snort-2.9.6.0/0000755000000000000000000000000012260606571010007 500000000000000snort-2.9.6.0/depcomp0000755000000000000000000005601612260606526011314 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: snort-2.9.6.0/tools/0000755000000000000000000000000012260606571011147 500000000000000snort-2.9.6.0/tools/file_server/0000755000000000000000000000000012260606571013454 500000000000000snort-2.9.6.0/tools/file_server/file_server.c0000644000000000000000000003461112260565733016056 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FILE_CAPTURE_SIZE 10485760 /*10M*/ #define VERBOSE_MODE_KEYWORD "-v" #define STD_BUF 1024 typedef struct _THREAD_ELEMENT { struct _THREAD_ELEMENT *next; int socket_fd; } ThreadElement; typedef enum { PRINT_MODE_FAST, PRINT_MODE_DETAIL } PrintMode; static PrintMode print_mode = PRINT_MODE_FAST; static int daemon_mode = 0; static int exit_signal = 0; int stop_processing = 0; #define FILE_NAME_LEN 200 typedef void (*sighandler_t)(int); typedef struct _FILE_MESSAGE_HEADER { /* All values must be in network byte order */ uint16_t version; uint16_t type; uint32_t length; /* Does not include the header */ char filename[FILE_NAME_LEN]; } FileMessageHeader; #define FILE_HEADER_VERSION 0x0001 typedef struct _File_Storage_Stats { int file_count; int file_storage_failures; int file_duplicates_total; } File_Storage_Stats; static File_Storage_Stats file_stats; static void CheckExit(void); static void LogMessage(const char *format,...); static void ErrorMessage(const char *format,...); static int ReadHeader(int socket_fd, FileMessageHeader *hdr) { ssize_t numread; unsigned total = 0; do { numread = read(socket_fd, (*(uint8_t **)&hdr) + total, sizeof(*hdr) - total); if (!numread) return 0; else if (numread > 0) total += numread; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < sizeof(*hdr) ); if (total < sizeof(*hdr)) return 0; hdr->length = ntohl(hdr->length); hdr->type = ntohs(hdr->type); hdr->version = ntohs(hdr->version); LogMessage("Receiving file %s, length: %d\n", hdr->filename, hdr->length); return 1; } static int ReadData(int socket_fd, uint8_t *buffer, uint32_t length) { ssize_t numread; unsigned total = 0; do { numread = read(socket_fd, buffer + total, length - total); if (!numread) return 0; else if (numread > 0) total += numread; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < length); if (total < length) return 0; return 1; } /* * writing file to the disk. * * In the case of interrupt errors, the write is retried, but only for a * finite number of times. * * Arguments * uint8_t *: The buffer containing the data to write * size_t: The length of the data to write * FILE *fh: File handler * * Returns: None * */ static void WriteFile(const uint8_t *buf, size_t buf_len, const char *file_name) { int max_retries = 3; size_t bytes_written = 0; int err; char filename[1024]; FILE *fh; struct stat buffer; /*save the file*/ sprintf(filename, "%s", file_name); filename[sizeof (filename) - 1] = '\0'; /*File exists*/ if(stat (filename, &buffer) == 0) { LogMessage("File exist: %s\n", filename); file_stats.file_duplicates_total++; return; } /*Opening file for writing in binary print_mode*/ fh = fopen(filename,"wb"); /* Nothing to write or nothing to write to */ if ((buf == NULL) || (fh == NULL)) return; /* Writing data to file */ /* writing several times */ do { size_t bytes_left = buf_len - bytes_written; bytes_written += fwrite(buf + bytes_written, 1, bytes_left, fh); err = ferror(fh); if (err && (err != EINTR) && (err != EAGAIN)) break; max_retries--; } while ((max_retries > 0) && (bytes_written < buf_len)); if (bytes_written < buf_len) { file_stats.file_storage_failures++; ErrorMessage("File server: disk writing error - %s!\n", strerror(err)); } /*Closing File*/ fclose(fh); file_stats.file_count++; } static void *FileSocketProcessThread(void *arg) { ThreadElement *t = (ThreadElement *)arg; if (t == NULL) { ErrorMessage("File Socket: Invalid process thread parameter\n"); return NULL; } if (t->socket_fd == -1) { ErrorMessage("File Socket: Invalid process thread socket\n"); return NULL; } while (!stop_processing) { FileMessageHeader hdr; int rval; if ((rval = ReadHeader(t->socket_fd, &hdr)) == 0) break; else if (rval < 0) { ErrorMessage("Failed to read!\n"); break; } if (hdr.version != FILE_HEADER_VERSION) { ErrorMessage("Bad message header version\n"); continue; } if (hdr.length > FILE_CAPTURE_SIZE) { ErrorMessage("Bad message data\n"); break; } if (hdr.length) { uint8_t *data; if ((data = malloc(hdr.length)) == NULL) { break; } LogMessage( "File Socket: Reading %u bytes\n", hdr.length); if ((rval = ReadData(t->socket_fd, data, hdr.length)) == 0) { ErrorMessage("File Socket: Socket closed before data read\n"); free(data); break; } else if (rval < 0) { ErrorMessage("File Socket: Failed to read %d\n", rval); free(data); continue; } WriteFile(data, hdr.length, hdr.filename); free(data); } CheckExit(); } LogMessage("File Socket: Close a processing thread for %d\n", t->socket_fd); free(t); return NULL; } /* Add a signal handler * Return: * 0: error * 1: success */ int AddSignal(int sig, sighandler_t signal_handler, int check_needed) { sighandler_t pre_handler; #ifdef HAVE_SIGACTION struct sigaction action; struct sigaction old_action; sigemptyset(&action.sa_mask); action.sa_flags = 0; action.sa_handler = signal_handler; sigaction(sig, &action, &old_action); pre_handler = old_action.sa_handler; #else pre_handler = signal(sig, signal_handler); #endif if (SIG_ERR == pre_handler) { ErrorMessage("Could not add handler for signal %d \n", sig); return 0; } else if (check_needed && (SIG_IGN != pre_handler) && (SIG_DFL!= pre_handler)) { ErrorMessage("WARNING: Handler is already installed for signal %d.\n", sig); } return 1; } /* Signal Handlers ************************************************************/ static void SigExitHandler(int signal) { exit_signal = signal; } static void CheckExit() { if ((SIGTERM == exit_signal) || (SIGINT == exit_signal)) { stop_processing = 1; } } static void PrintFileStats(File_Storage_Stats *stats) { LogMessage("Total files stored: %d\n", stats->file_count); LogMessage("Total file storage errors: %d\n", stats->file_storage_failures); LogMessage("Total duplicated files: %d\n", stats->file_duplicates_total); } static int ProcessClientRequest(int sockfd) { struct timeval to; socklen_t clilen; fd_set rfds; struct sockaddr_in cli_addr; int rval; pthread_t tid; ThreadElement *t; int newsockfd; to.tv_sec = 2; to.tv_usec = 0; FD_ZERO(&rfds); FD_SET(sockfd, &rfds); //accept incoming connections clilen = sizeof(cli_addr); rval = select(sockfd + 1, &rfds, NULL, NULL, &to); if (rval > 0) { memset(&cli_addr, 0, sizeof(cli_addr)); if ((newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen)) == -1) { if (errno != EINTR) { ErrorMessage("File Socket: Accept failed: %s\n", strerror(errno)); return -1; } } else { LogMessage("File Socket: Creating a processing thread for %d\n", newsockfd); if ((t = calloc(1, sizeof(*t))) == NULL) { close(newsockfd); ErrorMessage("File Socket: Failed to allocate a thread struct"); return -1; } t->socket_fd = newsockfd; if ((rval = pthread_create(&tid, NULL, &FileSocketProcessThread, (void *)t)) != 0) { close(newsockfd); ErrorMessage("File Socket: Unable to create a processing thread: %s", strerror(rval)); return -1; } pthread_join(tid, NULL); } } else if (rval < 0) { if (errno != EINTR) { ErrorMessage("File Socket: Select failed: %s\n", strerror(errno)); return -1; } } return 0; } /* * Print a message to stderr or with logfacility. * * Arguments: format => the formatted error string to print out * ... => format commands/fillers * * Returns: void function */ void LogMessage(const char *format,...) { char buf[STD_BUF+1]; va_list ap; if (print_mode == PRINT_MODE_FAST) return; va_start(ap, format); vsnprintf(buf, STD_BUF, format, ap); buf[STD_BUF] = '\0'; syslog(LOG_DAEMON | LOG_NOTICE, "%s", buf); printf("%s", buf); va_end(ap); } /* * Print a message to stderr or with logfacility. * * Arguments: format => the formatted error string to print out * ... => format commands/fillers * * Returns: void function */ void ErrorMessage(const char *format,...) { char buf[STD_BUF+1]; va_list ap; va_start(ap, format); vsnprintf(buf, STD_BUF, format, ap); buf[STD_BUF] = '\0'; syslog(LOG_CONS | LOG_DAEMON | LOG_ERR, "%s", buf); printf("%s", buf); va_end(ap); } /* Puts the program into daemon print_mode, nice and quiet like....*/ void GoDaemon(void) { int exit_val = 0; pid_t cpid; int i; LogMessage("Initializing daemon mode\n"); /* Don't daemonize if we've already daemonized */ if(getppid() != 1) { /* now fork the child */ printf("Spawning daemon child...\n"); cpid = fork(); if(cpid > 0) { /* Parent */ printf("Daemon child %d lives...\n", cpid); printf("Daemon parent exiting (%d)\n", exit_val); exit(exit_val); /* parent */ } if(cpid < 0) { /* Daemonizing failed... */ perror("fork"); exit(1); } } /* Child */ setsid(); close(0); close(1); close(2); /* redirect stdin/stdout/stderr to /dev/null */ i = open("/dev/null", O_RDWR); /* stdin, fd 0 */ dup(i); dup(i); } static void PrintHelp() { printf("Usage: file_server <-dvh> -\n"); printf("d: daemon mode -\n"); printf("v: verbos mode -\n"); printf("h: help -\n"); } static void ParseArgs(char *arg) { int len; int i; if (!arg) return; len = strlen(arg); if (len < 2) { printf("Option length two short!\n"); return; } if (arg[0] != '-') { printf("Please provide option start with -\n"); } for (i = 1; i < len; i++) { switch(arg[i]) { case 'd': daemon_mode = 1; break; case 'v': print_mode = PRINT_MODE_DETAIL; LogMessage("Verbose print_mode specified!\n"); break; case 'h': PrintHelp(); break; default: printf("Please provide correct option!\n"); PrintHelp(); exit(1); } } } int main(int argc, char *argv[]) { int sockfd, portno; struct sockaddr_in serv_addr; int one = 1; setlogmask (LOG_UPTO (LOG_NOTICE)); openlog("file_server", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); if (argc < 2) { fprintf(stderr,"please specify a port number\n"); exit(1); } if(argc > 2) { int i; for (i = 2; i < argc; i++) ParseArgs(argv[i]); } if (daemon_mode) { GoDaemon(); } AddSignal(SIGTERM, SigExitHandler, 1); AddSignal(SIGINT, SigExitHandler, 1); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { ErrorMessage("ERROR create socket.\n"); exit(1); } //allow reuse of port setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one); //bind to a local address memset((char *) &serv_addr, 0, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { ErrorMessage("ERROR on bind.\n"); exit(1); } //listen marks the socket as passive socket listening to incoming connections, //it allows max 5 backlog connections: backlog connections are pending in queue //if pending connections are more than 5, later request may be ignored listen(sockfd,5); while (!stop_processing) { if (ProcessClientRequest(sockfd) < 0) break; CheckExit(); } close(sockfd); LogMessage("----------Exiting.........!\n"); PrintFileStats(&file_stats); closelog(); return 0; } snort-2.9.6.0/tools/file_server/README.file_server0000644000000000000000000000127512232305217016555 00000000000000file-server - Tool to received captured files from snort -------------------------------------------- file server is used along with file inspect preprocessor, to receive and store files captured by file inspect preprocessor. This simple program should run on the directory that you want to store files. In other words, file will be saved on current directory. File name will be be SHA for that file (from file inspect preprocessor) Use -v option if you want to see what files are received/stored. Use -d option if you want to run it in daemon mode Use -h option for help Use Ctrl - c to stop file server Usage ----- $ file_server <-vdh> Example: file_server 8000 -v snort-2.9.6.0/tools/file_server/Makefile.am0000644000000000000000000000036112232305217015420 00000000000000AUTOMAKE_OPTIONS=foreign bin_PROGRAMS = file_server docdir = ${datadir}/doc/${PACKAGE} file_server_SOURCES = file_server.c file_server_CFLAGS = @CFLAGS@ $(AM_CFLAGS) INCLUDES = @INCLUDES@ @extra_incl@ dist_doc_DATA = README.file_server snort-2.9.6.0/tools/file_server/Makefile.in0000644000000000000000000005666712260606526015465 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = file_server$(EXEEXT) subdir = tools/file_server DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_doc_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)" PROGRAMS = $(bin_PROGRAMS) am_file_server_OBJECTS = file_server-file_server.$(OBJEXT) file_server_OBJECTS = $(am_file_server_OBJECTS) file_server_LDADD = $(LDADD) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = file_server_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(file_server_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(file_server_SOURCES) DIST_SOURCES = $(file_server_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_doc_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ @extra_incl@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = ${datadir}/doc/${PACKAGE} dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign file_server_SOURCES = file_server.c file_server_CFLAGS = @CFLAGS@ $(AM_CFLAGS) dist_doc_DATA = README.file_server all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/file_server/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tools/file_server/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list file_server$(EXEEXT): $(file_server_OBJECTS) $(file_server_DEPENDENCIES) $(EXTRA_file_server_DEPENDENCIES) @rm -f file_server$(EXEEXT) $(AM_V_CCLD)$(file_server_LINK) $(file_server_OBJECTS) $(file_server_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_server-file_server.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< file_server-file_server.o: file_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(file_server_CFLAGS) $(CFLAGS) -MT file_server-file_server.o -MD -MP -MF $(DEPDIR)/file_server-file_server.Tpo -c -o file_server-file_server.o `test -f 'file_server.c' || echo '$(srcdir)/'`file_server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/file_server-file_server.Tpo $(DEPDIR)/file_server-file_server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='file_server.c' object='file_server-file_server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(file_server_CFLAGS) $(CFLAGS) -c -o file_server-file_server.o `test -f 'file_server.c' || echo '$(srcdir)/'`file_server.c file_server-file_server.obj: file_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(file_server_CFLAGS) $(CFLAGS) -MT file_server-file_server.obj -MD -MP -MF $(DEPDIR)/file_server-file_server.Tpo -c -o file_server-file_server.obj `if test -f 'file_server.c'; then $(CYGPATH_W) 'file_server.c'; else $(CYGPATH_W) '$(srcdir)/file_server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/file_server-file_server.Tpo $(DEPDIR)/file_server-file_server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='file_server.c' object='file_server-file_server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(file_server_CFLAGS) $(CFLAGS) -c -o file_server-file_server.obj `if test -f 'file_server.c'; then $(CYGPATH_W) 'file_server.c'; else $(CYGPATH_W) '$(srcdir)/file_server.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_docDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dist_docDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-dist_docDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/tools/control/0000755000000000000000000000000012260606571012627 500000000000000snort-2.9.6.0/tools/control/sfcontrol.c0000644000000000000000000002452612260565733014741 00000000000000/* ** $Id$ ** ** sfcontrol.c ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2002-2013 Sourcefire, Inc. ** Author(s): Ron Dempster ** ** NOTES ** 5.5.11 - Initial Source Code. Dempster ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sfcontrol.h" #ifndef PATH_MAX #define PATH_MAX 4096 #endif typedef enum { PRINT_MODE_FAST, PRINT_MODE_DETAIL }PrintMode; #define PRINT_MODE_FAST_KEYWORD "-text" struct _CS_MESSAGE { CSMessageHeader hdr; CSMessageDataHeader msg_hdr; uint8_t msg[4096]; } __attribute__((packed)); typedef struct _CS_MESSAGE CSMessage; static void DumpHex(FILE *fp, const uint8_t *data, unsigned len) { char str[18]; unsigned i; unsigned pos; char c; for (i=0, pos=0; i [-text]" "[\"sub command string\"]\n",progname); } static int SendMessage(int socket_fd, const CSMessage *msg, uint32_t len) { ssize_t numsent; unsigned total_len = sizeof(*msg) + len; unsigned total = 0; do { numsent = write(socket_fd, (*(uint8_t **)&msg) + total, total_len - total); if (!numsent) return 0; else if (numsent > 0) total += numsent; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < total_len); return 1; } static int ReadData(int socket_fd, uint8_t *buffer, uint32_t length) { ssize_t numread; unsigned total = 0; do { numread = read(socket_fd, buffer + total, length - total); if (!numread) return 0; else if (numread > 0) total += numread; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < length); if (total < length) return 0; return 1; } static int ReadResponse(int socket_fd, CSMessageHeader *hdr) { ssize_t numread; unsigned total = 0; do { numread = read(socket_fd, (*(uint8_t **)&hdr) + total, sizeof(*hdr) - total); if (!numread) return 0; else if (numread > 0) total += numread; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < sizeof(*hdr)); if (total < sizeof(*hdr)) return 0; hdr->length = ntohl(hdr->length); hdr->version = ntohs(hdr->version); hdr->type = ntohs(hdr->type); return 1; } void ConnectToUnixSocket(const char * const name, int * const psock) { struct sockaddr_un sunaddr; int sock = -1; int rval; memset(&sunaddr, 0, sizeof(sunaddr)); rval = snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", name); if (rval < 0 || (size_t)rval >= sizeof(sunaddr.sun_path)) { fprintf(stderr, "Socket name '%s' is too long\n", name); exit(-1); } sunaddr.sun_family = AF_UNIX; /* open the socket */ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "Error opening socket: %s\n", strerror(errno)); exit(-1); } if (connect(sock, (struct sockaddr *) &sunaddr, sizeof(sunaddr)) == -1) { fprintf(stderr, "Unable to connect to UNIX socket at %s: %s\n", name, strerror(errno)); close(sock); exit(-1); } *psock = sock; } int main(int argc, char *argv[]) { int rval; char socket_fn[PATH_MAX]; int socket_fd; char *p; CSMessage *message; unsigned long type; const char *sep; ssize_t len; PrintMode mode = PRINT_MODE_DETAIL; const char *extra; unsigned int extra_len = 0; if (argc < 3 || argc > 5 || !*argv[1] || !*argv[2]) { DisplayUsage(argv[0]); exit(-1); } else if (argc > 3) { int idx = 3; if((strlen(PRINT_MODE_FAST_KEYWORD) == strlen(argv[idx])) && (strcmp(PRINT_MODE_FAST_KEYWORD,argv[idx]) == 0)) { mode = PRINT_MODE_FAST; idx ++; } if (argc > idx) { extra = argv[idx]; extra_len = strlen(extra) + 1; } } type = strtoul(argv[2], &p, 0); if (*p || type > CS_TYPE_MAX) { DisplayUsage(argv[0]); exit(-1); } len = strlen(argv[1]); if (len && argv[1][len - 1] == '/') sep = ""; else sep = "/"; snprintf(socket_fn, sizeof(socket_fn), "%s%s%s", argv[1], sep, CONTROL_FILE); ConnectToUnixSocket(socket_fn, &socket_fd); if (extra_len > sizeof(message->msg)) { fprintf(stderr, "snort_control: message is too long.\n"); exit(-1); } message = malloc(sizeof *message); if (message == NULL) { fprintf(stderr, "snort_control: could not allocate message.\n"); exit(-1); } message->hdr.version = htons(CS_HEADER_VERSION); message->hdr.type = htons((uint16_t)type); message->hdr.length = 0; if (extra_len) { message->hdr.length = htonl(extra_len + sizeof(message->msg_hdr)); message->msg_hdr.code = 0; message->msg_hdr.length = htons(extra_len); memcpy(message->msg, extra, extra_len); } if ((rval = SendMessage(socket_fd, message, extra_len)) < 0) { fprintf(stderr, "Failed to send the message: %s\n", strerror(errno)); close(socket_fd); exit(-1); } else if (!rval) { fprintf(stderr, "Server closed the socket\n"); close(socket_fd); exit(-1); } do { /* Reusing the same CSMessage to capture the response */ if ((rval = ReadResponse(socket_fd, &message->hdr)) < 0) { fprintf(stderr, "Failed to read the response: %s\n", strerror(errno)); close(socket_fd); exit(-1); } else if (!rval) { fprintf(stderr, "Server closed the socket before sending a response\n"); close(socket_fd); exit(-1); } if (message->hdr.version != CS_HEADER_VERSION) { printf("snort_control: bad response version\n"); close(socket_fd); exit(-1); } if (message->hdr.length) { if (message->hdr.length < sizeof(message->msg_hdr)) { printf("snort_control: response message is too small\n"); close(socket_fd); exit(-1); } if (message->hdr.length > sizeof(message->msg)) { printf("snort_control: response message is too large\n"); close(socket_fd); exit(-1); } if ((rval = ReadData(socket_fd, (uint8_t *)message+sizeof(message->hdr), message->hdr.length)) < 0) { fprintf(stderr, "Failed to read the response data: %s\n", strerror(errno)); close(socket_fd); exit(-1); } else if (!rval) { fprintf(stderr, "Server closed the socket before sending the response data\n"); close(socket_fd); exit(-1); } message->msg_hdr.code = ntohl(message->msg_hdr.code); message->msg_hdr.length = ntohs(message->msg_hdr.length); if (mode == PRINT_MODE_DETAIL) { fprintf(stdout, "Response %04X with code %d and length %u\n", message->hdr.type, message->msg_hdr.code, message->msg_hdr.length); DumpHex(stdout, message->msg, message->msg_hdr.length); } else if (mode == PRINT_MODE_FAST) { if (message->msg_hdr.length == message->hdr.length - sizeof(message->msg_hdr)) { message->msg[message->msg_hdr.length-1] = 0; fprintf(stdout, "Response %04X with code %d (%s)\n", message->hdr.type, message->msg_hdr.code, message->msg); } else fprintf(stdout, "Response %04X with code %d\n", message->hdr.type, message->msg_hdr.code); } } else { if (mode == PRINT_MODE_DETAIL) printf("Response %04X without data\n", message->hdr.type); else printf("Response %04X\n", message->hdr.type); } } while (message->hdr.type == CS_HEADER_DATA); return 0; } snort-2.9.6.0/tools/control/README.snort_control0000644000000000000000000000124411652017025016326 00000000000000snort_control - Tool to connect to the snort control channel and issue a command -------------------------------------------- About ----- The current version of Snort can be configured to provide a Unix socket that can be used to issue commands to the running process. Installation ------------ snort_control is made and installed along with snort in the same bin directory when configured with the --enable-control-socket option. The control socket functionality is supported on Linux only. Usage ----- $ snort_control "log path" specifies the directory passed to snort with the -l option "command" is an unsigned 32-bit command value snort-2.9.6.0/tools/control/Makefile.am0000644000000000000000000000036711652017025014603 00000000000000AUTOMAKE_OPTIONS=foreign bin_PROGRAMS = snort_control docdir = ${datadir}/doc/${PACKAGE} snort_control_SOURCES = sfcontrol.c snort_control_CFLAGS = @CFLAGS@ $(AM_CFLAGS) INCLUDES = @INCLUDES@ @extra_incl@ dist_doc_DATA = README.snort_control snort-2.9.6.0/tools/control/Makefile.in0000644000000000000000000005667512260606526014637 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = snort_control$(EXEEXT) subdir = tools/control DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_doc_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)" PROGRAMS = $(bin_PROGRAMS) am_snort_control_OBJECTS = snort_control-sfcontrol.$(OBJEXT) snort_control_OBJECTS = $(am_snort_control_OBJECTS) snort_control_LDADD = $(LDADD) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = snort_control_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(snort_control_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(snort_control_SOURCES) DIST_SOURCES = $(snort_control_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_doc_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ @extra_incl@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = ${datadir}/doc/${PACKAGE} dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign snort_control_SOURCES = sfcontrol.c snort_control_CFLAGS = @CFLAGS@ $(AM_CFLAGS) dist_doc_DATA = README.snort_control all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/control/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tools/control/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list snort_control$(EXEEXT): $(snort_control_OBJECTS) $(snort_control_DEPENDENCIES) $(EXTRA_snort_control_DEPENDENCIES) @rm -f snort_control$(EXEEXT) $(AM_V_CCLD)$(snort_control_LINK) $(snort_control_OBJECTS) $(snort_control_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snort_control-sfcontrol.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< snort_control-sfcontrol.o: sfcontrol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snort_control_CFLAGS) $(CFLAGS) -MT snort_control-sfcontrol.o -MD -MP -MF $(DEPDIR)/snort_control-sfcontrol.Tpo -c -o snort_control-sfcontrol.o `test -f 'sfcontrol.c' || echo '$(srcdir)/'`sfcontrol.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snort_control-sfcontrol.Tpo $(DEPDIR)/snort_control-sfcontrol.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sfcontrol.c' object='snort_control-sfcontrol.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snort_control_CFLAGS) $(CFLAGS) -c -o snort_control-sfcontrol.o `test -f 'sfcontrol.c' || echo '$(srcdir)/'`sfcontrol.c snort_control-sfcontrol.obj: sfcontrol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snort_control_CFLAGS) $(CFLAGS) -MT snort_control-sfcontrol.obj -MD -MP -MF $(DEPDIR)/snort_control-sfcontrol.Tpo -c -o snort_control-sfcontrol.obj `if test -f 'sfcontrol.c'; then $(CYGPATH_W) 'sfcontrol.c'; else $(CYGPATH_W) '$(srcdir)/sfcontrol.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/snort_control-sfcontrol.Tpo $(DEPDIR)/snort_control-sfcontrol.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sfcontrol.c' object='snort_control-sfcontrol.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(snort_control_CFLAGS) $(CFLAGS) -c -o snort_control-sfcontrol.obj `if test -f 'sfcontrol.c'; then $(CYGPATH_W) 'sfcontrol.c'; else $(CYGPATH_W) '$(srcdir)/sfcontrol.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_docDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dist_docDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-dist_docDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/tools/u2spewfoo/0000755000000000000000000000000012260606571013100 500000000000000snort-2.9.6.0/tools/u2spewfoo/u2spewfoo.dsp0000644000000000000000000001001511662530534015456 00000000000000# Microsoft Developer Studio Project File - Name="u2spewfoo" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=u2spewfoo - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "u2spewfoo.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "u2spewfoo.mak" CFG="u2spewfoo - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "u2spewfoo - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "u2spewfoo - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "u2spewfoo - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\src\win32\WIN32-Includes" /I "..\..\src\sfutil" /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 wsock32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "u2spewfoo - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\src\win32\WIN32-Includes" /I "..\..\src\sfutil" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "u2spewfoo - Win32 Release" # Name "u2spewfoo - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\u2spewfoo.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/tools/u2spewfoo/u2spewfoo.c0000644000000000000000000005152712260565733015133 00000000000000/* * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2002-2013 Sourcefire, Inc. * Copyright (C) 1998-2002 Martin Roesch * Author: Adam Keeton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef WIN32 #include #include #include #include #include #include #include #include #include #endif #ifdef HAVE_UUID_UUID_H #include #endif #include "Unified2_common.h" #define SUCCESS 314159265 #define STEVE -1 #define FAILURE STEVE #ifndef WIN32 #ifndef uint32_t typedef unsigned int uint32_t; typedef unsigned short uint16_t; typedef unsigned char uint8_t; #endif #else static void inet_ntop(int family, const void *ip_raw, char *buf, int bufsize) { int i; if(!ip_raw || !buf || !bufsize || (family != AF_INET && family != AF_INET6) || /* Make sure if it's IPv6 that the buf is large enough. */ /* Need atleast a max of 8 fields of 4 bytes plus 7 for colons in * between. Need 1 more byte for null. */ (family == AF_INET6 && bufsize < 8*4 + 7 + 1) || /* Make sure if it's IPv4 that the buf is large enough. */ /* 4 fields of 3 numbers, plus 3 dots and a null byte */ (family == AF_INET && bufsize < 3*4 + 4) ) { if(buf && bufsize > 0) buf[0] = 0; return; } /* 4 fields of at most 3 characters each */ if(family == AF_INET) { u_int8_t *p = (u_int8_t*)ip_raw; for(i=0; p < ((u_int8_t*)ip_raw) + 4; p++) { i += sprintf(&buf[i], "%d", *p); /* If this is the last iteration, this could technically cause one * extra byte to be written past the end. */ if(i < bufsize && ((p + 1) < ((u_int8_t*)ip_raw+4))) buf[i] = '.'; i++; } /* Check if this is really just an IPv4 address represented as 6, * in compatible format */ #if 0 } else if(!field[0] && !field[1] && !field[2]) { unsigned char *p = (unsigned char *)(&ip->ip[12]); for(i=0; p < &ip->ip[16]; p++) i += sprintf(&buf[i], "%d.", *p); #endif } else { u_int16_t *p = (u_int16_t*)ip_raw; for(i=0; p < ((u_int16_t*)ip_raw) + 8; p++) { i += sprintf(&buf[i], "%04x", ntohs(*p)); /* If this is the last iteration, this could technically cause one * extra byte to be written past the end. */ if(i < bufsize && ((p + 1) < ((u_int16_t*)ip_raw) + 8)) buf[i] = ':'; i++; } } } #endif typedef struct _record { uint32_t type; uint32_t length; uint8_t *data; } u2record; typedef struct _u2iterator { FILE *file; char *filename; u2record current; } u2iterator; static long s_pos = 0, s_off = 0; #define TO_IP(x) x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff static u2iterator *new_iterator(char *filename) { FILE *f = fopen(filename, "rb"); u2iterator *ret; if(!f) { printf("new_iterator: Failed to open file: %s\n\tErrno: %s\n", filename, strerror(errno)); return NULL; } ret = (u2iterator*)malloc(sizeof(u2iterator)); if(!ret) { printf("new_iterator: Failed to malloc %lu bytes.\n", (unsigned long)sizeof(u2iterator)); fclose(f); return NULL; } ret->file = f; ret->filename = strdup(filename); return ret; } static inline void free_iterator(u2iterator *it) { if(it->file) fclose(it->file); if(it->filename) free(it->filename); if(it) free(it); } static int get_record(u2iterator *it, u2record *record) { uint32_t bytes_read; uint8_t *tmp; if(!it || !it->file) return FAILURE; /* check if the log was rotated */ if(feof(it->file)) { /* Get next timestamped file? */ puts("Hit the EOF .. and this is not being handled yet."); return FAILURE; } if ( s_off ) { fseek(it->file, s_pos+s_off, SEEK_SET); s_off = 0; } /* read type and length */ bytes_read = fread(record, 1, sizeof(uint32_t) * 2, it->file); /* But they're in network order! */ record->type= ntohl(record->type); record->length= ntohl(record->length); //if(record->type == UNIFIED2_PACKET) record->length+=4; if(bytes_read == 0) /* EOF */ return FAILURE; if(bytes_read != sizeof(uint32_t)*2) { puts("get_record: (1) Failed to read all of record."); printf("\tRead %u of %lu bytes\n", bytes_read, (unsigned long)sizeof(uint32_t)*2); return FAILURE; } s_pos = ftell(it->file); tmp = (uint8_t *)realloc(record->data, record->length); if (!tmp) { puts("get_record: (2) Failed to allocate memory."); free(record->data); return FAILURE; } record->data = tmp; bytes_read = fread(record->data, 1, record->length, it->file); if(bytes_read != record->length) { puts("get_record: (3) Failed to read all of record data."); printf("\tRead %u of %u bytes\n", bytes_read, record->length); if ( record->type != UNIFIED2_PACKET || bytes_read < ntohl(((Serial_Unified2Packet*)record->data)->packet_length) ) return FAILURE; clearerr(it->file); } return SUCCESS; } static void extradata_dump(u2record *record) { uint8_t *field, *data; int i; int len = 0; SerialUnified2ExtraData event; Unified2ExtraDataHdr eventHdr; uint32_t ip; char ip6buf[INET6_ADDRSTRLEN+1]; struct in6_addr ipAddr; memcpy(&eventHdr, record->data, sizeof(Unified2ExtraDataHdr)); memcpy(&event, record->data + sizeof(Unified2ExtraDataHdr) , sizeof(SerialUnified2ExtraData)); /* network to host ordering */ field = (uint8_t*)&eventHdr; for(i=0; i<2; i++, field+=4) { *(uint32_t*)field = ntohl(*(uint32_t*)field); } field = (uint8_t*)&event; for(i=0; i<6; i++, field+=4) { *(uint32_t*)field = ntohl(*(uint32_t*)field); } printf("\n(ExtraDataHdr)\n" "\tevent type: %u\tevent length: %u\n", eventHdr.event_type, eventHdr.event_length); printf("\n(ExtraData)\n" "\tsensor id: %u\tevent id: %u\tevent second: %u\n" "\ttype: %u\tdatatype: %u\tbloblength: %u\t", event.sensor_id, event.event_id, event.event_second, event.type, event.data_type, event.blob_length); len = event.blob_length - sizeof(event.blob_length) - sizeof(event.data_type); switch(event.type) { case EVENT_INFO_XFF_IPV4: memcpy(&ip, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData), sizeof(uint32_t)); ip = ntohl(ip); printf("Original Client IP: %u.%u.%u.%u\n", TO_IP(ip)); break; case EVENT_INFO_XFF_IPV6: memcpy(&ipAddr, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData), sizeof(struct in6_addr)); inet_ntop(AF_INET6, &ipAddr, ip6buf, INET6_ADDRSTRLEN); printf("Original Client IP: %s\n", ip6buf); break; case EVENT_INFO_GZIP_DATA: printf("GZIP Decompressed Data: %.*s\n", len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData)); break; case EVENT_INFO_JSNORM_DATA: printf("Normalized JavaScript Data: %.*s\n", len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData)); break; case EVENT_INFO_SMTP_FILENAME: printf("SMTP Attachment Filename: %.*s\n", len,record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData)); break; case EVENT_INFO_SMTP_MAILFROM: printf("SMTP MAIL FROM Addresses: %.*s\n", len,record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData)); break; case EVENT_INFO_SMTP_RCPTTO: printf("SMTP RCPT TO Addresses: %.*s\n", len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData)); break; case EVENT_INFO_SMTP_EMAIL_HDRS: printf("SMTP EMAIL HEADERS: \n%.*s\n", len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData)); break; case EVENT_INFO_HTTP_URI: printf("HTTP URI: %.*s\n", len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData)); break; case EVENT_INFO_HTTP_HOSTNAME: printf("HTTP Hostname: "); data = record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData); for(i=0; i < len; i++) { if(iscntrl(data[i])) printf("%c",'.'); else printf("%c",data[i]); } printf("\n"); break; case EVENT_INFO_IPV6_SRC: memcpy(&ipAddr, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData), sizeof(struct in6_addr)); inet_ntop(AF_INET6, &ipAddr, ip6buf, INET6_ADDRSTRLEN); printf("IPv6 Source Address: %s\n", ip6buf); break; case EVENT_INFO_IPV6_DST: memcpy(&ipAddr, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData), sizeof(struct in6_addr)); inet_ntop(AF_INET6, &ipAddr, ip6buf, INET6_ADDRSTRLEN); printf("IPv6 Destination Address: %s\n", ip6buf); break; default : break; } } static void event_dump(u2record *record) { uint8_t *field; int i; Serial_Unified2IDSEvent_legacy event; memcpy(&event, record->data, sizeof(Serial_Unified2IDSEvent_legacy)); /* network to host ordering */ /* In the event structure, only the last 40 bits are not 32 bit fields */ /* The first 11 fields need to be convertted */ field = (uint8_t*)&event; for(i=0; i<11; i++, field+=4) { *(uint32_t*)field = ntohl(*(uint32_t*)field); } /* last 3 fields, with the exception of the last most since it's just one byte */ *(uint16_t*)field = ntohs(*(uint16_t*)field); /* sport_itype */ field += 2; *(uint16_t*)field = ntohs(*(uint16_t*)field); /* dport_icode */ /* done changing the network ordering */ printf("\n(Event)\n" "\tsensor id: %u\tevent id: %u\tevent second: %u\tevent microsecond: %u\n" "\tsig id: %u\tgen id: %u\trevision: %u\t classification: %u\n" "\tpriority: %u\tip source: %u.%u.%u.%u\tip destination: %u.%u.%u.%u\n" "\tsrc port: %u\tdest port: %u\tprotocol: %u\timpact_flag: %u\tblocked: %u\n", event.sensor_id, event.event_id, event.event_second, event.event_microsecond, event.signature_id, event.generator_id, event.signature_revision, event.classification_id, event.priority_id, TO_IP(event.ip_source), TO_IP(event.ip_destination), event.sport_itype, event.dport_icode, event.protocol, event.impact_flag, event.blocked); } static void event6_dump(u2record *record) { uint8_t *field; int i; Serial_Unified2IDSEventIPv6_legacy event; char ip6buf[INET6_ADDRSTRLEN+1]; memcpy(&event, record->data, sizeof(Serial_Unified2IDSEventIPv6_legacy)); /* network to host ordering */ /* In the event structure, only the last 40 bits are not 32 bit fields */ /* The first fields need to be convertted */ field = (uint8_t*)&event; for(i=0; i<9; i++, field+=4) { *(uint32_t*)field = ntohl(*(uint32_t*)field); } field = field + 2*sizeof(struct in6_addr); /* last 3 fields, with the exception of the last most since it's just one byte */ *(uint16_t*)field = ntohs(*(uint16_t*)field); /* sport_itype */ field += 2; *(uint16_t*)field = ntohs(*(uint16_t*)field); /* dport_icode */ /* done changing the network ordering */ inet_ntop(AF_INET6, &event.ip_source, ip6buf, INET6_ADDRSTRLEN); printf("\n(IPv6 Event)\n" "\tsensor id: %u\tevent id: %u\tevent second: %u\tevent microsecond: %u\n" "\tsig id: %u\tgen id: %u\trevision: %u\t classification: %u\n" "\tpriority: %u\tip source: %s\t", event.sensor_id, event.event_id, event.event_second, event.event_microsecond, event.signature_id, event.generator_id, event.signature_revision, event.classification_id, event.priority_id, ip6buf); inet_ntop(AF_INET6, &event.ip_destination, ip6buf, INET6_ADDRSTRLEN); printf("ip destination: %s\n" "\tsrc port: %u\tdest port: %u\tprotocol: %u\timpact_flag: %u\tblocked: %u\n", ip6buf, event.sport_itype, event.dport_icode, event.protocol, event.impact_flag, event.blocked); } static void event2_dump(u2record *record) { uint8_t *field; int i; Serial_Unified2IDSEvent event; memcpy(&event, record->data, sizeof(Serial_Unified2IDSEvent)); /* network to host ordering */ /* In the event structure, only the last 40 bits are not 32 bit fields */ /* The first 11 fields need to be convertted */ field = (uint8_t*)&event; for(i=0; i<11; i++, field+=4) { *(uint32_t*)field = ntohl(*(uint32_t*)field); } /* last 3 fields, with the exception of the last most since it's just one byte */ *(uint16_t*)field = ntohs(*(uint16_t*)field); /* sport_itype */ field += 2; *(uint16_t*)field = ntohs(*(uint16_t*)field); /* dport_icode */ field +=6; *(uint32_t*)field = ntohl(*(uint32_t*)field); /* mpls_label */ field += 4; /* policy_id and vlanid */ for(i=0; i<2; i++, field+=2) { *(uint16_t*)field = ntohs(*(uint16_t*)field); } /* done changing the network ordering */ printf("\n(Event)\n" "\tsensor id: %u\tevent id: %u\tevent second: %u\tevent microsecond: %u\n" "\tsig id: %u\tgen id: %u\trevision: %u\t classification: %u\n" "\tpriority: %u\tip source: %u.%u.%u.%u\tip destination: %u.%u.%u.%u\n" "\tsrc port: %u\tdest port: %u\tprotocol: %u\timpact_flag: %u\tblocked: %u\n" "\tmpls label: %u\tvland id: %u\tpolicy id: %u\n", event.sensor_id, event.event_id, event.event_second, event.event_microsecond, event.signature_id, event.generator_id, event.signature_revision, event.classification_id, event.priority_id, TO_IP(event.ip_source), TO_IP(event.ip_destination), event.sport_itype, event.dport_icode, event.protocol, event.impact_flag, event.blocked, event.mpls_label, event.vlanId, event.pad2); } static void event2_6_dump(u2record *record) { uint8_t *field; int i; char ip6buf[INET6_ADDRSTRLEN+1]; Serial_Unified2IDSEventIPv6 event; memcpy(&event, record->data, sizeof(Serial_Unified2IDSEventIPv6)); /* network to host ordering */ /* In the event structure, only the last 40 bits are not 32 bit fields */ /* The first fields need to be convertted */ field = (uint8_t*)&event; for(i=0; i<9; i++, field+=4) { *(uint32_t*)field = ntohl(*(uint32_t*)field); } field = field + 2*sizeof(struct in6_addr); /* last 3 fields, with the exception of the last most since it's just one byte */ *(uint16_t*)field = ntohs(*(uint16_t*)field); /* sport_itype */ field += 2; *(uint16_t*)field = ntohs(*(uint16_t*)field); /* dport_icode */ field +=6; *(uint32_t*)field = ntohl(*(uint32_t*)field); /* mpls_label */ field += 4; /* policy_id and vlanid */ for(i=0; i<2; i++, field+=2) { *(uint16_t*)field = ntohs(*(uint16_t*)field); } /* done changing the network ordering */ inet_ntop(AF_INET6, &event.ip_source, ip6buf, INET6_ADDRSTRLEN); printf("\n(IPv6 Event)\n" "\tsensor id: %u\tevent id: %u\tevent second: %u\tevent microsecond: %u\n" "\tsig id: %u\tgen id: %u\trevision: %u\t classification: %u\n" "\tpriority: %u\tip source: %s\t", event.sensor_id, event.event_id, event.event_second, event.event_microsecond, event.signature_id, event.generator_id, event.signature_revision, event.classification_id, event.priority_id, ip6buf); inet_ntop(AF_INET6, &event.ip_destination, ip6buf, INET6_ADDRSTRLEN); printf("ip destination: %s\n" "\tsrc port: %u\tdest port: %u\tprotocol: %u\timpact_flag: %u\tblocked: %u\n" "\tmpls label: %u\tvland id: %u\tpolicy id: %u\n", ip6buf, event.sport_itype, event.dport_icode, event.protocol, event.impact_flag, event.blocked, event.mpls_label, event.vlanId,event.pad2); } static inline void print_uuid (const char* label, uint8_t* data) { #ifdef HAVE_LIBUUID char buf[37]; uuid_unparse(data, buf); printf("%s: %s\n", label, buf); #else printf("%s: %.*s\n", label, 16, data); #endif } #define LOG_CHARS 16 static void LogBuffer (const uint8_t* p, unsigned n) { char hex[(3*LOG_CHARS)+1]; char txt[LOG_CHARS+1]; unsigned odx = 0, idx = 0, at = 0; for ( idx = 0; idx < n; idx++) { uint8_t byte = p[idx]; sprintf(hex + 3*odx, "%2.02X ", byte); txt[odx++] = isprint(byte) ? byte : '.'; if ( odx == LOG_CHARS ) { txt[odx] = hex[3*odx] = '\0'; printf("[%5u] %s %s\n", at, hex, txt); at = idx + 1; odx = 0; } } if ( odx ) { txt[odx] = hex[3*odx] = '\0'; printf("[%5u] %-48.48s %s\n", at, hex, txt); } } static void packet_dump(u2record *record) { uint32_t counter; uint8_t *field; unsigned offset = sizeof(Serial_Unified2Packet)-4; unsigned reclen = record->length - offset; Serial_Unified2Packet packet; memcpy(&packet, record->data, sizeof(Serial_Unified2Packet)); /* network to host ordering */ /* The first 7 fields need to be convertted */ field = (uint8_t*)&packet; for(counter=0; counter<7; counter++, field+=4) { *(uint32_t*)field = ntohl(*(uint32_t*)field); } /* done changing from network ordering */ printf("\nPacket\n" "\tsensor id: %u\tevent id: %u\tevent second: %u\n" "\tpacket second: %u\tpacket microsecond: %u\n" "\tlinktype: %u\tpacket_length: %u\n", packet.sensor_id, packet.event_id, packet.event_second, packet.packet_second, packet.packet_microsecond, packet.linktype, packet.packet_length); if ( record->length <= offset ) return; if ( packet.packet_length != reclen ) { printf("ERROR: logged %u but packet_length = %u\n", record->length-offset, packet.packet_length); if ( packet.packet_length < reclen ) { reclen = packet.packet_length; s_off = reclen + offset; } } LogBuffer(record->data+offset, reclen); } static int u2dump(char *file) { u2record record; u2iterator *it = new_iterator(file); memset(&record, 0, sizeof(record)); if(!it) { printf("u2dump: Failed to create new iterator with file: %s\n", file); return -1; } while( get_record(it, &record) == SUCCESS ) { if(record.type == UNIFIED2_IDS_EVENT) event_dump(&record); else if(record.type == UNIFIED2_IDS_EVENT_VLAN) event2_dump(&record); else if(record.type == UNIFIED2_PACKET) packet_dump(&record); else if(record.type == UNIFIED2_IDS_EVENT_IPV6) event6_dump(&record); else if(record.type == UNIFIED2_IDS_EVENT_IPV6_VLAN) event2_6_dump(&record); else if(record.type == UNIFIED2_EXTRA_DATA) extradata_dump(&record); } free_iterator(it); if(record.data) free(record.data); return 0; } int main(int argc, char **argv) { if(argc != 2) { puts("usage: u2eventdump "); return 1; } return u2dump(argv[1]); } snort-2.9.6.0/tools/u2spewfoo/Makefile.am0000644000000000000000000000027711607650044015060 00000000000000AUTOMAKE_OPTIONS=foreign bin_PROGRAMS = u2spewfoo u2spewfoo_SOURCES = u2spewfoo.c u2spewfoo_CFLAGS = @CFLAGS@ $(AM_CFLAGS) EXTRA_DIST = \ u2spewfoo.dsp INCLUDES = @INCLUDES@ @extra_incl@ snort-2.9.6.0/tools/u2spewfoo/Makefile.in0000644000000000000000000005224412260606527015075 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = u2spewfoo$(EXEEXT) subdir = tools/u2spewfoo DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_u2spewfoo_OBJECTS = u2spewfoo-u2spewfoo.$(OBJEXT) u2spewfoo_OBJECTS = $(am_u2spewfoo_OBJECTS) u2spewfoo_LDADD = $(LDADD) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = u2spewfoo_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(u2spewfoo_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(u2spewfoo_SOURCES) DIST_SOURCES = $(u2spewfoo_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ @extra_incl@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign u2spewfoo_SOURCES = u2spewfoo.c u2spewfoo_CFLAGS = @CFLAGS@ $(AM_CFLAGS) EXTRA_DIST = \ u2spewfoo.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/u2spewfoo/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tools/u2spewfoo/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list u2spewfoo$(EXEEXT): $(u2spewfoo_OBJECTS) $(u2spewfoo_DEPENDENCIES) $(EXTRA_u2spewfoo_DEPENDENCIES) @rm -f u2spewfoo$(EXEEXT) $(AM_V_CCLD)$(u2spewfoo_LINK) $(u2spewfoo_OBJECTS) $(u2spewfoo_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/u2spewfoo-u2spewfoo.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< u2spewfoo-u2spewfoo.o: u2spewfoo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(u2spewfoo_CFLAGS) $(CFLAGS) -MT u2spewfoo-u2spewfoo.o -MD -MP -MF $(DEPDIR)/u2spewfoo-u2spewfoo.Tpo -c -o u2spewfoo-u2spewfoo.o `test -f 'u2spewfoo.c' || echo '$(srcdir)/'`u2spewfoo.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/u2spewfoo-u2spewfoo.Tpo $(DEPDIR)/u2spewfoo-u2spewfoo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='u2spewfoo.c' object='u2spewfoo-u2spewfoo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(u2spewfoo_CFLAGS) $(CFLAGS) -c -o u2spewfoo-u2spewfoo.o `test -f 'u2spewfoo.c' || echo '$(srcdir)/'`u2spewfoo.c u2spewfoo-u2spewfoo.obj: u2spewfoo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(u2spewfoo_CFLAGS) $(CFLAGS) -MT u2spewfoo-u2spewfoo.obj -MD -MP -MF $(DEPDIR)/u2spewfoo-u2spewfoo.Tpo -c -o u2spewfoo-u2spewfoo.obj `if test -f 'u2spewfoo.c'; then $(CYGPATH_W) 'u2spewfoo.c'; else $(CYGPATH_W) '$(srcdir)/u2spewfoo.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/u2spewfoo-u2spewfoo.Tpo $(DEPDIR)/u2spewfoo-u2spewfoo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='u2spewfoo.c' object='u2spewfoo-u2spewfoo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(u2spewfoo_CFLAGS) $(CFLAGS) -c -o u2spewfoo-u2spewfoo.obj `if test -f 'u2spewfoo.c'; then $(CYGPATH_W) 'u2spewfoo.c'; else $(CYGPATH_W) '$(srcdir)/u2spewfoo.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/tools/u2boat/0000755000000000000000000000000012260606571012343 500000000000000snort-2.9.6.0/tools/u2boat/u2boat.h0000644000000000000000000000232212260565733013633 00000000000000/* * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2002-2013 Sourcefire, Inc. * Copyright (C) 1998-2002 Martin Roesch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef U2BOAT_H #define U2BOAT_H #include "Unified2_common.h" typedef struct _record { uint32_t type; uint32_t length; uint8_t *data; } u2record; typedef struct _u2iterator { FILE *file; char *filename; u2record current; } u2iterator; #endif snort-2.9.6.0/tools/u2boat/u2boat.c0000644000000000000000000002214512260565733013633 00000000000000/* * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2002-2013 Sourcefire, Inc. * Copyright (C) 1998-2002 Martin Roesch * Author: Ryan Jordan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "u2boat.h" #define FAILURE -1 #define SUCCESS 0 #define PCAP_MAGIC_NUMBER 0xa1b2c3d4 #define PCAP_TIMEZONE 0 #define PCAP_SIGFIGS 0 #define PCAP_SNAPLEN 65535 #define ETHERNET 1 #define PCAP_LINKTYPE ETHERNET #define MAX_U2RECORD_DATA_LENGTH 65536 static int ConvertLog(FILE *input, FILE *output, char *format); static int GetRecord(FILE *input, u2record *rec); static int PcapInitOutput(FILE *output); static int PcapConversion(u2record *rec, FILE *output); static int ConvertLog(FILE *input, FILE *output, char *format) { u2record tmp_record; /* Determine conversion function */ int (* ConvertRecord)(u2record *, FILE *) = NULL; /* This will become an if/else series once more formats are supported. * Callbacks are used so that this comparison only needs to happen once. */ if (strncmp(format, "pcap", 4) == 0) { ConvertRecord = PcapConversion; } if (ConvertRecord == NULL) { fprintf(stderr, "Error setting conversion routine, aborting...\n"); return FAILURE; } /* Initialize the record's data pointer */ tmp_record.data = malloc(MAX_U2RECORD_DATA_LENGTH * sizeof(uint8_t)); if (tmp_record.data == NULL) { fprintf(stderr, "Error allocating memory, aborting...\n"); return FAILURE; } /* Run through input file and convert records */ while ( !(feof(input) || ferror(input) || ferror(output)) ) { if (GetRecord(input, &tmp_record) == FAILURE) { break; } if (ConvertRecord(&tmp_record, output) == FAILURE) { break; } } if (tmp_record.data != NULL) { free(tmp_record.data); tmp_record.data = NULL; } if (ferror(input)) { fprintf(stderr, "Error reading input file, aborting...\n"); return FAILURE; } if (ferror(output)) { fprintf(stderr, "Error reading output file, aborting...\n"); return FAILURE; } return SUCCESS; } /* Create and write the pcap file's global header */ static int PcapInitOutput(FILE *output) { size_t ret; struct pcap_file_header hdr; hdr.magic = PCAP_MAGIC_NUMBER; hdr.version_major = PCAP_VERSION_MAJOR; hdr.version_minor = PCAP_VERSION_MINOR; hdr.thiszone = PCAP_TIMEZONE; hdr.sigfigs = PCAP_SIGFIGS; hdr.snaplen = PCAP_SNAPLEN; hdr.linktype = PCAP_LINKTYPE; ret = fwrite( (void *)&hdr, sizeof(struct pcap_file_header), 1, output ); if (ret < 1) { fprintf(stderr, "Error: Unable to write pcap file header\n"); return FAILURE; } return SUCCESS; } /* Convert a unified2 packet record to pcap format, then dump */ static int PcapConversion(u2record *rec, FILE *output) { Serial_Unified2Packet packet; struct pcap_pkthdr pcap_hdr; uint32_t *field; uint8_t *pcap_data; static int packet_found = 0; /* Ignore IDS Events. We are only interested in Packets. */ if (rec->type != UNIFIED2_PACKET) { return SUCCESS; } /* Initialize the pcap file if this is the first packet */ if (!packet_found) { if (PcapInitOutput(output) == FAILURE) { return FAILURE; } packet_found = 1; } /* Fill out the Serial_Unified2Packet */ memcpy(&packet, rec->data, sizeof(Serial_Unified2Packet)); /* Unified 2 records are always stored in network order. * Convert all fields except packet data to host order */ field = (uint32_t *)&packet; while(field < (uint32_t *)packet.packet_data) { *field = ntohl(*field); field++; } /* Create a pcap packet header */ pcap_hdr.ts.tv_sec = packet.packet_second; pcap_hdr.ts.tv_usec = packet.packet_microsecond; pcap_hdr.caplen = packet.packet_length; pcap_hdr.len = packet.packet_length; /* Write to the pcap file */ pcap_data = rec->data + sizeof(Serial_Unified2Packet) - 4; pcap_dump( (u_char *)output, &pcap_hdr, (u_char *)pcap_data ); return SUCCESS; } /* Retrieve a single unified2 record from input file */ static int GetRecord(FILE *input, u2record *rec) { uint32_t items_read; static uint32_t buffer_size = MAX_U2RECORD_DATA_LENGTH; uint8_t *tmp; if (!input || !rec) return FAILURE; items_read = fread(rec, sizeof(uint32_t), 2, input); if (items_read != 2) { if ( !feof(input) ) /* Not really an error if at EOF */ { fprintf(stderr, "Error: incomplete record.\n"); } return FAILURE; } /* Type and Length are stored in network order */ rec->type = ntohl(rec->type); rec->length = ntohl(rec->length); /* Read in the data portion of the record */ if (rec->length > buffer_size) { tmp = malloc(rec->length * sizeof(uint8_t)); if (tmp == NULL) { fprintf(stderr, "Error: memory allocation failed.\n"); return FAILURE; } else { if (rec->data != NULL) { free(rec->data); } rec->data = tmp; buffer_size = rec->length; } } items_read = fread(rec->data, sizeof(uint8_t), rec->length, input); if (items_read != rec->length) { fprintf(stderr, "Error: incomplete record. %d of %u bytes read.\n", items_read, rec->length); return FAILURE; } return SUCCESS; } int main (int argc, char *argv[]) { char *input_filename = NULL; char *output_filename = NULL; char *output_type = NULL; FILE *input_file = NULL; FILE *output_file = NULL; int c, i, errnum; opterr = 0; /* Use Getopt to parse options */ while ((c = getopt (argc, argv, "t:")) != -1) { switch (c) { case 't': output_type = optarg; break; case '?': if (optopt == 't') fprintf(stderr, "Option -%c requires an argument.\n", optopt); else if (isprint (optopt)) fprintf(stderr, "Unknown option -%c.\n", optopt); return FAILURE; default: abort(); } } /* At this point, there should be two filenames remaining. */ if (optind != (argc - 2)) { fprintf(stderr, "Usage: u2boat [-t type] \n"); return FAILURE; } input_filename = argv[optind]; output_filename = argv[optind+1]; /* Check inputs */ if (input_filename == NULL) { fprintf(stderr, "Error: Input filename must be specified.\n"); return FAILURE; } if (output_type == NULL) { fprintf(stdout, "Defaulting to pcap output.\n"); output_type = "pcap"; } else { for (i = 0; i < (int)strlen(output_type); i++) output_type[i] = tolower(output_type[i]); } if (strcmp(output_type, "pcap")) { fprintf(stderr, "Invalid output type. Valid types are: pcap\n"); return FAILURE; } if (output_filename == NULL) { fprintf(stderr, "Error: Output filename must be specified.\n"); return FAILURE; } /* Open the files */ if ((input_file = fopen(input_filename, "r")) == NULL) { fprintf(stderr, "Unable to open file: %s\n", input_filename); return FAILURE; } if ((output_file = fopen(output_filename, "w")) == NULL) { fprintf(stderr, "Unable to open/create file: %s\n", output_filename); return FAILURE; } ConvertLog(input_file, output_file, output_type); if (fclose(input_file) != 0) { errnum = errno; fprintf(stderr, "Error closing input: %s\n", strerror(errnum)); } if (fclose(output_file) != 0) { errnum = errno; fprintf(stderr, "Error closing output: %s\n", strerror(errnum)); } return 0; } snort-2.9.6.0/tools/u2boat/README.u2boat0000644000000000000000000000106211404013614014322 00000000000000u2boat - Unified2 Binary Output & Alert Tool -------------------------------------------- About ----- The current version of SnortSP lacks support for some output formats that were present in Snort 2.8.X. u2boat aims to fill these gaps by converting Unified2 logs to other formats. Installation ------------ u2boat is made and installed along with snortsp in the same bin directory. Usage ----- $ u2boat [-t type] "type" specifies the type of output u2boat should create. Valid options are: - pcap: Tcpdump format (default) snort-2.9.6.0/tools/u2boat/Makefile.am0000644000000000000000000000036711600174703014317 00000000000000AUTOMAKE_OPTIONS=foreign bin_PROGRAMS = u2boat docdir = ${datadir}/doc/${PACKAGE} u2boat_SOURCES = u2boat.c u2boat.h u2boat_CFLAGS = @CFLAGS@ $(AM_CFLAGS) u2boat_LDADD = -lpcap INCLUDES = @INCLUDES@ @extra_incl@ dist_doc_DATA = README.u2boat snort-2.9.6.0/tools/u2boat/Makefile.in0000644000000000000000000005611612260606526014341 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = u2boat$(EXEEXT) subdir = tools/u2boat DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_doc_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)" PROGRAMS = $(bin_PROGRAMS) am_u2boat_OBJECTS = u2boat-u2boat.$(OBJEXT) u2boat_OBJECTS = $(am_u2boat_OBJECTS) u2boat_DEPENDENCIES = AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = u2boat_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(u2boat_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(u2boat_SOURCES) DIST_SOURCES = $(u2boat_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_doc_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ @extra_incl@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = ${datadir}/doc/${PACKAGE} dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign u2boat_SOURCES = u2boat.c u2boat.h u2boat_CFLAGS = @CFLAGS@ $(AM_CFLAGS) u2boat_LDADD = -lpcap dist_doc_DATA = README.u2boat all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/u2boat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tools/u2boat/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list u2boat$(EXEEXT): $(u2boat_OBJECTS) $(u2boat_DEPENDENCIES) $(EXTRA_u2boat_DEPENDENCIES) @rm -f u2boat$(EXEEXT) $(AM_V_CCLD)$(u2boat_LINK) $(u2boat_OBJECTS) $(u2boat_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/u2boat-u2boat.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< u2boat-u2boat.o: u2boat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(u2boat_CFLAGS) $(CFLAGS) -MT u2boat-u2boat.o -MD -MP -MF $(DEPDIR)/u2boat-u2boat.Tpo -c -o u2boat-u2boat.o `test -f 'u2boat.c' || echo '$(srcdir)/'`u2boat.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/u2boat-u2boat.Tpo $(DEPDIR)/u2boat-u2boat.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='u2boat.c' object='u2boat-u2boat.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(u2boat_CFLAGS) $(CFLAGS) -c -o u2boat-u2boat.o `test -f 'u2boat.c' || echo '$(srcdir)/'`u2boat.c u2boat-u2boat.obj: u2boat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(u2boat_CFLAGS) $(CFLAGS) -MT u2boat-u2boat.obj -MD -MP -MF $(DEPDIR)/u2boat-u2boat.Tpo -c -o u2boat-u2boat.obj `if test -f 'u2boat.c'; then $(CYGPATH_W) 'u2boat.c'; else $(CYGPATH_W) '$(srcdir)/u2boat.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/u2boat-u2boat.Tpo $(DEPDIR)/u2boat-u2boat.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='u2boat.c' object='u2boat-u2boat.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(u2boat_CFLAGS) $(CFLAGS) -c -o u2boat-u2boat.obj `if test -f 'u2boat.c'; then $(CYGPATH_W) 'u2boat.c'; else $(CYGPATH_W) '$(srcdir)/u2boat.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_docDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dist_docDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-dist_docDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/tools/Makefile.am0000644000000000000000000000036312232305217013115 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies if BUILD_CONTROL_SOCKET CONTROL_DIR = control endif if FEAT_FILE_INSPECT FILE_INSPECT_SERVER=file_server endif SUBDIRS = u2boat u2spewfoo $(CONTROL_DIR) $(FILE_INSPECT_SERVER) INCLUDES = @INCLUDES@ snort-2.9.6.0/tools/Makefile.in0000644000000000000000000004455412260606526013150 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = tools DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = u2boat u2spewfoo control file_server DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies @BUILD_CONTROL_SOCKET_TRUE@CONTROL_DIR = control @FEAT_FILE_INSPECT_TRUE@FILE_INSPECT_SERVER = file_server SUBDIRS = u2boat u2spewfoo $(CONTROL_DIR) $(FILE_INSPECT_SERVER) all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tools/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/preproc_rules/0000755000000000000000000000000012260606571012673 500000000000000snort-2.9.6.0/preproc_rules/sensitive-data.rules0000644000000000000000000000243511435274307016614 00000000000000alert tcp $HOME_NET any -> $EXTERNAL_NET [80,20,25,143,110] (msg:"SENSITIVE-DATA Credit Card Numbers"; metadata:service http, service smtp, service ftp-data, service imap, service pop3; sd_pattern:2,credit_card; classtype:sdf; sid:2; gid:138; rev:1;) alert tcp $HOME_NET any -> $EXTERNAL_NET [80,20,25,143,110] (msg:"SENSITIVE-DATA U.S. Social Security Numbers (with dashes)"; metadata:service http, service smtp, service ftp-data, service imap, service pop3; sd_pattern:2,us_social; classtype:sdf; sid:3; gid:138; rev:1;) #alert tcp $HOME_NET any -> $EXTERNAL_NET [80,20,25,143,110] (msg:"SENSITIVE-DATA U.S. Social Security Numbers (w/out dashes)"; metadata:service http, service smtp, service ftp-data, service imap, service pop3; sd_pattern:20,us_social_nodashes; classtype:sdf; sid:4; gid:138; rev:1;) alert tcp $HOME_NET any -> $EXTERNAL_NET [80,20,25,143,110] (msg:"SENSITIVE-DATA Email Addresses"; metadata:service http, service smtp, service ftp-data, service imap, service pop3; sd_pattern:20,email; classtype:sdf; sid:5; gid:138; rev:1;) alert tcp $HOME_NET any -> $EXTERNAL_NET [80,20,25,143,110] (msg:"SENSITIVE-DATA U.S. Phone Numbers"; metadata:service http, service smtp, service ftp-data, service imap, service pop3; sd_pattern:20,(\d{3}) ?\d{3}-\d{4}; classtype:sdf; sid:6; gid:138; rev:1;) snort-2.9.6.0/preproc_rules/decoder.rules0000644000000000000000000004757112243745447015321 00000000000000alert ( msg:"DECODE_NOT_IPV4_DGRAM"; sid:1; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode;) alert ( msg:"DECODE_IPV4_INVALID_HEADER_LEN"; sid:2; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV4_DGRAM_LT_IPHDR"; sid:3; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV4OPT_BADLEN"; sid:4; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV4OPT_TRUNCATED"; sid:5; gid:116; rev:1; metadata:rule-type decode; reference:cve,2005-0048; reference:url,www.microsoft.com/technet/security/bulletin/ms05-019.mspx; classtype:protocol-command-decode;) alert ( msg:"DECODE_IPV4_DGRAM_GT_CAPLEN"; sid:6; gid:116; rev:1; metadata:rule-type decode;classtype:protocol-command-decode; ) alert ( msg:"DECODE_TCP_DGRAM_LT_TCPHDR"; sid:45; gid:116; rev:1; metadata:rule-type decode;classtype:protocol-command-decode; ) alert ( msg:"DECODE_TCP_INVALID_OFFSET"; sid:46; gid:116; rev:1; metadata:rule-type decode; reference:cve,2004-0816; classtype:bad-unknown; ) alert ( msg:"DECODE_TCP_LARGE_OFFSET"; sid:47; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_TCPOPT_BADLEN"; sid:54; gid:116; rev:1; metadata:rule-type decode; reference:bugtraq,14811; classtype:protocol-command-decode; ) alert ( msg:"DECODE_TCPOPT_TRUNCATED"; sid:55; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_TCPOPT_TTCP"; sid:56; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_TCPOPT_OBSOLETE"; sid:57; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_TCPOPT_EXPERIMENT"; sid:58; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_TCPOPT_WSCALE_INVALID"; sid:59; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_UDP_DGRAM_LT_UDPHDR"; sid:95; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_UDP_DGRAM_INVALID_LENGTH"; sid:96; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_UDP_DGRAM_SHORT_PACKET"; sid:97; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_UDP_DGRAM_LONG_PACKET"; sid:98; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMP_DGRAM_LT_ICMPHDR"; sid:105; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMP_DGRAM_LT_TIMESTAMPHDR"; sid:106; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMP_DGRAM_LT_ADDRHDR"; sid:107; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV4_DGRAM_UNKNOWN"; sid:108; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ARP_TRUNCATED"; sid:109; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_EAPOL_TRUNCATED"; sid:110; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_EAPKEY_TRUNCATED"; sid:111; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_EAP_TRUNCATED"; sid:112; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_PPPOE"; sid:120; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_VLAN"; sid:130; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_VLAN_ETHLLC"; sid:131; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_VLAN_OTHER"; sid:132; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_80211_ETHLLC"; sid:133; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_80211_OTHER"; sid:134; gid:116; rev:1; metadata:rule-type decode;classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_TRH"; sid:140; gid:116; rev:1; metadata:rule-type decode;classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_TR_ETHLLC"; sid:141; gid:116; rev:1; metadata:rule-type decode;classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_TR_MR_LEN"; sid:142; gid:116; rev:1; metadata:rule-type decode;classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_TRHMR"; sid:143; gid:116; rev:1; metadata:rule-type decode;classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_TRAFFIC_LOOPBACK"; sid:150; gid:116; rev:1; metadata:rule-type decode;classtype:bad-unknown; ) alert ( msg:"DECODE_BAD_TRAFFIC_SAME_SRCDST"; sid:151; gid:116; rev:1; metadata:rule-type decode; reference:cve,1999-0016; reference:cve,2005-0688; reference:bugtraq,2666; reference:url,www.microsoft.com/technet/security/bulletin/ms05-019.mspx; classtype:bad-unknown; ) alert ( msg:"DECODE_GRE_DGRAM_LT_GREHDR"; sid:160; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_GRE_MULTIPLE_ENCAPSULATION"; sid:161; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_GRE_INVALID_VERSION"; sid:162; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_GRE_INVALID_HEADER"; sid:163; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_GRE_V1_INVALID_HEADER"; sid:164; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_GRE_TRANS_DGRAM_LT_TRANSHDR"; sid:165; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMP_ORIG_IP_TRUNCATED"; sid:250; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_ICMP_ORIG_IP_VER_MISMATCH"; sid:251; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMP_ORIG_DGRAM_LT_ORIG_IP"; sid:252; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMP_ORIG_PAYLOAD_LT_64"; sid:253; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMP_ORIG_PAYLOAD_GT_576"; sid:254; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMP_ORIG_IP_WITH_FRAGOFFSET"; sid:255; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_MIN_TTL"; sid:270; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_IS_NOT"; sid:271; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_TRUNCATED_EXT"; sid:272; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_IPV6_TRUNCATED"; sid:273; gid:116; rev:1; metadata:rule-type decode; classtype:bad-unknown; ) alert ( msg:"DECODE_IPV6_DGRAM_LT_IPHDR"; sid:274; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_DGRAM_GT_CAPLEN"; sid:275; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_DST_ZERO"; sid:276; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_SRC_MULTICAST"; sid:277; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_DST_RESERVED_MULTICAST"; sid:278; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_BAD_OPT_TYPE"; sid:279; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_BAD_MULTICAST_SCOPE"; sid:280; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_BAD_NEXT_HEADER"; sid:281; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_ROUTE_AND_HOPBYHOP"; sid:282; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_TWO_ROUTE_HEADERS"; sid:283; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMPV6_TOO_BIG_BAD_MTU"; sid:285; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMPV6_UNREACHABLE_NON_RFC_2463_CODE"; sid:286; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMPV6_SOLICITATION_BAD_CODE"; sid:287; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMPV6_ADVERT_BAD_CODE"; sid:288; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMPV6_SOLICITATION_BAD_RESERVED"; sid:289; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMPV6_ADVERT_BAD_REACHABLE"; sid:290; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_TUNNELED_IPV4_TRUNCATED"; sid:291; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-dos; reference:cve,2008-2136; reference:bugtraq,29235; ) alert ( msg:"DECODE_IPV6_DSTOPTS_WITH_ROUTING"; sid:292; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IP_MULTIPLE_ENCAPSULATION"; sid:293; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ESP_HEADER_TRUNC"; sid:294; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_BAD_OPT_LEN"; sid:295; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_UNORDERED_EXTENSIONS"; sid:296; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_GTP_MULTIPLE_ENCAPSULATION"; sid:297; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_GTP_BAD_LEN_STR"; sid:298; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_BAD_MPLS"; sid:170; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_BAD_MPLS_LABEL0"; sid:171; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_BAD_MPLS_LABEL1"; sid:172; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_BAD_MPLS_LABEL2"; sid:173; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_BAD_MPLS_LABEL3"; sid:174; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_MPLS_RESERVEDLABEL"; sid:175; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_MPLS_LABEL_STACK"; sid:176; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_TCP_XMAS"; sid: 400; gid: 116; rev: 1; metadata: rule-type decode ; classtype:attempted-recon; reference:bugtraq,7700; reference:cve,2003-0393; ) alert ( msg:"DECODE_TCP_NMAP_XMAS"; sid: 401; gid: 116; rev: 1; metadata: rule-type decode ; classtype:attempted-recon; reference:bugtraq,7700; reference:cve,2003-0393; ) alert ( msg:"DECODE_DOS_NAPTHA"; sid: 402; gid: 116; rev: 1; metadata: rule-type decode ; classtype:attempted-dos; reference:bugtraq,2022; reference:cve,2000-1039; reference:nessus,275; reference:url,razor.bindview.com/publish/advisories/adv_NAPTHA.html; reference:url,www.cert.org/advisories/CA-2000-21.html; reference:url,www.microsoft.com/technet/security/bulletin/MS00-091.mspx; ) alert ( msg:"DECODE_SYN_TO_MULTICAST"; sid: 403; gid: 116; rev: 1; metadata: rule-type decode ; classtype:bad-unknown; ) alert ( msg:"DECODE_ZERO_TTL"; sid: 404; gid: 116; rev: 1; metadata: rule-type decode ; classtype:misc-activity; reference:url,support.microsoft.com/kb/q138268; reference:url,tools.ietf.org/html/rfc1122; ) alert ( msg:"DECODE_BAD_FRAGBITS"; sid: 405; gid: 116; rev: 1; metadata: rule-type decode ; classtype:misc-activity; ) alert ( msg:"DECODE_UDP_IPV6_ZERO_CHECKSUM"; sid:406; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IP4_LEN_OFFSET"; sid:407; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_SRC_THIS_NET"; sid:408; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_DST_THIS_NET"; sid:409; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_SRC_MULTICAST"; sid:410; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_SRC_RESERVED"; sid:411; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_DST_RESERVED"; sid:412; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_SRC_BROADCAST"; sid:413; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_DST_BROADCAST"; sid:414; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ICMP4_DST_MULTICAST"; sid:415; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ICMP4_DST_BROADCAST"; sid:416; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ICMP4_TYPE_OTHER"; sid:418; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_TCP_BAD_URP"; sid:419; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_TCP_SYN_FIN"; sid:420; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_TCP_SYN_RST"; sid:421; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_TCP_MUST_ACK"; sid:422; gid:116; rev:2; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_TCP_NO_SYN_ACK_RST"; sid:423; gid:116; rev:2; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ETH_HDR_TRUNC"; sid:424; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_HDR_TRUNC"; sid:425; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ICMP4_HDR_TRUNC"; sid:426; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ICMP6_HDR_TRUNC"; sid:427; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_MIN_TTL"; sid:428; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP6_ZERO_HOP_LIMIT"; sid:429; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_IP4_DF_OFFSET"; sid:430; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ICMP6_TYPE_OTHER"; sid:431; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ICMP6_DST_MULTICAST"; sid:432; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_TCP_SHAFT_SYNFLOOD"; sid:433; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-dos; reference:cve,2000-0138; ) alert ( msg:"DECODE_ICMP_PING_NMAP"; sid:434; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_ICMPENUM"; sid:435; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_REDIRECT_HOST"; sid:436; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_REDIRECT_NET"; sid:437; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_TRACEROUTE_IPOPTS"; sid:438; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_SOURCE_QUENCH"; sid:439; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_BROADSCAN_SMURF_SCANNER"; sid:440; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_DST_UNREACH_ADMIN_PROHIBITED"; sid:441; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_DST_UNREACH_DST_HOST_PROHIBITED"; sid:442; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_ICMP_DST_UNREACH_DST_NET_PROHIBITED"; sid:443; gid:116; rev:1; metadata:rule-type decode; classtype:attempted-recon; ) alert ( msg:"DECODE_IP_OPTION_SET"; sid:444; gid:116; rev:1; metadata:rule-type decode; classtype: bad-unknown; ) alert ( msg:"DECODE_UDP_LARGE_PACKET"; sid:445; gid:116; rev:1; metadata:rule-type decode; classtype: bad-unknown; ) alert ( msg:"DECODE_TCP_PORT_ZERO"; sid:446; gid:116; rev:1; metadata:rule-type decode; classtype: misc-activity; ) alert ( msg:"DECODE_UDP_PORT_ZERO"; sid:447; gid:116; rev:1; metadata:rule-type decode; classtype: misc-activity; ) alert ( msg:"DECODE_IP_RESERVED_FRAG_BIT"; sid:448; gid:116; rev:1; metadata:rule-type decode; classtype: misc-activity; ) alert ( msg:"DECODE_IP_UNASSIGNED_PROTO"; sid:449; gid:116; rev:1; metadata:rule-type decode; classtype: non-standard-protocol; ) alert ( msg:"DECODE_IP_BAD_PROTO"; sid:450; gid:116; rev:1; metadata:rule-type decode; classtype: non-standard-protocol; ) alert ( msg:"DECODE_ICMP_PATH_MTU_DOS"; sid:451; gid:116; rev:1; metadata:rule-type decode; reference:bugtraq,13124; reference:cve,2004-1060; classtype:attempted-dos;) alert ( msg:"DECODE_ICMP_DOS_ATTEMPT"; sid:452; gid:116; rev:1; metadata:rule-type decode; reference:url,www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.15.3; reference:cve,2006-0454; reference:bugtraq,16532; classtype:denial-of-service;) alert ( msg:"DECODE_IPV6_ISATAP_SPOOF"; sid:453; gid:116; rev:1; metadata:rule-type decode; reference:cve,2010-0812; reference:url,www.microsoft.com/technet/security/bulletin/MS10-029.mspx; classtype:misc-attack; ) alert ( msg:"DECODE_PGM_NAK_OVERFLOW"; sid:454; gid:116; rev:1; metadata:rule-type decode; reference:url,www.microsoft.com/technet/security/bulletin/ms06-052.mspx; reference:cve,2006-3442; reference:bugtraq,19922; classtype:attempted-admin; ) alert ( msg:"DECODE_IGMP_OPTIONS_DOS"; sid:455; gid:116; rev:1; metadata:rule-type decode; reference:url,www.microsoft.com/technet/security/bulletin/ms06-007.mspx; reference:cve,2006-0021; reference:bugtraq,16645; classtype:attempted-dos; ) alert ( msg:"DECODE_IP6_EXCESS_EXT_HDR"; sid:456; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_ICMPV6_UNREACHABLE_NON_RFC_4443_CODE"; sid:457; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_BAD_FRAG_PKT"; sid:458; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ZERO_LENGTH_FRAG"; sid:459; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ICMPV6_SOLICITATION_BAD_CODE"; sid:460; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_IPV6_ROUTE_ZERO"; sid:461; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ERSPAN_HDR_VERSION_MISMATCH_STR"; sid:462; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ERSPAN2_DGRAM_LT_HDR_STR"; sid:463; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_ERSPAN3_DGRAM_LT_HDR_STR"; sid:464; gid:116; rev:1; metadata:rule-type decode; classtype:protocol-command-decode; ) alert ( msg:"DECODE_AUTH_HDR_TRUNC"; sid:465; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) alert ( msg:"DECODE_AUTH_HDR_BAD_LEN"; sid:466; gid:116; rev:1; metadata:rule-type decode; classtype:misc-activity; ) snort-2.9.6.0/preproc_rules/preprocessor.rules0000644000000000000000000012303112232305217016405 00000000000000alert ( msg: "TAG_LOG_PKT"; sid: 1; gid: 2; rev: 1; metadata: rule-type preproc ; classtype:not-suspicious; ) alert ( msg: "BO_TRAFFIC_DETECT"; sid: 1; gid: 105; rev: 1; metadata: rule-type preproc, policy balanced-ips drop, policy security-ips drop ; classtype:trojan-activity; reference:cve,1999-0660; ) alert ( msg: "BO_CLIENT_TRAFFIC_DETECT"; sid: 2; gid: 105; rev: 1; metadata: rule-type preproc, policy balanced-ips drop, policy security-ips drop ; classtype:trojan-activity; reference:cve,1999-0660; ) alert ( msg: "BO_SERVER_TRAFFIC_DETECT"; sid: 3; gid: 105; rev: 1; metadata: rule-type preproc, policy balanced-ips drop, policy security-ips drop ; classtype:trojan-activity; reference:cve,1999-0660;) alert ( msg: "BO_SNORT_BUFFER_ATTACK"; sid: 4; gid: 105; rev: 1; metadata: rule-type preproc, policy balanced-ips drop, policy security-ips drop ; classtype:trojan-activity; reference:cve,2005-3252; ) alert ( msg: "RPC_FRAG_TRAFFIC"; sid: 1; gid: 106; rev: 1; metadata: rule-type preproc, service sunrpc ; classtype:protocol-command-decode; ) alert ( msg: "RPC_MULTIPLE_RECORD"; sid: 2; gid: 106; rev: 1; metadata: rule-type preproc, service sunrpc ; classtype:protocol-command-decode; ) alert ( msg: "RPC_LARGE_FRAGSIZE"; sid: 3; gid: 106; rev: 1; metadata: rule-type preproc, service sunrpc, policy security-ips alert ; classtype:bad-unknown; ) alert ( msg: "RPC_INCOMPLETE_SEGMENT"; sid: 4; gid: 106; rev: 1; metadata: rule-type preproc, service sunrpc, policy security-ips alert ; classtype:bad-unknown; ) alert ( msg: "RPC_ZERO_LENGTH_FRAGMENT"; sid: 5; gid: 106; rev: 1; metadata: rule-type preproc, service sunrpc, policy security-ips alert ; classtype:bad-unknown; ) alert ( msg: "ARPSPOOF_UNICAST_ARP_REQUEST"; sid: 1; gid: 112; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) alert ( msg: "ARPSPOOF_ETHERFRAME_ARP_MISMATCH_SRC"; sid: 2; gid: 112; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "ARPSPOOF_ETHERFRAME_ARP_MISMATCH_DST"; sid: 3; gid: 112; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "ARPSPOOF_ARP_CACHE_OVERWRITE_ATTACK"; sid: 4; gid: 112; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "HI_CLIENT_ASCII"; sid: 1; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:not-suspicious; reference:cve,2009-1535; reference:url,www.microsoft.com/technet/security/bulletin/ms09-020.mspx; reference:url,docs.idsresearch.org/http_ids_evasions.pdf; ) alert ( msg: "HI_CLIENT_DOUBLE_DECODE"; sid: 2; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:not-suspicious; reference:cve,2009-1122; reference:url,www.microsoft.com/technet/security/bulletin/ms09-020.mspx; ) alert ( msg: "HI_CLIENT_U_ENCODE"; sid: 3; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:not-suspicious; ) alert ( msg: "HI_CLIENT_BARE_BYTE"; sid: 4; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:not-suspicious; ) alert ( msg: "HI_CLIENT_UTF_8"; sid: 6; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:not-suspicious; reference:cve,2008-2938; reference:cve,2009-1535; reference:url,www.microsoft.com/technet/security/bulletin/ms09-020.mspx; ) alert ( msg: "HI_CLIENT_IIS_UNICODE"; sid: 7; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:unknown; reference:cve,2009-1535; ) alert ( msg: "HI_CLIENT_MULTI_SLASH"; sid: 8; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:not-suspicious; ) alert ( msg: "HI_CLIENT_IIS_BACKSLASH"; sid: 9; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:not-suspicious; ) alert ( msg: "HI_CLIENT_SELF_DIR_TRAV"; sid: 10; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:unknown; ) alert ( msg: "HI_CLIENT_DIR_TRAV"; sid: 11; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:unknown; reference:cve,2001-0333; reference:cve,2002-1744; reference:cve,2008-5515; ) alert ( msg: "HI_CLIENT_APACHE_WS"; sid: 12; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:unknown; ) alert ( msg: "HI_CLIENT_IIS_DELIMITER"; sid: 13; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:unknown; ) alert ( msg: "HI_CLIENT_NON_RFC_CHAR"; sid: 14; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:bad-unknown; ) alert ( msg: "HI_CLIENT_OVERSIZE_DIR"; sid: 15; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:bad-unknown; reference:cve,2007-0774; reference:bugtraq,22791; reference:cve,2010-3281; reference:bugtraq,43338; reference:cve,2011-5007; ) alert ( msg: "HI_CLIENT_LARGE_CHUNK"; sid: 16; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:attempted-admin; ) alert ( msg: "HI_CLIENT_PROXY_USE"; sid: 17; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:protocol-command-decode; ) alert ( msg: "HI_CLIENT_WEBROOT_DIR"; sid: 18; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:unknown; reference:cve,2001-0333; reference:cve,2002-1744; reference:cve,2008-5515; ) alert ( msg: "HI_CLIENT_LONG_HEADER"; sid: 19; gid: 119; rev: 1; metadata: rule-type preproc, service http ; classtype:bad-unknown; reference:cve,2009-4873; ) alert ( msg: "HI_CLIENT_MAX_HEADERS"; sid: 20; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_MULTIPLE_CONTLEN"; sid: 21; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CHUNK_SIZE_MISMATCH"; sid: 22; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_INVALID_TRUEIP"; sid:23; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_MULTIPLE_HOST_HDRS"; sid:24; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_LONG_HOSTNAME"; sid:25; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_EXCEEDS_SPACES"; sid:26; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:attempted-dos;reference:cve,2004-0942; ) alert ( msg: "HI_CLIENT_CONSECUTIVE_SMALL_CHUNK_SIZES"; sid: 27; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_UNBOUNDED POST"; sid: 28; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_MULTIPLE_TRUEIP_IN_SESSION"; sid: 29; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_BOTH_TRUEIP_XFF_HDRS"; sid: 30; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_UNKNOWN_METHOD"; sid: 31; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_SIMPLE_REQUEST"; sid: 32; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_UNESCAPED_SPACE_URI"; sid: 33; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLIENT_PIPELINE_MAX "; sid: 34; gid: 119; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_ANOM_SERVER_ALERT"; sid: 1; gid: 120; rev: 1; metadata: rule-type preproc, service http ; classtype:unknown; ) alert ( msg: "HI_SERVER_INVALID_STATCODE"; sid: 2; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_SERVER_NO_CONTLEN"; sid: 3; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_SERVER_UTF_NORM_FAIL"; sid: 4; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_SERVER_UTF7"; sid: 5; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_SERVER_DECOMPR_FAILED"; sid: 6; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_SERVER_CONSECUTIVE_SMALL_CHUNK_SIZES"; sid: 7; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_CLISRV_MSG_SIZE_EXCEPTION"; sid: 8; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_SERVER_JS_OBFUSCATION_EXCD"; sid: 9; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_SERVER_JS_EXCESS_WS"; sid: 10; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "HI_SERVER_MIXED_ENCODINGS "; sid: 11; gid: 120; rev: 1; metadata: rule-type preproc ; classtype:unknown; ) alert ( msg: "PSNG_TCP_PORTSCAN"; sid: 1; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_TCP_DECOY_PORTSCAN"; sid: 2; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_TCP_PORTSWEEP"; sid: 3; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_TCP_DISTRIBUTED_PORTSCAN"; sid: 4; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_TCP_FILTERED_PORTSCAN"; sid: 5; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_TCP_FILTERED_DECOY_PORTSCAN"; sid: 6; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_TCP_PORTSWEEP_FILTERED"; sid: 7; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_TCP_FILTERED_DISTRIBUTED_PORTSCAN"; sid: 8; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_IP_PORTSCAN"; sid: 9; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_IP_DECOY_PORTSCAN"; sid: 10; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_IP_PORTSWEEP"; sid: 11; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_IP_DISTRIBUTED_PORTSCAN"; sid: 12; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_IP_FILTERED_PORTSCAN"; sid: 13; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_IP_FILTERED_DECOY_PORTSCAN"; sid: 14; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon;) alert ( msg: "PSNG_IP_PORTSWEEP_FILTERED"; sid: 15; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_IP_FILTERED_DISTRIBUTED_PORTSCAN"; sid: 16; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_UDP_PORTSCAN"; sid: 17; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_UDP_DECOY_PORTSCAN"; sid: 18; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_UDP_PORTSWEEP"; sid: 19; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_UDP_DISTRIBUTED_PORTSCAN"; sid: 20; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_UDP_FILTERED_PORTSCAN"; sid: 21; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_UDP_FILTERED_DECOY_PORTSCAN"; sid: 22; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_UDP_PORTSWEEP_FILTERED"; sid: 23; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_UDP_FILTERED_DISTRIBUTED_PORTSCAN"; sid: 24; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_ICMP_PORTSWEEP"; sid: 25; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_ICMP_PORTSWEEP_FILTERED"; sid: 26; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "PSNG_OPEN_PORT"; sid: 27; gid: 122; rev: 1; metadata: rule-type preproc ; classtype:attempted-recon; ) alert ( msg: "FRAG3_IPOPTIONS"; sid: 1; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) alert ( msg: "FRAG3_TEARDROP"; sid: 2; gid: 123; rev: 1; metadata: rule-type preproc ; reference:cve,1999-0015; reference:bugtraq,124; classtype:attempted-dos; ) alert ( msg: "FRAG3_SHORT_FRAG"; sid: 3; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) alert ( msg: "FRAG3_ANOMALY_OVERSIZE"; sid: 4; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:attempted-dos; ) alert ( msg: "FRAG3_ANOMALY_ZERO"; sid: 5; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:attempted-dos; ) alert ( msg: "FRAG3_ANOMALY_BADSIZE_SM"; sid: 6; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) alert ( msg: "FRAG3_ANOMALY_BADSIZE_LG"; sid: 7; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) alert ( msg: "FRAG3_ANOMALY_OVLP"; sid: 8; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) #alert ( msg: "FRAG3_IPV6_BSD_ICMP_FRAG"; sid: 9; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:attempted-admin; reference:cve,2007-1365; ) #alert ( msg: "FRAG3_IPV6_BAD_FRAG_PKT"; sid: 10; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:attempted-admin; reference:cve,2007-1365; ) alert ( msg: "FRAG3_MIN_TTL"; sid: 11; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "FRAG3_EXCESSIVE_OVERLAP"; sid: 12; gid: 123; rev: 1; metadata: rule-type preproc ; classtype:attempted-dos; ) alert ( msg: "FRAG3_TINY_FAGMENT"; sid: 13; gid: 123; rev: 1; metadata: rule-type preproc ; reference:cve,2005-0209; classtype:attempted-dos; ) alert ( msg: "SMTP_COMMAND_OVERFLOW"; sid: 1; gid: 124; rev: 1; metadata: rule-type preproc, service smtp, policy security-ips drop ; classtype:attempted-admin; reference:cve,2001-0260; reference:cve,2005-0560; reference:url,www.microsoft.com/technet/security/bulletin/ms05-021.mspx; ) alert ( msg: "SMTP_DATA_HDR_OVERFLOW"; sid: 2; gid: 124; rev: 1; metadata: rule-type preproc, service smtp, policy security-ips drop ; classtype:attempted-admin; reference:cve,2002-1337; reference:cve,2010-4344; ) alert ( msg: "SMTP_RESPONSE_OVERFLOW"; sid: 3; gid: 124; rev: 1; metadata: rule-type preproc, service smtp, policy security-ips drop ; classtype:attempted-user; reference:cve,2002-1090; ) alert ( msg: "SMTP_SPECIFIC_CMD_OVERFLOW"; sid: 4; gid: 124; rev: 1; metadata: rule-type preproc, service smtp, policy security-ips drop ; classtype:attempted-admin; reference:cve,2005-0560; reference:url,www.microsoft.com/technet/security/bulletin/ms05-021.mspx; ) alert ( msg: "SMTP_UNKNOWN_CMD"; sid: 5; gid: 124; rev: 1; metadata: rule-type preproc, service smtp ; classtype:protocol-command-decode; ) alert ( msg: "SMTP_ILLEGAL_CMD"; sid: 6; gid: 124; rev: 1; metadata: rule-type preproc, service smtp ; classtype:protocol-command-decode; ) alert ( msg: "SMTP_HEADER_NAME_OVERFLOW"; sid: 7; gid: 124; rev: 1; metadata: rule-type preproc, service smtp, policy security-ips drop ; classtype:attempted-admin; reference:cve,2004-0105; ) alert ( msg: "SMTP_XLINK2STATE_OVERFLOW"; sid: 8; gid: 124; rev: 1; metadata: rule-type preproc, service smtp, policy security-ips drop ; classtype:attempted-admin; reference:cve,2005-0560; reference:url,www.microsoft.com/technet/security/bulletin/ms05-021.mspx; ) alert ( msg: "SMTP_B64_DECODING_FAILED"; sid: 10; gid: 124; rev: 1; metadata: rule-type preproc, service smtp ; classtype:unknown; ) alert ( msg: "SMTP_QP_DECODING_FAILED"; sid: 11; gid: 124; rev: 1; metadata: rule-type preproc, service smtp ; classtype:unknown; ) #alert ( msg: "SMTP_BITENC_DECODING_FAILED"; sid: 12; gid: 124; rev: 1; metadata: rule-type preproc, service smtp ; classtype:unknown; ) alert ( msg: "SMTP_UU_DECODING_FAILED"; sid: 13; gid: 124; rev: 1; metadata: rule-type preproc, service smtp ; classtype:unknown; ) alert ( msg: "SMTP_AUTH_ATTACK"; sid: 14; gid: 124; rev: 1; metadata: rule-type preproc, service smtp ; classtype:unknown; ) alert ( msg: "FTPP_FTP_TELNET_CMD"; sid: 1; gid: 125; rev: 1; metadata: rule-type preproc, service ftp ; classtype:protocol-command-decode; reference:cve,2010-3867; reference:cve,2010-3972; reference:cve,2010-4221; reference:url,www.microsoft.com/technet/security/bulletin/MS11-004.mspx; ) alert ( msg: "FTPP_FTP_INVALID_CMD"; sid: 2; gid: 125; rev: 1; metadata: rule-type preproc, service ftp ; classtype:bad-unknown; reference:cve,2010-4221; ) alert ( msg: "FTPP_FTP_PARAMETER_LENGTH_OVERFLOW"; sid: 3; gid: 125; rev: 1; metadata: rule-type preproc, service ftp, policy security-ips drop ; classtype:attempted-admin; reference:cve,2004-0286; reference:url,www.kb.cert.org/vuls/id/276653; reference:cve,1999-0368; reference:bugtraq,113; reference:bugtraq,2242; reference:cve,2006-5815; reference:bugtraq,20992; ) alert ( msg: "FTPP_FTP_MALFORMED_PARAMETER"; sid: 4; gid: 125; rev: 1; metadata: rule-type preproc, service ftp ; classtype:protocol-command-decode; ) alert ( msg: "FTPP_FTP_PARAMETER_STR_FORMAT"; sid: 5; gid: 125; rev: 1; metadata: rule-type preproc, service ftp, policy security-ips drop ; classtype:attempted-admin; reference:cve,2000-0573; ) alert ( msg: "FTPP_FTP_RESPONSE_LENGTH_OVERFLOW"; sid: 6; gid: 125; rev: 1; metadata: rule-type preproc, service ftp, policy security-ips drop ; classtype:attempted-user; reference:cve,2007-3161; reference:cve,2010-1465; reference:url,www.kb.cert.org/vuls/id/276653; ) alert ( msg: "FTPP_FTP_ENCRYPTED"; sid: 7; gid: 125; rev: 1; metadata: rule-type preproc, service ftp ; classtype:protocol-command-decode; ) alert ( msg: "FTPP_FTP_BOUNCE"; sid: 8; gid: 125; rev: 1; metadata: rule-type preproc, service ftp ; classtype:bad-unknown; reference:cve,1999-0017; reference:url,www.kb.cert.org/vuls/id/276653; ) alert ( msg: "FTPP_FTP_EVASIVE_TELNET_CMD"; sid: 9; gid: 125; rev: 1; metadata: rule-type preproc, service ftp ; classtype:bad-unknown; ) alert ( msg: "FTPP_TELNET_AYT_OVERFLOW"; sid: 1; gid: 126; rev: 1; metadata: rule-type preproc, service telnet, policy security-ips drop ; classtype:attempted-admin; reference:cve,2001-0554; ) alert ( msg: "FTPP_TELNET_ENCRYPTED"; sid: 2; gid: 126; rev: 1; metadata: rule-type preproc, service telnet ; classtype:protocol-command-decode;) alert ( msg: "FTPP_TELNET_SUBNEG_BEGIN_NO_END"; sid: 3; gid: 126; rev: 1; metadata: rule-type preproc, service telnet ; classtype:protocol-command-decode; ) alert ( msg: "SSH_EVENT_RESPOVERFLOW"; sid: 1; gid: 128; rev: 1; metadata: rule-type preproc, service ssh, policy security-ips drop ; reference:cve,2002-0639; reference:cve,2002-0640; classtype:attempted-admin;) alert ( msg: "SSH_EVENT_CRC32"; sid: 2; gid: 128; rev: 1; metadata: rule-type preproc, service ssh, policy security-ips drop ; reference:cve,2002-1024; reference:cve,2002-1547; reference:cve,2006-2971; reference:cve,2007-1051; reference:cve,2007-4654; classtype:attempted-admin;) alert ( msg: "SSH_EVENT_SECURECRT"; sid: 3; gid: 128; rev: 1; metadata: rule-type preproc, service ssh, policy security-ips drop ; reference:cve,2001-1466; reference:cve,2002-1059; classtype:attempted-admin;) alert ( msg: "SSH_EVENT_PROTOMISMATCH"; sid: 4; gid: 128; rev: 1; metadata: rule-type preproc, service ssh ; classtype:non-standard-protocol;) alert ( msg: "SSH_EVENT_WRONGDIR"; sid: 5; gid: 128; rev: 1; metadata: rule-type preproc, service ssh ; classtype:non-standard-protocol;) alert ( msg: "SSH_EVENT_PAYLOAD_SIZE"; sid: 6; gid: 128; rev: 1; metadata: rule-type preproc, service ssh ; classtype:bad-unknown;) alert ( msg: "SSH_EVENT_VERSION"; sid: 7; gid: 128; rev: 1; metadata: rule-type preproc, service ssh ; classtype:non-standard-protocol;) alert ( msg: "STREAM5_SYN_ON_EST"; sid: 1; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_DATA_ON_SYN"; sid: 2; gid: 129; rev: 1; metadata: rule-type preproc ; reference: cve,2009-1157; reference: bugtraq, 34429; classtype:protocol-command-decode; ) alert ( msg: "STREAM5_DATA_ON_CLOSED"; sid: 3; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) alert ( msg: "STREAM5_BAD_TIMESTAMP"; sid: 4; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; reference:cve,2009-1925; ) alert ( msg: "STREAM5_BAD_SEGMENT"; sid: 5; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_WINDOW_TOO_LARGE"; sid: 6; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_EXCESSIVE_TCP_OVERLAPS"; sid: 7; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_DATA_AFTER_RESET"; sid: 8; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) alert ( msg: "STREAM5_SESSION_HIJACKED_CLIENT"; sid: 9; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:attempted-user; ) alert ( msg: "STREAM5_SESSION_HIJACKED_SERVER"; sid: 10; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:attempted-user; ) alert ( msg: "STREAM5_DATA_WITHOUT_FLAGS"; sid: 11; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:protocol-command-decode; ) alert ( msg: "STREAM5_SMALL_SEGMENT"; sid: 12; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_4WAY_HANDSHAKE"; sid: 13; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_NO_TIMESTAMP"; sid: 14; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_BAD_RST"; sid: 15; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_BAD_FIN"; sid: 16; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_BAD_ACK"; sid: 17; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_DATA_AFTER_RST_RCVD"; sid: 18; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "STREAM5_WINDOW_SLAM"; sid: 19; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; reference:cve,2013-0075; reference:url,technet.microsoft.com/en-us/security/bulletin/ms13-018; ) alert ( msg: "STREAM5_NO_3WHS"; sid: 20; gid: 129; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "DNS_EVENT_OBSOLETE_TYPES"; sid: 1; gid: 131; rev: 1; metadata: rule-type preproc, service dns ; classtype:protocol-command-decode; ) alert ( msg: "DNS_EVENT_EXPERIMENTAL_TYPES"; sid: 2; gid: 131; rev: 1; metadata: rule-type preproc, service dns ; classtype:protocol-command-decode; ) alert ( msg: "DNS_EVENT_RDATA_OVERFLOW"; sid: 3; gid: 131; rev: 1; metadata: rule-type preproc, service dns, policy security-ips drop ; classtype:attempted-admin; reference:cve,2006-3441; reference:url,www.microsoft.com/technet/security/bulletin/ms06-041.mspx; ) alert ( msg: "DCE2_EVENT__MEMCAP"; sid: 1; gid: 133; rev: 1; metadata: rule-type preproc ; classtype: attempted-dos; ) alert ( msg: "DCE2_EVENT__SMB_BAD_NBSS_TYPE"; sid: 2; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_BAD_TYPE"; sid: 3; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_BAD_ID"; sid: 4; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_BAD_WCT"; sid: 5; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_BAD_BCC"; sid: 6; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_BAD_FORMAT"; sid: 7; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_BAD_OFF"; sid: 8; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_TDCNT_ZERO"; sid: 9; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_NB_LT_SMBHDR"; sid: 10; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_NB_LT_COM"; sid: 11; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_NB_LT_BCC"; sid: 12; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_NB_LT_DSIZE"; sid: 13; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_TDCNT_LT_DSIZE"; sid: 14; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_DSENT_GT_TDCNT"; sid: 15; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_BCC_LT_DSIZE"; sid: 16; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_INVALID_DSIZE"; sid: 17; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_EXCESSIVE_TREE_CONNECTS"; sid: 18; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_EXCESSIVE_READS"; sid: 19; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_EXCESSIVE_CHAINING"; sid: 20; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_MULT_CHAIN_SS"; sid: 21; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_MULT_CHAIN_TC"; sid: 22; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_CHAIN_SS_LOGOFF"; sid: 23; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_CHAIN_TC_TDIS"; sid: 24; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_CHAIN_OPEN_CLOSE"; sid: 25; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_INVALID_SHARE"; sid: 26; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_BAD_MAJ_VERSION"; sid: 27; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_BAD_MIN_VERSION"; sid: 28; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_BAD_PDU_TYPE"; sid: 29; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_FLEN_LT_HDR"; sid: 30; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_FLEN_LT_SIZE"; sid: 31; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_ZERO_CTX_ITEMS"; sid: 32; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_ZERO_TSYNS"; sid: 33; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_FRAG_LT_MAX_XMIT_FRAG"; sid: 34; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_FRAG_GT_MAX_XMIT_FRAG"; sid: 35; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_ALTER_CHANGE_BYTE_ORDER"; sid: 36; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_FRAG_DIFF_CALL_ID"; sid: 37; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_FRAG_DIFF_OPNUM"; sid: 38; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CO_FRAG_DIFF_CTX_ID"; sid: 39; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CL_BAD_MAJ_VERSION"; sid: 40; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CL_BAD_PDU_TYPE"; sid: 41; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CL_DATA_LT_HDR"; sid: 42; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__CL_BAD_SEQ_NUM"; sid: 43; gid: 133; rev: 1; metadata: rule-type preproc, service dcerpc ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_DCNT_ZERO"; sid: 48; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_DCNT_MISMATCH"; sid: 49; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_MAX_REQS_EXCEEDED"; sid: 50; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_REQS_SAME_MID"; sid: 51; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED"; sid: 52; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_DEPR_COMMAND_USED"; sid: 53; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED"; sid: 54; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_INVALID_SETUP_COUNT"; sid: 55; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_MULTIPLE_NEGOTIATIONS"; sid: 56; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS"; sid: 57; gid: 133; rev: 1; metadata: rule-type preproc, service netbios-ssn ; classtype: bad-unknown; reference:url,msdn.microsoft.com/en-us/library/cc201989.aspx; ) alert ( msg: "PPM_EVENT_RULE_TREE_DISABLED"; sid: 1; gid: 134; rev: 1; metadata: rule-type preproc ; classtype: not-suspicious; ) alert ( msg: "PPM_EVENT_RULE_TREE_ENABLED"; sid: 2; gid: 134; rev: 1; metadata: rule-type preproc ; classtype: not-suspicious; ) alert ( msg: "PPM_EVENT_PACKET_ABORTED"; sid: 3; gid: 134; rev: 1; metadata: rule-type preproc ; classtype: not-suspicious; ) alert ( msg: "INTERNAL_EVENT_SYN_RECEIVED"; sid: 1; gid: 135; rev: 1; metadata: rule-type preproc ; classtype:tcp-connection; ) alert ( msg: "INTERNAL_EVENT_SESSION_ADD"; sid: 2; gid: 135; rev: 1; metadata: rule-type preproc ; classtype:tcp-connection; ) alert ( msg: "INTERNAL_EVENT_SESSION_DEL"; sid: 3; gid: 135; rev: 1; metadata: rule-type preproc ; classtype:tcp-connection; ) alert ( msg: "REPUTATION_EVENT_BLACKLIST"; sid: 1; gid: 136; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "REPUTATION_EVENT_WHITELIST"; sid: 2; gid: 136; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SSL_INVALID_CLIENT_HELLO"; sid: 1; gid: 137; rev: 2; metadata: rule-type preproc ; classtype:bad-unknown; reference:url,technet.microsoft.com/en-us/security/bulletin/ms04-011; reference:cve,2004-0120; reference:bugtraq,10115; ) alert ( msg: "SSL_INVALID_SERVER_HELLO"; sid: 2; gid: 137; rev: 2; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SDF_COMBO_ALERT"; sid: 1; gid: 139; rev: 1; metadata: rule-type preproc ; classtype:sdf; ) alert ( msg: "SIP_EVENT_MAX_SESSIONS"; sid: 1; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_EMPTY_REQUEST_URI"; sid: 2; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; reference:cve,2007-1306; ) alert ( msg: "SIP_EVENT_BAD_URI"; sid: 3; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_EMPTY_CALL_ID"; sid: 4; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_BAD_CALL_ID"; sid: 5; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_BAD_CSEQ_NUM"; sid: 6; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_BAD_CSEQ_NAME"; sid: 7; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; reference:cve,2006-3524; ) alert ( msg: "SIP_EVENT_EMPTY_FROM"; sid: 8; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_BAD_FROM"; sid: 9; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_EMPTY_TO"; sid: 10; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_BAD_TO"; sid: 11; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_EMPTY_VIA"; sid: 12; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; reference:bugtraq,25446; ) alert ( msg: "SIP_EVENT_BAD_VIA"; sid: 13; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_EMPTY_CONTACT"; sid: 14; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_BAD_CONTACT"; sid: 15; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_BAD_CONTENT_LEN"; sid: 16; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_MULTI_MSGS"; sid: 17; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_MISMATCH_CONTENT_LEN"; sid: 18; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_INVALID_CSEQ_NAME"; sid: 19; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; reference:cve,2006-3524; ) alert ( msg: "SIP_EVENT_AUTH_INVITE_REPLAY_ATTACK"; sid: 20; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_AUTH_INVITE_DIFF_SESSION"; sid: 21; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_BAD_STATUS_CODE"; sid: 22; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_EMPTY_CONTENT_TYPE"; sid: 23; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; reference:bugtraq,25300; ) alert ( msg: "SIP_EVENT_INVALID_VERSION"; sid: 24; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_MISMATCH_METHOD"; sid: 25; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_UNKOWN_METHOD"; sid: 26; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "SIP_EVENT_MAX_DIALOGS_IN_A_SESSION"; sid: 27; gid: 140; rev: 1; metadata: rule-type preproc ; classtype:bad-unknown; ) alert ( msg: "IMAP_UNKNOWN_CMD"; sid: 1; gid: 141; rev: 1; metadata: rule-type preproc, service pop ; classtype:protocol-command-decode; ) alert ( msg: "IMAP_UNKNOWN_RESP"; sid: 2; gid: 141; rev: 1; metadata: rule-type preproc, service pop ; classtype:protocol-command-decode; ) alert ( msg: "IMAP_MEMCAP_EXCEEDED"; sid: 3; gid: 141; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) alert ( msg: "IMAP_B64_DECODING_FAILED"; sid: 4; gid: 141; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) alert ( msg: "IMAP_QP_DECODING_FAILED"; sid: 5; gid: 141; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) #alert ( msg: "IMAP_BITENC_DECODING_FAILED"; sid: 6; gid: 141; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) alert ( msg: "IMAP_UU_DECODING_FAILED"; sid: 7; gid: 141; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) alert ( msg: "POP_UNKNOWN_CMD"; sid: 1; gid: 142; rev: 1; metadata: rule-type preproc, service pop ; classtype:protocol-command-decode; ) alert ( msg: "POP_UNKNOWN_RESP"; sid: 2; gid: 142; rev: 1; metadata: rule-type preproc, service pop ; classtype:protocol-command-decode; ) alert ( msg: "POP_MEMCAP_EXCEEDED"; sid: 3; gid: 142; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) alert ( msg: "POP_B64_DECODING_FAILED"; sid: 4; gid: 142; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) alert ( msg: "POP_QP_DECODING_FAILED"; sid: 5; gid: 142; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) #alert ( msg: "POP_BITENC_DECODING_FAILED"; sid: 6; gid: 142; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) alert ( msg: "POP_UU_DECODING_FAILED"; sid: 7; gid: 142; rev: 1; metadata: rule-type preproc, service pop ; classtype:unknown; ) alert ( msg: "GTP_EVENT_BAD_MSG_LEN"; sid: 1; gid: 143; rev: 1; metadata: rule-type preproc; classtype:bad-unknown; ) alert ( msg: "GTP_EVENT_BAD_IE_LEN"; sid: 2; gid: 143; rev: 1; metadata: rule-type preproc; classtype:bad-unknown; ) alert ( msg: "GTP_EVENT_OUT_OF_ORDER_IE"; sid: 3; gid: 143; rev: 1; metadata: rule-type preproc; classtype:bad-unknown; ) alert ( msg: "MODBUS_BAD_LENGTH"; sid:1; gid: 144; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) alert ( msg: "MODBUS_BAD_PROTO_ID"; sid:2; gid: 144; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) alert ( msg: "MODBUS_RESERVED_FUNCTION"; sid:3; gid: 144; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) alert ( msg: "DNP3_BAD_CRC"; sid:1; gid:145; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) alert ( msg: "DNP3_DROPPED_FRAME"; sid:2; gid:145; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) alert ( msg: "DNP3_DROPPED_SEGMENT"; sid:3; gid:145; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) alert ( msg: "DNP3_REASSEMBLY_BUFFER_CLEARED"; sid:4; gid:145; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) alert ( msg: "DNP3_RESERVED_ADDRESS"; sid:5; gid:145; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) alert ( msg: "DNP3_RESERVED_FUNCTION"; sid:6; gid:145; rev: 1; metadata: rule-type preproc; classtype:protocol-command-decode; ) snort-2.9.6.0/preproc_rules/Makefile.am0000644000000000000000000000015511326435735014654 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies EXTRA_DIST = preprocessor.rules decoder.rules sensitive-data.rules snort-2.9.6.0/preproc_rules/Makefile.in0000644000000000000000000003002412260606517014657 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = preproc_rules DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies EXTRA_DIST = preprocessor.rules decoder.rules sensitive-data.rules all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign preproc_rules/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign preproc_rules/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/m4/0000755000000000000000000000000012260606570010326 500000000000000snort-2.9.6.0/m4/libprelude.m40000644000000000000000000001665210234500325012637 00000000000000dnl Autoconf macros for libprelude dnl $id$ # Modified for LIBPRELUDE -- Yoann Vandoorselaere # Modified for LIBGNUTLS -- nmav # Configure paths for LIBGCRYPT # Shamelessly stolen from the one of XDELTA by Owen Taylor # Werner Koch 99-12-09 dnl AM_PATH_LIBPRELUDE([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) dnl Test for libprelude, and define LIBPRELUDE_PREFIX, LIBPRELUDE_CFLAGS, LIBPRELUDE_PTHREAD_CFLAGS, dnl LIBPRELUDE_LDFLAGS, and LIBPRELUDE_LIBS dnl AC_DEFUN([AM_PATH_LIBPRELUDE], [dnl dnl Get the cflags and libraries from the libprelude-config script dnl AC_ARG_WITH(libprelude-prefix, [ --with-libprelude-prefix=PFX Prefix where libprelude is installed (optional)], libprelude_config_prefix="$withval", libprelude_config_prefix="") if test x$libprelude_config_prefix != x ; then if test x${LIBPRELUDE_CONFIG+set} != xset ; then LIBPRELUDE_CONFIG=$libprelude_config_prefix/bin/libprelude-config fi fi AC_PATH_PROG(LIBPRELUDE_CONFIG, libprelude-config, no) min_libprelude_version=ifelse([$1], ,0.1.0,$1) AC_MSG_CHECKING(for libprelude - version >= $min_libprelude_version) no_libprelude="" if test "$LIBPRELUDE_CONFIG" = "no" ; then no_libprelude=yes else LIBPRELUDE_CFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --cflags` LIBPRELUDE_PTHREAD_CFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --pthread-cflags` LIBPRELUDE_LDFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --ldflags` LIBPRELUDE_LIBS=`$LIBPRELUDE_CONFIG $libprelude_config_args --libs` LIBPRELUDE_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --prefix` LIBPRELUDE_CONFIG_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --config-prefix` libprelude_config_version=`$LIBPRELUDE_CONFIG $libprelude_config_args --version` ac_save_CFLAGS="$CFLAGS" ac_save_LDFLAGS="$LDFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS" LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS" LIBS="$LIBS $LIBPRELUDE_LIBS" dnl dnl Now check if the installed libprelude is sufficiently new. Also sanity dnl checks the results of libprelude-config to some extent dnl rm -f conf.libpreludetest AC_TRY_RUN([ #include #include #include #include int main () { system ("touch conf.libpreludetest"); if( strcmp( prelude_check_version(NULL), "$libprelude_config_version" ) ) { printf("\n*** 'libprelude-config --version' returned %s, but LIBPRELUDE (%s)\n", "$libprelude_config_version", prelude_check_version(NULL) ); printf("*** was found! If libprelude-config was correct, then it is best\n"); printf("*** to remove the old version of LIBPRELUDE. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If libprelude-config was wrong, set the environment variable LIBPRELUDE_CONFIG\n"); printf("*** to point to the correct copy of libprelude-config, and remove the file config.cache\n"); printf("*** before re-running configure\n"); } else if ( strcmp(prelude_check_version(NULL), LIBPRELUDE_VERSION ) ) { printf("\n*** LIBPRELUDE header file (version %s) does not match\n", LIBPRELUDE_VERSION); printf("*** library (version %s)\n", prelude_check_version(NULL) ); } else { if ( prelude_check_version( "$min_libprelude_version" ) ) { return 0; } else { printf("no\n*** An old version of LIBPRELUDE (%s) was found.\n", prelude_check_version(NULL) ); printf("*** You need a version of LIBPRELUDE newer than %s. The latest version of\n", "$min_libprelude_version" ); printf("*** LIBPRELUDE is always available from http://www.prelude-ids.org/download/releases.\n"); printf("*** \n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the libprelude-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of LIBPRELUDE, but you can also set the LIBPRELUDE_CONFIG environment to point to the\n"); printf("*** correct copy of libprelude-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_libprelude=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" LDFLAGS="$ac_save_LDFLAGS" fi if test "x$no_libprelude" = x ; then AC_MSG_RESULT(yes) ifelse([$2], , :, [$2]) else if test -f conf.libpreludetest ; then : else AC_MSG_RESULT(no) fi if test "$LIBPRELUDE_CONFIG" = "no" ; then echo "*** The libprelude-config script installed by LIBPRELUDE could not be found" echo "*** If LIBPRELUDE was installed in PREFIX, make sure PREFIX/bin is in" echo "*** your path, or set the LIBPRELUDE_CONFIG environment variable to the" echo "*** full path to libprelude-config." else if test -f conf.libpreludetest ; then : else echo "*** Could not run libprelude test program, checking why..." CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS" LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS" LIBS="$LIBS $LIBPRELUDE_LIBS" AC_TRY_LINK([ #include #include #include #include ], [ return !!prelude_check_version(NULL); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding LIBPRELUDE or finding the wrong" echo "*** version of LIBPRELUDE. If it is not finding LIBPRELUDE, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" echo "***" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means LIBPRELUDE was incorrectly installed" echo "*** or that you have moved LIBPRELUDE since it was installed. In the latter case, you" echo "*** may want to edit the libprelude-config script: $LIBPRELUDE_CONFIG" ]) CFLAGS="$ac_save_CFLAGS" LDFLAGS="$ac_save_LDFLAGS" LIBS="$ac_save_LIBS" fi fi LIBPRELUDE_CFLAGS="" LIBPRELUDE_LDFLAGS="" LIBPRELUDE_LIBS="" ifelse([$3], , :, [$3]) fi rm -f conf.libpreludetest AC_SUBST(LIBPRELUDE_CFLAGS) AC_SUBST(LIBPRELUDE_PTHREAD_CFLAGS) AC_SUBST(LIBPRELUDE_LDFLAGS) AC_SUBST(LIBPRELUDE_LIBS) AC_SUBST(LIBPRELUDE_PREFIX) AC_SUBST(LIBPRELUDE_CONFIG_PREFIX) ]) dnl *-*wedit:notab*-* Please keep this as the last line. snort-2.9.6.0/m4/Makefile.am0000644000000000000000000000013310234500325012265 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies EXTRA_DIST = Makefile.am \ libprelude.m4 snort-2.9.6.0/m4/Makefile.in0000644000000000000000000002773212260606517012327 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = m4 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies EXTRA_DIST = Makefile.am \ libprelude.m4 all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign m4/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign m4/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/rpm/0000755000000000000000000000000012260606571010605 500000000000000snort-2.9.6.0/rpm/snort.spec0000644000000000000000000006056312260606571012560 00000000000000# $Id$ # Snort.org's SPEC file for Snort ################################################################ # rpmbuild Package Options # ======================== # # See pg 399 of _Red_Hat_RPM_Guide_ for rpmbuild --with and --without options. ################################################################ # Other useful bits %define SnortRulesDir %{_sysconfdir}/snort/rules %define noShell /bin/false # Handle the options noted above. %define vendor Snort.org %define for_distro RPMs %define release 1 %define realname snort # Look for a directory to see if we're building under cAos # Exit status is usually 0 if the dir exists, 1 if not, so # we reverse that with the '!' %define caos %([ ! -d /usr/lib/rpm/caos ]; echo $?) %if %{caos} # We are building for cAos (www.caosity.org) and the autobuilder doesn't # have command line options so we have to fake the options for whatever # packages we actually want here, in addition to tweaking the package # info. %define vendor cAos Linux %define for_distro RPMs for cAos Linux %define release 1.caos %endif Name: %{realname} Version: 2.9.6.0 Epoch: 1 Release: %{release} Summary: An open source Network Intrusion Detection System (NIDS) Group: Applications/Internet License: GPL Url: http://www.snort.org/ Source0: http://www.snort.org/snort-downloads/2.9.6/%{realname}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Packager: Official Snort.org %{for_distro} Vendor: %{vendor} BuildRequires: autoconf, automake, pcre-devel, libpcap-devel #Conflicts: %{conflicts} %description Snort is an open source network intrusion detection system, capable of performing real-time traffic analysis and packet logging on IP networks. It can perform protocol analysis, content searching/matching and can be used to detect a variety of attacks and probes, such as buffer overflows, stealth port scans, CGI attacks, SMB probes, OS fingerprinting attempts, and much more. Snort has three primary uses. It can be used as a straight packet sniffer like tcpdump(1), a packet logger (useful for network traffic debugging, etc), or as a full blown network intrusion detection system. You MUST edit /etc/snort/snort.conf to configure snort before it will work! There are 5 different packages available. All of them require the base snort rpm (this one). Additionally, you may need to chose a different binary to install if you want database support. If you install a different binary package %{_sbindir}/snort should end up being a symlink to a binary in one of the following configurations: plain Snort (this package, required) Please see the documentation in %{_docdir}/%{realname}-%{version} for more information on snort features and configuration. %prep %setup -q -n %{realname}-%{version} # When building from a Snort.org CVS snapshot tarball, you have to run # autojunk before you can build. if [ \( ! -s configure \) -a \( -x autojunk.sh \) ]; then ./autojunk.sh fi # Make sure it worked, or die with a useful error message. if [ ! -s configure ]; then echo "Can't find ./configure. ./autojunk.sh not present or not executable?" exit 2 fi %build BuildSnort() { %__mkdir "$1" cd "$1" %__ln_s ../configure ./configure if [ "$1" = "plain" ] ; then ./configure $SNORT_BASE_CONFIG fi %__make %__mv src/snort ../%{name}-"$1" cd .. } CFLAGS="$RPM_OPT_FLAGS" export AM_CFLAGS="-g -O2" SNORT_BASE_CONFIG="--prefix=%{_prefix} \ --bindir=%{_sbindir} \ --sysconfdir=%{_sysconfdir}/snort \ --with-libpcap-includes=%{_includedir} \ --enable-targetbased \ --enable-control-socket" # Always build snort-plain BuildSnort plain %install # Remove leftover CVS files in the tarball, if any... find . -type 'd' -name "CVS" -print | xargs %{__rm} -rf InstallSnort() { if [ "$1" = "plain" ]; then %__rm -rf $RPM_BUILD_ROOT %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_sbindir} %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_bindir} %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{SnortRulesDir} %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_sysconfdir}/snort %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_var}/log/snort %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_initrddir} %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_mandir}/man8 %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_docdir}/%{realname}-%{version} %__install -p -m 0755 %{name}-plain $RPM_BUILD_ROOT%{_sbindir}/%{name}-plain %__install -p -m 0755 plain/tools/control/snort_control $RPM_BUILD_ROOT%{_bindir}/snort_control %__install -p -m 0755 plain/tools/u2spewfoo/u2spewfoo $RPM_BUILD_ROOT%{_bindir}/u2spewfoo %__install -p -m 0755 plain/tools/u2boat/u2boat $RPM_BUILD_ROOT%{_bindir}/u2boat %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_libdir}/%{realname}-%{version}_dynamicengine %__mkdir_p -m 0755 $RPM_BUILD_ROOT%{_libdir}/%{realname}-%{version}_dynamicpreprocessor %__install -p -m 0755 plain/src/dynamic-plugins/sf_engine/.libs/libsf_engine.so.0 $RPM_BUILD_ROOT%{_libdir}/%{realname}-%{version}_dynamicengine %__ln_s -f %{_libdir}/%{realname}-%{version}_dynamicengine/libsf_engine.so.0 $RPM_BUILD_ROOT%{_libdir}/%{realname}-%{version}_dynamicengine/libsf_engine.so %__install -p -m 0755 plain/src/dynamic-preprocessors/build/%{_prefix}/lib/snort_dynamicpreprocessor/*.so* $RPM_BUILD_ROOT%{_libdir}/%{realname}-%{version}_dynamicpreprocessor for file in $RPM_BUILD_ROOT%{_libdir}/%{realname}-%{version}_dynamicpreprocessor/*.so; do preprocessor=`basename $file` %__ln_s -f %{_libdir}/%{realname}-%{version}_dynamicpreprocessor/$preprocessor.0 $file done %__install -p -m 0644 snort.8 $RPM_BUILD_ROOT%{_mandir}/man8 %__gzip $RPM_BUILD_ROOT%{_mandir}/man8/snort.8 %__install -p -m 0755 rpm/snortd $RPM_BUILD_ROOT%{_initrddir} %__install -p -m 0644 rpm/snort.sysconfig $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/%{realname} %__install -p -m 0644 rpm/snort.logrotate $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/snort %__install -p -m 0644 etc/reference.config etc/classification.config \ etc/unicode.map etc/gen-msg.map \ etc/threshold.conf etc/snort.conf \ $RPM_BUILD_ROOT/%{_sysconfdir}/snort find doc -maxdepth 1 -type f -not -name 'Makefile*' -exec %__install -p -m 0644 {} $RPM_BUILD_ROOT%{_docdir}/%{realname}-%{version} \; %__rm -f $RPM_BUILD_ROOT%{_docdir}/%{realname}-%{version}/Makefile.* fi } # Fix the RULE_PATH %__sed -e 's;var RULE_PATH ../rules;var RULE_PATH %{SnortRulesDir};' \ < etc/snort.conf > etc/snort.conf.new %__rm -f etc/snort.conf %__mv etc/snort.conf.new etc/snort.conf # Fix dynamic-preproc paths %__sed -e 's;dynamicpreprocessor directory \/usr\/local/lib\/snort_dynamicpreprocessor;dynamicpreprocessor directory %{_libdir}\/%{realname}-%{version}_dynamicpreprocessor;' < etc/snort.conf > etc/snort.conf.new %__rm -f etc/snort.conf %__mv etc/snort.conf.new etc/snort.conf # Fix dynamic-engine paths %__sed -e 's;dynamicengine \/usr\/local/lib\/snort_dynamicengine;dynamicengine %{_libdir}\/%{realname}-%{version}_dynamicengine;' < etc/snort.conf > etc/snort.conf.new %__rm -f etc/snort.conf %__mv etc/snort.conf.new etc/snort.conf # Always install snort-plain InstallSnort plain %clean %__rm -rf $RPM_BUILD_ROOT %pre # Don't do all this stuff if we are upgrading if [ $1 = 1 ] ; then /usr/sbin/groupadd snort 2> /dev/null || true /usr/sbin/useradd -M -d %{_var}/log/snort -s %{noShell} -c "Snort" -g snort snort 2>/dev/null || true fi %post # Make a symlink if there is no link for snort-plain if [ -L %{_sbindir}/snort ] || [ ! -e %{_sbindir}/snort ] ; then \ %__rm -f %{_sbindir}/snort; %__ln_s %{_sbindir}/%{name}-plain %{_sbindir}/snort; fi # We should restart it to activate the new binary if it was upgraded %{_initrddir}/snortd condrestart 1>/dev/null 2>/dev/null # Don't do all this stuff if we are upgrading if [ $1 = 1 ] ; then %__chown -R snort.snort %{_var}/log/snort /sbin/chkconfig --add snortd fi %preun if [ $1 = 0 ] ; then # We get errors about not running, but we don't care %{_initrddir}/snortd stop 2>/dev/null 1>/dev/null /sbin/chkconfig --del snortd fi %postun # Try and restart, but don't bail if it fails if [ $1 -ge 1 ] ; then %{_initrddir}/snortd condrestart 1>/dev/null 2>/dev/null || : fi # Only do this if we are actually removing snort if [ $1 = 0 ] ; then if [ -L %{_sbindir}/snort ]; then %__rm -f %{_sbindir}/snort fi /usr/sbin/userdel snort 2>/dev/null fi %files %defattr(-,root,root) %attr(0755,root,root) %{_sbindir}/%{name}-plain %attr(0755,root,root) %{_bindir}/snort_control %attr(0755,root,root) %{_bindir}/u2spewfoo %attr(0755,root,root) %{_bindir}/u2boat %attr(0644,root,root) %{_mandir}/man8/snort.8.* %attr(0755,root,root) %dir %{SnortRulesDir} %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/snort/classification.config %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/snort/reference.config %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/snort/threshold.conf %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/snort/*.map %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/logrotate.d/snort %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/snort/snort.conf %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/sysconfig/snort %attr(0755,root,root) %config(noreplace) %{_initrddir}/snortd %attr(0755,snort,snort) %dir %{_var}/log/snort %attr(0755,root,root) %dir %{_sysconfdir}/snort %attr(0644,root,root) %{_docdir}/%{realname}-%{version}/* %attr(0755,root,root) %dir %{_libdir}/%{realname}-%{version}_dynamicengine %attr(0755,root,root) %{_libdir}/%{realname}-%{version}_dynamicengine/libsf_engine.* %attr(0755,root,root) %dir %{_libdir}/%{realname}-%{version}_dynamicpreprocessor %attr(0755,root,root) %{_libdir}/%{realname}-%{version}_dynamicpreprocessor/libsf_*_preproc.* %dir %{_docdir}/%{realname}-%{version} %docdir %{_docdir}/%{realname}-%{version} ################################################################ # Thanks to the following for contributions to the Snort.org SPEC file: # Henri Gomez # Chris Green # Karsten Hopp # Tim Powers # William Stearns # Hugo van der Kooij # Wim Vandersmissen # Dave Wreski # JP Vossen # Daniel Wittenberg # Jeremy Hewlett # Vlatko Kosturjak %changelog * Wed May 09 2012 Todd Wease 2.9.3 - Removed --enable-decoder-preprocessor-rules since this is now the default - behavior and not configurable. * Fri Apr 27 2012 Russ Combs 2.9.3 - Removed schemas related foo. * Wed Mar 30 2012 Steve Sturges 2.9.3 - Removed --with flexresp, --with inline, database output specific builds. * Wed Apr 02 2008 Steve Sturges 2.8.3 - Added --enable-targetbased --enable-decoder-preprocessor-rules by default. * Wed Apr 02 2008 Steve Sturges 2.8.1 - Added ssl * Fri Aug 03 2007 Russ Combs 2.8.0 - Removed README.build_rpms from description - Removed 2nd "doc/" component from doc install path - Changed doc/ file attributes to mode 0644 - Moved schemas/ from doc to data dir - Added installation of schemas/create_* - Removed redundant '/'s from mkdir path specs - Eliminated find warning by moving -maxdepth ahead of -type - Fixed "warning: File listed twice: ..." for libsf so files * Wed Feb 28 2007 Steve Sturges 2.7.0 - Removed smp flags to make command * Wed Jan 17 2007 Steve Sturges 2.7.0 - Updated version to 2.7.0 * Tue Nov 07 2006 Steve Sturges 2.6.0 - Updated version to 2.6.1 * Thu Aug 31 2006 Steve Sturges 2.6.0 - Added dynamic DNS preprocessor * Wed May 24 2006 Steve Sturges 2.6.0 - Updated to version 2.6.0 * Fri Apr 14 2006 Justin Heath 2.6.0RC1 - Added conf fix for dynamic engine paths - Added conf fix for dynamic preprocessors paths - Added dynamic attributes in file list - Added epoch to Requires for postgres, oracle and unixodbc - Removed rule/signature references as these are not distributed with this tarball * Thu Apr 13 2006 Steve Sturges 2.6.0RC1 - Updated to 2.6.0RC1 - Added targets for dynamic engine - Added targets for dynamic preprocessors * Sun Dec 11 2005 Vlatko Kosturjak 2.6.0RC1 - Added unixODBC support * Sun Oct 16 2005 Marc Norton 2.4.3 - Fixed buffer overflow in bo preprocessor - Added alert for potential buffer overflow attack against snort - Added noalert and drop options for all bo preprocessor events * Fri Jul 22 2005 Martin Roesch 2.4.0 - Modified to reflect rules not being distributed with Snort distros * Tue May 03 2005 Daniel Wittenberg 2.4.0RC1 - Removed more Fedora-specific options - Renamed spec from snort.org.spec to snort.spec - Removed CHANGES.rpms file since we have a changelog here no sense - in maintaining two of them - Replaced a ton of program names with macros to make more portable - Removed all references to rpms@snort.org since it just gets used - for spam so the address is being nuked - Updates to inline support for 2.4.0 Release and fedora changes - Replaced initDir with system-provided _initdir macro for more portability - Added Epoch back in so that way upgrades will work correctly. It will be - removed at some point breaking upgrades for that version * Tue Mar 29 2005 Jeremy Hewlett - Added Inline capability to RPMs. Thanks Matt Brannigan - for helping with the RPM foo. * Fri Mar 25 2005 Jeremy Hewlett - Add schemas to rpm distro - Add sharedscripts to logrotate - Remove installing unnecessary contrib remnants * Sun Mar 13 2005 Daniel Wittenberg - Updates to conform to new Fedora Packageing guidelines * Wed Dec 1 2004 Jeff Ball - Added initDir and noShell for more building compatibility. * Thu Nov 17 2004 Brian Caswell 2.3.0RC1 - handle the moving of RPM and the axing of contrib * Sat Jun 03 2004 JP Vossen - Bugfix for 'snortd condrestart' redirect to /dev/null in %postun * Wed May 12 2004 JP Vossen - Added code for cAos autobuilder - Added buildrequires and requires for libpcap * Thu May 06 2004 Daniel Wittenberg - Added JP's stats option to the standard rc script * Sat Mar 06 2004 JP Vossen - Added gen-msg.map and sid-msg.map to /etc/snort * Sat Feb 07 2004 Daniel Wittenberg - Applied postun/snortd patches from Nick Urbanik - Added threshold.conf, unicode.map and generators to /etc/snort thanks - to notes from Nick Urbanik * Sat Dec 20 2003 Daniel Wittenberg 2.1.0-2 - Added condrestart option to rc script from patch by - Nick Urbanik - Fixed condrestart bug for installs - Fixed gzip bug that happens on some builds * Tue Dec 10 2003 JP Vossen - Removed flexresp from plain rpm package description - Added a line about pcre to the package description - Trivial tweaks to package description * Sat Nov 29 2003 Daniel Wittenberg 2.1.0-1 - Applied some updates from rh0212ms@arcor.de - Applied some updates from Torsten Schuetze - Applied some updates from Nick Urbanik - Fixed ALERTMODE rc script error reported by DFarino@Stamps.com - Fixed CONF rc script error reported by ?? - Gzip signature files to save some space - Added BuildRequires pcre-devel and Requires pcre - Re-did %post sections so the links are added and removed - correctly when you add/remove various packages * Fri Nov 07 2003 Daniel WIttenberg - Updated snort.logrotate * Thu Nov 06 2003 Daniel Wittenberg 2.0.4 - Minor updates for 2.0.4 * Tue Nov 04 2003 Daniel Wittenberg 2.0.3 - Updated for 2.0.3 - Removed 2.0.2 patch - Remove flexresp2 as it caused too many build problems and doesn't work - cleanly with 2.0.3 anyway - Minor documentation updated for 2.0.3 * Mon Oct 20 2003 Daniel Wittenberg 2.0.2-6 - New release version - Changed /etc/rc.d/init.d to /etc/init.d for more compatibility * Fri Oct 17 2003 Daniel Wittenberg - Changed as many hard-coded references to programs and paths to use - standard defined macros * Fri Oct 10 2003 Daniel Wittenberg - Include SnortRulesDir in %%files section - Added classification.config and reference.config in %%files section - Minor cleanup of the for_fedora macro * Sat Oct 04 2003 Dainel Wittenberg - Nuked post-install message as it caused too many problems - Changed default ruledir to /etc/snort/rules - Fixed problem with non-snort-plain symlinks getting created * Fri Oct 03 2003 Dainel Wittenberg - Somehow the snort.logrotate cvs file got copied into the build tree - and the wrong file got pushed out - snort.logrotate wasn't included in the %%files section, so added - it as a config(noreplace) file * Thu Oct 02 2003 Dainel Wittenberg 2.0.2-5 - Added --with fedora for building Fedora RPM's - Removed references to old snort config patch - Added noreplace option to /etc/rc.d/init.d/snortd just in case - Gzip the man page to save (a small tiny) amount of space and make it - more "standard" - Added version number to changelog entries to denote when packages were - released * Wed Oct 01 2003 Dainel Wittenberg - Fixed permission problem with /etc/snort being 644 - Added noreplace option to /etc/sysconfig/snort * Fri Sep 26 2003 Daniel Wittenberg - Fixed incorrect Version string in cvs version of the spec - Added snort logrotate file - Removed |more from output as it confuses some package managers * Fri Sep 23 2003 Daniel Wittenberg 2.0.2-4 - Released 2.0.2-3 and then 2.0.2-4 * Sat Sep 20 2003 Daniel Wittenberg - Added --with flexresp2 build option * Fri Sep 19 2003 Daniel Wittenberg 2.0.2-2 - Gave into JP and changed version back to stable :) * Fri Sep 19 2003 Daniel Wittenberg - Fixed problems in snortd with "ALL" interfaces working correctly - Removed history from individual files as they will get too big - and unreadable quickly * Thu Sep 18 2003 Daniel Wittenberg 2.0.2-1 - Updated for 2.0.2 and release 2.0.2-1 * Tue Aug 26 2003 JP Vossen - Added code to run autojunk.sh for CVS tarball builds * Mon Aug 25 2003 JP Vossen - Added missing comments to changelog * Sun Aug 20 2003 Daniel Wittenberg - Moved snortd and snortd.sysconfig to contrib/rpm - Changed contrib install to a cp -a so the build stops complaining * Mon Aug 11 2003 JP Vossen - Removed the commented patch clutter and a TO DO note - Fussed with white space * Sun Aug 10 2003 Daniel Wittenberg - Fixed a couple minor install complaints - userdel/groupdel added back into %%postun - useradd/groupadd added to %%pre * Sat Aug 9 2003 JP Vossen - Doubled all percent signs in this changelog due to crazy RH9 RPM bug. - http://www.fedora.us/pipermail/fedora-devel/2003-June/001561.html - http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=88620 - Turn off rpm debug due to RH9 RPM issue - http://www.cs.helsinki.fi/linux/linux-kernel/2003-15/0763.html - Removed unnecessary SourceX: since they will be in the tarball * Thu Aug 7 2003 JP Vossen - Changed perms from 755 to 644 for %%{_mandir}/man8/snort.8* * Sun Aug 3 2003 JP Vossen - Removed the conf patch (again) as we moved the funcationality - Added sed to buildrequires and sed it to fix RULE_PATH - Removed Dan's SPEC code that made a default sysconfig/snort file. * Sun Aug 3 2003 JP Vossen - Trivial changes and additions to documentation and references - Added --with flexresp option - Changed libnet buildrequires per Chris - Added docs and contrib back in, and moved sig docs out of doc. - Moved CSV and signature 'fixes' into %%install where they should have - been. Also fixed them. - Added Dan's new snortd and snort.sysconfig - Commented out alternate method of creating /etc/sysconfig/snort - Created %%{OracleHome} - Added BuildRequires: findutils - Uncommented the patch and added the patch file * Fri Jul 26 2003 Daniel Wittenberg - commented out the patch for now since it doesn't exist - if doing a new install echo "INTERFACE=eth0" > /etc/sysconfig/snort - changed --with-libpcap-includes=/usr/include/pcap to /usr/include since - that is where the libpcap-snort rpm Chris sent puts things - added missing " at the end of the SNORT_BASE_CONFIG - minor change to the ./configure for plain so it actually works - during an rpm -e of snort do a rm -f to make it a little more quiet in - case of problems - massive re-write of multi-package build system - initial support for compiling with Oracle * Sun Jul 20 2003 JP Vossen - Took over maintenance of Snort.org RPM releases just before v2.0.1 - Various cleanup of SPEC file and changes to support building from tarball - Removed some old packages (like SNMP and Bloat), per Chris - First attempt at using --with option for multi-package build system - Added a patch to snort.conf for $RULE_PATH and default output plugins * Wed Sep 25 2002 Chris Green - updated to 1.9.0 * Tue Nov 6 2001 Chris Green - merged in Hugo's changes - updated to 1.8.3 - fixing symlinks on upgrades * Tue Nov 6 2001 Hugo van der Kooij - added libpcap to the list as configure couldn't find it on RedHat 7.2 - added several packages to the build requirements * Fri Nov 2 2001 Chris Green - updated to 1.8.2-RELEASE - adding SQL defines - created tons of packages so that all popular snort configs are accounted for * Sat Aug 18 2001 Chris Green - 1.8.1-RELEASE - cleaned up enough to release to general public * Tue May 8 2001 Chris Green - moved to 1.8cvs - changed rules files - removed initial configuration * Mon Nov 27 2000 Chris Green - removed strip - upgrade to cvs version - moved /var/snort/dev/null creation to install time * Tue Nov 21 2000 Chris Green - changed to %%{SnortPrefix} - upgrade to patch2 * Mon Jul 31 2000 Wim Vandersmissen - Integrated the -t (chroot) option and build a /home/snort chroot jail - Installs a statically linked/stripped snort - Updated /etc/rc.d/init.d/snortd to work with the chroot option * Tue Jul 25 2000 Wim Vandersmissen - Added some checks to find out if we're upgrading or removing the package * Sat Jul 22 2000 Wim Vandersmissen - Updated to version 1.6.3 - Fixed the user/group stuff (moved to %%post) - Added userdel/groupdel to %%postun - Automagically adds the right IP, nameservers to /etc/snort/rules.base * Sat Jul 08 2000 Dave Wreski - Updated to version 1.6.2 - Removed references to xntpd - Fixed minor problems with snortd init script * Fri Jul 07 2000 Dave Wreski - Updated to version 1.6.1 - Added user/group snort * Sat Jun 10 2000 Dave Wreski - Added snort init.d script (snortd) - Added Dave Dittrich's snort rules header file (ruiles.base) - Added Dave Dittrich's wget rules fetch script (check-snort) - Fixed permissions on /var/log/snort - Created /var/log/snort/archive for archival of snort logs - Added post/preun to add/remove snortd to/from rc?.d directories - Defined configuration files as %%config * Tue Mar 28 2000 William Stearns - Quick update to 1.6. - Sanity checks before doing rm-rf in install and clean * Fri Dec 10 1999 Henri Gomez - 1.5-0 Initial RPM release snort-2.9.6.0/rpm/snort.sysconfig0000644000000000000000000000651510236462261013624 00000000000000# /etc/sysconfig/snort # $Id$ # All of these options with the exception of -c, which tells Snort where # the configuration file is, may be specified in that configuration file as # well as the command line. Both the command line and config file options # are listed here for reference. #### General Configuration # What interface should snort listen on? [Pick only 1 of the next 3!] # This is -i {interface} on the command line # This is the snort.conf config interface: {interface} directive INTERFACE=eth0 # # The following two options are not directly supported on the command line # or in the conf file and assume the same Snort configuration for all # instances # # To listen on all interfaces use this: #INTERFACE=ALL # # To listen only on given interfaces use this: #INTERFACE="eth1 eth2 eth3 eth4 eth5" # Where is Snort's configuration file? # -c {/path/to/snort.conf} CONF=/etc/snort/snort.conf # What user and group should Snort drop to after starting? This user and # group should have very few privileges. # -u {user} -g {group} # config set_uid: user # config set_gid: group USER=snort GROUP=snort # Should Snort change the order in which the rules are applied to packets. # Instead of being applied in the standard Alert->Pass->Log order, this will # apply them in Pass->Alert->Log order. # -o # config order: {actions in order} # e.g. config order: log alert pass activation dynamic suspicious redalert PASS_FIRST=0 #### Logging & Alerting # NOTE: NO_PACKET_LOG and BINARY_LOG, ALERTMODE, etc. are mutually # exclusive. Use either NO_PACKET_LOG or any/all of the other logging # options. But the more logging options use you, the slower Snort will run. # Where should Snort log? # -l {/path/to/logdir} # config logdir: {/path/to/logdir} LOGDIR=/var/log/snort # How should Snort alert? Valid alert modes include fast, full, none, and # unsock. Fast writes alerts to the default "alert" file in a single-line, # syslog style alert message. Full writes the alert to the "alert" file # with the full decoded header as well as the alert message. None turns off # alerting. Unsock is an experimental mode that sends the alert information # out over a UNIX socket to another process that attaches to that socket. # -A {alert-mode} # output alert_{type}: {options} ALERTMODE=fast # Should Snort dump the application layer data when displaying packets in # verbose or packet logging mode. # -d # config dump_payload DUMP_APP=1 # Should Snort keep binary (AKA pcap, AKA tcpdump) logs also? This is # recommended as it provides very useful information for investigations. # -b # output log_tcpdump: {log name} BINARY_LOG=1 # Should Snort turn off packet logging? The program still generates # alerts normally. # -N # config nolog NO_PACKET_LOG=0 # Print out the receiving interface name in alerts. # -I # config alert_with_interface_name PRINT_INTERFACE=0 # When dumping the stats, what log file should we look in SYSLOG=/var/log/messages # When dumping the stats, how long to wait to make sure that syslog can # flush data to disk SECS=5 # To add a BPF filter to the command line uncomment the following variable # syntax corresponds to tcpdump(8) #BPF="not host 192.168.1.1" # To use an external BPF filter file uncomment the following variable # syntax corresponds to tcpdump(8) # -F {/path/to/bpf_file} # config bpf_file: /path/to/bpf_file #BPFFILE=/etc/snort/bpf_file snort-2.9.6.0/rpm/snort.logrotate0000644000000000000000000000041610236462260013611 00000000000000# /etc/logrotate.d/snort # $Id$ /var/log/snort/alert /var/log/snort/*log /var/log/snort/*/alert /var/log/snort/*/*log { daily rotate 7 missingok compress sharedscripts postrotate /etc/init.d/snortd restart 1>/dev/null || true endscript } snort-2.9.6.0/rpm/snortd0000644000000000000000000001241310236462261011757 00000000000000#!/bin/sh # $Id$ # # snortd Start/Stop the snort IDS daemon. # # chkconfig: 2345 40 60 # description: snort is a lightweight network intrusion detection tool that \ # currently detects more than 1100 host and network \ # vulnerabilities, portscans, backdoors, and more. # # Source function library. . /etc/rc.d/init.d/functions # Source the local configuration file . /etc/sysconfig/snort # Convert the /etc/sysconfig/snort settings to something snort can # use on the startup line. if [ "$ALERTMODE"X = "X" ]; then ALERTMODE="" else ALERTMODE="-A $ALERTMODE" fi if [ "$USER"X = "X" ]; then USER="snort" fi if [ "$GROUP"X = "X" ]; then GROUP="snort" fi if [ "$BINARY_LOG"X = "1X" ]; then BINARY_LOG="-b" else BINARY_LOG="" fi if [ "$CONF"X = "X" ]; then CONF="-c /etc/snort/snort.conf" else CONF="-c $CONF" fi if [ "$INTERFACE"X = "X" ]; then INTERFACE="-i eth0" else INTERFACE="-i $INTERFACE" fi if [ "$DUMP_APP"X = "1X" ]; then DUMP_APP="-d" else DUMP_APP="" fi if [ "$NO_PACKET_LOG"X = "1X" ]; then NO_PACKET_LOG="-N" else NO_PACKET_LOG="" fi if [ "$PRINT_INTERFACE"X = "1X" ]; then PRINT_INTERFACE="-I" else PRINT_INTERFACE="" fi if [ "$PASS_FIRST"X = "1X" ]; then PASS_FIRST="-o" else PASS_FIRST="" fi if [ "$LOGDIR"X = "X" ]; then LOGDIR=/var/log/snort fi # These are used by the 'stats' option if [ "$SYSLOG"X = "X" ]; then SYSLOG=/var/log/messages fi if [ "$SECS"X = "X" ]; then SECS=5 fi if [ ! "$BPFFILE"X = "X" ]; then BPFFILE="-F $BPFFILE" fi ###################################### # Now to the real heart of the matter: # See how we were called. case "$1" in start) echo -n "Starting snort: " cd $LOGDIR if [ "$INTERFACE" = "-i ALL" ]; then for i in `cat /proc/net/dev|grep eth|awk -F ":" '{ print $1; }'` do mkdir -p "$LOGDIR/$i" chown -R $USER:$GROUP $LOGDIR daemon /usr/sbin/snort $ALERTMODE $BINARY_LOG $NO_PACKET_LOG $DUMP_APP -D $PRINT_INTERFACE -i $i -u $USER -g $GROUP $CONF -l $LOGDIR/$i $PASS_FIRST $BPFFILE $BPF done else # check if more than one interface is given if [ `echo $INTERFACE|wc -w` -gt 2 ]; then for i in `echo $INTERFACE | sed s/"-i "//` do mkdir -p "$LOGDIR/$i" chown -R $USER:$GROUP $LOGDIR daemon /usr/sbin/snort $ALERTMODE $BINARY_LOG $NO_PACKET_LOG $DUMP_APP -D $PRINT_INTERFACE -i $i -u $USER -g $GROUP $CONF -l $LOGDIR/$i $PASS_FIRST $BPFFILE $BPF done else # Run with a single interface (default) daemon /usr/sbin/snort $ALERTMODE $BINARY_LOG $NO_PACKET_LOG $DUMP_APP -D $PRINT_INTERFACE $INTERFACE -u $USER -g $GROUP $CONF -l $LOGDIR $PASS_FIRST $BPFFILE $BPF fi fi touch /var/lock/subsys/snort echo ;; stop) echo -n "Stopping snort: " killproc snort rm -f /var/lock/subsys/snort echo ;; reload) echo "Sorry, not implemented yet" ;; restart) $0 stop $0 start ;; condrestart) [ -e /var/lock/subsys/snort ] && $0 restart ;; status) status snort ;; stats) TC=125 # Trailing context to grep SNORTNAME='snort' # Process name to look for if [ ! -x "/sbin/pidof" ]; then echo "/sbin/pidof not present, sorry, I cannot go on like this!" exit 1 fi #Grab Snort's PID PID=`pidof -o $$ -o $PPID -o %PPID -x ${SNORTNAME}` if [ ! -n "$PID" ]; then # if we got no PID then: echo "No PID found: ${SNORTNAME} must not running." exit 2 fi echo "" echo "*******" echo "WARNING: This feature is EXPERIMENTAL - please report errors!" echo "*******" echo "" echo "You can also run: $0 stats [long | opt]" echo "" echo "Dumping ${SNORTNAME}'s ($PID) statistics" echo "please wait..." # Get the date and tell Snort to dump stats as close together in # time as possible--not 100%, but it seems to work. startdate=`date '+%b %e %H:%M:%S'` # This causes the stats to be dumped to syslog kill -USR1 $PID # Sleep for $SECS secs to give syslog a chance to catch up # May need to be adjusted for slow/busy systems sleep $SECS if [ "$2" = "long" ]; then # Long format egrep -B 3 -A $TC "^$startdate .* snort.*: ={79}" $SYSLOG | \ grep snort.*: elif [ "$2" = "opt" ]; then # OPTimize format # Just show stuff useful for optimizing Snort egrep -B 3 -A $TC "^$startdate .* snort.*: ={79}" $SYSLOG | \ egrep "snort.*: Snort analyzed |snort.*: dropping|emory .aults:" else # Default format egrep -B 3 -A $TC "^$startdate .* snort.*: ={79}" $SYSLOG | \ grep snort.*: | cut -d: -f4- fi ;; *) echo "Usage: $0 {start|stop|reload|restart|condrestart|status|stats (long|opt)}" exit 2 esac exit 0 snort-2.9.6.0/rpm/RPM-TODO0000644000000000000000000000025310236462260011645 00000000000000################################################################ # Future releases - get to work better with the CVS current snapshot tarball? - build chroot RPM package snort-2.9.6.0/rpm/README.rpms0000644000000000000000000000700512046023337012362 00000000000000$Id$ README.rpms By JP Vossen & Dan Wittenberg Last Updated: 2005-05-05 "Official" Snort.org RPM Documentation ====================================== Official Snort.org RPMs are back and better than ever. However, we've made some changes that you need to be aware of, and we've documented some other things of interest. Thanks to JP Vossen (http://www.jpsdomain.org/security/snort.html) who was originally guilted into taking over RPM upkeep , and to Daniel Wittenberg (http://www.starken.com/) who graciously volunteered to help and to provide a build host. The RPMs are now being co-maintained by them. Improvements ------------ We've made a lot of changes under the covers to improve the flexibility and maintainability of the RPMs going forward. See the next section for details about that. The most interesting and significant is the new ability to build RPMs directly from the source code tarball! That means you can download either a release tarball or one of the nightly CVS snapshot tarballs and build RPMs *almost* effortlessly. See README.build_rpms [0] for the details and the caveat about the "current" snapshot. Changes from the previous Snort RPMs ------------------------------------ Use this command to view the most current change log before you install the latest package: rpm -q --changelog -p snort-x.x.x-x.i386.rpm | less Beginning around Snort 2.3.0 the RPM files moved out of the contrib directory, which went away. Beginning with Snort 2.0.2, the official RPMs include the following changes: * snortd has been significantly revised to better conform with the /etc/sysconfig scheme. See /etc/sysconfig/snort and /etc/init.d/snortd for details. * The doc, contrib and signatures directories are included in your doc directory (e.g. /usr/share/doc/snort-x.x.x). * The signatures directory is gzipped to save space beginning with Snort 2.1.0. * The signatures directory is moved out from doc to the root of the Snort documentation directory to make it more visible. * Rules have been moved to /etc/snort/rules for readability and more compatibility with rule-updating software like oinkmaster. * The RPM SPEC file has been significantly revised and documented. It has also been added to the source tarball (contrib/rpm), facilitating building your own RPM directly from the tarball. See README.build_rpms [0] and the SPEC [2] file for details. * The binary packages built by the SPEC file have been simplified, and rpmbuild '--with' options have been added to facilitate easy do-it-yourself builds. See README.build_rpms [0] and the SPEC [2] file for details. * Neither version of flexresp is included in the official binary RPMs. You may build it in yourself if needed. * We've added a lot of new documentation about RPMs, like this document you're reading. Supported Distributions ======================= The rpmbuild -ta method and new SPEC file have been tested and are known to work on Red Hat 7.3, 8.0, 9, RHEL-3 (Taroon), Fedora Core [1-3]. Some basic build tests have been done on SuSE 8.1 and 8.2 (which use rpm version 3). They should also work on any distribution that supports RPM and have rpm v4 or better. References ========== [0] The latest Snort README.build_rpms http://cvs.snort.org/viewcvs.cgi/snort/rpm/README.build_rpms [1] The official Snort.org RPM SPEC file: http://cvs.snort.org/viewcvs.cgi/snort/rpm/snort.spec The latest Snort README.rpms http://cvs.snort.org/viewcvs.cgi/snort/rpm/README.rpms snort-2.9.6.0/rpm/README.build_rpms0000644000000000000000000002330612046023337013543 00000000000000$Id$ README.build_rpms By JP Vossen & Dan Wittenberg Last Updated: 2005-05-03 How to build your own Snort RPMs--Introduction ============================================== RPM is the accepted package manager for a large number of Linux distributions. It is designed to allow easy and repeatable builds and binary installations for software. This is especially important for a package like Snort, where security and consistency are critical. Since you should never install a compiler on a hardened machine, and especially never on a security device like a firewall or IDS, a binary installer like RPM makes it very easy to install and update software. However, many people are not comfortable unless they download and compile the software themselves. This document will show you how to download the Snort source code, compile it and build your own RPM very easily. RPM requires a SPEC file to provide details on how to compile and build the source code into an RPM package. The most difficult and time consuming part of building an RPM is writing a correct SPEC file. We've already done that for you (and it is heavily commented as well). The snort.spec file can build the following packages, with or without flexible response (see README.flexresp for more details): plain Snort (this package, required) mysql Snort with mysql (optional) postgresql Snort with postgresql (optional) oracle Snort with oracle (optional, not official) inline Snort with inline support (optional) Prerequisites ============= In order to build RPMs you must install the 'rpm-build' package. You will also need the following if you plan to build packages other than plain: Package Dependency --------------------- ---------------- All rpm-build (rpm version 4 and above), pcre-devel Snort with MySQL MYSQL-devel, pcre-devel Snort with PostgreSQL postgresql-devel, pcre-devel Snort with Oracle Oracle libs in /opt/oracle, pcre-devel Snort inline iptables-devel, libnet If you plan to build flexresp, you also need libnet. Depending on which libnet RPM you install, you may get statically linked binaries. If you have statically linked libraries you only need the static library on the build machine, NOT the machine on which the final compiled binary runs. Given the fact that Snort sensors are security devices and having dynamic libnet capabilities may be undesirable, static linking is a Good Thing. The strongly recommended libnet to use is custom 1.0.2a Packetfactory RPM Chris Green built a while ago that may be found here [0]. This is the only Snort.org supported libnet and it allows snort to statically compile libnet as noted above. Building from a Tarball ======================= If you have a recent version of RPM which supports the -tx options, you can build directly from the official Snort.org tarball distribution. RPM versions 4 and above are known to work. Some versions of rpm 3 have been known to work, specifically those with SuSE 8.1 and SuSE 8.2 Version 4: rpmbuild {package options} -ta {path/to/snort-n.n.n.tar.gz} Version 3: rpm {package options} -ta {path/to/snort-n.n.n.tar.gz} (We will assume version 4 elsewhere in the documentation) rpmbuild Package Options ======================== --with flexresp Add flexresp capability to whatever package(s) you are building. --with inline Add inline capability to whatever package(s) you are building. This will create its own inline package. --with mysql Builds a binary/package with support for MySQL. --with postgresql Builds a binary/package with support for PostgreSQL. --with oracle Builds a binary/package with support for Oracle. See below for some examples. Rebuilding from the Source RPM (SRPM) ===================================== You can also download the source RPM and rebuild from that. Simply get the SRPM from Snort.org and rebuild: rpmbuild --rebuild /path/to/snort-x.x.x-x.src.rpm rpmbuild examples ================= $ rpmbuild --with mysql --with postgresql -ta snort-2.0.4.tar.gz --OR-- $ rpmbuild --with mysql --with postgresql --rebuild snort-2.0.4-1.src.rpm $ ls -1 /usr/src/redhat/RPMS/i386/snort-* /usr/src/redhat/RPMS/i386/snort-2.0.4-1.i386.rpm /usr/src/redhat/RPMS/i386/snort-mysql-2.0.4-1.i386.rpm /usr/src/redhat/RPMS/i386/snort-postgresql-2.0.4-1.i386.rpm The "Official" Snort.org RPM build ================================== We build the official Snort.org RPMs with the generate-all-rpms script in the rpm directory. In theory, anyone can build RPMs that are identical to the official Snort.org RPMS. However, only the official RPMs will be signed by the Snort.org GPG key [1]. PLEASE verify your RPMs with this key before installing them. Distribution Specific Builds ============================ The SPEC file contains code to build RPMS for specific Linux distributions, currently cAos (www.caosity.org). Since the cAos buildsystem is completely automated, no rpmbuild command line options are allowed, so the SPEC file looks for the '/usr/lib/rpm/caos' directory to see if it's running under cAos. This is not ideal as it will build all packages under any cAos machine--not just the autobuilder. But it's the best I can do right now. Anyone have any better ideas? Verifying an RPM's PGP/GPG Key ============================== Download and add the Snort key to RPM: wget http://www.snort.org/public-key.html rpm --import public-key.html Verify the signature: rpm --checksig /path/to/snort-x.x.x-x.i386.rpm rpm -v --checksig /path/to/snort-x.x.x-x.i386.rpm -- OR -- rpm -K /path/to/snort-x.x.x-x.i386.rpm rpm -vK /path/to/snort-x.x.x-x.i386.rpm If you see something like the following, it's good. NOTE, you MUST see "gpg OK" for the signature to exist and be valid! Any random RPM may be created without a signature, so make sure your official RPM has one. /path/to/snort-x.x.x-xsnort.i386.rpm: (sha1) dsa sha1 md5 gpg OK The -v (for verbose) options give you a little more detail. Again, make sure the signature lines present and OK. If you see a "NOT OK" message, something did not verify. Any items that were correct will be listed in lower case (e.g. sha1 md5) while any failed items are in upper case (e.g. GPG). There may also be an error message, such as "MISSING KEYS." Examining the SPEC file ======================= We have tried to make the Snort.org SPEC file as "user friendly" as possible. In particular, it has lots of comments. So it may be useful to look it over, or you may just want to build the old fashioned way. In any case, there are three easy ways to get it. Get it from Snort's CVS (see reference section for URL). Get it from the tarball: tar -xvzf /path/to/snort-x.x.x.tar.gz Get it from the SRPM Get the SRPM from Snort.org Extract the SRPM: rpm2cpio /path/to/snort-x.x.x-x.src.rpm | cpio -i -- OR -- Install the SRPM: rpm -i /path/to/snort-x.x.x-x.src.rpm Building from Snort.org CVS Snapshots [2] ========================================= Building from the CVS snapshot tarballs should work but requires some manual intervention. 1. Cd to /tmp or someplace safe: cd /tmp 2. Untar the source: tar -xvzf /path/to/snort-current.tar.gz 3. Rename the resulting snort directory: mv snort snort-current 4. Edit snort-current/rpm/snort.spec and change the line %define release {whatever} to %define release 1 and Version: stable (or 2.1.x or whatever) to Version: current 5. Rename the original tarball: mv snort-current.tar.gz snort-current-orig.tar.gz 6. Obtain the snort rules you wish to include in the RPM (see [3]). Untar the file then move the rules and doc/sigantures directories into place in the working directory. E.g. mv /tmp/rules /tmp/snort-current and mv /tmp/doc/signatures /tmp/snort-current/doc. 7. Re-tar the file: tar -cvzf snort-current.tar.gz snort-current 8. Build as usual: rpmbuild -ta snort-current.tar.gz If you don't know how to do all of that, you probably want the regular compiled binary packages or the snort-stable snapshot. Building from Snort.org Anonymous CVS [4] ========================================== Building from Snort.org Anonymous CVS is very similar to building from snapshot tarballs, except without the tarballs. If you don't know how to do all of that, you probably want the regular compiled binary packages or the snort-stable snapshot. References ========== [0] Chris Green's Snort Libnet: http://www.starken.com/snort/index.html#libnet [1] Snort.org PGP/GPG key http://www.snort.org/public-key.txt [2] Snort.org CVS Snapshots http://www.snort.org/pub-bin/snapshots.cgi [3] Snort Rules http://www.snort.org/rules/ [4] Got Source? http://www.snort.org/got_source/source.html The latest Snort README.rpms http://cvs.snort.org/viewcvs.cgi/snort/rpm/README.rpms The latest Snort README.build_rpms (this document) http://cvs.snort.org/viewcvs.cgi/snort/rpm/README.build_rpms The official Snort.org RPM SPEC file: http://cvs.snort.org/viewcvs.cgi/snort/rpm/snort.spec The RPM Homepage http://www.rpm.org/ The RPM FAQ http://www.rpm.org/RPM-HOWTO/ Book: Red Hat Linux RPM Guide Esp. pgs: 236, 399, 400 By Eric Foster-Johnson, ISBN: 0-7645-4965-0, 549 pages http://www.wiley.com/WileyCDA/WileyTitle/productCd-0764549650.html http://www.bookpool.com/.x/zsz8obm990/sm/0764549650/ Book: Maximum RPM (Older, but mostly still valid) On-Line, free: http://www.rpm.org/max-rpm/ http://www.bookpool.com/.x/zsz8obm990/sm/0672311054/ Note on "rpmbuild -ta {tarfile}" http://sourceforge.net/mailarchive/forum.php?thread_id=1840467&forum_id=2311 Linux RPM Repository and Browse Tool http://rufus.w3.org/linux/RPM/ snort-2.9.6.0/rpm/generate-all-rpms0000644000000000000000000000202310277202365013763 00000000000000#!/bin/bash # $Id$ # Generate the "official" Snort.org RPMs. # The following will build 3 binary and 1 source RPM as follows: # snort-x.x.x-x.i386.rpm # snort-mysql-x.x.x-x.i386.rpm # snort-postgresql-x.x.x-x.i386.rpm # snort-x.x.x-x.src.rpm # # mysql and postgresql are probably mutually exclusive when building for # your own use, and flexresp is optional. We therefor encourage you to # build your own RPMs as you see fit. See README.build_rpms. # If you wish to build with Oracle support, you need to use --with-oracle # for the build syntax, and have your client libraries installed in # /opt/oracle rpmbuild -bb --target i386 --with mysql --with postgresql snort.spec rpmbuild -bs --target i386 snort.spec # If you wish to build with Inline support, you need to use the # --with inline build syntax. You will need iptables-devel (for libipq) # and libnet installed. # The following will build the above binary packages with Inline support: #rpmbuild -bb --target i386 --with inline --with mysql --with postgresql snort.spec snort-2.9.6.0/rpm/Makefile.am0000644000000000000000000000030610236462260012554 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies EXTRA_DIST = Makefile.am \ generate-all-rpms \ README.build_rpms \ README.rpms \ RPM-TODO \ snortd \ snort.logrotate \ snort.spec \ snort.sysconfig snort-2.9.6.0/rpm/Makefile.in0000644000000000000000000003011012260606517012565 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = rpm DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies EXTRA_DIST = Makefile.am \ generate-all-rpms \ README.build_rpms \ README.rpms \ RPM-TODO \ snortd \ snort.logrotate \ snort.spec \ snort.sysconfig all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign rpm/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign rpm/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/templates/0000755000000000000000000000000012260606570012004 500000000000000snort-2.9.6.0/templates/spp_template.h0000644000000000000000000000053710013174367014575 00000000000000/* $Id$ */ /* Snort Preprocessor Plugin Header File Template */ /* This file gets included in plugbase.h when it is integrated into the rest * of the program. */ #ifndef __SPP_TEMPLATE_H__ #define __SPP_TEMPLATE_H__ /* * list of function prototypes to export for this preprocessor */ void SetupTemplate(); #endif /* __SPP_TEMPLATE_H__ */ snort-2.9.6.0/templates/sp_template.h0000644000000000000000000000052510013174367014412 00000000000000/* $Id$ */ /* Snort Detection Plugin Header File Template */ /* * This file gets included in plugbase.h when it is integrated into the rest * of the program. * * Export any functions or data structs you feel necessary. */ #ifndef __SP_TEMPLATE_H__ #define __SP_TEMPLATE_H__ void SetupTemplate(); #endif /* __SP_TEMPLATE_H__ */ snort-2.9.6.0/templates/spp_template.c0000644000000000000000000001276010013174367014571 00000000000000/* $Id$ */ /* Snort Preprocessor Plugin Source File Template */ /* spp_template * * Purpose: * * Preprocessors perform some function *once* for *each* packet. This is * different from detection plugins, which are accessed depending on the * standard rules. When adding a plugin to the system, be sure to * add the "Setup" function to the InitPreprocessors() function call in * plugbase.c! * * Arguments: * * This is the list of arguements that the plugin can take at the * "preprocessor" line in the rules file * * Effect: * * What the preprocessor does. Check out some of the default ones * (e.g. spp_frag2) for a good example of this description. * * Comments: * * Any comments? * */ #include #include #include #include /* * If you're going to issue any alerts from this preproc you * should include generators.h and event_wrapper.h */ #include "generators.h" #include "event_wrapper.h" #include "util.h" #include "plugbase.h" #include "parser.h" /* * put in other inculdes as necessary */ /* * your preprocessor header file goes here if necessary, don't forget * to include the header file in plugbase.h too! */ #include "spp_template.h" /* * define any needed data structs for things like configuration */ typedef struct _TemplateData { /* Your struct members here */ } TemplateData; /* * If you need to instantiate the preprocessor's * data structure, do it here */ TemplateData SomeData; /* * function prototypes go here */ static void TemplateInit(u_char *); static void ParseTemplateArgs(char *); static void PreprocFunction(Packet *); static void PreprocCleanExitFunction(int, void *); static void PreprocRestartFunction(int, void *); /* * Function: SetupTemplate() * * Purpose: Registers the preprocessor keyword and initialization * function into the preprocessor list. This is the function that * gets called from InitPreprocessors() in plugbase.c. * * Arguments: None. * * Returns: void function * */ void SetupTemplate() { /* * link the preprocessor keyword to the init function in * the preproc list */ RegisterPreprocessor("keyword", TemplateInit); DebugMessage(DEBUG_PLUGIN,"Preprocessor: Template is setup...\n"); } /* * Function: TemplateInit(u_char *) * * Purpose: Calls the argument parsing function, performs final setup on data * structs, links the preproc function into the function list. * * Arguments: args => ptr to argument string * * Returns: void function * */ static void TemplateInit(u_char *args) { DebugMessage(DEBUG_PLUGIN,"Preprocessor: Template Initialized\n"); /* * parse the argument list from the rules file */ ParseTemplateArgs(args); /* * perform any other initialization functions that are required here */ /* * Set the preprocessor function into the function list */ AddFuncToPreprocList(PreprocFunction); AddFuncToCleanExitList(PreprocCleanExitFunction, NULL); AddFuncToRestartList(PreprocRestartFunction, NULL); } /* * Function: ParseTemplateArgs(char *) * * Purpose: Process the preprocessor arguements from the rules file and * initialize the preprocessor's data struct. This function doesn't * have to exist if it makes sense to parse the args in the init * function. * * Arguments: args => argument list * * Returns: void function * */ static void ParseTemplateArgs(char *args) { /* your parsing function goes here, check out the other spp files for examples */ } /* * Function: PreprocFunction(Packet *) * * Purpose: Perform the preprocessor's intended function. This can be * simple (statistics collection) or complex (IP defragmentation) * as you like. Try not to destroy the performance of the whole * system by trying to do too much.... * * Arguments: p => pointer to the current packet data struct * * Returns: void function * */ static void PreprocFunction(Packet *p) { /* your preproc function goes here.... */ /* * if you need to issue an alert from your preprocessor, check out * event_wrapper.h, there are some useful helper functions there */ } /* * Function: PreprocCleanExitFunction(int, void *) * * Purpose: This function gets called when Snort is exiting, if there's * any cleanup that needs to be performed (e.g. closing files) * it should be done here. * * Arguments: signal => the code of the signal that was issued to Snort * data => any arguments or data structs linked to this * functioin when it was registered, may be * needed to properly exit * * Returns: void function */ static void PreprocCleanExitFunction(int signal, void *data) { /* clean exit code goes here */ } /* * Function: PreprocRestartFunction(int, void *) * * Purpose: This function gets called when Snort is restarting on a SIGHUP, * if there's any initialization or cleanup that needs to happen * it should be done here. * * Arguments: signal => the code of the signal that was issued to Snort * data => any arguments or data structs linked to this * functioin when it was registered, may be * needed to properly exit * * Returns: void function */ static void PreprocRestartFunction(int signal, void *foo) { /* restart code goes here */ } snort-2.9.6.0/templates/sp_template.c0000644000000000000000000001431210013174367014404 00000000000000/* $Id$ */ /* Snort Detection Plugin Source File Template */ /* sp_template * * Purpose: * * Detection engine plugins test an aspect of the current packet and report * their findings. The function may be called many times per packet with * different arguments. These functions are acccessed from the rules file * as standard rule options. When adding a plugin to the system, be sure to * add the "Setup" function to the InitPlugins() function call in * plugbase.c! * * Arguments: * * This is the type of arguements that the detection plugin can take when * referenced as a rule option * * Effect: * * What the plugin does. * * Comments: * * Any comments? * */ #include #include #include #include "rules.h" #include "decode.h" #include "plugbase.h" #include "parser.h" #include "debug.h" #include "util.h" #include "plugin_enum.h" /* * don't forget to include the name of this file in plugbase.c! */ /* * setup any data structs here */ typedef struct _TemplateData { /* * your detection option data * structure info goes here */ } TemplateData; /* function prototypes go here */ static void TemplateInit(char *, OptTreeNode *, int); static void TemplateRuleParseFunction(char *, OptTreeNode *, TemplateData *); static int TemplateDetectorFunction(Packet *, struct _OptTreeNode *, OptFpList *); /* * * Function: SetupTemplate() * * Purpose: Generic detection engine plugin template. Registers the * configuration function and links it to a rule keyword. This is * the function that gets called from InitPlugins in plugbase.c. * * Arguments: None. * * Returns: void function * */ void SetupTemplate() { /* map the keyword to an initialization/processing function */ RegisterPlugin("keyword", TemplateInit); DebugMessage(DEBUG_PLUGIN,"Plugin: TemplateName Setup\n"); } /* * * Function: TemplateInit(char *, OptTreeNode *) * * Purpose: Generic rule configuration function. Handles parsing the rule * information and attaching the associated detection function to * the OTN. * * Arguments: data => rule arguments/data * otn => pointer to the current rule option list node * * Returns: void function * */ static void TemplateInit(char *data, OptTreeNode *otn, int protocol) { TemplateData *template_data; OptFpList *ofl; /* * allocate the data structure and attach * it to the rule's data struct list */ template_data = (TemplateData *) SnortAlloc(sizeof(TemplateData)); /* * If this is a transport layer protocol plugin, be sure to * check that the protocol that is passed in matches the * transport layer protocol that you're using for this rule! */ /* * any other initialization of this plugin should be performed here */ /* * this is where the keyword arguments are processed and * placed into the rule option's data structure */ TemplateRuleParseFunction(data, otn, template_data); /* * finally, attach the option's detection function * to the rule's detect function pointer list * * AddOptFuncToList returns a pointer to the node in * the function pointer list where the detector function * is linked into the detection engine, we will grab the * pointer to this node so that we can assign the * config data for this rule option to the functional * node's context pointer */ ofl = AddOptFuncToList(TemplateDetectorFunction, otn); /* * this is where we set the functional node's context pointer * so that the plugin can find the data to test the network * traffic against */ ofl->context = (void *) template_data; } /* * * Function: TemplateRuleParseFunction(char *, OptTreeNode *) * * Purpose: This is the function that is used to process the option keyword's * arguments and attach them to the rule's data structures. * * Arguments: data => argument data * otn => pointer to the current rule's OTN * td => pointer to the configuration storage struct * * Returns: void function * */ static void TemplateRuleParseFunction( char *data, OptTreeNode *otn, TemplateData *td) { /* * manipulate the option arguments here */ /* * see the code in src/detection_plugins for examples of parsing Snort * rule options */ /* * set the final option arguments here */ } /* * * Function: TemplateDetectorFunction(char *, OptTreeNode *, OptFpList *) * * Purpose: Use this function to perform the particular detection routine * that this rule keyword is supposed to encompass. * * Arguments: data => argument data * otn => pointer to the current rule's OTN * fp_list => pointer to the function pointer list current node * * Returns: If the detection test fails, this function *must* return a zero! * On success, it calls the next function in the detection list * */ static int TemplateDetectorFunction( Packet *p, struct _OptTreeNode *otn, OptFpList *fp_list) { TemplateData *td; /* ptr to the detection option's data */ /* * Try to make this function as quick as possible, the faster the * detection plugins are, the less packet loss the program will * experience! Avoid doing things like declaring variables or * anything other than just doing the test and moving on... */ /* * get the current option's context data */ td = (TemplateData *) fp_list->context; /* * your detection function tests go here */ if (the_test_is_successful) { /* call the next function in the function list recursively */ /* THIS CALL *MUST* BE IN THE PLUGIN, OTHERWISE YOU WILL BREAK SNORT'S DETECTION ENGINE!!! */ return fp_list->next->OptTestFunc(p, otn, fp_list->next); } #ifdef DEBUG else { /* * you can put debug comments here or not */ DebugMessage(DEBUG_PLUGIN,"No match\n"); } #endif /* * if the test isn't successful, this function *must* return 0 */ return 0; } snort-2.9.6.0/templates/Makefile.am0000644000000000000000000000017307744774522013777 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies EXTRA_DIST = sp_template.c spp_template.c sp_template.h spp_template.h snort-2.9.6.0/templates/Makefile.in0000644000000000000000000003001412260606526013770 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = templates DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies EXTRA_DIST = sp_template.c spp_template.c sp_template.h spp_template.h all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign templates/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign templates/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/etc/0000755000000000000000000000000012260606571010562 500000000000000snort-2.9.6.0/etc/snort.conf0000644000000000000000000006630012260606571012523 00000000000000#-------------------------------------------------- # VRT Rule Packages Snort.conf # # For more information visit us at: # http://www.snort.org Snort Website # http://vrt-blog.snort.org/ Sourcefire VRT Blog # # Mailing list Contact: snort-sigs@lists.sourceforge.net # False Positive reports: fp@sourcefire.com # Snort bugs: bugs@snort.org # # Compatible with Snort Versions: # VERSIONS : 2.9.6.0 # # Snort build options: # OPTIONS : --enable-gre --enable-mpls --enable-targetbased --enable-ppm --enable-perfprofiling --enable-zlib --enable-active-response --enable-normalizer --enable-reload --enable-react --enable-flexresp3 # # Additional information: # This configuration file enables active response, to run snort in # test mode -T you are required to supply an interface -i # or test mode will fail to fully validate the configuration and # exit with a FATAL error #-------------------------------------------------- ################################################### # This file contains a sample snort configuration. # You should take the following steps to create your own custom configuration: # # 1) Set the network variables. # 2) Configure the decoder # 3) Configure the base detection engine # 4) Configure dynamic loaded libraries # 5) Configure preprocessors # 6) Configure output plugins # 7) Customize your rule set # 8) Customize preprocessor and decoder rule set # 9) Customize shared object rule set ################################################### ################################################### # Step #1: Set the network variables. For more information, see README.variables ################################################### # Setup the network addresses you are protecting ipvar HOME_NET any # Set up the external network addresses. Leave as "any" in most situations ipvar EXTERNAL_NET any # List of DNS servers on your network ipvar DNS_SERVERS $HOME_NET # List of SMTP servers on your network ipvar SMTP_SERVERS $HOME_NET # List of web servers on your network ipvar HTTP_SERVERS $HOME_NET # List of sql servers on your network ipvar SQL_SERVERS $HOME_NET # List of telnet servers on your network ipvar TELNET_SERVERS $HOME_NET # List of ssh servers on your network ipvar SSH_SERVERS $HOME_NET # List of ftp servers on your network ipvar FTP_SERVERS $HOME_NET # List of sip servers on your network ipvar SIP_SERVERS $HOME_NET # List of ports you run web servers on portvar HTTP_PORTS [36,80,81,82,83,84,85,86,87,88,89,90,311,383,555,591,593,631,801,808,818,901,972,1158,1220,1414,1533,1741,1830,2231,2301,2381,2809,3029,3037,3057,3128,3443,3702,4000,4343,4848,5117,5250,6080,6173,6988,7000,7001,7144,7145,7510,7770,7777,7779,8000,8008,8014,8028,8080,8081,8082,8085,8088,8090,8118,8123,8180,8181,8222,8243,8280,8300,8500,8509,8800,8888,8899,9000,9060,9080,9090,9091,9111,9443,9999,10000,11371,12601,15489,29991,33300,34412,34443,34444,41080,44449,50000,50002,51423,53331,55252,55555,56712] # List of ports you want to look for SHELLCODE on. portvar SHELLCODE_PORTS !80 # List of ports you might see oracle attacks on portvar ORACLE_PORTS 1024: # List of ports you want to look for SSH connections on: portvar SSH_PORTS 22 # List of ports you run ftp servers on portvar FTP_PORTS [21,2100,3535] # List of ports you run SIP servers on portvar SIP_PORTS [5060,5061,5600] # List of file data ports for file inspection portvar FILE_DATA_PORTS [$HTTP_PORTS,110,143] # List of GTP ports for GTP preprocessor portvar GTP_PORTS [2123,2152,3386] # other variables, these should not be modified ipvar AIM_SERVERS [64.12.24.0/23,64.12.28.0/23,64.12.161.0/24,64.12.163.0/24,64.12.200.0/24,205.188.3.0/24,205.188.5.0/24,205.188.7.0/24,205.188.9.0/24,205.188.153.0/24,205.188.179.0/24,205.188.248.0/24] # Path to your rules files (this can be a relative path) # Note for Windows users: You are advised to make this an absolute path, # such as: c:\snort\rules var RULE_PATH ../rules var SO_RULE_PATH ../so_rules var PREPROC_RULE_PATH ../preproc_rules # If you are using reputation preprocessor set these # Currently there is a bug with relative paths, they are relative to where snort is # not relative to snort.conf like the above variables # This is completely inconsistent with how other vars work, BUG 89986 # Set the absolute path appropriately var WHITE_LIST_PATH ../rules var BLACK_LIST_PATH ../rules ################################################### # Step #2: Configure the decoder. For more information, see README.decode ################################################### # Stop generic decode events: config disable_decode_alerts # Stop Alerts on experimental TCP options config disable_tcpopt_experimental_alerts # Stop Alerts on obsolete TCP options config disable_tcpopt_obsolete_alerts # Stop Alerts on T/TCP alerts config disable_tcpopt_ttcp_alerts # Stop Alerts on all other TCPOption type events: config disable_tcpopt_alerts # Stop Alerts on invalid ip options config disable_ipopt_alerts # Alert if value in length field (IP, TCP, UDP) is greater th elength of the packet # config enable_decode_oversized_alerts # Same as above, but drop packet if in Inline mode (requires enable_decode_oversized_alerts) # config enable_decode_oversized_drops # Configure IP / TCP checksum mode config checksum_mode: all # Configure maximum number of flowbit references. For more information, see README.flowbits # config flowbits_size: 64 # Configure ports to ignore # config ignore_ports: tcp 21 6667:6671 1356 # config ignore_ports: udp 1:17 53 # Configure active response for non inline operation. For more information, see REAMDE.active # config response: eth0 attempts 2 # Configure DAQ related options for inline operation. For more information, see README.daq # # config daq: # config daq_dir: # config daq_mode: # config daq_var: # # ::= pcap | afpacket | dump | nfq | ipq | ipfw # ::= read-file | passive | inline # ::= arbitrary = ::= path as to where to look for DAQ module so's # Configure specific UID and GID to run snort as after dropping privs. For more information see snort -h command line options # # config set_gid: # config set_uid: # Configure default snaplen. Snort defaults to MTU of in use interface. For more information see README # # config snaplen: # # Configure default bpf_file to use for filtering what traffic reaches snort. For more information see snort -h command line options (-F) # # config bpf_file: # # Configure default log directory for snort to log to. For more information see snort -h command line options (-l) # # config logdir: ################################################### # Step #3: Configure the base detection engine. For more information, see README.decode ################################################### # Configure PCRE match limitations config pcre_match_limit: 3500 config pcre_match_limit_recursion: 1500 # Configure the detection engine See the Snort Manual, Configuring Snort - Includes - Config config detection: search-method ac-split search-optimize max-pattern-len 20 # Configure the event queue. For more information, see README.event_queue config event_queue: max_queue 8 log 5 order_events content_length ################################################### ## Configure GTP if it is to be used. ## For more information, see README.GTP #################################################### # config enable_gtp ################################################### # Per packet and rule latency enforcement # For more information see README.ppm ################################################### # Per Packet latency configuration #config ppm: max-pkt-time 250, \ # fastpath-expensive-packets, \ # pkt-log # Per Rule latency configuration #config ppm: max-rule-time 200, \ # threshold 3, \ # suspend-expensive-rules, \ # suspend-timeout 20, \ # rule-log alert ################################################### # Configure Perf Profiling for debugging # For more information see README.PerfProfiling ################################################### #config profile_rules: print all, sort avg_ticks #config profile_preprocs: print all, sort avg_ticks ################################################### # Configure protocol aware flushing # For more information see README.stream5 ################################################### config paf_max: 16000 ################################################### # Step #4: Configure dynamic loaded libraries. # For more information, see Snort Manual, Configuring Snort - Dynamic Modules ################################################### # path to dynamic preprocessor libraries dynamicpreprocessor directory /usr/local/lib/snort_dynamicpreprocessor/ # path to base preprocessor engine dynamicengine /usr/local/lib/snort_dynamicengine/libsf_engine.so # path to dynamic rules libraries dynamicdetection directory /usr/local/lib/snort_dynamicrules ################################################### # Step #5: Configure preprocessors # For more information, see the Snort Manual, Configuring Snort - Preprocessors ################################################### # GTP Control Channle Preprocessor. For more information, see README.GTP # preprocessor gtp: ports { 2123 3386 2152 } # Inline packet normalization. For more information, see README.normalize # Does nothing in IDS mode preprocessor normalize_ip4 preprocessor normalize_tcp: ips ecn stream preprocessor normalize_icmp4 preprocessor normalize_ip6 preprocessor normalize_icmp6 # Target-based IP defragmentation. For more inforation, see README.frag3 preprocessor frag3_global: max_frags 65536 preprocessor frag3_engine: policy windows detect_anomalies overlap_limit 10 min_fragment_length 100 timeout 180 # Target-Based stateful inspection/stream reassembly. For more inforation, see README.stream5 preprocessor stream5_global: track_tcp yes, \ track_udp yes, \ track_icmp no, \ max_tcp 262144, \ max_udp 131072, \ max_active_responses 2, \ min_response_seconds 5 preprocessor stream5_tcp: policy windows, detect_anomalies, require_3whs 180, \ overlap_limit 10, small_segments 3 bytes 150, timeout 180, \ ports client 21 22 23 25 42 53 70 79 109 110 111 113 119 135 136 137 139 143 \ 161 445 513 514 587 593 691 1433 1521 1741 2100 3306 6070 6665 6666 6667 6668 6669 \ 7000 8181 32770 32771 32772 32773 32774 32775 32776 32777 32778 32779, \ ports both 36 80 81 82 83 84 85 86 87 88 89 90 110 311 383 443 465 563 555 591 593 631 636 801 808 818 901 972 989 992 993 994 995 1158 1220 1414 1533 1741 1830 2231 2301 2381 2809 3029 3037 3057 3128 3443 3702 4000 4343 4848 5117 5250 6080 6173 6988 7907 7000 7001 7144 7145 7510 7802 7770 7777 7779 \ 7801 7900 7901 7902 7903 7904 7905 7906 7908 7909 7910 7911 7912 7913 7914 7915 7916 \ 7917 7918 7919 7920 8000 8008 8014 8028 8080 8081 8082 8085 8088 8090 8118 8123 8180 8181 8222 8243 8280 8300 8500 8509 8800 8888 8899 9000 9060 9080 9090 9091 9111 9443 9999 10000 11371 12601 15489 29991 33300 34412 34443 34444 41080 44449 50000 50002 51423 53331 55252 55555 56712 preprocessor stream5_udp: timeout 180 # performance statistics. For more information, see the Snort Manual, Configuring Snort - Preprocessors - Performance Monitor # preprocessor perfmonitor: time 300 file /var/snort/snort.stats pktcnt 10000 # HTTP normalization and anomaly detection. For more information, see README.http_inspect preprocessor http_inspect: global iis_unicode_map unicode.map 1252 compress_depth 65535 decompress_depth 65535 preprocessor http_inspect_server: server default \ http_methods { GET POST PUT SEARCH MKCOL COPY MOVE LOCK UNLOCK NOTIFY POLL BCOPY BDELETE BMOVE LINK UNLINK OPTIONS HEAD DELETE TRACE TRACK CONNECT SOURCE SUBSCRIBE UNSUBSCRIBE PROPFIND PROPPATCH BPROPFIND BPROPPATCH RPC_CONNECT PROXY_SUCCESS BITS_POST CCM_POST SMS_POST RPC_IN_DATA RPC_OUT_DATA RPC_ECHO_DATA } \ chunk_length 500000 \ server_flow_depth 0 \ client_flow_depth 0 \ post_depth 65495 \ oversize_dir_length 500 \ max_header_length 750 \ max_headers 100 \ max_spaces 200 \ small_chunk_length { 10 5 } \ ports { 36 80 81 82 83 84 85 86 87 88 89 90 311 383 555 591 593 631 801 808 818 901 972 1158 1220 1414 1741 1830 2231 2301 2381 2809 3029 3037 3057 3128 3443 3702 4000 4343 4848 5117 5250 6080 6173 6988 7000 7001 7144 7145 7510 7770 7777 7779 8000 8008 8014 8028 8080 8081 8082 8085 8088 8090 8118 8123 8180 8181 8222 8243 8280 8300 8500 8509 8800 8888 8899 9000 9060 9080 9090 9091 9111 9443 9999 10000 11371 12601 15489 29991 33300 34412 34443 34444 41080 44449 50000 50002 51423 53331 55252 55555 56712 } \ non_rfc_char { 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 } \ enable_cookie \ extended_response_inspection \ inspect_gzip \ normalize_utf \ unlimited_decompress \ normalize_javascript \ apache_whitespace no \ ascii no \ bare_byte no \ directory no \ double_decode no \ iis_backslash no \ iis_delimiter no \ iis_unicode no \ multi_slash no \ utf_8 no \ u_encode yes \ webroot no # ONC-RPC normalization and anomaly detection. For more information, see the Snort Manual, Configuring Snort - Preprocessors - RPC Decode preprocessor rpc_decode: 111 32770 32771 32772 32773 32774 32775 32776 32777 32778 32779 no_alert_multiple_requests no_alert_large_fragments no_alert_incomplete # Back Orifice detection. preprocessor bo # FTP / Telnet normalization and anomaly detection. For more information, see README.ftptelnet preprocessor ftp_telnet: global inspection_type stateful encrypted_traffic no check_encrypted preprocessor ftp_telnet_protocol: telnet \ ayt_attack_thresh 20 \ normalize ports { 23 } \ detect_anomalies preprocessor ftp_telnet_protocol: ftp server default \ def_max_param_len 100 \ ports { 21 2100 3535 } \ telnet_cmds yes \ ignore_telnet_erase_cmds yes \ ftp_cmds { ABOR ACCT ADAT ALLO APPE AUTH CCC CDUP } \ ftp_cmds { CEL CLNT CMD CONF CWD DELE ENC EPRT } \ ftp_cmds { EPSV ESTA ESTP FEAT HELP LANG LIST LPRT } \ ftp_cmds { LPSV MACB MAIL MDTM MIC MKD MLSD MLST } \ ftp_cmds { MODE NLST NOOP OPTS PASS PASV PBSZ PORT } \ ftp_cmds { PROT PWD QUIT REIN REST RETR RMD RNFR } \ ftp_cmds { RNTO SDUP SITE SIZE SMNT STAT STOR STOU } \ ftp_cmds { STRU SYST TEST TYPE USER XCUP XCRC XCWD } \ ftp_cmds { XMAS XMD5 XMKD XPWD XRCP XRMD XRSQ XSEM } \ ftp_cmds { XSEN XSHA1 XSHA256 } \ alt_max_param_len 0 { ABOR CCC CDUP ESTA FEAT LPSV NOOP PASV PWD QUIT REIN STOU SYST XCUP XPWD } \ alt_max_param_len 200 { ALLO APPE CMD HELP NLST RETR RNFR STOR STOU XMKD } \ alt_max_param_len 256 { CWD RNTO } \ alt_max_param_len 400 { PORT } \ alt_max_param_len 512 { SIZE } \ chk_str_fmt { ACCT ADAT ALLO APPE AUTH CEL CLNT CMD } \ chk_str_fmt { CONF CWD DELE ENC EPRT EPSV ESTP HELP } \ chk_str_fmt { LANG LIST LPRT MACB MAIL MDTM MIC MKD } \ chk_str_fmt { MLSD MLST MODE NLST OPTS PASS PBSZ PORT } \ chk_str_fmt { PROT REST RETR RMD RNFR RNTO SDUP SITE } \ chk_str_fmt { SIZE SMNT STAT STOR STRU TEST TYPE USER } \ chk_str_fmt { XCRC XCWD XMAS XMD5 XMKD XRCP XRMD XRSQ } \ chk_str_fmt { XSEM XSEN XSHA1 XSHA256 } \ cmd_validity ALLO < int [ char R int ] > \ cmd_validity EPSV < [ { char 12 | char A char L char L } ] > \ cmd_validity MACB < string > \ cmd_validity MDTM < [ date nnnnnnnnnnnnnn[.n[n[n]]] ] string > \ cmd_validity MODE < char ASBCZ > \ cmd_validity PORT < host_port > \ cmd_validity PROT < char CSEP > \ cmd_validity STRU < char FRPO [ string ] > \ cmd_validity TYPE < { char AE [ char NTC ] | char I | char L [ number ] } > preprocessor ftp_telnet_protocol: ftp client default \ max_resp_len 256 \ bounce yes \ ignore_telnet_erase_cmds yes \ telnet_cmds yes # SMTP normalization and anomaly detection. For more information, see README.SMTP preprocessor smtp: ports { 25 465 587 691 } \ inspection_type stateful \ b64_decode_depth 0 \ qp_decode_depth 0 \ bitenc_decode_depth 0 \ uu_decode_depth 0 \ log_mailfrom \ log_rcptto \ log_filename \ log_email_hdrs \ normalize cmds \ normalize_cmds { ATRN AUTH BDAT CHUNKING DATA DEBUG EHLO EMAL ESAM ESND ESOM ETRN EVFY } \ normalize_cmds { EXPN HELO HELP IDENT MAIL NOOP ONEX QUEU QUIT RCPT RSET SAML SEND SOML } \ normalize_cmds { STARTTLS TICK TIME TURN TURNME VERB VRFY X-ADAT X-DRCP X-ERCP X-EXCH50 } \ normalize_cmds { X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUE XSTA XTRN XUSR } \ max_command_line_len 512 \ max_header_line_len 1000 \ max_response_line_len 512 \ alt_max_command_line_len 260 { MAIL } \ alt_max_command_line_len 300 { RCPT } \ alt_max_command_line_len 500 { HELP HELO ETRN EHLO } \ alt_max_command_line_len 255 { EXPN VRFY ATRN SIZE BDAT DEBUG EMAL ESAM ESND ESOM EVFY IDENT NOOP RSET } \ alt_max_command_line_len 246 { SEND SAML SOML AUTH TURN ETRN DATA RSET QUIT ONEX QUEU STARTTLS TICK TIME TURNME VERB X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUE XSTA XTRN XUSR } \ valid_cmds { ATRN AUTH BDAT CHUNKING DATA DEBUG EHLO EMAL ESAM ESND ESOM ETRN EVFY } \ valid_cmds { EXPN HELO HELP IDENT MAIL NOOP ONEX QUEU QUIT RCPT RSET SAML SEND SOML } \ valid_cmds { STARTTLS TICK TIME TURN TURNME VERB VRFY X-ADAT X-DRCP X-ERCP X-EXCH50 } \ valid_cmds { X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUE XSTA XTRN XUSR } \ xlink2state { enabled } # Portscan detection. For more information, see README.sfportscan # preprocessor sfportscan: proto { all } memcap { 10000000 } sense_level { low } # ARP spoof detection. For more information, see the Snort Manual - Configuring Snort - Preprocessors - ARP Spoof Preprocessor # preprocessor arpspoof # preprocessor arpspoof_detect_host: 192.168.40.1 f0:0f:00:f0:0f:00 # SSH anomaly detection. For more information, see README.ssh preprocessor ssh: server_ports { 22 } \ autodetect \ max_client_bytes 19600 \ max_encrypted_packets 20 \ max_server_version_len 100 \ enable_respoverflow enable_ssh1crc32 \ enable_srvoverflow enable_protomismatch # SMB / DCE-RPC normalization and anomaly detection. For more information, see README.dcerpc2 preprocessor dcerpc2: memcap 102400, events [co ] preprocessor dcerpc2_server: default, policy WinXP, \ detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server 593], \ autodetect [tcp 1025:, udp 1025:, rpc-over-http-server 1025:], \ smb_max_chain 3, smb_invalid_shares ["C$", "D$", "ADMIN$"] # DNS anomaly detection. For more information, see README.dns preprocessor dns: ports { 53 } enable_rdata_overflow # SSL anomaly detection and traffic bypass. For more information, see README.ssl preprocessor ssl: ports { 443 465 563 636 989 992 993 994 995 7801 7802 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 }, trustservers, noinspect_encrypted # SDF sensitive data preprocessor. For more information see README.sensitive_data preprocessor sensitive_data: alert_threshold 25 # SIP Session Initiation Protocol preprocessor. For more information see README.sip preprocessor sip: max_sessions 40000, \ ports { 5060 5061 5600 }, \ methods { invite \ cancel \ ack \ bye \ register \ options \ refer \ subscribe \ update \ join \ info \ message \ notify \ benotify \ do \ qauth \ sprack \ publish \ service \ unsubscribe \ prack }, \ max_uri_len 512, \ max_call_id_len 80, \ max_requestName_len 20, \ max_from_len 256, \ max_to_len 256, \ max_via_len 1024, \ max_contact_len 512, \ max_content_len 2048 # IMAP preprocessor. For more information see README.imap preprocessor imap: \ ports { 143 } \ b64_decode_depth 0 \ qp_decode_depth 0 \ bitenc_decode_depth 0 \ uu_decode_depth 0 # POP preprocessor. For more information see README.pop preprocessor pop: \ ports { 110 } \ b64_decode_depth 0 \ qp_decode_depth 0 \ bitenc_decode_depth 0 \ uu_decode_depth 0 # Modbus preprocessor. For more information see README.modbus preprocessor modbus: ports { 502 } # DNP3 preprocessor. For more information see README.dnp3 preprocessor dnp3: ports { 20000 } \ memcap 262144 \ check_crc # Reputation preprocessor. For more information see README.reputation preprocessor reputation: \ memcap 500, \ priority whitelist, \ nested_ip inner, \ whitelist $WHITE_LIST_PATH/white_list.rules, \ blacklist $BLACK_LIST_PATH/black_list.rules ################################################### # Step #6: Configure output plugins # For more information, see Snort Manual, Configuring Snort - Output Modules ################################################### # unified2 # Recommended for most installs # output unified2: filename merged.log, limit 128, nostamp, mpls_event_types, vlan_event_types # Additional configuration for specific types of installs # output alert_unified2: filename snort.alert, limit 128, nostamp # output log_unified2: filename snort.log, limit 128, nostamp # syslog # output alert_syslog: LOG_AUTH LOG_ALERT # pcap # output log_tcpdump: tcpdump.log # metadata reference data. do not modify these lines include classification.config include reference.config ################################################### # Step #7: Customize your rule set # For more information, see Snort Manual, Writing Snort Rules # # NOTE: All categories are enabled in this conf file ################################################### # site specific rules include $RULE_PATH/local.rules include $RULE_PATH/app-detect.rules include $RULE_PATH/attack-responses.rules include $RULE_PATH/backdoor.rules include $RULE_PATH/bad-traffic.rules include $RULE_PATH/blacklist.rules include $RULE_PATH/botnet-cnc.rules include $RULE_PATH/browser-chrome.rules include $RULE_PATH/browser-firefox.rules include $RULE_PATH/browser-ie.rules include $RULE_PATH/browser-other.rules include $RULE_PATH/browser-plugins.rules include $RULE_PATH/browser-webkit.rules include $RULE_PATH/chat.rules include $RULE_PATH/content-replace.rules include $RULE_PATH/ddos.rules include $RULE_PATH/dns.rules include $RULE_PATH/dos.rules include $RULE_PATH/experimental.rules include $RULE_PATH/exploit-kit.rules include $RULE_PATH/exploit.rules include $RULE_PATH/file-executable.rules include $RULE_PATH/file-flash.rules include $RULE_PATH/file-identify.rules include $RULE_PATH/file-image.rules include $RULE_PATH/file-java.rules include $RULE_PATH/file-multimedia.rules include $RULE_PATH/file-office.rules include $RULE_PATH/file-other.rules include $RULE_PATH/file-pdf.rules include $RULE_PATH/finger.rules include $RULE_PATH/ftp.rules include $RULE_PATH/icmp-info.rules include $RULE_PATH/icmp.rules include $RULE_PATH/imap.rules include $RULE_PATH/indicator-compromise.rules include $RULE_PATH/indicator-obfuscation.rules include $RULE_PATH/indicator-scan.rules include $RULE_PATH/indicator-shellcode.rules include $RULE_PATH/info.rules include $RULE_PATH/malware-backdoor.rules include $RULE_PATH/malware-cnc.rules include $RULE_PATH/malware-other.rules include $RULE_PATH/malware-tools.rules include $RULE_PATH/misc.rules include $RULE_PATH/multimedia.rules include $RULE_PATH/mysql.rules include $RULE_PATH/netbios.rules include $RULE_PATH/nntp.rules include $RULE_PATH/oracle.rules include $RULE_PATH/os-linux.rules include $RULE_PATH/os-mobile.rules include $RULE_PATH/os-other.rules include $RULE_PATH/os-solaris.rules include $RULE_PATH/os-windows.rules include $RULE_PATH/other-ids.rules include $RULE_PATH/p2p.rules include $RULE_PATH/phishing-spam.rules include $RULE_PATH/policy-multimedia.rules include $RULE_PATH/policy-other.rules include $RULE_PATH/policy.rules include $RULE_PATH/policy-social.rules include $RULE_PATH/policy-spam.rules include $RULE_PATH/pop2.rules include $RULE_PATH/pop3.rules include $RULE_PATH/protocol-dns.rules include $RULE_PATH/protocol-finger.rules include $RULE_PATH/protocol-ftp.rules include $RULE_PATH/protocol-icmp.rules include $RULE_PATH/protocol-imap.rules include $RULE_PATH/protocol-nntp.rules include $RULE_PATH/protocol-pop.rules include $RULE_PATH/protocol-rpc.rules include $RULE_PATH/protocol-scada.rules include $RULE_PATH/protocol-services.rules include $RULE_PATH/protocol-snmp.rules include $RULE_PATH/protocol-telnet.rules include $RULE_PATH/protocol-tftp.rules include $RULE_PATH/protocol-voip.rules include $RULE_PATH/pua-adware.rules include $RULE_PATH/pua-other.rules include $RULE_PATH/pua-p2p.rules include $RULE_PATH/pua-toolbars.rules include $RULE_PATH/rpc.rules include $RULE_PATH/rservices.rules include $RULE_PATH/scada.rules include $RULE_PATH/scan.rules include $RULE_PATH/server-apache.rules include $RULE_PATH/server-iis.rules include $RULE_PATH/server-mail.rules include $RULE_PATH/server-mssql.rules include $RULE_PATH/server-mysql.rules include $RULE_PATH/server-oracle.rules include $RULE_PATH/server-other.rules include $RULE_PATH/server-samba.rules include $RULE_PATH/server-webapp.rules include $RULE_PATH/shellcode.rules include $RULE_PATH/smtp.rules include $RULE_PATH/snmp.rules include $RULE_PATH/specific-threats.rules include $RULE_PATH/spyware-put.rules include $RULE_PATH/sql.rules include $RULE_PATH/telnet.rules include $RULE_PATH/tftp.rules include $RULE_PATH/virus.rules include $RULE_PATH/voip.rules include $RULE_PATH/web-activex.rules include $RULE_PATH/web-attacks.rules include $RULE_PATH/web-cgi.rules include $RULE_PATH/web-client.rules include $RULE_PATH/web-coldfusion.rules include $RULE_PATH/web-frontpage.rules include $RULE_PATH/web-iis.rules include $RULE_PATH/web-misc.rules include $RULE_PATH/web-php.rules include $RULE_PATH/x11.rules ################################################### # Step #8: Customize your preprocessor and decoder alerts # For more information, see README.decoder_preproc_rules ################################################### # decoder and preprocessor event rules # include $PREPROC_RULE_PATH/preprocessor.rules # include $PREPROC_RULE_PATH/decoder.rules # include $PREPROC_RULE_PATH/sensitive-data.rules ################################################### # Step #9: Customize your Shared Object Snort Rules # For more information, see http://vrt-blog.snort.org/2009/01/using-vrt-certified-shared-object-rules.html ################################################### # dynamic library rules # include $SO_RULE_PATH/bad-traffic.rules # include $SO_RULE_PATH/chat.rules # include $SO_RULE_PATH/dos.rules # include $SO_RULE_PATH/exploit.rules # include $SO_RULE_PATH/icmp.rules # include $SO_RULE_PATH/imap.rules # include $SO_RULE_PATH/misc.rules # include $SO_RULE_PATH/multimedia.rules # include $SO_RULE_PATH/netbios.rules # include $SO_RULE_PATH/nntp.rules # include $SO_RULE_PATH/p2p.rules # include $SO_RULE_PATH/smtp.rules # include $SO_RULE_PATH/snmp.rules # include $SO_RULE_PATH/specific-threats.rules # include $SO_RULE_PATH/web-activex.rules # include $SO_RULE_PATH/web-client.rules # include $SO_RULE_PATH/web-iis.rules # include $SO_RULE_PATH/web-misc.rules # Event thresholding or suppression commands. See threshold.conf include threshold.conf snort-2.9.6.0/etc/file_magic.conf0000644000000000000000000005063612260355636013445 00000000000000file type:XLW; id:1; category: Office Documents; msg:"Excel spreadsheet subheader (MS Office)"; rev:1; content:| 09 08 10 00 00 06 05 00 |; offset:512; file type:POSIX_TAR; id:2; category:Archive; msg:"POSIX Tape Archive file"; rev:1; content:| 75 73 74 61 72 00 20 20 |; offset:257; file type:OLD_TAR; id:3; category:Archive; msg:"Pre-POSIX Tape Archive file"; rev:1; content:| 75 73 74 61 72 20 |; offset:257; file type:MOV; id:4; category:Multimedia; msg:"QuickTime movie file"; rev:1; content:| 66 72 65 65 |; offset:4; file type:MOV; id:5; category: Multimedia; msg:"QuickTime movie file"; rev:1; content:| 6D 6F 6F 76 |; offset:4; file type:MOV; id:6;category: Multimedia; msg:"QuickTime movie file"; rev:1; content:| 6D 64 61 74 |; offset:4; file type:MOV; id:7; category: Multimedia; msg:"QuickTime movie file"; rev:1; content:| 70 6E 6F 74 |; offset:4; file type:MOV; id:8; category: Multimedia; msg:"QuickTime movie file"; rev:1; content:| 66 74 79 70 71 74 |; offset:4; file type:LHA; id:9; category:Archive;msg:"File compressed with lha utility/algorithm (lha, lzh)"; rev:1; content:| 2D 6C 68 |; offset:2; file type:ISO; id:10; category:System files; msg:"Disc Image file based on ISO-9660 standard (iso)c"; rev:1; content:| 43 44 30 30 31 |; offset:32769; file type:ISO; id:11; category:System files; msg:"Disc Image file based on ISO-9660 standard (iso)c"; rev:1; content:| 43 44 30 30 31 |; offset:34817; file type:ISO; id:12; category:System files; msg:"Disc Image file based on ISO-9660 standard (iso)c"; rev:1; content:| 43 44 30 30 31 |; offset:36865; file type:S3M; id:13; category:Multimedia; msg:"S3M audio module format"; rev:1; content:| 53 43 52 4d |; offset:44; file type:FLIC; id:14; category:Multimedia; msg:"FLIC Animation file"; rev:2; content:|11 AF|; offset:4; content:|40 01|; offset:8; content:|c8 00|; offset:10; content:|00 00|; offset:20; content:|00 00 00 00 00 00 00 00|; offset:42; file type:FLIC; id:15; category:Multimedia; msg:"FLIC Animation file"; rev:2; content:|12 AF|; offset:4; content:|40 01|; offset:8; content:|c8 00|; offset:10; content:|00 00|; offset:20; content:|00 00 00 00 00 00 00 00|; offset:42; file type:MSEXE; id:21; category:Executables; msg:"Windows/DOS executable file "; rev:1; content:| 4D 5A|; offset:0; file type:PDF; id:22; category:PDF files; msg:"PDF file "; rev:1; content:| 25 50 44 46|; offset:0; file type:RTF; id:23; category: Office Documents; msg:"Rich text format word processing file "; rev:1; content:| 7B 5C 72 74 66 31|; offset:0; file type:RIFF; id:24; category:Multimedia; msg:"Resource Interchange File Format "; rev:1; content:| 52 49 46 46|; offset:0; file type:MSCHM;id:25; category:Office Documents; msg:"Microsoft Compiled HTML Help File "; rev:1; content:| 49 54 53 46|; offset:0; file type:MSCAB; id:26; category:Archive; msg:"Microsoft Windows CAB "; rev:1; content:| 4D 53 43 46|; offset:0; file type:MSOLE2; id:27; category:Office Documents; msg:"Microsoft Office applications OLE Document "; rev:1; content:| D0 CF 11 E0 A1 B1 1A E1|; offset:0; file type:MSSZDD; id:28; category:Archive; msg:"SZDD file format"; rev:1; content:| 53 5A 44 44 88 F0 27 33 |; offset:0; file type:ZIP; id:29; category:Archive; msg:"PKZIP archive file"; rev:1; content:| 50 4B 03 04 |; offset:0; file type:RAR; id:30; category:Archive; msg:"WinRAR compressed archive file"; rev:1; content:| 52 61 72 21 1A 07 00 |; offset:0; file type:7Z; id:31; category:Archive; msg:"7-Zip compressed file"; rev:1; content:| 37 7A BC AF 27 1C |; offset:0; file type:BZ; id:32; category:Archive; msg:"bzip2 compressed archive"; rev:1; content:| 42 5A 68 |; offset:0; file type:GZ; id:33; category:Archive; msg:"GZ"; rev:1; content:| 1F 8B 08 |; offset:0; file type:ARJ; id:34; category:Archive; msg:"Compressed archive file"; rev:1; content:| 60 EA 00 00 |; offset:0; file type:ISHIELD_MSI; id:35; category:Executables; msg:"Install Shield v5.x or 6.x compressed file"; rev:1; content:| 49 53 63 28 |; offset:0; file type:BINHEX; id:36; category:Executables; msg:"Macintosh BinHex 4 Compressed Archive"; rev:1; content:| 28 54 68 69 73 20 66 69 6C 65 20 6D 75 73 74 20 62 65 20 63 6F 6E 76 65 72 74 65 64 20 77 69 74 68 20 42 69 6E 48 65 78 20 |; offset:0; file type:MAIL; id:37; category:Office Documents; msg:"E-mail files for Netscape, Eudora, Outlook Express and QuickMail."; rev:1; content:| 46 72 6F 6D 20 20 20 |; offset:0; file type:MAIL; id:38; category:Office Documents; msg:"E-mail files for Netscape, Eudora, Outlook Express and QuickMail."; rev:1; content:| 46 72 6F 6D 20 3F 3F 3F |; offset:0; file type:MAIL; id:39; category:Office Documents; msg:"E-mail files for Netscape, Eudora, Outlook Express and QuickMail."; rev:1; content:| 46 72 6F 6D 3A 20 |; offset:0; file type:MAIL; id:40; category:Office Documents; msg:"E-mail files for Netscape, Eudora, Outlook Express and QuickMail."; rev:1; content:| 52 65 74 75 72 6E 2D 50 61 74 68 3A 20 |; offset:0; file type:MAIL; id:41; category:Office Documents; msg:"E-mail files for Netscape, Eudora, Outlook Express and QuickMail."; rev:1; content:| 58 2D |; offset:0; file type:TNEF; id:42; category:Office Documents; msg:"Transport Neutral Encapsulation Format, an E-mail attachment format "; rev:1; content:| 78 9F 3E 22 |; offset:0; file type:BINARY_DATA; id:43; category:Executables; msg:"Universal Binary/Java Bytecode"; rev:1; content:| CA FE BA BE|; offset:0; file type:UUencoded; id:44; category:Encoded; msg:"UUencoded file"; rev:1; content:| 62 65 67 69 6E |; offset:0; file type:SCRENC; id:45; category:Encoded; msg:"Script encoder file"; rev:1; content:| 23 40 7E 5E |; offset:0; file type:ELF; id:46; category:Executables; msg:"Executable and Linking Format executable file (Linux/Unix)"; rev:1; content:| 7F 45 4C 46|; offset:0; file type:MACHO; id:47; category:Executables; msg:"Mach object file format "; rev:1; content:| CE FA ED FE |; offset:0; file type:MACHO; id:48; category:Executables; msg:"Mach object file format "; rev:1; content:| CF FA ED FE |; offset:0; file type:MACHO; id:49; category:Executables; msg:"Mach object file format "; rev:1; content:| FE ED FA CE |; offset:0; file type:MACHO; id:50; category:Executables; msg:"Mach object file format "; rev:1; content:| FE ED FA CF |; offset:0; file type:SIS; id:51; category:Archive; msg:"Software Installation Script, an archive for Symbian OS"; rev:1; content:| 19 04 00 10 |; offset:0; file type:SWF; id:52; category:Multimedia; msg:"Flash file "; rev:1; content:| 43 57 53 |; offset:0; file type:SWF; id:53; category:Multimedia; msg:"Flash file "; rev:1; content:| 46 57 53 |; offset:0; file type:SWF; id:54; category:Multimedia; msg:"Flash file "; rev:1; content:| 58 46 49 52|; offset:0; file type:CPIO_ODC; id:55; category:Archive; msg:"Archive created with the cpio utility- standard ASCII format"; rev:1; content:| 30 37 30 37 30 37 |; offset:0; file type:CPIO_NEWC; id:56; category:Archive; msg:"Archive created with the cpio utility- new ASCII (aka SVR4) format"; rev:1; content:| 30 37 30 37 30 31 |; offset:0; file type:CPIO_CRC; id:57; category:Archive; msg:"Archive created with the cpio utility- CRC format"; rev:1; content:| 30 37 30 37 30 32 |; offset:0; file type:MPEG; id:58; category:Multimedia; msg:"MPEG video file"; rev:1; content:| 00 00 01 B3|; offset:0; file type:MPEG; id:59; category:Multimedia; msg:"MPEG video file"; rev:1; content:| 00 00 01 BA|; offset:0; file type:EPS; id:60; category:PDF files; msg:"Adobe encapsulated PostScript file"; rev:1; content:| 25 21 50 53 2D 41 64 6F 62 65 2D |; offset:0; file type:RMF; id:61; category:Multimedia; msg:"RealNetworks RealMedia streaming media file"; rev:1; content:| 2E 52 4D 46 |; offset:0; file type:GIF; id:62; category:Graphics; msg:"GIF"; rev:1; content:| 47 49 46 38 37 61 |; offset:0; file type:GIF; id:63; category:Graphics; msg:"GIF"; rev:1; content:| 47 49 46 38 39 61 |; offset:0; file type:MP3; id:64; category:Multimedia; msg:"MPEG-1 Audio Layer 3 (MP3) audio file"; rev:1; content:| 49 44 33 |; offset:0; file type:MP3; id:65; category:Multimedia; msg:"MPEG-1 Audio Layer 3 (MP3) audio file"; rev:1; content:| FF FB 90 |; offset:0; file type:OGG; id:66; category:Multimedia; msg:"Ogg Vorbis Codec compressed Multimedia file"; rev:1; content:| 4F 67 67 53 |; offset:0; file type:RIFX; id:67; category:Multimedia; msg:"RIFX audio format"; rev:1; content:| 52 49 46 58 |; offset:0; file type:SYMANTEC; id:68; category:System files; msg:"Symantec files"; rev:1; content:| 58 2D 53 79 6D 61 6E 74 65 63 2D |; offset:0; file type:PNG; id:69; category:Graphics; msg:"Portable Network Graphics file"; rev:1; content:| 89 50 4E 47 0D 0A 1A 0A |; offset:0; file type:JPEG; id:70; category:Graphics; msg:"JPEG/JFIF graphics file"; rev:1; content:| FF D8 FF E0 |; offset:0; content:| 4A 46 49 46 00 |; offset:6; #file type:SIP_LOG; id:71; category:System files; msg:"SIP log file"; rev:1; content:| 53 49 50 2D 48 49 54 20 28 53 49 50 2F 48 |; offset:0; file type:JARPACK; id:72; category:Executables; msg:"Jar pack file"; rev:1; content:| CA FE D0 0D |; offset:0; file type:JAR; id:73; category:Archive; msg:"Java archive file"; rev:3; content:| 50 4B 03 04 |; offset:0; content:| 4D 45 54 41 2D 49 4E 46 2F |; offset: 30; file type:FLV; id:74; category:Multimedia; msg:"Flash video file"; rev:1; content:| 46 4C 56 01 |; offset:0; file type:WAV; id:75; category:Multimedia; msg:"Waveform Audio File Format"; rev:1; content:| 52 49 46 58 |; offset:0; file type:WAV; id:76; category:Multimedia; msg:"Waveform Audio File Format"; rev:1; content:| 62 65 61 74 |; offset:0; file type:WAV; id:77; category:Multimedia; msg:"Waveform Audio File Format"; rev:1; content:| 4D 58 43 33 |; offset:0; file type:FFMPEG; id:78; category:Multimedia; msg:"ffmpeg Multimedia framework"; rev:1; content:| 34 58 4D 56 |; offset:0; file type:DMG; id:79; category:System files; msg:"Apple Disk Image"; rev:1; content:| 45 52 02 00 |; offset:0; file type:DMG; id:80; category:System files; msg:"Apple Disk Image"; rev:1; content:| 32 49 4D 47 |; offset:0; file type:IVR; id:81; category:Multimedia; msg:"RealPlayer video file"; rev:1; content:| 2E 52 45 43 |; offset:0; file type:IVR; id:82; category:Multimedia; msg:"RealPlayer video file"; rev:1; content:| 2E 52 31 4D |; offset:0; file type:RA; id:83; category:Multimedia; msg:"RealAudio file"; rev:1; content:| 2E 52 4D 46 00 00 00 12 00 |; offset:0; file type:RA; id:84; category:Multimedia; msg:"RealAudio file"; rev:1; content:| 2E 72 61 FD 00 |; offset:0; file type:VMDK; id:85; category:System files; msg:"Virtual Machine Disk"; rev:1; content:| 43 4F 57 44 |; offset:0; file type:VMDK; id:86; category:System files; msg:"Virtual Machine Disk"; rev:1; content:|4B 44 4D |; offset:0; file type:VMDK; id:87; category:System files; msg:"Virtual Machine Disk"; rev:1; content:| 23 20 44 69 73 6B 20 44 65 73 63 72 69 70 74 6F |; offset:0; file type:VMDK; id:88; category:System files; msg:"Virtual Machine Disk"; rev:1; content:| 2E 03 00 00 01 |; offset:0; file type:FLAC; id:89; category:Multimedia; msg:"Free Lossless Audio Codec file"; rev:1; content:| 66 4C 61 43 00 00 00 22 |; offset:0; file type:S3M; id:90; category:Multimedia; msg:"S3M audio module format"; rev:1; content:| 53 43 52 4d |; offset:0; file type:ASF; id:91; category:Multimedia; msg:"Microsoft Windows Media Audio/Video File "; rev:1; content:| 30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C |; offset:0; #file type:CRYSTAL; id:92; category:Office Documents; msg:"Crystal Reports"; rev:1; content:| D0 CF 11 E0 A1 B1 1A E1 00 |; offset:0; file type:MSWORD_MAC5; id:93; category:Office Documents; msg:"Microsoft Word for Mac 5"; rev:1; content:| FE 37 00 23|; offset:0; file type:SYLKc; id:94; category:System files; msg:"Microsoft symbolic Link"; rev:1; content:| 49 44 3B 50 |; offset:0; file type:WP; id:95; category:Office Documents; msg:"WordPerfect text and graphics file"; rev:1; content:| FF 57 50 43|; offset:0; file type:WP; id:96; category:Office Documents; msg:"WordPerfect text and graphics file"; rev:1; content:| 81 CD AB|; offset:0; file type:TIFF; id:97; category:Graphics; msg:"Tagged Image File Format file"; rev:1; content:| 49 49 2A 00|; offset:0; file type:TIFF; id:98; category:Graphics; msg:"Tagged Image File Format file"; rev:1; content:| 49 20 49|; offset:0; file type:TIFF; id:99; category:Graphics; msg:"Tagged Image File Format file"; rev:1; content:| 4D 4D 00 2A|; offset:0; file type:TIFF; id:100; category:Graphics; msg:"Tagged Image File Format file"; rev:1; content:| 4D 4D 00 2B|; offset:0; file type:MWL; id:101; category:Office Documents; msg:"Metastock technical analysis program for traders"; rev:1; content:| 5b 4d 65 74 61 53 74 6f 63 6b |; offset:0; file type:MDB; id:102; category:Office Documents; msg:"Microsoft Access file"; rev:1; content:| 00 01 00 00 53 74 61 6E 64 61 72 64 20 4A 65 74 20 44 42 |; offset:0; file type:ACCDB; id:103; category:Office Documents; msg:"Microsoft Access 2007 file"; rev:1; content:| 00 01 00 00 53 74 61 6E 64 61 72 64 20 41 43 45 20 44 42|; offset:0; file type:MNY; id:104; category:Office Documents; msg:"Microsoft Money file"; rev:1; content:| 00 01 00 00 4D 53 49 53 41 4D 20 44 61 74 61 62 61 73 65|; offset:0; file type:REC; id:105; category:Multimedia; msg:"RealNetworks Realplayer REC"; rev:1; content:| 2e 72 65 63 00 |; offset:0; file type:R1M; id:106; category:Multimedia; msg:"RealNetworks Realplayer R1M"; rev:1; content:| 2e 72 31 6d |; offset:0; file type:WAB; id:107; category:Office Documents; msg:"Outlook address file"; rev:1; content:| 9C CB CB 8D 13 75 D2 11 91 58 00 C0 4F 79 56 A4 |; offset:0; file type:WAB; id:108; category:Office Documents; msg:"Outlook address file"; rev:1; content:| 81 32 84 C1 85 05 D0 11 B2 90 00 AA 00 3C F6 76 |; offset:0; file type:M3U; id:109; category:Multimedia; msg:"Multimedia playlists"; rev:1; content:| 23 45 58 54 4d 33 55 |; offset:0; file type:MKV; id:110; category:Multimedia; msg:"Matroska stream file"; rev:1; content:| 1A 45 DF A3 93 42 82 88 6D 61 74 72 6F 73 6B 61|; offset:0; file type:IMG_PICT; id:111; category:Graphics; msg:"ChromaGraph Graphics Card Bitmap Graphic file"; rev:1; content:| 50 49 43 54 00 08 |; offset:0; file type:AMF; id:112; category:Multimedia; msg:"Advanced Module Format for digital music"; rev:1; content:| 41 4d 46 |; offset:0; file type:WEBM; id:113; category:Multimedia; msg:"WebM audio-video format"; rev:1; content:| 1A 45 DF A3|; offset:0; file type:MAYA; id:114; category:Graphics; msg:"Autodesk Maya"; rev:1; content:| 2f 2f 4d 61 79 61 |; offset:0; file type:MIDI; id:115; category:Multimedia; msg:"Musical Instrument Digital Interface (MIDI) sound file"; rev:1; content:| 4D 54 68 64 |; offset:0; file type:PLS; id:116; category:Multimedia; msg:"multimedia playlists"; rev:1; content:| 5b 70 6c 61 79 6c 69 73 74 5d |; offset:0; file type:SMIL; id:117; category:Multimedia; msg:"Synchronized Multimedia Integration Language"; rev:1; content:| 3c 73 6d 69 6c 3e |; offset:0; file type:SAMI; id:119; category:Multimedia; msg:"Synchronized Accessible Media Interchange"; rev:1; content:| 3c 53 41 4d 49 |; offset:0; file type:NEW_OFFICE; id:120; category:Office Documents; msg:"Microsoft Office Open XML Format (OOXML) Document (DOCX, PPTX, XLSX)"; rev:1; content:|50 4B 03 04 14 00 06 00|; offset:0; #From others file type:DWG; id:130; category:Graphics; msg:"Autodesk AutoCAD file (dwg) "; rev:1; content:| 41 43 31 30 |; offset:0; file type:ISO; id:131; category:System files; msg:"Disc Image file based on ISO-9660 standard (iso)c"; rev:1; content:| 00 00 01 BA |; offset:0; file type:MDI; id:132; category:Office Documents; msg:"Microsoft Document Imaging file (mdi)"; rev:1; content:| 45 50 |; offset:0; file type:PGD; id:133; category:System files; msg:"PGP disk image(PGD)"; rev:1; content:| 50 47 50 64 4D 41 49 4E |; offset:0; file type:PSD; id:134; category:Graphics; msg:"Photoshop image file (PSD)"; rev:1; content:|38 42 50 53 |; offset:0; file type:9XHIVE; id:135; category:System files; msg:"Windows 9x registry hive (REG)"; rev:1; content:| 43 52 45 47 |; offset:0; file type:REG; id:136; category:System files; msg:"Windows NT Registry and Registry Undo files (REG)"; rev:1; content:| 52 45 47 45 44 49 54 |; offset:0; file type:WMF; id:137; category:Graphics; msg:"Windows graphics metafile "; rev:1; content:| 01 00 09 00 00 03 |; offset:0; file type:WRI; id:138; category:Office Documents; msg:"Windows Write document file (wri) "; rev:1; content:| BE 00 00 00 AB 00 00 00 00 00 00 00 00|; offset:0; file type:RPM; id:139; category:Executables; msg:"RedHat Package Manager file"; rev:1; content:| ED AB EE DB |; offset:0; file type:ONE; id:140; category:Office Documents; msg:"Microsoft OneNote note"; rev:1; content:| E4 52 5C 7B 8C D8 A7 4D AE B1 53 78 D0 29 96 D3 |; offset:0; file type:MP4; id:141; category:Multimedia; msg:"MPEG-4 video files"; rev:1; content:| 00 00 00 18 66 74 79 70 33 67 70 35 |; offset:0; file type:MP4; id:142; category:Multimedia; msg:"MPEG-4 video files"; rev:1; content:| 00 00 00 14 66 74 79 70 69 73 6F 6D |; offset:0; file type:PCAP; id:143; category:System files; msg:"Packet capture file"; rev:1; content:| D4 C3 B2 A1 |; offset:0; file type:PCAP; id:144; category:System files; msg:"Packet capture file"; rev:1; content:|34 CD B2 A1 |; offset:0; file type:PCAP; id:145; category:System files; msg:"Packet capture file"; rev:1; content:|A1 B2 C3 D4 |; offset:0; file type:PCAP; id:146; category:System files; msg:"Packet capture file"; rev:1; content:|A1 B2 CD 34 |; offset:0; file type:PCAP; id:147; category:System files; msg:"Packet capture file"; rev:1; content:|52 54 53 53 |; offset:0; file type:BMP; id:148; category:Graphics; msg:"Bitmap image file"; rev:1; content:|42 4D |; offset:0; file type:ICO; id:149; category:Graphics; msg:"Windows icon file"; rev:1; content:| 00 00 01 00 |; offset:0; file type:TORRENT; id:150; category:Executables; msg:"BitTorrent File"; rev:1; content:| 64 38 3A 61 6E 6E 6F 75 6E 63 65 |; offset:0; file type:AMR; id:151; category:Multimedia; msg:"Adaptive Multi-Rate Codec File"; rev:1; content:| 23 21 41 4D 52|; offset:0; file type:SIT; id:152; category:Archive; msg:"StuffIt compressed archive"; rev:1; content:| 53 49 54 21 00|; offset:0; file type:PST; id:153; category:Office Documents; msg:"Microsoft Outlook Personal Folder File"; rev:1; content:| 21 42 44 4E |; offset:0; file type:HLP; id:154; category:Office Documents; msg:"Windows Help file"; rev:1; content:| 4C 4E 02 00 |; offset:0; file type:HLP; id:155; category:Office Documents; msg:"Windows Help file"; rev:1; content:| 3F 5F 03 00 |; offset:0; file type:AUTORUN; id:156; category:Executables; msg:"Windows Help file"; rev:1; content:| 5B 61 75 74 6F 72 75 6E 5D 0D 0A |; offset:0; file type:JPEG; id:157; category:Graphics; msg:"JPEG/JFIF graphics file"; rev:1; content:| FF D8 FF E1 |; offset:0; content:| 45 78 69 66 00 |; offset:6; file type:ARJ; id:158; category:Archive; msg:"Compressed archive file"; rev:1; content:| 60 EA |; offset:0; file type:MP3; id:159; category:Multimedia; msg:"MPEG-1 Audio Layer 3 (MP3) audio file"; rev:1; content:| FF FA |; offset:0; file type:SIT; id:160; category:Archive; msg:"StuffIt compressed archive"; rev:1; content:| 53 74 75 66 66 49 74 20|; offset:0; file type:NTHIVE; id:161; category:System files; msg:"Windows NT registry hive (REG)"; rev:1; content:| 72 65 67 66 |; offset:0; file type:WMF; id:162; category:Graphics; msg:"Windows graphics metafile "; rev:1; content:| D7 CD C6 9A |; offset:0; file type:SIS; id:163; category:Archive; msg:"Software Installation Script, an archive for Symbian OS"; rev:1; content:| 7A 1A 20 10 |; offset:0; file type:WRI; id:164; category:Office Documents; msg:"Windows Write document file (wri) "; rev:1; content:| 31 BE|; offset:0; file type:WRI; id:165; category:Office Documents; msg:"Windows Write document file (wri) "; rev:1; content:| 32 BE|; offset:0; file type:WAV; id:166; category:Multimedia; msg:"Waveform Audio File Format"; rev:1; content:| 52 49 46 46 |; offset:0; content:| 57 41 56 45 66 6D 74 20 |; offset:8; file type:MP4; id:167; category:Multimedia; msg:"MPEG-4 video files"; rev:1; content:| 66 74 79 70 6D 70 34 32 |; offset:4; file type:MP4; id:168; category:Multimedia; msg:"MPEG-4 video files"; rev:1; content:| 66 74 79 70 33 67 70 35 |; offset:4; file type:MP4; id:169; category:Multimedia; msg:"MPEG-4 video files"; rev:1; content:| 66 74 79 70 4D 53 4E 56 |; offset:4; file type:DICM; id:170; category:Multimedia; msg:"Digital Imaging and Communications in Medicine"; rev:1; content:| 44 49 43 4D |; offset:128; file type:ZIP_ENC; id:171; category:Archive; msg:"PKZIP encrypted archive file"; rev:1; content:| 50 4B 03 04 |; offset:0; content:| 01 |; offset:6; snort-2.9.6.0/etc/attribute_table.dtd0000644000000000000000000000240110662351337014347 00000000000000 snort-2.9.6.0/etc/threshold.conf0000644000000000000000000000477412260606507013360 00000000000000# Configure Thresholding and Suppression # ====================================== # # The threshold command is deprecated. Use detection_filter for thresholds # within a rule and event_filter for standalone threshold configurations. # Please see README.filters for more information on filters. # # Thresholding: # # This feature is used to reduce the number of logged alerts for noisy rules. # This can be tuned to significantly reduce false alarms, and it can also be # used to write a newer breed of rules. Thresholding commands limit the number # of times a particular event is logged during a specified time interval. # # There are 3 types of event_filters: # # 1) Limit # Alert on the 1st M events during the time interval, then ignore # events for the rest of the time interval. # # 2) Threshold # Alert every M times we see this event during the time interval. # # 3) Both # Alert once per time interval after seeing M occurrences of the # event, then ignore any additional events during the time interval. # # Threshold commands are formatted as: # # event_filter gen_id gen-id, sig_id sig-id, \ # type limit|threshold|both, track by_src|by_dst, \ # count n , seconds m # # Limit to logging 1 event per 60 seconds: # # event_filter gen_id 1, sig_id 1851, type limit, \ # track by_src, count 1, seconds 60 # # Global Threshold - Limit to logging 1 event per 60 seconds per IP triggering # each rule (rules are gen_id 1): # # event_filter gen_id 1, sig_id 0, type limit, track by_src, count 1, seconds 60 # # Global Threshold - Limit to logging 1 event per 60 seconds per IP triggering # any alert for any event generator: # # event_filter gen_id 0, sig_id 0, type limit, track by_src, count 1, seconds 60 # # Suppression: # # Suppression commands are standalone commands that reference generators and # sids and IP addresses via a CIDR block (or IP list). This allows a rule to be # completely suppressed, or suppressed when the causitive traffic is going to # or comming from a specific IP or group of IP addresses. # # Suppress this event completely: # # suppress gen_id 1, sig_id 1852 # # Suppress this event from this IP: # # suppress gen_id 1, sig_id 1852, track by_src, ip 10.1.1.54 # # Suppress this event to this CIDR block: # # suppress gen_id 1, sig_id 1852, track by_dst, ip 10.1.1.0/24 # # Global event filter to limit events from a unique src to 1 in 60 seconds # Disabled by default turn on if you want this functionality # # event_filter gen_id 0, sig_id 0, type limit, track by_src, count 1, seconds 60 snort-2.9.6.0/etc/unicode.map0000644000000000000000000047153611607417605012651 00000000000000# Windows Version: 6.01.7601 # OEM codepage: 437 # ACP codepage: 1252 # INSTALLED CODEPAGES 10081 (MAC - Turkish) 1254 (ANSI - Turkish) 00dd:59 00fd:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c7:5e 02c8:27 02cb:60 02cd:5f 02d8:5e 02d9:27 0300:60 0302:5e 0331:5f 0332:5f 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2032:27 2035:60 203c:21 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 2081:30 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2191:5e 2193:76 2194:2d 2195:7c 21a8:7c 2212:2d 2215:2f 2216:5c 2217:2a 221f:4c 2223:7c 2236:3a 223c:7e 2303:5e 2329:3c 232a:3e 2502:2d 250c:2d 2514:4c 2518:2d 251c:2b 2524:2b 252c:54 2534:2b 253c:2b 2550:3d 2554:2d 255a:4c 255d:2d 2566:54 256c:2b 2580:2d 2584:2d 2588:2d 2591:2d 2592:2d 2593:2d 25ac:2d 25b2:5e 25ba:3e 25c4:3c 25cb:30 25d9:30 263a:4f 263b:4f 263c:30 2640:2b 2642:3e 266a:64 266b:64 2758:7c 3000:20 3008:3c 3009:3e 301a:5b 301b:3d 301d:22 301e:22 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 857 (OEM - Turkish) 00dd:59 00fd:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bb:27 02bc:27 02c4:5e 02c6:5e 02c7:5e 02c8:27 02c9:16 02cb:60 02cd:5f 02d8:5e 02dc:7e 0300:60 0302:5e 0303:7e 0306:5e 030c:5e 030e:22 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:07 2030:25 2032:27 2033:22 2035:22 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a4:4c 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212b:41 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:2d 2215:2f 2216:5c 2217:2a 2219:07 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2758:7c 275b:27 275c:27 275d:22 275e:22 3000:20 3008:3c 3009:3e 301a:5b 301b:7d 301d:22 301e:22 301f:22 30fb:07 30fc:5f ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 20905 (IBM EBCDIC - Turkish) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005b:68 005e:5f 005f:6d 007b:48 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00c0:64 00c1:65 00c2:62 00c4:63 00c7:4a 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00d6:7b 00dc:7f 00df:59 00e0:44 00e1:45 00e2:42 00e4:43 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 010a:67 010b:47 011e:5a 0130:5b 0131:79 015e:7c 015f:6a ff01:4f ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3b:68 ff3e:5f ff3f:6d ff5b:48 28593 (ISO 8859-3 Latin 3) 00a1:21 00a2:63 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ae:52 00b9:31 00ba:6f 00bb:3e 00c3:41 00c5:41 00c6:41 00d0:44 00d5:4f 00d8:4f 00dd:59 00e3:61 00e5:61 00e6:61 00f5:6f 00f8:6f 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 0122:47 0123:67 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 1026 (IBM EBCDIC - Turkish (Latin-5)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005b:68 005e:5f 005f:6d 007b:48 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:4a 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00d6:7b 00dc:7f 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 011e:5a 0130:5b 0131:79 015e:7c 015f:6a ff01:4f ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3b:68 ff3e:5f ff3f:6d ff5b:48 10003 (MAC - Korean) 00a6:7c 00ae:52 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 20a9:5c 949 (ANSI/OEM - Korean) 00a6:7c 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 20a9:5c 1361 (Korean - Johab) 20a9:5c 20833 (IBM EBCDIC - Korean Extended) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:70 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a2:4a 00a6:6a 00ac:5f ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:70 ff3f:6d ff40:79 ff5c:4f ffa0:42 ffa1:43 ffa2:44 ffa3:45 ffa4:46 ffa5:47 ffa6:48 ffa7:49 ffa8:52 ffa9:53 ffaa:54 ffab:55 ffac:56 ffad:57 ffae:58 ffaf:59 ffb0:62 ffb1:63 ffb2:64 ffb3:65 ffb4:66 ffb5:67 ffb6:68 ffb7:69 ffb8:72 ffb9:73 ffba:74 ffbb:75 ffbc:76 ffbd:77 ffbe:78 00a6:7c 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 20a9:5c 50225 (ISO-2022 Korean) 51949 (EUC-Korean) 00a6:7c 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 20a9:5c 500 (IBM EBCDIC - International) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005e:5f 005f:6d 0060:79 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a6:6a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3e:5f ff3f:6d ff40:79 10004 (MAC - Arabic) 1256 (ANSI - Arabic) 00c0:41 00c2:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00ce:49 00cf:49 00d4:4f 00d9:55 00db:55 00dc:55 0191:46 0660:30 0661:31 0662:32 0663:33 0664:34 0665:35 0666:36 0667:37 0668:38 0669:39 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 720 (Arabic - Transparent ASMO) ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 708 (Arabic - ASMO) 864 (OEM - Arabic) 00a7:15 00b6:14 066a:25 203c:13 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 2550:05 2551:06 2554:0d 2557:0c 255a:0e 255d:0f 2560:0a 2563:08 2566:09 2569:0b 256c:07 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 263a:01 263c:04 266a:02 266b:03 20420 (IBM EBCDIC - Arabic) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005f:6d 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a2:4a 00a6:6a 00ac:5f 060c:79 0621:46 0622:47 0623:49 0624:52 0626:55 0627:56 0628:58 0629:62 062a:63 062b:65 062c:67 062d:69 062e:71 062f:73 0630:74 0631:75 0632:76 0633:77 0640:44 0651:42 066a:6c 066c:4b 066d:5c f8f6:77 f8fc:45 fe7c:42 fe7d:43 fe80:46 fe81:47 fe82:48 fe83:49 fe84:51 fe85:52 fe86:52 fe8b:55 fe8c:55 fe8d:56 fe8e:57 fe8f:58 fe90:58 fe91:59 fe92:59 fe93:62 fe94:62 fe95:63 fe96:63 fe97:64 fe98:64 fe99:65 fe9a:65 fe9b:66 fe9c:66 fe9d:67 fe9e:67 fe9f:68 fea0:68 fea1:69 fea2:69 fea3:70 fea4:70 fea5:71 fea6:71 fea7:72 fea8:72 fea9:73 feaa:73 feab:74 feac:74 fead:75 feae:75 feaf:76 feb0:76 feb3:78 feb4:78 ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3f:6d ff5c:4f 28596 (ISO 8859-6 Arabic) 00a1:21 00a2:63 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ae:52 00b2:32 00b3:33 00b7:2e 00b8:2c 00b9:31 00ba:6f 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 10008 (MAC - Simplified Chinese GB 2312) 936 (ANSI/OEM - Simplified Chinese GBK) 00a6:7c 00aa:61 00ad:2d 00b2:32 00b3:33 00b9:31 00ba:6f 00d0:44 00dd:59 00de:54 00e2:61 00f0:65 00fd:79 00fe:74 52936 (HZ-GB2312 Simplified Chinese) 54936 (GB18030 Simplified Chinese) 20936 (Simplified Chinese GB2312) 50227 (ISO-2022 Simplified Chinese) 10029 (MAC - Latin II) 775 (OEM - Baltic) 00a1:21 00a5:59 00aa:61 00ba:6f 00c0:41 00c3:41 00c8:45 00ca:45 00cc:49 00cf:49 00d1:4e 00d2:4f 00d9:55 00db:55 00e0:61 00e3:61 00e8:63 00ea:65 00ec:69 00ef:69 00f1:6e 00f2:6f 00f9:75 00fb:75 00ff:79 0108:43 0109:63 010a:43 010b:63 0114:45 0115:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012c:49 012d:69 0130:49 0131:69 0134:4a 0135:6a 014e:4f 014f:6f 0152:4f 0153:6f 015c:53 015d:73 0166:54 0167:74 0168:55 0169:75 016c:55 016d:75 0174:57 0175:77 0176:59 0177:79 0178:59 0180:62 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bb:27 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 03bc:75 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 201a:27 2022:07 2024:07 2026:07 2030:25 2032:27 2033:22 2035:22 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a4:4c 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212b:41 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:2d 2213:2d 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2758:7c 275b:27 275c:27 275d:22 275e:22 3000:20 3008:3c 3009:3e 301a:5b 301b:5d 301d:22 301e:22 301f:22 30fb:07 30fc:5f ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 1257 (ANSI - Baltic) ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 28594 (ISO 8859-4 Baltic) 00a1:21 00a2:63 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ae:52 00b2:32 00b3:33 00b7:2e 00b9:31 00ba:6f 00bb:3e 00c0:41 00c7:43 00c8:45 00ca:45 00cc:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d9:55 00dd:59 00e0:61 00e7:63 00e8:65 00ea:65 00ec:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f9:75 00fd:79 00ff:79 0102:41 0103:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010e:44 010f:64 0114:45 0115:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0124:48 0125:68 0126:48 0127:68 012c:49 012d:69 0130:49 0131:69 0134:4a 0135:6a 0139:4c 013a:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0147:4e 0148:6e 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0162:54 0163:74 0164:54 0165:74 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 28603 (ISO 8859-13 Latin 7) 00aa:61 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c7:43 00c8:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d4:4f 00d9:55 00da:55 00db:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e7:63 00e8:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f4:6f 00f9:75 00fa:75 00fb:75 00fd:79 00ff:79 0102:41 0103:61 0108:43 0109:63 010a:43 010b:63 010e:44 010f:64 0114:45 0115:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0124:48 0125:68 0128:49 0129:69 012c:49 012d:69 0130:49 0134:4a 0135:6a 0139:4c 013a:6c 013d:4c 013e:6c 0147:4e 0148:6e 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0158:52 0159:72 015c:53 015d:73 015e:53 015f:73 0162:54 0163:74 0164:54 0165:74 0168:55 0169:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0174:57 0175:77 0176:59 0177:79 0178:59 017f:73 01a0:4f 01a1:6f 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01e0:41 01e1:61 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 01f4:47 01f5:67 01f8:4e 01f9:6e 0200:41 0201:61 0202:41 0203:61 0204:45 0205:65 0206:45 0207:65 0208:49 0209:69 020a:49 020b:69 020c:4f 020d:6f 020e:4f 020f:6f 0210:52 0211:72 0212:52 0213:72 0214:55 0215:75 0216:55 0217:75 0218:53 0219:73 021a:54 021b:74 021e:48 021f:68 0226:41 0227:61 0228:45 0229:65 022e:4f 022f:6f 0230:4f 0231:6f 0232:59 0233:79 02b0:68 02b2:6a 02b3:72 02b7:77 02b8:79 02e1:6c 02e2:73 02e3:78 037e:3b 1e00:41 1e01:61 1e02:42 1e03:62 1e04:42 1e05:62 1e06:42 1e07:62 1e08:43 1e09:63 1e0a:44 1e0b:64 1e0c:44 1e0d:64 1e0e:44 1e0f:64 1e10:44 1e11:64 1e12:44 1e13:64 1e18:45 1e19:65 1e1a:45 1e1b:65 1e1c:45 1e1d:65 1e1e:46 1e1f:66 1e20:47 1e21:67 1e22:48 1e23:68 1e24:48 1e25:68 1e26:48 1e27:68 1e28:48 1e29:68 1e2a:48 1e2b:68 1e2c:49 1e2d:69 1e2e:49 1e2f:69 1e30:4b 1e31:6b 1e32:4b 1e33:6b 1e34:4b 1e35:6b 1e36:4c 1e37:6c 1e38:4c 1e39:6c 1e3a:4c 1e3b:6c 1e3c:4c 1e3d:6c 1e3e:4d 1e3f:6d 1e40:4d 1e41:6d 1e42:4d 1e43:6d 1e44:4e 1e45:6e 1e46:4e 1e47:6e 1e48:4e 1e49:6e 1e4a:4e 1e4b:6e 1e54:50 1e55:70 1e56:50 1e57:70 1e58:52 1e59:72 1e5a:52 1e5b:72 1e5c:52 1e5d:72 1e5e:52 1e5f:72 1e60:53 1e61:73 1e62:53 1e63:73 1e68:53 1e69:73 1e6a:54 1e6b:74 1e6c:54 1e6d:74 1e6e:54 1e6f:74 1e70:54 1e71:74 1e72:55 1e73:75 1e74:55 1e76:55 1e77:75 1e78:55 1e79:75 1e7c:56 1e7d:76 1e7e:56 1e7f:76 1e80:57 1e81:77 1e82:57 1e83:77 1e84:57 1e85:77 1e86:57 1e87:77 1e88:57 1e89:77 1e8a:58 1e8b:78 1e8c:58 1e8d:78 1e8e:59 1e8f:79 1e90:5a 1e91:7a 1e92:5a 1e93:7a 1e94:5a 1e95:7a 1e96:68 1e97:74 1e98:77 1e99:79 1e9b:73 1ea0:41 1ea1:61 1ea2:41 1ea3:61 1ea4:41 1ea5:61 1ea6:41 1ea7:61 1ea8:41 1ea9:61 1eaa:41 1eab:61 1eac:41 1ead:61 1eae:41 1eaf:61 1eb0:41 1eb1:61 1eb2:41 1eb3:61 1eb4:41 1eb5:61 1eb6:41 1eb7:61 1eb8:45 1eb9:65 1eba:45 1ebb:65 1ebc:45 1ebd:65 1ebe:45 1ebf:65 1ec0:45 1ec1:65 1ec2:45 1ec3:65 1ec4:45 1ec5:65 1ec6:45 1ec7:65 1ec8:49 1ec9:69 1eca:49 1ecb:69 1ecc:4f 1ecd:6f 1ece:4f 1ecf:6f 1ed0:4f 1ed1:6f 1ed2:4f 1ed3:6f 1ed4:4f 1ed5:6f 1ed6:4f 1ed7:6f 1ed8:4f 1ed9:6f 1eda:4f 1edb:6f 1edc:4f 1edd:6f 1ede:4f 1edf:6f 1ee0:4f 1ee1:6f 1ee2:4f 1ee3:6f 1ee4:55 1ee5:75 1ee6:55 1ee7:75 1ee8:55 1ee9:75 1eea:55 1eeb:75 1eec:55 1eed:75 1eee:55 1eef:75 1ef0:55 1ef1:75 1ef2:59 1ef3:79 1ef4:59 1ef5:79 1ef6:59 1ef7:79 1ef8:59 1ef9:79 1fef:60 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2007:20 2008:20 2009:20 200a:20 2024:2e 202f:20 205f:20 2070:30 2071:69 2074:34 2075:35 2076:36 2077:37 2078:38 2079:39 207a:2b 207c:3d 207d:28 207e:29 207f:6e 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 208a:2b 208c:3d 208d:28 208e:29 2102:43 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2119:50 211a:51 211b:52 211c:52 211d:52 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212f:65 2130:45 2131:46 2133:4d 2134:6f 2139:69 2145:44 2146:64 2147:65 2148:69 2149:6a 2160:49 2164:56 2169:58 216c:4c 216d:43 216e:44 216f:4d 2170:69 2174:76 2179:78 217c:6c 217d:63 217e:64 217f:6d 2260:3d 226e:3c 226f:3e 2460:31 2461:32 2462:33 2463:34 2464:35 2465:36 2466:37 2467:38 2468:39 24b6:41 24b7:42 24b8:43 24b9:44 24ba:45 24bb:46 24bc:47 24bd:48 24be:49 24bf:4a 24c0:4b 24c1:4c 24c2:4d 24c3:4e 24c4:4f 24c5:50 24c6:51 24c7:52 24c8:53 24c9:54 24ca:55 24cb:56 24cc:57 24cd:58 24ce:59 24cf:5a 24d0:61 24d1:62 24d2:63 24d3:64 24d4:65 24d5:66 24d6:67 24d7:68 24d8:69 24d9:6a 24da:6b 24db:6c 24dc:6d 24dd:6e 24de:6f 24df:70 24e0:71 24e1:72 24e2:73 24e3:74 24e4:75 24e5:76 24e6:77 24e7:78 24e8:79 24e9:7a 24ea:30 3000:20 fb29:2b fe33:5f fe34:5f fe35:28 fe36:29 fe37:7b fe38:7d fe4d:5f fe4e:5f fe4f:5f fe50:2c fe52:2e fe54:3b fe55:3a fe57:21 fe59:28 fe5a:29 fe5b:7b fe5c:7d fe5f:23 fe60:26 fe61:2a fe62:2b fe63:2d fe64:3c fe65:3e fe66:3d fe68:5c fe69:24 fe6a:25 fe6b:40 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 10001 (MAC - Japanese) 00a1:21 00a6:7c 00aa:61 00ad:2d 00ae:52 00b2:32 00b3:33 00b9:31 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00de:54 00df:73 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f0:64 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 932 (ANSI/OEM - Japanese Shift-JIS) 00a1:21 00a5:5c 00a6:7c 00a9:63 00aa:61 00ad:2d 00ae:52 00b2:32 00b3:33 00b9:31 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00de:54 00df:73 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f0:64 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00fe:74 00ff:79 20290 (IBM EBCDIC - Japanese Katakana Extended) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:70 005f:6d 0060:79 0061:62 0062:63 0063:64 0064:65 0065:66 0066:67 0067:68 0068:69 0069:71 006a:72 006b:73 006c:74 006d:75 006e:76 006f:77 0070:78 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a3:4a 00a5:5b 00ac:5f ff01:5a ff02:7f ff03:7b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:70 ff3f:6d ff40:79 ff41:62 ff42:63 ff43:64 ff44:65 ff45:66 ff46:67 ff47:68 ff48:69 ff49:71 ff4a:72 ff4b:73 ff4c:74 ff4d:75 ff4e:76 ff4f:77 ff50:78 ff5c:4f ff61:41 ff62:42 ff63:43 ff64:44 ff65:45 ff66:46 ff67:47 ff68:48 ff69:49 ff6a:51 ff6b:52 ff6c:53 ff6d:54 ff6e:55 ff6f:56 ff70:58 20932 (JIS X 0208-1990 & 0212-1990) 50220 (ISO-2022 Japanese with no halfwidth Katakana) 50221 (ISO-2022 Japanese with halfwidth Katakana) 50222 (ISO-2022 Japanese JIS X 0201-1989) 21027 (Ext Alpha Lowercase) 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005f:6d 0060:79 007c:4f 00a2:4a 00ac:5f f8c4:20 f8c5:21 f8c6:22 f8c7:23 f8c8:24 f8c9:25 f8ca:26 f8cb:27 f8cc:28 f8cd:29 f8ce:2a f8cf:2b f8d0:2c f8d1:2d f8d2:2e f8d3:2f f8d4:30 f8d5:31 f8d6:32 f8d7:33 f8d8:34 f8d9:35 f8da:36 f8db:37 f8dc:38 f8dd:39 f8de:3a f8df:3b f8e0:3c f8e1:3d f8e2:3f f8e3:68 f8e4:7e ff61:42 ff62:43 ff63:44 ff64:45 ff65:46 ff66:47 ff67:48 ff68:49 ff69:51 ff6a:52 ff6b:53 ff6c:54 ff6d:55 ff6e:56 ff6f:57 ff70:58 ff71:59 ff72:62 ff73:63 ff74:64 ff75:65 ff76:66 ff77:67 ff78:68 ff79:69 ff7a:70 ff7b:71 ff7c:72 ff7d:73 ff7e:74 ff7f:75 ff80:76 ff81:77 ff82:78 10007 (MAC - Cyrillic) 1251 (ANSI - Cyrillic) 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 203c:21 2190:3c 2191:5e 2192:3e 2193:76 2194:2d 221a:76 221f:4c 2500:2d 250c:2d 2514:4c 2518:2d 251c:2b 2524:2b 252c:54 2534:2b 253c:2b 2550:3d 2552:2d 2558:4c 2559:4c 255a:4c 255b:2d 255c:2d 255d:2d 2564:54 2565:54 2566:54 256a:2b 256b:2b 256c:2b 2580:2d 2584:2d 2588:2d 2591:2d 2592:2d 2593:2d 25ac:2d 25b2:5e 25ba:3e 25c4:3c 25cb:30 25d9:30 263a:4f 263b:4f 263c:30 2640:2b 2642:3e 266a:64 266b:64 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 866 (OEM - Russian) 00a7:15 00a9:63 00ab:3c 00ad:2d 00ae:52 00b1:2b 00b6:14 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2026:3a 2030:25 2039:3c 203a:3e 203c:13 2122:54 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 855 (OEM - Cyrillic) 00a9:63 00ac:2d 00ae:52 00b0:6f 00b1:2b 00b5:75 00b6:14 00b7:07 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2020:2b 2021:2b 2022:07 2026:3a 2030:25 2039:3c 203a:3e 203c:13 2122:54 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2219:07 221a:76 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:7f 2663:7f 2665:7f 2666:7f 266a:64 266b:64 20880 (IBM EBCDIC - Cyrillic (Russian)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005e:5f 005f:6d 0060:79 007c:6a 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00ad:73 0401:63 0402:59 0403:62 0404:64 0405:65 0406:66 0407:67 0408:68 0409:69 040a:70 040b:71 040c:72 040e:74 040f:75 042a:57 0430:77 0431:78 044e:76 0451:44 0452:42 0453:43 0454:45 0455:46 0456:47 0457:48 0458:49 0459:51 045a:52 045b:53 045c:54 045e:55 045f:56 2116:58 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3e:5f ff3f:6d ff40:79 ff5c:6a 28595 (ISO 8859-5 Cyrillic) 00a1:21 00a2:63 00a4:24 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ae:52 00b2:32 00b3:33 00b7:2e 00b8:2c 00b9:31 00ba:6f 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 20866 (Russian - KOI8) 00a7:15 00ab:3c 00ad:2d 00ae:52 00b1:2b 00b6:14 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2026:3a 2030:25 2039:3c 203a:3e 203c:13 2122:54 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 21866 (Ukrainian - KOI8-U) 00a7:15 00ab:3c 00ad:2d 00ae:52 00b1:2b 00b6:14 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2026:3a 2030:25 2039:3c 203a:3e 203c:13 2122:54 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 21025 (IBM EBCDIC - Cyrillic (Serbian, Bulgarian)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005e:5f 005f:6d 0060:79 007c:6a 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00ad:73 0401:63 0402:59 0403:62 0404:64 0405:65 0406:66 0407:67 0408:68 0409:69 040a:70 040b:71 040c:72 040e:74 040f:75 042a:57 0430:77 0431:78 044e:76 0451:44 0452:42 0453:43 0454:45 0455:46 0456:47 0457:48 0458:49 0459:51 045a:52 045b:53 045c:54 045e:55 045f:56 2116:58 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3e:5f ff3f:6d ff40:79 ff5c:6a 57002 (ISCII - Devanagari) 57003 (ISCII - Bengali) 57004 (ISCII - Tamil) 57005 (ISCII - Telugu) 57006 (ISCII - Assamese) 57007 (ISCII - Oriya) 57008 (ISCII - Kannada) 57009 (ISCII - Malayalam) 57011 (ISCII - Punjabi (Gurmukhi)) 57010 (ISCII - Gujarati) 10010 (MAC - Romania) 10017 (MAC - Ukraine) 10082 (MAC - Croatia) 1250 (ANSI - Central Europe) 00a1:21 00a2:63 00a3:4c 00a5:59 00aa:61 00b2:32 00b3:33 00b9:31 00ba:6f 00bc:31 00bd:31 00be:33 00c0:41 00c3:41 00c5:41 00c6:41 00c8:45 00ca:45 00cc:49 00cf:49 00d1:4e 00d2:4f 00d5:4f 00d8:4f 00d9:55 00db:55 00e0:61 00e3:61 00e5:61 00e6:61 00e8:65 00ea:65 00ec:69 00ef:69 00f1:6e 00f2:6f 00f5:6f 00f8:6f 00f9:75 00fb:75 00ff:79 0100:41 0101:61 0108:43 0109:63 010a:43 010b:63 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 013b:4c 013c:6c 0145:4e 0146:6e 014c:4f 014d:6f 014e:4f 014f:6f 0152:4f 0153:6f 0156:52 0157:72 015c:53 015d:73 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0180:62 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2032:27 2035:60 203c:21 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2191:5e 2194:2d 2195:7c 21a8:7c 2212:2d 2215:2f 2216:5c 2217:2a 221f:4c 2223:7c 2236:3a 223c:7e 2303:5e 2329:3c 232a:3e 2502:2d 250c:2d 2514:4c 2518:2d 251c:2b 2524:2b 252c:54 2534:2b 253c:2b 2550:3d 2554:2d 255a:4c 255d:2d 2566:54 256c:2b 2580:2d 2584:2d 2588:2d 2591:2d 2592:2d 2593:2d 25ac:2d 25b2:5e 25ba:3e 25c4:3c 25cb:30 25d9:30 263c:30 2640:2b 2642:3e 266a:64 266b:64 2758:7c 3000:20 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 852 (OEM - Latin II) 00a1:21 00a2:63 00a3:4c 00a5:59 00a6:7c 00a9:63 00aa:61 00ae:52 00b1:2b 00b2:32 00b3:33 00b5:75 00b6:14 00b7:07 00b9:31 00ba:6f 00bc:31 00bd:31 00be:33 00c0:41 00c3:41 00c5:41 00c6:41 00c8:45 00ca:45 00cc:49 00cf:49 00d1:4e 00d2:4f 00d5:4f 00d8:4f 00d9:55 00db:55 00e0:61 00e3:61 00e5:61 00e6:61 00e8:63 00ea:65 00ec:69 00ef:69 00f1:6e 00f2:6f 00f5:6f 00f8:6f 00f9:75 00fb:75 00ff:79 0100:41 0101:61 0108:43 0109:63 010a:43 010b:63 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 013b:4c 013c:6c 0145:4e 0146:6e 014c:4f 014d:6f 014e:4f 014f:6f 0152:4f 0153:6f 0156:52 0157:72 015c:53 015d:73 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0180:62 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bb:27 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 03bc:75 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:07 2030:25 2032:27 2033:22 2035:22 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a4:4c 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212b:41 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:2d 2213:2d 2215:2f 2216:5c 2217:2a 2219:07 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2758:7c 275b:27 275c:27 275d:22 275e:22 3000:20 3008:3c 3009:3e 301a:5b 301b:5d 301d:22 301e:22 301f:22 30fb:07 30fc:5f ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 28592 (ISO 8859-2 Central Europe) 00a1:21 00a2:63 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ae:52 00b2:32 00b3:33 00b7:2e 00b9:31 00ba:6f 00bb:3e 00c0:41 00c3:41 00c5:41 00c6:41 00c8:45 00ca:45 00cc:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d5:4f 00d8:4f 00d9:55 00db:55 00e0:61 00e3:61 00e5:61 00e6:61 00e8:65 00ea:65 00ec:69 00ef:69 00f1:6e 00f2:6f 00f5:6f 00f8:6f 00f9:75 00fb:75 00ff:79 0100:41 0101:61 0108:43 0109:63 010a:43 010b:63 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 013b:4c 013c:6c 0145:4e 0146:6e 014c:4f 014d:6f 014e:4f 014f:6f 0152:4f 0153:6f 0156:52 0157:72 015c:53 015d:73 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 10000 (MAC - Roman) 437 (OEM - United States) 00a4:0f 00a7:15 00a8:22 00a9:63 00ad:2d 00ae:72 00af:5f 00b3:33 00b4:27 00b6:14 00b8:2c 00b9:31 00be:5f 00c0:41 00c1:41 00c2:41 00c3:41 00c8:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d7:78 00d8:4f 00d9:55 00da:55 00db:55 00dd:59 00de:5f 00e3:61 00f0:64 00f5:6f 00f8:6f 00fd:79 00fe:5f 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02ca:27 02cb:60 02cd:5f 02dc:7e 0300:60 0301:27 0302:5e 0303:7e 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2017:5f 2018:60 2019:27 201a:2c 201c:22 201d:22 201e:2c 2020:2b 2022:07 2026:2e 2030:25 2032:27 2035:60 2039:3c 203a:3e 203c:13 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:09 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:54 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2212:2d 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2758:7c 3000:20 3007:09 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 850 (OEM - Multilingual Latin I) 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01a9:53 01ab:74 01ae:54 01af:55 01b0:75 01b6:5a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:27 02cd:5f 02dc:7e 0300:27 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 0393:47 03a3:53 03a6:46 03a9:4f 03b1:61 03b4:64 03b5:65 03c0:70 03c3:73 03c4:74 03c6:66 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:2e 2030:25 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:39 207f:6e 2080:30 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a7:50 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:54 2124:5a 2126:4f 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2211:53 2212:2d 2215:2f 2216:2f 2217:2a 2219:07 221a:56 221e:38 221f:1c 2229:6e 2236:3a 223c:7e 2248:7e 2261:3d 2264:3d 2265:3d 2302:7f 2303:5e 2320:28 2321:29 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2713:56 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 858 (OEM - Multilingual Latin I + Euro) 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01a9:53 01ab:74 01ae:54 01af:55 01b0:75 01b6:5a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:27 02cd:5f 02dc:7e 0300:27 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 0393:47 03a3:53 03a6:46 03a9:4f 03b1:61 03b4:64 03b5:65 03c0:70 03c3:73 03c4:74 03c6:66 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:2e 2030:25 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:39 207f:6e 2080:30 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a7:50 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:54 2124:5a 2126:4f 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2211:53 2212:2d 2215:2f 2216:2f 2217:2a 2219:07 221a:56 221e:38 221f:1c 2229:6e 2236:3a 223c:7e 2248:7e 2261:3d 2264:3d 2265:3d 2302:7f 2303:5e 2320:28 2321:29 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2713:56 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 1252 (ANSI - Latin I) 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0179:5a 017b:5a 017c:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c8:27 02cb:60 02cd:5f 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 0393:47 0398:54 03a3:53 03a6:46 03a9:4f 03b1:61 03b4:64 03b5:65 03c0:70 03c3:73 03c4:74 03c6:66 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2017:3d 2032:27 2035:60 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 207f:6e 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a7:50 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2212:2d 2215:2f 2216:5c 2217:2a 221a:76 221e:38 2223:7c 2229:6e 2236:3a 223c:7e 2261:3d 2264:3d 2265:3d 2303:5e 2320:28 2321:29 2329:3c 232a:3e 2500:2d 250c:2b 2510:2b 2514:2b 2518:2b 251c:2b 252c:2d 2534:2d 253c:2b 2550:2d 2552:2b 2553:2b 2554:2b 2555:2b 2556:2b 2557:2b 2558:2b 2559:2b 255a:2b 255b:2b 255c:2b 255d:2b 2564:2d 2565:2d 2566:2d 2567:2d 2568:2d 2569:2d 256a:2b 256b:2b 256c:2b 2584:5f 2758:7c 3000:20 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 37 (IBM EBCDIC - U.S./Canada) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a2:4a 00a6:6a 00ac:5f 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3f:6d ff40:79 ff5c:4f 20285 (IBM EBCDIC - United Kingdom) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:4a 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a3:5b 00a6:6a 00ac:5f 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:5a ff02:7f ff03:7b ff04:4a ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3f:6d ff40:79 ff5c:4f 28591 (ISO 8859-1 Latin I) 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 20127 (US-ASCII) 00a0:20 00a1:21 00a2:63 00a4:24 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ad:2d 00ae:52 00b2:32 00b3:33 00b7:2e 00b8:2c 00b9:31 00ba:6f 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 20269 (ISO 6937 Non-Spacing Accent) f8f6:7f 20105 (IA5 IRV International Alphabet No.5) 00a0:20 00a1:21 00a2:63 00a4:24 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ad:2d 00ae:52 00b2:32 00b3:33 00b7:2e 00b8:2c 00b9:31 00ba:6f 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 203e:7e 2122:54 2207:7f ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 20106 (IA5 German) 00a0:20 00a1:21 00a2:63 00a4:24 00a5:59 00a7:40 00a9:43 00aa:61 00ab:3c 00ad:2d 00ae:52 00b2:32 00b3:33 00b7:2e 00b8:2c 00b9:31 00ba:6f 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:5b 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:5c 00d8:4f 00d9:55 00da:55 00db:55 00dc:5d 00dd:59 00df:7e 00e0:61 00e1:61 00e2:61 00e3:61 00e4:7b 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:7c 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:7d 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5e:7e 20107 (IA5 Swedish) 00a0:20 00a1:21 00a2:63 00a4:24 00a5:59 00a9:43 00aa:61 00ab:3c 00ad:2d 00ae:52 00b2:32 00b3:33 00b7:2e 00b8:2c 00b9:31 00ba:6f 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:5b 00c5:5d 00c6:41 00c7:43 00c8:45 00c9:40 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:5c 00d8:4f 00d9:55 00da:55 00db:55 00dc:5e 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:7b 00e5:7d 00e6:61 00e7:63 00e8:65 00e9:60 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:7c 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:7e 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c8:27 02cd:5f 02dc:7e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3f:5f ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5e:7e 20108 (IA5 Norwegian) 007c:7e 00a0:20 00a1:21 00a2:63 00a4:24 00a5:59 00a6:7e 00a7:23 00a9:43 00aa:61 00ab:3c 00ad:2d 00ae:52 00b2:32 00b3:33 00b7:2e 00b8:2c 00b9:31 00ba:6f 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:5d 00c6:5b 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:5c 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:7d 00e6:7b 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:7c 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 0300:60 0302:5e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a 865 (OEM - Nordic) 00a2:63 00a5:59 00a7:15 00a8:22 00a9:63 00ad:5f 00ae:72 00af:16 00b3:33 00b4:2f 00b6:14 00b8:2c 00b9:31 00bb:3e 00be:33 00c0:41 00c1:41 00c2:41 00c3:41 00c8:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d7:58 00d9:55 00da:55 00db:55 00dd:59 00de:54 00e3:61 00f0:64 00f5:6f 00fd:79 00fe:74 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02c9:16 02ca:2f 02cb:60 02cd:5f 02dc:7e 0300:60 0301:2f 0302:5e 0303:7e 0304:16 0305:16 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2017:5f 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:07 2030:25 2032:27 2035:27 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:70 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:5f 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 226b:3c 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 3000:20 3007:4f 3008:3c 3009:3e 300b:3e 301a:5b 301b:5d 30fb:07 863 (OEM - Canadian French) 00a1:21 00a5:59 00a9:63 00aa:61 00ad:16 00ae:72 00b9:33 00ba:6f 00c1:41 00c3:41 00c4:41 00c5:41 00c6:41 00cc:49 00cd:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d5:4f 00d6:4f 00d7:58 00d8:4f 00da:55 00dd:59 00de:54 00e1:61 00e3:61 00e4:61 00e5:61 00e6:61 00ec:69 00ed:69 00f0:64 00f1:6e 00f2:6f 00f5:6f 00f6:6f 00f8:6f 00fd:79 00fe:74 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:22 02ba:27 02bc:27 02c4:5e 02c6:5e 02c8:27 02c9:16 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 0304:16 0305:16 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:07 2030:25 2032:27 2035:27 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a7:50 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:70 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212b:41 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:5f 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d 30fb:07 861 (OEM - Icelandic) 00a2:63 00a4:0f 00a5:59 00a7:15 00a8:22 00a9:63 00aa:61 00ad:5f 00ae:72 00af:16 00b3:33 00b4:2f 00b6:14 00b8:2c 00b9:31 00ba:6f 00be:33 00c0:41 00c2:41 00c3:41 00c8:45 00ca:45 00cb:45 00cc:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d4:4f 00d5:4f 00d7:58 00d9:55 00db:55 00e3:61 00ec:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f5:6f 00f9:75 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 0278:66 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02c9:16 02ca:2f 02cb:60 02cd:5f 02dc:7e 0300:60 0301:2f 0302:5e 0303:7e 0304:16 0305:16 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2017:5f 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:07 2030:25 2032:27 2035:27 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:70 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:5f 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d 30fb:07 860 (OEM - Portuguese) 00a4:0f 00a5:59 00a7:15 00a8:22 00a9:63 00ad:5f 00ae:72 00af:16 00b3:33 00b4:2f 00b6:14 00b8:2c 00b9:31 00be:33 00c4:41 00c5:41 00c6:41 00cb:45 00ce:49 00cf:49 00d0:44 00d6:4f 00d7:58 00d8:4f 00db:55 00dd:59 00de:54 00e4:61 00e5:61 00e6:61 00eb:65 00ee:69 00ef:69 00f0:64 00f6:6f 00f8:6f 00fb:75 00fd:79 00fe:74 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:5c 0161:7c 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 0278:66 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02c9:16 02ca:2f 02cb:60 02cd:5f 02dc:7e 0300:60 0301:2f 0302:5e 0303:7e 0304:16 0305:16 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:5f 2011:5f 2013:5f 2014:5f 2017:5f 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:07 2024:07 2026:2e 2030:25 2032:27 2035:60 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:70 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212b:41 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:5f 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d 30fb:07 10079 (MAC - Icelandic) 1047 (IBM EBCDIC - Latin-1/Open System) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:15 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005e:5f 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:25 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a2:4a 00a6:6a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3e:5f ff3f:6d ff40:79 ff5c:4f 1140 (IBM EBCDIC - U.S./Canada (37 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a2:4a 00a6:6a 00ac:5f 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3f:6d ff40:79 ff5c:4f 1141 (IBM EBCDIC - Germany (20273 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005b:63 005e:5f 005f:6d 0060:79 007b:43 007e:59 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a7:7c 00c0:64 00c1:65 00c2:62 00c3:66 00c4:4a 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00dc:5a 00e0:44 00e1:45 00e2:42 00e3:46 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f6:6a 00f8:70 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3b:63 ff3e:5f ff3f:6d ff40:79 ff5b:43 ff5e:59 1142 (IBM EBCDIC - Denmark/Norway (20277 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:4a 0024:67 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005e:5f 005f:6d 0060:79 007d:47 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a6:70 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:5b 00c6:7b 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00d8:7c 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:6a 20ac:5a ff01:4f ff02:7f ff03:4a ff04:67 ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3e:5f ff3f:6d ff40:79 ff5d:47 1143 (IBM EBCDIC - Finland/Sweden (20278 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:63 0024:67 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005c:71 005e:5f 005f:6d 0060:51 007b:43 007d:47 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a7:4a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:7b 00c5:5b 00c7:68 00c8:74 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00d6:7c 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e7:48 00e8:54 00e9:79 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f6:6a 00f8:70 20ac:5a ff01:4f ff02:7f ff03:63 ff04:67 ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3c:71 ff3e:5f ff3f:6d ff40:51 ff5b:43 ff5d:47 1144 (IBM EBCDIC - Italy (20280 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005c:48 005d:51 005e:5f 005f:6d 007b:44 007d:54 007e:58 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a3:7b 00a7:7c 00b0:4a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e9:5a 00ea:52 00eb:53 00ed:55 00ee:56 00ef:57 00f1:49 00f2:6a 00f8:70 00f9:79 ff01:4f ff02:7f ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3c:48 ff3d:51 ff3e:5f ff3f:6d ff5b:44 ff5d:54 ff5e:58 1145 (IBM EBCDIC - Latin America/Spain (20284 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0022:7f 0023:69 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a6:49 00ac:5f 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:7b 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:6a 00f8:70 ff02:7f ff03:69 ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3f:6d ff40:79 ff5c:4f 1146 (IBM EBCDIC - United Kingdom (20285 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:4a 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a3:5b 00a6:6a 00ac:5f 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:5a ff02:7f ff03:7b ff04:4a ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3f:6d ff40:79 ff5c:4f 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:44 005c:48 005e:5f 005f:6d 007b:51 007d:54 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a3:7b 00a7:5a 00b0:4a 00b5:79 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:7c 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 00f9:6a ff01:4f ff02:7f ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:44 ff3c:48 ff3e:5f ff3f:6d ff5b:51 ff5d:54 1148 (IBM EBCDIC - International (500 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005e:5f 005f:6d 0060:79 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a6:6a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3e:5f ff3f:6d ff40:79 1149 (IBM EBCDIC - Icelandic (20871 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005f:6d 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a6:6a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c6:5a 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d0:7c 00d1:69 00d6:5f 00de:4a 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f0:79 00f1:49 00f8:70 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3f:6d 20277 (IBM EBCDIC - Denmark/Norway) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:4a 0024:67 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005e:5f 005f:6d 0060:79 007d:47 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a4:5a 00a6:70 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:5b 00c6:7b 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00d8:7c 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:6a ff01:4f ff02:7f ff03:4a ff04:67 ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3e:5f ff3f:6d ff40:79 ff5d:47 20278 (IBM EBCDIC - Finland/Sweden) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:63 0024:67 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005c:71 005e:5f 005f:6d 0060:51 007b:43 007d:47 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a4:5a 00a7:4a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:7b 00c5:5b 00c7:68 00c8:74 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00d6:7c 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e7:48 00e8:54 00e9:79 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f6:6a 00f8:70 ff01:4f ff02:7f ff03:63 ff04:67 ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3c:71 ff3e:5f ff3f:6d ff40:51 ff5b:43 ff5d:47 20280 (IBM EBCDIC - Italy) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005c:48 005d:51 005e:5f 005f:6d 007b:44 007d:54 007e:58 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a3:7b 00a7:7c 00b0:4a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e9:5a 00ea:52 00eb:53 00ed:55 00ee:56 00ef:57 00f1:49 00f2:6a 00f8:70 00f9:79 ff01:4f ff02:7f ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3c:48 ff3d:51 ff3e:5f ff3f:6d ff5b:44 ff5d:54 ff5e:58 20284 (IBM EBCDIC - Latin America/Spain) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0022:7f 0023:69 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a6:49 00ac:5f 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:7b 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:6a 00f8:70 ff02:7f ff03:69 ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3f:6d ff40:79 ff5c:4f 20297 (IBM EBCDIC - France) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:44 005c:48 005e:5f 005f:6d 007b:51 007d:54 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a3:7b 00a7:5a 00b0:4a 00b5:79 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:7c 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 00f9:6a ff01:4f ff02:7f ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:44 ff3c:48 ff3e:5f ff3f:6d ff5b:51 ff5d:54 20871 (IBM EBCDIC - Icelandic) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005f:6d 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a6:6a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c6:5a 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d0:7c 00d1:69 00d6:5f 00de:4a 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f0:79 00f1:49 00f8:70 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3f:6d 20924 (IBM EBCDIC - Latin-1/Open System (1047 + Euro)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:15 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005e:5f 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:25 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00dd:4a 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 0160:6a ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3e:5f ff3f:6d ff40:79 ff5c:4f 28599 (ISO 8859-9 Latin 5) 00d0:44 00dd:59 00fd:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 28605 (ISO 8859-15 Latin 9) 00a6:7c 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0138:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014a:4e 014b:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:54 0169:74 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0179:5a 017b:5a 017c:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 870 (IBM EBCDIC - Multilingual/ROECE (Latin-2)) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005e:5f 005f:6d 0060:79 007c:6a 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00c1:65 00c2:62 00c4:63 00c7:68 00c9:71 00cb:73 00cd:75 00ce:76 00df:59 00e1:45 00e2:42 00e4:43 00e7:48 00e9:51 00eb:53 00ed:55 00ee:56 0102:66 0103:46 0106:69 0107:49 010c:67 010d:47 0118:72 0119:52 0139:78 013a:58 013d:77 013e:57 0163:44 016e:74 016f:54 02c7:70 02dd:64 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3e:5f ff3f:6d ff40:79 ff5c:6a 10021 (MAC - Thai) 874 (ANSI/OEM - Thai) 00a7:15 00b6:14 203c:13 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 20838 (IBM EBCDIC - Thai) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:49 005d:59 005e:69 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a2:4a 00a6:6a 00ac:5f 0e01:42 0e02:43 0e03:44 0e04:45 0e05:46 0e06:47 0e07:48 0e08:52 0e09:53 0e0a:54 0e0b:55 0e0c:56 0e0d:57 0e0e:58 0e0f:62 0e10:63 0e11:64 0e12:65 0e13:66 0e14:67 0e15:68 0e16:72 0e17:73 0e18:74 0e19:75 0e1a:76 0e1b:77 0e1c:78 0e3f:70 0e4e:71 ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:49 ff3d:59 ff3e:69 ff3f:6d ff40:79 ff5c:4f 10005 (MAC - Hebrew) 1255 (ANSI - Hebrew) 0191:46 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 862 (OEM - Hebrew) 00a4:0f 00a7:15 00a8:22 00a9:63 00ad:2d 00ae:72 00af:5f 00b3:33 00b4:27 00b6:14 00b8:2c 00b9:31 00be:5f 00c0:41 00c1:41 00c2:41 00c3:41 00c8:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d7:78 00d8:4f 00d9:55 00da:55 00db:55 00dd:59 00de:5f 00e3:61 00f0:64 00f5:6f 00f8:6f 00fd:79 00fe:5f 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02ca:27 02cb:60 02cd:5f 02dc:7e 0300:60 0301:27 0302:5e 0303:7e 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2017:5f 2018:60 2019:27 201a:2c 201c:22 201d:22 201e:2c 2020:2b 2022:07 2026:2e 2030:25 2032:27 2035:60 2039:3c 203a:3e 203c:13 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:09 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:54 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2212:2d 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2758:7c 3000:20 3007:09 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 28598 (ISO 8859-8 Hebrew: Visual Ordering) 00a1:21 00aa:61 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 38598 (ISO 8859-8 Hebrew: Logical Ordering) 00a1:21 00aa:61 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 20424 (IBM EBCDIC - Hebrew) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:74 00a2:4a 00a6:6a 00ac:5f 05d0:41 05d1:42 05d2:43 05d3:44 05d4:45 05d5:46 05d6:47 05d7:48 05d8:49 05d9:51 05da:52 05db:53 05dc:54 05dd:55 05de:56 05df:57 05e0:58 05e1:59 05e2:62 05e3:63 05e4:64 05e5:65 05e6:66 05e7:67 05e8:68 05e9:69 05ea:71 2017:78 ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3f:6d ff40:79 ff5c:4f 10006 (MAC - Greek I) 1253 (ANSI - Greek) 00b4:2f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 037e:3b 203c:21 2190:3c 2191:5e 2192:3e 2193:76 2194:2d 221f:4c 2500:2d 250c:2d 2514:4c 2518:2d 251c:2b 2524:2b 252c:54 2534:2b 253c:2b 2550:3d 2554:2d 255a:4c 255d:2d 2566:54 256c:2b 2580:2d 2584:2d 2588:2d 2591:2d 2592:2d 2593:2d 25ac:2d 25b2:5e 25ba:3e 25c4:3c 25cb:30 25d9:30 263a:4f 263b:4f 263c:30 2640:2b 2642:3e 266a:64 266b:64 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 737 (OEM - Greek 437G) 00a7:15 00b6:14 037e:3b 2022:07 203c:13 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 869 (OEM - Modern Greek) 00a4:6f 00a5:59 00ae:52 00b6:14 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 037e:3b 2013:16 2014:16 201c:22 201d:22 201e:22 2020:2b 2021:2b 2022:07 2026:3a 2030:25 2039:3c 203a:3e 203c:13 2122:54 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 20273 (IBM EBCDIC - Germany) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005b:63 005e:5f 005f:6d 0060:79 007b:43 007e:59 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a7:7c 00c0:64 00c1:65 00c2:62 00c3:66 00c4:4a 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00dc:5a 00e0:44 00e1:45 00e2:42 00e3:46 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f6:6a 00f8:70 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3b:63 ff3e:5f ff3f:6d ff40:79 ff5b:43 ff5e:59 28597 (ISO 8859-7 Greek) 00a1:21 00a2:63 00a4:24 00a5:59 00aa:61 00ae:52 00b8:2c 00b9:31 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 20423 (IBM EBCDIC - Greek) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 005b:4a 005d:5a 005e:5f 005f:6d 0060:79 007c:6a 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:74 00a3:7b 00a7:7c 0386:71 0388:72 0389:73 038a:75 038c:76 038e:77 038f:78 0391:41 0392:42 0393:43 0394:44 0395:45 0396:46 0397:47 0398:48 0399:49 039a:51 039b:52 039c:53 039d:54 039e:55 039f:56 03a0:57 03a1:58 03a3:59 03a4:62 03a5:63 03a6:64 03a7:65 03a8:66 03a9:67 ff01:4f ff02:7f ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff3b:4a ff3d:5a ff3e:5f ff3f:6d ff40:79 ff5c:6a 875 (IBM EBCDIC - Modern Greek) 0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005e:5f 005f:6d 0060:79 007c:6a 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:74 00a8:70 0386:71 0388:72 0389:73 038a:75 038c:76 038e:77 038f:78 0391:41 0392:42 0393:43 0394:44 0395:45 0396:46 0397:47 0398:48 0399:49 039a:51 039b:52 039c:53 039d:54 039e:55 039f:56 03a0:57 03a1:58 03a3:59 03a4:62 03a5:63 03a6:64 03a7:65 03a8:66 03a9:67 03aa:68 03ab:69 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3e:5f ff3f:6d ff40:79 ff5c:6a 1258 (ANSI/OEM - Viet Nam) ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 10002 (MAC - Traditional Chinese Big5) 00a1:21 00a6:7c 00aa:61 00ad:2d 00ae:52 00b2:32 00b3:33 00b9:31 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00de:54 00df:73 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f0:65 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00fe:74 00ff:79 950 (ANSI/OEM - Traditional Chinese Big5) 00a1:21 00a6:7c 00a9:63 00aa:61 00ad:2d 00ae:52 00b2:32 00b3:33 00b9:31 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00de:54 00df:73 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f0:65 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00fe:74 00ff:79 20000 (CNS - Taiwan) 20001 (TCA - Taiwan) 20002 (Eten - Taiwan) 20003 (IBM5550 - Taiwan) 20004 (TeleText - Taiwan) 20005 (Wang - Taiwan) 20261 (T.61) f8dd:5c f8de:5e f8df:60 f8e0:7b f8fc:7d f8fd:7e f8fe:7f 50229 (ISO-2022 Traditional Chinese) 65000 (UTF-7) 65001 (UTF-8) snort-2.9.6.0/etc/reference.config0000644000000000000000000000125712260606510013625 00000000000000# $Id$ # The following defines URLs for the references found in the rules # # config reference: system URL config reference: bugtraq http://www.securityfocus.com/bid/ config reference: cve http://cve.mitre.org/cgi-bin/cvename.cgi?name= config reference: arachNIDS http://www.whitehats.com/info/IDS config reference: osvdb http://osvdb.org/show/osvdb/ # Note, this one needs a suffix as well.... lets add that in a bit. config reference: McAfee http://vil.nai.com/vil/content/v_ config reference: nessus http://cgi.nessus.org/plugins/dump.php3?id= config reference: url http:// config reference: msb http://technet.microsoft.com/en-us/security/bulletin/ snort-2.9.6.0/etc/gen-msg.map0000644000000000000000000007467212232305204012542 00000000000000# $Id$ # GENERATORS -> msg map # Format: generatorid || alertid || MSG 1 || 1 || snort general alert 2 || 1 || tag: Tagged Packet 3 || 1 || snort dynamic alert 100 || 1 || spp_portscan: Portscan Detected 100 || 2 || spp_portscan: Portscan Status 100 || 3 || spp_portscan: Portscan Ended 101 || 1 || spp_minfrag: minfrag alert 102 || 1 || http_decode: Unicode Attack 102 || 2 || http_decode: CGI NULL Byte Attack 102 || 3 || http_decode: large method attempted 102 || 4 || http_decode: missing uri 102 || 5 || http_decode: double encoding detected 102 || 6 || http_decode: illegal hex values detected 102 || 7 || http_decode: overlong character detected 103 || 1 || spp_defrag: Fragmentation Overflow Detected 103 || 2 || spp_defrag: Stale Fragments Discarded 104 || 1 || spp_anomsensor: SPADE Anomaly Threshold Exceeded 104 || 2 || spp_anomsensor: SPADE Anomaly Threshold Adjusted 105 || 1 || spp_bo: Back Orifice Traffic Detected 105 || 2 || spp_bo: Back Orifice Client Traffic Detected 105 || 3 || spp_bo: Back Orifice Server Traffic Detected 105 || 4 || spp_bo: Back Orifice Snort Buffer Attack 106 || 1 || spp_rpc_decode: Fragmented RPC Records 106 || 2 || spp_rpc_decode: Multiple Records in one packet 106 || 3 || spp_rpc_decode: Large RPC Record Fragment 106 || 4 || spp_rpc_decode: Incomplete RPC segment 106 || 5 || spp_rpc_decode: Zero-length RPC Fragment 110 || 1 || spp_unidecode: CGI NULL Attack 110 || 2 || spp_unidecode: Directory Traversal 110 || 3 || spp_unidecode: Unknown Mapping 110 || 4 || spp_unidecode: Invalid Mapping 111 || 1 || spp_stream4: Stealth Activity Detected 111 || 2 || spp_stream4: Evasive Reset Packet 111 || 3 || spp_stream4: Retransmission 111 || 4 || spp_stream4: Window Violation 111 || 5 || spp_stream4: Data on SYN Packet 111 || 6 || spp_stream4: Full XMAS Stealth Scan 111 || 7 || spp_stream4: SAPU Stealth Scan 111 || 8 || spp_stream4: FIN Stealth Scan 111 || 9 || spp_stream4: NULL Stealth Scan 111 || 10 || spp_stream4: NMAP XMAS Stealth Scan 111 || 11 || spp_stream4: VECNA Stealth Scan 111 || 12 || spp_stream4: NMAP Fingerprint Stateful Detection 111 || 13 || spp_stream4: SYN FIN Stealth Scan 111 || 14 || spp_stream4: TCP forward overlap detected 111 || 15 || spp_stream4: TTL Evasion attempt 111 || 16 || spp_stream4: Evasive retransmitted data attempt 111 || 17 || spp_stream4: Evasive retransmitted data with the data split attempt 111 || 18 || spp_stream4: Multiple acked 111 || 19 || spp_stream4: Shifting to Emergency Session Mode 111 || 20 || spp_stream4: Shifting to Suspend Mode 111 || 21 || spp_stream4: TCP Timestamp option has value of zero 111 || 22 || spp_stream4: Too many overlapping TCP packets 111 || 23 || spp_stream4: Packet in established TCP stream missing ACK 111 || 24 || spp_stream4: Evasive FIN Packet 111 || 25 || spp_stream4: SYN on established 112 || 1 || spp_arpspoof: Directed ARP Request 112 || 2 || spp_arpspoof: Etherframe ARP Mismatch SRC 112 || 3 || spp_arpspoof: Etherframe ARP Mismatch DST 112 || 4 || spp_arpspoof: ARP Cache Overwrite Attack 113 || 1 || spp_frag2: Oversized Frag 113 || 2 || spp_frag2: Teardrop/Fragmentation Overlap Attack 113 || 3 || spp_frag2: TTL evasion detected 113 || 4 || spp_frag2: overlap detected 113 || 5 || spp_frag2: Duplicate first fragments 113 || 6 || spp_frag2: memcap exceeded 113 || 7 || spp_frag2: Out of order fragments 113 || 8 || spp_frag2: IP Options on Fragmented Packet 113 || 9 || spp_frag2: Shifting to Emegency Session Mode 113 || 10 || spp_frag2: Shifting to Suspend Mode 114 || 1 || spp_fnord: Possible Mutated GENERIC NOP Sled detected 114 || 2 || spp_fnord: Possible Mutated IA32 NOP Sled detected 114 || 3 || spp_fnord: Possible Mutated HPPA NOP Sled detected 114 || 4 || spp_fnord: Possible Mutated SPARC NOP Sled detected 115 || 1 || spp_asn1: Indefinite ASN.1 length encoding 115 || 2 || spp_asn1: Invalid ASN.1 length encoding 115 || 3 || spp_asn1: ASN.1 oversized item, possible overflow 115 || 4 || spp_asn1: ASN.1 spec violation, possible overflow 115 || 5 || spp_asn1: ASN.1 Attack: Datum length > packet length 116 || 1 || snort_decoder: WARNING: Not IPv4 datagram 116 || 2 || snort_decoder: WARNING: hlen < IP_HEADER_LEN 116 || 3 || snort_decoder: WARNING: IP dgm len < IP Hdr len 116 || 4 || snort_decoder: WARNING: Bad IPv4 Options 116 || 5 || snort_decoder: WARNING: Truncated IPv4 Options 116 || 6 || snort_decoder: WARNING: IP dgm len > captured len 116 || 45 || snort_decoder: WARNING: TCP packet len is smaller than 20 bytes 116 || 46 || snort_decoder: WARNING: TCP Data Offset is less than 5 116 || 47 || snort_decoder: WARNING: TCP Data Offset is longer than payload 116 || 54 || snort_decoder: WARNING: Tcp Options found with bad lengths 116 || 55 || snort_decoder: WARNING: Truncated Tcp Options 116 || 56 || snort_decoder: WARNING: T/TCP Detected 116 || 57 || snort_decoder: WARNING: Obsolete TCP options 116 || 58 || snort_decoder: WARNING: Experimental TCP options 116 || 59 || snort_decoder: WARNING: TCP Window Scale Option Scale Invalid (> 14) 116 || 95 || snort_decoder: WARNING: Truncated UDP Header 116 || 96 || snort_decoder: WARNING: Invalid UDP header, length field < 8 116 || 97 || snort_decoder: WARNING: Short UDP packet, length field > payload length 116 || 98 || snort_decoder: WARNING: Long UDP packet, length field < payload length 116 || 105 || snort_decoder: WARNING: ICMP Header Truncated 116 || 106 || snort_decoder: WARNING: ICMP Timestamp Header Truncated 116 || 107 || snort_decoder: WARNING: ICMP Address Header Truncated 116 || 108 || snort_decoder: WARNING: Unknown Datagram decoding problem 116 || 109 || snort_decoder: WARNING: Truncated ARP Packet 116 || 110 || snort_decoder: WARNING: Truncated EAP Header 116 || 111 || snort_decoder: WARNING: EAP Key Truncated 116 || 112 || snort_decoder: WARNING: EAP Header Truncated 116 || 120 || snort_decoder: WARNING: Bad PPPOE frame detected 116 || 130 || snort_decoder: WARNING: Bad VLAN Frame 116 || 131 || snort_decoder: WARNING: Bad LLC header 116 || 132 || snort_decoder: WARNING: Bad Extra LLC Info 116 || 133 || snort_decoder: WARNING: Bad 802.11 LLC header 116 || 134 || snort_decoder: WARNING: Bad 802.11 Extra LLC Info 116 || 140 || snort_decoder: WARNING: Bad Token Ring Header 116 || 141 || snort_decoder: WARNING: Bad Token Ring ETHLLC Header 116 || 142 || snort_decoder: WARNING: Bad Token Ring MRLEN Header 116 || 143 || snort_decoder: WARNING: Bad Token Ring MR Header 116 || 150 || snort_decoder: WARNING: Bad Traffic Loopback IP 116 || 151 || snort_decoder: WARNING: Bad Traffic Same Src/Dst IP 116 || 160 || snort_decoder: WARNING: GRE header length > payload length 116 || 161 || snort_decoder: WARNING: Multiple encapsulations in packet 116 || 162 || snort_decoder: WARNING: Invalid GRE version 116 || 163 || snort_decoder: WARNING: Invalid GRE v.0 header 116 || 164 || snort_decoder: WARNING: Invalid GRE v.1 PPTP header 116 || 165 || snort_decoder: WARNING: GRE Trans header length > payload length 116 || 170 || snort_decoder: WARNING: Bad MPLS Frame 116 || 171 || snort_decoder: WARNING: MPLS Label 0 Appears in Nonbottom Header 116 || 172 || snort_decoder: WARNING: MPLS Label 1 Appears in Bottom Header 116 || 173 || snort_decoder: WARNING: MPLS Label 2 Appears in Nonbottom Header 116 || 174 || snort_decoder: WARNING: Bad use of label 3 116 || 175 || snort_decoder: WARNING: MPLS Label 4, 5,.. or 15 Appears in Header 116 || 176 || snort_decoder: WARNING: Too Many MPLS headers 116 || 250 || snort_decoder: WARNING: ICMP Original IP Header Truncated 116 || 251 || snort_decoder: WARNING: ICMP Original IP Header Not IPv4 116 || 252 || snort_decoder: WARNING: ICMP Original Datagram Length < Original IP Header Length 116 || 253 || snort_decoder: WARNING: ICMP Original IP Payload < 64 bits 116 || 254 || snort_decoder: WARNING: ICMP Original IP Payload > 576 bytes 116 || 255 || snort_decoder: WARNING: ICMP Original IP Fragmented and Offset Not 0 116 || 270 || snort_decoder: WARNING: IPV6 packet exceeded TTL limit 116 || 271 || snort_decoder: WARNING: IPv6 header claims to not be IPv6 116 || 272 || snort_decoder: WARNING: IPV6 truncated extension header 116 || 273 || snort_decoder: WARNING: IPV6 truncated header 116 || 274 || snort_decoder: WARNING: IPV6 dgm len < IPV6 Hdr len 116 || 275 || snort_decoder: WARNING: IPV6 dgm len > captured len 116 || 276 || snort_decoder: WARNING: IPv6 packet with destination address ::0 116 || 277 || snort_decoder: WARNING: IPv6 packet with multicast source address 116 || 278 || snort_decoder: WARNING: IPv6 packet with reserved multicast destination address 116 || 279 || snort_decoder: WARNING: IPv6 header includes an undefined option type 116 || 280 || snort_decoder: WARNING: IPv6 address includes an unassigned multicast scope value 116 || 281 || snort_decoder: WARNING: IPv6 header includes an invalid value for the "next header" field 116 || 282 || snort_decoder: WARNING: IPv6 header includes a routing extension header followed by a hop-by-hop header 116 || 283 || snort_decoder: WARNING: IPv6 header includes two routing extension headers 116 || 285 || snort_decoder: WARNING: ICMPv6 packet of type 2 (message too big) with MTU field < 1280 116 || 286 || snort_decoder: WARNING: ICMPv6 packet of type 1 (destination unreachable) with non-RFC 2463 code 116 || 287 || snort_decoder: WARNING: ICMPv6 router solicitation packet with a code not equal to 0 116 || 288 || snort_decoder: WARNING: ICMPv6 router advertisement packet with a code not equal to 0 116 || 289 || snort_decoder: WARNING: ICMPv6 router solicitation packet with the reserved field not equal to 0 116 || 290 || snort_decoder: WARNING: ICMPv6 router advertisement packet with the reachable time field set > 1 hour 116 || 291 || snort_decoder: WARNING: IPV6 tunneled over IPv4, IPv6 header truncated, possible Linux Kernel attack 116 || 292 || snort_decoder: WARNING: IPv6 header has destination options followed by a routing header 116 || 293 || snort_decoder: WARNING: Two or more IP (v4 and/or v6) encapsulation layers present 116 || 294 || snort_decoder: WARNING: truncated Encapsulated Security Payload (ESP) header 116 || 295 || snort_decoder: WARNING: IPv6 header includes an option which is too big for the containing header. 116 || 296 || snort_decoder: WARNING: IPv6 packet includes out-of-order extension headers 116 || 297 || snort_decoder: WARNING: Two or more GTP encapsulation layers are present 116 || 298 || snort_decoder: WARNING: GTP header length is invalid 116 || 400 || snort_decoder: WARNING: XMAS Attack Detected 116 || 401 || snort_decoder: WARNING: Nmap XMAS Attack Detected 116 || 402 || snort_decoder: WARNING: DOS NAPTHA Vulnerability Detected 116 || 403 || snort_decoder: WARNING: Bad Traffic SYN to multicast address 116 || 404 || snort_decoder: WARNING: IPV4 packet with zero TTL 116 || 405 || snort_decoder: WARNING: IPV4 packet with bad frag bits (Both MF and DF set) 116 || 406 || snort_decoder: WARNING: Invalid IPv6 UDP packet, checksum zero 116 || 407 || snort_decoder: WARNING: IPV4 packet frag offset + length exceed maximum 116 || 408 || snort_decoder: WARNING: IPV4 packet from 'current net' source address 116 || 409 || snort_decoder: WARNING: IPV4 packet to 'current net' dest address 116 || 410 || snort_decoder: WARNING: IPV4 packet from multicast source address 116 || 411 || snort_decoder: WARNING: IPV4 packet from reserved source address 116 || 412 || snort_decoder: WARNING: IPV4 packet to reserved dest address 116 || 413 || snort_decoder: WARNING: IPV4 packet from broadcast source address 116 || 414 || snort_decoder: WARNING: IPV4 packet to broadcast dest address 116 || 415 || snort_decoder: WARNING: ICMP4 packet to multicast dest address 116 || 416 || snort_decoder: WARNING: ICMP4 packet to broadcast dest address 116 || 417 || snort_decoder: WARNING: ICMP4 source quence 116 || 418 || snort_decoder: WARNING: ICMP4 type other 116 || 419 || snort_decoder: WARNING: TCP urgent pointer exceeds payload length or no payload 116 || 420 || snort_decoder: WARNING: TCP SYN with FIN 116 || 421 || snort_decoder: WARNING: TCP SYN with RST 116 || 422 || snort_decoder: WARNING: TCP PDU missing ack for established session 116 || 423 || snort_decoder: WARNING: TCP has no SYN, ACK, or RST 116 || 424 || snort_decoder: WARNING: truncated eth header 116 || 425 || snort_decoder: WARNING: truncated IP4 header 116 || 426 || snort_decoder: WARNING: truncated ICMP4 header 116 || 427 || snort_decoder: WARNING: truncated ICMP6 header 116 || 428 || snort_decoder: WARNING: IPV4 packet below TTL limit 116 || 429 || snort_decoder: WARNING: IPV6 packet has zero hop limit 116 || 430 || snort_decoder: WARNING: IPV4 packet both DF and offset set 116 || 431 || snort_decoder: WARNING: ICMP6 type not decoded 116 || 432 || snort_decoder: WARNING: ICMP6 packet to multicast address 116 || 433 || snort_decoder: WARNING: DDOS shaft synflood 116 || 434 || snort_decoder: WARNING: ICMP PING NMAP 116 || 435 || snort_decoder: WARNING: ICMP icmpenum v1.1.1 116 || 436 || snort_decoder: WARNING: ICMP redirect host 116 || 437 || snort_decoder: WARNING: ICMP redirect net 116 || 438 || snort_decoder: WARNING: ICMP traceroute ipopts 116 || 439 || snort_decoder: WARNING: ICMP Source Quench 116 || 440 || snort_decoder: WARNING: Broadscan Smurf Scanner 116 || 441 || snort_decoder: WARNING: ICMP Destination Unreachable Communication Administratively Prohibited 116 || 442 || snort_decoder: WARNING: ICMP Destination Unreachable Communication with Destination Host is Administratively Prohibited 116 || 443 || snort_decoder: WARNING: ICMP Destination Unreachable Communication with Destination Network is Administratively Prohibited 116 || 444 || snort_decoder: WARNING: MISC IP option set 116 || 445 || snort_decoder: WARNING: MISC Large UDP Packet 116 || 446 || snort_decoder: WARNING: BAD-TRAFFIC TCP port 0 traffic 116 || 447 || snort_decoder: WARNING: BAD-TRAFFIC UDP port 0 traffic 116 || 448 || snort_decoder: WARNING: BAD-TRAFFIC IP reserved bit set 116 || 449 || snort_decoder: WARNING: BAD-TRAFFIC Unassigned/Reserved IP protocol 116 || 450 || snort_decoder: WARNING: BAD-TRAFFIC Bad IP protocol 116 || 451 || snort_decoder: WARNING: ICMP PATH MTU denial of service attempt 116 || 452 || snort_decoder: WARNING: BAD-TRAFFIC linux ICMP header dos attempt 116 || 453 || snort_decoder: WARNING: IPV6 ISATAP spoof 116 || 454 || snort_decoder: WARNING: PGM NAK overflow 116 || 455 || snort_decoder: WARNING: IGMP options dos 116 || 456 || snort_decoder: WARNING: too many IPV6 extension headers 116 || 457 || snort_decoder: WARNING: ICMPv6 packet of type 1 (destination unreachable) with non-RFC 4443 code 116 || 458 || snort_decoder: WARNING: bogus fragmentation packet. Possible BSD attack 116 || 459 || snort_decoder: WARNING: zero length fragment 116 || 460 || snort_decoder: WARNING: ICMPv6 node info query/response packet with a code greater than 2 116 || 461 || snort_decoder: WARNING: Deprecated IPv6 Type 0 Routing Header 116 || 462 || snort_decoder: WARNING: ERSpan Header version mismatch 116 || 463 || snort_decoder: WARNING: captured < ERSpan Type2 Header Length 116 || 464 || snort_decoder: WARNING: captured < ERSpan Type3 Header Length 117 || 1 || spp_portscan2: Portscan detected 118 || 1 || spp_conversation: Bad IP protocol 119 || 1 || http_inspect: ASCII ENCODING 119 || 2 || http_inspect: DOUBLE DECODING ATTACK 119 || 3 || http_inspect: U ENCODING 119 || 4 || http_inspect: BARE BYTE UNICODE ENCODING 119 || 5 || http_inspect: BASE36 ENCODING 119 || 6 || http_inspect: UTF-8 ENCODING 119 || 7 || http_inspect: IIS UNICODE CODEPOINT ENCODING 119 || 8 || http_inspect: MULTI_SLASH ENCODING 119 || 9 || http_inspect: IIS BACKSLASH EVASION 119 || 10 || http_inspect: SELF DIRECTORY TRAVERSAL 119 || 11 || http_inspect: DIRECTORY TRAVERSAL 119 || 12 || http_inspect: APACHE WHITESPACE (TAB) 119 || 13 || http_inspect: NON-RFC HTTP DELIMITER 119 || 14 || http_inspect: NON-RFC DEFINED CHAR 119 || 15 || http_inspect: OVERSIZE REQUEST-URI DIRECTORY 119 || 16 || http_inspect: OVERSIZE CHUNK ENCODING 119 || 17 || http_inspect: UNAUTHORIZED PROXY USE DETECTED 119 || 18 || http_inspect: WEBROOT DIRECTORY TRAVERSAL 119 || 19 || http_inspect: LONG HEADER 119 || 20 || http_inspect: MAX HEADERS 119 || 21 || http_inspect: MULTIPLE CONTENT LENGTH HEADER FIELDS 119 || 22 || http_inspect: CHUNK SIZE MISMATCH DETECTED 119 || 23 || http_inspect: INVALID IP IN TRUE-CLIENT-IP/XFF HEADER 119 || 24 || http_inspect: MULTIPLE HOST HEADERS DETECTED 119 || 25 || http_inspect: HOSTNAME EXCEEDS 255 CHARACTERS 119 || 26 || http_inspect: HEADER PARSING SPACE SATURATION 119 || 27 || http_inspect: CHUNKED ENCODING - EXCESSIVE CONSECUTIVE SMALL CHUNKS 119 || 28 || http_inspect: POST W/O CONTENT-LENGTH OR CHUNKS 119 || 29 || http_inspect: MULTIPLE TRUE IPS IN A SESSION 119 || 30 || http_inspect: BOTH TRUE_CLIENT_IP AND XFF HDRS PRESENT 119 || 31 || http_inspect: UNKNOWN METHOD 119 || 32 || http_inspect: SIMPLE REQUEST 119 || 33 || http_inspect: UNESCAPED SPACE IN HTTP URI 119 || 34 || http_inspect: TOO MANY PIPELINED REQUESTS 120 || 1 || http_inspect: ANOMALOUS HTTP SERVER ON UNDEFINED HTTP PORT 120 || 2 || http_inspect: INVALID STATUS CODE IN HTTP RESPONSE 120 || 3 || http_inspect: NO CONTENT-LENGTH OR TRANSFER-ENCODING IN HTTP RESPONSE 120 || 4 || http_inspect: HTTP RESPONSE HAS UTF CHARSET WHICH FAILED TO NORMALIZE 120 || 5 || http_inspect: HTTP RESPONSE HAS UTF-7 CHARSET 120 || 6 || http_inspect: HTTP RESPONSE GZIP DECOMPRESSION FAILED 120 || 7 || http_inspect: CHUNKED ENCODING - EXCESSIVE CONSECUTIVE SMALL CHUNKS 120 || 8 || http_inspect: MESSAGE WITH INVALID CONTENT-LENGTH OR CHUNK SIZE 120 || 9 || http_inspect: JAVASCRIPT OBFUSCATION LEVELS EXCEEDS 1 120 || 10 || http_inspect: JAVASCRIPT WHITESPACES EXCEEDS MAX ALLOWED 120 || 11 || http_inspect: MULTIPLE ENCODINGS WITHIN JAVASCRIPT OBFUSCATED DATA 121 || 1 || flow-portscan: Fixed Scale Scanner Limit Exceeded 121 || 2 || flow-portscan: Sliding Scale Scanner Limit Exceeded 121 || 3 || flow-portscan: Fixed Scale Talker Limit Exceeded 121 || 4 || flow-portscan: Sliding Scale Talker Limit Exceeded 122 || 1 || portscan: TCP Portscan 122 || 2 || portscan: TCP Decoy Portscan 122 || 3 || portscan: TCP Portsweep 122 || 4 || portscan: TCP Distributed Portscan 122 || 5 || portscan: TCP Filtered Portscan 122 || 6 || portscan: TCP Filtered Decoy Portscan 122 || 7 || portscan: TCP Filtered Portsweep 122 || 8 || portscan: TCP Filtered Distributed Portscan 122 || 9 || portscan: IP Protocol Scan 122 || 10 || portscan: IP Decoy Protocol Scan 122 || 11 || portscan: IP Protocol Sweep 122 || 12 || portscan: IP Distributed Protocol Scan 122 || 13 || portscan: IP Filtered Protocol Scan 122 || 14 || portscan: IP Filtered Decoy Protocol Scan 122 || 15 || portscan: IP Filtered Protocol Sweep 122 || 16 || portscan: IP Filtered Distributed Protocol Scan 122 || 17 || portscan: UDP Portscan 122 || 18 || portscan: UDP Decoy Portscan 122 || 19 || portscan: UDP Portsweep 122 || 20 || portscan: UDP Distributed Portscan 122 || 21 || portscan: UDP Filtered Portscan 122 || 22 || portscan: UDP Filtered Decoy Portscan 122 || 23 || portscan: UDP Filtered Portsweep 122 || 24 || portscan: UDP Filtered Distributed Portscan 122 || 25 || portscan: ICMP Sweep 122 || 26 || portscan: ICMP Filtered Sweep 122 || 27 || portscan: Open Port 123 || 1 || frag3: IP Options on fragmented packet 123 || 2 || frag3: Teardrop attack 123 || 3 || frag3: Short fragment, possible DoS attempt 123 || 4 || frag3: Fragment packet ends after defragmented packet 123 || 5 || frag3: Zero-byte fragment 123 || 6 || frag3: Bad fragment size, packet size is negative 123 || 7 || frag3: Bad fragment size, packet size is greater than 65536 123 || 8 || frag3: Fragmentation overlap 123 || 9 || frag3: IPv6 BSD mbufs remote kernel buffer overflow 123 || 10 || frag3: Bogus fragmentation packet. Possible BSD attack 123 || 11 || frag3: TTL value less than configured minimum, not using for reassembly 123 || 12 || frag3: Number of overlapping fragments exceed configured limit 123 || 13 || frag3: Fragments smaller than configured min_fragment_length 124 || 1 || smtp: Attempted command buffer overflow 124 || 2 || smtp: Attempted data header buffer overflow 124 || 3 || smtp: Attempted response buffer overflow 124 || 4 || smtp: Attempted specific command buffer overflow 124 || 5 || smtp: Unknown command 124 || 6 || smtp: Illegal command 124 || 7 || smtp: Attempted header name buffer overflow 124 || 8 || smtp: Attempted X-Link2State command buffer overflow 124 || 9 || smtp: No memory available for decoding. Max Mime Mem exceeded. 124 || 10 || smtp: Base64 Decoding failed 124 || 11 || smtp: Quoted-Printable Decoding failed 124 || 12 || smtp: Non-Encoded MIME attachment Extraction failed 124 || 13 || smtp: Unix-to-Unix Decoding failed 124 || 14 || smtp: Cyrus SASL authentication attack 125 || 1 || ftp_pp: Telnet command on FTP command channel 125 || 2 || ftp_pp: Invalid FTP command 125 || 3 || ftp_pp: FTP parameter length overflow 125 || 4 || ftp_pp: FTP malformed parameter 125 || 5 || ftp_pp: Possible string format attempt in FTP command/parameter 125 || 6 || ftp_pp: FTP response length overflow 125 || 7 || ftp_pp: FTP command channel encrypted 125 || 8 || ftp_pp: FTP bounce attack 125 || 9 || ftp_pp: Evasive Telnet command on FTP command channel 126 || 1 || telnet_pp: Telnet consecutive AYT overflow 126 || 2 || telnet_pp: Telnet data encrypted 126 || 3 || telnet_pp: Subnegotiation Begin without matching Subnegotiation End 128 || 1 || ssh: Gobbles exploit 128 || 2 || ssh: SSH1 CRC32 exploit 128 || 3 || ssh: Server version string overflow 128 || 4 || ssh: Protocol mismatch 128 || 5 || ssh: Bad message direction 128 || 6 || ssh: Payload size incorrect for the given payload 128 || 7 || ssh: Failed to detect SSH version string 129 || 1 || stream5: SYN on established session 129 || 2 || stream5: Data on SYN packet 129 || 3 || stream5: Data sent on stream not accepting data 129 || 4 || stream5: TCP Timestamp is outside of PAWS window 129 || 5 || stream5: Bad segment, overlap adjusted size less than/equal 0 129 || 6 || stream5: Window size (after scaling) larger than policy allows 129 || 7 || stream5: Limit on number of overlapping TCP packets reached 129 || 8 || stream5: Data sent on stream after TCP Reset 129 || 9 || stream5: TCP Client possibly hijacked, different Ethernet Address 129 || 10 || stream5: TCP Server possibly hijacked, different Ethernet Address 129 || 11 || stream5: TCP Data with no TCP Flags set 129 || 12 || stream5: TCP Small Segment Threshold Exceeded 129 || 13 || stream5: TCP 4-way handshake detected 129 || 14 || stream5: TCP Timestamp is missing 129 || 15 || stream5: Reset outside window 129 || 16 || stream5: FIN number is greater than prior FIN 129 || 17 || stream5: ACK number is greater than prior FIN 129 || 18 || stream5: Data sent on stream after TCP Reset received 129 || 19 || stream5: TCP window closed before receiving data 129 || 20 || stream5: TCP session without 3-way handshake 130 || 1 || dcerpc: Maximum memory usage reached 131 || 1 || dns: Obsolete DNS RData Type 131 || 2 || dns: Experimental DNS RData Type 131 || 3 || dns: Client RData TXT Overflow 133 || 1 || dcerpc2: Memory cap exceeded 133 || 2 || dcerpc2: SMB - Bad NetBIOS Session Service session type 133 || 3 || dcerpc2: SMB - Bad SMB message type 133 || 4 || dcerpc2: SMB - Bad SMB Id (not "\xffSMB" for SMB1 or not "\xfeSMB" for SMB2) 133 || 5 || dcerpc2: SMB - Bad word count or structure size for command 133 || 6 || dcerpc2: SMB - Bad byte count for command 133 || 7 || dcerpc2: SMB - Bad format type for command 133 || 8 || dcerpc2: SMB - Bad AndX or data offset in command 133 || 9 || dcerpc2: SMB - Zero total data count in command 133 || 10 || dcerpc2: SMB - NetBIOS data length less than SMB header length 133 || 11 || dcerpc2: SMB - Remaining NetBIOS data length less than command length 133 || 12 || dcerpc2: SMB - Remaining NetBIOS data length less than command byte count 133 || 13 || dcerpc2: SMB - Remaining NetBIOS data length less than command data size 133 || 14 || dcerpc2: SMB - Remaining total data count less than this command data size 133 || 15 || dcerpc2: SMB - Total data sent greater than command total data expected 133 || 16 || dcerpc2: SMB - Byte count less than command data size 133 || 17 || dcerpc2: SMB - Invalid command data size for byte count 133 || 18 || dcerpc2: SMB - Excessive Tree Connect requests with pending Tree Connect responses 133 || 19 || dcerpc2: SMB - Excessive Read requests with pending Read responses 133 || 20 || dcerpc2: SMB - Excessive command chaining 133 || 21 || dcerpc2: SMB - Multiple chained login requests 133 || 22 || dcerpc2: SMB - Multiple chained tree connect requests 133 || 23 || dcerpc2: SMB - Chained/Compounded login followed by logoff 133 || 24 || dcerpc2: SMB - Chained/Compounded tree connect followed by tree disconnect 133 || 25 || dcerpc2: SMB - Chained/Compounded open pipe followed by close pipe 133 || 26 || dcerpc2: SMB - Invalid share access 133 || 27 || dcerpc2: Connection-oriented DCE/RPC - Invalid major version 133 || 28 || dcerpc2: Connection-oriented DCE/RPC - Invalid minor version 133 || 29 || dcerpc2: Connection-oriented DCE/RPC - Invalid pdu type 133 || 30 || dcerpc2: Connection-oriented DCE/RPC - Fragment length less than header size 133 || 31 || dcerpc2: Connection-oriented DCE/RPC - Remaining fragment length less than size needed 133 || 32 || dcerpc2: Connection-oriented DCE/RPC - No context items specified 133 || 33 || dcerpc2: Connection-oriented DCE/RPC - No transfer syntaxes specified 133 || 34 || dcerpc2: Connection-oriented DCE/RPC - Fragment length on non-last fragment less than maximum negotiated fragment transmit size for client 133 || 35 || dcerpc2: Connection-oriented DCE/RPC - Fragment length greater than maximum negotiated fragment transmit size 133 || 36 || dcerpc2: Connection-oriented DCE/RPC - Alter Context byte order different from Bind 133 || 37 || dcerpc2: Connection-oriented DCE/RPC - Call id of non first/last fragment different from call id established for fragmented request 133 || 38 || dcerpc2: Connection-oriented DCE/RPC - Opnum of non first/last fragment different from opnum established for fragmented request 133 || 39 || dcerpc2: Connection-oriented DCE/RPC - Context id of non first/last fragment different from context id established for fragmented request 133 || 40 || dcerpc2: Connectionless DCE/RPC - Invalid major version 133 || 41 || dcerpc2: Connectionless DCE/RPC - Invalid pdu type 133 || 42 || dcerpc2: Connectionless DCE/RPC - Data length less than header size 133 || 43 || dcerpc2: Connectionless DCE/RPC - Bad sequence number #133 || 44 || dcerpc2: SMB - Invalid SMB version 1 seen #133 || 45 || dcerpc2: SMB - Invalid SMB version 2 seen #133 || 46 || dcerpc2: SMB - Invalid user, tree connect, file binding #133 || 47 || dcerpc2: SMB - Excessive command compounding 133 || 48 || dcerpc2: SMB - Zero data count 133 || 49 || dcerpc2: SMB - Data count mismatch 133 || 50 || dcerpc2: SMB - Maximum number of outstanding requests exceeded 133 || 51 || dcerpc2: SMB - Outstanding requests with the same MID 133 || 52 || dcerpc2: SMB - Deprecated dialect negotiated 133 || 53 || dcerpc2: SMB - Deprecated command used 133 || 54 || dcerpc2: SMB - Unusual command used 133 || 55 || dcerpc2: SMB - Invalid setup count 133 || 56 || dcerpc2: SMB - Client attempted multiple dialect negotiations on session 133 || 57 || dcerpc2: SMB - Client attempted to create or set a file's attributes to readonly/hidden/system 134 || 1 || ppm: rule tree disabled 134 || 2 || ppm: rule tree enabled 134 || 3 || ppm: packet aborted 135 || 1 || internal: syn received 135 || 2 || internal: session established 135 || 3 || internal: session cleared 136 || 1 || reputation: Packet is blacklisted 136 || 2 || reputation: Packet is whitelisted 137 || 1 || ssp_ssl: Invalid Client HELLO after Server HELLO Detected 137 || 2 || ssp_ssl: Invalid Server HELLO without Client HELLO Detected 138 || 2 || sensitive_data: sensitive data - Credit card numbers 138 || 3 || sensitive_data: sensitive data - U.S. social security numbers with dashes 138 || 4 || sensitive_data: sensitive data - U.S. social security numbers without dashes 138 || 5 || sensitive_data: sensitive data - eMail addresses 138 || 6 || sensitive_data: sensitive data - U.S. phone numbers 139 || 1 || sensitive_data: sensitive data global threshold exceeded 140 || 1 || sip: Maximum sessions reached 140 || 2 || sip: Empty request URI 140 || 3 || sip: URI is too long 140 || 4 || sip: Empty call-Id 140 || 5 || sip: Call-Id is too long 140 || 6 || sip: CSeq number is too large or negative 140 || 7 || sip: Request name in CSeq is too long 140 || 8 || sip: Empty From header 140 || 9 || sip: From header is too long 140 || 10 || sip: Empty To header 140 || 11 || sip: To header is too long 140 || 12 || sip: Empty Via header 140 || 13 || sip: Via header is too long 140 || 14 || sip: Empty Contact 140 || 15 || sip: Contact is too long 140 || 16 || sip: Content length is too large or negative 140 || 17 || sip: Multiple SIP messages in a packet 140 || 18 || sip: Content length mismatch 140 || 19 || sip: Request name is invalid 140 || 20 || sip: Invite replay attack 140 || 21 || sip: Illegal session information modification 140 || 22 || sip: Response status code is not a 3 digit number 140 || 23 || sip: Empty Content type 140 || 24 || sip: SIP version other than 2.0, 1.0, and 1.1 are invalid 140 || 25 || sip: Mismatch in Method of request and the CSEQ header 140 || 26 || sip: The method is unknown 140 || 27 || sip: Maximum dialogs in a session reached 141 || 1 || imap: Unknown IMAP4 command 141 || 2 || imap: Unknown IMAP4 response 141 || 3 || imap: No memory available for decoding. Memcap exceeded. 141 || 4 || imap: Base64 Decoding failed 141 || 5 || imap: Quoted-Printable Decoding failed 141 || 6 || imap: Non-Encoded MIME attachment Extraction failed 141 || 7 || imap: Unix-to-Unix Decoding failed 142 || 1 || pop: Unknown POP3 command 142 || 2 || pop: Unknown POP3 response 142 || 3 || pop: No memory available for decoding. Memcap exceeded. 142 || 4 || pop: Base64 Decoding failed 142 || 5 || pop: Quoted-Printable Decoding failed 142 || 6 || pop: Non-Encoded MIME attachment Extraction failed 142 || 7 || pop: Unix-to-Unix Decoding failed 143 || 1 || gtp: Message length is invalid 143 || 2 || gtp: Information element length is invalid 143 || 3 || gtp: Information elements are out of order 144 || 1 || modbus: Length in Modbus MBAP header does not match the length needed for the given Modbus function. 144 || 2 || modbus: Modbus protocol ID is non-zero. 144 || 3 || modbus: Reserved Modbus function code in use. 145 || 1 || dnp3: DNP3 Link-Layer Frame contains bad CRC. 145 || 2 || dnp3: DNP3 Link-Layer Frame was dropped. 145 || 3 || dnp3: DNP3 Transport-Layer Segment was dropped during reassembly. 145 || 4 || dnp3: DNP3 Reassembly Buffer was cleared without reassembling a complete message. 145 || 5 || dnp3: DNP3 Link-Layer Frame uses a reserved address. 145 || 6 || dnp3: DNP3 Application-Layer Fragment uses a reserved function code. snort-2.9.6.0/etc/classification.config0000644000000000000000000000732112260606507014666 00000000000000# $Id$ # The following includes information for prioritizing rules # # Each classification includes a shortname, a description, and a default # priority for that classification. # # This allows alerts to be classified and prioritized. You can specify # what priority each classification has. Any rule can override the default # priority for that rule. # # Here are a few example rules: # # alert TCP any any -> any 80 (msg: "EXPLOIT ntpdx overflow"; # dsize: > 128; classtype:attempted-admin; priority:10; # # alert TCP any any -> any 25 (msg:"SMTP expn root"; flags:A+; \ # content:"expn root"; nocase; classtype:attempted-recon;) # # The first rule will set its type to "attempted-admin" and override # the default priority for that type to 10. # # The second rule set its type to "attempted-recon" and set its # priority to the default for that type. # # # config classification:shortname,short description,priority # config classification: not-suspicious,Not Suspicious Traffic,3 config classification: unknown,Unknown Traffic,3 config classification: bad-unknown,Potentially Bad Traffic, 2 config classification: attempted-recon,Attempted Information Leak,2 config classification: successful-recon-limited,Information Leak,2 config classification: successful-recon-largescale,Large Scale Information Leak,2 config classification: attempted-dos,Attempted Denial of Service,2 config classification: successful-dos,Denial of Service,2 config classification: attempted-user,Attempted User Privilege Gain,1 config classification: unsuccessful-user,Unsuccessful User Privilege Gain,1 config classification: successful-user,Successful User Privilege Gain,1 config classification: attempted-admin,Attempted Administrator Privilege Gain,1 config classification: successful-admin,Successful Administrator Privilege Gain,1 # NEW CLASSIFICATIONS config classification: rpc-portmap-decode,Decode of an RPC Query,2 config classification: shellcode-detect,Executable Code was Detected,1 config classification: string-detect,A Suspicious String was Detected,3 config classification: suspicious-filename-detect,A Suspicious Filename was Detected,2 config classification: suspicious-login,An Attempted Login Using a Suspicious Username was Detected,2 config classification: system-call-detect,A System Call was Detected,2 config classification: tcp-connection,A TCP Connection was Detected,4 config classification: trojan-activity,A Network Trojan was Detected, 1 config classification: unusual-client-port-connection,A Client was Using an Unusual Port,2 config classification: network-scan,Detection of a Network Scan,3 config classification: denial-of-service,Detection of a Denial of Service Attack,2 config classification: non-standard-protocol,Detection of a Non-Standard Protocol or Event,2 config classification: protocol-command-decode,Generic Protocol Command Decode,3 config classification: web-application-activity,Access to a Potentially Vulnerable Web Application,2 config classification: web-application-attack,Web Application Attack,1 config classification: misc-activity,Misc activity,3 config classification: misc-attack,Misc Attack,2 config classification: icmp-event,Generic ICMP event,3 config classification: inappropriate-content,Inappropriate Content was Detected,1 config classification: policy-violation,Potential Corporate Privacy Violation,1 config classification: default-login-attempt,Attempt to Login By a Default Username and Password,2 config classification: sdf,Sensitive Data was Transmitted Across the Network,2 config classification: file-format,Known malicious file or file based exploit,1 config classification: malware-cnc,Known malware command and control traffic,1 config classification: client-side-exploit,Known client side exploit attempt,1 snort-2.9.6.0/etc/Makefile.am0000644000000000000000000000027612260355636012546 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies EXTRA_DIST = snort.conf classification.config gen-msg.map \ reference.config unicode.map threshold.conf attribute_table.dtd file_magic.conf snort-2.9.6.0/etc/Makefile.in0000644000000000000000000003010012260606517012541 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = etc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies EXTRA_DIST = snort.conf classification.config gen-msg.map \ reference.config unicode.map threshold.conf attribute_table.dtd file_magic.conf all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign etc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign etc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/doc/0000755000000000000000000000000012260606571010554 500000000000000snort-2.9.6.0/doc/snort_manual.tex0000644000000000000000000240214312260606571013726 00000000000000% $Id$ % % BUILDING HTML VERSION: % latex2html -info 0 -local_icons -show_section_numbers -link +2 -split +2 -noaddress snort_manual.tex % % BUILDING PDF VERSION: % pdflatex snort_manual.tex \documentclass[english]{report} %\usepackage[T1]{fontenc} \usepackage[latin1]{inputenc} \usepackage{geometry} \usepackage{longtable} \geometry{verbose,letterpaper,tmargin=1in,bmargin=.5in,lmargin=1in,rmargin=1in} \usepackage{url} %\IfFileExists{url.sty}{\usepackage{url}} % {\newcommand{\url}{\texttt}} \usepackage{html} % \makeatletter \newcounter{slistnum} \newcounter{subslistnum} \newcounter{subsublistnum} \newenvironment{slist} { \begin{list}{ {\bf \arabic{slistnum}.} }{\usecounter{slistnum} } } { \end{list} } \newenvironment{subslist} { \begin{list} { {\bf \arabic{slistnum}-\Alph{subslistnum}. } } {\usecounter{subslistnum} } } { \end{list} } \newenvironment{subsubslist} { \begin{list}{ {\bf \arabic{slistnum}-\arabic{subslistnum}-\arabic{subsublistnum}. } }{ \usecounter{subsubslistnum} } }{ \end{list} } %\begin{latexonly} \newsavebox{\savepar} \newenvironment{note}{ \samepage \vspace{10pt}{\textsf{ {\hspace{7pt}\Huge{$\triangle$\hspace{-12.5pt}{\Large{$^!$}}}}\hspace{5pt} {\Large{NOTE}} } } \begin{center} \par\vspace{-17pt} \begin{lrbox}{\savepar} \begin{minipage}[r]{6in} } { \end{minipage} \end{lrbox} \fbox{ \usebox{ \savepar } } \par\vskip10pt \end{center} } %\end{latexonly} \begin{htmlonly} \newenvironment{note}{ \begin{rawhtml}

Note:   \end{rawhtml} }{ \begin{rawhtml}

\end{rawhtml} } \end{htmlonly} \usepackage{babel} % \makeatother \addtolength{\parindent}{-5mm} \addtolength{\parskip}{2mm} %\renewcommand\floatpagefraction{.9} %\renewcommand\topfraction{.9} %\renewcommand\bottomfraction{.9} %\renewcommand\textfraction{.1} %\setcounter{totalnumber}{50} %\setcounter{topnumber}{50} %\setcounter{bottomnumber}{50} \begin{document} \title{SNORT\textsuperscript{\textregistered} Users Manual\\2.9.6} \author{The Snort Project} \maketitle \newpage Copyright \copyright 1998-2003 Martin Roesch Copyright \copyright 2001-2003 Chris Green Copyright \copyright 2003-2013 Sourcefire, Inc. Copyright \copyright 2014 Cisco and/or its affiliates. All rights reserved. \tableofcontents{} \chapter{Snort Overview} This manual is based on \emph{Writing Snort Rules} by Martin Roesch and further work from Chris Green $<$cmg@snort.org$>$. It was then maintained by Brian Caswell $<$bmc@snort.org$>$ and now is maintained by the Snort Team. If you have a better way to say something or find that something in the documentation is outdated, drop us a line and we will update it. If you would like to submit patches for this document, you can find the latest version of the documentation in \LaTeX\ format in the most recent source tarball under \verb!/doc/snort_manual.tex!. Small documentation updates are the easiest way to help out the Snort Project. \section{Getting Started} Snort really isn't very hard to use, but there are a lot of command line options to play with, and it's not always obvious which ones go together well. This file aims to make using Snort easier for new users. Before we proceed, there are a few basic concepts you should understand about Snort. Snort can be configured to run in three modes: \begin{itemize} \item {\em Sniffer mode,} which simply reads the packets off of the network and displays them for you in a continuous stream on the console (screen). \item {\em Packet Logger mode,} which logs the packets to disk. \item {\em Network Intrusion Detection System (NIDS) mode,} which performs detection and analysis on network traffic. This is the most complex and configurable mode. \end{itemize} \section{Sniffer Mode} First, let's start with the basics. If you just want to print out the TCP/IP packet headers to the screen (i.e. sniffer mode), try this: \begin{verbatim} ./snort -v \end{verbatim} This command will run Snort and just show the IP and TCP/UDP/ICMP headers, nothing else. If you want to see the application data in transit, try the following: \begin{verbatim} ./snort -vd \end{verbatim} This instructs Snort to display the packet data as well as the headers. If you want an even more descriptive display, showing the data link layer headers, do this: \begin{verbatim} ./snort -vde \end{verbatim} As an aside, notice that the command line switches can be listed separately or in a combined form. The last command could also be typed out as: \begin{verbatim} ./snort -d -v -e \end{verbatim} to produce the same result. \section{Packet Logger Mode} OK, all of these commands are pretty cool, but if you want to record the packets to the disk, you need to specify a logging directory and Snort will automatically know to go into packet logger mode: \begin{verbatim} ./snort -dev -l ./log \end{verbatim} Of course, this assumes you have a directory named \verb!log! in the current directory. If you don't, Snort will exit with an error message. When Snort runs in this mode, it collects every packet it sees and places it in a directory hierarchy based upon the IP address of one of the hosts in the datagram. If you just specify a plain -l switch, you may notice that Snort sometimes uses the address of the remote computer as the directory in which it places packets and sometimes it uses the local host address. In order to log relative to the home network, you need to tell Snort which network is the home network: \begin{verbatim} ./snort -dev -l ./log -h 192.168.1.0/24 \end{verbatim} This rule tells Snort that you want to print out the data link and TCP/IP headers as well as application data into the directory \verb!./log!, and you want to log the packets relative to the 192.168.1.0 class C network. All incoming packets will be recorded into subdirectories of the log directory, with the directory names being based on the address of the remote (non-192.168.1) host. \begin{note} Note that if both the source and destination hosts are on the home network, they are logged to a directory with a name based on the higher of the two port numbers or, in the case of a tie, the source address. \end{note} If you're on a high speed network or you want to log the packets into a more compact form for later analysis, you should consider logging in binary mode. Binary mode logs the packets in tcpdump format to a single binary file in the logging directory: \begin{verbatim} ./snort -l ./log -b \end{verbatim} Note the command line changes here. We don't need to specify a home network any longer because binary mode logs everything into a single file, which eliminates the need to tell it how to format the output directory structure. Additionally, you don't need to run in verbose mode or specify the -d or -e switches because in binary mode the entire packet is logged, not just sections of it. All you really need to do to place Snort into logger mode is to specify a logging directory at the command line using the -l switch---the -b binary logging switch merely provides a modifier that tells Snort to log the packets in something other than the default output format of plain ASCII text. Once the packets have been logged to the binary file, you can read the packets back out of the file with any sniffer that supports the tcpdump binary format (such as tcpdump or Ethereal). Snort can also read the packets back by using the -r switch, which puts it into playback mode. Packets from any tcpdump formatted file can be processed through Snort in any of its run modes. For example, if you wanted to run a binary log file through Snort in sniffer mode to dump the packets to the screen, you can try something like this: \begin{verbatim} ./snort -dv -r packet.log \end{verbatim} You can manipulate the data in the file in a number of ways through Snort's packet logging and intrusion detection modes, as well as with the BPF interface that's available from the command line. For example, if you only wanted to see the ICMP packets from the log file, simply specify a BPF filter at the command line and Snort will only see the ICMP packets in the file: \begin{verbatim} ./snort -dvr packet.log icmp \end{verbatim} For more info on how to use the BPF interface, read the Snort and tcpdump man pages. \section{Network Intrusion Detection System Mode} To enable Network Intrusion Detection System (NIDS) mode so that you don't record every single packet sent down the wire, try this: \begin{verbatim} ./snort -dev -l ./log -h 192.168.1.0/24 -c snort.conf \end{verbatim} where \texttt{snort.conf} is the name of your snort configuration file. This will apply the rules configured in the \verb!snort.conf! file to each packet to decide if an action based upon the rule type in the file should be taken. If you don't specify an output directory for the program, it will default to \verb!/var/log/snort!. One thing to note about the last command line is that if Snort is going to be used in a long term way as an IDS, the -v switch should be left off the command line for the sake of speed. The screen is a slow place to write data to, and packets can be dropped while writing to the display. It's also not necessary to record the data link headers for most applications, so you can usually omit the -e switch, too. \begin{verbatim} ./snort -d -h 192.168.1.0/24 -l ./log -c snort.conf \end{verbatim} This will configure Snort to run in its most basic NIDS form, logging packets that trigger rules specified in the \texttt{snort.conf} in plain ASCII to disk using a hierarchical directory structure (just like packet logger mode). \subsection{NIDS Mode Output Options} There are a number of ways to configure the output of Snort in NIDS mode. The default logging and alerting mechanisms are to log in decoded ASCII format and use full alerts. The full alert mechanism prints out the alert message in addition to the full packet headers. There are several other alert output modes available at the command line, as well as two logging facilities. Alert modes are somewhat more complex. There are seven alert modes available at the command line: full, fast, socket, syslog, console, cmg, and none. Six of these modes are accessed with the -A command line switch. These options are: \begin{center} \begin{tabular}{| l | p{5.4in} |} \hline {\bf Option} & {\bf Description}\\ \hline \hline {\tt -A fast} & Fast alert mode. Writes the alert in a simple format with a timestamp, alert message, source and destination IPs/ports.\\ \hline {\tt -A full} & Full alert mode. This is the default alert mode and will be used automatically if you do not specify a mode.\\ \hline {\tt -A unsock} & Sends alerts to a UNIX socket that another program can listen on.\\ \hline {\tt -A none} & Turns off alerting.\\ \hline {\tt -A console} & Sends ``fast-style'' alerts to the console (screen).\\ \hline {\tt -A cmg} & Generates ``cmg style'' alerts.\\ \hline \end{tabular} \end{center} Packets can be logged to their default decoded ASCII format or to a binary log file via the -b command line switch. To disable packet logging altogether, use the -N command line switch. For output modes available through the configuration file, see Section \ref{output config}. \begin{note} Command line logging options override any output options specified in the configuration file. This allows debugging of configuration issues quickly via the command line. \end{note} To send alerts to syslog, use the -s switch. The default facilities for the syslog alerting mechanism are LOG\_AUTHPRIV and LOG\_ALERT. If you want to configure other facilities for syslog output, use the output plugin directives in snort.conf. See Section \ref{alert syslog label} for more details on configuring syslog output. For example, use the following command line to log to default (decoded ASCII) facility and send alerts to syslog: \begin{verbatim} ./snort -c snort.conf -l ./log -h 192.168.1.0/24 -s \end{verbatim} As another example, use the following command line to log to the default facility in /var/log/snort and send alerts to a fast alert file: \begin{verbatim} ./snort -c snort.conf -A fast -h 192.168.1.0/24 \end{verbatim} \subsection{Understanding Standard Alert Output} When Snort generates an alert message, it will usually look like the following: \begin{verbatim} [**] [116:56:1] (snort_decoder): T/TCP Detected [**] \end{verbatim} The first number is the Generator ID, this tells the user what component of Snort generated this alert. For a list of GIDs, please read etc/generators in the Snort source. In this case, we know that this event came from the ``decode'' (116) component of Snort. The second number is the Snort ID (sometimes referred to as Signature ID). For a list of preprocessor SIDs, please see etc/gen-msg.map. Rule-based SIDs are written directly into the rules with the \emph{sid} option. In this case, \emph{56} represents a T/TCP event. The third number is the revision ID. This number is primarily used when writing signatures, as each rendition of the rule should increment this number with the \emph{rev} option. \subsection{High Performance Configuration} If you want Snort to go \emph{fast} (like keep up with a 1000 Mbps connection), you need to use unified2 logging and a unified2 log reader such as \emph{barnyard2}. This allows Snort to log alerts in a binary form as fast as possible while another program performs the slow actions, such as writing to a database. If you want a text file that's easily parsed, but still somewhat fast, try using binary logging with the ``fast'' output mechanism. This will log packets in tcpdump format and produce minimal alerts. For example: \begin{verbatim} ./snort -b -A fast -c snort.conf \end{verbatim} \subsection{Changing Alert Order} The default way in which Snort applies its rules to packets may not be appropriate for all installations. The Pass rules are applied first, then the Drop rules, then the Alert rules and finally, Log rules are applied. \begin{note} Sometimes an errant pass rule could cause alerts to not show up, in which case you can change the default ordering to allow Alert rules to be applied before Pass rules. For more information, please refer to the \texttt{--alert-before-pass} option. \end{note} Several command line options are available to change the order in which rule actions are taken. \begin{itemize} \item \texttt{--alert-before-pass} option forces alert rules to take affect in favor of a pass rule. \item \texttt{--treat-drop-as-alert} causes drop and reject rules and any associated alerts to be logged as alerts, rather then the normal action. This allows use of an inline policy with passive/IDS mode. The sdrop rules are not loaded. \item \texttt{--process-all-events} option causes Snort to process every event associated with a packet, while taking the actions based on the rules ordering. Without this option (default case), only the events for the first action based on rules ordering are processed. \end{itemize} \begin{note} Pass rules are special cases here, in that the event processing is terminated when a pass rule is encountered, regardless of the use of \texttt{--process-all-events}. \end{note} \section{Packet Acquisition} Snort 2.9 introduces the DAQ, or Data Acquisition library, for packet I/O. The DAQ replaces direct calls to libpcap functions with an abstraction layer that facilitates operation on a variety of hardware and software interfaces without requiring changes to Snort. It is possible to select the DAQ type and mode when invoking Snort to perform pcap readback or inline operation, etc. \begin{note} Some network cards have features named "Large Receive Offload" (lro) and "Generic Receive Offload" (gro). With these features enabled, the network card performs packet reassembly before they're processed by the kernel. By default, Snort will truncate packets larger than the default snaplen of 1518 bytes. In addition, LRO and GRO may cause issues with Stream5 target-based reassembly. We recommend that you turn off LRO and GRO. On linux systems, you can run: \begin{verbatim} $ ethtool -K eth1 gro off $ ethtool -K eth1 lro off \end{verbatim} \end{note} \subsection{Configuration} Assuming that you did not disable static modules or change the default DAQ type, you can run Snort just as you always did for file readback or sniffing an interface. However, you can select and configure the DAQ when Snort is invoked as follows: \begin{verbatim} ./snort \ [--daq ] \ [--daq-mode ] \ [--daq-dir ] \ [--daq-var ] config daq: config daq_dir: config daq_var: config daq_mode: ::= pcap | afpacket | dump | nfq | ipq | ipfw ::= read-file | passive | inline ::= arbitrary = passed to DAQ ::= path where to look for DAQ module so's \end{verbatim} The DAQ type, mode, variable, and directory may be specified either via the command line or in the conf file. You may include as many variables and directories as needed by repeating the arg / config. DAQ type may be specified at most once in the conf and once on the command line; if configured in both places, the command line overrides the conf. If the mode is not set explicitly, -Q will force it to inline, and if that hasn't been set, -r will force it to read-file, and if that hasn't been set, the mode defaults to passive. Also, -Q and --daq-mode inline are allowed, since there is no conflict, but -Q and any other DAQ mode will cause a fatal error at start-up. Note that if Snort finds multiple versions of a given library, the most recent version is selected. This applies to static and dynamic versions of the same library. \begin{verbatim} ./snort --daq-list[=] ./snort --daq-dir= --daq-list \end{verbatim} The above commands search the specified directories for DAQ modules and print type, version, and attributes of each. This feature is not available in the conf. Snort stops processing after parsing --daq-list so if you want to add one or more directories add --daq-dir options before --daq-list on the command line. (Since the directory is optional to --daq-list, you must use an = without spaces for this option.) \subsection{pcap} pcap is the default DAQ. if snort is run w/o any DAQ arguments, it will operate as it always did using this module. These are equivalent: \begin{verbatim} ./snort -i ./snort -r ./snort --daq pcap --daq-mode passive -i ./snort --daq pcap --daq-mode read-file -r \end{verbatim} You can specify the buffer size pcap uses with: \begin{verbatim} ./snort --daq pcap --daq-var buffer_size=<#bytes> \end{verbatim} Note that the pcap DAQ does not count filtered packets. \subsection{AFPACKET} afpacket functions similar to the memory mapped pcap DAQ but no external library is required: \begin{verbatim} ./snort --daq afpacket -i [--daq-var buffer_size_mb=<#MB>] [--daq-var debug] \end{verbatim} If you want to run afpacket in inline mode, you must set device to one or more interface pairs, where each member of a pair is separated by a single colon and each pair is separated by a double colon like this: \begin{verbatim} eth0:eth1 \end{verbatim} or this: \begin{verbatim} eth0:eth1::eth2:eth3 \end{verbatim} By default, the afpacket DAQ allocates 128MB for packet memory. You can change this with: \begin{verbatim} --daq-var buffer_size_mb=<#MB> \end{verbatim} Note that the total allocated is actually higher, here's why. Assuming the default packet memory with a snaplen of 1518, the numbers break down like this: \begin{slist} \item The frame size is 1518 (snaplen) + the size of the AFPacket header (66 bytes) = 1584 bytes. \item The number of frames is 128 MB / 1518 = 84733. \item The smallest block size that can fit at least one frame is 4 KB = 4096 bytes @ 2 frames per block. \item As a result, we need 84733 / 2 = 42366 blocks. \item Actual memory allocated is 42366 * 4 KB = 165.5 MB. \end{slist} \subsection{NFQ} NFQ is the new and improved way to process iptables packets: \begin{verbatim} ./snort --daq nfq \ [--daq-var device=] \ [--daq-var proto=] \ [--daq-var queue=] \ [--daq-var queue_len=] ::= ip | eth0, etc; default is IP injection ::= ip4 | ip6 | ip*; default is ip4 ::= 0..65535; default is 0 ::= 0..65535; default is 0 \end{verbatim} Notes on iptables can be found in the DAQ distro README. \subsection{IPQ} IPQ is the old way to process iptables packets. It replaces the inline version available in pre-2.9 versions built with this: \begin{verbatim} ./configure --enable-inline / -DGIDS \end{verbatim} Start the IPQ DAQ as follows: \begin{verbatim} ./snort --daq ipq \ [--daq-var device=] \ [--daq-var proto=] \ ::= ip | eth0, etc; default is IP injection ::= ip4 | ip6; default is ip4 \end{verbatim} \subsection{IPFW} IPFW is available for BSD systems. It replaces the inline version available in pre-2.9 versions built with this: \begin{verbatim} ./configure --enable-ipfw / -DGIDS -DIPFW \end{verbatim} This command line argument is no longer supported: \begin{verbatim} ./snort -J \end{verbatim} Instead, start Snort like this: \begin{verbatim} ./snort --daq ipfw [--daq-var port=] ::= 1..65535; default is 8000 \end{verbatim} * IPFW only supports ip4 traffic. \subsection{Dump} The dump DAQ allows you to test the various inline mode features available in 2.9 Snort like injection and normalization. \begin{verbatim} ./snort -i --daq dump ./snort -r --daq dump \end{verbatim} By default a file named inline-out.pcap will be created containing all packets that passed through or were generated by snort. You can optionally specify a different name. \begin{verbatim} ./snort --daq dump --daq-var file= \end{verbatim} dump uses the pcap daq for packet acquisition. It therefore does not count filtered packets. Note that the dump DAQ inline mode is not an actual inline mode. Furthermore, you will probably want to have the pcap DAQ acquire in another mode like this: \begin{verbatim} ./snort -r -Q --daq dump --daq-var load-mode=read-file ./snort -i -Q --daq dump --daq-var load-mode=passive \end{verbatim} \subsection{Statistics Changes} The Packet Wire Totals and Action Stats sections of Snort's output include additional fields: \begin{itemize} \item \texttt{Filtered} count of packets filtered out and not handed to Snort for analysis. \item \texttt{Injected} packets Snort generated and sent, e.g. TCP resets. \item \texttt{Allow} packets Snort analyzed and did not take action on. \item \texttt{Block} packets Snort did not forward, e.g. due to a block rule. \item \texttt{Replace} packets Snort modified. \item \texttt{Whitelist} packets that caused Snort to allow a flow to pass w/o inspection by any analysis program. \item \texttt{Blacklist} packets that caused Snort to block a flow from passing. \item \texttt{Ignore} packets that caused Snort to allow a flow to pass w/o inspection by this instance of Snort. \end{itemize} The action stats show "blocked" packets instead of "dropped" packets to avoid confusion between dropped packets (those Snort didn't actually see) and blocked packets (those Snort did not allow to pass). \section{Reading pcap files} Instead of having Snort listen on an interface, you can give it a packet capture to read. Snort will read and analyze the packets as if they came off the wire. This can be useful for testing and debugging Snort. \subsection{Command line arguments} Any of the below can be specified multiple times on the command line (\texttt{-r} included) and in addition to other Snort command line options. Note, however, that specifying \texttt{--pcap-reset} and \texttt{--pcap-show} multiple times has the same effect as specifying them once. \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{-r } & Read a single pcap. \\ \hline \texttt{--pcap-single=} & Same as -r. Added for completeness. \\ \hline \texttt{--pcap-file=} & File that contains a list of pcap files to read. Can specify path to each pcap or directory to recurse to get pcaps. \\ \hline \texttt{--pcap-list=""} & A space separated list of pcaps to read. \\ \hline \texttt{--pcap-dir=} & A directory to recurse to look for pcaps. Sorted in ASCII order. \\ \hline \texttt{--pcap-filter=} & Shell style filter to apply when getting pcaps from file or directory. This filter will apply to any \texttt{--pcap-file} or \texttt{--pcap-dir} arguments following. Use \texttt{--pcap-no-filter} to delete filter for following \texttt{--pcap-file} or \texttt{--pcap-dir} arguments or specify \texttt{--pcap-filter} again to forget previous filter and to apply to following \texttt{--pcap-file} or \texttt{--pcap-dir} arguments. \\ \hline \texttt{--pcap-no-filter} & Reset to use no filter when getting pcaps from file or directory. \\ \hline \texttt{--pcap-reset} & If reading multiple pcaps, reset snort to post-configuration state before reading next pcap. The default, i.e. without this option, is not to reset state. \\ \hline \texttt{--pcap-show} & Print a line saying what pcap is currently being read. \\ \hline \end{tabular} \end{center} \subsection{Examples} \subsubsection{Read a single pcap} \begin{verbatim} $ snort -r foo.pcap $ snort --pcap-single=foo.pcap \end{verbatim} \subsubsection{Read pcaps from a file} \begin{verbatim} $ cat foo.txt foo1.pcap foo2.pcap /home/foo/pcaps \end{verbatim} \begin{verbatim} $ snort --pcap-file=foo.txt \end{verbatim} This will read foo1.pcap, foo2.pcap and all files under /home/foo/pcaps. Note that Snort will not try to determine whether the files under that directory are really pcap files or not. \subsubsection{Read pcaps from a command line list} \begin{verbatim} $ snort --pcap-list="foo1.pcap foo2.pcap foo3.pcap" \end{verbatim} This will read foo1.pcap, foo2.pcap and foo3.pcap. \subsubsection{Read pcaps under a directory} \begin{verbatim} $ snort --pcap-dir="/home/foo/pcaps" \end{verbatim} This will include all of the files under /home/foo/pcaps. \subsubsection{Using filters} \begin{verbatim} $ cat foo.txt foo1.pcap foo2.pcap /home/foo/pcaps \end{verbatim} \begin{verbatim} $ snort --pcap-filter="*.pcap" --pcap-file=foo.txt $ snort --pcap-filter="*.pcap" --pcap-dir=/home/foo/pcaps \end{verbatim} The above will only include files that match the shell pattern "*.pcap", in other words, any file ending in ".pcap". \begin{verbatim} $ snort --pcap-filter="*.pcap --pcap-file=foo.txt \ > --pcap-filter="*.cap" --pcap-dir=/home/foo/pcaps \end{verbatim} In the above, the first filter "*.pcap" will only be applied to the pcaps in the file "foo.txt" (and any directories that are recursed in that file). The addition of the second filter "*.cap" will cause the first filter to be forgotten and then applied to the directory /home/foo/pcaps, so only files ending in ".cap" will be included from that directory. \begin{verbatim} $ snort --pcap-filter="*.pcap --pcap-file=foo.txt \ > --pcap-no-filter --pcap-dir=/home/foo/pcaps \end{verbatim} In this example, the first filter will be applied to foo.txt, then no filter will be applied to the files found under /home/foo/pcaps, so all files found under /home/foo/pcaps will be included. \begin{verbatim} $ snort --pcap-filter="*.pcap --pcap-file=foo.txt \ > --pcap-no-filter --pcap-dir=/home/foo/pcaps \ > --pcap-filter="*.cap" --pcap-dir=/home/foo/pcaps2 \end{verbatim} In this example, the first filter will be applied to foo.txt, then no filter will be applied to the files found under /home/foo/pcaps, so all files found under /home/foo/pcaps will be included, then the filter "*.cap" will be applied to files found under /home/foo/pcaps2. \subsubsection{Resetting state} \begin{verbatim} $ snort --pcap-dir=/home/foo/pcaps --pcap-reset \end{verbatim} The above example will read all of the files under /home/foo/pcaps, but after each pcap is read, Snort will be reset to a post-configuration state, meaning all buffers will be flushed, statistics reset, etc. For each pcap, it will be like Snort is seeing traffic for the first time. \subsubsection{Printing the pcap} \begin{verbatim} $ snort --pcap-dir=/home/foo/pcaps --pcap-show \end{verbatim} The above example will read all of the files under /home/foo/pcaps and will print a line indicating which pcap is currently being read. \section{Basic Output} Snort does a lot of work and outputs some useful statistics when it is done. Many of these are self-explanatory. The others are summarized below. This does not include all possible output data, just the basics. \subsection{Timing Statistics} This section provides basic timing statistics. It includes total seconds and packets as well as packet processing rates. The rates are based on whole seconds, minutes, etc. and only shown when non-zero. Example: \begin{verbatim} =============================================================================== Run time for packet processing was 175.856509 seconds Snort processed 3716022 packets. Snort ran for 0 days 0 hours 2 minutes 55 seconds Pkts/min: 1858011 Pkts/sec: 21234 =============================================================================== \end{verbatim} \subsection{Packet I/O Totals} This section shows basic packet acquisition and injection peg counts obtained from the DAQ. If you are reading pcaps, the totals are for all pcaps combined, unless you use --pcap-reset, in which case it is shown per pcap. \begin{itemize} \item Outstanding indicates how many packets are buffered awaiting processing. The way this is counted varies per DAQ so the DAQ documentation should be consulted for more info. \item Filtered packets are not shown for pcap DAQs. \item Injected packets are the result of active response which can be configured for inline or passive modes. \end{itemize} Example: \begin{verbatim} =============================================================================== Packet I/O Totals: Received: 3716022 Analyzed: 3716022 (100.000%) Dropped: 0 ( 0.000%) Filtered: 0 ( 0.000%) Outstanding: 0 ( 0.000%) Injected: 0 =============================================================================== \end{verbatim} \subsection{Protocol Statistics} Traffic for all the protocols decoded by Snort is summarized in the breakdown section. This traffic includes internal "pseudo-packets" if preprocessors such as frag3 and stream5 are enabled so the total may be greater than the number of analyzed packets in the packet I/O section. \begin{itemize} \item Disc counts are discards due to basic encoding integrity flaws that prevents Snort from decoding the packet. \item Other includes packets that contained an encapsulation that Snort doesn't decode. \item S5 G 1/2 is the number of client/server sessions stream5 flushed due to cache limit, session timeout, session reset. \end{itemize} Example: \begin{verbatim} =============================================================================== Breakdown by protocol (includes rebuilt packets): Eth: 3722347 (100.000%) VLAN: 0 ( 0.000%) IP4: 1782394 ( 47.884%) Frag: 3839 ( 0.103%) ICMP: 38860 ( 1.044%) UDP: 137162 ( 3.685%) TCP: 1619621 ( 43.511%) IP6: 1781159 ( 47.850%) IP6 Ext: 1787327 ( 48.016%) IP6 Opts: 6168 ( 0.166%) Frag6: 3839 ( 0.103%) ICMP6: 1650 ( 0.044%) UDP6: 140446 ( 3.773%) TCP6: 1619633 ( 43.511%) Teredo: 18 ( 0.000%) ICMP-IP: 0 ( 0.000%) EAPOL: 0 ( 0.000%) IP4/IP4: 0 ( 0.000%) IP4/IP6: 0 ( 0.000%) IP6/IP4: 0 ( 0.000%) IP6/IP6: 0 ( 0.000%) GRE: 202 ( 0.005%) GRE Eth: 0 ( 0.000%) GRE VLAN: 0 ( 0.000%) GRE IP4: 0 ( 0.000%) GRE IP6: 0 ( 0.000%) GRE IP6 Ext: 0 ( 0.000%) GRE PPTP: 202 ( 0.005%) GRE ARP: 0 ( 0.000%) GRE IPX: 0 ( 0.000%) GRE Loop: 0 ( 0.000%) MPLS: 0 ( 0.000%) ARP: 104840 ( 2.817%) IPX: 60 ( 0.002%) Eth Loop: 0 ( 0.000%) Eth Disc: 0 ( 0.000%) IP4 Disc: 0 ( 0.000%) IP6 Disc: 0 ( 0.000%) TCP Disc: 0 ( 0.000%) UDP Disc: 1385 ( 0.037%) ICMP Disc: 0 ( 0.000%) All Discard: 1385 ( 0.037%) Other: 57876 ( 1.555%) Bad Chk Sum: 32135 ( 0.863%) Bad TTL: 0 ( 0.000%) S5 G 1: 1494 ( 0.040%) S5 G 2: 1654 ( 0.044%) Total: 3722347 =============================================================================== \end{verbatim} \subsection{Snort Memory Statistics} On systems with mallinfo (3), you will see additional statistics. Check the man page of mallinfo for details Example: \begin{verbatim} =============================================================================== Memory usage summary: Total non-mmapped bytes (arena): 415481856 Bytes in mapped regions (hblkhd): 409612288 Total allocated space (uordblks): 92130384 Total free space (fordblks): 323351472 Topmost releasable block (keepcost): 3200 =============================================================================== \end{verbatim} \subsection{Actions, Limits, and Verdicts} Action and verdict counts show what Snort did with the packets it analyzed. This information is only output in IDS mode (when snort is run with the \texttt{-c } option). \begin{itemize} \item Alerts is the number of activate, alert, and block actions processed as determined by the rule actions. Here block includes block, drop, and reject actions. \end{itemize} Limits arise due to real world constraints on processing time and available memory. These indicate potential actions that did not happen: \begin{itemize} \item Match Limit counts rule matches were not processed due to the \texttt{config detection: max\_queue\_events} setting. The default is 5. \item Queue Limit counts events couldn't be stored in the event queue due to the \texttt{config event\_queue: max\_queue} setting. The default is 8. \item Log Limit counts events were not alerted due to the \texttt{config event\_queue: log} setting. The default is 3. \item Event Limit counts events not alerted due to \texttt{event\_filter} limits. \item Alert Limit counts events were not alerted because they already were triggered on the session. \end{itemize} Verdicts are rendered by Snort on each packet: \begin{itemize} \item Allow = packets Snort analyzed and did not take action on. \item Block = packets Snort did not forward, e.g. due to a block rule. "Block" is used instead of "Drop" to avoid confusion between dropped packets (those Snort didn't actually see) and blocked packets (those Snort did not allow to pass). \item Replace = packets Snort modified, for example, due to normalization or replace rules. This can only happen in inline mode with a compatible DAQ. \item Whitelist = packets that caused Snort to allow a flow to pass w/o inspection by any analysis program. Like blacklist, this is done by the DAQ or by Snort on subsequent packets. \item Blacklist = packets that caused Snort to block a flow from passing. This is the case when a block TCP rule fires. If the DAQ supports this in hardware, no further packets will be seen by Snort for that session. If not, snort will block each packet and this count will be higher. \item Ignore = packets that caused Snort to allow a flow to pass w/o inspection by this instance of Snort. Like blacklist, this is done by the DAQ or by Snort on subsequent packets. \item Int Blklst = packets that are GTP, Teredo, 6in4 or 4in6 encapsulated that are being blocked. These packets could get the Blacklist verdict if \texttt{config tunnel\_verdicts} was set for the given protocol. Note that these counts are output only if non-zero. Also, this count is incremented on the first packet in the flow that alerts. The alerting packet and all following packets on the flow will be counted under Block. \item Int Whtlst = packets that are GTP, Teredo, 6in4 or 4in6 encapsulated that are being allowed. These packets could get the Whitelist verdict if \texttt{config tunnel\_verdicts} was set for the given protocol. Note that these counts are output only if non-zero. Also, this count is incremented for all packets on the flow starting with the alerting packet. \end{itemize} Example: \begin{verbatim} =============================================================================== Action Stats: Alerts: 0 ( 0.000%) Logged: 0 ( 0.000%) Passed: 0 ( 0.000%) Limits: Match: 0 Queue: 0 Log: 0 Event: 0 Alert: 0 Verdicts: Allow: 3716022 (100.000%) Block: 0 ( 0.000%) Replace: 0 ( 0.000%) Whitelist: 0 ( 0.000%) Blacklist: 0 ( 0.000%) Ignore: 0 ( 0.000%) =============================================================================== \end{verbatim} \section{Tunneling Protocol Support} Snort supports decoding of many tunneling protocols, including GRE, PPTP over GRE, MPLS, IP in IP, and ERSPAN, all of which are enabled by default. To disable support for any GRE related encapsulation, PPTP over GRE, IPv4/IPv6 over GRE, and ERSPAN, an extra configuration option is necessary: \begin{verbatim} $ ./configure --disable-gre \end{verbatim} To disable support for MPLS, an separate extra configuration option is necessary: \begin{verbatim} $ ./configure --disable-mpls \end{verbatim} \subsection{Multiple Encapsulations} Snort will not decode more than one encapsulation. Scenarios such as \begin{verbatim} Eth IPv4 GRE IPv4 GRE IPv4 TCP Payload \end{verbatim} or \begin{verbatim} Eth IPv4 IPv6 IPv4 TCP Payload \end{verbatim} will not be handled and will generate a decoder alert. \subsection{Logging} Currently, only the encapsulated part of the packet is logged, e.g. \begin{verbatim} Eth IP1 GRE IP2 TCP Payload \end{verbatim} gets logged as \begin{verbatim} Eth IP2 TCP Payload \end{verbatim} and \begin{verbatim} Eth IP1 IP2 TCP Payload \end{verbatim} gets logged as \begin{verbatim} Eth IP2 TCP Payload \end{verbatim} \begin{note} Decoding of PPTP, which utilizes GRE and PPP, is not currently supported on architectures that require word alignment such as SPARC. \end{note} \section{Miscellaneous} \subsection{Running Snort as a Daemon} If you want to run Snort as a daemon, you can the add -D switch to any combination described in the previous sections. Please notice that if you want to be able to restart Snort by sending a SIGHUP signal to the daemon, you {\em must} specify the full path to the Snort binary when you start it, for example: \begin{verbatim} /usr/local/bin/snort -d -h 192.168.1.0/24 \ -l /var/log/snortlogs -c /usr/local/etc/snort.conf -s -D \end{verbatim} Relative paths are not supported due to security concerns. \subsubsection{Snort PID File} When Snort is run as a daemon , the daemon creates a PID file in the log directory. In Snort 2.6, the \texttt{--pid-path} command line switch causes Snort to write the PID file in the directory specified. Additionally, the \texttt{--create-pidfile} switch can be used to force creation of a PID file even when not running in daemon mode. The PID file will be locked so that other snort processes cannot start. Use the \texttt{--nolock-pidfile} switch to not lock the PID file. If you do not wish to include the name of the interface in the PID file, use the \texttt{--no-interface-pidfile} switch. \subsection{Running in Rule Stub Creation Mode} If you need to dump the shared object rules stub to a directory, you must use the --dump-dynamic-rules command line option. These rule stub files are used in conjunction with the shared object rules. The path can be relative or absolute. \begin{verbatim} /usr/local/bin/snort -c /usr/local/etc/snort.conf \ --dump-dynamic-rules=/tmp \end{verbatim} This path can also be configured in the snort.conf using the config option dump-dynamic-rules-path as follows: \begin{verbatim} config dump-dynamic-rules-path: /tmp/sorules \end{verbatim} The path configured by command line has precedence over the one configured using dump-dynamic-rules-path. \begin{verbatim} /usr/local/bin/snort -c /usr/local/etc/snort.conf \ --dump-dynamic-rules snort.conf: config dump-dynamic-rules-path: /tmp/sorules \end{verbatim} In the above mentioned scenario the dump path is set to /tmp/sorules. \subsection{Obfuscating IP Address Printouts} If you need to post packet logs to public mailing lists, you might want to use the -O switch. This switch obfuscates your IP addresses in packet printouts. This is handy if you don't want people on the mailing list to know the IP addresses involved. You can also combine the -O switch with the -h switch to only obfuscate the IP addresses of hosts on the home network. This is useful if you don't care who sees the address of the attacking host. For example, you could use the following command to read the packets from a log file and dump them to the screen, obfuscating only the addresses from the 192.168.1.0/24 class C network: \begin{verbatim} ./snort -d -v -r snort.log -O -h 192.168.1.0/24 \end{verbatim} \subsection{Specifying Multiple-Instance Identifiers} In Snort v2.4, the \texttt{-G} command line option was added that specifies an instance identifier for the event logs. This option can be used when running multiple instances of snort, either on different CPUs, or on the same CPU but a different interface. Each Snort instance will use the value specified to generate unique event IDs. Users can specify either a decimal value (\texttt{-G 1}) or hex value preceded by 0x (\texttt{-G 0x11}). This is also supported via a long option \texttt{--logid}. \subsection{Snort Modes} Snort can operate in three different modes namely tap (passive), inline, and inline-test. Snort policies can be configured in these three modes too. \subsubsection{Explanation of Modes} \begin{itemize} \item \texttt{Inline} When Snort is in Inline mode, it acts as an IPS allowing drop rules to trigger. Snort can be configured to run in inline mode using the command line argument -Q and snort config option \texttt{policy\_mode} as follows: \begin{verbatim} snort -Q config policy_mode:inline \end{verbatim} \item \texttt{Passive} When Snort is in Passive mode, it acts as a IDS. Drop rules are not loaded (without --treat-drop-as-alert). Snort can be configured to passive mode using the snort config option \texttt{policy\_mode} as follows: \begin{verbatim} config policy_mode:tap \end{verbatim} \item \texttt{Inline-Test} Inline-Test mode simulates the inline mode of snort, allowing evaluation of inline behavior without affecting traffic. The drop rules will be loaded and will be triggered as a Wdrop (Would Drop) alert. Snort can be configured to run in inline-test mode using the command line option (--enable-inline-test) or using the snort config option \texttt{policy\_mode} as follows: \begin{verbatim} snort --enable-inline-test config policy_mode:inline_test \end{verbatim} \begin{note} Please note --enable-inline-test cannot be used in conjunction with -Q. \end{note} \end{itemize} \texttt{Behavior of different modes with rule options} \begin{tabular}{|l|c|c|p{6cm}|} \hline Rule Option & Inline Mode & Passive Mode & Inline-Test Mode\\ \hline \hline \texttt{reject} & Drop + Response & Alert + Response & Wdrop + Response\\ \hline \texttt{react} & Blocks and send notice & Blocks and send notice & Blocks and send notice\\ \hline \texttt{normalize} & Normalizes packet & Doesn't normalize & Doesn't normalize\\ \hline \texttt{replace} & replace content & Doesn't replace & Doesn't replace\\ \hline \texttt{respond} & close session & close session & close session\\ \hline \end{tabular} \texttt{Behavior of different modes with rules actions} \begin{tabular}{|l|c|c|c|} \hline Adapter Mode & Snort args & config policy\_mode & Drop Rule Handling\\ \hline \hline Passive & \texttt{ --treat-drop-as-alert} & tap & Alert\\ \hline Passive & \texttt{ no args} & tap & Not Loaded\\ \hline Passive & \texttt{ --treat-drop-as-alert} & inline\_test & Alert\\ \hline Passive & \texttt{ no args} & inline\_test & Would Drop\\ \hline Passive & \texttt{ --treat-drop-as-alert} & inline & Alert\\ \hline Passive & \texttt{no args} & inline & Not loaded + warning\\ \hline Inline Test & \texttt{ --enable-inline-test --treat-drop-as-alert} & tap & Alert\\ \hline Inline Test & \texttt{ --enable-inline-test} & tap & Would Drop\\ \hline Inline Test & \texttt{ --enable-inline-test --treat-drop-as-alert} & inline\_test & Alert\\ \hline Inline Test & \texttt{ --enable-inline-test} & inline\_test & Would Drop\\ \hline Inline Test & \texttt{ --enable-inline-test --treat-drop-as-alert} & inline & Alert\\ \hline Inline Test & \texttt{ --enable-inline-test} & inline & Would Drop\\ \hline Inline & \texttt{ -Q --treat-drop-as-alert} & tap & Alert\\ \hline Inline & \texttt{ -Q} & tap & Alert\\ \hline Inline & \texttt{ -Q --treat-drop-as-alert} & inline\_test & Alert\\ \hline Inline & \texttt{ -Q} & inline\_test & Would Drop\\ \hline Inline & \texttt{ -Q --treat-drop-as-alert} & inline & Alert\\ \hline Inline & \texttt{ -Q} & inline & Drop\\ \hline \end{tabular} \section{Control socket} \label{control_socket} Snort can be configured to provide a Unix socket that can be used to issue commands to the running process. You must build snort with the \texttt{--enable-control-socket} option. The control socket functionality is supported on Linux only.\\ Snort can be configured to use control socket using the command line argument \texttt{--cs-dir } and snort config option \texttt{cs\_dir} as follows: \begin{verbatim} snort --cs-dir config cs_dir: \end{verbatim} \texttt{} specifies the directory for snort to create the socket. If relative path is used, the path is relative to pid path specified. If there is no pid path specified, it is relative to current working directory. A command \texttt{snort\_control} is made and installed along with snort in the same bin directory when configured with the \texttt{--enable-control-socket} option. \section{Configure signal value} \label{configure_signal} On some systems, signal used by snort might be used by other functions. To avoid conflicts, users can change the default signal value through \texttt{./configure} options for non-Windows system. These signals can be changed: \begin{itemize} \item \texttt{SIGNAL\_SNORT\_RELOAD} \item \texttt{SIGNAL\_SNORT\_DUMP\_STATS} \item \texttt{SIGNAL\_SNORT\_ROTATE\_STATS} \item \texttt{SIGNAL\_SNORT\_READ\_ATTR\_TBL} \end{itemize} Syntax: \begin{verbatim} ./configure SIGNAL_SNORT_RELOAD= SIGNAL_SNORT_DUMP_STATS=\ SIGNAL_SNORT_READ_ATTR_TBL= SIGNAL_SNORT_ROTATE_STATS= \end{verbatim} You can set those signals to user defined values or known signal names in the system. The following example changes the rotate stats signal to 31 and reload attribute table to signal SIGUSR2 : \begin{verbatim} ./configure SIGNAL_SNORT_ROTATE_STATS=31 SIGNAL_SNORT_READ_ATTR_TBL=SIGUSR2 \end{verbatim} If the same signal is assigned more than once a warning will be logged during snort initialization. If a signal handler cannot be installed a warning will be logged and that has to be fixed, otherwise the functionality will be lost. \texttt{Signals used in snort} \begin{tabular}{|l|l|l|} \hline Signal name & Default value & Action \\ \hline \hline SIGTERM & SIGTERM & exit \\ \hline SIGINT & SIGINT & exit \\ \hline SIGQUIT & SIGQUIT & exit \\ \hline SIGPIPE & SIGPIPE & ignore \\ \hline SIGNAL\_SNORT\_RELOAD & SIGHUP & reload snort \\ \hline SIGNAL\_SNORT\_DUMP\_STATS & SIGUSR1 & dump stats \\ \hline SIGNAL\_SNORT\_ROTATE\_STATS & SIGUSR2 & rotate stats \\ \hline SIGNAL\_SNORT\_READ\_ATTR\_TBL & SIGURG & reload attribute table \\ \hline SIGNAL\_SNORT\_CHILD\_READY & SIGCHLD & internal use in daemon mode \\ \hline \end{tabular} \section{More Information} Chapter \ref{Configuring Snort} contains much information about many configuration options available in the configuration file. The Snort manual page and the output of \texttt{snort -?} or \texttt{snort --help} contain information that can help you get Snort running in several different modes. \begin{note} In many shells, a backslash (\textbackslash{}) is needed to escape the ?, so you may have to type \texttt{snort -\textbackslash{}?} instead of \texttt{snort -?} for a list of Snort command line options. \end{note} The Snort web page (\url{http://www.snort.org}) and the Snort Users mailing list: \url{http://marc.theaimsgroup.com/?l=snort-users} at \verb?snort-users@lists.sourceforge.net? provide informative announcements as well as a venue for community discussion and support. There's a lot to Snort, so sit back with a beverage of your choosing and read the documentation and mailing list archives. \chapter{Configuring Snort} \label{Configuring Snort} \section{Includes} The {\tt include} keyword allows other snort config files to be included within the snort.conf indicated on the Snort command line. It works much like an \#include from the C programming language, reading the contents of the named file and adding the contents in the place where the include statement appears in the file. \subsection{Format} \begin{verbatim} include \end{verbatim} \begin{note} Note that there is no semicolon at the end of this line. \end{note} Included files will substitute any predefined variable values into their own variable references. See Section \ref{variables} for more information on defining and using variables in Snort config files. \subsection{Variables} \label{variables} Three types of variables may be defined in Snort: \begin{itemize} \item var \item portvar \item ipvar \end{itemize} These are simple substitution variables set with the {\tt var}, {\tt ipvar}, or {\tt portvar} keywords as follows: \begin{verbatim} var RULES_PATH rules/ portvar MY_PORTS [22,80,1024:1050] ipvar MY_NET [192.168.1.0/24,10.1.1.0/24] alert tcp any any -> $MY_NET $MY_PORTS (flags:S; msg:"SYN packet";) include $RULE_PATH/example.rule \end{verbatim} \subsubsection{IP Variables and IP Lists} IPs may be specified individually, in a list, as a CIDR block, or any combination of the three. IP variables should be specified using 'ipvar' instead of 'var'. Using 'var' for an IP variable is still allowed for backward compatibility, but it will be deprecated in a future release. IPs, IP lists, and CIDR blocks may be negated with '!'. Negation is handled differently compared with Snort versions 2.7.x and earlier. Previously, each element in a list was logically OR'ed together. IP lists now OR non-negated elements and AND the result with the OR'ed negated elements. The following example list will match the IP 1.1.1.1 and IP from 2.2.2.0 to 2.2.2.255, with the exception of IPs 2.2.2.2 and 2.2.2.3. \begin{verbatim} [1.1.1.1,2.2.2.0/24,![2.2.2.2,2.2.2.3]] \end{verbatim} The order of the elements in the list does not matter. The element 'any' can be used to match all IPs, although '!any' is not allowed. Also, negated IP ranges that are more general than non-negated IP ranges are not allowed. See below for some valid examples if IP variables and IP lists. \begin{verbatim} ipvar EXAMPLE [1.1.1.1,2.2.2.0/24,![2.2.2.2,2.2.2.3]] alert tcp $EXAMPLE any -> any any (msg:"Example"; sid:1;) alert tcp [1.0.0.0/8,!1.1.1.0/24] any -> any any (msg:"Example";sid:2;) \end{verbatim} The following examples demonstrate some invalid uses of IP variables and IP lists. Use of !any: \begin{verbatim} ipvar EXAMPLE any alert tcp !$EXAMPLE any -> any any (msg:"Example";sid:3;) \end{verbatim} Different use of !any: \begin{verbatim} ipvar EXAMPLE !any alert tcp $EXAMPLE any -> any any (msg:"Example";sid:3;) \end{verbatim} Logical contradictions: \begin{verbatim} ipvar EXAMPLE [1.1.1.1,!1.1.1.1] \end{verbatim} Nonsensical negations: \begin{verbatim} ipvar EXAMPLE [1.1.1.0/24,!1.1.0.0/16] \end{verbatim} \subsubsection{Port Variables and Port Lists} Portlists supports the declaration and lookup of ports and the representation of lists and ranges of ports. Variables, ranges, or lists may all be negated with '!'. Also, 'any' will specify any ports, but '!any' is not allowed. Valid port ranges are from 0 to 65535. Lists of ports must be enclosed in brackets and port ranges may be specified with a ':', such as in: \begin{verbatim} [10:50,888:900] \end{verbatim} Port variables should be specified using 'portvar'. The use of 'var' to declare a port variable will be deprecated in a future release. For backwards compatibility, a 'var' can still be used to declare a port variable, provided the variable name either ends with '\_PORT' or begins with 'PORT\_'. The following examples demonstrate several valid usages of both port variables and port lists. \begin{verbatim} portvar EXAMPLE1 80 var EXAMPLE2_PORT [80:90] var PORT_EXAMPLE2 [1] portvar EXAMPLE3 any portvar EXAMPLE4 [!70:90] portvar EXAMPLE5 [80,91:95,100:200] alert tcp any $EXAMPLE1 -> any $EXAMPLE2_PORT (msg:"Example"; sid:1;) alert tcp any $PORT_EXAMPLE2 -> any any (msg:"Example"; sid:2;) alert tcp any 90 -> any [100:1000,9999:20000] (msg:"Example"; sid:3;) \end{verbatim} Several invalid examples of port variables and port lists are demonstrated below: Use of !any: \begin{verbatim} portvar EXAMPLE5 !any var EXAMPLE5 !any \end{verbatim} Logical contradictions: \begin{verbatim} portvar EXAMPLE6 [80,!80] \end{verbatim} Ports out of range: \begin{verbatim} portvar EXAMPLE7 [65536] \end{verbatim} Incorrect declaration and use of a port variable: \begin{verbatim} var EXAMPLE8 80 alert tcp any $EXAMPLE8 -> any any (msg:"Example"; sid:4;) \end{verbatim} Port variable used as an IP: \begin{verbatim} alert tcp $EXAMPLE1 any -> any any (msg:"Example"; sid:5;) \end{verbatim} \subsubsection{Variable Modifiers} Rule variable names can be modified in several ways. You can define meta-variables using the \$ operator. These can be used with the variable modifier operators {\tt ?} and {\tt -}, as described in the following table: \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Variable Syntax} & \textbf{Description}\\ \hline \hline \texttt{var} & Defines a meta-variable.\\ \hline \texttt{\$(var) or \$var} & Replaces with the contents of variable \texttt{var}.\\ \hline \texttt{\$(var:-default)} & Replaces the contents of the variable \texttt{var} with ``default'' if \texttt{var} is undefined.\\ \hline \texttt{\$(var:?message)} & Replaces with the contents of variable \texttt{var} or prints out the error message and exits.\\ \hline \end{tabular} \end{center} Here is an example of advanced variable usage in action: \begin{verbatim} ipvar MY_NET 192.168.1.0/24 log tcp any any -> $(MY_NET:?MY_NET is undefined!) 23 \end{verbatim} \subsubsection{Limitations} When embedding variables, types can not be mixed. For instance, port variables can be defined in terms of other port variables, but old-style variables (with the 'var' keyword) can not be embedded inside a 'portvar'. Valid embedded variable: \begin{verbatim} portvar pvar1 80 portvar pvar2 [$pvar1,90] \end{verbatim} Invalid embedded variable: \begin{verbatim} var pvar1 80 portvar pvar2 [$pvar1,90] \end{verbatim} Likewise, variables can not be redefined if they were previously defined as a different type. They should be renamed instead: Invalid redefinition: \begin{verbatim} var pvar 80 portvar pvar 90 \end{verbatim} \subsection{Config} \label{Config} Many configuration and command line options of Snort can be specified in the configuration file. \subsubsection{Format} \begin{verbatim} config [: ] \end{verbatim} \newpage \begin{center} \begin{longtable}[t]{| p{2.5in} | p{3.5in} |} \hline {\bf Config Directive} & {\bf Description}\\ \hline % KEEP THESE IN ALPHABETICAL ORDER \hline \texttt{config alert\_with\_interface\_name} & Appends interface name to alert (\texttt{snort -I}). \\ \hline \texttt{config alertfile: } & Sets the alerts output file. \\ \hline \texttt{config asn1: } & Specifies the maximum number of nodes to track when doing ASN1 decoding. See Section \ref{asn1} for more information and examples.\\ \hline \texttt{config autogenerate\_preprocessor\newline \_decoder\_rules} & If Snort was configured to enable decoder and preprocessor rules, this option will cause Snort to revert back to its original behavior of alerting if the decoder or preprocessor generates an event. \\ \hline \texttt{config bpf\_file: } & Specifies BPF filters (\texttt{snort -F}). \\ \hline \texttt{config checksum\_drop: } & Types of packets to drop if invalid checksums. Values: \texttt{none}, \texttt{noip}, \texttt{notcp}, \texttt{noicmp}, \texttt{noudp}, \texttt{ip}, \texttt{tcp}, \texttt{udp}, \texttt{icmp} or \texttt{all} (only applicable in inline mode and for packets checked per \texttt{checksum\_mode} config option). \\ \hline \texttt{config checksum\_mode: } & Types of packets to calculate checksums. Values: \texttt{none}, \texttt{noip}, \texttt{notcp}, \texttt{noicmp}, \texttt{noudp}, \texttt{ip}, \texttt{tcp}, \texttt{udp}, \texttt{icmp} or \texttt{all}. \\ \hline \texttt{config chroot: } & Chroots to specified dir (\texttt{snort -t}). \\ \hline \texttt{config classification: } & See Table \ref{Snort Default Classifications} for a list of classifications.\\ \hline \texttt{config cs\_dir: } & configure snort to provide a Unix socket in the path that can be used to issue commands to the running process. See Section \ref{control_socket} for more details.\\ \hline \texttt{config daemon} & Forks as a daemon (\texttt{snort -D}). \\ \hline \texttt{config decode\_data\_link} & Decodes Layer2 headers (\texttt{snort -e}). \\ \hline \texttt{config default\_rule\_state: } & Global configuration directive to enable or disable the loading of rules into the detection engine. Default (with or without directive) is enabled. Specify \texttt{disabled} to disable loading rules. \\ \hline \texttt{config daq: } & Selects the type of DAQ to instantiate. The DAQ with the highest version of the given type is selected if there are multiple of the same type (this includes any built-in DAQs).\\ \hline \texttt{config daq\_mode: } & Select the DAQ mode: passive, inline, or read-file. Not all DAQs support modes. See the DAQ distro README for possible DAQ modes or list DAQ capabilities for a brief summary. \\ \hline \texttt{config daq\_var: } & Set a DAQ specific variable. Snort just passes this information down to the DAQ. See the DAQ distro README for possible DAQ variables. \\ \hline \texttt{config daq\_dir: } & Tell Snort where to look for available dynamic DAQ modules. This can be repeated. The selected DAQ will be the one with the latest version. \\ \hline \texttt{config daq\_list: []} & Tell Snort to dump basic DAQ capabilities and exit. You can optionally specify a directory to include any dynamic DAQs from that directory. You can also precede this option with extra DAQ directory options to look in multiple directories. \\ \hline \texttt{config decode\_esp: [enable | disable]} & Enable or disable the decoding of Encapsulated Security Protocol (ESP). This is disabled by default. Some networks use ESP for authentication without encryption, allowing their content to be inspected. Encrypted ESP may cause some false positives if this option is enabled.\\ \hline \texttt{config detection: [search-method ]} & Select type of fast pattern matcher algorithm to use. \begin{itemize} \item \texttt{search-method } \begin{itemize} \item Queued match search methods - Matches are queued until the fast pattern matcher is finished with the payload, then evaluated. This was found to generally increase performance through fewer cache misses (evaluating each rule would generally blow away the fast pattern matcher state in the cache). \begin{itemize} \item \texttt{ac} and \texttt{ac-q} - Aho-Corasick Full (high memory, best performance). \item \texttt{ac-bnfa} and \texttt{ac-bnfa-q} - Aho-Corasick Binary NFA (low memory, high performance) \item \texttt{lowmem} and \texttt{lowmem-q} - Low Memory Keyword Trie (low memory, moderate performance) \item \texttt{ac-split} - Aho-Corasick Full with ANY-ANY port group evaluated separately (low memory, high performance). Note this is shorthand for \texttt{search-method ac, split-any-any} \item \texttt{intel-cpm} - Intel CPM library (must have compiled Snort with location of libraries to enable this) \end{itemize} \end{itemize} \begin{itemize} \item No queue search methods - The "nq" option specifies that matches should not be queued and evaluated as they are found. \begin{itemize} \item \texttt{ac-nq} - Aho-Corasick Full (high memory, best performance). \item \texttt{ac-bnfa-nq} - Aho-Corasick Binary NFA (low memory, high performance). This is the default search method if none is specified. \item \texttt{lowmem-nq} - Low Memory Keyword Trie (low memory, moderate performance) \end{itemize} \end{itemize} \begin{itemize} \item Other search methods (the above are considered superior to these) \begin{itemize} \item \texttt{ac-std} - Aho-Corasick Standard (high memory, high performance) \item \texttt{acs} - Aho-Corasick Sparse (high memory, moderate performance) \item \texttt{ac-banded} - Aho-Corasick Banded (high memory, moderate performance) \item \texttt{ac-sparsebands} - Aho-Corasick Sparse-Banded (high memory, moderate performance) \end{itemize} \end{itemize} \end{itemize} \\ \hline \texttt{config detection: [split-any-any] [search-optimize] [max-pattern-len ]} & Other options that affect fast pattern matching. \begin{itemize} \item \texttt{split-any-any} \begin{itemize} \item A memory/performance tradeoff. By default, ANY-ANY port rules are added to every non ANY-ANY port group so that only one port group rule evaluation needs to be done per packet. Not putting the ANY-ANY port rule group into every other port group can significantly reduce the memory footprint of the fast pattern matchers if there are many ANY-ANY port rules. But doing so may require two port group evaluations per packet - one for the specific port group and one for the ANY-ANY port group, thus potentially reducing performance. This option is generic and can be used with any \texttt{search-method} but was specifically intended for use with the \texttt{ac} \texttt{search-method} where the memory footprint is significantly reduced though overall fast pattern performance is better than \texttt{ac-bnfa}. Of note is that the lower memory footprint can also increase performance through fewer cache misses. Default is not to split the ANY-ANY port group. \end{itemize} \item \texttt{search-optimize} \begin{itemize} \item Optimizes fast pattern memory when used with \texttt{search-method} \texttt{ac} or \texttt{ac-split} by dynamically determining the size of a state based on the total number of states. When used with \texttt{ac-bnfa}, some fail-state resolution will be attempted, potentially increasing performance. Default is not to optimize. \end{itemize} \item \texttt{max-pattern-len } \begin{itemize} \item This is a memory optimization that specifies the maximum length of a pattern that will be put in the fast pattern matcher. Patterns longer than this length will be truncated to this length before inserting into the pattern matcher. Useful when there are very long contents being used and truncating the pattern won't diminish the uniqueness of the patterns. Note that this may cause more false positive rule evaluations, i.e. rules that will be evaluated because a fast pattern was matched, but eventually fail, however CPU cache can play a part in performance so a smaller memory footprint of the fast pattern matcher can potentially increase performance. Default is to not set a maximum pattern length. \end{itemize} \end{itemize} \\ \hline \texttt{config detection: [no\_stream\_inserts] [max\_queue\_events ] [enable-single-rule-group] [bleedover-port-limit]} & Other detection engine options. \begin{itemize} \item \texttt{no\_stream\_inserts} \begin{itemize} \item Specifies that stream inserted packets should not be evaluated against the detection engine. This is a potential performance improvement with the idea that the stream rebuilt packet will contain the payload in the inserted one so the stream inserted packet doesn't need to be evaluated. Default is to inspect stream inserts. \end{itemize} \item \texttt{max\_queue\_events } \begin{itemize} \item Specifies the maximum number of matching fast-pattern states to queue per packet. Default is 5 events. \end{itemize} \item \texttt{enable-single-rule-group} \begin{itemize} \item Put all rules into one port group. Not recommended. Default is not to do this. \end{itemize} \item \texttt{bleedover-port-limit} \begin{itemize} \item The maximum number of source or destination ports designated in a rule before the rule is considered an ANY-ANY port group rule. Default is 1024. \end{itemize} \end{itemize} \\ \hline \texttt{config detection: [debug] [debug-print-nocontent-rule-tests] [debug-print-rule-group-build-details] [debug-print-rule-groups-uncompiled] [debug-print-rule-groups-compiled] [debug-print-fast-pattern] [bleedover-warnings-enabled]} & Options for detection engine debugging. \begin{itemize} \item \texttt{debug} \begin{itemize} \item Prints fast pattern information for a particular port group. \end{itemize} \item \texttt{debug-print-nocontent-rule-tests} \begin{itemize} \item Prints port group information during packet evaluation. \end{itemize} \item \texttt{debug-print-rule-group-build-details} \begin{itemize} \item Prints port group information during port group compilation. \end{itemize} \item \texttt{debug-print-rule-groups-uncompiled} \begin{itemize} \item Prints uncompiled port group information. \end{itemize} \item \texttt{debug-print-rule-groups-compiled} \begin{itemize} \item Prints compiled port group information. \end{itemize} \item \texttt{debug-print-fast-pattern} \begin{itemize} \item For each rule with fast pattern content, prints information about the content being used for the fast pattern matcher. \end{itemize} \item \texttt{bleedover-warnings-enabled} \begin{itemize} \item Prints a warning if the number of source or destination ports used in a rule exceed the \texttt{bleedover-port-limit} forcing the rule to be moved into the ANY-ANY port group. \end{itemize} \end{itemize} \\ \hline \texttt{config disable\_decode\_alerts} & Turns off the alerts generated by the decode phase of Snort. \\ \hline \texttt{config disable\_inline\_init\_failopen} & Disables failopen thread that allows inline traffic to pass while Snort is starting up. Only useful if Snort was configured with --enable-inline-init-failopen. (\texttt{snort --disable-inline-init-failopen}) \\ \hline \texttt{config disable\_ipopt\_alerts} & Disables IP option length validation alerts. \\ \hline \texttt{config disable\_tcpopt\_alerts} & Disables option length validation alerts. \\ \hline \texttt{config\newline disable\_tcpopt\_experimental\_alerts} & Turns off alerts generated by experimental TCP options. \\ \hline \texttt{config disable\_tcpopt\_obsolete\_alerts} & Turns off alerts generated by obsolete TCP options. \\ \hline \texttt{config disable\_tcpopt\_ttcp\_alerts} & Turns off alerts generated by T/TCP options. \\ \hline \texttt{config disable\_ttcp\_alerts} & Turns off alerts generated by T/TCP options. \\ \hline \texttt{config dump\_chars\_only} & Turns on character dumps (\texttt{snort -C}). \\ \hline \texttt{config dump\_payload} & Dumps application layer (\texttt{snort -d}). \\ \hline \texttt{config dump\_payload\_verbose} & Dumps raw packet starting at link layer (\texttt{snort -X}). \\ \hline \texttt{config enable\_decode\_drops} & Enables the dropping of bad packets identified by decoder (only applicable in inline mode).\\ \hline \texttt{config enable\_decode\_oversized\_alerts} & Enable alerting on packets that have headers containing length fields for which the value is greater than the length of the packet. \\ \hline \texttt{config enable\_decode\_oversized\_drops} & Enable dropping packets that have headers containing length fields for which the value is greater than the length of the packet. \texttt{enable\_decode\_oversized\_alerts} must also be enabled for this to be effective (only applicable in inline mode). \\ \hline \texttt{config enable\_deep\_teredo\_inspection} & Snort's packet decoder only decodes Teredo (IPv6 over UDP over IPv4) traffic on UDP port 3544. This option makes Snort decode Teredo traffic on all UDP ports. \\ \hline \texttt{config enable\_ipopt\_drops} & Enables the dropping of bad packets with bad/truncated IP options (only applicable in inline mode).\\ \hline \texttt{config enable\_mpls\_multicast} & Enables support for MPLS multicast. This option is needed when the network allows MPLS multicast traffic. When this option is off and MPLS multicast traffic is detected, Snort will generate an alert. By default, it is off.\\ \hline \texttt{config enable\_mpls\_overlapping\_ip} & Enables support for overlapping IP addresses in an MPLS network. In a normal situation, where there are no overlapping IP addresses, this configuration option should not be turned on. However, there could be situations where two private networks share the same IP space and different MPLS labels are used to differentiate traffic from the two VPNs. In such a situation, this configuration option should be turned on. By default, it is off. \\ \hline \texttt{config enable\_tcpopt\_drops} & Enables the dropping of bad packets with bad/truncated TCP option (only applicable in inline mode).\\ \hline \texttt{config\newline enable\_tcpopt\_experimental\_drops} & Enables the dropping of bad packets with experimental TCP option. (only applicable in inline mode).\\ \hline \texttt{config enable\_tcpopt\_obsolete\_drops} & Enables the dropping of bad packets with obsolete TCP option. (only applicable in inline mode).\\ \hline \texttt{config enable\_tcpopt\_ttcp\_drops} & Enables the dropping of bad packets with T/TCP option. (only applicable in inline mode).\\ \hline \texttt{config enable\_ttcp\_drops} & Enables the dropping of bad packets with T/TCP option. (only applicable in inline mode).\\ \hline \texttt{config event\_filter: memcap } & Set global memcap in bytes for thresholding. Default is 1048576 bytes (1 megabyte). \\ \hline \texttt{config event\_queue: [max\_queue ] [log ] [order\_events ]} & Specifies conditions about Snort's event queue. You can use the following options: \begin{itemize} \item \texttt{max\_queue $<$integer$>$} (max events supported) \item \texttt{log $<$integer$>$} (number of events to log) \item \texttt{order\_events [priority$|$content\_length]} (how to order events within the queue) \end{itemize} See Section \ref{eventqueue} for more information and examples.\\ \hline \texttt{config flowbits\_size: } & Specifies the maximum number of flowbit tags that can be used within a rule set. The default is 1024 bits and maximum is 2048. \\ \hline \texttt{config ignore\_ports: } & Specifies ports to ignore (useful for ignoring noisy NFS traffic). Specify the protocol (TCP, UDP, IP, or ICMP), followed by a list of ports. Port ranges are supported.\\ \hline \texttt{config interface: } & Sets the network interface (\texttt{snort -i}). \\ \hline \texttt{config ipv6\_frag: [bsd\_icmp\_frag\_alert on|off] [, bad\_ipv6\_frag\_alert on|off] [, frag\_timeout ] [, max\_frag\_sessions ]} & The following options can be used: \begin{itemize} \item \texttt{bsd\_icmp\_frag\_alert on|off} (Specify whether or not to alert. Default is on) \item \texttt{bad\_ipv6\_frag\_alert on|off} (Specify whether or not to alert. Default is on) \item \texttt{frag\_timeout $<$integer$>$} (Specify amount of time in seconds to timeout first frag in hash table) \item \texttt{max\_frag\_sessions $<$integer$>$} (Specify the number of fragments to track in the hash table) \end{itemize} \\ \hline \texttt{config logdir: } & Sets the logdir (\texttt{snort -l}). \\ \hline \texttt{config log\_ipv6\_extra\_data} & Set Snort to log IPv6 source and destination addresses as unified2 extra data events. \\ \hline \texttt{config max\_attribute\_hosts: } & Sets a limit on the maximum number of hosts to read from the attribute table. Minimum value is 32 and the maximum is 524288 (512k). The default is 10000. If the number of hosts in the attribute table exceeds this value, an error is logged and the remainder of the hosts are ignored. This option is only supported with a Host Attribute Table (see section \ref{targetbased}). \\ \hline \texttt{config max\_attribute\_services\_per\_host: } & Sets a per host limit on the maximum number of services to read from the attribute table. Minimum value is 1 and the maximum is 65535. The default is 100. For a given host, if the number of services in the attribute table exceeds this value, an error is logged and the remainder of the services for that host are ignored. This option is only supported with a Host Attribute Table (see section \ref{targetbased}). \\ \hline \texttt{config max\_mpls\_labelchain\_len: } & Sets a Snort-wide limit on the number of MPLS headers a packet can have. Its default value is -1, which means that there is no limit on label chain length.\\ \hline \texttt{config min\_ttl: } & Sets a Snort-wide minimum ttl to ignore all traffic. \\ \hline \texttt{config mpls\_payload\_type: ipv4|ipv6|ethernet} & Sets a Snort-wide MPLS payload type. In addition to ipv4, ipv6 and ethernet are also valid options. The default MPLS payload type is ipv4\\ \hline \texttt{config no\_promisc} & Disables promiscuous mode (\texttt{snort -p}). \\ \hline \texttt{config nolog} & Disables logging. Note: Alerts will still occur. (\texttt{snort -N}). \\ \hline \texttt{config nopcre} & Disables pcre pattern matching. \\ \hline \texttt{config obfuscate} & Obfuscates IP Addresses (\texttt{snort -O}). \\ \hline \texttt{config order: } & Changes the order that rules are evaluated, e.g.: pass alert log activation. \\ \hline \texttt{config pcre\_match\_limit: $<$integer$>$} & Restricts the amount of backtracking a given PCRE option. For example, it will limit the number of nested repeats within a pattern. A value of -1 allows for unlimited PCRE, up to the PCRE library compiled limit (around 10 million). A value of 0 results in no PCRE evaluation. The snort default value is 1500. \\ \hline \texttt{config pcre\_match\_limit\_recursion: $<$integer$>$} & Restricts the amount of stack used by a given PCRE option. A value of -1 allows for unlimited PCRE, up to the PCRE library compiled limit (around 10 million). A value of 0 results in no PCRE evaluation. The snort default value is 1500. This option is only useful if the value is less than the \texttt{pcre\_match\_limit} \\ \hline \texttt{config pkt\_count: } & Exits after N packets (\texttt{snort -n}). \\ \hline \texttt{config policy\_version: $<$base-version-string$>$ [$<$binding-version-string$>$]} & Supply versioning information to configuration files. Base version should be a string in all configuration files including included ones. In addition, binding version must be in any file configured with \texttt{config binding}. This option is used to avoid race conditions when modifying and loading a configuration within a short time span - before Snort has had a chance to load a previous configuration. \\ \hline \texttt{config profile\_preprocs} & Print statistics on preprocessor performance. See Section \ref{preproc profiling} for more details. \\ \hline \texttt{config profile\_rules} & Print statistics on rule performance. See Section \ref{rule profiling} for more details. \\ \hline \texttt{config quiet}& Disables banner and status reports (\texttt{snort -q}). NOTE: The command line switch \texttt{-q} takes effect immediately after processing the command line parameters, whereas using \texttt{config quiet} in snort.conf takes effect when the configuration line in snort.conf is parsed. That may occur after other configuration settings that result in output to console or syslog. \\ \hline \texttt{config reference: } & Adds a new reference system to Snort, e.g.: myref http://myurl.com/?id=\\ \hline \texttt{config reference\_net } & For IP obfuscation, the obfuscated net will be used if the packet contains an IP address in the reference net. Also used to determine how to set up the logging directory structure for the \texttt{session} post detection rule option and ASCII output plugin - an attempt is made to name the log directories after the IP address that is not in the reference net. \\ \hline \texttt{config response: [attempts ] [, device ]} & Set the number of strafing attempts per injected response and/or the device, such as eth0, from which to send responses. These options may appear in any order but must be comma separated. The are intended for passive mode. \\ \hline \texttt{config set\_gid: } & Changes GID to specified GID (\texttt{snort -g}). \\ \hline \texttt{config set\_uid: } & Sets UID to $<$id$>$ (\texttt{snort -u}). \\ \hline \texttt{config show\_year} & Shows year in timestamps (\texttt{snort -y}). \\ \hline \texttt{config snaplen: } & Set the snaplength of packet, same effect as \texttt{-P $<$snaplen$>$} or \texttt{--snaplen $<$snaplen$>$} options.\\ \hline \texttt{config so\_rule\_memcap: } & Set global memcap in bytes for so rules that dynamically allocate memory for storing session data in the stream preprocessor. A value of 0 disables the memcap. Default is 0. Maximum value is the maximum value an unsigned 32 bit integer can hold which is 4294967295 or 4GB.\\ \hline \texttt{config stateful} & Sets assurance mode for stream (stream is established). \\ \hline \texttt{config tagged\_packet\_limit: } & When a metric other than \texttt{packets} is used in a tag option in a rule, this option sets the maximum number of packets to be tagged regardless of the amount defined by the other metric. See Section \ref{tag section} on using the tag option when writing rules for more details. The default value when this option is not configured is 256 packets. Setting this option to a value of 0 will disable the packet limit. \\ \hline \texttt{config threshold: memcap } & Set global memcap in bytes for thresholding. Default is 1048576 bytes (1 megabyte). (This is deprecated. Use config event\_filter instead.)\\ \hline \texttt{config umask: } & Sets umask when running (\texttt{snort -m}). \\ \hline \texttt{config utc} & Uses UTC instead of local time for timestamps (\texttt{snort -U}). \\ \hline \texttt{config verbose} & Uses verbose logging to STDOUT (\texttt{snort -v}). \\ \hline \texttt{config vlan\_agnostic} & Causes Snort to ignore vlan headers for the purposes of connection and frag tracking. This option is only valid in the base configuration when using multiple configurations, and the default is off. \\ \hline \texttt{config address\_space\_agnostic} & Causes Snort to ignore DAQ address space ID for the purposes of connection and frag tracking. This option is only valid in the base configuration when using multiple configurations, and the default is off. \\ \hline \texttt{config policy\_mode: tap|inline|inline\_test} & Sets the policy mode to either \texttt{passive}, \texttt{inline} or \texttt{inline\_test}. \\ \hline \texttt{config tunnel\_verdicts: gtp|teredo|6in4|4in6} & By default, whitelist and blacklist verdicts are handled internally by Snort for GTP, Teredo, 6in4 and 4in6 encapsulated traffic. This means Snort actually gives the DAQ a pass or block verdict instead. This is to workaround cases where the DAQ would apply the verdict to the whole tunnel instead of the individual session within the tunnel. If your DAQ decodes GTP, Teredo, 6in4 or 4in6 correctly, setting this config will allow the whitelist or blacklist verdict to go to the DAQ. There is a modest performance boost by doing this where possible since Snort won't see the remaining packets on the session. \\ \hline \end{longtable} \end{center} \section{Preprocessors} Preprocessors were introduced in version 1.5 of Snort. They allow the functionality of Snort to be extended by allowing users and programmers to drop modular plugins into Snort fairly easily. Preprocessor code is run before the detection engine is called, but after the packet has been decoded. The packet can be modified or analyzed in an out-of-band manner using this mechanism. Preprocessors are loaded and configured using the {\tt preprocessor} keyword. The format of the preprocessor directive in the Snort config file is: \begin{verbatim} preprocessor : \end{verbatim} \subsection{Frag3} \label{frag3 section} The frag3 preprocessor is a target-based IP defragmentation module for Snort. Frag3 is designed with the following goals: \begin{slist} \item Fast execution with less complex data management. \item Target-based host modeling anti-evasion techniques. \end{slist} Frag3 uses the sfxhash data structure and linked lists for data handling internally which allows it to have much more predictable and deterministic performance in any environment which should aid us in managing heavily fragmented environments. Target-based analysis is a relatively new concept in network-based intrusion detection. The idea of a target-based system is to model the actual targets on the network instead of merely modeling the protocols and looking for attacks within them. When IP stacks are written for different operating systems, they are usually implemented by people who read the RFCs and then write their interpretation of what the RFC outlines into code. Unfortunately, there are ambiguities in the way that the RFCs define some of the edge conditions that may occur and when this happens different people implement certain aspects of their IP stacks differently. For an IDS this is a big problem. In an environment where the attacker can determine what style of IP defragmentation is being used on a particular target, the attacker can try to fragment packets such that the target will put them back together in a specific manner while any passive systems trying to model the host traffic have to guess which way the target OS is going to handle the overlaps and retransmits. As I like to say, if the attacker has more information about the targets on a network than the IDS does, it is possible to evade the IDS. This is where the idea for ``target-based IDS'' came from. For more detail on this issue and how it affects IDS, check out the famous Ptacek \& Newsham paper at \url{http://www.snort.org/docs/idspaper/}. The basic idea behind target-based IDS is that we tell the IDS information about hosts on the network so that it can avoid Ptacek \& Newsham style evasion attacks based on information about how an individual target IP stack operates. Vern Paxson and Umesh Shankar did a great paper on this very topic in 2003 that detailed mapping the hosts on a network and determining how their various IP stack implementations handled the types of problems seen in IP defragmentation and TCP stream reassembly. Check it out at \url{http://www.icir.org/vern/papers/activemap-oak03.pdf}. We can also present the IDS with topology information to avoid TTL-based evasions and a variety of other issues, but that's a topic for another day. Once we have this information we can start to really change the game for these complex modeling problems. Frag3 was implemented to showcase and prototype a target-based module within Snort to test this idea. \subsubsection{Frag 3 Configuration} There are at least two preprocessor directives required to activate frag3, a global configuration directive and an engine instantiation. There can be an arbitrary number of engines defined at startup with their own configuration, but only one global configuration. \textbf{Global Configuration} \begin{itemize} \item Preprocessor name: \texttt{frag3\_global} \item Available options: NOTE: Global configuration options are comma separated. \begin{itemize} \item \texttt{max\_frags $<$number$>$} - Maximum simultaneous fragments to track. Default is 8192. \item \texttt{memcap $<$bytes$>$} - Memory cap for self preservation. Default is 4MB. \item \texttt{prealloc\_memcap $<$bytes$>$} - alternate memory management mode, use preallocated fragment nodes based on a memory cap (faster in some situations). \item \texttt{prealloc\_frags $<$number$>$} - Alternate memory management mode, use preallocated fragment nodes (faster in some situations). \item \texttt{disabled} - This optional keyword is allowed with any policy to avoid packet processing. This option disables the preprocessor for this config, but not for other instances of multiple configurations. Use the disable keyword in the base configuration to specify values for the options \texttt{memcap}, \texttt{prealloc\_memcap}, and \texttt{prealloc\_frags} without having the preprocessor inspect traffic for traffic applying to the base configuration. The other options are parsed but not used. Any valid configuration may have "disabled" added to it. \end{itemize} \end{itemize} \textbf{Engine Configuration} \begin{itemize} \item Preprocessor name: \texttt{frag3\_engine} \item Available options: NOTE: Engine configuration options are space separated. \begin{itemize} \item \texttt{timeout $<$seconds$>$} - Timeout for fragments. Fragments in the engine for longer than this period will be automatically dropped. Default is 60 seconds. \item \texttt{min\_ttl $<$value$>$} - Minimum acceptable TTL value for a fragment packet. Default is 1. The accepted range for this option is 1 - 255. \item \texttt{detect\_anomalies} - Detect fragment anomalies. \item \texttt{bind\_to $<$ip\_list$>$} - IP List to bind this engine to. This engine will only run for packets with destination addresses contained within the IP List. Default value is \texttt{all}. \item \texttt{overlap\_limit } - Limits the number of overlapping fragments per packet. The default is "0" (unlimited). This config option takes values equal to or greater than zero. This is an optional parameter. detect\_anomalies option must be configured for this option to take effect. \item \texttt{min\_fragment\_length } - Defines smallest fragment size (payload size) that should be considered valid. Fragments smaller than or equal to this limit are considered malicious and an event is raised, if detect\_anomalies is also configured. The default is "0" (unlimited), the minimum is "0". This is an optional parameter. detect\_anomalies option must be configured for this option to take effect. \item \texttt{policy $<$type$>$} - Select a target-based defragmentation mode. Available types are first, last, bsd, bsd-right, linux, windows and solaris. Default type is bsd. The Paxson Active Mapping paper introduced the terminology frag3 is using to describe policy types. The known mappings are as follows. Anyone who develops more mappings and would like to add to this list please feel free to send us an email! \begin{tabular}{| l | l |} \hline \textbf{Platform} & \textbf{Type}\\ \hline \hline AIX 2 & BSD \\ \hline AIX 4.3 8.9.3 & BSD \\ \hline Cisco IOS & Last \\ \hline FreeBSD & BSD\\ \hline HP JetDirect (printer) & BSD-right \\ \hline HP-UX B.10.20 & BSD \\ \hline HP-UX 11.00 & First \\ \hline IRIX 4.0.5F & BSD \\ \hline IRIX 6.2 & BSD \\ \hline IRIX 6.3 & BSD \\ \hline IRIX64 6.4 & BSD \\ \hline Linux 2.2.10 & linux \\ \hline Linux 2.2.14-5.0 & linux \\ \hline Linux 2.2.16-3 & linux \\ \hline Linux 2.2.19-6.2.10smp & linux \\ \hline Linux 2.4.7-10 & linux \\ \hline Linux 2.4.9-31SGI 1.0.2smp & linux \\ \hline Linux 2.4 (RedHat 7.1-7.3) & linux \\ \hline MacOS (version unknown) & First \\ \hline NCD Thin Clients & BSD \\ \hline OpenBSD (version unknown) & linux \\ \hline OpenBSD (version unknown) & linux \\ \hline OpenVMS 7.1 & BSD \\ \hline OS/2 (version unknown) & BSD \\ \hline OSF1 V3.0 & BSD \\ \hline OSF1 V3.2 & BSD \\ \hline OSF1 V4.0,5.0,5.1 & BSD \\ \hline SunOS 4.1.4 & BSD \\ \hline SunOS 5.5.1,5.6,5.7,5.8 & First \\ \hline Tru64 Unix V5.0A,V5.1 & BSD \\ \hline Vax/VMS & BSD \\ \hline Windows (95/98/NT4/W2K/XP) & Windows\\ \hline \end{tabular} \end{itemize} \end{itemize} \subsubsection{Format} Note in the advanced configuration below that there are three engines specified running with \emph{Linux}, \texttt{first} and \texttt{last} policies assigned. The first two engines are bound to specific IP address ranges and the last one applies to all other traffic. Packets that don't fall within the address requirements of the first two engines automatically fall through to the third one. \paragraph{Basic Configuration} \begin{verbatim} preprocessor frag3_global preprocessor frag3_engine \end{verbatim} \paragraph{Advanced Configuration} \begin{verbatim} preprocessor frag3_global: prealloc_nodes 8192 preprocessor frag3_engine: policy linux bind_to 192.168.1.0/24 preprocessor frag3_engine: policy first bind_to [10.1.47.0/24,172.16.8.0/24] preprocessor frag3_engine: policy last detect_anomalies \end{verbatim} \subsubsection{Frag 3 Alert Output} \label{frag3 alert output} Frag3 is capable of detecting eight different types of anomalies. Its event output is packet-based so it will work with all output modes of Snort. Read the documentation in the \texttt{doc/signatures} directory with filenames that begin with ``123-'' for information on the different event types. %%Need to doc these eight types of anomalies and truncate beginning of section. \subsection{Stream5} \label{stream5 section} The Stream5 preprocessor is a target-based TCP reassembly module for Snort. It is capable of tracking sessions for both TCP and UDP. With Stream5, the rule 'flow' and 'flowbits' keywords are usable with TCP as well as UDP traffic. \subsubsection{Transport Protocols} TCP sessions are identified via the classic TCP "connection". UDP sessions are established as the result of a series of UDP packets from two end points via the same set of ports. ICMP messages are tracked for the purposes of checking for unreachable and service unavailable messages, which effectively terminate a TCP or UDP session. \subsubsection{Target-Based} Stream5, like Frag3, introduces target-based actions for handling of overlapping data and other TCP anomalies. The methods for handling overlapping data, TCP Timestamps, Data on SYN, FIN and Reset sequence numbers, etc. and the policies supported by Stream5 are the results of extensive research with many target operating systems. \subsubsection{Stream API} Stream5 fully supports the Stream API, other protocol normalizers/preprocessors to dynamically configure reassembly behavior as required by the application layer protocol, identify sessions that may be ignored (large data transfers, etc), and update the identifying information about the session (application protocol, direction, etc) that can later be used by rules. \subsubsection{Anomaly Detection} TCP protocol anomalies, such as data on SYN packets, data received outside the TCP window, etc are configured via the \texttt{detect\_anomalies} option to the TCP configuration. Some of these anomalies are detected on a per-target basis. For example, a few operating systems allow data in TCP SYN packets, while others do not. \subsubsection{Protocol Aware Flushing} Protocol aware flushing of HTTP, SMB and DCE/RPC can be enabled with this option: \begin{verbatim} config paf_max: \end{verbatim} where \texttt{} is between zero (off) and 63780. This allows Snort to statefully scan a stream and reassemble a complete PDU regardless of segmentation. For example, multiple PDUs within a single TCP segment, as well as one PDU spanning multiple TCP segments will be reassembled into one PDU per packet for each PDU. PDUs larger than the configured maximum will be split into multiple packets. \subsubsection{Stream5 Global Configuration} Global settings for the Stream5 preprocessor. \begin{verbatim} preprocessor stream5_global: \ [track_tcp ], [max_tcp ], \ [memcap ], \ [track_udp ], [max_udp ], \ [track_icmp ], [max_icmp ], \ [track_ip ], [max_ip ], \ [flush_on_alert], [show_rebuilt_packets], \ [prune_log_max ], [disabled], \ [flush_on_alert], [show_rebuilt_packets], \ [prune_log_max ], [enable_ha] \end{verbatim} \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{track\_tcp } & Track sessions for TCP. The default is "yes".\\ \hline \texttt{max\_tcp } & Maximum simultaneous TCP sessions tracked. The default is "262144", maximum is "1048576", minimum is "1".\\ \hline \texttt{memcap } & Memcap for TCP packet storage. The default is "8388608" (8MB), maximum is "1073741824" (1GB), minimum is "32768" (32KB).\\ \hline \texttt{track\_udp } & Track sessions for UDP. The default is "yes".\\ \hline \texttt{max\_udp } & Maximum simultaneous UDP sessions tracked. The default is "131072", maximum is "1048576", minimum is "1".\\ \hline \texttt{track\_icmp } & Track sessions for ICMP. The default is "no".\\ \hline \texttt{max\_icmp } & Maximum simultaneous ICMP sessions tracked. The default is "65536", maximum is "1048576", minimum is "1".\\ \hline \texttt{track\_ip } & Track sessions for IP. The default is "no". Note that "IP" includes all non-TCP/UDP traffic over IP including ICMP if ICMP not otherwise configured.\\ \hline \texttt{max\_ip } & Maximum simultaneous IP sessions tracked. The default is "16384", maximum is "1048576", minimum is "1".\\ \hline \texttt{disabled} & Option to disable the stream5 tracking. By default this option is turned off. When the preprocessor is disabled only the options memcap, max\_tcp, max\_udp and max\_icmp are applied when specified with the configuration.\\ \hline \texttt{flush\_on\_alert} & Backwards compatibility. Flush a TCP stream when an alert is generated on that stream. The default is set to off.\\ \hline \texttt{show\_rebuilt\_packets} & Print/display packet after rebuilt (for debugging). The default is set to off.\\ \hline \texttt{prune\_log\_max } & Print a message when a session terminates that was consuming more than the specified number of bytes. The default is "1048576" (1MB), minimum can be either "0" (disabled) or if not disabled the minimum is "1024" and maximum is "1073741824".\\ \hline \texttt{enable\_ha} & Enable High Availability state sharing. The default is set to off.\\ \hline \end{tabular} \end{center} \subsubsection{Stream5 TCP Configuration} Provides a means on a per IP address target to configure TCP policy. This can have multiple occurrences, per policy that is bound to an IP address or network. One default policy must be specified, and that policy is not bound to an IP address or network. \begin{verbatim} preprocessor stream5_tcp: \ [bind_to ], \ [timeout ], [policy ], \ [overlap_limit ], [max_window ], \ [require_3whs []], [detect_anomalies], \ [check_session_hijacking], [use_static_footprint_sizes], \ [dont_store_large_packets], [dont_reassemble_async], \ [max_queued_bytes ], [max_queued_segs ], \ [small_segments bytes [ignore_ports number [number]*]], \ [ports ], \ [protocol ], \ [ignore_any_rules], [flush_factor ] \end{verbatim} \begin{longtable}[h]{| p{2in} | p{4in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{bind\_to } & IP address or network for this policy. The default is set to any.\\ \hline \texttt{timeout } & Session timeout. The default is "30", the minimum is "1", and the maximum is "86400" (approximately 1 day).\\ \hline \texttt{policy } & The Operating System policy for the target OS. The policy\_id can be one of the following: \begin{tabular}{| l | p{2.5in} |} \hline Policy Name & Operating Systems.\\ \hline \hline \texttt{first} & Favor first overlapped segment.\\ \hline \texttt{last} & Favor first overlapped segment.\\ \hline \texttt{bsd} & FresBSD 4.x and newer, NetBSD 2.x and newer, OpenBSD 3.x and newer\\ \hline \texttt{linux} & Linux 2.4 and newer\\ \hline \texttt{old-linux} & Linux 2.2 and earlier\\ \hline \texttt{windows} & Windows 2000, Windows XP, Windows 95/98/ME\\ \hline \texttt{win2003} & Windows 2003 Server\\ \hline \texttt{vista} & Windows Vista\\ \hline \texttt{solaris} & Solaris 9.x and newer\\ \hline \texttt{hpux} & HPUX 11 and newer\\ \hline \texttt{hpux10} & HPUX 10\\ \hline \texttt{irix} & IRIX 6 and newer\\ \hline \texttt{macos} & MacOS 10.3 and newer\\ \hline \end{tabular}\\ \hline \texttt{overlap\_limit } & Limits the number of overlapping packets per session. The default is "0" (unlimited), the minimum is "0", and the maximum is "255".\\ \hline \texttt{max\_window } & Maximum TCP window allowed. The default is "0" (unlimited), the minimum is "0", and the maximum is "1073725440" (65535 left shift 14). That is the highest possible TCP window per RFCs. This option is intended to prevent a DoS against Stream5 by an attacker using an abnormally large window, so using a value near the maximum is discouraged.\\ \hline \texttt{require\_3whs []} & Establish sessions only on completion of a SYN/SYN-ACK/ACK handshake. The default is set to off. The optional number of seconds specifies a startup timeout. This allows a grace period for existing sessions to be considered established during that interval immediately after Snort is started. The default is "0" (don't consider existing sessions established), the minimum is "0", and the maximum is "86400" (approximately 1 day).\\ \hline \texttt{detect\_anomalies} & Detect and alert on TCP protocol anomalies. The default is set to off.\\ \hline \texttt{check\_session\_hijacking} & Check for TCP session hijacking. This check validates the hardware (MAC) address from both sides of the connect -- as established on the 3-way handshake against subsequent packets received on the session. If an ethernet layer is not part of the protocol stack received by Snort, there are no checks performed. Alerts are generated (per '\texttt{detect\_anomalies}' option) for either the client or server when the MAC address for one side or the other does not match. The default is set to off.\\ \hline \texttt{use\_static\_footprint\_sizes} & Use static values for determining when to build a reassembled packet to allow for repeatable tests. This option should not be used production environments. The default is set to off.\\ \hline \texttt{dont\_store\_large\_packets} & Performance improvement to not queue large packets in reassembly buffer. The default is set to off. Using this option may result in missed attacks.\\ \hline \texttt{dont\_reassemble\_async} & Don't queue packets for reassembly if traffic has not been seen in both directions. The default is set to queue packets.\\ \hline \texttt{max\_queued\_bytes } & Limit the number of bytes queued for reassembly on a given TCP session to bytes. Default is "1048576" (1MB). A value of "0" means unlimited, with a non-zero minimum of "1024", and a maximum of "1073741824" (1GB). A message is written to console/syslog when this limit is enforced.\\ \hline \texttt{max\_queued\_segs } & Limit the number of segments queued for reassembly on a given TCP session. The default is "2621", derived based on an average size of 400 bytes. A value of "0" means unlimited, with a non-zero minimum of "2", and a maximum of "1073741824" (1GB). A message is written to console/syslog when this limit is enforced.\\ \hline \texttt{small\_segments bytes [ignore\_ports ]} & Configure the maximum small segments queued. This feature requires that detect\_anomalies be enabled. The first number is the number of consecutive segments that will trigger the detection rule. The default value is "0" (disabled), with a maximum of "2048". The second number is the minimum bytes for a segment to be considered "small". The default value is "0" (disabled), with a maximum of "2048". ignore\_ports is optional, defines the list of ports in which will be ignored for this rule. The number of ports can be up to "65535". A message is written to console/syslog when this limit is enforced.\\ \hline \texttt{ports } & Specify the client, server, or both and list of ports in which to perform reassembly. This can appear more than once in a given config. The default settings are \texttt{ports client 21 23 25 42 53 80 110 111 135 136 137 139 143 445 513 514 1433 1521 2401 3306}. The minimum port allowed is "1" and the maximum allowed is "65535".\\ \hline \texttt{protocol } & Specify the client, server, or both and list of services in which to perform reassembly. This can appear more than once in a given config. The default settings are \texttt{ports client ftp telnet smtp nameserver dns http pop3 sunrpc dcerpc netbios-ssn imap login shell mssql oracle cvs mysql}. The service names can be any of those used in the host attribute table (see \ref{targetbased}), including any of the internal defaults (see \ref{attribute:service names}) or others specific to the network.\\ \hline \texttt{ignore\_any\_rules} & Don't process any \texttt{->} any (ports) rules for TCP that attempt to match payload if there are no port specific rules for the src or destination port. Rules that have flow or flowbits will never be ignored. This is a performance improvement and may result in missed attacks. Using this does not affect rules that look at protocol headers, only those with content, PCRE, or byte test options. The default is "off". This option can be used only in default policy.\\ \hline \texttt{flush\_factor} & Useful in ips mode to flush upon seeing a drop in segment size after N segments of non-decreasing size. The drop in size often indicates an end of request or response.\\ \hline \end{longtable} \begin{note} If no options are specified for a given TCP policy, that is the default TCP policy. If only a bind\_to option is used with no other options that TCP policy uses all of the default values. \end{note} \subsubsection{Stream5 UDP Configuration} Configuration for UDP session tracking. Since there is no target based binding, there should be only one occurrence of the UDP configuration. \begin{verbatim} preprocessor stream5_udp: [timeout ], [ignore_any_rules] \end{verbatim} \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{timeout } & Session timeout. The default is "30", the minimum is "1", and the maximum is "86400" (approximately 1 day).\\ \hline \texttt{ignore\_any\_rules} & Don't process any \texttt{->} any (ports) rules for UDP that attempt to match payload if there are no port specific rules for the src or destination port. Rules that have flow or flowbits will never be ignored. This is a performance improvement and may result in missed attacks. Using this does not affect rules that look at protocol headers, only those with content, PCRE, or byte test options. The default is "off".\\ \hline \end{tabular} \end{center} \begin{note} With the ignore\_any\_rules option, a UDP rule will be ignored except when there is another port specific rule that may be applied to the traffic. For example, if a UDP rule specifies destination port 53, the 'ignored' any \texttt{->} any rule will be applied to traffic to/from port 53, but NOT to any other source or destination port. A list of rule SIDs affected by this option are printed at Snort's startup. \end{note} \begin{note} With the ignore\_any\_rules option, if a UDP rule that uses any \texttt{->} any ports includes either flow or flowbits, the ignore\_any\_rules option is effectively pointless. Because of the potential impact of disabling a flowbits rule, the ignore\_any\_rules option will be disabled in this case. \end{note} \subsubsection{Stream5 ICMP Configuration} Configuration for ICMP session tracking. Since there is no target based binding, there should be only one occurrence of the ICMP configuration. \begin{note} ICMP is currently untested, in minimal code form and is NOT ready for use in production networks. It is not turned on by default. \end{note} \begin{verbatim} preprocessor stream5_icmp: [timeout ] \end{verbatim} \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{timeout } & Session timeout. The default is "30", the minimum is "1", and the maximum is "86400" (approximately 1 day).\\ \hline \end{tabular} \end{center} \subsubsection{Stream5 IP Configuration} Configuration for IP session tracking. Since there is no target based binding, there should be only one occurrence of the IP configuration. \begin{note} "IP" includes all non-TCP/UDP traffic over IP including ICMP if ICMP not otherwise configured. It is not turned on by default. \end{note} \begin{verbatim} preprocessor stream5_ip: [timeout ] \end{verbatim} \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{timeout } & Session timeout. The default is "30", the minimum is "1", and the maximum is "86400" (approximately 1 day).\\ \hline \end{tabular} \end{center} \subsubsection{Stream5 HA Configuration} Configuration for HA session state sharing. \begin{verbatim} preprocessor stream5_ha: [min_session_lifetime ], \ [min_sync_interval ], [startup_input_file ], \ [runtime_output_file ], [use_side_channel] \end{verbatim} \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{min\_session\_lifetime } & Minimum session liftime in milliseconds. HA update messages will only be generated once a session has existed for at least this long. The default is 0, the minimum is 0, and the maximum is 65535.\\ \hline \texttt{min\_sync\_interval } & Minimum synchronization interval in milliseconds. HA update messages will not be generated more often than once per interval on a given session. The default is 0, the minimum is 0, and the maximum is 65535.\\ \hline \texttt{startup\_input\_file } & The name of a file for snort to read HA messages from at startup.\\ \hline \texttt{runtime\_output\_file } & The name of a file to which Snort will write all HA messages that are generated while it is running.\\ \hline \texttt{use\_side\_channel} & Indicates that all HA messages should also be sent to the side channel for processing.\\ \hline \end{tabular} \end{center} \subsubsection{Example Configurations} \begin{enumerate} \item{} This example configuration is the default configuration in snort.conf and can be used for repeatable tests of stream reassembly in readback mode. \begin{verbatim} preprocessor stream5_global: \ max_tcp 8192, track_tcp yes, track_udp yes, track_icmp no preprocessor stream5_tcp: \ policy first, use_static_footprint_sizes preprocessor stream5_udp: \ ignore_any_rules \end{verbatim} \item{} This configuration maps two network segments to different OS policies, one for Windows and one for Linux, with all other traffic going to the default policy of Solaris. \begin{verbatim} preprocessor stream5_global: track_tcp yes preprocessor stream5_tcp: bind_to 192.168.1.0/24, policy windows preprocessor stream5_tcp: bind_to 10.1.1.0/24, policy linux preprocessor stream5_tcp: policy solaris \end{verbatim} \end{enumerate} \subsection{sfPortscan} The sfPortscan module, developed by Sourcefire, is designed to detect the first phase in a network attack: Reconnaissance. In the Reconnaissance phase, an attacker determines what types of network protocols or services a host supports. This is the traditional place where a portscan takes place. This phase assumes the attacking host has no prior knowledge of what protocols or services are supported by the target; otherwise, this phase would not be necessary. As the attacker has no beforehand knowledge of its intended target, most queries sent by the attacker will be negative (meaning that the service ports are closed). In the nature of legitimate network communications, negative responses from hosts are rare, and rarer still are multiple negative responses within a given amount of time. Our primary objective in detecting portscans is to detect and track these negative responses. One of the most common portscanning tools in use today is Nmap. Nmap encompasses many, if not all, of the current portscanning techniques. sfPortscan was designed to be able to detect the different types of scans Nmap can produce. sfPortscan will currently alert for the following types of Nmap scans: \begin{itemize} \item TCP Portscan \item UDP Portscan \item IP Portscan \end{itemize} These alerts are for one$\rightarrow$one portscans, which are the traditional types of scans; one host scans multiple ports on another host. Most of the port queries will be negative, since most hosts have relatively few services available. sfPortscan also alerts for the following types of decoy portscans: \begin{itemize} \item TCP Decoy Portscan \item UDP Decoy Portscan \item IP Decoy Portscan \end{itemize} Decoy portscans are much like the Nmap portscans described above, only the attacker has a spoofed source address inter-mixed with the real scanning address. This tactic helps hide the true identity of the attacker. sfPortscan alerts for the following types of distributed portscans: \begin{itemize} \item TCP Distributed Portscan \item UDP Distributed Portscan \item IP Distributed Portscan \end{itemize} These are many$\rightarrow$one portscans. Distributed portscans occur when multiple hosts query one host for open services. This is used to evade an IDS and obfuscate command and control hosts. \begin{note} Negative queries will be distributed among scanning hosts, so we track this type of scan through the scanned host. \end{note} sfPortscan alerts for the following types of portsweeps: \begin{itemize} \item TCP Portsweep \item UDP Portsweep \item IP Portsweep \item ICMP Portsweep \end{itemize} These alerts are for one$\rightarrow$many portsweeps. One host scans a single port on multiple hosts. This usually occurs when a new exploit comes out and the attacker is looking for a specific service. \begin{note} The characteristics of a portsweep scan may not result in many negative responses. For example, if an attacker portsweeps a web farm for port 80, we will most likely not see many negative responses. \end{note} sfPortscan alerts on the following filtered portscans and portsweeps: \begin{itemize} \item TCP Filtered Portscan \item UDP Filtered Portscan \item IP Filtered Portscan \item TCP Filtered Decoy Portscan \item UDP Filtered Decoy Portscan \item IP Filtered Decoy Portscan \item TCP Filtered Portsweep \item UDP Filtered Portsweep \item IP Filtered Portsweep \item ICMP Filtered Portsweep \item TCP Filtered Distributed Portscan \item UDP Filtered Distributed Portscan \item IP Filtered Distributed Portscan \end{itemize} ``Filtered'' alerts indicate that there were no network errors (ICMP unreachables or TCP RSTs) or responses on closed ports have been suppressed. It's also a good indicator of whether the alert is just a very active legitimate host. Active hosts, such as NATs, can trigger these alerts because they can send out many connection attempts within a very small amount of time. A filtered alert may go off before responses from the remote hosts are received. sfPortscan only generates one alert for each host pair in question during the time window (more on windows below). On TCP scan alerts, sfPortscan will also display any open ports that were scanned. On TCP sweep alerts however, sfPortscan will only track open ports after the alert has been triggered. Open port events are not individual alerts, but tags based on the original scan alert. \subsubsection{sfPortscan Configuration} Use of the Stream5 preprocessor is required for sfPortscan. Stream gives portscan direction in the case of connectionless protocols like ICMP and UDP. You should enable the Stream preprocessor in your \texttt{snort.conf}, as described in Section \ref{stream5 section}. The parameters you can use to configure the portscan module are: \begin{slist} \item \textbf{proto $<$protocol$>$} Available options: \begin{itemize} \item \texttt{TCP} \item \texttt{UDP} \item \texttt{ICMP} \item \texttt{ip\_proto} \item \texttt{all} \end{itemize} \item \textbf{scan\_type $<$scan\_type$>$} Available options: \begin{itemize} \item \texttt{portscan} \item \texttt{portsweep} \item \texttt{decoy\_portscan} \item \texttt{distributed\_portscan} \item \texttt{all} \end{itemize} \item \textbf{sense\_level $<$level$>$} Available options: \begin{itemize} \item \texttt{low} - ``Low'' alerts are only generated on error packets sent from the target host, and because of the nature of error responses, this setting should see very few false positives. However, this setting will never trigger a Filtered Scan alert because of a lack of error responses. This setting is based on a static time window of 60 seconds, after which this window is reset. \item \texttt{medium} - ``Medium'' alerts track connection counts, and so will generate filtered scan alerts. This setting may false positive on active hosts (NATs, proxies, DNS caches, etc), so the user may need to deploy the use of Ignore directives to properly tune this directive. \item \texttt{high} - ``High'' alerts continuously track hosts on a network using a time window to evaluate portscan statistics for that host. A "High" setting will catch some slow scans because of the continuous monitoring, but is very sensitive to active hosts. This most definitely will require the user to tune sfPortscan. \end{itemize} \item \textbf{watch\_ip $<$ip1$|$ip2/cidr[ [port$|$port2-port3]]$>$ } Defines which IPs, networks, and specific ports on those hosts to watch. The list is a comma separated list of IP addresses, IP address using CIDR notation. Optionally, ports are specified after the IP address/CIDR using a space and can be either a single port or a range denoted by a dash. IPs or networks not falling into this range are ignored if this option is used. \item \textbf{ignore\_scanners $<$ip1$|$ip2/cidr[ [port$|$port2-port3]]$>$ } Ignores the source of scan alerts. The parameter is the same format as that of \texttt{watch\_ip}. \item \textbf{ignore\_scanned $<$ip1$|$ip2/cidr[ [port$|$port2-port3]]$>$ } Ignores the destination of scan alerts. The parameter is the same format as that of \texttt{watch\_ip}. \item \textbf{logfile $<$file$>$ } This option will output portscan events to the file specified. If \texttt{file} does not contain a leading slash, this file will be placed in the Snort config dir. \item \textbf{include\_midstream} This option will include sessions picked up in midstream by Stream5. This can lead to false alerts, especially under heavy load with dropped packets; which is why the option is off by default. \item \textbf{detect\_ack\_scans} This option will include sessions picked up in midstream by the stream module, which is necessary to detect ACK scans. However, this can lead to false alerts, especially under heavy load with dropped packets; which is why the option is off by default. \item \textbf{disabled} This optional keyword is allowed with any policy to avoid packet processing. This option disables the preprocessor. When the preprocessor is disabled only the memcap option is applied when specified with the configuration. The other options are parsed but not used. Any valid configuration may have "disabled" added to it. \end{slist} \subsubsection{Format} \begin{verbatim} preprocessor sfportscan: proto \ scan_type \ sense_level \ watch_ip \ ignore_scanners \ ignore_scanned \ logfile \ disabled \end{verbatim} \subsubsection{Example} \begin{verbatim} preprocessor flow: stats_interval 0 hash 2 preprocessor sfportscan:\ proto { all } \ scan_type { all } \ sense_level { low } \end{verbatim} \subsubsection{sfPortscan Alert Output} \paragraph{Unified Output} In order to get all the portscan information logged with the alert, snort generates a pseudo-packet and uses the payload portion to store the additional portscan information of priority count, connection count, IP count, port count, IP range, and port range. The characteristics of the packet are: \begin{verbatim} Src/Dst MAC Addr == MACDAD IP Protocol == 255 IP TTL == 0 \end{verbatim} Other than that, the packet looks like the IP portion of the packet that caused the portscan alert to be generated. This includes any IP options, etc. The payload and payload size of the packet are equal to the length of the additional portscan information that is logged. The size tends to be around 100 - 200 bytes. Open port alerts differ from the other portscan alerts, because open port alerts utilize the tagged packet output system. This means that if an output system that doesn't print tagged packets is used, then the user won't see open port alerts. The open port information is stored in the IP payload and contains the port that is open. The sfPortscan alert output was designed to work with unified2 packet logging, so it is possible to extend favorite Snort GUIs to display portscan alerts and the additional information in the IP payload using the above packet characteristics. \paragraph{Log File Output} Log file output is displayed in the following format, and explained further below: \begin{verbatim} Time: 09/08-15:07:31.603880 event_id: 2 192.168.169.3 -> 192.168.169.5 (portscan) TCP Filtered Portscan Priority Count: 0 Connection Count: 200 IP Count: 2 Scanner IP Range: 192.168.169.3:192.168.169.4 Port/Proto Count: 200 Port/Proto Range: 20:47557 \end{verbatim} If there are open ports on the target, one or more additional tagged packet(s) will be appended: \begin{verbatim} Time: 09/08-15:07:31.603881 event_ref: 2 192.168.169.3 -> 192.168.169.5 (portscan) Open Port Open Port: 38458 \end{verbatim} \begin{slist} \item \textbf{Event\_id/Event\_ref} These fields are used to link an alert with the corresponding \texttt{Open Port} tagged packet \item \textbf{Priority Count} \texttt{Priority Count} keeps track of bad responses (resets, unreachables). The higher the priority count, the more bad responses have been received. \item \textbf{Connection Count} \texttt{Connection Count} lists how many connections are active on the hosts (src or dst). This is accurate for connection-based protocols, and is more of an estimate for others. Whether or not a portscan was filtered is determined here. High connection count and low priority count would indicate filtered (no response received from target). \item \textbf{IP Count} IP Count keeps track of the last IP to contact a host, and increments the count if the next IP is different. For one-to-one scans, this is a low number. For active hosts this number will be high regardless, and one-to-one scans may appear as a distributed scan. \item \textbf{Scanned/Scanner IP Range} This field changes depending on the type of alert. Portsweep (one-to-many) scans display the scanned IP range; Portscans (one-to-one) display the scanner IP. \item \textbf{Port Count} Port Count keeps track of the last port contacted and increments this number when that changes. We use this count (along with IP Count) to determine the difference between one-to-one portscans and one-to-one decoys. \end{slist} \subsubsection{Tuning sfPortscan} \label{tuning sfportscan} The most important aspect in detecting portscans is tuning the detection engine for your network(s). Here are some tuning tips: \begin{slist} \item \textbf{Use the watch\_ip, ignore\_scanners, and ignore\_scanned options.} It's important to correctly set these options. The \texttt{watch\_ip} option is easy to understand. The analyst should set this option to the list of CIDR blocks and IPs that they want to watch. If no \texttt{watch\_ip} is defined, sfPortscan will watch all network traffic. The \texttt{ignore\_scanners} and \texttt{ignore\_scanned} options come into play in weeding out legitimate hosts that are very active on your network. Some of the most common examples are NAT IPs, DNS cache servers, syslog servers, and nfs servers. sfPortscan may not generate false positives for these types of hosts, but be aware when first tuning sfPortscan for these IPs. Depending on the type of alert that the host generates, the analyst will know which to ignore it as. If the host is generating portsweep events, then add it to the \texttt{ignore\_scanners} option. If the host is generating portscan alerts (and is the host that is being scanned), add it to the \texttt{ignore\_scanned} option. \item \textbf{Filtered scan alerts are much more prone to false positives.} When determining false positives, the alert type is very important. Most of the false positives that sfPortscan may generate are of the filtered scan alert type. So be much more suspicious of filtered portscans. Many times this just indicates that a host was very active during the time period in question. If the host continually generates these types of alerts, add it to the \texttt{ignore\_scanners} list or use a lower sensitivity level. \item \textbf{Make use of the Priority Count, Connection Count, IP Count, Port Count, IP Range, and Port Range to determine false positives.} The portscan alert details are vital in determining the scope of a portscan and also the confidence of the portscan. In the future, we hope to automate much of this analysis in assigning a scope level and confidence level, but for now the user must manually do this. The easiest way to determine false positives is through simple ratio estimations. The following is a list of ratios to estimate and the associated values that indicate a legitimate scan and not a false positive. \textbf{Connection Count / IP Count:} This ratio indicates an estimated average of connections per IP. For portscans, this ratio should be high, the higher the better. For portsweeps, this ratio should be low. \textbf{Port Count / IP Count:} This ratio indicates an estimated average of ports connected to per IP. For portscans, this ratio should be high and indicates that the scanned host's ports were connected to by fewer IPs. For portsweeps, this ratio should be low, indicating that the scanning host connected to few ports but on many hosts. \textbf{Connection Count / Port Count:} This ratio indicates an estimated average of connections per port. For portscans, this ratio should be low. This indicates that each connection was to a different port. For portsweeps, this ratio should be high. This indicates that there were many connections to the same port. The reason that \texttt{Priority Count} is not included, is because the priority count is included in the connection count and the above comparisons take that into consideration. The Priority Count play an important role in tuning because the higher the priority count the more likely it is a real portscan or portsweep (unless the host is firewalled). \item \textbf{If all else fails, lower the sensitivity level.} If none of these other tuning techniques work or the analyst doesn't have the time for tuning, lower the sensitivity level. You get the best protection the higher the sensitivity level, but it's also important that the portscan detection engine generate alerts that the analyst will find informative. The low sensitivity level only generates alerts based on error responses. These responses indicate a portscan and the alerts generated by the low sensitivity level are highly accurate and require the least tuning. The low sensitivity level does not catch filtered scans; since these are more prone to false positives. \end{slist} \subsection{RPC Decode} \label{sub:rpc-decoder} The rpc\_decode preprocessor normalizes RPC multiple fragmented records into a single un-fragmented record. It does this by normalizing the packet into the packet buffer. If stream5 is enabled, it will only process client-side traffic. By default, it runs against traffic on ports 111 and 32771. \subsubsection{Format} \begin{verbatim} preprocessor rpc_decode: \ [ alert_fragments ] \ [no_alert_multiple_requests] \ [no_alert_large_fragments] \ [no_alert_incomplete] \end{verbatim} \begin{table}[h] \begin{center} \begin{tabular}{| l | l |} \hline \textbf{Option}& \textbf{Description}\\ \hline \hline \texttt{alert\_fragments}& Alert on any fragmented RPC record.\\ \hline \texttt{no\_alert\_multiple\_requests}& Don't alert when there are multiple records in one packet.\\ \hline \texttt{no\_alert\_large\_fragments}& Don't alert when the sum of fragmented records exceeds one packet.\\ \hline \texttt{no\_alert\_incomplete}& Don't alert when a single fragment record exceeds the size of one packet.\\ \hline \end{tabular} \end{center} \end{table} \subsection{Performance Monitor} \label{sub:perfmonitor} This preprocessor measures Snort's real-time and theoretical maximum performance. Whenever this preprocessor is turned on, it should have an output mode enabled, either ``console'' which prints statistics to the console window or ``file'' with a file name, where statistics get printed to the specified file name. By default, Snort's real-time statistics are processed. This includes: \begin{itemize} \item Time Stamp \item Drop Rate \item Mbits/Sec (wire) [duplicated below for easy comparison with other rates] \item Alerts/Sec \item K-Pkts/Sec (wire) [duplicated below for easy comparison with other rates] \item Avg Bytes/Pkt (wire) [duplicated below for easy comparison with other rates] \item Pat-Matched [percent of data received that Snort processes in pattern matching] \item Syns/Sec \item SynAcks/Sec \item New Sessions Cached/Sec \item Sessions Del fr Cache/Sec \item Current Cached Sessions \item Max Cached Sessions \item Stream Flushes/Sec \item Stream Session Cache Faults \item Stream Session Cache Timeouts \item New Frag Trackers/Sec \item Frag-Completes/Sec \item Frag-Inserts/Sec \item Frag-Deletes/Sec \item Frag-Auto Deletes/Sec [memory DoS protection] \item Frag-Flushes/Sec \item Frag-Current [number of current Frag Trackers] \item Frag-Max [max number of Frag Trackers at any time] \item Frag-Timeouts \item Frag-Faults \item Number of CPUs [*** Only if compiled with LINUX\_SMP ***, the next three appear for each CPU] \item CPU usage (user) \item CPU usage (sys) \item CPU usage (Idle) \item Mbits/Sec (wire) [average mbits of total traffic] \item Mbits/Sec (ipfrag) [average mbits of IP fragmented traffic] \item Mbits/Sec (ipreass) [average mbits Snort injects after IP reassembly] \item Mbits/Sec (tcprebuilt) [average mbits Snort injects after TCP reassembly] \item Mbits/Sec (applayer) [average mbits seen by rules and protocol decoders] \item Avg Bytes/Pkt (wire) \item Avg Bytes/Pkt (ipfrag) \item Avg Bytes/Pkt (ipreass) \item Avg Bytes/Pkt (tcprebuilt) \item Avg Bytes/Pkt (applayer) \item K-Pkts/Sec (wire) \item K-Pkts/Sec (ipfrag) \item K-Pkts/Sec (ipreass) \item K-Pkts/Sec (tcprebuilt) \item K-Pkts/Sec (applayer) \item Total Packets Received \item Total Packets Dropped (not processed) \item Total Packets Blocked (inline) \item Percentage of Packets Dropped \item Total Filtered TCP Packets \item Total Filtered UDP Packets \item Midstream TCP Sessions/Sec \item Closed TCP Sessions/Sec \item Pruned TCP Sessions/Sec \item TimedOut TCP Sessions/Sec \item Dropped Async TCP Sessions/Sec \item TCP Sessions Initializing \item TCP Sessions Established \item TCP Sessions Closing \item Max TCP Sessions (interval) \item New Cached UDP Sessions/Sec \item Cached UDP Ssns Del/Sec \item Current Cached UDP Sessions \item Max Cached UDP Sessions \item Current Attribute Table Hosts (Target Based) \item Attribute Table Reloads (Target Based) \item Mbits/Sec (Snort) \item Mbits/Sec (sniffing) \item Mbits/Sec (combined) \item uSeconds/Pkt (Snort) \item uSeconds/Pkt (sniffing) \item uSeconds/Pkt (combined) \item KPkts/Sec (Snort) \item KPkts/Sec (sniffing) \item KPkts/Sec (combined) \end{itemize} There are over 100 individual statistics included. A header line is output at startup and rollover that labels each column. The following options can be used with the performance monitor: \begin{itemize} \item \texttt{flow} - Prints out statistics about the type and amount of traffic and protocol distributions that Snort is seeing. This option can produce large amounts of output. \item \texttt{flow-file} - Prints \texttt{flow} statistics in a comma-delimited format to the file that is specified. \begin{itemize} \item Timestamp \item Total \% TCP bytes \item Total \% UDP bytes \item Total \% ICMP bytes \item Total \% OTHER bytes \item Number of Packet length entries \item Packet length entries - bytes,\%total \item Number of TCP port flow entries \item TCP port flow entries : port,\%total,\%src,\%dst \item \% TCP high port to high port \item Number of UDP port flow entries \item UDP port flow entries : port,\%total,\%src,\%dst \item \% UDP high port to high port \item Number of ICMP type entries \item ICMP type entries : type,\%total \end{itemize} Specifying this option implicitly enables \texttt{flow} statistics. \item \texttt{events} - Turns on event reporting. This prints out statistics as to the number of rules that were evaluated and didn't match (\textit{non-qualified events}) vs. the number of rules that were evaluated and matched (\textit{qualified events}). A high \textit{non-qualified event} to \textit{qualified event} ratio can indicate there are many rules with either minimal content or no content that are being evaluated without success. The fast pattern matcher is used to select a set of rules for evaluation based on the longest \texttt{content} or a \texttt{content} modified with the \texttt{fast\_pattern} rule option in a rule. Rules with short, generic contents are more likely to be selected for evaluation than those with longer, more unique contents. Rules without \texttt{content} are not filtered via the fast pattern matcher and are always evaluated, so if possible, adding a \texttt{content} rule option to those rules can decrease the number of times they need to be evaluated and improve performance. \item \texttt{max} - Turns on the theoretical maximum performance that Snort calculates given the processor speed and current performance. This is only valid for uniprocessor machines, since many operating systems don't keep accurate kernel statistics for multiple CPUs. \item \texttt{console} - Prints statistics at the console. \item \texttt{file} - Prints statistics in a comma-delimited format to the file that is specified. Not all statistics are output to this file. You may also use \texttt{snortfile} which will output into your defined Snort log directory. Both of these directives can be overridden on the command line with the \texttt{-Z} or \texttt{--perfmon-file} options. At startup, Snort will log a distinctive line to this file with a timestamp to all readers to easily identify gaps in the stats caused by Snort not running. \item \texttt{pktcnt} - Adjusts the number of packets to process before checking for the time sample. This boosts performance, since checking the time sample reduces Snort's performance. By default, this is 10000. \item \texttt{time} - Represents the number of seconds between intervals. \item \texttt{accumulate} or \texttt{reset} - Defines which type of drop statistics are kept by the operating system. By default, \texttt{reset} is used. \item \texttt{atexitonly} - Dump stats for entire life of Snort. One or more of the following arguments can be given to specify specific statistic types to dump at exit: \begin{itemize} \item \texttt{base-stats} \item \texttt{flow-stats} \item \texttt{flow-ip-stats} \item \texttt{events-stats} \end{itemize} Without any arguments, all enabled stats will be dumped only when Snort exits. \item \texttt{max\_file\_size} - Defines the maximum size of the comma-delimited file. Before the file exceeds this size, it will be rolled into a new date stamped file of the format YYYY-MM-DD, followed by YYYY-MM-DD.x, where x will be incremented each time the comma delimited file is rolled over. The minimum is 4096 bytes and the maximum is 2147483648 bytes (2GB). The default is the same as the maximum. \item \texttt{flow-ip} - Collects IP traffic distribution statistics based on host pairs. For each pair of hosts for which IP traffic has been seen, the following statistics are collected for both directions (A to B and B to A): \begin{itemize} \item TCP Packets \item TCP Traffic in Bytes \item TCP Sessions Established \item TCP Sessions Closed \item UDP Packets \item UDP Traffic in Bytes \item UDP Sessions Created \item Other IP Packets \item Other IP Traffic in Bytes \end{itemize} These statistics are printed and reset at the end of each interval. \item \texttt{flow-ip-file} - Prints the flow IP statistics in a comma-delimited format to the file that is specified. All of the statistics mentioned above, as well as the IP addresses of the host pairs in human-readable format, are included. Each line in the file will have its values correspond (in order) to those below: \begin{itemize} \item IP Address A (String) \item IP Address B (String) \item TCP Packets from A to B \item TCP Traffic in Bytes from A to B \item TCP Packets from B to A \item TCP Traffic in Bytes from B to A \item UDP Packets from A to B \item UDP Traffic in Bytes from A to B \item UDP Packets from B to A \item UDP Traffic in Bytes from B to A \item Other IP Packets from A to B \item Other IP Traffic in Bytes from A to B \item Other IP Packets from B to A \item Other IP Traffic in Bytes from B to A \item TCP Sessions Established \item TCP Sessions Closed \item UDP Sessions Created \end{itemize} \item \texttt{flow-ip-memcap} - Sets the memory cap on the hash table used to store IP traffic statistics for host pairs. Once the cap has been reached, the table will start to prune the statistics for the least recently seen host pairs to free memory. This value is in bytes and the default value is 52428800 (50MB). \end{itemize} \subsubsection{Examples} \begin{verbatim} preprocessor perfmonitor: \ time 30 events flow file stats.profile max console pktcnt 10000 preprocessor perfmonitor: \ time 300 file /var/tmp/snortstat pktcnt 10000 preprocessor perfmonitor: \ time 30 flow-ip flow-ip-file flow-ip-stats.csv pktcnt 1000 preprocessor perfmonitor: \ time 30 pktcnt 1000 snortfile base.csv flow-file flows.csv atexitonly flow-stats preprocessor perfmonitor: \ time 30 pktcnt 1000 flow events atexitonly base-stats flow-stats console \end{verbatim} \subsection{HTTP Inspect} \label{sub:http-inspect} HTTP Inspect is a generic HTTP decoder for user applications. Given a data buffer, HTTP Inspect will decode the buffer, find HTTP fields, and normalize the fields. HTTP Inspect works on both client requests and server responses. The current version of HTTP Inspect only handles stateless processing. This means that HTTP Inspect looks for HTTP fields on a packet-by-packet basis, and will be fooled if packets are not reassembled. This works fine when there is another module handling the reassembly, but there are limitations in analyzing the protocol. Future versions will have a stateful processing mode which will hook into various reassembly modules. HTTP Inspect has a very ``rich'' user configuration. Users can configure individual HTTP servers with a variety of options, which should allow the user to emulate any type of web server. Within HTTP Inspect, there are two areas of configuration: global and server. \subsubsection{Global Configuration} The global configuration deals with configuration options that determine the global functioning of HTTP Inspect. The following example gives the generic global configuration format: \subsubsection{Format} \begin{verbatim} preprocessor http_inspect: \ global \ iis_unicode_map \ codemap \ [detect_anomalous_servers] \ [proxy_alert] \ [max_gzip_mem ] \ [compress_depth ] [decompress_depth ] \ [memcap ] \ disabled \end{verbatim} You can only have a single global configuration, you'll get an error if you try otherwise. \paragraph{Configuration} \begin{slist} \item \texttt{iis\_unicode\_map $<$map\_filename$>$ [codemap $<$integer$>$]} This is the global \texttt{iis\_unicode\_map} file. The \texttt{iis\_unicode\_map} is a required configuration parameter. The map file can reside in the same directory as \texttt{snort.conf} or be specified via a fully-qualified path to the map file. The \texttt{iis\_unicode\_map} file is a Unicode codepoint map which tells HTTP Inspect which codepage to use when decoding Unicode characters. For US servers, the codemap is usually 1252. A Microsoft US Unicode codepoint map is provided in the Snort source \texttt{etc} directory by default. It is called \texttt{unicode.map} and should be used if no other codepoint map is available. A tool is supplied with Snort to generate custom Unicode \texttt{maps--ms\_unicode\_generator.c}, which is available at \url{http://www.snort.org/dl/contrib/}. \begin{note} Remember that this configuration is for the global IIS Unicode map, individual servers can reference their own IIS Unicode map. \end{note} \item \texttt{detect\_anomalous\_servers} This global configuration option enables generic HTTP server traffic inspection on non-HTTP configured ports, and alerts if HTTP traffic is seen. Don't turn this on if you don't have a default server configuration that encompasses all of the HTTP server ports that your users might access. In the future, we want to limit this to specific networks so it's more useful, but for right now, this inspects all network traffic. This option is turned off by default. \item \texttt{proxy\_alert} This enables global alerting on HTTP server proxy usage. By configuring HTTP Inspect servers and enabling \texttt{allow\_proxy\_use}, you will only receive proxy use alerts for web users that aren't using the configured proxies or are using a rogue proxy server. Please note that if users aren't required to configure web proxy use, then you may get a lot of proxy alerts. So, please only use this feature with traditional proxy environments. Blind firewall proxies don't count. \item \texttt{compress\_depth $<$integer$>$} This option specifies the maximum amount of packet payload to decompress. This value can be set from 1 to 65535. The default for this option is 1460. \begin{note} Please note, in case of multiple policies, the value specified in the default policy is used and this value overwrites the values specified in the other policies. In case of \texttt{unlimited\_decompress} this should be set to its max value. This value should be specified in the default policy even when the HTTP inspect preprocessor is turned off using the \texttt{disabled} keyword. \end{note} \item \texttt{decompress\_depth $<$integer$>$} This option specifies the maximum amount of decompressed data to obtain from the compressed packet payload. This value can be set from 1 to 65535. The default for this option is 2920. \begin{note} Please note, in case of multiple policies, the value specified in the default policy is used and this value overwrites the values specified in the other policies. In case of \texttt{unlimited\_decompress} this should be set to its max value. This value should be specified in the default policy even when the HTTP inspect preprocessor is turned off using the \texttt{disabled} keyword. \end{note} \item \texttt{max\_gzip\_mem $<$integer$>$} This option determines (in bytes) the maximum amount of memory the HTTP Inspect preprocessor will use for decompression. The minimum allowed value for this option is 3276 bytes. This option determines the number of concurrent sessions that can be decompressed at any given instant. The default value for this option is 838860. \begin{note} This value should be specified in the default policy even when the HTTP inspect preprocessor is turned off using the \texttt{disabled} keyword. \end{note} \item \texttt{memcap $<$integer$>$} This option determines (in bytes) the maximum amount of memory the HTTP Inspect preprocessor will use for logging the URI and Hostname data. This value can be set from 2304 to 603979776 (576 MB). This option along with the maximum uri and hostname logging size (which is defined in snort) will determine the maximum HTTP sessions that will log the URI and hostname data at any given instant. The maximum size for logging URI data is 2048 and for hostname is 256. The default value for this option is 150994944 (144 MB). \begin {note} This value should be specified in the default policy even when the HTTP inspect preprocessor is turned off using the \texttt{disabled} keyword. In case of multiple policies, the value specified in the default policy will overwrite the value specified in other policies. max http sessions logged = memcap /( max uri logging size + max hostname logging size ) max uri logging size defined in snort : 2048 max hostname logging size defined in snort : 256 \end{note} \item \texttt{disabled} This optional keyword is allowed with any policy to avoid packet processing. This option disables the preprocessor. When the preprocessor is disabled only the "memcap", "max\_gzip\_mem", "compress\_depth" and "decompress\_depth" options are applied when specified with the configuration. Other options are parsed but not used. Any valid configuration may have "disabled" added to it. \end{slist} \subsubsection{Example Global Configuration} \begin{verbatim} preprocessor http_inspect: \ global iis_unicode_map unicode.map 1252 \end{verbatim} \subsubsection{Server Configuration} There are two types of server configurations: default and by IP address. \paragraph{Default} This configuration supplies the default server configuration for any server that is not individually configured. Most of your web servers will most likely end up using the default configuration. \subsubsection{Example Default Configuration} \begin{verbatim} preprocessor http_inspect_server: \ server default profile all ports { 80 } \end{verbatim} \paragraph{Configuration by IP Address} This format is very similar to ``default'', the only difference being that specific IPs can be configured. \subsubsection{Example IP Configuration} \begin{verbatim} preprocessor http_inspect_server: \ server 10.1.1.1 profile all ports { 80 } \end{verbatim} \paragraph{Configuration by Multiple IP Addresses} This format is very similar to ``Configuration by IP Address'', the only difference being that multiple IPs can be specified via a space separated list. There is a limit of 40 IP addresses or CIDR notations per \texttt{http\_inspect\_server} line. \subsubsection{Example Multiple IP Configuration} \begin{verbatim} preprocessor http_inspect_server: \ server { 10.1.1.1 10.2.2.0/24 } profile all ports { 80 } \end{verbatim} \subsubsection{Server Configuration Options} Important: Some configuration options have an argument of `yes' or `no'. This argument specifies whether the user wants the configuration option to generate an HTTP Inspect alert or not. The `yes/no' argument does not specify whether the configuration option itself is on or off, only the alerting functionality. In other words, whether set to `yes' or 'no', HTTP normalization will still occur, and rules based on HTTP traffic will still trigger. \begin{slist} \item \texttt{profile $<$all$|$apache$|$iis$|$iis5\_0$|$iis4\_0$>$} Users can configure HTTP Inspect by using pre-defined HTTP server profiles. Profiles allow the user to easily configure the preprocessor for a certain type of server, but are not required for proper operation. There are five profiles available: all, apache, iis, iis5\_0, and iis4\_0. \begin{subslist} \item \texttt{all} The \texttt{all} profile is meant to normalize the URI using most of the common tricks available. We alert on the more serious forms of evasions. This is a great profile for detecting all types of attacks, regardless of the HTTP server. \texttt{profile all} sets the configuration options described in Table \ref{profile_all_options}. \begin{table}[h] \begin{center} \caption{Options for the ``all'' Profile} \label{profile_all_options} \begin{tabular}{| l | p{3in} |} \hline \textbf{Option} & \textbf{Setting} \\ \hline \hline server\_flow\_depth & 300 \\ \hline client\_flow\_depth & 300 \\ \hline post\_depth & 0 \\ \hline chunk encoding & alert on chunks larger than 500000 bytes \\ \hline iis\_unicode\_map & codepoint map in the global configuration \\ \hline ASCII decoding & on, alert off \\ \hline multiple slash & on, alert off \\ \hline directory normalization & on, alert off \\ \hline apache whitespace & on, alert off \\ \hline double decoding & on, alert on \\ \hline \%u decoding & on, alert on \\ \hline bare byte decoding & on, alert on \\ \hline iis unicode codepoints & on, alert on \\ \hline iis backslash & on, alert off \\ \hline iis delimiter & on, alert off \\ \hline webroot & on, alert on\\ \hline non\_strict URL parsing & on\\ \hline tab\_uri\_delimiter & is set\\ \hline max\_header\_length & 0, header length not checked\\ \hline max\_spaces & 200 \\ \hline max\_headers & 0, number of headers not checked\\ \hline \end{tabular} \end{center} \end{table} \item \texttt{apache} The \texttt{apache} profile is used for Apache web servers. This differs from the \texttt{iis} profile by only accepting UTF-8 standard Unicode encoding and not accepting backslashes as legitimate slashes, like IIS does. Apache also accepts tabs as whitespace. \texttt{profile apache} sets the configuration options described in Table \ref{profile_apache_options}. \begin{table}[h] \begin{center} \caption{Options for the \texttt{apache} Profile} \label{profile_apache_options} \begin{tabular}{| l | p{3in} |} \hline \textbf{Option} & \textbf{Setting}\\ \hline \hline server\_flow\_depth & 300 \\ \hline client\_flow\_depth & 300 \\ \hline post\_depth & 0 \\ \hline chunk encoding & alert on chunks larger than 500000 bytes \\ \hline ASCII decoding & on, alert off \\ \hline multiple slash & on, alert off \\ \hline directory normalization & on, alert off \\ \hline webroot & on, alert on\\ \hline apache whitespace & on, alert on \\ \hline utf\_8 encoding & on, alert off \\ \hline non\_strict url parsing & on \\ \hline tab\_uri\_delimiter & is set\\ \hline max\_header\_length & 0, header length not checked\\ \hline max\_spaces & 200 \\ \hline max\_headers & 0, number of headers not checked\\ \hline \hline \end{tabular} \end{center} \end{table} \item \texttt{iis} The \texttt{iis} profile mimics IIS servers. So that means we use IIS Unicode codemaps for each server, \%u encoding, bare-byte encoding, double decoding, backslashes, etc. \texttt{profile iis} sets the configuration options described in Table \ref{profile_iis_options}. \begin{table}[h] \begin{center} \caption{Options for the \texttt{iis} Profile} \label{profile_iis_options} \begin{tabular}{| l | p{3in} |} \hline \textbf{Option} & \textbf{Setting}\\ \hline \hline server\_flow\_depth & 300 \\ \hline client\_flow\_depth & 300 \\ \hline post\_depth & -1 \\ \hline chunk encoding & alert on chunks larger than 500000 bytes\\ \hline iis\_unicode\_map & codepoint map in the global configuration \\ \hline ASCII decoding & on, alert off \\ \hline multiple slash & on, alert off \\ \hline directory normalization & on, alert off \\ \hline webroot & on, alert on\\ \hline double decoding & on, alert on \\ \hline \%u decoding & on, alert on \\ \hline bare byte decoding & on, alert on \\ \hline iis unicode codepoints & on, alert on \\ \hline iis backslash & on, alert off \\ \hline iis delimiter & on, alert on \\ \hline apache whitespace & on, alert on \\ \hline non\_strict URL parsing & on\\ \hline max\_header\_length & 0, header length not checked\\ \hline max\_spaces & 200 \\ \hline max\_headers & 0, number of headers not checked\\ \hline \end{tabular} \end{center} \end{table} \item \texttt{iis4\_0, iis5\_0} In IIS 4.0 and IIS 5.0, there was a double decoding vulnerability. These two profiles are identical to \texttt{iis}, except they will alert by default if a URL has a double encoding. Double decode is not supported in IIS 5.1 and beyond, so it's disabled by default. \item \texttt{default, no profile} The default options used by HTTP Inspect do not use a profile and are described in Table \ref{default_HTTP_Inspect_options}. \begin{table}[h] \begin{center} \caption{Default HTTP Inspect Options} \label{default_HTTP_Inspect_options} \begin{tabular}{| l | p{3in} |} \hline \textbf{Option} & \textbf{Setting}\\ \hline \hline port & 80\\ \hline server\_flow\_depth & 300 \\ \hline client\_flow\_depth & 300 \\ \hline post\_depth & -1 \\ \hline chunk encoding & alert on chunks larger than 500000 bytes\\ \hline ASCII decoding & on, alert off \\ \hline utf\_8 encoding & on, alert off\\ \hline multiple slash & on, alert off \\ \hline directory normalization & on, alert off \\ \hline webroot & on, alert on\\ \hline iis backslash & on, alert off \\ \hline apache whitespace & on, alert off \\ \hline iis delimiter & on, alert off \\ \hline non\_strict URL parsing & on\\ \hline max\_header\_length & 0, header length not checked\\ \hline max\_spaces & 200 \\ \hline max\_headers & 0, number of headers not checked\\ \hline \end{tabular} \end{center} \end{table} Profiles must be specified as the first server option and cannot be combined with any other options except: \begin{itemize} \item \texttt{ports} \item \texttt{iis\_unicode\_map} \item \texttt{allow\_proxy\_use} \item \texttt{server\_flow\_depth} \item \texttt{client\_flow\_depth} \item \texttt{post\_depth} \item \texttt{no\_alerts} \item \texttt{inspect\_uri\_only} \item \texttt{oversize\_dir\_length} \item \texttt{normalize\_headers} \item \texttt{normalize\_cookies} \item \texttt{normalize\_utf} \item \texttt{max\_header\_length} \item \texttt{max\_spaces} \item \texttt{max\_headers} \item \texttt{extended\_response\_inspection} \item \texttt{enable\_cookie} \item \texttt{inspect\_gzip} \item \texttt{unlimited\_decompress} \item \texttt{normalize\_javascript} \item \texttt{max\_javascript\_whitespaces} \item \texttt{enable\_xff} \item \texttt{http\_methods} \item \texttt{log\_uri} \item \texttt{log\_hostname} \item \texttt{small\_chunk\_length} \end{itemize} These options must be specified after the \texttt{profile} option. \end{subslist} \subsubsection{Example} \begin{verbatim} preprocessor http_inspect_server: \ server 1.1.1.1 profile all ports { 80 3128 } \end{verbatim} \item \texttt{ports $\{ <$port$> [<$port$> <...>] \}$} This is how the user configures which ports to decode on the HTTP server. However, HTTPS traffic is encrypted and cannot be decoded with HTTP Inspect. To ignore HTTPS traffic, use the SSL preprocessor. \item \texttt{iis\_unicode\_map $<$map\_filename$>$ codemap $<$integer$>$} The IIS Unicode map is generated by the program ms\_unicode\_generator.c. This program is located on the Snort.org web site at \url{http://www.snort.org/dl/contrib/} directory. Executing this program generates a Unicode map for the system that it was run on. So, to get the specific Unicode mappings for an IIS web server, you run this program on that server and use that Unicode map in this configuration. When using this option, the user needs to specify the file that contains the IIS Unicode map and also specify the Unicode map to use. For US servers, this is usually 1252. But the ms\_unicode\_generator program tells you which codemap to use for you server; it's the ANSI code page. You can select the correct code page by looking at the available code pages that the ms\_unicode\_generator outputs. \item \texttt{extended\_response\_inspection} This enables the extended HTTP response inspection. The default http response inspection does not inspect the various fields of a HTTP response. By turning this option the HTTP response will be thoroughly inspected. The different fields of a HTTP response such as status code, status message, headers, cookie (when enable\_cookie is configured) and body are extracted and saved into buffers. Different rule options are provided to inspect these buffers. \begin{note} When this option is turned on, if the HTTP response packet has a body then any content pattern matches ( without http modifiers ) will search the response body ((decompressed in case of gzip) and not the entire packet payload. To search for patterns in the header of the response, one should use the http modifiers with content such as \texttt{http\_header}, \texttt{http\_stat\_code}, \texttt{http\_stat\_msg} and \texttt{http\_cookie}. \end{note} \item \texttt{enable\_cookie} This options turns on the cookie extraction from HTTP requests and HTTP response. By default the cookie inspection and extraction will be turned off. The cookie from the \texttt{Cookie} header line is extracted and stored in HTTP Cookie buffer for HTTP requests and cookie from the \texttt{Set-Cookie} is extracted and stored in HTTP Cookie buffer for HTTP responses. The \texttt{Cookie:} and \texttt{Set-Cookie:} header names itself along with leading spaces and the CRLF terminating the header line are stored in the HTTP header buffer and are not stored in the HTTP cookie buffer. \begin{verbatim} Ex: Set-Cookie: mycookie \r\n In this case, Set-Cookie: \r\n will be in the HTTP header buffer and the pattern mycookie will be in the HTTP cookie buffer. \end{verbatim} \item \texttt{inspect\_gzip} This option specifies the HTTP inspect module to uncompress the compressed data(gzip/deflate) in HTTP response. You should select the config option "extended\_response\_inspection" before configuring this option. Decompression is done across packets. So the decompression will end when either the 'compress\_depth' or 'decompress\_depth' is reached or when the compressed data ends. When the compressed data is spanned across multiple packets, the state of the last decompressed packet is used to decompressed the data of the next packet. But the decompressed data are individually inspected. (i.e. the decompressed data from different packets are not combined while inspecting). Also the amount of decompressed data that will be inspected depends on the 'server\_flow\_depth' configured. Http Inspect generates a preprocessor alert with gid 120 and sid 6 when the decompression fails. When the decompression fails due to a CRC error encountered by zlib, HTTP Inspect will also provide the detection module with the data that was decompressed by zlib. \begin{note} To enable compression of HTTP server response, Snort should be configured with the --enable-zlib flag. \end{note} \item \texttt{unlimited\_decompress} This option enables the user to decompress unlimited gzip data (across multiple packets).Decompression will stop when the compressed data ends or when a out of sequence packet is received. To ensure unlimited decompression, user should set the 'compress\_depth' and 'decompress\_depth' to its maximum values in the default policy. The decompression in a single packet is still limited by the 'compress\_depth' and 'decompress\_depth'. \item \texttt{normalize\_javascript} This option enables the normalization of Javascript within the HTTP response body. You should select the config option \texttt{extended\_response\_inspection} before configuring this option. When this option is turned on, Http Inspect searches for a Javascript within the HTTP response body by searching for the $<$script$>$ tags and starts normalizing it. When Http Inspect sees the $<$script$>$ tag without a type, it is considered as a javascript. The obfuscated data within the javascript functions such as unescape, String.fromCharCode, decodeURI, decodeURIComponent will be normalized. The different encodings handled within the unescape/ decodeURI/decodeURIComponent are \texttt{\%XX}, \texttt{\%uXXXX}, \texttt{\\XX} and \texttt{\\uXXXXi}. Apart from these encodings, Http Inspect will also detect the consecutive whitespaces and normalize it to a single space. Http Inspect will also normalize the plus and concatenate the strings. The rule option \texttt{file\_data} can be used to access this normalized buffer from the rule. A preprocessor alert with SID 9 and GID 120 is generated when the obfuscation levels within the Http Inspect is equal to or greater than 2. \begin{verbatim} Example: HTTP/1.1 200 OK\r\n Date: Wed, 29 Jul 2009 13:35:26 GMT\r\n Server: Apache/2.2.3 (Debian) PHP/5.2.0-8+etch10 mod_ssl/2.2.3 OpenSSL/0.9.8c\r\n Last-Modified: Sun, 20 Jan 2008 12:01:21 GMT\r\n Accept-Ranges: bytes\r\n Content-Length: 214\r\n Keep-Alive: timeout=15, max=99\r\n Connection: Keep-Alive\r\n Content-Type: application/octet-stream\r\n\r\n FIXME \end{verbatim} The above javascript will generate the preprocessor alert with SID 9 and GIDF 120 when \texttt{normalize\_javascript} is turned on. Http Inspect will also generate a preprocessor alert with GID 120 and SID 11 when there are more than one type of encodings within the escaped/encoded data. \begin{verbatim} For example: unescape("%48\x65%6C%6C%6F%2C%20%73%6E%6F%72%74%20%74%65%61%6D%21"); String.fromCharCode(0x48, 0x65, 0x6c, 0x6c, 111, 44, 32, 115, 110, 111, 114, 116, 32, 116, 101, 97, 109, 33) \\end{verbatim} The above obfuscation will generate the preprocessor alert with GID 120 and SID 11. This option is turned off by default in HTTP Inspect. \item \texttt{max\_javascript\_whitespaces $<$positive integer up to 65535$>$} This option takes an integer as an argument. The integer determines the maximum number of consecutive whitespaces allowed within the Javascript obfuscated data in a HTTP response body. The config option \texttt{normalize\_javascript} should be turned on before configuring this config option. When the whitespaces in the javascript obfuscated data is equal to or more than this value a preprocessor alert with GID 120 and SID 10 is generated. The default value for this option is 200. To enable, specify an integer argument to \texttt{max\_javascript\_spaces} of 1 to 65535. Specifying a value of 0 is treated as disabling the alert. \item \texttt{enable\_xff} This option enables Snort to parse and log the original client IP present in the X-Forwarded-For or True-Client-IP HTTP request headers along with the generated events. The XFF/True-Client-IP Original client IP address is logged only with unified2 output and is not logged with console (-A cmg) output. \begin{note} The original client IP from XFF/True-Client-IP in unified2 logs can be viewed using the tool u2spewfoo. This tool is present in the tools/u2spewfoo directory of snort source tree. \end{note} \item \texttt{server\_flow\_depth $<$integer$>$} This specifies the amount of server response payload to inspect. When \texttt{extended\_response\_inspection} is turned on, it is applied to the HTTP response body (decompressed data when \texttt{inspect\_gzip} is turned on) and not the HTTP headers. When \texttt{extended\_response\_inspection} is turned off the \texttt{server\_flow\_depth} is applied to the entire HTTP response (including headers). Unlike \texttt{client\_flow\_depth} this option is applied per TCP session. This option can be used to balance the needs of IDS performance and level of inspection of HTTP server response data. Snort rules are targeted at HTTP server response traffic and when used with a small flow\_depth value may cause false negatives. Most of these rules target either the HTTP header, or the content that is likely to be in the first hundred or so bytes of non-header data. Headers are usually under 300 bytes long, but your mileage may vary. It is suggested to set the \texttt{server\_flow\_depth} to its maximum value. This value can be set from -1 to 65535. A value of -1 causes Snort to ignore all server side traffic for ports defined in \texttt{ports} when \texttt{extended\_response\_inspection} is turned off. When the \texttt{extended\_response\_inspection} is turned on, value of -1 causes Snort to ignore the HTTP response body data and not the HTTP headers. Inversely, a value of 0 causes Snort to inspect all HTTP server payloads defined in "ports" (note that this will likely slow down IDS performance). Values above 0 tell Snort the number of bytes to inspect of the server response (excluding the HTTP headers when \texttt{extended\_response\_inspection} is turned on) in a given HTTP session. Only packets payloads starting with 'HTTP' will be considered as the first packet of a server response. If less than flow\_depth bytes are in the payload of the HTTP response packets in a given session, the entire payload will be inspected. If more than flow\_depth bytes are in the payload of the HTTP response packet in a session only flow\_depth bytes of the payload will be inspected for that session. Rules that are meant to inspect data in the payload of the HTTP response packets in a session beyond 65535 bytes will be ineffective unless flow\_depth is set to 0. The default value for \texttt{server\_flow\_depth} is 300. Note that the 65535 byte maximum flow\_depth applies to stream reassembled packets as well. It is suggested to set the \texttt{server\_flow\_depth} to its maximum value. \begin{note} \texttt{server\_flow\_depth} is the same as the old \texttt{flow\_depth} option, which will be deprecated in a future release. \end{note} \item \texttt{client\_flow\_depth $<$integer$>$} This specifies the amount of raw client request payload to inspect. This value can be set from -1 to 1460. Unlike \texttt{server\_flow\_depth} this value is applied to the first packet of the HTTP request. It is not a session based flow depth. It has a default value of 300. It primarily eliminates Snort from inspecting larger HTTP Cookies that appear at the end of many client request Headers. A value of -1 causes Snort to ignore all client side traffic for ports defined in "ports." Inversely, a value of 0 causes Snort to inspect all HTTP client side traffic defined in "ports" (note that this will likely slow down IDS performance). Values above 0 tell Snort the number of bytes to inspect in the first packet of the client request. If less than flow\_depth bytes are in the TCP payload (HTTP request) of the first packet, the entire payload will be inspected. If more than flow\_depth bytes are in the payload of the first packet only flow\_depth bytes of the payload will be inspected. Rules that are meant to inspect data in the payload of the first packet of a client request beyond 1460 bytes will be ineffective unless flow\_depth is set to 0. Note that the 1460 byte maximum flow\_depth applies to stream reassembled packets as well. It is suggested to set the \texttt{client\_flow\_depth} to its maximum value. \item \texttt{post\_depth $<$integer$>$} This specifies the amount of data to inspect in a client post message. The value can be set from -1 to 65495. The default value is -1. A value of -1 causes Snort to ignore all the data in the post message. Inversely, a value of 0 causes Snort to inspect all the client post message. This increases the performance by inspecting only specified bytes in the post message. \item \texttt{ascii $<$yes$|$no$>$} The \texttt{ascii} decode option tells us whether to decode encoded ASCII chars, a.k.a \%2f = /, \%2e = ., etc. It is normal to see ASCII encoding usage in URLs, so it is recommended that you disable HTTP Inspect alerting for this option. \item \texttt{extended\_ascii\_uri} This option enables the support for extended ASCII codes in the HTTP request URI. This option is turned off by default and is not supported with any of the profiles. \item \texttt{utf\_8 $<$yes$|$no$>$} The \texttt{utf-8} decode option tells HTTP Inspect to decode standard UTF-8 Unicode sequences that are in the URI. This abides by the Unicode standard and only uses \% encoding. Apache uses this standard, so for any Apache servers, make sure you have this option turned on. As for alerting, you may be interested in knowing when you have a UTF-8 encoded URI, but this will be prone to false positives as legitimate web clients use this type of encoding. When \texttt{utf\_8} is enabled, ASCII decoding is also enabled to enforce correct functioning. \item \texttt{u\_encode $<$yes$|$no$>$} This option emulates the IIS \%u encoding scheme. How the \%u encoding scheme works is as follows: the encoding scheme is started by a \%u followed by 4 characters, like \%uxxxx. The xxxx is a hex-encoded value that correlates to an IIS Unicode codepoint. This value can most definitely be ASCII. An ASCII character is encoded like \%u002f = /, \%u002e = ., etc. If no iis\_unicode\_map is specified before or after this option, the default codemap is used. You should alert on \%u encodings, because we are not aware of any legitimate clients that use this encoding. So it is most likely someone trying to be covert. \item \texttt{bare\_byte $<$yes$|$no$>$} Bare byte encoding is an IIS trick that uses non-ASCII characters as valid values when decoding UTF-8 values. This is not in the HTTP standard, as all non-ASCII values have to be encoded with a \%. Bare byte encoding allows the user to emulate an IIS server and interpret non-standard encodings correctly. The alert on this decoding should be enabled, because there are no legitimate clients that encode UTF-8 this way since it is non-standard. \item \texttt{iis\_unicode $<$yes$|$no$>$} The \texttt{iis\_unicode} option turns on the Unicode codepoint mapping. If there is no iis\_unicode\_map option specified with the server config, \texttt{iis\_unicode} uses the default codemap. The \texttt{iis\_unicode} option handles the mapping of non-ASCII codepoints that the IIS server accepts and decodes normal UTF-8 requests. You should alert on the \texttt{iis\_unicode option}, because it is seen mainly in attacks and evasion attempts. When \texttt{iis\_unicode} is enabled, ASCII and UTF-8 decoding are also enabled to enforce correct decoding. To alert on UTF-8 decoding, you must enable also enable \texttt{utf\_8 yes}. \item \texttt{double\_decode $<$yes$|$no$>$} The \texttt{double\_decode} option is once again IIS-specific and emulates IIS functionality. How this works is that IIS does two passes through the request URI, doing decodes in each one. In the first pass, it seems that all types of iis encoding is done: utf-8 unicode, ASCII, bare byte, and \%u. In the second pass, the following encodings are done: ASCII, bare byte, and \%u. We leave out utf-8 because I think how this works is that the \% encoded utf-8 is decoded to the Unicode byte in the first pass, and then UTF-8 is decoded in the second stage. Anyway, this is really complex and adds tons of different encodings for one character. When \texttt{double\_decode} is enabled, so ASCII is also enabled to enforce correct decoding. \item \texttt{non\_rfc\_char $\{ <$byte$> [<$byte ...$>] \}$} This option lets users receive an alert if certain non-RFC chars are used in a request URI. For instance, a user may not want to see null bytes in the request URI and we can alert on that. Please use this option with care, because you could configure it to say, alert on all `/' or something like that. It's flexible, so be careful. \item \texttt{multi\_slash $<$yes$|$no$>$} This option normalizes multiple slashes in a row, so something like: ``foo/////////bar'' get normalized to ``foo/bar.'' If you want an alert when multiple slashes are seen, then configure with a \texttt{yes}; otherwise, use \texttt{no}. \item \texttt{iis\_backslash $<$yes$|$no$>$} Normalizes backslashes to slashes. This is again an IIS emulation. So a request URI of ``/foo$\backslash$bar'' gets normalized to ``/foo/bar.'' \item \texttt{directory $<$yes$|$no$>$} This option normalizes directory traversals and self-referential directories. The directory: \begin{verbatim} /foo/fake\_dir/../bar \end{verbatim} gets normalized to: \begin{verbatim} /foo/bar \end{verbatim} The directory: \begin{verbatim} /foo/./bar \end{verbatim} gets normalized to: \begin{verbatim} /foo/bar \end{verbatim} If you want to configure an alert, specify \texttt{yes}, otherwise, specify \texttt{no}. This alert may give false positives, since some web sites refer to files using directory traversals. \item \texttt{apache\_whitespace $<$yes$|$no$>$} This option deals with the non-RFC standard of using tab for a space delimiter. Apache uses this, so if the emulated web server is Apache, enable this option. Alerts on this option may be interesting, but may also be false positive prone. \item \texttt{iis\_delimiter $<$yes$|$no$>$} This started out being IIS-specific, but Apache takes this non-standard delimiter was well. Since this is common, we always take this as standard since the most popular web servers accept it. But you can still get an alert on this option. \item \texttt{chunk\_length $<$non-zero positive integer$>$} This option is an anomaly detector for abnormally large chunk sizes. This picks up the Apache chunk encoding exploits, and may also alert on HTTP tunneling that uses chunk encoding. \item \texttt{small\_chunk\_length \{ $<$chunk size$>$ $<$consecutive chunks$>$ \} } This option is an evasion detector for consecutive small chunk sizes when either the client or server use \texttt{Transfer-Encoding: chunked}. $<$chunk size$>$ specifies the maximum chunk size for which a chunk will be considered small. $<$consecutive chunks$>$ specifies the number of consecutive small chunks $<$= $<$chunk size$>$ before an event will be generated. This option is turned off by default. Maximum values for each are 255 and a $<$chunk size$>$ of 0 disables. Events generated are gid:119, sid:26 for client small chunks and gid:120, sid:7 for server small chunks. Example: \begin{verbatim} small_chunk_length { 10 5 } \end{verbatim} Meaning alert if we see 5 consecutive chunk sizes of 10 or less. \item \texttt{no\_pipeline\_req} This option turns HTTP pipeline decoding off, and is a performance enhancement if needed. By default, pipeline requests are inspected for attacks, but when this option is enabled, pipeline requests are not decoded and analyzed per HTTP protocol field. It is only inspected with the generic pattern matching. \item \texttt{non\_strict} This option turns on non-strict URI parsing for the broken way in which Apache servers will decode a URI. Only use this option on servers that will accept URIs like this: "get /index.html alsjdfk alsj lj aj la jsj s$\backslash$n". The non\_strict option assumes the URI is between the first and second space even if there is no valid HTTP identifier after the second space. \item \texttt{allow\_proxy\_use} By specifying this keyword, the user is allowing proxy use on this server. This means that no alert will be generated if the \texttt{proxy\_alert} global keyword has been used. If the proxy\_alert keyword is not enabled, then this option does nothing. The \texttt{allow\_proxy\_use} keyword is just a way to suppress unauthorized proxy use for an authorized server. \item \texttt{no\_alerts} This option turns off all alerts that are generated by the HTTP Inspect preprocessor module. This has no effect on HTTP rules in the rule set. No argument is specified. \item \texttt{oversize\_dir\_length $<$non-zero positive integer$>$} This option takes a non-zero positive integer as an argument. The argument specifies the max char directory length for URL directory. If a url directory is larger than this argument size, an alert is generated. A good argument value is 300 characters. This should limit the alerts to IDS evasion type attacks, like whisker -i 4. \item \texttt{inspect\_uri\_only} This is a performance optimization. When enabled, only the URI portion of HTTP requests will be inspected for attacks. As this field usually contains 90-95\% of the web attacks, you'll catch most of the attacks. So if you need extra performance, enable this optimization. It's important to note that if this option is used without any \texttt{uricontent} rules, then no inspection will take place. This is obvious since the URI is only inspected with \texttt{uricontent} rules, and if there are none available, then there is nothing to inspect. For example, if we have the following rule set: \begin{verbatim} alert tcp any any -> any 80 ( msg:"content"; content: "foo"; ) \end{verbatim} and the we inspect the following URI: \begin{verbatim} get /foo.htm http/1.0\r\n\r\n \end{verbatim} No alert will be generated when \texttt{inspect\_uri\_only} is enabled. The \texttt{inspect\_uri\_only} configuration turns off all forms of detection except \texttt{uricontent} inspection. \item \texttt{max\_header\_length $<$positive integer up to 65535$>$} This option takes an integer as an argument. The integer is the maximum length allowed for an HTTP client request header field. Requests that exceed this length will cause a "Long Header" alert. This alert is off by default. To enable, specify an integer argument to max\_header\_length of 1 to 65535. Specifying a value of 0 is treated as disabling the alert. \item \texttt{max\_spaces $<$positive integer up to 65535$>$} This option takes an integer as an argument. The integer determines the maximum number of whitespaces allowed with HTTP client request line folding. Requests headers folded with whitespaces equal to or more than this value will cause a "Space Saturation" alert with SID 26 and GID 119. The default value for this option is 200. To enable, specify an integer argument to \texttt{max\_spaces} of 1 to 65535. Specifying a value of 0 is treated as disabling the alert. \item \texttt{webroot $<$yes$|$no$>$} This option generates an alert when a directory traversal traverses past the web server root directory. This generates much fewer false positives than the directory option, because it doesn't alert on directory traversals that stay within the web server directory structure. It only alerts when the directory traversals go past the web server root directory, which is associated with certain web attacks. \item \texttt{tab\_uri\_delimiter} This option turns on the use of the tab character (0x09) as a delimiter for a URI. Apache accepts tab as a delimiter; IIS does not. For IIS, a tab in the URI should be treated as any other character. Whether this option is on or not, a tab is treated as whitespace if a space character (0x20) precedes it. No argument is specified. \item \texttt{normalize\_headers} This option turns on normalization for HTTP Header Fields, not including Cookies (using the same configuration parameters as the URI normalization (i.e., multi-slash, directory, etc.). It is useful for normalizing Referrer URIs that may appear in the HTTP Header. \item \texttt{normalize\_cookies} This option turns on normalization for HTTP Cookie Fields (using the same configuration parameters as the URI normalization (i.e., multi-slash, directory, etc.). It is useful for normalizing data in HTTP Cookies that may be encoded. \item \texttt{normalize\_utf} This option turns on normalization of HTTP response bodies where the Content-Type header lists the character set as "utf-16le", "utf-16be", "utf-32le", or "utf-32be". HTTP Inspect will attempt to normalize these back into 8-bit encoding, generating an alert if the extra bytes are non-zero. \item \texttt{max\_headers $<$positive integer up to 1024$>$} This option takes an integer as an argument. The integer is the maximum number of HTTP client request header fields. Requests that contain more HTTP Headers than this value will cause a "Max Header" alert. The alert is off by default. To enable, specify an integer argument to max\_headers of 1 to 1024. Specifying a value of 0 is treated as disabling the alert. \item \texttt{http\_methods $\{ cmd [cmd] \}$ } This specifies additional HTTP Request Methods outside of those checked by default within the preprocessor (GET and POST). The list should be enclosed within braces and delimited by spaces, tabs, line feed or carriage return. The config option, braces and methods also needs to be separated by braces. \begin{verbatim} http_methods { PUT CONNECT } \end{verbatim} \begin{note} Please note the maximum length for a method name is 256. \end{note} \item \texttt{log\_uri} This option enables HTTP Inspect preprocessor to parse the URI data from the HTTP request and log it along with all the generated events for that session. Stream5 reassembly needs to be turned on HTTP ports to enable the logging. If there are multiple HTTP requests in the session, the URI data of the most recent HTTP request during the alert will be logged. The maximum URI logged is 2048. \begin{note} Please note, this is logged only with the unified2 output and is not logged with console output (-A cmg). \texttt{u2spewfoo} can be used to read this data from the unified2. \end{note} \item \texttt{log\_hostname} This option enables HTTP Inspect preprocessor to parse the hostname data from the "Host" header of the HTTP request and log it along with all the generated events for that session. Stream5 reassembly needs to be turned on HTTP ports to enable the logging. If there are multiple HTTP requests in the session, the Hostname data of the most recent HTTP request during the alert will be logged. In case of multiple "Host" headers within one HTTP request, a preprocessor alert with sid 24 is generated. The maximum hostname length logged is 256. \begin{note} Please note, this is logged only with the unified2 output and is not logged with console output (-A cmg). \texttt{u2spewfoo} can be used to read this data from the unified2. \end{note} \end{slist} \subsubsection{Examples} \begin{verbatim} preprocessor http_inspect_server: \ server 10.1.1.1 \ ports { 80 3128 8080 } \ server_flow_depth 0 \ ascii no \ double_decode yes \ non_rfc_char { 0x00 } \ chunk_length 500000 \ non_strict \ no_alerts preprocessor http_inspect_server: \ server default \ ports { 80 3128 } \ non_strict \ non_rfc_char { 0x00 } \ server_flow_depth 300 \ apache_whitespace yes \ directory no \ iis_backslash no \ u_encode yes \ ascii no \ chunk_length 500000 \ bare_byte yes \ double_decode yes \ iis_unicode yes \ iis_delimiter yes \ multi_slash no preprocessor http_inspect_server: \ server default \ profile all \ ports { 80 8080 } \end{verbatim} \subsection{SMTP Preprocessor} \label{SMTP} The SMTP preprocessor is an SMTP decoder for user applications. Given a data buffer, SMTP will decode the buffer and find SMTP commands and responses. It will also mark the command, data header data body sections, and TLS data. SMTP handles stateless and stateful processing. It saves state between individual packets. However maintaining correct state is dependent on the reassembly of the client side of the stream (i.e., a loss of coherent stream data results in a loss of state). \subsubsection{Configuration} SMTP has the usual configuration items, such as \texttt{port} and \texttt{inspection\_type}. Also, SMTP command lines can be normalized to remove extraneous spaces. TLS-encrypted traffic can be ignored, which improves performance. In addition, regular mail data can be ignored for an additional performance boost. Since so few (none in the current snort rule set) exploits are against mail data, this is relatively safe to do and can improve the performance of data inspection. The configuration options are described below: \begin{slist} \item \texttt{ports \{ [] ... \}} This specifies on what ports to check for SMTP data. Typically, this will include 25 and possibly 465, for encrypted SMTP. \item \texttt{inspection\_type } Indicate whether to operate in stateful or stateless mode. \item \texttt{normalize } This turns on normalization. Normalization checks for more than one space character after a command. Space characters are defined as space (ASCII 0x20) or tab (ASCII 0x09). \texttt{all} checks all commands \texttt{none} turns off normalization for all commands. \texttt{cmds} just checks commands listed with the \texttt{normalize\_cmds} parameter. \item \texttt{ignore\_data} Ignore data section of mail (except for mail headers) when processing rules. \item \texttt{ignore\_tls\_data} Ignore TLS-encrypted data when processing rules. \item \texttt{max\_command\_line\_len } Alert if an SMTP command line is longer than this value. Absence of this option or a "0" means never alert on command line length. RFC 2821 recommends 512 as a maximum command line length. \item \texttt{max\_header\_line\_len } Alert if an SMTP DATA header line is longer than this value. Absence of this option or a "0" means never alert on data header line length. RFC 2821 recommends 1024 as a maximum data header line length. \item \texttt{max\_response\_line\_len } Alert if an SMTP response line is longer than this value. Absence of this option or a "0" means never alert on response line length. RFC 2821 recommends 512 as a maximum response line length. \item \texttt{alt\_max\_command\_line\_len \{ [] \}} Overrides \texttt{max\_command\_line\_len} for specific commands. \item \texttt{no\_alerts} Turn off all alerts for this preprocessor. \item \texttt{invalid\_cmds \{ \}} Alert if this command is sent from client side. Default is an empty list. \item \texttt{valid\_cmds \{ \}} List of valid commands. We do not alert on commands in this list. Default is an empty list, but preprocessor has this list hard-coded: \begin{itemize} \item[] \{ ATRN AUTH BDAT DATA DEBUG EHLO EMAL ESAM ESND ESOM ETRN EVFY EXPN HELO HELP IDENT MAIL NOOP QUIT RCPT RSET SAML SOML SEND ONEX QUEU STARTTLS TICK TIME TURN TURNME VERB VRFY X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUE XSTA XTRN XUSR \} \end{itemize} \item \texttt{data\_cmds \{ \}} List of commands that initiate sending of data with an end of data delimiter the same as that of the DATA command per RFC 5321 - \texttt{"."}. Default is \{ DATA \}. \item \texttt{binary\_data\_cmds \{ \}} List of commands that initiate sending of data and use a length value after the command to indicate the amount of data to be sent, similar to that of the BDAT command per RFC 3030. Default is \{ BDAT XEXCH50 \}. \item \texttt{auth\_cmds \{ \}} List of commands that initiate an authentication exchange between client and server. Default is \{ AUTH XAUTH X-EXPS \}. \item \texttt{alert\_unknown\_cmds} Alert if we don't recognize command. Default is off. \item \texttt{normalize\_cmds \{ \}} Normalize this list of commands Default is \{ RCPT VRFY EXPN \}. \item \texttt{xlink2state \{ enable | disable [drop] \}} Enable/disable xlink2state alert. Drop if alerted. Default is \texttt{enable}. \item \texttt{print\_cmds} List all commands understood by the preprocessor. This not normally printed out with the configuration because it can print so much data. \item \texttt{disabled} Disables the SMTP preprocessor in a config. This is useful when specifying the decoding depths such as \texttt{b64\_decode\_depth}, \texttt{qp\_decode\_depth}, \texttt{uu\_decode\_depth}, \texttt{bitenc\_decode\_depth} or the memcap used for decoding \texttt{max\_mime\_mem} in default config without turning on the SMTP preprocessor. \item \texttt{b64\_decode\_depth} This config option is used to turn off/on or set the base64 decoding depth used to decode the base64 encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the base64 decoding of MIME attachments. The value of 0 sets the decoding of base64 encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of base64 MIME attachments, and applies per attachment. A SMTP preprocessor alert with sid 10 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the base64 encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. This option replaces the deprecated options, \texttt{enable\_mime\_decoding} and \texttt{max\_mime\_depth}. It is recommended that user inputs a value that is a multiple of 4. When the value specified is not a multiple of 4, the SMTP preprocessor will round it up to the next multiple of 4. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{qp\_decode\_depth} This config option is used to turn off/on or set the Quoted-Printable decoding depth used to decode the Quoted-Printable(QP) encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the QP decoding of MIME attachments. The value of 0 sets the decoding of QP encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of QP MIME attachments, and applies per attachment. A SMTP preprocessor alert with sid 11 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the QP encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{bitenc\_decode\_depth} This config option is used to turn off/on or set the non-encoded MIME extraction depth used to extract the non-encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the extraction of these MIME attachments. The value of 0 sets the extraction of these MIME attachments to unlimited. A value other than 0 or -1 restricts the extraction of these MIME attachments, and applies per attachment. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the non-encoded MIME attachments/data across multiple packets are extracted too. The extracted data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{uu\_decode\_depth} This config option is used to turn off/on or set the Unix-to-Unix decoding depth used to decode the Unix-to-Unix(UU) encoded attachments. The value ranges from -1 to 65535. A value of -1 turns off the UU decoding of SMTP attachments. The value of 0 sets the decoding of UU encoded SMTP attachments to unlimited. A value other than 0 or -1 restricts the decoding of UU SMTP attachments, and applies per attachment. A SMTP preprocessor alert with sid 13 is generated (if enabled) when the decoding fails. Multiple UU attachments/data in one packet are pipelined. When stateful inspection is turned on the UU encoded SMTP attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{enable\_mime\_decoding} Enables Base64 decoding of Mime attachments/data. Multiple base64 encoded MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the base64 encoded MIME attachments/data across multiple packets are decoded too. The decoding of base64 encoded attachments/data ends when either the \texttt{max\_mime\_depth} or maximum MIME sessions (calculated using \texttt{max\_mime\_depth} and \texttt{max\_mime\_mem}) is reached or when the encoded data ends. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. This option is deprecated. Use the option \texttt{b64\_decode\_depth} to turn off or on the base64 decoding instead. \item \texttt{max\_mime\_depth } Specifies the maximum number of base64 encoded data to decode per SMTP attachment. The option take values ranging from 4 to 20480 bytes. The default value for this in snort in 1460 bytes. It is recommended that user inputs a value that is a multiple of 4. When the value specified is not a multiple of 4, the SMTP preprocessor will round it up to the next multiple of 4. This option is deprecated. Use the option \texttt{b64\_decode\_depth} to turn off or on the base64 decoding instead. \item \texttt{max\_mime\_mem } This option determines (in bytes) the maximum amount of memory the SMTP preprocessor will use for decoding base64 encoded/quoted-printable/non-encoded MIME attachments/data or Unix-to-Unix encoded attachments. This value can be set from 3276 bytes to 100MB. This option along with the maximum of the decoding depths will determine the SMTP sessions that will be decoded at any given instant. The default value for this option is 838860. Note: It is suggested to set this value such that the max smtp session calculated as follows is at least 1. max smtp session = \texttt{max\_mime\_mem} /(2 * max of (\texttt{b64\_decode\_depth}, \texttt{uu\_decode\_depth}, \texttt{qp\_decode\_depth} or \texttt{bitenc\_decode\_depth})) For example, if \texttt{b64\_decode\_depth} is 0 (indicates unlimited decoding) and \texttt{qp\_decode\_depth} is 100, then max smtp session = \texttt{max\_mime\_mem}/2*65535 (max value for \texttt{b64\_decode\_depth}) In case of multiple configs, the \texttt{max\_mime\_mem} of the non-default configs will be overwritten by the default config's value. Hence user needs to define it in the default config with the new keyword disabled (used to disable SMTP preprocessor in a config). \item \texttt{log\_mailfrom} This option enables SMTP preprocessor to parse and log the sender's email address extracted from the "MAIL FROM" command along with all the generated events for that session. The maximum number of bytes logged for this option is 1024. Please note, this is logged only with the unified2 output and is not logged with console output (-A cmg). u2spewfoo can be used to read this data from the unified2. \item \texttt{log\_rcptto} This option enables SMTP preprocessor to parse and log the recipient's email addresses extracted from the "RCPT TO" command along with all the generated events for that session. Multiple recipients are appended with commas. The maximum number of bytes logged for this option is 1024. Please note, this is logged only with the unified2 output and is not logged with console output (-A cmg). u2spewfoo can be used to read this data from the unified2. \item \texttt{log\_filename} This option enables SMTP preprocessor to parse and log the MIME attachment filenames extracted from the Content-Disposition header within the MIME body along with all the generated events for that session. Multiple filenames are appended with commas. The maximum number of bytes logged for this option is 1024. Please note, this is logged only with the unified2 output and is not logged with the console output (-A cmg). u2spewfoo can be used to read this data from the unified2. \item \texttt{log\_email\_hdrs} This option enables SMTP preprocessor to parse and log the SMTP email headers extracted from SMTP data along with all generated events for that session. The number of bytes extracted and logged depends upon the \texttt{email\_hdrs\_log\_depth}. Please note, this is logged only with the unified2 output and is not logged with the console output (-A cmg). u2spewfoo can be used to read this data from the unified2. \item \texttt{email\_hdrs\_log\_depth } This option specifies the depth for logging email headers. The allowed range for this option is 0 - 20480. A value of 0 will disable email headers logging. The default value for this option is 1464. Please note, in case of multiple policies, the value specified in the default policy is used and the values specified in the targeted policies are overwritten by the default value. This option must be configured in the default policy even if the SMTP configuration is disabled. \item \texttt{memcap } This option determines in bytes the maximum amount of memory the SMTP preprocessor will use for logging of filename, MAIL FROM addresses, RCPT TO addresses and email headers. This value along with the buffer size used to log MAIL FROM, RCPT TO, filenames and \texttt{email\_hdrs\_log\_depth} will determine the maximum SMTP sessions that will log the email headers at any given time. When this memcap is reached SMTP will stop logging the filename, MAIL FROM address, RCPT TO addresses and email headers until memory becomes available. Max SMTP sessions logging email headers at any given time = memcap/(1024 + 1024 + 1024 + \texttt{email\_hdrs\_log\_depth}) The size 1024 is the maximum buffer size used for logging filename, RCPTTO and MAIL FROM addresses. Default value for this option is 838860. The allowed range for this option is 3276 to 104857600. The value specified in the default config is used when this option is specified in multiple configs. This option must be configured in the default config even if the SMTP configuration is disabled. Please note, in case of multiple policies, the value specified in the default policy is used and the values specified in the targeted policies are overwritten by the default value. This option must be configured in the default policy even if the SMTP configuration is disabled. \end{slist} \subsubsection{Example} \begin{verbatim} preprocessor SMTP: \ ports { 25 } \ inspection_type stateful \ normalize cmds \ normalize_cmds { EXPN VRFY RCPT } \ ignore_data \ ignore_tls_data \ max_command_line_len 512 \ max_header_line_len 1024 \ max_response_line_len 512 \ no_alerts \ alt_max_command_line_len 300 { RCPT } \ invalid_cmds { } \ valid_cmds { } \ xlink2state { disable } \ print_cmds \ log_filename \ log_email_hdrs \ log_mailfrom \ log_rcptto \ email_hdrs_log_depth 2920 \ memcap 6000 preprocessor SMTP: \ b64_decode_depth 0\ max_mime_mem 4000 \ memcap 6000 \ email_hdrs_log_depth 2920 \ disabled \end{verbatim} \subsubsection{Default} \begin{verbatim} preprocessor SMTP: \ ports { 25 } \ inspection_type stateful \ normalize cmds \ normalize_cmds { EXPN VRFY RCPT } \ alt_max_command_line_len 260 { MAIL } \ alt_max_command_line_len 300 { RCPT } \ alt_max_command_line_len 500 { HELP HELO ETRN } \ alt_max_command_line_len 255 { EXPN VRFY } \end{verbatim} \subsubsection{Note} \texttt{RCPT TO:} and \texttt{MAIL FROM:} are SMTP commands. For the preprocessor configuration, they are referred to as RCPT and MAIL, respectively. Within the code, the preprocessor actually maps RCPT and MAIL to the correct command name. \subsection{POP Preprocessor} \label{POP} POP is an POP3 decoder for user applications. Given a data buffer, POP will decode the buffer and find POP3 commands and responses. It will also mark the command, data header data body sections and extract the POP3 attachments and decode it appropriately. POP will handle stateful processing. It saves state between individual packets. However maintaining correct state is dependent on the reassembly of the server side of the stream (i.e., a loss of coherent stream data results in a loss of state). Stream5 should be turned on for POP. Please ensure that the POP ports are added to the stream5 ports for proper reassembly. The POP preprocessor uses GID 142 to register events. \subsubsection{Configuration} The configuration options are described below: \begin{slist} \item \texttt{ports \{ [] ... \}} This specifies on what ports to check for POP data. Typically, this will include 110. Default ports if none are specified are 110 . \item \texttt{disabled} Disables the POP preprocessor in a config. This is useful when specifying the decoding depths such as \texttt{b64\_decode\_depth}, \texttt{qp\_decode\_depth}, \texttt{uu\_decode\_depth}, \texttt{bitenc\_decode\_depth} or the memcap used for decoding \texttt{memcap} in default config without turning on the POP preprocessor. \item \texttt{b64\_decode\_depth} This config option is used to turn off/on or set the base64 decoding depth used to decode the base64 encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the base64 decoding of MIME attachments. The value of 0 sets the decoding of base64 encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of base64 MIME attachments, and applies per attachment. A POP preprocessor alert with sid 4 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the base64 encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. It is recommended that user inputs a value that is a multiple of 4. When the value specified is not a multiple of 4, the POP preprocessor will round it up to the next multiple of 4. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{qp\_decode\_depth} This config option is used to turn off/on or set the Quoted-Printable decoding depth used to decode the Quoted-Printable(QP) encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the QP decoding of MIME attachments. The value of 0 sets the decoding of QP encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of QP MIME attachments, and applies per attachment. A POP preprocessor alert with sid 5 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the QP encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{bitenc\_decode\_depth} This config option is used to turn off/on or set the non-encoded MIME extraction depth used to extract the non-encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the extraction of these MIME attachments. The value of 0 sets the extraction of these MIME attachments to unlimited. A value other than 0 or -1 restricts the extraction of these MIME attachments, and applies per attachment. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the non-encoded MIME attachments/data across multiple packets are extracted too. The extracted data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{uu\_decode\_depth} This config option is used to turn off/on or set the Unix-to-Unix decoding depth used to decode the Unix-to-Unix(UU) encoded attachments. The value ranges from -1 to 65535. A value of -1 turns off the UU decoding of POP attachments. The value of 0 sets the decoding of UU encoded POP attachments to unlimited. A value other than 0 or -1 restricts the decoding of UU POP attachments, and applies per attachment. A POP preprocessor alert with sid 7 is generated (if enabled) when the decoding fails. Multiple UU attachments/data in one packet are pipelined. When stateful inspection is turned on the UU encoded POP attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{memcap } This option determines (in bytes) the maximum amount of memory the POP preprocessor will use for decoding base64 encoded/quoted-printable/non-encoded MIME attachments/data or Unix-to-Unix encoded attachments. This value can be set from 3276 bytes to 100MB. This option along with the maximum of the decoding depths will determine the POP sessions that will be decoded at any given instant. The default value for this option is 838860. Note: It is suggested to set this value such that the max pop session calculated as follows is at least 1. max pop session = \texttt{memcap} /(2 * max of (\texttt{b64\_decode\_depth}, \texttt{uu\_decode\_depth}, \texttt{qp\_decode\_depth} or \texttt{bitenc\_decode\_depth})) For example, if \texttt{b64\_decode\_depth} is 0 (indicates unlimited decoding) and \texttt{qp\_decode\_depth} is 100, then max pop session = \texttt{memcap}/2*65535 (max value for \texttt{b64\_decode\_depth}) In case of multiple configs, the \texttt{memcap} of the non-default configs will be overwritten by the default config's value. Hence user needs to define it in the default config with the new keyword disabled (used to disable POP preprocessor in a config). When the memcap for decoding (\texttt{memcap}) is exceeded the POP preprocessor alert with sid 3 is generated (when enabled). \end{slist} \subsubsection{Example} \begin{verbatim} preprocessor pop: \ ports { 110 } \ memcap 1310700 \ qp_decode_depth -1 \ b64_decode_depth 0 \ bitenc_decode_depth 100 preprocessor pop: \ memcap 1310700 \ qp_decode_depth 0 \ disabled \end{verbatim} \subsubsection{Default} \begin{verbatim} preprocessor pop: \ ports { 110 } \ b64_decode_depth 1460 \ qp_decode_depth 1460 \ bitenc_decode_depth 1460 \ uu_decode_depth 1460 \end{verbatim} \subsection{IMAP Preprocessor} \label{IMAP} IMAP is an IMAP4 decoder for user applications. Given a data buffer, IMAP will decode the buffer and find IMAP4 commands and responses. It will also mark the command, data header data body sections and extract the IMAP4 attachments and decode it appropriately. IMAP will handle stateful processing. It saves state between individual packets. However maintaining correct state is dependent on the reassembly of the server side of the stream (i.e., a loss of coherent stream data results in a loss of state). Stream5 should be turned on for IMAP. Please ensure that the IMAP ports are added to the stream5 ports for proper reassembly. The IMAP preprocessor uses GID 141 to register events. \subsubsection{Configuration} The configuration options are described below: \begin{slist} \item \texttt{ports \{ [] ... \}} This specifies on what ports to check for IMAP data. Typically, this will include 143. Default ports if none are specified are 143 . \item \texttt{disabled} Disables the IMAP preprocessor in a config. This is useful when specifying the decoding depths such as \texttt{b64\_decode\_depth}, \texttt{qp\_decode\_depth}, \texttt{uu\_decode\_depth}, \texttt{bitenc\_decode\_depth} or the memcap used for decoding \texttt{memcap} in default config without turning on the IMAP preprocessor. \item \texttt{b64\_decode\_depth} This config option is used to turn off/on or set the base64 decoding depth used to decode the base64 encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the base64 decoding of MIME attachments. The value of 0 sets the decoding of base64 encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of base64 MIME attachments, and applies per attachment. A IMAP preprocessor alert with sid 4 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the base64 encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. It is recommended that user inputs a value that is a multiple of 4. When the value specified is not a multiple of 4, the IMAP preprocessor will round it up to the next multiple of 4. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{qp\_decode\_depth} This config option is used to turn off/on or set the Quoted-Printable decoding depth used to decode the Quoted-Printable(QP) encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the QP decoding of MIME attachments. The value of 0 sets the decoding of QP encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of QP MIME attachments, and applies per attachment. A IMAP preprocessor alert with sid 5 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the QP encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{bitenc\_decode\_depth} This config option is used to turn off/on or set the non-encoded MIME extraction depth used to extract the non-encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the extraction of these MIME attachments. The value of 0 sets the extraction of these MIME attachments to unlimited. A value other than 0 or -1 restricts the extraction of these MIME attachments, and applies per attachment. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the non-encoded MIME attachments/data across multiple packets are extracted too. The extracted data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{uu\_decode\_depth} This config option is used to turn off/on or set the Unix-to-Unix decoding depth used to decode the Unix-to-Unix(UU) encoded attachments. The value ranges from -1 to 65535. A value of -1 turns off the UU decoding of IMAP attachments. The value of 0 sets the decoding of UU encoded IMAP attachments to unlimited. A value other than 0 or -1 restricts the decoding of UU IMAP attachments, and applies per attachment. A IMAP preprocessor alert with sid 7 is generated (if enabled) when the decoding fails. Multiple UU attachments/data in one packet are pipelined. When stateful inspection is turned on the UU encoded IMAP attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option \texttt{file\_data}. See \ref{sub:file_data} rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. \item \texttt{memcap } This option determines (in bytes) the maximum amount of memory the IMAP preprocessor will use for decoding base64 encoded/quoted-printable/non-encoded MIME attachments/data or Unix-to-Unix encoded attachments. This value can be set from 3276 bytes to 100MB. This option along with the maximum of the decoding depths will determine the IMAP sessions that will be decoded at any given instant. The default value for this option is 838860. Note: It is suggested to set this value such that the max imap session calculated as follows is at least 1. max imap session = \texttt{memcap} /(2 * max of (\texttt{b64\_decode\_depth}, \texttt{uu\_decode\_depth}, \texttt{qp\_decode\_depth} or \texttt{bitenc\_decode\_depth})) For example, if \texttt{b64\_decode\_depth} is 0 (indicates unlimited decoding) and \texttt{qp\_decode\_depth} is 100, then max imap session = \texttt{memcap}/2*65535 (max value for \texttt{b64\_decode\_depth}) In case of multiple configs, the \texttt{memcap} of the non-default configs will be overwritten by the default config's value. Hence user needs to define it in the default config with the new keyword disabled (used to disable IMAP preprocessor in a config). When the memcap for decoding (\texttt{memcap}) is exceeded the IMAP preprocessor alert with sid 3 is generated (when enabled). \end{slist} \subsubsection{Example} \begin{verbatim} preprocessor imap: \ ports { 110 } \ memcap 1310700 \ qp_decode_depth -1 \ b64_decode_depth 0 \ bitenc_decode_depth 100 preprocessor imap: \ memcap 1310700 \ qp_decode_depth 0 \ disabled \end{verbatim} \subsubsection{Default} \begin{verbatim} preprocessor imap: \ ports { 110 } \ b64_decode_depth 1460 \ qp_decode_depth 1460 \ bitenc_decode_depth 1460 \ uu_decode_depth 1460 \end{verbatim} \subsection{FTP/Telnet Preprocessor} \label{sub:ftptelnet} FTP/Telnet is an improvement to the Telnet decoder and provides stateful inspection capability for both FTP and Telnet data streams. FTP/Telnet will decode the stream, identifying FTP commands and responses and Telnet escape sequences and normalize the fields. FTP/Telnet works on both client requests and server responses. FTP/Telnet has the capability to handle stateless processing, meaning it only looks for information on a packet-by-packet basis. The default is to run FTP/Telnet in stateful inspection mode, meaning it looks for information and handles reassembled data correctly. FTP/Telnet has a very ``rich'' user configuration, similar to that of HTTP Inspect (See \ref{sub:http-inspect}). Users can configure individual FTP servers and clients with a variety of options, which should allow the user to emulate any type of FTP server or FTP Client. Within FTP/Telnet, there are four areas of configuration: Global, Telnet, FTP Client, and FTP Server. \begin{note} Some configuration options have an argument of \texttt{yes} or \texttt{no}. This argument specifies whether the user wants the configuration option to generate a ftptelnet alert or not. The presence of the option indicates the option itself is on, while the \texttt{yes/no} argument applies to the alerting functionality associated with that option. \end{note} \subsubsection{Global Configuration} The global configuration deals with configuration options that determine the global functioning of FTP/Telnet. The following example gives the generic global configuration format: \subsubsection{Format} \begin{verbatim} preprocessor ftp_telnet: \ global \ inspection_type stateful \ encrypted_traffic yes \ check_encrypted \end{verbatim} You can only have a single global configuration, you'll get an error if you try otherwise. The FTP/Telnet global configuration must appear before the other three areas of configuration. \paragraph{Configuration} \begin{slist} \item \texttt{inspection\_type} This indicates whether to operate in stateful or stateless mode. \item \texttt{encrypted\_traffic $<$yes|no$>$} This option enables detection and alerting on encrypted Telnet and FTP command channels. \begin{note} When \texttt{inspection\_type} is in stateless mode, checks for encrypted traffic will occur on every packet, whereas in stateful mode, a particular session will be noted as encrypted and not inspected any further. \end{note} \item \texttt{check\_encrypted} Instructs the preprocessor to continue to check an encrypted session for a subsequent command to cease encryption. \end{slist} \subsubsection{Example Global Configuration} \begin{verbatim} preprocessor ftp_telnet: \ global inspection_type stateful encrypted_traffic no \end{verbatim} \subsubsection{Telnet Configuration} The telnet configuration deals with configuration options that determine the functioning of the Telnet portion of the preprocessor. The following example gives the generic telnet configuration format: \subsubsection{Format} \begin{verbatim} preprocessor ftp_telnet_protocol: \ telnet \ ports { 23 } \ normalize \ ayt_attack_thresh 6 \ detect_anomalies \end{verbatim} There should only be a single telnet configuration, and subsequent instances will override previously set values. \paragraph{Configuration} \begin{slist} \item \texttt{ports $\{ <$port$> [<$port$> <...>] \}$} This is how the user configures which ports to decode as telnet traffic. SSH tunnels cannot be decoded, so adding port 22 will only yield false positives. Typically port 23 will be included. \item \texttt{normalize} This option tells the preprocessor to normalize the telnet traffic by eliminating the telnet escape sequences. It functions similarly to its predecessor, the telnet\_decode preprocessor. Rules written with 'raw' content options will ignore the normalized buffer that is created when this option is in use. \item \texttt{ayt\_attack\_thresh $<$ number $>$} This option causes the preprocessor to alert when the number of consecutive telnet Are You There (AYT) commands reaches the number specified. It is only applicable when the mode is stateful. \item \texttt{detect\_anomalies} In order to support certain options, Telnet supports subnegotiation. Per the Telnet RFC, subnegotiation begins with SB (subnegotiation begin) and must end with an SE (subnegotiation end). However, certain implementations of Telnet servers will ignore the SB without a corresponding SE. This is anomalous behavior which could be an evasion case. Being that FTP uses the Telnet protocol on the control connection, it is also susceptible to this behavior. The \texttt{detect\_anomalies} option enables alerting on Telnet SB without the corresponding SE. \end{slist} \subsubsection{Example Telnet Configuration} \begin{verbatim} preprocessor ftp_telnet_protocol: \ telnet ports { 23 } normalize ayt_attack_thresh 6 \end{verbatim} \subsubsection{FTP Server Configuration} There are two types of FTP server configurations: default and by IP address. \paragraph{Default} This configuration supplies the default server configuration for any FTP server that is not individually configured. Most of your FTP servers will most likely end up using the default configuration. \subsubsection{Example Default FTP Server Configuration} \begin{verbatim} preprocessor ftp_telnet_protocol: \ ftp server default ports { 21 } \end{verbatim} Refer to \pageref{sub:default ftp server config} for the list of options set in default ftp server configuration. \paragraph{Configuration by IP Address} This format is very similar to ``default'', the only difference being that specific IPs can be configured. \subsubsection{Example IP specific FTP Server Configuration} \begin{verbatim} preprocessor _telnet_protocol: \ ftp server 10.1.1.1 ports { 21 } ftp_cmds { XPWD XCWD } \end{verbatim} \subsubsection{FTP Server Configuration Options} \begin{slist} \item \texttt{ports $\{ <$port$> [<$port$> <...>] \}$} This is how the user configures which ports to decode as FTP command channel traffic. Typically port 21 will be included. \item \texttt{print\_cmds} During initialization, this option causes the preprocessor to print the configuration for each of the FTP commands for this server. \item \texttt{ftp\_cmds $\{ cmd [cmd] \}$ } The preprocessor is configured to alert when it sees an FTP command that is not allowed by the server. This option specifies a list of additional commands allowed by this server, outside of the default FTP command set as specified in RFC 959. This may be used to allow the use of the 'X' commands identified in RFC 775, as well as any additional commands as needed. For example: \begin{verbatim} ftp_cmds { XPWD XCWD XCUP XMKD XRMD } \end{verbatim} \item \texttt{def\_max\_param\_len $<$number$>$} This specifies the default maximum allowed parameter length for an FTP command. It can be used as a basic buffer overflow detection. \item \texttt{alt\_max\_param\_len $<$number$>$ $\{ cmd [cmd] \}$} This specifies the maximum allowed parameter length for the specified FTP command(s). It can be used as a more specific buffer overflow detection. For example the USER command -- usernames may be no longer than 16 bytes, so the appropriate configuration would be: \begin{verbatim} alt_max_param_len 16 { USER } \end{verbatim} \item \texttt{chk\_str\_fmt $\{ cmd [cmd] \}$} This option causes a check for string format attacks in the specified commands. \item \texttt{cmd\_validity cmd $<$ fmt $>$} This option specifies the valid format for parameters of a given command. fmt must be enclosed in $<>$'s and may contain the following: \begin{center} \begin{tabular}{| l | p{3in} |} \hline \textbf{Value} & \textbf{Description} \\ \hline \hline int & Parameter must be an integer \\ \hline number & Parameter must be an integer between 1 and 255 \\ \hline char $<$chars$>$ & Parameter must be a single character, one of $<$chars$>$ \\ \hline date $<$datefmt$>$ & Parameter follows format specified, where: \begin{tabular}{ l l } n & Number \\ C & Character \\ $[]$ & optional format enclosed \\ $|$ & OR \\ $\{\}$ & choice of options \\ . + - & literal \\ \end{tabular} \\ \hline string & Parameter is a string (effectively unrestricted) \\ \hline host\_port & Parameter must be a host/port specified, per RFC 959 \\ \hline long\_host\_port & Parameter must be a long host port specified, per RFC 1639 \\ \hline extended\_host\_port & Parameter must be an extended host port specified, per RFC 2428 \\ \hline $\{\}$, $|$ & One of choices enclosed within, separated by $|$ \\ \hline $\{\}$, $[]$ & One of the choices enclosed within $\{\}$, optional value enclosed within $[]$ \\ \hline \end{tabular} \end{center} Examples of the cmd\_validity option are shown below. These examples are the default checks, per RFC 959 and others performed by the preprocessor. \begin{verbatim} cmd_validity MODE cmd_validity STRU cmd_validity ALLO < int [ char R int ] > cmd_validity TYPE < { char AE [ char NTC ] | char I | char L [ number ] } > cmd_validity PORT < host_port > \end{verbatim} A cmd\_validity line can be used to override these defaults and/or add a check for other commands. \begin{verbatim} # This allows additional modes, including mode Z which allows for # zip-style compression. cmd_validity MODE < char ASBCZ > # Allow for a date in the MDTM command. cmd_validity MDTM < [ date nnnnnnnnnnnnnn[.n[n[n]]] ] string > \end{verbatim} MDTM is an off case that is worth discussing. While not part of an established standard, certain FTP servers accept MDTM commands that set the modification time on a file. The most common among servers that do, accept a format using YYYYMMDDHHmmss[.uuu]. Some others accept a format using YYYYMMDDHHmmss[+|-]TZ format. The example above is for the first case (time format as specified in http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16.txt) To check validity for a server that uses the TZ format, use the following: \begin{verbatim} cmd_validity MDTM < [ date nnnnnnnnnnnnnn[{+|-}n[n]] ] string > \end{verbatim} \item \texttt{telnet\_cmds $<$yes$|$no$>$} This option turns on detection and alerting when telnet escape sequences are seen on the FTP command channel. Injection of telnet escape sequences could be used as an evasion attempt on an FTP command channel. \item \texttt{ignore\_telnet\_erase\_cmds $<$yes|no$>$} This option allows Snort to ignore telnet escape sequences for erase character (TNC EAC) and erase line (TNC EAL) when normalizing FTP command channel. Some FTP servers do not process those telnet escape sequences. \item \texttt{data\_chan} This option causes the rest of snort (rules, other preprocessors) to ignore FTP data channel connections. Using this option means that \textbf{NO INSPECTION} other than TCP state will be performed on FTP data transfers. It can be used to improve performance, especially with large file transfers from a trusted source. If your rule set includes virus-type rules, it is recommended that this option not be used. Use of the "data\_chan" option is deprecated in favor of the "ignore\_data\_chan" option. "data\_chan" will be removed in a future release. \item \texttt{ignore\_data\_chan $<$yes$|$no$>$} This option causes the rest of Snort (rules, other preprocessors) to ignore FTP data channel connections. Setting this option to "yes" means that \textbf{NO INSPECTION} other than TCP state will be performed on FTP data transfers. It can be used to improve performance, especially with large file transfers from a trusted source. If your rule set includes virus-type rules, it is recommended that this option not be used. \end{slist} \subsubsection{FTP Server Base Configuration Options} \label{sub:default ftp server config} The base FTP server configuration is as follows. Options specified in the configuration file will modify this set of options. FTP commands are added to the set of allowed commands. The other options will override those in the base configuration. \begin{verbatim} def_max_param_len 100 ftp_cmds { USER PASS ACCT CWD CDUP SMNT QUIT REIN TYPE STRU MODE RETR STOR STOU APPE ALLO REST RNFR RNTO ABOR DELE RMD MKD PWD LIST NLST SITE SYST STAT HELP NOOP } ftp_cmds { AUTH ADAT PROT PBSZ CONF ENC } ftp_cmds { PORT PASV LPRT LPSV EPRT EPSV } ftp_cmds { FEAT OPTS } ftp_cmds { MDTM REST SIZE MLST MLSD } alt_max_param_len 0 { CDUP QUIT REIN PASV STOU ABOR PWD SYST NOOP } cmd_validity MODE < char SBC > cmd_validity STRU < char FRPO [ string ] > cmd_validity ALLO < int [ char R int ] > cmd_validity TYPE < { char AE [ char NTC ] | char I | char L [ number ] } > cmd_validity PORT < host_port > cmd_validity LPRT < long_host_port > cmd_validity EPRT < extd_host_port > cmd_validity EPSV < [ { '1' | '2' | 'ALL' } ] > \end{verbatim} \subsubsection{FTP Client Configuration} Similar to the FTP Server configuration, the FTP client configurations has two types: default, and by IP address. \paragraph{Default} This configuration supplies the default client configuration for any FTP client that is not individually configured. Most of your FTP clients will most likely end up using the default configuration. \subsubsection{Example Default FTP Client Configuration} \begin{verbatim} preprocessor ftp_telnet_protocol: \ ftp client default bounce no max_resp_len 200 \end{verbatim} \paragraph{Configuration by IP Address} This format is very similar to ``default'', the only difference being that specific IPs can be configured. \subsubsection{Example IP specific FTP Client Configuration} \begin{verbatim} preprocessor ftp_telnet_protocol: \ ftp client 10.1.1.1 bounce yes max_resp_len 500 \end{verbatim} \subsubsection{FTP Client Configuration Options} \begin{slist} \item \texttt{max\_resp\_len $<$number$>$} This specifies the maximum allowed response length to an FTP command accepted by the client. It can be used as a basic buffer overflow detection. \item \texttt{bounce $<$yes|no$>$} This option turns on detection and alerting of FTP bounce attacks. An FTP bounce attack occurs when the FTP PORT command is issued and the specified host does not match the host of the client. \item \texttt{bounce\_to $<$ CIDR,[port$|$portlow,porthi] $>$} When the bounce option is turned on, this allows the PORT command to use the IP address (in CIDR format) and port (or inclusive port range) without generating an alert. It can be used to deal with proxied FTP connections where the FTP data channel is different from the client. A few examples: \begin{itemize} \item Allow bounces to 192.162.1.1 port 20020 -- i.e., the use of \texttt{PORT 192,168,1,1,78,52}. \begin{verbatim} bounce_to { 192.168.1.1,20020 } \end{verbatim} \item Allow bounces to 192.162.1.1 ports 20020 through 20040 -- i.e., the use of \texttt{PORT 192,168,1,1,78,xx}, where xx is 52 through 72 inclusive. \begin{verbatim} bounce_to { 192.168.1.1,20020,20040 } \end{verbatim} \item Allow bounces to 192.162.1.1 port 20020 and 192.168.1.2 port 20030. \begin{verbatim} bounce_to { 192.168.1.1,20020 192.168.1.2,20030 } \end{verbatim} \item Allows bounces to IPv6 address fe8::5 port 59340. \begin{verbatim} bounce_to { fe8::5,59340 } \end{verbatim} \end{itemize} \item \texttt{telnet\_cmds $<$yes|no$>$} This option turns on detection and alerting when telnet escape sequences are seen on the FTP command channel. Injection of telnet escape sequences could be used as an evasion attempt on an FTP command channel. \item \texttt{ignore\_telnet\_erase\_cmds $<$yes|no$>$} This option allows Snort to ignore telnet escape sequences for erase character (TNC EAC) and erase line (TNC EAL) when normalizing FTP command channel. Some FTP clients do not process those telnet escape sequences. \end{slist} \subsubsection{Examples/Default Configuration from snort.conf} \begin{verbatim} preprocessor ftp_telnet: \ global \ encrypted_traffic yes \ inspection_type stateful preprocessor ftp_telnet_protocol:\ telnet \ normalize \ ayt_attack_thresh 200 # This is consistent with the FTP rules as of 18 Sept 2004. # Set CWD to allow parameter length of 200 # MODE has an additional mode of Z (compressed) # Check for string formats in USER & PASS commands # Check MDTM commands that set modification time on the file. preprocessor ftp_telnet_protocol: \ ftp server default \ def_max_param_len 100 \ alt_max_param_len 200 { CWD } \ cmd_validity MODE < char ASBCZ > \ cmd_validity MDTM < [ date nnnnnnnnnnnnnn[.n[n[n]]] ] string > \ chk_str_fmt { USER PASS RNFR RNTO SITE MKD } \ telnet_cmds yes \ ignore_data_chan yes preprocessor ftp_telnet_protocol: \ ftp client default \ max_resp_len 256 \ bounce yes \ telnet_cmds yes \end{verbatim} \subsection{SSH} \label{sub:ssh} The SSH preprocessor detects the following exploits: Challenge-Response Buffer Overflow, CRC 32, Secure CRT, and the Protocol Mismatch exploit. Both Challenge-Response Overflow and CRC 32 attacks occur after the key exchange, and are therefore encrypted. Both attacks involve sending a large payload (20kb+) to the server immediately after the authentication challenge. To detect the attacks, the SSH preprocessor counts the number of bytes transmitted to the server. If those bytes exceed a predefined limit within a predefined number of packets, an alert is generated. Since the Challenge-Response Overflow only effects SSHv2 and CRC 32 only effects SSHv1, the SSH version string exchange is used to distinguish the attacks. The Secure CRT and protocol mismatch exploits are observable before the key exchange. \subsubsection{Configuration} By default, all alerts are disabled and the preprocessor checks traffic on port 22. The available configuration options are described below. \begin{slist} \item \texttt{server\_ports $\{ <$port$> [<$port$> <...>] \}$} This option specifies which ports the SSH preprocessor should inspect traffic to. \item \texttt{max\_encrypted\_packets $<$ number $>$} The number of stream reassembled encrypted packets that Snort will inspect before ignoring a given SSH session. The SSH vulnerabilities that Snort can detect all happen at the very beginning of an SSH session. Once max\_encrypted\_packets packets have been seen, Snort ignores the session to increase performance. The default is set to 25. This value can be set from 0 to 65535. \item \texttt{max\_client\_bytes $<$ number $>$} The number of unanswered bytes allowed to be transferred before alerting on Challenge-Response Overflow or CRC 32. This number must be hit before max\_encrypted\_packets packets are sent, or else Snort will ignore the traffic. The default is set to 19600. This value can be set from 0 to 65535. \item \texttt{max\_server\_version\_len $<$ number $>$} The maximum number of bytes allowed in the SSH server version string before alerting on the Secure CRT server version string overflow. The default is set to 80. This value can be set from 0 to 255. \item \texttt{autodetect} Attempt to automatically detect SSH. \item \texttt{enable\_respoverflow} Enables checking for the Challenge-Response Overflow exploit. \item \texttt{enable\_ssh1crc32} Enables checking for the CRC 32 exploit. \item \texttt{enable\_srvoverflow} Enables checking for the Secure CRT exploit. \item \texttt{enable\_protomismatch} Enables checking for the Protocol Mismatch exploit. \item \texttt{enable\_badmsgdir} Enable alerts for traffic flowing the wrong direction. For instance, if the presumed server generates client traffic, or if a client generates server traffic. \item \texttt{enable\_paysize} Enables alerts for invalid payload sizes. \item \texttt{enable\_recognition} Enable alerts for non-SSH traffic on SSH ports. \end{slist} The SSH preprocessor should work by default. After max\_encrypted\_packets is reached, the preprocessor will stop processing traffic for a given session. If Challenge-Response Overflow or CRC 32 false positive, try increasing the number of required client bytes with max\_client\_bytes. \subsubsection{Example Configuration from snort.conf} Looks for attacks on SSH server port 22. Alerts at 19600 unacknowledged bytes within 20 encrypted packets for the Challenge-Response Overflow/CRC32 exploits. \begin{verbatim} preprocessor ssh: \ server_ports { 22 } \ max_client_bytes 19600 \ max_encrypted_packets 20 \ enable_respoverflow \ enable_ssh1crc32 \end{verbatim} \subsection{DNS} \label{sub:dns} The DNS preprocessor decodes DNS Responses and can detect the following exploits: DNS Client RData Overflow, Obsolete Record Types, and Experimental Record Types. DNS looks at DNS Response traffic over UDP and TCP and it requires Stream preprocessor to be enabled for TCP decoding. \subsubsection{Configuration} By default, all alerts are disabled and the preprocessor checks traffic on port 53. The available configuration options are described below. \begin{slist} \item \texttt{ports $\{ <$port$> [<$port$> <...>] \}$} This option specifies the source ports that the DNS preprocessor should inspect traffic. \item \texttt{enable\_obsolete\_types} Alert on Obsolete (per RFC 1035) Record Types \item \texttt{enable\_experimental\_types} Alert on Experimental (per RFC 1035) Record Types \item \texttt{enable\_rdata\_overflow} Check for DNS Client RData TXT Overflow \end{slist} The DNS preprocessor does nothing if none of the 3 vulnerabilities it checks for are enabled. It will not operate on TCP sessions picked up midstream, and it will cease operation on a session if it loses state because of missing data (dropped packets). \subsubsection{Examples/Default Configuration from snort.conf} Looks for traffic on DNS server port 53. Check for the DNS Client RData overflow vulnerability. Do not alert on obsolete or experimental RData record types. \begin{verbatim} preprocessor dns: \ ports { 53 } \ enable_rdata_overflow \end{verbatim} \subsection{SSL/TLS} \label{sub:SSL/TLS} Encrypted traffic should be ignored by Snort for both performance reasons and to reduce false positives. The SSL Dynamic Preprocessor (SSLPP) decodes SSL and TLS traffic and optionally determines if and when Snort should stop inspection of it. Typically, SSL is used over port 443 as HTTPS. By enabling the SSLPP to inspect port 443 and enabling the noinspect\_encrypted option, only the SSL handshake of each connection will be inspected. Once the traffic is determined to be encrypted, no further inspection of the data on the connection is made. By default, SSLPP looks for a handshake followed by encrypted traffic traveling to both sides. If one side responds with an indication that something has failed, such as the handshake, the session is not marked as encrypted. Verifying that faultless encrypted traffic is sent from both endpoints ensures two things: the last client-side handshake packet was not crafted to evade Snort, and that the traffic is legitimately encrypted. In some cases, especially when packets may be missed, the only observed response from one endpoint will be TCP ACKs. Therefore, if a user knows that server-side encrypted data can be trusted to mark the session as encrypted, the user should use the 'trustservers' option, documented below. \subsubsection{Configuration} \begin{slist} \item \texttt{ports $\{ <$port$> [<$port$> <...>] \}$} This option specifies which ports SSLPP will inspect traffic on. By default, SSLPP watches the following ports: \begin{itemize} \item \texttt{443} HTTPS \item \texttt{465} SMTPS \item \texttt{563} NNTPS \item \texttt{636} LDAPS \item \texttt{989} FTPS \item \texttt{992} TelnetS \item \texttt{993} IMAPS \item \texttt{994} IRCS \item \texttt{995} POPS \end{itemize} \item \texttt{noinspect\_encrypted} Disable inspection on traffic that is encrypted. Default is off. \item \texttt{trustservers} Disables the requirement that application (encrypted) data must be observed on both sides of the session before a session is marked encrypted. Use this option for slightly better performance if you trust that your servers are not compromised. This requires the \texttt{noinspect\_encrypted} option to be useful. Default is off. \end{slist} \subsubsection{Examples/Default Configuration from snort.conf} Enables the SSL preprocessor and tells it to disable inspection on encrypted traffic. \begin{verbatim} preprocessor ssl: noinspect_encrypted \end{verbatim} \subsubsection{Rule Options} The following rule options are supported by enabling the \texttt{ssl} preprocessor: \begin{itemize} \item[] \begin{verbatim} ssl_version ssl_state \end{verbatim} \end{itemize} \texttt{ssl\_version} \label{ssl:ssl_version} \begin{itemize} \item[] The \texttt{ssl\_version} rule option tracks the version negotiated between the endpoints of the SSL encryption. The list of version identifiers are below, and more than one identifier can be specified, via a comma separated list. Lists of identifiers are OR'ed together. The option will match if any one of the OR'ed versions are used in the SSL connection. To check for two or more SSL versions in use simultaneously, multiple \texttt{ssl\_version} rule options should be used. \textit{Syntax} \footnotesize \begin{verbatim} ssl_version: version-list = version | version , version-list version = ["!"] "sslv2" | "sslv3" | "tls1.0" | "tls1.1" | "tls1.2" \end{verbatim} \textit{Examples} \begin{verbatim} ssl_version:sslv3; ssl_version:tls1.0,tls1.1,tls1.2; ssl_version:!sslv2; \end{verbatim} \end{itemize} \texttt{ssl\_state} \label{ssl:ssl_state} \begin{itemize} \item[] The \texttt{ssl\_state} rule option tracks the state of the SSL encryption during the process of hello and key exchange. The list of states are below. More than one state can be specified, via a comma separated list, and are OR'ed together. The option will match if the connection is currently in any one of the OR'ed states. To ensure the connection has reached each of a set of states, multiple rules using the \texttt{ssl\_state} rule option should be used. \textit{Syntax} \footnotesize \begin{verbatim} ssl_state: state-list = state | state , state-list state = ["!"] "client_hello" | "server_hello" | "client_keyx" | "server_keyx" | "unknown" \end{verbatim} \textit{Examples} \begin{verbatim} ssl_state:client_hello; ssl_state:client_keyx,server_keyx; ssl_state:!server_hello; \end{verbatim} \end{itemize} \subsection{ARP Spoof Preprocessor} \label{sub:arpspoof} The ARP spoof preprocessor decodes ARP packets and detects ARP attacks, unicast ARP requests, and inconsistent Ethernet to IP mapping. When no arguments are specified to arpspoof, the preprocessor inspects Ethernet addresses and the addresses in the ARP packets. When inconsistency occurs, an alert with GID 112 and SID 2 or 3 is generated. When "\texttt{-unicast}" is specified as the argument of arpspoof, the preprocessor checks for unicast ARP requests. An alert with GID 112 and SID 1 will be generated if a unicast ARP request is detected. Specify a pair of IP and hardware address as the argument to \texttt{arpspoof\_detect\_host}. The host with the IP address should be on the same layer 2 segment as Snort is. Specify one host IP MAC combo per line. The preprocessor will use this list when detecting ARP cache overwrite attacks. Alert SID 4 is used in this case. \subsubsection{Format} \begin{verbatim} preprocessor arpspoof[: -unicast] preprocessor arpspoof_detect_host: ip mac \end{verbatim} \begin{table}[h] \begin{center} \begin{tabular}{| l | l |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{ip} & IP address.\\ \hline \texttt{mac} & The Ethernet address corresponding to the preceding IP. \\ \hline \end{tabular} \end{center} \end{table} \subsubsection{Example Configuration} The first example configuration does neither unicast detection nor ARP mapping monitoring. The preprocessor merely looks for Ethernet address inconsistencies. \begin{verbatim} preprocessor arpspoof \end{verbatim} The next example configuration does not do unicast detection but monitors ARP mapping for hosts 192.168.40.1 and 192.168.40.2. \begin{verbatim} preprocessor arpspoof preprocessor arpspoof_detect_host: 192.168.40.1 f0:0f:00:f0:0f:00 preprocessor arpspoof_detect_host: 192.168.40.2 f0:0f:00:f0:0f:01 \end{verbatim} The third example configuration has unicast detection enabled. \begin{verbatim} preprocessor arpspoof: -unicast preprocessor arpspoof_detect_host: 192.168.40.1 f0:0f:00:f0:0f:00 preprocessor arpspoof_detect_host: 192.168.40.2 f0:0f:00:f0:0f:01 \end{verbatim} \subsection{DCE/RPC 2 Preprocessor} \label{sub:dcerpc2} The main purpose of the preprocessor is to perform SMB desegmentation and DCE/RPC defragmentation to avoid rule evasion using these techniques. SMB desegmentation is performed for the following commands that can be used to transport DCE/RPC requests and responses: \texttt{Write}, \texttt{Write Block Raw}, \texttt{Write and Close}, \texttt{Write AndX}, \texttt{Transaction}, \texttt{Transaction Secondary}, \texttt{Read}, \texttt{Read Block Raw} and \texttt{Read AndX}. The following transports are supported for DCE/RPC: SMB, TCP, UDP and RPC over HTTP v.1 proxy and server. New rule options have been implemented to improve performance, reduce false positives and reduce the count and complexity of DCE/RPC based rules. \subsubsection{Dependency Requirements} For proper functioning of the preprocessor: \begin{itemize} \item Stream session tracking must be enabled, i.e. \texttt{stream5}. The preprocessor requires a session tracker to keep its data. \item Stream reassembly must be performed for TCP sessions. If it is decided that a session is SMB or DCE/RPC, either through configured ports, servers or autodetecting, the \texttt{dcerpc2} preprocessor will enable stream reassembly for that session if necessary. \item IP defragmentation should be enabled, i.e. the \texttt{frag3} preprocessor should be enabled and configured. \end{itemize} \subsubsection{Target Based} There are enough important differences between Windows and Samba versions that a target based approach has been implemented. Some important differences:\\ \textit{Named pipe instance tracking} \begin{itemize} \item[] A combination of valid login handle or UID, share handle or TID and file/named pipe handle or FID must be used to write data to a named pipe. The binding between these is dependent on OS/software version. \begin{itemize} \item[] Samba 3.0.22 and earlier \begin{itemize} \item[] Any valid UID and TID, along with a valid FID can be used to make a request, however, if the TID used in creating the FID is deleted (via a tree disconnect), the FID that was created using this TID becomes invalid, i.e. no more requests can be written to that named pipe instance. \end{itemize} \item[] Samba greater than 3.0.22 \begin{itemize} \item[] Any valid TID, along with a valid FID can be used to make a request. However, only the UID used in opening the named pipe can be used to make a request using the FID handle to the named pipe instance. If the TID used to create the FID is deleted (via a tree disconnect), the FID that was created using this TID becomes invalid, i.e. no more requests can be written to that named pipe instance. If the UID used to create the named pipe instance is deleted (via a \texttt{Logoff AndX}), since it is necessary in making a request to the named pipe, the FID becomes invalid. \end{itemize} \item[] Windows 2003 \item[] Windows XP \item[] Windows Vista \begin{itemize} \item[] These Windows versions require strict binding between the UID, TID and FID used to make a request to a named pipe instance. Both the UID and TID used to open the named pipe instance must be used when writing data to the same named pipe instance. Therefore, deleting either the UID or TID invalidates the FID. \end{itemize} \item[] Windows 2000 \begin{itemize} \item[] Windows 2000 is interesting in that the first request to a named pipe must use the same binding as that of the other Windows versions. However, requests after that follow the same binding as Samba 3.0.22 and earlier, i.e. no binding. It also follows Samba greater than 3.0.22 in that deleting the UID or TID used to create the named pipe instance also invalidates it. \end{itemize} \end{itemize} \end{itemize} \textit{Accepted SMB commands} \begin{itemize} \item[] Samba in particular does not recognize certain commands under an \texttt{IPC\$} tree. \begin{itemize} \item[] Samba (all versions) \begin{itemize} \item[] Under an \texttt{IPC\$} tree, does not accept: \begin{itemize} \item[] \texttt{Open} \item[] \texttt{Write And Close} \item[] \texttt{Read} \item[] \texttt{Read Block Raw} \item[] \texttt{Write Block Raw} \end{itemize} \end{itemize} \item[] Windows (all versions) \begin{itemize} \item[] Accepts all of the above commands under an \texttt{IPC\$} tree. \end{itemize} \end{itemize} \end{itemize} \textit{AndX command chaining} \begin{itemize} \item[] Windows is very strict in what command combinations it allows to be chained. Samba, on the other hand, is very lax and allows some nonsensical combinations, e.g. multiple logins and tree connects (only one place to return handles for these), login/logoff and tree connect/tree disconnect. Ultimately, we don't want to keep track of data that the server won't accept. An evasion possibility would be accepting a fragment in a request that the server won't accept that gets sandwiched between an exploit. \end{itemize} \textit{Transaction tracking} \begin{itemize} \item[] The differences between a \texttt{Transaction} request and using one of the \texttt{Write*} commands to write data to a named pipe are that (1) a \texttt{Transaction} performs the operations of a write and a read from the named pipe, whereas in using the \texttt{Write*} commands, the client has to explicitly send one of the \texttt{Read*} requests to tell the server to send the response and (2) a \texttt{Transaction} request is not written to the named pipe until all of the data is received (via potential \texttt{Transaction Secondary} requests) whereas with the \texttt{Write*} commands, data is written to the named pipe as it is received by the server. Multiple Transaction requests can be made simultaneously to the same named pipe. These requests can also be segmented with \texttt{Transaction Secondary} commands. What distinguishes them (when the same named pipe is being written to, i.e. having the same FID) are fields in the SMB header representing a process id (PID) and multiplex id (MID). The PID represents the process this request is a part of. An MID represents different sub-processes within a process (or under a PID). Segments for each "thread" are stored separately and written to the named pipe when all segments are received. It is necessary to track this so as not to munge these requests together (which would be a potential evasion opportunity). \begin{itemize} \item[] Windows (all versions) \begin{itemize} \item[] Uses a combination of PID and MID to define a "thread". \end{itemize} \item[] Samba (all versions) \begin{itemize} \item[] Uses just the MID to define a "thread". \end{itemize} \end{itemize} \end{itemize} \textit{Multiple Bind Requests} \begin{itemize} \item[] A \texttt{Bind} request is the first request that must be made in a connection-oriented DCE/RPC session in order to specify the interface/interfaces that one wants to communicate with. \begin{itemize} \item[] Windows (all versions) \begin{itemize} \item[] For all of the Windows versions, only one \texttt{Bind} can ever be made on a session whether or not it succeeds or fails. Any binding after that must use the \texttt{Alter Context} request. If another \texttt{Bind} is made, all previous interface bindings are invalidated. \end{itemize} \item[] Samba 3.0.20 and earlier \begin{itemize} \item[] Any amount of \texttt{Bind} requests can be made. \end{itemize} \item[] Samba later than 3.0.20 \begin{itemize} \item[] Another \texttt{Bind} request can be made if the first failed and no interfaces were successfully bound to. If a \texttt{Bind} after a successful \texttt{Bind} is made, all previous interface bindings are invalidated. \end{itemize} \end{itemize} \end{itemize} \textit{DCE/RPC Fragmented requests - Context ID} \begin{itemize} \item[] Each fragment in a fragmented request carries the context id of the bound interface it wants to make the request to. \begin{itemize} \item[] Windows (all versions) \begin{itemize} \item[] The context id that is ultimately used for the request is contained in the first fragment. The context id field in any other fragment can contain any value. \end{itemize} \item[] Samba (all versions) \begin{itemize} \item[] The context id that is ultimately used for the request is contained in the last fragment. The context id field in any other fragment can contain any value. \end{itemize} \end{itemize} \end{itemize} \textit{DCE/RPC Fragmented requests - Operation number} \begin{itemize} \item[] Each fragment in a fragmented request carries an operation number (opnum) which is more or less a handle to a function offered by the interface. \begin{itemize} \item[] Samba (all versions) \item[] Windows 2000 \item[] Windows 2003 \item[] Windows XP \begin{itemize} \item[] The opnum that is ultimately used for the request is contained in the last fragment. The opnum field in any other fragment can contain any value. \end{itemize} \item[] Windows Vista \begin{itemize} \item[] The opnum that is ultimately used for the request is contained in the first fragment. The opnum field in any other fragment can contain any value. \end{itemize} \end{itemize} \end{itemize} \textit{DCE/RPC Stub data byte order} \begin{itemize} \item[] The byte order of the stub data is determined differently for Windows and Samba. \begin{itemize} \item[] Windows (all versions) \begin{itemize} \item[] The byte order of the stub data is that which was used in the \texttt{Bind} request. \end{itemize} \item[] Samba (all versions) \begin{itemize} \item[] The byte order of the stub data is that which is used in the request carrying the stub data. \end{itemize} \end{itemize} \end{itemize} \subsubsection{Configuration} The \texttt{dcerpc2} preprocessor has a global configuration and one or more server configurations. The global preprocessor configuration name is \texttt{dcerpc2} and the server preprocessor configuration name is \texttt{dcerpc2\_server}.\\ \underline{Global Configuration} \begin{verbatim} preprocessor dcerpc2 \end{verbatim} The global \texttt{dcerpc2} configuration is required. Only one global \texttt{dcerpc2} configuration can be specified.\\ \textit{Option syntax} \begin{itemize} \item[] \begin{tabular}{|l|c|c|p{6cm}|} \hline Option & Argument & Required & Default\\ \hline \hline \texttt{memcap} & \texttt{} & NO & \texttt{memcap 102400}\\ \hline \texttt{disable\_defrag} & NONE & NO & OFF\\ \hline \texttt{max\_frag\_len} & \texttt{} & NO & OFF\\ \hline \texttt{events} & \texttt{} & NO & OFF\\ \hline \texttt{reassemble\_threshold} & \texttt{} & NO & OFF\\ \hline \texttt{disabled} & NONE & NO & OFF\\ \hline \texttt{smb\_fingerprint\_policy} & \texttt{} & NO & OFF\\ \hline \end{tabular} \end{itemize} \footnotesize \begin{verbatim} memcap = 1024-4194303 (kilobytes) max-frag-len = 1514-65535 events = pseudo-event | event | '[' event-list ']' pseudo-event = "none" | "all" event-list = event | event ',' event-list event = "memcap" | "smb" | "co" | "cl" re-thresh = 0-65535 fp-policy = "server" | "client" | "both" \end{verbatim} \normalsize \textit{Option explanations} \begin{itemize} \item[] \texttt{memcap} \begin{itemize} \item[] Specifies the maximum amount of run-time memory that can be allocated. Run-time memory includes any memory allocated after configuration. Default is 100 MB. \end{itemize} \item[] \texttt{disabled} \begin{itemize} \item[] Disables the preprocessor. By default this value is turned off. When the preprocessor is disabled only the memcap option is applied when specified with the configuration. \end{itemize} \item[] \texttt{disable\_defrag} \begin{itemize} \item[] Tells the preprocessor not to do DCE/RPC defragmentation. Default is to do defragmentation. \end{itemize} \item[] \texttt{max\_frag\_len} \begin{itemize} \item[] Specifies the maximum fragment size that will be added to the defragmentation module. If a fragment is greater than this size, it is truncated before being added to the defragmentation module. The allowed range for this option is 1514 - 65535. \end{itemize} \item[] \texttt{events} \begin{itemize} \item[] Specifies the classes of events to enable. (See Events section for an enumeration and explanation of events.) \begin{itemize} \item[] \texttt{memcap} \begin{itemize} \item[] Only one event. If the memcap is reached or exceeded, alert. \end{itemize} \item[] \texttt{smb} \begin{itemize} \item[] Alert on events related to SMB processing. \end{itemize} \item[] \texttt{co} \begin{itemize} \item[] Stands for connection-oriented DCE/RPC. Alert on events related to connection-oriented DCE/RPC processing. \end{itemize} \item[] \texttt{cl} \begin{itemize} \item[] Stands for connectionless DCE/RPC. Alert on events related to connectionless DCE/RPC processing. \end{itemize} \end{itemize} \end{itemize} \item[] \texttt{reassemble\_threshold} \begin{itemize} \item[] Specifies a minimum number of bytes in the DCE/RPC desegmentation and defragmentation buffers before creating a reassembly packet to send to the detection engine. This option is useful in inline mode so as to potentially catch an exploit early before full defragmentation is done. A value of 0 supplied as an argument to this option will, in effect, disable this option. Default is disabled. \end{itemize} \item[] \texttt{smb\_fingerprint\_policy} \begin{itemize} \item[] In the initial phase of an SMB session, the client needs to authenticate with a SessionSetupAndX. Both the request and response to this command contain OS and version information that can allow the preprocessor to dynamically set the policy for a session which allows for better protection against Windows and Samba specific evasions. \end{itemize} \end{itemize} \textit{Option examples} \footnotesize \begin{verbatim} memcap 30000 max_frag_len 16840 events none events all events smb events co events [co] events [smb, co] events [memcap, smb, co, cl] reassemble_threshold 500 smb_fingerprint_policy both smb_fingerprint_policy client \end{verbatim} \normalsize \textit{Configuration examples} \footnotesize \begin{verbatim} preprocessor dcerpc2 preprocessor dcerpc2: memcap 500000 preprocessor dcerpc2: max_frag_len 16840, memcap 300000, events smb preprocessor dcerpc2: memcap 50000, events [memcap, smb, co, cl], max_frag_len 14440 preprocessor dcerpc2: disable_defrag, events [memcap, smb] preprocessor dcerpc2: reassemble_threshold 500 preprocessor dcerpc2: memcap 50000, events [memcap, smb, co, cl], max_frag_len 14440, smb_fingerprint_policy both \end{verbatim} \normalsize \textit{Default global configuration} \footnotesize \begin{verbatim} preprocessor dcerpc2: memcap 102400 \end{verbatim} \normalsize \underline{Server Configuration} \begin{verbatim} preprocessor dcerpc2_server \end{verbatim} The \texttt{dcerpc2\_server} configuration is optional. A \texttt{dcerpc2\_server} configuration must start with \texttt{default} or \texttt{net} options. The \texttt{default} and \texttt{net} options are mutually exclusive. At most one default configuration can be specified. If no \texttt{default} configuration is specified, default values will be used for the \texttt{default} configuration. Zero or more \texttt{net} configurations can be specified. For any \texttt{dcerpc2\_server} configuration, if non-required options are not specified, the defaults will be used. When processing DCE/RPC traffic, the \texttt{default} configuration is used if no net configurations match. If a \texttt{net} configuration matches, it will override the \texttt{default} configuration. A \texttt{net} configuration matches if the packet's server IP address matches an IP address or net specified in the \texttt{net} configuration. The \texttt{net} option supports IPv6 addresses. Note that port and ip variables defined in \texttt{snort.conf} \textsc{cannot} be used. \textit{Option syntax} \begin{itemize} \item[] \begin{tabular}{|l|c|c|p{6cm}|} \hline Option & Argument & Required & Default\\ \hline \hline \texttt{default} & NONE & YES & NONE\\ \hline \texttt{net} & \texttt{} & YES & NONE\\ \hline \texttt{policy} & \texttt{} & NO & \texttt{policy WinXP}\\ \hline \texttt{detect} & \texttt{} & NO & \texttt{detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server 593]}\\ \hline \texttt{autodetect} & \texttt{} & NO & \texttt{autodetect [tcp 1025:, udp 1025:, rpc-over-http-server 1025:]}\\ \hline \texttt{no\_autodetect\_http\_proxy\_ports} & NONE & NO & DISABLED (The preprocessor autodetects on all proxy ports by default)\\ \hline \texttt{smb\_invalid\_shares} & \texttt{} & NO & NONE\\ \hline \texttt{smb\_max\_chain} & \texttt{} & NO & \texttt{smb\_max\_chain 3}\\ \hline \texttt{smb\_file\_inspection} & \texttt{} & NO & \texttt{smb\_file\_inspection off}\\ \hline \end{tabular} \end{itemize} \footnotesize \begin{verbatim} net = ip | '[' ip-list ']' ip-list = ip | ip ',' ip-list ip = ip-addr | ip-addr '/' prefix | ip4-addr '/' netmask ip-addr = ip4-addr | ip6-addr ip4-addr = a valid IPv4 address ip6-addr = a valid IPv6 address (can be compressed) prefix = a valid CIDR netmask = a valid netmask policy = "Win2000" | "Win2003" | "WinXP" | "WinVista" | "Samba" | "Samba-3.0.22" | "Samba-3.0.20" detect = "none" | detect-opt | '[' detect-list ']' detect-list = detect-opt | detect-opt ',' detect-list detect-opt = transport | transport port-item | transport '[' port-list ']' transport = "smb" | "tcp" | "udp" | "rpc-over-http-proxy" | "rpc-over-http-server" port-list = port-item | port-item ',' port-list port-item = port | port-range port-range = ':' port | port ':' | port ':' port port = 0-65535 shares = share | '[' share-list ']' share-list = share | share ',' share-list share = word | '"' word '"' | '"' var-word '"' word = graphical ASCII characters except ',' '"' ']' '[' '$' var-word = graphical ASCII characters except ',' '"' ']' '[' max-chain = 0-255 file-inspect = file-arg | '[' file-list ']' file-arg = "off" | "on" | "only" file-list = file-arg [ ',' "file-depth" ] \end{verbatim} \normalsize \begin{itemize} \item[] Because the Snort main parser treats '\$' as the start of a variable and tries to expand it, shares with '\$' must be enclosed quotes. \end{itemize} \textit{Option explanations} \begin{itemize} \item[] \texttt{default} \begin{itemize} \item[] Specifies that this configuration is for the default server configuration. \end{itemize} \item[] \texttt{net} \begin{itemize} \item[] Specifies that this configuration is an IP or net specific configuration. The configuration will only apply to the IP addresses and nets supplied as an argument. \end{itemize} \item[] \texttt{policy} \begin{itemize} \item[] Specifies the target-based policy to use when processing. Default is "WinXP". \end{itemize} \item[] \texttt{detect} \begin{itemize} \item[] Specifies the DCE/RPC transport and server ports that should be detected on for the transport. Defaults are ports 139 and 445 for SMB, 135 for TCP and UDP, 593 for RPC over HTTP server and 80 for RPC over HTTP proxy. \end{itemize} \item[] \texttt{autodetect} \begin{itemize} \item[] Specifies the DCE/RPC transport and server ports that the preprocessor should attempt to autodetect on for the transport. The autodetect ports are only queried if no detect transport/ports match the packet. The order in which the preprocessor will attempt to autodetect will be - TCP/UDP, RPC over HTTP server, RPC over HTTP proxy and lastly SMB. Note that most dynamic DCE/RPC ports are above 1024 and ride directly over TCP or UDP. It would be very uncommon to see SMB on anything other than ports 139 and 445. Defaults are 1025-65535 for TCP, UDP and RPC over HTTP server. \end{itemize} \item[] \texttt{no\_autodetect\_http\_proxy\_ports} \begin{itemize} \item[] By default, the preprocessor will always attempt to autodetect for ports specified in the detect configuration for rpc-over-http-proxy. This is because the proxy is likely a web server and the preprocessor should not look at all web traffic. This option is useful if the RPC over HTTP proxy configured with the detect option is only used to proxy DCE/RPC traffic. Default is to autodetect on RPC over HTTP proxy detect ports. \end{itemize} \item[] \texttt{smb\_invalid\_shares} \begin{itemize} \item[] Specifies SMB shares that the preprocessor should alert on if an attempt is made to connect to them via a \texttt{Tree Connect} or \texttt{Tree Connect AndX}. Default is empty. \end{itemize} \item[] \texttt{smb\_max\_chain} \begin{itemize} \item[] Specifies the maximum amount of AndX command chaining that is allowed before an alert is generated. Default maximum is 3 chained commands. A value of 0 disables this option. This value can be set from 0 to 255. \end{itemize} \item[] \texttt{smb\_file\_inspection} \begin{itemize} \item[] Instructs the preprocessor to do inspection of normal SMB file transfers. This includes doing file type and signature through the file API as well as setting a pointer for the \texttt{file\_data} rule option. Note that the \texttt{file-depth} option only applies to the maximum amount of file data for which it will set the pointer for the \texttt{file\_data} rule option. For file type and signature it will use the value configured for the file API. If \texttt{only} is specified, the preprocessor will only do SMB file inspection, i.e. it will not do any DCE/RPC tracking or inspection. If \texttt{on} is specified with no arguments, the default file depth is 16384 bytes. An argument of -1 to \texttt{file-depth} disables setting the pointer for \texttt{file\_data}, effectively disabling SMB file inspection in rules. An argument of 0 to \texttt{file-depth} means unlimited. Default is \texttt{off}, i.e. no SMB file inspection is done in the preprocessor. \end{itemize} \end{itemize} \textit{Option examples} \footnotesize \begin{verbatim} net 192.168.0.10 net 192.168.0.0/24 net [192.168.0.0/24] net 192.168.0.0/255.255.255.0 net feab:45b3:ab92:8ac4:d322:007f:e5aa:7845 net feab:45b3:ab92:8ac4:d322:007f:e5aa:7845/128 net feab:45b3::/32 net [192.168.0.10, feab:45b3::/32] net [192.168.0.0/24, feab:45b3:ab92:8ac4:d322:007f:e5aa:7845] policy Win2000 policy Samba-3.0.22 detect none detect smb detect [smb] detect smb 445 detect [smb 445] detect smb [139,445] detect [smb [139,445]] detect [smb, tcp] detect [smb 139, tcp [135,2103]] detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server [593,6002:6004]] autodetect none autodetect tcp autodetect [tcp] autodetect tcp 2025: autodetect [tcp 2025:] autodetect tcp [2025:3001,3003:] autodetect [tcp [2025:3001,3003:]] autodetect [tcp, udp] autodetect [tcp 2025:, udp 2025:] autodetect [tcp 2025:, udp, rpc-over-http-server [1025:6001,6005:]] smb_invalid_shares private smb_invalid_shares "private" smb_invalid_shares "C$" smb_invalid_shares [private, "C$"] smb_invalid_shares ["private", "C$"] smb_max_chain 1 smb_file_inspection on smb_file_inspection off smb_file_inspection [ on, file-depth -1 ] smb_file_inspection [ on, file-depth 0 ] smb_file_inspection [ on, file-depth 4294967296 ] smb_file_inspection [ only, file-depth -1 ] \end{verbatim} \normalsize \textit{Configuration examples} \footnotesize \begin{verbatim} preprocessor dcerpc2_server: \ default preprocessor dcerpc2_server: \ default, policy Win2000 preprocessor dcerpc2_server: \ default, policy Win2000, detect [smb, tcp], autodetect tcp 1025:, \ smb_invalid_shares ["C$", "D$", "ADMIN$"] preprocessor dcerpc2_server: net 10.4.10.0/24, policy Win2000 preprocessor dcerpc2_server: \ net [10.4.10.0/24,feab:45b3::/126], policy WinVista, smb_max_chain 1 preprocessor dcerpc2_server: \ net [10.4.10.0/24,feab:45b3::/126], policy WinVista, \ detect [smb, tcp, rpc-over-http-proxy 8081], autodetect [tcp, rpc-over-http-proxy [1025:6001,6005:]], \ smb_invalid_shares ["C$", "ADMIN$"], no_autodetect_http_proxy_ports preprocessor dcerpc2_server: \ net [10.4.11.56,10.4.11.57], policy Samba, detect smb, autodetect none preprocessor dcerpc2_server: default, policy WinXP, \ smb_file_inspection [ on, file-depth 0 ] \end{verbatim} \normalsize \textit{Default server configuration} \footnotesize \begin{verbatim} preprocessor dcerpc2_server: default, policy WinXP, \ detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server 593], \ autodetect [tcp 1025:, udp 1025:, rpc-over-http-server 1025:], \ smb_max_chain 3, smb_file_inspection off \end{verbatim} \normalsize \underline{Complete \texttt{dcerpc2} default configuration} \footnotesize \begin{verbatim} preprocessor dcerpc2: memcap 102400 preprocessor dcerpc2_server: \ default, policy WinXP, \ detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server 593], \ autodetect [tcp 1025:, udp 1025:, rpc-over-http-server 1025:], \ smb_max_chain 3, smb_file_inspection off \end{verbatim} \normalsize \subsubsection{Events} The preprocessor uses GID 133 to register events.\\ \textit{Memcap events} \begin{itemize} \item[] \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline \hline 1 & If the memory cap is reached and the preprocessor is configured to alert.\\ \hline \end{longtable} \end{itemize} \textit{SMB events} \begin{itemize} \item[] \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline \hline 2 & An invalid NetBIOS Session Service type was specified in the header. Valid types are: \texttt{Message}, \texttt{Request} (only from client), \texttt{Positive Response} (only from server), \texttt{Negative Response} (only from server), \texttt{Retarget Response} (only from server) and \texttt{Keep Alive}.\\ \hline 3 & An SMB message type was specified in the header. Either a request was made by the server or a response was given by the client.\\ \hline 4 & The SMB id does not equal \texttt{\textbackslash xffSMB}. Note that since the preprocessor does not yet support SMB2, id of \texttt{\textbackslash xfeSMB} is turned away before an eventable point is reached.\\ \hline 5 & The word count of the command header is invalid. SMB commands have pretty specific word counts and if the preprocessor sees a command with a word count that doesn't jive with that command, the preprocessor will alert.\\ \hline 6 & Some commands require a minimum number of bytes after the command header. If a command requires this and the byte count is less than the minimum required byte count for that command, the preprocessor will alert.\\ \hline 7 & Some commands, especially the commands from the SMB Core implementation require a data format field that specifies the kind of data that will be coming next. Some commands require a specific format for the data. The preprocessor will alert if the format is not that which is expected for that command.\\ \hline 8 & Many SMB commands have a field containing an offset from the beginning of the SMB header to where the data the command is carrying starts. If this offset puts us before data that has already been processed or after the end of payload, the preprocessor will alert.\\ \hline 9 & Some SMB commands, such as \texttt{Transaction}, have a field containing the total amount of data to be transmitted. If this field is zero, the preprocessor will alert.\\ \hline 10 & The preprocessor will alert if the NetBIOS Session Service length field contains a value less than the size of an SMB header.\\ \hline 11 & The preprocessor will alert if the remaining NetBIOS packet length is less than the size of the SMB command header to be decoded.\\ \hline 12 & The preprocessor will alert if the remaining NetBIOS packet length is less than the size of the SMB command byte count specified in the command header.\\ \hline 13 & The preprocessor will alert if the remaining NetBIOS packet length is less than the size of the SMB command data size specified in the command header.\\ \hline 14 & The preprocessor will alert if the total data count specified in the SMB command header is less than the data size specified in the SMB command header. (Total data count must always be greater than or equal to current data size.)\\ \hline 15 & The preprocessor will alert if the total amount of data sent in a transaction is greater than the total data count specified in the SMB command header.\\ \hline 16 & The preprocessor will alert if the byte count specified in the SMB command header is less than the data size specified in the SMB command. (The byte count must always be greater than or equal to the data size.)\\ \hline 17 & Some of the Core Protocol commands (from the initial SMB implementation) require that the byte count be some value greater than the data size exactly. The preprocessor will alert if the byte count minus a predetermined amount based on the SMB command is not equal to the data size.\\ \hline 18 & For the \texttt{Tree Connect} command (and not the \texttt{Tree Connect AndX} command), the preprocessor has to queue the requests up and wait for a server response to determine whether or not an IPC share was successfully connected to (which is what the preprocessor is interested in). Unlike the \texttt{Tree Connect AndX} response, there is no indication in the \texttt{Tree Connect} response as to whether the share is IPC or not. There should be under normal circumstances no more than a few pending tree connects at a time and the preprocessor will alert if this number is excessive.\\ \hline 19 & After a client is done writing data using the \texttt{Write*} commands, it issues a \texttt{Read*} command to the server to tell it to send a response to the data it has written. In this case the preprocessor is concerned with the server response. The \texttt{Read*} request contains the file id associated with a named pipe instance that the preprocessor will ultimately send the data to. The server response, however, does not contain this file id, so it need to be queued with the request and dequeued with the response. If multiple \texttt{Read*} requests are sent to the server, they are responded to in the order they were sent. There should be under normal circumstances no more than a few pending \texttt{Read*} requests at a time and the preprocessor will alert if this number is excessive.\\ \hline 20 & The preprocessor will alert if the number of chained commands in a single request is greater than or equal to the configured amount (default is 3).\\ \hline 21 & With \texttt{AndX} command chaining it is possible to chain multiple \texttt{Session Setup AndX} commands within the same request. There is, however, only one place in the SMB header to return a login handle (or Uid). Windows does not allow this behavior, however Samba does. This is anomalous behavior and the preprocessor will alert if it happens.\\ \hline 22 & With \texttt{AndX} command chaining it is possible to chain multiple \texttt{Tree Connect AndX} commands within the same request. There is, however, only one place in the SMB header to return a tree handle (or Tid). Windows does not allow this behavior, however Samba does. This is anomalous behavior and the preprocessor will alert if it happens.\\ \hline 23 & When a \texttt{Session Setup AndX} request is sent to the server, the server responds (if the client successfully authenticates) which a user id or login handle. This is used by the client in subsequent requests to indicate that it has authenticated. A \texttt{Logoff AndX} request is sent by the client to indicate it wants to end the session and invalidate the login handle. With commands that are chained after a \texttt{Session Setup AndX} request, the login handle returned by the server is used for the subsequent chained commands. The combination of a \texttt{Session Setup AndX} command with a chained \texttt{Logoff AndX} command, essentially logins in and logs off in the same request and is anomalous behavior. The preprocessor will alert if it sees this.\\ \hline 24 & A \texttt{Tree Connect AndX} command is used to connect to a share. The \texttt{Tree Disconnect} command is used to disconnect from that share. The combination of a \texttt{Tree Connect AndX} command with a chained \texttt{Tree Disconnect} command, essentially connects to a share and disconnects from the same share in the same request and is anomalous behavior. The preprocessor will alert if it sees this.\\ \hline 25 & An \texttt{Open AndX} or \texttt{Nt Create AndX} command is used to open/create a file or named pipe. (The preprocessor is only interested in named pipes as this is where DCE/RPC requests are written to.) The \texttt{Close} command is used to close that file or named pipe. The combination of a \texttt{Open AndX} or \texttt{Nt Create AndX} command with a chained \texttt{Close} command, essentially opens and closes the named pipe in the same request and is anomalous behavior. The preprocessor will alert if it sees this.\\ \hline 26 & The preprocessor will alert if it sees any of the invalid SMB shares configured. It looks for a \texttt{Tree Connect} or \texttt{Tree Connect AndX} to the share.\\ \hline 48 & The preprocessor will alert if a data count for a Core dialect write command is zero.\\ \hline 49 & For some of the Core dialect commands such as \texttt{Write} and \texttt{Read}, there are two data count fields, one in the main command header and one in the data format section. If these aren't the same, the preprocessor will alert.\\ \hline 50 & In the initial negotiation phase of an SMB session, the server in a \texttt{Negotiate} response and the client in a \texttt{SessionSetupAndX} request will advertise the maximum number of outstanding requests supported. The preprocessor will alert if the lesser of the two is exceeded.\\ \hline 51 & When a client sends a request it uses a value called the MID (multiplex id) to match a response, which the server is supposed to echo, to a request. If there are multiple outstanding requests with the same MID, the preprocessor will alert.\\ \hline 52 & In the \texttt{Negotiate} request a client gives a list of SMB dialects it supports, normally in order from least desirable to most desirable and the server responds with the index of the dialect to be used on the SMB session. Anything less than "NT LM 0.12" would be very odd these days (even Windows 98 supports it) and the preprocessor will alert if the client doesn't offer it as a supported dialect or the server chooses a lesser dialect.\\ \hline 53 & There are a number of commands that are considered deprecated and/or obsolete by Microsoft (see MS-CIFS and MS-SMB). If the preprocessor detects the use of a deprecated/obsolete command used it will alert.\\ \hline 54 & There are some commands that can be used that can be considered unusual in the context they are used. These include some of the transaction commands such as: \texttt{SMB\_COM\_TRANSACTION / TRANS\_READ\_NMPIPE} \texttt{SMB\_COM\_TRANSACTION / TRANS\_WRITE\_NMPIPE} \texttt{SMB\_COM\_TRANSACTION2 / TRANS2\_OPEN2} \texttt{SMB\_COM\_NT\_TRANSACT / NT\_TRANSACT\_CREATE} The preprocessor will alert if it detects unusual use of a command.\\ \hline 55 & Transaction commands have a setup count field that indicates the number of 16bit words in the transaction setup. The preprocessor will alert if the setup count is invalid for the transaction command / sub command.\\ \hline 56 & There can be only one Negotiate transaction per session and it is the first thing a client and server do to determine the SMB dialect each supports. The preprocessor will alert if the client attempts multiple dialect negotiations.\\ \hline 57 & Malware will often set a file's attributes to ReadOnly/Hidden/System if it is successful in installing itself as a Windows service or is able to write an autorun.inf file since it doesn't want the user to see the file and the default folder options in Windows is not to display Hidden files. The preprocessor will alert if it detects a client attempt to set a file's attributes to ReadOnly/Hidden/System.\\ \hline \end{longtable} \end{itemize} \textit{Connection-oriented DCE/RPC events} \begin{itemize} \item[] \begin{longtable}[h]{|r|p{13.5cm}|} \hline SID & Description\\ \hline \hline 27 & The preprocessor will alert if the connection-oriented DCE/RPC major version contained in the header is not equal to 5.\\ \hline 28 & The preprocessor will alert if the connection-oriented DCE/RPC minor version contained in the header is not equal to 0.\\ \hline 29 & The preprocessor will alert if the connection-oriented DCE/RPC PDU type contained in the header is not a valid PDU type.\\ \hline 30 & The preprocessor will alert if the fragment length defined in the header is less than the size of the header.\\ \hline 31 & The preprocessor will alert if the remaining fragment length is less than the remaining packet size.\\ \hline 32 & The preprocessor will alert if in a \texttt{Bind} or \texttt{Alter Context} request, there are no context items specified.\\ \hline 33 & The preprocessor will alert if in a \texttt{Bind} or \texttt{Alter Context} request, there are no transfer syntaxes to go with the requested interface.\\ \hline 34 & The preprocessor will alert if a non-last fragment is less than the size of the negotiated maximum fragment length. Most evasion techniques try to fragment the data as much as possible and usually each fragment comes well below the negotiated transmit size.\\ \hline 35 & The preprocessor will alert if a fragment is larger than the maximum negotiated fragment length.\\ \hline 36 & The byte order of the request data is determined by the Bind in connection-oriented DCE/RPC for Windows. It is anomalous behavior to attempt to change the byte order mid-session.\\ \hline 37 & The call id for a set of fragments in a fragmented request should stay the same (it is incremented for each complete request). The preprocessor will alert if it changes in a fragment mid-request.\\ \hline 38 & The operation number specifies which function the request is calling on the bound interface. If a request is fragmented, this number should stay the same for all fragments. The preprocessor will alert if the opnum changes in a fragment mid-request.\\ \hline 39 & The context id is a handle to a interface that was bound to. If a request if fragmented, this number should stay the same for all fragments. The preprocessor will alert if the context id changes in a fragment mid-request.\\ \hline \end{longtable} \end{itemize} \textit{Connectionless DCE/RPC events} \begin{itemize} \item[] \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline \hline 40 & The preprocessor will alert if the connectionless DCE/RPC major version is not equal to 4.\\ \hline 41 & The preprocessor will alert if the connectionless DCE/RPC PDU type is not a valid PDU type.\\ \hline 42 & The preprocessor will alert if the packet data length is less than the size of the connectionless header.\\ \hline 43 & The preprocessor will alert if the sequence number uses in a request is the same or less than a previously used sequence number on the session. In testing, wrapping the sequence number space produces strange behavior from the server, so this should be considered anomalous behavior.\\ \hline \end{longtable} \end{itemize} \subsubsection{Rule Options} New rule options are supported by enabling the \texttt{dcerpc2} preprocessor: \begin{itemize} \item[] \begin{verbatim} dce_iface dce_opnum dce_stub_data \end{verbatim} \end{itemize} New modifiers to existing \texttt{byte\_test} and \texttt{byte\_jump} rule options: \begin{itemize} \item[] \begin{verbatim} byte_test:dce byte_jump:dce \end{verbatim} \end{itemize} \texttt{dce\_iface} \label{dcerpc2:dce_iface} \begin{itemize} \item[] For DCE/RPC based rules it has been necessary to set flow-bits based on a client bind to a service to avoid false positives. It is necessary for a client to bind to a service before being able to make a call to it. When a client sends a bind request to the server, it can, however, specify one or more service interfaces to bind to. Each interface is represented by a UUID. Each interface UUID is paired with a unique index (or context id) that future requests can use to reference the service that the client is making a call to. The server will respond with the interface UUIDs it accepts as valid and will allow the client to make requests to those services. When a client makes a request, it will specify the context id so the server knows what service the client is making a request to. Instead of using flow-bits, a rule can simply ask the preprocessor, using this rule option, whether or not the client has bound to a specific interface UUID and whether or not this client request is making a request to it. This can eliminate false positives where more than one service is bound to successfully since the preprocessor can correlate the bind UUID to the context id used in the request. A DCE/RPC request can specify whether numbers are represented as big endian or little endian. The representation of the interface UUID is different depending on the endianness specified in the DCE/RPC previously requiring two rules - one for big endian and one for little endian. The preprocessor eliminates the need for two rules by normalizing the UUID. An interface contains a version. Some versions of an interface may not be vulnerable to a certain exploit. Also, a DCE/RPC request can be broken up into 1 or more fragments. Flags (and a field in the connectionless header) are set in the DCE/RPC header to indicate whether the fragment is the first, a middle or the last fragment. Many checks for data in the DCE/RPC request are only relevant if the DCE/RPC request is a first fragment (or full request), since subsequent fragments will contain data deeper into the DCE/RPC request. A rule which is looking for data, say 5 bytes into the request (maybe it's a length field), will be looking at the wrong data on a fragment other than the first, since the beginning of subsequent fragments are already offset some length from the beginning of the request. This can be a source of false positives in fragmented DCE/RPC traffic. By default it is reasonable to only evaluate if the request is a first fragment (or full request). However, if the \texttt{any\_frag} option is used to specify evaluating on all fragments.\\ \textit{Syntax} \footnotesize \begin{verbatim} dce_iface:[, ][, any_frag]; uuid = hexlong '-' hexshort '-' hexshort '-' 2hexbyte '-' 6hexbyte hexlong = 4hexbyte hexshort = 2hexbyte hexbyte = 2HEXDIGIT operator = '<' | '>' | '=' | '!' version = 0-65535 \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} dce_iface:4b324fc8-1670-01d3-1278-5a47bf6ee188; dce_iface:4b324fc8-1670-01d3-1278-5a47bf6ee188, <2; dce_iface:4b324fc8-1670-01d3-1278-5a47bf6ee188, any_frag; dce_iface:4b324fc8-1670-01d3-1278-5a47bf6ee188, =1, any_frag; \end{verbatim} \normalsize This option is used to specify an interface UUID. Optional arguments are an interface version and operator to specify that the version be less than ('\textless'), greater than ('\textgreater'), equal to ('=') or not equal to ('!') the version specified. Also, by default the rule will only be evaluated for a first fragment (or full request, i.e. not a fragment) since most rules are written to start at the beginning of a request. The \texttt{any\_frag} argument says to evaluate for middle and last fragments as well. This option requires tracking client \texttt{Bind} and \texttt{Alter Context} requests as well as server \texttt{Bind Ack} and \texttt{Alter Context} responses for connection-oriented DCE/RPC in the preprocessor. For each \texttt{Bind} and \texttt{Alter Context} request, the client specifies a list of interface UUIDs along with a handle (or context id) for each interface UUID that will be used during the DCE/RPC session to reference the interface. The server response indicates which interfaces it will allow the client to make requests to - it either accepts or rejects the client's wish to bind to a certain interface. This tracking is required so that when a request is processed, the context id used in the request can be correlated with the interface UUID it is a handle for. \texttt{hexlong} and \texttt{hexshort} will be specified and interpreted to be in big endian order (this is usually the default way an interface UUID will be seen and represented). As an example, the following Messenger interface UUID as taken off the wire from a little endian \texttt{Bind} request: \begin{verbatim} |f8 91 7b 5a 00 ff d0 11 a9 b2 00 c0 4f b6 e6 fc| \end{verbatim} must be written as: \begin{verbatim} 5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc \end{verbatim} The same UUID taken off the wire from a big endian \texttt{Bind} request: \begin{verbatim} |5a 7b 91 f8 ff 00 11 d0 a9 b2 00 c0 4f b6 e6 fc| \end{verbatim} must be written the same way: \begin{verbatim} 5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc \end{verbatim} This option matches if the specified interface UUID matches the interface UUID (as referred to by the context id) of the DCE/RPC request and if supplied, the version operation is true. This option will not match if the fragment is not a first fragment (or full request) unless the \texttt{any\_frag} option is supplied in which case only the interface UUID and version need match. Note that a defragmented DCE/RPC request will be considered a full request. \begin{note} Using this rule option will automatically insert fast pattern contents into the fast pattern matcher. For UDP rules, the interface UUID, in both big and little endian format will be inserted into the fast pattern matcher. For TCP rules, (1) if the rule option \texttt{flow:to\_server|from\_client} is used, $|$05 00 00$|$ will be inserted into the fast pattern matcher, (2) if the rule option \texttt{flow:from\_server|to\_client} is used, $|$05 00 02$|$ will be inserted into the fast pattern matcher and (3) if the flow isn't known, $|$05 00$|$ will be inserted into the fast pattern matcher. Note that if the rule already has content rule options in it, the best (meaning longest) pattern will be used. If a content in the rule uses the \texttt{fast\_pattern} rule option, it will unequivocally be used over the above mentioned patterns. \end{note} \end{itemize} \texttt{dce\_opnum} \label{dcerpc2:dce_opnum} \begin{itemize} \item[] The opnum represents a specific function call to an interface. After is has been determined that a client has bound to a specific interface and is making a request to it (see above - \texttt{dce\_iface}) usually we want to know what function call it is making to that service. It is likely that an exploit lies in the particular DCE/RPC function call.\\ \textit{Syntax} \footnotesize \begin{verbatim} dce_opnum:; opnum-list = opnum-item | opnum-item ',' opnum-list opnum-item = opnum | opnum-range opnum-range = opnum '-' opnum opnum = 0-65535 \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} dce_opnum:15; dce_opnum:15-18; dce_opnum:15, 18-20; dce_opnum:15, 17, 20-22; \end{verbatim} \normalsize This option is used to specify an opnum (or operation number), opnum range or list containing either or both opnum and/or opnum-range. The opnum of a DCE/RPC request will be matched against the opnums specified with this option. This option matches if any one of the opnums specified match the opnum of the DCE/RPC request. \end{itemize} \texttt{dce\_stub\_data} \label{dcerpc2:dce_stub_data} \begin{itemize} \item[] Since most netbios rules were doing protocol decoding only to get to the DCE/RPC stub data, i.e. the remote procedure call or function call data, this option will alleviate this need and place the cursor at the beginning of the DCE/RPC stub data. This reduces the number of rule option checks and the complexity of the rule. This option takes no arguments.\\ \textit{Example} \footnotesize \begin{verbatim} dce_stub_data; \end{verbatim} \normalsize This option is used to place the cursor (used to walk the packet payload in rules processing) at the beginning of the DCE/RPC stub data, regardless of preceding rule options. There are no arguments to this option. This option matches if there is DCE/RPC stub data. The cursor is moved to the beginning of the stub data. All ensuing rule options will be considered "sticky" to this buffer. The first rule option following \texttt{dce\_stub\_data} should use absolute location modifiers if it is position-dependent. Subsequent rule options should use a relative modifier if they are meant to be relative to a previous rule option match in the stub data buffer. Any rule option that does not specify a relative modifier will be evaluated from the start of the stub data buffer. To leave the stub data buffer and return to the main payload buffer, use the \texttt{pkt\_data} rule option - see section \ref{sub:pkt_data} for details). \end{itemize} \texttt{byte\_test} and \texttt{byte\_jump} with \texttt{dce}\label{dcerpc2:byte_test_jump} \begin{itemize} \item[] A DCE/RPC request can specify whether numbers are represented in big or little endian. These rule options will take as a new argument \texttt{dce} and will work basically the same as the normal \texttt{byte\_test}/\texttt{byte\_jump}, but since the DCE/RPC preprocessor will know the endianness of the request, it will be able to do the correct conversion. \texttt{byte\_test} \begin{itemize} \item[] \textit{Syntax} \footnotesize \begin{verbatim} byte_test:, [!], , [, relative], dce; convert = 1 | 2 | 4 (only with option "dce") operator = '<' | '=' | '>' | '<=' | '>=' | '&' | '^' value = 0 - 4294967295 offset = -65535 to 65535 \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} byte_test:4, >, 35000, 0, relative, dce; byte_test:2, !=, 2280, -10, relative, dce; \end{verbatim} \normalsize When using the \texttt{dce} argument to a \texttt{byte\_test}, the following normal \texttt{byte\_test} arguments will not be allowed: \texttt{big}, \texttt{little}, \texttt{string}, \texttt{hex}, \texttt{dec} and \texttt{oct}. \end{itemize} \texttt{byte\_jump} \begin{itemize} \item[] \textit{Syntax} \footnotesize \begin{verbatim} byte_jump:, [, relative][, multiplier ] \ [, align][, post_offset ], dce; convert = 1 | 2 | 4 (only with option "dce") offset = -65535 to 65535 mult_value = 0 - 65535 adjustment_value = -65535 to 65535 \end{verbatim} \normalsize \textit{Example} \footnotesize \begin{verbatim} byte_jump:4,-4,relative,align,multiplier 2,post_offset -4,dce; \end{verbatim} \normalsize When using the \texttt{dce} argument to a \texttt{byte\_jump}, the following normal \texttt{byte\_jump} arguments will not be allowed: \texttt{big}, \texttt{little}, \texttt{string}, \texttt{hex}, \texttt{dec}, \texttt{oct} and \texttt{from\_beginning}. \end{itemize} \end{itemize} \textit{Example of rule complexity reduction} \begin{itemize} \item[] The following two rules using the new rule options replace 64 (set and isset flowbit) rules that are necessary if the new rule options are not used: \footnotesize \begin{verbatim} alert tcp $EXTERNAL_NET any -> $HOME_NET [135,139,445,593,1024:] \ (msg:"dns R_Dnssrv funcs2 overflow attempt"; flow:established,to_server; \ dce_iface:50abc2a4-574d-40b3-9d66-ee4fd5fba076; dce_opnum:0-11; dce_stub_data; \ pcre:"/^.{12}(\x00\x00\x00\x00|.{12})/s"; byte_jump:4,-4,relative,align,dce; \ byte_test:4,>,256,4,relative,dce; reference:bugtraq,23470; reference:cve,2007-1748; \ classtype:attempted-admin; sid:1000068;) alert udp $EXTERNAL_NET any -> $HOME_NET [135,1024:] \ (msg:"dns R_Dnssrv funcs2 overflow attempt"; flow:established,to_server; \ dce_iface:50abc2a4-574d-40b3-9d66-ee4fd5fba076; dce_opnum:0-11; dce_stub_data; \ pcre:"/^.{12}(\x00\x00\x00\x00|.{12})/s"; byte_jump:4,-4,relative,align,dce; \ byte_test:4,>,256,4,relative,dce; reference:bugtraq,23470; reference:cve,2007-1748; \ classtype:attempted-admin; sid:1000069;) \end{verbatim} \normalsize \end{itemize} \subsection{Sensitive Data Preprocessor} \label{sub:sensitive_data} The Sensitive Data preprocessor is a Snort module that performs detection and filtering of Personally Identifiable Information (PII). This information includes credit card numbers, U.S. Social Security numbers, and email addresses. A limited regular expression syntax is also included for defining your own PII. \subsubsection{Dependencies} The Stream5 preprocessor must be enabled for the Sensitive Data preprocessor to work. \subsubsection{Preprocessor Configuration} Sensitive Data configuration is split into two parts: the preprocessor config, and the rule options. The preprocessor config starts with: \begin{verbatim} preprocessor sensitive_data: \end{verbatim} \textit{Option syntax} \begin{itemize} \item[] \begin{tabular}{|l|c|c|p{6cm}|} \hline Option & Argument & Required & Default\\ \hline \hline \texttt{alert\_threshold} & \texttt{} & NO & \texttt{alert\_threshold 25}\\ \hline \texttt{mask\_output} & NONE & NO & OFF\\ \hline \texttt{ssn\_file} & \texttt{} & NO & OFF\\ \hline \end{tabular} \end{itemize} \footnotesize \begin{verbatim} alert_threshold = 1 - 65535 \end{verbatim} \normalsize \textit{Option explanations} \begin{itemize} \item[] \texttt{alert\_threshold} \begin{itemize} \item[] The preprocessor will alert when any combination of PII are detected in a session. This option specifies how many need to be detected before alerting. This should be set higher than the highest individual count in your "sd\_pattern" rules. \end{itemize} \item[] \texttt{mask\_output} \begin{itemize} \item[] This option replaces all but the last 4 digits of a detected PII with "X"s. This is only done on credit card \& Social Security numbers, where an organization's regulations may prevent them from seeing unencrypted numbers. \end{itemize} \item[] \texttt{ssn\_file} \begin{itemize} \item[] A Social Security number is broken up into 3 sections: Area (3 digits), Group (2 digits), and Serial (4 digits). On a monthly basis, the Social Security Administration publishes a list of which Group numbers are in use for each Area. These numbers can be updated in Snort by supplying a CSV file with the new maximum Group numbers to use. By default, Snort recognizes Social Security numbers issued up through November 2009. \end{itemize} \end{itemize} \textit{Example preprocessor config} \begin{verbatim} preprocessor sensitive_data: alert_threshold 25 \ mask_output \ ssn_file ssn_groups_Jan10.csv \end{verbatim} \subsubsection{Rule Options} Snort rules are used to specify which PII the preprocessor should look for. A new rule option is provided by the preprocessor: \begin{verbatim} sd_pattern \end{verbatim} This rule option specifies what type of PII a rule should detect. \textit{Syntax} \begin{verbatim} sd_pattern:, ; \end{verbatim} \footnotesize \begin{verbatim} count = 1 - 255 pattern = any string \end{verbatim} \normalsize \textit{Option Explanations} \begin{itemize} \item[] \texttt{count} \begin{itemize} \item[] This dictates how many times a PII pattern must be matched for an alert to be generated. The count is tracked across all packets in a session. \end{itemize} \item[] \texttt{pattern} \begin{itemize} \item[] This is where the pattern of the PII gets specified. There are a few built-in patterns to choose from: \begin{itemize} \item[] \texttt{credit\_card} \begin{itemize} \item[] The "credit\_card" pattern matches 15- and 16-digit credit card numbers. These numbers may have spaces, dashes, or nothing in between groups. This covers Visa, Mastercard, Discover, and American Express. Credit card numbers matched this way have their check digits verified using the Luhn algorithm. \end{itemize} \item[] \texttt{us\_social} \begin{itemize} \item[] This pattern matches against 9-digit U.S. Social Security numbers. The SSNs are expected to have dashes between the Area, Group, and Serial sections. SSNs have no check digits, but the preprocessor will check matches against the list of currently allocated group numbers. \end{itemize} \item[] \texttt{us\_social\_nodashes} \begin{itemize} \item[] This pattern matches U.S. Social Security numbers without dashes separating the Area, Group, and Serial sections. \end{itemize} \item[] \texttt{email} \begin{itemize} \item[] This pattern matches against email addresses. \end{itemize} \end{itemize} \item[] If the pattern specified is not one of the above built-in patterns, then it is the definition of a custom PII pattern. Custom PII types are defined using a limited regex-style syntax. The following special characters and escape sequences are supported: \item[] \begin{tabular}{|c|p{10cm}|} \hline \texttt{\textbackslash d} & matches any digit\\ \hline \texttt{\textbackslash D} & matches any non-digit\\ \hline \texttt{\textbackslash l} & matches any letter\\ \hline \texttt{\textbackslash L} & matches any non-letter\\ \hline \texttt{\textbackslash w} & matches any alphanumeric character\\ \hline \texttt{\textbackslash W} & matches any non-alphanumeric character\\ \hline \texttt{\{num\}} & used to repeat a character or escape sequence "num" times. example: "\d\{3\}" matches 3 digits.\\ \hline \texttt{?} & makes the previous character or escape sequence optional. example: " ?" matches an optional space. This behaves in a greedy manner.\\ \hline \texttt{\textbackslash\textbackslash} & matches a backslash\\ \hline \textbackslash \{, \textbackslash \} & matches \{ and \}\\ \hline \textbackslash ? & matches a question mark.\\ \hline \end{tabular} \item[] Other characters in the pattern will be matched literally. \begin{note} Unlike PCRE, \texttt{\textbackslash w} in this rule option does NOT match underscores. \end{note} \end{itemize} \item[] \textit{Examples} \begin{verbatim} sd_pattern: 2,us_social; \end{verbatim} Alerts when 2 social security numbers (with dashes) appear in a session. \begin{verbatim} sd_pattern: 5,(\d{3})\d{3}-\d{4}; \end{verbatim} Alerts on 5 U.S. phone numbers, following the format (123)456-7890 Whole rule example: \begin{verbatim} alert tcp $HOME_NET $HIGH_PORTS -> $EXTERNAL_NET $SMTP_PORTS \ (msg:"Credit Card numbers sent over email"; gid:138; sid:1000; rev:1; \ sd_pattern:4,credit_card; metadata:service smtp;) \end{verbatim} \item[] \textit{Caveats} \begin{itemize} \item[] \texttt{sd\_pattern} is not compatible with other rule options. Trying to use other rule options with \texttt{sd\_pattern} will result in an error message. Rules using \texttt{sd\_pattern} must use GID 138. \end{itemize} \end{itemize} \subsection{Normalizer} When operating Snort in inline mode, it is helpful to normalize packets to help minimize the chances of evasion. To enable the normalizer, use the following when configuring Snort: \begin{verbatim} ./configure --enable-normalizer \end{verbatim} The normalize preprocessor is activated via the conf as outlined below. There are also many new preprocessor and decoder rules to alert on or drop packets with "abnormal" encodings. Note that in the following, fields are cleared only if they are non-zero. Also, normalizations will only be enabled if the selected DAQ supports packet replacement and is operating in inline mode. If a policy is configured for \texttt{inline\_test} or passive mode, any normalization statements in the policy config are ignored. \subsubsection{IP4 Normalizations} IP4 normalizations are enabled with: \begin{verbatim} preprocessor normalize_ip4: [df], [rf], [tos], [trim] \end{verbatim} Base normalizations enabled with "preprocessor \texttt{normalize\_ip4}" include: \begin{itemize} \item TTL normalization if enabled (explained below). \item Clear the differentiated services field (formerly TOS). \item NOP all options octets. \end{itemize} Optional normalizations include: \begin{itemize} \item \texttt{df} don't fragment: clear this bit on incoming packets. \item \texttt{rf} reserved flag: clear this bit on incoming packets. \item \texttt{tos} type of service (differentiated services): clear this byte. \item \texttt{trim} truncate packets with excess payload to the datagram length specified in the IP header + the layer 2 header (e.g. ethernet), but don't truncate below minimum frame length. This is automatically disabled if the DAQ can't inject packets. \end{itemize} \subsubsection{IP6 Normalizations} IP6 normalizations are enabled with: \begin{verbatim} preprocessor normalize_ip6 \end{verbatim} Base normalizations enabled with "preprocessor \texttt{normalize\_ip6}" include: \begin{itemize} \item Hop limit normalization if enabled (explained below). \item NOP all options octets in hop-by-hop and destination options extension headers. \end{itemize} \subsubsection{ICMP4/6 Normalizations} ICMP4 and ICMP6 normalizations are enabled with: \begin{verbatim} preprocessor normalize_icmp4 preprocessor normalize_icmp6 \end{verbatim} Base normalizations enabled with the above include: \begin{itemize} \item Clear the code field in echo requests and replies. \end{itemize} \subsubsection{TCP Normalizations} TCP normalizations are enabled with: \begin{verbatim} preprocessor normalize_tcp: \ [ips], [urp], [trim], \ [ecn ], \ [opts [allow +]] ::= stream | packet ::= \ sack | echo | partial_order | conn_count | alt_checksum | md5 | ::= { 4, 5 } ::= { 6, 7 } ::= { 9, 10 } ::= { 11, 12, 13 } ::= { 14, 15 } ::= { 19 } ::= (3..255) \end{verbatim} Base normalizations enabled with "preprocessor \texttt{normalize\_tcp}" include: \begin{itemize} \item Clear the reserved bits in the TCP header. \item Clear the urgent pointer if the urgent flag is not set. \item Clear the urgent pointer and the urgent flag if there is no payload. \item Clear the urgent flag if the urgent pointer is not set. \item Clear any option padding bytes. \end{itemize} Optional normalizations include: \begin{itemize} \item \texttt{ips} ensure consistency in retransmitted data (also forces reassembly policy to "first"). Any segments that can't be properly reassembled will be dropped. \item \texttt{urp} urgent pointer: don't adjust the urgent pointer if it is greater than payload length. \item \texttt{trim} remove data on SYN. \item \texttt{trim} remove any data from RST packet. \item \texttt{trim} trim data to window. \item \texttt{trim} trim data to MSS. \item \texttt{ecn packet} clear ECN flags on a per packet basis (regardless of negotiation). \item \texttt{ecn stream} clear ECN flags if usage wasn't negotiated. Should also enable \texttt{require\_3whs}. \item \texttt{opts} NOP all option bytes other than maximum segment size, window scaling, timestamp, and any explicitly allowed with the allow keyword. You can allow options to pass by name or number. \item \texttt{opts} if timestamp is present but invalid, or valid but not negotiated, NOP the timestamp octets. \item \texttt{opts} if timestamp was negotiated but not present, block the packet. \item \texttt{opts} clear TS ECR if ACK flag is not set. \item \texttt{opts} MSS and window scale options are NOP'd if SYN flag is not set. \end{itemize} \subsubsection{TTL Normalization} TTL normalization pertains to both IP4 TTL (time-to-live) and IP6 (hop limit) and is only performed if both the relevant base normalization is enabled (as described above) and the minimum and new TTL values are configured, as follows: \begin{verbatim} config min_ttl: config new_ttl: ::= (1..255) ::= (+1..255) \end{verbatim} If \texttt{new\_ttl }$>$ \texttt{min\_ttl}, then if a packet is received with a TTL $<$ \texttt{min\_ttl}, the TTL will be set to \texttt{new\_ttl}. Note that this configuration item was deprecated in 2.8.6: \begin{verbatim} preprocessor stream5_tcp: min_ttl <#> \end{verbatim} By default \texttt{min\_ttl} = 1 (TTL normalization is disabled). When TTL normalization is turned on the \texttt{new\_ttl} is set to 5 by default. \subsection{SIP Preprocessor} \label{sub:sip} Session Initiation Protocol (SIP) is an application-layer control (signaling) protocol for creating, modifying, and terminating sessions with one or more participants. These sessions include Internet telephone calls, multimedia distribution, and multimedia conferences. SIP Preprocessor provides ways to tackle Common Vulnerabilities and Exposures (CVEs) related with SIP found over the past few years. It also makes detecting new attacks easier. \subsubsection{Dependency Requirements} For proper functioning of the preprocessor: \begin{itemize} \item Stream session tracking must be enabled, i.e. stream5. Both TCP and UDP must be enabled in stream5. The preprocessor requires a session tracker to keep its data. In addition, Stream API is able to provide correct support for ignoring audio/video data channel. \item IP defragmentation should be enabled, i.e. the frag3 preprocessor should be enabled and configured. \end{itemize} \subsubsection{Configuration} The preprocessor configuration name is \texttt{sip}.\\ \begin{verbatim} preprocessor sip \end{verbatim} \textit{Option syntax} \begin{itemize} \item[] \begin{tabular}{|l|c|c|p{6cm}|} \hline Option & Argument & Required & Default\\ \hline \hline \texttt{disabled} & NONE & NO & OFF\\ \hline \texttt{max\_sessions} & \texttt{} & NO & \texttt{max\_sessions 10000}\\ \hline \texttt{max\_dialogs} & \texttt{} & NO & \texttt{max\_dialogs 4}\\ \hline \texttt{ports} & \texttt{} & NO & \texttt{ports \{ 5060 5061 \} }\\ \hline \texttt{methods} & \texttt{} & NO & \texttt{methods \{ invite cancel ack bye register options \} }\\ \hline \texttt{max\_uri\_len} & \texttt{} & NO & \texttt{max\_uri\_len 256 }\\ \hline \texttt{max\_call\_id\_len} & \texttt{} & NO & \texttt{max\_call\_id\_len 256 }\\ \hline \texttt{max\_requestName\_len} & \texttt{} & NO & \texttt{max\_requestName\_len 20 }\\ \hline \texttt{max\_from\_len} & \texttt{} & NO & \texttt{max\_from\_len 256 }\\ \hline \texttt{max\_to\_len} & \texttt{} & NO & \texttt{max\_to\_len 256 }\\ \hline \texttt{max\_via\_len} & \texttt{} & NO & \texttt{max\_via\_len 1024 }\\ \hline \texttt{max\_contact\_len} & \texttt{} & NO & \texttt{max\_contact\_len 256 }\\ \hline \texttt{max\_content\_len} & \texttt{} & NO & \texttt{max\_content\_len 1024 }\\ \hline \texttt{ignore\_call\_channel} & NONE & NO & OFF\\ \hline \end{tabular} \end{itemize} \footnotesize \begin{verbatim} max_sessions = 1024-4194303 max_dialogs = 1-4194303 methods = "invite"|"cancel"|"ack"|"bye"|"register"| "options"\ |"refer" |"subscribe"|"update"|"join"|"info"|"message"\ |"notify"|"prack" max_uri_len = 0-65535 max_call_id_len = 0-65535 max_requestName_len = 0-65535 max_from_len = 0-65535 max_to_len = 0-65535 max_via_len = 0-65535 max_contact_len = 0-65535 max_content_len = 0-65535 \end{verbatim} \normalsize \textit{Option explanations} \begin{itemize} \item[] \texttt{disabled} \begin{itemize} \item[] SIP dynamic preprocessor can be enabled/disabled through configuration. By default this value is turned off. When the preprocessor is disabled, only the max\_sessions option is applied when specified with the configuration. \end{itemize} \item[] \texttt{max\_sessions} \begin{itemize} \item[] This specifies the maximum number of sessions that can be allocated. Those sessions are stream sessions, so they are bounded by maximum number of stream sessions. Default is 10000. \end{itemize} \item[] \texttt{max\_dialogs} \begin{itemize} \item[] This specifies the maximum number of dialogs within one stream session. If exceeded, the oldest dialog will be dropped. Default is 4. \end{itemize} \item[] \texttt{ports} \begin{itemize} \item[] This specifies on what ports to check for SIP messages. Typically, this will include 5060, 5061. \item[] \textit{Syntax} \begin{verbatim} ports { [< ... >] } \end{verbatim} \item[] \textit{Examples} \begin{verbatim} ports { 5060 5061 } \end{verbatim} \item[] Note: there are spaces before and after `\{' and `\}'. \end{itemize} \item[] \texttt{methods} \begin{itemize} \item[] This specifies on what methods to check for SIP messages: (1) invite, (2) cancel, (3) ack, (4) bye, (5) register, (6) options, (7) refer, (8) subscribe, (9) update (10) join (11) info (12) message (13) notify (14) prack. Note: those 14 methods are up to date list (Feb. 2011). New methods can be added to the list. Up to 32 methods supported. \item[] \textit{Syntax} \begin{verbatim} methods { } method-list = method|method method-list methods = "invite"|"cancel"|"ack"|"bye"|"register"| "options"\ |"refer"|"subscribe"|"update"|"join"|"info"|"message"\ |"notify"|"prack" \end{verbatim} \item[] \textit{Examples} \begin{verbatim} methods { invite cancel ack bye register options } methods { invite cancel ack bye register options information } \end{verbatim} \item[] Note: there are spaces before and after `\{' and `\}'. \end{itemize} \item[] \texttt{max\_uri\_len} \begin{itemize} \item[] This specifies the maximum Request URI field size. If the Request URI field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. ``0'' means never alert. \end{itemize} \item[] \texttt{max\_call\_id\_len} \begin{itemize} \item[] This specifies the maximum Call-ID field size. If the Call-ID field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. ``0'' means never alert. \end{itemize} \item[] \texttt{max\_requestName\_len} \begin{itemize} \item[] This specifies the maximum request name size that is part of the CSeq ID. If the request name is greater than this size, an alert is generated. Default is set to 20. The allowed range for this option is 0 - 65535. ``0'' means never alert. \end{itemize} \item[] \texttt{max\_from\_len} \begin{itemize} \item[] This specifies the maximum From field size. If the From field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. ``0'' means never alert. \end{itemize} \item[] \texttt{max\_to\_len} \begin{itemize} \item[] This specifies the maximum To field size. If the To field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. ``0'' means never alert. \end{itemize} \item[] \texttt{max\_via\_len} \begin{itemize} \item[] This specifies the maximum Via field size. If the Via field is greater than this size, an alert is generated. Default is set to 1024. The allowed range for this option is 0 - 65535. ``0'' means never alert. \end{itemize} \item[] \texttt{max\_contact\_len} \begin{itemize} \item[] This specifies the maximum Contact field size. If the Contact field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. ``0'' means never alert. \end{itemize} \item[] \texttt{max\_content\_len} \begin{itemize} \item[] This specifies the maximum content length of the message body. If the content length is greater than this number, an alert is generated. Default is set to 1024. The allowed range for this option is 0 - 65535. ``0'' means never alert. \end{itemize} \item[] \texttt{ignore\_call\_channel} \begin{itemize} \item[] This enables the support for ignoring audio/video data channel (through Stream API). By default, this is disabled. \end{itemize} \end{itemize} \textit{Option examples} \footnotesize \begin{verbatim} max_sessions 30000 disabled ports { 5060 5061 } methods { invite cancel ack bye register options } methods { invite cancel ack bye register options information } max_uri_len 1024 max_call_id_len 1024 max_requestName_len 10 max_from_len 1024 max_to_len 1024 max_via_len 1024 max_contact_len 1024 max_content_len 1024 max_content_len ignore_call_channel \end{verbatim} \normalsize \textit{Configuration examples} \footnotesize \begin{verbatim} preprocessor sip preprocessor sip: max_sessions 500000 preprocessor sip: max_contact_len 512, max_sessions 300000, methods { invite \ cancel ack bye register options } , ignore_call_channel preprocessor sip: ports { 5060 49848 36780 10270 }, max_call_id_len 200, \ max_from_len 100, max_to_len 200, max_via_len 1000, \ max_requestName_len 50, max_uri_len 100, ignore_call_channel,\ max_content_len 1000 preprocessor sip: disabled preprocessor sip: ignore_call_channel \end{verbatim} \normalsize \textit{Default configuration} \footnotesize \begin{verbatim} preprocessor sip \end{verbatim} \normalsize \subsubsection{Events} The preprocessor uses GID 140 to register events. \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline 1 & If the memory cap is reached and the preprocessor is configured to alert, this alert will be created. \\ \hline 2 & Request URI is required. When Request URI is empty, this alert will be created. \\ \hline 3 & The Request URI is larger than the defined length in configuration.\\ \hline 4 & When Call-ID is empty, this alert will be created.\\ \hline 5 & The Call-ID is larger than the defined length in configuration.\\ \hline 6 & The sequence e number value MUST be expressible as a 32-bit unsigned integer and MUST be less than $2^{31}$.\\ \hline 7 & The request name in the CSeq is larger than the defined length in configuration.\\ \hline 8 & From field is empty.\\ \hline 9 & From field is larger than the defined length in configuration.\\ \hline 10 & To field is empty.\\ \hline 11 & To field is larger than the defined length in configuration.\\ \hline 12 & Via filed is empty.\\ \hline 13 & Via filed is larger than the defined length in configuration.\\ \hline 14 & Contact is empty, but it is required non-empty for the message.\\ \hline 15 & The Contact is larger than the defined length in configuration. \\ \hline 16 & The content length is larger than the defined length in configuration or is negative. \\ \hline 17 & There are multiple requests in a single packet. Old SIP protocol supports multiple sip messages within one packet.\\ \hline 18 & There are inconsistencies between Content-Length in SIP header and actual body data.\\ \hline 19 & Request name is invalid in response.\\ \hline 20 & Authenticated invite message received, but no challenge from server received. This is the case of InviteReplay billing attack.\\ \hline 21 & Authenticated invite message received, but session information has been changed. This is different from re-INVITE, where the dialog has been established. and authenticated. This is can prevent FakeBusy billing attack.\\ \hline 22 & Response status code is not a 3 digit number.\\ \hline 23 & Content type header field is required if the message body is not empty.\\ \hline 24 & SIP version other than 2.0, 1.0, and 1.1 is invalid \\ \hline 25 & Mismatch in Method of request and the CSEQ header\\ \hline 26 & The method is unknown \\ \hline 27 & The number of dialogs in the stream session exceeds the maximal value. \\ \hline \end{longtable} \subsubsection{Rule Options} New rule options are supported by enabling the \texttt{sip} preprocessor: \begin{itemize} \item[] \begin{verbatim} sip_method sip_stat_code sip_header sip_body \end{verbatim} \end{itemize} Overload modifiers to existing \texttt{pcre} rule options: \begin{itemize} \item[] H: Match SIP request or SIP response header, Similar to \texttt{sip\_header}. \item[] P: Match SIP request or SIP response body, Similar to \texttt{sip\_body}. \end{itemize} \texttt{sip\_method} \label{sip:sip_method} \begin{itemize} \item[] The \texttt{sip\_method} keyword is used to check for specific SIP request methods. The list of methods is: invite, cancel, ack, bye, register, options, refer, subscribe, update, join, info, message, notify, prack. More than one method can be specified, via a comma separated list, and are OR'ed together. It will be applied in fast pattern match if available. If the method used in this rule is not listed in the preprocessor configuration, it will be added to the preprocessor configuration for the associated policy.\\ \textit{Syntax} \footnotesize \begin{verbatim} sip_method:; method-list = method|method, method-list method = ["!"] "invite"|"cancel"|"ack"|"bye"|"register"| "options"\ |"refer"|"subscribe"|"update"|"join"|"info"|"message"\ |"notify"|"prack" Note: if "!" is used, only one method is allowed in sip_method. \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} sip_method:invite, cancel sip_method:!invite Note: If a user wants to use "and", they can use something like this: sip_method:!invite; sip_method:!bye \end{verbatim} \normalsize \end{itemize} \texttt{sip\_stat\_code} \label{sip:sip_stat_code} \begin{itemize} \item[] The \texttt{sip\_stat\_code} is used to check the SIP response status code. This option matches if any one of the state codes specified matches the status codes of the SIP response.\\ \textit{Syntax} \footnotesize \begin{verbatim} sip_stat_code: ; code_list = state_code|state_code, code_list code = "100-999"|"1-9" \end{verbatim} \item[] Note: 1,2,3,4,5,6... mean to check for "1xx", "2xx", '3xx', '4xx', '5xx', '6xx'... responses. \\ \normalsize \textit{Examples} \footnotesize \begin{verbatim} sip_stat_code:200 sip_stat_code: 2 sip_stat_code: 200, 180 \end{verbatim} \normalsize \end{itemize} \texttt{sip\_header} \label{sip:sip_header} \begin{itemize} \item[] The \texttt{sip\_header} keyword restricts the search to the extracted Header fields of a SIP message request or a response. This works similar to \texttt{file\_data}. \\ \textit{Syntax} \footnotesize \begin{verbatim} sip_header; \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} alert udp any any -> any 5060 (sip_header; content:"CSeq"; ) \end{verbatim} \normalsize \end{itemize} \texttt{sip\_body} \label{sip:sip_body} \begin{itemize} \item[] The \texttt{sip\_body} keyword places the cursor at the beginning of the Body fields of a SIP message. This works similar to \texttt{file\_data} and \texttt{dce\_stub\_data}. The message body includes channel information using SDP protocol (Session Description Protocol).\\ \textit{Syntax} \footnotesize \begin{verbatim} sip_body; \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} alert udp any any -> any 5060 (sip_body; content:"C=IN 0.0.0.0"; within 100;) \end{verbatim} \normalsize \end{itemize} \texttt{pcre} \label{sip:pcre} \begin{itemize} \item[] SIP overloads two options for \texttt{pcre}:\\ \begin{itemize} \item H: Match SIP header for request or response , Similar to \texttt{sip\_header}.\\ \item P: Match SIP body for request or response , Similar to \texttt{sip\_body}.\\ \end{itemize} \textit{Examples} \footnotesize \begin{verbatim} alert udp any any -> any 5060 (pcre:"/INVITE/H"; sid:1000000;) alert udp any any -> any 5060 (pcre:"/m=/P"; sid:2000000;) \end{verbatim} \normalsize \end{itemize} \subsection{Reputation Preprocessor} \label{sub:reputation} Reputation preprocessor provides basic IP blacklist/whitelist capabilities, to block/drop/pass traffic from IP addresses listed. In the past, we use standard Snort rules to implement Reputation-based IP blocking. This preprocessor will address the performance issue and make the IP reputation management easier. This preprocessor runs before other preprocessors. \subsubsection{Configuration} The preprocessor configuration name is \texttt{reputation}.\\ \begin{verbatim} preprocessor reputation \end{verbatim} \textit{Option syntax} \begin{itemize} \item[] \begin{tabular}{|l|c|c|p{6cm}|} \hline Option & Argument & Required & Default\\ \hline \hline \texttt{memcap} & \texttt{} & NO & \texttt{memcap 500}\\ \hline \texttt{scan\_local} & NONE & NO & OFF\\ \hline \texttt{blacklist} & \texttt{} & NO & NONE\\ \hline \texttt{whitelist} & \texttt{} & NO & NONE\\ \hline \texttt{priority} & [blacklist whitelist] & NO & \texttt{priority whitelist}\\ \hline \texttt{nested\_ip} & [inner outer both] & NO & \texttt{nested\_ip inner}\\ \hline \texttt{white} & [unblack trust] & NO & \texttt{white unblack}\\ \hline \end{tabular} \end{itemize} \footnotesize \begin{verbatim} memcap = 1-4095 Mbytes \end{verbatim} \normalsize \textit{Option explanations} \begin{itemize} \item[] \texttt{memcap} \begin{itemize} \item[] Maximum total memory supported. It can be set up to 4095 Mbytes. \end{itemize} \item[] \texttt{scan\_local} \begin{itemize} \item[] Enable to inspect local address defined in RFC 1918: \begin{itemize} \item[] 10.0.0.0 - 10.255.255.255 (10/8 prefix) \item[] 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) \item[] 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) \end{itemize} \end{itemize} \item[] \texttt{blacklist/whitelist} \begin{itemize} \item[] The IP lists are loaded from external files. It supports relative paths for inclusion and \$variables for path. Multiple blacklists or whitelists are supported. \item[] Note: if the same IP is redefined later, it will overwrite the previous one. In other words, IP lists always favors the last file or entry processed. \end{itemize} \item[] \texttt{priority} \begin{itemize} \item[] Specify either blacklist or whitelist has higher priority when source/destination is on blacklist while destination/source is on whitelist. By default, whitelist has higher priority. In other words, the packet will be passed when either source or destination is whitelisted. \item[] Note: this only defines priority when there is a decision conflict, during run-time. During initialization time, if the same IP address is defined in whitelist and blacklist, whoever the last one defined will be the final one. Priority does not work on this case. \end{itemize} \item[] \texttt{nested\_ip} \begin{itemize} \item[] Specify which IP address to be used when there is IP encapsulation. \end{itemize} \item[] \texttt{white} \begin{itemize} \item[] Specify the meaning of whitelist. When white means unblack, it unblacks IPs that are in blacklists; when white means trust, the packet gets bypassed, without further detection by snort. You can only specify either unblack or trust. \item[] Note: when white means unblack, whitelist always has higher priority than blacklist. \end{itemize} \end{itemize} \textit{Configuration examples} \footnotesize \begin{verbatim} preprocessor reputation:\ blacklist /etc/snort/default.blacklist, \ whitelist /etc/snort/default.whitelist preprocessor reputation: \ nested_ip both, \ blacklist /etc/snort/default.blacklist, \ whitelist /etc/snort/default.whitelist preprocessor reputation: \ memcap 4095, scan_local, nested_ip both, \ priority whitelist, \ blacklist /etc/snort/default.blacklist, \ whitelist /etc/snort/default.whitelist, white trust $REP_BLACK_FILE1 = ../dshield.list $REP_BLACK_FILE2 = ../snort.org.list preprocessor reputation: \ blacklist $REP_BLACK_FILE1,\ blacklist $REP_BLACK_FILE2 \end{verbatim} \normalsize \textit{IP List File Format} \begin{itemize} \item[] \texttt{Syntax} \begin{itemize} \item[] The IP list file has 1 entry per line. The entry can be either IP entry or comment. \end{itemize} \begin{itemize} \item[] \texttt{IP Entry} \begin{itemize} \item[] CIDR notation $<$comments$>$ line break. \item[] Example: \footnotesize \begin{verbatim} 172.16.42.32/32 172.33.42.32/16 \end{verbatim} \normalsize \end{itemize} \item[] \texttt{Comment} \begin{itemize} \item[] The comment start with \# \item[] \# $<$comments$>$ \item[] Example \footnotesize \begin{verbatim} # This is a full line comment 172.33.42.32/16 # This is a in-line comment \end{verbatim} \normalsize \end{itemize} \end{itemize} \item[] \texttt{IP List File Example} \begin{itemize} \item[] \footnotesize \begin{verbatim} # This is a full line comment 172.16.42.32/32 # This is an inline comment, line with single CIDR block 172.33.42.32/16 \end{verbatim} \normalsize \end{itemize} \end{itemize} \textit{Use case} \begin{itemize} \item[] A user wants to protect his/her network from unwanted/unknown IPs, only allowing some trusted IPs. Here is the configuration: \item[] \footnotesize \begin{verbatim} preprocessor reputation: \ blacklist /etc/snort/default.blacklist whitelist /etc/snort/default.whitelist In file "default.blacklist" # These two entries will match all ipv4 addresses 1.0.0.0/1 128.0.0.0/1 In file "default.whitelist" 68.177.102.22 # sourcefire.com 74.125.93.104 # google.com \end{verbatim} \end{itemize} \normalsize \subsubsection{Events} Reputation preprocessor uses GID 136 to register events. \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline 1 & Packet is blacklisted. \\ \hline 2 & Packet is whitelisted. \\ \hline 3 & Packet is inspected. \\ \hline \end{longtable} \subsubsection{Shared memory support} \begin{itemize} \item[] In order to minimize memory consumption when multiple Snort instances are running concurrently, we introduce the support of shared memory. After configured, all the snort instances share the same IP tables in shared memory. \item[]\textit{System requirement} \begin{itemize} \item[]This feature is supported only in Linux. \end{itemize} \item[]\textit{Build configuration} \begin{itemize} \item[]A new option, \texttt{--enable-shared-rep} is introduced to \texttt{./configure} command. This option enables the support for shared memory. \end{itemize} \item[]\textit{Configuration} \begin{itemize} \item[]\texttt{shared\_mem} \begin{itemize} \item[] If the build supports shared memory, this configuration will enable shared memory. If this option isn't set, standard memory is used. This option must specify a path or directory where IP lists will be loaded in shared memory. One snort instance will create and maintain the shared IP lists. We use instance ID 1, specified in the snort \texttt{-G} option to be the master snort. All the other snort instances are clients (readers). \item[] \textit{Syntax} \begin{verbatim} shared_mem: path \end{verbatim} \item[] \textit{Examples} \begin{verbatim} shared_mem /user/reputation/iplists \end{verbatim} \end{itemize} \item[]\texttt{shared\_refresh} \begin{itemize} \item[]This option changes the period of checking new shared memory segment, in the unit of second. By default, the refresh rate is $60$ seconds. \item[]\textit{Syntax} \begin{verbatim} shared_refresh period = "1 - 4294967295" \end{verbatim} \item[]\textit{Examples} \begin{verbatim} shared_refresh 60 \end{verbatim} \end{itemize} \end{itemize} \item[]\textit{Steps to configure shared memory} \begin{itemize} \item When building Snort, add option \texttt{--enable-shared-rep} to \texttt{./configure}\\ For example: \begin{verbatim} ./configure --enable-gre --enable-sourcefire --enable-flexresp3 --enable-pthread --enable-linux-smp-stats --enable-targetbased --enable-shared-rep --enable-control-socket \end{verbatim} \item Put your IP list file into a directory, where snort has full access. \\ For example: \begin{verbatim} /user/reputation/iplists \end{verbatim} In order to separate whitelist with blacklist, you need to specify whitelist with \texttt{.wlf} extension and blacklist with \texttt{.blf} extension. \item In snort config file, specify shared memory support with the path to IP files.\\ For example: \begin{verbatim} shared_mem /user/reputation/iplists \end{verbatim} If you want to change the period of checking new IP lists, add refresh period.\\ For example: \begin{verbatim} shared_refresh 300 \end{verbatim} \item Start shared memory master(writer) with \texttt{-G} 0 option. Note: only one master should be enabled. \item Start shared memory clients (readers) with \texttt{-G} 1 or other IDs. Note: for one ID, only one snort instance should be enabled. \item You will see the IP lists got loaded and shared across snort instances! \end{itemize} \item[]\textit{Reload IP lists using control socket} \begin{itemize} \item Run snort using command line with option \texttt{--cs-dir } or configure snort with: \begin{verbatim} config cs_dir: \end{verbatim} \item (Optional) you can create a version file named ``IPRVersion.dat'' in the IP list directory. This file helps managing reloading IP lists, by specifying a version. When the version isn't changed, IP lists will not be reloaded if they are already in shared memory. The version number should be a 32 bit number.\\ For example: \begin{verbatim} VERSION=1 \end{verbatim} \item In the \texttt{/src/tools/control} directory, you will find \texttt{snort\_control} command if built with \texttt{--enable-control-socket} option. \item Type the following command to reload IP lists. Before typing this command, make sure to update version file if you are using version file. The \texttt{} is the same path in first step.\\ \begin{verbatim} /src/tools/control/snort_control 1361 \end{verbatim} \end{itemize} \item[]\textit{Using manifest file to manage loading (optional)} \begin{itemize} \item[] Using manifest file, you can control the file loading sequence, action taken, and support zone based detection. You can create a manifest file named ``zone.info'' in the IP list directory.\\ \item[] When Snort is signaled to load new lists, a manifest file is read first to determine which zones the IPs in each list are applicable to and what action to take per list (Block, White, Monitor). \\ \item[] Files listed in manifest are loaded from top to bottom. You should put files that have higher priority first. In manifest file, you can put up to 255 files. Without manifest file, files will be loaded in alphabet order.\\ \item[] Here's the format of the manifest file. Each line of the file has the following format:\\ \begin{verbatim} , ,[, ]+ ::= 32 bit integer ::= "monitor"|"block"|"white" ::= [0-1051] \end{verbatim} \item[] Using manifest file, you can specify a new action called ``monitor'', which indicates a packet needs to be inspected, but does not disable detection. This is different from ``block'' action, which disables further detection. This new action helps users evaluate their IP lists before applying it. \item[] An example manifest file: \begin{verbatim} #ipreputation manifest file white.wlf, 111 ,white, black1.blf, 1112, black, 3, 12 black2.blf, 1113, black, 3, 12 monitor.blf,2222, monitor, 0, 2, 8 \end{verbatim} \end{itemize} \end{itemize} \subsection{GTP Decoder and Preprocessor} \label{sub:gtp} GTP (GPRS Tunneling Protocol) is used in core communication networks to establish a channel between GSNs (GPRS Serving Node). GTP decoding preprocessor provides ways to tackle intrusion attempts to those networks through GTP. It also makes detecting new attacks easier. Two components are developed: GTP decoder and GTP preprocessor. \begin{itemize} \item GTP decoder extracts payload inside GTP PDU; \item GTP preprocessor inspects all the signaling messages and provide keywords for further inspection \end{itemize} When the decoder is enabled and configured, the decoder strips the GTP headers and parses the underlying IP/TCP/UDP encapsulated packets. Therefore all rules and detection work as if there was no GTP header. Example: \begin{itemize} \item[] Most GTP packets look like this \begin{verbatim} IP -> UDP -> GTP -> IP -> TCP -> HTTP \end{verbatim} If you had a standard HTTP rule: \begin{verbatim} alert tcp any any -> any $HTTP_PORTS (msg:"Test HTTP"; flow:to_server,established; content:"SOMETHINGEVIL"; http_uri; .... sid:X; rev:Y;) \end{verbatim} it would alert on the inner HTTP data that is encapsulated in GTP without any changes to the rule other than enabling and configuring the GTP decoder. \end{itemize} \subsubsection{Dependency Requirements} For proper functioning of the preprocessor: \begin{itemize} \item Stream session tracking must be enabled, i.e. stream5. UDP must be enabled in stream5. The preprocessor requires a session tracker to keep its data. \item IP defragmentation should be enabled, i.e. the frag3 preprocessor should be enabled and configured. \end{itemize} \subsubsection{GTP Data Channel Decoder Configuration} GTP decoder extracts payload from GTP PDU. The following configuration sets GTP decoding: \begin{verbatim} config enable_gtp \end{verbatim} By default, GTP decoder uses port number $2152$ (GTPv1) and $3386$ (GTPv0). If users want to change those values, they can use \texttt{portvar GTP\_PORTS}: \begin{verbatim} portvar GTP_PORTS [2152,3386] \end{verbatim} \subsubsection{GTP Control Channel Preprocessor Configuration} Different from GTP decoder, GTP preprocessor examines all signaling messages. The preprocessor configuration name is \texttt{gtp}. \begin{verbatim} preprocessor gtp \end{verbatim} \textit{Option syntax} \begin{itemize} \item[] \begin{tabular}{|l|c|c|p{6cm}|} \hline Option & Argument & Required & Default\\ \hline \hline \texttt{ports} & \texttt{} & NO & \texttt{ports \{ 2123 3386 \} }\\ \hline \end{tabular} \end{itemize} \normalsize \textit{Option explanations} \begin{itemize} \item[] \texttt{ports} \begin{itemize} \item[] This specifies on what ports to check for GTP messages. Typically, this will include 5060, 5061. \item[] \textit{Syntax} \begin{verbatim} ports { [< ... >] } \end{verbatim} \item[] \textit{Examples} \begin{verbatim} ports { 2123 3386 2152 } \end{verbatim} \item[] Note: there are spaces before and after `\{' and `\}'. \end{itemize} \end{itemize} \normalsize \textit{Default configuration} \footnotesize \begin{verbatim} preprocessor gtp \end{verbatim} \normalsize \subsubsection{GTP Decoder Events} \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline 297 & Two or more GTP encapsulation layers present \\ \hline 298 & GTP header length is invalid \\ \hline \end{longtable} \subsubsection{GTP Preprocessor Events} \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline 1 & Message length is invalid. \\ \hline 2 & Information element length is invalid. \\ \hline 3 & Information elements are out of order. \\ \hline \end{longtable} \subsubsection{Rule Options} New rule options are supported by enabling the \texttt{gtp} preprocessor: \begin{itemize} \item[] \begin{verbatim} gtp_type gtp_info gtp_version \end{verbatim} \end{itemize} \texttt{gtp\_type} \label{gtp:gtp_method} \begin{itemize} \item[] The \texttt{gtp\_type} keyword is used to check for specific GTP types. User can input message type value, an integer in [0, 255], or a string defined in the Table below. More than one type can be specified, via a comma separated list, and are OR'ed together. If the type used in a rule is not listed in the preprocessor configuration, an error will be thrown. \item[] A message type can have different type value in different GTP versions. For example, \texttt{sgsn\_\-context\_\-request} has message type value $50$ in GTPv0 and GTPv1, but $130$ in GTPv2. \texttt{gtp\_type} will match to a different value depending on the version number in the packet. In this example, evaluating a GTPv0 or GTPv1 packet will check whether the message type value is $50$; evaluating a GTPv2 packet will check whether the message type value is $130$. When a message type is not defined in a version, any packet in that version will always return ``No match''. \item[] If an integer is used to specify message type, every GTP packet is evaluated, no matter what version the packet is. If the message type matches the value in packet, it will return ``Match''. \\ \textit{Syntax} \footnotesize \begin{verbatim} gtp_type:; type-list = type|type, type-list type = "0-255"| | "echo_request" | "echo_response" ... \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} gtp_type:10, 11, echo_request; \end{verbatim} \normalsize \textit{GTP message types} \small \begin{longtable}{|r|c|c|c|p{13.5cm}|} \hline Type & GTPv0 & GTPv1 & GTPv2\\ \hline 0 & N/A & N/A & N/A\\ \hline 1 & echo\_request & echo\_request & echo\_request\\ \hline 2 & echo\_response & echo\_response & echo\_response\\ \hline 3 & version\_not\_supported & version\_not\_supported & version\_not\_supported\\ \hline 4 & node\_alive\_request & node\_alive\_request & N/A\\ \hline 5 & node\_alive\_response & node\_alive\_response & N/A\\ \hline 6 & redirection\_request & redirection\_request & N/A\\ \hline 7 & redirection\_response & redirection\_response & N/A \\ \hline 16 & create\_pdp\_context\_request & create\_pdp\_context\_request & N/A\\ \hline 17 & create\_pdp\_context\_response & create\_pdp\_context\_response & N/A \\ \hline 18 & update\_pdp\_context\_request & update\_pdp\_context\_request & N/A\\ \hline 19 & update\_pdp\_context\_response & update\_pdp\_context\_response & N/A\\ \hline 20 & delete\_pdp\_context\_request & delete\_pdp\_context\_request & N/A\\ \hline 21 & delete\_pdp\_context\_response & delete\_pdp\_context\_response & N/A\\ \hline 22 & create\_aa\_pdp\_context\_request & init\_pdp\_context\_activation\_request & N/A\\ \hline 23 & create\_aa\_pdp\_context\_response & init\_pdp\_context\_activation\_response & N/A\\ \hline 24 & delete\_aa\_pdp\_context\_request & N/A & N/A\\ \hline 25 & delete\_aa\_pdp\_context\_response & N/A & N/A\\ \hline 26 & error\_indication & error\_indication & N/A\\ \hline 27 & pdu\_notification\_request & pdu\_notification\_request & N/A\\ \hline 28 & pdu\_notification\_response & pdu\_notification\_response & N/A\\ \hline 29 & pdu\_notification\_reject\_request & pdu\_notification\_reject\_request & N/A\\ \hline 30 & pdu\_notification\_reject\_response & pdu\_notification\_reject\_response & N/A\\ \hline 31 & N/A & supported\_ext\_header\_notification & N/A \\ \hline 32 & send\_routing\_info\_request & send\_routing\_info\_request & create\_session\_request \\ \hline 33 & send\_routing\_info\_response & send\_routing\_info\_response & create\_session\_response \\ \hline 34 & failure\_report\_request & failure\_report\_request & modify\_bearer\_request \\ \hline 35 & failure\_report\_response & failure\_report\_response & modify\_bearer\_response \\ \hline 36 & note\_ms\_present\_request & note\_ms\_present\_request & delete\_session\_request \\ \hline 37 & note\_ms\_present\_response & note\_ms\_present\_response & delete\_session\_response \\ \hline 38 & N/A & N/A & change\_notification\_request \\ \hline 39 & N/A & N/A & change\_notification\_response \\ \hline 48 & identification\_request & identification\_request & N/A \\ \hline 49 & identification\_response & identification\_response & N/A \\ \hline 50 & sgsn\_context\_request & sgsn\_context\_request & N/A \\ \hline 51 & sgsn\_context\_response & sgsn\_context\_response & N/A \\ \hline 52 & sgsn\_context\_ack & sgsn\_context\_ack & N/A \\ \hline 53 & N/A & forward\_relocation\_request & N/A \\ \hline 54 & N/A & forward\_relocation\_response & N/A \\ \hline 55 & N/A & forward\_relocation\_complete & N/A \\ \hline 56 & N/A & relocation\_cancel\_request & N/A \\ \hline 57 & N/A & relocation\_cancel\_response & N/A \\ \hline 58 & N/A & forward\_srns\_contex & N/A \\ \hline 59 & N/A & forward\_relocation\_complete\_ack & N/A \\ \hline 60 & N/A & forward\_srns\_contex\_ack & N/A \\ \hline 64 & N/A & N/A & modify\_bearer\_command \\ \hline 65 & N/A & N/A & modify\_bearer\_failure\_indication \\ \hline 66 & N/A & N/A & delete\_bearer\_command \\ \hline 67 & N/A & N/A & delete\_bearer\_failure\_indication \\ \hline 68 & N/A & N/A & bearer\_resource\_command \\ \hline 69 & N/A & N/A & bearer\_resource\_failure\_indication \\ \hline 70 & N/A & ran\_info\_relay & downlink\_failure\_indication \\ \hline 71 & N/A & N/A & trace\_session\_activation \\ \hline 72 & N/A & N/A & trace\_session\_deactivation \\ \hline 73 & N/A & N/A & stop\_paging\_indication \\ \hline 95 & N/A & N/A & create\_bearer\_request \\ \hline 96 & N/A & mbms\_notification\_request & create\_bearer\_response \\ \hline 97 & N/A & mbms\_notification\_response & update\_bearer\_request \\ \hline 98 & N/A & mbms\_notification\_reject\_request & update\_bearer\_response \\ \hline 99 & N/A & mbms\_notification\_reject\_response & delete\_bearer\_request \\ \hline 100 & N/A & create\_mbms\_context\_request & delete\_bearer\_response \\ \hline 101 & N/A & create\_mbms\_context\_response & delete\_pdn\_request \\ \hline 102 & N/A & update\_mbms\_context\_request & delete\_pdn\_response \\ \hline 103 & N/A & update\_mbms\_context\_response & N/A \\ \hline 104 & N/A & delete\_mbms\_context\_request & N/A \\ \hline 105 & N/A & delete\_mbms\_context\_response & N/A \\ \hline 112 & N/A & mbms\_register\_request & N/A \\ \hline 113 & N/A & mbms\_register\_response & N/A \\ \hline 114 & N/A & mbms\_deregister\_request & N/A \\ \hline 115 & N/A & mbms\_deregister\_response & N/A \\ \hline 116 & N/A & mbms\_session\_start\_request & N/A \\ \hline 117 & N/A & mbms\_session\_start\_response & N/A \\ \hline 118 & N/A & mbms\_session\_stop\_request & N/A \\ \hline 119 & N/A & mbms\_session\_stop\_response & N/A \\ \hline 120 & N/A & mbms\_session\_update\_request & N/A \\ \hline 121 & N/A & mbms\_session\_update\_response & N/A \\ \hline 128 & N/A & ms\_info\_change\_request & identification\_request \\ \hline 129 & N/A & ms\_info\_change\_response & identification\_response \\ \hline 130 & N/A & N/A & sgsn\_context\_request \\ \hline 131 & N/A & N/A & sgsn\_context\_response \\ \hline 132 & N/A & N/A & sgsn\_context\_ack \\ \hline 133 & N/A & N/A & forward\_relocation\_request \\ \hline 134 & N/A & N/A & forward\_relocation\_response \\ \hline 135 & N/A & N/A & forward\_relocation\_complete \\ \hline 136 & N/A & N/A & forward\_relocation\_complete\_ack \\ \hline 137 & N/A & N/A & forward\_access \\ \hline 138 & N/A & N/A & forward\_access\_ack \\ \hline 139 & N/A & N/A & relocation\_cancel\_request \\ \hline 140 & N/A & N/A & relocation\_cancel\_response \\ \hline 141 & N/A & N/A & configuration\_transfer\_tunnel \\ \hline 149 & N/A & N/A & detach \\ \hline 150 & N/A & N/A & detach\_ack \\ \hline 151 & N/A & N/A & cs\_paging \\ \hline 152 & N/A & N/A & ran\_info\_relay \\ \hline 153 & N/A & N/A & alert\_mme \\ \hline 154 & N/A & N/A & alert\_mme\_ack \\ \hline 155 & N/A & N/A & ue\_activity \\ \hline 156 & N/A & N/A & ue\_activity\_ack \\ \hline 160 & N/A & N/A & create\_forward\_tunnel\_request \\ \hline 161 & N/A & N/A & create\_forward\_tunnel\_response \\ \hline 162 & N/A & N/A & suspend \\ \hline 163 & N/A & N/A & suspend\_ack \\ \hline 164 & N/A & N/A & resume \\ \hline 165 & N/A & N/A & resume\_ack \\ \hline 166 & N/A & N/A & create\_indirect\_forward\_tunnel\_request \\ \hline 167 & N/A & N/A & create\_indirect\_forward\_tunnel\_response \\ \hline 168 & N/A & N/A & delete\_indirect\_forward\_tunnel\_request \\ \hline 169 & N/A & N/A & delete\_indirect\_forward\_tunnel\_response \\ \hline 170 & N/A & N/A & release\_access\_bearer\_request \\ \hline 171 & N/A & N/A & release\_access\_bearer\_response \\ \hline 176 & N/A & N/A & downlink\_data \\ \hline 177 & N/A & N/A & downlink\_data\_ack \\ \hline 178 & N/A & N/A & N/A \\ \hline 179 & N/A & N/A & pgw\_restart \\ \hline 199 & N/A & N/A & pgw\_restart\_ack \\ \hline 200 & N/A & N/A & update\_pdn\_request \\ \hline 201 & N/A & N/A & update\_pdn\_response \\ \hline 211 & N/A & N/A & modify\_access\_bearer\_request \\ \hline 212 & N/A & N/A & modify\_access\_bearer\_response \\ \hline 231 & N/A & N/A & mbms\_session\_start\_request \\ \hline 232 & N/A & N/A & mbms\_session\_start\_response \\ \hline 233 & N/A & N/A & mbms\_session\_update\_request \\ \hline 234 & N/A & N/A & mbms\_session\_update\_response \\ \hline 235 & N/A & N/A & mbms\_session\_stop\_request \\ \hline 236 & N/A & N/A & mbms\_session\_stop\_response \\ \hline 240 & data\_record\_transfer\_request & data\_record\_transfer\_request & N/A \\ \hline 241 & data\_record\_transfer\_response & data\_record\_transfer\_response & N/A \\ \hline 254 & N/A & end\_marker & N/A \\ \hline 255 & pdu & pdu & N/A \\ \hline \end{longtable} \end{itemize} \texttt{gtp\_info} \label{gtp:gtp_info} \begin{itemize} \item[] The \texttt{gtp\_info} keyword is used to check for specific GTP information element. This keyword restricts the search to the information element field. User can input information element value, an integer in $[0, 255]$, or a string defined in the Table below. If the information element used in this rule is not listed in the preprocessor configuration, an error will be thrown. \item[] When there are several information elements with the same type in the message, this keyword restricts the search to the total consecutive buffer. Because the standard requires same types group together, this feature will be available for all valid messages. In the case of ``out of order information elements'', this keyword restricts the search to the last buffer. \item[] Similar to message type, same information element might have different information element value in different GTP versions. For example, \texttt{cause} has value $1$ in GTPv0 and GTPv1, but $2$ in GTPv2. \texttt{gtp\_info} will match to a different value depending on the version number in the packet. When an information element is not defined in a version, any packet in that version will always return ``No match''. If an integer is used to specify information element type, every GTP packet is evaluated, no matter what version the packet is. If the message type matches the value in packet, it will return ``Match''.\\ \textit{Syntax} \footnotesize \begin{verbatim} gtp_info:; ie = "0-255"| "rai" | "tmsi"... \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} gtp_info: 16; gtp_info: tmsi \end{verbatim} \normalsize \textit{GTP information elements} \small \begin{longtable}{|r|c|c|c|p{13.5cm}|} \hline Type & GTPv0 & GTPv1 & GTPv2\\ \hline 0 & N/A & N/A & N/A \\ \hline 1 & cause & cause & imsi\\ \hline 2 & imsi & imsi & cause \\ \hline 3 & rai & rai & recovery\\ \hline 4 & tlli & tlli & N/A\\ \hline 5 & p\_tmsi & p\_tmsi & N/A\\ \hline 6 & qos & N/A & N/A\\ \hline 7 & N/A & N/A & N/A \\ \hline 8 & recording\_required & recording\_required & N/A\\ \hline 9 & authentication & authentication & N/A\\ \hline 10 & N/A & N/A & N/A\\ \hline 11 & map\_cause & map\_cause & N/A\\ \hline 12 & p\_tmsi\_sig & p\_tmsi\_sig & N/A\\ \hline 13 & ms\_validated & ms\_validated & N/A\\ \hline 14 & recovery & recovery & N/A\\ \hline 15 & selection\_mode & selection\_mode & N/A\\ \hline 16 & flow\_label\_data\_1 & teid\_1 & N/A\\ \hline 17 & flow\_label\_signalling & teid\_control & N/A\\ \hline 18 & flow\_label\_data\_2 & teid\_2 & N/A\\ \hline 19 & ms\_unreachable & teardown\_ind & N/A\\ \hline 20 & N/A & nsapi & N/A\\ \hline 21 & N/A & ranap & N/A\\ \hline 22 & N/A & rab\_context & N/A\\ \hline 23 & N/A & radio\_priority\_sms & N/A\\ \hline 24 & N/A & radio\_priority & N/A\\ \hline 25 & N/A & packet\_flow\_id & N/A\\ \hline 26 & N/A & charging\_char & N/A\\ \hline 27 & N/A & trace\_ref & N/A\\ \hline 28 & N/A & trace\_type & N/A\\ \hline 29 & N/A & ms\_unreachable & N/A\\ \hline 71 & N/A & N/A & apn\\ \hline 72 & N/A & N/A & ambr\\ \hline 73 & N/A & N/A & ebi\\ \hline 74 & N/A & N/A & ip\_addr\\ \hline 75 & N/A & N/A & mei\\ \hline 76 & N/A & N/A & msisdn\\ \hline 77 & N/A & N/A & indication\\ \hline 78 & N/A & N/A & pco\\ \hline 79 & N/A & N/A & paa\\ \hline 80 & N/A & N/A & bearer\_qos\\ \hline 81 & N/A & N/A & flow\_qos\\ \hline 82 & N/A & N/A & rat\_type\\ \hline 83 & N/A & N/A & serving\_network\\ \hline 84 & N/A & N/A & bearer\_tft\\ \hline 85 & N/A & N/A & tad\\ \hline 86 & N/A & N/A & uli\\ \hline 87 & N/A & N/A & f\_teid\\ \hline 88 & N/A & N/A & tmsi\\ \hline 89 & N/A & N/A & cn\_id\\ \hline 90 & N/A & N/A & s103pdf\\ \hline 91 & N/A & N/A & s1udf\\ \hline 92 & N/A & N/A & delay\_value\\ \hline 93 & N/A & N/A & bearer\_context\\ \hline 94 & N/A & N/A & charging\_id\\ \hline 95 & N/A & N/A & charging\_char\\ \hline 96 & N/A & N/A & trace\_info\\ \hline 97 & N/A & N/A & bearer\_flag\\ \hline 98 & N/A & N/A & N/A\\ \hline 99 & N/A & N/A & pdn\_type\\ \hline 100 & N/A & N/A & pti\\ \hline 101 & N/A & N/A & drx\_parameter\\ \hline 102 & N/A & N/A & N/A\\ \hline 103 & N/A & N/A & gsm\_key\_tri\\ \hline 104 & N/A & N/A & umts\_key\_cipher\_quin\\ \hline 105 & N/A & N/A & gsm\_key\_cipher\_quin\\ \hline 106 & N/A & N/A & umts\_key\_quin\\ \hline 107 & N/A & N/A & eps\_quad\\ \hline 108 & N/A & N/A & umts\_key\_quad\_quin\\ \hline 109 & N/A & N/A & pdn\_connection\\ \hline 110 & N/A & N/A & pdn\_number\\ \hline 111 & N/A & N/A & p\_tmsi\\ \hline 112 & N/A & N/A & p\_tmsi\_sig\\ \hline 113 & N/A & N/A & hop\_counter\\ \hline 114 & N/A & N/A & ue\_time\_zone\\ \hline 115 & N/A & N/A & trace\_ref\\ \hline 116 & N/A & N/A & complete\_request\_msg\\ \hline 117 & N/A & N/A & guti\\ \hline 118 & N/A & N/A & f\_container\\ \hline 119 & N/A & N/A & f\_cause\\ \hline 120 & N/A & N/A & plmn\_id\\ \hline 121 & N/A & N/A & target\_id\\ \hline 122 & N/A & N/A & N/A\\ \hline 123 & N/A & N/A & packet\_flow\_id\\ \hline 124 & N/A & N/A & rab\_contex\\ \hline 125 & N/A & N/A & src\_rnc\_pdcp\\ \hline 126 & N/A & N/A & udp\_src\_port\\ \hline 127 & charge\_id & charge\_id & apn\_restriction\\ \hline 128 & end\_user\_address & end\_user\_address & selection\_mode\\ \hline 129 & mm\_context & mm\_context & src\_id\\ \hline 130 & pdp\_context & pdp\_context & N/A\\ \hline 131 & apn & apn & change\_report\_action\\ \hline 132 & protocol\_config & protocol\_config & fq\_csid\\ \hline 133 & gsn & gsn & channel\\ \hline 134 & msisdn & msisdn & emlpp\_pri\\ \hline 135 & N/A & qos & node\_type\\ \hline 136 & N/A & authentication\_qu & fqdn\\ \hline 137 & N/A & tft & ti\\ \hline 138 & N/A & target\_id & mbms\_session\_duration\\ \hline 139 & N/A & utran\_trans & mbms\_service\_area\\ \hline 140 & N/A & rab\_setup & mbms\_session\_id\\ \hline 141 & N/A & ext\_header & mbms\_flow\_id\\ \hline 142 & N/A & trigger\_id & mbms\_ip\_multicast\\ \hline 143 & N/A & omc\_id & mbms\_distribution\_ack\\ \hline 144 & N/A & ran\_trans & rfsp\_index\\ \hline 145 & N/A & pdp\_context\_pri & uci\\ \hline 146 & N/A & addi\_rab\_setup & csg\_info\\ \hline 147 & N/A & sgsn\_number & csg\_id\\ \hline 148 & N/A & common\_flag & cmi\\ \hline 149 & N/A & apn\_restriction & service\_indicator\\ \hline 150 & N/A & radio\_priority\_lcs & detach\_type\\ \hline 151 & N/A & rat\_type & ldn\\ \hline 152 & N/A & user\_loc\_info & node\_feature\\ \hline 153 & N/A & ms\_time\_zone & mbms\_time\_to\_transfer\\ \hline 154 & N/A & imei\_sv & throttling\\ \hline 155 & N/A & camel & arp\\ \hline 156 & N/A & mbms\_ue\_context & epc\_timer\\ \hline 157 & N/A & tmp\_mobile\_group\_id & signalling\_priority\_indication\\ \hline 158 & N/A & rim\_routing\_addr & tmgi\\ \hline 159 & N/A & mbms\_config & mm\_srvcc\\ \hline 160 & N/A & mbms\_service\_area & flags\_srvcc\\ \hline 161 & N/A & src\_rnc\_pdcp & mmbr\\ \hline 162 & N/A & addi\_trace\_info & N/A\\ \hline 163 & N/A & hop\_counter & N/A\\ \hline 164 & N/A & plmn\_id & N/A\\ \hline 165 & N/A & mbms\_session\_id & N/A\\ \hline 166 & N/A & mbms\_2g3g\_indicator & N/A\\ \hline 167 & N/A & enhanced\_nsapi & N/A\\ \hline 168 & N/A & mbms\_session\_duration & N/A\\ \hline 169 & N/A & addi\_mbms\_trace\_info & N/A\\ \hline 170 & N/A & mbms\_session\_repetition\_num & N/A\\ \hline 171 & N/A & mbms\_time\_to\_data & N/A\\ \hline 173 & N/A & bss & N/A\\ \hline 174 & N/A & cell\_id & N/A\\ \hline 175 & N/A & pdu\_num & N/A\\ \hline 176 & N/A & N/A & N/A\\ \hline 177 & N/A & mbms\_bearer\_capab & N/A\\ \hline 178 & N/A & rim\_routing\_disc & N/A\\ \hline 179 & N/A & list\_pfc & N/A\\ \hline 180 & N/A & ps\_xid & N/A\\ \hline 181 & N/A & ms\_info\_change\_report & N/A\\ \hline 182 & N/A & direct\_tunnel\_flags & N/A\\ \hline 183 & N/A & correlation\_id & N/A\\ \hline 184 & N/A & bearer\_control\_mode & N/A\\ \hline 185 & N/A & mbms\_flow\_id & N/A\\ \hline 186 & N/A & mbms\_ip\_multicast & N/A\\ \hline 187 & N/A & mbms\_distribution\_ack & N/A\\ \hline 188 & N/A & reliable\_inter\_rat\_handover & N/A\\ \hline 189 & N/A & rfsp\_index & N/A\\ \hline 190 & N/A & fqdn & N/A\\ \hline 191 & N/A & evolved\_allocation1 & N/A\\ \hline 192 & N/A & evolved\_allocation2 & N/A\\ \hline 193 & N/A & extended\_flags & N/A\\ \hline 194 & N/A & uci & N/A\\ \hline 195 & N/A & csg\_info & N/A\\ \hline 196 & N/A & csg\_id & N/A\\ \hline 197 & N/A & cmi & N/A\\ \hline 198 & N/A & apn\_ambr & N/A\\ \hline 199 & N/A & ue\_network & N/A\\ \hline 200 & N/A & ue\_ambr & N/A\\ \hline 201 & N/A & apn\_ambr\_nsapi & N/A\\ \hline 202 & N/A & ggsn\_backoff\_timer & N/A\\ \hline 203 & N/A & signalling\_priority\_indication & N/A\\ \hline 204 & N/A & signalling\_priority\_indication\_nsapi & N/A\\ \hline 205 & N/A & high\_bitrate & N/A\\ \hline 206 & N/A & max\_mbr & N/A\\ \hline 250 & N/A & N/A & N/A\\ \hline & N/A & N/A & N/A\\ \hline 251 & charging\_gateway\_addr & charging\_gateway\_addr & N/A\\ \hline 255 & private\_extension & private\_extension & private\_extension\\ \hline \end{longtable} \end{itemize} \texttt{gtp\_version} \label{gtp:gtp_version} \begin{itemize} \item[] The \texttt{gtp\_version} keyword is used to check for specific GTP version. \item[] Because different GTP version defines different message types and information elements, this keyword should combine with \texttt{gtp\_type} and \texttt{gtp\_info.}\\ \textit{Syntax} \footnotesize \begin{verbatim} gtp_version:; version = "0, 1, 2' \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} gtp_version: 1; \end{verbatim} \normalsize \end{itemize} \subsection{Modbus Preprocessor} \label{sub:modbus} The Modbus preprocessor is a Snort module that decodes the Modbus protocol. It also provides rule options to access certain protocol fields. This allows a user to write rules for Modbus packets without decoding the protocol with a series of "content" and "byte\_test" options. Modbus is a protocol used in SCADA networks. If your network does not contain any Modbus-enabled devices, we recommend leaving this preprocessor turned off. \subsubsection{Dependency Requirements} For proper functioning of the preprocessor: \begin{itemize} \item Stream session tracking must be enabled, i.e. stream5. TCP must be enabled in stream5. The preprocessor requires a session tracker to keep its data. \item Protocol Aware Flushing (PAF) must be enabled. \item IP defragmentation should be enabled, i.e. the frag3 preprocessor should be enabled and configured. \end{itemize} \subsubsection{Preprocessor Configuration} To get started, the Modbus preprocessor must be enabled. The preprocessor name is \texttt{modbus}. \begin{verbatim} preprocessor modbus \end{verbatim} \textit{Option syntax} \begin{itemize} \item[] \begin{tabular}{|l|c|c|p{6cm}|} \hline Option & Argument & Required & Default\\ \hline \hline \texttt{ports} & \texttt{} & NO & \texttt{ports \{ 502 \} }\\ \hline \end{tabular} \end{itemize} \normalsize \textit{Option explanations} \begin{itemize} \item[] \texttt{ports} \begin{itemize} \item[] This specifies on what ports to check for Modbus messages. Typically, this will include 502. \item[] \textit{Syntax} \begin{verbatim} ports { [< ... >] } \end{verbatim} \item[] \textit{Examples} \begin{verbatim} ports { 1237 3945 5067 } \end{verbatim} \item[] Note: there are spaces before and after `\{' and `\}'. \end{itemize} \end{itemize} \normalsize \textit{Default configuration} \footnotesize \begin{verbatim} preprocessor modbus \end{verbatim} \normalsize \subsubsection{Rule Options} The Modbus preprocessor adds 3 new rule options. These rule options match on various pieces of the Modbus headers: \begin{itemize} \item[] \begin{verbatim} modbus_func modbus_unit modbus_data \end{verbatim} \end{itemize} The preprocessor must be enabled for these rule option to work. \texttt{modbus\_func} \label{modbus:modbus_func} \begin{itemize} \item[] This option matches against the Function Code inside of a Modbus header. The code may be a number (in decimal format), or a string from the list provided below. \end{itemize} \textit{Syntax} \footnotesize \begin{verbatim} modbus_func: code = 0-255 | "read_coils" | "read_discrete_inputs" | "read_holding_registers" | "read_input_registers" | "write_single_coil" | "write_single_register" | "read_exception_status" | "diagnostics" | "get_comm_event_counter" | "get_comm_event_log" | "write_multiple_coils" | "write_multiple_registers" | "report_slave_id" | "read_file_record" | "write_file_record" | "mask_write_register" | "read_write_multiple_registers" | "read_fifo_queue" | "encapsulated_interface_transport" \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} modbus_func:1; modbus_func:write_multiple_coils; \end{verbatim} \normalsize \texttt{modbus\_unit} \label{modbus:modbus_unit} \begin{itemize} \item[] This option matches against the Unit ID field in a Modbus header. \end{itemize} \textit{Syntax} \footnotesize \begin{verbatim} modbus_unit: unit = 0-255 \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} modbus_unit:1; \end{verbatim} \normalsize \texttt{modbus\_data} \label{modbus:modbus_data} \begin{itemize} \item[] This rule option sets the cursor at the beginning of the Data field in a Modbus request/response. \end{itemize} \textit{Syntax} \footnotesize \begin{verbatim} modbus_data; \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} modbus_data; content:"badstuff"; \end{verbatim} \normalsize \subsubsection{Preprocessor Events} The Modbus preprocessor uses GID 144 for its preprocessor events. \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline 1 & The length in the Modbus header does not match the length needed \\ & by the Modbus function code. \\ &\\ & Each Modbus function has an expected format for requests and responses. \\ & If the length of the message does not match the expected format, this \\ & alert is generated. \\ \hline 2 & Modbus protocol ID is non-zero. \\ &\\ & The protocol ID field is used for multiplexing other protocols with \\ & Modbus. Since the preprocessor cannot handle these other protocols, \\ & this alert is generated instead. \\ \hline 3 & Reserved Modbus function code in use. \\ \hline \end{longtable} \subsection{DNP3 Preprocessor} \label{sub:dnp3} The DNP3 preprocessor is a Snort module that decodes the DNP3 protocol. It also provides rule options to access certain protocol fields. This allows a user to write rules for DNP3 packets without decoding the protocol with a series of "content" and "byte\_test" options. DNP3 is a protocol used in SCADA networks. If your network does not contain any DNP3-enabled devices, we recommend leaving this preprocessor turned off. \subsubsection{Dependency Requirements} For proper functioning of the preprocessor: \begin{itemize} \item Stream session tracking must be enabled, i.e. stream5. TCP or UDP must be enabled in stream5. The preprocessor requires a session tracker to keep its data. \item Protocol Aware Flushing (PAF) must be enabled. \item IP defragmentation should be enabled, i.e. the frag3 preprocessor should be enabled and configured. \end{itemize} \subsubsection{Preprocessor Configuration} To get started, the DNP3 preprocessor must be enabled. The preprocessor name is \texttt{dnp3}. \begin{verbatim} preprocessor dnp3 \end{verbatim} \textit{Option syntax} \begin{itemize} \item[] \begin{tabular}{|l|c|c|p{6cm}|} \hline Option & Argument & Required & Default\\ \hline \hline \texttt{ports} & \texttt{} & NO & \texttt{ports \{ 20000 \} }\\ \texttt{memcap} & \texttt{ [< ... >] } \end{verbatim} \item[] \textit{Examples} \begin{verbatim} ports { 1237 3945 5067 } \end{verbatim} \item[] Note: there are spaces before and after `\{' and `\}'. \end{itemize} \item[] \texttt{memcap} \begin{itemize} \item[] This sets a maximum to the amount of memory allocated to the DNP3 preprocessor for session-tracking purposes. The argument is given in bytes. Each session requires about 4 KB to track, and the default is 256 kB. This gives the preprocessor the ability to track 63 DNP3 sessions simultaneously. Setting the memcap below 4144 bytes will cause a fatal error. When multiple configs are used, the memcap in the non-default configs will be overwritten by the memcap in the default config. If the default config isn't intended to inspect DNP3 traffic, use the "disabled" keyword. \end{itemize} \item[] \texttt{check\_crc} \begin{itemize} \item[] This option makes the preprocessor validate the checksums contained in DNP3 Link-Layer Frames. Frames with invalid checksums will be ignored. If the corresponding preprocessor rule is enabled, invalid checksums will generate alerts. The corresponding rule is GID 145, SID 1. \end{itemize} \item[] \texttt{disabled} \begin{itemize} \item[] This option is used for loading the preprocessor without inspecting any DNP3 traffic. The \texttt{disabled} keyword is only useful when the DNP3 preprocessor is turned on in a separate policy. \end{itemize} \end{itemize} \normalsize \textit{Default configuration} \footnotesize \begin{verbatim} preprocessor dnp3 \end{verbatim} \normalsize \subsubsection{Rule Options} The DNP3 preprocessor adds 4 new rule options. These rule options match on various pieces of the DNP3 headers: \begin{itemize} \item[] \begin{verbatim} dnp3_func dnp3_obj dnp3_ind dnp3_data \end{verbatim} \end{itemize} The preprocessor must be enabled for these rule option to work. \texttt{dnp3\_func} \label{dnp3:dnp3_func} \begin{itemize} \item[] This option matches against the Function Code inside of a DNP3 Application-Layer request/response header. The code may be a number (in decimal format), or a string from the list provided below. \end{itemize} \textit{Syntax} \footnotesize \begin{verbatim} dnp3_func: code = 0-255 | "confirm" | "read" | "write" | "select" | "operate" | "direct_operate" | "direct_operate_nr" | "immed_freeze" | "immed_freeze_nr" | "freeze_clear" | "freeze_clear_nr" | "freeze_at_time" | "freeze_at_time_nr" | "cold_restart" | "warm_restart" | "initialize_data" | "initialize_appl" | "start_appl" | "stop_appl" | "save_config" | "enable_unsolicited" | "disable_unsolicited" | "assign_class" | "delay_measure" | "record_current_time" | "open_file" | "close_file" | "delete_file" | "get_file_info" | "authenticate_file" | "abort_file" | "activate_config" | "authenticate_req" | "authenticate_err" | "response" | "unsolicited_response" | "authenticate_resp" \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} dnp3_func:1; dnp3_func:delete_file; \end{verbatim} \normalsize \texttt{dnp3\_ind} \label{dnp3:dnp3_ind} \begin{itemize} \item[] This option matches on the Internal Indicators flags present in a DNP3 Application Response Header. Much like the TCP flags rule option, providing multiple flags in one option will cause the rule to fire if \emph{ANY} one of the flags is set. To alert on a combination of flags, use multiple rule options. \end{itemize} \textit{Syntax} \footnotesize \begin{verbatim} dnp3_ind:{,...] flag = "all_stations" "class_1_events" "class_2_events" "class_3_events" "need_time" "local_control" "defice_trouble" "device_restart" "no_func_code_support" "object_unknown" "parameter_error" "event_buffer_overflow" "already_executing" "config_corrupt" "reserved_2" "reserved_1" \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} # Alert on reserved_1 OR reserved_2 dnp3_ind:reserved_1,reserved_2; # Alert on class_1 AND class_2 AND class_3 events dnp3_ind:class_1_events; dnp3_ind:class_2_events; dnp3_ind:class_3_events; \end{verbatim} \normalsize \texttt{dnp3\_obj} \label{dnp3:dnp3_obj} \begin{itemize} \item[] This option matches on DNP3 object headers present in a request or response. \end{itemize} \textit{Syntax} \footnotesize \begin{verbatim} dnp3_obj:, group = 0 - 255 var = 0 - 255 \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} # Alert on DNP3 "Date and Time" object dnp3_obj:50,1; \end{verbatim} \normalsize \texttt{dnp3\_data} \label{dnp3:dnp3_data} \begin{itemize} \item[] As Snort processes DNP3 packets, the DNP3 preprocessor collects Link-Layer Frames and reassembles them back into Application-Layer Fragments. This rule option sets the cursor to the beginning of an Application-Layer Fragment, so that other rule options can work on the reassembled data. With the dnp3\_data rule option, you can write rules based on the data within Fragments without splitting up the data and adding CRCs every 16 bytes. \end{itemize} \textit{Syntax} \footnotesize \begin{verbatim} dnp3_data; \end{verbatim} \normalsize \textit{Examples} \footnotesize \begin{verbatim} dnp3_data; content:"badstuff_longer_than_16chars"; \end{verbatim} \normalsize \subsubsection{Preprocessor Events} The DNP3 preprocessor uses GID 145 for its preprocessor events. \begin{longtable}{|r|p{13.5cm}|} \hline SID & Description\\ \hline 1 & A Link-Layer Frame contained an invalid CRC. \\ & (Enable \texttt{check\_crc} in the preprocessor config to get this alert.) \\ \hline 2 & A DNP3 Link-Layer Frame was dropped, due to an invalid length. \\ \hline 3 & A Transport-Layer Segment was dropped during reassembly. \\ & This happens when segments have invalid sequence numbers. \\ \hline 4 & The DNP3 Reassembly buffer was cleared before a complete fragment could \\ & be reassembled. \\ & This happens when a segment carrying the "FIR" flag appears after some \\ & other segments have been queued. \\ \hline 5 & A DNP3 Link-Layer Frame is larger than 260 bytes. \\ \hline 6 & A DNP3 Link-Layer Frame uses an address that is reserved. \\ \hline 7 & A DNP3 request or response uses a reserved function code. \\ \hline \end{longtable} \section{Decoder and Preprocessor Rules} Decoder and preprocessor rules allow one to enable and disable decoder and preprocessor events on a rule by rule basis. They also allow one to specify the rule type or action of a decoder or preprocessor event on a rule by rule basis. Decoder config options will still determine whether or not to generate decoder events. For example, if \texttt{config disable\_decode\_alerts} is in \texttt{snort.conf}, decoder events will not be generated regardless of whether or not there are corresponding rules for the event. Also note that if the decoder is configured to enable drops, e.g. \texttt{config enable\_decode\_drops}, these options will take precedence over the event type of the rule. A packet will be dropped if either a decoder config drop option is in \texttt{snort.conf} or the decoder or preprocessor rule type is \texttt{drop}. Of course, the drop cases only apply if Snort is running inline. See \texttt{doc/README.decode} for config options that control decoder events. \subsection{Configuring} The decoder and preprocessor rules are located in the \texttt{preproc\_rules/} directory in the top level source tree, and have the names \texttt{decoder.rules} and \texttt{preprocessor.rules} respectively. These files are updated as new decoder and preprocessor events are added to Snort. The \texttt{gen-msg.map} under \texttt{etc} directory is also updated with new decoder and preprocessor rules. To enable these rules in \texttt{snort.conf}, define the path to where the rules are located and uncomment the \texttt{include} lines in \texttt{snort.conf} that reference the rules files. \begin{verbatim} var PREPROC_RULE_PATH /path/to/preproc_rules ... include $PREPROC_RULE_PATH/preprocessor.rules include $PREPROC_RULE_PATH/decoder.rules \end{verbatim} To disable any rule, just comment it with a \texttt{\#} or remove the rule completely from the file (commenting is recommended). To change the rule type or action of a decoder/preprocessor rule, just replace \texttt{alert} with the desired rule type. Any one of the following rule types can be used: \begin{verbatim} alert log pass drop sdrop reject \end{verbatim} For example one can change: \begin{verbatim} alert ( msg: "DECODE_NOT_IPV4_DGRAM"; sid: 1; gid: 116; rev: 1; \ metadata: rule-type decode ; classtype:protocol-command-decode;) \end{verbatim} to \begin{verbatim} drop ( msg: "DECODE_NOT_IPV4_DGRAM"; sid: 1; gid: 116; rev: 1; \ metadata: rule-type decode ; classtype:protocol-command-decode;) \end{verbatim} to drop (as well as alert on) packets where the Ethernet protocol is IPv4 but version field in IPv4 header has a value other than 4. See \texttt{README.decode}, \texttt{README.gre} and the various preprocessor READMEs for descriptions of the rules in \texttt{decoder.rules} and \texttt{preprocessor.rules}. The generator ids ( gid ) for different preprocessors and the decoder are as follows: \begin{table}[h] \begin{center} \begin{tabular}{| l | l |} \hline \textbf{Generator Id} & \textbf{Module}\\ \hline \hline \texttt{105} & Back Orifice preprocessor \\ \hline \texttt{106} & RPC Decode preprocessor \\ \hline \texttt{112} & Arpspoof preprocessor \\ \hline \texttt{116} & Snort Decoder \\ \hline \texttt{119} & HTTP Inspect preprocessor ( Client ) \\ \hline \texttt{120} & HTTP Inspect preprocessor ( Server ) \\ \hline \texttt{122} & Portscan preprocessor \\ \hline \texttt{123} & Frag3 preprocessor \\ \hline \texttt{124} & SMTP preprocessor \\ \hline \texttt{125} & FTP (FTP) preprocessor \\ \hline \texttt{126} & FTP (Telnet) preprocessor \\ \hline \texttt{127} & ISAKMP preprocessor \\ \hline \texttt{128} & SSH preprocessor \\ \hline \texttt{129} & Stream5 preprocessor \\ \hline \texttt{131} & DNS preprocessor \\ \hline \texttt{132} & Skype preprocessor \\ \hline \texttt{133} & DceRpc2 preprocessor \\ \hline \texttt{134} & PPM preprocessor \\ \hline \texttt{136} & Reputation preprocessor \\ \hline \texttt{137} & SSL preprocessor \\ \hline \texttt{139} & SDF preprocessor \\ \hline \texttt{140} & SIP preprocessor \\ \hline \texttt{141} & IMAP preprocessor \\ \hline \texttt{142} & POP preprocessor \\ \hline \texttt{143} & GTP preprocessor \\ \hline \end{tabular} \end{center} \end{table} \subsection{Reverting to original behavior} The following config option in \texttt{snort.conf} will make Snort revert to the old behavior: \begin{verbatim} config autogenerate_preprocessor_decoder_rules \end{verbatim} Note that if you want to revert to the old behavior, you also have to remove the decoder and preprocessor rules and any reference to them from \texttt{snort.conf}, otherwise they will be loaded. This option applies to rules not specified and the default behavior is to alert. \section{Event Processing} Snort provides a variety of mechanisms to tune event processing to suit your needs: \begin{itemize} \item \texttt{Detection Filters} You can use detection filters to specify a threshold that must be exceeded before a rule generates an event. This is covered in section \ref{detection_filter}. \item \texttt{Rate Filters} You can use rate filters to change a rule action when the number or rate of events indicates a possible attack. \item \texttt{Event Filters} You can use event filters to reduce the number of logged events for noisy rules. This can be tuned to significantly reduce false alarms. \item \texttt{Event Suppression} You can completely suppress the logging of uninteresting events. \end{itemize} \subsection{Rate Filtering} \label{rate_filtering} \texttt{rate\_filter} provides rate based attack prevention by allowing users to configure a new action to take for a specified time when a given rate is exceeded. Multiple rate filters can be defined on the same rule, in which case they are evaluated in the order they appear in the configuration file, and the first applicable action is taken. \subsubsection{Format} Rate filters are used as standalone configurations (outside of a rule) and have the following format: \begin{verbatim} rate_filter \ gen_id , sig_id , \ track , \ count , seconds , \ new_action alert|drop|pass|log|sdrop|reject, \ timeout \ [, apply_to ] \end{verbatim} The options are described in the table below - all are required except \texttt{apply\_to}, which is optional. % fixthis this table should appear here with the [h] but floats away! \begin{table}[h] \begin{center} \begin{tabular}{| p{2in} | p{4in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{track by\_src | by\_dst | by\_rule} & rate is tracked either by source IP address, destination IP address, or by rule. This means the match statistics are maintained for each unique source IP address, for each unique destination IP address, or they are aggregated at rule level. For rules related to Stream5 sessions, source and destination means client and server respectively. \texttt{track by\_rule} and \texttt{apply\_to} may not be used together.\\ \hline \texttt{count c} & the maximum number of rule matches in \texttt{s} seconds before the rate filter limit to is exceeded. \texttt{c} must be nonzero value.\\ \hline \texttt{seconds s} & the time period over which \texttt{count} is accrued. 0 seconds means \texttt{count} is a total count instead of a specific rate. For example, \texttt{rate\_filter} may be used to detect if the number of connections to a specific server exceed a specific count. 0 seconds only applies to internal rules (gen\_id 135) and other use will produce a fatal error by Snort.\\ \hline \texttt{new\_action alert | drop | pass | log | sdrop | reject} & \texttt{new\_action} replaces rule action for \texttt{t} seconds. \texttt{drop}, \texttt{reject}, and \texttt{sdrop} can be used only when snort is used in inline mode. \texttt{sdrop} and \texttt{reject} are conditionally compiled with GIDS.\\ \hline \texttt{timeout t} & revert to the original rule action after \texttt{t} seconds. If \texttt{t} is 0, then rule action is never reverted back. An \texttt{event\_filter} may be used to manage number of alerts after the rule action is enabled by \texttt{rate\_filter}.\\ \hline \texttt{apply\_to } & restrict the configuration to only to source or destination IP address (indicated by track parameter) determined by \texttt{}. \texttt{track by\_rule} and \texttt{apply\_to} may not be used together. Note that events are generated during the timeout period, even if the rate falls below the configured limit.\\ \hline \end{tabular} \end{center} \end{table} \subsubsection{Examples} Example 1 - allow a maximum of 100 connection attempts per second from any one IP address, and block further connection attempts from that IP address for 10 seconds: \begin{verbatim} rate_filter \ gen_id 135, sig_id 1, \ track by_src, \ count 100, seconds 1, \ new_action drop, timeout 10 \end{verbatim} Example 2 - allow a maximum of 100 successful simultaneous connections from any one IP address, and block further connections from that IP address for 10 seconds: \begin{verbatim} rate_filter \ gen_id 135, sig_id 2, \ track by_src, \ count 100, seconds 0, \ new_action drop, timeout 10 \end{verbatim} \subsection{Event Filtering} \label{event_filtering} Event filtering can be used to reduce the number of logged alerts for noisy rules by limiting the number of times a particular event is logged during a specified time interval. This can be tuned to significantly reduce false alarms. There are 3 types of event filters: \begin{itemize} \item \texttt{limit} Alerts on the 1st \textit{m} events during the time interval, then ignores events for the rest of the time interval. \item \texttt{threshold} Alerts every \textit{m} times we see this event during the time interval. \item \texttt{both} Alerts once per time interval after seeing \textit{m} occurrences of the event, then ignores any additional events during the time interval. \end{itemize} \subsubsection{Format} \begin{verbatim} event_filter \ gen_id , sig_id , \ type , \ track , \ count , seconds threshold \ gen_id , sig_id , \ type , \ track , \ count , seconds \end{verbatim} \texttt{threshold} is an alias for \texttt{event\_filter}. Both formats are equivalent and support the options described below - all are required. \texttt{threshold} is deprecated and will not be supported in future releases. \begin{table}[h] \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{gen\_id } & Specify the generator ID of an associated rule. \texttt{gen\_id 0, sig\_id 0} can be used to specify a "global" threshold that applies to all rules.\\ \hline \texttt{sig\_id } & Specify the signature ID of an associated rule. \texttt{sig\_id 0} specifies a "global" filter because it applies to all \texttt{sig\_id}s for the given \texttt{gen\_id}.\\ \hline \texttt{type limit|threshold|both} & type \texttt{limit} alerts on the 1st m events during the time interval, then ignores events for the rest of the time interval. Type \texttt{threshold} alerts every m times we see this event during the time interval. Type \texttt{both} alerts once per time interval after seeing m occurrences of the event, then ignores any additional events during the time interval.\\ \hline \texttt{track by\_src|by\_dst} & rate is tracked either by source IP address, or destination IP address. This means count is maintained for each unique source IP addresses, or for each unique destination IP addresses. Ports or anything else are not tracked.\\ \hline \texttt{count c} & number of rule matching in s seconds that will cause \texttt{event\_filter} limit to be exceeded. \texttt{c} must be nonzero value. A value of -1 disables the event filter and can be used to override the global \texttt{event\_filter}.\\ \hline \texttt{seconds s} & time period over which \texttt{count} is accrued. \texttt{s} must be nonzero value.\\ \hline \end{tabular} \end{center} \end{table} \begin{note} Only one \texttt{event\_filter} may be defined for a given \texttt{gen\_id, sig\_id}. If more than one \texttt{event\_filter} is applied to a specific \texttt{gen\_id, sig\_id} pair, Snort will terminate with an error while reading the configuration information. \end{note} \texttt{event\_filter}s with \texttt{sig\_id} 0 are considered "global" because they apply to all rules with the given \texttt{gen\_id}. If \texttt{gen\_id} is also 0, then the filter applies to all rules. (\texttt{gen\_id 0, sig\_id != 0} is not allowed). Standard filtering tests are applied first, if they do not block an event from being logged, the global filtering test is applied. Thresholds in a rule (deprecated) will override a global \texttt{event\_filter}. Global \texttt{event\_filter}s do not override what's in a signature or a more specific stand-alone \texttt{event\_filter}. \begin{note} \texttt{event\_filters} can be used to suppress excessive \texttt{rate\_filter} alerts, however, the first \texttt{new\_action} event of the timeout period is never suppressed. Such events indicate a change of state that are significant to the user monitoring the network. \end{note} \subsubsection{Examples} Limit logging to 1 event per 60 seconds: \begin{verbatim} event_filter \ gen_id 1, sig_id 1851, \ type limit, track by_src, \ count 1, seconds 60 \end{verbatim} Limit logging to every 3rd event: \begin{verbatim} event_filter \ gen_id 1, sig_id 1852, \ type threshold, track by_src, \ count 3, seconds 60 \end{verbatim} Limit logging to just 1 event per 60 seconds, but only if we exceed 30 events in 60 seconds: \begin{verbatim} event_filter \ gen_id 1, sig_id 1853, \ type both, track by_src, \ count 30, seconds 60 \end{verbatim} Limit to logging 1 event per 60 seconds per IP triggering each rule (rule gen\_id is 1): \begin{verbatim} event_filter \ gen_id 1, sig_id 0, \ type limit, track by_src, \ count 1, seconds 60 \end{verbatim} Limit to logging 1 event per 60 seconds per IP, triggering each rule for each event generator: \begin{verbatim} event_filter \ gen_id 0, sig_id 0, \ type limit, track by_src, \ count 1, seconds 60 \end{verbatim} Events in Snort are generated in the usual way, event filters are handled as part of the output system. Read gen-msg.map for details on gen ids. Users can also configure a memcap for threshold with a ``config:'' option: \begin{verbatim} config event_filter: memcap # this is deprecated: config threshold: memcap \end{verbatim} \subsection{Event Suppression} \label{event_suppression} Event suppression stops specified events from firing without removing the rule from the rule base. Suppression uses an IP list to select specific networks and users for suppression. Suppression tests are performed prior to either standard or global thresholding tests. Suppression are standalone configurations that reference generators, SIDs, and IP addresses via an IP list . This allows a rule to be completely suppressed, or suppressed when the causative traffic is going to or coming from a specific IP or group of IP addresses. You may apply multiple suppressions to a non-zero SID. You may also combine one \texttt{event\_filter} and several suppressions to the same non-zero SID. \subsubsection{Format} The suppress configuration has two forms: \begin{verbatim} suppress \ gen_id , sig_id \end{verbatim} \begin{verbatim} suppress \ gen_id , sig_id , \ track , ip \end{verbatim} \begin{table}[h] \begin{center} \begin{tabular}{| l | p{4.5in} |} \hline \textbf{Option} & \textbf{Description}\\ \hline \hline \texttt{gen\_id } & Specify the generator ID of an associated rule. \texttt{gen\_id 0, sig\_id 0} can be used to specify a "global" threshold that applies to all rules.\\ \hline \texttt{sig\_id } & Specify the signature ID of an associated rule. \texttt{sig\_id 0} specifies a "global" filter because it applies to all \texttt{sig\_id}s for the given \texttt{gen\_id}.\\ \hline \texttt{track by\_src|by\_dst} & Suppress by source IP address or destination IP address. This is optional, but if present, \texttt{ip} must be provided as well.\\ \hline \texttt{ip } & Restrict the suppression to only source or destination IP addresses (indicated by \texttt{track} parameter) determined by $<$list$>$. If track is provided, ip must be provided as well.\\ \hline \end{tabular} \end{center} \end{table} \subsubsection{Examples} Suppress this event completely: \begin{verbatim} suppress gen_id 1, sig_id 1852: \end{verbatim} Suppress this event from this IP: \begin{verbatim} suppress gen_id 1, sig_id 1852, track by_src, ip 10.1.1.54 \end{verbatim} Suppress this event to this CIDR block: \begin{verbatim} suppress gen_id 1, sig_id 1852, track by_dst, ip 10.1.1.0/24 \end{verbatim} \subsection{Event Logging} \label{eventqueue} Snort supports logging multiple events per packet/stream that are prioritized with different insertion methods, such as max content length or event ordering using the event queue. The general configuration of the event queue is as follows: \begin{verbatim} config event_queue: [max_queue [size]] [log [size]] [order_events [TYPE]] \end{verbatim} \subsubsection{Event Queue Configuration Options} There are three configuration options to the configuration parameter 'event\_queue'. \begin{slist} \item \texttt{max\_queue} This determines the maximum size of the event queue. For example, if the event queue has a max size of 8, only 8 events will be stored for a single packet or stream. The default value is 8. \item \texttt{log} This determines the number of events to log for a given packet or stream. You can't log more than the max\_event number that was specified. The default value is 3. \item \texttt{order\_events} This argument determines the way that the incoming events are ordered. We currently have two different methods: \begin{itemize} \item \texttt{priority} - The highest priority (1 being the highest) events are ordered first. \item \texttt{content\_length} - Rules are ordered before decode or preprocessor alerts, and rules that have a longer content are ordered before rules with shorter contents. \end{itemize} The method in which events are ordered does not affect rule types such as pass, alert, log, etc. The default value is content\_length. \end{slist} \subsubsection{Event Queue Configuration Examples} The default configuration: \begin{verbatim} config event_queue: max_queue 8 log 3 order_events content_length \end{verbatim} Example of a reconfigured event queue: \begin{verbatim} config event_queue: max_queue 10 log 3 order_events content_length \end{verbatim} Use the default event queue values, but change event order: \begin{verbatim} config event_queue: order_events priority \end{verbatim} Use the default event queue values but change the number of logged events: \begin{verbatim} config event_queue: log 2 \end{verbatim} \subsection{Event Trace} \label{eventtrace} Snort supports logging additional information to a file about the events it is generating relative to specific blocks of data that are matching the rule. The blocks of data logged include information about the event, the GID, SID, and other data related to the event itself, plus packet data including sizes, timestamps, raw, normalized, and decompressed buffers extracted from the packet that may have been used in evaluating the rule. The amount of packet data written is limited with each entry. This is useful in debugging rules. The \texttt{config} option \texttt{event\_trace} to \texttt{snort.conf} provides this control. The general configuration for event tracing is as follows: \begin{verbatim} config event_trace: [file ] [max_data ] \end{verbatim} The are two configuration options for \texttt{event\_trace}. \begin{slist} \item \texttt{file} This sets the file name into which the trace data is written, within Snort's log directory (see -l command line option). The default is event\_trace.txt. \item \texttt{max\_data} This specifies the maximum number of bytes from each buffer of data to write into the file. The default is 64 bytes and valid values range from 1 to 65535 bytes. \end{slist} \subsubsection{Event Trace Examples} The default configuration: \begin{verbatim} config event_trace: file event_trace.txt max_data 64 \end{verbatim} Use the default file, but change the amount of data logged: \begin{verbatim} config event_trace: max_data 128 \end{verbatim} Change the file name to which event traces are logged: \begin{verbatim} config event_trace: file snort_event_trace.out \end{verbatim} \section{Performance Profiling} Snort can provide statistics on rule and preprocessor performance. Each require only a simple \texttt{config} option to \texttt{snort.conf} and Snort will print statistics on the worst (or all) performers on exit. When a file name is provided in \texttt{profile\_rules} or \texttt{profile\_preprocs}, the statistics will be saved in these files. If \texttt{append} is not specified, a new file will be created each time Snort is run. The filenames will have timestamps appended to them. These files will be found in the logging directory. To use this feature, you must build snort with the \texttt{--enable-perfprofiling} option to the configure script. \subsection{Rule Profiling} \label{rule profiling} \subsubsection{Format} \begin{verbatim} config profile_rules: \ print [all | ], \ sort \ [,filename [append]] \end{verbatim} \begin{itemize} \item \texttt{} is the number of rules to print \item \texttt{} is one of: \subitem \texttt{checks} \subitem \texttt{matches} \subitem \texttt{nomatches} \subitem \texttt{avg\_ticks} \subitem \texttt{avg\_ticks\_per\_match} \subitem \texttt{avg\_ticks\_per\_nomatch} \subitem \texttt{total\_ticks} \item \texttt{} is the output filename \item \texttt{[append]} dictates that the output will go to the same file each time (optional) \end{itemize} \subsubsection{Examples} \begin{itemize} \item Print all rules, sort by avg\_ticks (default configuration if option is turned on) \subitem \texttt{config profile\_rules} \item Print all rules, sort by avg\_ticks, and append to file \texttt{rules\_stats.txt} \subitem \texttt{config profile\_rules: filename \texttt{rules\_stats.txt} append} \item Print the top 10 rules, based on highest average time \subitem \texttt{config profile\_rules: print 10, sort avg\_ticks} \item Print all rules, sorted by number of checks \subitem \texttt{config profile\_rules: print all, sort checks} \item Print top 100 rules, based on total time \subitem \texttt{config profile\_rules: print 100, sort total\_ticks} \item Print with default options, save results to performance.txt each time \subitem \texttt{config profile\_rules: filename performance.txt append} \item Print top 20 rules, save results to perf.txt with timestamp in filename \subitem \texttt{config profile\_rules: print 20, filename perf.txt} \end{itemize} \subsubsection{Output} Snort will print a table much like the following at exit. \begin{figure} \footnotesize{ \begin{verbatim} Rule Profile Statistics (worst 4 rules) ========================================================== Num SID GID Rev Checks Matches Alerts Ticks Avg/Check Avg/Match Avg/Nonmatch === === === === ====== ======= ====== ===== ========= ========= ============ 1 2389 1 12 1 1 1 385698 385698.0 385698.0 0.0 2 2178 1 17 2 0 0 107822 53911.0 0.0 53911.0 3 2179 1 8 2 0 0 92458 46229.0 0.0 46229.0 4 1734 1 37 2 0 0 90054 45027.0 0.0 45027.0 \end{verbatim} } \caption{\label{rule profiling example output}Rule Profiling Example Output} \end{figure} Configuration line used to print the above table: \subitem \texttt{config profile\_rules: print 4, sort total\_ticks} The columns represent: \begin{itemize} \item Number (rank) \item Sig ID \item Generator ID \item Checks (number of times rule was evaluated after fast pattern match within portgroup or any-$>$any rules) \item Matches (number of times ALL rule options matched, will be high for rules that have no options) \item Alerts (number of alerts generated from this rule) \item CPU Ticks \item Avg Ticks per Check \item Avg Ticks per Match \item Avg Ticks per Nonmatch \end{itemize} Interpreting this info is the key. The Microsecs (or Ticks) column is important because that is the total time spent evaluating a given rule. But, if that rule is causing alerts, it makes sense to leave it alone. A high Avg/Check is a poor performing rule, that most likely contains PCRE. High Checks and low Avg/Check is usually an any-$>$any rule with few rule options and no content. Quick to check, the few options may or may not match. We are looking at moving some of these into code, especially those with low SIDs. By default, this information will be printed to the console when Snort exits. You can use the "filename" option in snort.conf to specify a file where this will be written. If "append" is not specified, a new file will be created each time Snort is run. The filenames will have timestamps appended to them. These files will be found in the logging directory. \subsection{Preprocessor Profiling} \label{preproc profiling} \subsubsection{Format} \begin{verbatim} config profile_preprocs: \ print [all | ], \ sort \ [, filename [append]] \end{verbatim} \begin{itemize} \item \texttt{} is the number of preprocessors to print \item \texttt{} is one of: \subitem \texttt{checks} \subitem \texttt{avg\_ticks} \subitem \texttt{total\_ticks} \item \texttt{} is the output filename \item \texttt{[append]} dictates that the output will go to the same file each time (optional) \end{itemize} \subsubsection{Examples} \begin{itemize} \item Print all preprocessors, sort by avg\_ticks (default configuration if option is turned on) \subitem \texttt{config profile\_preprocs} \item Print all preprocessors, sort by avg\_ticks, and append to file \texttt{preprocs\_stats.txt} \subitem \texttt{config profile\_preprocs: filename \texttt{preprocs\_stats.txt} append} \item Print the top 10 preprocessors, based on highest average time \subitem \texttt{config profile\_preprocs: print 10, sort avg\_ticks} \item Print all preprocessors, sorted by number of checks \subitem \texttt{config profile\_preprocs: print all, sort checks} \end{itemize} \subsubsection{Output} Snort will print a table much like the following at exit. \begin{figure} \footnotesize{ \begin{verbatim} Preprocessor Profile Statistics (worst 10) ========================================================== Num Preprocessor Layer Checks Exits Microsecs Avg/Check Pct of Caller Pct of Total === ============ ===== ====== ===== ========= ========= ============= ============ 1 detect 0 338181 338181 9054573 26.77 64.62 64.62 1 rule eval 1 256978 256978 2570596 10.00 28.39 18.35 1 rule tree eval 2 399860 399860 2520629 6.30 98.06 17.99 1 pcre 3 51328 51328 505636 9.85 20.06 3.61 2 byte_jump 3 6 6 7 1.30 0.00 0.00 3 content 3 1077588 1077588 1123373 1.04 44.57 8.02 4 uricontent 3 106498 106498 79685 0.75 3.16 0.57 5 byte_test 3 9951 9951 5709 0.57 0.23 0.04 6 isdataat 3 8486 8486 3192 0.38 0.13 0.02 7 flowbits 3 135739 135739 35365 0.26 1.40 0.25 8 flags 3 2 2 0 0.20 0.00 0.00 9 preproc_rule_options 3 15499 15499 1939 0.13 0.08 0.01 10 flow 3 394817 394817 36420 0.09 1.44 0.26 11 file_data 3 15957 15957 1264 0.08 0.05 0.01 12 ack 3 4 4 0 0.07 0.00 0.00 2 rtn eval 2 36928 36928 17500 0.47 0.68 0.12 2 mpse 1 646528 646528 5840244 9.03 64.50 41.68 2 s5 0 310080 310080 3270702 10.55 23.34 23.34 1 s5tcp 1 310080 310080 2993020 9.65 91.51 21.36 1 s5TcpState 2 304484 304484 2559085 8.40 85.50 18.26 1 s5TcpFlush 3 22148 22148 70681 3.19 2.76 0.50 1 s5TcpProcessRebuilt 4 22132 22132 2018748 91.21 2856.11 14.41 2 s5TcpBuildPacket 4 22132 22132 34965 1.58 49.47 0.25 2 s5TcpData 3 184186 184186 120794 0.66 4.72 0.86 1 s5TcpPktInsert 4 46249 46249 89299 1.93 73.93 0.64 2 s5TcpNewSess 2 5777 5777 37958 6.57 1.27 0.27 3 httpinspect 0 204751 204751 1814731 8.86 12.95 12.95 4 ssl 0 10780 10780 16283 1.51 0.12 0.12 5 decode 0 312638 312638 437860 1.40 3.12 3.12 6 DceRpcMain 0 155358 155358 186061 1.20 1.33 1.33 1 DceRpcSession 1 155358 155358 156193 1.01 83.95 1.11 7 backorifice 0 77 77 42 0.55 0.00 0.00 8 smtp 0 45197 45197 17126 0.38 0.12 0.12 9 ssh 0 26453 26453 7195 0.27 0.05 0.05 10 dns 0 28 28 5 0.18 0.00 0.00 total total 0 311202 311202 14011946 45.03 0.00 0.00 \end{verbatim} } \caption{Preprocessor Profiling Example Output} \label{preprocessor profiling example output} \end{figure} Configuration line used to print the above table: \begin{verbatim} config profile_preprocs: \ print 10, sort total_ticks \end{verbatim} The columns represent: \begin{itemize} \item Number (rank) - The number is indented for each layer. Layer 1 preprocessors are listed under their respective caller (and sorted similarly). \item Preprocessor Name \item Layer - When printing a specific number of preprocessors all subtasks info for a particular preprocessor is printed for each layer 0 preprocessor stat. \item Checks (number of times preprocessor decided to look at a packet, ports matched, app layer header was correct, etc) \item Exits (number of corresponding exits -- just to verify code is instrumented correctly, should ALWAYS match Checks, unless an exception was trapped) \item CPU Ticks \item Avg Ticks per Check \item Percent of caller - For non layer 0 preprocessors, i.e. subroutines within preprocessors, this identifies the percent of the caller's ticks that is spent for this subtask. \end{itemize} Because of task swapping, non-instrumented code, and other factors, the Pct of Caller field will not add up to 100\% of the caller's time. It does give a reasonable indication of how much relative time is spent within each subtask. By default, this information will be printed to the console when Snort exits. You can use the "filename" option in snort.conf to specify a file where this will be written. If "append" is not specified, a new file will be created each time Snort is run. The filenames will have timestamps appended to them. These files will be found in the logging directory. \subsection{Packet Performance Monitoring (PPM)} \label{ppm} PPM provides thresholding mechanisms that can be used to provide a basic level of latency control for snort. It does not provide a hard and fast latency guarantee but should in effect provide a good average latency control. Both rules and packets can be checked for latency. The action taken upon detection of excessive latency is configurable. The following sections describe configuration, sample output, and some implementation details worth noting. To use PPM, you must build with the --enable-ppm or the --enable-sourcefire option to configure. PPM is configured as follows: \begin{verbatim} # Packet configuration: config ppm: max-pkt-time , \ fastpath-expensive-packets, \ pkt-log, \ debug-pkts # Rule configuration: config ppm: max-rule-time , \ threshold count, \ suspend-expensive-rules, \ suspend-timeout , \ rule-log [log] [alert] \end{verbatim} Packets and rules can be configured separately, as above, or together in just one config ppm statement. Packet and rule monitoring is independent, so one or both or neither may be enabled. \subsubsection{Configuration} Packet Configuration Options \texttt{max-pkt-time } \begin{itemize} \item enables packet latency thresholding using 'micros-secs' as the limit. \item default is 0 (packet latency thresholding disabled) \item reasonable starting defaults: 100/250/1000 for 1G/100M/5M nets \end{itemize} \texttt{fastpath-expensive-packets} \begin{itemize} \item enables stopping further inspection of a packet if the max time is exceeded \item default is off \end{itemize} \texttt{pkt-log} \begin{itemize} \item enables logging packet event if packet exceeds max-pkt-time \item default is no logging \item if no option is given for 'pkt-log', 'pkt-log log' is implied \item the log option enables output to syslog or console depending upon snort configuration \end{itemize} \texttt{debug-pkts} \begin{itemize} \item enables per packet timing stats to be printed after each packet \item default is off \end{itemize} Rule Configuration Options \texttt{max-rule-time } \begin{itemize} \item enables rule latency thresholding using 'micros-secs' as the limit. \item default is 0 (rule latency thresholding disabled) \item reasonable starting defaults: 100/250/1000 for 1G/100M/5M nets \end{itemize} \texttt{threshold } \begin{itemize} \item sets the number of cumulative rule time excesses before disabling a rule \item default is 5 \end{itemize} \texttt{suspend-expensive-rules} \begin{itemize} \item enables suspending rule inspection if the max rule time is exceeded \item default is off \end{itemize} \texttt{suspend-timeout } \begin{itemize} \item rule suspension time in seconds \item default is 60 seconds \item set to zero to permanently disable expensive rules \end{itemize} \texttt{rule-log [log] [alert]} \begin{itemize} \item enables event logging output for rules \item default is no logging \item one or both of the options 'log' and 'alert' must be used with 'rule-log' \item the log option enables output to syslog or console depending upon snort configuration \end{itemize} \subsubsection{Examples} Example 1: The following enables packet tracking: \begin{verbatim} config ppm: max-pkt-time 100 \end{verbatim} The following enables rule tracking: \begin{verbatim} config ppm: max-rule-time 50, threshold 5 \end{verbatim} If fastpath-expensive-packets or suspend-expensive-rules is not used, then no action is taken other than to increment the count of the number of packets that should be fastpath'd or the rules that should be suspended. A summary of this information is printed out when snort exits. Example 2: The following suspends rules and aborts packet inspection. These rules were used to generate the sample output that follows. \begin{verbatim} config ppm: \ max-pkt-time 50, fastpath-expensive-packets, \ pkt-log, debug-pkt config ppm: \ max-rule-time 50, threshold 5, suspend-expensive-rules, \ suspend-timeout 300, rule-log log alert \end{verbatim} \subsubsection{Sample Snort Output} Sample Snort Startup Output \begin{verbatim} Packet Performance Monitor Config: ticks per usec : 1600 ticks max packet time : 50 usecs packet action : fastpath-expensive-packets packet logging : log debug-pkts : disabled Rule Performance Monitor Config: ticks per usec : 1600 ticks max rule time : 50 usecs rule action : suspend-expensive-rules rule threshold : 5 suspend timeout : 300 secs rule logging : alert log \end{verbatim} Sample Snort Run-time Output \begin{verbatim} ... PPM: Process-BeginPkt[61] caplen=60 PPM: Pkt[61] Used= 8.15385 usecs PPM: Process-EndPkt[61] PPM: Process-BeginPkt[62] caplen=342 PPM: Pkt[62] Used= 65.3659 usecs PPM: Process-EndPkt[62] PPM: Pkt-Event Pkt[63] used=56.0438 usecs, 0 rules, 1 nc-rules tested, packet fastpathed (10.4.12.224:0 -> 10.4.14.108:54321). PPM: Process-BeginPkt[63] caplen=60 PPM: Pkt[63] Used= 8.394 usecs PPM: Process-EndPkt[63] PPM: Process-BeginPkt[64] caplen=60 PPM: Pkt[64] Used= 8.21764 usecs PPM: Process-EndPkt[64] ... \end{verbatim} Sample Snort Exit Output \begin{verbatim} Packet Performance Summary: max packet time : 50 usecs packet events : 1 avg pkt time : 0.633125 usecs Rule Performance Summary: max rule time : 50 usecs rule events : 0 avg nc-rule time : 0.2675 usecs \end{verbatim} \subsubsection{Implementation Details} \begin{itemize} \item Enforcement of packet and rule processing times is done after processing each rule. Latency control is not enforced after each preprocessor. \item This implementation is software based and does not use an interrupt driven timing mechanism and is therefore subject to the granularity of the software based timing tests. Due to the granularity of the timing measurements any individual packet may exceed the user specified packet or rule processing time limit. Therefore this implementation cannot implement a precise latency guarantee with strict timing guarantees. Hence the reason this is considered a best effort approach. \item Since this implementation depends on hardware based high performance frequency counters, latency thresholding is presently only available on Intel and PPC platforms. \item Time checks are made based on the total system time, not processor usage by Snort. This was a conscious design decision because when a system is loaded, the latency for a packet is based on the total system time, not just the processor time the Snort application receives. Therefore, it is recommended that you tune your thresholding to operate optimally when your system is under load. \end{itemize} \section{Output Modules} \label{output config} Output modules are new as of version 1.6. They allow Snort to be much more flexible in the formatting and presentation of output to its users. The output modules are run when the alert or logging subsystems of Snort are called, after the preprocessors and detection engine. The format of the directives in the config file is very similar to that of the preprocessors. Multiple output plugins may be specified in the Snort configuration file. When multiple plugins of the same type (log, alert) are specified, they are stacked and called in sequence when an event occurs. As with the standard logging and alerting systems, output plugins send their data to /var/log/snort by default or to a user directed directory (using the -l command line switch). Output modules are loaded at runtime by specifying the output keyword in the config file: \begin{verbatim} output : \end{verbatim} \begin{verbatim} output alert_syslog: log_auth log_alert \end{verbatim} \subsection{alert\_syslog} \label{alert syslog label} This module sends alerts to the syslog facility (much like the -s command line switch). This module also allows the user to specify the logging facility and priority within the Snort config file, giving users greater flexibility in logging alerts. \subsubsection{Available Keywords} \paragraph{Facilities} \begin{itemize} \item \texttt{log\_auth} \item \texttt{log\_authpriv} \item \texttt{log\_daemon} \item \texttt{log\_local0} \item \texttt{log\_local1} \item \texttt{log\_local2} \item \texttt{log\_local3} \item \texttt{log\_local4} \item \texttt{log\_local5} \item \texttt{log\_local6} \item \texttt{log\_local7} \item \texttt{log\_user} \end{itemize} \paragraph{Priorities} \begin{itemize} \item \texttt{log\_emerg} \item \texttt{log\_alert} \item \texttt{log\_crit} \item \texttt{log\_err} \item \texttt{log\_warning} \item \texttt{log\_notice} \item \texttt{log\_info} \item \texttt{log\_debug} \end{itemize} \paragraph{Options} \begin{itemize} \item \texttt{log\_cons} \item \texttt{log\_ndelay} \item \texttt{log\_perror} \item \texttt{log\_pid} \end{itemize} \subsubsection{Format} \begin{verbatim} alert_syslog: \ \end{verbatim} \begin{note} As WIN32 does not run syslog servers locally by default, a hostname and port can be passed as options. The default host is 127.0.0.1. The default port is 514. \end{note} \begin{verbatim} output alert_syslog: \ [host=],] \ \end{verbatim} \subsubsection{Example} \begin{verbatim} output alert_syslog: host=10.1.1.1:514, \end{verbatim} \subsection{alert\_fast} This will print Snort alerts in a quick one-line format to a specified output file. It is a faster alerting method than full alerts because it doesn't need to print all of the packet headers to the output file and because it logs to only 1 file. \subsubsection{Format} \begin{verbatim} output alert_fast: [ ["packet"] []] ::= [('G'|'M'|K')] \end{verbatim} \begin{itemize} \item \texttt{filename}: the name of the log file. The default name is $<$logdir$>$/alert. You may specify "stdout" for terminal output. The name may include an absolute or relative path. \item \texttt{packet}: this option will cause multiline entries with full packet headers to be logged. By default, only brief single-line entries are logged. \item \texttt{limit}: an optional limit on file size which defaults to 128 MB. The minimum is 1 KB. See \ref{Log Limits} for more information. \end{itemize} \subsubsection{Example} \begin{verbatim} output alert_fast: alert.fast \end{verbatim} \subsection{alert\_full} This will print Snort alert messages with full packet headers. The alerts will be written in the default logging directory (/var/log/snort) or in the logging directory specified at the command line. Inside the logging directory, a directory will be created per IP. These files will be decoded packet dumps of the packets that triggered the alerts. The creation of these files slows Snort down considerably. This output method is discouraged for all but the lightest traffic situations. \subsubsection{Format} \begin{verbatim} output alert_full: [ []] ::= [('G'|'M'|K')] \end{verbatim} \begin{itemize} \item \texttt{filename}: the name of the log file. The default name is $<$logdir$>$/alert. You may specify "stdout" for terminal output. The name may include an absolute or relative path. \item \texttt{limit}: an optional limit on file size which defaults to 128 MB. The minimum is 1 KB. See \ref{Log Limits} for more information. \end{itemize} \subsubsection{Example} \begin{verbatim} output alert_full: alert.full \end{verbatim} \subsection{alert\_unixsock} Sets up a UNIX domain socket and sends alert reports to it. External programs/processes can listen in on this socket and receive Snort alert and packet data in real time. \subsubsection{Format} \begin{verbatim} alert_unixsock \end{verbatim} \subsubsection{Example} \begin{verbatim} output alert_unixsock \end{verbatim} \begin{note} On FreeBSD, the default \texttt{sysctl} value for \texttt{net.local.dgram.recvspace} is too low for \texttt{alert\_unixsock} datagrams and you will likely not receive any data. You can change this value after booting by running: \begin{verbatim} $ sudo sysctl net.local.dgram.recvspace=100000 \end{verbatim} To have this value set on each boot automatically, add the following to \texttt{/etc/sysctl.conf}: \begin{verbatim} net.local.dgram.recvspace=100000 \end{verbatim} Note that the value of 100000 may be slightly generous, but the value should be at least 65864. \end{note} \subsection{log\_tcpdump} The log\_tcpdump module logs packets to a tcpdump-formatted file. This is useful for performing post-process analysis on collected traffic with the vast number of tools that are available for examining tcpdump-formatted files. \subsubsection{Format} \begin{verbatim} output log_tcpdump: [ []] ::= [('G'|'M'|K')] \end{verbatim} \begin{itemize} \item \texttt{filename}: the name of the log file. The default name is $<$logdir$>$/snort.log. The name may include an absolute or relative path. A UNIX timestamp is appended to the filename. \item \texttt{limit}: an optional limit on file size which defaults to 128 MB. When a sequence of packets is to be logged, the aggregate size is used to test the rollover condition. See \ref{Log Limits} for more information. \end{itemize} \subsubsection{Example} \begin{verbatim} output log_tcpdump: snort.log \end{verbatim} \subsection{csv} The csv output plugin allows alert data to be written in a format easily importable to a database. The output fields and their order may be customized. \subsubsection{Format} \begin{verbatim} output alert_csv: [ [ []]] ::= "default"| ::= (,)* ::= "dst"|"src"|"ttl" ... ::= [('G'|'M'|K')] \end{verbatim} \begin{itemize} \item \texttt{filename}: the name of the log file. The default name is $<$logdir$>$/alert.csv. You may specify "stdout" for terminal output. The name may include an absolute or relative path. \item \texttt{format}: The list of formatting options is below. If the formatting option is "default", the output is in the order of the formatting options listed. \begin{itemize} \item \texttt{timestamp} \item \texttt{sig\_generator} \item \texttt{sig\_id} \item \texttt{sig\_rev} \item \texttt{msg} \item \texttt{proto} \item \texttt{src} \item \texttt{srcport} \item \texttt{dst} \item \texttt{dstport} \item \texttt{ethsrc} \item \texttt{ethdst} \item \texttt{ethlen} \item \texttt{tcpflags} \item \texttt{tcpseq} \item \texttt{tcpack} \item \texttt{tcplen} \item \texttt{tcpwindow} \item \texttt{ttl} \item \texttt{tos} \item \texttt{id} \item \texttt{dgmlen} \item \texttt{iplen} \item \texttt{icmptype} \item \texttt{icmpcode} \item \texttt{icmpid} \item \texttt{icmpseq} \end{itemize} \item \texttt{limit}: an optional limit on file size which defaults to 128 MB. The minimum is 1 KB. See \ref{Log Limits} for more information. \end{itemize} \subsubsection{Example} \begin{verbatim} output alert_csv: /var/log/alert.csv default output alert_csv: /var/log/alert.csv timestamp, msg \end{verbatim} \subsection{unified 2} Unified2 can work in one of three modes, packet logging, alert logging, or true unified logging. Packet logging includes a capture of the entire packet and is specified with \texttt{log\_unified2}. Likewise, alert logging will only log events and is specified with \texttt{alert\_unified2}. To include both logging styles in a single, unified file, simply specify \texttt{unified2}. When MPLS support is turned on, MPLS labels can be included in unified2 events. Use option \texttt{mpls\_event\_types} to enable this. If option \texttt{mpls\_event\_types} is not used, then MPLS labels will be not be included in unified2 events. \begin{note} By default, unified 2 files have the file creation time (in Unix Epoch format) appended to each file when it is created. \end{note} \subsubsection{Format} \begin{verbatim} output alert_unified2: \ filename [, ] [, nostamp] [, mpls_event_types] \ [, vlan_event_types] output log_unified2: \ filename [, ] [, nostamp] output unified2: \ filename [, ] [, nostamp] [, mpls_event_types] \ [, vlan_event_types] \end{verbatim} \subsubsection{Example} \begin{verbatim} output alert_unified2: filename snort.alert, limit 128, nostamp output log_unified2: filename snort.log, limit 128, nostamp output unified2: filename merged.log, limit 128, nostamp output unified2: filename merged.log, limit 128, nostamp, mpls_event_types output unified2: filename merged.log, limit 128, nostamp, vlan_event_types \end{verbatim} \subsubsection{Extra Data Configurations} Unified2 also has logging support for various extra data. The following configuration items will enable these extra data logging facilities. \begin{verbatim} config log_ipv6_extra_data \end{verbatim} This option enables Snort to log IPv6 source and destination address as unified2 extra data events. See section \ref{Config} for more information \begin{verbatim} enable_xff \end{verbatim} This option enables HTTP Inspect to parse and log the original client IP present in the X-Forwarded-For or True-Client- IP HTTP request headers along with the generated events. See section \ref{sub:http-inspect} for more information \begin{verbatim} log_uri \end{verbatim} This option enables HTTP Inspect to parse and log the URI data from the HTTP request and log it along with all the generated events for that session. See section \ref{sub:http-inspect} for more information \begin{verbatim} log_hostname \end{verbatim} This option enables HTTP Inspect to parse and log the Host header data from the HTTP request and log it along with all the generated events for that session. See section \ref{sub:http-inspect} for more information \begin{verbatim} log_hostname \end{verbatim} This option enables HTTP Inspect to parse and log the Host header data from the HTTP request and log it along with all the generated events for that session. See section \ref{sub:http-inspect} for more information \begin{verbatim} log_mailfrom \end{verbatim} This option enables SMTP preprocessor to parse and log the senders email address extracted from the "MAIL FROM" command along with all the generated events for that session. See section \ref{SMTP} for more information \begin{verbatim} log_rcptto \end{verbatim} This option enables SMTP preprocessor to parse and log the recipients email address extracted from the "RCPT FROM" command along with all the generated events for that session. See section \ref{SMTP} for more information \begin{verbatim} log_rcptto \end{verbatim} This option enables SMTP preprocessor to parse and log the MIME attachment filenames extracted from the Content-Disposition header within the MIME body along with all the generated events for that session. See section \ref{SMTP} for more information \begin{verbatim} log_email_hdrs \end{verbatim} This option enables SMTP preprocessor to parse and log the SMTP email headers extracted from the SMTP data along with all the generated events for that session. See section \ref{SMTP} for more information \subsubsection{Reading Unified2 Files} \subsubsection{U2SpewFoo} U2SpewFoo is a lightweight tool for dumping the contents of unified2 files to stdout. \textbf Example usage: \begin{verbatim} u2spewfoo snort.log \end{verbatim} \textbf Example Output: \begin{verbatim} (Event) sensor id: 0 event id: 4 event second: 1299698138 event microsecond: 146591 sig id: 1 gen id: 1 revision: 0 classification: 0 priority: 0 ip source: 10.1.2.3 ip destination: 10.9.8.7 src port: 60710 dest port: 80 protocol: 6 impact_flag: 0 blocked: 0 Packet sensor id: 0 event id: 4 event second: 1299698138 packet second: 1299698138 packet microsecond: 146591 linktype: 1 packet_length: 54 [ 0] 02 09 08 07 06 05 02 01 02 03 04 05 08 00 45 00 ..............E. [ 16] 00 28 00 06 00 00 40 06 5C B7 0A 01 02 03 0A 09 .(....@.\....... [ 32] 08 07 ED 26 00 50 00 00 00 62 00 00 00 2D 50 10 ...&.P...b...-P. [ 48] 01 00 A2 BB 00 00 ...... (ExtraDataHdr) event type: 4 event length: 33 (ExtraData) sensor id: 0 event id: 2 event second: 1299698138 type: 9 datatype: 1 bloblength: 9 HTTP URI: / (ExtraDataHdr) event type: 4 event length: 78 (ExtraData) sensor id: 0 event id: 2 event second: 1299698138 type: 10 datatype: 1 bloblength: 12 HTTP Hostname: example.com \end{verbatim} \subsubsection{U2Boat} U2boat is a tool for converting unified2 files into different formats. Currently supported conversion formats are: pcap \textbf Example usage: \begin{verbatim} u2boat -t pcap \end{verbatim} \subsection{log null} Sometimes it is useful to be able to create rules that will alert to certain types of traffic but will not cause packet log entries. In Snort 1.8.2, the log\_null plugin was introduced. This is equivalent to using the -n command line option but it is able to work within a ruletype. \subsubsection{Format} \begin{verbatim} output log_null \end{verbatim} \subsubsection{Example} \begin{verbatim} output log_null # like using snort -n ruletype info { type alert output alert_fast: info.alert output log_null } \end{verbatim} \subsection{Log Limits} \label{Log Limits} This section pertains to logs produced by \texttt{alert\_fast}, \texttt{alert\_full}, \texttt{alert\_csv}, and \texttt{log\_tcpdump}. \texttt{unified2} also may be given limits. Those limits are described in the respective sections. When a configured limit is reached, the current log is closed and a new log is opened with a UNIX timestamp appended to the configured log name. Limits are configured as follows: \begin{verbatim} ::= [(||)] ::= 'G'|'g' ::= 'M'|'m' ::= 'K'|'k' \end{verbatim} Rollover will occur at most once per second so if limit is too small for logging rate, limit will be exceeded. Rollover works correctly if snort is stopped/restarted. \section{Host Attribute Table} \label{targetbased} Starting with version 2.8.1, Snort has the capability to use information from an outside source to determine both the protocol for use with Snort rules, and IP-Frag policy (see section \ref{frag3 section}) and TCP Stream reassembly policies (see section \ref{stream5 section}). This information is stored in an attribute table, which is loaded at startup. The table is re-read during run time upon receipt of signal number 30. Snort associates a given packet with its attribute data from the table, if applicable. For rule evaluation, service information is used instead of the ports when the protocol metadata in the rule matches the service corresponding to the traffic. If the rule doesn't have protocol metadata, or the traffic doesn't have any matching service information, the rule relies on the port information. \begin{note} To use a host attribute table, Snort must be configured with the --enable-targetbased flag. \end{note} \subsection{Configuration Format} \begin{verbatim} attribute_table filename \end{verbatim} \subsection{Attribute Table File Format} The attribute table uses an XML format and consists of two sections, a mapping section, used to reduce the size of the file for common data elements, and the host attribute section. The mapping section is optional. An example of the file format is shown below. \begin{verbatim} 1 Linux 2 ssh 192.168.1.234 1 100 Red Hat 99 2.6 98 linux linux 22 100 tcp 100 2 100 OpenSSH 100 3.9p1 93 2300 100 tcp 100 telnet 100 telnet 50 tcp 100 http 91 IE Http Browser 90 6.0 89 \end{verbatim} \begin{note} With Snort 2.8.1, for a given host entry, the stream and IP frag information are both used. Of the service attributes, only the IP protocol (tcp, udp, etc), port, and protocol (http, ssh, etc) are used. The application and version for a given service attribute, and any client attributes are ignored. They may be used in a future release. \end{note} A DTD for verification of the Host Attribute Table XML file is provided with the snort packages. The confidence metric may be used to indicate the validity of a given service or client application and its respective elements. That field is not currently used by Snort, but may be in future releases. \subsection{Attribute Table Example} In the example above, a host running Red Hat 2.6 is described. This host has an IP address of 192.168.1.234. On that host, TCP port 22 is ssh (running Open SSH), and TCP port 2300 is telnet. The IP stack fragmentation and stream reassembly is mimicked by the "linux" configuration (see sections \ref{frag3 section} and \ref{stream5 section}). \subsubsection{Attribute Table Affect on preprocessors} \begin{itemize} \item{Network Layer Preprocessors} Each of the network layer preprocessors (frag3 and stream5) make use of the respective \texttt{FRAG\_POLICY} and \texttt{STREAM\_POLICY} in terms of how data is handled for reassembly for packets being received by that host. \item{Application Layer Preprocessors} The application layer preprocessors (HTTP, SMTP, FTP, Telnet, etc) make use of the \texttt{SERVICE} information for connections destined to that host on that port. For example, even if the telnet portion of the FTP/Telnet preprocessor is only configured to inspect port 23, Snort will inspect packets for a connection to 192.168.1.234 port 2300 as telnet. Conversely, if, for example, HTTP Inspect is configured to inspect traffic on port 2300, HTTP Inspect will NOT process the packets on a connection to 192.168.1.234 port 2300 because it is identified as telnet. Below is a list of the common services used by Snort's application layer preprocessors and Snort rules (see below). \begin{table}[h] \label{attribute:service names} \begin{center} \begin{tabular}{| l | l | l | l | l | l | l |} \hline http & ftp & ftp-data & telnet & smtp & ssh & tftp \\ \hline dcerpc & netbios-dgm & netbios-ns & netbios-ssn & nntp & finger & sunrpc \\ \hline dns & isakmp & mysql & oracle & cvs & shell & x11 \\ \hline imap & pop2 & pop3 & snmp & & & \\ \hline \end{tabular} \end{center} \end{table} \end{itemize} \subsubsection{Attribute Table Affect on rules} Similar to the application layer preprocessors, rules configured for specific ports that have a service metadata will be processed based on the service identified by the attribute table. When both service metadata is present in the rule and in the connection, Snort uses the service rather than the port. If there are rules that use the service and other rules that do not but the port matches, Snort will ONLY inspect the rules that have the service that matches the connection. The following few scenarios identify whether a rule will be inspected or not. \begin{itemize} \item{Alert: Rule Has Service Metadata, Connection Service Matches} The following rule will be inspected and alert on traffic to host 192.168.1.234 port 2300 because it is identified as telnet. \begin{verbatim} alert tcp any any -> any 23 (msg:"Telnet traffic"; flow:to_server,established; sid:10000001; metadata: service telnet;) \end{verbatim} \item{Alert: Rule Has Multiple Service Metadata, Connection Service Matches One of them} The following rule will be inspected and alert on traffic to host 192.168.1.234 port 2300 because it is identified as telnet. \begin{verbatim} alert tcp any any -> any 23 (msg:"Telnet traffic"; flow:to_server,established; sid:10000002; metadata: service telnet, service smtp;) \end{verbatim} \item{No Alert: Rule Has Service Metadata, Connection Service Does Not Match, Port Matches} The following rule will NOT be inspected and NOT alert on traffic to host 192.168.1.234 port 2300 because that traffic is identified as telnet, but the service is ssh. \begin{verbatim} alert tcp any any -> any 2300 (msg:"SSH traffic"; flow:to_server,established; sid:10000003; metadata: service ssh;) \end{verbatim} \item{Alert: Rule Has No Service Metadata, Port Matches} The following rule will be inspected and alert on traffic to host 192.168.1.234 port 2300 because the port matches. \begin{verbatim} alert tcp any any -> any 2300 (msg:"Port 2300 traffic"; flow:to_server,established; sid:10000004;) \end{verbatim} \item{Alert: Rule Has No Service Metadata, Packet has service + other rules with service} The first rule will NOT be inspected and NOT alert on traffic to host 192.168.1.234 port 2300 because the service is identified as telnet and there are other rules with that service. \begin{verbatim} alert tcp any any -> any 2300 (msg:"Port 2300 traffic"; flow:to_server,established; sid:10000005;) alert tcp any any -> any 2300 (msg:"Port 2300 traffic"; flow:to_server,established; sid:10000006; metadata: service telnet;) \end{verbatim} \item{No Alert: Rule Has No Service Metadata, Port Does Not Match} The following rule will NOT be inspected and NOT alert on traffic to host 192.168.1.234 port 2300 because the port does not match. \begin{verbatim} alert tcp any any -> any 23 (msg:"Port 23 traffic"; flow:to_server,established; sid:10000007;) \end{verbatim} \end{itemize} \section{Dynamic Modules} Dynamically loadable modules were introduced with Snort 2.6. They can be loaded via directives in \texttt{snort.conf} or via command-line options. \subsection{Format} \begin{verbatim} \end{verbatim} \subsection{Directives} \begin{longtable}{| p{2in} | p{4in} |} \hline {\bf Syntax} & {\bf Description}\\ \hline \hline \texttt{dynamicpreprocessor $[$ file $<$shared library path$>$ $|$ directory $<$directory of shared libraries$>$ $]$} & Tells snort to load the dynamic preprocessor shared library (if file is used) or all dynamic preprocessor shared libraries (if directory is used). Specify \texttt{file}, followed by the full or relative path to the shared library. Or, specify \texttt{directory}, followed by the full or relative path to a directory of preprocessor shared libraries. (Same effect as \texttt{--dynamic-preprocessor-lib} or \texttt{--dynamic-preprocessor-lib-dir} options). See chapter \ref{Dynamic Modules} for more information on dynamic preprocessor libraries.\\ \hline \texttt{dynamicengine $[$ file $<$shared library path$>$ $|$ directory $<$directory of shared libraries$>$ $]$} & Tells snort to load the dynamic engine shared library (if file is used) or all dynamic engine shared libraries (if directory is used). Specify \texttt{file}, followed by the full or relative path to the shared library. Or, specify \texttt{directory}, followed by the full or relative path to a directory of preprocessor shared libraries. (Same effect as \texttt{--dynamic-engine-lib} or \texttt{--dynamic-preprocessor-lib-dir} options). See chapter \ref{Dynamic Modules} for more information on dynamic engine libraries.\\ \hline \texttt{dynamicdetection $[$ file $<$shared library path$>$ $|$ directory $<$directory of shared libraries$>$ $]$} & Tells snort to load the dynamic detection rules shared library (if file is used) or all dynamic detection rules shared libraries (if directory is used). Specify \texttt{file}, followed by the full or relative path to the shared library. Or, specify \texttt{directory}, followed by the full or relative path to a directory of detection rules shared libraries. (Same effect as \texttt{--dynamic-detection-lib} or \texttt{--dynamic-detection-lib-dir} options). See chapter \ref{Dynamic Modules} for more information on dynamic detection rules libraries.\\ \hline \end{longtable} \section{Reloading a Snort Configuration} Snort now supports reloading a configuration in lieu of restarting Snort in so as to provide seamless traffic inspection during a configuration change. A separate thread will parse and create a swappable configuration object while the main Snort packet processing thread continues inspecting traffic under the current configuration. When a swappable configuration object is ready for use, the main Snort packet processing thread will swap in the new configuration to use and will continue processing under the new configuration. Note that for some preprocessors, existing session data will continue to use the configuration under which they were created in order to continue with proper state for that session. All newly created sessions will, however, use the new configuration. \subsection{Enabling support} \label{reload:enable} To enable support for reloading a configuration, add \texttt{--enable-reload} to configure when compiling. There is also an ancillary option that determines how Snort should behave if any non-reloadable options are changed (see section \ref{reload:nonreloadable} below). This option is enabled by default and the behavior is for Snort to restart if any non-reloadable options are added/modified/removed. To disable this behavior and have Snort exit instead of restart, add \texttt{--disable-reload-error-restart} in addition to \texttt{--enable-reload} to configure when compiling. \begin{note} This functionality is not currently supported in Windows. Caveat : When Snort is run on the primary network interface of an OpenBSD system, the reload and failopen operations may not function as expected. \end{note} \subsection{Reloading a configuration} \label{reload:reload} First modify your snort.conf (the file passed to the \texttt{-c} option on the command line). Then, to initiate a reload, send Snort a \texttt{SIGHUP} signal, e.g. \begin{verbatim} $ kill -SIGHUP \end{verbatim} \begin{note} If reload support is not enabled, Snort will restart (as it always has) upon receipt of a SIGHUP. \end{note} \begin{note} An invalid configuration will still result in a fatal error, so you should test your new configuration before issuing a reload, e.g. \texttt{\$ snort -c snort.conf -T} \end{note} \subsection{Non-reloadable configuration options} \label{reload:nonreloadable} There are a number of option changes that are currently non-reloadable because they require changes to output, startup memory allocations, etc. Modifying any of these options will cause Snort to restart (as a \texttt{SIGHUP} previously did) or exit (if \texttt{--disable-reload-error-restart} was used to configure Snort). Reloadable configuration options of note: \begin{itemize} \item Adding/modifying/removing text rules and variables are reloadable. \item Adding/modifying/removing preprocessor configurations are reloadable (except as noted below). \end{itemize} Non-reloadable configuration options of note: \begin{itemize} \item Adding/modifying/removing shared objects via dynamicdetection, dynamicengine and dynamicpreprocessor are not reloadable, i.e. any new/modified/removed shared objects will require a restart. \item Any changes to output will require a restart. \end{itemize} Changes to the following options are not reloadable: \begin{verbatim} attribute_table config alertfile config asn1 config chroot config daemon config detection_filter config flowbits_size config interface config logdir config max_attribute_hosts config max_attribute_services_per_host config nolog config no_promisc config pkt_count config rate_filter config response config set_gid config set_uid config snaplen config threshold dynamicdetection dynamicengine dynamicpreprocessor output \end{verbatim} In certain cases, only some of the parameters to a config option or preprocessor configuration are not reloadable. Those parameters are listed below the relevant config option or preprocessor. \begin{verbatim} config ppm: max-rule-time rule-log config profile_rules filename print sort config profile_preprocs filename print sort preprocessor dcerpc2 memcap preprocessor frag3_global max_frags memcap prealloc_frags prealloc_memcap disabled preprocessor perfmonitor file snortfile preprocessor sfportscan memcap logfile disabled preprocessor stream5_global memcap max_tcp max_udp max_icmp track_tcp track_udp track_icmp \end{verbatim} \section{Multiple Configurations} Snort now supports multiple configurations based on VLAN Id or IP subnet within a single instance of Snort. This will allow administrators to specify multiple snort configuration files and bind each configuration to one or more VLANs or subnets rather than running one Snort for each configuration required. Each unique snort configuration file will create a new configuration instance within snort. VLANs/Subnets not bound to any specific configuration will use the default configuration. Each configuration can have different preprocessor settings and detection rules. \subsection{Creating Multiple Configurations} Default configuration for snort is specified using the existing -c option. A default configuration binds multiple vlans or networks to non-default configurations, using the following configuration line: \begin{verbatim} config binding: vlan config binding: net \end{verbatim} \begin{description}{} \item [\texttt{path\_to\_snort.conf}] - Refers to the absolute or relative path to the snort.conf for specific configuration. \item [\texttt{vlanIdList}] - Refers to the comma separated list of vlandIds and vlanId ranges. The format for ranges is two vlanId separated by a "-". Spaces are allowed within ranges. Valid vlanId is any number in 0-4095 range. Negative vland Ids and alphanumeric are not supported. \item [\texttt{ipList}] - Refers to ip subnets. Subnets can be CIDR blocks for IPV6 or IPv4. A maximum of 512 individual IPv4 or IPv6 addresses or CIDRs can be specified. \end{description} \begin{note} Vlan and Subnets can not be used in the same line. Configurations can be applied based on either Vlans or Subnets not both. \end{note} \begin{note} Even though Vlan Ids 0 and 4095 are reserved, they are included as valid in terms of configuring Snort. \end{note} \subsection{Configuration Specific Elements} \subsubsection{Config Options} Generally config options defined within the default configuration are global by default i.e. their value applies to all other configurations. The following config options are specific to each configuration. \begin{verbatim} policy_id policy_mode policy_version \end{verbatim} The following config options are specific to each configuration. If not defined in a configuration, the default values of the option (not the default configuration values) take effect. \begin{verbatim} config checksum_drop config disable_decode_alerts config disable_decode_drops config disable_ipopt_alerts config disable_ipopt_drops config disable_tcpopt_alerts config disable_tcpopt_drops config disable_tcpopt_experimental_alerts config disable_tcpopt_experimental_drops config disable_tcpopt_obsolete_alerts config disable_tcpopt_obsolete_drops config disable_ttcp_alerts config disable_tcpopt_ttcp_alerts config disable_ttcp_drops \end{verbatim} \subsubsection{Rules} Rules are specific to configurations but only some parts of a rule can be customized for performance reasons. If a rule is not specified in a configuration then the rule will never raise an event for the configuration. A rule shares all parts of the rule options, including the general options, payload detection options, non-payload detection options, and post-detection options. Parts of the rule header can be specified differently across configurations, limited to: \begin{verbatim} Source IP address and port Destination IP address and port Action \end{verbatim} A higher revision of a rule in one configuration will override other revisions of the same rule in other configurations. \subsubsection{Variables} Variables defined using "var", "portvar" and "ipvar" are specific to configurations. If the rules in a configuration use variables, those variables must be defined in that configuration. \subsubsection{Preprocessors} Preprocessors configurations can be defined within each vlan or subnet specific configuration. Options controlling specific preprocessor memory usage, through specific limit on memory usage or number of instances, are processed only in default policy. The options control total memory usage for a preprocessor across all policies. These options are ignored in non-default policies without raising an error. A preprocessor must be configured in default configuration before it can be configured in non-default configuration. This is required as some mandatory preprocessor configuration options are processed only in default configuration. \subsubsection{Events and Output} An unique policy id can be assigned by user, to each configuration using the following config line: \begin{verbatim} config policy_id: \end{verbatim} \begin{description}{} \item [\texttt{id}] - Refers to a 16-bit unsigned value. This policy id will be used to identify alerts from a specific configuration in the unified2 records. \end{description} \begin{note} If no policy id is specified, snort assigns 0 (zero) value to the configuration. \end{note} To enable vlanId logging in unified2 records the following option can be used. \begin{verbatim} output alert_unified2: vlan_event_types (alert logging only) output unified2: filename , vlan_event_types (true unified logging) \end{verbatim} \begin{description}{} \item [\texttt{filename}] - Refers to the absolute or relative filename. \item [\texttt{vlan\_event\_types}] - When this option is set, snort will use unified2 event type 104 and 105 for IPv4 and IPv6 respectively. \end{description} \begin{note} Each event logged will have the vlanId from the packet if vlan headers are present otherwise 0 will be used. \end{note} \subsection{How Configuration is applied?} Snort assigns every incoming packet to a unique configuration based on the following criteria. If VLANID is present, then the innermost VLANID is used to find bound configuration. If the bound configuration is the default configuration, then destination IP address is searched to the most specific subnet that is bound to a non-default configuration. The packet is assigned non-default configuration if found otherwise the check is repeated using source IP address. In the end, default configuration is used if no other matching configuration is found. For addressed based configuration binding, this can lead to conflicts between configurations if source address is bound to one configuration and destination address is bound to another. In this case, snort will use the first configuration in the order of definition, that can be applied to the packet. \section{Active Response} Snort 2.9 includes a number of changes to better handle inline operation, including: \begin{itemize} \item a single mechanism for all responses \item fully encoded reset or icmp unreachable packets \item updated flexible response rule option \item updated react rule option \item added block and sblock rule actions \end{itemize} These changes are outlined below. \subsection{Enabling Active Response} This enables active responses (snort will send TCP RST or ICMP unreachable/port) when dropping a session. \begin{verbatim} ./configure --enable-active-response / -DACTIVE_RESPONSE preprocessor stream5_global: \ max_active_responses , \ min_response_seconds ::= (0..25) ::= (1..300) \end{verbatim} Active responses will be encoded based on the triggering packet. TTL will be set to the value captured at session pickup. \subsection{Configure Sniping} Configure the number of attempts to land a TCP RST within the session's current window (so that it is accepted by the receiving TCP). This sequence "strafing" is really only useful in passive mode. In inline mode the reset is put straight into the stream in lieu of the triggering packet so strafing is not necessary. Each attempt (sent in rapid succession) has a different sequence number. Each active response will actually cause this number of TCP resets to be sent. TCP data (sent for react) is multiplied similarly. At most 1 ICMP unreachable is sent, if and only if attempts $>$ 0. \begin{verbatim} ./configure --enable-active-response config response: [device ] [dst_mac ] attempts ::= ip | eth0 | etc. ::= (1..20) ::= nn:nn:nn:nn:nn:nn (n is a hex number from 0-F) \end{verbatim} device ip will perform network layer injection. It is probably a better choice to specify an interface and avoid kernel routing tables, etc. dst\_mac will change response destination MAC address, if the device is eth0, eth1, eth2 etc. Otherwise, response destination MAC address is derived from packet. Example: \begin{verbatim} config response: device eth0 dst_mac 00:06:76:DD:5F:E3 attempts 2 \end{verbatim} \subsection{Flexresp} \label{resp section} Flexresp and flexresp2 are replaced with flexresp3. * Flexresp is deleted; these features are no longer available: \begin{verbatim} ./configure --enable-flexresp / -DENABLE_RESPOND -DENABLE_RESPONSE config flexresp: attempts 1 \end{verbatim} * Flexresp2 is deleted; these features are deprecated, non-functional, and will be deleted in a future release: \begin{verbatim} ./configure --enable-flexresp2 / -DENABLE_RESPOND -DENABLE_RESPONSE2 config flexresp2_interface: eth0 config flexresp2_attempts: 4 config flexresp2_memcap: 1000000 config flexresp2_rows: 1000 \end{verbatim} * Flexresp3 is new: the resp rule option keyword is used to configure active responses for rules that fire. \begin{verbatim} ./configure --enable-flexresp3 / -DENABLE_RESPOND -DENABLE_RESPONSE3 alert tcp any any -> any 80 (content:"a"; resp:; sid:1;) \end{verbatim} * \texttt{resp\_t} includes all flexresp and flexresp2 options: \begin{verbatim} ::= \ rst_snd | rst_rcv | rst_all | \ reset_source | reset_dest | reset_both | icmp_net | \ icmp_host | icmp_port | icmp_all \end{verbatim} \subsection{React} \label{react section} react is a rule option keyword that enables sending an HTML page on a session and then resetting it. This is built with: \begin{verbatim} ./configure --enable-react / -DENABLE_REACT \end{verbatim} The page to be sent can be read from a file: \begin{verbatim} config react: \end{verbatim} or else the default is used: \begin{verbatim} ::= \ "HTTP/1.1 403 Forbidden\r\n" "Connection: close\r\n" "Content-Type: text/html; charset=utf-8\r\n" "\r\n" "\r\n" \ "\r\n" \ "\r\n" \ "\r\n" \ "Access Denied\r\n" \ "\r\n" \ "\r\n" \ "

Access Denied

\r\n" \ "

%s

\r\n" \ "\r\n" \ "\r\n"; \end{verbatim} Note that the file must contain the entire response, including any HTTP headers. In fact, the response isn't strictly limited to HTTP. You could craft a binary payload of arbitrary content. When the rule is configured, the page is loaded and the %s is replaced with the selected message, which defaults to: \begin{verbatim} ::= \ "You are attempting to access a forbidden site.
" \ "Consult your system administrator for details."; \end{verbatim} Additional formatting operators beyond a single %s are prohibited, including %d, %x, %s, as well as any URL encodings such as as %20 (space) that may be within a reference URL. This is an example rule: \begin{verbatim} drop tcp any any -> any $HTTP_PORTS ( \ content: "d"; msg:"Unauthorized Access Prohibited!"; \ react: ; sid:4;) ::= [msg] [, ] \end{verbatim} These options are deprecated: \begin{verbatim} ::= [block|warn], [proxy ] \end{verbatim} The original version sent the web page to one end of the session only if the other end of the session was port 80 or the optional proxy port. The new version always sends the page to the client. If no page should be sent, a resp option can be used instead. The deprecated options are ignored. \subsection{Rule Actions} The block and sblock actions have been introduced as synonyms for drop and sdrop to help avoid confusion between packets dropped due to load (e.g. lack of available buffers for incoming packets) and packets blocked due to Snort's analysis. \chapter{Writing Snort Rules} \label{Writing Snort Rules} \section{The Basics} Snort uses a simple, lightweight rules description language that is flexible and quite powerful. There are a number of simple guidelines to remember when developing Snort rules that will help safeguard your sanity. Most Snort rules are written in a single line. This was required in versions prior to 1.8. In current versions of Snort, rules may span multiple lines by adding a backslash \textbackslash{} to the end of the line. Snort rules are divided into two logical sections, the rule header and the rule options. The rule header contains the rule's action, protocol, source and destination IP addresses and netmasks, and the source and destination ports information. The rule option section contains alert messages and information on which parts of the packet should be inspected to determine if the rule action should be taken. Figure \ref{Sample Snort Rule} illustrates a sample Snort rule. \begin{center} \begin{figure} \begin{verbatim} alert tcp any any -> 192.168.1.0/24 111 \ (content:"|00 01 86 a5|"; msg:"mountd access";) \end{verbatim} \caption{Sample Snort Rule} \label{Sample Snort Rule} \end{figure} \end{center} The text up to the first parenthesis is the rule header and the section enclosed in parenthesis contains the rule options. The words before the colons in the rule options section are called option \emph{keywords}. \begin{note} Note that the rule options section is not specifically required by any rule, they are just used for the sake of making tighter definitions of packets to collect or alert on (or drop, for that matter). \end{note} All of the elements in that make up a rule must be true for the indicated rule action to be taken. When taken together, the elements can be considered to form a logical \textsc{and} statement. At the same time, the various rules in a Snort rules library file can be considered to form a large logical \textsc{or} statement. \section{Rules Headers} \subsection{Rule Actions} \label{rules action section} The rule header contains the information that defines the who, where, and what of a packet, as well as what to do in the event that a packet with all the attributes indicated in the rule should show up. The first item in a rule is the rule action. The rule action tells Snort what to do when it finds a packet that matches the rule criteria. There are 5 available default actions in Snort, alert, log, pass, activate, and dynamic. In addition, if you are running Snort in inline mode, you have additional options which include drop, reject, and sdrop. \begin{enumerate} \item alert - generate an alert using the selected alert method, and then log the packet \item log - log the packet \item pass - ignore the packet \item activate - alert and then turn on another dynamic rule \item dynamic - remain idle until activated by an activate rule , then act as a log rule \item drop - block and log the packet \item reject - block the packet, log it, and then send a TCP reset if the protocol is TCP or an ICMP port unreachable message if the protocol is UDP. \item sdrop - block the packet but do not log it. \end{enumerate} You can also define your own rule types and associate one or more output plugins with them. You can then use the rule types as actions in Snort rules. This example will create a type that will log to just tcpdump: \begin{verbatim} ruletype suspicious { type log output log_tcpdump: suspicious.log } \end{verbatim} This example will create a rule type that will log to syslog and tcpdump: database: \begin{verbatim} ruletype redalert { type alert output alert_syslog: LOG_AUTH LOG_ALERT output log_tcpdump: suspicious.log } \end{verbatim} \subsection{Protocols} The next field in a rule is the protocol. There are four protocols that Snort currently analyzes for suspicious behavior -- TCP, UDP, ICMP, and IP. In the future there may be more, such as ARP, IGRP, GRE, OSPF, RIP, IPX, etc. \subsection{IP Addresses} The next portion of the rule header deals with the IP address and port information for a given rule. The keyword any may be used to define any address. Snort does not have a mechanism to provide host name lookup for the IP address fields in the config file. The addresses are formed by a straight numeric IP address and a CIDR\cite{cidrnotation} block. The CIDR block indicates the netmask that should be applied to the rule's address and any incoming packets that are tested against the rule. A CIDR block mask of /24 indicates a Class C network, /16 a Class B network, and /32 indicates a specific machine address. For example, the address/CIDR combination 192.168.1.0/24 would signify the block of addresses from 192.168.1.1 to 192.168.1.255. Any rule that used this designation for, say, the destination address would match on any address in that range. The CIDR designations give us a nice short-hand way to designate large address spaces with just a few characters. In Figure \ref{Sample Snort Rule}, the source IP address was set to match for any computer talking, and the destination address was set to match on the 192.168.1.0 Class C network. There is an operator that can be applied to IP addresses, the negation operator. This operator tells Snort to match any IP address except the one indicated by the listed IP address. The negation operator is indicated with a !. For example, an easy modification to the initial example is to make it alert on any traffic that originates outside of the local net with the negation operator as shown in Figure \ref{Example Negation}. \begin{center} \begin{figure} \begin{verbatim} alert tcp !192.168.1.0/24 any -> 192.168.1.0/24 111 \ (content:"|00 01 86 a5|"; msg:"external mountd access";) \end{verbatim} \caption{\label{Example Negation} Example IP Address Negation Rule} \end{figure} \end{center} This rule's IP addresses indicate any tcp packet with a source IP address not originating from the internal network and a destination address on the internal network. You may also specify lists of IP addresses. An IP list is specified by enclosing a comma separated list of IP addresses and CIDR blocks within square brackets. For the time being, the IP list may not include spaces between the addresses. See Figure \ref{IP list usage} for an example of an IP list in action. \begin{center} \begin{figure} \begin{verbatim} alert tcp ![192.168.1.0/24,10.1.1.0/24] any -> \ [192.168.1.0/24,10.1.1.0/24] 111 (content:"|00 01 86 a5|"; \ msg:"external mountd access";) \end{verbatim} \caption{\label{IP list usage}IP Address Lists} \end{figure} \end{center} \subsection{Port Numbers} Port numbers may be specified in a number of ways, including any ports, static port definitions, ranges, and by negation. Any ports are a wildcard value, meaning literally any port. Static ports are indicated by a single port number, such as 111 for portmapper, 23 for telnet, or 80 for http, etc. Port ranges are indicated with the range operator :. The range operator may be applied in a number of ways to take on different meanings, such as in Figure \ref{port range examples}. \begin{center} \begin{figure} \begin{verbatim} log udp any any -> 192.168.1.0/24 1:1024 \end{verbatim} log udp traffic coming from any port and destination ports ranging from 1 to 1024 \begin{verbatim} log tcp any any -> 192.168.1.0/24 :6000 \end{verbatim} log tcp traffic from any port going to ports less than or equal to 6000 \begin{verbatim} log tcp any :1024 -> 192.168.1.0/24 500: \end{verbatim} log tcp traffic from privileged ports less than or equal to 1024 going to ports greater than or equal to 500 \caption{\label{port range examples}Port Range Examples} \end{figure} \end{center} Port negation is indicated by using the negation operator !. The negation operator may be applied against any of the other rule types (except any, which would translate to none, how Zen...). For example, if for some twisted reason you wanted to log everything except the X Windows ports, you could do something like the rule in Figure \ref{example port negation}. \begin{figure} \begin{verbatim} log tcp any any -> 192.168.1.0/24 !6000:6010 \end{verbatim} \caption{\label{example port negation}Example of Port Negation} \end{figure} \subsection{The Direction Operator} The direction operator -$>$ indicates the orientation, or direction, of the traffic that the rule applies to. The IP address and port numbers on the left side of the direction operator is considered to be the traffic coming from the source host, and the address and port information on the right side of the operator is the destination host. There is also a bidirectional operator, which is indicated with a $<>$ symbol. This tells Snort to consider the address/port pairs in either the source or destination orientation. This is handy for recording/analyzing both sides of a conversation, such as telnet or POP3 sessions. An example of the bidirectional operator being used to record both sides of a telnet session is shown in Figure \ref{bidirectional operator}. Also, note that there is no $<$- operator. In Snort versions before 1.8.7, the direction operator did not have proper error checking and many people used an invalid token. The reason the $<$- does not exist is so that rules always read consistently. \begin{figure} \begin{verbatim} log tcp !192.168.1.0/24 any <> 192.168.1.0/24 23 \end{verbatim} \caption{\label{bidirectional operator}Snort rules using the Bidirectional Operator} \end{figure} \subsection{Activate/Dynamic Rules} \label{dynamic rules} \begin{note} Activate and Dynamic rules are being phased out in favor of a combination of tagging (\ref{tag section}) and flowbits (\ref{flowbits}). \end{note} Activate/dynamic rule pairs give Snort a powerful capability. You can now have one rule activate another when its action is performed for a set number of packets. This is very useful if you want to set Snort up to perform follow on recording when a specific rule goes off. Activate rules act just like alert rules, except they have a {*}required{*} option field: activates. Dynamic rules act just like log rules, but they have a different option field: activated\_by. Dynamic rules have a second required field as well, count. Activate rules are just like alerts but also tell Snort to add a rule when a specific network event occurs. Dynamic rules are just like log rules except are dynamically enabled when the activate rule id goes off. Put 'em together and they look like Figure \ref{activate/dynamic rule example}. \begin{figure} \begin{verbatim} activate tcp !$HOME_NET any -> $HOME_NET 143 (flags:PA; \ content:"|E8C0FFFFFF|/bin"; activates:1; \ msg:"IMAP buffer overflow!";) dynamic tcp !$HOME_NET any -> $HOME_NET 143 (activated_by:1; count:50;) \end{verbatim} \caption{Activate/Dynamic Rule Example} \label{activate/dynamic rule example} \end{figure} These rules tell Snort to alert when it detects an IMAP buffer overflow and collect the next 50 packets headed for port 143 coming from outside \$HOME\_NET headed to \$HOME\_NET. If the buffer overflow happened and was successful, there's a very good possibility that useful data will be contained within the next 50 (or whatever) packets going to that same service port on the network, so there's value in collecting those packets for later analysis. \section{Rule Options} Rule options form the heart of Snort's intrusion detection engine, combining ease of use with power and flexibility. All Snort rule options are separated from each other using the semicolon (;) character. Rule option keywords are separated from their arguments with a colon (:) character. There are four major categories of rule options. \begin{description} \item [general] These options provide information about the rule but do not have any affect during detection \item [payload] These options all look for data inside the packet payload and can be inter-related \item [non-payload] These options look for non-payload data \item [post-detection] These options are rule specific triggers that happen after a rule has ``fired.'' \end{description} \section{General Rule Options} \subsection{msg} The msg rule option tells the logging and alerting engine the message to print along with a packet dump or to an alert. It is a simple text string that utilizes the \textbackslash{} as an escape character to indicate a discrete character that might otherwise confuse Snort's rules parser (such as the semi-colon ; character). \subsubsection{Format} \begin{verbatim} msg:""; \end{verbatim} \subsection{reference} The reference keyword allows rules to include references to external attack identification systems. The plugin currently supports several specific systems as well as unique URLs. This plugin is to be used by output plugins to provide a link to additional information about the alert produced. Make sure to also take a look at \url{http://www.snort.org/pub-bin/sigs-search.cgi/} for a system that is indexing descriptions of alerts based on of the sid (See Section \ref{keyword sid}). \begin{table}[h] \begin{center} \caption{Supported Systems} \label{references systems} \begin{tabular}{|c|c|} \hline System& URL Prefix\\ \hline \hline bugtraq& http://www.securityfocus.com/bid/\\ \hline cve& http://cve.mitre.org/cgi-bin/cvename.cgi?name=\\ \hline nessus & http://cgi.nessus.org/plugins/dump.php3?id=\\ \hline arachnids& (currently down) http://www.whitehats.com/info/IDS\\ \hline mcafee& http://vil.nai.com/vil/content/v\_\\ \hline osvdb& http://osvdb.org/show/osvdb/\\ \hline msb& http://technet.microsoft.com/en-us/security/bulletin/\\ \hline url& http://\\ \hline \end{tabular} \end{center} \end{table} \subsubsection{Format} \begin{verbatim} reference:, ; [reference:, ;] \end{verbatim} \subsubsection{Examples} \begin{verbatim} alert tcp any any -> any 7070 (msg:"IDS411/dos-realaudio"; \ flags:AP; content:"|fff4 fffd 06|"; reference:arachnids,IDS411;) alert tcp any any -> any 21 (msg:"IDS287/ftp-wuftp260-venglin-linux"; \ flags:AP; content:"|31c031db 31c9b046 cd80 31c031db|"; \ reference:arachnids,IDS287; reference:bugtraq,1387; \ reference:cve,CAN-2000-1574;) \end{verbatim} \subsection{gid} \label{keyword gid} The \texttt{gid} keyword (generator id) is used to identify what part of Snort generates the event when a particular rule fires. For example gid 1 is associated with the rules subsystem and various gids over 100 are designated for specific preprocessors and the decoder. See etc/generators in the source tree for the current generator ids in use. Note that the gid keyword is optional and if it is not specified in a rule, it will default to 1 and the rule will be part of the general rule subsystem. To avoid potential conflict with gids defined in Snort (that for some reason aren't noted it etc/generators), it is recommended that values starting at 1,000,000 be used. For general rule writing, it is not recommended that the \texttt{gid} keyword be used. This option should be used with the \texttt{sid} keyword. (See section \ref{keyword sid}) The file etc/gen-msg.map contains contains more information on preprocessor and decoder gids. \subsubsection{Format} \begin{verbatim} gid:; \end{verbatim} \subsubsection{Example} This example is a rule with a generator id of 1000001. \begin{verbatim} alert tcp any any -> any 80 (content:"BOB"; gid:1000001; sid:1; rev:1;) \end{verbatim} \subsection{sid} \label{keyword sid} The \texttt{sid} keyword is used to uniquely identify Snort rules. This information allows output plugins to identify rules easily. This option should be used with the \texttt{rev} keyword. (See section \ref{keyword rev}) \begin{itemize} \item $<$100 Reserved for future use \item 100-999,999 Rules included with the Snort distribution \item $>=$1,000,000 Used for local rules \end{itemize} The file sid-msg.map contains a mapping of alert messages to Snort rule IDs. This information is useful when post-processing alert to map an ID to an alert message. \subsubsection{Format} \begin{verbatim} sid:; \end{verbatim} \subsubsection{Example} This example is a rule with the Snort Rule ID of 1000983. \begin{verbatim} alert tcp any any -> any 80 (content:"BOB"; sid:1000983; rev:1;) \end{verbatim} \subsection{rev} \label{keyword rev} The \texttt{rev} keyword is used to uniquely identify revisions of Snort rules. Revisions, along with Snort rule id's, allow signatures and descriptions to be refined and replaced with updated information. This option should be used with the \texttt{sid} keyword. (See section \ref{keyword sid}) \subsubsection{Format} \begin{verbatim} rev:; \end{verbatim} \subsubsection{Example} This example is a rule with the Snort Rule Revision of 1. \begin{verbatim} alert tcp any any -> any 80 (content:"BOB"; sid:1000983; rev:1;) \end{verbatim} \subsection{classtype} The \texttt{classtype} keyword is used to categorize a rule as detecting an attack that is part of a more general type of attack class. Snort provides a default set of attack classes that are used by the default set of rules it provides. Defining classifications for rules provides a way to better organize the event data Snort produces. \subsubsection{Format} \begin{verbatim} classtype:; \end{verbatim} \subsubsection{Example} \begin{verbatim} alert tcp any any -> any 25 (msg:"SMTP expn root"; flags:A+; \ content:"expn root"; nocase; classtype:attempted-recon;) \end{verbatim} Attack classifications defined by Snort reside in the \texttt{classification.config} file. The file uses the following syntax: \begin{verbatim} config classification: ,, \end{verbatim} These attack classifications are listed in Table \ref{Snort Default Classifications}. They are currently ordered with 4 default priorities. A priority of 1 (high) is the most severe and 4 (very low) is the least severe. \begin{center} \begin{longtable}[h]{|p{2in}|p{2.5in}|c|} \caption{Snort Default Classifications} \label{Snort Default Classifications} \\ \hline Classtype & Description & Priority \\ \hline \hline attempted-admin& Attempted Administrator Privilege Gain & high \\ \hline attempted-user& Attempted User Privilege Gain & high\\ \hline inappropriate-content& Inappropriate Content was Detected & high\\ \hline policy-violation& Potential Corporate Privacy Violation & high\\ \hline shellcode-detect& Executable code was detected & high\\ \hline successful-admin& Successful Administrator Privilege Gain & high\\ \hline successful-user& Successful User Privilege Gain & high\\ \hline trojan-activity& A Network Trojan was detected & high\\ \hline unsuccessful-user& Unsuccessful User Privilege Gain & high\\ \hline web-application-attack& Web Application Attack & high\\ \hline attempted-dos& Attempted Denial of Service & medium\\ \hline attempted-recon& Attempted Information Leak & medium\\ \hline bad-unknown& Potentially Bad Traffic & medium\\ \hline default-login-attempt& Attempt to login by a default username and password & medium\\ \hline denial-of-service& Detection of a Denial of Service Attack & medium\\ \hline misc-attack& Misc Attack & medium\\ \hline non-standard-protocol& Detection of a non-standard protocol or event & medium\\ \hline rpc-portmap-decode& Decode of an RPC Query & medium\\ \hline successful-dos& Denial of Service & medium\\ \hline successful-recon-largescale& Large Scale Information Leak & medium\\ \hline successful-recon-limited& Information Leak & medium\\ \hline suspicious-filename-detect& A suspicious filename was detected & medium\\ \hline suspicious-login& An attempted login using a suspicious username was detected & medium\\ \hline system-call-detect& A system call was detected & medium\\ \hline unusual-client-port-connection& A client was using an unusual port & medium\\ \hline web-application-activity& Access to a potentially vulnerable web application & medium\\ \hline icmp-event& Generic ICMP event & low\\ \hline misc-activity& Misc activity & low\\ \hline network-scan& Detection of a Network Scan & low\\ \hline not-suspicious& Not Suspicious Traffic & low\\ \hline protocol-command-decode& Generic Protocol Command Decode & low\\ \hline string-detect& A suspicious string was detected & low\\ \hline unknown& Unknown Traffic & low\\ \hline tcp-connection& A TCP connection was detected & very low\\ \hline \end{longtable} \end{center} \subsubsection{Warnings} The \texttt{classtype} option can only use classifications that have been defined in \texttt{snort.conf} by using the \texttt{config classification} option. Snort provides a default set of classifications in \texttt{classification.config} that are used by the rules it provides. \subsection{priority} The \texttt{priority} tag assigns a severity level to rules. A \texttt{classtype} rule assigns a default priority (defined by the \texttt{config classification} option) that may be overridden with a priority rule. Examples of each case are given below. \subsubsection{Format} \begin{verbatim} priority:; \end{verbatim} \subsubsection{Examples} \begin{verbatim} alert tcp any any -> any 80 (msg:"WEB-MISC phf attempt"; flags:A+; \ content:"/cgi-bin/phf"; priority:10;) alert tcp any any -> any 80 (msg:"EXPLOIT ntpdx overflow"; \ dsize:>128; classtype:attempted-admin; priority:10 ); \end{verbatim} \subsection{metadata} The \texttt{metadata} tag allows a rule writer to embed additional information about the rule, typically in a key-value format. Certain metadata keys and values have meaning to Snort and are listed in Table \ref{Snort Metadata Keys}. Keys other than those listed in the table are effectively ignored by Snort and can be free-form, with a key and a value. Multiple keys are separated by a comma, while keys and values are separated by a space. \begin{table}[h] \begin{center} \caption{Snort Metadata Keys} \label{Snort Metadata Keys} \begin{tabular}{|p{1in}|p{2.5in}|c|} \hline Key & Description & Value Format \\ \hline \hline \texttt{engine} & Indicate a Shared Library Rule & "shared" \\ \hline \texttt{soid} & Shared Library Rule Generator and SID & gid$|$sid \\ \hline \texttt{service} & Target-Based Service Identifier & "http" \\ \hline \end{tabular} \end{center} \end{table} \begin{note} The \texttt{service} Metadata Key is only meaningful when a Host Attribute Table is provided. When the value exactly matches the service ID as specified in the table, the rule is applied to that packet, otherwise, the rule is not applied (even if the ports specified in the rule match). See Section \ref{targetbased} for details on the Host Attribute Table. \end{note}. \subsubsection{Format} The examples below show an stub rule from a shared library rule. The first uses multiple metadata keywords, the second a single metadata keyword, with keys separated by commas. \begin{verbatim} metadata:key1 value1; metadata:key1 value1, key2 value2; \end{verbatim} \subsubsection{Examples} \begin{verbatim} alert tcp any any -> any 80 (msg:"Shared Library Rule Example"; \ metadata:engine shared; metadata:soid 3|12345;) alert tcp any any -> any 80 (msg:"Shared Library Rule Example"; \ metadata:engine shared, soid 3|12345;) alert tcp any any -> any 80 (msg:"HTTP Service Rule Example"; \ metadata:service http;) \end{verbatim} \subsection{General Rule Quick Reference} \begin{center} \begin{longtable}[h]{| p{1in} | p{4.5in} |} \caption{General rule option keywords} \\ \hline Keyword & Description \\ \hline \hline \texttt{msg} & The msg keyword tells the logging and alerting engine the message to print with the packet dump or alert. \\ \hline \texttt{reference} & The reference keyword allows rules to include references to external attack identification systems. \\ \hline \texttt{gid} & The gid keyword (generator id) is used to identify what part of Snort generates the event when a particular rule fires. \\ \hline \texttt{sid} & The sid keyword is used to uniquely identify Snort rules. \\ \hline \texttt{rev} & The rev keyword is used to uniquely identify revisions of Snort rules. \\ \hline \texttt{classtype} & The classtype keyword is used to categorize a rule as detecting an attack that is part of a more general type of attack class. \\ \hline \texttt{priority} & The priority keyword assigns a severity level to rules. \\ \hline \texttt{metadata} & The metadata keyword allows a rule writer to embed additional information about the rule, typically in a key-value format. \\ \hline \end{longtable} \end{center} \section{Payload Detection Rule Options} \subsection{content} \label{sub:content} The content keyword is one of the more important features of Snort. It allows the user to set rules that search for specific content in the packet payload and trigger response based on that data. Whenever a content option pattern match is performed, the Boyer-Moore pattern match function is called and the (rather computationally expensive) test is performed against the packet contents. If data exactly matching the argument data string is contained anywhere within the packet's payload, the test is successful and the remainder of the rule option tests are performed. Be aware that this test is case sensitive. The option data for the content keyword is somewhat complex; it can contain mixed text and binary data. The binary data is generally enclosed within the pipe ($|$) character and represented as bytecode. Bytecode represents binary data as hexadecimal numbers and is a good shorthand method for describing complex binary data. The example below shows use of mixed text and binary data in a Snort rule. Note that multiple content rules can be specified in one rule. This allows rules to be tailored for less false positives. If the rule is preceded by a \texttt{!}, the alert will be triggered on packets that do not contain this content. This is useful when writing rules that want to alert on packets that do not match a certain pattern \begin{note} Also note that the following characters must be escaped inside a content rule: \begin{verbatim} ; \ " \end{verbatim} \end{note} \subsubsection{Format} \begin{verbatim} content:[!]""; \end{verbatim} \subsubsection{Examples} \begin{verbatim} alert tcp any any -> any 139 (content:"|5c 00|P|00|I|00|P|00|E|00 5c|";) \end{verbatim} \begin{verbatim} alert tcp any any -> any 80 (content:!"GET";) \end{verbatim} \begin{note} A \texttt{!} modifier negates the results of the entire content search, modifiers included. For example, if using \texttt{content:!"A"; within:50;} and there are only 5 bytes of payload and there is no "A" in those 5 bytes, the result will return a match. If there must be 50 bytes for a valid match, use \texttt{isdataat} as a pre-cursor to the content. \end{note} \subsubsection{Changing content behavior} The \texttt{content} keyword has a number of modifier keywords. The modifier keywords change how the previously specified content works. These modifier keywords are: \begin{table}[h] \begin{center} \caption{Content Modifiers} \label{Content Modifiers} \begin{tabular}{|p{1in}|p{1in}|} \hline Modifier & Section \\ \hline \hline nocase & \ref{sub:nocase} \\ \hline rawbytes & \ref{sub:rawbytes} \\ \hline depth & \ref{sub:depth} \\ \hline offset & \ref{sub:offset} \\ \hline distance & \ref{sub:Distance} \\ \hline within & \ref{sub:Within} \\ \hline http\_client\_body & \ref{sub:HttpClientBody} \\ \hline http\_cookie & \ref{sub:HttpCookie} \\ \hline http\_raw\_cookie & \ref{sub:RawHttpCookie} \\ \hline http\_header & \ref{sub:HttpHeader} \\ \hline http\_raw\_header & \ref{sub:RawHttpHeader} \\ \hline http\_method & \ref{sub:HttpMethod} \\ \hline http\_uri & \ref{sub:HttpUri} \\ \hline http\_raw\_uri & \ref{sub:RawHttpUri} \\ \hline http\_stat\_code & \ref{sub:HttpStatCode} \\ \hline http\_stat\_msg & \ref{sub:HttpStatMsg} \\ \hline fast\_pattern & \ref{sub:FastPattern} \\ \hline \end{tabular} \end{center} \end{table} \subsection{nocase} \label{sub:nocase} The nocase keyword allows the rule writer to specify that the Snort should look for the specific pattern, ignoring case. nocase modifies the previous \texttt{content} keyword in the rule. \subsubsection{Format} \begin{verbatim} nocase; \end{verbatim} \subsubsection{Example} \begin{verbatim} alert tcp any any -> any 21 (msg:"FTP ROOT"; content:"USER root"; nocase;) \end{verbatim} \subsection{rawbytes} \label{sub:rawbytes} The rawbytes keyword allows rules to look at the raw packet data, ignoring any decoding that was done by preprocessors. This acts as a modifier to the previous content \ref{sub:content} option. HTTP Inspect has a set of keywords to use raw data, such as \texttt{http\_raw\_cookie}, \texttt{http\_raw\_header}, \texttt{http\_raw\_uri} etc that match on specific portions of the raw HTTP requests and responses. Most other preprocessors use decoded/normalized data for content match by default, if \texttt{rawbytes} is not specified explicitly. Therefore, \texttt{rawbytes} should be specified in order to inspect arbitrary raw data from the packet. \subsubsection{format} \begin{verbatim} rawbytes; \end{verbatim} \subsubsection{Example} This example tells the content pattern matcher to look at the raw traffic, instead of the decoded traffic provided by the Telnet decoder. \begin{verbatim} alert tcp any any -> any 21 (msg:"Telnet NOP"; content:"|FF F1|"; rawbytes;) \end{verbatim} \subsection{depth} \label{sub:depth} The depth keyword allows the rule writer to specify how far into a packet Snort should search for the specified pattern. depth modifies the previous `content' keyword in the rule. A depth of 5 would tell Snort to only look for the specified pattern within the first 5 bytes of the payload. As the depth keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{depth} is specified. This keyword allows values greater than or equal to the pattern length being searched. The minimum allowed value is 1. The maximum allowed value for this keyword is 65535. The value can also be set to a string value referencing a variable extracted by the \texttt{byte\_extract} keyword in the same rule. \subsubsection{Format} \begin{verbatim} depth:[|]; \end{verbatim} \subsection{offset} \label{sub:offset} The offset keyword allows the rule writer to specify where to start searching for a pattern within a packet. offset modifies the previous 'content' keyword in the rule. An offset of 5 would tell Snort to start looking for the specified pattern after the first 5 bytes of the payload. As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{offset} is specified. This keyword allows values from -65535 to 65535. The value can also be set to a string value referencing a variable extracted by the \texttt{byte\_extract} keyword in the same rule. \subsubsection{Format} \begin{verbatim} offset:[|]; \end{verbatim} \subsubsection{Example} The following example shows use of a combined content, offset, and depth search rule. \begin{verbatim} alert tcp any any -> any 80 (content:"cgi-bin/phf"; offset:4; depth:20;) \end{verbatim} \subsection{distance} \label{sub:Distance} The distance keyword allows the rule writer to specify how far into a packet Snort should ignore before starting to search for the specified pattern relative to the end of the previous pattern match. This can be thought of as exactly the same thing as offset (See Section \ref{sub:offset}), except it is relative to the end of the last pattern match instead of the beginning of the packet. This keyword allows values from -65535 to 65535. The value can also be set to a string value referencing a variable extracted by the \texttt{byte\_extract} keyword in the same rule. \subsubsection{Format} \begin{verbatim} distance:[|]; \end{verbatim} \subsubsection{Example} The rule below maps to a regular expression of /ABC.\{1\}DEF/. \begin{verbatim} alert tcp any any -> any any (content:"ABC"; content:"DEF"; distance:1;) \end{verbatim} \subsection{within} \label{sub:Within} The within keyword is a content modifier that makes sure that at most N bytes are between pattern matches using the content keyword ( See Section \ref{sub:content} ). It's designed to be used in conjunction with the distance (Section \ref{sub:Distance}) rule option. This keyword allows values greater than or equal to pattern length being searched. The maximum allowed value for this keyword is 65535. The value can also be set to a string value referencing a variable extracted by the \texttt{byte\_extract} keyword in the same rule. \subsubsection{Format} \begin{verbatim} within:[|]; \end{verbatim} \subsubsection{Examples} This rule constrains the search of EFG to not go past 10 bytes past the ABC match. \begin{verbatim} alert tcp any any -> any any (content:"ABC"; content:"EFG"; within:10;) \end{verbatim} \subsection{http\_client\_body} \label{sub:HttpClientBody} The http\_client\_body keyword is a content modifier that restricts the search to the body of an HTTP client request. As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before 'http\_client\_body' is specified. The amount of data that is inspected with this option depends on the \texttt{post\_depth} config option of HttpInspect. Pattern matches with this keyword wont work when \texttt{post\_depth} is set to -1. \subsubsection{Format} \begin{verbatim} http_client_body; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "EFG" to the raw body of an HTTP client request. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"EFG"; http_client_body;) \end{verbatim} \begin{note} The \texttt{http\_client\_body} modifier is not allowed to be used with the \texttt{rawbytes} modifier for the same content. \end{note} \subsection{http\_cookie} \label{sub:HttpCookie} The http\_cookie keyword is a content modifier that restricts the search to the extracted Cookie Header field (excluding the header name itself and the CRLF terminating the header line) of a HTTP client request or a HTTP server response (per the configuration of HttpInspect \ref{sub:http-inspect}). The Cookie buffer does not include the header names (\texttt{Cookie:} for HTTP requests or \texttt{Set-Cookie:} for HTTP responses) or leading spaces and the CRLF terminating the header line. These are included in the HTTP header buffer. As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_cookie} is specified. This keyword is dependent on the \texttt{enable\_cookie} config option. The Cookie Header field will be extracted only when this option is configured. If \texttt{enable\_cookie} is not specified, the cookie still ends up in HTTP header. When \texttt{enable\_cookie} is not specified, using \texttt{http\_cookie} is the same as using \texttt{http\_header}. The extracted Cookie Header field may be NORMALIZED, per the configuration of HttpInspect (see \ref{sub:http-inspect}). \subsubsection{Format} \begin{verbatim} http_cookie; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "EFG" to the extracted Cookie Header field of a HTTP client request. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"EFG"; http_cookie;) \end{verbatim} \begin{note} The \texttt{http\_cookie} modifier is not allowed to be used with the \texttt{rawbytes} or \texttt{fast\_pattern} modifiers for the same content. \end{note} \subsection{http\_raw\_cookie} \label{sub:RawHttpCookie} The http\_raw\_cookie keyword is a content modifier that restricts the search to the extracted UNNORMALIZED Cookie Header field of a HTTP client request or a HTTP server response (per the configuration of HttpInspect \ref{sub:http-inspect}). As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_raw\_cookie} is specified. This keyword is dependent on the \texttt{enable\_cookie} config option. The Cookie Header field will be extracted only when this option is configured. \subsubsection{Format} \begin{verbatim} http_raw_cookie; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "EFG" to the extracted Unnormalized Cookie Header field of a HTTP client request. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"EFG"; http_raw_cookie;) \end{verbatim} \begin{note} The \texttt{http\_raw\_cookie} modifier is not allowed to be used with the \texttt{rawbytes}, \texttt{http\_cookie} or \texttt{fast\_pattern} modifiers for the same content. \end{note} \subsection{http\_header} \label{sub:HttpHeader} The http\_header keyword is a content modifier that restricts the search to the extracted Header fields of a HTTP client request or a HTTP server response (per the configuration of HttpInspect \ref{sub:http-inspect}). As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_header} is specified. The extracted Header fields may be NORMALIZED, per the configuration of HttpInspect (see \ref{sub:http-inspect}). \subsubsection{Format} \begin{verbatim} http_header; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "EFG" to the extracted Header fields of a HTTP client request or a HTTP server response. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"EFG"; http_header;) \end{verbatim} \begin{note} The \texttt{http\_header} modifier is not allowed to be used with the \texttt{rawbytes} modifier for the same content. \end{note} \subsection{http\_raw\_header} \label{sub:RawHttpHeader} The http\_raw\_header keyword is a content modifier that restricts the search to the extracted UNNORMALIZED Header fields of a HTTP client request or a HTTP server response (per the configuration of HttpInspect \ref{sub:http-inspect}). As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_raw\_header} is specified. \subsubsection{Format} \begin{verbatim} http_raw_header; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "EFG" to the extracted Header fields of a HTTP client request or a HTTP server response. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"EFG"; http_raw_header;) \end{verbatim} \begin{note} The \texttt{http\_raw\_header} modifier is not allowed to be used with the \texttt{rawbytes}, \texttt{http\_header} or \texttt{fast\_pattern} modifiers for the same content. \end{note} \subsection{http\_method} \label{sub:HttpMethod} The http\_method keyword is a content modifier that restricts the search to the extracted Method from a HTTP client request. As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_method} is specified. \subsubsection{Format} \begin{verbatim} http_method; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "GET" to the extracted Method from a HTTP client request. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"GET"; http_method;) \end{verbatim} \begin{note} The \texttt{http\_method} modifier is not allowed to be used with the \texttt{rawbytes} or \texttt{fast\_pattern} modifiers for the same content. \end{note} \subsection{http\_uri} \label{sub:HttpUri} The http\_uri keyword is a content modifier that restricts the search to the NORMALIZED request \textsc{URI} field . Using a content rule option followed by a http\_uri modifier is the same as using a uricontent by itself (see: \ref{sub:UriContent}). As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_uri} is specified. \subsubsection{Format} \begin{verbatim} http_uri; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "EFG" to the NORMALIZED URI. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"EFG"; http_uri;) \end{verbatim} \begin{note} The \texttt{http\_uri} modifier is not allowed to be used with the \texttt{rawbytes} modifier for the same content. \end{note} \subsection{http\_raw\_uri} \label{sub:RawHttpUri} The http\_raw\_uri keyword is a content modifier that restricts the search to the UNNORMALIZED request \textsc{URI} field . As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_raw\_uri} is specified. \subsubsection{Format} \begin{verbatim} http_raw_uri; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "EFG" to the UNNORMALIZED URI. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"EFG"; http_raw_uri;) \end{verbatim} \begin{note} The \texttt{http\_raw\_uri} modifier is not allowed to be used with the \texttt{rawbytes}, \texttt{http\_uri} or \texttt{fast\_pattern} modifiers for the same content. \end{note} \subsection{http\_stat\_code} \label{sub:HttpStatCode} The http\_stat\_code keyword is a content modifier that restricts the search to the extracted Status code field from a HTTP server response. As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_stat\_code} is specified. The Status Code field will be extracted only if the extended\_response\_inspection is configured for the HttpInspect (see \ref{sub:http-inspect}). \subsubsection{Format} \begin{verbatim} http_stat_code; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "200" to the extracted Status Code field of a HTTP server response. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"200"; http_stat_code;) \end{verbatim} \begin{note} The \texttt{http\_stat\_code} modifier is not allowed to be used with the \texttt{rawbytes} or \texttt{fast\_pattern} modifiers for the same content. \end{note} \subsection{http\_stat\_msg} \label{sub:HttpStatMsg} The http\_stat\_msg keyword is a content modifier that restricts the search to the extracted Status Message field from a HTTP server response. As this keyword is a modifier to the previous \texttt{content} keyword, there must be a content in the rule before \texttt{http\_stat\_msg} is specified. The Status Message field will be extracted only if the extended\_response\_inspection is configured for the HttpInspect (see \ref{sub:http-inspect}). \subsubsection{Format} \begin{verbatim} http_stat_msg; \end{verbatim} \subsubsection{Examples} This rule constrains the search for the pattern "Not Found" to the extracted Status Message field of a HTTP server response. \begin{verbatim} alert tcp any any -> any 80 (content:"ABC"; content:"Not Found"; http_stat_msg;) \end{verbatim} \begin{note} The \texttt{http\_stat\_msg} modifier is not allowed to be used with the \texttt{rawbytes} or \texttt{fast\_pattern} modifiers for the same content. \end{note} \subsection{http\_encode} \label{sub:HttpEncode} The \texttt{http\_encode} keyword will enable alerting based on encoding type present in a HTTP client request or a HTTP server response (per the configuration of HttpInspect \ref{sub:http-inspect}). There are several keywords associated with \texttt{http\_encode}. The keywords 'uri', 'header' and 'cookie' determine the HTTP fields used to search for a particular encoding type. The keywords 'utf8', 'double\_encode', 'non\_ascii', 'uencode', 'iis\_encode', 'ascii' and 'bare\_byte' determine the encoding type which would trigger the alert. These keywords can be combined using a OR operation. Negation is allowed on these keywords. The config option 'normalize\_headers' needs to be turned on for rules to work with the keyword 'header'. The keyword 'cookie' is dependent on config options 'enable\_cookie' and 'normalize\_cookies' (see \ref{sub:http-inspect}). This rule option will not be able to detect encodings if the specified HTTP fields are not NORMALIZED. \begin{tabular}{| l | p{4.5in} |} \hline {\bf Option} & {\bf Description}\\ \hline \hline \texttt{uri} & Check for the specified encoding type in HTTP client request URI field.\\ \hline \texttt{header} & Check for the specified encoding type in HTTP request or HTTP response header fields (depending on the packet flow)\\ \hline \texttt{cookie} & Check for the specified encoding type in HTTP request or HTTP response cookie header fields (depending on the packet flow)\\ \hline \texttt{utf8} & Check for utf8 encoding in the specified buffer\\ \hline \texttt{double\_encode} & Check for double encoding in the specified buffer\\ \hline \texttt{non\_ascii} & Check for non-ASCII encoding in the specified buffer\\ \hline \texttt{uencode} & Check for u-encoding in the specified buffer\\ \hline \texttt{bare\_byte} & Check for bare byte encoding in the specified buffer\\ \hline \texttt{ascii} & Check for ascii encoding in the specified buffer\\ \hline \texttt{iis\_encode} & Check for IIS Unicode encoding in the specified buffer\\ \hline \end{tabular} \subsubsection{Format} \begin{verbatim} http_encode:, [!] http_encode:[uri|header|cookie], [!][]; \end{verbatim} \subsubsection{Examples} \begin{verbatim} alert tcp any any -> any any (msg:"UTF8/UEncode Encoding present"; http_encode:uri,utf8|uencode;) alert tcp any any -> any any (msg:"No UTF8"; http_encode:uri,!utf8;) \end{verbatim} \begin{note} Negation(!) and OR({\tt |}) operations cannot be used in conjunction with each other for the \texttt{http\_encode} keyword. The OR and negation operations work only on the encoding type field and not on http buffer type field. \end{note} \subsection{fast\_pattern} \label{sub:FastPattern} The \texttt{fast\_pattern} keyword is a content modifier that sets the content within a rule to be used with the fast pattern matcher. Since the default behavior of fast pattern determination is to use the longest content in the rule, it is useful if a shorter content is more "unique" than the longer content, meaning the shorter content is less likely to be found in a packet than the longer content. The fast pattern matcher is used to select only those rules that have a chance of matching by using a content in the rule for selection and only evaluating that rule if the content is found in the payload. Though this may seem to be overhead, it can significantly reduce the number of rules that need to be evaluated and thus increases performance. The better the content used for the fast pattern matcher, the less likely the rule will needlessly be evaluated. As this keyword is a modifier to the previous \texttt{content} keyword, there must be a \texttt{content} rule option in the rule before \texttt{fast\_pattern} is specified. The \texttt{fast\_pattern} option may be specified only once per rule. \begin{note} The \texttt{fast\_pattern} modifier cannot be used with the following http content modifiers: \texttt{http\_cookie}, \texttt{http\_raw\_uri}, \texttt{http\_raw\_header}, \texttt{http\_raw\_cookie}, \texttt{http\_method}, \texttt{http\_stat\_code}, \texttt{http\_stat\_msg}. \end{note} \begin{note} The \texttt{fast\_pattern} modifier can be used with negated contents only if those contents are not modified with \texttt{offset}, \texttt{depth}, \texttt{distance} or \texttt{within}. \end{note} \subsubsection{Format} The \texttt{fast\_pattern} option can be used alone or optionally take arguments. When used alone, the meaning is simply to use the specified content as the fast pattern content for the rule. \begin{verbatim} fast_pattern; \end{verbatim} The optional argument \texttt{only} can be used to specify that the content should only be used for the fast pattern matcher and should not be evaluated as a rule option. This is useful, for example, if a known content must be located in the payload independent of location in the payload, as it saves the time necessary to evaluate the rule option. Note that (1) the modified content must be case insensitive since patterns are inserted into the pattern matcher in a case insensitive manner, (2) negated contents cannot be used and (3) contents cannot have any positional modifiers such as \texttt{offset}, \texttt{depth}, \texttt{distance} or \texttt{within}. \begin{verbatim} fast_pattern:only; \end{verbatim} The optional argument \texttt{,} can be used to specify that only a portion of the content should be used for the fast pattern matcher. This is useful if the pattern is very long and only a portion of the pattern is necessary to satisfy "uniqueness" thus reducing the memory required to store the entire pattern in the fast pattern matcher. \begin{verbatim} fast_pattern:,; \end{verbatim} \begin{note} The optional arguments \texttt{only} and \texttt{,} are mutually exclusive. \end{note} \subsubsection{Examples} This rule causes the pattern "IJKLMNO" to be used with the fast pattern matcher, even though it is shorter than the earlier pattern "ABCDEFGH". \begin{verbatim} alert tcp any any -> any 80 (content:"ABCDEFGH"; content:"IJKLMNO"; fast_pattern;) \end{verbatim} This rule says to use the content "IJKLMNO" for the fast pattern matcher and that the content should only be used for the fast pattern matcher and not evaluated as a \texttt{content} rule option. \begin{verbatim} alert tcp any any -> any 80 (content:"ABCDEFGH"; content:"IJKLMNO"; nocase; fast_pattern:only;) \end{verbatim} This rule says to use "JKLMN" as the fast pattern content, but still evaluate the \texttt{content} rule option as "IJKLMNO". \begin{verbatim} alert tcp any any -> any 80 (content:"ABCDEFGH"; content:"IJKLMNO"; fast_pattern:1,5;) \end{verbatim} \subsection{uricontent} \label{sub:UriContent} The \texttt{uricontent} keyword in the Snort rule language searches the NORMALIZED request \textsc{URI} field. This is equivalent to using the \texttt{http\_uri} modifier to a \texttt{content} keyword. As such if you are writing rules that include things that are normalized, such as \%2f or directory traversals, these rules will not alert. The reason is that the things you are looking for are normalized out of the URI buffer. For example, the URI: \begin{verbatim} /scripts/..%c0%af../winnt/system32/cmd.exe?/c+ver \end{verbatim} will get normalized into: \begin{verbatim} /winnt/system32/cmd.exe?/c+ver \end{verbatim} Another example, the URI: \begin{verbatim} /cgi-bin/aaaaaaaaaaaaaaaaaaaaaaaaaa/..%252fp%68f? \end{verbatim} will get normalized into: \begin{verbatim} /cgi-bin/phf? \end{verbatim} When writing a \texttt{uricontent} rule, write the content that you want to find in the context that the URI will be normalized. For example, if Snort normalizes directory traversals, do not include directory traversals. You can write rules that look for the non-normalized content by using the content option. (See Section \ref{sub:content}) \texttt{uricontent} can be used with several of the modifiers available to the \texttt{content} keyword. These include: \begin{table}[h] \begin{center} \caption{Uricontent Modifiers} \label{Uricontent Modifiers} \begin{tabular}{|p{1in}|p{1in}|} \hline Modifier & Section \\ \hline \hline nocase & \ref{sub:nocase} \\ \hline depth & \ref{sub:depth} \\ \hline offset & \ref{sub:offset} \\ \hline distance & \ref{sub:Distance} \\ \hline within & \ref{sub:Within} \\ \hline fast\_pattern & \ref{sub:FastPattern} \\ \hline \end{tabular} \end{center} \end{table} This option works in conjunction with the HTTP Inspect preprocessor specified in Section \ref{sub:http-inspect}. \subsubsection{Format} \begin{verbatim} uricontent:[!]""; \end{verbatim} \begin{note} \texttt{uricontent} cannot be modified by a \texttt{rawbytes} modifier or any of the other HTTP modifiers. If you wish to search the UNNORMALIZED request \textsc{URI} field, use the \texttt{http\_raw\_uri} modifier with a \texttt{content} option. \end{note} \subsection{urilen} The \texttt{urilen} keyword in the Snort rule language specifies the exact length, the minimum length, the maximum length, or range of URI lengths to match. By default the raw uri buffer will be used. With the optional \texttt{} argument, you can specify whether the raw or normalized buffer are used. \subsubsection{Format} \begin{verbatim} urilen:min<>max[,]; urilen:[<|>][,]; : "norm" | "raw" \end{verbatim} The following example will match URIs that are 5 bytes long: \begin{verbatim} urilen:5; \end{verbatim} The following example will match URIs that are shorter than 5 bytes: \begin{verbatim} urilen:<5; \end{verbatim} The following example will match URIs that are greater than 5 bytes and less than 10 bytes: \begin{verbatim} urilen:5<>10; \end{verbatim} The following example will match URIs that are greater than 500 bytes using the normalized URI buffer: \begin{verbatim} urilen:>500,norm; \end{verbatim} The following example will match URIs that are greater than 500 bytes explicitly stating to use the raw URI buffer: \begin{verbatim} urilen:>500,raw; \end{verbatim} This option works in conjunction with the HTTP Inspect preprocessor specified in Section \ref{sub:http-inspect}. \subsection{isdataat} Verify that the payload has data at a specified location, optionally looking for data relative to the end of the previous content match. \subsubsection{Format} \begin{verbatim} isdataat:[!][, relative|rawbytes]; \end{verbatim} \subsubsection{Example} \begin{verbatim} alert tcp any any -> any 111 (content:"PASS"; isdataat:50,relative; \ content:!"|0a|"; within:50;) \end{verbatim} This rule looks for the string PASS exists in the packet, then verifies there is at least 50 bytes after the end of the string PASS, then verifies that there is not a newline character within 50 bytes of the end of the PASS string. When the \texttt{rawbytes} modifier is specified with \texttt{isdataat}, it looks at the raw packet data, ignoring any decoding that was done by the preprocessors. This modifier will work with the \texttt{relative} modifier as long as the previous content match was in the raw packet data. A \texttt{!} modifier negates the results of the isdataat test. It will alert if a certain amount of data is not present within the payload. For example, the rule with modifiers \texttt{content:"foo"; isdataat:!10,relative;} would alert if there were not 10 bytes after "foo" before the payload ended. \subsection{pcre} \label{pcre} The pcre keyword allows rules to be written using perl compatible regular expressions. For more detail on what can be done via a pcre regular expression, check out the PCRE web site \url{http://www.pcre.org} \subsubsection{Format} \begin{verbatim} pcre:[!]"(//|m)[ismxAEGRUBPHMCOIDKYS]"; \end{verbatim} The post-re modifiers set compile time flags for the regular expression. See tables \ref{pcre-mod_perl}, \ref{pcre-mod_pcre}, and \ref{pcre-mod_snort} for descriptions of each modifier. \begin{table}[ht] \begin{center} \caption{Perl compatible modifiers for \texttt{pcre}} \label{pcre-mod_perl} \begin{tabular}{|c|p{4.5in}|} \hline i & case insensitive \\ \hline s & include newlines in the dot metacharacter \\ \hline m & By default, the string is treated as one big line of characters. \^\ and \$ match at the beginning and ending of the string. When m is set, \^\ and \$ match immediately following or immediately before any newline in the buffer, as well as the very start and very end of the buffer. \\ \hline x & whitespace data characters in the pattern are ignored except when escaped or inside a character class \\ \hline \end{tabular} \end{center} \end{table} \begin{table}[ht] \begin{center} \caption{PCRE compatible modifiers for \texttt{pcre}} \label{pcre-mod_pcre} \begin{tabular}{|c|p{4.5in}|} \hline A & the pattern must match only at the start of the buffer (same as \^\ ) \\ \hline E & Set \$ to match only at the end of the subject string. Without E, \$ also matches immediately before the final character if it is a newline (but not before any other newlines). \\ \hline G & Inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by "?". \\ \hline \end{tabular} \end{center} \end{table} \begin{table}[ht] \begin{center} \caption{Snort specific modifiers for \texttt{pcre}} \label{pcre-mod_snort} \begin{tabular}{|c|p{4.5in}|} \hline R & Match relative to the end of the last pattern match. (Similar to distance:0;) \\ \hline U & Match the decoded URI buffers (Similar to \texttt{uricontent} and \texttt{http\_uri}). This modifier is not allowed with the unnormalized HTTP request uri buffer modifier(I) for the same content. \\ \hline I & Match the unnormalized HTTP request uri buffer (Similar to \texttt{http\_raw\_uri}). This modifier is not allowed with the HTTP request uri buffer modifier(U) for the same content. \\ \hline P & Match unnormalized HTTP request body (Similar to \texttt{http\_client\_body}).\\ & For SIP message, match SIP body for request or response (Similar to \texttt{sip\_body}). \\ \hline H & Match normalized HTTP request or HTTP response header (Similar to \texttt{http\_header}). This modifier is not allowed with the unnormalized HTTP request or HTTP response header modifier(D) for the same content. \\ & For SIP message, match SIP header for request or response (Similar to \texttt{sip\_header}). \\ \hline D & Match unnormalized HTTP request or HTTP response header (Similar to \texttt{http\_raw\_header}). This modifier is not allowed with the normalized HTTP request or HTTP response header modifier(H) for the same content. \\ \hline M & Match normalized HTTP request method (Similar to \texttt{http\_method}) \\ \hline C & Match normalized HTTP request or HTTP response cookie (Similar to \texttt{http\_cookie}). This modifier is not allowed with the unnormalized HTTP request or HTTP response cookie modifier(K) for the same content. \\ \hline K & Match unnormalized HTTP request or HTTP response cookie (Similar to \texttt{http\_raw\_cookie}). This modifier is not allowed with the normalized HTTP request or HTTP response cookie modifier(C) for the same content. \\ \hline S & Match HTTP response status code (Similar to \texttt{http\_stat\_code}) \\ \hline Y & Match HTTP response status message (Similar to \texttt{http\_stat\_msg}) \\ \hline B & Do not use the decoded buffers (Similar to rawbytes) \\ \hline O & Override the configured pcre match limit and pcre match limit recursion for this expression (See section \ref{Config}). It completely ignores the limits while evaluating the pcre pattern specified. \\ \hline \end{tabular} \end{center} \end{table} \begin{note} The modifiers R (relative) and B (rawbytes) are not allowed with any of the HTTP modifiers such as U, I, P, H, D, M, C, K, S and Y. \end{note} \subsubsection{Example} This example performs a case-insensitive search for the HTTP URI \texttt{foo.php?id=} \begin{verbatim} alert tcp any any -> any 80 (content:"/foo.php?id="; pcre:"/\/foo.php?id=[0-9]{1,10}/iU";) \end{verbatim} \begin{note} It is wise to have at least one \texttt{content} keyword in a rule that uses \texttt{pcre}. This allows the fast-pattern matcher to filter out non-matching packets so that the pcre evaluation is not performed on each and every packet coming across the wire. \end{note} \begin{note} Snort's handling of multiple URIs with PCRE does not work as expected. PCRE when used without a \texttt{uricontent} only evaluates the first URI. In order to use pcre to inspect all URIs, you must use either a content or a uricontent. \end{note} \subsection{pkt\_data} \label{sub:pkt_data} This option sets the cursor used for detection to the raw transport payload. Any relative or absolute content matches (without HTTP modifiers or rawbytes) and other payload detecting rule options that follow \texttt{pkt\_data} in a rule will apply to the raw TCP/UDP payload or the normalized buffers (in case of telnet, smtp normalization) until the cursor (used for detection) is set again. This rule option can be used several times in a rule. \subsubsection{Format} \begin{verbatim} pkt_data; \end{verbatim} \subsubsection{Example} \begin{verbatim} alert tcp any any -> any any(msg:"Absolute Match"; pkt_data; content:"BLAH"; offset:0; depth:10;) alert tcp any any -> any any(msg:"PKT DATA"; pkt_data; content:"foo"; within:10;) alert tcp any any -> any any(msg:"PKT DATA"; pkt_data; content:"foo";) alert tcp any any -> any any(msg:"PKT DATA"; pkt_data; pcre:"/foo/i";) \end{verbatim} \subsection{file\_data} \label{sub:file_data} This option sets the cursor used for detection to one of the following buffers: 1. When the traffic being detected is HTTP it sets the buffer to, a. HTTP response body (without chunking/compression/normalization) b. HTTP de-chunked response body c. HTTP decompressed response body (when \texttt{inspect\_gzip} is turned on) d. HTTP normalized response body (when \texttt{normalized\_javascript} is turned on) e. HTTP UTF normalized response body (when \texttt{normalize\_utf} is turned on) f. All of the above 2. When the traffic being detected is SMTP/POP/IMAP it sets the buffer to, a. SMTP/POP/IMAP data body (including Email headers and MIME when decoding is turned off) b. Base64 decoded MIME attachment (when \texttt{b64\_decode\_depth} is greater than -1) c. Non-Encoded MIME attachment (when \texttt{bitenc\_decode\_depth} is greater than -1) d. Quoted-Printable decoded MIME attachment (when \texttt{qp\_decode\_depth} is greater than -1) e. Unix-to-Unix decoded attachment (when \texttt{uu\_decode\_depth} is greater than -1) Any relative or absolute content matches (without HTTP modifiers or rawbytes) and payload detecting rule options that follow \texttt{file\_data} in a rule will apply to this buffer until explicitly reset by other rule options. This rule option can be used several time in a rule. The argument \texttt{mime} to \texttt{file\_data} is deprecated. The rule options \texttt{file\_data} will itself point to the decoded MIME attachment. \subsubsection{Format} \begin{verbatim} file_data; \end{verbatim} \subsubsection{Example} \begin{verbatim} alert tcp any any -> any any(msg:"Absolute Match"; file_data; content:"BLAH"; offset:0; depth:10;) alert tcp any any -> any any(msg:"FILE DATA"; file_data; content:"foo"; within:10;) alert tcp any any -> any any(msg:"FILE DATA"; file_data; content:"foo";) alert tcp any any -> any any(msg:"FILE DATA"; file_data; pcre:"/foo/i";) The following rule searches for content "foo" within the file_data buffer and content "bar" within the entire packet payload. The rule option pkt_data will reset the cursor used for detection to the TCP payload. alert tcp any any -> any any(msg:"FILE DATA"; file_data; content:"foo"; pkt_data; content:"bar";) \end{verbatim} \subsection{base64\_decode} \label{sub:base64_decode} This option is used to decode the base64 encoded data. This option is particularly useful in case of HTTP headers such as HTTP authorization headers. This option unfolds the data before decoding it. \subsubsection{Format} \begin{verbatim} base64_decode[:[bytes ][, ][offset [, relative]]]; \end{verbatim} \begin{tabular}{| l | p{4.5in} |} \hline {\bf Option} & {\bf Description}\\ \hline \hline \texttt{bytes} & Number of base64 encoded bytes to decode. This argument takes positive and non-zero values only. When this option is not specified we look for base64 encoded data till either the end of header line is reached or end of packet payload is reached.\\ \hline \texttt{offset} & Determines the offset relative to the doe\_ptr when the option \texttt{relative} is specified or relative to the start of the packet payload to begin inspection of base64 encoded data. This argument takes positive and non-zero values only.\\ \hline \texttt{relative} & Specifies the inspection for base64 encoded data is relative to the doe\_ptr.\\ \hline \end{tabular} The above arguments to \texttt{base64\_decode} are optional. \begin{note} This option can be extended to protocols with folding similar to HTTP. If folding is not present the search for base64 encoded data will end when we see a carriage return or line feed or both without a following space or tab. This option needs to be used in conjunction with \texttt{base64\_data} for any other payload detecting rule options to work on base64 decoded buffer. \end{note} \subsubsection{Examples} \begin{verbatim} alert tcp $EXTERNAL_NET any -> $HOME_NET any \ (msg:"Base64 Encoded Data"; base64_decode; base64_data; \ content:"foo bar"; within:20;) alert tcp $EXTERNAL_NET any -> $HOME_NET any \ (msg:"Authorization NTLM"; content:"Authorization: NTLM"; base64_decode:relative; base64_data; content:"NTLMSSP"; ) alert tcp any any -> any any (msg:"Authorization NTLM"; \ content:"Authorization:"; http_header; \ base64_decode:bytes 12, offset 6, relative; base64_data; \ content:"NTLMSSP"; within:8;) \end{verbatim} \subsection{base64\_data} \label{sub:base64_data} This option is similar to the rule option \texttt{file\_data} and is used to set the cursor used for detection to the beginning of the base64 decoded buffer if present. This option does not take any arguments. The rule option \texttt{base64\_decode} needs to be specified before the \texttt{base64\_data} option. \subsubsection{Format} \begin{verbatim} base64_data; \end{verbatim} This option matches if there is base64 decoded buffer. \begin{note} Fast pattern content matches are not allowed with this buffer. \end{note} \subsubsection{Example} \begin{verbatim} alert tcp any any -> any any (msg:"Authorization NTLM"; \ content:"Authorization:"; http_header; \ base64_decode:bytes 12, offset 6, relative; base64_data; \ content:"NTLMSSP"; within:8;) \end{verbatim} \subsection{byte\_test} \label{sub:byte_test} Test a byte field against a specific value (with operator). Capable of testing binary values or converting representative byte strings to their binary equivalent and testing them. For a more detailed explanation, please read Section \ref{testing numerical values}. \subsubsection{Format} \footnotesize \begin{verbatim} byte_test:, [!], , \ [, relative][, ][, string, ][, dce]; bytes = 1 - 10 operator = '<' | '=' | '>' | '<=' | '>=' | '&' | '^' value = 0 - 4294967295 offset = -65535 to 65535 \end{verbatim} \normalsize \begin{tabular}{| l | p{4.5in} |} \hline {\bf Option} & {\bf Description}\\ \hline \hline \texttt{bytes\_to\_convert} & Number of bytes to pick up from the packet. The allowed values are 1 to 10 when used without \texttt{dce}. If used with \texttt{dce} allowed values are 1, 2 and 4.\\ \hline \texttt{operator} & Operation to perform to test the value: \begin{itemize} \item \textless{} - less than \item \textgreater{} - greater than \item \textless{}= - less than or equal \item \textgreater{}= - greater than or equal \item = - equal \item \& - bitwise AND \item \textasciicircum{} - bitwise OR \end{itemize}\\ \hline \texttt{value} & Value to test the converted value against\\ \hline \texttt{offset} & Number of bytes into the payload to start processing\\ \hline \texttt{relative} & Use an offset relative to last pattern match\\ \hline \texttt{endian} & Endian type of the number being read: \begin{itemize} \item \texttt{big} - Process data as big endian (default) \item \texttt{little} - Process data as little endian \end{itemize}\\ \hline \texttt{string} & Data is stored in string format in packet\\ \hline \texttt{number type} & Type of number being read: \begin{itemize} \item \texttt{hex} - Converted string data is represented in hexadecimal \item \texttt{dec} - Converted string data is represented in decimal \item \texttt{oct} - Converted string data is represented in octal \end{itemize}\\ \hline \texttt{dce} & Let the DCE/RPC 2 preprocessor determine the byte order of the value to be converted. See section \ref{sub:dcerpc2} for a description and examples (\ref{dcerpc2:byte_test_jump} for quick reference).\\ \hline \end{tabular} Any of the operators can also include \emph{!} to check if the operator is not true. If \emph{!} is specified without an operator, then the operator is set to \emph{=}. \begin{note} Snort uses the C operators for each of these operators. If the \emph{\&} operator is used, then it would be the same as using \emph{if (data \& value) \{ do\_something();\} } \end{note} \subsubsection{Examples} \begin{verbatim} alert udp $EXTERNAL_NET any -> $HOME_NET any \ (msg:"AMD procedure 7 plog overflow"; \ content:"|00 04 93 F3|"; \ content:"|00 00 00 07|"; distance:4; within:4; \ byte_test:4, >, 1000, 20, relative;) alert tcp $EXTERNAL_NET any -> $HOME_NET any \ (msg:"AMD procedure 7 plog overflow"; \ content:"|00 04 93 F3|"; \ content:"|00 00 00 07|"; distance:4; within:4; \ byte_test:4, >, 1000, 20, relative;) alert udp any any -> any 1234 \ (byte_test:4, =, 1234, 0, string, dec; \ msg:"got 1234!";) alert udp any any -> any 1235 \ (byte_test:3, =, 123, 0, string, dec; \ msg:"got 123!";) alert udp any any -> any 1236 \ (byte_test:2, =, 12, 0, string, dec; \ msg:"got 12!";) alert udp any any -> any 1237 \ (byte_test:10, =, 1234567890, 0, string, dec; \ msg:"got 1234567890!";) alert udp any any -> any 1238 \ (byte_test:8, =, 0xdeadbeef, 0, string, hex; \ msg:"got DEADBEEF!";) \end{verbatim} \subsection{byte\_jump} \label{sub:byte_jump} The \texttt{byte\_jump} keyword allows rules to be written for length encoded protocols trivially. By having an option that reads the length of a portion of data, then skips that far forward in the packet, rules can be written that skip over specific portions of length-encoded protocols and perform detection in very specific locations. The \texttt{byte\_jump} option does this by reading some number of bytes, convert them to their numeric representation, move that many bytes forward and set a pointer for later detection. This pointer is known as the detect offset end pointer, or doe\_ptr. For a more detailed explanation, please read Section \ref{testing numerical values}. \subsubsection{Format} \begin{verbatim} byte_jump:, \ [, relative][, multiplier ][, ][, string, ]\ [, align][, from_beginning][, post_offset ][, dce]; bytes = 1 - 10 offset = -65535 to 65535 mult_value = 0 - 65535 post_offset = -65535 to 65535 \end{verbatim} \begin{tabular}{| l | p{4.5in} |} \hline {\bf Option} & {\bf Description}\\ \hline \hline \texttt{bytes\_to\_convert} & Number of bytes to pick up from the packet. The allowed values are 1 to 10 when used without \texttt{dce}. If used with \texttt{dce} allowed values are 1, 2 and 4.\\ \hline \texttt{offset} & Number of bytes into the payload to start processing\\ \hline \texttt{relative} & Use an offset relative to last pattern match\\ \hline \texttt{multiplier $<$value$>$} & Multiply the number of calculated bytes by \texttt{$<$value$>$} and skip forward that number of bytes.\\ \hline \texttt{big} & Process data as big endian (default)\\ \hline \texttt{little} & Process data as little endian\\ \hline \texttt{string} & Data is stored in string format in packet\\ \hline \texttt{hex} & Converted string data is represented in hexadecimal\\ \hline \texttt{dec} & Converted string data is represented in decimal\\ \hline \texttt{oct} & Converted string data is represented in octal\\ \hline \texttt{align} & Round the number of converted bytes up to the next 32-bit boundary\\ \hline \texttt{from\_beginning} & Skip forward from the beginning of the packet payload instead of from the current position in the packet.\\ \hline \texttt{post\_offset $<$value$>$} & Skip forward or backwards (positive of negative value) \texttt{by $<$value$>$} number of bytes after the other jump options have been applied.\\ \hline \texttt{dce} & Let the DCE/RPC 2 preprocessor determine the byte order of the value to be converted. See section \ref{sub:dcerpc2} for a description and examples (\ref{dcerpc2:byte_test_jump} for quick reference).\\ \hline \end{tabular} \subsubsection{Example} \begin{verbatim} alert udp any any -> any 32770:34000 (content:"|00 01 86 B8|"; \ content:"|00 00 00 01|"; distance:4; within:4; \ byte_jump:4, 12, relative, align; \ byte_test:4, >, 900, 20, relative; \ msg:"statd format string buffer overflow";) \end{verbatim} \subsection{byte\_extract} \label{byte_extract} The \texttt{byte\_extract} keyword is another useful option for writing rules against length-encoded protocols. It reads in some number of bytes from the packet payload and saves it to a variable. These variables can be referenced later in the rule, instead of using hard-coded values. \begin{note} Only two \texttt{byte\_extract} variables may be created per rule. They can be re-used in the same rule any number of times. \end{note} \subsubsection{Format} \begin{verbatim} byte_extract:, , \ [, relative][, multiplier ][, ]\ [, string][, hex][, dec][, oct][, align ][, dce] \end{verbatim} \begin{tabular}{| l | p{4.5in} |} \hline {\bf Option} & {\bf Description}\\ \hline \hline \texttt{bytes\_to\_convert} & Number of bytes to pick up from the packet\\ \hline \texttt{offset} & Number of bytes into the payload to start processing\\ \hline \texttt{name} & Name of the variable. This will be used to reference the variable in other rule options.\\ \hline \texttt{relative} & Use an offset relative to last pattern match\\ \hline \texttt{multiplier $<$value$>$} & Multiply the bytes read from the packet by \texttt{$<$value$>$} and save that number into the variable.\\ \hline \texttt{big} & Process data as big endian (default)\\ \hline \texttt{little} & Process data as little endian\\ \hline \texttt{dce} & Use the DCE/RPC 2 preprocessor to determine the byte-ordering. The DCE/RPC 2 preprocessor must be enabled for this option to work.\\ \hline \texttt{string} & Data is stored in string format in packet\\ \hline \texttt{hex} & Converted string data is represented in hexadecimal\\ \hline \texttt{dec} & Converted string data is represented in decimal\\ \hline \texttt{oct} & Converted string data is represented in octal\\ \hline \texttt{align $<$value$>$} & Round the number of converted bytes up to the next \texttt{$<$value$>$-byte} boundary. \texttt{$<$value$>$} may be \texttt{2} or \texttt{4}.\\ \hline \end{tabular} \subsubsection{Other options which use byte\_extract variables} A \texttt{byte\_extract} rule option detects nothing by itself. Its use is in extracting packet data for use in other rule options. Here is a list of places where \texttt{byte\_extract} variables can be used: \begin{tabular}{| l | p{4.5in} |} \hline {\bf Rule Option} & {\bf Arguments that Take Variables}\\ \hline \hline \texttt{content}/\texttt{uricontent} & \texttt{offset}, \texttt{depth}, \texttt{distance}, \texttt{within}\\ \hline \texttt{byte\_test} & \texttt{offset}, \texttt{value}\\ \hline \texttt{byte\_jump} & \texttt{offset}\\ \hline \texttt{isdataat} & \texttt{offset}\\ \hline \end{tabular} \subsubsection{Examples} This example uses two variables to: \begin{itemize} \item Read the offset of a string from a byte at offset 0. \item Read the depth of a string from a byte at offset 1. \item Use these values to constrain a pattern match to a smaller area. \end{itemize} \begin{verbatim} alert tcp any any -> any any (byte_extract:1, 0, str_offset; \ byte_extract:1, 1, str_depth; \ content:"bad stuff"; offset:str_offset; depth:str_depth; \ msg:"Bad Stuff detected within field";) \end{verbatim} \subsection{ftpbounce} The ftpbounce keyword detects FTP bounce attacks. \subsubsection{Format} \begin{verbatim} ftpbounce; \end{verbatim} \subsubsection{Example} \begin{verbatim} alert tcp $EXTERNAL_NET any -> $HOME_NET 21 (msg:"FTP PORT bounce attempt"; \ flow:to_server,established; content:"PORT"; nocase; ftpbounce; pcre:"/^PORT/smi";\ classtype:misc-attack; sid:3441; rev:1;) \end{verbatim} \subsection{asn1} \label{asn1} The ASN.1 detection plugin decodes a packet or a portion of a packet, and looks for various malicious encodings. Multiple options can be used in an 'asn1' option and the implied logic is boolean OR. So if any of the arguments evaluate as true, the whole option evaluates as true. The ASN.1 options provide programmatic detection capabilities as well as some more dynamic type detection. If an option has an argument, the option and the argument are separated by a space or a comma. The preferred usage is to use a space between option and argument. \subsubsection{Format} \begin{verbatim} asn1:[bitstring_overflow][, double_overflow][, oversize_length ][, absolute_offset |relative_offset ]; \end{verbatim} \begin{tabular}{| l | p{4.5in} |} \hline {\bf Option} & {\bf Description}\\ \hline \hline \texttt{bitstring\_overflow} & Detects invalid bitstring encodings that are known to be remotely exploitable. \\ \hline \texttt{double\_overflow} & Detects a double ASCII encoding that is larger than a standard buffer. This is known to be an exploitable function in Microsoft, but it is unknown at this time which services may be exploitable. \\ \hline \texttt{oversize\_length $<$value$>$} & Compares ASN.1 type lengths with the supplied argument. The syntax looks like, ``oversize\_length 500''. This means that if an ASN.1 type is greater than 500, then this keyword is evaluated as true. This keyword must have one argument which specifies the length to compare against. \\ \hline \texttt{absolute\_offset $<$value$>$} & This is the absolute offset from the beginning of the packet. For example, if you wanted to decode snmp packets, you would say ``absolute\_offset 0''. \texttt{absolute\_offset} has one argument, the offset value. Offset may be positive or negative. \\ \hline \texttt{relative\_offset $<$value$>$} & This is the relative offset from the last content match, pcre or byte\_jump. \texttt{relative\_offset} has one argument, the offset number. So if you wanted to start decoding an ASN.1 sequence right after the content ``foo'', you would specify \verb!'content:"foo"; asn1:bitstring_overflow, relative_offset 0'!. Offset values may be positive or negative. \\ \hline \end{tabular} \subsubsection{Examples} \begin{verbatim} alert udp any any -> any 161 (msg:"Oversize SNMP Length"; \ asn1:oversize_length 10000, absolute_offset 0;) alert tcp any any -> any 80 (msg:"ASN1 Relative Foo"; content:"foo"; \ asn1:bitstring_overflow, relative_offset 0;) \end{verbatim} \subsection{cvs} The CVS detection plugin aids in the detection of: Bugtraq-10384, CVE-2004-0396: "Malformed Entry Modified and Unchanged flag insertion". Default CVS server ports are 2401 and 514 and are included in the default ports for stream reassembly. \begin{note} This plugin cannot do detection over encrypted sessions, e.g. SSH (usually port 22). \end{note} \subsubsection{Format} \begin{verbatim} cvs:> stream xœmRMoÔ@ ½çWÌq"wü1ϵ!!ñµ„í¡,mb‹º-ÿO’ÝD¢Eqì÷üü¬õ?kx슊ÄgçdÇšÅOgÎ\%Ö-åWÛY«èBäw—rÜŸ‚çsqÚŒ€OÌ⣜¶òºyÖjòûœ9ôN­äÿEü¾õµ”í+`É‘×2®á«ð7Fk6½ˆ];´‘ߌÝg?ÿ¸”endstream endobj 259 0 obj 432 endobj 267 0 obj <> stream xœåUÁŽÓ0•8æ+|t$âõxì±ç­@âÀÒÛÂaÕ²iÛeÛ‚Äß3NšØQ‹@À¢(#gæyæ½ñøAYÊæçø]nš‹+GV­÷U—ò®›‡zuü,7êé¢wņɑW‹Ûf‰À¬"XcåϦ¹ÖÏZo‚óLú¾í‚I‰õ§– `"Ò_ûE¶Áë]Ûyãë­ôèu‰úPÌÃäðnñ²ñÁÔd!Z¬dÛeÛ! @Ù!gìêŒ;É4pŒª›‡½Ý °øÁ7«4›d³ÁJF|b¦¨SYìúêÈ¢veÑž˜„mç„@òI¿Ó Z1o†‚P\wÔ@ƒwÂnEÙV¢Ð›ˆQ_õìðȾà¿“Þ·hYŠ#_8ÑÌ!SÐg’5;ˆFþ§¡òZÖ)¿)k!¯ª½¨ZÑ´ÏRFƒôe+E3a}!à¨f®2·›†¢ ý‚†UØÖ^C8§á› #X_“÷ùœœ¥ÞQ¡l>šâGrmª|œ·b½Ó/ŠÚÛ)•êÀš<%Ø'‹§b{ëþÛ[tóljè¸âavÌdö¾Kxr!™„~¾yu[ðWþEºŸµ€C‚]½×a~º=d_÷ÛVtOàRÕ#w}Ú5ÔM™äêÙù.="׈ÉOò ‰Ö&‚÷.— ù:©ÇËIä™2v€T~(ã¬BþÎ|*ÙT)VÝÿeêÆ*hUv=öy1÷Ä(;«NT™]Æ©ÿû|Ѽ–ç\Û?endstream endobj 268 0 obj 583 endobj 272 0 obj <> stream xœíœ[s7ÇgúèOáGo§º_¹•^(pÛ¦™Ä¤’HåÛ÷H{ÑY­l¯8vÂð¬%­´þ¿ŽŽŽüqL Sÿ§ú÷èlôà5×t|r1¢ãgð÷dôqÄB‘qõÏÑÙøÑÌ3rÌ%1Ö°ñìݨl€ k›gg£·“Ç%Zii&ÿŒ%¨œSJŒdZÛÉe1e„JEÅdî/…œ5%˜Ñ¸Ä4a(SÍ~©:àˆÓ\KßmˆÎŽgÏG³ïßNT£T-&o šãÎrh®•z3UÄZçÄä“€ÖŠ…gq©Ónò²˜J¨¥ þçBÃ-ŸÏcÑO£Dø}ŽMý£uZ)*úÅF;§Eè¹Ô ÁËšà r¡¶cͨ4ãšJi|é)30?<_‰••¨’]&NJ¡Ê!sï~ò,>÷ä2ö]¢^ŸÇ±œøw¡‰qåûŒÊª’äNOËVEù%jþ|??.¦VÃwh|gµÄ*æ/¥ƒæL.;Ôâ˲,¿ý²;{ð²²¢}éyð RcjØêZÒ-¬µºÀ†e™á Ì;~Z÷0.)_8€G&ϳæ÷®`º&5\Õt¶¬·4tЗß|ûDÁÖ¢`G¶njA;Ä2ôþó $o‰äÀÃ|ÿR©#–¡×7à9àÙÏÍfuñ|ÒÝEv®µ½K$iáIÎ ˆˆÞ¢6"º*{9YJSrÂMaEñ€ x¬fDÂký]Œ¸—à7à)Ǭ¼Ä¾`vÇø.C°”ØýJ¤3 ßk$Òé¸Ãðº¡kžFõÊyšXª{…¶Â&XPÜ×=Íæ÷µ‚3Ìcó­Ã¾oYý«aAã Ò¢3Žï; ÈÛèæ5$²{±>M…?5Ÿù 9Lªïcüw¥E>Ëõ`ÞéA;•ìžÞ»Ü&[wê<}û´GœB“áVÄ òP£mzý¯ã6xYn»Óun>C%ÆJøtT1ÞϺÜf Ä°Õ¡±æÖ‚[ËúQ1ÑóxÔÈî!ö{kùÍGÞÖÄŸ‹Ìd'Ùúfœë>°&ª}Œ{ Ç;9oÕÅ:=z丟aVù³Bpby+¡)ðuOË^k½Y)¼½ÝröæÁ›á½§ëÅÞeCD™S±>ÞÈÛ¸nžZŒH?ˆx¾ôgP`QÌÇúÃ(1I8}ôÔSœÆ6UÎmÝð²7¾W.tV³ûeêä¡-¨+ÑEéº1; ᇠDУ»§Õ'ð)nCÊ…·Ê·º¼o¨¨CTa­œ³m£Óã;g«ÎnŽ:J¤ÈþòAöJhGÛçJk¯&ÛÀ×òŒ”v|å)©Î¹?”œì³òÇ<¯Æ± 4~wHO bÒWÄEò¤£ÜŒñù_®éf7G¿ƒÿàtCÕø–¹øA·/S˜}¦}Ý–^|N0,À‡ú£`ÔÀBŸ/8ú”äÍ¢.äVÁòßG[(EÁ`U÷œø6÷3·k Få§±c-³B‡”ö*‹ôyCÌ<ëI/?u ¾êö‡Î¥5UýôHà¥?çG ë£úæ\¡` a®#ú;Hã»®QdÌö› ìªH òjbü™BÞÿ^B›=²?ÏZZÂF¬ãT“öe¥¯´ì7 s„ÙoÞ)*B-ÔìóÙ³UýÜÿ<ó(|³ÎÏ=u§` >Ðcêl|ÙCP}û¾ü†°n{¯h1¶LBý‘@¿†ÔµTó$_æélô þüµ°endstream endobj 273 0 obj 2229 endobj 308 0 obj <> stream xœíYÔFÇ¥<Χ˜GÏÃ4}!JYVy‰ò–C(0 aAJ>}ª}U¹§ç>ìÑZ+´–§Çîöþªü¯®êæó”31åñ§þ}óqòàJZ>}÷e§Oáß»Éç‰(›Lë_7§ß_—ÍÄ4°`¥ÕÓë·“êbêÝÔ Î8œü8ù£³¹a>p£ 6›K´V¦³¹à20'‹_âY¥¸öÅû‡ë#Eñe¦˜±Üºâš2k°Å<ü€MÉá_Ø`QÞׇ è×n«³Þ_ñó/³¹æ†'bu°Ì¹²·†{æMzv]³ú°j+Ïß¶·¯k«º‡^ÿ4QÚ2î@týÀi¾¥ÃÊomn°g[!•`Ʋ‚WS¨ö0öu®¤b:;ŽY|ÕgPuaÏœ…¶BxËd(®fš ÷§T.ZT ÊÄBÈÙwpU¥Á˜Bñr&XP‚kúù-þãd`સ‹_û•®1UÙ‚TŽ)xPpVÍÀ¾‹Ç³9gŽsom\–U¾ø¯¤±ŠØtÁqÍt÷ê<}%êÊ=ž > ¨ëníµ< ÔÝü„[q}ò.xƒø¢QÜ•Ÿ+®þkÛ•WÕ5=·Å£ò¢V„ÆP„i1ÄøÉ¥Hÿnñá6]…WyÇ¡u¼Æ¦pg93bïJ| ´€¡¨°'Ðg$^'Ä×ý.‰×\îN¼Bâ^Ò€ÂD¦šÆo[—ÛÑ}CäË"µÑ<žµ7xOzP2¾xH\öësà&pOý8ö«y —mì‡XÅR·Ê«ÞeMmX ÜÀÃã‡?è:ÿzc1+ ß“ÞM¡ÍþÎ_£) Çý”ÕázÂZʿ۾”£Î9#/‚%S*éû”4-OO?GÒŸ¡¥ÒÑRÓäý@šÞt$“žië³w@}“½@~ßµ™|‹XhŒk¼Ñ;¡MDv¤…G!BªÜO*£g?ÍCˆö¿ÃîöcröC˜ß$ãרŒÔþ¢ï…oY1†±@µ|™€þsbEHp+¯ R±+Qìfs$¿BòYÙ Í|¹M«ff9ñJà}­”ÌùqB³/ÒZ‹†é¦rú}U-ÚŸ¼ÒSý»Ì?Ik’ˆlÏË”½òè•·e•àM±ÚʳËYÒlši¹n+ºbÁ8äŠ)ëFj/€ZL“nÀR›FÖwÝßÃÕ‹ çÂQu¬Hòw ãËoç dzjŽ_Œ3á¹Ò&AöŒR!$ ×}Ùßý’"/¬ÀE|AK0 úõ1)‡\.ýRÝ‚–n™Šópå0¢Ú¿Ï=µRÀz”¥ză•©§z‘–Êu§ÊöJJ.V}eŸ[‘)]à€ß§5ŠeU_'ý£4<%=Ò½ÝU¢’3¯Ž[Lu ÝiáUÝÃr"Xrµ;Ýéþ‘xÚk€Îiç›CËE[îM>›‡ªëbó庱àJ{¦F!Ñÿ<ðfÀÇo*$êìï].Ž#.“€é5‚q%N0=§Zü½”d¢®ã‡ƒVÌùããéaF=Œå K]Ý—ý1ö9‘AWÞÌÜò2¼R)ˆÓEC@ër™î}'a:[‘ÖtïÂt@¦Q-×ü0Á»V=á­`œZØ¡ 52½7ÓòR2/»2yÇGs–ÏæÖs¦A²±Üœ|€ÚõÌFÊ»µ²kÓòíêœ-#]™‰ ßàÍ]„ |Æ´ gBpXìWk4!V¹„’mÂ~ªQê!…}ì£ê~ÙZ@$©¥;HSzäpÌ“ FNo§·=g‡¡àÚìÞ¾™èæ¬DTéTòsrü"³à˜äŽŒ^£)®Î0öM—dM¥D}ý£¸SµÞþŒs)ÑJ ÒXv’Ã8vq½Cb07>=µ§Î@jeB-É@o*ÞH­Fji(Góysi€×°b'‡ÛìáÛzªAª¾Ô®† •u&Þ.ô’X™N÷®v èiÚOªg/è&/!°îøIÖA'‰íÒ•7‰m¨Äzâ܇¸P-}Ü;¸SÎ’õ[7Éú¬=lN{ɉ6Í®.ï,ª•†qídñ-n²hÙv!/ žÚN~U.Ù+°'“pÞ1áÂÑq€\Ú^SNFïd‰ð&qbc–g¶:Ôß;4‰ç„ÙŠ:>dWšÿ—͵¬ó£L?‹ƒß”O|™OPO½{¹gZ^ݤû)(ÜOá¤Ò¤ùR9ï{/°½jÿ÷ˆt#òtwñ¸Íƒ;W°Ü—eT²Æ&[fžµ à4–‘La†kÈõt®ü͹¨†ªb›'דßàçè =›endstream endobj 309 0 obj 2450 endobj 351 0 obj <> stream xœí]É’Û¶}•¥¾BKi!ó°Jʼn_âÔËफ²H²ˆ»íŽëµÛvlgøû\pÂ%R¤$J”š•r„¢@¤Î¹8wúÝ’¶¤þ¿âóúõâÑ\Óåíû]~ ÿnï,ë²,>®_/_eÝØÒ§¹–Ë«—‹ü z9b—†QBáøëÅÏ+¾Þ(b­sbEÖNœ”B­Dò([o³šp·ú|-‰âÒéÕ›Ðõ>oZ³úd͈ãÎòÕmøúcõõë$ð$bõjMa”’Ã…ÂÙpŽpŒžÝnBŒ‘¾©¨%V±pTµ7ó¾üø}Ov㮾¢½™õ•®µÃ¯W_/„„ººÐⲸi¸"Zh0€€c¬D`ÖtySS凲)DzaNr6Òó€ã*¿XsN$tý¹Ö„iÁü± #Z+hÈ~È «gz³æ}¸À— IŒªõžp Oì0cb"d=oãçG5 Ñã·|TrCÜêyõm1f-ìêwtŠ8Á%<\y ]û f¦a¸+/† ~)<«rÅï€ïIš4"4—$ƒ£JbØÃU厾zà/ÍÑn(à¡¡ùƒG3L%Ì­¾÷V]0*KÜ2€xÀÎu8]êýZ¥`yKSmZ­¾±þ5™ÈêÏÀá'€Œ`ŽhͨŸæ« @RÞ5ÈmB&L¿Ì"³ HæJR«ÿVðGø½ ]ëg5'ŽÖÙBjAô ïÑõMza<6=œÞ,‚w1Â>ú& o¤ozÐÖ²ñn$%ºãwÌ.ß-Jý4øæ)|çæ[1ç†ã[ì‹ï+| ß¿M6¨cM“)™ n’rnoŒý±œžÑ})Ö[vXïĉÜÝÿ g!Wó6ÙlZêB‰{ÔZ=-˜LæÆ{c¹C”=Ò‚°¬v´¤±¬öÅòÕZpb¹DvéôºÇ 7$Ü¢hv,’u„d“»º}Â$*„IBÀ#)s_V­dHïµo9®t ³çuørf‰„ŸbK”%„Öïz"…`„±ðrg" é›Kxƒ®Er Áîi䉉ˆöøï#OTÿØ ’ÑwÉØÉaA-aè§š1=¾qφŠf‡ ‚ébX}dJÓ(`’ê‹qIº†ÈüwÁ#‡±>gp˜fýˆ’}}üÍQ²·DáDÜ Â-ç€ø ÐY$y Oƒø8ZŒ{w+.jˆÄ¥[”õÿ½ZWÊÖÔz™òà"Ég.ï+À_‡ƒH#}ãŸD*m=ØRÏ›¢Xe3ÍYr«•<œsb¨Yý² ó†Ë/kï9+ÂDŒÑ 0âò *4ã 9ʃÆAÅXàë ð¿[o(Ñð¡°†AñmdïCýJ‰~žâM㜦0 3æπ¤ž™ ã žÒYÕb»³z°7bŒ”XÑ/.£·‰xdôÓMU¾øa<¹Z<[¼[мð úØ%Ó`_´]JËàë+Ö?]±¹ƒ€òmg2€i4ˆ(¡:¶ø™íÿ`\Oiªû?`‡Á4Â[vP>ð¬à±ž——ÛH ]Ôná³Ym¢Üèû€b-Š˜ZIÿ&\à¾\IoÆß9 þ¬.q‰^4¿êQœñÛtò5 q –TøM†Ôc77 ÚtÇ©&’É’ ¢2ü%€Ç&H¹Z><ÌÛð} Uvõ¥‚NíÐ_Ê¿V!µlþHðÑ™®6ßRÀÂQ¿M3pÌòÚþ \ d³Ð;BÔÛVtNÁiÒ¹¡²bã05=•_¬ÕLÖüƒ-ó Gi[m)’!p''Œ.̶¸Ô>æ³)¨:5si#Ï2‡r´Ñ$a‚ç‹Ñ8iräÀq@š4EŽô>,ƒÉÁSä8E!OF!Qƒ6Cª A7° L¹Y†Áuj%Áè(½®T: ªvŸØÓüŽ Øš¨åƒõ‰'m¥„”¨×úú ÿËC PsÆ4-tÉô½—MÒa4ö)‘’“Í«š,爰ŠðS rð"bŸü|YpU>ˆ]ÿó"Õ>9äS°àSàÒž®ü˜ÑŸð*EK2RÊ¥Ó1S¤ªBW8ßY€´·a¡o*æ4é?UÔúªÙ~ÖÖ¡´ýc¥v瘠 ÷Ê¡w xÉ“–sdê[t=b˜6špþ0áŸûÒª½œù<àÏ@ 0FàU`_–¿{µ‡Á³Å¿N€)þendstream endobj 352 0 obj 2669 endobj 395 0 obj <> stream xœíœKsÛ6Ç;=êSèHãý8ÖIš¸3mìÔ39tzplç1±ã&qÒúÛwÁ‡°„ K”D‰v0™D õÛÅ»?)acêÿÔŸç×£ƒW\Óñ»¯#:~ß>XYd\œ_OËblìˆÓ\ËñéÛQu¥±cÃ(¡pþzôWÁ'SE¬uNd2åÄI)TÁÂY–,—iK‰¤¼x2‘DqétqŠ~ª­)~ž0⸳¼x¾þ6ûúËd* tJ—pwA‰¦øÓ_#•Í}ü5&:¤gÅ?ɳ¡N¨ÉAS¾ÍÐ4bLy¨¨%Vñèlúp«e÷Vñ}eÅâò¬tpø÷éo#!,áÆB§ÀÌ¢¢]n»¼¬áŠh¡kÿ1M8Õ¡¦Ê7pÚ´pÊ \älÕÐ5áî_g$^• Iœ_NÀ€„¥ºø/\ß™­ÓÅ׉ JSm<²‚Bú)X豌ç —ÁT¼1ÔèlÉ·TÄ0ƒøÔu³¶µ P¿šyl„êYu(àªópöÖ7™#QGÒ€f‚÷Eð=~[Óˆë¾ –ÁuJ‚½V)‚¿…¢WA x-¡$ùSü2™R¢Óp‡سÂHBÌ+øz-a6í»‡ÀÌ`*îÇ5Û½»fÕ¶‘X`O……‘Ú9å@zÕVðæŒRÓâ5 Ƶâ¦Ô ƒ¼Û™zh Z$¹¬\+ÖÆÍ×7XN#×Íáá1íÀ\‚ |‹Mc/-É¢Àâ|?¥Í“O??–ö¼c*E¥ÉsnöTüTÉÈøåŽ^œ‚R"ÜIc‹÷Á½EKbJ‡3ã?K)­A¨‡1 l˜;h‡Ö‹‡¬<¼ Æ T£#Ô,½öãÚ¸O›¶Zšp_aô Xö&ªxŒ8­Û.ZæÒ¸™° JÄ\gÚ÷@{‰¸ÎvZ´ J¬ˆÅœXJK<ƬïžÜ#£y)v î ãH»¦¹nKÊw¯F34ÏDUím™H•Ý&ùD,ß$mÀSK a4ž|gÏ<–—»î^X6)–Ó:d5–E`ùh¦޽feÌû`$3.ðÄ£áþ«îz2ŽÚêÆ»eNYFyï(ïÉ-'Q¶ˆ ™rËÈÁ=ìgÈf«R´fȳ²×¾¬ã ¦ðof¨/ÔÖN@mÙ+ÿ°(Ûm+ P^yŠFz8™–ꨢ¹Ä€cé«0”Z=KÁsÐÂÖ•)Gm3-õgçÔOù° ¬@J™LþBšyLs‡À>Éçü8ò·ù:¿ÊôGµ`Å÷ ³ '€ö³dIdá,6»¹ù# Žn†F„Ê^5Ì·‹CÍÒ6ÁÍZäpJ¶ÄÑT;hxÆþ¡bï"쥆_3­]âp èlB!/©hLÇPˆ5 Ü8z98Q3ÐwÌx‡· Œ?O¯ƒ‹MŠjäw¯‚Vß¹½H¸ËÂ~shÖ’*\ñÚ€ ‡4²ÿ«ÍQeò, „#Ab$~©¤•`h]"Ù_ïÔ_¯Y ´€•[w½Y7VëªV™„¦YEaîädòmêd²$òª(3Œ¦ž@FyP(ï'Ê}Ê8ʽ–ÛEQn´I€‹ÉÔisÖìw¬{÷»lÛ~űƒ0h³*¤ xC^Ðô(¨­f‚~Ú-Ì»Q[׺>µ*­8'’:^|ëfÛe°Ï¨Õ:X¾ØÁ*NEwTQŒùf6¹¼4øbE@Qcfek‡Þee;,–÷®lc–;¬ßH³lËÀàÓa®ä÷m¬ ·à­C÷³_Î,·YŽ7­m̲MÇ.“ =ä¢ÃZ¤tîÎZ ÿSÙ‹à¹ÈN6­!‚WÚ´Ö…`Þuâï‡r2¿žÉš(cÝà>Ö›‹œCÉk”§®|ÑÒ¾ô‚¿Oá©¶C|ðXàqˆí€8X (ù­³)Á[@£Y%ɧB’ïxÂqFµ6fÝ%Q k£Û¼\jfó4m6饈´Û°ùkñr¦vÓ98·òé6˜²¬Ðµ`ä~¡«qDàçQŽ•hÂÜÜò]ÍCû±öþÏ)¸2â c•£’gYrö™|…JšúO¡¨ß¥oHž1Yåd•3Gp•“&%‹ó\¼_ŽC)ÍN®µ/± ÐLp&8±û–&^Ò…`‘ VŸ•o÷9ó/Ò oÂõw‘_®_ „—u—УÌoæwU~—­’Nó‹R„é½ß±V-5Ä{¿àd¶Èn÷a‹Îî0GïÐÂ9µ„Ê"µðv±L¢EÉMƒ^ì MG7ãûðÝ×ÃwSÕ “^…’)³TðÍü|ŒL9Ö•Y*Ë{ϵ$wnâŠQÞðßô¶pHÐ4Ká×ÌÅy•ÌðÞ»?ŽÞØ£|!"ô6‰pHŽûÊŸŽNFŸÇ¢zw2¨;eã…O¡‘Ö¿tùðhtpôûøöË·ËÑÁë1¼ðÿ?£§ãŸFÏŽÆ'_Å ý.«ñµ•¯bN/Bù°<ø×XÔ%+|Ùt ~Ýêš6#¥2µw!â?(ûLÅý;=_F“M"è®»g¶üìÛîýna9g÷7söFò19ì‚3Њ“¹]yP}œöT ÖŽp¡›ÁYV´KSrZ\_¢WðÒðÞÝ-ÚeœèþíŒúK3»?»¨¹F—Í쿹ðX˜Æí]Û--§÷dš‡`ˆÙleDu¥_˜j83ß(Ýœe}Ø»UÈ-ëÛÞ­+òþÎ[PûE9]^˜ªýºÌKZ±a%†VL,Ú…ˆ‡Öõ²6ÈÔx¦¦ý+zYa.Y)‹ÇÖÞÛ[ ­­¯ïüîÂåùêcs±”®L~tÝTM‹>L^Z¹1-keºtU>êXЫ~¿*ƒÖÊ<¬þuÿ°í<å\¥`X•þõ”UåUCÏŒÿ“ÑÿE®åWendstream endobj 396 0 obj 2272 endobj 438 0 obj <> stream xœíK“Û6Ç·rÔ§ÐQ<Æ«ñ¸z“J¼U»§¦*‡­=8öØ›d<ñ+ÙÍ·ßA-=Hh43(—-š‚†MñÿC7Ð ÌÇ%gbÉßîõõûų¤áËwŸ|ù-þ}·ø¸m“e÷òúýòùUÛL,=óF½¼z»ˆ?@`+ÏÜÒ Î8ž¿ø×J5k`Îy¯V¬YKæµV°‚ìY‘ÎêfmgšËÕÒÙ/ ÇkHA?ô þ}õ·Å7W‹—‹Kí]k´G€õŒ·vAxÅ}þbñìÅß—_>ý~½xöãR,ž}þyþý_ñåÅ×Ë¿,¾y±|yôí>¸ýß“ñŸ4¿^µú¹Y[ü¢ŒÕáî;æ@„Cí ³ñ,95€Ý‡±­<Û{»ð]mÕîö­öœØÖJ`F™Nì^Xù&WY”‡5(¤«7¨œî}Ã!¼¹Öø±ðîZXü¸w±Ñ‰tA ºŒ—Ž™âtáeXW"êUƒÌ)+WÿmÖœï‚]æZ#ƒ™åÍůEjï®Î gøH+öO ûþPnÃn骒ÿ$Éwè,Zì‘×IØÛ"؃ ‹c– 97öÅmØÛß/ï%Enã>|Ì!Z©¬?)ÖÕ.Ö§ºxW„uå=ÓåYWíUZ^®Ö·é>:ç©ðpì<ÃaðžN1MR ¡1\ípƒd©úáònÌ´ämÃ@ï'‘æioËçBSo”óV;93­?2Rê²á(x†ãP)ð­ÈYêòž”&Ó õ¶óa®Z1q3`ÊÛÁ¬ÔÀ±éq˜ðfB+ÓYžˆÛ1ÒK5?ʺíGYQÕZz³QµJïGÙöF e]~.…·šSHÛ^sçö.9…öÂ7ž½…‹Ã~“í—Co †)¹·7®b¾€îº•8¨Ý/-f3sgË,b–IÌD·),"aû«Ô“ž™œÝŠMðÇŸ4W]ß—®[1k`VP1ßO'mºîÌš% QI×$z~ ޱgÆq3’X¿W UÁÐ3ãú>·‚;fé™uVÁ¿ææ‹vŽXA„¹Pºp\¨ ¥ú ÊØo †¬x¶M¡8¢ŠÊ×ÅòUÊ/ÄJ Á|³új¹©¡É‚U|Õ JpÝìƒ!çn¼xÀ …]8QÑá%LŸ©¨x]Š‘—Œ—ÌáÅ^|7^§Í¼¼HÃOY±¶c Ã¥Cc³åÿö$>,oÝ›öž® R?í{7bü!‰‹!ÂòºµWÌŽÆlHT<ŒYC¬‡Pp–˜Ðž*' g9:¨ïÓG:µê¾ž$W"ÃÕÔXÐe¹ú37Ö:$.ôm<¨²…‹od‹*~ª‹ ó‰@šå\Kk<“Ŧ†…Oƒ«8[‚Q˜LX8*e'£®©Ì!MQ¸ô%’¦!š-i¿$;IˆT}hÖ € g+_O¯A €ïQ¼L]*BÚò"|aÄUx!VäKº~%Öu»DÄY¿ú_Öxº˜d8ë2PZkĵ2÷ˆ™‹Ž é=]ù¨qö’ÒVÐ"³*³%œ”I2EÐ9ô·é$Ñr(˜´èáFUÖ÷ ëûI¡æe=¬s¡)Ô©®„”d+&o{Õ"(ìoÐgðeõË¥3¨yk[huj¿LjHgúGjð¹Y£øŸšù¸ºEŽ ˜¡ñHÝÆ«žž:!mIæŸL‰nÇûwÓfü¸Â©ð!'©ÀnR#¤Š,TÜ[§·×m߆“È»"š¨t],]³ú‚8,F©ˆ\brPW3}Š´…ùèÒ¼üJ@—ò}Ž„ŒȰâ¶Ŷç¢,Ç`m™ñ%Èõb.üp™Í:óÉŽ˜"³NS#-3SRNštLIÙ'M²K– H?mèÚ½E‰ 6—·Ýz¦·L?$e Z1·+©ä?zòwùPÎâ@IB"çç£V,Ç5ÄŠCá´ ˜à8×}Ú†$h®³ÀÙ¿õ^õMp¥šáé®ôIý§bÜž;Óf¸¥NEêq"u×´cB”›ö!H‘‡wéìq›WÅ!  ™ë3¬¡Âëôk¨ˆ¤>ŠÌª^‡­^1 ­µ²O¯»—PÝ1<-Hð’óá%lé<`ÄK˜Lð6Ÿê£Ði|E‡Uáªpeàrsϳ¸Ôlp!æ¥Ó€-\Çw›4àa¨”YÙÞÒ"ànï±Eö4­œ=NÎâ°ËÐ$`~Ø5älrq,áLç†]éèfÿ&Ò¶”9Q:1ØF x>»62ç𫄺Ï飧Ìã˜kO ú]”Mõf0eF—NÉEÊŒêSr‡' ÚBxh`’UÎîƒ3Rèò}#ó Õ*™H¸ùgiÓ7x¥™•~õuú-8;²Òù]&È6|cW“Hߟ÷«—á–sgYn?¥¸ôÇþÚY†Mh4DÙÓX»AœEÏ~Êž½MÏ…\``A­:H©÷…HÐO›©Àü`¥Ç…ò'¡5@D……ðsŸç ) H€àÒ£nWÿ ²Ínà»N’ˆ´x¼öé´H‰W“ehé ¸X¢ûËM‚å:´” ðaü“€õ¡oû%µ%Œm‘Ù…5N‡0󺓶OÆ7,P@˜cÙÃÊ`²°Öƒ?ȘìY’Î0ìøÓtXv9+™˜ 2}ÛÏœÐäÓ)„ÚbmDØ¢–×_@„tI«’¦«÷MZç%-“¤ó¿•àµhƒFÉ÷Z >Ý&ìó,ºê–,ºÚ7O•×­Êê–ôµèUØÕ´ª¶ªö(ÕŠ‘€³ª=)€ÐIµ$ 5ÊÒ±ÑdcÕêC×êP¶èn2EµÚ]êô²Z%EãmÛ¿ù{`PŽiz#UÁAÁgÜP@Œ7 ƶe‡ä²N¾f#³~.üåâÿd:endstream endobj 439 0 obj 2418 endobj 482 0 obj <> stream xœíœ[oÛ6LJíÍŸB03¼_^{A—Ýš"X†=´¹µh’6I»­ûô;”dóˆ¢â»-»BÑZ•)“²‡üŸ u—QÂ2êÿÔ¯g7££×\ÓìêaD³ð÷jt7be“¬~9»Éžœ–ÍXæˆÓ\ËìôrT}ƒVŽØÌ0J(œ¿ý™‹b¬ˆµÎ‰œcNœ”Båºë,cVîòËb, ŒEä÷Ó£·ð6ÑZ1_…ëß…Ã…!)ÅYþ%>cmàªìKQK¬bþP:MŒ‘Ña«ê>¬Úòí·ÝYǵ݇e[é:üuúëH(A¸1ÀÑé9€³ŽÅ‡†+¢…ÎyÉ‹cLå¬u¨©òCOÆ2f.r¶Ò",›ÀòyhðP¢´À¬þWq-àý‹bì$#ÌΤrÀ¶ئ”0kK˜ê€y}ØòÛº×å±µÛŸ Fœ`TvL¼0¯ eˆe1ж¶Ëc+)_[—ÂöSÁ,áÔ˜ü?6I”Ѫ‡€jL­QD9LíúPªuWËϰ,œ¥ L-%@|µ”hç4\5ÊU©õs_a޹ʕÝ*W1çV‚™˜ƒÊ½Êá¤-gD4äaÞlw.̺å–l‘Ì= ‡‹±Õà’Q;p;p»6nWÕ"p‹u·¡1Š@Tò‚éò2%àBk„÷áŠ[J ›-Ö‡°®°„e@8­i¿…¶ŸÃ¡‘YG„Ž…Ä€ð€ð‚¯ªTa¤>µ&ak<Á–Ã(Ä #‚w< ëYßÀ@‰ãJãIØãùéèdt—‰*1l²Bi3%$'ÜúŒâ“ãÑÑñËìËý׋ÑÑ›ŒŽ~ñÿémKU5ÕJÓu€8úÚ€{ ð=ëÇÖ‡U=kp2!ŠfØ0#€Û€ƒÛÐé+Xç})5ó¯›[Iü\ ¡ø*mµ’Ì|yÇšj“ö*Kô.ü×á˶Æp¸PöÅØö6å@Tõ ¹\j‰Jn%§„‹5Ùßšíq«¼šÛ¸íq;-©¬ˆØþ¼ƒ[o>ÃwÀv–ZÙXå¨kNèj‘.dU(çüÊ9#⶘ä8Æ•…’¿*˜ ÎÁ …¡ÜÞuÃ먯GMÏa0œCo<†º½eó•e j>[‡à´°Øô?„¶¡77’Íòß…¡ÔÂñ×itÕYèá#\&áq.]H¢à~ÁeøÐÙûäÙÛðÛ56XÁ¡¹uÛðüøÙÍ)×Rd‡b%q!2|°ÛM­AŽVZoð ÜÃ=àÓâÍÄVßxºî$Hö¬iH D9R‹dl7µ VLÖHÂw1á82¶ ß4|“¿£Ñ|žB̪Ëjê#¿ÇÊ ˜jìÖ1íÃÚQ Id¢"䃲î™w51]ñ³I¡~{Ú÷mÑ“f4Ê 1Ô|ìµæÙbÜ÷‘ &³Òinyà6éЦüÝÎùÙדúÿßþ󻛸T¼ëd¸Tš_øMú¾Z¿ü[ |ÆSí0ëîµ»™u[ÔÎ_§Ÿ¦VΠ¶]±_yƒ ä)az@‚ûEðÌ»*ŒälsC5·¾¾&Ö Üî%·ý›y—â=Š%½-ª‡€±ù(cþwµwµù¬–tHãÁs¯ˆtƒ îÖ%µREïnÂ*ºÖò‚Âlëi‘WÞȘ2oĵ³>™º¹¼‘¥>oý:m„¶…Ä¡qQç`e½Y<¶m[†êMjù%=:&½&dSnqolüSdL\Ü9, ûë•N¼$¬ìcº>&ª™¼N*ø(['aš§Ã–Ú} x7>f‹ààc.›N?Qíù~4¿ˆ2åÉü¢äN·s~Ô7G}]3g†nXá0â»Ñ¤®nþqš†½#Oßð½7TC„Óýâº7¶ÖYEæ¤yÓ»_Í¢DÿªY”ð³‡6QÖÃÔ ðƒJòëhAª R’*.‚±¡fžj% Ìâù)¸Ÿ ·$hþ÷¡íŒ¼jV#ôù§¬Ž…̆ÐÒV‚*r¤}j{‘ÈQ? ¯Ç=Oå— Ð¿襣Z!z[Ï2)uHúÁ<>ú¯à–„Ì_¤+*ëçõ¬.Õ<¶†â¬¥-Ì~¢pˆêMLJŠ}ü( >ÿs®]—š¸ÏO§T&+‚‘1´„Â$Ä})ò—¾!¨´O;”ùÆÛëÑÂÐ62è÷Ê?/ˆÁÈl_àÚªgâò-9´sªëaÍJSÍST§ƒÿM'³9j€øD·˜Ô\uLá·«&uìÕ*£Ú…?û.%ì¯c/¡<ÛxºÈ1X\þ3 ‹XÏLU×_û Ÿéƒc$® ~?}Ý×óJÛ ¥òÃjŠ[UŸåû5s¬´"Loß\K…o¬ä+Þ×i?½[ &w¾üZ 6n5¸N þóÈâÈχ–4òfãSÐÂÁBýÒwæñã3Q>?ò±Ñ$Jæ‘3Œð¿ö;\|Da[½­ýq뺇R{TÁ_ÿYÚdSŒ„éFºGäÞŠ&ÿW‹ásEnÓƒêÛ;0¢x1Ú>›ÞØímÔq¡9=QyÓ’YBy¼·Šf¥T©Ÿ„ùmWÏ™­qI©z„ËK)TwZhëE„IGxÒ¬Gü–JÓØˆF†‘Q¶ŸÐå -5™Š­‰Æ¼*bû hV SmsQqàT9Oµßö%ॹƒ°EìE8ŒÁ¸#ÊÇ@}ùŒ¥¬¾™üàÓÔ×Éè¬è‡)endstream endobj 483 0 obj 2280 endobj 524 0 obj <> stream xœíœYoÜ6Ç>î§ØGéA,ïãµhÒÚÆÛ¾4}HmÇ1ê#iœ6ýöêš‘–ÚÓöjm!"E2¿þg8ÚsÎÄœÇ?õ¿§×³¯_KËçŸf|þü½˜}œ‰²É¼þçôzþÍ"6szX°Òêùâݬê@Ìœ;Á‡›×³ß3‚sÃ¬Ê¾Í ÎçRû쿼0ÌûTv“ dð2{‹7¯á¦ƈì2çð-ƒÍNóBjÉŒSÙ«\3¸5Ù->t{R‚ëìsÛçUù¸1Rdç0f­6û”+f,·îÅ3mŒ|q£•egA“©¥KËMlHЙZùy!Ì1øª]=ÁÎ š­•ÉD\ ˜“ÕZØ,Ü~‹ãºÃÑÂ]i4ƒ—d'í¼îp1þÎ Íà¿JÁdËð..P¢§Ï¸BøPg1 §Õ` ÷Ìúå–9§{—K ÌðeÕV>~Ûƒ½xU[Õ½Œ0)mw®á¯yJ‡Á§Ö7ر­“ÑJíF6P(©˜„q§°/IëbŸ¾+„·L†Ž1tCÃ5±ëHpüÉ%"NÀÿ¹5–+44‘ ìŸ<ƒw_Å!*ÅÁIÕ6b•秊žquPÎŽð4‰%öÊ>ž`?:Àë–€k.·\>8àµ7¦uç zýr÷·8ÑSlJž*wDã¥Ä½±ÙZa|äMÍ.î­h†Ÿ¯ DqWÞÕ^1MwŽgd%ßNíÊ÷8  žÂî^=¼È Ø|‚vžúíµŽÀž`xÙÉë˜ç“ŒyR^^{y#BØr£LÙ†xHBôÐ>ððŠº…˜1€¿r jÝøNHs—^€,q“2 ¤—¤»aNl%ÝézX» sÏ~[*ÎâåkˆÙÔ(ÇcWCñ9¸_ˆôµ'£yñ}ÂÜçÚT¡]Òk?4̦³«ÂãM²+³+Haêc -ÁšVÓg1çƒ÷ªòêuz©o ñ2}!o¸MYP‹ºÇ…šò,÷£Âaw·j€ä1©p—"¥Â7˳Èuy–="Ç>à©\jCÂkÓ H×Q¡(1áý¬ô7Á[îžeIã=e9Oúâó%9©‹2O8è¬Ë= ¸bÏrÚçq !İjüŒæÅÏò|8ɤl'¢L¬WÓÏ´÷ŠHÓzˆ÷wÕ1cÛ$@eÒd_{+ÔÞÄC~ABÓqâ‡UWYéÂièN’™ôaÀ#Ø ·æP’`“ ɺ¤Ÿ«¦–J1ÑM†Á“ƒ™esƒ ó Okà­Îr¶‚…‰sQòásƒëŽ¥ä6ßø'͹œtLj^üTu‡í`»TXVhn*!"ãj(«ÊNÚ³–²LqÝ?`!'$\¿°ýPQp¦¼ Ù?ñ\Ū®+¾J†„Z·_Uªié©×Çš¶»ÆéWš‘¥ý¥ª4kõ˜Iê1Riv’ÊZþ‰—é´ý]ò2}°zw#Íœ6õÉ•3v ¨ìvïÛͨç: NæS.ô>ñæB»ÖP4Sèîgi) ÌÁÈ`nÒmWŸù2Urv› ðžÐÿ¿ Ð4ôJVgÚ ÝŒ6€ñ¡Î1íßóõSÚÂ{ÑfDž|9#º Þœöß§¨¸:ã-“f æÅ{øòñ…á/ù&aø6°“ôÿOv¢ç ìÄ›# ­²Ù»<¾V肯8É\GFõŠ üef+¨®s»eUrµJŒ“Ó_ ¿7IÖ¾j%nû ›ÊÚ+;Mt7ùH¬›“*%ºˆ-ë¸4)QH ÜûÄ´°|ÿ3'á²7õøÙ“égO+¨/?{ÚÌ—¯=:8I‘ŽP^vbMLGÓðœ¿'SЉå²ïIE< HqüY?_oÂh”Lò‰õg­[ÖÜ+¬É,ãõñÊÆDoÿ«¤‘ÑudX_¸ô+*“õñÛ`­ëZ×OCÚ“Êás˜ 9ë-*7¢{êÐN:ÒÎ9XA ^OŒë­´Ëãq½»ÖÇÁµ”Þ¡šnc2ƒZ›A)¦yŸû ë犵9.¬ßdÈõo¹à0íàèc$‰9øK,èÁ¯¶oêÁ‚¦—íÍ7y^xí˜ûP} Ø—T×ÛèÍ~Í0 4wR)ö¸°òæÕÇWâQÌÂqÉâõQþü@ÿaÿ ¨§°»ßwdég’ÇÎÛú«Œßìg3‚L }P¾F ö± šþïjAƒÕÇÛ€íמ}¢<Î,–Ùr, ^yÚõš$‡þ®©©[JÆ7ÅÅ é¤äS‰ñãWÃã:LÌ?%5³Ä|•îߤtQãaÑ=í{Dî¼vªÖìVڵȭgÁéNáa÷û#8óœ©^ëPN½ªC½É;8à® ¸Ðš™“Š>JÈjœ¾qs±É‹Åìøó?ЀÐendstream endobj 525 0 obj 1830 endobj 559 0 obj <> stream xœÍ[ëo·úQ_ú/ܷܹõòMEѦIiêÆ*Z ) Y²%×’­Èvÿ÷ásȽ“Œ(Ç]îpHÎã7þ°™'±™ñ/ÿ~sòè[içÍåÛ“yóþ]žüp"âMþïüfóù)sz#çÉZi7§/N±qrce˜¬ÞœÞœ|·ýãNLÞX/·W»½˜Œš…ÜžíæÉhã½ØÞ¶§ï`h°~=ßÉÉJ©Ýön·—FNA¨­¨ýëôÏe~=9ïÎo̤Uð›Ó¯ONóÝöén?ON kýöuþ­¥Ü¾I”‘^!iø¤Ã™÷0Ù´ßþŸjågµýq'Ä4káŸ8TI_ùIã ¾JJÉíK`wÖÁÖHó'`לËìZ± °>‰;ìºIûYvOw{…tUÀ}2“÷!( <ÃÆÀ¼o²“°a{³Ûë)H3ãFÂ|Öaq‘ø™wÛ÷y ?]˜Ü,²RÀÌÖnŸ±Ÿ½Ý©ÉØÙº´¶ôð™±ðÜÀ~Ö¯^ןiŦ_q°“²³!9½Áø FÐÒÖ–)cZ GRy$ì¶)¶—ÀCð“žu^zz„¨Œy—è/ã9‹ &»ümÚpeLÞ¯øÑu›*/×*ßö€=IÊc@ðòºžÕy?d…Øþ¶yRjË{ Ò„¨aë…QËåªÙÅåF Ò¿z206…q,nÏý«²EŠÎJö¨œ£±Û—÷dç8¯çÝb„¹4DG)«ºC¨¤^µU‘YÓfŸ¿ŠÜ U{hÀ’à(§)ä+FYtØ>Žº?ÏÞ :˜lùÙ¶¦H°¤'-aY¶ôoq°ÐVxV,ÜTGž·ŠîÚ(Àe¿ß™É8§Ë9*° Qv®ëÕÂÑ™P¼‚6ÆÑ½»Û3¬—LÅ®ËÊIºà »¿»÷ÂÚ¼8r¯­f¿Ù ™^•÷lZXï'd«HGèÍ ¼‡MPv)iQÝŸw–Nz˜wt; 1Þ`ºÇúÑÔI7ãîSù¡±ðyK°þEÄçÎnŸ-ùÖ"Ë2j3QÌ·ÕNýD„–¨Øu³ ÍP±'*¬›ä(©ÞªcÚŒÙY"¾IPCa6œ›ËYŽCr: å¾€˜®­JÌ ‹³(£W `<%ÉéD%ÎÞMÎHj”‹¨JLjŸª^»ðLô]{xl(1HUúL>šÈu‘¾ˆ™V̲t>úú§ª`k4cPŠ:ê@ƒۜ‚S†2sÆš18S-$€Uõhaç jÝ 3ïû´²@Ù>ÛI ¤B/ P·¥ÍM Â4­ÁÄx@Y(g«”G~Ê.ÍF—/5ü$»”~jÔ\2vAhÕ¶X'g¨æÂ”V“P©78- D²ê­¹¯@ÚÛ{‚—ò&jMí oýV!aš­§dËZŒßþ _‰Y2Ù²š åU?"žï©¢8°÷ÎE žÓ¯ª¬¤“ôï2ø¼÷QÚÊA@ïw(5€n'] AæY Æó¯+*yú²“€2)÷ Ñü ¶Bi-H³o’Ó¾ zPùŠÜŒ‘KâÖ ééØOñˆÀ±úÇR·e·eYT pjzä(^È^11q¬–”ÝAÌ@;„4£;+sÐÇd’ëág\}RþxŽ^¼oº~ÛÄÿ¢==c-G-'ã»Y{/⃲EC—Ž b6ðØÚ\DëО?yÐLHÿ¾ü¼î]j;%[ÙñWhÝlÛ°~ØæÁÅi%µ1d.Ö¡E›oÀH|¹-@•¿4.6øk “rÂúHÐáìQ ¤,„áൎkøh’fG½×âò¢ø¬ŠƒúÀ?D9×~&r¬dÒ^âË€5k›heÕx¬FC0d)¼ã-Ï"ÞS"å.¬žfphœ×¤¶ }´nÃ@q3ÈÓ*ùŒsªh#JfgƒÇ-×ò¸ˆó,Ȱ¹º ìì³T«Ñ›³ˆ®€ñ¯kþ¥I²,U“€¶0wË€p&Qú€a/faYü©&¯‚ljé7§Ý<:¦¬`ŒÄs6ùrã7ÝëTZÔlVƒûÏùàåEŸf܉š¬†_EL Y2mÃE å… œóö“XîÜxÔÁæ'ˆv^…_qæä³g£Ñ[ÄY‰Xw›¶Wï%jo*WâM%$Îäd)bdï7Ð¶Ï ÓGzåÆÚ£pçGçåÇ£úîmyôºüxSßÝ•GïÊ×w7åÑYOß½_¼»®ï¦FsÆ^[‡žŸý\†ñY^´ V+ºUc¡1'äHIJ`ÜÝdIÑÿ/–ìEL/’ÙnGi‰‰žngá³ìx`SXÑÎ)éâ®ÆÐ(f–ÑX,-v"Ò*&K K¼\0W³Âñ}Ö×B§èÿ¡SÂ=+)rÆ· "ñp 9Àµû{Ø®§œ‹^ÉZ$ªaû¤~sÇÁšÿ,ü3šsÖ÷ù²TµHF—R†<×ÒðN{š*eçÁãð!·ô€¡hagtÑæ»XSÈaèÏ—±¼PÐÐò€Ã.SuŃŒ=ýä¬qpÇ’'“^ª¬îÃV²´¤ãÁKξiZÄhœ…\®ûdgÌ„úkf’Þ¬¤Ë)jÓ»]¡ ʈq{)ï×úM BGõj‘²ÀÉí!ïG»ìDΉg,£Ïþ•} ¿L™ÅDßyslWÅ›êM^w΂´ ‚cKb:[©xØvPb’”ch½k•Í…Bf+•Dåä¿…ˆ¼e_×mæ*„u•ZhÇlC­õæõ´Põºs_è'Áꬤ¨‰¢ZÒŒŠƒ]>5ÓÊ[K!H³`­ÂkòeÞ{0‹ñäѦ@Ûrädˆ ¿ Ñ£S/ {<ÃA³ù1© ~Ë hÍ‚]2ožOC± ¶¶tÁG™spÛŠQ$¹}$L$'1ˆ^AM·Üg„V{ Á].¢•±hÈDõaJÊ# dyd]kÿ¾ðý‚¼ÇC˜] ‡°ˆýVeà<“7nÅ…µã&Y2r Í-m!:´š{ÊÒÞ¸ºâ¤ï`¸ÈßËPòàF¡Ètù°ûD±]pÏy5ÆÑ×ÏŽð\R%ø;¦Ö¹ZÕ•ƒŒaàË]qVCmHí¡¯ð–® ˆš³ô³eþ ƒ¼ff/»c-ïI5¿ÏîGŒ$2u} ïóÖ¼(Á¼W&ÅLJ<Ð&JÆç€bÔ‡ŠŸ 5k9Ô¬ÍfaBÎrýºrÃ7a8!*F|Úx'¾œ,ùEE//Ø€ö.UAbš¼šÀ•¥†WˆÁ?MY+³ÖáåD…Ej[yÿLcWX‚%øHœl?±Í}È“Jœžjõ’R Âj•6«„2s¬q±Å‚óÁÑ—º —©”ë"ð Uà΄ ïãˆøÌ( fîØZ:õ„`àëºy«&®Ôu›XtÕ‹b-IA§CÍ›¸*Ëek¤Y‰ÈšnpÍÀ·,^~¬ù¡\ƒ»3b½ ‚r:ˆ(~sD‚€ôQuŽ›;R¬äñ1}à>V(RJ ¢í¸OSOu6ÑLÂMBf^ ¨‰äù¼QÍeØàWêû}3a Aýöûmåµ}u¾jXÕWª¿ß5™]d–zÛº/ö¢f0³ú#ûdç8ÙÔ´Ô°"+•J´‹pN}7Cò±Jo¿®¾ðMµ —5³r¹’c‰Iû_Ð,{ˆ‚E0k–“Ä>ÿqI"Cý²_ö¥¿€)] Å"x njԫ¦~G¥È$EŒR„¾í#¤è›1Dº^~ªï»h…p«¤ýx­8ÏwùÝqñßǼËõÀö€”›í|¾ÌÖ“¢Öê/ÒÝ–4.à"eéW¥¶!`ÆC_l Z€ojK!iÃú‚䘞v†CAܨ“e¬#$Åò³-ŠE¤£Oñξ5Òä[âï۔ˆÜRa‘µ°»<2ÁÁNj>¼á«.|Þ~µÜ“øÖë9¹8 ÷ùdÀYý­Õ¥xjô’lÅÂ& rnrwOŸû<ŽÆÈèU;…Èjf“9Ö‰‘Á Ù äÖù}‘’<$c5<&þ€ã>¨ôÅꮸøÖ£Çíæv~.Å?GÇG‹,Ž&ăÀ/¢ì!õŒ[1ÛI+f'F=¯”Ž”©`©˜³‡“ñÎ žæJ¹J¶rU«1µT­J½hU%ò“˜îRrÑ …×)`Ö”I/*õök¨°õ§Z€z¹”px”Yê/ž»(2ø†”nwäŠá‰²ù,R}¢eµLÀä }ˆBà^òáqOcóͳ+†Þ80H³^o¢Âb &–IµtÈVuÌ%¬E•éÉUŠö` –zËéËJo6ð¯rßS È@Â}õeC¦*Žôë°.ÓNÛ£ÖíßjÉÚçÄ_?ÁïuìHúHXùÔբÌ@²[CÜ¿È<ç¤_ºDc•ûXgrKa«ù±¸Žx/â]‰žðu>BظŒoÆë=Í«P% ¨™˜LŸ ÂDƒ‘4jî‡v žév¢i½QbÞç+“#³˜ØëQÓlh*aÉEƒF_RŽx\Ë&¹Ø:ö˜_[o;‚m’Ø""Ì\Úo°qÇ;‹LìÁ_ý¾:‘ðÙ]}2g•âr»¯,v9™RdcÈÄÉ}.BFïôQ—Í7À‘`¡dÈZ3³\³‘#'E"‹’UuËâÔØ,Üúœú^g1£†{ØNìÄq«åPKâR±Ð0ázKêWÍr>Iägqà2aáôþ¶ïï$N ÁÊŠ¡LÝü˜$ΚÖÈ“+–È*æ¬,Ó©üp+Xês¨ÈZÅæ†×œ—ãÍá‘Bf |]Z-Xoáb¯?¸¼áª öçz{àªMžŒ-ÝN5·ƒsMæžç«4»ãËÜÇïSé’vªñ'Pû¶Ù<¾AžØ¾Ý-ÌO[bhm²ë’¥-|Æk8¹ƒµà¼2³Éü`¢ˆõp¿0F>l¨ÌÞ ÌÞfÇ]ÉXÞØÉ¿>«¯ïëmâ•5Lýo=Nkœ½—*W÷ò>1«ÀÜRz$=MüÅ9+måv¡ô"ùví ¶x%Éy*ä,tÛ–¢º mK‘ÔÐæü~4nÅtWºøÙ³<••”Áz.î^—gÓl+VœbêL3$0ø é&>·Ü¢Ôë ùöê}¢%\ò¼¨pã±ú;$$¨{‹„ŒäqëËíÓåÔ g\6¼l¹°Û•ê’4h›é™ef¥=º®{”åÿ(åýˆÞÑúðÞèŠjhÄYÂui¼µ(8@1Š5ô‡8ªC×÷"…WÕ}-w ·mÆ(mÜ„ŸàšJ*²Ê—°ºë^¥Sïøu±w{§„D±~±Y>°P>Ç×_žžü þþ Ý»Tendstream endobj 560 0 obj 4355 endobj 568 0 obj <> stream xœÕ]Y“¹qvèq~EûIÝO±€Â¾iåµM[Ò®lFìƒäÎÁY™äËåh—¿Ä×™8@¢«gØ´C¡X±¢…3/äü¸›'±›ññßë·ÏþCšyw÷ÓżûøïîâÇ á›ìâ?×ow_¿€fÚ,;79#á߯.æiÕ¡ÙÎÉI®³ØY1O3üøöâOûé°L«ÒzÙ?ËO?ù'è`Uìßåwò»‡K£$ô/÷—ùå_sÛüî6=ý׋ó t†"NÏÊÉ çvf•““az¿9\Γg¹¬0­K¹¸i™ÅþåáRLÆhS¼”j™¬©ÞþtP“ÖnYö9Ì0”ÖRÀ„.õ´®«… å–ÿˆß‹É:‰]áïÎ)Xn~üX: }]—n±‡yÒJÓ¶?”ȼ`ˤ´Óêì -v¶ÈI/ŽA¦óöp¹ÀöÀÊâ“6y¿ßçEÂr%œ´YöoüPj¶ÕBK'„ÎK6윙Ýÿ÷~5é3ßÃÇòx]†ý¡Ý[£Â‰);)%iÓ—¥A:ÀNYœxÄÀ˜ ½ÙŨž“ú '/ˆFì‘W¿¯Ëïxrr(Oí!W§Ða´²Û¢”oÒ‰™F0§·e ïÛ¾| ‰G”²›É³AíÇõzß:ÎõM5$óï ?Ý•·=úmºÙ@é3Ò–ê„å?¶Sð”¯>Eµ¯ì˜û"ûÿ<hRb^æHé5Û©çeë_¨¨£RÏ£±•r×å®vˆö’¥ãÞ Âs%m‰!³Iû†ÅëÌI÷”6AÀøüg\¢cø$áç;*UüËZÝGA œˆ‚€ïé‰,àZmªùy×µ£1LR¬ßzÛR‡¦ËS´Œ$$ÄΊ2ïíŒÈ‘š,Kà Áöžjìá.6pÃCëJ¡HÌp&:y¢™‚I#[Ô›æ2”v•Ã=ÅÙ#:%Ò¢riomÇüê^¿eEDˆ÷h¥yañº¼L:ë2v}¥,’>’P/ÀƒZçV^,ÍÛ>~˜¬ÝMí›É0ù‰eUÃÚ¸5@I~ò{Êh Äí8}^—Ä_:ù¤ì€ë‰ÈðÌY‰œq›‰ùì)Ç—ww+'¦¿MowègÝX‹ŸzéËÈôjJ"ÿfÒ«µn„¿‰î»¹™"¼Ê/JßC:¯a÷c‘Vnì!Onmâã“vªÃ£#.íœð dçÓB7ìÐËßäôa[)È't™—¢ÜV7ÎBÆýÛ†£ùÁ†ük£U爼×ÃÖ@5ïãf+{Šq›L—ÍDÃ×É{ŒäÆìZ‹ŒŒâ¦E*ÞÝÿHQK<ËïòY>+ƒ%ŽÞ ç0á„ÏMäAD甋 ‘Q™|™tk™Îkî7ÅÍü²FgÑ&!o‰[¾³òw,êê­žlÛÚGïã2ªò™×S‚áÂç}ì˜É80Öi)ø‚äl1~= „Þð@OXjq³ú¤x’3ZÊ l©$ÁΨÊ`Ïtt=,³ÏGçø³ú<ñ’Ó =×wèÇ3¥F±ÃG|nQVœÃdйO|¤‹Lp”’àѰ•uÈ3M° þGY´µ,‘_ºBË2¿,ŽºØÒÿnòïkÛrªÜçsÉb¸ŽÎ›™ÈG~õÅ^‹ºN»$%Ìì±y”Ô3Fb­¹Cr‰0h4¬a{C„^ƒ½æTq±éá?»+"ë=+²®‹ü먬‹ÑDÐ !ôïtÙÄ?“ô.ÈèE éÄk_’ó¶Ü%,êe¯(ÜD³mí·¦½¡išf/oɲÿ2>‚Dø RíÉwjRËç_ÌSØ’J_8RŽ(¦ÅûL+Ï”È9Ÿ¨»‘”^­ OXÿÿ¹Iâ¸bÅÆ˜;cVÀËO)ÝRˆŠ§'>“‰Vå[Á£z¯0.WVy§x…+è!ã±?Iw½ÈK”ä=yýyŸYŠ7UÊ‘^–#oÕ”o)ËcÉ.OMñ­)¢**Íÿþç,gÅU¬Ô"ójãk4«=²É¡»ZáÑÀŸÝ¥Ò`Ú¥¨Ö‚Û.$šÁ.ù/ÀœÛi½6&þýAEpggÁ`pJ¾kBe—Uë?øù(çóíAum´·2ä´€Òpûo>Ù¤(vúÍ‹‹?^ü¸ƒmSÅ9Øðu·.AP¢BÐxýöâëçÏžÿ~÷ñÃÃíųïwââÙ¿âÿ}ýÝoáŸçÿ´û»‹ožï|WÓú±NúmxT?ƒ €ìéæ\çäùÑo=5â­|9ÅNÑÂ:¨¤ó7,®XbáÄ%Ãrɧ¤Aâ¬/ç\ËÀ¹½íõòÐïs¯—¥×ÁÅ{ÜÄyY¸™*[˺&kï´puByd¬Za¤£«’ü ÍØŸ>ú!BO‰épQË Ãþ#`šs¹ûR‚¥Ô£y¦Œ.tåS0͸±ëy¬³Ý½*Ò­K_)`Z’@©¾dNЦ9gáP²ªàÔš‡’ÇûeqèÞ³|\_iòÉ+åÝ6‹•&%¤Š~fÝêª`Ôœpé•w–¤‰^ 7yÔOJ!¿25áºd—Š5LNÄL|Ê,»\µ<Ò0.Â0_åZ1‰BÃÄÉå”4•ä/@•,˜ÆUgê)E´ˆ=Þf%”ÄË8Bí1ÿî(œó¤F#suò爹—pÓ¬ÏIl€–¨æÖÒê'ªî!š€¡§å ¢€ä¥Çp”Œ.¨G¦¥·¿>ø«¥³¬­Æä£¯@¸Ø$fTãGYÝ…ðWRŽ[9Hµ JÉB|4ð´ dò|¤TZËï‘<Ï¥6LT®S”’~Yסå{jBúçûã‚q F{—FªéÇ;y$ß‹MØå1ËÑ›ð$O†uE­š}3§ÜÇüœî°m²7cñu:@¸tR¡“'zùCœû%A”È"öŠ_JZ;r­OÓTS8D°S2r(,ÕYrí­éææ¼/s _Vm˜«ÁѰ$êo oTÔÈ>ú˜½%ÞX¹§Ì‘.ó5YF˜8ûÓxLê;¬ú1¹ç¨DœVuû¯sèŠe ñ¨1p¨þ>û*·î¢E”ª4°ò#¥ ¦?‡cß#Ûb,ÕLH·ï¹•S¯– ©þÆ«²C–or8£ÐBc§õ¨ú).¹XGT†þ°ôØD°}eG½dG­ÈÆ¢ÉTh÷¿Ê—gˆôHXÊ´ÆiJ?ÍŸ޾öˆÿmܳ„ñU §æŒˆuÍ€èìI#gÈÁwWº )ŒÈ+:îî‰ÎG…ÙþòH„„ÜÎQí a4BV¼8N[ÚôOF^ß·ÔØ×nˆÉ |Ro®ƒ+`šáí÷‡ó5•¢ûUFÝ58|éoÁ™U®îå oÍðužb@1ë2,¶ZwϾ½ÔgåGÕâG)Ã*âîÙNø:ŸãÇ£E«k˜ê(]äiŠQþ$/u‰q—ñº„4ˆ)I¦@,ø"íXó<¸áÔ u¼8± –-ˆ’.±)‘‘ÚÁ`GÌBï¢aX,ò€Õ2´wÏMwÅÄ;%H©ÀtÆ#ãÄE,\ìº.“¸دrBPý{b„ËÖ!>:38û*öìüã± ö8ªNׯ'$(=ûˆç¶øÉU+ÉÇläˆ?Ê‚äׇqnèGµ7 ãK*(°, íϸ Û&V1;€ÖÈ„!>Sš,GI˜Zs¼˜Ûù³÷]3ë<„r_ÒŸ›ä-–Æ@fÎÀß1¯5ña]FzÈ„VWìîõµ@Ž`….–ÑX~£ÊK™-«Ð:+”5˜±ÊX`G­ôl@òvàj£ÝÀ&„®4ûY l™*óˆ±ê®Ï4J&9_Ñ’3Ìí¢±ÑWqRòÓ>%éáÕM”É]ÆN§¼&雲)ìüHÓ|wà‹Õ <‡öÓÊ÷d]}¾Uw &'ÎSrÕ*ù|Í-É¥F„Ô$õ÷ÈEeÐ;‡@J•ž•¿ÊÑ$ d`ãý©]¾éw(Âi|?,çê§°‚@9álš-[ ¦KÆ!{êÅ\|% LÎ`™Íôw ­€]2 †ÌS …¯šoûÄ»¤§½ÐÓjè–nõQc>·èXÙ&•JœbQÑLN›ø¸\ZÇÔUe=…¢¥mò{jZ¼A|"d]ovèV?òšÒ†hëShÎÉfuÄÛvÜ*ÎH2§Ù¦åÙ¦Ë •_ÏQ‰ÍwL³°Š¤õe¿t$’ÿƒ,ðtý´¹¼F~L÷Ïáöˆ¨â¯‡V9^6Óðâ…Ò­KšDó¦K˜Uy'jÞÿß%– =âjd¦puÈ5` 8øÉSZtöU0<Ü8i´gÐͽ|ú®„¼ÝQ²åæ…Ï\ ¦Šy‘ÏÞåŸe×ÃßT%˜Û‚U03èZ1Dú-ÎçÚ{&µptö³inæ®\v—gúèWôSûÌÁ$8B9)·2•ÜÛBÁäB&‹ú‡8$‰ÍD§æïœR%ÞñdW'L‘Í‚«x˜N»²6 wÝr¥˜Â4#QBÏñü“ò5&,˜ðà÷ñ[âD |Çü¦òDæšh:ž…kbœq³ ¢·£¬nêº3>R?éñ -ǯ[o>ýdMêM¥xÔ¬Ôs´õ÷¡ØcUbh<$7Ìø/9Ä}!fí#R‰ñê›—é‚ûÖœ1}µÙUó§z?b`çµÒ”¯b%[Ë|+x{R-ÂD“£¸I8¬&ð¦‚üÂÎÑ’&À4òÝggœ¢ÖSƒ¨ Õ´(Ç%TK| ]ù²^qw R3óÊr¥JRô ˆ`"£m×b}_¶û3Hbl©ÅZ*c‚úL—Û!!e´©!»ZjÙÅì_»67s‘Âsä]tˆ!"A¬ÿM¹¼½#´w4g•‘6D ã•”´SLW'TƪŒþXÐc,Úú-|CE ©Ýêg¶éø©¯:?5äe³”b —3Üx ¥>œÜϪúÊ ã¤m2EF¾ÑãF”d¢‰|æ‰?ü,/. ç§ò:)ûfPïÍ;xv'¢!é;óø¢S^_QÑQýù–N:µyù™ØNºË þf)«¢³ûÓmc¯SèâiYlß„}¥Í°{ D­×cj8Z5JWmžÁÛ`W`åÊ„@_}!ìTUU.ŒñsÅÙS¡~£­[¨NVØ!* L¦*×È#‰qMD#üE"3tä·£º¬}|ƒa=í.Eòc=T =þ6A>®t.ÂÉ× >0Sùã~Ðò'É•D—²¤<ðÊ¢´/wœo» S6k¨Q%&%‘–˜ ¬•ÎÌVã„8¿x Ä/¬ÙÔeL7fƒÿZ]¯¢_ÝØ*ˆ1ÁíLwÎÉsS:hì¢øW»v%&pJÉ̼°é7e´ ‡ÑÞ6§ºÅµ,ÌùÀ “Ú}Ë`I=®>z0Iº´çXÉîFãÙ£ôW /²c'…™ ÿ$ãNÄ þ\3nxjx’ó¾±*yÓÿWšŒÚ%¸6wWHE«#™‘wÈM úˆ[»üAœ÷´ê“lêëKäëBUgÀ\Å”€OS­ëÂI¹NXI[:¢ Ê…ø9¯+ßæúãÅÿ‡Ëñendstream endobj 569 0 obj 6015 endobj 574 0 obj <> stream xœÍ][s¹qNå‘¿â¼™'¥3¿ízmG®ìzUÊIÙyÐR$µ‘Dr%jcýŽø»ƒKÓ8ŠR¥\6ç‚Á¥ûë¯/€~ÞˆInþ'ý½x{öôß•›ë÷gbó{øïõÙÏg2>²I.Þn¾~Yg6a NÁßçWgbšíòØ&¨IÍBn¼“€›oÏþr>mÍ4kkÍùÓòë}ü œßÄ_f–ç·åÚ»rí~»sZAûê|W.¾,þ·…™¬$wß-×̬ÎïÊÅå•‹ríuùuYîÞ—kSùõ¦ë¡÷ç×éÇ?ÿCœ5I§C¦¹ðjò2„›ÕdÒ\ü×V —5´µ³ÓLƇíNÃU!-ôn''ç¬tÐåøÓÀ7õ·Û™‚²NçðÙ›ØØ<ûóŸ¶zbTp0ú|ñÃò+ ƒÁûÖ*Iß¿¯W/·;åçÉ‹™^}U[¸ÄÎÀЬC¹È·õ"=:‡Ô¯xG#Ã$`MW_ÆxY_ûç­œ‚–¤ŽÃ4Hzÿ§zµ4Û|÷¦›„ø2‰?–û—Ë4ŒDHÍrÒ¦eÂûWب4üüß­„»º®¾ô±¶ÿ “ &0vðUiê~¤ÆjÒþ‡-J“ró„B#6Ï_‚¼\×F_a§̆:ÿ¡ÌÊM½Ë5O&øW[k§`Äî©Ù‚Ö("#i$NÏYqP¯·n’ç”LÏ=pÃ*N·µ+×ìÏVÈ˰š.^&á‡×øÈ—‘ÛÂû.‡ž`­a¸?±Ý…¶T0¨6I¤³æÞ´êÑN“—*=à…Q{>?°¸È;\å Ãf'Õ²ÎY"…ÊëˆZõ²bÄeEƒ8-sþ:nñ ª¸º&€œZÓ˜\ù+ÃÁ'È¢½‡Éµ}NN8ÚZ«¸ÊÎÓlô0”s(;ç_nZè;ÿ¾ˆðïð¶ž„›÷®oÖ|¢£Yȯ¶©³5:^Ô…Âsæyu|AE»Ü_ôÅÌs™hêÅV˜+Ї_¶rž”ÍG ¼"T¸iñLY3¡ý¹ª£"²|»@ƒXQ$Fhk1¤M¢Î·,®m >[‘ÄPi3yÛ 0¿Xd…&P\#&%q¥±ŽöQÖz@;o_‰µç«÷ ÞMZ:³hÝeÕET £§FNºx•>6; Ô¤7ð5rä½ÅŸDk>&‘‡ž­LA‡^IZœhEÇF”!wû òè9ØÑÅ0ç©â®d­ÓÖõSõý;Vµ¢˜uüc¶<Áó”t2t((‹áxŸØ©.ìHÜ»Ì^L w0 ÊŽQ$uêQPă«àU¢Hü®5cR'Λ… Ál1d(ÃLÆQ®w“ðÉ4z!f×ô¡5 ˱ÇÊ„T„l\6hQP7¦¼éÙÄ–u,üàYJ¯·*Àä¢ÞZ v\?ŽÞj ÷”-Bƒ1EEÑÈš5iÞQ‹_—ÿé°;éÀÖ÷ÜIêDÂ7ÕêDâÝÛr @Ë`¶‰Cò,kËoó¥»SœMÀ¥™JVV„8›ïÞKÎsÎ ÐdEWZ½¢X¾0„Ö‹Èx*(·‘8I¹¥2  LbFœÖÆèµTŽÃÄ{F0Šz¢eç:&z ®I Ò†bhäÒB&!Œ8­Å)Î_äAù‘£¥°ûÙPd†g6I0ãŽÂ8¡Lébk3cS*Œ-B|€—õ>¯9T$°:!ê"›4“6N¡B$gd³ƒ‘+#~JliöŒÏ„È´›aZÌv‚‡éRçßm°-‘ <?Ë(cðš*i¢'„‹Ê’ÛzW}½øb â X…2G :8I›"o}ˆ÷g}.|IG{$‘ÌôKQ—+Âù7]O½Ž6¿\ `Û`¹bû^8Ë~-jîôÇz?õÏê2,íÁÛE„,ü·ø€Œ>cú‚ h³±Y$é!‹iÊ óæù¿=ÿ—¿œ?ß7RF‹bž©éºa ÞlÌ+û¢`Ô¿ãc+‰Û{ËããëäXBªI_Va ¼Ï‚Ú*dPÐsiþ›ƒ=å9ç}O³¢VW¨È_ÐŽ€JÆÊô–‡ÅLÛAzÿz^aç;B­žUòõ ¹\?÷×-®¨ªv/n9¼IØŽaµÚµä;XŸáì°—¿ð@£å~ç âÄÈãlïW{ñ+4% ·Ëæ0@{ž@všlðx-†"%²æÈÄ'2Ÿ_Ê®¨Õ|˜«´1Ôµh„¤NÌ*]ës\¤l !2±Ü·†¾Ê¼[I—5,%åµã‰ÇŽÎ02B²Îœ·›lenP™Æk8NV§7°Õý˜—‡áðQaɪnŸÎuÍ ôeþì\÷²\û¥rÝá«%‹RIìÓòvŸÉtÛ™S3>Ҿ܊Ì×ByAåKSþ!Ë=—/ÍíCxO®Þ]áRil¼s`ŽHK¿.j¿ÞçkýlzŸ&Óû£/DÝ{27ùÒÕ)ŒÝX°ºi½©¼¶¤6Ké»êÖ«E+L²ÿÔû®Û­kBÅ(ß­ pÑMU+ŒWù×ÞáKKÕt©Q È!Æ4_‚ÿo„˜ÿdKRœlÆøVã›\al—š€J¨%¬UžX#¨·OÌ·,š5!Õ[¾|>7ÊÇ©‡ p±¢„ ˆ!¡ð0ÙÏ·;=©8CƒíºÈ¤É&‚BâÞ%¹ tt€H׉•Å×äì>]kÇ£™w¤…„·’YúÐ5ÚÇ^ó¼¡\‰ÍÕì[›x?i£‘9}ÍäK”à)Ât–X€GÁ9™Ð>}63ú6Œ:+¸$#em`Œg‡bå}Uä(ÛcK7â„©R×Q Œæ™&~›bf¦‰Cñ!«W™ø?8º•ߨ/Y°%Í’…lŸÍîD—k<Ò&Ç~“c„ƒÈÁ1lçÀÓ,Ò *לºDCÌ®¢wxegÀhž>纀}ªV²Yø`›¹û˜¢šèï]Ó8Îc¡i9,³yy»Ò¥Â-… ·_qC'©â7Í2'™û±uA`ɉӋˆ ‘4-È éÌ‘&7®º$ž+‘ľ ÊÚ^þóPÝ+:sÈB)ÞÌÆh ‹e(ļÙ_¬xöÓ.^N ÓõšãŸÆÝ÷Ú1 Ë9Úá6ÎP¢ê'˜´yï?¾~ÓŠ<×JdQçãé$‰ÙY©ˆ‚Í'nYm*ðd¡°ôŠ¶Å´Øž’/&ýÚŒd·dÕgÈî¯;X2†ŠjFNA«c*?J*”4PLù‰a÷4?%«gPDÎàC“Ùl t LJuú˜Í{SȶHŸ"zY¡¹”J”¬ŠV‘Èbv#-R¥.ÈAÞ½ëaä'£¢µz»L+ËØŠœ¯•M‰¹ÇÕÔ¶3CùÙƒÑÆ'ÉÕÑÇqpŒè×쮺޿TæXE]*e‚hXb ^åÌ¿"-¼: ¨{ØI‹;Œëƒ­Æ.K»´­S æg–&Š=e-`="A=\Í‘y9EÍIE£†H¤Tág#ÊX)aOÞ@K$_SYš¤•#wIÅýdº² ]‰DÅS;ÈV-ëÃM(týЫIm‘ͱE_ÃÐ0W›B —X†ê£—¯ÀÛÄRZB×V€Ôæ’»8Åš²6z@†Ó—–ꮥ· &_n¹8ÃЉdf P{jK,­ÕŒK[P€VR¡M”à„òŠuµwvcq˜ìu)§×”³”³úUwÍûù/ù•®Á,>”ÝùñØ×V–Ö>¬ D÷hòuegÐâÕÃyðªOˆ3Y¼´~ÜZÌkß1=òj¡zV ½ªÀ¹¯àžŠª½¦ËJÖò ]÷ص¥¦¯6Z¸ ï Þ÷@ecIoþÕC•®É#$ë•ÅíRWøÆáà#…ÝkH€â}E܉Š,µÒ½Ø=ÛF‡L©•c¹T ó邪̯·¥Ð– ŽôU—¦úâÊ5 BðUÃ< oœŒó¼cüÒb’–÷–ŸqýÞ;H Ö²À¦ý… )*l˜-h(ìL5„ÿSg`Å&—®,uÍV ørƒay¹^݆ 3ìÙyÄü$¨‚ƒÖ`3üÚ$ÑxC÷Fæü[òŒû¥l*yÜØÁŠ){îI½³•!×;{mP1W%AÛXV™­š±±ŠÌ“>«†—@]ðçßÂd€7KŸK|›s‰¯JExódÁLü1•â8™Êñþ=h¹wXõyW®Ñ»°l‹óÛKiyûv,Î$,–"“nÜ”ß/ƒ:¦ @8­4æذú*C^ôäÝIò^lËXB–Ù©ÅJ?Ž>E¨%pyKcð¤R™ôåc}4ï`5«½ ·ù îCŠ”ŠNï‰à¤ya3ðëÜpû©¬ü0Ymd6NÅ©Û#RbµË~ÄIqÇ[ÊŒK·czqW‰ÔÇÔ0“º+­æXK5ãT‰c“¹xqœÌÅYÓæ$;`Ý8‚Ê<Àó³f{^WÃ}8e È<_öhN=ô.äPƒ©ªØt 75¼»æÂÒMSe£½#@ŠUòJ·Z‰’ÆÉó}š8¿v°Viu‚Žñžc‰ª Ú,Š0æw¦Ë°&³½Êµb#G‰Ë¼÷ëŠc „ ¼©ªÝ§4­qs2Û˜Ò~aPÒ%Ó£°˜6Ã@§®Ñ"˜Ï׿2ƒkùïÊÉØ$÷ «ÚuŠó¡-]âó3ü&÷×L5mz6mJÛ±‹«¬NÄŽRîÄCCuþêp‡»ÎrØá¦¬Ð"%/ô¢Q¯Vÿz8Y]Ì%0{ôÊ^Çz&¾ÞŸ´QS½|þ8üaä'”T¦m5¥º°J¶p±€ûáŸà Jfó‘ëÃFLµn‡é5¾„{_õAô®«ÓÖ¸ì=Ý¿†a燮JT¼žŒ›|Â%‹dõg:ïcRÈ¡>« ŠnÙÀ½;fÝÏö°°Jõ¯s.ÇF‚9 !  ]0‡Ÿ:žÑ±)Ëäãm×IXŒ”ÇùŠ„½ùâ¡aôщ còk™'䨪jši ¾–kѰ[ü2-ÜiÏ2)OPed—-µBÛ|¤–vè{úÚv@ϱJð`…›XL‡í—ÛI%)À”Á:wc_Fyæ~²Ž]ŒñDÈÅA dèiPW—ýóœñ”g¢ ›yÒ†9Î ÷pyí‘NkpSÃI@÷k¸ ü·ƒ_Š»“ŸxÌ€¸Ž•Z#ðÞ:¿¢Û¡'ÛUÍmƒˆ¬ÆP{ó$¹Üž"O'ÉBzEó1Bòp~í5_©Um•¬lï<Ó}nx[N4¤/lt‡¬6Ö¦…I¯î ‘ø¿¥CûèK>qÒy‚³7§¥‰{¬Od$©x¶Aœ\fëšÃâìhÃͺˆ¦Íû6Ôä Tã·ŠvãjÄ|N%©Nø ßÒÓìçGb7©äî¥3ö(e HV  c³E™ã“aì¾ñäe-KZ€ì'!nË1þT~ %³Ya·ÍÛ½Û¿}~ö§³Ÿ7Œøäb^ ^™7Þ`ÅÓFÂS“™ñݯŸ=}öíæþ݇˳§Þȳ§ÿŠÿóõ÷¿?ϾÙüÓÙoŸmbSÓ¼´#•€v¦Ø¤•X)tJ;ƒCz1IÀ¤òfû“ÔF‚M©¼b˜Í¥÷•HΧHÒÉ¡#’˜rž¿Àp(ÂÐ NÌXÓ¦¥gøl?]yc?ˆ“£y°ÚÛÎÃPÚtxĦâî„ ®2UpuØÞ§¯ò8+^d é«]It•J}BJjÛX¢›SÞu¿{³!¨_0QÜGÒ(­ž— §ž”¹w{hîïs…rµ?:ÔNë e*€•(0¡Þb¥L0z ìm^[z‘õþbüS#!8ÜŽÝ£ø ÓIáÿãÜ)RsAÈpHÇùÂη‰äÚî„Ç>Uß×;¯ÏPÍÕ‹DÓŸn…Ua”‰9)ÜJc*Xšß%³#w;ïI ?ï[U§:d›ÚþþH>TÉÎ-=!ZÉ?º(oŠ´Ô—ï‹á©}ÊF÷IM>…AÜ*òŠ:ò††Oø8ÕFq†EšxÌÁ1,Âa÷†åsΛ£ Ë£ é€a!Ãù]qçÆ ´åúDËk‘NбxâHäë½IÁy[–TXôÛ q„NŸl¦âÄÌǸ·qWļ//šÊïÛ×Ñw[BÓn >³º®¢ñTr$$næj0G|±;ïòçã¯ÊÛâ³d+@wÂnÜ[âi W¹0Fí99AâaƒM™ÕmmŒ?3˜ìØxŒÃ“gY6Qþ\&p¢  駃ÍÒÁòƒ"ÊOvrƒOí´v éx@!þbú‡®¶¶ujÿE¹ûzÎSÏ÷ñƹç›1þÐ×+¯Ã‚5ܹ$ëÍ|毲ý¦¯íϵ*D¸ÿƒ@× zþ?·ËÀ ã"jyÄ?L²T9·Ý?¥qyÐ=.¹›ÿµÜ6‚ý^é%Tº¥èØ’—µÛg•*døÊWº¿£ðéð_Èá¿Í@$|·_hXãB>¿}ø©ðâÁ¡y”xÓatqaÚ‡¸)׸ÒûËcaäÑÆ³EêXžo Ø!ÑrÅ 7-‚ “cÓœ#ÒyÀ¬Jiõèx1=}GRŠ{ÒNµ§Œ”:ÜWþ…Œ î˜0ûŒàÅ^IíÍaëö-Ç7âý‚ÜŒöaæðÿê³ÑWðnF䊄îÚ‚¦þ6É3®5þïÉXúO¨ZLÕwý©M¹¤ùЦúC‡UVûR­FWÏ“6ÖÒ «¸ûºL€ÉÄÕ¯¦½ñÙã5þâ6Ryhò1’;|•/d˜À— Öa[túúXM~´ìWäf¿çs:«,vkKøx\[ï“â Dç×¹wcjÙ»YÅóÁ¥l<ù1Õû¸ˆÕ‚Ó—j¤F~ÞEÇm'¸‹g'ô–eNe£2â?ýF{‚Òendstream endobj 575 0 obj 6085 endobj 579 0 obj <> stream xœÝ\YsÇ‘ÞÐ#~ÅøigšF݇Þ$Q+Áa[´»~  ‚ÄC6‡ýƒ7³ºŽ¬£ç€@ÇÆ†BB«¦ººŽ¬/¿<ª~Y±‰¯þÿ>srúaØêÅ»¶úþ}qòË UVñÏó7«¯ÏC5¾ò“7¨ÕùõÉÜ_Y1YîýÊr61øåÍÉë§.'o•__l¶|2Fs³~>?*­Ö¯7fâZi¿¾*¿¿ß0h]kÁ×ï6[áô¤¹HoaÒÖ-V“—býl³Õ“sÞKlLx6Y³¾)mÝ•ß_tÎÒ\Âû–A1íË]ü”â´ôeõÕÔÀ«Rá-öENRhl¶©k¤[_oìd½°yŽ$üþ!Tõœk:„÷ЖQã<µUúM=/ Ü•ºªø{¢•ë¯6[˜+ÆœáëÿÜp˜LÎÔú›š4,µ_Ÿm¶j‚'-ñ1 ¦ûº”Þå¼-…oðÑ m$W0ðÖÏç¿?ZNäçüÄçÊñIÂrÏS,™'ÞC[ÖbKaa¥MË }UªÞæÂ‹2+s§´gný±Œú¦ú@|ëE\cX¬ÏòLšI°”ZÿZ&˜¬vê êe$TŬƒÙëméÖ³$ZY̱ßd Édvój¹pqài¹ÃM%:¤·}w¸…­&'h¦þoD^Qáˤ“dl4cÐÚâÂn…FZm¹˜÷|K ¢ëÂ*3Y›dÓ3À‚WtÛc_Ót«“ýMÆ…#PbÒÚ­ïK…mPøÚX¦y6[!Τ:,æÎ*á ‘9”(+J:p3œÂñ®èNÉ_¨å'Ux»‘^ãnýž¸ s¨eŠ,ÝU/)*„ߥ·eÿþ JaoxÃÊ.™ uËÄ\Ɖ1#›©É€J£æˆ`ºeT’c²š"ã"-ClES)dM;AE7ï?²®º+B‰ˆ½â†~( FV”ˆ_U†n'Ï %²ú:£Ì Þ“v’•Ìœ ´¿n¸›c•x“I¼©`hÿ¶‘,(Ö±2‹HΪ¾~h…6ÂË$ö;ä °øÂ‚$A) KÚ/2MÔËE»SZ‘ªÛ@JŒ]õÔî$­aµ,‘¹«(œlRŽSéD€óŠè̱*ÞÕ?vOÂü]­Ä:Xƒ°¥œ2#+¡&ë,G&P€1¾ÚJx¹XèªÂ®À¢)—Þâ@é`>¼å'³ × _çú¿Ûȹ¢¶Àëàƒ0‡èñy·l«Ú }’Òøõ†2ÀæÎ±PÒúõ·øÈ·áëßžŸüùä—•R Ý&GXQ·r :îVF„‡lô볓ӳ?®Þ¿ýpurú×?9ýÿóõÓoàÏÙ“Õ¿|{¶ Múí€Ò#íhü{D;Çq]ÏV *A>fš;s%å Ý,‡âcÐŽ»uvÒ’è…}…˜}ý~ˆnK’›ö"–·­ïP^az VzªôVÞÄä‘´Yó¤SZÔÍJg ò¹yÞéáÎ<7€òßÈòþýð}¢möM@ŽûÈqEöi„F‘á6‚îA;ª†î†RÍ‘7ˆŠæ;‘7<î€^o€‰E­¸¥¼3|Ö24c{ƒÁV;‚ïüÖUi ÐM $çñCNÂ#æòS1DX8@.hŒ0ý›¡2¼C½É¬™m滑¬âm92*аR„›^“õYhÍsÛkÃá–k·o$‰Æ ºé®3Ï v.ù½Q‘05‚|‰ô¤èí ÊqwìãØü¬!ù€†ª ?T›3‰ ¿ò“møËh’F‰Ð¿ÎU‰6þ8kÃbb5&ÞEa«ûØì£ðVì‹V5où€H»úv8-µ¾Nº*,-¬~ ÆZT¢z&>¡òKŽ0]'=•qǽ lo6A¼ªöÏmÙU0½Ü™I;¾`/F\äºvqkê˜Æ´ =»ôàcö"Ì{õçØC0‚>4 äqEò³ìø“B%ÛŠ…ÝŸPí=Šec=Ú- 4¥Ö­Åˆ=~ì3:ÎýÄá[Öá-ÇXße}v3oá‘ÙÅíÒ °U±5¶„Ù‚9^ò9qIgõ" ¤%(³ý‘*îZz—P#¤ÒËóð™1é¿íš5•]ØÄÇbŠ?Ko‡ðZÜ8op^Âÿ,8ÃòÄØõоýÈáw噘dsld0‹ 8ÿ¤Œ[y9)YƒÎWí‘wóõ‘Nîð=)~šùÍ_[—°cÎÊdüw=Ô­<|/P룱S{ž){÷|’ðÅ8‘Zúy"!ÐóDÎÏ É95Ø öâ'EoüŽ‹Ý~&Ícéi€²-7|4ŒÃ”Pƒ³eg¢M@ÜYPehƒ*B„¡ˆ[»æ¹Ò€x0·RZ½0­HΔ®õ+&'øÊ#z(£"VÔŽXD“²•$h$MGÁa £ ØÓ“p_BÁ0ñŒ?å²ÈÊŽ Àm8á9û ªÜ8èNÅ,Ÿ\òJJJÐöª3).éP¹kººw,“Iv?Th¤±C4E 4žpŽZ¥ut‡ÂiÝÕ 1£d´‹É cM4iŒŸœT½ÆÀÏX’ ú·Ù©^¨Èm»Ý’ÿ2ô¯&(‘—¢ÃbŸ¹q·vf²÷xéÙÄŸýµzü;ùÒAöF|òˆù¦ ”–òH× S¨Ý—É™kG¾Ø’tÈšÈ.ömóh)6púY³Û4?Æzº4 -³Ó2(ìCAWÅ1óPoKn´uÈK€6Ág¼bâ üÕLV€¿þ{ù™¨’¸ÆJQ—ÖØºˆн‹<¿¡ x~²:‡¢·Ã3!˜ì?ªàe¿ Œ´ýžýñ˜ÊÃ0MLV»É ³ST¬íÞÂR÷¶ÈìYãè‹NòýÓºì…aÔ»‹®ÆÙè»rY¦û¸øxR?m’ i- ‘ÝDz ÇÆ@ê9ˆb1®ºª¨ /‡mõ[¤1š tüÔï´ÎžÚ#-Î@7!RQnžçßL*ru%üwï±üÛi*Ê+èJG†–'²„§vxÐô‚.°3…rTËŽÍ ¢Cöæï ’1bÖwZ¦Í/8RËpàèZÿ-YÉõLïcê3þ%!ÿJÅà°„]P‹*&"ôø­÷9øârRÁÐOü~±ãT30ùÁ…o–* ï´Ôý5G8ÆžžÓ¹Y?§Üv“Å"oU*a+À4±N=ŽVŠ#ÿ Z Ó'¤]ÐJ¥ÝýÁ5¾ž¸˜µ{¢d&áˆ}eÛí¼VÙ ›×s¶QŸ_B³„ª¯øàK“RÿßßWåÃשì"¿ñ.½ú.wúÿŒÂ«•›U+2¯‘¡På¶R‚M"®Ó'&„l/­T1£-Ù{Q’Tiܱ+Œ²¤§«˜¤±\xP>jÍIn.Á2`1Îòì¬2nØÌ+ô 25Ûé©ÑØ Òb>L*ÜѤŽ4I~~›:‰0`@œLJ§¿ðãšyÝ G‹ Ø à°i( êCÓ¡ «SQû#ôvÈC„‚o`®ØNÎ?ÿqýWXWåa®“˪ g†'6CÇFšmBaI„ÎÔÉbûB¾M^™Ð“¬ëæ¾ÚÝPÖÆá”õ ™y ’üâV xÞ%^§ü+%'gd­g¨tÁTÄg®ìÆÉ¥lWÞ@ŽD]ËǤ<½.ΜíR!9¨Šv…æ«Ô½qì˜57tøÞ G׋O_æŸU5Ò8 R°ú1+˜Ï›'ìûÏ —e¬X n!Ÿ¾Ì¿ê¿–w.zã§u£Fú®è)üõ}.ûŸ„Ú—¹è*=¯M,üí2åJEùù˾„ÎYØsÀúÏ{Ë-}“žfËíIÝ~Ñ©ô“Ïwüv5¹L“eŸçúŸ§¢ŸãÃAö—T ãT1꟣]µ•’ÔJ² qD8@=à*ì Ä6*ÆÕ³!¦ÃªÉ[f¡ÊC/¥E‘ÀÜoÆÙš‡~%G¼COÈ–üû`¦â6m¶?Ù²i8²B ‚šc(H¯i³0iâ3$¬-¹”䪼A).)”™>³ý¥Ž-Éû ŽÓiH)ªkÀ@'/]Çn Õ©\b¹4.ó”¨=5‚Æ†ÉØî¨?²Qrr§éåq!¯MûÛ>)‹Îˆä?—­hJp4[jR˜)Ø­×±ji£šÊp;­( F[“D÷qÑœ xRyn’$n £ßëL¹h™Fô H&0nT6kÿN:â…©¯®Ú÷ý,%&ñø¬Æí8€ L'Þ˜n´vÊs]$ ñ\ÔƒD¿@rjm^"Ž¡:ÑMLÌïöõúUN¬ÙACÒhɧÈ^ yù¹ )E(q¯GØ2g†BûC8±!ÏxØÓú[JÞÜíf¾šOq3Žý6Èæ W¬ #“ ¨Ùö|ÚÌ“½Hq¡F\TIÞ RÕr¼=ì¾þG^5(†TÝñ)µ®n¨ðÏüZ<{–;G°cÌ& /¦/›Ã”ÒT‘fgkA>²½¼£'ËåÙkòs±æÚ€{ w²À¤D{i‘M R•b)m>åÎ~ÌNš}º¦XÜH#ÚÉÜëª>ÎþŹ‡Ï–”¢'ø)ØE0-4¾×Bî½q&Ý8·fÉh…pÀ·®³R…ëaiw¦¡Í¹Œ Ö¹;ÙYœäªVgóÜVS÷ªÄ; ç÷˜ÖŒj3]ê f&U滥©¸áRí)…/lbÚÔš%ÄLf¸ 2kõ‚ó¿ÐLâò¨™ÅÜ–¦™ã©W =/¸uÕêœäòTÓ¤ ö>îøpnᬜxÒ%£IyÎ/d] !½>«‰3ghÉKW ˜jäZ åÚÉgTp ‡³g~·› KKÖ2Ù0ˆÈû$§a«÷u]/&¦xÌÆÄT$JcÊWúB j‰R¢røiÚÒ‚´ãÎ3|Rª¢—MZPtÊPž1NÁ!}lä`=ÎO jŒ@ã“…dÆ’ßÊ/8~b\LJrض ›íöF‘^†8·&1ÙéíIy„”%»ÛM^ªÊOizŒéÂ#“z _˳<öt¨IÕ¦ê¾Ó`ƒÃNéqB6¥&ü*I ¹Mi3î S0¥VŒ‰`g«G&Œ»>œ%Ç'„#S—/›ü8žœèþ)75 ÅCÐ%dòv8Ãù´h£u)1xʵÜ,‰1ÕH霫ƒqõ§Á;œèx8TÝQì’[§æî£Iœ1Ä…C×½¹ü Ð¡r ÉýcÚ™iÅÊÊÀ'—™&‡W&4Nó"ÉÂz:÷Jõû"§s¢ØËEäæ`Ò€ñ1–ÁŒ# FÑ>ÏèQ¦…7^¶y^ˆCªÃõ–9vZ"|˜ˆá„™Á1rfã­ÀØïÖè¬êõqšiœ‘ñ¢´6ÒCÌŸ Ÿ!%û¿€B<~c«qnv‰H½@ŸÁ{™gl @uFÂ@¸Áø9³Ñ´„5Ü\³l\× À2 €çø‡‚ ƒ[NŒ&{ìÙñ ¤’S1N/}^ÁFï:›KÝ/ºãÊHµ=ÙÒöÁ¼"&9>„Wp«ŠÒ“xˆÍ8’ökóvÏ)¬aâ8Z±|ȼ»¢N'ØrNõla©Y¶ŽÉ&%›àû¸absÄÿE‰ÔãÄJô H<\v,åCjAä_o`©°¡p2³ ó¿Ás.eÚÓ4KÀ…;CR‹W³ÁœÛoJFÀ]ûÆò?£‰ éçêÏ_'_,É q¸0åÃÆ‡ 9Ä¿±Œ —ò^qG7ç $ž¬áƒ‚y¾kìt¥ÌûÖå,•Âc¨åVïFUÖuií¢4QP©|m¼!\›¬Íd~ÉPóåpÚÍ~\éµ\¯GWJÔtžW¢[ï㨥> .Bexgú,ϱ²- _‰ú#nQ Òîû »DóöüGÁ¼Y¦i+:r@o¹p·éðG ¾%ÇœÃ.Z|9´'k$e-«¸˜WYý^g Tɲ$+åêˆúãé{¼?½qñœ©0ß´QQŒš7̳£[ÃD: ÛÄ(s²_Û»>B|¼öX¤ª"º •ëG–O…`#Çjû¢k¶‹i £å4 Gq}æ<]\Ñ&Dâ[ ÐaÑ?W±öÚÌJ“ÌÑÇj™ŽËp‘^i(v›­*«Þda€=y…!ô$%ø]”=ªéz«Ms¹, |CŽKÎﱋx1 :x÷x8=õÔ´ñFâ˜N¾Ü_¹Eø€+#QoÙ?vPʘ‘ ÍöñÀ¤Fêœ\xÿ¾]ˆKsRI-©x¶äÑMÛÞHkkðž 8CÎÃkŠÜ0L˜È‹@Ý"¦FwåE[¡>倄Ûò*2? v/½¹‘Ó.YöDD§c§>ÙÍñ[ [ÞyÞ´VSG)QÒ#ÕDa5ØX¤¢·â¸#½ÅË6y¼g|ÜŒs9Ú”ã3«ÏòÕ‹"‹çSoüíéM¥æôy;é|ë\C†C†½~T2ŒôLã*ò1›fVÐã:ñ%ɳî熖nqçoüû¯ Tn>º ˆécÝ;t¢Ô.ûÄPï÷àé’£(¾„ÜΨI2=ßT¶G}áY˜ @íDoS+• élÃL‘Ê9€®BÞ$ ÒLŠYÜ<½L1/ª¡¡áÂÜ©4R^é³Zó$r:ò³-Ó?|I?ü†áOÀD÷_É‹f ˆ#_ ,dÊÒìŽpÈÉ:ÖÇŒ¬¯ýgÜ#Î7–ÂÀ‹±tCRbÑÆ@8 YNBIJd7é ã 9&ÖE_Ùü üóÊ—ltÌbkùœ¾ƒ¿ÇsÒ½¾¸g­íÕs³‚¨ÎB‘i%ß-0Òûâbªf2~ý7R4[å)4ÇÄbHtè†oOm7‰juvZâW¤/ÃÜûö%¯vÄM:ê ~-)ÁÓãøvÂO!\J§ˆÇÇ»#¨5ú siÇ}:>ÓLZ.dø$§Êž•Z¥°;ñ¥ÂÝ[©ÉwU“ñlÁŽƒjÖv=Ë™úáàXúmªSê«TÿÛTt}H®<&z³š/áùL×Ðd wAýùä1©‡#endstream endobj 580 0 obj 5565 endobj 586 0 obj <> stream xœÕ\[s\ÇqN9oxÉ_ØT¥*»)íá™ûŒß$K¶™(‘%±Jv@€ i‚H‚Rø?üƒÓ=מÛî¦Sq¹dnœ3×¾|ýuϼ۬ Û¬ø¿øïÅÛ³'?p½n^~8[7¿ƒÿ^ž½;cþ•Müçâíæ«gøš‘Ƨß<»: °áÃÖe•›goÏþ¸e»=[¬QÌm—Ý~]œ0Bnåì©sjQNnƒOͺJÅ·¯v_àr{>“Únoò×á¡Ðzûz·˪V§ê¿sÅËØöKÒêµW:'¶/v|jUÛ÷øC:i·÷ð‘t 3jûÝn/Ç¥fáïøâen½þ~ü÷³÷kÈ6nqšk‰‹Ã%üÍÙͳoÏžý۷ϰoî”p0¹½Z¬ À>ù¢4¶Oݪ°˜žÖ~^íÌb7.,„ÖŠéíÇÒÀõVRÃ~0?~€Uýe»$Ì„|õ ûÒКEË_ÝàRÙÅr_ÁRiç´PtŒäå‹ÒÚ«ÒÚ; ÁV‰¥¯nËÏ÷¸š a‘˜%×]˜8c*þ´ÖÄy‰Õ0Ú\-ìöCØ-¡]|Á¿{_ÞM/€dÅ0%ÒÒÕ=ÄfŒ¿f\Ŷü ·i‘4âyÌEiàÍNƒ­ªj•4E:x¤Lim¡ qimèÔ³KУ¼a.-,ôz[V+m8ß>ÏNedö?\b²*·ùáðÏdχ“Â^™]¤å °M«¾×÷8, #é²á½Æ1²ºÎÔÂP?X)ÆéÏÚ½@>#=1;S%V¹à$£[©£vøW³ëív L„U·¥)ÜyÍ ߇µUnµQ }S×A  „쓈ìBB)µ *‘F%šæuò®X›ëva$wšJï%Ê™\ŒTÛ_eU'âF¸jC×ø ÜPìMЧµéKãº)¶dúnšÎ×ÄHÃr[ÍÌVò÷ÎbözŸæ€—b±º’ðWTÃÒG7EAg¯¦a'7d5›Œ€,hVlóPÓO®•–ÞË&‡ËdXò†J²¡DüÉç¤+"'Ÿv ¼s,¯ê·A?„RT«^ƾÀý>Î Ÿ—¨ð¡szzeVÉùÄ—\–wAßùâ$Brê|žÜXÃЩ{÷8g/ÀÊ3çÂzhãD$xÈ­Îä½Û§œ1áýÞ‰ð¢2Ÿ ?°ÇS0 a_½ý_~H=Ýw;XJ©•CcÄa«M}ƒ?™vÆ÷þͳ³ïÏÞm¤„åÓŸÁšÙ•lYí´,EÐ÷ÕÓ³'Oÿssÿþ㋳'?mØÙ“ßãÿ}õ‡ßÀ?O¿ÞüÃÙ7O7¾)øÜ·#¬¥-äëµ4•5nJ Ò­ +o#¨ô ¬/§ºN<(1'cK?~Íþä–JTlo[Eß-æ¤üª?JãB†Åb qÄæžÓn“¹Á8ãýÇ æŠ»Õ«D׆Z…ÊnQ€ª¯ˆ‡*_ùQ) £&]ÁÌpU8ÇÏK¶@ Ö˜9¤Á…[-Y"âmow3tú úeæÙÇ`áÀ"iÉ’‰#–M”ãË** sƒ €.3po´ÍÅx“wɺ½J’¡'«Y†ÖP + »ÖB¦¦ð{ÒÔÍð…W­6Œ[j½_ÖàÄX˜ïk~Ç(“ ŒSg]øQ¦…,¥ƒTâ~ìFj.Ú²Û;Z¹ìPA#W$ôïÂD…F¿VÁèB8ˆ~˜¤ 7†‡Aœ¬ô2 ,Øtï¾$£‡dµ!¸ÇÏÀ$;vH{±‹° ŬÑ0pQãyaAL=Šç†L°ÌÂ8£«;(›Qi ÝÓSŒ†)b]¥é°ŠýÀ:Œ—Åü~Ðdî,)28dþ°ýmî³Ä+ïq}ÀÁ‚>_ý@ˆˆÊëÆÄW»È¥|ïg_…k +¾Øy*/Þ uèÅÐTf¥­í¶ ¶<ÅE24kE®FsÀ8Ä"ZMõºXE|õŠM_½ßß(ã/i’â/ø曞½ÈÏÞçg÷ù×>ÿõyóþºÊ½ÍÏÞZ.#¸ŒåC~– ÉœJ˜uÕL븣¸ÿ¹L P‘ˆxS)CÁ[¸G±}äšá@å”ÃÿfèÍðÅ >Vðcí Ü‹ô* Rþé ‘bo_½k8/TØuâ·å¡z4Ö¼WÕ !(â8D݇¿­›!Ý#¶Û…81#¬×Ñîè:ª°×Œ!¬x)¾´)\eˆ1%/<Ÿ[.ÖEe¥¥·j¨3; ‘ݾÙa <4Í—‘þ’K'Ë_0.Ø=Ó˜n~[÷`£ö|SØúŠM»8`ýÓzöšž·žSÛ^›qß™šQ\žZÔÄgF8¶%!v%ª·Èm‚IðküO5ñ¯|£`“¤Ûy´¨çÙ¢þ]Ûy§ÐÆÓÉvº–£àéÍá ÿˆhÄþAña‘XäSOòãìwÔ³û¡© ‚)˜žÐ2W;æ‹aÊUÇ…®P_b¦é‘Øuõè¾7ÕÂzÆYsòðª<<ß…eFéWXÖ/Jf°zÞ6Plso¼Ž©¥— ?÷ ¿UNŠ®B­9ž _jâ: vîÊçÚ¢ñŒE”ØÛ/*{»Oû™VU¬ŒŒá)¡Ú ÓÎ en¨-Ô®ÍWKžŸo3g?ŽWYSÍ JÓ´†w,ðgV¢a°3®ÊSÔxøC2éÑ‹ô£ÍìÁ£}úÑæ")?öMt~®ǿݤG é€¯¤6"÷s8܇Yêj®‡+=Ð¥:G¸ ™WvuÈü~o†G¿$.A{ô  ƒUzôKh•yi  žò2 %üØEçåÝ Gm,Éz³CVØy$œz; ’'ð<u7NÓÞù³YÖ`1(þr>ÔFÆÂyÚ tO๋üìû[£Uyv[Æs“ZŸì'DNv•²–Ž o SVì//ÆmëRîbP·µ&C˜HpêÇãà1ø =Î3É¿r[¶_ï„Z¤ÂåW «Ü~OÊ$SÂB»=s'@dLÅåŽ#§ ’«XuV‚Œü]k©»p39Óq`;1c=ï˜o'Ê8CžÖÇ"°æìÙUftlftê45®Ÿ°éÇO–åVl£¸CÂKB6 ¼\9 $ê3sò±Ng¦Ü §OŸ7° =ôEPf_/5žB˜žÞæù‰gX›0%•‡i 9Aöã €V’´cÅV;N”˜†Ö¶Ä̉w÷øœ¹°1Tl0èË«T\k¦z×¹faý~Š ÄÇu…ãcŸ/†6;QðœnáUÜ ¡ûhì%Q÷pb™[7 á§ê$ˆt$GÖ„°bdâ1麠»©ÈÃèBÏèí£±§#­±ö4#ˆA;×§e ùÁxFz"¤ËÜz $uÉf†½>8ští] %¼qêì2ùù L“šª`—à‹®F%}Öèx+>yj;c 6•iý Sèù{LƒûeR$÷u¦²‰)Ox"j˜l‡òÓè+w|ëÎ(ˆÝVÞ³'óš’ºvÈ_M(zR»1óòjõï},à…`ÿÔX/Úàr(¿K0 á!:yŸê'N!R³•Š…YûÆœqtŸNIY¥äþ™ çã«:X½ˆV8ýFÊ¥ï Å‘³7oqXÖ;®C¨Ã›’òB¬à”*k;)´'7QŒóeD›ßÄBú÷žalþúŠûÞ[ÖG1O€©)Dê°Ý¦>@ “•FÜù“Á©îÓùs(Ğ̟“·?';f}2z íˆÏÄ8LùsFKéÓÏC€'Œi$l°Õ(1ɬ3«=?6&»GLºuˆ™@Ijχ³lf(¦€3¥6PЂ•Hx\h Ý3cü¹Æ!ÃÛŸŠŽy#æì¢Á1ý¥<üu}ÁÀû £«ó Ìú{u¶?ì°*W3GÛ³á¡JL»¶J,® dCE¹4ûÙí»q³¤"»lÉ_Êèh^ùºC65…¹_†ÕKö€ŸÃeÃˌȲýŽŒ{LGÈé‡k .’˸žøk DÖÓd)K@Þ¯§­§3a=½Ï«ÖsDq§uT,­£÷Ë¡ÿ"­Ñ$z}ßÂ>nYöU±XAÚ9öÎú…5LEy®‰Ô´Æ8|™„ARKhúô¦s älÖ<ƒwY9(P„e=P;8››Jûx4Ú·IÉ›r"~\QGn‰$¹uÚ!›ù±bRlN!ÃB¨£Qj›C #%¤ùÄ0)#s‰ôE©Ÿºº£.8ĹêT›>«Îð5»€QÈUÿºðë¸íBVqC…9Çz8‹CË…Eé× jß:ºŸ’nûÕy¥«ãÐ7óà¨l½ÿ.¥ÛàÕø mH`è¿ò6Sºp¾!ž9è+:°·Ý·VØyºW=ð2´˜ ˜°tõýX‰â¦ÈÇôᔡâ>Ùôhú¹Ë@ECÜ€!ñ,Ã+òŽ’x„´ŸfòýÍf\8G79$Û5VP'32/‹Ìa1ãK“îO@ÎU¶‡Ó|ºÄa->T¥©òЦ€FÓRÅÌžH‰ð.% ¼e ƒû{rMÁ&¼!]Åòm©ÇÿÁ;yé¯]äÖyW6%ù*:=î[† j!`­âmß!§€ß¹ÉÁðd½Ô Ø·EÕ1Ž44QIÁ§_[L|V<‡rGŸÎ\ûBDœ!!Iæ­ZÈô@=%ÃÚÏú|d=:wšn“ó·ÚÌÎÆ}VÏŒ 9!ðÊÑäpà§Þ­À„È™éã©D¬É’Žƒ¨‚ÆÈ”ÇÞ±2Î0„ókƒ?Õ¡ÓÖÙßdR‘áþ8®òðW0û³NôçTmT¶ñçSuÌâŽÛ_gªÇ)…18ÃÔrEÄñýÏ.ßüW”dŒ†)+¢’Mß§ÚyG[º­úOwéQs>»\…•Å&1ùuVÇ£¥4H5Ù „È‹ 4È¿ìöz”CjWòáY´þÔJ9KsKªdöZp膓ò˜ÿ-KmÇ¡¶Á?i^E!…ËfèÙ0@Aã_¯šSþ¡¦Ûÿ¯é\ÿ5Ói+}+K•> Ëfü“Æ|¦]¦—<3°†ºäY Ÿ²ñ%ϱাÚùW£Kž?æ‡åºæóòõ=øD£1ãøºÜðnä>§A†ß!9-Àá+b5Yx5ÈÈ¥ÞÑÐN‘7k<‘Äj~ !ó¾{R{¥œ?4cæ§ ÞúÏCCo|†Àc]ƒKO¬3§ç@)L¬)b`!VÝù ûÿ©éÁg.ÝqmâœdÊ=ŒÚ¤À§® õ*äúݺ¢7\Ê(ÇLãð0ïI™º€©šT/Ö îfh"jì¯ Î]pκºu1…”•æÀs´T=”O(9*'j’XÛá9&½OˆíÛ\ãòKEÃ9e*p—ÏgÀ[Í”'Õ·Wè/ Gq’JøGgõ=ÿP_\ÐTÀô½v8ΠláË‘™ܳ¬çóÁ±XÖ?³XL°lbrô´?-àhFü²˜ö–OFYû Ò¼Ew‡Í¥‡M]¿žᩉÚwUˆ±‚ÏK¨©kõŠ6þº*àáÜz3È_ètø¾0C¢­‡žßŸý/žMpendstream endobj 587 0 obj 5626 endobj 591 0 obj <> stream xœí\[o·Ú7ýŠô!GEΆ×%™&R´(ZÒꥈƒÀ¶$[ˆ,ɶäTAG~ogxrgŽoA ÁÐz¹$‡sùæBR/7b’?ù÷ÓGŸýSÍbóìõ‘Øüþ=;zy$ã'›üëé‹ÍOà3;›M˜Â¬à÷Éù‘˜¼MŸm‚š”r㤘4¾8úv;›ÉkkÍö³úô:>ÁÛ«ød¼Ü^×w¯ê»ÛãݬŒ¯¶•·ßüíH™ÍNªÍÉ)Lðmý|W‡ØÕw§õéqm} ÃJ?ͳÞ~Aæ*Í÷õÝM}:«­_Õwß­Q'åä]p›“¿üþÝì{àÓ‹ÚzÍô=ZŒ›„VdIuÙ³¤²"çâ‚Ô‡]Ëim½¨ï^å©  ÿayúª¶º•é ÿp$¿©­÷“ÌÈ‘L4f‡ ­ôäÑz¢V?­Ær]Ÿ®jçó:àE}÷¬ñ`ÿ¢>‡…™LPï£þEÑ#ÅI9>"ÍߨŸçõ;hQ¯é¿Èbö+ »˜õ«hÿ/²ŒC¦,h~/”Š@wš÷E]Ûm}º¯=y=®«üœ0¼4™lÄR#xÊpþ&»«·ÿÍ]Hë9CÂãa<|ú!CV¦n›èa\ĤµËlæ»{ðªR¢ %&„,jhn’~™éž~xÑÆyëÏË«YŸÑ„óbPFä /ê…óŠéÜ܆nÈ?j<>]ÖÖâFa{È+…õµ¡_—Wõ¡ ÷¦I³xSŽWÃüuŒ®íŒ²´+_ßÔ§f§’føUfb«S @Áæ' ¿n™I¸¾÷œ¹7ði]^4Žõ@¯¾,#VyÀÃem»[˜.–“1$ÈFÃiQC•— ­×Y’^mÿTÞ}]{|ó€œÖ§ †‡ jDl¾­ïž7ÿþ#yÙt|é6ЦEÆ!K½lËo­ùÕeº†×dŠjž]a^,ûh׉ù¬ŒÛäÖ:~2ÊÅé¤y‹ÌI‹S““!l¬´5i99ÞéI ÆÜ´àkBÐ8©Hpö:Öv2VX “U RX`¢ÊLd­’h¥ÿM7”Ä?Ånfí`g¦ ,$&×íÛÓôè]ée匽¤[B:0à„Bƒ6ÔöW8$t4­ÒBÚŸ´ñ/ÛÌ"”nHìU줴H– @.ˆ¶Q˜&Ó¸˜L´ÝjŸ¶ÇÛöíu€ôÎ)'ð5e !æ>Sàër´‘´m=ÙYÌ.s>’½¤eÖž2é7Çr Z‚hÏZ;YìÙq @R¼ŠÑ:Y6YÕóQp8),Py9i©@p Ûgú}X**!„„—×m„WùQ¸Â6'•eˆ,ž-ÕÂŒ«Žq…±d6\NГ6nèÙå5…çì`D dÜ<ñ,,ÀJä˜r6ÉXo¹NÀæ³¶´ <‹ýûX –­è¨wõ1e]³Ùìjƒ²,üªèš‰ÑäNYʰGÀO›éVÞ­˜±20³õÔ"_£,4€J`Ô?¸:ž'©˜cæÉ9ó‘ŒiѤê{:ÅAvÈeü ºPA.&#$Å| æhTÁ'brØ‹PpÊÁiãg"ñn5©þ¦¹ÿ 7çcv©¼e=ËÓûuôÿ2¥˜‰ ¨·Cy–)µÛÏàKàKÌ=kÍ`?ÚˆI}ÉÃ™à‹‡3Ñ_«Ù‚­1.öïq6-5£ÎÈ¡Ê_Ÿ™>vKð@¹€ïhìo ß8—ê(hkÈ5j­+ Î8eƒÁLs´E^]7¸jŸ TÐ4@Ë0 «– Y‚„’\-M˜çø¥´·K{-àJá‚aX›§m–yUúÏ«*Z¼Ö¡^ipæm1§Íy\>d:Ĉÿ$èyRÞS BÎH7iÞÍ"î8pÊ àD$Ù«)ȯӬ©{©þ68¹ì¢&j9£ˆz‰© Æ“ÊO’S«Ã|ï>YqD'¬C#ðe3®ìM}"öšx ùw÷HF]âxqÞba`uåùÓdð ÀjîûL,Zöy&B@€I6€c,³‰˜?(c9˜R‰8à_Û÷ç%Hbè¡ILw@  œŸ\Ï\x€ÉçÎèÉ·ØmžÓŒ8|3!@i0¾•ú6uáÅLØGÞ’å^R‡Ð'c’á '›Ý5óB7ãÃäf ìø"„Ÿ%µ¬K:.| ê®U–P‚)@F6ö‘{åA$M{i¤BTÉ©¢#OeL>¶ È`V(°ªÌ:=@¸‹9W ]´'K)©™ôŒ(¼5D]tŸY1ÀsÕ ¯ zÆ9ÙˆL¬@j×xLˆYŠsY$d«5 ?d#åm“ÉfT¯›‰ERS¯ž‘Á–]Ž*ÊÄd=C޲ˆa‹ôcõ²Ï©OB) P‘% sSðD,Öµ[ <$Äèò^%b{R “ØÃ©iú@ ¤×‰ÙÌ~ m:˜ öÄ@j‹kШ¥ oY1AŸãRÀ µ“–Riëz*¦Ta£  µœPu³ß¼š_¾8VX`r*»<Ýó |Š5&Bá×Ä.))eІnÈ> RѸ§™24°‚(X’‚Yƒ´ëEœ()ÏÏ4+í¤×KVÛ—Bé ®íá3*À@ ájˆ!dˆâ¤Žœ'€ŒO> ¨Ð–MR÷5[ë’êZ7–1jžÈ üÌseüRþQYkèÆëÄcêfR5D„Áiª9ùóö_5ãã£æVG+CZ`赺UR5JwàHìfáhÆXš¶qÝó<ÁxB„ÒäwÑù¬–̙䂚ži²_8¤£ ÇIS•©ÖùГéX}d¹j…3ÝI¹‡  î4WHþM´ÊÛjµ,“ÌÚz3Ä庇˕¸›ïºmÖÿþaªË¥"ì=qAg¬“#oŸ¶<ý–-’Ÿv&©ºå-/JÖ@M¬²vŽ˜Ø÷M+Ù“êüz!3ó|c.aY0igkwLZ|À|­†úþn©ÖˆEªú3µ22Ѱž Ó@ü»PŒ¾>ßÂ㋎ Ë_)Éë¡ÐT!Hj‹,µã6×r)>O»ke·w3Ûõ9=ª=¸_õAO¶s|í$Èx¸)y)­­GÛtn{ö¯‡³øô-Ù©/ï9ƒ(”Wß‘k<:ð+Xÿ)³þ6ɸÖ~äq­åp³“v6O g£g;ÆÓ˜õ@w覸%|pÏ#ü ÚóÇpPu;aOh¸nq×®3u%æðy³ºµ­¾•ÈBú0I7óiõ2Bšð<‡ÖŠIOêb·œýÐ{ç8­1¿ø^¡±`±V„ä.Ö¸Ööº<Ï(£9—¸ƒMZÌK೫ÐsAà ³íQk~ S8RTX,sÈŸ1‘6&i„M÷\ü=Ô  íwÔßÙäw¹QŸSf% ˜v»ZÙŠ+”jÅ•“DZ‰')ƒ÷’VnnWåqªî¨=ÏB÷;1$z"aPvb`9uücŒ+xü(TH1Ó½„¥ý2’94«Æ^)ieÆPÅöm€Ož"¼‚ „¯ü ¾þzЂ`âþüpDBØ®÷àNéöÐ&1å)o„e"GJ%ƒèÀg¹×œåɵܬ´uZÛœKÅþx+&c- ® ~Ž¥çlæÝç2̱ŒÈV&GË~€‚à'ð2ïXäÃÈ.ÿ’ @Ä‹†2×YY옳‹kæ÷£€ ø&ZýöÇc0K­ûÃW-² È1õÀi íuÚAW™€¿¬Ã˜÷QÜá¾1’w'“ºÔÒIK.–0Ù#É¢ +'lecé<Ë ¸“ª¨Ñ“X„(ø™ VÚß¶B!ù´_N<ëÕH=„OûV&\BÍ\ûì •Òõ¬>žþǨJÁûœ´Hƒ¾¼ ÌÇ?rÇí<ÖjýöѶ!SCã½õrzÖdÏiÇÒN8Ïè¿IG`øvT“QÌ÷¹è ÜàJqßdž@»ÝPY×ÄÈщ²]­Ü@Y: ¤³ªÑÀa„=º¶¨¸°U”O‡:lRš]½]€ºsßÀ†×]‰ä-=EêRSm œóØ^Ò–TmpCÞ«0ÏýÃv‹Ä:ü CéNô|,Ñ“K¥¬È®,Ïר¾dCN®fXˆáÕ˜„î¥âêf>ÖXèÕzñ¶•V¶Ž«*äÄ×™ H4X¬¤œÔêu‰«òw8&älÐN›­eߪã]6Æ7À7x©ð DžVd­ôë\µ•Í»8ÆYT nšvOEôà&ã‘ÃÛ¸+ö»òɵÓîev±Œ/×*óÙNÕb?)õ¯9åóûó¸ËPNä5…[å-ŽL› ñxC¿ÝTW­hÈyG"Mïw5?ëw«³¯îзÜp_õ¾°’ §{ ëÇO3)$'#çŒó8Ý{\âŸÝ¢NèHùß{s‰›Š74¾PÏo¾•PÀt,’‘²‡¥zŒ¨Û†ÄLåøø”DµÕó˜—Wï"Êð‡6©Ÿe%à€“+õÇãdj%j]”=ƪ&¿Ë³tk\»Zw¦[†[9í^ÚM ¿\x„º‡å„åó_þXü¨¾F¼ÔZ>=´À­„ûHÕí‹ve‹+=·«_o˜¢n»:^Ã+—£ûëÞœúWõííxasßõ`óш|¨€^®ð|oø¡ù2ø¾;så&«Ðïu}5®%´) æÜv¼Áë\ãbàB1“Hl¸Ûú±µÝ¡³å¨õûFÅyÏòÅmÉÈ"É…±u—ćAØ«¹í°H à™oU–+YÕ•`xWBþn¯„\,9×|è¾Ü3 ˜çÕ?Ü·¡Ö7@²a<C–æ¥!cöÛº)`wuêòŠâÇÈBHÒJ‚Œ›D³óÚa"ºÁ€™EX=6Í;þ·w`ãÝû÷}~•–:\4/>*›Ò“ÒÚþÃyoIÙT{þ¾ßÎÜ~Zö.ÀÃÃïj[%á¾<´ýè³6Í´ÂÌ moeºn†L@äÝÑÃÎeå“ÌÊG4Ä¥… {ÄBøT-ý£)á5‹å„…Ýw‰©–k—œº¤ŒÔ›SéìŽ^²6¹z:”î¤æ³“lqŸPõfwÞv›lÒ•ãs/tŒœ žÙ윘´:…è²Nfêºðã?Ÿ}?ÿ’/Úendstream endobj 592 0 obj 4181 endobj 596 0 obj <> stream xœÅ[Yo\·ú¨_1@z'ÍÐÜ—,F“&)Ò6A襰ƒ@ÖHŽkY–cË­üøò’<‡¼ÍÈ­\‚ˆs¹žå; ©—+ÎÄŠÇŸü÷ôùѽ¥å«'¯Žøê/ðûäèå‘H]VùÏéó՗DZ›Ó+!X0F®ŽÏæ ÄÊÉ•œq½:~~ôpë`Þ&¶Þp”Sz2CªZoB0Ì=}©ŽsmäôMì,¡·›~X[Ï‚w±ƒÌp®¦?“®[o4 R[1}½ÖÌH£ÜtœZZ™ŸŽÿšŽ'V+­Žû–š)üêøïGÇ=œNâbÖa§ó8™4Á†éj½1Ìûíp:7µÑÓ³µe†0áç×딎ùàòTv{3]b3Ϥ ùz ì°Z;=MM௘^,†y7½Š »¾Z+f€qšz>sÃXE©Ø$gùæÒ† SvP–•Æ3/¥þ‚›9‹Ã$3:ÐÕÎð8„:Ÿ!aâj‰µÜOoã!$³Þо'8ûªG'+la¥™)à÷ÌP«|7Uê*ÃôÕZ¦uð I&DýÓƒxZÅâ Çká™ä(09vÍ‚ ëÇ[Ðo”Fä•¶Ì%% PÞ…éßdtäŸâNÐÍÏŒ°‘í8Ó nþ"ëWYni"ÍÇC¦’:Vçã“¢-)0*Ò÷ gx‰K\c“Ì0¶Å¾ŸÔ¾³ 0=b‚œy“Ñ#H°t.V´ŽûBدWä{¯¶^¥Ll‹-í£²Ú¯•6h•„ùå´©ÄMí¸­´“Ú‚ãZ¾õ„v^G\ FœÖ¯Ï*íl±¥òÂÎó6–k¦½œ>+´m7Ho°»–sØé~ùy«AWŒ« ³ŒLJúpptdGÏ„øõe7"¶ÞÔ¯xt½…597 ‰…x];žw¬ûžÇfÒÏ¥ñª~{ZHï–ãj÷ç¥K^H•­¿¯ß¾+¤/‘uP|´š~Ê´ÈD!‹7ø Œë;öÌ„Í>©$º×…?C?Ìœae¹ev6¤oÑ¡¸—¢r°*âe®3Vh3ýk ʤ”3Ô_çýœ@ ˜Þu$8,·p~i~å–.7v]z\…~2vM×q#v¸\‚O—u+-±,@<â¢C¯âå¬^ú³ØÛ¦kÙìÇñˆ–Õ™ÇÙK0YÜÌzMÜ{ôé^Êt,2–3 Dê(ÒVؼ“ÙC‚WÕ Ü›J{Š.„DgÙ¯)X ¸5â­j `ɉ;æ(Îb,‡ßK8aå˜cÄïÕñ’îïòpÇy¾vÌy£u{$( HMc ÒwìÊfV+ØV¤VÌ[0…9Öô¶DATè»-ëª@;,öè„ôq²¨¢žÛAûêã~á4Cä¸RLÈFÇÎëv¢ŒAšLl"ÂE1Ÿ¬gRrlN0®mY3/ úèÁ ¦a-ŒA‰E^õQM6³™ŸPÛ­“’ñ5º+çNû¶Xtš¶D Ã ˜Øù“º— ²‹m»]^ Ñ0¶`ŠŸˆYlѺ‰Ú.54R‰ôüZ*h1,b-5†³c„Î:Ž1$`Ђ‰¶×I«8Õ¨íÐËD¢Æè%D_Ú6 z1ì;Ç8NnÜE¸‘Ëœ¦lnÂëX´³èyÏjàúº¶~©ÎžWÏþI¥Ñø±´p„ 1ßÞˆ™¼“hæU•|à­í£e½DÒŸ»åCq›±r0°×shÈÏCâgU>Äví5Ì0ü˹xó6»S#JØy}†›ÜY.Pp¼â‘[6ü yz6Ë» ·æ|>çtÓiÀŽfE²ù±!Ÿ±ré"µ ij¢ÂŠÄ¹|%~=!„åÚƒ$`Ï:Ƴåø1†XF.n“ .x¢r4 <9¨2Ç]€v¾Àk“­›¨?ÖĨ >LÿX ꀄ;¾Fôs€cëtºX¨ó`è. (;sdÖr–žµ–Lq{`ÑΔíkSá[ÛAÚõrƽ¤q%=“ê ¼¶Å,?ü\[X°À\þÝ`,Žød··q Uwõ}œ{!‘P.MžZ%tB±1à4ô•L„ŠˆŠË˜Ÿ½î1¬ÛW,/æi¥P‡ -µÆ¾'Ôji@HJ‹G0¾ÐpÅëÂ×Ó!Z]Œ„(d“oËj¶0§MÙЗ©ÇœEà…ΰŽÅA¿P#')…ú‡µ12ÜÖÊQÆ3| º ôº@ ”ŽÊÄE­ÞÇAb>‹Aà¢DÝ%O O4Í›C=ÜŽNºp¦*(*”Æ™ÂRƒ\%*$ªJÌ"2f‡|“Œ6"Ýú†YTênŒ¨5¾ 'UË¥óžÅR¬…\ µ¸1"î\ß!Àë¦7fcânÀ^÷f¨¿«pVFµ%V‚Wcì&}۔̗©(ØTÆÒÎÑ%á¹ÕX]ª=ñiJ…ìªñ")/„'º¾-PµÔÊq{¡Ñ΄QåÀÞäô§¸ 4M4ÌyoŠÄw™N›`ÀÐÀ²M4ÌTtº¡„Û8ª ßûÑ7Oý^öù‰ë²5ô‚a9¢¡`ZC,µ«ÑÅ{$P]C’ÚÜåÂ]@ü$¦ÖØìÁ.íïeó1åJ8(¢)ªz…X´fyܺܚÅCœg•ˆ8•Åã¹:|Í-\RX¤ê=t]Ô«×±'Üw»YŸ7黬RÐ9c{K¹ÊXÒÓG¯ bb4¥8ÚHLúc»@ Éíü(pá“É[CX ŽÉÁìaÉã[Ãí-ßj|køýø­áƒú–p×»A©ðÝ -™¥ˆ\B ^_”íxquSµ~™Ï7úZDðXÖI¿ªMNE•ûÑ^Ää@;©¦7é-£Bà)÷°,H»å{Eod›ì–¼¸YÇ'Î:ž‹G³Óͽ'NJ%»‚S3ž5¼o±ÿ€œ}%[Jð ÿçÇn—]I{~Ì4urzôˆV“%yCp·o¤ây´¾‘º}ÿ<®½üû¼¶>ë¶EŸÑál÷ é'Xßðzüû>,ŸýŠKǃ«MT‰Ñ‰ûYœËR9££^d&8&b;&”†8¯bÎ:Z«##Nà,õ•á¶=öüÈ. _@~Óœ{ƒO,À»'<ÞB™ô¬¦ÝA;bÏ#ÁÛo’._ÑÜ{µ²¹y,ÑŠ*s(6\p3›>°ddÌ÷+$îô?GHB«¿Âç´¿Œî),®ÿãp¼ËÇÇ“ÃõÅí§y•УGó¾õ¤4®;&;Ëš÷ ·þm¡ý€´ÚyþÏtv»®†«Ço—CC©\ÕÖn˜ii÷ÑßìÈFRå«FAþ–;ûÙ:Ëo…ÿ‡¨öчÓ`m½‘¿hôOëá¶ /ÒzÔ[V?³J³µeêWSijðõÓ|X+‡Nï·ßŸc|æ!g.ØvYiEߤޣowÁ£ü çÑ­”* 8ìåÑÞ»zïc¨y›Ëúò¸¨¤¾©×ÒM9÷ªŸ¬¿W»2q ¯ý ¡ÍYKIU/Ó§Huº}›Nvnê씺òæ¹äeI@üÞ;•]ÿ3-N¯—‡udö6¿™Ï¦×%¹ýz®ƒÂ7÷8_‘6IŠIï6+–Ò³‡û˜òæ&¶­šÇÎ_=€ŸÿLu³½endstream endobj 597 0 obj 3260 endobj 601 0 obj <> stream xœÝ[[o·ú¨_±@_vƒ,3¼Ô@×A‚¢ˆFáäAÚµd§’v­‹ ùñ=‡ÃË!‡³»Šä¢-AcÞyx.ßwH˜uŒÏ:ü W—G_ý]˜nv~sÔ;ƒßó£GÜ7™…?«ËÙ·ÇØÌªçÌi-fÇgGÃ|fÅÌòŽujv|yôfÎKÎz«¹›³Å²cNZ©æzªÔ9Í´SóïKÁ”=Ÿÿˆm4¶óW‹¥bN(Ã9þÁ¯”ÏsF…KŠIíúÙñ_Ž¿xƒc(&´3Æ€… × Bv0·Ðó÷ ˜ØÀòùüK3œßæÒw‹¥f}¿Å‚Y7ßä‹Üt ëu —2ÿ´©HiõüWnŒæf~ý-븦lré6{í×k!s­†±ä°–8ìÍB2 òR¸á,ÓÆÐ}‘Q‡ia:×…c z6ãëßæz¶‡#‘6ŽMC#{º¬. ã¶ÓE2«_«éŒÅ#WV0Ó›pF†kl ÂEÔ.JKÉXÛÖZÉ^VyYtš.æÝ54‰¾v³ã5¨j<ãÞú–W­Y‰ˆ‡zÇá ÉQF‘¥mea©6iª+\´`÷'ÀHõã‚÷Lt dϤw[(§yyD]“:×[ÔÑYûn×ÁŒº$V”ð2—ŠÜ–¡Ù:¥ÁV]Ø‚AD³p2ì É]Ì&JDŒ§i%S=î äÁ˜ä]®'íÕú„îÆv]oŠ­¬GCYYr1hɸe§UéK¢M>K…ƒ»Òঈ»êX¯ƒÓt<\ÇgFÁ–Äà9ÙB±^jü«ôµò_0ˆ¿T§ËÎRÙûôužjïRÙuú‚ó0 N\ 8ÐX¸L]ÞV“à×Iª=MedÀX»l,æªêam¨´–Ô᢬fÒ ØùÒtŠ)çÂxÐðEjø],ú~\÷S(jŠ«˜åÎÍ ÚXX?¥PANšxòëU@­À0™sfB+`'B ¦•‹Ž¬·ˆEBKf@U^,¤f ¬üÏ í˜ÐkÌJ'GõWŽÉ^Ãa7¢ÄESý7ƒçùxí7°`©¥§°}˜qZOo’äcݤ²¬ A#ŒßÖ¿u¥uøõºÀvLOôj›zÄZПŽõƒ«Ï&ü¦1Už¾žt¶ì_Sm^ÜuØ’d˜l6‘M:[ÛŸÒ×7Õ²à ߯<ÚóXô Ìo-uiûƒ"éñÜ2ú`[ù›ÒkÝ6ô¢µízØä&~Ôc@Q! t"Ê”’X¢"À¯W„o’®ÓWë´ž'{–Êž‘e'£*9x.0óßÀ>]Б#¾MÝߥ².}}Å(F]²ÎÀ.¿Žþ±Vlu‹NâGY†Á³'¾ÉKOŽõÇ\ÖðØ¿ŽtsU­šzú:t ƒz™Ïc›¾¦•§,{ž]ÉÔ!Á4oº •ð·Ð°ÙΤ²$yñ™DŸÊ²¨2¦Mò/ÝIpÓç_fÿz™?_¤bfê'©˜éÄN*ö2}½Æ°ÖÃ|²"e>ØÙ~ ưØF}¤Ái3D’ðÜŒ¦×X¯Ô˜ù· z «1>¼Ã˜=„oáH,½ÏÝ3Æ¿-挋ºØ, ß’IЀÎÊŠy¤aÔ“s#¡áDKj‡BùhÅPñ7!²ÁÙ)B4„f€a&²°˜‘TÐþ©¨Ñ˜ûF(÷ìy0»,éöI,s©HM+^„×öļOÒéò"!êàa¼HèÞ‡ö&[q ¿ò‡cK6%Ôÿ-ÚŽƒÄ§ŒÚCx†fZI/SÝë2ªìfJJX€AÃác\C2e îTô?èöˆƒ Ü&ñ…Äm_妘`¸Cxävb²ÎÛ°Ñ%q³ÌZL:ç¦w­Å¼m®…Ã?ôTÊŽqÜœâÅ„ _ç…³$‰"!%ã ’ÙkÎ>ˆäi6•cò.ä¶ðlqüuîõ;ì³Û‘ xñû!£Ÿš”æNljµ¬ØPà}{5ZZ“¸?)W™Å‡#H Då:¥© žèØ:«Ë—¨BÀÁ®ŒÂ{ü±&(ƒh` Mª>ÂNF‘—ñ¼å~¢,–Ôôÿ¾ì@ŸB;0æCÈpBòá(9ÚÕJ¬·AUºH„ ⓸lbG5÷MÀO¿¤ìÀx³²àû-^Õx,‹lJ¨=lЧZ–jY*Ë|I§ZÊd£öë 71Π<ˆXy%pMfÕDz̷»²èÀ`ˆIÁ~À‘æsAí™X9±âûv‰9’ˆU‡]N¢Xæoß©»lá®òPÄq-¸ájþ‡ä®H  WIÝ$¬ˆ7AŠBÌ–ý$^Ü­ÈXmf¬/€Uà-î@ZÐ@x\Ñ1Î…ä(¤Pzcmƒ›DhúC1@4AÄáBÇ DÞ“»;’·¼‡Ëäm8EKç¦6/uûLÀd‚’ÒP5„©¦¹!J‚‹6û"ä¨ÉãîÒn…ƒ¬åcX&¬A‘y¦õ¸%˜áY“¼‘ ]ßd彫ö!_V|yÏg#§¸~«krê¥3Φu¹¾†8Öw} î+nk1q@¿Žt\ãçms†’éÚ,èå3™"ѱgc®ƒµwù¯Ü€´Í—ŸCJyЇeʲW÷„ï3l¹|ï@jO¹b‰N'Ôúäë} ‡¯Œ¸¾ÏÀÚU#jG4!åA@âpÆqëq ¿¬RãŠãÉ…r½›œ¬ª=”µN=É*½x…›nírB“Ž3H$4šNOŒpˆâ”Ï`f‹*Æfq‘eO@ä(wá›/(’?@ƒèÖAüÇ‚ƒC²|hý–rŒ2Y8äè9í6z×F”„e½˜Få÷Þ0=}G±y™êê…LKðç}^øIÎЬ[F60. >øµí$¨‰ Î46‹ $ЈôÏÞïPxÂÈÏ•&|XÜIJ»Ôã’ç”:“”ÍRâ§ÈÅÚådEÎE¥Eº)o$~®Æ£^Žú=,Ë Á—™€w2WÝy¯ì ƒÒ´AÖóŠñ„ÿäÃÙxŸFÌclÁ1t‚!ô]‘H%¶ø!.Lí½°Ý6ØZë-B±àm_|U·—$4íºÈ‹´ÍÂüÛ‹Öõïß툷¨¯ bÓH,×!ôsØGŒý›QŒ‰g/-“Ú ¦)3=<2Òº*; €©n„‰(ëXÕ~¢ºÎ~uÎÊØ•¡Š‹”¾pä´ä¢c'qý-Äo¡zªåíßFC4– êi3¥Kf2%…À ¢íDJÊBØÕ@Ö~%ò°D 6-Ì$‚97­N(‰Â4¯Â–¬œ0X"4b±0†ÕI?ùm÷lÛÛ–Ñx‡l |ÀüÒ?¯‰O–Ú¾ÌÛgûÍ•´}^TiœMÆTb)÷»@h„œz$Ð 4¢¸šlcãÓú<¼)¶¬ßçÐþE™½¹jéI•ø ¯ÑßÑi1I‡pªxŠ1ØSÃà*”=xhLÞ–nsp]5¯I Fç½;1¼*"`™@­®írž>¥ªk½ÓVйJ!÷S®‰ÐgŒ¶‚ƒ [öîÊkæ”#œ2¨q:Q¹¶Â#FÛg©ðàklÇÔç»Ê~úlÑ«G}V%ڎǼÉ“C¤¾“ŠaÎË™¸9¼õL¯sƒW3Eºå/ÇG¯àçßhwKendstream endobj 602 0 obj 3116 endobj 606 0 obj <> stream xœí][\Çqœ·}É_<xOß»[eË \dz=ØyXî’KFËݹ+šþþÁ®êÓ—ê>Ý3g†CIAÚÑ™Ó÷ª¯ª¾®îùn5l5â?áïåÛ³'ϹW×ïÏÆÕ¿Â¿×gß1ÿÊ*ü¹|»úò_3rÅØà”â«óWgSleøÊ°qåêüíÙ×l³eƒ5йõ°ÙŽƒFȵj>µ›­sjPN®ÿ°øËõÆ Fs¡×S!©-yøf³Иsbý~³åƒÔܲö÷—>é¤õo*1çÖ¿ÆæÍ8JÅׯS£¤©Ûôðzz(´^¿,ªšýŸóßùÉc+78͵ÄYárÊÙÕù¿Ÿÿó×çØî”pÐØV ÖbÇ^B’J«õ×Íé¦.h­˜†Ž§ßnôÀ”‚!¾Ì ¼€Fa ¿ÙÈqÐ\I8L«†Åaëw›­`UsKPþ|cÙ02X»Ü“‡\ˆ´“Ÿâp¥äX¼p›k¸Âô` …§8µÚ9-iƒôqê„cLam\ÈÁb&Ø(C)1šÔ°HýõO±gš Rjø(`2Gmâ$iacªRÝàx¬ñµ k¨ã4ÁÃW8F50ÍIosñüf˜y¦Š©ýùF)ÐÍRõ ¡q)ÇA‘ί@ys¤ø}~ú˜ZBàfp£ còÃË!ÿÉßçòW¹R1¨œdªÉ W©ij¶¬þiž 2?´/©Û?鄹’tÕˆè‘L ,_ÿKú>ª§ê•;œOРåȧiý‡©¦QÉ©‚—I¡q°*€™ÓðŠiÍ¢ýv#+”W1üÅ ›øIz䉟^¦oßUÏðÓUü¶ L™ôHJ›'šD÷±šç Í~rm¡âIxƒù‡s°ÁÅñ`cFUMAz–ôà¦)dI'Pn´ô)Á,3…üOÇ©ôÜ2Ëg¡¿+Ëã\X‘¾¿Èíßv4ˆ¥‡B¼§VÝAH†â‘$>-^åB ¬3Ò‹¦& ða†Ñ¸ˆßP Œ´]`ÄFÑV1‚_ÀÜjËl°bGjí³“ø>KÚs›ôãúq™¾­5êpí!ÍŸRæë÷µMËf—¬øuaöçÒ×V”¶É«Ä“óÁ0³_?šæ1÷€4ð ,$+5m+‹Mõ²$F9`©àäÀ"ƒw%«ãÀ±— Á¨*Z›½*&¾W–óؾR¦-¶ >;/¶ú@Ÿ+XçInž&±½i€þ]úôa™`‚[h‹út¹l{s3¬ñm}Ì/ü%¿P9Jã~Ylºñ{#ûX>Ù‚¶Wèç Üü]Y¸2—Mëy-¾+ε]™}²Kb½ B‡ÇÏP=Ø— A¼«P?}{ˆ ’útA¼Êß¿)œ¿h~guU2ѳ©ñᇠD­€ ª’ï³H"ü $í"øãœ4X\ž¸/QUÏ}¸@|”.ç‹TÁMK$‰ô~fEJ:€ÇVùùöËì§€§²v0Üž'™Í>ñ}’Ô £éÛ˹Íß-ÇB-þxR<ùÛoñ™ã£Ð7‰gID;»Î%‚ÉÚµZÒ~²¦Ìk=ÍÜ7i­^§Õx³3ºÉë—ß{?÷Þöxj ˆvä”KHž¾nVû0y'Îp_‘²Ne?¤t1¡áé +ϬÒjP ^žx™ˆ$Ÿúâßä£1ôͪUeËSXX†GÙ;#ŒÈ‡ÀYÍÖOšu5©ˆ\×}•yn25¡)Ö±ƒŒ‘N䌸#ðù1<Ô²Œô@n@6½3ùz ’PË0ˆ3JX÷ÉýÍ¡DÄ›¹à)NH¼yb¶®›/Þ$Ù‹Û£ä [ñ¾«q±ËÕ8)¨ÏåÿGqà(‡`9 ‡©-¤o'ÊÈÊýØ焨CV|"ì{c8 B0²O7m‰¿šz¸N2yÛˆáÞ¥o:ÜÁÜMý´…ÖII›ýãõ“6^ÅP3wY0z~SF9×»Š/ŸoðT&ï2›<²YDÀ òÇ*Pžž±ŸIKmÑH»Aõa q"Àj©AÕ }wŸLŒ‚ñ†RI÷ˆ$wz¾¯ã+¸Å Ö…gMhïy•º(¸_TRŠtkd‡‘%TÏ@vÔú¯¹¦ùÍ›Y¯2|§Ý½H@ µrQÎhÚ‚¾ `æÛebtƒÞ/çm‘´z•gµØ#Õðñ¯ÍM¤¶©ÉÃÊŸŠ°(²Ü"m’á¤h ÂcO1)Ü·¬àE07`±‹ 烴]?aÒHI†’ŠsBÚŸm1F™,1]ײÚ%µ¨Hg•’@ö#´U'QÊà …å®÷Ó_·|•÷TèDÞK /suºtuÉMöèêã|¢C=ï€gøÀeZ\ÚÞÃ#!5Ÿ¶ËÃtm…Åý7ÍZÈáZÅlma24¦ë˜$¾~¾rÒ8”·j°L™˜DƒÅ®|5hl`Úµ‹y5ézÊÜ`^6ë¹ÇñƒUQ˜._½ñUZ§B〥FB˜¯D'/ÇLñAÈËy–aä¶[^fƒ(g”©(xä½öÂsG"Ñ„´`„ÀÐutB)‚o*<­ý‚·QÂLå8…ž”À÷Fš.DÛq Šõ ÁÑ*Yì3]ÖöÉ?T¼“q÷©Ô±Çøh)]Üm×D‰¹Fô›¿/¶Œ|ö Þ B|$[ºˆ°Ä¸)÷¥ÓãûÖD>¶Š$ì´c±öŽk;¹'îdq˜0NÎÆ›Úf…!`5dÒ¹lrx…Íò+ï:/ì%ñþRHÜ”‰§;ö%wròG&ÙØ2(g&¹Ïr‘ÁbŸ›ßþ ÄÄ(Ï»)kXÄ4±Ýp—éNÙá ×89Óv•-á Ü` âð*f¨ôšL»®H ‰ö²·sÈìW$+Ά[ ðÙ—!ö“÷ª½Ÿ6I¹”{2wÚÐ\è•.J‹%(H³¸j즓Y}ÃÓGZgI@WMÙ:úqngªãâh–5¼³±…y“ÈøQ£ÊÖͧ,g ÓdÞ»éeLá}‹bŠÏÍ,_?~©cÞ0I!ίyI'ÉZZÍ» ãÈȘ,ŒS!Ú¸O!V£"uæ¬åYÅÄ{y† šv748I^ÝÄB4JqyXĹÑ{³/Ч8d"æ0–Pml¹½qUµÑÉ~Éý¬Uâ`UõÞ)w–¯«ð34EvOš»âíLàûÖ«±«ÖuJ‘¶Hg¥Pf•`­^7¹=ÒV›= m‘3|˜Ò=èç¦ÙûÛÂÆÅÖIÀµqZãÞ­O>¤’l={îü]ÓD+8A"sÃÁña°v0ªÚ^Dõd¯g(R$¥BŠE—âMv4¥»#[R²³w¹µ"”Üí”x äÄ ?Ž ”, lfYÚ)ÇQðFN?§:àÓu',¹-Ýê‘ÓÖ*ìšÑŠ~ɨ} …ÿ$>IûìA»˜©gŒoÄ=¬erD9ðÊs_'xR¦¤giÉ1FðG;ï< ”þaôSràÔ3õÓ§}šŽæA®x_µ¢oÓÚ}|t?\Ì¿›DØq3&lC’~£Ý(¢`±,í]×kZ6ZaàN:Ú4´)Æy >,£äó i§f†Î’èZ[iî›ïÆxrTb}S¶¡8]Ì_HdmȦ°ƒòWídˆÌ]O¥ŒŸ’„YD…cØ¢#ÓŽžù¾ØA êÖ‹¼ŽsS^%z†¤Îö9Ÿàpwý3¯ù}ùø¹r/’” ¹ gî«ó³ßŸ}·’ ™;{òì?Vï_ž=ùfÅΞüþç˯ žýfõwg_=[ùª ¸¯‡ñqe”ÜÁ¹ÆüêÙqê°¡`@}¾€`ûëu⿲UºO~âCžñ¯ÒÙ¡Cb`9p,Ÿ}LütÇ‹!ýf¾‘“rç}{IíMËÜ“uÉ2ô“ðjo&”PÇÎDWàØˆ‡tNT•<‰ìŽÎÿýôuî™$¾#ž`¤vÓU`%5ŒE‚øþ2=|ÕHϼ©ì(~ûu¾wÊóÉÆÙ1[QžÉŸ§ó!Ý­åÈm¶µy¬©™fTµ@ýäøŽøLÄM V±ÌSÚ©‡O_Or!`<¼ª†äB=ê@e:Zr¹Ÿ¤ÜÚCRžŸrºwNÏ%Þ7ä;gkå ®ZæñÓ¯Ò·¿LÏ^U¹‰SÙ-˜u>K AONìR˜ÓMïn…!S›9¸®W4ñ×Y˜ü óKrýð²‚ò®O‰Élâî#‘ÜõÙP¤¦ÞÏbô(—Æ~ðËÚŸ¯øÎV:âr5>bQ»jlÕáUÅ>q™ÕØ*~ !;^Æ\ÆêñR;õ«ô¬ÖÙO´q8“IeO6•{T–Lão“ÎkU&!ìà:y~%ƒòu Íœ¢jÇ”ï$zMÙmÊÓZBž1n“„Y¡bWê”/É%Ì +ØØ99^ø¶P«LÈŽI10-ÝÛTš…¡ä“©%?=ð˜èãÏÛâ·w±->•ëc"W$¨‡‰˜d)—íuW:ež¸@?ÚçÚùT±†2÷j¶ þ]² M^pÚâœ:˜ëf L{Ú¹°Í› m´ü¸QxÚÁz84Òù´ákŠ·\usM%ÊigXÛ*`ÝKs7^ƒÿÓȘ®9"t~¼`‡Ê™Æ}ñú ‰V%Œá­Vë¬4ûó@0ÉnÅAJ´ü„܈ØŒ 8I3Aö$€È¡ìTËÏY’ÍføiÇV»ÌK\’ïÁð¼#íLiv ÒM6¾ ­œ'MÐT˜ê¨+’mß<^æ}B¦T:'–¹´ÙG‘m°avüéxtaÙÜ¥£ü9îyˆÓ «væ+êtÊ!uä4ð9÷㢠Už¿jGû‰ø9<Úï?Ìhq jê94õhÚ‡¹Ö'Í}ÈW\ß5¾ýRh5}ºiÛã)kæò5ÏVF»0·6;g31ÿù·,D.ø0§6’ªKø—x°üüK<ÉyÜ6Õ¢‹Ú„ðKziqKO4Þè´€©’–ò.ó{{–ÒGHs—´<>¡äd1-N”ü½—0%夻ãîÈîxæŒvá Í«:ÝtìÁ2ÏèE[<÷ƒ? sȦm— ˜wN}zS«”:L÷cœó $µ¿à ëó§,-A¿_pÝM,TÑ8ù#Ýc¿ku•ÊÌ(k}‘º-˜ø9‰…®õ»¼%F˜²Ã]D Óµ~+_±çïð2‚øFíËð*Êü˜qìݱÕ&ÉJ¼œHÑAÑöQÒÔY *ÂÏL³añÎ-äúÏ$º·˜ýŽ[¡²w!I i’Rþ†ÇM‘e·ë€ZúÙ <+9†4Û *÷˜»Ìºæ½ hßEQóßPZ~á"ýU(2oüR< Z: ñǬº‡wÉÏÙTÁªa«_Ù‰7aeãÛâXIºÛa:Ÿ.Ïw;Â^t-ºp‡ŸjE¸Ëõ%Á01¢5û,§%^W¬õìWIvÆ '›„=vœLÀ× ú‰j`q“Z¼bfÉ}ÓršõF„yÿ¹èxÌ¡-\´4hÊ6’D°ìͨiûm> Üœ2m_´»kx"=øy’⎻.ps豿ƒàÒÙùûWú¿pÙ¾«†ç»j¾òá2&Ëÿyz¯Š!WÉлbîÓ1äZš¿AYž'­n‹yNn‹)/³SᎰœ3©†¬ôäs!#¥ÛVßrUYrð´¼ &–º§§Mw^í™Ò¢ø3”2.Â?MG$ cZäË;B¯l¡W {EX”ÎY¾ªP´¬f¨ºüÉ’š6 ¸›¸ßiNÒãmÃ(Ôù¼ìê‰2f6O~ “¤6³í)Ê®î&NG”ª•Æ_¤sYõ„™„: j~ö7ßäendstream endobj 607 0 obj 5425 endobj 611 0 obj <> stream xœí\Ko¹ö¨_1XäÐc¤)¾ç ²QNvZd Ðk%;Yÿÿà-²ù(v³gzV²,Û‚a¸Íf“ìbÕW_U±ç—%lEýŸøïÉÕÁáO\ÓÕ»ûºú+ü}wðË ]VñŸ“«ÕŸ|7#WŽ8͵\ °•á+Ã(¡Ðxuð¦ûiÝSb(åÒv§ëž­¥’ÝñºWÄ: —›uÏ…%Ît·kFw–w'COÅtìiÃ}Á¨ìîáéˆp²;[÷’À’Ew·†y…áÝMyä :r «ôãpe‰UÝy˜Ë5…[’Ãí¸6áÄþo§tõvŒ/è8á–²•¶Šh;¼åÖ½¦’(X¸$VHË`>ÏwïãMkMwoòÝ›ÜFòÕû|÷×Q\ùõ1¾:úÇÁÑ«7qHr¼]ùÇÙhpßv›ÛZ‹½­¦a FxÕEsñΕ_é0~Þ˜æ*tšÛsÛv —~·ùîxaõÝ{¼D.†ëÌ›ž;u×IïÐöšYPš®Ïmý¾²BϞ廹í²!ž× Å3ì›1E×¢þå&cëàšµmŸæÜ ¬‘ðGëþã”p°Ù./‚å)Å™·e!ÑÐú¨Ç%¾„ζĚìþ´‹t¹ñ=¡€+"2 K6\Zè9qR)FùþIÆ<êðG˜‹[Âß9ß24Æ©´°i*€¯ÔÊ$n½0”1•^–q|<ˆÄf'èîôÃÛñ!/«ž*6ž–µÂffˆ„–QÏs×›|uååã¸Ò~ß‚Q)ëõ9Ú¼‰O‡­Ž’dJ ÇoÊBP×ÛÒ:Ý«(ÀÔá~-ˆÒT‡ P¶€±îŸQñ¬fh²÷•€„wR\áÖò‚h®÷^`åBvÿMƒTÑ+ :¬µù)]¬À/fÞ ¤%ô­=pMÙ¸ÜðšîcTªp‡?® „³)ƒ¡}F}ëÝOã¢íEK¿n æ7\2_õÞÍg À€9ZÄy¡ˆ\ÜyF¯!ø´oŒKN”t»È@`š)X2—M/\NìÁ/ѯ€ø7³‚cü:½·ÄeÓÈ&Ò4åQt÷®XÏG¿@f¬¤è6FÝÚ°£ Rò¥Ÿ@jb¬[‚d`Äð©ä@”$_+`†¤Df̸n¡JZK#µ×>ŽF¤¤|ôòV4xÕ¬Ç)`—Õä6Í€;---WsŒ$•‘¦UzP’hVírå²C•åÞ¾’é/¥ÍJ(ÀßmþR ê²Á îÑlSõcƒ}ÝŒXÐ¥1ñ6ÁÉÃÎKmD\ž1åìµuDq6¦5.O=›fFg•Û:ªØwÔØôã>¤P1¯ËIa2”E¤0 è"RàG? 'äÌ#܃8!š«¥ ‚yR8ÀòV.å¯Dyh?VZ/{aiÐÎŒÎ>Æ~ÈÌaíxë¥f$êzQ¸Á€Ö–êYo<ÚìÁ§Ûó’—¦Tš<¼Ü4ð²Ìö:ß-(YBîóÆJ¯’œŽ0!jKxy3Å®Ãp—)ÊÇP5¼Åôn‘Ù^°%I þyakB•±Ù{­AO!ZQO.(ñ÷›Oå¹,ž3¿\EZœú÷ðälu{„¨çhnYؘŸâh1ã^÷¤q0ˆ¹"ž8ê"í¢Rtï"Ó“²-í÷cç‰|Úî•9)—" ˜¨ÌK3=ù}d0C¤ýUd0‹6ÖÒò6¯¶ÙìOŽ '/>!óï>Ýí[ƒÌ³áü\Ù‹Ôt9ut¯ëîmf¾4%;Òó—ý,»™nì]º(!bf0çÓ¸[~î.ü›qÎápúf'!"8'”‹” iHàéÉNºÃ-@Ä6¶“8V˜jüŒM˜’rþÏ_iÁtæ'Œ¼H;ðõj'/BTñ"ÔõcŽç“BíÁu$ƒ‡äžÄ¦ê@dä<½kÏpZâ•ÂPÎ'YÖi€ Ø{ŽB·ãfr·Î|7’†×1'PîSéùêå§rßÇÑÀ¨Üâ‡U]—”c3_¾nRZˆ)„Eiéõ6c(@sýJà…­ÔXj×^É­Š2ŠÈ–Câ?ˆßP ð7M9‡5áÈN'‚8ç=ªü8+W-~ðÛôôü Œé_M©`ÌÕ’w¦C–ÑÞ&VôÿsþÚèñ!+·Ó BªÊ¥ Â6¶ `‘[H=#ú+÷IQ $/îÑ»b- …ÝŸ ¯ÇµÍèó¸2„*ËzUQRÙš.8°“Ž7ʽ¨¾– QX9vvÈo´KBFl±™,GYW»ÞƒÜUÊ ËŠûÜ$=ðbL:§3h—el ú`˜Ô€¿v3`Iš«5þXbê²+‘„ü*Ò˜_›•ÇO‰SºîmWŠäÇsÞß¿Ž':»è¢'“:q˜mØI“àµ!´·}i£uÉc—zwÞµ‚\à@«Ý[h>a/åȘƒøÁ³ý\Å€a-¹ì¯2|Ðj Í>®h"©Ýx5 Ìcgb ¤……Í!G=Øà¹d#2)N*)(¨šõR±ï€2ƒºô,îÉ.Oó &z‘Mi}ÐñWbiŠŽç6‘¨>2*‚x=,0)4—ŠË=Q dœ#™V²³ò{3ñdŒØN†9¹~¡÷!'KÿÄ jmÖ“jF'‘ò˜1 Ì)Õë˜RãB{²›3j-Jò)òNeBMÈhY™ÁÈö+ PB2ú€A·‘î‰&§ÇLæ® W{“ÛDZ.öñq v‰žÔÚvg˜1>õ’yøÖ2u]ã‘Ó-µxØ6o¡ô¢>»lÂöjCÎ!<´ÆÀöÒ‘Š:™ ™"r6™P´`²4d Âãb6æïÑk‚ÿBNïrBb¶Aö+Û ‰´K_Cår¿“Ô†¡öË6H“Aë"¯"9„6ÌÕ^E‚ÑðúS€ßëK*@¶¼«c} ÌUj¹ëXr¬“Py”¯Ï’ç5±¾ >FŒî¸¦Aa€zTg€Sã~ÄZ2p…va>f‰àÆ_Sóü¡µqª<ñ¿6_€€ €Ûl?ÜÌÆq^b]ƒF˜ùé%›ÄCÿŒ 6>á½Áؼ—rl¬ÓÃ?OÅ{CcL·óÈÕÅæYÑé—1è™8ó¸a{;ò1üJdÞ[Dó{o‹YªÿˆK¾°Ôo¥¾PÓgMMó —¢æ÷RÔÌÊ,û4ÅÅ(ó%"y‰H^"’ï7"ÁUȯ!,’‚lm–b’m‚MÉÌ'£ßб0$É¿Cà? W{Æ$àÚ}Míù†$‚ºPJ!‰…±w†$^Ð>¦«L2üŒÀø,ã#E$^#´$‚ÎüJATa§„š·\¡Â¶é΢–P"”EÐI­UÝ­giÙ…¿‰àåmݨÞºÇÁÀªª8hÁŽªâùËö‡Ï±ÿRC«bµï¯„à_áZã¶“>‰®L>Šq6çþ#öUÏÂêòµ®ÍcùÎ9:øüù u··endstream endobj 612 0 obj 2954 endobj 616 0 obj <> stream xœí\IoÇœ/ù ïï~£é½Û€6b È ovI™´(’æ"™þ!ù½©ê饺§†|´åAuOoÕµ|µ XƒXø“~¾Ù{ö•´ãê»ë½qõø÷ÝÞ{"¾²J¿߬>ÝÇל^…!XiõjÿÕÞ4X9¹rbFh|³÷Íú«ÍvÜ8Jí×Ç›­¬ÕF¯¯7j0&h°ë›ÍVÒèãéf„UtÃú|#† Ä¨×ßm¶RÛÁ–L5 ²£Zl¶fð>EëJÿÙÿ'ÀØæãàM:Cƒô£XYo맃üe³µ£ ¬§¯´°|‚ñë‹ÒvUž`a+<Œ_oKÛ¶Œ¸,m‡åé€é­cJï)³ÚÇ¥÷Yi;)O¥÷Mi;ŽOΑ¯rÓÅf¥­SihóÚeìf”ióÐ{Àõ^ œ”‘éðâ–¼˜šØIš×ááj¾ñëüpLˆ>5M7,­àYtp"„•5~H·»¿ÙªA£P­ðpŒ´v°ÐzPÙôe}ábca´ ë·ødtã -£<‚$(ïÂúÇ:†Ìôy3H`ÝËÚùÝ)ÊTƯߡÙ¬2I"âgôq+Fc€Vsž§ëÁ«xv¥ik7—ÕÃ( ²îÌ;àå _U£™\ÞjYµþ êY}3íEÁ¯q¯jÐ ·eüy| BÜ`YåñTR ·^dÖ¯;Mt5VÑñÏêù^MF‘Qu}òêåyIÐbÀ2ãjÿØå°å >^Ö ¢R²£uëa×J Î#ã€>#\K=ôM¢´t&²¿–€WÓ]H¡hëA=,ÙáIºmwˆëÖW§QNHýùUÂdù¶¼OœeÂè)eɺG•xrƒË©õ×ÈpM/™Ð›L‹1…vây°ÞЇx^$©Œ³!#=X¡ö;ÝŽ’6æ›P™æq…ºIdƒ¸5#Âj+ LDd‡ƒÊù‰F°qU¦©*So«;¬RHF×ǨåË·õñŠš¾jOËZ§ý‰òRJP+’ß!?Ñ)xÅ4¬“ŒÌ¥£ÚÓÝ~ 6 # ¤h%^”^mD<²1ŸVfr+r´rƒÅ>g²´ÖœÉŠêOÊ.ò˜Xÿ©ÜÍ-§N&¢ P'ëã^`pÊ$/atd4BÒJöÜ"7û[ àÆ4Titžª‘2+îÕ:8¶££nص°­•²ëÏ7B·Û ¿´úÕ‚N9¬ j¦Ëâ ‹Êl¦Š<å½"ñþ}¨š3VÚ^#.p8ª˜G³ƒ:Œ,#àuf™Jü¨ˆ´\eAÉ©»S× ˜ós˜Ø›ˆçL£xA$WΪ˜Iæ$œ¤j¨Ã„Z|±³£¢Zï[©AÐÉ;Ð…$)¯s6²[¹|2~AÓñ* ØQ@eHlý%!ÀÂííÿí›õ^UÎ|’QSO£!kç²8Oß<‰œ¼¬XÏãRMš)TúwõcŒóƒ‘O~ÌÁ¹îŽw™Þå¾Ü¼oõþ‹àœœÿ¢”G¹yþKœ üŒüea¹Í,ú/ Ôy‹PæSi¸ºÆ}QT‡Ó‹îK$ÏÜèä£Ü¥=J÷{¸/ÀGR<Â}Ù*Ûç.ŸPiÐáÆí ¦›ÕÄ!Œ:§ŽH € p¼F¸NÞÈž7ybù°ðqPÈ 3ÑžEÈÉ Z2œ<´ÆIf`½ŒÁw…om|ò`&¯¨kµ¨h€Ø™“Ž™„¡U;¯¾ËM/¢Z»¾›üGUȽh½Ä: J6ŒaµÑB£&—ÑF‡AÈQe-p ï «o!(ëAÊ(ð>2ô§8Ÿ°Ú¦õ¦—¯q?Bi[G—3ø ¼ˆè´¾€ãŒ84z€[üù„ØK½³l7«Ã%`fSÑÅ×ÅüŸS¥\®ÜØMŸ®øØÉ‡WÐ5ëï¨äAyV+i+Fz¼ã'€­ÁÓUÊ™Á¥‹|oÊh,ÈE’Ã`¨É$ Í·tDWQ âߤ8Díµz3|©:Õ„†½””VD—Ö7³§)Âo㊛Ûëwª>±ç‰ðJÒi “œ¶tCgdâˆ3UXÉ Iz„ÅAEý¥GÆõ­5ÈžÍ]ºcð®Úhaä¡9ÌÏŠš ÇÈ$Ъá6ˆ3Ý«äƒ8g½‘Œ£¶t„4ž~¬{!ŒG&8h¨/ØÑ,˜>–u·GF‰ ¢ %½ÍP̓ÖaÉ‘âLñÞÛ0Ó«ŸOX]L4Gvè&ŠÝ(ã°®þ"‘Њòˆ€±3ðSí?n4|8ñ&¤ÑRâ1ðÅ€Sí85—NdÔÎ/˜Ûìê`¹¾Ó—H!c‰,WQ¬@s£Q`± ‘f«:9jVÍnÞr ì[_ã’ÛKÕ,UNºæµEW¼$ÊŒbØìšWI½¥}HGB`ˆªÒ”—ÒŠÑ@IÈñßsä™{ô÷`ô̪$sЩ’DD£–’ƪÒHV%–6&BŒm¢&à»a,˜†»†߯±­áh]à¿ýÝ SäÚQ'±!¤Ž6ŸG(áä00#š€rã g1––€ ùÚH&B¦ £ Ïôn$êíó›Â³€³£Ì˜…w5™t]ˆ?p:3ŽfVÖ<ÏèÁRóŠD•²×ú–ÝÊÑ"<Š2ª„ˆB«üØ¢÷ÉòìmZ«E3ù[`Š,ÙŒÃm=§I%'ü\…VW–0±oÖqøQ#Ü©IxŸ ?“M±àåˆ(˜I ZÞã¾fTzÉé1²TÀe.(s»3t­ÜjÚÐ2TrhÙŠV••).Y]GÔÚl“4¡5:'„ŠÄõ<æ´e}ZÎÝD‚ÒùyÃп)5bN-qLëûÅ@· ¡ú¶Ë©z´ ÖPèó`+[þÖa±ÑCº¢ƒ9èó†>Ù] #g¨B|î¼§æÚ×zŒTd¥rÒîh¦µ:MÀ:b}¢¨Lš¬üN)¡XÓÝ' `yÖ­5``ú]¦kÈüºÝfn"Ø0JëP‰Pêlh:ÀA©ÇNeyí¡—°Í¼8¤ËÜÅB²ÀçV80Ëv_ uµœÁ«‰Ž˜”–:#^p|{[Éváæ'ÅõñRŒ;ÇÔÅê·Yk¬º“ô\3ÄK¾xÈÔ~ïȚõÛ 5»¥¶Ó+‘8K-+ž4CJ MÅ)ÙØO€÷“R*õåTÈJ¿¿Ø”Ï~—?½I¶{aF£« AL,¥yùX÷-ôÞ©âhL¿µëp]ç3Œ2t_õÅd«~0¯Z¹––éùli^¨ÉÖðpDÈvÁÉ%nUƒ’w>^MboÁm*Fb–j¬Ö½EnD‹ Ë– Öã,Òçå# â~Î(Ô'äÙñ’Ow?ÛlÌ­¬V`Ž_Óçg³šìR2‹Å.~3AxwÏÅÇoâîùB;CÞümÞC^P‹6±<¿í|sxÝÆäTóã®ûy­º tûž½d>JÑ]xD…ïç¾w¬ðxP)²ÌÙ×ÌöŠæ&ù3Š~âó* :˜r¹äÊ›è ð먀uØ?2ñм—œNäôÑ(Eð©þ‚Gðç)r?}˜—§>Bçö_Áw¡eü”jŽï½™íorÑ[œ*f5Ç?Vª·*ÝimÞ´6Ý4-Ù5rnúšØÒ­ÖùC“«Q³¿_Q‰ËI“§ª’§¤ÉSÒd§ª’YÞ¶S–¶×å‰&ë§ì2祱&J_ÔÄù~鮹®ë•Þšeý(?µÙf¾†KÉÖ¶ÓÒö¶´ÕÞú!9I9ÿ²Bºó’rþ¤ìö¼#?+mw¥í§ßf·¥lãÛufÑ ¦ò0ÜÓ7–¾¿æ¦o7mÎŽÿ]¨íW`­D²äî’m Å6á$Ÿíï} ?ÿ`Çf endstream endobj 617 0 obj 4138 endobj 621 0 obj <> stream xœí[[o·Ú7½ô/œ—¢ç=4ï—yÈÅ18µë¨E¤ºYV-KŽ-×q~Gpgv¹œ!—çèKu C0Dϒù~3Ü¥~ZH¡ò;÷žj/Çoväâü;ÞùiG Sù×ÁËÅ—»0Íy»H"y ¿wŸíHÝ8m‘´ÐQªEPRHxørç‡å×++¢qÎ._—Ñù0ËWÃÈF•GH;*´Ã2úlµÚxaôR®Ö^Zá–?.Wk¥RÞg†°eI!5|öû‰ôã*þ±ûíÎÚ‰¤“O‹µÒ‹ÝCþ›"òIY{Z½(´£B{ÝÐH |ZÔp·©† ¨‡5”ˆ!…Q—ÇE—·…ÁE¡½)#Òj¯ÐÎ:ºEèéq­©“â6%=³»vþg'®6ºp‹»òãÆÂyçÏËΟ>-mûS¢áÎ-í¶Ÿ®¤V²fF4No`ƒOUH[*'§Åàºÿǧ F‘ÂhŽ„IÀÚ…eAyF¼gh (,Á.‹’s+†Êå"è…×QÈ8V ðxåTTXK‘L0vºT;%'\²Ë'8AÌ૵°Ja…VY!ŕҘVZ›läÄÓÕZ;pf ËïWwÒ–-ßëñ%˜åþ8\üm ERàl°›QËFY~^&fµ”Ce€‘2Dp,ÊjdeMA@_C¿¥Pd «—È iç î‘|l‡2Á/ãobO”£G[H9?¡ÏŠ;@2^€Ï‹.è¶$E0Y‚mÏ6Ú£í_”©‡et¾RQ¨ Ù;LË eôjØßEè™%Žˆsï¤ ‘ÁjÙ^:L| Iᤂd€|‚·>k5Ì=©'2ðÀ›GF®Õ˜8Úå¼ñ%o*G°¨8 å,X™¯g”Ž%šý&¾LXf.&7›»×“ahKr,”®äß”.,MÏrÚi+;ô„éª|c™µ.ÉÍXíÍò‡/V^( Ï× î¢IPhMåB€,ílæûèr4S«bJ]&[DûSž÷6B·iM÷›…óóø¶Jldà•°`Šg$_?‹Ô¦$cuVÅØðJ"‰Åòik>ãðåˆ& -Kã‫õ"¤´š;¼G:g;L¤îõtÚŒ »©Ú NoD/gÅØ¸—çänFd²`Y÷VH݃_´üûlOîWé;l¦LvÍ@e¾c‰Ê˜mÌdí‚ÐZÍëi›Ôg$Nn1C ý‚³O(Ú–7r$à8'4Àd´N(Ï“ý¬ ÌÓïiÂ/ÝDÿ;¢­x‚ð$H§6â ð p€q ºŽ¶¥ƒ±Z8›n,l m´£)KîÑfq54©¨b l“unj®½æÍ£r H"a˹ÿwÅ—Ýf‡R•âk,æ>,MU ó€ÌÆÐ•ÁçÛ")‹’Ž·\QºO°J´I–ÝjVl=Ûõ°•µ$nëBƒ-CÅÄú%–«äWÖ«>PÎzWÖ:àýá«‘ÕVg=ì;Z))à˜¤YM™µ˜ÃÌ‹*c‡„ÔiùÛÒï œ,z—›M84L¡‚&…†ÃJÕGë=Þ9UB¿b 7 ùõ/Ì4o,Ó5”«ó–¾EíI‹gDeÎ+ÕÆÀIÎv”ÁC‹7sdÛ˜v< gõÍ?DÎöjkÛx†MMº/ ”(°8€¾³•ú& ñ˜ÆF°eé‰FUºÓ ó³aSQÞ¶‡¼ÜPSWüC”¾:{Ý*ÐOënвÜèfsÓ)ab:Û´ƒS·v)ư¸¡ìë6´ÌÞý–椂FÂy gÝ& ÛM#(d"\ïø=än}íùÇ"µfFýÃ*ˆ(¥²#(’1¸y05•¹Ÿ×lî¥ùe1Ø¡·¢Jé&ùE‚&ÝÈWhçÀP#“„oΦÈdí‡ÎsUS=aÈn7gªÑ-Âs’e_n.¡üîoÊo#–£ã]Á3d Å¢ÊÃÓ¶ëÉ嫉ç&wîµ­z™-bÓ­&( ‚IohˈHìgMõ7C( žéîs™¼„~º>Ýì:.PNu}A/;[ŒÝ«æB¢YŸ–ÑýNãºá%IÐ2 Fßåßµ"ãÚûÔp~T/=Høydl2ú¥¯Dnßè˜z×Òß­kmš†c[d¨_{F»}…ª?Û,M¸?é8b·¡¼1ÀØÜ5Þ\šÀudQ®l>¹cGL­Ô£fÂß?rŒ|Tˆôå€zïWµô·‘³4nO¨(IüýÝJ×m}iÎ_+R®˜·/—ÇSj÷ªçÊ”7Wåh.Qfv¿eú 0ü£ä^àvùÓ°.wdõ•üþîÎ_àç?5”k·endstream endobj 622 0 obj 2877 endobj 626 0 obj <> stream xœíÙn\·µÏóÒ_˜—¢£¢¢¹/F[ ŽÄ…ƒÄšhú`K²äZ–d-qÔ¯ï9¼\y9I^êFàˆàårö•ófÉ™Xrü/ýÝ}½¸÷7iùòà|Á—_Á¿ƒÅ›…ˆK–éÏîëåƒXf¬^¬„¿;/œy3-[ !™õK'8ãðíõâ_«Ç[šy¥½X}G°kõÏ2wkÛZØäÕÊ–I“\3íåêÇÕÖ¶!0ka8·bdeš*Y¾ý.Oý¸•FÿÞùëb[ä2¸å¶Ë=ðQüjŒ^]”½‡†‡Õ“2yRà?)s§'¥dÂføÍí¡ç ‚yÀï%[– å[eà‡ù†‚ ×iHRJFbê*RÞêäRËŒrV,– Ç6gA9¥AûF³`yB0Ì vMá¤Ô«ã2:™6ipdg[’)à ؊mi“ÒAÌÇ™vƃgÜÇÏ:hŽN‡TàŸí ®ð°&B’;/¶sVBˆñ¬î©“/Á1ñ³8l[2m9Ðiø}7*cÄWÊÉâ`@ÐÌ_jˆhx‰Û¿E¸ç@<†Ú2çð:Å ÐG#Ü`³|ŠL^ ‚†`è€[kÛì®±*¡›@á·xƒ Á*—}äˆÃé^Ï›#žÕƒêZ2$‡W _à Òr…lJ3'Cô/iVÕ¥à1òìŒ1Eø¤/Óa:!$ó6à¸-ÀkXP¬H3Ë­Ë„²Êã8å/a©àнx[¤¡÷Ž^pÑ£gOÊÒ㺟œŠ°@¸#°\Ôýd)™%œoM˜a2[©1$»õ¤IR¼”¨uJX6Å¢d1 »Ä„$dó«*¢f—Ô"ê0< Ëq«Ó²ëY½ë 9Jq† ~R©÷÷&Ìè<à†ò˜ƒ0ÉSlgóÚ³t±ÓT•á 8/‡àLÜVBN%4…!ÄŽ|.£ýÁ@üösõgs·pZL—h°2lHõûev²;ë+Žh¹e˜ÌöçÐçsèó9ô‡>Û™B%‹©å¦Z±x]æNʨÖe®R’eeÊòutJYkâsPFû%¯E«Q… ŽF¡«2ºŸ¿¦Ša—“UÈku¦Íë @Çe]ÍâêÜvZ nEõ´|=%HçV´cò×ç6mÒ¸OèI ‰¥õº³<µŸÇP4{…©$^Jº[éR0*ßj!J´SMU)WZçZJ©<«lØ/£Šå˲î¸FâpÚѼ’ ¿æz 8׳Áç*‘õ¾Û. —7’¿Ööžç©£A…5ƽ’”`)\FÝ;zC”Ýj-±«$8>"‡î^cM×Ë\æ¨ñÄ‘¥6\¡³Ä !ø×†\m˜‘Ï{ÈAH1Eӥ˒6¹ú£qˆÌ޽ÉÌug% @K”Žø_Mô·ÞÍe7w¬&Ùuô^â6Zõ‰kÁrÎc›º¹ÊÒw”AF¿ó5q+cŠxŸ$·µ"•Ü\j±EÞ—Ä{ÜŸ&ªF. z=c*.ML—ž*û @zAê¤æYT*!y4À=£ÍòG(]Î3G Ù˜liãsÙ‹†Ÿ1ðÒbNX¼²yQÒ‘·[)å‹_÷yAÆ9ˆ¬^“ÃTsPuŠÀG,7áÛМˎ䳂im[FPœj¬i9ÿ.FtÜŠ?Hñ°YÍ^:$öO&<`ÞŸLxbž ý êŒðPÞ ¬¢†<}ì/goEú÷Cg–ÅÃ*j¸ þdvœ=\mAÐ¥$ÄøDE‚óOY‹×¶3Ü™Âåù@À¬{â@Þ*Ì3fÁúý>°ZIQAÍ+¦]d·×£ß#£=ÄeˆÖ«¬!a!Ê ·µÝ­í{® à-3Nw¡z¬Œ”ph^·A3ÍÅuÄéÂb?@¾ '½;kkÜÌ¢Òú–(Ÿ­ó=“²¡Ã?L¸XÉêF€ K¡,»±1ÄOSÕÝÊ^­ó{„Ç¢éý ^ÃLÞ·¢~+§1¹GOéïà˜ž|D \eîŽèÍ< ¶7õÅ\B<ÃICXŠ‹w[ב»{3W¹è²îê:¦r®hz@k“Ø “vmB€?öð^ݵøÞz‹ÜZgƒ£Œ™ÞÅ]>¼³ æ“‚b;êÎi>iŒiMc…›'ZNÖ “€/@ä?´uφ±(A¾³N uJ¯W…”_¯µd‹î‰ØáµVLK×1 ) j(×Ù°\‚ËC,FÁÉ(k‹QS÷6Ð ¹xfÃprÜeØ`ÃtúYXìÚ6¢ÒÉ¡XlŽÝÅ„=ªê§þ©ÃÌT$•¿X»¶ÖTM óc©P’D-NK7¶Ë] ‰|þåä ½£AŽ)º{"½ø°uÍ·H læQ {cRÎnú(|1ßÝCØzàöŠÚnÞu*) ÇKß%ª¸]w?É®ûÅêä ùg–SŸ÷‘B÷4lfêK*ÿÊ6ªºrëÂ%cðWõÎ1 -¦Î¥Mò2þáîÕøgÂ)|Ñ_;7D-êoVf¾°›»Ù¤?½”èßzM/‰ú÷E³ÈNŽ=~UÌúycû¤oÊbéxz£KÿäàøtÑ?dÉO·fo3cWvüP4+‹\Ó«%Ô¶XÛ6w+“³“òdnˆCÌBõY*ììifßÝÚ˜¶-›Ú¼?Ô‰¶ùŒÝñ½e‘¾ûeõÂJ ¬=óØW¬“å Qx^ÜÞÓÅÿ`dÆ~endstream endobj 627 0 obj 3996 endobj 631 0 obj <> stream xœí][o7’^̾éeÿÂyYì9‹Q›÷K€<Ä3FÆ‹da'Ææa²¶,ÉFlI‘­8žß‘¼U¼Ùìs‘%'X ‚ä´ØÝd‘¬úêÊÎÏ+6ñÃÒïÉÛ£ß ÃVçïŽØêkø÷üèç#Y¥Ÿ“·«‡ÏÂcbå'o„Q«ggG±¾rve9›4¾=úûúß6Çzržiõ¿Ïþ+¼Åé[xɸ7Ÿ½„§¿Ú³Éxo¤^¿Ù0¸©µàôòrÃÝ$˜µë›c¡ødÖ_â…˜¼÷ë«0šó^®ŸoŽá¦ÑܬO⥄֟6fâ–i¾>­÷ß×îßA_ÒNRèõ÷>yÉ™Z_Ô^/ëåõæXM°VÞ‡—`&ÂÒQ/f´ q*’Y¾þpvýz?‘e¤[¿ÄnÕd¥¥Än=çº< ^¦¾^×ð¾2“µe pÿ²¾_èN+^zÞ-–‘0—Ó¸ÄZyzÿ¤ÒJ–pYF½H¤À5™” îO^im3›4Ìuœùä˜Ã÷>²ËaÌõp£&-”7-?•]:©{÷ÓæXÂHL{ä.)€#`î‚»$óÐwwI ´¼¬÷_×^¡UJ>q.·Yr1 xô,öʵ$Ûp]?l8Ÿ¤aŽn3¹_ÙìÏØ)Ìå´>š¶ÑÙçåQhÔ‚!Ýäý›Jß)v¥&Ç=åÃ˼%¥0øÞúEéà͈ÍGâ2;1®ènFïŸn}„ö“˼Bhþ­N/rB÷=5þ–f§$• ä)' Ó'+ñn#' 'ÒšZ. „…0ŽnúÅè-ÂjGž7úRŽ2ȶÚIÁk¿ÕgÿŠXls†§Ôž5ï]ÕKœ% ß ¿_FÎdˆBÀÀø¿ €so=í©åæÔŠ›rw嘋¸/DF‰°T¶?+bsSo‡Ò`òõP𜴛à÷‹Ú:áDCÎ`;á¾ðjòZQy­òL¾*t_ Ç}™ säQ²Û ß7 'œž4pÉë*df¯êvT–Ž¼ÅŒ *ÀºÉ¸¹fìÞ¹¦ÝÃKfbÖ-j¨¹.øFÖ—×Ü­vn¢£E`}ã±â%ðÿ— ‹·3Íý“µüqƒû*'©·©cÜxã‚)Ø7Í<ï5¿ô±ŒÍ6>ÀÃlã»u)Ÿ÷=Hñ¶}ŸCQÜx7vv°ñáòšv^‰îä<®ÖRg•ÄigAC9Çx³Á(,[ìEî@ö‹½ØT4Kt{eŠŠ!ÈI”?‡Õò]±Z0\uü¥ÜŸ‹ˆN¦›V“á.ÊÆ‚¡ îÆPV~RŒh(köü-6z,FäbÌ)*ý·"R-¡õä¡í$8+ø%ÒÁfÿ:SBQ¿¼ÉJ(‹ƒC*99É-\s`—΢ Rmì4"=„B!aë×Éd™Mˆ ñ|ˆ‹f9z†wKfü$¤¡PN¦?\ž1@gÇ¡µ!ÈR½š,}@ĤQ¬ô3¸š„wÊPÈz=cI 6¡€¬ÆEÜ€Æò¸’ò1âÀ ‹t•`Ù°¡OÛ±‚ïeÆV[2nD5mfáyÓï`ÿ®°dn Sø@åмÚ5f é·U q °fÁþJ8ŽqĕC%‰4b+'À•zRÊ»õW°ùú)1J?úþè«<3:ñAï{Í-îN5ü™UzdÊ)‚|pYTý'º—èT̵û|CàIƒRE6”°wu“"ÑN èFþñMA)ðÓ{yÞ‚‰­¶Zz6¨rX´H¾¼ .¥C®_ÿk¡¥ I͂؊ô5¶«©Ú‡'õde”˜Äy"úÀ#Ç3«N “_´+:#AÍÎn_‚íàñú¼¨}}LHÛ‚04Ôbœ@w Øâ[°*ò[[ S¨«°üzÆuh’‰=Æóác%Œ.¸A_U¯¿©Ðÿº62#¬¦)Ðú¢È<Í%![ÆÞ`fÕ}$b†¬­uzAøzʺ…Vâ6Ü ùeûÃýÙ–]’Ä[€V¡a¥ëlànë2’?ОGëªãàÅvúyÁöj}3¼_À' ¹â1äRg’kØk¬‰àïĸãØåœSìrîôj(ñoZç1t¸$ ­ŠØ"ÂËÝŠ(‡ÈãDÍZöÖ9v¥ÅaAF!¨…¹Yº‘ i ˆŸ2FÉ·ø,€‰°»ÕS z¸©zs3Þ&À‹ÌêÅÄÀšK&5hà-&µõìºØeÈ‘È&^ûjO &Ævx³•ɨ~}5çlR‡tGHBÄ!8 ë‡ÖÁveÄ›øK-iÕú vëBèno%ª)*a‘ô–â9Š”iãÍ PÀÖ¥˜Fظ6¤ñ8l‚G+@µòV¾¶A:eBt˜CAt¾ qÑaøqÁqŸI·÷Ótõ Ïî +Oâ13!\“€»§¨‹j‘O?;«"7c|ÅÆN›aQ>Y)¸}X6å©ikÂZQÚÕÄjˆóE#wÈ ÀÈ»‚™Õ¹kÕz ¦)÷y6³ëÈÃld–ô^uîLªuŸ é€ch‰ŽÝzŒ 0\2^D (6;«fÅANHc$ý…“ñjê€â [ @*?,gUÆEI¶>D˜ö>fP ¦èÜ0¨AgXËÌMë–ãÏ Àǽ.Zb/€EkCñOˆ< TVüÌ‘‡`8l±RSüxÁJ y¹ÖòŒa‡»ˆ:$ód˜õø]·3÷ 6ܱ’!š%;ÎàO ããÐYöËŠöËè=aØöwŠ7Öêçd§Îêõ×z‰ŸüüÔ£¾¸àÑ?Û˜‹5“0ðM^Žø{bÜR¿6#è¬ ¥¢‹EmŒÝ‘xÛë&é Õ;¯Üe¯ˆ Ý[3¸X]FJVçò=.  &&±R`8ËŸO`¾€—¨}ðB9dÁÔt–/^—{°À``M!G–nÞÌ_,§åÞ›Ô„>zvôôè界åÚ@º[ @ŒI9 MKü=y{ôðñуÇß®Þ_ßœ=øaÅü ÿóðÉ_àçñ_Wÿrôèñêébõ÷–E°À2Í"ü2§÷:7½œ/BY³²ïò½¡îÊ•ç¡Ì²9Fd‹Å òã8IuÜ+J0(·3øyNÀXè‰a„qÆŸ9“PýŠÓŽÝG%Æðt9îl΂ý7ÑkãŽË uKÄfkØl wB톨‹!90mõBè°O r„äj*_V$#Q2@݈æ~  ¬ãÎêù¸I%|¢C’PC¨øÀcoMíãZÿ¨ð45ò:ƺ¬þ'):3²5?0!°§gAü¡£&¦xßÖ%Š[ådIÕçV’*n“Åø¦E%4c„%µJvA¬}_ ¡²Ó ·u“%%i„¶V!añ£6·µûãûÎuk¨,ÁŒ¬ò˜ˆa‰àõ¶a kC†k/¹4­ãb­±Ý$=`ž©e“Hf)¿í`‹ž¦ÕVqW \U ¸§ˆçRujBGÊÕ/‡(²tðiT»EHȦíÀ·º}~b˜¶_Ô;R¡èð3~Ûƒp¨g(šB®š ¼Õ•W6Et„czNïy2¤Ö—ìuè úƒ¿îÇ‘aQ€ÎaÛû!¶Ž|Ê ß±#χG–I'ÏdÈÉ,zò)D»—'þ7¨¢O÷ä¹×`ɉ}<ùäŠ7¦e [ªÏæÉÛÞ'ÏÖ0c8è\ù°kf‹+Ÿ¶í0WÃÐÚ»2? ۴ܲ/ŸÌæyœƒ0wã̇ ÿ4g>lóžÎ|<,¸ìË? (¾¿ÚX¬Uâ.œù|ròv޼ňÿ†ýÁÜy :hÒôý»ó•]…ÏåÏ Ïvä%^ °pÉŸ¥Ý¢CŽ?É››3™åréñt“3»‹boïÓ+v¦ÜϧsX*oim„¾X±±„za„OñéS_³„¤¹­E%Ÿ Mb?èЃ1 ¶ŸGŸêk;^[X¬{sèƒo®xôèÓ&ïáÑãù$#Çݹá`f*~ )k.Æ]}^>X2ˆÅe_ ÜaRÑ6ÆG“öO¾†¿Ëº®ÖoÂØƒØ·Åt–øT¡½+Y~ ›{䎥øÉÎ9Ü«3÷»5inëÑ7iðÈ”ÌvØ!L¬À œLâQ´1SóëÐ1ÉLÌšC–$…Aæ‹ÒºË±b% ‹JðË =µVé ulß¶ýnmÜ|ßvßw=È…WrÖ(gÆÝà]ný–9.ø—ÙÀøÿxYD‚óäu9rôÇ"°ÝÂòB¹W7ð~î‘Í+T ‡¯ ïŸúß—¶×åŠZôÉjëï»WŸwmxõ®Üý‚š¶³H4íðUgáã½ÝŽVLeèùØbTÛ5 ¸táH?çÞ£‹ÁòÊLå•ÒÔ]à½ÏM?nÈú8ýæèÙþ}ýMyü²PtNÜ›|uZî¾üÌôŠLê“òäóÁâ½ûýI=®Ü‹ fdd‰o:^ÄÞø³g6lk˜Mb@Α¢áo+R{©ÒðŠ0/YÒ5®ïÓòüÍ€uoë»ÔïO:“„‚w¯PºCèz8˜ôe·œxõÓxï (×~×±^] ¶¨Êo¥»2N Os‹{¥›w\õC!ùUy·‡«:µvB•¯+¿ŸOHÞã„*èpª¢]ëj/àÕOÌ)„šj^<./œš*öUî¿ ÚçÖ"›°y‘ÿéÌüá\Žû»ûOgfgæÁwªW“TFÐȸ+ÎBä?8Fœ•&d¬Bâ·ìtêí$ –¢:?9üXÓÍFb‰A£¯œ5éʇ4Vä:®±è“ÏSnxá¼&ÏaÈÈøIã‘ÙðM%ŽÌbÅ„h&SÍ“vÂ4­'aÏb <·büMÁ ¦ÀñÊCU‚¯Â†©®JyûºöY&0âkXñâ ïÄ<„BI×5‡žò—.ì®NÔ†´·i>ðy: `Í¿ëÓ¥¿Ú*—m£ã°f~b|ð‘©XÉ‚ß Áâ”|¸G4ç˜úxp&Ñ-YÝ‘¶UÛê»Èïð~mFÆIZ~Wdú i ,+´¦¤?&?ž­;ˆ_qÃúGµÔý?)u2õ*¥œ±N¦cr%|Ù)§›†‰'RB°u|Ldç sßbàS üpë“y&'Ÿê‰›B4=M[èë—%VØÛöÙPw!kWBÑPq÷EÅpF@S²ã\0õö=Y5Xt8Ô¤Ih^¬?:·µõÅwÖkTȈMS5΄“œô«rVjWFë”ÊdiÆ­~ч—ûT{)m’ ߉ÃÍYùþæütf7‘˶˜‰!W{†ž ÆÐÃâXh)ätùâ+ÓjV`Ó”ŠÅ)çïš}2*ç¼Ö°2ožAš!fþÉׄ)ê'á¬Í$„^H?¨·\Êš>ï}Û Áá·•?K§CsU,ßÕ4ò.rþ‰-åHKøjîÄžøŠG³YÆŸ°Ú•”_h5V&ÿA鎗 =ŒÕ‚2Ù)Z((Ä€h²”Ñb (†úRs7 ƒÕ'1}ý0}3ó×aÎ~ø¯”;ó`÷ørsýXSÍ”¤•I7#)ÝöeÁþÃY±¦fŸàÀ¾=×ÁSJvkŠÎc£´V|ªWãJ¸úø¢ŒdD¸P žt'Šò°hÒ¤¡vèéÑÿí¾Óendstream endobj 632 0 obj 4817 endobj 636 0 obj <> stream xœÝZ[o¹ .úx~ÅèÃ9ÅY÷˾5‰±ëE¶õ¦.ú°Û‡Ävì ¾$±­ûëKjt¡f4öq´h$GÑHE‘)RÎÄÀñOú=¾\í½’–g7+>|ÏVV"ÒÏñåð솫‡À‚•ð{ôvÅ™7ã°!H&=ƒœqøx¹úyýûÍÖrÍÌšm4óJ{±Þ‹-˜¿>.}×¥uU¾¾-}ïJë¬|½+}KëÓŽq%×ÛÒ¹-SN:oÊ××¥ïMi]”¯§zÎ%^*Ðuš?ú! TPI‰$&'™! Öfì(¦£Œ @[i<U¿[Ã|àFÃ#‘cÓ87ÀñV0k°À2õ!(๠yH-™1~œe‚Ö ¸2ôýØô.·°óº6?n¶šZ¨õ-P’˜SÉ}í@©ë¡Á”âÚ¯7‚%¸^¿Ül“A;¿þ vÊàåúäM1oé6®Òæ•ÎÛ´(ÔøÝ*O~];G.MàžöÞ¶bPœÙétSyÖÿ,¤Æ‘Š;‘7,ŒBRQvVƒšFªª'a×Dà·e§gõó]ùÜ͔Ȫäpú¨ER#Л£P“ëÉÅd§ï*Ñ:…ª4s¶ù~ƒû L9KvBDM6Mzë©ÔVÿ(î+ƒßG»xA¬LþßÈeézŸ».rã&KPâô @Ë@ˆ-” Ì2ˆÀƒðΊ°Íd®’ïöÂØ‚›åL;ã…™(ü.506Ë ¨_”G* »ÆN=BG;2vF¼ñÌx¿Þþ4 Õ/<Þ6è “z§­'„P#™¶ŒsÊG¤N&ÍXECÏ߯¦Ded‹ÉR3e9Èôåêè?xºšb„á¬ß6DDT@Iºõ¯(VÀ° µå Ú\Ò~N763¼ú ú>T»C`œAPÐŽ'$¨0¤± Xž½‚:ÎëÐ Gìhñ$[vq0:C2€ðýºãEîê$"¸> /Á\&z.œM°ã‰Fl>®¤f¼.{”f©%dT/åP«û[!û?GYYæ¹¥n`ôË^Ê]¡Ñ8Ç1ü~ Šy[Z°Œž^ }*}zÄUäú»Òùª ÜÏdätp x·%:ß"‘h;,Ã>å®BDB$”úž“eGܧ¹Î°½Ÿagõ¯s×ÉS3#Kák×öw>*‰øðUêᶞŷvT:Ÿ—‡åÐþ3òæ5ŽXê8?2ÇRx˜ai<œ –F`¦Aq*§–.áÕ6”ÎCO&šËhéò×pÖEþnp6y'!%î}!² Ðcüòp G¢ÏÙPEÂ|ð«dÙ‹fY26G½„/Df48Œn\ƒg!å°…u숱O kd k^–„gÝ&‰kjäP¿w•Ã…çq ,½TUGK¢…ù†r`Z¢÷8.¥ÀúðŽ$À}ãɯº zŸ”.¸¯NÜ~Ÿ›¹¯Æäf8»Cz— ·0ÓÄžáH°yþøE.ñxziè[ÜaÂJªRçTSó»ôÉÿ±±L8n•%‹ö/J½¸ãlÒJQŒ&lªEá±*Ð-ÑD"É4<(N%9µ—ÇŽ–h ŸëtDAþ]œy;WÖa§Rý~½Ÿ\™¾‚[Q¡FJgÕU$‘ë(’UOÙ7¦HÜ?Aç³)6R¯ µžb2»Ÿr`þsOù Ô[u{¹-—àÝA×hÑ[&ï,#i˜Ö_®âŸ'Á¤â_.Â]Õ˜ Æýÿ˜KgÙg_Rþ+Z, ÛöNÐ3ð°å!“ºé€ézväÌCœ`Ó†ÁÝÓ†ô·QId蔃sˆ €dŸ†m3úOí•‚€áÏXU[@˜ÁàèìcSØàâêûG«ŸV­•‹^†à>ýàuÔàZ1í1µÿì`µwðãpûñîtµ÷·A¬ö¾Çž>‡ŸƒÃoVûC$ÅüHG·…¸Dÿ$: …ƒ=| z‘Ôå¹?®ÊØO€èúªÑq 粦Ó0¸;K²Ô‡%÷sTóÕЉ cˆÞ³ÓnBúóîú„×ó´¾v4Dì§2.º½ÿšåaÇ´ìÀ0Å 8êQ`ÞŽ®Ú€œGUQ ,:иŒäHJ0æ¦2È-ܸ¬Ñ Ÿ¥#’ÜPÈýc)ÿÑM„dFH°G® ý,Ò-½.IÐI#«û$d«úI˜i™#vÖ® ;{W™“|ˆ“¤:ˆÏzCåKvBÒMçuU¢%ó™Ä¨“„W_nM^~+ÁOÈ–.Y¸I¤Gch}˜1¦œ·Ó$·àÁ,Óºš[$yRzñ·é·ªž´±ÁÌb“8.bß$×9Oê‘Ìjà¶_{0A7º¾äQ É%n ¶”^Êõ ¼*×Áz1L¼V†B6ÅY#ùL ]Ä~P`üý ˜÷s¸j;­;TC[xPÖ仸õ€/ãìAb]P0×|8R¢ Qeõ•Ö˜Ý:/b¹4/òȱáƒÉ%™3üÞY:ãºò1V‚dnÊA¢Ð!bI€~²!@SÈѧ‚$µ cO3©Kü,„V¶[CÙ¥prPSè\y€-Š\œ$èîœ:‘AÙ…»n’+0É&©q\—°$Ùr×àƒû´’šl¿ðÒV¸q)1³~Á€Š¯˜Rs††d, y ¦-P|ƒzzßsžwãP±ú”«ê¼3!˪ÉV..Í­·Õe½ÀY£NâG%áñÿdÙ „"_ôs*›X ¢EvÙMLbÁ<½µÔ÷“’D¬oÊ^ S³bN·Ð>¯ o™)µ·\ÙjjÞX¢¡ÎyZ"r\Ëœq–7N’>òi”:jq'aWŠk£o}¿àþa:¬Š‰ýž›¾îúñÜn€À0?±P³Ä ™qcKOÊv+­äñ@wFGŸ¾xúg÷Óë¯kÐ_=6Ií-UP{AÃqc±@ªÌB~”XrI6orú,å¾ËÃ]º;×hèA`ÃD˜[ª,¼il9–.š¤û›n¹´lrb©BíjídV?¬ÍŒƒŸ›bk7¬.“Æ×Cu[÷õU }ê“K¬®äM§•™©š×ïgY|º¼Þ}©lTŽè¥é{Òþ+i"9!á@È…Iœ=ÖERè9s^1O¿©—šº¤&àZ-tæg¨Y&GÁ à â~zHÀ„sj§½¤Cl*óI\á4ˆ’M¿n¨3À“¥vžç½ovŸ7GжµB@-\ÞQâ}«A/%à 0ÁkÌEœrgY;ÞÖÀ官ÔçÒ;÷ `A—èÔ`ʉ?P˜Iº§…+I-ç@ú†\ì¯ñðMA£TÏ\ W2î=Ibá3Ì㊸…üBPåCÓ€‰xïóg}Äbˆ™Ô\ÀEk&~[xÚ5çéd ‰ñJ´Wrw¥UŸŠÕgõ-Û4_‰­ãNæò¢3·>8«Óê;¸½ÒwÓù …ë- „'lÁáÀ… ,„>„;ILoØÎkŸÈ}¡Ì¹‹å† R—oá71›Ç'»†®B_3X¸^Âý—_Hj]ê âõwK„XØ®ÒùÔ‘ö®'u¶³´ç”o)7¯Œ!r³Ç˜b)â?žîÃ9ò°ñ&w•Ê{DM™-ÒšÕÛ.æóòçÄu3¯°P¾šoècÔ7mª$êÉǯÂpYgT"o“ZJ¢7­|±Ù­´’ò5qC2ÎäÉ Iokï»4ŒƒűX•6†bù.ÞÂäWpã+2Õ í¾Ø[~?˜ÂÉ/~èýPå^Ð7$w×_†i܉¯¹¥í¿æ~41Ü÷ $r|ìevÿÍYájÆ ‹mÑ]JåŸmI!’Ȳ„jòš1Á÷Óêß][!endstream endobj 637 0 obj 3063 endobj 641 0 obj <> stream xœí\Yo$Éqöq~E¿©Ûó>ðƒ½+ 2,ìXA0´~à°yŒæ —CJâÑïuDV‘YQÝ䈶a[ ¦&«:Ȉ/®Œüi#&¹ø'ÿ{þéÕéo”›«/¯Äæ—ð÷êÕO¯dúd“ÿ9ÿ´ùç·ø™7›8E§œÙ¼½|5w 7^m¼“€ÆO¯þ°ýíNNQÅ ¶ŸñI £·7»;…(¬ÙÞíNääœÇû݉2v’.lßìNô¤¢ñaû«ž¬Æl¿‡÷VOÎêí/Úû÷;s°VÉíÇôhTtÛ‹¹[õ¼ý—´$IçªÌ¤m ›·ÿúêí?üaûû™LÂl¯ÛÌ.ÚÌ>Ãp2NÂÉy9ZŠÔŸ†ËzÒ#¬ÇL@@ËÑRM2D:Ç/Ъ _C¾|h?Ç‘„Ÿ„´Û³y|+]û‘ÇV­|¶ûö3òm[ùöŽ•uÝ a Üv¯¡3«&e%̧cËLƒ<ö¥¥™¼ßׯ<–ÓáðXði*nÏÛ§yáö‘t@º½oäºh­…0ó6¯7u?~Õºý?µSaûM}ÿ±­ð"1Ú¼5©µìòH ä Ädð÷Û=ð4¡ éµ­û*÷ä-¡‰§!Ñ=×+ùÕãΛà¶4F7y¯3,®º.Egùs²0l”À[7íñ®ýªr¬ßªöŒ ¦h¬õ[×Z‘u¤›Dì¶ëº}Ðvn–@ë:´@½ &ÄI™ vraÈ ½o·éAmÞ—¦ýÊGy4?Üן]ç&v9¯ë4ΛX*¬.}<ëà¢| Û¯”š<ô𱑉àùöñO›YàõzÞˆÉE`KFhN&y€²´‘`ÃCå¥6ÀE3Jû Dç©0‡¼ˆ°­–Êl« ð% _Z‚"¸Žó«)¢©€·aj«”ˆdâªè'%aìªè§ß[?ˆ~"œrGG¥f 2[ áD{æ˜y‹œpÈÖ£T‘> )Û¢ t¶97aƹ'REµ9‘~²2Æy ÿ”÷K™NÇì›j\l(ÏNËõê¦W¶—¢´gTPEpQa’Þ-Á¥ˆJîê¸Hc& Rm\Lù ~Ä,mwõ颾=«m÷ÌÛÖßm}z_ßîkÛe¥÷µéciºx :) ‰ï×Ò˜„JálÂn„ ”ÚèIZÚH40ê-pÛw1 ÃåF‚R”1÷ùÇÂÌž†Ëç²q;+dNDÓ~¥ñž“·¼>Ô^­ñ¹.NÆÍ®pÕÀ¤ŒFÍ—ôkâd/ÌLô{di†6·ýÓ÷-ƒ¥t2-u·ƒ¬"mÛbW”9jp…ê<:y@-UÀé¡}ù™}\(¦Ôz•RNsá J@‚Q‹Ÿ€°¥±\ÕH´MÖ ‚ˆ;€@¬Íäíšõº§üXºêQ ˆX¦fXsFä ½}«ã€$ ÁAƒ¿©žJ±¤\LúÄ¡a¢ú¤8ʹ©àRSwPß0î}+:ƒîS²b¢Ê? é]ü>kÚHµúMVhÚ¬ èÕHyZTBÖÔ`aÅ»ì¬ÁX ƒL96Ždˆ@·[î}ûQnDÂÛH,ð ýb⤃[‡µm¦³¥Q䤘4V‘! EÎX("Lv"ù~¿#RÝ:+lcÂAJWÿu]Áé¼³(çœñŒzæsiº)«a\›ÎËǾüè¶×]Ôú¾\¼j}?I­&º%Ì„g„Qk+ö/î/Ú¿héû" *¬ƒfáÊ…¦ÈzÐÓàzÁÔ+è-]¡IèlVcVlÖ!˜qéšGº¾Ìb œüØ&DÐ塨éšÚz7 Sxûi¦<üG®á^Ã¢æ• »’FXq†ÎYcñaE( îyÏ ƃ^X£¸©DÓ”¾dì ƒ90¥Žz½O±ÄÒ 9.wvÀš–{\qZ²‹õWiF;5Sàî >S™ÔkìS£t¯YǼ·'Úž40´þ¨v2àÞ·î{[[¦-1ìl†ÏÃP@Æy=Â!ø0FŸʺò¯Ãe'ìÍFÂF[ÄÛK´Ýl”Ö”‘LbGÁ£ L8*˜²`KD¶UÁ¢£M»þ›ÚuƇŠ^2ö›†³±†—ÁÍl‚?"&LåCµá5œ· ðYÓ9­ûn¹‘LƒÄ·NZ4šüê‘uVy þžCÒ/ xø#ËXÀÒ{p¸íŒÐ• Lç™yÙ›œÈÜR`êçP(˜ žŸ”Í®v&ñ˜o©Q6t›Âr‹X\úª„¨¯tqŒ1™Æ†Øú`qÚ^¯ùôUOÅÙ* ä÷÷¬)÷®9«ÇìßââECÉ–þ;¥B²áVl*"’7#ÿa¯äࡽ&üò„hÔœ$8Å+h[æ½"3‡š A î1û°AÖh@O!¢§É~µ€õéK t·ÀùimûXÛnêÓ9VÿÈüöÝ`Ë7‹ßžÖ¶/ÌÛ›d†+á™°£ °A?xÁðÈO‹þ0ôí}óN‡9Sï£%ζû]u(î—¿«S¨(HçÒ’SZ¯µIþºiÍtÁ·³”`N:oÑüÜþø# ΤÈ-˜ª¸å 2¸$IKe4 }ªoo‡_àÓ¾¾}v©Q ß~böºñIëïn˜AÏcziû#Ø÷ÿ¸Ü€ûFŽO}æÞI§€ËÆXè g`ø°r⣨¬ÛELµ×Ü1îÂgp?7;ŽO§±!à!Úœ58ŸÝn웫ºªmDk¯ð Ê˜ÏŒTäÍs‚ÉuÑäˆÂÂL¢½èO) :…µVó…èÇŒÞÎh˜ËO¦FZâ&CçªymÆ·,’¯ZI±ÑC:D, m|ÒèØ~ôÈì¿ÅÊ.ÒA§ÐÁlÖn4ƒÀSOªÿŒö”3%ɘºâ•eë•amÑÛ_mZßÖOŸ¬65F Ê)’¢,oêSSU—LÎXÂi5e˜Û£åˆ¹=J˜ÛëÜsû4øˆ¹ø¶¡þÒêT%9SQx8ƒß_7þ¶)¥Óå‡FwP^”c£×2þF÷4´û@D{rrg ñóÑÆêÌðÿ_Àõ Úb< 7¶èx/Þ 1àWýØ™0†À%#¯.ò Aþ¸Kï£,s“¬†S‘!z7ÉײX互Ýeq Z´Eá„ö䟜,¹„c¾d§ –±’uÿ,oõótYRÅr–áÕEt¢ÆeŒ¬ÑlýŒËÓ¼ ˆés× OtíQÙüÝúÿà©ÿ.qhNpYJ÷îË`‰4ë¤gáûÚ6 ³j[1çUK[³g¾-oq Õ¹œOÜÿÝ&úßmi!§|Vƒ$«ŠŸ™L|= ‘U'1.ˆ¡’T3è/٫椹½2õƒqRõu²³ŽFåm¦æ>;‰è\b±ñç~Ô#Z&Q´ªˆ‹zË™Q\¡;‹Pì,Oì ÚA=ÃgµNÙX4ŸÃ9¥ÑˆT#žÁ]îb¨=x¢ÊÏaáƒÙl.˜¯Mfë–Ìþ!Åà ¾«ÙÛK&ŸŒäŒS ×RÇø’;î“ÞxCJ”¥ÒÑ›¹U)[dc⻥‘秨—¸&3ú2ŸîÐ1•UØ—ê®ò—‹)amÆ$ƒýÀäÔó8b6†:«!¯aVæ@Z;À6ëNæÖÓÚø­ôÛ>­]J©n)ÀÔGšé…؆’~JœØïé ¦Ç"!2ì Dì–?ÄyE‡…Á€Á´f[J¥n94hç°y§ëg&,ãÁé‘L?;ä¶åò¥2þSš-fsmPËÜ2Éè´·ªw VÄZhÕüÞk‚ñ™ÖaûçȽÖýB‰'RöU„ÖfÆ0«)î(Gûð½î¢h?àPsþEÎëðHpŽ7ãèû!ºŒÜô7Œ:ÃÑ"9§K£¹ødÚZ _žc6JÓVW{{J랪•“­gñ’`­¨—B]Éä¢p…øÑb%»½V¥MáÕ^X´ó“2_`tüyÚkGtüÌĈd…O´¥¢i˜*ŸDŠSq­z°´ª<Ãi¸ÑŸØ(Õ¤+¬°ÀÃôB­Ln’ÑM+ç³#)Àlcþ Nº æêEí@½= ´`¬%lʆá{«T'CI Ì]IÎöͱ0˜Ñ$„bz¨â:z@ä*&Ö“48ÀÅz´Ô¨Kr¦¹Ï¹€Í-óßTìâýñ•‘Ôzæ4Wš¥ý듌‡äµH|sRŽ}\bÁj?j ž([<‹í1@¨¸ óCûÓtÅôï; àé¥Mt'‚y™$^¸bˆ„•š‰ÀžB.n”[/9˜Ã•jÔkNRÏá¹µfiµúÙ§[f{ `"%Ëý±Ù–±ºÂgÏ îÍŠ'ÄfÉÞ=–ݧàðÂú4ícTëâ8“Æöâ­!u¤_Ù$®{×¢½í([ƒ”öÔŸ•›Å޲'šùZ§t×[˜…§ÅÌåsµ1Û ‰¸Ãoå‚ÀŠÖ€C6ÖH¾†M|ÔJ®±(›ÉÓÏ ÆjK»jÚûC¼ ü”?g7Ørѧœ&cá©@“? äCæ%…•ô”UvnÔ Š;ÿkÝDßsïWpª#SkåWýª´/N1ey¬²³lÄb8˜Èæ fàr!yÐ'ÉS³`!ë Z~–}¸¡J$QôÀ!‡Ìм`“Gò[|t ¹ãáÅsd-û´Ù/v<|ßK0fÂD±¾HiøVÏ_Ž%{H樯Š-Xò:ëPïi©gÀÜÃŒyK+ðiLâ,HÞïrY˜£ô§Z;;Öžøæ²Š8o:¬Ÿ)XHÉû†—º¼Hz6—» ,¹ôk¼ÝKÄNYçãD 6yÈñN·£y⺸HôfŽ'$ÎWähåò•Ðû(°zDÞvÞMØs ¸¡M,fW‰Vø4 Tt£=žÆ2‡´zš-ѾçkØÚ£äx½ŸëΑ¾¤²O™5ª„1£,)´ÌÛÙ»G«-Ÿì_ˆÐ;Gý ,1àÁ‡ ŸfëÇ»'ÔËÈÖÛ£ªDθÉÚèÚ—¡wPðÔ5à\´b¢‘œëÉ?VC ‚&²s6hÅÄä4Çw»d¶)—)—W²-µRíò¡6~[GjÎ^¢‡œ¯ò™jš±eï[Î~Ì.IÐ9õhU—×­ óÖø'®ñ®5ò9úej—K»yvlœ¨Á‹Z‚ñ‡q>Y¾¥M–¶X;Q¥i*²¾s¥)ôá;¹øXæïkç†æ£9rÿ’LGoæM{NÞÆ´¼M+þ»Šî„4&š@+ [Rç±å;V(:“ëül~QŽ˜Ò)cÚ'õt»c óäNJ‘!Iµ±IR§V#’4Sû°&¡.fÄE‰#=Ž¥ˆ‚OýÌÐ7ËâÅ–AjÓzJAãçZ)éÕ€ƒo6Fзz éÌÖˆŽæ™Öú³ ­úì‹„`¹jƒw­¥Bûþ&¡_Ò³«Ùs‰µÑ®ïã% ¾ù$¬=6D~`™:.Ï;kœÆò†±"+€ÜsÌÅ"Ê ®`%ã2ÜU|à;·ðo¾ §”,Á¹^/ðµcWƒº÷7I°Ä‡”Ü‚.s¥Ò³eÏùj— W´ˆ8 VCãÝ›À‹|ô¤PæjRÂäØ5F$¸.#`ˆg.´)f`gR&SvYx8ç…Û%ºn±ñ8…áî"¼lÌÖ¹ì¯õ›}¨b*Ó“;œÙçŸÛþR¿%Þ›ÇZ»&tx¬Qßtø¥ÏåfßwYø;x¯<Ùš›7øN˜nî¹ø%dcÔaC,_U'ò:3™ì\R>&Ìúnwµ¦C„þ> stream xœí\[sݶîäQ/ý ìSÏishâä­n<©;Íʼnfòt:²nN¢[$ÙiòCò{»‹ë‚¥CI'ãN;[4 ‹ÅâÛowAýØ =ëüžï=û’ë¡;½ÙºOàïéÞ{Ì7éâÃóîù>63²c¬wJñnÿd/tÀ:Ã;Æ~ÝþùÞ7+¶Þ°ÞÅܪ_o†Þ #äÊ5ïªõÆ9Õ+'W_­Þäru‘¯.ÃKRÛÕõš÷B ju»ÞpåzÎÍêÓõÐK£,3´åQ~ýß‘NÚÕ ¼ÔKÍŒûçþßý„Yçz§¹–8.¡og»ýìíÿé&Éå ÊFõÖ:'p¸tƒ’ ËFö „v( s¬7­Q­Ó«ƒry ¬Ÿáeéìª\‡¶.C¿z´ƒ[˜¤Ó ræ›Z˜’«ïÊ]ƒú¡ÚöM¡t{\ºÅK'{90PXnJº=Y3×[X%¸j¼ßì4ªË¯mzmÔê[:®tÒ!>c:ÆUÀ NÐõ [ºŠºÐÂÒ®È[g^h1¶ú;нRIoþîAi{•=|» S`*¯G-H# 'Ëy¸Òƒ6  4 .T/8ÿþü»µ‘ETj|ùÛuéýCԵ굊úõB• ùëemh¨tE%Mй=z¬M4óÁRe·D v77¸·LÜGšI:Àe¹¼¦Ä}dâZŒÛž•ˆà‡Å6¾«÷I¼›,J9Ú–˜TÚ=`¨¯k-ÀîÖÒ׈8qB霥`ƒ\–çoËóë`2uå’Í ã–ll·‘ʹnÃxh:ÚêR÷ƱéV÷Èg.á2,Ž“þ&WlB-.†^1ÞØÁøÖQ6*ò­0€¦p]ŽaÔ_¢¥ô  P”Á½PvÕÀ(¿XøtzõoŠ£ ©‰}}\äµ9(/Ýæé~×µÌ5¼WI{‚ºW ¸ÀM7hUk#Ti#®Aò:œN©êµXXéßgÁC{¥+… ½UÑå:u£Kô»/A,+”Ÿ5^Ák ¼’7Mº*OÓ½¦Sdã±s c}U@̨vÁP#xÅLœéÈø¼g‡ÆZÒ…A‹Ò¬—Lwn`/sd€6\\TÂrÉÕ9¨ñ-Jc^Qp-U®†Çm=éYtíjÂ$¹ẟ¤Ði’èM¾È ý*(lª¾Ä“ËË5˜ ³°/Búe†ÁjÖö§qñŒ${üºP”t•–ÙÑçoà)pS îÎfü‡×r[*i\Úʇ_A„>¥B7Öëz R´6à¡{¶Ð)ƒäw8/ª9Ä[ÍÄS8/dfä28"‡ã#” ÒX:‰·Õ¸aauÛù{ÿÖm<ßf`jo¡­öºn·q!~;ª$°^|Øt€h¨BöFÎ9¶´`J„¢X0p¬" Ê ÛŽCl‘´¯ëµÕãÅjÉâ´¹mŨ9ƒk¥"1ó{홞'„~Í-#,vbù£Žc pÙîE €ŠãK„½®}ø7{ZÍj¨Hoߎí&mûØ´6Ȼܠp¼ç–u汈Ѩ¼G3&ww–nÈ<2Ç[?Ç çÅþÞ«½;B^P…íŽ]-vFd1V~þrïÙËO»Ûë·Ç{ϾîØÞ³¿á?Ï¿ø+üxùq÷»½/»W³ôüT$0¡ÉTÎë©4Á4c"÷¬ß–#)ÒãAE‹ƒ’1ºóPѦÛgaÀ‰ðd¡N$Ø•¢øQnzßÊ1fz.;p¿¨`/ÞMƒ¡”e¼ÎW`œH{ Òßä{¯Ò8.Ëœñ07¸Ì]^ä{'#r„OOcçZD[ª_nñ©Ãüôç|ï_ùê¼1—£|•¨®2Scˆ gw<›o™‚5â¬!hz9Ϥo‘yæAž[Y»›†RßMç»ãTà„ ÌÞšqz®$2Nsfã&zPNó4ÅWÑlû6àÇ«×Ú[Ø{G<“`„m~L6zQ,†n ®ÜI¬Ib#%Ñæ†•Íß~ '4ÏNè’ú›@㜮 q#åÓV~ô¡x6MM‰´Wô42G"Gäy[‹†(Ýêצƒ$Dî¸IAI[’¯!ó¸nâ;qÇäµÊC$Po?'^V‘çÜ æÂüm´ðÚ4^ÄÄ©cÙÄ¥Î)’ÙÔk¢>¯§Ÿ3œ’›”]3¶ù´É<5÷ÍüŽÁÃC¥¼Òðx ð`/[€GÈß8²×JÆ®Í\O‹ÊHìõfBÓaüݰI =’CÞË•@Î*Ë>æ~ö…SÜÃ…ÈRpƒ‰“]²GaÁ?ój2çÓÉ¥[ÛñÇ׬êó=dÒˆ>&ÀþÙÞmº8ÈÏ®F‹3Çè¤4½´etôíGd ßo<-lð–2ô{™Ÿ„ÀKñ$]®¶-L>$tÝd Þ_kÛ;eíª•¥E¤Ãà«[$,D…–·“äõ·M¡ç+|… ØšÍC±€˜®^é 3ÐÛøß|Iy~‚7Áˆ¸\ä ²(â,86þðì¥ç}’‘b\•‚`è7Ê.Y Wêñg3cWÙæXs ¸Ó…GÔêiëÿ. ®ÈKSQ.B/ü  ö®4”7­ƒòȽ5ƒ1³šÁn÷ÌU Åc¦8uDòvˆ2ËIªüdXnŸ 4΄UŸ0æQ=ÈÃjŠAØRm]¯±=wÒØQ )4ð…P›Àº´/4º&Cž·1 ®› "‚‰úEÑ­ˆj+ºÕë¥N†‘ðÀaÔìáQŽ\Ý‘Jô ›«!,ñ Rû-ÃB!0eãJ~ÈRr e'¢(F‡Ô‚uRlQîð €]FãÀ¯×Öµ·zf‹­ xÆõ@{7ߣa%´êõà„%_Xp…ÝQñó1ãHlv¬×{+X{ʨËc½¶£¨+lÅöNDá¥è'i4 >ŒÏØ,%¨žE'(@ ȶU=R@há_ÙùáäiyÑ Ã¿71€ÅGù­-žNÉÇ—–6°¶dJ äõ(gTÔ‰O7w†Óc“jVxb9iP=»™<ûŸ­„Á0?©(éš’À§ ¹~zZ2-€ÆF­ ã ŒÄÒ gé;'mÙ' ÌspþMÚ;<(6`Å ÁîkÖ@¼GìôCÀ–‘Ä2UëÏü±8ö»ú|-B+‡a ð°³¹/ð’ig,)…ñÇm"Ì8°~ (3(_`]€2ô$ú‘~þ|f€?ÑéOÎÏÌmƒ%p¬¥7KàׂÌü&F ¤ Úžº™GŸ3©kM’KÞ¹[±­Îb3…x<Ìrf°Lša¡›ëÔ»,¦nƒ¢”êi¬á§›pQè|²îºát¿ÝëCâð¦Ù†6Ê=Ù”æPNù´ÎÇ»çJ%éd؟îvÎï0®ÑzL¸šðúšÒ––÷›rÁ]kËqYiç/„Z¶ÀµŽÐ¯) ê€,MiæÚ»¾|ÔøhEeœÜµ¢NE-)ÏøL¡xŒ’èuu2.×Ò  a…)2¶Mp¶ë#Hиèí<žŒP ¯ª³!w¢Ø“ÍcÅ`“¡¾Êžg4:kM’Èþ„Èá+H!FçÓ[ã¯2Ròbšz õEËTÛem/@Á]kן`–SíâælÖ¬É4~ [2j—Ϫ§ß¼·R!¿v3tîZ» :ßcíŽKÍí0Žäz`îrõÎ`.ž&²Æïðw\àɘËž‡ö‹~‘au\áÀ{ç£Î\*ÿ—iÕã^p~² ϳ´<ÑÉ~F(fó i©áµjÿR}üNËY¸dëì69˶Ð3¨ŠÆÝV•«;x×äŠc)–jC)Ð0)C—³}øøø)£åÎfbªx@Éa’éRŒŽ°„ýåA»kõ%„}ZõŬû©ZòB]®¾ÌòÄ@ A³óÏ.‚Âßü!b‹¶^å{g -ÕÕíÑòÉ&7+])êévuýÁZÒc : 1kÁ· ‡¹k=Eø{¿µ Ð-WTè˜óß@>è ŸŸÊ@gºóy »É÷®FD²>2r´-Ð=ÝäfÎô¡;lR=‚SUà’~9R3o™7îsò[ î´kÿÛPÇèS‡"zUÑ¿†Ã´c»±6FçM—h#ÁÖε‘`ë}WH‚§(dž¬Ø=¬Ä³LûÄÙÿÏ<âì@>z=H·§½n{ˆ`~[ h¥¬°~q_ðl®jj®¯öþ·žEendstream endobj 647 0 obj 3898 endobj 651 0 obj <> stream xœí]mo7’>ì}Ó—û óqæn§Ý|'ÁÉ&Øõ"Ù¼i‡ƒ"Ù²aERdkÿû«b7Éb7{fzÔœsÖ V£_ØUŪ‡O9ìŸWmÃV-þëÿ^þtöì;®ÛÕõÛ3øïìç•´Ž7Ò_ÜÊÆ® 7M‹Z†áÏžŸ={þÕêÝÃ㋳g?¬ØÙ³?ãŸ}óGøóüóÕ¿œ}ñ|õ-6ûvo¡Ùhh‡9Ýð9í´«?ý|ƼԫþÏåO«Ïνälå§¹–«ó—gNlelïqð2Öp¸òÓÙ¯?ÝlÛÆ´-—v}µÙªÆZçÄúb³eÖŠéõ}:ûnÓB«Jq¶~‘nxØl¹ |ý6B´ÐØ]÷˜5´ÙôÔÿœÿåì‹ó³‘=˜äÂv¶Afƒ ÓH›Ùâû kœ`­\ßz‘cŠèzÊZShPå&XJ€vÓ£´X_LJÞnD£”å|Jaa¸EE«+, ûξL²ß%o£ð¿‹¹F…ec4ëýØÆÞ$×x/7¬m„Ujý>ÞJ !ÚPR0ÛE33#jž¤×#³ÃOسŽcÏ•®Òaç·†q;ÕRs4Zýn”†5†gâÞǰ…ÞéœT¹ÖRUîûînýÝF6 œ_®‹½ªr˜ÄíúϤÝÞ͵°48zé¶o´’sêäÞëxï” •îºþNâsk|˜/Ò”šë˜e¨o•˜)Òq0¯Áжw‘o6L@÷HG‘Ýc“n¡ó:”rRBß·à]ë¿otô€ûf öbº)ЉèÖ6VànM¦ÚÚ cúiÀsê!¼ˆ×.©wãç®FÏÝÅk÷ùíÆô-áµ·;®Ýä"ÄÆ©œ{džÚ.#M¬È]† ö$øïK8^FÂÚB«–ƒ§æBJ ëfÄVPIýˆ4_—)ÑNÌoª#Úq‡f®#V¢¼§„‘åtÛ#’Ã8˜iw›¢~«[<Ï\¤¨½§Þ¾Õ»*†/Qæ©á[_h ¦r¡ÿJ—З@·…\¹ÙІ;+5½h8bmôìäã½'Cݶó›*…ºmërÊê†7ŒŸ6ÔÓmc ª}Œ¡ºËgà½Ôªëà $ƒ¼I'ËYAŠÑ©¼#¸ùW©ºxÁÖæ*ëˆ%]Æ Mk÷‡'C¹ô•¸ÐªL¤¶ó›*¤¶ÿÖHåý¤¹˜nû¹Ñ®ªÝULfÐUµ¡I·•Ó3„&“ë´ 6ÕîiM£âÿ°úg™È*nåŠp7.!ÅkÙa•®=7âØ|µ'qLéùM•p £jí3â˜4ð'űÅtÛCôˆjÑ«í2F{¥3³ŽàtÇ À><-#Rm¥["JÕbKóU™D)æ7UB)Ôi Ðð¦O‹2‹é¶‹-µ™jÕ¨Rí~ò¡­ò~ªÛÕµÒ¶+†­öוˆ†Ö•p6ÐsœXãný8q†®+׿l€ ¡m€À1Üι²CXÌ|sNâ‹`ó›*á‹èhq}|á¼ééäóÞ¸Ú3¶JŽÝVº6ÜÖ#øÜG«õùüÊÐ¥ –ö#~„ ÅÔŸ† ¦D£©þ‰¨tGð !6·ŠƒWÐòF ðOöö›aoµã£›W¥ÎQyò^U9ïæU©J Î]ÔîžšRékqÓùªLzsçÊ‹£´3÷× GŽàƒ†p£Árúïå¦Ôÿ¸Ü´ºCõðIŒY>N±,…ª´|VïžwSéÿÿy÷ZO"­å|‰,ʲ¹¿S8ih„þðv1ý÷ònb€òîß ï®ý47õŽêSaÕ• ä•(U‰¼¡Ê$¤jg—XL툓LC ><<]LùýÌ5¨ÿL[k»R@Ÿ`ÊúÐS]£žø>Ö7_åIˆR0ö.°ÚiO2÷£$@ê“ç~\ƒ³œV;¸œ.Á3½ê|›Öá|䨶õ3>ÔÚOñ©.sà>DæZÜg¾*“À"[bGIГLãÿŽËbZí 5Já¾ T¯·ßµÍ’Hù䀬-sH"s­€œ¯Êd@ ø»D%]t.\? á=îÉ•ôCr1­öôD¯x¤¯íF}ýœ»výœËʉH_?'*-X?¯Ý4‰ôµ@s¾*“ É!&—(Šc쟤(¾¨ž\?4Ój?‹!zÁbj›¿"dm°õê&J=Ø•›Úýj6Dú l3_ëI\jm»He¹5u·"¸$Aõ“q¹Å”ÚËåˆZ1•«íD}M™»~U¹¶N=":ÕbCó5™Bé–Ù7Ú™»ÔàHÔ±i?µê°³œV{ÙÕk>ªnþ¯DÊê[]©°D©%ÉÁòO†©½/ß”)Œ÷ÆgáŸþÑYaY#´Z7h'´å†žnat‚Ì5_ÿqÃ-ó{ž…ë·@!°Fãb`l–Ãɇ F@@Ò;o™á¼2òNЙ )³¦.Á´±L™õ› ãh7_¤“éØ!£ÎÆ™pvuþåÙù¿÷Û(s9A„»„ Sð¸-äÿL‡½ˆq›üBZàœƒ»˜õùŒ9D î5K»K7 ¶0ö¤=™ÓýžÎ-…,d² × 0:b`ó^”|KìÔÀ]ü¹úßÓå×?¦ðhÁÌݯá9³4jý7I‚¿ö„ßÍkC£†læüE1­Šã p"ØÚXÝkåÛ|_t‘ßÊà´´Õ| `ÎÐ=B¯Xφ¼&:Ø—î~ WÑu8„«ÓçWW>Úq*Ñ]ß6¼†èžTNGäqÑ6,LljM¶x&‡DçdqòKï·ØQl©‹ž`èÙW¹4蟒‘ö¶x8ùSptFåh18/S‘ߨ§\3æp! Îð_ÖP†R<ß5`b®Gj™r»í»x‹»a'ÿ¸§Z» !€¨:È ñÇôJ5/# ![±·«ú½Xÿ‚ñ£8Lf˼‹Â¯õGWà-»ú$Y‚§šê« /ãÑÝ =šõ< î¢Kk¶ãÌæ.e/—áÜ"^e0~g[ÑLo§oZá©=RwÇ}7$/!æû[‰ç…aï¼ÛõS(5 3 z7÷ídOð¥:7=äIu<º‚ºõËô•€ÇVxDBt†).R4—÷Y'm½ïñSgQðmÔ@º$žïã©üÓ¨Á«þ½rÐÝw²[_wƒàX èƒÛ$ë×µ£~’á÷¬‹Kæ=§qR)ï³[)ü¯>·ÜtmK3YŠ–M+Ù–ã¹|ÈR´FâV‹¥tõ¶ÑØ„¢€¬¤§(&zmA¨cb`ôè˜A»2V¤ “ã¡Ç§Ê4&(x<èˆ ZœQ¦¶6ŽTö¤íc¦¾ òXëE‰“$U÷ L¿ á¯e»6¼í Ÿyß–ºbÑìuZ¶¢R¤õ'á\,Ÿ]ĦâPô*üá±ÈoÃ3'¿6]ï‚>Ôâ¤wWé ZçcBPèc >–}î„d [ ¼™¥ÁI„–u.A ¢ü…RÅ<>¶¯#ž´Ú‘¶äÃ8<61åÁX·K+<½ÐçTvp!&pЧ‚^EA_G>ùÉNg`‚AvNÛÊ6 ƒ8tøE™0ζ‚Z÷¦È+ï‚òÜ‘RÄ„‰ÿ™1Ø}‚Õð!Y\UÖõ„R²§dxt7VÚÿdÃâ¦H‡=›_šF1™jÚøÈyq8z¯þöF]—º_4HZáC/ zÝKÁeÉ9×ÿ;¨ÄOxtA8ú$^½0æ¤ ^}Ïeºl±¬ R@ΉˆÖO¢6ÃFñÜ»x4l´¯ig…  #°ÊÝ!¸Õ}F¦“Q—Œ‰[ÁÛ®±wj:] äTYu4[$D‚œ8ŒéÆûžMðq¼R(ZñHÓò>ž%Ú¶aÊ Ò~C¤—tØŒÃ\I4Z:é)fà¯[w,]‰Á”0΀ÞWȽ„/ƒ5ä„Ü7=ïU~‡âž[\ßÐmƒ( Ï·A ÜË6[¼Â[ø£—õEïP0ªLÔh¢$¤ò{쉱ÂÓy¡ ©Ã¤\ÜÓòäDp¸[hÊ4InAÀ¼Üno.§{s¡¶HĤ£ràæ›eÂæeº`¹C´¡4É cn@v G™—EF€ÐSþÐ@ƒb¯ôäyŒÌ—8<ª¦ ²ÝõºÚ&Œ†â”ô R—ÏQerëy¢l2m/Šˆó*j ÷™_ @3Õ“<_}éû÷ؾ@jJc€|º/ŒNÛéÐ÷Î Ø`ÙAõ¶X«ìA @xÌð5DCY,‚µY%,ì?Yà7¥ârÊ5È·þ®Jw–%¹,Z¥øþ.QW£< R`ü’¨ŠcsÙ‰4:äN€jý!ÄZž‡[Sí­ïùÞ\qÃãÁ‰˜%J”êqí›wPsÕúEh»úWŽð7Ï@‚¨Ãb"ªq;>)”+yC©Ö4+ 6›½t,VÁ;‘ç;­†jŨTS¾òRôå,ïŠLº¼zà*1 òcÅzÝuë2«“ÁÐhL„`‰âF7í0†»×ºIäGDA C†¶¼ Ñ ž’Lñ^ųù’õäåòç]ƒÒb8ô(HžGª¬'Ôš¯FCE˜šò60Ç%ü~u„Áž¿(Ž…Î-L9PŠ€y­ ³#ã;± ð"R‚}0e5°&±¦ÛÁ®÷˜Î ˆ›Ò¹eæ!Ž‚’Ö¾%íùÉË yÉ2âg#ŒË×WMÏF@^†èM¬²ÄlD«F³ü[&°B¼Ú·à~2üê Y~vð,ÿïü‘ÓÌO ö—ãI?ó/[ݱðOÍî¾®¥O߯§/ «„g2Ò*©óëØÖ_ÓË»µaj€/eõU†¯É7§ÁÂB0Ÿ]$¢<ܻʵO38¹ñý ÄMž9²‚méyÌmp‰¦¿²'|]*Öjqƒ‰ @„ä“Õv2ªùÄC[:Gð¾S¿uvfÍ@jhE8•˜ö÷1çò9{Á5vì á@|¸“HG^TyÈz<®*u>Wæ‡mqV5›:~Ö,Y‚Oq€Mpžó‰™èRÁÞõ.6( WøÑ_+l)u&ï f0vÿèò¯qtɾˆ]Ò$´ƒG Yžm'ãBm²äUt/·Ìä&#(™a,îCO³üÉ2Yu¶í»2ŽtW¥á <¿ÖÄMöYJ7tPíò›*GĪŸ­²¤³Ë±%òþÁ‰©Üà,æO’F¡xHîôN2pTÑ^MŸJÆq¾? Æ/Gs8×ñÚc¾b€.¦Þ=ªJÿë*×SGUL ÓâNQ0ÈPÏgǤK‹s•ÛôðÙâÚ-VήHCèÐ eq(V=Þ— …ÀI‚ǃä–Ö1?ƒ«”\ýº„½\¥I_H »Äq¬ûg΢˜ÓÙ¾@Á†ÓÙ½ä1"öx1 €^©†“/À„2ߓ݌ Än£cMíߟEÓõ`ÂÆÙÅï#~ƒéO1:þ>W¿¤ñQJé¹ñ?†·¨ê)=à‘+)”„G‘¿Žç¾‹Gç{+ÚOžD …ç35’ _Œ-OJýòù·x ·¬Y1 õî-GøNz¸¢ë0[}sƒà:C}ôœShÑ{NÒ"ºÁúoQ‹¯â¹oöõ€mO'»¸L®ØÑƽ÷¤sxôý¡®îl‡˜G:{öx=ww¶þ~·ZÎßO¡Fçî™IЯ£çƒÞÈ]ê‹}ýâÚ“õ‹ó•’‰~™Žà©±@¶Ú£?{¼^ÿývŠ((h´\œD. 2=J„!yÍçûz¡Çý“Hßá~&})LÏǽ0!=o»=ÞO!=GlHcò³(ò—ý©I¤áa£šð­§´÷ý0‡ñå‚ñÎF˜AüšîíRÉ÷SŽ¿×“`$Mó ä½a¿=û?úÌEendstream endobj 652 0 obj 4804 endobj 656 0 obj <> stream xœåko·±èGýŠë§ÞÑzù&ƒ¶nŽ ÇvlEÑ_’H²"Kyô×w†ËÇËÕÞ©Zµ@8G/wIÎpÞäŒ\õ[õø_ø}sºwï×ýêøÓ^¿z Ž÷~Ücþ•Uøysºzp¯)-W®sšÃïáÑ^ßY5¼¶r¼ã¶g+Ãú®‡ÎÓ½¬»ì¬PJ®ï¥Öß‚Ö}KZ¶>KÏŽÒ³©uœz¯Ò³‹Ôz·Ù×Òt½àë—éáAúäqzö4µ¾H½OÒ³ïSëeêÍ_ú:6žûs‚ΈImDë‹Ø8LX~YbL}Ž¡q’ú* Cã^ê;}wšúvCã»ïââEûÜY#Àý€¥»£[ì=l|›{U³aëaêý¾êMˆæN’]xA¦HT—z*J½dsbïO¹—lOì½jÐó="QÆßžR™{´QPü6X Ü³)º÷Œb’ ŒÒ!Ï2†Gsgê~ÔXEìûŸæ DªFõ ÊÄðÎ0çVÚôÀ*ƒ2ùû†õ Pûª³®mTÀAäh‹ŠeŸuZ+¦a~ß”ð²3R­?mD§”“÷?¾z‰˜ÎR/7=¬D)ÎÖïý Ö¹8™oút¯xµïðÕ<ê‡üýqþèlhZW…³žäW?áTǦ ø8Àe*½r/p-¢c ß¦¹B¿výÛ ë›$K!Ýð Z ~Ú0Ûñ¾q¥8ú°RÑR~ž–¯"¦ —ÄY×Có‡ôp˜Ý1†oÂL(ËÞì÷é{«=Ëú…hŠèyúãÖH¯<3qÕw<²Òɰ£®7cÜãŠ&e縂y&:bŒÌ©¤Ãe~úž"‚(Ò(²æ_óòòCò9™•¬¥Ûì‹^vøp)¬ÄY©ÃT~¬8—ã`%Ág\¹ÞF^ÀQPJò» œG‘Mh•`ó8nÎ a•ZÿB±ÝÂâùð‚îÃL/9OË,½ÉŸ½¯3`€TK g*C< Æ Ûí8èOÖYã̰í#îõòW!y§¤C¢ôHc‡òÙ+*ÒÓ8‚¦dö+$'é:ÙßX@á`r¬¤‚²åf-ò çÒ`‚Žp–_xe  Hн Ø%<þ±^Œ ßkFŸŠ&Í‹Lš„^G†Ï2¤dˆ¸Iä)™êuúêdî«„"]H/%@*¨$&&Ä |a$èÊ(Aô1%À4ÈÜô-iç—Q•+xÙ­yØ!#ן§¥ pÞ¡‚—¡ÿÿÜ¡º‘14L>6@GŸboea¯È½ì¿f&êŽ u™ø¨œ²p£¾Ï}cWi€!z1ZbFéƒøèIÆÏȆ<ˆÇ©ïÛZ¿äØÇw2{щ@þY„ƒ äÚ/êk$¿ÖÙœð˜ÈÇ À[Š+`U§n.«5hnfèW¨4ëd–*ønž ¶q&¦Â&1WQƒM K ¸°¼¢€jËÇ÷-F5t("ßäW²4³8@ÄðÏÐÅBèÂt$kÉx+«ðð8j0×0Rü»…mÐíˆ^xì@ƒ±§d6ÔÚqÕ¢–FÔu°ÛkbM_åWÛú­ JÞáÂôml:! ÔømÃŒ<%Ôþ![[Ę"6ùì_YÝ“w/›ï›’¬ T:IÊć€äCÀ:³:ÓƒÊöÚ˜¸ëa‹•‡•c;ѯü,[šo›v/1jòF›|Gs™ô£ü üW˜‹ƒ»šüuÁ žÕŒï_帵-Ƕé^ñ}° ^}ØÎ"&›xdíeGÃn`; ( b«ØiÔ²‚íàòæÜ† à®Gñ]bºÎ ±ÈDFŽû£§*  ‹×ö""Ö¶¤‰w3‚4Énô/Ý1Ó+VA×üN®IòÎ*s·pÇä:%ÇÑ1=l¤£,d®šìG|³Z²\' få ì×Ë3jÂm ¯Kß×Ó™.]ÛÊÑFC&‰ÅÁ€WÊÌÙÚÑØîlˆ7½Lvm9+/b‹†ç£¡ ´¦‡ñ91±?¥î³²UÚi%È,€gÝKpyø¦4é³™ŸöËØ‹>:ÜûfïÇ•P@ôX´£]' BÚâ±Ïƒƒ½{_¯./®ÞíÝûÛŠíÝû ÿ÷àù—ðsðpõ›½G+JÆqïa‰ßÃ8@ä;3q¨4eÚ°)°^÷Hƒ;ÛÒ+•Ðn8Ój¢¿0ÃC‚Çx!àÖßô°¿[ø‡„yˆä9Ú€f3ª´½®šêñ2 BÜ,Ø7…Ñ‹»¡Ñ;Ð'_œ¼¡º ò¡¥—’½6’½ºá6Oòoe(Æo…… t·%Ý…Qx󚇉;£)\ÚþTzߔƆhŠùkëBôr’ “. _dÒ¼ë‚E<ÐÍʸÝ1%ã¤ujWƒ¢%ã`v'á `˜mÃ#ÿ©Œ³lYK1ʸ¦[—q‹2È8‘V…C2„l¸ã:ÛhS«·BÝÍê­¶»µ ‡JK ¡x«–Ä¥^ÎI¯(“ç(“›PÜð6› þFÙ¼8tQ6èš—ÊË–ñ@´y¹´}A/½:'…oò¤6†ïj´6¥°ÑæN¢rRÛtÓhq)¬í²NJ”Â5L·.…dÂàd¼¯®t°) òLº±8C+´éÀ8&î';¦¤F¥²Ñ ~3©¼4Çx©l¦À¸ù%Ù-ÅòÒày±ÌJðˆMÛ¼ÔÑ–»)OÄ,#­wÇĤ´ÖÒÞÆ‘"Œ#î$Œ,Õ]‰j0“õТ¨V‹ÊéÅ¡ä´Òׄæ=ÿÒTfþXoù¥[œ.-½©Cs$#‰¬‰usÖ‹;!LXаQ’\}29MzciÞMzcLê[(¬*ȳÊbi˜’²PcMq³èÊÿVŽMèŸUE»ãyR)®nãÆéïäGèzÛCœÿTI¹¬OµQ Ó­+¤Åãˤ“¾jž&çMØJ;)ky8À'aå†L+× *n”ë”`jý÷yQ™ÄÿÒüƒ9MÒšP_&¡OCíY§Ñ[‘³º`ic<‡ØLi'7óeªŒDLl&~È+°!Ý廪Slb6äÛzH¼òÝNE.îIièfÜïç—×úñJø¬®Ø}&u…ìÙ-ù‚F®˜Ä$9^¦¡­$Xƒa7ÂhÐ>Ð,4&ã’ÇàÅ:g`9F…(dåFbÿņL wÚQŠö™ÓvŒê€Æ66—õ®üC–)¿!`f¦{¿Cÿ%6 4¦qkiëŠéÓðÍÜ;¤.ÝüOöÿ@ååûæ½éóüt hézi Ói.†ä ÞkŸ×Hê )®PsG"3•X3dÙ F ””L —‚ßGf˜ë()²¬œMCÆ'4Jšß4*ȱ±U›‘€oÌeѲ1í"£`¬Ö>»¡*²ôFI8~Î`!É8W­S»¶Z$…Ä™ÒíÎrd:ÃtNašÅTÎæðÙóBcZVd´o¬R·N™‹•°DÕEÎ}U!$¸‘´™q‚ æ§]ƒlßlxÉ Í¥Ù&o@²f€ý’UÕ…8æëíS–§ J 82ÄãüX£ÝúÖJy¢»h ¬Åi¶‰‰urÝUSžœdª?o¾ïÖĵ«"õ­ªy€lÁÜx3SÎð”ÙɲÈG燆þG¿Od.߈9©eB›.ºu¦¶>ÆÜ鋨¸ ùBv½ݯ_›NªF”3¶ìçÎÁèÅÃxåÆìºðýôúûQQ¡\çé|›dqL“ÇÀ]Öœ8l»Á ã H¨iŵBÂDŠ.Ìîª0|qáò73‘Ã{[È£2_%𫏾¬ûiÜà OmJ€«8T»@ËeHÝb7Y¾*òÛ‰Šílèq它` ±¦”ñ[~qLK*ùÚu¨h@·j®I#v@#±LÈh^W¹¶Gæz©qÑô]Sˆ!~üE7¬s—’NI’VYb ä?ÊÁ‡Eæá :c ó̃E“özÉAÒ›‰Î ‰'¯Á;`Óù×]§WªãÆi7¼ÿ»Mxf‚]ðãÂJ„³«ýâí§~1uú³ L*µÂ eðPöŠù žÐîÊ«ÜR˜Ng«ß¾6°ÔÍ/1Ëqv½(´›CèÐù´©& Á. o«–a9ZxÎz†ÐõŒÖ§(5Ye$9µëŠå£§ÏB¿òbB€¿c£™ìdD~þÐÊd?išéÅ Ýú»u¥`)º@3N É|8B­q–L|ù» N.•°e²ô¾àžÛUÏÚ™ÛåÓéEâ9ðžH:ÅÙ '8#bøœ® "}*s;ößÏCá®É\IZS".ÅE‰]]4¾Ê´]ˆ_ÃþèR» )ŠubÑãöÖ¹Þqç-E1g_€#‡‘Ê4•yaL°.˜÷Î*ó"™Ù`à-Æ”SHé4Y“̮р˜®øúþ6VŠ´%bña[—5ÓÙß5uüÛ°²ðDr…¸Ù2Sý dDJqúTe¸gkSÏiÂyiÏá³û4 }:ž)ãè¤Sž7—ªcFÓ’'µù¤Ê"ŒÄs. s?–&ÇQÊßÉÒÜL˜’„­¦œôÈVos¸¡í½OçnÃŽÒ¢,…PçP%*nÔ u┚氈eïφ² Ì~Æ‹3PÌ®¼½PÅ/ŸÐì@´> ±µ^çÒ{Ûx¬¸à“¨·ðÁ&‡‡¾÷ãš¡•½%l}žzsUÜÜú9õþ\=3&T™Ë%+Ʋ7Ÿð²wôÝØÿ;ÞÎKÕ>ْ‹ žÈ‰1¾„Ë´RGŸ5÷__’)ì==ƒ.а4j·ÄÈUi²Ï¬ÆÉPJ*„Û¯f»ƒÈ„í &î‘Þ˜&Ô¥|¥£’ÎðÙyj}^ÑTIg§éÙ«Š\°• vÕ9PVIÉ£|H½CiaÞKB'¹²áEª6—)ö*õž§Þ®±¬©÷4’o†í~. x’Kâe†×`§,“zÓìƒ"žk›k+g€H¥ê‹QïVõó|)¢`l4k•Α‰xeÑM[ ʇýÇ"j¿Ú…©‚8Þ¿TvJBøTÍV~ÛU[-Ó$‰L0oöcïQENI´ T7.Ežç=kô^nµ…hó€³S`þ¼%¬>&[ý§V*n&à„™æ‹…´ð¦ôü¤¢®98ŽÉ•þKaÐØ²pûäò]süª.¯¾ˆò+êÀ Þ¢ÔE…ªv¨ì n0ä£8 C gÍÁ½p䘗±«Î’&Š;_D7WOœ=œ¦ ˆÖFçxt$槺¦®àpˆ8I“¨™büX‘Öý6Gók•¤û^ÑS¾fóü懩(Ï™ë‡_á —çAÉL™Qˆe6aæÃÀöþ1ƒt³bk™ Þý~£|nK g–yõÏ{íCÍk`hkô¢ÔÖ•é>øj³%Á‚eèü=Æ*jà•v] ·Ì†ˆ#LšOΙ—A!¿A¬®XçéP8‹„XÁø '7±z:­½×Œ@4.I®‚Ò¦Ç#BÿËÍ06,ɸô‡3–UGÇc´7ËÏMƦ1K)V…ç‰ ‹È=Ûί<þƒ×S"¹IÚ"‹}“ÏÛ9Fma5>–ß±hà–„‘ÂòÓÌímz1q˜H„F;$Ð(s©Ä.áƒfIM"Õ²ƒ1(=%Õ˜d¯ Èsna¢•¨Þ) bm ¼yý›½¹ê›endstream endobj 657 0 obj 4934 endobj 664 0 obj <> stream xœµÙnÇ1Ðã¾ä&ÇÃl ö}ÈÈVl¶lKë†m¹¤ñEÊñß§ª§ê™Þ]Z‘ HluõT×}5ßtlàÃ?ñçÑÅâà™0¬;}»`Ýð÷tñfÁÑ.þ8ºè¯ñ˜U`ƒ1Âtë“ň€wVtFøÁ¨n}±ø±ÿlɧý«åŠZ2.úK6h¥ãýuÙ½…£ÞXm–b0B(Ûß,WB‹ÁsÙ‹üÑÏë¥ûÕ`åx¿Öƒ’Þuë¯ë¿á½@š6€â ÐJ¸Áõ—ˬâƸþYŸŽ'¤èïÈî R&½¼?z˜f¼FqŠ´18¢ûçd›¹Ê˜6ËOX2¥˜.Œp5He2bä ã‰§•F÷bö„i{¾\yoaD¸\©K¥ Ü-á€7¼?Bþ­ãÚöçA®ÞwuÖôÇùܦœ{›ñDº ï<|)P—' a¯‹€×Ë•„×Ò£fõàœ÷еÆhq€(¶íă8¸÷rb°f4–³¥œÔZ#¸RÁ >ÒÞ]Þ;Î{›´jŸ¬“K`×U—¾^šÉ  à Ng}ÿ[áè×%:Ԡ̼yƒ¢?‘@ÀJЃP`Õ‰w e´Û!K°7p§ Mï  ±K*vŽÞp[>‹âu6I×È``ƒö ÈAf,šœôœgbM´rHWÒŠ-åhD†¯.óWÐh$g Í\Z?gÈæÈ•d–'¢Sf…GúÃÀ/ƒ¶eÿ’²"­˜AïÊGËý„>r×]†¢ IÚŒ"¶Œ¹ú†™\г²{Ù :@[5ó`=ëc°–J`+çr—¼a:ª@+néýàÎÙ”Ö™[TìLay—i¸ÎÖ´¦ÇMfÞeIh u·S‹µï¶ˆ.)Ò:ˆ‚``iª!\F1xFq¡ˆWÛnÅÑx0ö¡¨Š?Ǹ@$¯ ËÈÒéîpXR„–Ô gœD.TŒà©(³£ßb´Ç@ªbH®Û!áuÙ‡ÊCLÑ™X#“ãbæ¯"±Jo!6*ËtК0¿KŒ#‚K¼Ì Öûþ/ÙJw9j\u7µ¦håB‰AƒKŸ”@B4Iô{gá?Šzÿ«*å!;¯Ð­”rXÌU‰^§Móy=“B%Ï$&˶·`꘥ѥ–圀}ÈÉÓf zˆÊäPœÊÖ¦éŽm×P,Ão÷Aˆ.P2¹Ý‘cQÀ`™"’c¹pô6rš¯´ýEv‚·Aàóf?9/á˜è‡ÐPäbBÔQ¿!ù•äy¿ð*Lƒ$ý6B€ÒôÀqu r•i\H á§À‘̺±Š-Íï„Ú–ìÍ„°ÑÇ÷S«mâÄRÒW]hÚÜVx$/LŸÙýÿr¼€ÒMsO’í-å+¥0ü¥ˆ@àÄ5gÆØ¢J‚« tTŠJëºÐrÝ 9J$””¨ÄDA‰Îï•ÛƒœRÏ›~ké%à° ,{WI"+0áèG±¡@QƆÂJ…ýD{×û±Êü'¯Ö±ôð¨ =’ e!ô3,…dÅÇ–Î!÷wJ HüŠA.ÚÝ®îß ¬Œ€_ôÏ›gùà´½ÀÕy†Þå½9B)!þÍžWARF£Íà¦Åt‘ ·iëUZdØe}“î¶>‹ÔåÚ§.ºÑIˆ‹.vá*¨Ä{åJw½Žg>|íz§¡ bÜŒ6ò§¥Œ³€ûo®Ã`wØd¯ªÓOƒJi|ÿÍ Mí±?„Nƒ¡A=Á%7Þ†ÛŸ¬ß-ÞtJc˜@0¸‹ëœ‚¦ØÕÀ”ÛG‹Ç‡‹ƒÃ¯»Û›»Íâà?_|‰ÿ<þö3øqøy÷‡Å“Ã. ܈‡ãà¡`â:é߃iÛ¤£ÝKzÖc<šëÓ9…j4rJxCýº½I†JQHªí‘>-¥ç,âæT‚U¨u4×\¥TbǪ1â¬1NÂæYaaÖ6TUK‹Ž”9ItLuô=’ Úu§3FONÊÄ“±ôäF´±’è›b²ô4ë´+/BAé֨ז§vBïez[ý[gö­ØBŒsÉõ ãHä0f0pè( boî±FÁ)ˆ´™9.g7U­%,„z7$§ ãá Û@>¡¢šj®‡¡I“œ˜/!¦Œ ˜xAJ<ônK©&,Dt§ëº1ˆ…‡E#ƒ[š™z>Ñ0­"—¶é ¾Ã$,“óz#\uÖ¬ô^¶*AÒC6±6+²ÍXfÉYb•…Z³8³”í*¯žFŒÜêûéz‚ gÀއÄU¦”Ö©h åAM÷‘T×¼©ä;iî¶ÏÅÖuw*äÆªVr« Ë2PÙT ¼ƒ—5áÛÞ'!Úb ±,L»d0Å›»"äIsPd0vrœz:Ý!Ûæ%WübKcv’6¿'e~•V·K$5ka20káR®$­# rSðÝ ¥Ù×±*âxc s¢!Œ<"ˆIñú͡“™ör©“yÞ bۦС´vëzlæ º›eªyô(?~yt’Z½[}R¸ì=Û$QÚ¤/TPÁÐ6(·IgøhÂ4óš‚_Žï2¡ÈðMúæm(¤Øò²å²4Lì~–¹) mr1QE òöq=³uj ²ò¼\Í °®Q‰øËf5IˆÍ趸öoÙ¯^Vd‡Q¯Gš)@ÎܶWüÿ>3õ(£*M-ÌtÑuˆ½ÕsMÕÔ>.Yñ’ z¨ælSôÍëV Å jV•à{Ü{]*¿f0&Üï¶ŽG"1;bÖû©Ya?ªÀÁˆRö½}¦ÓeF¶Åò¬Ô:•ÐJlýz›‹¤~é#×Á¤ ,&~Y¢ñ½üþ}òŽ€ÎÊ€2øÛÐgl'ý=_ü„vP»î­?÷Í«°!ÀW{Ž=Ó»ù°çf2«iö_ÂW¢Bõp’¬vá±/©>>Kt\g:ÞÍK7÷z,—B"Ú)i@4ÃÜ>z¡›éó ež’]ÍWÆeï2lÂÃé|ÊÂŽ÷~gÓs?oGqÒ¿¡arˆ2›;šc~ðS[Jã¿ ˜­çï¥'xT=—ÞgÊ.¨iâøôE^ÝÄ1¥íŸeÑ~ŸÇ™_å½'yõ§ìRý©OÐò,s>Ëw§“[ÙžgØ')4øøòbm<ÐÓÙ—žÄFØú¡ˆ"Gò „—Ph—)ôuZŒªçaV^Ý‹OÒâ§e:5þMDZÏX>Ð ZQþ³|ðû¼7Í¿/C¤ÕA†–dðß¼z‘¡åI,‹ušG‚ï¢Û)ce©%Ê«ÞyqÊôÅî"‚aöí l€Þ#¾öˆ\¸ê×ÂÃÀw‹ÿçØ\endstream endobj 665 0 obj 2863 endobj 670 0 obj <> stream xœí\ék\G‡|Ô_!‡€gë¹ï#…lb–,Þ¬7Q–€“Š%Ë"²¤ÈÊáÿ~«ú¬î×oF#Ù$aü軫ëøUuõü´Ï&¾Ïð/ýÿâõÞ㯄aû§oöØþßáßéÞO{<4ÙOÿ½x½ÿ·ClfÕ¾Ÿ¼Fí¾Ü‹ð}+ö-gƒÂ×{ÏW_¬å¤µWjõl} ´™„r«ÿ¬½žŒÕju´>Гó >¯×|2FÁçÙšÁÀJx“8gW?¬ùä…wbuªµ|u;inVo`|i')tîä½\]`/É™Zãü|b\õt­&-ÌyVÇSZÞ¬Ô¤‘µìûÃrqJ¡&©½Û?|ºwøÜ?vÓÞx˜+o—j夜\½Æz/4¸êL€·Ø€MÎJØvÙË –ºÉ8EÖuÕÔã>_TºÝ|PV@š§¹Ú_ÔaëçÙZè‰IïV¿ÐÂÒ‹4ý¹ÜQ] 9¹ózÆo׈&Œ^=Âã€nV§Q%³a-a…FâXH›º‡êÙq9!à¸J!ê¼ÏKÁmã8=iië Ÿ0Ð0›áZ®>_°É2æ _}…-Ťó©¸f!—¥0‘ßH·ú±â:ŒðÐ.×È;HÍá1HÊ5.ˆO’ ºÌ‹µ™¸tÆžÐnr:ŽÕqJÏ©3'IV×R±=ìÓ“±ÛÈEšTIRø7â'! %󫺔Ĩ–‰…×I*˜Ëœˆ¤"ŸÓú@Z3Ie‹A[”V èý¸›¸·åH±•ðiðC]Á\‡`d Ã'•YÉàiu'r¦÷ceajæªà©¤c?à"ü&YF¡yÑ+Ʊ,cSœ^ªÉª¼¾0V`.àpœ§µÓâäHK²ªHv§êëÒ º ›3rA•Pu:ÒáG­ZJ«º¬ ëI9q“)9}M\•`LÒþ×U‚ÖÏ ÏµµZ}Cä:63 ƒRf²Þï6k&ÆËZZ¥èºÖ7ò^¦ú"* )àœ³’@ nòvûüd'¤ÁPq¡¼Â`ªU»Ù JOè3V^ î]3íyß6é™ÀNÚ¬~%‡q2g(}Y…û²Q$‘ˆTÞˆÄGÙ±\dEüºæ h 5Ö8­AM>ÖµWU%Á{2Y¦À(ýPÛ’Òó®mü$#Dûˆç€&„ÙÉ …p(i@¢‰n"˧•Yf8fPDÊÀ  ˆ8pã±y> „DgôXƒ¹ö {Ë çý zCR`mƒˆh_QÆOúb®äˆÀϱ–ÈÇÓ)™`¨D4ç¸å³à1IÕ!””6«’p㥎MG-2 !¬Œšl¿Öi$æÞ Ä·Ô»Hü´˜•f‚G@ð¶eÒ n•†Zw6ªó”ò-þ * $ú³‚‘¿(” øÈxið‘E"Å­dUD•ó#µp¶z‚ˆŒÚ¾­¡ª²Â|Š(í“5¸!ÒH…ê»E>„’S,’o•DT] h0´11ªi dj¾lt.Òo[äYm ®Q<Ëv Ô`áÆÍT¸ò@©„bºñ+µŽ7A£¬Š‘2<·íàåË5÷““¶±v'CËtÒ˜»4ÔM¯k’ê+³ÞQ¡&ÙÍüœ{ýKÎùë •†gF£¨°¶7ȩצ@¼I–v°°Š5ÏzQ £’¹Šn‰PüÏ‚%EÕÈIá(K;/þ Xü Ý²àKK€õ­E~cÅsB›¢âR.@{Ë8î7ê¸àœ7Ü£¸µ >&Q!ÕǬÚì¼·›J'è%6B›'–|•vÝ:Ô-ZÊ¥„ûNFRuƒcÁn$ï€e˜Á†%€ôOœË[x´ÐTMÊó„_d«ß`=1ƒ¡Ozš|N61Ç[pZÂÌ<öÐömÜ\ý«q޳÷üp(ëǹÓÍxyD›ô_ë^V­‚l¥av`+ã%øàKòý96®óC.Á®„â†(¬J|Õ$¦t“@ªQÁ§I·*x›¯(GæµìÈðï–gX½ DàAvë¦õ•*–ŒÊ!ð5èC Hw@è4úꛡ¸¬¦f¦:’ún«µKçB¸(Ä=¡ Pú­ÖÞK»nƒ(-£ f&¥Ì-@2`‹xxa…· m=3 xõf¨`_U´¶ÈpÉ!'‘Hú\…8(/M“AwlPÎF* Ф-EÊÂ~»àCn‹7¶_€0`²=y× ™Â~T L3BÌ8é=+Äå‰á¢Y]tkB"”S÷ž 6ÕÝWh (‚ƒ11œß4âû¥h9㬜։¹C=Á»'5ŠqEýQŒ„(/’øð1¿L!§[C™¡XöÀ¼ÞH¥í¥¨WDgš”ÝWáêã!ðì¦Ò0)•³Òä‚?þJ›æ‹MN§K,/ÀË Â\n²žƒ¶wRܼ|Má HeÊñ eøÅKí£R&}û²Úkk+_I߀Y cÝJ•êG¥úA¨æ JŸ—jÄBk›%”Ú)× 2ÇÝû’ye®ý¾Ô~ŸŠ†Wnõê1د}-5(úxj˶ |Ã5X×ÕŒÍcXɇJOŒH“Öcq Œ18ÆfFì±ÞÄM °àÝ/–Wƒ{æ6.8)2Rõù/F¯Óp-žbKª¬"ó·0”7C\ÓxR1€â*/c¯ZÃñòÛÀ¥ì• û’+—ãÚíõ7uàI„›ºÔéab#Ü«|Z€!Ûp.Ÿó™‡ÛëõÜ …X‰FA´d+ó*u“nÑ>·GÈ%Ë‘—X®:F[DÂ.$¦}Z Ú«ƒEFÜa$àÖPÖ  2žŽ#ŒU{OÉ‹ÎQ:Xf„ &.©0Æob§€o¸;£°² k ‚7Öà^Qïé|„VÉjJ ×R…‘U\ì9Ï=î¢ÖP/‰4_/È@ëδúzÁÑjôA$­lJÛ(bvÊ—7÷kƒ¦Ã0ÃŨðzÆVQ‰D°«ÉÍý¶­\Ô˜õP7ÖƒºæÞc¬A[{ŒCüžn7»z€~–Ë1Ö@jh0Ž”°èÆ(•)F׃$ðÑ"Ñ41£¤óc¿î¯ÌUº¸JP ½ÎÊ f¾k¸@L±‹zÁDäð:]R¥´zª…Vn~™Ûé‘6Ç&ÞßÇ'î­`½viBúÑzÁYvLò¨ä;¾‚îÖ2K„i|Ó\¯k‡ä 7Eža–,л; Ê:ä·9ÏŠ{pU¾~)èû¨`Z ¸f“q«'¥ìÛÒîÓRöÏòõ¬Ô>-eO`)`E‚Ày>ðîï¡th¾)ê°|*bùãñ¼Ÿ €_+ÓDPö 4{þn\‰Ò÷Ñ=úÖye­Í |Ä4 Ñæ´¿£ròçåë¤öº xSxঔ½(í®R­«ÈçêoKYÏ,Xû¬”Í™%ÄmsáEéHÉ05i†(íH9‘zX›:`×·iÆ/Õâp`¾[åê×¥úM.:Í—ºsÑ“üñ[©;j‡‚«Rwž‹NòLJ¥îXŽáÆUú¬Ô·‹°–Ç'¹è»5ñCßË9o–áêíWîËj;¬­‚熡€v¶†Ù»¢†"# A¯$ñê¿§Û™E6JŒòÇf<ìn£¡äjT;…+"ëæEˆT£Ké®íâµm8²Úœ —ËiZᦣíRæAÇBFÊãÃD¾t/|çÙy®G]('rKÉ$$ã8©àUr¹Û¼‚‹´ú›\/ÁŒìø´®è<ÿFG÷2È™Ó-¡™6’±‰kßýþƒdo~ï•Þ‘Óг»[_|çyývïÜ”Á¼ƒ”øŸ>§š¡š¦ŸF·{âBï˜\•~0aa Ec„Ó€?X^¿Ô¥\õbCE ÖÄ.Ê óA?[lù͆P/vÓyY…)y|ï¢Å?ÕÙ†¿s>T$aŸõŒß†ŽÌï:‡#óÎP,çC›èwÑb)Ùá „@î¥JòuÄÐÊ“´Ëš4R«ÛL±FcÆ{~AÒå÷Å S{éÙ§³4ù™Ô×ìè >ˆ× }~5£¤Åv±òW ¢¥ª³ñ¥_"(¥Ýoä¤wècp Ì.»r‘äæå¬.×6}Œ<[4¿’( ¹ i¡ô›ïJ¶k•ø>åùzƒ×Øù%2/· o3%ú<Öô,ûnšöƒâÆt¦+íþvO´S‚,ùYbcª/žU(>ÉC°¡$t3œTò³äíØÅ-ñÎ ~s%Œ°{ ß×,¿D¨nuDêRÆ:¿ºæ`­ëÊðëãRë;ߺuâ{§yÜAsáÍ>ð=ªš¸‹úØÆ²à O÷þ ÿ8M÷4endstream endobj 671 0 obj 4094 endobj 675 0 obj <> stream xœí[{oÉòç~ŠåtRv#f˜~wsR"HHâÈ'Àq^â²±1(f ÆäŽoŸªž~T÷ôzל N!ØV?«ª«~U]S¼Ÿ=›ø'ü¾|;»·Çõ0?ù0æ„¿'³÷3æ§ÌÃÏË·ó‡û~›»Þi®å|ÿÕlÜ€Í ï snnØÐ0òvölñdÉzÇ勳e§zk‹óe'{8K,.–·¶gbñï%ƒ_çÌâ`Ù±^kÅ4™øf9ÀJqFÇóž§yÂqžðö7¢—ÊASôJ9)¯óª@”5‹Í­Ž>Þ;fèYǸ«íµ•d×wÅ8  ù2ÓBXøe’ ™Ï2dû[Îéò•vŒ©Å ,rÜâW£°˜‘XŸ<ÏÃ~+1Än•Žbù~p*Ù´_vîJ³Ø‡fÏP*ÓÓ‚bqCoo2‡AVgËçûžq){)Auö@S^!û¬ŒÃ¡R€ÌAfž<>€¬%k×sÅ(SgA(@éQ"$HZ /E¤»ö«Ú'„»6ƒWLÏ€0{þÇUÊ ÖëµÑý`UTlãâH™:Õlœp˜·-5{$†/~\v@Ê0XÍè§´9Ú7t·x ZÙÄÞxòÈšÓCbH²(=Ãx’Î%_Lì{Q§•í­•þŽ÷Ce‚Ñq©z¦çãI)¼œ@½G•rƒ’ô,Ò{žç"“Z÷p—Uo´Å6ZPàµÕƒ6t,@2ÞKèýÃ’Š°›×Ff-È®Dñþ•'ü¸d°H¶ }Gy&™f½k"ÀB(x‹«WšbQlb$oró0M%DD¤—ˆþÓRÉ^ñ]¼eØÁ(j#ŸeÅDBD¹V9¹˜‹DïmÄ6ùÑ`õ!…ƒÃÕ:°ªq™™›ÄT×+CŒ–ý0¸ë†˜8¯Õ€Ÿ7<‚BEÂÙRƒµŽn$¿)¼g`PžR÷ÆjªM ?"¯™±a¼¾t`qÖ83ªÍ*ƒHØFB3ÚÒ0º.ÉA5 8 §O¡q@0g.€qÑ»ÊsˆÂTÓ ÀòÚò¨õ§y€•ÉUù|´?{:{?càvÎ4@‡µsmA׸ňïáÎìÞÎ÷ó‹ódz{Ÿ³Ù½?á?Ÿü~v~?ÿÅìÑÎüéUã@¶<øsËs(Ø  K{KP`£Œˆ…4Öƒ2º ^F×Pš0šBC¼tÒ°U!Q®|h1u›5¬½ÕÓÂù$ø©;Œ Hй­‘>·mn^úh:¶”~Ä”IÐäÑо`ŸŽ™^Ë!xÝÀŒh/µÙVÔ-ŸeÛ9m†!g#øN®ÑfbÍ éáo¼\°ÑÅOMW¬³ ¼×?àú¹¥®ô¸µñ¤+êucŒOÔ„ÀwÛ¿¢¸€s©mLpˆ„³mx?Ž?nú„ê?@*pÓ •¦'=m:õ³®éàÈú“ L‹k qEìðUÜA ˜‹^÷°å©*‹Â[ƒÙÆ©]Æ*Л¦WÍ´œWA¹ P@V‘U£No=µÜ@¿™FK¾9^<vÑê ÆŠR½·§À’‰Eƒ«`ÔŽƒúl6 š:Zõ»%à ªmlûlbKZôͱï õ!<եΤ‰Rß÷©õ$¼–… …XØÔ9Ä%c ÷,ìïÎöý,P¥¼ËÍÔw.ìäzˆâiôEµ[Óè^êäC/ÉA랥N›&©ï~j¹Š]ºç¡1ÚÊvo¢+¶^¤ÑZFØzFkak·±–·8fiâóدÐM#C·JEVÀ|Ê*-ùDù¸uÄËL|¾„;i‰©T,+ Ž®UÀÛÊ­jqÛ2²»•‘á(«$Ü:²sèºl*œÔÈ6Ì'c™ˆ¶1g>M­ãDäyZ} Ü!¿LóÞEóçk”¶ÓƒW»ø¶#ŽÖVŸ¯Gk«/×"\KÓðé"Ë¿O“6}«´6ÒnïÛ8Z«t=ˆZ kwº. þElÔ8]{±ЙÁ›ý‡Eì|›|ˆ]'Óþ¦<?¥±ƒr+c‚¹àØ©x„Ä`MÅ€ç8Îû&ÍûH3WžÉxG¾Á ÐH:Ëbã»ØøaI­‹'vÉmâÁ_Më²A?N}µw*ýì6PQ\w¥Ðàùº¯ ¤È™vTøË©OèZ£2Èž–µÊàèѨx #í”ߺŸE“wiëOXØ%Ÿýô‡z¦tm]êœÜåtŸp̳«Á9›Œ ÓuÉEd*]ÙUŒU¢oïÙt¶®Çwæ×À,y˜%.Ǭß%¼}ãwÁ¿/`þI,Xxs¥ªÄYL5Ü\zW™1`ÌNUÒ¿LRúשÏÃÞ@Îä^Å,]¿ö»hxYÞÜ;_÷Ò]òF±df·y´ORùÅë³Å3„ázádÉØøÐÀ/TYu;®d˜ÐLµ“9S±jä<®˜¾¡8ê°)¿Äó'É.Í3ÞO»† ´g®L¹ý5Ìç2¥‹•8g4Í–µèNÒ—šSމ¥OY³î'·Í4£{{  äñp§BC\B½}h!ǘîÿÂɇÏ#t#ˆ Ÿ“/f7çiÏŠ$jTbƒä{a GõšŠÙŒ6I®¶Ï½hâ列ëg¨îàzs“dúêßœ¨Ójõ3£æàGLÆ·,Ë™À´¡DŠe"ø3×ötçmŒª´• *Ž_ýÎ&Õm¼sÓºs–(‚±%Ò¨&aä-ÎuÊïäø‰|æ|™!€\+‰µòµç©…-Šk>ªL¾×µ[MŘ@„äN—^Ý»â²V¢üŒÓ÷[hB¾ä6Õõ Ç_ý[E7lcpùÉ9| g7fýÿreöçäÊþ;ÒíWà˜†(ˆ€†$+?ëÈ”ëíöå¡ fØk.Å\1¾"häjÊ·ºD«*òÈ$î$º2Wwi ,‹9]» ÝDB‘@oÌåü߆ ñõkmÈȶ ÍÙ0`uW‹¿-¡ŽuKÄ‹G‡]šEœp˜”²²ŠPÝw.Ý 5Ê£TsYs°ÊœeFÕ.±ê‘ÇGæ“–žÖb5¹¨S_w±xtø$Œh&}ªôbŠÖÃ*¢£vª.ßóÓœEYV ÙK¾UX[U<ùCµ¸Ž’,.d,T§ ]ŒÊQ> Äaµþç’ àž“Øíc YèKª<ƒÌhžÇ'„´À¢©ÊYÑ׃×Y䃣ͬËìßp¢-þ"4¬Y_Ö²âÅ[¬ª‘ôƠʃØhœú®˜K·IA÷Aîõ'˜«ŠÏhñ·Rp0óתйXf¥®h‰W˜ùŠæšÞª`|•޳bã §ÊïÃŒWšŒ åÞE–,šqØÛÕN†Ékë7#64Ê?;þØüh‚´ª”XÙäâ/±ò²œ9—ZƩɴ7…,k‚+ôž÷M¿Ý&&ÄJO,V¤ ׿£G7Òb¤¯³¤[v[Ñb¦L”•íÔ¦}¸&!!‘¨þ¤l¹*½¯ÂNÿIBÖè úÈŽ.ÍìôU¾Ã³>­/Ïœ–Æfˆ%Õ™m0ÝXQ^Áœõð€›%УՋtØöJµOgÿz0mrendstream endobj 676 0 obj 2775 endobj 680 0 obj <> stream xœí[mo·.üñ~ÅÛ"GóýÅÀ‰Ó¸°ƒ&NPØ:I6jɲ,)ñïhpf¸Kr¸ÇÕÝɧ¤( :‚äΒÙgž®ßÎ9sŽÿ†ßÃÓÙýï¤åó“w3ø3{;×RË8´ÔÌσ Lû¹“\0îqúÃdzûŸÎ//®Žf÷œ‹Ùý¯ñÏÿ?¿œÿiöèñü[G9Brãðy'‚er9|þ×ÙÛ™ˆkž?‡§ó‡¸n§ç+­žÏú‰yÀ>.áe‚I9=[üÐ쳋çÝÒ0ïCP‹‹n)˜µFØÅ«ŽÃ3ÆH‘&x·xÑ dðrñº uKP3Ö,¾Çq%¸^¼/BÏrçe”VEdþšgþ|ð·Ù£ƒÙš¦„ávªÚQMÂ{Æu¥¥/»%g6« n4iç]§`ÃܺÅaßi•OÚÃ&ÑÞykûdüMÜÂMMiÂw[MLX1w÷!HÁ)~¸;pvt«‰36¶:cμyƒ žÙŸóu«QÚ£µc ƒóú6æÞ ÖqƒaÒOæ½è¡Þ0¦äað_|‡¾˜òÑí£Ûê°8Eà ÒXEç^FUÜEH½ËbÄ×ðLr®èøÅØÈÇ^äu½.ãäµ ÖÅ‚6Æmô‚ÝÕÞ6^ôî‚Æ rÌŽÞt{ãõ– ÛÛÂGÙxZdë[4¶.òèO]·´p| s@ 2¾´\Ã$‘y ÚÂ5ö§’ ®AÔñ,΀™[êç#³K‘-!öa±À†¿¸°øÎqî­ –}Y¤½ÄÉ–yn©ï¼¤~˜<޼­Âÿ4õ²éÍq\"˜Ÿ2v…ãÇø*‘wã¥xì7Y©‚}ÊúTz3rnÍŠœë¥M°2°9[‰Ú"na~á¥evá¥Ø1NÞ"0$ß!ä¾en­òèQî;nDΫÜ÷:·.)öl‹{ÓÖô(šºðøoÀ¥˜zz)F³Þ*þ¼P–¹Êbo:ÂE‘´pϼV‹—-­ÊAwŽ9°KOwU¦!šþêŸ3õ?ŽZ5ûMúÑR"úMë½zDRö„~4à™§‚Èz²Ájº£³ÒTbyV Zÿ½œáœ5lj"w@îÝ]¹W·&wRäFö½—ìs ä¶‚i½èþ<·NÐýnÔª9ÞInm ݨ­ Ý{S×è&ªÚ/v#ñpAn‡ÊÛò“ઠöË=ã¼H·YÔ€óÊ(fÀƒÿ Þ)Eu&·ÆqëPU¶ ÛPZ0£9ÞöÞ&uÄÐI`Þ%Nð <:gú3­î":m’W¤…‹FÎúº’²o/%µÕ“zʃG'4±õ¼DXÕ±óƒèò¨œ)Ô¤Ôßh(¸¤Q!ÕºnFoôþŒÞ»{ÿzkî4t’9ÂÜB„åCHüzðx©}:mt20®(s…O4WPþó‚?g}Vè‚k+LlBëdÕ8>ª´"‹ÈUÃ8!s»JÖªLˆH êW•áuž—Jƒ‹ì»ÎÓó 9xޝ™:>^›z¿m7rìHÚbÌÊ‘r,1aòXâ+òÔM ¯õ\ÌMÀ2IbPˆgÆà±¥V»hÒ—\üâiîûGž÷ÏÜ÷Mn=Ê£𬒰[½y8äa™ûXn‰×n?F÷D= ­› AB‚g‚O†÷#¬ Þ á™ƒåÔN8¡*VHÂï JÔð¹jH `梇[J”tÑÚ61õëwMŸ`(ÄM[ n䪄FÂVu†š5Äå)]zS±!iàp‚­•K¢â2ií,KÖRç‚ §~Õ Å‚«J(ßAÜ m:WÔÒ¾¨8ëÐz¤AN)O›è'‚kž·öNxªX äƒwtõ‘J7ú¦ƒB[a•ãc<‰VÍ"'è°0Mc^ ÷çoGÞØ*”¶Ù.±RD jLijÚàÖäñ±L‰â„©ã¡A|‰'Ÿéî@‚[÷ÌS[ºfD·I×T€„°ŽÙ6®*ðëmGSÈ#OPf™#á„¿7náÁvî †å †‰S³¥¯gÇãÚ×Ë‚.›Ê wàŠp®›«¤wñ/DȘ,a×ï³ì_:! ZˆW’U¸+›PÃ¥”øi‡û´Ä£–#°Ä=:Mý}-‹«, ]Œ\õ‘Çz³ #Éðj}Uýmp,{Tmr©|np1¯ª„•L%b‡<ÖÕ{*Dt‹¹©º©X<‡à4¤f•¿Súä:}†%><·•{7µ{Ö¡-V©{6VrB¸K °î©L³ #1ïy!KHÉKÉ!xz¢N~ç•ɼ²g¹ï#’eÔR&>ñ YÐ'y4Œv Äùçq¾¹¨ eÈ_=.Ñæ¬ƒt,G´ãÒ´• ùÿº•sx@ʇhAω-¥´rÆ ¡Û÷ [0HÉ×îO€°3ŒªøR ÀF$F`H2…L °€VÈ!öÌÉ:`Fwe€ù›'“:öŽ*tì0šÕ½©É[Ì }FOkÁR]]¹^ñÇÖ]ÙhxU¸‰ØHž- ‰5S Š0ŸÈÙMÅËŽš*­ßªv½çunÒ®z¥5pD£ ó ©Îû²»T!…x¼N1mcoÚѪµäãNt5ܼ&5´•Sß¾TÔN5yœp¾FÓpá˜é7㱄>„Yq•ñà: Fù¹ x¹FÃð†µ}é¼*!RDÔŒ”’‘%’Mú¶vIᄤ÷¹=}ƒMú’k­IbEf0žL˜¦R:Â{+fÕÁƒGL’2RE«ùðÂ=FÖ›y8ïåo¡ h´oP¦ê]ÛÜ&Fbå$È}ÄȾ ÙÊDhüãa¿d8†qØ–Ò*!VƒŸÁV…ÊþŽ^!OÉ;H&Ðõ8VlÖÍ[½ª[®3ˆJ‹/ÈÔýµ NÂ6…s¥†#O­“~XY»M‰ò)æ; lÅÕa§ã¦ÇE4@åh„Z7x¾XÝ Áß<±Ø/yÑ6– ˜ÜÂ"¡Žq¹Û ,7W2n–&DBÃ:h$ØŠÿµ@“psNñxë+ž¡|ô¥ý™ä÷ãX ÚŽâbÎï·(4+%6ž÷‘Ó &r™’@ ¹Ì"ú)Qr#qÈ+ùð/ÐÊ[ÉÍÜU‰FCXÑ"Ùx ñ­Žk)'ÿËCozåJ•òuyŠ„ºj°vi±Ô¸TÈXSløª“ ›¹ìÈ{pLa'__Ýãàð«FÂP>È9Ì}— Ñ×£'Ò-ÙpT²å2êÓ”(Œ³ ç†K>çÈžù~ê³Ý ÅÑæÒ{Ý©lm¢¢ñKƒog¿Õ4Óendstream endobj 681 0 obj 2786 endobj 685 0 obj <> stream xœÍ][oÝHröQ¿Bç+ûÞ\lعmì3'A0»²%Ë’Ç–fF@~|ªšdwu³šç摬^š}©®úêÚ?·8oñßð÷廳/þ*m{þãÇ3øïì§smlxàüB7þܹ®ñðG´¦i=>þå³³/žýåüþÃÃõÙÿ}.ξøWüïËツ?Ͼ>ÿ§³ož¿iCðzhGÈÚñ í´\ÒN{þ§³ŸÎDߥáÏËwç_>Ç pú¼k:+­>þ꬟qîõ¹kEƒßý°ûjÑ6®m¥ö»»ý…ñtÚÝîEÓÉÎËÝoð—­Þý¸¿Ú6ΫÝ×ø–í:«Ìî;…¯#ÅîÃ^´rrw½¿€OX#ìîeúy¿‡YƒuQðŽP |Ôí~ÞÛFXwÓ;þogßÎâ0 Â(z¿ŸúNÓO=>Z›£ÔÚiàé×v^`ƒÿH 9‡?OCÌÖ„vÔÂ-^!9c3’koÒδÞöë‰îå:¢ŒÑ@øK{´1^{¯½ ¿ =Ü VÉÆK½»Œ·oâíëxíCüu?Þ%ĦÈ4 m4Ò˜õZ8‹Ç/´oŒÍæàf”÷ñÚëñW­ó¶ ‹ö$w²Ñù¾)–-ï|¹x7-j¿~Î T^p®2X)|äS VJѸ|¥nÇ'Ê{7^bzÎòõí6ð×_§þ#áëï{áçÝð+ðbÂìoãý«tÿ#ˆDi`ƒ¸™«Ö òè}ºx‰ˆQ¼Ú;¨F+˜·xÿe!ð–TmcDGZ½L÷ßaS4V…Gµ”}önÚýÂÍ¡~ÝãwaÜým/ãÎÑ…nanó)þ8A$ž›‰ð½á|Í à³ðób¼öŒMuAµî#³þmºkºÖïEÓéÖVIo”¥+H¯"p|Ï0?OCœäò0GËdò*Éå,2ïÏ ¹& ÖÞýP:î¹û}¼ö*>W¾›ó肽ÁwƼûñ|n³%™ãsdAþ#¢ÏëÄ:îúD6]R¦¬ãud8#kÑK™H|`ü‚³£–Í>$FzO¡r¼ú@)0Z×t­# ßaÓ<¸é—¯Ce¯:àÑös54MZê·½“æÔ0·½…ÅÞt׌·oã5‘ïaÐAM›ø]|%5óküuÁ4˜zxÅ0Šù†Îf1ÝqOo6ßs{:ÍvÚÒ<\!)A&¿)A¯Æ^(‰Ê®¨î~%-þ¦pƒ0‚_SˆJKž%®ªÖ6­¡0)¿?¾õ‚ö€°ÕšFyGuæWpUÀ:ȱÕp•<0`6ÛÊqä- ˆ®£ ^SJ4mvñCB~¤ö¶ ?ö •¯'«ƒßb»¦Õž¢É;vÉ€~Œ£@‚@ >{þÏ9ŽM„ñï䪦ØÁÄÂN¼*§• gx2k>¢[¾?x˜®–º1Ð+l†Z`({Ÿ|ŸÐàÄ@‚Ÿº†âº¢ßG¦ï[µ3©I †«®:`c6Ð͸ªdØð ªQRRrÌ_CÑ×µ²2GÕOŒW§{ªÎ53QÅeFXS’Ä"`¢Z1RÌu°Ôy˜Ã_¨I/âÅm0‚Y€Ød êì2ŠÞåì²"1•õÛàí5 ƒÓŽŠ^eÕS nÄCÛ"îÆN‘ü‘•I¤^Ç» £§–ï§ïÖŒ6¾uÁh#ýRýg¹Ñ?‘Mä{Æ*“F[ÞMó-5ÑÜ‘‰øã®h¡jÎñª§JaO> ÞÁgLœ‚«H7i }qÈéáŕ²ß"O0,˜D$Ú†Ò9m/bPŽ‘õ{=â¾Í6ûî#úŒ.4°So5ªüƒ¬;·ìh J¬_ö ”ÊÁ`" º^ÛÕ@A‚m™khª³‘ybIÃ’èÖf* oÚL¶±¾HWo’h¼ÆL#ûO0˜«Ò3À°x»Z†ë\]¸b5ÌÒû._ã } =ËÀ) V%$ùÅ"ˆ ’Y8ZtÿÇ+m+*À›L“Wx“t„¾È'Àe\ßß”uÔ]†“ɳdQoàaàÑÚv”É’¤!&gbM2ÄÏm‹r=î±_è½4¥.ÐÁ&)WÂdµ€žz÷%™×‘zŠVAÃx1!æ‚*Qƒ,"#Ž=À«.ó'æÆåÝEÓJ92òÚ{$©-°–çWÁGï]d…Vã󋈯‚‰ŸAаB¶³×fª¯áý×ä%œ4€ãgŽ®2f%: _“‹Àë$¨j­kMPxŽÍ¢O0pPÒü(Ä­sus˜ðvf¹2Åpš~°¢Ô@°Þ|Fö‚è¨eî×fØkÔª”B‘>¯/ßgüzÒ•žðúv.¥aK—™<Î ØMý”FL# ÉA¾9¯¡ô‚=j(Ë;¯Xï·QuV5Äx ñ¾l½v[Ø_ø;³ù×€¦2aõ p¯“»~•o”ÍÆËˆšÁœ‰à®[è“ÈÍ™[8%¶£Š Kçh[ ¦„]«´Ü} Ã5Ѓn÷]|ò[¸ ›¹µžwð\‰p°Ñ{áío(2™ïƒÂšé™7´ÕÁ罡ßRz¯»C[68ùâà ÂðxÏÈ b¨ð,gå&æ™U ±æãŒ{󌫶0Ϥ׌Æî¾w?jnæ#©ÆÊ´&¬¼uKÍ`Ë&l ŸMÐcvIS•Ì.,¿L¶ªÇq»¼Ÿ±ÅÌ1Ä\·ßŽRæX"™†ç{ÜvBáHæ£QÏò¹ #+Ù-î=‡Õ G}‹ É¡†4šûkCûÁH1zðŒxO€/AÛ™B¨ÐŽ'l¬C»ÊD WÔäÜJ¸BE¨è·²ÿûy'u²JD §W“nÅVÂ'V“EwòðÊAM&”@â]ÅUÁYžBMF2‰Jòft2' É$,R’¥Én}áHÂà.PB7P’¥7 €‘2ã"ħ¹ŠÏò†¬³ö’ýnŒ9˾04,rIÖj¿!°DæÓi¿ž9é²ú‹ÐSçüæx,<¨ã³ýy³ êøªþ„=Ñ¢}{íô7™5¾D/·aLó=ûtåWÙÆ®í¢þ ]\«ü¢ZÞúµ]s2(\äå7 ?ïe°‹¬û¼wåâ4tôéVѰªÞ²ù4¬Ve¯&®ëGo àVcµúkÚ‚pWi¿Ú if­ò«1I('˜yô‹’?bßå’¿Y[õâ<ä-€Êei8k°¯˜àý‰°o¡š£Æ{¬è PLÉÿœZûƒ5ëPÞlg€!¯ö£ë7…ê°Î‰;VEryÕÍaäzÐÆp¹Y‡uQùaâ°L}V®˜äX„¯bü6>—9œA,AçdµÃùþ(~& šóèץ߮ žèN|ƆV¢»¶{‚` ’ßl«F§Ú29/OÓKL‚k:µÇ%¼a˜T*–X“AH9p§ ‰DQ…_Ù»Ñ/Û-Ó³"‹TË’ y¶V-÷˜Ègitc…à¢ä`&3r0Ìì0›Ë”èË›Ž“6‡¹V7­…rMÙ¬$¯Ð¦¦ce}¦Vòc¤¦êîñ!0+(¢ÂI\·M™žU ±ÉÁÚyó!0Úƒñ–L‰ËÌÈãþÚ`P†OŸÜz)æf£¼bÆ‘ SL^6m½gØlYâï.ÈEÞnyç˜Y¶¸&ŠŒõNW8"¥EøBW«ô ’4‡1ÃcÜ0žEv‡>©`' ¬Öã?IòÂ-×À¯r¤ì‡Ê®8»úA¹2±tÌú$ 07ýõ=¬9Ùò×B'WÙ×bwx~|;åLLõ¡á);¥’¯A’ƒ€4—QG˜1¢2'g"ô+·@büe›ÛHïXk'ŸÕ^+ø£`Û—%v°Ó²Í‡<Þ*OúÀJ)ò³šnRÌe-+`B^#ª) ú‘huÈëA ìŽIê6Τ¨Ü¹J&39É‚/éb;Àåê0–FðŽì‚Ç ‡Mß £¸dUºŽ ç‘Ežý¼‚AW –vugMCœº£åSÔÉÓJmS'/ ìKÆkÈùÛnçäp¦Rl6sR˜LÄ·XT³sÆòdÿ–°ÞhéÈ?Ç w"æÒ¹,9Jx‹Ýl·£Æ¡™/ d‘iµýâëã æP}›r]ÄüŠÕ®ìÄÁ~ž†¸--»§( ¦¥Ø¦€XéÏ­³ùë5¥Âu…™ÕQ*ŒÂÜ :º/®ÍtÞé§ë¼sÍú~ìUÚÊo楛Ñà/%ý®Tü%X§Œ‘+@© ùgP˜Õk2@ýX¾Ud®Êw^s¸ÌP3cŽ.ò—†ü¨Eædà#Ù¬¬æÆÇyè‘@sF°Îš¼‚Z*,T¸ÏØoºîäGÈÛn“ºn3.«ÜÖêqÜdË&”]‡¾.Å®+زGO2™–#k‰T¹r÷t}÷ê¤ï‹9®YŸÊˆ2Z`2Å—­PS|ÙÆS|a¿ÚŒÆç¸}šŽ?f“éõÛ}Á`¬MѶ0݆ö/>à«^ –¶S²êDdê¯Ô*­°jÑwš¥ÓË® ¨°v„Ì®Ì0©ÔÌ UE¨ו%úÂ~šÊ³Òõ`U~ö"U!¸‰áeé ¶n%S¨Ï(Ú±»rƒ¯¶¯n ü|Z5£Zï¢#–1È$^õkQ±–lx¨ÔôÝH]Õ 5.ì!Èò}YqºŽ)¡]Td“—sí+ r˜ ûJh;Ÿšx`)˜Î†² ÈbZ‡&ÕXé êõ8£® Ù>”ÔÍ61¡¾»’ ¡}m|CŒ”Æo…I©–þHkìüñID`Á¬&un}õ|××kbð+‚¼N6­´+ëÔ“ÇÌØx(ô æNy3Š„h–<Ô'B®/L!‚‡³º±yÄ‹™¯ô³yÝŸÞžî7ᇽ_YÃî[¡ƒb¢»ŠI{ºÈy½™E–ÒåP€GàÊ ·‰YeUC,”‡–––4Xå1¬t“:‘œâ§yçf‚—…Ã3W 87·›µpHçŒÔàiœç°£ö='޹_&7žÈN úë½2Æ¢tÜLbÖb÷=¶.ÐÊY9‚ÀɯA^š8Çø,«ÒsÂÉ1šn°Ýç½Äk[z2q°²;4®£„/×·3€°?]ãÕ«„‰¬õ˜Ïµfi™’>cÏóòÉ|ag¾’ù KiÙ™_äÙ^‡ÑÖ´>`s¥ñUíúW"²;Ä@Ò|/9$¦¶´ø¤Ë|8•9Î`IÏíŒå9 –´Þ˜IZ͸P¯òÅK´–¾À2"˃?°ä×m€ÔZ”µÎ{¾!j<(2ž„oŽÏ%ͱΠÉV(xh×^áU ñXOê9½Ù²Ï :1Ô9PrVsékKΑá~Rjh:@£t­‡i›-øLKã_‹Ò.ðÌ*cªŒU ÑïjÛ3Œ 'ÇO¿ +`Cî_%µl ¢ØÚI^`cù^ ûLÔ!¸aÔ-+$ÇÆ¤.lcEd¾ )¯B&KEo ÁCü²«„ÖA¼«ìäŠ,Y£_-WË@M?™ð¢Ã ¼1Òðeìqe¤ÅXôW¶  ¿„.òP"4‚hUÈx¦>m¢”‡ó!Ë *˜Y²ò¯{̹A$ùMñô8j´û C%1¬ëì¢lDŒIçÎàÀ ¸v:Û)¤›D«œö“8Ïz­¶ÊˆŸjó¬½@R‡—sp3‘öV^ñ–¶®Õ }â“ÌYÖòâ z“€7i wp*ÏÔ{éó tÌ+€å~‘ó”iêÌ´[8”±>‰á *Ç„ê÷€e”ò 1Ùr1VRm·¸[ÓÉZÿ…0ÑI¶I!ÌOeÀNŸЃ22ÞŸ™.ùÔ©š§?•'©æXì_âµò#YrTLNðxGìv2âÈ|U*ì½6.€ŒÑsUãŠÎ…L§OMÖ|9hçÞðu)‰Ñ†¨¹GTñ"~-`F¡\ÖQ‡wDdIWÐëÿe oPÑÝ[€•ó‰œ-Ø;OqGêüÁàSólqVÆ|5°übx.šM’›ó.,¦Èi³eêïè鮯õg𖏨€ûÁÃÑV~H¡áݪõxn,Öú x­¹Zt3Åß÷þ*@7ëD„I<ð¸é4Û:«œs<ÌXÎhyt ܯ¬jˆ…z;}JòÅM ‰} Ì€Nœ<:o€t¼G¤–0ãŠ<äa»åÁt°Ï÷Öƒ’’@È^ò€—/:+KÁÞYDÇL}x¹ÁF“¥_oGF=£)œCi†ÃsúãN¶ÅŸžÄk~Eæ8©,äêq"U1š€w'äµLGwFMHáQ’±•åC‹ ˜iÃ4- Nzþós]…,cu^ŽG´êü`£7¦l%Ææ=G1Õ*nyÌùfZôðUF0v +G²Ò/]”@ÅÁZ_]<Øå܉]¥·ŸÔ!YóÅ´ÛÕLÓëáŒáŽu4¢oI¨Õˆ \çFÊ8äA;¦úÞÔdÓc+.ÕE>^ u,‚XÁ†+‚_ÙmŠ1­jˆ=±ZzŠrLèÙ¤Ó'!éO~xìˆ Èx¹<2¾»pý/þžñ8•¨"síþ>c‚ÈÏàØníçà™‰Ãð"Øö[± ^ˆN4.ºÃ«žØáñ-Þº bEx Š…åcÑYž‚¹µÀËMUÂb¶fÖ‚\Z ¶6! ß…újMqœ"Ó!Ö 'Vƒ8ä›/Žysa©wÿk–æA·aâ…ª×2?K^{?˜ |ãL7Ú &¡¸x׳s)ñd='ßz‚¶:±Ò¼EPæØV`RL¶ïÊ<–üIpÆ‚´I HiëÊý.c€k¶ŒbÉÌ9»ÒE÷Z[ÝW™Oä»Ì,’™^zš ç™ $•¾:T¸9”A•‹À¡O¶˜èG1i—Áú•»l`dè$Dݨ °û8b]¡üDã#©t_Ê…'|>ÂüzàŠ¢ ÈÄ2åaÿsæ¹Dˆ0 G¦„‘ÏíxëÝ%“ìÃÌ0þ)r(–2‡à²þÁü˜×Óñôr¥þ¸&“239Bç ÈÙÎXæqíWûxŽžûe öÀ*xÓ,KÁ—T9xºïŠhûü4ƒ`‹Çþ*ÝBYÕÐ88ßI‰€–NžÿJ&úZý]Æ@à™¨'6Èe èl”g `—‹“ýúô˜‘—gâ¯t.,I¿¹°—»ÛýQ1.<¦)MBã2” >x­üF%·wPc*fÒžúF=f;ò›Ñcèt“ìGsiYL(Ì:4­¬$5/Ø ãÙH3¹4WšiîdíÔ).c©=$i‚8ºÈ;¼bðžÊ¡ÑÑÃÇ„—nL6œ}ˆ¢:TWëáç'Râ1ˆïb³$掤Žtð.á<†jÈ2L[ˆ_‹›}¬ÅGÃÆ 5&µ9Ð[ÖÜÑÀ`=ޱâöøz’œˆ%ÒÅôJ ä˜B’}LÀ”¥×›ÚL>&7•ê¯è-nA­H”Á—®»t·ÜÁçòþ²œ‡ÈÙñ 1´‹-¾j`Ød÷Ð…eܱU‡q p~Êš²¬ØŠ¹8ÏD*2 s+H¡|°ÌL¦Í°‹¦¸½<4z’Ú› 9}¿B.8&󹲤‹9b> ”'›–4‹G(XQ;}&ËŤ  º¢¦ì4¶¬E†òË¡n¿ÔÙ±7™®8ºÆD8g–|ÖÏ­4w0yα3ó•„9”‹æã¨  ô‚A ŠM…ÛÎ 8¨RðòqËòÒøå&¼9[çtʬL°†8`¥27üÝPÆNÛÇD-#ŽÔL!Ù­³ï ×áuo¢ÏÆRe>VsÞÃçɯU|G+ /à6Ͼ¯ëŠ= uÅ€¶¢â¡ ü”~ àk/º±È_*”.3^ÆüýÙÿ“¤×endstream endobj 686 0 obj 6655 endobj 693 0 obj <> stream xœå\YÜÆœ·yÉ_˜Ç™Àlõ}ȱ%vb% ì‡Õ®ŽEöÐjWöù½©j²ÙÕdsÉ™H`@C7Éîêê:¾:¸×kÎÄšãÝïÉÅêÑߤåëW7+øgu½ÖÆÆÖf~í\`~7Œ{|üñ“Õ£'߯oß¾{±zôµX=ú#þ󸇝áçÉï׿X}ódý'‚×ã<Æ«À$Lå™S ¦w™Š¯ÿ°º^‰–ªîçäbýøH7V¯ VÂïÑËgÞ´­½^;X Ç/VÏ6'[ G£7WñJ{±¹ìÇ^öcgñ æÛ¼Ú6VIæ¥Þœö·_ô·ocxuR¹{Ö_]õw/û±ßl!µdró¬»éŸË3÷Wo«9·y.šþÞEz‘.2EýãWé¢ßßOGZ Á¼ n}ôÝêè×Ï6¿í™t1Ø1Ž gEª3ƒ3ß¾êïþD×úæhUiƒCÙ]V¦äDZAåDtB"-¤äï[Á‚\öVùÍù–ÛÆHAGOÚK0¡‘@w0.ñYÅØÜmºãÝæMïãi‡b˜_â aÂJ¸tÌs.4x?ýÍV1c¼”q!Kæ<Î4ÝfJ !/òTo· ÕÀ £@hÍœrp°0¤±Š.Kf {}× B˜Á¼R)&”¤äƽʯ]åË–¸5/ÉjíÎÛ¼BÞYæ‚Ø¼ËÏFŽY%dG£Òo<Ê‚æÖ¡ä¡HÈB$@=릗ÿSˆ_%6·ïL›ÅáôÚúÀ@¦¢0Ý”:˜Õ†Þ¦‹“±Z6éb¨p½÷:ŸÍJÔâÆZÁ$—Òî3EwñUwѱÊéšöƒãžmÀŸ¸çÿ”ü¨^raáåÈܧۆ3ǹ·éô:I4DYÃmzÎ4W» n|MˆN<@èZÇU-9ÉàA2m ]÷EUû^WÅý´½´%´±×pÜ0/T›ïQD•ô<í' nœ×q à$ŽiHó:M‘èY~6Úz™ÌüuÏêwU ¯ÂŽ„ÓÌ€¦å³ºÌ–œåS9‡·‚=Ñô¬^V’[¦òyƒg‚×—Ä¡'œ²…·0±¨ÈÕ`²R,JÆÄÓy‹„Y8K-Û nL0Xfóz1MÙU<šLXý O;ja÷DæÌ(:÷$ß§Yåföhçùõ«á“\$š¿„IE¸÷°Ó[É%Y<" ªÎnóï­ð`Óx¡âd}"˜õ³*™–½`Û¶îhÛ(&ƒ×–òzplÊ1þýý܃R¥`¤û:úò$ODñ —…9°K—¡GC&¸zU=ù˼‰¦]M Wnu·_gây[´U %“¨ìe^'ÕiÉbcˆ¡Õ&0e}‰†*zø2Ïše‹Ü¯+'á+1’¸¬2p¸jÂ:¿;/r¯q²Àtðô˜[Iå.z8ظåà 5„ô9£^j²}r>™ÓUçªd\dó㆞ÒŽpw™–M[ת¨ïdb½ÒŒÂÛ Ð=r% W\FЗõ±~|ä-P7†ˆÃ³³ŠU—Ì:´=Ïîù®Û0xßçU®Í"”Â’lòñVp¦|¼9°2È·»uôõÆØB‡Ï&ŒØÃkÆ0B:âÿÈ“l ³²ˆ"0ãVM³Ä/#÷ÔËÍÛ,3Ñ…gÀ8É€y4—-þåâèBC¼6 [hhˆ*âî¡:0ÈÉÁ Ôñ–u I ª¡)Ç2×e@1Ae0=Ñ9ÔZ±àïˆ}­ì&ŸÇ×°ž¯¬'âÍ‘—BQ;«Êê¿:­6aómÚê6æí,,¡B²³q±:¬(]K\Âê‰Ø‚ŒæM"/8Xe‚Éê„jè4£šÞmãs"Â1@‹ÎD qvÉJxñ—wtÙCý|“ô˘º~5)´l„bA„°Ÿ‚Yp‚ó²ü<]ä<ÞË4t¼HÎ!E9§Ë=LaÃKˆ0ÿ€zçÆÄÕ^»w?Z{¦ ö¡Ú:;ŸRm•u(›Çý¬äÑ D:«ÑeÍ3Jˆ;þ Ùá·[ˆ‡HYÜ·©©,0× Hl~ŸŸÕÿ:cZ‡IrÀ%–ÙqéNLJ.n¤äC¨¼?0¯hù‡TmL²ûV8ÏË8ªÇû2aV$í.©´³ ût•«42sݨÖãŒÿÅ„6ÏìcœÁ¨*KØ|—ƒåB|þ2é,Ma`·@| ÐHöþóV*¦œB9Œ€Ø˜.ó00Qmƒge¢×ÛaD0pE˜=”œIˆúcqÇhö¬@•€(Š–¨/`p•þ ê‹ cÅÄ[§CEMÐ9¹Êzê÷ÃA¤Ø_ÕÁ¬xx¹<Ì;`æ| ÖU€dHLÑ™dòœÐŒ˜ÞÏ p¨uÖÅ÷¹û7ý½^ûÎF%µgï`°XøDÞªâQ`?†s4Ó_j ¦5àÊÅâLc°Œ—h:ÈnÑÓbÒk ÉàLxʶå ÏwzX–š Ó:[nÛ H‘ÿIÈv‚0'…‡Ë”Š”¶M’Ä轞 Ø5éA­U«âý79Qdz+ÂîºÅ´,Â’)[FÕÄQÛ¥–ÍÆL°§†^"K:IåÃÛI˜{€©: *ÁØCx ÚRŠ Y¯<¼6Ñ>Ôòµ$ÅŒÉ=°yl/‰ÎFHz ÔõµGßÂR‚× f™9gc5bص†0 ^íC “H…ù÷1ŒÑ˜ˆyÜáÓµèñhò/i$6ÆÁæe† »üLa¿PŽïFÛÈÝ}Ì•ª×¢“ë€Hâ* PÌvPlGG_=“z;:ŸóñOƬY‰CD”t|€é„›'E±Å)KÖh˜Ë{K\à½ÛÈiÒ]&¨Ùóªa˜ ët€èI«ÂT+Rí3¸íHt²T7t€eÁuX&,I£vyýÆðÔvÐ "AGDÉúoj¶³Þ£’*LܑΖËYË/v„eî>Æ2”Îdˆõ™ÕQá`øÚeŽKÉèË”–8è³'€¥<3¥šê2× ÆAIö™ÄÞÖ ¤!¨šÔ¯–xÆP¹ìÏh ni¡”$Û¼SoÆÀÑÅʉ3;¶ (lªà´{ÃE×±ÑljQÕ ÑcIÃ… ¨ˆ¸S7Õ –õÒoOyØü\=îë<ïϹE&°e‰¬§ºT¶'#Ü¥“hS)qÀðŰ­­ÿ¥Y1Q?*:hìgÂŽ´‡÷†õœ×÷Á—û wmþ½b»:·äš@µŒT ¯«KÆŽ…9™Ï.+_‡Žé§÷‹Æq4©ß×Ù]6ߤ äqÉn˜òvªL˜ªŒw¹tWמ°fëþjËIOìP vÏš˜2n>šïQ×õ²ˆ°>Øð~ê¦ó;{ë¨m‡ÖEnÉEÁ::ïÀåäA2X"fµ¨c±ß®œpC4™wøÂÓ®¹¨SxB Ïýa*O¤ | ÷³x]#P§´4]k²³Ÿ´ú ’iƒ«—qÈaNj¢™«jV7±Pc‹QÿŽÙ‘Þ“|?D–Dxì¿R ²$l9êÙ2=ùàY©ÆØË:ê8Fêb8ŠàÛN¥/Rc¨'Á#9Ø÷â‚,]oÝPæ~Ú¤¢öÜ.©—qÚ‰§.úíÒ7FN`ž²Y)Æ~ÄLÄNï+É#Y頼ǻ&_/ø]û ²Ýà½eöÐ07 Äv…0eÌ Ž ¡bÝý a­¹“s…°¶ÐeÄÄD§u“Ò•ºä8þ-ƒP/v7€°në²iÖþV0u Þêr–•P£Þç:hÃgùYÕ»ï‰Þ3.Þ)zÿ+qts]×}Ó~€ ì’@{›Àn0y€Aöíþ>k)ÿŸSsiÁ‚ò Êô[çB&¿¨tÖ oºÔ=Sõ ª£y®éø°O+͹{âH XœÎù¶¸ƒH?ÝUš#ËÛw(Û{{?\^µÍ‰úÓE–Þ¬ÍÒe0Ik›½J´‡ŠúŠ ÑæncÐGêù¤Ê_¾ëòº ß9@l©™úúiºC„.´…Ý];àî{‘Oß¡ø£CÉ Hʤøß,q+#˜!Sa1B>m>¡„Ç;•ð7s\TË ~ž.Ý΢«áæ0¹’@-ŠÆÀKJýµŸg…ÿmqp¨éƒìEÉJyõt,óm„’Ð`3‚bÜÒt¨Ð ÚÊ:™’&q!ÎÈ4vV•öòÃe;þpþ}Ê"¹ÚOYàLÜ‚žõJÃøcô›þÞ‹”l‘Ò`•,mñD_Õ\ÐGS-X’ñà÷vBõ’\ƒ_—¾àqï9gZƒ‡Ežø‘¨+ÚP #|ë ÉüC·£Ján»ÏFC'þ‰Qjß?FRÿc:B‚;ùÕ‹¡Á®mÄ"ª©^6TaÓ㦟®þ ‡ë “endstream endobj 694 0 obj 3413 endobj 698 0 obj <> stream xœÅ\[ܶ.ú¸/ý óÖÙÂC‹w²(ÄIкè%)6ŠÀöÞlÔ^_ÖncÿþÞžC‰Ò!u¨ÑÌ®]ð*E‘çú çí¦rÓáÃßóW'ÿ¡\·¹¾=NÞnŒuiÀfgDØxE€?²³¢ 8üÑ㓇ÿºyÿîÃåÉß6òäáŸðŸGß»ùÕÉw7?àDðzšÇz…ƒ©‚pi*)Ì!Su›?ž¼=‘ýª†?ç¯6Î`éÖ™MÑ)ø{vuÒ‰`ûa›`6¾„÷_ü¼=?…õhkÍöuº2AnoÆ{Wã½é æÛ^ŸîœV"(³½_ŽßW÷ðêœyúb¼z=>½ïýþt'•QBmïÝŽãÞŒ÷^2óõßð~»ËO«­Á­å |ö4ߪá³'í'g>‘Rýæì/'g¿ûyX Rë¶Ú:Þ›>ýn\þùxïùxµŸN|xSm ŸNÛ|ÅðæCü'À/o…ÖžÐòÕøÊ´À_˜Å¼™Sç}µ*¸u™/ÞÍ =2áeµ6BèDU• ú‡‘x/ªéðÞôù¯ÆU>É÷p¢ïÎN85S.zÔ¯Ãõ¬¥cÊIªcrP0å]¡a?ÝuÂw]pH±^ÐGÖï,˜€ÔÛÁh§£úí”±B:bŸ¿IWQJ;¼o­B¦SMCo¦¡·0•²BEËõéôÕ÷0huq÷êT‚“*ÀØ<Ø­Õt­çìW§^„®“†Nu{ª…µA©4ÒJ£¶E–ât $«¾œ¼Kk±± ¸Y¥ö‚8Ãݨ¬ÓÉΧ»Ï'½˜Ê]÷—®³[ŸÑt.‰(²\,! Üì€RQƸ9»†ÿ&o¬§mŠuÿc6.HáU/,·Y5j·^Ì5°²p£Já³3 \0ƒÃö¼á$ZK•ÖéÀðõËüo¹ÅJð²“ÞMôø%1  å‘$r÷õÄÂéÓ݇ˈ^”*”…õjšŸw.68…^l<*~ÂwBw†Ê™ŒÞÅlex—¬¡×-#]# ›OdÜ>¶X¥½Á­g!çgE…ó^¤ ø0 }YkTº|€Ó‚ØÁ ¾&öéoäúŸ§²ƒ©¥ÊkÌî…~°Öí×a7ð¾UDÓy6 QpFtRRî}ßz9³½Qha¼¥Ì{WØ*ت0j„†“š_¬S6o óëV-‚±J £ÀëüûÔ¥nÛ'dHLˆT¢núç‡q`‰Þùºt§+¨¯ƒæ¸‡2NÞ…HLªAVÁ©öÆÝ‰Ä‘¦ÓB»5'“u^DhŠ:J¡UM;¢ :x!•¥ay¯6f+_ ¯1»õšŽå•lXNe!*2K%%/•†\ûP“­rh-÷?0à¦Føú%«·H` ²M¹†¬”ï·ÏèT´_@^pBuShTbJg3õDjტÈ^‰éý*šïl¡h„`8}€)* +{„ ÂúâkèÎJ.â¸dÌa á)Ý „[«ëIõ–l+zTp kl«ò`df–•Ü´Hu°n(s\9O®ÊŒ¢3˜Åtªäè8ëó–€)%Eç×X…’å1 ¡ qœû8UÐö’Å,dc¨­[ ~ãÚiçá'Öà¼DFØ€7ìdû¤1[Ú‰¡WSôÕTckFœŸ3Ì©` Âã„÷¦W÷†9—úé~Ò^h](.ÒÀ‚áK\ž+)’Æ(ؽ¢ÛäðÁÚ šˆæ“¨övGaS’šY²ŸV üìû9„¶aÓ¬ãà›´t ô Þ˜^Ï‚â UÀ׬ (]P2¤&Ã/Ñ’uE誹À÷:¼UüemYBÅÐäÓ UüÏ)°@»^kÓj€Z_Æ*äàY-$Ô¥º®Ð°c1EN]LFý 5Dü5¸iôÑg‡±7G”ó4—× 0X9Ѳœ¸é…Ñ zï*Q3è––JŒÌÅà£5ÑHÚr<Žû¼O¼ÀY£èŒá9‰›ÇdŽŒ4Ùuùî+šÓƒ낚AJn­?(Ò\“þ±^pÒš;ɳõ}. ß8=$>B*¡LoYª`¿Œm*©…Öw>iÄr=ÌjôBÄ2ôˆÄÒ´sW ÐYX;ÒÛ3¸*ã Ë‘ø…œ.åŠ3Ÿ …ˆÁ»E´…=é!ËEžDdªó8jÕÖNÀ€ ÜzÑhšÖDÊçÉx‹•?ÐAMJö¢FaY©R–¡ OÙ–ò»¦acÁMªPåw/ˤ¬L˜o¸už/žÏR¸¯Ê÷e‚õè×ùâ¢Ìîòõ î ®r(X<ÝfSt %z¯K z‹á|¢ñ Ÿ ]ï>n»L ½±çLvi°òpCÎi!…¬A9\ MÑÃD :±Uò–R-Ýþ vŸÀYpQ+ŸÖ"…3¤Ü+¿CK1—Ê¢ÜWIåTµœ‹eQÛ«Är*ô®–ËˆÄØØÎåÝPZÎÊgL¼oª‡­PiõGG«hU¼ûŒÑ*Ø")|)¯±·r¦ÁI·*¯Ñ§^ͱy=í;`cú¶Ô¿£:}\ÿ`ÌyÿαHºîþ£Hºîý£=Auçߺ– ÍQ-=ÔM©ŸY>']º§e‘ø4C{½Êí¬4\ÝŠ ‹…0–p§ KXVb3Ì"4,{£ÔV{øZ;t$Q¨UZé×E‘+ñPïëhŸ“øÑßΟ’­OgÓ/c+04ªX;˽ˆÔÝ;:Í ¬ZòÆNÖyGÞ>dèä"Ÿ}6­~Ìd(š“ o$Uù”M"¼—œeSs°Fg'Á:Ä…9v@u¿ þ€Ñ0>n™­-© qN7¯s¼×vH‰Qgª:ziVÒH]øÄFÔH™~&Un\ºâÃ[„{-üFŠë)¡$ë&¦ÌóvQ»hf] øeÑàD_btfáZnF†èBw–à:¬G²®§fui¶4šQ•ñØØ¶?b°nÛ̾ÀãÖXM­¹W«iœE'¯±aï D‘T~ëÁP¨ ¾ /'Zô íƒ Ö­"q)SQ¿»_ARû)ÚpÊ7eíiwkpºÌÝÕð4ToÇŽ6sPr†P›/¸ð}5ÀDc° ¨Õ©¸˜®v9AÜ—®VVÌ_¥…X3|^¥š³´Weˆ ‹žzTlVÉ˺ÚqAkh—e5>Ó÷¾å¨¤JÉš(°c»•Ë)c¶±c¶Xõ½5<ÞéjîB kׄ@GaÐ p{Sõª4tÓÉ" ›çŠŠã Õ¹¢âxÃn†Æ&øz3yòj8LTO7³/No^7Ž4ÁÅWÙ¸¯ ¬Ð[©#«¡ì«­m—} ä²sUæÕX#¤KPÄlë wH¾à§ñ´YâîB¹ÔcÔ¦ÓìªÄ&lu0Û»v®”‘h¢s /TU¹)cÃÛ¨_Xf’±%.Ã6Ä u£»¬°­ WžçF0W7…Ò ù*çp²û©Nä>¯5¬J=ºf]´ôØÊ;-Q¥ÇNk·Eº÷Cih‡ÖË2›Îb¸uEÖ>ƒº·ÅÀG¸c"·xö͹v±Åsì¦îΗßÏk-À_'ÇE!n¿?•ƒn¡¶5lž`7ìASÁ.¾+íšÕÃwX9…mê¸_f2mdK¾*/ÜÉÔ¼ú’Ý¿²f@P!¥¹ÌÖ•Ï—9*Ë*µ ËBøƒ$,km‚1ûvÐú G”‰9ÃQnÀ/ÇS.7—>ãÔjÓTî(Õ±ÒÜV¼WËèš“¹³xÍY* Ë=qG(pÜÊÜ‹1HQ¿wcf+õHþH䘥é+›Bá!Öe9ûDf¯Á­d ïœi·‘÷„ökÎ"ëŠ& "I ‚>Âg›gv­Êt³~™<ÏšEñ¶¤¦³ƒ¶è·lä;pd]¼Ì3 û¹d}êHj/p«Ö=ô ·Ûnö°÷ƒ=*kMšÿ§>5¶å÷·ã¹YôäÒ¦5O‰ÎycOsªâ%xð|8µÔ.« Â>p‹#SÎ{ò««7¬NÑÚfï®KpPkÀ· ¹ÇÜߟŒ" ËðZóØ3ï s\4Å:ëPjÕ¾¢à=ö÷p.ìJ€x¹‹¡á+U«øØîVD^¹ =]gŒØîƒüß*©Nk!Ï…&++: »*Lj^ɪ¯8VÅíú¯dªÅ¦%Þï-œÌ(©)·®Æáò”¡æ«ü (x÷°cèâª` j•,úDŸuáODºNXæ> £h½J¦ú‹v Gz-ø\Y)™Ø€‘~e†WßýA&T”’÷‚«RaÀ©f sRÓú]ˆ•¸k¬ÝNY_ÝAÐë\ßYU¬˜E“¶TÜð@uÆÝ´€—“ª—‰àDƒÐè`äEñÁp†M»Mm`Jª2û>ïD¢ç±pS0U]eJŽÈl¿È}?¦d~ìFðŒos›¬è3·©|ª2ÈF“LunÃ+—¤4cä½âüèuˆu[X>ýÅÏ™¤Žh]VrÐVihi…§?ÿEþ NÉå>â¿KK`6Ø-µVàûÐ^k–0L/qR¿ð¥8¡(¿¢)85s—ë:Qõ'ιSÁÕdœ .­s[u’!müúÀg<ö•ÀÃðƒKVž©Öëÿ{ê+a‘û)OaÖ4ÌÒ;уÖå§*BÞÓn8™¢dL¸fëhZúÐ488¿ú ýž$õð+JwN V%µÆÏÍY­ý¹9þ§&e‚RŸñwë„D·A?sÛ o YI›þáä„3–ßendstream endobj 699 0 obj 4147 endobj 703 0 obj <> stream xœÅZYoÇò¸/þ ó–]Óêû0‚QdÄ b[² † ‡%)R‹pwI.©($¿7UstW÷ôðÐÁ@€8è鮩ó«£÷ªáL4ÿ O¶‹g¿HË›óÃþ[\5ÚØnCÓjæçóðGpøÇíÏ_.ž½ü±¹¹¾}·xö[#Ï~Àÿž¿úüyù¢ùÃâû—Ík$Ç;:Jhß‘òÌv¤8“!Å›¿/®¢çjøs²mžëÆê&°`%ü=:[pæM¿­ñºq\0\ß.Þ,OVÀ2F/÷Ý“öb¹‹kgqmÓ=½åùªµJ2/õò4¾~_ßkøtRy»‰Oûøv×¾ŸÞýc!ó.¸æèŸ‹£oß,ßDöv XÃýß-PÑŠØ+‡v²ËÇ)ùñ ð P²õ9Û+ùù¼‰²^Wô´Žo·TþŠk%|ÛNž›šžhÃ'GŽœÀׂ¿É;.û·†ËA5΀蹘âqÁr®ªÄ|îôÕš¯+J»¬œ­Åy[ð‚o“š·I-i1yQæCX”‰SÚÐEøã3ç\hH+hhˆ!.$DÍ™?¯ZÎçÞ"Ë(îÄòýª5`ïÐæ# (´¯Ô† +AéÅ{«üpÞ)èêI"@>°I{÷­ „‡m¥ÒÌiM¿»KÎãw7‰ÖŽ2#g†›*.^¦ã„Cr>m%_:¬ƒ2ɺ%¢,hc:EÍÊL³ºwàVÀ¢¡ïoFšý™y R`ð.Å ædo“ÝÉ)gU£])à%FÑWTpTtÊçaäó¦熸ƒ‡5 “õ5a´Ñ]vx a èœÌ„ÙŒ 'T?L„¹.–D*ð §kQ§D_GY¬ÿÜsÿ(¢¹°p¶s¦_W‚Uõe $Ĉ[ÿ1ž"[ÀVÒÕp_Óh…`N”#Á@hŒE?@.JƒÕ„£á>‰1PÅ‹ž¬ |PNQË æ¨:Ö%â8!ýò_+Ë„ãFÌàªC9¦¤$̼OTl²(·iõ"8K*ØžBN¯E ­´0SIïVR2- ¦1¨>$ç™V/’nK³Í£0ò dÏL|>Ñ_áC Z© ´pÇ3›1:cš(D¾3OtVë68®Á*óy¥É=g’':»m±]Z%Çß]|Ë£U«˜ ^[ꛩ¿Y[Ur{á uNÂzÝ»3½­NT9I}¨ÕIîì3¿€hƒˆ÷aør‘I\¥ÈM¹„óƒ„h  ê%€CR.á‹P j ,ì105€89ܽ+G–¸q:|Õézu;~UѼ·Ùyö¼:rŠl%låCÃZZhtì—®FÆ?·"ÈA9µ9û ôÕ°k|L-¸óO+(y8º ¨î±_ÚÕ9·˜AÍG UÐU ³ÇXˆ®·,+ ª#R“@»½ž mŽþ©Q,µäò f²ù ¤uÎóÌÌõR Õu0pYäNÅ3yÔ¢äJ0îõ“IEÜYùä. þôjº_/Ägêƒ{KPXßS~^sixáÐçl§ÙÇ{3a Î&€Šùú]fÀ2|52\ãRìÐî蔇æòIdè›K*CdøÃT†Ý´‹ŽsÇaìèÜd¨÷Sá‡YÜ´c…‡~0)‚zH£j gòÿÞ¨*hϽµó5“wLˆ¹rõcµ€'{ Jõ“7dò ã±ãjqLc$UœaÅá˜Õ¶ÂdÀ²ê½GÞÞ(ë }Û€ŸM†üÕì\tyÅR­õn(x×Ê šXç@ûòUñ5,Ôh€fB•)P[Õ¶ Y¼­:W¾ª•aÐÖUqÄe³ õù3Àð† î‹$I­ªt‘$;Ý€rM^wÊÚÔ*@í™j6þë—'JDŠ¿Ó¼m=.åe…/âà-]xP(-¯;("–—4”Wx—ÑN‰^§«Œý„Æåc€*aL­GÚW3o©e[É”(vf`ý–‚9hFH視ðb.2…¶^ùäá*d.>3UGªA3eÃÌx$+˜zfµ£sªl†Pƒêˬ|•аÓO$2÷9¯gš—z[JÀ|2©è0ƒˆ\Ÿ"Õ<ô0–+0‚vèa¤Hs³02În7´î†¿–X¯:«ÌMŠãVçCÞu‹¡2FžÎÌÆdô4 ƒHi†;ß»$>”7ˆ±NËj«ë •·‡´Ü*ï# Y-·(³™||(oòàSSô÷l`ü25•‘È¥&ÎvgI5ÍÑH@•™¥vùÜ¢À þ!žµp4™"ªtFªõhMy²>š&áNfScÏÏ.k:×O¶Ò)¦©_̦‚Œ€AºJMæyÐ5ô5°¹HP=¸~þí ÿ¡œÖ! g®`®»ê¯)ý¬Šô9LK¨Ú­)‡½t¬‹Ìþ?ˆÜ+Êé4ÌHsÿ€29d}†<7ù¯×Óùp¨KªBãøqõ¯$_ÐD÷û ̓·$m"<¿èIÿ×ûÔÌ,`³Ô2½Ÿ ’ñ/U_¬fæ‚ o—"ãéQ&3ëIæ†Àºã§F©OýiGý‡š*‰³Œ¯öÌ£Á6ÐE@Æ*ºDÞ€tB¿^üí˜endstream endobj 704 0 obj 2340 endobj 708 0 obj <> stream xœí]Û’$7%xœ~¡gº¶t—xÃÆÀ\ LÆ;·õsó\l–á{I©ª¤”*ÕÝÕS]»v8b§]ª–”RêœÌTJýíªmتõÿõÏoŽ^ý•ëvõöñþ9úv%•/¬Ö²±+c\cákUÓZÿúg¯^½þãêéáùòèÕßWìèÕïü?Ÿ}ù9üyýëÕO޾x½ú‹¯¾êΪ†CU¶Ñ¡ª¶áSªjW¿=úöˆu½êÿœß¬>;…®+-W®qšÃßÓ«£¶±ª{meåÊ´¬ñÏo޾:>?þ¥äñ]ø$-;¾Ï®â³wáÔwüöd­o,—DZø2?Ïü§s¢ô]ütKoã³_ž¬—¼áÇ_Ågñ½TóYüô?½ ŸŒ9þºÿðõéïk¬qfuú‡£ÓŸÕ×êE,eðÏÊZ;±‡gëøé>–>rÝR¯‰Ò»bœjcòt²vÿdÐàF|135ò€ ¥ªåÇ×Ãø\¢nÅÒ§qé#QúK³QæÏ?ÄÒ¤ׄ¦o¼Mü@ÌÄsà{¢¹³4HÏà ½C ÇÒ‹¡4}÷"•^¥I¤7©ôÝPšA“ƒgâ4¨áñ¤õsžJï†Ò$æ¦Q¾$æïë¡tÀÛ²˜ú“C> P¶›Tz¿qqDõOÃö±âËU,}CŒÇ1À÷i€ß/&OÐû€:³Ã:?Cc:<»,ÆÇ7•Æ,ÍÑw±”j~K¿GÀ4V¶ÛãøT‹5ÑÁÛ8©,Ü® óÅéesqíL#÷1ºj× \¬·¶¸Ñ™¹õç“uÛ˜¶µ:¨ƒаë[øªhµøñ.–߯O0lœ+ƒþ% Í*Þ|€r©fü¼ Z Û·¤gøéy÷Q81îJx·kÀ1¦|_¸‘r¨Áí6½ð6¶‹d¹Åá¢mT«èž0Û0¨ò¹¬ÔðõP½i%çCóþ)z·¦'[TÁÏÏæHv½fð9·:½€úÙЩî;uCZ€ê€1­-k ïf7RCi Â£HHq ô2’R˜áP»^é*ÿ_Þ±BáüÇ–iønâËÖ8ÁZé5bP4¡h¾J€v î•Õ‚v™Æ¶-“ÞüfùñD4JYîí@xêU©ñRÏF!…AÝ‚¾@iãÛ"5f¤è¡Û]ʵֳ‹lWZTºP×d_¹J•åM5Rxˆy5<ïÅ å¨1ÔºÝóô.RìëôB^™¿RX‰[£eO­VÈ[Œ c°@I“Ø/¥èE#Ò-–5o›àtÏUÃÿ¼ÇªééEK¢äîhõefôzTV:^ñQf6–´Lz&ZçÝ ¾Y¸\ÁøÊžFeã²GÄi[1£õeK‚¸Ü!-ª)+¼ 3M59ç@šB©ñà èà›e¦ç©ðô™”‹£·] Úš ht˜`·Çÿ>Ñ@Ú­b9Y÷Ãå©j¦Ó`¦~ –Q|áÈ3ÙÔ:vv0w!ú©ð""UäÒòÊ“/ÙÜSò ôaŒ%Ï„¯:‹ß,‚ÁÛÊ.Fß»ƒPĆ7±¬p\#n€9µ pµ7\. 0Hàbàúhä4àF5³Ñ® HÿåÈÚ ¾é¾È!­Èc»ýÐplú>²ß[̹_\ôE4iªÐ ÒvÌh¤H·›ê»A oÅž&œØËVÿø!æ1Õ1‚˜Ø¯óXVDÀ‚`u¹AÓNxÒêfQ8áziu¯ç…ŠmÔlÁ,^j¨±kÒ}…ÍY ز»Í#§®ÏÎüàɈ^;úÏ3ñ¾´Ú‡b~(‹rìjÜUÚ&(]»­@©u£–uú%øbAvðEò&{?®¶bµIƒ‘K¯¶«d±eùëÙj»/bÀY¥ODø!ïÄŽV¯£`àMZ#¿9a¢qFé"þª øg³ÅÈç O¿ñïZèB KÜ•3W²Ö¿Gd´r¦ùz Lö¦ žöd¿X´lZ!*ê(ŠW®L´¼¿ ºeŒÆ±®±ªûíSŠÜ^&˜Æ”_øzEcÁõ½'WÞΨdäÄÅ Í gçy¼ÚÉØùØÞ FCþ­³ÒÂ/Ü?K- Ó¸o²€:³ ¸ÐMÏ8ëçè–h+ëz·éð‚™ T“¢¡I 'µSyëš–‹B§Qo:yM¯ßPVÚ\¿9¼awÐï|Ž‹8ê.!ì üÖmWŠ1îêUªq Ö÷2a¡‘Ï’á1 íeÎÙV[´a¾SÉCŽèð¡Ü9C6M%å®aÊq1y*L¤„X?’çE†”Ð<Æ«—1¤´ñÿüi ͸„ñ½"׬\ 7í¼ùÄ-m†ò+ÿÔ3 ©¯7mt¸€;‹Ö9Òø³„ñ9KhÉaÍãu>´ ~QZ±cëÌWÕƒ½d‡L/û‰ü[ÀÕä.c×$ØZ•8èí/vÝ5(½Õ;Xª±.˜mãX#9ö\kèêeg­_Ê*(†mm£nŠÞpºô­‚1Èý’H0ù?#ÙÖe6êÈ,¶ÆwuÍéßÝŠD`|Û•nº/¾D­ÑLù 7ù#d½’ˆ0@‰m#e’r«Oq¾ï*Û6bíŸ;¦wÒåB–$®Ì÷ ´Äix‰×¬5Þ©XGÚôȇ`áÎïn€.ûÝ‹áSL %Š®§Ì˜ˆ¶j Ô(鎅 å?¡Ïÿ<ñÝõ®Þ:Agýe¨úÉôN‘Ø=#=Ðå.`%wE ±oî Ä,Ó®¢A:ÆÛ!êa^—gålLƒ-xüzÖ4èTœ2ÁÊ&_ZâZŸ Òϸ@CË” 梅ÆfÉTª o •á]f)KKæfײNeYB ×oH 4×ã.SD€wÞËéuvH%›Oi7¤’aINO$à+˜šÈh A´AŸÌ«àÝzF¿òÅ¢a[BtPµž[7û­ÑÞÝÈý,"Ô¤í¯1}øú³X×ûž(Üã$¦8Þ¥%Å£wþnÈdK&Þ¤2k.´«ua ‡¼=peÿæ=E‰™~[òÏêðŠ:ðÆŠJÃ=wΓöªhMgØ9¸³Þß?4sp×[=q@_íÄÁÝ—8аPɿׅ´y鮼±ˆ<ol‘'={sî:gb±®s¢Ù¨ëDÔ}¼Á›”7÷ÇÙn²tËo ÁùÖßD²ýš†'³ÒÛL>Åù rtà|´OU„wïkìþSë$ͯˆ3Ç=»ŒU:£GðöUY*.öûu>Ì žm(Ä!0Õ@¿@{‘c:÷=ël®Ž)ï<9¬¹ªaé0É*Ü”˜‰6OkÁB¦±£gÔ;ÍÖ6°j;.Ñ»“çÇÜ3ï(fЏÖ[­VtĉŽãm I <@()‘凯L¦ÁimuvÜ€žÅ÷}]z{èþ*…áPpîÚ‡E°£Pgá]Óú¬$5ÍžéQŒcYhŸˆÑoÛûøiœJ䜓–snZ²ÖxHÛmß V©ßOK!bÚÐE"%‹•¥´/AÇF®K]Áåš+<ë4ôâEOÉ­zÃe”,SFEï3x(¶†¸‡å`•êãgÜMTç“ÐÏqè·/sÎŠÄÆÂ#‚uëðméð.løxfï+´|§a³\ç$3‚Ž/ÞŽ(x=¦îÛô=¿³ÁÔ&ú±)Bž¼‹ÁPd [&·hÄêáMn@ÏÜÊoTóñ¯“l6iãapLö0*þ„bóDÆöªˆhqÕªZÞ¯dŸJ@‹û¼‹eZx\’î§³Ÿ¥ñ›ˬº#2Lé"bÀºÐ6ã`a¬ùTu“$™Û„¡.0k_'BÿÒgÏ€=ÄÄÈZ/7^«yþÈ£®eƒf¦Që7©‚p|ƒ·­¨„ÓP.J{aÒùLQ; BGÙ²ÍçÁøËó6•öP› ä «ç *íS…ݲ%BJþ@ܧÝ> ½PH) K²tL¹—›ãúÓ6y†Òòô!¥$Ïá |6ÝáIC!ø‡Ãê~ã`9¬®lƒÕÓõ£±\‹É·_ÍVÑ — «a|–°³ý¡ðÄÿ*AŒ‹øÍwŲ÷Ï^ˆÞÌuƒÔê™î¼Ø€v\4àPs0 †ã€o%Âl/"2M.O‚êÿò”@žïÜï•÷|É2`=†þ|ƒÁò¥¦–sˆ E ,¡‰<æsä±ÙVó&CkyöõOuǼÏ4®Ï,8xÜjRD©_tÀ@›ä×>³[…TÿÓ“µh¸³R~âãI>kuðãD-º8å¸MÚ2ؼuî522çt¬^ËÛy¼œ}*¢¼œ–©¼æ`V?/ú:ÕÜ×ËAÃr8/gy:/ÉsGÌÅc!Íã‹(kìׯÎ%ÂÒÍÈ|™7ÛjÜÀ|HŒ‰¯'¾$ÔYÁÁ‘½Ûæ½æ§ä†{Î>2ËÜÀéJFsŒ™Å Ü«"‚Ì žƒ§–z”³áøÔ'Âf–Mu±÷f34.¤³%êéŒ(]Üy^ˆ±5l‰¾÷‰`¸ïb«ù–Û&¶BrüHW=]õÄsü*U€žŽé¦ýPt³‡–TXÂ1‹¶WEÝ}ð´NBЊüT¶ˆ ³ÄtƒÆetÞÐyã–ë¼Øå“ºË†PmBϦ¡›‰ò#BŠ=]K*Àª¥›Ç³Ø§" ¡µœú3-{!´Ò~×cN„N××ßìcÒ_áá±X<¦Ç¤ðÉ~cÉ}G¿‰/oŠOàµ!ÃJ»`$/"†ñéÔ™å´å<øž˜zgS½MЋúý2èEÛçô=%tÆ:zz^‹† ¯Lë÷Ýw„õ÷Þ%ô ¾٭· XÕ+P"A8‹A"h­™‘2w?GT»!VRG ¢ Ø)P<]k*ª&§'ÎXÅŠ/q¶ÛãÒÌg»_ÅRþ°sÅHòiy;‘ ¡ÙÔ;#Ül3º áT8ß(aÜ6z;¨Ã —!×}i_‘')Ê{û÷Éì‘׋jx_±<Ã)`øÖ˜ó+4¡i(‡o™Þ äÚFä3²'ÈMWœ 6ÉÉù{3VDœpKCf‚Í| ùE'Øáæö—ŸâŠxÀr’õñ€$ÙwEÐEg¿RuVH†Ã1ª»ºgÓÓMÐDÚ¹3CÓg¦˜îØj¸™§Å?¤D_´9úq…þ°ìpSì¼G3;ןåt\{gd…eçþïž9Ôðny«úûZ"NA»¡“†M‚4E;ž ë¨mûÇNÜ8Ë-noO꘮¸ÄçðwC{ŸŠˆV¨g‰£bŒAoçàê—HéŸl…4«!äV†‘`îàAXÒAÿÑhâÆ£î¨Ø"uGÅhR**qÝÃ#!E¦ ‘4fÓÐM¤ø"EKékË3ÔeÖSIËæ²[Ét/¨˜ y¼¿<#fu£,ËÛÝݶŒ¡>#h.Ç5Ó)­ˆ·ô"s–Ñ }Ñ})úZºžárÜ×ì^À÷é'ö¿T QsX“aJ˽,¯¬\J¼ë/\Íï6èßìŽzwïÅ“Þs:„5R€r®0ÜíD?qÅFwƒ”ÌïX*¦ïaO´A¡7ŸÁ¯{,ö ?¶âVDm+–8×çä,ÇúG³N-p–/°lŠÃqìÒt›¤Ùå't³;#âÿͶ$r=ƒHˆ†]@NŸêš„<ÐùVác"I±·)Á4̾»ÐUOÑ_¼.y±ýâîíÓf;ß>½Å(Úæ)¼SkÆUVîp<íþÊÞa8ð’¾äå¨2úÀâ¾¼@–1êÖŸ‹@MÐ?ÿ[ýQàþ'1è¼ÝÞà7XÕó¡™QÑ'Zéž!Tÿ5iƒ=zÑ5LÕÌp­qŠm¿¿*ß­ ¦§©\9æûKB¶Ûo#xξšéw óû­‚e ¶ ù»|ôo TK$HËj7v¾ÁóÕ‹¨+ïFEuÆã»ÕyšÈïé r{õýìTÍÃTm›9?Á`›¨´eÜL)ª`ö?>áôÊßlç†_ŸQ‡t¶Ê‚À9ú?‡‡Zbendstream endobj 709 0 obj 4698 endobj 713 0 obj <> stream xœí]Y$7r6ì·~ñ_è7wªTòN.=hWöޱkh­±†V£9ÛÛÓ=WK3ûëÁL’Af°ª²:«¦L—ò`2È`ăoÏûNœ÷øßô÷éë³/ÿKÚþüåû3øçìí¹66þÍ£³/ýñüû»çg_þù\œ}ù{üç›ï~ ýîüξ}tþ'l^ÛqChièlh©ïä’–úó?{{&ÆNMž¾>ÿæ1ôÜX}î;o%ü}üâ¬ï3>v>ès׋¯¿>ûáâé%tG£/nÃ/=ˆ‹›tíEºv~A{//7VÉnúâyõ Þ~’®ý”~]§»éÿÇÙ·Ïp<VazF£—bá¸. aTçd1ÏR—Ÿ§.?M×ò=ÛŸ A›NŸˆ Ác— Ê]þyÞå‹wá—sï«y†K‹?žWT;× U*e‘ƒOAªTŽ™8èí»j¶àÒ›•„€j1Jë]˜®Å«±Eƒ´‚Ò "Î|{¹Qô°ê`-mL7x! ,¦ GB^ešžçþ:!‡iLêÆñ1¾BÑ ðÕ§ùÛüÚ4¶Ÿ(p½–’~â*_%ÏòWÉÈŽshŒ´gdæ_æŸ.‘_¥v¸¨úóÇÏ€]2éxo3ÝÜ Åy7>ó—¢óJôš~‚|˜ŒŒƒ|'Œ‘ÏpÏ;¼¯;3ýËå¦ï\ßÅLN"üñ _³qšŸì—‡IïQ<‰¡“}¯(SN¿+^d§´§_ $,' bºj%%¼ü†H­ðôW³e9MÙH¢m<›hT '6?A8óÅÔI¥wø Ûõ§#_)x"2ÖlIWÃÔÁ8w^´ÀV Î:×ÁŸ ážG1|“Dô“xé§øãºRÀMe£z; €¶xaAݦÖ®.J̳¹v|/%ÅS£‰61º÷ãN@ŒÖ I bR‡žuxeˆ |/NF(h]ÎÚ“6›M„Š Š ’ÝÄé E®%Hôâ+¯Qê€Î³j’Z“ˆU\2¨:DJ¾XD8äGoñQj“öëZI rÞ6¤ÑNä5^ø€š»$䋬‰˜ÉÊ2(aP»r”¬T¯¤²öJÒ1\½Å«¶s «¢b]jt‘Õ/.¡w’ò‚•åDÙ\]JEä÷ˆ”c%UßÕ¿\p:.# ¢v>á[ºsª+,˜º¦ßOcM`Å0×[™:áÃøþÍ4V^TW™yåˆk-åL2Å3”Xç/—ãÌká*¡Ï#g£Ô¡È™7­­ðg?WC‘8eˆn­pØâ1ÅØç Ó‡mžC‡…Cz¨yNƒ³Î3ovõÝéÓõÔ¥]ÿÀtý]u­t,Üî Gö€þäiÈ‘`WŒ#éI ƒ¹¨-³½Í`£¤[¯ævúÍ;TË0Zçë­Ã-Ö9¡öûdI¹zË™)ÿË¥1`1ÙÑ 6€œ9Ô¢»±ïÀì%Vþsöý™X'â}èªÒ¢3ÊÍ4_­M>a¯Ms¿ü«µÉGÀ»‹Ç—ܽS-“¼'d°±3Âû¨½ÃÃòÏïÒýœ_³ùµÛäA(| ¤ &Ü8yñßÄÂýù¾Ó¬‘AÑÒzqþøgÿõ‡©uÄâ üÛIe§.f©»Œ¬sçQËAtª—ܱ"<4% ‚#›ý0C—¯`Žð x¢M'<á:vfW"gÂRD?\¨ô¨Éêìü „œÐBÂB€‚ÛkЖš®W CgLghüúÀ¢ŸÒ#ˆ2X{ý +$®¨ø5|¸ôû8ëóµ?؃À!22Ç¡‹6âÕiÉÔÅÀárÅäªõá̃°qó`£V4Ü4×ð˜ ý6ö2ð‚÷t"w(1ж£ÑQSD4z€¦h€HiW‚µ‡4‰“ºOXùØz±(ŒŸ°Œ gíLˆ`”ŒÆU…< ЖÑèyàn—úB<  ùm9©T¿ÛJÆÖà òeg«1æ6pF(88tw*ÄZnjÔ£nÕ ZõCoÉë/à¢WÁ±{ü¤€CA•ù`dåÅ;Uøó‰ -}ÊÒ£ó_SÒ“NC-ÿe|ˆD¿+Tsüù4ûvzçŸeHÿFÐb]‰ÆÐɀιÉý)=ZÓÍMt•_« +¦ À¡]£¤y€~¥Èé¥c)2ct±,Ê–ó+é#ù•P¨$=¾\¨4Ôo/>cClæ´¤Ž/Mn<Œµ|КÜx¥Ží_›49׌&¿Þªø8¿ÒI:üJ|ß`f2糤pÈûêÞSfH¬Çµ[Ô<¥t 5‚ýNMÆDÊ⎹3»$«ühö†d¯šár5xЪââ(â”ê5õPü!“ò=¼ß»Ç*Rx¥4W£›£M4v –ˆ|»—ÝR7„º‡å­¼бlW÷0‚©tIì9Q¼/)_-­l>1¡ ‘…ô Õ†y1™æ†{ŸPüË%Àeïüëäu*3\ +™ÄÂÄO[ôGß‚š1{1rCøÀã5 êq|AvmL7÷$˜Ñ‘Ü&¤y`@ ”jèàŸAÐèÁkÕÈâÁÉE+‡á‚Oo(xjê*2ÄècVòŒø‹$¾à)Ru=AÒHD%ƒcÏ‘›w›’ûÌäèw»§(¨r\²¬KÞ:sèDFw"ã “-ß/â â'‰Uüâÿ?4Ä2oÜH-HšÒÆM‹Jl2 ȹN™¬ƒð\™Xõ²!]æçc[Eª 6/ùg4q|C€ðŽ@Ò.¬4`´~+ÍH †£ÑÞ1&60N9zèa¤éG· ’ð%œ£ÓËêÃäã€O(2™ÂjJ¹ga¸&ÓØvwÈù(ÂczcTHÖý< EâÈ›Œh©?›ÏŒöAÚˆ…cz°q@Fc%ãàÒ÷}²¿ËÉxRQ›Â¹EâWŒÔÂÄïRO)á§ SÂ)ñW38I2.¶hÔ¬·Ú¶5¤“kú.ïoÔ@g»^·ŒF""Û팯“NÏü\U§x/ÓËè¦jyûæ~Hâ{B—ä»ìo"ð"ÃÛü« â°š¡NÆB0§%ýìÍäüñäЫ-Žm-ñx뇀¥Íemß Í¡¬jÓEDÙ`}bä›# v¸ÈC‡Q|ÌôzJHp„ç®XtšÑ+vyW¿@s±ÛC3öÝ–Ä~´å,€¹--›-ŒL…ùJ•Ýi±)§È·f.àíkcbr&#¡È3` P…ÙjigÌçY¿Ì z¾."ÔªCV_ʇÂ3ä 4I¿ãú¼É¤”ÀQnO{‘k Ã5‘!¯ ®ˆ2ˆGÑÏrˆ·fP$+Ð"²ÊÿiÖYQdݱ˗2ϦÄ2š@ó=/S¦qÐo¦WRúïïÉ’¼M8èB}vð yÜÐh: >sN’ÌV6õ!Œ…l1k=?›ì Qç[ÛY=U¨Åí6Ðn;ÍvñÄLý¨옷=F)“÷§¼h­Æí6Âg[on©Ûâ¡¶3lúèheƒâSþ<í-!#@\6›ø\b¬<ó]7 `p¶w;‚·¹MB2Ñoø ïCÂL%;Qà”-æûiH.úäÄ µYϸ…²ð%Ü6Úĸómž÷ÞN˜»)E¢¹~?P$ŠÞ4tÒO,RºTSmŽ“$ù-¥ßgÌOs”Ç2kEßâakgMeMÃ/âöE¤ý=²ó¦+ÒYò>YN¯QW 0M·09¶¥=½_ DÑN_ü—ÑxñŸ…ó™dZÀîÈ›G…R‰øü(™VâÚ{5©HäL”(ù->áàn¶¼ª¡ß)`¿H[ÛRØ™y3¾›Òçƒ( Ò} ãÑž²õXšŸlã“iöJ=tPC%î>î²¥ÍQ‚ŽÒw©€m“ïR5ÜÌ3ï%^Ü™¼—èi-xqò^ÊÚÓ«.½—£¦ë#£ííÄ]щy€ë÷=jëõ*™Š5Äd*B;§paj°HÍÃÎTÔV¬TU`§ “ŽFÎxšºœ½zu²Ÿ 6󂦪'!h¬jA Ú'gqW½š²¸‡nqûQVÉe*| §hÕ¢ÒÑqU$,*k@ÈfÂâ¸ûBoMXLYøÛÇ-4r¿„ÅàŽIãøÙÃØYGÓ.~›T[ —þ¾ûªü_³–x€¼h¨Xm>cCœ®Öc%‘cëjeÁ"=\W¹žÌóôR]a„Ôåô¶Ð¡È„Æú*ÇNí[²ŸJ#s½­?}åø‰)ú” Œ¬>2Õ‘I¼›7Y¼®žÃ»yž?T3žç¹]®J(yªÉ•`E#(#cqÿŠU‚YmÝnC0dÕ®`BÉ¡m›.zÛ餮×A1ÂÚíu‰b„·t{ÛÅh„¯°ë"ìôž».ð³õ•ÀÝ¿ðë#"úŒ;I³¥—³ò¶k[]ãpùÎ Ý.0E`3é*Gtÿ=ó2"»‚¨¤½ ½¿;€ƒþ‹ Ó>ÀY.N¸DöÃ:ΈCâŽìÕ±3Qàt=lg„KÝ;;#ÈhÑq ‚&g!è¶š ìòû¹NgJN¥b»¦Lbte8 …èÒ(…+C•ÕVà6¨Bº¿JŽnñÓmgKŒ¾¬ºC½ä¾r¸HàuaÛ—˜,µÆѰ­qO‡KPn% ¾—œ!BîóɪÛ!kâÌkQ¢ÄmoÉWŒXÅ£”š°Jó0ÞLXåïuÍ­2¤z44ƒ=œ@G£ c¹`ూòV¯âU9¨!t@;G¯ˆ  ëâ>lÌ¡†áè¡  sÁ8ä8 =#ä`éIµ%ȮΨ‘wÔ ;E×§ºa¤ëëB‰õÖÕ(Az¿ ’‰_ª$0 måÐ _kb*HuŠZH³²{"‰)û‡¨|¤iÌ`*³'ærÒôg;¥TQjŒ¸¨—Ædáþª÷wëýVqC];¹´ªðŠ qzß wgfº«®ø—Oäl £±¦Ü½yë$›·hß—f*ëKñÚr5nܦ- ¿ªË_Õå.u)Õ” 4åòÜPpÚ--¼bCœ¦Ôné9ZiJåWU“ܶÚ:(½¥òŸ6£)¦üR7Ãrý¢Ì>KÀ‘ÈÕ âÊUÿøXÊ Éçk©æó|Oqp¬9¬Ž,]Uyí«4 n|J׸~e_û×{Û«qÛ6M‡ú{îž  V- çÕuaâÅy ÛX "¼/zËDwñr•’(Z´lt-ùpˆýΆr»,–!ׯÍ÷ÇMHÆ ¸}µ‘ˆÏohÙµ¯.Wë 9}óÓ—ÊÝ’(q…ìtQ™¶Î&wC¹‹£•M¾1 KD±™ ² E×>7¨ÓÅ!_4é¢K¿ì” —NPpç«òô ‘µ_ÁE!ßÀQÖœmÚùÙ{¨¹å˳¡¤úŒ EÒ¦—è¤é0Àv›Pèt ÍÃRv˜vlcjRvd Þ¦ŽÞ1dÜ1zeÒr]//~H·_3vñÇ]W?òÐ —T‚dwnFcºT Ã!?¾'ù9Y)ßTC†×^W GçÇÌ@yð²Û ó!rZ¯Ã.º¯ïÃ]5ò{|å–A,õÉ!ÙªÞ’(F~íÕ ¦mô3ôr~Zs&W*¿’á=ªj!Zpów[‘׸cUÞU£¿~Üæh˜„\BX«I¹m‹°yY³Ä¸ú (‚vfG$F¯ƒ4êÍÎmĸ›è{WîE'{;·_Û{ôpZ¯ºAØŽ&AZå`âV}iùÊ7óÏ:z›¯ÞÕãòÏfWíT0TtìÅÿج%ŠÔ€»¼G¯N÷9hßÜP6ç†=½cŒ_’jìNû)Ü/‹l)œY)Çi‚CX—sÇ ŸÝqø¾Î’bÜ×ù›ôd<®NëF†.öuÿÛÜu˜£êá`yð‡ÖÅ*Ì»ŠP ‚¦rKÏã:àÈFŸ ý]®±}ÉÉezÌl'…ã¨Ãªi&&‘w™£”ªÄ0Zh+_¢ú«ÝU¯:YÌÛ×UWkùÚwZùT‘ |- qk¹]$A 'JÛÆfò7Ùj[rZŠPL†òg‹´  Xüõ®Û#Ü ƒ· €gŸiƒU*˦°˜ô]_¾|\³aWýÞáLvSé;üEo^Š"¯„gŽ›‚3b¶œñ÷å̲ŘÇ=”¢¿v3ìÅnƒš„òýN÷U2j‘_ñl6Ñ﨔ã5UòJ-ŽžnŠÌ:  ‹¡ïÆ‚âµv²Š’…éøÚ«ùJœßËŽ.Gá¯L§Îk`d ´óÿw‰%dú~çäi0ÕhÐwç'ßÄn0˵ЦÚÕÚ«qˆ?›Úû“uÝè8õ²&€ÙôãÇBò´ÎÞ ÐÏÑTá3ŒõŽ~AO$Ú ªZÖ&×—õ¨:,(ê›fa5[J’Bï¬ÛU«-z¦Œã–ÜYÎä&Ç1w%-¿ål ÒGÃWÒ Zƒ ¡^"LÖùMbfìýÖ©¾ÕtÅ ÏS1™.N®F¬x¤ë‹Æ„Cöba“f©KÔŽ92w^%/ÓÆ"ýVûÛAÕ^µçЀ®²ŠâϲÄnãk`´E\ëlÙÌíµM&w@òè.wðŽX°;—’µbCLàR¢{èøÅM„_É›osÞ¸_Ò¯¼—%oÁ­ÝM[œ½ÀA8ߟÀÙk~‘ P}T=Rñ7Æ8zxÁó3ßcöp:—MÝM5<9*îþiG&—UÞ¼©­ûŸqM‰0ºUÙÚ^tbð|Wf ªq»· Û—ZŒ3Û®}[ŸãÐߪɼp‰ ÷ÔåÍe6ÎBÔ´!¼çvD@¼<^‹ ˜ËÏ×Pyä섎^NëÑ|¼? Èêýeºu`m-/Éù….úã 9¿t4ê=e8‹Á0#s8?ã€7ÌË·seË)ûÍ€ ”æ"pu÷ðZÝ=üjÆ×ÌÖ'¶qÑö±Èq¬Ç¤Û™”ã„çvO^Èm˜bièÅxF¶)Œ·œô²«:~¬Q"UáÃÌZŽÕg¤@d¡yRP­™BÀK‘gD ÅΑÚ,„:#¸¤¦°³5˜Ÿ²¨ûo ?aMaië*¾­â¸c±Ö`Mº„=>Œx*e³™ÞNëí0~#3ó Kßú®7íÔs¥T­„ ÙÔó’ߦ‹„*V„oÊ ¦ìDΘÃg9}w)Ъ×K˜*9tdPûÈõð° õN•î;)tyœF¸¯Hcºb"ôÓâiä­œPÎV˜¦³?Ûg<ñ{ÁwFT«Òz8KedçN’!LVâ[>©;oR'§W±›ïÉ(HYÛ|ü[ûè2DþZ7*‘d†½SXKÑôÉù·ôÔ˜ÅA·íy£^ŠÀð½ÔÀsZ--LºbCÉ &“ŸHh¹ôD°ƒ`!¨3±†Ÿèªz¥ØÍ–jË æŒ€¼ßºòºóÑ„¯«=Z)â@Û\+8ê è¬6ìÛ€ôF²waeai¯wºåï}i,>Á:¦ËCLåÁèBðTgÏŽ§ÚjgÌìN%‹!Kþ²Úì h‰!Ê7¨ ßÛö‘4a“¶qÇJI6-g¥†HQýғ×ñ$Æ…½=ÇÂý>žž¬ÒÄ»Âé(þÓÙÿŠå*$endstream endobj 714 0 obj 6189 endobj 719 0 obj <> stream xœí]IoG’ô‘—ù <’¿råž%ÚížiÜîn[ÀÜ>P¤6˜e‘òX€üDd噕Y¯ê±ÞóćZ²"—ˆŒøbÉŸÏûŽ÷øÏÿ½~{öùw\÷ç¯îÏ࿳ŸÏ¥Òîóìì¹1CgáëU×[|ü˯Ï>ÿú¯ç>¾8ûüÎÙÙçÁÿ¾üûŸàÏ×_ÿÛÙŸ¿>ÿ6¯»v˜cS¶Ó®©¾ãkšêÏÿëìç36Råÿ\¿=ÿò®´<ºAsøûìåYßY5>vnå¹éY‡×ßžýpq} 4¥äÅû%-»x¯½Œ×Þ¸_ÐÞū˼³\ú‹xû}¼ýK¼¦Ã¯Ÿý÷ÙŸŸaçC&{á±çlå ®î5“¢S<ëyêÛ‡HüU¼ö*þzîb7v¦ïz.$Ìë¬Ìù³hë‡8bÏã{÷ñÚ;è¥é¤=×CÏ×-¢78æÚÑã@¤Y¼Žñ¶˜Ùâ¹ÕHôIˆ¬$~á,¶ˆWütÄ+…TSâ¡·‘øE‡ð×°C)1aR|ã·xm¼k •—áÒþ‡[ÅVv’ «˜— ø3øV·-'kù*~lïZfrpkÙØã(ŒIŸ2•µ|DÖºåp â%ƒëñ\Ëš›q8N@¼V%ñ_Ëøë·°\/åAãR{–ò#‡– n»×Zh¹è +Z«8´•]8 è4ÈwñîÇl¸q·Vüâ‹bkÊgèºr÷i¼öcjæ‡0 ŸÑQÛIM6FÛ³q2ÞÆÉH£ýk¸Öía×±‚=[{7„>Iø”SD¶`B.”[)§ ö.Ã3âï‹UÄß›¯£ÞûÉ‚¬™·•Ñø5þÚŻŸÁB¹*\ú)ü K,qµÙRUæzpŠÒz]¹5º\3:ºÌ-Ö£ºâ³Ëèø‹öâõåfx`LÁï¸ä̬˜~hL Q|ÀZ‚°‡¦Eo˜ÿ©G.ñÇ{èûÿ^îúÎô½Õ8#ñÙw±Pµ9ç!m¾OŸHm’·Ó£ïÒ£÷Ø‚(˜‚ôK‹AÀ¼¸ŸZX|–˜‡ç±쟒f J¸x š´²œãíÐÒMúÔ“HN$Ž0ÏFXŽÒa:¿ƒÅÄ¿‡æÇwÚk^ÀÄ#âù5NÍó°’Òê¾™®$Ê£w/TQ,p¿>. 6à'½o½×kãu–6áv3~"ÂA~å„Çí7íåWáÒ«=„ky:µޤ„G*o éû?JµÄ˜‰VÂQª%äGXíUy"…“%„¨^8‰¡†Þ^| ª +0p·îUà.dÎëôóMâù—©O žÀ®ë™ÎdJ.ªBDlL0`ÍÁ˜ì@Ôuöú»ô\ ¤/gT°ÜÕđӘ€IIZÙC&¡¸²u[I!DXÁò!ÉUÒB‡ý•þüŠô—¼÷ò4S£´ Ÿø˜ˆ%òfž ˜3a¨E‰ –Œ0º.Qÿy‡¿*çvð[ M,øúã‚Nš¸¹?Ÿî§K%´G×F‚¤#¿ÉåüK¸¤ŠºSPîE¡| Yw ʽ¬#”ÿ?v„ªI»I»%ÒŽ9XáÑ,ÈÙh„1-m® .KÊ™ ŒŠ^äÅdw}L\I™KzsdyèÙç¾ÀAfÒj±w” 1Ù»o¦ìÿ0!õU[’Ì’*{ë6ò½§#­ |ê¤wŸ[;[‹ n qKmž·xàÈ6„±?¦/¼£ì¾»^XúìK¼:t\ˆ©1æ~’O 1…žàLò@úÄ(F@*KÉ Å™\º×¦Òg1dÔ'Ûñ†XlÀò¦r(å’³ø²«MÚÃg“xH&!‘)ˆ3EdY¢ŸTð„eÔbþ&ŠL¿`õ%‹sd™<'¯%ûôõø¨í5òèóª„$=‘ØSVvÌsH”%ʲWɃVôѥݨäQ‚#§½’wÊG%R~ŸKº„E0!“á…ªD‡y‰m‡.Ÿã{0 ±é»M‰ Û‹rà×JlÁýJŠßÛ'±UÅ9’ÐF$P[‹Zt}Ï©¨&zaÏ«4|Èø{‡^bNÔ¸$ìPÒKÍ .ÿÖT„¢¸~WÓ"D'ß/¥ëß%;ÂOþ5# `±ÒØë ÞªêÉekñUBŠøÖ#6”Òz%µaC±w¼qÐŽsjSøáƒÖØ!·…<oçxDþrÚžÀìs0¹¾(žÇ§’œMÏ? w« †0ø¶ÃÁ$Úê–f0§Ùf4t€Fv›ñzÂý3-α’h³ tÊ qQíÝL@GY?î§›É]¹a°`7ÁfqŒ2pú=ÏóNv‚UË»A*UwøÀìÞ?`v,+A¾¯ÖÚ¬¡Ð5.ïK1#BÞ  nï5Ëü͘ åp0 b8z”—°n…“þ>2 D .4í$Äk^ŸÓ_›þÕ,<§Õ kÙÉæFŒÛ¬7SBI7‚µPÈ+QÈoÆ,sBžÝò;PÑ::Tº?Qtg`^|)×íОêkî#Î)/¾Nmý=~õ—ø¤ö-iKlí ¦QEÔET¤{î몞z“H¹Éôï©fè:hz ?«8‡ÿ‚Ã^ëÏæpF€z‰ny“Ôz¯Kf(¼;ŽjÕéWF÷Ž¢ó\ÏÝ Ž ¶¦ÖÄ;ºãjåÒbŒŽ·}v¹-ánª¡€rþP[S ªáIoqÉúNX3ï' ¥0ÜD^¡6ÐwŠSÐ窪˜\yÅõÏÁØã }2 Áô#%Lóüö|·ïõ|ÛØu9Ø›¨î‡4ºf˜étÜÀÙ N¡¼Ãâìßo+‚ø×¥û7ckíƒ÷ïÔÝ„‚=Ì»)hõcåÝûzkGÍî$½µf\C±·¯+úÕ}Ñ‹,ÒÅ[T ½QwËF(š•†.^z:³ýŽk=nÀ›-ö¹ 8Æ+Kb°prMrÑq§£î³ ò€¯äTîö’ ´¡›Æ›"YŽï}óתÍFž-*ØyÑRLÐýJ FÃDá˜Ltf0É!T÷ë0 ½¡Ã|‡ƒ @kŠ;ò“:D„Éܳ䵻Z×pé!äöÍÙ³ÿø¡9èCÇ£#ý@§²†Ž‘¹~Žaw,úE‹í”h@ä*ùTŠŠ«»na?T½ENºø+nBôÒ64 %«‚²ë9nÎ.Z° ïñÇLs}²•tXÎ"=Ë«ŠU¡ñ¡J)g\èákS6ÀÆV²ÁØa‘“î56·@‚5®Eu¦ÐŒ¬]´ñ¢MZ,MHS¬öþOñb_(ØU!ÚÁ¡‚ëÎjA´2Â5Îg?p3,òÙ;óa Ÿ½Àãðl¢»O ôI^L¯âÏÐì Ç2/‘nTØæ&öi ý¨»è(·²YîÃÊ®“Yþb.D ÔÖÖ`L[´LŸME úγR´„·j–qž¼È츩M&ŽUÊ ©ÿEˆ³†ä(wØ–'6JÖd.wŸ¥P•"¸gF¸ê{ilˆrZT)Ïúöìá" ªŽ¯½ªþ$&áÍh¼ Ôm¼íÖ”~õŽ{£ãSEv‰…F¦¨®2T£¿§–¶rدà…{J'!ö‘•.–¬å=ô“  1FÞ­à/"Hàu=rª®DCMË;1íE«•™G*_ ŽFXZäsAòˆÁ…hY¶«YŠÞ4º¢ÏŸ‚/ŒìXÀ#B 0Eï2âÝE°Âƒî¹<©ô}m¦Èèå2†„âýa­ü‚\¬7ÞUšÌ¿÷îˆIâwŒ÷à$ON$fpU„åB†×ILž!S…Äô«õÙ%H€ž‰ŠÀ¬øGlCgnè*ì3Dýþõ:Œjôªjª5$|ä¸΢mB|žá๶å!”õ–WùÒlƒÅÔPèœB–ä±-m+Ï„ê·p€>C"ÔѳÂF …ö÷÷QNÒÝD¡Ý­%Á¥NÆô2íFËÜïé!GÊž¦‡\¸DaÚÃ÷9Á4Ù®E°4ÚÓñ VÆIé}è½›âOÕzBÇ|ÇÝq¡’ºõEdÐàÂk%J–#gO+ÓYH£rm'Žf@.:6 P.aÑöu[ 0 ´kMtƒÂ®2÷­ýZ<É;)ØZ¼Ì½&‹0qôôsÛÆËÕ›àe6n.ícŒO%œÇ§0>q褮+Díú¥JîÄ óÞ§¨Ï°ö†‹‡šò­u‹á*×í\ðëЈBËá5´P¯Ýìu4³×+q#j‚éŽqµ¢& ‹•–­ó¬‰¡a0ŸÜ¡ÊdZbBå°‰¦¸aR|?Œ¶»¬adB&]÷1ˆŽc„-Á#\˜Ü9ý£*}*ab¢væFKS2Ì _šÆC¿$è4ªA?«‚[ýBb‚Òòâ?/™m^°Â¤rÁð$a-ÅÞ\r¸&ë]¥d¡úé†Þƒ9#×W•Xè–¡K ÅVܘK\ÂÏæ¢c™ó€LB€0}AÛJÀ|(àÛjÞÁzIè¾P¨^`G@d›BÊ£`[ ©h3bû’^\ÅêßòЬ}¦õ­`Šu„Ä|¶ /äŽUX%ÃÚÅ"ñ™GXDClE¸‹ñ¤€ÕóÔÈÏ,ôÅeÏMeŽóDìzœàva÷ Q.í(ç³h¯&É[{DpnÙnCêλՀ#¡}à€«,¬¾’å(Z»SE²Ã\7.ÚRnD¼@ È°Ð’¼ó0—»™‡Ä´±EL†2j[lƒcU(1mºAÊÆ¶Up–Ì ²q]ñ ²AË’\ÏóG¨"Çj To'|MÀÄ÷Õù˜ …e>Œ l§{QA ýÖ›!…HÎÀc¼|cŠCcLe€×0XT°Âò$‚+à G6 4ÖÇêLä»ã.¼EØ!hbî+œl‰ÞížÝ—ªWOµ«¡‰Ì£‰aݪµ0S5kôÄ95Z¸L<À­c€ àÙMr2j(tN þÀDhéèI÷Vž£BRZ70Û?~ÁE&Òþ–•!‘äÛÖÙP}âÇ€jJüme¼֙дTÂ.Uéy]y÷M1åmü‰“Mg®.Ø´ß`³ŸÊwLxq ÈØ-åˆ|Œ×ÒbHÀÒ8¥¸ïTJm!(7ruå¶cëPŽŽ×’Ð3‚ØEž)¬œ VŃǖvéjcÎ5M)@'ÑÃZØNj {ŠÈµ©X§¤m*Ë¡cH®„-§Ð PÕ˜`ŽÛš‹j‡aß$—ï÷H‚ºµ=H$y=*¨@8c°GÃà¥6·¡¦ÚJª„7®ÿ‚nècF;ìýíÊj¸˜u½_¹àë„(Á×})º¶¦‘ÿE‚BP‚m¯„,‹5Ë*ÉReFcÖZ Oñ™Ï‚þ=´*·Ômš×~ ó¢ õÄwi-’à€%æ+ðз‘—Ѽ‘ؘA ­ÞÔÌmzɕ̖ ïJ÷ùÜ™6UÅ_É@ÞÆ–ÈjžŽØÔ,JkËÍJVwò…yUvÜ‚*{À¾ÐÐ@¹ÙÆÁ~PC•¬`hçè5ÑQ‘†7Ûf¤Ûïöé‚A‘Å”±#'QE–ô7yÀ“Ë0釓Èú–ûü¶Ph¤+o7¹sê éêŠ|et}Æ<–7[’S7t°ôð ¿Ëfú ¡ì6Õž©X 4)µ$ˆ-8‰ê`lü°®€E ‡—— ½jLs Ùçc†hÎôK¬!ИZ[òzÆêF>K8¶lì5ŠŒ-eãA³?%ÈY ’zJíy*ݘ¬ÞOá—–Êê”3]3Ãéºf9%¤]K2üS$>u÷Ù ²À°®{IŽNx×AYæ¯Éxí· jP¾wuñFÈ”ˆ~]¹›ÂœÞͽ»ÀâÞŒÇæ¶(2K¶¨Ž¿Jž“ìPl.š!¤ìo’á{¤Kb¹ª!ù©îpW>éý\—'dš@ÿ…±¦… éïFÜÞ°Œ˜zõ›ä^6íˆd‘wékä5B/q_ÉÜ.ìM§Õ|m4¾ÜÁÞöÒ…»r¼Ù²é" ÖxfÄ× Žðn2ö°lÆ…õ‚t˶Îòö]­B#öäD) ãú`Õ4\!âC#?tKN˜¦DàÅ=@_ qŒ.Ñ–vqÂlnQߦE}—®^Å…UûüŠº™®(¼››ðd­|*šfZä•·ˆ±O®¦·R)™Ñ°Çü]/¤ëº­y—ÐA UÌ_hgí¹j‡¨xÈgl 󷬟4SŠEô.6>½(8ÀèÀEY/“‘ ùÔßšŸûë9õÚ·ÛÍÞŒò@{õU=Ñ%ÉÔ%îÞ ;B¹TÁ ƒVÃ\ê6kúêu)òR¸B©µ›¬Ñôha3;ïû°ªö(1ùJØ_û‹¡¤˜NÕ¿è)3EÀ%êÛô‹Ë³_¨%{ÀbjÈ&˜‰M,Ùƒª 9­Ù ìXL 4[ر!71ñ׫¥8Øv0''H÷%'–‡³Õ×ӣ1÷q¸ø¶š…WOú{‚qg½+OJÃlV™/1À†YT@Z®âóÅúÔl†â-ô±°,:ŽHI’vG„ã‡K¥@…SitRÝÃTš¹Í詵Ù:(d_LLantü¥P÷~FÑ÷íѧÀ”ùÂ;Pô­ç†ÄRrí¹;6T}J˜ÔMÂÿ-êÖ$ßû©^DtªZŠ\]n6s20ÃñU¥ëªÝLì¢*<2‰œ‘Z!e[´*ðênÌ%bxYqÒæ¯ÁZ’­­Í¸aC5•ìè¡JÈ£`¤ô[0izåy¼^Iy¬éxËĸµ Ùå,¼Ù@ͱ0¦¿N^|’V;­oRpJ‘¬á”U^yÒ4=ËcyojVJ=;I™jœl'\­2mlï–= Cëÿm‘eÖ¥ß;p{_¿nÏW'õnØP¥®1Çô˜ãçôsî¾²¥èH;x ^,“¬ñ® `¢³š„$å ùaÊfò»³1´øív#:'cÈxþ (SðlµVDYåfN­¬êL&Ž/çVu×TƒÚHrMµÑL¬E{èCM,Ö #_Z¨H‰ÍQü@¶/ŸêªI/ÎŪë;õ*8¡”’Ö¥“Ç—!V%¹úƒ.AGW¼§¤Õ)¯{@b>¾˜}•˜b:¯{h®«ãó.[‘‰“\ŠªKc¿:G‹ÕÀg QÚ«mŠÖÔPèšHÜïåÑÝì •±rƒØT/-¬\tî-Bâã&€œ£›š>n‚ö¼–ÙñPt(yñgüzpþ‚“tÃÕvȺq[™¢ÒK«ÍY´Dó¤!\'VÆRëþD$#÷){)˜½™¢/Ê‘2>’“í|©Œ;Ç2ýèSJn)NFž‹÷fL7³qÓû.nÜÙΖe Ï•檋âèÀÜ_`ŽHè¹ör Î_<´QÑø——ñ˜“ç5%$?ð¨âé΋¤›MñZp =µÓag]U`Ìâ4Ä“=êV¸¯}ý+ [lf¸²Õ|(­x0­Y_œåoæeèjå'ë§(¾ß£_a˜:Dr‹àuLZõê*¸³\]çÙGµ7¯s©q²"WÖQànYž é.ªJÌHóÈ„¬Låˆrñ¡aM×ÀêÇ+ã –åúÖ¹"ÐCXá½_U "žVÓœÄ]‘µæ^©•Ól¢~Is•a†àJtø¡u¹+.^×¢ÆÐ$ña,×[Í?hX•Jìå¦ì³/3›Ç+gôD,–¸ëÜ*/g07)Â1š{%Pe y:Bç¡ÎeòåfЄؔ€…EèÓ,aºŠªm‚%Ê™Xh–¥?'aí„o±­²ñ8_ÃK‹ÐO~aâŠÒ­ÿÈ€ª8”Ã;±ÄÞÆ>¼É»U?Ï4‡v0Tꈌuûª„îZyŠ#uŒ‚;ý¶ÈÎOStdOõ ƒ{Þº1;´zP¥ÃyØßÇ¢ëed„/)ÄIÌà·ñöl, 7Þlvgì묫ĨŸÕQçS®ª»PÓÏü`ß&wÂù&Ĭ (Ö #{³!XQì’%‡RœÁjÇ÷.î6ûd¥¾ï‚ âõ‹£.Š ?î"C[gÐç0 Þ}Eœn›éL®¿ÿ8û?› ÄBendstream endobj 720 0 obj 6909 endobj 726 0 obj <> stream xœÕ]Y“Ý6vNù±E?v§|)b!—ãT¼d¢T&ñd45?HÝ­–c©%Ë’=ú÷9$€ð€ä½b·’r•ûŠ ˆåà,ßYðËy߉óÿ›þ^½:{ôßÒôç·¿žÁÿÎ~9׃ œtçέõƒ?¢ºÞáã_?>{ôøçïÞ¾¿9{ô×sqöèßð_ÿ üyüíù?œ}÷øüOؼÚqÊvZr -‰NÓRþ‡³_ÎÄØ©éÏÕ«ó¯Ÿ@Ï£Ï}ç„¿OžŸõÆÇÎ>·ð%¼þê쇋«KèŽ}ñ:üÒN\Ü¥kÏÓµŸÂ/hïâöò`”ìœÔoÒí×éöËêüu•î~ˆ×~|òïgß=9ÃùPdZÅÐë0½GÎëÑ3!ÕYYÌÆo©Ë7©ËoÓµ_™Ù¨g }ïâ ±’ö@ä…0ÎwÖŒŸþòò0tB[_juÛ ˜'úæ³´\O«®boÒµCºV½Mwëa–ë{WµW~í]Õ^9YùÝ[JÍ)Îvƒ)ûÕÖiÂéµ6½÷Cœ¤å5ñ]¯¼+Þܾ0¾P½œ×†›…ëmsôà+wðþ²¤™;²ÿ·,ì-\,æbZ:gÔÚLJ1à[ôåÃW­%|£â£Òx‹ ôxFÚbÒvhÐ'Ê4þ|):¯D¯/ÞãbÖˆ?³ä×ËËZS½ÀR›ÎZ Kj:a”À­z€Vò ×@wðýAÁ)ؽÁÕHï¿NÞåoŽ÷‡A zõvúT ŠÔÀ]jàyþTn•|ÿþôR ü%tÐ(ä’¾Õê–Tº³@ùïŠûÒÂB2!µõ:wvê·é‡‹ÏÒ´Þæûïóý±‹ƒ2ûe…œúe{-%Žò ãt˜ñ 0H=®ÌøÖMnkœy%äEwyPFwêâk ÃA*«é\äçnp|®ƒ·aY‘T¥ªyr „r“_y{)@ƒ„½†á{‡ÏƘ¼õv|o€ÃtRòä‹<âü$¡Ï—yr®Ç÷a}Ÿ¥'oð<áÂä*Cɬ'!“&ñ)c;©|E|¡Ç½ŒÓˆ4O¶ÇK|­ï4-=é aH×ÓtôÏ{È£R'ö1V__<΄r‡¢éâ_דí’ÙÀoâûŸ›UzCše}›¦=ÁÄ¥ñõbÇ©&<`™œ";…g)ä×ßáô¸N)5õ>Nï¸k÷QÁŽî°« ªƒ” S lf…†‘T@þãìÉ?þ°¸çpÞ¶\%ਆöf¶H½¤[ü Ü»TËâ´?ϲ‡Ì‘HøQØ„ÀPþœxÿ]=¨ú¥4*G' ÐuG6¤dãëi:Ïë )½Ì^ +ÏkKq ÖÖUx/¶w$²Êo¸½™× €y1ÛÕ¢q6$`?ì(3 5Á @–ÈÎëaX0‘¥N5‘yødœÂ¿Ÿ¦¡88©ûˆ¢B;=ª÷‰"²ZíÎjFqr3ÜË_½¡@ ‹¥›åæ°T2/ÜÐ2hµ<ð«9@ÅQ5.|„}ö[ù؇Žïû´¡W­`äª`‘ôªaF/íøð³~«¶ƒ®¨õunè 4çn‚]¬j±¾ôúV,¼žqçIÿšÛ|¹«¥„‘Á?M:ÀR«rÈU^û¹ÊR…|uíA€‘‡7¥¨ Ðåï©´AÓv¹ ÿd–Ë|;³ê‹½šŸMø±¡dÁ·»Q[`UÎr±£¼æÖ‚ŒŽÌ/èKŽ.—ÅnÔ(|Nب ™>¢]¤Ø) q§ÿÞ³ð¼Âùûÿ!| ³v4~UøÐyÉÞ§÷K?B¼ì¶¶ â…ŽàHñ2ÀÓÞ<Œx1°[„©äKPÈ=ílVn Ç@î3è¦s£$XuLA0P¼!A´aÚ‚ ôPï!6â{{ÿÙl‰ÃQÀ¶5 ˜ßg ©ã“T o'©òi„ÁñÛŠçჵvK䤆âЬ Ð’ºo½Å“;ˆƒ_žùÃ3ß-ñÌq"×Üo –¸&™€oy4(“&á^'0!~Äü€#ûÅ;gç:gÛ{O1™&ƒJ8<†qg¾;(Ä¢6¶àЧ¹øÛEáBZ¢?-ÁÔÅüQñ´(ÂŒL—ÞM˜;ü<Äk¿lBÑM@Šéÿv™œÇ‚x²ÀÜÿ“Â]ª¡ÓÚ;г7þ„­qñN¤£ihñï¾OxurÓòaËKkÂ…9xIÙ*/óû–*8V3é,b¡µ$OÐõª‡Åøs`å]?¾Õ‚¥HÆŠ)§:]4ÀSøÏ\P¥V0×F”Øgôž?çÄ[)¢aN]7XÙÀfK˜vçãÈk„|@¬ˆN¾¹çìÞ«ô¡: ý]5Å+O¯èç²~Þ‚§EbÉ&{Û÷99éÉ‚à’4-ïËq”?ú„í&Êßµ4´æi9ƒÓ\‘«Szg£ö7«Ä7‘')z•­a@àµ. w#·Õhxïuk.Éä?YåË ‘/Ã7zÍzEƒF¾\yE+—æ-v#d埋üzR²^aí¤-F¿‰GôºSµB ±»¥çKzV<“ïÌ•1óϤ$šõÌoUIïçhÞxX:w$—17K¯N\J– ¹E¥;Ø$(ØÜâÂép0 U˜kå³”ÕŸ4È*ø„e‰Íýz;hþ‘]„ê3w{BÕ ý\…yP½ÛP®òžÌ9ʈì®@.9TC浉8T߇Øžb˜ É<–«Z†•#Ìæm¡=V@)Ðñµ2tÁ›„H_ëPu†(Ǹ(‰hÊd7ȇé9†´xC˜ÇP ÷|Öσ³T{^„–‹0«ª|îŇ (¸BÅ:C´£¿`˜dXoê¹ÆG'0UçÔêjx^–i¯Ù~G8Ú˜ Æa0xÒÀ‡ªÕ°»H8ÓëL"„p¦M3×¶W#q‚½Ú@úa'\㔆lÚy0BcüXÄÛ wÀÛÏ,‚s-æ8÷+æ.˜z"ìø‹/[É_ûŠºYŒx¿9^@;È ÿ Q²d¹¦»äàÀ Ô£ ãz¤ [Œ!Ê­ÃùÐò ò ÿì'‚྅ŽAÍÕz?×ðiŸåÓ§pò¨q±À¿ìq1.©Pê=Ђ$åõDM˜ó¼Š4¤R5Èر;!Ú2ªÒcÈå Âr9Ã=«_ä‹òH嫳>ež_©FÄÖš«F¼5‡iä[ÿœŸ%R'ã?a³BXé×à6Ï1a£~†X$X;PïÙ †Ì×¢ý¿Ì}[ÎB á0ãVÝ{ôŽ@äÐsuÇ J0JAÄDP†ÅSXðÛJ^ð©J%<¾], 2Ò½’öv0¥©$C²¥¥QúßãUê$U bNì„€lœ0‘㲆bSÀš1‡ÌJÛ„Ÿ$PË˽;X¢Rôð¡2\ ʃAç,ñ“M?'MÝWþc¸f#/ ŠÃžÜƒeüpr360±§£8šM}´™ØaûAð–Ðd=õ,æÈ)ò˜ kE¡© Ã1¾† c®SI¬JƒåüjJÉšq5}֊ڌڊ…nU Ú0aÓƒ­pC6)¢cÖ-4DB…M6æ~ù-T7¥‰•XÌ@™ç a¿JŒ:§˜ðjïÝŸÁBqÊíÐõ Íò:¼Æ´ =øïꨕvkœªeä”ÓÀ‘iðÂlʃX2íµwö]¡Oežt[ýZI7 Ùr¦á€à †Hà•ßÓ'¤!«üŽýÂ{–ɳïÙ/Ü„|Á®ïe;–ot‹¶¢ôo.W„Q®©`—>Ç:²'@ƶs¢‰‹rœƒ>é÷X¿*µab·U1_Æ­qß7›"nT/+h)oˆÐoñ­Ì]çé&#>¯ †“M²oRÖìã Ý=Έ ùØFl*€<(uë„,ÆÃgX6÷^ZåLS ¸c2mUŽFxË4<ôM6r´L?„TJœY¢Çèä[2Ûí¯3­áo×'ƒ¸Bª«ì”y¥¦…÷•3¸8·#1ê{c[?±;&ú]ıv¾å‚¢vŒJFh 5bï;á ‡.ðá’±ë7iSàtʬÙϱÞšG—¼Àè“’Z!ÄÁUÓo1\øþ°¡Q/ݦÛ,D–•`î ÖUè±æÊ§j(N[ZÐl ÏEkÒ{ä¹pˆB®VÂÕº«$yùn@q¥þ6UvÁÛO‰õ^«•/¿ª>LÝÔI](ÕÕ/Ó@¯ª¾âµ÷Õ„”]HøñÅÓ„(Ezýùˆ4h'I=˜ÜÙߪ‰­‘•4ŧ¸f`™ßØî´Š‘ÚP±¹-„ØrMÆÊnxÓR² µ8‰ @DÞ,£rbYƒ…e(:ò<£#k0ƒÎÌÂ-@½‡Ò@Ãö¤P`ì9ªUÒ`6Çÿ,é¢Ëfó'ÁVK÷l]~ë"Ä%ì PASÓŒEUrbÍ#Ö˜}Ä©¬ M¡i¦J{ô°I¡|ŒBW^Vé^skj  ±¢ïIý+è“ís_"fØî •É|èØ+ü.úSd+à„PK™¼;öWV:Ûhøt@W×å:x_º™¿ßaˆ$­ê ì[£ñ™9ÿÑ6S…c’áfôFLž WÉÇØ<‰§ß ¾rkžÿÂtÁÚ ÎZŠ ›a טdÖ#Ô+<&Û¤˜ê-uNbÒJ…‚¢¶ cáÃDšA…cà‰âM¦ŸÕHÁ&¿›;£¾B€Grá£yRƒ®ŽIÊcÑP^8°õ-ø’+ÍœÁ‰rØp&>XTbL¡•eá²Øûµ‚s7k#0cT@’.¼«àÊ  þT ÅÁ ™3å‘6Á)š|È}ÝA‘ç”ñ"Æ“sï©Aá"Bî=?˜[§ î-3 ¬hC"+зMG_V ù/¸²QkÞoi´f2ÒfËjP¦«Ür¼= *¸ú¢7˷ȲUgU!MQаÅMæ¯U Ùgœ®[K½­Îˆ”°‚—W£ûæ’Y;9_e[Õ'௒~®ÊVYà€HJ‘ÿ@J ¶¥Ý%:⤆8þ†ï  Ô·’ñQ Ó{î»ÇÄÉxëøü Ë<…K µæ2V;óúâ/«lå£Ú³Eo¡EØ"©ÎçT18º­ún»d»r1SìÈ;uÝzf03­OÕ ` ³ž‹Ù¬Xcá:›±F—9ã{ºÚ~5?`¶ýàÄÃB,C½s<žÊ< —{ Æ'5Ä1G5¸¨(¡d˜Ç=™ã‹t;7óû›Döˆ³‡0Æ}׌Р¤èÈ?0œ=WTËtžçy»­ÙÏ#ýÎ<¯¨Y‡æ¹Êlµèc’ ]FLm‘FeoKÕ»¹!É`QN’=q sfÓ :Ž©ÌÇ>lÒðÀ¨Ñ®øà‰:Þñ„Óà>ˆÁì¢,žÒ“|í{JÆIlL½îkäÞ1œ {«^2Žz ĤX)¢X=K¯dvÃù¨r–ÂIiöÁ~“¼ÄwÈ7}4ˆnÛdSøxt^Ÿ¡ª¤pË!e/FøËVî0¥æ/ÍÏ‚+ áváC9ÝYy &Â"¬*x“ÅŽg"䀓³^µyChb±v‰Å}_°¸ÆaXtAïO*.pÌÕÛrcÎÍí§ÉÜNîØ—ñÇMýôb?‡ãôŠÏ}Uut®-£wç|ž$˜Áá-ÁhªWó¹­Ù˜ºðAWƒ¦¦Ga¡Uj dA\*ÑáôeF\>—ªÎfžµu‰B¡|]|oÝ ™/ÑÇøcHuúÉLsSN`­¼@•Þ›],•“ŠC<‰$–ä˜!‚lÜ”,S¬HuÑéŽ#LBa@Y1Ê%èšõót?.Ït~°]Ù÷WU?˨™«Š/àݬMjϤóX;©œ<[$褟è%Çʹ}Mc9_:‹¥*£²% EÈ&_eÒ[ìñ‰*È\ZÈ„‹ö=îtä@„ÇŠëÃIÝfŽÕ0ôIÖ*ø)‡ær[Àt’ªò2‡F>c­yU3,V4Ôr»e»Ã;y±v7a B–è0G¯×UèÐ þø"O0Ÿ’ S¤®O5wѤ_¶˜Þéb~p€Ž8CŠÈÐè&àKùã4˜àë/±ìkµÎh ž u6l8t€íbUžÒãm‚vâð 仞‘MÁT’–à*ªú¼²É wͱ³ßô,™drŽpfÁÃó£øLM66¨ i¼\Ù-a}á\>`-ˆžÈí§…Ç­ì„ ® Ó5·Ð˜4 ±ÌÆóŽ«gYDBTE³±ùQ>®ô4¯Ñ TÙà"ÒîsœÂI ±g¢Kiâ@Tv9PáŒäðÃ[†!¥˜š•óÐ%…}ïÇ(„óÐél¼a”ÑŸŸ™­†B9ØzúŸç. ¨>¾¶RùÒ¼_4 öjó6›[9-ìU5SxíïéÚa>?DRåpÓÅRcå1×ûí%iD¦î¯—˜¤æµ*µ}¢aÇÊOs5 Þ"[=Aøjja 5=[öQ…ñ0Ða=¶,¹MÐ;fO.œTZ÷ç×a¬Ó%šX¸L »r –"J `}:{D±Žæq±ã Áv› ƒœ~Üh¨é¬™gãŽÒ.w“ì(ã%ŒVYƒ¸œŸÇcTAUÀ5”wNv$ÅR«keBc›¥º!ÓXw±”U raG.%?ÖŠ)ÐJñ9vÒwz(P’™Ã<ÐÜJµ Tÿ®X6ðØžGñ0êIfõd®òÛ&•hÀ‹äs§±”ã çH·÷©†£} ÃÚpqöûÂ’ãýÓÙÿ¢¼Îäendstream endobj 727 0 obj 7071 endobj 734 0 obj <> stream xœÍ]Yo]GrüÈ_Á·ïñé½Û Û3 `{Ìà )Ñ‚%жÛÁüøTõZݧú\’¦ìñà,½T×òÕÒ}8]qºâ¿ü÷òõÉgßJ»ž^¿=ÿN~8ÕÆÆNzñ§Î…ÅñšeõøúON>{òß§ï~|ÿüä³¿Š“Ïþÿûâë/áÏ“¯NÿåäOON¿Á†àóÔŽó±%¿ØØÒºÈû´´žþå䇑•ÿ\¾>ýâ)ŒÜX}–`%ü}úâd]¼I¯z}êV±àý×'?»<‡á(côÙ›x¥½8»©÷^Ô{/ã´wv}~°J.^ê³õñ«úøbh®þ÷éžüéé Î] ½ªHÃUŠ{ÒðÞ³Z-Fv3o½®ƒ¯C&Ôx[Ÿ¾¨W—å)™ä°Àҷ臬ðlžÒ :O‘')ífø%ŒÍÀ»æz€ÛVuöþü`„003 Š]­;{Þž¿=?(ãäÙ_ÏÅ”X5Ð¥~ô&^zïÎ~<‡e„æÊ€‹ÒpµÂÀÔê„eÝ"UzÕ»×õû›zõ¦5Ÿ5aõ8(¥üðYyóUkˆÌéÇl)ÄÙwõÕ<'«<}õªuE^ ½âüµYœæ¯7û*tÓ.ÏÕYº-Í*«–u•g·íî{vŠ·#]ƒ]˺(!éq\J-6t£y‘Gã$pb}—¼pÓš=¤~µpÈ«B,Þwúô¿NžþÛßÉb>/ÝȺ¾lÓî;’$.˜aeÊ Wí…s1.ZÇ×ù]ÛuÌ¿Kù}a¸6³ë6˜èæaÝÙS¸Zdþ¡‹HæøÇ¢m=á}²p„ ö)ã6Ízòi˜åÂËWíÝ_Z Î…_Dp’à;„BpÛõ‹£ñr ZÎùW‚Þ­|ö¬Ý½8G¦‘ Feóô ôKäSã%åS|ë_;™^$K´™+Ró“ªh®G‰ÍÅý8ž.«Ðg?V˜ÑêíDCà»",«Ö¤ß6¿ž~¥ƒkI±€œ¾Æ BK>'ºŠëíðêj#%•´p÷¸<ïP->ÿ±Ê{&›Ò§¡¸U÷³âY°àS0ž¡l× w¢ŸßÑŠ¨Ì¥ëUpâ*`7[¸êP¥<óR|XyéŹ[üŠ‹Ê5" `•Àø:}€‚§ˆ¾%òüâFï‘>D7’@A1ÆÍ»Qê¡ÆG”ÖJ‰xð÷iˆ…¦ÖâÒ~\€°Ô‚!{ TÚ€ÝU}|UïýX¯ž×§o°·ƒY‰xÆêïIÜûcV9Ÿ¥ó–ÁÛ—Û™ÍfááèßhÞEj³¸ ðvŽLö]¹õ²\\2Ë4AÝǼ;¨›Ìî¡ >Y´°÷ÝÒÀËvDÝ:=uK-Q곯ΰ‰Äùïç&À¬´8û›÷ÀÈ ª¾†Z-ö§Ûªˆ5¹yK!GýˆØBŸÑ‹=i|…4€Žç¨]‚WƒÂõX }˜GFíùfÜ~rSë†JÐG¡ÒM7äòê}:X·Ó•^œÖwƒéø®‘¦K°f!؂ӽ¶;8l±‚ÁÙÞ¨G›éÆv3›Þ ¨çî Ôµ—[ô@3b#0 My·Cß铊˜žUÊ^ŒŒ™ÕPä|p€~7œ^8î.8]‚Yô ^ï…ÓËG ¾ÅŒÜ ݲïU$þùÀº¿Ä 5Gë‘ W'!p‰á±Ìe;¬•Þ;TM†¯_q …0ÝÚŸ™Á¦K·„Ò€&ØZèGBûi¨LNêµBt¡ìÇFrÑWƒ£ýõývÀ{øøÕ^xTë1d¾êH‰Õĵþ¸È<Æ7(5^3º9^}N¡ùÁËeÝ×tõ»JÀ‹ëã½0DmÈy¤_ÿ´ áõéËaáúH>÷ô¨gáÖètš >þ*8ýÔ%x·寉˜¸ (IÕax4QÚsë4ÄOô绀xƒQýçwæÑƒX9+IDé «j‰†½<ë¢<(è_ð{»øŠ˜Ç¦vûyê* .‡e½ª@1)éël!WgoÑ5vß‹Þmñ /z×QDÇjt?”‹çù"õ8Y+4JíëÓÎÚìÔ¯ã@ënÊÅ«:Ðí³;Ï€Azaݺc£Ež¤²4 §)JÊQ-87Ñ jµ›þ-´šø­b¨$mqçê³]*+FºW6û°õI÷×'0Cn!Î+†-Løn|ú9îŸ\WB·9|ò®6ØdŽ‹¼¶¶ÅløÄ2ˆð¦>ÕÃx¥YôrO®\kÚÌÙ<kïດ_ÔÈ!XdÄ¢À2þzçªZa°]ZÈEƒOÅûÙ‹/‰Iç‘D %`€×‹j\R ƒ€Ä$*Áçô‰Gý=÷j¡)‘·2¯@0ì",™Àç'¨†4u9C`Ê‚êÔ]0g(UpfY§gë|£§5‹%”w ‘ 1&ä­™pP7It“Up›TZú¸ s ìð!*BmàH@ãKC®Üâ~Qk³Ãô2ñâ»WQƒ÷g!\JÒô_Ÿ „® 'Ÿâ»f±ÂÎRn%’»WÜøJC^‚Š˜'ãG^õv1Î΃+H<¾Ëðy×¶Æž³]¶Xé„£ïóòÁ2tÏmq¶ƒé?æ°Þ(ÜvAPeý¾ªä?9Ôòü²¿ˆ|‚2 1”¸S †’ð¡±ÔE!«ºYŠ<¨5,¨QïWÊZRø0ÑF„Jï7²Þ´dä›>43ä–&c^žKƒ~“çÕU™Àæ.”`À`Ü“d‚âLbUAØæWZ48Æ+¥ÅàH(VzƲٛ‘e‰âF­Ó²d>Òd•˜‰ë'ƒ]Žã T+¡¶BZÂÙ"qvì¢cÿüð£ÕhtåÝøÑ`‚‚–ÑLH7xDZ8 ÞO ¹ «xÖkvŽ·2„È$r<˜W%`²ì2L†ÐíìÊ!ßcÎ\7aÎÒ“ãHÅk¸«&XD Ÿe6Å •‚ŸYP%ÕáøGáVÔ(a šÄµòþè&ˇxÊwÎN4Õ {I2´¯Òx‘ay«EñgRzñJ%RÝp±jQ†E›½j¡¤¯øÎ{…B— jT§IÑ(Y–+Ž™:Ý}”¾¬`26‰ú>mÆ&¯Öâ³l Š1•zÂM9DhYuÏßÓ!ì& Ó€îÓ Pa>4©ŽiiRˆÂÂ0]Ÿ½Â7¥3S;´‚|G‡S+æøwK­ ›ˆ˜¦ù9ä×DL©¹ ÷"ÞÔ%™z%å¨ôþç¶}Îgc‰æÇÏC•Nõ½(B‰ñC«yf'ŸóiQ&ÇjÔqÆ&õûåM‘2`#‰"sÌ—YŽõ®o“…6yV+hù‚uÂÎà³õxð:»Vñë>1úñ¼ì87­x{lÏ:*¹Ò©RacÝ’ÛÔ-Åœ´%ø¸3¹®z£¾ºc>J1Ïäã¸Ö&&SðSªÆŽe\‘Þ¥Šz“TÉÊ­”¾z:/}…‡Õ_ï Æè 5ƒ%@‡ôÌß.7É@ùð YD$€ð±*þ]®­ê쇊õ¸€» BQxW\Csuƒ_y±µ;êæ¾7UÂY¦â«¯¸hˆˆôË{J¥U/ø¯¶ä&Uo&dWlpe7UFæÑd$s© â`6iö_k 1i $²¶¢pާã´AÎx³Å3k#gUc©ôŠþYý(0·šNë¾£ª6U’m¶fû3×:8ECùaÄŽsvá«zöóL9d]RMYó"m)Õô€†fAt§Oàm% ¢;yª•¨[Þ$’Û;e#倶ʢ;· DZ à0¦½…Ñ(²­qéV€Ÿ^ÜÙ£à«`Eylc Riõ²½I>z‹Ì+”Ö–^’Ï~ܼ«’Û»É`%” ¾x6_Gi^V‰¶5ËnDÕù!(úBæ¥ÕT„eš¹ÆËÑ ºT7’¦ì+“…ʘ¤<-ehSí]¼4Rt«Ðb³]€±|Eº½j—ïÛeouJ··´ :‹!i0»Ç`J#ÁË…4-˜B³úLÐJ£‡a›7Õä£xSÇ'÷‰8R?,Ö»úY êy¬ÚpJ‚ÝL¨Õm#´l2O‹R½‰N©e¡…šêkΧ’]0ç\òþÆŒ¦ûñR²’dT˜gp`[„HyXŸ‰Eä\¦’}àdâEMv!@´±TVâçöœ}ôÁ¸âÄ ávœ‹ ´³šIQwqWâ*9sƒz˜”/³—âjp¾z)ï›®È"±2òÕJERe”øü¦“ßRÉ»ÑKƒ¨_s’@˜‚ÀmÄ¿W;8*¡pˆ¬“à¨ZaÇr›‡mÖ?±›û.:õ ù•䣎í{R< ²ž1  w×)‚á{æ9 g·Ô½,ˆ’lø$ŸEïuš–­59j¥Ü$d²Ù °‘Ì^œoYé~Ã)%ÖkjCê]èxÁ$*Ñ tñ¼ûGÕ‡^#£©0jšm^m¾;G­‹Q;A÷è˜J? Ÿñz‹àîZsž³:‡Ì"£—:¨†ë¦exl€!ßU‚·1æY@žœ°ÇåëÈ&´^ܪ1… *T®k30L/ÎJÓ^T…±%\VC13¦˜XDWLÑ ªIÇ“š>h湓®”±s‚xÕÏYþ/»œí¤®„8n^¢¤˜È]QÓN1K¢€D´• 2¨fÒÊ÷ Å%«iÈ6u\¿Öû„«Ê-¹&·9"gGù’²£ãU“®_š>ù¿Ír•Þr¡—™œäc&Þǘˆê!Ìy`•Ì6¥—ÏÆILPNEii{„Q¨¾Ö=ƒÚTµÖË".D´¢1mv7TŽþÊVä0@„ f"\`ÈO0a²ïXÙ½™´[†HšÍ®ƒV‘P€Û€‹%ªM·@>QêŸÀÛK{è:%ÛyxɺØmò¤ÍFmä›qydØ9°GæBzxÈn´^o•ÜoÙ,ÚØëÅãuÖxäÇ)&Î7åëc}¤sܳº?úr§ª¹^¼ª/:‡nlßšlÈÓNÁC#x€ÙUV¨UƒÖTs á”ÕˆQ'P“À¬ƒJK9{›ìu µÑU›ÜôªŸý±×…õÊñW<`õ]üÕˆPâ¯ð4W`PÖÄ”ÁŸñ o ¬ËEé s‰w˜bºn—ª^òáSð$íZ C²¾A©Çä19Wñ}4£o J¹n_©œŒôžnlít¯º6Þ)g¥#o¼ÓÜ‘´!†9¸c¤"½úzZšìxñó¯;Z0ªäІ}|û8µ­9/û¤}ÿ5Ž´0(÷I1;WÐ@"ĺóÅŸlPdozŽš¤ª%ûëkŽç¡ ’xvS;Ëd€ƒÖÀà†÷g.@­ð­ÝdEƒƒE”Ó:›%Ÿåºù,Û¢¢ì³¤SÞfÑÉÞ¼ÈD6zÇ>ç$:Ù‰ÊÕ¹‡DHm:;–/“Øu_ †(†P“!Òa MEPOaÉH!W•º­«ÞaØB6³T¶fP°B=joꤠ#ŒûyL˜>Èò~*Õv¸‹ê—‹¦ˆækž%ŒØP-˜Ü3o&ðˆ(mÍ“…®~.7Gt_Q²þúx=ÄFÞÕ¶§®F¯¼OônØå×û>¾­|)Ä,OÏA­B„Ñ48g½eL>ßš†š-¡Â :}ðûðÐa©&kÙ—7E,¯L²„½c¹)šŠLº)pk˜¬%Ÿ»:P'¾×¨q?ÔðáfÚl=hûí Ž·u{-Ø@‚­CÕÃõæ{Ží-{¦:`xS8êuΟ¹ á ÙIH¦‹µ§`¸b<Š„‘Ï[°õçöÞ&èÙk‰ïØ<Ï˺ÙÎPœ¤£g òYOònô½5V£1KÙ;Tìm@âjæ¸$žŽ¥:õX6œ­žÙpViéù°tc\~ÃÛ´ˆ§§'•?¼äØliÛÝS\ÞIY¿/ð»V“øÀ\m9QÖ©ÞHæ Ëν9¯Çµv; QÕ{ú%óßr4Ì!ÄW'²a‡º‰Ô$Þ6´ Y¢uÕ^ØÒs+Ÿå.±-Cñ\„þl>Dr)IµoÈx"ô`ÌĺŒÛŒâÍ~’ÅͼeÓôÍÞþÊÒÌ| W/Dl»áà7`å­â€”“¦Ç*xô‘’ßNÁz·V¯« 5‡¼)–HrŠX='‹óJââ@xº›2»[‡Ê ¾æð*w`e-ΞÓXy”è&1J>t´ນ\¾b5élëÛÖ òò7^7s¶ßÜëæ3ÝYjhž8±Ÿ'N\V§0h >×AÄ~7.0Tž5Ë¿“’1py.;í¨oH”Þ#Àå˜Îk§lzncÝÊún1ÙNdzíÇ,X:ð>¶·ôYɇµ¶ûŠ•š"ÐÚMªï†ýw¸1LP› 6n‡ý »¨­ŽJÈ—zÜRÝ’òúvP‡J«•¢ýs!›æHÅ1‚(¶¶—â¡Á³´äÇ¡_\2VÙ0H¡8‡Û+ !èwÜÄoÛÁš±Êù¶Šx¸îü%>uQ~¢ãÜD `”i|k4‘ªú1ò‰¡Ók¶>;Î'¿ÙM´c\Ë”—ô¤|”FVD·¤G%ò:¡ro6q»XdÄo‰áÎðÚqš««=÷Ñz‡fˆm¶˜~ßÃ^LzÊ”54Æžòî‘鶃<‰9Ý›]"H°å¼GZ¶mrúfÍZ†‰YãÛ½nDéCX³ݘæHdÁ`·xM–¾cȶîu )™)õ JNU-` Ʋàïï½â„÷N•†µ®ÛeÈo›Ü–9‘ºÝDYƒ˜tÒªì÷Jí{§±™'5.ÅÎí‰x‘žZÏ”AŸýíOôY+þ¿º)?¾S’>kÌù( ëx%7«~#ª±•YJú1 Ó¹ D0øBòiÍ6Nç:‹ŽDC#&[Ó±´èŒ¿`%“—×Îù)¥uzËÊèì„åTUº(‘ù–äò¸¦¯~XpG‰i¯b]¥³‹ÒÓ¤r$òb8ï©Sàç×nP'ìD^jq]Âw¾Ød ˜Ýyóàý]½žòK(}ͬì ïŽ,Úájóûe‹Éå({)#ä«Êú¢­ò›9órÖT¦ûm<®Lš‹ü²Þ#'öL#5G{¢*†þ’OÎ05…À‹{)üspÀøü(î úÔl£áÑä˜ü‹wx£p‡½3%Øm‚)cåã&]IK˜>˜Ë;’Ë•¿­çÑцeÅ~&ÁþÄ–ŽC®ãÓ3p5›’ݤ»Té—0sî0ÿ¤Îþ‡ŠHóÑÒû£§©=jk»åA§C³¸“on å§$‡ƒŸ3 ÛºW0A$2k¹Z0=†^H|ƒäDøÜ. ö‹›~Pp<Ì%rÇüŒ^U4ñH=[6)·€;ü—Ü€Ÿé.BïÊEKæ7ÏÆÎx®/÷p2A+:© ÿd¬Ë"…ç Éma^‹ãÐæBåø“s5VÏè_o†¢Ä4¬•„ÃÝÏEOð…‰›¢>¦ͱãïL^(.ùŽô­«Î”^lC«ý·(kâöù©ß~«’;sÛöò]Î:QŒtߨö,¿Áðóˆ£û5™C^¥*Õ|¦¥ Ó@KÝ69ˆñn:ÍEœn’ÅA+—´Á=K«Ù…bÌgŒc2 ï¦1z5©­£5©œ2ò³§Ï¦÷ÙS6ø$ñäW,’Óhå=QIr5íX[§Ò¹F,vïN}‰’-²,# úcù8µ©T*ÔcXŒ$ÅL}‚:Ó¬O•à¡ÉWD~ÿšòJ+·Ë™‘Ô[Øüú9Ò%W‹?c[(¥Ëý!|dz8ã~ŒU°†c–âI“bÔNxx°0òŽw[Ø’$^T=-m0îìvÙûå]âIÒwÀ}‹òOÐàw@|&b&$ÚP2Ÿý” ÖAÍ7˜åŒïD',°I/oQqœ˜eBû]ÑZê‰ô·¯2ö÷$ «BXº)Á½ŠQ_?ãÇ/ß]­Ü`é#ûQcüÆor]Ùðò{mç!’ˆK™íkç¹D|q•EjÌK€r‘˜ïò§®òÎ_u2 …¿ Il?ÙÄ¿MÒéTœÈr1I‡wæx ž#¾®GдÕ`í†ñ2 &žÿÜÛïÄ›]ñü ß"&Ž1.ú«ÇÞ@¿9¯?Q~—»3¥¬áhYgú9tEƒ>‹(ž)kè pÛ¢ž\ 'cloìÊ>~ÅB÷1ç‚W©G80(<²dv fh_‹¢?ü¾'kÖwG]åר¯Å¤ñˆ£ðýH¸QÃMnÆÛE¦?Î>Š”ãÝ/Îë±ñì/`’¶.YÅŬõƒÀà;õ! ¶³'×ÚI=VꛓÿB± endstream endobj 735 0 obj 6657 endobj 739 0 obj <> stream xœí][sÇqNé/ù xrpRÂrç¾£r¹J’%™);–&~ˆó¼Éˆ(ówD•ß›é¹vÏöœs”\* «=»sïûãñ<‰ãþÉÏ_=ø‹´óñ³·GóñwáßgG?‰øÈqþsþúø«Gñ1qì'o¥ÕÇž¥ı“ÇNÌÓn¾>úï“×›S=yifyr¶9“µÚè“íæÔL‹Ÿëåâ½:y’0ž¼Ùœ*á&-ôÉO›Óy²Þ[eNž·‡_læÐ¹1Rœ¼j—¡ %í´X]ºƒÖ¶; å—åä=´ë§Ù™“«ÖzôíFMÆÎÖ¥+ãµ]I&ääÉ;hȪð\é(´Ù|ßšlí\“Ñ•~ʺXxôT)¦¨ò³jvV@OÒøyÉÍz! žõ¶Ý}–genáÚÓ†ˆz»Lc\ÜÉEk L…!¼‚¶ä$g‹Ûz^ß‚‰«C7/[Sxâa‰ÂÂÂðó:ÛüÏ£;’&¼ªÃÙytÎËÓM˜È"¥=ùl#&¯Ä¬OÎËZ£Ï6RN:ìi·'BOËpžÕ×oع§ ½—=qá÷xþÜpÑh§£g8mbY¯WáÊÀ2ôV9ˆ¥„ƒggÒ>¢ü+L¼aÂ}í(©\äm45‹úBcm¿¯šêèé‹v|¯ñ~•ã9mNm`2á—h—aÜÆM.p·‡p çÙÆ¶Ð~¾„%rÀ1Ð vT·N¢’ƒlt8NážtvRÒàa?Íý[CÙH¢ø@ºÎ’G8k´xÝ/A¼Dœ·Ë8µX‹‰Dˆ“ CÄl£ÎK›ÉióǼqÂ(Ìóx’xÚ˜"ÄêPg˜Xkc/Õ”¶™wyüÖã­RÄ x€ ;²ƒÅÄõ6wæ1= ±‹ê†/3‡Hû}ââ¼KÛ:æˆXÀ“ÆP‰)ËÞø´¹™ª^R0Ju‰ùêÌ$ éamü÷{ ÕnR³ªKò2•#€ q¾ ûcçI9‡)¦o`ýW»kã¨ÑÇõDðe«éiÛî¦ò$ŠQØÀ»X¹7>¥ŸÃ§h@É1.ÈTü°QÎï‰ *}‚gƒ2ËÉ£p9IxMaÖNÞWæÐ‰+'Ó–m-©óÀÚÁ®Y†»¸½ÓA­!4{VÚòcF™a'ÿË’QG|Î-ó²ŸøN[gˆ'W jࢀÅrÐcüFý bš…Ä õ€øZê ¹$¢ÏûXqAYëõ"úAšB8N¹@x'ßn„š¼3¶'þYL. u͹)w€mt¼;‹©–—Ôèܧ-×ÒÛˆ‡½ bÄà€•øÀ–¤°’îÜú0 -è]BÎñŠ¢Røžð ‰œ‹<Mq8q­AN‚ åë<¹àFäû–·¨ˆŽW}¿qà™iáðtwD϶!d€Ž[æñ0TÞñ_1»ˆ-W–רùm ÇÕN{L¹ç<(TïJçÚâ·:Œ‚ÿOÄ0Vzjçìy^^3HmZ‘ÊÝ—óyCA¿.笚bC(KˆHËÉh\oX%¬ãú2œ©E!CÑ ö¯MqTÎñ E „‰\ȯ­ëª©Ü0ê÷m‚Äè”t¼¹éxW\Gç SâmQ-ë[s;×s½©Ò ±~ vXK\­Ú)^£å:;Þk70û^­HT´òš€†sA§Ã¡‘¸^ß=ùd¡ÒÉ­xt=šFîG9Í•-?°ÇÔØ[œa# Ä% t¹ƒ®á É÷røc¹r¯`õ¢žÁˆ[ÚͰüÂéÉ(‹¹A–?V‚>e,ö#D½¾×w_` a³¢ô¦^½Ýd%Oc8Òc–Q(õŽèè(Ò4¡G´l^©‰™±¤ »èøðu8C8mËÂè„]!P$,ØõxßNÛ@$¿×Ôšu:±Ø°Dc·œí¤ë‘¿¿¯¿³Ü†·øIh ¿žæM¯#€ÔD‰w »3¼–#0;$§Ñ£HŽfzGVf€ÐrüÈêLÝħ_@p‡5ãýìYH: œOùŒ%ùL¼~ö=Z8äÅ´ñ’(Vȯ7â¥ö6Ò‘ RS  ÖùÛ)":t¶ÿI.î„Aö t4’?Ä3 4磙&b…çÝ!T߀…è|+×iúaaÇàèÀq»Ï’(³Úã ‚ÈÁÖDçVÆÄjF ½)1ܪ½ù°Þ Sg¯s.›õ¢#Žëã0­~{F;†ßÞEë1‘âò¯Íи]ÛöÖvÁhÉ%fÁØFùííj¶í½ó¶pÅxY'ù®µYÝZ¨ƒ)¿Z ›¾([L¦µ#hõe¹5— UßœèÌœ+æPž±¶LpG v|:[¦¶" ÕœùÂ_7Ë®‹EÁŽâ|E`9Ô¤ |Dvˆ‚Ý]¶ápPKÁ+å»c0«3ÆœjuÍÀÐëœô@bÿ ÖÜn!âkN~²ne´ènSGÞ÷"ã““H¢3IÜÚ÷6ªˆŸÚÛ/2¢Xà,eDÔ.äsF—l—§mø·7¹Ìî#˜º“ÒL’3ßeCF:Ôöl¶s$jÉè,¢ ö±¤e““ò4 3°+^b0ÐJVšçÚû @¥]­bò:ÓÃç›k¶€»»Ìð†IÆ~ÒK§‡¬GÛy9®ø—MèÍk¯«¶$#ï(êéu¿y‘¢Çèü$ùµ§œóûM²XŽpJ;Ú{µŒºÜ$N5Û"·*RXR¬`f.¨_êÏL3ð+ÇDf`{ƒ3éÂí¶5„S¯æÞpÏ,§¨!(üd0U„œ(aÛÓ>­ ¶€(ÓÇ߃ÇNƒÐÊ÷ƒU”ÒïuçY 5RÊ@gÚíV-¶‡gl»÷ÇÆêþ1A2@³ßÑeÀYωCVÔìJf•WØÌ)À‰n\6>¶°µ|ª‚"Té^4>‚Ø^5>Â;3Ÿq±ð õЇvE¯w7“Ñ“Vq2á ï¥ìðÓ·Õkƒl1ˆW 7ªjºT6æ8C˜ÈqÕBÐÉÚz°vº0:ÎÊ|Á÷ÚE[HÊ‘“«+T½ GxE`OÖDÚÇÃ6×d'³>yÅq¦žw,h‡ä®‚wG¦ó…m›´S T3ʬ`Oñ‰g¬°/Ëà¦;ÇÅ~Tæ„™-ÍÇßoîmÆ{´+¼óµ*¯¦?7ù˜¯e=E;v#Ó,‹Ôázÿ)ÃÜÐÑ£*PPžÑ¥c›öøTI@eK¡éÞñ¦ñ£³Æ¥ž5$¬2•¤ú5¢bB) Úò1W¸©7ß­ é?™Ÿ­ .mžUe*xÕýëŽÀÆÑTå‚™Ñá !¥ìÐÅZlšdåú·IÆÅ#åô^urÓàè¿õ.³*Wg?ÍJñþ(^ðAÉ[ %Ö T€›–9+µ‹3o]epjƒ‘Y)0U1„ùEwoØ V3£±5b‡Qí²tfïS¾mEx¢š7ß+N¬ÃxsJVô+·…U{"ÅŽkÀ={¾ã€†èè|çÝÆ•ÈjÆ3½Ú«U>DX 8ÆŒÏhºqGÎOX4›«Dýk弴ijö~¶6© ø['~Ì-(n6Xqäœød•9;‚»³,Ûä‚vàb4Øn½‹)ž—CüÖ6²’ 1» @ЋiuʰÏžÁ>æxÍ(päFÎÑ~[Žm¬Mâ &À÷¼ š®DiIsàPôÑÕ醽åÚ/ÁcÀŸV2ÈÜ„Žãg&éœløjÈ;û¦!/€öÛé’õ¶®Ú®„°ÒÃŒ;¬*”þӺꂬµl[»¼ž†|Þ÷ÇÄÊåçÅò!G¦¤BÇ7@¾ytôÃÑÇ*U#CZŽå¬!Á;´ ùæ ”1øêáу‡:¾~sóäèÁ_Åу?À¾úþëðçáïÿé蛇Ç? ‹ìpZ.&5™Fu¾êr :âhƒß^u±ý’ó‡-îXyYË(Üîü|¹q"luÐlW(· DáS¡y3Bļ½ûPv±àøÅ&Å0p‹ã~ÿ¼QfÒ†øå¿I—a¦ñ­¬¨}‡¤ÌPݹp* ùHÝ)j¼"±Q¯üs½Wå€P˜ÊŃb·NHE•“ÂJiØZ1û³^/6‘×’ø-¤OìµvÀÙ,Kùjîø¿z¼ö2 @ ˱r3°Š\œ¤9à ÿù{¹7à5’ÆçØŽÿÒ}òIš ùP–ù³Lèƒå2ÂBöéà·°žB;½ŸŸ›pFÈ»-'릮­ñãzõd±µs˜€¸îêwi˜‹U|XÁýO嘟f×¥³'‚C¦¢ zG3ý¬×àKrÅ•˜c ž|« þ’sÌÜÆ.q›Ð {¢k¿h‹¾ªÑ‡ûû~¢± ¬œw–ìjðOØ#&ŸtôÕ°8üÚcw’ô;ÂÆ»ˆ Áü¾±Ôa “¼7v‘ø¤§ßvÒv—zd'MÞ­ÐûuHg r|{l €\1+QÖà,ƒ.|‚Ï­ED¹íáîÚkPʆð"—¯6@‹½¥"5¦ƒáŒÐFwY'ïR?V ’~P‰/å,(Ú‚–I@1¥jèÎ;;_±j)Z¥U6뎌µR¡KË[ª§ÇŠy·Z7ÞÏ|Ñ€ç;Ž–BµH’;Ç›øØÓgÀG»“Ä2>óíP™ÉEÓv"óo'íµ(S£ᎼG½ˆW­;›{Á›¬[³ -ÊvT‘³Vñ[*ëÄnsùÛ¦¥}ò­˜g>I0’¿ˆ|$¼|ù†&ù‘u]Gƒtp0H–3øòÉ»Û"ºnê8jPýc*ßpæÀ!ò õ²_¾EK3’oÒO:í—¼UlHå(¯ÜÚr“ ¬ŽâµpÙôi\väÜRÀéy’³ 8ÊÿeÅ[¬3zÛ<¬,Þ&ÎQɯۇ 8‹²¸Š¤˜‹ ÐÔì̦XuÝ((lç_Gú­ëŠ%·E’¸f/ŸJqÃÊâCê5~4AqwEÜæ:ä‹.ç‰QjÜô1#(÷º væoI÷§¹§Pƒ@…u9ZëÕ]ü Ô(N£gJâ—(h ˜ìT ´ìеtˆ¨Pœ3‹ˆ9Ð(ˆGúÅØ>ª™ÂSµÏå@G½ İPÖY ¡¾OmAÕ³}i?$ù-Ky¿« ¨:&ˆïÎÀ©ïÔZ¹D(µŸ=Èd²ù)OÛÄPÚI¥Œ—g¦l2I»ÚYä8»%Ì"b`z>˶ã8ÏT• f—cg¥xè¬&‡”„‹év¶*­²#à;û ,4ãz¨¹ öýE.v5»ÈEˆàQrh—+Á<¤”ÄŠÎÊßÍ߈@„#9çÜ£xÜ›2¢u¶µ¡ªÜÙ@¹{bó¥£#ÔVbnJÂÛŒÚ:Y´#€h»"å;Se:(s—Î^VåòX¹SÅ>[V¿†H!Rs[/O“ ˬŠ4dììššºÈ©(4“ºéƒ²Séx»KÐy_JÓw%MY׈´ž9¦:ú£Âd¥ÿe9 k2ôÿåœï9ä®nù+ m¨«ÚI}Ñ ÔÃSb?‰méA 1‚7m~+©—LŒ¹Ò6Ë9†ÕO3 ¿u ÁöÁP67¨ËË5±Uc“oº#âj®“Ñiˆ 7µ±íäó^ïa€ª`“·kÒú:Öäƒ!!>ø¢†úœ£A3Æ3«è$]úûv˜ÙÝ÷ê+ˆïXÿS ÝÊw±ÃJépîUq”;Øí'µ…9ëÁ&µ›A«½W[Ø2ƒOÍñv¦°êGŽ€Ý¨ý[¥^qa à"´zš…ä3 Œ”YŠ…0r±T²tŸSõP½`pÚ‡_@”µP¯ÖNqQjŽAR®y»ÍàS8±†nôß\ÕáœJCöngûEŪ֨ù’S)X´`Viº\Ú÷ík4Ñæ/s¨¿ÞUä ö–LŠÌªÒ}™Â^øxZáaÒµ¤NÕ’3"„3ˆéb¦!ÈSîHãˆYž4ãxg €b(ƒjór{¡ÿÑ…ûbÙˆ‡‹–¼9ЬJèÁH³Êqœ7”™~B•9A¿ž³­ ù}ËØ ·ÉÊ1Ý—*j‰Çì»úè·ÚãÌ×âK¾o‰S¤"@ä×®ÏÌÊuE~nïóY`MBÚÖÞRf¨­Ÿ[ggì¼Ù¹=5«´1ƒORk1oùÝg¢ÕÀ¼sp¿® æ›M)¶íó,:…®ý^ˆ[üj’oÿ‘Åphƒ°Puø~²BÛþ¾½­9‹O£ªÛnìµ:ùíI§$Œ²„vdþ#‰a˜ÄðM+>µ#±7R£Éür†”\óêc (uåÍ~ ñ¶¤1€æ¹Æ¦g+ä] ÁûVSK iÙ‰^>v&ƒýÀDVËæô Û¼|}t ýTJ‹Z¸¦*ã0Ä8-p§·1v°‡ß}Û .Õí[kåÛúëÅHÇæ À^“N÷ç „‚+à e *éÒR¼|àA¯W„ š±Ú¯²Ý[@?²aç1}Ë çU¸Ž´‚rZ«`ÎOQð«]´†rz§ö}ä®)Ùð­±0Õ…¥`õ2¼V¿­T¾4á Ï@-Å[±Ã’Z»?#Òå-8`f c@ï£áÉ€bSN/$›ÂžÔ^Ýö\bᙎˆ^¤¯kà-\Õó±bÌ"àcejP"ù‹W–Š.y¿ãÕ¹^î'ˆ”·u4s› +öIôVÌ…Ð÷áñ%ú®ˆÞM«ô&w¶˜=ïH ó):èäϵñöU…‰1xüsíÖšº…ô3àÁoo¾có›Eúf-÷„5Ît`{“k8!‡Ò6x¨¹++®H à‘4²öœ=Î,èâ]Ó£¯šFŽoÕ¸”«´$À軼o±U½Œåt^­³"°>®ÀNåļå¡èþèlÈbÞ³,í°T»(èê§~ªéz$»aªzžá›†ƒ˜™"ó3Ç~º«óÒœ±)‚Ï,r²³&[Z•‡X@¬Â²uÅÖœÆÛc¹êoË(9Ÿ+¢Y,Q¾\ûTŠiëfêÍ[…­ßYO·Y54±á~.µð|ýëHœhoA»psŒ¿WqbâW È„ÎU¥©/\‚ù«NfÒÅ8Ô3áÉHоp ŸÝDŠtUô±9[þÂu´ :vüú;‡ ò™^f58Ó2[5?(èìÐ¦é² j'~‡|¬#`’5ã^Ï¯Žˆ‹ ¾ßåap#á ÒÆm¡y¹ÁÕ~<¼øIV*(¦hO·4’ú@+Š÷«Øc•ð1¼*›ÊË—ƒè÷~âÇZÂ]TÆžˆ \¬bJ}_Z?f}΂/ÜFÔŽø½7ø–)•Oñ+8FÞY³#gß3¨îSK?#?P±ãXRiÐË V‚è¬a5Å„>[NmT§ /ŸEHl›×»š‡ó†X4ªTÂ@›Ïþn²,—ãjÆõ.³çe “OC½ó¼çr¸Û0Í„õbtâ8ÚÙ šî<þªG«¨ÚŒ§øÄõ‚ͬ‹€ÿp_¼ËÛÕÇ(Š<4ºÑ/”‡©%,»=€‘Ô›S‹Žþ¨&”Û)o€Ö{»Kì>Áj¬5u¤ W_´‹…e;@šÒ Å×§ÆLòøTt:[ÝAÎr”~?ý? ¢ÔÍendstream endobj 740 0 obj 7118 endobj 746 0 obj <> stream xœí]ݎݸ‘^ìe?ÅÙ«í³˜–Ŭg2‰“Iv&Û; ì…ÝvÛ†ÛݶÇNÆyŽÁ>ïVQü)Jdëè´tX,‚Ä'j‰b¿úXU,‘ïw}Çv=þ'ü{õöìѹîw/8ëw¿†ÿ¾<{Æü-»ðÏÕÛÝãK¼ÍÈëœæZî.¯Ï†Üe;+w†õ]x{ö—óÿÙ_¨ÎZçÄ_þžTºx²ï¬Š3x¸xön/;+¤eçó¿à¡óéÚ‡ôë&ýõiºö.þÂ×þêò컳÷;1qÙ1%u§ýûT×[”þñ“³GO~¿ûøáÓ‹³GÚ±³G¿Áÿyüí—ðÏ“¯vÿtö«'»ïš:¹G2e:Ç ÑnRG_§Î¿]Ã_÷ZpP*?ÿEºx›ù”® sþ,]z/}ˆ?~I•‚ƒÍj£Èƒ‹Ew/ö܉NpuþÍþBtð”‚nöp£è ¾´ê¸Ò"\UŠcïÓ ?@ VuŠqzõÕ€k ³ÜØÎ€pñÒ'ÿË1¦hóÏè#¬ÓZ8^pí:®-€&þý_É:¯¼ÛëŽiÁ4 )þ*—ð0S&uîi¾á]jô]îô6_} oh€ëÜìðåz›ÕÂ⽡Y" éiöc~ªR³NrF{ó"7ûaœ;Eo ï½ò? ãöü êÃôŠÑÈË:èã4òüry+u·ð^W žø\>¸<¯vëzo:ã¸q´+do(p@DÙõ½£ZFÁ锿ç?åúÜÂOI.ìӅЦ“Âí.úõ×óaDzÞ‹¼‡?IÈ{ï·ÿ„T€ªç¹±¿îÓÛ¢µ‰Z”ÆFôã½#)ÑRzÆÉ·{7é/ æŸ÷`©‚õÒ£ÎòÎ1‚ÿwUô£Í·Þ¦Ç?Vñÿ¦f5±£Â€Uyó$%Sú46Z¸ø<§¾ÏÎ¼Ü Oè®7–võ‘c—…úHK:bhÄÔÉ[Ÿ –§¯âéøŽl«ÊcO ë JýG¾X69á.KPºSÊ6 ®•Ú5^XümPuô]÷!Äÿ$÷ÞŽ™ÄÓGÅTS'¾ ÝùÆ|L/9§W?ì•‚þx*mJ¥Œ·î0ZŒuÖ8C™Ç› 1ÊéPâP\Õnh¹ fap´Õ‰îáîBcòe- ߃ÿøÉ÷iî'¡ª»ÚÜAn­SQ E˜N¨‚\ÞåŸ÷A"’†ÑCf«ýa/Æœ{: ,/go.y§`b¹Êc2Ü„æ¦ìP7i@ç0fðR2—ì DÇêfüºô\¤ë„ÑÇskPÓˆ±¼›à¡\œ^ï7ýý:Pšz¤¬ëª&ˆzÉ«Jkš¸ôžº¬d`_ªã²3èRw^›]_㱋ÝιéBz÷¨¬}c7¬.Ò._¢2Æx9ò¾Ëøä–8ñá¯-! ¶<‘0ytTÈ›QÄPŒ òcúv¢axµA‰1äOñÒš!‰îQ1´×Á凙ç«ýEß™¾·ºàwO0:B%#÷ÅðÉØÀTº×5.œŽdâÄ©)Ú¢Tçý“•½ÿH ¹«„lJÿã(mUòv±ïjÊçªï}WèŸ|e{º€a™þ‘å".ºÀ¥»äo~UuˆÓŸ_An Ó½jD ØG…ŒvähÑ“jbäß:uqðUIXs‘Ftˆ4,Nƒ úšMâØÂ”ß1˜nɸxÈZ;¾ª`€í˜ÔB }€À4ËüqDÔ]¦ÿ [ƒh×€+¡i[ä†ì€Ö=zbsHè‡q¼ë¹ªÝ(}L®VÃÐÙq Í1ìCóÞ’ì`žÜÂkÆ\7rÀïãº=½®Z ÎK¨Ê>8‰p@®E×÷ö!ÙrLžrÐTA>1Ý⊼=1Ö7ÔÙðºR¼$ð˜nIñÄuÕɺªÚÁ\¶‚n\Ÿma̹#³-Ì¥ø8-€†eTŒêÇ«Žøë*ýõsŠ+Íëîì¤,^õ ì&“FÎöRã¬P<›“ ŸSGÞò³]×±lõ—eÆÆ]ŠƒHV6ÿ3!Ÿ çÍ<—]ˆ¦íÝîúÎÓÈé}/Àö=“$ö¯óæE¶¢gc¾×E46²Bôïµj9! °÷‰ã×IJ"‰c?Vi°¤±¡“ä¿OEsqIÄòóß‚ƒoT]r"/­/ä>«º\/ÂÀ”ñy°xðSd2ùúzk^Ȫ/|俇””f1JW’•Ü@Їê!ÞH’Œ +/¤ÏøƒÈY*i¾õyÎpÄh={ëEêëì`|Xx ~Lv-#“|Yæ,»êWpTkÕ•Dd±öÇü[ ¼.yþwÌj˜óDeYÞßL<•;4XúXš Ç™¹†…ý"©à©ƒbš‹ tyœiL:˜‘¿Ñ^6Ç4aI@ŸGÇÈ!¨Ï¾™u2<‹pˆLg opvwùÍÙå¿ý¥±Âo7¢Øóo÷ð„‘¨ƒJv¬Þèör nH [5„™`({ÀqYïá;Øþ=v‚YdgˆqgEµ‹<°3º’YÅQ/M—Ž{ˆ! •Wµ¾2œÕŸÝ1âmŒ&ìžj,R£*À¤QøŽL÷hØVÝî ]…[£ª¦ÛÊ’Õ\–\ NæÄ_„¡=;Ããäíhô°¡’;ï‚ã¨d£~%ÂUÛ¾ö~–É3êZ[ °ºÖФ  °0‚ŸCo{^ÎN5ï¸ÚÛ¯±v O|jT‡*sÙo&h¢R?(“ÞÞ—fDCWS+`È ^RVädëqmª #&MJTªq q ðzטA¬@ÉgÕ®ìq¤zlȯêCCb¥V£êšã{•Ò)üý6{`¥Wšýð8–×{›-·…¯õ!Õ[ˆX¬SŠfê 1¡¿.±¹˜\›BÈ˽AoÜŠÂÁKþ"­Ž &ù‘oƒF ¹°<ìž¶Wƒ4¨À•Ø´fmà°ØîdžzèOÖþŒ £°âEfë^\mÝ{+Ò÷Ç{ |¦™# !šÍÂiyÛnq[uë¿vØÂw÷0ÈÌ7!œ”p«ˆ,n«w­§…ÓÖšðp"zx(œ–÷· 'èÛ:ŒÂõZ\/œ˜Ilÿ¥W£tzâ2y碬”÷·wÿAИÆa+[‹é±B„$ßÖTs½Õu³:l–w½ &OjuØ0áðß­aÓCÄj§«eQÄ}$Néã„°‘¡°™ËÖÂy°ÑJ,ËûÛFHÏû¥$UGHÏÔ:°÷"D:0³A‹¿!ÄðíÞç>D¿­…-$Âùªžp®ÆHEŠ2$h%ýé]áyOsé·Ôq¯ÕlÇŽà÷,b·V6"–¨z°tÍ«ž5ÏIbW §êˆ_.oñÒ:³”_«ˆ‡†ø œsi{\³©@>ŽÄEBÞ‘¿G "ó#q¼X†f_õÌxí†9dn®L¢’réým#Ëø,Ñ È2ÚžÀç—ði„,"VQ?‘5³ÚZ|!"|v5e"-óDYGÑ––nïÚ¸u–Ò SGväÿ˜XhT*ÇAešT¾úõ¡!Áæ²{TÉÊLËûÛâK¿}l‚8 ™—HÏÌb³ÙZ6"ÙC²¼¿m€Èž¯Há–&*ŽˆÑWÁÇáù§ÍEóøÈ‚=˻ۆ7nŸ™›¥ ‰£àÁ\ª žÅGòk@d¬( ØÈÃa³µÈ6Dà‡âfyÛ¸Á/RVñˆ™Zš¦8 7½ÏØÒŒ®ÄRÚáÂçb©¹lO[«Âã‰(¢þñYöÏË¿?ιø dË…hƒ¬lï¸çK3Ç€L8‰E:?Ȉ‹#;5ãwÏâqk­!©Î6Áãr!šx2®âlCCò¤'¬ß4ìgÀ£®áñp‡lsýxäíl¼#„h#ÏØÅmÕ‘g@ê0¡vÝÏÊ¡Ü\?xD;› o¹mä)±¸­:ò”XiW û‘'ÕÉ`WeΫ·jÁ£3lð4@¦Iít÷iR^6Ú‹5Ÿ-S9•Î)*JíÜ*ÒéöÆÞ~xË%àú¡íy¡x¸HÉw\Õ}“n »|‡7ëò@ʋݴ§¶Ë»tøHyÀÜ}'§Hƒ&ü#RôtP}]ªÊüH…KÃ{OWU=ÇJ Úxskæ ð\sÒ iò&öéiüñCêïAÝ„ö0e<Þ&q%¡I—g¿«Ìµ¯ NŒWØÎ€$e“¼67>tu|ÂÅmAš®ÄÃ5Ì“²Už†'¢Á(/f!Ö@·Ž›QÅ–ÓÃFÙz8/«ÀúÒ6w¿yz›–|Ÿ­#d:Ù¨{d¸iwïâèÍÔkù`f¹ ‡ 0r.ö“ÜiÜtÅEQ û|Œñ6±æþeýÔOÓï~>–$>ß«éSIW¸½¸nm/žPsÈ!1þÜæ*{ÒǶ†]ÑÝô z̲ÝMæÀi±d<Ç”m >Œ²¦¯(ŽMà&lÊ>=ƒ!œ_àÇ>m—NžŸx hýa lN\ÂñôÉêç–?Æo1¯”-êF‹bÑŠÔ=®Â•ñúYgʧâ)ý+£-NPÆ¢ÜA–&ðÆ!ºä¼•5,ÍŸò¡·¾¹ˆã¾ÖŸz;P¸ê†|¤<ñŽfÁ® ¸¢ù]ï‡ãí¸œUÅ<½ûa‘EK½Ç ÜôŽ’èâäšOU»#Ö8Ùpߟ¡ù±Ê„«É½„= Ã1'ÚFì‚A·ibPR‹ëçç|kÉÿ|µÎÊ1c+ç¾ G‚!'OãÉGjïñÔÈçUvYª[†’³H 8õ-D±hP=OPx?iˆsÍ&9 Zwtµç’œI8¡àœÞñ)‘ác)‚mrEH+››Öšo8θø²6îò±42!;Ý—r ßý/ |>endstream endobj 747 0 obj 5515 endobj 751 0 obj <> stream xœí\én$Ç‘^xÿñ)úß²êšÊ;SX, ÑaÏbm$†a‡äpñ)‹û«Þˆ<#ênÎ6„ YÕYyD|ñÅ‘õ~5Ol5ãñïÉÕÁ‹ï¸žWçæÕ¯áßùÁûæYÅ?'W«—Gð˜Òrå&§9ü=z{0OV…ÇVŽOÜÎleØ<Ípóêàχ·k9Y¡”<¼ËWgþ :ˆw¥eñ.¶Ýä¶“|U~ñ!·•«›|÷n½ÑšMÌè÷ƒ®sÛy¾ù—ƒa½ñWÆî.cÓ_þë€ñÕÑýûÿÓ¹Ÿå«ë|·üâ"ÍýºùA˜;‘©¤ƒEÑ0|¥µš¬ RñÅz3Ofž¹´‡§k69î,?üi­aø³b0Ø <ìfX°k¼-f)`I6l‚^˜†wæËÓõ† ;9«¿Ä^µsZ(XìÁ:'bl–‡¿ÊWçåöCn¼+½—û÷ëœ@7L~†™)ÅÙ°û°»ÕCËy’ÿêqøyŸyœ´Ýu’ —}7é¢Lÿ‡Z(óCxï45åÎ?ÄE±©åç]jâD¬ÿñ”y¸SeBy7reŠðKfAÚ§Ê0 é!]ü·Epçm,s»/ÃÚhÁAÏâ6B“ËO¥m<œú½Ö©É–‡p»…  ”öèt”u]̹‹­¸Êt{Ú¤®6ŒMÖ8zü§,=Y–ÞöÂqW4:^Ü?£,ý¹——y‹,å&™.ÌH–‚‹½¨æ.>Ë÷‹˜ÓI\3¸Ðë›w`4óM"ãx“׎Á÷™îå1ü•à gþOIþTTT«Š»Æ@–bú£ã²¬A˜ ãöðÇìÅ‘e'oÝD=šm”ò¶¯°B‚%ió½žF”‚Ü¿‰g*ÃÀºÎÐú·ègZÍè—ôrí7ð04!`goʸîÊhL`%–ú%³,zà g’’l8‰®7£Á¡kžÆ€€ù@Ñf÷¢ K½U¿ý–J*‹ÓV)p¸» ¿“ ¸ò}ÏërŸxG£Leþ·h+ÚÊ ´ˆÒº)üæ”ðyR³J¦ynÕ 1±fè8†¿‰• ]æ }œmÃÁ¦ÛV©'p­û¥I<ˆK>)0]„‘W< áfrO´ÑðkÅ“˜ !4R)s…mw0TLÀ¦‚æø{°`Í'(ó”˭ΩIøÞ™›ŒFft¦'qPX‹“6ìŸ5Üš+ìˆ1!`¨*4qY¤ØzÎc<*C³o4–ýûÌÁÉ:ÞÛ¼$b¦"63C­f‘HÒÁm=~ß cÐ~k`Ý$Ù¤F]Ð*×:ÎÀÓ~Ô~®¢b2—»5HË<³¸®E£cW~ÔoZÇ¢–¢³Þü‚ç7ùÃ/½ÑÖ $¯q|nbN.h1Ÿa-,€l÷*¬h“ , ô÷JrxÖl%&m¿.[q:b¯„~£ j¨bW¦…[ðåÁF´ô¦áüwCvš#ÁèÁTkú@ Š :úì÷Z& µ ÛYµž+2^¡41VQ dkN€^š‘–̶gëþòÇ%;”ZÏ Çn‰y(²ßx{‘7¥Ë¼<îávúd ³ç7Å‚=kì?XZ Eॖh®="5#6ì4Zž?ÈÄWäú5ø `Ì•FÄÔüq-á[&&ЯvœHÝ}qº;P"êÕ£ZÐÏâû%_¦ÏÌNÒ(*Ë‹ZƒºÃ+OþkéÍnb’Òx’Ïnšù’û|wÃ<¡Ó‚^Dî©J%tÁ×sN“iöˆ1Bž#P.k1°ÁÕS=Óô#+üä”Y>]y5¦•} ¿J*A~´¬Ëø{pñ÷#µQv¢P[©£P #BH+W“`Õˆ7þ'#Ú¼Nˆ  ±‹¯Èuz5ß}áâŠPsH‘ÜÀÆcŽ›¸¹ÁdmØã£58šÆ7cýΠ"Š àl Ö¦ºø#1ÆÈqv¸ÚÒXx¥É)QÏ€ð׆´^RYÃ$5Ì(ì2P>¿ÔàáÏ‚ô¶#­E1ÊíEF.c@Î í `”X4éknllkäW% ߦñ¥§{? iúqÁØ÷"C$KO mI!0s‚K,=^äCq ~é|Yâ+×­ý«côGÔøÂ¤«_ÎÁtAXrj 5ô6-ÅZ ½@ÎZÑÁêE§J/9ˆŒûÒ†Aý zÆ;¢>Áo¿h´Ç³w…;‘¹œ&ǵP†‘.+wH‘⽺5Â÷> aƒ}B¶ì ÁD¹,ÈŠ yíEe(s¨ßP1¦ u8à¤ìæ+rä9‘Ð9¤k’feêB»ãNd¡ÄîFàxÖÃÊjÿƒYÖ †@ÈX=ÃݵUôfˆC<¡ ãéòO#¦q Sƒ‹”*Þ/Z³@Jh2ÔºaÄF`Eޏ¤ã¸ôað•Án™%ÞI°ß¢™ܶ¼Ž¤ÉL:aIþZBM2åÎ5Ű«·ÀC¿Ð[ý–,ŠšäV’Σ7kÑ­ÀUål)€GÔ¿ËŽ´ëN¸)´à$iã|ˆ¨G“”Ot٪܃ßÙì;¥•Ñ)‰èþ.ŽÅè4ÛP|×DK¶Ä[Hh„„qúœfö72žõ$¹ØâˆEMïèNÍQZ=özND&ï­¥ “k:VŒp1ƒ¤œÏsÙ è0fí³C…±TÆŸU«ÒoÐõ“bBG€Òûw#L#kñ.iJ•›|3š !™VŒƒ¢ã¸ýÅáe%«òXr(÷ÕZ ‚,ÛÕ« {%X¸îÜQ,ßE笈ڹ“OÉ%µÿˆØÈ(º[9@a{¼䣨Áb3ô;W¥³ÁWÑ2U)øFâ)Ü•Þd-z™SuÄêìV ìUáëÀyzà‡•ö{æ)ÄC@A Có²%Êþ²"'>@Š7Rio'¢°uñ}“'Òv!¿ÑM¦!7Ä-"@S#Ñ õ:&‡ÐoM“?Þ+IEV,G\}ñ) ¦èÒ¡å&QÞnÛSÞUÕU*R4<*–vÜdL¢‘1¼F,ÿrÐ4­Ó8uSÛŠõ ƒg>±\ñ¿EúB܈°Øv9XdÞêˆsÿöœ¦ÏØ5q£‹ajµ€²Qk'aÌpà±\ Fí½\¨@ÌÛz7WÙ#ÂlN)Œ…ü­`ËyÍ, # ÓÊeÒãE%˜‹2X“™Ë HvÊUÒ¸X²å%Pî#©5AŸÛb)-x%#X'ËUÅ‹¶0<㊠ò«[Š&éWye}«š)š§™ÂI°V…< ‰½ÿ‰ôø;rM^ZÌq¥~‡÷Ídª ïHmy¬~A¥ÆˆÆ +«‘†„â}Ñɇ¡Ö“ Oå3¦"}¥ îÀ›a4…¸=e`Ù$«‹T‡u%0Y‚â=ÌÅ÷ÆŒßËìµôxÉLŠ-‘àÅ8ÜzQ€‚¸*}ˆ%Ye°Äéx)ß8ú0¬‡j¢±–Tz>–Z†gÈ aWvÞævWáÔA|#Þ§|‹z.ÅÁªìg Õ†kH¸$šŸ›PMë\àá"r Yâ¸&÷k×<ˆ ×là?wÑçmHª*çm"þ÷–4L †+¬Ö ~Q5œš¶@JK[¸mŸõh•Zæ|QÄ Q¸µ!7^x©[óØìL ív´€¬AŶ§}üöÖYê^dŸ"8=–jqd®bž Ôù‹*•›<¯vfežÃ«aÎNšYBC† ÕF`U©gĤœàdUrÆg„ýhLÂÜ0æÑ¿¨<çIMiìÊ¿ØVL-sÚS–µ;ÃÃaÒæÁö`<…Qƒ¯}=¸d`¸X]Þ:-ÿÓù‚##ëuèEéàv8ÒA»mø³wAYR½Ô¾ ¥E«i6¼YL/˜!@ðàº0Šq€übÈÆžF­Ìbëw±}q{ò— ¼O Wˆ›za•‡¥êeÃúb'B«ºb§˜¬ 23ªo!®!>!T)‹QOß8ÎòÞÅò[Ek ÃÖÁ½ïbµ§1üQªó¦¥5>Ö¸b¢‰ÞåêôtŽÄxýWw,ñ;ü xã—Ó<'Üä' ¸ Eûc¸ÃäbªÂÒÚ\Èc²ÝfL|>6ì“j ÖÕžÄZÙ1Ê’BË’xÔåöçš“˜Å2BæJ$uø—ÃòDïm§Ð›±ÆÚ†k…ŠAcS˱?t7¢ un«£¶ˆ*o‡“XtÆóEƒ¼ØIdrLdð/ëÒÕgUÜy#MÖÄ`–s4¸oRÑäÑmõÀ šÒDëcÔÎ2îO.@)¤ë±ü~9tƒò2Ì=ì_ëŽå®cYŠ©]( [8Ø?RþìÀ.î“U?…Œ£ŸztÃ’œ ã¥c>DˆÉÇ,SÏ|ž‹?ùDËάO.á\Šî7Z|gÞkËèJ¬G“«tœ äb ƒ}#ÙAÃìL}¾%YI#×€FÜÀÓMÏ ÍïÁßáÈN³ èˆÃE0g|r¸ýE7S:=t3³{N&ÐÏÔ\ʯ Ñ:騋yY0‡thápU<3 Q•eÛëë3{Ÿ´¨ë 5l¤¶4†F–w\a½G¥c°õ³^° ‡jó£ã¸úðØj¡]ã&pSÆö»ø^ùL&³‰0Â>Ãbd™ƒçd*Ú¸¥²…Y5PRÇÅ1÷_ŠÜ9ê%Ø t”ŠR9» ™}~˜;ËYD·d›HÄa`\Nk‰ÕR» ¯SQœ*ªû s°©XòÁ8ÖQ(‡)p–9•sˠΥªš7RÖFkŸÝG%£c$ò§ò³‹’ÇÀºßâÝõèuî:­ ¸§‡L O¤'VË·@Ê*ê¶“üù{zÔô룃oÞ¯DøîLÚ®3óLpL0ãë^¾:xñê·«û»‡³ƒ\±ƒ¿Áÿ½|ý%üyõÕê_¾~µúö#>cÇ8®H5¡ö[õ‡LÚ¯iàÝòåªö{ÕgN¶ž¬eÚ»yt _o‡°¼|v²?%y³ÎG­vºÞ¥j h*ž·ÈvCÚžèÁÇ0Á,ç‰Ï4uBžlÊ1ýG4(í#e;NoבžV{ÚW#ò£{|+"‡,ÃKÄŸH§”&‘1hµf§ û7èRÕTäÈI<v\FÐ%âhýiç臖K]FþvKeù¶GÓ&SëÃF(0¶up¿Y3ŸGê.UE‹¥I”_VÞ&Ư-P{K!†øf˜íßÖ>B¨´¿¯a™·Ÿ¬” ø8MvÏx˜¾'/­ò9­À6rN.é/«tžß¼_µŒ÷/$U™D¿ö(ð[¦gxÄP°%zJ¤ƒÄDízQó±™=Š4›ÒQœ¬–cWv)BÂõ!Æëj¢0[ˆœÕg\·×"Æ©ór¯é Âq©JIÊ7^F58cÖÓ9Ö0úRÄñ*åŽ$¢üMÉì5|¨Ïƒy‰—%£âŠýC÷ñ´^>U-ÁGj°þP*U‚Ÿø±£¨¦Ïk•s–NÇiï áûæÛ0C6ã¨,v¼DŽçd¹ÍK•L 'Ä >öK¼o'ÉØ‚E%Åà´¨hú×Eý_EùŽ Azí—h¸ðC¬v!út]ÞU£#þŒËö8ñé¡Ä¨‰çR¥|øMîYM=Ø!4ÇÎŽ =Yr;Ôô.ÀÖ¨>ÏÏîò _ èêI&ý7 ƒÆ¶·ùªpäóô¼ô…½šV—ÏþýÐÐïú€?ç«Ïã…8ü=²|Àð4_=ä»ÿ¹ß÷qfïN€­`Îñ°.2Â\Þóùöàÿ×T¬endstream endobj 752 0 obj 5024 endobj 756 0 obj <> stream xœí][oGrö‘¿‚çËÑô½; ÄkÇ«$›Õ&Zìƒm,x%X¼X"m+ÈÏÐNU_«{zÎ…ÒR`6Ç3súR]õÕ¥«k~<v8â?ñïéåÁ³ÿâz<¼x0~ÿ^üxÀü+‡ñÏéåá—/ýkìÐ Ns-_¾: °CÃÜ;4lFxryðíêçõÑ8˜qäÒ®^¯Ô`­sbu¾>bƒÖŠéÕ»õ‘¸rÚ‘»ß¿ü7èGAû¤Ÿq°*vÅÆq¼êéŸ×r°BZ¶ºôWð«Õq¾÷K¾:ÊOoò½³|u—Ÿ~‘î…±ÌÌ™I70] äÍz„÷”âlõ~}$8LI®Nºs¿-¯zBiç´Pé Q¿|f™ZýO¹Û¡ähW×é]½únåok¦ÞÆQX³zµf¦g\åÇß­×G܉AH \•ÿ‘cÐïYjV®tnJ”ç&ß´åæ˜oЕ•ƒvõZ /¥"[øWÒnÐÌѱ¼õ/À½¼^3;0«tf7«K °–ÿ½fƒl”t2…ï nñG ÊÅʼn  ×¨°U1(=jCŸ“’»d ‘ïÖÈPøÆp`¡—gÀ2“iy|(‹zŒ¯NC£hz5Œ[Ï8@íï ¬ ]•_F#\rÞ¶å//± 'üŒÜípÁ.•!ø+e9§o^âï‡7¢„ø α/ÀÇH«H@, «wxÄx ái„ë"l©ƒ‘ƒ¸ç»¡éÆŒ9RIJ$¸Ë%Çñ®^dÞùŠˆè_á­€Õ’Øé…`@¾º(]·ò‰/žeÖ‹#áNSv ´rR"s®n餀›¸2s†¼:×ÒÐÞãôa=)Õ¯r÷[y˜HäuY +*Ò‚é ¾ú×5ƒ3J×’Fêâø¬q€Åéñq—nê´Âô{\èÅè¯îz¿ºÂfm“°‘)Íõä×´A³öXþZƒ ˆõ «°ç Bî®tWH#;Xé™…kÓ$8CÚ"Bx1'.\I@M‘ÖJ½ú¨2Å…‘0!è@xœ(’9‡Ñ6 a'Œãô¨Â´Ì(AžÓzH]K~  ¯)CZ#ã~‹ãZÛ¹&&Ìç/Ï3zHˆë|ÄØ|fÂrû5:ð¼†h‹ ü*ÊÁº™ˆmÑþ.¹¬0ݽ@q¸ê0fÁÿ#ÂS†lÞ%WUWUr¼Ô[ò85ÇÙ½õcÉÒÆÒ°ïˆ†%‚|Ü"j‡ÂøS=ãžÕé]W.ÐÊèˆN3ÇëJ£1á¡€WÍhA˜yLðü$(¨A!J5°Âe5üRü°<5hkœSH†Õ0ƒ‹–D2òÒøRóFÎèáÓb+¼ÆwAwŽ:ʆfóø6DÙæ»¼Œ,v°Ž.Í1¥‚~aôj* 1°ÑÌÀf× ²1›ÓßJæu”nÆ^¸*ïþ.ÇE^1"ËTíç–΂ükÇ) è¾7EówµØe àX弡BWÉŸ÷DŠÆÓÚ€ÕMW|*}šR|ññœd`½·+âžI±MÿÞST†¥i#yì(¢;g*×RpðâF`ÿ8xùßÁ/ýmñN߆.÷1EVP:NÁPTÄÀºo U± »d09¦ÈV€Àø²ò—¦Ÿý._”¿Ë7ßuÇz›YwbÞÕÍw]_.A­Z}C´êd’^GIH³d®RZ=߸¯+kµ›.ƒ„Ö&§ktn)õ"²ÐDˆ(nãm։܋z^D'€‘qÓõ™°…› Ì;OØ~â)Ôz³Ò JV¨l[lÅqp7FvÈ1*Q 9*]w)ïò½ë|ï4_•_¼Ï÷ÊÕu~ Ð`÷á•Ç·äqÝ ^ç§—ùžÊWÏO/ò½·þÊ2Ò“të8]¼ÍÏþ)ŽIËÕwßÅÇÁ·(:çÛƒ=n(‚Oh†Xÿ¶P¸CF¡Pâ\ò‹çrþo~zÕ¯rtkõ}š+˜ñ`-#pö·éÞe3z¸õKºhG ·NÓE¯Hã5† ã®n.Nš%5&.6µZŒløh*ëqÙ!U™[YãŠâÌö‚_å÷î:­œtúxéÊ´L±¬ÛítÚe¿H·ªiGªÖÓæÓ?„Kô¬¢Ç§Ë™£Î>Dð\t=Þt¡Ðå&EðVfël÷\˜7h¨î…Ã=í-,-euÒ„ô+QdŸ~Ÿï-°™ðFw¼¦{MñWyjo›® ðéëů;Dû{C‚ºeŠÈSð­‰kÔ „)Ä-‹õ:ÝʲòsÓ?%Mé3Û™¶oò³l†d%Zfr“nåU-òÿCÝoà|oŽ>àût¯ž™uƒâ|GÀºéˆDY ¢ Ï”IÕfàEó^m«Ñº`heî¬uë‡Ff+BçyÑ'@D›¼´E½eÙx_Ó¼Z¾·ÓÏêŽ숖ÐØùM> !ø„9¿osÛ4[•0ÉY¹ØÝ¦ü¶þaéÿ¤™*í§áõäwyÞ_¿<øËÁ‡Ò07hïv‚Çkñ­=”J¸AZLIøòùÁ³ç:¼}ww~ðìo‡ìàÙñ?_¾øüyþÕá?|ýüÐ75ØÐã#´cð÷ÐŽÄý€=Ú™Kx¨£E9áújmp’ÿL÷;¤ Á|•†Î†Æ‚GþøÓḧ«)}5ݹ©£$*ñ®„èª_‰¡ä=€¹]EvêQBIaph÷ Ä,¯I† ±PS9y8ÛÊÑìÉþ3ë<ãAΩ:,s€ŒÞ)¸„÷NóÕ ŒÈ ‰±P‚°@Ö·m÷$ÅÞS`£¹éL£¶Ø“o·É·Êëbë8“{”ä•Pà屜«¼=ÒF¶ÙªØyÞ;×ßr+7‹´O¬Þ&KÁW®hÆKƒ¯$(ldb¦Ï‹5Ã;\a¸RÁ¯ŒšIÂ0­áw†dSá¿Z˜7UúÐ]wó#íxÔ†i3 Æú±´ða²oUã!yµŽ¸nijý9e„¸µ{Cc—„¸{ââ½@¨à÷2cL›³÷fÐÆEêñq!½¸!&®a$ŽŒ÷¶AÇ50Åv5ßͱñc¸nš®…*i±e9\Þ N‹­ïpJûJƒ£´T éfÄÌí‡ú´´QõscvÛlw¤¯zØQ«´”S9Ùt NÓ¢h*p˜îh’½¡ [¢Z°*Ÿì¬4 ¨¤´F©h†P ¬>µNkú³MÈŠ7g‘Up¯mj'h€ö!ÿBæ;—0xiJ—|#r—•KÙ½üX’~óÓ¸élÈãÀûx”É’ âóNÏìŽ=ÌË2¶]9”üX2›oª|eZÂàMÒ&Ì•9ÿSeÓu7ñ§rƒ©5dSöµ{Íegõ‡X”ÕßþX4«þÆà¼—Ór«¼¤Í‰2ø×'=Ÿ4ÊÄA\t:cG‚‹aá8÷´Z<ÒÄG4Û7Dšð¤*wËDš÷G";篅&¡&•úc›8&œm&Vg/Ò¢9jýÐH“⿚%ÐtDšU…R¨Eìq)ÆÇ¶fQ† óÇ1ÈÁ¤zìXY2ÈÉ4JöPÙ©sK£|jÛ|±Ý¢ö->ãüyy^Âi$btn>Y#½[A‚D»ö°Ì÷ç”Y8>óá–¹=qáˆãz?Ü2Ç#±ÌÈ–9ò›Îæo =`HÇ?#}±ß‚V„|ÿŒt_Xf”;À™7Ö¹UËšë²- :Ä ñ+ëÁBgÉ<' J¶T±ÔÕÄ~o¶H i#x´3ÏYˆÝû”ùß ô¥ ôýÑhV#Žzÿ¦zqÔž]ä-'Ý.m CÛûú*÷5Ðé4ÞL4¢}’@y¥Þ[½ÍêÎ{?c\‚Ý©ª}à‡« f1cbÖ—ž/,Õ^Ñî¡H›ÐÐټپ/7z ³“Wµt ´àFëö4»­ågrõŸ$ZFÒËëò^81ŠÕÖ:#8H‰L$iwÏ‹Â-uQ>FÒôÊÅ3üi?Ú5µßü›„JëcLHð€©éë: ~°àÝMF‹'¡öŒªM2“·¦#9Nsº1ÿYY± ¡J®à-ç¶Û*¡ !/%-NË^ÿu¶_~êY2©p —5SÃ];8`Õ®î#’H¬Ã¢ÆÏº&A]„Ëx;Y‚¾F¯ôð«è+¾{zfi“Ëg˜þuËR©äNZi™§:ƒ!ç\ —9YVe“ZkË“øçwåù»Ìƒ”Ík»m€À­¶ÃþP?g;p@ï%¼ihgß!÷²ŒÀZ’õ¦¹‘ûÆîíMÓ!oºk'ÌyÎÑÅþÕ<çåw‹iAHµ„çÌÑuuü×òœùÈÀñc-Ls0Åã„$v“Á²¦7%1Ñh/™ãá4]ƒ±¯Ê'¨-Âb‘KE¶¶Hæ4qI–Ü$]:yÉÀßÀK%Ä!³YÕU'±d£ û]ûäÃ=Ü;ÆIšQ}^Þñ=gVÃ){ÿ³Š«•f§ÌSœVDrÊè`e…ñ¦ð¢÷”¯;–@½wþl“¦˜¡~±9nz2É?c¬äOÊè5éÂW¥öe¿NßYµ ÀI?éá²YeÑ¿¦øžSý2à u@;ÕÓ4ÛÂ;3,}Qƒ¹GS’áú!ÒÊ,³«„n®šeƒë¨¯DU¾…«jày¼Ú°¦ji2¿} JÛ¦BHªê\“ÂN*ìêTW5¶Kz ~:0¤2i¦¬]ýmÖcèûmÏ0«¦Œç”˦ß3Z+ºÏZUVïH€»¬œl#8ÑÆ, fÄø`q`L¡kè4õâ›Gl%[ijŽÅúàB÷ 4®{Uù³_ؽ_±žô úÎK»=4?ãÁHÍ™×HªÇj©v’QšŒL³™lÙá„ÁÌÜÔÈ‚z칩KU²j~ýˆÔMäI#¦^}¬Ï ÔnDïf5uý˜R ñåIRü¸úØWíÄ~2%ˆDœvÕÕMQdN5*¥Â¢Ç]€êVÃ%Þ©q-eµ©d¬KÐþ3e€ Ø&ý– Îö̾O%îg͆º,³Èx÷€R®~Ó' hÌiÆ"¦a¶É÷7 gmrþ>8êÄ™~ЍÃxkŽWÙænëXá½b›¿ÞuÇŠ‰}p÷Þ±"Óh#CÊŒz²òуh‰í•zSmu¯R j‡}²åxf‹‡C&Qlîéæ"L1ä^30k¤Ð3ÈZ¬­üÅ1$ÝÏŒlúô‰¿,FZÿó}Ôû°V,zá«™©§¿’á«»åP OÄLË}T ? ëdæ£7Ö…öô¹¸e¸feÒ±×ñè¬k4¿?NkÔ̶T¿ý#£‡±Ýnßd(WÑ»é-€(…~Õ.ÞœõÉ­*𔯿›4·;˜^ˆ_!ðîÃYö„‡˜ZnØÓ¤BúMôÃYÝímؚ¨hu@]É颻ȫƒ×{„ÀöÇ©9uËÜ=4w'ƒÚáO ¬ÅQ{äljIŽÀ{?oÛî±aÜÖ‰ÇÏ ñ;JtìmñvT]'ÑPï×¼mÔY½7Sieažnj’Uó*5ðK†¶Pe=ëRvá}g^ÝÜòåxm³š¦{A?&Ñ)àG g‚–$;`K,¤ÿA±Чqïb 1¹› Ÿþ'ûHÒz«Oð«ƒë0ßÍ›Õ'U¸©ŽŸÏÊS²Ý`¹ï–9Ú+Q½¡´ÑO¼Š'Ú3þb)ç“?ƒ~ijyMÍ5 ¬ð«åG¨<õy„|i V,” )2³BÍ"•[Ã@ D㮆ú‚|ÿLzĤ9öMRj>ÆÃ0RTE¨HUª^!<"G¦âé” \L*ÂÜ»¤Ü­rÕ©|–¸W)ÿAÞ“ ,ëû¯£„o&á®i8ŸZÑþ‹âU279Wÿ1~àÙºÊ6Þm5˜á=Ψ¥„ؼéâ4; …øUÔ]½Jw%­&ÙÖZœhѽ^î`Uó·¨;¸‘Vû'.u’³p­õíëOð:Á¬¶"§Ìß4?ç°ßòQËq‡ïˆ/“l†ALÙxu²Y`Æâ_©ðZ9²°!쌬ì‹ìodÍú"¾ªÓ/µß ¥ä½ÙwÞxõɨ“fªÚ™õIl0b¹}ô46Ƹ_J2¡×Sk h1²o1·É0¿.ŠœÈï„ç’Åøêý-âbP¿.»çÿ²þTø óŸr„師|H_ݱì¸Yã/I”©¯ïï¥/ìrŸÚE>{˜$Ž;¥O1÷„¥ÚÍ»GaB6ÚHökRÂa½¯òÐpÌþŒ? ø¥øeêçÍ|†ãQ.Çè¯.õAá—ëôÍwúe`4ºãêsø`ð‹L‹w…þ|—B¿ñ§À0£ªò¬tFÈ•ÙÔo‘b–‘0×>Î& ùppÚ/Ítâ~&/[¯7ÝäBÁù0e<©…Á›Å/~<5Pd¶Y¦a€0>¦g°(|Q}d²NP9Å2½¢B­ë²µ¼)ÝÛÚm3¿Ç$µa›zR3ùšbRp}8Ö¦I@Re]yi1.:Ži[½“ ¢1H]m4›Øž(¼ mpÜál}ìÐWQÖbƭеQ;ä³ç—Å·«T'?µltøt¦~Þnÿ4ÝU·±‰ïŽ'#ð«+Vt‚qs=ñ;yáº;2á¸v0³HˆžfXî&ß—†TF•ê¤wŒG®]]/'Š~müš" 9 jªÝJ@á/glQz¯âƒ cØHñ]}là+}÷œŒ¿ùV¹2>FÐ=bEF¢mj¦txI¥RØÁU' ªæ=Êej„£‘`äœÄ÷l2*çÙ&¼ŒI!à‘« ½¬xUÈË[ilé ÈØ~*#.åTÍ$O×ssÛã‹„Áï-bl“ƒcˆ¶„&¢Mº“î $Dz™Z4õzBÔ†NƒMÏÏ'ãá(­qF„M’åÁXç'jÙ£’µ²…Û»š‘Í©l‰V6£@ÿPnFcV vF-:RG’ ÆÛ?8 (уlùþåàÿçªiqendstream endobj 757 0 obj 6074 endobj 761 0 obj <> stream xœí]msÝ6vîìGýŠû­º™\šx%±“ÉLóÖu»Ûz7nw;›Œ,ɲɲ-)¶;ùûƒ{†yyM)ýÐÉ$b@Ä9xÎ+ppßnêJljü'ü=½>zò'iëÍÅíQ½ùgø÷âèí‘ðlŸÓëÍWÏá1cõÆUÎJøûüåQ]µ¦{lãd%ÛZlQW5ܼ>úëñ›­®ZeŒ>~¯ÎýtîêV„»ØvÛNã½qÛèê&Þ}·ÝY+*ÑðïØí´C¼:‰w¯c›‰W?Æ»wÙ°š†þ·ð]ÝTµÇ?ünÿíù¿I½Ù ¹y~œøk|úEìô2¶½ŽWgñî ­;«$ü:þ"6^úc³ì#)㿌më)ü<Ð¥2º„¨ÚÆ5›ç¿?zþ'í®@ÚuÆõt’ïÙ»Ò^ÇWî 'ÏA]7F2 Ðí8{·ýÅÝ¢­lëmÉlßôMWýÅå°ûý01‡ô.h*/û¦³™ÁƒÈ:Ÿ49œ/Ÿ ¼"l\eh«7 ^eCM劈¼ ‚Ù3=×@Õ‹l|Ðôn† ˆÜZÑ ^gD@Ó‡!ß§S¹lBSœÀ÷$!_ Ÿ¿O?}ˆ"Íe:‹4O4wo³A¤2™kÂtUÆ ¼ûŠ)Þ€/ņðE|0§¾$±@#?Šýmzsoq°K±Y?ËH…¦»‰ïÄ{¹§?Ág|(Nëípì8äÆTJÛ¡ŠEc:ÙÓ”ätàÝŸbQr[JnQS ¥$Ôß«ŒV¼ûßC¾nw®RÒiF•(¼×þ®0 ¯.ÒŻȟÖUFJšÒûlÈœÅ9±|JIwÝ¥ÃðcLÙM/‡Ó}3è3waRÅé.Àê–èŽoüÏç^Õ&_‚Så=‡szðv’A €v}/„|Œ|~S#ž33½{“‘>¦Nr㑺b“ᄀ¹‹¼Œ²ú{5²(rš [¼Û‹›‘% qC3—Ìs‹8ϹɵTîz”mÀUÚUYët8ѶQäÐdmL§x [µ=†2hø[»¨cRt\Çy ùñïæ&&ümÌ·%n|Œwï ïÞ†™S YÚüݲnÏLÇ@z¼›æ–ú oSm”|1kJ0qT°vt/ÀÔ|‚[Ñ; ìC<[ãzd\ Æ3ᇘH¡¯‚Ž!k’󓟺–ÓvŠôÄuánI{GEØf'3úщù˜}5µõ!†XÃ1º5—cÊîÉ»Á° ªõ&ý`BÎ-±ûûFJW¦ &#$~R8¡Èm8ë­l¬ ΊˆÈÏâkE7PH-aæs¸†1àJÑLɬ¥ Âiµ§z=üâ5õº³µ®43Ì£L Ëhå ½WO§¼[m+çtþõˆCT*ñ™Â‚ŽYG;pÁà ú†&2l žÒ*rÁN ï’Eºžz¡lÀU¡g2¼Ã£nh&^…™féUßôãð=†‹»Œú^}t“µªÔ?µïƒùíó£?½Ýhc»\ønmšã«1óÞ˜CÿêéÑ“§ØÜ½»??zòç8zò;üÏWϾ†?O¿ÙüÃÑ·O7ëvä=üVC?èn@? qõ¢~FRý²IRý"äù[½10+Êv)þßNbòf+àʵ…A£4Î:@z }héPî Úâ,†'9{91}¤âÁ©‘ºNÈùf»««¦®[ëU•@Sï07¥*cÐ…9¥ÆwÝ¥Um ¦Pt\P¢Ö VÅïw\pB˜Ž øèÌálA™–ÿ÷:Rø÷×é¨$@Z¸ª^rãke(C %;ÐuŠ Çò%!l‹Á#C‰bô~:(å2`ñÀEÝx^³Á§«Sh³[9½:5F‡j[Ô€B‡ɳ dL)O‘/”áÕ—ýÝYݵ@‡Œê.FÁSÒ7϶;©ÚÊ5è$D…uFªç,êâwôV®ðlm} ( ¥%Sàð’ÔB, ûÆsÒ‡w¤ïÞo…S¤o÷Ÿü {×U£Ð;ˆ­Ã56ô©ê]‹þþ%5öU ÖßgÚöŠÆÄÞ:ÝŠºRmãÀs2Ú´‚Žœ¬jÀóíNUÒa&æõtŽƒ’ÀÍYÊȹmªÆIèô„ï‹C#!A•¶®áFiÑà¤7:Ì„2åïN€°³œÕ7ø–…/ þÝ×Ûn1ºFP‡¸£U·Ö[9mL3k„–ãyDS«º^Çg:¤£ž4”ž^åƒw‚ZåKLGq­™ªüëØvž9Ãiª_*7r6³Õe+ŒOø`Ô¦Ýî»ÝO÷!C£î[£Sºñóûèu1)áJ¬¿b¢ÏýÑ 8Žk&×Á˵Š÷OÜÇ+öþ^zDÕ ¿¦§ÔjæI5âr…蕈=þ;½¯èý:~ôïôÑÏqP¢jňÆí•„æŒ+ŒW¯ée2 ®qØ¢jŒÑ~l`‚^ëZ!ãp›Ö¥:Y:¯þLº+¨?¦3 j䊖õú¡HÙ.;uë£þð¥tye@=r‰óÝ4z~ÖZú´èÒT&“*Aüqmù˜l+ƒ™É7ÔÓ»H7žJwÈ%ì•¡†9WÔúÇUÃüá”JÓbxNøgüþØÓ+8E‡j¡CS›f åŽ"i0e£Ñªz„8E Ì·ó‘Á¸*2J‚öû ¤f¦ª”l/m"ûWZÆBc òB»fi ¸´ÖBòû'<²]×B#¡¥˜Ø ÍÚ$üõœ€±h¯Ø‚) Ôj[ôWØS ð—0ÙÄëAÒtë Ò"ucÀ¸LŒâÏBXjå”8˜x?•0/† ‚0I³e1:­VÝ(b†žÐð’"Ü97¨ˆ&fï®x„&ëÆoŒ–põÛx›Íš4ÆÒ¼Iå¼}}³{ðoŒŸ'‰Ê:îc‘®ªÁ{ âqs~‡Ñÿ€*9Ô+šTnÏ?zt>g ]·šq'ÇmYšpíI|R¢8ʈm›‡öÀ¼˜X€{БqWb¾›—/cÝMù ÐW£`茂ï¶BU®1˜™ ®¥Ác¯ëRæðo"rYæ#·K†ùD†…7”À ýÕ9·Ðñõ«¢ /FD¬ƒ³º.9ç^YÕÛý>²-d ‚)²µéä­©µ”Käiù„I±‹{*K¸ÎÝŒèSöCqÙù$KR±-€³Ø_mÜ3Øgãþì ö—OØöµ^ÜS–æ Ø×¿Tå±~*_+L6ZœM G¿ÚhgO£ý®„ÞâºúW@„‘­Õ! Â=¹ßÀ;š!bÒœ0-̸úжI‚4Éýí| ¡u²L…¢§\›øà‰¤`þÓø|/)øšÔ‰Y^èê(À¤%…t=²=–4,¼'GÎXú²—š´Šk1=­“1·[‹y“>Ðf…c.ä7¨¡DeZÊéñõ©©ñŽiœš n<-*Ñ’zÁchêb9ÚÇÔ…¬Å:¦R@´»J\1£.„¨¤ÎLe¾µ€oÚú°·Ã¸3*„Qð{JVCJ¨ ¬,R/åžòÕ«¶Y¶œ}c˜¬›åûoŠ˜¬ùÐkŸˆIàŽÛÏhVËmØñnx/+Ålx ؇}½½ÕÈœ.'s=àÊÀeÀ<)f˜÷wYŒùày9WGð¬œ9|÷wÉ £¥{ÃskãÆ›÷:6+Æ{ïó€}Îq[¦ð2šþ¼ÕàëK£ËØ¥õº.¥ äÚñv»kŽèz|¹Ò7‚wÒÊ~é×¥|^¸J€_ùÖül+0ZÑ?Õ(ð›á§ò5l¶ÃgìcaƒN¡p×Åêæ }ÇQk}B$ÿu€’¨¾í´‰­Ë+JÌó9.cR‰‡y|ʦä(•Mýà;l¼TZÏY©”ýEïÕ}“ÚÓ¤¬GÓŒT2š>Y*ý9iæ¤R{"]yg 3'>ÙÐÔæ@rÇÀ ÁÈâÕþ"XMûà+ë¬Úŵ¯Ÿ‡`¨`Ÿ…æjÌ@“Q°4ÿsk° ]‹tWLa‚|¡Y”-gÈÊ´]ÜSeÚ¸ÇÈ›âÒ1·Cg$K¥&u\—û8* îV£iwŒ¦ïgËNpaÕuÌ\g© ïœË çÛ{çâa¢Æ¸:^…2ºx•2‘ø}PýËÉèÌ,±>Wö >iØ¿KýÏÕÿ`­Á¾ªÀƒ [>‚v¤þ:©ŠX5:)ÖYi‚Ž––È:g.í:˜¬Ü‰œâj¤Ì‘‘r É?œ…Ìr¢Æ S»ÃhÈÔmû(qGí«+ØnÀ²!Ý[Q­6î|°q³ò¡?ÅŒÿS2™ 6h§FÿZÚi9F õâe‚"Ô #óQƒÊE0.׃Ȁ ªoRçm¨a= ¦AÇ)èªÖ-GÛó—n•ô‹ÝµPEýÄ×ÕúV5¿B`æB1)vp•S·ÓؾӸ¼‘%V©ÿ=¨£B —¬?´G –T6¦Ò|w¾ç‡³Ð·a¥ç5ÌÖ ×QÕ˜·_B*GFÙ’s<Ãù”Ÿvfkµw}Ùz³=±cžq¤¼”S®ºKCK Òº°â–ò|Y(ßHó"_£êH‚N­µÊv.+œRý0[‚Êiò x 0kœfo±Ø››ðS)c˜qM»Ma#Rã=us\,Ž¥M%t{ìn;À UøýñÍ÷¾:B¦E¿]q­F) Õe«TÿúJæ¤0:ªë¶±wŸ»Øy¹-2ÂÊ+€lJ$Ù‘ò¶`ÊæñÊ,Ü^"\Õ˜ ¸•féÂò¸²ÊA,žk‹¹œ´xnÀ9ߊ£Õ ô˜wFÉ1Ày¯÷¯œ®„”2G°’m%2´©Î ¨Äg÷¯–;@§Ž˜tãÖ)?¨£ž4ƒ+ñÑ;0‹wä wª¹onüÆ®t·´˜}ç|¦ºyðPBÔ>3ÀGü¾`öóÓ¯Óšô÷¥ãðÌèf4º«Mé” ÀØSUö”ñP龜Jñú»¯c¨ý $cÌ|qPy5ÔÀ&Þ  )T¾ÃK¢5v,Î9K £_*oÕxÙ F*š=«Ø'Í¡jp_t®umpßô¸9TméMŸOXÜ }¹Fn•ëö)SågN°~F‹þÜ]t»™+4g•H»ðJ4ßkØFÀ©çGj•6~cÛ¨,VîLØF¥D%Æ«ãž?#ÍH‘øBÓèÉQržvH£¬¡KUl-[TV_?(µï9&ÈÕ ðì ·ìR%V[aÍžm92ñ‰ý¢x([á¶éjšiðªÈÑäí¾5 NÏ) ´Š‚;A7¹!˜eœß°¾ž6óÐ…EÆ£>èȦ|ÄÕD¥)=µ?ÆÈ¨X*œ â£Æ6ж®ÿÇfݸGQõÞ |¸«HZ¬HŠ|¬ƒ©hCŠÃïânó¯c>0aZ€J³PŽk2oçÆ*Ϊ7جÂÃV†zm4²ò';¤gã%[¥v¡Ë¨÷ŠŒ*ÇEF¦öKàf¶6 `nú¢a£&… T”S—™úx ðQ­óˆ—µ­4Pʤx³–èl©D:.Š2SdAŠêBP÷ß³cã;l›¡¦\kº€ü7^AÝŸÍa²r„aã]f&«í,‰ë#~pëò­ü¸Ú5‚+ûbÈÞa¥ªˆÀ‹þ‘ù‘¾H`Ù+^Öw[ÐÀ-تü(ÿÁÑ“\fݬ´m·œ_91 «aߣF¼èö»gúhÜj† ›^.-sL‹*0ÍíôN(„§Âµ2#î’ð¥&͵—Úçv”÷º »}Œ ûlDOöe¿ ç 5LMÞsŒ•Ê·/Šj>õ¾'Â÷."2‡GDå¸[¸•ÎÍ9¨£ž8LGÄÓn §Ç8íF€7×oh˲ãÓ·±í¾,NkžÉï 'þÀš.¿ÏI›ÿ‰§plܲŸx»ù!Ì߇¨~š¤–Šý6Þmѧ±mñÙttxuId:TõI„õ`5‘Dàœÿ–GÒºeû™û ù!¤Ô_¥.ù‘wãçàåš>9ì0øg»5ÅûlL½™s.}´74,õ“èÞ^#¿É(ͽ½ò™|™· Tº‚Ú¸ÛBÕ ªÍü/f]yuç úç&áøŸ¶ Ô/ J~ø¿æývC/?Ú¹ÙOJÆtÃêPtb˜¥È}—®#&d -ϳ¸(ƒÁœ¦ ÷úpMì›û™>ÁÐo È“Ò5þ¨Õ"´û·b|}èjšèåa‡ØÓSh§(ÄßðãoYtV>€¥¼ÆtB9¤«ŸŠ¤üujéÏÏw!Lƒ5=¨4¥GÖÆNiÉ;ßE²#bÏR]ÐpI¹{>ˆP}§Ì!‘¨EŽHôŠØüMùð蔃âk­O3ÏìçÑÜ]É}C;—Ö=é3[<ÌPTð.>4Ozе ÅfYÁxPÞSº,õPÜ(+ܰå ÉY†) ©Â¹Í:Ç•]s‚T9«Àéí6 þü,ÚW€ãÄ8>z6œÖô!¡ÿ Ü3$C¾"(ĈÑË‚úÜuh9¨?# ÏSØÏ§ÈÑOï¿Ê‡Ò³L"ò gî4ªbö/Ëz9ú–óB ú?w²£$§Õ®7Mé™/‹9 ,'CÎù×> stream xœÍ]io&Çqœoüü&20GÓ÷ `°lÃQ`²½A>ØþÀc—»=HÉô3„üÞTõYÝS=ï±/©@€øî=}TW=uö‡ãqÇ#þÿ^Þ}ùiÇãëOGð¿£ÇÚXÿÀñ™¦cçæa‚?b4Ã8áã_}}ôå×:~øøøúèËÿ>G_þ;þï«o~ ¾þÝñ¿ýþëã?cCðºogRn°ÐÒ4Xß’ô.-Ç8úp$B§âŸËÛã¯^AÏÕÇó0[ _½9‡É„ÇŽ'}ìàKxýöèo'—§ÐeŒ>yëéIœ¼Î×.óµoý/hï¯þãè÷¯Žp ŠÌ‡gç'd”bÇ ÙyB¨a¬‡ñ©é<¼E®•_ïòÝû|í.ýê MO3éE†fä l5´·Lçÿ'_;Ï¿.óÝo›7Ê ñî53܆$¥‚?zšìXZAG,âp¥«±þúfàÙF}f€ž& zX«&¢ÿ©fc¹]Ï®RÀ»fJØ„H¯¸Í–º’?Š÷¡SJ‹Á(Û÷ïW›U©i˜¥¡4Nz ÛŽ†Òør‚y…+}ò¿ø]å‰â|ÑE;©åÞUBÒ) o]”.xrv£®wwiàmy”|à*Ò¢´N¤Xg{…¾kòóÍœ Ry.Ï ’VVQ{²4ru²dœwù"!Ųþì;ßžZ˜dãå(´®”ä›×‹ŽW )•–/=`Sž KKõ;žÙ’Ýñ!ß~\Ì"Þ/Ÿ$zÏ®b»0P7šŠ7=Tü¦~Ð0¹,ë tJ®¾;=m€}Â,NIE9gRÛaEC0Òpí¦-ƒõoÊLp…H[Ò÷óWn/Ä݇øs@Ž< ÀtO¾.C}“2 Ïdz^Í?lÑÁYAW¥Ç†¼d¡39ÿ™u”:­}ê4 èecÅàp5aaÔ( µT¼î#~U<áÎ⣞°ªf‹þ«RwÇ-ŠIÚÿÈòz¹Hh­\¼)ó³‰ãÕÞ/–žM×b,îeOªð e©>%Ñ'=…í cÖtÑÉBT‡òKlМ‘yêš òrvà‚ŽÙ<ëA¢¦1ƒ®&e$Ë^€gæ6]Êݤïsð)½¦´£Ï„kSÝ…/A2…G²$)ôýž2äFÏh8"á¿åúŠ.(Qs¯÷ ivMTE’÷ L}Л¸;a d«½cw][@üÌM§£DaT²h9=óò¼ƒ^¹¢’†‘)87Ê ÊØ>ˆQ°)%• ë»ÂË/”³ô‰·/¤‚ gUÆ7§ðˆt•À  XRgÕ§éyPÎòø6üÙRJ½¨ÚÍÂ}s aB±@Y?ÄaÖ°™úÖ/³¿õ‹7—ôìðçi( N¡®˜¬Í¦ã¹m™“>¶ÂeÛÞc¶*·ÆZ¸ÖŸóì°—VLÏoyåÐô¸ôó![OÏ›kµ]ö’±­V¦dÐáýô¿Ä€àS³¬ô&wùž±ƒ—½Ïw?®š’6 w’Ó‹ wò *¿~e…~hh/C›ŽA<ìšd?ܶY1ˆÓ!ü‘ÝIO••…S’Xr‰‡ipÂ3¯ÇJTìòر z> ªArÙxnǶț† ¦!Œ5.±¯‹!b+̃K+æFåö–øìE6FÄM&Â[Þ(æWÆšŽz]Y/ êiÌ^x›LÁ+B_gˆ4fˆt‡eEÓ S€G]X°N66¶•1Ò8±Æ B97t^q2'@.°0°üj×qcÍxg+g5gžàÉÕbb¬5`eà_ÆÐ·X»üÅ(é"€ ë€/8³?vÄxy_…¤ .µ¡ Ææ×Uh@LË ÛíЋRÎ@ŽVƒ´ÚB3OMؾu@ð–ëc QP%ƒâ ,ý¿dùÄ»bª'c½kÓ(Óe¥l†& ¼ýÇDX[\á,KsKmß葇„™aÉ_N{ r L7*äLgˆDÚjßôXZV†©ˆ¥a±tœfÁÉC`েå{5Äbi¤ˆŸKÀP²²Q!–nÃðÚFX6j¿(Т{n£(¶~¶Iç9X]†ñ±h+!'L¿È0˜¦Ã¸ib0j¸|½ý0¬ôJ΋ Dël«a¼g†Ñ†ýÔq5EOØ9n“¬ g:®oÐÓ €Ô?ßÂ^ûº–>ø€Vè]ªd7i ãóø¥'m£KE‰Ê€·YäÀGå`M˽ŽÀÕ¾£K[þÓf·j}UÿV39•{ 6ùóJýÃé%»?¥èIÓÕÉ„ÁêÝÀvðÞû²± [Áî§r„†j¯ÒEVª×ehe±x6ëÉ©´Ôƒkv¸yôþ°CgÿL-t˜G&=è Æqf¡=Í0yÎm´BÏŽéh¸]ýÛŸ*’gîò$¥þ5¼Í8È“S~É pžRozžÔBrÕÔ¥My¿S$?\„ ¤: å.Mç¼T‡›8ÖXZÌîQi ßä´62¼þĬÕXw[,¸‡(è@8£*÷i( ÎÇ0F$hÐ#òüHPd9‡D‚°rÏo` HtžÁzÄÀÚÆïâÝ×ùÚmþu‘ïÞ4í­ ÜLaÅ^bàVbÜx;HìüÓ2 ¹Äôr» /ëƒQÞ¼"#øaÛ¬[ö‹,ƒwÛq$ ·s$WÃЈ,ëZœF@oÝèLÂÛøªF,F6­ÄÔlj¥a…A•ˆýE=´ ”¢Å©4'¿È‘4—8éÝ_oY …¶§qÌÜ‹º!âüb±2%ÈCµ$•Œæ¥N´J@â.ê¢õ ú=Ú¿ÁH‡€ïE§_Œ7:zBû5ìºâ ¿¨—,­¬ÅÊÕñ‰/í+=¸qgÇ͈ñ òa•‰dÖƒg7û󶎘—óÏØPš™©íHÎbGî^ˆA¿ã¾Íà ¡n熅”ÏmèŠnXÒá¹› xd ÄÕ–^ØO4•ñ\ä?1&•לYDrò+ê´Ð¾[§>ýzÍDH1cˆƒÑâ†(ñÇÂ7y³É»šb°kOõC5ÚAW&ÂÂZý2ÄËGÚÚêc¨ÊKO¬xj|£#H'¹+à!Qœ>ìQ¯8W±[]Ù΀eÕØác^Ç6‰#†ûžÇy×Ôò‚…Õ<ñÁÂw)Ž6‹N4‚…|åôÉ7AÌÅgt°`÷fê%êùwXq¢+# óA2Y/ö]cUì‹}ïŠÕ­àÇÄ~?•DiaÌ×åâ”/šüË•Û6_ü)ÊúÑT)P"?Õ¨§“¯ª(b…–,Œ;–èÊufc.Y60ïDT‡[Ñ8h¦Qc cyà§ðš™çŽåt‘ãý‡i6kç]”wè8‘#¡²»â脸;Y¡Ÿ³Ô~¦I¿°ˆTM€ØC9­JÐâ¾å"I)ú¡ Ž{A‚|¬ã 7Ec¨f¿:Ù:ãšÎ)Y–‹š’jz §S /Æúäiö!‚ÞÍ‘C4xÃÞ?Y>y¶&ÉÍÓfj]ŒÌS Ù…ªütí€ýOQ^›]:ü±˜¥´3ªøVc7¨âÄoõ?"ìîuŸ:4áf†?ÈQvr8ID&½J ]|B5lOƒ–޶eº7½.¶_»cjä³vµi¸ÈåU«É‹µ"Hr¸O}Ù(?þ%"RŠìºae×uÊÈULPS«§§qõɘánRoµéƒDö¼b³V€˜L“9W©íUêÀY“ šÌlo“Sî’eZMÚK_« x×ìwyuPÛs~¦†X½Z_ &Acî´ýlÅR[@“»{_Å’öøù4ËPÐ,逸*× …öQÑ(K0oïm£=vìϵöx8Š[Ñé`wTqe³wÓÖ1ÐʽÕG_`n’BS®®º&ÆèÅÝdLXhÜåbc5+L°ØÏz¦ï솷­*̱U¥G`ÞÖú-: o-á¡'y»Ü+ù†ÝÏ;„gF™Ž ¼Þ!ð¾b3ÁþàË•//úsëmӿބWj¦ö"êvÝPWÛF£—Ýv)DѦ´M8ZôÖ.ÒÂy3b4^¤Œ^Þ¼H&o6v§²Æ²ÄGa‹Øñ]”è=`G÷¥ïÓPœAè¬EÓôÜj꤫œEÔ¢‹vž¯•§›MQå±#´ý쉾±ãr=Mô–¹[‚ž*UÚ®¶×X/Mþ#¯ÏÌN¤M‘yy¢[÷*^[wÍ~^·ò8ÿÆä¬^7©xÛ ºëà$k5MÏOóŒÄ€ÖáDï›Î—9 uT꜂3¡ —%úU^Ž2%³|Û !½t•ƒ4¦ à{ló5zdÙr0~±f!Û¬!d•Ï_äˆblxdEÁ ]‰´øû0NÖ« EEá}1DJߤj€ö°æ”÷¡ôoa9ñˆ}iOi|z 6}tƒ“Ôâз¾Kh#§Á®ØY–Ú¸xÕÕ”ç`³&À’ôkC${Îx°šõŸ/j ¦Bn±bÚÉàl€^‡±:`qßޱõöß„û­âj¼îsÏQ#¯eóÅåX•º±8úª6¶ƒü Ï­ÆÜwšvÂL†¾ ¿;ŽB¼2u¥GŒT+6´fHmkk¦à55Û%”ê×'ò˜Ìg|6ÄÿˆÖ`ã ?™e ¾¾šï7‰FBÕ‹"!rÒÛ*7 i胯 i¾xÃAÙ tXŸ¬co6³OUá,&$í?³lŒ+®+&-ÔLµtüzÁhSA«XR¢†&7åvç2ž¿=·Ÿ„FEåèxS,ùDÎæ±µ²D•fëS-mÁxqC^×®Á7U¬@èS]¹VE•.MóŠÐÛÉ\eaã´aÙXm3Æÿ´MYøÇl·‹¤¡v½è: ÌÑÒ×OÜd4%F%2{‹ø­&žÃ›uô\».i…ñ¸™¡#äÏ×QËU#æ9kŠN)ÕÛ’lj8{-\]|­»Óc¸Ó!“v ñD Lv7Böp›õ¹ì:DÖÖ&6`1MžV kMøÉ¦êxl˜"«\ëTš]ì#Om¤ð6Ù×5i{˼Rë\4Z}@¦™~樼Öý²“Ï$­ŸYÛe™^ºÿ ,ÓW+‘[Æz÷šÿp»‡±ìƒŒGøØ ° ò(},9&òm8fX«zsÍn ÞxZ‹H¶äë”-ž÷ð K á3Þ¦-,:ß8GÌçT ´½³¸j´Ûpi9ðªà¦T*~ûÄ@N,΢¸¢°Å…S‰Lµ¹D'o‡/þ\K¾ñ2¥ %jmªiõq¹¨[ÜsÇÕP×kK“õ6¾ÖønºæWÍÑ/,³îõ-t°å=N™³–r$¾]qÙà ššI»^ où‡ò_Îücao.Ÿ¼ìôFŠ|\ËnÅÞ¹W§¹N?¯òÜ)ÈÚ´2„€Õ€\bý;Œ­Úg~÷ã•@ñ3¢$7#ɈOÈk„ºŸMÍ- k—O s }`iß:¾w=€×f¥‡ Þ«!öÈuPAÜ ‚#AjÉV+.±ˆ÷ŒV\tÍËæÚ"ö73þVá¼lžÇkÿ¯µè ÀQ¥¡~޽m¿ËŒ«lLk…?§±LN©ŽÝF/oPJ–lýÐõÃQåšæ]hòŠ·¯´ùìÓCèÝþ Ð^]âôn ó줫u˜tèÞšwô´"Œb&É6®&<}¶‰I¡gläF5Ò ê3 bM®(·Ð£¼§Íz îïÆ\æ;ÖçÊûZ1yµ’^žš=¼^zUãÞ—UÎPƒÅvg¿à‘÷“XqëÄr${+ç€EÛ˜žr®hÅ®c&«©ÙwKö‚GjÝ7»¨ð©G5¨Ù[BY—ݲ¹ƒ¿jšö×Ð|Áj›4týZð*zåŒf}€ìl‹¾JÌ=€^n ûª?_/—^ÞSrG½è; ‰\ÐV, æãFl ª®N®åäì2^ÃëXÚñ‘óW,!“®ciiº¤•"­÷Æs žÂÄ.x*Ok¯ÏÜä÷Wnö‡QÃâ磢ʈñXÒlµÌ©àBg™›‹h5Tž.íÏŒ÷Ai¶QÿbtßNx§ LÐ3éôªRmë4§a/Ëøøòí«NS•%á1æ÷§ ŠŽºENyY7Ögfïa¼à­|ÂØù µÚ÷jˆ5BKfÇxœ}Ì…˜oÄßﲉ«Mçkªdç^ ¸o}Â<û™…ðDÇsÞŒ¢*dÞ/©ç ¼HCI=ÒãËJ‰@æ”™“|ŒËfûÞáÈhžG†°ÛI-X&ÕíΑué"zG ¤…HÖ¹)”lr9’q³·“ éx²~ðëíð«Íšö:ÄovÑúÅš aÏ}EájèUšøcÖ”ÉËÁ¿‹¤¢Ä•ÔÙ^´¢Ý™rhks5©žNût}•I…a dåLÈ,bÔ­õ/ÅÑò¹ý,àoz™aõÄL*c³'IKÏÉ©±fû“±Ÿ7ÀÛVBœK×ô–åŽ!/Û¸\c5¿C  /ÃÌŽ2DVBq}Hž:—&h¤%úëÞt¿i6äûð¡2Ôp>–”Ý€ŽÅMÕ <»}𝧵SÄ[’ÎBO2Õþå4êØfÖ1’KmŸ"g7ÒûXï°XT«ŒñÍ$qòØB9méœ?j«†Â~ dï,SŠº¶H«’Ë·ÍWÁìrEë°¾æGÔ¦)Õæ¸x’¯¶Äþ9.ÉÊœ‚òd/å¶ñßãÈÛSsŠÕyÎa49®qoO‰?fqIæ[¯%k‡ÛR}7iÔX]dªÎŸzþÓmó›;$­ü`žbP¨íV˜j×^ŸŠ46kÚ«9¹ùPNÿ¾î•x!?—GláÏöüÍt™ñ4æ<Õ&¹·±IT!Ó‘§óWJ´-SºFYÊŸï[²f¸*»;4Éd[5gÑ!+_ئÃs«j1Ñ~µ+øòEG·âº±}k”_ߦRƆ}Ä~àZ_xÁÂ"lï˜(jø³Î] ɤ “=á½M)çXµy7 h¨N Ѱíý6›>7º‰¬'DÉÛÄâ‰,Àظïrœx©¹U„úï‹Û©˜Zÿë2° [fÀ‡K¨Öhºä[$(¯|jíŒã†˜eÒI¾x°¡X+O|®ƒ }æçLCÖ*“¨?sž©$l¢Ûp0×[Iè±÷1Ñ w–J]Cȳëåâ>vöH¢Û²w3´SSœ…]ÜæÒeèe†¼öpKʪ7|ñæK_ã+L‹¦×mŽ{TxS¡“‡19îÓN}Tv´8:©_àÄYÞúDƒd^¼iL_ÆŸøš®½e ^\ýQ«ŸýDìX~”F·W<Ù\ åGÆÙ¬J²àlYV xÕh–˜®ñ¨NXmË|¬oƒ`#r&WËv%JØX¢B„¤›ÖK‘ rÑÌ Gð¶tå‘`7KGØ ò±1“¾t^ô2”¬Võ>&eÝ'§±EØLµ¯éSé˜kZN(q…:…xê#R‘Çê8è A¢ÁJ5Æ ÒõÉrŠ*¢-U÷ÙuåP¼Ît)ß,Ä*å"9­n!–³×êa%uä_WÂC)±h>!¥åqy©ÞfoŽ+¡K°ÄÂý÷%„²‰ÌŒ‰ü[HBl•ÿ~TKâDÓ.È)„ÎÄ^Áƒ~ݬH 0‚1bÍ—å.!=ÈÇb„ï× ¶F ¯øo:8gQÎã…Y/ñ&ÃB•eNËDv¬#Ÿ ˆÌÞ‚¨Sià@j÷vvŒÈ+g{ NÌsôæ”CJbLž¹?ý(Þ¾endstream endobj 767 0 obj 8045 endobj 773 0 obj <> stream xœí\ëo·/Úoú+®ŸrWXëå› ‚Mê¶.š·ƒ|H‚À–äbIŽ,5Ñÿ‘?¸3\>†\òtw¾3œ -ö¸Üápæ7ÏåO‹q`‹ÿ OÎîÉõ¸xöúh\ü þ=;úéˆù!‹ðçä|ñÑ#?Œ/¸Œ5lñèéÑ4[X>ð…ù ξ]ÊÕ1¬sÒ~ÿè?þ13 ntþ1ãÔÀôÈ`ü)ŒÿëJL•éøàS~~6háìâ¸ýéꆡÝò³•ƒÔÊ-áM9*æ–ð’igüÛ<:úâè§…”ÂÀk‘Þc9Ø…•l-=¥™ðÑãû?Y\_ÝœÝÿfÁŽîÿÿ÷Ñç߇ÿXüéèÁÃ…Ÿ ÷óp 6Ì£³ßjž.‹Ù Ns-)‹Ý¸ÐÖ!©žÃW° ®ðà),W»k½¼X§,0^,/á.l °/ãÝWùòz¢•âlù"_’±a2k–¯a.éa–qcµVL/¯<zË3øÙØljA)'%}ÏÙôˆ€Ë“ü4yåŸWlpÜYN‡žâœ#ÈÆõ…MÄ¡pàÛý¢Cš¦×?K¿Xq5ŒÂÈåÿVDAÀÉäar#PlÄÀPjùñJ ¸ï–Ÿãï r£Š 9ÉË_Ö¬£a°:qa[Þ®”v©4ƒS<°Û|žæ|œiºÆ¡rY1'rÞ* Ë´'H¬?]¡¬;PÇIOе°ÀC3Ç6òʛ折ÆóºÌ±f`’¿ s¤Õ˦7z\$qmçb¿/š/¸©’Œ|ù$%bFf8M— ĘÁA ‰Z= ü{0­–°~€¬Bµ¯ môJ ¼&¼x•/×)qä[äà´‚ãú…ˆ8f…#›¤'HǨd>‚:œe F •z°£^þ¼:@@-Š·âžçÁFÁ]ã Åò±Œ î êi÷m°×B4ÞëX©¨€MìjhÎ(Ø®šóƒq…ùoˆ©–èÙIJßË<éË Ä6¡?Lõ4ðË>˜€n‚Œ 7[ âÑFZ°¸,ÂMN8@ 1 9Œ·I¾i½2Hž6¨JjÔ©%VˆÙ»™âžw  w{Ò#[úoøBK‰ÔzÕÿ*™Âël߯&¡º÷8‹òù =-ÆFñQbù5QÈk”Px&Lnš6ÊÉ,û«gùç›tóªIÍu²Õ=Å Ïg¿p0N<"²{Y¨óÏ]œšð¿Ó«l,gU9ÉZõ#q„’~eÌ{–5š`€¿¯ÒÖ6:ÉoŠNG²?s!P,djòµÆûç‚bfôÏÈ Ói'üÑ /~žµð#zU°¾'µ×Uâ y(úžš>ÔdJv$:žF& ]A¥Àï{r%Óüþže¯&Ùlj‚uÑ`šÛð{ÄY ê…iµµ[ùXí±qcË'µdÆ-%’¬2\JÙàÇ^4'Ëûä}— ÇŒORp™áÍÄÀ±aÙñw¤[òAI·V“<ë]šŽÄ Œ¬Ù‹:~ ^û'… ‘². lŠ‘"ãèÅ);RN†å@©oq;^ù+´öÓ¯Ò²ð+Þ»L÷NÒU~âuº—¯.Ó¯°X­ÙÀ xM~.'Ä«Çé×ótO¥«Ò¯7éÞ©¿2†Pÿ>¼Wˆ¡øòÛøëuúõE¼u/Î*Ú óû玵àp-–Ä{iüÍl®'Õ¢àÖU˜B.o<‰·Òo¦ß¾·î¥Òz^¤QÏJ² â&ʆ'@Ù^•*®Ó)n+žûeÔ¼yé/˜÷ÊëUDÚ©—¦ÐõÏΕðœ+¥¹À¿;¥^apVqvX' ^c˜s ¥'…ú õÙ8`ÜpÚ:¾EÙraqĔK9ø’8ĵàtÒyÜ3ãh5+Cœ*â1®WɃ¸Îf¿–?°Å %Ä®œèÊ›t{œJíž5”Yt¥ë=ìsß$é•°½<¦¢Èpr^†Ò3î"0B$2þAºwÑwÆ)AŒ@¶ 'ÕKÊiNöåÃøk3”D{öÆÕNÖ&jáhöž›Ñk¾"~dtœ£fÔ9$ªsàF :ÿeíiØÂ¹—A:Íh¾âyé¹9Xƒâwüwg Å8‚³Å+ï^ŒnЀ’¿æDžaL¯ý5¿ö>N»a]WYŒ°.ë(_š:¹† Vx¡çÈL»Š2?æéVà÷ºX~ì×ì¦"µLŒE‘mœR³…%åv®).ÌNfý¥o±ÕÊ,¥4ýÌ_ Ê'þŒ3md§lžN'žÊÖöÉAï¥^~·Ìf€PΑD&‰ˆ™øeÍFÖWŠÄz‘üÆ1 <{ƒûèc"E¤ž0ù6Ýün•pGþI“µ=ütí WÛæŸ3MÊY?Ódi0Y§ß’¥u!£õ"Y•gÌã½ ý9ðHÖ§“›¹PžÍLïÉGꯈ1d!]Ïㆱº½‹b!}bò­P,Ì xAr·nÉ/!Øëuöu¦da÷&MwXX² Ꟗ3‚Å{ÉZ¡1&°lH**?>O,$Ÿ7ØícÜ<£ŠBÀ…Õ:cÅ]A9Bqµ ãYà×LŠ&–€™rºÆ6I [>ÇK¸®HT,¹¦F;®ñOH6(Vdò²³ñ² º‘iÂÄjÉô«<ë×dS鎋eaÂ)-Ë„ŸÐ˜!—åÝVŠ87ÄŒ5/:¢xêß`.{v™Œ%õ|Ú Î$}ÃÌÒøìç¤%ç4§GÆ–5Ëc÷1É“_Ä@>EÄóúužN~AaÊL+Ý®"U ³ƒÿ¤Û5/b×1k-8JŠˆa̼Q Š/sEâWèÑjK¹äàQË®\‚‹<ÞÏkGä÷Gª«„}TXàkûØy¦v6ð¢–ït^gqé×}0 ÊÞ”,O¸è€ö¶(Í‚ .𗾃Ýmß¿XM`1︸•Þ2>€M)p>HaDhÝ {˜s¾ÓRÊzõ_’t\N•F@ÖŸá\ ®½'5“ÿ×etÃ}‡RñL˜ôc}Kí9›ël»O% ¤t„–³,ûäM9é|q‡žÕ˜‚Cq·ÖçM'T¬‚#\¶Òu¨˜ñ8ëÁ«–Èbž6Ý~2 ·³Ò€WŠ„`epä¥_Ä"I/ð€=Âå–èubð‹ŒÖpF£bÝH0Žä8•0¼ÙÜÆ. W¡ñÜ]é—àCßB$ûi»Qt+{QUÉü󬆵Kw³2¥§¶¨óÇàŸ:ÍJQÒŒ¾ÚNB é¬d1äòÇÐI e=ƒo ãwî×ÍW¥''»>“VLKLJ1ó[ðqÂïÓæÖ²rk°£ƒÉhGUÕ°YÛŽ/Ÿ/t|AQ™ž=¨:¢ÇÜQ•˜UX«”^ÙÄ8ÿ=¬Ð8 .t´n¹CéËtõ £<>ÕêÚ ½BÙôÜ67—-ÆA‰¥ÔÅIB¸{?[ÆŒI#Ü0¦&ÌÒ8îhj^´R×)O$–»†à4sžxsmkªoi'|)ršd @pç(@¡ë3MS žrMÛâ½\“ÔŠmYŽÛ¡I\òq«&qnA‰6n'£÷Ù$.™Ý½I\–ÎdÞ&.Çøf%Ù !kš2±³ÃέGl¹Œý€dÒkU¶rΓ z™1%|ªH–Í'1¥3_HÆ”6q6e}]ŸV3úÝÃÓjDxOÌßÅÖÒO2¿¦Î2ß*Ç¢‹d¾Î QqhhX²Ö;£±ukM†kn›Ú$"÷bDn6MmñUäéI’ýF!7þC/6âæ²C;?X拼S®]LÓi‰­…¬ã¤öó2^ mme4˜Æb3®â¤¾Dö‘xZ$kð<ß-#3ß2ç«Ù tNpskÚ,ã³ Ò9~?ÛÄ.r˜¬#Îb»Ó+(<¾LµhD[¨B)Ú2Qà(2:ôU­bYÐëþÒêË7‰ÊKö²ÁÍ0Ýj³VPÒV6¹0ÞÁØ.XLü ÁíÀ_þsÅðBéÊóóms¼©ä=³ j?õ}LÁªD%Wf`Ö;[ÑÖ¬ƒ˜ÐŒ·ÄÐTã¤'ŠæÁ¶H:Vi.ì¿×n³¤^]Ο%õêØ¹ŸÔó¢£7SÏàj«<@”øŽ["[ý‘ÑUÀó^žwæ Ônù†Y§P²£ªtŽ6YOAÉy¯íyÌ2ã´´‚ÆÍj+läÀˆbŠž“*ÇåIyïë˜ÊÈùÄ‘: æxt©!Ç·9!n»¹¼)}–>Ÿä~¡èe¯o•y?Ÿ€ÀªÎw-³å‡VbÜ–'é‹Ú“>³û”` „ ÒY"h;ˆjMût2¶;—­-)¾¹$¯ìÛúhtañœS°"‹¿¡ÐLj ´?ìCãIÑÊ$Œòy‹v1á ›c-7ð`U—GÊ•ï'Ÿ vÙÃB& UP"šPmvƒo¢ºhiA/rW×ÃÌúÐ ]ûÃØ”äû⢓>òy]2~Wç“o nÓͶwPy†ž&Ú¶]0½Šõë€ÑiV×› Úvf(®UÌ>… *ž7`fašl¿¬÷Vø¡…Ò9S”¯CÞH É]n/”Ð|Sq2ÔLÖåi|Ø¿IÛ!îï%#„ÐÞSüÙÏÓÎSgðf‰ã´ÛÑÁk¡-ô‰|@¦®Ð×ý'¶HJÏ”ÁÚi³W§ê4ǯ¶y'šmYd‰½öµˆ–E·ÄÔ¥%—¥Ún;§5û„c†ÀÑ2'FÄf©»:âš+mw^^\ :nÛ¹/’x ÈXäüÛMœó¯âc¿~¢¢ ðJK”¯¹3"‘iŸäô9éÜì~[ñ¢ùulH9Á£SØý’!2šp«ÉI.mõKÙÙ ’Ïó.ÙyV¨`þÉ7DVí|Møð,/o‰¬!ÞYûé€ÍªuþØVUë|~Š‘dy³Ïl¦`ý‚BÌpWùO±§m“60Ÿ&Ñïï:b}Ì?E1æß!„ìŵÜB¼½!ëžCƒD¡÷{ÍÃt¾ =næ°TÒ:œ¯ ÎÕ»zÐïÀy4AÿºçÑ`^äøaú=Sú ¬£´éx*¾—ciŠbåšÊÁÎÇÒà7•0ÕvÇÒø¼íÖŸ=M.5:”ÇÒ„£ŠÞÖ©½ýE:s4Ä.´î©4Sßèv‡ÒhÛï¡4¡]pËCi|Ÿã›JNƒ«¥ñvbÃÿü ½æÀ$ ½ÔÃJã…¡ü>a·“iÈ9Ÿw)õ»vBM^ &RcË{èÑûíˌٶé«yL,̳·&Ë^Z™iƒ¡x}LlW|„%as]B"BÕ”•«V«.ûx“6o®.ÄÒ> stream xœí\ÛŽ· ò¸_1y› 4­æ4±cÄ ìØIäÁ6 i/’à½yµk{óþàT±Ù¬"›=³3š•#0ämt÷Åb±êÔ­¿_ôXôø_ú{|qôôïÒö‹WoúÅŸáß«£ïD|e‘þ_,>zޝ9½]°ÒêÅó³£a±práDßõpóâè«å?V¢ 2x¹¼]­u'M°ay³‚7”_ž®Ö¢³Ö»|±Z›ÎûÔò~âƒ1biVk©tçŒZ>[©Î˜ õòK¸il'µ_~¼Z÷ Á*³¼¢.qN%z½üm¾zEïòÍ›æü¡¶WË7«hŒÍá¿yþ—È.Áù u§Lð‹çŸ=ÿýW@¢îŒÔÁ–#àeèM¢0ò§ 0_Þdb^±·D×@¢–4w8¾4¾óÊ.Ïò﯊A¥ °ø:>G¾:Óõ>,ßff³Š7mo{<Ç µô² ZpJ›+9¦Ëï2ùèªw"q oì B˜e·Z+g;¥Ô ^q/›?JÃÛAÖ¤µ^ÞÒ«¯ó«i¥Šx.@ìðWÎwMoñžêt`]¥% >ø >¤ë|ß D©{`80ÏOàœ™·¸u°&ØÏ—yôôœvýè$Í®ûQ“!'ÄE¶w—t÷U~õ RbºÐ»]†l¶*‘ª„L?Šãblo’”Ç»çD ®Åõ0EZJ|>ŽjF9‹w/›ܧœ™yw¬|‰Êpé„ôœÆ›¤¿z?^j1r!¾{Ù g3º³ð›í,†Ò°Nâ°rvl^“®À¡´ì HÞ3R¦_ÓÓ´xš&Ú·l¢làÞκ¦qÚÇK8˜xìµ2£j” ЇÎ;M,r±V¶"„a¡'‚ßjOÊ^ }ˆ¿]˜N˜àÜðþïVjxÑ806xà„‰C¹ ´îºxû¯‘¥€K_¬ÀhkÂò9ÞÔ½aù ^ \œý“çG;ú~ä;˜­°Ã/¼æúØÑi&ò£gGOŸ}¾¸½¹;=zú¯…8zú)þï£/?†?Ïþ´øÍÑ'Ïq(øy’ÆÑ  vgΗ†g4À¡_X`ºOøgÚÊBhF½ Ïeè;§¦ !î)“)vȘԜÔa0pÆ€_JpYbœ£Êò]Ÿ¬)µë,–°uªS× fWi)Oiø"2p}ï­Xþ‰]'#'$×iìd3M{¶¡óRZ†"Žs`#© Ç Ýìò‡|UªDéE‡ÚïiÇlcýF{…œÓó»ÔwT~ÁðifYøÏQâ•ôÑÞGCd¢4&CĈ:C¹PÒ–ê:¡LiGšÐ¤¹îC(‹2jæ‘ûlO~dûÇVMæ%ië=W¼SåF§F„ñù=o«vÆwÐqºï;76Ò˜×hJ‡¨”| ÖŒïf`ØŒ5h3؂;²7t–Ùùa'ð$açÚHm;{ x÷>¿zÒê À‹ Ò~–™`Çš[ƒQ¹rh†³°JœÕÒ½ ø÷ݵ«±…{gÊŒ Vv ÷ba<쀴ì5 ¯Lܘñê4^Áé©ö"=Å{WùÞq¾¢_¼Í÷èê*?…Í· ]…ã/Þ²Çå€xõ"?½È÷L¾ú6?}“ï D;·üfƒ ê•\~5޻ͯ½o]Œ§ÅAFþÝÚ* ×jù‡ñÞe~ÿn2ÖËj)pë& aÒÚ‹Ç[ùÙ‡ùÙ7éG§Á“RAé1ÈÝ}m½=ŒˆÇ1‡²õmg¦qˆ¥ Ì“ìý¨‚4½„løÞ3cz³uTqA"¸È‘G_‘ì*¶ n¾™œP°ÏÜhÞúgjø:ëü[2e0›,óí[Œ0JíˈYi3ê€CE´HÕ$¸Fõø÷1Õh–] ˜Â{}›•'é¡‹J¡–ªðŽé¿µˆÍ’fÁ{—÷.Ò{F1åIš÷¸š¤椡—?Ÿ6íœf‡ç`\þãáa¥Éi+ˆ@W ú$(¸·E\ƒ‹¤m¬âãÓw-ćÊI8ÓbDô°½Œ>‰‘Sïb€æ Q9hVG@*À5¬ ᨜KP’?ÓŠFèó´?Ó´OðWºÃæ""ª‡uùÀùÒúìfzU‰"Úp,€¹„ª%ÒmÀkbt úÙÏ„Y‘Zž‰,âG ‡ž$ÀwNŽÀ4ðö#.,ÎFý©é—°w«•g´k¢ù„#Q#ÔŠ´±ò4œÍ<Õ­í+6R¹×vùõ’Ì ëüêu3êÃÌÄO6’±FÅhr~á´éÝ!ú îc Û&õŒÉ÷ùæ×+Z@‚Ù`0çÔO6Y»«ŸY;ƒÇó0šl6‹`àØyØ,§´EDW~÷ÿ$†$‚”°Ëf>‰ MtB>e,Ì|=@ƒä¯2šÛ+ÉÑV>ÓdEH¾…›¡ðòŒ=Ä7ÔÚgü«ñ _W¿˜ñ iì^ŽßV´gç-»lų<@ÅòPpq>ïlêÞNÆ}:V6bë œ9¹Å-MÐQ’‡J@õ<ÚS%ñ…0Ôóé{Ó•OŸ}8^ ^«}2î¬Z~ý5óe#(Á)KsùU… KïžVGûKp߀¾ÇÕ/ˆáøô²bt)²$u?4¤î ¦þ8ñ5—˰ !e &ÕQÆâî‹”KŒ~>͇•&Ü[°2ãöa°rRUd‹ïk;VõgÚl§\›¹ó“.mƒÄ¹ª†˜qÕ3U¸mØÀ°Ô+áåÊ1 8”¡âÚPo)f [Ä]¯¥œ ñ±ÊuLíïÄeR߉øAµKÐà‰0½9$/hO0Dâ—ØuCÉí°–2uò²0á;y–œ òêæ´ž|3êžJÈUurkMröèùÄ[¬'AÓÆ(%²gÔ.ÀusÏr‡Ùœ)¥¦Á¹tÆT! ç„:KÁ;~^’|Å5–4]61Õê3¥M?9n$µQVßfGÑçæ­¹8gÐ-–åÙ‡ô7€Ë‹êšþ ”›wD»…Z‰²â‰KZcâúDÂuBâ5Ò6¤FÅw³P\ô»–Ì·31¢ßµöt/ ÞËÜ\L¨ö¶|eµÅmå]ożCÒæÛ5â¿;æÂaäKkaÞ:}YD‡ç–¡eÜÝ÷² ʵXF-4¯Aht ’Ï'_ˤïeµå›Ó©[o“Þ-H›1g¾øu•ÕL›2½_…o¢+A¬Ë²ÑrŽˆŠØÎ ˜€ÏMÐÓHX¨¢yHmª*‚öGÁò‹»«Q=‡ ÏTà½D³(õq %uäÎ8 £½‚}©¢‚ÉÞò _]¦V›iOW…¹»ÕÖüèî;g˜ý[[u¶0Ž8LsÈF }@Åéøº~„ô>jÊ·ÓZú]cUûZ¾´w(e™µ. ûô‡¢\ÏvS‚.¿„)@)MÁáÄx³)àÌ™7øõ‰"ü1o °eBëʤ&äÔ›0k Òï+Åtô¦¹ëýº…ò™{øz5~ ƒÚOb8¾,Kº˜†}Ã]¢XÉ ¶ô*§mé~b}`·ªÎŽCXмf6/RØ™èy‚›+rä¥m[òNnO$nŒYLÓ­ìs#iÜÁˆ*C([Å¥’½„xØ £eµs™&<”ß¹¬®ô©“ôP$«»‡n˜µº\Ú}ý.nuݼ}l«k#$àz—íjÝA·5Ã<~ƒvJ€p’ß6 @] ¹=ò>¨O N|]˜‰ÄSb£.Íħ§S{¹ÕìL޶˜=¶0öi‰úEóÖe«~BGÊ™hP”]KaêÈÒ9WS1ª±ÅÚ Àñƒ£Ý0eõ$ùNƒP}F é/=[‘ºy¥n«l}: óÆÌX7²RWcs«‹Pb‹œjB™é'‹ö›«±ÕJÏX´qçØ oŠ%ÔE9<×0É13Yƒé²iýp?{Œ:jîñUÅ“j{`ù™§‘† Ä«I©BÊ:ÈÉwWê/ž1ûä{µÕ>í~ˆgí“áq+«AÉI1¶ù²{ÜRQOŽºI=nC?Ÿ¬Ø¸,ÉPÏ/ÜÏGÝjÍÎ>!§’ÖñôhIÐ:±9: ŸhINv9;Š3UíÀÚà·›&%Q!Í~IIº¿¦ç%ÿ”´x¶±ˆa—ª“6mã"ìžm¸6xÿ0}â`•PÜÔ4óÏ>!Tù4íìßlÂ(¶ÚëêS†C¶ŒßºI…‰Åå‰áN“ÇX>CB\,´›M¶êDÐ3Vù’^(KÜ,ØL¶Íüö8ƒŸ×ÑJ‹ÎˆÊï hç$™™`.!»û²)H7(Õ æáF#î7Šn™©l|öO03Ðlt¥U6:³£+“·¿Ùj¾=è2/›JbüNÔ¤cvØnŸÎ(ã4“1&™ß¥©”k§Å§yRê^ømñ6©ÂÂ=Þ¥[–Š~Œ.ÝØÒe–»uéRõ¿s©I·èøz5)ä'2_Ž·^”/á³R&ÈkѼ'0Í×½¥UHóOùÞ·3V¦ï7É¥Ï7E~1ä{2_=IÁAO}•7¹Ò .¾«(É]”E9V¦#¤š¸¢W/k=¡®Ó}'Ͻœ'Åä¸ÿrëÜ1?¶÷Ôo¦ëÎÒ3ÒÐÔ,,©o3ï=^äïÑýJÊí„}Dú3¬tdÍ ¢¸îë¡uãÓû$uR7â7 fÐjGYŒõ‰ê:Ã:7õ*7¾àv<åRî¾*/Š1sÓòÍtÌËØd¯­Sô>ïOŧ»)ó/þÍ”ŸŽGb*—Y'ýJä²RûÉ%IÞ«LÒeµŠ9N}[\þö¾z¯\,%áê4sÅΉ¼ü#Lé>}þEîíÅøzÿË}yø«mTáôÅ¡ü¥ÐbØW`u•À/ø±Á¨Yr8ù‘mŸà»”š‘†ÁÁÁ{´J³Õ·óÍ"Ù‘ÏuΤ¸Ð>¯«@”YéÁì7ÅK7d˜ðŒb“_r¾`º ƒA@ÍØ|ÕDøí0#»ÛŒë±¯5ý(–Q›4áva¬­À°Òè™Tƒ»WX);žba_šûØWÊäÍu¨erÃvr?£2Æ7äI±è sðXeÝ“žÇ€°­¼QŠÞÔ9¼Múç ߢQì=?Œ“x$ÿÊíøÅf,v)Ë3š'?}ZèêÓЩ‘…•®šŠ©ˆñE?G›e»^f[9ãâ±^G¹ÝŽÉnº'G­Y‚D àö íf³›o¨‰‘½^€Cž¬Cú†|š—> —ã¤;úÀ^(Nendstream endobj 779 0 obj 4865 endobj 783 0 obj <> stream xœí]YsÇ‘ÞØG¼ø/̾ašf×]%?Y–b͵$ÛpøÁÞp€ r  JÆ¿wÖU•=8´,Û¡ ¦ÙÝuee~yVóýjžØjöÿ¥ß‹w'Ï~Çõ¼ºúîd^ý7ü¹:yÂÂ+«ôsñnõż¦´\¹Éi¿g¯NæÉªøÚŠ13q¹2lžfxöîäO§wk9Y!-;½WÐêôe¹G=½-÷.ÊÕËòô»r¯^Ý–§÷ë–fš™BÐã¶Cu^®Þ…+cNU¾øKyv•o]ç‹:ÍùÖyû’ö9LȨIž¦Oï»±áÖE¾x[žý%ßzh_ŠdÛhÁîîô1?}ÙƘÿ;ûŸÆWgÿ{röóšxHV§î‰­ÙÄŒ¨{ò¦<½É·.·ôz›){Êò-WÞâùÖ”/Xy¦ó-۾䟱¡Ý\ž=Ë·Jç²<û,­G˴Ȇí®Û%’ø-ÜNŠYȳKÀGè„ÙIëÓ†‘$̉J“Û|QÞÆì´Éo›¬q&ŽñoÞz"oU>èXêhüÅ÷åŸü¬2 z+0—“²…¹Êº?NúkÃ.éõÇ¡=Ny2Õ¿ÛÒ°(:ýÒ–UÐçF‚JžœRÜ+j–´´á+-¼š¯7^–sÀ_›yr¹pW¬7ΩI9 Cmø$5‡á_­Ùd4úôÛ5Ìß8a=³ûöR[˜'Ÿ„šPÍ¿ÇDiÌŒƒåÃS餅…•&7káGä2-D3lqp9 =Ív¶Þˆ‰;%ÜéëõFMÖ:à×pWØÉIÏbR0g 3Ýȉ+§Ÿ* Áfé§š݇çz0WX³Êáæ~†Z+¦ãdãå 6œ àhï¸Ò÷z/­“róºð²ö"+#ŠçVq-È+ù~­A¦qÔô® š^Õ°+Ð'é4‰_”çqþ³³§¿ïˆâˆÎ‡òf"S"“BDJçËÿ,íÑ«èy^Œÿ&ÌZÌÆx#¤šŒâˆThÖaô¬ ntUÞ¼¡WêY‡+tËhõP[ßú!EP­äÃîø»hÑžhzâ J·¯q_Àóžgi¢Ô5ùž¤ 1hÏ^WòŸ÷„€ç¾{®' Xñ¦NÕs¢R‡¡ÎûóLŸÐ½ÂÖ€B1¼é÷IRf 6iâïf.¨=º<ˆå/ßÖ~¥%èôéï¬F$ÖB|+ È–°) &íp°Gì̲Z ¯ÏJæ I¸|C‰tÚ‡YuÛ#‘G| ¨øVñ¼@ÆM.Å1E:HbÐ@é¸véAFì…ù†¼<¯ïÆuIî4⪺Âa]¡}+¿bæÛl+úWc¯–ó^¨Á,dA7•»7UαØYA—è4¯·ì„gq4ؽŸ,8TÖ"¸ˆ›ßE`á:‚L¼ºr(+AV@šy¶K{#@ ?˜Å+|,¯’¸ìpvA¯Þ–ç¯<»˜IrIÏê0 ž½¤Óðý ¨ÙC¯MÂ]Z,ƒæ1³~($2ÝâX‹]ľ|_[!AEãÆf†ñB.Í"Îy t˜cÑ *Ç>”ÉFàˆP,Ó*0HIßU ¸«woëÝûjP7Þt‘ÙL‘ÆbLh@iÃ9 ·ío [.fpÊÔ©† ÿKrXÔê iIŒ¨­Ž ŸÅd1a®E€D:í! QZ¾ H4oä5Š iy¹U’h®ÀFÆE4™¬8›'˜ú,½¨#Wçç%ÆÅ°u¢™Õõ6€« µ8ƒ¹ø9fi’O‚ë@6nèç•@jOÈšíÀÁ ¥92q‹Ža/´ÖM¾{åI* è½[ìaºpü½%£*’Ó5fÆ­_„wE.@æ +Ý d"Ãy[‘ãã ÈsÌ¡ðÄ¥$ÃWXj¢X5†èf5Ó±[퀆ŽF/Ã\§8ç "¨×A?ôæÄ-‰…ʺó·Ò+~”z(Òè1Si¼ÄÖ#kRÒÑŒ_åê®ç®êõƒ&p™ÙÓ´n—Ì,·ä1DÃô´%<–f%f²ó Ú¯aBÒ~‘¶U4ý%… :é7œ¢fŸù±À o©RGh>°}'a{dϤë‘Ý1Ì%{G7ù©á1Þe$;øxWƒ'³þ‹Ã<‡½à>]ÔžªŸl½:')û¸VrC‘蟜TÊ$»DG»Œ)æ\äƒ_"\ðÄÓl’‚Â_,ˆ»‘¾ÞŠ¿Èûð—ÑòvÖb䩲:Bˆ 7L¡Û×Qp5dà›½êA¦3 ©¢‡Ece±K0[ciËÊŠ†©¯—ä7µ¿jY"Ù.Εnæï‡÷P’MºÏ}(t(ž²š? ú]ûùMؼiA%¿xØ‚žcЉk€úTkØøj:9sÌN‹%ß12«R)køa‚r`aÚ96XØ6¡®”Îõ–[Õ—ä–ùø¯vOÄÿ/˜<Ñší³U‹#†ŠO°VƲ¶ª¢<,_*aÆl©t!$2W^“Õ£­‘‘©¾X=>§C¤Á3„ˆ:×Ì»\û½æaµG(þäΟ‘xFÿÚ\çð¾6I‡˜ìñãenÙ£–*Ô¶ŠCí.Áá¾ÐDÞ¥«Ö ÃŸw仹œZ "±Arq‘g?ÍhÊăK –Ç»$ÊCaœÅØ B`x°¦kW2dò "'ÏJ¿ñÖ¡€¿YÄ+8í2ówZ Á–ƒKÉàÙðIEr»C¸wò?UÞ-ØL”™Éhë˜éŒ´U5iš21Ò¢»(Žœ9eö©§ðKsØ ï1Eoâ¨Ñy8(TóƒiAywi'®Sm’JžL4è@¦.$“CcÂÏ$Lü¬fJ%¸„vóÑëÁcÁOàà'ë}ŒÃ›O»0è…KP³èŸyŠüxþmÓÔ äÀXzuó'g*}).ft!; #zºS(Æu gŠŒ±4!UØu3+Vª:Ü£=‚„ð‹1%º¿Mõyj¤ü/ëg:ÿ {1c4±HÉð‚âìþ´¼œ=ܶCéå§EÚÛû[:å$~‰2p(9Ü$Åð ›úé¾FLÒ±E/2­Å]}ýë\Ö@'Rlo 8¡2±å Hza¿œ“˜ítOò…vžF= ¥ aÐ}û\3ë§/½‘ÃKåp0Rü‘-”%Î[g³0q™Áìí†ÇB²]e|uF’¨MuTöò9âXëB"aÙct•X~'ra—©Tã2²± Æ÷•vM²¼—¹Ž>WÎ9£w=4vàP~Ÿ ëDçT- á½5FQL|¸rò¸­E}ý ^nŸŠÒµ]Œ¥·¢¬5¹­ 5æÛhzw@/¹jÛ° áÞŤÏÏájwi¹Œ¿?£œë)|îÌö½Ž¿¥Šúâ1TÆå8S ¢–ô˜ërØÏ-ˆ„‚ô¼P÷ z¹<2Ó@©Úªú<饱ˆ€Åzh*ÕRµ–pÈœ!O[T ÍÜèe…/Š…C1% ÿ£{Yû¸N©œkŸ4Ô'qœF¸¡eùSøN䉱ÑûÑ‹²€Z±³|Ì.Á`‹$žìe/ž½Û÷â?ß‹ü¢y ¼§o8mŠìKZ÷ÿÄ\–]·¿Ó¸Ÿw»~ÿ¤ûøüb° õÇ.Ùø£[g“[>nßR-§Ùç"Ž›äZO¥öø^/ú†:(³/w*¦m¡Æ¿KG9÷ÑŸØeõ~ë_ æŽp¢+*ä–MbÞãå?ò!È’0hLÎÈÞ'ñÇ÷ƒsW«·‚?†¼´ì ‹fÚ³Õ!²ç'ÂYBƒ]Ñv_ƒÌt¨0ˉÊÈ"æÈ)‰ÜW2eŠ1³ÈÔ„\QiˆÀ(M9AÆb Nf•lM€¾š”žû"¦Lø¼øÕT.MØÉ€ÑõcXXIü>Y/ŒøÈV9¸*ª« ¡€Ì+Ò#ä´«m5JþtÀÖÂhE6'²óÇvž¦ #OÓ•ƒ×¥P¼m8$GˆKr«?U‹?fc ‹f«âáTìBbLé§»#mU/ zž‹êE¯|µ=€WVGIk)3¯˜(¦ÂW'YLŒmš·¿óþc߬aPé¾3SΞ½¾ò—Lƒ¹á;ýêìä·'ïWR ¯¡ýW,Vve%ó§›m,£¿xwòÅó“gϳz¸ÿðòäÙWìäÙ¯ýÿ¾øöWðóüËÕœ|õ|zšlìÆ ‘.)?ìž>‘ÝéâüåM7¯ŒŽJ<|zóë&Bí³Öà:ä¬õp€ºO[Y^ÿu£öNÌÏͧãÚƒvù[-‡”¶ßwȧ\èNm3áî<ž7Vcòƒª!kûí_(z’´~VÊ ´…å@£ƒ œn1;c`‹\ŠõDèZ‚Sí^§‡ ñ;þ( Î# þ;÷È{’ËÔ!Rkç4⎨çÖÿ3_ZŠïdiæ rñÛ“¿]ìšendstream endobj 784 0 obj 4798 endobj 788 0 obj <> stream xœí[ÉrÇuø8ÿÂøä™N±öÅ7S¤l8B«áðÁò Â$† ŠÂwØ쬭+«;{°q• ­žêꬬ̗/³²_-9Kÿ)ο—–/O\ðåŸáßÓÅ«…HC–åÏÑùòÑ~&—+­^îŸ,òbéÝÒ Î8Ü<_üsõ»õÆ0¸ÑÿÚÿkzJà§â%žÜ?†Ñûëb2hçW_¬53R»úv½‘F0®\ ”àzõ2ÍëCP«×ëf ´Z]®9ÌgŒ«׊´^½]o8³!XeVO×Á¬5ÂâË‹<—wUÄna›*ãFÀ•!‹z»…ý ñ]ǵ)û|×¶—d4Á†a9°¿„å4ü Æ”âÚkôæC¬q#a2Íår#³—VÏÚ{Ñ ém–óô©%3N­Úï/š`è©ÁaµŽ)-ðmh}«“áf¯ ©øÞv"´ ŠÜР˜vÁÕ­ù=È¿X+n²‘çQž íÖ¾][&Tð~u¢RÁۛʋ˜ASi÷E!Š;Quk]ÞIǹ·ƒ­òhIhÚ¼ÿ^ʃ·ɸ´«oÐÛaè°eºîn/Và2ê VÕn5Iš$[ü|ÞQ°žƒ¶ym‚³¶Ö&Ôi{¾7ž*êõÜH°àPín£ š9X=Úª7Ãï/š HÿgíõÔÐ(“âÌ€ñ?k’tú‹Æ# gJVSIó;®aº‡gÜÚêq^[<éÙÔMŒ, @[¥ÄpÓ‚Tmƒ*_4 ®Š^tÀb£}Í—NH_†”¥‘†Ig:#E¢#{Ý¢%¼QF3íAeVM´¸>VGŽÂóR2  ð6šLwÀ—”waõssï‹v‰ÖÚL kPK@Øb > &½¡F±­{¤+zi—uZ/zÇXæ¼À°×ãjuäP—¤q¢Gíòy‚o-ƆŒÚ0‘ÿ £ Ü L9‹múåȹâÕsÒ‘ŸŸV3Ò™…Qh‚™Ñ7¸˜Ø ZT4›³ìFÚGªWÜè·C<Ù_|·xµÔZÅh3èÁ/=¸÷K㤈Î4üÑÞâáÞWËË×ož.þc)ÿÿóèÛ/àÏÞãåoOö–i*x<Í#AÚaMþ6óÌ’|A‘üÀ—ÆŠ¨êDòç IÐ`ËG£7=uy c9£¨zhjY=„LhƒÑã$Ême– ¹ÀPvk²Û2Ï„·Ìxq“žèŠ1³‰®Ê\àsÛ`$ﺌ‹Ì ¼n€€„i °‚p;b)WàmvDDð ˜×Œ\Û‚ñ‰ŠUVUÌ|b±Jºï¡hÙm'„7®`¥?El…›±Õ?ÌжsyÜ::2!k“§c, äÀ) h}¹ E‰ëÉö#jP„-û¹ýŽ–„vÑâO[¨U¦’ž‘5ŸÄ=   ç­{"ÔŒÑ%€ /Ç,+Ú%5I[º`ôž‹¼³$Ü+)R}JƒÜ¯°•Á¢†®™¼ê°„w 'kEÎ…¦3™ó=̵;“™ Åu#/Wnå£âmèƒø;è †Žrˆn1å6rµŽ/¦¢Hð×½$l¸J#1£@”vÚA¬ÂšGC¯ŠwÀJ™ŸŒôeU°Í hfÞi*t@QyR¥ÀʽKxÂC:ivÂCtð <$¯ìR¨:-´ˆÆRjÈÇqÚ5¿c žåx#1ßIæ"§2ô,sào|‚‹@`—,É)¤ßóFià_¨P¢rÏÓ«íݽ|‘ø´ r湃òO$¡`œ·Õ´ìKrç:,šó4C$çA9D™'é.^àˆ3£»(¹ScW½ IA[3SO˜ ¹ºRƒ÷SLùã (º(E`®«½Ûzô—Ãî¡LöfIKE7[ ºKYqÖÊóµ´ý«šæªä¿jæc9Ùcš/¢²ÍËÈŒ†tÑ‘w£ÚVwûاNŸ†rKŒ¿‡rUPwU.ä´ŸºCx}þßàÀg{NùYÅÝOBcŸz~·Jº?¬]wüýKÕÜg…_é\“¬‚“õòØ¶Š \lFÉr<äÍãMºMªyPý¹Aå‡Þœú´wçc©¸!$¦Ý~?¨æ ÿ4² ¹® H%·ª0mG¿˜*÷[‡Å½{Šèêz}p79ˆOÖQK¼&à·MóâÐn0[k$ÞÒÚ…¤*Vè$³—ëà®r^»^ºž¢Œýv-SŸÿ£ÙŸ×"ýrt‰Oe9éÁlªûÅݸ¬Yý°jíµEçhfEóicCjÙÙ’pƒVG7H Æ4àp®ç¨UÜ7’ &åHCé˜ä*YS– RN”!ÆèÕ÷ÃÍ¿¥’µÝ3­ ÿú4kè1¢æWÉ™ÕÞÿH!oêNš†êµÆÅÛI 9m:I<~Ï "cl?»Nð¦üT_äÏÚcµ;¨?~)%õCÒÉ—ª¿ç3‚ÛV ¾ ÐtÜi†¹t…^„p&6{iÎ$ìÊ…YXFc3zYÁtoÍ/(¾î8ó®;©<ÅX0=‡>n«'[ñއ+ô3,.I›x=6æ8WšHã™×]À¯'·~½VXB\£àŽ9¡pîÖ¦/ïôaÇéd|‘»hc¢&ÍçOç(Fn.˜s“ö¦ÔƒõÛùå0‡¡A…r(Ô<³€ÚŠª“ÝôµEH»¡3©—ì,ØRÙ õ0]–f ؈¹%¢ó «®âè;%;ÓÉFMÇ®KDrf¼˜>žv åENN½G`N£ ÝÐŒbðAÃ-ÊÑg ²1«È3ô¡­(šnA®~Òš€_6A0€Z”†?êíË]·×ã*òΡÀšatT#'£¡ ú¶ûH «^œ¥¡à¤í1]R¨¹Žz_Ýw¹ Ìéç8µÙ{QaÉwžQ52åYúQZ»i¡ÉÖªËbë×~«ÑÁnúCN;`]ÆYÍ\^1mŽÎÙ1°&ÒMë5(m¢…àp.w8—¼ðý÷öDxïzoQùÁUÚZ¿Fás’I÷.Óåý”wͶ ¡w‚-íªQM¾æ{ð#?ÕMÙåˆÖÜà» DoJ•°¡`²RiŸl¤¼ÌþOK. ¸V+#t|#ëèZŽ©Ù‘ÍÏ}‹T¡ìº¤‚þn¨ùDÿ™ë¹ì;pÅ^/‘[5s@ðµ|’$Ÿ ˜ÑÉ­3‚dé~.rß@žá1ÄñîÑEj†Xù¨Ô kazÌíë'm)QRñ…;‹?È•€žX‰Qð0èhçñs©¤©¬¿sÉ‘z%}Štc„‹Ï¼Ó#s0 ûoÔΫR1wŽÌwE…¬ A—È@‹^…€àª‰8G†ëïÍ}é/ƒ†ÕÚ¹6ÄÜû+ãG#]ù`ˆ‰ÁÜ3‘º+øÂúå¤R1˶—ÌyœC\û‰ä$œ´bQŸ:Ä–G5þ†3¼Ç v¥ÇÎà;ÞÙø˜Êuã¹.ÍÅû|@ñÑ+ôÅÊãó—}îÎýع`›ŒHDÞÚ´8ú0Óm;j–OÑÝŠkI=ý}ÒsŠÌ ê$]ݼÁ—‡”J+2ÚÌ5f2ÿÊ0ÞSn⤵rK z&Ÿ¨ Â0Û˜;Ò ’•¦ã‚ Qy¤›¥ËS¬„+;¾ „E…ˆ›|æ Ÿ«ŸÈÂÿÑ…E7Dæî5Öæˆ6”d|‹]™ªu\Ëp•’* ¡ˆŸ4hŠŽ•¾t w‡¦ „O¬D õÕ…¾ˆ“q¦ØÌ4ÓO™¢C¢> stream xœí=ÛnÇ‘‹<òeá<ž˜£éûtˆíl¬ Îʱ‚ÅÂɃ$R¤Ö¤HÓäjõ«Þª¾V÷Ôœ›(;X†­ñœéîêêº_Z?¬ÆA¬Fü'ýùêúäÉ_¥W?žŒ«?¿'?œˆðÉ*ýñêzõùsüÌ镼•V¯ž¿>‰ˆ•“+'Æa„—×'ß­ܨÁ¯õúõæTÒxë×Ï6rÜO7›S3L~4z}·9ƒµïë§uü«ø»vý"Œš¼Wë·›S©¦Á»iýÅæt¬÷V™4oúB ^‰Q¯Už.êÏåå»@„ÅŽjýf3Âv‘‚þÏÿ'(V¤”ñÓêùŸOžÿú»õßD7ŽROqgvÍúö å`œ¢øxoÍÐÜ×…/ëÂy”öëoËâ§Zz‹ÛI€ŸÇ)ô¢îñ÷ÒXµ6ˆD=8é×·uÙ8*ý>¹ü³0j|I‰ ª‡˜6mE!Ì$G?ŒJ'«Ñ øöçå,]Šì凲êCÄš†?ê ¦•r°“IÙíQjTòݳ‚雺æ]"×qJøOðçñ¯fø·jBÊMK¤$ãÑy`¢çgÀ8ý™†9ÉJçu¦uþëH4“˜2Ãüo6Òv^ÿ÷ÆA©z:8 (!Éé¾½’· Ï^"Ê $;¶Bæ"T?ã¼×ÛDµÊÓ𭶃óbÎ7aòsÈñ1Rë$eøÔèÁ6ɺ¯…Àd‚0|´cyLë¹ËüxZP†ôrš æTÈH2Wu‚žù‚œÁƒžÌ`Tfã,w³°½¡bv„’É[²naZú’lì{$@7š¡tÓàÖO‹˜ùb£ÃíúkøqPj1ù ¿òõ– ¯·uudèI¯È(^“ø2‰ÚÉ äZPI Vàcëoäú?7btƒª¿¡‚$ÌEɛΠ'qÈF3 “n$9AÂ/Ù+Öð?”×.˺k‰‡ ^Œd.(&&˜Àz^ èoYA@”ÐD#T2õ"?O”›nDþÛ|”~ýž“D•±,Z¸¨wm¬‘q˜L2H´Tð~e¡Ÿ=LÊ9X0=Ü„”QzuŸ†üðªýºŒÇa¯Ó+Ö È¶‘v`´ |¶9Uz¤­‚cVƒ6Sž½©è%²„œO@ª5|ð²"LIUNðL‹ £G‰ðž G1 ¢˜¤Ÿdž-6¢÷·J48DBËÊÆÈ™˜ÀºKoÅ4È1H~‰P— ï¥0Ý´7E0Ÿbé Ðc4YCEà‹º‘jô´Z5›JçìFÉÛ:AÒ«h‹½¯¹ù1‰Î¸%R.ðP‡Uk*ïÆ¸N^GüÒYgY«7ˆ “ÍBTš~Y.%cô‘mˆd—’#¨RøŒƒúªÎO &³Þ%yG£Š¹ED×oʉ™[G' ×xлÒ:Ž•–€8§?DTÏÕ7ªÕ°™PêË,Ë$]P‹A ‘ ý-~-@”°Ð¹¡|xÄú;<  2ˆâ‚Êßu¶²ðÔ‚ÔqÞ»8ÙQÅA¿ß8´ بÏÇÆY!’„hKòÁKÖ) évn)–…Uö/]U¶ûM‡Ù¢¥eØ HaIýëì—–€ýO+3Á«¨#žÝ¢A |ž` ˜4éBžjDkdânP2Nv0dìß _ ؆“>2ö)ƒ‘¯Ë»Ã@£§#A"cß”åo3H8ÉžŸ|sòÃJÅØ pÜ´ÒkÔÿ0ÚãðW×'Ÿ?=yòôëÕýÝÃùÉ“ÿX‰“'_á>öüñôËÕ¿œüáéê›ÅPÌ8¸` œ·λ‚º›òî¾<ÝÐ]ìD¢ðGb0|Q¾*`]uçÈœÀŽUv”+íÁš·q6ÉÉãm¡¤ÉÅ@Ú5KÇŽ3| 뀉*ãØ6$„Çùé~ª¬~OÅX–ïÕü`å3ÛC‡*E˜ugù æÆAØGD¦"Û¡Ð<*®QF…†zðÿµBŸà8…¦mQh·s)“¤Q+ƒ~,¿¾*猪x{ˆ„ÒúxHÇú»òî¼{Â_oÑUZ¯>éØ3WÝÆðéý.M†˜A‘¨F5ŒŸX“i×£àç #q¼µ@ÇÖxS€û‘½êèj_¼,Oå×{†ÈÎvžÓSP4â'°CÜ„,DQðñ§W0{²òGZ)eàÇ[)tQRj»•rNYsÍ~Vq¬Áâ-ž¯rŸZÿbœ_7[kT:ŸNΓ¸³®%h{°ÝòX‹£¶§ àÀÚÀÙ/NívFÒŸbØÿ]ÏÍlU(;hMç:MÑdg×ÿ[±÷çÔÃÕ°¼˜`›ïHŠàCEä Ž(ø°Á.Fø””nN­É›æ¨Ø 1›¹Àÿû겂$îH¼ö-÷’DÕH|ë¾ €Ñ¼'ð‚Õ-(1Rèé—$ìÇæx1vT0ZEb}$xMbHMº‡/‡H3%†X »ë{Äj!¯ÏH\dz˜ ±>­Qû$Vn£–‰PM¨ÄÊ8 Í %á‹IͳD᱆éïk@þ3Ä:¸’ÚÎÓÁaÔY¢ ’%šåMÞò¡[×bF7oQy Ia.'ICdY2é«.oIÖeP1Yi1ÝÔ¥ˆHªÕ,ÓÝqÁÊ»Êöl­Bn}LšJÁYH½KœEâ‰)|œæè ãù²–¤É„æÚ$X‚õ"±§Óǧ#aü4.€’ÒÛ°o¾0€pOª©†8߀æ×h–¼Ã¥`Ü(à÷Ì3„‘®(‚(1½.šŠÅ†plBðÔh¹™ ÁÌR£pøW$?|S´ó;ò6îN‚ðг…/’„‡¥<ÀV@ÙÍsÓ›VeòÐ-“.’G¯Æ ;^¤žiáæÍŠ+üxй¶(÷¨œZÚ#''ø<ãEÍ3^°Rë®/_G\ª^$j;àߊ¹û¦Ö3]±˜a¥y™óœJ“”ùr¶- ó0k ¢uš²µÖª¾ö§f«ZnU`TC±L”P`n"<ÖèÝ¢ØÛ¹ŒÄáÚ¾²]@ÝÁ-'šz[3ÕÕð¼)€ªRîV\8Pé(²<`øÉëG·ñüyqþ’U„³]uÙõ®`)ÈcQ‰}"b€ÀÊkZ²ïW‰ô’œhsÖ¹ŒiAN´ÆG=D‹"æE¼·VDÃÐé GÛª ÇLŽ×µ|Þ±­òi”u¯— ˾æLõ–y3ESo`¦Î3ž3`—•©Ø8O5sŒwdwFT_À· è–6yXAä.HuÓ¨XïŸGaƒ«ÑÙ;ÊÇ““G÷,8f×L ±}µ¬ëý\@#1âO—BÐ+Ð(†ú€±Lzi;¥À5)± Ìó¡ª%Þžáeiçä`ÙtôíÜw›ùN±Jš9wtuó*ÃNÌDWKe¿Ö·Vã SžtxdnÝVrPï&Õë5¥a©ðn_:Kfw^Ƀ\å¨G,ÆÇbqð>s.Á õ1pž:.휹Pé\ñN„½:"ægµ.Á‘Ãð@tµ ?˜›Ýb³3À€Ñµa ¦DR¥èl.¤HbŽR<†T0éÎã#ŒE$öû„¦ÑϽ‡Îk´‡åদhý†Óoú]ƒ2y ~j½†X_Ùj¡ ÝÜÚšihÖ‰s^Iß¹ê%'2Ö_W™ò— ˜ÌËX_jW‰©T-äA/‡Q‹]õúÿÃÒD_hX'¾©­ý yþÁ Sû»·Õ¦UfÅ‚¬Vš»|eÝ¥ ™ôÉϪ¯×Ê䲉éª(<¬Q.ÆS2ÇÞ%§4'kÜm&k! ðŸ¤àD\þ.=òT|Ô¾&¦—”¦°ÆdçP£i¢Xd%Bò¡òÎW¼3SÝ¢‰?$8ÉŽü>‘¬­ßÏJ™5Þh»Ÿaß^æ$Õ¼©3'áhü)•áSÁãü%¨×ásøc*‡b2VùÃ#±LÒ Âª.ܵ;i6ï,äI>p›„ßÎ; ò~G:‡fÍ}çàÌêýÿ>¤¿Å¹ 9‹1.ÅñIÈïe9Db9æêO+- _œQu(I>-TÇ´Âßk½°ãhìÝ-™“ô\ bßÓéK³¢5óK’¨j‚áK<¾±|— MBǃ -¹„Cj;PÅ(Ÿp;gµÑûгVìäŒ S£“3SÓ’ázX£7“Ñgû”öqï‚?Ó«i¦½øåº’ѱd…4Íä!¼´E!GÁöûñÕCÞLû’ƒŸCû­äÑq‚¶†ÇÙ+ˆ6¾¤÷ °]`{‚5.a‰O\fa`›3Ê1ÝÒŠõy¹×8ÞdÅÍžÚÁ€ÞøR*®gm—ú/˜Áii$»”ÄÒ}a·.' y?a %2è¬ º«üõ]VlÓÑÆé'ã[Û»Š?šû™íÑŽµnï  Þ.\°P=×ÂëuÛµ1~ØÝpU~ÿG}YY16¸mQàd랊)´·_¦"Jl&|½ïŠYJóþÞY«È—%zYã2Ï 4q¶Ub‚¹_Ö^´Rö÷ŒîÉa<¥É ð¡"ɦEóûÒcÓË7ZD ‹Îgm†BáÔl‰!òΨƂú¹3Z".!_YµÀàƒ¬˜P!\°(ÎÒŒ\¸»&ªÁ:±+µ·C¼Ãz×àÞclÞ‹K˜*mì4 NÈ™Jî£D÷ñ ÞZÉD¦Úä–œw<¯Öó}Jo:*×o“8Ϩ”ÚV¶G‰Z**¤l,«Q˜_=†L[Þ5·»¥Ô¿ïöÀ0ãÓ*miá¯ø-ø\’Úóñ{Gdfi«Å.JèßɺU@ð^5WÉÂcšP›Ñ!nUJð1ßò3U—w‘„¦½l®éìÝdÏ~¬Ðì¸$ÙêëD&- +ô9U½<¥fpâ‘&ÊuÖh†ÌöõÚjªW¦­OÄŠ´‡þY5©aàÒ@z •¼S°ƒ¸io¹˜gª>ñ¬ •ÄžÈÁ¤;³BàÁ7‘²î²›uY.bKî’[hLÞGnoË E3L‹»Í>ÖâP[Lÿ‚r{hçP`ÝsÀ†™ø K̬‹’ŒãiÁ Þ%}Øšúq" ß';²ÊW$ïy9XZP™ùŒ´¥€—äÑs`p½Çý÷m¨ ¼p(4è)…ð1Sl•’;ªZ‘‚Í’Vé¼q@¶KéM&L¢Ü‚ÅÀG» ¹¸›c–AU1ƒJ->·´GJ”Rn´Ï唫YŠps…ǵÙìŠ-* Ó.åŠÉöQ€Ã„(ô±±: ÐpŠ%¼¶>dòNR'XÛûÍF*@¬[øSéÐðÿ #Ë×øÞ^ö×eno¹'{l…ôÌ2äolñG´Õý3†:z‡‡ngýÅž|¨™§:üë8<Ö!L¶ŠœÛ{AÇɼ¬uŒ_6Oã7ðM{¿ÖÌ»éŒ->5R®–±,ñ"±.r{ÍÑ•¡{Çû3°VóMw¼J›_\¶Ü ˜{=”¤\DJMvÔën!ÈeC¯K[ÞØ9C9Ì «esÃ5nQu)TÓM2R4€ózÆ‹W ŽØåjWò½ïrGziM¿/w–{/É%ŒâÑ ¸gÄÆíÉ=ŽâÙ²Ðäð’náMóv¯» µîq°K«cÝ„JzÝäăýÉõº÷Ø/>¹^÷S¼vçûM®Ìµ9!uÄqÿŒ ½/3øE¡ÿ| ] ÿ\ý¬y;xÎÜ•PÓ=‹Ñíº‘´x6!”£¶X;î©üÅ(i~]ªéö1 Ò¦K—±ÿ–@h‹•ËQþ]· ëi5)lž}L[@ûpyÚ¤ì#)«-{0rÐí´¬œ!a§10 Ú“ï8càŠåY"j ›­Æå/UUqÙCuf¿V:•wøÂÓ¿û]%ƒI|•Œmî2Æ›L–ƒ;˜ºÍÇwBžÓ4éåÅ^ò65FÝ­n¹*£ºŠ0g‡Ñ˜5ß»sü}Á©‡ªoÞïÊÚ—ºØâµÛ¶)±ÄÊÜÑ‘zݹ ”‘zêÈ’5ÿþ¸9š´~úë#@UÉú×GˆñþÂL$Kr•¯èÊ—š“NÍ«üê|Á œA&¯·ž1¡õÎ>d·…ãtP%)\&÷”ËæMWó w|^j9~2õô†‡ùýNµ¹ ¿¬€ç:ŒÅ–>åÎö*ÖYjÉ›ikjj/VÕÁªÏ'…ŽrʾüVó¿ _ËnöæþîŽ-æaêÅý–+—a‹Q²‰Ðô¤±]Íuè¹Õ{¡ÁÆ슙:5'G0˜ñ†Âù7e¸(K•ÿÍÉÿ˜~5&endstream endobj 794 0 obj 5180 endobj 799 0 obj <> stream xœÝ\Y“$·qvøq~E¿©ÛÁ®-Ü-)‚—¥µ¥Ð’‡$cv®Ýà\Üáj,ù_è;qg¢€îžÝ%åp0È)ШD"/ ü°š'¶šý?éïéõѳo¸žW—oæÕoàßË£ŽXè²JN¯WŸûnF®Üä4×ru|q`+Ë&¡g¾2lžfh¹>úÓÚn¶j²nVr=m¶vö?[¿ÞÌðG)ÎÖ769î,_Ÿn¶lÒZ8±¾ªí¥ýÌ? 6Ëõy쩘þ¯ã?úêøèë£V"’¸•“]1nÕ4[OHø sûüùѳç¿_Ý¿y8?zöÇ;zö[ÿŸÏ_|ž¹ú§£¯ž¯¾~ꌙ`“¢¾2­“ÜâYVÚßnĤ”“r}¿Zábýf¿†£‰­O߬nÄ•b~¶~&e+ä¤<×·LMN9»:>2Ž7[1q']¿ªC!’Þn¶žKjVëÛÚá®>Þ×¾èg¨ïOnvëw›íX¬~WDâÒ}o¬OüXrò ]H¥oæ4ðµŸÖGį>1èñ±°Ù/ëÖ¯ë–Á°3‹ËûP-ðÍ@›²âÁÄ8g@¸ÃFƒX%Î'ÉŒYÿXÛ½lI ¬3˜.d(Nê~ÅÀ`=2ˆ¡@Wv²²Pë{SÌæÂlY»k'–µ(7Ì ö“ï‹v›Y1ü{¤"U)ÿÕÏ,±0q2fž­f™sCóñ*³€˜¯ÒЃÁ —¦æ1Š’OJ:dà_æ<üþ6ƒ‰{p³À:þņ¹É‚»…'ø‘˜XcsÅ ióL÷Êi7˜‡JñUW*ÀØ€I•J™ä©gÞr £‚ppÉ"{C×C!=@¼2zyÚiB€944ñŸzpÏQÿ‰é=f@Ÿ§9¢X29韃b)'I)®îû™êŸ3ø+Z×Ç@<7s.` + Ž‚Ó×€²7? qÉ?r`&¤þ¨Hð ˆï"34Aùeƒ‚Àtx3û“¡ 1ëðb‘2-÷Éð1/‹Éðc*@+¬b»>¯™xþýÏ£ùU®ŸU®·ÏÌ’çPÀxÓêávóžŸiñB¯ZÎg™‹,4^ú _ú„(ZÂd,pqÁž;úêÛ'æ¾0'°t[–”ý³P“~±€\•^ÿèˆVðs944y½Ö®à*„µ“œÙú·H¹o7ÌN|Uþ<@#   ,0HSh%|ÎækàcF6`g` 4ĵ -›Ù‡‡Éb„:™)ÓV º" ®ta”ç‡qÄ£_U«µt `CFcAK2»AÕ…õP$ëúc—=[ØE,+31먭¨ö§Ç %®_®SšÈÓ#aE£ã\c‚ôð¶ÅÄø±‰=Î2Tc¸ï =\äF{«}ðÙ€)yªáŠ,k"Ç4nTÿ´œEÿ±."ez,G_Ù–°ù}Ò ñ â´lq×—e@ËRuöN”Ö3B`¶!OÌAÔöæÌå,€“ðÖƒ¨ÀNVó\‰± Ì›ÜlzŽÓ–Üi¤Õ‹¾,=¯jOÊëb»JŒ'ž’Þ5;ü!ëJU4²-ceXÒƒdæ}þκ<ÖŸ¿Û@.” éµ¼žyút»FlfðkŽ~³“É‚€bVÑx‘¢1æÀF3Ö±&aˆÆšÀ$à¨WÌ(ï±’[íñmWô`DŒ ÄpÕøžðvfÉtF÷™Ýk5’J H%–*X{)&Q€Ý ¦OK‰] rVõëÈ4µjŒ°‘/¹Ä™²àëÀ÷’)‹,¦|—‡7Yæê™TÌÀ—ÕCôñ("laS3ªã~¥ÄÔö{¿šÃ>4º-¿Šn!®{ñ Ì-üåì¬Ãz8>Í –Ø(Ý¬Õ õu“äNšžÄϺ̪Ñx4Öaò¦(‚¬S©’GM ³Ò[ð6kÃ@Î4F4¤l*¾gÑËbûq$ÍNf#4ÌZ%¦¡8 } ½EjˆlÔ]˜Có^Òò^™Ö>éW— GÄ-¤dfù/À"’|¨ïMí»È×Ð)(F?süÏmz+=/ÅF1“Sاèˆj€²)©Ô\.B_ßž´ÀsbsóM\~¤8g›Ö¶X‚>bð3aœ6TpÓü&?$qTò[ÎÕäArúÄnd„Š>ÐíJ´Û{s÷²¸ÖóÜ×,v¥éëOlçè7ÕáQ«€—›UÉ ,¯RvSSN ƒ¬î¾I6®ßÿ Â/ÿ-¤ÁS¸Cܳ{’,›tgCl(uQ‹°yBä£ÌwÕíˆpÁÒA?Pí¿w9¹ÃYyÙµºtõs‡¿'ARÄÝ£gÃØÐG%J6ùœ1öGRÇš²mÃã÷­W[á³Á9cûo€ûÆÐâ7‘©dÞ\w)¼Í$#ÿì¥Éw ŒT)ÿ Éý®˜ò‰¹´[^ßó_ÉOçá H­Ò²ÔêßÝ–w§å©þâmyWŸnK+ÌDk¾Ú|ÑùÜmçÃ÷¡OKëIywžŒY _“fšO#“†«Ÿ0&k‚Òƒ´]ÿ2¿jz‘ß‘¡Ni'ßv•_½Í¿®dýùÏéeTA ÛöÏÐ?}×áÎcyº+­ ÎÍjžæF›[vû§ûΚÖ?)­•˜¿-¹V8ófɵÂwùἨ0ÔÖMBj#êðg¨›oejæ=Ö?ÖÖïz¤•Ö.qË‘ñ”ÖU¯këÛåÈojëëÜú2Ø`1;°”,[á‡Úñ~É¡³îäü;ö­Ç÷ÐBÑBšXn+ºó·e[‘äòà%!Ñ‘ämž ݈Û,/•ž^ëwÑÖ›w±_Q®_6?¦‚þ®[ßz½”?¼ªéÕC~¸n†€W¯òÃëÒv¹hól3 ÊP¶yåÿÝÑñ¿ü Wõ¬JPÕÂWNÕ/ß%¥ñâyùÉ hžÁQkÞIËSGÿòEùɳòî‹<™ÚíËüê<ÑDh–Š8Û–WT.z® ®w÷ÛÒÚZ©j2éÈç‘ß&ÐfÄ3ï" ¯Zðº!»”_—2XéüÜÏÒŒ­Ú#%2a?Õ«fZ~ôËòî¢`ߊ•>ëºî«Nµ*É«${’w9qV¦u±œV™i17 [‹ö›œå]¹òÞÚêc+µ/»Œ¨ë–Z»ð2×¾nöÅ-î}µÉ{ƒ!¡TÆ’_Þ59k «SÝé!PSh5ý†šÍÂŽÁ§Ev뀵BV ]UÅ"DDbçM@èùU««ªŽs2Æ!Š"ýˆî½ÊÝּѸÿßà>¿‚èÝÄð=¯û_A@[„pè“Uh®ªõÿŸd?òסcæúOˆÝÿš¿:¢.š´–¸ÖéüÌ@¬PÝóïÕ•Ö]öÌ—ÏZÙÖO]¤<8¸ˆ{‚èûÚuWýUÙÛ´“36&rÒþj×&æO¤*¹Óë?ÔÉC±©µÈî®TxuZ£@Ç3iéþ3¥“¸´¨:¬Íz†—çuÆ¡NØMÌ©¦g±?idtn)jy^†*…Ì$µHv™EËB6°WÒlófR³;áníÄf;H£]¥ã4¼¯&¸>%¼ÏÍæA?5Ÿ0²åP“t½Í”šKÉ5ÁHÑ÷(¡6"Bõ€&%1µý²yÂ…H¸L¦W„ÑÛ6õëRrcc¾æ<£š\­ByJÅ ª*¯©@”ÿ¾í&Ó‘`,§›ö:I?´à}Ö“Í8`˜€ )ôU‰x§‚ÙçÄåÃ"íˆæàëÆÞ—¤Ä˜œûŠT0‚2è´.>TŠÏÎ'I¯<Šr1qoÜz¼#˜²»ýÌýc³u´§pÞ§œÙè–ƒ*VÒzccBž—ÀÝ/ *Ц8T€Ô~ÒMpww%PñF ¢µÛòYLÆÉ`Äbɧۃy7ìg¶faÛ™TÝÇc[kô¥î@‹ö¶Nè1K¾ì® Ý:´h¾’o6“©ÕŠãýÀ]µ§}ÆŒ6aôèkÑËHlOçÜU#³PæÑÊþœÂ õ} ŠÝÙ€,ÓTøY*¡¢z“x‰µ9·ûAóåh; iجc,à¸.˜ii]vÞodnPV“÷Pµ\Ó“83BöËÛ¾döv·¾¢¿©xJÝhØVDÕ£T©IÊÎö$5´JN1Ò¬[޽‚ÙQ5”_7àêùiùü¡YPÓ®|Û ÈkX³«_vBîûœ\âëß——Ÿ•Ž_”8ê³eŠ¥œÞ¤æô«òòW5íÛ›á÷g‹W4Ä|^æ÷¢Žýâà€<·ž6ïrd™²ÊÝðòR•qT¤wé;.¿<.¿ü]ù»_›ñȋਆ­àö2e§ºþErËê’YIÀù¨H» ô`µ¨µˆUÔ£úzÔ·±’@µ£9­qáa3Ø.Ë1˜\’ç=\†¿'å!þ€Õ‘oe ‡6"µ?¯ªí=á¨Ê`Ó¬¤²ŠVÂÚé½TaË•«8])Ë8Ä„þ‚±ÚUC,ÅÈ¡&d.÷׺SO˜Ò.–6‹p:D9Y°%¡ô€#Ê‘-v‘QHQòKê'=áŠýdÑ"-rž8cÙm[©‡Õ°¤ú_†#‹J-‹ogUü½·"©üÜ_X°8S×ZLJˆI·¶ÅD;O9þaLPP%¤™ÄG¨9¯!˜û§Ï»– ÁÂÉ'p(—õny)…OèÉ>JhÒgUüüg×$|P\'@{™œ¸~Ÿ/U0…¬Ïמyrl  ”C‘ÜHgùzo%„žc•?€~öCW4ŸÍgF±:8ï‰Ï;J°ãÇÌÀ@,ÊÓÛàèUZ@A,×…Ë&ÕsÄí‡÷™½®Õ‡D{«“X ÔÓ™@Gj>®ŠE¨)žå AïNé>ºÀä¢w1Ag–•‚s5áæ‚Ñ&2X %µœå(Rv\.m[@ªêñ…P×)öÇY(kèJ½õykLšÃ²~2,¬ ù¦Ûä¹Fµëè}…L5àÂWð ¢#*qéû~ 4ĺ¬¼œkÏ9‰ëmý½óGßIõQÎÏú³Å3£Âßq\9­éó‰TâéAû̪bû›3çÝ™ìçO’¥Q©÷“NÚïH{/(éHkìŸã¼ëpCÒ95ä7`9x§³–7OßÂ(‰±eþ±1w‹zV…ç\£ðٛݠ£h ×Ibü­YbhewHkªpƒñä” W uÜ’«÷`Íí h+ˆ§ó£¨ýa ¸‰Å‰‡¸ÝºI¤;Œú©Õ§½è‘öè{%Þ=yÄtÓD`kâ¯#UV BÊ&xMqîYO座è«7ûE9åŸÅ˨½û7HÝâDñÀˆ¼ýû«ùèUñº~'S%QCÿƢîäÛÆ·,aËwÈ…LŠcín†¦{øÌÒ±a¡;çZÂã/Êð"qn1h>ªê3 šƒó£ˆnQ‡±O(óƒoJëœÙZÙjlHÁ˜…@^v#~È®i<ÿ,ø>íëö1û®½ØîÓœŸJ²I•8ŸŸÚ·‡ÐäC Ð`gáI‘|>I4Ldt¼ï€WÚn“Ö_Y5“ýæRzÒŽøŽñj‡`™tjîsºî»Nm ±šP½q½Üß{¥ü?ÖT“á»pHÑX.wÚWS°ë*¤sù¨ÿ“bøÀw-Þßç›’ 5„€|ŽWÈNå ²Ð2UgvƒÅ…ÆùZ„& :mæ¼ñ°ß×ß?鎆î•5‹*8_ˆÝq¼ÝõÇf< ë–Mº'[í»%áO”˜`-èQ÷Xa){"¾mw]ã5VÜYEÕ!ªÆ§*œ„[”ÍÄt ,Ï_öôÔæ…ÐŒÜVnõ¥þš—ißõ_"R¿ ¢ ™ÄÝ·QîR°²Áõ¿AÙ\Œù¼š’´‘-æŸR"«Ÿ ¨v¥=Q/ÑÙè|¼6¿=¤´`l·Ð–¾àA=Ñn§æ½(^(î-þ¿P+ôVµ·ò©²i÷^ÅL¹FðR;¢*ÞüÒºê(#;Ê)‡€â/ëÝó4€u¹0 ÍYÔ^TXšÎIÁ®ªÙå‹ãR&dyƒÊ¾Î’›õ.9øèܼ°³Þ¥ö(ßÍ'Œê]¢°„àéMí3U[ˆD9#^ïæe>åjÓ¯þ! ¹endstream endobj 800 0 obj 5113 endobj 804 0 obj <> stream xœí\[s7vNí#że&•i5î€S•k½YnmÊ´—)?ì¦R”H]JIÓÔzõïs—àô )YzIÊ%³ ƒ€sùÎýófžÄfÆÿÒß—ïOžý(í¼yýËɼùø÷úäç»lÒŸ—ï7ßžc7§7a VZ½9u² 6Nnœ˜§ߟüuû瞌ÔÁnow{3y‚Ú¾Þí¥¶“ aû‡Ý^M2¶ow3 gŒÛëø¨%¼v}ž¬Ø~¿Ûë)HcÕöÃNLA‰Yo°(VÛ;l“ÁKî×ÿ>ÿS\™ $;?Y ùü2ÒéÐγ„nWÆìhÓr2ÆÑ—>ÔLJº¤»¥Õ»ô{ }Rº)Ì.­^ÍNlÁaäœÝ^–·šßÕdìl]4u]§ºØíÅd­U~û±¼µ4*  •JOÎh:ê n´Ÿ¼´‰ìØú†«ÃöÕ²­Â¨¼nøýº¾Dh¹Ý ?ÉÙ¹í¯»ý<¹yöp”í´i€×‰,åø îkãûÊ u]d·ÿÆarZÒ7u».ÓÉz ~Uùe®fc‘ypé!„Ì.d‹ Û’ñ¯jœJÊÉ™ÖeÂì)Ü×V²„7ì`÷¸IjšƒÛ¾`; {/à@éÞS:,Bal#ÇóäMå 'ég±±^N:Éó9ȳW&²N~zŸ` Ÿ´ÇYöf·~;—¶Pú=+mõW_~Ý—6QžLùõæ]ÇüªºQðש´YfµÛƒÔ `„…`Zßus7MÈÍùŸOÎÿå¯iÁ¸ /OWeº›òöCiûŸÒö¶<]ò÷V»i–j+óÏqF1ƒº<­(“…ò$™UÖ•ÛnŸñi*¿ f_3ìµäY‘Cúwhœõ¤Aó æmÙÍw˜.Øó¾4ÙüºÁ ÉdšäöoÛÜxWúÝæ¦ûüðP~û%7½Ìå·›Üô·]:Xôyn|^ú-«7 ¼ȿ֓½n'uŽˆÈ}Û )¬’ð¬`ØÔvÕÒódMQ?÷ð¿”a»µÀC^ ´Ï#푉q¬³ÂA÷lãùÜväb[]^ÝÊ•ôçÝÞã+º}meâ›ô²ÔU‘Xdõç…¨ÛòtÃHX•º— yÜ‚nò¹šÏ#¹2ø\~n–QÕÅiYÂYšßfò¼_)S¼,OÌ~Õ=¤¹Œkd¢”08RúciäF|Íœ¡ôiº¡ê¢¢…Ÿ®T~øf|/䇞hê_´ÚcÀÂvÝJ£å0 ƒÂH«&ò‡Šmjbˆ*|•»« Uþ}VÚÎ:lùæ´}uîþ*‹ù,äSyC—'WžL>Îòàè⟢ºA“€ “\ Ói‚y6h©Í$@ÐFÄ7G Ž;˜=‚Àþ4Âò¿wä®>^5P8‚mhòZ–Pˆž‰r“’†v½É^’W“çÍ„= nʲ7ùy€ÖaALÛ{%·[â´¸»sÉÏ!n·•Ôs`= |_Í“ãpÙ8£GF$­,dÔëêý=$'Ð·ê µ8¢ÕKêP?uéêqzG”—µë»„› ï@TÙêi" BÇC¬ùq×Ô{OÜeŸƒûè4¥‹øYéÑÎ;sÓï<ã]å×¢gãf-åc=¬dÿ;6ÙØ1Öés¼›ªÐ믚]L ½õsäÿ»8#ùš.Î÷ãøÅ?¹IÛ¨{Ò8ñI2"ý¾œßËE‹<EÐ@ŕꚪªnkñjÅÍøk²Ù|èÒ‹IÙYn´õ“LñQmò´Ûû_Û~·ËAÍ¿£2µJج’КÝðñÇïÎO~8ùy£–0*üà7BJ‡3Âî{Œ¿~{zòìô?7÷®Nžý´'Ïþˆÿûöì9ü9ýýæŸN¾;ÝüðÔ¨¬4^³2·º,¡Ógµ±[¤ Þâ"­p :_a‘, my_b{„ôW£Â{ XÜcMsò‘ÏktøÍ§pÈh(MкÚ9EbƤç5Ýö2TVZ…vè[dV ùÙRXr›£»ŽR0Ä.ã°ï2ž]ð4í S¡* q+Ø^€º+ȡŌ-íL “ÑË/³Ý²¡ÔÔå¾Ë–y) Nbq‹ónv k¨˜ÅF [S²Q!ÊGkÙU/Dyø­›lìçL f+ÂtBúa¶žÕÁ{†E‚ØAúMQì$§|Ϫ,ÞWQyÛ°:qb˜5gô±®ê92§ °3oSsIƒÂÎ:Š3í¢D´°SÒH}¸­ ¨}pÛAŽs‹©üŽ3qä±Ê*1§&пT¦«[óGöÒKôɈ ¢ƒŒæܰœ?ƒìˆ”sHÎûY/è ÑY!4o§•´îÑ.„³ëT¼CUGç\Yˆ¬Å[ÃO¤”lÛ›A ±•䄈šg‰EЗÒ¥¼Ÿ”Ë–´K@Ik'à Ñ‹ÑgõædvY‰òòWQ7 +nÃ$Õ\— `&4=8²1ƒ èðPÂ(éÑþ•MÄÅ>T?’œHyp 1މrÊÇDÖw ʃãçWƒò/ªæ#x +aÝE…F2·PÒŸV«ÂÛ"Ü ö@¸/kkÀ_“BŽ}ò„K|zò þÍ &››EðxµrpŸÔÀ˜³ DO¥4¸Aü©Á8ºR@po-ª =+PˆfhÞpúûŠÕÔÄðÊ‹£=¼<Ò`³ÖÂiТZC2Y*]dH9ÝÊP~¿1†ÄD«uÔ_zÓé•Hµ)Õƒ—ü4Ïn%¢H´!ЯÁ–zÐéBŰòe?ƒ3µ¸0ÛŸdÔâ¨(Ûr±¶Éªym©Â~Û2Î ßЈÜTãíDau˜—/ç¸`æ O9Ld‡„°†"¥l¢÷}‰ÎáJ‰æU|E8bnô'VìXûz~¼_j¬×iA3 Õ™ØùÁ‹­× ÈÀ óÚrvëå> lÀ¬›’'7‘P ½¡¹E©J†Ûi•ÓüH#Î䓇Jš²{)X+ŠÄ8›j¤Ž:4IÆšd“¢̉•T!£,xé§Æ?ƒVãë¡kÃGê|ˆb«iý¤Ãv@º¢,)åa‹H Œªê "¸Upog€Óòë$L)Ûx*‰G¬OñØöT¸ËfóHþrá !Í`ÉÂ(ìéÔ ¼’‚ðòaÂNc§ T¥V‚[nù€5tÀ:µý#3d²×u0XT±y¤ÞúLsšJÞv³¾rÚŸðÐY¹ƒJ£³ YÃ*·‚Y{õšê’Ø ëPwa ó˜€Þª™*µ‘ u†1¼è–à“Á'þ·¦üxŸ¶Ú÷lu¨Ô~ÝÖuÂHò¶9ÕÒFbã*}~ßµšVˆ,„ H/ŽZ»G1Cºš{ì"òlÜ OI d•Ñ8ÇQ—rŸb-gÏv¨·¡;v’;ŽtÌŸ•^µG&GF޲ß^zð'”ø щµi³aÐÏ¡hÉ •£%ë>ùc‚%)hÑWPŒ`Ù«Õ(ó“b%kXWëD¤sløIÒÚ>’×4ºL]øë¢üJ§˭að62¯žåpQ±~ã «ñ .IŽù”.‚Ûèñ˜N‘Du®,XÎs¼´ø¥,g…å^͂הjщ«ï$Ac3>¸]€±¶ÜðXLÞ`ß×Ì”–ˆ›Ù(¼µÝ â«°û[nfܘ¿üFTñ]Ù·‡þÚÉð݇¨gñqMôC‚#J´zÅ­°VóóÄÍá&4Ý2@¼zšÕá ÔVˆŽ¤‡Zû _ó¨DM)“ â°z‡ªÉ­ßäiA%hÍò‘ŠÈÆ¿Ž×÷Ë·¿ÊÕþ7ôS Œ*á ÊŸ5Q·}¾¸õŠþm×ðv¸õzøòªŠNk3ħžWNŠvÐÓŠI‹æötSù›Ï6_Ó —•+Õ–¯ê!_&9Pg®2ppþÛ'$IÅ_kÈÁÚ•ÁˆÏLÊ/?Vr)a˧\,- s‘zÉÕRÒUhÂ^#] ›²MõócÊf0ªÚ„Ñv¹æ°¤*{÷~ùFªZ¡$+_PZ®ÀËæ6^IW*«a²ßý#.Rw·a¯9V'6î]ãza¶W3Iâ6Ò§AŠñZ²Ôa%ÂÞ\XX¾i´¦ŽóçP¤$ ÿ±è¾£-ßÉ^¾á`K¼Ã_žÒ\° díùpš¨UÅ>Gïü»1ê1ê[ÄL@£¿—;ýŒúÖRàFÀÈ_\}k¬ÛÒí:õ}äÓˆIîFhävÌÅPKÄW³¸Yóäýª¤HmâYê@> stream xœÕ]éoGrò‘¿-_`Ž§Ï™v‚±½NÄ Ù+`ØÆ‚II1EJ”´Žò×§ªÏêîêwЋ]qßÌôôQ篎yw:OâtÆÿÄ_¼9ùòGiçÓ—ïOæÓ‡ÿ¾ xC>¢Ëðçºì:! C­š9¡e‰Tæ?Ý¥?Ê̯âOƒÓ‘ZØÉ~žÓ‘ZON2§~‘'|‘~º­ÿ ‹ ,«‡\U\Z~ß]Úø³·þ/,pöa3ÃÃÆH›‹ªyäÖÛrëû͹\i$Lج‚Ó¼+×ßlÎqÆz6T³œ–ÕÑQoó¨ªWÁ¿Ó,tœ^¿)×/Ê»>¥[m3ªnš8ûms>OË<¯V$I ŠP°jÄç§ë‡Xf-eZ¤ Ö9•ÉM—ö‘nLd›qq–~ï®6°Ñj™W zC¸Þm³ÿ“ìØE™ã:lØG'¢óãÞÑ3Q“1+¬áCYÎ{|ÊMÆi: zìžœ„[àW¤(©W#óé³K ™{œ¡4Vvo;×ÊLÊžž îüÛÆNÂJcˆ ŽÛ™œ¡báEù³Ú! ü¨ÜUÂú©#'Ê<{%¦fÿ©üJnø˜Iê'S^ FWì~Û1)£ ŠlůyÔ þBΆiýy#&§Ä¬·ð„Î)[Øë—å&må‰Wù:Y6ªUöĈ<¨,½cäI– ×Å žYr]wÓš¿•T7FçËÂÖQɳ^4ÊØe†¿yÕ½ËÊa¼eœK-¹’3|µa£A“Uz>H 0:’¬ $ÖÉðdœGi¹KßßoŸì –—qvÖÕ¶Ipháü8 Ü¡¢w» ÉÑ Iåzj-¼Ä²°T†m„§ç –Z–]¨”2F4 ^`ñE‰Ji»¢U@×Ò R^t¥µÜvðÔU·º÷û SNhÖÕ{ ánƒ§Òi22 ø]NNƒY áA=ï ­³ô™|G ™m’ a|¡?Ë¢–°"9Wò-KEEÝUeºÔd_û8D¨ñÛИ[+¬^dÅ^&{ˆËCüàŠGÅHõsâðç³rÇÅÀ ÊÃê"A\ňöÀ" N‘CÚŒ-ãcn0§çœ<Úqi7÷ØøšÂáHÄàÏ›r´D¼ƒ£–™~ 5!e™¹<–Ì5ìnfhÇ™fFî[ñ Øì*2 ì¯^«µ ½Šs‘ŠÜIWÒEÛ½vðÞÞ§;]¦\•+˜³é«éÜï"¼´:Š¥”Ý=ÌÛwã;Y¢¼Þk9']o÷ô“œ,&^G\5aû鬨—Mxò/ÀÚÍÖðq\ªƒ.w÷¼:"h]¯=×´rOµ½q½¨V÷޴æm„2½.Rf †7œF iwÌ1:팊 )4Å+FväUŸ’ù^¹OUl!¸ž\"™±Þ!Ù¿ÎÍn¢èZD‹ôÙ÷H§ Ô%eÛ:žýˆ*\#1έ]¿ëÙ{ôÆH¢Y¼SœTK5)„¶’˜¾,I‚–[fä|ðéx™(ò&ê2Áë&âÛ¾Oo1R>ÈRlœ´`hZ{ö?l ¢èÞ]sËÀG¾dßÐG ôæ™´‰fálŒ̼’.ÓÆôzàë.Ô„ÓöQ¯1.BxA%ý.«#Íú’ãƒ{j#òà¤ppØbŒô%K»Ã9#9oc‚2:ÎÊ®¼<âgUù2…¥ÚYc,ež}Ç­•µÀöËœJîÖ‚&ðBsPdHp –-HtŠìŽLº‘–žp“aHhh¦øXîå-—:Tá÷s1o‰qÌ@5¬7T¿UT rˆLõ>’=ô¶ qžw†¯íÀ3`M6¸™ÂÈj¡C]VÒ+x-rã£ËVS."žâ”}g&²¨<5 Û'Ó‚</^°bÞÊ£¦`‚¢³t)MÀl°î˜þ;„pÐ{]é{oXyWss<Ô>SŒøb5±9ź¡4á#~ÆŽ²$É *néý©Æ¡ŽqQ¨NŒ6 N8k«æ»2#j¶Á`Ó¼8ÞŸ!wîB²XÒ £™°xá\ŠC´¾Ï8A†~Ý}ºÅXjËl²Î¢ç/—Tˆz‰ÿ_yÑ­2¹€[•á´ûÂþ<ŽÇßPÆO†šVgߣ¦ÖlšnóJäóETW`ðÏß2Ï_u6Fƒ¼tdôÅXÈ ¦¬Ÿ)£É>'™]iô%“ ‘¨†ršàfòÇ–TUŠ»xç6o @ïö€ wÙŠÍ)!cÅÔ³jÜ‹açõH`N”pA˜†c¦=äpʶ´‡O/B’ .|Bè='™¿Iû˜ÝK³Èúˆ}#¥˜(C˜ö?’RM•sË¥ŠðIÛu&uŠ™ìQú)h]³SÈ(Yxnâ$àü[åŒÁ³CAcÙ@Rоˆ¶ì*HUPR2âc†Y0ÀÅy¼d±í`á=~Ó ï”U]ìDºƒ|R¿Ä„hÆÃã †¾y“¹D2ÈÓ­Bõ•1ÔëÂÛµ¢gʼ(ÑÅû ÷MM+jÅ ·Öžc(bâ°}>SŠ-~+á‚C5©Â„j¾hbÄA{yzÕV½æôt)‰†l2±”1\„OVÀ+¡=–3b(Ù²–G{?± ¸‹5oë>Ö‰çlK«<0SaRYCàöÑ‚™!Âìjð$ÊÓQ®Ò=ç}P.#NË«"2Šæd‰µ=œ¢À;‘N6­1ºEºw‹X×aßêÒq*!›&Tû&N©¨±ãÑ{VdÐ=NoEq4/KeŒ3cõU­ñ¤vÞ¬åa¯ý¶ŒåJFÙ–ŽÝ#v ¿†pÞ “ƒ#ìc¬$·´² BÐDÓŸ ÇCÇ¢‰Ú‰·ï:ý×DL»©¶NRš‹5ùßÕ@¤ôñ—¦ˆkŸ\†TzÅG:øÊ>[¡ÉÈÅ[‘èÖšÿ«fª¿u¦Ö[äìƒÖvJ\äçµñå³×s%‰rEëÇZþu+pÍÖg*¸_L‹‡‰…Õj\·‘Ægk(>´ Ï]3fòÔà~—vlèô…r©pHe®lòRë[IóNïã‡f òP‘JÉÊϺËi’Z²ŠÏ?ï `±Í.V…‚q“‘z(lØ®œòƒMbA´«Xµ·3ÓžË%Ü‚ÚS8TfªÖžx3ö5ÃW‰ÑYíéÖIÏEv~£>Åê€*>k&XE¡ÇPŸ~^Z7ê3¥s=žúLñ#¨O±JÒé!ªOOTj9L œ‹TÒV•Û4ÊÚ©q£‘ ‹—&튾öÛ>smbÔ)±ÊHå g|ÂÛHåz¦YF¹çÇU¹Û’ 1P9­³ž³¾”\rP#wµ¹/Àç^Š»%8ùpÅŸo¯wG•ñµæ ýöè³5õ÷Æ>}u¿Ž Ø@`gîæ S‹Õ›y&ðš?¨;ošÊµfê £—‰C=kæNO“¢h‚¸èÃeA—3r brj-<]M•ó§ø«Õ´:£Åý÷1étÝÙF+÷U²c[=öÍy˜àØÚ~À ‘·!R…;ý)ÿ½Ûí½}ãGûÊä¾[L]ñï Öž¬¶j#" Rƒh'±ï$$†5Ô Þ£ ÎÏg &]’oûMãË5‡"«ý†×aˆYìiTô+å¸Ý”?Ý,1Ðïe¼Íýê’`Q®÷ º¬ó¹¯õªÓ8_O!»Ÿ‰S`t±jõÏà@h‹¾„ ÉøŒ¼~KxÊ<, p>§WÒFq|¨LÃõPCÏjRvæ?†âç¥Ú6áµè_(ð •TÇð/Ô N¬ã:žþ5džç”u¾$²Ççô2Ib)ðì0.qˆÊŽцt?´âSÁVwHE%ÇWÍæ½ÞúDÄô<[9±—öGÈ:Ïzoíëkÿø|]é•¿eét;„J¡Âä\ßÇ@ðá·*Y¤ê²š‚•2ëåWe¯Žie™(E#‡åv¸›RµŠ=t/Jz3K¼ÞäL·ÔV:µÇ™_«.ZYŸȳfÄ#!íDzÞýÙ×~ýß© öÞ§Slçh\¬i›ž“£«ˆúï2ùŽstöó²ãͼrOki:—MÖåóÈ “þ§(;é‹ká rJuuȪ9 œk¡…½Â¦>BÎj€NW9r!ŒEÌî¶Í"I ɶ¶OXcbJ}}tºaç—:°De=ÀÆô¾‚î)ó-ŽòõîKåê‡üÐUþªF¼ú±+ü°W¹2“®§Û¤è‚´T”tWÉû” ɲ;!Õ.W¦ˆƒ–À‹Hɦƴ³ŠéÈl,Ž—'Mb›þ7©Í{ñz ÿ³ebÝõ6*Hò?y ð±e`ºÙ¢FH.!A;èò >{8e"‹fÜ`§+’£9 Èú­sŸ×¿Fýª‚QO5ñÂ+wº¶)s(¥ºÑo{ ÌÈŠÇÕ¼ éDß¡+g0.Æ~5‚Ÿl¶uuÆ«™Øtá¶Ü?;dÒ@i”Œúk5AÌ’ƒ.εòÙ3)à †&C÷ÒŽ¸aG)/›V¼g"kœ@ iKhº®XcšÄСI»¢ 2ÍË^ò½µ>¥mY¼¸7^l•¡]ÌÅúÏIðɾd7ð ÆxO­.FðïU•”ᓈwêv¾È!±—Òô±;v¾ysY‘±“­ÚÅóE?„·'íÚÆdnp¼ÆÍÕ¤ÜÁ¡€H‰˜âuéb°²%#渺+¥çnÓ]ŒÉÝnÆà{ÜŒA%Îâæó¦Í-€®XããSn›ª™ò¡ÔVJ·}☼ízV e¤zÍ)·J1yvŸÝEN/ŽÍqýh¼±Ò×ÛÖÝèwfFgšX÷@öã>7†Q݉ÅMº©N`¿*C>Ë߃,Kõ (¾4€ð%©޽nÑ-Ù‘ë›{˜’¶º ‘¥íCɪš¹0@"¾ú›4ÃDç€ °uæ¯Ù%÷¦QudøP/RµÅ”T€eÉw›ˆ-B >ú¯[ÔŒLš‚‚K6ój­«.T1V5 óùñjÐÅŠÜÙe–uEñ¶Ä’êæÞ>­Å6åo­êŠ“…LÛ¹#äÅl©ë}aüÑWY×Yó[žF¦Ïá©+Ô³Lí8p¼j¥Kszm¬ÆÌ Q1eÕʯ›¹$M}=ìê¸Æ=ÔX‹F>3¦ù޲XŸ ˆ±8 $)(#™ø/o*[ó‡\Þ€C.ÄõRYè(Ýú’$)¹{™<ÞÔ`@¾±E›.$ízâiUÈ0¤žþÄ -Ì3ë(ås”URë¶}%ÁW]OK¶þàIk-¥–e‡ôªLÚpþÙ¤íku#ò{ã€øïømºö{ƒå =i¤!Ë}›‘¶ð@ÚàmæžÄMÕm¸ w¼ ê¥Â6GŽ˜žÂÂ&mùNWœõC“ÅÅ’~Þ‚,ÇñÜœªÓ]!5S’˜Ô§x¨V×J,erìRb™«Bʆ¯y+²5 *7ð[C¶‚À)5w±AX)_——Åé_LÙýJñÂ"x§Jٕ˱óPS¶tŒŽc"äû•ìᑲØwCæPW­[këŠðZm^Dþ‘[‡AÚª0wbÝÛÏ­X‡Þil6s5ï;øøÏ絟Å"m²ï?‹µO¥éFû€²Ûè†M£y%Æ  \ð·Ü£GjÁ’¤R)0%‡™?O¡Fùç˜`ŽBë±%feøý[íº¥ƒGl”˧·‘R·ÑÇl6êûL‰ÕÒ{y×{œ ‡År4Y·í‘:6¦‹hÊ-|*²©rW×”²àÌÏjÿTµ4=Í+“Â{ž-ªÒº]ÿÚ"™bt heÜ ¬{)öxˆmßÝBï5)WO¬i=v=LZ—,õH¨Ô¨wV@ÙEÉðÚ…òr•Ä7yò­;î‡k ¤6 MŽ{ÌZ݉hÜiÔTãdŸÃïëR0ö*¸`÷°Üz<ö,!^ ± ñ&ß S ÚûE÷gi¯ÕxcS£ÿšBSê¿eÀÊ£w•CU1§Ÿwýa†HÛCÚ¬É<ÛñŠum?®Ò6×q#¬D!Sù>ÂXã³–aÔ¸5¾ÁöÃÔxÊ–Q²€ó‡ès<§v÷v8>çØFµîO4‚[r¶â(ÂÇÔè;í„èšHÀ´Ýq>ÅàGzP½Û?2šÝÊ‹>¥ Q;ð=ú_¢ 9çGÉÆé:g&ê®ØL]¼5V@íÂ*šˆW22G¸»‡P}¿æ!­½÷·•¸rfØH£Ä/XMþ›lçJMʸò™4LŽ0Âá3šî Wù_õæÜ9ãû;¤nºÚøŽ¿«Ñ F¨½>ÀCþ–ܼ¯œ‘`$~†(|¼߀Ý×.7˜Vß#N÷±¨¹Ä¾R0ÿº•¬Q®±Ô¼æDæ ëh2wQƒÞîbÆš%øw9ÖWùWbFqƒïÉŸÈã;ÎvñUZ>Õ€o,…“±Øp±I‰em^6.Áã®Êay‘w5o(µgø¿²ìÞÕÁL³}:¶,ùH€H(rÐ ó†ÕDº½ånMTeWêLóZ15û/Ë4¦0/ÓSE¹i"ËÉl.*‘¼“i]Rùž÷mDœ„'þº¬œb­‡Úï §Øþy™, lÛYÿÿÑž½·vm›0×Z›¢ÆïhÕ}4–¸JÙ¡·vv„×¾M`z1>0=* m­dRò¼ÜmãQ±ãÅ&Q™ØÙäe„‰A»¥“Ks©Í|#´Üen$p.VððcCÀÑÜåZv¿è¨€KS"ÂAã¡zO¸ª $Þ*"ãz]3ð°¤Oìø[Óçì Žü>×…®+ƒÁ‘Ã$Gla´_)D¤"Š ö|ÄáéB𹺩ÉjËI5û¡žx³pfÂl~mUùŸRÖ´ÆnY±€z0ûš•,¼è!Ò5¥kp?d^“†x d®±ˆÓƒ¿Î ƒŸ"ܯJB,ùfAqEÚhoá.$Ü ÇlI˜°ÆOár5ߤoe‘>|ž@ý¡ÛôÖ—Ä(‚¨Ì—Õú m@€¸Ÿ°_Œµ-ËM8æaÝXBõ³9ù)Qž›ÜCc„™åd;•åú’\ªQãœg@ R첨ІõwM¹°'ŒûBñ»Á.¦ùË9qgWU„Ã/^á9x…Ïpzãk-ýÇgýkÒ_W¹â-SQê^4: SL¿½oª+bºž™`åtùm¾\ükþë2_½b^\†¾ì¿ºô¼M/àÀɳŸ&_•’D×ÿ 3¶¤Ô€Ô+üWTœÖOð× ü~v‘/Þ0óæ†++½f6»Œ—¿zþ¦_h_o‚toÁª×îì ‡½}–zDöç~j>ÌUoB™áE¾zÓL¢žõæÙ7ùêÇfêý(e7o·îå_Ë·µÎ:Z• yGjrðª0³,Wߓ׿«ùÓ^°]vu“Ñ ÕäB†Ï·geÝÍ…"¸])Ô˜®ûVÙ˲goê¯Ì‡å]ùÐïYÚÙîÏg%§×ùjùÜ' ·l'§eòÖüBV·å[m¨kN­Ï•A¨š,þu§óÇ'ÿµ*Élendstream endobj 810 0 obj 7616 endobj 814 0 obj <> stream xœí\ÉrÇuè8ÿÂÜ4ãÐ4j_|)ɦmÚ’ˆ( lDA@"ýÒ;³ºº*«»z03, 9A4z©ÎÌÊ|ù2«怜áS†ÿâÏý³ÉÎ÷°éñû ü7y7UJšF…‹ Õ¸©S¢njã søÀ³“/§×W7‡“¦|²ówüïÙ·ÏáÇ‹¯¦š|ýbú‡q¸`S'}ã`î Ž·ú8lú·É» ROãý³é³]”ܪ©o¼FMw&­N|êY#¤Ç—ñFÀ•³ÉëÙæ Žš‰Ùåœ7^r¦f×xÔ—³“9ƒq”ðfv1_hÕÙÙ9Þ(¼?íþcòõîd ”R7j­ÖÔH°^¡ÏWók,cÎðÙá|Ác¤—³÷sÙh턘íç“Wí¡‘.ꩵàC3p-éõÖžsÝo3„V£{l`ˆQcÖ¢m·3”D绳ó2ã× ‚‘iÖ¦˜fÖ8Ýó]ã]£E;×{sFj­f§áH9œs<‚`v»s×Ý92M’espnÚÆökÚcm=8÷ 7…GIЫ$ü^:wœŽÎÒÕÃtî|¨$øzÁ"‚*DÖƒ|¶±¯´¶·‚ÍúÓ:†Æ«õ‡ª Œ£×­ÍÂŒ°ànç !.*AQ`cASxzK)k 0 ¾Všãý´åk@™ðöÁÔà¦Pã, z“Ô8í G'éêeOñÃÇ”´Ò5攄l Ü‚*yUI6ïzŠ—Wß÷L`íê ½½ÐYÒDAÊ¡ àí°èó¹Öˆ¶qVS4^Ùµ˜ýJ^ö&½Œ`løÁziÜÁ­½7âX£¹ ‚õnЪÁé!à“†%:×<±rk÷Z¦·ùïѸº^Ç÷†W =´kœp%M‡ BEÃY’öZ,‡ÞbÞ´LYäºÕ³Î~:šuœ0ßwÎ:Nðûæs)ë •Þ8éXP|=…7N:Yέ眇Ð"本EN{ê¼zRÑ.ÔU¢…)&âÑ €íÈòÜ’UýäR‹oÐÊ· ÃŒ)"{†×á)‰2GíI˜ã‡-@¶šoçœ5Òi=û¯ïç÷æRJÓËé%Y mkx™¥Ðg11 ô×Ýð™ûIWë»þhº²­Û(’°P¾g:›Ò•áRç+(sï»áÓå+"èÖÖC¨Qã¤Þ¨Æ~:wQû¥E)«Wþ­¹Úrà'Z?Yäß«|É·ãóÇYØÓÃóVmï[#¸~Õ²²‡NXè„8Û~Hlˆæmß ÑlßQBáEŠ¥ÿ/ …/ä>jçDtÀ¿^â¸çòfýˆÍÚú-UôVM9Çöj>° áè:mä T‚‰{Ôt—Vª‘³z¾ð^7Ú+lc:†T>´1á‹Û£9¦OÉ0g„q”!WÏp@Î¥”ÑûÛëçà^ºw݈‡m5‹}Ó—0/ÊjÇ-´}ÈB1{2_@žUÞc¨sðk!Míõ8•`ª‘†™þ5ÙýËëÙ.ŽDGúpXâ°èñN‡B>zƒÙE—ñCinH'€DêE?ÐðNòP»"å•"¨s‘E¹B»ØÈ]*ðy‚Œy¨›b€¸†W¼t!€Œ+Ïg¯R—úu)4©´®3ô´#O]&åª"/:ÀÍ1¾‰à_ÌÎE"ñ˼ƒªÝÔ¤²¼ºÌÉÙî·Ëë6ö%6h$@‹/óÁ¢GwòÉW}tDös@ü8KI¬Õ:úÇy·Èãg¯Ó UJÜß'äFw¯¦¿u¹ççØ’8‰üDz"|àscucPÅ|x¯9hØm×Ô13Ò}º²+j÷zŠ­Qâó¨iG2 Ziz[¥{Ü\ÝåMÜ¡¨‚Ëø|W¡JÙðr ­NGú[ŠƒÔ?¥§êQÅ4ß< ¾$®9¬o2Ü£^÷òJ€Â|òU·y»ÒK¾¿8þ'Ñ`‘dÍ;%ßVKȵèšðw it(M:¤mAÉ?jH·T—7‚ñÎ_Êræ)Æ4ÔsÜÜ)¦-‡wAÙðKv¬ãnÉ&l̼«¡Ñg<ýÄ7ZAnïÜcDÉ’z­N‘ÿ QÒ†?.…Ãh |òQj¨;D ¸±„’KМKS("¢l‘õZ±ŒiñÉ×¾¬ÞšccX0å.eŠ9(3<+ú¼i“zìåÔvëB0™Û“¹Ð XY—=]Ú¶ˆ‹ÃU/)lØ®«C=Ð_4"µx¯ƒB¾ÝXmy,¯C÷|,ºU\nÉŸ ¥¶IÖ ã±gߺQÏs=T_X¹®bZ}‰ƒØl'hãH+nÇ$úüNu_ž;’Qˆ£Ž“­Jýt¿lñ6Q)&ø6Íôb¾ÿ&²¶Ke‚CnÆ3R Öú-ƒ/©Q‚Ê¡Î'}^+ÚWA¿îìšÿ-{LRm2êi¤D6íÖd21þÍŒùèÌbW·T¹Ý0i9oj¿ÒÛæ\Æ;Wh¥%–»Må"~Àá?IcÜ1 ƒx áËqµ(l‡ænöMm¹é¦‚Ïu‹õKš:~—Æ¢–¸û”·¾³n$Îè8ÎÄA×÷\W*“ÿ[µjÕÛ»ÿÓìoÈèoæOôöqøGÔzxœ+ߤsž§¡ÉZ†cc—¡Z2ÝÑÜ”¯`€nþs±™†8Uugd? ñú~Ñó4hëFfy‘ŽªuÅæýêçO©?J1k]»%½¼OØ´2«o »h»,Æ‹­ÙkåE¿ø½oîîÔ!»º3ácl|Óð ù¢߀UíÏ c»º_ Û\’[ê½BÜoôTüá›^Ã%üUyà'[(Ã8üoz]ƒÖ›jò4È#à Á¦u½ IÒ7á)dËL½÷Xÿ`e}R¡åÈ­„‰½Mã¥Þ§[½-ýh¼aX`¢Á?DHtªM½[‘¸ZµÜò:ɰsüÀúº<ÖÔÅï‹çЛQ·þ©ŸúŸh¨ÃûÓDÊÖš’ßRRà·^§\Rî„yJúµu¨~Õ:´¤„¡ÝÏÔt¦ÕI}€(}ÉõÝä:¶endstream endobj 815 0 obj 3232 endobj 819 0 obj <> stream xœå[[SÜ6îôq_úühgºB7KÖcHÒ–¶iIº™v&á{h€Bnýõ=’méÈֲ˲ L†à‘eéè;ß¹Iâ<£„eÔþk~ïž Ö^sE³Ãšý ?‡ƒós]²æ×îI¶>rÝxfˆQ\Élt0¨`Y¥3Í(¡Ðx2x›ÿP KRZʭѯî+†¿²”)ør´½ÿ(†”(c”(óOîËÊ‘ŸCI /•ÈwêÖJçûÅ¥J¦ò‹bÈ9#´,óqøêZeIàý³B’’K£òÍ‚#•ù4ÕGè©‘‚åoíT€€ÈŸ„‘âG.$Ñ*ÿ p:ÖT–œå߬Šh-ó#×*¨f^¬’ç»õ|VËm+ñjÏüjÑh†%ª|¯LÊü‹•LSZ)†¿» ß½¯%«¨Ê/†‚p#»zí¬µ"š!Þ ç³Õç‹ÑàÕà<53àë*Œi"+K‚’ÐÊRj}c°¶ñ2»¼ø´?Xû;cƒµ_ìë›Ïàׯóì»Á‹ìÕDc)¢ & ´`²ýåµûH„ ²•y +7¦Õ#Àù$À´2¢l°r°½ÇŒã’“RšVá®JÈü«o»´ÈB§º@ï ´Ã1¶ƒ^Ï‚¤Í£¢%V<êkí@B¶,ƒ)JC+L-Ô!=BÍHÍx…9RÛ;ûÉeÄŠ­z2Étkä‘kãÔVUCf€ ÎЯç&Ø//QÜ`Oñ± #ØÀ†÷-ƪÌßåÞÔ“ Í }½+Ú¯ÒKm%_Ùµ†¯¾u†RTi¿>XëôfÌ*®qÃ?í%3 K×'òD;oîd©„äFÐÂZh > I½<Zö‘Ð ¾CgÝut4(æmœI Ï? Þ èÇYßÑ7Fþ‘Uàü'Dì^,r6øJC„Ô±ïzP;*Æ#W!ÍV`3Ðý|IR÷qÑÔaÔvÈL³O€º$ngå%^ 2¾½fØŠ!°ÑÉLz\›†¤-QPZ2F·€g0Œ½îf\ØBènjõºvêêÞÖ”Ô½¹Aô´Ð ¦è>šúm½u_›"ö³>Ÿ°t#T´ð÷MaRݤ^[jº:°,¢\yÔPÍ›hϼïsÏQ»íŒmV2ÎÏWÙå…û¥ôoÈý´Öíq f´]nÄ ¤Òqër#-WÖýß +ïêW –¥»õyýÏÝ€´ª^üñ잺ëQQÙ]fði?‚-ë¸=‰uG—‚]F6ƒ˜óÁPÅG1Û×\¯}DÝï %bXŽ ^ªi™.JÃùÔCÅê9bvàȸG·˜y1Dvo]A]¨‹n\Œã¬¤Y”²•¶Q]Ý:ृ^ï…z¶!ùˆî\s!oDNÉÒUØd°£8·µ¡'Ķô­™^‡vw¦Õ­ĴÍÔWà/Z;z:MQ‰ó/Ö½²äŽ=ÅBÙlÎj‚ ÖYq¿y³RTÿÉ«è(Ä©tüNê0MÕf3Xê*º¦à7ƒo®—&f?,ñ;LBt%k!pZ½üSSä˜ÂnfHÁPWØœÔvn·g§ñ-¹ÙÞIõÝÓQÒIŸ&$í%‹Uiç-—~Ç)Y’—°ü–¶X Ìú v3Ñ 1‰Sq³˜”<*@ѧcŽvHLwm+ÛœîPpRñHæþ%8®ö|۳˕&àòŒv‘‰üÓèòuçBbLå¶r]®«ôsºÔ§» êNÇz£ß ê·È´æ _ŸDzèw“õ(±ètpéĶt6ö˜/œÉ\Á¶3­ ¼ïùz”§Ï༅Ñ]`8{¾p%±–V¿ $í“}m"/7“AS‚PU-´©5÷´œþs½Uªu|ÅÖ;Äåâ?Úw·;€eöÜ„KAÙ¯¬¬}#‰ê“YÊ“Åò9B §2rÀ¯¢¬¥ôc*±üßâ¼ü‡ÎGendstream endobj 820 0 obj 1827 endobj 824 0 obj <> stream xœí[Io7Ò›/ý º˜*†û’[ÒÝÐ6MÕSÓƒmÙŽoMâ¦þ#ý½}äpÈÇJ–ËKPAh·÷½ý‘þkB ›Pÿÿß?ÝyòŠk:9z¿C'ß¿£¿vX2‰ÿíŸNžÏÂ0>qÄi®ådv¸Ó-À&ÖL £„BçéÎÍ—íT먒Î~³žå›”i˜9›Ãè¯[I—N7»í”­ÓÍ~×N4oÂjÖAó ˜·S.$1J4¿·SJ´sZ¨æÔ~ C%ι淖'•ÍûV¥œ”ÍY^÷=Œ”ŽHÊŠÐv'-,¤•â¬y’›yÙƒÑÑ¡ÙS_`6íÉŸ2h1ç:6Åì2Sñ®JŒÄ-t.Dï —ØÎ|úRã–‚/¬' ŽRæCngdÏ»m­‰ÇvŒ©n¤¦ÚlØŸàØD*m‡áŸ(lÜm¯‘°®—ßö,Aw xÝœ >C`|È„¡f^¬#\rØv¯e–pbv‰—M“<òœ(éšYk¡Œ9̺½<ëd<ˈæ;t®sl2"¶x³hG„ÕÍë¦;-Õm,ŒÆ2õ®5Ä¥Es”AÒÂ&d¬hžŒu>·è÷W–ó~’•^·iûí1‹,”(Æ×e™’D³æU’ɺG\Üa×»aˆP™4qQñûÊENÅ'š¼½´óñsYèŸäÎEN°W;aÊåÈH×ì’†[‘ä[Ä € ­[ Ã °<Ò¢häQnöÈÐϘ7a™8õß÷6<@Øàl¨vÑÝÞ&H—iôuá(® gœÜJf¾L‹¾-]'ƒ_ăP°ûÑÃÒ¿ûƒÛ«'÷é%å›`øcfWéE\¤¥FLÙ¡€· ÂÃR±ÛDæ6”ö%Ü«Ê"Oi)ëÈœµSA¸SÂ-ÈQ;ÙTN»Ðë$Æà¸»Læ,Ä\š0-àóß©U.Ê,ز¼+-šÌjÀIc ©[°ã–+ˆÀ…½jr…†^&Èvq0eÚm1#wÑPÔÛm ¨aõ¤}ßÇ‘=ØP\< s =Éßó±ç¹ìQM ¬´@ß3Ï,A$KŇ2å8ÃEßµ^l¸€ß{@Gq%M¢K|ÀN3¬CÞè2ÏB¨]äÞL48f1e’ä{#ÂÅ!®E:–’î5T/üR–h®ð,D×<‹c¯ÔFb”G)%Ⱦ¡ŠE-ð»"x-0<”9oòª»EÊØQkðhÀÞˆ‰¾÷©Ž 9Fbà›ìÆ­?C ×&áõêô"Fžv"Ã-If"Ššª œÄÉXyšJåM.iнäÃÚ£`6µ/‘ìÑyŽ‚áïK ìÕGdÍëå(óDá™/ªöþú ä÷Šx#L;²#g±ðøî©4—@²M*5Þ/`©îH3”Z]R¢úÁHü «j$\÷ô–¦‰üaÖ¤¬ÊH½Ïªk2p~[ª‰,fU+¼EfDÌ×Dy/bÕ“Ä+Þn¶‚dÑ·<šç¡%ËûV5ôè/L„³°^v G!ˆÌ±0[S¦ßSnQ¢-Š  °„Q½¾÷?õïHà0‚:âc$Èr-pÀ$M¨±‹Å×Ñ ¹èû¶îh$`«í;ÏÁyれÄsàŸ0ðÝQ-¢ä0rü:Ò)d‚»˜ƒèäx?Ú T*è„%=@§¿¨©Äù@@ÂArçÈÒûÎPHBÁ÷Ϋ Ùù^Áø¸À¨CC÷’9®;ÿ‘Y Š›€beWr˜‚RÂT¼9$^ í€N›dm@#k€LŽÈEò {Î0ËPÉ9ö|Gy³ä, øÀÒýIc±û%¡7wSÁÑ­à›Ð²9ÊGKÍê:Ѫ^߀åÒ±JÐÒåÜÎuòPçfS,Oê(ñ÷ £iùÈJ¥>é&m7ì|-7~£ÿz˜úŽS+Ï=XÍ1bÔñŽIÙÌ¦Ž©¸…\Œ3ÁQA( YÛ×:Gd¹ì2ÿ'\‘;lžýi9™d\Y0ûA û8š†©A=Ôšf̱JU²Jt´Ö¨Š/PÖÒ‡žœ'ºY4Øß~5ðCÙq‹½|„&ûÆ“â„>ˆöÕç @$„ZÖÀìÓ 8ˆù°òºÜ»\ä3ÑR†¥ÿ}¾(5…ðO‡Ü 6) Ç¿ÉÆ®R¿šµRK^ˆøQ}CPûâ,ø~1<ÁàÜÙà©Îrmtîþn÷¼êÔÊ W€´áÍ㎥” ìBó3ÿŽB BµÅ ×Uu‡¬°šèUÎÞ ½+<ÙÉVÜÉß§`$s]I¾ì&QˆÁ¶Åì»î_Z°?R1,åø)Ê‹®öl^yƒ Áô®Š‚7SÃ×A[@ágt`8VëÝeј ÈwÇè¥x·!ðRµ7X¾ùÖ×à”¯i¡E‘/8áž%ÁQP?(®„pº¥³êØQx4ô­ë€¿¡½Ù*J螦ŒöÞô/ÝÌ‚YK^ ÷êS ®Bê™o4™«*ö5o¾J<(ƒI’Û¦š× Ë9þxpÚ²ÐMzË)ŠÜoÁMez£÷E wŠ‚+W‚äìøž«ÅMÀ5dȹQé gfR0‰ê=‹ê ×%2?,½Œ=ÓàN!®eá´ÝZÚà×kè(P® '+µËœb¹™v=Ž,V×J@½ƒn¥‘[CyJäãsà¥{Fi+·ç·§<[2Q+D¶ÕJmè n‘ÿ ÕݪMYŸ Õ B°’­êŠÀkÈË2Se‹ ¥¥Šáñgl©VOH†(CL@åïa’n˜ôxÿ½ë#ÆGˆV/½oÐút=¬«—”5½üH¬Ä¡’˜/åz⯪Š>xÖÀ9©¼0©Ý,ù¿R1Ëøf7Kõš#Z«þ’Õ¼G/Bó¤àßò¼»~Ã> stream xœÝ][sÇuNé/ù ûæÝ*íhú:=yeÅaªK6].'Î$# H@ôCò{sN_OwŸ™ÝI8I¹lŽggzúrÎ×ß¹5~ÚŒƒØŒøŸøïÅÛ³¯þ í¸yõálÜüþûêì§3áÙÄ.Þnž<óÉÍ<ÌVZ½yvy7m&1#Ü|{öÛÜíÍàæÑèÿ|ö¯ð–§É[ãàL|q¶p{”ÕÛ/wzpʽýÙ_Ákñžvb{¯nó¯Ò½ð9i×I¡ÆAÕŸÚïöÒ‰A:·}¶Óz˜ÇQoï|ïÝ<«íûÝ^05 >›o~€—&5h3ooÊÝklJB 3tVÊAK#`vV À^ Ö¸$MÝbSvíL>µÊmß…GÝ¿4 aâ“f¼?Â8Õ8‰íiŒñþÙW¹ÞGè–†¡îÕ g˜âíëò(i ÐÒÄ £â£þ³×ùwÒ—ô~ž øù®| GíÜ `vj0v´Õëça”Ÿ f€±ýú-ßiòûEi»2OðôD›Å»Î FUß½‰K¨f¸‹¢$¥êM5h²®p ˜] ¾µ«hì’ûš´[‘%œÌù8sOi0Ö@—»-ŸšU%ZÒ:šÞïê-,ꆰÃ83¢Õ†fÊÒZV3³ª»b‚c‰ ¡uldö‚ŽDá>…aFÈq ´œµOç; ŸÖM Sxò ¬°>¯RÁÕ÷–ÝG›HIŠúM„ª¥ãÍLV´2­™ ñ½­Œk®ï6ÊÄG¹*§ ØŠã(q¿…M[©ºƒ÷“‚è;UEÉ€ 2¢±¢?.`–@_6.hdº!E«o"È‚~¼Ä»@º2ejÊ­3aÖU¬íù!XˆpIÆ ·ôZ뤤žüýUáá¥C° fÄ­ 2dMQþ&§ ´iƒ è ´ôƒG„œ1²×hkí÷„óâlK;ü*/D¯ÊûE¯±'#wîÔ8™ç`ÐÿEï´ï Ì Š6µ[„ÁM¦­Š-¥Î.ÁYúÀZ(ÑëRãÙèûÔx^¼¢ÔûïÙ­=/8Kfn|<ÅζÀº/Üéº<âìKŽ*†ge1ȃ¬[‰û|^ž&¤‚N3ZÒØu…)rÉÏ'A¦bcÜ -דTu‚„Žë©B3ÖDéü`Y°£àܰd°Ñès)5 É•Úã5¬Ì9\aÝOüé¹R€ÃH%£[$åJghûå¸l(á½D´±}ô0B§eCsBê=º«~¸èË_| á·í¶îaä‘é*†#&.ƒÏþr(vSã‰pFIYÏÙ–l²‡ÊPéxl²b<á™j’FٮėœhÐ=qPëŠåiìæÁûò›Ô tS–䬽ÙÅÕ¤ûDº8;>&=-Ù™IÈ4Ý\ß·ÚO§·AØbq–«Úܨ•9eׂ®o©Ù±Ý2)eÅÄdúym‡À›Ë‘@¥Á;ô]±CW°2€.kbë%f*iÍL°€TÎEÔ“[È“ ¹ˆÍ]Là“Ž±~Fz_b‡ü„m¥ø‚šu×çðê%á¿Ç _³Ÿ–V(P-|Þòa#ËM„ð5Q)&Y€ýè—QáºeGbRøŽ°íÔJü¦\¦]òö ˆy+²C”–”Õ~a’ŠèieÄ;— ¬“$Á£±>Fï³'%\΃Ï{‡¢%Ø×d*½c¬Õ‹öÒ÷‰‡ƒC6dôEù5­­ÅÐ3i Dµ*WhŽT‘|˜Ï¬¬ô˜y«ßÄ““É o®.’·Äú½ºþSïØgQ޵ Ôo¼C Ïßç½ôOÄÿX”ãј ̉‘‹L3r?0&ðU¾÷ò8ƨLõE¤‹èâ€í·LH—%Þdc®³-ÁìyáÁoM®¥Gz>-Çùüâëù`£@HÁ°cbC½px/ñGÊ…¡¬ÂƧI?xååˆñXÚì>ZÊÒ<|ñ£ËøQß×´BÞ‰D"åóóëL …ßÍöeäÃc™cðÙc‹ñ%ahKä]¨u•š‡ˆSÃ:«É>_½ÒˆftŒõYD¹ÁÐÙÈœn"PÊó²%øO ` Œ@%õößn7žùX Á»k¯Â*L¢[6LVĶ}«Û”¹ãŶê ï»&c¨ m8zW8JÎb¯´¨4–ME²y{'ç­Ì´"\r­þ²#0&Qmêw…»ó÷ÉjÜU•<=JxAùýø¬9:$PŒ‰„‡êd‡²ÓÒDˆÛü[Ny“.ZL>ätÆê[uÆBYÂ_§ÎùyKÙ0µÌ«qDr¸Tε,e)©Ã]ÆòVCƒF“§HÏ›ÈÙ…»P¹Ç;˜¿h¼ÍÏÙ¸“k~‘¾Ú. ƒP ¡ä¯°z!5‰·Ö/XÐàûp¿3ìfg3šyyâ™)úInØeI>g1“}ÎlåÙÁÜg.c2‡ ”™hueަ¸™ºÍ½?ð-¾Œ’0ò~íf«17éÂ>H0/²o•m¿ô”MnéÃXmt]6ìC‘v»} ©JRŸÝRRèäQÓãÔ„æ„-!–ÿý(jªŒç¤´ŽìHH;c;²ÏÈœóßš· Ñß®ä ìsºÜÒ@_O—Sv̰’×»A[´`æ°)‹ÃmÜ i_a?]‘rí&}ü²$¨{4†!…Æ•cSÙ”>¢E½ é( £ƒWgÍ€zBcˆjòAèTÇGtþ£„wŒƼT=ÃWlÕ¾o±Ú.w‡0/D†î e»Ì÷a Ž®vH•‚çÅ”æ+ž–b¨L¥7³:R˜Ö©a>À8/¸|¯¢©2¡…ÛWjõ1i•Å;™*’f³Ð™C±nžŠÝ—=¥vU÷‡ 4é…T„’(£i é×»b2¤‘õ³•„q¡\#O1œ’4Î3%IäÙ;Ú1¦”"Å—AœI0¼¸~cɃ_üÌ\ZJØæÅмÙàÿœž¼à"èùÄø¸î.³6zK©-GðOF’Væóz5ì‰s•ù^¤³©X3ÍNWýzðLc«Oíc¶¬Þ×½ àþW»¡4ÙJµ›)eN/†™S 0Y ÒlD­™lŠTn„Ž0M­£œ1¢ùt9ÂíØc&ß¹sÛ¤\ö„ŽÒ•Ãubù€Œ®¼_:T4TõµY¤3?6òÎÅl<{—µ¿+X2jp¬“¼,fÅ>fçñÏj(ZÜnòªu455#`uŽq:m—Ï[ 9í•Ýt—5Ìݲ ô36¡_P''ž÷M=˜ƒ¹-ØÈ{aº`ïÅtEL¢NÅ\m*aÏ‹!3¦ÊvîsDTM§~d©Y“VˆÛZ…SÈJ ¥Z™>­. r)»¥ìî|!h“D{³19%Ý#ë7;cÀ¬³aã…]Ýû'e¶„±D£¤çR‘We'Môs`.!ÓŸK⋜*ÒÇWíáG)Ú„½• Ç›fhðY®l̰ˆnR\@uv&£Z8¸©q:xÔzgAÑþ{vÒjZ>°TüZWÉàv­E¢&ñD‚±œ¶”xuIöªÉ¸/.””>, v¿Ä“„-p°@=Ò½k…ÝЛŒÈå n¦‡FÍ3fE}4>3òè£ÄnÚ>ÇÜ¡Ð$µƒ9`Küø\5Íým ·œ½Yæ!çQÀµõ†×y(÷'@/íQ iÑYÐïì‘| MsN’¦OÇÖr¬–Ç*ôBœæ²TµÞ†ˆ¢ýh©ÎX"«·¿'°~½ Ëiض²†ˬ#²^4ÛãKì´W.\âéö ¾îyD³èBHˆ¶èið¾”ÉÕ \sq‰òµDèøe'æ9ïÆ¼Ž`oeÃ?1¼5*’>ĤxØä~æ’Iù‚ê&¥Ÿ Ï¢ }éLc\÷b9ªì?ÖæMÞ1‡“cF©¯y­O÷¹/eíÝda(¹­½pÉŸÏZéMt"ž×Æ' –#ç~áèùê?U/Ë©Âðt a üÿx™‚ÁF¥§TÍøœ!ÍÜ>¸g~½]%Üí¹ÍÍ@R‡¼mƒÐ­c—N y÷²±¬¯ÂL÷þöhÃ&^<òîéÃyÓija°h‘,}·ÛÉGƒ“0þf8çkï®’’D”€œ1„ñçñ4³Ê7Ä{&ê\77òq¥©ö²bÉÄìBÀ®Ä¤KÆ nYÖY-bGxTŠ"‡Æ¼¼R ß$Ø]E s­"¡ Á;²¹õÉÑ)Ë5F"O0áRi€Z<܉ øëÚ×ÖÇ yo§B×Ê?tÍŽö>:IHu>€7§ëm=ÊžVÉ“Çï.ž;ìŠt€Bâ£- iæ\Sp°ž•9Ki± "añsŠSí?Eº\ø`‚=×y…§µ=RçÕÜvþÓù_OuˆY5Œu³h–‘¥Ô,#°Ó%h65¿9,¹œc–Ö>I/æ?Κ¢Q_«¸„VY}—i¸+¶LììÿêúšZLü¡IÛãg‚DdN Ûl¢g ,æ¤èò97¬¸†£42ƒbOÖž¯ëåëRÞúRKã°‰¹ù0Éï¿vžy¼ÄD7éÀÐ^8)&²©˜H{z"ž/ªšlW_ 3EOÈ¿_±M=ÌÅʲ·ž[ÒŽ VÞK—Nc¨ô™Ð>ˆ!Aa´ž©?‹·íòøÓ7©–ôáù&ŒCŽv]ÌnÃn»Æ½”]ùñ(ƒ‡Wæ`Áý(¶!<`ù:JHŠ ßE.`ð”Uê;ÜÁ•µ£Rß?½þ—¶7³0ŽÃ62•NŽïR°ÂJh‹ôÕ)ó"z¤Ž7µ‘ɰQ«˜€j&<\®?Y£IfŒÕ1+µ !…‰(f¸W+Ð>³rö7®…yðYö ª•œƒ¤Ùœ‡¹$EØ"rl¾&#©É=ç+ÎVNÔð3§—iF­Ä~5ê-˜O}jí)ŸvØ— »ÉÏŽÃÔú+sèG…åRç¦î&^ºr©ò£véÑ´™WÆÃ“}Ÿé¯¡ËÜÂï\BØþÅ ;ܪú¼õ…ÃNJèñFo§ƒ1«ýP¡÷¡$.’_”­Bßë¦ÿƒ&ì§>‰á‚wÇI¶Ö'èÖGÈÑGl­#SqmmùGøäkÌ+¢Ý5ÂÇ79¯èJËW^ä¿!2mŸæ=ô{d)ÐO[áFÙc \úJxšì ‘NZZ¥¸’oЫÃÍâŽJ]>&0þ°Gù;{>‹BËÒ)~tCó^3ÍôZÓckºS€C§¢ÅƒÒäõsy%_ï C‘Éc HjûÏxôç<™æØ±dðu ‚nع: j±/^”]•ì{YƒÜf[¤?paVìï 7Kô–¯B‰úÓÒ,êž¿¬e¯í94Q1 ±ß/šÝ+ÀÛÝöuF¦úOA佈ÿ0M\üC?l.!O…ÑßmðˇS Ùchxøi¬¤Þh2ßýŸ@z¥õGêT™~ÍIÆ« t£m93_ÛÌTè8±h=‡c}ž0Ê>Ó?RÓ—a/ »|¾)ÂúZÑd“¹IÉÑ×;Ê’Ýa1^üdçÅ^ë6€RV0Ïjçÿ>Oãmñ‡Z¹ªF“Ò®‘bPì Õâ@¨¸ÙšSyQœwr€[ÙŽ¿1¡ùûŒ§½á²õÁ~1ÆU[4‰â‡PŠLà'ŸaÏvJzãÊÆ¯*¿iÊbpmfËÈ’ñ3$ñ€7ÂۿŹ6~“hݧÿÛsUr¿Lv™·ì™ô™†o¿-Ÿ<”æÁ3Ý©‚€ÇïßO„>Öïðu˲?Ÿ8ý‰ìp4úã§z:Ï N?lEÅÿw\8b >«\³¾ÌÅ ñZ~vuÿ=™EšH\²¡L¤1,„ù¿°A~Êá>Li°Lxì*Î=ý™z­Y,r©þä¯pþÌ=þÁ»0N“_w•ù¸ýgÿM¹@ôendstream endobj 830 0 obj 6343 endobj 834 0 obj <> stream xœí\Ks·®Rn¼ä/ð¸›ÊÂxcà›•¸l§’Š3'+zIJ*Q$M‹²˜’ß›n< w©‡%9*–JS Ðh|ý¡nìO‡œ‰CŽéÿ틃/þ)-?|òó?üþ=9øé@„*‡é¿í‹Ã‡G¡š8ôÌ[iõáÑÙAlŠ,”qyègÞ¼8øau´Þ(&½vÓêézcØ4y¯V§ë`ÖaW?¯3Æk…RKfœ"…/×5FŠÕqýˆ”>«Ã¯Èû-íúòLX¤ÙëõF3Ð*²h¿ºªb×÷¤Õ‹úžtKFxm)Íœr¹/uãg^*hËÜ$rÂaÝ00Ë­Ë…VMÐÙFÁ¼·´Y,U07ÐY”Fq'²ê'GvºK˜ËòÕ&¬¤_Wa¶µôil`â6i)HpQÚ"b®ÿ}ô—T޲€ £ ÑÀ«µ˜˜˜L3Àóú9ƒž˜×Æ8la)),A hXn„gÖyÛÿ}*7:~d 2ùˆ³Étp¶ž£|ÎgkÍ&eŒ9ð >5á“…ýRž6åí³Rv5x{VÊj½Úòi.Ëãš°œi݈¹IóåìêÑ0¢×T³sø–‰ÑÒWó˜ ÅtkÀF¿+\â|Iî(°©"ã»Úë#Ŀļ³Ñ ŒK)Qÿ1ðð~KMf2-zJ3±IHI£ª™|vY á Š>7ud'Ô¾H%"¶È,4FQZ@[.µzB ÌU³$3:1³‘´‡ËhvZ1'³ÙÍÈ"è O3|ÿ§úÒq\ŽkÈ@Z Ö5ÀIhà¸å«ÀLºåìDÄ:Í®2Qn–pBŽÁ¶H ü7Æùë5HŠkÆ­]}µÞpæ8Ÿ¬H“Z8OD äF¦)Ï8&¼]Zíµ 8†\#£>ÍŒÌ=Yv††MÚº¬Ö|ÑÃ7/[R2ë%•ûÇúÕåÚ2a 0Ö+|‚™³ôû?"x=sºYöPlå˜âø…LÇØlÎ+|»&9Ùå%NqfHcò9n,Œ,|s³.Âq–&)Û×e`íº©R·¢ÆeÏ0;eû#„ZGBàH©/*@rUjmƒ Å“†I¨ÛñaXìi¯7C$=o!r ñ|J-5Úã™Qv´ðc-%6‰-xX½§Ì|¡ ¢ëZ:’"Q 6‰¦i¡ ÆÌWÆÐ¡"äMžž±HiòU`[¤Éßx¯y⌯«¯L,ŽØüÓêIžùá¢]¡q}㲫&Üï^×+±žWþH­EEóµà~ªFkbm\ÿã5ŠÖidƒ%Ø|Ù.¸˜+}BɹZð oz*Ã9˶©äÂZÝÃxhüÁä¯:ëħÎ}Æ%Àøxµäpeÿx¸’Ï|‰ÖH`÷ÞgÎx¼ÒËe5ê!?Ö^"‹ ½Ë ßöN× œ*åï/KGÉUuºuÅ%xòÉŸ¸ˆòÿ· bèßâ#ecð]Ù|=Џâ ÃW„'d{qyXg34Lp¤†eâ «ïƒ×ã'Iá¸kø¤>â%d“‰LàÌíǨ™‡¨™ œiùÉ醜?ü vS<[Ô|Û#NAÝcv”û¼89Äµé¨ œÍEvÑ9=' NÖ‹h¬ÎšŠ´ÎjÓÖäaÔ ÿáÔr´VdÑd(D?gk°ãI9E‰mb©_Òzó°ts»ëÀ„ì>ɶçzè­ê Õ´é³áG ×7b¾cÅÑgÈÝrE³bÁ”ï§YÉÕ›hö_„êÿLžƒr9z ïw¸HsOš éÞžèì{Ŗˆºè>VÌ¡E†óPÿ!¹î7 ¼wLwo¨Ü¿….îbIH'F.Æ^òÀèÇa¿ïR‰oeÜñóþÀ%ÉͱÜŽFçn{AYã‰KñÀù’ï3o¸lò8^¦ƒ_“kÿÏ‘üqLÂ.çþû>JÓ†þëÓ®E {ÐÓÒ]Á´Ÿ›ÖÓõy€§ ü¦TXû9~Óäf´º £ú0;š÷ªŽ&$7>ŽÞµ³%]>Æ Þ:A9äû~²^”²’yÊb˜<—w­ÀÛ»3±Ñ71¼*…Ïäøô9h‘BùóP¨òMp||è›+¶É! Á¢«Dè‚F÷Šë½pÐN䪅¤Ñ†uBóºÉ| Žz(Þ¬¹ýçApòdØ>qw†ùÃðé´‹®†5´é€h˜ ;.£àiÔ”‚mjT RB¤ÃXf'Ñf'PZïB|3.WB.¼ßÒ HI"b9ÊQÚDþû°lÐvNÇrަ/Ü— Ui1Q£$6z4)°2BÖcÌ=P˜ú#jöÁ²¸‰9êRCŒƒ¡NÞ´ñºf×èÓ“¢+*1Ú6£LN’yáv’i›;6h–„/0”kóF,›\â=Í(|CZ$ÙE4eÜìÎ`"&ƒÐ˜`f{ÛCý(O"Šä›Ê24'¤Ûìü‚l9ë§&Û½“4«É0x)AIZPß5]ítt\³/¢UGmò>„ßå"V;¡I ˜ô²&0‘¹½Mðw†tv:²9 î}h! FÜ“¢©¹æ'ƒFKÊWc-téIiÞ7|€'ÍVËš·kƒy•@t¬Zã8Ïwèåõ<†½Îò* eáöªÍ1 ¹OãM¡§Ûªõ¹×Ö%,§ç¢s õÎe~»?[;ð¤ó´}’;BFŽh‘ Ðû¥9ĬiÝšpÒ]™RUÖ>õ¨p*…Sâ X§uæ ^+ÂcHrpMŽC툗§¿AMP-×S=QÉßðÑ,‡·Opà`^am„¥±fÊdOýu³R%_ 0÷!y»Mb™„¦mÂN÷[2‰rH/J–íUq¿¯ËÓiq—«ƒ}=pη«mƒ–ËêÓey hÁYÁœÞ«ÁÇ×¥ìlà»×Ž/ºŒc|û²ëÎ9ÒܗЯvàÚÉÕãÇéuDGÇ&/-ÓÅÆrÍ´—+U y*œ$Ùq¼šç?©_uml:®©Co„6àY2kdªèÜ,ÝÚ¹*aR¿sdHÇm‘sdŽX.ºšk¯(tWÏ0µ’ˤ0çÈëu”Ëð)¡Æ¹Ù|yšwM¨*SE|ÞiÔ¹Ú:ÕvÒ±\‰ü–rP@µfš*;à[fÈk½ –šd¨´?øl½kLÈu-½g.·:¼·¶Kù(ó³­ÔÓ—·1“:œç‘¶èñmq„DGsqu ½$Gèž<½ËN‚mzØwÍ0]::ÝÓØ–º·Íí)á^­\»íüÝ«äIPhÉÉžû‰qÜ轞‰X*.ZùDÜÁäzÉËGX¥ÓÕhG3¥D„CjÕΆ«.”ÿÙª?%«¾Ýy{S,ñU§cŠ?꣕=Àñümù²Cw³uðnö&·©y-÷£{/¥qjùÞŒ’­Z9“­zOk vº]45¸úî¼_=×Ë#i ÍÉCÁÑ#‹2&g„ÇsŽ·¾•^(µë÷&ÜÜù6ði‹Çvá E™ôdÀ™±ɤ4á‘L[€©°%/@¡px¼’ O×34îQáÉ„cV ÷I5Ž J¼ôç9=8úÃ(S8{—ÐB:K4ÊÓcEKJ°BÍÝ 7 jÄ÷ª?…ë’aò ²è•„*’—˜R÷¤9‰œß¬l3Kæ¶¥¥oI› *=bªÝ{&`‚†Çˆã›KÛÇxìîUŸIÒæ*žc¹ì·8$5ÉA$9É®ºž]wî£mw]ï&áùÐ, ÏÇx ÁûCÉÖzÒ̳ú¦‰ÙHÃ8ž0Î.¤æ”àO!ú¤Ø›DãÈbƒzʇ²Uk1˜‰A³&FZˆQg=†®ÂEdó·Dè„€IÛükl;ø]=Þ'‡Ò÷¸,]à®®Á=h4EÍî4†>f0Ìu³Âöº8¦¶¬³AËÂûrt“šµ-ë[ëS‘óʵcK³´Mäß·Ø×$1ª-åüšy³8Ê¢Ò:t „™š;R$M¥²JŠÊ(ÑÄÒgéLÁ¦þSñ‡áЧ¾ã®tŠ] /ÒÏFØ]Ffw‚‘Ü‚:\ÁžšÔ‹–B³3L‡±l3ÔðeúI6X‹RK!«çM¶ÏìšöEMÿ¨b‚îÇ9çc;ŒÌ<F2/hcåwÆ‘»ŸjÝ›¡m3Êu=Iñ1 cùq|“è¼Lѽ©“°‰Ë=¤¤Ëv²×ðû6(*1sÊ1S’눓Х8pËtÌ)Éw32¨aZýÑèÏ?˜ñÏÔÏ÷H5“eÆIZŠ? À=l9öä!Ž»b½Ÿë37²òn„¿LËÿƒ`äm–[Ó—ª®N†ß·©­b߯èÕ®¼‰qnì8? º,ˆ~ê2˜ª•¯JO®l˯GnÐÁåŒ ðñ9í!jDëå4,ù°pì3 ”U–Nó9ìy|u/”[ËIåÚ”_8ðÜ· 98ŒÀ96ßÔ®Hq# Ù( g6…|‡i ã$ÇM±ëYîBx¬ïç]/¹þó®Rzš¤4É]öühô^® weI Z¬ß/Jq~O¬ù¹ì8w-õiÌ'9+‡vz–70 ¿–ÒLQ<ò±äg‘N‡Ä”³žD£Œ.IŒ ᢓ¿øMS¿mè3ŸÉ ~Žø…Ë?¥Âf¿À‚[(=±ÖŠ +šœ¹Y}mkÔ13Œæy¶¹ly¶)^†û„bsNïÜSô¿ë‚Ó ç˜> ü>…ƒ•ó*’SÏšÊâKXý룃Àßÿ3ã$®endstream endobj 835 0 obj 3847 endobj 839 0 obj <> stream xœÅ=ioÇ•‹ýÈ_1ûÉ3Ù꺫ŒÀ@ì8±‚Ínlk,ÃxI0EJ"©#c÷ç½ê:^U¿žR¤dÃV«ªWUï¾æõjÄjÄÓŸG/ý(í¸:»:W†ÿÎ^ˆøÊ*ýqôrõÍ“øšX…!XiõêÉéÁ4€X9¹rbF¸ùòàçõÓÍ¡¬5®/6‡fð>µ¾Œ—a4z}½ac¤X?¯/œÔÏÞl¥ÃèüúåæPA›GˆïO—Þ­oêÍó:,Œ%Õ8t3̃ŽÙ^ÔK²†3„K6Èå5H-£®A°¯ÍÂW5;ZG®Ò›V•u+á×ϦÂP?lŒ”Raý%L*ÂଆW…ä“Þ”^ã^À©)—€V£+@û2©ðÌÂ4+yºøn± ª8,Ù7rr/ê ×›_žüå@* ‡Èóä¸" .ûº?‚øÑeö¢îÅà` $}õᶃó Üä3r—Àý¡ÌðÏú¼6=O8àÄòvæ{Un’}»¬ Å’»Gu7Ò];¦“w£–r=À 4ØõŸ6¶Ø λ–Ü@0aôD/Öo7vW@p¼:ᦒž,¶;iÌúÝæpÜ8zÛ`Ä9½LHÒÖ¥³ÕÊ©.D˜Ã„1‡Bœ‘@ÀŠ&MÐ cIǬ »Ña y‘x÷´ÐgÃBX:^¨X?6,è¨âÉIGÕ–zµÌK”å.G¸YÜY G¯ å;dŠ£ ÌóD !0'Ñ–9¸"39éJƒ¿%Èeà)äº!ÜLo kâù Kî•‹%ìBLl™PŠŒz5ñ-UxÌ]™lÚAÁRñ« *a+'¨ Ò/ì³Õ„ÙNÛ ðžŸ ý>—Ô~ýds¨ª€TÒ¥¹ø7¸”ðoÖ zôªè÷ŠâQF ‚% ÔÚ€ ²ò §‚¿¸HUJèÁ›Ì9ŸéÝ g­ ˆ£Ñ<5½µQ–à AÕ;6UA%áé´ÑÉòI;Â]½ÈìàYšIÙœçm¯Ù,ÄD àgÊÈHƒß œÀZm¾;–¸U­Â“ž¡x$ó–⥅•ÀÆ?® 6*fæ¯êÍ p'¤§ª3 ‘^«ÁK»/¿5ù¤_ ù‚}Êýn#ˆÇ¨½O®–ÈwÉ ¨éÐz+§H'^ôaB¬<˜ÄÁ¨Ux“PkÍO©nÀYij âåWHLvá ÏX&@>{Vðºa â¹ÈœxÂqÖ&áB¬ö1¡uð¾}ÑZ L+ƒ›ùèGé4õk(Ø) ´Õ“ÿÆ«¯›uEî³ 9¦Qã¢BW†cV’×uWæþœc8ËkŒÌ.„ºÌ~ÎO{&P¾s³5:WÙX¿Â‚ .ÿÚNSxVËXÁµ9öX^[á•ôœ[ZsxEI]ÆËžõµ§¼ îƒZø´ì»^$™z œL«`<ÛJ¯‰XW@MãªJ ö)•ãA»vp·I߸ÉÎ`O­zp-1xÅØúþý!©ò¶ >aXwA&’0ý. ¬e¨C9õ±Ž*÷ÙNèÛŒ'ˆ+ù’›ê‹ ¼f=X|Äv Nª3Î"ɦ½l]Ú“NçÀ®Ìª;ŸD2K{HkŽæ-µqÐäÕfF..#{þÈæ{)jýhÉLÛÒ]:{k!,Äž’÷з`zh0d{Óã[bÔöNºèöš9ÀîÝÐã'ìê°øþ0Q »w‹n±u,܆Ð2+äƒ21@0cU8àwO~8x½RSNîWBH;Xã ȘŒöÍãƒGÿºº~ssrðèï+qðè{üß7ûþxüÇÕ¿|÷xõÃbŠÚ2Ì€Giªò ò{K`§n¼´4óéO´4ƒÆr³4Þ(! ãx’Dm;ÖïE„vzZ¯n·oÁ;´Ÿ?žÉÝ€Ü_Uß§vÕE·.ª|œìµÉ(€€éÌ_O»ìíNO†pe vÑÛz¤åu¬m?ÜÀè}°rì¶=H †g4;z=ÛíÞV,Z¦sÛÕsRï¶ÇÊÌPã—fÒ%ªpFóÕâ‡$m‡´g¿»žÝÅ”§Qmñ2¢ïÒÝ=â–_ÝIÙÖ¡L£«ÚênY"n/5Œœ)z‹GGAÞ‡ß7öÍqŒ ë’˜€û‰Ö“,u³®Žœ©µY‘ Ùv¨ª°òil˜0]¹&ˆ? À»;Ù˜óýì…ÔS¹Ú±óA«(f?ÅΗ¦ê0ªa`e O þùT«R T°{A'jHGqDÇÏLÎÆèDØñÉœ¯»pCã¿:žÂi˜8³Í.‹ùÔ[ ³ø<ÙZd†ƒe×5 {9 |ÇXAÃm|ú¹KÂ'ìlänJc%ÜÛå]”`¾Íã)8m1%•8ÌÍëòÏzŽÐØÐÆ1>€àÊ[ ÁZîm>éL:‘Ü––Üu6XVà›üÆÎ¸ìQ숵Òã6•=ÊQã¹d§íVòD”(B#“ŒÄt5g6—½FD<²ÃFT§{öh¢¶J`iíy´Ý­$JI†«)h³4ÝRÄGrÒëˆåM€ØüÓ§¬“hÓ鶴7*CxX õõŒCtDÍ-.ƒ¡v?t™%ѧÑä›ä”ú°”}GòÖ©~r¹¥Ä£X?rÎòšä€Ã›hðXƒa&Gad¼r[)}§f H&0/4aï®Yª1z$Ìþàš%gß@ü Ž>ÝÊœÄ5Ñ¥íáHXà"ŒÝ6-ŠÀWÌ_ê´Ì‚š’2Mª¿à8/÷g|Éïõj+'«O²›”–¾Lžá…ü…W|AÎó+y^óy¯Y¥œgfy •Ø3÷$†\W~YW¶…‹ÏÓˆ’ÓØ0«ì59ò]Ê3ÃH]©l˜ÃÕCŠzÚì”z†zÖrƘΨ{†u O¹{ãùð“;´>¸j˜‘aÂÎÆ,”&+ê¸z\ç9iXç/˜—¤º‰4R¦âûÕ<³-ÍÛ3š5_’3/Üjó1›¢¢>ç¯ ´åP˜j¦–3*BÆòê¥þŸ61ŘÎ]sÜPr¦¸Ý’h˜ô‹[pReÖIáxp ÓË‘•P ׸†zWBÚÂÖ(ìAãå+Y!6ÜÍ6Âq˜Šr_Žj‚ëè´*ÿ+¾®ÔØæë±›}Ù-õs‚ïµ*¹ˆ÷pp¢Am<÷Òâ~0 ŸÔƒ Lˆ÷œ"–ÅAÐÑ€k%_,Våz¡€8ÇDwÔ`uZ'ºÓ:Õ$éEtW£ŒÕ›?ÉMRKY³'x[‹þÂYñ%š$_Ï«j÷p$©˜z·’.|FMãdnícéhò¡ŠÔxÎ<}ŸLKÝ…,½Œ±W’¸IêÄÈÄdŠSŒãÂGM%_§Ôæój,ÎIÒ„IégëwFDGÖ³Óô¹Ýò}‰Ï 5U¦ML$¸³2¬ß¥®’’³]ƒEµÓ7À-V¦D·¡ŽÛÕÇ :ƨ³ (ÀâfGy[žß÷Qu7X®t™^u´\`H9šÞˇâ”4¥ÎÖrÊ tË)…1k`Ê‘±.™©3Ÿ•¼gwA~¡z.ÝÞÑ×üwUeÒ¹€&Ñm0äÔ”åNƒÂþ°šeGhþ쬊ê&!åWUÍ}Åø Öh'È´Wµëä3õ΀ïy˜u1%·åsq¬QuZ÷\;^PÕ++i­A”I–-}#ÔUeÎŒÇç/q—T$Ù{Q$öuwX°¸V¨Qe޲ÕÀ&É^‡åé!“UvE'µ@SføçÆÕcœ„.òâ$ ­«4ÕïJcœ„.êlX¿è' ‘%Ö~=_pqßvNÛ]>¤`8ªlÄ(['Ãgb±(âdS4]ùêNÕLÕÒÓó¹êW6¼ä–~/€¯å[åâ]{/½›Oç‹/‡YN\ÄuôŸÍýõg5%¼@PÐÿ|ÊeïQ‹q¨üìb†XoʳBeÏÚuЬV/ –1cô’å½Y|æ1ïMkL€"íĘ5ž(ðGíëT _‡1ÄÀÆY™ĪM®äÿØdUß0ˆà…%ñ°yû¿"8JÙ°þï ˜¸ÚšØ!tÄb©ïðRØàÂõ=5ˆ¤]Lu{,jÛùó/q‡<¨¨½ã Õöm ÃÇТÖzžü=Ò­ï¡Ý ¦j+ ØìøX´ãOÙ»ü»|qpé©v7`Ý )"Ï­¨º—Eò¾kuÖi®½ êUv•šûr™%'ñyð«jôµò"3`Ê5 põè¹¹=Û\âäÂQ#¼ܦugìÅ”<-Œ/,XVþís¨é@ÇÅõQË×ú’¶¶¥<]ŠJçP²Á,î~öe[\4ê tA}uÝR‰WoÖW×ívÖ£Ëæ“,ש¢Ë½êΪ­ùzËœdWè·gv©ÀÄ=‹ìRÌôQîòy›xLåãTžÞ®¿ElÚꛬ¾#(ß°éâ—rr _0s˺þØy€móÀ„gc›‡[E»&—úíVµÄ~ê-ѸüyÌé“ZaZ¢“UöÏê{&û°:Û¹Ù+r)y…÷RÓaÍáÛÞH/q‡£r­‚ÎwKlýr‘MãÎ[r°15H_öa¹x²´%*ïšV.Ù…–¦{ìn(]·º;=o›øjH£ˆªï‰RA˜Qº´£ˆ­ü<¬bl”!–$¤ºE:PÁÑ"]Kó4Á;Èg‡ŠCXÿ‘ Û ç‹iASÇagÚ@±–5J.Òv;Ë› ÝÀØjúöäÏÛà).ÝÇf±‚TÓÞJyg½¤&hÉö^éö–I¿˜è½ùx]ŸukO4ϤM¸·‰éú ·^쬃“þ6³|Ó¶!q×ÉÆÂÄwHfÙšæ’§ÙO°­N41Ýö…Ò·2·’n4½@¢Z.ä,äÄóÕ’a†Kw†§Ô®ÃU´M—é¯r¥ämkHYóOà3˜&K›PU4R†âZ!d’eðt&gILš„Ô§.ƒóöó$Ö ’]XÌRp[žGK—ZÍ·lGž¡ú²¦´·].óSwEeûî¸u²é¤Æ>Ÿƒê|ªn¿ñµóƒñylåÚº's>ž\‘س&ÍÄGNI²Ï+ŽZvV!M œ‚÷¬/¥i[VüœM…ŠòŒËR§ÏÇ¿ˆU ÆÖîy²ñ°¹"¹±›ÚI.»r¸q0ÑÑ/þš0V-:úâNX¦%y\‘Ïg£6zÿ䢘ûh°[‹ôvëù窻îíj ò?ƒ:xgxKfŽO Å¿å4w3×øì C²Ñ ûÊéÊ/T¹0–®kÔêm¶âR¯²Ù°±¤ÛÍÌ.f§A³þ¸¦uch­oî:aϪ{©¶ËàZί.*¾˜´­*&þa¼CJ9í_}ŒËËae<ª;\´ÖET»}Øáˆ¹ÚÃàáÁ=?Siz³ ®?TïæiZöìåè1!)†{{zP¥±~A‰œ‡cçíÕðî~£Ôøn–çrÆ3†r´ìœxsßTw´c‚¿Gu“Mq}_‰ýCÍÀäD9˜yêLJ@ÒÌ$ üobÀÏN-_¢j“jKEîçg{–Æty±gÜjq½I'dræÎf" EÅI‰<ÎÁBƵׇ­x!Q"‰ùY7|_F©7º‰ÍS·9ÊßíÉ#ñG*ì'ᑺé„Ù6»—n ŠL]Uò ¸]³¥ ½‹?Ž–BuÐ:P–KûÿÐõ75gÞºO»=Ÿ w‚_ðbq¿f:%œQ›ð$Fv6];®TÁ};˜Öµ îçB0^;åÍçN½Õ ¥8»¬æÇÖSqIdb.´ºùž~‡l?žUûÍYL.{…?’¸ø’GrRÔ›>Õì¯uu¼;ÖÏnù%„©(Z>¤<µK'<Ÿpg2Aþ÷UšbêCÀËÔƒZ6ò/5ùâ³¹©LÏ5†}éB{9ïJjmh"ûkaMO/ê9I¿ëµë×ÆÞ—>¤º¡ñÎÚ ùqNÀ¡eV7qûl™slWäÊ?ü •3endstream endobj 840 0 obj 5923 endobj 845 0 obj <> stream xœí]YsGrvø¿büä½hvÝU{#,¯Â¢Ãë•ÖÜØ‡]?€ˆ%ˆ‡-êwð;³Î¬êª¹0 ,¡ ÐÑÓ]wf~ùeVõ÷«yb«ÿ‹¯Þž=ù=×óêÕû³yõ¯ðïÕÙ÷gÌ?²Š®Þ®¾zæc+79͵\={y €[îÍ|eØ<ÍðËÛ³?­¿=g“l–ë7ç3ü,¹ÓëçlÒZ8±¾ —Šéõûs1)å¤Äß¹ÖøÄúæüBMÖ:xô¶\~ðe)Å™VÉI3zóuy”Tð‹•Ó<»õuyö%`&æÖË[U[R[ß_È ††’Ø$¥¡å—ßÉK¡Ž1µþÛs3Çó-0‚Ч—˜ªÞú>4ÅšØ(ÿ>itÿ­ +5Ôáâ`ˆÙ07næÉÂh^•goK¹7¹²¿Î³õªüü1ÿ\×Ê%‡12ëÿ9¿˜'3ÏV3Ú˜ç8®v²B¯ïz%Üžÿ׳;ÃB¸…åól«å‡Rë§ØËH´XÎiE¿ÂÉ0NéõëüR=©MŸòï·UWýï°ÞbKW:/!-¬o•/ÀÒzQÀ™U0ˆ°Ê/Ó*Vqíû™#µ¥õÈ«ÙÈë1›¿N¹ÙÒg{ã¥i{ßT‚’î’ÂˆÐøÁÕ‚ñõt~! aÊúO\0a’V‹#ã=kƒSxçð‚ñ0‹±Ù³’úQP.ËŒÔB+Ê2*éDþIYØY!'£‡2‹:®JášöŠ2“^ÔòKÚôG~‹T[I½ït•L\—EY·çËΚ®Z23d7y­ö˺®„=>Z¤ºZœ›É5Êt³YZœCwY34dñ¿{Íëzd^xûežY¢¥õdt …e‡+ôèä,_u3 ¹¸@ü“d‚‰NúÑ:¢é*¥ݔ̠Ncl¢¿È Зÿ&*p˜êC„ôº+ޏ¹š¸Sq¦ý³  ¶5Ú#XÐ4~*³ZDzje–Þº¡J'7aªÄ̺‘Ô¬ÃX© ./ÜdÎ…é’E¸ãûR¨ð¾ÒÕû`rTƒ ´±j DW0oV(…š¯à5X x%AÜå«wù×ùÞûæ ~Å&|ýì컳ïW" ˜ »bªÔkÆõ„0ç«§gOžþvõáÝÇgOþ¸bgO¾Áÿ}õí¿ÀŸ§¿YýÕÙ×OWß Áϸ—L2ìíä&7ôEîFéÚ‡|õšvëà=€Å LsUþ?âl0iä®` -²zõ:W~“›ö¡i.^½êŒ˜c¶¶–3G>×ùëÐ\€"qÅ5@Æ—IÔ ÏÀ TÀ‰º»•!g@%¢cîºk}¤"áÎ4'ðéU yŸh;"b¤E‹4âì[5Æ#†Æ*ÖXW_ag &|‹•!†`´òìB!Ô¶µˆ… bt_⸨IXIGƒ˜‘0†q»þ˹ž˜™kP˜Á³PnPÀ§¢›¼V5³Cr[îÖֻ茣á#ÀÖËf1sM[o«qK#ÔWàÕ„&`TA$Ô}€=‚AŸ@0@W2™U X»|( F”Ù‰Ïså±¼é"Ä`B•PiY6@å¦`ççõkÁSZx7É;òÈU TÀ Ád¸æ„ô¥Ö,ÖddëqD;«ó¢Re˜U¾)z7³qw€H؆ŠUš°—ÙÑ"2A„† kòÄ„I½®Ë»ÐWÖåkŠM Mn€Iwë"¿tÕ dZ»•R Ø– ŠgùQYŠ/ã<—›õ"EuËWж†EϦ€;TËÁfkØ9i‹Ž‡ÞÍοä@Þ«XÀ¶áù¿9Ê\ÐúPÔ•¹– Ì/ª§ÿÃ7 •[ÿîê•ZùYÜ:Ä­¿ÆK¦±Ä Ä0^Ì£QwŒX”yM_áë¾5Ûª$qt0 FØÌ' ö—¡þ¸3",8‡l?f„¸È¦FZÑ cáæ‚s××#Å(b½Îé®*C;a`f¤YZ'\ŠoZo¥Åæw½G±.£¦Y[òûmWz‰€jãº*«ö4‘;ÀÑàè4 ¤š òB+7~ÀÇê%ßjv,˜ŸŠmós%í^žA±³''P”ÂÀ‚ñ#½Ú6-þòêt‡°Ê{‘´º˜[ (,èÍh½Åξ(Ö; AEÈÔÞVÀXzýäˆ&ÛA ~Š™+cÐð&sDÞÃÏPæ=n A«Ñ˜§+b`‹-õì€v0]ŠÜ½¦ƒÝ£MЀá²ÓÁÊÂóCáD‘‘è‰Rs×}ô@¼)p¤^»žJãz¸v›RŒã6‚/2[Þ\ÏætRc3àmøýiÁ 7ð\-4x€øàÄäg¿ö¾rj†ÀÔ¤›QßGÛð&‰f{½Ð¢è÷ô•ï&bBî" ¯`°Ñ …Ùrѕ㔠ž‹dÒø-}M”zádÇoEõòCfeÓ>W‡E-öóœbcŽóœŠ‘^LDvÙ6TQåÙ= ‹0VšQÑìRš'ôŒ¨* ÐDƒJzl¤S½á‡šY/L$XaQ.-d ÏDׇè]MŸž•Ž¿’Å×ßÂâʲRSçòÛ *3£>u\l1³œ\Õb‡Ä¬µ»©…ä1a/v0·½¢"NñÓ•qJO3U‘ ntãf!³(g›,ó•_ÀÀ8€[ñ2yÏÝ0Íb¤qŠ_¥¾äÄÊwrž]ž•BŶ|ìu¦5 ™|™ŒÂó¥ùÌ#±ÕNp¡Ð>кÿB–<‘ØïqP¬æÀ(Â}z; ê ×^­B‹ÉrkG¾¶2\ŸÆÎ7Q†4`àä~U Eüˆ©ûÄhA›k(4üUžãÛ|õ¶CÒ¿ëPømü!®†^üAš0~jvȵp7{k|šè¬ TæGGŒžj“G¢_’Ño°fÌØ* {IM|>øx_\/—ØlèŠ5h;/H[ŸwWÉew– ‰‘\²Å˜¿ŒÔnLÖƒêÑn” •01 aëp`k&`‘ëTó”Ýü©MÈ#ÐVÑ’h'¾ó"¬$<¹yÁ™ò™L’.¢J xÛ>›BIò­Ñ†F䑱‡ƒž•z@  [ûÞQ15 K1&‚sN£‚ 8Ý 1¯µ‰ˆü´QLü=ŽÚ`Ÿ¸ÈõÂ9Á›cçᄼþk‚<<¯÷sÎ1'*¢h›oó¸pÁxèQ±¼<êÊ%/Nÿ2dSr2Ú°hã1d#1º²Ȇé™é½C6äéS†l$ô—äýC6Ò)s@µ=d#­ïæ1dó²y Ùü‚B6”î|ŒÛ<Æm¾|ÜFÏÍüDqpÙŹGÇmhOê¸ mË/"n³ätC6!›ÇÍcÈæg²‘Ò5ãË…lhÝ_>ds„[;ôµ±''1ñ;B6à`€gFLß'dC z›C6—yÚØla\#¼‡r܃oö`*V•›\B?æ&—(ÇݮƇ-w_¦ñ`%šÆtY"Eok¹E…”g¤iaû‡…´Av…¾{ÿ})»ÌgûÏh¥;BClÖ>S9G‘2¥Iï'ª–øeۨŴý1êêMW—÷¹#¢…ìëêîÆMNäŸ×=ï6"ܲX Ô§.Qº0|°þ|m‹à;¡ÐibS¸KÁéãcS8ÝJÕnîŠcšwö-.ÊA¢y’3KÈ‹@†O%2È tÐB  냉OK?c4äé{ÓÙHë§ü ½ Þ’1C:*laãXA½â„eìµ)&HËb+=•• äŽ`™—‹.¼êïF› ž¬›õ@û`NNÁ‹Þ"ú¦ŠÏâ¾ÒZ„˜37³—Z…Ù“³ êçl°evÒŒFÑúîä@Ïr{Cô`m_†š43ƒ&R^ê°p=³ÚûŒU©É»ÊÛÐD~…~L¾©c9esÖaZ”l}Þ+^ }æ³^Û ½Öƒ ]¿¹Dl[†maï±6ŒYlñq=ȹ:X£^²©¶ç…©[Ƭg79­ûEbìý¸x1ä÷®Ö•"ˆ¨p“ØþƼ£EôA‘íw.Ч FA¥å~Bbžëóý³Fˆ¢Ù3K£t¼9÷#¥8NÕá@ÈÝtä@‹è|N†Igœ5ÀgFžoÉQ;Aô!VJ“‰:ªÚÑ=BNï›ÓqDòÀ0J`áÜ–€;#3’Ü>­zˆ»Ÿ9(×–gI²‚-< Ëå!{'CjåÏ5/$:AGâ9´6•ƒ1æÓ [ÃðV_:E`/¿ËŸNžÎv¦3ãh ”ßÍí™49i¬ÝsÝ–y’¸æ”i×òÌ×Çž9&þB‡ø´½Ãý”^Ʀrµ½ŒOîÅ.‡]Õ¨’:Þ5ûùUŽm?v […£fÔOéVØre[i”¯¸ZÊm ú°m“f‰×˜ÊSÊŠ/ÐU˜£ ¯cš}AÝŸi–Ìë/Ö;¬eÌ4KÒ¯o:¼Ô¦N¥©5ëhõ[ÈfìZd›…ºÝŒº;‘ÍG(ï¡=aâÐÄ®ãÈfÝDÏ›ûÍ´ B6wÈO²S PÑwûQ£Â‡3hUûS£Òo¬¤ï><5ÊŒÐJ]7¸eFñx¥G^ô‘}äEÿ¿ñ¢‹C-½¾Z\fΧËVÆ<œ¾µÅ˜ ®ýxÿdÞýþA¥ó3*8˜Ó²©Ì/2žø†”@šÛ:ì¤tÓG³„_Ä#¼$µ»ÕþÜrl”’¸däæ7ÙŽ0Óºw2ÔÖ„V0#Æ{ Òx<ï½5Úk>§?žp´Ù€*i ±<ˆ9øae ñÅç\¿,§°Õ»„`ÞÇèžmDŠ"Iõf×]S(P«IzÝ÷FußÓqä`ò‹PCpÀWñìI$P‡§Îá0šf®ì˜fv*D‘´°8ÞYHû^o—Å|·1V%ºö3Ë^òmç¶¢aêÙR;tsÒ1 á0g½C¯ú¿Ž&IØ×©B<Á´Ø2ˆ]Únq€êR ðYO2m0xÕ\µsOÚ—‡ž´„¸›?–úÉÆ FPûÞq?Uöu¬ÌCŸà3«Â_Æ]+ƒd´ÂG, RrC?bŸÑd;Òù¥É‘ÌÐUåñš=@ûÙ=°Ònæ±ð3ÏGÛ‹Òž/ÓÛd‰µØâÝè=«&š6‚½ã%Fïá^×Ù™wŸƒÀýd½Qè„s Ù<Ò-õ âÃ|œ‘Ãî6ÿ@ÖKxR0f&¹Ma¤N«0xRrÔà{ tÛ£èƱ O ò {¸­ÈÖ”!×÷#o¡ºŽˆmT›ìÀ¾(»fO")á0TAp.yëÇRlZ"žø ß´ y¸;—CýQG„Òª:8lˆnCH¥rrûç‘_¦„ænÆ5(^J˜Ë¥Ì“kKšôJ§`9”(†|Pæ‚2¿ŸÀÄ£M ?¾²Ésµ¸˜²ÓÙ¶ƒDOW3î ŽÖ|Þì³ÁDµmœö±‘öóö9Ô—EF}.Àš or)·ÝÅ×dJ±gÝ"d‰îƒÇwƒŠ`ýgÊcV")q\(Os,²”thPð¨`3«{ æ=óƒy¿”`õHŠè m&€'ˆèfÑ|Ò?E4œ=Zù cyÐwï¨ÔÛVà·­ÒSpÉÏ [/‚ÖÜÌ)и·•¦Hrö9`ÆãœÆ;ý~þÞnÆ­œ)¶šŸz+`˜¡fsZ¤[%:$BWì€Ä8쬡çök€m¶½ï-÷9~Î!lS•ó9#ÙÓ-Û6 ¥Ú":U{|,ëÞ»Dÿoíš'ÈçðßÏžýÝŸÆŒnø8Zµ>t§ì.>ËÍi)M‡8§š­‘1’ûO!ÍšÕ_iéG4‰b êæ®ö¤Œ3º6Þnk5æzìi¨J&Öá:ö¬; ï¿w·ñŒ_³“vý÷çþ¤'Æz»ÊCåäz;-æ—Æ1ÌLúlÞ”÷“²‘ÆI”vL[¥öÁÎbüøßðKn‰ÉºrôcYûDÛõs*Ü£³bë%GG°<©¬ð¹¤póõ?D&˜‰½¬‹Uü8æi×bd¨N!‹1Fµ,nK½ß#J“-P@$³~¢¤S´%^Ó(¥zÎðÛOšo£çRÀ²MO |DJP;‚²$œé/’ æ\øëý€˜f~\†ZUR9ÂöáÝ™Ô ¶t–FH~ø=2ºjI ¸,¤؃ªzÎ&$à¡ZM›•ñ±‡“loRxna¯D=Œã„ŸÄud`|[ªªÛP(Ÿq»Lái.RMŠÜ䂺çm^Eíaý1?Q}ŒNî„õíúìèUeo+DÚìÚj ã0ˆþCº{åaàòå•ct`F˜C=¶ªŠ/È’=jä;x„r" {ŠÊÿ°›ˆºh©›0q½÷vÏ’½ªLPÕ›S_+)Ä «xà æ?9¿šþjHºY«>Óã×ê–3kC§9Õ1Ýmvízëso´Oµ T–^Äø±¬B¥IŸXšW´ÃvNië µ)](±J1¿Rà0áz¥Ü‰ŽžñäÈ[p¨fRþƒÒeZ PúÖ·Ÿ#å§íýgtýÂ6y^ÁzPS2c_óu qRo7Gn¯Ó.áIŽ©‹¥î÷™ú˜2Œ¿ùL75Øð]p}i i]†«JyZn²Þ–›Ò>ð$rXø¿#Ÿ(@èÔ˜fxïdÜΚj² 󚪪è?;:\7;ŽßH;¹?ÒÖ†í n”mYºà h)ÞîÊó`ptš¥”g#ÙúŸ m“}6²é~ÿN6T§Fº°Y[ÏÄ(6»{C?}j¼Ë< JŸRúÔ£”‚s*¿Žp$ýñ¹Á®Ÿà¡'©i”H@XGW‘º”QkÞøŒé¬ßJ=™´ˆ9¢LÖ‘‚ Ãmœëâmí&Ÿ ‡Õ–Œžl޾;û_П¸šendstream endobj 846 0 obj 5621 endobj 850 0 obj <> stream xœí\[o\·.ò¨_±oÞ-²Ç¼_‚¢@㉊uyHŠT–,Å,ɲl×)ò+šÜ^†<<»ky»m8:àá!‡Ã¹|3îÓø‚áñïñ“ƒ»_ÃgÏØâøwvðô€‡.‹øçøÉâÃØÍª…¼F-œŒð… ËÙÀ ñÉÁ7ËWjÐBy³üçj­ç¼—Ë£ðè™VË'+OÊ/¯àÁKÎÔò|Å`X­_>Z­…ƒ¶jùÉj­/´‘´Ãeôaà¨4žÃ¨vyoµfƒñÞHM?»ÈŸ½—ŸÎÊëç¹ñzµæƒ1š:Á ’“ËÇ]ªòð{ðg`š6ÓØàt䛃pŒ/ŒÓƒq#ó®€yNj“§§Gá ˆo•ãñ-¶]æ¶ãüT¾x–ÛÊÓe~ 4†Üšå÷ùõM~}“ÛÊÄßå·sÛE3IMêHŒµ„¾›ÔôÁH€`bùí·±Ù&ÔbÍÅâÁ °ä,vÞYôÃüt”ß‚î`ç$!òq‡'ßå§çùíEóEál=ñI‡Ûe¼'i…G„‡kcõ ­ˆ³ÁÛv²Ì%xh§‚¦ÌÊan"xÀy”˜KžÚDî¯ë¦‘Ý›TÛ(ê3 ~ݪÑH”eº2>¤krJVÑ+ÃÒK—\ÙóQ}É=+NqÖäEx³ÕäÛ ³6û‘­®úW5^ñ·ú⸞àŒ„<ÙgðûQ_¾ç½z;ÖMÒ*ÿ6·pÚïÃøƒúÿŒƒ¿KϦݯÓË ï0€¢¥éÒ rÈß  íãòS[;EbNŒ¦{1ïi€×Ñô9YëÚ€ª8f›·ï4­©0ö¼Àqîž“^kÃ@ý\Mƒè̪›Âëqanù¯ñKÒ¥·,¶:ýiÇPYYô~£ß#¨|¢y'àw?:·΂=r$9NCr?0Xèaö‰÷±ô âò?óp’¿:Éô¾Q†¢â]36ë†|ˆpMôêLqXƒ¸¼…ñì,fLÄÕV~-C‹L¡ü3l¬ÂR–ÖÞ@Å4,ºX¯pu’¡È´¤•Þ£jXÉí rÜú^Æý/ÿïnèH ^Ô8áv ò ?—¾ïãÊÕÀ¬œuã’ žpù¢;ʳòšÖæ§+X–“>í]€æ}ÀNZÉdÇ#RÈH"ƒ>Ѻh Î)‹ðûYøˆÍŒ fÁ’™qË%4<$Xø¸;oñŸÇ¸·h-P×òjïç÷uü,-83Zh€¬ã‚+ÍOáüEv2±—˜³k{ ¶‰’Ÿ”÷)©»VPFóh{ƒA•Á¥О¾‰ÄíxF19ügÞa8Ãók–_—Ìzy;ä·mÛØoÄ$RþÏ©Cœÿ.›àôò³®’= †”ð¦?|k{BÏGÉ€ë ` –ï oÁR\^K² ÐK¬ÝMdmAPN Lñ_B çþN¨°ïЍ{Áçî_;_Iî«‚óéæ4€ ÂŒ'‰Î×0VÃÁ…ñFŒzéÂ>Xj% ‘ÊÏåõû1Õ™$0}ø“pŸï¤?:À/¶Ô ,'ųOá õާfý³´ÔzQ”ž¤€xà˜2鈦9˜› @Üó³b &\H¤,Àæˆz%JÒj·RqÕí›%Ðýl"£^•¡«=ªÐqª³©l¤ Q± ` Cm¬D¶NŠZ½ÈS=гêê±KÀ%`tÜv >|-Lß–3¢}ý$‹>)‘J?ÏJ3²¹ ®€ã`[úF¶oïˆ&ÕVX è-Ma–œ4…ÇÖ"Ž9þ(¢¶7§Ñ"B«*­¬,¸ooŽªmnÌÍ|ê¿™òTY£è*›[vj<$[ŸÏîåÐà°è?=ÃüÑ¿ƒ:j ¸éºŠ›âÃg!DN}¯…Ðv²WÇÛ >K«I QúˆvDÜ8òÇ>?xºc•LéÜ 4F4E`yÖ‡‡w?[Ü\?tp÷ë?¸û)þïÃû÷àÏáG‹ß||¸ø|¶hkñ ME{‹ýëP£Åþøv þg&¸øÕ&¸F¸JWö¬í n~1ÿ®ÈÒ4 ¥Íæ÷­ÍEׄl;`ÀíÑíaÿÞë}fa ðÛ6Áº‚8ß°ž^“ýÃe¯­ ëÁRþ®ï=\{ˆÔc«÷²ç9Öô#%rä˦©úîîä;UJñ~*‘øUÍ¿" ÖnÍ„°ÞÏ% ·ü-’ଠ!Ì›$ ØAæþ› B.ÿZY±yí÷ÁúÑœyÁô›Ây¬8 æ|Ì””` ËÉg´è„Â’£B :9KÁè&ð<”&}™×B%à3§ÚÍ[+Ý–! %|½¢F¿W¦Õ=¶@ˆ6U)CÎ:ŽVá]Ãå¤8pŒßM°ƒµÈ©vÑaΚ“uqƸ)c•ˆ±„f,~ñrà²ÿNs(c/« išNºƒÙŽ«u‚§3d¡£ô¼S^Q‹µän&§Íô›p'•KÙCƒÛÂÔ!Jʆ½$9—iT×D““aâëÈoÛI(¤¾cž‚.½ÒP1ࣤ°×uZe¬–Æw”¼ „0SˆC;Ç])º‘šî¾-Ý–@NÝzÕ]ÌÆ˜·´/æ5ÄrÅÔeH½Æi.¡)BnI7xÞ”&Žsªý”ÈÑòˆÁ7ø~™âÜF wÌÛ¤#miY«Ûy4ƒ„© üÞ°A_©Œ„ÄÒ^i'–¡µµ" üšO‹ÑØP™°†ñ¥è5án7<º, ‰;˜@ñƒ2²Î¡‘q°qý,î.VF J:O&ó6Úž”Jèi0Ø4¿·3Y§%ëò*/=Úƒ°±>¿$’þÕ„©AŠ'ÄåêÉY‘JúÞšÿˆhì›Øò Š"„ÊN&×Ù/°Dw œç®-/]4E©ª²ö½á*…ª|<&ÂQ ÈÌûج=7}SçßC)¦©Šîâ»m‡2#äð`çñW6ª[S¦Oa~ˆgä4 PCŽþ1"•Ä1àrôµ¶E¤Ì¯Ê×NSä„ôÍbŽ:tÜýçÒ0È„“n·ò\“qËæŒ‹zD@‹¡ŒDS}´[ß¡ )o8‡Óz7#ó4ï§nò-ÖVL5G(›;ÛÇ`™ÎÈi°Ô‡ãUìî*Sr:VI^3³9úl5™€¿ÊTPDg}(ɨ̺x¢Åæd›© ÑFU¹–uí¦çãÎ刷äX8Ût|æ—žð´«Ö_æXŽ ¥É0g—+¿ó&/ýîrbAçjŠºøÍ_¸í.û­ýzOËh©âíË@ÃMÝ7…WÇ]5 ã?l¿§á¾V½l hă•Édv'?Œ|WÞ-EéPΗåX¡ìׄDÖ ®eB¤¨A&Ó[FË1Ìçÿ¡òbendstream endobj 851 0 obj 4566 endobj 856 0 obj <> stream xœÍ]Y“ä¶‘Þоõ‹ÿB½l¸*BÅÁ}øÍ:Ö‡7,K£Ø‡}˜é9ºcfº[}Hjÿ û;$ˆ ‹ÕÅR‡bÔ  ÌL|y"úižbø_÷÷üóÙ‹ï…a«wglõ'ø÷áì§3YuÎ?¯¾zã+ßx#ŒZ½zÖÀWBøFŠ•e²«WŸÏþoýjãxøäë×›-oŒ‘^®ßl¶ºqžs½þ´a0ŒÖ‚¯ßm¶B‰F[µáç캛WŽÉµìoþa³• È6bý·Í–5–1gøú¦à>Œ*™åëËtyÝ~Õ_ÝÁøB7’‹õûÍV5À˜–äÉ[$J7Ü:èEÿy$Zùõ?ƒ¯F:Êà§4À¿àkZ5 ¿õwÞxÉ™Âw ø¢ÿ˜|ý]ÿªÿõ—³o_ýýì§•”Ò‚Øq&`·âÒsfƒ…¿0¿_½<{ñòV÷·ïÎ^ü½ø3þï«ï¾†?/¿YýÇÙ·/W8~? ÄÌ«t¾Qne¼· ›5P >V•àÃAÒ ßÃE?C™x¡„é’¸o˜hgW o²Ù……w‚'cH(es†„òDÆÐ=ïHZ†´gñ2€à2AçªÿÖ‡^wjÜ)+宊!ã¬kÄÑÆRHßÓñ茟 ìyæ,âx7íìÝmd£µWýìin¢ÞÞ˜Øt®ø1ÕUFä в5Ö³™r™Éމÿìau½á0ÁÌÚõ/hQ;FêÁžŸˆ`/¿m•܃%.þÞFOZ¥a­@b#¹2–\!›"¸WìùוÑj>×H”•Ñ‚4çYˆÃ”ÑÀkT+Æóâf/³">p•sß?Px˜ªð®cù‡šF²0 „§U8ëFZ˜â6„âEtri4E$|quÜj&“i(ï—5cno´9“4µë‡aΈ7?Bö&Ucµ¬x˜ó”  àÊBûþÍãÒò‰ˆ"ò!ù{1¥éë= †Õ"Oºo½§ò¹H¶v(ëpóã0UpIxM °ƒdW%AÒ$ Sy)ÎÊ.‰ŽtÕM°ák½Ó+To Ð*Û:ðÖczî~Ÿ umfáD5iívþÜ×V:6×i•VZ½¬­îVø†wAôe1äë3´šwѺM^„_8^ÕI¥?$U¿*Ú‚I»‘ÌM57ca"–gÏcr÷9•jˆ*ÝLÖ+z£¶4†¢Q#44ômÉ|¤ ™4R\L%E4~®AU‘DC˜î:?YiLæíS©ºIÊ«™Ñ£dæ¯Ìuâà‹Bµ‰XgbèÉø£šk@ôhü½*Wó‘P7q ýãT›„ž[F=ÌÄqÓtAÜSÞGê†_o8eåÍúe_xz‰õdà_ˆJ;?" s¶D²´t¢ò&é Ëùà/Ñs%Ì==`y¿áTsáÈÒÀ$tçË¡]áÊQj3ÀÃIj3L5J¼q{¤Ls_tß7Åg£ísÄ¿ÓÏ_' §DsF‚¶´|"x‰|ž'zç ¢Ž^ÆüqŠŒÍ]/8½Ú ü3¬p¦BÿزâåýÐï…Ò·»´BfÙdñÑN}æåµD8ü£¸î8R¯âè^qÙÒòï´ƒÊÿyjÇ|ATµC;§R*æðÓë›—HiÌû,,×RHK*Úô‰Ë¢{x7°îÁú§¼¢ðb™‚Ð…)€/.Âp"Âg ðQ¸5â(¥mõÜbøa7«ÁCóO¬sÊ€ÞT£ÉÍôo„/.ªd"ªÅ¼Úxûuø‚Ý8JÚÍ­‰_­Û ù/HW ø˜:0þhxœW¦^œ÷ˆÇÈûsã|Þë`Ô\%„æÖ{#¸yÓ%:oFBÞ3Ó·ýIúèci¹ž>;Ñ Oµ°K 0"šð9z>ûuPãßcä‡Z:{ +ï;×¶0D£$?N©_p×(Ïi8=~öà*u³/™L¢iIGôI?'ôÏg¿Ž~afUF?ˆð$&[œšýÐ_¶ùò!S½ðùÞÝC‹Ë$â”Èäy&tóQG,W³Ç*#–«…ÛF;Ä2 fmOĖÉrW!)mO,JÍ¿eÌ.-•ˆY"•ç‰Ùù‚¨c–‰Ùc•1ËøÂ}•-f•—ýNZ##ˆJ=%Åý"$@(vÚ•Á·4{ø({ÏɱÏg¿ 9åæïº(BZ¸ý±ƒœCá¶sR^•¸*øÝ¼a“Ù–u¾p(b$N¥8EÄþ¦ärp·ë4[\¦õF­$Jö}¿°þWÌ3UÃíý$‹+·i¿Nß·õÔÔrñùŽ:H¤wˆ²@g]Y¬=VYYìi¶)Óïá¸/F«)ò­öŸYߎ´ôæÓNw¢˜ä¤% ©nOêæ}q‚mˆLÁKe¹ç˜TÊ¥q•21}Is0C¾‘–¶5dÛ§|¯´óù¨+­Q³Ç*+­9Í–!¥Ó&qGBê×I'ZŠõÒÛk С2Š/ŠJ@¢£²–Lî:ô²ÍÅYòý eéS1UJµ)Òu8Úp±OÇÂâÀŠZKxJÝßÃ*ú?³îͨµ£© Œææ)4ªWâÞ=ä›×¯iA÷h,‹J>yÕy¢ú#nmUNúùÛý£†ùSR7@ZÌ«l€ôi¶G)•6æ<Ñ©ì‰BD(ö\ìhö(ujL*ëÒ“••°”Η8d«ß×±¬Ž´eJÉÓl™R2m z"–%_8fï°L(~ª3ë¥ç#špWôAÉ<$¬“™{3ôQÑ ìÊŠyíQ(Fî×RÖÜ»ÂôsòQ󧬮×böΪyG‹©Ò0±Â÷Å5žÀ»íûU_ÕèÎÒQí.òßk“̧£æ€@@sèØ¯a'•Ãm¼Â£kÒ½óþê¢ÿô]¼×¾­¦¤Üؤuñ¼ ­l„WÖ•uu’rœ2Þbd·;÷û÷טŒ©¡ ñéÛ ©¶r¸(á-${Š4œ¥*SŽlT㵪Ÿ] ®ºÝI2:&‰T´Fj·!}ð‚_È„„7xä¼’¡•oÏFqÆTj¸éû€S¥ æ"ÂAjMµ¿$-KÖÃI Ý®@H1Q€­ptÅÒg ×™ýއ‚óh³5P]÷é.Ä*Á‚®Ù¾µñgmº¸ ¼-)U Ö ×‘˜2’0X’dÙc4çËû¹èäÙ1¼Ò¥ÅE¡QßÂ0•ÙUR}+E°´[ކ—ñÕ«·À=­ë›òßñh(b |Œ4õ›pÕdÚ$_Eâ„bW|.­Gèf¤ìÙ 2Þ…ˆ;â˜qã<0<:5@UŽÒà¦1E}÷U6@`Âøª—–NA,WÊV¥Ø£RÞ3˜%¸BÅI˜R¶ZYÉ’Œ; Ú­ÖˆÜ/ÄZ¼”c‹;da•í3Ç»x2dèœ5Ò‚Ž}(Zª2¬Ç!ô`ó™û–/<ª®ÆWü¼ãÆ0jˆÈç*i­ {JÂeˆ¤,Óíûm™—ÉŒËð˜;ö]å>QÐÅ"]ÓѶ› ÇÚé ;gn1F‚?ÒT-?Q5ü:bËzTí*ã³@‰ ¬° G1=:ò°;Æ@·¸û÷õi`x©«½¨pö¾XJ¨Ÿ±5"΃ÖvÊO °‘0=R+üÓ¹˜ÎCÝöqÔu¼õ>wcøÙ§x Þo8¶Wû.³¶KMënÇ‹‹þ³wÝ­žPbÞç2J'ÊçTüµÍ×€«§ƒ¶íØ9>ï<±âtA-Â+-Sù"bþ é¦^äî¤Ï,;käò8«t!OËŽ¢ ¦œÄ—‰Ü7ECƒ~CëF€Šž§UyêιÛîŽ å~]\S+í …)é”ã¬Ú0g@Õ‡‰Ï ¥ÚBˆÑÒÃàE ¥˜M}M Óœ|Êb߃„´JÑ(!}Ùgws&.°†r´œÉšlÈ'§ ŽB;47Bq9WYÙ+ß=Ï-ª”U{™ÂùãR¸‘Å7wÑa°î?“ÜZõU…lapò †TûȬDC^JÜ}vˆ­p[›až&±HV£’IBÌ $ŠiýH†½*ù¤}BØv:‰M¹n1pœ¿.{[´(å0é&7jÌ7†ù.yf;·È otvèÎ(” æø"MW XvÃäGùÜnpi̓åúG‚ì"Åv[ޱ’¸ƒ6}üY©\æX©@xí±-#¾k›Ð1<Ш°A£Å”Z9Sr`È—ÈHÃ=z…C¦}´:(b‘¾£f,éPƒ 2ë÷©K1D:¬iÇôóû¢Â¦3¶§<¦=2»¦C@pÙÝÊB@)`äÃë f ŸSÔÖA”BïÂA~1j-¦ÎÍÔiC½¬¸»È€Ë>3"Š_NEFÃæ=|ý1jÞT;ˆÎK†Œÿ¦øý·ét¼\[ÂfDay&¼1ž5v”ÈK¦jÅ­êt¼!>:óÛBPp?-Õûn…º=œá³‰#ß\Î-nT•¡,È ?Ò!n»*a#%ù¡'ùª'9±q^ö0hÛÁš§c͇£ì)kŸ ‘äÍ ¢Û‰ e„DüâëAH™G°)ý…‚µ¸•£ÝDéˆà,@^J™ß=ÿÚ_=NñàE¨GŸ„‡ ‘‡‡Y(µ8íDB{@üa` ß¾=7^?ïú´Š ×JUÊ#ý¨Ç~l8HŽ2ô¾ð!¬wÚ‡ÓßA‚_0diõ~Ô·P0¹=(ä»ç¹^ÈM6û~_ p¤³k§B:PNA|Bü@aº?Úw6PÈwKáP²2“ À*d–é#ý0Ã.¿Â´—ª?7cÚÓž¡}ë9¦<ÆrÙ—¯Æ¢­."»°äêà ¾ø"²È -E ¨Ãà¸Øb¸K¢[Æ•höå˂ݺhT‡óý¡ŒËÝ0öXgÌï2o¸L˜³ö0wf°ëV-l2?É­QËH¾ÌFVù|œìþôþ0€d_N$ý¼Éwc¯ÿ1†O*NÆ_¥\:+© ?´E˜Lf/%‰“až·!ƒ:É‚1\jÏHÄf,îÊa2ØûGÁGƒ'ûrÁ^È “Á<Âh´AµØh#e{fáòÉ­3XÉØnÖÈwܾÏØm¼u7czQ¤ùm'Ešå“ÌvR¤†ì‰ÓdÏ>Fá£øÂ|”7Û0,¸­Li,p˜¾T)³¶ —¿ŸýL-×endstream endobj 857 0 obj 5094 endobj 864 0 obj <> stream xœÍ][Çu”·}É_˜Ç@Ó¬ûE0DŽb3ˆa9dàÛ0È%¹»ÑÞDü÷œSÝUuªºzzzvf-Ò¶º»ªÏ9õk]æÇëøŠá?Ãßó›³ÿ- []|:c«ßÀ¿g?žñðÊjøs~³úöux¯|ç0jõúÃYß_ !;¥V–ÉN¬^ßœýiýzãxǸäë7›-^®ßn¶ºsžs½¾Þ0èFkÁ×ï7[¡D§­Z‹ð‚svÝÁÍÎ+ÇäZ¥›ßl¶’ÙF¬¿Ù²Î2æ _ß§B¯’Y¾¾Ê—wéùmºúýKÛIå×6[ÕcZ’7?âsÙqÚåezú>ñô—×ÿ bÑ "Ö9=HF ×yA%óf£:'­²ñB9žoÇ‹Ëôìýp«ÿЄü¥áÕW¾ßÀÉ™BNÆì}•_gþJ®¾{}ö‡³WR‚˜DøôãV\z}À·Xø èùöåÙ‹—¿[=|||öâ+~öâ·øŸo¿ÿ5üyùï«:ûîå ûÂö¡#.€jé|§ÜÊxo;¶¨£)pZÕWû7@·¤ó{”‰ÚH…(‰‡^P€¸;JxS`eì Â)J™Î<CB3mÊЫÄÅ0ˆFº!íY¼ ¸Êšw›Z]$ÍœâNYq(w“2κN­/…ô=Îø…À^f,#wÓÞ§ì´ö*žæ&ê-Àñ§é€Mçš©®2"PP”­±ž-”ËBv¬hÌìüs‚Õ݆Ã30hŸÑ^vŒÔS{þL{Yü®Wr.ŠH¸éV’˜µ§†Q´™ ™fÙѲ9‚“b/'xZ­æKD[-Hs™…8L |Fõb<Ï QÊU°Än3rÒ SC¾u,ÿ0¥‘, áé@•ΆžNLñBñItòÔhŠ:Iøx¢R.§xZ)°¨SOWJ#Äi-ô ”Z"ÝAŒ÷wù28NÃŒÝGû0GÁN•\(……ÄÝIS¿–ƒm¹L¯Î‚ùÔ£ÁLٷˉ›Æ­fò8™†òþ´flÀ­â#g’‡výXg¤xóL9Ugµœð0ç9“&:@ÀU„öéîÅÞæñÔò‰ˆ"ò!Õf&JÓ×t«E™Ò ßzOås™mm-ëpó‡¢ 4ØXK xC °ƒdWeAÒ$+ XÛ%Ñžn‡6|­wz…É›´Êe¼õ%¿÷0ŠOº>³pb2iM »|ì§V:¶ÔiµVZ}Z[=(¬ð‚èËQɪ½QYåÍúeJËàJh€~¹¾†‘Ü__O-ž¨¯DAž¿É@ÏaØ‚ðåÔâ‰àÍâùebw¹¦±ËÁ%íž%íf ç ê ™`3WÁƆ/ ¢‰Í­¾ >W¡VóÕA{åo²U&þ–1ñ†Ö[[ï¶P7«§–T"ÿ_¦v,Ä´v0æ“ÿ2¶´Ô|vh/ðOR¬¡šCÁæ4Áy3AnƒïÔì à£ì|óº— ·œýIÈiçôQRWèhiAõ0ÈYßÙ25#¥ ŸíÌùh•ÛÆ¸Aù´—Mó>ÎZR<âûŒ†ñ‡e·ÁüÎÁúä"Œ°&"üÁúö§am8J‚§­^Z’< ÖÆbM.ŒÉcË&F—4=¦MpDÚ,ž²\H±ð¡;L4]çô?¨.tòQŠšCxþEF#bZ‡Àd%Ï„Ž––GÓ!­û¡iÇÑ· 4•õwfßZŸ8x22ŒU$7;“‡VZAt£H+¶˜—y£¨½È­®#¤®q¨ Æ¥©÷ÔrÏÉ:ªa”ÜAnf9‘Ó*¢¹>J: --H¦"÷˜!zhVJÞ¶ê#¥Ÿ±¾ïJž8à3ý`’›H¿jå åB“aäON±Õ6Åíºk{ÖžÇv ¥ó˜UÊSC+*%ášpöBùNZZ„{ß*IÌ*îrF¦ÿ#ÓÖÒÙgñm2ð^Q‰âþ<ëÞÄ@1;qDk€UP|ÙÔ!µÕdv™—Ãhžš%¯áfÁÒu3/ÌËwózÅñäù>¶“+ª-á)Ïäa«ÀM9^SŒZ;ºÀhiŸúÕÉíØw9ʼnÈüê}µnÄÄ”êûQ*ŽTÿ€Ë•S†>·ä°|H¦ 0‹ûj Ög‰¸E¸Ãqwât`0@„âº^³£PÔªòÌ*ë©!*+a)ïD8dÙÖOc™«Å}µ±ÌÕ‰ÖXf!N;–™9qÜ>`™PüTgºÖ§kÂ]Óeð˜±NFîmí£¢ ð5èS‡ý9ûµœ6‡u9’é_’Z>dÓzÍÄûâG[ +šŠ‚KGÕJ™°Î"@é_ŠTv×(D—moÓö¦»p`ìã½›jc>½N÷®ÒÕßÒÓ÷ñÞäBf} K§'ä´ƒ[g°€KÙ}L$?$’?P’gå®9Bå0¹“¶-Éþ<';Ýçõ "Ç“ËN‡…Ó”äz'’ü&Ý{×xúq 6(Þ³0äîÑ¢ ]7HÎúpw>¤[—ÕÀ@!·æ@ ¶OŠtKg‡ !ùS"ù¾”ó†Ô?-RA!1T8L²¤í“$‹û(f~^²„ä'¨àB3ŸðÅ2&m“;$‹$=TdâÕmzZ3‘ƒ§“…OFCñÅëÓp*Á€P&?îB4Ù\|W±kíðšµ³~S`枇Eü”7‹W‘ÎÛ Oi÷4å!ïž~ˆW•RWûYSé4¥©a kYuÞ¦«ëýCÓ[WøÄ‘æÑv0cƒƒLÜœWâDz3¼~¨B´7³âvyAÐb‰“¶W ¡·4#ëMfìaNüV†-ð½#­½Þ%~ƒ5ÊÚE#ø½³¶—´K«ºK›´}lH»­ß4®raŠgby áH›ùfcyÊnËÝÕzfæ¦kƒ]X¬dÍâÅ^§UÚ]¸xàHÛT4)Y8Âîÿ6ú©º—F¢p'iàjM#®f¯S,ذxàHÛ§„ÐÏ‘&>fCHJò>ÂÏ QêÔÇ uø4q:­†ÙÞ]>ß‚³:Â÷爓ˊ ¥4ìAÂWÁ¤×)T÷Ÿ0Ý¡F#7=a<#ÌÒõPÇ3™Ÿ¤6C=fqeFrÑêDsÓË ÎeÂr?'Bíz¾¸Œ‚˜¢¥î˜ôà&Yµ_áÛ\Y5«û*¬î³2U“*г#2èÊöŠ-IrÆÐ†xɸ‰ôÿ ì˜UB‹æWD–äåý™uhùѹË Ö›·ØÅµ=¿ê—éxpËßD¾†+åÁc|ƒÏ]‡û r«¦”¤·˜ŒŒÿ¥”’Ø)¥bËÈ÷m9Nk*Ö Þ(õÚ‘‰0fî3õݰpHÒfý±w¸2é3¶‚èNùö¹[!’—•Õ£ø‡žÑã æÁ8ºÆ±`}%Ç‘åVd»éŸpø™xœâûËePX‹2Ê‘CÆîê Ã{ ðc¼ˆªî†S‡¸Š+ßÊ5]£Í‡á å« *«¢“HàT|‡à·„ï`êà2¸9íqiÛ€²ï±茥ÑjyTSd»?R^ަÆ)HÙ‡L¸;ô‘~8;EGãýä£D¨hB¯†Ä¢ýW1ûò€‹¯Q:pÝà ¥Ãε~5°eЍ0Cöõ»…à†ÍÏqX!)©* %”„Œý Z´ ÃwO§M¦'"Ñ2p'kê¶Ã@¥p„,%Û ß ëÒ•¢ê4~×Mæ© ¸/Ö®•šL-ÞœÝ@KÞ4šbw{{GÑeŸ½8f¦aL:vwéŒ)44CÛ+«’¾PßL‡\Ârr$ûÝU˜ˆ¹¨…;i4P -hœöá+&¯­§N9è· “­ƒ~ç ‘dq«¦§êå=—H*äR`¸§-ÍpZÁ+¢qñCÿ…Í G…^J"Ò~ᮩTõ mFrA® ©£MBͦqýÆô-€^^òI&øbSL¨c€™g`ŠÚm«ZÃû%³øÚ }Ór9úþ,‚(ÊÛ£ ŽînªN,s"¢:0íávÐ0]§UŒ? d‹1±Ë™TŽUçÎ7$½ÙÓ¡ ÖEã”î÷|cY|úÜ9dEгA'OUˆ–•˜¸ò\‚ÝfÌ+ˆ22÷©Õ[ü¹¨xëE¼•.>§gŸË[Ö’âõ§ÒÍ”–s»»ì×R©þ¢¤¡÷ãø”kðõøéy~z×r«éic}ÚÛüôEáZ'õŸ£q+¤œíÔU­Õuªvîy×r_6ÑÂ烸n…C¾õ]ÎÆŠeºP¢d¹¾d™Úu²Ž„lˆ)7¡Y•¢+ÝÙ©Dï@SrÑRãH#2±ÓŠN›$WÀÿHCÞ*-aíփðÞöFâ(AKHù™žZÂ!eRå³Ô*;TNɶʮx4” SÜ_ÚЭÃ!núã¸ÖíH¥ðLý vYÿÀ»§]Ñ&€ø¤4Å.v¬™aâ"ŠÃÅŠ VU¦æañ×ย‹\a%CãÿÔåWkXhÓp½d2~²¾A¥:. Å:ª±Î27?>ôÉy¬¡üsÛ²{”‡ã)Óc\Ue•û¬6WY÷‰2mKÎMNh,û½ŽY@hF._õÒf’WàÔÅÛÜE®çìªA1]-&õží0DÉïÉÅ¢e¹‚š?™Åˆ?A '~t¤®‡³…]Sò±¥ÜšD3ˆêÜô³Pv´ú¤ÿé†)b*•ÅíÞÒZÛïOLŠöz[@2®4™ª#"NõüÏ<ërõ˜4»²_íþ‚t{›´š¥êi“ìöQRmªª¹¬êw‰ÔÆHŽlä®Gý7–¬lFÂô Š‰ü!®Qž=±Nê6±ª=7>³ORcä»~Hæ»J[~õ5†*[6ª`ÍÀÓOÁ“ ]BJ¬$o'k̓Âè{ z¥*ï"(Í\Ôõ~i<&+ ‡S¿NŠ ·ßÇ¿÷ð—c§6‰iÒ'é©Ð©,ö–¬JNp¤FfrJ7"!À]nXˆÙ11„:‘Ó´¼©|é+¼*¬N¾/f& RaoŽæ8v¢šN”\n6J> stream xœÍ=Û’Ü6v©ÍÛ|Eç!•Ƅó´Ö:±R›µwwR[©uFÝJÒh,ÖÖ~}ÎÁ…8 n²§9™rÉÃb“ÀÁÁ¹_ÀŸ7¬ã†ÿÅ¿Ïß_|ý'aØæÕ§ ¶ùø÷êâç îÙÄ?Ïßo¾½ôñëœFm._^„øFHÞq±±Lvbsùþâ¯ÛË]Ï;Æ%ß^íö¼3F:¹}¶Ûë®wœëí»ƒa´|ûb·JtÚª­ðô½Ývp³sªgr«‡›ßìö’ØFlØíYgë ßÞÜùQ%³|û&_~~¿®>ÁøBw’‹íËÝ^u°0-É“(Ýqkè ¯‡ß_ «úßËÿÄh@A ëzq#¥é EÍ›êzim¼P=h­0VÉR«N#ý¸ã“œ)wº†ß ?¿ËK(ÿîòâ?ŒÒ 8ŒÓo¸tÆ€¹˜ÿ $òíÓ‹¯Ÿþ׿îãç_ÿeÃ/¾þÿ÷íOàÏÓßmþáâ»§ ß÷qPËÞuªßçlÇ Ô¢@«jÈá°Y çáŒØùqâ„6($aâ. È*ˆÎ × ‚œbAB)ØÎXО(ôçaqìã‚´céÒÁ›Ì^7Ã[¯ök­NYqêêš4dzÛwâlc)„ïþôØ·°—IÄD°vvïÓNvZ;5ìžæ&ñ-ãßv¦ƒeö}õgÊ«Œàqk¬c ñ²p9VxjÌËùǬ>ì8l0ö e #u `Ç`'G_&w ‡†«ºcóG¥ÀÚd”¤@^†fY›²cŒ½à63ZÍ— ‰:3ZÀæ2 q3˜F4>Ï$@L‘7…U’¸É”s7<Ð"p¿U~®sé‡G2¿ dM'²$¬,Ž´2Ä‘lÄ«ðäÚÔ”x’¬ãžL¹â6Sa‘§îÏ”Fˆu%tdJ-nÆÛLò¥Wœ†;‡û„ôÀk%ba!ðF£-NŸGË^¶¼=JÌkïB"f²}6#ùl^g›„5“çq:”sëJ´HŠwZLôJÞåí籊7ß‚‹)Ugµl(›çÙs&ì@謰ò‡»¯fKʵñ“ˆ‹à‡DªN)õdïA0¬¥ /|ëÅÏë,vǸö7ߎ—€+ €ízð{UF$õ·00 eÇY];Ñ‘nâNb5Ѽ)€«l ›à­/ù¹»‰©‚Ð'£Mÿu`Øå{ßfXÙ³¥ú«Î°ÒêuÅvdXá:nR4¦fý ÎZKÑhüáV6]u Rˆ?gV¿©Ê‚£r#‹›¦›ÆüF¬¿<‡Á,ºº÷9jCXéöhèbjkÓPjæ Â=‡^×ÄG¶²H#¡Ê DáÇáðÐDI„åþnïšqKlUŽˆ·wµX) ÖB„’툿úªó ~S <éL=Áõ=Vk9%´E`ÿ<'¡—FTOqÜtÑžûmvIñÉNRVÎlŸ1(¸Ö/DÚ]n‘ø=›o‘¬Ä¼;ã䀸+ÔÜ ëïo°¼Üqð¯¹èI¢á(é.ÇC›t9˜+g ÓÀ$LÃT§ÔDµG"6wUõ}[}6ɾžèwúûU&ôìs.ðÕÖÆO"^‚ŸÇI½ËѦ^ÆÜyâŒ-MœD½Ú ü3 âÌ1ÿ©dÅË»±Þóä·¾D·BÞdõÑÈ>@æWÙ™Ä;=Mü=ÓyvÂ^Õ„ê,»lmüGî øœÜ±MîÐ}¯Ï*–ÆòOãë:C$4M9áYÍBÌ('t^ V‰oõå%â#Ë[øæ[Â',¿MrÖˆ³8ûÚꥑêÓHÎX ÕŽ2¡£ì“|µòÏàºõN®ùŒnZzÇ—ŽW_{¢Ç´öÇDŒË×Þ&FÍõY\3hiö4b÷ÉD׃ÈJâ8Æm(ë“ôÑ/5õMŸ]NÑžî+a×F`¢h‚ÀÇDÔË—ß&jü{MËÞ>ˆ„•~í³{¢S’Ÿ'ø.xß)Ç©Ó7}öä¸ñpsb¥þµ1¨Ÿ`ú1Qÿòå·©_˜ÅcÕ©Pø "[ÜšyÔ_—ù„äߎÊ6Ž…Øüï³K{VÇI¢S‚“GC8mŠåjñXuŠåjåšÎH±LƒX›I±us¢^òG‚Íäî4Ñު̭ÓìÚXI4K°ò˜dëòå·)•‰ÅcÕ)•ñ•K¥*'‡â}"ùn'RTæjŸQåÉ×ÒxÙëªíQ'Õ,hs½2±Ì,ÇQ²^…‘¬) Y/_~“¬U¿¼Ù¢JÖ0ÐÊU‘¬{DnØ“z⦢ÑË:MfÃÒùÊFŽ‘¸]âÌ„]²Û:5åCNf)YgÔö¿ þiH¢ÿùTu¼§%Ÿ$‘ò1·é 5Z÷uZWßïă{§0Ë p¶™ÅÚÅcÕ™Å>L2CëÆ´ŽIë×£¼"Àfí–p( ðëªñDÄlݺ:ÚµädØËÕWä4.YÑ»ª†ÌÞ3©TšÔkÏÉr®NU‰%ó’rÁ(ªB%}ÉØ¤QeÐdãü:Kýèk[êsšR½k~ô}4è\ѨÜ}1±Iê·Ø§zeèï×ó…Ïòi £U>æa:ž”Î=*÷”>zíî (}ÄcÃõ€Å\3wòêÚ›x•,)7¸ŸÒ(tÄmZÖbñXuZÖÓ(¤TnQ¹'-«èBZ&ßW•. ëµ÷#‘5Y]Ueð9Ó:Ù¹gc•TÀb…"BÎb0ât½–ïpîÓIG-ß²6_«ÅÝS˶߸Ç`ÿ™ê˜š–òÔCet#˜ sóø{ãoS‹LY3ç³ãÂÒdMÑ}ï#*Ú¦€+WÏ#èK>>Gàa \#Z¶%R ý½1Ä¿åÉä•üËNƒýªMh‚é¡?ZÕÿ[r0ÊÈu®ü~šØÉÍi\H³U¯¶Ú!…G·`žâÛÿÙ!éãv8ƒôsy]¸Ÿ³ÁH !ãÝ ¼Ží©9wÉXÉoïyÝžÏÔ (?d %—ÓÙâYØÑ÷²1X †iZT4 ËeÜÏÆm ]©Ô2¹|;/S޳áŽíÓ–˜ ›F˜.‰H©¦8Ç,¯vÀž ¶¸Á·¤³‚ ,õ$Q» +N0C„Œ(x”¼šp°!£–u~»šR˜UGY“ȰZj–š* c½k,áñ•ì¾9@z†-úËÊ0ëT”gÒÆGkIëÖÚz­fm}§RѵUÖMí&aöz{RyVj nKÙVq‘ «g4×Röé,PSñP¨ò˜ ½` µ…»Ü¹À¦*ŒÏ´J¨pð᪒F—V ¾<¢^ø©4Œó«¿‚×Ît^Õ‹áêføõºòëuúµe‘ËpZ̬Ïc´´WÉ•?£Œ.òãd\ƧáÞípõaøõftdWñnó€ áËd‘½îT±Æ7•­¯ÑZ²gÏÓ­»é9eÒ­›9– tpj•¼Üíe'œ²}ÃPDÑ –-¼Ó芟œ'WÑTŽã`ª¢þU…ÒHàlœu²·.ù‘Óµi¼°îµ]G³.¿'&X\;p½ü1(& 㘌Y&ÜŽuûøL»”XHÆõ"¡êSצÚÙ@“é{âã)/ ¸fÈÉàÐ;æÊ2Ø"2¹˜¾u&·Šóí·>íh¸£½`„Ò«MÖyøªHx…e‰ çªÛ±o¨‘°&þ–’ÖѦ1?•êÛ&ó€ôà@úD¢Lh‹QD>?/sc¥¦Õ!ÀÅxÝiy—‘£>ZZŠt Ö¨{šeÀaê£Ñ @ ¼7ÞÙ9§4""šÈDB¥mÀø×®›8x”×ÙT%À†j8i% ÎTã¡­óÙ@ Hñêì½kƽ#åâƒæ–yïšùãŽaž¡fü茡¶ñ?¸a^:)«É©Vm‚çÂ"ÖHULóÓ.Æ`u‹"‚ ]ˆüw)¨—S q}‰ou Ül;õpJS¹~ KÝ(ÓÏ¢´Åk7…dHK¡¬‰Aéb˜öaœ;ñïðº±R†aÂè¨wSˆ1Ë­Zuu#_Ä^düÇÄöw…âr©ÇpR”Ka|÷ÇǯVR Â2Ê[uäÑ Y‰á÷±P3Í®ÑÑ9C…´2TH–ná`åEÑha¡à®á«òÜT^Fó!¸`ãSüª3ù"Ö€Ú(à¡ÐäaóXÑAñ[\z(Ï…0z$/uÌZÉé§qXN± ²{ËQú9pÙœµ›=ˆ=MÃzØüéTŸ.ÀË`bÄ—Ì´cxð>ÿO»t,½QŠ|ĵ—­Põf_<ý’”ÆmØúPF;4h€AÀ°ý/¹q¶¨ V ŽMÖ ÎøÜº0öôó:4ÅHg —µ²ô8›Úà‰G6F§þŽ•rÌèF¾hR‚ÁÀ\ã8ÏQ K‚ùhKB’õ£kJu“f«KF¨*Ÿ›É"¢l Ãö£3UTKÅ:QÊ‘—x-øÆ¹‡/pÔí²y1/)u'Ïó’`vÃÝz®²èRáe¶é”wø>€"Í4Ѥ…—þÆWÍäðTZt®f¨Å ¤%ˆ fÚ>/1×px™Å\² >žÿ5ý#sè&›Cw9ŒD¤å UaÍF6’„Âê!Q 7q‰à M³õ£ÁèÙãWÔ:‹XÌ3´Š%êuQ{Pï… üY¡Òð¹"AŸ­¯ýg¶ °‹Z–ªaF¾0QuF©z40WïMð4[‰:xª)£€#0z¨ƒU÷`£¼E«Ðíô¥9yö )ÚÒÎàš]t„üôÔ)ª;fÏ£©æÐ…(êÆUHYV[_5*G¬ßÒR D¢(¥_LAlqå­w ưóEµ¶ÏL;óx¿ß[»,£ ¸õ•VößØÑ­ˆU¢ÇGB«i‡’‹QñD´¶ü.•ÖV=YH†§Ò´¦™k kz&%ãG‰»†þ•Ò‡ºüw¸¬V¡ëŸö˜²7yyÊéÛ CK'ªêl"4;•Ÿ=B»_ŒÉ5ùPÍ€¬÷ O/+Çc%9]R8 ­ïÃsl¸Z“hðý‚ê«1Ö§ª¶BºÇДY=z[OO]›L~/üŽàÒÈœøùMòmj¦äFM4­>yj!”a¸j¨õD2à¡6¢àÍN‰}ܪÙa•ƒéÖ¤©±ÂÊž#Š|¤ØÀÕ왡L]TÑL¤£Å±Á4P®àMYð»JEÄP,Ð,ˆ^gª=>;(WÖ7€Ï•W£2¢ à㜿 ›3éD_ÊVÚPb•ªA9”d\[;T*´ŠŠT8–ì!ðëK1KÈ?M!¿×Q´ ·ìá ·U-…|(÷øÐ"‡cDö†>™œ¯ÿ9€û¡ •R`%?HNé}ÐA.*U‚þ>Á™kƒ^Íú(!DÁʱšaà å~0±ÇB-~.¢PŒG[³ 76ÂÆˆÁ† îØ¢Äj.Ë)©;1ÚÀ²^pÜm"kZEQ³<´ÖŒ÷q{®îúwÑFÄ"2ìåLg†¯iœXåHÊU޹8.«ÅgÃÕ»á×AC¶ô¼°¾³f9ÓaÐô¼ô8tAÏ+5‹Y°¿®ÞÔt´”ctw~%Ÿ5ú>Ðì·ø±la( z¦·Ìøp‚ÃA\ʬ纳«ÐL8&ŸþŒ9·æ÷BÔMS?²^KòŸí;X:CŒöçQæsìöÅ€©6¨×¢·V”:äÑT>Ò)f â]ôºh¨§ÊÚºª{–Þ9¢µcà>†ê+i•Å*Ùq-ù®—;ÛY'¬£ž{³1„Ÿ+]CÜÅS¥½G¼,Èñ;38gõCA'M¸e§DýÜòv>#†N›Iï6;V›ù}ZŒšfÅÍ,]‹žËeñ‰è#µw£Ð!7{S„E*ùj$>pµz£Ú•µ)J{ºÄŠ´¤H½HL™Ef&âä¾ßÈÍåÜØ¤]žLÝ’Á~YMÙ«=f6…ž2Ëx–ÏBÔ¹úcŠÐWõÔuÊJSSr(;‡ýüµà™ö¡LšÎ…z¸Ü@0ê EeãäÓã´µÐK‰ewbÅ-qâsa^ s¸sä;5„yÇä<6=R\õÓ¢Yi{ MŠšvˆúc©f¦:ÓRNU£•¹”0bú@Ñ ¢»Ùä9C" “³ì Dv²ÞWhã­g­‡/þyœ\¿}ºx2•#q‘­ÞÙ^–¯Q.`õ©8 ;#Öda_u —XJÎÂIHÔ8ÕÕÈ‹| òŽÑã ¸?nk0)NeÞ`:‘w%ù.Û¼›dzÄP°*±7&F婹‡|3éwgÚú}&aúKbu’Õž¨K·ßÌ 1åã`tÂû€„èD1àš2 .ó˜,{D…êälX²&…¹~„I}sjè‘Ìu˜§©§^ªn ±O°€ÇŸRH¡zçxÙžì„Yéï²±FM1yæáí¹%ô%¹¤SO uä‒Ž8Ú2˜Å[q`’$ÿŽ™3Ij~š‡È6ŽžÍäè'™ÊFÿYáã é§§s±vÙZÚ4SË_½…`³jè ñŠõ”¶küÌTþÁE%ôP"#N¿¨Ss9æÈ·ƒ1ò«IAÉ«/ª60£^Võ5y¿mÄúÚvY¯_oñZµ-ðt“§]ÇÎdéÛÁqI΄u6là<·C$½ndšçø ±Sà$ÛÏkA»<*í°¢Ë}Q±|Wi¾ÿf·Çÿi•a™ËÍi‘ýpõ¤Ç‚ñ×±æÇ+œMO.EÌ áÍ/Ã+ã0sp®*Û½‘®åö§ŸÒÍÜ~ŸïÑÆr0½Âîÿþâò_ÿº}J‚õªdá¯+ úôÇ9•)¹²>¯ü+xÅ'ŒÎŠç–å1`ùVP ~™lïÒ­wù±góWoèpþ¬-*¥1ôÔ㯗ï—éÖy²×åÊŠ¼gµ¶ ¼i2”Ÿ‡_¦[¡\Z†‡u%!þ"c)”yª›49û`”£å>Ò8Þ«ãY‚ÃÁ¬’÷‘žÊ-i "»üRÉÙ¼#[?ø³âíbËÃéMžIïø=qG7ÝÏW«8ìT ûuxÓ+ÔouóÜæÓq¦ÑN7ƒÔ×EÌʧïþxñt /> stream xœÍ=kÜFrómÅæCàÀK±ßÝAàì3Î>$ñ£àäòAÒJ–liW–WvìßqÈïMU7›]MVϳõp¸ËiVW×ûÅ.ûN\öøŸáßgo.}-mùíýåà¿ß^üp!â#—Ã?ÏÞ\~ú8>&.C¬´úòñ‹‹´€¸”RuZ_º^uòòñ›‹ÿÞ=Þ{ÑõB‰Ý“ý•è¬UAížî¯Lçƒf÷zßÃ2ÆH±{¾¿’ZvÆéŒxïvÜì‚ö½ÚÙñæ?í¯T`[¹ûýþªï\ß{Èox±wsÆ*úÚ÷ìkïà Òua÷Yê1¼¡“AC/ÿØŽT»/÷Wº,µ»áúq¯:c{ëvoË«TÏÊåðVäî+òÞ·ãZwBÕ;±{U.oÇ¿OÞj¼”ÿóøŸ?¾øóÅ—J)G€§púK¡‚€§ádúø/œõ§_^<úòß.ïÞ½~ñè/—ââÑø?Ÿþé3øçËß_þÝÅç_^âZøû¸pÆÊ‡NûK‚ëúU µHÉiŽ”„6¸¾¸Õ@K_!΃ÄS}»]P¢×ˆH< „&-ƒ­ÐÊà)rª I­mg`CÒx²ÚÐŒ»ˆÄ*?lÈ„>_F"{UöfüÕ·#•µv§½gÿL¥tO¢÷ï9—jìÇÉH d??J”Û½ÞîÛýŒZ ĆU¦qqPSˆ¯ óÚóe¾y” ·¦¤Ì…dŠaÃáòÄ#C®‡¸ÍÌ}†´R®é§1¤QwDã³BIJ{UÙ–ù›B:¬„®HÆï¤ýKÙõëÙ5ärvÝ;™] v¦ÁÃð'HÖIïïÏÍ/ö¨¨…ôp•Ÿ›óQ^€ùû“BôÅ©Yá lŸz)~>Lê]ˆ&õïÍYfXhm|ú4êuQ¬N}NBœ%®<·Nð’4›†øe°[Uå®°ìdþ¤¡³€Z¤‰_ MggìÅ&-å2wlŽÿÌÿ$wœ€ˆ6w8+Ïâ‹gÖ‹Oãë00O‡Ä>)'wŠ`¿ ü–³ªŽßÖÛËÄG¶·9ñ网äÖo¿Mr ÎâMÂBkC¡§‘œ1é@^±¦¬è´™òB¿ñûIÔó˜ÿ¾82¾9B2‘f„|˜âq=Ú´j„9‹û ­yžF«`žZ]…âH”š&)>šÄ2³‘«C%`_²¦ÈLÅ£ôÍUnð4»5V2ͬ|˜4»mš•võZ<Í2D( ‡‡O‡w¸n_ç=û¸e#üÆ&Uñ¸ÄE˜ßq.(a–Êu±ÁêÝ%òõwÿWÔ2ºž¦P‰ßø®Ô<Ž9ûØ7?ïÌ{'YÛëál3‹Ð«×â™EèþA‚w½éŒïˆ1ó¿G™E&ˆ{»±Íe]Aü’Õ8Däò*éh)`Pé47ßR0p³ÚÒkV–bóRrï%@¨¿ÇzSíµ¥¿^.€ÖI[õrõZ¼êÅÆE¥Ié Ærüû Xic›8 ñÔõ:àóqÛQfÝúf¥[*­?§ßq“–µ_ß3ÁÒ2,´q-æ@ËÍYhÙ‹må– Ä÷U¦ËÉzóóÈdMvÇê ¢Hk9¹§S•UÄ”@å¤Áš&6Ĭ׊KªTo> u‘µùÚ¹s?ßéåE§lç¯E'±–šCotniÔ©†ûÑׯV«ô7ÃBÁÂíÉB¯À©òÊÀ:7ñ ~G†WÀ´ òÕóñ¯ÏÆ{wùªÅþ*ÕÀûÖfQjïM(eÙÚ·# ¿ŽÀ¿šo-a­Áz#ʤ«‡Ní|#®‰$ïÁ^’'n:Q©|Ù@íÒà ºà ¯“çL²‹¬õQîS¤"\ ƒŒµ|½1>«zÙ¹¥Í«!t"hš›=¹yÕûNG¥UGDÆ”úÍÚb–θUÕå-n4®Ð|Õ笜ˆŠK%<…›È³i=eÜ"b¥€E¦@‚’¥Îã뢈’èõáðËSG*“‡¬Î²¼;G8h׈R BRìñ©ur÷¯»²Qâr¤ì¼Ã¨]Ûàø÷aY ®…VZEƒ› ƒM¬ …ÓRSh±±.(äx9Ƹ$­ý#Š,ü=_%×âÎÕW]Æ&yËñ7.\)ºÞNÓt ìŽ!n—‰çF¿÷LUEqø¦„P©v°üŠÏ5Tà”¸ÞT‚‰ÐlYÐnÀ$}·I„ ßË ‡‘p@Î`Ï0Y“Š‚’‘ÊÍ„lèüLÔ2aO¢^ã±ùN×ÝJ¡_-Æú 7˘ê.Ÿ}»“C–Hag›jÄž ÆÝîã‚0^Ìhÿž#vÆ• imúÔůAm*­ Ø¥ñ5£¬ž;ö:±ùîŠÍ÷²ÜýÙ-€%¬x¹ÅŒîc¸æJ Ý‹D>ïá8Á`]×A³Væò®C;•ã >=*I…!»M#mÍ|Ϙ?©SÑ£8fª*¤rP9¾ÎŒç–ë¡áLh"sþtцɊ1<—oRõrSïh0e쪦¢´éE¨Ô‘5³ÂP«b™<àý/{ 4“!št6‘2ÔS=d®íF×ò ü™Ï‹7Jr59i0»­Yä:&ì„)ÙéÐ)§É fÅ\”ªSe•î$×?Õßs ¶ÈÓbÞlÕà1OŸÌj9'¦Â¤ô¾ØGß5¸­ëãkîRàŽ©¶x¾e-BÃÇ}›Ô8üˆo¥ÝøWXˆÐ ñÖʄǑ³d8Õn‹ì¦ †Þ~{Em¹T(VE—š€`[›V“èT¼ §¶)~ryìãÐmë'Ñ•_&ðYQAû"5ÅŠÀħ¯¨¸?:ýbðù«,âªB ¾¢L™çØ©Ï“Ž¸6F>kª>Ê4'ЄñS„iUnaÃÐ?a?Gà%À“ì4¸S}šwÃ:î…n_í¥éz”÷?‘{ãOʃïgg7©$$âô—¼—s† ؈R„v€Š^äètH^¡X" Ûé,ð÷ÁvΫ¶ë6~;aXÑÅa^ŽÇ^Ix5û ƒ$d]‚·Tî©‚£kÕ>s÷¦f|Ì HÆ‚XËøcþC6Šëzò«tÆ£±0@…9·ª èJ:Ûõ6Шœ»QI‡ߪ<áä¨Ü‚Bú‰úáß1‹nRœH(>Ú6­IÂ+ Ùg¦A^!©•Lã—à5U™Vo‡4×!{7£ªÉ³;Ù#ùJÉÑS#Sªcjä\̘ÌstO2 ‡¹2êZä…ÄÑa†GÔzjÃ& 3¥–×ùa7 “F´[ÝW²V=q0ž±›˜¸óÚÇàã ¼\¸¦Ð$SläL)TFYOÞ6¤€âÉÜþñ¬î ƒÞf<£Lµ#àš¯íg[aÀlƒø¢î~ãAùa,d{ˆµ⪠¾wL„—Ì“N]÷=¬Eµ"¯Èʪ9µ¢Ã,ö6ÝVÆ‹b$¯"âùDOÑ—ŽéºX…[;zÍZ¡tºaXñB¸…°!‹è©t}_ ‹˜Aí+ä`ŽÊ…Œ‘ÈøC™@šˆeEztðê3ø³|ƒÿØþzäekb0‹·òÖoüµ(GþìØjžZÜ«·t<ÅkÖ*.¿ú$Û¿XD¹»¢F®nS)àGö_P¶ï'ÕóOyàÛšÐQØ*¼oÙ¿·hYÄÅO¬'XK–¨2„jó]"­–@â­J"¦Hrê` Ì!ñ‰ ÏgM5KsÐpëH{U9mͤdä»CìI0'}좵Xõ³1–öódhAUqSøÞoš<šž ²æÆ<Úq7bK«•“Pšœòì"ç@“6i‚s— @Á|ȆšÆåiÚ—ÒPk÷aø‘½Äy™R|þöj¨¼u`¿b”E˜hТ}‹^UOÿ{ pv_íñ½ôÛc¼©{rós¼6¸ª§]+×ÙbŒëê~;'¶˜ž¬³vËJ›ÓËúr(±¢_rß'ë4c¡N:Pž6ùÓP}ËÒ/1˜•…)‡õn„DîæŠYZC‹‚ÐS}ÏGÇ’—é­(³œ~Ý ‚,÷};O«Tn¸…˜®oIµÖKîGü÷sŠ)ìDZdxøôóÄ<ˆµð&¾²jR—«§Ã<ÂÍëá)å*EÑÕH×S‚«k@øm”‹îuR.6l+ö4øŽ¨\l˜ˆ½Sz RX¶¢žZ¿$C9d£§ ²MSïÍn3ç¹nŽjœ¦ä™P\f¹ž:x¥¥ÆnWn‚;“xÂß'(€±užÌ™ã€·cpëÝ$†WOF Ëœ’ç ã€Â™ª±ŽÆÉn¿cöóÓä^ êÕAÂw“}×A»Ea@Ù÷XˆA "I•f×ôd&ËêùC5:ïFÏB€ð}N°bÔ,´Ë^s¹8;2‰ð9o#ùÑÓTSO‡¬ûã(ÉŸì%N•ÈÆÒ$­œ=R>¤ÆÂr9k߬g8Ú0?4+ÇÐÆØ¬ÜNØ`¬M/œ1â]¬:&xgÉ·骼õÜ¡3@ðtö#R÷Š¿OVœ³Žô\ንؚC"œŽíϧú­ÂÛÉ÷Œˆa·d ~õצÿz43ç”Ôë 8#XNŸÌèãÇÔ€L4€²JRÛ9pRjæ\ùÛÍø·ëÙߎ¥¤s1/ ïÜ\ìKßÇ:\²¿w5ÀEÄ;7ÈpçHè&ßúqö»æ¿ÝôûÃY'«ý½šŸÑ|eïÏò­ñ‹*¿­—rî Bƒ¿w¦†e6¬oéÔüö·j6QŸyj‰° ò¹ lFÿ bYæy¦–X“½¤Ä3IƒVо‘v gò¯ƒ·Å^\›A ›$Ú•#Ò¶8Ìí&¡aÙf3"J„eåç¹ mZ~N”Ôâ‰nq‚;-!ÇÂ79~~=`ž¬"¹Uù,ôÕý%K#‚Ïf=9k©p­Âlÿõ²â",àµkƒN0O0`äûdÜ y6ß­ ¤iD‡— â7QGÄRâ Ñ–—iÀ“‚gê¾Q‰ÈÊ•Nx´¯þ*´Ó¬we`C1”fˆ&ŸC`¥ ô˜Ùþ—ƒ€0Ch¤Á34¤_Ù 'ÂG â%OŠ ±;~Õ²ÇI?¦P±K…ÿ²ÅýVô/›ˆ T†Gäå1ÐW”î­ZDê,~XÁ<—HXJê-HXZ§ã*†Ú·xzíZ^>Ì:FEÐ+pÛSú»·]ÍäûìóóEpP[c2LJÆHƒŸE~ŰŽjg;í¸áãm¼#[ÏN¼R½O’´ ¦úø\š˜æ«æ°ï¨\@5ÜÌÔp]ü0WãŒc⦄obʼnqí”FLÎØ*eBê¶ÆodÏ&{L`::Êôz(År‹æ ¥žˆeÍh¼Ìyäcó㾣܀gNÀyM¢Ø~[’RýUõß3rÝ:|Ëðæçм!,Y[”=u¯C¢UÛ(ƒx^ ÂGXrš|/ôPI {™Š¨cý- fÏD"cÎP¿g¨ÔZ2š!+ÌÔž…ã9åðÊ£s›Ž‘VtŒJ:âÑ&ZÓǧçß~¾2¢9óh$§W%'O|ÛgãH˜)¯I¤vÖf[Ay>ÁPQ´hxbŒ„*9©‡l*žé¡áY,*èFä}€ËUfä/æÃÌ^°^ ï»Ô(DO³Y߯‡A¦@`:2^€g¢j §ð•ûãXû„³ÇY.ǂ؉´2í{h‹ÅS|HÆ4µc Å?ø6|–ÿÄ\‰€Ìøž8LJ|XU‘%~µÂöѨñSá® ™[åÍ8­Á '—Î¥n³<üÇ}üf H~³$‰n1˜vÕZµœ?‰Ó˜Ïå!y?ƒdz±JÕÇLî‰Pæì­5³ùçߌùÛorVò ¢BµFÓGN4±.£ÈšïçpͰU®ªþ’ÃðKü–Iõ*܃¥°ÆïKð_‚š4|á$oˆå\ÌõšiÀ‚8ðý‰yYÐ(ÎÖµ„/“ðu—Ê…Îü †ÏàÌ' ®³øaóéJ­>ÞCMÔ\Ï+™ñ²óü‡-¢¶?ړǶ’UÞ41Lâx¹àëZé åæ_LU&¿Óc³Ië"òò«´wбrq†ª´À½l²xù+NRÀNUmuð Np³)ñc Ñí´´°™V˜åuq´Ÿ"$3™fчã@âXýç~ápœá³ç‘€cÈ5×äÉÍ,¾–±€áò7,¶3Ƈ(AÓů\æ{¦¯6×ÚÚö\š´#%޲öÜ€,3䦜7¯›™Ë£ã"Lüacò诺šcA'ªÔ‘Ÿk>˜×ºê»2|ånfѽGÆ3MMwoK[™Á𹿆'`«ÇcvýÏÿ‚øŽendstream endobj 878 0 obj 6751 endobj 882 0 obj <> stream xœÅ)´‘jŒ2«kê}»Ž“š 5Àa;àS=8"’cÄÄ)VçyZZ ¾Í(XåKSM‹•Þ´‚­‹­8­”4yZ5:±z1!ã]ui#ÑaéýuÅ4Ù5”$óÂZóMë0(çW'•ˆ2&¦(ùüFÅ¥ýjFRè="aMt´ñ ¢ä¿˜- CÛÁyÕP—ë-£C>b@ìtM½$ùL30ê_ue”(zL4œû´õêÝÚFæVq‹l/§µÉúfÎKé‹ÙnÞìœ2eüh—%ÖèÔùwl‰«îE$Õ€ùˆ$’NœèÆDóùLåBÄEÅ»BµÊ31WE˜74i”J4'É«tè|ã/}#ÛR©AH™¹·UL¶ûç] ¿ÔfQ@úÇQËk&[D,} pÚ7ÝŸ7ÛÖŽƒÌwè´+~Ç«/䨱Këb›Õ±úS¦#VQ·ðãÞÁý#rFYáç8À‘±u¡ûlEõb•Œÿ£âÞKçˆC¢ž±£ŽwÇêg„þ€Ð'O°ó[¹௹ mÂü>bÞ3[øî76ޜ֯þÞ@a?w&$ul!wz¹ú;¯µ§¹\Øw;OÈäsn¥šóÁ®Ø0s˜, K´þ¶ôý„ß”®LÀØšÕ¹LS—˜ˆù+“HCãÞuw9#pˆWüœ!‰]±õ¡tLw±%:4}ÄtUq]+UÉ“UÙØýUwAn¼lŒZF‡Õ“5‘õqéü®„Øuw~DÃìˆï±tmJÃ#ì¿KbzÕÐ*v½( ÁæÜXíÏhÔè9BJ×ÿ–Æ[„½MJ^Iõ¯+jþ´ÞQ7‚[«v›É/£üs黨·$Òý»~5~œuÄa¸L˜áâK‰”ùZ$‹wÆÿœ×7eó!â-3Љ?vt ‘ŽeƒP’¸–ô%N;Æy†Ï›Eˆ€™½Éô© êÀ¾š[5å¼×Y@£„ÊšÒ‹ú¹Ž’ ¿j`Ås÷[BõW<¤C¤ é"*éžöà õ·Žf"êžté-Û(Ò3ìüÐY®ܽ戄íöîö¼ÃíRKPbØ;ȽFèIg,ié²oË9B X·‡G{l6Î7‰8]ç?à~iGí™Ö;¢Û†Œ²öÎ*ç§Ý0*ɶICÎ:Cˆø×}P’S÷­†zšxî÷Òõu­é&káÖBvÑvÆyÝì±¢UÎ;c!èLø)Ï­–’Eõ^ÌÚ©>µ‘eü¡£nF+†ù‡[)@Çñ´ƒÌ˲ïóèEX{´}k“èEßL[§èûKF%€ o|4 ÎRŸ2r‰Wq™Zü8¼t È×_áY’b¢-œ1’{ÿ÷ZûGD6ÒÑ_cß5xÕ³>Ô?5Ç@-€¾Ç¾÷eŸÔ5Ô]•s0$£<*ø„ˆ‡Oª(UJ`È!•Ñ À¾¯:GØÊ a°äx×;ëp2Mþ¢3œlÑ£þ”õdÏ:*›’™2£7S˜4 鈵.»j¬'œÈz£+µ½z—T1yﱚF$©±Ñ ¦kd…àëŽZâ6BÑÅàj¡Ÿjê"sóqæ¹Ð}‰`MP?‡Z‚š­Ð{“c8ª!QÃ…/·Íóp•[Çf¨ äW|Yaj³{°öpËœr LÏ`]<˱¹Ò¥k|nK—Ù[`÷ç09÷ž¬‘'y«€ÿœû&_8Ÿ7f zЉ¼ŸVÔº¸Õ3M³¤ùÈ“êyÒdgý!eÚµ¦®¦\Ìm–À¬ òU)0{°Þ¨Aí|›¶pã ê$ËsžCVÀ/šü@$½[½¢óÓ”I£—ÿó~lNJVÙ¾œ‚™îZ›ÃôO¿‚… Ágª´ Ë(œòæF18c:I JO±$P“,{ÊUj0mv1e!¼”Ô ïÊ ò|ªÂœ²—’e2šÌ … ¹áèç6^™´N‚ —¢ìÚÃLÊbVG„h¨ ?eäXÒå>C Ê+0ä„·)ÇÅЪ3„éc;Â2v?t}<\Qƒ0ËZŒy:+ªìÔ‹Yʇ%*íhnJqhm­+AÂ;²1n!–×xÍÎQ¬½ ÖWf¶Pd¡ƒP‘Ÿ`qùï³YhȾÚjŸ¯f{y‡ûÄ®·¥qXƒoø‡ }7ååì:áÒÏõ2Îd5¤S^wsÁ¥ÖÜhÕ§9ÿ¥Uba&l0ùDj誛E¿˜Ò¬6êÁG=LH^´ú°c5(Œ÷o’΋Úòa¬jWN9Ýʺ¹òÄz}ûlùvE)G;è¤õKáÅ¿O'z=n«§j‰3Üåœký5¥,+ á0(Ò£Ö]¹bfQU– ¤%µ óëxMÒü¢œ²ÙM!N˜U?kÜ¿1áÈãU¯]•úîÀ ‹ú•G…vL\§½U§þºB7ÍUmçÁç•qÚ© e:940Ï© å¸äé{ÂêJ¦ZލY—B”ÞVª0ÕiEÁYø~Aɶ‹-Å'l]ëŒQ|¦«î,Qñn·ÉŒ4…±çÕ¸_öÀzo_´ @"åt½?mP±zëÁ)ša»!·üÏÜb;ãT’Au/ÔÕKâQÂqg,ùÙäkóü´3ö^3Kä«âVõ!%.Æ83$î\ع£,­øðHÊŒôoûüzûô‡óé1ÎB¡uÁ¿š²æz¾¹;”yÇ–¬  GX!qo¼kLôQÆR´Y+ †“‘-RŽWO¤¼ë|&ªÏ`6žòõ.nüÌö>k6Kd2b×)š]ÍðÎÛü†kIädgŽÀ昺&áË„ßÀU‚U!Y‹GÜÉÅ’J@iýöøP2奿]|¨ØÿÌbƒŽÑ1ºf¶Oc4eø³òÖREÏ\¸^î²»d¢)=%¤æFÈŽ¥ %ùÌöú·9F©ºÞÝÒ/šl–¨èd‘ôÝ$(vÕjK€'Õ× »ìåbïeÇ(UZ‹åŠõ´@5bÍÚlÜä-nÐé?ZŒ&"…ѦŠ(\Ps'ÖBŸ=Бß_7ÃåòC¦g}Óüxí"PºÊ­f%ê§ÜQÉ¥ÔÕC,Uw&qÔ[¼ù¦ðQFí'(ìFZOAºÊS€³÷/@ô LȬƒC»ø"3M:ö $2Tð>_|j%m¼Ñãõ`Dí¼9:±íÔî¼#üÑXA`›÷æÛ ÕåŠÛ©AÛê¾f:jÛ}P"Yéê\ wü_²µØ==!›Ö5¾•ù¨³„œ‡ŸZlž¯ã^•=ˆÒ<.1n527®[ÅÓõ Z5øü‹…ÝNHå²/Çéye€c[Em]TÕj‹e ¡É ÂrsºÈ…xùåôqTU°ïy×ví[XycJøæ¶œßÁo!¶ØŸŽ™B®¦ó––ý½Ë´ì[v¡—–ž?­áeÔ³^„°<[´hƒ¤' ¹„X 6W|2g«{=™£ÆÂËã,”× Ò%M<×>n‹¼¦Ç^¢°y7{ÕµŒ»vãqö†·‘NùPWRrÚõNÎ!.¼’Ši/QÑ÷žâåôÅbÄ¿„î¿Ç©SŽ_95åøEp¡ÖåCöÈõ’ìq¶~WNš`:Øú¹ Ã:?²c++ÇE¸?ìi~¥Ø*ŽéiŸCxyŘQ¦†r?žÑQÊG°ËmիΞ¬7“¤²vÿ°Žˆ*’¾ŒÒ1ˆ…ë­Liõ2ûŸ˜¢:!w‚ÞvÎ_¬æOo2t”†(Y4ã$°N/MOö(ˆVöÙRžž. †ªŠ¸&“ÂEm£?¯¡ª‚L†*Ûè«ùfÞÕ]"±Q,üèD=ÔF˜R/Zf…j‹_ñˆrVÏj–Kb¦æþo©S\Kæ÷­}ãêYwXc™DŠrˤ<ζ»Õä‹´GÉмԠHŠ ^²T׿_ÌNá‘NÒ¶£-ˆÛa5QÊ~¬ü&õbd¤Ûô¦U{0Ìê**öz>zcÞ©eûC«>ÇýÝÄ šû[‡d74 °rU(Q²øÔÅ,é¢ýІ?e¯ï›š¹:š7¯™ƒkbé>b›Ûn?/À×Úé¹y‰À9˳Á‹éÚD#zœé+kiö¼>©æ}½ÕѸ«–8ÏÌcMõŒnK´DwªB¨Ê¦ã¬‘¾´5?“§S˰E2»u“§­îCïh©'sJãxıRGe¦nÈ™8„é…naÀb@9ÿÜÀm+màô¤Ý1œºVNåÇD»m`ø½äÛÖT/“ø|,>#ÖC0Ç¢”8¸ï¬[Ù³dM¿7'ÛðD®·¸‰j¿1׊"`«‡kUž^/øËï×Ñ5Vªþ¹PïûGtOn(=0­eUë›§’=¿Ó„(ŠK–²Zöº»,ÛT… ©¡™ÞïW±·ŽáK‡Òioð×è÷S¬NZÆmèsðíú7äÖk~”sŸ¹¢óS•ì®%²“ÚÌë—ü•]ºÝºq¿ëÝýê‡r—Ðõ³ùÔå'2§ßÅŒžnÿw1û> stream xœÝ=ÙŽ$¹q†ôÖ_Ñ~Rµ¡ÎMÞ™€!À:ìÃ:=¶ H~˜{š£wŽÝ‡>ØA2¼*3««K†!¬&‘Eɸ/~{=âzÄÿ…Ÿ½½úêҎׯ>^×ÿÿ½ºúöJÐ'×áŸgo¯þ˜>“×RnrâúñË+?€€¯ì äµå`¯¿½úÓAßÜŠašg=ý÷ã¥âWÃ<Îôþ3ƒ°£€ïŸÃ÷£ü‡ÆÁ€r˜…04ƒ¬åõmöõonná¥ì|øíÒƒ¶f><Æ—z4b>ü …Íþ«ÇW¿¿úöZkå`Z„øVÓõlçAO×vÖv°nÃÏ]}õè×ן>|~qõÕ¯ÅÕW_ãÿýüw¿€ýòúï®~õ蚆‚ŸÓ8 Mã¨aÜ5Nw“Åõ<ÌVZo²&}m'ÓÑ.Ã’Õ gí¦Ã77°Eì¸:¼€·Ò“Õ‡÷éí‡X5³:¼¾ƒ°ÆHqx•þÎÞ¾KoŸà9Zk„=¼Áaa¥ÏøÛågl„é6Ø'AOƒÒîðhæwðR™A }x¹¼LÀú :Þâ—€µúð_7·ãàÆq²âðÏ7PAŒš=}E¨Ñ Ø"Û&Í2¦€ÇϦÉE@@w›þþ‹=xœëåÑ ìWï|ŸÒ·l¬Gé1.U>Ø;Üèª\lX¶­?ÂÊ Að|ù‘ÄñÅ0ÎÀ˜/µgDy¢š÷ˇ¯–§øøo㡪têVM tÆžò]Sj"=|·¼Ë¶G%J#ß³ƒz‘}U.,™úñF Æ*!k\¤¿¿òË2ÛêoÒ–¡?ð±GÄf\KpdŒ™¤<Üñ pa£›³…y´5ó8uæˆ]icÊm8•[!ý¹´©˜í’Þ¥Œ­×Eß²Ç7ø-p Òb= ¦¸k±F¯þFëúD,¥ƒ•§$Ítæê£‰[§qÈ3ÈU§[rÕÙA«&Âó^° ¿—£Ñá‘8¬_Ï6è*6p&ÆœÂM1æG*“20ä z‚ŸÁ–㓞‘ƧÆ_Ùv«1í‘fAϰEý À—Yf z¹€üfùýòîû5௠Þuà.ÞØï»åݧå雸×x䲩›MfÐÙøÿˆh#´Ók¨"f`þÙO_/“¿[@ûT€ëPˆW¯>„‡£°J9]±æ¬JÚ:ûå­±k@ Æ£õf±¥$ð„ŠÒáâ§f¦(j*ugž$ÿ4Žêd_Ôú;M\{}‹Ìm– _0.ü9ýªPSÁ â2†­$0$+j ‰l’1Ïïn,¨6“µì8¨­HwäI)˜‘B¯²EÍW*àÄAÑJbén_ZBõ}ùeÐ!áX…0#}v2×W9$%È/¼ä2„1Arµe%°S%èäá7hԀЈ™«æI0®Q“šG”˜ŽJSt¡Ž òv.üMÐáÕóüoìM‡‘iŒ ežœíyUyZ™lm*`?.+º‹¯ÞLJwùGìg½¥93£¿ÈÒÜvqYÝëàÙê–•?‹Ëé¾Îw€s“ÏEiÀ"Ò$Œ«+…ty 6„ÖÀ í(<º3¾Ä8LÒ¶ßU<9Ò ˆÂ\³gŸþ~lIO™}„Ì =³(Yï %Äx ã½wk`®†Ã.ìKeØýª°>ž˜sœ¤3êUÎ £³‡¯™ú„,”?¢a<Á¶ötíy#ðúd³2õ8iù_ÂÚ@Dýù¦~ÞbBÏcMS3±’¶´·bŒþ¤#clŠ’çÉä~Þbëìž„]¶¹©ÛÄ̔Ƿv\å¢Z*⢠°ätZì13“ò39TJ”ÁXï?c‹zÁüŸœeðEå 2¡)ŸoTM…¢f t8Lix×<²H{&sc°oÿ|³ Aüä_r,HŒ3©‘ ; ëÞq6Õ],@™@ËY®« AàßzªCß’ð•ñÑ<8þKœ*[^¡=àÍ Ð’5R«ýå))É p‰å)iÈœdë{]Q½¾´öž«t¨£l%£Ö¢†ùµ€$0~ÍegÓió®ÄéÀˆ‚…ä\á嘇IIÎ%°*a÷ûŽÒ0Öª$Ð.[E¥9$BŽù]çoGÔK7‘Îwô€C ˜¸¬åeóM­'~r3Š‹AnFÐ0lŽL5§¹[@_°÷›ºn…¨ÇtÝZ¼œ®Y’C_”š%êÁ£:bàcôAšCÏEÝŠIeÞn@‹mòKi7({^Ý4,€kí¨³ß´˜EÓefÅ  ð…ÑŠZ>"/©¤/gj1[HGI+`j™ñ3Ư¦Ã0ôÝâ°‹ºËÀ€ý úKô¤9n¬ÚùÖ‚2è‹Þ³€¸ÏrzF¶ýº¢“$ VTS5;òO ÏœFt®æ«¹wÒR\t 3Ž9èçãNÚ !’Þi…Ú­Íà²#Î6{ÈõkâKå Àë]nŠÝU'õhîF-3K=à̃íà`r/Â]ŠAäÊ0*rrÎø•Xk`¯‹ºm˜¶Ü ï¥?W»PºPÛÖÓ€ŽèMÁÊÉPlé}%úÜ9ã˜^»éG¤£ý’E¤É$±’±ÆŒã2.à³Ñ…«“Þ:æf“¾ÉlîÜ¢ÆO‹àè5Nô=#ÑzjjwUh?D8ý¶JcƒV 98kTùôÌ~Éøñ¿ãŽÒ îZÓ2>ߌ‘2éÇœÕf0™å„¤ÕH£+¦Î·ñ<œæ›œ‚·äM·,ëÂì±…ÎäpØב¥)Ãà®”u,sñ”XêÉù}"òM]7ÇÃ!-*Ó6s}ú1ü]ÒoÒb|˜až¦’=HÔtí‘è>ĤØ{AóÙìÔ]í 7Йö÷©"Ž-žå0*¸3s²wµRvA3]‡)yHH Ø@çϵ5 w É)2û¦G¡YfÌ‹&.V˜€ÓÌ)þy›ÓSJ‹|.xAËœ"=ï‹,ù#ï;OÑPã‘·-{»6߇묠ü0ú¹=Fô˜'²ÉoI‰ÀÛšÙBŒ€Ã¸vÎÇÍüå\{ð 3Bé1„ÛfsŒI¥Ç׃˜ ñ/˜ÿþMÆÌ÷‰ ôbãÂŒ¤À7Ÿ'6ÞË)ý—†3K`¼åƒKÜ¢Ø@’ÄÈŒhuc‘1ØŠƒùh'ÝØaüÙ— &ÃãÂ샎„'©JîHÍŒ0›iELkࢨZYÅ™AÛûþúFào ¹¼RÂVtGÀ¡þ$QC‡_c‰R£æQ„ôeô½fÊ„{O£¨çŒkÓz/+E5£d•ƒZe™^@gÀ1›omÊ%7\X~y-N‹¶dÁiQõQ®Ãažd¤ñÁ‡°&ggŒÂI Êy²\ì/à6òß p«0wéÛ˜‘åÕ ÆÙšy¦AǘˆíÈ*øøMGZëJµs µ¨ý6ôHVºM–ÜË>ý¸©r…3ÓA{šsä¶ÊzZø´uRüG We¨È:fÇiÍës¹ÙÉyRÆb k…¼ÎÕ©Ô ¤Î³ï<ô33 ¾4N†W¸ëÀCКËÉ=ŒŸ ­p_²4ã&1¶õ<°ÆDý¦’!Ç™”µ 1Çø–©x_×™¾Ç­Ž¸™ÎŸJ”ÑM5às"¡#âÚVDÖ\¥È”8X±K¨jZ¤Ò·cöõš§éí&4@â“öMF; È^¥ÇŸ–yÅt¸ 'xŠ2YÌs–çiÄÛ—fôïs…ç*S…^·ôŸF<_5i¾/õ‰€\[™HæÌ—0(• úIËÞ%7Ö•1Ê€æ.Ï嶦äøÒ ʹKKp>eEéV ¼èF^u“xÙl×$âªCt´²Gw¾‘ÍX ú<—ˆßwý¿õü¡˜h 'œáL:é‘Åèq˜²µ¼¬}»KHnŪ+.¸Õ¤·3ÈŸ×;½Ä gh¤öÊ€ìV‹løÙ‚–Ô|¦ieUsKóFtü¡éOeß2‚y빃›'O¯bvs‡ñ~®(* νfŠßîÏ1æiÍ;M† lxÇÂ~+æi0°SO›?kúfšGj±;RÊD#½Å‘`½"“áÂÏŠn üXã[»0“¶Ô,/Uë%n3fXƒÌú'„hÁÔ{Õ /-k.’a¦¸ƒ:[€?Y k·=·+žÙx–À¢WF>¶„ü6*3Ÿ&úgYa7ÑDböM«P˜ƒ ÐÛ;õ&žùÖ¼`›‹þ¸hMò¸YÿTØ#`«)SÇö8eèç»b)‚G]9ŠÊ}ùT“ CÛxJ t“œx4$kîGiV'®¦Ö> 6g!vyWˆ¼#eÙÌÓþ{îøÂf0çN#ß)e$m‚߸!?ɺ¥yá@Yçò”ÂâZåg¶âÁ³’FA(¶ÈOK’ZN1.°>ÈRgëû›¥%a`p,aÉ4d8 ,{Ø•4`bÿNg’‚’’dT‚Åzöž7¿§{ëÇh(è1=da€¤ ¶K ææ€íw„ŒÎ_à¨Ôï"«›F¿‘]"ºpm@MBò¥N. ðÌÜ Ô¡`t sô^/<†hL6ìËàZ*ØGRëˆA±ÚæŽgZqtnøèܾ0 “)‹k=$ÓÉÊœ•@KÕå&ôw[øŽµe¨ñ„°›wÍM ›ÍÌ7aY¯a Ó×Ëqe¶Ëùfu@Á{åE©À'¨·zåiÍé^ù<5tç(\¦è éõjÄGÓÎ'hŽ”å0?7zŸ¤µûÍ`®¸Æ 0jöQ§¯ë(ˆSY4ÑͨÀÖQªg¿!IŸ#ÍT8XÒdéLì +€åkQ&Îø: {hævjìËJîokÑjcx=Ô\¯I›-YìóÔÚÊä¬öId”Iá“x+ð/m&~,U¸¯ÉŮdzøkš¿¶åЫÖ¯…Ëm¹ˆü Æ`ÈQ-ËT2¾ÀÁʪa{¹çgòçÙÍSo×Òt"û™§ßÅY½5˜Uy„!„Øè˜Ižˆ*s×GòþYò|ÿgløÀMĘEÒ1µÄù%û`IÛ2<‡®™ô²åiJ®]~¹5Ê#“ŒBªoTÜÕ4‘ñ?o(®ë©ZìDUÀþ4e <å8çb õC`ui-~KáÌ °YtúEYÄHú>½ƒÂÖ}{£ÎÝËœ¢žª%*~c Ã4 Œ­–vÊÝj˜Û©„ÜC¤ÌÀ2îŠx¥{Ítv¥Â…̺1-À®F¼›uƒ_, ßnKÒ„?OÏ«—š×½Ü†sZÈzatvY NŸ8'¶ØN©øýnZ¯¼‡~:ZY‡¹£‘AÏö”ººFìÍ8øYUñ‚ø«uÃך¼Xª§›Åz´äß×Ôí„z:K¬Ëê.PNçÈ/w‰ÕùÆ|y»jº‰º e d^«½ÍkÕð>K7’Ò/±%^m¦2]%pØ' «c±ã6Om‹#vÌjÛš S h]´Yi ¦4#íU•Ñ7Ð1*§ûosE%²"é'¨/L;a†Sï› DEt•׫T¹Ë‚ö)cx‘µ)´«ÓY’*Åâ¬R‰³rŸ$O¿VG˸kÌ“]û' ·˜0Qoù‰—† —;³åÊ/‰ëª>‚’.³‚²fRQB§* U%ï„&ƒ &’Õ”•˜EjUGj#Hþ­gx©q¤öiMëŒi/MUU«ÁJ™Û*Í“ÿÓÊ å“ÂòÑpb>Ž~#/'Ÿ4wSâùmÏ|;éSs›•Q$¢±ÇŃæ6« #/Z)ìýuBn³_§á,eªVÆ#‚Si·­K,=%&9v;Öhš~^ìùúÛÍ2•‹°Œ•BacšæÆì™¼ÌJ'“õ–0ѵšìÒø¼5UÒJºÛ“Oº¿²´”²Ès¢*9ÙËA>Í€ºäç,ªù¦ä±%r”U öäÕžáet€ŽõÆqÎåÊd47hˆÑͽfKÚR’ðGä¹T‰ÊÔ–*UOLçªS8Æ}ùóÙÐn…?g8wþ|®Î‰‹g¤ìœè-ðN¨«Ù(¿#ËHG³þi«Ø‹l¤xüO×Äwô¢¤â½”Âн¢:‘ôs­û¨ª´¡å‰Úa1wU^òŠÚ¬âÞåÅјKݽ ûÓwG+’0ƒË«WfœË÷{”QŒ×ÊéòPð¯ÖÂʑڪ ߈ÞqÊsŸ–‹Èþ/9LU@~ÆŽ‹xR6vK#Ì|ðŸŠf¯{ÒNiÞú86UVsâ¢ß-ý 6üʪ+-çA™Ù¹ë[6½ŸgÛ]–ô«ÍwY¦¯ss¾»,•r'ö¥û»„Ó8ãƒ7 ×Y*ÜɬaAç¬ÓnÈÂ;þPëâLá‘c7da>_Ï}/Èò .» ØO¼«çΉióÃnßNØ÷0£ã=k£Á¸Jî_¤‹+Uœaê÷Ùˆ×6o"\"]«#°OàO5œfeÍvºú‚‚Ð@€ó˜X’ºÌñÑÓ.kÌ[D ò˜¸óà\ëâü– ÀÈon–.MÛþλ"ùO/sW$ŸqÇ]‘j»Û¯8FϽnäñÜë®Hß^ïX@,D‰N¾+’Ú¿[¤€ÔyŸøŠEÃR8ÊYoßîpìªqïM ]†Û)vß@s6ð;¹}¡{ß(±(ئvxº÷¾À+¢³cO` ÒF°ã]–ŽØ­ Œ(¶«ýQ¨˜î7£¯þ±èY3í%¶àœ²V˜‡·éï"N[5Û ¡J‘ÐéÑ&Ý„¹±—v²¸À£å¸+‹(5Æ&óºª5ag+`K*÷à# ‹‡7û¼°c :“°»ðAØ1àÏmø©lô6.¨”*Ñv6)óJ¹.|²TP2óßW7vÌ­{a‡o­Wuw¤\ #ý$‚Ùº¡cmÈe:ÑîM•¢÷¼t”<¸Þ¶vX×Ý»é˜ÌɆCÈl±ŽÁ‹î Š©@jjbHÆ¢Š.ô3B¿ÄN_‡]ù‡1ï‹1úÒ â-í"ÞKmCÀ‹n±,‘èy2-6¤üñýì«LSö2†0Øl³rÑ,¢C lyø$Ý }Ž~ =ìŠàÇtôf™Âz4ÖŒ°ë Bæ›x­wóªVÆ9Ú¥òL>Wzü’Â0íàR{ŠfÙªk êN“ëÁì*t›Ár$ºH îΩ<–ÿ³DKYöß«ah_¹ãûÎŒ@Z,½Âôk%·¥W+‰7KÅ”ÔÂ@K¦ò—#ƒœ9ÝÛ]'xUîßijICl²æ½K«ét¡'ƒ˜Û~tÛz2„úP/ÆSÕ5%'*5Zãì'+1졤À‰°†ã•’e]hlOܽÏ9ì0¿P^c.ä gêóVÙvpìéä³ê‡Ù’Wèû¾n+-½uÎ^,ˆáfǼð—ý$ÂP{=AñÛ‡ô“*‘yJÔÛÙïë,¥åMµ£J§––Så¿éå,gÅZyRVA2ᤕ˜.^[Btí†Æ»kËÑ\]Ô–gøùÜÉxÕÊ’:}ŽK¬©zuíV0»<Œ Þ¤Ú¿ÅŽnRÍÈ`é#¿e¿®ëÊ—^úŸXUÃ1»ëlô|d1­ÿ|1÷©0Ÿ¦ËŽéZQ°£s•˜/óÑ[],2 «•`zkxȳ§ÚI?,ôÁx_%Oðïȯ$l‚{T•™çe·KîF`ãUõð@`³Z2•Ù;kÉÄ8âuìÊ[L¯OWÞ~¬º»Ðß9#º‡F;!©éþÌ¥W5¼l‚íµWfFlå¿ÝR|…O¯–¿–]2–ÊÙÀ@ù†ü,‡·¬¾š/PÜúÿ¯ò+Ì”:ó´±K -åÝñª¥]QYtÏ¥×#N€„ŽŒ§'Å`©]Ö|•Ùyâchô—ysbÞ½NzDKc˜ÔŒ‚áỢWŠ»‘¹½üªîzò+n[ýUxÛnÇ¥“47?`—W²Œå¾›4žÛJÅÀÎŽ{!Yxçm²è$%S ¥K*ãˆarÄE®‚U‚úJÄŽÁÖìL;õû[ݱ§©[P•vJ瘇GNÎ<í öñÌSd²b„ î ¡‘e‚~æ)õæ8rQcÀ¼Óåj¨¨Û€º¡MH;Jr¢4Å4f!ͶÂfÌ@š;úÊ3OùŠòFînï8arnÁ•”>­­è½M[+Y;AÆqY@c‘÷¥ÓÑ_¶Øiݽ¯exî5kÕ-Å›7E`;@(•m"ÔÜÕ€ ÐnZȦH³*kÓ|bÒzÑ]“Ô58Z5H¦×^’1‚WM×h4“½7WŽ,X9(›P¤Δ1S²zõ¿ÑUˆendstream endobj 888 0 obj 8555 endobj 892 0 obj <> stream xœ½]{o%·u/Üÿô)ôOP©ˆÆ3$‡ôÄiÒl‘±³Qª]­ì­ei½Û›¯Ñ~àžÃç!çðÎÌÕ]¡H÷z4Ã!9çù;þp>Óùˆÿÿ}ùýÙç_ =žóîl<ÿwøß7g?œMþ–óøÏËïÏ¿xŽ·uî§…VçÏoÏÂӹу’Ξ›iFøË÷g¹˜.¯æÁºqVÊÿ´ÎÉ‹áòJ N)§ÿúü?`ÀYWŽƒã˜NnnƼ¾Tƒ•3 ùÎÿ‚Ç.^ú_ÊN¯›_ð×ôÁÍzfPªzÁ?ãL'eÔÚì&9¢~öc~ý«<¹wéZOt&2ƒÔÕ`ÿs9F‰Y¬Nd–Ã$ªgïóD¶íƒ–C=¿ÖÛ ôDŸ»Òzø¹¯¦yøžßÀCÏ/¯`§Œ½ø¶|ðW—WÓ õ<­~ð FÓö\;…ÿï+Ùõ½›ùæu*…ߌ¾à†›(¼Âÿ”põ¡ÜPß+'xå<ÑÞ”Ÿïáó9=Ïç–’{ïa„Ñ ã¤â½ð_Sš¾ø®\½+#¼ƒÇÜ2ë‹a0kòEe/~º¼ºG«§ôà†8¬––N,üÝÁ¶Ó÷¾Å¥_ȉN쯺a„ßpÃ.vÌ[Ý*G1ëè»îË­H¿I[§/~M–û§ËiprÕÅo€f wñìò >¹ÁŸR¸AYIßEöàºÚƒôØ»K$)1ëÁ y:ÿ%Œ¤ÆAŒ&=ƒ;Û<›‹ïÊ äêuÜ7]ü¦j6òB„[õ8_ÜÆ jyñ/øÓ Rê‹ÏË÷Šï`7ØpÌÓÒçÉò¼E‡ ^V«™%<8¦=œÝˆ÷¸¸3’Rõ»K9ÌZN^TÁÕ0¢ha·î‹ äwx”ßã/,鸃iƒ8°j¦„„Ò°…á3èʶ¯ðÏbÀµzÂШw^èžD£§ ¡PØi:Ô}™ê!aà¿1Ù BÐßÀ¸>wŧ8i+]é7 9 MÓ³Þ}\4°ÎŸ ¹•‰üAî‚ZŒŸbÔþc‹–äbÞ?G_ð_ â²~í;¼× ÒhÊ„ yŽ%Ÿ“ü\ð“N¼U³ùäì §J¡Fö0­@PÂéïdRðï ô©ê|·L”£_ÖòØŒJˆò‘ÔÅïÉçˆÊÏ=/ßãx³œ­ØˆPIyñ›V›IXÊ’¸H`jX$Ñ „©ßRžå4QC¨¸9À ·å1²{e0Ïàñƒe_hÏÕæÂ @©Ç(ËøQ‹8‹š¾¶G¯~™QÂì,1N‘˜¢ócLQ 0j°^eSôçlš¼o,@üuŸÿzÃüõ†.¿}~öåÙç2˜Ü°éÌLc½Q4 ‰blõ/ž}þì?Ïß¿ýðêìó¯Ï§³Ïÿï‹?þþyöoçwöÛgç_v-øö—šÐ’¤‹<Êþâ–¡µÃé?É2̈ôI—ñ!Oôm^ÆëÖ2gMFüòÈHKðp¢ÍÈÛ¹ Á šÜ>‚à,ÃÑQJDø½(W—ÂÃ騸‚±þ’5+€Ì Ѫóæ#"ê!_¬D ÐþJFIâUFu«°Ó @‚½ºoCZÐä?ç?óv0‘T=kÐo•žwZƒ~*n³å‰b5}X×êgð(œÁc„PÖh•.L´£9P]4šÃÌÃèlGýþÇý°°ãÃ\“fÁÏúhfÆ€FQÕ„2щa„ˆF#V2GæÕÆ"9DæþÜ: 2&ÙŒëéµá§(uµ'š03}Ûí%x0všÑsA£…–5Ú‹¢.>Få¨;žâí¥sJ_—‹XŽÌFŠ¢÷ž¾)VJ³zTØ®tï&Ñ.˜¶ñoûüÂVh9ð¦Ô½¬,H*VÐÄ´£¦2êþR“´Zç •††ÛhƒkÁ›zÈ938í ¶ß4‚§1Ÿ!Ûõ8FÊd {üÑ–„~”%1΃®´Zï³vº¥Ú‰S¨xzhŒ@ŸZ¡F\†LÙÖʳ‹¯áUîÀ×dûÒGàk ¾a5ÖxmBÙ@ŸÝ¯!6S ±†¯­g<¾¦ðljð5…p:ÚGaÄÞÅUþe7âk÷оàx|Mß©,À² ÀýÖVÑ{_µŽƒ¯y¯×±Þ££ ÝD-‹â«¿{áÛµt’áN4 [¼âhÐ-íb™ ÿzÅÊâ±›¸³0×?ó[ô»l{]•Çlüô±ûh2¡-’L&¢Y-1c&¸FM-²G?'ž·“–$^%.8’2°Æ:à)ñÆów¬ A¢az°€.ÓªÒš6šp Œà[G–Ë…X˜dGñ&[­G9 ƒ{ê&y¤íj“Ê%á:2…‡K0+&ôª—NoB—Ž À2GØ2·”jiO£  <¾]­À¿-~h‡A"Ò”£Ž•>%úßkÂY‘Œµ1Øjiéü¸Å€OÝDg¬§ðËý²°Ã Ü1Ž’pšWÖzÍ·…ñÂè‚D ßat[ÀÛtC¤¸‰Z¬5åRª5ä#Dˆ€‘1ìϳn1TRޤ !“rg…ÄsÚòõ%˜¯#Z‰…PÍ‹p›¬ ž¼¦,Û)ˆµ°ÀZÁ² MÜ9“kõ©˼(b£ßµ²»å|^ ä• êTÎCø„n“%"GØkWÝKØúÍ’4´ªAÉŠty$û-źˡæFÓœ4}ñ5ð¡r£žyP¡¨…UxAûŒ¨4ó"ì²ز#&ià0>ðõI-ëSÈŒí¦ Ðä< CžãñZÞ:_„nZ§ 6¨&žœ'ŸqŽÙ ‚sÓ¶@+¹ ¼¥µ&ÙŠ×s’-òs™L+qñ¢÷еPwxŒt$¹Ê?ÆÛ(/£6a¾a¶ÂbÚ ‘H<0±%¦Âª…Ÿ×d'ñ¸œÁWSÀÀeÊó#¸y ޱàY7xO,ŒKžf0}b±€@m5;.šÿ²A«h~yâ02"îôUÛrevªgcØVºj´í¹Æä8úèn„ÜèðqË+¹ÿ˜Üò]°–ÄÀB­8÷æm‚g<º í"&N±Vƒ¼RÂUñ}¹Za8132FGÎ8Go’×â=IŽ?áó eLý‰sž&§:Rðhñï“A+\™È(6ñ4n‘œ*Áˆy†Ùyªðö‡lüÿÖÝäÉVo˜a.Áúº½FÒɶñ‰6íÆÅ¤¤Ìfb>œŸµ°@p줬ƒèD‹ï4Q¯]Ð4ºˆz”.ꎢ«œBç~ÛÁMù©#Ò€{æ8*eá©°×µëzj“6@j|"°ð‚fM™/“nM8ï!h2ê_¬Á³%ø@_ ÏâY~LiÙ;·®¦^ÿg)xð‡\ñß®1”Â[¹™¨2Ñ=éÑä*o¤¼b«óT1áD¡­|×¹Žùa<Þh0ýœ`Õ–Åý\füss±ù3ˆ5Ž`éNªK&fTúÙüç´‘¦%¤˜Ér¼Êú èNÃg"ƒ^±äBf{`¸c°¯=žåJ¦JãB³Ñ±è“ÎkÙž„#0GCN³câ35 \AÃéÎ;–Ïxî" O%já>]uuòwüõ'ÊÁÍ\੆9v;ìH.kAžæ¥e&D" xÓXÅ_bè þ˜Õ+ïª}X,ÅU«®,~[=øW Y½–•” !v>Ë-»ù‡¢ù }I`Ñ‹Š¦šf—î3Ȥä>“Xª^®Ãªr!+øu¿î£×Ù(͘ EÚz&[#WJÛ–Kpd¤m²Éh­FøV›u‡@§;è\%ÇCµŠeåøXÆ'?Eùy›Ö7—rÓ–ËÀúhñþ üfù¢à?ïÚj^U6æ{VJ •«p[,5Þo#L”Ò“ðª±êö "#uÈÂ_íV;&ô°Þž€Â1æ^Ÿ†4Èßóiñ§'_Öã¡`u0ü³¿l þ='9.(:&Üñ™’[¸è”ìmÁ•çã™#‚ñTŒarªt¶2ByÏ}X¦$?”ÎH•á•°‹ã"ÙMP$VwR{kJø.ÛÀx‹\®£ÞC¤·[û“ž'1OkYج÷ÔžD¬˜BqP4/y¾2NVŬÚÈG©Ã‡8À~Iç¯Á˜Úîk«sÎç:MÚE2*jVN‰êÝ 1ƒú“M’.ó¥ÌA³0ÌÙª/A‚ÇQé,6îëÊ6M¹ "fØeÞ!A¨Óçù>´É|»XIAtØ 5â:¤‚) R/1ç­{\|¥raÁòëZ7žÜUÜ -™I)(%ÌNôÌwáš8…7·4ä ýâŽ-ÏíÕ±j  ±Z,±MD¹I¡Ûþ˜êtZ#s°/Ͱ—¡ÄÃr©ƒàuŽ›}ØÜel˜è)€9?U%OÌyÚÓ½Rטó„.Õ±J¨Ñ¶rÈïÚTŒØFTÕ¶¢5Fž £hÛž±-&E:ÛÏ›Ñÿ_t‰î,oK/ä}UÈ'<ݳaÍäÝvq‰Æî1`2zÊ+}Á®×<8s Ù†Ä žO|šmÐ)—2Š’}\ZoµyÈNc‡‘ŸYcÿYúÒí˜VØí>ûÌ8Ü`:Øv,ÀWôÙݘóÜK‡XAÀÜŒ®¨Ýªí#mé„;Â6L¾Y¡Ûª×Ú:Ý¢çbý88»OK·`ÚÖ3>!ÙöêpŒh·éÝB¢0>ÔrjÑàà X5¶ñ¸e­—Q݃QØ[| 6°›n="Ñ,·Õì¦?¤7½9?•E {ëÓV>Íú ¢õúøbÑ7‰©*Coo«¹˜ »£çj± C/ƒºnêV?ËÅÔµ×!Q¯9Y&}¼)ÞÜG25ƒlëô õŒ øœ•®eM/jÄõ•f) §”>¿1D¼‹—:T(0YÕúAN”ëu`¾Ò‡¼È|?¤ùÞ7zט¨ºŒY~—1õJ'4·èëÖ";Ò"ÉuZ!#M`³ÈÒ¦°–ø‹Ä&édÇ GŸKûÔ’=*…÷\sŠ„>P›ïgÁç)—Ůіõ –1‘²¦0'à°v|ÒRX{¯Vžøä=½Š´ŒÙIY ŒñêeÇKK© H¾žk~Ϫ¾5Rï hMÇ›n2öðÍJPº›5‰‹z}`*v,#Ò.7Üá/ÚÊ{Ùk+hoÓÖ­HXgÇrâÛ¤wMÓhN=%Nômt,w¥Zö2˜¼Š«ÛFé0½«—¡G6€7dî"oåîà­Ï—Ò¸ú‡2‡Eô6v±cºä”‹½.=ߥ›@ä?Ysgþ(r‹€Ç™t §­î·›@Š¢–N Äñ¾P)jaÔ'ïyŽÑQOùx æJK•Y½iúxP][F¸ßdú€3éj¢¿Œ³8EÚ­ì5¨÷Êñ¬(«ƒ ž°„ë¸Á¬„&°<éyÌŸëÁãîËN…M`ª. öX)-„`ÌFyåcòBh>¤…¾'ånˆ«ç¼™¥‰ˆ[Ç["•0J] ¾ŽR^‘ÆÝt›¹D¶×`aìéÁïšÁƒ……~‚C ,L§üøÚ,áb³O\º0Ÿ›·çŒKÈ-çÌÞF7 Íö€€Âäv·­ æ'îŸB?i?¶A}òf:>͢꿯™N,âF· fr]u|Ãh³Ú£O é§ÎµK?‡0ÆjqPb#ØBycæÆÆãäsN†\%ÌçzIRœ¹³}_$¯SøçœÂæ›Q)»ÞËs™¤³¬%Àà¥{ {½?ÎOÊ-«(˜ÅÉs43FYIQ¿]Áœõ ¬˜ÇO®d7@%C& ¤¤GlçbT/#-„ׯ¥¦r5œNã u¢„‚I9ðþP°SjLŸ~ÑE£–ª‚;¾¥gã£m“%>uç:‰qŒv5uÄõ$ ª@ Á·ÈïÙ6 ¥W~ð!aëƒ-y¤íñ`'¼O”Ü #`²Ç1lµäCÁØ6L¶>ó)Îl0ÂêéìˆƲ{$å3ú=žžà0¿ž#i·g½Ú ÍÈ«{–ÄÜz2´`[Á6Y;±´‘?ù±ëL†LÓÅã‹uDZä]¥äüeñ¢û–tœv¡æ[ÅÙíýJpâT]чc© iŒÔ6°Ö\ðÙ›½ßå+¤×’ˆGN~ävu(Ê-{™y'û'œ¿kÛÕô Ieèi±¯CXÈ{e`”=þziHKÕÔ,h.X©Âû†ÙJ%…õ y—TœË\Áta‰:´.ðMö­¥,J°ÁBÞl”tNçaÀ‚"ÖæêÒÈý6Ù°‡²Úc*Çþ3ÚäÂöÛÞ9ãµî‘íÉLÐÖ,5.ç Apžçâ¼¥“XW1Í•à8é ^/í4Lv¾ª ¯\Kµ)â0NÕ“È{d“êœÆPn-09$¢ÉÅôÝ4;ÒLžˆÌD¶‚A¯9E‡ÉˆŽ×yWüË-]©©üEHT;J‹Õ¤\¤—?“~9yÑf£¶0ã‘Ùü*SqIyŸìÖmµ_k6OÖ醞°°îJTÉ–©÷ÏŠÅëU@‹mæç©üÐq7X£m;n‹r*ñûp™ÏM?މY ž\U1Jj5°µ½Œ=Ðd&̪×wgOƒÍÕC%>U3‰,É ÌÇïÙí¥³ëüù Ó¼ï€vªúü¡æ†"Ê«ÌÜTežH(|cǶœH©¤G¹®b)»QŠ‹¯/-r…¬Ð\þ–P%‰Ùì!7láLA<éùytb 3EÀÂ"Ö…Iê1?Éšƒƒº7üÁn…>¾+ Z¸>0Ê4/mæMgýì4™#pZe[™J2™W…Å/bÅá#è¶7÷ôoUÓE£Ãü‚k 8süBœN'GŽ#‰ðäµíÕékq³ÏÙÆŽí^Os 2âP7I9çÇOµ¾L¬³ZžNqÔª“ÛVÚ7¾Š¡ø:E§|ßä^í«Ûx–âu%Ka«1ªY 'Ýé-êxb: ¶?˜èa«¯©BÅÓÃ¥©Î¶ï–%Ô왊)¼×vò^üdU±%J÷Ì8!¯7%eÑ9¿"‰¾*øÄÀÑa1±«®Ñ¾s€?ˆì)¹Yûò;˜£=Ÿ¼×B1fšWû!çܾH—î¸T[.}f^ å§.«Â†§“æ×’¦ÑòÉÎqiÃc¬^Ÿ¶ÉÛ,¤+ñÁi´YÒ DÀUglRãD‚’¤©À»¼ŸÝ«íe–žîIšºÑ%{å$é-¡ñl_u¶|Ã2­‚3c›l ߯×s|‘MÑŠª&›"f©ž6ë¥xIG”“ðT6| x )ù$(X‡ï×Âe1ïkB_ôiò¾è”Kk¾Ûe¼¬[ :Iäí'™²ôgyÓ)—pÞ·yÊ×ùÚÛ6œ×©QÆ„_W{›É€ä⩇Îf½¶#x-êW¤Ï ˜ïíšúb«5}ŽSN¤úKû®^“¦7Çåæxõ¡ìa¯Ç–Ë5†îß•r¥1õŒ™šñÚo*…Ó‹­Ïá¼)f'ò|›­q”Vö×zÄÁmÈR§µ‚숃¤’±ùˆ r<•×M7ÛèˆohŸ”;9ć:f>1ÝÉóá°ÐYÍ µÌFL¾°íøÇǨ[À⵬­kLR5as6{®M‹fÂæñ(›ímŽJ¨íwÄ®€© |Ke §³üf®ð¤i]è¿À,O¬”ÿå†e‹üñˆE¤Ãed¯óÓ®òð}ÌÌ„"É1ñL IHŸ‡(a.²í-|ªŽE°ãôvâº7Á‰8rÀN¯‰ó´8P#‚ÚSÈ7£î2_s–QÔ仲M_îÙ[ù³kØðö«Ø‹grt,¾¶&6 œœÙï!(NMla^*Pã‘7'…ûÑ¢ ÷'È©Þé35ý×SË¥þY6ñ¹ -&7âá¿çåHÏÔ¢±ÂRÁõ½üw’¢âóÅsŸo’ŒBè™­ÝÈ‹•]~­Ç¶å¢¤SŽQ}ïu…ÛØr1ö#>ÉZ€ª)O¿JŸ&ûŽ/ŠûÀCØü¡¦¾«IÏ<.Ö6)Ì%p>¢$;OõËò›ººFµÄ#k›R¨Ø'Šït^¸pI*ih¬z¯Ê÷åz¢f‹Ôo±ÛïÔO¦õße,rÀÏ?\æN‘5Êå/Ò&t„ëÃÿ ã.IkC6ÆTu4I¡´E³a?½úȺÊÛ'RÔ3º—dýˆ¢ÍºÀ°—Ÿ…EY<ó3ËÕ«XMŒ…št6HhR'Žúš Ô»X–?ø˜Ìf(Ððüâ€b£öx®­Ï@IRð!;€wsTˆvÓÄ…AoK›O_4ÎL®–‘“®I~pqÅß-õ-ê7ìíV=üèÖaÕh{{‡UÙ<¬ã„ÝÃç3¶D?Þùœ¸ð£ë²ÅcäK^I“]ò†¿-|·”’‰)ÀjákîZ3 ¥o½ÙžS$=ùûuc\z¯Š -¤ýÔsë_ù:Wo ¦3FÞÒЊï…‘ë¡:)žÆ´A'¥¥¬psÿ·\ecHdÒD^Þuèêê ä*ÕPzœ;ªäÿp·õ €ÈáØ dÇ“ª^`*ÞkØÀ±Òß*à7«€£[”ßÓ‘IÛÛ?­ß_¢hI¬%Ñ4*I ºd îG•®ÈÄW¤èTI•Üw°šR”Y®´ÜYoãM®¹!õÕÛÙÞÁ[~¶j˜µ, ¡Õùj>Ôü@ÿÛ®p‰õN \bVRŠÖá†N4z†¦øÜÍEK{-Yò3&m“pVÙUÞÕXúví‘­ß^æÚ²kÚY†´—sYõÝ_‰¨@2cû¶4Î?]ru¸k=ЍÌè8³lò I-\A¨VÜþ¬Ÿ²ŽÜHêaÓ.Øz7kû ˦PhGà0?¼«´Þ¾ýòìÿw´‹—endstream endobj 893 0 obj 8107 endobj 897 0 obj <> stream xœå][o]Çu.úÈ_qÉÂÜšûÅHÄ©«hŠ8Qч¤((‘”UI”DQq˜ ¿¢ýÁ]k®kfÏœ³i©( ÃÖÖ>{nkÖå[—ر…ïþ“þ|ñöäÉo…a»—OØîWðïË“'<|²K¼x»ûæ~fÕÎ/Þ£vÏ®Ob|gÍ¢¤w;ËÙÂà—·'¿?gçzqžiu*ãó^ž.gçbñJyóïÏþ :Ô¦é-N§>½Y¼îú|u¦'5tŸ ÙéÇð¤Ç¿}vòýɇŒ³>‡_vœ ³˜Ð^˜Ãå~óôäÉÓ_ïîn?]<ù·?yòþç›ßüþxú»¿9ùöéîû)æsæ\§¡Ê”Ÿçé^”)¿(ï^—§å×7]‹ö×èrq.b´!ܘE›f"?ÃMàʪC„çV-²m{_&r5¦;2Ðx"Î/ª¥Èž±Å*¡ÅÁ‰x±Õ´½)y—'²—‚‰EЦ‹ŸG:8#óÄ9myŽlË?‡­tÈÓÏ.¡Ñ¿œ³Åxo¤†‘ 7ßž‹èÈÓ·øä…6víœ/ÆhŽ[É g­†-®\ÅG }}ÉàrÒÏ”Hg/ê·¯ëÏä¢5HŒ´ª¿ÿ9›G?Ÿ i©Íé]mÿߪÅêÔ¿aƦþ%³¥YÆwB¬û7Ò‘æ ù’›…Ÿ>ƒ‡ExãÔăØPú9½ªcæ·ÒÓá_ÖÈ[Òì&-@>À·Ê,ÖûÓ§q9¬5>jÏÜéïàО[ºGd—?Õßœ!' Å‘ÕXd˜‹J‚»ž ¼ÞjÝÔžP;Ó3)a|ñ’3U6C„… ­¿Û:m2Á¥W2¿«ÑnÝ!»Áúô_‘·-cÎðÓß‚Ti ³BZmÁóTCW×8¹pèà¿ê ŸÔ^W’fõq¬,„%¤»Y}Ü((qK•¿~¾bœÑmÆÔØ' ÙËMºýÉ<¦š]! !ý®%;#Bx^¾ÅuœK+Ñ6œsÄxœý^­€—™Qm/ŸámÞütµ ¨—ˆ²"äÓµ®‘A±i½xë°¤ñ°9Z !ÓPi_Z,TÖaVèa¡y…¨ÇÀcÄb’ ¿À€ÛÎDáÓ‹òë]g7ðé¶üz¿Í¦* BØLd»Mrê¶í#lªeØ íl»M.l›kR¹“hÑi?oÉÐ[TX„{ß™Ôd”uÙrø¢¹{3@X÷}}\)Ö,ùƒ¬ûM’æ^ ö™o”‚(ÌJx3Tü 3¤B/øíåp9u0¢{ˆM¿Ù¢åïq±Xú!QGgð£’Bþñ ¬¬‘-º U“<Ö[E úÎbf%˜uRÀ¥¹¯«a_×uØóúH¦Mš]Ó·Á¢ IÌÂØà‘iíl³Éäé¼E@áW=5ûŽØ"²Û3„ZOk,BZŠ…EùØ#W¸'¨_ÝVî"ˆï†R[Ý—õ|]˜þ .áñ9,-ª'E“\ön xŸ”_¯®ÎëòkUäøCyüòóey÷j Óëd–î©ý5úg6:¯dêÅÚ¡:ãÄ0&vÚñâ[¼¬ÆîjHû"[î ¨¤Ë¤1˜›lÿ×åíÆ­Öˆ ¼Û½+ÜlØ6Zƒ 8Çÿ¿'(ýñ ¼)­¦þ EDð©YtÛy  §ŒÞâ¤ÄÓ‹^§ðN$f¨žd·¿WÑÕ¾ŸJ‰¯7=XÍ1 !fõ+\’P³ù~èʾ¨öÕpI=Äø†ìÍ}¶Õþ|Übpâ¼ÙeXdjiñYí0bBÀÑÄ3o"!Е)çͤœ4l‘@ ²æ›L½w›ôÎVªéP’â€e¶o ¡GcÜVŽ „-rÂ'nü}’9´—t`£ c§@t‘ÿ‚vq F˜kÜÉEhäakÍÉ‘8CÓ„ÅZ¦BȆÜáLZȉ#![ $ïý|&\{²\ÄÈE 0F.D„¨5¤HtH¢£ ¶C(Ó œÂ¦Dµ?¯AÚ™ÕÝ GgKùE±‰¿½¼M«^j·8‘ô]ˆ²ÓÔeaLéUVƒÎö›³¢äËê}?ã º‚y¥­ëò€à~LðGú Zƒz¸(ÁŸ÷ôSS+?¬ýˆY†HX‹°FÁ)~Þ è9À€tA?¦\=𹄉 fÙ¥«VO:! Òö¸–W¢m×Ì#>£mŽk °º¥ëÌÍRE 4íà3E ƒáq‹ÿÞš, É´ ïȰ–”àt‚ú$>Qz+SXV0Ue½<Ö»0w±…»î%MJ‡†“ GbÀêK÷‰ÙÃýé?½ûKìt™&ʈ¨µi*õ~1Ôk—‘Bœi¢@¯qI0„=R—KöCÏfõ<@T£µ¥â‹æ/BPË(ôE1¥=T»BµLqEV?ºSCÐÍ^ûgˆùë§2à«r°…¿ t=ÅÂD°@1ÎV€^¯æSk2Ê­2_ ½æµ5Þ#ÀF„“B’—ï"× ®:d6ވɕïÄ-*x‡HÖ*ˆ»@ ÃEoÄ{@^-èLÝ96‚[Wµ€&¡œ`ܺïx\ôNç€rÅV¿ þïŨ IýâԌ㰭pÔ$)å¹€~åØjs¾qÞ‚ˆaÃãR« ¼`¹†§7:§ AÑ!‚Tkf#IõXV`"g&q–ûü§[€2É@Õz>Qv3½0ŠÖW¡Û«V‡æÇ¯RèÛçgÜŠ±ž*ˆ;œ"mê÷8fie‡œ,T€F™‘YWd=úp¬°¬±'nŽmŒ71ÓU·¯ToŠ€µ>\‚é¡Såi§Uæ‡A"þÇÀt1©¦›GÁtéK0ñ1¥ZR1ù…Jµè”/ȵcUHþv#L¿Ý¿c©ȱ¥Z´í£KµhgÇ–jѶ,Õ¢]<¨TkS^™ñE0ZE”ØÅÈØŽC`͹w‹º ØÒ€,ð²c–ZV&:eAyZfPŸ~W‚´çå]]ÉÞ˜_WUÃ//¯£ŽŒQ´“–dÝnŠ¥õHýzµH»äÞb^ç`#¨oì´T ç¾-5ê¼”m~6º‚žÖAÕ`~"Ð>@*<äLN´ö²TÊ&š<žy,•h.±›É˜:Æ"“y7¡óQB­U›6š‡nÃ.™þ-Î×4¾q, qÈã»:›m ƒ­Œ¶>m~[‚ÕáðˆLmkþaFŒ ;οÜS“.VúLôIÃÙy¤±ƒÝÑÄ[àICûÊcÉÃjì8Ï9fpì ¿ärÊÔ¾Ûv\L™À:»‘»Ú³Ö GåâÖ|OD·L¿¾lê/ûE§Eżšq~òN2Œ¦Tn´×Y]D }ÚY85ÆÊí̇'úŒó¾Ñ­!/Ñhé»F,•rÁù¦”jŽñóý0±ð)í¯l6(Œ›úÁ!ˆßhŽ4®žY–íÛ‹æÇnHêŒy·9åºÑsÜ·ë7ÉXHmóGDåÒ.+·Þ®@¸} 3j@½( ¼†–?\VÚkŠÐ†raBßþ³s‚ðto˜¶NþeÂ9%Á1hL‡Ú½CYlÓv€xÉ»óòôçA…Ó-i{nu+RtŸF°K&:¹ÖÏ£¼úcÍ`Ÿ)àYÖo:r•D·µ„”åU[ 5Ãî>T¶PbÄ_cô¥áK…b¨ß©¾_LôY×Μ¨\TvðHJÚ?Á‚ãàˆ¬`ÈoJ1?Çüç8*7ŒÝï-rïòëä1g%Ùì¨ÈmŒ­|I 굪=ªÎB6Xm¤MIè:[ä×iL®Æpe]Z4>”ä;æXJµØd¬ÕùœòNÇVµÓïse²šå’D ÁÇR8OMýŠ´=h~Ïþ(J²U¡@0ÍåfÃ(`4ÏqI³E:p ÿ4”ë7+a.ÔÑ´&N›á0:’ƒ¯ª&ò{YOø~¨†Á\V ÕäÓa±ŒŨEàMÇ“¾#»OX”<þ{pÆAåf¿Jó¼ž! öÞ7I ¸‹“[çÏ'iÚ*øÁ\Útº.g‘EIwîÏ>&Ýâ ØhÇç Î= ÄÎÎEÅ ˆ«ÇZðð¦{Úâ¤üüaˆ#ËUf<‹‚ü`äö‹,C«€kÈ2EgÑWp•ôÍX×……Æè‹ÁúÏ"ñ³qí)–`.`×ÕîÞ+³M›S#<¼NÐÔõ0´¢Z‚&÷#FД þé1 ø+(½#–b=Ê.å]Ç]ÖÖy÷‡Ä¬­ëÝ‚¨…ÚJ²q é„,XéVTiqtÛP6õ Æ’HóÜÇøâÔÝêp.jŒ4>{ÇM‡]£a¹a©AÙACßN –a§¼vÏ· ”˜F ’ÇçöÇpø‡À³+* ܽôѬU4ëh°âÎõ3[ fz&ËD>;“!E=0uÑiËöÚ‰zR«Yà¯5¶ñm×K[X5òå ‡Ú›QüõkX'Vbëuiç!…[B—æUïƒÎ6§Tê!`§³޲ŠH{›Õ¼¿<Œw©Œ5Õ@›dl8[ÕŠá€K÷•©à¡Ré3émëÄ\ «A(ÜŠxf…ç=†Hé9)ü¢š`-)~ HÃùïÝÌþ|NãªT¶€´pÈÊ©c……†<€’nT'àä’¿G©â\L¬ÇD»Ç÷û°E¥…>Êð”Ò¡«—Æ Ûµ½œ(‡Î—ú¬.eiõ”HøêDe¼Â‚:C]}Ìà¨@„Ï ý[ ñGÕÉO¬mìBõ-ü\\•A÷e+$Z¼¤ƒ‹ Ç„à\8r?šþ^r?“*Ù¤ÕÂsMwꕪ°ÞƒäùÎ$ o¾'ªÆ}Þ^>öQ±Õz %é¸ôL=ï~þ5Ê©®xÎ!n$†ج°Ñ %»ceµ¾s*— ¥ È"…ˆ‡o–>Ío˰¬—Åúu½z]’ŠýÔÍÅ]ƒ<*O>+TÝ­G€ …YEñ}Ì.Å3î±JdœNö ’+³%¸m):MÀý,aV;¹`exܰjq-~“¬S³"ÜÌ¢)‚6´ñlj€îþ‚P2e?ŸZ‹;ãÛ¼'Uò’ƒ7ª9™¡P%Û×õ%//y]–//¿JÒÎýØGö)ÊKSý„é ¦°¿›"$±È̿ზ'q*äX ”ŠšŒRèªH^(Aðö¼w籄·õÞ ºDÙ°:®Qâ‰Á4¢ˆ‡\$2 M‰A0ÌÃ;ÞJºÿ¡g‡(sœ§ñƒTGª°Ÿ®¯G¢n…'þùäÙßý>KÖrUÜ›.ÏJGú^#=²˜}Ñ ¾.ÃêÑãœýœ?.  ¯ñ­Wå_“Ãj)B[U”¾¬]+öP’›3*£¬3³fÐÜ æþÌ'“ÂõŽÍDë9ÿzšê}§Z•3 «_Z¤^ïYd̬7‹ì¯ðÄe|è“çûïóɬÎ/k½I<óÄ«< ¯êئDzxaÑty\ð7¿#ú‰Ì7=ÆCu¡ªèýpµíàÁ’ß:îxú®ž äP~ægx ¸ˆƒñÀ[s¦'ü±B•ñødÏE:jÒÔÏaûÖFgûΊi vÆEE8”v‹P³ë(WõQ­‡1> @f0Í6rc±aoñ°2»ý–ô@ŽÛ_?è2xe°d=c€ ÔKFO:XE*ºàè*RÓY3+šsk+îî{Ã¥§bðÍ-ìÎb¯–6x¥€'à/;}bE-õuMÇ÷âû“ÿìwù¬endstream endobj 898 0 obj 5253 endobj 902 0 obj <> stream xœÕ]YGr6ü8¿b°€¡@S¬Ê»dC€å]¯d¬×’–Â>X~ ‡‡(’3/‰úúÁŽÈ323²»šsȆ M©º*+È8¾8ò§ÓyZNgü'þ½xyrï[aæÓ§oNæÓ?ÿOO~:Yü#§ñÏÅËÓ/îãcV®Ój„Q§÷Ÿœ„–Sk&%Wwj—yšá——'ÿ½“gçzrë¬Õnö—n]ån:;ÓªÔjþçþ@ƒÚT ΓӱÍÕL«nÚ¼ b;û¿×W±JêWÀ$á;0oQ½J …0§ÂP_†ƒÔ.,rékð9 }£2ËÁfK_Ê&$L™PþcúôEOÂ1 :-™Xh&zÌZ„”SÅÛ£”+Ñ!ç"Ÿ¢Ü‘ÀwWSxÙQOòF&ÍךC }^·!â“U<:j¢Ü/q⤚¬¤š a=éB(x™Ì]™˜zm?Ÿ Ø6b–0x¸ ÖI˜b:/×1a²±Fù ›Î/²¥ù"[ŸWùêçôëˆ×ãV¾mÿ÷VÍic¯†ñ*wôuFéü/ùêáaÀêx‘uÃÐÈ÷«a¼Ë}“‡ñø8»6´ŒBð / €0¼M§õ´¸Á>f –lزã>°6Ùhç*Ø|Jl2-¤Ò“iðœ0Ô¤>’o›UKM·dèEùüšÎ!96£5ÞIçIAÛ½60àƒÜnD¨Ôv²®² ˆÆN.¯©&ƒ|úš\þ޾¿Y>+±šZ‹ fÔÈ­µâú ƒâÝh†.æL‡†ëYKl…éÖUºøù€ N(¹âž‚†os eñt ¯R?_7ö޵QüÀŇCc°Â!˾“1Xƒ¬Žá]êgñ'>Ž·ö ØÚMS×ÑÝРMV"nòc¹ÙpÿŒÿÀØÐ¹„ ª1Þ%HÝTy³ cÜØJ½¿Š‚J®Ææi½ÈW,³{LeZÂk ¼Ž4ų²w”rì‰g²„yüÚ‰ÍÈÒ°zNÚ­¥™g?BÒžUþ3?˶BËÙ>zº€”,TQ»Ú‘!¾r÷ÝÆšr„±ýÚ¹W’®Š`×*¶ùVçꟽ5¢ìvF ß~ #®ƒÂhX-† #mw†"üÛ^ë½Ý°Ä2«ŽnÑvë †7GÁZ{xsØBØ êÄôqa ø]5Wm=9[`EïÝ`¸Š¥²»·¢Ðƒx/çÛš³ze 7OïÃ\è]Ò,AC‹­ÑiSÍMªoµÚiTèoXˆ•8”¸09À`Ó¨ÊÜP¾@HÆ×ÁÅ6‹Ê`¸dDá¦=øE]ŸùÙFä‘·ræ –·SI“®j,h®ÀÜþÁ‡¼+ø‡'#;«lTyù„Ú @-nðâ‰K˜l’P¦õAø­w…TÐôž›Úùа²Yk¿*|÷2JEh#FB~/ ìÐL‚lf²Ãûm—Üo1¢ F9%ïq,`Th<¾å5šÇÔÈ’÷úòW²®ŠÎUml ·RÊf&*@¤O[ Xð¾wÝ*r14aãÂ!´þïÿë¬; µýHwˆ¼– óÆš s®² ~¿W¾x¾„êýÚ¨à{„¸´ÁhðxÒ- qµxMŸ òQgXÅ#Æ»)î¤ËïW]~ÑÏm‰ðRïõŽj½C7!ÐÓÞ%Ÿú¤¥EYuÐ,že˜‘òîemcò­ótÑÒI¶@ý{çF ¸–Å<½j¨Î;„[X±ÜzŸ.—¶ò—ÍLùÇâÅÓq¿öΡ:¡“ðy˜@g$«òy×ìì£KtPúünÞ¤ŠÑ{ËuÂ3˜ U¢‚=oúQø ÕÔ‘B0·G¦þÚy€ì*"mZMƒÈùÂr K®+0 Ȫ:(!a ¬»©ÒÔÐÚ·Rðêßë‚¶1“'¥ÒÿRèênT$¥ “Ô<Ä…{»Ùޱ­4jnX6:СK¶N zuë)˜U56cì(é ÑÆ~I!¶•ðí47߯´˜ Áí‘t‘ÇDX%mi„9jq¸nY‰ãµ­Ú{\‘¨Ç~Hte‰#º$ˆ9 ×wD!ü6û¿ÿÀPCÁØnÔØhÒøÌXÈâÃPŽajòvéèH6~-zï3á)êØQõˆì`Þ©ÌÆIDÞŠÑÝØCÞÃK< ÍÖq3rÎ!“À0y7pº7<Â{W›¨±°É— q›7ôâf7´81Žç±=ü„cEO„5“”Õ.ÌÃ:Þi ƒ–‚‹`Ârw÷^›¼Ù°¼givÅxCô‘:Ë2·ÐåUùð£vŸ»(Ô©³šÈÖ°VÆê¤èà çÖ^£= —ƒ»>ÄMÌó_!­&3ËŽ"Ú‰å0W—ÞÀ„Þ6@ô’J™+rà9æ(z=ÑÚ. ^ÏJä~•:À¹Ùd’²,ª-O>@vO¥w„ˆv1†m"˜´×k¦ÀïyiøP«Ú ýÙ6”Ãþ‘ØÅÃ÷Ü´ZS…k6$#s:D“±SÇ&* = .ÔZøB3ƒÍ×kœ ß±O±Yé‡ËÇp2I\†NO=Iy>Hšñ”Ѓsê­ˆ˜Ø©Šì7ÞA°Ìjïê:Æ»Òk°:žeËý²ÇžI°I±/[hñ‹Ø™ðS7È¾Çø•è+ã*!%LæÙ¡þêÅ¢sàNú¢s[Ë·(­Ü©½ H?%Lnò8=é¹c“>DÅïËÅD>Ö~£‘’oöz8Ñ+Ö.è×ãØú¸P‚Žù¶>Buò±´)ä· YüVB¹UÉš{“Ñx£Ôµî Œw÷Æq4!=ŸF' ‘P—l¢SwŠšdâ~Óu#u§7_-o\WºX3}]ÏΑ›èìíI‚ö´-†~]}º)ohýÔAúaYøöÛžò7ÆúðÝÄŠÞ¬c}.´ÍÞ=¤oƬF]lÂä0kkÓù…«œd{jcµ=¯Ý>ÞMŒÊ®Dš²!5ZŠ1ht[2d>zk¾ÑB%»Ü±oåo/¼¨4Ž”9|(Ñ…Ð0Ù ,Dð´5ßœK£Dð¯å®ÎþS f!—z;øˆQ±'6Í&EfR0¤°­-B‹½‚È•ÌP«QyÍ75ƒ.hItËU»ïðæ'h±'Ü®ŠîÎñm7n迆cº3nì`•êÊ…˜'vOü[„‰nRÿÌûE^rv® ew)%}',[m~(ZÙêï"c]«læÇ•¥Îd6p—fÚˆÓÊ0ÖMv1w%ú›èW”zGÎ ›¥)Á¬„¥ñÖ¡8–lL·;£MÀ½i³Ia“{tᎣ͒ró¤eðÒ»VŒ7Oç5Šã!³ÕkÉ£W윥•pLÚ#“`à!ãÚÄL:ƒåv2Z­¨p˜}«ÉY±>bŽ×‹Å0B, w²å ÆÁ76<.° Xn.Åï2‡n•$ ƒ9‹D–£f‹áª‡­'b2ucˆoó9n è_Œï íÒQQIoÉ d¤¢Ô YˆRXkZNñ6màˆÈ˜ÃzrD–Ž*±ÀËóÊ'—°¥Âx¸šçÂ9f= ^kXkŒ»¢))çé=ÇŽY .ƒ[bG¡çÀIN.+Ô$$ÃL`þ89šM \hjVšßO ¯R­<bXöP[“ôþƒ…¬L­ }S3 ϽmÇDÚÿã &æ…uã¸C D>zèÑfÔ1Œ :¤_ðü¨*$Ø„>éÍ"‚Ëé÷ì˶,‘3Јáp92úßÏ@¯¶®"–¡dÉ+ì„P‹ èÕ!’O˸vІLj8F´î !V.¤4Õ”rHkw0À­áÕ¥GeÌS²–ªxB¡ BQï$â©û‡ü,¿uX²ž aÍ©cã½ÏÍ‚J1a‡¥t,§™Aô,¤½‚ˆïZ1ü9¼œ#¨>·”KoT‘Mé…Ùí\úu.o|¿‹×+FTté3OÓ­ÏÒŚѧ}ñTÌoHÿ }I»8Ý6ZÅŒ5ò¿}Vâ¼rûOú”¦p±¬²î¾ æÉ÷gg› yÊ<мıŒ9¸‰»”/,ÐU.¨³›B>ÞI¹G[nöqmðw8ÜÇìãX!ä`á¯Ï*‹hËþœd¾1=¸×>Þæs/ÿú$ÿzÕ^M}Ø$ÙÈ/ µ?W…)‰—­|xIÄ6•½˜~ûþû.2Þª(½}¬~5=¶‰|…ÕTî§î¯„ø®ÊzíMɨÁ¢T0ÊªŠ’‡Ð»'J••”D‰¨úHMã"n8³óxä:(ÜÈ¥z }X¡ŒN&aš£Us$káb™é½%«Ç¥Wš/¬Yn=½Òh,BGõ®'¼g:ì`²ÅuØ)4h‡Á”ór?lÙ(r›N5KËÅdܨWµK ½q#Ë|{²²ôEàî€4A¾3ÒTóz€4sPø¦ˆë°ÐwFšÊã,ûH3玣F²‰4t¿!Mb«ô€F©' h#ÙRÑ «–Ä÷½ ä9iÈ¡cªÈTme¹|‡¸w+H^êVk§O‘ … @wnRÇ}„#mfÕ¤1ªŠ•}¼OÊ4U£:@Ú‡ðöð Ò¼AØWLkrìÞnÖ—Âdc—99aG¿¶&¾?ã>dÑÒ¾Ü[¼0±ú*£µ¬3r„aˆ–.Ës|ˆ–G¤â†}™¶YÌ¥~”>èN*µÓ.•·hØÅN}Äüz0—J_rþN¤V¤7: [Ë¥rzRÕ—6§R @¡M^-¦DÁ\ßô[öPþSÄ>>ÿ)X>ºðWIÈM\•{&ÝÓ¹5nÉî·yU¡n –ùUXüócr«R”ÜçVù”KM1hÛ™˜¼$ãiò’ÿêÒ8ñS©ú›L1È|=áËV¨=IK7–³Ì]åB ]’ ž‚lr6 Ñá£H>b±žô«Ïu@o;<åDú© ¦éñZ;œxÓÉ{´+“ŽÄØGÔmðPAÒ²úÔ»ë1ݳ)$©|ôa{‹Ý±šº &VaYP®<=ï0n(ÇJ2ˆFmö™ï•ÞKó¥^Cò)n“=dŒ!¹…$*l<ífBÅ£¡˜,áÉÝ_ MøK)¤Àé•O Ïü’ßqª)LfŸµô[J¯=2…Š:©‘m«.Ë„›¯ågÛ0ÙEíº°e*T¤Ë”ÔÁÚ‹;ýQQ¿É>y‚òh¥¼wSg‰Œ )!ÅàpbÜ‚ÁO>Ö6…3óW½Wu¿?ÎǧÜD}áà¾ldsªúu¢1VU¹ÙÌ`¨Hë‡Å>›QÔà/Õús5'›YÉ›)F=ýÐî¾ sÉêa&¯“ |x@0¸!yè.†¤ýY[tHÍŒSàTõï#&V¬Äž¶¿ø¦4«»Kd†’}`ŠqÊËB"o{H  âeãqiÊÚðl*rNJ(¼¤%PKjï¼k9 ´…!â!£ÒÇø²Yhù¨£¹…»ØxÞ^]Ùïÿè=;)ÃéAJxacÙà¨gB¹B°ÑãÔ&©\»j޹ª³ÀFNÌ]Õvô­WÚ¨ír›X£: À² zA¤ž~j; ¢W,ÕCß݃ÔXM¹÷ž âÿ92ƒÎb×jf"!Ð Ps>¦ÊŒ¯:-$T¡a†ÒÁ‚ŽR·HˆA—¿½$Äh_f¤ABügM‹„øÏ®·†„µxxbŒ„éÁ¤¨^‡ýˆû½šÀ„dÓ‰p]>ž­Œ˜j7¨ñ©H’U c-—c  ID’ó+òpdz…º$¢Ú8efæÚ®ñ‘»lè/ñ¯¨‡µÇ&ìE~”jCЍàOH†j4:ŸmÞZ` g§©m³ïaJ[øsÇF&7#ô$-· ªîòJ_ =ö`0#[‹¦+;MèÈ·ŠÄ:u#ií6À<ÁQ)FfIÀ=€V3ŠyÈ>ÙÅÖä¬}“ˆæ ŠK»mKt‚ºë=‘«6~Ÿflææ´Å@F®-øäuÚœ½— ÓT+‚OmlÎ4ó1㣈çþL—øå­+PoªäïK3ñäû«Æø¯­q]˜ã%«³{tÆ5Çœ¦ŒÄ”œ˜`7|åoXÝ{ªXÊÁ×gKÞâS@ùø„}y}C‡òoÑJT•³dTç…$ç…BïFnÜ4±.^Y]ôEXÐIDªÃ ý2)W-3GªËæ—’Ú@qø3é ×¼M§­¹tå[X)ÓSó<©}úLXm;80¯Cõ ^ÛP¥üEÏGÚç¾ Å2v|·xFñ;æ$V @Xº¬ˆb¸Ö•šÊ*„ì.×€œˆÞèèýý0N„[œl´ýTŒüÿ*ÈU ®ÈÜÁX §Ná3l`-1¼Ó¹#øp^> stream xœÍ]Y$Çq6ü8¿¢ýÖ hŠ•w&leZ\¢Di =H‚±»3³$¸7gD. ý þ`Edå™ÙÇLi›ÕÕyÆñÅ9ï7ó$63þ/ýûÅë‹Oþ(í¼yùÝżù-üóòâý…ˆ¯lÒ¿^¼Þ|ú_sz¦`¥Õ›§7Ëbãì¤Uð'æi†o^_üe«v—fòa6zëãG‚ÚN»K9­ƒýÛÓÿmœ'oÒ˜ÁNÁtcÞîôä•!ŸÅOð³íóøI{~öôâË‹÷µ¬ú¾Ù!ídã8fš=n÷Ó'Ÿ<ùÝæöÃÝõÅ'Þˆ‹O>Çÿûô¿=ù¯Í¿\|ödóåðÆk¤©Ê’ïòò¶Ê’¿9´d%œ×ϳd¥'#›%_•%_—%¿*ÏÊâ·¯×J7ÔþöÝ.’šàhïÛÎrcƒÆ=Ç•<Ý]ªIíüöëJCßìfxÕ)¶ßÁ 6L^ëíÛú»úñ¶¾K~FÞ}ƒ#¸IjGß½«/|ØÁ{ÄWóCœ×¸É9ÓåÂ$½¦c‘•_ã p¥Î漃±ÔdŒ—2~íÝ$d¾½ÁõUÁÃeL5»2&|Ÿ#ýþÙîRLÖ*˜óù²(µ}QŸ-?@®ôÍ´Sa}š~f•§›ºn~W8ëí_·uˆ¹,ñ‡òi®ó†òð¯;‰˜0{”{ ¤¤‚Sü5y÷Ýê"ðœ—#wBzzSxÓVM³°ëwûŸ]×§dŠÛ5ãȆTɸ™lfEŸâϼ˜¼£ïâ=\拸ð5~ˆ÷qU•@Z’v}Kñã¾[¢4‡#T¦üwP(ÒMa¶é¸ñaýô'ü$‹p™tß6,I(NJìK9ý-+KP9ÍsØþ÷„upÆÒWa}R)àd™×‚TDèáO;1%€Ê~…¯ŠÉùx­RËÉè0æe òÚ)GÉûMzjÆ""»¦S+®+®vEv¶ŽÒ]¥ý»ú\áUš^\™SÍ“QŽ®éC=€Ä¾Ö`Bf_²Už;¯ê<[]œy³³“PÞÚíÇú«º™ÑQeRÇ+”d5e±•àŒÜ–¶¥…£O÷ Îecr\!'àÆ?íh´êXŸŠ!“Þìï¶êH¥|0ñ^b¬Ôg|iOJ=®éîc é’/…\®ùm• ™vWÜ£Í|~‘{4€%†y¨DC™Ìc< Ÿþ4ˆ9לl/Dæ¡x¡´&N|šgPð=á¾Js„“y¢¯\¹VDC«EšÅC°–{“ÎÓDþB–9,ÒTV?&Šˆd <(b‘ b’Y2phBÖùë׈&"ßšLÈIkçE]vHdÌZÝÀÜWÖJ À‘Û/È5¿Å“³¥ýa‡ØÑƒ|Y÷@¤+Q…×U ¼¡|y)ÁÖв® Hïöš•Md€-J‰ì<©p;›l¼É$$ßZƒ€@IÄðT„°\1ÃC Akf8ÿÅ0xS Á·k3#&øéÙ^æÇòíõ!‹LË€V ¬Áx~\‹ èE¶Ûýš±ªž•gœ½Vã»Ó¬/`Jo} ÀÂHó÷·¾„í Ì‰ÖWœ·ÉÛÉ89Pu$Â]DBñ¦Ãõ…g¬#ïVl‹±rÒvhCK0bû9‘鼬éÇ?ÀËÞ ¾yùš]+»p:'«&ÿ†Õ4¯êÓ:RÕ¨lþÝŒzÑýs£Ö“|`=Ø`: šÆ|ÁÎYmâ+®ø2 ×ß[O˜,åÛn(7ëÅÔβ0S“tÙ~•ˆã*M÷/F…=ð,®›‹\['ï½Hf©nW–ÇU^¯Õ~ÏãÒÛz CL—>&ø/¹ ·wUž˜SÙ‹ðÔJíAOu€|!p ŽK ÖØ¹"gtDúÅ̱ÈÊ$3ôL4sXu¬ˆPÂÓk:·ˆˆòªõš|Ó ÔÆ4ÌLžfvÂ%]™èUTâG2Ãe·29ùUcb1–!Y@ß,’AjÀïY2ì…_µ×ˆÉü«;­ÊD¼/¼š¬hF"?'ƒ¦£òpŸˆ ‰+&[‹á›g(ˆJÑûÊDgÍÈa—'»YIäÀWÈø"šæäÂk{g€RQÒ¾¶Ö[,QÆ?²¯“Y‘þ,qX:»¡¦:U%ùé‡Ñ ±d}b•¸PLë?â9½±ÄÀl<Ra}<øÂÇÀCc”ŒRÞÖˆIwŽË {DQ²E?'¢ˆªVÁKåã‘Ý[ÁGG‚RD: ú ×0«¡ë*Ñç‡ t¸UŒ%ü¢ÖP]ý n÷EYrÝîÛòìÛnk͆ND葆=!>*϶ÞÉSã#@,³ '"ô8¯UýX pp÷Àè €áIt§ý@RÚÙã@º’ð`G;¿ºö¥…7Ì}!:,hEøž‚‰»E‹“TqUä,0™®ÛŠ¡ƒ4®Ô{2ÒÉ*”k`þ‚H¸ÞуH Qbc8¾ž<%+ËDßGÊÝxµÇ8 ”åº Ü>–eÍ]š– ªW²+ÅŸ5¬$,RûB~ó(KðY†²@vΪ_ÊÆèÊv‘‹s!Ø`@$ŸÀFVž9üv‰ˆ¹ßY ‘Ìò8 ›äG=ÿ+1–9¶RïtÛKö‘´ÁGkàŠåï6 …Ÿt^,±3ÍIy¯mÔèj—¥<Z²Ëµ×e×ÐëÊÎ ÄB³‹åôíàð>vûB-’~^1^F§®±Ê‰!$H$ ‰Ÿ¶AtÆžâAØS͸é_{‚-ƒÀðçÀžd»5Åè¶,ùæ4L‰T}<¤Œ1ÃAÊl’)ã¼²O¹Écý¿€”K0“>ÌÁ7+Ñ҈èà5´kVÀÉölŒ>çd3«ïº´ˆtáß'@)§¢mF±sâX„Êäsóâ‚èý ‹ ½¬ xºóx  ª˜ì¢b1SAêA@Î+ö…ä!@³†wÆTŸo›ƒñ2-í.'ã1!S‚žx±y.$R¸uÞF ÁôÎÙä6ÛŸêÓ;V(Ü޼,Ÿˆè·õã«Õ¢‘ɵEqÚçIÿT@ äéK©-ˆªÊ ’ƒ¸ëÍâ Èf[à•¤Ë×ò|Eçd- 2]œ¼ðß:K‚ã¤[òtÏk'³zá6‚ÛÉï×$UFhçU"YߘD­Ó.:+°Éˆ)ÇÛF»-jH<š·dTí 2›3 œ’¹!è¥ò¹†ß.›ð³øŒo{u^!çB EtøŠê*·=gñD6Wœ¾/]-6>}YÈ*3ŽÎé=†}Ó3<Ðb-afÖ˜ºT´Dam‚3 ¨4& ·1åH6Ï¡t¿ë˜åÊ»@²fVéx9U'gøTñ÷‘½ú.+&æ5»m‘K^ µ £ð@§zMý«_ÙD`BUV[y`}ôÁŒùãC»}Î@¿fj~8²FA;¡=½d©Q K>cz‰±’34„±“²Í¤ÿ.´Ó‡YØ¢¿}ÇxÛ¿cL¸jÕg'Û¹´J¨ôµsÉt¬¿u.íÚ¡·¡=Õ¯Î3$+ÌEÝ•Ÿ•1€N팉0Gz6—ád~¤Ó‡½g©fÌ‹£ÇñŸËQz«XkÐ ð Jgôà¹FÚ?ÊÐÃØ§V1ô¢_°1ôˆ8ýStAOY*xK6oójI4ÕÉÛH({NÄ}޹*ÕºY¦C/¹ã´]Žc¬ý°TËìKßËC­E0ÊëPÚP ÔYè¶ ¼¬.q×J’EuVJÚ5ïl”É*3ÃÀ¼Cù‡ºf>©¿= †![áp E›Í4…›ä…„Ë:Ι+šðÃFöfvËñ±ð÷«PF—…IíœÏy´±äâÕ8¶Jììª0˜ªFf´‚A(iØüü}wq=—Õ£W0^O.´¢k,^Ô§­xi¸ —.]‰æ~‹@i‹uÔ‡ÄIþšû'çÕ|ˆåpÔ öÖ‰%ܲü«‡Ç#× ú@’ÈyîA‹OÔIæõ;ºÐx ‹³³ðÂD ˜À ò -€Ÿ…ÈãGÛ˜½¿C4³ê‡t’ÍŠ¬,Ó§0ó'ÿSÞæ(Ý‹ÿY—þ {WTØ0¾œYŸ8Ár¢R±î¤ä´Á›ãj+nvv½ˆ…lÒSP 3cD€žä]û7¨å‚t2av²üî$<(¬Y$×›XzÒKd»‘×9@Ùëƒ:Sí1èÒ ˆ#äcZ˜ZÙkñhq§Ó´nMÄ­œY*ø`fÍ^W˜¹"½¸pb]Sô–‚¥ÅÿÝAŸ„s( `D÷èMàP¼nÿšñ:ÔÅÍ8®F> 9ðI€Ô0²™ô¦}>ïFŽtó¹8¼ *}M’t Ì[ÆðÖ6³;°xçbVýÇii$;!ÆñçšF}Ž ÿÖNØM7áËvä^¬«¥ëÇÜ8:ûµKFÔxþžj›-OËÚæDk°áÍ#"¹¯|Ê—JaøýȺ¥Ý¤,)´&[\‡D–@oDÈ·-gT2cáY7‹¬° ð¦J–”(ØØÍ|¸ˆ­ziÕ±2sL®kµKlæàd+a#Ãaîº\¨‰WäAù '_ÄIH—’ÆÞ€š„jZ]²Œòó’v.÷u,8 ƒª¶Ñ ñ=aR¾¥ïy+©©û´Ö„)Gýq¬&fk`+¡‘Â_åÔ®h„ ¦I7ý-á‰ÏžÀt5Õ†ßÞ4ô³4m¦É,þ{2Xm–@ø+eÄÅ™–Í`'9±Ç‹†f$º¬€Ef7!'áèBβ5˜¹Æ¯„kCÊj–1R¸Âöq¾4®ÞX]TKêÉ­ítžèà™ó¡Ÿ7WÍ$È® §KJ›7S^d®ÙéëamAò1Ä)ÂŽOWǤ9^Z—®›ÞK…樵ØJ¼¶ñ@ã]+µ”ø«0j‡ò¦ewDÿ5U½åñW#!Ìzʲª Ý ŸMÄQä<;7ÚÚw4F3Ýqr¨óÜGš=ÏÀ¬Â$›Çj’ɳ_h_{‹ X"•~Òõïaêƒ=ºtªäå‹C\t9ŽÔ÷hº’$#ÞZ¬š7û„¤‹¹f9½E‹ùÝðdLËÎwh}—¡gxW~0G,¢Yoö €å>£Eë‚[åDz‘ÿ¶ÉÆZ dSM™ƒñLíÆ6J9\E€Ýk©mÿ·|Û›Gío{ó¨†q—Hé¥Õ ¼ø¿%.‰h5¿÷UyïiúRÄ̼ ü}yí‹ü¨|ø¬|W^š"¬fû&²‰V‡3Ü;ÑXd3J€ ð>&“Ä“ÑxÖ Ã´¯&ˆ˜Q¾Å_†Én0"¸tÿ¶Ë¦›ƒ‘œ…‰SÀ‚Þ\6o/ 0}€)=ikBÄ+€¶±´ü3ü(lpžÉpÇ.æ?&Cp ÆìAõ‰íäŽ>÷#³sgÉð}4/œøF¬t%ç·¢.R²Ža´¿Níwé!ç &ù2Κ¿Bü:l©Èë%ÓÅÚ'Ø4Þ F|½+Y¼ÃZÌ¿qMÏ¡{‹êťɲ†•Hq.³ŠîÄž/–¤ï™:¥–ø¥2-S4À Hy÷ À!Sïœ'¡å@çQ©«4%¾4ý_óSRðò mÉêqÂÏÔy”.ù`çуeØ—î„JSéHP¿}@¶HŒiŽO‰ååq }ÅŶœá_É"ÓPî+byó6ÓЪF=?=A‚¬j³ú%0´Bo@'C–O>#aü‘ן%£7Þbaûƒœº,4«¾M°…Z ôÂäXjmÌ›sR,SþÄ$lV§W^Û{Š|¿:òwÜ«…¸Ø¼B&% Û4Ûõys=˜¨ FVHœF]V[Òê‡ô ²(§~všN&eÿ¥ß37ªÞ=-‡1„àýQˆ y»,†èÒÜÓV!ëþUÊ_t*úZ DéÚ“G¸ÝUEê[F)d4ÝIP#ï½ä}úqn¶Æv!˾^öÙö=2S'+%-~<¸Â-Š÷‰/áHÕsX[²ŽDlݯs*‹9KÖ3¦';±¯w‚lèçe÷‰ÙXîÄ}ÈE@2tj¤?Op™ç}ƒ>Ú„–ÖyƒÜ\ªØåÙ—|–Ã~;éçÙí·#oŸÓoâùÔ¢ýê6³ #I4\Ýs'´*és÷uÝÅÎ<ÒåºËcý*'„3]ȹÆS˜ëaFOO€]H?¶'ò¼Vj!çÒlÊR—ÛMÄT½ç¯l¤»ãæí³T¤79².‹m¬Ûc‘.E$…§ålÇ᣸SZ1…üYð{ºI°ZÛ¹UI/ù¾2÷'fs\$:ûÁQM¤ŠÇ»±3•µô…#O6+ñåheÓ–ôø5nÎE}ñbeýÔtÞ8pß±‡ŠÐ=~¼Äâ$C¶úñ$Sìö® á·ß—g7] ¨iK·×(PªÛf!ëÐq.ÌÂÚV/Zš€ŽUG¬µRÙqg%‹ñ šõÞ¨i¯ Á©sÅQž( :ØÃ]..?xÅÜ{ôÕ”}ú÷ÐMC…‰áïó¤‰ï÷é ¬˜\¹ôÍC\údȇxôa˜3iúƒ}²b.éµ ‚/~Ãñ2é´G…°’ñ×ñA€³•Œž'»÷Ú#ƒX8‡³f5yá¹ @ìšò°·»òw‚N `ý©ßÓm¿w¦T*T£$Ïα±Šz®Û†Ç¦Þâ8yþäÐQòzÆþô{œqWŽ–¢QÓ¾ßXÊœs¢Ÿvçh+”ZCó5®—~Œ+"±$ïA¼ºâ#Ìggåª÷•íV™Ë}ágé©ýŒeæ«ÅÉ€¦¡=_èã Xý$ÝÀñÀ–ˆæ‘æ¡ãI£~虈MK˜ÈSæŠT-ÍÚ1¬|èÔ¥t )ÊÉ}Î2¸] jµ'à‘ú992æö¦m<Nq6|¤¼Þ³>Rg–½?kûç¬Zdv€î@bnlçÒE}¥z$œZTv¹tëv@§<„ cpÕT¹å†‹H8NÆ&O†*~¶#ß: ‚U£\[¥€ˆáý(ëžóa,vmïëõˆ_qý'n÷žØã2Ï»á[èŒ{ì¤-œ9æ‘Nî¤Æ^Jz<€MÒ<âÁá#Ó}ø#šˆƒ"xrrlºi¢ºR>œŽqcbJñÁ¶}ûðBßí1ù_¾)Â9`ºÚ: ý…=›aºÄ6œ°îŸºkK꙯Gá Nš>.åz'lbÿ…Ál§a•¥kòG¡DšŽ:ïuAð\|T0@>uÐ{po–Ú0íAu:Ù]ÆK¨¼ey\,²5âÝÑ(ËÎæviŒ—yáìÕkíü½q\ŠaâvÇ.K/ŽÔŒï¨xB¾$ö.ädCBrºŠ¾}Ë£YÔ¡˜búG„CfŸ±–aýç{ïe“¤ïí8ˆ\˜«íriäë½Ð°ÿØBû6Û$ü8M¹«œmæ/n^bñqŒ†bÌ3ºåðØã.Ì//þ O©K0endstream endobj 908 0 obj 6305 endobj 912 0 obj <> stream xœí[Y·ü8¿bòÖh¨æMæÍv[ÈÉy°c´‡v¡=ä=d+Fþ{ªØ<Šlöîh­ Ža²Z<ŠÅ:¾*²8߯GÆ×#þÿ>¼X=ý›0ãúõÍj\^¯¾_ñ0dÿ:¼Xv†‰µPÌ:Ë×'«‰‡Q†I±¶£`f}p±úvP›-gÎ{åþyðç0G1?ú0ÑÃ8͸9Œ?‚ñ¿ßÈi ¶@P0Ϲ+pfÔ(ÖÛjô_6["¥ñÃ_7R1e´°Qšûá~rãmXýÙÁê›Õ÷k¥¤…e‘ã­bnígÊ­W†‡bøìùêéó¯×·×wÇ«§ÿXóÕÓ/ñŸ½øþzþ§õïVÏž¯)˜è€<*J°ç¢´(f¾öÌaT-fXM­S¸\ó‹ AðQ ç¯Q›á…oŒôrØMŸš›áf#™Ö^)ì—Ò1/ôp¹É:P”®Êçm ¥µà”Ö˜¦ÚѧeÚYi½±J3«—ZÏK+YøõìÓÙÄ‚‘n8ܳѸ4 ú§= ÅPªïq“œÞ ?l¶#³ãè ÜÈÑòfRIÆ•ˆ­aÀ)e!Iì®·.Ùã'¨áÀ ‰èŽò$QØ*;¸+”SoKkYô%JMÒ-Ò'¬Å­h \¡ù -!0 à:Y"éˆ^Ñõ·<•|^$QX}Ý|…IõNq|Ô±‡mõÅ~X”L¸‰û2@-˜¯½ÓþóÊP¥0ÌCì)Ù°B­^›- ÁnØ–ÏOqs¨XÊïÓ0’Êäå¦Ìc¯”Ö6‚ø5ñï‘9ݸ¸ÙÅï67R9¶ƒ_0 „‘ÚÞæ¯ãÜûCn;É_W¹÷*µdîaFiUŒ,!°*€ ÖxU¼÷[ÓV&ÛÅÖ ‚ˆÅ }[Ø s ×A†kÙA¶D¢€5¼ï½Äçop1Ϥ5Ä'wE—„ƒ]Ú‚1f®‹V‰™] 8P‹ø!´b(þŸiRmU)ÊÕ¡ICðdâQ±i1`7"Éæ¬ê™žkØtÊ$ž¹jЙ~,†´›¤0j¢ÇDCyð„:ÒðUÅ¿‡|УÄF¾}3¡&.&7Ó°Þuþ*Wœðzîfà7s-|ÓqQ02cDÁJOs÷mî¾íxÿw¹÷,·]6‹Ô¬NÌXKø»MMߥ›ùðëôñîž¾?œgZšáåËØ‚‘Zo!§sÖÛæÂ¹ÎmíI8Ü¡c D'ÅŽ‹K<ëèä6®ªfðõ°U”uwÐj£m±® a¸ÖƒåÑoÁò,{\ü¾èÿ®íÉÆt‹• ‘\p ÿ*pñó"$`çÆC‡ŠÓÅÿ ’9œGá˜CóåI fŽcÿGéƒLþUmr2>q¯©gx›ÛuôQ"R/ú—m5,×sÛcýÒºÇe“ïÓ&)•É­àˆºS~j5µ¹Jí EMÅVßG0bßüê¬ÃÁMG†¯î•ÛÎÜbP»Nïiɯöà´1‹»†ÁZy—±aÕ)^š{—Ë "”¶-Ö™V¸¼´R-´ÚÍÖ{Í´WÃß7!J}½™²Úq;lÂå¶ÔËM¸±á PH¡e Áçèv‚Iå•q!„„½rªDàâ dsˆõ¨ÉŒ›P7b’!~rëéœë8§[Âb ô.¡ëÁf+™ðd:/÷ ûÄú…5|‹I9 q–².lTs¢T† bgÌ%¼±›«¤TJ‘¤Õ»æÃѤúfZ+5¤V¦§²kK[Xƒ’jÚU(.Ìw¸HwuD«>©®tXj9¤l4*#‡HAëIoÛØ¯tÀÉRKšví„h)iÛÖŠIñ³˜Ôz‰XH‘“¸í޽ŠÅf2OÅæËš¿  𭾨 ÄB³Ñ€û¼ÛÆäÕ;†Teô>Ôåb-íJx¯6àób%ÚɆ{æ¸pQСªG”v½‘è"jOÐjxX~²oÓ%4£%8e¨%,ÀÏégì!xÍÊéÅn,ò8³›4VÈÒŠªÀ}Zâr“ ¸ç'eñ(ˆKBH­S’0)x‹ùª¸v—äeX‘uá‰N¬g"4ý^Á¾Ý½ž•ðÂ{`[S‡'ËïJÑBü"[¥ xË>[oYíÏÀ åR,š8Tû(eÑ5K#øƒøð¼¸;¾EGƵ_z½ÒX‘ÍBnGÜôœV½ B œ´LGZ²1òð&*Qèa±¨ aØJ»o$XƒeÔ ýU‹´ˆi£ÓYˆDÎïåèÈ œÈN{ð[?èøB¥Ã°[9×òb_<ÕS÷Ä7%ï£ y‚@|ÀÒ÷ï°‚ØD«÷?†yáÔÊmýhrEKQ꫺2 Mþ=i+û÷Q©´GúJ«FÉ{âƒåÃyÔÁ½hÙé_ Øæði—ÓUOËæ>šm%ô/•ü· õœ¤}ÞçOÞ°õž—Ápãñ:qD¤,ÃZ+ÉJÜ:Gªÿ:»gŠ„&Ñ‚Oä?Á19b<åµè2f&Í ¦K#ünÊK½ë‡ò$3Iy;Aä5£ô +ú9>ô²0Κôà¨öu"H Ç]Q\¢…@2å(´Î,,¼!ÂüDB&ñ®÷®¨ ¼›ÁÇÆ[8g@–]…‹]Þ Ôì¨ù®Šó£RŒfx~ø’lõ*ÇùZ¨iÓ¤–(K‚€Rq8¼êF〾…Ìyyì}6†Ÿñ_'úæÄÜý)7éÅh„©Cê^U[˜'>ÐS®Ù?-ê\Ž—`¡™E‚àôw+8ü£z•›s`»ðþ6”|3W<¿8!±†h’W1®~^ÞÜ” ܜģ‰Y~F›<¤¾Ñœ'$1Í:;@¹H‚Ya;>s•áUôHÃ}zÇù㥕G>(Þ‹i«Æ·¤a01¢òzÊ´Æ3¸=òtåDH¦éÍÒvµúïlOKjÑMýikåüÑL aØfŸÀ®2³$¦½Ò®p˜3 t w]“­ tšÉfr²SÔäléÓÄ £h"!/‹â×Ôq³µ=2 ‰O‰ÜRŠ%u¹²"—5R ’óeÍçþ…r5¤¬ÎÈËû»|"»®^üpŠÜÌòÔBç/Ý'AÊoë÷HÓñ¯Ÿb:1úpŶˆŠr,Ÿz›—È%­"DÓ‰Š/: $ÍD˜s€æb«¯æÅTJÚÅÐÿÁª1Z¬Âc‡(OšˆSð=-Â^txè­¬°r¿ ¡¯d­‰­Í×ì÷¾:Þ0E.þÄaôCÜI,õrg‰™¶H`má½­¨ÞI™áª&eél9–GÓ«.™øÐ_-<š¾g·,Öíf¶K=ªÙåêàRŠ?zt¡~ð)I-gW ÍÏ4’5B¶±ÏõYðwµªˆ¹ÏòÔ>wξJPäî§¡U b„ê܀ƜFpš !¸àŽ¥(Á岌~ ›¶3ŠŠÆÃO¼þUƒŠôã›:Ø]Mg,Lv¯Ù‰¯ò­:º¥ß>ox8vzúï°»¬ ¸¾&Šñ†ÞÊIC$Í»æ&$ðÐÑÏFÂc!…ÞÓ·÷!Ìm»ÙÜe/Iæ÷>ã=á°ÑéwkJÍ³ÈÆìâù×1“¯Ê¦›Y<°}’Y=D]ŽX¢¢L5¦‰Z¯êÓq˜UŸYK¼êþ¬Ÿd•Ä:ýöD™äê¹_I8æ@#|Ûå!˜¦2#ï_“å(Cç÷“ÙJµ·Vÿ<3ˆ7uò®½D·‰w$X™`ãCE¯×pÚfc>ßÚ,VY å›Õwo£endstream endobj 913 0 obj 3381 endobj 917 0 obj <> stream xœÍ][s·‘ÞÊ#Åy<§*ã~I¹\¥ÛZÊ*¶lщRI$’’¹¡HZ¢¼¶+?#?8Ý\̹ð\•ËÖx€iÝ_h4 Ÿlà †ÿÄ?ß|ñ½0lñîã[| ÿ¾;øé€‡"‹øÇñûÅãPŒ/üà0jqôö`l€/¬XXÎ/ßümùzuÈc47˓աœó^ÆGÏ´Zž­4¢µàËëò8¾Užùåe©vQ¿:ÜÖòå‡Õ¡@h¹<]Á—¥Ëw¥à§òx^ÚbIx Õó“jù[òBIå&žCYagí ){]}BH6h©—Ç¥){‰Á2»|S;-ÕÆK}Œr6<ã9×q´gëãŒt(¢€1vùv"®eN¨—r¨#Êdœ¦oOÊ—Nru"ÝdâÂÛËFæPŸ´z¾úÇфԃR :G' .W¹ééÝ\GÒËé ʬ7áûÇå-~Á«ßôµ|àãJZ;!hO*/ÆýòåŠ^r¦h÷ËD—®¤Ù±Q#¹À ©kTì_œH˜Ŭ_þNЇÂjù÷e)pÑŠÉ[ü3ƒÒT…/âÇÀôHg~¬k¡ˆe°PðO]eëëáUþd(ý nXnVqKC 9Œ*rÈŨ$髯'±Hˆuc¸”çqê¼RI@Uwüï«h"Á‡ƒÿ¥ØãU?.3PÂWÆÿ% $5x T£€¶úýÝRP7ë¹KJ¿Òwµ¿ƒ_XVZbȯËÌ]Oß"ÖJ>8– ýþ±‡Øo¡ÉÄÌ[b«§ rYÒsò±³Ôg  ýç•8¨‘™©ÿëˆ*à”K¨2ª3U_+S‹˜ké7/#>sEë² @&T'X󺲎T€ ™º«°]b·•S¦€`ßrf^²–ÙØf²ïY` }¿2Õ­ÆÔÇÞZ.EVÒØ[ì8˜ÓÔ¡Ìj_Ýtô?T+h2éZá¸ÛlhË2%Ež‹Qe”DvDˆîƒW 3‚”õc0È0¡n,t´:÷Zú4êɃ+ÒUŽ¿Oc~‡žCx'ˆ‡'Œ¥ FŸcœMÉ'nó\¶@¶M ÙõÓEx›E2ì¬ò”–¢ÅöŽ»ŠGlà Õ\Â=’¿šüŽMU  *ø†“A÷™3|ù‡Ü>N$ÐV«(muƒQLÈÅ!Ð:å`†ÃÄòâV¢"(©Çúà…i}À™¯7𚉅ÑPAŒô÷j¥m5´sž tŸ”CÞ”ž>¦_£Fô¸5G!Uõ·yÐ7‰Ç%T®ê~™?•…»ÌïZ1ñׯV‡FŠÁ µü[þùËüóU~×6ƒ¿–Þ~ž–þÛ“Æ9¾r±ôj혚Tu+[RªW­S¹²hç‡à½n,YYG-ù¬rèRóg†¸Þ«‰Æ£Æw]o±tR4¶jl¬T4yTdãA5•«ò‘‡Òࢇ sÙ"H°´ëÊ!K¥;qxÒÀàœ×õãÄuN¢þ3Š Þ}ŽžKCFxòŸÐª¤dÊ¥¡‡&–/àÑòç~zj$øÆ£•Ã%Ò€TŸø2Dþ×]Ap%R p"¹‡ß£¤fBoC‰Æ9ö.u?uŽíí—|º” ë—ù;?©¦KJ#n—¢¼Õq–5Ÿqä'ã|rïéØG^–CÅ “¡}SJVƒ8¶ê–ªün*±’?Nƒ«ÅFZ2®ÂÌäåq>ÄÓ.Þë×Mî‘´•ˆ<®Óc„+Ž+ X¶Þ£ñ>B$‡W‚ÉQ|±—ïa:‡^βï¹Èü±||:Í¿w<ÓYÇ5\¤'ëÉÑÁw?-ä‚‘u €Ø@¿AÇaXé᳃/žýiqýáÓéÁYðƒ/žâ¾x<{¼ø¯ƒ'Ïßָ͛5 ¦_w¼ÿkÇ5Á”à 0êË©ÿ%•_wài~÷6ù«OùÕyôfÚ/ÿLÁ ÔǦ­´œ_YKÚ=¯_YKæ,7õU㻑¸¤Úyœ„04ÏÊ񪯮I×åM£VeQÖ»$T5ã¨N»õª ¡”a.« .·€—[?ÃdO{VÝçÊ9ô"hÚ£¡L•@z9J>K\Þ§Ü/\gK·Ž·ÓåFÜðSçÝ·á~0¹dµV8ézò2ZÛMa„(¹Diãa Fu¼XKß7ƒ¿ž7À„O¿ó-†øËµ•Ï €©‚'÷׈8=à æ}œl²H{R[n¶×˜› ØRä²ÛðRh-†ë–4KÈ*z4E±ÉºÑÂŒYAËNÈ$¶Õ³ž'"þ6 ƒtW±¡Z7f< [eƒ€¢ßµC˜XÎT°†^wËÖÖ€IVíJ“Éš:Žþl`£à²oÇU m ]¨ÁähW—61þ0Ͳ?Ü”Z °Â!8E˜àën÷°–1>öGåu ÎP/yÛÙÔá*îÌLom5Áǰ’u @‚~Ì-ï‰&!kžÜj(|"pC˜Õ228qÈâãHcÇY<ä¦$E"ˆî/»nï¸kgµ·µR€ÇÝ0¾ó»Ì…/ºn9ÅoTêN®ÊéÉrzƒŽ…ÈZÞ Fð€€B¡æs5ð™ô€†<+>˜eÝÿ¥|Wä—¬¼Ì{Õ¦qç}'þ¦àÄIËFëc59pék¹SS­—ßÂOcÄÞ¤]Üä§Ï§Ît­Oã„«Úêkt?~òÏÚeIVÜDê¥3¬iïÜLØ5´šÛçíâ [hŸ§7”Ol7€~°†¶º£ŸÆmé@¼]A›Ž‡ÝÆ _Ö|?í¬l½]]ÅkâôWÁ«-¡lâ4D¹xÀÝ-Hy‰áÚ¨õIÞgU8iv[ªmö»ºPo†…ˆº»»%³Šãš5³Oκ{îMr¢ë|X­ÞÞ«<%û쨌¦¹ ÌIUsp‘X~ô΋kI0!/ðÏÒÃo $ŒëúN\ErcA`üº¿ë¸Š —iS^¿ÔY«Àœ·¯Û,›„#‘ 5yKÔkWhÅVÃû†o\Þâê© Á©}Ö·Ê‚âŠ6÷®ãz›$•Sè…Ö„UÀ‚ ¸;­I†›*´C²Êªº1Ûj™«€”k3‰K‘,ˆ©SjW?ã.±öÛ¥c!w´ =nUj½§ Ð#k¯ÉÚviˆÊº"†1{MŠ”~2IJ¢|3Òü¼ÓŒ¾ïôÎj¤SdlÖÈýH1Û‚Þ™,Ojµ?ŃFÂ^ã=P¼,ï"ñzÊàȯ6õ&dåßSoƵ_î;”ŽÝŸäVÎH¾ ¡«ûuSF']NÎÛ•ÑaDJØ–ÑGÕú†](æÅ‚é<^áÙ2è÷ƒg`ª\BAt°î~šïl—l_{p=D`knÎõªŒºõ\/¤ÙmÇŠp?Hú›s=P5ü½æz‰Ì•0ß ëë¯ïÇ3‹¢¡zÓ úÙNÅ¡&žhW®Ïp6\¯pªÍ\/ø%¾3×ÃùÐbG®bíÆõRÌê¼)¤î²øµ<;槆Ö$ŸöSPCÛÀƒ¡‰Ûg‚˜»Q3AåŸ'äùgÖ“J©æIaÐç¹…Š¦®Ãèrz K…m€¤˜á4õ®˜KHÚšâs2PæíZÅù V gt{qFfLïONáýÐF"ò‡cédè%Ù|œÖŽ»—Nj|_urOB逽°{ÞILè _sJL—¶);§<ÜFPx†±ÐQJôCñ–R듊·”2æCoC)-8ú|A³³293Xgduö§ŒZ3—¿Üà&¶rÝÒ§Ãm7f˜9ËfB€ý¤âmÈV”êÆ Ò9<ò¸9X8’ÊÍŽŽg–?Æ¡®ù£ñƒØ2»´]¨LD¦aõÒžsC_ «Äåyöˆ=°zgöëC:F@ÁOÝŒ­Î\Ná†úÛomL4†Jª6,Øq£DÖ–Dܯ"ívñ†xUbºMo®×\Ê¡ªTÞnϤðí°n¸wCH1oÒ#Dû–P÷ÉÍN5s/O×Ü9ƒNó(ã ª«=`F+lQ wçÑ|¹øTâ;E/ï¯g਴¡=ëõÍ–¸!U^ h±û‘\†ùìÉ«sýUuW·¸-QMîú“0]¾Ó?}ÚÞDÈçqŒáq~Ogf&)p&²}ÊrÈåK¬˜w"<ÞlCxðbÜVnö$ÖœÊ3J^¹¨îšæ°¢DÐöœH}éDïN¦íÎeÈLNæ?Z)˜RŠ0wŽ,å?Î£ç±æãõ Ì„gª“íaO&ßúÉÚ³iã÷'üºwF>¶tÕv”Þ]Ù¤Ö“Ä$š DiÖ'¹•¿ZÈãq¼nd{Ùgý˜î¯i·{.×cöéõ'ÕxQ!=šH<ØËh†= fôsgK°Ç½O6Q'.ÑÄl{~ç›P"ìsÑnÜ î·‰Ñfw~Ô¬ªîþÀ_û²sMØÝA¸àèó@~‰Û0¾ÚMØk(a[ì^vì&Ö™ŽË#d0SSÞ|EødÃJÏ& çdy+È_mhäÅ•…>[¹üËÊ9 å²w_K}iõ}Y l—ÝRîî$µðªw\ª0±|ƒªÎ½õ´ù¸±Y)·\JåÃcµ"Wõ7$¦0Räó&[{ÁRöµq?1Ìg}©ÒV¬ gBÍå”Õ ¦4Õl²äa1¢‰‘´_Ÿ©Œ ü!o5vS@oñ–rÐ2lm=Yƒ™”…ݧ±5Ëæ7«p直|°ÂsÎøÃ„[“ZOKÙ‡¹Iê­À*¸Ÿ'ãoÊ»êGÌËÕ,Ü $´ WQS|R.~¸SÕxÅþ¤À×£¸GNÊ>%%ž—×ßF™iQ’ûñ ®…j&À?Â%e„–Å& ڸ헥Ü=îˆPJ~»¶UnCÎÕÆy“Våy£ÿLš*[Óí”|@/i.7N½ Â5žN§k×ÛJ;•6,î‚ZoÇ–ŸuzÒ=Ðüb\Ò0`Öϲ=îWû¦VN¼n SÚI5 *O­¡…¦éU®šogžƒH`°˜ønÝ‘0šª!iú(6-I"-W•‘–!¼ ‹.9*ÒÎk`ì/QÜy½ZW–|·U\4Pè8m훾V¼Š¥Á ôŒ”ý¡”-íJ‰[Q¢ W©ÿýÊ`®ÀæQ×8ž—·/£>qCË>+÷>ʆô?­ßÏ™+ÿŠj’…^)-˜ *)‚V`«8=Ùªhoúðk|¼¹ÿÏ}Ì,zõ%ÿï¢.ÛKsþkŒã4æ¢Ä¿‘/¼ª¬$5ñ¿fÃÇ™&lËñhGÉ\ЫÎ_û)΃x›Ôì“1¥Ì*QÉð Öi2ãîÕŃô ÚKôèi-QwõѨ¿FàŠ6ê/éhø½ºRm@¤­¤Ÿƒu“’36jíøÕ¬µ¯ˆR}=‹££ úªôóž¾?Êzù¤€6â K$»ª?³ˆ0–­;?™ok(Yx5•ZñSÏmþ¡û‰\­¿tõ}¤éÜøwR ¿ðÀ9Öci6>™´zùîà?½1Tôendstream endobj 918 0 obj 5339 endobj 922 0 obj <> stream xœí][o$ÇuòÈ_Aø%d éíºWFÝm »Ê&N`ûAZî â’µŒVF~|Ωë©êªžr†²Á°wÜì®>Uu.ß¹Uÿp:OìtÆÿÄ_¾?yò ×óé›OæÓ…ÿ¾9ùá„ù[Nã?/ߟ~öo3òÔMNs-O_¼> °S£')œ=5lžføËû“?±ó𬛕<þ§uNœMç>9)þË‹ƒ•®œ'«â˜NON5c^œËÉ C~ëÁcgü/iY¼¿pè/_œ‡ž~qú'_>=}>\Ž1õŒÃÿ‘ñ/3¡ï3ñùÚ”xÜÞ[h&õÄë5ywÛŠ2×4ý6¿ÿß3M7Ë´ã__åk›üë¢ó×Kÿ˘³wÍ´ó%øQöîUºtq¾ÑFM°É½!~,On4³“Vüì:]ƒ•гœ¤å‘^¸v½|{þQ¦wUÞäí8û—xiu_„‘³òÒ¾ ûbóƒŒ>¸áÂLŒŸn˜ lþâžùú|#&0çîVŠã¤Å¤ ÎZèy H×E¦^ãU5iܦ ›´VLÓ¿¿?öwž¿”0ù|ëU¹õ¢üüF•j2;Óò¶Ü@FHtYIé&ã’«d°pŬ¥ÁpfÊÕW8®˜æÙ„Eг6xoÕ¦7X wŒ©ðwØ `©‰Ï2­Œ5eáxš¸5‰žúm¤„˳ŸÎ7ódæÙêjõ" m&Xg:¯«xUº4…x5~olD#²0°8p瘭Ԗ‰‘u»ìîáŽÅ~¥íHdßâzâŽt¸ÃO&o['`„Zò2¼D~†…!7 ÿi‡B8xC5õÌ×冴t³ÛNãçBM`–ìÙ§çl6“j_œ;ø# ã§eËq 6q6ŒÁÒÎ,lÅ!„s¯Fœ¯¾*÷¢sIƒ}ZI+é³ß³É Œý9þÙNrVgª0d£ðâ]á›K*°ðNa¨$eeÕ5ÒLÑRá׫†Âxd%ÓÍc>U³hùtñfŽ8—[7Q ‘ô͹)•î®¡à†»Øc¸ Ï (‚µæÓaû¾Ëð]†WÈr›ÿúó6\ÈZÿ®ŽŠ 0 ¯&tÑ¿'¨Å0éG"^É–øƒ€Z;#.¥ÃîjíDMÓ. ´H!=ƒÏM«¿ý?´ÚâzÒeÝh ›žµræ;ãY®À|ÙÎz+§ g9hwƒ³ž,Ãg9ˆLýpÖÛoÕÀÙ°p;ÁY¤D3Ö T‚E9øšøå.6ÎrNg’†!»ìBÅŠê4þ‡€e\Å“…y'ÆøÎAø Fƒûê1h’ù¹%òðä"bEÇÁ c‡ëraŽÐ=íD 3á3¯Á:¼ ZÛ$@7¶IʉYwö_dn_£‰|J/žÇúŠ\Ue¢ó‚´j"¬¾q¦ÆþÉì þ¥0“‚]Ý0¸ŠF ÿ‰CzøÏòmFÿw°üvÇ0 h4?B˜Ð~À0uïø/yö×ðïAÿde÷ˆþê=Ð2s `„jà2³ Â…:4^ô4Í\í„—=aÒÜ/SÓZLÆk–OBðÆ61g[ìz×C' êYZ7ò2‚Þ‰Ñìyro1ßH¸KÒcz†ÑH-óŸ n[@‚ü¿©ì¬ {û]°žˆ¥tÒʯºøï§¥Ä;êù30 Œ2™êew~ƒe‹îÆî³øV÷=[Ï•›-@}=1Ьþ»BÉPÎ[ € NºÀ{°s…f‡ Ã¨ë€bÐvGû¯AW³ùé¹r¦egÿAhQ üWHx$*[¿ËsU@Z Ò¸‘F+ï_ï‡ÔvR•0o¨fè ϳÁèlADoÝõÍ%–1Äl~vÂR¨>ŽùñuFÌa‚#ôCp„Òý”H\vÌ×mþõ!ýu<äs0¶Ã âq!νšÆ]cÄpß7×ð×uþëOË¿Ž¦¦ÙãMM«j^{b¥nÜ·«R3J°÷SÂñ—•ÏL\»((É]à•¶H^šAÓÆÁHÀ€XQb†‹öü'TXÚrŸ·â07°¼–в4èÅ<1û×òR%fXUwOze qœí*å¥P`™Ý$Œ® ¨äq§ÛuôØp<ètâÏ`ŽjÔ=üËP®éÃû94¿ÆþûތպnsgÀnƒÒø3 ê‘(¢éúþÈ¢8a¤Ô¸&¶ó¾–l0nŒÐÒ‡š”êO¤Šû¥2ÐÌ4è÷I@— ßçù׳îÖ‡Åñ³ÿ$3ëEÿ ¦˜w'DŠbBQpö[òÚëùfv¤¼6P¡ÇÖÃ>ÄzH'q#¼Œ}ì ÒwTã¯ïó_ùRÙ¼J4B«™"š+ee0ÏK‰ÛC+kŸL§¿jfQS÷]4 –o£ø\žýoT„Î…ÖÑ¡9­Ûg¼ãéõ+À•?-µüm­^!ã/»èKn]»\[ô%s<ðU—Ä/#¸Ž(F’éC×'åjI¥Hºâ»ŒÊaɤ)„ÑÜÐô|ß+6¢*¶—LirW¯V±~^ñ¶›ãÃê`üIu+¹¹ÀÉ›˜°1’ªÎ ðù}i 7”}¶—Ò÷! ž“¨úÁût+Š,§BŒ»!ó95fQO“Å*c! sV0,°’¾f«Æµ«h‡×=HãLñTÜdu[*…zêv× ,ŸSð€<‡CzÉRŠ\»¼K݆÷[¸í²øµ‡ŽIƒ®Å¤ý]× ^»Ö}Wu@Üâ¿”9í ÿgˆVVAê:?;c'„%©R¢!ˆ¨ß”W‘P(!€xëä±R€QTù5 £¦vÖ9jªxŠ"¸"Ñð"#•¬’Qq³gÀ‹3Ú¥Pµ°-é ëîL–»Ú”uúsŒçî.QnÝÀ}­mÓPe[ïºSYVq·é‰·!ó­]ÇÍÈu¸ßrP"rUj'þ1CYRCj+âÒI–L³/!ñ¯5³äURýϦšE6¥™¤æe¬/µÙå©XÓ›œK:Þ-^ w-¼©vˆÔ11ìC‡4¬"bŠÊ¢£EdŸˆIª’j§J“ôØ^Ñ#üá—ƒk4?È1†yÀ¦¹©¶þØâ‚—ëèQAØÔ\mUú©\ß÷q×»Z ­‰‚ìáe¥¨6ð¯´è»èXzfž1QÒ g¿Çõ€’lÒZhžáX hP}v"ª¾«?®U}ÖºÕªH‚*Ö§À„³¤1Ö¢µºj¸ÆÐA줫ýº2ÛÄJýU9ªÕë”ÅÝ‘„­K»J)R»æµ¾a°6Iíc3 8ÆB*²h7 $ŠŒ¢â©Ã艔Ÿ_…¨z?öî‡ë²ÒÇᙩª™ë«ÁÚÈw–xùb1‹Á¸7Eƒ]ý¶\ű˜’ÓDÓÞµ é {W´²˜Mjr]¡x¶ôM¥¼Î*Cn )3îËÉajŠf"†We’ÛØk¨¿¬“Xƒ’“aŒ\ûfÏG™t1Ý6¡›Æ·(•KÛÔ6fí]ý‚OšŒêZ¸|®žü!¿üf›‹ãæÇc PdûóD7l?˜ ç!•ñ³AßÐö¦ã£Rõúçü¨ ÙÆMX c{ìáÌ iª~ò.½ûn‹DqmÐèl]¾&?²/ˆ™?/ˆY‘„`÷ç!tÇrTÖ5©Uèå–EÖ˜x¤E6s» ‡å9Ïî±ì‰œ%¢ó•Éä`5óà¨â˜-9)XËŽ5èå9j¥œÎˆ}’¶òvú - ðÜÄpŠRk©¿õ¢¸â¯»á’D®µM~*”K ßÈ–½Û~ª¡·k[ú´·ÓÈ+[¤âZ÷ª>nÅ2<ì™a€eöÕõI.êûFnÖª‰´/Ãyâ5¸ Ú_-i_Ç\V{ÌE«ÙÁG(¸¡Q‡¶:ÑqãvËäúpþ^ndj™ÚéX‚4V‹E)‘L¢kåïÄ¥¾{l©; {FêâØÐãÆ±ÓØÛ²@ÏøYèΛ;F˜µòºÈ¯a˜u-xÄØ£h&ƒÄŽØCbGA,š¢ïáê)f^=]=Bò]½Ç˜Ptõ¶Lèþ®^vè±o(¼€ÄÄÆÅ.VMjµ4*ÄWû¢°:0‡¶*Ò!‘¶~Å~=*·À¼³k‰q¤§JÖ,ÚõbØÔÁ4çÚýTYï 3;é£të–bÁ'£8ºŸpäyÄàŒ PIÝvN¥yŒ~=‘ýÂKÞäY?PÑMBŠE rö-Š}í“ÊžaKîÕ³M„¸[4÷f±²1½à‹ƒ¤²Ý7ñïC«®5É ð÷²„Ût«râÕ"ˆ¤ÅRå‹¢wW‹Û‰ú°`óŒÚs]bWþun–å¹Ríuj:vÛg²¶ájæSÕ …©x.1£³—R­‘‰ h¾ôfä±Ý?dŸÆ­O‚ +§“xYØŽ§…_¢$bŠ¡#Æ£žüdWñ—D%QyÚ± ÀsVË%Ã5Õw˧ §Îân’“›BЉ©‘ ¬2SBȨ „ÝÑœ5û½jÈ‚¥iuóä³û^ ¦aj²NÛˆÔ`„C#VÝ¡—@È× T-ô>åA¼úeP$Š5‡ô¼ºokXZ ÛRéžæàwq†°¶DÆs®Š)ÈýºÀµóähébm+3«û>8Ø ãqgj挔Üõ´H´»©7ny<Å09M ü<Üc[`pwáš¶òƒÀÂÒvö1N‹Ü@B$Ë|Ù­ªBÑëêeãcç­ÀœÔtåWMÙaT ˆµ´xä öbÍتXüÁuÞRo˜I£ë3Ú‹º‰;Sw¹ÞqÞ·(„ôeÇÆ’¥Ôµ5!I’9æ„ØØaC¡?îÊV­ƒãò3@2fêWsqŸJQ¤ppJвõ[éÞô$üªw‘€éáaVÄ´¥3bþ|ÖîUM“ztö)yÇw]»²¨©ö7üùü<œ/´^º"4¶õÚ•P)&‡±iå<”FôAQŒÛ¹w²]—­ÁðciܤÕDÿÑòž†»|­¡‘„zš€ÝÅMõçØüàØ æ“²b»|bëÐuò¡ª5uwp1=i©…ï€]ofUq, ­“=¯cÖ‰ån>òv^êŸâÛ•æ‹\¸kr÷iHøã9v:)j) ršÔJYô¾í+ˆQÝY8e¯­«K«^¸aʼyÙÝáwÅD^ÃyU´i£ôš±WJ-xÕÒpkHÀÈ6žèëVí5Ö Åïï?W±¥°³âö…g¡¸Ú{òXJ¹ÚØú;—L[;^㾞ݻnYßEBOË’ä¬n[Œ¹T·õ­©ïiV÷U0•µÇŽW®†º&èIÕ{ºÄDdOS´Ÿ ÉÐ’Ùpàô&Ñá̓¬¼1í¾ ³»Ô‹'©)ÆEgÙZ@V$¨³~ðeëy‚m=uf œ®0TV ŠäNu·¯ïi¿ìrͰ¿ xq®òßâúmÏ‹ÜöíÂbõ"oòÑ¡92Ú?„µgÊ·VBij[8(2µ¾.Š¡.Û*œQå“E®¶0œÇþâˆðÎUEy.j[I¿ìzÐ,ùeLtãXñÝ{áî2éw—ÄÈ |¥átr•—«* ¦äT÷K&2ƒTæ—À…µäeÅâ@︴#@Àïý#R ‘Mä ÝzZftQ<ÕW#=S;«_66/„IÝov¾>yñÏ;fŠýiÈÉùz}¿ês7>ÅÒú ×ĺYÃÀ\rJúJ}[AÈòd·±¢¼ˆõiºi²ÖPéÔÑ ]ës `rÐDAƒ<´?·[ûªßÁB‹îqk_-ÂÐɼ_ªÕ÷»ªU<ö±(`Ø+Â÷¬'}WošÁœæN½FáÜ蛇ñÃÀq[m›ó§u7¡XˆÛê_? ì1Ö>vÇ­pM>‡y=°N¹ðg@<åB­ñÌCÊv ÔK’³Î’ÆÂs—æ¢×7:¼]³µ×açýïNµx*ͪîô…)i'!ÍÖj¢ÛôÅ$·¨­£ÕÙÞ¦/_éô!¥}3ªjöåT«“Ša!?)ÕDkýw¸Io?¬Ÿé©SªIËà·œLþJKpÓ´d{äÑ¡ô]«!ÞÇwêýJDRýƒÈ=‡÷k4,ŲM…RüÔV³ôÊv­ŒwÝ ï7,4éùV»ÜŸeaoMÝtïMyrV ù”U‰üøÔ’µ>Ÿ8®‡òK¯öM´„…¯Ë•~áDË eÒ;>'Rè»^{]™²ÉÄ‘4m©MÇÅÔ5ÌéÔ»½²™†fñ€` ³úH4P'²ÔýÒ@%ñ$0“¿K<ŠdY´ŸEúLY¿ÿ¿Jãú¹ÛÅ‘jñ›ý®þEgtf‘¶g{•¿Vq äDéÌùƒ¶‡[ Û¯¸ æÀŠ,岚|†ÿàÈÊ—$âºG~”‹¤Ð¬÷{ƒ1ئW’pµÏ!½_§ƒG«WZèî$]>Ĩ£ðYØÝåN²æ×4+“œã˜¾_Tµg±J` ·O¾c¶ðĶAºú%)ÐøEØÖ-á‹Eƒ ^ ³op±nt,к€>ø¨^Þ´»Ã§­ÓØn±µuz6¾Ážöˆý¸Mx8QEè1š,˜?æêQ&$}HsÛ„ÞdÁ¸ÍÇ ì;Ë :ê²ñ²Üb>®çÏÙ]š,Rt+z6YD£rï&‹Å󷉌š,‚»\=' …þ ¼¢|KSWN%^ò»œCwô”ÊlÓáÃZ–”„ [j-J<Ú@q5‰­ò3lú÷‘#.—VèËìR-ƒAS¨¶(—9®€&&Í슀al«Wΰ*axp««[Šâº„’x¾Õ Î»)Y÷§œ >¤øª·—ýôbk9‚Éyq¬aÓURïq=•çÕ!åát:]½ûw ú+¶[ŸøfVƒTæñzDÈ™d›¸žµýlzGðð6c:ñ·ñ™Ò»öŽDëFÜ:3ã9uþ[èÂj mï†(dý §/ù‹ZiÏfÀ¯µ™ñËa5ˆº¦'rYc2ü"êA^»[–ÙÇ.ýªÉtP=°Èu!k0Ÿ¦Ôïì+pQ±¯vümÈÆ%ã“´v¬Êí~o«hÖýÛ?|òˆ¹qû='ìÂ/Ó܈!ÿ!ß,ë?av9 ´9ücçÃ@tÄr8hÈ ìa‡,gÃdzmùnÇ´Tžrk¯ñƒ¿ñ#8¿ØR•)þæ[@ZîÏ'¯};ºšoKÆå™ylÿ€¦âÞÏgÛ?â>lr–æíÞ°v'@ë=ÆcŸR0³û•cu¢]´$ßkÔþáNÁï[ ‹ 'ª AmÉSsôQÛ?ÜT}÷Æû‹ ;$øqy„êãŒ{·¡'Ñù”È1º?|K÷¼8Lë<*˽góGhén³Wa¹VEa·Mlb†>Џ߬WÿÚÖñk[ÇßG[ CœnÐR幚Nd+癞Ÿüšg'endstream endobj 923 0 obj 6579 endobj 928 0 obj <> stream xœí][¹uò8¿b§ƒt©x'ƒ @6q°ëÈØ;’F—E¤Ñ¬vÆÑþûœÃë!‹U]ÕÓÓ»k [íš*Ö!yîçã©/Ç]ŽøŸøï›OÏ~Ïõxùþ§‹ñòßà¿ï/~¼`þ–ËøÏ›O—ß¼ô·±K78͵¼|ùî" —4\ù¥aã0Â_>]üñêån/Wv{5X뜸z»Ûs7F‰«ëê*´VL_½ ?\ý\nèß W¹åƒ½áU¹án7aJq†WÅÈcÝÕåêOxÕ zÄÇ8$WìêÏ;f>ŽÕPä¡Õ¨é†×kâßÅhXž®0Wïv{9Àú©<1¸õ ¾_ ~^ç‹q†ZX:r•¬Ñ]y¡0¼À1¦®n pW÷ù ?íÄ ”åœ>tSz_"/ø@)L‹ù¥Lë~i'Ó¾ÝýÏËÿ¸àR øçå5° ™éåéòH¡}ö{H8q¬ŠÌ(4üYñ⻬0†ÆÒâ&ÆKoãöùË‹ï.~¼éaböRX†àpj-JË7/.ž½øÝåÝ—û·Ͼ¿dÏþÿç›oÿþyñ¯—sñüÅåw³2´@¹•ƒ©¥è:‘ù*S~W_ ”ÏŠ¦e$?9À–Ä£®þ{ÇOJÊ^¸»LúÝ…'à)5©”¹RÝ«¼\UQ0%ü¡Üh#ø>V|DR¶½-?'œ1Çâ@ï»ò6rüA øýÞà¸Ò¢¹!=VÖ—ØÜÀí—{Æ›)u£’TÝM4Êf Vr§é|ƒì9)ÓÚIáYÙL8{ùò?/^þݯ^D’@q~ ›LÑŽøN¢züzÔ^0¹äƒ²ŒjOX.ÄÀ¸ ó¿/7òú«}۽ߪRjK #/¾Éâû·žÑœå¨[*-„+ñ÷8P³ú†‹qPŒO•³È4ù‡î' CˆðÕÛòü›ÂüdÒžfÁÆJ8Ðæ šè©›x´Ü¡ ”5©Y8^Ü}:±ÂïeP tSTd!ú"v784»©ym^_æü>p¶Š>ôª¬ÄMG7…}‡{Š<­|Ð>ÂÂî~-w¾©ü4ŒÛv¥=ÛÊ”ª ‹ªW0g%¬Àýô)á"[Ø” [xb6²…'¶5©\‚¦ul~ TÛ„m= lÞí ŒÈË\ñâœ0U†0G hQîÑĘÊrí9,# W™sj^¨åMIÙ9}È~£3©@j5Ü“õÚ›:¥d´àðX´ƒhßæ_7ù¯oÒµ»Î¸1há-fk×ð:¡ë†øŠdØ¡ôë:ÿõí¡ iæ'r– iup6·Ã‚¿>¤¿.º,)šÐ Q_Š&jOž 3¥·±ºWÛÕÄÖ-¹iÐ8@‡ɨXkG´ùuPvÔÔn|ŽjÃVîw±lÄç¾)·ÕûniQƒ‘ ãÙ¬ïäõ–¬£ôÍ™æµkQ¢’=ÄIƒszÞÚ¡"ÝkGV¥ühàBÞ5ÕŸÁjàx–ìá5š;;hf¯~‡ZGˆQÚìPÕÕç¸W|`à©F+zõ+1byzdÑ_M<‡Õ¡2‹põò£ÒctƒÌ(Áeý<GÍX±]Ä`%ç„;ʺÈNÊ֛׎%&·G˜Ò7õÖG‹2o”qdóý$Ãî+ÉL´~a³ý#Fï¦ÒÖ wbä”0è9„@ž”rôLaêä«Ú#/@¼ìþH6`T-‡Ñˆ¤îÀâµk«ä ÇNŽbÑ Æ 1r†…‹´½ï:ÇD³uò¥i} š–›H6몳̕úJg Hd©òEÑ»8É×ÃÚ(øÿŒCŠùô¨õ¡4kÀf"Q%Y”*ªa9§K•4ÈIzP0/S¸ï§àÑtÔRµFåz²]Õ<ìÖž—kG6íW-—)N\‘Q,$5½\n Oµ´´ ß)‘Œ»á§ñòœ®# góö_å§}#‡2¢ú³š£¯(›”™Œ¦å9Gº«Ì¹gEé'/%?ûüP)3äÔÇÄÆÞtå·@:XÙ‰åÅ=ÔŠj 2ÂÇ®46ý¡ËçuàIrqȧÜj¯ µŠ7‡ÆÈǬJ”÷¢s‚”‡-ËV|ò|›¥/NôØ2Þù¥d¯öYA$›’Ðc%ÒEx'ºï$«ú¦«SÒvºŽJÎ"]܉H5Šä„ޣ雍-B½3³N–¤³äN'KDó×#¸ï3ëU!ÀZô&X f§ž‹Ÿ¤åÈ $­sÛ+NüЩd¯'OÕüîW¾¼«ÑÇS‹Ô᥅YP21‡ ýe¿n{¦B¤U‘m=†Ðæ“Ò«ò»±zµÂJ£ï*k#üVº¶W…Cž•‹%oÚßžW¥âP§pxd£êWòbÀ®ßö^@øþwÄGzKVhôòJ8ôK§¢Zy!°Ë‹’æ2½õ: ›A͘¤ kA$Ptßï`ÿ¬“¢¯Dp}F3ŒU½¡¯ÈÕ*sÝ­æUé—"7äh[×6„ÏŸK¼™ Eyãs ˜Ã¢â׃^}“ü¨Zk§›5¡~Ã;"T»X»Òg—Ñ<Ø_*\Þ(ñX¨r¼c©j†®yñ¦´Ú¦ô­y×ü¤RĨŽU)DÆSÍj—djµÉÒÂh Ijz®ZŒ¢T˯hÐì(²ACêj‹6së‹¢+°ÏÑ÷ûQ@ßÝðUà$ŦÉ;S­.AN˜—àÌBK¸e ØÇ„–à 9µZ‚бP)>Çah‰gi¡±Ž9šbLz.Ôƒ±%lÕ¥Â(éØîЃSJ±ÇÇ–h̽PÊO€-P»Ý ‚ÀÍ,´wWC¬÷h 0Õ:h‰×Uõa+´Ä+µ-ñR¦Ž€–¸Ë3AK|Aí ZÒ×7OÐ’'hÉ_ ´„Æ ¿y|‰,oÚŽ/‘Î##½ÝºÏø’{ QèÁ,F£÷ ³Þ†‹”ÐGÀH&1_{– Ip=4¡‡CG X@ÄÍjèˆ3·‹Ct/é[±#>k zÙ¹;âVÚ6aVJc­ÀŽ4SØŽÁ S‡H\ÎbG@+œÏת|lþ?ìöŒ£Õ4£ELc Z‰i»ëÒº/nX=l(2Ið3~„ìÆ×]2wƒ¨¾Í»nˆ…×ÏŒ:‹ñÛUÛœ9HÍi9kˆüÉ›2Âd6ut!£å7Ot6ÏßQ¯mgwm_,1… ˾³›vÀŠæ&oóWÿt•ô9úûO»P²äl.%µ5«S +«1Ýä8†eã8Hðwæ‘%X!ÞŒœðYõd‰fƒl²D£ ZD†Ï&L %ñ*…–Qwˆ)Œ’~c²‚‘û‚ªu>9ÿ€†R@È“&lÏŠ¢Ù -ÁÊ¿õ(´Dc˜i] ‘aŠTbÿP¦{¤ª˜Õ|$Ó²»á½Rã Máxÿî]2&<¤¼kLÓÄ´‹vÓsö/ou°`ºgS–‚k¸Aoã!¯R…®Œt6²#ül`L¬‰µùyØf2½§5v=/#O a;ÁÕপ-Æu^„ Üár»KJã&Å2Ì„‡[â^Y©;×I jq2"±¾;q4d*-J—ü ©5ˆ)fä Æ °a„˜Ã>1åÇ-bʳ“Y@L…í6­#$ILu1)-'¶¦>q®›Œͼ"åÂzŒÙ¯Fª]í+Ýõ*V¬¸!f 0*:10*֚όÊHî£LTeMƒb€»ƒf^€ÂG÷¹^¿ zê£CÝѧ>:ÓGÖa*§ê£Ù3õÑ¡”Ÿªó©ÎS'°ÓØ©÷ú'°Ó¯ìô—ÒGG•7mÇ9A´„¸o²ÞfœSé”S,âëÆª¯‚Å>:ðw¦>:tBŸ2É¥1ЧR´@@#ùÌ >^a7YÆg%¿v]òk³û)ŒÆúœb¹…>ÅÆÔÄM%I¾¤Ïu=§©žn&%xä®ÇêZoUJ˜Û®PÞNĺ8šmúü¦{ïueüB‘zÍaU€;uæUp¸,ôƒ2¯Ý|Ã4LO¾ºüŽª®j –—%yº*§¥(¢~§ÇØùlEÜëc¥§d*1>>K›&°Jú¶–ú­ëÊ*Ý@¤–rµ(•Ÿk–ŒÅ×=·Ê6=yðêSsGk˜ª®Lö•MÊ>ÞöÑÁü Ð2#€ÁbE›Ý•Å„@Þn‰;KéÑ­"Cëhü:ä+åÉújˆŒd¦SoRÃWÃÎâ:#LÚè„m<ÐG§HÒ¡xM‚h®t\³DJ¯rˆñõ`Àg1›ãèG?´ÊÀÉŠ‹÷ÀzÊ3Ñ®ž¢ÄŸö¬ ³À.Õø5ªF(áqwD¤ˆ|’ R?º¯„â†øª®AKRJõýZ:ìOº0t{¤òzŸ‚b¦é´&‡Inè'ôú¢q3]Ë·} ,xH©'U™â뺊“ú\â(À8Û>½%1.1¯š)— T뙄Qr6ôd‘Ô­¢$2o»â¥«*C ¨M-ˆ“ìncXq†ÔvXd øñ5‘;·¼V \Ö³,¯5ƒì)êÌƬg 5Z<¥zÊøÕ‚÷);¡|‘×í" ¦N 2“7ø™è¸xCQ0ŠA}4÷K)[_¹ïVw½œ‘­Y0è3l²ÂÆxиwê9¹³A}xÊRò®3¹nMº ß‹qjßy½îèjLŒ11h pÖI—#O?”=Ï\|RY˜ËmºÔ‡”¢2ìI¼9à{篨$DÍL“‡¤~¦:Ió¾"›‡‘Ä.õäÜI[Hmˆëœ¤¿Uî|ãøCÇS2î1Ú÷gÈHr0*ÎØ·ƒê·ÆÊyP)ƒouð€¦$‹òˆóÕY<ÆCÚ€é3´±QáU-ÉG§ñB›óó/\Küú4Þ^3ìpõéÞtžø§MP`ªÜä¦8JÓ‚kc— XÓáOwt¾ô¡ç#h>†ij(mYr³{:.2‡áh6GŒ<õšZ×Õ€¦Â4¨ã®)“à‰BvtÒŸÚáU|ztm$œh‘«zÔâ²rÑjzì%fºx¦%|&…¡*é)Ïé!Åp S¬: š`Ë¡n¸ˆÓh!fF,geYŽ¢Ç]þ–XÑ¢ëv.%Üê ½uTI°ùé<·ž4Äö6Ž ïÊrðÝ4¨$‡°²}°ûÞȘ»tÌ7lK­ÆøPÑË÷ÝeÎߘ çöbóˆm̺µVÊ<ÌŠ±–I±¥E8o8ñ¹?O!:øéË~Åp‘>EÛ †PÜ'ƒÂPáÐaõÉ¢.ãàãGsNŒƒ÷êv’eAy°•…¬¾Õ“¿Ì˜w¨ƒ÷™j¾y¼OïœQÞ£|û¼ö-cd {ðŒŠƒíœñm¿¬³á¬-ñzÏÚ¹‚3o›(>d’й·Ø°‚õ)(¢Ó´2™’!ºòž*~ÓýN¢àÀ—:Ã1-dõU€hO*í ®ÔißN>oTÉzu\Ö?ú”©ü-e*±,ãMUÂ(>?Cª’ü8¹ÊsL&æ*LæÉJ:úS¶ò/+[i’­dˆšx²’ñ€u:C²rBñCs•g¡=ä*»´¿%´ï5„ÔŠ=VZr´ùˆükŒl„oC+5cx§RÒtéwLœôйQOîhiáú)Ÿð³lsÔìí5"†|Fs¡£Vêxt`'3ˆ­ "ý³ý­ƒ½B¦Ò|˜’!/Ù‰¿'ã§^2û€°ñ3ŽÏ9ï½2!ßÈÖä,™} ¸ÖkÚPï§ßý†(öÉ¢Z.¿êÖÌ7ÔP`¡m‡‚-žð ¹â}PLœ¸Èi§N§†ÀEÝ¿WM¡k¯‹ÑØv4öàÛŽ%ë@ßâ“^H?–[I¢¦ß”´;é(Ð&»º£æl±/nÏ3:–˜Äo¾Sï® l$Lˆª2˜¤½ó³qŸáïJÙIëAÿÁ »îÛ°Ô|ýA½ÇcCA$óQ´óž“ ßé–ûèÛqóÅøŽkY¿®~jpp’³q¡!î/wà­Mþ†Ïé -Az·‹Ô|³aß’BÍ„Ó9ûÍh9"ÇÈÓ´mÊðúœšÚPD™}H;“/ê˜aùÙä&ä÷ë’ÒËXc¾H8œÖÇOžÔø¯æSa«¾‚=ÅkUºÑ §NçºIwÛl¼O3غþ¯B ТsݤЉD®NãT `ÙÑ5G÷žäfÖ•Iœ¸÷z> stream xœí][o\¹‘^äQ¿BoÛšDLJwؘ[6^d0™¬<$û ±Æ²±¶ì±åÌ8¿#?x«x-òݧ[­ì®LÜè>âá¥._},<Ÿ'v>ãÿâ¿Ïßœ=ù3×óù͇³ùüßá¿›³Ϙä<þóüÍùÏücìÜMNs-ÏŸ½8 ÀW¾›ù¹aó4Ã/oÎþºysq)'Ç•›«‹K6i­˜Þü|qÉ¥žŒ3›bRÊII½»˜¡)¥8Û¼ƒG•¬"OþPZò_êYÓ†^•¿~{q©&k›[hÈÌ“Õró[ø81&­ø¯gÿãQ02xHÅ!1c'ÑŽHNVHË`@ø þ Æ¿Ãö¾~vöÝÙç"̌ɞ3'ç‰[lGM³ÅÉþâéÙ“§ßœß½ÿøÃÙ“¿œ³³'ÀÿûâO_Â?O¿:ÿ—³¯Ÿž7\‚-]vûÚïò«ü)|g Lfø0è:gÆÀ ž¤ëœ³~×s7iÏÃÚ d‘ ™ª¥'^*ÄlØæo5®Ül7<Ê—›Ï¢„XÛ["”ÅÖ%Á²fó0ƒ/c»š©‚ÅœgU¿OcÕy¬rûâˆÙÙSÉ•`¾¯{|½\çé«·éÃuþm‡¨ )N&jB¢–ìÍ»ôÕ]úð’ªúPü„áošÿ Z'•2»„Þ3©F8>¦|Üak„µìd³è˜Ç}e‚*]¯4?m‚<Íh$W“œ·Ž>¼Ëchdb‡E’jžô|¨HÀ3°¨õ_ÿXwi<‡à*O6‡Ú?Þ5‡Ïó6Vb·@¨y§o¯ÒÛÄ=B 6™Fy‚[qŒ©Íûì£vÉFÂ]œAíK”’Ñå#J¹k 1~ºÍ¿>ß…axð–‡Ç0|u= Ö‹T]Žb„Ÿ®ó¯?ìfÕâ$ÒjçhÞåïÊB½L¿n•$æ]Víÿí" ‘YØÆ¥à˜@X.špöüÙ5<ÿû &&g”¦ˆ$ 0E@/AH…51Púúˆ—|¿+¿¿.8œ v´y(ùŽS þ‚vrûLú±Zð¯TÒq²tžJ¹kér¸äÐŒžô/½q¸,¤ÇÇeŽ8PŸf<œ¡H,Çsܘ)®KjüUí~»I½™#7’‚n*P·Å’^g¬N{^`=AøwåÊ·øb€¦B:@_©-ò"èä $† ýê¿áß 'öºô6þ®…¥½};X;ð›ü;’ifŒ·7I;Á)ˆšÑt‰2S9CÔÃO#¦Â¥·ˆéý`ˆ”ÂÓ $]w,ÈQP©‘Þ¶ çE)+œÜ°")ó⣞U6ëÖQöæey–Hs;ï’B¸ã=’Ç1Þ#‰#Ô}ZÞÈý{ÑF•8ÂpÁÛÞ‡7¹C;æáy#/Èý.Ä]?A×9Ÿ}бìû!Ä‘j§0G<[ÔÏò']d\å/Ë'QýÌ9ŸLå³¶SM z¿`vâöÐß_—>}¤ƒrVÂ$<…/(TÕûÕô”z!ÀÐSŠŸL|!Öi×íÈì”Õ>L8É`¬Çv¦AYhý×}&=•G›aBŠ7/³Á"«#<h‡6盃L>/6õªg^A&…‰Ó–UOÓ©+”ô±:ܵà*™÷~˜!´˜fÁh¿jcuáW ^ë,'(©ô¼™°vNRÀö²…f ‰;‰^î@x´òüm™®òBþ¼Ã–"û3ûV|Äú ¶TZ6z>À h`Ò)zn8ˆnÏ÷uÎ“Ž´©Šð²Ë‡²BHD öòåe1Ð Ä/¼†S  ÔêìÆwðB°×‚‰AœÐH½`³ŒRï˜'¤šŒT›Ÿ..çÉ̳Օ¶½¦/‘Ü–Ü€C àÎ+GmÓé0%ÏŸö+´Võ2òu,™YrNÍ@$…„xTsÚ›OØͱ1õÝyœü¡úÙw@ßUùr4ûÞ^2m<ˆøõûó¯ ç΀ÑIKž|áþ±Iò~b5‰øL—žõ…þ€Ó¬È©¢¸t…t•PÒîA‹À5p¤)2…utKeM&xåyL¸~ø[Äö¶Q39Iƒî»(ž¬úÅĸ‰½Ue»ï^ˆÂvEó ó<ÒC½–`f¼˜T éç@ºŽƱQY¾e@èu¦1þ€>¥0ßÈ4ƒ†ü7ÑROò)¯@éo~º` FÄúÔ4N™W@UiRC¢O`,‰&}_âÆ×EÅäÆC³q|t³ö#¤Ô.Y«ë€Kp/ö® ær¸æÿ’á.ÙÌÂ2ľÏJ.úîåž,ý÷#äÁ%øe7ÿ™—ô …˜¥Ý<ƒžMÜIc7B”nXUdéûLØ}×îÄÕŠ[a/ßë‚gV÷ÙM£ >ܰ^ʹ’S %ð&H¢ªö·¸©œ÷%Æm"a1à[Xµ°¼,†-ýŽmI§×ì‡ j…‘£÷îûuÞy›£ï›]Ñ7 Ü´ã¼ÀÌÅWå.÷ƒ‚À^çO/ò¯ï;$ò›u;ÊMºz;Ø—ejrHÌÎÛ"]D¢ûÀ½v† |Ó\Ä·á$Z×܆£uÄÝlU@T@ÚÆ¥«`¤Õw]£G”¨HÕTA 6­UÁÔô:Æ['z€6¹t몋œJûhè!š³ÌyÝ0É’rņÜÄ·5ö$øÅ*“뙲¸=Ùm±é}LEúŽ2eÙ*;¾äDðÛW5 e }5C×Õ°Soâ{%3ÔÔÁDAVà4Šü¹4Eä˜ ¼öyùØG©×µ`öŒ.PñE ¬‹ zò&ìí–p6á>ï|:ü³ø üÜaøœ@À§ùÄva•Ãý¿¨2¾ð¨„^Kþˆ´õÏà”¡²x}n«8ëHˆ13à¶ŠœÖÛž· )¡g³³¼â5ŽF_#ÒJÒäÞÐ/k2»ùr)(ãÝ%2  aÜb'áM£×5ƒáB£kt¢.q5¡Lè?A¡àª§0Åà'„ì­ÖÀáÏ #OЂÿ8¡¢É _­±•º ËüTk=°D+ÉÛRCÄ9úHúð±+§v1àÆ°Ymߘò¢ì”xø©ë ;ûŠ¢‚’Dóo‹˜¡Š§mCîÊz‹õªo-G³Ùã79Ù!þ cùQ²…TuYI Áy_ègÏ>û+¸ïd«Â¤Iî*ÑÒ)pÎM¾:WÍT~“*´GõkæþzÍšo匾ξÄ>ËNôm!iôS|’‹ufQÎA´»ý0_Ýo2Â@dXå–?þ/½* ZXoÙÕjЦ€^lÙ¸ö#±hB|íÝk4•yLŸ‘Ãö-îüÎM󉢚8Ò¸>î¬?é3,%Ú¡bWßvWÈ®s•µ]9±þ iäZV1öeùø9Ž 0žã´¿Än® û.ã‚øˆÛ8Öåc±ž¼aš<\&†'xÅzñ$]ƒ÷6í°õ·%r˜Ë¨NnLj¤×uA5Á·ˆûQÄÕ¢ãh£±œÞ;PR쪋5¯Ò$õüýˆåMð v¼³‘àÎý5¿oÏwðø¡åÜ}xå]äýy%”Ϭ>@»\¢úç[sïò¯o逯1¿´ˆgè«ÖýÞ›‹ƒ@B•NQy¹{ý\è5A?¸ùËýˆgÓýáT’Ø/èçDÒŒ]¢Ï}anèÓÒA—¡ ˆ`5C!èçSv®d"ˆáz×µÝü*/Ð`N²”iúWkHÉ~ R õ„~qÊ•?(Sáø ½¨ÁÀcÏrL$Ÿ¹¢Tý`€Á¤n¾ÌŸ ÌF-ÂU‡Ÿ]Xˆ»xJÊ@KL$ÊSÛk?J ‘‚ûQB0ÀVîà–…äcF÷SùõHsø`Œ@`öižÒßEž@Lû µ´CB@p7Éu„@Úc>*! 4rÉhs; QÉæÐ¶46ö dè´/Óiûq Ýʳ¬†»´y\¢ ŒJœé»VȾ­+X«ÙúEëÆ ,Z…—‡!I:þ¸Uuë<ËnˆÀÌqC!Ø&»È\ WãÕÀž“N:“Ád¾´6íQPfgƒìv1 Þ°¶uöðýO˜,„T+WTÀ l[‹òê¼æXT2¿Úf“¾,Ë;3F˜éð«J ‰»MúrÕõ¼ ‚«¦O»ùø×ûÊ»ßé84W­¬". ‡° \Afà®L»U±L•Ü—çÂä?§÷ç¹¢âyJK::î\´L7çfv3]Èÿh·ä=’1ê|¬û“ë&ôŒ³ö:oÿU}ØÆrÉè Ýa™²§ïQ_6å1¡Ž0¦Mdªb¡Ž™Èóq÷ä¼¼ôÊQiÿÏ‹o=Í}ÊËÃUÕ÷c çÇuÛ9sõ–Ýš8aG ½b·%½¸…5| ¢Ç¡xOÌ#H"­€pcÒ+¢åƒI¯P¬b½êiï±óó.ŽC‹a¨r?ZÌÏÚF‹1ÑöwZ,,Y ¹±Gnl=7FüËþÜžsGHv‚v̉’h—ÛƒÚ5ûÕŠìWoXãàTÃ>ƒŠ#W»"E¼JׇuùYÍÔ¬JÎò´FÅì™ÁmAÞØ2"8ˆµ³jÍ\“™…›RNþ‚¤vÐX… Þo¸_f–›}p2NÍrX}cKj–ÿ}\\ ¼ L«'Ä"ë 9Ù&,Èüî›M…hFÕ¯âtU¡úÎÕ iàêT™S3I³gæÔ¬=G»âob™Iñ¼µ³ò(H(ú@AßR)HXyU ‡Ï}šÕ€6Â|&¤0ahw‚ …Ö¸½ò•–lœ§4+¬?¹*OÉ tu š*O‰°2¨´¯rb£ÍúÓ Q0_IpÔº1(õCƒõ0PÙëK•r¶o°Î5ÊÔ9¿î¶Ú è4<‰Õ|A ûEÊZMÎí“Ps¼)4L€ú¹Ÿ¹L‰á w4 ^¶»ˆ©/?е Ž|œô¥@¡í‡>ÎÓ%t-ðÁOïSž»JÆÙ“u§ªß¯ëÂ`Øí›½Å²…ó‰z+g,Ö[õø˜UW58¾¦ù&¬õëý©"eƒ¬Gë‘Áú¿Ê`=&v=’W{“WDD ¯f¤/( BòꞀˆs_zPÌv~ðd/Žc¯†±Ô¥±°Dç‰:/±èhÕù’•¶¨U`ÞNÑe €±êñú‹.5C´¹ù·ŽLÝ.€ÔïÖ)î+YÓõÅkG"왩H»nRQøþ©—’ÐËÚb{†ƒMúÕž¸¯a},‹ÄÕÞXùÞïû»jV•ŠøãœW‚`%Fe\Ö…OB²%yíi^•¤=¬òsˆ/Ó~VÔgÞúáy?À¯'l}ÇêìnœÔeÒšR#>ùjU¡‘¸“~3Äx`Æ.§ølE¯‡¸¼È%Pˆk"ûö2K•íþŽ^ ¦gñsÌM>Ãã ¢Ü݃F¤¯ƒP¡—žÅú·Z°¨¶Xò‡} š}5$2£$½€úñü™KR=L×£ô0V.š¢ùñѼp|KÂN,7t„*°—hü­‹[™«ÿjQ°µêÙ– ³5S­8ëðl˜î¡¯hÇbt–¶Þàf’ì×â¡Sb¼†1¾/¡€7Vغäpšµª´¹_=['Tm¬¯iõ2£«_ÛÜ û2‰o©¯8È™fÍõcÍþ-7¯ª¶–[cd:†.?Îò~Æž•úàÄèÓÄ®¤TÀ¦–©_Á-[hq G(ø‹Zïö[’t•Ö§”ðÌ[5öÁdÅÌ´‡®s2]0¼äßC&m'}< ?jO³E"Xn<ðPº¸XaßÛ=àg)ÔlNXõ^Z^Jg£ gdµ—GPŸßÃrÛ)£›ê¯:›y ½Y/7 -'Ý%&eyÄ<åÔÆýˆª¤8pÎÛ¼ÁÖÝj#DzÐz{[Q”þVÌ3²ý¸™TŒN߆š†ÚoÔQ4 ©g0¥»­·…u$oLgÔ…X˜¡hÛÃã2”i;~ÀÒýÇ„l³+,ç ò±[‡™P‡ýb'×aI! îú¿N‘Öd5ùU]#é[ШDË:åÁN¤Ä»\WaËvtbÃuRõU„›+±Å¤DâmM­oÀë‡^HBPÃâ¤Q![üÐ :ïbFÅîE,éĈðlºÌq]µ/Â!Šûpˆœ ,kEJh+¿;œØ r‚²Ü¹xE¸¢À ÚµÄþ|Û¡’~·î ¦Æ;ªªÞ¨Ú–÷ºoûÆžDf‹K ÄZ¶E4h,¸Ú³¤Ž\n9‰…g-†ç6ö=b<»¨Z Ï.vl ÓžvÅ0(×m„¯…_žž·O¦þSLëÒ„›d?ªÊ Ëg:›d°ª ZûÖ‰·3ÛÎ;“EŠM]D« iý”á]Kwù³ž1« ?­‡Eö¦êxÐW¨–;«âî±üª¤U¢Vˆ@Túµ7G;o•V)¼*oó9™Dr‹{KéÏÑ,Š{«P½+þ¶¥ÍD®èhŽXËÑß4ëåT CL€LÇðˆù—ùSUqŒkyއŠcj†Yû¶°o»û*æè®êm¾ëugq½}Ó)cEí#SË€i¦ÙÙAMíAdݾîè01x¶_Ûë¦ áh©ue©bI¤1‹¡Å÷9øHUÀ…eÔ܇oÃå”F"=ùGy4Ó·jÕ–ó²Ói£;§}v2~ýFø:ð„là Žm¡ÒÁ\xén¥‹•+¥ËbK3`{¾4k-ì'÷ÍZyub ™˜·ßy}¥X‡ì¼oF[ùªÜö^•|±1eÃsxƒ±µ¸©‰âöÐI_’!¦¨‘®w,Ù_ïóÕ;²ë¤à>_í$]jÑõ&ÃΘ¸“ÌÂнƒþáNòIz¬BòdéïïX¶ƒVm¯ºfÏ3‹ÃêöGîíNIù³€­¬ UÙhü<6¾Cô¯i^¢¦. ò&@%kV¥Ýs£|žû=Ü×92h{ŒðndEf981Ð »rŸV[Œþ® ¼lðÞ{sZú;Þ. Awäbeåþ\å:1œ˜j=1aµöÌ`¸}›h®¦YøûGü”1 5úµ\áM­°‚¹ÀŠoNŠñµãá ÒVBÁ°£2äÛç]—. —‹>„é][‹æ4E5Úäø°f­9ÇŽR1;BdͽŸ¾®U¯»…zE‚Âß¶h÷J´ÅWábÈ—s4-„Z€N‰I°Dä-âoé)Ú8iÇßH{¤ƒjBCäÀ%úÇ–ºŠ41ÌlÖÄ~ý”Ô¬{ÜÄ4—:65°¨iÒÛn6–ün:µBŠwî–íë?y`xfêLDŠ¿,[üDŸj¾ŽYí÷ÒW˜-†¾‘»#Þù€ïw÷æ„RèË@“sûºoˆ½üfí1Ü7ó×Õ7Þ›9†õÛkjƒ8íÐo¾—×ö#ô:¯íä„ö[œnzMS.$9ru›Ÿ%g‚±«OJb†¼W£öÚ©&ãYBS ͧÝü:tЭ)oÌðÄ-ˆÙ¾†óÒýk”nÆxÀß[ƒ#A ÚÚfómòÌï TÑì8"tÆgFC³>ÎzÈøJÍU÷ïÇ‚P®×\bàI:¾«°P±=Q¥ÀJ¤¿Ç‹b•ö×ŶÉïõ‚˜†ºÞ*ëor%V-¡†œç×Ô]Jé0ýtÓÛ¹ûG³‚Ùv+)VëZÐ’~Sȳ’¼º¡¶à!‰¶[@ñåÁ<)¬›QÐ?3Lºö¯@}†K5õõ¿"K>YÃh[¥8Ž’ó»]ܸØ>ÈÎģ͸pä}å±Îp€óàú&áÄ_{Ce:”hó£¢,RùÒ–/Kjk˜æï@Õ¶À[rô(q©Ò@ŸÛ¯t/·¿:éX]ÑÔ½Q§NíO·EWÆ ¨£ °ë}¬9 UþM”JC鵪éZÜfŠîèîIÎ\uY `™,-•U‹W”õ¦-àŸ‘Æpñ-æMï¶õSÏ÷Ý|£m\£WßYÂÌBÐO7,™F@ù”XcßñÛÙn©yîBZÞF“ Í[e`V%K¥Œ7ßCg[éA?\elŒücªžBU­ݦ9Z¥ñýëDßRÅVw§SG;‰¼ ¾"ë6¯Îßñ·eÕ—ö´%iIæh?›½wÚ_v`vcYK,Ê¢À|p³jÜuŸ‚¡aaÄ ™¨¸äxe¦F¿E£ý Õ§)Ž–*Hô0%,«EÅk$©yç|I Ž¡ßéŒÌb„dÑúŽaï®-Ô¹:gsn9 k¯)T†¶NÉA5áAÿÓÏEiú.{E6gRêR›ÿ—J뼌ݨ£½Çó;çwÏï<žßÉÞûñüÎãùÇó;‡ ÜÿÏçw2~<¿ó‹Ÿßá³<¿.e¢M~ÒTëç7?¾;ûKÓbáendstream endobj 938 0 obj 6986 endobj 942 0 obj <> stream xœí[[o\·ú¨_±»E—åýâ7·uÒvì&BÚ")Œµv%‘VŠ$'vÿ÷Ìð’C.ÏjíÄ(†a‚ä!çòÍ7ÑüÃŒ31ãøgü÷äòèÏ_IËgg·G|ö9ü=;úáHÄ-³ñŸ“ËÙ_Žq›Ó³À‚•VÏŽO†ÄÌÉ™œq˜¼<úvþh¡™‘:ØùëÅÒ0ïCPóUnôür!`¤ÃüA ®ç Ç#Å|³X f­ö¿Çÿ€;­îäÌ›ñÚ ™ô\̬7Ìúáîk¸Û+·ÜäÑ&Žà€qU{1®âÜUž;É£òÅmž+£«¼z³XZ+˜pvþu^~’—óܳo 4å‹6?¹3ç€&ð2ìz‡Þu¬Ô‹ªÖOuBnc³fõ66k9Ä;µýŸ§9š¸* —Ô;j¨¼xççÂì‡ç‚!Çt\{Oióã^×–/Z»Ôvn3er<¦A2åT –¡ÐŠ3Å= ½¿Ä@‚Ÿîy½×%H¾Ï«’\µ½ä¹)É3‹´n”­ËÏrÊ‹. •p˜Ä®óÆ(³4ÖC¹ç¶yÔ%ÎÝouT‘÷l|‘)qz–çʧ¡ÚìWçËUG¨MÁãû‹²iƹU#^Ù^Ö,ö¹©,5–{ ”C%miç € ¨O;²濜2Z ÙC*ÇŸä¹òœ*‘rGĘO“²6(]c¦HuÞ¡ê”]Ö»hÌTô­é¨8¹÷ö.Zžƒ–>0£(…„­¤a&ßo“=œ³Ä^§´#ç–\”.çÍÜh©FÁÁ$‹ünÚˬOj>¼È «è¦[ׄX„m÷Ոꭖj²FJ¬ ¨cFU`'ªRø}ÔäÐÚ¶ðäËfnªí­ºÐ÷À©å‰õA=ÑzøÄ,mêY7š=ŠíqÔÖ&µß²5†Öæt;UH~l§þm±äÌq.µOÍQ+ƒ¥fÒòÔZ]ÖWØQ•ÁKÚQ½K;m¨BEÏô§†êû4T;¨¦—ú¡û•¿º¡ú›½»Yå÷ÞK­½ùÑõ)r÷Œ¦Ð^ŸâIÚø0oü"M=> Oñ©ô¡[A¥qÍ¡Æý{ÚXèçqšzVŒ»oÛÓ²íQñKÚ–½W(l_ÓŽkB7>Íså˜iu¿nÞ25©Û õ49@Ó×ù÷0žÀ$ŒƒSÁЊÉFG€PÁ „P”Æ[­òÔ@ *º™L[O»³doÿ³5Ê ï\马WèlÉ‚–Tš[œ… U&‰‘Ê ü0ŒžÅw¯šÀ6öT”Ã:¶¼'Ã<Þ Oš!à Pœ `z›=óx¸A;­í0uXéŠ8Ak‚L²|R†Ä/Ò0î Ø~\Xx´)aéGäaÿfa4ä ãGH¦™ÿk¡Ah¤Ð@!jM6lG7a#Yô!¾nõC§óÜwêÿ=rWC4h /R8œ]ˆ _•H”^ +-±›¼`Ækʇ`.Å´W#Æ­#Æqô,sbË'˜ÜáØäÏ2áÙ0Ž)Û[1â9ñ1nN¦ CÜ…I"I¤@¬tÕuS?ü+ã‚æ@?qÖ¾üâðǶE"‡þöèÑe®-ѱÛòÛˆ«ÒRKgCQFm -1H× `Ì» TK«Ä¯¼3à†ÆÊ)=1ë¡ ÀhÙ 6HØKiA[³.$q Ýp³èB`«¤êkÀvP>61pU ¡—j‹†††òBi+‡N8š|s“¶vk ´cyVûYî:>%U!­PAH5„inqÄÕ¢áb ÃC ˜?%ü[®PeëºpÙ.«‚¢•\³©¬aVv*ù—ÃÃR’‰T"•¦Á­>€¸SÑ]î¢›Ï òß=÷ã±U9å Š‚úrþ9‰ù!± •ì$–‘?°µôñ7ÆT¬âõU— q§wŒ?±€zVr®HAs:°ªÃÆr"ÕÓ.Áß,TÄ^,a”÷Ló,Œz`ýT©×#à Ül™á¶Ÿ£N ‰ì¤³ÄsÊaBöÓDˆ&Àa4@Î$9ât!óÞY“uRÄ ÔÔÆ5£EÄ›¡|ŒeN³Œ~sž”Aµ½’UÃ_êŸ7‘¢„D¡F2$ܹûhBe© Á:g¦+/e!+qxEÄÚ6Qw¶Ÿç˜à‚—r^t‡®Ã>„4’Í4’p³ i¿*1R(õ³>)r¾öªÉi@_‡×~ÅÓ‹ÄØ!î"o€XC4k|YŽÑ¼éÒV?”##Òí»Üú¢q|So¾d’·ñ™Øðx¾ãRÇÞ‡”å±SÉî‰Êˆ\KÞT¯Ë:Q†Ô?«V°Tÿ(ˆElšcFzçÞê=€îº²á¤„÷9ýïC‰R Ä»*ÙKÈ9ÒïywiË\üÑÈûær©83BÖï¨ëE|x‹¯Ëg;Ï:ïw_#„ú zÓe…ᑦ•K…¤1±›$¥‡-3(¢ ùº|±¯ÜøèøèŸðç«~õÎendstream endobj 943 0 obj 2583 endobj 947 0 obj <> stream xœí][·•^äq~Å<ö,Ü¥â\âÄH´Ø`­¬€<Äyf4Ò ÒÌXÒ$ñ¿ßsx=d‘]Ý=Ù`ØÓ®®b‘‡ç~¾ÃþñtžØéŒÿÄ¿çNžý™ëùôí§“ùôðïÛ“O˜¿å4þ9ÿpúíK;u“Ó\ËÓ——'avjød˜s§†ÍÓ ß|8ùëæû369î,ßüïÙvžÌ}¾+~éMŽ¥ùÁÅËòøþÓ#w~,LŠˆ÷‡ðçÜæ‡MP.ŠO\ÖÊÅ„–ON*U€\ý&À8~šÕû2—²*º•ðzÿcú‹&Ú…Ö»ž]ŠXP˜Dâ½Qœí‹X_F‰àZ],te#™¯ÊnöÇ-S z—°ëg*БH¼ÑDŸ}¬¼ìÞê&=;úýežbжŒvs&pÂ.?µE¸*ŒLtÈgY¬#§H¡ð%³w|8ª&3i9GýôÙùéìŒvÝ€oIÂ?ó‚Jáý¤2c¢qn{ת‰‹òüëJO a'\™¡h¯ë®ªÄaæ[èG|™Äaº©F ¿Á+l–Ù+DÛWÁsÌ!un›bäÖ÷•Òˆá¨ӄ»ù@|Ê­w]—HÄš´òŽàV Óc­çB—íµ“V¸§I=}2“€Yï¤o‚+GÞ/¦jNµ¦ô+á•#DDþ¢§ãdœ„°sõ]+¯U¯•’áSÉ’§æÇßEŒ¤]„T`‚©hÜMÒ:îÇî½·ÕÂ`Іñ¬š%3A½@dÁ+Nɪ|÷üþ7Kñßaû•œ„Pl§Ç?Ìç%¬xâN ×ú*’é6DÓKù \åY°~xCÖV˜•ð]QMçåÎqôãe±VœÃëM¥˜K‘Œt“pró²€çyª¿?󎣆·²<+Y6—Ã÷B‚ã)©\Ý ìdÁU¯Ä U”œeWT;~KãA°2.S$ÛØÏúÞ} €åœ¸*¸÷“IcòmáÁ!O&éw$Ü®twâ_åOoË×wYq}¬Xš8Ì‘ÖW­É.Ããóq®uþ€;+d×ÿ9yùŸ{0,a¨Úü¤‹5Ô²0q?ò­aËaﵩ®ÞR"¬}F`Ðô¢šB%\~±Ò ‚•Âg$ì"ZŒ°ä"Núß³<è›n_y^ÇÒ0ö¿òø]îiÔ3Ó§S¶c%úª•Ö³?+]= 1¨Šù$§á20®R 3>Ÿt{&'+Œsã?i/žøIZô3Ó§OéÛÄq¼—±bÜLRV/¸Ìô^›ƒ¬Ÿýu~ýmžÜM¾ÖN¿ýÍÙVƒ|ZÐÍ_ÿ:}›¯µÃà·eµ¿ñŸŒÙü-Ž'ÐCצ|[º´“&\UËÊBÔ•Þ-ŸÅ;Ø*¤ÿ¨Õ‘ !¾ªãÌ?Í4)w»`vQÒgÈ÷d€"ä¬ÖRt-÷ï?‰…Xf£?çÓ Ed:7=õÑ„5F€_¡ZâÃCƒ¿ÚajV‰Ò÷÷8_Ѐ—=‹šâp®†žtί÷nÛ‘èW‚' ö¶Ï‚ñÅ”ëOùyâ‘m8_øq"»+ž ϼ^ˆ®Ct.Áð%÷·ë=W¶5F޲REWÝWå¤1ï§Ï»s½kRŽi¸±ÀÛ<©1¼J>Îá£VF‚9S3C¯£—ÿ¼<3“1v®ÜÞQÔÜd˜÷ö½ Tf(¥!„¡žëº,".X×ÑU×w¶ßÆì? <';%ÕØPÂÛQ²ò.òq.¾]kxZ ô.ÂMÚÎ,¬„ßËlÍö.¨Ð‹l¶®²úþ”õò«üéuþö}¾ö&ºhZ· “Þ/O|ø÷ÿž¨½6»êwŠP·8%wmå€ãä0Ê@} 0jz"±Å VJŠGŒ-Jv•ÄIl˜Ͼö“@˜®ŸƒNŒ èçìŠùU^àÛò5òŠºE;[OÕ~m=5kE…W­›˜âD'çŸì1wdã`P‡æ¸R•ÝTcªÂ€;Ê“*.d[ÄÀ­­ªuLšÊO=^¨´bK&f˜3a`7åÌúé‰óŽ“]¹è¸.rø×šV¿§qo‹ôó2³j¿+Wq_´šfšß Ê›Ìëî SË–)ªXÎØ¥D$°¢Ð• ¿NN¤ÿÀ‚«úÝË“'?žŠPª…°§ŠI9‹£TEçN¾}~òìùŸN?¼{sòì/§ìäÙñ?ß~ÿ;øóü÷§ÿqòÝóÓÃÊïxŠXÍ÷"MóMúpžæÝY¿ÍM£¥H;Oü‰–¢X|ÕŽµÜæµ|N—Þ5îuW;+°è²ü›&”_7-H àÿôÙ´ÜRóС!›áݸ0Ð|ø÷1iˆ™\¸H'zÑX4´rç'[¹bùF ’Lzþ~ŠAXdøê‚JÄV¢³w{™m¦ábý‚oöö9˜Q(ôá»üþ»5¾°Êxž| 2‚Sn€‡2FVå¶¡®àÌ¡Éx’õpŽ~Lo=YY”|€1­²ˆ¼=d ~ÊÜ ¿¿ºà |¹~:[‘«†S©r»Î߯ÚÊù©T F´Ü®’:ÍøÆ £Þ§Yà VñhŒ#¤[l}@ˆiè‘ÿÅÅ !$§åâ’«ýÀmŒ»¸£þQqšHAå¢Ü:¬Ùàl±ÜØwÛŽwãÇUoÌbNŒÒòÃBf>d‡ sà«ÚYXó ˜iuxS!—Ú—ÅûDØÖeoÉgØß”cÞÁγ©é~Õó&(äîT{ R¦ÝRlWtÔ^¬HF%“Á€Ÿg]Uh\«P/vÙ_M•‘©9†¢¤ü8ÃV—ÇêõM% »ëŒKx Èµ.ŒöA¬R“³³^­uòâ>y 6I[jMÐùÔÙtË5¯qí½6éº놪ðª2åÇpCuð¾žbA ×^]ÐñnhÞe,#Äådþa“ãVÝ£ –òúÍd|žX¯–Ž/ZH_›µÿÜË 1¿.·RÈ›EkD2"ϺX¦´á:é}9€é!âdí®Öqt%—7Âɤ‹šVÆýœøR¥ÄB_¥ÄEêŽ`¦»Æ.º´^Y ÒÎdX‚­øý¬ê¹y?ݱþC*Ì|iÆ2ð%‚Ö^—«-ÍÛéêrk&z“›ë¥–†s$d ŽÍ÷ÇÃß²þÿ*}!fi L"\äÔÇwhÝ4X*=(‘÷ÑóDö 7.ÈÚ¶“F„ x¸¯}Ræ¶äiݯ@ÝQNófÝH*Ää©*EÙI|¬ ‘í¾Yÿ°ÜÖ$ßÌßË ¬¤6)‚¨ÊX*_½‹H-n'jè·ˆ]£ŽÞatAb2–DZ‚›½L¨t·¾’‘šÌb Ó+™ÁåDa*îß$,DŽÍ÷rhuACÏÏè&Ò¸55áù£xYØŽç…_¢$‚¾G¡‹¥‚,‹eõèÀ9AT2 ͇‚(À¡³Z._ð¾ëÀ§§ oì§±n硆jd+ÈD‡Úê±5ŒÈusÖì÷NC,¬±ÞaúìXÃ묊6`9Õ`„ÁÁ7KÚ89 _3Ìj¡÷)âÕï‚"PtÐÔG‘ÕÃy¡Û”›ÉÆr'À)É"Þw]Dòâ~Úµ•™ÕP¿Å­0Þ¯óLÍ"2½ƒºëi‘hwÖd¾)a׸rZ‚-=Œœë¸„¼F¹AÅÁ%•«4˜ÐIÏ^ƒ®y”^»ùrçÒ¨&ÜR´óÁŒÀèÌ(Dµ`*áíþ±‚”Ñ^~‹Rj§µ-vçÑêÎS6º»©ñUºmiØÀb4D'Q2¬ª"ÉVjèûR ½êŠQ^Ël:ÁGü¨é±4 H5¬$8HµæÓœÚ 8ª›¦¡àT·a;jÏ™4—=)tã,äÀ®’¡(8-ö:Úý2rè½ ¬v›Q/¢¯Gü'Ùb³Ð/ïçmO–¯{‰Û<ì6íVØÊ6't î¾áwòŽ×] R¿.Ý€M?Š®ÅÞ` ð7däµãÃ*?,H™”íe’®z”[6²’Dâ6®ó‡6ãljª£p“†§0,Hõ›}λ;|U¬áM±‘×E‡6ÙH¯+7ªßuvÝÎ!y¨¡²"ÛÌ!ò“è ðj†âÇGÊU)ìlvfû³Ð[þj¿‰á"h+må¿üCÈ ¯=¼žÝ[´µ¦>â˜d"“mÕmëM.Õm}kªéÎêXSY{l_©{ +]t¤!éQv®ãèjÙE™–OÑÙYDΕ1[ïP@*a¿1í¡ ëä†>“6óZ{„gÏóýb4Kÿì”°Þöñ?Ÿh|ÊBŠnDÝ™° s‡DmÓ’5»õ ”[ùù7”[‚9Â"j¹C;ÎVYlQO—å=Ê7´¦„}«ó^²èÄŸB,`õ@ÀÆØ©ŸÝÑËÄX¯0žÖA‘š:³êÓ0s`5yGõFˆv¯ÚuxÅñh-äæ_$3œ³J$QG˜2uŸ‰ãµ¨×>¹b›­ >HlÊu$am(º'h%bØ „“ðמ’[Ç"ÔKZat§íaP§Ê³EÞD1—Í(5ÞãˆÁ=ÌLàCÕ©~‡ôp Zl¢l2Z>%ËWPhÒm¢# ‚näw™ Râ1Bˆaó,s æ<:wkÐלò1#×=q¿©ÄÍs´ŽÒhawÿUî$4'¦¥¡´gû'좪 “-ÜCÛ9?ÙÅQ^¨<\BU%õÛºâÀú®iÇËZw£—#vø=MKlãáhZ´ÇÜÛÊO›ÇÇÐúV.:ÑÇkåz’…V®µÝC+(ûch1©¦z¡Ñ:êþÚ˜ƒí%­í>Ú”õ^u`†ÚhFކÐ.žÿX\„ÖûE;LWô¯^’_™å¶÷R`ÅŽãö==F©Õ“ê&.…Ñ-íïS¿L‰çǨ)Ø2<†ƒÚÌîÎv—½0»ÑR®H–›¼ ÎÆ»ì¿mŽ… ûYQíþ·%ìvÛ}jf±í4i‹TOñEp%}ÅlÁŒÇ_>HÇ#ËÔÎîýp1ùã}ñ0ˆîÒ8Y58”!;8Æ]þv€1ŠãÅØ ¨•N^®²y;DU'&8nÀʵ§Ø¥«;€ÅþãYœAqH6#ŵÀØ€HS¤q­¬¡Ó÷µ£Xšˆ¨Yý ‚*'î鑆-È.i-J[a¥ šôÐúаK­ƒÛÉ®€&|ri,`اÞ+aí”0küAÇ5žÏÓÅyÀ#Äyb„âk‰xäñ(‡_…ÐÁƒì§[˱ÝryÐtM¬÷¸^Ê‹º¿P8å;\À¨Žéñ/Vl?:Äfýxàê¤÷@Ï,ƒ (ظ‰›êPG"K÷GÖC®žÎÌë?«}×ôHwäúÊE_fNÐ8Ïf=ÝÉa5•…º„¬±žˆÍé¦Ä0í>½\#m½Ÿ–¶®·,§)åÚCe-êôøÞŸ‡x`âÐÿÞ„µËÌTöú½­RW÷öj´£n ì­[7 Ðì“bvÒá[Ö·B)0HÂv§éÈk= ؇¸»ö¦kìõa¥àG{—¾F¾zÂÿ£{©æ§¨„q½pz“Tߥ8Ø~ta 0ŒëõEs{n£ox©Œô°ÞЖ×V¥¹výÄ‚ßmÓø0(Ü…þW¬îªHÅêþl±º|_±ºS|Åê~¬.qÏ« Ãù¿O€Õ¥3(¬.ó+V÷—…ÕýŠ«úŠ«"®õW\Õ¿=®Š&â~à*U¦|8¸ÊšØðUŸUX~ƒásƒûÁO×KHÓ´ÄAƒh}žûq1KÀf®YÐ# °4óè«§XV뫹?Ë$öÿ™c°Â©ÈõÀ{V¼õh–WX²GV!X±ÝaŒûš™ëV«?hmmƒfJí*À_$ö?Â:9ÌΡ/\pÿsKÑ<.¥ ü^­_„ß+óÇÙŽ3|D@–oj±}Ln]æÿ›Xÿxß>4«ß+s]¹^…mür¹¯/vpbBa„#Ä…N<…qÿƒ£fÝëàDж…7uÔÙ½ÏM Ç. Ò½’«†ö8úT忤{Ç&V™}0N!Ç)©<91Ö¦@€÷££–jNCÄ9*·êÂvUS<•I„Ρ_Þ¦ZNb} )6 Ê•Z-ñçϰmÒî…Žòý‰zŒ×H]£ObäB-º»ªÑü–u÷hÚQžsˆ»—9÷Ìò€XUÔÇ{`cÚª:1„Ôvbª ­vÊ.DªQ$è8š¾‰:D¨òQU{É ç<î;°æ,ãÝR?fX f—žKîÛù8rÃ8ÕT%†¸©ðϼ_€OáQy×Ó‡ˆY Hø|EˆÁ·Ü{jò”]U+ñ9ƒ'ÿÅ=r7endstream endobj 948 0 obj 5985 endobj 954 0 obj <> stream xœí][7vò8¿¢ßÒm¸KÅ;¹Hĉ’UMì~X¤]°ÍHÅ6‚ü÷œÃë!‹¬îžÛî&†aO™UÅ:$Ïå;²?næ‰mfü'þ}uyöä·\Ï›7ŸÏæÍ?Á¿oÎ>ž1ÿÈ&þyu¹ù湌mÜä4×róüõYèš4´Í|cØ<Ípçòì÷Ûßìö|b–vûe·W“µÖlßïfxR)ζ7þRr§·ïJëuxÔ9AŸ½€¾Ü<ah·Ïv{9á"6rÇõöén7' o½ØíÙ¤µb:~Œ|×_’^•Ë·™ÚKü€ãJ ¤ ÝÿÄlØöóNLJÏÚlŸ”Æóüdü’¶ù¾–’q ü[п`nšÛ^åÂGc*O†”i¶êÄ¡˜Â?ìôÄ ötQop†`ñ5Ooaë§0™Lù±Š™OÆ:òB`i¼(_%«Ueùèùî?žÿó—fRÊÿã`Ý$@B±­nõ´¾_êÖúQÔ&bž,í-µ ÑЕ¥QCÅ_‚ÈdÁ¿ØÑÖ¸íO=ÅJ^_NÛXÆ‘‰„œŒ®&£èÓr5!;9ig:P·gp_8ˆ|2h›X&2-7v2À(‹Q4,ó)³oŸo*cGEÁÌ“5œÊJŸ×_bPljˆ¨ÖðH•ä°|ÿµFäsM yéýBl^ŽØ§€*Õ2·0jnÙÄ­%âqÑ‹.Ëõ¹ÖL~†œ"’àeFY>Råo,XtÁé*c“àÆ§¾­ ã÷,-4ÜI]ÆO,EkZ†,äa‡O~«a¤CTl ÍÁLm4Œ€¨õ ¦4^H‹K›.âöúôùÙwg7"`:˜ÝËjXìMï üæÙÙ“g¿ÙÜ|úrqöäû ;{òküÏ7ßþ=üyö›¿8{úlóÝ"®n5¢CBøy¢òE&ü¦n „§œ5ôEzD!A ¸ÙþûŽŽÔLRÞŠK«Þв8Q(e¶ªÛÊK« çæÊ+ÝàV¯ åÙ5®ñ·QQÂZûELQ«P?^+óàU˜ÝÄe1ÝADa`’ê ¥ EÁ|WÐûûÆ0*È4ΞA—zÿàù¿œ=ÿê÷Ñ–+§¨%SkC¢–ŠýÃÉ”|R–Q ñ½˜«Ø¸ýÙ»h®µ¥„‘hû—žÑœå¨X*„3ñ5vä䫱²A Àr¡—E¦É¿ôeñ’0d‚¸´EdОfÁfÙÂG4š²õG|«ZÑ–qeNà÷E™.ÌAæ°)ëR2}o†94»%Èl>_Æü&ALE_"¶îCG/e}ƒkŠø ~XÝŸÊ“¯*…“<„f¦=Û›1$“ªW0ЂHfàËò-áNqWŽa OlkO¹ÔÞij›°¬”Íëy+6Ž„¨2Ð…¹•€å Œ©ÌÂ? ÔBs.¬ ɵz[3z)4¢9:-ÁH}ñ¦MA?á ^˜g60pß6ˆ0Ò<3`dh¤„žg³|‘…ÉNmWùê<ß½Hm£I&g<Ê€Ê~p@× öÀ«·t]†½@ûNÒ†/ô=…ÆËë™;oƒ /é“Är­‰Ôk ¨^ÈAR!+¶«v¨|TJÛÆ¡J±ª›ž"ðùÃb½xÛ¢>"þÓ!ÂS;‚ðjd Šƒ÷r6´]Òý¿ÛíòϳÕ4lEìàO=;vÓ¥u_0WÝ­·oJ fÉÂ‘Õø)ú%’÷Ý¥¾;oˆíy;8qzÐëu îÜ”hÕÛ¸\µ)V…˜’k¤é¬‘Œ}¬zUzXŒ¦t®„­üâ‰Îâù'ê¹í¬Î¡å –+.X¶]þkÚ_(!Z|Í·þ°Í®?}^ÿ°ƒ‘‚N˜½½ø™Wåæ!¢b¢ÒPÝ8GÇaÊDÒ†`ëZpãCa'"^Ç¡BÓ›. Æ@ZdÿíÇÜ.Z¦ä•¨³ƒd£:Ö™E=ɹÊw‰ãYqÒŒó¡Û¿Ã9˜Ly«ù¡ÚÕc¶ϳDq%WÃÌy«©Š FŸ>¶dNˆ–JëïÊ`o©&ÆZ¥@«šÜŽdÁþ6Ãß#âù-vzæeÎδ(¶ˆô5ˆí-¼…Ä1\¸è±ŒÙΑßG–µŠ1r5¡U:ˆHQ÷lÖ˜ÃHê“?`²…£Û„æSð½9[îóHc-ãÄÏ"ãpÀˆÌ ’Rý¬!æm¥”uf#¨í%chVdfÀ¬±pÉé$ÒNzXäðü%áÙw]¦¯]E=ó M/ÚñάçOM×ä¯I´Wñ°f{î§… ¿t‹^ÚÀ:A«sºTÔö"òœzþÉFÌÞDÌÃIÀŸzénj€Lo?5@¢ùý<»wƒL[YKØ»‘5v» ¥BÀbCÝŸTœP¾F ôÄJÞ°Q1C­9†Æ—‘(QéæÔÞue#/žìgÐ3GÉAqigÈŠâåÚ¼¬h Œ™[t•½¤V‹çÃçƒÅ#³Ð1¸jµn+>F¹êƳƒ|‡EÊ&¼oõˆ qÃ’ ¥¶?kß×qoC´ËÎTˆÉ£ºAÓ€601.fy8LÞ‚Ý~ÓEí‹J‰šÖ>òhPDuÉã@ÐJH@Û(ÕÄ´AÂá/»F¡¤¼÷⑟YeQ¼«~vìØ!÷A~ð îÙöP¦D˜ï6ñöß÷G4ÜÇ~0VèTJßsݳ½’­ïÈœ˜$ã,Dú¤â|u î™y‚ i’ Ìj¯ GEN~ä‚ߺȉú0l¥È)Mí9QÏNŒo¿ÏìWìʨÆ)AËû­qJ“Ò%ÿ„TÒ1%NÌÈIÍ 5À–þ%N¾_Ñ–8yv2+ÞgXî…c$I4Jªc¢†Aª%øÍÚÁ[& <Ǧ‚§ÅC-ž Ð6ój+W2ˆ)fëªÃ[ÿê˜îf¤š:¥˜‰¼‰¥$æiYJ2.X /ìsŽ}½^É×›ŽB‡§†Ñ'˜]‡c–…©¢´“ ñðæöµIøÀ°6)–ñŒª“à6YäCïîÄê¤øÒ0g'ópuR\pN†}šrlò>‹“àäF¡zÅI˜d·Ð›â_œä“…„ð{(N’úÜ%zZ}5¬NB÷—öÕI1…tTuR,?¿CuR¬7W'}Àì§W'™®¥:ÉÃ÷_ª“~©Nú¥:éÿuuÅê†%J¦|z‰|)ïÞºÌ%J¥Pæ2ÛÁRô‚”Ñì5°Ìèö¯óíwùö‡N•ÍßžTe#…¯T>ºÊsRÙm»U½Œß@0€¿KpØ8 ý´I7Ì—R«ÊÑj†›‘îÒý¹k¨TÔ½>D‡vh­â=z4„n¢Þˆú视ˆœ§ô9s´‡¾ýÿÒ¨2ª¿T›Ùó–TbþUÿ![犦&8ãgêr­[ŒqZ/zëÅÕ|ä¸/uÀµï%½Qnᆅ<~é5[Áp0ó³3ƒ¸Çí3ôU¸Ä/W†{/‹&á­Ô¨‹€Ê†¿—:š¸¶$8ò±ék_¢Œ–yÚ€}7‹ulæ íKOLê¹öê MX­)QUîtâq…á¾Rv±ñÊWÙåî=ÏY¤õ)FFSÖ[âŽÈ†@ øºŽ¢Þ>%xâF>%'=Ë:–€Û0P Ö ïPŠv\[=÷Íô¢$ì`*YTS„0°>1ÒåW¼iG!Œæ)}lmL •y¬ªžId½¬_CÞ Îf¼åp.U"¡_DK]°f¨tV1€9Užuo’‚S`6£«5jpȘSåì‚yN• cŽkœzG"EðVc,À뺧Fî†éÁáBèÚh‰P,r]~/KRïÖSËlk¨b5\žcC1Œ=ŒpT­;E8b`ñ”‡´ŸÉ…× „à{vš•T^5=Æ`D~h0·Ž£øÝôUïÔ&ÎØs«BµMpÔµéé¬#jÓÇtISš¶ïó{/M÷GHq«¢×z—>·~¿ò(S%ñ`Pá€Ùžq÷=U^ÕZ^ÖÆ³Úøq}ŒÁ¨ïùLÂç`‰ôá“Èî\§œkaZË;Z˜b>:ePžN“Ö€¾ÀÔŒSüU"Ým0K/«a#külÊí†,/’MŠŸ~‹4·h4ìIí äÓä$ÍŠÿœN2[« ˆGŽõ«¦Iß’ZN~ÊIåd*IõOßï®Â_íÀOvùhLÀ·˜ùcNêÇR}7*”©ËŸ7`xìÙ¯Ivµ{r‘w4ƒÀR´ÛîÉ‚ùcš³¿¨º"îDéjÏ’¸Å7k'è•ù« B<©ÒRÆM¢‘kvònrøX'…ãÐï£"@Kïל¶qÄÝ« &•‰«ýPü&åqe1Ñ)ÃíšXñ#Þ4~ûÍHmFЬüœ_ùqÜ(ªß4!¢›Ï¨äª‚ë)µ¸8‘Þ Æû"ð¤À0Ÿo«ÔØÊy†¹òOø^e¬»Nç㸢õ!e´ìñºètOêÖ_ $uY¦P¬p;óeç²ñËCÍ W+iÁmL?A@ëç‡ûˆq³VMÞ² hX°—*üû»åIë2ž§7%éK!g'Ìxì>ë£O1ñGÚ‰“2²ÕfƒGPþ°àGV_ñ±@Ñœ‰A´«÷Ó‹Íi~–§,t¶ÑǪóCû[Æ{:„õ¿ÈÓò­#÷tPºE¶}¥*°WÞe‡è˜¥‡¹Rì˜v˜u5~§Žµ:è-LLUHá·‚ŸÜnØO1“å!›$øú®OoUXàH #?SiḠ‘*ïå C"0øGüBÑb_ÅJ¸ŸuÒYs«²–Ûõ¸ J /Ež–N7Yˆ¤Ý/]­“øS\‰o»DR •ýÒÏd‘VÞzÔηò°¼{•Û^5o`dçsnûܼw´ 'è]wn—¶_Å=„ p?ü@iF6‚êJRáSn»ÉWŸcgvûß04 p3˯°üý9>høöÊ“ Éø Ôn,*´Ìò[—Ê óöÈBƒÈ·KÛœ¯ ¡°ÜÝkà xk1C‘¶Í:âkÿ™ÛÎÊOHÓÄ^FwÛsÔñ.H¨Ö 캭eæ÷¢Ï¶c@ê_fúÚ¶µã¨)hÇwÛàRÇèîu¾Kσãp>.ŒÔ«ƒgÒ"”a¼k¦¥L=^}è,Âú4?ì -xó³[°cÅ„^­¢D U!Ò?_•ò§'΂<€¬€ e…÷?7sˆW/sïï;š)[¤Îh 7x˜§sѸ•’ò¹‚>¢üÝÙÿÔrŽendstream endobj 955 0 obj 5381 endobj 961 0 obj <> stream xœÕ=ÛnÇ• ?ò+ø8³ð´ºîUAÀŽ G‹ `í ȃEJ‚%’¦HgEþ=çÔõTuUÏ )чƒî꺜ûµôËé<±Óÿÿž8yö?\ϧo>žÌ§ßÁoN~9a~Èiüsþáôë—8ÌÈS79͵<}yy&`§†Ÿ6O3<üpòÃæ›ínžÌÂ×ÊLœ¡ÂôOá´JYÎÓD‚Œ„sŸ•§7þ#ǼªJß…+fÃ(ˆâ®µ°t‚»îØë2íU½-=å f°ìw3Vã\^€LÝj8²`šž±!õdœÃ p­ñyÌV6xW¶’†º^m‘‚Ï æ ] Ô.·ÌM–q› Í”¨(óÂú]V395hÐŒúˆE_5x'ÌŠÃ@Æ  üãf÷Ó›Y‚H_“²Nû¹+ L5æP6«w&¬R›ÿ+ïÉYn ‡žµ‹ç¸À!ÇòT7¾x»ÄeŸˆpäõ)m‹œ÷5ÃÏHp5Ïž¼«mPLÜŽ×K–=Bßs1OŠUè½ šÃiI¾)Ÿ¹rÛ³ ¯‘g‰Þékñ‹®€øm J¨ÆK#>9©”7²uÌ9ލ1|d~³Âœó¾Ûaòk P.‰<ß¶²¸È`ðs •µ}j¹«>JO‹íuOçßq ˜’ ¥‹ B]_,6²oòùüä¾2ŠÚw@eÒ³`;Û7§¬±Ô2»;€<ÄÌØo]AHÍ2â"ˆb‰ã’(FÓÎ?z5¯µÀ*ü 6¢0UžåOÊ@bÓT:L9Í`cöXŠ6ú3Í̪b‰»žÎDœ€zÕÒmþBÎ|í«ˆþQÀ á¹d_Y6 ÖQ‰ø¾OKZRXpuïDÃUpÛµ k­à9c¶D³õ÷¸ä7xd¾d¿Ë2¿ï­½."DoºOû†^íaùBßLnÖÑæ×žºË’ܛ׺ož¹¿±ÿú_ueÚoÉ¢¼ æ9szh“¥ý•õkòK¨õä)¬Öæ§‚¦Ëi%–ì”àcåÏßyÛõÌ΢D—I¢|+á¤?nZõçáWyŠnžRž%ˆ¿I”b9Åe M.úÇî[Âo{¢tÉf…F#×{µI­µlÖçSÂ|H¯â²ãG{|ŠÁ¼e DôV±ûÿ ÝH£äfxW3€•Å2À«÷Åy²ÄÓFí.®™R¥§ÒÍŽ ‘·™¯#­H¡–¦œ£ØúßœÇè`F»ŽpÅ çÛŠ¼‰Qa½ˆb•éñûn¦Ó;{)¶&:l±ñZqÊíFßq@¸6¬€iÂIò-¹ã«U[¨8ʼÍ~¸©qɈ#t¸pá£àBNN×ů,2pq9S•‡û‡<—ä€õÌô)¨ƒIjcÅ]«åÖZ‰‡ÓðèU€2Rº­ó Õu¶TmÀÛDh¼W½Â`‡RV \fˆïÛÖßþ±“ïnK:êdñŸ¶; li¹Üü_ÿ±SHÒNS§Òÿ³â›¿ÇùÚ®ñÙ”‡¥G«0áȨ:Vf£.Óî˜4ÁôV]TñHc)7~Ö‹5 ÎÙ ¾óôèxZ32Z³úŒ´€…e¦!tGs³èÈ[…W Œ€¬µ}2 ›¹ç¥9côùi#g ÎâÚaŒ‰Ã|¤¢¢ÓÏ$‚‘XÜ\CªIŒp¤(µ’Ýav’°IRãˆ<]ļÅsC¨`쓨-ŒôCÑÃGI;¾’ÇÁíꥶ«³ÃBàÖ*&~ݧÄHôïK0|¯þQ#à˜ÇŠ‘´Õö¡¡ÒâüU¶Ãº \»T“vu$ýp²B8nõøú©f Bçý¼øÖ\ïnk6 ÕôIn‘÷¶¦l J¬”÷ﻸðM 1C–!ýÃÌn Ìw뺩ÄcÚ›Š| «ÀG´À#ûRDÆN ÃuœC<&Îáp>…_¢…z*¿„lù3ú%Oq è—ì9ÐÃý’Œel‚ᬃ"þVMضšÃK²#¥ð|ݨUÈ»y¹8»v3¾6VïM+c5ýš}›Ð>nÌ$ˆÒPZ1ÖiFz6*ý÷'®É€ë$$­Ó«ÊtsÁð°wcQæ;ª­I5Íšû=ñA I‹e0)–´¢bs¥êÚÜ7DГ ñµ˜X,o ø¬Ò¾Ÿî¡A%Rÿ2Ž[!ÈsãH[Œ×Ý®®² 08®Z=±¾GE0?¹Œ…DfÛp-w 9¾Ý†Â¥IôÕF üYqiM®5j$þL †@¾}Á“’€_}{žÅ +uO‰Ì+x#)ÿvû•Þ,€Ú” ¶î+õT›i’¹êDz’ûë' ª2—ÊEïaJDߢÁAi£Ž„K.õ -–†”â’ê×½'Ùcªåt•]ÊÊвèËfÌJ7Rª+}8¡ hF®ÅÃËiÞºŠ5Us3rÑG\'éb² 6HšeÅëïÇJ¢ð´cn`ÐY-—T‡ ã~ùU]‚z;õü=±=q «<Š`嫿S'ã~uÖ }U‘M#ëRñ°}öPÅë{ Y§¯¡õª­%ì€t]Ó™Œ`²Y³¥ð§„ˆO¿ ÒD±¦,¶çÎõ› Ã.ÎsÖ¨è à '`²Ñܡ۱ªí%3¼ïšˆdáw]VéêÊLꨯÆÛu¿æN ràQ7¢$êÝ€’¬{¯‹Û5L¥’*BŒ2 kcë:a0çøÓTF5NÆ v.%)>{!¾âûz •¾MàyW4e”®˜©(¬ýÄŒé=ÍÆôç—fÌÈìqÃèÐ*µMz瑇½cYx“‹¥ÛÙöeØ cviæä^b$€R@2¡¤LÓŸïKRô]—"¶ñF’eî8V•xHMW[UeŸF´ [Ï`¬HÏÕL€ªêèáq?s.§ m¤Ií÷¨—îëW2­d ÅEÀfƒfÝZ¾ )ƒ‘¥²24]AŒ)Ù–n¡‘ ¦Ð›O_õ.ÕÇmͤ¾uЖìÈR§ß=YãUW“ÔË¥Ø;ÓbX[AÎéùì™Mé}qÇO,}ã¿vFÁEN½(¤[¶Ä’˜â.žÂªÔ}@$­>ihÊב-’àNÓàapˆw *šÙßÁö°yVvÈå5x1o+“ëTE§©—ã/1D†Õ䜣èãÆ¡XBwÓ‘ßàM vVq¯ ªÔÐir‰:©³œð›¿m%(G'Å’qš{‚ŽklßW ,;-êMªªßtÞÅ𻢯‹ª¼*2´S]»·ý޵«v¹wËçZdAôÐvi'¶· =Øm®¢I³µsÚç cîÊJyAÛ±±þÍ…æV¯Í½žò[´È¦žäv"›menkZ.en=ô"ʦY=TÊT*[^ø¸S1IýÓ)»Ž Û¢ü8´üŠÚ̆{Gwi‡ô4¤ÖS5"Úc <&+È€>Ÿ•~S1Š•¯”ƲNÌ¥ËJÑo&ŠØi;êMH.i}}û¼K5Û‚óæº‘þ=ßþtÈm_9,  ¨óxéWM)תÞ>ß[®£g¬Ù`ØIœº”;ïÛJ‘QuŽe¸œ ï’ý¼Õ9V¢ Ïõ,gMò1?ÚWÆ&BØ}š/gqèd¨ØŠ¯™¤´…¨eÒ£–ÇÉ5ªû”—§©Yr*‰ûm™:*L †µ„eEß°ßqñ ¦þ8§Ò¾ß ÒD›0BáH¿òòr•¥©=o­¿o^ “"$2ѽµ“ÜzÕ˜>ØËîXßW^¦ŒkͼWI÷/„ÉE§îi){CÑìöæŒÉ]œ]S¸èÓû.e$…n5½™äA ›C®3ð½Q¬õÑc{ÙÀ'6.bWQL)Ißš²L)Iª¥}SšÐ‡xþš 1÷É¿Yu5t›nH9ÂhÛ™|MTc²Çû4;ü`+KÿšRK`#GHD-1´rIËE=Y–q”,n^ñxË"E‘’Úùô€·–õT«]AcÀBßëŒë˜a [Ónè£i¬¿ƒÂ;͵©Ž™+G›Ë{*=:ujäž‚}4O}r¼Æ@ ï‡L5vx3Ö§e÷ÀãØö”Û=ëû“âu»×Fyø¸6ʉb¹Š¬µE÷B®Dy¶*Â]11Þ“t‹JÈ1õbWèßi{\åSeÛ"i"C1€Âè–šä±±c‹ð#Ao¹:¦µk(ÕbeØò‘Y¾÷&ÝòRRhÐõý.#Áa?Á\%Çñí°Å–á]ërt‹×¨º5Zä£ÅŬ ·_WÜæ%½é^ÖJ`NôKiOö$`V[¨êȶ4KB4nV îiHEƒšÆ5c;”4ЇWûµBédâ*KJq‡¥ÆÕ‰É¦>7ÔÍÉF§§+•Æþç¢Ô8È!ØŒ|x\Q[)+ÀêSB‘æ¾r†Î-§+ ÓüO4WÊ’2c¿Øæ(xÕ\‚U§‰4‹€ ›ÁW. ʆ̋“Ë+hYendstream endobj 962 0 obj 5652 endobj 967 0 obj <> stream xœí]YGr6ü8¿bÞÜ-hŠ•w¦alÙ+Ãk¬Ööa×Ã[Xr8¤H‹ú÷ŽÈ£2òê®îénËÀ`¡e£¦*+32îø2êÃõ<±ëÿÿ}þîêɹž¯_ÿ|5_ÿü÷úêÃó·\Çž¿»þö©¿]»Éi®åõÓWWa¸¤áÚ̯ ›§þòîêÏ›¶7ó¤ÓBmþ°½VLŠ«Í‹íš¬uNl^noؤµbzó<üpõ}¾ÜûÓv†W(ÅÙæ._} ãj3q.éc¯àª1“–fóûí Ÿ„˜¥Ý|¿½‘,SÄ‹Üq½ù'f'#åæ6ÏæS~Yø)fÃÒ 8G2Ý7þ½Ž1µy‡op\éeixCœ®5t¬Ÿ·@ =k³™¶7†‰I3»y “™¸JÑQ_âjÔ4+¶ùŸ-³Ÿa d.o󨟗WáCÖL³³‰0pq¡‹ÛÌðÓ1 Œ%S‰“Öp‘Pàg¼UL0º€7õ«[öËC5[ëWõbûßOÿýŠ[>1,ôôpL³ÇþÎvË¥x>3ól5ó|æ,GÑÁÂd ã¶œ ¥vzìE|1>rŒÊ6Rn¶‰¹`Ç< ÓPik**’Ÿ· mðç.>òó%«(vwO0Žä¼‰ô¼ÿF®0V½-¤Ò“Ãj* ™Á>f» Šƒ)±a‰ˆoHW‰°ga" ·>J›e0‡K[ºµ1/‚ÊL2Iࡲuz£e{â±ùžb|’ÖÒ7Ü4 {+è ÷ù†øSÃ"<ÏšYrN J¶·Q»É2GG(Y5Ò)®ß…;oœ ›±Ë QJû‰?3¯´öÿ~ו'X«{òÊ$a“éwø›Ò®saá©D?ìÇå1òÚ{*ZIÞךÙ3n-Oʳd‘‡`(ÎÙ4›A$#‘·~Â2˜µÛüBú§ü\©h¸Ô“M”§@n}ƒÙ ( ÂÆHú÷Ÿñª›€ýQºZ½(²$EdaŸè¼ìJ9Ù$»8Î'ÃÌæ/›®Æyµõ|Æa)âÉIÞõ,_}Ûp¸X|3Ã_¶q€Ñ(Aßt9ÿ.’ÉêVŸ§{¹ä°í|`˜÷ñ¡#á 4s „SQ'O½íi‘ÉI¥LYOü¦‚ëë÷€ˆIöÅÞÖÂ+¹ÓômDtJZ ®qˆU^¬œbúÌJcäÄ>)ä¡´¶•¦‡«‚帣R‚æXЉijxîŠÝ¨h'ФµȘÝ‚³aÐ]~IEˆ „š2yiÃý ¸"/ ¼ï‰iã2¥µ´·F4]¬-0”#1k·ùÓV‚irR´ŽMòV< r»ÆHI,W_å•RÆ„5ëI°ÀdÖol˜¾¾óS¶ï³ÅÄ6±¹N4“RM¦°ÙŸ ýžôà]W ÑfÎk¢ r™±Š »m*—¬PIF÷›µ8Ó}º7r-dÔ@ÚÊ5" †Ù˺ÇŠ4Ç^:Þ‰‘+sö¾f/|W²‘NÒÉÖ”Xfÿ³Õ å­hGhÅY«3 #. lªdµqÄ"î —&– 9],;ëÇü+š&ˆOÓ„ó(SL/H“¼éĞܨÓÊà‚ºÙÑúŒ†`sl]­f7i#‚¬HÞË{àP}sMnx6b \®0T'–q߬&ˆ±úÛ×F¾Õ¦ö´TN° ðG8<û¹cß%>4 #1?öU}CÅɲï#ÿª Ö*½æ¾<;|ôÉ•–458ƒK³ƒBϨHÁï™xL¾{g!ª„¡ñ‡´¸‰ñÒËø‡ýîéÕW®EÈBÞ Çá1·3Ól1}ùí÷WO¾ÿýõ§Ÿ_^=ùÓ5»zò;ü¿oÿðÏðÏ÷ÿrý7Wß}ýÃ0©¹cæÄ3‘¦y»ÌüSy)Ì|˜+•³ŒÓ_Æñ•#µù¯d‚({½ >î®È<‘ýQ =:Wy¾ª¢`JN•1±´¥ãDR¶%.@Ã#‡ù¾êª~ŒÛœ}Ê©Â/oHe:xÝ\·W¡rôýg%©6jm¤X2ÉÞ¯Ý|å¤L”Âóõ¢AÿãêéW^Ò ‡w)Þ*Ì.Ñ?EbÕG4–Uij.ÀKá¢cõª` Oòaààͱ¶tbäÅÙAý[ÏmÎr›fJ|9`5T:ÞÀ‚ƒxPfÚ?$ !P›#©<²h?gÁfYùÞTJYyâþ*¨º} È4)ù8^$9À®©~õ'Ëñ8!D_Î &aŽÁœÝÀ)¨öɯùur!‹ŒI“Ѫ§¬µ1÷úS`€Í`è`w¿4i˜¨u’§_Q:¦Æá»'ª \Áœ)Âì&ß[<%Ü!aǶð“­íªÏ@¸:ÑÓÑb>Òç»” ¦ Žª€‘0ì aŽÐ2vÆæ > ³…K̹0e•§\ª·]Æ/õÀ-Ø4XªgÞÂ)%£á†Ç¢ùCCørùu·üõyº60猃öÞâð5ç4ç 8Ì• zQM¾˜2ìIúõbùëË} ÒÌàðYV{Ws_ù)øëMúëNOea­'ÅÃúADéÀûPIéØ;D:ôFbÝvyiÐ8@g*²¨,eûV…Z1Ë[†Z!UYxÝÙ–Wû.ßJ+' k ³H¬ñdè2yM%Ë`]r¦ù¨JÙNíúÒ`ߺ¥k¢sóôŠìl°X‘‘ø—9ëKÛ;+Dxó‚O Ôh—@“~ée ÑûùU2‹pƒ3©ô|ÊÙ¬7ÉÇpÔpekELTrG¸£¬û>– ¼AíØ^rk[¨êaĆìÍ¢7ŽÙ|¿È°ûJ²”ÙÛXúØO) s:wF{˜ÿš0¢–ÓlÄ—$›ô| .Ã>Î"÷ºëõJtJ?Áö.¨ wYÂîè´…5õF/3 Q¥Z.ŠÞÅ)ˆ¿ˆþ‰Ò¿Ôíqô) ÐI V ‰ÒtHòxIåqJª¨©_^3 îûi¤xE$UU1Û0Gåö:°]ý¤<ìÖâÖþ¦E2EæBËIÌbG.Ó‹ä¡)88ZVP),•‚ðnf_‡[•âF@ä=oøWùe_ÀÈ…ºtwU£ùµ…÷hÚQ”—Øv•9÷ÌR$ÌÉKÀÕ¡*^ø¥ÛX^ÜC­¨‚ #< üCM’‚C>El*A ñ˜98F>fE:`¯¨7˜¿eÞŠÛ™5Y]"8·…FOz®9(b;RÒêfÑɦ¸>ô#Kp£ñÎU)RêOŸø¹\UÚä„ޣ雨C$+ºhœjO °˜ÙçáÕUS k^½[íǼ ¦b¶õ\R5+eãÈ ”ª*L ‘TÞ^•ÿ’é=åó».-‹‰ ÈRs›ÏŒI•«5xð]ei‰³xTm¨ð X×WýŠÓB Øõ£ñ óìåuŒ‰µ³âA jF‘$Pt+!³™æ¢Ìp@H¤ÊE!¾H´lüRÿå0†(øõ@HH*>UH°1$7ܱ#âå°‹H‘G¤ÈqH‘F'Ç(g÷áGŒõeЕ¾W ãè»|•( ïnø*L NŦÊ;Q­„)ANbJCD · ¢{ND RÈ©%ˆ;j£ÑÝØ(ñ,-¬š8šBKzÞÓƒ!%ÌÔµ´‘%‡”p‡Î›´½ŸR¢1íBg~H „ÚÅèIHn†ˆÜ] aÞ%ÀtnVë%^GÕ‡C%^ ¨ˆ/eêD‰C$N'?"J%ˆ’GDÉ#¢¤(Ñyʇ#J"rÓ[ªÏ ¢ä3%ô€³3gñiuv`02\¤=RD2‰Ú‹,Hz$ë¾=,"ÁŒ²À"íÍÜa|BùâÐÿ¡hŸ"h£`êA®A‹„S'¶ ¬RÎjZ¤ZÂáh\€1e !zÄå-*pâ|\ò'³`þ?’C1y ˆüÒ³cŸºs½ÉŽW9l(+Ið†ÄÙ/Û±üðƒÎEÔãqôƒQ‡È¿]¥!?JÖHä¬!ˆ“5} BÂsGúÊožèl^}(òKwwöm_,*… +½åə໮¤“Œ@::‹â9úÛŸ(Å£ªl”‰:4™3gH‘­ëñ!çy’àጱ$X>+á“êXÍ&)Ø:,‰F@Õ ŸDhÀ$ñ*“yw“X~ìE•øæ,r澎jOÇ? ²¿€' R„EÞgYÛ &Á‚¿å(˜Dctiw¸¶Ã©Øþ˜—{ê#Ð$ÁrwcñCßg§›> ~U¯j 80µÝÝCç¼À(>LRú³ÔZØC2¢0Ò‘.Ì÷ ÁS¦jdn ÏB`1~ŒÓL‡OkëzNÆ2ÿŠá„0Þ¡hÔZŒâ¼ø‚.r½jÅÆ` Yâ"T¤™Î7U?¡hæüb=B‚ß§Xm²›fw!ĈRà@;KId4’|Ò;C…iØD'àHv7Ñ!æ2+¼Òê¡Ëzh‘hZç¨ByƒÁÁ„ªð"Ž#wFØE'±ìPàëÄÎeråׯoŒÏ#­’ Œ±™× ìG0³˜dLbzÂne˜ÀÓ ':~Æ‚ü@°"As|¿‹VtÒy ûá9Õ^Xe$„— ¯b' r§³“Eƒ°K%Ìú>ÛàCûè ¾bº(o*ë6:‹B> 9Ð)d¨<©¥Ž ]_¢;Ð×{u?rkn£c¶—l£ÓKî;ÚçxŒ—ØÈ³´ÏiÖjmàW'µÇg?N¬â0ý;è oÑBüDÞö´GÝA'¬â¬)fQei2z…%\ã°>)_íL0°•@ªÁ¬²Žûåø•? _3Χ¹‡ø¨DÚ3á£hrMŽDPTª‰d„âN±¾/q4<*¥;ýªOkÐQÌÈIÍ ’af³AGùqEŽòìdv £Âv›Ú ’$Z]LŠ?«ûmÁiØæÅï%…ÒýÝè~3ríJW‰h¯ÛXŸâv0™5X¨xèÿ-êa6ª°§A5p<©ÚÚÅU 'ÿì¯eîÇ<=öÌ¡ŽècÏœóôÌÁô‰Ò'ë™#€!°„zž9tæ§ê™CÇ|ì™sDÏœxƒGpÓ#¸éÜônz7™<åÃÁMXTÓbón7eˆÍ»ÅfôÐ-àÜhàÌLÿÃòçÜk箃Ïù§ƒð9\Š%¼ŸÃ¬ó)¯ã¡6!²ä÷·u« ¡_Ri’Á„@pk&€ ʧül€jÙÓýµk¥‹_1W ¿#€büPLÐ$ßB¼Œ_S.a\ÖLÄXUä`èA9Û¤¸+—†ê¹~Œü¼«Š³¢Ì¿J÷‰ïå®ðuÈô1Â{—CD,]9öæ#éA6äT~]$QžeÍ6r½ÒEÅU.Éù“€qâæ’dɇ|+±ý¢ew,âpt $]ÍÑOîLÝãÎ<¡cé‰IlCc<¸&j0jª&éd âÃß•²MuÂCRW¶RÒà^–‡ìV•C*‡-x4Ð÷î¨`y¬ß I|¨mZ.ù?'IrzQ—.Y6ß1X®‡_TÄ!Þû OðXÕ þKnf¶Í%„¡Aâï!v@Kç‚Ðàç%Ñ ïBøh´Šùdí›å¢Ž1ÈÏANÂÒ§ ‚žJlkÎcÍËE"Àß‚C§8‚¢Kß#êUjÄ•úó@—-tÏUƒ»®÷ëØàþ¾ª ^1žY¢Q„Â?ðÓ¸Q@WX/Ý qŠf軤œ’…€(3zeÛÕÙÛÁ‡kÞÆF\þ DTâxª_ÏþÌôéYâY5x[¶ @¹]gëãçÖ`$`g@4ßÔëìÆ‘O‰2ZmOìG ¦Pq>˜b¡ŒÓg1Vùž¶à>+Ö[Äa;Ö0<²GÀm«K°spJªñëvi_óš*®¦n•žÜ“Ò×kÛk°Ûá§Ôíí9¥{l,zÀ¹Magö“‡Â‡c/ºáÁnLHöeµ]Ù,z×QêeØ`x»ÜJrÞù¢Í30;› žágQ6øO¢Û÷úçû‰(GPĸÂyeP9~–0qr>çuWºX ‹wâL寯Uû¼‹öøÉ]¿%p¯Ó ¶ûiÃDà¦-40ÔcãÚa³þ½÷­õóÒÒÆ-%Øn¥[¸+¹<6vìçl‰X¿¸[¸[ ûâEÒué"7 ßßv­Áû°óÆ–ƒtœì1|Õ·*5AÑü‘>À,ϱg‹@mÕn*òý—”ØyWäÞû˜R“ª·½ÂýU©BíÌ|ó8uƤû²®Ì(\#<I×ò\㾤+9¨9Ì òÙâi ú*߯„£gžÓŒ_eò …-$H+”>³Ò‹0#WÚb‚ÏR™U/Ë–»KÅÜh(F9û¡Tüâd9ßeA;o˜?éÔWÇeo6cÆ‹¬E0ɶk1÷éÒRÿ~³Š÷Ð}¶åè_WuS“(‚ÅßÓë?ï9£,~§æB$Äòœüî÷¥xÛR˜ÈÌ[ú5€æ[òÇ’7Sûæq¿›‚ÃW{ J¡v‘Ï˜È ÌK/ìGÄH .Æ…øZjß]h÷Zî—µTªa'8=IÉŠÑ» }\¡fd)Ö7?µ|ºÌü®ÜŽ!ÉÁÍÅÃ!¹’3vf?ÿ(Ã.fZÀ7­µo1Ç2r(ÑåèXçLÎ ùíýH5ã!/V9’ÿºûçŒ* ó¤Yp·7q#£s”ûyv üñÖØ~ÿêtF0÷zŒ°Nîûa¤6Ïu¬—PîëÝaTj‰öÏÜ»ܤYS>}3>£ï}™q†LÑYÐI|¥§£÷õ9Ç®ƒ#?åɶ6êoãÓq¤¹|Æ5ÅúþÒ:ênRé;Ž06gÿî*á91VÖ="íuIÙ0T!{T¹ cN•³ ª÷œ*÷®ó˜Sè†HÐöBk‘Ø aÏZŽvCŒô¶½º:ÙAMÌŸ|IêÝ®ø¸E‰§¾I&ÎXSmF{˜áÈ)®‡f8BfË”áin±ãåÙ3ÈíäU$ÃÁE𭕦mÉ};Fm=zÊvwR˜ÓæëW&Rð4…® Äá™ç{Q&¸ÕgÝÃL±c/ñ‰cgå”7«—Xæ`Åö®æèdŠ5¨Šá£—›¸Ã£ù -­œÛ3hw©¥_ƒg÷õQKuÁ«Ô­‹ŸÎîAIqZ¶8ê/<ö~,fo^9Z†å^ªÁŠÝ|WšÓâ´Èý„éO´oä5ݾ'ûšŸ=ÛnÀxñ²Yø(iÄ\ |³¤VµAUÅãŠR5‡™ƒuzV,{éq“ ¿¡LœË @ßE.×þi8ÓÚG, ì$­›ÿšúÅtº”,@‚Øå¬¯j*¹2Ô?•«–Jkó•C #@ߤ» ·Å>Kg¬Èx‚¥=¶qKâ¬â8>ÍBl~Gj¯-³iþÎÐìëf¸|eÒÑ’þËb,bä±–¯kv+ªÝ$°€$»M87Õ´tsD¥ýz]·¶y2ÄÀa§MüâÝHû1+:Ÿ³êlo?ãùÒŸôDÄÆ/[äQ¨%à”oùuyä—-p¤(>©ò±Pf¯bN|ª76 ñë~.H ¬´D¶£â‚“ô­»ÜÅN2Ç.a‡7n‰;µˆöÿqÓ–ê°N 1n3Ûã ¨=äNH‡C~þS5nÖªBðý꺣~RýCdrµÍ¸Ð"´%yÀŠVmo7},ÕÑ©_'v;¤L ^ìµÁï6#ìl0 â=´ÙL•ó%:_P³Åç‰1hz74gò÷žá³%fv>¤Fد<B×P~˜­–·ú|H‹Òw–Ò±E=„V6aþŠjŪKþ=€˜½Tq['Zbƒ¶ç'ɘ .ìÏ÷vi¤ {ÇÚË==ht¡ÙÛF{²6x¸›é}_OjNhì¨OZl®•ÇoŸ‚« –FÆÉñb‚>þáê=÷’Cendstream endobj 968 0 obj 6268 endobj 975 0 obj <> stream xœí\Ys·Nå‘¿bó¶›ò‚¸?Ú–¥rØ1S~°S)Š)•)’"E;J*¿"ùÁéÆàh`0ËC´e»R*ISœî¯¿n`öõŠ3±âø'ýôjoÿ/ÒòÕéõ_}O÷^ï‰Xe•þ;zµúè«9½ ,Xiõêàdoê@¬œ\9Á‡ÂW{_¯Ÿl43R»þÇfk˜÷!¨õa| Üèõ«€'Ö—ð”àz}¶áЭ1R¬Ÿo¶‚Yk„ýÛÁïaLc›19ó¦k½aÖOÃ^°^à*>iå²ÑÛ‹RvÔµ€ÑÖ×¥ìºko¯6[«ã¬_–ׯÊëÃRvYž>„&ÂÃ|×ß|“ qB®¶ð÷à¸YÄEiwUÊÞ”§ëÒ׿@°3¥ÂZ”&¢L„§ŠN®ÿ]kv€ýð\¬þ°wðÛ¯Ó*p”çÝʪ¨ðé° r™±ŠÌA•×µŒ—'GfXßn­’°Ár.¡4·×݆b³¿—²ãnæØýQ·yøt\Þ>ïzYz[G{SÞ¾€éZÁ„uë-‘üÖrÍ´Ÿ­¡ò³2U[ÚêRÖ/©L¿$|{Üip]ÒÒÛËòöM)ËK &n,Ä,nE]ÁËN8uðé|°»…ýîÏfx˜)e£Š¸R´É­2i׎)ó´n° ÜOÜÄoµ‡:³º]×8ñéYéýl µef“÷[ö¸FÊÉï}²Ùræ8—Úgç©a˜“ÍV3ðëÙõF/|ƒW'âqßäšwp¸:8fõÿî£:ÜŸ¼/Ý´°bj^±Q?7·ýÀuý¢¼ßÒʑĄÕÎ ôö¦¬òæç´«d''€…e@Â`5W%¶ˆ«ÞÖ á6(§ôB©˜J5@È1à ˜Ð§X*¡²[lb|¤ÌúóZ¸¿Ù*ˆ ¤6¦ñÑódJÀõ³úö|£p ©§×†pi“Bѯ6R2-„&ý\ÆÆ>Â)¾UÜÃN”ùåK×{PÍrçò£Œ›Wš\¥šIšVPß!5S–ø´xŸ\ Úy˜q.ܯ.é`c=ƒ2R—u^]Zª àäÃ1åÀ&KÕk, ÌKŽ0÷("óšÖ}…ž0HL粎pU<éÅÆ2¡TëïðÉ*aéIs2+2Wœ ÈDj eÔ œ¡ƒR‘JwÑX±™wØ—r†qg“\œ¥ýŸÕ6ç´ ¾·Ê©^Õž.¦]€‹UU“ ”Ì@W‡ýúr«¸%²ü¼Ëâ&É/Jí»òúåUGZ°¼è“‡óÄ}T ˆ>*f,S'ò:¤zPJÉìOêÊJÚE8’ÖÆpphˆÄÞɈyi~€cèRèL"4(ƒdl8*(iN´ýíÐtH§0¼¶Ì9=ߤב7,I,…<ÎÀs\[¡'UŽ)i–ÍMÄËì|âr0DÁ+!),µPSËU[0•:0åõí3HÖ© í`¦²“×É*;œ÷$O'äÛ¾&Ș´`[((*C5fø¾®™æ›!p;ª¥¤JGÜõŒ!·:Njã{½1†±VLÒÓD1ÿY+ )=m Ãd9À"˜–øë¢¹cH9îu!ƒ0|4˜ÍG˜÷& ÀK©{Òi 3Xë÷Ø=¥l‘U˾%^7nêI­yž¤BrXX¸ä¯&NÁ™Ö8ކS~9¤ u!yöN/àÚëRõfH†™ÀØe"%•fNkÒ*A…ÈD!ÆÝ{ dI'ø¡$2 ‚6ÆMv °â0¿â,ÊO²ÿ1ˆ¿L¶6rØX´âù½lOJ@ÔeÅÒC峤ðYí`7ËY¶bóà—@°LÓ‡"0n$q¶3tî\I{p¦¸T $ÈgÃÒ c=hâ»Ï…„ßM¡ö™Ø¿¨4sZºü¥š.ÍB˜5”ÔÓŸ&ñ›†ó' ¾s’FnÍ1i©Ì.:P§o[§`!ç&úä1[Yl–KçÎfà‘:’Γ<\èJó"³q(ŠdâÌ¿E8r܈Ö”q·uº$ì L­VH~_"ˆ“|mñî‡Õç›M Ç *€›ÓÔf€ÈºÙ¤2½hA¸Aö(—°Í¨Ð{jn™:Û-7 _9Ù8pj¤OæC˜K›©ð•‡.Ã!Œlm'Rpœ¡#¤[Ø_ámd?FøÂó°ç­fÇ êGŽçE0ÑáñãùÎÊQ€âXÑÞÅ¥s £Áå‡ s`{¼¾ Ñâ^zÑ!Zû}a ­©€¾&‚ðã©,5zwŒÓ¦a9`ÁÝ0ª½bÔy%7‹þ“„G“Â}:¤u3ª^Ô$ë}vÛ°u^ ú0麘çx€]®Cׄ7Ãèd˜÷˜™@ä,û3¨È"£¢Vf*þÜOYÄÝÜ/%Ñ‘ìOޏUè┡Öÿ½'ZJ„L&ð_LõZ椠; XiZ4sœe¨ÖUc½Óúú¦³³h|cø\4.²¤Á„™GŒí‰6“O‡óe5@’«!0±¨²µa®dwfÄ—ì°RNj.úw$%FBØ.? Ƥ¤Z?­"z W˜Røx¨¼®Øðe„G.„Œ\yÐGE¹ßÊ%JíFà@tðͦŽß‡éþ•,xÐBí"^H:Ÿ'E—†V˜)GÄÍÚß§aµpD )*ä+‹›\n4Mã¾Ü@üÏUé¤ ¾'­HÕ›¡ÕŸ%ƧÕ½I©=;7ÊÖÔ§Þð5²/+˜V»²EŽÃ …Šq8ÎRp'£-d‚ÛøVzÐ*Í)'m¿Cõ’œ«ÎX³YŒS"ĆߦÙÎ¥ L*K ‰5“µÃHë:±%Ǽ&d)&йkÖ]ñ‚tJ¬õEšª£Ñ'áu|’½isg1 ªé;}i-h¶Þ`ž dÌΙõbÝyÖ ÚÛq«,Tß3û(³@4ÆkÓ­œÍ7¢E…œTz›$`5$ñZ‹˜¹/ E3ÔÒáQ*L¤'nûò¼äÀWM&êmï̧quG~$À¨ƒÄgÆï 7½þx“ï1?ÐX²µÄ>üú«†PG¶ 6NEu!R2àå푲´¥=šZø/GP£èôTÊëa|Ð0˜ #‹Õøh" ] Ïšã`AMqÏå{'X¢;öÀžÝú3‚cÃøŒÄ Ä4ÏÚràãœ|ð!Íl×yX<âìÂ%»PNï¶‹.@Œ5c"4ýz¯Ü cÒ€B.¾,ÁÅ -Š?ïDWô.xÕ+5!ßÀ´rFì¼ñ‚gx-úšÓØØ­öõ Ô <ÄêÙž$Á6Oõ³É×,_ ´mab¿bŠ™¶Mí?ÅÉû ë?o`PmÁÖâEŽ×Žžà#°uGr°÷ÅÞëd.^¦à+X³_y´q%9||ôtoÿéWo®nžïíµ{û¿Ã>úücøïé'«_í=yºŠ]1?õ£¼§=é{õ´ôAI{_(ß¾ ðOÀý˜n_Õ %@ÞæLâ‰5— ogß±«Ó}ÚÐx|`fÞ¹ûé´ÆÐÒË¡OXì¡„"Óɬkb¡xW+ø6jͧôíRæ; |:æJª_tˆ½x&aÃl15!ám·†6t³ŸoÓ•Br¥ïšÜ2\T LKßt5:H¼mBxŽ dÓÍyžÑEw;pa"Ù·KÊ—A J 8E˜f—¯^ü0›tÇh1—ÌjvŒœï àTµÐîÞdV¡ÐY@ÉÔ§!Ö܉§¾ê±òØ›4áSê*qMÜÆâ7æsJ™z`åʽ?p‰71Þ[¢3ÏÞñÐÇ“ÉÎkŽ‘ãóÒá!ëиÛóÔ‰Héíb¸‰óÐtA»BóÑa CäÂÉ$I¨Ï£]Âi¼×4Þ­Ü ïº†>·.»(s~X6“ДJ‰jžL@$fGrÑ‹ûRà#R`ƒç|† °mf! lO 2ÕY¼È&y›ÚÀ¿)ñËKåì—§úMÃÝÜ¥ä¾éqýž€gch§—½’Lgƒ£0­SB¼÷š¼ÍEà÷!ÓU¬ûÁÐh6í-$•FO:‡èp,Ûx®3(?  MpOï…d¾AìmL2nÅã gqJîožèdOršn ‡­×HWÞJº{9þjƒ&óÌŠš–B9aäËG À¿/Ê3•ØígÉyóÝàE%IÏ"yäºùÎ?§à%¦ *Æ5€˜9gŸw©_+ÆÂ« ½äkÆòáâ"óIíïòqÊâíx©*ä|д°ÑhõRbw Z ”xì1fRšKòó[îŠÿŠ—•ìÝŽòM¡÷–^›IÝCÏZ’°>'ËAew<™øäð¾ýèÆW"†W*2÷±Ëü._ü«šsÇŒâ´ïeäŠÙM¿=¬ß'—¯ß5×ÎNê-¸Ý©¿)ïûf?‘Ë{ÍâVq(¯í8Ê-Çþ.úI=ޏBÅYå”Óœ«‡Yøñöœ ­f p£Éµ?¬’m9)’Ö4>ìÈ# ŒÉq‚²ù¨ÕïDä»Êzà÷WÑO‡s[(ÙÝÅ{ïâáª<úê÷Ex©­;èÈß±ðrPAú#@„ýauø£ÛÔóVI&ã)L÷n$h–oÕñª&Ä˯ð}ç_³Ôb¥ hZÀè÷ÚOëG»Wóðá¿€ü‚Íž ¾î¿3oßÖÄãÙ ªyÞµpñÜ&þú€ê¾ˆÞ‘«Ä=[AᥨI@¾h—j¢ÑÈ¿ØûNð…2endstream endobj 976 0 obj 3924 endobj 981 0 obj <> stream xœÝ[Yo¹ò8¿bò”™ÀC7oräÁﮃë@À"ð†,dò$GIœã¿§ŠÍ£Èfë°¥x,¼jôÁª"«¾úªÈy¿_ø_ü{ônñøÏ ËÓ‹aù-ü;]¼_ððÊ2þ9z·|r¯i£–žy#àïÁÉb`N¯-9̸¥åàٻŋÕéZ1'•㫳p_­.ò½Wùê0?=[o w̹úñÇôü¯¿[p±<øýâàW/Voògçù³ùÞe¾Úæ§GùÞ>_½é(tž¯^æ§å‹ |ºu gÜX¢Â>?>lîYµÂ['éÖUº@㥀ël¼µÁvΜõ6MÀ¶3ÅÄ]£0>½ìL@™žãÆìÚ†2Þa£:>=i&¯ŽÀ «™”6ªP™ýžŠéÁ5Fæ.¶¼&]FOWoóÓ—U07¨" §ÞÏ£ë[Á,÷~i”aÚŒ¾ÿ—5,Ü–à`Íœ´‚¥ÞHc™Pg‰ƒŸkŽn.¼p_é3ç½Ä»éòl=€|­Ú°‘Z3󔟮…`JñÕßÖüRòà¤RãW%IXšÁbÈH¦µW V.IŽ—ÎF‘Jøq(#Ù òóF'¢ô«ÑlÎu2P†w70Lj›fï^”wϳܟ¯9ó’*Ê ¯òãÝz£,ˆ–tü}ÐE–S»ºã?Bc`ˆàéæEOÔ/×°’Æ M Ã'K™ªí¨ˆ‘ÑA@´;_£ÔÂëà9Ç‹é|LL"—Ôd©qÙ¢mA¤™Ĭè&Ü+:9ãøÚC~Œ>§ E^}]Æ"ö‘þ¾Þ ̃3Õ¤ô3á&H'W — ï”iDoµ~õ :ÌJ¯‚«ïóÍÇEÔÁÚ8æ8‰¨³Ö¯[Ê›8s¸;qfË“7ØA ˺­˜Yn®ÝÀÇÕ%a> è £—*ET‰ôjt„!{9µ/JN¼< Vçàau%v\œÁàJo„PTÀeyó²õnYx¹Ãï%ãqŽÂ7äÍ“¬ÿE/t·øõÀ´ÔS—‹2…L+s6±—Tf^­å§è#¢»1IÞ=,Â> 0 éN Op,:ÀÜ9˜ Hò¬ö ñ øóJkÓ™­ÈÜ&©³"² óVåbˆÞ‰QípE’ÂU¶eW¹Mz¾Ï~1çÁñ{TÕ3T±%4z­ã%`¢eJêѲyšê ܆´5ÌEž:ròïQJTëéÁâùâýRŽŒÌwK®¬gÊ6ÒªC*þäÙâñ³?,÷»«íâñK¾xüþïÉ÷_ßg¿]þlñôÙòù§tÍ™¬ oÙmMˆ¶·"?yBǬÆx­¬£Ü¤Ê cÐ@ÎéÓãîgSÒT" ”t7Ç¥”ñ%šê³í1A räûÊ]P>K±ér’jé‡nÂAîinG׎9a*ÀÎÏgÇJwOŠÜ‚#gñ¥­19!Ö§‰:ëÞi¦"¬‡Â@ö’øIž€¯¨qܾ›Ë„Ì ÷‡‡1Åg¡ƒBcFgÞvÐáÞjŠ.&X Gvú°˜'\eî¾1­.dOš+|JK¿ 1´=Äà. úk\,CuÓe¦þöcgŽ zÿ;• ¥º¿ e笒B(„3*è7£’ÎÈ. n¸°Á õèDÁ ï…$ý]ÒLy ²'T(±–’Ð%]òYÒ*Èã R6Ô“èÑ5Ü4 jÍG‚ºPzV¥Q~á¸ûB_°ö‰Pa?§ ­9Á›ótÓÓQ‰2G]Y¼oX)ê82qnc•bMš#b±žáð¼MA±Z©yúü¬}“¹WU8A.á¡vïSRR(KÂtaѪ£ò)ãH•t^-}§;£ÁjÆ äC˜BHZgùù@(*áLIïÆ™S8*¸¬r%D9Œ>øð•‡,!¬½µãû¿XÇXÖ‚‚j@7!¼©ÞþcÐIb ûÓåíqŠSfî§xÉ·Ž@;¤ b3¼{Ÿ‚¤~Gt_âçaÚ–qBßõó³Ä ¿ãƒ@´VûJ#þªü`zlŠ`³7¢¹pL‹jìÿA{w.ïZ¯1ï‚6þÁ¹¸˜]¨á÷ÁÅÅ Y;”Ú¹óàÏ¢¡˜Ü;åÕò¾3ÑM`å&Æ÷•• –¡h5mE‘äƒPò6›¬µ†’àŠïrÚhþpÀdâD¬ú}7‚¬'k ®0Y†´P>x ò‚iƒ-v 3n"¥$¤1ELÌQÁã«òÂ.fÚ¬3uð ŽÑ}eÔpl,c›n Ì· *Ek¡Ã®*oq,;h^'ºlz¥Qu“ñÆŽ$¹KQN.¡[…! L­& ±°+mr¢V¿×mz]QÂË.Õ RóÖ•ç#üŠƒ*!ï ôWTý¹ºÅö9#ai´ìÅz*x…"°@¦µÜ,‘>e§”`ñ[º1pïr7‘´­"Ĉxét PÁ>‰LE¨3wŒú1N°û”âäÄož°áÌ8>gW"|5\g€K+0m9”0k#ª3CZÕ$B’OØ úe ¡U¡G¾K$ֶ̧-±K$‰2¨¹°ÿø)Ôf–mi-ãî%Õ­‡”yÇ%ä^úx!÷ÊÏé@ÐŽrâ–;¢s G@…г!Á“Õ3¡Ã!f|™ÍÙ<¡Ü2„zÔäYô\ ò¤Nîbý®åýr71.§ñ(²àŽ)«)€ ö/)Q™²¢@U¼' 8\T‚8Ά·«¦‰Y—r³;²×UØÍ^š:¨ÌèGY”º+©PÄ•lžtìzÜ3‘ˆ—ÈõøqâÈò’aœë9R <™ cÝ|¥ OÀ÷U‚L¢ÒûvQÈü¶Uù~$ŽW³~ËÎ@;™«k EÜ@Ór¼øÊ´É‡¯b2‚(K A¯ijÜäl5nÖÆ%Îôï6m¶tÙÂù´=bn¤qšO¯4гúGEßR’x·ÆÞ…ò u*ê&]¢Aß–E˜;{‘ ;n‰ ;néÅ ‘ÞžÛd'òþ·ô®ÍqûÏWÄÞëeN»|µíä‰]§ð?êäŽÒR(WäÐÓx®ËÒNûŽ¸Þ‰©’æÎ: oÛ|aíê+¦,¤¨D Õ&ø¬ót_öÜœµ•ˆñ„˜Qkɇõ­ÛšÛN[ýGéÖ.]´ÇøúrŽÓ­—SýòPYÑvSn½Iä4Üyº—§®‹åT7•;9k>`'³*4«3.i>>Çódíxÿi„|CÑ&iŽÿb³ZKß& õÔâýZ{rÌgºc ˆÃמÆÉGÎèIgïç,Ž0!Íl©L692›ô2¡©ö¯I-X“LÉ=w#‰{°C&£‘šÐ’}'³”aaFéU4ÜA¥]õÍ^Çó2ƒ°ˆ´¬Òo\c#¦]”ù ˜°„×t«m̾„›F+ò(q.4GE½·)Î;ݼê,P>óå°4Þœ¯ÓÍéFm‘†ý* ›©TÆY¨ •oÖÂÉÕ±°+q“ R¼d&p[r/pÕýÿ³û2H&œ» ,¯_âXk¸.©œgZšNÅëÙé¼´*×O÷7ÿøæ²;Ó2áCÊ­þ.‰S©ù±¢€hý'þ¤™€|”ÛÞ©å¾ëV>uÉ‚Wÿ$ë4V FÌšZÎ<}$34uÃÎÓ¶˜©«©·×ÖK¯;ÞN>SÞË……‰Óéýô‡CdË}¶¹mCùf{ÛE)KQŸk—bÆ¢[ýÄe&EuÊtZ/Ôûa)ë§L[Ò7ùª ëU7ý¦Íá;•Ãô‡9ñ<Ö«iª·’îã}ê¯pÒP·,‰ÚæêO!ÅÅp*«¯Û&‹ywh„ŽhˆÕ\Êðï›nç„¶¹7¸QânÞy럓è÷ {¼HÜmOô"“¬ Ýj˜Ñ„$%'&†§Ö*áðÕzÙðïU!“JÅÚ--AùmLˆ‡Ðü«îo‚öÑB²@)Ž?þ9ì$Ó¥Ëý÷ 56famBYÀ%¤ <$ÆÃb^tyU,ï—=_üÚ6€> stream xœí\éŽ$Çq6ôsž¢ÿ©Û`׿}†žÒ°¤QæÞwg†»3’IAO!=°#òŒÌÊêî9–²ƒXN¡*+3òˆ/¾8ªX±‰¯þ—þž½;zñ­0luõር~ÿ®Ž~8â¡É*ý9{·úü›Yµò“7¨ÕñåQ쀯¬XYÎ&7ßýaýÅfË&˘Pn}³ÙêÉ9ïåúzÃ'/¼ë_”««úøoJÎÔúýfË'c47ë“úün³UÈ)×o6 dÐZðY÷øþÿãÈOÒ0nV[¡'­½[Ÿƒ`<´öL«õ´ÙŠÉ+%56ñ­6ÍÌØätšœ7p›‰•qjR.Îðv£&'5ôs®à5¯”ã i¾úŸÆA„£åãÂNJ5\–yeñš7õĤw Þóú7lÍ•UûæÂ›„L…Ý9•¡e†õø÷V$g }/q{’ü€ µJh1EL–6>|² öÙ Æ'.øhºÎH”O8ŠV­?ÍóJWÊ[—ðÜA޼5\%i “yâlWIì\¥¤XÎæÆœ6Þr%A]ùjËu<Ýá¥ãÍVNÂ+ëÖ¯«buûšéüÄïî /C_»Ùp7 nÄú/ð–—“âV¸¼Eš^@ÌLJ:@r÷ÃF¢î*…Ï$ÜDl@„Ý:«0ÑÀ@šøeà^ìÞs®±'Ä®%íghíÄe;À˜3EXè!Î[2[À×^£Xn2œÃËMoúÁ´g.-Aè,½{“úb|}^úJ"X"2,¡mêáhÂû'ÍÄÂÁõdæoëÝë~Xð’P‡ù”‘žÈ Oª¬—î''@Ë~Qàý¬>F¶x.Õú¿Êózõk1.yž y[‡$ØN_G‹vASP>YvšÊ¼™¾Á¿7Qù¡gQXÇhWyÒ„B‰Iê¼aËÙp.U»ç:‚M+Î% çX²ž9…Ázœn¸É½B‹'Q@°È&üë ð]¹:)Oß–{oÊÕOåéEK=:{Í{A¨YbÛ‡má€3Muî–2krÇÔz€µbž¶ë_£_[Éúæè‡•ŒQ˜¤[ g ÍÊ0ààûŸ½;úüåÑ‹—¿Yݽ¿¿8zñÛ?zñküß篾€?/¿\ýËÑW/Wß,ƶ >ƘöMÓcÝ—ÀÅÄè“ÉßAùéVvÌ;fPǤn[ öY 4e• ¼î9 Þ.°&Ê ˆ€ýQ4}ŒY×ñ„÷lltÖ_'€ävýË ø÷ž«Î-ßAZ¸¢}ý—Û‚ÚðL²Ä} ÒL" … ÆÚniòÑ0Œ&Ã4¶°oܯ€jG“$NËa>]Õ€ÏÕýnŽœlÒRï 2éÌÎûj9Íœ2T5ï‘ö§ÙñE|DG€ƒ< 1Æ$9•ÑŒãÆ\•I”Ò …–âƒ\€ÞPíëçØº·oð6_ˆ¶tš€ž –¡äcoÒ)s+ôgéÝÒ í)6¥|ÝTž s?›ÂŽ3ò„Œ:“·³­ ç w…U ÒÌ2):*Pq8z/% œNÌøì⪥>Y–q|ùdOÕg›E„v³OGo]¤Œ“y³?™&ªNv¨N»ÚÏgÙÎ@þh‡œ‘½¤÷²ªÐýp÷ÒCÀ-ºÀ¶z=ŸŠ¹ì´gzx1àZ®µ—< kaqq©Êµ`Ã|;¡J¯‹È7Õ×Åøð P=ØÃ ]U”äe½åºâc7ñ|†J3BÀº‰¨ßÔ¾*!HTU’ÐŒÅúïªÉ®X¤MG±»6Ȥšh×Ã\¯yúí“”0v q“·KAèY´Œxн´ Œ²øˆž’;=Mé"c$'Dž0>„Œ×©ñÓG8;¤3h`þ`ÍׯFæÏpfÉÄ2x¦ÄD¿üØ÷3›âi¢_‡2 ¶ç‹rï“d¼Œ!;[Ò>YQ\WýîWr^/®dL.›¶Ç5œ;Ëvƒ “Iñù¸çûBYã_-“øwÜóÌÎP=‡@ПÄ/(½rp5D‡«†:Pú0¥äOûqT¤22i;ÎÚeØ!£ÞÇm,jˆQýÑ$ó/qÏ4,d†ee©ÕžárÏ+Š[0dT«¶KzçÆ‰t)"'õª‡¨ÅÜ{ ÊÛe[•´*±XÕ¦Þs Põ4C… Iö(Æá"ôRÑaÆ'Z³F*n†J¸˜,ÇJ1˜hBèš·.f¹²»Ž÷È|;w·T›…ø¼†Ž˜]´Ð{‹$ÚEµ•°¾zNwõv¹‡×uˆ“€'R`Àe4‰®æÓbT๣òêu„E°× y²û*©;¬%y©â.ìg›’?­®[Î+ÛE;rýMBNÍa¦9÷CZ“ïm:#eÑÇÍjˆ~ghç¨?HÑ”oœ‚yeÂËÕ¦+ÚiB« °òu9­äd¾ÂçzbÞíˬ|ÿ"(X7Íéë¡ÞCÈnÊ]åHÍìØÄpGì“ûf›¢µÇ’h?¨µÌg_ s\©Kšf4öK(v=¼œ'ö%Òù2›øžó&¢6#Ü^¡ ¤­• äLŒ]ˆz|ÆÄb—§.OéÚQ²¸1%uæ‰Ä1€å¾Žl(tÑAªW-ö]5Ž?Ú›\—Z#Ã]b¥µ7d9y0¿& )µQ”§…”!m£Ø¾ Nœi&t’s_5Cv“o•Y;½Í·ÞÌsfšœÙRm–S»¤ ©äàí˜ÚÏ"² \8C-ØgÉôÓD#ÿ£e.¡¹†Ã1Z`Lü1ù £/Iåc}ˆ¸3úŽyŒ¯–̉þËÂ÷ƒ8|ý|íý ”}¶+XM®hÅúÖ>qP§ËA‰EîOƒ§¾µö‹î ½ÚÉm¾•+È,îÚ[Ö’y•[Q?…8^ Y÷Ò@²‹u¯K/roœ¶ص 1ƒ¾D8 ¯¸õ_ኬEy(ã-åÄúoéÒû4r3ù²Y‘Ÿˆè[:è´¯¶éÇ¥hz-ÏîæÏÎò­ïç[Xš¿n÷².¤µÅ¸!`ðœuÓ¼Å/бòR§BÒ¯#"i‰øà€¼ Rð/afš°D‹ù79)haFþÎò …_0ÃþÏ£ã-Õ.¸ã|õûšZÊ‘Z¥ÞiH`„ت¿lÀ'…!ƒQÚM®áä¬Û™™ C•Mð¸¦fŽ~ßø*:L<:ð”}ù}þO¿…Ä€w^Üã2+Õqþ4;³ãògü(Íza›âšq˜F˜†qØtnªŸý¶_i$ÊDòÿ¸à2ò'ÒéìÂå’ëQáûÞ|u±% _’ Hý+­rÍ*“T•î‹z·«[õGqÌÛçù ¤0 åÕBEÊ!ßwÙÔ‡æHRQïA9Üþ¬¼òn2«}ÅÏqXSµð,ˆÔê£.;c:!"ÅϬˑ)#ô‘(k® ¹w²¤¶KGåIeÍ˹ÍQ4 +ÁѶáBÑ%GâðzðUuâ²ãƒA0‚ÝYå>+Ð~êœcAc·Fªuón!ôzÞo‘±ÿH»«3øáÊ nÖ–°íÊ̬@¿§Ð¿…_)îHk:³Æ’Œáëß ÒIÉ áU}%ÕUCHŒèM/J>YhϤøXæ’äiBlÝ.åAÆ÷+¦Úìj:7ãâ¯ïQ,ËôÒ'NDu–ó³I7ï)"fS7 /y¾9ÆZ‹Ëö呞͠?;• kT¤½A×ý_ „uùH~ý—„p“ó¹lûû¾î²Jùì e?.òõ®A#x˜kPRÙ5…ˆ‚ÎÖÌ3\ s R­c‰Ä—Í[Ú¦ÆsôÿÇ>Zü`<µèäÓu¹ ë’ïýyø´DF‘ñ:\õÄï‹»ì󋺃HBYY„c"?å4Dq@HŒ¬E‚-Xýá¯o7]v°eôä&ª˜¶XÒ2 _» 6ß´¤«¶z‘~϶£N{F—kʨ˜ïTý84ßÿŒ¤Ø¤hvýõ›ñ®þ»²g$é—}H>4¸ÍYîCÉé€Å\µ6.²lÛ2ü~ù^C'mø&A&, âý³~Àn+ð£¾ëL]#’܃³àÀÏõÞ4“õ1¥çå­ó"_´tF5®ù²Éc]Çß{q½»TÄ[èÏ.:Nùæø+Øü³ÚÓóŸF„ Ìu—\Ê?MaèO»~Ž¢çº'M·’[ð’̺Mç‡ýàÿû0€B Šiœp‡(fáµm.ƒµr‘š†_¼pmñÀh€óš˜Öy+ âgò lŸ~'¥š¬ÈßsפS.Oàb¡†g1+„]Lµ.n>3³ Y,xšû¾£9ýEÓçèjÔBéö;tiyˆj-}ÍtR­]ApÙ×ú$šùl!§e–~Ò`Á¾k~6šßVàãŠF·nGÌœ¬ÄÒÅ_êr•ù«ÿÌß{XSöϦþO'÷ÕE‰úDzŸòNszO÷#r|^³òx*÷êÓ©<íïÅv[ƒ?×çÕ#Ø>YXƒ1Û/ÎÀeÛKãiýi¾Ü%GyNE—DJêcü.?~U^ým¾õenV[}1n…“Ñ:'h¼Y†ƒ‹’ÔÃ=ÔEãJuÑ7Gÿ§ÓÏendstream endobj 987 0 obj 4796 endobj 992 0 obj <> stream xœí][“·qN9oû+ΛΉ½ÃÁP¹ò JŽi[1E­íTÙ®Ôr—K*âR«W&ãÊßÈïM7—8÷³±+)—Íñœ .Ý_}öûÅ8°Åˆÿ ÿ^Ýž=yÁõ¸xýÃÙ¸øøïë³ïϘdþ¹º]|v¹pƒÓ\ËÅÅÍÙÔ[¾0lF¸y{öÇå/VçbàN ·¼XÉAq¥Ìòùêœ+=À—_¯Øà¸³|ùjuέÓËû´ _þ¸ÒÓn¿žsÉeÄòéê|´sZ¨åw«s5XëœX¾ÃFåò'éêuþù!ݼϭ^æß߯Îå³ –߬F¡Rœ•ÍŸs®¡ ±ü->ê` by—Z]ó¾cL‘îý°ƒÒ£6¾øÕ™„™^@ãÃhœY\\òé½QÉåßœ”BáãO^(]¬À8XÁAïôÈÚ¸˜Vâ¦ß í|ç¯à5?^IË Ïñê‡øëô®yk™7ƒ”ÅnÒ ÅîoªaÎJxÛëçø4“Fn “ãÀmc(ØÙµCiv# @õþ¹ì’Õš¾ˆ—¸<¡ÿ„¥5’+Þü  }xûÁZvôÑò‘ Œ³Öp-ÈîÏQ¢A(\~Ç®¤3 .áw -XòVs–(,EøŸËYâkg)¨¨5ñaF>gR¬°Å9S— Ýþ¥‹ `¤±Ë7YE‰âý}×l‚Õw¤côµïVÌœi¾ü ¾¥mPÓ[äÑWØ€  IºçÕY†F¸páJ;è±X^e¸)ádö„V _g´xH?ßO¸Â” íãH$`‡“Øi˜îq´:u^›F-FXÇ«üÚÄ`‹â% 5}L¹Ñ† ð ¤É,îÂkÜ4È_§¶B5K¾P<Ê•P°/ËáÁ`~‘3,7à˜·"PÅõ>p»BAâÊF»Í€M>•—àgSÆÕ“½ =]’q¿ÅÙ’Ã8:*Ddf/ó³7+æËUÍdìþ Ð/Œ\^¬,F6šåÇüÑ»|I„œ40}É ¿ÅÌ(9Ÿ.§g?Fy°´±ž@¤qñüÃõ,3ªDÒŸ·Õ¥ï®ÑyX¤s´úe¶z¯²¹'M½ËúC´Š|€¨åL&ñÑëü{mW+fƒxVAOã™d ޲4É÷ Ù¿IÈþ®Âø`’¿¸8ûêìû…˜Ø¬‰cÌýôAÛ8&¤qŸ=;{òìËÅûû‡WgOþ°`gO~‰ÿóÙó§ðϳÏÿpöųÅW]r·ÆBMŸ Ã¸J½Mø®øD2Pª³zz€X™` >'ìŽ,ç}‹^yìd¨&ãÈ]¢–äîeS¢¦$wzùŸÈ³íÆæH—?ƒ×¬ô¨:ö¥´U̺qŸ4F´töáˆÊAìß…¬¿šõÑ!ۘɄYÎ+ÃŒÅü7…R99È‘KÒ¶UwM8! CºW|?v*fxɃ;h¥âܑέ³RUÖ‰Y ¯ÉvÿÈ”e;ð‡ìÃMÐ`ò—ãSYuâƒô­:±-ä£='ÆÊAë ïÆTâdpÌ©I"‹~•M›0E¶øÄ Þk)(™:? f²ÐÞj•š9X±0E……NÖxf˜}Lj]½Î—“lÇ$ÉvÄéÐŽª Ò0!¶•ºyBŒrFè‚ÿðÇ»§àÔØòg¥'ÌÎvEbW`¼à*GO,Ú•d9²ѳ! W[lG£¿uR‚#·E—w´!m—N¢“SÍD퓲5>)a·Äö$þÐôx#.@Ï/dk<žc|p+ÍGíc™ѵBÙz½…ÄLŒ z‘1VÖ™èDw³}"Ó@^ÊÊGQ¿PhðY+„$Ê»«·…÷jU[0ô8‡…ⵄä¹t`ÞæJ0¶‹ MY·èF³«7A _£Þ„øtãDQù*«â¸-yTA…¡Ê›äÑ,Mþ*¹œDÓaÔ± -ñXpŒÊ3&þœ!þ¶úùÿ !úDW vha­µh)mq÷]ò@# I'QÎÚþ‘ø—i­ YeR6õ Üîe4‚(¬ìhý8pš’ÿ¥aS¦×&¸sñŰK•œßœ]üæ©Áò:SÒ£3àŠ˜’¶`>äßÉ”ä!$%kJVúÓtwc6\=.j”øqí‹ 0Iþ{ººJ¿Þ¦{ÔŸ>ׂÃÿË¿Â%´¯@ïã¯ÏÓ»H÷>Ÿ“`ÅóƒOÓÕô 1þ9Œh¨øÜËý.ÞzÞxìËôدikþ«ù©é©/ßü¯p¯p‰q˦¥—–§@<$öBºN±—Wio¶Œ½@;{¡]Îr™ºüaS—è‹}¤. „ê¢Ëw.ßW÷Š`RozÑ2 ¶¡ÆÛÔÑ,,ïèÌ÷Ë,L¿,Û¾ÈÀ•ïæ\ÓC8^FM{•nÝŠÖ«:à,ÈHúP]>0Kòs„Ñ­âOã³jP£:¶sŠ­ò^Ð ”²$ 5´êgÞÞ|häêFƒ,ªŽÑüÐäºäÙ‡‚–aÍ:¨Çq%1»OÓ;„ò´ÓÙ¤_¤)BqÛíY¶ü¯›dðMˆA1’ ºiñKNï¬óøa€Ý˜sÀ§û!°½H0ØÉø »|VæÖ-,óô} úb CãQQÁÓz œªŒ<ùÞàz:襒%s„]ø©ñm¯šäz÷ã›\J³I!JÅŠ¤ÌK/eÎõ2SÍï›VÐ8x5Nv¬ìU†×ÿ1-àTÊ3h¡‹ÅÌïhéûM«€bæwxÂ\G‰öª%PñFkÂÕËD;Þ&¿-íÚÿû´#÷ø Öñ=¬#÷øè¤ã1FHGÅáœ#·µ3åȯž–qäïÌ Gù"®D‹Þ”™·­Ò…bòx“é,Cu§ÈöÅ£Öd‚%²v¢kj§d„3 —GÏ%„V»tMŒ0>×`XøU„Ä£üŒ`áïȯÀ‹Än‡_¡=¶ú” ºkÿöàW©‡›hU/ˆé'Þb!¦ “ˆÝ,¦Zxj½ðÞ¾—±>øà02¹-;NÊŸ–ye2ÓúÓ*ßEŠ'ÁÖWOŒ£ÏQô ÎvÉ¿’ð²mÞ4º&x^=hÀ2eu¥$óPÄ2O‹qéCUø*„¡¥™X"G±KĔч³D ŽŒ„ ‰ÍIbUÙ¼MÅIf(>`´pw êø³°c d•2t”:Ž«‹ÓÏ.„ Àï8}æç‹¬E/‚æÚÁð†=Ú;ûÃôÿbóÖnð€ˆ’¥-FäׂcÔ_Ñ2ø©®\+œ$Å(ÄtQe5AµÜþòupqSƺW^WbB‘þ›V!yWd“Niú—Y…>6óü³ KÔaÌkH±ý|/–·´ S $$ï‰=%p0+µ¬ýêÞv‘-~ÔWZõ¿WƒÉA?5¢ §Z´ÛDBŠÄ|gvÎ#‘‚/Ùrà $Ù\c—ßøP=Wf.+^¾{Ûx·ö3¦’ösm€* "¾1~°á~—3_§—¿È)€˜Ø)ÜæIâu“v®’×ý&ûÛ-½n¡$¯›ô8UR’üÑý¦¯ûQzn*MÉ“pŠÍF‚”ííÕMŸgG.²‹„²¬˜‡j=/‚µæ ³Á°d¨¶j÷Mvƒ9=| »Aºüc#ø™M|ÞµvÝØÉ–)Q ‹êœ\_ñ¿! žjѹâãôÝ-ìK/ØÈ&ûBÛ˜Þd~ÿõñ²¿éâÝ^ÁɱoÇËì¤âp~4†ªú.xû@§‹¶ÅÆš&§–e}^®TŽš÷ |³âHDŒ„Y‹`*xLÓ¢!ëzóéó% {¬HË©ìÞ4¦iƒ|0–±Bÿå\`Lá™oõÍÂSËy“D‰fn»ÇU8~3‹ú‡M*ÎHdó_Ã/­­(I9ý1¬·wôkVƒß¸ÉÙm›þʲ‡u-{PܦÍÝy'EŒ¥UÛ¿«Ý•YØ?M?S³Ç» ßß÷ 1>bC‹| !…Û¥· “My=Œź—߯VùçÌ»Õ+rK&¤—v|”a 4ñrŸ·S¹"àªÀÁ×›“S‘äÖ99½™àÌì9=Óüx-ùTäáÒª3…ïu¶ÞGiU˜Á™–¹½o>[ù¢yê>GÑ$}~ž"é—M[Lî¶ÃÃíd c˦µø3“FÔÌ6Ý,ïl>'¼Â…%è&ÅæÞ›:²û’ô$[:»c­dG²%x2ǰõ’-q:cÙAgÂKrõvÉFf©£‚ê!EÁ'Cú¿*ø±wÍ0:Sg_ç«Y·ì¨ý!6~…n§_rXBÓ³oÔìRj£Jî.,=•Ä$Àn‘ÙŽJ ív´Zû©$÷A•Û2èI|ǹ(mžÎ°²/‡?«H@Õ 3¤mPÛ~vrãÈ1}ó³ÞØÀ˜s±áÒ?X §žìy²ÿ°bS\ãBÔÙ5ÒÔÆã»ÚþZ7Ö¼}TL•‚øaÍm;ïÛݤJlö\ Åƒ KyÖÌn)ÐØñÙxë¬yZ:ta- í.Ð=@ó;g÷4‹[›2¤!\ekÇHc:íÒºž!J·Î¸j´*qkPÛö»ÓNçè*B8ÔŸuLŒ9º±è¦EHPwêEˆPGáôXwpp„„…NÑLUn²Gê%t ìØ7ÍÃ%ëº$tÚ-h˜êÌê…ÈS/Ÿf\þ+ù@QjÇý²9®OΦ ¦)2´x®jSÁX;‚¾Yv;ð­aðȱKÛ¬z´>¾ím«_Íó#ªôv•±>óQÖ'þGæ^7‡¿%’õ"ŠÁ¦¯åH÷ŒqlóÍ6ýÈSÑ>•5ž©4v‡JCÁdçƒÅÂD°šøúO§ýíˆXçÐ?æÀç™glÈ&ò5ifΧo4ØÝhtè“ì8þ“ã£øG +mbÅN>÷&Mùg`’äÆ:'ää# –™Œèô†¹}TTӹصj#¤&Cíw}<ØT«,LQ727³êBÌø¡iš.WPŠY Îó©Ó¥v· p=ÖúâöÁí9¦Õï«ÂYçì!c=Eæn¿ PdnÅ+€o&BZ4Þ̉6âëE ˆ×YúFOœ€É±²èü]³ó‡¶Oœ|ê#âÞÿÅ=2;ý®a·)l<¡YµŨNDæfÅñýß@t¬k4§ IŒ”Ý£wð/2Ä“ ê¨ªÛ:ªº‡xõÀ†M§’ï6àÕd°Á]˜ÁF“JÁÛõsŠ0Ñî&Ø(æÁf´'ÎÒàߤàEçFJ>*Ÿ}=yçùn}Ñ÷íÿšBK’QlPžZl"P’ÞÿM%žhêê³ÙæHÙt1‹qL6mÄÔ œ¥ÜbõÒy¤ÇÒx®î¿áz_ ÷b4Ä»ÌS ‚¥ÁéÜ´H73òö$3aìî’ÙÁX‡Ì÷ëøøtì÷zæÖ—â5ΛË?©a³½ƒbòÝ.  ?ãVîÊwÅ3»«çÖŒ¤×wTýñúŽg8•]?ŸZÀ½?!ƒCµ ÚX‚1ƨ„©Sûx0¶UÍM«íÑl_5ÉâÇ­ñ¸ÁNnƒàþDB¶‚ã£1€[fHëfûø&&Lüæ!N‘Éê„Ti —C,spál˜ô'i¼FakΑ֨ÒQ­&£×ÑÓ˜…_Ç—vWÔ† † ±Ó©<ž+«¥}ùVð!lÃçO#þêìÈDyêendstream endobj 993 0 obj 5322 endobj 997 0 obj <> stream xœí]y·‘_äÏùì?o6~­æÙd°|l´°|ŽÄаkO"lidE9¾E€ýº[ÅæQdß13’½Ø pôÐÍæQ¬ãW9?Žƒ8ññß'Ïî}%íxxñò`<üOøïâàǚƞ<;¼š‰C?x+­><>?˜;€Gžòpã0›gV­Õ ½žÜê/Gk38ç½Z­Å`­võìh­/U«Jƒ§G#ôeŒ«³¹­‚§/Örƒðnõ¼´=‡§R £³«ëòÙ÷¥ô …ôdVOØOç¶nz|ü_|yð㡚— mÜ¡pBAÿ¸0ƒÿ­î?8¸÷àááõ‹Wg÷~(îýÿïþÂ?>:ü·ƒ~¹/…ÓCM¿ŸŽ`ær+šê\–Ÿ§eÅóS5N‚’ä JÖËD>7E¢{! mJ:(M¯Žã`µK“ÁMyt„õ˜ŠÐ/Ô`ìh§¸a€ç¸ß¼>ZÃ4–‰Ð+ÌjZ}—Š[n•£K _Kèæõ‘ñƒ‘Z¬øv::¿:žMCG¬˜'Í(MÓÂ/Xr“OÌ ƒŸ”Á—¼ ïŸÒ4¬ L"µÚN›ëÒÃ÷tÍéýébþ8™ó£i˜<,@>…¡ µ¾9>FyU>"4»Æ^á¹Mœ=-è3 éhƒ?—3Õ”«÷°+?Lºâ2ÁQ§ÕWGöGMzõÉ‘Z¡WÂ[eeíÊ—ÏMùé#wÈ\•‘,v4¸üµRÀBòp-äL€™Oýht_ 0û‚'Í „ úç¬[l;EíS^n!CF¡s&18~…¢¨-ìç´Agi9íé´Ê`d²ó{ãǤ ÃÓ'¥m+ÆII$ã9íʬÑ!¼6&¨Ç{_ÐYDwƒ3I}‰ $àÐNw&è¯'À Ni'€<ø ¾’¤gÿý”ßžägOó¯KæÛËüë:¿²Z= #Ìÿa~ýy~ýQ~fÉ‚´Y`€ß†‡ÓD¦ú}zt’~¼ˆíÝêëôè~nþazô~ütB¶üôàø?~F|_ç×_ågßܘŸ¤G¥³/X`ÛQüìtø ¿þ4¿þ”°¡ÃÚŽzÐÞÇ.'4z¥ïðÖ€p=* Ÿ¤†ßç†ÉB3 Ô¶žq Ö¯ƒz°IêÇMÇùõòë/xÊký[YÍ6:…eÜ+xöqìÅÉ}¨{ù,=+“þ°ìÞãÒßß÷žàƒ›¬ëòÇÊÇW©å«ôcÞZDJߥGgÁèëÑôn4úص’*qÂ8ÿ(£PZ§³ÉüÙx©ðMQÎE™³¼”5ÒóÜðezt~”9ÿP7û@å ÉfjmulŒGÜ9¶Ð@ƒ-½©K!5Xj‡]zh÷] 9 ªžúm|Šˆ*+ŸBi0÷¾ÓÃUiŒ€’”hdWÁ}·„B“Š árA/ Ö‚ï´\WÌÜ«‡Ÿ( †ú)ÿâa!ù¹ G¾¯û.œ_­´3þèAüüyØçAÁ*ÜdC?[gëçÖ!nWjJ&ÏBesZõ’6礀S‚-y·«v+ÒFœ³@5Îdô]dÎñÐfZÓÑHD.ÉÏ“âû,½ŒÚ÷Ù›Ic  ˆÛ¿GËCŒÑ÷Yë]eU\hYlXômѯóÛ—ÉhòñiW1g•Y=Êš² “lĞƴŒ¶¢RħÅJÅ/ó»÷Šb Ï“2@e«^™ï.Š ß<Ÿl¸¿-¦äõÒZç!ˆ%Ox÷¤žcÙ4Йh¯ƒì(:AOI~^&dÏÛ#ècvgã‡Ù8g¶ù+ciÈÏÖ5Ä·eoß0œtIg%Ïóëg Å_/ÈÇ ãûrID†“Šf!ŽÁ>âžx?ÃØâƒÝO²»ømæ0ŠB¤ªˆ“ÙàƒfÍ}¥z=gv7NÑ%>w|Ú,¤æ ³¼&"…š_/©‘Dœ™‡ém!êqzô0÷›)ZÖE:ÿ(;žÑrò!½û…xJ…­>ʯ‹îȲqN—kÎd&úìªlÇ‚4ïèÝ£zøwÀ-~PÚ|{´lö8¼fD&¾EÿÌ\Õ•WÓ€ý¢–‚ºÀѽyÂÅí÷µs̓ˆ@©Q;ØÔõ8Xï´HAg;†mÅð(àz St±ÆÚW)&¨ë<|ï„ Ñ£´œ\‡²Õ^-“ÚLK‰s” 8@/+eU  ®anÙÃ\ ¶¼¤ˆ4Íà±»‡×/<†€À.ò7ˆÀ¼ñ«ß¡îñZ¸M¯SGs ?!-…;EΉ@z.—,ã”ÓÛzZ燗‹õ6º¥|¿.<ÌvZ•¡’ñÐ’(v|" O¹•.?ÂñE,‹Jf \@ÔÅ_8+ûÇ£jï+ïR íøÈ tº}΢Mšz+|yið瘄‰ÞuÚ1fúz#ä´ÂÇœ£´„lu׌sm3‚¡©y½ÛxSʃ^™¶¥)ÑÕx¢Ó)©ý"®Æ·¸PÜðs/µÚ8V|¹–OöæŠD3ý ΈÓÃ씈'µ¨ãCʤh>bK*Üý&¿Þ1§0¯®1Ehÿ_"ÁK?~ßý==Z—Hð?¸.r$8ð˜Æ‰CLx®tI´bcÂ)lœKÜy¹˜úENÌ5!áIs!aЂ CÂjÒ¹ŒÂ»õ­Vfw¦Ø2íhž¼1:f×êÌN¡Py›—Û­.Ç–£ÜQuÉyS ™õ‚6ËÛK:yìY²u+‹…«n‹zÒ[U€Õ€¶«oß0Tl&";Qºª³?2ÝiäÖ‰€O9êêÛ²9)·™^b’vñ~M‡&‹±öðYl ¶Ü´å(¼3ÔdFйŠAþÀb–E`.4¸ŠA¥ÑÓ¶¯8PFB—9~d›¾æ ÝDÁËxä±iº9ŽÓE+×­›™+Òé{>:ÈçIº± @¥úí¸Ê3¸f‡}Êͳ“Ä/›¨<ÀXúƒRÕæ$‰R6Tü# :k©ê—3P„ låJ7Ç'6M€!š1ÍnÏOûõDaÝOD S[ÎÝ®ÆhŽ÷ôŽeðŸñîAVu™Ò:nfím=("„b]Ÿ¥) l8ÆÓœÌÂÂ,NZðÕr¢°“¤O _F0H:¦9F±€ÿwÄ·˜>•½ø}A×DTO£OS©Î<ÍUŽz*Ç:(œ gm6Ÿ3ñÐl-±tÄæïgLm jê¨Í4{>kë*ö,ñ™êüLœ3¿’®€«¤ùítNpOoS@hVà@\²Íào…0CènF —a^dôÓ‘N×6„‰^ýn&YÐ5çn ™-ÆWßÑ‚¬©VsÆlÀÉ/—ÕôÖàÇw·)^hK–± 쟦h£aJ¯õ;«¶q¾”S@êäã7Å]nçQüÒV¶ÍÑLÅé0ï7sl!9àq°ö‘;=Ê=9v›Û ò «m'äÖFe„­þšd£UÑ#Mç[ÍæhP«ÃV¸Ê Àø¡qƒ“ކz.¨Ö7‹kN•Nê6X8ÚšíX˜É¶Pâ-@à´Û1©°ŠS°9È9¸É; 'ÜêHH/Ùça7ŸXå}¯4-0š1_6ŽØèψ¿ƒçµ@¢ÒNÛÕGÊÀ³Q‡*Ùù 1F¨Œœ4Ý™Æ\‡ƒ–nažEz+–;„ µ¢…®ÍùÜÖî¶¶8÷Ãç}Ì9Pr'ÂDÖ>-¥A¸deͲC±mÇÖ*y³U2ùÀð¼z CÓÕÿµ4¸, *?‡•BÌ€,¨†©I zR;×¶4ó*canNk•ŠÂ>÷.ðX£ˆžP*qÐBíR¬ ¬F¡·®–Õ‹‚še¢¡äjƒôƒƒ˜ã—§T9*‹nÏkL̘‚±QÓÎÇ‹ p–&ýaƒ'*æŒz[·SIÕL(ɨ‰÷ò‡@JtUªŠ¤2)Z(êÔW˜ÂØ)l³’Òµ—ücAÞ¯zB—žò5… ¶‚~°jrTø‹2üXJ>€·»øù“À*ÊÎå4û\™ÿÉ6xŒ¥6cèÑ!Èz«Ðë7t5ùö`z¯èä·–u£›˜B©;a°˜«»C࣪Ä)Ác­»ßd(qVÒ˜â\ÜQ‡KY€í#­¸Â õƒT”g¯Z)_ƒÏo«Ú¢høc‹ ÆÁ0 –ck{‚!—%Ù^Ïð..ȘQšýrž‹½*ƒÔ¤%ÀP ¡±Z Âài uä7†Á1LÔ³CXe1ZZ`YU`ÒŠlií8󜟅‹v„4«™÷)Ö ÀIâ9Ì/ ~°a~nzœŸ–®>/+&½²zÜ)¬sKhUŠç´å›ÖôÅ"°ÑWØþÃÕ½s ìP¡¼TORÕå¥ lºÎŠç”ʈÈÖðv3™óÖš&ËÈ20éê’§EÔ*4xSÈÙ‘¬Z7Ôd\ñ¨X&‰>Þc°’º>"2'K,I–bC?†¼ýMì]Ÿ…;g±KsSY‚ç,äª=WP °TÌ<0ç4ʎؽâd÷Ý÷ʉ4]¤»‚‘èœBiÏl€¹ÖÜ<ç¨hžÏ7¤1~f=ÀŒ[ÝN°3Ð@L¼GØ™76cþ:¢!ÈPD,îøHp~Îþĉ"Þ¬*)Õ¢u5d<È…‚–ïr Êk_á½xÃÖ˜3ì·šŠXò‘&ÛàûÄ؈éòFÄê¨c§(¾)Î ‰äNEc³ŒÃVÇRz·d5 Ñ»óK\’£ï¢« ˜YÞ4 œ:jóþqBuºá›*¬OLSˆ•È*bxžÃ]—Ï ÿ³0)ÒáKN‹í&àÐh¸C9Žxfö-Þˆd昄á–gµ­çOJ©ÿ'FŰòÞ-ñþ®·¨†X¦2 ×)ÐfNv®ÚæãòÙ‹®3¨&p‹áJ2ƒ'LÍ@}(%p‰¬Ã ʨÀÀÝ“*…u{ßúÁýDYz‡ÔôŽØIacAØé´Õ@K Ÿöæî±Ðû]Ìëß$# |x½AæY<Õj›Daƒ±x-°<8ñFdU&A޾”§Zj',Òð­ÓR;ƒ%-wŠªZ.l›«}š"ä=mvV±ÕZ¹i &a$멽¯ wïF‹ >d6ç÷CVw¢—‚s€c[IhJðJLJ1yÀÒ»ƒ Ìƒï6‡ÿIü]Ü&þަFÈ·]ƒ£U÷jpè‚6ß´5¡`f¹|'“7ºü^ …^i¶ñ¤ ív÷uç°|†~{óu¬ñ¶êlçu9š–6ùÄóÈ ›¡·Ã`@IÏèTíUž/X¿E"&ÞºsãD ΠwÕNR`‡vÈÄ™©NóŸ1˜¥6›ó0HGøy7y<VBÙ;æaæ[ßßrfÊyžýÒ0Õ±_Ü Ž%Ê›§a°Z\ª~&Ü[³[&6ù;JÃÄ 6~Æ4Lø› @ð¯sȘµP·17“®üL°Wn&+0·QÞ¨JêŸÅ3’úÀo*]P>Qì±)^2¡÷Íó¤£ïW©süi6Ìe!¢YœÏqA€•ûùÓ<ã\‡q“4þý/:WòÖä 0&ÝMó?†ûýÒ<éŒÊNižù¦(Ûüá¯C÷olÔÑ{æ Ý­yŽ@æ,”ý<ÏLÝZ`sSEÞfžÈ^'mÉ!—d›6¤têÓü¥ÓS:ñ ì&¥Î+ÜEF'rÕ2£³-÷wwq~î\dw×HÍÝ2:ñ(Ì>tÒ¥\¤ß»ý+]×ýö2:!0í–ÑQ*€³äi›;Êè ¹•¿“ŒN¸£Q-2:ávn¿[NÁ¤Ù Á¦ŠÜÝR:a»ë*¿åuþ•×ù¿“×ᎋ)¬\Unr¤?™6º3CõÇáÝ! “{W¨|$ú{QláýÐ¥öÁ‚V\œ¯£ § ÌŒcº©ÂÓIÑ•{Q^¿¢—Wc]ðzbù >¾ ehŸS[›z½.|ÜsiRÓ¼*¥J=_‘ïÉÉTç¯û®D#ûj£kÊÅ»¶þ$Èu6‚M´×Øxçš×JzÔüM£…•Ù£L6\Ëß¾Ö?2Š…vqçZ´Ú…‰O­³·¿S¦ªÁ9F*Úrz5wÛËÚe¡Ýãö±¹ •3‡jwº†,'ç°,Ím¸þ-˜ñ:¹Ù`"vÍ1ååÙŸlLŽ:³ÃS”ëà?<-_¥ *®N‡Ko`ÜÔä'òhüŲÄmxËÖ&¦fºý,³¡ê‰y6¾-e°xYpØã^‹ 6S À ÛW¡î×øŽˆßø2á„PO8mCÊÍÈûÓE_µkÏkUž:)î^‹E¯òâ®+ÆêvU_ÑÊÄE}˜|¡DâÂH0’”G`Ï ßÁ‘¦ù¾CSîЪÔÕ¼Û²ÿwMgô»o¨6–ÌoG@]ÝŠ¦änò6Fè˜dÄnÊ¿xW–üìÿ¦/ìÅÅzÇ“f„âW\³§/2ï9šqmR(—Ò°ó“?¹Ö·¿Aägý> stream xœí\뎷 .Úç)οì>cÝF#A;»n¶õe½>N¸F°Ù‹ífoY{ãIž¢}àRšIit.ñÚ±QcE¢$’¢ÈÔœü8œŠðÏð÷Áéäæž²búìåDLÿžM~œÈH2þ:8ÞžYkÍÔ7Þ*ø{~<k{²©WrBN;)ƒ§“'‡›¦qºmÍÆ¶Žc Øø.¶Œ“§Ø·}?cë;½À>¢»¬Ì=­Ì=Á¾#lmάóMkÚ ‰§ˆÔ÷tþ÷‰TÓùÝÉü¯O ‚,¯°uQ‘êûˆŸCl½„½µ‚ÿп@S˜¦ÝxŒ£pî6öí™tmõÆ.vÞBÂGl2ÞÂÎ/ŠV×mÌû}§®¯‘jkXIJÑ-}œºvqG©ëRݧúFTd×xåÕt&eã:ßMç‡`*‹¥ƒD;Ø7'‰ö°s»BxŸçØù î²ÉHøˆm“÷;ƒ€j ÄyÀ´4tázj˜ûò…¡k)"ØRmoZ}o9“2&G'¾»\l"¼‹„w±ï‰]‘Ïz^û>’ÝY$6©÷>î=Ïö1y{¹~¶˜ˆci¶kös ·† (éˆÿ‘]„0(Ü ÇE×änÝ©é‰`:ðšÎ÷ ¸ÌxîWŽƒzÅv*º«Úõ7õƒ+î--r«r¼_Ž­Þ%2¼òtJƾâ7¦Ž™m›Î¹àT¯Š÷ç`ÉœWt÷eÍî¶ðVí4èjí&%£åÜÅ·¤½/ÆÚC…Þ!²íñUû‚¬”+Mì}‡®ÝBú܉VV ]_!ÝÞRÇ™f™Ž4ûUEe [L–­66ß?Ü©8·ª5>(t–Û7ÿ¥Îä‘ßó¶*<Ý[Ù×ò€¡õ-¹§tJèËï2 Œ|Ù‘-¹Uû¨±“B‹Ì›³Ö‹FkO´ Þ x˜úêÏ®c, Õ}Z ýá­±ÒÙ­­Ä¦ÄFÚÃÕí1Õ^eϳ47Ïþ>˜-­Û™-‘rÏqÎËbÐq}‘ºÎé0øƒŒX¨LMô~•™Ç::9©è„ûè‘Nžt²P…и(–GÆ0ÑsîÚG…Ûo¡B¬?3WŸú?€ œÿQi³š33m>IÿrDŸ$y©Úý ¹ã_+„j]Â2¶c>OCi#È‚ðzsOuÙƒÞ:55V5¶Y¸³9Óò-BK«Ú6&+ªµ ü QF4Ê8P½€åÚV=cóhs&Áe·2ÜSÙx-EÈÚfÊ´4à Ö{«[0˜Y –à!ퟱõŒ†¯°ó’Öß§qØÀ4Ê ÍY©-?èÂJ® sµwÉbå!2³ÅNÃ^µ"ëíu`¼ð›À˜i#QÜpÏ87ªu€';Þûœx< ³¤“Ž!‰;ïÄ Ùƒ®zã8S÷%êà§M ö-ZY +­©4\8ìÍt›®ë *àö]Å–—²MI¸ƒÐ:AJ‹NŽÏ N£õo+¢k:éù¬ç8¾LàH(J`à¤d 6ˆ€ö¨Á"âÂñ*¯Üƒñ(cgD¹Bºk+å%ð$AB£™&†¥¬vqÜøFÛLi¯7Á™j Þ#ØðÖu†¿Á¥.¸ziQÝ´VØnãSP¯l=øOd‘o‰yÕyγ æ˜}‡£Ö&fÓÎhÚáÀ¶³€±÷Mß A" RP,¸7Ï]»Æç<f‹…¦ÉH[#“¼TI^-k5°jã xºª£œ '>ÓÃKl<ø-æèæãÜ/œW¼N™ŽʪG2²i¥÷ÉÌÛ7ãƒYT0ŽN7bÁÛ_îHxÉ%H ½ªºú|ùÞ¹õzm½1|ы Kƒ©ßW&ÔB7ѹ¦޽0푽êxu{……l#œ»†?/°ÒŸàðÛº‘è´Lf’Nüê1­sÎWÖí|ñ³-´³)§B”[ìw]ÄíXO p@qÛQQí8Fv¯maé® È„¯{>Þ¢ã³ÎF>"4_lª¶ù!b²NœuXžc1º“(z'ŒÊ®ö›á4ZCgd ÑMÍÐMÅ,VuöT‘ÄŽn¬'K=܈Òzï‰6x8¯ŸÀDa3 º²).ªŽ_îc„3o¨ó¼d%XÀZ­„0ÌM­$ÐË,AwKx=xcg³»Ê>éwöŽœÕ#„bê`ìâJ?”àªðéôÛ±«À€§MÓ‘‡ìÝbŒ‚&¯*<Õ-y$- |,™¯ÂSïÂUª®ñïÓÏÕã ¿9¡¹2l÷zÉÃövLjŒ· £MíÓU:®=] û'™IF=ÄÚbi ³ÔÅñ¿\+¥DÖ§¤+D÷9òW&]Ã^ï,ér]O ÎÔs®ˆ Š”+XÊ>yéU–r­þ ²W@d}z…€KlaŽN%z¾;Ç>zB TÀ ”.©$p\©ÐvßUF©¼Bµˆ³Êè²úLÎÇäXU9(8‡®“ÔøtxŠÔvãŸÿdi¿2E,©Ë—>Ó9(d £/ uÖß À™VôNÛQÉæ GO3ýcK«¨&|^ÌÀ…LGôLsF3±¶~šúʧa^º,8ïØcQyø\ëùSp¨¶B:¡Ò(~æ8´Vbe5Ã'ž¼ÐRÖ1"X ®[&é^ëàÒRдô¾ƒHa7tÚÆtá›r.‡8ëù»Ü”RTc¹›"Ì)h5’*•+ò €Ef,Сn¤[ˆ€S'ƒYÂ4˜‰—¡×7V¨¾¶y£åá-¿7A–\³¥Ø¶u¤²Ÿ-«e×ÌÀ"íùpp_ÿM´ã¤]Gè‘Ý:åÖ‰ì¸ÃˆöFÜšÖ ¡… ÒwŸ–ÚÁŽD¸#6ÇàHp¼ b9íÓÙÅœŸÁ”Ëj/Ûì`Hˆ,D)I”Š×ØüEتg6¯f,LT’ÍPUá¢Ü,& Õ})ü„³51uÈêi!áðÑ-;zòâ7?&ÎR™E'5ˆR@sš`Q6Xœ‚Z3º­:Aðà >¬À¾3˜–9¬ˆ§Œc¾ç¢VGešXtF[BØ{ïÈÍ`™ÍG‹Ü”jÿÛÞ9lSï±Õ~œÑ`68Zöõt€}lã½yìÖ?ð¿Cª—ô0ö‚¸hOz£}{'åâÿñç´™Rpä:|‹xæ‚3˜Í7ÊÛª‡ÉÑ_xÝ! )ÕX h’ü~E–¸&ààÚ l‘ñ4èuy ¿ nÏ''?NuÿÛ,ÁM¥9­ ëØDN'·w&7wîM_]^Mn~=•“›_†ÝÞýþÚÙšþi²½3}ø?õÍ [!Ë¥QçNñbó€ºÓóÚ—Ì—ßÌfßn¤TµkX:³ÅÂÀu¼jÁîÆØº‹€»ÎÛUzø¹èòe°&ëÇúµÊ"V/¯ à›nå¥6¡ð© :Ç0‰ CÁ=«¿ñ’"jý;†WÃ×T:Ü ‘yL¦ØÐü¡tÃÁ76©.)ûúó€Ò1vfel]"VùÔÈâÊUTkß>í¼`hþ@±ñ¼ºÅE˜ÑGw1² Vm£ºüá;¯•(·2G•Q*:û ×9*M>`™èÞ&$](+·d—¢pQa€‹1 P&»¹ˆaléFÂwqË{³÷þAE­¡FÙ‡]r+£3hW}\¯"ϱ·XXý-pÕ°ëóš¡ÒV çÃÂòyuæqÏj¤ôéâÇ”ŸÝÏçôíB¦ x¿Áº2U­/TÕg-=‰w*—~^àDcLA”н€ú:Īþ›¿wBjÅÕuá]Ćsï»j,¢_ @Ëaˆ‰%‹lõáRëó™ôi¡ÿ¹ý(“~AqGŸŒ«,Yé¹,ø&hTF ߘœ£©uFµj•,J*0y™Ï.~ùC5uüy#–8³ÊóëÔ¸ÁÄ›÷4Úµü¡O·Š£'½ˆƒ2| ÿ4~ÁI†WmWœäŠJIÝ[?Aè0ýÕrxÍ]–vEK8ù/6ín endstream endobj 1003 0 obj 3785 endobj 1007 0 obj <> stream xœí[{o·/ú§þéW8 @qWøÖË÷2 ø¡´nãıˆŠ^V*ɲ$;vÒ||ÞwÉ™!—{'Y¶4AkÁçp8ßpæ^ÎÚFÌÚð_ü»s¼qó‘´íìà|£ýþ?Øx¹!ú!³øgçxvg«&f¾ñVZ=ÛÚ߀& m­œ9Ñ6-ôoë”>Ù¾‡ôÉÆ;Û'ù€óÅR¶¢‰pÕ:Áˆ9[,uŒ2*Ññà ÝM‹"Yx/„™ßË»ÆzÃ׎C©1QÒùù6mpDØç‹…è`¤±ó˶qmÛÙ~˜Ýgë›í…l£U7¸W¢Õó/ÙV7Îtf¾†vMëLº…÷Õì80ÆKc|~»õ¯ i|£5HÐÖ. ;ñ-0ËéÆÈŒÙ°¨Q³@ñý|¡c:)‘h=ÁA”,5¿ß_–ñm8Ì’M'»DJX—蟶5ñŽéf€i=V ‰lÕ~þlN[0!Jâ/ºùÝE8 y`ÔÜËx ”µ Èñ> `Œ=£VÆcv&èÏ´0Fó'µc†;ZÆKZ 9\Ó ?¾5™VE¡oƒR-Á:4m‹G­ùPi=Ð+ ~TTøˆ¼¢Ÿ[tAšH1ó× Ûà}¯öp3 Ø(®ëëh¥ÆíÌF¥IÄ ¦Ë›ýa´ÊÔŠéèȸõkæ“'j„ˆ»1ÃAwT4²»g ÄÄž‘B ÀúRÛ¦km¡v ¦Ö„œ9¶W3¨µRM«|Òëû|èR: &¢ã&"Þ%“Í6Ȫ€™ÐvfZ¥ka@i,ú5}킃lû£tºr›ýæ·9pË%(t‘ièúd‹íefFšŒšì,ðK‹ªé•1½qr¦‰oa[ÿ„LÓÉHPÃØª1y=¾XøD‹6˜‚x±K!šÎy7ÜoÏ)ëÛ5W_K¸KÕ6F™i¯/µl XÎÏÐáDFX€F4-\ü.Íb:Ë–ÝŽk¹Ì¦<Mc.ÇçŸ{\–RºÆ—þWûF÷$Ñbýû á›NÁþû êŒ{¿‹´'›^°ãE;Îêi?ÙºSÕíêšsR˜–/Aìµ1.H…€°ßÖç[:¿6‚é‰ä6MJp¶^Q:÷à¾ÈPÔŒò£Óš›ð£‘æ„¡ƒ!ð0ôìt°*3°… CcÑý .žfdð6|¶Â&Cv› :£åˆ+`,oŽNúîÐÏ2`%2ãó"Ù 7´‚§O‰;ÐuÅ¡½ÀXììàÎÄÄô³ˆt-Ð_Ç!(¹´zKÛbóÔ(UÀ’rþëàž@¢ÃšÜqe­9kÕtV­U‚)غcî™4o¢ÁDœ‰A2@‡œYÝ5N1ÐC@v þsøÐ]Àr± l€¿ÆÂqEjó8L¦¦éC`ŸMMÝÄ l)šø 71?L3©)PUŒ÷éà,uväÜ8¬â—P€›fV¿Ý0÷{<â‹þ+@¸WØv‚_;Ø»‡mßá×öÂ-ZˆÞÊùÏðÙÌ^Éëæ2¼n°O¬˜w£ä#ˆwêk+}K Þ])7ÿ¥à»¬ñ]@œÕß[|ÿ ¦LAÙIó~ŒYgÀýÛ˜ðŽ—טõTÙK³Ìã{˜H_ѲEZµK Ôâz$Ì øxÍö:ßÂ]wùk¸K×Ü)Ã:æ&V–ÜÂBˆÕ9Y+ˆ¡]7ia•ùžsš‚Úu&Cƒ#t6“ûÂÄÂÇ#4f[ƒÒëΕjÊW7•Ò¾IMo M¯ZXДòÄ72 »Ôܬ¥øüÊp<"dÄÞD÷ë]ùìՃݼWÍÞkÛ <V{`±|!Üa)€rŽ«Ñ°þD$[G³5á›x+(pØ‹Ë9.!)Ôß»ãºÜ¼%È1|jîò:XL^ÉåÁU6ö#x¼?Àû;ƒ÷QP^“ryžú/äîÒG–kÜ;;@¯øŽêí•[wxUk¼*ú5ðoJ˜üŽ¢ßJŸ¼}êšèܤý¦ ÇF}½„ÙZÃÕƒô¨ š×§…¤ï$¸Õ´¼Ê.³¼Ô(•R`_æŒé…?¢\£ÀOÔßÐÈ|BþŸ}šH3@ÒKÛ=S³Pj[¿«ê·íGUýý$Î4µæ“ü#ôáCêŠÁ>?RÍ}½Õ!Âùu§kÊÒ‰F…Ô±8¥#;"CŠ)rU+³Ž«)Í8b`=äÍQ…¯Ô{‘ÚÂv›[_m¼œ©!bÒÍ„tî;ì–» Éó;÷7nÞ0»8{µ·qóÉLlÜügøçÎûðçþ½ÙŸ66ïϾšL©¯’“6<(ñí ÉÇHò.¶sâÃÊuód,°<[öÓÀp¡^+ºVÐËç¾­p ™ÿ·àö —"3dh³nåTFt a¹V¾ƒH(½HcS°JÆÙ|ÙÚëT Œ+XŒC1³»,óž¯Õg¶µãé½jzƒÁê€ÉôN ×x½ªÜ»¦ÇiÝácàRž)ͳò, 8PpQÝö¨ ²þ`È[6ߎœJ fÉÇ!e©ƒN´<Å]”?Kb„¾,žkÊüð(N “2’!°™£,ôUT˜fLqÛCëD"k%¦óŽáņŠ:ŠÌcVÔQÔôE¹`õ•/ÖòÅ1õiõŒ&ƒC¹ë]ÆËì³”]+xÚxà4Sª)¥Kj*¬”ãmûr€©ªikQÕ0Î5»öINïdŽÉR¦kœ<ý§ÙZ)ÓA³Þ¯Üx(»‰RBšLUY˜'÷û(}™äþ¸f!½Ju£J†¨ú˜} Õ&¯Ôܪ|þJŠ'Íf¢¾^hQ7UL)Ȭ°(3+K4×O2© }>ܾí…Y¸© #,^C@]!\¢s-¨BëC„€@ø!›;‚Öë   ñ‘ ;ÐEo]ÓZÐé#Èšì4{• ØZ:ÍÔ|ûñ.Å÷YO~ŒËàrçVâ] ò?\®ayg×>I‡°Uæ“ߎã½DGDåÎ4aÆ5&Ç[%*¶‡ÿ. ùè„&> N·½áx(÷É!“<Êœ¦bíÚéb=hˆwØAGNmÅZõ⹜„ž,ð›¼Ü—¹é/XÈs7°ÂZ©æ›ÃˆNÛùí…2ÐBFõÀ}yi@’nE±îðºeù…Œ‹B­âåÉéBm¦£° „~¬½ÜÙ"í‰÷˜CñMÒ~þÔù9ùa‘24¯Ïg†€¶¯_«žãêhR [süDi@φ]•*F`N €ÛF^Ì*Uðª—ëEx„Ë cÀŒE@VÖ58G&®Naú-…ª”eNŸöÝê #$·6ßdv¹‘L¿Ÿ¨Z΋p1¾ÿýÄ)7㋱5ÊÕ$Dç€õ|®ªâÎ+e‰Uµð¯ÆuäOàZ_§k‡PøÈ^ãZñ9]™ÁîË…Ç»°0#&?uˆð\¶÷á…l€’0¾K6 (¬Ê @è?!ë¼oöIÚÖ•Þ¤þ{Ìf°±T’ºÍ“"• .’ÝuÁZãZ¾HÓþŒ_µUÏh¶ë’2mJÛúdµ¿¡lÖA# ñqÙÿ˜'9çž:ÙŸûNÒ’,]Z7StÐË—Bz htW…x}À‰§‡UåO+aÅf;• æ¼$PòÎj­èW÷+ùÚ®–=!À\ÆUyïeM†œÜ˳g GK]x¾ƒbåü˜”Úf‘ÝP% &8.ã8×{"w ~†¯·•ãׂÉÝ•Ì9+ˆ _ûØKÌ>d·‡éÓjL2ä§Rd¼ ';¬œŒnû´BûNåd‡VŸgÌÂd–Ò8e×>HTŸ’³e»hËΈ©·Wék€I 'R±ŸTü?+Ëws‹ÇpŽâ"orŽëEÎÅA}£Rª5 ø.' ´ Ÿs9®êóXA~Ê„,æmÇ›‘ˆ½eÔïf»Ò{Qé%†þg¥6<¯ˆ[ù¦0ŒC=_QV‘ <ÞË_S–z«Ø6lvÈ6‹5óªhì«<åHFòǾó‚÷¹fÔDã„õ&¾ Éø Q\ŸGbHb¦'–NmÈ• „9OR·è_Œ‘ï_§6ÒîÍÔôíàßÒ—§ZýÛ8á1­w¼3$²BíI~=üWiÌÕ¯ˆtìÎ óý€t¬æ†Ž‹³äHކg æ+Uó%h¯˜‘.$6ù­èTVi^o àQ“êr8^ó„ ÀŠaÙEÖtšÉÖ„÷ŒGÙ/<öñÇè:Ýü úÊ º¯ÐW¶ª1Z©ŸolºösRÛëj/BîÝJ7mGù {1ÑxQ9™ëÕ«O)§G;¾)Æå—JãjiÍãÊÜ£‚–¤Jeatö«ŠÉȹ†Žj±Âoàdõß‹¤“ýLÞãnø„Ùaø Ìo;7ÿ«µÄ˜×•Õ±Ûzô6ÙÂ+´Oé hy+fÿ ìíÔDnøNjBž}ƒ^ìÖ£äoˆGk,ãÑSèͪ1èn/Ó-š>xßÓÔÔ¬èÃyOéuÛ¾Åñßö½Â´2|öZe†ÏÈ!DdÐ7ö>2<ÓjíRªeØD ?ÎK±Ê-²¹Ø,Óäü¡…dˆÐUùÌ@®37OgŸÜ,“‰I1¹bUî_cïcœ»‰mˆJåe±(þ\ÿ †¡û£•öRÓ—¨©¸Áýñ¨MZìAjû÷U ]ÐÜkÔ±;¡_¯sX¹^/ýNŽü‚EêåZ,F¡¥žç˜º> stream xœå]Yo$Ç‘6ì7þŠ~ìÞ5K•w¦`Xkk¬%ØÉ08äp†^â!™ÿ~#òŒÌÊêj²É Á°YîªÊÊ#⋈/"s~Z[øŸø÷äòà‹ï¸WîÆÕ_á¿~:`þ‘Uüsr¹úêSZ®Üà4‡¿Ggã`UxlÅ´]6#Ü»<øa}¶‘ƒÒ²õ½¿‚·Ö7›C=ÊA±õI¾{‘ïžçßÞç««|÷ÞevÐZ¬O›ñvùÜq¾zÈw/HgµàÐs¾þñGÿ«1ÿ8úïÆWGÿspô?¬/›–ðýåßþ™¯nóÝÒÝ»|u“ïþ³jÝï+è4ÃÈÔšçÛ*ßÖqÔ&wîûþ²ÁgR§ßåw¯ó»Í,âÕ étžÏÇN¿îòR5ßÍótßyë¢óÉr÷¾3‹¥CeÞOÉ|†Ù|¦“¤g ÆF‚$N)ŽòÉ¢p¾Òå6&ßâÜ)æÖÃæpœ0BÎüʯR[¼tN Ê©õ÷÷¹$Wßlåà¸Ô©/šQ]árzÌsw´9wJ¸õÇÍ¡¬uNà’#â†qpgy¸£ø ! ´‰Ò•_ºÅƒû׬§b:Ý·&ÝfJ€d¤OÊ“ä¥;ŒRNÊp¥GmÒ;ñC܉AT@Úçôþý¦MÃä³ô«€NºÀ μ\“_Ã\8Êæð¬7„ ÿ– ‹—¾ë ˆ4Yÿ‚‹hÆÑÂl—g¯rà#*ž„on P'Ðótû¦t¥j?ÿz^~½/í—™ûz-% ¢^¿1U0€¼ØÐþq˜-,mÿbƒÒÃ%”Ù=:y%syU>ÿ!·Dî–™ú.“Ü+l9'R¦”´^†ë0òÁ8¶þ*7ùß9Û07XÆ-]%òÅ[\F3Hæÿ’ùy£¦qÂÞ—y¢ªÜh×ðâ¯amèŠ*ß—lýGlT£³qj…‘qÀxõõº /Êx¹Ä÷å8p˜ðïó‡HGNÊåCy‹t/ §¨: å`$LÊÑFÛÁá¿Ä'•ò6æ0.ì!‚·YXß㢠WE¯@ÅLcEGAFåû‹Í)éÖ÷ÁFÙ×öûV~ýˆ^’_/ UnòÖþ @Ke½HÆe@<丫ãä Ãh쨧ʆŸ½¡=h{ Cè+ÛPÍ.sŽs˜^3€ðÙ0½Aj¥«†‘nô*p@ŵÄG (a]“ÜiÚË÷“õ èÒAÈÃŒÕßåOµìç–Ìé5JA¹±0v4L;˜5LÔ_lŲÈTÉ­‘stÐP&¬¹vÒ Ð Þqè€Qïp"x|`4J‘\O¬^~¢°¸œ3¢¸øV­¸ÞpIú³€´ ²V&¤%]©!Ì¿Î}à#Å_0mŸÈ¤')L“Æ»v†ô¾k&Ÿ¬cz!Æqp‘ÄÌkiÕŒ¤4h!~Ö÷_K¿ž•_¯çÓ éÈék¤“a ’øš~ èQQ{<õ3°±ÓòÀР®·M,ð+ë]>°‘Kò»Oy%QbÁgC§‰`ØÕFŒ¨‡ÔÔkß(jÎOVjÌá-Å8qÔºØC¼³ê›ù×Ѷx=‡™‚ëÞÔíŒÁˆNRåpøžCÜ"Z='íº}RD#'Àh‚9ûq]LÏÏŽùŠ À»üãâB3&ÁHþ¸AËŘÓûê«~)¹žÕÝ4þ»èzA'Ï«‘{¿$ÂjÝ‚„ƒH€x›ÄD’Ë÷ÕT®…Á>"‘i}Œ3(L ny.ç1M™³-*ï½ ð¡ÈÊ>t•p‚^¯ºÏúašQ‚ JTž|¢ÿ,A•«4b9ÅNÿÀqi÷¢´05Ø`úè:Dt…u=ÚX/6Ò›èÕ¡ÌÔNÝiå¨ak.§ÈE€#<ë–ÙNç7ù\k´¿4%A¢ÔàF½üÙï³ãPBÔo6cµ3û¦ÄxíÆ-mdš <*ßhèûä¯ô¥QZºA8¹f‰2å~G_¢ê&ÕÀú- f\Æ™³ à½’×— ^ê4xc¤Ó¨&î@^õÖ'à3‘¥:N¤N€ÖŒƒÕb:ƒPüÚØÁøV€Õ¼ QBµòôŒÞ»Þ–—ÒÚŽ ûq¨:àÛ$«âï?eê£O§Tôé¨ã£kg%X`FV)ƒ‰ãÅY¹)@’¦H;Š)}¤ù}VΫJ“b ã02ŠŒÄ]˜HG‰‚Áý…“ð¬ÚñøÍƒ÷]š%Ü8mÕ lIÁ;‰jä³ÕvtroÅ}9+–¾ëýT‘ ²U¥?]²˜Aè%ÛÐËO•fÓ(4ªeEè¢[jûc0¯¨†g—ÔMI¤+úê¹èž4ž¸q`Ï1]:®V/ÜlÁ/7ŠÐ/`Ê­mñH|…Îyà°„#…b"Z]Àä¦ 6-«æÍŽ`Ôƒ!ÞŸËïGQcŠr]ð@™ @;@ÍA™*œˆÄžÔÉ™¬õq–ÕeÖÌë9?ð„!`Îzb}– HÂÐå êÄÈí€/ñ4*Þg8› €ö5«¤x‰Ù<™Qé¹ðWßT‹;Ãrÿˆ}WÊòYO„A0/G6×>Õ M‡[q(1ÞÑ#6–Àã¼²èeÖ’€Äš¸¾ÑI¼™ËOðÈö @«çü T»Šœ„á3ï<4jGü ¯¶§iÑ+Wû:õ´B± ý‰mµJoÔµÿ9ßÖÇ$á¿?5¿ìb&Všúý ‘ý©C‘(õ СHkÔÙ\•µ" N3¶=Ñ×T©‘BWøI°Êç[ !°ã3©° ±3Ã~—8!³ß þ˜q¶‘ß |LΞëŠÿ³3M`ÜÕÀkFå¶Âª4ÃE—ßµj)䮞L iÿílp>À¼+G(“Ä M\ª™ÂØÀl(G5ǶF>äUØÖšZ )g’æ±EÜ­GKmð›û\ÚšÏOŠS+ZH‰·Ãj¢§˜ÎšÏ” ÊeB¡Ëˆ“}ÓU“— L-5 P‘÷Ê R,szdbMÁah‘….ç1ró¢}WÈ6GBÌ6QÝNDŒq!I¦·Í€,š˜ ”I9íÛñ†Ã4€ HdÎ*mçTž{ìÛ¬8%Ñì§b‹Û3A‡Æ6f¯Ï ΡLTª é†ÂË–Úr Å…Ÿ·E“H>*IFOº¶ˆø¥ÝH$ºfgR".õ  n½°ˆ„²ƒ2à FÆ—¥Páåù"9§ág: °¡)0)µ©¨é6:ýÜ)yº¥%O_|{ðÓJ„2=˜-»bÜ ?q¾$ïäòà«·_¼ýÛêþöáýÁÿ·b_|ƒÿóÕßßÀŸ·Yýîàë·«oŸSõ†ÚUã¹é”¡•ñÜ“º®x7™&N?‘ ·˜f°@´ý³,ži²«Õ0‚ÛšëOø4“F.­ 3XžõŒt{‘»ïdÓý?ײZÓ÷ðrd:õþY°Ã»Í¥Ç¡Z-–ÆŠî(Ùt°ÆÄ±–âFcâPÙ:R.@ùGÖ* ¶Ð_¦1Å+é@£¿Äû€«•ý¹F3C>>Š4èÔ3Ä·ÎP†Î®7&Á@Ûû ÿßÄ>ÒØ639 J?E{’ø"7•j‡Ææü¾¾‚õµ©hÚþš2H8.ÛÝ ¡¸¥@"ÿg¡„O.ýÚ¾P¹=I4ÔñENãè̼&#Ä]ŸâlË{Zººb” )O±·SUçhú~Q'ŒÑ#¸t  ð#*œßÇè +riøe¶z ë9»Æ¸Æ¹†v¿^Ù®1?•»Ü«H?iЯI­ûÔì3~º4\Í4®Àg®VÕXKÏ;cý´µ°ûn'ˈe3ÁO1`Í*}ù*Y«Rò~™~z—.ÞOŒÛö>B|íÓÏ´ÖibC”ÁµBâÔv’tZ‹8õ‘`’’†u8rÆÔ–`nJ»Ì11&ÄuSk$h¸Ä @½ødÁ².{/˜­£™Â­@=P,œ”†µE)2*Fc1a½Âæ—ùj殥;®ÜhKLݵ*Þ€(6ŸºÓ(€l®’½¡Q,8P‚¿ˆáñß­¨¾§xHm°ÊÉ lÚUkZÛfét¿ŒÂ[¿TMHÚ=ßðàÿ÷ÓhWåýRô]{!Xüš“M}Bñ!JB0’æ¬Ê·Å›õ÷â²€•C¶$¬½š/»ñ]æ)›Ö`ÈE;‘Mþ¼K¸é3}:ú¼«Û¨0Fø|Ôþ Óñ ï£ä×0QºÜ‚«ªÑ%úõBDÝêçà“òõ åSÁcd“ú”êÇúkÛ9Á¶·yÖ( àç/¥ûãDpU1$H‘k!k=ê©ßÕÒI?yUyu,Š`í¢øšp7§Šbd¾hsAË퉮µFeƒðQÉz#ÊÔÎÔE;1¥ÎR’Óßø“ ³¬´Þ£§y/áÑ5îG¦ÝÄÏ /×^mjWÇlVçƒØiMN$czCV‹zý!C¸¢ê1“ÞO !»¶~ZË¢Ú§·Õñ Ǭ=E ¤•‹½JEÞ1Tîò˜ bÄD×ë;S±Ô³ªÇÙd1K£«ÒBEÛ2ëP{àkæËJ=vgPÛéA`ŽœîV)¦íuÂå”åÄejÑ ?”ã eçÇv\­¦­EOjŠ3ó›&:%ËpÝ +u[>åSš9T>^“ëkj¿»¹>”;S[C7|™'¦,q”* ²æªÒËë”JYTEU.±$t¯U»'1veóE?ûH\©œ–V”/«‹RE»‰83ÖçÅãyé Ç㉟*L¾0©H(F=ÚÒŒ@7l¸ŽyDõÌ s1A-L©[@cÊstR»ºå²ÓÆ®nqÆk\Ü}GÄìö27V¬9š©yÊ…R9µXü4WðÝëV? ¯Ê&ÓnƒnÅ¿qµ¯w/QD͹#‹›•‰a _ÁÎ#Ž¢›bdêª`²SÊÝ\O7²=÷*j79“ *ÄzÞìŠÔ …,µ¤årÕf¡X¿5®ìDFíWT–M53V“[<Äÿ k¾ZŒÉ­!ü…U`ýò„õö1 L~†1 _ñBGü zŒ„_°©ù¢£*˜lx$²ùÓ76Šb„¬ Hb›"öFWÓ.¨ª¶[Ê=\d‘óÎ16ïðý-ò^D’žÉçRìYïævË•QÆÂ9pdëü©S帄&±DB¢˜™f²ÎL§Û)N•Ûèïè@õzRMjL¨Ë—ŒF˾ W¦®_cù±ld'[¢â°!ð¡S¿c¬ÚxhGLçÄ»¡j|ëBÕàð€™ÓykÉ|Ðý¸×Z¹´ëB¹OÜŠ³ øþq+´ã^¼ãVÚå»&¤{ŠÃ·~–…¸•hk—ÉpÏóÝë&8ß24«|ÆgšuÕ¸ú‡îV]áb§scO¨®€pÕRþ:ÕX‚]}f1ôÖ# óŽÕ´Ìêž[Y%k"Úú3¦.²õ} ïèôó}pZa×c/$Œ]è'Ö9Àzîók!˜?E­¦À1ÂôüÎ!¬Ï#Îó…3 yߌìpŽŠ€@Lj¶ÃÆÔþÌ®Eo„L¹Ÿ½wÑÏ’µÏq¼,=R÷gg—í…aùš8ÜrªKX<³ÇÁw±þÁw)ß¼F£{u]Ò)Hîêį\,g¶CÕŤʶë¿.˜tûñ¬Öè–Œ2Ÿñ³ó+û… ß·9ô¬çûVš’}ß™TqøúIÛósS&ư]¼Ûà&ŽICÿ½|Üi:Fw£F7$M\[~Öûp{» §Éµ—; 4¿Þîg'¶pë…ø/ÎÒi¾[l}¯´õdz·kÐYÓ'f Úwß§ÿ"u—3Ñ9b·«š…|’e³*>Þ031ãt»°Ýá¨Ë~9ýܦÇ|™v«jÖ‰pw.OBÝ–rñ¼(%v;'øô>2ÆßŒ¦åÓÊŸA‘䤜Ó]ROS[ØçÄ´åèí~†}Nt@·Áoÿ®wµqJ}„øY3õ»¿ÁÚ"´6T>u íÆ¢Æ¤I9`¤9mMÿ–É&Ç,Ÿ®Ü£[C•ç3óïÜ¡­1sñ”ÂåÅ£Të2˜¶¬s‚…µ°aö‚ áëi_6¯žd°AT "§ÑAjÓo,_•Sño›ßðJä»üiÀ€‡fËß"2T‡û3o¤m)~ù:v¯¨É̤ÝGsà/ó:øºª}u.,hN5 »ŽÕü¹±•…¬ÝÔ¢Dgùnkgñê—º¶eAìøø­èSñ+ûÎh‰Ïú[ÿé¡áþ ÆËQ?â×Q½l´Ü>ª‡Û%åÈ_[õôh^}3`P½j@7Õ+JÓÆŠumV©‰»ëÜ=nZ©ãÇtZÕOáõ%§¿uÜéŸ}hXÑþù¸ù_}PÛþÕïã>ãà«î¿úðRºÍÁ¡9–¶ä:¼TÖ«oþØnwºendstream endobj 1013 0 obj 5245 endobj 1017 0 obj <> stream xœÝ\ëo·/’oú+îã]‘[óý‚±“4.ÒĉU´@²,Ù†õ²$'vŠþïáò1ärïôt€"H´árIÎ ù›'ïí‚ |ÁðŸøwÿxçÁO°ÅË‹¶ø+üûrçí]ñÏþñâá.v³jáo„Q‹ÝÃq¾°fPÒ»…ål`ðæxçç%_­õà<ÓjÉ£ó^.‡ÕZ ^)o~Ùý ¨M5 œŽcz3xÝŒy°Rƒ“†< OðÙr/<)Ç—ÏóÓQ~{Úpº¯ww~Üy»#Mkx³àÂZX΢æïyµøÓÎ×?βhž".ÙàEEPYò^^ò‹ÜvœŸ.òÛ—¹­ô{ßžSrQª¼'.d­aba¼¤Wòõj-á•uÀÛ,®½ÕšÆhn`©¹õh„­þ®Cé;Ú·îZÏWÀrØhryYÞ_ÀBZóûÓ2×9¾ç3ÕWe(2ëáŠûÁ ®–Ÿ¬øà%gj¹Ÿs7(ã–ŸæÆÓ4 fíò·Õš –1g‹8¼d–'8 ì†ïL¦ï_å÷H?ˆUsQ×Çu¦úNGU¤˜ÉüäóÈ? ¬Ø/d-¯ WÆ©<çšÌ…'ÎÂ&°jùÍŠKxІ,*ñ·^@ùüb…[IH«…ͳûö ™}¯¬é¤ÌNVJÖÿRí«ê9(ül–Ã(A«—gtÕ]¬ä µbù.÷<Æž^h“{¸> `üÆHy=¯=sË_Wfàp¶xó^0?€¬Q”‰jÒ!òÂ0=3ì^i½œlÅsÒ&Ë[ÉÁzÝýŒáG€ÿ1ÓƒÓ.!ž=à«¢“~6b63·Â:î…5çÀaÆÇ-qZÐþ< THºF³¶÷8¯Ðj@¸ÚïBÆ”2ì@P )“°¥¥Šì­Ó¾ãî™ÂÁŒ)󱕀Ҹ§@cõ‡·‡wŽîÃÌE·ôFÖ3*ÐJ¯£¾ÔÚFD¯0lÃA &A~TÁAD÷òÛè^XÂ}+^˜öÂGQ¼™š³ŽÖýÐèÚZ¯þžÛ®§a•„»­†m·%ç·P¶ÊÒºye‹—Á“p:"µY þ¹E|¹ZÀç³ ­¸¯?äzTNHÑJD­ä¡VQýñûD׌ð™º^ë)Y{‚Ä­N€]~ïÖ«N~$ë•tÞœŠÒSÛi~z™ßž4g Ÿ.óÛ×o3«®v޸ؽµE-º›2i©øü!Szà¶Òi¤CÑ^ëüýÓ ˜½ãSPß"xÐNúÆjF(1hÇk#U(3XïÉLõœZ{¸XcÄî$³“5ÍF˜jxæÖÂN&cbw”œ–>ÙQ¿K›AØ–áé[|-¡¯¦S$DÄÖµ# ˆURo2 5T‡UÓž¯&ò…áßu·À°j`ÀÃßV`ZI ïio¡oRO•v0¼ÿ ñ(¨ü-È ­ïŠÜÈJˆÜ@ZÊöÂ_ïæ°,¦o¼žãj@Q9Eío2óû<ó ²ÁfCór¡¹#d›AÜ3 çѧ·ø4DE•MExPé±-$k)к’µF$§$Ÿµš¥H(~ƒf®eº¢¨:à p?Œ >iebÆa›N†¯ºÎSá:$’©§ ûïUå‰¨ÈæG‹MdÜ~‡ÓVð– 750Ðo,O5Žp ;1†°Ü#ú¸–ˆ„€we0B÷¬ÚEkÔû Ê5fËYå†bŒ§05Å6• «‚má©2ó÷¹ð ÷ÔMÃ1A0j>Ú3‡Æ‘Frêä½^ÌÀÑ=/à”i¿°<ø¾ë¸è.±‚I¥ÄjËÁ¾°€ÇË.>ÄåÙAyÀDÑÐêIÔ‚ìì£Væ-2¹^¶Øï×eÖŸòTݰG«’GJÆŽ'œÂ´v< ÖõdŸN˜ÛÀÞL,M8?Xçk½5 Ô6*Ák@=`­ÌŸˆ¢ÊPk9›x†ŸUð&ì–ú@“ƒÓÈÛ2%ª-Ün,"£n€mÙÙ÷0ˆžœª?š8™b¯—v±$¦ô²L6 €q¬²ñcÈ&ÂÄI b$U pMLãÚÜ ±B[AÊa´gMߨz[z–¨ÜÈ"…ÖR÷£äôÝEˆˆÐòvhGÒh»K9®ù¦²cæ¦VÌ¥ƒ•cÄýª|0²…óð¬ò‰v'°ôzBÕ¶ÍI&Z1÷N’ÁcÊ+š*{¸ÄAûñÕ«8(œDÌäx„¾Š!J99—é\B:¯<ÀQ‚ÊÆÉD×Ë¢ö€}f<0U×N`ú¬hÏ—ô(¥Æó²ÿ÷ªýOÕT½EœA‚*âógƒ´‚v<Æáï-ѨaqÂéé‹a˜Ea.ÝpU¢"R¼Š®«’ĈÊîw;»þyù]ñÉjIúMiMa/gæ=rã‘ùLh˜<’šÞ| ŒÅ¥lËní0¤ÑzÕÉwÅHŽ•êÚñæ„Ë!¶n¯à”ÃòÀtæ<ŵFKŒ Ç×7\λ~`‬²C8±5€.…¤ab_&6¹‘•Fƒ`RÝAt*Ÿ¨×7£Å£ H!Y<'„/h°ðÚ.ïÓW<éi–'…& ×Cž¸CÌÕtL­6+„e0K{¬²*&HpdâŽP<¯ÍгmK‘‚CœöxqaŠ‰ËØäºò6I‡²õ»Ò©TîŠFÎ(ðlä<ÊMÂ0ýÞø¨<óÔ+ªÝžŽ=TÂs?å¹ºÎÆY‹P4Îç“ Ÿ rLwžúh†®·S`a6·?Ph-l¡fxz’…½" Û"¡bp`÷½oâmðè´»_¯ ÜLcpP™’M9ËÁôóüT¢Ð%ÃsžÛJLy¿·.YŸ‹& =ÖU¬ lVŒÙ¶ñõ«Üö9t€ÄgÏhô^yÑ™¿ÄÒÝøößùé¬CYéwI([c #‹ÿG¢Ù¦~blR …þ½Ok·A4¸ìQé–‚”’8{ßYÚ~~{Ô ø²Nšå–QðmɈ|èu@ä°6`GKm@µ¤FŸŸL$2?ŒBr )¡}=b{äì7©3ŒgÉyÑaE›±¬™ü¦Y‹E;} ðJöˆ(öÈ(õQ—õ\;YExsÞy{Ñð¡ÞÁ›wÿagÞò- žq~ÐÌnìÝVN!¨àï$Ä Et’D‚£ëö€ŸU¥XH‹:¢ @eà¬äî½D²ßÊÇV,…‚ÞëA{½ü*š ¶Ç÷Qc éöp¾jÖÇ|[äèlÂ40•ò,¨Ì¿'zé)2zà\üaI ]¨œ5i4üÄg ú}³—Q˜ŠvÝ÷ä™{£H^ÍJöBǰì—e½ˆf£¯²{•±˜:t³H}«°ªK‹î…¯‹¹‚4øMyÚFÒtR!–Xä•yq­Ê=4‡õY/MÀ=ÖA‚Ÿ·UÚ:XÒªÍA¬NrS$ ³õ«È°ÀÊ:è#:1Ý&®I\ÃOsíå²öh-òT–·£0³Ió9àÏ»6œ?r|úÖöå4:¢]ß°îŸÊ‚)z¨4 “ãèízû;›œ_Y­iU2¤ˆ¿pRÀè—rZeð~Û ¸ˆìûн=ÖG©ºo&)@üán9óH%I>Éf¶oÁ§ÚxÑsï&¢,â},C› ~|~ŠÁt>¡¦‡¯u’êÈŠ¥%š(ÍZ26p•LT,’IÓÝ­Ÿ†‰“-‰° µ’‰àIŸf×n.ë‚™DÄœÓLaà ®ÅÜ«yàO%QUƒ¿D¼¾« 0¦ý|§ÆŠ;?“ß}›…÷®‹¬ç£bp rˆ^ Áx¸´$hÖ¯t™¦QdŒ]ª›±È\÷ž®Ó¹™ žWÇ,툾6Ø++xÞÕ^M &N1\ñ<‘v„³¡¨©'‰á1ÍÌ¡½)ù}Qb­Ɖ6±˜BßÙ¼r”Ï–p¼!K—,ÏGVÚèy­~’Ÿî4zN¸³Í8~˜1çC2Iø ó&U:¸®~½ÙO¨®$Hf6¸³ÂzÝm®hÄ‚¶½^פ®•§–ñëÆj š•έծ/Jzm”¢ ›½9 Íïèø·7Š>lÝ‹|ÈB¾”~^0ÇÔ¼ ê*ŽMUŸÐƒ¨­»«ô»JÖ@ØÁ/uîH…mMìEÛšó"®Ë º `¦`B™1Ç„Ùmý™+sÆ­Ù¦bfM€¢.ÕÛv{`Cš @UètF‘fíÏ7n_å=êýÜœCg§Ê ÷h¿höçí÷M%öä}S˜A’,ÉØ‚ën0 ¦””a§Úk©¯R{ø  q.>í„•.§Q„좗{æpàÈÒ ³LÓòª/ÇÚ’|Ê¿ÀÞ\Yµ®†¼§¤´ñé )Ýed k øK½$g ý7iý?ƒ¨-œVÑ6<í|ubn ~çÔ Æ.x\ôŸ¾aoÈ}žèŠOÊÛÓ ¯òU—K+„˜L„ÿRsIläRF®M±æà2ÅVup¶*XEï“Àêë©îÖæ&” l,Å)j¼ïÞîwáºàjcÚ‡‹(ÓÔ^¥”Ÿ„–l0Á¿ZG‡"~¦¯ Ûh½j`–˜¹ŠØ¤³C}‘·="›ÂC>­ôï›'cæIâ]”ií_×R)¯‰¡Ò¯·žGÒ Â÷cq­‡Ýƈ>JŒzêW_ïÚbTñÚbçâj&àK}ñGÜFãp+qß—}`ó‘nÌzN›µ×‰ÓMôõz@ÕkF‹vÃG¢Ñ‚1EI,ËüÐI¼µ ¬«^IâX–“Ö_’¨Ôv,„I!Q0ÚmUІ\ÛDG²~ÈõÙ2¯aŠó©Ü(^ð-ñ´o²³ñ£ÖXnH }HMO)ôÕ¥ñÙ*½y83FdoΜ)üÓƒi.ÖÊ[¡è–ûÿ% Ž5¥ç.à” \òû‡§d„KAÀñº¥%´5ÃGb†×xÀ)3Z$)ÉnkKŽþ‚±G¦öîG®šÁ¨‡Ý˜À¨ïà_–bï^ƒßqþ¯'Û#êVˆÃîßaâcÝßÏÔÿïE‡š^ÌÑ Etø(4hl/4´/µÅÔV¼Ô¥T´âå:¦ˆK¡•ã¹òȾ7÷¦˜÷Ûn4oÈÁ%g§L|Ý 1Š]Œ:[åœÑŒiòÃHæë_Ä Û]…ÊQÍwp*}?¹Ý¬¶ÅAÃ-,¹±R&¦èþ¨J™P"_ÅøO»;'å혦<¥²Ü^ßœZ_–’”æGƒ0}¥ˆšéþúQâ,eÀaɨÎùî!çB9lºîøëø¤ øDÓÜGý›KG¹l]Šä¬÷khû…#¹ Úµ9Ú˜ŸKBôTÞ4íÜêꤧsÂÒ(E{ó¼&É:(iàd»x-3g*œ8ï]àêÝ» ¼Ñt=d¥Ñê`ËDµ·%õ„¢Ërï –åÔ)â2q,bVdi% 1‚'^§y«4=»í^rÕµ¹Ó;Wß²²ð¡(C>«´Bç*JJ<;M“'g¥•‹õïÅTþkXm·®‚ÌUgúÓ¨ärøÖbˆþ9™)-k6ú¦ykŠJŽàJ9>};±s¿ú6Fù<ƶËuáÀX”bYå’F)Ö¥¥Ì”^ýž´{•å’¦Ïé÷ú,îþèO÷§ØâoÀ†èߟý!µTLñ|Âàæ¢  {µ˜±Ò§Š@û[ºW2«âêßîhoÕtÉFz.ËžT¸õOJ &¿ZϪšZ›ÃŒ¿’§«ŸT™Þ€ëþBD`*Ç=¯x˜k“,`"· öù¼=x…”Áœÿqç|ÞÉ}endstream endobj 1018 0 obj 4474 endobj 1022 0 obj <> stream xœÅ\[s7rNmÞø’¿pÞ–'µ î€k+U+Û‰•h½ö.“<Ø[[© KIK”V*ÿ=ݸ60=çðˆ’·\6Çsf4Ðýõׯü²™'±™ñŸü÷ìÍу?K;o^¼;š7ÿÿ¾8úåHÄG6ùÏÙ›ÍÃS|ÌéM˜‚•VoNŸ¥ÄÆÉó4ÃÍ7G?»Õ“‘:ØãÿÙž˜ÉûÔñ“xf£ßl\ép| A‰Y¿ÞÎЬ1R?ÛžˆÉZ#ìñ»­šŒ Z?h¿³=™'‚U†>û|{¢'£ô;}Ïup³=‘ÚL¹ã¯I[WíµËúÚoêÕ ®Õ·­ÒëMÊEë55„0Ðü‰”šeÔÂ(h ¦P9¸™GâÌTzÒŠ4v¶.Nzȃy ªõŽMNðú´1îø¬=ФHÒò×Ó !èJK=)üæôñÑé?ÿtüx{¢&Œ tÚ®Ú¿jwßÁ³s˜¬dÈ[0t%ܤ•‡¡×ézK—³­±“—‚®Ë¾®'¯U¿‚p7L3LÕ—ïÉõ_à©&E´Œ¨SëÿÃÖNB㠥%.‹@&6½nÂŒBÁ£r!›ú¨jÂ"ˤ¨#Žáøe}2wjazȾÊòYOU¨Ó‡~RÕìDߪÅ‚ë4?nž=(Ù÷äºÎOÕëÖÔÅÂ`q„—[Ô@‰Éz‡Ós€œ‰³!Žÿ\›¢½>¡Ê[{xÒ†x…K`Ìû‡zõ¬½ô¶ÍÀ?V½¸Ú ?ÉŒü#* ŽÄ×ë´¿o—.ÛÝÔÒ—ÕÔÂ屯»OÛ³d6bcnF͸ ˜S/o·ŒI{‹+ 99§ºé€UTJL)JD¹²FIY§ç~ ¡xwPD\0Ê—¸t'eíN„L«GŒú)5êb3Äèx¿éîJ5Of6D<Æ5Eô.PÇqÝ.—k^1VKp7oðfÆv^Rd®c!°ò à•õ=E'¬0pTb„$ƒá­•†sœ =9+¨ÚßV½æ0 ¹î ±í|ót K{˜;“:Ë£LøÆ}ŒJ$yËE:ŠÆ 7zt–T“ ùù¸¶š&$€ïZLˆv>4þÜÆüó~7ؗͺ³^\uÚÙ?ªrLuÚ“þû‘hàyÚíPy­&i^{` E¼ÄàCðZ]H@ èq]p~=èF5ö«#H‘Š*€ÐL÷šÅ£‹Î4;+’nH˜ôšòþdÐÁóÓ³¿v{±#bÉf–¨Ôžã´ ô­tþ˜u±£¦‘¼dû¸ÌqŠ4Ä>ùˆeˆB”-awD‚—‹wì¼ 5ÔËáŠjİÙ™KbJ×h@¼‘ør Z —ƒ–Jìw¡c_—™ÜË.Cò¼†:|lØsz˜‚DPs`ksótëA„Xc1=x‘üT:2¯ãIq©Âø;$<\o­;BÊãô³î`²dyfEiÌ"µ2ð©}&ldUBPù®8˜Å¤ž÷ ŒòX×µÓM…ºs0zÏ]sSß}'˜D.æ3pSž*°³‡5·q[ÔË0tÄŠ§¬–°iDâŠê!ÜZN'Bš…ÿ- ¶Î ‘‘èô2b’JŒ$ ÂŽ¨¹®ëB¨æðrV2®p+¼¢‡ˆ~-ãÌb:½ÇpàcvjX13®@"7— “KP¨*å,³ˆ+HÈ#÷I>¡šµ J‰Ë¸àFt[fD:¡·±asßžýxôËF¥T>tä7!2Ë8I·>:zðè››·ïŸ=øï8zðþçá_ßGßlþáèÛG›×7úȬ„’Áb“Ìd´Ë­ÏêÜv°ÍäoH[ç×°gÞZë¬Ñ¿Ã¤^Ùd&0»Åg=FÛKe(‹ƒ+ ¢­¢ô3@®$F¼Ðg¼I¨~39öW£@ÏS®MKà`t›ýq1½ eíK7Ã{«{ Z3~.oܵ•"´™Dh”€ôéœÌ/€/@n‹&ˤ5½?fÕ÷ù¸ ÑßȘQýí2 Ä÷ÊÀÜæ’A$uaò +œ×$Ê™×Y~ݘÁ/ï>PêôÅhçy…ÊšLŽ1™,;tñ“ÍŠÀsLA&¥uê bEymfÑÙ1Y’æÈv¡4”r¬=¥/ ØôrÞr´‹m²ö³ C²™m=rM¹F*@œsP2¤ºã²è¡Ó̦÷µ¿@RŽ檚ÿ'#ɉ”à€éD¡ è0)×í¶´ ¼Û“ñ(Œ¨øÃº_pÛHíy§ÏÅ'c ÆéÍò?2ó¨£A‘1«Tœ†ü…ËI oºÏbŸ6^¾¢i*`´SÙmZäâ@Ì¢:ÄÔ˜£ŠÿY=Wv›lf¯»ý¾ Å}Ø‘¸[ŸäÌ÷x¢¾„ ·EÓùŠäÌ †oEϳ7­à~xBC:?Ù°žµ×Jj~t±u»\H3‰h;J“W¶i.% 퉑òî§¥q7Tƒ„ðû£.·C@~˲fidîÐi|Ôê•„jk`¡ ùïã‹^­á­œ…´°aHC~$iÈEà¯Ã÷ûLýl)[îÞîË ¼¨— [²†ptúeã$ÑWK\±g¢ûÊòjþìK†öèT´XÆDwÜ{é˜1U7/xÕo [êlfÛ×éÕ$•zAMÁ‡;ílFªhWXGæ…#›¼²ÜP SeØô%‡,ï–α€\pðtGu>nÁÏ)›¦"nb:ÃÎé QyD™¯ {9ÇÒÕÊ5ÜÕ4v>¡ Ý8Q‡/Ò¬Ë"6nR[Šî.L£$Ix¿ÌT"âpLbå­ôs"«‰õPYdq"ÎÅ—Ül: ûüàIÒ” +iQ•í"•Š­•!Ö\Qû-¾¨¸X*A6஺$kËáQdºXNø!qþ¾yÂ‰Š—3nQðk'¡‹¾”À°m`eÄRã ¼à•µ£_™2­fï«Gþäß÷kޏãA¥Ôøg |ýf‰*|á&uÜ6F÷Yc-.ˆ#w…e¤)tWX/„c/1†ÕBw±Y, ¨–g–Ýïæ³·Ö„æ–€íß·ïx±€¼TÀÈyìÛ¼~$ÕŒË\U^ˆèh•"càà HÖ¿dÇîðÙ20oû¼mÍEÆ17ÛQÒÑmw„¾ìÉ­ZZN_°;ù¯küª¦“!·wžŽØ= ‰ïnÎJN`µÆˆÍUó5FÅ}6×@˜æ:eñXþ'÷×¼{léÞ•M½5ª’òöR1IþQ‹_ãjÎáÐù&ÚBЇR¥ºrºeÃjTnÝ•ÿa«Ì¤ `ç×5÷$Rϳ?·<¿ªûÁ˜q[MúöµÀ½Ëc]y2»œ1fH»61ó–ScûvÙߦ—¼’Ãóç)‚êÀ¡Ä²r…} ͈¸ {'íWXÈÕ r”“¦ü­%bù]¹Lq’_ʉ”L´ö}(¾;;Žñ½´ûžîŵ}*Þß¿çÐeÕõEâÆ Â”rTw‰²s Lš¦bALbPúËæñXvÚ"¶‹3ß<¤V‰ç Ìön5BÈRýʾç%Œ1ƒsïMvZ#îmQxŸëµ««<(äï|±ö)øøÔʃˆTw`U<Ç’Sˆníìd¯7ËŒ1}ɲ{—¬n‡çäAÚ\”é«z“wV¹°¨`dIIýÓÂO­¢1â7˜‘È©+ìê Ūà•MÀh,më;böÄN9[ü å 1è…UÒ]óÉrbჵUPs ¤±¦ÚD“SjÖžŠÜŽÑ"gµÑƒå´ =Í0r¶ ¤±ïW>ðw+ŸE¶äHnÕ$*iŒ Ó71¿#‚<þ‘y¬â‘¿¨î*,9Ic UP_  Jû×*Ç} ÓëO^Eë;áBN$iìtk=’¾Î),>Ó0’Ráò«à’SÄ«âd¯´±G5:#¸´C‰¿´µ ¯Ö¥ÔIYZj"¶o.´4쯳|ÖÕOq‚äVhcmuþ4®‹°CÀ˜IFfÐLÞ'ÖÚà!8´K&Ö¾>nÐÅÚ$ÈkŸ8«¿vAsÐD€5bç0ƒ´ûŸ4Ù[ŒÇ©¸ÜwÚç+Z¬zˈ{3Þ}·a§JÔ‰ÙËÑú=‘ .¹FˆòÓÇ–”Òøû”“ßãðb-õr|"q-N‰Ø+ç÷²•db9Ï7|9qŒªÜ°³ÉŸYÝ+NIJ>¯Û#$ÂÙ›BÔMàD`!dlIÝ j‰S®µØØ@(ÛeûZ]¡‚åVý­ÑÉërëY¹8ègúÈ’J(å=t\Y|Ñ48D}ÖËÕjç2ýu.G¤¨7½ÌøÛyÿ=?ž"㇢¼d Ÿ ÑËV^(±<'âhTGUm£§ôù T}<«Š%J€¡˜ï·àö„b ŸC1ݳžI9GŽ ÀùDø;‹Ö‰›¬yÔPE–µ¹ª?ý?Wû?)endstream endobj 1023 0 obj 5002 endobj 1027 0 obj <> stream xœÍ[Yo7^ìãüЉ_2³ð´›g“¹r ëE‚lû†"ɲ`YR¤‘lùñ[Å&»ŠlöÌè°cŽ6Y$‹äWÇÇùsÞ6bÞâñïÁ›Ù³_¤mçÇW³vþ=ü;žý9¡É<þ9x3ÿz›uzîo¥Õó½—³^€˜wrÞ‰¶i¡òÍì·ÅwKÝ©½]¼[®Lãœ÷j±о5zñf) ¤ýâ ^‰V/N—-ˆ5FŠÅÑr%k°‹«¥jŒñZ/žÑ÷o—«¶±Þ[exÛ—Ë•n`i¤0èum€õr%µiD×-¾a²Î©ÛÙÐíŸCé¸&õ’Æg£®‡©œÐ¨½x/„ñ+)-ˆiÖÂ(*TTÆ™¸4Õ·´¢×…mm×ÏN:ãYÃ8E££Èº7^Ó-¨A6“´šÈï{ÿ Bð–ºQÆ»ùÞ³½á¯T#½Qö8iãªí5¯}ëÓvi8W05Õ5J;˜ð ¤WÔíwI6ŽÉ¯Ã,CIz'?Àgc ý/¨Óå yv2.¸–’jHuÔ²zôHñçÙ@RЦí_5ÓÅ!®O7è×§°ííÂ)Õ²³‰jѾQ^dzà‰5µÈ…c­kœ´8Z\ ëES´Ê¥–§Ù´‚®MÖÿlhJ’.èì°µðÓ‡çG*Ó´°aïðà$›s”y$}¥Òfª:£AÙHl3o´×u­ã¶HÙt"kЋ2¾u\U/—ƒvA½„ô™.WcŒÍ°±mœ‰ðèe#]+æv ´0ò0Ò)cCRé(”@@üªˆ_±î|¨;JÔãj¨£Òùðh­È7ÄϧCÝgÐP¸ÆÔúXÎÉPwV¯Ÿ5ÀêQ*ÐLשêEÞˆd Í».®¿Ý¦ªAøºX=TÆB„®I#e¥øè7à„þ®mA®XÉí4`Èà*þ„çÃKÓJf²J”×ÒÛì('™Ãí©"+ÂéÁi­‰èl¼M—%ØQ6ÙSnh`e jyˬ³D ¥Žãu`Ày]"÷ Œ8†‚Üæ mGF/ÚTB“úUf12èNÈO(|=Õeht^€|¸Ì[1€ÐðµMçýòìSíT{Z.»@Ψ`ë%ŸÌ«á;µ DT+<,ü1¶?ÂWéüÓ<ÍoB~ÔÒMPp@œÎDUm$SÓ4Óïy˜Y·~ÿCGV´õÙ mŠ¢³?7‚Ï\S˜öb(Ý _ |.+}O è#‚¯8?!“'´ëÐô•ðk¿@Çlb8ÌÊHðA+Ù5MH°§WƒÅ(7ê°ßw{³Ÿg‘ *»¹s i77 ¼ íÐéÿúùìÙóçëËë£Ù³ÿÍÅìÙ¿ñ_ÿ÷øóüÛù?fß=Ÿÿ< l0wïl ‡ ;tS¹Ü´Ñ2N*æîŒ«dòP{t“[97-î~Ыºs¬FÌÙ~ÒL“ ܸÙŠªõxqM n€}¿š qÂØŒo*®Byâ¦wÑÉFgcîbK¬m îcK¢—ØÁ²;µÝ‰c¸ô:³@ÚŠIT–³x³´°ŠBƒÂñ$T›ôqÑCW–™„£çY5„”.ÃÄÑâ 2”WŒZêÒº ˜Ø·Ñóqäec‹Üì»-ê©[Êú}îã𨋸€ù$¥R4Ôi®!p†¤ãÈ1&azà­õñ¢šÅ9:ØiøêG1F'¤KgJ‹.Æ1†/«Ü­®Õ2ð¡-“ €9ø=.!“Ó¶˜xœNðA÷|%(-ÿÈ㈚Jޏ¥ªma²Û…:ó*„Û£3{_$iÒ“çYƒÃ¾²C¿&™õ¢¸jb*0”iLkÆŽb¸ç¸Óβêê‡~䃒ß.Çì”X<ÅÞ²i¥å×+?Èa©Jb"&DV<Íä*¥™T¯L>@Z?½(Ig€ÃryÅTcØ­ €¯ÄÝ#MG ë…ä0¹Ÿ] 0Ÿ †™~íÜ5/€¢6í:~?¤+“öní ‰eöñˆƒïC±×‹aÛ7VÜ!Ò”Ød.h2Lu³Î Ð\ç7]Ø0.S 1T\¥í\¡»‰ú94w % `æÓ~«‹1ž±[c¼ŸX”úË9þ´Ìä%­bÖ•y0ж6Z¾1Öö×À˜Æ+Š”ŽÀZÊyNz“áRJñqÔ‰€=‹óÁ,HïMqž“ŠÙp,±ù*G—É}‰÷lŒ3yìƒrÖ†˜8\¹ªèû t âåuqç£#Òï¼>í|€Ò\$#9>稞æz'CCL›M/à¯5®âïJê¦mÓJ‘íN>‹j!š¢]-pî¬êq°[pP½“üóY´v lÐÞ|®V´PúµX.ut·‚ż&H|YM!$s$eî­‚û£lß4[Í!ô˜· wšÆæ{ÄHÕ6FÈmdÃý'ƒHˆ/sX=Ki(;‘P–“¬žr¶N:°,ѿΌhîû°I¦vô$Ý.aFJA4‡†[xð ôŽ E¶ú‹ZÓ»¥È Õ¦Òì[Rd•x]‰N`Ú¤˜÷)Q²Å¤ ŸðÍ8=~™¯¡ëFù©®rè›!*™ÇЮºQCâ—cü†h Ú†o˜÷Ã`ƒEM×Õ kâÔ¤ç)Øx'¬P¼[é×4:Ì€¹Z¸I™ÆGD ¾Â5‹د”|¿ö•ÒýJ÷÷]%ãÔa¬(D™ÀésECȤ •™XÔ®C­ µ/¨ö†j¨ö²*á„jÏ©xF >ƒ8t¶ìâ jpC ލö’jÙ|O¨¶>ÄŠjOËnFªl¾kªýj(7Íõ‰¿è¦=H¡öŒjWUŸT…­I__Æ¢Õ3$÷¯åʶè' [-Õ°XïƒT™BÏ©Èä>}d¹Åþbíiµ¶ºá¦b’ºmÝ£n*>`hÀF³ÝùÚ>¡¶ŸTkJHyRx|=q]L¡’Š ÁX¸ëɰM}RÕÌV¹*—;>,OJ5³-)7UP±¡bKmÓ}?ê"µÞð݆À£ƒFUw"9áõÁd6C“Þ0t.ùÕIpGÓC§•mTk!Ê~·„h×:ƒÁ˜j„ÖàB½‰áœ×ȧÚSð !³èuBˆl¯m¥;Ze0=û÷[ˆÉkÀ@½XQíçCméÁÏG»—¨µ¿]ëêÀL˜ Ú†j[ª}úaåÅxºá ”°Áº~(~žüq?åR=Tõé0¿DRm~¾6¹â>ðB;\ïð¬ ÆáßÁ³Ö§\ÒÌ9õ<°;qªÈ—<§ªñí“xOR5g˜€TU8DuÆÄÛ—\þîJid Ù…?Åd…tI9Ægv÷'P!”£ôu…!ŒùÊS°–“tfJ gùD ; ätælâèÀöiX–xÔ…“l¯ƒo8ÊBR¦ßo…œ™ZiÏñ´Éµ)íL¼É!r7Á§],ÉÕ nYg&'õ'JùqbiàÒÂ{XÇShý†#î@a·ÔŸ*ßU—òªJΰ¡Ž«óÎsû}:Uµ²5»¿ ï `$\É»¦{•¦©gî³wÈ+|@bÅ4’3 3¦@­d(æwm‹o²?¢‚è…çþêÉð](Î@7Øz&ˆwƒ…ÖÈ;Ò•‰,¼/]®1p)ÒÍ—8ÒSœr'2ò–Å{ì}R +Öæy˶SÄvú‹·Ä•K—zêJbõÄÄØ.Y!|ÿñiÖ¶`aˆ>ùßoRžû_WMàñè¶Ði \çèfñ ªPÇÔ®Ta`íCìö¨Âøä®Táø}Çð~dÓ£›DS?5©Aõ75r øMxŸ”YR4g¾ ©j&¬n€ë¯\ë¯X6ü6*GšÂ„÷§»AΣÆ^{kîÑ&Xé_.u…T?»Ló÷$T«wz+TP¯Hor–°—Ÿ=óÈè€D&Õ·hX×–7õôã=Q¢ñeFضÁ{xE¼»`ÃCwYÿakÊl5¬ü'³›$]k W$>þØ_VØq`ènäM­¿ñw4ÚãÇà˜Æ0(W=2Q–åÄ.¬ͪß$iªDgýâñ²öë®{=ëW£?‰$ƽ)KíÂo$^¸÷œtPp0äĄ˔ÃPÅéÌÍeçû…ôG'(kÆ$ÃzñØ´$Ϋ³JK‚ Ž‚èå³’N×}XIÖ–e@÷«µŒSŒü#œ¦/ªƒ­©v¿ZËr‘#¢±ÌEÖçøU–>,ˆÆ{.k¥XQWTÁ—‰Qw7 øk7%Õ: ÝÓfÚ.'%¤âˆä»P¥·'§wQAOüY®Ä;Q‰Œ÷;ضlÝgå²BƒTûªª®ÓªºÓi²)ÊÓò…XçzwŠéô°)l;wÑâkÞ-0øH¨ä]ßÒ÷w$ §3+sÜQlÓy¡$ÃÂ×TËÚÞRñ5H3Í,´½¦¶gÕ!ÎÊ= Å·ÕO†ÚhP¡õG@ƒ )ïEƒÞß$ÝõþìÖº:W¥Ñ*-‚mdÎnÝ•µûÈt𺪃ñÍ Nµ\EÃ6\(ޤ„ïn0ö4½Wùðʯ“£uþu룭T;:‹å*Æ@ϘÖáÅ”ƒß¢+:·>ýߎªÊ¢ìéü<û?cZÔÔendstream endobj 1028 0 obj 3594 endobj 1032 0 obj <> stream xœí\[o\·.ò¨_±»EöøðNæ-¾4qÑ´‰­"‚ eÉbI¶lÅñÿèî ¯CžÝ•¼v`Ã1<\rHÎå›’¯ãÀ#þÿŸÜyÄõ¸xöú`\|ÿ>;xuÀ|“Eüs|¾¸{ˆÍŒ\068¥øâðô tÀ†/ ‡Q.Ï~YòÕš Ö(æ–Ãj=N!gjY¨•Ú.åj휔SËo±G©øò–µsR°å«5—|`ÐäñJ`\._æÒeéŒOáGÊ þk9a–W+Îɘ\ž¬ø ¤“6öd¹Ž_ÅXutŒ Õ¨Â/°ðº¤IEnýÉUlùëáßý*³…œæZâòq ßœ]þãàð¯¿,Wk1p§„[>_­Õ`­sÆZscÃt^¤>ZÉAqé´_k&Ð ¥œÄ5É\†¢5©„•¸&ÖDkÚôjµ–P7úQÙ µbù»5é3S´ÓãÒ’ü¨PâKzÔÕðW¸ hÖ˧ÕTÓïc¯"ÓïS©-ŒzR¾ãÂk6H.òYÍâé°éiÊ\ŽBZX:Öo+=03*Fx³fÕb4ÌeÄ J`ƒ‹ŠBnFøŸ±8Vè ćÑÚãÙÁ,ȇy!ÿp- ?¸Ã§ dÝùu;"EÒ švž@Ù®¯q*À­–/¯óTÈTÏÊTŽËTŽèƤ®Þ`Wzišî02ϦxL9hKèUöºCøc Æé —Ê4ÍéÆO÷ÍÑY‘Ïd‚„c=*2ÔYoüþ¶“JÜéuÜê5ãa³Õ@ºzÞ´‚Ú¥F%iÜ nPAÑÎ.Q$õ`ÜòaÖ¸/Š #xŽ•ŽÃtÒ Öºh‘ÉúÚg¥8 ªÝ ¼Z~`Îq³5X¦ü3p‡t`â4é,$¡kî€$«é(—©VQ2¯Vf0FCSBÅu)ÆÉÉj™H¯Om#X=Qœb丌]e|2‘?ü9Y±¯V`^9 iú4ÎÊp*Ëi®ÆP©#JºìN ÅrNêZ»àùð´ˆ_–C}Nµw°yÂôM¡ÿe€È÷åD¾D½B…jjD¼*®4:©Â«hÌ”+é)½¨gïý²U­&ì¨_î(~B©Ù¥H2MæwÑûžTa‘£¸ÁµóJ%ö%™é«ºR"$²…Ú ê<ÛÈ©.I+ã7VÒ> …µª€U]£çÉŠ=©n9ŽÀš¿,*„Hí&ïj:Š0H§„ tIEi5£‰/’J53:‘¨€"ä{µµ*¾rjU½u¼T.,(£w¨óA-M[ƒ?®»¢Z£ ÆIµ(Ì´‚ /Ьœt ƒvÿ-g-tI¬€cØQ/¿#–îîãf‹AC‘åi²¨0 >c'ŽãJàp¹Æá|Ì?F…,Ø¡f$ ¿ƒ¥á±©‘dm¾¼!Ê÷³Z¹ ÷ãYOMhÑW.GT¥ôÀØho•2YrœöæVË‘ïlnsÀölù¿ÌkÁ«QàÍ¯ЯŠ~!¬¬Á¾ è0¢o¸†q¬°°×¾ß ïTw–KÇùëQ®{KoÒ×®_•ÜR&%ª:<Ð.„E S‹È´Ð~ï×j¦jTÆblÖ–xa]mÕÁ ú*ìBD• ³“–¡±ià…GOq …êáCÁ¯'Ø:Ï hWà¬#ª†ß{!]RS³Cö¥«ò˜À\rY?íR‡91Îé–íèIM¼Xµ<%7ïJ ƒâ¹R L¤Ý©*Êl¼Št›qÅ:«ûb¢®P¿B¶ hÒÉ56AÙÁJl‚vÀgŠx0IQø¬È3)NMAcCw6hj5‘òH ¡ü-z×ÊA·O*H-ù ÌF«08ûîãH `†# ÷;¨Ot{qúq7…eô˜á*Ç7d’@Bô«žÆkå¼²1µÒ Âè÷ÉÔKûŠæÕŽ"úî¡FíÍ>ÎbjVEI¤ƒ-vYŸèà0°¤=Ÿúˆ íê¨k–’c\؉ýU‚‚»aX·AbdëywÜ"ÁeiÞ®ÅWwZ9Ëà< ÁÊÏ;Có–¡l}Tº1¶ÁÕØàÃj÷llÖÎzø¼ 3 >‚(g` èÇà$ðó2U½N…—ùÛeªÊ…Óô ~pxðÓÁ«…Q}˜†]Íl;Ž(‘oÏî><¸óð‡Å›«ë“ƒ;?/ØÁïñ?w¼Þ_üåàÁÃÅO³I‚ sÓ~ˆ<¹§‰È“Ùå*c"¤ßæfâ”úh3qy&Ïëu/h•y6(tÏ‚UÉ––Ñ΂¥—B§Ä€•ºuÓ‘weå%ÜQðO‚àÞNý¬žMµ Ð˜ÙðB“ô‡·=I¸=F –ëëx¡=tYœ×#ö6©¯boSrůa•¸ˆm Ÿ®@•“!´ýVE};XB iú®ëcäx–óðÄ“mÉX'Þ­G¢‹~š*¥0 €ô̵úóš‚›‹–›ý›º’¬6³IgÎu¤Ó­‘·$®ÊfOM"$/Øž€!8ñó[a¨’JS—íŸ]þ€ö\€ó‚é ¡)Á[¼‡ßq5“›"PÝeÁ§Óˆà-…. ‡ô“äg„²v€æ•ƒÏšï‰t¶£{å…´ ãM£|×ãS|rNç¼hŠf”œ×*Šüu‘î¸!.⡪êé©Q51³ˆç–™Õ0ײBñÓ{Y1“Çœ‚Ë&ˆð¦%Gr§‰Ü>KþIô·"9M„3Àh˜ýôfà ¸zÃVz`°}zù{.õãut#IõÄŽ$¬ÌÁ¦IËgü’Û¥%‘õ)xåW¼ˆ.YbÍ@bHÅóÅ‹ÉR¢–$¢õ  ,M/7w3`–0„4v> 2Íé^t¿“3çD%1Ÿ€ˆú ½O1D'L¾û¡J/®ÝìE?Û?½ Ðä,º¥¶Ö»DÈÀÆg÷¹Äx6¦= ÷Çÿþ¤\n;& Œ¼¾×raTÈx¹›² öO3ŠŽ–ˆÈ¼MÄhñœIÈïº'áû1~>qböaüú!–ã·á‰&ñÉŠ‹1×B¢Äțۣú°÷IñpµÁ¢j1Œ¦w[¦kQ}6ü,ç¾è©ß”÷ánéBeÎvIÿç€Êg¥©+E^H(yÚV—¶6ű­, Æn– K•ʘønØC0y°áô2+ÒðR[îѶº´µ¥HÚÊR;vð^í®škûYjö/9‰ýæ$XúìòOyªRåo:UÙº~“©jœ~ciùDœxnRYí/OÉ7ÜvFI•Û¨ã†>nÜ?–˜—¦U<[F®!ðæû„˜JÌ—Öd'ËÙ.0ÖiÕÔ«j­TGjÓQ‚} Z1Ò}|D‹¡×*SiÈeGÐ?"Í·úÎ"!ëI©‡U„ ìV™½ºµ Î`nüìp†WQ‚Vó=­Àý‚[>1Óñ·|a¾/¸eækpËìËM +ãïõr“*/7Ý'/7Ý#/7Å”xÑw¡À#Ò˜<Ít/œÀ„•òçß(~Æ?Ñ·›ƒ]àå|þÈ)XjÞ?À[LPÜÖE[“ÔwýV@y‚¤¾ô%›J¾áNƒàÚß4ØÏ‹PMê{‡Û¸xIVðæ¬À„SMx—j,¤Îžh8íH¨>_ùÇ0ð N9 L.ÜÅ¡8Því"È2•€Êª;áJ‚×Ñj˜×^Îè„Þ }âKººÓQÒü¥}` zîÞ*…,”´Ù$¤·‰ÑÐÌgÒ…”þh§d6$JÙ¦€$î&©0ŸUë>‡4yè 8¿ xu©fòÄ.¸J¨8Ç“îÌÌei=‹2Çx!ÁïaA’L<¹›P;Y¯“(<™íU, ê UÝ7>ªXµÐfà¢ÒÝU Ùô£­™;ÊÂk¯pÕ¹Ùé%U,>§¦^ -¯&*lNp´âÆ?©6+ïÚÛ‰à¶kQ·•<@j°—Í£á©Mܺ=(¨ÎeSl)&Ôl`ùý½ÖÙÇ=N~=ÔÞ5Ël1fîJO§÷Kd5ý S“tI«ˆÊA“ ð~nÇQ—;]ÆKüÌý ÜGãn*÷|òÒßзÏ]I"©í0ýVA%+¹ì†Qº¯u õr‚Ú¿hqŸ| êOS‘Œþ2>½K”â=¨îaÚ–«>˜È÷¦Kù•9—j0bƒ½B¶VÛ’\Ú$Ë?w§T~“g¿-¬Â-fLVĽ?oå4w²sä¡ñtb˜a6n(˜Bð]uÿõÎ1|fÃÜŽ¸µQÖ¨^cÕ‹©Ó•î=àñ‘ØüQª*îãÛÚϘ™§3ƒ½í4exFhÓ4sð‡Þ·ÎÓÌôS‚EOÓGî%„,‚I׸™gšÆuÝ|‹L—·ž¨ÕÛösëD¿íL4µÿÏ.SP˜ä†O·œƒ ˜üò° p” œòÏJ¥ÒëÎ×6H€q†rÌ¿D!.Ò×ÍÏAq´¢îëó¸è&ëÞÔêÊQCT ¦Ô_wŸZ¸T~ÑãN¸ç¸ùIÞ÷*ÓyDâÝ.¬ÀýSYÝÛð8×,YÖ'Ívg>ÝF’–¨0oK’žNh3IA®Æ,E)ùd~³Æ2»­VB!E·šô·˜j'e‚ª›7ccN¼R£åöc›ý³/{A§á¬1›"±Öq½ à3ñœàöe‹úÍX€ÁþÑ®£®&,ÉV‘ÃBë<@ˆ) Ö?û¥äË BôÞê›ò¸y|ëizò#y£h~ï_J³v¸2Õ}ƒ±  ~>ò’Z¦—ät~ìºG{Gǹòæ[þ›°}ôËî< £Ñ£]‰BÆ#w;Ü›Ï,éå÷„ru‡‘,ç¼CùûJal‘‘ÜŸY,¾É²%øöG™Iz;áOä=S‡._~ä®?é*ÐáU?Wau3WpkOº.b?^ótÕ{Éç²> stream xœÍ]I“ÇuŽðÿ…>èÐíÐ+÷LÝHJ¶¡,ŠÚŠ|̆°/bÀ¿Þïåúrë®Æ4(‚ÁBvU./ßò½%owëÂv+þ‰ÿ¿}ùè«ï¹^w÷ï­»ÿ€ÿî½}Äü+»ø¿Û—»o®ñ5#wnqšk¹»~ö(tÀv†ï [—_>úËþׇ«u1ëÊ¥Ý?=\±Ek©äþÍ-Ž;ËS£bzÿ Å*Åþ®ýY8~ö·¥ñÓáŠK½çößãPÚ9-íõ­ï•­rÿ1?ýxXaæ’;½w€Ù -5ýæ%¼iR¬Ÿ~þáp%®™û÷±(½jó¿×¿õ´c”(\.B9»»þÝ£ëûËþßL,ÎH·}¸R0 ¤x‡+P ð¦j„”ÓéUë`±oÊ#™vÀÙ²*µ&¶ Xk~õUy$„ûPH¨¡gt°ø™5ôwÒ×=Ëao-ýêY^͇òÕójÞ\òE ÈjÞåy“uEr0¦29òX¾•¬†°‰ße9/{C?"]ýÊÏP¬†¥ÍãG«Ý×0Õí®ï€—ÿ5ïÏp³ñqe¤À¿ý'Â.„Ûš…âŒo(ã]qe {Öᤤ4)K*?O·[¾8ÉèN”ñÉ ·åño¥ƒù®+»X!q®RéÌmÖêƒa–Uˆý“ü3n¿Ö‹.Ú@dVóÛsSZŸ”Öe.ä³»òÂ/qZð£â¼qW÷ ´”2ô³Ò¶QéJ‘­@ý¨Ë¸eÀÉ; êìýAÂÚÕჴHÒØô4=Üäß^¦&†Œ“T§`z‘’S•Œ/ÒèýõáJ,Ü àŒçe݉žÂ&q"¿+ê‰,û‹‰“—w)'þÍÓúX¾ú±åH?—ø.æ=vëa%r7ôLš`¼~µž þ܉„EÂÀöjÕ‹„ŸÀMéõ¶<þí  ŸÈ¨¸ní.íëuaøy|^ut®¤§¼ä˜+ÎÜ"íîŠ1¢Žîй ÂLú¸™ó|£ê®’ôÏ­ð„XŒec#ps\÷U6;«£'E_Íñ)¬ú]b(˨»,Ó®PÖĺ(aˆ¬Õ,‘éY…×#±$ã×úŒAå8ëiŨ.ø‹‚Ýþ;üÕ.Ø¡,¤•B>”˜ÞtÀ0D—o€™-ÈÏËÜ’µWœªÝL=„È9\ø[â”ma!\dᆎD‘N»WÅü–šÈsþÕçùU"iR·& râÑ'£/äš @+¹ÿ=J àØûü]/´ú@“*—A³Õ,n°0rÿ›°ë êW8˜Y%Lñûüûwy¬ò ÚE)Àôhº@2׫̴AÑ„ºb<ìÕÄðÉœ†ÉðÉ»Eª 8ùXЏYð³)OÉ‘þKvîó2‡“w±{Ð4y¾n¿òòK˜©ˆÒr5Àl|,`äû¿£òVkʬï¨×sq ËÄ{uËÊ*ÍM¬æ‡!ƒ,€´£Fú"BV(|_a+fÅ¢™¨…ÌK6dm“d—¡N!+Šx ˆ±ðè)Þ%¬t›áSFTc½É¿Ý¦&¾ ZiÕÕp?\BÝQ 9³ úA_ÿD„œä ú ¶ÑQ6ëÀ20¤ƒe¾¨d6cèC (è%J·¿ðÓï– žV]Õæ¹ë§Ü4â( q&0س¡[œíâXUà(y ÷ q:¯Üãl+¯› Ð3MÖVžn†ŠãÓAI°"€/D÷¸;¡ c“ÂiVVBC³èéû„àJî´G° ®ï¢§Êu~ÞiúÚRþC,!äb¸küU„ FR!¿Œ¿*€³W¶É_MÐkr¶k] €L)ÔæÑÃ|V«XÔ¬7©é>=ˆôÛ ÷†ª:ÿǹ¤3ägâ2·|ÐnØCøà¸*Nª0P·F¯ßEXi55Ù5îÄG½ª…¼×ELöÇò{$¬d‰Qü +F¦+!Ì:®ëÅ\OÁ—U`(Ãõ­°²ÕKh‰Y¦Hê}i$1ß%Tð¨Òéø}ã~U¨-"½!ëaP5:C ܉)DMZ ·¨^9U-\ô¿s=ÑMC%r_ŸÇ­•Y *ïôÄŒ•_ÁeÙ‚iª‡+ ¤VÜ£ÄÒ?á·Jâ‚G£t-4IaMùˆƒ!wÛUïÿç AcÉÇ ´@Û×fÜJ»A"¹V€¹’#Q• µD)jœÓÄlå&z<ØfŽçë’uL<êØfÜâ±*†ù? óÕ‘+²€wÀ·+09ÕÕ…¾œ¦ê©Eo-fKzÈUc­ýf¨g^—ÖqDíyìÜŸç“Ùd*=®‡¨²BÜ€Ãngv † ý$ÕÒëè&šÔËIƒRj'3½€zÕ€¤ZÂrDäë<£iõ•qn«ÒhôÃçj$m¦EÕj$š9ÇùEÁcغÿY‰—}B1>˜ÌŠZd‰uî,óY’£àÇš²} ‚*R¯¶I¸€Ï ¶§ZÃíóEJ†é–ôù4ÝFš¥¹\y“¦ú3?Ha&q”ÈY°¼'CR‘ñÏàè´µù@±ªEXJuøZû/†½Þ•äÕ‹áXŨ wÉÓ+Ô‚°ŠayËÆ.ÚµAW'Vàb{H”Fë~Y°ú|޽:ØAÅa¹ìÄI¼øq4‰n2‰¿Ž ãôÔŽFÂ:7_ CL_ì8éµ×«ÉÐà~sC­K'½9å…ÄÒrb<8ž“ {­×àÉe0M©‹QËDr}ö€ÄÊC„˜`õ‘Ü¡õŠvÊoA¶S‹EêB)ÔÝ’&áÃ?‘ò‡bÆÙ¥¤«TåÍO³HI[Ž&8i¬9о8AÜ7‘ó0ÅB\áy>Ô›RI€ÜlÙòaú\ß`.„y«Ý›úð5Co8!åQào€)h"Q’ÑãDÊ„#t=üAØ.+$°;Ûÿ,º¤9Hf¢,„ˆÙ³âç(¯þt`,„µ*LK#Ž_y„â}66½º!eÓx¾1„FY8°¦l‘ÙšvþÂ<×HAÔ8F‘ –ë°•—V^R”=sQ x˜S¡ÎΗõ” úÇ¡®.ׯ£…-Nnþ×D¥¼Ê.Ч¤¬?פÿ@º}œ5UR°Z±Bˆ/œª ÚÌ{ô]Û4B’¡wv')ø ,Àu£‚^sh( Œ¼:àTìTàI×ñaI¢O'TøC&.Ä„l ÒL‚Z‰äi,}ãhÔÛ"À[µm,“oUœ¢úc5ó*¿ÚÁ€]_V&§†I0¹XŦ<*¸Zp g¿ÇV˜Ã,Å?Ž‹ö.u i†Ý—ÿ>2ï7q¶\çGUEÍÇ,ù´|v7ê¶@ù.[H£JN¦]ÿz(‹A·4/N5ÔKÌŽF:o3˜X¬™°î ¼ÊæL4¾BWª%í ¬BÐ'“€ó-DÞ—}˜§Ìo<$öZÜ–No•Ê@â,”uÏ ]7 Ý”$^ˆ‘òPŠÔži+ÓX¨¢ZŪfž(B.sPXòuDžºŠ( «’žürF-ß0àSPäØñÜŠEL3L¸PÕNæÕy6­}~:¢±t¾uK,6È%Ž$–{Û’ǾÛ&÷Ö/| ±;?s &¯Þ£Z;Q$áp]d~Kzè%y3ìR H}"µ½Ä·Ne.½2°‚±æý!¼‡ÓÐZ¿J}aðÕ“4¶Æ¾y,”xÇ}Ýô™È5‚ãmÈ!^H@þS!WÙá_¹Æ²,_TL×–ÎóêÀ€­•¬¸ãÁÄ n><8ÌÿIöÅW0¾îÁÀuìÚ6e¯žVƒ ½¬qbuáô¶ž¸fCû=L,Ç*ž@¢ºr¹µhŠu¡îº4Ù—`VMô(+·ô³-ú;!òÓ±*ÐÄÆ°‹¬á{?+3>HÑL¿^UÃ÷غZ»…ï‚D€Œ=\]ÀÚG09Ü9¼ ”è« tV<ÊD7Ìzdu·Äƒ=QdáôTus±‰³êˆ¬”ä£f¥ãP ŠGªŒR›’W}Z°N^¥ÇcÕŽ(RØvò\×48ƒð ‘ðåëåîΕd9wê$H9suÓ¦F “ËR5®îÑ ì™®®Ç‰r›«›"Ý7¥j¥ru{W²öyÓ÷çú¼­±é½Þ&ßß{½Þ¬dßfæà‘°ï4'ãwd€o*ýœ9¼éÄÑEÞ¨r†Îæ0ÔKs(Ã8i&wͱ0·ÒÍA&7¼³Ûœ» ûÕ˜`Ýù,Í)ª°Otvù™P2®5…ø¬ÛäêÊü–ÎÕõHg“§ëëifä³=]Üm ÞÒ‡ñÚŸb–G‘}€Çv“µó~È 6c4  u®‹U›\]¿ò6ÐyIW׳ ô@àlÉAÅL¬ ÒI!êÜÊE¾™'1´‚ö-QÞH§ÑùAù#ØN\\Á™ 4¾RlÀޱɹ’¡àŒó=uñ¯ŸµêL¯Wx—±¼¸@æ¶XÞ ¥%I8ד'_œFnCˆÅC•ôïR™õë\‚*¯™×ÄñÇgåáJc¸Bï¿NM¯ÒÃ]þîÏ[NÅH…ñ,2•Ö:û8Ä$§ÚïT‚¸SFÕê*ž·#ƒeíQÑ usÐÄ?ÓÆÍ‘ùrŸS5CïA‘sñ™|äª6Ó¸)ÁÞ½ð±3Ã[ Ë9AK‚b¡ÜR‘Jý`@=¬°8€ÈÛrÏ$©Ô¨\jÑ– Û øµN—·ÕÌ­gFÂú1q©yU¶CR¤(`í-yúð¥ò”éž‘KNäϤù»´‹qLý%üïƒr‹jú:áÔÖ!\ÂØT–9îV—YÌÊ ]\¸pœÁj”=²v-døëÚ±=cÎÊ¡‹Å—¨²bÎú§ËTYqÛÀç 6L‚qú!{Ç¥òH) º©âXh —õÍÏóàÑ4wêÇbfS|µ^bÆñDQo¿ò±f#ì} Ë×§¯Z©‘^sRclM›…ûI£–ÕTeNÇŠcµ·K¾©Ú\ýeå∔ø¢Z²EÀF~“oc(2\s¢_6?Rl‘\‹a1ìà²ê#eº}'çŒê{P[bp~¦ªÁùVA××,ã´ÒuKÍáSÜ–=øPF Å6€úx »ÍÏj%…‹ù™~‚mªÖë"̱‚à°þsÊ„RŒŸÞÐ%ÍãHçÔ w`·Í5ÇkìŽÞ”àFƒacúpª§}v®Èæ”Ráü™`—†(Ž:³Ñ™þbª#Ä'̼žyÕ€²IC kÇ·5À=¦ïFüxÚuž—L#aMÕÙ˜µúE¦k•°öîXDøt®ÒG9»3Á¡ßåA¶c_ña=ã*ûA!Ñ(ªÝæZf~U¦L㸠Š|N¯¥4NûE&ãaò–¹ òÔ¬‹I€)V>ùñÅ*cD>TÇ´Ç™|1ø-4GE±V_‹“À·àº!Ù»õÌzˆIøb‹e¶ÕýqU€ò Ú;ÁuRpqWvpƒ"Çõnþê-µ§¤TS(î{šÖXfR›qxª±^±/ Æ ²é¸Jô1š¬ŠÃ(Ôü; ß—n4W}bµ?–ŽûK>;z¥Tªó÷7°­êàØñ  .釓+ÑB¾Š÷¥=Þ* J{›MK{,xué–)~ ¬Bå>ߎ7™*íÄӫ&Ð5™½—ÖߥÑ8w'¯Õ÷^¨eýÜ“º™Ž³Àoªw{¡kBƒñsu_ =WNíôöª}Õs}¹®xl!ƉÔbW^äóÿzQânÇjrîcmÜÚxEÖÑ/nÙ¸œy Høc³°ˆï‚iñŸ¦èË!Óv05Ö,'Ë:´†öa0dÈ—>ŸË2¾Ë…ߦ¦_lºµÔÝ×n9ÌHWµÆO›!?ï¨O*’™Æ¾^$–4½ÃS‹Ò†›6©ðo¦³“+#ù|4.é‡êäÎÀY¬çþ½ 7ͧö[$4ÝrÜé°çˆß¾Ím¿Øt"s˜KÌ]ž¼¯•lx¾îÙV®ñØMÌÇò^^-:å¦S$Mq™K1ê„OUØÊ° ‡;Upù3UIÜo®ýþü?⿞0endstream endobj 1038 0 obj 5116 endobj 1042 0 obj <> stream xœå][oGröQ¿‚ „\˜£é{÷£åØ‚,âÈ\ì»y IŠR,‘²,­¥ÿᜪ¾VõtŸs(Çc¡³=3}­ËW·æ'ë"NVü/ÿ{õúÑãgÒ®'·?=ZOþ þwûèÇG"¾r’ÿ¹z}òä^3VŸ„%X ÿ^<´.Þ¤×N„Ñ‹Ö'N¬Ë Ï^?úûéžéÅ+íÅ雸 ¾:½©mwå×_üû#¡– B8¹øGúûé_ë[oë—/kÛ»úëæìÜ ¿Xúe×/~q OW½qúUlsîôU}í¾4ýT~ÜÐ á,ž‘qJŸ—µíšÍ_/« ¾Ìß—q^:ÈÓ'µñU}ñ¾¶]Õ_?Ô…>+Ómýýœ›ÊFÊU}úF2#ýà !i J3¢ |îO¬ò‹ô‰^`²ëb¥Ñ0Å>0Fâqž›Åûî[ùy_Ka%Œu…`•£<—Ê-JšÓœžë¨ZÁ¼ÎÅb­–Tû}…ï´¤;ýç™]„U©³¾ú¶~ÿÓ™ZŒ šMë¾Í%Ïлô¦]­;ýÇYú\Ovêä\øz•'×°Ø/ɼ¯Ú°ù§‚~ÉdÞ´ÑÞµ9àruXTÐ{ÖhètŸãWL»zўðpK"Ù:™ïã Aì ¶Ë8g¶q©¡+¸o½ÆýÒXE’Ú.^·¯p…Ò¸Ó÷õù]{~]óf9áÉI)–5’d×?~•¨r.ÉT<-+%R"̧…Ä¿­$^%Ê¡u¥Åb$ë3m¾ZȤfÂêé2nÚÜXÑ´1®Ìr.-²Ò©¯ô¥Œ [ +ðØßô"`óýBy(ÔkQ~Fb½ÜP~îXÂê\$aÐÊ»@©Š|µen˜BjÔ2XÒx[?]ÓÀOqᕱŽ"E‚ƒ-íZÕ{äÅGü^ã4‰è ¼ÖÞ$Ý“#x#áÒøøw8¾[V ú8Y·®ÞVÆõ•Ö‘t°!Ùúý,n”©Oîïëûî8#ußõ3TUŠÅçäÕûŽÇ“L…ñá|}1/Pø@;}Õ^xE;…CÞXØ7$#iÜ¢+#±”S•–Né»Ë Èá{*aÔ ئ¾hAf2\>ám"‷µ×‹Söô»3i…¦g¹Ù^:¾ðNRJz*wy VmÅ||,‡|6}—Wµ`o=X:¾å¬] ]e™¤Pœ§P_ÂI⹜§ƒ9™—Icæ\†t ºžh<¢?46$­È”œªO¢î##O$Eãt.Añì õc¦ÕT¼ñã¢Âx8Í›;¶Ç[áÛÏØá\: Tl+Î-Sýg‚Øu«Õ<æmýÙAƒþXF¦×”ÿ«ÄÃ:ÞÌ'îÈòA}އà o.*ÚÔowoB•D\A j#îÚ½“&غ¡ˆÈGwCN¼¢òžaB§ˆ©ãÈÛŽñ'!ðÊN²,#ãæ9!óæö=\§V ?ÐY¶!çÃqž Û¼ŠtªeÓl ÜOzx߸¬É„;Ä» Kê GÇýdÆçd d¬ =Õsàž*•ZÄE·žŠU@‹"whµxm¹Ä©›¼‡.÷joþ=i|~êÁË¢A€xy„*]ã¶V³µJ-a½z"tî:IAÉ_½ŠšÇmaï’°é«[­-ÚÎE­‹Y©¡@¶°̆¹$Û9ÓŽ—,ëœ>ý ÁiDà—Éd¶8¬vìV]ÕðŸO¥Ög`«)å}%#e@,b$ÕÇcAó/gnqìXRºÅƒùù 8S)>/²#ïŠ!Ý1¸Ô6Š·¢Ïò·3nðç›üª·©9,?t"$ÑCE÷ÍÐAúh!ãúË¡X¹ÌÆïŒ­ÙW`wée]ÃCÚZ$‚†X&B¼ïg;=Ÿ€3¯þŒÇ’;Ä9íåP·î…|™Ò Ë!+#£ò%¡'”±ÌMdØs ãÁüÑŽZW&@†H…Ó]ìH2>yÞ¸sØÓ±.{I%Fmý˜„:ŠìhôÝXÿýPÃ]ç‡1³ ž²öŸ¿åCËø¶±Òe¡(“uRä1«ÜqÞÍæ3n]¼5tܱÔÿ±õõ¾—•QbU¤_IÔʉ±ÁíØ)‹up( x®U|*סZ—êl¥%sÄ=Ì«W„GdVoz–Ê.àBBÏ›LiÜI !ã±§ñl9”ÖÕ›¡L"ìrL ޿ɋsÓƒ m]K3à8îØº Âjl+*NÆBÃM05é?SbÔÏEˆR+(°^Üå@g5Ž6ô¾a¾Œ¦"„²èc/j{`9DA€Õ¹Æµ¡U9@óÖ‡Ö9i½d8 ú=­ïmŒR!Ãa@Ÿ\ñ£½®½}l.¼Œl®=W/‡äc”_i),5:Ðq£ðG¾ÓS&ŽÞ^åè6V¹"Þ >*7 ’D#›5âÂ&p_NÌ=À.Û6,ÈØE‚²!9Ê…Û:v7&Uœ•ÑSh=êkç—…¯Ô¢ô€ü6ï.òÓÊaÖ¡ŠgÁÔ¤í·Üt¦[È3Š;‚g€Ù­jé]Šñ™ùC†â‰/j1ht(L ð] âÝ"X˜äÆš“#†rš†Ïv8WáÆÐ`jý÷NµÞ}ÁfRúœpV®‚ IJ€ H‚B]YÎÐ^¤1ÜdjkVÌï°R=ŸÖl§ù„çñ‡b’ã pù 8êA0dÌwõ;ɉ×zÎëz `ÁÀêC‡Ö«DêÚ!Ûȼ“#¿F·…‰ÎØË™ (/tâ)u`6ÃÌŸ¸9V,$†ÞJäGÍnÐ*€ID@Ï8ÄIüA7T+€™dƹGe»×@­”í¤Ë¼>¡©ÉDDÄ–z›óˆY[›<|a?@rh~KÝ ZbéDÀ¹ÕnY¡·Éûm]lEFS—[õñ ŒðäØb?_¬ b™Uk5ÉÛr[Ó#   \Uä9P,ÃTš¨4È=­ÙfužçòñŠH’=®9 Ä ¿²AŽì˜)Ðæ dP/ËJ†ˆPW<Ì™3Õ&E|øAɤøqÁÑ´šŠ^b h`TVL‚@– ‰ü91–Dzˆ?'…ØÜÈâŒÇŸ’žœïwñ¤ ¦yŒn‡Ô-hy³œš+Ô¸WCãh‚—Þ²!ßžÌ!W1mP9SÝÿŒÖ5XýÚ³<©=ùÓ ©²¾8S`¼JÓ¹[RÔÄ-UËò½ÆÐñ<˜iTH⨂–$ÜŽÒä .‚ 4½²dŠy?É˸æïâž9Êð„ö6il½!Êyà5º ¥÷•‹É¸]FWŽïʼ£¬˜dÎߘB¢a Ó'L0•Ym" Êq/9§˜e‘bfQá¶”á!ŽMeXyÂs-;*‹Y.b‹”:~?K3ÈÓ¦kAg‡m‘`ïvû»tƒN–å#˜ªù”£\ë_ÛÔ ¯F  ún®êk÷›g8Ϲ óĤ¡yF[ꯄ*0^dL@p¤}У„t.{“Êw2$e¶'U!}vv_¼°3ŠŒ?› v5cϤËÃ锯“ƒ,OÝ.äìd‰Ž»uN‹ïr˜+Á+%µjÂX»ŒâÊcÙsø¦Û¤N#—þ­ìÝÙ÷9L°˜XKRò§;ë£sŒ¨ý”]Ïv³)sLø_õÒù|[†E'ȉt`N_LaPÁ;v–þZ(f Eõ´ëL+%eÛÓoj-ÆÓ„É4Û¿’ Œf:jy°‡TyÜ?ÔÎÆîÊ®â-"UÓg*þí ¡ÒYqHËK”X5EŒOоÙ,g¬yÉxðBqyú‰G’(ï¹Ç²OÞåná‘|šsƒ%ØRoôÉSÔ·º=Û½"0ú-ŽPå™'ôÛº³OÛñ÷Ä’üÂútŸ‹uRöÐ1æˆÌðCÞ#úåD¿´Æå$h•D…ÉH¬ÐxÚVÛ/¬´/8†Z0*ã1eÌȵ&¶;V:–«‹Î YKšŒ}Áo†j”‡„`Õí•fGàxX¢É7ÄÔE6 1ùûv¦j~÷ˆ• öãáVµßš+™.‹¤œ;Ì£¨Á:Iý‡-¹«ÖòXVíL*‰ zZ?C2€“qN>\ ðÄãIˆ‘iT¶³MÆZg*Œ ÍÄüUÚÉ¡55~Þz:Lpu®ŠQ²4Û’ºÐC¼xI¼Ò ˆ‚AP=eíDZñáò6•yRÁÊ’J¤ ÐÛ$JpÝÌaîPÁÏT£j‘dÏ>Õ^`ìïˆ/rõÐ,kœñËU-O3:‰Ø¢bç´¸jìΰórn•Ëiœ3ÆÖC&«ý_ŠêÇø†ÖÃýžQ¯‹÷Œ–NoYß»ñðãšBo]?{›æç˜4¾åÞºð[t­îó>ÐÌàžÕ¹™‘=º¿W’г+b@Ê6f¥×ÉkÕQ<U=¡OÛX{g…ÂVþŒ<¼]•/ÓV Ê1ÒE0^õ6oT8Z³~æÅ#Ü;/C;…¬«Ð.wªn\{:%[Òœ†á5ãš…²KHÍò ºcó¼:Í’9 ‹§L{ŠáYü1Õ7ˆ¾b4v6¬ 淰ܲ=O±”yx{ˆ’SÿJ¡Á|;b¶Æ^F ±vÓ¦7Ç\<­æˆžI§Ë ðÿ‚©šÿª(¤Û]–]ÆÉÞ)÷É ë¼vŨæõQ,柪o<R,Iƒ¡bIšÀd¡Ë‡ÍKÒb¡k ­o6?Q›smÝBÕñÄ?O¤À8N÷±½Ðƒ’7‰@Äï˧ŽzÝÉïüÒ¤Zló6ï  ET”%j1½ß&Ç"¾ µqã(–A…®`!Õrʹå«a„uWVll¦âmÀŒïÅK’šv|UÒêdØ5%±j:]sPX÷—6­¡$Ý™ Ût)¾JºjW@D¯'îu!ïæ´ÚF‘ÈÅùÊÿv„ßlÅýG ãÿiÃs˜I=àÞ ½¦öv$MNm¤¸ð0Ò!R?Æÿél‹õ¬Y„=Xºf+þù3ÌÚ˜Ôûò‡bsj† ˆÃáUk%Ûú¤…§B¸„מµw ½ý¸  tÁΡ9UP¼G<1{³³V¼GŠO¬']È ß§Hí˯Jà ‘´Û¡-¸ÝÏ\ÄŒfa‘‡R1évÊ¥â¤3!ÆMé›ù%^D‡WÕÛ:^`õ,iUÊŽ] °–7ﮫŠEP³TžÂªBLbÁª“Õ“b•Ùõ~Ÿv«Ç¾:óxRÄ@Ö‘Ž zg¹’¼ †¹ðj?HŸ~xofyÜÀÚ³ú¼y’¾ÂŠD¥eïƒnÈ3Ö4îzèã?X%iÝw^ov½»¬k‡èÙµ[›òN,Åj{ ,zW{Ö ca¹5¸F~Žu÷^K11\Édoä9¿`ð]k»uãXÎzæ›ù2ó]•‡pvÒØóš×ˆÀDØ^¾ÒáÂq­ÿX?¤$¨¿m3™)Ço÷)Ü8Nvá'ײ+±ddãö¦XQ[ éãUAQÿLŸª·¿9ë}±UY¼t`>i̼a—Ò=¯ßÌÕ"P@¿¹]Ô½a²¼µÜKŠÊ t s'‡jvÇ}rÛ:´˜ý8«çip±YL:m“Ú/,f ‹D@áPÍDfêׇ$ +½v]N³ÇJi=½ug¼± ô%BpެZV©ÃXÿmC¯•¬[pØËÜÙ*¡ê°S-«^—ír…EOj]y¯#S«¤‡Î‹lE”Û¸fHàt•4K²18ÁêWCy3üyM$@ªÝw²gk¬)—2* ¿®‚Ù¿¬ fdÂÓhLÎQÝÕM…`>–¬Þwó#¡Œù¹+BP$^:N8,Kœ}.=FÒ:†.>÷Ú ÐC'¸ʹ_ÎowÌoËÞÖkÓ¿â9‹Lv¼«ù‰õÃý%{ V¼’„Nï˜å™H_ S®XÂËó|¤b–Ç|ß<¢Ä÷ù¢µrèšûÝwfCÒð³èsÍï¤u®;7Ѐå¨ïtzq­  ¨CèÒ­¶’–³>‘õê¾Ø#^ëægÉM'Œ<™D´SFô˜¹eÈúSÆeàØAíîþŒWºcH™&1ã¬ù¨Ü.çöE XBþÞU7®P¿K£Ñ®ðH!E®(÷i>MÕZó ì:l•­u=«µÇd´Î7•]ËÛøC¶‘Å÷Vò¿Ýcy"ÑG%5Þ’>Õ3—ØB‡t›v÷u,+–æ PâXÐ7=ð>£zƒaTîعZ+E¯w‹{´?¦Ç7wO1†âfþH5"rWžÀÉ Ý'²èî'~°¸£§y®9&pÏèãw6mÇ*Ó:¡“¯*g!rÇ’ÒaNÏæF§¾¢fê—æáåvß•…G)CÊÕÎ+¡#9t¤Açݼ[̘¿m?¿ÂuCÇ Á¾93–Ý&[`2)³£‘i›{>£HôÛ3ëíž@ô<êÊB1§O`";^¶&ZÞ ~ÉÞ8tqSk½> £$ãâ“qÐ[úx™ˆÿQ¨ã[ûúúâÑÁÿ äÐá©endstream endobj 1043 0 obj 5823 endobj 1047 0 obj <> stream xœí\mo·.úQ¿â>Þ¸õòе“´.Ú&q„¦@Ó’eIA-K–-×þ÷áòeÈåÞÞIwrEªÍî93œyfæ!7o}Ç=þ/ü}yuôä×ýââÝQ¿øüsqôöˆùWáÏË«ÅÓcÿ[¸Îi®åâøühni¸×ó…a}×Ó«£-¿^­EÇ4vy²Z³NkÅôòe¾¼\­¹fy¾ZËDËÛtE~t±Z«ÎZçÄò Ÿ;®´X¾Ê/¼^°fùep-ÕòçUR)Å>çRwÆá¨\òNI·§Ic fMS…´°Ë3”¥ï´‰0•0ìÛ$õ]Š<·Ò½´âÞàÑ€øü$O5L \oé\ƒDoX9,ØÝt‚G¹ý —I˜WÙDd²ë,"µ6™T¶×Ë£ÅÐ…(g«ÿå§`¼çø œå:ýæ¥ãrVºÓt“w—n’õÁ•à¼3LRA&ôH*£ž¯Lg¬±–ýe¾D©Dß).©Û¡þ¡ç,ÿ»b¬B«Öö ¸>Òл×Ñ…uG2ØVºcB.è…)‡½,|ÌÛPqª#ñÜ·µ=‰kÆmpMÁ8™Wu–uÍø°°¥1 : sR å]uV8 ?rÄ ÿËWb‡+Yrã,_^¯˜í8Ó̼†9XKEýü§e+Â_çq_Ç•2ËhGPMÓXÏá5W ;‹¨–*‡ïO«“¨/‹’4=ÎHy™Š‹¤ÍæLü`'câ› > ƒBÙÎr3á&'9¢' C-,L§IؽÎÏIX‘yÇî;ÌÐ A2ا!aîJ+Ë9ýÑY~ó<ƒa†˜[|®:bÏAÌ»²›f8šGX!"?%±ZÍ*Sxà3Õ«ÃÊëy€øíŠÁbi5@…dÔ쨠‚7LLâ$ùK‚Py‚qFÆC ¾gxŒ+uKZ­)$Ì J×ôÒ{ŒeB¨„y'B%¼0€Ü°k€tk{6¬Š7”`½¤¸ñznRLV&¹²@(wm‚Ó#iä-É\>‰ö†FÀ¦UA¿/ŠH0“ŒŠ«vµ±l—ÒaÒŸãX'T4…¥þ”ËÇÿû¾wuh ¬!)eüšÖ üCZN²0ÄB§Ùð¤¦ü|‰Æ¿M_æžœt:Õ(ÙA¿—Tã…|Hªñˆ"' ó—–jBPß;Õ å¹ÞKªñ–`¦1Ý}M(OwM4^Kƒ„ -4AÙõ½;d¦=L’Og(òÑ2éH5ý%Çü?ç˜'/TIŸ¬ÁŸ5b3¨ÜIã̰Ê_acúžK»|¶’ØU:Mù”'~Zé ^ä»ßåËg¨—í$¸á7+¥±nG€»jÆmcæ)IŽÔ:–¦v â~gÁF«e mµ¥ÏßæF6Âç9{µz`¶\£OhïÄòÛ`«Ùò¦eïAÅÊÖ“–•Ïý&¯ñ›Ø^‘IO[ÐwðÆEÆ!dÏa‰y'ñÂ/ñVäF²Ú37†™œ©BÓwVûJ‡Ûí‹›¡ÆÐèRî%ïa^ÌÛ7†ùRØšÚošr‘ÚǨ˜‹˜èM Ç”m1—îX• µ7úpaˆc1Z–$7ÔóǬ«Iñ"+! HB$Ú„xíU¼€¶5¢“rÈ$Ä%ŵFoª^t+’q«\-àdVuJøÚ2Ž5®8I1€I;§ßjŸö™óY9U+æ›ÂåMºùnTXãåËÚ]$/µ¬Ç}øEúùйÎB¥—gj6v#=@»™X¸F­^S Óˆ™#!ßfS½3lª’EŒ”lj¼[fPÊ*Áô×ЪÅ&í¯GÇ¿Û/÷Éó»ýèDÊ7ƒ òsH!j)eŽ’ÛßEÇÙ•ÅYöÇ7­µ&a~5´Vò‰˜"ˆùÌè®·ªnä<Ý#µ¿ßv›îwxq²ùÕM7¿˜Å>‹€¦ÑöÑ)$©‡ü òö,&èDpغ½°_ÂÍ@mÕýZÛ1X€Cv¿`C±©ùEieQ¹ÜÔæôy´,Xß'T2‘¥ì^Ë„:˜¸Ì¨UåX¥ÉÆ6Tö»6¶ÈÙHý :øs÷µ¡¼žìkCËîtŸxý•‚\_ÕìóÂìL~¢[CÑsõ9Í@ =ÓC7þ„fÓ·f4wuÑ M1½Miúvyƒ¦o±u†ú¥Šý0¡È –Ÿ%4 Ó½…¡ùÍqh>ÃR&4Ý+KùCsE Þž¦Ž÷¬ÀØÆ¯Nr[¶µ‹ÎûÁÌì¸Ñs ·t²¢ó µã7|ü¹![ÉÚÐkJÖèÊcY šÞ–\Á}™ºÇoæÚje‚¹Ï’w‘H¨W5˜ÚÚ;k¹g›A$8I¢uÓ6Uä‘ðè©°äG‡"L±×&1ÆyË?­Ò)Œ‰¤:l½a¡³O]CU:eéC¥ ŠŽP'M;Ëø4¢OÐP#ú¤&ͪ3 ñå×Ô®ÏÝjCßI£;”[,‘‚Û= ¸Ã±¦(íÿ1Û\Å)É©ñ1¼::d)}”ÀîrnlÓöؘa€˜=%ÍP*ªpJZ×ñ…è;þˆôSH›6¨^HÏþ‡[gᢙbâ¹kÌ.d¼1:Ýû0gŒïäÖÜ‚WýÔ¯wq¬˜s_Bù—Êsòd‡­èÝxûãž>Q+…¹˜©gNãl¹)é/?åølo­\ •„¶S©ÈÉÍfX8pG»´i˜ê¸)ðn ÑÚ °\`È…RàéŠÅöÑÙxίHv—æ6ÇQõǘšBðOêa—!¾®ÑJVi¼»~áo^yîÑ[)$)"´¿òW3ïݤ{ù=¯6B?7~j“f¼i! Aͼí{Û*AÉуæÙŒìÙ%¤qè I8UÌW¬ß§ Ÿ"é5ªÊ‡&v(9ÏûäSR„6¹ké¿ëýð5ÏlE].¡‘é¿Êpæû0>Þ¯dM¿çd1Ú Ñ‡D D^Ë@'ñ*&þ KÒ{äµNr=AN¾Mš2^fǼõǼ‰4¯›3Œ|È †>ÄMçzN)®ö'0íÈ/ó¸'âU󈃯ªDç!2¶éô­ëU ÛR¢ùæ]‘ãÚŠàøôqß[Ú‹:)3aÁš|üF2 ÿ²àÐæ˜”ž$‹@ø*ÝÛ L:d½óŒµØŠÝí«¬ùØ‘š·q˜¼º¥ßùwëÊÃÇQÔéäLïº^ˆÏˆžxÉSµù†TÂTߜۆ.Ë9¤˜+3f”‰™_˜ðð¦| .8iÀ¾>>úþèíB ¤v!…âxÞæAz¿¢}úüèÉó¿-ÞßÞ½:zòã‚=ù3þßÓïžÁŸç_-~sôõóÅ÷“ßÖN«$…E˜H*½‹2¾Š·I£Ïæ:Im¡nÎSTôŽpÐ&q‡»d¡ û)èÆŒ°tÚ„’˜Ç! fÖ¸Ù³MT„•#Î@?DUçãxÌ$,«UJie ¤ˆ¬Íÿ‡\XLJv: T(äbéx›®réxS¡#Þ»®P´,6ߥ{ùêš”¢k ÍóÄú¡ÁØ  }63ªÁÑ&«îØn“D7ò³H@—xRò ³) ‰ÇB¤GÈJJCëQL:÷áÍ(Êýèû'~_ÓŽ>O þ{¸d†ö¯H“k=ˆMz¦;k;þ‡|ž0®«Cº¸gc_Í,\w²á)ÜB`—„l3·L: Æ‘M'ùL¹›qzH³µÙ©© ¦I-<:5í h2,aôµKØÁQaCº¤(Çû–Üð*o}Kòé™ßçÍʱ{¢ŽF‘®øS]MVŸÈªâcÁ#„Ì#…oËBâqÚašg‚û®`‡Ä³11ÞÃ8>1ìæ>ØŠõ³Äõú-Ù¼Yw3ór¡g¹çÃk…ÕI_jõG‚Q·+ÓÙmÔ8ÎÁ³ U·Òîªúî2s†f)d®1eÎ@ØÂˆBzÉ=D<Šô€µô5<£ôo¶ÅµGðýB-s£PKÅØÇx±NÏÎGTP½<éucF1&ÛºÀÛ›a6£ea•{¢åÁEõ`YHú@°Ü]â6VÚ~÷qPiaɼ? ÒðŽ¥Œ“+ã v<…0´È£:m.¬A£Ð~¥°®U£»hµbÆäm¸­Ãso nÏB»{†çÁEõáYHúÀðÜ]âvxj»û8ðÔ¿–9pbâS9Xõr·ÄšóN½XFoÎk÷꣔ÀZb¢¾¤PøY@©ùû$é%ÙßIO4¿¬vDñêuzz¶-n=ÆRsÁp˰P8W­%­+j«Ðz¤¶ ܺÜÔö§ýfT+T¿'ª^Vk…¨„µ{ˆÜÆ5…‡¨Žk "ïÐ,ÉkxjqìOžÎÅóÞTÜÈšdõöK™Zú޳âÏÅâÁåô¡˜Å|`î.n; ¥Ø}œFÂØÄà (‡d_=˵ÆÚé–D .È¡–')D>o€G®æ/* hÏ/9–úc­¢Ù™21~ÕÃ/xi¬Åu ³>yéÓÌþDDÊGðB_øWj”*Ÿój©håS«H–â‹»´­uÞ¾òÙ›ö›VUªßm.+x6vr…¬„ÜÝenC®ðŸ-²êëñ8ÀBûf6èîÒY “Ž$…¿?úwÛÏendstream endobj 1048 0 obj 3971 endobj 1052 0 obj <> stream xœÍ\Yo]·.ú¨_qá—JEï1×Cò¡u´.Z¤I´@ÛY«QYR$ˉƒþøÎðpò̹‹%»E„ x¸ g¾YyX‰A®þ“þúîàåwj«Ë‡±úü{yðÃŒCVé§ïV¯Ža˜ÍÊ Á )WÇbðv¶ò~P+'Å ÌêøÝÁ?ß­Õ Líáym’ÞÓØ´ÂÚÓڼ;Z6ÈÁއ¿…¦0ƒUúPÖbšÁ;{¨j¯©½k¶—Ìj¯©½zj*—ˆMèµc„3‡ÿ<¬Ýÿ®Í·u¶ëÚ{[›ojócû¾öž×æCmþó¨´ÿuü§ƒ0ư:þóÁñ¯êžÔæOµI¨pQ›÷u„æ—,ñ®kó¼¸fp~K÷cYšó÷3Ö^ËΠûÞL¤a«,³ÝÔ¯ß׿ËawÍ€¼þyí}¬½gµ÷–=¡×‡¾7^îMm¾¯öŸ¼f쇞SÊ=ü8x©è ¿ªþQ›¿šö]"7×µy]Ǿey8ŸÍjº5ÛI3äK½«×÷À^êc%èÓî›7­@Îû;ö–í%󾘮ÄäRËdxð–Š@êØ'²ûz6=öÔzh>3Ò«N4ȹ>°§m©8ñ"=÷l‚ݘ™°Ìoþ‡Ü€°¶Á¹ Â{Þˆ“A#exözÇ’–ôÎôeì%¸•™Î;Š/Øs‘y‰~zÁ" ™á´6‰ÄåÏ„ÜþÙuóY«à¼>Óöž%èº6 ‹_Õæ=KE‚è0Ö8oº{¬¼Œ¬N"šJs½Y^/ê^ïØ«#€2gIì=­½Ù¼`O{ÎRf†…±÷~Nâ/”ˆÐ¢®ëxÆ…È3X6K¶$¬FÄøj ,ÑL•«0„Q¹ fªL6ªSÈ`XrL2S¿9Z‹Á Óã…ØÁû4¬#à{D€SaÓZ%q#0 kâ© l:Y©Á(+Ñþ’Ã8Z9Ò¹®ë'S/Ðõ¦þý¤_6-ÏŽô`m0&ŸÙÐ3Ó<ŒÐ-Ô ©²u ¤-ä<¶à³Ôg€¯NKë¤üõ.÷MË)žÄRúÁ¯¬“ƒN+}$‡ ¥0”$ç•P§µIŽüËòŠŒ­ì EC¨«fZ0.œ‚²c¤ožá§Bÿi-£ÂH‡>–¿C§ nÍßkX€ M¼ ¥%_Ý”2ª@¸÷ùú !A€=$%J›€ˆV³Ÿ¯ëŸ§£jáž ;ÁS àhÝunÞô´„GD‘Á#l‹,vU6C€Ç’Ð sÖÞ4`Ô>ʈƒ%8Mïe¤S]!'ÁaAàã3`–ëº|¥¿á€óÚ{V8 A§€Øæð»£’`b?Ö¿ßÔæºÒ‚—@†ÚrdÈ[ØÜš.A¶sZ'#ØA¶NN9-ì¤òQ<„àßöBÆA‚K\7}…„_'ʯÎ&‡½;mÏXo„0/º´ÚxS1#»¾faŒ}Ã\E& ûž¥ª$âgÓZ( ·€ÚÌØAº‘òÏmýxšŠ5—œL“ÃÎöÚK%;?2âè@êÃß'mãGIxqäP“ŒÍ ä¾ Q5¯Î·€WoÀ:…Óʲ®¨ˆ¤­Ñÿ‚ºRkúîU‹Q†¸EØ µnge›° âÏŠ2y[ÔÅC§B°õ¦üõºô—ÖYþë. F†Á¥Õ#MÇ”°ô*Šz¤\S!éšå5¤#ˆ…1nƒ†GMÕÙ}aF"9wÍP G6À]{¥¦Ö(F×¢ˆµCðà£Âi忹FF'pþ |³PD> Ê…ÝøÌ‚\f²:¡c>$í‡#¸%„n¾ }lT‚5QçtS9=˜@eEñ¦?_† dó€hQ»èqP>k—‹#`PyQ'BB1Hð'ÿvýJP¤WÜì7‰ºNó$ÉGRùî{à'7Á¸íu@ÄuòÙÄZ*Òj•ŒÒzµ’0Õ7걕8Ñ“¨€¬'¶pÂWuƒÄ¶ Œ†Õž›>¦±­Þ¾êÕ.<é¦éÞv×Ms!‰`T*På33ó7ÛÛI½uhë»Åº Ìôj¢5X&íf$ÊaÆ€Ù¶J(^ÑánFD],~µÉªÎ;H³Ò©l¯ #m“/ªv£°[4ÉÂÞêßý”¸šÀWϨÜp᯾=øa¥§Œ ί$B8ð9ˆ&¸ S1¯^¼|ý—ÕûûÇóƒ—[Ƀ—Äÿ¼úëWð¿×¿_ýâàë׫o7&hø³ 8Ï­n7Qúî'ðr'ЀžL U‰£ÒˉD¶–5°Qƒñìxr2³ÝÐkà¼RrÔY#ìÍ3E9õ6¡ðŒ~4!‹l¬Â¯Š2ÿÓ °ÞáË:×wåï-òó*`VË¢Ú/†—*"€¼ IýÚ²•MbÙ¹pscXé£ÐÂe{²Ô~&£¸» 3žˆ6¼Í¸&çÎOÃØ$úr £¾¼¡\B#BG;©ÙM.ETÉ Ó€9wÆ4ƒÆMý©¢ýÓ6¬’ ì^ó`¨öób•´i©²å—pË|/·íh"Ð~‰Í'v›ï5nþf(ÅˆÊøYâiÑÚîU<ÅZç÷¤hZ 5Âù„£¶÷&IJA¸E0*p‹^J Zø¹~•Î2z»SË¡¶ôKQ£»Öʃ#¦UðJ‹‘y ²°8}VõDX„]‡e“+^ÒY²‚±‚žM $ûóéaVÊ…0!Ñã6=7¸&mÕáëz6Œ±z9Ä“Eºõ4ðžXÙ BkÖ‡šü—éŠÿr¹ÅRÙ»O‘cmD•ˆe ÁŽ~ilçʤz5|Èßf£˜ŽÕ´¥oݘ˕z%h,"r ³ˆì'„|•À­ü1lχcs@Wi~>F{YVÝSÀñ£r–$àS¨,¸,¶‹‚ž²ÿ3oWù–~¬gÇŸ"ßÊÎpˆh {3vAƒHÐ.–‚Ï0Rz@éç1Ø|7QjÜF´—?¿§ÀÞb‘û¥î\ˆšÞI>µ´‘ÏÁˆ!;›ãÅ8ÔÖf"›D 2æ®­”Ô˜O·•¶tj®s?\;Wê Ï‹Íú¡ØP5x\¬) ÈÌKßÁ‚‰?SÆRú0Ô4caɆ¢tÚë™v-ži´p*TwÖœƒ ÄïºÀõMtŒj–úf„@U‹Få w •é,’˜Àra‚9oX‡|–¥Ž…–¶¾ïÉ™l8,OÒv¤Þq<vi7üy*5 ½³1҄ʯ€õÍD¸jÛ6Ù²x ¶q™oŽJÒ•ßv“‹fÀ:a¼~AG¾­¨z[±×ªæêÀí,ax„GÐVÚ[›Lýø÷;öFçsábŸ¸1¢0ƒœÌ ’=q°p €/ÝxŽmWø‰µµ á·A‘ô5+­}Év½cœ¹g)°«R´ÒÅ×û†¤¶HåGXGt×®Ãü>\f?J]&#;2÷ERaV-›*)H·µ&„ª‰xÐ=Ò!&™—Ì@æe£é9ònU+«ñ`£ÊÌïñsÉœ,5õó´T¦,ZΘ»lÃg$K0ð®dw-šXWx -G~ªqëw…9ßìÜ tU.!úaÎ9´£Fª®N ‹öl:…â6òfrix4¾7Ï „®|°’ɺ^ÕMÉ‘@4R“B‡¿ƒ â±[´¹c^§ûÖ´žÙœûÙQ zUÉŠªðt»[º=Ý;8¼z€"®êI#ñ‚Ïj3kÞE“X:5¤2×|ëlÚˆdžïÚ³2c½ ®s'Ÿ²c½¤–“$è NÐÓ#û´BC8ÀC7 ^štäʆiÂñQÅ;óéfáhÑRë<ÙF-éyA×.we›päm6GF*B|T|ÎĨ㌥{WÆ6qGO±VELìáöÀµ¯«³û²ZJµ†-²ÜÔo’ï)¿–`œz!§ `sdóJ,¢Æ˜$X""þX‚ÿŽ=*]ï…J`*þ‰¨¤5Ø[‹¨¤>¼¿(*ñ2M+ƒÖZ„èo<+¾h‹EÔro|‹´iáEƒ‡$‚ÿdxÑ †ÿ,z=×x&ºv‹Û×°1÷…Ñen1õõ=.y_”€«cZakÙѺqŒÖÙZDÙ6ï‚#$ßë"kÝþ¶ˆ «¢Èß35ì5%øÐµÚxQuØ>©nø˜F„ÝØÏžN´±–žü}ÙèUÙüý|óäàWÙ×@m­Ù!P&ÀDêg ”ärö¦”šç%¾Dû±À2~eŠl›—Ì_Í‚ÿš¦AñQµúÑÇmz?±F  µ÷$@øe"nOi>@#bèú«7æbmá“TÙoÅ@îræ£?^͵v KÅ(›ÿÿ®Ð™&¾_„Cp²[ª@µMJ²­ZϽÙa’ŠÆP÷Ll¥±©Þ&ˆpî‘’\„ô©¼3[çÀMÓîÏž‹&ûŠérO|or[Äúú7"&UCÇU¾£æCÄ•ãI,_ìµKä¬òà±§%™ :yS« u De3Sa–ÀPO’ß\n(s\‡äâ˜ä’¦`w¬l-‹åZ,.eÕ¼„©‘ã$Fº6ɘ*Ú]ÇÅ™‰ø¸Ëu¿Û~@.y„ÝšóLcmmw.Ž>¡h¦p¶À΀‹é)X—$‚j‡¬…ÌŸŽ_8—E[a>xQ5ÏÅQ:àYaúH¼i1ëÎ’S•\ŸA'SI6Š›?Y~ø–¬!Œ´9¢XÄù)4 î*ðErSQ’ñ1Ê™ˆ" ôì$nÁ¶‡Å¬X03+vß× ™ºÂÖ3kqb‚µ¥‡LŸ©ÆàGþ1_“É‹sôæý” ÜÌ>ÝÙiÁÀ»÷Mb¦aâ¬àg_昜FÛå9’S‡OVyhN¾iý,/³ìË"û|jíé´j3_$:è…ÞÙÕ—&ÇЧ¿·ÚP¯,Ñ ¿H½2Ùq-W®¯FjÊe笷|I“Rç·›*]–(à`Å¢€Cç‚஋8´–zœÓò×{D!ž/®óº8ùå¹\*«"õs[£ <ä5Oœc±cÍïyAf Ý&÷fzkNŒÎÓŠnÀï}qdô(3äÍ.ZKä0ó‚ÔyÄ9ýÃnèRmÃI&¨›.9l¹µ5¶ÌÎDÖŸÛCؤaÿ6î’-¦¿“ZD6˯JÌù–Õrù¸¥€}ÛãÏtaÅ«a ?Tùyì9©MaÕºäÖÝ ù ü“ìJu¦fØò“,TP:ŽM%'{XüCJb1Î_g´,ËŽÍÖ7™üë®6Jiõ á†ïböÐz9z—¿cAÄÉar´Ñ‹oSjG´¯i7æöÑ´ÜX>GW/Á•‰–ǹøwæ¼²ËØ=.Õ«5¿ØYÔŽÍ È”ÝrÔ7I[k 1ï—ÈMð™^R»·¥‹ÿ~ÏLn~-ÀgNªÜÉ&WÁÉ8á=þ…Àx“;íC‰‘Ú œžÚª Ä sª™@†Î¢îª% =]R~˜éI’$ôåÒ*xT.þ$HS5ÐņZ…¼Ážíò<Õܸkƒïýà$pCÀ‰‹Gú\¿G~òíÝ1ñFÒø‚Êî'ß:Iá ΂r¨— Y|:Žþâ·ÿMfäàendstream endobj 1053 0 obj 4578 endobj 1057 0 obj <> stream xœí]ë¹q7üqÿŠùv3ÁM«ù& '€ï‘Dã»spY´/­à}iw¥HÀýñ©b7É"›==3;3ºèŒÃi 6›]EVýêÁšîw³¶a³ÿëÿž^=û3×íìÍÃQ;û7øÿÍÑ»#æ‡Ìú?§×³oŽa˜ÒrfgZÆfÇGmcU7lfmÃg†µM+gÇ×G/æ×‹%o¸tZÍÏS“ôžú¦j•š¿NÍ»ÅR·²Q\ÌEêm»Û¬ ÍñÞ—Çÿqäiœv³ã?ÿSFÊëÔü˜š¯Òœ©yŸ¦'¾I½ä¶«Ô²ççÕÞØøÞ»Ô‹ h×´VMÊŽõ4ŒðÚ¯…±†¸Zµ÷Õ `õPîE 5õmÀ’o¾JÈÊ^¦Þûê#ªcoK}ó¬_NÅæj ÀÆ5x¨Z‰“)”~[E3‚Ò„qÂ×]•ÛúdUÈ¿›Z2‘ƒOýÊIEŠˆOuK~½‹TW¡·U B~éÐsa3×8ÍÁƒÏ…õn‹áaÎÍ”åp±ó\¾] ¾Àj"ɪ±Ö9o?¡éZ%ç¿M½oRïûÔ{¿`ªÑŒ{ ‹ž g@|læOàȆàä :ࢰFkÅ4 6¾m´³’áò†Þ«4éyºía!¥œ”aVúo0²q¼[…»$Sutº«ŠÌmu?ë(òP½í>9MgU³7ÕËÉXžÁLá|i,Η,Ïu•²ëê ¹ûígÐ2à6hPëÔ¤^¯ð„~%+N\Œ©—˜ÝUQ†o¾I ú*5¯Ró<5oX²Ô«SÓ¦yeuςǭJùˆ¡'…½¯Só.Í ž*7@ŠlÖ úøìè¥æCI#ìMàâ{(ùñÍä-áC—á©Ë(¹g_ þ"‚HÝÓ7÷Eus‡ a輻±2Ç&…&F>-†>ÜšF&¹½ÍƸAZGI Jý²:íu•Üi,Aˆ‹Ô¼/o{:°PQàÉjoÚø^£ºõøõh™÷m•2²$¸*i(7÷¬ºKƒ-§šŠ½dËC”«Äÿ•ó¥ÁgUÇTæxHâè¤kZ¼¦C—œƒ5lý„tÐ ¡…w òY„®”ÏRÖñMóY}s­Ü“T¦ùBSO»tã¼æm_™—ÁßÕò,<­ÛÿZ°Æqg9•fà_6\·Œ‚n˜ÁT?I<âòHÕ@kE:µ“¾0ùPø:§Ìë4ù@ö$OÓÃM¹è}|ôÓÑ»™¦ÑžK˜Ñ£¦`Dr«ðïéõÑ7Ïž=ÿÏÙãýûó£g™±£gÿŽÿ|óã·ðçùw³ß}ÿ|öÓʳq² D¾,<ØŠ™´å6È8!”_ÈÐ:÷-˜ ¿*-ë¯bßmì;­tÇCìK­ÛxVQk»„‚Oƒ—Ï‹Çaë.^Mã±õªòàncÈ$B×ðÚZRHÒÇ‹¥h¸SÂ!6II"—PfdX#…³Ùœgqíkkºæbm0Æ@É®»W c¢mtÎZ¹/9CV]]¹5L{!¦š60…ŠC_f^FU\´¦b^cà$\pý?p]p˜„$ÁÁ]ºk€þ®9üОí®ÚÀ€Ö6ÀËz+o5›=nÁé(Äù,hD)yQIŒ!8pºxß‘:Á0y©¼ms±‹Ÿ0º>Œ_[)rB|W“9Ü\(¨Ì ÖÊpF‡—f…)A÷y-¡Ã“BÁÑdƒôq¥£ ‡üy›Œ£'8;ãh’ ‡¤Íf¼©°±&yÎ6BW6ÏÓ´ºc¡œôÎwʪã\+R'Qj«óñ ÝbŒ0ÐÛcm#¬q˜-èï?­Þ?À—V`¥Õ”yÿàE)CN¢Df†ÊÇ•;ë(Wi…ºzË=~Á64­õÄõ‘›$¤ÿbaã¸qt} 'E°‹DuÕa‚¬; š¶×ýõû.Í#EHñtO7ŒÛnËL+»qxÇ @jBÙT Ðú‡¨;.Š êï²ë2-!!1Eð,1…›)Û†·|þ<ÙŠ‹ E—B;Ô’%ã㨒¶Lé­E}D'YñŠ“œìöEìÛ þpáœåD Žß^z‘ÂØURMC-Qºw©þççMËÜN ek-€³ 0­ñcß×…¬‚Û(­¨xþ¶ ÕÀ„=¡“q7켯€ Y«³Þ•b¦dº j0à@,¸¢P{Ù©·p`#Sa@?ç”p£†8]‘íÌ%½]…„×6ó‚$ ÒÖÄú)øæ•^2³)²…&€‰lÁ:þýOç«X©©wô6mRî¾ùˆ† mHáÞ‘i×òôòÍyŠ£'Yü%Â*(é úpÍ[9^Ï·%˜„&êUË@³dlîby·Dì$CobXyp®yhâN$ÎuNB=fþ¯ pÙQºPAŸÃË|¤t7„8ü´®7È…@Ÿ–ìÉž¢_þ~%Û{V+…T.i{ ~[U¬Ýg }‰Áj &è¨e¸è…Eq2´zÿ2PEŠù»Ò¢[Ó?©Q$˜ÛS 4ÏeUl°"Q_Á»æN„éÑùåô¶[ú4übí¾\BÜ)ÀUÑyF 3-¦èrûØCðRB¬ÝijyÙYUát ²HÌœŽ&ãºiL³ÚÎЄCQ¶jþÃó´n´Ìܹ£@æm“ó¿€R1ZÕÃoµÔØp ¥ â ‚“!M!Xòk‡DÞô'‚èMuç!´çûÎü‚=–éÏñúQ¾E ÖrŽ**H"¦ æ@.@0’ NPp âŒÌýªÂ\ÇÂD+ü놨¾oJè6{ØçËö–ºˆ¬òGéÕd Q÷³^þ2m¿è=ªM:AUEØv2xûæ—àUF]è ±," âé`&xŠmô%fvœ¦ÞËIÁC¢|QE£©¡ÙdFŠK̃Có䌔P(úd®Ï¯²w‹zâõˆº\Ä)Ç5„›Ç,5ð¡$›5ƒCŸgBzCzªš¨º/½ß$üžå‰k¥{2taÝK¾ûÅ.pªòòÙœ8T,¬–“ºÁA–N 5hóMrpÕdmA>†u:¤*:ÔÁl©CØ;Ð!ÿ´à8U¢»Nmá«U@½Ëä)t€’‹v—ð`'Aœ¿×*0È£¾Z([íd4T`“>U_¶A«:„³¶¸ÜEþŒÀñˆÑ®aÉ[Æ¡Ä;;+ŶÍ<²DH4£vm<ÃÞ„\ÎÕªa÷ØZ* pë¦Fêcï ·–L4†Æ.Ó­aEbAãXØP9*Rà/ÿOw5oŒîBÕdH¹à)¤´ùá)DýÑÿ 8îÇfHÕŸiea&™7ÑrÎ)AÂlsxM½ ½®žìxSþ.2 eíɹ@jÝ©9˜HªWE5¤ZÈÆÀÒ稳^ÎP´X57Cà ÓkÉq¿$ £{›å!%tQï. DjTSŠjrR ‡>ÜF÷I{­Ò(B•æ°&0D7¸uí`”‹™›üXÅg‚å:ñ%A.Pl r^-aö•RµÒ€»Ñöªù)^ÔEøHmˆ#¨²!06Šèܧ<Ç“óP~ëNr»Òp‰”ßÀÀDLbmÞÉ0ã-Ìã‹?¹²j7ERcq"1à„½¡¶ù‚2«ÊNVWS‡å¡E¼ä^ A¼Tâk!IÚƒ»‚‘œ,a¼ü©Ðþý$ ߮ I‹F­Ü?Zò•ÒÓñŒ¤°`2¾:œž¨l}–H ÞÎfuX­Ê–ï{ØG´ØÆà@ݼ½ã5¬ RtíÇùåøZd}Êýk:*8Aý¶tVXH=­†yð›ŽxoºCÛÛ\ yŸò”ÕÜ\êÆŒ¦5›þpeÅ¢®øZ‡– qm,d¯}¤ϲ[ü¹˜ÿsúh7ùpoø¦…‘óŸÓ€¯Ò€é›_-â4ò€eê~&}„*|¤(|æã«Ô›¾%Ö÷†oLß0}›X$*Y¦æàëÆå‡¸ð%ßÊÙMW&à‹ØûõzëåY\¦±äûB£ëE–c¸Z·äwœ™Ê&‘¯‘O­œ¥^ò-–Ÿñã'[Ì[|9ᄎùϲÍ‚ºËnË?ÂD¿ãZ,ÝÇEüòÕÏéKd™W¸(>%5à"®Žÿ\½›æâ¦$½ü€[ýVDþ>!% ß®ÝßI%(¾hƒ½Dn(¥).’W£p›ÞzÖùªŽhñŒd¦Æ\x»©‹GF.ž«DCñÓÑÿHR³úendstream endobj 1058 0 obj 5289 endobj 1062 0 obj <> stream xœí\{oÇ‘îO~Š…`@ä!;êwOwIJ‘0Hr²Í;p‚Ÿ"a’KS¤$þùÀ©~MW÷ÔÌîR¤œ;GÙžîêzþªª‡?-XÇÌÿ/ý{|µóê[aØâí»¶øü÷v秦,Ò?ÇW‹/`š6ja;g狃³Öõ:N[ô}'–³Ž©ÅÁÕλ{KÑ åŒÞ½)CU†Ë0ÔLëÝÃ2<‰z›‡áé- Óíwÿ}oi˜ê´þ5ݛεû¾],¬pYž^T놸ØÝ/Þ” h1•¶p}&RȲ2 ¯Ý–§§eø®ú¹;øÃŽë”uÆ-þ¸sð¯Sü2ÿËøež˜_a1kvÿº[—!¢ý:Nîß=ªö´+`zmU†We…›òtŽ´0÷9ó¯{ÃØ ÛK‰õ¶ OËð¬e~Ü[*ÁX'žX–¯Ë„ý2á«òôÛJ]ý ®I²ïÊðŠÔQÄ·÷–R»¾còis]&œ– wå)’óˆ² °G§EòZ•áe"!—á)¯eÂ÷…´Âuy*ÊSVž2ò)¬«ëÜÏ3»…#"Ö]—§¢ Y; seyú¢Ù°›Î»ù kwûK¾­ë-ýç¬ Û­ûßí„ÖbïZ¯QTèçÊ`-‡ØÖ»ÅÒu °Ö.N ¨!¾~G*R³#R“©“ªÇ¬ÛdIÊ«#e‹žŠ‘Öe®€RM ù;Ò_•§ÏE"«HDÒZ"q©ž±>Šëd¿:%-øn#[]‘OѺ/Š”‘ÀQ¬¦ýzŠ×ÉMÎnª¹Hµ³_– ?”áËDYoq ;m7Ægk"1MÙåŒUb"½µ#ÊþVQÖ¸åÇ 5S…Ô%é‹ßU¯qÞ»&`=B|Ó4¬ÊÓ›jnpìšcÇþ¤ÒY«7H$¿þçPdóO® “ràÖñÆ Qß’9¤M7¤ã@+Ü‘á|´~ ~!¡¢³ÝV Íá|4áà6~.IAÑR¿ªí±?__– ?” /S¢Ð»Ç²b¤¾m¢€¸½‰¯«bZÌ ‡Ú,â° Þ’CB:Ùi9ô–B0ÿ¨<°ÔE rLF,PáŽû2Di$× 2ä½h…ˆŒ£ °HžHöïIÕ¾%_;'-â®Ý¸} ‘sKÒð± êkÞI3ƒ_‘y!iÜŽ8XœäŒgDùÙéˆdÿ½v>:£4+Þ­ãö{2ê MƒCi7‘tz‡lêŽ<Ôb˜1¤’›·$[Ðn$ ç¯È€1Úíé½ùZlðŒn w:Q_+ÉMxûHIæØœH6S€Qlãý[Ê>‘3kCïÛŠ_>BAö7åµ±v<%³$Ã\&±†þ†ÔP#6QVBóëu ¶”V°~]Ñe­øÂò¦<Õå©.O%õ4“ò®lz^†‡-UÈX²$’f„@P4@J…¸rJá‡I´–…8Ú¡ÅÆt-wäq°G§“Ô&#šMRÉÄq6Ô8ª&3Þ'3üq ¬ˆÏ(¦Æª¶”%Ñ8ûëÜÔ é¦Ö¾ µvnݪ¶]û±$oéò=÷}ËüÖ7!ŽXçdžÃóéÃø°ÎÑŽ:8!ü|NZJ9êÆB†O¿-P –î’ìç΃ÂÉÃZÅFUCfðî»\ ’xÂÇv±v…qM§)³Õ–š£×ZšôÄ tMøbJY¬Û£ïgì·mnb´D{ôÿuìÿ€Ž¥ÎzLy£ê\‘ªó‘T$A:ú5ݧqz@C2ÔÒ#!Yvg…*t!õG`¢ª@²üáæQIã[ß—B‡u¤[h‚²¥Ñý„ÖêÞ&ëõF/Kú¬ˆÅ}„æàÂ|›\›bºGÊf’„ Bõä¹ÎÊÓuå6´Ò‰^©ŒEz”ð!nÖÕ'Q#®Gòè‘E•çRÏHõü5©žˆu#MmYGk*ªeNzVÂýçοU»ÿFšÈu;ôÔ”¡*Ãÿ!çþGIz‹exQû c|á:g„Qþ&O×ÀœgL,”¶J7Á¾Üó¬é‡ZAgŒæÆ»?™zqä§÷°a×÷Îù<¤­R)Zu°ÐÆ`}­÷œÈSÑ„ïöxç$g*ÜJ¿¯Êä­:aXì©h˜l”ªsB›Š–‹²—ç¤î»>H%/…¦ÆUµc}"»"VÆ]…Ò7.@2Ëñ[i®‘}^Ö¿†æzS0¼S^Æ#p0…/"5)^úÀ}£ò[¢Zë|xË3Î?9Òm˜±xæau„¼kæ(ÿjXÊë>Èœ;Ì+­ú~÷`LN,uâµPÜ+ ‹uY4óhXþ²å‰V§)‡§Fq;Σ=yiñ)n_T‹µÌ’¿¶J‹ ¯½œu²·Îc‡¼ÙMFj,‡„¼¡FB:£Ö(¤ÈÞ­Û9•d ¹H"jWMGPÜ&ºÃSO·´ âàË: ÐÇð‰Í¼ÿ° xšÔ(ð㋲۠G•UÜ— …F¯FuLf9…ß‹&‡Ò{í’‹(\ä"gpYh]M8ƒ¼@欴»?•©÷#»ï-æZ ¬®›À {7]{788Gpk  p–óŸ‰Ýà7±cˆ›)ÇB$Æ1\“Pkyv ö©¹×©LZ ±ãp8Íuå„êmÃÔѶaÂ5ÁÏ|\…‹®õf.øpýù øó^jí…áGÞïž…‘ê=™yt?üz9<»Ë£Ù(ÂÁkô i%è_ܳøõ›Êï7á¤ñÛÿ2¼UI=Ú /:œ Ça¬¡&æ¢Íкˆš1ÿA€…®·År‘ƒ¤£ÁX­ü^­ÀC ¿¨G ÊËhXv…÷Êc2D$o{‚æpu¶gL [9cä/.±JÌ´(Ú ¥‡~¿g:.{cÚ(*eÇ…ÂcCˆ^?Sù œN $Ç¡µÝØ’´ìDµúš°¤­,NmÔ³Xˆ´Tmèx IëþsZH'‚<³_6óWVeß9kJzyM™Hf‘@j`Òðãò)£ãdŒ¶±B11#Æ’Ù@žØ|Q»{KÐm'cñOH€Ãç­Æ¡çÄ~Gá¢@­e @÷¹ë)ˆt‰‡ÞZKÙ¸´‡A ‰8,gC½)´_*ýk÷m@QÁ :‰ Ði:÷IþyÈmÞÄ#°>f¼”ß:iåÏ$ ŒHà5Øq—¿®–ÆÓó)‹û‡¬ã¾e`ßW&sÙBËgh(\›¤ƒûo€úN‡ ]r—ÃÇÙ`Û€>:æþ½¬ðýž'­XÅvDì_]o¼ê7T^À³ ™|SSó¹½ÓyÍ€ÆÒ³ÚÚ¶Áj7°þ9¬M2×ÅŠÖ„µIÊî¢X¾ú–S®É}ƒ¶ÿBîUYàÛá÷Èè^;ߦ’ÂGÑ  Ô~Xi0¶€ó¬(­öªÒ÷gýLaòPgܣɴ·aÚîÑûMé­×á+32Cª`ÓRrŠ`…ÀsêØ´±œDcÓ Äz0¶#ì!¢(9‹«þé1¦¯ –~Bfk3ðÀDð9q |©¹¹I ÿ ü2¹hœ¾4¦‘´- ¦¯,dC@Mí¾êLÕöõ¾SN á“DMÄdI4KÎûŒWËR NpJ8‚2ò‰Rt‡’²ñ2U–¡ó€)f°W2Už¢¡.+LVœì¤ÐÈOýÉ{V)@¾XÎ7ÜùÊ%<é¼:ñáuY8ºÅN(ux=¬ïa¬s`Nj½Cø/$ô¯ê8áöŽuVàÀoëW“›Sû-"1sÈ{GÖwFøª88Ðn(´ãØ k%Œë }Üý=":q£W3f`‡C62çþLíüf½ã†—¹ Ùe_ž²ô4vbi?à—µM|‘°@ ϯó³h@‰CVƒy•G§•=ÅÜ:1(…¯ƒ´ÒÐ0>dçuŸ¦Ø2¾ƒXö•I%¨"ð:ôÀ}G2!èÃ=Üèa5ŒN†_OÇUQ„<ŽU3åàŸ§fºep Só'†þåP@ÝŽåì÷ó¡ ga7µ ʘ*ÙfYÙÃé€2øPº!éCT#Ñ&!½(¬j\ƒw™Rì’½-Õ§ÑBIœCC”£ƒy¾1Öq]å«$n-'pY¡I,¾)KµÀLY\PG•Ÿ3ÊƒÝÆ†«à3&™Û°#øe˜œ€¥àÓ*ï4héüu¨3Ñ gj"aœã1¹4†m*§¨=½¥ýAFê“OºUØYüÊtUÐ÷Œ¥ÉÉñŸ’\ºƒšÙ()>K¸!|îû¶ÉÖ¼*<6Qˆ½ÝÉú¶Nx¹£p0~Ø€”…°c|£9$ÒŽÜ·zl6C¹:È™èí#6…ÂóÞÿ[ÿ‰6ÍÜlÊaHw>Ò„¡[¥² ëì ̱õTÆ…C÷olSî‘’w,_H±™îÑ PpžÞsv&è Oq?Æ[øZ‹'íÙ̸°t¶.ìK`°èùD«ƒv-£`ë»pt8…¬Ú¦«Ìéþóø9÷ÅX¤³d0̓p™A5u/G+}=U ÿ½±§d®è™íšÜKÅLQ1 •Oäò)‘òOõûaTƒ¯ á°ëF “¾ÛÚ?6aa‚ˆL¼ú7Ôð—‰ÓC€n`lÎÁR»þÁ'hXn81;“I§Ž ºjuØb{? MÍ1¯ºƒGV |š¥uðÀF"l/ë´w½6@ŹЌ,vU§àIJ?¶ÞC ÆÐêQJÞ×-ØÚdºÒûRÁø:¦…P=Üo{UÞŸ¨#½ÑÛ‡CßG“]ûâÀJ]M8Â[€njæËW*kS…'—òP”è®F=7¢¾t¬º0‰bÏÉt`Œ¬Ën'd#š(ªÝag8‚lÂna­ÈB_#ÔjÈ/u‹Öà РU¹£®¾z€î«~€©`V•zOæOVî> qÎÇ'l0éC¾©¦POëš ÚHC‘±ŒLqèÇÓ ´äBÈÄ;#3;åa¢á¨>ß ²à'C—‚2/*ýÌŽÿ Ó¬MvÐò€ÕºšbœW5U=¯m(RÞoí|“Í9l¼¨>ëŠANZl²îd…‘¡CÜ›,0릧h«ª²¦X”7…‚æøTQ>9;=]{OÂQ•¡HÔå´ËÂECý^ÎU׸¹ëC[w²jìÝÅT…;}¬¥ç¨8í!bè7b}Ÿ‹,ýœ‹k.Ú ËŸ ©J@R[m4@…îu¯¯›Áùƒ~lc”LsÐÌæVÝpk¯óõÁÎ7;?-dü‹¶@K¿àÌú|^w>ï:¾ÚùrçÕþŸw·÷§;¯¾_ðW¿÷ÿ÷å›×ðÏþW‹_í|½¿øföïãÒ”z9û1¡ÔUÙg(S7ü³ÜèúÔç •õ©oÖQÞû/K>彫)h]Í”)} #kë;8Ä c³žöÏp¹’Ô)Âí¶ú8Ö&9X–7ï9Ø Êê}Ò¥;CU+߯oäû½£dðâÜ×@Ü©PÉ#3$DÁÌåšOªIð@§¾Ç òqÁ$°¡ªŒ^îq‰Púï„xšrwp×2/Aù$åŒX¦äÞxëF踮h1Ó•{¿_ªNÖwýŸqô÷Üçná6åú¹¾XªÎÆèß7è0ðmæb„`B#ñÌ–gÓ…×È"È~Á+µUË" v}Ë"tŠ{dŽÈFQ–¶Dï¯IÇ8xQ®ÐÈÐ"´å’¢c¢š»+_‚y؃,Dö½õÝPÖšºûÜ\~÷7;˜n/Âù§wµfÓÔäGÝ©ºäž³#U©}ý!àw;çôüæj4î= ’QýtT.-Ûÿð•ÆCºpQ|¾,óa|{'} ëöòÑ]ÙxùAÌT'`7c³ž}LL”²-Öºƒ¡¡×J²ŒšZ·oøáKIÛ6SÓ·×£·jo>˜´iJ.ô×yhøc,4úkXôG"èi€"«ª²ó£œf¯mfžàm²úp"ÿœsRÅ7³ÙÐcBöqC1 ÛGՌ̙¼O^åä=ᬳ(ü•™žUÆ’· AŸ²q=mý¾R *3•ª0“Ú$7d.\®sÃx§€ùæq6ð&K´'®$LºŸøµÎS9ôåìIÚ@O~Ò|9›Ê›Ó"°XBX÷VàXe÷s ·.*'y a™þ\‘þF´©Ž†O$,Æç£oCòÝzåÿd€iÐa\`«‹Y©gÑO×õÚ°¦^ÇFºÜ¤#÷‘®˜ç;Ä=ÓhµOw9žþ¼àÙz‹±‹ˆ›wÙ1ëÆ¯¥/f6©3Í5ó š…¿¸±ÙíGÿM“0ëã+ÑùââS¬2ÉmY}Í1º.g-MøóD|± éެå-ê®°üp¨$|³ó†¾õendstream endobj 1063 0 obj 5019 endobj 1067 0 obj <> stream xœí\ëo·/úñþŠC§B·Z¾I‹Ý´U‘´yHÃô–PI§èáZÿ}‡Ü%gÈåÞeé"»F‘šà’Ãáp¿òôû´mØ´õÿëÿ=¸˜ìüÄu;=¹™´Ó¿Ã'“ß', ™öÿ\L_¾†aJË©kœæðïëãIÛXÕ ›: Ý-ŸÖ6-|¼˜¼™ÝlÉÆ ¥äì"´`Úl?´¤eo_ÿsòíëɓߧ¢[d_¦ŒqÝhë騦µž»—»“Ýï§·×wG“_¦l²óÿ/xÿìþuú§É·»ÓÀ3cª_*±|Ù›]&–ߥ¾½Ô:O_qÆáª­)XOnhkJ6®vžÑÓIJé=­»ð£äÜT@v¼µÒ’mvö¼Ì1“6&™ôëÂQx-?".c®aŠmx•:iàeáTs/sún×ó7–7<çnŸ¬|åðNø›äý&é÷ˆ;38ó vÝö$¬›}“Çø]¿ö¥bàÆ5\fü7^Lã€Ã¿nÍÛÆ´­Õ™©oÁhCtÞwÖ½×Më C-8úK£—Z` F”÷~ tPp­“J™U…VÆGÍF@ÇyB@”å‹=x–߯bY0ú¼–ø¸\Êh‘5¤PHëàa¼¹=>° 6Pñ•‘,7¶1ïç¿O£[Ir§éPbÑÕ¶* cI¸£D$'¥ qòØóÏÁ8x4YœEÒ¯~+`¿œÂƒEÆ`de¸Ù>¾"Un@ t5Hˆ!³ˆõ_Ò*:Ozªv-,e4(„ÍK€FyÌ:„‰æb ô‹Y¥gÿú¼>¤sD¼_¡ÇUF€™×! >D1 Š¡ÅYˆÉ½ø™Ä7ž‰ÆŸÏ;¯È¼mňÎßQ^¹h%LáI<ú j{©úå ƒEFˆÎì§‘uÀïe .\€Ývfª…‡a½™žÖJ`ù¬„³ þX:ª¬—™Óæ°´³RÓ.ô"ðÊ;¡2gÆlô.36.!•4šBôÂཎY]8’8­¬÷åGÔ;Œï4u4õ´/ª¹–þ ûÞÎD;iÏïä]KÌŒ£ªAÓš€/2wüãÁ—r" š €/ÊòqZ<ËçE² †A¼æbp¤Ð^Ä$•ùÈÈHiþY¶*©¯ø¥¸«‡€KÊTÒÔ«ç~«æ‰ñj›´dŸ÷E £A<1•ɬVjâ9®VÍÈ‘f±Xk<ý‰ ¤—™ƒU1â°<7à óðt¹jFÑ‹*dµ“þ A¯ƒ4ak²[×´’ó‘Ô=ȵ¨ƒn([Ê9àÇ.ž„ã ˆ@UwjhȄߴ8<©½ª!ß§`àmøˆqãHRÄ!”NÒ¢§þ¤!‰dKü„€hƒ3í¤hF ýy®õC»ë @­-…`7~@4[Í0‰ ðZÎFH æf€æšág9–¬a,nÜïUÍÜëZWO®ý1™FJM]Ëug䊃ˉV>Vïw½ bk€3 ŒFK®!¡ïú´ÎPàïždzdÚÀ¢1Ã.8X'ÉÀ[嘀>Λéq†Ì–y9>V@âÎxáæèk–åoWd›MÏTQ|][ðÚ±ì™@÷)$lY™1‘¡—Ú¼Šˆ \§ç4òü&f2G%&éò—Êܶ_ ŒÆññ0¯|?'n)»ÍžÀ8etô‰OŸ†S¿’‘úgXê #þ-N;@«¬½vç:cHKcS -‹½²‡$Ö?uêݹ{»§®¤žâÆÈJ´A¬¬òÐ"]³ ÿÞ¦¼ '&n¿I]”€èþÄeöF…Øs¼ç™H)«/VDGÃâì^g­~߯¼}©Ö?ÈX?ž_¤¥oxët»N×z­gïÓ(ÂÍãÞMûB†¶Q^íž°Œ¼aIÕǨ¸FÔ2V\è;WR!ã¶²rÒ*¤ ×z€Oýö Ïדs­Èj©™¦íŪêòbj÷vŽÝÆK¢ÌS2ƒHCÒ‘±‡º$ºrÕ´Z Ȳ’è‚hÃ3 AýgæcÁf ìÁ_<~ƒ®þûûºàÁ;4 `F •£¾‡{r*@›À$ýƒ±|©€ÿŒ]§P#W¸¶Ê•ž>ÕüQ#øò d±j–³§¡+‘žœJÜbØOâÀýÍY›óRÎÈÕnòÐe!·%Ä-“Ϊ.|°Æš“ã—ÂÕžA'Œdl~=þ :¼T¬[*8Q*¶„•óÆJ¿¦!Ë(·¶V:ÇÁ´¬ÈÅbú1ˆàP7ì?úWõg¤ŒQM…âCËJäw,¹Éߣl¼àé‰ó¿Ó>èÊTg.½æŽsîíÁvçòïÞ*üÅÅàžJºÖ Å  @&¹ŸxŠþšû=ž×^„ýëQ+]a…ëFc2^Á+Œ TŸO¥ðé À3™ ‡Ò7ý¯,À,¤uDƒÐ[¥f®`y޽ ö’±{mul[ö†&« ð›òø[ÿúý»Éë¿<;¶[°ƒ½{e¶™µvð¦*W%_— Æ^[;ØL¹Åªè$ö¾ýð}=³“QØ«ªBZ6¶äW‰ÕÇ"gk‹î !¡=ìÝÇÞÕóRÕ±{É´=°¿êÌ^TO‡P8(Ù)§b¯¨.Á˽ÑSç"klc“L;Â^…ͽ²I%Yеؔ%±/‡ú™jô!¾—a“—ž±¼lfôtž¨bå€Ð  ^i×´ÎnP¶¨‹¡¹3[(ÊÛÔìàÐ-ÓkÛOÄsÐò©Ï¡>1ùýtŠs Óì€3ß{Põ dÚ᪣¬öhN®+íˆ1C~í÷xî.WÒy\jhÜ8íº¯PCØ<Çæ‰÷6ñÙ/Ø{†‹_Vµ™(`[ë­$ ÏàÏØK„zQUI¢ÔóªÃX‰YÉn‡ÎøpÌ5ä½åfnq3D®‹ª´ÑBoÑì½ÀE÷Ÿ`{Ä5Þ¬:«aúò„;UÖÿÚÅP¨Tõo•x°©!h®b°[TÂÚ6 Ázô#&Fðìvu3d‹Cw·quŒ‚ú}ýa[$lûÝZÖ¯@ȆïWcZ¶ùÓ à’Àc‚±¶qìèf–6Q=.r´$Ô±.AokÍÏV‘×P¤è.YœH« ï:ã€Cl^ ÊW¾w%±ëŒBl&çØ»Àæ;l°Lˆ‘i§Ø¼-›Ô Ši7#Kt=Â4Ú©(Ü„æuíURŒ"í&'Lä´MÍ!é+§$;°ˆèLæqó¼;s¸«É5‰”6ˆo«½¹Aõjû¶QþVùç LÙ(o²ÎÊЫšß¨–ç!Õè_H*Mô»^X~‘mëYž@ŒÛV<¯Ó""¨ç¨õÛ’Ï‹ª`½¶×œV'²Ú<[ùtEû)H9ö"Œº+9XÇŸÝ®>ÒÛl#Ú•F•ƒ%f¡:YÀ—O@56 D26®öéaåqBV¬ŠQ„LÒ‡¡P ¡ÞþOSŠˆÌëd²Âm/)<Ö]îÔæ‘@ÐB9“þFRÛ lîcó7<|Ru½Äßa/)µžW§¥"tIvzZ%v]µ—›>£é~\ã²ð;ì%å^¢I˜MG3ÿ<$óU5ˆ\—<,á·î¬¾úüåõ |½_¥ÞÏkã$Ð<ª¢D¼%ë=Ó+l~=P©zÐý섌zô¨Þ‹J1k­6(ü‹ªdÞcïoØK`L] ùI˃aÜl•&z@Žn¥R‘›b5ƒÒlidáE¾ÅþÄ¢¶ÚÿÃnq,²ÞW®:ÔòÝç)ƒ7ˆÂ«‡Ÿ¬¹ÿµÅ؆(;.&õq²c‚¡ È>§Xσуç0Y…îËélìtÚÈÙÇ:î/çðQç@n1HrH.UdÙ[ÞŽ; ÇÆ+œ/Gñ{?PËès¬3lþ‘^rü§ÂÎúxè†1ÿ.K¿³Á¿‹Œé—¬?NþÐÊ!endstream endobj 1068 0 obj 4275 endobj 1072 0 obj <> stream xœí\mo9>ÜGÿŠÁâ>؇x¢÷õÛõ{9\ímp] [©“´òâ&NÑþû£F£!5C'qâ´»‹AÑZ %Š¢Hê!%÷s!JYˆð§ý\œMvÿ«œ(>^MDñ3üý8ù<‘M—¢ýXœO÷¡›u²ð¥wÊ™bÿxÈ¢Re%½/*)JßœMÞNŸÍLi•ñnz1›Û²®½×Óó¦é…5Ó¿"õ#R¯‘z9“¶tRÙéW3Ó[«äô›ù J8Ó£|eåôël.Kç¬t”ÓÙl.Jçk#§K¤ž"Ó#v5Ó¥µÞ˜wûÿj´`Šªô•2hA”µmQ×¥*\í€[Ô°VeЂ…õtÍ#lÆVØÔ¡i^Äue§ ¤!õ ©Wì0`fAŽªrÓCì°ÀGý‰ê’í«úž•gö…,ó é|)`“~û-’•¶AÉÒ—`P¾˜ûR;!]±Ú^Q”3„_‘ú*÷Ù–Ã"à&˜‰Ü’ºÊ)«î÷ý¾}¨E&&Ø›ìèðxïM|‘ñm"•ö!bLj¡{È.…¦öiA=ŸÄéóÑôzr¨B $0–å7&·>ÿ1ª*U|÷ò<¼®©„€9ÓCc ¬$<¯1^xúçßÿ÷7A: ³iòþ†>ʹ D'\<)³ïçDJQrÔÁc¤ŽÏÁ[$"¾E²µW›¾Ej›wz7d@ëá¥ËønhŒŒwŒß§ôÕR¯š©>Óf¢’"#AÙ½Cê Õ­”í¤ÀH²|R¥´™ )‘Í?̘1÷•k™5QhšC!–OÂ01Ÿ/lDÞj5íjÍÆT­Å†iRÒלQà[¤âûÊ¡»FÌ6`ÃA$eˆ™ÝþîênÉÄùú< eÄ$H}Š<;ÊM±Û ¢¤ÐðÇ3Àõ2ôÍ.Ó“Óܪ§¡Y†ãlh–‘ëý& ‘¤rö•íKl/¸åð3VٲȚaå ³GV¯öCwm¶Ø[Û0[lóvB<î7S¡)¼Q¿}j«ÞðøTeJ‹Ví‹ï>â$àqÅQÅ1Š“ÒdR‚µ6u ¡C€[¢]v­e÷í¢£©ÔºqífýI»“õÏ*nªjpw"€ËánsÜ,A¡¾Vé ¿”6q…¯/ƒÂArH*ÚYu›µ¨ØÜ0èø‡¥¿ØŸ¼ž|.¤S fÕóШ Õ—ÕÆëð¹8›<Ý›ìî½,V—×G“Ý7…œìþ3üóôÕ3øØ{^üeòb¯x}Ã/nÄæZy0¨?)6‚ 茕ìŒå@Nð%~·žm†í€Íê¦Zr¼^ýÓi||AÔM^PÿŠÔWC€CR€°?îš~Ì•Æ\)SÎýr%ò*iÌ•Æ\iÌ•°Ã˜+Ýš+U†Ï• eìaD²/º4éËÌ•€±ãæ?ð^ 0{ƒä!š_Ū»às2éJ#nÛŸÍu©¼Õ¾¹`À´D™°Xš‡ÅdÁzç©K.™¸èˆ ¶ò×WÝÉ_‚)~·C3 Áƒnˆ Uàinúsü½0d.Ík”Vᵊե©$òÒYSiSVÀw•e;ÊÄB3Y×ÑLŠRW:¥Sa…'˜-ábH E„m.7È·Ê*%°R à»ø¨°¤-$°ë*¢‘SZ“®æ~i¼Z “Ì8˜Þóî×ðTT`©@Rñ=$V5•ø9q½¾›7þ°ÈnýZ׌žc”§Qd…Äá|Ÿ_Ùqz°²ŠÝ\kÉŠjÃ*Æ÷a¥ÃIñ£XqÞb|½¡×mh{R–pFJGm[O“·ZDç.]ëD:<‰ŽÛèo³‹iæØ…*¡N÷bu¢^pÇî·ö(sÔß²³º‰äµÌO­æ^W.?êºÃˆ”[¾N×IðºJ]ñ°•À*:Šœf‡(9#3^I,² b-‘k‚&¢¦eÊöÍC:DûØ#±ŠØcŠS®"+®Mð¾­âzÔ¾´×e±A= œWT= ŒÔžjõtÆHª VÖâXë­QssYTtõYÝï?ÈôJ4x)Äê ÓÓ€'hØ=:rfÓÒù691Ñ<<|<6²> stream xœí][s7rNå‘¿‚oá©2Gƒ;&o–ã$JÊ»^¯r©ÊæEIY‰Ô޵¿>ݸ `.Gs(oJµUÖÙá  »¿þºÑxwÞwì¼Çÿ…Ÿ½9{ô×ýù‹gðŸ³wç’sÝI÷ÇKÙÙóAêNÛsÃzÕõxüäìÑ“Î?¾¿~öè?ÎÙÙ£Æÿ<þñ;øçÉ?œÿÍÙ÷OÎÿ€MÁ㮡¬kIvܵÔã¿ë[êÏÿéìÝsý>ÿ<{sþø©ë;;ºAs-ÏŸÞœù¯b猱ÎðsÓ³ÿðæì¿.øáRuÖƒøï§ÿröýÓ³Jçî+·÷qkÿ¸ÅŽÑþ}{¸ì;= Z¨‹ÛÃ%²3Â\¼:ôð¸RœÁU½Ò½½øåÀlÇû^\\.¡ ­˜¾xî$]‡¦”¸øyÃóôÜÇtóãƒì—ƒ¾xr€Ù‡w‰‹ß“§þÁò$‡Ÿ¬ëelJ {ñá :¥{mÈ/ßÑvqç§À÷°°Ì0Ôzï^¯÷­øÐÀ˜¢ŸõÌß+qŇð)î]ŸÆw½Å;aXÿ÷+D=Ž ¶ôÿn:!Òÿ·éýÏÓ­ÏR_I¯þ¶ö-q¤¤c§XqÚë—“¾2qÅr%:Áaõ<½†ÕBÚ'p]íëûƒR0gÖ^tÐèÀ»žë‹?°Þtš¿JM-,!I×ʧô®éùÅp‰âÄE_Af–Üû÷c»ø©~R DlúΪ 9Ò§Eˆäü«Ö ƒc~|p?˜›Òpé*þxQÞíߨTÕ[X,{ß7ða0žJ™¥Î1×vèŒöÿäÞ*- .Þ×î+ý0^ûÍv™ixiöÎ?]ŒÒ|7jA\ñçëlZ%S„…q3>õ¾xÞMõ¸Ê@ÁO"¯Ób&«¬ÆÛq‰“uÿ§CZaxm/–†—«¾“ùðþg÷nµq ¼Š?ÆqL—~I«âR ¿E˜ªq¥dm½¾ç6_}ô¹Ùù’u½¬NS"Wšá×ëLÏIn`†8_ø‘²bƘ줠ú­¥uuDŽպñ÷Ê„Ac‹ÂËe7ðìS7Þ£ð^åF§pÅ|ez ˜/cšÓµ ¢Hs¬xEËÞ/÷мSÀK”Ÿ,ø‰šíôŸ«ÁÚúŸÃTáÏ0SR¨EÑêA²yö™qçeœ©÷ãß&zî~hÑÛãDe²Ö‰V1W³¢ågKn-o£Çà|a[ŒZöÛôªëØ×¥9Ö ! ÿ¯Óaž†ýRªÔH¾×^çr‡‚ôË&i‘pª²Nt™ù¬qÅLÜŽ­@¼åÁh#9þû¥šŠÈe]!mİѩ:Ê Ðì"f½ ì[ôNß¹ ISçJ—‚"¸r„è¥O:kLA«VEiAõ_áŠ8íIœ¥IÑ"Ò†ùTr•ÿ€wÙöäÐlïí? ¯dYé?¸«CÛP²C™]ü<¯áûÃ%ÀïA(EûB¼‚—¶ ³ªczÀ÷Æ~Gî}7ööž¶å\ bÇ¢”Æø#jLXbb:/Ñqó"éb¹Ê†˜ôÚͱf?§«ÑhÙþXÿYÑ °2çô¿æ¬ø»ÓùœS«ÇM ¤·8—q(.÷ƒ‘ì})né§E\‡(ĈŽgL£¨äŒƒ©¨½: Öâ?>_ÓŽDowUìɧD4—pÌÏv0æê½hrŽÐ{M;!‡/ÚTÍäH„D`r¼SãÔº\osNÞ»`sHïžz•&K/X÷]¯xÓþ X ÖnΔ3tàÑujë.k– ¡‡Î‚ÈÝÂédÿ#¶Å¾ê©vt7ÜOUœˆËx6lÀï ôv-’ ܶ_#¼¡äM¼ôÇøã‡ño× EnÊÞ‚+¢ÏêøKÓ÷VS*ñc¦ܤ]W(ÄæÅÑå²NU¦)!–ÛLÍÚ”]|}R·u#÷6Óñ"ç7ÓšÁ²`$’‘ÉÍ’ °f‰A»+-²aÎHùÕÃz[½—,¿Oe n0È ©3Äd‡OÔ}ÆÞU?üc¶j/™r4Á%¨kãkC #aè}çå*|‹)YLgm¨<Ž>xUZ€Û³B\‚›åý¬BwGóL!•—$&€’v´Ä0¯ÏÈ‹È"ަ:—‡ûÚÚ¼¥«˜Ãhµ¯¬›£WE¾Ä”ÿ\¶„‹å¦ºÈs.8Ró¹×›}~à(®ŠMFá€FcêÖëLaàJË'© 8d/ðh“7ƺ.ò䳈J™âån.Ûgm@ÞËW>¦©jàZ}ðÐ…ix©“%µ!fxúî쒺׆.=ï’¨EU^r­ô¦ë“¹A¨NnMš‚x ¸ú­í’2ŠT0:c±S6Ãò7³©–ÃzTK–»(ä±®-tF90—`Ñ<êy\ЕOc®mgddèz#izÖ†‘¤×ˆ]†%>õÁ»ËP£ñ"ŠæÊ©Ras¬#tr‹†5°IfùG­˜Çýj¢x`B~8ð±D~XÇ5¸Ø©ŽM60G¶žçýಛҀï7jÍ‚ŽWc.£1z†¹ŒE"_‰‰/ÇÒ3 ãÅšDy!Rg†ÞlD®ð‘¢ÝJÛ½‰˜%ÄÉ@B[DŠ¡¿©!vò¦ºç¾ À9§»Ï¸ò<'ÅwÛ®s†\×Ù(¾¬ÊOç 0´*=|kÅ)—kæ×ÔÔb”«N•l†í<ë¥)Î)l…š S•;…»`Ë.ÛIRGܣóq7½€_;í8ª©:iÝÿÛ\§£9 ¥õ.…ÝBZŸ¼Þã¡ý#h9CîVm¯œ—ÀxŠÏä÷3ø?=;bÙ&`ŸFN>ÛÌÓAžˆŸš$âÒÂ,™*ÇMÌÕÔ¨Øåß1ÿ¶þ4]¹«"dl‡eêYµ¤ŠEN*¸¾P ‘ŒuMâ’Ü•w‰zHV 朓¥®~)-Š¡ÒQ k‰"G`¾P–ÚªrNŽjª²‹ Úá§­Ï·ð‡h‡YÄMw1¾wo“Þm14ñ¶•˜©¶/ÞžD h¼î¾*ˆ/{U‘Éå½J†'éà€ùۇ\i~ÝfEµÙüºÇò2q?e?“ÿî6kæt–šË¸yÒU¸&tÕâÍ~¾@²}Õ¡%âi#YiQ-b:—˜)òÊç3Óvªjáut«òꚬ~_²'ÛOñA«á¨è ü áAµ…à`n2]a7ÙÚ¥üÜ—ë[cDá>XkbMÀÑÕµÞûT ÷!¢´¡¾€zÛ†Š™…"4Ì­f»ØW,&È{¹‡}ÕX>>‰ž=ôôÚ£)·{F+øœd­P~v7—£ºï°b,!2OËx¼5³ƒÜ÷¼r¾bJ;±\ýq6Ðc6J(ê¿y”Ž™âŸZ˜l‡)Ž…+ðT‰1Ô6U$-Ï«Ù÷ä½ÕSE"£+]Zƒx‚ Y¯d°ëÛ]êéùc!!±ÊtL0q>ÇLƒÞ,'¢UšHO¬Ü‰®9¦©]:è!èšw¨M ã|yꌮ9y?`$mF·¿^þu䟹D²­[6w×ÏçŸm„Œá]äê\Žt‚„¾Uÿ<ËwŒú½“Œ­R&8¼QS8SÌW0 <å#Uìð­LÙ\ÙHmXÝv^_gHSÍB8¸%Y ¶Dvaïÿ‹ªj®ï2«ïø5-ÄŠ­pq/oÉM[sÞ¶%ÕÇ«ºIÈÚW10!¡}cåxùŒÚ#yß[ÑÉéÊ+¹˜¥Ì¸¿R®f»ÂoÙJnw³àG5Uåj ¥­åêŽ1¼¡Uix·” >}O½é¥]ýÊÕÇÕ¬©ò‰\…le5YÜù©w'¡¯Â·±->L"H±¬yÚ¥UË"¨½Þ¬¤]Â~ÿÏ ]p“½œgW1Í® Ê8†F´ìéL ·­å n¨aëÈ©Q«È—É­›­f}aDdi5ÝUÕÞy?ñ!O3ÁCT,žÃl ¥¨ßE£ž[#Ì~d[ŵ[Â,úÞÉ9¡H< õl ÿ$GK„GŽæJ¸‚+‰Ñ¾]€é|0—z©‡Ô @D\ɘøºŒc2î®ôG¸-n¢ØaçDp'äÐÄPªß눣šªÖüårØZLë(8&±ôÇŽm)ÿ{úž8Fººbs¾€ ²:»ar¤VÍâàc`ý¾ÏA¬V`$wþ8ö¥ŠìªÔC]=ÆlÖJ…;¾ï`\¼‡jû›*šúø{c»™Âq–2\&s+œ‹àЃX:ªfØ ¬ÜxVó7¾5RûýùtÞ ëýÆŸ¨ÂÜNxÀ»”™*kêü¸!k“R`ˆjuyšIš3m£'p=3;{÷§ø«šã—˜«Ý0VÜ}¶.IuÐfÜ`ÄÛu{#ÒÓ3H/ˆËšPSø‚áw„ö:'úk­ù:mG þ§ƒ’À’[`‘U ^q„¾°$G™TNËîVÙÕù+óAÞ²V@¶Æ ^E® “ÖFÖ|âc£`Éì\ê›xòÛL1¼LÜün’8ï›­„`HG˜«òLˆ'¹êe<¦A˜Å­3kÍZY•òµõâƒS&ÒæÙÛ¨xGPâª\]¿k}g§âE`¦€ÖªŒ‹×ßöèî¤sU&¾L½¨{ðíš¿®„Kåð©2’]„\Cå—Â'‡¶Iu\O}v„öªÒ0a r—g…w‡jžÛÍ+êb›>@ÏwóLŽi*~ a˜݉#E'w'hãiTu¾´®ïçèMœ¼£Þ› =ýGä £J¨ïІר­b'æâÙå ¤Ù ŸŽÅ¯ÞWN.‡†5BÊò»ñâÝxãX‹üJ¶–;ç éÚ~3è: ™³1{¯ ÇÍ嚊™¡ÓC»ÀHhti @!c}2Y³çñÒ8<ÌÀX, ;-tV~ß@ßo'uÍàÃÃ¥ÿ\3Kbpùãkgi-L}–v¾Ágš…5+úš¤#&åd˜/§ÅzšîWÏ<šœ2Ú.Ü)`l…=+˜àüj<²Mš95wz^^^–¼©ZR7~€¶è¼AI ’ñ™¢ÅÆ”xüJóô*PŒ–Ë«¢§¬xŽî˜°z’/†MGs”°²ÏÉ€ØH Ç2b}É`!nÒi•"g:>¯"ú—¬Á¬®еÎF¨¿nrƒ“…qŒ&çÖ¹«b×a¤ÎÔ²_#œnJ”•§¹„‘ÁKQþøÇ:âš ÷}òF…Œ ΨB … iu^"YD­­‡‹Tó$-ÎøbǺCR÷¢s¥ÂÜ…×Üt©¼Y^ÂÏúf,Û0 †©FcA„çbÏS¶ÚæÌ{Ñb$ñh‡ €‘uÉýw†|«hý¢WMLý©p²:k¼ŠZLdK0ïëßÈÜV—"iÎm¹“º§ï 2È|þÐRlt-ú””;`ò”àÓŸ¨¯!üÜqHŸ 0¡Jçß°§éˆOãÏÝe|l¯ÜB.1¾¶'¶Q7´›Us”t¥ÄÝtÃå­_Õ½m3úká´u¥½¦ËjOËOË‚9è’áéi¹à……"•õ¶²PÚâ?Y(eþ~º•ÄÁóêù•©Å‘\[)·œHA’í'óƒ†0¦=²VÚ=É}Ýd¿ÝCvrs8DŠœÑ@!„;׃k[@FîÕbõÛ•tk V—¼x¬Xü—5Á¯Ã‚ë˜ ªŠJH!ù¶š«P-'CÖ?µ$ f-Âõl> stream xœí]Y“ÇqvøqžyÖ¡mt]ÝõHвM…DIT„å‡Å±Â @€Døwè;³ÎÌ:¦{f{‡B¡bÔ3[]G^_^õãõ8ˆëÿþ}úýÕ£o¥¯_¼»‚ÿ\ýx­¥4ƒv_Þêa¹¶Ú f¹žÅ8 ã‚ðå×W¾þíõûŸ><¿zôݵ¸zôøŸ/ÿKøç믮ÿéêW__ÿ‡‚?wãØi Œ¤éFƒ>e¤ñú߯~¼nÞ×៧ß_ùØÍ]\ÛÁiôõãû+¿*¿2ðòÞ„Ï¿¿ú¯ƒ¸¹†e±Vlúøß}õ«ÇWÉ )ÝzOŸí©3• ΑNõ‹›Ûq0Ö5îoàà€ÔáýÍ=MRžßܯÍ$Ìá§›[iÕ ´8ÜÝܪQ³=<Íß¿Îõª9À›¼/ïa¬e`éô·ïð ó0sx–û6 #,3+gX<ü+®aÇÅœ#®ALŠŽëףƙÍÌf…˜/ðž°ñÅðŠ;?s£º!wøSxŸ‘‡é§ïnÔ0M _M1þ"«$ËKº|•òdòèÛ Î‡à8,S8C5®v†ßÝA©y†Åã½à*ã÷ñÃóôÝ¿†GþMRC&É^ó4Í1œˆ[Ù÷¸áVNFÑwù·ùÈžå¿rûeF3~ç˜uØ:·3@pL–>Í•?}ȃúMœÊ3!IrŠk[«œßÚoùöÍHøAÀžÅG›6Tá$R½¡H_7Ô­Õ³@VZR ̓áŒn, ^y+İÌv¾~ü ÞM~þ2³ì R ¾2P4ÈÑB ñ—3e—¥øZ‰y±^LGiDk:r…È×83¨±`ßô”pŽ«Î…Ãó¼§Œðð— Vœà +$¢"³ꇼÏoÓPo,»Š žv¦×cù8“ "ǽ`V%„]yÙà~¯@0.§IÈ÷7H6R/0"®#—æ¶ð ØBíë<è›#ëv›Éå½›¢P”Øè&ãv‰¥¦ÝÈýn“,=8¿ØÉŽ ]Bû„Ÿfn{^LÆ(!ɧ·­¡Û… ¼Òoa[ÍõÙTsäû&¾aÌ¿G¹0-(ïýÑ_wÜC§û&Ý%T§ðÔÜæ3²…^*,ÆPŽB³aîÖž,ÿ¨P 9€|=<ÀD™¦‚06ëV·×fžA½7êÏ»ø¨PðÝq• ”.5½½?¦WÊ­Ø/´¢f¼ÖQÎyëÈÉÝL¤ ÝeTÁ†ö—£}øçûe„ö"|µ?ÿµ¥ôö,XŒ%{gŽrG[±¡ûå+& 2’dÔŠrf‚o•ú¹¥p+Læ_Âiw™Ó‚Šæj2²ŸV¢Ý_‘÷ÿÀ¸VNð¢†eê¾Ïzø}µĦ΢w Ú9BBHBF£ýÓÆ¡¤‰³^æÝn«î·%9»£Ï„ÍŪÎcë4Ýd¹ýàb2Ä8Mu[ ´ Wò[2[2ØÇ|Ìï¼ÎTÓ õQIHcm»·€ymã%£š$È%ã¢M!ÝËFM8ñ˜d7œÑðhÀÖtmµ’ìÖŒ5e›@pÖ-Xž#ýþ:Kv…ßfb¾¾½Ë ýTë=¿‘ $l“[¼£Ð¥`­,öÞ&ì¶²í OF´·ˆÚ“9^þÙJÀÿ¾ÝC4KË™Û$Ã’›@s/›•5¥X²hFÇÐimŽò0‰þ¨·ÝÄ&]‚n m‡?Ót'4œ½ bÑ?$YB{2hU`PÌ®3{c?¹Îm`Õò¼K/U¢{+1`ˆãy#FÏK!xøbíJ Z_–Vp 1$‰ÒzR,@Ÿ,dªó.4!IRÀ(’mº v(ð:šÌ€&ºŒ,ûi© ñedØlk×h‚³tm«Ÿ’7{p1A¿FZ#vycÞè¶di“5Ÿ’Ö´Hì÷”7ѾÿŠßÃß‚òf%±›vèºì‰<ê7^p…×FÚžx€ß8ÄlÊ1À•ë™>”4È•/ÙîZþãOQ”O`:Î2m·¶ôÏÚ¸‰ ÎÊ÷Ÿ É.]…¨õn¨ÈK¢º-O%7›1ªÛÝ©“ÊÖt·j*¼³Â¨°é£‚Ý) À¨XåZ±9úë¥:o¨¹ÂÓ*#üö¸ù£·Ýí€K] k9LQ>1£Ô‘úcÒb´”²$쓆ĩ1iH":!Ýú2˜4ä4žIs\´HúÀ˜ '‚R6. Jñçê)¦'©ùÂRö¤Õ€Ó€Ó#àôtHÔC”Ú*÷ïçªÙ?FR'ÂÜsÀ©^\Ýe NÕQpÊ{g\~¦œÒ©bßmG3œ--˜rÅù¢£»Û;*9𗚥"¦m b¢ƒ+zsú4®D3V%ÑŠ¿ÞÀ””š§–~_Kn5V_TL£¤‚¥•–m$%ª4ÕVB$ÌŸZ4FéσiC¦Šq¡qTݬóï2yÌÿ9¾âŽÒŽœÅu]qŸRÌ:Rn]§9£ÞÇAƒ.Ý Œí]vŽr ÓH_/ÓëI¯Cò´i¡G”ßäO »Ô_eË@IŠÆÚ e)¿liøˆþBiNA° HS5£Þ_OÍå¼wÙZôa‹œOñ›âàPå½(žy¿MˆFí »’i>¡=ùö['Y)º"nÔñÁ¶rVã³³|’NLâ4ô4-—’Ú`{¯¼•¼€J Pó Rü½÷x¡ç·ðÂÔí{ Á‡÷H‹ëÛÛä(êõ­éá×X0“JZ d±9 /8mmÐÌU-KÒ˜áÍØ´¡°ò®µóãª`né^"y;m}3MƒKVrÞL_IaEKšûÔ ,N‰ÍžÙ¿< ‹ÄmyÄ–8öš"¡ÈãHî:ï¥UC tR/¨õ°µ™ÄQÂ^UÙy¯xíYCÅN–$ÃHŸ"^«|g®ÕLc–áçõ—Ÿ¨×’™’›V5ºr¡KòÇ“.þ)éìlxa~爱à˜ßÉUVäoÈŸÄoŸû-kw1[Â6@ÔVí\á•ѳœBWD_ÝÓõF™<õ°ˆçE÷ºs´”ž¾ø†»œ=Øì Öm G=O3–ýê7›Ö€4–2ˆ“i/¼pö!h÷¯8A¦Ö©kˆS°ÆÅg°™ê†Kq|sçnˆý¦Ï7v|jœlWÛvȹh;Î`ŒK7,«9Ö!h±V%3/‹Î­eÍ|¨‡è]XPÝ[Ò¨¨òÓ)]"¢‰`’ÉòÕ»73Þ*X8È>¼aÝ-AdV—µ–ЯsY«“s`Výœ=ÃÕ%…î¸Ü%(ÀR°7¼½I×춯#¿%ôeÌ™zv¸n§™vY¹”-¿ê†ú˜Ú™–¼‹ †,Çn—«šfʈGvYНJ癥éŠÄN´¦yC[QüSbÙX™PÞâäÓÎYó'~paPb‡ÄVÜÊvÆ"å ;vßè¿=-´R¤ïø2AtSã$þrßk“Ý€äúäÆ{(OÙ»:Ñ•,§·#›½µøöÖ+®&`ª¥.²âWD 1†Y~øò­ÇVÿYîñ3,¥®¡é‚cŸo¨fcPiúAо•ÍšÍ×;ƒ^~¦Áf%Sårwà‘ ëVï€ {Ï7 ïY«/x®ÌŽ´v á–L9N˜+J'²‡ /RÔÎ÷©ŒêTñ¾j²+-] 2²þÝHˆe›7™cê³Æ†oéÕÕû ¾Ä€±8Ï…gßÝX¨û>|8@,ÏÜ!†êwW¥­r÷à IåÇæmu.žl”r…?¯¯^½R™7~ÀK½òå¼ÉçìxIw¦Ú½5/Äúâ6_ïz¦ð&ïTï]¢G¢e«‹E¥¨­ô蹟’."ä@šó¸ò[–Á+…63 ‚·jßS%ÈBè±S"tEöšœa.¼ã”‹5´‹8Ò §*ޏ™CùÇ™—¤¦¶žk Aš@áM aMBYŦØ/VšmÕÌŽœuc­‘ZýavlSFØ.Ú)¦ú¢š¥t}»ew K÷*ìF-çŽI¼ZÈ3ò"5›a„Û§Ü&†ãÍô]¬Áliº››¸¦Ÿ¾ñá»kIènëÉdi ØÂ‹~ω«b\àüi¢7úZ(§y>]Õ ûfû‹àY˜{ºN4tÏ^ïi‘úâþ–~C&ý؃J5ÙÃo²×÷ÏbIïÓ–Ô3“?ÊôéoÁ±¡—xÏ“JÁ3»¤@æÅ‰®—x§éFÈžv¢^'{Rˆaÿ,å”gìc¼tâÄ<§Ðñ³Aø1£Ï¢ÈÕ¯”_‚]\.2„¥Ê£•µÅ=žê›·Õ&Q>oë/ÄKôbH®3„Äèî9N–Êz(»·Å$úÕ|‘™8¢3BGصØä礮†óüPn‘zu´ÂD7.Š9qí*æItÚ)l¸ÓÓ¿wb„ÿ¶d—Â)R¤ú-#ìø!´2m¡ÄÜ57`ýÝ7]1?åø.¯9w‰ Ky×­oìNûò½ä6óø=ß;Q½çÅS{éM­Šë\=N™"èGJôª~§R¾@ÚýW2ßW8È«bL#ÖšÕ.­«´Fx#4WBÞÙNwñðf¨g8z~™É^6¬&aâ€Øát…ýÁ³žó±éø0-ÿWÿs4ì×endstream endobj 1083 0 obj 8351 endobj 1087 0 obj <> stream xœí]Y“7rvøq~żíLÄN±p~)ÚâFèXiû`ù§H›â Wœµ¸¿ÞHœ T¢º«Ù=¤7Šà´ª«QY2óËïÏç‰Ïð_úûü׳?r=ŸÿòÛ™ÿçìý¹ä\O2|y%'{´=7lVÓlៜ=xòíù‡¿Þ½<{ð—svöàøçáüŸ'_ŸÿÓÙã'熡üÏÃ8BÙ0’œxi†¿û4ŸÿÛÙû3è>Ožÿzþð:ÐÎÎÝä4×òüúÕY|+æïÒþ‰ff\ÿõì?.Ô啚¬uN\ˆòñ?¯ÿtöøúŒ –qÞw;µ[)åhĤ^_^‰‰;iìÅëJõËË+‹VL_üõÒ/_µp‘»y2J\<|/f>_§Oïê˜wõã¯ðÇ¥¼x¶x¦ðý˜Ü²IÌêâ&Þ`ÍÅ+TMÂ|^oß;ÆTUi?>­÷¾+c½¨¿úÍ?ˈIuñárös&fÃò\ø[Ñï?~7kޝ¦ `ªÎ€u+¿]ŠI)ËùÅ›ðT¥8KdÁ×i2´°i|åf‹¯¾€)âðŽô¯nËÅ–¾L¢ïiýÕ‡JËËKذ\?Šß<×/üfA]Lkx¿Jʃ:RzíW3-,7 ÏÊ3¼yZÐ÷o1U4­qg <ÔGX 3Í~~뿟·~“¢Ù~NÎñÍb^Õ[föR ¦ê*ÍÕc“5ÎÄ)ûù¢ðGÎK&Ì^@ºöROšD¥˜¥½øé’MN°Y^\•Ÿ?º”“âÒé‹'åÚ¿–û~ò?Vlšy܈ý`í@Ú0·ú Ø&õ"š¸‡áñÚÿüçËz룪ÉÍ&SW_]†É`žHž‚—Vròâiç>½­3O/ÚÈèguéÂ'=kƒûPˆ‰Í†æžäŽ{ŽEAy- ÒMBï~Ù;Äþ‘»Ô¤3s¥ûüi…^˜I„jØ)Z`ñµ`ùÌg0U’å·2^ôã ?ây,_ò#–¬L1­ŒcV[˜“ð¡¹Ê™õ‚—cÂhy~U–>qÌÛãqæ–Òíý(í¹“‘ +¡;ŠÄ%„ØYcIñ!2—Óòâ.¯æI;¿Ê ßñŒ7[LÌR„uªmà©ÉI¥Ì2(fæ•¶B†êÒFrøû¹†Ê/¨pÚ· Þü"MKì&W±[¤3c·Ó±¢tt³³ÿ½ßÀ#èf¹W \!¶¸¡[É«¡#£0ãØ$½Ü…Y/7˜wð2þÁÊdx¥p ÛˆF g-ÑŠ€ðsÉC ÀÔQsÍbï]•¡U°.@b/ü”ÛUp>aàf½ °~«Ü-ž輻¢[Ñ;½…±ô4 ‰©ªc Ÿ^$4Ò1íVµÖQ”8lJ´ëêNit›'a¼–ü½Þ áu'ç|ø(ø•‡e ­Çû¬*Á%ˆOTíÞ(yz@d3§ü¨™+…Réùx¥ 4 €$?©¨’°Óê[£=õ¶~Gñ ¥¼$óJÄŠåýL‹3¬ñügüW'Í/Úsíž_ôýsŒÂN ,äò^}C à$íñ­»ÑÂB-Ì”–ĸm)ÃÛ™EŠªHDð-ŽŸ&&­ñÒ K×ú«)oyð£òrIxÏ—* y¼dkG)ÿ“ÇÝV0àƒ´,@q¸„´’˜«æL{{ÖÂ( ’OWI+ûGÄG‚e‚¿/»ƒ`¡`ºï‡`a½AÓ| þ±üU¾ô]þðÓò»ò¢×å»'í»‡®¼mç¥%÷8Úc/…„ÙøÈÁ´ ˜¶{Zgá§­Ý—?f2/_áëõõÊÝᚉ(ÿnÉQ?äKe(ß=ö,m, ížý‡ÈЬAˆøU%˜™÷ôª°ø*/ÊW–üÞxQJµƒý‡¯2Á=c”ï–¬X~¶`Eî<+Ö z% Ÿ€È‚V*?G*Àtÿª\û®|ú);˜K¦’ÃÝÉç’),/îÊ\þ…x'åÚ5Úà;^Ãß–Æ>ýkXo@6oQ§ûÛò•9GüÊàèNiâö¿‡wåjÛ½ìºSëù¾ö×nbÊ5ŸXyæï¸ç]ÿ˜‡«Q?ȺZ2úÞÖÞ0“íT~OíåþmxÞÝúm$¤»¯7”"Bé•í½:R~˜{ÚÞÒP®ÛÞßµÛt¸w¤6úÞèןXeÃõfPˆræ“ð#·Vç;=ËI!®¼Þ¥9¤‹Î1fÙqœck ÃlhfPls£Gß>Úÿ%ˆZþ>^Òo%zÇGÝ;6Rã«vyñwÑø¹ßY¶›ÊWƒËž>c‡ƒW úåÍ<[Ͱ3…òË3ìøAŽ•‘cþŠ ?GŠãq!.ãÑ+k¯¢8Á1ÃJÕã³ðصΩ¡ÃŽsã¯|CõÍ”Ud]œ3¾aŒ<…–ú^B4KÎ5šµÅ³ðˆ~öð8ÀÏ>ŒR0y´ØÉ!C‘+š VÜ©³‚§õúqw¶Êé)MDêõ¥à“å….èhw•è{äeFœ¸ð7fß3÷;ÎÚoºFD–QŽê%rM<ÆôШ‰'pXÐ^üíRO̳dÌ 0v ÔÇÌÓú ‰‚xû6åi>Ò¤—–Ó,ÙÅ?— €—XŽàwb‘ûÄH¸ÇF³ŸIÒÉ]%úzì”r5…ÒÙÊ,}†ø4—õñwXŠ……œk „CÚKLkн „d%vÁêE½”ÃXojô;O h.³„ТSlYG¹JÊv¡—°Æ-ƒ]˜(FÏãTQÁ™½Ø*ø´Ñ ¯±•äN£0ƒÊCˆ‰9EgÃ,¶3üè¶>ßk @½ˆŒ‰P0Éæó!ÁÁ'.öƒ$›ïÂÉ­~æazI„V“žqË<5šo%‘»¸*wm“)vN%V˜¡ð|irH3,‚òrÂ0.&Ò§ †Â†â^R½"Öü‹lÌžõ¦yæGŽlNƳ’TH<&¸ðäv¥C¤{y½büÕøZ:’õ,æ¼ËÖ»1¤¿%å,1‚bʳÑ?êP$ªó#‰{HcQÚúÅY :½ÕžÒˆê0©s!iÌ5{µeÎüž2]j1÷ÂE E¤¸"r~LHÓê-ló–C@¡øš`ðKùÕ –ƒô "¯IXès¿œ²ÈäpuM$+#Þ±i9”Hiæn±ÎÀà'šÚ¤ö¨ÉÌæf*£`2K ’ Ãpà ˆ0* ´b»dÎv*6°XQ~1ÙP!l‹Tj%: ïf"•$ÐG&½Àª‡ÙÓÁô»­Bˆ±þzIj ùÿÑíS„;oÍx"(ØB·ªß'å'¸Í\~QÙã&%P6í&© ‡ï¤± c.YÌi^³Àµf¹ [û—ïS–CróC Ð/:c´•±s=Çè(î:Û€AšÕ^×$ÒÊ­yÖ@Ûp±rZ½Æ”GÅj@²šÏè–‹ŒiQqÀÐA7»i{ÂáÎC×1½ÅóÒ˜feÿ•\±ŠÂ,)þ)l ®A!V*m°¢}Kjˆ6')Í2•í|Gj0Ú·qKÞ›'Á2ÌÅèg«9ÌÈ©’M}˜ŽUkTŒ N?Y1®!éÖº{€x†€Q²£ÁØC†"S¨ýHì8!©uì)BÊw=Í*öls¨OOižˆT¤.uY»N²ì1 sB[ó–Œê½*¢¹/0 }U[Š‹„h…S1:f{´°EÐF™˜ rhÍö‡K¨Ú—6ÆpA³>‹æ:N¬þ@>åE²Ñ H»É&<!¬XcDëØªÅ¿Gʤ ô®ËÅõâ7´ ªÃâ¨MÔpà¿Ç;jÌŠ<>‚h¨ Ó´úD³Æ V¸AÎÉÙ;ð Vq*éÚÈtÛ®‹@" êmÝ_-JË~÷;q"Gyµv)Z-#5ó L©ª›¼V©öþÆ·íìƒãÎ5$À<{«Ôp—Õ~!³Ê³:W²õ_-wÑ °†‡ò ø[Å™ÏHŽnÐ;ev´K*˜ U} € Ò‘^7xá0£?Ã+÷jVèžS Û¿B–‹©Ï" Ùš|aÅt£îï04ˆ,hüN.Ùá´|QÔÓPA½L€˜„GˆA\úW]Ù,¸£Ë0ÞõÜÖ¬—=s˜£¦h½ ª«COøÃ¥Ç·³×Rƒì?ÖÀm%ÖÍŸX0Näî¢ PìÄFÆÅr°LxÂLgJÇ¥øøóœÜMÁHIîÍÁÇ„€žØ¸"3?€ Ó¿ò³m7n°1ß¶+ë´·QmÖãÀ7”FZ<*OáÌ‚J¬?¢­‚7 #.SÀß~;»"¨óv«!·H­ÀxZÕ¢N~…ñ^#IÐiíÆm¾U z±ß-°VÜaÖxÓÉíÀ·ä  ½ÿ1% Mß×NÑeT½[>ÌAá˜~;†èÖ"6ûÝËHþuÆŽ½›QP4ñ­Xf†!møºž7¬µ!qdŸà{†©@|Éía*ø™jÆ-z¶Kœ‰R%qFÌ.ÔQ#•M×R½!ß×Eº„Þ ŽbÒЖY0·Í Þ¼€šîN¹ÃÆ8_h¿‘N{ÇÏñHqemq~bZOšv£Úo:ú…"Öæ[ËZM-LZ=»ŽÕ|p ç Ó¤,p~™_•JöÈqz[ù=²¼†Ný|U³C[lȲ،]” ¶°ZµI{CÑþHhÅÎ+†rqYl7”G~iÙ±¼ 5L€$Íw.oçÎA¡)]ócWŒEdÇÍ^Õ5ž¨C3òÇÚŒƒí¼ÄKa·[hûþEŽ»°‹¯Ñ†¬/ö¸*´ß~ŒWõ ÕKå†GÉåWrDêo n:¢¼Ìx–{VîHήƒ†Ê¬Áøœ]]~¹±ïÀVWWà?áÍ·ÙæúÌÌ÷¨JZH+ÅÌ@qöyžäèóÂ$ãm†6bU;ˆ=*"A =·ÝÖ GѾ÷LD–iLÄh; '¾Ì¡¶æ‡u¨<é\~Lƒ“»†…ð÷ß×5 df&9=‰I¡CØšðw|ØÞ÷°=?(µôžá4ÈçlÝ.{%¼Cf¢l‡ò/oì©;Ñ®Ögm2EkÝò¹¢¦–vHíR}] b£¬LÓü¨¸§'¬™3•Ç”‘ªû‡¢@1ûÝÎ]:‡ê¿(ó>gœzñ“ƒ¡«tRué÷£$~Ôwe¯¡ä}d  {ÛžQá|‘ž ™ÔZ-ý=dzj˜Õ6N zÚ¬qCnóÕù)B]…±šÝ`”£˜5 C½¯7Ô0Gã«N±OÓu1µÎå˜XõK>Ƚ¬{C•¡ígŠÒ>ÚŠ{L =/TÝ_õœœÈ¤z2•_¬Þ ýòìiõüŒëÿ×;»õÓ48àj™pÕy€;ÿàOȆڣáÕ'(žŠÖG7+†Ú þ(ù¥³]â 5tø8’ÉsÈP”Ò‘’݇É#T©EzÇí¯wNNgÒ;ˆÐq¤Â9Ïús©(kQnO“'„ãf½9R?c½Ébsj¥ &Fýchžd$Ôºæ‘j‹Å#¡»W õ"üß!\7Oœ7Q‚õ¥o›iu²Ó*èÊÁMo½ÈYL‰ï[\§¾륔mëXQÅç¶®oXQ•uépÙ ZI¹¦ö³&?‘Õë ™úÙ.ø†:ƒÏŸu(Jý0·µ¤è õã÷_êõ‚ŒöÑ>''3iŸJçØîIõ>ŸËî éërO»'TŽ˜ÍvOH_W½ÝÊmÌØîIµ(ñ„.ª‰×mP"uˆ™!¥Ç¯Šä2 üºš0d$¿¦P¼£¾nЉÍ[RvUù¼¦F_ˆÜ^%ç"§¶$% Jp.¥_3 IT¬ô]9R”¶£{ËËÚÄú{“u+eV‰¯’þ šâÒöÅÉ.k-È8¶È|)ÔN™¿]ÜŒ5wêXýAŠù~œûhéÁ=>š—BŸí-ôOOgú˜Ð±Éy;µ€éÞMŽpÒŒúÉQ¡æXêç„&ºž‹Ž-Þòâ/õД#«•œµºI­ä¶B5ÿuÍîr›½¨3%5pYzPËS©"„¡ŒŽc Öà Né¡{ÃÐYÄúҼ ·$(Õÿ¿ÁSg ƒŒLKöÉñyŸƒ¿T-]JáþþI2Âæh%U EÉss/U\×*%$Ïùþòüät&yŽËóxØçñB)óûˆsƽ­¼Ýƒ”ŽëÄyP$}ÊuÎô¬ØÙ^{ËB7s[Ùú±sw¿wùÒ‹½Úü96‰vLÊ¥´‹´°´í0¥ñàÛBÚ‡|éeþàŸ =ÀÕ¶¶¡¼Y¾I÷;øî÷þ»Õ·†õäѺó}y÷»FnuR„Å„û‘:¡ƒ&/S/ª¦r¸ý>rL£ nª2ØâKGf(“ŽÌ(–^èËÕhžË}m2Øò®ÛFt~Oà\ôä˜Éì,qÄFný´§5q€Üª y´Úàƒ†¢´Ôö´‡DFí ÿ—ÖÄúq–ö99Iû BÇ>$è§Â>›5Á,°ÛÓ‡?Äö&¥ág¶÷!÷ª×>±wˆÜ¤}üÍTºòñs2 × zˆöÖwÒ´ã|QêôN÷žÇÕ?Ü«³RëÖî—¢~€%VÔOú¾Õ>Áµwè@¯H ØÃi¯ªp©×Ç]* v~§¬žNM ºÝáMNX+Í)Ún7ƒ’þÎÝ #HÂB,ÂlHGK2Ä¿x‘nÑ»” vTÕGÿ mÀPìh•lË¢ñàvá?Ô›œ«Ìà ¡È~n~¤S%ÌdIÚGJxý\¶ŸÛé)Mj‘ú¥†r‚œqûö ?0”C«áÊ)­Á8bÑ]a~ºØ †³#ñŽì³cÞ@4¦÷´åFk{xÚb4¤SM1–3ãžnmw íŠñÔG!ÿ^‡*a‘°v%+,Ç]š¼ÐƈaÿäZ£~¹†§ì2çù‡Qž[¸lhÜE (Ü¿Ø_MJo®]ÝŠqV»Í½~‘\nöTÝÒ˜dЪmÎѨ£P/T—ºúZ( V¸O]²¦9Ôh€ yÚfƒÿ|‘ÜÐÖ?jB¶G{j3óšbP´åzà¶Pá¥ÃÝKçc¢¥MºÉù(ÇwÅÇe[2¥âá”z µ0^‰\”Moé§1=gn«‹áÅ-$ÂŒv,‚à××WZw#,ZåUt‰ÊÜ»鸻 ¼˜aÖZœŽ›ŽóR $Ùc¡‰t ÎqŠšThµkª†š ~ ïq~ÐTr”¼FEºj“ñÐo±>Míü\{úmžð·˜1kŸiÐg(ýœÆùA6 y”Þ«=²Ö£Xƒ6¬¹e©.‰rtÞ5:XdE¶_"UÛÙîì7‚ÎÌjs$GØACž~~Ž0= —ްõ“2p…ïééŒ:Fà€‡¼Ñüwl«8dÂÄÈi 'Ê›Ú –›c§¡¯Ó̰äj}#©çò®S6J6ÑJ™L2<~-ÉTRø{#⣶|)”“ó ¹‘Ö–m Åˆ®M¾8CñÄK p¸.›q±û2a(NGò4¢`pFÓéäL‡p~/™×»ÝãÅééL’:–ÌT·­GdZ¦€³´•pMR|™–—3=’æm£”ÒoÅØNGæ|ºÏ:Å÷1&ÂCÛX:ꚸ¡E’»ªß:a•cN!ä  Ub;§êa©†5Z çõ´ï—r\=€+•}ÛËJPW¬nNVO!ivz,îÑ{$¸Œ–De ´€z9ÂJ+J¢ƒ¿¶ˆú¡´¸*¿IVLÕÈ»A4Mðvl߯ï"Úô¼&Iר·éðÆŸæÙåÆ/s„é@ºhƒnXX¿‡Àà Åpðæ'QцÖâ¬1.SgÑΑÑ6¹Ã²sIäÊÂ=Ú¡QI‰M´Ø<}T»H;`è lÐS:Kÿ†_V2 ‘)Ù09½Ã­F.B”ý]z EÓfpÔÁ ’ûȺ~½Õ±¹å¦ÉЬ$<Òus¢â5hÂ!ˆ›OÀ=êP‘N߇¥(YéƒðÈþmnNOgÂ#ˆÐ–"}Ìa© Ùíít:ÈP&‡Ú6d N„Ëg ´.|èúص/Ä*t§Â‘ø;¹fû„…³s°Ïé5¥ˆîJóe踗Dfw$œÍHHâ"9½ŽHQèOâ ÏUk§-nLyñó‰MŠ^q¤ õ+NbF:n  w%;¡ÊøÒ„&´¸’w!–-þá]‡Æ ©ÌÖ¨¼0Ñì›®,úÏ—u¬  ÄÊYŽ‘„Ïx–ã}œ.|俪œ.½5ykÊ<$a>¸¨ï%]HŒÑEÒ)~|ÏK:Pi :¢™ó}½w¹ ~ª'2D6Ý?ŸåÍ<5ÐWåHþšC†"óY„¸NŸÏÂÔ.-Òz7¦6Ÿåô”&Œ„Hc¤pÊVs¨ òLÆëÖùò°ÜX ÛÔúßQ’ý)‚sõ²ÄÒø–¼©¿>'»?LÅb52‘éôT §!ÄÔ‹‚ ¤cÙþ~§Û»Í¾;tj¼R&Á:nú3ºySScn¾«~”癡í°8 ·7ËY‚f€Œv:Öb¡±*Xd4”u>ËÝrÓ)<ƒQ_‚Kab ZÚœBÙ†¥rtH-Ê»Cž;jvÌɧïwåíÒQ¤wÔvE¤,Ü?¸¨ÝîÆüåb‡ôCäE}Òïœ3äq¥ÐgÕ:¨R¥þÓr¯‡vi)Î~2k1-°¿áhF/ǯ«[“H.s|€YÑfÙÔÆ»ŠÂ§}OdìUê¡å Ðp!ö¹î‡´ FÖ»•Ã¸Žæªc¹§ÿk¤¼*õò¡6g#ê×à\ߨ®¾P9ZQZª£âÄäõNÀÕ‹¸ëTÆÉ7$VÎoËÚ°Ž…èPž¿Uµ¥ -ÊKŽPÚ«–{ ]ó¶à.*,fÿ,ÿرÃ^|f_®Ã2CåÚ?øÚ5ÓžKsvÍ×6Ƕ6ôÃö`’/tBêBßæ—·È/Àf:»«sv¤Ž^]gáôˆ…ÁÊcá“Õ\ìã4í+:^áá@x†-ŽÕÇqûHÛ°‘7øàh*=1æ\ÂF¬Lï\÷X9 LäŸÏþ®æfMendstream endobj 1088 0 obj 7237 endobj 1092 0 obj <> stream xœí]K“ÇÞðÞæWôm{64ÅÊw¥o–,¯éXïÊ2>ØC‡zŠÉÜ_¿@>‘YÈîêatq8dvTWgee€@λy»ÿ—þ}öêâÑ×Òλï.æÝÀ/.~¸á–]úçÙ«ÝçOà6cÅÎOÞJ«wOn/âbçää„÷;»èI/»'¯.þ¶ÿâROFjo÷w—WfZïÕþuøèg£ÓÇpõù啘¬5ÂîŸÕï/gx’1Rì¿­Wƒ…/ë i0Wß]ªÉ¯5|º’ÊMJûýo/¯æÉzo•!süòòJMÒk·ìÕ±¾ŽWí,ö_Õ¾ÀÁì¤ìó¤ç÷?Ö‰“×IS\}›0-;[÷?Oþpñå“‹?]ü°ÓRÚI‡å¼ÒÓ²óÚNvÙY+®(ìÑç/=þãîýÛÏ/ýu'.ýÿï󯾀ÿv÷/_>Þ{(øyGÈÆÑ“ ãHï„qÂ$yaóæk¬\”¥?_ŠÉ+1ëýãKx'ø¡Qy#-è:Ò )Í4ÿS–ËW蔩˜({O%ým|©Y%A× rû7è„‹kE€ï«ŒÂ7'8u!†âdæð²çJ;òPœdj¶û%ÓÂcZ&!ã.ë AóÑ](âøàóLâH&ú¤Â×7 ðJ-A M7¼ZÅ‘nÇ·U« >cáp–û»æARŠivbÿª‹›çÅf´Wx™àúK¸Ù ,b]!þe½—?™â{kX##鸷8˜›Äâ“v…«ß”×É öâY6NÝ a°¿®É ȯÈVêÛÅ¿M\ÅEÊ`Æì£Y"¾¤‹fÌ ŸÍ˜2&™±0Ö×åû¯ ¢³ó¤õ²u‰+µ™œùyròB–ø»:Ðü°,Ÿ…UÝùnêÖ__* ÏÖô|Uí'å4]aò³¼±2?ÖªeÿCýþCühg“_o@);ï@-òŠÃ2-rIF˜àêäµ1î(®ž®ÑC0TÆ"˜ýRCq¸ª@ïNóî…«ð €=®Ší¸úàóL¸J&úO\ý'®Žpõ«„« …2á*þ/¸Xjè¤ïò±ÌúÍjÙÜ}!ò: `®Å2 !K‹\¬uƒ¿Y÷"¾ ¼ªfß@6hú±ÎàÍjñi'ëé*=DC©ÎæûÞg¨üzRW`•Òÿ«€¨|…«ò ®â, ®>ø4®ÖyaUÁ=‹t¿¬z5)¥¶ÁªRh~O†U%ä$…î`UÁè1ª†u1‚¼7Ñnšß£³æfÓêõg ^È/ú‹@x#è#zÏödПçLw ˜¦`Z¸.àk×™¯ba¼óëJ¿î&Á›„qZ“ïÉï_ᬽÄØ?¥3!o…Ë¥æ€ã÷ÕÑn¦ï'ôžÉK¿ÎæAS“¬ÚÛˆùà VÌ'C{Óº<«•ÎŽ4NÅx½ƒ ‚œÄ@’U)·6öá-^5“Zô@—µL†<©O^¨3<®Õò¸ZÕ‘l,ðõk>×Òo&êËËÆåƒ¡|£oÒ/Ï[!;™E¬¿Gu¼¯Ô¢µ¸·Ô 'áfÙÒêa¦n¬b‘“’š×?ê²dù?ÀßÊÉËi––f:òLl3“€wAqÖªÆ)ÃOŸERHÞe¢Gð‰`Y…XÚ‘·"ïò"É„`¼Ö²«aÿ5™g –ô.y' žÞpHÂ#ȸY:±7½:°`ýs©Æ•=¬DÃn:Á G&ë ­´l´‘€Eÿz•ŠÄQ_P–jžðGOWN¾u§,PÚ,׈ˆµÔ0øòî¼­2çÖ¾ñz_Å{ëXæ‹X#£Z-¶£¡z² ×Ÿá“àó,Z; ŽA`ÕF(‘l¡9<"ÌwÝöõÎ÷Mb¹¥o (Æ2`0‹];Æ‹±`rCWŒYr5ODùÎ’têÑž,ºc,ÓizÉ Ö)î7”›oŪ”ƈb@a?B EG6‡÷pd‡q2¿ç¡î1ÔȽvš/ÉØ™Á5ºÖ_'dÇ=ù¸<¿ÈΑÐLè§]Ÿô2¯ùžËQS–ÇlªVÞ¿Ô“‚Ù=ùÏ‹'ÿþ·ý‘iUoä'Ô5•"ÁÖgñÂÊ‘nÖ‰h'PJ vkIP¬X#¢Øl‹ê~X=uiÈ©6’H#½_¹€ø$TL‰…4–bñÇ Q+/ˆºƒxõ)‹<#?f‡ÎM5n#øtgpË“ I«0²ÕÎÁ×QØn.AÒ•C ?èß3]z›?¼)ß=Ë—dúÀJNl5´¤Ïcã¾ç½Ó’qÆ ÌäÚȰê×e ­–€ˆNê6ó¤šÕª ¿JË…×þ·|ú¶|{[®]ú-Î¥9Qß¶>ë®|[·éuùô¡|ûªy–<õ1ïÊ·ï»ÁñÓÓòmýÅM÷êío¯ét†”«Õ”_J¹ÎˆB†ÆS8KÞi#¨ø«šÏ9IÞ›j ¤ )*û–±>ßʧžž?®ÆÂ-HûÐ5yZÖõ#³Ö˜%¬æjè„_?‘tƒ èäßgPyÞI›s廃R"%Ö$4c^³\dà(R¢Mã–¦ô±Ì²›¸sƒõ•VêŸm}­ükfþ]žfÕ×W-´[_ÕŽIлò -{­½&ž÷•:t‘ Ù´Šè'c·r×ýI6ú–ƒÁ_w‡ßöæ”ÇøÓçô¾¯ pœ®ŒÄXIﮤ›lŒlâ xpýàÚ@Ê—% ¹:Wçx{½@TÅgÁzÆíý¶Ì¸7¹Ü«Ãµƒï-\›%¼Ÿ-uy¿»„@É;c;O1¤ûì‰ÅÊùû¯Š3þÜi,XC}ÊkJ%tQuòD•†ÞR³E<Ý5…™X‰Ã£º÷>fAÑÖ­s‘#ƒ'™Éi³&æ§’sx°3b¦Áð:?¦Zþ¢#á§k6DþÇŸýB=â;\@3ÉYòDzAéÍþ_‹Ù¿Ã 9RBíª¢ÛÓÎmHkE,|àu+/ð”_?fNeût‹}ùõX7ø,Ié+¾„gÛò¶ rð,àMÚ¶Î׉tu.†ç‚‡{TKÀ)µÀ¸áÂcª[‹`îØQoÊÕÈåÅiQç]ÜÛK7-óì Õ§—œ›F25|hÈ–H6eߘ”S¹.¶lSX, &¦o“p3¦÷Ï$=ð†ƒ­ª½Ê¥ËÆ •2ý„lyB,§†¦zÈS‰åÿ¶qÖ¹RÁÐ)oJ&±WSçÊÿžÌð8‰u†+)ïX`“\°èwË«-­²u ÉìCb>d¬?NÌW§SXOûÉS„¡Ì b3@Yæ‚'_¦Dñƒç®%|Dù3»\ÿõ{‘¼V}Ê¡ÂYÞò>w·®0÷ÏXõ^ƒdDz¿O¥ÆÞíÙLW#} R£RX.däÐÓ ¶›ó2©ÛñU]R­Mä±J]&ÝéAà 6Tuž¥‡ ®µàÙ‹%ªVSxX±×1«u…—‹¢ó‹ö¶Ÿšcšüd Øéœ@Pœ¤>Ä›¤ä ΚÉH?cuÀàÇ´aZóñINÌß!f*º'j×|Oدøûßr¢]aÃ2ôqÿ4•nqK£í«ÔYH¨åÜ–3=;’*Q·x¹Ÿ $YÕ¬Cytò¤m3«Ø‘ !lx^y~·jf\-õºT´²½Áμѡê—au ëêuÎ×[Ó³Ò"Œ¿õÒ°aiKƒËç¾i/]ž’bX“új¾nñ›ô@«xÎçʼnBÄ57ºÉfwBq™Ö[_CÎ"4C§SvH6u˜1LJ £Œ;À3Ö¸ê~™¬Vð·µ!™Ë'›ñƒòàu«L6(zœ¥!lWºyJ˜Ö?ÒlA}ÿ¾ù,œÍYn( oæfÊ…ð θĄæàC@¬î´ã=öýß/ëÓŽ–РmpÝRoë‹mš÷Y§VSeØè¶‚’ä±îi•Wn»ð1Ú<ð‘ÚäTŒ &Vž†‡`âYð¸å.²w++ÛV€ûiæª}Áq]06°Óú两«vÆ/åKïš#¿[7ß}ÌÚ½hc”õlÇþ5òǪxÒÄ›’Øò‘«2ÑF2ÍÒoÜI0@¾Ïqk„KS\ÏÖóšÇ—éB†ŽH~ÿàÁ]µz"†•­öÇ|xAZ S´O‰ ¤ŸkôO)D4PNMÚwï{…d<Æîq<ÀgÙÉ#ˆç«VDêEÎscˆy•BOn!TM Ú¹zá¹±ÑÍYGŹ/©" ?´˜ #ÒÁn˜q¢\ºer÷ˆÚ#&˜v†»«;ÇDÚ¥¡#TA(¬8§”É6>MعUÃ,.¼–½ ¦½‡°V´íàP¾† y, ÿçyÒbSøÞ òFãt:4ß@ îf묷•(nŸ_–ÖðÃÜÌdTÔTüþÉ}y‰ÏjüÓ¢@f\~"1äPènÈ# œ '%>Vç~¬6®‰B}¶9‰­q@€eéP&[Ц΃!·ß§6ÇB6ö,T@P• •ò÷Ï-k$G%ú#Æñ¸£ÅÌU¥wb­ g¥ûa‹ý_1A=°:ðVCMüVm‰Z·½W±n„ŽmØÖƒ¿dø`핤’°8Ò0“•0áªÌyEL®3YYâF³nŠ)c¨†¼U\Z„q7ÃÑ”>™ –7Ü>¦—6­·’ ¿¾?ŽM™£=©-;ýEá?½ éJÎÊ€.lÎX9pF1SGC¡C°4ÈÁ=çå™5롊Œøbç£ÌëÍû!o=hðÛxRœEÏSÅQ-7èš;«µÀgI%d'qM?Á£¦*ÉöïtYƒàÅñÉI¼Vވ挪Z ÷,…‹ªiû=3—†mü $n9Y¤o`7ÊZ~뺖¬Ïë2Ü¥Ä?ü²]&ì`BLéÊO +R{Ü c™÷ÙíxˆˆHRVuº.4ÝêLÂ(•»_Åk¾«µCTøVbLée+ôü€Uå¹2në\DCës]C$”˜‡5T"ÆsvÑ뺆®ÊŽ÷R]ƒÓ|./Œäÿ`³Kx½lJ“%WdÃ1`'ì"%s’“£Y²ˆ¦Å1»$ºþÒ‘œÿª§›]>Ée×MüJ4Q2¶Ï;F`@£7±cùø1{oü± Ãþ¾Ì" ‘7Ü0ËAå?yƒ­,޼8[¢Q©Y/€'îÉ l Ëuêx®aY-\é´Oò–Šƒ5á ³½U÷Åå+õ5!é° ½k†Ð¾gäÏtØßÔçiVÏUl³éÜ—£ó/ì'0rјA2(°Ô\æèÁiÿ ÎÄšðô¬«ÉùNX2 £"áy£*ÏšdP¾…u•”&\ÕwÚ®x$£… õfA–3ÅiàdØÃv&“;™­™nÚuˆwð 4zEÿçMöG¥6}p‘N$`Ëè^¤MlsôWÝñ< KZÿ8A‹µK¼°Þ¥hɃ¼†÷ž—iÓa~<©šÔñ^ø¬ÀiD£î Ÿ·âÆ<‹?,Ð5‰LÎÇo•à4ºÂùT)s@ÂKùQ>GÝOL" ÚÂh$hë"Špt”¢5 D*,Ê;êš =Ç-ô¾uòo*¬µti!)üRr¡ñ¡io}‹¡ÜØŽgVêàs[b‡?+`]¼>:ëµn}ìß8°ê–ËMê‰jííÑ:ÄôÞg<Æq °ÝÑ)£Ó>¤£kÌÚ”w4d*<ÁSàˈÆashûo ä§Kbe£Ë‰Pµ‰Ö«Žp¬WI¸JŒšxÏká°²9Ô7:=¨ò{Q'É«jRC›ý´XFDÎëx}YŽaàO?¨#¤stL5úwUÉ[µ5W‹$U2Ý RxÆ `'eþ+3VBóT]ûÉÚŒt…ÃÖ$}àäÚp Ȳv1(D>h[u(ÞRÍxë ÙÑgÁFâ›NR"J*£e›Žš!Vc»p©ä6>*bRÔ ÙJ•¤©>ZFKׄï$8zÒâk°Xó@ÑL\Õcµ–Ùì7%£˜ècÿr9kµzHO%AHªŽÛÜvña{ï»õêÉÇ×XcµJ6klû*˜ ;Rýg’íë#™t¢YLâœ~Ôû¡þÛt؆lÒ\ßÞoúš:‡#jlȬåþoÛ6œ°lBäŽ 3×|oX[cɼʪ_‡É—¢-²}cÌìZš{å&‰N¬Åu­òa]œÍ¤ 8V¤R÷ û’|Ç]Ë©ƒˆ…VEªä=Ý“n9?è]ÕîÊ!–”ñÆ;wÞ£…¯ð`9JS¿ü†½ÈA)êo Ä.ízÇ ÖÓð; ‚¬R‚5Ÿ7´ Àôå¢q²÷?f9–,˜>‰ŸSûCþž¡Ö(´ösní,yñ0u=ȾåDΙ¡¡k>«vx*U‡Y¿‡ü8°iäDÿªNe¸ä|DÞ¸'ÛÝbm*$<8ñY2 ¢V_Iå‰Ï-xXÐõŠù³`ÚXž?bæ\É¥‚§ø<ŸO_sƒl;Þ 5ð} Ü!­n6R'Õ–«Ü=¡õøœZn¸2}ä‘r3t ³Ï xƒ3ÄØè´GHo¤)Šá›JY§¾Ëìcé`úÈ¥¡J±½îâ 禀÷6¹­‹Òª@jŠ;-[—3©-9£ãxj¯eAʲcšõ^×e?Š>¡{ÛÏîÜ\Öý@ƒþÉ¡Q]ׇÞ÷œÅ·Á?È™ÀÔ±m=Í*n©+hBü¸³ÅÒ³g>Ö ìÐaÖÃH€/ñ«,"{o=ÓÙ¸t4õ Šåýá—œ’w'*ÛåÈSUÖ¿-‚ç· Ž³å™ÇÖæ«å(QpBåÁÈÈù>! ñ7¥5ÒLçlÐÁÔ¤ÆÔž¥U[8ü˜°´£l9ß;â)8>Î'774ÊY‚¶tMÂo(Rùêg—ôÌૼ_Œ~]+gØè½©¹ñ¶¾jpeb6%úöÞÕGŒ t>µ¨ŠÐòçš vH¥±ÚÓœs½-_Û÷oá´fc+ôDú)WÄÜûÏÅ¿xÀ³¹Ž¦óÙ8 $}Ù%±µg0ÿA§IÍr¬OÙ®y°åñÓöö”†ûÜÒ œÚÖg÷÷ŠÃÑ.~“å—l#z"—ážÝëÀv­Žk=¥¯kï–x˜uëyíbx·Cþ{ÊÉm Ãïsg†¶> stream xœí]ëo·±/úQÅé§Ñzù\2MäáÛºè#IUôiQÈ:’ìYòCNm |gøš!—{α,5Å­$ÞðpÉ!9ó›çÒ/Vã V#þ“þ<}vðà[iÇÕÅ«ƒqõø÷âàÅ]VéÓg«/ŽC7±òƒ·ÒêÕñùAš,´r5‰qá—gß­_ªÁ¯õúùᑜó^­ÏÄ`­‚ÇÓøh„]?=á}c¤XŸéˆQë·‡GRéaÒÞ’rÐÒˆõ‡Â r„ŸOèõKzý5MuBSÝ„Zújª+ê{‘æ²ëkj¼*ý¹.áw#ï£úeyJ/YåpxÔMëgø³—ÆV[)ñB˜Dj?n “r=ÀLƒ×ÆL?þœ‚©OAšA+ïVÇ¿?8þåwë?ÇÑF£q3áW…6Å ­öMéšçЫiðÓ(Î1ΤÃB ®€ôA¦³Þ ÒŒÆà±Â£v[iýµ>¥Ösj=Ù5Â'ôø)uxM­¯»Sl¨õ3jýŽZ?†-°~ac>¥×Ôá9µžQëËØ*U!o¨Ã5µ²¾ŸÑã§ôøÃlÅÍk¯èñiwŠ«î§ÇfÅÀ·*2vg„·Ô÷ÔzÞ¥ì„ú^t'þUyD¾éõ†XuŸãÓ îƒë_Ù΂8êõ“¡ÖËÙ&aëUEk öà#êpDdC«õ Ï³a+;74;ÖwÆ¡ïMšØ‹<1v¨'€ÿíçËî¸ó­ÆÖÇ-ß´‚p–ÌïžØ.LŒ¬£ä8è èxˆóŽ0¦Ö·ÕÁÍ)Ã…ú£,í\Á+je}Ò½¤V˜T«4r'ïo1{­à1µ¾­hå¤ÌÏ€‘ý[êûZÿ—Z¿¢ÖGÔú›nëqiÇ¡ŒŸ¦|ŒIžw÷ŠÉæIw1×UßÎq0äb*‘‰Óñ8Ÿ÷ý¬ê›Á¦ô5\Lݦ~ß_T}—õ‡î13æcŒÊTcÔ«î1-‡¾–Z µjU½Ö®ÕZ»f2°ÑnsÈëÉ1KŠÛW`ùƒõÞ*à bfO2ƒ°ØÎ{ÚbÆhüã'°ÅtWâÙžÊnßóî®=Áð(º‡9QëØU+#uÔº¡GÕ}MÌHÇÖ‰]ûgÆÔÝÏö[™î;kÛU¸îcmj¡¨}à…ÿV^#_{p•…æŽ[ů*ˆþÀ,˜%0Ë!ò <“QÙß°F©£Ðr•8JH>#v“Ynâ¯=§Ç8/ÐRæÕ"ïGh ËF-eÁŽ,¬¤r°¤q‹:ƒÓ<< çyY%< Y–›¸¾ÞSz¡ï¦Á{é¼uFPò‚È^Dž@–ñ¨øøÒ<ºìJp<ÛÑNȧJB³vœ{Ÿ´²“¸S)1ŒÞ­ÿ¶&Fþ¨°Lv’eÍÆÂNø,WŸâÈB;«º@> .÷üˆ¦øÛ!±åÇH°ƒ=óLFk¹Ê3¶\5šA9}O‹¥`0Ìž–ôÙ.ž­ó‰ÔëÐ1„ó|™×iEniEQï 1IÏ[‘ž¸k•\ã^J°M…×»²>‚íAÄ{ÄO´ÇãÈ´Ò•¿ @ih7 þOOsÑ̘DÇß>Ö€$å= ˜&nïK?? †¼“ ‘@Ý9c¹õç,ÚuÙ¦4qZ†%À\öti`X‚†ƒ€1`Ç63‘® r<ÌÇ!g«†Á¾Æ. ÙoɬʑŽ6È€± [Ê»@·å&<éôh‰5å]aúEí$Þµ¹ÈÑMIÊTº±e39aÈf ”¤k@M‰®ª×‚‹ 4{í„cY†Õd°Â6l«+Ãw.ªôbñ‹E_5m…NèÒ´BT†ÍY×ȸ¬$W;!ÜÉíE¦&†1Ï»jh)´’ãK(Ô‰ž0úoeöT$õµêi¹Pû–pîûíÐ{‘\5²d/íˆîì†>‹ÁmT‘ø/2Ž<-8r•›6{Á0…®Ç\ »$yßE¦FG§òóLÓe~¸)hwFPxd,<~™Û®kdA¦¦òâ›zÐ]+ö09ywi!¨Ð²t°4sظý¼±dÁÚv“®aPzààçàÚX ~§ÂjÖÞÏ»ÎDj€=ý)âbÚHçœÃ2kº–3+kÞÃßÞ5Á®±"o Ò²‘Åൣ¦"ãq#”­Cî`)5T€6‹@4Vç<¸@•Ù ûÑ ëh’Üøtæ"@õs Ùž4`¿¯²xŠGçÂNø [~ÿ:ÄD,xo_†è/†j;T‘›NP6oŒTã`êuqúØvøœ%Mk*9=UÆ‘ès£m*Î4–˜“‘ô?‡À~2U¹<2…Wi€0ydÇN1é¸{‡f8ìоÀ²rŒfVÃ.Úmû!‡Àb°zD¶ËBèMi# øw‡Ö0GEá;XQ»<¸sÃ/:¯j”à_ú[›A`FÁ©£A·YIŠVq½›´qК™ÂYÍ7Ù®å þ½’šÛ“hèdÀÛ“š8œõmŽË-ˆ›bBlFyгž<Ámœ€lÙQ_ÞÜ|DqÓ ÏÑIE»c’€¨á­o¡(E+Y »N_Íý¢K™¼Æ ÎÜ“…Žûþ ÆË¢2$g­OÊ>¨(Á¶^.„Ö¶¥a÷N‹cüÐÉ=ÓâR׌²/ÒMè C½{ÅST¸馸u×4ÙÐmz0ÅÔâÓ9÷ÖNYŠ·ïJ Ìí ÷œÝ4À·å÷¯ Ú ] ì€ÆiÝ ‚ò:÷I}Ïm‰kjí[ çÝÖ~_&ý5ßp¼q ;˜û« àóGO.<áÚ]êß R^·u†Bª± 1Ï#8T,2ÇœY-NHû9· ò iX‡Ó”,gy0°ø4Ásá$VgbZƒ‘Òkʼ—6ÛŠE<ö$Ú²È0,*Y°§•ÞTB_S¡R?b•\vÐL«)3†Ì¢ñ‚Œ#Íí… *—³É’ÇïØ¾lhãF ¦»F„wmMK8{¼.®½ÑS­îãv«Š„E{ 1Ñr „àw™y¯<™žÔ~)[‚'ñd‹ðsŒð¸M€ÿ¯›db²Ölœ6!à»\kS³L¯™û«ëÁÆý(8fÚ9>/ ͬT—,Âfç÷ €xvC¥'ý÷OºRч÷~J¬ž7{ïpúÃ81°@ŽKÚÊ0XŒ]gŒÚ#HÌ$xWl8ï1û=²‘[=´VØgî#Ò‰ŠÚûÇ)–4{¥_ˆuI+ß©n ½µ“®0ô]@W$aÆð$ýñ,ksày…s+}ξµBïZ d¢ï+|¨HXiÀû¾#‡ü~j’½õ³’_KåÅ€†žä©92f—½÷Û×óýc1oXízíæDôãÙü`€öcŽŒ³ú^vè¦Ø”¶n6+\!–lú¼óÎîÚÃû+zÆ n9> AÛºÄ O/µ°³’ríƒý’&lº½OFpË9ZÔvFô.¾X ¿å |eRÖæIˆŠ£SÈ ÅïM“Ó¡ÞaF¼Ø/Œ¨ ¸|Î÷"‚­%z« ˆa½ŠWåéIùõšEë”üº3¡âëéçVFÏöÆKàûJ`C©±²w­Û䨒æ"P'zr‡Ûɹn}]µXI³û²5•B‘tƒd9&ÖX?³®ì÷ ZW¿(nÓ{«©#NôQs3;›dÁ…˜¦’UÁk…zå{°fi̦PV ÛV¬þV–« RóK%¹ŒçJ*æmZÙ6¯#ïx‘³JRlì— Ò 1‰Ë¬8`w(U¤å›Œlƒ©qßX_¡ˆÊ@×E$̸(™,N"ÌŸ•ÁP€c„Y°¯¢ à¡׺QÐ8šæfGc~ç•K¿,Äñæ'½ Ë[!íf?ÛÈá.`¼ÁKßsM3,çó&¢ŽyuišEd{!o˜ê ˜ÆïÕ ¢ë8+8¢eõ¿žÈf¦™– Œp䲟¶…C’³ Чi)¶ß J%pþþ€ªYI7Võa½c?ºxA"Þà Ã8Ýg1l’Ôï˜D‰ÞE<»"ïýJ‹ú†­ÜáûÞ'7ÙÚõU¬ðüÎÙ‰P—-Á“ÝâY$£rArërØÊðª ËØüÏbNc²±ä8¹.ý¬cÅ›/JÉ|áÖºk?ëIíb¥ð›‡»*€Âš‹©ô󦟔Ƕ¡˜°6ÍŽ˚΋õçÒå,bí˯"ß #×Si|L†™–Ʊ4ŽÔxÎf,yyG‘ÛØÜ¥ ×SÛãÜ&Û™Óx!3îSmP=‡Îmçñ,µuÚJíiYÑû°Cv40kÓ§¾ ûîw)•m>–‹.í]§§YՔßTvË\?`ÝHXçŽÌeœò“/¿Š†/ñÉ•_:¿ÿr¶ËOG‘éiÓy÷(/l8®`«Dß41’eøU`ŠóˆŒñ}þõtþ«¦_Ïç#[ú•³´)Óã¾ý˜N¹Ámû¼¼h7^îÇ8"qj d!*oö´S¬ànu[HœïŠ–,„^j-¨áÖý/˜ÏStÅ2´_ôºÂ¦÷ðºöÓ\àè¢ãÍÎ÷½õF«ò|ÌŸRmI!±«Q[¦ˆîIQ[] ÕÕe\¶k¨®.멨ž*ûÿ¤¶„Çÿ@µµÓ¼ÝÏB\Òe'¼N¥¾%Þ~ge(¬(×P†ÿ)ʃ¯ùâ½.[I÷b¼ÿe+ód}“fq˜J£q_1QSßú€Î†·Üß¿g¼Û j¾¢åþòá3Ð}‹Î¬XY(‰`ÔÌ Šçš«lsJôh¼eªNôV_Vþ´Pò2qxĵúT$}õªbÔ;ë½³Ãè@;ÙÖ‚îÐY „M~›…¡s-I) ðH¾ó2SŒÿ°ëVRÊÓL)jÖÄ|R†7b‰Á,×e†búR÷óR²³lã+¦ÞbÝŸíõæðmùýërG—˜Å/ʹ:“AàÍúº ú$()âp±‹uËÓ˜mç |žJl$É2 Bf*ý0iÊz+=Â/”‡²­œÝ6ÓÑ·ôÝ_ÈŽXÞØÇ=6hŽ¶Ú¡¤v÷ùÜ$^·SåX=F¿ö£o8c Þ|=MY?áW$Ëå%˜19۾쑊;¸MÆNÁ¶LÕGRÍ)ØÁ› 7i0&ÞO2 µR‹\¸)Òû)ŠçU„;c™õLˆnû lLm× DFS_e_b”oõ=}¿ÇÅøJ¼‘ðÖ_ðÎï½Èô/ß{_ë›ê¶î5&å>²¥r‰[9…¡)Ð|Úþ…'] «vR;jð~AIð²x‹K€+ÐièŒ÷| €ÁtJEðâÓ´ß HÛM¸õw×h(Û bølZv2· ¼PÃoQ0Yï—R6Côì3ºd†,ŸÍË£$eC…µ¶Þæ\aü†ák˜æ¶ž]æOj€F6Ei÷—÷ q=½g\?Ü5(5×àB}G‡¿óq1è$÷ÄyRw[o1xo§[ÿ‘1Ë5SUv*ùTû|äbõ0а÷ù­Mo5³Ûy’ERÆÚz;Oþœ+žzæK§HÍè;ùTÅéðØ]”jæJ²½,’¸µš{ùlŒØíDt¿Y,jYptü+aNÈyÙã©Ú9‰Vì——d¿ìiú·—”™êb89 üêÅ!´i2QƉ։Ǡƒ’ûæà_e‡·endstream endobj 1098 0 obj 5243 endobj 1102 0 obj <> stream xœÍ]YGr6ì·ùí'ušbåµkØ]É6 {­ÕÒðÃÊX g8Íc†ÇP"°?Ã?ØyFfEuWÏ4iA ¦••gÄgf¿ÝŒƒØŒø_ú{ùúìÑ÷ÒŽ›çïÏÆÍ?ÿçgoÏD¨²I._o~û$T“©çØ<¹>‹ ¨e%7n”ƒÝ{u'7k·ïv°\@j{W«¾ªUŸAUç'ìö¦V¸­¤3Ò©û¦ì'2Rù}°v4a¤ðõMùŠ0ûëˆI(cA†° z¥0œVù‹{¯·ÁÌŸ6Ì ¢Ô}Á°‡¬x|F ⇺š!æÌ–a½õ8qvÝ/Mp¦Æ¸q_ $„1XF„ѨK¡º¤`ç·¿ÛéÁH=Y€—s JÌto,18f·ýa[µviÎÒͼÆïÜ –4Ü5£Pˆ(=ßÂêJKØDM˜à–%B£µj¥«¤‚Ft1@ “Ô1©.¸µ¢¨c×°’^9>h-§¢Ÿòïʻ¹(W"ꪫª*ጻš†ñæžYy7Œº™Õû<ÌgeäïrÑÇ=ïþ’®çïʲ¼Îïæ®´1ðeæ®4gÛÌýr¾£/Ú);¤™~G«ÕÃèñ „V× !ETžð èw-r5H‰«JÕ_G,hÍ=KÚ³†Ó”Aÿvˆ€ãÈS.˜Z©òX{1È[PSÐÒ™Óô}WÚðQ?¢`ÐÉu#ÊÆ_ª<—NŒ‘D¬áÓûZì!‚¤¢ÿ>ùÔýU]•5ò‰¬Ê¹2 g  Ö²›\œß"*åƒ22³ZFKAûAŠ3ŒTÝ+»ZÝí ö*!#ºº¶ˆJ×(ðµUhÉ{á‘\qê0•,&ÏeùÅ„yfDcV]ãg¸EfÑXÈK´BL„ªŸ_JL`m¬,!Qªw؉ï^ï—Jaç€ Çã|÷ÀNÀ ÙLôÁrãÃl–&ê½ BâKLt’  MÍLK Tõf^¤„–¶é£õÎ(P¢œ¡~¼‚²x„ˆÐ¨š¯ä½"$6Ø®L©< "ì0™É¯‘ˆšªY³JD4² Ö>ë×´êÔ¼ý[‘—g@<ÆÂÖ(TiÀ9hVßDýYI‹Ø´F8Hhî>¡›Ù›4·ÂÁFüK3Ã&·«„´êí[b Y$©¡Z©Zð½ÔÓ §e¡‘–îoл¢ÄˆBAøAŽ‘á5\­Š–íØjÛ~•Œk ÄB…e­Åö%#:b/ˆ ”\k“‰cý¨xþ ”Ž–?¤‘ë9;1i ­ …”7 –ã¬çEÎ<Ž'ëÁîîxR ôË«mšV)mûækhÔa§Bþ>ªm­¤þႆu:…Î&%lø)46ô5˜äl@ÁªÕï‰c«¬hë%¸jFƒuÁeÐòlp¹È´¹‡50!t Þ|ÒA£ ÖÎú”–vtd0ÍVCgToyzZÙN1À Hk_üùüd¨×†©`tÓ;ñãœo‘4‹ ¢4žý;·$wÛˆ‡T€$jʀؙP5ùŒl™ÏÛè×@à ¶^5lÞîR®Ë8á8–ŽÎ-jŽ<‘ÓšŠiË‹*²*R]´"»h³+-øh5uì±*ÌU}‘ !A† â‹G& 5œcvcLic| Ý÷èÕè=Ñx×bÁ­¿HW†\…!^iùW¼̸ln¦ªÀdž?ÁŸÖ ¼(&Ã{Î>à¬Ñi´r¬Ð' 8ï±v€OÐWEF~;ù‡~äœY÷fÕƒ:ùÔöwĆ>órDi²-ºEF‚ ë\O! ë¨qö†E‘·µôŽbè›£Õ Œä º‰bÓ,:š #p£–rÛE§“k®óƒðkìÇ]ºÙYtÃÁz|,O,r¥hDP„ \-ûõ“'*A«Ð)0fîT¥p!¬‹nŽ9–¬Ñrj<~,,µ–¢­“ÓiL¤Æ´‘›œŸÒ&•=ÊÀäÇg•,¥º˜É›êr4^8PŽÐÓlœÁ®_Æ7F'? ¢Â³\¶€qÞˆƒfÜ熸I èóÍoÊoË#~a ê®sÀAÙ^P›,”rcÌX<þ$þÆØñ5zÕ%ÓTr"Òû5 ˜ú ‰@š|ϾŸÅeg¹q=Ó`EàXeð…$êÃmtf>üëbn_¦i;EƒØwDãÓ%«L-áz¶l/gz=60·<•h\7Émeu瑈ά…(7¯ØHˆùF7F™XÊÙIhŠ+ àbÁ°ø ‘A×û¼L –ƒ#]º.Ƥ@QE‘¹dÆ„÷c/7ꋈȂÑPCé»O¼¦KPœ××;«7Uû¹H™kÛiS©†À@C@¯zêÇØ¸¢+Gé…Î º'ñ6¯ˆ¿´Š£iøzFàSÔº£¢ÛÌð&{ CÚ[t7ˆße éˆ Ù¹ç;9ù`£F× c)=8µ'ÑIè@L{|z£ ‘ºŽ>%ÔË÷+¾\câá*ÚˆSÉÁÇ›úo;LíÑ«ÂcÎÁ³²‡‰°7¢ÓÅXÛ¸+gX«Â–Ž7!ô>ÏÌ!<¸ )PÐ&?/2I”w˜;f€-²HºÊšz/¦-ÐQ¢f¡ügÎëÑbtÀ%ÆÒS"~¥ßl“mã5ÉkɩЎfQ¦•üS¢r(¥qþ´b´R Ž ¤&0Àe«rVÏ$aˆ™ƒÙû¦ÛèzWÉÎóH} so]ÎP®M=m‚ŽKúÕa5<8dtã> ÒXÃ0éá©´ÏbFoœ ®Ð—uª ò}y_²‚á8¨<Î&þ CäûTée‡hI<¦ÎÈL[“ñ«UIhU`„mžüÛÙ“¿ûÓöUkú´lÞçåÌœüs©Ze ÃE¢)B r¿Ñ6Ì&ÉÀsÌKMXxÔÞEzH¥®¥7µô¶–¾©¥wµôu-ýU}üû7v^K_ÕÒõñ}­ð¡–þc-ýu,•q?.ÅXvà3Œ*”¾¯¥0*á £ÛþÃîÜŽ¨OÐñ‹¦‹n'a¶ø™ñ ‚,ÿK|t¶ìV¸­oj wM ùñ¼>¾˜­8–òUK¿®_ÅuÐ~:Áp^Í–Dª²øX‰€úàÏé`ï>`éëS@\PÜÈ®¬Ü»Z÷¢o!<>ç¶ñ4+÷®–^°-<¯(ó„R>|¿êGs¢¼çÂh°/ßLkd—ËÖRSKM-U\)+„zÇZfAB|[w?7bxãŠMÌòyî|=ßâp¥¬RÕäÿY%Ø5ýu)ÍÛûK¡ QKýLè¥ýÿ¥ D€±hH/ û¼–ÊZJØá—¹ü¼\­ûuÅY+Œ‡&.+Ì´ZÌAO<&„e_?ï‰çÃ>ü„k—Ɖ¾ôÖ„^ Åw–ѽùœgf­'°óÀ÷ñ§u˜Q_wèÁÇúmot®3$ ‰iõš3i!q@.Dly·ùÁs»­½’æ- 1»šãkL·?ì’sÌȒˆÊZÈV÷[~Zõ«6ë$„·Çæ#úõG‘× nìæ$ºŽD=™w6ç9Dó’—_ÔRR—/Íg&Eã阉d,nj‡´’~¹´q‡raþÚn´VãÖkõ¦š•+"k˜‡æµ¤†më­O_=b9‡mÜ Ç%ìXê6“çyq³U¯;?”ç,ãè†öÁe€NÓû:ðôm¡‰µ¤ ÓòŽ~„ù@óRu(4jãÒ°ñІ<–G•™¿/ï¿+±AtixLN—§pßÇÌ"µ|Â5ð:X#•×р“ ÆvG]q‚Ú/D(Vf>—, LÓÐ÷—`ÀA^lÏ­âÕR€,Ü6Ü3ÛðÐ,˜(õ4 ç©ö;ƒï0ÚCß6²—ºL÷`ÙA½)1èËLŸ‘ëYþÞ_®'zÀ9 R§í*}"ÇÐïÑoŠl'©üð´û¢Ý4¸ë”J/ºÐ·„ò }ªq;6“Šþ€ˆBk9‡/G6‚"\%ÐÛ¸×J â$î­Ü¿Ô.ö¬=Æwë`þø‘‰qòMzØuU ööpos*‹×½»Â FIbÇo+™ßÑorQÒI•Þgœ¦ÖäIëËÉ©ä<ûìÊrþòû2äzî®ä==pfZ©0Vú%F$…£ž¯7ù¢ ùCW–ÐPÃ\r'c»,Lù¢g©AùFLG6*EÀ¶Õ Òµ1D—"IȰ¿$$  "U¾öÆÓ4¬·'Ä,c¡]l˜1FòÄ”#š'&뢘ɪW½ã,³6ÊÙ.l«!–#Ö KþøC› 7R¼‘Å{^¬t¹­h°z›#“M¹Xè97>²ï÷»Žh¯^».T§F?,¢Hÿ4Ou¢)V¼à!¥xÊz„-j­ä„¥5µ|5‘s{ÔÆxq ‰}’õœñYo”uG+K†=ù~[-³ÊA„m QµùºH™e:ÆC1~]v*ûÞôV\°lNŸö€‡i&G?[ÌPŒó„‰Ö€´xM OÎ]¦‚×Ä«^+’-c¦ùÚ˃’Eµï‚µ”B)A­@ÐÿXòªmÆß‰Ôf`fCtý ̲»Œ¹½ÆÜ …06¸¯fc%8™zˆ÷`-83¨éÆçÖ¬˜rSµÇâ-éš?Øo“ŠyVPC•GõU²Â©2Û©²Í‘‚¸óë|C¬ÅzljߗÍ÷䤜‰ž‹Û¯•xZ9™ d€ÌPzf5öË•“™Œ]ðƒTX 1GÌló…´˜å“Myïë> á„ëÜCáî©î@#ùÿû_â”ó)e¹?à !LXªžÖΫ¾÷ ¸@º‡Ï;òÞW²–·•SIò`ä3g\Ê—šçC5:O®ã£x˜vÏæ°¥mèö )”Á å/é ªzÝGDúrLOÿç7x9ý>e†/:ÜÒ{{Šp|mÈ3®‰ôuçjû´W’óßeѧÒY2t§¾d`ýˆìU¹d®4ÿ5‡ùš <òí¼lCŸ8áuÓפ\פ義™‰Ä=À›ÉI6ç­È^ñÇEÙóëõiQ5Ëá|{¼Ÿ¶;eƒáÅiåˆlŸO{44r· ÷•ëKÑ2ÖS(Jbæ¸^£®®AÉ¢ñ†—o*£=­¾#\O­u€FÆe’J{ðô3YhÖ§W‡ÜºéÂM_Ö÷ÊW¸-¯ d«à#g\å“U®ç‘p ˜á‘þ’NjQ§4dñÖHºyÔõ:SS{¢ªiL‡7:Ÿl>n£ U°š£É;/Ä©ƒÚt¿‘Õ3'=š¥C:úvê«>÷@U>—êÄCn £êp6«›ñ‡¬y§|ŽX›ýo/×»pv)¨ÇÊF×Bî¶6•â¾zž©Ñ1 ¨drT LÓñ*@eÔÃ|­Ét½ƒéx¡‰¾AO¼®Lû@“@Œc­0*^^¥5ÖO(©=ó Â_«YP¨N…ÐB›÷¿|+³{•?ÿ $ÍU…œã½Ï*„§Ã÷Å‹é¼J[z¿ãÁ Ü„Û;¼VŸýž¢gÖ¸»O©ÆÐÃOC칌W¥|‰‘:»´ÖÌK«îQ2j°ýV¢&ÚU¥/Þì+|oÖçë²@² ãØX»O;h'nƒ¾yþ—{ Jú–Ô9³–P‹X°Hè…€%A×Ù µå!·^ÈÛª}ñ¶jÙzk#œ´ Þéµ&\VôZesfÎàU7ÕÌÒ«3šÎÉÛÓ—üWüå% Õ“,ŽÖÞë›Ý”Õ稳5]¸î&¸}™¯G^–ˆz¹îÍd9¢¸Àe9œdÖ¾KwA:¢+ñ§¸—Rçñ¢1°l»ËµRóóÌ™²é,ôér9Ø8»Ã=øÆå³×áx¸1åö2£<$.¹öRȘä^~ USB̶rÆ.ŒXP±ø#Ý é„Užl{oZ8?‚‹NÅŠ{̵1RŽ— du+öâ™l°Në~è-åšÔˆ/bhç Lw†‰CÚE«'ÿdÌ ó6´?­±zB£‚QOƒ%´Sé©þÖø†ˆ~š¿¿iî~Î|ø) Ê1žá}ÁÒèÑÒ$öÈ$ް? ±ÌîŽLï4Y´›†oh°9EøÞpUsS“%–É1éä)O@ W®«ˆ FX2Žî͹)Tz "þ’^eMæ€pr}é˜lK.rËT9Ÿà\È4Ë'?¾ŸIŒ Rt90!î­ˆ-Æ&m•³"û~Ý)ÉÖUÞ„bs9iÅÊÖ’O ,‚íi?(¤Ÿ†[ é(ÈÃA!ü* ­ #G¡ªPð¾ãùš.V·—‘â97R’ÜÈ_î‚4zƒ`äwN¹Я8›Ï¢ì~-´Ðß±–åïržDPÃä€ÖS••þ ™OU!!É$Y‹Ô­ ’˜_v·Ë…{b'wŒ«‹Çéxï„@t96‰ïuÊÿ!·‚Jwv£,½HmÛ—ó<ñ¥Ôv'4ÚFʆ?Ÿ5³ÝAe°§Hj“tiq…;é¡¿d—¥ùyUÅÙˆ<Ùcöý,©õÀÑÛ”Uš£f»à¹ð¶{­?ƒ?/gZúAË[Ƨó.ê™Hí’q0²{êâ£Àt˜s99+JÏä×l> stream xœí=k·‘ß·ý“ 8Ï4-¾Ù”mq,\$9[ÞC c¥}Hö¾´«•½ˆó=?;UìfW‘Íž™]í®ldaØK×°ÉbU±X¬G÷›™häLà?ýß—G[Ÿ)'fç[bö?ðïÁÖ›-»Ìú?/fŸoC7ëÌ,4Á)ø»½¿%šÖvÝf^ͼøÑÖóù‹…iZm­™_Æ–iåüíÛK­o·ÿ´õd{ë«­73ÝÍ´„_fAùÆ´8 mD‹~þtëáÓ¿ÌÞž]ìm=üÛLn=ü#þçó/ÿž~1û­'Og_]ï`›¶2C¾D›ŸË€"”“|hÙ+eÛ¸6vg±”sVºùñb‰ó† ç»]³õÝpÓ˜JmW!2ât9à9`×ãÞãY!²´Nß•¥ ýTò߈^ È °Ó͈ܪFåÃþ¸XŠÆ…à´¿^xÆZ…Lš¯Ú¯£¸ª±9Éw#^ÞÏ_tö~%¦ÁL¨™k "ŽõûÅRIßXeç_0¬ÿãYe‚›?Y,u£‚ñíü!áÿløýË…l‚ ­‚g–J™Fëv~¶îÂvÖ€Ø ooHÞ.’¼ñßϺ±6„Z*¡›€/é÷\t•Rž=u RÚ4ª†©ú`ÅX±ß!(­± ÀÂ}Ç6/Dë†8Àˆådgˆxh„lÓî‚.¨ëN=ì›b‚þù„Ö9@ÛÐHÒ‹{ˆwÛo hê{:ÌPÿ½£\«Úo(LÊ*X2JÐö.ˆ ë :CÐ/À䎰Zx9pF¶BöûAÿûü„c×MΩãhßD(ãÀ!5‘Z4–˜Ü:&ºwú „¿ß^XvGW/UÖ·Á|Ü=óíNö[ã*üÆ)" –‘„J¸Æ€é¨mƒh9ë t‘sAõTˆ˜ø²U22°¾ ÝsœX6 :pù}]%Ôá°xäí21w)UÇ^61Ûm?,È¡†b`íùïˆBââÕ °|à§ËÞ8nLDPLû6{üláï]ëP8 Í~ÓÕž^{zÐ’íÌy5è¿ÝA…^Q™*© k§ÜFIö@}¡ (Ôƒ€~`ðý¸”)¨Š“ÚFþ! «ØFÛ)ES¸l÷½$ Y×R@º¾—„7Û€™^Œ¬n›‹Êt]`á×?½ØøµVb›€í36Wu]ëÃ4Ϙù"²—©ÑY52 4 HŨ1¨?D”³hqܦQc´D»€cþ6!œÐìíF÷Ê¢m,è“lȇ›SÒj€ß%½ñwFIßöS ˜Ÿ¾H£óÓ( ¤Ê¹ó¤Zµôx@Â) (Ë ®ûAGÎ':]˜6gš…™6{ÃQ»Á¡­êõW\/÷ǦºÛÏÀ‘CÒU3°j–Šc_Õ6$]s’MM­7Ó±J³`°†iYO:¶Ä¡ÈˆÌ¤‚JôYPÌì(, Ñ)QL_µÐPW* ¼°ŒTû8?žBëñ«[€onν…w1I¤:›éŽ/á°7|}o{ò*5^d±2pëñ†kó“¶®Q.ä'8‚Ìd2ý:ÆB_ÓøŸK>Ù‘loÕÖd!{ é <¬HO v¼€¹€«jþ.XH6› ªêæ Z¯@Nk×^å‡Û 1›ð˜\ñ2/}§­ñ¹í˼‚ÿ1ò%¢+=&vÚc ¾¡êÄQ¿&-s92?[_˜Ì©ëOCWbƒGÓ[ÊŠGíH0ö¼K\*+¬Fœ ­ï†ºGÐïú– {=¯ŽðˆšŸR‡—=!è1AßU§8M¡àyLMPDB[9NÐßPó[áS‚žPó”šlñgÝ¡æÛê É3·l>í»rÔøÐ!A/JdØzc_µíÔO}9ûÔwŸ çÕqßfˆ§qŸwªÛi¸7º;Íë' ëÆªìuIÎkâÔ@;˜­µ´;’!çÔ'´»xöx/a»E%Ñ¿ñÓ6áü³ÅÒ ´Sô\RógjªžVÎÔÎ 5¿™WYw\‰K¢ÅUj2.¾êû 9!á¬ïë)î¿%è.5_VyÇú~³ÚÈ4®á˜žmÿykû¿Ÿ§©¸§ëH¾SU@'Y_8ÐáLù¸ª€>î:¸òýLkü˜ðþŒšyßÄ5Ö÷qÖ7úºÞ÷ÓrŠ„NâÔÚ)®òØ]³f}û)gȨwDűªBèEÆ>m[ÑhÎAÍ%5 Í©¨h,SBcÓQÓSßѱi3ù+„n¬‹“Œ‰" ]À«[&^Kêàè1KPKPa•„.?E¢¤Á5ÈÕV0=[â“ÚÐþìÎEF7-ŽØUݵr›8¿A€y½¡bá>aÕ‡0CL~|¡,ÀþL$.¸Ddâc¤· D år·½ÅCó)„‘’.mšOFãnù ª|ø uø,ëT0Ûå¬ÙVY ‡%Ae•“Œt¿<î¬ ¼Âžx­ë6Óßàúa‚p¶pÀ° …FW^ðÜõMn‘ïÝCr*¶È&Xë h—¡\ºÆñ>µ—ߢ¦|ã p9ãƒe1,ô÷£¯ö`MŒl".5¸È™/⤧_Û²©ÖÆV] „r< g%Ý™?uâú«Z«ÐëÃ9ü{›×_tì*ÐDÌÏs‡ëg¥-ê~>&:+=†²óI½rØæUòPV>ÑÁ¦„Ÿtå.<ÜÌÄÐɲJ®0} w! 3UÌ*a¸^ @´µ-Üù¦p ·@õâŪ=\Y™ºÂ@j£&ls ¨w¹Ç–»ÏµB‘ȆäV‹×O­UægÁÈQ,Œ$V¶ ‡yjSßäé}Ÿ2*¬W¹ m&˜BÚpß¾ôíÁf)(l0ôÍ¢[•ŒÏI4|d1ø°‚ÉÛ±'­ïw•sÁ5¦†æîJ%%æ2ñ‡ õ†%ÐëÔ8~;Ø(¬k0¤q]»høÕX+ÿ´Dôºh8‡xwŒÆËÐhm)Y“QîÍ2È´ødœÏ´Ù%=Æ>ùPWwo0Dwƒîï´¼÷7GþJ¹l+ï¢Æ:ü.Ýß¶~?÷÷÷½ èAO«÷»uß´;8AŸç³õ·«;pãuÑ™žê¥³ü°J(6Ûiµïëê*ÎjpFÞ ¥Ë–¡ð]uÁ;%6›9ÿ¿íÉÐÚù7ß àÎí 6a°z¶ü­ˆôóªƒùUÇ´@èAUDY$%7yÙ.`8v t¹¾´&™`¼a”e‘ƒï«D>ÏK}ª³¯àn|lÚ©s·”w¶ÑŠøG¿­¯è7XJ ‰mÛÛˆ8ëu|þŒ¼É’šÌÇü+€$,o;rE_´æ´âäg>®‘û˜»¥z7¾èB¼O«=¢ŒUeáJdîXUÊŠÃ@$Pj¾ ŒÈˆ”šï³®Œ‹ «±š)V{^]íQ¶‚ÊŽdVÉXÍl–ûY7î.3klFQtu !Œ H$4€Ì º$¨ÉÎá=«¢Ã4ê*Û¬<Ìrov>B9.Ó¨Õ£“!¹ÊŽ[¡©Gv\9qžÃ³$³¸Áƒr,T®ZåI?²WÊæyg?š¶ñ`‘Qy—”kÁ6£©’iÕñ›Ÿ }7hhÿë p”ß;lÀû%‡ 8ž76ÐÚ©; pÌ‹gÄü(6ÊqîÃ|ÌðÁ a¸NØà.„¡¬†k$¼waƒÊ¾Ü`Ø@+]HÛ{„ ø`Wð‡o7lPAsó°øÃ×ıóó‡ß/lpM4º°øúaƒXðrM«D)ʉ“é› Â_pE#zØÐ;­·éŽ_T”9×ÀîJ†Ðœ*+ŽI2ìÆ/N`žxeÅÊŸÕðtµ²NÄúT>`D°ê³Iò f©ÛÑ5Š•Ð–õwˆ‹‡-¦ÍÜH Çï!ßuh£ŸÔY0r²þ‹š<еel[U0^åðP/ŽK5n¢(ì´†ÓšyÕ!nØ&èXêŸ2}Qˆ!¤‹5ú’é͉¬lV¼Å{W\ÄÊ2êžØl‰4ÖhÔTƒ…£úùb©¢–ÂL\#˜ÕWß„Ñaì¬AóëÃd…?Õa÷¢å&ŠÎvrtán)DÈ­f^i¦#è_ ú{‚þ¹tˆÇæ_«ƒmS¤”9;™'ò’–Ì÷˜ÜÙ¿#è©ù¿4Û_ú¤ôÆæ3„nS„ЏY†²¦Ç˜ýÁº¾¡Ú×T›Ì)ÿ „ÆfàSDëHœ™Q5X–‡­Êyãdúmáú÷¡ì!‚©Ðßså¡ì2,ç,¸r0š¡¿ùRzœEŽÍg¥„Å_L=– ,bÇ\ïïH˜o˜ùºÙ`̵{ž1…\˜Ïyä›çžhæ"gaßÉÿ\ŒóûÊ<öõ€*‹~BR¾ : ú¨\#I™AÀPÁ§èr7|̆èÅ•E6y_U'cá¼Uâ0V|WÅ1Ë$)ØÆ;`#Ó°H2­£Í6Jîè—“ï&Îã˜t!Ã,¹ƒEwÖÀöÓ‚ ,ô¢:˜ªöeq+¦}™ò£¾E~8)+A˜Lèêc¬æŒëªÍåˆ:…Ô0$÷K|KU¾_Er§º _EDä ¾}amzÈwC0ÊQ2S=7‚)$¦¦Ø¶gÛST‰Ã™¡5¬Õ› ;½í9f¸y^ŒC(#úN9BìÀ =f²’NÕÑ+ßq,JËD¼n­A úO‚6ý;5euýƒ üHd À[ ×XçHåŸJž–"xsËç~&hCÍ¿—2Ä)€Ð°é(Õ&‘¶œüLŠá`¡ù¾»,•|¹Ë™DŽÒÈÊH6ÛLjAàzŒwU˜#%bwÐÇ]3Ê äGd±ïƇ vHœÕíæ»®OÚýÀU¢ ú¸ e•Œ¬ð×UûÞKËLˆµ,¿9¡è‹ ‘.œSå©ûU$ë}ëÖ,ëÀ¶ýØ>:(W\ÎÆdô _qÚhì‚ÂÔ;ý‹ÙÁ*rŠà­ÄÜAÊ óŽ6 o¦-uë`„2Ûi|4 AYA-‘¡¶QÛÑÝŒe—Ž3À‹ÍWφ»$hýµl£ŽOõé]_O±ª÷­[—l6Öé|¶%s¢²s†_9X_¶;ÙΨߦזŸ3۰ͤ9=Vä¤b–°ìül¨F;/§¸÷ÀTYþÁ<0,ybÚóð™òf&%Ü*𥈔ÉêÕ¬ `X†þ¥ ó~`ðˆMФ¢•Ô¸X‚ml°ó¯Wø‘Õh 4¾¼EÒ§bfýR7ÂtiOøÊh¥1mÔ5Q¶EÛHë 3™Úƶm÷r/„±}ÚW7;=̳*o‰¿+@ó™c†ªd((u?jÓˆ/S¿ásá=_{ä¬ï9•zªcÆiWÏ»My¿yš™Žo@"¦ïìQ^0ËãªÖÅeÙcÊq}z#{ÿÉÀqÊ>’À²ÇòW à뇅w‡z²D·©ÜÕŽ€ß‘ÙÉ’@A]Æ|#"Ï^5Q1«ëNcáT°1ôÒH Ð6 çé¯{2*{ôj_§Êßï­mdȾs“'±jç¥åü£þ‡UY¬/{2çUÒplöq2Û8úu8i&†¥´ÐúWV},(¥¨Ç•·aþ”†e¢Áæ­×s±•}4`»Éçx…V/CbjÂÅ¥tÎX°OЂž4‰ŒPû|2Í4~I-÷ù°çé#)OµðÄé›x¹Ó2~õ®ž]ÏfEejÀ¸µß¾”aœ~OŠh\õ¸v…]y\`¦^ŽK¥‡ôÝøûEMS°DY\Šö è ž›ÎFÈ4xüÒF˜ø¼ÕY&ÝwAP¢ÖPië~©/©b4?eh¼Qóÿc¹åTä´.aÇb{­¤þé˜ôá8Òi€ºÚº¨)õÑ(à€‹…&¦ñ*ðMºŠ*ñ“zëtJ"‹Î¾Väö#[ZÇǪWæfžC¹ë°››pì32q1æÈ×ã«yóÍ¢Ó/¸ úã\˜«=WJŠ&ˆL“ÔM޼Œ§£Bn1À†‹kâÛx‡™íÁ„S)Ùt§¯Œj,•ªäÎl“ì­áu‹©Py(1–?tY˼Z)üI\n±Äš ir‘¯”}œÐ޾A´KhU Ô‘Àøå¥º!ñQ§Z4F#† Biªb½û6‘LäË+Ö/Fsk•JYDþÕ«ãÅP"õå žÒ2ØÝk¦Vè.à —ÙÔ Îr0ƒSÀYS Â'$àPÚøÕÖ¿-pendstream endobj 1109 0 obj 5233 endobj 1113 0 obj <> stream xœí\ë· /üñþŠýÔîÙñè-m8q\iž‡¶@Rç{#÷òÝ­“ëßá?¸¤FJ£Ù½µïœ/EàÜ@3£%)òGФæÍ¬ïجÇÿÂßýó§ßsÝÏŽovúÙKøw¼óf‡ùGfáÏþùìù.>fäÌuNs-g»G;ÃlføÌ°¾ëað|çÇùç‹eß™¾çÒÎKÖi-•œ_-X縳<*¦ç8(z)æõmáÄpÛîçÁÓE4Hî4}ôf!:¥œ”ÿÙýÒsÄ(©\vB9;Ûýjg÷Ï?ÎwKÑq§„›Ÿ,–ª³ÖÁ0—¼SZÍH?|ëM)Îæ×‹¥ì¸rÚQöòå9>à¸Òb®`.!;Ã0ž~a˜A÷‚Nî[o3%æ—ip??I^JìWº×&¾~ˆsÖõ†Q¢VùüÖ-R ¢âó×é7QJvš±r5ð¾cLE¦qôu=˲"¯Q€µDZ…èXµ@¢O RpQ¤E°^ÆÙµ°(|2³tš'"Ëwºà ”TšùۅDãìŸ/Ps@i;kèõîè2á“P·ÄÃ'0•¥Õ§·y?J{¤Í–óÑòÆ©†å¥T]"/º3ÖÍ]0Ö ¡EõRüý_òhouN*e‚á”6¾ŒY 2ëù —o³]/Àö…S®Ôéh×ÃmÃ#%=¨ÁX¥ &W•J3ÛIø¡Ïa´¾}â"éÇ“tuœo¯Òàua½ñþm2ÎÓ¬4­é›ƒ°òCaˆ{™ï°–½Šæz×ÐPV¡¡¢çq®® è÷aT0ÙYŨˆ ¢¶>I¤§±U ¨Ú¿4%¡%7=0«é7@(«¦ëzÕÂnmðQšÓÑL©÷‚¹®W‚ & cƒ‘®g’Xë^FbäýlwÏà>(?¬Ö$Bù²n <° óE\yŸýaçÅ«N…¯ûyïaX1œ³ßjž©]K[À @ÀÊ™ºSœÈ7ØÀH¾ëý^¸$ò)˜b"\ù1¸r¥O¹ú”pu½0¬“#·ï‘‰ìFqéu§=ceù¸â¸¥+8ý KÁóŽRÿ&³·JŒ˜¢üñÑIF!fö’~lF1 ²¢d4n±­.vZG°º`äZP÷Ýö¾›WR­;þ^ Nbƒ=Nù SõîA`FôzK’&–oÚF¤á¼ã!G’ÁYÃ¥\WîîRàí³4 ð‰só0Z¸† Á¼Â6²w;!N·ô´Ù¿âÝ“ÊM—"8ˆcqôc,@©.—í/‰æ‹Dó*¿>]‰À˜ ¸øÛ&‚>‹SªA”{_Xù&_o„À°[6"=[#îÛ†¸© ®?š î ToÐyR¿1™™›ÊÊŒ ÆSð~‚]>çñ¦Ú¤k ã·_ÁI`fÖàßffaÏýq€yp%~AΫx½Üdü²A›ƒE°^l)„í‰çº&>Cꪱ¹Zww#à>ØrL¡QÏ:ØSv&à¨1ìñaƒ¸OƒO73°O›Ò¦„T*ß/Rnè šò\ Û“< ½~˜ d¯(0ß Ò™š×‰"Ñ0Ì*dæÙ6¨}Ø`¸P”ä£Fö£ö©÷ˆ!pë:]ŸC²£D|NØœ•Î4GnÆäøá¼â5Eifz÷AåÁx^ *”á÷•Ǧ4îS)­Š*ÛÓ<…*ÒÉm·žk”ÓtÎôŒUÊimÇöœ¯Ã:!„z°åEL—‡ùòÚ_›Ê—aÃåÏÃÖ£'y”¼v˜/oò'yô2žåQ¬É:c;6ÿëE®;#æl±T°4ZΗLö˜LsßRÃ%9áÒO+êQ¼¼WnSJÙ‰‡Ëm. ²–\1’°¤s’›ÖÜ]Y ¼wʯî<˜/§a¸a¶³tƒÙíÍpuKæ?jæPš˜Nuz„³)ˆ ilÝÖá MâwkÅ âÊMÕXÎèe*{’ÞYÎV’l!a¢5ÿJ·(Ë‘v P‡=,E‰OwLX­±*À!”s|ª„HRį[éÔœ,n÷Nœ…Ûl„¾plÉØR*:!ÝüÛä:^ež_¡¨T'¬¤¿TvaøuÊ—`àŸ…,ÊmQ•Œ£ûMú«Æ”«0ÔH}s§@’:`]&$Õ\¼½±Ò‰õM Z Ü®o–•w‘¥ú€ëÀ ¥Lp˜«Ÿû™-2דVÇNb{¨~‹’ªŸÄp/`ámáWyxŸjß­_¡ú:PŸ»è $EèÃ‘ÝÆåƒgm_t6 ¿T)ÜDý¦­aFäÊÀiP áukÚ£fѹ¬X tÉ-ñ¢²GOy6ÝãBßbOÀnÚk¯Ñ7,'; …äÑlÜí¢Ä”8b/ÚM2c+›f O‚Â9M°Xf.yÔ:äÑ—½i×[ÄQT“ríËyýÊ(>!,"ã9Þ¤²ÉEÆ4/WìËÈ¿€=D` ó·ÍŸ%®jÎüÏb”Á„ë95êËÑkº/p)K!™5,Ò’aÍ gÃZ•ÄG3»£Oºµh 6»Ú½kyÝV©®ˆ´Ð ƒjô˜µW'6;ÐвÑE5F²Sƒ@Ø;Ô;SB‘û#+ªM>[ah󳽸o” fŽ{/’Å0õ½²¢ÌøŒ L ?+êS[”øÌŠnŠ?…JÏíø³H0On©¦oÙiÀ9Førm;ÞíÄÆ}eƒ1EºÚ^ä,ô+lF§Ü÷ÔBodLwð¢ê‘)÷ZZ{‘!d“¡µÉGokÁ|Ôíú÷ 6_¹îõ¡"j€ Ó a&¢Q¢dw±MR3~ ýÆaèåÕ¶7½rêyÖõgÔ\E´®˜¡Ýëyí)ª y¸PÞug†õʽçÄÉ~ð´imh7V€«qó:±F¼l6ß¶ñîr˜t1r˜x¢dð¤9¿ fmùg€¤jó.²Š@CxVöŒá‘&ÖwÚS²ñ–!ÕØ¢ÿ›çÜn?®þ´OàLo½.30Uî}wº·A×ê½×„†Ó`Ù¾vL»¨Kâ= ²t—%6ÑE“[Eox£I7Ó¡idåŸ5t¯ÑîuÏÛÞÎ’ÐÕ/Šé%lm‰Õe¹\Ô„ùÈh î6mi›`ìÛ/WÚrÞψêd¶ÒІ(Kæüç¦(‹;–šnR”µMéˆû æyü ¦ÂO%’·(mˆ£¸aÈ‹àr@ƒÔûã®XB0Œ»U'm|&T¦Ì•¸+`™d¢;F*BêûºeùO~IiºÒòýñÍHDv5Ú;;oææªãø¨µ˜Éàb?½w ƒŸu«òX¤°X$ZRƒƒiŸ›Â£,ØàTý4ÏOˆo5f0#Þ¾gx©úi‘A@ÀÆ•C\òrDb‡«†5‘Zÿ0«0®7G‹þüˆ³M*ÅØ}¦cãâAFÍä„û&H]æ¼ý]ð#+–¡ ”šŸãæhÍ©ÇÐÀ)š!æ:±šÔÓÖ옖ä*eX…¡Æ×<ñt›æ˜æ,œÍÈ·y¼° Ÿïz¶fdlgFˆV÷!³›1x]{ kƒ$¬Z 2’ºÿ»”w§™ ŠÈ´ #MIù‰¢í…HÉu)u7ÚíNT´"!±º×Õ2Öp”óëÍ C2Í@»†¸8=ŸŽ£U†K-¬¨Š '¯D«SÛ7‰gN‡àè¶Å›øÞEó‘'ŠÛ®$ÞBp„+”b£æ ¢|&±ÊèaeÉØÑ9co×ä˜ÜQš©ª“a½‡+ê©Û©‹“ð[*•§&\I¼ŒÅé&’ÙÍÜ91vÑÒÃ{¸ý¼Ý‚…~ã»?¢°ªÏsE _¦+¼‡Â´f%ës•ñ\_F¢Y—-H¹ ¾ØbÜL:Ó|±šH²TáÆe™Oh!ê8³²—ô™?"Œ$®ïŸxœ§OÒàYö|I¾º‘Œiƒ‹õ½ÉíU©.a÷o°Õ¤?ܨ—`2¹vë· t½ÏŸí@›÷Îç_Ž£oeÙC2¦ß;º¥jç©´–¨ûpBméÃÂNcæêy:ÓLEF°(–:7Ee{Óéï·™ói«mT?ä™& §]:Ï1é¦TGå¥P” ÿPþÒ-s ÷!hÓHF‘/‰ÔêX±™B½qüA|QPœ V…ÁÅÀ•¤_+wR“m“ÝèpÇÅ:à!ºp9Ê:××Å÷ b¶f”·©>22ªàtcñ‹gSìG—ð–˃ã4Ι"ÙÉLù/ä|U} †ÄS¤s•|N ¿v"-À\Õ[7 `âP*MnÓTïÛF¦vdd[€%sVl.‡A^¤¸ lž*#›÷ywa~7U\"!K¹Ïó Ið£“=€ )3“IüÒïö‘&Ÿí•tt[˜ÆÕ¢Éž¨°2gE$^¢Éá$«‰Ïla%LZ‹ÑæÎ—Æ?T7~Dj~«âüGAâíû|ÏÅk›qT[¶˜2øƒy!²/·¼Å:a\…bÙØñTÖ„bŽ”Iƒžr6)æb›SöWMÛ.>×z`퇱î×`¬ìYB¯û|–Âl¯JO©÷:à{ÈÔ‘ŽeŸ—c‘ëÊßlªLâ7b`!¤\±¤,Ë?…»©öÝÎÿåœð¾endstream endobj 1114 0 obj 4238 endobj 1118 0 obj <> stream xœÍ][s·±Nå‘¿bó¶<åá~ñ9I*Ž]9J9Ž/ÊÉC*uŠ")Úe‘’)Ò²þ‡~pº1 vv©¡’rÙœš0F_¾n4àŸ6là†ÿLϯOž|+ Û\½9a›?Á¿W'?ðÐd3ý9¿Þ|ö,4ã?x#ŒÚ<{q2À7V –{¿±œ ~¹>ùÇöÙéNÂké·ßŸîôàœ÷rûÃ)ƒîZ ¾}sºÊÒ«ííéN B{ã·÷¡­gZm_æ¶—ØV Úèí«<Øëüx—Û’O¶70‚Tƒ5ð]9hí•¢ýá|0FÂãùø¨¹¡Cýú”^x'hSœ‚´ƒ”rûötÇ㽑šÎ÷,7¾ÃÆÀ*´`•&Ά÷i¨‘±’YÂX5òÅ0c'úQùû÷ù%Y˜‹‰­Âãc¦'m¤£S%oÏOÿùìÏ'H.H Û<»y¹ËD 0èà•Ö›=ùV—R·›:³nìÿ]œwã—<Þä·„”³¼@¿¤ÕŽßRô[lpzr/áßã-F!sª'5Œ~‘žþ?ß^¥·M©-µaÀ¹‘éEËeƒÎs‹ª<ós‹ô ?®p~zûÅhëWÖ':ØË¦îÝvr23K®„7Ä‘NÉ’/ª®×Ll´Å®Q֢¨BãG:s7¸ÖÖ ðÈ“®ÿ“x¥M4UâˆJÛÕx{™ßÆq•¥~u  ôà©$—ƒƒÇkô^hS8ª›SÐHéŒA±”ÜÌjjž ‰dbÞ#àúÏðÑàÊu½–¨z’ø¿³¦ÿ¸+¼V$–8¸›L-¡+»½Q\œ@ -A]`ÔçÔkR­ìð…pžßgIȺ˜h1w¤0Kñíè’,V`êÍéÛ—{ =saZB¡}¢|ƒJÉÐãç©ãd ZŽjÈøÉqV¼%k/i{‘LJ®(6©…S¦â\ dî<ð*7¸ÏäÜä·Ó:r`h¡Xdàdñnäñ]L†¡Ý$:LR"J÷#êŒc¨v]$Ùî”}U "N‚yIwb_N QSë9ÿ.| Ï2]H‘ÑN…ž˜Þ¢ÕÖ°ÁÑØOy‚ý 5Ž/³æÌÁu2Éq¥+è¶h“…Ìh2_'“üxé3 ÎÏ›ÃÍt\²Æ[èÖAþm…PA²AKM%±ì¥-3‹HõnnGÝ $ˆ´|?‹>€‚¥@ãjòG.9C„éuÓ`µ¯£®@À̰àWQÚ–3žì HOÇ"W‹0=g{(t`c¨–ûhª_Ц ¿ )|‹`0†N-cÔû$†œ0k—%˜–ʸ}²¶ÃÄfEÖAÙÊWñœ.È, vøl²¸I¾áå‹ü]BéE¼ì§‰„%³ÁhµQ¬¥¡@mÀm² —éÝEzúanSðc_<;ùæä§@‘Ûpã0Öï8ü{~}òÙÓ“'Oÿ²¹»½¿¡,èžÄ#ŸÕÌ©ò‰…,ÇßÓHªˆºûAÈÈQ|I¼Ç >Õ"EÖáj½Ü×PØ‚)NKÒ2o§‰3…k½,”, æ(ºmE~D&²mɼPÔ A8Ú¦¡ ªqTk^¥ð.{D1Ö'CÈ›€š”ñ§ÚL3¤¢ Là/û¥p)–²\PõXD&m,Zgü®<èìs².Mr‹hùbDTb²ÇoA 0a|00˜ ´”VtRà1œؚTð$"˜gHJ§ÚÎ÷¼6©ª4Û\Š»Â8”2æÖnÿxŠyIš±Ï\W“ ¤hí1×A1¬$z¼Ï0-¬¼J©¸$ù:šÀW%Ûa™nÔ3v€ó\]ñU°Æ£§½GÓ+½›+!|‚O6KG´] ‘h•ë€óˬz¤ÁÑÌé#}úÌÎ8×S´Ú{b·@á:‘¬¯]û](ÜȬ…³Þv8Y‡Ó_fí¹Ï HÛ¸E(m'9sÕòC³É×qÝ÷MY?ýL’ MK~Õ1ï!¬ùöoÄÁf‘Ý~—t=‰bQxò’¨Çy“þ"«="¡ÉÅ^qjz_yº:WBÿnZ¤/±ÏÀ~/.¯ p'XØi0Ť5òÙŒ”㤀TE¦÷á*J€Fa;4Ž%Ð-r6H€pæÿ÷8€nz>ì1hY%€hd1r­4´ËFH š$ šV‡4Y:m_Å´õ:¨ËðYj—2ÁÇãgè½R¾z ?S:?@·æãà 20òã§Ò„nº¨¦a-™÷÷ñÕåì·CB©’pø>¯· ^fÙ•Òýða$L†Æ™Ó&?ceLW×@ãÀúÁ§‚ÌË!|‹Þqam›ÞÂcç0vÂ/¦ !”v–9)‡üjo#`Z#±-öâﯳjƒüöæRÛ“]envý—ä 'À®9ª­}M™Ðà5pøÜÕÖd–ÇN¸6§5vC[މÔñ%·Òºn¶´ðqà¡_\'ļ†tð5®aHˆãY°P;IO³|f¾q^™!ª4ƒµØô§:¢©é„–y²0fÚé˺œE°Y¾BV²(àÉZErÄI”õŸ1s¦\‘ì³B»PExDöbƒýÃ@\0Hã`ýZeˆ¢‰×¥ÀªÎPZãb$®ÊaÁí{ÑH¹öÄÚÌ—R6ÇÚ•ã#èqDè®®j_ÈI¤y<$‡ßc˜ÒA“°¾x*}ôXmñTÚ¬S~¼ žÀx.(ž¤ïç‹çŠë‹'¡ìcŠg3¶¹iÁ‚c¹2mA>žµ}AÆ àȱڂ _X§üdA…ÜCí,éÛJ£·yʼnõ™Pö1¹}Üðn 5ß!Ò^Y=ž{}Yüè±Ú²*˜ÇäÚ£Ë*ЫjtIß/–Õ'Ö—UBÙ¦Ñ}ÙÚ#t,Jõñ|îK5sGÕ–j6þ}t©Û)”jÒ÷íÁR½âÄúRM(û˜RÝ>ûîYÌKŠˆú;lí}µ²=¤|¯ð£.ÎŽ´ì#ÕéøîªBV a þ1Ç@÷ô‰týû¡Ê´æ´ºÊDûÏô‡i]•¼_Cé¸Wá¨ô¿_é }¥sêè±QB³q¨Qíœ\éöö~GèÁ¨:ËP%ö¦ V$´ïš•+k|”ÜçD’`î•udAwË›Mç 8kæbÐ}<ûB(_'Ó%¸yÜ­;K ß“é¨Â%”Î@ÓXrFŸ½xîóñ3ò™ý±u!ë+ò£/ë„+ÈzqInʼn²Ä“~Û2†êž\©hg8Ì ôm¹W5Žçz_5˜?öìSG5˜—¾ShAùÎNáþ˜1ã¥E±^q.}±&y$¾„¡«úßýðm?"!èæGZk¹r"}<Ç»"í-žsã¸záÚTg¦½5|:ÒÝûâbÝžNWŽ6–µºuléRÞ¥ ê\ÔX]¢.½µsZ‹XµÎ…qÓá°CÖáèRuuüÿ?¬sÏÑ$Èí’èÅ µ#Ãâ4²VÈæüú_ê!D°áîÿxÇþ,Û(Jh¦Žr \6jàÙ=óS'³ ^*¦Ù~s“ñ„¯à:H+ŸŽÕ­¿ $Ii<È,0Bn‹ìË4÷x©–€öÞõ* l‹™kš>úÞJ¢ýg’GBõL¾ãÕ?±R•öoDi üiŸrÙeEQœÏäC ߦ§/òa´O’@=•ÏŸ±µé<Öôsz{؉`ofܘ߲k‹Ôw÷.°pñóQÿo•‡fÆ«Æ9‰”_uüZò†ônxÜ£ñ.¼RwæX“I¸§tͰÞÞêyŒƒf׺/«kœ››¹Ó PÚþ@…êª9ÞÀø˜ _xlÙ€~…€$Hc¾•gþòBþæä_&o!endstream endobj 1119 0 obj 4889 endobj 1123 0 obj <> stream xœÍ\鎷òsÿäF€ÌšïCøì |Hö`‚´—…ìåÑJŽdä-üÀ©"›d‘ÍžÙµVN HK±I6ª¯¾*VïO 6ðÃ?ãÏÃó½ûßç/÷Øâ3ø{º÷ÓMãÃóÅÇÐL¾ðƒ7¨ÅÁÉ^ª Ô1±°œ žœï}¿|¸ZËAxeÝòß«5ŒÑÜ,Ÿ­ÖzpÎ{¹<_­Ù`¼7R/¯JõÙŠÁ`Z ¾<Žý$Ô¾\ÉAk¯ÔóPtlpzœ çvjaœ¸‰3y¹Rƒ“ÊñåQ(A¯åÓ\w•KÏòÓë\WJÇùé&×]äÒƒÕÚ(;0)–"WÞË]^åº2™§ùi©» %k—‡¹êEªz– gùÙ‡cUܱýpŒyK>"{?Ýp<¨Íj­ [Ÿ¿\­…´ƒÔfù3áÇrzäÈ. ±2ƒu¶$­* kͽK¯åmÏÊlÎ`ÍïH2YÒÿUµ,!*™åt5op5j°2ôrvìï9×( jðB¹|žŸ“Žãs-ÃÆ=·|²,µa,cÎpº®ë2›Ó¡l¦WŒë6r\­aÆŽ{æÕªExþd…Ci8a‘ÀW¥ÛU»|Á³j9BʧŠò$”@Øâà&¦Ç.øL+O^Ü›s<+']ýežÆE™Ûc^imoªßÒ ò£ßº£ßpê©òÉ“Ît~Éu2iñJUªûBé(?ý%Uuz®oÔQ•Žk?HÀdyKäXWꮃè}’*oaW3Düƒ¼b ÅoWÂ;*5ŠŽ¥†ƒ P+c šwƒòœÖ¾ª ÒÍõ=Éø=\wË“ò¼Là¬(ûU˜‰`p&SŒm "´ˆÁ6°Q¦—”±ûz2g²<¢õ×88{-*èây‘K²è+¢ 4Õž9¯\­Gäðƒ 9Lî¿.ÃÛ\éJoŸ+Y®ÄñÖã€k®ažÞÅq¿ VžÝ9ø)H›T„óÕlSÉ H~¼±—Îzä/©)±Iã~‚%ÚÊ^°éƒ\{CxÓÆ|E{–5ú,ãÉq®Û([*ã¨æ0GÃÔ ùòÏùéçùé×¹îË\zØÓ¯š§X:¡QŒ#ƒPžϦϞ¦ªG©P¦ñMª:H…o gØû[\”räÝebÿœŒñp:þW©ðQ~öEªzZ7*Ëc®á ÃäÕß6»H_ýhë²Q,¤q³6éMœ!™šlððƒ‚¤®k.bgbÎ;4󔨵ôôƒ\÷I#\µÀó‚ØÓ81PâÒ¹˜Û éeTËѶZK¸ñyªzž ­œ[$k#h̸žªUôz” _(õëÆÔÛ€Žq:¢Ô7 €ªLÁ óþ U}˜§sZ7/{URO‰€k‡’²,mûXQl ç,6,=ÒøÀ7õÖåÝAqkæJ:‘kå.¾{ÍÁ:Æã~>–žª\w¯{›f¼zV/š÷Ïé0ÕÞ„§\ƒÖÑÝq¬‹(|<8KÓQ³AZ'oʧБò|z¯§brXš¯ÕÀ¸ˆ¢œO§uU–‘že>šŒÕVr¨AìhªPù5XëÊÏ]ÈÆq7PÑÄ»ùnp åá_5ëà öïý´1ŽÛ-8œ.˜IèíåÀ@>Þß»¿ÿåâzóêxïþw ¾wÿsüçãGŸÀýOØ{¸¿x¼%,2;OÐSÍóNä+mç&Po΋š‰;ÎE—8!#4*ÚÃr^—]¿¸ø”¥ÌD•0Úç=JŒtKƒÌx5G„‰p ³–Føí)NÎ(:µÆSu” ¿š›‹1ö*ãÿ™Ì„̯ëÎ÷\iÁUÕH†êÊ‘x“»Ï’íк\W¯ û`èBŠ¯ë° “ÌîÞ§H×e2“Ý Ÿ„D¦ŒÛ¥8•mûEÜÿРڰ@ò¥ñÛƒ&Iˆw°MûÀ?ˆŠÞÂD†árÐŒK –¿ HèÀa;(AÍÆu6Ð×µE7’sÁ=J8}%t^R^Îu‚¬GÐèΔÚ/pþ)¶€“‡s/7q¹²x «@1‚€kXsð§`ò@±‡Ñ§(SÎjî±3´ OýZk•qjñì½×àÆÆI+ðw.K‹ÍJ€b:ÞÈp.$Õ#>?Û†@ŠEÍ`°·©×1”We î©Ï0x5h ß0•àœéÒWPÌ0ਫ਼“HË40ǪðÌÄü$šÆÕÀÀ…È¢äLÍ0"ÑŒ@&l da®en€¡ß –©ÈU±ÞGÝàÿz´^Õ„)ʰ©j YÓçIdŠÄ„ŸÌØ9Ä Ù²’€æt“‰µ'„b‰l¦Pn òÄÛÊ‹\3¥Ÿ8¹ ú×Ê À†uu•x]ï F¥Å„_+¹Á^¥+$²¨.•#•“¦a¬·å YLŸ÷$Ê»‘q?,Ï,?ÔV¯(6áòJVäìd¼NÒBÀv¼Æ°5÷ÖOï¨$ïÜòPšgXŽæƒùãºéÙš[ ‘l„¹ƒ ƹÏç +{JÔ†hûó­Ñ\¦§ûX)žò;U¿>'$gz”Ë»YáEEÍãdìsâíœ÷{¾u -»Úo9Õ¼Éùc¯?fœ=-‹¡%nÑ&CÓÓ,J͈ -v‡†Ýû²“ò’wÑ+/-ðLf1ò¡ÁHÝÏ¥qºl¼u¬;ib¦%['ÐhUí.×}u8ö¢C¢žçº³†DáÓu§ïå”båXV{ÿ@¢oé„12f}a+7Nf¹÷ ‰0z!1cDK߈ºä*x …)ܱТÃl\•‡Òõs®z‚U¤ÄKºÎQñ>ß|L)e¦‘Ì ©!^ñ€o&­Š-“3ñbð³GXï©gø\„ÿ¹ Kz¾KïO°©Æ»4:­´BNƒ(„fžMù@µêåa˜Ï;3½ÌmŒx„ExãÏ+íÑ­ãh¨”» G©Ä8j?ƒHJ’¸ÔUFÝ ³æ3̧ÓKlêfzrÈ htLdÁµš £Ùw1\2 !w„‘}é7 ÇzX˜Å$éç]­€ %À¬ƒr×+È Ž2I™D¸Í÷YG]až úÔo›"‚jöœ÷Š &r3òý*EiW2ÄxÑ>“Ñ BHåIIA5ÕþPäŸwI…o‰…i;f–¿–ÑÈ‹‹Êm±Ê7ó~Mi¢I.+ÁA“t¥ËV² ¸MIÅÔѯsX+N1òT™ò’3-”£'w <[ŸÒϸÊYýÀ@ŽhýJÔkëæiàø†“žtTñ»98 û&\âP³Z_+;îÊ?‘Z+oƒ'3‹ˆ2¥¥ÒzÖ5YD@úà… ïàä¤ ÂFΚÌñM±DÆOF[¬æl^J É;ôQ*Í`HÝÔ-.•$=fê?4£—Õ¡¥à*Ș™5ªíUì†s¸´$™˜•wá«÷C›DH*-< ›B^«‘”|àL÷Ínî´óî°Ç-4”K÷ôÓàÁY<È×4•iæ‚Gn@ùð_ò>/x˜!W/§¹©,ß?œ—íW8*$—Ð1+dȪ>ûí'¢£«¬€Ä¼F¸?%¸êR³`Ëo}—ÎÙñ!Ð)s@wP25ø’„ü®66(-¡Ûlì47E–yº+×]Àœš|Á0‰¥4)¾j™ w¬ “z°ªe•¸‚ubšioã1TYdÇú¤cÄ o"`Â:s.ÿýt“ äj'Ñ §DmÊÉœN –MÂÊ¡vS°–Ô¶ä½—ëA¢?åÁˆy¼LÛÏöúQùêJ%ß’Ïù*šÌÌajJ8š˜µ•åM’¸êmè·rÓ>79^Û¯ ‰Éx”¡:­Ìe‹Ü †^¿1&¸ó"±û‰š.ñÍt€Êˆ$^·õFg0{£AÙúþÝ:{þ›'£§à7wåc›«òÞäR‰-_5qä: ~؉F¿l,C‰FÇÔ·eÍ­™«ë̸6k·g8±ô¶BÏ Ù¥YN¿ÉßÎ<gâôòûi&çIªú!îålüÜ|s»æ×Í‚i.èùYêhz7õʪ Ðôê…é¹.IžÓ$Ïä‘ÔwW˜–YçÇëßY7ï^÷¦A”ѲFbwÝ5Áçé݆íR}aBú =÷œ[—E[Y«ä2¤%qè½²V  7ÕBó„ š©›(‹”a¶t¨_ãE®™óÆú!¯r%Ú§žíõ¥0‚Î'a"k (&r“?eM쮋ŒgÒtPHÄX„§Ë/PæwÈÝi2¿‹b£ó‹wvu°E€ãÇßUÅÓRPqU}C€VŠôUXíà“±‰œõ´éËp9^Üæ¶ªýñ{¼0ÃIfY#é°×JÙ7¿„”Dÿ>>Öìg¼ÌØ™Ê@øou¨˜Ç‡÷X'=o¼ë¢“3ï‡û¢Ö |H€è~p^^úºœgå”ô¢Nä#ØI½9å£1Œ£d%}$!k§+Ù5˜ySH+À,Í<~ X¤ªäVüfù 9³·—¯¯ˆQýš”á:vo®ržråè\í‡nl(Å.};Úe-tÀ«ê;€:>6Ìx"ý5ñÑ&ó ÷IÓèyã`6¿0!$*þ`u‡„õ/œ»§J"rG-<ö¾¯mD’«èÇl1ˆ[œ ñ;'iÐò<ÜG'ß焦XϧÜ3A‰fŒÞÁñûËÊpÂ…`4&\ZE °›ôJîë¦H@€12¦CÁΘt~fÿ§Èž~a"»šƒö~`¼¸&kuü ½6òcð.öÔÿ> stream xœí[[o·.Ú·}é_Ø·Î6ÞñðN®Ú µkú`¼’-×ZíZZÅ•Ûü‹þàÎ<‡îÊ·ÚFb‰^Ïå;×¼šv-›vþŸðw±œÜü;×ÝôùŤ›~ÿ>Ÿ¼š°~Ë4üY,§w÷ûm|êZ§¹–Óýg“á6µfjX×v0¹œ“­JÉæY?‚cÃ5\³Úã¬s­ÒÅsÙK¢9žÍY«µbº¹˜‰V)'eœNÄL‰æ§™n™pÖÒCG³9²5ºùÝŒµN°N6‡¸ü¼çÔ:¸éÖl.:©rÍ7œÎ: X)Îè­‡\ª–IÝlpï Þûg/ü^× c›§ÃkÂºè ƒ €XâÍ*­ŸùCº5ÎÑ­gi}´ ‡cªYz¹8®tFÀnÎ9ç­éL³Nw¾´°ôÚ—^°¦SŒ ~ƒ´ôŠÑ6M —¶NÚNDgpƒýF>3×ÚéþÑ{aM»®å(›„µUÄãGҲݨc²ÕÅ]INW¨¾5½&€%ÝÏ> ¨ÔC¡üS¡rɦbŽ×+Û4éÔQIÏf^‚œy«˜ÊÈ~¼F2DwäN¢üÍõ~ÖÛ)Œ‰ÊÉúðªr ¼ö@#/,p/AÞu0CkŽæ¨9•Ñ)RNn8ÌhÌQR.OjÖ–¬Qk¼BÂ3!x,qfZm==pÖ•2[°dpûP7]+GP?OP¡öþv W[^›¸DÔ\"èÎp¸¨:À ‚Ù#˜ÙV‚ %fCÜí.§â×7¹¯dàÔ¼žÍt´–)÷¶½“ç.„ k\ó¯ÒCÖ`§,çýS\µ¢ãuWx•& üVåNg´ |«@xõ*$£ÔŒŠÆž?¿©šèó´•„@BÊÒ3ÅZ†P7tÏ«˜?0ñ¶GУ­®ñ¹”ˆš¨ê·)ôÞÄ‹ÌãZ.,Nãcƒ´L³‡þæ¡çŒFòbo|mŒaÜ!—ÎyuºùÆ“àŸ.1FI€ †§UÝ\í|Á4<0)ÜPX÷Jšƒïi}T僖BøPN;j]ÁcI¡hÞãg÷r‹%žd°’xQ(W. ný¼Ö™4ýtjä]îm|Ä ðkhà[ܼõ‡\£-·ý¡N´v—/ëXMš¶†=ÞéVrA‚QQüªg„õŽÊ‡ÅÍ8ý*’62¶ f)©Þ|!/Öàž¡ôH„%d“Ç¢u¸­F?µõþ?Øô6óO³!àá÷!*·ÜA¢Š—ûÀWFÚà`‰‡º¬¾[ÏaK%™N‚ã®§ÄxNq/QØUðÒŠWƃwr‚qú쀈ʊÞzœªO¨µãy¢¦.ZÆvù³àL¾ zq¶ùóLù@-YóÈßêë#9f‘du=]½E$|jpƒ¾çŒµÍ öQYÐÛ×?«õ΂ÚõP£ù1b|L˜Ñ5…üÅÈ"™¢¹àvÁÏí¥ó\J¨¬t¬—XóÀg¦ë¸´Ô‡œ#1KˆL¢F/Ò¸N B„ô&Ë~ˆÃ ~æE‰áà¯bèKÌV34`Pô|ýu²ÿÇÇ)´èoàÎòÄ™nЧ’cñÔØv0}îsµ1g"×㦔B,«Kã»)Wsô‚¬é+™…£³|<O«z¨Tôà_ýZÍò2ºfh·2›Ø™}C0µ›*ˆªvÈ’×EòíGÇ) _§4SóUš[¤Ññ¸F%#¬`ArZ30/¤Úò(ë ÆÕÓ4‡ÕÁ›´zœæ~ìGÆmë8¥Ã`g1a8„qç¦ ¼–ÒƒœîÂAð[.URɼ.æZ{‡¹Á3Ÿ À ×–.`ÓòÎÿâ$¹&!Ÿ¤X§< YË» ñ&ïXû¬*]g\C†&3½ŸEä¬ S0&€Ô˜€Q¿všco #°÷ÝþäÑäÕT ML ÏNðº…×uçëëÅrrworsïþts~y<¹ù)›ÜüÁÿçîÃ{ðgïÛéo&ßíMmí‰ngT@6ÇtÆh"mþ­ŒEïT²«@ß\Év¨ãw7öH2w™ÖÇ•èÛ˜qëî¶dÙ\Æ@Zv& &ü°A„„ñ‚jb»ëÔj­ÐzKÒçŠõÉ%±·ÏçúΪ2‡ó=%%šQýÜ‹äúÙ±wˆ-‚Þ;ÈÔå.ö} #8é[¬«w‘ܯÞÙ- 9é»T1)¨ÒÊíº~WÉŽ†×nX= °úûÚX8FUIH? ²¶€#&i5ÒQÑe •«+ÑØ ÊRÕ¾¡©n·Èê–'S[ñ¤&©¼ñW1?»±¦ÙQYêh¨”C¥£œ-+{Ä2îCä‘P¾ZÿHÄ×M”©Æ<ãAÝ}ŸÓÞá_ÝK‰æ}/O’!¥’Ä"ð°šÐ+ØKÄ–—ŠNÚáÒžÖTY~‘ Q’× ‘ç4¶”å×lj_ÿçòKv>™ø5Õ_‹QÊŒœI’e²d_åòN¥ªßªø×RõCKÕ­¿c7Sw(+ß„²“ Ÿj@4ÔØþ䟰brð0}$Ü{e«+v~"aá ­¿ªDÁ‘Ds•«Bƶò£Z‘¡ºŠÂÒ`éxsûš¹Ôý*Šýª`5×Ó-ì€d„ç$¯*šÀW/"óäD E§•û^£în¿Çá\TÆç #T®ÆÉä&N݉ƒoÆ:}BÄ1÷0åü ˜sÓÛ…õúÑ"QöajškiÚ®ó®&NÞJÿ4@EQ[¨áõ¸"Î%‚ý?qm÷É~_ÆÁñHxÃA$ÈQ(‡itZQævʾ]W,Nä"Ûd"óNl™™áäáºÞùðØdË íî%hœ"£âOÅã^Ò‰uåóB°¹¯9ŒòO?¥”21‚9*¤Ù¯štë\¦ò¤_”kúiçlüR±Ý˜à^³s›ˆÛžaåºVS2Y_2Q”óIŽ·l-añbLÅ2ú1AÙ\æ‚êÛ‹Â@)bÓ'žäÄ푆7XŸâ^£÷ ÂÉþ®mîᢰ‰WqîÚæn³ÿwD“LÛn,ÃêÏè‡vû- ß÷'L×3uÂØ²®ˆ­4•üÓØògÇm3«Ò\òUÏ·Q­0×ùáÄ·‹!l³8×áÜÏ?5Í,Òµ€å¬ÂÝ¢¢·ÒDs¹ÝÁÀÿ–ܱ´¥m7Ò¶Ä'Ï”ßÇv‡«¢.…ëƒ:GŒ¨¥ÛØ–4½L£‹Št0‹2±Û5ÂHE(#kTE¾ÕíÇÌ·„À20ªŒÐ!㺞ÎÁ;B©+iÙá$ÎÒêå»ÓqФu‘ÖÛ4‡#^áG³¸ü–mÀ¯-À_Û×*â³}©"´ôÿÛÈ'øP%ò˜)tukBëu©ˆOøÊ\ˆÁ&çÜ‘4‰¥K^"âdø£Éÿ„®endstream endobj 1129 0 obj 2870 endobj 1133 0 obj <> stream xœí[YoÇœ·}É_Ø7ï&ÙQ߇à°#QbK–M 0ì  IŠRDŠ”DJ¡‡pªzú¨îéá.MZ2‚À°Ùžé㫣k_.ÙÀ— ÿ‰N÷¾†-_/Øò/ðïñâ傇)Ëøçàtùé^˜&–~ðFµÜ{²7àKg—–³ÁÃÓÅw«ß­7zpžiõϽ¿…Uœ®Â!ãVîÂìÏÖjÐBy³:Y3x¥µà«£õ†ÆhnVûeøj½J0º(SŸ†¯9ï%®J Zyœª8•¤[½^ËAk¯Tz(aQœÉµ\½Y›Kï]t›J5X³ú¡|éYù>!å5~ßÒ::á>5ƒõSª=çšR½·ÞÈAx©ud‹á~õ¼×|`2ŸÕÙD ‘.1ÏrXíZN¨õàk€­`¤µM’©ä¹I¢Ùp?0ëí(¡_ƒ‰'å—If15'€‡ã´‘éµ<;ôÛÕo×|ð’3•ø‡3£f9i _ÏZHYqV4w• 41Úƒa¦ú<ETÇävuÿוž®ìO¾åG; ˜H4«6Z ÀµŸ«6Æ7PTemîü,MÈDJ%4­ >(®j”'ÃCBÖU~x²FåJV$U9k—4x· Ú„–ƒq#²9Æÿw´u"bœyœ}Îu`Õ£êNÔ;ŠhÔ²wÍdß?²½Su©ð"E#WQšVQ@"0ENF¸Læb "€¢Ëö«('òóð:ÈçÇÑŽA~È«®¶I´H¤¶T8Ù KP=œýÈ£õ† –1¡Üô Ê3?=(Ê…ÒINw’ƒ¼?£†—¢ÅSyêNpæ¤À<ùìeùÖDaY/Bê3‡€OûVÐ#ä 1[“Ä©÷óÔ®rs8*ªt`¸ö®¯Û&“Elp:FûÞ ž‹¥vbPn ùŸ®;[Q½p„ò:Œ”ã]cáínÆŽ[MñndURŸËžØ¹ŒàДgµDF•$€ð¼<œjoCÉÁRéZÑ,-Ã]Ûp߃Y×OBÈÊûI˜,©š¨%ÁC²qÙG• M4e¿‹ˆû8ÕBèÕ÷«âß'F8vOkº—´ªh; ÊV„D´+exV4¦5Î qÀh3‚lè#·$w¡7‰]¾t]ÕIkÃáÔµäAûA ”ñgñ©ô«Ÿ Ñ N§œT{Ñ HPüTNðýºÌ¼T’šñÕ'á£{0øÝLMTn#!; ļãr,¢EFc™"ËÅu‚…°Y¥F0×€£ÌÖGòÒæ†pE“VDJ…°Ñ;aoxt çé‹ñL}b‡e&Áñ«â»fJ,²èؤ€€¯ WI… ïóSà/íê-ÊÒxÐ*4:¡Ãø{Gül !8ìY±¼óÂÓ Wn;ï íà1¤F0™=Æ«ì1Îoæ1(xÞèÅM‚è°ÞIÆ—$p­Ñ lè°»mÙ+Ø‚qÂRl'(ÃEÿž¸ÿÊ•]$Uáó åíê¿ldO’ÏʿŰm’Ääò¸g•ï†à“ËØJW—ƒÄ 傞ߞÈRçÐÍ_„,¯¦UŸŠ«Ž»Œ}º» \ØRÙÛÁ„‡p}4º‹Ž ?K& °¸‹1s ÇšjÛ.= ŽOÂÃ7y„úÍÝ ¬¦FÓÊ÷„¶V9 Õ®¾Éõ·£’ñ6^K)rë¶€©À­îÞ5·é¶·äöl¾½ÜM¤ñ$“Òõí§c’ ûë\/¢ÚC12é¾Q’èó9j™®,ý;“®‘°þî¥[mÛI6HZšx*å$EžžåJÓL@S—=‹?Ò†·kíAšpòÈw%õv¾Ï”›w`º’@ÂÝ3½ÚöÝ1ýKä™”L9b eôÎT—ò÷ÄÔƒÌTÐÃÀfy ñàdéíA~ö<ŽòÛ‹…Šùö«'Ó?•ì±§ÌêóñNA_Jxñ=´³WZÕQ~PlR‹þ%ÉTyxÖ ËHL¯Z·˜ð=0,M§ºj|U Yë˜SzMÆý*„J3Ir1e}MA*‚)š¼¤Rµ$Š)­¤qßY7,"§ÚïBü³xà h`Hö*™x`Åö;ª÷·(éÙÀÅ.¶” lÑFðí«Æ‚jKÛ Ò2%V FýZl©‘qIç¦lˆÐRç€Á쌟Ã9 f‰_d^5™¹ MJÿB9Ÿ™[ø*p­€: ú‹Å”´Žd¤Ü°K!O;Ô“iþAë=ø´*ª†”o=Êâm /A°ÆUZ6j¯µDy_¦G—iPKØõþúœ±x(8Ÿ¿åŠÄôc¾‚ImüI}!*!Ý–^xõä§È$;€¬û)Æ¡â{ÉéÏñȹl Àˆ«îÉúÖ< ³›î2Bï¦\¥U9`þ‡ª#íŠWUí2”ûÇ¢Yh‘‹.¿®3¥Cv™`Ê{zƧ ocy!ɹ_uÛÚ»è¶b¿Úo£ªš\Ó$œÒx€EYG–Õµ¬°ƒæ´R÷%Ž?)C²/™ÐÏ_HÀU.m„³IC¯M®WMÝÖ¼¦ôÆ"ZoîŽM$Oí¬rI$+æc:˽·3N³€1©‹w{bÓ†¸£ëßè¤ß˜5•‰Ð1¨gê sw[½ÚºSdi”OŸËUϦ±²[¼&êE¬¤[»J^ÛóÂCÏd)¼Â‰±+hhu¡ãQ¨y«ÛšŒÄŸ‹õm¼¸ù)"bxsE=1Âl'†–EPŸ¥•!D !¶KPíJXQ{ìKªo= Y&?¯iñ!Õ3eU™¯š#"7똰 þƒ ´¤­ó²¼Û*žän¹pm•ƒ^sQcDu††'ȯ¥&uñð˪1ðeÖæZ>†EQkºûÙò¶&bü©‘“±Ê?¦h);(y‹œ'<Éy³ü ˜d¤@Úyý"?ûW§#¢$'yt?n(å꣦߫îk·®7¼H׸eçÉ….ÏáÚ­Ž\h(MQoïæÈ…†ráÞn}£#‹$èñÜåÓžæÑ¼Üz_*‡À·Ã!”˜À6ûr²ôúO¹59½æùõŸ•‘Èou~VF€‘ñu-Ïr®y4/œ_æ\M»z&Š‹o[©Ue*ÆÕÖYù•…qðH×¶-m ÑX˜qH¬`ò í¼€Js{ÇãÅk)z6endstream endobj 1134 0 obj 3543 endobj 1138 0 obj <> stream xœÍ][s¹qNù‘/ù §*/‡)s4¸°•lU´G)g½Å~°S).)qUK‘E*«üútc@ã2gÎI¹lç‚i4¾þúCsøaÕwlÕ㦯ޟ½ø‘ë~uóñ¬_ýþ{söጹ[VÓ?WïW/_»ÛØÊvVs-W¯ßž °ÕÀ»Y»XßõpåýÙ_ׯÎ/dÇ•ÕvýÖê^üçëƒFÁóì¾}Ñlý[µôúqŒ¦}Œ4û&¾ìÝ9‡ÑQR­?á»´€‡®ñ]²4†ÊEß }o4£ïMÝ7½v}T²C§¿>¿·dôðá°ŽcÍ:Åa8^_ƒ÷ÿi„®Ñ‹q/„ðÄ]„ÄÝtjºBq=ÅâÉ¡ ¨Ø vÁââ[bñ,rÅcÁf«¦¡r£öKÞ›ˆÆÙ‘âðÄjpã~Kám¬³`ûÏî–1ÞØüx.:(ã„OÓSVS8݇–F]BIJ¬ß~ˆ'²‡ƒ‘ë™3£.Mo&â;ù¨K# œf£·ÔâÙQ—Övý¶ÕG;+•r€¹€g¯»`C§1/º°únN.ÍälGeãHÛ[7pS×iï2Ò^ ¥9Š$ˆ dØ[ 6Ü|þî€Á­áë›pî9ÞøèAjJxÓ»O¾yÞÒCryŒÐù{´”ÄX^†éûb4²eŒ*îÈñ‹¼|IC"·Ïz:N©ß'c×<¼lB€Ϙü$Àb­cx~Þµh–C€ôl¥5ŒCÚCPU™¾BÔ<{ çîù«pŸøÎÅ£ûp\¨!5°ÞøD.§ âÑe¸UŒ Gÿ®>efAüEë¿€÷Ê¡ë·6¤“©µ„¸I0_hÁÁ—ΦSÿîúrz÷âX‹¡ã£÷_Âs à§×Ÿahþa˜'ÚÞ„ÃŽ„÷ç$>X)$’nk°¨P@x‹ö’Š‚;æ…f\Þ=©T ÎS‹PŠJtCÒû†QÐàÀ ›¢$ãßÖ¥¦Ä*ù¦CÝ3—c•î8WžùpDîsšS¶7ÈGQé„/nsÊsÌð?KÜBî½,|Â9 „Ê&„žd’ð\r3{¯-ûs¸ó6Þ™êËéúßÎ#;Míë¿À@Hc¥H%‹MUmY½Äœ•EkÇ"œ0£Fm›eEçá$=W½KÔUž´¤} N2efÎZXTZÀA†~™eœ¼jìÒºiD컋,ÕÛNÒ†êã¶·¼½Ð´Æ*a6”§åÕ4rúg?¿<*Ó{m Å$·ù ÞA¥‚Á+ø÷g¯ÿñ¯¨2Î(`2Û¡†„©(¨¾úY6ž•Ú ±VuʪõOà'¸Î%Vwx'5úýýÄ ~Oqh Upø»È;!AÓ@bÆÇËøxUôNÁú]áªWä‰ñ5Ó!ÿgý­Up‰úÙxüD)q»{ôTØ{þtZ:“ŸœÍ¦Ú&†»ªP®+ÙMRWBFɸeœü¬—TˆÆ; h:[êò§y {)’Û¢Wb·âK‘àÁý€ã,­!(>PQ=DN>DÆz¨åâ¡«}¤§ê½)SNÍ^DÝŽÇf?×ÒÑãHð\¡(šžèûꛈQ„ßÉ­ÞÙBg£Y1ßoÞÐ/KKõdo½‰ouÃ¥-˜33…É‘“å:2÷d°F&4l*åæ}}œ^* m€øåM1°ÕÄëIŽ$ÂÈ`“ŒOl¸Ž‡iýÎÛð¹zÃüÛ°üb¡pGß6B:íSŸû=ž3‹EmM4eÌ '‡ÔÁÇÇ}¯z^1SÅeä,2×/îu‘~gœ‘ßÈì8¢0^žsûCŒyHwèÕ”4 †P3¼GªŠõÖ°H!úóNª˜qÚÎ*£\ÎÅÇçy½KÐWˆ;$Nº@Ø*%6–ôqôáÜea˜ec°[jµ±òà}ï»àGÉŸô] £äàÞ7²"Aï3þp¯œ*²Ÿa ÒÂÆÏáúub½«Wqªd˜ÐjåÖ¬"Îà´3 Ô'd„ˆƒ'&нÊD6g¦“–WrKF­·ÙÀ:=è‰â—’ˆûº*#cCK%…Œ.£¹õ¢aäeéäÖŸ'†BeÊÖN’ÞFóàö” PC"þ)¨)=(›Tu…W|!5²œ]µ$ÒHB¤ãº›“ ~YéS­jpøH­„¸ÆL!fНŸS–4#2Aâ ’Ri!Ym«#F¾†™*H’¯\µMÇDc’`®Ë ?ûæbýçó棚ÍÅ}}RO†ª¨¬8šrîz #T¼j Œ÷ޝ7±/gUŠs£]3&%#õú·\ŽSúGÄsÌs4vêdCjÀt«£ AÑL²×mø*T<ÿL–/&³”°dòå$¬Ó¶„¥²Ï¦T)7ørÞNše6dA÷p=Ra”ç¹øâŽTIPUVm1&Ý€$¡¦k~Ó²NUñÄ8÷‹:RzCGJqSòÞ¹‚Kx ¤A1!Ê&_„bûÈm=ÌmFÝãߚΠI§DäøÁ«=”…¼°–.ŒÎXväië‹7u)N8£>¥Lçã¨ÉD»¸ª…5ÔõùÌSQbþšRàÄ–õyR¤ò:<ž+¬Ž³lýp,‘rÈÅäð Á}ý¦_“€$u‘‡¼X2æ? ‹^b2Ï.2ÙŸ¼JÈ~,|Ùõ$I«B°=‡#R)TfKMŸyw«+ÍÃÇŸ*°­–ˆ°.ôí9àVé„“3q&òœôŒFâþ!™ÕáÂ&‘-Jаi6{ŠýÞ8!3Æ©Àtè“Õá·¡7³a²Ý-é2-é×&9âΖ[V6둼©/BpúK7™¨dµNèýû08ÕáÅÞŽù‰„à+ë%YðKÉV:Ú?|2 ÝêútY] 'òòת¾Í†Ën ÍKamâz¤hc:ÖÓ5ž7h Ʋ4–ka²=ä¶ Ù¸4Š(8)æšJG²˜Mƒ³RšEMcY-WÆÄ0ÒqMÀfõ¸càeE&ivÌH0Ãö`!3ù(!QX ÂYÎÔ®G´ EüÙxó59&mÔ'•tšcÓwLÙ|gŽíÝ‚Éň¹ä°qÄüê¢Gæ…§ªzqÒYOZó㌋ ¯£&]Ôº$HÊ‚Š«Ü4[ò,çl!~é @œ)M$ÈpýÌÌðá‡Bn®ÓËøNháˆy¯AW˜íè%è€JíÇm‘eàäÓ|³bEŠ2«1'f³2fS=Õ§Òí3x+ôef×!ŠȺ\ÒÕ亖"gI-)D¥ãvKMÑ{Yå¤êø+ë„Ó˜ ÁY‘Krw×õ4&“Þ ëI(Ì7œë K ?£»ÒUîùØ&ñâ}@Ç\ÇÅ>|ª–žÒr ƒi¥`²\/È›­;äŠ4XË`†ÆÊ™'™¤â$´>_- ½~Ì…GDZÓz[Õp¨Ö„è§ßTÅZµ½Q‹i#ij'0‡c.^ijŸª*€Ô¾eÜO0-ŽÍF׸ËSRV Œ\OsÕŠîm-ÍWEÜ…f0ø¸ùÕî£æÈ'˜R…Â23.‰¼*·â \½ÆHµd¦6/*Ehþ—¬êQ_Gà6•n~ðŽ.ÝMºv0+Ý|1`i«2)FÔóRW°–¶bÎñÙX¢T¸[¥\ÔÝifâæqt‘¦Xxˆã–;xvܰ”Ã6Kî휋öaCÐí4Õ3|}9öw!‘åÐÅB Î’8ßÎk¨Ç¥«AðÀÉ_Õ÷4ÇzB±Ÿx”[¤pîñ’Fªô¹œžŸ­ ¼ŽÊÊdY«™ÚÀééˆHö¾›ðb]û{_©ú®Ã¥ka²€^1íàúXnä}Øf.Î$DÚTž£–wP‹Þ@oÿßl¡~W¾Î÷df+òŠƒzºÿ't4jj› Heì®¶¹às‘+ÓÍI$, ·’½†R1C>àÓ—8À wï°Ùp%»©Æ{hgÀM‹]'±iqnKqÏqe—ÔM¼;Õ: ïn®éz‡vŠ÷nQ÷ô½âÒ}ŸG{Eç,ç07ï{& nq‰ RÂÖ7 ÌuT°Á`ö>yGOÇîÇPî!–Èóa6‹¬Ït‚Ÿí$Ü6aýĸ{é'-J‘žº¨C¶³iÏæATøÑÔ~h!%ùŽ;çâü(ìŸüû‡‰`¤ÃмëJˆ©á2ý\~A¾³¹öWÙæh½œe‹S´‹ß|þ‰Óóß$Ÿ¤n¤‘S÷@\aÙ¦‹dprS'2 ¦R”õ·T#oŒïÝMž Kawo¨–Â6øú K˜+³âKªø ÛoK_R1£Æ®ã~¸› á¬MbòÇ-Õ車’½ËîÛ†I næ–i/Ã÷{ùÁ©ß6YÔä2E‹ñ™ÖèËñ _ëDgCm:tïOÝ¥7å_,näÊ£ÑW’nîË• àä鲈óa ™vE˜ ÿ§G‘° §¹»¡ˆ¹Úòtª†¢ñSX!ÖÌŸëÓl¡Ï¯-fŽÝp&sà†Ê]ªe>IŠ/gHš^”9˜ÝUËî9ˆÉ5 ãá6£$¼zSæ•Å|Ñ`88O;vP²0C«!Á툦6$IB–ߦÁ×nŠDòåÒ¸„q´qYȤwûæˆò9¢ˆè½rDðø±x˜[ªšNðø_IÛ’þî#2CúLíÞPôn5iCú¸Ýƒ‘óR¯?÷”‘å6âºA7\AŸÓnºÌû3 Sw’_×ȸf 9z´^-PMìÒ¾LÓÀÿžir%Äž¹ÎêÛ*§Æ%`Ô&žxKK˜¿Ûgʈ<ª ¨‰N¼ÐX2vãmŒ@dÞhp¾MW/™h÷›a¢žïÞ·ˆËÈD=—'×r#á>¡ò×c †ì/¢ºÎzF3`×=5è›ÛL¯“¾UäÜ›">ò.ĊÛÍ ±§²ŽÖÓÍ”E»¹g9S=g5”‰³JÀ%Òl,BËÆb‰€‹2ï¼M(a#‘qÜ™˜<æÅa:ü©œ3?Åܦã¯R]¦ 0·í?qùµ)Îãýá®_áb/;åKúpêsÚÂôs(ø-'dÜ7ûXº:h·w%ÆŸ ÃpùYêÎZƒã!íöbõ`›QSn}¿™ÈÆÈw‡qÈ!‚Õ1$%´Ó7Zb`¹6‡×ØÐŸ¾ô1Ö¨ÉÏ™lÑÅà†½‰É²GÅKMÎÓæ~1­ªÒ[ w¿©ÍU5€ uoãÏ é >Âd"œæíÕ@ }#{q*+l ã*ÜvÖs<”l’*5|ÏyO D; 1Ø ÙíSbi Wbaö@,Ë~è1±µ°X²¾€D†e—ÕG}3ð5÷çÂ$.ÌÝ–f^{`f&aãÞ’}g^4ak54Z2fjûJØj8}ÙjJØÄ䫊É1#Þ./G¥ÖÄx©rãcq³¶û%1TMìÖÂPå~©¡‡iŒ`æÌº‰±ù!¬ûÛ-¼;_2˯ÊT˜ïvÁr-ÚY®Ý÷–€õŠùÀãÃh_;Ü-¯àù@Qt4X/ÔUˆÝûj¢èë*E:ÙK5€Å´ê´[àmø]ZpøÄï'7]2•›žEÞ¼„ãªAHn7EÝñäÛîðž‘oJ˜clÄ…vD£}Lâ'þGoø3mömP“ó_ÜG“?„sÏ•«yq¾ WcàVVæ\€¹¨oäà7žxà0iÕh¼7cQ}ˆ¶âv4½·ñ£-Á+€K2ÿê¹¼ˆC%ú»²ÇåúÁ\ß­‚ Ý<Ô v ê9â–JAÄð}eOƒè¥ ‚‡÷Ò= €JA;EsŸ›Êt %ŠÐeæ~`"ËösŠDÍ‚B*ø?—ÕUɸ¾Dɶ[H÷€ÜŒ‘Lãã&{Ûh7X-?\‰qúŪI‰D‹ßV~â’ïû%Û}©…íS)Ú~˜„hÎ5ªžhñaŸ@ØV0á@}&IÍü>í˼áÃø÷áš” üV`äÀÜ4¨,T<¢Ùûfþ öœõöÊû 0á뻀y‹rGË}¹cÍõœ½G!awØÌdoTßGø„q³ëïì½aªø-m¤la¯ßHYÀãÀ}4”,UωáûæèˆÕó‚ìöJÒ ªça9l¤l`qØH9åt%¾üMŠúÛ~U»xf2w/wo¨–¹{Ù7šIãߨu?$|hê¶êô¥û1s'&Ç-•÷e$íØ¡«òêì>Æ¡Y×´Ûö•tí°ßBø ¼ÊŒ>l##Ç÷ô5þñ[ì ’’çBÊ|*iþ*¿6[II¦E¯ ³h¨Ž¦%X¾¯h€|/*ì¹h€ /v„> stream xœí\Y·ò8¿b —ìžo6ƒÄŠDAâØñ~° go­µ‡´‡l!ÊO‘M²ŠGïÎHk[ ÃÞ"YÇW9~µd_2ÿOü{p¾xüOaØòäzÁ–†O¯< YÆ?çË'»0Lµ´ƒ³Œóåîñ‚ £ž†-ÄÈøÒr60µÜ=_|½s¾ZC«rFïìáçáS3­w¾ZG«w®±õ¨Ûz­§Øz‰ŸÅ4eG»ÛùÃjm˜´;Ç2+°Uaëºn:R¶’?YÝê§}³û×…”uÆ-wÿ¶ØýívL:ÄÖSlÝÃÖ3l%œ9)¸¨åh>Ø5PØÚž»b ž°=·ÿôç®{„Ÿ7Hóy÷‡…h-°¯<À£._.°õuWynp«Dçaë[ü$­ø¹×¬V 8Âϳ-–Ø«‰…i/ºc aì>¶¾én§¡Pïìª;í¤á¤o½ÆÏ†©„Xçðʃ`’¶^®¼ºH®c=Dí–¼Dd…S:+–HÐ9ð³g…f®€–Ôr¹Û§%ߢ¦Æ^uê¸níœZ7°Ñ͈œàÛ-¶îwy|Ðl§bÆ~Wäý=… ¿»zÙ—ó½K|WK¬V¥‹î´¾’÷§w—¸×æÎ»h@¸~ÝåÃIÐV²Aò1ikßε‹“6Q;fäP9Ok„o6ãf-ò«îQ ®½è16Š3%µ³v:Ô6^î[‰vÇž5vCÖË1ì'^Î`«ÆV­Ä¥ã€Ž?»÷Xغ×=qß6r­Üà·Ýi% „³ã‡Å‚>v¾ÂÖÛîYHxƒ>ëòó¼»Ä&ì ðìÆ‰_Ä«K ÑùG¬ypÑ Šî#»¼ã0=y¹ÑĊt˜×µÙÖñùÿ=rtÓ=ìAwÀ‡\ 9†qó.IØ6ܨŽõ¡rÃ'öÂÎHð!±ç1«·b©Í881%ôÿX­Ù`ƒ‰>ZÐÃ8:'á< ¦*Ǩ½ÿÔZpÏà˜VáR VZ8šƒš{îòÁÍ ¥u†ö¦ÖÑ«ˆý{õ²ah³l@¦]¯ä µS*WÑãÒ:†fÇVø3ûp¨)5ä4|Á4 è¿Ôè·™¾ösïYn;Ê_‡©wÚ‚èsœóq— £AF¦¹âƒ“œ©§€àÌÓrçsਇ m}TNù¦9;0où|î 8¡¤ó ­Õ`x!Ô«i1HÍŽAÕ+ÜËen<À‘q’̼…˜¾ 36)ç“gSzàJ¥ùr’³ÿ4r Ú3 àðyM\Ê›˜…5]êÉîaë>¶õ"ÓqÀc@Z ·ð4›®àÏàC7e z0©­d–ûjÇ]ì¼Í_'HßWH4èwÀ®)õð2M™a,ªÀ¯³ B·½ÅÉ™È>[«&ôÐ;Ãj- Ѐã=YŒ²*ä^nÂRV¦¯ì`¡ÛQißvYé!ÓHŸ55ûç3‚±Rª2˜wå „ìm±/aÌÊ[Ó5¨X÷¶Ð^8·vl¤ÊWJ>¶Æœ/HkÍù0Zg©Ð‚Ù¯¸á*ûEûæ*ªÎÄÎWÀ\ÀY£“êø)Ä>ƒ·€zlJc…c‰ßÃÖɱngìgƒG.ý.KæÂ óªE"EĈXp†#£öýùC‹)j\]=K:;c¦G~£ÌØQ,%FóC!íOw_,^-åTD‡ñãRJ-µ–šs_ òÕ÷'OŸþ}ysu{´xüÕ’/ÿÅÿçÉç„?O?YþjñéÓå³5ùG"%h¾ñë *ú1d#ÑOlDѵî´dØuJ`š"ý/±¿ñÌ©ÈåR Q"eB5~%f™*÷Zámðvçû´Œ¦Œ£ÒÁx«Ìš¸!¹  OC-cRz?‹,ŒøZm!R¥[8¥ FM˜0@H:ƒoH8V,} 0"&!ž· €’nÑ÷R‰¶‰¯OBx%õ¦–²`5]¥k/‡P?¤ÀiÆ8ÆÐÀ|Cšß3÷µè±Øòuá•1!~aÄx™Û.ªq›Å„JBN‹ï‚¶  \v¤Ø^¹-i!;6ùRÀ'0I4§Öè /¶O%K{‡sQbЪ‡Ž~DGºK«OÉ,Ä9•ʦþ4«ˆ Óf¯¦ùà—wŽc¨iÄÃb!0E±—QDT @i>ÒQbéz®ZEiŸwF!6D„Z’ˆ°¿ÔÍlÆU‡è3ýQÛ¤Ö.) hú½J6héÊÆ‚Á$:ðÝw—”ÃÒQ ¼‡4%KXM­óI/FÎtÛièG8jm'ìžÄ“±-ô2ÆöRÍZ˜¿©‚À1*1¥&VrÉ÷q>ïÛJ™Cãažª÷dÂG-Ѝ囍«îþPè§1v)Îí}ÖNl”„µGøÏF-.ÒŸ315ø|BⲕãÉšô^'Z3ÙÞ|¦A¦ ®t™Ÿ¦±æÓWm«ÿ %ÞÈÃ ë½æû{xH+!›ûI<<ÙòaLJc­+<—¹÷¤õÿ›øuˆûì6ŽÝç£L?´cYn“RÏnÇÁ>_×v@ÜÙÞÒ}ij¿:â±¶›?öý&Î?¡ö‹²µ‡i÷Örvcû˜Éìv¸4¹ö` oUáÜî½â™ÚoùrƒP$ޱàgbqrAZS©“´ˆ$KÝ*ÈL«÷‘Æ‚äçóŸ‰i‚n›à^‰@%(kkÉZoJ ùus3aß”i8š´õrH¿ƒ8í¸W±NqØü¥¨>cÅMÄ=ÅCr~,]tç€jwXŸäéJ¤¬O•—˜LËHòÔ¤Y±J¨pÔL°%沿ÓVÍÔƒ:(amåY:ˆÛ¯g—xÐVÓÝØÎtƒ?6îBŠqï4TFëÙu¯בÁkˆ¸œvñÑÓ—¨ðoŠrväãMÓi(^!Þ4ì`²6R˜)¸>̬ ÷M;ÿ… ü}î~Ù©ïôÈ| d¤¼ž~A²5k#kÐô1ΛhIñ±mÈã‡xO 0g|3µ)€¤ÿƶ;ï}#j”XîúA“ÜÛQœôê_ç66»Ámì$61š´÷’šÎÝ,O6¤mš@¥ßXî5©‰§a5+ït@¯æ ÝÏ«ˆ+h+2žÅ¿ó Æ®Ý|h~gö_u ëâöº.Ž,Eª^M˜>]íe_Ô÷P~ÀUD|¥R@œÛ*=ð9?Ä#ÿÎc“|D! Жqþ8¢+K=0éF•ÿ™ß¼/ÎSïÙ…L&Ê'[n#1cûä\(`~›c)-éyÇâ‰mžè 1ú4~ã L­|à â/𼮊Á¤‚ EªÍb0)Žœž‰aºaÀeí—}£ß€iÚT‘Èbèl™IéËÝãld&‡¬NÎÆfRêxþ£Äfc¼‰—õlWåyÖ³•ç†ÿmŒãT÷2CÖõ‹•d0Gø'vmhÕǂң„1­G +qQY‚´"ŸBœ&Ç­ƒ¯¸ž,V“ýÕÈ¥ÓjióÀJNUä‚Héó“7µ¢„LÜSÓb€ì¡ ¦Kj±yÊn÷sšºŸÿÛ|‘ØØm²Ö¾?»ZùpÙò¥[yHL’JyƒTý–„“!uiàm^€–ì+­Ëm¡Š¶PÅ´n¿sÜmŽf•Æ£™b‰±»š‰Þ÷«{:(Ü\’!1ƒ®'žÙ‹ëî/^ökîþ(˜+¸2Î]2ؾ•³vUA¾ëÕäȹòý¼![ÂH*–°TH“‰li$•© b"ÜÁG¬µùu›bˆ9óopÔܲ²»,‰/ˆ;é›9å›{O©î@(Ô²ÈÕ}9DâL¢¨/ŠjTÀ %¶€!X‘jîÚ™P(ª á9Ÿc¿Jlsˆ­¼wªíÕ†™!ìÀÈÒ¬ÒªjŒ… ÍÈ Œm¢ªFZ›è¾OLO;fó§ú±Êô€ÑûWTôš¢²ÛÀÚêj½SEø`/¢ÁgÅWzü½?‹ÿ•߯±T­ý‡è0“<°¢ÕºrÏdG½%yôGFvè¼ætÅm@–âÜŬEaµ–]}{í2Žá`ÿ"lD€ŽÕèÀïì°«}y6"K0s”ž%èÞ3$jkcñìØ³€BŒÄË’ÇEÝŠõe!uݲÿ<·MtÊ„#Õ”¦gý?zU NŒKÜM7xçwA›'SS]G _µEœX#²¶!l-V†j²ÖFªð±®®,CE1~\W•“PdZPm°FË^­ÒO%Þý€õ^|ïiçÑÔß„…lW¤_=¨ðÌ îñ¨Ýö󲀆ïí¡éí;³pm ™Ø».½Nx]\1?ï!æÐïËâð”Ößb;ʺG¥èñ4½nûnÊãÂÇ£Ü÷¶l²þ-SêÛKMmßQÉŠ9šþg£Ê„ ©!ñ"ôr É‹¿Í½°w?õ¾!Ëo8÷ªõ övM'÷æ3^•â6üêÝ!n þÒìMéî{ypµÁ^6 ¾.¹é§={F < Š­"¸·­ ªs[*7²»ºSv knSÓ~ÛwÐÐDýÛǽd}¸[jy%,boÖ¥r¤ õá»Ö¼O±÷¢Ç–ràEÖ‡ãF¦TWjžžç¾£’•á#õåsN?J—L‚;Ìÿ …£<.“-U%ÏADGM.šmß¾šSØ_Åä‚f¾ýȪ€ïl²š¼hæmpƒáäÏ|}¡üµ³Õ?NlPƒ¹Ÿñº•F¡ôáî [÷ZÉæ>DÀ³<±ËS§›ÞtÕ…ÖÚB:1 Ÿ|ñ•Õïe;¾‚Ëâp™ex“Àñýcœ_õЂ"à™Fµà‰—€ç%Çh7Qâ!ýj¢‹ÌSØ)Ü6W{*”HÜ/w{¿Üíýw{ùÙÄZºih· cèbámí‹ÿ0Mtendstream endobj 1144 0 obj 3930 endobj 1148 0 obj <> stream xœí\Ys#·Nù‘¿‚dÊœÅ}”ä!N¹dÝ+­´YÛå_‘üàtc€AcCr,Šk»T.[0ˆiôîþÐÀÌíœ5|ÎðŸø÷èjöâKaØüìíŒÍÿÿžÍng< ™Ç?GWó—0L5÷7þœÎXãt;lî t31·œ5 ~¼šýsqµT“Z«ÅahÁc‹÷¡¥ÿ×ÁŸg¿?˜}1»Ëv’ü2ç\˜Æ8¤£æ»—¯g/^ÿe~÷p2{ñ9Ÿ½øþçåçŸÀŸ×¯æ¿™ýþõü‹ŸÀ3ç:NÕ±üØ[Üu,_lbYrÙ¸=±,U£K-_v,Ÿt,_S–ѺœÒãüØ7ž5¦%u°\ÉFxeÝâ|¹Ò ”÷ägð¬Ö‚/Þ.WÂéF3 MÙhí•Z¼ÉCO–+Þ#¡yÔ657”ÀGKÞxá C‘ª•rjqŸ‡žd…u…÷B Kª£ÿ>Œô`N:û@¯0  f_.Q—†{ÊËmÚ>åœ-yE±À*0eôÿ¶\±Æ2æ 'T_Ã/)t+¶äL%RF:0\Çë1êU4žÛvÃŒ²HfùâûÌ!Ѐ„\€Þ$Î¥˜UËÅ)Òâd"j3P8§Â0¹•Ó4€+IÙXkçàVËDUO¹¸ _§ †ƒ¨QYx Ë³Ìß]Z{æ(±ÃÜ$ˉ ¸k×€Ðn¸Þ]Bá:YFŒŒí1Ö±‹V”ðùýûL–pó18S ©œ7΀Š_Eͯ¸huOVÿå@FìmUc˜ÌÆ5^= ¥þ‹®û«¿¤J*{3UX§8B-^áò0¥¦kîtik‰[c'ñZ"#Šc@]œSéÖu ºZ%Xê7ѶÒ/D'­Î³š®3I mŠ‘Öè*H*/”à2ÏuI§…¸Ë6‹ÿg!Ú@°ô­L G¿&t³mÎJ48œW Îà­ ×bòÖ›î™nùóz€è©5¬òø›<%±üE¡Ö4à:I2æ',šì¶J1")>PЃ¦ä#«ÐJ°4„3‹ÿfÓ³<àÉJ‚f‡zè¸Î³!¿†7Jâ–ð˜€Ø+ÁHï–¦áE/ƒLŒM­·ÆøiÜý‚²”’ºMì›ñ˜Qx{<:4»êÀMf9žËÈ,,‡ý0/}Ÿù8‚GGæÇÕ,,½0ª“˜‚ÑGCHa§@H©4À#È@T™q)5þ *)LÄRÂöIŠÅ'ÄÙöW¬´ö iYðé­@"8/dމÑpÛÙLjR# =Š¥t(ùn$Õ³`»„"¹ö)1m¶LGÁÌZìJÅA¶­@ „øÍ¥Ý ¶ B€ÒÀãi~ªD€°F¹5[!À NÏ·¨R`":ï–`‰^gQêô *ÖW F:lWÚ:,ÌÄ'cAˆ×ÂÆ$,¸á°UžæÈ}àky[à§½Ù ð:û~”å» $¹íú*¿¾íúî»Ögݯ‡]ßÕðÙ1XÈœlO*°è <”iH(V|ðÂ^Ø•ó5…½X‹ÚiiÄÊAe cÑC+‹Ú^È©\àH|%ž[Œ°¥d[Uî‚°f¤0G¢:Îï 3=RäxSc«Ä­ŽDàÓX„í|Á@ë4 dm½5ƒ¿¯jàô6Öê¬í¾.•¥l)$ Ü¥åšJŠR#ÐnP¡$†„½=­¾uuMÃõzSòA¡Ì[ ·#ÌY‚Ò»š@ÝGˆ7` …DcF å=¾…n$£­!E²Ä>ÆL¹þ¼!uO­;B\wr€'0JŸÐ¦+àÙlövá$Õ1Q ``o¹úU^M¬;¢8FŽˆ3Š6asìœì£MÔ'0–Ñ&+^#KŒU €öœº*„{µÅöl+°É”+7l"úO³n _‚7¬²7¯UÐqÑÒÇ×AÌÐìÕQ‚:QÕÆZu<=!¾Œá¨uõh¶°á²Þ¶Ö"Oô¡¡Æ}L¦yÚÛ"OÅ#ð”Ù£7¶ÀSî­à¨a>ÀJÇXQûÁ„åÓÊðÍ;n(8î…ù¶àH™4dăl52Âx¡v]É Tµ_1ÜX½ÈÈ!¹¥èÎ]mËŒà’ù€ó¶9ÌÅ,íÅÄB]Šù½Ã\ŒSÖÖ1#ÑÆnQt€> @ ÔBF‡Œ˜ˆê{«³X` ÅX;‹m£ûV‰—‘‘Ëp=ôSN;± ×ÂSÍEe­ÖŸq}öà–µ`3˜«C›û*À…¸@&è p…»œM'Ó¹Y©À­;ŒÅò—°;EX•òþVà"Äœ|»uÝ U¯Ë²[[ìs¸{O>>HH€’<ò ¡ª*å7må7€ÃÍ®Á‡÷€‚ǹ€v³©D† jO| §jvtõM1 4`v}r kÓ²5xGÂZ¯ÚÑÉ%3 Óäu€+¸ ¡BBÖã\nu‰CS™pkh~Þ°ò\Ï 9 d®F¡Mü±¼öŽQß\“úÃØ¥=¸„ñŒn½éY"Ê¢FÂy™.$÷á®ÜVg‰Ù©(âc¸ÞÖ;LDuL>Jð?ʰõ`L4Byrù fžÁÌ3˜y20c`Fò½™Ìñ»$\ O7\éß Çí•~Âñ£a „F?åJ8ߨ5¬ÙóÉ äüïKíaZUćÃ88Ú6¨VáfêM|Œ.zÅ›pÞ¶ñ"þ×’‰ÆBØÙ¦bS\šïÂb0­Ã:-ªéBâVÕ¼£ëGîõª&È’«ÛZµ&ž±íââ|šwj¹Æ¹†y×G: ,ãýA:üP­áy2–›ùXKåΔGa=þ¬¯NÅT>Šu0ýN»8õTH§».•ñMòå 1Á@KßnjÝõ@G:DÚG:@Ç#~ØÒ¡, ë68ªNèhøëèu˜OíI4K«í±˜H6 =Íõ•žxéú‰î¨Ñ¥ˆˆŸÑ{@ /Àñ­Ð^”VS¾ J4Ü›~}(ÜÏ?úÞQß„éŠ:¬¢7Ô£¬OyE==ÇjEû¾£Ž§ÛÞŒLûwÔÁÏWÔŸ¯¨o´ž¯¨ÿrÊJÛv‚¶„ßÚ",o‹¶*€e{´µÑ"Ú"¢=má÷)Ü„ ¾lÜ®+PøÒ®ªäîe ŽÞQJÛbåÅÄcê·Véïmð‡”p¹aèY5²ÇvŠðà­¾ñ=süÊI"šåhZËDžÂsy¦ήžúÅìÿ®¸®endstream endobj 1149 0 obj 3763 endobj 1153 0 obj <> stream xœí][s%·qNå‘¿â<’.q„ûÅo‘¥8ë’/RûÁN¹¨ÝÅ÷¾ki+åÿ440sÎÌž!w•”KÞ)p¦§èþú‚FŸW;6ðƒÿ¥?;ûü[aØîæÍÛý6üwsöêŒÇ[véŸÇÏv_\…Û´Q;;xË8ß]}ƧÇÛv^ Â1¾³œ Lí®žýõüåÅeUÞèó×åòi¼ÔLë|ƒ³ù†8ú¢Œ>.£OËè›2ú†|,ÓÎ Ö|Ãm¹áå4úßW¿;óƒ²ÞøÝÕ×gW¿ú4Ø>ÿuº×»ógeôºÜûsý;ÉÃ>ÎâèmˤRŸ?/—á^müÀ¬:×e”µ—‘Øl´¹„uø¥OþcòÅÏËèÛ2z]F—ùz[.Ý»2ú´Z¨¸:ZâÕáåR Ÿ8Üp]..÷þ½âÅof³£·å²/Miäaiy&`‘–®ž¸¡Eì³BöÉ.šôHŸ<þOº4Õ§¡ïùÇL“š <¦-ôùßþV)Â%w|pRï.49ÆÜøH~¬!ùy\F‘ÆÜeNÕ\ªâ½?ŽŒ(çÏ¿+콯8œÍ:×Ìá ù­ozŸÝêœçx¾_’k³D~þYfö3r™nZ ñˆ.ý™s]nÔ䎼¤û¤€ØyNòPèFI ߯¹5¤|j(ú²GŒ@Æ´ÎŽƒ ŽË£´ . +Ï<ðç½l —ž…îâ Z ÕO†·I_470où±çãeò-ƒ7-Ùxùú‚ëA;/ðkß–wÝ–Ëù ÂeþüCÙ:mÝ`>±lÝçß «èeÝie(ßóÕ„á#‚û‚$#F¶òÂ<¿àa­˜‚y½Tƒ0L†×ËAÆò{jñj†‰œ&¼º¸Ì×Òƒ¸æ5€W"P‰lg1y_¡½ñ˜…—“@Œ7<Àñ‹iIz(ò¨½R™[c± ÀÊ>0˱<•‡%ƒÀÚà]›óß‚øïMP¢GÓt¥Zf4™–*—`¤l û¶’H¡Æ¨}×Ó Îi¥È"¾pc Ì–y[³ð]JÃ2†Q!%4O +ËÉI <ç35΀â|iòJk «üÕÕÙ7g¯vJˆ 9QÇnç÷ÓÌ1ø÷ñ³³/}þè÷»·¯ß==ûü/;~öùÀÿ}ñ§ß„}¹û—³¯íNM*<épÁ0•@ÇÂì-¡ÓIæ 9‹|*ï1jÒFUáLeÙ€õür§8žFÌ0Bì>8ÅÇ_"ynu' ҭד¼â¨„Ǫù¶ ÎQ7ü½]j4·l”€ÅóÐ&åµ…©}(R„\:`T6\e·ñ âŒd²øÁ¹Ï2¸=wIwH!Á‚·­8†¤Æj°°:2¦xÔà…6K.}AY÷áV8Ž íëÊÖˆÀ¦Ý0ŒØhò ROXz].YXüaâài|’9àø)ÆO&ÂW¤òvqõ²͆•¹4/qôq¹·²wÙ´–3“â.L2÷)BTÑcØ«Ë0ySþüŽþ–”*žƒR˜À =Úq>òÛàÅÈÉE ަ\_Óuç?%GÚ™ÊK½Ã—ãÍÂ@`•™ÈË/ –4ôôfÄÚ[’µ'#]Ãt¶öa­Áó ˆèbª“üЇ"EÁ³€ºx¶jòÀÅñð¼9w žwßNñÂÙW“º¾«Ðyî}çpOŸÿr6 ÑGà<Û!€G«`Ê?Ø!¿cÏû[¥ñI¹äݶ¹ˆ{z!™v‚æÑM÷‰kÃ=þû+ ÄH8…©Ðûœç"©¡ú(9ïÖ´Ðjø x• K÷’ôäß_èˆ gd3Š6)ͻ⼛c`4¢s@o&tž–[)4'„·¡¡}8ˆ[®f]\²Á¡9‘3»†q–é…žì:ˆ3bà)ÐÇCÜæÜ%ˆCÜ¥ìÒ)ЇÅ@ƒð+ c\¡TAíxˆ`9ëx’×$ÆuN˜ å“B5¯*.ÝsêÏOJþƒ†’òÔ ‰e?$5’×ÚEét>'š•· àø0íˆÌBÛæ=t҄ĘårÞH žÈ#[CŠÂ˜`ðîÅR`×F-VÇcÌæÜ%ŒAÜE/Ã3£ˆ)yÖ¤‚öü70 ÀôŽ .'çhžŽT³%yTóxYr÷p^ Æ>ÄwÀ8eF„½1û!×a¡V/—¬®*‚…z@R”V+íïÅsvHÉ!}¼RoÎ\RêÂÜA¿áš¬Âc̵šãŸG/˜ùj²c÷>>¿È;~r¿ ’õ[ùÓ«zþÀ˜·à®'Ïa†,ä®âKù ¤òç U0DJ½0Q³Cì‚zjö‚07ÈæÜ%AÜõQÄ„™—~¾+yLôQö[š4¯]û1̶nÀ;3˜Ê/|×ênÞh 1 ÷°½ÈÝ “k_¥Eàõ†óó߃>HÉ”«’!e-L‹p,Üb³Ë`£ÔY…BéÏtÆ!NÉh—+„åE5LW©e@a+e"ôŽ3)§ÇEaä²0‚’8Àí1j`ÏT‚ð­á 3†<ß gp¥Y[mÌÑ»¿ió9°zCÒJ‹.нÑfó" ˜OËPΗ7¨Z^ßä~ÕT.6~ÿ%Dê0ó{»×?zž®5Y¬¯I»ÎÀŽÊkÃDãÊ« UÀä.8Õ#ÖT;Ç=ì­Á¥wŠ,†–xw9=—Œ€ o( šŒÀr ê"7óæTŽäR”#É<ßv«;Ærå’=Þ‘Üœ¹d sÉ}Ipܢ锨ÐþzŽ&FH64ÕS“®ð¾#)Lòy!]°AÈ«âœÑãÿçº&þnSJ$Í6à4ÎmLˆ'©xž$sdŲ€{³]Ó.Ê‘Nír¥êôÁîžÆ©]EŠÀ3黢éÜ RðéŽ´í¹ s÷ï“ì‘5{ÏÆ.DZ>!èBv>ù/Ž™£ÓYeS¬©L*Ù¬ã%wÅìuÅÍ)"£¾Š%¹.ü{‰Ú€ì ŠQ6üñ’»9wIrw÷(¹ËÓ7©ïië>¦üÍòÌï Qíê¶úT¶r ) &,$ 7­¦ в“FX4E‹ñ¼ç‘€±9Ÿ 0£WŽCôîclHê‡0jÖ/+i]>O]3ìTõ`«HQÒª½Ý6‹7J«æƒ43i=¾Úv{>“´"F7‘Ö²N²æS±dQ¡°…%[.•]…VöT…T«HQØ BÈ·í¹ˆ ÒÏ€áø:Ïí™LÀ¹üó…öÐDa9ºNI&tÞÃSWV>¬=[>a]A“úT…9«HQ2+5Û6€eV˜é”#Ûãk÷¶ç3‰-btsÉ=½m‹Èü‰Ù¶_J”¶\B»Ê-$?•™\CŠÂ ¿iºdÄ ßÖâÄñõwÛó™p1ZJqÈ£æÈþÌsBç-Õ;§°ÊÂAQ]X{ØÎ{èïÐé¤|µß›OÕÙ@¡ËÝVŸ˜Ènm™+R/Éç÷ÌDdš§Á±-Ûͳmù8³5¡q~ °w˜ m]ߤJØ¡M,èḲ\¢»`lÆ©\™5¤(\álé6É*\aP0ÕãK·ç3á btA àFÀ³¾ð”Eþ(cïŒ-jEà YîÁ€ðNÈéYEŠ@”@gi—‡5ˆ"\ˆ æºýõ€Q¶çsDÌèAD9Ô6g^ÎÞ¤ˆ¾SO…n½¡€j zUÿ÷QÑ4þÿT]ò(•$@Y; !Ë,álAZš×½¿Cù°©"Tõ\õ)C"<]¾$ïE% ¢¯6LiÛ:eÍóªE‘ ÎDÏŸC–“0E±ÍQt†´¡Ô »–é ¯A%ô…7üÕû"ø|Rø&%ýé"v‡„Nc~Um?²å¦3šèÐxyæ.{ѸZ‹òJTC^w=)]<*lŒ­ÁÄ\žÚÉÞ'OÔÂÀÂÆ^pÀ­ä¢y*Î%õ–2wx¨Ä¿UÔÛÊ`õÐXz=Îé%‡²=ÆÇ©ý _¾%? iè¼|’¬d¾É`k‹5 éð>Q£¤éeÇY¯³®0üTUb«HQ>¶áK[¢¬²(±Ä̤_ž¸=ŸÉ¤ FÚ”äxwmJò5gç+ðñä®WíÐP™våu•ÚíÖEoF!Õ¸%½U@©0Õ³£<³†ÏÝ¢;æíP@•K¥wû]ós%Ía‘ÆÑ™¯Ç•‘ZÓOõnÈ#*×q¸»&Gó1SÅ£I‰õ1¥2ʈö;Ç.{zz¥€bn^›%@ÖUegûU—yQ½B§ºî÷)úsK{çht'¾\c»`§ü©ÊæV‘¢pS¹¥}VVá¦bÃ6¯ÝžÍ›…Ï“µA9æJtfŸSγBZɉÝÁsˆ·µ3 *¢E/h7¾¸Ž3/º³ÈíZµ°bm»Z!í©*ýV‘¢B]iî£Îä»Ðc>ª}É£ŠÍB9”d¾âÄÖùÛï©6doz·X26píÑóå!”Ð}wšÙ®‰R=®þ€ðáÏ(û„Ò4W%%ôU¹ÏÍ‹°j¾ÊZ‘M×ëf0Q“÷t2Èš^¶ŽoIÃxGÉåM¦Ë ™‰4t‡ìa3Ë,Âó󜗅óÛ¥Ï:d-dÚ²e”|ŠX æe²º.¡W­æ½—{mú›Y·ìCt0xÖFšŽ_ù|ʼ¥“8‹“߈ö3°Rt›¥S«á8œL–a:teðânˆô®*@ýbò5 ð—< Ê~G‰8µôös6xk—rte&§r¹+Óó¹5§:𱊑‚ tîãÀ޹™gHŽ?§´=Ÿ£C‰%ã¨61¿ƒÞj¬¼žÜ-”Ün¡ÝÊê碦nStMVU|ßå*EB%SdyõÔ·'nõ§]&™²”mÒB‘¿…z«–7!€>ÜîMk€â%Û+¤£«XFê°Å*R”Ž‹paó.æaßñ‡²¶ç3é(bôøšç^Ä7ÕŽið ùôB¤ãmÏgB$Äè¡ýÒ /þ:Y£QcÛXð‹渦Šg× èCbR§$ùÐe“MƒùLã99¸ïN(óª4«©[HG3HR¼l˜Òš_ 1Û&nÓŽ/=¨ØËEª«ÒŸê´Ä*R”bK§%8쉘™bþj{>“b#FQá6Ém²#´?<÷Zû^÷¾ÄïšUÁ¶j^2BS­Bƒß—Zû¯N¥A‡•xMïN”rûæbüe CüTVóË{Ý2)”£Ü«ÐËE©«…Â>()J¡…¹b@;ÓçãO?mÏfÒçÂçÁÃOôï~«ƒÝßDyWÙò|ù#ÞnÈòüìwºþÇçG›ªå“ÚG®”%Ù\ÝGÑ1gzªåE¢}|“çíùL¢=(Û{;ñ+…KšV#ñç<'ƒƒÞ[2¹u7sië:Û|ÊAöŠå™òtËÁ_Ò:mòß©ÌÍ«© ˜W¶4{¯%ÒÍ…)nÏó¦ožû@õg2¶BáÉiû¥ú]Ù´ ü©…vOrA€¼\-ºˆÂÄ’ê)«U”²Z±³yŸtÌ1À.X8ìï NNÁ.ÞÓB3qþrršÞR?–Ž%2Óœ„˜üõ¡艸»úúìêW÷J[eé§‹ñW‚&ïÊø,L«–ë5)P.®´ sx(T~5y,¢Ïïfou½Œ}¡Ô/逬Ü`X|_¢dú°RTGÌ6äâ¼èê}¢:.£6•˜±Áé$ipÄ-þç ¹OÍ×Þ¯ÛI ùz¸PxC¤Td©…ßÏð¢¦õ`¿ žIýzšàþMàKȹÀV ¼p3ï雳ÿ‹òÉ…endstream endobj 1154 0 obj 5479 endobj 1158 0 obj <> stream xœÝÙŽ$·-ÈcE{_Ül×–niíäÁ‰O;>ȃm,z®õœ;ÇÚø3üÁ!¥R‰R©ú˜ËF`ØSfIÅK$Åê÷Ó¶aÓÿéþîŸM^}Ëu;}{=i§ÿ„ßNÞO˜2íþìŸM?Û…aJË©kœæðw÷hÒ6V…a0Ð4­œÖâŸÝ³É÷³ë¹l¬–ÍÞù'˜5»ìaoú§³þía»éŸŽû·=ì >ý¸û¯ ãÓÝOvÿ²ù‚×ý۴̲XߦûýÓEÿ¶'"‘íÉa5ÎlKÓq… ËbÃùÛ«‡1ao_gwñ-"Gõ`TáS-]#;ÿg¾hÓ¶\ÚÙ‡¹n˜æJÅ Öh­˜’²áÊi7;·€O)Ž,]¨ÆºVIØq?ö`¾àœ7ÚJP˜æ¸Ò¢k8­".ÉžýyÎ'X+‡ËêVs\˜FH3%€KÝ“@ÈoöKZè]y=RNJ:¼?O³Þö…+LÇ©¦àäeEó‚¼éTÀ˜•¢áÌ6*GÚ±)1»íyä Zƒj là Ù ï/ƒpSÃ-ûYièyêù¤[mf¯û‘Hî‚q† œÂJ°g§»@Ù¨8ÚÁ8@D°!5ûž!ZЦN/ð•P±ŸD|Dh[=û®W´á¯á½bMÛRm *ò> .ñ†¼§‚½4°Oª‹W¸¼…ßtu„¦M%~~—œÅ§@‡åÜKK´b7ŸS¬EƲƒ„“¬y5誤š½DTðÜ2B>1±?¢ëDs–kÇ ÞI*W’u¶ ¸h¨A=4=EŒéÜZÂ%1€Ïw'ßLÞOE8§€N;@G#- Q U¸Ïv&¯v¾œÞ\ÝN^ýwÊ&¯¾Àÿ|öõßáÏÎ?¦š|¾3ýæÇžƒñKõôçfšü8€†ï®61fa¸÷i•mÃI¥üÄ7àBôtÁÀÚ{«úº—åë ÎnmSBÂÂî9l mž›-JØ“G5*tÒÁù__¤Ùé̹›+Ù昷à»·ù»[ƒ¹ '-¢¸¿ù´¶á±hüû¤æ#À3‚÷"ÁeXbL•¬3LÁ„ÜZVV¦,„œrO)9`ÀFøg DÂÑÀ)ñ´ìsm8D)Ég=Ée4±Þñª@v%[X ìQ*:¡ÝùB4ÜIcã„f›,|màêj)•±ë»*=òLý©½=w@BñY‘äIÅý¹Í´…%ÈB'>žL“õ.1ýç9äB U8ÐÎ+ƒß_Õ´FQÏѰoc':s†$‚R4L–~ÉCÁóí§±ÇÕhc?E&'0 ÂÖÚÙQrÜÉ1_!ZÙˆ ¯c%¾5%û¸œlôÒËGŽ÷=Q·Õõ}p„ Ž,uø‡åëùv¼úhIHÁo) œr<Úš•:g0j×Ô¤ §þi51 8ãžP°a]ýɇàAÕÈGö’Ḉ,vŽ„AôÅ4ÝÙyÉø iSPÞY Ùf5XÖÛe’VªL‹”{nÁKáìe΀ë \ɰ/«Î‚ -98Ê“:"@×è8pÃtµô'Ë@W±¤†Za!a yÄiZ?‰»ì9DDT×’ºÉt|ƒ¨ƒ¤K‡ˆ†p“;ìN;IfuNÍ¿“—*R/â¼";bIÓj6û¶;l!ÐêOÛ«./ÎU5‹î=÷ZuíÎ)„ƒN%`>’ñF‚{ßIüÄ,ÚhäýLÈ$Ý#îRî½l5¿s-©tˆ‘_&õÈL+ûïªGsÇgWH£Hæµ@:]*‹SU¼¾TžøZ½pU®±ÊÇœ×ö+¹Vlà^¼éorÑö UÇ»Õf‰4’¯¬‡Võs–l†øí‘ÖE†Š·Š,“hî)©"ñÅmõÈ^ö§lØ÷ÀIÔgpÜx¢-ÏÃþ®6¸©WÃÁ•^ ùl4õ™VÇmÖ§ÑI¿ª7Hk펜ðÕªiUÒÑQÏWR‘N⢒ j™O$ûHAE:¤nKåÓÁÅռƨ”£ÛKù½ãZk'ËqÝN{. ‚˜d½è]±d#‰$ÚAz-WSM&x ø_×{Šaý1+ú,âðWM§\ß…%ñRô®–·ÞdÇF”ã/•Ú›AdlP{ÃÂÍTjŽÅÒ®úTrÕ*L»ñQZãOü}“ g z˜ 7 zœ  z_§Ÿ&èY‚&èM‚'èE‚¼‹ôxš¼KÐë½\¨ÙßÒã'ýd¢ƒ0Ëi¯×´qÝÀ¸qeµÇþšNï«8Ž< œ9NCŽ#ü¶Ò®a‘.„ PQá%Tþ‘ Z¤±§ ú.=^×HD1=L6B9 ‰eò÷iÀ‹4í£*ôÇùBCÊw±/ªFtž?T÷uS²Î}‘ ¿¦GÝOËrµrÉéK,Kd~ÚIu샻— wUrJÊ®ªÓÞ¬gTCè´«à¡1 a&zèœé0dJôõ²ê@ÞUÇÁ_W7üÙ/88åø aN Ø*aêUUתЫ*†º¸ •·U’û”©5YìU°VÜ·%¯‰›ðc‰NÖe¼v‰ŸªÒXìZ_1í¨ºÄZÔ(9´ˆÞ­–x%–ò“ÊÎ ç§€Ê Ýâ}é¸Ê'(9ˆ{%| Šx·…³!¦uUÝ&Q¹“^¿%­Ñ´…·£pv㦾ZG>á×ëpø‹ÈþýQðòXu!^þ£Œ zø<¶p¦ÝfÐ8:DÇ_ö$ ÜIéÃïºã'ÔP+ca÷?£ÃÁXúÚ°5KetZ%’ û¹JC\ÂhºÄy‚Å'ˆÊ¼YgElÓ[‘Óf,‹Þ{íDïå¹p²o¹û<ݧМìg¤ód†ÃšOÊx Ë[ÜcRo§ÂHÒŒ[3Ógî‰% £ ‚œº1vñe²ß8`ï ”„(ƒx‡†Š¿;>ª.Lvð¡Êº›Á¾êmк.=¹Ÿ“Û©:¹eçV¸X︮:3u6Z÷¸ŒÈ^®{n2£W!‘±~âÎê*Q4’\±/ãÖÆ2¦»ŽÆ– ÃíÌE…JI^¿!ë(”¸mr°z°ñ6YOœNè¨8¢Å«‚ÞÉ­]ŒPþ:?n#¦$YÛ‰ÇÁàÕ#¶âåï׋nMûÔ­£Ø‹ÁMäÔðX~׳‚x%}Ãæ³¯ pËùýšÁ,†Úì:kÁ-($·ñÍÑ ²¼¼Ã+òxËï¯CƒÛ¶ÝÏãÒ#·‹è½°‹Þöy[ÓË·Ï[ÉyL[øÆ¯ <”ÞxžD#5i˜8 Û‹œ€DBXÛ`'sg¯"œm•n·~K¶²aWå¢,(­Ül‡ûsŸë(†ÊÞfÝrøz WŸ‡diðf<»ÃÆlß²&CŽ « ÅÌŸT¾ßb¼)'´‘”‰\c3_vS“Så»WZz¹™_‹Œ·—´ëT¸ý¼ ~G6i¸x[p®ÑRCzŒ&žp\¶Û¬íJ¨Sˆ·àjƒž€{Û‚t°z[ —óI¿c…^aþœßYÅÙͼZ—v!ÿzòk»î€åþÏÖ™}~µ¡Ë*ôM‚’´»~é–g•úi‚n‚!Údá-oðb‰ê“, îÓ’ ¢m6³%)>ÃK¤˜7oÃo’u¼ÙŽqñ‘”ºë,ZU7/+h$×­g(E…ìN½rZ™à’ÕIk™soû6áL¸×ST$¤tËÒ´6AÛ%Wµ.A]ú¢”CY>g¼¸/—ó*vòˆ(ÃAQwsÿUWEĶº‹9~§!ý©#mhðOkÐ-¾î>S·Êú(>l,”3^‰ LV`ªÓ=¬éaÙ6,º²-»Ä'm•ïOÁ¬rÝ®L8›[á`Ÿxyܯ˜ð¤·']Ûb|ÁðžWv ƒÈØ_9@Tˆ7¿ù)¦c’r |t–ž~ë—xâ"ì½SùS‘ jöq$IT&üÒ£ à ÿ©¡Ø7šôäÆ<ÝÖñ4Wm1×xa¤¹zùH«‹Gß¿íð ƒãaÇNï ¤æ¾<Q'Ù÷‹•¹Ýj&}–Ÿ·â 3IÎï[Àg’¥Oãþ¨§<_ãEïSržÄ€ƒ÷B¸§†!?àñÇ'›žYD±ÊÝ=fk#7-:ÐVüûС³âÉ?íê†ÉÇ•oc—£Õ„]mU‘ƒ„?^=NJ‚ðžŸÆ2üu#ôs|Ë-¡÷¸ÂÌò÷lîÃja€Ñd¡¿ÔX—1’Œ” }7ÈÄ‹‚úPBŒwÆrZÑrß:^ýЦþ‰J^€Eôü6× µ~ÙÁÞØ±Í.ÕŒ¢*Pù†…_wéÚ¶É€A+vQ!Àh̉‚…ÁúàkrÂ’NnÂí‹®#†7°\ Ž"Rߥî?,S]ݶ‹ ¾‹‹ Î5à‰MU§T-ý ÏV#ió>Áô~ÐQ?(»•ŸÅ°¬Ä‚ŸL· „è¿Ûñ‚uld±E 0&ð7CR[{µŽ5¨‘TKÇŇ)u'X9»ÚT°ÓôUra§'tÕî7œ,!€ ]õ{åg6>â7 ã{ýÜgè÷§?w¾èhøc§µ_mªøjØ’ÿÙÍžÜWs ÿ# Ùýïk”—%=hÝM8¡[×íδ¿¹yôf÷‚8Þbð ÊH*»¬GÉ’ñ8*o/šo&ÿN]Åendstream endobj 1159 0 obj 4060 endobj 1163 0 obj <> stream xœí\[o·.ò¨_q'©ÈYó~IÒuâ4.'q„öÁ ëf ¶dY—:þ#ý½árÉ!—{öUGM€ p´àr¹ÃáÌ7×=ï¬ã †ÿÅ¿‡ç;ž ï®wØâoðïÕλ¦,âŸÃóÅã}˜¦ZØÎ[Æùbÿd‡uN÷Ó`¢ï˜[XÎ:¦ûç;/v¯÷–¢ši½{.•³z÷2þ’GOóèq}™Gòèq½Ê—Ÿ¥ ?ïÿ=ʾóFÉ@*tzcL,Œçèé|²·”ðʺÝ_÷–¼3FsƒïÖsÞËÝó½%ëŒ÷Fò‡á7{ ÖÒZp$ Ÿ“0z½';­½R33VtÒô”ý¾Y±ß0z„8Ó9¾{Ûäj˜ê”ótÙ‹<áC¿€uvz°Â2Oø"ŽZ3¿®î'àË—&ÏeqŒïþ´›g\ç˱äàè/ùò4_Ž%Gê áò*_~ †æÑ·ùò¢àzc±‹|y“ç~šG?Η_æË›¤¿k>†D-wÚÛ˲EDœÈÈ”åÞ/ŒrKê¨:'µVÀS¼R :—Ã.ødç‡w Ù«üî,œSU^¢¬T<~ºóèé·‹›«ÛãGÿZðGßàÿÿ%üyúÕâO;Ož.~X m’AAm\AòA"ùm"ù(\Á hq¬ç†˜Qx¡;5~?küiÖçã¤üsìåž)V¼Nô%ú.)} ær ˰°Ž¶Ê].Uƒ”äƒDòÛDòQ[¹\»®\õõžé¸‘ Ç{` ¤³> Bäñû=Î;©{ýAAÌ “¨«’ƒ”Û) }™ö°¿4Ò•ð»”RZKPE|L2ˇSH:Æû®óB àS·á¾‡sÄhÏ\„r'Ä@,<·¥ð2ŽÒrƒ«šNòù·Ad‘j÷U;ËO_¤Á‹LÝYf…çᑎqE(=AJ%í,Má°5±'åå?àLÞq±ûÑï¼äL ,Gî“ã!áA(ÝYœHœ çõ2ß~•I"uˆù¼cÞ`à”‰Ì©=ˆ”sQ|áÌ"£j‰yM÷ÉÂÍÃf%éw`íz&$W¾l’ŒŽU}4bv:v“'dÍšÅ1YÀ.;÷¤coÒØñ¢i«Á_Àý¶í7¬¢=ƒ×ËDûM56 hN‚Jòb]Âð‹ JGƒ¦Ì2Ùøà R­ *ykík×&˜â`­à®³®Š3Go‡¡ƒÒ¥ïíÜC®ع f'ˆ›HCÖ® aº¨Å¢˜ë¸M~ ôè€Ê7`+Ç V=R0cǰq:,d©í ð“qš{×îÚv„¼7ùþm òK‹*`ãBIºÙ)±ƒÄ&]Ð ä×.“¨ Kv’±´°„™„[ýÎj ¨ ¬a…­Ï¦cÒ® °ÑÆRÓôFƒ–1g8Ú&!ÀÁ3uIÉ O‡À.’èh†£mkC¼0 b†Aq‹1àÍ^1ÔÃÂEç­_V oçÍ ®G¿¶÷mø¦60sp.âš\K2³iá¨Hfs ÑRZ¬ÃxÊ+­m3G  ÙÿÇÎþŸ_`x†ë1?>ŒL@IIüÚˆ"V&€Øþæ)“ƒ<ú6åÑyô³4ºVrD¿ð·Ñ‚áŸ?²#wÌŽÔ *$8úa”q‡›ùK¾|š{3À`ž®fZ˜[Œðu‰}ÛO}<Þ;°ú}ÍÞz?§Í ñ`!ŒáÍ·‘Ë¨Ž€Úžª¼åtRg¡@CuÄŠ”»!NäU;¦™Ù䈲¢ö~Ý ?Íȉ†AÁ`ˆ8Døÿ&±~üi6ñ¦³ç2øºdúhËô¾€ÐXAW"`³ÊþƼJè ÒIËÌdÛ3wè•1Uðîrì×_ CÇk¹šÀäò8>MžZ|Ðô€'àCIJ”@šbÑ/øOV¯ÃKÆ“sò pÔV Ñî·(šR2Uå:ƒ‰pÚ{Ž™i‚e3í”}ÃQs¢;„á|òØú»Äw vç]šHÜ¿Ú.×â_/®4‰˜X>?NÜÀÂÉIÒ7xý›pdÐö\^‚p8Â;âÁ¯J „ „wH*8tÒ¬O"eN¦Cʨ2µií(m<ð8†´1¬²õĦ4 Š‚âÓRårôomGºR1¥'Õ—ï©ÝÉZ5…ÓÚ–"8ëí]T3;ÅI1·¥—YíráepÕ…TÕy°?TðTPÚNI4®ÇÙ—õuPKŽ©8XeëI‰©)[R<ä„F•kcmaNᬱa&~[àz£Â9PR&{úE0<qibáï)‚é«¡jüØ1 Ý5‚!±ÊažLJ²$¦Eaî£:d—Ïòå?›1Å~}’/ÉbßLF1_¤Æ\G;£8 Œ'ôŒÀBÙ`XAͰ@Œp8䇆‡– Žaà|ô‡ØmGìΛñ+™ðý*Qâ ’¸« µ.§Å§÷` æòz‹Á#”B§DŒ@4„ç¹GD”Vª‰QÞb½Ôï-½×öz÷yÌ¡*Ve–áñH|H(½áꌱ5BÆø _(ž!´3Í|0õx_š¢C̤ÀCà¿V£!D§8Wý•÷©¥&Þ•}¬9¼èp -ÑNMfíp)B==rg6m›PΊ!Áø<”]!¦ì‹‚Àý2goëWyæOç®ö—M†-‡è$¼ºÜGÀÄ".eÎÙåà~•…ýà2×~=M%¤Ûd'ã@$´#R Ȥ^»}Óûå’,ÕöêH~þukjQ0‰YÀº÷eýJbüíÅÓ \Ã˸'ƒeig\ú9‘%3°!° ÷1rɸÁ Ë=­8GOHxà[ÿ²âžå~€#oÆÈ2 {P\xªMJ谔κéÉ¿x¿’vìF³f"“–‘á–j{ˆÍ¾‹Êz_d}›âk"ž@„Ü.º`†—®L -¬ãº€¡9ñ˜9¤AæÑ€If}¢Í§¥¸þ7 ¸dUrŠ„II¥<=ò®ÙV/&:ë €ég½n^!F8ûäs\ΡB{ÂÛù¥ìåž[ž¾ÔÈÍu Bñ%D¼‹c¹.P÷ÀâÝü=ÅuµA’5Kcxǃ ?œ_w[u|âݺ ´lvÎd•lœè˜‚h‰cy-2ñ;‚£ö„'ÝZT¶!O#-Q–;7 å §±E:•„@•±"ÄÑú«*B 5¬Ãƒu,ºx\rx•¥©^l0. _¼'7ów\©Y·ý#Ö\#ŠMqmýÃì ÂXŸîê¯dWW{¶s ¿ä(ŒML:?e\5µS¡!Æ4°SÌÁ–Ç× ßµÂC®mªh¿onÓ{Û‹û–·)Rì“¶“žÀÙZ[yÀälIT5ŒQæŽÇ8‰ ø©ÂfýÓKY/ íºŸÓ[ñFÄ™¾ã4àyêœ7 Ö˱͙˜‡Ø`Œ*wôy¢ù<Ñ|\µöfmvH¾˜Ûc‚–{Ûãä®Þà3¢sßåëYxx€ãb$`…ß—†Çß«`ÕÕÜìêá&K7Ù¸¤›ouR½™Ö›"ES½™Fgò!ÔÛ›þ“èêsÝÆ_x1÷™›a÷à-¹¢Šøü=^öˆkµÅ«7ÃÝYHº·S˜òy<Ãï Š]<#NÑ×BŸ¤”Ë,âl{ qÆ[¸äl›Öˆ7­”Å_§œÃ×4{°;6§y ;<ÆÀŽÿÏØáÅ=ùu³Ðá†,JùÙü›td=|Ýø~6ë×ã/Tç´ô!ök¶¬ûý¼±ßz}0Ý›(7û q?O‹aþUvq§ãÞø³ æÜ¶Mj€uHÝo<Ø|SpàØÆ+µÐÀ1½õ/Î{4°¢ã Vß'É=mhÇ ‘ú{Fƒ‡ØoÅ~7hpoüYsîˆÛ&5¢Á:¤Þ 6ßÁ·ñJ-40›ß7ò1î Úw6l+Ñ]gè§îf°ø°®ã~ÛœrÜéD¹Å©ÆB¾iÿ< ©æÔ-sõá´õ&~ü¡Öé“kUoçÛãÒàÏÅÇ~«ðd묎€RðúŽ€òÒA¥!ýÖ’¢ÌYùHû^*fa7DNÊhXaìtÅüãÊ¥zXhÏ-k>?r¶MÁ˜6ü>²Ÿú~¬G1…©úpˆÄ6 Uó²¼{Ô°ÉåïœÉÀ_e·ÀÀ›¼ »©¿—ZTï铘ê{n 4¾h•ø/ZÅ«Öç°¢ècjwì”Ý}K¶mÿšL»}ãç¢gcNn›{&3÷ Z"kÕ*pëz¦q«øÂOö ñj%Ñ ›‘Z…Ú@ü*G䱌 Õ†)úÏñæç3…ÅJn¼R ‹•T”©–à«Á¦n`ÎÁÛ½íc ެƟ¨(6‘î¶ kõ7Á;œüöbøù¦Y#ý¼SÓå[ʶͩeÒ—¬º#œ=€t8³¾%ž³nÚ ¸cDúP8¹pu6†^¯éÂmΆ)Ôá' ¶éï{‡zbBP¹É“ˆ,ÅlÔéðÃÎÕòÅendstream endobj 1164 0 obj 4179 endobj 1168 0 obj <> stream xœí\Ys·N9oüû‡Ý”wˆûpÊ‘"'ŠíÄvXåJÅ)/‰,QÍÃ2óëÓ¸¦ ¹KSJ9V¹dA ÐèóëfX°/Xø/ÿ}øzg÷aØâåÕ[üþ¼Üùa‡Ç!‹ü×áëÅ“=¦ZØÁ[ÆùbïÅœNÃ^ Â1¾°œ L-ö^ïükùzµ†^å^c3õj¦õò0õ:«—ûØ{±Z+ÇÄ ÕòÓÕZ;3X£–¬ñ5…½ {=öjœáKì=À±·Ø{½‰^-¤^^Íïý5òv;x#€Àž`ÅÂ8=h“öþ÷Õš –1˜.lHÎy/a ¯*Ïüò46µ|ù&ð v|«I5Xi!%4_þ´ZóÁÍ ë 'ØO½Î†÷ËóývÙ8t²l@^»ZÉAk¯TÙ®¢Û¥"7ÐÍ`ÛÈ,Wƒ“öq[ðVîSŽƒ¸Kk|zQúÒj¢Ï\ÎÝàFÉÁ¸´R¦” Ø»Ÿ¸#öŸpdŸ qjðB¹¼ÁA¥ÍД=oºLÛGœ…×€DM§=Æç¤7‹•s½¼ ½B{æ¢Â žXm˜±™®8ôb”åv¾;ÉL‰@É,/á[,eVç—Ïãk†kÕ<ì@Ø`€åµ¼E#]ÔA6‚:× ¡À(­"dãKaVÍïMarÚAœÉ{Jì›2¿ö›‡2$Û:óJx*p$ê_"Ò:^eÆ€Z²ÅÞ¨KRj'DäÉà•Övcý ÐlÖW£‚Ž*¼?ªõ9Uæg{;_ïü°Éƒ÷¨±µE„á‚ë}ò|g÷ù—‹ëË›ãÝo|g÷/áO¾z =ÿÓâ7;Ïž/¾¾Ó!÷©çþ¡*âÏFBߌķ6Zgåé&6É ¸Ì4ÿ³ÕZÂ+ë7Tlã ë¼Šf)ßbRjÉ=7E †˜á!6‰¾Ÿu Œ%VP ]PCŒë¨1Éh[ÄÑJB‘vJ—ˆé|´»‘œ©²¿úñQ6Øê)Ñ9Ñ7 / ëûågãLOá±aX çôHßEŸÀ±WdV<ŠÙù‡ÈÎmiZx°þ¾7£ 2Â4žb39ÍZcó<ˆÔ‚÷âbF¤þ!"EJ‰eV#¹ïÆÝcw¡ƒ§)JŒâ¬!0¿ŸbÜ>[WãÓë±owl½ŸžtÞ½Ÿ71Ç…§WÍ›¡t-ÜÀó^÷œ Ê…€à \`)(ÒW¡SL ¥IìÇ€M;áÊAGqÆå8kYÊÈ™ØOÞšÄæÜ)4lKÉå Ô È…¶ƒƒÝ¯Àþ¤³ToúpèFÿ. A˜p֩¸Ò-ì7 ’óÇÌ;ÿ•¤W3DH%0ê:!t©Îýt%àŸÊŠå+3p#¹‰â¨œÅsˆ&œ Ñ(Ã¥ •Yµ• 'Áe¨Ê‡”ýã 7t…À@ ^kšÅ‡ççYkD›WðXü{\ .*J:ÉHÀœ FÕe@’S™­âŽ áTö÷ò¹N¥ÖYœë`üGuŠŽ!¡0×BdŒdcýÉúIÄþú={Õ{Š £%4N%âuO=Åeޤ¼kªí8SØvFT©oé ²Õ´fµßu„€Ró„HÿXa é—z¦tB|é'à–œ”®r:PIáç*>U³1\x!5Æ"ï\qQj †_gAnºf; µÀ¸9ÇõÐLÍBø÷zÖïõC€ä5”^~¨¦V§µdlàÀ7ªzdQ­/D`)@ ÅVµ£NtZÒ}Úk¡<ÆÔJcO(?Џ.’›«Ñ¢¸ùŠÛ¥ÀùcÏŠP]oº¾ŸÇJ¤Š«`KƳ6D}®Ù…ÔöÜqå……ã€e40‹sðk³¾£^œ(’•’3ꦽ ôÄ ÿuWÔ@²EÆ„%’Ç· U($·Ä³†w\¨àG)½XŽaŒCC!…èĘl¼b¶³â5E‡›£gŸÕwÜá%¬ÂüõD·]¦‚ ë¡‰–Ÿw…L´ð6R¬êg¨fÌÔy ÛÄ“n’7(ð&6Wï.ƼárDè§ME/´zO1G¸Ý¢¶§´Ïrþ1Šá¢’h§ÞVûö¬·Å쪈0q0! ^?„#™Ç‚$¯R Z°™Ù+‚Ý |ga?9lnɬû5z )Ž“ýU_ŽSÏ•Ý|äd0]ýîzÜ{ƒÀ-†º·É˧´/{ù“^x,®BnŸøÐ›ÞòD”dS$¯ïê.ªš’wãúš-ABáèOèvlàÕ3,LŠ›€Þ‡Ô ”÷wf¤Y;x)à=5UÈVÀçJîõQW3&‰>yžA™d~ydPÉRjF\5˜‚w¢eÎ¥áýº‘&›ZM"çdŒ1e@W}‰úwõ¡»ñó¼/S½_koúÛ5 J"˜$svMâcôàHôM×éN ¾aèËÂKC‡Þ´ôÅæº-µfz-(#t¸‘náOD´wÙºBe@ßõ"ŠÜÇÐÐÇ–ÿA‚ÉØëîØ‰øB3Ń$½{`bÿúT©“¨j시…15ïÔ…uÃÃ+„6Ô®+ˆõà«dŠÖ ÇÁþܲbs$fSþ=d¦ûUØ¥§™0¼“Õ¯|N2œ4´ÔãµµORó±³hç3û&Š™*ŒÁ/L* ¬i;p߉.#Ø jÅÄLâV'cYBô-cœ‹‹™´+5®fê™™Û½"p¶EblÛÆÍè´¸. ¦vÝÐØ\ øÒ¹™8L4p(²´`„eÚ~˜Ü,Œ–è±–4º¿éRPª–ÚÛ«9~má|CÊ+„®UàëÜìšh!̹+³{ërû’¢ ›jzçÛº3òôè¾ ŽÂZØ,ÂEH ÞéG€Þ¾ÚÖ;/¶¨r†Œœ¹Ç«r¦K‹3é y‹Ìu’¶ J`F órGÁWT[Ü?ìßÂíÞòÅìg®®^wl.µh ùBñvX5¦W|KsJC²õ‘[m†Xì¸oSõÛSÔÊç\êÆKÅ\3…½/ýK)™KÿoGC=¹³¸¼Ús5˜G,îÇZ‰½žå{}Ø7Á­µÞ—¨yÈë%”¿C4Ô«ã} ,WÎWE°¦F‹Àr[²"¿X&Ooë:<Þ¸é)ᆠOMâ[ß‘‘kE¸èx˜(êãÒ¢§ä¸eªªþx˜Ø¿VCJjµÆEÑ™wX¿ïtþ!S+{ÓBÂóq±:ñ × ¼M²º?Õ•Á @fµ•¡q0>À«CVV}vÓ½Æ0=¤¶gÏ;p[ÊêþE°J‹š¢g*¬¹ç÷yRn®Š¢Õ9ì…û™Mºë7uͦa¬.;å³w9úú<9ýˆ ÇM‘{nݪåÞO×ð G’ž\Ðà$¯gŽÖ¦uºF›Ô*ÃýÛP<«8\î,£1œ· ˆvu9žJQbÊÇNV,ÿ¹â‘Ç¢©æÆªë}µMT¹™®®æ¹Ö‹ÖBc턬5 q·¸ìqwì&Gä:òºˆs,¿ã#&Ûúå™#ôÐ|…ùT÷¶ÅƒL¯«çkeFêyèµ2z=jÓCƒ­cƦ÷Ýß9g—‘Aû|ü¦õV~BoªÊO¸a4½\žT—‹1~þ:CÌsÅCOSÍÈ…<“UgMu¯!Ÿ£tS•ég’Žñ÷¦ D…í×ÂÇïü ¸ïµžÆCfåÍ´?6þ¨Õ¥·:^çz0\èm?&_vÍ|ÁLfz,Щ;®ýV'‡õgÉý/ÑÄ"}5Z.Nßž_bó›i@üü›oVã×à‡Ø{Œ½WØ{Õ} &‹ßž[Cç%3…o°÷{÷»½§Øû{ϱù øî»±;0Î2Ô‚ƒ,åOzr€¯žá«ä“|ò¡þ«îØÓ–…fmüÀ ¶ívpÝ]"­?¾Ïû£»½—ؼÆ&™á_;ÆÞØÜÇ&ÂYwޛ؜ò,ôbóUwìiw›d5ðóZÊx,WĘ… øWÆM —o‘']™LÙàW/¿·Øœò¬y,¼…ü" ²—X×)ë×ç’¢*±™K:¿o}•&Úò}—º Téƒ.‡È¦ˆ^€)¾STSSTޱñƒˆ®ôæJ?øÏþóÿÅJím®ú½îR·Éo/qî`¹ÑO+÷Øâ8•$±Z²ésìý¾U‹Øœ ©ÑR2öãÂEç%êv5áv3à¨%§UÍ‹¼µ”åÕD…¯Ô”EŽˆžÃ™¨gëDj•ëh ÑÛ̧âÈŽ’%f=iÒîÆ>„¿áïW!´wþb™ïg *»dÂeâlnæD&0´ÌDßߥñ!Î~ƒÍgØü ç&(ü .óöþ{Ÿbïçí qÀgØû¼;Ù3ìå>Íà]È"Á0v˜h\“@\ÝÇm¢Égí ­¾l‰{‚´lc3Q9rúQ(õÐŽmÀËÉØn|›Ç¹º’€Ô$X›5Ú hŠÉzJ{ßuý0ø°l ññ7øøö~…½w™BlþUà)6?Ç&Á¥Ÿákϱ÷ l>Ã&DZèºÿ‡å‚_çÄ8ö΋K"œ“š…8÷>÷ñWÈïCã5ůwþ ¼I.»endstream endobj 1169 0 obj 4014 endobj 1173 0 obj <> stream xœåÛn·±ÈãùŠƒäå¨è¡x_2( Ô±›¨pÇVч¦²$K‚¬‹u‰í~}g¸KÎp—+é8–Ý¢1<³ÃáÜ83¾[J¡–ÿþîŸ-¶_j/—G× ¹üþ=Z¼[¨²þìŸ-Ÿì˜ójEôÚÛåî›E@-;½ì”&Ïÿ\íl­­Ð.ú¸z±µÖþGšÕó-%¢ŽA¯N¶$àpN«Õõ–ÎEkW7é"¬þ²_D)-|KÃC„´Â+UÒ ¥ÝêbkíD1šÕUÁy¶µ–ÂÇ`Õj~¿)¨þµû×´)Ë7%Epþ¢‡i©—>XaC¿¹W[Vãœ]}L#ølužF6(ÀG{å×y®_N·y¨Taé½Î÷+ín­ÐÑvauLÔãî­ 7ðÙo_ôÌ“ÊqFÝÉgoWß DŒF÷Y}æ.ÀòU}Jxï”Tkm:aŒ^)¤Å‹®³ø€=OŸEÄ«A*‰Xå 0®|vÙ/ºŒÀ›€ Ú‚Xm&ÌÈ®Ú [­+€_Ò „Xb6‘aµ‘ÂéîSÉݧÏöˆÞó¤þšï'É©æÍ í熆Çc.˜¤Æ=¼Î‚FbPÒ&ˆØ¡¤P¡P˜º‹ C» 4›ìæ¢,ËÖb[¼ \gˆ jÙ™o†Âµóp²HóX^ç~W“œŒÓ®D² ð„ T»l\ÇdQ'4 AŸ áy=›NfFöpÑoÈúniø–ð¾í?sÒ ³ à„†ç{Øã…Ó%›.hxF°g4{8F–†7¶÷a&i؇K³Ûïž}˜é@ü6Mb³Ë2C€ã1†kb3ãm–d/³ ÌOÃu%³YAeŽg¼Ÿ[PIÑl´BU¡#¦h,t|^|óIñ××Ì_÷€Qcú9|ËœýOáÁ)R0ú¡î5·Ë&šê|¸Ãn æ·K01z±Ûlj±Û$â–-CP4Àd«E€Û‰Øq6[íW¶ÙOŽ;!\Û,s `\Ê ¼²™=Äf3ëj›íýl@‰1&åÙ¶I2—{·ÍöqÅgÔêù´P)Ëû&,Ã{L°×÷á=â|@Õ1å’t°½ÿ@ ;4|J¸^’'}=± ýÀ²4»O³§•ê®3ë¢ÄFü_îØ©­$;©™âŸèTŒKkºwQ‚Dø:'ŽÒQáŽi¬0WRL™5ƒ) q)F’€NxL$'ÿ è»NtÉU8S;*­F•ƒpÌÀáÊî¹`Ða]ä³(ù€É¥â!ÚU©´k,òÜçeXÁ ÙñØ\ÄKüÙ¾£v”+h>‚KæÙžNÕÕ ø£ w§ñ€È³WCW†Q]ªp±,¾_IC±w_õ‘zPP±Mñãè”0ÑäÅP#“XU,Ÿg0è04(p]bËeQb8x4µ*2>1ÚYLþq`Ygø>Yã-׈%T0º‘V‹ Gƒ¦én Ë(=SÖACó^ø®QLR»¥Ï×,ÿó²;„`Ä#´F7c¤²—üÄvS«eF€$BªÝÉéu“æ 6̘B±ò:ÑgÈ6Î$€¤ß”{ˆ£2wÛ2]æØ¢wðb)ÿÔ× 3±tK+Ç­—ä{¯ª2Ï^ÒìÍNœ=¬‚ û5>»¢Øýª‰QƂÚÝkβÀæ‚fÏiø=, .Cz½úå—rô&“ pÌËtXY ÿuŽfÜ{4»O³§MØ“1/2͉Ho·› ¸i.±ÝDv>Çã:¢ICV´:˜ˆgY2ÍB¿i„>Â+høº2d,ô;½/x¼n­†òÂhü=m¼ÜL¶ø/óNy6úŒ-¼¡tÖŜ༉.±çNe”¹”Ã2Á“ÉNÎçbз4;åξiši;ÃdêÁBÖG´ù̬oç\‹Óïͺ›«©C:_ ÀûÊ1&¼Ã•aå#ÇÊ}ÕÜSíé³#o'Su.'S,·cjÌÄÁ\ÄqÞå°o«aÞ[ø’†¿^K40dM³c&Ê áz<›(d7ÅR–[ÉO›m¦N•ØEEøüë§¡*“æÊäñ ÙÄä=! M:‰ãCî>NãÛ°L|í<_Wéì ŽêHf&Œc,fÆÂlwrr¶‰12ÑQ™ˆÛc‡½l·® iÖŒùuom“uGMÖ±aU8šgÇØ/βcû¥îìL×”¶˜+ôÑÿ³Ò{ðë–ÇV çxàrŠ•†-Ë/A2œ\0ÃIæýJcãIjÆŒ‹ló„Z”È6ïì[¢âÛp…ßb„St`SFÌ©“ŠëA_ UC3UˆŠûñĬÞÞ«€ÔÒ)tï³>>uƒ2ê^l)#bç<¯¢1Å;Eÿ^©*…cxf¿±uM°÷Õ]ÈÍ_£&ˆé è O›°LÍÇ~w¾ðÜö›-5ÿVÏêf×Ô­¯…ª¥æÞ|5÷¡DEúájþèÔ jΨ{5Ï?Šã·MUªoò™ˆª7h£@±¡Âw`quGù!Ncí=´ûØ.Öe¶¯‚÷2oßKñ Yðªe“: ¸§·`s…¯}Vù´Áš^%Ÿº*caeÖuBÅŽáŸ>Å3q¦´v0Xœ{Þó?RÒ>„¢ˆö°»ªHé ·”Vît5ì!Ä{] =B<¢Ÿo[F9‰YñwÔ#8%ƒ ³Ý6 .+¤öÜD+DâLV¡@Wºúï÷ýˈR"y Àª{Ô¸GoðZÕÑ+Î8Õâò¤ ƒeô°ˆ=žjwU@0k„t­Goˆáu³;Š)IÞ™Ûz_Cå„=d¿y–ò™Þô⬛ˆx€Žd=ØEW*Ö´[#µ2ݸõ•÷Wäs>¶ rí@ö¬/A»¨ñEs„ÀÅW±×;r d.'Ü=âGZÕHÇÅAöâ¯õ:zJ©þ2q­ÐqIÓó³ýl©öG›Gí´Ú½VͶ¬üŠW陼â7xå¤Ùí2<ºUìTݤÚêÄËú…TQl¿zNÏ“›Nƒäùa.9W]ÄpZ–6âáMŸè> stream xœí\Y·ò8¿bà—Ì.ïÃHX¶ìl R¼€ì ˜=%H{hHûGò{Sdó(²Ù³³—£a/Áî&‹u|u°Æç”°9õÿÄ¿§³pMç'W3:ÿþ=™}œ±ðÊ<þ98¿Øƒ×”fsGœæZÎ÷ŽgÃ0¥aŽò¹a”Pxr:ûyñb¹„;iìâf¹RÄZçÄâݒ«Jq¶øP†‡Ë’©Ë#Z+¦çå³³ahÍâ·eò¤ Ñ—K¦ˆ²Ž/Öeòºì…(oÃîý%ð£:(gÄ gç+ƒ½C8â·@¶1Ä(ôùâhÉ9‘’->ÁS%ˆotq¢àÔ_ÃZÄI¥Ì@ž²y”XEÁŒ…ÝçÚZ¢í ‰ÕRõÒ²8‚¯€Ê4w–Gëüt?Ï}#cЫ4u•o›%`êrüÝašZÕ/ùgGiê"ºRHêæ™‡Ãg(¨a@Ö ¾#’I<[xy]&/—+I¸rÔF¶;Æ”×ÆøêMEµÔ­a(@@^o¥&–j¼êyúê.Y ɉáÕ9HbÄNæÍAš:Oƒ"²ã4õ. Nò³›iYl䮤Œðš»åȈO§ž{Ž+-ðpÞ5ŒÛÈsÄÓ0$ ’ÎØboÀ+5èP~C’%×xã‹2ÜdCá…³$"–çeˆ(Côî—YN賬Z oŒH/ïz¯¸(Ô`@Á€WKA”rRbԺȚ†â£š×TM=j¬87°?ÍÕ/r©3mô¶<_Q–5 è&(æ é<šElF–t»T’®ƒ¤ÔªnU¡ª÷?ß–*.Ý£€f\=Êl@Xf ˜0‰Öq•MîmFÐužkAÎ?=Ćøroözöq.O l´s§6(@uÁÁE¿Øíìþm~}ys4Ûy3g³?ûÿ¼xõüÙý~þ›ÙËÝùë Ž{ò8ŠÃ¹ñyN;ŸnL¾¤‡¥v³Š² ð†Jë±éD¿ /øìVà”Š­"!aZogWAY3@cµ½®<ˆà¹áû°¨¦Ú`+ÛS¢ñ *ÉoD_'¸”˜Ä·ùµç`ûFñ ÄÆVĈŒÊhDáñM×p,tX´ÿ$Ø æ ”>ú¡ÄPj5Ã$~ÀRôºÄ¥õêGÛG,At˜„h!,qÌF ÆÇ y,™‰›…ÙóÈ¿­À îÔS–Nb·<ÏúÏ'\Gíõ9>ÂéÅáà†×n¨Ú/YŠc·„ÈÖhëí¤ÊAz¹ DŽWVnÁÑ›èñº|TTñpäœüó✼GrÀ|%nLà p–ÆZÀñÀHñ²-ç9£àEZp`1xJm#uàŠBœMb¬£ÇºD²Ñ{´& %YÀB;¡³ @‘z\ìýv0K€bšÍrí× ÔuY©Öh8¡L7ÂTa%f&"I YÝAw‹ÍBÖ5ötƒ³f;A!w•¹¾ò'†8XVÕÚLÀ™ëZâ^¥ëà_ëºÂÐPÉù`¤ÇW,†Aû•käið÷ç]»)ÉKÔ)ÀY¹Q¯_ÖhlÛPqìæÒ²O+&7÷wĺ3|œ é8r­SÄú`YKB…èç‚e%äÛÖ]'„<ª'è†8g+7·âFª4^¢ÏоI¡“W¤%;u<ÙisãŒ,|TK¿Dë.¯p˜iJ9Ò6Hø, )$J'$íÆ#„2˜¢iãÌð>2ë>TÀ )KD‚$e‹_º5š±»o0é@Ñ–_–e6Vf¤PÝÊ ÄÎ÷þ:ÛûýÏ‹ŸÊ·=@«ùŸ^ýœ_½³œ¢ l¦ ûúÑõ”Å¿òè´Së>M@òÍrÑÄ¢¹mê9…Ç ÞŽ}½Ïq85 /nºÎ©.øqpÝ“Óeý”-tc™ãÍ¡N¥x![T§Ó¦Z6¿!äÓ ÕÆȹJ³ÚÔd!½Ô[JǽDW:x_3À’œ’'¯.;QA¾ŽîÜì£n•ÖŒ0«¨sõ~Ž:~>·ü ûœ\ÞøÚ®éI-tµ«Ç\…»+ÀŽ?‚9-¾J[±aFZùè0‘é1Ïë¹4•Ÿ¹üL§)³á;•_Õucü)<Ðò/ þÚ.¿4MËŒ§[ñ454‰”“ FꨒÝs÷á•!BTÉy™§èp‚ÌØÐ!Ÿå °Ò¨É n® À7ÚIŽiNõgˆEÚAçéÊC'¤¼ÍïÆ¨ÏTÚ‘räú†ÿß™Ân¨è‡”åTüÍÒ›Õªq+)Ó)îwqÜyá¬â}ò7?åâz>Ñœ1öŒUAù°râCÓ›|py 9ù%5šÌ$Ѳ©§­ÆÆ“S¨b§û%s¥lÿýf0¡Xu¸5bJˆšGÏ׈łúnq²¡Ñ$\NEúa ±ƒ3J7Ú l:Ä`pö;wC16®KÇcÐ÷¯~³u½–)é¹8æ]Éö=t4þ¶´Ö9fñË'ùi©, MÊœçÐæ“žV;²çÙ1ÛOaϸï`¼_£x#&A§¨y*’Ã^#$‰‚fŒ>ž~ÿó °Z4–¾È0Vi“ºÔúøvÖ:ä(ëe*JÙéíõ¾Æ8Nôª‘Ÿ½kN‰+eŸ7¨Ô):a¨nB4o5¥¯õ˜¸æ }²ŸO×cneœŒ¹•_ß7®GFËúÈ>µ1W$d£DÞ-X:Ó„ •,ýztŽóüå‡Ñ9TËûÀà}Ð6e³Â Ún?–L‡ú‹â9Ìÿ ç~å«Ρ(ñ:]¥êIäUÍq\ÂÀ÷”{[Wí[Ð çÚpW¯ˆóVåZvøHr—ï…á݉д¹ W¸¡l“îKQEŽýÝA·€Ò½Nš5ÔÚ2HAº­6ÓåN.AÁèpßÅ6ÃE`YÝ󥚎v¸‡©ÈêîɈ+àRÏphüµqÝ8l•h.£ºÒ³ŠßæJÛ—¯QDŒ×Jˆ{“øª–:ßiæj¿hÖ3Ïu‘Sž,QAJ=×Á6óÅ‹¶uÙ'˜ (ß(ØMú&ï`™/#8Ó– ª1U‡d·ŒÐí…D“MƒÕDŠÁca§Û"\I­#ÄŠõÒÒ@.;ÝðTýµã¨AÙaßøÞ÷^ÁgÓ áˆ‚ÉAL~›¿GuŠ›(9SÝoLü’‡9zqt ÒÂ]Lp%¬Ó¸¼E‡e¢ªžÏ+®¶‚ÿvë2‚äþX†$gÉŸj£ôÑÀñ6f'¼ ¼fDE¥"*¶ÅþÏxŠ~¼+<¨·ä¬¸ß&r˜¤¢&šÌרS4z¶( wõ¨ Ù øBG¯Û²±oØV¿TwGm¨ËŠQj¾ŸáºàhNÃ7C¥öWËv=Y¿PÚ4_¼ë'9£~•&4\)A¨¤Þó*Ëqÿ"cöC¡¶Û? R(ŽQî®íB¼Çå¹¼¨'cÀdí±÷ÏQì2ÜÜkŽ¿Ò¿x|D3¾wV!ÐEê}~± Ç·ôJãŸjv;ô°N=¶¥3¬YscƒànáaÎÆÇð^ÍØÀêÕ8”{QU[ù‚cLÆJŒùÿV¤§jEº#„5ö8ªÃ€ýä6uZ‚z ß3=î_N‰²;æÚ¸vt½µ©Á¦½ßJÉaö“Ó]Çn«‰¶Z÷Õ3áOÞW¯Ž¦új|‹7eq¸Læñ ×MQÄ—Ö€Îu"Xä0ú¿Ëével'–ö> stream xœÕ\ën$Çuò“O1Q~x&ÑôvÝ« I@ÖVì b[Z16 [0¸ä’»XÞDr­¬·ˆçÍ9Õu9Uuz†äRaÅFuwuÕ¹~çRóÝjÄjÄÿâß㋃g/¥Wg·ãêWðïìà»YÅ?Ç«ç‡ø˜Ó«i˜¬´zuxz0O à)?x½rbF¸qqð§õÿl¶fð~šÔ·‡ÿ> è›x9 ožÀÓßlÄ0)1êõÝf„[ZNv}´ÙŠÁZ5©õÍf«X£‚û[iàa¸»Qƒ1“Öë7ùcüK¯çA#ìúÞWzprZ_àýI[=@F¯æi½KS £ÖâÕ“ä«óª¼”q+ÆH‘æ·ÊÇ©Ì4úõŸ×eÚï7Ûqpãè­ ¼ s¨Ñ‰8]¸|Ým§øó–&Å0ºj¶nа¢™d“fæ±gÇÁ›È\é5r•2w»ÑƒWέ.´,““x3[Ï0ÂRµœÓ„Ê×yMt¥dýåÑËòèSMr•Zÿ–l»<Ëîç›­A¬ä§=/+ø;Mü£¯Q$ÆÁˆ‰‘ äy «Ä™Ú D¹Q­;,A&‹”©±#|NOqytŸâÖÁ[»0EcµP0ÅŽÏ©Q‚Y³Äê\²V'Ê’.8`ï‘Søy5vG¬ý9.ö§° …LˆG{ FDñF1›Và ߗÁÆ6Fÿª<€´6˜Euý’µ¯Øik’ˆ¦Q+ÛÆdç‚qÌûz˜qüãF€N8‘·Ž~Ÿ|Ttþ’2”EçôrQžP”ì'ù ãzcPOÚ¤L`T¿B:ûarž~Š,€EFhò¬´ë³ÌH"¯(n  ©I-,ïŒ`’l2š¸ÔZßðlz û^´Ä÷öµºùBô½äÙcÖ_µj‚C(°}Æ’ÁN·SèBL÷ååGj5da)3£ÅS‚¸/²½ÂµÈûHÞ ’Rà#È´^m‚ÂÒüüý—`dðÎS #rUé\ºL\Q®‘0 ×£Ú)a(Í„éiP“¦¢<ÚY1¤ôYT'Ÿ9‰Ë&kmýwxÿfZ匶„gç‘QÊ^\QªK9€auëw ×èÕ&JþÂ5Ö  yDŒµÐ~”±'/Á= ‘¥ô¹,ö¤ê’³ºul6Ëä:â/­â­2Ê ÐÒ ×ïÖI%.þ^0HŒpÕÇ+ûa”À@îGµM( ‡nû{'ièmºþX%áZ­?Kc×ùù£4t—.Þä{_ġݰͨõtÉ5äÁÀ‚,b]:8‚þ}†ügå6‰vIñ–Ô.³tö¼c/ º4ºy¬Œô+;Nƒˆ”8δ¼ Wè1/óØi¾z›ïžEnÁÞÊË·ùö_–C7ièçéâ³|ï: 5 Ç{oÒPÃðÉã&ðªIö¤Ð,ÆïT¹.:ß)Të)x v^bEŒs”p€+<áÆjEÀÑÆ0jM ÏQ•ÀJz¿ÅÔT…úu€¯@+¼ „Kï×ÝXÐ%ìB§8‰%[– ¢[4†˜;ü(¢0%‰n‘õõAnÄ0ó¬~ýße”J_åo½Ü4÷ ðÔï#•ÞIŸP€•c@¯’¼ðÔý1E/¢F@[ðGX½&Fë+˜²ºÆ˜èk‡ n¾¥€ ÕÙ\uÆ _û°d ji‘*Lø¾õጢ< ‹7ìwoqð Å8ÅÂZÊ"¶%K$û&ž-ƒ¿”Í\ÙŠˆ2zLb¨"u8xVô®G8z]¬t|šf061˜O¬ 3j<éÌ0N xa!`IƒŸÆÄ£)D„娛ˆÿuGñ&B ß$™ƒÍ–’€“-ETr„A”ÅyŸÀ¼¥T$pÃÀ/h?Á—ºÜJ„`Pº»„NÔßêбÁ=Á*ÃÖ•å•”ìâg0QÎ>ø«‡QV¤ï"½ œ±êB´ÅÀàÂTcR*ÙÚeQªPÅ›Á,!”&„îŒF0È'Îø€k2Â4Ëù”5úcU¯³ÔÒð Q‹™…¥¤»Óô[Õ ‚×½Þšâ6Z穨“£”¤k³Ñ˜>>5ÀûÝ.¹Ì{ˆ¬ƒÈ5Áb¢7PÆ4Æ|FÅO¢^¡ÄEÍÍû¨ÙÖ›4›,ÿgþ+ðÆÂñlSw\Y£Jݵe£”ˆòkUiýš¾V!ý˜ÿ²TyȺ…`¢J'ƒÊOθ¦²Ú¦À<Ðé_7BáÓU`›c#"ôÿÉ*X FæS‘ŽV  !aüïsDðe8^æ±oòÕ‹|÷wyì·ùêó|W4yÿñ„ž,îñDqèˆþ¬¤^Î[FBí§Ngé¢>c±Ë&¾+QÞ½+±Ü –WJ(öE¾zÖùeŽœxÖsWi(_œ7 §ïµªsqOÕœ ªÓæFyfÖ=E‰¥_JÇ©ãÃÛO’3¸ã UU†CCi扑`>PW•–ÃN1-f~j/«ìr‡%Úª“ÇóöÉ“!’´n;‚Ï´Á64YœÿËï¾’†9aç~¥¥™Á¼NÁ:°—ãù‹ƒg/~³º»yÿúàÙVâàÙ¯ñÏ¿úüyñËÕß|ùbõõb‡ÇŽ-€s}µ…ãNÖ.óîj±írO^IÃΔl>—íïk«»ˆ¤s'sL?¶ DY@]záA4À¿gÇ9õ!ÔÒ‚L¡ëmìþB%†5N{-’šùÖm¨ ÛlT^ç±b›ŽòÝWy¬…×ùn›a\Ê[QÃЙÄ\2Ûm'eþwÅ´¼î Ï”­ò­$;Àg&?¾xw¸ñ BL4-u]¹¨{×ÞN³ã»bqA…ÜA°å諃M,k/]J~¯Æ-çäk >GûvÁðߣ֗j•¤ °nLÿÅ}zŒxõ8€ØÏCMÄŠª³TÕ'H! Ùì‡F(wô3ÂöˆË¢¸°I,òv*næì;yՔ㛠VLÀükï0Ä» ŠÄJÔö‰û˜›‹îªÉƒÍ¥&A_»îÖ…|1Ó–öd}Hg× –Øe–›þˆç7r„Üæ\Cš)nËLºujMo*ö1æÜà>ªœötAàR¢9M:Ä®] Mã³{ `o¦•6.7ýU+9MÝwxµZJ#'Þ2.fÙ“A¿nMY#ÆoJŸa“…ˆÆ²0‚åcªpU­ |¯Òõ²ÓÛ2jéËþm‚¢\•úÁdxW˜QRœcœ”nÈnó á’ï..%Ü%K›åÁÖNן­°`Sü7UðL ønMvM6CýôÛ’4q¼åJÁEªþÁ"» [B%±!ႼFzF.ló)›&éuF‚r-äVjŸ^»¬ýk9B3l”Â"1ÈsÃðrWSÁOLR§§“¡-£-nºwáòý6‡5Õ8?k[%„>Ø÷zQrÐãy¼³¸T±˜ÉZ×–.äç—¼w²Šˆz4ÒªwÙ)wÐìè(ÚªÁÔì~ÅÞ~ ¾A 3ühxmöú %ÏZç–¥,n¼–¬ï¸D.ÛíLbø×}·Z‚¦Z_>݇Zø~·w-*j00®@ ~$Ï 7ñp÷º€Uâdùìþ]d±YÿÀ¦6.«Üs0pIrÚíƒÆÔeª°X£™öÈD×õê<Ùæšˆ‡‘[uWîCº5T·´ØÆ:Ÿ®YlÊh¬ÍÍ[%y˜±z(¨RÖðU…@—íîå*bÃ%á8¶°‚ÇÇä’t ÔF>.ƒÉ{z6má0„â°ÀÇiç\_ÔÎpC·á`<—³TUN]K*G ¥î¶á‰ %xòÓMd›m¹ ÛFŒ¨J!|‡QÝ3‘N–ÜÇo%ºÊÉ6lleÝI‘¨—'à÷“{””l½º÷ÌCÏø.?‘Ü>%$»b½ÈPK½¦^†ˆ|:=y‡™G£¥ç³ú‚W+–ô·ë{iI¼Ë‹‰ ÑáZ¥ø®r²ƒÔB4­ƒ^íœÓJÄ›º0×ÜÞÇw<Ç€-hQëÞâ^ƒ{£} QÕˆ<öŽd¶¨ðª‚­ê{h ‚'ó¨ÛýÐJf¹vÿ‰F(î8hJÜÇþ¹ÇŸ2нxÄñqÝÅœöÎ7úPö@ßÞŸ C[mªv¯¦¼ØÌJ¨‰È¡yÿ1·ðV­8©›6í¤Ú„NúqŸæH“kîQ•ÖY AH6Ë´µqPšvœêDqª.¤æ!Þå‘Ö¿.™Öu3³RŽUÓlw|þäÕùC2ŽŠtóÅnPÔüR`‘Wµ¬:eJë ÕŒ|g©3Öi>ϲ([ÕI¤¨W;ýÌš2“)®r_¤.$F þ`3zÁ ì膛³D!yűéi"Ô·BPïÇ×î.ú¨ir¦¾!ž¸»_#+ºd×6ª¦?ÞaèLrÐM¾5Ë}u$™o~ç[ƒÙnÚœdtKœ<†ŸÛv¶ÚYR‡Ÿ¿&¹T¢‚lúãgaj«]b‡:O(Àb[ Êü¼±È›×ô­Ôëkw ýøÕ¿mú…)[~YÊ–D,ú»‘r¶°¨t¦Fä=,›ÓF,L¿z ?ð«{ çvô!]n éUšË§Bh!¤òEчt´Â¤z%å4ø¶:yš Œå¸×Õ6MáÕÓ\Uj’`AÉÆÈRh+3çS˜·¥â6—×|¹wÒÕ®aÖxñY_³;ÞtÀËË»y¾jLfXlÖ£aüñmsº_Sè°X@à!3èðä[ÀQr}ûG¥ÚLCƒô@Z EçÜ{{î(N–!:þÜIj äÕ´¨q—»$9hS£ä:M–¦Ê'æ6u9ŽŠv¦“É‚¾Cðx )FU;ªÏâTr2|Ýíy{Å!Hrý‘²]õçöÜÇ®†MœÏKÛ)Ô–ù6Äæ¼4Àq§êm̓FòÛ>݈ ¼ZBøÚPüQåðW!²ön•X`¼W¾P©qšš þçúvå©Ãèñø»µLœÃÀåþØ"þÁå£pF_-µ7•¾ŠN¼BŠ»>×N’„A¨½§Q߈¼‘öe´˜.Ü˺~Ò©¯ÁĽ4ŸÜu`¥‹þõ°ü„ Ú›Rqü©Kº0t{:Ôö¤†%0µ¯ûú¼Ø•Êþ²ÞÒ/ÌkR4×õ¨t-Éù¥yõxŠë¯ÙØu?õVZ¦ßÝî–"ÍZ·„xÝÙö„ÁžÞ…YÙE¥ì§â¯ufqÙ{ÃåTðSUQ‚н­.6GzOŽ v;U®ž¬;f§ÀâGu³:˜AÙô£SÿBÀk’‡¿+÷ч[çcÍÜI„§OU÷?ê˜Fï™~˜Àš  ÿG&è+]¸7LRî¾oB7ʹ÷ 'C„/!Ô¹HAÉQÑ߈:mVÒ&,b@zÚ‡•9*L/"™0>û>?ò† þyìûfúù°S›qÁÍW>jŒ?šÂûœDi×B·Þ®„$_êð¾=;WóƒžhKwË¢ÊÖ^å»%IÔo »µœà ™œ9sÒ„é|ÂèýÐ ‹’6ù´¤Mš/ÅHöqT?Ôÿ rEm‹6ûRg[‰¯Õô¦!ÍÒÍ’½ü4ÉnqíPÜŒ#­\±m’„W†&KçŠv`dˆ%™1OiÇQGp°\6¥“¾"ÛtY\›Nƒù0ô×ÿ Ãçô…endstream endobj 1184 0 obj 5085 endobj 1188 0 obj <> stream xœÍ\Yo·.ú¨—þ…‹¢÷¾ãáN:@¼Ôq‘ű•¦E²ÖÀ²$Ë’ÿûžÃõùº²e´(ÒLÈ!‡<ëw–«w‹q`‹ÿÿ½ÿvçþ ®ÇÅñûqñþ9Þy·Ãü+‹ø¯ý·‹‡»øš‘ Ƨ_ìí„ ØÂð…aã0ÊÅîÛŸ—|µfƒ5йå°ZƒFÈÍ£RÛå¸Z;§åÔòéj-Ç¥fËÝ•—B-Ÿ¯Ö\ò9¹|Œ˜q”Š/W|jTË}|NÚåyÙô`%ðK\–÷.ae-ør¯¼x–_<Ày3Œ‚á'ÙÀ­VVq>HF7ºÈK¤àÕ§÷Ó{yÁ{Øyz4&=rËè’Ëøæ/»ÿðLa 78͵Djs sÎ.v¿ÙÙýëÏH#OÞ]­ÅÀÎÙƒõòÕÉÈ•Ó.¼­ÓžÀBÁF¹|ˆëôò%œgäƒåHp =Ðvy½Z«ÁZçP§}´î×Z1½<]C5ˆ[þZɪcx×ÀÇ`ÛòùK>Í”@"Ä]¯Êúó²~¿|‹Œ’ϾZÁ¥ÆÆ#ˆÑ0Oç‘ Ìºt‹ÄƒR–ót{ á@,Xµþ,ŽŽ,ß GpŒ©xåFë7sÀ$«gÞ}ÄZiA˹ iÉ ÈV{áQ K©DÞ='[¡ q% *º{j9a\³Ïo+Pm¡è.„Aoõ€•f@U¸ª>EˆZ(M>D®ñ:ïzZ¶"TÖŸ„ýhÿòTR&ÚàN'…Ìaøwö£ä‘Üÿ/ã@\J°0âìŒe¸ª„±Üæ… b’ƒ!*"zŒ_ƒÉ Œ_@ø&½…çö¢'%[N}1WáV•6â]D2ö¨f×ÊÐJõåJ)@ÚÀ»šMÀRæçÀ' !òiweÙ02àj².sA±üyž”XL26ႨG¯(óAŸ@ÆDE½Êü"|Gå>èþC6Ž}XINuÑJ|•ìù]Fc{* T%„êʾÕí÷ɫM°•ðhh¯%QZDNn:b>àèú»p\Þòk çL–Æ…¡ÐaðP #œ#ÀK.|'Ç]"üøSFÝG–}Ï|P3ç¶øà°’¿ÀE³g[þÞà"ª}ånd.ÎODqȲ ®m=•$pÝ®WíÚ‰J½Z™mÄ«àÉÇäÝÉóWù}¶'¨Ø¡/Ã÷Mø É;¯Ò aZå]½9ÐÃVôÓ‡: MBl]Yß5@ó’‚n@iÊsìœî8ë(d9™ðÌfWŽ›è±¯~\EÞ=.ö‰¸êP/ñcÇ=«ˆ×¡ðV‘23TÆl¦nš¹%LÑ—$/¹9Î= Š—ÚQ+eÉs©<®<êâ]b¢ûÀޏœ$~z†Mƒ^´ë}èIBá™QóâÁõH±kÀ}à÷EÓ÷ý§ôi “’ 2auÓÁÏÙ;ØcdwcÆ™´PUv {U½KT–ÈÞënÖ¨>C´Üënvo¬æÒ;Åfÿ1ÛY‚̯{âV' âü=< TüT6Y>~'ð%–j÷$óG%„¿ˆŠ Ú! žˆÌà7zÞQ¥ÔåIïZ{-­¨‰ì+¼¾ái´F;o3‰>³VíE¿¤o9h3tÛß×P“pÖòÃ+äa÷»§Ey?–w‰JŸ•QL~hÌ(›±–øûûåŒ$|”³JÝ7)0xܦ¥J Ä`6öõ‘øÈ½bJ.Š)äu«¯>’›¤:Zœ¼>2«²à&̨ª *ß>‚aLJqt°œÌ™ª)`9ʃ5â ±³`oÙÍ(hd±(äÕÆ #øàjƒ† ßØ™ìÓ”Æy¹ê¢‹Ú&&?_òWçÁ|.ÏÖ£Î4û%ÂÐSDAÜÿQ¨Õ° è©6Éè&LÕMª‘o›~ÕO¬4@»ïãIbzjÀ‚òû˜,M›š|sò?)UŸß»²žðÜÈ©2u"äyGƒiËQÒƒ_ûO$Ä(-NEEHrh¾¯ÃÜÏQÍ€õsäñMrgfÊTÕÇ’`tÅ©*,Eo"‘‰xÀ‹©Xu˜TRJÇCyô] ò‚Fw­G€H–/×~P‚"þ­ þ˜û'Ø=­Ãv—<̓»Û.y–'ç1†¾¸›ÆU+Àpiíº+¾Nc»Í±`èy|èFŒ¬%$^NGEø­R¼eüu±=']#æo¯ ³¢L÷ò}Å$tw-f=9#î€]ˆ˜Oá¯Õ·1ñšx} 9”> 䩹—Eñ4KËafÕe~ºŠlFÆöóŠ‹,_{yö,Ï~¼qw6 0æ\1®1&.ÁÙ´!à›¿¤Ù¯§òÕÎý§•½å÷yîÅdÝKøŽf*¿Z¦Á·yÁû4tœä¹?O6;œ®C¢ ¬ƒm§'qSœû*®x”fOóìyú­ …C@˜ÿ•<îUšÍïgò„#2kâÐezøP߈NÝ›.#—™¡¯ËÉ×àk•åèÙÛu'~’AŸ÷<ðC⌯ˆ Y§ëy Æ>Ür?Køy–¹"JEš7Î>ȳ… /óÓ÷yöÛ<ö¤c‡‹“û]ž}ÚYûO²ÂIƒQý¦/{)_'¯(^îa0WYqç®'\ü•îÊ|Ç8g‡™"˜ô•œ~r²_©Á¤’p!г6ðŒ.öW•` ßr²‡·à©X'UaZ¸°æM[ŽÁÀUuŒD&ý®—‹xúd ®O'þz>ˆAß á¹¼I»ƒ >4ÀbÉ’Ñì“‹6†Í6Õ•ñÅ·#x¶Ür¨aTsïò‚¬é[µ¼wƒ ÄÎV JTÂv^>1›ÏH<ïW÷kÑOï’Xp«¨×¹B8áj›ÃŒ|ª­ÿ'fgûK8‡0Ìñùa‚“ýrk“ ô}:Ç­8Ô™ù£`ï¬a £äüÊ—/bÔŠÈvR44²)C¼ôÂs®è1éd$æ‹¶—)óT£ïj¦ƒÊ¤Arþ)t€ò '»¾ËÙ¯ëüDú.}A˪œôÞ´NÕ!êY^~U0|*6N {9ÿ¾bbpF&§àsa©¼ i‚ì²Ä?ÓŠx§ö‰%àvÉ?õ›:')ïIJ§‘âzbraÚåÛÌz¸€mWýûÝ[i«6¨jŠ L…²·J‰˜Û•?_!"ÖiS«S9B n 9—¶¸é¯T¦gÙ'HEN™mUü~S6˜åzðœ®ßÛJ;AAý‘Ô´ý=š#6ƒ&6»ãr:Å{ø-p¬¦ÊÝ3E—Á¨ò}ß7—B¦Ÿ—Wˆ;aЩiI`nED®ÁÿuÚunEÅC[Ž{éq¤*2£Ü ]nðñF‘êD>ðfzNûÉ×¶4,U°(ݧÙ]ž1ž¿¹Ë•cöÑÐ-šüÊ–ÓÞ·¦U]’Ù¾ôÐÍˆÕøxóÙVªÔ°\Œ¶oªêÿxd¾AÁG«ÔÎö[ H[À¶I•6ÃE ç$«âg{4ÓãƒüÂM?ÃÜg^C»­„”:Žå§’º?NéyNÒò¥tWÊy¯óS¯Œø²aš-ʼn‹ô´1ƒwÁæ¼x•‡ÙVŒ‰s8âÔ^H/3Ç£j×G:„Ó÷b¿W›š¬˜ä3Æç¶† »X\Â&`?µ¦8bª§?Ù˜öœúÖΑQÅ»®lJ‚œD ND;Ð)‹?ÓŽó¬¬Wyã/.@ôlú%£WÃY%Izü¡·+þ–[†aC×RLÝ ÜÒ¼ÆÃ‘Zî Çú„‰Æ`I%þ;ÿïQ¸‚\Ñïm!Á5)/ϧMI °J傺¯ø<êÈú§ ¸Ö(”·ýMœ±àÄ8 ìsEÛÂOlóV×Õ·ªÈÛá{ˆ[Gæ_·N´ôx'ðÞï4žòª*úfàt#Zò€-¥Ï½¡Ÿ9nÀQè$Ý#0ŽÕøz·˜þ“Bmäsÿ5R(pí0õfÏóØ~§ð}{߬p­%¶Ù¨Ï Ç?„°K6¶ò2ŒM"´ŒØù/vUõendstream endobj 1189 0 obj 4421 endobj 1193 0 obj <> stream xœÕ\YÇüÈ_Á7“9êûpvä8 â{ƒ<F²Ö2²Z­´»¶… ÿ=U=}TÏôpH†”ŽÍ™îªê:¾ª®Þ×KÖñ%ÃÿÅŸ¿\<ùF¶¼¾_°ågðßõâõ‚‡W–ñŸç/—ŸœÁkÚð¥ï¼F-Ï®ý|iÅÒrÖ1|¹ønõåzÃ:˘Pnu·ÞèÎ9ïåêaÍàSå™_ýµ|õ*¼à™V«ÛõFHÕYiW÷kÙií•Z½]oxgŒæǹœS…ïÏË¿äW¿?ûóâÓ³Å׋×K)„ìD t£:·ôÆwÊ-‡•ŒCî?y¶xòìóåÛÇËÅ“¿-ùâÉŸðÿ>ùêðϳ§Ëß,>}¶Ä©ðó0 æ±Ãy„‡å÷™gB¶¢-[ÎDçÔÒ8 —ˆ×xo¤‹7Èd$ÞðÂm~$â©xâÒÈwÔ6”© SoÖ¶sŒqµº.Ô?–Ç—kØI/@9.GÊQKb’Qçô»aÔ‡ÒSN¿Y«N åM¢^ɯ{+à\'FAËûm”Ìr °,´g.}e¤[]¤W§øÒþNΧP²ã‚²ù4:g8eô öÖZm$n|,ÜßÕ}ÈìO±§¸g8ˆ½I¿à8GÍ8ÆT¨;†‹±Ngó4lÙ<Ö9=ð2äÙïߨ©“Ê¡ Á'ø´0=ä§ûôë¬Syl(5`ã÷™Ð»ÌÆ«<6d½Ïc¥§Y7r4֦̋Áü”­/ˆu}YžgýÀ;Øƒä †ªdíHðÖF¹[[ÄŽ<  DSV‚ƒ!s_Q¸•,'Ñɧ"-Í3YyH®7†»Îhy,½æÒ‰[i–€4tEôõœßÎŽmÿýšôF¦÷&ÇØú)hÀü¬9¼\ Ñ)¡9Avt®› „ IpÀùAà¨`Ï9•ò†°Í}­êøØÃkN£PA·ÔÞ£.„ùÏÖØ\¯¬[½(–îA|ÊwÒ+‚¡‰ÌH(~^„J&xoÍ[y'è«8«´”r 3¡Lg½]ýLàÛ‹jVyÀ)€G‘¨q6m;Æ}pJÜÏë MG_ÅuO< /Êdc&‘‚–Ï®Âj†ëÌPóßµúŒ8×(pØÒÕWð»p yB c*)¡Àý“aÆR d«oÓÁJLuÈàÙÚÁ:z›¿¹+ì‘Ý"ì¯Q—„Ö4 =g .7EhÄXÞ®µ™½úYæ¶)ÚJX#Ь¾ßì(BË } ¢òÖÒn „nòÁÕn É3¯teåÑô†U£‰7.ç?ãe¶At^ÁÞ%ó¯Ls¼áº7þ ço‹Êœ¯nÅ5=Œ6ºSj_xÖ2·ú, Q7p?PÔC¡‘AO¿KÁo8Kð֎怡Êwý\àLº4Öå÷AþÌ@ƒ#È_|ß)pJÿ®"îD(Š~SÙ,®O‹ß$±„ìÅËvRM”sd´;Dˆ¸ohs„}ùgž?.c³ÈÌ’¡Mé4$¢Ìý@äÛC$O‰Ó/ˆDIÐxIwâCt~¬ãÚÓ^Œâ¾Û‡ àÀJy>ó{3ž7ƒ!Y*FSþñ‡¡÷FßuU¢V;–! eèZ·•›ëc§/ðDÜ2Q@ UJwÜšÕ?ò»mª}gEŠ´<ØKÈe¤‡ô)¾ü~Ydšx„j Ô*8KÁdšùzO2’0¢oÖzÊ7+ð÷K ªc*¹æ§‡F *€gW‡/ðXphUˆè¡‹4TMÆàtã½2Ø®]½YCàÐ`Ðaè´x á•q>Ĥ°"ãKeB˜Š>Ƨ šéñ2Dtûb*aê [ãlvprzÝ K/"Ì7ÃrÖëÑÛ58 Àþ– ëŒU9±GòÍì!f2’ödR³­•G •L5¥)“àW* t7ôûU¯9ZzÌ5X'½®”á.ƒ­þg+¨×§ÁU½ƒ< B ÐÛÓÂe)Œ;–2UË· s¬íß —%wG˧§7:¶Dïÿ$T>@ “ŠÄ•>T>hª–NrÅN‹;Y¢[„(âN>ß\”4ðäÔE $Ô}Žu)Y©L¹5RG¬ÎkR=àðOÊguäC%²­6°ÿ>L*.æxGœ‡LÕ²DÔ'p½ ̽F˜sÖNN]o”ºgÙ¹m½ÊƒÍÔ¤†Ä0v)Wbfëàß6öQ*ɱ\(l癥ÊßL¸®éWô¡Ç¯|` ¨W¿Šñí¯S#0K;N,;hª†ñÁ<ò8½&3ÆÙ“¸Xîl|§§.¡îÿ×ø*ƒBjAM¢.Œ­ºþ09™ÄãÈ£MW© %êNŒ4é Â¥Z£uç3{XÜ»>i&Öª#EΦÚ;{„\ÍÇålä1}ÔÊ›X;¸R¦y×ÈÛD§<Í™~óŒOÀ$ÒQYœý¶´3öG6©ëëçu8Ñ3¹:güÄ ]h¦*qÐj‘¹×i÷CåÇѪ¹e' 6 ¼}~Qì÷‡ª­¤G~ÂR‰MþЬ¡VQŽDÌP-õ¢ÝTÖší¯4j ‹p*µ9VMž´Sdk/Atœtª¹J,éŽ"¥\r&O*Ð3[íƒü«ZîöVj‹7a;äÊÞu£Í¸4‚ü½ñëÛÄðé’ö BtxÎ h×~Ì¿Þæ±«qKJXAì;ùOù×ËF3QnyŒD”ñé–.½QX˜É‚ÎÃ(ú‰‹,Fl®*ŒÑ+?¬øYç‚åZé(fK;(GgÖ‚xÖïüC&y¸£•˜¶šCj3å;!·õ/2«¤<@!:åÖ]ž.ƒ@-‡yöŽû÷öK‰^’\ÔàmC1w“.×½ öŸ¤t‰%Rg}:5B)÷kZÓ¢WO-=V s}+;å9¹àÓ Éü¬ë]É MåQ=ÃjRž–Lp^Lÿ–ß#YŠ'h |[¦@rã td…tÆæubà {!švàžÇ ²ÇÝ`"j½í7˜^›¾„½ÔJÒêFöàÝÿÅ„@Åxºq"±"¨dpXo^°œÉ~œ*JcÔVJo;LÇ"е kOé][µWÔ.0a‚êîÖÁ¯;)Òª¥.JÌãj ü:i«u_sc”6¬m„$c§xR³'%­Ø'^Ë;Sx~4•$Gåó=‰QóÊ`¡¢(S=ˆÉjêô%ÞïûãšC.kµdbؤ%É:Õ÷ÐT‰ò’S.Œ®³Må× jÕú¥M•%L…ïS /×òúD\jyÚ€2}ã¯rÏݽKxÙ¼JMúóÑ¥´ÛLz¾”v™~^HŸàJ3þ®¸Òxýʸz3¢üuæêqôÛ}‹«ÙB“ödÁ¥à~N=ezªŽãJcF¶“+ ˜ÝŽÝÎà”ë±]HöÈRÒ+†Î(–Y&ÝEŠÚÔ³’`L_•Šå†}æåÙ=ädÂBÜLœ?VNÎ(lü&ßÈ&ÿ=·‚xÏyÐ9¬»V*5s.а:ÿÀ €S[+àÈîbXÄåA»v0-1Œ‡ª¦Ýíµ5Ó¼q“ñ2ÉwGÛâh{ã_íá¬^íä­"îF®‘Üg|d5¸‚Çq+ŸúË";–jÒõÌÉ•œ¶áPa‘ö(`&NµCe]¸§´_?jWeJMœü¡‹ß•ªÌéÕ¿<’ÖšvÀ½õZ,%$ûQ¤8Ô3õ±<óXu‡å&ŠÈˆAÝ^ Îz*ª5ÆÇráµ'FEu¼vؾHÏ`û-G9vBEUcÐÝ8u¢AY Råð$(Ô)Ê—& fX÷õâ?3•åendstream endobj 1194 0 obj 4089 endobj 1198 0 obj <> stream xœÍ][¯Ý¸u.úx~ÅAžö)r4¼_zš6H§h‚$5‡ \ÛcOã±=Ob ÿ"ýÁ]‹¤Dj‹ÒÞÔÖâ1‚‰mê[\·‹ùí=ø=Ãÿ¥_|s÷Åo…a÷¯¿¿c÷¿€ÿ^ß}{ÇÃ#÷éŸßÜÿìYxŒßûÁaÔý³¯îbpËÀ=&î-gƒ¿|s÷ûÓÜ Ü{{zþðÈc47§· žÔZðÓLJG=8ç½<½zxð°Òþôu~à{¸+í ?ñü¬Ì—,^:{àQ/ÆíéwjPž}z3{Áˆà¶ªk–PbÐÊŸ¾yxTƒÚÌýþAÚ0cã•öJ²éN¯§×#~ÉÍÅ釀_2ËOŸ¦¿X<)m’4<9J*=ÂK¾Wžs > aá¶<½,›‘üí¼äL?/þü.Ëf/;B‹²'~|07¤O Hè¾ï°{@õZ}R4õ~zë» ú§¨T?XøûóÜÔ»‡ÿ~öwB;°›g/ÁL>%pE'}ü"ÿòˆÌ2ÍKd©gü¹`Ê ÖùRojÍ FÇ'‹ž‹‚kÏ\\‚Š -tô.ÊaàzxdÐÛÌ^>ü¶¼„¾?…hÞ>p90&°ÎÁÀ‹?Ê/› F”_•‚ùYøYñl‚kÁcþšö«y– 5öˆ*{ä"*­ð—¹‹—¾ÈwsÇÿ_¾‰;x¥µÅÆÁLlÙàìLﲿH^=@L’ðäëj8ø{R|ò)ô>(è³"Lå(PX :—vƒS³·¾O*~õax‘»¿@ðUv¹O£=óJœ’.'Dá«qJ«¢÷qjü9ú±’ †0%À/…‰³U§_6õìáQÂK­O¿Æ.s7®Éócô€Á\Rùat¦EL *T3Øfc² Ioó>ÖƒDaLePMŽ$yþÞÇpŒW¼å¬ÙúÐ4µ糈ò&¿ã,’iÈÞÉòXñÚÉŒFÕƒ‰º³XDí¹è)´D}>BÐsðÚ¨Ö™;Ž.qC2VãS”0 Ë"H,Oü"Ù}s¦Ç?ÏCǘ*‹w}ÊÌ<&{}uÀD{œ÷tvòòµ©gµØõV>þÜ´ž@w&å©©É7\ù‚ÑX!:.sexâ,WâÃþŠ“"bƒr9TD,~S0ž¿f´¿ÄT$ÁªÜŠwz‘˰y.ûâ·zΑHbPÒ»ˆõ¿¢’™Vh¼¹ÙØP}6³šŸ?»ûÍÝ·÷Ív胻·dƒá8BwX2ûÙ—w_|ùËû¾ûøêî‹ßÝó»/þÿïg¿þWøçË»ÿ›»ŸytSƒ‹ípÓ‚m;¬­Y5µ´QÝsÐo@uJU: PH\4““»<{°IzÀâÈÃ?Ä+kÈ R0ÓeαÀÛ"hrðç`™%ö4"H‘‚ÅHáÚ!XCJöcÄÁ`‰2­‹œÒwÎUQÀc,tz…Ã!ˆÂ¼ŸŠ¢Hï!¤\EÚNZQ0êð¢&Še0‚I¢(@.DAï£Pë¢h)õNïXsYå½?Èûw5Uõ~hI“ªÊÛ8lQž—Šºb£Ï_vpr|û‡9º_þý 0)íOÿ’}å²3“Ã@+°“/·Â—¶ÊΏƒã.qãíË^º÷ªk9 Kâ險{©ƒ»x© ņ Þà¥Ôø8Ø63x$(ïpÙñêÍD!ÞW²•°ƒÉJâR{Ð5…0n°b†ý;¤ÚI© 1¾Àœ3¡ð×ï’:'aP‚l¼D3¿A¦@D­áäÍ…WI3È#.kF¼‹f$ð‡ºf”mTŒL$Å`øº"ÔR+FI18UQŒe>¹ ^½™XÑûñjU1J³ލù–›ZAàßNÀ?NWù¯Q+Ö(w•V¦DÒ®•Õè÷¨D²§©z"±ŒLDbA Ú ‰„Wz˜£»=H†¡Mj¦ªáæ {5éÃ4ä8½›®Š§__‘Q¨U$Àñ7UÔœP€,÷Qd®ÍJìxå…Nš‰±[CSj¡Ö‹g5ÝZ”•;µŠ ‡aAqKEgùãÙ¨¬wÓ½âÁé×Wä™v­&‡ÄcŸª©zž1XIí‘g´Å÷=ʆÆò㘶!òSããR…™žÞgúURõF×tõàƒZÝÂø9?ƒ4À|e˰ÁÀÅN PëzÌ…˜‡¤„vÜ«qœùÃÊh{šª§ælã79)AÂ;.c˜/ÏG[s¾S^ ÉGàòªh^VY ¹×µ_S\Â…\HþõGÙ°Žº(ÏËç€7…õ…¢<+ÈFeUÔÑl—ëÁJaNnZÈãy\EA.›WaF«m÷`ëj2>¥YjïÁ­ .yϘkBöÎ#œ¸ä<³….Ss¦óï÷8O`-Éy´\8þyÀ„¦:È&…_qžYjßiK!Ü!´¥÷×ÞšƒhË®¦ª´ZjÝH ™¶H—·ìÈ´Å^O[ÈAr>6*RÑ$7ЕNï™$ÚI[´ U6zÄ&,™®ë€ˆ¶¸¸dš^6–L—²]W'˜ÏßZ' ÷#¡õE?:„ÀXÛÇðc¤ nt-‘}Ü×Fïp£ÛŒìãFàà+nÔ³CîE‰Ê”bAevà^åÎUßßÕTÊ8ݺ+J;•±nÚ*S×@e¨ArÁ‘—@Ï¿-˜/DÚÍdâ¨^D\RRaÔR ´·#ÂçmôˆÆ}JÄô!ûhÇ ÙJÙú`ÈGhsÉyæë¬v`xç.¬ÑÝržkù‹õ]ã7ÔN5;ÏmüņyazÙ$[qú ¹ïŒ¬¥îÖÒŽ{•jXuÔÔ®¦ê¬ÅªÖ]¢ÚY‹1èSg¬Å7°jœû§  D¬% U uE)|9Pʳ—´0Þ°¸wE‰˜¾üâuÙ¼V\Èö$åj/Âýk…Ûô¢cè‹u16S+Nà±›^t-{Ñ}¼÷ed®Ù‹nc/ÊvQФ/êZ}¡v¢‘ÇbÂcÚq¯’#õQ–Û%uQIAû3ž/±oðgYÈa긥À¹·RdÃfôˆ- ³ŽUS¡ªÛG8ŽŸËÖ±RDíãñLù™tÅ'Ç列WܼB9xÂvˆ£ÔÊqMÖ«\Iª¬p]\EXHU£«ÜDª˜]\E‚± ·`W>Uxt§$ú”õ¹Ô æçž‰žü‡^tð#)jQ¢CEŒ:HŒ,²îÙŽ{•ú…ÌŸ®©:‹ÄÛ¨Y¤àÓéN™EÊI ’s2L”ŠFšð-¼‰ø : íÏ%jâ‘ÊÆåÓä85 ˧ œ{ydª’#ÆÆVL…ŠF*ÖGUÜL´ºÝᇉOR{»P)ôe9á“2¦qj-áºu¹í2×òIÆ»¸Œ°²Ùan!“ÂÇôH.°Ö0Z²OC&pM.z܇¯,º'©cÅH+ 1¡•í¸W¹ w‡ÍÙîiªN+¹%>{R†CvÇNŽGb\E+©A¦âd“hžu,Nrêjk,Ní*N’ÃLÅÉçÅIrÄ©8Y îVœ$—-' Ù:'©}ÏM-åoÿ2?àí+ò5ì1¯-qß–×Úq¯&#f›¿ÛÓT=¯1C|Ö¥ eyM7ä5j©\R¥Jl±\„ž¸Ë%¥D{Ê%ô8c¹¤Äy[¹„q(—”€{•KèE å’R´')—P{{Ìp¥˜‡d8jØ)ÃUpß–áÚq¯¥%áõQs »šªf8h‰øCÈpÎŽ'må×°³-9F®dèÕŒ³zŽsqY;8xë똙 }⨑¸ÅE!Ç¢Ð9OÅŸ_œå¿½»µ¯„-rŠ”’7t¨lqU9vwë> ÄèuAó|׸{ö•N®À1€gÙˆß;`¯]§Ž*âíjª¿$>–â÷rM`ßä¹pXL[ Ó>^fÈ*VСâÑ”Š£©ní(ÁzàýÛ‡G3pÆÀ±Ï£õÙPk#Zoö3ѨÈûÀùÜýªCä¦(L$[ ¿>V\g±þ?Ä,r5ëá&_·EÄ»a‹ †\nÃošÙ\¤¾$>ÿO¨…-Ò/"7Å1¹:jèÕ hÅQgþíjªžL­ >ó’)šóy:mØd’#'¹ œ;ªôaÁ­0ä£7œ¥*ð~VU†èEß xZª*{á)«"7NaØã¼6Ū>Æ ¹|Û8Ÿ2År×Ç8q9EÕ8{®!·Í1ãf)ɹí°W¥á‡Õ2÷4UϹ†·(q­ÞtÞYNº {$’ƒäÜà1¤%нY—…µ!Ðñ¨[¨%âÏ)ïZÖžÐwˆ4³n¨&Þÿ=ŸÅúê‹J0ߘçJ¶H-’`1Ç^‰fˆNíiBóKžv%…0º§ ã.yÚS’æûxšä"™ÿæçŽêàMŽ&eüîŽ^"©W­CýÚÏF6TwjǽÊa4;lj`OSu:¤<ùQ£øAÄxŽšœèPÃV‹ä y<-¯º“‰x˜šPÔUÉpÕc‰ø³¢Cqs ún°*,X*ºŒéä0Ô"­[sY$âu?ä>' `_ð¹k‰‘èãsÀÀ.ùÜ“#ÓÇ瀭øÜáĈõq9üªûÌŸ¢`Díq#E*Ä<„"µã^å5Òu¬é®¦êI:ÚÍБ"I6Ï–)RîŽä q­—›á ¶cp'Ù¼LsÊ2Ô°…ŠóîÂ;k'Ôö ÌÑà|c½^^ÎQÀ—BŽ’Ôå§B(+äëœ5·­_¹¦EhäÓ"´ò›ÊÀóù²»—Kî€í49ÉÁ µâ=]§h¨GñøAW!&M³ÙÔzSqMÓ2Ð’Ñø¹+½tƆ±Ã†UžñÍ“¹< Tíš+xi»U®’I¦Ž:vWSu^Êùq°¸ÙŠZðÒ†ÝþÈArU/~õÀù`=/÷øü:ó¹bƒ¤< ¯qŽ-õLÍÁK‰k½0†™ËVåFssøàU§”ñÀ$è%rðžËÑT©m—G³8³EçýƒnÙb™Á7¦#ã’2rÅ ¯ê¦8#×Îo| eú¢ÄRÉEyhjwÔv¨8®Èâ3é¾yÀ£§‹iõåtUXd¦¹Ÿ. ÕÉø”ÂõŒsþ§RÁz¾I /ï0ÄEw ì€:ŽoÚ]Á®ÝþÖØ ÷ò¨)ç]MU‰÷‚ü¼Yîôtn^&F ÛE’ƒÄ¥Ð0f/v Fqrx)q5Ú‡¡E)3²qÁ½H`¼ê ‘ˆ aäv‰Ë…«vIH’œïc–¸¿|Ý,fI²Q[1Êžõ%r›T\„AP–’„.ÉNf¨p)³™ÉCÖTT¹<0ÜÖbÓ ;Ô“vXá*×GѦ=MÕi“ãäGÛr+§ƒâ2mjØ„”$w3œ> »‚)üƒ[êZ˜2ÁO ð1ŽY |9ônÐ7«ú5l˜ãü°I8x©Íx?TËSÍy¶vkB3l•A/›ó8[ ׯÄEîÂ\•¾ågóWÐ3ë¢oS«FÜuÿ˜rR˜Z›èãÂëKîQ¡_«É×JÁûxNXJ,M-݃¾ðFîqÑÜ\º—æu~FÃþesä ‹Ëææ"õ[7G/®›cÛöHVˆÛa«4Ð2}£ÜÓTQâQ‡ÔŒÒˆéŒ¸Ì(6F&‰lÀ°¥z¥ŒkA£Ä‡“ªà%øFJ©b¥‚¨¶¡RQíÀ)eœ&k3Ùž¤4Hí)ø•Gr°á*;Ø¥îã*xô=CßD/ïã*Àcãôà–¯M0¹‹S…ÔÂá&—UWéZ°¤ö”´ ®“ŠgÆqäzK+âJ‰ú­ˆ£—.¬ˆã›vÙ£„Ùn—«,QûÃ&‘÷4U'œÚ‘€Ë£CœΆ­ÃÉAÆ=)JœGìIA;žx¶€}ã‰gä°3¸ýQ‰;¯M~39lžlÉNüz²7±HÎB]ÀP!ÔLžwg¡¯®Ü¥au1vú‘âÕø¶Þ ÖÄHFÞ Ö§î>??·C] ÝfWck:#󩚪‡ieÉÏsųEÍ"L7l6M2…éç!ašv Óç°o ÓÔ°;ïí¼ÌQ:,“ õ†D²”糊Ò2i•ºlœñ,ºá)hu»ñ®Yi+ ïiª¯¥!?K aÕ.VM1í´_à,<ª¶÷Võtåb¹å ±þغ£Õö7¼<®7Ô'ò·Ü5g¼©õžö}ßÒ;ÆíºØu;™Ñ7œºû@ÓGï’»ºÞ;LåR«=í ZÈvÄm;`¯†wKØø50çÔãd"cÇ<ɵöÓfØëÚÿìr…ì£}\I.Êï:)C­û1eŒ2’0ÚA¯Fy.:ësWSõ„öG0˜‚ÓSÊh8gƒ#—q]aÆYXøë) 7¯ëš…}8£é°ÕI>GªšóΦq f)Ìb æ «Ç ðéEs"vá$ZÇq µÑá®mŒî,Ö^6:át£Ã‘M»Ñ…D™ŒN˶}¿eš  U‹ë0¢¢6¸1=fÙIí°W³‡•ñö4UOŒ“ÌéÕ ¹÷ç)²áœr”\†¥û3¤$É4¥å©Ç„šáÙ03ôäYÒÚ˜Ées ç‹g²1´ 〖¡µ c.›àŽ”)º˜ ¤æ]&x[Î]Lróš v`R[`Ê 39É¡íÀןçGÕ7÷´TÍ ž‘åˆ}%6A ’+>GyÄÓ†Ò‘£‡EgàéG˜ñÐ8rÑîï6-—v³¼lGc¤¶#aÍ;jÏ€^t±£øUe³Ý”ïbGøU¥›†êŬԃW’µ!¥\6ƒ|D.kǽ–€¬?êн=-US™õ´·B*³Àš*©¬a+zjqÝÜ ç ç¨a íp_€îÊžÒqýÓ`7ån]ù×®6™ƒ7RŸ­çÏõQ#ßokTë“Zå<(Fà–)M‰’uO¨÷â²è$õ:j{Mzég7èvÜkaÕ¸£*{ZªhcÉO¨CÓVLœè†=™©AÆ=ÃyD€¦†-4¦g°‰ã³ÂŸÃ©Ï³øýùL°'БS‹Ž't]#:qaˆÚrS¨^zÜ¡º÷Z€Õæ¨Óž–ª¡Z¶à¥ŒÕ ×G.cuÃ6±ä(c°ž="X“ã†@„v0N®eXN¯¨Ç Îàzã™`O®EÑ%¾FÍE¯•h¦]ò®ç_ºŸ/Žœ–Ü]ŽÖ䦛ÂõÒçn ×;€¯EY¥:ïdOKÕx­4ùi'¸¨­®¶§¤£õ çÑš6Þž~â€&¼ Kbb&Ãã¹f¢×$ÊË€s­¶Ö1 5¹@ÂÄ~» K’啦¸¼ô®ãr;îµ`*Õ ØC£Î¿íÕ0^8÷>õxÄîìI„+Ϲ>Ùñæ$ýoîþ$¿¦úendstream endobj 1199 0 obj 7588 endobj 1203 0 obj <> stream xœÍ]M$¹q5|ì_ÑÇîÃÔ$¿™G­$Øk@†e àƒáÃjfg´Ú/4£Õþ{ó«’‘,²º˜É—5°ÛªÞf½ÈŒx/"ÈŒüø8Øãäÿ—þýöLJ×ÿÍõôøáïî¥RêÄÃ/_É“}4–Ÿ¸û›Ôi²þ¾úúáõ×xüô·Ïß>¼þŸGöðúßý?¾ú¯ßº}ý»Çyøý×ôK¹?ë06¤[‰ùÜJì${Všÿíáã ¸Ó¿ÞþøøÕ›€=ÚÓ¬µ°oÞ?D«Øã,ÍÄOB?¾ùñáŸÔ³ÃÂô$žLüÉðÿ{ó¿óPÁÉ&c<À~  ™þœÿùüj:™‰1!ž^?¿§IÎj~úÿXϳ¹› 9›+{âr…ûoϯØIYiž¾}vŸÊÙò§2þŸÏýéíòëoüOŠ+ùô)ÿ‡ß…ŒüÍO•[ÆÍIgå³”'.¥õΊ3}6ÞfjzÍ¢ˆXÌsümø¬vaš >éuhƒ'Å_¼—žNÖÊ™«§¿.¶UîPú9Ÿxþë¶Ë sP¤Iiõ”¡¦gãnD%ÔüÇmÜJµÊšüꢛuóëÀ¥ªT­gk ÷ÅÑ´ž'÷yIÓövš†ƒŒ4MqŽ i8lnœÈóî÷KhçØÍáþË3ãŽEE$²÷ù—ïn agõ†1‰å,tJ¯ #´“!×X©Í¸LˉõmÉR£ÔOY¿}fêd„Oÿ|9>Îä w´D®²“\7àn2¢5½2:t©:¹Z#àäjfŸä:w+d"W‚s¹¢as©½³SÜXr5JG÷C'÷ν]BH »sr/˜L®6]0÷½rez™|f'£¥L™°ÿˆ\|‰>úËÑ6RMÖ+ÞH%J#³Gæjåûs–ƒ¾ cí¬/%GìÕ—~ÜMQ0º7iºT]_Œžüƒê‹bî‰^ôeêÐ4Ȥ/ç}AÃæÚyà 68wOô£ÑEÉ,y® »O6Š#½`ŽœWà¥î…=BE†‚Û#laÏ^-@ÇÅY ÊxÞ«ý¸›®Õ4J ¶,U×íòU´¸ Õ^hìÐ4Ȥç-@Ãæ³­ÁŽøºa/¡Š†-Ý×yª'¸—Ô9’åì~z·üô]6$kݯç_7ÉR ‚D+t*æÓÌWöüiÓ~3͉AýOeÝ´ú¬mvÿ:­NëÛóv™ïÏrË–jÛï*·©Eµý~×äG%†uˆ¶,U§Z%8œj¥¿uÓª¦EcLL›a!Z4êD´ê½<‹F-üž$§° šõ™è~šå.|}w_¢3<®ý1²r}¼9Š»«MÍyÿìªcgjDº)’IÚKú¼^1²mšQæ˜;å[…«;E|ë§ë Ÿ«‹|.Z…ázü¼ˆÌO"ÓtMepž?Jd¶,UÉf¡"#¤³¡Ý!2hŒId2Ì!"ƒFD¦@½WdШ%Æ2ìwV.ûàåÀ ä%dlD tu"b³?„I槸« 7ÇÅ‚O²9Ç$óý~×$G1Í£xvËRuž“‚ó,ç¾®,ˆ¶ãœ"d"Z‚sÓ¢a'¦-aï¥Z4l‚á{î¥_ßÝʵܓºÿ&!°âÁ=+Qƒ0)½\„7Çù¯ol{ð9}â[¸m&î¤Û¾œ¤¾?òš ÁæaM¨-KÕņ¹š-6ÎOÕ…Øôœ¶DƒLbCp4ì$6%ì½bƒ†-ý¾ï 6„š ´å¾\¦¸ü—­í©!Ž{Ê.¶$9þ¼pRþ“òøþUŽÖ©t©MÐbä1É~¿36Is²Ãú3[–ªóïdæÎsóýü;…CÙÿöÈDƒLüKpá_4ìÄ¿%ì½ü‹†-fú*÷Ÿ*É~íTO³xjÙ}¶x‘ܹ _Ùs«xto¤’¡ÙBŒÄ64óñ¶¹ï±k‡ür €þhl©†šõ¨ÆÕ¦¥ªäVê}ƶ[€”µþþ†k¶œØ„ƒŒDqŽ 8lnýÙ@ ;Çw¦ï[že[WÊά˜ÚçÊñE¤û­<½rVŸ…Ã8pð¡ h\íj,羿Þ~œî4Ò?æ»2#óêÏÏ‚ôäÈòrÂ1ß—2›Vúû—÷ôe|Ø~·¤ »GÔN¸`jvÁñ¶é9†ë•0º—`nðߦÊY5ªù¶i©º`ZÅ¡kzÁôTp!˜¬C0Ñ “`œC ;Vl°wVlpØ~'\ñn±…æ‡ÐÎÍ™[ö¿c§Ì--Õ"ö¯7<û•òI…Nú…ð}~G(èC­ÄÏ€7qÌ‹ñöè©p¢/§gÑï‰MÆTlXûcËRuòU ;áӯ˜»yËbp‰| Î!䋆ȷ„½—|Ѱ%3¾9Iqç«¶?[ßsK÷"ž…s_Îø%÷…=5s|?ò0Þ½öªÜÅFùÚÔª˜ÞÀ¶ý®×¤H¿›0ˆm·,Ug[ÿt$šm]-2_°mÇ“Rp‰m Î!l‹†í û‚˜à^βåS2ñ#ÃÄ-£b¸eqwU Ótû«{ž “£ËÄÉÿø¯Ï¯\¡<ÏÌ–3ÕÊÉb¥n@³Þá,ç «˜8£/ƒðó‹WW¡¶Oûqþ¹rø‰ô;n¡¶EUÑîy.iˆq UÕ±*@ß,?áB¯ M¸‡Ä ŸpÁåUï+¤3Wu•Ú¥Ú»Abûý°©‹ÜkLmYª.±ÜÂç˜*>-³ÿ²Äv<#™$–à"±hØ\éÐ:'¸wK¬‰ÓØGcñÄþE),¥ú*8)¥¹ w˜àwTÉtØv'fæ2(Óö»Å¶­b+§dº&—a+5#¶qž(Þ=—Lr\Ûï}M]dfXûqËRu‰e>ÊUMó2R1KlÇ“pIb Î!‹†Íe8„Bqï–XSJ·&ú<Áþ%i¬ûmôe,j9¹ 5ýKí‘ü·ƒ¯L~Έ·È]9+_´S˜£#ÎÑ3ze&W&<ù¿[.)Iß³„É„>Äû\Râ'‡]ó¾# ó~?lJý¤G ýÝ´T=k˜|诜Í2>4g ϳÂAƬâ’5 aóøF;Š{ÖTsÜ n*œ¿'cÿ¢²†X Á/ƒ?Ê=óÕe@e 2<ã‚·H˜ø=×-B÷бç·ËÍúÆ¡¦ÝÍêWLûåÔ"ä~9Þ}Ý q†~ßk ½œå¨}MKUs·vZ±õ3c'\VŸ§Æ²ËÇÏ?Mâå 9eðˆŽÚïðN’ÂΚR„ 9Ì×ýâ*nT˜z#-ºb¬oE{öæCbŠc"áÐÅ$‚žÔnEÿkcȯ¯d“8Æ40vuWk#À#(íïÛPY@Ü߇߬´¿O BnïãÍÑʘ»â{46xaSÅ­µ‹±i©zB`9všÙ’u]\KXGB€†œ‚ xHB€FÍ ®‘aƒÇ ;$&L öìnÌ–¥%±ÐÅt¾D—·”pc¹+.óÞœM»C‡K’ó"–@©”Ç“”º¦rŸ$?Cy­¹&õ€â;VúšŸÁz¼«©Ó†z¿i©ºä†1·H¾Ë”éšæóÍGcNšO}4l®x(= î\‚eêÍæ7«¾Ži‰PÎMظ¦íïpvv?¿|ZcÇ7âѼmB>&¶× @G‘ˉZGJï™8Ä]báç{R‹6 ~zd8<²|Í¿Ž¨öû=­©×)Sº×Rué×vÞü"ýN—ÔéÒÆœ¤Ÿ "ýhØ\†q27Húãì(÷EàF*a‰Aû+þY‚Ýå!R v|Éoçt½À¶ VÄÇ=J~t8¥7Ï_ÐÀÎ7ÏoÀÝ”wqG)Ê–¥êŠ"-vÔߢ(Ž…ØE‘Š‚Æœ… ¢(hØç-e‚û–7“íØT–èò8m*‹†í*£±Ÿw• öö•á¶¥mebÛqÕ$:ŒÎJR†ÿ^%éÇݤaì(%Ù²T]I„ÁN(\”„ÏË(ïš’¨%AcNJBQ4ìó^$ÁR’´é™ jQÚ$ ÛŽDc?oGì‡íGÂmKû‘Ķ{T'è€:kJI{5¥wS¸Ö:Û²T]S¸ÆZ\4…ÙeyÖ”å-][]hÌISâ!š‚†ÍãpaŠ{ÿ´¨xŽÝ­‰~{ ù.ÁNYÊS¬b&Mõf|—˜P׊—Ï/ŸØÌÆ{h3¿j&6­Gûß™‚˸ÙKÁý¸›¼ÉÔ°^Ó–¥êÌ$v¶âBÁ“Y†×(¸gË9Q0A<„‚Ѱ¹ƒÍ׸÷Sp|Y[ýþ6®Á~(«˜£Í쪙GåÃhO<“qA{ɸw“A'1¬]³e©:O;’ïLÆþÁGsñüW&ãžn=s$cŠx£a»}-Hqï'cNJ‰Ë[íyPìµþБ͹:Äô4Ïš~\ŽŒöÉD˱´—–ûq·¸T8DË›–ªÒ²[ ;¼m¡eWŠ+´ÜÑú†cN´L e8l®‚VS܆Z‡S,nMp~oC˜Qì÷¦e6Ÿ/'ÖtÇÿ¾EBM¿CÞ ÷Î3A—Qµ“ 7àn²ªe£^3°i©:AÛ ;1k!h×YÖ5‚ÖÆœš BÐhØÜUâL¯pï‰<‡«0èœß;¶\a/‰&ëÅ+Ã[*M69Ú:á7µŒ#ÛÂßT”è–1JÜ„n?Þ1ù“ÔÃR|xøœ¤ û½ Ò»IûzÕÄÙ´T]AôŒ™´(ˆfˀ暂˜AcN BQ4lNR®`ïm¢— «3»ï¥ÐÐxÚnœ*Ú³aÝ‘a¯oˆû^±¾M÷(FÐqt–’2þ÷JI?î&ÿ+;¬ñ´e©º”(‹¼³H‰š–ù½5)±R‚Æœ¤„ "%hؾ‘+Øj‘(% ]G9¿Ö+臔"QJÐÆùRDË–u¯3^=rwE?âà\á–¥êbê$â1峨L†ÍjÚ³=„ÆÕ”""§hØ\‡×ISÜ}zÊLú{ôÀ×0SœâÜ/¨vÍ-<øÙEà ;DPY¯7Ç)wé3÷¨´Ð¡áTÎï>6\î Uר“ ¶aäu—à&±úa eòá 4%dT*‹.„ñ—Sô™x+ĺîl†i†\§i†ë__¡àøò ¼mÚ¶!¶Válp»&[;j¾ì¦¥êÄkì1óe¹™*óe3ñvl>Á1'â%ˆ‡/v"Þö^âEÃcµW°Gð.OîͰ“V¥P+èxÒe:2Ú0-}ÂKm»CÞ»Áùšœ©Í¨^Õ¦¥êô«MïÃøéWÍ•Q¬™~;F±Â1'ú%ˆ‡Ð/v¢ßö^úEÖ<ìüSÜø7½+Á­Š~­€ W‰ ‡S°‰4ð¶¹2,÷O²‰ßWnE‹Kû=©I€JkGlYªÎ¥J3S•K[™©š¹´c¦*sâR‚x—¢a'.-aïåR4l?ySËî²MïI&'R¿<3ßA$¶ó/ßÝæêº/çèqÖ&5¬– þûº9|»œ»hû;ø]íonP£2ÝØÑrLó¡ß_›4+å°>Æ–¥êŒíÕûƺ2x53vÇàU8æÄØñÆFÃNŒ]ÂÞËØhØÒŸšXã3¶ˆûI~TÔ0g‘”+ÃîÎØ<ËÀ›nÔ-¦£[ý®ÛdÜ´ä½–ª“·?…|Äì&?ƒør,Ÿ]Ìåô~è ŸþKßd 6.µi©:ù°ù˜áRÌOG¼x"?“OÇt8æD>ñòAÃNäSÂÞK>hØRÄÌ„à®u—niÿóx¨ÄÓv¢Ixz‘"®òLåPеMÄ€Dƒ×é{j—»ºm“ïÁ¯ÄÙï6M¶›ì°2tËRuâœì1c¡˜KÜ/ÇBeâìeÇœˆ“ Bœh؉8KØ{‰ Ûïvò5îojñ[iNß4DI =}*¯W¶cyeù¡ön§õô_ø_ÌfTé¹e¥*ñÌþ]–á‰ÇúT{ºR/vŒä€ƒŽÌ³‚<‚zà¸#õ\âÞÉ=pÜ2¾ k|(ùHHÇ¢“Ï8üyeÇmäS¦oñ}÷p¼z.ýeg{mƒ«´8ΪQµò–•ªli•<†-î}-;f`ÀAG¶\AÁ–pÜ‘-/qïdK8nßå×ðÊA×kl*ÛH ŽEáÌ5~Yõp«áz~úG­ëFþË_Ïg(^&¥ w¤E%þ%{cHiËJUR2ò˜±ü?)ÆiNendstream endobj 1204 0 obj 6766 endobj 1208 0 obj <> stream xœÝ][7vò8¿b§™ÀSæý’Mĉ×Q]x³ öÁX³šY°4Ýì°ÿ"ûƒsx)ò°Šìîª.–€À€¦Í®b}‡<ç;²Øï.É@/‰û/þ}ñæâëÿbŠ\¾üpÿ\¼»RÊù/oÄ`.µaƒ?”ÈwÃ7Ï.¾~ö›Ëï?Ý_|ý‡Kzñõ¿»¾ùþ_áϳ»ü›‹oŸ]þÎu·û~(%ƒ€ž¨ëz¢ƒXÒ¹üîâÝõ¸/ãŸo.¿yî±ÓK3X¥¸¹|þp¤‚&3HEØ¥&làêòù›‹®è5¢Šð+>ivÅÆ¶?>ÿ‹oŸ_T`S¢µÃ»÷BÌTq7Þño¯oÈ  ¥œ_}}}Ã"¬´Wÿâš•µZ³6lÆ…Ý6³¦;à[ ›ëF[êcÜ®É`ŒVÂ\}òzÁ­ÅO¾Ñ qu w MìÕcj»?µ…“œËu&дKOºØ.7ìªjâÊÝuòFóV–À—móæ§›wwÌÁ¼1â-Ì»;ì`Þ3ØgšwwØ‚sP‘÷öæÍô ² ÿﵟ gOýdSrÐ¥òß&Ä/Ò§ŸN'¤ÓÑd£ÍBé7íªNHFó}IÛA™6!‰„Ôs$$„xBê ;Òö¹„Ô¶l°¥‚¼¿¾¡ƒ4B#™‘”ãž7×t€&DL'˜ôršvÏÞʤ×tU7i­ˆÉþ&­< 5MZ.0éÞ˜£I#Ä›˜toØÑ¤§°Ï5éÞ°X-d“žÆfÕOç˜ l“ªBžsãŠåSÐd%ÉV$´¦«: )¡ö!!©œ 4IH- ¡Þ˜# !Ä›PoØ‘„¦°Ï%¡Þ°¹Q@$î`ªÖ°)I&E4i÷íÇ,SúºÍBÄHÏB²w D}a ô*­$døëšÀ™¹²Àm1¹¥ûˆ)¨ËÞ°˜ üÛ$[è—kÊ@“8âäüå Ù©&Ê“_wÁ Y2R´ì+Ÿ²Ó|}ÂTY ²‡DÖ†çd‰j~þ]ãSE TÕ°åA—óGÓíI¾Y’¿¦«º•œíãA…T õÚrt ð&þ³7êè?'¨ÏuŸ½Qs#0æN®SúˆL¹sBB <‰³«ã ™}!¹ sîë6•6Nœþbiâã¸,W/¯ ŽEì!U/&êHrœëïoSy> ‰.\R[ÎMŸ'Øfµ5]Õݧ Ö%ýÝ'ën»O³À}ö†Ýg¼‰ûì:ºÏ êsÝgoÔcö™aß%¸OÞòõÄ[ž‘}òÎéô˜}f¾DòÙ]ʘ|f)÷É=»ËsÏ,WçÔ³»@1õÌí—y.玦¿ãÄnå:×tUwœÈ}\'ó+MßiøÎÞ˜£ïDˆ7qž½aGç9…}®÷ì Û'Ÿt/ßÓOÆyWqbú‰úùgw)Cþ‰¤Ü'í.WL@‘`3ÐîA*J û)èri:?j7+¯éªîGiZûûQÍåÌêÄ™dí9úQ„x?Úvô£SØçúÑÞ°a>A¸k†¹IPLX·58aS3¾°Ïì›a V& Ùj›2^$¯9%6ÆC²µ%’"ä4Ý%’z(­ùOGRó–÷ó¶9§õbôÁ˜£Ê×'G[nYM‡@Ìf•Ò5]Õ} Ñvá+ +} !n+Wӷо¥7æè[âM|KoØÑ·LaŸë[zøԩu£,m#×"ƒq“Îé'ø0I,Z/ÏB}¬Ù_ )|À$êãZtä¹Þò/È!åÛ#Ynb-Ï ­Úª¦¸ª«ª“ž–¾ÚºÎÉHø`DÛÉ,ØÄÙsp2ñN¦;ìàdf°Ït2Ýa f]ƒqß!K†@p-¿ÐDˆVíìùžj½­¶_{ZcâÞÂ¥±¼¯œJM¦'‹y[©ö…ÆIu³AS+&©É-FnU²YÕU¦Œd]_+L4å”þM-Ø*×s¤)„xšê ;ÒÔö¹4Õ¶`̽ ‚qïJSRKнc~iBžLRÓˆQø ?ý‘jZšð™¯ð¬Pª&j±UµbUWuZÕ|éKÆ+i|9@« ¶PuÇi!Þ„V{ÃŽ´:…}.­ö†-„ñš8Çí)tŽÛ5Ÿ`¹Ëq7ÍM±ÍRÀ5]Õ-W±¾ç,$˕­Œ6-wÁŽî˜£å"Ä›XnoØÑr§°ÏµÜÞ°ÝÀ\¸sæeúôK˜&ì¡à†zVÓ9ˆ“Üçšó‘¢Ò4Ô™”Î>¦ÀîNZ>#M"‘t³|oMWuNr³¸ÇA#n±n~°™]ÅI½1GNBˆ7á¤Þ°#'MaŸËI½a æcŒ{5'‰ðöôÕ;R>±D˜;pÒ´èeÉ>ÂiêÊ]X¸ss²å:Ô¤>A¶:?nUWuåvŸóã$§é­t丑hÙ–¢î˜#‹"Ä›°hoØ‘E§°ÏeÑÞ°ó‡«aÜyßFæÓ»TÞJE ÙæÜ˽÷ù°÷Uc’‰šŠ‘÷t‚@‡Ž£ñRû#V>BňwÛX³B¿š´ÈÌfiøš®ê ËÌ>âIFÒyg5†]°±¦;æÈ°ñ& ÛvdØ)ìs¶7l4ÂKéİLzÞBúÀ ´’a¥æÞ±b~µ!þûKVhZ“ ©Þ¬¼°¦«:×R½ÏI…’Øtp[æZºŠk{cŽ\‹oµ½aG®Â>—k{ÃväE‰;@ø¶ÂQh6¿Üôùø- 'ÂszŸîL% yºmŠ;cºK$µª‘D]¶."âs:Ëc|µ˳_ð¾Üœš^€¨­N\ÕUÝ¡¹Ï©“”Äp( ~=£;æàP0âMJoØÁ¡Ì`ŸëPzƸÏAq÷q(Òoò¶w2ÂLxN–§—Ca>¦ï/‘{‰@uÚ ïKýå1 þ…8_"UYnW-w ¬ØªÂ´ª«ªgžö9Q5Ìêî|M¦Òrt,ð~¥;êèW&¨Ït+ÝQ âߨG°“WÉ䕚N¡Û˜‘Ó;à  B^c˜º³ÀÞñí¤Ntx?lØMÚ_¸pT`]¸ VbµòÇCõ—Æ«˜£ÝR’–Ód{÷*—­êªî8 ÛçB¡åxVÍq,ÈHºCŽŽ#ÞÄqôFÇõ¹Ž£7jA¸g¨ ûlÇ3Ý9“3Œ|Ç!CÒ]8©ÝÑ;uá¶pÜÄiï}® òÞ=Ëñ’FÔ$~M·:oUWu¢é>ò f{À‰,øÕÈAˆ7ñ"½aG/2…}®é Û­“0Qà>Û¿ú,”è|Ø<——º½‡#á~BúK/J…ê³YÀÿžý2Ü•³<ûå"Ë­¨IþŠlV[ÓUÝ(²ÏtB²täSÍ,ø±ÏAˆ7ñ#½aG?2…}®é Û-ˆ÷Ù~„úÊ7tÙ9“bÂýp2†¾‡!a¡»t’ûu+$]?â^ô{dˆ{¹ ô%R“åÕôÂnV)[ÓUÝ¥³Ï9tî`~zÀ¥,ø±ÙKAˆ7q)½aG—2…}®Ké [„ðã>m$”¸Dï¬ŠÓøœ}—bB«»tŠøW]º5ôOÇÑkÅâtwF~Šªý~‰Èr›iR=§¤©®ê^ƒë}–sLJjռƂƒåºcŽ^!ÞÄkô†½Æö¹^£7l·.bK9Ûk¨h&¤óYq€™–ÐwYñuŸþÒ…ßähH·ÚkpµÏÜhåÒø/‘t,7ž&ç3µYIlMWu÷-­¿û &–݇Xótw̔ѡDœ4§ú󬩱i5”«P¢§½&n}‰fÃùN9ôùGhß&ÙÐ…Ià¶DŠ…²|w‰ÒÈ%‰ÐÐ#Ìyj“Hˆ¸jÃoo j¹'ºþ‚ZŸsxêÞ%é>¥Où[$ñ)qr nz“jk£bn‘a£bZ4Œª8 =ïÜÎhú3L‡LŠY½IqBŽ›@>Í¢ŠßÓ:¾››»W1÷°'ÎiÞŠYÛÔœRÐÝÛœâQ X¸-Îó[»¤P¹Y½vMWõx‡Š}Nân÷@¼³d÷yoÌ4(†¼AÀÃÃZéëC:âÖ’øN´!ê.˜ .5h瀇·Ú]P˽[=6uH¦§$hžÅªð÷ m…>½í‹A¾¿µ}1eö±/²öµqì#ö±.²Ž[W¿ØGîcZd5L«˜µ °LFËrÓv¾e¥(¨·eQs“(h9îfèBøfëkºªGA„ïsª1·2›£ ¹j÷RoÌaÑ#ÞdÑ 7lf¤+bÜ÷ê:…­_Ìä¶sê sÖŠ§ÅÛ9™^ýt ñ)£ÒÌØ‚j[$Ô{" Í4ç\ZŽ»Å~#ZÕU•„ §}Ž1æF¤CQk$´`¿KwÌ4œGˆ!?Ím8V* 1Ç ¨;d~õdU|ªPÃb»C-AÞÂbWànš™¡[™»¢«ÆhJ%.Ýoˆ1ø £ ¡Œª!c¥Ö^riÝ;L~Dý1Ð\ú]î“04(†kCƒÉI† ±¨‡¬Ÿò»28; }ùU‚ü˜ ?øOÐAˆ‹]›t u=ê–UÐæXÇÕ?B·Ï>A‚£ÍÕ×7®Äk-g.L)IUè¯ •Rr5êñe‚÷1Á{Âð*cKy8S•óÅ¿œ»xp)—î«÷1Á}Hm§+•~©õúÓµN %Ø!7Ú^}ÎãûË5è=—\ÂR#Ä  aŽÿï`RÀ^¨ÑÏÃ+%£çÜ€½ FI ,|ÿᚃ®@ö3ηá~maZ9Ì»Ÿíd¹á YœrȈӵaÖ-¥÷/nQn¸Òãþè‡J>âïÝ÷rpãæÁ(¢4Lø‘^‘\ –å”÷½_ÓVôê»ßŸ£ŽÂ\}ïÆBǼd L áØøÆ}´ Ô Â¹æcóª¯ØÁc˜F–æu¾µÆ'H•¬È=! ã“ð0§K AîM+rùüÔe¸¾Q\¢•£°F(<55p?ýÉmÔ²ÀkŒÐç|SÔ²Q߯BZb²–YÜŠ@‡éä”áB—"P/ªƒ9j¬V¸u®qp›“ÎܶŠ·ïÎoqº¶Ú|4N/ æEþz:¬çöôL§û.§rŽdd<ûƒ™"©ó÷éYU‹E³~›±ÌôjÄ2v`ÀxVÐóË)éG×—(gȢЕ¯3‚»< y›ÛøodrÙ’QÎÒ‰5˜@n 0a”EÝ:ŸÒ§OÁˆ›,3ioDîgØhD«m;LÛt ~v‰!µÚb,h >ÕŒàê+@çP‰©«š+gÂÔˆ@C/«Oxï R Yï+ø9£TáçÂÏSÄqþîÓ‚]õ‰`C!¥‹É¤g©¾Èž×Wÿê`×Ü‘^¾˜eåì#0m] < Æ>þ¸D–¯µ°01aÔÑ*nK:rˆƒv:å´§:©“ÏËÈiÚDÓiÈàgßÇ€À+9Ÿ>aìö)>¿v‰1Œ¦·?å+_c „^aTÓ÷F7hèm,ž€£‚J2`AGGnÑL^=Ëfÿàzä8šùwîÈõÎ1ÓÄGcðF`3ãÞaŠÊv<ÄÝ\)t˜Q]*téw©’x,òSKIü§gÎ=tÀ0½­ûëª#¬Æh€îZ¼7¶6ƒ Wà(´áÔ/@2?§)kFùS5Æò4ç5…5(X)C8òÞ˜™«$¾œøËIб0Ò?:ƒÔYß]Nu€æµÕ˜XòÃÞ7 Æù@ÇŸ¼…)üÊküñ†IÌ”´À¤nXö{l¹ÎŸ©ÆnòaJ4 çÄM¨”QHÃþóâùßÿpõHà„%`¥ÕôÖk“Ën„nsà|0îc¢¢Âò{0vÀ26 ¸ŸQbX¹õæ~/XÃM`÷CÒ¹Ž€)Í¡ß9¼†éÆg-àAð"åðWòׂñÇáÏ*’±Äå/…Š}„ëö §pâ©è^qïçKnõ R2Ó57ZÖðŒŽ@×ã50VávÄ1Ö`»JfÈÄÿ»Ì0NÕù©!‡\‡ÙIjè[%o3€g)1½m¼µ–öË8“ò(áW…A7}š”`ÖyD‚ç’R˜;A’;’u±!Ø¥?\SgàËuÜãAƒI5žM}¤«®¾•p©mrР7B–rð*Á[ü>›2ºu¢Œ»t1çÞ¨ÝK£M»( ˆWY†‰ ò®–‘¾šêôô.úP>0~ÿxù¤.ùgžæª£Îf…z„‚p?9Xà†µœ+ª¿ N1‡ ÐG>ï¯ý ¬ £ @‡´šÒu‚c>%‘ºSúTØ #'ƒôÜ5uóP>jœ¸Ãk„Oà º ŠbKüIÖ “DØÚ䮤!}÷æƒ,ºþ´“"÷˜–V)QyÓ€]ÔQÕcë¨ùšôFÞD«*ürª—å=ƒ ÂÅàt%jãCdj~Y£€T”ü¥D¢ØÄ%‚Ì­¾è«ÿÍ÷ÏŒa,ÅÀ¨Y¢ë÷W#¦»À ܢθü¬‰@K3Õ‰˜ÆJcZÐZD¹o©M•wÃTp»pa ”G¦õ¯`E¯ã  âpÛVÜU'ÙêrB¬_…ÙNtø*ö ýß;!/I©rdÛ;X¬*R£1%Ëøõ5ßVK5¢ä¬xÅýÏùkD#™ÇIÔ'ö«ÀŒ½Ûá~ªPªKè»}_ø½ڙϸàÓØôaüpÒƒèpïØ:k‰Ã,VœI•PŽÆ" žU•]«±íeùÑ_üœÕˆŒ·È⼉ÁL,é—&änzÜ9•œVóÝduÚ­5ó¦¤jÜ|ˆ]'¸¬c â~S[[ÌáËQ >ŽÂFjyc£ŒJs» —6é@¬ÄSV ~5}?<Œˆã^]_JËçµiçIŠNOÉè¢WÒÇé…€c¦¦{Ð’ä ·r3;Y§»Í© Zr›³¬æ­èªÒˆŠ·N7ÝÑFêhR‡:”ªÖ×gÕ„ÉSë¢dº}+ÂLb?ŠôhV7ãý‰{ÏÞ¡èG‰0!‡ˆæ~¶¶Ÿò»©‘{GΎªq*ÊTŠÑœç‡¼¬U£š_0Vðò™ˆÇÑ-Y2¬Æ,z¼c_ôL’Í3ƒŸ‚³FÚØ^6tõÃq|ƒÖǸƒrÙ0ÄЕ…“dõqSLs›cØÍ‚çž\åŒLÚ {ˆ¥KWüÔs#ti¡zp—&’bPÉÁ‰i€èu§‘aÞbMrÓjÜXß©­Ò28¡ãÎH® ˜¨–àÔGØ+ÛH>ÖBt)¢TCú-Âü6ÛÞ›´Í(m¹­>ª¾¡ò¯¹u("É›Ðå •¡ÓgÑr•ßcé«T•J‡·±8ßÄ&é2NÍq«0JQ¸›YÙcÜxpp%ßUÏÁë›@¡}Žö»{-¸¾mïX{<½æ?–Þü£r:$¥;ÄlîpÞÏíÀÆÙ19;îå&T32…WŠ B"s;‚fjI†[ŸŸ’ËGw2œî7C¼£>¯þˆX~'/cæú±29§ŸQѳ–[çªeÓ×)LrrHG«ƒë]†ÀNì¥Ùn"ò{–\ÞCÌ­OY"=£²—ŠRøíäÇÇn¼–œÄÏ“%=_"n¯îçø`Ef]O§WšbpJ"¯s¦Hc²£"¸Y°E>yKÇúç÷8gö´tmâ9]ké9]ÂZ$–7a à$ÏïóòÞçY"dŠ¢ômÖâ?§Ks2¯Ýz ¥ÓwHˆÛ™2•Nu©X>‘!‚dºaI6¶þOn}•[sëCn}›[ÿ!·þcþø*_pŸ[ÿ9·þ*µ:Y¬Ëp•7E¡ç»]+îðÒÿéúF·ØÏ¯þ._@rŸ7¹•åV™[enE=ü%µ:(ÈGH·Ý€ aÂÐåïs'·UáZiÔŠú—*b4üorë‡êðÇÛ€|ƒž… †i«ûXÕ¾é›U®–àkN%¾ÍµÑ¬ZXáÞ BêÁZ$ÇÑØ‰Ê©y~#«›jú‰ðeÃøµj© Ó»î@>æ¯ßä¯?ÔÔè¤éjü½³²æ=]TôCM#,¨fˆï“ Ä p[c'´ÒV͵‹kM,v§'ÌW&©ÃDŦ»á u9‹  ]c™,×bÑn|;6¦"æï.þõËendstream endobj 1209 0 obj 6490 endobj 1213 0 obj <> stream xœÅ]M¹‘50·þuì>(ůäÇÑã5¼³À.lC€‹=ÌHš™…gF’­–=ÿÞüJ2’™¬N2iPªºY/H¾Ç2‚ùéF&z#î_üùöç‡×f’Ü~øûƒýïáÓkB&á?|%&}£T’‰é›¢džˆvñõ7¯¿ùïÛç¿=¿xý—}xýŸî¿¯ÿø;ûã›ÿ¸ýæá÷ßÜþ4¸-÷÷¾!J]›”ÎjÒ¾):‰–¦Èퟨï…[üñöçÛ×o|OЛžŒ”\ßÞ|ÿúˆÞ(c7EØÄåíÍÏÿûøæIÍ“”r~üõÉB£R±ÇéÕû'û›Âhöoþëá÷oö ³ˆ}Ñh@+xmû| þO¯È¤¥œ[CìÐHÎ {üãÓ+9QBfñøÅ›¢‰~$‹QuS˜°ÃÙ5¦0£&ʶ¦Hc”íõh e0…Cu4…óH_6…+C/1E0÷Í;–("Ìb‰`zk‰â‘-6Õ-fÖó«Ê[ÛÏt”ô´UÑi´Â¥Ÿ…¤!ö³0Zh±0žž§™­àý`øë§WÜÊ—™Íão3[^¦3:nng¿ØÂŽln…½P¶`ÆÞÁí¹»ÅíÞ~™¨¸ëäÒÊ·ùïj«FT­ø%DUf’: ÍÑODE‡§y ïíâ)<~›^='?âïOÄöcäK‘ˆ‹m·3Å®Ãw옙u"žÓÊì†ÍGìHLƶca2°ãÿ3{~¢“²¬œá0ÄÏÝŽ¿ÎB%Å0Fw´Uc´²MÊ -}ú!b ŒF‡—^o3ƒå;3È~~€ÉØøã|¾u7Ñ'þb£ÌNÂú CŠ˜(§îÕsr›ƒÖ$eÈ~|€ÆífÔ©'g2ŒÆmÕh,…¼„Ƴt_燊7О֞ÆÞßž^ÑiÖœ °27q4·ß#ö0 Õ9²`l¢²‚9Q°øÃµdVA¿øW”ð{ùo]8~€ÎíFÖ)8óq>{G[5:Ïœ]Bg1O1 lFG§Ã@gtŸó¢ö“93Ç—þÝ&bcãwÄv,¹ƒšÂ8mc96þÅ­Îø‡ÄÇí°ë\lœgÞÑV·‚÷·Ü1ŒÌÜÀ[ttšºè>î ³>Ÿ£ e %GwŒÛªà>tô±û–ëáȶ¾åÄþ¶¼ o9‘Å´Üôí‰(»k¹Ëè‡È];ìºDqb†É]G[5¹ãaò£Ëõ:MÙ wèð´ôÀû”¶þ>›€|–wœÛ¤#ؘㆀòÚÚ)T9®þÜñC:wÌ¿whX× 5E0ä¬f +§Üù(/™‹4ªIè±Guz`æ¡oÇ]çÙÈa!XO[¡·MµfOv ý¬õ¤Es\èñáI5)¹‚·—;¶~Ü&fî.·ýæð^bÆæ7ýË,7¿WMô^bZLR´÷’³ã}’Ò²—ŠÍf ºC{iQ!ô^Š*{i„ uà®+‡ž‡Å˜=mÕTHϬñô¹U…ü©û¬Ô$D‘ËÕ’~‰4Dˆèˆwˆ7°OFˆè°ÊnqŸ£l;î:Í”mö´U£¬â­™œ}”•Ò&e1ñ*î;ÍG8y%;rüä‚0ß²Óc˜ý^¸ž9Úžq™4»ã™!ÞwÛt¼ qôãËÑ Ç~èýO;îtüTWôŽ_TØ1D5ÛqוN²q¡[G[5Õ”¬5[¶O5­ö)YªfC²+>P%œ— PHe|ZÓ<£»aÌ»a]× }¹›§EdøŒP·áï"ÝݬÉ9öŒ`V½kœÌ6ãç+z—3‰ûâ@ZA¹ 8óK¦3§zÌdHK ödK ]¡²Æ´¯¯ 3˜w´U[cfŠ\×ÁS½i^c2±ñ*âtOºï8äÑaØ!„æ^úÐ/OÜŸ¾Àôkn h›O#v·ÍºÎaЇ†¹t¶34ID×{GöC!úȸê4¹70Œo¦Ü¥90Ix±& /0yˆð¶¯‹¥ ÃJÇ{Úª /7Ø¥ãAxí4ámHšÇª[!ÎOÏ}A†5#”fHð·¿6H¶‘̈}#«'ÉÞÆY/6*µ52•ŸSl½Ìfeå5h^g0Óã¶ :Úª©ÓØõéA ÙÖ§·¤â㕳÷nнZt¸ŠîiÄç]ï'çÝì–ñ·2ah°½v&Åɻɀ³в«Š=ZLûÍá;ƒåÕ Ô å7ËÁÚ?·Íƒu?GFè0¿‘‹Sû½Ü ­$ÐØ£•€"ÐíÀë¢êöúF tG[5vá!nachD²@7Ôà•Ìo _åë»>¸€G*ÿ‘O¢ïlÑÚ‰C¼ÕØÑø= 4X@BÄ¥Åüø]º}¬\iÜRro¯6ÄþØv¸½ZµîüÇowô§ãŒÁïꊜvîÍñ‹öÌv»¶óºsw#ð½¨ýÎÊÄ/±{—S9±Ö¾MKvß.§€Þ•§w}µ rØ =mÕV2cßá»P•®FÈ+OCA >ÐyvŽ2zbå¡^±-¡‘ãë‚Xņ Ç®<Ì‹#¾fv[|ÐŽ†²ÛÒ^ºDà…ÌøÚÒ€=õ˜ö‡úÐúKaæ’±sµ‚qöjQvSnóVSþÅ<ˆV졉+ 4nÈÊÒŽ»º#†m`õ´UYYlSØ—µ„•EËi³ÝPÀ…3„4çéˆFhì0,D43F@ƒnF h€Ãâ|ì1žà$M-kú¬Žá @7.šAïÛÍ´õì²ä ÷ì²ädt#VœØõUBóa;r=mÕVͰ¯ ÔWór#J^q*ÉðqJŸ©p¶åš¨àœ…r)íjÎçwqSòéVžowNe~\k»¾KQÂÞ‘ÎÅ+—}Â`ìÊh6¨,ýu¦y'ÂT'"Vº¼|ÅãuèÍ›fû0s”9C²OÐfÉ>˜‡èp;îºvÆm†W[5Vûþ£ Ã’§[oÒÞRB‡4”ÐA #JèÐq‡T3;Ë1ؗ٩(jºÂ ÝŽÅ•*ûÿ,‡Ûq×y'ɸ€Ž¶j¶1é%žYº's¸¡¦hä0:„ÃØ¸ãà î½{”Ù ˆ÷jjÆ6c¡pÙýg)ÜŽ»N;aÆ…VmÕ(,4öÅI‚¦«N2… ¼ðF  C(ŒÛ ¼GáïœØKø–°1ñuO> xÿdÁ)>óÇî||@а‡c‘¢r•¢vÜuùàJ“¢Ž¶jRÄöÕ>AŠ\l%J)j¨Â¥"Eظ™RÓöžíÞF–nȹW9gá¸VíhÆÇrŸÉîÛÜ¥—>ö¶Íš__N#eÒ¯íèfrW$.Vf‚¨í…½ÀšºbϰE]KfœU×vÜuEdr\Ü×ÑVM]ݼº ’_P®¦ÉêÚPìƒ4ª+:D]±q3‹ÛNzˆ{ ¼Z§LÆñÃu8ñwA3Påµ&UØÃµHU9ÍÎJU;Ðy\|ÛÑVMª\%ÅRETº&KUC%>Ð(Uè©ÂÆíŠ1Ì÷Ç-¤õýÕURcÝ÷;wDK…• ûÜõŸXôU~6u8Z3Z£µ{ž¿4sW€@Ì›D‹cR‰=]©,§ùY©lÇ]—7ÂÇÅßmÕ¤’ðKîgâfNךd©l¨ ¤"•ظWG׸«É ±ðšZVRx;t–ZnkçTÊ0ºÈ¾§Æ=€©ÅÈèèP'ìŠê´™YgÕ©wUQ¸KÁ¤N=mUÔÉ6uÉÍ>\‹t÷GV§†º| QÐꄎÛÝacNˆ„[{ág¾?b/ªÔæ/µÍ#ߊN6 {w_|\uÐ{~QrÆœTÜu¥Ðtص6=mÕTG“K®µáŠ¥;F²ê4઀QlÜÌ0/ ÷HÕ!Æ'±q…ì8Xys…3Ò^nj@„E€ÊÉsV€Úq×ECša^O[5’æ’›t¸¤é,@ 9æø@£ C7sã+Üm·ý±àoHt÷lv™g™¿~T¾úfO;óCPÎçÆ'«E§Ê9vV§Úq×µÅöý0êh«¦S³¾äB>“tãB ÊZÒ7ñF@‡è6îð“ ì“O1A‡-8 Úq9Rdñ†ŒXž¿d_`k;ä:Ã,Œalíh«ÆV!/¹„ƒsªØ3[25ñF¶ CØŠ;²µ„}–­Ø°Óewg¶&·è»DÛ{·‰¶íØëTãó¸À¢£­m­u m½ Z°¶!©gdmÆ9„´Ø°#i Ôg9‹Zpæžb `¿O”ÍL=R†•¨Ú¹N/&ÆùÖmÕ¨Êø%¥ááb‚ª rø8#U3Î!Tņ©Z >KUlÔ‚‰bR€,;.ðz¯Á2Ýoœ/g¹ˆ’"|dœÙ x—$å]—ÐÞÇu= lX¹sO[5m¡ì’rgW[³qÞRÚðqFmÉ8‡h 6ì¨-ê³Ú‚ÚÚd;ùëÙˆr#è‘8»q]„Žsþ;Úª1•ÐKŠš™á©X5Sµ!¥ h *:„«Ø¸W7°Ï’¶py7kÜÅ¡ƒ}©¡wÞ}WìšÝMìLln7©Ê@fȰø §­ ›™6—Ô7»§Ð ›RðF6 #ØŒŽ;²¹„}’Íè°5.]âÞÜf´v˜ÁÇo‹c:·LoŸPaWì\ØÓ²[Þa|«J+&îi«Æ{¥/)&fФJÄÌû†$ | ‘÷èÞc㎼/aŸå=6ìx¶qç­·‰ÍØÚ¹Î0©†ùï=mÕØ*Ukö_[g“Šñ2[2fðF¶ CØŠ;²µ„}–­Ø°[‹îÎlÍkozu€­íë ›å8ÿ¼£­[çù’úL&tªK+jËÕ}ø@#[Ð!lÅÆÙZÂ>ËVlØ®–º˜ù0ëý–­›$ÿÕ{õ-uëXÇïAö„Oî‡ö|Jö$áÐ I~ÚÇ .BŒ :ÚªÉë¶+ä‡ËTð•å§!m h”tˆü`ãŽòSÂ>+?ذc~ƒà.‹ÀóC6y¦å±ö%—Ìå×£‚t…ø´À´÷r]8Ùt´UÎ/)[dlNµ]Y`2íðF@‡ 6î(0%쳃 [0n5Â.kÀFàú¼®Tî lSÈ™U¾ž ›'§0·nÚ©iïïº<06.,ëh«&5Œ^R«È(OU\YjÒñF©@‡H 6î(5%ì³Rƒ [í!npš¸-=~Ù;¨Èç?ÈT>ˇQl?nÛ~Ù Pý㉲I*%S”-ÿkÃ^mû¸Õe†’q¡\G[5É¢ä’êF΀ ÉjH“Ä% "Yظ£d•°ÏJ6lÁˆã3ijûÃ=…Áöö„,§¤tž¿WÓŸöA¨j5fX¤×ÓVElS—T-RCSuZÖŸ†TJ| A ÐúƒŽ;èÏöIýA‡k* îò¡>eãÀÍz ];0×)¦õ°²Åž¶jtµå%tU&•§eº6¤Sât@‡Ðw¤k û,]±a;ºZwâ~NîÂO{ÉTøÚºÎ1%‡… =mÕøªä%õŠTêi³!Ñ/‰3Ò5ãÂVlØ‘­ê³dÅF-¬nV½w[¹Ÿ`|N¢/üb¢‚+¿é×ýÍ庇v :º¶.rçýw´U“).©«t_ÇJIiHÅÄÇ%%ã")ذ£¤¨ÏJ 6êx/€ X +Œžá3OšÐ¨#è!ÁÆ…¤„}VI°a»l ¶Æ Ž8i*œ"iW€ïä+äú¬·C'Z·ÛV§¢»Fv­;ڪњ“K +©Eº¡uC&>ÐHkt­±qGZ—°ÏÒ¶Û*XO‹]V?Ÿdp»uÖQ3¬D²§­ƒ©¹¤D’º"sQ2¸!Íhd0:„Áظ#ƒKØgŒ [PŸŽ q¿Û9Èÿiïpíå¨ .}î#u[;æ‹Æ _üƒÀô ’~ʵÚÏIœÒ¦á!jºx=.Úèh«&DD_RýI%!jH‚Ä…"Dظ£•°Ï 6la©«ÖÝ’QÄ…§°ýd×Èe.­ÌÙ)8¹«c :OŠ3ùøÏÈTûXU¥Å¨aÁSGS‘2ÒÙIÑEÊ=}WMÀÓ÷ˆ4¨Ô é™Bdj‹û¤N¡ãT­QgZÿ¸S­^>!ðLζ+nV"»„3ušµ2²oGµc0ªê¡ça1`GS!ÒžåøB¤”uÒ·BÔ‰4Ñ é!B„h‹û¤¡ã”MÅ̸PŠÂEÏÊÎb)”Û7n²òð¾RÇU5E‰a‘aGSyRâ’ÚY)'¾£N ùžè@ƒ8­€Ž'lÜA›¶°Oj6lWB‹î®?4Ðï%eRï¥nN–}¾‡D÷õ ßìØUÌ\ Òp—Xû(T%Còa_GSõ‘ì’rZ« fG}ÒWÑõY¡>ظƒúlaŸTlØîf¢¢·qjÓˆW¡Ýѳ¾–’kƒÀ]'ÙŽ=¿­¢=ícPŒ™Ž òzÚª¨ÏL/©Œµc#5¡¥ú4dº¢ ê³:B}°qõÙÂ>©>ذcªëîSÏÀlÇ]e™ #˙ˤX? UO³¼É‰Rc¢bѧWnÚhõÈý+c‰úH–7“ýzø#<1äendstream endobj 1214 0 obj 5467 endobj 1218 0 obj <> stream xœÅ[7rǃäm>Å,’Ó¼4«§ÉÃê…û`ÆÃóãí_ÅK~\nìqâßÿððæ¿¸^?þùÁýëáçGa–å&ý/_Ë›ydL/7nW¶¨Ûbà/¾úúáÍ×ÿþøë/_><¼ùïGöðæ_á__ýç?¹ÿ|ýÏ÷ð»¯ïÊ‚¿÷1e2¦Ö›ñE±›ì)jyü—‡Ÿ˜'ŒÿyÿÃãWßxzöhnVka¿ùî!Ô‹=2±Ü´û®…ß„~ü懇?¼²Oˆé•§Oüæß~÷ÍC V*ëÝ Û jÔMñô?ž^/·uaLˆWož^‹Û"­²¯þ~¬­]¸¹tý4ÔÈÜÂË=vàëÆ«e—`KÎêqñÙ+å«o·O?úOÂÚ ™¯7&†n€„’ :ba5'þ5µîorªÆ‡'÷¿Êu±x{»¿5ƒÃ•×ǬW"f–…ȶf¥Á\߸tß³¸ß…b›Ô,Õ'³˜—E‡9ˆNŽ1yû¹ñ §Õ2mò”…M^-õ%“Wiø:tòŠŽÉKŽ'o†Ø:‘òHNå1OQGj쨎õ½âHNmÇ„ýeÛr%›ÈA/ÝO ®9Lûƒ 7y‰½2§Æ0 û H îÅ‘X¨‘LÄï·E_ƸžÖ¾ú~¿åÜ\VR&èy…\ù¶˜ª?oÀ_¶OJÃçÇFg`âß?ôqÁ–|Þ*y ,Lüeð'ÈÅß¹Õ!þäÄQüññ§ÆŽâ_Qß+þäÔÖ•_`ÜEŸcÌT ä¾¼ñ¦%J>ó»„ôÀŽtÉOÄD’ö&è+¤¬ûÞ¬:¿¼ã*-;MñÊÂ_A"W|ÎÁ0£’¯;$Ÿ9J~†5¶ŒÊ—q§‰;êòsŸYÿ­^k$µ«·‰ àֆ՗Ɔս!º« ÍR¤²0Eö’ J°Fô©#Œ…9*R†l½$ŠZl#JúÔ{@Õ'Cž¢>ÔÜQ}jì{Õ‡Û™xЇŒ;è‹5<úÅõ¶t¦ø©Z„¡É“¶ý—°«µP{¢BÔ•l‰Së’Vúm¶–jyp×̼nšÃ…¼n[geÈ=ûuýcËEOË3R&¼‹º$Ž´k#NúÔÂ@„7Gž"¼ÔÜAxwØ÷ /5¶?‰ ûcC~ö ÑRt°)ÜON;iå´UàHYÈvE]’¦E½OÓ’>uÄÐÇœˆgL`rì8+ê;ç/9µd+ì¸dØ­µM½¥ÅÂH0Ä^„]§œíø*h¦2o[¡ð­«¢Ûí}+ˆÓV…#eajdø%yCäªöyCÒ§ŽëôÄQñ5¢ÆŽjTQß«FÔÔ0áÝ Ë°Ï¨‘ñ{Bîè][Œ„$GIo’Ó“-[:v«ÚW†•MËU1R¦2+»$W…Ô¢‘«‚\3§GŽ2“!OÑjî¨35ö½BC ©¶„.¸›[BÛD+´mw¹)°kIøÁß÷ÉÙ³MñÖ­ŒËƒ^æ-ÕʤF/—$yŠ7’<ðÊ·9'5äÈQj2ä)RCÍ¥¦Æ¾Wj¨±á`¬jîz¡â÷œybNkÖìNb¶L9³U+CZC÷EÄNšôW´ò êOÓãš!í¼ÅÙ@Y˜þHsI¾·¾mä{àÕ§súCŽõ'Cž¢?ÔÜQjì{õ‡;>1Ðà¾ë‰n|‰ÕL›¼ea“W¬—ðCíøÓäí¸M'o†Bç[Uð¦VêåÁj@3à”á6Ñ(Ghꥬñï”眭ÌÉ€¿¥_+.Ø ›HÝ aÈyýûNØ’õXBê*ò>€Çaϵ³ ‘Ÿû@‰Î>ØŒ uÀ L–ltËP„T2äýï æÈcW^×k×JÓ´ ,Lû•¹$ùPK#ù f¢GvÚ¿òùsÃ%üÜ@ÞY¿ëJ¢Î©O]åÀ×êÞ# ;^ÿüâºÈ™ƒ°KÝ`ü0íë9怺7âuì¼r3®cpãêè¬Ð4¥( SZ©/Év#„id»IJÛËEl´WÚ 9-Ã?ï§Ê 9¢F†kuzñ6e©‰¥Ú`„2düĶÒ]™F,׋÷|„ ÷H çõi œ×W´ã"¯òѼû1Õ| Î(NïÇ`rÛ?æp‰jÞÉ@Y˜Ü uIf"á ª¶‘kôÄZù šˆ“`¥}þ8¢ò³ç±X•ù--_æÓ˳‰YåÚ Ní½[ï/¦J;_la6/Ÿ°2Ô]Å•í¨«œˆý´¹¿¿Ö‚pGO ÆC%©{J°z´,#N7t²Ãäï¼w#ýqÞ‰››¾P#C®X#%ä4qÓÛ2-u0®©ÿجî¯>Ÿ–Ëi¤,lVG[G>«@guGÀ=±3D`•q:øÚ¿—†"ûé·›ïØ3ë©«o)7UWiËr÷±F~.ûiÚbìYÓS×61E'¥)¾ÕíSZ0¦Åð‰«èðz¸$ µç$ÕMÝ’0wW÷Î)V»ã*³°ykä²0ÅZØ%)¡à¢î>%T’¬ŽØ@zäô’#Ïz!çŽÞHÎýóÖÀiq—ôõ„òP3ƒòè’9ùõ] ßž%8X­þdÆ•IúÉÏÆœ=[8ÿVidïE¡þ–Gõ‚ÛeÚzj¤,D{¸±—¤ƒ‚Ý}:¨¤=wôÈQ{2äÚCÎÍWq(çNég6?¾ßOéö!fæ¦Û„©ð£{…˜ŸUíPñ𜇃'N 9éÊFJýåü"‘¼7eXå ]¨ìdGlÃ<.F«™–*k¤,LØVsIª,¾.TYIØ:‚äè‘£°eÈS„š[,æ@Î)Îw]q¢Ûü¥††ÝÙj|4£“NÌÖ~T|†éuÚrj¤,l¶êµ7¨il¶*ÛHÓ”fkG$=rœ­ò”ÙJÍÍ­ôK Œ{÷ƺºÖnEž9ÍL…)bS,˜¿´œ×h,”¼í!¦^—m¿í½ÛZ¹ñ޾’c!Љ¼‘%_êaÓ qÙ…èÔ‡\}á,¡Cèk'mª[í’ç–òK´ƒÅ´&çúÔ¡ÞÀøÃÕ_éy‹ã²0K¢Ô%‰¶¸4D[É’tD¾Ð#GK’!O±$ÔÜÜ.5w½Œõ«ÓÖc¾­ÕP}{8\sÅ»¯Œ×#‰¸ íÙ($ïH¢%Êþ¨¬‹•²Ïº¸™ï§uÄLb9zÓº¤ÞøËV¡zóãìÑJútôusÊWVím£>©ŽoÛ·˜ÁèR¸Èƒ œe|Ê †”—¤ãB7RŽÉ‘pzäh02ä)ƒšŽ }2î–¼¾{y;rQ> Cü1m’´ äÄuœ}¹í­]2­Ì6P7}Ìx˜WänÛí3uÀ3%Õ½`å¡‚U ¯s­ËÊ]A¸| 1oGk ,ÌqIb5ÎU#±Z2ñ<ôÈÑdÈSL57$_d%wˆÄSl})¯e芢Î+ì¯çÈß7vÆZYMv Y˜=x?v3 Ô aåSTè^› ÂSsä}!Åê§W†~ÇÃÂ?"J ‹)a êA±ï¸@s>oÓi ,Lì9»$ùg¢‘ü,‰}G8=rû yŠØSsƒ§¸”M}”3~øqÛ?m>œIko81bDzQ‚UÈê6xø@Ý °=¤JÒû·‡ü}òFލH#·r´×v)l`Óƒ øa»Ó1B–¬bú~¿”/ošï3a¦¢XáòΖyÛMea¦‚-—dÓâáZj*:"…è‘£©È§˜ jn¸gV5u LܦÒµx ÿ!Ê/Ä>4„TιõŸºi…õ©rÒ»Ÿm˜ËÔ /eÛ=ÏîâbN%%~Þ½³*Ó呣ܪE´ð¶ô-¢µ?ëÉZ¤ýºßù5EÿøCÅݵë´Í¨‘²Cኺ$õs3zŸzKVŸN zä`(r䆂œ›Û²Ïi¼ëJ¢NQå=Øœ˜ä™¼Ý!ÅËVÓ§»ž™ŸˆB_Ò n÷{røÌz¤¨š ^”‡à\WuÆÔ¥ÀÅBôé›–Í„@»ãmÿGÓªEÝk¯R6ò€@!Ä% §PK9$_8…:ÈïT… 7^^8¡èý½‰«0„ÓÎRô²0EË%‰ÔDjj$Œ9*z†È îçEgÓöŠB&°æ—ä?S°Ût4;BÄÈ‘Ã.gL`jnxù­æF—rå«¿À!’¢¶ãðdæZÁ9\1ï|#ßÈô Ì§U,@ç#êI=„àù•ºri¹–Níߟ¹æÆ.éxÍ­@>» гíozT½›·–) 1Š]’ßLŠ›6 ÃMAGô9r0ò S@ÍÍW¿5VpÿÚX~žÈ·`Âqš¤ö>ßH)ˆ7̤ªÉŒe«éO¹À¾¼-,ý](ê A 1Óe…Rà^½…ueC|x¯¶)¯¨…ô9lŠZŒ%ž£ò¶C+uÉö,vI_‹Ÿl}ó©9®š7§Oýñðv4u7I.w³çscë£ùLÁÑ-O°›¿½\Mż“WTŒ÷]i¿÷UµþñÚt¹Ìô™¬kG®e}Þ¦ô£¾1fí¶({ ¦É¬¯„ÿd[~¸Õÿ÷ÿ]Ú¡’endstream endobj 1219 0 obj 6608 endobj 1223 0 obj <> stream xœÅK9rÇõ­?E»wŠïÇÑc/ÆcÀÆ®!ÀÃI-i„Ñ£G«Ö¬¾½I&3É$«Š™Œ4ÕVW±þ$#~ 2Éàï'2Ðñÿ‹ÿ¾ùt÷⿘"§÷»sÿ¹ûýÄ !ƒ|ƒ9QªÈÀÌIS"bü7~úåîÅ/ÿqúöõùíÝ‹ÿ>Ñ»ÿæÿóÓ_þÅýóË¿žþáîÏ¿œþêÊòßQêˤTêÁ„¢è ZŠ"§Ÿï~¿£Aù)þóæÓé§—A==™Á*ÅÍéå»»±^ôD™˜8i®N/?ÝýÏ==;ATiv/çW&¼2ÄüïË¿ûóË»’l!ElFÙ­’$[HþÏó4¡”óûç>a¥½ÿgÿ¶²VkV×Í„ë±MÍݨ›i;è¥î¯ç:H#ôý‡¤úÓ™Z $3=¨dk̺NSÆ—d|‹ã)¶r¢¢øËlÏá·öþ[ª¨Ðçù“ï§OVëÆÕÞÐëÆ™ð½ ëöêì^ kØýã¬8½šk^7%®-=Ä”³¹øo¹Y#S{OÝ!¨¨Ëw_6=¸ÊCç}´•‡=˪°ÕµŽÆ…ÔÈUe‰û[«öv®âK¹ %÷à*ºnfÔÀ—º'„Þ¿ž[z|KS~ÿ·3qº#¬N!âÊ mN.…(ÍÛüÍL¡DØDÐ?ÔàüÓFßV—º`âzj%Ê]pu8\C[p5˜…ÈÑœ:¶ï34CWH&EìMìuznhì:ñŒn»–U£§ÑüzºˆÉÅ9=ÕüŠ4Ð]r¤'Ü…žØº™–Î=º÷Ò“YC|aÊ ‡AÜYºYšI’wÿvöÞ’oƒø4¹ùÛ‰½âS5Ž èus!^fO)>MJ•|UÐ^°JP‡š…öôãqœ‰BKãf¥Ý`U‚ËèØÁ57>ª^[Uçq¢½êlwÒºʪZ *´huœ  ãºä8NÉ]Æ lÝÌE5T-tÖ&¯˜}áúð £Òix’“ÎR¿¹}Ê¢¾b*‡e?e+KÜ<ÖSjÌÇ6á|Ñ.ůæ1¢ðÄ¿a9e&e»ô:Ý”$ÝH¹¡¬)•P‡R*ÿsUR²R¢Kޤ’»[73|Xʾ¼°8F¢’qz™v´8‰¸q[Ù¥x°°˜è™jÔÎáX%ý|LTŒ ‰9šàÔ®P:ˆ„æØM¶;²vn»LÚ‹Koùúgz¦Ì¯æáâ[>0øo·L±-mâmî!{yÛ®»ÎHbú͵7”Uã-qáNÛ†Îm¼u5¡x«x‹.9òHîÂ[lÝÌY]Ꞁ‡­iïUá¯ÉÿS¸X ­r¶©ÑÓ rdÅ;—ULÒA(›jöT€Ü ÄÂX¹í%V»î*e¤UÝæí[ʪËÕz¼g±¤1~ëB•X çqð%Ä‚’{ ]7SÚ{Ô½?B$al”Ær\í®|ºÔ~À\›ÚÑ¢°kçßò¥E¥pñy®¢Å°{¡–7=çE7Àˆá•ãìÄðÝutÙmÒ¿¥¬†d¨G& kíÀU1Üp|_rÄ0ÜÃØºýD]-dïß.cÆ-¬®Pì ×Pñ»—k»¢S1,-¼çNpuD-¸ !¨F¿>è¶?¹ÏîÚuש­E·eˆ-eÕFÍqÏO#€R~[G6è-Gð%ÇHî2`ëfÒ5õBöî8\›¹2‘熆®ÚˆÃ‰–þ)!zí¸·ƒ¥d'²UŽô^9@ùÝ´¬{ö 1¢ ¿îÂøÅX÷Ï…9Èl–7Œ&Ø~4&¹ÿïMÚu×GÅú-m(«6š(†{ôxMÜH WGÓhÒpP _rM€ä.£ ¶n uÙÒûWut8þ#%r8è,y®íebÎ5z{õ´§Ê#ž†ó’ñ_®jLÓc„²° …¦Ùå«ÒÖp´ݼ'Èçn¹òíºë`–´ßÔ†²j—91U„¼à…\Z ò §ð%GÈÉ] ­Ûï5ãKÝ îÅ`û×Å=¹nÞØ{]·]wÝÝé–®iKY5×åötM’ÓBº¦äº ;éñ%G×’»¸.¶nfß& u—ûLú?^_ñåq[“äÈï_5UKCÙ¶ ½'Úäö±—6íºë„ð§¼zÊªÑÆŸà=‚6ŒÒ%Ú4l¨Ç—i$w¡ ¶nÿ ÜÅÉPw)¥Âóõ…§iÑa‡6qÑ (Þ»ð„ÝÈjrãØ‹švÝu$CŽ$¶!'¡¦aÇ9¾äˆ ¹ j°us±–=êk–=;/¶ìÉy׺÷9o»îºÃÕ-iË–²jÎKä!I[Ę5£ê¼ Û—ñ%Î %wq^lÝÌ#}!{ÿªñø„ÊÍk°C;,$)~»àéWÂÓ¥›¸íŠÅNCC³VOëpï–ÙcodvƒOÌÉìd/sÚe×9¡i·„4[ʪ1GÓCÒÅ iÌ–½¹ø’#t€ä.ÔÁÖíŸÖ™…ìä¶7%ŸÑ£³*|ftV ôï¥øæ±°Ð_ vÛN€Émb/aÚuש H¿é憲j„QäD-~³ñ:QK"LÃ~M|É‘0@rÂ`ëf*,_ÙóÊ[šŒ\8êEÂYT÷}äðËL¿s9¯ÉåƒF«¥aÌEï7–ê¥m¤5µË)Þ¯×/]Ž2ÎÓÑëÃr›¹|.!ÍÝÓçŠÁqm(Àv‚i(ÈwïPЮ»Žoç‡Ý†‚ eÕ†aÉ!#-äICACæ||Éq(’» غ™WH@ÝÅEªÒŒ7…Û—À;ú‡@ñ“;”]ÊUŸ([ ®Àâc1WÀõåì+9ÈÄèQœ`ç˜ÑYlÛÇ‹ÞY²r#Û‹¬vÝuÌ0ÕoÅaCY5d1uH–Ûá:KLBVé|ÉY@rdaëfš/Dclqa6Ú ÅŽsm•a}.ßúü­û¦Þ 9! Ó¹OÌë9IñãÅU…j±lBmî{QÛ®»ŽG*ûÍè7”UC-‡¤cDÒ±$Ô6™À—Q $wA-¶nfD®{ÿã­‚ Kþ1^jÓÓ/gîØiºÿ£Øâ92e@%¾h6@ôÆXÛ4&@æ&½íºëP#¼ßT|CY5@~H†ne!ÃHdÃA|É# ¡ä.€ÄÖÍœZ(zÿNññÙ·Èñ dCí4¥Ë„W›…ä1BiH«UläçBØ[Ùˆù¦05ST}Z±*¢uå {ÑÚ®»ŠCnY·%ƒ-eUÐêŠ:$¯wqÑ:¯GBkÃ1|É­@r´¢ëö›Ȳ©÷Ó•†Í´®Lä¸ÙgÇ^j¿¶Åz=¯§VÃϾ>»¹(µVìmIqgg•!âDoÎÏ–›¤”Oö·ÛC\t œ8œ{ÎNoÐ]g§¡Ý’´l)«ÆaCIÒÂ5+$i1Ù«Û8Œ.9rHîÂalÝ~ÅŠ/u_yô!{þþº«]ßGÄÌx¥ר‘¼e~¥V³¸©ëæ+šóxÙŽCv=8 —ï”»«”ÒîÒy$rHÓûD=fÙô—7¢¥d_æAñ»ň†6Ùp5ºMƒIîþ{“vÝõ@Ùnk/[ʪ &Ê’ƒ‡+ZÈÁ““†ƒKø’ã`$wL°u»Ü!ÊNpJÛeÁ¹¥§ë,‘vÔŽúëeõRü•ë ßž©›ÂKªÓ„H„݉rÛÙK¢vÝuz83èF¢ eÕH$Í!)z¸$…=vËi&|É‘D@raëö  v©;è÷B¨Ñp]ºøÉ…óFßëÂíºën't·D=[ʪ¹°P‡$êñËëD=É…Ž áKŽ. $wqalÝ>QŸŸÝ.ö·nú£8˜ä›cÂrÙ÷qâ@9˜.”æ±Æø|–sä1Ú_°îc PµW¥©öÇÒª_ýêäk+…žs´sØ=eÏ+.?ªQA¨+ 9•±¹‰3ó•+-ûnÑ›zNn"{Ó®» ©úÍl6”UŽ”‡$rðižÖ‰löê6à KŽÀ’»[·‹lýâ%Ôý¼|^rù†÷Pºïc‡44,Ö¥4ˆàÆgê¦ßZ˜bº²†ãdè}0‘(·½$j×]§‡ý&@ʪ‘HˆC2&0®æ×ó¸Û¶qß-¾äH" ¹ ‰°uûåX±Ý-$â>‡ðßר ”Ouö z°yBMn{QÓ®»ŽÎûÍØ6”UC ç‡d`þ® ¨iØŒ/9¢Hî‚lÝÌx/]èÞ6ÍrÌ ;á\IØy´_)+¾:« .êí~ƒ‹\¶v ÝÀ‰®R4-Qa›ÍÏÜÜ÷³]wxþÖ^ðÜPV žŒrìŸQ>¢-Á³a×1¾äO ¹ <±u3-‡eK§­ió3+è×·`”(¢ĘE@|J?e ¯~›7J§I仳€3"ð˜ýÒQù0×A¯™¿ºÓ.­©œïjN•s9IA±ØÖ516÷нŒm×]ç"%ýæÕʪ1–’CNóqWC•± Ûžñ%GÆÉ]‹­›¹.õ*Ð € ¼ù}¬.ï:_•È@´ÜBÌì8—b;:·jXšÙSa¯xw@ñêhÀÁ×÷T0@^KIJfšW’Ô“n¾W¡Fylû”—ví˜{1ß.¼Šfjm·5-eU0ïŠ:$Õ€ zæ#ä%Ì7lÇ—ðù9z¯AtCYµAÔß`{À_ÊøœE¡4ˆ¶,ª£KV,—¼zšÈ¹p¨rŸÐLú{axxs}ù$VÞpâ„VˆÜob‡ö£§€ºÅ4ˆ„¯Ò .צÁFZd•õÆ4öó¨„Ý›LÛ-\êÍðð7t¦`Sg2^%ú¸xõøzgúãC†ÛRo¶$µìЛ3é±{SøSÖºÓ ±îNe§î”±75™Ÿî w®ú7«½)B>ÊzS¸Ñ‹ÛRo ccoúJ®|ÓWéóüç±7µfÝ›þïó'oÿÚ{³>fQÛ-U͆²*]!•8y 2÷¯ë ×r2ö†f'˸+ËðÐο†ŽVçßíÈIktØaE§¥ÿºTK< Ðû}ÖûvÖû5¼r_w2½÷a~ïËüÞç镯×h¬àg'cµÊ½GØIùsÆ$ZëKooÌ m\¸ÿà½ÅZŸÜ9¥R’ª±ÄzE(þdÒ¢Ì÷³°o³Ø'(±ÐôÔ'ývV½’_̹ïÞ…äï³ä·³ä¯ó{=ZŸjê7{-~õ·³›++ 2p£ýÞ¥¹þðs-.¹t?6¿éxéB*å†þÇósüÑÜ£“¸_äD{­ÌÍ;¸V÷Ïã·Œ¿8‹ÒlêYnÇï 7åúiþþ—ñ]müö£ù³£mX‚Ââ]U毽RÉ'ÝNÁW/ÖAr”¢ˆ›S=]+s¬•”ŒÞÿéLË)þïÌï+¢ôþçq…“E';vtÿÿSÖΕ¾ƒžákÒ—Ä|X´@ý9)\¡ƒR†¹Óƒví.ÿ>P×ÕÌÍ/_>ºþüéì'3Â*à@°_¥wŸSŽcÙŒæOå©Ð9ÓßA3¼;»ßs1+Ÿ™@_¶ÞüœJúæÛÎ5¤‹/~Ž ªÊY`€o;-Jäºí–¿p½éüÁBç+SUŒž ò}›:ôséÏÞŠ„€_?´jß›å>烈š[BÜòu”Z|4yLªè«¤ï==õð¢óߟÎÞ`|v{î#”`'YEµÒ8[G ï16$µ°þ©&5o›ÞŒÕã!›øü³ß’M­º/üìÔÌ@µÓ×À»ëôïÆ:("Ç_só÷©5C»þ“o8í| Šœf?7’‰Èôb#2ÃÿH_ŠÈ\Tel i‰™sv}7+‡¿ù%i~Nï‚Z?Îï Än}ð±ßcX;›= ;¶Ox²_òjà¡Þš¨„2®*ÉCÁ‡Wå¿wu”–á<wmG]¸º}”VñÖ]Õ)®¾ YûTX Å)û±VœÂ¦Ëð•CÖ¯rVN~7:Óµ¶eÔ?Â*4­Ö«ÐSëJÃ2&Ò°ã­¦@ð‡IðË8®Ä·¾L/†›˜Ù°¢<–>ç’ÀÄS3ØÀ¡Iþz÷¿æ˜¼endstream endobj 1224 0 obj 6330 endobj 1228 0 obj <> stream xœÍ[Yo\·.ü8/ý ƒ¾d¦ðЗ;™¦’8i]4èC´’µØ°%ËZ’EÿE~pÏáårÈË;Z#A"†ÃílßYÈû~90¾ðŸø÷åñâɷ ˣóŰü ü{´x¿àaÈ2þyy¼ü|†iמy#ŒZî.Æ Ë@ß –V,wŽ߯¾[o4s~Ðjõa½áÌÍÍê$ô:gWë&i-øjwìô^®~ÉCÜù[ØP--óvà7˜ÓqO>x6¸¥±†É¸åÑz#˜ÐƒÖ°:6•³zuZzÿUz*½¥÷¬ôž—Þ×¥÷]iž”—ÞO~£->-½ʽÈ#Ï”€;_ìüñû»mzaSn=grõçõÆ Ši!W(C‡2ô1ÎÈAœ¼ xØ¡/Ê\Bi¹¸J¤ä9#uïzÜ#^€HåêY-d”¨ØG¦ê‡B uCRÉ@Éx@íƒÕÆ Nú©üNÔ‡ÐOD‘ø«]벌­Qy4+CÅFNC‚²1KT4òl—N‹T‚CK !úRš– WS‘Ø”[¨›¨.F˜Z£‚€'n’f+?ø´?x]z)9ã\ö‘XñEË‚Ð;Ñýèû6pf&)eƒ&€ñ¶•c„©# Îx¬â~ $Ö8",¬M¢±Ùá-=x°)V?£—±º˜q)YPZ)BIeIx*'µcàTœ¡+¨í¹98W­OÌŽœû¢Â¢°/œ‹Œƒ-‚%ã±{f}6b†²Ìd̨ ¥”3@"¼Mñð{ƒ&k]ò‚Z<0eÎëò;ѰW-ø ¶4Œ{;ƒIJ& Üb ±ã#\¬ Ô­œ$+À¸9àêé`+„œ:˜ÌYVSö…Iç‘J2®Å£À3D›ê#Á2 ùf—¡3©CìՀʫ_‹¡ *:uÒ… ý¿FŸ,5e2v(fr„½2àC/Ã+û"‹¾ÜY¼X¼_Ê1·F¸%w ·ÔJ È=HJ?¶xòìëåÅÙåÁâÉ?—|ñ䝸ŸÏŸž=]þnñå³å‹ÙTUôó îÃúdgÆp¸Ïž"µ†;1J*œÞ殟^y«¦¡#g^imƒúpÙˆõ- qi tm˜2{Ú!ê…[û6ês:‰XXÇì}{à9¸­àÆ dT& —k œ ddŽ„¢_¬1UÞ¬>#¦ùt-5ä;(Õ‚T‘óÿ¼† IjÞißtœH.(eh¤…¦R‚¨ü)ãòÂxÈÓäÝ7² s­à[àÿf¢oyWA$wQ :é#Fkng‚è¶bTšÄ–DÑOâù #îé}’4@݇ô{Òg—µ,ðÔ‚;¾lmƒ²MûºS^Šì¿7z¦û1D„ܺrd!û´r&ú%>¤ƒÖ ’8‡ƒ Ì£s 2/PÃØTjæ‘N ÉÖ±»H:ümœGÖ:ŠnÀL}t':LYæ½§¾¥žƒ,oSßN‡J/{MŒSg¨M®!@qØÀ¯Æñ±CÄ\­ÔžFÊQ·Šˆ8/j"  OÓüŒG<ÉÄ‚?¤¼Ç¯¾%Õ1²êû ®—¹cá±úÂ&ªÊ Ç0Ì[óéñpúEáF–Å\ÑEb•/2ã«5dŒÞBÊM4û,Ç:§Ug2 ârˆ^‘s%ÉC2ä(ç·ýhå}1Ë0û?Zq®’ï<¼»Á í˜öfÅOYWÙÑ£HÐÑfDãn:‹`pPÊžûUä€áwrR½&JTßš¦ÞIèQö&!ðÂH°Åm`ûy†í-5ì™ ‘”&R†ˆ÷VAâæ5(¤‰™´šÊ£R’¤_僼-êÔâªC?mÍ9çø³47Û–‰çKèÐj.¡¹ åÈ/HJZYlbEË”HTŠ'ÎÌBœß…ºñöBÕsŸï ­NbAºI¦N°½[+~­™àg„ëÔ–<1– ·Ü%ýÖî”fFÛ¾†ï 7Ùä:ñ.˜Jr”*S“ßšEh»-HÞÿJ¢ŸdçÄ£4u|ýDl€¼~RƒÃʤeIﰎטõ[c9âhotÒê_ÅÐÅ)n=˜“˜öÓ¹:m>䃉&&ìž"Ô6ꥎ®ÂãŒW7—Á,ÈHH˜ïå)Ò–øŽ‹:þ¸[|w/ð™¤qMqk7;Câàwoöô¾¨è+Iú¸ƒ;ËDµß çÃÈxÝ’º›ÈÕë<^ Ï<­ZL/”e]Í& <êÝÉãªÒBv.ÛŠd¸”oBb\öª’@)õ§¸dšýûÚúgØW´¯bÇr”§Ig}ÉÔ‰'xS¦ÍßÛÓEO éÃZ+à·K¸Üf©iY¶}=”Ũ¹·¦Õóé±Ôd;OÚ÷¬d‰ýêºã OE¯!‡Ò¥ôØV ÛŒüÛpŒëÒã¥ïŠ2ßñ»¿™8lDb¬Ópjc@[ý6!¥¿a 3F.ž•ìûäáÚUh¤]º>-óƵ$õcËãYüþt8Ïø1~\póßÊ™Î8™ˆˆÜ>ЧtÛ„æ}Ô“;K7N–¹ÏÆ)V2ñÍç_UêÒi˜è…*&uÙÈqß0|« Ä ž®Ä“Ójw¿üqz…îç+À[ïG¯º?íz¹Ý®—k®æ°ÔÀëzlÂÃn‰³Î®CõßнzW&ÕëRâwê¯5Ò€ôJÌšÕ¿óØ™gK?NŽhß¶0u¸)ɮᣲÉüáã½þ§“2­|tÃcÌ=6œ ³â … ó}ÿÌ“ÃÃê ¥º,̪p¿Ãë}uP?Ž{TݳwªMgkðÚyq˰óªÏwÈ‘$Ð ßÊŠñÜÐ<(Mò/ùH—|ý²ô’zÏKïyw,–>Ý=îØ/½{¥÷²]—|æ;“Èz‡Õ?z¸O,sz½›´UN²©‹ÿ’“q0endstream endobj 1229 0 obj 3659 endobj 1233 0 obj <> stream xœÕZYo#ÇòÈ_1ا¡a¶úžn;ÉÃz7±ŒÎ: ò`‚DJZÁu\­ÿøTÍÑ]ÓÓ$uq½†áU£¦º¿jvÝœ‰‚ãíßéÕèàGiyq±ñâðÿÅèv$ê)EûgzU¼>Âi•.<óVZ]š DQÉ¢œq ^~*O8«8—Ú•ë±`^z'Ëù˜ÃJc¤(ÏÆi43^—?Œ'&.Ëœª×å ‰À’*/ëEZz[^'†9çªrö\Ž3–ÛêGßÕRÊžÔLŽŽ¾ø©<O“Þ(_¾oöò^Õ¼pË´Ðå÷0d 6®ºÃpÂ,OÇÂ1á´±q9žç™° @ Þ `Á¬5ñ;lß~F±¦q&YT‹šÒQXÊÝžŽåI\4°û/QRÁ@ÚRÁ f­evßÏÆR2­¼+ïq¦aÚPF×abcIÅ+µGiäôB°d0úe\EM¦FñlZÁÀ­Í”1­Íê©­zT­ýnUÇŠTã]GɤòàÌG3pà§ Ð8˜êªõjÐïIäu7˜FêûÖ,½m;ât:Éyo+"ိš™õ/ã©`—½pÄ}­r_8l¨•.zNïˆs¤zƹ£ZꛩVsˆ,Ç;7ñ–›Ö5ë©md)¹ñ¡ñ‘Å“Èâ,;¡Q“ñܵޢ„,¿ Ì6YÃØ^RãÌ™6¯ Q1© kã®ÉmWcÍœÒ5#Xgw´Ó0Z‡¯Ë@;£óðuh‹0šv_‘?!À#¸è’ØËœ¿ÆS/ÃhÕ;_¾ìѳðõ$9G'ôèABxÃ*á}qÏlc—ÍÉ]K°»é\Ÿ¼ÂúO¥ c“¤„xt«ó Á ÐdJ+虋ød²j>í¤DÅU¹C‘Wm˜¨,MTï <ô“®qR›êAI·¶…~2TH¥Yeåï5䘺C¬(eûBÕé]W…ºìþKøŠ@ü†´´+tgœƒï4£ÛxˆÞ´Ó0Š!¾¤Þýöhônt[¨¦ÂÝ9¨¶ ®ƒS<¨Òaiöúptpø}±º[Ÿþ[ˆÑÁ·øÏë}ß½=,Þm,ضä6ˆדç|kz˜v£­‘é-и,ÀÍ™îE¦®L?æ8^¥häZjàõÌÏP ¢ÌWàE×';0¸vÐ3dýE6â3Ù2f…lY¦¸ÙPÊ ]–¥/¿Eš{’b Œn*C@mó ˜Ì€¡< ˆ>N6ç{pñÔ( ù<°«eWg¥3ªBMa,6Яx¯¼™5aY;I•m`,Éh HŸX Œñ¿ÖËÿ›2É p‡¡nÍ¥éÒi›”JA0hI‹ ¢ØY,\º¹Âe—ýŠº1L ÝæåÞBµÊÚIRß!Æ'ûžö&¥ \UÊösËœ¬S¢²'¶'ˆç¨ïYÄCâþÓ¬{ç£jŽ€R1÷‰ópÝéƒ_KÜ•?ÃÜ/1Í V&@Šà„UC#Úð%[Ý%wG¢Šz§ \oaAaŠ×=#H¥rôÆîx™gã2%»ÕpE› Ò)ðCø¼)ì:˜µ—„ªÿþç9Íx‡‰îÇÆCN.Zìäî°¯—ÐA0(}!“ƒWx‹F¯ùwôš_›“4 ‘J,q•þ1X=-xNÅ…H` ðÐ.Ÿ²Y`Sjز†úv8‹ÃÓz+êðé†Ëf‚« ”žz©dî"§qÂW‘ú—HFêu¤Î"õ,Rÿ¨u O~Œ˜î’ ‰·'(Çþ Št¶vCOšÄ“d¤šH…¡å€påù­Ç ä ¨™ªb♲\ØÆ´¯â&wq“³H=É |¼K9—‘:ÏèU+HÚç³çAeÏgP/#u™ÚË«,õ8+í"Ro²NºJyê°p­†z©U‡Tµ:^Fï³F"–É+‰ÉE6¶òì\d5³Ü¢Ðzxïæâ5c Ä×{QÌ-÷,ÔÔUš=ÒÍžà÷]&öš ³Ü¢™T®ù®ÍH^½Î²CvèDô,÷åÿÓ¶ïÃëÉÜÙLN&ÜduK4~jq‹ÆW)“©:Öƒ ýu̲Š'ê¸Èòz½‹W²ÙtÀ`羈f‘Á€fÊøªÊ ÙEÖù“¤«H½JÍœúì‡,uñ´ƒeÑM—qê4“oFü?„ŽæÙƒ‰§u¹Íˆ}ç6"í:e0•€ø4 ñg%õT¿ „}lËúù:“²Ž¡D_+Ö>ˆ0×Ù¹D‹Ç)¯©¾HúÌGÈqVp‚<Áø:ÉŽ/ƒfçÙóVL—Ýe…É_gÈ\‚1\ƒ¬ÿâNMî°ù›Õc5ÂwY5o¬ËÂ-r´IŒ'¾ýKÖ÷YVˆ´;•´¯J¼Ó}8p=Ñ“Ÿ¯ƒmÙoK w“ÎÍ‘–©$]Äáð–ÔÇf?¥ðw¦½”¿ù„A¨×Ùe·‘ºÎœ§>4ûåk¬$šn*NÎäïúƒ$£åSy¾Kš©ˆ¦Yã§Þ‘ú×I.RG©‡C KœŠxÝ«07ûÛ'ik’N1Õþù6>1Œ¿}žÄß>¯Hßy¿šÇ¦Áª×úA¿ˆJËñAð³ùITDê×Oþ|©êqK4½TMóL’4çYWÿº—òl-¥÷ýl §TØ(³ÿgk*OÚAƒÏÖi/ËCŸ­AWÌØ‡¿[KUÁ­Þ–O¸nZ^äݺcæñ×™VYAR“;Ÿ½þÓ¦¤õä™ "M’Å4…˜Œ ¤µØI±N1tñ·Í•ÏÆ¿ØÊq–…?dK{¦\¯O0Óé iœ@%a> stream xœÍ\Y“Åvøq^ü&ü4ã`ZuðHÀ: °?€Ã±ÚC(V+iŒ?Ø™ÕuduWϽ»¶©®®#Ï/³²æÝœu|ÎðŸø÷üÍìÉw°ùË36ÿþ}9{7ã¡Ë<þ93ÿìºiÃç¾óF5?½šõð¹åÞÏ-gƒ7of?,¾_®tç<ÓjñÛrÅ;c<^—ÖÛ%ƒ‘´|qZ÷rñŸ¾¯ææ_§ 3ª¹í¼eœãŒ¬s:Nê\'æÆø°ŸñÍr%:¡`ÌÅÛòxQ_„GÍ´^Ü•Ç}gõâߥõ¢´ž•ÖÛòxV:|’[Óš×RÉÙ¹H¥gË•ì„×Ò§#•Î •`S¬³ŒÁL‹›B¦×xJx³¸ì¿“Ðúa);­½RÛÑN±ÎüÐN­5‹óÒámép=!´^–ÖëÒJ¦ø¸´þ¹´¾h®á¢¹¡ÛáŽCëÕðQ ™§ÀÇOòcÏaU[憹N‹žþÏ‹¼_‚I¯}â,è°žw^2%ãk+FIHÎKÇ–4§·E„ÞÃB¹ëLôl©`%ÀçÅ/KÓq#Ë@8æu˜œ3ÔÙ•êÀVŒDMÔ"/T'µÙúÛìô/?,NËî~* @*Ñi®¯‘hRxgé /Êã‹%,•;ØÁ]iDf ÝIΩj¼Ïk¬èÞÃøñ5×2Mcâ †;$ à³¼^Tú¨blÕWÕâ˨ÐÎðÅIYËSìÝaZž—¥zs®ñQHÕY÷ªµ\ŒÒ=zlƒÄuK–Ð$YíM™¶ï =sIÞ°õ¼ôÉ›bD®4TO.øFˆN ÍAÜP|@[:.P3N/@È×åój+i¢åÆ+­-ŽóìtöíìÝ\ a:ô ïæ^´sÚ2PL‡þٓ“¯ç·ïï.gOþ9ç³'_á>{þ9ü9y:ÿÃìÙÉüØCÁça.Œ£ð{m¼íÔNãL8fÑv9œ©“&ùå¤ÌµôAGï§t¤+æ¨iì!–,\-tÉqu Óz¤žAʈúíU\døÛÒøªTQ£ë¬ÈS„ÐÜFšîLˆIqÒöQ‡jI¦¶Õý±™ó| V¾ç1ßHø,÷¾´(iiÑ{)ë&¼×ë"I•×Ì}_¶äï§hÑ+ID0£]ç„¥¯1­òÑi(pD€/ŠÅŒ>S›äžàuv™" êlZ´‘QQ²½d$b‘ÑŠKÙñäœ]eã.OZ€™uW„W¨/{*ø«¤Óß/FÜ  $ÝzO;T[Iäy]Þ< v}Ùô-™+œt%º¤êY4|W&ÐFK²»@·uVéÃÆÉ¶û@ûi˜´½†½(òý[bða °h¼Ê¾‚¼'j{^ØNÖBàUå7’Øi%â~Ѧ6|iÊÈ¡¼M2"å‘däÐòÎ(íLð°°Ãw¶û@ûI?—h8h]ÌYñ Ö$»gÕCI}±Á[I}1ÁgE¾“‚ZöëbÃ/C0ëlÈ~Äïošî¤­‹µ¹ kÑÓRjœr8@"ÛÅȾaÏךÞåŽwþ0¡U⸈“2ŽÆSø,‘'ESÌn:›»mEž´½%‹ µâŠ&Q€ÿ•¼µÈ~ʆj£u9Tw’*œtÌí§ƒŠä ÒÙ(r/:&9"'6×CNÇ£Ù¤ÞÓ¡NÄÿ}ÆI>'±TÙ‰ñ©¨çD3Ÿr= tø¼F¹B²N3½Vÿê$ªj{¸úöú'IȳŸcŸ0m——8X©’rÊóòY9wh?åñĪ­ƒ 'øw”x)uüxiØkºŸfbí²©~%k±}–k/)˜—„Þ=>?âP-šÝo„#/nPBƒtÊí#¯{_]T²ºïr-T³Ô )ájJ«ºdë¢d뎔²Gv7ð #ºMÆ>bµ-Ω‚_p| waWÎoB­;¨ØîlžÔ .ù‘J)öjJø¬=»‰Õ~U  t, ž@ÒëçIãַ*ãðÑ{Ýi°ÊO#Â…@iñM¬™Q’cq!ú:OÙ3ÕºÜj5:n,ÈâTåC±©„Éœ0ñ­ìáQšö;"Ð(_„ÚIe„ãé‘[O¿y¿9¨dPrÊ#ž’ÂØoHÐó '%vö3îÑʈH9ô¼xàiy8ñ ›Ñœ``rPãÊ´ª[üJ€µ¨ÒùÍfˆ$d"(päÕ'ba*ïÛÇ×[žt§óoHÓÐR ,åv™±§}Cž)cο,s wÄ 2÷…Ó ‹qh©¡?!U²¾E^óŽOXk‹ŸüRÞQà¤3Uú.èPäȱq½¶xʲ˜‘· ù’¯ (¸ÌƒQƒÜIÐ1]á¬óá£GÛ>nÌOÈÒUäé “ùÈÕ±âay|Ú¸I"¬<ËÜP'†Öä¯ìñSBþGŽ“?$MÜ|þJÀ 4«ÉìúŒx0Ãkºî$h¶#BtÅÂM‹t„·Á}§¤’ñåéëÓL5Ñ9²ò§ ó} Ì´‹µÒÖÅä‘|0õ(‚mÌGN§Ý ÍÞÀ¬ýŒ*j™®VÕ8¿»¥—Èê£+i×YÛ I#k;4DocvÎ21±–̱9)2Rš*)vÔ¦KÖT4hCä#—ÝEžœ¥$5uê!­ìUeëFÆ¥7)½t¬€9Ç8ÍJ„»åøü÷Qå ÚÒõºi+Úø¤Ãï1+#ª`›ôM.¨-YC]Wù±Á¼_KVp,7¿šK‰QÎ}FQF#P†y:5J@4Ó€:1gGìëM“’kJ¶£J®·>VÀ0R`;ÐaW›Š !ãóó|Ù!¤± mfˆáŒ#*<¶k‘U7Þ*¹‘D× T?,YPùyŽi?%šøt)oðõ§ø‰èÐÌ5k^Éê]‚IÍ+#œ-óÏ —œ0 ¾Q†¢¨+\º ©Ü"ÜĤÜÑáCO@a/NbjRO¯_âðv9=`¬œ,b‘/cM áëÚ‡@@cV÷‹ä{Ávk8©gµ_ïà`«*&XÂVÅX^Òqs2Û‹)IÒga‘FÔØ4„‡VNÀXâ†F:ÈG0ª5À·ÚO”¾½Æx‚ ¼Üd·SœÄrµ‘Rf;×úLeCÏÈÝ¥Z«k¸bÿ.ùØ£‡ª;[A½kM4RAš¡5Tó®–8D+ºÕfyt9G3sÔ>øîB ïDÍÃd³/†¯û’ÊÔHT5ךûÅwí+Fï² ½kRõw1ªÒo §óZóñòÈJ¤FUص)!òÅ’ËÎ[å©dgž «Ã£¶G­s˜óZï^ Ò‹*m]H]·oˆϺ֕ .7áÁ"&þ‡8äb©9mÅ1³éÛÇNí³f²0²o]–€Ã2Ö)0$1Î>¢6Ã=¦j…Å`9ög¬w)އK]ÿ¨ðÐÅv¼.ÞŸôMbÓmPD3ŒXƒ‹W$%4¾!!èe[Ê:e†Ñ/l ‹{Û6ƒÌ¶Ñ¨´Õc–žKk²YSj9H#Ç➦¥{WºÞ ¬nÛjôsæ³¥³ÁjwºÖh´2,ôªÜ“æžâÑSó«šS}ש\ ¹ _¢²ÂúÇIRë¾ÔF•¬ø  ÇŸúØÃô—<ÕšDöD$‰ü×­9« ÄóÔÄIZMx%#ÉÅ~‘B~ldh1PÚv`÷ãå¥yªçKï@Á”Ò ´Ìúã²d ·°Y¾óf`´p+V×_<„œ‡–[ºà‹I*™(hÁmM]®oŒoLç¬ÚUÓz8ØhÝŠQ²³ü€M.ÄðAøà^ºwÁøVÞ"ŠnP7Ù¼lLbâš·hdÜ®œ¨|Ü¢H­Ïzkr'ìÀjµòzM’zHàI¾¡;á[×{A…xófT—²ß½7$49ÀÂ|t9¨!7¿ïÊûHaÅ“ „5Ž¿Äkuð (2æ¯r{ñè?ìó9 k+M¤%ââ‚JâƒØ‰ú76Æ!~ß4uýé>àUƹÏNݦë6aß$Ú'¶½™?nº±7o¢°N­‰5#,¢??2Yi08Qz¤ôÍ~²¿u÷0n+|EÓ4ÎŒ—Ë3|ÀªÝ’·hG©Àwê‚^ÿ³kDÞÉÏ®)†7sÎñÇ®ú“’ òœ´8u|¸ ÜãéCßÔT£tø¢`åJUcÊô‚¬˜ã¯kõ&TQàŒ:$‘ðI9dojk½}›ÛÎ_ôEjû0øÂ„¢•Q쀎dÀ××ùõMn“éiÃïëÍ p1òáfþÞþé> stream xœÅ\YoIF<úWÜ7îEs;µ/!f€À03‘xN;!‰íIl†ñ/øÁœS]Ë©¥ïâ8÷TwW×9u–ï,u¿[±‰¯þÿ>{òèaØêâý üsòÝJJç&nn\xã'åVV0>1‡/<~ròèÉV7ïn_œ<úóŠŸ<ú-þóø¿‚?O>_ýèä‹'«?ÁT*ÍÃy,¾o¹7“8f¶úÍÉw'<¬zÿ<»zü4¬œ¯üä0jõôüd¦‰ÃSbr ¾Å'7ÞžüeýõfË&㽑z}½ÙêÉ9ïåúfÃàu­_¿*—WåË|ù·§¿;ùâéIG×ÂMæ.”K•öU¿$T½ÛØÉ1ÆÕú¢,ÿ¶\¾ÝÀ~z¡ÔúÅfË'c47„<Š%JÓìA(HbEè75ixÚ§ÅKXñwañžsèt6n£d–G€b¡=sé-#Ýú,=ºH¦–:ˆü''64°³Ðù9n¨eÌN)=‡½µV¹>-ƒ·…ü7Evo2ýKô)©‘w¡oÑ:0kñï½L¥í½¦å‘KZØ= »FvMN×vÆ]ÜÀkT'•C#‚WðÈa»ÉWïÓݽfå!è0|ªÉøy^èu&ã*µáÝ÷yìéj¯¹7Ò–LˆIšŠ°¯ˆ‚}]®÷Ú‚Ø…hzi²¶ã= ݤ‹÷”ßÈ 1ä…Ÿ_óâœZÂ]+“Œ¡…¢ïŠôu–WÆê!zoçʤ„]Õìûlt¶aÇïËÐZ/ÌZ8pÃf¦ómfÞ‹¬Heìy¾:Íw¯÷)W²BÑl7AÅn\æ%ßæ±BÚ³|÷EoUöÙû#mÝ „ÝÑn<Ä.$»ÑÉhà‹†÷0ô<]œ¿5„Sˆ¢×&ßÍC<]¨|OÅ¡}zz>ŒõÔñÓS+2?‹&¾n¹ûzàÕ%+‡  —±RÝ´ÜA†äóC2Þe2žlPîõKñÑAëÈ‚¿"ñ àèø›­œ„WÖíµŸš‚d7Z î`7>ùR£Ñ K%Ë[ÿzÃ'/9Såj¯Š¿ä±Š¯pi¡â&ä4õgY7^ 0íéÀs½iœ7^ ëïÊ=ÚDH¼gmúÔ$mj)¸ƒ6}ò¥Fm"KýXm:~ÉKµÑöÞjH=‚w`´Q5åB¹>Õ¦<ó}ªÍ3­0%À-Z‰°ö^ Í×ÿ.¹*2ÉwœæÌÉeÞ)Ãú.'­½Rû"U¼a@6óÙ|ÎÈ\!GDþËêËq+5m,²õiÖL!yÉ„¦÷À?å'éU!„2䓞®’ ~ŒÂ)¼ôQœUÚIJÙ0M(3Yo×ßëñ²Ú‚”q»Á)€F‘VãlÚwL^‘4]I^åï MG¯âwO4à_–Éz"q¯Ëkçák†ëL¬æ~LN¼Ê¿QcóǬÁÕ°7*gT1-W1 yX:\f,eFmÇïL°ËLMHëÓs0ný!¿s](%÷|ƒ²$0q¦@zžž¸Dá›Â?¢86Z{^$q?Y£(«_ŽRªIƬ™÷=²‡¬å ½V߬¥\È‘×H^ó¬ÚX!Ù¤…‚€$²îÒ°Ñ(^kì(­s¾£Ò¼mäß–ëÉkïf6~[$úC—6w–šbtŠÕÚgI8(†Xi aÁ± Ä­á%Öÿï‚Ò™¶›“u9ôûK ïÚYrþÉÚnúEyož LŔƦü<°ß€dkPóüÆßæ1&ç¿$’\ô4Ñ*J—¸Uà õd'ÞŽë>DÜ:5<ÀþÇ]ÀõûØ6ÞÄÚø²Ìc6¾K&Æù._ëô˜€Ë.9gÒ,÷ Çwû!ÀËJõ(òjègI}éghÎØÄµ§¼ìœ>;ûàPbÒ°ÈÓ=÷‡žîtèéȧ¢S ñ|cÑ—4vT¸àŒ2ô[—•áš§ßC -@ôCJOÌë?ò³ãä) NÀ]ÑØ7™Üf/õĤwÙ3ü¤|dyñÄ€©{V!ÀT &ÓÌG.#1£·Ìû€X p4Ù…ÀëNIÔ=¢¯Œ@}8slœ&‚Iäî¦zTz4A@09¸— "øÿn<±ÞÐGKñ€~Ïlšàï„¥á¡Q@‚|€è@ùõðUÀ,ŠBªsœTNttŒ“Æó+,콕;ÁL"1~—À ‚¶Ö)–‚a7á†o1&ŽZ»—]5\ b-m’Œ×°'ÕŠb¸q…züaÒL£å¢zm†›’ rUseÀë²y€8A€ÉíüØâí>’Ùˆ-Ù¶à><ÉRˆâFÚh¤Žk‘<š* B9¶(ÌL ”­ò]XÀ7ÎÚœL¨4ŒÃW-Ó- ,™ QÅ«@CkÕú_3qØ%CµæäPçt& ç â¶°èâ?nÕ§æŠ`a|Bd`©þÕÁšà ÿ‡L0œµ\¹Ïh^´M{о¤ëÁGo©85U!SÕtü:²—ñ ØEíϳ2ÕÕh~Ü*ÏÁ:x€fó׿'fâ1’/¦ÝTT%Zz5AåéyÙ¨ q`ä-§6NÙnuÄr€…Ì^vPÓ{~ú…¥&XŒø£ZïÈA8`çI§Ë¥É!ܬÔó&m¹˜·éuÑ—Ç¡HDÑSrÍ:È;ƒrG•0ê lr§/ )¢Žq¾ `C\ʵ7VM¢s ]ÏîI(4f€“rÙ]Õ`ºã.xë@ÿ¡¡è<&ŽjAGwJ/®áuIø™¼\͡ɀَáFÍz²§Q¯ïhUcH ª¼NøÒA°q/VJ ”’,°ÃX!“QðaWøš\@HwUYÎål¢`î0hÎE‘§°™†Ía^B|rž[9‰Æͪàp̱)ºnâÐÈ%ÍwjˆÜ”s!ß(ƒvýç fb¼’µñ È!$>åBìñ¦5ÄŒ]MB"µü­Kâ[?ŽNß‹Z[q¯Leçjמ áÂV¤—ˆÿC·*2n‡V„ms¡Ɉ՚Ø-ø0Ñâ…£Ù¼}VF[ßî¬s‡øvÚ'¼û‘4I¸ôE–°‹©ÈpA6„Ù!Ó3Ý'©Mc+¤tV—®²zôâši›ÈÉ«–ÖÖ Ö=…Öp–I¸Ô‹Y djoh܉LBR4­ãËøÝ¥<~â‘Ð¥ z'ÀÛÕe $ä9@m“·¾˜Øð©dÀþhÌ»HxR¶à)á€ð–Cð™’ûÁª3)Š2{¬G”–yj|™œ5QÈŸ„ÈÏ…øwþò xQÝi öF%h\QT¾væzVÓnMð{Ý ªÑí\Ó‹IA+Á¦uÑ *" ”Ï7@Š O…×䳟E´¯å.w ìÅÂÿšûv7ìlî}Ø`ªÿ•Àà5±CƒIrYjzßoIÍ+ÿœU¡hjÌ’:&Í’J'&G[¿0Iú±l"túK'Å'ïÒvTìh`Û“Ì…pƃ“¹ÜyØ8O=Ù‘‡‡8&¦@Æ™Ý {:ªeø]k'.ärÈÉ'`LˆšŽsŸ,ää6Jip±ˆÆ[ÊÑ÷T$yŒjñû–Ax¾lô¹W¡hsdíŸÚ‰@ ñdcñFO̦‚:¸•=ÕйAyí“{(}†“ò¢y4¤æØžÈ7yeÀÜüå,ÈNEü8yÄk‘,IÇ~9LÔ}Âôázn` +çpǸxÆ”?uæc§šÝÚ¼Eu¹€!ke ¥WûA0×à\/ÔMJ^:K0ÝR7Õ8›Zäë‘Ï­ê8D(SXÓw\´= Z3±‚£Ó3f2ÊÑ· ú."ºXë$“⌤v²Ô¸-ÔÌ2ò K)À¶ä³KIÙd™ºì}¼)K­Tl!Ãq–B¦„ÓfMCó³tÖ1XÍ{ÉÛĦſ[·‰V=[š·Þã*øµ²×í£ñç¾FÙ{ô¤Ê_wÆ{G¨˜®w†MÌ€¶S£º¬rl&s*Už¸?4[cã!š­}€ƒL/•qú¦êˆ#å–Ò$–­ø UgÔ¥gið¢Ô›È‡†Y#²èqÇÙoˆý#Fçó˜Ô9÷çRB0f¥Çn·¤ô(Ù¾Y¾ÍqF3' è 8µyÇpŒËªsDà÷Ö`¾í èõp´ >0ú´+¥´£y…£ŠÙUY#,’€ DÝ)SEEðÙÌšAéÿ´šjÒÕÙî°XÉ—3 FþpAj|Â.ùüqJ°-HÆÒ±4!æ+hª›8ìßf´p¾€©Ô¾¤õ»ºi1ÂhÇÌe$ìs‡ðê0¨›Äbom4¦b¦&¼N¼ ¶ BD§“6 dîãxrŸ~+Ð,0&TÁÎRƒÝ«ú\.E€8ô,]¼©è…šëÁÝx!åÏîH- žÅÜBݪW\Uêô’­ÊÎ&× R¸M÷d*š½Ú}ž¿ZA›9RIï Ϥ¶´}É£Ú¸8Ô'8›cgGH¼-p)°LXö*ö„+R½,·›æÍ‚²V•moaQº±*6Ø'y®[kÕ"Ѫ­=H4@›¹â©œÙÛÄݦެ€Î‰)±áçäDJ¤F>Ÿ 'RHÇp”N<‘Òt4  Js@…#Ž›}Þm¸fxqÇs*Å:YŒö9o¬“ÃöhÄÇåh 0 »%f±‹—/Êåü`Óô@¸¼šp6ˆx}QFß—Ñ÷Ã×`2í v>ÑŒ\–ȇe&Ъ…ÃF‚¹”ü†ììm®,5S̃j†˜6Ù›l•Ho%ºiάC-@<Ù/Ožþ4£--}Û*®®$roÎ|W_ 9UÛ‡®#²kN6º5OéC³yâ4\9+ÜŸÚ$ÀÙ«yÑÖ*ê.æÓ\Øbó}‚ÕGE…b=:}iÀ`ÕÇ1èS[ œ*û `XŠU÷°êÙ*kRÛ¿ü¹mÉ²È kúìÂ-_O›‡™Û® Ú,ë¶[–¬lú«Jóšž¼$a~–›ªMSHØ>:1ж¡„“ ÍŒŒ+‰Ä¹•,æÏªøÎLjhÅuùq“rÒø²ïH'ç>þžïžç±ÛÁ»U$'BgCtü·®š@¯þIƒNL¸ÜuòWÍ]D{·iË%Œ.¿LtJù³­-v_z¿Âžu ÝiÔ¼lǯ XH‚büÚæ¾ÇW¦«½¬{%BçHuR§>=ÛÔ;ÇG¦¢GH«‹'+ãa“Å¢N˜³ŠÛ‡p 7 Ï”45QsÌlIy¨”™O%™³è’Ì•ÊÒóKòèõÈHtág‹¥Æaí>àÖ[]90HŠ­=âHuÆU¸îw/ÛJ*dµJmx> stream xœÕ[ëoEGðÍÅ©ŸÎ¨Þîûv)TjiEƒ(j‹%„ªªrmÇpâÄIZZøã™½×ÎÝ}vRÒ 9wgóž}p–p&þ)ÿN÷^JË“Åù€'?Á¿‹ÁÙ@äC’òÏô8y4†aÆŠÄ3o¥ÕÉøpP0I&Y&¼O2Á‡_ޝÒ߆#ÜçF§‡#Á¬Õðy©CœŒ‘"äTç½Jÿ*Æa_ÎWÔIÆ|Æ…+ræL¹¨sL&ÖY˜X¬8Ž$“x†eªÏÓø©òOÃIßÄÏÃb€ËLz©'‘:Ôïâç÷ä€U¤Î"u©jjO8æ4—Éø—ÁøÛW%£ë*~"¹€‘̦ܲ?€Î\øÒ)+âJ2RM¤Â§åš!ÓP¨Ó¸,y¦3o}2žNïD&ÓÈdEêé0R"u©Ç‘z§@ïZ `mǹ«ôV_ǹóHê¾SÊ(U‹}‹ç%Â~Aš°Äž¶²?'!/Iê”\´ZÉeÛWB^wJB^“*Û*^Û4­%gqÂQŸ•háÞþôyð[Ï8FÛ¹”åÂÎu{…Ayê„äPIëk{IÕJÈÁÉàœ“š¡Sæº »-Á§k8Ùm@º³²¶¿µ„Ù¥-Ì'’Šœ •œ%ÉlBúñnj¿ Ho§ÚV:ø•vÞ]ÕÿF‚ëd'e|–Ù‰n3PÕœ‘°iÍœ“ÒNÈi½a²9¥~ ¼&õwà7§Ô’JÛBšËÞä9#™]Ô]cû‹ ƒŒjüi¤.÷朄ÝköQµ¥½B‹PÑ 'fNɱ-•;™]¡ öïû2½;CþBï[]€}møœd¬ò–4 »³më€ÎŽÈ‹§$õ‚\¸¹{ÊýÕˆs6Ý?ÓözK fô~åÇÉ YqJR;½v[Šniîíª'$ÀsR3 ÒQz›¦Þ%öÞºÑûRd­¤]è|BbB6¤7T]£a÷nÇVäXº]@ ¦Ò¥Y‹NÁˆzÔÖWÿW:Ù¾»{Ú‡è´Ö‰¹½Rð”d„ž“é R v­Q½¨túÛ¦¶-Ìv- ‹>(;*ˆ†½¥BÌVMØdÄm>!A©ç’”àÝñÒ©Qí%zÏBöQÒNHè’ܼ·û/Ü¡šöéuEt·M{ÑÏx]m÷u»·Ì¡èârÖMÖ}¡~Ëä¢×ûËE+ÕyTšè6›>¯Z–žâÙÇòZÝp[UWXSC'ñ÷eÙ°’æ:«¿Ž"ÿiœ_²²ÊaØ…\^S0ž».®³"ý}?¯A«ržuéC4 b= X’¾5bÓ*ìøaάöC›¾æ—ÿЂÎ#ƒ\V Y!°Ü´æWŸqhåY0ÿ)’fNBœE¾hÀzh ”“¥ ~—þΦÏB‚SÒqr5 Iþ®FŒ4*¬4²°­¸?‡–‰,X,¤RÅóG#F Ç4¤]”"~Ìõuì ó†:þuYוP³£ÖB¡bœ¨Võâ*É@6ºxyØ4 :VA`C¶BÝ8%ƒ7ÆÈ'¼ƒD$pR»¬_ÆI(¹ ̧ÔÐJ~ˆþ(¯”ÚÄ'¡:eFÒ:™×Ù*¤WTàuôœ³oð”RBÌo¶j·Gc‘UC ‡æy¶!û]"±PFÊ=T9½”¥táFž¼$“GíW²•i méôë mð ]ñÒ"‹46Üa½Ý©*Ët/±ã´…lXåœ?*Ó’Õr· Uºažvª•¡¡ƒRŠ IDu5­Ôyž44i ²†ísQ,¸K8« r“iµ ˜Ê\l£qáFxXH™6G9: ¹¨æR‡#ŽÆ²MVÔ˜EBOi.žf;ÛÕæ»Ý´H¨³@C±ûv{À£ºß è ÁáqÛ@Ü…f¡7´ƒU8Tú´b®‘Yš!Òª?w ^Ï Î–—eæv«\³5IK€­¯œOšµ5ˆÏB ôÚ˜ŒŒ´‘Ì8„Jp™0Þ næU©PÐB_kóGÇ¢ Uç%i{£Fßû “¶‘úw¤ÞÔßöŽ ¢êøBµ0QAe$õuc‡*BÇàëÕè¤eüœÄÏEùN“‹ðšU}£Úpâ±$%@ï½>ï¼Øí¬ªyt_ɇǛ_Éîss‡$íŽéïRÒ‚l>ü¾¾òF$øì°Õ )~Ó-ú ɾ÷XrÇ[è®:XÙì(ÄV¤Šé'4;Þ$´ŒÐÁ*}¡ß„½Óí}3%ÇÒʤQ¡ó³Þ— [ý•†ýþj°é·­W|Q´6rÒ •úÐ Óñ—¶¶éÿ‡‚ÎúÈ2ô“#ú}@Wðòô}ãA4ü¡¯†^Ix_ž‹º×Q±×É*b}Ôøbð/Ha¼õendstream endobj 1249 0 obj 2211 endobj 1253 0 obj <> stream xœÍ[ëo·/úñþŠCúEWäÖ|/7i$±“ºHS'Maœt²ìÚ>˲äDÿ}gvÉáîÜÓ'»³| ‡óøÍ÷vª*=Uø_ú{þzòàgÔôòÝDM¿‡—“·Ýv™¦?篧ߜB7Ü´®šZi==}6QUô]·©6ªªÍ´ÖªRnzúzòï“ÏfsS¯¼?yÓ6]¬ýÉQÿKÔ ¢žõ†¨O‰zKÔ5_R‡•¸ðoÃa-•˜üÏéß'Måê&4ÓÓ&§.vpECD½©¯Å}݈Ôkq‹£-õZÜ£~ÖSq3ƒ\Ð÷"u%òú”¨gâ<67ì੸™kq‰WÔa|¶Æö MA òJdðBì»$ê¸6ì÷mJ}+Šù…¨—ó͊:Ø×ùP*ɘ_ˆÓ3å;Ò=¼%ꕸ¯¡}YßÔµ`_ò¼Û¦P²ê,‡ûj›fƒÕG¥â§áJ¯ã ½­ž6U x]ð¶:¹Zp³Á‚÷6›}4›ÛÊ4Þ6¨{º Áy‡Úë«Ø(h‚;߬,‚‡äØ4 @ÁÜÎ4™Äq¨ïf¶ò¾q.³°ÎáÇXª®PpÈÇŸfó \–wòu·§&f&Ë tÅÇPE=Ð\œËÕ+“å»m.ã½xFKÑzuÏÂ?‰øsG¬kw è‰ÞSs¬H}JM3òZK’ኚWÔ´¢:1ë^‰ûþBŒ=÷(ÚÜü\œìX s9@Û¾_²Õ´^™lì÷¤µÌ‡²ˆÅ0Â;qßÌ ë¬!1Övø‘:žuxEâUÂM¾²!Ã&¶Ò9 ö¦DÚÑWÄñC lë¾8œKû~Ù·æ$6ˆÜRÓ^ìÉw(_œÎç^k9bgÃ3§¦XiE¢X¦Ã‚]±£än2¶Õf øð3ãàL”µÀ—æb}>Báå´xRótTs ác{bgYºR˜(8À‡yêà ÿ¦Hˆ¬Õ•ŠMá:˜é“Z³8ÿBLŽCËöái\`Þû–¤*Ai>Õu-óPªÊ³ßõÖÈ MpI¢Nòµº8vž°À=$ÕUcÎKQ™Ù–y©50¯œ™Û Û.°+øÀóæ$Fl;ªaw̜ה!»&›xiÌÒ Ò u¾¯å)¾õVô\dEšeu]9«ùü½’ÅñªÙ¬”nФ÷b¦¨¿æ8Rè–ºÚÖá2’Úq×ø w ÜÇÃ@nugÉã³s¹í}l‡²© 1Üļ—rçºãœë”7þ@ÕæÆv‚T´ I§±;ÚI;ÁØÁâ\C;iÍ¡ˆ+²pxÑ!’®Ç¯¾(³¤dÝqh16Ž˜Î;·‹™µ%†à6³Ü¹ñÃX[ªN»q€p¿Í4ևà‘Y}™ŠC¶.—êäÖ¬G&«%‹dýúu‘~Gôˆ[Ù2ñW»TDÀ±²\‘©emdž¸›k¸®‰“¿Ì°h qžÛF©¸rTaF1Ñ,‹Ü8ŒÙž¸&5ÐXÖ„$p*:­#äk¼öu·N¨hD#á‚1UA3L~;ÌÅóÁ«Å]K¤ë5?¹âÈù®[Rü,ƒÜ*SãÑÁÖëë] 0sWÁ4>)õ@QEKÈÚ Pè “ÜÁ$º“+EÀD/ÃÃ"¢uöíQ_’}½z›V£Ÿl^‰¾0ûºènó,K¦Y)hâÞ˰ÞHoÄfÛ¡V“6¼:¬HŒƒOWxm¥µ)Ðv×á]ÕÕUÊi±&“×)CfÊLç„ʱ‹ ÐIŠÑ5æQ{$'GªŠÝ<Ú(˜Çá Ìcï7_RíË­ –CZŸBéìÓÅBtšË‘s¬ÛªÁ²‰ˆÕ9ËüÚchœ­’AÔ Šè¤ï»WY× ÂëZ%ØWkÕI5nÏ+µ£N%i¦Šxó~Ç F;PÐŒ+õVÙ÷JxïÜ%%dÜáͺ·U [¬&ÊÉÇË µúk­«l¶Ö ˵ eMaT0”íÙ\âsÌ÷ bîšb1UÀ­xÂ(UpͪlLÎú¼I ZÐMJÚ°E4Ùï‹fº¿ªˆÑœF>OÖÝ&:Hw#&l*yÐ_Oz5|DjÈ4–iäÙºÚØ(_”/ï5^Ú›rýóþ¢þyyÑÓèëËüu]¡1Ö .Ê1„¸aÆÇköqÝïã|§§FámM9Ûà…_*¥m«š}jð¶Íµü±wX¹†w[ù1ã¥tS‘+_k.ܘÐ2¢­Ã×2z­ÙÊŠMK~ää×Yq…´É§ä äxý¾O9“àç¢ó{"Ûƒâ~òã5³sÔ¿wÖ:ÇI¬±¿ÛË›”ŠÞ/>°,ñŒÂºk[ŒSÔXuUL–Gw»cœÀïAtӾǤI‹—ÉÝ‹n†>"¹ÃÐ@ÏaÆì.ȱۀ¢ Þ¦¨êTo¸;(Ù_“×Y}mê#%!‡Ì$øðáQ^nöÁVÑå8*ÞOŠ.äÞ¹ë\HÁó"§3k ð9–¥Ê×÷õ›^ö:¹éYs%å/1ГàËiëXeà"-‹Ð›®ÂØ/ð÷÷ï]r"º†zĄ沢_ƒ ›QÑ>oîfÞ(ì>)ËþJ*Z"(Âq2–&:Èj¼N¿:Øù÷L©œ)¿“¹(Ô0Ç.ÌmŽÕ ÝÕm îÏÅØÛCuWèDûòʺ½,¦@²é !ÝE[%µM,«¤98^U{ÍÉ^o±h¾’ÆL›Ùãè^4ª­5¹ƒT^‡.Ú{­0™¦½P…sÕM®sRÝß’Èb&ö›ÿiò?'òËendstream endobj 1254 0 obj 3432 endobj 1258 0 obj <> stream xœí][sÇuN9oø[ŽvSİïéI7ÛLQ–Ì Éƒ•RRóø眞¾œîéÙ—fU*¥*a5ÓÓ÷óï\ºõnžbøOü{ööèé aØêòýüëèÝJ a^«Á­¼2ƒq+Ë™˜Ã¾~vôôÙ÷«û»‡WGOÿkÅžþÿõõßÀŸgß®þéè»g«?cUðy¨‡ õ¨A„zþ]^[ýáèݽ^Å?goW_Ÿ„žó•¼F­N.ŽÆ1ñç|°beðÅÛ£¿¬ÕæXÎy/ÿûäߎ¾;9št F¸÷ípØ-Ú»“ͱ„WÖ­_玮_mŽ…ƒ6zýíæ˜ Æ{#õúOä÷>xÉ™ZK,lÇÌúÅF Z(o°hÄhnÖ§ãO õ¾ßÈAkXò‹”|»…÷B¹~9vÆÙõÕ†ÁH$³|ýalÉZï¹crýK^l¸ ~AE0 Z¦ê±õ;ø\ʯÿgË$%4Sõ *÷ƒtf}Vž’ÖIMñ3#V MiÏ\*€OÏcO'#!ï/ÊW7á½ç\7u ¡ Ó'´`-i¿ÈWdÖn{³Fú}_=’ š{:[¤§ܯP-lØ='ç°[.sý¤QRÿuéÕ=Ô/,–©Û8nÒíqݼazì¬e8qñ霴hnYÄ…}¥¥‹ Æ;>¨¨'‰ï#*z”øçkFñ}9•Y›VÑ0ÙCü„Ï0c—Š¡Ï’ µà´ìyÞ´?x¥µÝµr=ãiåœ9ÐÊí_ÑãVÎÚ¼r}à}S&9á‘W´YÅ"ì·Õ.Hï¯ËS¬‹CsRö =ù. ñˆ]ŠbOÙ3¯6œ žj+ ´_ç÷ <³Äú0zWàèC®àMA®Rë%Ö*`KiŠl¯)à‘P~ý÷ÒêïQs §ýúYitÔ\†‡’aÌÜ­ÿ9ë8ÒÓË4=žjÛl·=À?­ÔPj×EÚA*A \D䵸É#òÞwñ”ýBŠöŸ> ì³ú–€1AØ?[U½]ˆ±§qò(ƒÂh9DƮ۟¾sQrJç¾B𔃑v?ÃáyцDÑøkùyœÙ ùŠèųb*8LLjÿ¡DÓø­Å4Ðx¢€’f¶†Òì áø2Æ©†|U麀ÚÌöÕÖéT{¿ù½)ÂÉ¢H+E¤ÿeá-iÃm±‡ï¿™f…OùÏZUOŽ•×ŸVÉD90dQVÌrAþ佋‚Lz÷W’‹Ã`Ô×ÌNR=áÝ}AJ±¬8Çuõ™DÒ t[áÎÌn{Úÿ¦QÍMáZ÷Mj8,ž&m>ìrÈÂ4J$› b§\Q`ànàNô JP+~‚É A²pÁî+X‘yXëdHŸ‘ö_–§u·C½®aZÒ`ªˆPš6âŸ{½grÈγ:’†Òź…°(éú´í>L(“îö UEôéÀYößMí8 ”_u8iì n{t?l]hPqd'|H5-ù>v×öx\\Ð<ãò¾,â}Z  HWåT;†d–L `ƒÏ…@уgE:¢"––ÂÄUSghè& sEÉÏ({*xä^b]ÓŽä@Ý=ý<6EšŸ†poz@&â¢r²'¬=’¢»©¥kŒWU/þí¤Ri ä$Lj¨L¯=ùM´ÒnFP srøò¢ª?‘¶àÀh¶CAvj&ü¡lË*-~ÂˤÜKøsж–ø‘Š–iÓb‘ÐŽ›¡úTÙ¢p“Ok8m0ÌÁ›B.#q1Âl¡7,J“÷ĈÆdŸù¬põ߄ؓw=ƒŠÉAjOKžìõ$÷ÓZ¨P/ÀÞ{Óž+lØO5±zõ¾}yé;É _L7–‡*84ón,‰3 u{Ý TÄ1^Ö" ävž ÍÞT›Ø)ì¶šäŒl£!1É‚èÆ:û㯼:Qsv:‚cvæ±Ú>¡ˆ ˜rößo8¨•¼–q"£’tZ¯ÿÖ•ÏIjJ›îQâ’ë'P–C·šê)œÁÑ*ÕB­680 h§ÁÀà1Œw¶+PZ\åøã:üà!ȽI?.〚£Ê/ã<¼ÔZÅò*ˆOzvš½Ìo¯ò³Wé1Ÿ%+f*gÖáöÒÜ™ÃäÍÏzœ`LÉGœ¥óÜå±£c¦Qzv“ç·;¤€µ«Ѐ@ËÖã9m– ê1lÞôë>¿}OÇ3ïƒUÒ¦jªI×°rPž÷ýÞ»¶/÷.NY®=w+nÛ²ÖÆqX‡ï†ô¨Ù÷¥kó¾ß:TP†è0¡y‚þª8a2~2#•n"ÚÝ|²jª1IAÈJUµR+.aÍÀ´™EýðÞÖásaÌ`”;0ÖSçž…Å7ºæ„Áä`©ÕMI ÄYß5“*vó++î"­ì¨[ªNwéÛ€Ýw‘l+¤IM6dŠätE›E0*Õ­º}6á2`¶®TÁìÓŠ¢…ŒÏ*—˶FÊv}=­_9|Ô·ÝZ¯…Â|Ž* Ä 8_ïéáñÕj²â˜lúŸèèlòJšGÉòi‹ñ€¼sˆXy³ɵzNø*Aä ¢bÒ)` •Ì_DVRó·Š?Jï‡J)¿J¥½úxÊeô`¸hÂsŠi`8v¦®ÆÑ"ñŲîÛ‹èV2v¨iÒ£ˆéªwZÄuÞWqÑ-&)±Y Ò ƒ¬B¢= ƒ¬c Kx3ãuÂH`H€ñ´ü‰«MÛr:üuÕP%x6Ëé@YõQ^ÙÄî·P˜šÂ?§“ÆÇV>ý€TàðýÝå.—aÜ6œÞn§r µ²nàIô?šS €Lh¡ÍÒ±ÓŠŸz¬Š Šz°ŒÖ8 c²B;’­2‘ÍTçúÐB\mÝ´¿.ª?ÂÜYíÑšÚïj– °ñ~Þé;½ŽjhÄV÷cdxe-. /­ú”‰Nz¢/Æu_æ#X(lJ`®KÇtp-(˜ž¶z(àuXKËtUW,ëm—ŽûfdÁœ‚…qn/Ä'¦|}ä%@+!ˆÂÅj“>ÁšU‘S Hn*2ãB… žïüyWV'*˜³¦lÞ”v?GÆb~h­w=fvi¿S´hùЬ;´eÚ| §AIöÓäw)X¤í^¬” ß×zõhxú`cÓ¾Ô>õž|R¡F¡<ˆÁ©Ûúçóèã™±,`6â[%MºâLP`)ƒ.ìÚ>ÊrôbWkv>Ù,7™ Ý.Ù ¨¬®÷äÙ%K?¼‹h"JJËü9³8mŠw’zð«'u¼½Xš`Ø,.¥32$<@ŒÈb|ŠL÷dVmðGI_jÌÌ«j‰;!ÈÛmJÜ®úÊɨƒ¬ÿ=Û)¤Õ‰ÉŒh—2Í$c1Œ ÊÔì%3m>q£…§—%ZÙ#;´_¸¡ø´Ê»g'vb¨¤XY6•‚…Ÿ¦/ò»ïÒ£¯Òoó»ïÓ£\hh¼µ‘Àg®0»)´ËÓ) ÒGFCâÅÓ §;šz]d¯2uÇÄ@>Ã/¶E¾hµ‰4㠪̃[ÏÑi͘B6­˜ ÒÝû£èCøUJJ¤Ôi¢n}›¨›y—ÖH¸q§6Qk,´¦1wŠ(ø¢½­|2Œ0“ æŠáʃD‰”ZÓ×0á ¦¯YÒ9;O9æ´é@ø¿‰ ¬´H™`ʸ˜”f…‚~]¦D±”†ï6b`‘¡:–S#È5ß@•ýô0†Ëcˆ9ZúÖñ¥q]ÝzÉÝõíE)|<¡=“=F¦ë}®ì1ìžSëÖ·HÈBë˜Fß"H4Iv)'Ë ShDHÖôµ9ÝÙ“ª¡<8EÙ¼o1(c6(:ý\Ì̼­yIñXÛ{wÓòÚß O8M¦“‡9p5?()‘éW£Ê$롉|Q­P‚IO—0ôö˜ª•nÞV7Bÿ¸éíò”Æe£®Ç= æãã6Ô”¨¬;_ÓbQf}?0~…1¦èð>“¬Só¤tƒçÕŽïßQÓÎä 2s=ÑñR„c$¦ÐRÂE›ó¡QG¤D§yþ ô"˜ƒøõ}vÆ5a¿ÂFr–l¤Gû&‰lùmyÖîÿúÛeQ^Øs §žÍî\h_cr˜ôU• D“ae ¯gF†aZçCzt5_çvˆàºÓ§0ú.ÇŠ÷á!ìªëó«î„ãKê•^ Ö–ûŒlÝ6çñ6Ú¯epÓr¤nÉä'ï Mœx•âû˜²Ûäñ¢GO؉‘ÝœW"âUÇbƒ ³¶k×ïÄ)P¨@^ð윶Ë)4dÞqúñv E—5îà»·éÑis;mQN¡Ñ^µ~ƒù“KµaµVI2ÚLäâè<[„‹:ê£U}2î”2Óû¾–þŠÛŒîdw À Û›ÏÅ#jþZVrÇÂIC÷9pÌz\ÀL°>#Š!u°{f‡´&¿ £‚áÞ ÒŸbql'Mpº›vS ÔÍ^ 5ÞYÖÉÚB IÞû&Á„ûQ²Hí›ng\ y yw?Ý®1÷ò‡jþºgäfN×Bw4lEïfÎ(ü¦õÊÆÈxoÜ®³ÅéÐí×›ÞåJi—ÇÙ™¦Ý½În¶[øÚVùpsGL(!‹{`ÖY‘F{gN‡e[N{…¼b¤@²HŠô¶K´R|›{P. uR:åÆr^z7_ngøÆ…CÕÆË©3y ŸåðM¶²ý0ñ@oÝç0­xf»jïŠÿ->ûêÌÛ¢Q>ÔVûJ§•0½ÓPÅPÐ…)„ꤠ›üì.ÿZ‚ø¶Ôr±ˆùDË™ô¨ª—ÓIy©Ö]GãEïa·$Áý:XäÔm¹+1ã=ù¶Ð Œ°æpÏ‚ 2AD†TÒdcõ×¼|§dI ŒÎà¡é´T/òò}—ŸõÞþŸ}“ýœß–0Ïä_Ï;5ÿÜ´o¿ÊÏNò¯?BO^JIBI%*3ìûôãõÄùWÞÝLß}´w¢Œ£ñMwÃ1°Â+ÙqNâRòìÅòÒ´¿b‚zÓˆ©|+Í^ÉØ{ÈϨêØH;E¬×™ú6:7÷¶]||[¦ ]||û¼SsÙ.eƒå` ]ûøèi˜He¬ì/¾åš‰þ’å·]—R~Ûu*å·]·R~»Ã±”!ûùÿ¯c\ÇiœÑ7ÍgÎmV¹ñõ5+Õxûšoùû¬&Ä Sád¾Å”˜£ÃÝÒØZ÷èõCbŒÓñ:¶†×¤xçhÐ`“ÝìFºøK)@>«nœ‘†7[?$X|â n>•»è¨‘ŽO•Ò}¬ÓTÏZ½Ž3Kˆçn_°†j¥þeÉ #0Œ~Wy$ðMt•ö]d*f²?1²í4Ÿ5Rhqw5“wðè+±»æt‹CÿžìºY©DÈ'™[a¿EJ 4\5Ç!ǯÖ?­Kýl…¥–C“Î0›V3^µÑ$Aì`³ß©bfˆ ‡ §ç~H¿Žë¥^5—},©$Ë YJ+ÂÞg‚ðäéO› ð|x6‘ö>Ã&¼ø²¦½1[yž‡ÔÄx òêp¹ïvR©qªu…³VxžQ#a>½&e– °†<5•SÒ.”ÛI´Lõ´t¥Ÿ>IZX–/Ñd±·—ž£ ѽz"fË×Fì2_ž”ÈÓ/¥@sXh96tnB»hÕ¿ c¹c_:<"‹€[AÈ6l ¢rÙBà©þ¹LM¨V×µ/sÿ†¶(ÃS3.ÝîÅýÍÏZ.»¥f”=;•½NÒlj`ˆ׬Ä]ç ƒRØޥxNïÊ‘2â,nî~ EK \Ä´;³lbD¿{@pË…4‚ÙÙ;$jè ¾®EpÿG"Kà¬uÈêŒfí¼ïþÿ5R,wÇí}dS}‘»µÔÀ­ÂkDˆ •£a帙}Dµ[>*Ž¥Ëªhm#Ýv¼ùÄÓœ]®.¸kšÃª(/n¯öÃÞ™«~?ïšÉÀ_¿ä:¨q“žÝÓnì4Aœ‰ÍáÄ;*TqÉ÷ï¬ãÖ§;*È=QuzËíìŽñ‰ù š¢ö“ºÉfÝÊ/šÛà/'¢Ÿí¿_µÿî¹aG_˜ DÔ05èI ¿¸ÌϾˆ_€Bûm~øm.Xìãâ û!¿-¹Î=;úOÍ•ýszô,ý(f÷¦G*ýø¹é<úCúñ¢x¦²½þ}.ÿÛb.ÝošøGʵ ÙˆÏ3"Ö<=ûrœLí÷)ÏÅL[›/Z»ׯÇ@'Ímâ2;úôÓOÄL ™ø-aé5]¨$—\¼QR·Ê³¶¾ý"úmŒX·‰IµÓ§Œê¸Óð‡)(—²@Êf¼*ñQß§¦È”éõ僫f4ñê}3Xkc×*÷lfZ_LßÝMúUF9u³0ή¶ãºPñõiîã‰oß’Qäm}]æ"ì¼ ¬˜uÇ¥ ™P|†rЛÐPÞú2à/Ó°Õ–pËx xp#€ñ¬ÙeQâ>=Ì º>ú_Ü^.+endstream endobj 1259 0 obj 5592 endobj 1263 0 obj <> stream xœí]msܶîä£~ÅM?:÷ç“§ŽÛ8qMû¡îdÉr4‘uŠl9ãß]– x<^XYšédq@`¹XIe¹ÞOéîwE ¼:.êY»~/^¤{ÿŒE*^üDt;òäÖ¯ŸÆ›/ÓÍGíMÍÄúy¼›»õ%ôÕùF љ»§±èa´¢XóXöeg&':Û7 ÖÌ-yªe¨°î×±ìMªö1 C„Hí+ âøPÓèÕ«®ëI©Bƒ#.Ú&oÒØ|He¯‹^àÝ\VÖûØI)g¢úxû&ݾ(‡WG•JWWéî­lÄÌ6ÍRNbÑ&^œ’gµ65É0ÞçE7 è}ÿ"wŠ>Å‹«¢/aT÷®zå^¦¢By¼w‹Žú•Úvˆd­¥ëÆî¾#½H8¿Ì¶p¶q0ò\ŽrEbP,“€¾šAãìJþ2^¼: WÜËÖsMø?£4à°æÿ„W·Ö¹B0á‘j„öÆwÒy/ÑŸ Ѷþ j&±óZscd£¬^ÿ~xÄ㽑{k\ä'_@eçÀ(D8Ýhih)iF„]'>dYDßË| Æ:ÆCŸv#“Gœ´—J=4 ·L§‡aak3É,tÓ2æ _ÿÒÊu663€–hIæ°TX˜NSa½Vxß‚÷>’ð·ÑŠñ—µûh£`›Øm¸ßÙú´I…äI›]¡LãTDîI–™ÛàjÞx˜ç}óxÛÀJ ‹IzÒ‹C¨(9SàQc{ÕÊ­>o! å Ñ( *šÀˆÉ Ò÷‡žÇŒ¥zd=/#põú T)j%¯S|¨h<¢BéeWªD×¥`ñ²KÞ0úÔ hGÌs®éÃZÌY.ÒŒ+*\wPUŽJx+Ä9"°0@üÉG´ ÷ÖÓš¤c7µg…J(,X 8X œ0Þ9.¢Þâ—˜]R¨ðÁe¼®ú„ª'ÈÞ&7ºaÎÖ=#q4WY?âo7¹”¬¤YpJÚ…ð6º§MO70dJ‡ÁÑðXO]ÿ#²´«¹w|„èOk EVñ¤ººgx•]#Ëôñ|°§ÂN^æºÑàšÞ?Cµ!ü…›i XcS¤FÞRµˆWƯ v±ªðç]³©‰;±ÆkO‘[„Â)N„H¬ …i¥–6ýlvÓŒi³÷»L/ì0ÈîO­ÎÝF›Ã»IOé`ùÂ1‹¼Jž²œøíF·{cYŽ«O*-r”Ÿ¯6çÒT$ßûˆäí¾Õ‚T´‡ý%èˆ3‹M±·óMK_¬„B ˜=ücZ5Éu9¶j#èAf"´Š ,T8ï…*±FÒÂäÐ!2Ú6‚ËNP£ßNà¦TÚ6,î*Ÿ%}*O¦#¢Î¹GtÒÖÃ.î4ªáÁÉ>E¡9ŒmÞv ¦·„}iua .K:x >«êi‰ª›žü~Õn5‚‡5ª¾Æ!ô Jh“¤Û +쩯¹oa=—C75ÙpS+ìé×Ç?ü¶ÂÃ.!L*x[qè :mm%ê ¼ÇÏ<{¾úp}óæàÁ¿VüàÁ7ø¿Ç/¾‚?Ïž¬þtðõ³ÊRQ0E=ó(@[a0r˜!h,?hUÕÀV…›xCˆ¸[Wðæ…6l1ütÚ#/_çÁüPÅh˜K¬Ñ°Ì?KV=R‰Q{†@1°güßBÀâ,EÏ *çÏiÚôܤ+¨l›±)ÁPÔ>‡›aÿ.$+$xÿ8tµ÷3çÀȈm‰ó;ôÂ.\w YÎp²t¥I±d‹©<¶è@Fô}œ‚_âÂHúkö¼ßÇ4ˆôƒû"a’H輤öê³/4““bþŒY96w‚Õ¬¬ž9»ö²Ä=Ì8Í®@^Lå }ó..'†¾Â\Mz[¸7U SKs‚¸fˆÏ#MBw¾ÉÇ¡+µÁaüãЕšÏtæ{CW`W äæ+±+rÓx¹YÝGu·š—‘A@–ᚯÎbÀz÷Ñ:ßÌãhÅ-Ò"Á®n™o­B;5×íb*OÀ•èûcr¯—58Àá<´vÿ;L†Mbk¾MƱÅ3½j[`¯™.uol1OÅ–ß[‹©<-¢ï7&Ç9½J._ ¦\ãawM^o]nw–Cĵï[xÊÏç.ƒ»¶mÖHé†[Ž–´q Ù×W³«ýTNxèCRi×™2„GgŠòN/²oAssûÎØ\§—òe¨ß陲œÊÛg Õ÷ÿ3…,DõWòk bJU¨93eŸ)ΈE6†Êé¹i—½gеl Åìðz9•'f Ñ7oëÉçÞÑ’â5œÌ¯Ï;‡’!öî§2ö°ô8b­t‹ìAÐÜäÞÞˆ5z®rW¸.¦ï\£²KX%¨"‰¹· ²{¤ÅÝÇâ|3Žc:·ÈnÍÍÏíE-ðuç(Õ®p\Lå 8}ó"KN>T¢ }\â|óÃPy¾ÈÆP)goË%ªÐýQîúšb9•'`HôÍŽ±Àìzð€t<‹© Ã[w !ÍÝÏêîaêqÈJ3[V²_RÞdñ|–Ú®y²åTž€,Ñwd øPÃ{("ûÿ‘ÓÅ))0Ýmkî<¦çÅ8¦…š-«Ži¡Ø-åç0f‹¶»bz1•'0Mô%‰„Ðÿ•ŽÉ%Ø{àrç›už x™çö¶’bLâ¨ÂÓí ÏÅTž€'Ñ7c2_}ƒW"Jî>ôæ›lzÒûÙ²ªÐAò–²LÒã‚6½]ß\,§òvèQ}3àH>©ÿùQÿ”wù¬›îöó÷à¬ÁöÇ©³³eÕqꌿ¥”ÄïÈJ˜ÊâUÛ0]Lã ˜fuékØïÈõè$¶þ€o¾ÕÆÁgÕlYuðYµÐñÐið“NˆÖзk*~9•'ÐGôÍN2äù)á­ÿ*Ö½óxœoÇq<1;i_ǣ▶3RgB†w͵/§ò‰¾Ôa‚ku>U˜qHjŠø=%¿û8oßqœê…iKuk‡´¥ªÒ–³“ðË©-¿KÈ›o±qäÉ…NUKyk§ª¥¨ª–³“˜Ë©<Ãj¼$gëy«(5ä­L]©I†@˜&Ú"¬xÄ5Sq]¤\”¾,“é&"³ ™nâÁ=ۉ߂ªž2”„è¼JXDØGÉ)’ú ¯ø¤3&a@ùý>î¹GiÕ’~n'%íØ­r¯G®ÚÑ™øqØNÕ*cS$¢² &YåLf–ô:hÚR%Ʋ)béÜ&ûîʇ]mGì$qÄmÒÕeâe;KÐ8Oeo;êêàâíL]]Ò6÷(ßTКià2…\ÉžÝo›™Ì¯*m ß6vé“@Ò,&©`íkùíås1—ÚÇסãÝ“JÛÇv¼›”ú‰è™îì‚EÛ [i.)pïx|˜›Òq)ˆÒð)’AK?Í ›È~EŸ_@Tãt|Kï}Ÿî¦£¯þû!,ʘ!á?ŒO`%Ë̆†¥YÐRØáÌa^ çøwÚš†Q•9Nb* &D¾Ñ):%™â­[“˜À…!‡,¸YüP;| ¾€X”¸Ò‹Ú'ФŸT¥@„§²í®:"¼ž[’ë¾Kl娑8”¸÷M’´]fÕÚÛøø2áã£_$Gjf؇K^|“IZµlêj$v&²v ®Qô€¨UrA®Š•;žó™4©RzKÇtËãÚRFküîϜѽy‡K/.Ÿ2Û$a•'³é¬ZJ'cm6÷w-G/&a`MóW¿k?Çqœ°Xæço“q8]9ÎU:ŸYFW}’Ôëb•Z8¾‚}”諃~µÂ71ƒn~$>ËÞ!‹Ëîn‚Š!ͬ¨¯çCÐd{\„â”Z†;—bÕ¦³‹’tÓLˆØÉòiW5µ!™×ƒ¾ÂK0Ú#m'ÕòE•j¹˜Â¨Œ,×¢x>hž?héLÃ{øÎ‰âåÈuÙFÉÄ è‚#Ž¶ÊØGŸØVÍnþH1†ï»Òo¬ ¦|¤ä¡õi¯€D½g‡,%lï)nòü'¶J„) /œÊ–Eº Ñ-èv–)a†|®Ö•#«Ï–j;ýKé~Ÿñ¸Ëk¨F*ò°zwûê.•!aÝ%- >UaÖ‚XDä¢L»,+§.˰m¶ŽkÛ¥ ¼ií¦a &¢ÂüçTš[¸xÚûã³Nr{"ê=v…K¥ ½QÑ'?Xå‘ .Î)ú&©!2oªÖKÅŽæ¹#áSK)êŸeֵоdrŽ{|¤8?Œë æx’¬²  Sæö‡ƒÿÖܳÁendstream endobj 1264 0 obj 4337 endobj 1268 0 obj <> stream xœí[[o\·.ú¨—þ…}Ü-¼Ç¼_ŠÀiœÖE$©€¢ˆƒ@ÒJ²këb]’Èï /CžÝ•­8@ŽxÎ ?~3ä¾[°/þÿž\<ýV¶8¿=`‹¿Á¿óƒw<4YÄ?'‹ÏC3±ðƒ7¨ÅáÙÁ8_8»°œ /¾[þiµÖƒóL«ïÿ½4´&½Øàtìè 3Qõþb¥'µVËÓðÝ–wáK9Ëðë¤Sû:]åÚËÕÚH18#–_6 ±úm.k'ÁÚ›\v›¾Æ5 Ã{šH 2^ Ì úÏŠ3;X.A(TŒó^.ïWk!Õ` ¬cÍc47Ë£ò R e 3ß—^·+9híêf-´à{¹)õ§e€»Q´<•JhpÒmð:|*áMÑÙ J¨ôò+>xÉ™må–ý nVk5í™aa ~.µ•Ì¢a@p78PnXaÆ.¯Gá\w„5ÒE Ãdgaõ\¾O"*Têct‡<Ù«¼š›Ò‹ÌP$xU$(*x[FÚ”©ºã•Aï°)ø†´Ë œÕ md²"4è„€–èLB‰A8pŸÃ xËqn‡&†*mÑÚ°A¤³~ùs®&Ú!+:-¥:RªOë0¼ž)u:+ö»**!VE©$´ôAç( ´Á}éö¶r‘ÐÖ˜åùÄØ8ñåXjXUJÆ=*¥S×ÃRô7i)-m7’cØVˆA p‘Wfà-8•å" Ðß‹1¿<\­å ¼S†º qÍÑ$hÖu´ëšsÐ2ã£y«Öãþ°ŽnË+Mzç¢ÊȶŽ~̪½ŽF…¥§èø B| ©Ó õØÝPÀH.eỖJ½´ÝR^JÙŠ»;)R½Ö6iu¤¬ñ›q³X 8@£Ú~¤#@{#›”£î‘²6L ÊÒô)ŧ9 ŠÏÍãÞü¤ˆš‘¾Ú9WÙÿˆ«‘C “l½ó ÿi¸ÈH£<ö¾Ôy1ŠNpÒ×Õ±Ô8»÷ËŸVk6XÆœ¡P:œ£s*œ¹/s!Hr>LÐxÔq8 ´´HÄ=Ó„Òàå‚jå¨Ý×­ZÊge€ˆšOa§1Ð]`ˆ¸Ê6¸“Únº0IŒ±?¨ zܾ@N©r°f ¦Óo=˜À„}aÈ'i@Ö𦌻 Ü„±ƒÂ# ¹÷Œm ‘-?ÏÐöcƤ‘/ v­ @°qŸ〴(µã¸¡˜ßr0ˆ±ó‹Rn«ÿÆR÷;œ”Ö~ØqàRµ`‡’J?C57½ýO€›BÐÐlÛJ˜=•C Œ†1 0?0Î)„–úóæ«eè›h@î>@FŒN”ððûêPPaÈ꯺èRPàý(9·Ó˜ Q?ÐÎÔ/z…›·ìÊšQ²ª¨˜õr¢÷HíÇ•¹žª>þwG% Â~%©ù%tlH°ô}n p°ëš‹Ñ²‰ÌßW‚up£G' 4ƒ³•"ϸ¢ñ¶5}B†;É™¦¤´Ð#²‡ÊP…Ðî ¬ êÚ:<å?Õÿ•Ëîsë\V¾n:ãÝ6_XÛfRʼP»úkƒtãqn墹ÀF×¥ðí¿ûÙÆr*AÓ“Cç:»&™kŒeüˆ,dä.Bïd‡û£oŸh e¶OïÊÎêoýþÖîâ;KXI¸SBzTŒøÏ™ñC#)xB·¬Z@´í5î£@·4Yk0l„ ƒ;«¹ÇÎ “4pŽ«n)„¯Þëp||¥Åè¡Î*ƒØ <Â9‚”‚ý þ댆¤N ¦F·ÄOͼ®z‰A"°Ýà‡òÊÑ.—°ND(Ô]œr˜XØw)‘zÓD½…Þ•äªñéùáÁ7ïrÌö‚¥Ý‹@Ua4ø‚YâÏ_<}ñÕâîæþôàé¿üàéßñŸýWøóâ‹Åž¿X|3›;Þ‚€zLdÉϲ”¦¨[¡‰ 3•yº[ù*Ó—K5ñéiºuÜõãù¯ýCÂíã2i[vU“ã a)Ÿ‰ðÈç4ðÅÏ7%°-hV‘Õ`p³!t "ŽpÑ÷ez"¾ CºH›*'s]Rh À-m7Å:ÏácTÙOMŸŒÀ„mLxþ„3•‚`ô}_½9X!錊ߡþzpÑBØl.äœ ñ?"`Êzö22sQíšMÁölJXH€*oKîÝâ9Ié[Ø}3)ý¢ÄIúÂ#™„àH¨&›:M\zˆ%cÁü°p"¨ìI€Óé nöð%6†ó҇ܔxN@èœ 0¥’—{¥Û‚LÖ5„Ô6Øf’í÷õÍÍ4Ý_xt'B#É P&,Ï,¿ÂƒSJ¦\?êoðë^Ó´š=“Pãʧ±w;mŸzd%U9Å:DM¨yÆÜ™G P¸E–0¹ÁîEªË^õ&YÛìpJÁçs€IA؉È$è8 ^ç~*i„'Ø Z;Óp/i,ìÞÉcnIɽJžlgÂÀ \ƒ¼²2Ý+êˆÁ“µFô†qžÕe•ãví–cGz8áÙཉìî»gj?ØÖß½8™¬*AF‚o”mßg09s³Ã¦mŸŽJ[º„­\·ÞÙ„Ni®æÈÃ)¿3!{ë#½>ÌŸY1Bè¢Ñå”UãÃÓk<©ý`µOû¼NA/³VT¡„8à•ÐÂU‹œs]|Üš÷ÆŽgP5%=ö¼ÅØÂzwŽjÐIüôB®*à ±–p2]ß}¹@Τ ƒy‘‘„ |^€æWRõ]ÚO]J/03àðσÃ?7|V–wÒi…œ–çc–Ë # qWÀ;¯¸º©#âFs©jz,cjÒŸ'(½¦6"Éìrˆ5X÷¶uç3ÏoÖ~³­ž™úZ0ˆ—A/—½Ìo™‹ŒZ6%¸ÍdO[¼ìá/LJ‚9¥Ev¯˜–÷rG°†®ºøZ„> ü¾eI€]èÔÍ‹O§¨i8"š5 Ÿzy™?ùÝo?Uéß•ý%îÌzâÛ ñÒ›~¶B‡ Ÿy0Î'¶v2ˆµqZøx–ëžäŽQ6ày®FT½#šK•\ÒIþz“ÓÐeýǹÇûÎJ¢ù¦3Þ/¹ö8—µ£ŒŠ¯Ç³–ˆüK*:NíÖÆÙm€$œ^ÉèCÖÇyj9F”¨9«©E£º|•u”Gˆ÷[“÷Ÿ5:Àµ­âû”bÜâ›ítU¦¾RÑèh xÇYž¥¢ä“õÕ®qÙ‘ä§Ž¡:r¶ï5±–Ê>Ê©$ñµ²¯én®ÄÚ_:{í¦Qµñ>>Jû\t4UÎmÝÜZ’¼]XûùtÐÛâ7yÞ´]±¶#ÐM©=Mµÿ%Zϵ'SßG#:ŒhÖI{6¸è@fÏ…“ãzâ¸eC·/tÛ׸S•¾Ï"@ YË7Ù!“VÛ¯¾ö*VzŸk Ë †.')€¿î ¸î8äëf•!ò¶úž¬f6?m!úÁD ¡ƒ‰9êxóŒï-;!¨Ñ”Q“‘Ú £t0R° •;©mÿ©qac'½þ“'8mÿÄ–´üÀ(¼Ÿúž ¬b¯îû× ‹DÒ±ë.ó«XX «,w“žRNÂ.ßõ^w½T½RìëlŽ}É ßýŸ “(öno>Àä•»fôl/Ÿ3hÒƒxæî ÂS†Og…·ŸÑÿš—O ªÕ"î’ WTÐÙm žè3Zã¥âÌ+B¸ÔÉ·íQ;!æ]›m ¸È³Ë~k™š¹J¥q=5a!®÷&¾SÃn’©&1|Žë¯›„N›ˆË!ï>Áþó‰õ´i4r0yb|ÉÁ´šã-¯”|à\âæ–°Ï5Ÿ‹¦[pàN…{)pÁaÇKépæN¨„cýܘ?Óý‘Jf¦é½ÚNåexz[ …¬˜–á²üÀ”Ú×Oß5·…ûÄða2«gBÿ»nðLV[òeUhk §YΘ2:p45GêãÍ•»nî6E~Zßtc`´Ú›É:àǧúΘݎNt5£âàoä½(|½4²8N“›r–äR<-6làrÝV¾ð6á“Wy½:9„zæI,YxýÌut®êG"äŒ"ª›» è$þÇlÿh®p¹g½­ÖôsYÐ¥Îh¥¶'“àVRÎ37ýKƒ©ÂU=‹Ù³XýÀ wºóôÖè’SÉ52 +¢áX_ã.Ü%Çœ¸Ð>¿€Ê¹ÅüÌp§PAOºÒŸÙ‹ÛA¨WBŒåc÷ÿ#‹ÄsµÌÕº B„.˜1êÎCþOíŒ÷Mµ‰›:ôºíŒwR-0f*j79ˆ‡'ZŠbYîÁ&qåã%Z âO’Pi“"uÃ뉔èþ¸ö"-+'&Ê ÷%ŽZ÷E Y×{…ÁpBåŸp= çKèE‚} ç€l0óPÆ'˜Ôx_õØGa|øÄÄGNˆüB–ñÅHîÿ¾ ÷QøOÜ?Ý1°e"úê“1Ý5õßvLhICñz—?ñžˆ{^Ÿ*ã7XQßý>Ç-ósçÁù^l‘{R¨sl1ÍtŽÅü«€ðTÌ6tQ ‰4M¾Íjž.v~¸°]LÝŸ.j?,ªß‚}ºHÜ1üÜÃü¯ùÕÄ„â±iv.Ü&g†Çç^LnÕ/¦“~CŽç4#Zúw’÷0’'v2½òûu˜ÞGܦ}j’Çv©øwzWÑ;¿\3 8 äÅ<¼QDraNsð?æÇîLendstream endobj 1269 0 obj 3726 endobj 1274 0 obj <> stream xœí]m¹qüq¿ä/ÌÇ™@Ó×|o¹øÎQà$v, |qÚY­t^íî­vÏ‘q?>Ul¾ÙdO÷hVÃÀi<ÓM²Èª§ª¹?múŽmzüŸÿ÷òÃÅWÿÉu¿¹þxÿ¹øi#•vlö²6ÆØn€xϺ~ÀÇ¿yuñÕ«Û<><]]|õ_vñÕ¿à¾ùÝ?Ã?¯~½ù»‹o_m~ Áë®Æ{hÇtÚaVw|M;ýæ7?]°qHþŸË›o^ã¸ÜØÎj®åæõÛ‹Q"¶$ôÃ:_~¸øãö?v ‰åªçÛûƒOvàÛGü’+«íöý®‡6$·z{·Û+w0ÛÛðä¿þ׋o__LâBœ(ÑJi¸ì3q~½Û÷éûA³íÕnÏ:­…Û;Ñ)5p¾½L_>Œµ¼”Jq6΂`½ô³ ™ô÷q,cjœ|´5 êôihhZ?jÊ9øïI*k˜étTÚ^Û•ÊßXb¥³%î»A%ÕvèùqCJIXBü$¶ý!~w¿ûón¯ÙÐéaû&~÷É}‚>Èš 2?Œ+†bAvå­‹ñµ‚Šö1ô! UV÷²Slû‹ÿ´Fm¥ïäùå1¼“ùRâ@?Fyý²ùŸqô{°¤®—mgóúo¿‰‹ú‰>XÓJ ë¼Ñƒ~v)­é\GQƤ„OQÆ›øÝUeä…%E´<›)jµÐ’®ÎCB¸.>:°½qÊÍл÷éÛðí  CŸ}ðN£Bcˆ¬oÿ¼ÓÓ‚iŠÌìf×ú-éŒôð.: « Å9LÔ%üþ GÈ;ËFä×½6¸ŸâƒdÈHQl ¥ÔöUzàwب$­CjöPk¶ôBn,ɽ@ùa©M[ºJ˜u3az ‰?ºMo£2+g3ßåæÝzݲ¡€Fu½…–P[aNÁAsœ1NµºWaÕ% ‹âº%Œ“ODR2\¾u‚ùÕs_~Š.øqDX ³›Vò&ÓÚ0åÝno¸êp"_ïö¢ãàÄ+’ëŠÌ¨µ€¡ `´|T¤³õ#j}û%oµTU Ö0A[­›QAh@X˜NÕ†tŠñðµ tœúÌyÝ ³&˜@E ~*a©yêgÔHh:ªã©#t:a þÈ5äó!F C'!Ä›^º£- 6ÂuCÙ µÔ–D Nd°/ö~™¡]©ëgA;°ûŽÙïÆÙÖTÚ3àN·€¾îF=”8 Ša¶e‰}¼£–ÀúN ÊÁ õ`éøˆŸ-µrìhÏŽz6öGôè:ur]×#×s¯ÉϤc2ÜÂZ„-R昴‡˜§j X 1øä_r%1 û¹4'; &A!¹Ú~·cbFéB·%ë”0k¼¢T-3»9Äy„#¤è˜âtïÆµå â\6­™¤z\]eªóˆ•ïAR5¬†éç÷^5™ E¦ÜU¡1Wl£;! ùry¥µ\¦!OÔ;0J&ò63A8 œ0ê.³¾Û•±& RR̼©úç«R\lÍF£ š™é@ߨ-‘üª ÎrÄ 3Ë èÃZ–Vö¾tÎn /«xð~AVo$óöJÄ'oÒ“ŸvJ‚ A– ºTÊ 6Ìe\à;)ìFƒçÐ’rÆøìËÏ0+<_>¾ ß}ò‰¤ê%®ôÅÖrz«3IÕcöG¥ŠÂ<…7Qª+2ðù àÔè±Á¦ wlæAë1ÙÍô»î}>Ö8Çílr³q’…åç¡gD€Lù#"CÔ;:ÎöœBÆ,óꑦ6bb{,×dv Hzϸj˜ $gŠñd*RTXÏ33^Ýu +×0â£[èõÀsº¿1î{fYg¤¡Ï>U¥, þ‰ƒÀßoÓ{×tñÇÂ‰Èæµô6Ó§šK NÓ€ÓÐË™ªA$É€ƒÇ~0'.ƒŸC˜l³eI"‘>ªäS¿ßá jð«ºðå{ÃÞŠ\×ùÞk5ršT1£FìMË`Ö¢lžÜ& Šñ˜ÌÒ¯ÜVQXbQ…P`]år!i­!î{&‘OâPŒœæýn,Õa…É( º|*õ‡/d5î AÞ@’¢¡z¢ªNOTëR½«J<‰ ŠÐûô¶’È»†s[!þ¾kUaZƒ!ŸÀöZSé‹ÿPc޾{?ÝÅ_o=7ï¸ðóMü9 žJ<=÷!±xu1¡~(žÄ·S^}ï»%ÿ…œ€FXL¨’ë½sž†“ˆš´_|S‘êzZ/œÊŠñ±‡âU:Ò —¼Š/ÿX|g ©»¦™jij£ZNèKèµãþ&㈤×Í”†+õÅôÚñ5½®ÎpÊrJÆîØ>±¸™I»©WºTCœ:“ï‘Hv{m—ìÍH¡:žmÑl½|1‹Ý$ä1w6ËÛü—GI2‹EÍÙ¤,"]d¯²—f"Ô¥THVIHÈåò=Lj$îb.|¿H0=àn móÅò傾LÅÊüÇ ­È°e„øj;¢â0aYèv;¸%+ëÇV>åîbeļjWU@['‘W>pÐøã­,£Ìñö`|]/Êw¬tÚuúª:ª¤î3™3J,oê{—oçü°èm§{>'K¨5ô²äéRýÛŠˆÍâcGÚŒþ¿«Ú&É©ó rÖ…ÜÑŒ*E+e.…ÍTé(?%°4ƒ´}µg¦e·¨ö?NL¹îÿÛúoDÖG³ò<¤ËRü²a!DJ]‹’=òñ“O {ÓÌ„Ÿ-¶nêY÷!5ÛHîòÍõ1DÛ߇IU3=™r¥ùýÑ1*S§GeˆI¹úÜc=bÂ~Rô&*«ÃÀ;¥*IQ ¼Ÿ&Y‚«ùÙ!-¢á³ 9³CJEÌ m¶âºq<è'J:Ú°`¢Éu„c0U×@´ýºf: 3‡Âå¢2ó£øáô0ÓUÞYœú–ÎKmïgMôiy5QÁ£ÑçP¾w†MP€ºTRSŒI•AÇkw{—:­–j,0¤ïGµðĈէQ¿ðûlBmgëCüâÎW©5 ©OÛÝКÇ,Ö)B¿&ç+q ZÐ:ÒÑ@…ÚnWÀœjÕ³ ŽÏvsZ§;³ê%‹ûÏlûOÄ-.‘FtÜm”Cþà–>?Oy‡z±B%þ´´rmÍéúI'Á(© ϰ3 ‰sÖEs[ÒígiYÔù…ý¨§šá“8×(Ú–'XFJ–5ú­ŸÕº®™ãX»g vòæ¢3‚bokG5oxGíû­D~×±ÑMBÛ%õ«ø¨nUÐ,Á§¬Ä™XÅX;'@óÍdŒ»ÔJ¶OòÎóS$0ߨΟS… …+ò“~[׳:òç°u‹Gϳ^VÅôëcËzL/Ͱ>9¨V=Jc†ç>ý1=F"£R1~/¯àw‰L?z«FoGõÒöÙ@Èì ƒˆñH’Çðƒšo¿.¶:0#IRî+û)¯Iûñ×—s‰K^Úy¾•œI\è;ü<¹–¢¼Å'ÃÎXŠvì Ä1 "U>/W= ¾ò,¢s´Ã¤tÀ•½ÙE¼ž¿c£ÞÀç^’QÜçàNeˆ)i¦¿Ì}c…FÕ_¡@/¶¨•’®:çí‹YYV"Q`ŸNðƒÊ ÂReJ½ÆwÉì ÕýòuW´øBZÂ_՞׫¯ªj]°°ÄÂEkfMBýÇm­­œH™ÏÑÒØVÌ‚ïU){‡@_O<ü}ôðûÜéÓ‡>æ‘ |x^›÷þÐ5€ÁÊó³2{ù¹ÏB_Ï~+Øx|–Ju–ã³$ ~öñYGÍä-–»D'Ÿ•=ú[høÙgy¼ò(“aåùYuoYÍã³akŸulŸÔÅFB»fK6ÂÆ;`žëø¬¬»ëß é‘ŸZ¸P§ÞE†úžääžÎá\×Ù×ëÃ¥B6 &óΟÒ£D„ Mäwè)‚Ï=[Tg@Öœé®Æ’Gi w=”nCù'¯Ÿ\rõ¨[#+ÛE€S’‡Ü¿@†]ž©jS!õk.ÒÂTk2ê—=¦;ȺÕ÷‰M%KØ"5©Ðu?N¸¹x±WGcØl—sœBÝx´ž2…jÕêÂ`àE ƒÐ?dŠ€QÄ»ÌE» 7ýT É[^;¢"„) =ÜO: 7Ù¸:Aá n˜ž†<§…@ž:XéÔ%üüÆtÔð1 eRD?pýÀÏÅ)¡ñªi…ÝŸâwo+µ{7Åù|DãN+èó÷ßSÃÉâ^W^LùS¥ÓCº!Õ^W*ÓØ—ñ×þÔ—¤ 0µ}ÝìylÐ÷œJkÊFèaÉXèz_ô1Öx°¸u“¦/–u’ê‹+_Aiie­F²dr?ÿ’YßW×®PHÒµão*qêáÍnÀŒMEiÀá~Ä?èø2üúÂ×&H^ÌQØè,'*ÝbQ^ª‘ÿ]½¯É˜Â±x…,sÊ5*íý-ÿ®]j¥¼t"w&¬Q’­ …¸,æ;?»W»ºûëbÔY}¬ëÑ«PZÔ´Ðew ®U­˜ÀK"ÊÜÝEv©Ë¤/ýqÄü"“åIß^c&ÇÅßà¥/-ÓùÆÇáÿð2ûç#”Þ@ìçˆ+°ØÊ©qšs¸Š‘ß_ü/׸PÒendstream endobj 1275 0 obj 5771 endobj 1279 0 obj <> stream xœÍ][7vò8¿¢÷)Ó¦\¼“Ab Ž]›¬ÈÃ:XH3£‘ if$ÍØ« ?Ã?8çEòEVu·ºaO»ºšÅ˹|çZ7ãÀ6#þ3ý½üpöÍp=nn>Ÿ›ßÿ7gϘ¿e3ý¹ü°ùîܦ´Ü¸Ái_¼>«ÂmÆø íưqá»g>¿ÜÊÁ iÙùÿ¿:L×nÓ§‡í…f~}þéÚeúÅ·éÚ3¸o”ƒtüüsºxn¬—‚ß^¥kŸaÁaæ|zž1d¼o§Kÿýâ_Ï.¤FÆ7Ü zóâ Öôà¿VJž¿I?ù”®]§OyÀ7i yZïçÓÂçá10º¿,n.gƒàmù §Í}»á>¥¸_·jPÜž¿Ü^°AkÅ4,®òÁŽ^}ŸFF 7ÄÁ?½½†€™_¨ÁZç,vº&¼@ÆJs¾NðKÚ€ë&ALßâ3~xqöÓÙÇ„·>J1H‹c»a´HÁß=?ûæù¿m>=^Ÿ}ó_vöÍð?ßýø/ðçù÷›¿9ûáùæ§èšfzTZÆëH5o«…KñÃuE¢º'Ì…LyÂì´ÐƒRçßÁ ~èâAX|žž RX8i®â‘1%È­ŸòÅønÔ"ž¹€3}(iÉÏcä2Â5Ü 5^Çñ†þaŽ1ŸûvËÕ0jê—-ð7Çâ©ïó ÈH·y¤|”FQüŒÜp…“…³r æ-€ÚFm¦çûïïÓTîóÅz_”mz”,6ãMþ.ÚŒ|€<`šl‹±È½d޸ɚÁA#ÿÓG൰a5ÊrB-]$Ó}»Ebâ’LùxÉô*Œ¤Çb$Ü"e ²áUóQïédñ”0寸Z H‘H\l™¡úUþD&ð‹µ› ›~ZD´Ähç·f¯¤«®Æ{?f‰ó˜?†•Üé,‡è¯®ÒÙóGH¥Ìªœ"• tï¡!»?U '(’ømÖ_!ãít9‘JÆK7cã"q?ÈÒïkvÏ;ƒv™ˆ#!ÚŠf„Œ0 |‡7H‰”2WŒVGº÷ ]ÐP œ—ðqŽw%— Ø>(~ÉÃȯgì–Áp>fè¤o#¯h*G["÷±%\qÖbI]_]–xd3ß_WýLDmƒò£4@:+GÃ2 l>Ì`/ݸÁŸûqaœ ø”Ø}½ŽåF¶èÞÀ3¤F¨àiþO“†A{¿²áÎr¤‘(#fÂÕ3Âm¼•n ] g —Æ'Xg.KúžðH}®TÈOš6²!Y©ß ÁF9í„'¬žš™níí„’úÐèҚNJ›=!]^—™l%÷ñ”Ð)WˆÁNÒú¦22¦…k$ëD8 €öÄ@Öi˜‰+§ü6Mùj²­,'FØMRaéf;êÛJ/Ž"ñÜÑ΢ž'ž#+ûÏÄ1÷3؃|FXŽh€×Yq|É*¢„ÚDE¡°;é†^ŒÜ{ÛºHÓ ~ûñ ÆÁêƒ;Ÿg–ÿ/ºA j ¼Æ™ˆqY©k¯£5k+˜¬UˆðhïJÛRh†O-ÅÙÖ{»C49 î fKv|¬Æœè°šdÀüixM"åè«Á< §ñÚ³|ísi\‡›µ…ië¼È{Š…>ŒÆí¼²EÄ+ÐŒ*#öÎË‚™àt•ãY¸á‘WHØ‚E e·ÄÌòFŠ7nœ…Èkœ‰¾ʇ4¸±Ž0Ê¢$©46_âXž“¢Ùó[á&û¾©Ó30n›Ï¿M1ª¶¬j£Ñ¼°7-MÆ'x¿9~! Ú7…0ºoAwò€·M±‚6gÜ©úh&”ÞÞdp8*o››\ÛÜžnJÁÔÒl Cí¯ÙºÀ‡Ùý‡jfüx§>#.³ìç"ÞVÈa÷°ñHh|Ü“g¼{> öí$V`O^ØQPƒ#é0:J\fi¨ÃŒ”‘ñ´‘Nׂõ ¥ªQ·J¾·ˆz`á#c5êáˆPOƒzp¯´8êß7gµ½Àº•äÓpšä#†›sÚ!رL½ø( gÄíu|[ÿmb‰J³04ïQF iU2Þ°£JöÞÖ¶[ô·‰”E˜,S†¯Íè°CRY_˜ÂµG[É™úªeT´]{™3Í'ÀT0mTÙúH*D»|O•?®1ÿ ôF9Óቬ}Œéð„àÖó‚röäņ” cׄkˆGˆ"hT“±E4˜†°¦[ovXÉä¿l‡®Iª@¼À¹¡=ï¶·Ó'€…Ë;hé®Öyoe7þ^;ƒ´¤³!ˆLì.ÊáœÁÜL‘r2¯6&œ Ž.¡§ìÚØOteŒ@·ž®F¯˜è’ÐuúÅÜó€ÃØA¨Ò>Jøjwh…× ¤Ö=¯RmZkYɬ§ãW=ü7 7çêüÅÖ‚*cb.†*cv)NcöO©iŒ™ånQxRgn3‰sc² »¢fõ”Sh“›iJi ”Œ?¸EâüTóèfŠãa Œ—1ÿîiž ÄÀÜÿµŒaUãÈgÎVÿ«l“VŽéàkµ#›ùZßZHgUp¼{‰Ï nÐd:\dbësÌȽOxŽá6LœŽa$p¼ææˆ ƒÈÛBLXöUÉÏ$ZƒÇ`£¡EÆ<œ=ðNNÕeväÍŸïÃôî1RWT=Èci> 4¸Ì‹«¯›+ﻘõÆGR1…¡_2cíÜj½ñBlT4I¼*ÄÑÐæª¶žºmUè±ÚduåÞÃ3’®_ü¹˜½äC8Àür ê‘úЃÕK®Î*«©1¼?N”Ñ-˜6Ø žƒC&§¡ß“Á«ìvzÛt&õ’BB¾ ÂÜì‘&æy†y?e?2¹¦]úX—¥Š¹.IÞšòUütJXJW§ô™Ñ»e§Ë Æ0ò¢ù€‘×5ÿ…°{çßÄY EͱØÓ›ÿ\!0ªÌÿl¿L×.Ó§w©JàUºïËJ¢8 pæ—Å•:õ²@˜#Ì¡Kû\Á̲J¡å8øÒp R<œøS,Hioj“Ñ"Š8凯”+âJ~£Q׊_ƒL™po;Ú…­ñ§¯©(¤Â<§Ò‹ïZ(æ` ÝÑÆk‹vÞ#_¦äw#ÚQ­f€L× &ðµýˆ£¢ûµÈPši ]² ²[•-=§xå§žuU/ºÌÈš®­=ˆ*kß[BFÜ6‹®Ÿu=éD\=Z6J¬ë߉$‹³öÏÏQ‘O€Æ¨àÀúØ‚ÎJM•ÛÛ¹*Õ¢c’½œ)cœLå|‹JÀœz“@*ŠÁÿ(QsƒÏ>× ’5uºvk#¬júá ÌvkdPW¼øfòq×^*ÙõfùJ vk{8ƒM¿¯ ´µ3z‘Áö$±f ²€ÒªD¦!] ¼,ô±ƒ‰æwŽÎtØ\³Í®í³¥ÝŽE+SÀt­&¦ÍãUì4¬*ñ@¦µvý!ËÒ<%QVG¨¼Í}DÙL G<鸯€ú1űÛVÆÃœ[µk„uQØL«5q¬¹fš>æv•CzöÚ¦UêÇäY_)!‡¶¨ñã»–CNjØöQKêû£–P—Àöe@FbO§“Öb"+)çE(žÝAéZÊt'å¼—»CÃã­gÒe:#"‹è·Y¶EÄbÞ1Q%# <.wILú¸ÐR1¦¿·Tf IZYÐè¥H%2‘WºtЗËýpmGQ$ä=ÊB G´ÖA®e:(fl0çv«Ã{²“L´EKõ­æ&U“@òúÿRƘ—Ed²›N"õÄ’Dõ~̽¾‚–^Ž%TÕÈ)JÁüö×ÑŠ‘¥ö-Ò.'\x£ü™s^Äò€¦0f¬3¸ ¯Ž o¥[çz pPXãÎÿºâIœÉøŠw Á¿k¨,È” ¹aç‰$\«èÖþôwd¿ªô¬:zÜ,…lêÅ|ñš{BTä]Jî\«Ç~¬w%`䟷_é‘í7TÌ>k¯\dÉÉ&Ü2t›fRd"HNÉ´+sH(7ªïeô›­ø^ŽÐ`2IµgªŸÇc³î 7¯)\-«m]¿:bZwà"g°œ¢4i©E•ËBáŽE©Š¸KŽŽ¦ÓhAò‘`‰ñ½´àéŸå«½o¡u"Xš´¸ÃtelK?ä\¡”ÇVg®´ò µð¶ˆÔêä5‰B{§]Ã)ÚU§½Ê#Yö}—ú´×…ÔšíÎuÎ3O\=…€ZqÌŽª 'òî× ;Cën›ÏK(›Ö>o‰+›¬qŸ˜L+Û¬´¿£°4šèë2)ªŠE›6ny¯ç&3O‘dù)ÌL¦®ü賜ðÑ^:zÛCGd_;xÛ4QšØiw”$¬ò(iFÞ«‚D?êC$¯íëf…Ö6ºLýªÝP æ ©"²»mªû Ñ>gÜyºOTüXL¤¾¤øðcW J7ÇöàšoÀ3Ö0zN=–Ňøƒ’¸b뜴ù|\ºÑùßá$Ý(g¦âÊßmcŠñ0ÔË”€‡üvsQÜýï~º°þ´öÕéÐy lYwþ~dÚK7Y C÷Æ pê+¢£ é´ñ+7zFÒ6õÂðbŠËTOî¢ñ]p0Å …{®Üt9ã‚tˆÙ!ý‡!6×ÅóÕ¯‹ó¢ŽVŸÜiD4”«xÝH_ͽì$÷i' 6òyRÛ¡“ÎH—PÜ»zѯ\¶Ô ’„1e?±tTh5ãLü“;E½>Å”û}3Ç”·D4 r`‚úiè=Lå|ç9¾]˜ÚR^¤Üz’Õc¾²œelΙ Lñå zD'P!óf“¹˜›%;Vviºzÿ¤n8«ú¾Uïžâ5%Å»gÙ<ÍiJôÙ†ð:ªwO1lxV’L'‹]úÞh­^n÷YÅÜך‰¸ ½’ªü ˆ®ÊÇèWp´ABðK8)éæµÌ8™ºÜÓ÷ŒºÜ]óc9¡”a¥V¸¥üÔÒr™€T=½–þ¼˜r]«ŽSžúŠ(v€ã>âi–ƒMmÀz˜/gg1†T3–#ds’B*Ÿ¶·ŽçêI*èg¦D%墷vÇȆ7[ÊmYíT§‘ž~ø::Wyw:¥,ŽÁúvÇ UO^#cnS×NÛ÷Íé¶3eÛé7ýЗ7Ù’GC­“¢q¬ òÙÒ튖bF`¤´ˆD HrÆžùGZ]k‘‘“ˆ¯pT2e†çˆ~ÑŠ·S`ê rä{ö™ ¥|†74õÄO^1)OE«o¦é¸…Õ±*ï†jLoè;»Æ\5¯œÃPúÝ¿µƒb£oU÷쪘ôÍSf,»koÅ%º$éX§jÀ–1¥Óy®ÛZÛD4Õ©û·_ÃPk‚o‹“o ˜¾q™1mœµ“*…÷)ÒŠTç©¥uûÙŒ d„D¡1 Âv,ƒp¦­‚"¡Ç·!xsá^Ÿ J'#?âiGñcLI¡çsãøÉzçTíîvjCU4•ÜúÄПÏÓ«Y1(‹äœš÷qûq'ƒ4xbƤ§ç´¼wCÎ]€2XÌO±.! š/+ëú]¼öO{¶áòa=”ú5×AÇnÎ.’¦ÓZýò_'ûë¼]veþ¼ÍÂÉwDIÏ‚íî³oˆFl³2§¦á$j<µ´u‡õïZ0U}^ ëŒ@C§œ`ŸI™%×Ͼ¶bÑuçMÌ\wþeT@‰CÛQ¤¡žåÓ)›£bªŸâIDßmBÞ{p·Mï¶¹-®Æ±€Žé†µ{²Yàün›Þ'RùEB[€ý:L¯.y];Pb˜™dãn`uT(÷)išk3ê†|ŠpÒ¤—…Ì’"ñÆX¦ÕoFK®LÄšªŒÝLÃÖªÕüFýz'Ëä©ê¾õö¤BÌTxVØÖá¤x[4Œ`ø ­ª¯^‰xœî¬+omT!FÞ(S’‹ßIÓ$CŽ` †äv""ã±)R•¤‹(Áß|•o¾žI˜ný qÝ·ÝUd,Âõ(öck»Ž+¢ò¹¢Pj)1(ËKô£åOsK:‚D OhO+ñ=H'NKÄ.‰hÉ¢ÿàxi‰\=<á°²S×s4”‹%œä%Z ž0œ>ÙÔšù= 'U9ÙË÷-‡– –ý „ ¯9{ŠƒJ{£÷ÔG%¬„+ŸCzþd¥t—ËœÛÉ]DÕÞ%ÇZk¤6P«’’=§ë^`£‡ù»­Â"årŸÎ‘_)–…þjG³v¬¡—¨1aˆp¤'Ù]–Þ©<ÐOk2„cX!7^.Ã)®Â­ 9|‚ Eöµ|±aÎýŒºH“jû³£àÞUwµÃ·Ãm¸Õo/gGí"†YȪãÖœ^ ~+˜®â$rXaf}JHZe^0ø{!4¶Ìs6wË/Ô#Ó»çæ»™_È¥=<ãd$sòt7n°þ|\„)ë)~Lù÷þqÒeNˆÁŒ!Y,ã+baeþ|ß•‰n¾â™m_"Ç Ë3•?Ó·fA·Så jÁ¢xsí…xs£n†Ž\íQc×ê¥?½è–ܲ‹Wñ­+Ï2µd|Y ‰4ô“¾˜ã)¨³áÁWTxd ¤XñŒƒ»ÝÆÃŠ^s£ˆm?½ú³îó¸èîù3ŽéØhÂ87÷ç$4å1…%Þ4TZ½VR#sÅæÜÖtëYŽHI|QŠÁ´|ßQyœÓD/KBa¾SÊt)õ½Ý…bÔ8ÎsH[·ÈÂ`¥³‘Ç×1Ó¸QSEŸo›YÐÆbçQ£¯‰I<8s˜Yšò팗«ì8,]@¾ }¬À!î™ìRjPxL‰Ü(Ì/Êq$ÒZ’§FžY5¿ñíø÷[úy[¬Óú#Oª¨šŠmIຟ¯†ÎÄÐŽ$öUm7> stream xœí[ioœ·.úqÅý²[X4ïÃòÁÛªH8VQqQÈZ]d­u8UþFûƒ;¼‡|¹«Ã2ê¢EˆáËc8$Ÿyf†ûaN ›SÿOú{p>{þ=×t~|5£óßÁ¿Ç³3šÌÓŸƒóùË=h¦´œ;â4‡¿{G3J¬ŠÍæŒq¢íÜ0J(|;Ÿý°8^Jb…´lqJÐkñ¾Ôý­”NË×ÕrG3K´ V>?ƒJ*‰´|q5ès|爂Ë%Ñ–’ %c<`6Æ™€ÿY¼}›*ÿº÷‡ãó½og{¿þaq]zß–iÖh©QZÇQÓÒð²Ó‰/]•¯'¥î¢”ÎÐZ°J¤!”*4Éei¸_êò²~Lšµ‹w¹ê¶ST]åÂåt„gI“ªÓ #Ö8“•sЭÀ‹sSêêî_yÄö®G§ºØ*ç* ʺTÒ\ò2ûãÎð9féN sn®•%JÇSüírGî”pp¬(ôQгÅùrGÇå¸VÅ#ÎpضR{±ÜQÄZçÖ¾hM@rç¯G®„Ïœƒ8Ô¨x(²Yn¯µ7uÔ«¥ J9)ƒ,Ö(üɽhÆ” ãâãR¦ÓþÄ2¸rŠ•éý@¾;7ð? w©Em/¡T„ÁTºHMý¤’Í¢$šj“;iaaCQÀPQ+Ž1…V½*¥¸˹?\Â…”Î.œN©ÈK††e&+*ß×ÁÑFÜVé¢Î5lqäµc³nñÓr‡‚Ê©Õá"sɉ’Š€jŽùâe†ƒ¥?I~·†³³·‚£rXW‡Ö¼J³Ây¢¤&ƹm{âGBKAáÊjˆ/å}–¢GSmÙøîI(®j1 _¼(²ÄµÙ28N¸¥l"Â÷x©â­VJšsid$®K]÷£ÌŸu=Z䀣ª5#ÌèŒ] ¸œïx`_ý—Y+A9ÂhÊ2SïÝ›®¼²8×}lŽ/ý˜–#ñ$0;aV·ÉŠÉ¡¥GÚ7ÅžÖöó@Ó£´ÃóI¦§³áî?‰=ò(&U0'~P#?¯=ñ xdÚiP@E=ÞÒÂýÒë"VH…éëFþúÈ3ñù2ú/jF¿ßõÖ]iãi÷ȳ‘sP›S>lƒÉóÜc1O¼™{´°F1çMõX@i9¬ËçHºí­¼î•îÃ¥_(÷©LéM¸€.6¤ ¢á@ Þ„JpSJëAé2ðE@¯:ž·EDjf\.ò°¹@ù©L”ÜË+užºø©¦% ù ¯aÆ T`«‹,ÓºÃÈ©¹ÊƒÖîµt: ƒEåÀÑ´/F³:»WpKñðÓв^&4µÀ-Éå–‡wÎtJ.°E$qØsßö¬±UÈÆ¶þMîuœ%ä÷3¢S‹Œ_#ÄØÐÔ ÎC^-bE»å ŠØÞè”qc‰¹W¸Ì7Œî½•ºÑŸƒ™¾W.)Lì!ª4@|ªºˆØ’HJ‰/#øÕ ®Ä¬‡E$Ìa7ApXêT§ÕKic®áÙÆ9ªý‘CS*£··¿xõåþ¥\ŽÉÆì³Œ X7ºJ£øáFŽ:»>(¢«"‡Ôz|‰Ó¨ŽêO¾ú‰]+‡1pìýÄP€*þk‡|?6ÐD¸~{LíÎ(ìÆ0"1 T‡ãîeâÊn¦îÔÊ5ÒÿäÔuÜvzè £¢Ô‘N#T€s JÄ{Ƚƒfà‚cX£J[ä¸Ã±˜ˆ1fà k¬ÍÐEAßSB‚Û&žÑŠΆiîé8"s4#Ô`ê°¥ ³š(£7ìÊÄ^æq¯Åð^5±ü&Gµq†3B-Ž©ÿ¢èÅ•d4Ÿp`¸ø`ùÄÔ S€©á@wÉÞ‹×ÈiƒãDÚ»Ú qÒ PLÖ~ÞRmš €"c“z@]£Æá\ ‰xP´ãMA³ M ÙÆÓ¤’èvlãi9ãqK©Ñ_Nu µÃ…µ¦¥M:'6ÄW¦ñ“„Ñy®‡ÆZP€°C)Æ—°ŽHÂŒ!Lð1ÑiF Bµî‘&78ÖŽÛV P,Äwžýû¸cÄl:}õÙÆ~·&ù:e\ŒôVOÓRôJ!øG Ýogm{1GŒ2wZÌî¹×0‡Ã½VdB˜* 8¶LhB”ûJ†Iî8@½\ìE'Î?->J“)BˆF“5— äf¶ó"®–‘ Ö ÷[¦XàÍ’ cÖ½eò> 8ÏïÚ¬5ÑÒl¸Á5˜½Â™äm¢Çcµ­IOùC­ qM`ñ2ú'\|šÖ½ä+VÍŸŒnýûÚv»«Ö„•c,•Á‹ñÙM  ä‹JÃ[÷:œ½éý":ÖGK ^#çù õWjѽš³*¼$¬‘à‹á êülï½²‰ïN2ïù˜߀MƒÒÙ)Íäoûd%lV{§‡›ï%Åø5áªé`½#TTg|ܶ˜•¾§¼TÜë‚ wq5èZ#äX/ËïFPƒ£2Ön¹€åikC=wXá+ö [[>‡”(—RfB¹”OƇ…ÿeɼ‘c«Ö%œOrœ±CÒÞúd1Ü}ÛÔõ„Zä ½ >F7C@œ¤*PVtžÂÀ ÔöI±òÇ­~ZKÄ´±å·d‰ œŠaš3d_;•ü\‘fLž.Ò‹¥ïf'$¥ö…(ÛÍÑbnòf6i·Š¬I0ÝæsÑðË3 PYmµéøešêÝöè[Λ‹iíÀá®d•ôï°•›3¸ÿVâwYƤ|S Ô³ÀÛº þ†§Ö–áySÀZèS<µÞ²åˆrí޲œ§¹pVÖÐåÊ#¤’u?Ù‘N2·Ólôšãµ ÷ 9¨‹FÅ16¿À«—::ÕàÁ{ Jo¹Þcÿ0ö#ùy¤]q"ßÃŽýñÚé­S!¬¬Œ0?¡TÏ:tÿv hý\G¾>º¨îú}àÙ‰˜†BBp¿}%óÛ%‡ž¶Âl³~ÓY'ƒ#“?_g¹î“áÙ«žNŸá¡©Ú ò]ñNÍÇÕÓ½r¿ûÚ…0ÍÑÙÇ¢FŸ†ou¤é¦›"©¹ÁméGüÈBƇ|®J&÷¦”Ö³ËmÖø •bžWˆÏõRõ«òùx9¯Éà¯GAö¢58I ÷ƒ“¦-9à»^PÂÑó?(õ,.ê¿þrFV4–¹²˜ª×³î Qendstream endobj 1285 0 obj 3477 endobj 1289 0 obj <> stream xœí\Ûn7]äQ_1o-»w÷{aØb}¾Çÿ„×{ïö¸ï²ž¿]|yÝ´Q ×9#àïÁË=Öõzè¶p¢=ã ËYÇàåÛ½ÇËó}ÕõRkµ¼HO§þ Oªç˳Ôö"µ“§•‘þG.Ÿ<‰­?ükO¨ÅŠ‹ÅÁ!LµNÝ_¤ÁŽSÛÿÒÓëôö†å}gŒ\~‘^¯Óëשí0=ÝOoï„5 EšÇ^OÎ< f[;šãÃýôîNú00ÂZäç]o]|»wð÷ÇËMƒ¯OSÛóôô&ŒÖúŸ¥/>6H8OoÏãýšÞ>Kmõ(ãËñ€ÄMÅbhBZ­î@f2KN¡©Nõ"s.³õ46­âÃј«[¦DV>8ØûnïÝB)m^²WøÐkÙ±~²¢€_¨1_>Ü»ûðß‹ÍÙÅ‹½»ÿ]ð½»ßà¾|ôüyøõâo{.üPq.ŒÃð{c„ëúYãL裰…>ò¨Œ¼ £a±ƒ"þgÈpB3\ⓜ)à4‚ÞKàƒ1”pfy²¿Ò°´Þ‚ö@GázAùB‰áŽiØ‹›§†;ór¾Þ_3Rƒº¯8*±“°·²Óº„25ž FöL­skIßlpœëØuŠZ˜«òaRÐ4è4»¦¡˜ÅÕ]If…Ê2 Â3Söçû/¶Š#ýF¯“ÛÈŽá8²’eº93ή„œIøìóÁÙÑ%—f¾°V3LKÖp3’Î]Ûn€èoÑ9BØIeN³rí#:7(’d–/_zõÒŽõà VBˆÎr4¾©Ã«dp`,!Y§¹.‘ƨ¾Ç­Æ³<þÓ¼2~6hÐU0 %—³Ò«r–Žt}‰K‘÷NF=ÆVÕYÃik¶:þÉ0c©ùh³e´Vou]‡a.i‰~±i…Gy,²|Õ9¥µwfÛ$Wöi(›µ#]+\#U5éœ÷‡·¡j ^õ UóP)i£ø!´—XR¹“„)Õ›[#LóÎ:·3eÃÎN¨­²ÐÙ–ƒ=ÏRõ´Ð&/`Ê\£úìu´á"·‚-A1Y³\x ïqE+a-¼p‘o o*”*‰Šl5"•·~™5àc\¶×L˜léoy„u÷¨éÏŸ%"JHÔé·À¦ÛfЍc=sÓø˜K¦J¤åÃ’³A¿n;̘"´wüV¨®MAP}"‚KÞ4–܆Å×&][a1]o†Å-¯vºK¬àãJô¨å$*È ¶ªÚè² t‰ÏFsìXg‹,ß#<‡ŽÍ)Œð¸K|×\9 »!{K*ÜxüzÓôø—¢û©£ UÁ WÑ*Às§v¤ÕG*ùedXÄñªÇ|¤Y±p½24×ñz8’µZÙ€¯U§”€sdè€s”‚˜›¤»d—_6ƒwp Õ!çžíƒuãÎ ­ ¾g×nœfÊpq e…Ç«x²íI:ÍqļJ¸Gî9NöôÎα‹™`Þ!„u†ðt'—*f³‹Þ†3A#klëWQ¬3D7Q·”è´Um%?IXç=AB4õ5ÖÃbÚ2„‰Gôfù3öYÆzSD~M´;'Ì7›S8A[k¯œn’º÷#y¤#É™ç~WD ¦‡½§¢4Ôf4²7GìMöÀ›ôöþ6‡5P]Öõ‘¹Ýe"¿‡Õi)ÓÖUbrΚÂ$&Æc*Løè,Ûý-ŽÒ7^fLšé!zXN $ŸWaâàIUÙ³Š ž¤ÿd§ûÇsŠž©c§8Øï´$ÄÑgæLDØÅíeÞ±ŠØ=<ÐË'Ë<›®Cê?[²ö”ŠÝTÒÌo\qŒóqçð2hŠ6ISêò¡8€·yÞìævX“bô,ü„´ñ!.¶õ¢¹ÿ¤•Hå“}hªÐs5åî²\˜([óø9;¯ÀVÌoÀš$n_`g®z#›Œ´Þ€úží\QË„µ§çÎÅÑîï‘ ¹K£éF^mœ_4åYXDO=‚!+&ð>¨Ëd}*žØâ¤©ª?C %XÇuúl;ï÷K¦…ð%–Ø WDÄEõ`c]%Iº¨¨æã툤u}íÄÑè²BC‰³¢ÊgÄu3?DÌó!BŽ©Ð´-­Ð³jÜDìzܲ7›lo^Åë•eó*l®¯š6ò07ŽRœ$™\e%×C6Ëôºyž×½u¬$ÛRÛxŽ Þbù. Dä†|Ôn-SÌCic;£X¨Ý §ÐxSáUÁ/¿^£cÍ!ÓŠ¢èãoqs2ïI^í(ÉËVÙâ>Kžt]\í,}›RÇá}vÒ§SëË$om~å ÙÍy;6Læ2A3qžÛ¬°e(7j Ì1S3žýÛ|ð€#^Љxÿ$=¥›…°ÆèN@=ïÁq…yñmFþïÒÓEãÛ‹Füp&VxŒ§—Óë·éu¾Úý!Þz6kÃÀEÍ i&}<î ¥ÿ2â§ØôSõi„|ùú$6­Îw×9ÏI¥ÑðãÅ€üÞ*LŽé¬dS1Ñû²ÉÚ°›Ü›í´æ•1SäUćSÿG±éA^}õcv›ƒÜÆ„gÎcê,´.ý f¯ñrã&˜-–ßQ4\nãGE#±j§!bÏÑyabß\N zê,ÿ´pzÅmó¦¹30„L·Õý±Êü{ÚÙ@L†>“Σt>öIf®§æ»HÑD‹Û6É£lŽ qüêä]Né~m¡¬#ˆœ+nÌ‘"õËʦIœ3ªòJ 7]’0·P`8»¥Á×PÅÆ0E”ìÅ5œNûúq)–ŸÓàý3Rµ{H9Ußm™?SãÆ±­…0¨³dúøS WCxŸg–°×3Ù4†+á LP‹Ø5ìÏÀ.|¬ä¥uX`;r…÷B\tü¹.úÍ µ …¹ðUc0Ì—tÏÂTqų±ÃÖ$ub ²6$¸‚aT¶ß’ÙÅ«>ª¦´O«œÀ¨º‚Ä$$?O¶ý½¢)Óàm‘ø!vðC+qºJÞSñÄsÀñ‰b«_Êj§pï§y7˜‡Ì„à (W¥¬óõAÿØ^:«M™k‰‹~±ÆPBDN˜VØ;oµéRyoó™ób}]åSZ•#×Í'â"ê‹mUƒò¡*É‹™‹âf›_WKְ[’/™ÌU u´†:¤$AzÙçÖÈEeÇαQƧé|¿[éº[<²Õ³’uÂVr>Äc#èc¸8^ݲè–$¼i”&j:Œù KƒÙ˜!øŒ«©ÎEâ¤ÁÊf©ó¬Ülº»_ª›ÞŶ,m}÷ ÌÒFÉ+³$è+bíIÛˆÛ¶Ü/÷-p¬5 SIô@b£×©“Ôõb¼‚Rfâå;¥Þ÷­={ <½+ŽWibFH| .)ñÄÖ{Á£*9Pœ¹íäS€wwª Js;N•÷®ãjªL‚8UbÈ>æz ñÚñ^ùÓ¢¦{¼êYŠ_¶©Kœ‡>Õ>3^çzÃÉ›ø›@b0á.þœkœñzüÄøÒLÓ9_‹µ@”üŽ4ÓÛÿ™öõçã|@ð9Ú ‹è)x]LÏ·¯u'ö>“t¨OœêkT5Ôn9ò½!Â…_·vÚWGÙúš7eÃéÜX@¥a™ø;LÔ^ý1ÓC`Õèh‰†+ÒÒgœ â<íðÙè.Ò Éü¼Ïy'¥Õô}JûjâïOGÓ’ŸÒÀ¯êŸð¹òx¯í&À) \ü“ûA9E z p{þwã4ž”XeÁб1‰÷w{ÿg©endstream endobj 1290 0 obj 4189 endobj 1294 0 obj <> stream xœí\YoÇüÈ—ü…}Ënàõ}Al Ž‚ˆl~°`MŠ”`R¤(RýëSÕÓGuOÏ¢)ÀaØ÷ôT_U_½olà †ÿÄ¿'—GO¾†-Îß±ÅWðïùÑ›#º,⟓ËÅçÇØÍª…¼F-ŽÏŽF|áø  ËÙÀàÍåÑwK¹ZëÁy¦ÕrX­Åà•’ú‡ãm**lp:òšBW+58©ÎMx‚Ï–§áI9¾|‘Ÿò[äéñÑó£7 9N o\;(‡´õÀ®ûógGOžý{q{s÷âèÉ· ~ôäøŸÏÿóüyöåâOGOŸ-žÏîÆü:¸€µ»je¢ïò2JÛëüt›ß¾Mmã® Ã{{Ÿ¶Ìx5H1Žu¼ZËAxeÝòe8ç½\¾Z1誵à@z-¤¤6ËÍjÍc47°ƒv°Ö8³ ¬™ç•'MNå´Ý#]|¯=s´µtE¡÷b`Ü/¿]9Øh.%‰lÊ]™>¡Ú ¿Ô‹òˆç*Õ`¥'únÂJ+ãâ%Ñ‚’™ÅÀ¨W‘CòJä¬ÎVÜy O½¹î±‚Q` eÒ•L‹¬eÉâI®Ç£\s1æUÁ]"„oWrІ»ü,ÓL°"*XჳÞ.`bÞDÿœ)íBpÎaÇÆà #]O61µ]m}{›Ÿî)ºÏ‚!‡Åб×xÄzàÖÌ`bâ£g’ áËž”Í(+îA†®‘1 ÈÜ ø~Y:sœ¶¬óË{³š”ðß ™¥‘Ìû<7n$0D÷"ôý ÷E\Š_Æòfi_¥†$8–öý“É4\%yVÜŽKÕNDè°LÁc´s´¶]ÑZ €A+@T5Ø!Œ h)üzdï“FŒPxZK¢I3oçÌ% ¬bÂx|TsI[Øâji['Þ1—^îe.qÏkª¡$$ÓŽýk ¡áKŸÌ`š‹Â˯¯ÁôÐXšåJÉaFzFÞSª0<¨RÕ—v¢}®ºª瀛=ïÛ7Pª®á{×HXØ6¡ú€G6ëº;+2™@‹'AÈ ²Ô ”`ÊK§èL«ÙØ Z¬äbù)ÐRlœ'Z£ªm%5(•@Ô>SQbÂ\LŒÜQOÀd=X>jF«o¨Ú_K”¥ÚÄ™,˜¶RèK'@v«Ö5z[.A·`V„³-fÅI±¼¯ŠJ,6îÔ´ï8à€9_{]XÄ}‘'Ös(¦ò–ZO£ ¨t’òÙ¾#$´¬8zLšJh°"× ´s†S Z=*cÇ ánrÜ]Иîrdî aÙœ«ÑS;ñîû2«¨×“£ÁÉÑèuÁDŠE™·¯p#¿¦&nã’ÏÊâÉYÖFM0Í…wÚx˜ôœ GX÷e¤f¶™"Æ}tSdô“R¾ºj%·â;mÈI’®É2tÖ£ó‚‚Ö"ÂIÄÿÝCÆó¶µ;â¨N"Ž^÷¶W½¤ñ„ý¶’I¥£ÕY$ –Ë:@¢Z”˧ÈL¡+íÙ‡ñ¾A J Ï`/\ì*ÁqŠ’½p+¶Ööä:îšAþö»~$æ C=^Ø I¨ç‚z#ñôˆ ˜ ‚1I¿"]ï¦3º;>¨r”Q(Ô‘íX°‚9†¬öÆá߇[°36¥à`Ë*gPÉzݳçT8{ÖÀÄ•¨¯k. ZzðÜû‘žëUy1 ¸ºÞ;è,™Ýb-–Ï *ß…÷œUὪc7Úëås«ÃK}?ÉOU$15Þú›ÊBˆÊþU+E‰7X8^J²Ò÷åý†ÆÖ@GycÑôDïÍi?k—E@èz `……Àöñ¿ŽŽÿš…MçØRC8-Á—8†‚Ç…-XIv§€Œ~©w‚øå„h16]m;»Çé± m‰Ú‹A ?«¹l\SŒÚ—øýëì«eÿíUnƒU)@§«ˆ•ÿ/·½ÉOwoï:någ0°B÷ ù&½Þä×ïsÛ8ˆµ“1¬ä¬­F銥ƒ]õlÒF¿ÖZøÂ…®Pz²t¼JorÇÓÉ`7Ó¹åwBÓëôPB€È™[¬šZóA&ß¼C‘`Ì*e“z/r1™YëÇSú/ãÃV'Þ‚]„¨§œA ÷´Èf ‰÷“ý çqÝÊžÞd•î ‘ˆ³ˆ•ªRðºò[ÒSu– ÔÞKh¢ÚÅ$ßßbA$HC=Rk:ö[}eXÎ>ý!úDôyzÉ ‰)ÀG1‡ðVƒ])cGï?&„]‡c@Gôs¿ÝÀÙŠ! 7rÞ£×-TVìLç¤Së~Mœ¶_ÓX~ˆ¼6‰×‰À¶Fþa†ùÔJŒäË3©âà°öÀšàUÄ/0G õ@ÜùaÎôgÙßÅ0ʪ~Ï(ÖK§µÅ¿¶Ýp=¥úª†‘þ»,ï÷éÝ^/Á«SÈûÉ{,™.å»ò‹¯{v ‰Nò1ÐâœÜ@Èö™ ^÷ÕqÒ“ØI1•™N"à9n ghüg*SHépJj‰C¿cè)»«j^èÚX±µR·jÁÁ†-ªe|É•¸7ÜYÍ=ÆCr&È™ê¶êÕÚ{=h¯bpc÷ïVCጆmæt$|â„ ü®ý¢޽UƒuÌ¥Ž›qiвO™Nª0FðM¶ò‰Ä“¢Œ¤ ÀÛà 8˜!lÞÈ:^)*º%‚yÝ’j<†&Fí`#X'¾:Ÿ<æ,pƒª(•p"\6•K’¾?m¾'Õ ÔÖC ÌŽà5î`S·†Š©»Æ@ÄÉ]IkâMý†”,H£Ñ±®J¾uS2Ÿ%¦UG÷BŽWQè{iœ»ç¤â€pÀ,bzPqò%`Þ€¶ÎBÁ¢ØÀµ§­)CÉD éuÝÒ¼¹UÌ!UfâYŽÕq††éÌXÜÎ$?çΦÐ`ªåPgÊ=àfUÖ|–†d{¯[ø Py'Œ[Žý¤dÑÉ÷#þ„ÖOeÝI6iÏ’‹ŒAþÀk¬ÃÊ5"$¬¸)aÅÛj“Ê^<™|6Æsvy.› ˆBîëÔÚ,Ï¡3Ãd§„üµsd.}£‹XU ´`᫜mÙ”'…Õޛ⢇“#ÃÆ$Ü×&Gª|8m±¬áÓ”•·²?è&I‚¢™ÒÒÑÎA—@… TŒ»ÓzK"¦}d¨õðÝŽ”á‘Ø„È­\ ¼Îu8d/Dж—Žbå‡@3a7ý¯HRÿYÁ­/Is¢¦£€ecÏJÙXÛ•Ã4Yµd’§8Fd¹Wè9+QDºS…ÀK™ÞD+Ý΄$§ØÜ/íNáËPŒkLuˆ~~â{D 檉1B¬s¯ÔTÑV%E!$rÝ;Š©" ›o&ŽÔO¸Ët•Œ³öûÉx*³@@* &ìdHèâÀΪó"Cþ2)Õš %“†ŒÕ/unkG[ÝO¾º&»Osø8ª2©6+ÎpÄòçXú=”€÷ž®º_4ÕqB–õKé0©‡Ê(·u­W-ïcy®iкf¦`«ôïôëì&»Œ&Pyz+a-)Îh G‰ÑýÚ( !î}váYHu†ªe²8ŸSQjEÑá ± J4ž“³Uê†ðA7—y²/ø¤¹à÷…qH.‘å%D§â¾Êð)orKÛÄ<Ú\±Ðÿ€»&SîK÷Vªj¡6л&Šv«Fkç!ÕÒÜu„«SZ'ZÛ!•£¿È×KL¾_2‰V5ušw;°¯ x§ŒÛâ:ÅåP—n­3oOŽÉ~3ƒNS3…¿sé£õ‚‚•s2Q$Aö'kFSáÀi—@£KBmޝê d´tôàúÕ‡¯ l½j´-âK¾£bÈ%• „*Ï<ÍÐöUx#ÜaTYUö¿#µ–„D_~û}ûõ€MîW`I8’Ì@ú [xM+–°YGÝŸ¢ ·žõ{DÕZ ID»y“ˆæ”ñHÚ@ÑŒ,úƒdm®À”…8¿@}\ÓVºM‹oâ팴ŽtÈúsIž"´î“«àBâM:Ñ7×]fÚ,Ûy;Ds1:äÁ¡à¹« ÖªHûñoÎ:Öî\I:•œÖ&·4Qé]G#˜ÃK=ÀÔ_ݵÝÄÅÖdÞNë[šôW•ARÓ¶œûÙ>©paÁA®çÒ½‘q•mƒw=yîâB²Ò´ë«Ù:€8W…§»ÊÐûBˆ‚hª`A„ñ6FÀ†¶ø|¾08¨¤0ïuGúÖæE¾¾ð[Õå^™#Æl öÃéõ±*¼}/vÿ£›ßç‡~…v7ÐDtEZ &¤µ•ÅÒÞj=$×Ïþín‡A[“pû.¿>˯ËÕYRr3æàÜòo5ªTÉø¦B§¡Mz¸l&MO?ĉ³ýÝ´&ñ~Zt:ç–|— ©òä_M'x[ÏßýpH Ç4 ª~;aJ&Aóäã&qûeòß?°ŽÐò"´Œ`G¨x§Å<„«¶ÿ°2”¹ÊÍBå?¶m°b#t ™o¦ü2‘³ªÝaЗRßy5Ö ýkaˆ†äEþs, .Þ¨?ËYÀ°½«»ïO–pn2ïå,…T¦™FrÀ¤€vÕÉä\SLqµYÝT œ²ºÄD˜Ö3“‚,i䊤"©ëÚRµCš>› t¤Å¢ÈÉgû$±bâ³Éã.w£[~Ò`6Šçò"!jKoQ¦Š‘ïâö36õA¤ôÙ7ù 'aßùK–Yi=xmJv\˜ÙD^:¥~ˆ½=énx?}3hF¥ß‚Í4’Kƒ{cBØ‘Ÿ A#6%ÓÈÀýXò$úbOM¸“øJÌDÄIß2³˜Ê §ØKe}˜J™HÇWÃףНoð|œërý Î‡Ü> stream xœÕ[Y·ü8/ù ó8x(Þ‡aøÁŽ+HÉÙÀ’`¬÷¼;»ÚC‘üøT±›d‘ÍÞ] †¼Ù<ªXõÕÅy»äL,9þ7þ=º\<ùIZ¾<»]ðåßáßÙâíBÄO–㟣Ëå÷ø™ÓËÀ‚•V/NÃbéäÒ Î8t^.^®ž®53R»z·¶LXiÌêd½ÌZ#ìj»,(®Õên½‘Ú0aäê`í,sÞ‰ÕMùòp½1ÌûÔêhèUЄ¥¤ÑÌ Ovz_>gy·º„|ÐÒ¯®ãž‚ëÕÅšÆHAÏt»V̘ õëƒDvJ§ÔL™à—ÿ\üå%œu£˜ F…ÕyÙ¥%3Ö¬ŽcoàF§=44O׎¹ ]À¦ïËädÈé` —Ço¯Ê·ÛLãWH™ ^®ÎrY¸©Ü®¢›Þ•Þ”ætyl~“?Xcl%œy3JALz.–ÖxÆý GpA^ þ*·¶± G°¥=#õVIæ%ò. ¿ËÃ¥o›[wyô—¦[7yô0÷åÖIý6ÖŽqaºçº S6 {̂ԳX„®mj”£üRwAã&¦®£Ô(¤²É¼÷„е´Lƒ¸£…Ð÷©+o}<Ýñ®Ìx¯Ôʦ>¾ïjFAæDK«8ÓãÝÿg½áÌq.µôËrnŠöR)<¯&ª‘£%åJÂûj¤à´JjB@Ë`Óª*_ã± Ü®~]ÃíJ*CV%K<¯P'­E´ç¬Æà޲C¹†RN»DÒX5*hüö>ëzA‚ 2©2tžŽkeb§wiy«<=ÊḿKì–wgõ‘@ ‚Ý:óÀN@M(¸/ Càk¨œžú3ñÛãq-`âu¤åÒ¬ë2‹)ñaæ€ÉõR&ŸÑ:: –R d êeÿ“Îd§Órª«5 Â/ØD¾<8Í!‡&.VŸêþIzÞ†æ>BÓCq>°­5iøm¹ÅMÉ׳¢8YI¹²mo3Nû}”b¥ 4’á[¸¡d‚ëîZ…Ç»ŒŽ¶žJi_"£ ì ˜*€öÓÔõ&5Îöqt W˜o »~\SË>ë&ÞÁÅ1)tã|Œì¢i’ípˆÛƪ d"¥Ö]c°ï¨™V®¬’màƒ|Ò€çCOÔ÷ô@‘¥—´rÎè½M€³=ô’¼RD=2Â× Ú>žÃP2‹ì›¶ ÚO<2¢ž¤÷Mi¶³È½Çñ£Úci2¾ŒÑØb@kK78§P#Dµ }R!˜R9.kžd IšÕ«%2KzØä)–IóÕÄ•°¯úðsÄË•ƒ&X<é:¯È+Ð÷yu²Ñ䇔‡óŽr°@S+ÊŸA µGϧ‚%yýèRG¶q<j 5×RFP„ÒK‘@17¼AUã_9k·Ðâ#ïº}Ü%á8…0qß[ŒMš|ÝàH-§¹õ&^侊O/o—jHî~)80ÅzØÎqü{t¹øþÙâɳ-ïnîOO~^ŠÅ“ñß?ÿþ<ûëòO‹§Ï–/fsÅóT PQQVè¹ïú÷©u›FÆ@ˆä<]¾f»X/ hä”ûus5Eç™e÷ýÀõGá>(„;(+<¿ž†8ÙŒgÃ~»—q SÙúktQt„¾9¼Uyó8A)È0æçÞV×ÖMI88¸å¿NN«,Ù÷0&!XÝ$zÔ£\KwB§DƘåËÔaÆí¥eNµ™äÝO'  âaõêYüÓŒ|;Ý=ƨR”_× Ýç6¨>ÞÇÛÓ`|¸ t—¼•ÊTÿWÔs&L Þïu‹Ø`²ÓŽàMv(ì¬Á°ÜD1–`âm´:Ã%г ‰(å•,¤Â)Û F\ê9µ÷-­Å#æ0«>q¼tà!:^΂ì˜$š)]7äÝIÀX¼1’`ŸèT›+ÏV­3 ›uà?ÕjÆo,3 ç~À%%†9J*zW³ºV{XKÄŸ|ÛËš3tÿ!0á9(a\“–GÆq±S«¦ÎG“Áo† Õ ¼§½Ð4@+ŽÑi3ŠB%¯mcâ¹¥Bc‡õIª»€Ùw¥Šÿ™Ø-«šhX×U­ó 3îfruhó«“™nW §Å‹ÖÁ¥‹öÚÎL+(‘…R̺ž :2z7Ú‹Ž¢’ŠQI›#DpH·¼‡Éc"7^vÂfhz‹Ôª¶¥9¢á¸oДYߙۿ¨ß©k•Äõ›‚E¿ÎÊ HVlšÜ¨1ˆ`Ô$(oâÈß×Ëó1´€€VkÝj !Ró˜Ì"óÖiq!B./‘².ȰºP‰<0sLjÂTf—ƒ®.¤6ätËôdÖ$•`B½ß»‘ù}ÒM,[¡C£[Þœi ”Ï2Yibb›¨²ì4ƒk57qÏçÃíLv¹!ˆRGo$½=Ø$có@N¿” ~M]Ó¼ýfâÒœ4>³s%“ÕúÓ4ñÕÆ t¿·mcUÀ€¢½²aÊc(]Q_îæ¡dXS„Ú¦ÒY› ‹bz5{Z¹6’úOÓü$ºJņ’:×}cn-\) jÈdžùí“;‚h3)¯ÀI` Þ¶D‚‰`£#6–V @ÅXZqJce¥Ó+°Þbb­ó§Qè50ã~(eHÃÆuÆVÏ °û9.&a5T ´àBèT(ÑÖ…’fþ›ÒÜæñ³<©×<`²\¦RÉßÖàñ;_›òRi|7ƧTqønßÀ9•’à‰|†ªãg ¼Ç’޶Ɇ’(©ßÓÆJ$¾±ñfõêÑGœÚ4÷ŽJµºC‡Š¥_½lê†õñáÚ-Õ0ýßÐ4«o›õpF!¤×N'v[ùL©Y Ôq2‰Ž¥RLÔO/ó‹ªI5µ}~VÃói¨£sUü«n5µNåg^õóæN7 ßzlàyvz?âFÁB9Û^鞪>—äÄ×i`cáÖb!ö‹&9%r«"ãÓPgŸô&ÄÝ NÕ¦}yí¿´%G-n£íÿ$6Rç!i9ï _ý-V)]p,é[‹Þc·»Îj½½ªuq±¶PZCïáT¾&Ôx;Ù ,Qž-Ñzª ›}ê/*¬Ê`ŶÊOè[Á¬©þmj|‡|z\Ú€Sb5“CŸ@¾·V?ù6äàå£Èï‘a‡ˆèQȰšA'%ãº#7»8ï¹Â£>Ê‘}Ú*ùÃ4{$cãò‡Y"Œàíž·EŸ= »ÎêwÕ/vÝ«– ´ë6_Z;ÁËŒ;å—Ü%yýB€Oj?Öí§³‹“øéaQí/ìé{™˜ÿ£GúÈXáª+ܵ ¦æwVã/ð÷#Ÿ±JÔ÷ðÁÍ”šcfzñµÿG:ùD׉Üz™/°‘ ” ,?jx½_X§ã«ýûÅ~ ŸN¯~Î7¾ÆŸ»ïj…¡€è:¿Ë™‘ú¡æD4š_èdÑØó]A<¤°’°a&zœ}«6ž›¾F˜{5þVcNzShByö­k'§?_òÊÙwM¸8dÜšì±ì9—Ã6“Ÿ9ã ºq£h0ÀëU ‚s®†uE^B— u©3›†‹ÿéÂxuendstream endobj 1300 0 obj 3388 endobj 1304 0 obj <> stream xœí\[o·.òx^úöñ¨ÈYóº$´€ã¸©‹Ü£¢IdÉ– [’#ˉûï;Ã%9Ã]®.ÇÒ©‚#bv–—¹|œrÏ/èe'ð¿ô÷ðtõè5ˆîøÝJt_¿ãÕ/+Yºôçð´û|Øì`:×'¤ìö_®DïíÈÖ9Õ9izoºýÓÕOëö6ªW& výžšo¨ùbocýлÖßõ‚šç±i…µë—#Õ;»~EÔ7D͹aý#1\ÃA“Ê:{GÔK¢¾"êaÅ‹£y¹þyMÔ߈—Mý‚¨ïª9Äùfmö6ƒ0½U:ñB+Ë,6ëefê;jþ¼WÚÿÚÿû*ôÆ…!tû_­öÿôÓúÏ$Ñ6ã ¯äŹÌxùkM†§>Ü!¢"æ D½¶y›×îc4eÀÁ›÷Vh8ÒöÆKÿñSÁ¾7J‹Þt0O/„Çø¦‰§{m½èµáÞüŒÆûbôãÃúË%†è_Þ% Š /ˆáWh†`cý„Nf®†ÔC¢¾®Pº {Ö_õ€š g‰zB͉7ë {;¬O=ŸñÆÎ.¦Cä|ð ðx½OÔWÔ\\ÅeŠü+5éµGD}rÅ‚¦+†Ñ¤ô¡ymEÀ`ÃЩ_sðF2ÊöƒqÙ$½ìˆê¯Ó‡#}¨¢Qô!H’Ä"¨éf²@ªªš{,QõTò±6„œ*!lœÇœeYXÄÙ Ãõ¡›úD•Óβʙs€Šlp.GéúæJ˜8E’†Ï’–$„½­l“ ÖÐXL°Eá>1Dê0í!¾¦¦Jøq³é0óŸ6QÂâN4ŠÛqׯ;Q1RMÓæuõÚ56ß¼˜6§’7MÉÛækLòî.%o[°Á%ïn y,-È.ôaPƒÁšL¥ 0Ý›ÄàÇ¢Á_÷d´„Y¼Úð†NbÄf{ï! y[AÊ#£N£zëGù¬q:tá)?¢÷ “ö0ádH]âÃ74"öhM^Wf4Ž8H«1DL/}R³×ǹ[«$FyÆxjÓ;íÖOAÚà³Lâ1@\)ûa€`£MÓe½~»4AȦ,Ä.ßîmDïÀ´ÉsI¼o[â»,SL*r†«h#GÝl4,O†0nÜO£Ô NM³ö¦z0v*¬YKh™CÖR‰¢x1.ÏÊ’ð<ŒÉö¡*û°ÝF>¡ÆqÿX†hÚ6…rtÔÔØL%£0ô9gÑãÜØŒ1ý²Ð™÷¹+°¦÷´ôk·þû—hF<§÷©ÓË4’SëçôüßhØX!s0A„S™üü¸4Q.O÷W߯~éôX¯Û`"¯„ÐÀÐYúØáéêóg«GϾî./Þ¿X=úg'Wþ†ÿûü»'ðçÙÝVOŸuß/–ÿ–\ÆQqœ^ž|Ùt‡ÃQLƒö˜&5ÄÜ×AÄbc9-«ì¨0¼ Çx¹çzçÐ/˜·0»f*A™*ׇ<(ržçYÇé1¹³"6f{}uÿ tæ„ãX†…Lc{i‘·-¿äoëY‘¡zŽ4P¸Ï«¹„³–T¨×j¨<+,0&´=«ÀÌ XXš£ÅݪT >ØðÚxì[«g…ö²´^•§ ‡AzœÈ&?¾(ϯ|ùM¡½È­÷€ÔD¡[Àda÷¾ ÷¸B.°•[UÉå¢Lôýâäº[Å,SÿÞu°¡!fǾÿ™ ™jwc×@&SÚ­0+&bpQb¦\C"sÞ£$°)ÆÀ0çíp(RùQ2>½óÜghG@„-×á…†Èx¨¤p‘ ÿ}ñ…7™ÔvІµîXW,A…ˆ| ïò%Lººðx?ןÌ';A|–;½$äC;+Ü2òáAÆ#Æì8ŠÐ.·]¶ÊqŒÈ–y÷¥`Ýà÷âòBßQÝùz—'±üwc±µÇ_ι i-Ká‹ Qv¢×ߘÊ"ï6zÑ>–Èv„U¿áAÚÀ[-g­³;D/†|8‘½ !ñt"(8Ø´q«äDf‚Œ¹9; ˜¢èY6TÁRP ãÆ¤K_']9;ejfoK§+ÓÓ#¦ ™K„Í#;À}Ù:YeÓbpÙ.q²h‹-3a~/ºªƒ|v•˾ãar~ÿ€&[‡sqKP÷îzp¥†øàÑ&{ïµÕ„î\.¥ª7)TU ^Æi~éë <+;Ëá¼Ïë*iÎöÚ©ûª¤iãPþ%\TóqøØ‘h#PšIq*ß¡ašÞ&Ó1÷&­ï= p ˜LÐfm‚~¨D*¡­å¸­¥û!¬z7ÙÖp féT»‰hU}¯°2̬ï°ä«/¯FøÕá.™ÊÉàšÓ$úíë27?yÊ ûe¾~ôð!W+¹£ƒ.—FÔjQ³ªßÎñ»Ÿ‡âj@¦8¶¾B•AÔ©N…P@ôÛdªB,ÁÖUðˆ{£“éêT$ÆÇZD¯LÈÓÄ]eð&i¹Ùøc逶Îé’ÖU€×-¿­:R çÈ>±ñŽw&~5‘tŽ¥Ï—À;ªÌËÐ7B3SA0›ÙkÄu'luÃaÞ Gàî•ûi}¾™õ°åj¶. µ›MŽ0qê¯kßÁ4×Hn7³CÖÛÚ “H9f]¨‘γÁÑ)˼¦–´—¯+"”ˆã¤ìµ®+ùºµÇÍž.´ÄØOèú$¨q›åÈó#k¤æë8±$Á®¾—8ô²7\$¹¸±í…¦ž6FS^©h^thOki¨1‹¸Í°,>%ùí‚-ëj´§kF7*Ud}Õ]Ži9ì*>«¡°¾Ž› ì5fXÀ€€|pvÒïx™?páa$„ÄK™u3»@_㼎')I’Á÷¤˜ é¦Ž~¢aiØ8Ù¡ZX»>5«çh©æ×ý§è¢=&´r{¬ŒßökHnýÜ@ø¥gtÜ9øpwVöÁÂÌcfÎ_Ñ__a¿Ü´:zYü-Ѷ_‹dÖÒ{[ïl\^¡OsÒþHÈ‚÷¶J²ÖC\#$½üšaÄk!êÉ6SÝ7̱tt¤´îåMäË1}^=i£cùò€‰'²9RÁê3=ËUqžáªú^è*µ6¾-"½fPÏ^kd»ª¿QˆS!z¿}Ìbœv…½y+ ×÷ï¬í[h7™aü‚Êó ÈUaܤ8ßö¤IÙ >Òq£mï<§£ã¯C5±ýé×-¬=ÇæÀ{OÑ0tôtÝ*@—*ó]fñdu'î>ÝÇ{NÂÊN¾JçK·™kÿªH:1^4Sˆì¶Š®ïIYÿlÄ}Arb¬8@rœT$Y¼!?ò™X %߯þ–fCendstream endobj 1305 0 obj 3528 endobj 1309 0 obj <> stream xœí\YoÇôÈ—ü…}Ü ´£¾Ã09J¬ N,G€H†A‹KREÒ”([@~†pªzú¨îéÙ]R¢à†!sÐÓg_]³?-ØÀ ÿ‹_¼>xð­0lqòæ€-þÿN~:à¡Ë"þyñzñðiè&~ðFµxz|0NÀÎ.,gƒÆ×Ï–\­õà<Óêû§£8…Œùôzÿyeù ÐËwaœó^.OVk!Õ`ÍòéJŠÁ µ|¹b0PkÁ—/Vk>£¹Y¾*cÞà;Hå–—¥uSú^A¥®ÔòŸ«5Œ÷FêåEé|>>:»|½Z«Á mäò°Ì𶻇Ó<žÖ„bb±v0ããlB{ããH:[½ËÔ÷²ô%­›î~yÎ+:JfÆ5í[6L‡ý¤€™ÕÌ\Ça †I¤˜ä~`Z´ã¥l½¯ÓŠR¤/°Í ÜHèºYäHgýòýJ«Aj¾`0¨Ü_ËAx©uœÈs8Jš˜ó5ðt’Ó§b¤Ë„c.2:Ìðf%A昱‰šöGFáY˜@d—Ï—ã¹¹–IT@>®vPÐ7J¨NÄ‚çà´¯ò °ªvB,Ÿ¯ð~P—E±AÉŠJA¶zVŽu]Z‰|žGn(E7¸)=m%Ã.ó¶ªS¥£ºy‹«Š{¿ü17nJOBL2þºeÌØÉÕààýDpBW2.‹ &UWôäÌ Ib<}OˆÜ?íY\LùM#äÌÂMvYmfµ\$6ËFäÐy‹5£lVB J€J¼[q‡´¶&’´¬W㦕ð¦K§p˜ýC‰?¡ð @,¥w°ƒ¢±yó ÓWÈVκ7 n©”=\©Ay Ev}[‚dXJõcܪrÌàÌaѽ·¸A08²’íë,°gE56¸–εjû$‘¨ôD¢kížâ'¼N&M+ºÁz©u¢‡q/ ´îÆf;J6N-zvl„$`¦tÆÐE³ýôSx¬u¿œt¥†qºÑ $š,¨[ÿ|‡D°‰Xú+ßEsݪ%>ïªÛ€Â+8̨c@4ÀÙ5€·…J>(¯|‚ ´¸„‰D!N#Ø>븤Çe‚/³œŸ¶X‰Qû3É`wMóa±¡Äɹ˜*ÏÐ9]sï€(šX´à¾eëVDW*ú¾èÝ:)Ûé:’2!EûÇqeû”\ê8·*·@N.ö1Ë‚™Aq…\Ë!¡kmbÃiA K,0ú(̶ À¥÷2µaUªÁÄYšø-é±ëy%¬ÜùÓÅ«…udœ":x‘øæ¨Uߥٛvæ=Z |rbù„hi!Ál|€;4|bCq‹²ÚâT›À¥ÑG;ìu¬.Ì&vÀð㹑±N…±„BÛØÕz×}~M]<ÀûDŠº&A燲I«|˜–¶ŽªÀ¢=zG?BëÑ‹õb¾[90\˜ìÁ#ÑÏ:‚O®ÎYK°Öž¿j¤‡ºðÄ«TºvüG¯ÉŠÚZ&_‹8,³yƒŒ–ÕÃÈ®â¬Ð˜Î¢©ëp3-FÌJ\ñ:©/f²}ÃÙw0ûú{Ô I1šxdú¸ì "ó¿ìù‰½HNîÐ1dƨˆ~°"éá)…¢®W)ñsßÜ7¨WªÜâ`µ Ú«e’gãqÑó¿ŠßßH;ì>¸Ìpb7ž „nè/A–© ê¦Ôã„)‹x*¡}sT‡~£o8—Mºmæ*5Ó¸3×7Aµ”,L®úŒí¬D#¦D. μ¥ÙbÍØa‚Íw¼F˜p«ª&Cзµ/Ý PÊáAWbJ’Ù×"Iw“,»¡AÀê„ “$iã`•÷¿¢“çåÄ •*Ÿ¸~c6Œ @Q¢ñ„,…û„ÅÁˆ^…õUµÊE¡#-äÑ+²eÊ[¦ˆÝMùݱ(£g#¿ÓiF†›™KMÕúü>JÚ`f†‘ÂitDÅ~¹ò8È%£* p'½?Ƀ ½H&Qà…;Ftÿ8xú§gË¿®C´÷ Ú¦Hî5(‚ó*réõÛ6¯Y-Àšc‘¨ @GQƒß ÜX)òb…×¾ZãéÒÓyxBzž”CUJmp  B.óë«üú"·õŸå¶M~ú!¿mç+ýæÞ^ä·/rÛ›ðFù3Ø©|yþ<6ŽàÕ8ͽs¼Ìmçù (m#€ÿÏrÛaçl i ÏÇG½ü¼™G\ç¶×ùé‹üöûÜv?’\×ç@k=ŠÍ›A®ªmÇí|ÞP©æ’ÞþÐLO—ùíÛ†ÇõÎɩ֯€FP!±a<dzêÈALÅÞrTèzØ¡ë&ÒPJB„ã»Û©ëƒ&ázÝtƒ&<$e ù,µ6D³¶<´[·h’ãCaþ÷„\Ûê¿øµ(½ú¯-˜²a¢ýy ¶Šj÷Ž$mĹjþÆO ‘C§ð$;1$Îñ$KôÇIÜ—JΤxÏæô(R‹§ºéºSýB&’¶éæ4‹CÓ7­Ù5­Çó«·ILu…e-ñÞjÍ¡)ß»ßBR úŸÊžh‚k’¤Ë¯pwæËmÖaÊ :Ǧ¦šê™ê)„É]~èpqÞª%/­,ÙCû©-üô$Ý—_ 7‰´»_F&¸rÔÏ‹µï÷U_lm-EÉÎÄÜw“*CbNOªéÇÂ?›¼ ôB†š¥¯iµÖÞ<÷ /þ?¼y@`yçYîå)]î æ;#_Öà€*UðÔÄr÷x÷­ƒZÄ·íµ™C‹‚lïr·‚^]|÷!5ú)ˆ/0ªÊ ÔÅfª¾ºq°Ä-ÿ=Rú€H©M#ÆÏRê¢?âôcò“CñøÌ—J·ûÌ.“d_pÔ:ÿPÎo5îöÓ€#¡Ëo3®ÑÚªØt¿Àß.” ÅOeg§SŸ¹Ÿr½im7‡ŸÀÇ ,^Èîß¿¢ü3Z‘J¨ßÒŸJáµdJ¶å{ da}`ØÆ öfÇŸ Ø¯¾9X¿úuÅ”­³UÝ}ÿç4?G·•@¹ól®}âw–gmÚuú«õnæ/®Ž{ Lríçõ‚ÙÙ[¶ú›Ði~%\ª|5UWÛ¢Ü{!šËo[L H‚PÜËBC~ãºÇç¿\S;×áûÔ9v4,á7J]¶˜¥ÆìT—{ÍçE7OT€ÎoUj(OÙDJÂÃ׺”´¿‘2­ïŸŒŸÿÅÏš­=Êuåø÷÷zÝÛ×ëòÜÆòˆäfóåîòÙ`hä^>•µúa’™¸‘ÃÛÏ ã)˜… ¿Wýiž¥Nùõ©1ûOþÍÁø•endstream endobj 1310 0 obj 4230 endobj 1314 0 obj <> stream xœÍ\Y·ò¸¿bgl›dó à‡8¶ƒ¶£ØûfÆzuFZ­l­|üûÝÍ©dõtÏ!Ù Qe^ïŸ6¢“‘þLßÞ]|ôµ²bóìí…Øü3þ÷ìâ§ 9LÙLÝÞm>¹ŽÓŒÕ×'¤Ü\?½7ã´SãlìæúîâÛí£Ë+Õ)¬ÙþLÃ'4|SO0˜í=Qo›eÞ™í[šû¶Y–&ÄÍŒ pzºÃ0ágšpOÔ§D}AÔWDo;çìöšð@nXê‹ú’õ¨/ˆz[ÌM§y¹ýn;RUo¶¿Ò°ü˜™ú–†Ó}ã›I¢ ~w¹Ûâûë_„N{!üæú‹‹ë¿~»ý˜ž|åp¸÷Þ¹é²Í\\ÆN8úç=b¢@ÔÅá!ËÞlju”Ö’ýø"1Ž4‘•¤?ý*iï+¥Åæjǜ鄯ˆ±ÞÑðîòÊÉÐG-4#ìOˆú¦žJs€$©p¾  74áwvßt‡Lç·ÿ gxNÃ'ÍÅõe!ö½ ¾jûQ£!(™‡b™5nx²/ë¹Ãð–U2÷¬¾á/'Héã“Øí߉ú ŸÑ²ˆÚ¼"h‚Å›½œT¥ÙÒŒwHÜ£•é¬v™7³NôQ‹ªß xv:Õy: ¬À+¢–f]û¨y†4÷!ªƒÇël¯‰x_¬Ú{›A>òGŒ2yÀ¹,…3z8ËÈ©³Œºï(#Ç«•,#îeä=ªá,#'£T>ÉHAeddÍ^k&¬^6pƒ?ÿ¾G,›*º²£@Ñ‘ ¤>ÈÈ€Y%þÀRÁ½íôâ¿ÓÞ ÿ@ÔÿõQð ‘ëÅ_„!:ÖéRVDøÅp¿ì DÖŠÞ‚è”G†›åéqݪƬ‘ÿ§7Z3·z£žl¸w¼&*„ ^—ï90óøaú=˜¹Œ °5Àо›Ùól6**›Á”w—J_&+*Tx|M2  *#†¨à÷ø¥#TƒoÜÞ));Ó#ƒõœ#h(HvVø¶òRqH‡ÑŠL…‡¬uÆ*‹ãϱƒ_@Ø€ALÆÔÎp›!Aåp…]Tиd‡Ætko…´9ÝjNÖk¼$W9gÒkYo5þ@m(d~:Æw`æ+tø8)оkžn¿î,å{µîÔ$Ú2$6YÓh„û¹$>Ä7,P@­ŠƒFõˆ0+p>hKïµfnÆtœ¬áËúe? ~ y­ŽsôøOéé ÚìW¢‚ì´)Ï =>£Œà½ZÙ­&„sìÕY³¬vôl1a¿:SŲŒoÎÀp-ú°/™³Œ™O>²&š 3HûfH<¸[ŠÜ-Eî– qY¼Þ‡s·"†R‰á¡Áé…‡Ø¹ïØ—}Â.»gækw@âbEr¬ ”fV>* Ee\ŒO¬Ôh­Z. I©”Vs…?€+Ê@åj6†LóS"^P8¹J½Q8¹?¤×ÅõÅïα£²,»ĦbIe•®Áj•¥PY¶@)É.@"'Ì#" eò'SÁ{Ì*ºª†CØ~a]zRû…ivY+L|žV/ S) «…É-L•£ ˆ –A‹ÐY|ð²2Æ~2-šL‹>À´uÑ=‹i©ú1›˜îzM%ÆóŒ™yq.]ÅL… ÕËFå¡k¥ÔzL.*}:e„¸Ù| Rñ\y`Étµ;zn0¾Ð7iB( 4Š´–Ð&ýZGÖÇ|’E³Ð(ö4M9>ÏÝSe±šcŠr²n&ÙeP¢(i‚‘«%ûøÏ. `ær— ãsë|õC°¯y–2`=‹_Ãi¢ñ¼lu @0l §gAª&ì\Ø!tcÜ^Õi+èZ÷LÅ› ÇLeõƒ¶¬ 0Úµ¯÷­Ù@,Éb©˜Â /TÀ’Å“_Ösï­ÉåÄçõ,žõ{>c3èä!ÙÉ×ßà…Û|/£/OÞaý ž¯ás)Ð0“s®ò”ŸÕ*y±4Kæ´aƒ™Ø)ç¼dƒÏ‰ ®T-øvg™†Œùðü•P›’b[å¥ùÄ <µgK§Ð–ÁãìŽNQÏdåÔÉƧ,¸³‰¦dÀGYü{ކ6‘]›ñó|‘US›ÈbŒ õÍ΃£–À-k\k NÎêœnp@D۵ʛ·¦jPŒÉnâu@¦ö ±~à²,Ù¾ 2ËÊ€c¿d—I–lWPÉy_,²ÙA²CYLúV²­¡SöXô¿ba„z#|lÞÝp»V'fä‹ãeÇKNî™;f‹<@#¸uêÇ¢|?_çÑWÅÜÕ ÚÕ0jã­®"úžJÁÏY„ø 2mP³]âÑÎìê†íÑúBHÏû[ºùPU¨Æwý¸CŽç{Â[ç Ïr),5m–g6:#φ×,SäÈMýN²—‘lû ¬Ï5åù[XáÛÊÊ„ SXY³ŒIgó:Ø8¬v“ä-‹æs6=µ íÿ†ßLXÍÝû ¾#oEõçØ!û9šÀƒZ6@g?gMïÄê¶1µÔ»(K¥ OkÅU«3ˆqß°s¿$*¤Ä*å9æBS¾úlËw³ðýîÀø® z˜’¨0•K˜òM$‹ý½à¾¬™ ˜B"bÕ$ø&JcT§£Üø)µ1„á|SÈ` š²?ð_™í ÙÏeEšÉ‡.z´f‰%dsIŠU¹ºtÅA§È-¨è—,Œ|—0ÿãU.\¡éK2¥;:~ÒÚIÍ]. €¹‹YEóÁº¸RóšŠÿî4Ê|- ò2§Ê­`ƒ·æKu8åØàmͲýåóÖnL²°¿|~d‹çiþFXrëž_rn]Ó·R{Ïe÷$“ýZ³lê—iž– ¨ö÷Ë”ÑÎ{é—Y•檚Ϧ‡ç­ ’èá'i/[²´—Ôì?š¥nš2=ýDüž~[¨74|•T—ŒGi|p{ùRbŽDü²Ì‹jUÂ=y'íd éznm$y{ ¢²û§nµ RÁ@=X+zËŽG:ý~‘Ü„.Xeuúa"9ý*‘Šl,Õ&=ˆÐã/}~)»ÐËø9^\Џ¢N¦ÖäøèÞ»”ᣠå`7u<#ˆñ[œ:ù C$?Mn¢¼õ@ü[$úä9?Ú3îc¥éÓ>²³¶Cß0sÐýn£Ûqªí=®z{™¾‹å•GVXk’¥ïûNJÇO3ÿ²û߯èÆ1FɤòíRÛv}“Þ¥é;z3üÐHžpC×»Kgelþ|é,8!½c=¸Èÿ¹¼‹ºÊÊéÑÓÜšû†ÃäawÅ¡_NwZ µ¹’6‚¯è½ã:CëD&¦eŸ]_ü7þù?ïÕÈoendstream endobj 1315 0 obj 3087 endobj 1319 0 obj <> stream xœÍ\Ýn¹±öÒ7çÁ™ <æ_“ ‚Is`lAï…,­dG²4‘åÝõ{,ò¼©âO³HG£]{a†ÝÍ&Y¬úªêcqþ}2OâdÆ¿ôÿù›g?ÿ‹\æ“«·Ïæ“ÿ‡WÏþýL„WNÒçoN~s^'~ò‹\ôÉéå³øqbåd…÷'VÌÓ OÞ<ûçæt»S“ôFùÍ«íÎLÎy¯6_mwRËÉ,fs¾Ý‰iYŒX6wå…›í ß×Ò/›wñ®³›7Ûž¼4‹ÚÜ–Wß·¤™¤ÛÜãs˜Bø~þè¾¼É>»U0Žy±ô&ùüC‰1Rl~±^~yú‡ Y‰>îfq²“vZNN/`öÿ¾ãg£s‹Jpx9‹„ÞþÓv7O‹÷‹2yÖ82í—«,È`ïQ˜f‹ß¼Ø¬S,“=cçu]._ló6;¸Zü$È+§­kWÎèi™%ýX?Z­Ó`½&VÅE}½yä©f+Â"Z5iOoÞ®³½hç½(G?”6¤§ ìi™Ü¼l.£0„QYÉ ŽÄØI E[•ÎËÝW8¾Ú%Í }•çï¹Þo™<ö?, bý<ŠUC»êÚgQÁÁ¤6b‹ Ë9uÙÓ™ä鑿û"ÿø‚ñ³KówÉüH³`ÆIILãŽý.š²“Ò–N…¼€Ê²,¨{IlÁŒ^—ËØƒ’š‘àEû’ " á¶\FÅ+2µà£Ž:‘ï¾êôß%£¹OʯÛIäwËp÷í·¬«Âà«t¾O³Õbóõvõ#j oâºîÒÂKK@‘X/‘áM'® (ðæ’Uz² ƒ½ã ²_üR²-ë-iODI0ë5;ê³jÔ©/òü} OY½Áääµ1–…à]FÔ€+ôE߆¿ØŠÉ+1ëƒvÕˆ‰ÈŽ,ëgF—R€šøÊ 1‘–Á|<)|^àŸ â}å È ªÅL‹@ÿ¡œŸì,6ßjÀóL÷Û”QY°6§y‰½áÝ1ÿÂŽP]ã°•EË£Âï 7,é9‹Ÿ­ŠpŽÓ²Óì©×!ˆtÈE'$š5ñ?—8>¥>(W€v‘Ô«_wƒ€ ÂŒ¾HNJfm!²(x`]eÊui„ýô:#ø vàAolvë­,î“\QTÀQòΊ×,¢dŽ=¥Å] F\É‘+Ü ëÊU3uƒknY/›|MX¸ ZWI,Øð lúµ®U ŠˆoJMU‚+M¨•Â6Þ_ôDãJþœœ“ ËaXÌÉcÞÈÝõý0ÙH YUɪv]$?H–Ñ‘¸â`ø0Y™ý4 Gµã2 Ì-3ì_ô©)ýBSƒû¸+ÓQŠÏQÈG ®u¯ætEb]éÊ]²+#)'R®®cûÅ™ZÁ =h 1zHº+S¥;×µŸ´Ë s«M•X‘á=‡o‚>ÚE“oò.†´ZSö*§çÍ¢F&è¾(wóhT5/²òû,c9€ð÷lŽÁ šO"ÎØá4_@_6ßlx•ZªL“dRÄáðräý Ÿz<¯0e—ÖvM3ˆ)=t.ïæÐ{þˆæïJ ùm1bbûԓ혛ñæƒ ‘šÕÀ^j$RÂN žg¦Šy„N"ˆDšw¹+ŽŠ y •VMOÌ0NH ¾åšÔ†…òAvæ?p©Ä$„Úü«¼PÈ4ê™vJÂLÔÒ¶ŸKi«*ùŒ*rÀˆŒŒ…Ddïq,3×ÞýŽ›ÿWø*˜¥5'ðÈÌ0ˆ¬,¬¤X'KÆÇ2ˆd*dMÆ4„‡†‹Lå{šg•ï öð9jàrãع+”‘^àÀ'-nókL%í ~‰§ÅMÞBRù÷­A ð0-Àá?È›E…PÁß÷ðÜLL¬Œ1‚M\¸l¾oì‘“eÄ2PHGmœX~ψ¨ª9B,ÀŸòºaD2ÑYŸË7 ®Ôܲ—=ô«\á¸ÜÒkoТΓ¡"ï[DKjšnÊäÇ& cò7¤,Õ´H¿9Ý*99©™lŠ[c´ß7Ö_o­€>@å¿®¨‚Ä=e¬ÉS;ª *÷½4þÈYý0^«nrbÇi™i1Žú¿’/Òïã]/ADžtÀ²3dZwÑÓºJ]3: úßjv;á|ØÜù†8”.XiùøšiK`Ì[\ä'q(Õ„çd B(¯¬¹o>/àC–ƒ„™ëz ±ÛÕéršHá&m9³á½:!…4†XôëQM~3jË]á.S²$U?¸j QþÄH õ¿a‹M»’BÉ‘$ÇxŽYÑ̨fxŒkÍ¥u»ÜèÀ­ë‚ÿ–f®„¿%[n³h|p#¶ ^qñž¹zÔäŸ@ÈÖlÔó=Kº·ý›Õ»¥j£™Å»ïŠv¤Îâ~ôªc‚DI¢Z²%¢»N ÒìÉÍc™zë„xê}#Afû _bÀiч걻IßÚ5œi(\ «} C 6Èo%tšsx¯;ÐDú˜d+Û;™á«¥IÄJÕdõ±Â–È#Y˜rö&—[;¹yUG|Rt„7 ƒöË@½²n²$Þ©:‚¹©$Riw!*L1Ûîs´Â%ˆh­2& ØuvÓz˸ÈónÒh%ȪÜÕ0bdšIšpQ/ …ÏQ ÛçÈFìá®–QÞ»KÌ; s„+«6¸I’D¯ñqCº÷Sø<×iÿ¡]Aé²ÉX¤1kˆ>ýæ÷dû{Åé êè'1­Fâö¿ò ’çMXY>Êi‘:AÑÝ‚ D äßTp!Õ<X÷GŠlÈãón ]uÃJßæÌJTV£L÷3.³½ÛBÀ"AϾÁ$ÀvhºN%­‡½;1ŸT-.޶²Yœ$§.ôeÔ'¬ž­G!ÁBBH¾d„ ÌŽ žÓÞYÇN*ôLöÙÊ »°!Ø{è×ÎHЦ»´:7ÀjÏ,â¶è,ÛÈ9B ±âZÈ“@!è6,Øž§˜@øŸV6È IGb§6¦«£7)ç¢ñÀh33Ýìù±†L’B‘MKª=†N ð³€Ì‘­$¬ždª¬…c‡8=àGn6 À¹AÄÑð³ lÕh®„žœô Œ:Àw•ï1¢NœÉ !ß_W?ßùÈF(Èt y“§žc7Ðm£‘V›¬Äiéè]æ]+VôŒsð3J"=P´$î7ß•o–pƒLˆHÈHzˆw¿Ë ¡é:î)Bõ:¯yæü;s*Ä0F†Æ7%„ï‚mR–`ƒ'ÃHpƒXÂo×T%$qS^´aO €Ézb¯aëÈÜ >¼ÏÎHQŸ^jˆHIsÊ€‘§¢æÏ³„µg žI™£’Âä‚LLf'x± aÂ$lÍåtCзexØbÝfÁ«¿/ßÊ‘¢‘Y»›cŸ¢‡°º®€å³ìÑ„çß%FÄÉ”J«&¼.ùW±4}ÚÒ°qO"“"·´)'­ä1*Òð…Y´&ýòZQ/ŽL+p½­mŠ´ã‚/t6ü~ 6[fÁŽŒD0Z”þèx}-œú°æÁHïä1(÷Mä’’âåù§LµÎþ@­<š«tCht¶!œÆU/È/*}\ð4X+‚gQ­º”$P†æ¨¨·&S ³ÑTV%NÉE¢ª6Ü·>gXïÏ’‰8•Ï<¬å-NC U¬lúzëöûšF[aÚvëÞÆ^$e<¦ÃZ¶g+ÂÂ-jP9¬œÏ¥0M‘x¤1³’£jË™ôvÅ^²Ñ@Ø€ Kf(T×ùGo¦ó¼QÙWïêë¬>ÄCã°Å–4’)‰Ä~œ5Âc㋨Àæ {WmwÞ›àҿغÉjo’);«³„U†\ê:ll-Õni¯#)eü$eØJ…Ö.ð£ùñ}n{¹…Æ©XEœ¿¼>}ƒ£B© ´ñù-è¥W.°íéÍ€ô²V»ù#P[e­¡ßŒmlØÝar…Q ,V Û;y±´Æ6rr d/6kó/°¹t‹Ñô’ŒäÅ6¼«ùmMÈ…”ñîäôóg§?KÛšò#á7Ôý1r„jÍŽšÊÖ»öÈvp·Y3âwÔhgc\âJJvp)ì;–šœÎ);ïøb9žÛm „C‚F>Û±hM°Ù" Yç‚uæÎñxÓ˜x:hM‡ê\±a·ãé«ÚÃÙ Aœ65!›š_s¡råMrÈ{–Yä—í„k¯WSea> 醮[E…¾èà`j:Ï!)®zr‘µ=ÙíŽÑHãBÃÞ²,¿šÃF ò> *YmO\cg©-l“Î)‡Ê©A*Mwå%H·„NkJÝãâ׉æmb†i!ƒ!\Œ_< 2B,/ŠñŠ/²†[IŸ7çµ’u{)5ÊdqÁ˜ùúy¾€Ÿô•´¼Úûlx.3Úõ¹‚Äò:¼sOYT3†4HϳªJV`)&×ÕÂ5ƒj6[PýuKˆÅ]-O‡r¹rOh•}+ŽV>¯¡/ð…Os{‚Ò­)2¿ãæLf#z<_ÚÁL“ĹªL(b×èlËÓ 'hêAœ @°D:òÇÊê:U§9¬¯´~•§ÊìHа¦–C»Œœž¡¸Aö¾«²ƒ¦˜¾±Æ\½;,Œ ¤çË n"\•,Qr£ÑVVÄE!¦GÌw(V£ƒÐ¼™ Ø‚‘¹ +kfôQrœdE^r¡=ÛòÛQ™™åK ®9ßLZDÚs†x›NÄ­°Á&¨¼ ³²{„^m†ŠuÍ’Ú} W†¦Bˆ{a  IuN9ˆÞ¨ 7Œ:;‚∥$Ó¹Þ±1Ù¦zÙØýÊ—å@ÿ´GªÊeýsza’ürX› Â%Vûï¶­5V©Ä-ÎÙ–Œ”Æ¡~:OW\;éwÚÈ¥n‡˜V¯š…Iqêã )Ø5N`ýšG1ÿÏÖd­[ÂÆqŽökvAÕ°1Ck¡££š=rÌŒåc "ë=7êhT$¬‘̸0®²IÛØlQ(³ßlª(âˆY1äÖ£' ž¸áŸŸñ…ŽügyÎr-å£%󇕭^?ìä&åï^ÕtT¾l·±¥Ÿ\ÜÅVÈ<\„_¶qã¾`ø1ÉãJ·´h¥&©ÐHVÀd½ g?0gñsuÊ•XÒ» š+ލjéÉÞEY7©K0Çí°µÜ<…ŸÃB¬´ öŸÃ|îʕֳìÊÚ³|ñ›m(æ†3Å”‹üø#M‘À´–¸sáïX½æ½ögƒ_¦óB²òÕC›¶ãZn_T|P¿\»]4±tìce†&fÖó #jÓú6ŠÈ5¸Oõ@e Æ^âÊñ O•r§“;ƒX™¯]k‚€daÅÇ·?2eMÉOH¬Lú¹-/ãïMI¬Iñç¶~²ÝA.=DmJ;„[¼ŠIE¾w½^}µ>¼X`h°ÎäÅ»õñízïr½z½>½Zï½[¯î×§g뽦íÝz¯ôñ‹|…BÀX+r½q`&P7ùêvý?°Ý’Îöì×ÇûõñÒcœö’Ü,²ûv½·c>sÍLpG$[ ¯J g è¾°jóËpÓZòôu¾už/î›Å±6ue1T¬×•¶+Ï~•o=]ËYn^¼H7# BÜ^o™éap«ýj}ºk†ˆWß®O÷ÌÓ[¦ß"ȯק¥Å*€A®50$•@¢àSafYÄU†ü¶(§8¥ODÊÔÊt©$ûɵMФ?)4¡ < ÷M_Eñé«f”µ]¤åY$«nE®· —rçµ­Í U¥Ì²¨y¹×‚U­ÛÅH‹'h!¯Ö£òj´7Rû¼ï øÝõx¼} Œ•·–ÀÓïCò”Üü’Pi¼ji‹Ö¦A5XÛ 3¥çƒöFø½gÆÖšl=ëf^WçÿÉ(5ç¾L¸êH‹³á*ë~È·¾$ózô—\IJ1°ü"žÇÕU%öy¡¹ƒj´ñ4n®¹íü“/ã .¬G™í†-¼âäZ(3fÌóW KfŒÿàéBªDÂcȰTuQP)edÒI~‹¦§W›c ‘E¾ú)žæçúR+‰† *c³s¤Ò!¸®Ò9ÿšM ¼"ÄÏd—½¼xÅeÓ’3ÿ”Wú¨f×.,é#~ÐDJ;ùMËVõRNR•e«Ä6žJîY‡LÑ¡DlE¨?J¥¡ðÕuü^Y®JäHf©ªHÂÍrö¢^€Xù¸ÐF|iØöÏRĈOJö§5ËÞ¼KÖQK‰)g,lL”ã`t߈¯ïáСoVÿŽÿÓxÉnOsûL*Í€ eÒÅ€½*œÓxç3°6ƒöÝ¡ý†„}ühçúCXüw½/`+É+Î9ÿ¼cèñvצÃ@B33g•‘¥… \e:Å:SZ®7±áïNŸýþþ Ò¯¾endstream endobj 1320 0 obj 5096 endobj 1324 0 obj <> stream xœíZKo7rô¥A7¯ŠŠáûQ=´(-Ú¾%=8¶ü€c[±£"ý÷r¹œÙ]®¥ØQbÀ`˜ —ïo¾ù8äûgbÆã/ÿ?ºÜ{þJZ>;½Ýã³—ðwº÷~O¤OfùßÑåìçƒø™Ó³À‚•VÏNöÚÄÌÉ™œqȼÜ{Ýü2_pæ8—Ú7×ó…aÞ‡ š«¹`A/›g%uŠÅ똩×ÍÍ|!˜µFØæË?ÌšÁ8Us>ç0c¤5ëÿsð[š‘ C•š)üìà÷½ƒï_7Í…bÁé{è:;j“Úèæbn™0Ú„f‰å0© M¥aŠš©ƒí %½›š`W|S¦rH[/³j'¨%6• u)%³Þ4ƶ!Xeš]¡A ã%*ÉÛ¹bÆrëÚÕ2¶·±œySö–9ÂÌZ_6øfï•u:L)íEó±ä-JjUJ/R š‡Avy‹JÞyI]–RØkÎ6/*ÅX娤nJéõ »˜º%MëbéO]^‡(Y¿w3Ø*æóÚ|—Ö8pSÇaLra¡æÁ1|MÐE6'£BAò-æ¾Ã=%Õn#, S¦Õ¨‚êØXBµãFL šôPf}¸Gs0~eµmþ‹mi攣µÎðSD~o ‹ùË „!ÀoG¥¸ÍqÉ<ÇL4»Ól"AcK­/%5Š+ì(VÒ–9ØúývtÂ(À$ƒ4¶G7y-­òy&&pO†Š}-°3—¸¤%œþ~\>Å„’°þ>Rú¬ –¸Õ:0å»=IÓ?+½/c¹dX¬þhRé²S Z`A㪇ÑÁxf ˜uÁµ£ú4À—¯)N掹 ]Ž×UèG¸JM8:³niœoxÞO§›7MÛv¶qã~ÛìÞ ‚àd¶Qý;:Dh¾­uDF‡-½™—áסÓá Çsqðt6g{›tXc’º×#ŸN«žig²Ù­é&“Êê~—tÛQLè,fÞþóÝdœ/=ge#ÊŽpÄ /™ÏqeÉ4µ:ϱ#Qk©ß¼žÁZÁL ˆ¯)²¥6Éãð^f‘è­ £Ú0þ?"A)ÅAY’š–,:ì°¿¨ ©‰,ÚÃ…Œ½­2Î3é[RÑB·%ïCE VtÏYÉC™²h«Xºª”^•ÒÛŠŽú—ê(`HÉ#±“U)>LÅ@ˆZèbP9–~+¥MúÈŸÿêú¨jÑ„(V'Ä[L[t$s:ÈsE-¶JgUã¿ÉN¢'´òÄXH¨¢ÿ‰ÓOÉþ "3O²qÚ¨9Š~À¥ Þà.%ÙöŸ½eϱt9­ZŒfdDŸ-þ˜‡mE†­Í[f‹@"õ»V…ï;¹," £cöèe(D”‘iÒ82 :Á¸/¢ ¨ÿa~o÷¢‰XÁÉFê…F`oM‹h±µòUὋBÈ…xB|WJ¯ Õœn{ìÒ^}uNyWe’ÓQ²ˆ­tªï˲nmp|Ë[»œƒÀÓÒDÒ‡/­v<ÙÄ¥Ê C}¨ù?иòúJHNRB7rÐ"yQÚ"”A>Qe>µœâÁÓ…\`„SæÄ@´oÿ8› üºS¢îs 7¹;ÁOæSЩ&æ3väÛÆÄZï2±xdAÎçJ®‚Ÿ´¯ÜJÒQñóûµCé€Mjz¼[e à÷Û?´Ê×iIhÒ÷í*è‡C‰©}uÏKr‰uãøê±‹žÃÝq÷ŒOLʵ~d¥b6]ÐáÁ8ü¬þ‰ô°®Ž†æš#QJà=ŒDc3žyIÚÿa}Ìœ‚H\#Ïíàl­ŽiÄ¿\c£H8GÆ?ÊÑ=c™Ý˪–‰­o Ÿ$× uXÁõ"‹X•Û¸2Wµ/Iè=ó¦åxVîKN‡[ˆ6]°D‹Î‰;!³ãs\÷á£PÍn–}@ˆQƒ'%v\”žOß–¼uIGnî¾-¸ÝV*§˜~TÁøÁa/’£ÖÖ×)¥¸®]–ÄÊ©¢ëñ·L+?d„;$TØ¢ÓĿīöEí­º˜)Ö 5—Z5p"¹u){†¬´Yõ¶òБ˜ü²¶ZSBÑ=úàùÆs |ɤær¶ˆ½Ö«r:êUè ÿéÝ›CÔ>íÞô¦”® âIyY‰oPÛh ÖH7¨î‘Þ Jo€‘¾:ißÔby5a¾ê]iŠabxï'zWJ®ËÈi{ƒêÈ¥À—½+uL?v¾¯_–nkƒ/fOá^ô^ñ£o—¢ß.EÃ¥¨”¢<ÃPÿÙ@QàÑ0¦ðÂò¬¢7Þ•<@ˆõÌ%0G•*ëÊ­(j£­åˆ&žóï!GÐ@–U:,Êl5c!¸ÏŽ zx[µ›¬¸.ôÕ|ŽÊuÞt`MØjÝÄFäžýeŒˆmúQ©83BRê^O0f+§t3ï]èeŸ³ýíÊ ä…e_-€—Vzp|íZ:ê–dxDÍtsUñ#ê<Úø'ñ£ª™^éšH§[Ú|šÚb}óT'$ŠIg“G|uaJµmiH^Lßa¬‡|‘ÑU]ÊG¨†/2ú(†­ôBÃÓ\y›Q?üu¯/–ã¦7’ب»™íèõÁÂðuÃÌH·C›Ški³•~f+ýD[ŸùÑEŽ/}⣈ì¦E$õvŲ›ŸMtŒVð²£÷`ÑæI< ð—f¸ òÚôȾÿ£Ï?0}ëÀŒáð¢Âmµ ¾ç@6<®ÔÝZ““·ÿÓyŒ‘6ÂCi ?¾çK!”©#Ò]ÖØñT>8UÅæ¦{#úÌ¢'ñwq¿{óX­ f·åÊ OÂÇ•mL$ÇE|Á%C6Ï83<“\år|Œµ~=Øû~ÿ#F!endstream endobj 1325 0 obj 2203 endobj 1329 0 obj <> stream xœå[Iod·rÔ%¡oÓä½p_|K#H Ž­›íƒ¦{´@RK–ZÎL~}Š|$«ÈÇ–ZËØÂ@×bÕW+ßü´`#_°ð“~¯¯þð­0lqvÄgG?ñ8e‘~­¯:ŽÓÄÂÞ£ǧGÓ|áìÂr62è¼>ú~ùÛÕ Gç™V?ÿ-®âtUh2n`åñf߯䨵Wjùa5ðÑÍÍr·„æ£÷š h-øòz•­_þ§’Uw«Ap‰3mým$Ñy/ûë¯CË mäòd—0uÛ]EzÉYWØüÇ 1/–›i®³Ë‹8.™å 36Ÿe¤[¾/3¯pæ‡pì²ÐŽKwùXfN·òœëLR{ñ¤‹•Ð#3Ü/^™‘9qRp7*«3'¸–ˇ=„äíËž“°5™›N'”X1ZîýÂ8=7Aån¥F'µVpLh)8—û>”ÖÐŒÂö ÍÜw¶Œð‡\~ÿÄÄÜú1-Q‚,9)K®J߇Һ+£;²Mje¤ïÓcø(^¢} P¾Ç^‚9²ì>ÀO’ÔhV-õ.’!ÈU¥@yÂÙ¬Y@­„/{AçÙË]ÿÐÕšÛ²êQhvôÌ.O—7eê]Ð =rk^ÛFtCÃÀý(l£4ž'»M™M¹|º²`‚hî v>t¥˜nî|fmì U@•uTbÄä½ÄÒÌÏÇ›äMmV…d£Øʳ€ ûM@ça5ZCÇOËúz&=U«q²¥÷¶{ÀE—·È»¤m¡ï@ÐŽ1®(oZ.Cë] ZŽ\¨¹·‰°I²‹óNæö!N´Ü Ÿ&usäÁ!;!Ð ⎲²ª»†Ÿ¨vÌ,ÿ½Xæ §ž¯\šün$”‰ñŒ—ghö€SçšP;qS{æúHˆ|Bº`ò%Hß¹ÀFõˆ2>¿”IÞÔ‰hÄ#QTĈï*m,vÂØäS/`Ù§B4µ;HÚ´ÆÞà¦ÛloLåûGC·£Ýö:q÷n°G­ìs C+È/ÂD¤-KTx™mof¥ú“+O²ã7+PvÉ™¢*’±a9*ÔŠçHÕrá&qZ¦€‹3’B3©‹Uµ’Ô-ÉC¼‘¼É×Yips&Ç· ±Ùi\­Î«Êg¢÷!7å]]j”ÚC4ú÷£ãß…S ¶[Kß›wË“ ªŠWèE‹K޾‚}d\Ú/§#xïŽ90:Ç8µ¦‘»UæâuÁ¬ ¬K-5•Ñö³„i_i¦à)™M”€d/i—!Ò´LWë3&ee îŠ5Þ»×U0÷U!û©´Ä‹Q8ÆZ°€Â¢¯KâqSZÛþŸ–ðÿ¢ôåŒÎm¾-Ã×¥`˜•¤¥oèlsYúvͼ:-¹(­k’È ! áV0C' †•Q–ººJ› Ny˜œ2¸cÔ˜Çଽñ4æû‚ðœÝ›´£Tœú1yVðlù¦^\EŒÅ›—¸×ü:¯…®j¿HèbÎÜæ÷˜[‡Ñ¡ìÄÖf °¾zŽáßÃ(àÇÒvyô¼!%n’÷eì^8‘[GöÁ}ÏÒ”&†ßæõ¢­qÄ›Vz@¢‚)C2¿{ç½*®4zBÅ– ¼v{æžth*Ë¡W‰¹y;¬«Ó¥—¤â³d"ß»ˆÐðá¡ôáo°ýý3לrŠItq–¾µ5˜Rtzn %µmˆÍt?0+ïg(ÕÞcÖÆ÷Tnæ6†xØnœÙ±1ÁÅD58'è%Ñ)ª;‚—X#"l0MëÖMNKaè„*<–]z©tE_‡þw«I‚5Ú``t“RL˜b=©¤L<{>‹òYåÔ_½YŸ'þf*AE[où;·ñDÕR¹­žó\Ò;&› ËþŽ…)Œ÷%z={TŠÛ’¤úSº˜òÔ|eÐ~uªÌf"a²Ið“èç¶)è~?B¿Ã^’ôöÃýõ§Pø‡¹ýê5ÑiŒŸûÑ>9Œ¨wõ~Uªk^—êž("Ò6ê{ä9 pt‡¤w4)„lCIG™]ï«—ÜÏ“ÍÇSéB8AÈ——QBÞª~Aä©yÝõ)û´Ô'§@ï‹SIpt³cUÏmCÊ=׿€ØYú˜ÐíÈGìy×hÞ(BHë–MU:tMóò~XV‡‘òUm¹¢‹ríËõa‘nMœ Ù‹x[$á °y«©©ÞR÷—éS˜™œó>oÓ½Zr7Ñ€5±évByæ[;2€L‰ksyHiD‚ Tî—,üðý&@¨†¿\Ñ/Œ†‚‰²#¹é¦Ö†sÅÄ rý“ÒºÏÕRN¹mfѱó†:ZjùØÜ‹Žmçç]äÆÏM­º†-Øv­£ÅL£—deåÁ;Z±ôXà<$šErS}‡Oˆç\v¸þÔ—)ôœôʦS{_úšÅuyìQb’.@ƒ â~5Ø‹ç!þõµÂš¸R,”{±´kÞCð óAÊ 8Þ°t5Šƶ¹kSƒ¿Ò‡s}hT«¢¾Q­ê¼¢ZwQe”±2QZ]’(Ô=^2ˆ]Æ`<Ç•> i¬ÀIz(2Á¾ö2atKØü|C˜ûn:çîÒÛD'²•y‰Y „H‹VŠšÖ:PÔ¯ÖšÁüM[€g &:"(’ªÌ0~‰V¿±bqz²Õä¿ O§Â;‘VS¡†>¬ÆÑæõ#|*ÃÝ´:>¼nËÌ*à¥sÆ‚ƒ_þ“~p’—ïH!9oÔ=äý¶ºQ8_ŧâ&=j#òZE/UXRפ­X&ûŽÐZR®“Y`Ê$¯^ú§{d`OÉŽý@ޤ¹Î’m ‹¸‡¬cÁ7Å)œ”Öº@ÿ²£‡;tßt†ïJßi£tõhÏ/ Š¯+;b)–ÿèlˆK.fº€Êv— óòÏs]+fò47.ˆ¦®¯ˆ1ãbV€{"¼2ñ>Ù×5pwÅ%µþ¡6a!mÂAX<0$£„p—qÓ±\ -×n~Ë&l¢£†úÎ<“݆‡ûØÐÅÒÓÞ<Ò/éuu¿äefw@{¹îÞ¯óžC{|o”$f^“á¹C¢°¸‹SzŸ6 ¯â—†—¡ìE¹PB„Ëú¤é³"¢Œ‡j¥ÇÝ/ÈU‡åŒc ¡¶%£ ^àÀuÑ<ºc­$Ÿ-ÀöC‚O+Ðl:·¹o˜üG æqʆ^$„hu ñmñ ¥…éQÍ/РâÔ©ÙgðâÿÃdÇwˆG@ñb´]e9OZî’ñó˜·¶þ¨¸Sû"{/Ä‹¦2*‡$Aÿ£)aö«/@ÀyÇ: I¨ç ŸÑ¶…ÑM6ã¶‹™”_—’&s"ž„ò¨á;܆ÝOJKíî~.·émMë`¡¼Ò —©tö¤#©öÿXÅp&ÛÆnnŒwÚûdÑ-ÌÈÛڔëð’2i,hËܶûúøè_ðó_ #‹endstream endobj 1330 0 obj 2924 endobj 1334 0 obj <> stream xœí\Yo$·’·}É_˜Ç™`§Ó¼I΃#qàÀŽ£<Ù~ëÎj%Y+9Ö¿O›G‘]­‘´‡7F°0ÜKvó¨ã«¯Šœýq5b5âŸôÿÃ×/þð´ãêôÍ‹qõøïôÅ/D|e•þwøzõÙA|M¬Â¬´zupòb@¬œœaåÄ8ŒÐóúÅ·ënÄdðr½ÛlÅ`­6zýz³ÕÐjF¹¾ÞlÍàí›Æ4FŠõñf+µŒ5ÓJŒz}_õ!¨õU}¼Á±`Ýj} )X–tëo6z0R»¾«o¦ï½[o§o„Áʤçõ1/Ъ¸5Âh~ýÕf;6« — q][ïÊlS¿–Á~ð7ž©éƒ7I€AÒbe½”8ÀV¼2 Ÿþ À…\|ùâà÷ß®¿./Ô§¿çWןl¶VøÁ¦§níH/w_•¶Ãòt\zß”¶ú´-½Ÿu_àÓié=/m—åéëÒûª´Ý–§oK¯-mb³ ƒÒÖ©õ÷°gedZ«s`]ùÅëÜt‘Ž»@Ó§ù¡N0¦¦(SªE<_°¯Jw¿-|²¥W”6Ü•’` rý¯NÚøbÝÄQyú4Íì×¾´ ÌÐ&ïV•&Ÿ›Lž,65Uç¦ÃYßGbzŸ3ÆuTz{}T3ÃÞ^“™åÞïéN¥z[ƒøßñ4ù~<­ÚžÎM’ºÜÛØÒc½M¾o«²2å‹¡´©9¶ oám¿*?“ïËÏ8SØ–§ÏKïOŒ']’o'=Yù +«–N¬ì!}µÎÒXŒÍÕÀr¤ªŽDq}k­„SO´°õË$M ãoí¨B2x﮼×9û¢ŽqÙNZMd|T?Í`„2tp܇›j¨RIóuˆÀõ¿,Xàk×.x5à¶lídö3ñ|ðÒuÖŽŸåÕ¡ ¶J‚¼_m‘…¸à&Y|·.Ò«1j,mÕ:4I• H¦W2½º´}Bìn²-]õ¨?&EÃycý²¨©ö‹ÚÓWlÝw ŠÔ¥ ÁÞZÈÖ¿Û´ó$qKL‚qËIÒ¿êà®>(þ1EÛwàëСšZþàtù­³Š3–«ÒÛÆrý‹ïôCx”þu&¦Sß¹[ÕxS`Þu+HžöÿÄ”˜ëdAì­í-Þi­†_´v÷ùf«´óëŸë«¤8—ßÕêÃUä´pƒ““Xª!íÊÓ!ÕRr6!5Q|í¾)m'åéŠé}]žv¥÷’5Ñ­Õn• 䯻òÉënÀ¤ !¿ÏŸ4ææ2YÊv‡Œ‰[ØÏɵœLÀ×v×Õ. ,’mEPêœÙlUK\Tˆ¾œ2ŽB ÇJNßDž·¤ñŠ?1˜YõWÝ’£1  {ÊP™>&ÓòvÌ §œø_5ëƒØ/_;‚|­£k)¤¼öÛª}hP¾rSÓ¸§ëe[01öoŠÞ•§ "lä?ïk¬Óíó?ù(×»aVpÑjU*÷›A´HýÜ -xÿ2“ŸåLÖJÖ|['ßãE½ª±»fÁÛ@Ø/fh‰œçao+ŽTÜ®(S O×°§yv°R#ÆÂ)~±Qƒ1A#, `×1Ö”'. ÃpC•7à‹ÆˆÜhúO&·… ìhÏç%bgþaü‰€‚·ë?"@ÆgG%T‚Ж7yK™%ÉFfµÅ(dHÑï~W¸˪ðq6²§!L褬ŽåD‡udKíÑ$¶ªz¶™„¦¨J :ì š–lÈvuØÃ:Ö«„á¨ÚCžãèWdÚ#xÁ˜A·€Ç«•sM¢V£›ÌÜÀßb™,÷“ª†Óª¬òt³QUv´.)ÍKI•:-*aÐðYxº­Ó/žóæ©Þàú€ïùÞŸa« Ò±˜˜xUçªÇ˸?´KᳬTÕv=tN²ˆ©²óÈÆr“TÐðÁÄC>ßÕA§ñ~}–ÔëÓJL}ÒnªMòÆB1(e×_N.൥3ܲŸ‘%nÄ8(o Ä´XI÷=Sø]Ò¶!dÑå^Ñ傊,¬ÇPÑkºòY]îT:Œj+±ø˜uŒ™—·Ú$ŽG¾ “€76Hên'$_êå†ý7˜z’\ƒ¼—Ÿ!xjHjE„Š>d€ç[a´½jD’7°¦àG¬Co%$sÆ8y·J·" ò9à{PÁ÷Œ vaÐj ˆ€ævþHP.Ÿí(¨v—O˜§íàBè—ë I$huP?·’ÿlDôCE!‰¨³v£#èüPæßQLÌJ$~ŠVê [nG%®“_†ÇÌÆ^`¯aPA$m\”¤VÓ R ×o-æ)íJâôNQ ¯ÃßNà ÓÿÉærÌÊg†zøýu»<dbÆç.çi†ÑŠì«U5ªç•„p¤:¯àF ï4ŒjÄMÏêg;uÏ;^Ë•8¬„°H´Ý}u”– gÞ…æê´?›F¤LZOXgß`9)´-RT_!•¢jëÿfû:k)Q‘}\å=»ùîâ ¹ù”ÃÙ9›òŽ®ð‚EޛާÂXÁû„îÊuÈムÔÊÎ(qÉ À‚6Qùþ1Ð’$ð4hAèóá‘Ñûöé4F˜†n14)Á€kÑjcb¦,ã·‚ @ÞŸÓt¦bv¯¬O9Àà•åÓ»™iáæ†ï'báFÙ)¶5 ÆG§ÕúyÐz<>%}ðøÔ[D„õ»=þ¾0Ö%æ9”M(1é»°·Æ¢UĺOfºQèœöTFŸÄs4ƒ¼z×ûÎzQëÚÏÎÑâJS±îs”ÁªdäÕ.ä"û"‘Ûë”­Mc¶‹1šÀÆ9R¤¹žÅ|•¬Šó7¥rЭ÷'ᬳ|† šRçÄn¸z& –dhûÜè-£ø\¶ÏGÝdÆUAwñ&ã"9@dɤÓ¹wʧëÖKHÄðvñ0o ?Ý–‰ q°³³`ÚPM‚îŽZRi%Kc™=¡,àβ¯›÷‘²Fù.+»5kÎ{•£éóøUåÖ‡êKâ/[ sŸ$\ð\dU« ûIË9¦†Sã>!9}YxÃYJ9|Ã/Ê'MFPäC¤–Ó-Þ‚÷¤<à!¹tdaW+=|ì<žU¥n˜ 4H‰Íú¯DXK52Á¤eâmo‰Ìˆ$®æªòŽË*gJG&uÚ@Ü—¸gÕGM;x*ЖoæÅ—T Š*ê2ôîsjp…Iþ“õ¾º3~-!Ï žì i; *Ixïõžzë€U(„вzþmŸ¼u¶¡Ü ôÇX$P´Ú“Êqk®±ŠãˆX* A]ÍÎX ‘´”çÍ1ò¨úÔ”ÊjBLJ(ü ybJˆK1’,…``…»³ºhºû ­Ý`}KäâêO8[&Kž3ê.^v…Ü ‡®êÏã×}ÒÏ)*"ÙûŒtŸTnÍB)ü®Á¿‡áœ,«èKœ!ÄúÁ¼ñ„½m2N€y¹ÔµW ®_T†zT[·%¤%°ŽÚnŸÈÖŠ ÌÞ*ùÌf»s²y"Ò\¨Ñ† –äw‘(âa<ä*j‚ɱ-$ñ'œä…êt]Ö’ê4,Qý¢šò>ît‘Bˆ3 ÎR2I¼q™áº>ý Å>>Ðh³—1>àÂѺˆ WFúŽÒE åsGÄ ×D¦¶€ØÅS|áU}mt`7_!L3èQ,”š°)ù uÃ1v{Œü'ðC{ÄEÂÒb­§RMÿgX»Ö°F5€/“¥ÜW»bI7‘ Ö°GÀµÑí§×ŒG1lñp".Ë?)៎~Ça¬§\êß³ð°>åØ ÔiK¡QÒ‚–»ï“΀êö·4ûCOâAm-@ºñùZ@‡¢h¡#S,Nîóˆ­“î?ä­‚Ï:çñp²aˆ¥Î£FFóâ#)‚œr5Oú+ ÁQAæ Aõ¤’IÚ8yÎO†%^zGÁ!ÏÉ®2S>›nËðHs™ƒvL°rX¨ƒ=Ñ唊PßÞ¦ˆtZŠël1WSmÅW3WÑriÒÞEÑ!&cK¡wÇŽ¢²©CNüŒ»ðÏÇ$!Žö÷P²äžÅYn¿œ|Ç}4Ü‘½AWP¢¿">Ú[Lô0rOã¸^O§žK~ö€4Öô…Z²œØzEOûîzSÆÕ’Rú¾CËD4£ZÛŸì‘ûñ7\ÊÍ_ý¨NÆžîç;“M¬³Þ’zýÓ®êc‘Üêy} Іel|µ‹wBÃ3õâáÚcwf1Êà×ìÁ{CcqÛøД1ŒÊç©ln}Â95ëtæ8•)6¥ÅRì\?ÞüØ/²b– J1€Ú'Àö5År„Òx|Šó%[Ö /[ü‰ÕAµ›Ç)Æô^‚7‰œ%Sµ¹ç¼Î’—RŽŠÅGfÉ£Ó+¡ñ×€2&Rc.(W[•® K£ßÂ<ÊâÕ»Ù†Ækåú+˜} àÙ#JJÁ!ú|0e^±ÑÇÝ‘nÌ—½Ã·Á›"˜hÅy®£òæ]ùúßôÐ(Àª‰%@ êPV°™-O|¾1ÿUªôKí׳__Åûß³__E;ÇÍXqÉQ+$R5Ä_„i¢åV8Mh1ùõrP² lDZ~¢1nHHj¡"Š9BSÒ?ɹIÚ9«Ùžs¦t‰KÖ@Äã¿’`šª¸‡ÏmÓ‚ ÀÚ–B2S§"Ø o#ÉmÒå2cÕÂã¯ømݾ}( ì’YTŸ ¤ —÷´à‡”Ø üWÀÈ­:Ô¬è¼úg{Tå#có“ǤÝß’ ¹NZ¯6E,Õ¾€|Ò»®<˜ Ë,0Îïöÿ9àvuÔ§¹+4‚ÝÚ†ï·È6é@P>¶/ðæÍ‹ùå’5¶Çmmv€‹vø‹-b>JZúçü…-h~Zvñ6Þ·M´¹/˜Á©Å©ì†‚¿˜ærBë@ñ§VÒÖ&l*È©„PÍ!x“\Cœ.è»9M¤?‹f¢RAÌâç7mnÓ•}ï[,˜ŒÈñaû´{ê+SÝ!DkÕÀ‰Z*nÔœaÆU¦Ü‘;iŠÏ°5XßÐtâÓ¯­xTE.J¥Á”Öá'™;&íšruŽðµ•ƒ<íKüyŒšŸpÌ.….0Mÿ¼E Xr(S#¡©ê܈~~ðâðç¿â!qŒendstream endobj 1335 0 obj 4110 endobj 1339 0 obj <> stream xœ½[[o[¹.Ú7½ô/èQ**úðN.Š›vÛ¦í¢›ÔÀ>t‹Â±ÇX;J;©ÿ}gxòÙº¤Ê"k†âeøq.ß åóñù€ÿ¥Ÿç·³“× ó«O³aþgø{5û8ãaÈ<ý8¿¿8 ÃøÜ3o„QóÓ·³¸Ÿ[1·|`tÞÎþµ¸_0FkÁï–+Íœ´Z\.WRæœ[|¨½wË•bB{ãqgÆ(èœ÷2 0\ËÅ:ö:»8C57y6?-%ÓÚ+[f06Ï!+ >^ §™–vqV§¿¯C/@VÉØÊd'rÂÔ+aÀùä€ëÐTÂrØK– \Ó¢žCïUçÃhž%„N2‰A§Ì+¹8…U™ðRë <H®˜fñv L‚ð-6½ÐFf`p‡{\@0Á™õ;-SB¥Ã ßQ óu_³üûô¯3¡ü4çô´…l?Æ2n_–¿^ ÍÃýâóÒ0ndUù QõÌpÞ¡&¹gƒæÏJJv]W+ì¿\ræ%ÞOXÔðØ P‹\ÞJˆ¼¨O‚M@ñ¤d–Ë$>Ê‘Ä7Ò[Üâ1-o]Òe¸º¹(Ò{S›gͲá¦8§j¹Ž*>ø sÅC“ðþH&E@x¦´Û°B=^ú*ÝúŠ‹xï[:~Àºöìò@0!4 ­-J:À y/ˆjè‚‹ò~ƒàÄ UùØæ= K\ÙMõ ¯Óp«D¶‡Ú$‹}(ê×|¾þ!Ç„IdhïJ‚U§Ñr‰èN˜?úˆ²*fÍâMã ä&8~]>1eÔ$¢«Õ”ˆ\¤­`­Ö€C¯ 8ƒùϲ*ñ¥“®Fìfôùã²fôi`a*û´³ Þ‹ZÙˆ{Ç@²ÓMÕºzðxŒK±øq©˜rèôH$‰wÖ¸Š*4YZ@r•7M°Ü1e܆} M².¹–¢x®s+œ$b³[‰·­‰k$ÞŠœ‡*Cã|¬kµ &?-ª#¾™¼3r¶ß6¾#x9nÀupzà: 1µ`fWW‘ó§%ÒÎäИc‹"[ÇìÈ)]éˆIoàÏJøžÌÛ›ðïià|ÒY<„úÖ‚ÞBN!¦ø3FH-¥é¤v`Î6ü„èÔE’,„¬E´ã¦–½åz —õ$¨¿õ±sѽ ¬Î„8ÃËä8p—ì8¾,W~†Á>6lœô>!àu‡@úr)2à:“ ‰@…Рc^øÈ™E©@€[RÃÃ.¾%ò£}[É\=ÖõdĄà v«Õf:4böc-J}À¦tLjò)²FmaéÏ:4Î ˆ¶|Všä+ÂÕF´Ÿ›Ë‚¼eQ†YOlî±Ún½¼q*ƒû'Zç£CиÁœEú©| Ò©vNdy‘.EÉä!ë91ø;„O3¤§f/ %¦Š'´ IÙ`uÁ,Njïç%„î´¡ÆKH Ú¨cpNèâ(*>'4ÁÀ«r:ëùדƛé#Üï›2ô1É,é¡ ¨o— b•ž8‡† Ç«–¶e_T#6 •¡„æ¹ê|¨6UÚ21ðlTY’³^ŽœZwƒ³q_eÝiè3†XB‰Áq2ãëüLr“¯ #5ä+YaVSœ&¸!exLÌ(e!”{v à„Ió¬z¨¶†" ÙÖ›NT²‰@Ôh6‚†ñ &zCÐ B^‚¼)¹É”Ø)©ŸHìþ‘‚P·±7ës8’úeçMâ´n;Á±gIkôgn3B|”‡©°*™52ÝÔ”Nx:O ZAö"²V/2JB3[rWX9lÐ:”„(mÚ%I$õªÇ§ bWQÛŒ"GL®»kIlh*õy(¹ä>[RÊ=0§Ÿ Ç"d8-ÿe &%5ŸN@ó•ÈþD2çŸ=ÇNykv›ŠU°’å ~ß”^<ùÉkm­øSÒ©èë¨+¸ ÐÈDcåw Y©“Œã¡´îC }ú‡ÐRާO±À4R€÷W‹ß•ß—ÏJßmi]–O_ú¾e ´OVYOl|_Z×åÓu·/¶>•VÜÃÚèQ ð÷Ùéoä®ûÜx—Î#óbÖn¹V~™ý‘#Þ'¯…Us0"†Ù=8hPhµN ú:«Á3ôåÀ:¤Z˜É^¾\y¯Cµå,ÀbÆ ÎC‘`Ry…Zz@ßÀ™5B”é»ÓÙ«Ùǹ4A°f7çX5D‚L~žßÎ^¼œ¼ü~~÷p9;ùqÎg'Áÿ½øáðãå翘}÷rþjó;Ëô±¹„|ÍÑ£cÜ`ʈ  å8©—[OO¶®®J3Áܾ묌‚}À¶Ám9P¦ç Ì…„Û¶ÀÞU3Bv‹ˆHµ§<€„±†Ö×\&îÚÏé8;™A‘Zörj5Á² i骤´TÞMÃuI¼Jù.Òj7 \QZ=o&Ãp[ÛŠ…›Éeÿ®S‰5‰ïj]e´EX7:‹O(åÔMxŠa’# 9Lâ@?„ø¶ª’¬í†øED~§vÂmú}C5‚ØÍÍŒË}E”\á׉a2Ű é_²§ ÜÙVDÚ³‘Ã_PêQ*m¤¬ßê E­š;¬“†9ÿdý+ézÈK¥h Éwµ9Íèxâý—záÊ óAwƈõML(;»C]4ã—…íêšo‹gkò F8ÜÀ«¯¶®H”âÏØžIe³u:1š¶çÍÏTü0Å2¯§œÏès²mš+;Ÿ´‘^#ZÛË’o ²‘QIf«ÏØíù£”â;òàäæž{j)ÅoÑ\<>?K«ŸŸÏFÒF]!#˜&áÛ©0€µÓ윤¥Æé‚Ãt)j¢@½¿*”?&)Àÿ¼³7“½O(itJñ´~êú•ø*…Õè`’²|Ç•ÑãoªDîE¸äL©AdÚÿíØ#¸_•êëBOœýÜÆÇø<àM§w…ö„ä™/þ¶äžqÕfï¤psJÙÒª;šèçõË clN<.žâOKF팧¢WÈFÇeæö˃^⯋Ϧºá>œ@¤/Ý” l"顤} ¤ ƒdÖ±Hª'í›eN[‘ûÄ*&ˆ¹ï~Œ^ZÖÙyÐÌÛýÌSBoˆ©Ï1ÐËòn ]ÊÁñÓš]^—ÖçüésK'™Qû¢Lg´tÀ®Ž£¦Tä‹‚×ÙD¡¢ÖdêÞo«ºÒh¶?¬uòA¨`9ÇQß‘Ä-lçÐmmhØTeñëû¢Jf«²†‰ãÀ:y\ùÖ¸ jo\Éìƒp^âSÍ1p‰¼ ®bk\êýõ•Ì>W I_G"ï‚«ÜWáñ»ŠûâJg‚+¬c¤¯c‘wÁUm«ÅÊèÞ¸’Ùáj•Æ7—cà:y\õÖ¸jÍìþúJf„«ŽOáÇÀu$ò.¸š­q•¶<Îí+™}®ÒúcéëHä]pµ[ã YºØ›½ÒÙáÊý±rW*òC÷¹áõr²œB^ð¸ƒàWü¡¾,ÝõUˆPY˜.v«Ûô$}µmÞÌ™ïo"töAh*{,¡"ïüÀÿ,š"üö̾h’Ù¡‰ È‘t“ˆ|Þ!‡"_wná´‘åï_É¡³ÂþK#‰È½ö5u±çr½7nuî!¨yq¬BM•÷ËDñ«šný²Pý*ÑûÎMn-ò몸ÍôCÆ”â8ZÙˆ\«"÷_ÒÂÖùØ>‡,~U}_XëÜC0ÕFIi«¼×‚šðk¿-ÈÛf,¾×ï_ñ¢Ó«{ce†¥4Ce®…ïúuÃ7¥ï¡³sÀ'A^à/ø™¹a¿€wàåaX×—N; ,¯fÿÜÏP„endstream endobj 1340 0 obj 3067 endobj 1344 0 obj <> stream xœí[YUÇŽòx_òNü¹÷Ðû‚0RpˆCÇ!ÉŠE˜Y1 Ì’„È?Ã?8U}z©îÓwLEh˜C¯ÕÕUÕßWݼØÄ†âïÇ«;† ç+6| ?«7+š ñ׋ãáÁ6³jð“7¨ag5À+ËÙÄ ðxõdüf½Q“š‰ñõšÃ—wb¼ÀB¡½ñãášÁZ >ž®7zrži5ž`SÉ”Ï×rÒ†ûlç÷A6QMª‡Ð“ÖÞ ;»0Ý/òs{m*!Ùät”Ó(fb0NMÊÍ­Õä¤NÃt—r|¸³z¼z3ÈY°7p.ÌdŽãq PáƒG«;¾.Î.÷Vw¾øêÎïð¯ú~=úÍð³ÕÃGÃã­ŠÝ.3ç:N•E~‘Ä#"Ÿä²s*üR{qXgc¨yò:$½?H‡F³I|‘‹¾v³È{¹ì(=ϵo¯­W¥&£n¬WÒûƒôª4ŸØ§Ñ+ùuÖÜ^ù,—u,÷ìÚzj‚HsS½’Þ¤WzuŸF¯Dä¢×Ã,òn£¹­ÁY{1©¸A¿] 6Ya˜ÄÞ³õ†Oàðy aØyåÁòsõ» “ïT¶Wf|ÐÆ¡í… Ÿgeµ÷lã"—ýuË¢÷aíyÇK;Û8Þ]oŒá“`r|ú”jJ¨aÃqAÐp€ÜË}öó8ÏsÙ‹Žæš²Zþ)Æû ƒ“ƒC­Lòº³øÃÎRzµB¬ s(;1–怲Óf2(ºHíTPt’>ΉäsQqJ4Fgy唰݃†“?U…fä¼W.u[†³žùÐÍC;ÂâÉýËu²( ÉɃá‡ñÁ%õ×h"%˜î7k Ç¡Ñ~ÜÁBÅ4÷ãCüäÆ[G\X)iaÚìÆN…¨¨™{_/°{G€´yë>Îé…ºêx¯gƒòÑ“~½Þ€ë2&”ƒÚŒßÁV)ÏŒ%?E]Á®xo¤epdØ9 èš³ZBðÈ¥§åsoÒË0èNj½¶ØDÕŸå‰/KýIœLÚÑi¯˜m®Ï0Ü©„`àʰD39fHÓ( ‘.Nª=sãßÖfâÒC…⺬Eè8—d6ÍåœϽž— ˆX¤×Û²¬ïóogY­÷I±®’um¡RXŸÆÇ©.ËZÉTeªÛ8Ø)C ŽYˆ /óDYçëÚàlÒ '8 é$÷!óGœn¾ îÀŒmpRÆß !¥3?Ù ´ a'¿E«'i$õú£JLÚš8~(%ÝfrBDc\P'ù¬©;/‘NQYÉEïKV‚ N¨Š“ Gã 㜀਴/i5QÜ•MÜ– óÆì–£u¯œ¼ ÑÜPªl$¨Øy›¬¡ñÍâ0ئ÷Ž.0éź‘WÑ!}Ú¼ÇSˆºJk;²+ ±S,Usx]jÀ4OÊR0-·^2PÐÇð9$o^ÛJ‹— Z2(ØW»óÒ]u@Ïz@haõ Oˆm‡–rì'§› Á)m‚†sç4ã¶ËüUÐNA¦—¹ì"â¡:ê­ÿø÷$÷y™Ç9íÈP$ü<—Ý{ï¾…xÍw4ó„¬$Õ¶2 ½ ø1ø”ŒºÌP/âO¨å˜‰y–joçÚg "çÁñDRÑŒ÷0Lýaµó«ÿ#ãk ã­¤  YfÅ¡†ˆkÆ”¸GV&]!_&9S4ªíåãàºü ÄØó?á½/›†ehºwÅ%y*bécZÖMéƒçº¦>îæ:½¨S¹@šP/ ±²ýÆÉ­ÎRYÙQ]Tyî•F\6í¬ ¶!…›€%xÚk÷~SÖsò€ûÛ±¶¹K3v+îÁ׃]7î"•Ì)x¤ER7!‘ó\ªÑtK¡­÷zr1Ãg•AèHƒ©^ˆI*ठøÒ QŸ¬ÒÐ\9o¹² §Ȥ?λeÝ\\4]û~’.ç<°\#‚§Ù´6F‚øL’EÀ—–ž¯"ò‘|ü;a™‡-ŠŸ€p@p t­p@Ò‹0Ç DÝømŽr}fY†ÂN¸$Å)(îÆÆª×ba€Þj±£MΣ€Ðìø¦ÌOÀ%éô¢@ÒW¸79î ‰jVà ^.BL€šMJMƒ(þæÔ,Ó•Û‚] šú?§ºaNPÏ}'®ÿ@{¡˜nãV0iÿεÜ8Ú`€Ù­ÑSnY\•û~û‹6-U¸ "V©¬ÙŒ}׌Åöi+çºÛ ‰ÉmY-2nÊl‚Óð’N ºCº±L‰”y +‹©r]_3¢M²€ P ž/í?É5”À«å3 j©@Í‚ ¿Á·„úßË]Ê0uµ·ÀßmnÁÚÒè~;”}¶¤Å sÁºW‹±ŠüŸ¥¢g…Eäáï5 ¤äáx¹²‹"jª{V†/ô»MTÔ—Œ%)ÑN1oo!ôóFkA_Iº|Õ ÂMöœäÚËFÑ*ƒ«Œä~®-ûütÌŸ·ò×—iÉ·ÒÇM+(úºn„u?ÌIëǯ–•O×˔л.ÞgpñN{ïw6§5ãZ¿­!W/ º¨p«¡ÓƒI`\"ÿ$åTt’W¡îÇ„ã@èD³áAWПãWDí%Ø&©Áw¿ÍC¢à´o aQ…íôÌtK}ÔÓÛiƒ~R¶ºë¿ùjŸåyÌ4¯úQp?Ǩî5e¬_×ïê·s[²¨jŽ7˜EYØOý®@å|©üß–R½ÎtU:3¿Ù_¦T¯O®Œã‡Ã 3Qu%,èb¨&æW Wÿïõ­Kendstream endobj 1345 0 obj 3232 endobj 1350 0 obj <> stream xœÕ[ÙŽ\· òØ/ù…À·÷î‹ ëA±lOoñI`Áhvh6fd)ðgøƒSäåR\nO,; KÉKɪS§Šìï—d¤Kâþ \,vþÊYž¼\åÇðÿÉâûõ]–ᯃ‹åÓ=×M‹%¥£•’-÷ŽÓt©ÙRS2±Ü»X|3°ÕšŽFKj‡qµ&£åš‹Aukùjm­¥ÃþÔA(3œ¯Ö†³–G+6ra…n\I9Ü®è¨ã껽?/ží-¾Z|¿äÊ˲£YRÎĨŒ“IŽÄ¸>Ý]ìì~¶¼½¹;Zìü}I;Ÿ¸?ž~ù'øk÷ÃåoÏv—_=tÝ”+7>^ûq”m¸[q·F&ðjrÑÉîö.íhS ¼V$t¹†piÍrïÝs_1+¹NWk9ãÆ:[Á&*‰/WkÆäÈÌðƒÛZMƒ CÎqúêÑ5\çÁnV°u Ű—¹ý¾¢ð®‡¯a‰–S"pûUo¨ø‘äÓá*%©Â²åÚò+4a¸p•–IÅq×—°³R¥§èŽÀãŸdQÂGŠa‹8eiŒ¢aµœh ó&¹`—£fÔËEa wÓÀF‡%ø¯Îó¯S{Fq3d^¬ÔH5‘ËV›N¾>Ê_ï率¾ÝR*ñç7+§H ,(¤×•iK cÎʘå26*—2L‡aÔŒÂâiÐÒŠiÒ.ÜæqOÉìžVzÇA8¬çx©^U €fCÚxÛ=*´Y—áÔ`†R‰}­Õ ×Û ugݸÇ+=j {‰Ïõ.w=Ç2NÚPhùUîzÒ-6&;0@¥%– õ¶IZb°´¹xÛ•!¨ ³##4ªÍ›Ôî×B¾,×”M­ßa*e‡?¨°Ä¯V°oŒhÍï¦îŠÈ… ™êF³hÕ—IQfðÅʬ¾]Án;¦ª¾LÈĪ4BšÑ0ÝjD„ &Ø(Á2šc¬å>I"žei²ÜîÅ6ásO¯ÉHÕ‘¹`|H}¯Òè«7A½¹F¸xÝÅ ¤h7~›à)Ñ¡Û5jC16Üæ‹uôIF]rÛ'ÁÃQ … D°ŽŠh¢¼‡aÿhº}ƒAKuØP#¥öêÌÀ2ú¬Gàvs7+j„F„M$ÑҼʖº1!Ö¼îx4‘ïBw¨5À$ g È;äbcÿ•ý¼YIG3èð¾›IŽjrQþ-'­¼Ü ëV¥˜ÜÒix²¢+§AÔ(Xa(}KÚï¢a¥ée‘û>  à–üªCFGd7OôåŠÂ·ìÁ)µ@ýļ³ÍT$Ú)ZI6þn)ÞÛïÚ!®ì!2Õ¾G< gH9†š†õh â6¬g:‹è'Ñw]„(°HØj, ¹À"‡“1ò~ÿ¶Ò–¾I‹ ¸b !ûÉv~)a&áÈÄmm1h—|·8mɘQeTgÅ7à'ƒìaœ¼ãAç9€E%‚)´éÍÅ F¥®Üû5€ø¹ÎzXr9¹ç+p>R&J×T)z2?ÏÓ^Ø­ÌkK~œcñ<‚EaóŒ_Ö}ˆ:İ,b ò]]¨DñS6Ùi&Z¢gØ=cÅÙ§äÅ#Uëâb—ÈT2ž Å'?âPPðH6ƒ‚˜UK,)¤×MåóÓöÏhÅÊnOë­Žè6± VKæNëâ@Sª«,ZDO pB¨Š9xЕ.Ç™¯\ep‰ W«{Žq—„³‹:zWöt_³‘á>Pâq{ˆ’Á#qIÑGB´˜ãxVè@Vz¤2š`ÑÑb”©Ùä=6SÒÊ)/„Ò7p`T8®¿,öþøÍðÑŠšæ¼¢3¸€Õ;q®Ø|7`š@ªbXrO–€øMjÇÛ¦äÓÕJŒ,NÀšcéÖ—¿ö%ahhuu0© s^*6Ÿ§æ£Tw“JyÀ¥ºãÎÐçÕx®ô¦z$œ ߤÊÇé“<Ì™/i¾=ŠU—±%¾ˆU©Ó“z&¨{\I¤užç¢ú6Û¾‹U±àN‰¦œvý<•ÎÒêê)¦ýuOÂIt>Bû;~Íàk%E«¸L­wÕN¸Òó§ø$µæƒ€(?ßK¥ã’ß‹…«^PõYÙɵý¸ZÛ‘Sm‡OÛF­»VIX±•.!ʰÂÇL«ÑKÉ™©IÑ— æ^3QP &‰¿>îN­gåþÖš–ûAk7“›SÄÚEžxz0ÿdf‹ôÃeƒ]ƒ·"u•Gx‰ m"!B?ïQ¬“œT¸9Haq|ÎåG´wyF“]s£Îg×|®4c3rª%ˆÄQÈDÜ¢Ò”ªf¤ËâjöØÍ@…QýD=PøØsnsc6uçH^W–v>ÙZŽ,ÇÃÓ¹^¨ÈÞ@¯þ¹¢D{^”×t”BÑNÖÆÀ›)i^ 1¤&åì~**0AuJk ü”ûæaoköŠ©]ÅÁPߟ2m8Î̬HŽzÓ!VwLE‹Ñ.ôRho²OÜN‰"pDá®Ë¡®ñ1tÚc²ßª ±˜7CùPiÚu‡SgUã¨]"z׳‰4—®ò>ýh Pxž?Ë1ØU)ò\·…xT U¸5eˆÙLé¼kW}d9€@¿rÉPO…£ìî­P?2ièe‰ kW&Ô© ”Ró-œ!0 8ã6L¥ }›Ýs¸˜Ü(‚ëŠUN˜ pQ\`ÇuÝÕ톟û˜Ômí.A¥f‚•¾ÍÞ:i D|¼Ì3L"ÊY'È¥û—EêˆÜÍ¿³¶Ä®0*ŽÚsz}†"øÓ,ÁÏwøÖŽ3ŠRDÑw@xÈšæby,ãX Nd´”s"Ìð”B‚*ø+}.!$̘¥œÐîò|RD»ì]™©6%|驲„ ÈT'8X´–n!~ÿ€Sж}’šk‘¤/ãoµa)Å5H<7ØaÖ3S÷¨¡SkÃ^9ïe8³£ÐÅHÙ¡½Ú›<‡UÓUFð}>Nqt7ñ߇õmMÎæ Áe7vï<Ô¬SLì„}æw^€“z]ø èûRD|]\•GØ68ñFÍþÿ‚ãm¦Kª«cÕq,ÜUC¤XZ£ÜEÿ- t”ìáoyÄ/ø–d² /¿ø[¼öü‚ç2•Îòj^ç5ºŒá(3Þ\\-Wî&..÷Eüþ!¯~&D²†EÅé ƒ¿”t“BÌ"3Ùu&tíˆ ˜‚öî–i3êáoîŒpCp$Ÿ£òn„8ê/¡_ú!ËÏäáEu¥îfµ8Ň¾ßô f‚O‰ ±IÀ™Z?,¯ÏÐÛ–\ºÒüá\&Y˜ša„™Ñõ»z!£è(¸©|-3Ÿ¼OK6/Ï@fò¦¯qHã§ôÉ…|íÞ Rº¡òyHú‹ƒ[²RÙÈ•äƒA±è=ãζór©hN—1èûýB¦ Ö34°HµÖÓr%«D±ïK;ôÞ¥‡ÓHƒ×ˆÆÚþ&r"“¬ÏŒ¯y L/:x:H°ööÝ€™#lã.¸‘Böƒ›‡½ô7Ÿ} èõÔlXUxòu]0ŠjU'\Cö,è~UµÀVCUXØÆô„»1ô¯ú×X÷ß:x²ókÞ:pbÒ­Ã~'ë’£÷p£ÌRr²5Çœ¯Séej½Ju©ô¢ŠMËýĂi¶7‰ýksQýosÑ_f¿ì,¡Ñ´ÈÙ×îÉITá©‘B”i…%ÖgGµ”¬Y­' ûý*꣆ñÂRé'€çÀ’ÖEïϽ•pŠÿÅ 0A(éß%1#ލ>sEª¬6ˆjB£GD7ð¡(#ÂÚCØæRøT,ŒC¹)†‚Ä;!®ý”‹…?,ÐË Z_ à›¬ð©—’÷Q AâÓdÝ?D¬ñýœjœ¿]°Äß”çò…n•·p•(¯Ùä-¢ÃÛdgn`¿ñ^¼Lû&éóËJŸ‹0ªŠú΀ˆ(&z•nÖûD3§#&Nî¯÷øP{10·^Ç×Y!Eº=ª0@ë æxó*V¥¨‘w˜ÚNbÕMûÝEó]Æ££f¾WþT”‡cñ/´bÿý|GxЬlã që¯rðÞœ•œÜj!Õ¼UŒ·žÐ±‚=úw7ÔpÿÖë]þlz'ÔÞwˆœB)è~­‡5SϦ ô4Í$£˜ÐÆBWðw4oXLÅK=¼‹b&…âš¹«#¬¶;øu²ª*†Ö:€æ<‰¥ZƆL é2}v¼Õ ÉG®Š%<Ú:œr&K˜ûÅ9µSÂçÏGEW:L­'tFþö¢óíM'’çmÀÑU^ûJ.YæÜù‹£ zÄVº5$6­÷¡£&€w$ðçÏQ ýÚñ^4Ü/q«}hÝ øvpY½<œ~oIs%iŠFw*CqúCÊÞdø¼-†îO3:d~wа¶ya&Z’Âö¾©íR°ÖöÕRÄQaÛWùÿgh) ÂF¤ oE>³HÍ/$*áÑæÄ¬;›9†‚è§Ÿ´ÙÓêÖ_Ê_«ð Y¼F‰¼usO©b¶¯JÑI¦å[æèæ2‡J¾£ˆ{.ùä~ª–@‹ ˜ x‘ßë ÒØÑùõµøøqJ•endstream endobj 1351 0 obj 3992 endobj 1356 0 obj <> stream xœíkod7ñq¾ðFýÒ;UçîõÛ®ÊJ,”²À" AµÊæµQ“L6Éniµ?cÅïå_?Ž}=LBQ%TmcÙ¾>Ÿ÷ñ¼ž=›ø_ø{t9{ò®‡ùÙíl˜ÿÎf¯gÌo™‡?G—óg¸ÍÈ9c½SŠÏNgãlnøÜ°¡äüàröUÇKÖ[£˜ëúÅrè0Bvº9«KçT¯œì.Kg8'ºÕ¸WjÛ¥á7¿Ÿ}v0ûböz.´‡¼”½3.\/-b úÁ"=ϞϞ<1¿»ys2{òåœÍžüÿ÷ìÏ¿†?Ï3ÿÙì³çó/îK%㦗² ônÁz£¹ÐÝÑ‚÷B:i»ë…@Ú¸ìŽÓèM]"é pf&ïDÊðØÜõNs-ìR)7ðù’Ë^(gçÇò¹Ä®{µXªÞZdØÉbÉÝK†lÞjÀ!aƒ”D6†½”aã †^Û¹¶š!;%=‰pMN…àÊGxÝZ+¦=‰¼ãqh p2M+eï¸Ò·2g{Í,]m9€p*òOê)ÿüÞÌ¿î÷²ž9CQ<̈Ì~»Ð=3ƒòâäH® óg1¸OE'W8 —!,žÊá^ãtpItŒ©H#L–< “Kœ„ÛQ¢;ÍÃUZ¿É“äûÃ&wãÀ…ib$»ŸƒŠ8Á†(˜þ+²ld³A´…RA´=1ç ”X. é0ê@äš°:ᥦ ¸SÊrNaªóÎ ¼VѰDë¸Â×ôÆjGÍÁ͈ˆTDAH輜¤å»¨´#¥ 0CoUˆ?ï¹Ø\3ƒ1Y- ¿ƒ‘ZÝù‘öæG´üMšpp¶9—Wiù,Íý3òGi.}œVߤ¹Ëj®~€Áp£_¥åOÓòiš;÷#c~'qê*+XÆäMO$Á$˜û4í¿ˆS Îåô]>+®}§âï ­ÿg} ÿ/Òè$ïª]0õ¢Ü„kï 7ê!Qpݦ‹_/ÆU5ð‚•wóVÜmÍ\Z;Šü/’êlU Ó šôëÓÆåÔrVò·–´¼V› PJ„WT ”@p™Ãæ–+¿!в у_·Ú"_@gȤ“z;„‹–·< 1<˜ØGÀ–#i 1˧ A7Žz> \P»'Á<`uµÅ¥¥ŒH•16ÚõdÌU%j–÷Z²èž?EL´æý’€~ §~ð|¦ón"Ãe<ýéÎx¹[wåeجqíßi\“å­DZˆ —ˆ¡`¨*-À F—âô²•®¬š’I`5ƒ1[€œRÁå-–„œ™¤ 1tã‚ñ$! ‰1 Ï\A b8ž¹C£i¼ØÎ÷§"\0„ƒݯ0òÏ›îo$Mø?OØþ}áC"]㕆彗yŠëÝ„ÆJZ®C^ed=C$/Œ¦f„˜×-ÛsUéhµ|ÜŒuWëÚI2\ɽÆ6Û9U QV†NƬA©Þ¤´!kiÓa‚˜ùÒÔ¾ñ‹=œ%ÈC•p—H¦7»C`(Ó€ì‰T^…ܶH™‰·¥‹ìxˆQƒFRdßméZ%¢‰—ª¬![%éÞU ôìe鮼h4*»1o I.K|ßÇH°ë0S£_•CyKcK"U·ˆ"‘‚rŽ ¨ÓÂÚ#ÉÆ¶Ï‰™sR""Üú!-+krÓÒâx>ªª—ÛA׌ÇÊ7 ß*WÁ9ÁVÐu#×›þàkoZµbŠÛŒRTxmZîòÁ¼¡ÊOD öbu¤IP˜ÊêTS–Îòî¯É¨”*ƒ7 ƒîßx-¾ï´T'†˜Ò çÛ*WÓ&HYÖ'l&–1S±c[@0»¦€´‰M~¸µ,¤0÷ðu!–z_Ÿyk(޹ 1üKu¡ëÊŸT¹k‰HBÊiøO¹DtÛÈÄWU-#Õipª/«FÆíge™am/X‚ŸÒ{ô‚uîçv*Z§^j¬‚¼-ZÁ“ Û¤z…JÒúF)6ÔxÑTjPctÓE9€ØE"ä9".ÖÁØ˜Þ Es’éT†ÿ<·'R*%˸«êuÝ÷ˬ”EÿY&L/Êx°© ÄãÄMq µµû0‡[í§è:x~ƒÇ¤‘±%m;Û®@Ç–e•ÝŠ€[kûÙ†ýp)3¨Úp ¤Ô•~4cRÂäïcûª°±Í†l¿v·¶£ŠQíûˆlIw[‡d›€ù¦Ã„p¬í“›‰éîà¢âa¤ZÕ3¼â9êÚiÿõd¢4‹“öAðž•A˜ª^Q•6²‘B¶iœ‡žæ$7#Îsëý¯TŠèª(áKE:Õï‚!ªÛqÍÎ *i%ïŸö  ¦¬áêš±jí\­ ã`\·ªéºÑc3ü£ôr„úu®R_l¬ýç³óÎ.û6­¾%}ˆÑ)»õm2 ݸ9-»1„¬Ëòø"2HÝ÷_m…¬ùÆ^ð¤;”9¢ªé(ÛSJ„XÛ'kª ï>hÄ^''qt؈Ì.*ȸšÏ{· o«#çî×5«Á¹§Yæw핦Õ,¢'ö¸zLºU]Zþ¸’þÍGýËãš Ø‹‹ά“•Ì“mˆïØIl HÍn}VßUs¥½È"|ÔØ—„惩zÞ•ìò›–Ú:ˆ…TŽêûI ¿QËþ߃}ô,7*%G÷/+Ó¯ÿ=X skÛ£è“áœ]°‚kŒÀª¬ ò†F{%Æ“ºV›€<vîÐUv.k[qBXy£ÿ*„‰Ù©ÿê ÞíÞu–´9~ÒíWÂÊö­µ3%R,;j¥joJûß©h•³Ý?l€+d¼ÊL„`e-­ì¨zñ†äC“w¡¾~L!ì#´âY Êï[iÖ]3±Yą̊E½еý9ê˜ø‹º½LΠÊ~šEƒMoàj•¿ˆµÜ»´RÜs讕ƶSêÝ^€øÌ´u×(jíL>+ðQSVß´ô'Âb…±¸Ê&s÷Ü ð¦î¹-;N‘–U%bLQAÖÊzpƒ‚ö‹oÚ"+(Ø•Š*œääÛ…ba·vdÀð Yǜ۷'0­œçúü¡ŒìSŒ³¥; ޲€„ÍYÃ{ įUl ¼k÷Tˇ¿F÷ƒ±•¯äÊø$œ&Í$ëMum÷’&%üJÔÏr(ËÔuÓüœ·œÊ•é±í¤]W=C0ß:M^.W5_ûäpÐw å°-à­‚P¼ÇwÃÏ‹ß8xölzn µªõŸC´;E›ø7jÏ@ê÷ãdÃ(eö½/ºvÓþ䶘ª…³©¹JÜ‹ÍP…»74CGƪ‡”üü›q×U K$ÒÚÊépZ¯7 Crµù4q“Èlå&Ii+u¿7=ó¯[][kïÞšëòáÅ~@b+Þéf*ý"¥õ||ÒÒlVãë®%‡Azþï„Ô6{ÏÀ0@®Â¼f…˜MsÖ:*ñ»Ê”U¥ëÊTø§_ºáÏ=æÌÉôÐü¾DÐooDœQDZ¿êÒÿ(Î1ó«¾ CލKrϦifHGK¾ß4RÔ| ½ß! UzO¾“oÄwãäÆÁw‚r®¢WéýfŽižúÝ÷æùöAƒ”_+ý#(ß4$õí½¤ Ýú¾ZN¾½l£³{!ü‹¿O¾7"äÛë†v®6içNÈ1ð {â–?½m vt9ž ìƒHññFT[YFQlDÙ ÌÝ~(7$ì^¨hÐúìƒJññFT“{*Fû \||R!€H½ªÈx€dŠ=Vün3z»\};¯åÎ{Ý3£ÀŠüŽUåÈÙÆÉd翘ý ÄøÕendstream endobj 1357 0 obj 3577 endobj 1362 0 obj <> stream xœí[Ûr·Mùq_ò ›·Ý”Âý’JùA‰’(±;fÊ–Ë%ñ^&)Š\Ê–?$ß›nÌh`°KîŠrʉK%q„F÷éÓ ðÍœ31çøgüyx9{òOiùüôvÆç†¿§³73?™?/çOð3§ç+­žœÌ†|å™×s'8ãðâröõâßË•aÞ‡ ¾9ø+ô4¶êÉ™7©³€ÎUßã¥f^i/ëøg¹í"?ç·W©m˜l»˜6h&÷“’t]g1³×¹í¤ß¾Ìm§ùé6½}àÎ3¹§~ißí¢ßvôûf'ýZÉö•²tÝ.äËÎÛïvR[fìžR’¾ÛÅ|[Uœí+eéº]ÈïóÓùTÈÅQ~zß~¿Ó„fnß5¾e.vÄÏžŽOû®;¹ÝI¯÷{ Búž7›ô@1Ö1±¯Hßb§Y—gúÆ&÷Õé[´t=µk®vÒ¡2Lï r´ïyÇ3/k“×y{¼“è"0½¯^I߇Š^Þ¾î€Ên¢sÅì¾Z'}*zÁã],W{ÇöT0éúP!3… ¶ÜÆk+{âz7×Ö@û0ᯣ¬}Ÿ¬ÁB3—UïÁ¥ŒÑDk—&+KN¢‰®&¥dÂVüÄ8±„è¿ÌZø/xíJiÅ„Ò`^I× ü¸^rècŒD!ò#ùöjxôŽ{ÃJàzZÂco€ËåJCD0VÑÖ5Jã™R*ÍÃfÍ⣥`A ®ÇQwè+eðöR³àÖƒÆ÷?b)5} £~¿\qæ8÷V9Ns‘n‡¥ÛY‘à(z<¼·Ê[uÌéBRvºÌACU°.Ü¢Žâ×´õ5Šh˜är!ò\²Œåá½DŸ-WTŵ_<£0` aÁ°»dÒøÅ<2`´q±?ª@A0Öõ 5I'06òùÁØËUO)c%<]ß%Ž ù4t3q}Ú0gp!QF.þFÔ>H­œÎRë°ø·–¢©‚Ó¾†‰** hcÜÂv[è+n`‹@pi÷£eÅoop ’¢Ú¨?HÝŠ8¨«•'†¹Âh~á&/üª8Ç0­åŠzÌMn$“çy¨Ëáã¸Z­LYWà„j`|öYÔ¼vñCêeÆ/KÀìÆuãpQ’ã,ê½@{깘«àrÈ~î.?•ð\pù.·*XßKMò–‹lßtâý·M¨!ÿmnx´Ú1¶ò$7¾í$Ÿe’'0΋ƒ‡Óæ+çÆ!à¡eOÐt“ 9f©é0=ܹVÖ¦ÀnŽÒÛ¢†“ÉŒwSI×ãCt|ż n~ðéìà·¿ìÐ#ïPÒ4 â—õ¦U=×iZÖM']¨2Vâ”ìí Ü|—R'çJppK‰NíbøºrÀ l·Õ-W!fZˆÂFØø«ütއkÄ”rãñ‚•á1‚J¢C0çÔÖwÉ `—Š5˜å¿ÆÐ!!à RFzÀµ"•"6~ŠóyË –÷5ÞcŠ*S ‚W¸¿¿ˆ¬_@¢ 2o@kËcЮ>8ÁVÀi úÏzó’u¥±¤žÆ.ŒÚGUÌO¬¤0¤QXÍ>ѽBá0æþóÝÒ2á¸t$ðyásBR2Væ?mž¢$“([˧(dè ¥R5ÙK­£V„AY"ŒÛ!$óA¤*#ݤ]s”¾ÂpWo@Ü÷0¶Ž¼¶#@´aéM K=*ævÑ2"kû¸m]À ®d’ÁÏ—<Õ)Ñ1|Œ&`x”–%à$–p‘–lø€HCf#ZžX<ئ-^ 9жÑFVàÞ©I4•—¨©ø4„¿ëÂÖíÜS…´@Ä7>ŽS×쎸8ö2š Ñ’Òö<¬žì!Ù·mþ<°Nlϵùa [[æ¼ Á-ªN0 „½`Ëu{ȶ)&±¬$ ¡‡¸C52ïD8Û}|B!–!W¹ ׃6|>;˜}1{=â l?—G꣠jðèéóÙ“çŸÍ×7wdz'_ÍÅìÉ_🧟ÿ~<ÿãüW³gÏç_l<Ú"pP@…Jâ»$q)2Ÿ§¦“)×È#3EÙV7º%¥4㮞ó4g!æ˜Å§%»$»2À„‰ÓJÉ4XÔ¦ ,ÖBLäcÜwðÐѰ\¦˜¿ Vn;‚Ç/è#?¨Ih:|ûn0g3XF›7*)/Ò_‹y›«p—L@Ü=Q9¦tƯ*|ŒHU§é>Zw=çµñ50=Maåx+Úèi ^6LlP­Tkl•©ë?l¼·ò§8–-dÙNwNB6¸:š2³qìîꔟ.£¤m¹¸Nû¤qÿz‘¥D,V1 St:=z»æL µ8Xzf®¢ÁÆMtš:s)v·°ž:H‘Ò-^å÷¯»¶}†¶gYâ1hïrÜ" î]ª<èfò&o ¾iC\–ÞP¼êÉ:-¯ ó"jHεݛ7¦Íú(×ÕâT޼Pš”¦Š‡q#"l(Ø^l[⃊lS sŽŽ4aqÒ>#kuZ¸q3«Þ‡øµàšúOŽ”9,ŠHȪ&š‹72çÑ}Ç1âc­çŒ5ȪÚp¦#¨:ûâ•}£CÚ Ä笰Ëã§W£C ¥ÞÏ3]#°v~ñ%Ú´eA8‚ׄ–€x7±ÅXŠXgš1†q/ý½êF‰£Áé¬×ÓÌ8šŸJyÓ¶Å"ÝÀÅbÛT§„009î¦ ¸iš%A«:f&¦[%!ÒµÁ™w>ꡨ˜ ëQ£‡Aj¦s=~_(GÃBÍv¡„¥}6± ´+ ÆÀ÷•Ê%dHÅ×®;KÑüº;ì¤ÀÝ0¨{݈Ÿ±@ìU>Xͱ\-»È^»Úk'ãõ.Ô~Èx¯]<Ʀ’gz[c’ˆ»Ò)Üv–`¸À¢ûO²Ã5NA—«—ïê]ªJå}¸ª`ÍØ[ÖMirú~MRÛW¥µŽ¾ÑÍù¦b\K#Ö"U–qÀêç SÎo*¬Ýëlõ^l\tÈÄ-õ‚M×6ªû6=âë†{2p$À”øµDG(²û¶ÃlKÚ»¾g’»Á~‚UHÁ£/”U4®PÕï§uÿ­¾€ñNI:xSABê,‰F‹†A% !Í'Á"‡cdƒ¦:›>kë.BS-rÜ{CU¡IÎcY â16éû”õjš¨8»!§Ø³49 þiÜ!•¨JÈÛ‚~sZ~4°£Ð­Fö S¥÷-.¤è^sÛárŒ„‘½ñÄYó€ 8_)Ëd&»:õ„ ÉQxLà!ö `×ÏŠùøýo–)ïwà0!È=B zU}ý÷(“R6,þ±„ej 4è5dz«gø(lpž …Ö@imA ¯ãõ‰ð¿X̱{­Ó–‘¤ÃŸï;`!p€‰…‰ˆ Ã} <Õ—JI‚‘ˆ8¹±‚wÝ€HŒ ¡‚rôÛÉY\¿¬K+@à}²IMÉ%-CEHS‰YUqøe4cÝØ”yoB­Tdßt“ßã¹&aó¤ÒxÜM&a¼)N„$bõsë´­‹2qtM¿»×u~(J~6‚‚ˆõä'/âÖŸRÙå¤S¥ÆéUU3œËD‡4ý‚ˆ0=5˜0;Œ(Š‘5CL(J¾nE>K¥Y»±L2ØEè\ëÈ› ÈõͶX)®+MíuÜœ\{%gQé\ÑæôN=–KC­ëï¯q;a` \FBR²rm‚S û8ÜkÃ¥Q'ç€ìùzÑŸ–Àõ@ù!Eu¬ªÜ•å«MäºÓ:Qö‡ÞgÚä[äÿµÛ2\Ž÷kf…u‹/èí ÝdV½¡·Þ'˼$ß ZPjñûÜøªÓå¶ê"К$BuBÖ\¦©îK}2JœákzÁ&f·r”®ºt>^Ðw—ô¼öü±È‘u^ÄΓ–ÚžqǦoÆÏúbç‚ÁëF“¤†0ÙZ5ù&F ¨eM®BõfzHÁe´[šú¼´\ånëI·M……ªHrKUƒ×¯”®my•–“1ö묲¢ré¬÷ëgŪ¾í¸VéÛùÅ r{¬ô-mm¦XLVG’Æú'ÞàËþù^ˆTŒ¼üvÎi#tݹ=†.èS#R‹>ø6E'ô‘\¥×áGþ‚<ÿwÈ“ ;^M}oÃþᇶòçm°Ãw†l[gk²]’Ç}$ƒÅÁìOa¯ã*?d¨t7÷?*ÇåÔäïg/7YƒÇºeB„ô»ªåWpLIö­ÊÇDê‹ÙÚLwsendstream endobj 1363 0 obj 3337 endobj 1368 0 obj <> stream xœí[ÙŽ\·ò8_ÑÝAšá¾ä-qìXƒ8ö†4Kk€žE³HòøƒSÅË¥x/ïL·4‰å¨!¢¸‹dÕ9Uäí7 ÎÄ‚ãŸôïÉåÑï¿“–/6wG|ñø»9zs$b—Eúçärñ§cìæô"°`¥Õ‹ãó£A€X8¹p‚3•—GÿZ~¹ÒÌHìòýjm˜÷!¨åËX ÜèååJ@I‡å ‚\/·+b‘by¶Z f­ößÇ…9mæäÌ›4mLz.Öfý0÷5Ìí•YJé>–@Lˆ%íEjźûÕÚ*ɼԠcnÞ–æ³Rw[JUà#Xº*­¥î¼”.:’OKI–Ö?€ZV0a]ì‘·ÍUg¹pUÚ^æªËÚiX¢RË»iÿë\u› ÷¥åª"t[ÚÎ÷»¤½SUÕªýe[G®­ðpŠK‘«déîsJåšå\­Ð8”æÌÆp|ZÎGܵý›ÉoR%­³¨µTØÒv´¹Ø¼)uc£ÁÖzc£i il4ØZw*äjbq¿ˆÕ” ëÑlèa¢x-ŸÛD°—‘I×fòž]dC2¢Ò¼‰`§µøBÜùx;ùo€ж²;xì»íÄ!&@êZ@„ªÍ´í4Wl¡1Æ´c\ý¶ð(F 2|stüÛÙg²l°ÌÉ0ƒ ¬ñ { Ò¾Á^ìtߎ£úý4Ñê¬ ËÓ%tÔ< ÓÁR‡³;][!ù2ãÿÞRË",‡Hþ±,¶V3HVoL´Á°}-qé!,ÿ¼ZC‚U&e£aØWiæ”[~Aú^×¾W%)ùM)mjóC©¼-‰Jª‹šÓtÅß­3&hvÅ º+R3e‚Ï”ó*ë8—Úƒˆ"m˜C’¶\+’A¡—®rµV¬XÄÉHâUôAu•Œ·|ÝdpyÔÊ :Sd•›IÑ»¬¬ 6/Á£—µªuøMéyS+ÉL·q¿Mà·^qHk#¾ÄS¦ôõ©B»aÊ£ƒëIÎ˪T ª‚b‚Œ(%X¿ Ž‹F™/ˆ ÙL=úDMdÂLJ€Èr,Þåé­òiTÜIRË «„¤6í0ÄÓ±»v}_ÅJüÚ]ý¶*ÕœYÜðÖwɼtùÍIÉ ÑB—'uÓ®«&µëØsbó=²)YÙµ‰ëdùQ§i‡ûÉÕnÛ%N¤±ªkè¬1ŽÛÒâZëI¨´«ªÄ °Ò/_ÕÚöþ"³VTµæÀŠÜhñV YFí&‹‚S~_QÄâ«Ä`0‚68­÷./+d¶¶&µd&¦êãmÇa{ùrWmÀóœ Maã¤û»ß?Ö‹ÞåA pÉ  ÌS7F@1FÃî sRB¢Ê»W¥î¼”*×og[¹sŠ_ã›m½-%[Z눦¼'QYÖT2oÇžvZSàã¾Æ]Ê©DÌœaaÀ å°U z ¸a„ J`E0MÐÔtd÷ϳ!ÆÁx,=dBu)^ÕÚîÅaÔFÒ¾_ èêþ@¾¾G`;¤£Ê^çàbžéb;€Ò‹ kß–Yßï°COÏ“íZn…·.>¤=Cý83Üн ÐtšT‰veMÐgíCíåv…åH@Zeú!ƒOí¦Ë;«]«vxzÊ1¥%•-Ì[²SDe¢\¤éM òëü2[šØ½ãîË@5Kߤ¢-KÉ´7|»²š Ô>±ÜSgÊ´ Í˜!ÉÃM^ Ç`A~ØëhÞ2x™¥"º£¥Í,—%I;Áá‰[FH¿¦VJܶlôq!ÅéÕª´Å°[çÅÁZ¯“J1Ayºë”gi+u˜Zjì:'>U&ùJø™³êFzõXv`m=4 8yVHc|³Šu¯JiœëbÝܯyòù^Эå”Ý»†­ÑÜ`wNž¼•„ÿèå×$CK«ÐÀb©h¹œ…‰èA‹rædÞjþ7=D<¡07~ÖSÀLHƒZ*€‰Å†©ÐQ0–S`JÎ5n—4(¯Ö·IÍ¢ß×tQ¾4mrÓI^ÆÛ(¤™rÇdIJléölÇ, ’Õå ø êY¦@ý†‡“4¥{„ òNöå§“j5œ”›»‡]sË’4`]Oð«•P,¯)»‘~·‚È–¦f,à´™,wHµh;Í¥…KsY¥FsAzÄçFµ ÜÙD'ˆWs²™ö¡;m]WJ ƉÁå~e€ÇûÂWÈÞ®š Fßû©GÄt~'ï•x$Þ´ˆŸ‘à ½v¹o›Ø`é:‰Iƪ$x|Ùu€OÔÜGÏeÒ­YÂqêá™õ6=ܺêUNóÂQøÖCR"W¸¡‘"%l¾SЄɌ „*ÑW'¡ŠeöS Vúµö3 V”‡¹Ò ë¶“ÿnFáH}:¨Ég“ïŽ(c˽îN©¤L+ñ1©$º—Òώļ k7D³ŠqH=öGÈIŠGHC›­a6êàD­Ú/AÃÛÚùÄ÷K„Ù€$Îêý<\Y‹rË=5bßw‘a¬ˆ{!m`2O_}Fè±q£s¡IVH8òWà˜wOkø5Ñܨ’b>D;Ÿ¼çì„{ãÅ`ÍßÊ)JºÜÎÖËÞí[æì`T{;'bwM Ú—0"©xC`ç®BG$O}fŠmÒÁŽGM£‘À©• õ›Mõî~°Ajó±Û@/§w¿éÑc 7;Cn=H¸o(Þ?øy>ÀÀÇÙéÂÇ/%90QzÊn%„I·¹yԦ܅Ë#ÆJÉÖ ÜÈöÓ [à~dûzt¯Œuw¥®¾ÝïêÃpó¿=K‡¦ò«½é¾*öË7ž£[É9b¹Ý“œÑŒ{úVw–œÓôS¹¥¾* ê’Ù üüõxpùºÀ`É›÷%‚÷Šzñ/ÃU©Þäwý~ Mçïµs|4…@'#kÝ“äcòi!ùD»ó$ÏÐŽI~<ìDò1}ïìÒuº&0x—Y(ºÿ¥À6)æ}GT"îQþ:ʶ' l›‚ÿßP|ûìR=m ŒímB›L7 H§?%†ºüôàSfxáãþÀð†?0üá#ÃÓ·€Íhþ@óó4/d(Oü»Òüeç€ñO±Ú'þÛQ`€­—ûÑ<—{=ûK]ôÇ<ûKŒ¬ŸéÙ_rÁD Ÿlý ÍM)®=å{DvüVÒSe»ˆÝ—f‚©í×UÓ÷çîwZøÝw°‘CG¡î…ò{†Â3íùR Juó‘6ÛGÞQ¾3d)ùqÏ“Gÿ Ô³l_µOçÔ<(''‹¾hÉD˜ørñ߇ Úï·vúV6û&Ú7û¸¯&aO0²ˆàâÏ8foÁ‡3pËŸë ɲ!TYþ‘Pø‹ú…À7¸JÏÐö¿Š `…Æ'ô7³ü;4È’lÿ罤GØñ‚/GΧlBŠä{aâÓ„“ûaÃôκý4ø‰âç_Òóøþ‘IŽA>82y¦ôž;÷B“0ûc…>»ŽÝ¨7ì…ÓH\2à‚„ÿf\˜<êKX߯#>qŸQ|¢1_ã{¾4Ôp£~Ó¹‡¸…%O#` `p ðŒfDY—­ÞÀs%Šûòøèðç?_þúendstream endobj 1369 0 obj 2794 endobj 1379 0 obj <> stream xœí[[o\7úè_1O‹™F=ºKyÚ¦I·-vÑlê>%Eáø– vœÆÎíì^ꉤt4ã±^·(Š ”%‘É÷çÅ äbHÿäÿžï}þX¹aqz¹7,þ ÿžîý¼'Ç%‹üŸÃóÅýýq™\Drf±²7) ¯„—1.¼Ä3ç{O–û«µ*Z—ÏWk+BˆQ/_¬øÜZ%——° HËåŸ Ö,_ÓÚ+ZË>» ¯@ƒóB¿<^­¥pÎJ—¤eÁÁ$Õ0|FÒ3RÆ>KÇqQ–߯¤ˆZfùïÕZ ­Ê}ŒËGéäZXøq߬ÖF€5×:ÍG)mž·qå¾IzHG<¦áå ÔÛ Ô4rƒóü#P¥mZ᳑ôàGËh…òeÛ|1Ó€ô§,xÍpk½¢½Ž²V³áÊ^yƒÓi^ó“<ÇÙ¢Δí#mºéûßT ý#À 3Ä ÒDaÂãîA¯jh%_jÇמ§DeæVaÐ:K‡U¨ÊG•-oY°ç¥ÊvuZ*‚“y ¬]~èž–ù…ë†W3À&éQF¿•ËÒÐGÙyZë¾\×sšOn ^¤ái‡Ç+#¬ÒÞ,¿ÄÑ£àESB[›œ¹NÞ f±Žþüj\ƒJjá ì»Õz~ÄÓZ°À§-Á’ÂF ‡:,гç@Ã܇MȃU”JéÈñg›òXi#¼±Ë÷éŒ.Ô,ÇFm7eœæ-ÎÒ}àö!l e”°&¦IXìþª'œ£DÇ*èŽ+Ȏױ |*!@ònå„lºâG)+ŽO(j)æß¤ X!!ª»¬G’¡=Ke9þ­‡¼#K iÊNó¼ÚÙ™EQ4' Z’B/`÷0)þ‘˜/nF»Œ˜sCN±6ÃçguȨèêóŒx€ó*W>šõ¥>; ‚òKÇEUO”ÖBrÌ_l(7NÌ^,&6©Ï¬_Ë*ÿÌnÝä}òB2ýç-PF ,²ƒ…W§ÄˆÁä’YÀ²42@NQöŽÞàì!Ê^£ìjÁnydF‘GÓ‰®!+Œn@V ý mÝÈŠ’)~"²2(xo²¢” Õnd%xõwâ*jˆbкá*S†R7ã*Ja ’7r•)›\e,›Ó²€Ö)nÊor®ÒÂ…’ªØôÃô‘Ò¨ i™ ÙfJV†Y¤Ïrt:aJ¦ "õ3tûÙuĈ™u¾A’bºÿ©J²»ƒ+ìBU^ܪ2yÉ2V¾ïW´YunÈ ü`[k ‡‰¬¿=‡KËÄ;q¸)¨3‡3¬Á©òG]Òô¬¶Á9£njjþbn¿+æfh¸!s;ÆÙs” ì2·3”ý„£ç8{„2b‚—ev'†Øî& O£ïÀðdpÂzõ‰Þ …Œ;¼!þÍž C[‚—è®7$xƒÆØÍOÆ ä7¼´«Ûü5n ëG¾yú¦ÇѾ`nú–”¨š®Þ¾,í?0±*…£ß’ ˜~`¬oz{~6!×íÄÏd„¸æ¾™ NÌé;½åÇžpÌ– Æ1Ë2ôÙAVª_0{Öi‹Ì)r=du*­{ß§uÓ¾&ño=[¨Òi—­Í˜B¦p9|ºåŒ-Åǽ(4©¨÷Ø#7W³»=öÔDáNO<Øٕšˆ‚Ô_Dá×# ÊWDaMÎÐrjamYT1sPU=BwU·) )½^þÀ:ZÀ¾ú¬õüe¥Jà8¿üŠJf•§Ñݳ’N+ƒÚ%¤ýkoÿïO¦#åë1·_÷ÀÈ[±¯V 4D£¸³hØå6p5ZxçC µ)+Ô‡¶½uÍ!FÀº–™(´ÁSpxÖ¥C,Å=ïf~æ±­*òˇòp¡êY k¾1%çvåºÎ‡šÏ·ÝW˜îÏOõϹc½®[dÔjVªš"¾áéçsÂVÝé$ßÉ)¸ÉDgTÝŠŽûÍ'ØØ4Y¡*H×>5|)kàyŽ¥}6O[1{¼íÝ·®ó4”êïXÕyEx8¾ ™Øïœ@¦÷å€Âµ``PœT×T}t­ åБç ^ûeÿ꺮 ‹ ®7È…TZ±·ØX)asÄžÉQöe'̓yš8ãÅ tV“¦_±éy/F/ðegÕ§Í«|í½¶gK?¬—žíWôáw,-½í&.¦¢EéX=v÷'tÕPO ¦L·|ºD>Dó½kšé4zÕ˜>Éž®¸u•†]B$‚{¹Qãrî-HŽN«ñwë8}„Ó÷`z¯ÈåŒ7¤‡=Öï¿Ã…Ç Š¦c¯ Â…¬Ú{ÖäÍÐm˜ihbÌj`á»ÒÞgÅÞ3½—EDÛÑEýÝ D÷ò­íR‘ÂU±ˆpàæs¡ $ÎišSzsƒû¤ÓA8/2´Øt9Ò;¼Yr¾SÞÑÏ©•)ðK´„ëKå‡l‰”¤"S˜úÞéC;³IY=6Zå, ¾ÀÑiv›¿iBØ؃r Kl¯Šµƒž=Ý›Ú2„[nfеÙ*!nbŠ ršÒáA­·¿ÁI}Š ½¨àjçƒ9 |ÀÀÁÈ12ý½”’Ì"_£/Þ4þé%ý$£“Ñ9>V¶ÎUÌa#€@GöÍëØAusÏÛN•9ìd´:Ã耳¢E$«OªÁ@g]Z“=Ù11.h÷ËÚ•»0žné.¯·Þ(Îof7ò¼"Hl[(ÉׇÄx)˜ûú¦ZÊ~[³,8à”ë)x/ÙÓ:«g‡!Dp«ÓQ™,g •uxÏnq1SAêçU⬺óˆj¸s5Kç Ý­ó ‚è§:؉4ñïN«½30X‚y6?$åôñèõÆøR ^ΪÁ¬öi]¥Šu¢›z€žXŘ4’¢GžƒÆxIöGÇÍÕAöCù3”jÄËň/;1}EºìLSP\4¨õ)ñÙ®‹ÍÓÈufC'%qb&t¶ÝÊ-Mìpœ¸– U2‚Væ6±²*?5¬lS0ÍÅAÔÐ2ºvv-Vú)ø9á%»h‘}lò\íTVù%U~ZyÐq;EF? žm ÙÓæ¬pùç÷h=Û#ë2xtŒHÆšP Â#lÊ,Ú§~Ñ+D÷Qxÿé$—×±mHÿ«† íÕn˜‹GKUPO'e݇Î(£GMjÙˆr>hd5Y Öö5Îöþ~(?—æËRñç¾¢>¤}„^›Š.âô½§–$ÕͳÉOQ7ïK°Yl—aÛX=:TThêý겪fB¿ª»vqȳE,Qù§l± |ÄÑëŽýú™![fµí¹[ ò WRAíXç!eî™ë:Œ´©V#I1ýu™ÛÇïö©~dP,(¢Ç¸ê®t| SËÏyF¥å/2¿ã´ªþ?2ª¯cdžQuî-~ó´ú‡~tûSgÔúÑíæiµzp//¿lŠ-ÎØøôúÓ$Xæl ®K¶9â²ÎKÜU}²Œ÷ôº×ùñ‰¡ðÖ/ÉŽM¢Á–S{'”vô?§Y9þ¡P£lë_½«ô‡ÑnáD²Mþ3‰©àèlP˜Ô=Üßûüó?)jÌ@endstream endobj 1380 0 obj 3121 endobj 1387 0 obj <> stream xœÍ\ëo·/òQÅý»Â·æû¤ê6·I‘‡ŠH‚–%E°t’e)©Ðöï ŸC.W'§NP²Ö$w8g~3œõë›øŠáŸôûèâàñW°Õé›¶ú~N^ð0d•~]¬žâ0«V~òFµ:<9ˆøÊŠ•ålbÐxqðíúo›-›,cB¹µØlõäœ÷rýt£&-”7ëËÐè™Vëçµÿf³U0"¿?üs`‰Ó¹„š¤önuøÙÁáïçxQ)_ÖV˜„OÆhnp!, YŸmP×ZðõhT~’ÖáP¡Õ³ÂÐ2€Ð"ç0V‹R­O2ï´ÿûåÄ×Gu~Ò½ÛH6 ÉøúÇ™¸‘Ð}\G^’„Âô®R:ÅE‰ÉÂ[·”~çš¾öÞ†O^8íó\†¾Œo9‹²RMÖ¤‘’3 Å×%³œ¾”¥æU¢ì ©›Úx‰CÍdAìu*òÒɆûÉI+³ ¹–tªëa+j+8<$€ê#¤™@oØêð%(äeH]à£Úý¾‘õ›œ´vB¬' ?y¥µEÚ /òÕ–[˜„‰8É‹zß6*61>io<ÝäUœY p^™¸Kû¡eâÇ+E'¸*K»êèP‹/+ýÿQK+{góÃ=b 0;;-AGßnk@áõ$™¦ÆZòÁf+¹˜¸÷DXi­F:Jàªp“LPgî`»e5Aå Ú+п¬~ÿlÌN¦à1/’ ºuçÍ. %Pé†W1ÆOk?Ù› ­È¡6ÍrØät2à^LÂ1¾2(T­ø-,ÏI œŠòô"<¡q¼ OÊq`#·Á)4RLN¨õ¶tc#S“r¸ÌÜxTÞy^Ú®Ò@/Ö–Ƴ2pWÚN½ç¥í¸<=‚`t<اHÐZÂömnºÉ=]h:Ï”jlªÂÁL‚;‡¨=ŸDrˆ÷ÄYÍ=šØ°tjm†­n³õ^O°Ãè_$8Õt¢q¬2.{P kžM|K EÈOä¥úøúup ö‰Z¢¤ÇÔ‰Ž9µd,U+a[›±h°­™xÜÎ;X»XÐxrª« ¹m2RÕºsÞ¡ýæ äs"¬›ŒS¼X<‰ilçÔ®ôÙœ,¡çÕÞÜ è6Öï¶X©e¿‹µšróCy«1™Q έJ€ÉN=/Y%JϹ‰KAI4<תø¤‹m#|çÉŒÜ/¥ã*왣¯Zpˆ‰féw½t–N€ò2|RÊ p‚”øžR"¼‹èæŒØÉp…K ; '¡yëÓÆgV¯‚OÒž ^XŠÙ.[jFMLÊãÂÇ4³N‹Áu%í²ÜÇFߊ´,‡ãö }»ešSÁ‘Eœ÷.=Ð:müå6iÆ–'DtÎ ¤*x8‚“¸«šÐ‰‹B®Ÿ•—v Uúh»TÝíEA³ƒ¬yíOOIöwÐJBŒGHŒqkh- úmåçbËp==¢Ø>:<øòàõJÆH øt+î:ä•ÖιÃí鳃ÇÏ>_Ý\ß<þfÅŠ=ýâðëÙŸV¿9øèÙêËåÀ­5ýÙOqð4°[àڟ諈‰>wÚ¢z܈•¨æ«ªG·Ä]óp4ÀwJÙ¼V8³7¬ Ç•he0*+äØ ÃÜj‹²ëCôšÂÞI›Ú/`÷”ÒÐ^W •™³ À,fèüˆ¶C0&-nìs€1¬›ZíÀN2Uaf‘c>Á10ãse €ébdeœølÿËnr*c²Ì`}0=»fçb0¢¨Â9ÏŒCg»¢RQ cë€{—l8…Ï[iÀŒsæ ?‚å°þÓhŽ1Ürna?ÎÀ5YÕã—hæÒy±zlÛ^¥ðzp:ƃjè–Å‘ÁšNÇ Í„\ÁÖÈd“îfQªo=VÏÂ-%8Á§ol€ƒø™¤®i<ûâÁè>¯Ý]Ji¤ÆmÁ^–¨§FB7%à¸ê‰.þ©ñÈeé>-mÿ(O»Ò{[Úλ'臣5Ø€õ¾‰|—°4Å9–eRätÕåwº­|°È$ˆð$3ÀÂXZÿ6F”šôÖˆñ‰·Ž¿W‚Â7óXp—NÓx—F•¾ÊºÅLS‰/óðílx4¨ÉœD5¿ˆ°è‰C«XïHMׄb•2- Ü á7-^®ÿÕp¥*Ž»)£ï{y\ãöçÝ~´_ÏyÇ™Š9ëï#ô¨$ó¶*„Knå- jUeR3oº7ðéL+XÐ/ÑëF¥R2 ¡EKwœV êRó ¸ï@*¿€1ÚRýøOVÔ}9)ÔÏʉøšù,X7-mŸÑ íôÔþ³ýÐÌ Â&ÁÏÍ*F"Ó(2&)&e„ãK™A !jiÇ^Éy°É,y®êhè/Ïj¸Æ©è= &;ð¡‹·hŒ/ r Aûh’œÄ{]àRR5ÒPÆ®»Änh|9ÂÀã\@ËpDFH0ô®ËÊ.»$ @DR,ªXwÞjv°5ÏÄê b1a,òT ½‹Xìþqíª. “j×ÞŒìÄb|'<¯Ôupë>¼Á w,I‰){õëHRÂTÆ $Ù[6bT êgISBP`Ø;—¦µò×ÒKéðÞ†¬àhŽ“~|ÁŠ7ŠR”Ö¸mÒ–mH˜2[ûĬÀÛ9*æ²ÁÅG§Çó. w™ý:2UÒ¶2-÷E¸W™]B£¾ðpÑÚ#weE¸±,“õ¡×=|ÂÞKºe……ˆÏ Ÿ'mSA8ðP– °TÜ0LÒ–çÔÑædçeã$¶ ñpE›0 ¹È wpw5E*JÞx¼˜µ0¾Ýå‹ó…ÔI~ÌòàóS²Ó„d”ĤN‚Ê: 5.©&ø"sý³9H™·æn±½Ðș͚:k2íy $D’t$]ö¢?åãrþ§Kú§âá}Çñ,QÑ]¾T¶Hzˆô•{ T–ƒ"Ú¯#;/ ðÕ z•<Á7„éÅDM×eÀêbê"¤ÖK%Š"ßl0îc•3vI{³zaî!à f&UY›Ýóg&Þ+§}&µÅxm·€¼ÙRænIù€Aá­hPŸ ÎEÐ-‘ò3xœeZÁ#œ @ÁÂ¥¾8[1N‰’l QãûªQr‚–[?ŸtNÐÖÄxØ¡û 2.Û57eC5­Ûžž¸Û˜iÌ ^¬fj‰SåÎCõbG„! BS÷Ò„@/0²w%uèøì톭Yàt-\Ÿµ™Ìºî¸UêÃ𵿒çguÿžÖ&Ü< [¸Ð®F®^Òˆ ûÉ[WY:ÍeÄU½·#3ÌáOÕê Š‚MnÒ5óÔñ(½Ÿ]]²¿Y5?úžˆ2§¬IxJNx’fŸ±±E/!-ï…ÆQÃcÃg5Jì)'è™ÏN a£Y]ö¿”Äàð/èôÅ3ëq¥as=Gän—sÑ뀊Þ¾>Hp‰j@dvéI¼vÎ ] R®5aõ$¥'µ&jb-ü}JÜrR 4JNÕIjaÒ(Ý÷¤ô~[Ú¾[—Ç:Éi©/òÓÒ÷ïÜTЉèô[ذù¥<( äC'ªÜ«–~Eîýn“»¿§Á_ÍV‘Ÿ–§ºò'5•{¿Pß/½Ÿ”Þ÷»uâÓûƒláû”³–§‹wÃÓçäébÌS—N®ì½z7ìýåì½³·ñXÌØ 4:ãûjÓVL“³lUsÖ™*c2FZ¯Û4¡Ð¯8—®»~,7á–ÎK¬Ý !•rç0G_o´€[âû&@^Rå27§„ƒ”3 ~‹»qÍòb<8z·žøËt™®Éë—)9i›’¤“4“i°Þ}È7 ‹í€S(–ë.öW—„«ð<šcÖ†¸F.DËe_9-³nŠ££Ðø"ØÛWÙ1¨+ hyVÌÛ9`RÍØÉƒ_xXa™‚ óaÕVA *Çü¹œÀ°È@pµ:îbÿ¬€$Ô.Ì1Ù©a+FõŠMXˆçZZE•oɇ‡s]ʯ‰ÀÚà:"A0´+Øôwæ¹ýU›Ð—v’‹¸¦/eï€Ë,à]ªd—–n ¥'ÞÔ·Ï‹¸jé>­áZ¨³¨„ÆŸp kæ[ –7åñ¬Xm”[‘Ø8W7Îj²†Ìê!¸‚-1á" –̺ž-] I£óU™q®-Þ•Y`T¬?… ™ŽY) ÆÑo%.±%©àfý‡ÀÒ|Úø+2š>^-ÇYãîa‘‹Ç+R¤òc˜Š¾r­•j}¸qh©2¦Ž|¼(/ŠÎã;Hѳ¨Ïó‹8° †‰yÉòøò‹húüž h÷ ––ò‡ÕÎıö]||Š %†{ËIéâ£\¹¦Þ² 2•_Ïê†sÉ,ú¡¶Â¬M¹yÎ29÷³·£Zs~3ËLœfrÝHnw\V<ªv;εjÙ9K —¼`÷ŠäMü>S¥ÎMîr!ž£Œk/¢Ëõ\w÷I+ÕaaIF‘¶®(Ö‹a®œ'·´08—¨·…»¥¤^,ø½ùÇF1ç»ú¾ä‰›¾J¡œG1Hs´œ¥¸lõ‘WCÏHŽ IŒápûI ~l$ØB ~ $os“Ä—ÒZ‹‡™!ˆg&Ðη:ù€&Ù¸ñ½U}ã…†J³|a'•œÐQ<«ÚÿEap[uàãò)â¼î>}Õ$%FÌÉ0‘sxÑ„âw™Œõ '³p …Aì¼éŽ\/å®o™ÖóƒO…ÿš×Ÿ7‚ãËžs6ßmª®ì5)ZŽß!þÀ~€t°˜¯Ë— 76©“CJJs/~:wÿØ.-:KNwYÑÃ-¼ë6»?îãx€Àòù'É“I)'ž,iAXCó•DW^¬DÚú¶à÷­ z¨Z°x)=—\pùK­T1ÒÁ…~ÅØ¤¸Z¸)ì2útãæ7Œ]2X©q^î[nA8ÁÚ>Ð _zÙ&0ð¦cØýr3ŠÅw ½é8þPÐÜU†êpúeV‹åƒ‹…¶`0„ÇO(“½ 3Vô3.ðÏ@.Wo§ ¶‚®ÆÈÑ{¯$ˆ|‡¡üóF”ã˜X‰ÕN>TÒã]»/î zA@ 9åYÌn'-v›t!¤/™ÆQÖØ¤äר,P ¢Ñ Fx¨½V¯ä‰enýµáR¦$›¨6•(rÛÚŽCšö{Íœ"›/Þ†Ö™¬X¸q%権W¼"£|›rÙ˜–å›q@tÚ˜‹VEqÒüÉ‘jÒDÊ3ïÒäÿ‰H–~¶y aB¶¤Ú}^Þ3õ½âÂKAÑ—ÿ´Ä1Ïendstream endobj 1388 0 obj 4112 endobj 1394 0 obj <> stream xœÕZmoÉŽ.ßöWL>e'ʶû½§%t`›sd {$§(BcнæÅ’’ß›ê™é®êžÞµ ¸mõkuU=OUõømÙhxøoü}y6Ûz"-oNÞÏxóþÌÞÎD?¥^ž5÷–ý4Ñxæ­´ºYφ Dã$sÂûÆ Î8ŒœÍþ>Ú æ¥ïä|Õ. ë:ïÕü¼oznôü]»ÐLoýü¢]HÛJ7?l‚Yk„¿o3Æk=´,·n\ßoõg¾n9ÈdŒtýö¾¢».¤öLó~®Ô’íç'¸ïëVÆ•ïæZË„U°ˆ¬_Y5svþ×SG±ôþ3¬wÜdçÇ»*=ÿØ.8sœwVŒWPÜ *÷oABË:n×L·±‚i•n¾(çöͨpÞÑÍ^´¢c]×é]ó*HË™r~”ÆÇ“¬ê¨(Q›NÏû“¬0Š:Ú^3?kÿ±üË,èÑ‚ÿ,À]È¡¿¥“^¡…È8¹é‹4õ4:Žÿ9l Xg½óqè5LI÷zƒò½©mK¼ì%jàÂ08–yÝqn¿®¿ŽÁh7ha·Šy÷Í‘"¥`¼34—8á4ót Õ>4¥dZ‚û}6–œgŽJ]N<½HKŸŒ p•î jÞ0k:‚ZâôƒØøÖ¼Æí f¢ü¢‡9N[Ipÿ³ÐòR‰n›78O²¬‚ü ñ.àÅ%Çp¿NJjÙ£0S2ë%]¿ÊõvQõ "긕ãŽÈw<àEzf»+Ôç¨à8^äå‚I¡2Nʶò­P¾ëKð á¼F3ØIuNàæÌík¬¢Bå4DTï=ô:!ǹŽkÙƒp6W8[Cá *Ž›¥+:ªÏKœP㤢×]“Ü=?-Šìü óe“¹a‡‘a8ÓÀ0rð˜ 4u†? £L¹Î aPrË´¶´·ŠCle±7€ÄÎ)¡øQSž@@A¼íƒÍEÆM2€ÔT?ý®Ä9É”•Ðãq+<ë¤ÐóB"£×Ô@˽„dGÌ÷йG¦vÀH\GÏ"oï8DçKò@FBýü±u5pÔ3`Çj"Ça†'2‹’‘Yˆ”_ÂEÎr˜ká sC¬ç.$¢äÜ;¯¶ÈÄ#zX¨Ž.a]ôÑ[Éfl3±ÓˆÞàýJD;õメà(4T†èÑRNÙht†T¸UV„ÿ׈k>—r&‘·ï=iR|e!h‹[¤–é™’Šo÷ÉM‹`c ã‰ûH»< ¤l’æ3$u*X?¤Í²«áiU.ÐÆ*E9›g)¡pÞ_™-_üÇ*ÄÕ–ãÚ Ü,Í(Æ>"Å·³b°|˜JLÙH(°:'B‰ ¾ìzS_Ì“u8´®»¸H@©Ê<÷ý"È“Ã$0à8ÿ­&õ*œ'÷¬’ïE6û I)pÜG-déÚ>—¡SC5çç;¡)¬wýé;ËÙϳ·”öå o@7]Óé@;•!±ìB•}oo¶µ÷°¹xwùj¶õ×F̶~ ÿ»÷ø>üìm7¿›íì5ýV¬ö†“}Lø½Á>7«á=o,ð›±Cù¾l;8W dÚ»Mâíâ. M+jœóbÕ˜Ã* Ñn ^«ñ™€e¬[!I#B]L!t;ÍÃY/Ö!7NHµãð”Ñg«’ä \— ÂHµê!Í$ec°Ó´$"F€bRr‚×5‘êeÊÞ2¶éÁ¬^h¾0ãÖ” Ó—ƒ²X.pQ­TH¸‘Óu€®øx“zA]¥–DL ¹±dè A îß§ O¤>YÇ[‘(rtæ3¡»–M˜DÞ 8ÝûyÐPþ’טŒ;>âÉžg] =<†ÒsWííÂÃEܽKÜ7L)Ò TseÈ©cëdVÖ‚ûÆÎw­dJ»ºV_´!;’*yúûÌG¾Ex\‚'†Ã—ñ .įΣßÓJ8òˆryU=ä”Ú,|S…>¶ÆC>¤Åä%k}¹«%ô»ÞIEÃÓ”¤¾G©õ$.SwS¿,æ…Ö“4º—úî¥Ö/•µ;©õ4f™¹Tp¡Î/Áx™»©µ¬lÿ%=O£‹ë‡Öã5â’0u§Ø4L>بµ_SßLvÞKk·§k¡XŽ£¸bëzkùIåC®Ž{Í´¨ài4 *x-$×W<ÐÔòkT+fĵ|3÷RÁ˲L6y|Y'ýfŸâWI™—q¾õ¤+'@ÐZnªjtJBA§DøG®èeÒè†ë7…j!‚ yDΪ½æáX§¢”…Uîÿea•ñ¤I+ëstœZà{V‘ñ~å~O ÍiZsW5w;ç^#àâ»m-M¾ò±à¦Y3(»|ÛI¡ïëÅp‰/ÿŸ¡»/ÖGí>NNtþõ«Ï¤óªXéîUÁ¦lT×ÌÚ?´ llc™ÞŸ€DúÚdñ•Šé žýµf¼endstream endobj 1395 0 obj 3220 endobj 1399 0 obj <> stream xœíZKoÛ0 ¾ûWø˜ˆcù- (¾¶ A‰›Ë0ôÐeÝaÝÚµÀþþdÇ"EIÎcIš¸5‚À)KÔ'~¢(ùÉõ=æúůzÞ=8½Qøîý³ã»ÅÿÞyrXYÅ­wîq.ªÅIär'xæßßËâY5—¥¡'„)ó=_èœ/ÃÈËÂ(c^You®@v ¥hs•¥4ýšvXàæC'ÿ ¶8°´xei{É«‘ÚIбdÜí2æe)OÝüBßb$49Òì¢cY¸1«ŸÉÂ-è&RÔ—…!ènŒ÷Ž@÷"Ew]î…Q’†G)S' Ð²Ø°u Ií´Ç¨½1ß=Cí­ÔNÔ@;4QÞU§‚Îô‰e./d[ç&ð§-RýÄÔÉŽ;L|ÐùHQèif•îÀ[Í‚!Z íÓ LºèŸîšÈ.œ4…½ôÒœGæ .d>3éWß(::2/)Úºœ3Î-SÐô ¤Y0ÇB'XÍ‚¹¶Z«i¦q-eÖ¡Œ4Г©£]R@ˆHsäjNla«oéKC ‘a}Ó‰¨1oµ±­äs#bàûˆþ2•²_PmŒ1–ÚO =DmÏ%h7LÙ‰%âªÃ6ßm ½€Ð“ `‚µa÷261oº°6DÖ­Ÿx{@ŽPŠ‘"¸×o§Ê›ßF…:ÍíëmóNŸQï_Áé-¶løÖÝ’w½ß[÷E»nìJ·ƒ®zÖkdÖË$¬Ó~|Pu\| ÏÔ¯ÜYõ‰{À3/NÜÄcŒó`ö;;èÆ‘,ËAQâŒÅH ‹æÎrçZüþ¤©àendstream endobj 1400 0 obj 1059 endobj 1404 0 obj <> stream xœå=ÙŽGrÆ>΋¡ýänCS¬¼+À¨å®¸ ŽÇ–…]c1žÐp8¢†Ôò?öƒ‘gdVTÃéñƒ±Ð²P•÷‘óËjÄjÄÿ¥/Þž<øAÚqõêדqõGøïÕÉ/'" Y¥.Þ®žÁ0cõÊÞJø÷ìåÉ8L&[ !;­œ‡~{{ò—õ¿oô0)=‰õƒð_­¿.ï¾+OO˯gåÝä§ÿ9ûÓɩԫS!WgÏˬÆè4+>}ÉÌpVÞýPÞ=.O˯ÿÙ}Oʯc~­«=,ïž0ßv{P€¬ÉÃFÄ09ïøÝT|à»oËSÅÖå]…èoeÍ/xïOù³AÒ‘+©794!ALr+«Åàl$½9…{¯§üPÍ8øÑ‡ïü`WfÎ[Qó/óÉÁ aÂb°ÊO«Ófô·›S¢”õ€+¥m‡}ÀK=áa#ð(¬waõGg'>ùe¥µr°,| {ZMî8Ô#@:!g<||òàñ7«›÷^œ<øq%N|ÿ÷ðû¯àŸÇ¿_ýÓɣǫ0|癦A—™”wøï3-pb‹p^ƲWVz6àøÇ+õ´~³ÔZc¤XßÔÇ×›S¥Ä Fç)_bÔë«  r‚“QëwõñýPbAÁ÷§Jâ³]Ëúû4ë‰}+êÛ/`a8ÀõË2m»–‚]hg×çøháý´~U¼ÙH3Œpêë˜ÇÂlëHOÖx¼Âùý0Ú°Cühri~¤šõ¯5;Zö´$Çò½‚é¯êP‚¬„aÔúÓÆèAv(–B§‘jttÑ8?Ð ¥‹–‘dN²þy}|‹'¢Y{ú–ø<¡.s}XSÀ6#ßÆÅŒ'˜ É^5(‰´xæUBû¦‚xU6C¦zW^’¼ÅG/•˜2¬VMƒdÖ:Ì/=|çš¶ˆ $à×Ïê¶ß±Gô:¼ZèÎ9áØ 9!Þòï@¤F#dÅé8¸qœ€t^f*TÝù» X¿BØ8A÷ÇúaÄ‹:¶•C:˜¢åÎ+qß°œ\Ù“,ðl#¦Axá6ïËTêD’–ð™6”%‰P¸¬|‚±#H´BþEaì‹Ê¾ „H µ¥^_sòå +yKðVÉèÈD­Prý×u%žÝ×å³¼[Wp/ mÌG‚F!¬Jxù¢¾ýë¦B@V¸æ„!2ùj™ïê¯#3ƒ–ó¶0ó{ŽYo8<¯¹©ޝ+€yFâ Of’’Ì”eèè¶#DÄ*á k³¬V$îÁ"`œ†I4@rúIÛž×qZééº×=¡x ª40ˆ5ì’çöó à ;–ÇU™7™ñ”ƒÙ8b&£Âþ¤ñc^MV–‹ÇzzDæ~i&´ò¶4Ô`Ð]ÒMƒ;L]çÙ+ ,œ ÑD8µ„½µbÌ@-eš¥ÍH†¨¥$1äBž_àJ,¦-ü6%:Å ûW˜NŸÒá€d$‚ã².ö†]÷ŠÀhbq³Q,(Àx+n½ë_qMܧ–uu8«èü¯¨²ß*‰ú|^†s*Ø© žÏœà8(ßJX¯Öp=åØŒvÐõÏî`ƒå³‡ÐˆçFYå*½´¦Ðÿ(«„}‘Y‰´ü°‰ãÃS ¬zyä’ÕêD.TL~Oæ¹1ŽzA­ëb¤3·ô]–*ئ?С:Ì rrpÂû•E¼¡/ôå&˜U8ö÷ÉÊCÇ(Q”Q_KÐx¹,å´¼SžÒø]ñ«.Øs™™Çœì¡ï@ó·/,vÙð’Zü†¯q·Ö/¢à«&FA¢‰QT¬_^¿VïíL T¼$?2(g› @¨Fd>l©8|åôú¿ Xß Å‚G'÷Ôào$_¶ë‚›Ú„Ê"aÚƒ´°Ä{E%ˆ6e|–•ïÊ÷j'LTåS+´$È"à²ßÐoX\¾N²J7R»ñ3Þ*ó 3— Z8ršÄ8!𢊲ŸÙ¯±˜ßVrI2€‰â)!í¬²‡ ¸#\Õ¥¬E™÷2‘‚¤—sDwf™Š¨"þ_°ÜÆrëE”ÞÖsú'ø”¼Õ)ë²1ülÒÔÓš‰\•Œ2œÀèÎN°ã]ïç»÷· Xf™Âð<@$~ ,<Žbç­²*¢hÂøœ#âåð>*Ó{˜eIè¡ÌlE`û™ŒMöOœ|ŽÝ[øÜQS»6œ!=8ßÀtûše8W1‚i-¨9sÿžB@M5I;Èž×|8e#(ycå‚MV-¢ë^J/X2ŒGê´HGÚâ.<<ÅÈÙjÙhàÌ£\ Ͷ²S–ä6³õYBi7Q Õ(æ(H Ñ.pà£@PãïB\örÆû]´–ÅoTIuNcÊdH§WàÇ{ÀZ¯§ig§`ñƒxH¬ CžÄaÒb@›p޲cߪͩ÷&˜<Ù–Ó-D`@yKê½'¢_ÛÊ EŽA¡y›ºn–¨—¥@F÷}‚»†ùrÚCë,@’"P@ЯYeALµ;›ƒYçt'q&Û's²¨mS88×(Cöò¼šÄü'ʸ*k\q¥¸_Æ ð6åæÂ[_e]¡ýt¬­¦&–Úífu¬ªºkúš„LF”cœÞÞ‹©JBE“ª"z¶ †£É´¡^ÍW…CòA)AÃRæTJë:š9•ùüÝ‚ùPÁªOÙyr|¾±¶É€“íd@x›d:2ó×_æÀ@SM„úDeD— ‡ëÌ–Èi‚òæ6„oI¨„{"ŽÅååXc,oR(ÀÂjYD˜½lŒ¹"_µ!7|0::Ï:küÎ3Ñpˆ ï‰ O½Dæçìn’@W¥ò âó5k„n o…}›ýMJe9‰ Z¿¾u=:âuçØj¿±Þ%IpóA«ìújÙ+¸àViŠD2`ö–ºñ¼À`ÐvÄvÅÎ~èì÷øn±.a”Aÿc—›[¸ZͯÛÿGu£ ij ~U)dúÀê±C_¤!©², ÌÏ&å3YÍÿ~qغr<â oå©v«¼¾ðVÔPÉ¢ËnhöÏÈAO]òOV]FÊm˜· v‚/æ\ÉAˆÔÕ/!öµ’!y—íë/Iôü¦NrC%IvÓ› ±´`Îx<ñL7­ó…ÑNÀÊXâXI–Ϻo±¹ÑP†ü’D¹«P«O/f‚0;ù)¤ß‡Ü§ä».˾þ7ÍTýϘƒb3ë½?Ø ™Æž¾µ°Žæ:Ì ”Û KÌõŸË‰³^>ŽÕoþ–à‹þ¶2›ÑðÆÌÏIg‚Qù¤ÆRÚP)Ñ]$I2ZMÜŠ±w^“ã| ?õéD&åNc} ËU¿Ùnº§ £wÂrÍm»÷£8óÎy>6iæ¡Dœ*´#ñÃ.‚""~AÏ Â8+ [£ +lóYX… èSÎÚp¡íY0,e[4Ї0S1HqzÚHÅÌþ M “›™Ë!ªy}–ED÷qšy…Á!1y¨i fò ȳôÁ2Ò»µLiD“D&É#Pz±1$Ô‡IB¢¤xiþ‘ðô£?”æ#e¨™–`×ú Ù\U×ÐTŒ" -„Ìv/X¥BJZ÷*pÏõ{ؽ¹(gÁîM5»]n‰Am齨×ÅÚòI¬”¬­ˆO³½ö¨µKѨû¯üjnÝ=ÚǺâj×ãn/Yâ%tÈ—°n«,ñ°”õܵDˆ*)8HÊ]+âÖ ­ZÊÛIË‹-b‚©l,Ôp*P¹²Ùôé¦í·^øÌ¢îøÑóÕoIƒn^’š©LaÔŽl¼7’Ùc£°üJt‰´*tB¨zM:DˆÂ¦&ÛEBSÓä»Iê:vp _bLJš…$÷UìVÛ\z¹XxÛT8Á€œ4ŒŽ<±;XWêô.õ«…3g:?w ÒdK’~œ@÷=¨û‹’}RK5(³&[w*½YŠðD}à/²>8Z¨GH¬wR˜StÜ»N–0†hmœw(õá÷ m)l¡²|PKîÝ‚Ø>(¢ÉŽŽ\ÌT†¦Z¥Òã_tyÃx€%¡}PûnLBÇåd}“­^ÒÇ\]§‹k„u–!fí¡,ÙQq²”ì¼´N›/m—C˜å¶œ“MN]õ‡†^°–Ð²Þ w]aoÐ6¹È—šÕX:™”Ê¿ÛòûÔÄŠÁ}ÞPì2ÄaÅÆûÉXˆt„üyãøÇ´ùt›´ygéôió¸£STyrTqc±D@ûÎ`Q ™Œbꉗzàf#ö|KŒoáÍ`µï”Xš©Ô>.·‘Hš”ïVKPKÎ?@°˜&GÔËâ|&áæLËÂcúHT(8ÚÍv[D÷rnâ9žÀò~¯ÍË˲$Ñ®·Ù!ß>HLó—8Pˆ¶mû u£é,ÃTÞºâúvA1ŒUÍ­º@rP,9`ÿG²”–ŒÓíU^DÓé—`ôú˜ŽLƒ¿Ûîö7)½xˆEë]—hÓÖˆ ±[Š3‘ê©`ã`¢ŒŒ›Ù·QÝ¥ÚêrÍ©ú‹”}Μ¯{SV‰þo”Uþý@•'ª¤"Ï+L%–gµååûjºØEcÞV]/L´šìRãÙ¬™¦ï¶â/ é» A,júU.œóMo|ÑÂz«ïÔ[¹û©áˆáÓây"¢5Ì·K¼+ý¿ax¼©°)B@?ðVΔ]kÐ+0å.ôË áîð(žeZx ylÝÁt…Î]t$ÛI)Ñv·o`ꪤORõWðaÔü^Ÿ½º7þu3zcëa´}î³n¦BîENÓÌK+GRZ¹œJ÷ÛùÛF‘9¿Ï…­U]_Ö6×7h96«^Ÿ–«ÀÚ³Ú.gy£¿™"Å«·¶yfQO`a5FÊçVb‘¬¦½JåHˆõ4[ѽϪîÝÆç¸/êhæRà‘^EÎD§$Ig=aëÿJ qhú¿v² 9âDá/˜Hõ.:|9JL+‡ø/8üõ=Õ¸àñø“Ž ¾—˜* à¿$Áƒ@–z 7d´š r'×·ŸVê':x–N¤¹«Ä ÜVÕ(ô½œ¬ìÔlõsKÒ÷d&u/LJ—{t SU)Qºd£E¬/Ñýˆ7=ím½îh `U÷!žt¬¬™S‰bÔ@x,¨-Ë‹à[u[bYù`Q†?[ä ?y´S-ò…™®·$y,>ï_Öknè.=pü=E=@÷´³hõká² ³Ó* kµS½ ²ý.írtD$í b1Zy;<0¸]úæè›Oúæø›ï„fwÙÉ.u|<؇³ÑÖØØ¥¤Ž}TRúßq~!÷K[.°My}#IyÑTß…x?$7Hräæ‹&]Öh·ØÓ²F›Üˆìôùm¾Á{Ðh”ÍL¡õÀm’ªè«£CœôU…˜‘Ø-¹ÿˆX™;MË¢x޽£¬xꎘŸZeŒÌ_˜XÌN rì]d RwÁFŸˆçEBFlc§28ú–lÏ$dü‘Qt;ÀÑ!N  B\µì¼ª®ú]Æf§ü?ö>²ü¯û ¨bö¸‡Ãr —ŻӇ_‘ÈŠw§åžÏíÄ;î}^£È_}¶Œêøà'YOÀçï^¨á_¹Ó+rýØÐg¹>‡¾ÍrÕ—j·)™Åù±ÏâœÏÞNxˆF-‚ûpàäéçNTÚgO”ÅÌ-&Z3Vª;²²ÛFïz}ê Ã8ù¯Hü¿jø~_Ç~X€`VG°x+•­OË}–Œ å¼BBû±TSéXàKâ'ó]¾q‚ijz@–dù{@B)AcI|Vm¦º§å<²ÜÔ´»}`Ìí.‡+pª3{TA…Ô¨ôØÚ܉¹o=T®hX¬ˆ h¥×fn­|Š}im½A)gBzÒÓ¥Mñ¶&ªæíb%<Þk>ú¶›-ÜuàTÛ#I;ÞºïâoqĆÃÜy3oÄ$Õm©¿Dä¼Î»_iÞ"jDwOy“’ô²\äôÖ4”,ÜýRLEs™Ý®›ÅK-ÊB­ÓÎr«ÏøKŠÌd2ž7—,ÿ¹R¤3»”ò ½6s×ÎÇú y~òö¼üZóÿl‡ðjïªÄ­vW<ÿ¸£¦—©ª"7;5— r™ð×…ÄîîØw^}ÞPk+ˆæCj"W´íTVlé½<+U±-ÜgºHL©^p­6`5¥»îÒµt™[Aª^ßEΆ‹—cŒ³.é;+]Lså*W}Ø-µ¥aGi¹ùq¶ý¼HònÔN8¢¥ââ]¥ïÁ0mT}KøÕ®öq²µ=šWh`¸aÙ ZJ\³Êé«xÏmsÕâ­Ä®¦}'E«”È£ãŒöJÄ%{>·æpÂÝ®:•³ß³ôÊ|`YÕ%ï@æ…¥ìÞN*² ªá瞘´>ÔämP¸ÝÎK—ÅVñ›+½oþTL¬æñoy”ºÁøµ·‹÷K§Éw‰Î ŒùNg¾Cšª6f-¸fk‰&L(-–{Ú ®¹Ì“–Ú?Ùx¼b4ØO›ôçQ˜^¯Ûô$(—…K@ÿ¡Õ‹ „T|¢X¿¼!t9IÓ@ÏBw «­u/vê^2']ãÁGhofŠ%]UÖ²w–uØŒ`Ô쌾K…ÞÖ—cSŠ=þ¢iÖµ‹ÀÖÌ,Äøç“ÿ=žC°endstream endobj 1405 0 obj 5959 endobj 1411 0 obj <> stream xœí\YoÇüÈ—ü……Ÿfí¤ïÃä‚ Ž›oq¬xˆDH®,Q2ôïSÕÓGõË!¹,é»»Žï«îÞ_¬å †ÿâߣ˃ßÿ( [¼yÀßÀÿ7¿ðPdÿ].þtŠñ…o½F-OºøÂŠÖrï–³–AÎåÁ¿šÃåJ¶Âk雳åJ·Îy/›“åJ(Ñj£›ÓåJµB{ã›M(à™VÍÅ’AûZ N“›%w­`Ö6¿.W¬5Þ©›óRàªtñºªµÒÆ. Ã~…hóŠ·¦y¿”­Ö^©æh¹‚Fsƒãä„vH“ëRà]nòœ/}½ÛV*N W+Úêzðœë溔íªIfy^"æšOqV°Da ,cÎð´´Î¦vt´±³Ò™Ú;lL¶\ œZØåÓÔ¸–͇ÜìEMÞ»zd¼Õæ­„æ­w¼yMÇZ° jýûðo¸R€ ƒÈ\å‚ao 3¶y;:£’¼®˜¾cO¦µ>o´ŠÓVºåF®6£›ÐBÑÖ+Ç$_PÁ_ aQÒWðÇtƒÿM–áT£RL2nÒTÿHʬÚɘ ‘a}JÅ@qµo~\ªV åMÚ,®º)¡U ý7ߒΈ(gQuÍOKØ*É™ÁÇÒêZm’Z‡+'%ƒVOFwi]íRZûu¿lèb]„úv![É?‡©îÉÞ]ºê둘žzÙ­š-š® ÖW´òcéu¸0’Ú;Cf0Ù0Rí,j‡ie2™¬Xj‹­¸n½ö®+ͯ²n«ùÅÝÝŒÊÏ=¬/*¨x‘Ÿi ƒ™h·gOŒjlÊëz>(äÕN>ŒY÷=Ch,pU‹Ñƈ}½NÖ±'ÂB;pCGC¤hÃé’ûÖ Pî/²ˆ¥Åp´þ&¶ EψÑëä ôI%ù*‹u]l7ÏU|™´È£™ÔÚÆ’!ßä|×/ •´Iª‹R]æ|ö.̈l ±ØdqpЬ¬TöB’uIÃB28Sá£0QÁÀåíÃrQ-ú‡R¶[,ÉEÁÊ6¦%WC¾¢Å5¼U|ô‡° „dØxh®²M¥­h¯8‡e¼Ûèqp=ê….F•œúL%uç(PÈZ§#^ô½¡X›ë:¼¸£î¤Sè¸NBJ9Ô‚”‚•y€jJߎr ÃÀ;ðØæ^åÜO7æbËV4«œý‡®Šr"Ö±6VÁÜÔ ÈŸH¹²Ôø¹I/s•÷éÓ›”ø*ç}™>¦DY‹º÷*×äŠ[ÅZ²byܧuóÎÓ§£”ø2ç} ­J»æKÍ‹œ»IŸ~Î#"ú™?J‡“Ä.¾­5÷ˆ9ªiæÓ¢å¢à³ÎWKщϠR Hwd1‰ÅÁÞýç8 ·Bg6v&Ú­ n Y¦„ hjœÏd4Õ–nÚÈgœ¼ùh òü!ù g¸T³øLÌ<>#l뙩ŒÁ÷K©[¥¼Ã J ³>‹E’ö O”òiƒ˜­¤ptÜ·eD°Îê¡Î§ç0¢Ne$šä¨257½1nb ¢âF=”Ÿ(QÇ{Q¢@>\ùËb¼ _Ç™ Ò"‹ÀÓÏ£ELAI‹p¹½Ø -b¦U¢¢Dý×c¦7êØÃ ±Hý¢‚ÄcE. D¨ÞoT¦Gù—ò¯ñ{] Û}1æ“@É —z–E<ÞëÎŽ1zõ#Ó`K½ºq’âŠEºïàÆ°ljKWÖ(ÍÖÒCwoÇ ªhESæòE¥4Þ_Ä€îsãgsz.ugú2uÙ*ß±úûÁáo·P é@Ž@*!-˜9DBzæÃÌ#ü#"ú`$4‘«=Qžƒ-ÔÓD!Pú¶< L‡Ëš(±÷8Á­åL÷ÀhÔùáÁˆö@fFFºµ6x0’(€½âÊ΢Ò$£4‡ Œ Ø”]P€nÙùHB 0gÆ$z!ìPæåD”ZÐëQ³7¸~ÝÛt±üöÇ‹Q{X:–þPƒ¾ $\G(ªpÓ0p.‹b,5 yN2S€6ã™ Œ±Ñ#bXü$a_ëÃŽ8½ÇİŠìPJEÙ7@‰1µ€OÊÖ[mh-NøïÒÀÂiÇëäxF±Û¤}ße<ãw¸ÆºeÖVvPép|½»þ±×ðV‡Ù9tFnM¼Õ©ýh%w2ñèÔ£s Óšù6{´–à-2å:‚ŠH/æàßÔè¼@zlwHyˆ™þ¥¡šC Þ ûÞsgÂùÎ$8Æ‹-€7¶DÑ™ù»5z溭Q5zînÑð;Ãç°õt7ñ`Dº¬ ªeÒ'm˜ £‡ñé§ 9ˆ9 ¼Y:ŒZM5Vè°õŽï@sVYoÐA’U¯Ò.L@·™`÷¢è!Àëž]=_[†èÉu?·eÁG´ŽÄÔ×7˜ð&=Fòù}Èèh*ïžýð„» 6@ ¢lfJ]èàö§ûòõ‹=íÚÓ®—G»厙¾‘qḺPê^íöj÷òÔŽ^–þ¼ºgêz'vŸñ˜`¬/øºåÄ(·yžâó¯[óMÝ}¬‚;¸8Æo¹òQéÝÎ Óñ`x7uÃñ`*syÓoÖíþÝTXn¹åž¡R-Ö©ß|y¨{†ñßô=C, ¶EHâ¸wrÏ0<óòÍŒI vW8zï¬+ ¼ÒϹgµãiÜ3 ± 3ïž!®«Ÿ#Ùé=à ©S÷ K³9°A±õÛìH¨6S»ŸçE"›Ê0ô¹·®‚ ¤lÚ]îïx`y{’ÌAîôË»2wÿWV·‡æ¹ÏçòÌ ßËzU?³âAºw†ÅI+c%Eã7&äMÀx1¯w}Ž`qú#Q`Kö'¥‡ŽVráìEý«z ¿VƢΠTcg¥ ö´['BøÚ{ &F S¨¬Ú‘Ê^óÒÙèÜœáÕ·lZŒsô7Æ»îÉ/ bð1ßa9îu0Щ™ãÐŒÇù!7x‘*Ÿ€±1ÖƒcEË®TJÃGá4@URÂmB…Ÿ¸KÖíª˜ÒhÒ$“¡cbâ’˜¿qõ)F)E¬r¿¤ã~è?’£ŸhÎészÚlikú”Š€x¼W.ytŽ^”Œb«qB¼î``ÎNÄTc<Û133ìÀ»Tœ®ú~?þ$…S¨«ŠWФ{]òŒ¡. XvPG¤ j];l΀ˆK‘7^SÏëtµ.¼¹¨Ø0¦=|x-ÅÇ©Õ:m ¦-dÛ føÖL薙ЙA»Qkb@(YõÓï²+7Á`1#7€Jð·>ƒIÊæ8óóÍÐ5d߼צ®ÕN‰ñžüÁQ Ìc5–Q0\€ÒKgð±X—Þ^Ä“bRˆGÝVjq] “«Œÿ.èVMœ/¥—E¤Û·ôµ°éÛÍL«F.¡ ‡É‹pḅ˜‘ÓQ¬ó×ÿÿp(endstream endobj 1412 0 obj 3104 endobj 1416 0 obj <> stream xœí][¹uöq~E?NÛ¥â ^{“lı#À¶Fs‘äŒ4Zi´ýûœÃâåðÖ]Ýê‘lÃXìNmU‘EžËw.dÿ¸™'¶™ñŸð÷úÍųßs=o^~¸˜7ÿ ÿ¾¼øñ‚ùW6áÏõ›ÍwÏñ5#7ŒMN)¾y~w±tÀ6†o ›§Ynž¿¹øã%ßîØdbîrÚîæÉ #ä¥íÞeÛsjRN^þË–ÙÉØY]>,¯Jm/ßoù$Ü{ƒmBØË«üüqË&£¹Ð~þï0@¥åÆMNsø œ'«ÂŸ¸ÙF[5i» ô[9Y¡”¼¼IW¯ýtŸÆ+iÙåmºwî=¦«Ü⧪^ýr»ÓÒL³àásxó]jr•îåÏ]¥§o:>¦§·¶ȇñʘ…0ã•ÓŠMÒ¿r<¯Üoð®™g©8Pc'€œ¸v|’°^·¸ˆÒI ô 誅 èÉaÏNLiîHƒÛô¡™q8ïŸ_üîâÇTzáËLqcŒ›¬ÝhÁ Nøù».žýðŸ›Ç÷o/žýaÃ.žýþç»ÿþ5üùá7›ºøþ‡Íy;‚æ¾ÆgèÇ"‹A?ÿÑϱ#\ÏÊ P‡ìŽ;Ë/?mw nã¼M7·0Is⃭¹ü¿ô"¥. ÂãÉ'Ãå\Ì&ò”ÕÈüÀ€Z ˜Ï‡­˜”²œ+¥›ï—K ¬öz ü©ËQÈ`ê‚Í2N)AŸ?øÉ;ÆÔB%|uDu:LÆg?׿ªŽfP‘_©£Hl§Ì¤“1§ÏÃtc»€BŠ‘é…í²!ø”4éÛt/kë7I ¿N÷®;ú½6"£§U/¥~ÿP]áÓ‡Vû/ªÞjÝ0††¯œìAŒäŠ2žÌ‰I–mï:öレl4> ÓúK9—züÊ#“F4å`Š–Ò½êÑž¿« hTtžÈ‹½V9ßE FÆÃ¢–/fŒðª\¢A˜µ8':µ_–DáUC×3‡ÆÏoà忬]O¤¼5(¤Ó¿®&Ž÷n;¬ùØaÜ÷éé§u³ÕÈj`Ò«ávå:ö¤oý$–µÕœ<¾‹q€;í×)‰&bY€1#â½#âW¸ü,F|ÝéúúUÐj£ŒJd¬®V&€íE†û3e¸Ún.ª<ˆ³ér0äCAÔó­¶,5E÷Þú‹Ù0z Ó09áx¡gm@é'tððÒû $S˜ÙÁŒð2uõ€]i@(œ~ wp•Çr^ÕŒvð*½z‹Ï3ޝ†›Ÿ(f©:Eøóè¸` ùN¯q¬`“Á_z×› ¡Ð»üååfK¡Ò»`d66Ãï.tñ櫇¢+í@|… Ï_åçW¹ÓðUÉLèßßEbÍr’.ÒÕ#8æ^tÇM(Cî~Ú"»rÀ*©Î?]æç¤Û»4/ð¡M’÷oÄ$« ÃÖŠO³“t > ¨Á2—Ód4{[0FœÊŸ¶¨æI×\¨Qÿfºð6¼à&©ÎÁ9ðmø¿³qŽ· 臜†Zy žÈ9ZâpÍ8Ç7FL æ?K n]S²‘g3m&–ØìyC‚_Ãé2“ÑìRû…á–Ö;Ðkõ®ï¤OBÞÇžê!­Ð´9t«EÅ¡Q Ç¡q¼af*kñE½`¶è–ŒàŽÊhlv  Q‰îø$Vñ>Þ*éÀ”èÌÁ#Úé·ÛUϸ Ãô”Ìä%ÌuO}L`^>ÇnýYd®›°Šòá§hdXJß׫‚’‹mP”fó Åh‚¡²•\†Ï)“ÝyÀ§NÒ‚W]Î{½åjšÁì_þ´Õ`•ó¦X aDQ+gë #mÅÎþ®°C£?My£.bР#Ei=U¨'uÁó¢¡Á€Mø-a„÷[‘5í½ 8hx3ë¹Fv¼º¹îF;²¥Š²£çƒ²#¢_GñßM)<Æ”ɼÚ·®ãÅc¼x(ß6&8l - EMÍ¥—  <ƒY:ÊÛ]Þn´%v–ø²@` ‡àëžF•f%Âù°ÂÑfjel Ñ:£`ˆ‰NøXé„h’•uÀüB#+ ÆÈ3’öûdL^ÊXÔ ‹“®dl¶Þ\žÔÀ\õuÇu÷k]ÉùÆ  ³Iø‚|ídȺ @MÌó‚L¶´(MòÉÊFúX3;ƒ²!v´†W~` ‚,P6«ˆRüp²¥&à `H}I.à…#u·¤`‘¢w‡Át€¶@« W4ïV jP˜¥XÄ.j˜]2ï7¥Ò1&Äì²» ·Þ4ší:i¶Ôç»FÝa³‡F!¦·?ä‹›wRt”äÎ?dÆe„’F÷b……0œÒgȺûȌ޳îÌ4Îñ–ÔU"dj´D.žUD¦áÅ5TÆ÷™ÁØÔtƧ/òÓ4FMJOãöƒG§€Š„–YáMõØõEŠ”DºÌ<¢m´ò ÏŽ&åTÈüh&©~ƒK>·Q’êã¾ëÔØm¡g¸“Gâ%h§}ûß…ñ=Ò×þù ´TH»dÀ‰JË>k}ýJÙ¾Õ{]˜ºÐôÏчc¦º PÄhvGšƒ#©Ï/äH£Î¯V…³i6ç2578Ï “¶NÂÆqAuz\°ŸvRDnþZÅÉzÈù+èI™I>%¥˜JµçÉ_å rÖñ/;áé·U‹ƒ9(oLp¯ÏAiLvm×ä Öä\J®OBçò¢iÎÓÕñÿQP›º(?Q£ÊûN^æE'ð%RSÞ:Íâ‰SSL+Ôä;çLì,”¡V|œ›”Ž˜›¤-ǹµ2Åû™i©F¤å ŽŠŒh Š0`f´4gäÄÏÈMq@^z#A/¯NO%ŽÛ››ZÔtÌMOOïÉMQ=qTnŠ;ãCGå¦Äa†º`Eì¥ä nÙ”–­šm;ðâl\Y0T¢f'«&Åձ씓>žaCpø5û£mö§wÁ>.ûb0ªì1ÁxÑöþˆ WhuhŸß.R! lýÉOÝ“"úüpB(0£ðå: †vâ{ÑBáýUh°»“¨Ñaã 95-„E÷M º3?4XÚLàŽµ³Ž,µL[žÆï2{ÝO’=šÁ¸¹¸ümPçŽHG‘ô D_2éƒ`„Bª*ãÓËÕ…ïmʧ…Ö#0´HB`‘Â]–€Ö³³•,…›CY l»F–¬ß\…¢àV©{Zû$a ÆdUEKÌUFÁ«íE0võ„I?‚PcRÇSFr6äkUf‘ z“IåvƒhyÈ`»É,+Mp.b:GPò‰Ó9þÕǧsZ¸}\6‡Û¥ ¢Îæ ö:˜pF'd +ªTCн£½®R ƙ͹mÚ¿lš½mÐAn?JÊBKN†Îò䤌TjDªdeŽÍÊPbþ#-stZ†º…Ÿ¹™“ÐÐþ‹è}tEìÜݲµÄµÔéq­~J€™9Ë&£“:êî ‚žä‘»ŒNÉ­H„ŠgÍ­Üt‚¿•=¼Õô¡ÁÁÌ‹™§r6ë/@p^4=GÞi fòè¤Ë`'-ÿÎ6ÿЩ=Ùæ‰qà†«¿Âæ:c7ÿ´“øJ›Лwæoz£A^ïl;€Î§±÷dY¨š:*Ë"Á‚câQY9[„€UÐÊ×ôéUYÿª‘ÃH„/½ãòGà®BIÃõ·]ÖºüMxbŒÑ¹õEÑL¿$½¨Â„ffrΜÂóßÕ‘1¼˜c,åYÊFìvÏÖ =‹a&'Ž1$W–OõŠ›hdßy¡áÃÆTü‰7KN+cV½Õ:SIi&ñ¤<¥Å¤çB¸2Ù"µžÀž~KÁgÕY6› · I%'ïÙË3hÞ¡ö”Ø9ײãt[Å£`wgû»ƒ¬åÀäü‹î WžÏß$\Ñá·0šÙz‘:sô:š‡"z vtR{2Aœ> I¯Ù$%¸Ð¬ €Á¶fÄ\¤‡‘ïã×N—ñëÅ–­‹_/s÷ú»³¨ÞmŒK!‹k Ù‰A]\Ÿ#;\äˆ"Ït6IåsCrž8£…{Å¥›Šûýö8(-ŠáÞŠ¿tvH8`‘!¥É:[ïZž^'`aïݲ´¢Ú|ïùL0é3ékDLpq-b@êïSE¬ ÚyBv2&ã¬QHÔÛ!ýUÒUåV „ý,“ðÌ×éhßÉ©€ý¥®ÏßÄUu¼8ShOÚÔ<&‡Gm~ùû-Ÿ´4ƒš30‘EØrzA[—NNåéŒTá·n èÉT”ø¢³ÀMxËiÜÖãKSÙ‚ ‘A,Ãó;âó·©ñCîñ½ÿ¶Dí B  €_§¡‘7󇾡ŸŒ?ú›(@¤K2ôG¼D¯ÂØÉ$‹î»º¼g§hïÿ¸xþÏô€Ì zœK°|V2±µvˬ˜Ï¦¿Í/,ƒeøŸ‹I‹qRFÈè’¢ÍÅäSÖe_³ôe±øM(Mž©RL—¾Mêê*¿PÃrÉ&j—ZêÉXßÈ×Lg£í»V)Ÿqô2?þØSÓ£j¶:ó9ý¹Î©ûJl-ª‰h¶¡ ™ëÒ[à S˜sw$k&2Ä öknÙéO¦¤« …Ô+²‘Ãú(vqúþ….k®–šr^;V±ƒºD.„Dwñ§n<±´c¾¬!‹– Âý8*1Ýxq> @¨-¬cßÎ,¸ý9ÀN6 4kQÕ®,¤­Ä2ê‡ r·!„郎ƒ¹Éêác-ß^•Qt³£jçeŒ2°\©ZY gø²è5X.Ii¾Žøí+iŠÝ/0‰~þU£`rMLœ@¼$* ÁªB”Â/…Ó2>=‘Y¹9¶£ŠGôù „QíŠwûB_æÜ"ÝiTˆˆ`½ÁZye޶ˆ„û:õ ˜G3¦„WC}2«3Oa@ #(erÿ¼^Š |€î¤r¬¹D”ÁsG¨­‹C©Ùc0üs’t!*ä1Kà~\Ú)‚Uÿrl/Á8Phtí_ua5y$­äë"ÏqÁÌŽêqNG H%+ÅÀ-÷‹·¤4ÈaÙ‚e,Dò Sý/ª}3+F…5v`í €|µ=r;ÈÐ'_µ2h‹e‹UsþPóÕÆÂ{´L1–.`Ùg®+ðÒÙ¢ÅtßG]„ª«DŒèþ Th$tk ìdñºÎ{ó”JõÒÆK± T»‰kÕ× ©@ÜÐ)?“Œ¯¯ªÈÃ40µÕžXmÄË)ä@ÿa‹»¥1 ×ãd­? ©ŒG6flQ+ÖêªwÝ ÑU]g}Q 3” c.ðÐc!Þ,£]îã‘S2ª+>û"_¶*—ˆBT1X×&ŠO¤M¬G§ëÒ|J0å®§¡ÞÇ ”öP~ÓI Ô¡àC ˆ›› ®%º¨Âë¾êš ý‘(# ¼OoÇ=^o#Ï-ž žaÑ:.§ì‡é«Ì—yž'ã.oáÖÂ.ܾ®WH\„å°ãÝ¡¹ö*®X©ÛåÇJÀ¾üŒí™w,¿"ÖY<Ê:^º#––ô1 ~X×¥žKKk¨PÃ|“c~a´ƒõ!Üô-Ü„jó§Òè–*At)Ÿÿ0£GÚK!¦2ïØK¤°tdv™œõ"ÉÄ-OhY4„DÂDQY ¾꿈8>TËúq‚]\•Š ùCŒCúž–ýªª]jm÷–õY§?:°¼ðìüsÜŽ;»moV•Ö„²ƒêªµŒs3®¯ZÆá¡¶R©*D*HVC¥n¿!È¡–Tbs n”Èç¨Ì³Ç%­” n!}µ¼ã¨Øç„d#ëuVµÝ·Tí¼,!躂%­#·„¯}¥¸œ×åtm“Âþ‘ô¯R•t#…€tåQYâ±ѺÅÜh>üÅ ŒÄãïÿF1Ìa2ù«ÂH±ƒ©8è¥ùÙÄ]œÃ>Xʳ­~Ñuï’_»ü~+ñØaBÓpŸø»–/ÒÍûüƒŠä·s£—1kËã%‚«K¬}¼™wéÞCþÐûôS‹ÕOiÖ¹T ÞWÎ¥>ß‚³=3æK+¼DE™Ÿˆ$q°;ãjE¯– “ U¸Ñ›’Qz…øF$¶H²–ý"Òf{Œƒ–§Y¤ÊŽ™IË9hµç¨j¸Ãäo £K›é3œÁè™×A>Lô:Feèž¾e=&­ ¯¢KÚ[bÍ6ꢠl¶eÔ¥µOg¢Q':fU€Ô£ ³Ê7ÆP8cÇÔ1ŒØ” µ§d—q)$|–Ú•ËÂ'Hàt|ÕkÞ/N» D—‚¤Éà)õ‘CjFõGš{ÊŠBn!B‰TwÙ•òRãØg”x2–tc%´d?]Û=|yäiH§–|°8˜W '{*ìʫ‚ÇÕ!!$xå“^ˆIw&ª!”nèšóK ßà/xW%;¡x¼J½ƒ)j£|²=åEåc–Ç2åþz'öçÓZÒÓÚ/ͽ”mß“«êˆ¼|S(>BÜÜ”§ôH&לŒ—Ÿî?˜•k܉P·ªunòHmµæp·pŽ[oèá ÝÑᇿ… ›*jWA‰PÞ~Þ ú–¯ JøõÕA> stream xœí\YoÇüÈ—ü… ‡Ý ;ìû0‚–ãX ⛆ìÀà-%)Q¤lå×§ª§êžžÝå¡ CÞQÏL_UõÕWU=z½`_0ü/þ¿ÜÛÿZ¶8³ÇŸÂŸó½×{<<²ˆ?Ç/OÂcb!Ô`勃³½±¾pb ËÄ`/÷¾_ªÕšÎ{åþuðð‡žÏ|xÍÃszà†qxþžÿÃJŽj ݉Ás®Cÿ|0һźzúóÕ‘Òøå+©e´_`£bšûå'xÉ·aôOö¾Ú{½PJZç»Vƒ[8Åæ`Ò fêpž<ÛÛöÙâæúötoÿ»ßÛŠÿ{òåÇðóìo‹ßí}òlº‚×C?Ò¹Ò“ñÞâïzšÝd¾ðƒ7Â(ºÉž-Œó8ٰǰ`9¯¥_>_Á9Øo¹|±‚m6Z ¾|Ûk–Ú,ÏV°f±\Þ–G/Ëå1ÊËÀVËåMè@ oh_W“ל]Žoin–åQòéëLFˆÁ¶4|P\Ó¹¡nð% ái†8YÂu^W¹:-k{EeŠS ÃŽs•Ìò0+P +-LFÚ0ccÿá­Wy­¯JãUnÕž¹Øè”Là$®š§u‡`ZB0"¿ün¥Ø`„VÍý8ÀI¾ºZq7ý§Õš  µÎp2ç!˜„r,ØG•f`jÿÜ;øÓ÷ËWjÐBW0%4_¾]0 ÛyZv–”lý‡ h ÀB‡éÊ3£©Ê‘.ã~šå7+&Ê™šm‘ŽÄ¡Yw•Wqòh­¼£>iäÁ9•Æó|ÿï³AsAä;çyôðÒKlõB™öDæ9q£â E„÷ÁHGµí§HCj>Q›0æj³hÄßW*òúÙÊ‚iUMó¸Ì— z£œ ß­PG„–ƒR,R+£IÛøѵW½u–©> :f}‹äÿ†£Û°áESßC Ú 1.Ô2—cï– G¥ðgœ&Cööyé+ WS1‘©^´`^;,D[5ØÊ ó'qc”ûîŒA}ÑBL;Ø«jºÍ†iË:ÊeÍÅ(™ø>ˆxÕµ¹b•ù6x@¸²•ÔZšÐC½ß¤«wÙ¦çAZ‚»âþ±ÝL–è&ÎUùA:„-°?é¬_þÜéÓ®=m©Q:½qTkK©Cíïµ°úžŽ…Ãé©Èh˜€®¤GÔÿ² ¿?¬ _©áØ}’ïG‡×kj’™Z‘(9¸Lù’7e:¹6Fšlz¸ì;Ò´—: ª,Hzx4á1Òm±ùÈlsÄf§«ûËrlÊ®»qIØñÄã=‘éV¨°|¡!Úd1Úü&éü³¤óËOSÓÓtñm¾÷elÚl†MÆ)ÆNŒà¼á-”º¡ŠuL¡ ÕÁ‘¾jeÜ´!à=5ªqŽ\­ PöŽ«Ô!zK+¿ÈmãcÊ‹ˆx{ÜGTœv#ñêi¾K·rm$øGð¹Éoòƒ—¹í*_]ç»7ñeØšn¿È·OrÛ_[(›ÏóhŒÖÜ=Â1òôc&z4‡Ì==\3ÒßiÍ$zŒ°ÃÏ §@§«4ââþ¨9uÂÔÛlÇæ˜}D•&dGrnÝöH¡çĤJëÅ6Òž!”ß iF…€Î çF ç8íL¦ ñ“ÌA7ôå3sÂæ&ÈÁÔ‡Ðt:é=£jä ±|ÈÔ¤X~Ì8ÈÚWa÷('ã Qèò-tÝAãàÑÛF9šMìDø™-"ôƒ¿D}**“OUÉêï‹ÿu£Äa4•,Eq ˆZDú”\K®¿„m‚Rú-AÚ~ ùîaüsx¤<‚éãàÈQÙå¼÷¨ßšxƒ‰ÄÆ5å=(™¨Ã®UÍ&7ÞQn¬ÓðÜ_Ö£v«ñ%²'¤«B‘tTȹ¤t*Ý¥2º‘}¼|Ýå!’ËøZVQòñ¼Ý•@#&jÕ²„¤WÚ·‰åxœ£Onºá,a5„¿ »¦b|,„Éí€lòäœIx`rN/GκRRyŠ«T€“zT(3´Aù8Œüf•>;!V=!Ù;,*œ 7É K‰l |›2#®|†ø+%SŽå“n *´Õ ÖœÆ@Öâ\ P8¼3&ï• äÁÒKtdÛÊPuqK2;Ü·RDs=V›‘ói®]Ì òi‹xâLjݬ¾õݲpÎ eU¹x¬ÆÛíáNù6!eÛ‚UÙ.ËBo‚´n#Å ƒ‚D¬ƒSÝúˆµ1«Ïa6M}.v*(²zt¢ð…S]@šÞv1²UEr”Þ:îizµÎF¤Ö ªmûT@"éC­ ŸfiOmÀ©êqcŠXq™”dVžù¾¿5pa“èRé¼}¥ ³î”@J §TWsÛQSáÁ»§Muíå´y£D6uÏ'Y’þÖ~À« µ¥¼ÍÂs¤Sž;-ws˜UB©Ãrwhm®Üiƒ1ÝÛnÖ™œ×™Œ¦ŠÅÍâIÉ~ùºÉ~õó æä£bwª¬£ ÚÜA˜PÐ)Ò ó_çã—Äõ^•Þ×7­³e‘P™6Ûn¼¯$a qö!1AÖŽñ8šoÝh¨Cˆ>ožžëBhÿ0·–¢&Uf…µFÁ¿F¶¥õûŒK] ÀKÌyGOùɉ‰uôTL"=¹_fNÎ_LOma-í}ð9ï—¹tsMÕB†áíLÿéø0†ßxB&“×L Î[)Èé¼TÁ²ŠV1Ñ&™VÃúqa>–©¦yõ† ¼è’…Ùh¨™òÇxȦjMI_p~™XuèÚ$Zkc¸m¬Oô&2Dz‚t™üMϨçÝÓãD}–FàjZ ­€Bokf5¹{DWدÌfÖ Ds ñv”Üf%ßÁ2z'wÁ ‚[gº*¬÷¨>!ß[.@OB…Àf:taƒ"çÆû%‰*ŠŸy¤áZdA¢±ƒrÄãâÓóèÃŒõ6×bs)râdå^r=1BOêCã`'˜Wóü×ÂN6ÇÓ¿; ÉâßPû~¨- °Õ/£Î:t@Ü™A;ªÄŒÿÝ•íäC‡ Q)©˜J-‚ÌIœ“-""Y©É—w8TÜÉíê¸ ¡§tZ#pkx·É+Ï3±Á:b’kÐþçßý܈8¶ùÈ¢Jë4´1ÖTYÉlCÖv:]ÔB20Ù®¹Í–¦ì€x§|*‹°Ì×ì€+—JÊÄñ¤¬$Ÿ3Ä7ô?À|huz7‘H•l^¥ŠK¬Ý_ÉÔ@8ýx¨Ó²Þ9úù1e¦xåf÷‹þMÑ®ú“hj![ýÉBûS ³V€àÓÏ3aõˆóûƒY:¤w'0¡¬)!E j!:‚õ)_7n¿_î©Ó8ù»¡yšy¿KMµzq•à cˆ«òç ÷÷ÐÅkݱBJ}iSÅ”EòÉ7áûK-÷–š~SÊj¸X„ÏÌnÃBZWÍiæýå^žyH ?Ð~¥( `5+UOåÒk>/ØÚÈ%&6ºß®ÌL—\XÖUP'a¦YÕ³­¾¬~”TÞ|â$.f†8çsÀÿð1Ýÿ0·îðaàõSà‡ùÓ’c¿Ém×EŽrÛmóF]ø±swÇÒDçß8Σ¶G§°í¬3Ïóx‚+°©MuëÎDÏ:–¹‰ŠGžcï;NG|ðXù@°Ò4V¯PS*?U‰EâöGXv)$vDó²3•Ë÷°ùe§Ó%“ùwî¾Ø4Gbgùn«RstMWúà5ž5£Öj,³žgYmQΛ¶ú+­ÿNwï±­úEóÊœÐJu³lA±¶"Ò÷aÕ½*êynk븕>öv½lƒýÜÑÓÃÎfÞt6³õxu»Q?æ»Ï;`󆼋5^pý®¨ÖæÒ.Dø¹óÀÒÆ¿<;LSªKù<íW{ÿ%Š©‹endstream endobj 1426 0 obj 3973 endobj 1430 0 obj <> stream xœÍYY#5–x̯Èc‚h¯ï!$@qŒxAhµ;™K$™Éûï)»»]eÇÉÎn²ìj4JËvþê°]õ×”31åñoø½\Mžý"-ŸÞ>ÑëÌ3–[7Jȃ&h=ûè½gšG˜;Q‚Š\ÇÏ%ÊzÕË’‚ТUT;H¼Š ÌL¯ã(Ð95l+1½M ‚&‘Yo]‘v4lÃ*Ÿ1ណ" P »Sa䮸t´ç`…Qñn¦”b˜‘µ÷ƒ]TÂ:jr‰Ô÷¨æ:ë÷Ñ\° ×1)­˜PfÜ1Lo†løŽJŒ~» ç\,ÀQÖ#È‚pÚŽÐi‚ÙÙ&J0#ê“M²Þ¢^Jâ0÷+%Ó>ƒáß%XnJTÆùGœÔÒb4°r0„ã4 î]JPPBš~1zÍÚD²{j0’g`úŠld¶l &ÒõhRý%Ž„/›w’ ˜F{wð”cÒO»œŽ¢Ý/@9&ƒï»Å˜Ôà»ð'RËH\Jb~𠞆'‰•¸t·§pÉBEJpÇ`ÛF]t {'ÄTѵˆ ,sa€1í…Ì6«‚pWø'Á .hßæÐ Zµ£dIS„”LGwý;ñç%lë¤t á 3C¿¿ðf™a\ºîsìF)¢È RCöOOœ÷“ WÏíèãÆ¸þlKƒÎ‘¬Ç¡±D0ûœÞWZ¤‚L!{Ëow’e»Ê_]5[Þ‰Š¢@‡Bh::“UZÏÿúñZÖ.ZÏ]¼ ÖÛ>pl‚×RºÞ€ÑUV•~{/U¼-n«í!ËøUTªWÉCómE9Ü=»½Ý}P«ù•±ÓšÅò¾þws¾½!åi6ý î«¥î¦5‹ï˜Ös¯~•hÃY`µcry~07ŸY(3-Š“GMµªÌ)V•Òø„,d´ý½at]áQ–Kð=­òl]g:””±ðnºl£J½eÕïß<ö¼JÇ/ãáDÛ ©«Š0~-tÙ€ô©æx *UU€w§]#Ë1ôC4xÎŒ‡*@wÕ–J_6TD«-(ZòÙ4ˆQÈu…éº9Ÿv•¸ÂGN9OF§FüëVâSœƒ€²¤Û°Ó‡h‡Æ&êÒ~…»kŒŒÑ¢æyîƒ#Ú MX_€Ý‹Øä` ù]Ääû>çpz×GÔ¿u¥2ù /„õÙW ®Ï¾bÝSξ·ò̯O=Dѩѕ‹”ý&Ìð)³h3«Î©§ò­ÛÜ¥q €eïºYBùgöOBåOBŠ„æ)²ž‚Þ õÙ/Òé©ÐLi+ËúÿÔX|_ᱜâ²&VI8 Êzéf‡ù¼ Á1 O±â¨&–L, 6Æ‚`ÁúJP‚/æ. J•ëBªiJO;ef_Í%ƒ¨ñÀÌòÖ‰Ä;;û(ßàt/Ù…˜Ð9³.ð±ìÞÏïiUÛc™>ÄR“PÊŽˆ•“XMK0õ†û52“ÁKÚ€ %Т1ÒI®˜v¬Ðñ”âi…¦u ÈG亩jqDTúÄ çŽÖ2;á ŸTS WR¬Ü«ë¥ÏMsm4·L+ÚÃÙoÇÔuŲ¶^•þH “”H–Öq‡ÎÅäXŽ-Û0{ݤ¡*.øIîôuË~PûÙoÑéø8Ä÷}™âoöþq0˜þ[ÜCd,c3MçV‰a¹S‹Ÿ<Àq%(ÍOqT2/iëë÷ú’jH:OVïX\DÊ ’Úl»yUöäÒÖMêHpIíÌ ²Z:2 ­\#2?k“![¢±Øº®ð¦–zqƒëPö>­ÐZ)¤„LÄÆ°ƒðvnlgxm€ –€Šû8§Ëê35‡úJrƒ|KzÑìÔá{QµC©­&f¯‰ŽŒ2ˆÞE8€‰ê¾« RvW¨tœy«I # „8-IÀëœÃ^ ¬‚m$.ÐeY{w,6­¥Ñ‰¬M~Ž`ìùKµ×_œ+Ø7k¢¼U²K9Cz¦lÙ;¥Î œë(©ÜvA?QègíÖÐb˜&’3pS‹þh†›@– r;põ§@ubϵ‡È6Óì+3¦Óä®ÎÒˆø¢ÙN*飙•ÍÓ#f•êôÈß9¦L7ï™i'y8ˆŒ›EéaŒ„__L~†¿ÿÖ&OJendstream endobj 1431 0 obj 2196 endobj 1435 0 obj <> stream xœí\m·‘>äãþйo3‡L«ùNA€³l$:(‰_çƒ}0¤}‘^í®¤ÕÆúùÁ©b“¬"›=»³šD:ã`Èj±Ù|)²žzªXœ7«q«ÿK¿>zô­´ãê廣qõGøóòèÍ‘ˆUVé¯ã׫/žÅjb†`¥Õ«ggGSbåäʉq¡ðõÑë«ÍÖ >ŒF¯ßn¶J†A›°~·Qƒ1AëõûøÞ‡ Ö/¨ê%•žn¶b°Ö»¾ÙŒÐŸ1R@ДÇVõCVëçÝš¯ºMáX„´” uYc0¥Ä0Ç:c㾜=z·>­j,+| -n…Ira¥§8,=xÖßmÄ”5UšJ#FÁ@ø»>£Òªjœ«òYŠ&h¡ô˜J_Ms£á¥W4šÌoÊ_Òë÷½>§–&aƒHèŸýÏ‘Ô~pvγÚ-©£IVš7Å&ð¦tõž¾:§ÅìuBux”#üΔ1wÈE(6ÅËn¿oZi;ÒÊj5m~«„œ¯l¬: ÜháÊÒš2×l9âg;Ö£mvš£ÒO âFT6‡º4ÔÑS Q½¾ ¯pbÊCÏný÷ÍvÜ8z+xcÍcü×~›+ä´üÇ•‚âhƒ yõ4àB_Å¡‚Ôr0.nµø¨C!RZ ¡2Vò¾fºX¶· ^&qÒF‹ï‚™0só†âFÏ+°‘0²¶j,Jcaûç¯ÆÁÀ"Ï— êÚ ãÚM‹Óvð£MÛs´îÀS¾p—HÐV±þž á)éճ⿰gêî—Àéö‹8 $S’Gm'¤4ƒ9r±Ý}ƒ¢+&“õi^wuý$-¢Ðή& :8Þ]nì ”hþ€=éÁžÐ”¯+èÏ:É––-é÷qÞïö“¢Xyëz[n®õ“UàËI0ˆû×èÁ„°°QimlÄ-°bð.¸i'œ{`€q¶qƒ Ò®DLÙ(q+HMøO† ùµÉÀ|6LÚyÞß+ÚVûŽzƒ½´"¤9n/™½ÌŠQø•ǽ†ˆ¬`†·¨!° lqÀGÅþÏ6" ^ÊŸuM{ßà_N¨¡ lÖa×Z@V%lÀ¾g*šmÒX)›5ûlr DÚ~U5%¿Ž ú6[€øXqÊô„X§Ü tƒ@p¥•8é)WcSkt\Àíc`ÒbZÑí‚°·þ´1— ¼ §W ç¾@/c›r ½$Ö ±ï 汨ˆÒkA¥ãô¨­o*„`uÌúq‚0m$ w¦ð¸% S'ÕóNYTc”EÀ÷稚£žtLa£2‚¬4¼\ÿfªñ±!¿¿ˆ™1˜Ô’T–·tÝÔÔÉoA¦d`ãHmð:J=ÏŠúÿ I~MÝ¿Å)!OxNog々ê7ŽlÐVz‘Ö¦ö‘¨êåéѳÿúaýe* }†È΂|ï…ÈÎ`Y>[‹úRgTü=*±ƒôžñ6ã3Ò4ª2'ÇûDÁzØŠÒïâQïâL©PÝ=(“’ å —f4v…Ø¡Sd8òpã^ c´7§` ,ðú—\ÓLæN(¯S¸Ü7ÈsKXŒlÇŸP±P&œÙ2f:6gn ýz­Ôé¨ô!Òµ>¹,¼q@á÷q —ÔêÈ}wùÌÿj:füàe‰¢Ìù=³DÁ`ä"Êã5v$€ðâ,{Úr½„ì¸dÄpÛ­PÓƒŠâÞœX^Ü$Å7¬IH‹;Ô’>6Ô¿oÀx(‚»ê¡ÁÏÜóš<QMõ* Öu»† miõ¤rŠ;ÊëÚŸ[¾QaíOGê8^D-þ-r&н/œD> —á¨?˜~ìê‚>ºà#~£ÃCÆ“Pe‰&EšúokÝÁ’/ºuë `n÷w¥îdq XZfq+ …]÷ƒöSØõx£*P†«ø¤=v‘ËÎÊÓyy ³µ UkÑÎ…Ók\ËRv²óíËòô;hPRjýûRx]>y^ÊnÊÓ«òö§ÎÛ«ÎÛwÍ쨞õJÔÆ‹Žó—Ï6€þäŸå—€9€•0°çosÙEùày.‚/í¨ ½¿ÏE·¥ÖE.bÕó»'¹è$?ó*ðÆÎ*ÌÜ* –Å—¬Û-¦¤Pëoaçü°¦™†ÔÇ]ÙÏQY|½¼ËN3³÷¢ánm”ƒ™l² ¬}¸®|¥‰ÝÉ…ˆ 3 K&ˆÜ¨l‚KØ8æña4´}¦lèG+» Å §¯fõ¡¬ð¶ ì˜ÜŒäy·j¥étò7×a1šª>!5¢B±pnJ.â6a¯^Ÿ\ò´®ÝŠé˜ ȽîÆH:~-K>:€ÇgtøÖœ¥àbF²Ó‹g³…kö@YC 8‚R/·0mn»° j±ƒFYör&ƒ]±Ù™‹o§!ÄC)kö ;Ô+’J§„Äc[(öId9ÔÇTs¦µ¾.ž[çÒ“|ÊîóA$ªã‡TêcÀ6æ±þ}F1VˆQ.'aàš£^S«ýƒ¤j7A·6”æ{¸6Æj”íYçÌWOv| á­ kåŸ=ìÇœ^wrEfúwOýAá9á×ßo4 ûqa’l„eùÐñ‹êkä0iÛ¦E·u4¦"¶//ãWV²É²H^RåÑÖ–²R^V J¹®d-ž¢äƶ4ZM¥¬B .LŠB ÷P0À%± ˆFV‰)ülªÏú¦f"„tÚ˜¸gu¦œ¬Äo)´8G:ã$¹ò:6A@F¹ç߇IòÁ«ÀºeÚûª‡4¬-QdðÝ?&e ün´ƒvYç›Ìš¥L R&¶ÿ ÿl9qܵÐÏÛÚMþ$êÁ(9û;'FÇ<ç§ôxN4îÝÜŸöºËèÐFs¿,=”Ña(¾Þ¸WéDÄê&èžKw$R’Ó°32RUÀP%|µ}Ó4º3ç=h:¶ëd¤3¦¼-ií`µ_?Žò³"pbö%Sýo±î8hËçZÙœ\È|•Ÿ9³›d-&³‹Íðu‘ Ïp²4—Y"à ¢9°°òN¡†ˆ6êj{ãB(ØxHeM̲éS±_ºæ°–ózò«½2\mÑ—´a7‘:— z”t´tçyÇÙÞÀXU60æ²L!f[E»B›ðÛùÉáãT­93WXHÅ0úërxB+a7%Ž,Có“´•&êÅ’¤á¹ßE'Z vÐ0¿œýas†-YÍÜ.5KV¥V³˜;¦|ԜڟåoX¹`&§Ng©;u q˜/.ûùâ÷KÃÆÔñ& ›g–wó°ºQë°“08“[¡\ñÓœÖ}¤ÉÙé1ÑœƒA> ˦Ѵ µ4Êñ”ôÒÎkœ gY8*¤éMCÕŒp§›ŒpeÐÇ›R“3¤Jf̧JfÌ©×%». rSЙ]´å$97T±ÀÃQý±Ÿ§ÞO-éè:>|A£a‡7{%qæ“ VóºËÆv^#Ja®˜U.¸ c¦•ð¦O#Ë©Æ!f–¼©|t€,l5Ž1mä)žÓY¬C¨+w‡î‘ë™<×;ÏÈqë†/çþÎdÌ O¦Éßú@'5÷%î¥ |†dÚÃÜ¥ÃÏZש¾œ­FöZOöZ„z`³Ì¡ÜV\¨¼¬™O%»¢Üw*Ë)§k"îYŒýáÐcº‹èæGÄ,îxŸ_"ˆÉqÿ |‡¾vXLY:gà Äz‘åYÓ¿ÓX•·MT|™Ë쟰·>ö¦Hº ~ÉÝ4w¯8ꔤåÑýIxÒ¹×;»XœÏîóó 9xýÉòÜÁ;S×1ÍûœÙ:O`¾hÒ–ñ鸼ýPÊ(=˜2”Ox~m“,}˜¾^—¾¨Ê•>Íocÿò°]ß–®)9ùm“lŒo)¹Í OÛñ{.ƒC÷ sü­†¸DÏÈgß… ñ×~(Ä.ZP¸TN àè"*T‘êêèA °oÙÇ‚äš~¶X¤Atnø!(X7 ‰a'«ÅGæ¹+MjÞÌ÷ªOmf<¶~]Ò3ô‚—I )¹ù^à㱘˜w´ã×âÖqõ¯qïGõ¦=p{ò0΢0"¦ª0ûY×f?ØPHÒ|rÉ×Ê*Äc—ºê0†F]SÀðÇuÑÌݱoµƒ§5?IлԷçïK| Ñc±›¹ƒvWŒì}OÒ~Ü$Òª$ï–µõs•xŸ”‹AÖô[¨ýßr8ND 3;;Ž×^äB@+Và^™âW³Ko.oé’Òû[ø©ÃÞv¸Ä5g0}Ç«w‹‹ÆI—³^”·tãfûÓœ_Ídq'#b ~/˜lñZ€¡gœ†ntå«T‡¾÷y ¨¿EŠ€®±d¾+?K‘´wåêK~TvÓù¶Ý)µÀÞ’HÚÒw~5ri7Hûm‘Ëÿ… B> stream xœí\YoÇòÈ_±yãÚQßÝcìÄH$±ìÎC—¤ˆ‡(Ró;üƒSÕguOÏî’¢L! ‹ƒžž>ª«¾:{ß-ØÀ ÿ‹/ö^~/ [œ½ßc‹?Âÿg{ïö¸ï²ˆŽ/_B7mÔbF#àïáéœÝV,,gƒö‹½î/Õà¤ÖjÿÊ?)Ç÷/sÛi~:ÏoÏ–+ÃÝ`ŒØ_çÆð¦ÛŸÛŽòÓëüömn;ÉO?å··¹í8?]ç·WM>Ýæ·?嶫μq‚YG^ÓÅàk®™ˆ#Z[-0¿=Jo»ßÞ¤·e#ïcÓ¿ÿ¼ÇÅâð/{‡¿ý?ÕHõuz{C¦Ëo¯ÓÛLOl>8;ÚÏœâ-íñíuóE™cnä2r¦xMÿeÖkɉo !úôÌìóvÊz7ƬÈùrWŽZç·T¨¦‡Píô­ /ZÅHPT"h•ï—+6XÆ„rûwK>ŒbtHi_j-¼ès „ú¼_ÊAëQ©8át¡©G—¸÷{Xj40ìJΣŒãª‘õ¸+)å`œÆÓÆVÍq³+5€•ØU C¸²Øw5%áñ¸|^öðë¼±ã8”E~Éï¯p|`n¤\•.ã³d¨³ÜF6XMvBf:¯&…¯FÎ5H!F;€Q ( u—_ßâòa™W—e rn÷Е3<Í0c霸ÒQhSè;êDU5®ßH7¥GæâV$³ÜŸšðt'k9ÅYí „Â¤t8E¢ ׸d¡ak øñp <ø¶ ŠKáÀÆÒ©’µ\†£âè“&Më·’~tWöZ@Ö_MHq^Þÿ§ uRæ_G²ÂVN Y]o"¤‰Äô­']jÎŽZÉÊj¤¾a¿– ‡SˆdYÒȼd€@ DŒÓ¦é¨åý –\tP­[ŠqPŽŽŠçºŠ»Bîç›ÖcÆt( ¤¾Æ¿t-©€dY0I@PˆT‚4çÎÌGãéºÆiaË–ö¼L~Ç’‰Á>V T•é ‡Î‚RÙñ‘ö}C¥!•VíÌl×À2¶Ñô¾ÌpDbÿßQe8é¼ó|‹$êó’L&ˆÅèö?, ¼“@¶“€Ê"Á *ùú:§”äú$ øQwÿav¡y5;í™è‹\eÍÀlO? \ß(Á`Ñ›iª{ ÀM°ÞKœçÉ™Šüáßß•÷QnOhìåÜÏj™b£6ñ ¾ŠÃ¾Aò¾B q¬HöäQ(xSº’Õ5ž”V]§MA§âô@ßÿ Mä€ë‚GÅH r[¬œHZWå388¡ôP«Þ70%­F¢°'fJ&v5šÊø5¡yåÞàA©¸l"Ih!‹!K\çQÃJŒ†Lu†(àB;Ï¥‘g-rÓ4¾!BÂ.„Ê "%×Tž5Úw¢wPž3Te’x´ë•É1áÅ}­®È7°#M€AÖ½íÝV§žZÍžêêÓ¢œJPVE¯K+‘Áû®¸“ÁŽ*KGp6㯻vÌ&rí T\#mÝD¯ P„ËÁd‰`^xŽ.q ù`)äAHNE¶ªM‚ED¤‹ “® @­ËWÄÍ™ Å›Hú.P"@™"jOF¢½pÍ«%—pfÚô12<¯×Û::üàMìÓïFƒÃ¯šÚ6Äœ• )Ê`^ ð*ù¼#!”.áµ'á'µŠàÔŒe#ðrÇ F­mé•{í=¤I[÷›>]‚oᤕÔö¨÷Ôi-‡Jªv‘m,¯àð¸ ìW=JZVW^Y_?½QSK: í×·]Îo=»0C¹òÙ˜&4æý¢²Z¶Dîµ’9Æò÷Nüé.·Ýä§c8Êñ§ƒÜø ™¯K°S •@ÕM€ªCVp˜F X,æ’ ¦¶‚£®:!¨[njb¸È{:!ó¦¶ÛNÄ­Ä㎚pÖóNà 8€áÈäóÐfѼD´¯š‘sj¡M(|Õ9î– 3¡ÊnØ­Äõ@À‰@¹rñ¾BWQäãMQID>Î t¿™è¬ˆýD¥¨âqèK1ÐBÊ÷•ãžT˼C½oúªãW­#ÌC¬óÆYGI;ššÿÚn„³ìÂ÷Ñ,:ƒuáÑ´²»ùÒൂ‹#$ϵëÃ’ÅG²‚JOÇ[Nñ¤½®zz¤«|[0[«$ä $Ö‡žr+úd»ñô¤.Ef±Õ¥)3…_<ÛðÝ|aß×tY¬:×Y£‡Ò ÷ >‹è@Q¤h£Šus°h…ÔZ¬¹aÑQÿa9j˜6øé “K6ÐìŠ/¿ÃTÆøäB¿ÃIé0c©€c¨ #¾‘ëêǸ|çóPuž@89>Ÿ¶ >›ß)¬4 €u\ÞÇN7x_°?ËÄN°W²Aä‘,Êóe÷Q-/Kl2F=_Ô¾¾gI0¡ìScIÉqÌM¨ÍmT¡í`­¸(4ŒuС`ÇN7h[Uéȶbú º :*qš»qµ VÖ¯SX.£¢…| 3YŽJ€‚…TBîO- ÁÓ7ƒêøùÝy¢> sFŸúÁP›2•´)¸.r£–ëPŽºâ£k¿v¦d|msöŽiEÃHD …Sž“Ýtzvµ.ªÚWYo™8éêÒaãkñ˜[bänÌ7³q0ü—OÒ·D)d°¹,5æÃùc¥$Ž8ã2ô!¿l?«ÂXÄ@&Â#H `(ALyœ«ÔHè¿›©#q3ÅUAèBbFœT²-AVD*ýØÛªÝ;UÏÄJ‰umö¿%úèàw¬ ‘Û50Ye?î×MÔM-Vß·'¦ÿ=äTÞ¦´< ~7ÎBU®ã‘FLá%V5ðS£xaÄ àSð‘ÔȤ‰„‘B÷˜¾'­]Ûú>Ilì»DŽÎºLý"ÆæÅL¿»×¢ÐÈ oŠmþ’”N…`†°kB¨P Q+ë—IR3)Y?%6.kBì¶Zæ>nÑÒ”Bqrg‰ ¦I~54&°—Â`¦×E²G9§^ëi¶­-™¬·[ncåO±ÕÓ/Új hÝDúK¡Âu—šWí\~€*ÉŸæjí줱*h‡]›ÜÄ: êµI]`¤L¹Ö÷ð 3㞟.-&×íH•r?„ˆÖ#“`hªŽ§Üô%K8ö6˜ƒî—cÜ}è~Ããa°å”umÙðj¬ìŠÇ¦ï`Ù|‚o5z pÌþŠ|°ÙŠh"s·]ÅI=&¡µ‡È+Áßæ|F^ƒÝm‰ ß.3šËùBÁBžðV÷ÕYô®²@Ê‹ùŒ«î[¢¡í€¼*OÚ-G…KÕu|M˜ØŸFUvØ×ê÷ ¾ ()M,ebo§ÌLœ³Oúš oæ$¦ŸÃ´€5g²2Éx´ˆCp¨ïܬñwÂBt’ãt°F^WÙfÙ€XNÕ®û,bqÀ™¡{båq§Gâ@]>Æ´„Aèõv£gxÜFH©ýÛªøjÿ¿Ø0%„n¢Ž ;¶¦@(&h ~9xC1¬¾*eEÙÁ>˜°æHL…Qka(©®^@D›=œ-ÖÁ!¥ÀªA³6€tôL¡ÐDcc?ê˜ÙÆ>g$ÑïQ¨dÚ5ÛY%Œñü’1æ´àÆ,šà7ZT’‚WF͇š:•*æ&Ÿ.RÃ]*4êæUŠv­‡ÐEEz–%¼b3ÅÔO~O8nQJ­g¢-¤dæ<¥"¸äÚ)3ƒ.ïz>¼ÿU ¤šÊLK“9ÓÇœNZTÛÎŃiª'=©îÎ4.š/*Ô3JmGŒw&×âPÞ,|V„©#6ïmr|¢a"~þ3mËŸ‹ó×X¾¥Fz_FºÎZ£óv63ïKRS¹X˜NÓfñiìoB¸w¥õ®:z¯<™~´—8RVl¶ÎlöHå{4+Ä mK­fÓ`žFŠXtY8Æ®XY¾˜YtÜ•,cëÍû[C¢ÊÍFÿqVÇ6—{~lBM‹ó^él·Rª·ÿÙ˜t:´m…BÝÀ‰iVEò>÷jgk¶šxf¨dhªíqwÂ8*K ¥æ)~P¢WZ.>—OÊÕæûÎÕæóNeæ±®h󻿬ï;s%íÌ…gpi1öèw}Ž,4Á` ýÊJƒ›Ì «P\!€CÊÝæJ%u é*})¬ô1¨ÚJ U‚%¼ÂºS0[qÐo÷¾Û{·P€÷ƒñ v §ð\1ü=¾Øûú`ïåÁ_·7w'{/ÿ±à{/ÿ„ÿ|ýê÷ðçà‹_í}s°ðC .ŒÃ5#ãHTgæžf öGøLZµñA‰¥Jg-š@Kr”> Ü€q¼Ýõ´7ëÓh¤bñ9M†Ø›)TMÅgUxcQ%HYB^uêÌ×»‰}–•Æûe¢é/?4èY–÷ãr*á…z˜†ôÞŒœhˆ^É[Ê‚¹Æïc!îçåÒ&Ѥò¤…Õ¨YWÿ~2ÙL—i8ã ƒ€.Áúcà±d_JóÚÏܽKõerg?t;MÆZTÈÃä¯êlò¸õ¦øÌš‡ë°’üÇñ³ › [ö9˜Ø$ÔHâZ¿¼kG©%-õ:W³ð\·ÃUïD–ÇÝOÝ Dk5þæ_Œêß³üUöï:wÕ®»o³‡X.νÍÎ[ûChs¿v×8¤õÀÓŽ[XF.¢Èoѧ’åmº¬öŽpBYËIjú0ýù±Üývú]nºO×Ó1ßÇ…i¯bcK¹»ä§¼hf‡¦/ÓËrÁõC=hùå9kŸ™e§|S~Ö.ß„½+ËÇìJÓå”r§SžÍ³¯3Ï6\Ÿy{W@©”_E¶vkøHš‡§%tD¢HoËã‰TcøÝ£Ôzòþsìû:9vƒOZ ŽFžP¹€¶lä ŒyÅxy ~«Û7gº³Ó«©ëÇÒ¨Ž×6~ºÙÙ7ú•ç•• VSVÔ7c½Å1QúâyñûUmµ6åV‚¾\¬ÄHòw<ïÌ–sc¶“¿Ûû/£çªúendstream endobj 1442 0 obj 4497 endobj 1446 0 obj <> stream xœÍ\Ys·N9o|É_Ø¼í¦¼#܇ËqÊ–•X)[–%–ý`¥RIÑ*‹”DQ>þ}ºq60îŠ:œrÙ„1¦Ñèþú@Ͼ\±‰¯þ“þŸÜz [½:`«Á¿g/x²JŽÏW_Â0®¤]ùÉaÔêðÉA\¯¬XYÎ&ç?®ÙlÅ$4rý¬6jó"4¬óŸÃÜ9<øîàåJÆwmÕäVÞèÉ9\TOÌ!_Ü=¸u÷›ÕÕåëÓƒ[?¬øÁ­¯ð?_Ü¿ î~¹úÓÁ»«ïÞ˜rï'åoÈ?-Ô¥„&é­ä¯¯ví„KÆ&ó!¶Â¥€Îf'•ºõïµùb¸©WÍNP$8}‹T“çÞÛO`åíf+¹”të6jRž½þi³Åcó^âÂ|2FsƒÜ’ÜOL{ ‡ÁŠZ žÆzÎõúiè•Ìr$B2?&ÖÏãbÎ"½y(Y€ÌªCñ]ÌN ^Û­*€é¡)'m˜±™B; «~ŒCÝÄCòЋJ@}ÕåΘ¤%²Yr`Ìÿu³e“eÌ™†Âgõ Ïð 0S©õë²Xx—v"œˆä 8Ü“Ç=³ÂJmøä…¾¦½H`üI™$à@=œš3ð\ˆI ÍA  lNrCç\PoQ`y9¬@þïÝY`+ üãu>Û ô­aƒYVT: ù¨2¼ô¤h–*M]< lמ¹taÀ%Гtj}·¸ ’œ)Ôcj˜Ô 8·›š]k™2 w çŠÌ]m¹ˆ¿LÓ§úÏÚÃù7ÌÌk³‘vðaá³Ä‘D¾~ßh5I8ê ^#uVh±Á³ÎrTè-žE˜2°²·å°8lÉ+WaÅ3fn®4ЇMãÿº‘q ¶BðB`F@¥ onµmFß 4I ùv¢ Ú!v*¦Aäï`“oSØ‚…×HuŠ#’å5€÷› ê §‡u¸fd€ÐoÌdÃVÀ TˆÊ°G9 ¯’*­è±4 8kÕuŠ› 5.B½°ð? Ø<¯ÎfÍVî@윈>‚˜ñ ü Þ´ D¶PÌ? ĪŽV!Ù¤¹ pò}¿PbÒÊ'µÂÎguäѤˆZfªMF†È—C8DZƪeb@wàøˆfŒ8®ÄüŒ;mäFÓx üOpM;q·Ï#t² ð)cçOýQ!!G=܇íJÈþѬƒúH%è4b¼È¼7²lc¥ÆÆ#Ê`Ãö±Ñ'Û!ÔÎÍg˜M1ØØB­5h¢š˜¥iµvý¸!"¯öºö6o"-Ž2:+x¤(²haõ ¡eí$üu塞Z:{àKçÃ(%‚°Êr×K+šçÜËbS%äfë–µ×ë¯ðX=¸TV›-6æo};šÒÁÙË‹]÷a-¡À¿É­³øX<§Üy¹ Ö`¨¢`ÇÙW`¦­ý?€Y¦˜šÕƒ>2xg ™×AI”«©éZ/Ê«jëY\Î?ER4Cß!üGYgèN ´Ñ`¿>8üÛë‡Á•óNPHO:Ä´¢ž*X/ 6µNEu[‰&ð'/(ØÀwš„L†8W6ë“E‰!«Îòy”Ъ4K _ÌãúÃ<€S©…„ÔЩ¿Þ¢Ó»–«ˆ uiqmºêÚüNRm¬AªøJÝNˆ%Šõs:Ñß EYS ¯Y‚¾~¯cmª¹åØBViæ_‡çg™DI†Îà­WøãúÚÂ:×Þ[À1O!)(4g;X—l§RS[V)6 ÞÜ‘ÔÝD‰¢±è’tÑG 5Çéí“ÖQðÇ]«¡ÔI«†Î5Ôy;H[´¸ðQÉМõºâ«égò!@!Ü0„tK7„Ô‰H’Ö©8F·Zús*ÄûF…Ç*F43æœ5îÆ„Æê¸,ë šlŒ.‰˜Œ"ÉŽ÷’ál áÌ›d‰¸fæÔ£Øx%6öÏ —€*GNó éÞ¾l+q ÎlnufSGª„s]šmæáÒY5MóÁµ„;ƒ»!Žß0¡t²‡à¥¡ˆ" €‚/$¿:i€Ã™Hk{yœ…ˆäÄNgc³ÊÂXãf~?®ÀQ!¢YuSÉø †?}x:T«v \:N3ãúj Éˆö¾'Hƒ~G‰Ð`9nè·¾BÉðxaLÇ>IZdõ[XRf&õNLf’YÊ*õ’Û¨1‰3„™Û×y0ç´§ðÒúÆ!ÕQeæÃ[¾àQ6ÓZƒ7ÿÁR Å Æ}§´s”¿æŽ4U¼Ë™Ïé4œÛ›fÔ’ûÚFJLŽïÉg¾ºRTf?f0´F틉sk&)4Í– Ì~¨²)  9L¦ *[¼&£ÞåW!Õ&åžÁ!·`¯|C¾³T,\“$ŒšaJø``ž‚öŒñ££åÇ1ù'(»ï²‡>¾—kiñ Õþ졚…Y}><_-ÂKn¢HIˆ@æûêŸr‡Øä.ZxÊaðã†îXD ¨’T["‰w@èîîé’cÜ)ú\ý‡u7,\)‹¶®k*P“T& „2&&òµµÈ÷ò:×ÒÎk7Çz Š*ÖŸoб·#w¼¾t\#0ÁPЃ¸Rúx­œV±~HCœi×ÊìÓ:ûŠ—J™tEïC±Ay{¬%pÖБq¾ßÌÛÉ¿õͼ¨jÞÚ§ÓÕKwlDìdc{Òƒv´„ñ_aÍ’@–% ¤0N©N‚{}mª¯m™Z–ð±ù™•™ÉTs ô$ÛŠ0rQ¿ËC%³Ú{ÈH¡˜§”k}g# qƒvHIeìØglä)0×5g×=Ù] ü{|»B¼òÿÿãòx\²WU±gâÒM†Ðº¯ëïÞ£Ðïª3—– BK(o4»ÔC.§GR P…õÚ78ÛÞÈ–›ƒ½Ä À­sÎvv‹HÛð~R†Å»æ.íÃ4µø3¯”ÚvÙêöÙ²©ÖQ†7"Þ†¿½c}54‚cfhØÆþø¬°=Ü_73j!\«µÝ˜ ÀbxIŠïwVv§fWÙÍke÷‚×kiI±6©›~ÜWKGô.Í:)ÜyŠÉqQ .±ü8—SÓjn3Á\ŸQ¸‰kÝ ¡D¢ÃP/èb%sœ>h„¸¢õZ¿=,4'#ãl±€Xµmjø;Ö.Ï›"³±DdmѦÍD”Pvø¹˜ô®ûç=˜GJ^ìøúѺ¬_‡ÎÃçΉ"%Ü{}E}i>N$6ñ^Fºt^Xæ;ˆ°i¿Wb’ƒå·ÅÁÓ´»äcŽ6Ir´®ùMù Rž­¾Hºð=æ‡ö'ób·jï0Âh’ªeè£ Þ‡ø‰ñö~hü5I9ž 7GN–$ ¹NRÉM2¤géâÌ‹+jÑ&n›Ôr†EûÔ@Ýz~U}69¿ç“ÀzÁDù\fÚà§°üª[¥uZXªò<´”C+ûž”¾§¥uVž¾.}—¥;4Ê‚¤Šõ¶tnË”Óî%Ø:*O—¾gdÁütÛÍÀÖqi]…–µ‰RhüÒ­amZÂÚ–`€`1¤O_”‡ÏãCÍD¢×Ú4,ïÕ¡‘ÀÐ-~˜¦£¾ãË2ðóÜu;7˳»¹ëûܸSžý7w=˜?{˜»îçÆ·åÙ½ ÚRàgª:«öÃÙé{à8 lNþÂöEËÒª'Qt9ŸãŽïø´2ían~ Šg Y‰úøŠàÀÅ€{UÐú}«à;-¡XËŸž£KO;>¶TìǽDs“8žq/…Q3‹¸}Zôñ¼´–¯™Ã>KG$$ˆ|þüøïØtp˜òcVO¥¯¶DyZÌ3<øÑ>–E`$¾õ nº~í>dyʺ“Áã¡^¿X ÑÍʃÝgˆ†8Çd‡ ‹‘£;>ˆ¾18É7F×ît~¼ÁÕÔì»öÃ(»ß·õR‚Çéº0hÅB$ñ†ÙÔøüÍ>!”kÓ\Ú‡Nïo&3_ÉóÙ~¡·¦õÏfŽe÷QûÒׄñwfäRâ4:å|¶|_¿Ç}¨V ÿF¤ùuüÁ½ïO¿@À*µmo¹âɾY‹Ù•(¾ÿ‚A* ÒÛ”¿´yXf³o?Zš]/6“¬¡ù2xé¤ö`\§ÐVDçŸå9šíLòwçÅG\ÇÀp¡õ%ÈG óÔ?BÄÏuÉëiù&×XÀ(mV[+úàKx9V[É4#~.ໃÿÖ¶å’endstream endobj 1447 0 obj 4312 endobj 1451 0 obj <> stream xœí\YoÇ’·ý‹¼d×ÈŽ¦ïiÚ ÉR¢À²e‹@,à ¹<óYò3üƒSÕguOÏ’2¥@ b£Ïêêꯎ®áëyß±yÿÂsٽï¸î燗³~þwø9œ½ž1×e~íÌnc7#çŒuV)>ß>˜ù ØÜð¹a}×ËùöÉìû_®X7Åì¢[®úÎ #ä‚åÚP”z `˜µªSV-a­é{©øâ,w>] ìËåâ©tè›…Ö‹ëTy±ä¼“̨ÅþrÅÕÐi®/RsžçÕr%€nkÅâ¼UyZ¯dü°ýOÇ16·Õ\Kd—Pv˜o5Ûþì{Ø€ì—V#ùª?m¯~à"·Çycûu.^,W²ƒCn½î$‹«%°JïÙâ(wÅ¢ïãaz®œËr)»Å(Öi­˜ÆµxoaÃŒ{µœuý ;¹/!Éda1¥‘¡i2Ò÷æe¢ƒóð•¢7n].dgà¸smXW$Ö ƒY¬‘.ÞéAa{Üù6·B©Àz bö»êÎ2³ø.U¾@Î ÖKL阱‹Ÿƒ¼ šÁé'F ·Œ©ÐÁÕžb,§»9JÄ’³¹IRº×X‰ĵ€>p}¶×per«+©sºÎYšñ4Óñ—¥R•ÃàxÊUÇ¡}/óì:wõâ¤l?DÉb*É@æ¯ë{…â´Aß ¶Îë\<[²¡ãŒkÆ™~›ÅËE^ÙïQ0w¥‘m¦ç,'¯ÅàÈáê eH¬…Í¿*eK˜NCgØ«‹†ñ!nkÏéæk¡Æ(s€o áá ¹¾ï‚Ðj9±‹<ø*œøŠqæñP´¥(P+$Hí«%œo ,Þd)1ÞµÃHV¼Ò ž'äy¹L ÓáUê€qd™ŠÉÒvÂÊ «V¤¾N²zÝ„B*ÖxS`_rß|-‡‰„ðˆ:(K°â0•~ Ó C9nÅè‰kAæ'¸DŠ(Rwf°í;zœÉŽ]­Œèm'«x€IÖòˆc/ù¶7Õ•D57Àí;O]Éhã Ê”4(Sºcp3µ;É;%-Eò3о•t#Á(>–w=ÀëÓÌÇÓÌ›xø$ÞŒ$9®àˆÑzLL>I~6\F7\!‚†û5‹žöKôQ XV·®€‘;®K `p2ëH‚äŒÈ‡yª£8yvT«µÑDá¨u¯¨:-\œulâ;ZŽi1Ü ;aT“-~îdSÛMfzÉymó™LF–¸Î»“ÎíÍÞYF!¾fû›(ȱ·¬À7™v—­èÄÈ]½ê¸¥f÷J€¦ùjkÐʈä6;­u‰óÛN³J™ÃÍ»KU´Šž#öÜ]i&i t¥#ùëL©vâò,¡(^ùÑ•»¢ï;RòQƒYÔ –] rF§Yü^N¤Ê,“G î½m±â:5çkºÛ|qL¿HÍYwždøéã³âz«‚ôÓÖÿéU¸3hÈAwB{%¾¦F|£•lâE£|áZw ™+c›hN0ïÄj †¯ÚàÄ/(Ôü)½ºà”¤±ÐrsŒoò®Ûošb?/„ª=ÕO!*ªv=·ïZ8t?µ«y"<ù僚±W;•µëÒŒ½&€k@? ëc˜FK÷\\=¥ ʽùSŸmìÈíŽ y¤jwüæ1~fzjFÛÞŒ£4•»wÕdDdŸÐU˜¦ŒT¡­ê¡ +¸&õ6 £ ñ[‘Eñ÷R§$3n³¨(œúºÁÔÏÏ›.‰ƒu°4àÞ›a˜ˆâ„})[¯K["Yxq¹ÓÇ̦P}€ Cë#ášœEEÝéˆUØ!_‹ÁÀ³¬\6òŠzÖ è„ ŠímƒuØ7>˜ S…1âÞmºgÍÈkò õ$Ðmé õ,y'€Vé뇠ÇÛ³og¯ç§ê7†ù -ºkR!Ò½“Ùç³{OŸÍ¯.®÷g÷þ5g³{ÿÀÿ>¿ž~9ÿÃìñÓù·Ó‰?mˆLg1ëE*¸œ!û‡Ðʘ½€ã³·kÐ7;º õÇS'†„‡oãÚ¥ÜmË`ÕöÇ‹ˆ€ÛïŽøËG6Äž6ï6p,ë¡ÑËl2¡@yr—*%¤Ä«Mg]÷v ÇZÏ ÆBq¹)üP‹‹Ü"Û¥â«D´y´p¯03$bü$Æa©ât x1Gh"­éóîq' ­0„zÓ(VŽrû&” Qé”)ED@¶C{OdêÅ7E$nsúEʉ€}óõ:l^°üxPdµÄH’ÕRXxéú7Ÿ’ÛpL@£Ý·¼¨>œ¦—C8wš’HÆ)ž“ë;ºS8R¬D?Ê…Ñ æoaBiV†×wÈë¹°1­„¿É±D8ñovørò+_ “ôÇÌ Pæä-ëm©Æ!Ä2ÐMVØJµ· ôIÎP·; ò©Æ ê Q’È^]ŽJîgºaƒ£XÕ7ÐæO&¥ /1™QxIe¿-;û[eô¸Ílhû²,m*žŒÛÇ‚òŒ ‰yU Œu‡TðÒ#ÌS`²\Ý%OYä<å'ØCg——“†AåuBZ@¢·yŸ’Ì¥!ÍÔ¾MÙÇSÙÅ\ö)Jó$åðö(Þ‡xyJdž%Ÿgøœ~®p)\lñ§”kâ²Oo[^mÓ.&N7‹òâ¤LxiÍIÉTc·™dPV)*ë¼ì­²}£¿¹aß›M*gHe Ô«F»èÅ»ÿ³`w8íÑÄÓnå² *lìòTOÓ¥‹3|Ò䆼õ1)Ko q˜v¢Ù(í€È!5tüø,iíwS"tEVTLÊ"j®ÎóܘIsk‚Ϭ˜÷™yß^Ì艷Îß% ×J6e#÷åý5¯à˜NñöÆv0ÙÔÆÛX¨múz‚σ‰PÀ‹š%OpY&%÷u,ÕÈ‘—µ•R(o«Ö/â«Ûïj½‘ÂçNÁ{ÿÛ~r ^³é-Éj¨õMáfý^øáYÑ9Ÿ”¶ç3Ê…³¬Öjß?«—r™Ò_Šœ$ƒ[Aà„^leæÄŒOžiù2_mdÚd<'/FxÕ›…¤üˆ/¿¦œ4ÆfdÞ3e+‡Ì¢ÙHBzU”osÛoL’Z‰)?W³DCáQߎC·2º™Éþ¸F·¸Éè.²KBª };ÝÊ9Ù7~wó#hÌ4Î=IP¥J­vßdÒL‰öÔS¥ÿꃅœÿâ8i,Iy ¹3t,1±Ó§Rí¯yoøÀvÃ{UGø†–˜È…Ùí0ùp?‚Gb@SngCÌõÚü©ÂÔ§@åqN>äŽ^óJ[~Ä“ø¡—s…¨å{Vظ.ïÜHjØ#¸mØÆÈ¿å§þáû;ÿ5·fi1LŒ!öpˆ¡’tõ›ìa†ï€òw{¸›²‡ÅïöðG°‡Ñ>öpÎ>N¥–‘y•2ƒëÌcyJ ¢ÙšÈü.¤/³ÉÖ08 ×}šœ:–Ö8# ÀumR_ÝÛdr«Rúlm!¶ÛÒƒâŸc!”ª>÷ÒÁ{¾1=žX±-%¯ßj\6TF‰í‘6¨<0ÆÚË#è’rŸöÆR¿ÏcÕûåÙZÌùB¡ ÆK0JnÈ¡÷Y ¿¨$1³ëÎci"ýŒõ '…)]ÚÝÓϦ©Í ú±$> ÎF¶á'M†—#ÛQ…$¡b‹eIa^yͧŠàdãÃZu÷·UÕ^qCîC½f’ñ¯5ËÌ"ÜÈû¿]ÀrùÃ…Zt[ XWßãy·ûáåK*d\Ò?ë3vUò ?6ZO BølþÜä¶Óe¯)ã훘Âã|¨ÒÊmÊ1É{«Ž£þ±t¶ÀˆÚËÜœ†Óúê¦æLVS&V™g#ý‡Ð ÆMSPh™´÷”„ÓPWa¥^䯈6+ŽM+íÆÂYŨ:*VŠìNßæSN›5TÔiƒŠ$âdå)–Q–VbSÅÉ»*? :«øá¥7=°¥Ãzÿ5êL®ÂÎK({Þ¥L¥ã²p“bávÀ/‹ÁoÃÄO,!ŸÉÈ—RB’ývö_˜ç,‡endstream endobj 1452 0 obj 4431 endobj 1456 0 obj <> stream xœ½\{o·ú§>ÅÅmÑ»"·Z>w©8’ØiR8‰ëÊhÛ0ôòɈd)²[E?|‡\rfø8éä$…á˜àÜáÌ3Ã^~žõ˜õþOü÷àtkû©´ýlõn«Ÿý þ®¶~ÞaÈ,þsp:ûr×ôLˆÎ#g»¯·¦Äl³Aô]¯g»§[Ïçr±Ý8áæÝbÙwN JÏõƦ¶# KçLgœ™?õ½Cßk#çG Ù)Ó›ùÍ:ð}Úéq~¹Ý`¥²/wÿö!f®sVZ픦ºq¶ûxk÷¯Ïç‹¥î¤qÖÁª°˜µFØi]kµÑ°.ö^.–R˜nÔfþf,Zس˜¿ƒ^i:Õ+?MŠ±Óƒ‰ëZè¼Z,aÎ蜚ŸÐ¬£8Ô‰ù 8§æ%eccßúúÎêaþÓÂvÂ*`ñh]jÜüšF¾_€‚”Q†O'a‡nì¬4ü£Ç4t¯MÒR'Ðå„0i¨ïݧÞ|ßi€œPÀÃMÕÛC+Ò­ã²ã8xÓRLD_%Qðï{ùHÙÙÑÌ¿‰Ø­˜ï.–ðM§Œ™#:¥zÀÌchöc׃æÎqÙ½…G4ªS@½{@^!5i°w†¨”1€Aõ²½=ê -3JÙÐt\62ˆ¡Ø^’ÉaÐQª’À\¨AƒÈïÇš+%$ïd°hÃ’1³JÌd»aÓàxƒÈ»ÞÚ¤‹Q[Îmq¶ö°uÙü\¾Ê0Ä {K;€Z@›Û A†H q ?Ä©R×÷©ñÒ¾L]SãÒ^¥®§5í‹ÔõUjì&ZÓ Ÿ‚ƒåÜÌ*Õ 9é-ÂÒ(Ç­ ?ïZÂáH&ÂõFsO±ªÇŽ®Î|¯í®ûõÐAE;à´æ®ˆ¬œ‡°O;rŸ´— ËÃGÛë“ɯ]o&þbÊÌÄ‹Soܸ٠ðíæÏë”èuº¬èÄè}LêÜÁ)ŸGð rþâ7dRÏ–Í~G! ¹‡³¿ÁÙhúXë R·±O(õTÏŒ•}'rdEŒ}]œO¦cF¾…\ÙaB;6Jÿ]q¿Ð¢Å¨‡ÝãRñ–{ŠçI_­õ´¹Ï%ZVàM±É|îNô¾`iòIãÃïæ‡wJ›Ïr„»lñ²±Å•ü<¡å©ççN¼—}(>{ ÌS¸§…ä ë³(Wð?^סŠ­/_þs¤]U4:馌 U”êAz"WžÌŒqb~D*e{ò­¸¾C?Á>Š­~@êW µþˆÔ'Ø÷(x­˜ˆ \;ÓÑ7ŠÍ~†¿Ä> ݾeHžX2Þ«¥¿]æ_©K¥íl»š÷°Øuè0ÙÎ9=ÿwêû¦ö]j<Žû£}„.rââN븖iø^Ñ·Ö¾y½+$©Ò¥óEÖ8Ò[¦q¥K?;‚7t5^S¥šs…Óß)äœ;÷EËS©¯kŒS¹8¡Af "ˆ„«Z°»ÑÀòiMý@Ô¸LRѼßDmB©·ï¢0™2Šž2Ó$’0rŽºQ$Ü\Ð@Ž0ß©ŒDXYÂjZeéÍOcñiè©'<h’sÃG.r ~òcᛩ uü>oN:½€´õ)l”éY}W <‘ÖQ]¢:ÆR?$*ß+R—’™Zq†Ý©WAÇ­°–J}¥qŸ×¶Œ rD‹¬% ~PÉ4ý¥“f¤)±™Ü¬eÃSéà=(‘·‘ÃÆ0Õ½M†»ôMü´ÁAyQË3ú ó­ÌÏÏØºB*…µ¿Z-"St[ätö¨œ2D+F[<ÐD´^'*4f+@K ˨—‡v›E#$,¡ÙÞÌ‡š†§»iú§Óc:gЇg±­ßˆ²ëc[ô‘ø.ßR½h<ÃiÏ|‹½ÚF©úHÞ²€¦<š3kަíê“9 àÆ“IR#HÄË´$QO¥¬áAÑÊÀ;Ö‹ËÃbi?åmÁL#ôÄ÷Sc»àºpíë$_ œÃï–à™~ÈE|óõ ¼så{Ý+6–‹¶ºü6‘_‚H%\Õjó×¼ ‡”#8+¸ñÔëßÉ,ß(4•hˆåãóó› .§ ¶/Òx%ù(\…H¡8º¨î¼Žoý©ïŠù¢5÷nŠ&ë.Š%Á•¨Ë%]¢î7: w9¤íË÷¯c+µ>KÔÒËJÙ.¦L¿e3©G^Fž²ÆÚõ¡~®¬nÖå’ó:²Ò×îÖçÓbeUAKòÚJÚnt¡¡;'UU9”Wã·¤¼p’WұĂ¼0fóB§ê'«Ò.2¾Ûòª€Š$±4#Ì´óä?º¢—êæigç´lV.Ž-ª+³ÙŸ.BÈ,¤áß§I4”q®n­ÅOÉi0½`µòIXE]¾®Fë <Ò×TèYó‰çNÀï˜×àSz¯,ðÊ·rY!‹·9íl7 fþ- ÛkY¸®‡¦/oŒ=LKðß:h–ƽdåØtß ukí½R¬³½á(ÊÊô.NäE•Dg“þâK5ÃØáHô}'`[4’qÍøc‹¶·P2ôZÊøæÄóÀP8’¢ÈN” tˆ×>8ªë”cöJ†ª«LÖtAzSÓö¾"ü;I­¼ç›ÿ¸€ÆA(n®¨&Ú6t2ØÆ<‡Jwƒ6|Õ_÷xý,u¦òXxEŠr!DJË7O+%ÓÙ5=}9o ½.x‹ž•#ãQ  E×Dª‹’eƪÉôeií«Ù“ «Ä˜LHÚ‰“Ü0±Bti»Ë’s“î•Þ9mÌ€8`:t0gœ¾ìÓ΀Lð:ÇTW=¢jª¶;wCå4*q“Ç`þ©¬ž¹@,¡…¹Õo)Ý(Ùû$ö©fáŸS?õ¯Ÿ†ðfçÖ*pPù«¨øòék¼vÄ5Œw¡t7¼Šª7Pœ/íÚ¯±ê'jÌÐ+ t"¼& Ž ±Ôøý±·<)½vð9ôýud¾:'«²WKÇ­ãÅX=&h¶\eU²÷ìÕIÓÇWWr4…Õýø·RðŸnü½+òCS†yÅ¢i Øï^‡¯òT_£ -ÖöÞ–Hvç¾`—FüÂ^ce6Šv”ߤÊ47¬ZsxµBY±IÔ›V½{è FÌLQÀp-²°çdWÉ|ddo¡ó¾”k¼n9çœs:ÿ©B‹Ã˜!W½0¿kô$ÿbÆÄqÍD,µ+’èM?)D ŒÑ%WAÍoô š‡¯©¯\&^_{_½’ú)Jcjă( |РÙÌØõbÁ±ôÀ—*Vç³Û™õúõ;›*ƒ]{瘬Êó"†ËA:/ñÅÚó´áOÉ aPL!!âè<5Ê]pZ¹^#~™hÅ`BH|®¾öWÉ)äÔão>þÇr˜Õp¢3·–eHn~ðN fZ¥ýÛŒµ‰Ì¸ÔV66u€£ÿÉ_/7¹=ŸXÍo2%Vs=H7ÇõïÔK¬Þý7ÿÅ=Ǫù’¯yÉQ-Ãó¶Ù!MoÑ®éAêýzfí$è üñWžã¢ÇÝè§Fù:ÒOUÈWÍèïm3x;Á_oþÂ~1Ú8ôë‹õ¿= f½É–|R[«:2ǽƟI¾gy{¶Ø>¥³6H>úµú”¢JiÆ)‡-«*YJ3¦Ð¼]²Ãl~™¿Ó—p¼õçŸS„æÒ ctÑÞ ¬¯#¿ùÅ(1,Ì­ Ÿ1õµG²¢CX´n]üm*»¦ ‚i$Ïs¥®Lz,›êÉTÓ54Émú´¢{ö´Òät£œš¬Xqïôο¥Â}·.¦ÝºÅÈCŒI\à‹€œþ›¼]ÈMTÞ®ü}bÌH¸ÞòÅ.Zɉ¨ë„%mø¤f’ õ_Ç pâH/¹©:ZT´öšZúZòfvªÌ!俜ŽU NBÕXð”k^`.ÊvÍñmþ8•9Ö±˜ýøHK6ý ]_É.Üö¡v=Ÿ‰kƒbYx0À äx~%›sv';‹Dt|«ÓçkÞí²«¶ìg'j mÛh¼¥e/©hí‹,Æ„Df§²jêº ýÄAfl˜¹)$å†É¯ÀòD{-v'1©«ûYY2ÅÇWÔ›ÅÏEíÜK®.?oǬU©.ÌJ~7øÒü?Âêàs˜%¸I1µÑàçÙ—¼\ö?¶È³~Ég²µVÅZEb´ -º äé?)­¿2-¥c~AààÖÕ©ÓO{´»õøó?Û{²Þendstream endobj 1457 0 obj 3999 endobj 1461 0 obj <> stream xœuVMoÛ8½ûWè¶Ôb9$‡Ç.PXì¥]ÝÚR§Iƒ®“4‰[ôßï )š#Ù…aXçó½g}Œ†ÁðgùÝv¯ÞÛ`†ÛçÞÒ÷v÷}ÅeX~ö‡á¯™Ý¢tF´Ã|³«`ˆvˆ`´ñÃ|Ø}Pvœ@§ˆ•'£³‹Î+èÖåч$pœrFÕ{¶FcØŸæ¿Ë$`È:<·h=Ìi˜ÿÙÍ~P3G³]V_Ç uJ­ô:«>k6ÈåRgFœ¹ù=~ãkI'«®ª!Pe'×ëåœ&öLõ"fï—åü<cßCµøÞÉÂ᥸»Xìý),Égí¢ìûj´4;êÇ4G!Û(h²ŸO—¿Ô”Á¥öèjðV^ÍîL‘ò¥ŸÆÉk‹Ù¤¥º €<ŸÅõ¸m“Š'鼎6·I°•{  ½uu¾Á„¨~õø½”i¤V}òañäãÃÈØá¾sÎĈùšXÀÑ]ÔÎguSÊ€N,ê‰ÛÚ‚<]ò|äÙóªúûÕ V@)\÷óËã{ì·^VÛ¯ L˦‹¯Ø @Gˆ†I½@ÁÒÚŒ4ä˜e.¯V,:¹¬‡íØs ×Á¡‡¶âb­=:°ç¨mʶ±±eÛ‚h÷ç¢)À9L#Ø$æÌKžÚ–'°uÏñËv<=®hHˆ‰O 6Ôc D§}-êuCŠŒt\ ULÔoÜ®p¦l üúB n;§;V®:®WcÞÀ’Bs»’|y# ™q¿ FEÆF¶žå-|:Ë»aä‰N²÷ ˜Å*¤„¥¿ùUئ5õ±Ý:®D¡ì:»D«þ¥‰L+õ²]QVà‘ž¡KUÕŽ †‰^¡R2P1qù¿_XE뿺C#¸“³kÆNÂB¨Œa"/RÍ '|ÄÞ6#ßz3ïÞÑçÁÛ&‚endstream endobj 1462 0 obj 898 endobj 1466 0 obj <> stream xœ½\Y]ÅŽÈÛüŠ›¼äÞˆ{ÜûB¤HHp638Ãxbì/ƒ±”Ÿª^«ûô¹Ë`_ÎéÓ]]]õÕÚ~¹b_1ü'ýyþüäÁcaØêêõ [ýþ½:yyÂÃUúãüùêá)³j%ØdŒ0«ÓË“8_Y±2ÂOF­NŸŸ|¿þdÃ'§ëëÍ–OZ2.Ög6i¥ãëÛúô õÆÀ¯‹˜ŒÊ®_m¶B‹És¹–å£ÿœþ+¯¯&ë,Çõµž”ônuúï“Ó¿~¿þ>œ¸TÎá|’^ ¾þ&fÊ‹ÁC¦”Väá‹Í–MVq¿¯pe6I§×ß’ÇtÈ ,µ”¢,a9N „O^¹õc Øhí­]ß‘Ï~*ë]ÄÏ„ë×0—eœ‘Íq5IenÎÈI9Æóæ$~ç¬4z=áÄ^ƒíšo¶ÞÛI±> Û7ÊໄÞp\·$ೇõýYìõf«iÊSð0¼[Ÿã&¬ãڒ׉HÃWF <ìË»Öõ¾Å„‡“žéÉ9ï%° zl…³ ‹ži\O!£ò€×@8pO©È'c€ÁH, GÍ‘pa >'Cr=0û9.à…†÷·•‚Ÿê€4­æfý!R€ [:€LvUg¸®?ßÔoñ Œ÷Fj:ñÎ)œ [—O01Äp-ð}¤F2ˇ\pë§ehzoàaà‡aÆÂñ•‡™áÌ%ªÂ¬·„”òPNŒsç(”㔬³JÖ‹2×Uýªî…Œ¼Ú  ÿ¨qú¥S‚Š$(³_¾F¦51ÎéN2S¸ZÿeOr†¢ÃA‰=ðô—2ùæ‡F ­Ì|saKOq€›÷ë—e‚»úž°ïÍpÚÛ:@ÄM‚Ãà A–1g8=Krl—õ'Y, n‚‡ríS&±0 O‹„)Sö;(wUé4e¡†h]d®7¬_X(=qå©lÕ­¡`l£dl9 SÀ=JÎÄ\É•g¾l–# xW’Éfº„<Ã%¼!¢N†¢ = Gá& ‹°YÙ¤†Ÿþ0Z ¹(À‚iÝÈÍõ Po%XJàÝ¡Áb®Þ0&%CÔá¦|s;q"h4aZËl„ÿ ‚/¨°ç©ØeöX”v’BÃLlÑû '‹ÀÐÖ6\#€@Nû§d•Ü[ÉÐÛ„ŒÞè%ºtIu ÉH•ű…B,aÆÓÊ×w=7©¢ª¡dH9qa-2x\TòаoË”T`ßm@×¥PNÀ÷RZÛ¨”Àaf=¨¥LðµÑ_à Pc©uOl`:ðÜøÐír ÂϪáˆúð®WðÞŠ£LXp•lácR•ªuºÉ6ƺ¾žÁ6ù”þ¢±Â2äc§ Â!Ë¢wÖªAÄlh)ÛM˜UŽŠÿXéUp`Š1Tël$ÄõPm3³À}» • ”TüÊ{N%‘,¶Ïô½*j)ˆÏ_g*MÇ—À@ØÀ–%C¾V€! ÊŽ2ÄÛ!3 ¿‘8Ó\R~Séãuª'k×<•ÎóáתþgÁJ|3ÂAbw[Ü)0ŽÍŽ3HadÉΆW,Xtîüj-´0~lIzløÛû-Eú0r N¬ ‰&"ʉH°¬è ü‰@tþ]dKÜâ ´~u¬1ºc¬yÓûýǸüY¦B ‚ÝÖ”Ÿ+Î) û9ktˆ¸¤sï¶A4 Æ.e7´zÄ>œ×ùŸQ™ÈÚF6C¾ªï+Úä(Q4Q"ó“.€P(F”68(*îô0„"~,¯¯mê§X¦êüerMÍBBf=•3ÊÍ$T´¢Š%é?.Z–NMÊó¹Îì6Žô×i¾h¥³çY®’w -‹nâ—™qLilÀбÀ·þ±ô`~MšpM’a®¼—nì”^$ŸñõضҊlU^/†¢H0œ–­SÂ)¡&-Å'søGWZ`¼Æï£aíí(Ò<†ƒÖdJkCšd1š•€Ý,ëÒ=ÈF cü\²BˆÛ|SÐËáœ_k㲊šžqˆœvÃ<_Œ#“,nÀÐdT¥Ñ ŠZðù& KŽ6™—øÝdl±ÐÉ<ú©.&ü»®Ø€[’ ×QFô/­1Oé4@È`)0œ×Ÿ»N-hsÕЩPà¨U¬ s³ù)QAò”lWPlÁƒÍ– ­rYW%{A^ °ön‡2(ˆžÀ•Û“Y#™êì84‘’CЖ\Å b_ãC È(÷ýäkÃhmÎv¥ºjUKKÁC´±—+³Är…œ%ñ¡†îÁ³7)EjÙIJ~dÏ\2  1ïbxŒ¢xÎÌp7• ô*ÔÝß%aÝñØ‘`è6i¸Ç×î°$ÊEqµçd!J\Vì;cWûPtðÑŠ\YGóé9ì…ðꀰ?%kÝñe‘®J ÕߘÐsëÜ2ö¡×Þ;©¹qdœ“'b”\,pdu˜­ÊÉy5U߻˼¥ÄÀÞôøp[—•ÔaB0-[eœç<à!RÿÏÅÊAš´OXk~¿kÔnœoÔ.ØRä¼_!WT’Øýj©žaœoÑÃjð7æ¬ øw=à Ŀ±Wô4í×å¤}‹n E‚@ìA‘šø»m<œ «­c¿‚¨ÝÓ”­Ö½‹³èócuN`²â]%æíFMvèÛØ¬¢±žfjŠÎ +ÒÀïºhkµc-…ô]ýáä³G«0U˜â20à¨y–šZÛãÈM­ž­„¦ÆžÖ/S$)”£Ð6 H&–œÆÇÜ ç&.èž¡(Íu@„‘FÞ?#B2ã»÷“·ãª÷˜¼ øU—½¡Ú _±‰kíÜ6P9ˆ¡Õ{<:OT±ÐêÁßq¦­#»–2±OSm=|—ÔõBà%‰Ålü¦ä÷òø1© j±èåe8Ë;6bÙG»—×ÿ­Û¼£æ#;Cxf ÜÛñû‹¦´V%yGæZì„r’#½(9ß í$ÛIwWu2rWÇa›#';1{ñ¬*˰ð*·Ú-9R{ûˆ»¿àÈ3tc_š=&1K*È€RûÑM§@—•ê¡éÖ£¶8WñÇYÓ½>@“>Im„]O*è›@Å©´§_ž¬K†T׎ÃvYzp­ó9tV°9F‚…)]¾óôh؉5c}79΋1ݹ¼™±¢Sþ'›ú»uò³i§öX ,ÃÞË /ú ¡¿¡m·"ä¬Vج㒅ÿ˜Xø®#4u%’¥jÉÞXbÜV¼³x9iQâÍ>¡¹3¿Ò¹)k<´\@G½ö;*¾Y#H"ìˆüƼߪ) Vnó•ø5odwö’é^:E6Ýd‚îkC ü°ûj܃2‡úœÈHaÓ߯Î#wXbÓ¾ÓÃp÷V¶o;lÓÃÁ “ùB$å¼’ ¥¹VÌ2öM÷y…«áb‹>EvP vÃäEìêiÚ·°+ÔUGa±'#¶ÿîTyt)ŽUùЙiiZ‚h,©C¶‰$Æ8µÍèš™úœçØÿÞfÈ‚lgIßÐ-)þ!‡uµ…ú×÷}eJjDl1ÓÆCD þêd‹.öŒ–µÁ@/ÿü4Z®¬_~뀾$/†m"cL}. U›ºÒ1ê•5ü?&…ÍÜlo–[Ðú®t§výX’\jtÓŠºb‘-jYÃòý¡ŸñæðÞ/Äãh² ,¢6ˆ%0W¸˜¼-EÚQë¾(r®ÿQÎÑ9h7±DMLw¡×ЊLnÙP0U@šA_EÂNDÑgU,Õvp¼Ëùr<Y2® þ;à%™©^‚‘¿ ¼àE˜…ÒpŸö%gTÀÝLSº_f|µb˜µ¸jÔ{ºåoŽIØ&- œ|UèqH4*©‡0Äa§ÖÛ߆Úe{o+œ÷j ~\Ȧ²î/‹zù1ÞW6Ômñú²³xLéJòņ^IÆ{»HÊçð”y8æ 1e¹Þü”Ü„Æ÷V2³þ~³4ô6¬ ‡ŽÄÃ<ÀÛö6æ<Ó&¬T¸‡ÁÓp3[ÅzœÐZAp÷f… Éx)åZ¹¢®œƒÎ¥RÕbðe•1™z«“:ø ù×EøÓ…øK…n¤­á˜¥€_ùÙyw›ÞZ‘&Ä×/Êëwè!ƒgÌߦ·åõßã'Ê ðÏòC_~‰ð ¤}Ê?ê(“¹v¾ã³ïXy÷ ?*“+ ‚Qîtý“¹â®0ÿ$½Ž¶¸"õ“õ€[7"óÛ‹o?*Ïþ\~ý¯¼­›a‘tnë)F¦:®òð,oRwsã?ç+’ð> stream xœå\[oÉqòÈ_Á·œ„³Ó÷™}³½ëͼVhÀÆÂ0(ŠÚ]Š”%r&ÈßÈïuUwWwuO͹èA£9}­®úêÚó—óqPç#þÉÿ^¿9ûâ…öãùíû³ñüø{{ö—3›œç®ßœÿò26Sçó0{ííù嫳4€:ú<¨qá図ï7WÛ 5xï”ß\§Gëìæq;BOç´Úüí<Λ‡í…¦ižÍæ>>Î#´¶zÖÃhÌær{a=Û0m^×¶7Ð@MƒÕæÝö°~³yª¿ßÕÉXÓåÂðq±°øØ.Lk=ø©ÙÄMÍÆßC7ãüæß·j˜mÞd–ÍP÷ðˆ«…×Îlþº½‡0Ž“W´õ)м™J[ëòºÌâµ±Cpz³+½h neØ›:lÞnC¦G'ÓÎgóÝff¥› ·­Ý ÓZµ§ôæ-ÛÀŸ.ÿõL[8`žË0L> ”øiëFWè‹/i£Þð.hÒ5}ƒDµƒÇ¦A€Mûºî„Í‹[QÀ}veÞ›º¿|‚ÊƱ$6Ô4/Ò:usó8qÞ[r™Ô6ŒVë¼µ ôT¤FY’šÉzakÝ`leW{„°q™¹Ì mI`~óó~Us˜yÿD™` ^®‘)7@.¹Hlr¡tb”]…ˆ›Š,¯¶a³®ó£LÊ`€ìüÌÿ`À=˜Á,°¦(=3ðàÕ)R_úÿ3Ž ;ñ. „oWû#؆îlÖÛ²jªT#žå„ÞoÍàüèCzr°ô1£P˜P]sPbM°‰Cô8®I"“9Ú?ôbm[¤Ñ“Âr|{N ¢=,˜På^ÚS£&n @ˆ¬ƆÇo«LßÓ¤3_ÕN¿3;f"€ÎMÙ®hÛ³çM_á ™ÁXØ ƒrêô„FøÛ#¹3 ½å/>Ý‹-7Ó[àí¦aÒ&16¦Ñl]l2¸Ð›„d^™ìNÃûÊt˜† Çù‡þ@ìEˆD2³žNð’æB©a sH|ó\A†‰ÍSF>P¶¯kƒ‚ k?£Þò¤WfõàlG»:RÏ* ò­.翎; .D¥<ž7}[O„3ÔÛ°‚h"xàEã¸ÑÅF`ˆù÷ë€gιu\&[wõ÷§ò{{PIŸÎŒHL³VÉyÛJŽš‡oÊåGg®E ÂÁ¬&3­¢Oj©˜/'w¢ 0®¬8;$NtŽ8ÑÁΩA¡Œ* ¬‹ØÎHåpš^‚ª¸ÍnÌiåId3š:ÕGºU$Øèxƒ{∓×êW¦‰ëî¤yfÛëXŽJQ,íº‰–¥±³ƒDÓc…9nä`hv'¶e\YÎCsÔºg«{X ZRÞ‰AÃNĈë cR«$b½H–ï$…u›‡©-Z‡ }:$iw Þ³šç´I- Ū­“ÌÕÀ…ìù=m›½ÅÏÙnß.ÍHqw­ààî`SÓùåoÎ.ÿéû÷ô–ë™2 ·ÊŠƒÉvÇä„IúÒm¡•$Ù¸ÿµÝÏz4D{éÖLôha‚±¼°0W \5F«‚Ò«hf­ÞJ™@@È–Í èÕY‹@vf#I©,ñµé!‡J_5¶tgkB“*XøÂ8€ˆ½8‘ ˜×÷|À b¨ÚZ+Ñõ?üJåq6lgºfHao™y×ùü(3ÞñÓeL#›gwUK|kWè%?öÄ”ªã*×>ÁZLŽ`–DCK*Ï€Eå£Ñ–»jÖŸÌŽÙó­vLŠÐZéÄÓÿ"ï¤UoþT¶mM~ Q2)r%ëÖ`vñoÜßC¶D*$’-aG Gf¸Ÿ¹”ÿ(‚}£c.´·Ã8Αž~†1ÔÉôŒîòb ûÑÚ4ú,œ@'Lã¹»•ØD‰­é²v¡Á1ò†!‰`d{»¢ö.·ŒžV"EŽZç6¿ÚÚÁ(Í›ïðWð\ZÅÒDi…yè *‚ äcqÙ0°2©ÁŒzÝõ'`†¬è‰>J˜ÀðåA‚õâËÄNˆ4“ƒ½ ÛG(eÛo#,(䪢Eî1JFηÕý¬cýúœFO€8¬7ÃX6x †“…A޵'Z ‹L3z°pôÉÁ`ðº)ZS|ä¥ÕÉä@2éºA‰©àWÙ]væ$,±ùñTåcæÊ¦ÓQ>Ž˜ö¾öÄ7‰|a`ÞrÀþàXIqÁ©M¶K30Ëô©Ê¹ì=²YXvâíBzÉuÁ¨iв84NÀÐH|æ:Ç8bç‰ÕOÃ>(裳U@3ž‚AƒtƧOU¼sÒ8›UÎÌ+É ¢ÍŒYeÔ¢pH›ÿƒo™!mCüîÌ0 òädøE¼ù9ˆQ‰ÎÄD‹Ù]Um¹à•>'D|Û†ÛeTN‘µäR²#JHûQ§DIç‚°ý(O=mrÕÛþ ™+Œí$ÀchR[~qõ‹Î[^ÚމËÕMàiTÎVÄÞXâôlê uTÌôtŸðnâ“¡@z÷\Þ½-OpÞhøJ-½|*]Þ ]~(¿^wïðé¡üúTÞ•Q¢Ï¬É]þ/ZwŠ©tVõcéþ\†l×=ÚX1r'Ì}ËgĹ„Í= ›ã¿^x°ÐÿÚ;ÃæÏ©¯…¡weÞtíð×/ab¯¢9›‚–!ä!0Ú_·¯BXl;„:ÀP~»k›‡ÐÒïB÷Šã¿ùÉí©É‹hxn,èž)qíÿ3$<¦2pUÁ¶ÙÚ‚™+‰¯¿dVt|î-|¹oÐiô­…œ+šÈÀ”S‡¸¹‹9^MUc¡Î"@БºÚìÌþù² ìFƒýL¸þ޽¤.»òîªCv’wËéQô6@7Í'C8¬3¾ˆƒu$Œ¶§ÏÊ þ½°µ÷Ýx þÞÒ« ïzÔ›ßлߖfßЫ?ÓÃ/Êo¿§W—ôð/õ”O«4ÿš^”ßhøOBäÏ­;‹&ÄWH[‹qýEu6‚±ª?ƒ=‡ßg@œ®¦«Ãlƒ3,MÕÞÅZùí<ƒ7<Çè-FB‚CKÅ”ŠN?öÂtäãC@Úxþòz«1`'þòu÷hçìá Ö«0‹€¶ƒqsÉ©ÊJŸÂk ¬î>)}o}Vú9~Y¿52$W¿³²˜Î3ÄH¿·5ÔŒnÎëëì,¹÷$Ù»¸ý aÙõÀ}Q}pÊÆŽƒÖŠGëåêñ®º"î¦  @Æ^IY†6º#ÿóÇg&¨_…϶Z¼ü•Igò ‡(µðý»z„® Mà fP°x Ë*ȉ6ÃcoVR 0'¾Ú@PëèÆ Eì•*ê³!åG·ùÏÚ­ 0F+y·ÕWù½£¬bA£>’í˜[VWveô½…UBoy1/lÈ.>Öè! zi^1ýSêðõÔYÿCƩ㠓ÒM/ç$1Ãè"YJ`dgà+ö\¥3P6nÕ‚­Ÿ’XfxÌ}r]oîs0{]ÍýaöAš³F´怘Ð>Iø$I@q‘ŽªÓá½ò¬ò —çšÄxÉÇ"f%¼,I’Õ€†šxF1_{ƒ¦:ªvà€–"ÙRQñ æ½ØÖàw¬«ïDKf¿ù‚zÞÌG™/1j¨¹IpèÎúMÀ쎳·˜,Æ ‘½µ“Ù*9Áî‘k×Oxƒ|ýƒêv=”°œHW¯Œ'Ž‘µ~-jÑ¥pR鯡â &¿TqàÔr]mó¡:Z¬*XÈt{ñ§¯\©ÖÒz•CŽ.‹÷D»Œ­”•EÊÑŒµ+@T๘ ·%®ˆ®®ÍÈÕX¼ƒÂ Í(—…h/­ÞQd`‚:߯ß%LŒjSú=σ†`³hÔ_#®Ët'ͺR|NË–H<êr%´ÙX²¹6Õ‰¦]SUÝŒ´K_ÍŒËþ­£@žÌ‰©ó[Úo•; Åqß_®GI©cÐD‡0Ç"˜5ÂÈ /°¥Б9µ:~bíîZå^ÖTŽ^|QYR–´äìO2ËŠ_¾` ”á.œžCÅ.¨×?ºôHY”(–žì”(¨ùÅE™É;Ÿ´“ýŸÊË|åÌ;8LE(ÃȤJK_Éôq»øåï¢÷¬™@w„ÌZ*¤˜_ÔáMýYë¬CS9q*d/£ /Ã5æ8È™’j×ß³?‘ò@ô ýºEk7D£sîá°}«“OôޣʮOTë Nñ¯·Ê¨9ßE,ãí%U".¥L«7Ž(Ó¢¦åXØãýaݺ Ÿ@‘’[Âø­Š ³·[cö mœ=¬(_J°´¸3ÜÝKmBtXT<°˜ãžUîçFHò˪§oxàï¾ü>õ-ñJ–’ºµ;£”®omMl%80~™8L>º(V%lñá€=ßbñƒç<–ÞÃ6tâD#]Óhb'å‹HMÍØGÆDƒ¤D‹6¾ªV€XT@‘¥0ñ·ÌµÁÉZ„ZNõ17µ€Þjí­@WUŽV²nŸ}1º¾uõ\Ÿ+}BÌ4™Àû^«ñÐc.‡Ç@ÉJ&¢«QÈáý®¶¼ŽÔ‹©â˜ÝÝÍèÀ[ú.µì»@â•1Œ!~gácR ƒM,r<¡ZÂfzÞ:põlN¢Æ»Ä‡ïÅ.>°U7)úX­qÙf`–»Ü–‰=e1ô' 1æÛ”v˜}q…PÚÔeå㯻f<‰ Òúìš_ÉÖt·ðcª@‡’Û“+ÈÖF¹S*—jw Äªø(f$Ýrâ^’ž@æ§=aМb:Ê4@«YÎy~&ñ#6¡R)íØ ük·á8%I¼Mâ•˱A™ÌµˆBö°ˆN¥Ü7*€šdOÙÞE}+~g¶½³·võÌD§+=Éi7I _åë@ƒ¹ð·U¢åÜH÷uŸXÉßT#6! PÊ#(nnÚ”šÿIAEôYäËðëvG>÷bxPR^[áK±Ñ'a8ìó,VQeŸI.».ñŠ&êÆ9^çŒ_)Yq‰–ÙƒQº£½ü½­½ï'›웞`õ1Ĭ6J¨$ô»}}yö;øó7V@,endstream endobj 1473 0 obj 4900 endobj 1478 0 obj <> stream xœÝ]ëo$Çqô‘í/Ù ´£éw÷0ØN ÀH™@:8‘KÞáxäIºsDÀ|ªzúQÝS½»Ç#-;„[ôÌôô£êW¿zLóûóyç3þ—þ½|wöÕ7ÒÎç7?žÍçÿÿßœ}&â-çéŸËwçÿt·«Ïì„/®ÏæÉ›å¶ó 'égq¼?¿xwöíæÕVO^£7·å×>þ‚6?Ä_ڋ͇íÎ ?Y¿rÛe¹ï}ºêäæå²(—Ci“å×T®ŠÒfË/_®N]í³siû*þr޼B謘„Õišpõ®\}Hc¶a³ËWm³ž´—émÐÖš¦ü£:4ùö¦:púÜpØð#Ú›ú  }ÅšÙo^¾L—ÿxñ¯gRŸï„<¿¸‚=}¹a¶è¾´Õ%øP®î^}QÚ~Y~ý™ÙƒyºœiuM=Y®ÒX¶Æt}CÓ/ó(â÷.7ýXn¿ÉM/ÚçðÚ>7ý”|X_ûa-eT·ðfm§t}u]Ëí“M÷W𤒓—dŽ—ÝÎ@Ó~=¡™ùçk/·d×Õv‘T] 1{n\“‹¦ÿóVLA‰YoÞlgxBÍ—ng ¼ƒ™à¯ „åØéIš2¶ß“«rëSжY–ÆÐèý$6¿ÝîÔ$ ¬yéóÕv'@×TP°ŒÐ}Æ*Äôøm¾SÍ“róu‰Fm~­FL³P›ÜîæÉͳ·q‘SW£ à{­ò°ª Öd¶¸Òð7)c7ÿFúÚoÅ<)ïY–WõùqˆÆHAWð¾Üz½J 2j6ßÀwH˺žaZŒeC¶5aröÙ!û[”{ü²-W«š÷÷µÏÎYº¿ZC¬Î?¾\Ãhy1LJ­zŒMÀW…™%¼åj÷R¼úGX`åÈt$æLǘ¿ýYmc»…u®ý ·Ï[W›±S]Nv[ËÕ²±y‰µ H)Ï-pÜ϶|h…fÃ[>E-Ÿš©Û•½R~ Î>©½ú]µ®d2õÖLc,áÜùèȬ‚_$ëëôV ÀhºŒªâ—Å’dúMµwËb…,M2h ù2l ‹‹eô{ž×¯§ÕÒ ™,ˆƒðZÚì¤uS0‚Ô×õ©ÜYœ²•ÅëÕ¢Ö÷_.«f„¥Œåër7êi62t¼õªvzÅtzp+µþw $K) 1„ÜàuP-yhOI\×° ŠnÕ}^KÙé–Ü{Y[_§Ç”Ý\WÉ»§s‘ÚLÂYÚ×ÝÖNByPμn'ç4íõ>—4à$Î"KÚêV|àÈM|¿R“Í d(„½-}¹¾+U]Q€Œ™B;¥¢KWiNž‘¯xC‘/OU°ßlƒ´=vàf-e¸ëY­Ò÷ÞåYJ*¯š‘ãO;@Ð"ËN|Å"P x1Jàœ‚[Iá2…$…‚<ÔI!é,]¤:؈¸JÐLMÑ"sÑ" €°t Ã²aëë4Û¨îâ€sö¸î‹ÚêOÙC±1.ßê£EÎwúq­`ðEs%Ŀב¹kX˜Û:B‚’òÝÿ5.÷–Íj€÷ýêª1¤ƒ•Pe{á@ÉÁö7=,8Y¥ [™1‚õÝZ€”y_uŒu8ÉzìÍl¤GêÎØGûÒ¼w¥ÛÝnï©Ù¨&£O96&ôó¾± ¯©Ôe º[p ¸´Ç×ÂÎ>ÚÇ L߯`”N”7dTÐn„’À€ø]T¦Cл“]TÀ )Ì®¡“*Ù÷ øF«i5]"nת+ÿ‡È¡¬ÐÔV1¾‡r®0Hc:¥‘nž¼5 èöé²¶&гMï]콕Ñomî5!¨Ø°õ=-,1s6E^ØB —‘8Ñ8ËOµ«–µªoÀ•’ÞvÜv´‡Þ€Ìиµ5§$¾Y­/Ÿ*ÇZÛcªÌ÷»"Ý™e…0VY—Pê ‹T<&¥€ÙÓaÒ”0‡‘!…WÔ<+«›øW‰> X°P½K•,£p¿+”ˆ6òã¤%-¨."é­•ôE·£fû‹Š$4ö|8ð~èDX3!+ ¡Å­È~ÄÅÛŠ–Y¿\ˆJv3“hÎØY쨞"a’,êdÉXîWªZ¼…¨ˆ_?ÿ¨Î®(z¡§RN®‡â8ê°“´—G~;I+Y¢ÛÄË=’­ªœD—[?¾uôlÏi"Ó ïómñW³#æÎ¯˜˜È©ÈZeO°9t^Q{Tã\ÓJVëz+&b:É–ÁYæ§OÛÙ°ÒÊíµŒÜ"i¦VwIˆêCg¢kG¤©õicK6éºâÀØAŽvRRzCzà1î6Ùg߸ãÓ¥ä4´k™J”‘‚*ë;ç˜)ÂyG[£ÍÑ–F±x_å *XÿlÞPã_¯²Â!›ûHƒq -xðÊ»¨zf³(x®Ü¨¢w–úâ­³ |„<ä¬v|$¿²uä’ëžÝ®ôìï¢ï ½¯Ï».òðþ …e#=Í¿öív­…ÕrNáÛ?b©úÀàû*ï9ëqÙa»CÏußè2ÇKà7¼_%ãHsâ¶rÇŠuØy¹…!aâ¥.Ó·¾g´Ò‚ ‡'`´Ë¾YGØé=EÙfŸø+3±{–78ª#Ås£•$#|·°V'ÝÇ5tŒ»Ó[‚Òäm¼ÙBœÐn‡0? võó6 q'.î*]¬€Â|uï¯6l©;ºçh%õD[?Õ,Dö~Ø9> Y“?«¾ÿßÌŸÆ<×\c‚8˜õþ.´­¿h0ó¿ÁN;¸”!g›²Ï°Ž>ãlê*5<ºsžS)ßZy3Nð™,íuY¹üV¯è«V.{'sÙ¥T]' Ug¶ÚÈËsÑmœõ„ Dó”YúœÄއ*WÆêRGÈ{ð„e¾a…Jäù˜-ÙS[ÚóÙÎg©2]G:JME XheÆ¢&¡FQ…xvªsµ2QgÓ5Ä Å"õÉ¡†–Fõß[6N¼†¯ë{‹< ÈòÒîòWßH§Ïa‹<Œ•aZÔ0 ñ»³‹¿ÿW¶ßÀˆ …ˆ.xï’mÕÛ]fD†ƒÌ:?ÇDÞŠ€ûÃVÿm^ƒ•6¹¢X ²¡°'‰µãÐ*€ä$WZ÷ùùØ‘Š•À\¸À–¹¡µ2H™—Éü¾ç='†0,å5tçhDŒHl”6‰¾630.eÄ%\kÀKL\p`ËÛ¾@N§ùѤû‹^=ŽïÒ¶“)=+Ћ(S*À~Pð%Q.2ƒ•Ia.ékeÇF^Ñx6ˆ½& pW_ÐæëP7i±Žý/òÙ§ó¼À*Ã!9I=±U½$C?¬M þ~´DºùF€(X—ŽEãMuÊÃ1>P²Êø­x. è9ùÈ ¾‚k< †Ñ±à­‚Vh¶šxŸàë|¦d «Y®’I ¾w0"mÖú–µß­Ë’+IøOØ [òeÁ ŤÝbõ"8¸hRÃ3`þ§¢Éž›1iüÏ—[ W¥ša”«L¬èóë«I(Ê‚ì‹Ed„·´–‹©Çw4é¿.ÈiѨº|Š #äĨÿî¼á.ÝÀzî*Í!,r]­\ʶahYúGŽ_»Tê;TG÷S.ÏÜßÔZ–ýVbP4øO„¾2±Év(Ã>}VðéAŽî$JyåÃÕÙ «ÿ…;©&ܨÿÜÂ"[ð"øàã«EzHåìc3QlY7ß~fˆ/‹¡§ääÏmýh‘xPt&ÙjSÞ`)ÚÁ²9ú,«©œeð“/©'kÉ£}Qvûþ‚èãý3ðVùÔ]Þ,O"Ÿ’T55©z t XÑ×$'gЇ'ý†¤Rß ™˜õâ— Ǫƒœ5½¬‰X¾šT–>@2¶¼ÜæßSÞÓbì«ÉÆÆîJ^÷U}²ö¼JƒÞ±ÉZÌÐŽc$Öbõ#-Z%ûÍNIàã$ç yŸú€J4¡xl^z*Ÿb%éäÖZÌ% ð+ìBhǯ@¥!7?•ßÇ}\ƒ˜ÚŽ}5Ü{¼ì{‹8='Â2©|:Jÿ¥‘´aBÑc#(|„äòép]plÙý)zV#|nÖ2Ú©Hbû Û=Ÿ¹8~-žÀ³Cs0¼G!˜«¼Ÿ®ä±³i8]­%扗ñ3«¦–#§dXª¢Ž•UÆüe(«ˆ5¬:Ñ0Aíh®:Q*JF m1ý¦”Æ|#¼ ¾ºnkÑQt|¤çŠJ”ÂCd_‚•"…n¯Å0äùtwI,S}Љ m`S¾½°3âµgt+ÁF«ÊgviÈ¥0Ý@—ª—ІÄóÞ‹&ºp¦ ©3¹LÝ«&kÄ3Îq­N„á”ï{”vÁ„Xò¾æÙ°þãGH¸ºñœr ¥EIç×£'ï˯›|¤$9îª9pOôËg«¶Ï=½š«Ü•Ë«Ãzëi•øLœâ_ð¸Þë¾æöÁåxâ޳sò\––Uï`^Ö}ño ý\’°¥ü9 f¿#}IîAêØ/¥ Ùºçðœ|¿ö¤´!¸[ßÞv„ ogÍ(þÆ|×xø`ÕЇ6œ¿aш­q;t ØÉp}ÙOòµ—ª i žûÚ™„“Ç™‹¶;nwFÇŽNᣅõ<®¹vPË*ti<wð«O{ ðŒNºýÿ <åTÓzH켞Ò×Q¼™Í‰h³>…(eÉ™ƒ6O€IPW¥¸¿£¹LrëÚ#¥ÀæzMH™óÇi8pFûñrÌ(Ü1¾z/·~Ï…ãºï~Kd2WYMþyÖ–Óÿ™i> stream xœÅ]{o$E’?ÝþçOѬh#\“fflÕJ°Ìs: –N§åtš±Ç‹Ç6Œ ëÓ~ø‹ÈgdVT»{·Bà"+++23âϬþy#&¹øOþ{öòèѷʉ͋WGbóoðï‹£Ÿdì²ÉÎ^n>;…nÖ™M˜‚Sð÷ôâHL³MÝ6AMjr㥞æysúòè¯ÛËc3ÍÚZ³½®W/ŽOœœ'ç··±ÍÌr{¯`Ðí Üf²rû´Þ½ªwï¼GVÛ“zûé3«­¬¡>£jÛ¯¼'Ý\išËÅTïɾ .D½÷¨4©ra€ ''9Ûí{¥ÍÕþ¢¢ëã¾{wOŽÏý÷é¿Ç­”tdÞ ¥ÅdÕÆÍî¥ýùó1\k)ÌöÇc­Zx‰dag¿½‹WAJ»ýåøÄLÊ1oŸŸ(£& èÚu‚Æ)˜Yè­­Cã&&õ³:ù&ëDÿ£HXÀG­ŠH ¡NDb¹Î®‡çTÁÖÖKö±ƒ,­ðÜWqqA‘ýëq/°DübÄȺ–~2Ú-jé[u.ì¼½7ˤ‘ÅžˆˆÖ¨iWÚ»nX똤\º¾„2IòØ«¤_ š"²° ¿Œ“ &u%¨BžZ.¢Õó;¿ ý r:3 Z¤øtÍØ Pq7ò„Ððqá`Ã[CŸùEÑr4k¢¨,¬†ˆ,.º2ªÀ“t^ò†Ï¬¨´wöæuôª$nƒ€ðf/VÍS=hùhùë@T;á­Jã¨÷‰µÆ±\X.ò‚ëÌ‘¥]?H2aâsv*½’_öˆ]ÌÅÆšš çÿ¶§X]¯’ü€ŠYãó=»GÆ8ŠêV(:êE‘§(òIr,uˆ:Æ€ÛJYµýõØ¡âåŠ]ÓÈÚePóŒ/A£Cì,‹8¼g ÿ~Hܵha—§tÚùñC6L^ vÑR5'SedˆŠª+\Id€ÊXÑÂG_S$¶‚}¨Ð?WÚLžºE,¨´Û;M­Þï›×a›À:ý”¼þ*¿T{§ú{€Ô>á3ÄJC5íE™¿Yµë >76ßÏmß!Þ€Z'¨ GÐÜM ów’ŽÃ +¬u˜ã£xÓ`–>£ógë÷P LAÏKÈüÏóVª0¼?¶‚˜¾>*"ÞûŒµ(Ê}ß EÖQ‹xÃy)Ã+ªtRÂX÷‘¥»gˆ ²×wW2T릉!1M®Á–Ì·bì+3SìBY°ÇÁ.Ü+ 8˜EÊ€Ýîç0 pˆà³K8‘q&@x §â'gJéSBð舎º`ÞMÚ̘H‡~G£ù+Š9×ÙK`¢Ï0®_7ýJßn%’½p8À9Á=eiäÝ*ÐÊ ~•7¬/œW:ž Ýx¹[„·V±v Ö%O+€ÜX¹}Òž¿jÍaΑ†½ƒ…K:^'›˜¡D±ÒâE‹¼hÐÃR “x½•qšcÚóØŽçÖwÖDŒ{ö._k²Ø®Þ¡ú‰~~£7U¿TõB;âîñ¬ëÎ5L‘=½bÓžgn­°àŒéqçUè ü§ÇîF{Ý›|Åe½a·«›áÀåÃÌ"xj‡d²®! C‘ËÁÜrÚ‡`O"~bÃA P {1ƹûð´šÕ@ƒ3©ë ë¥ p߯Zºl>&÷/;Öc˜OŸ RUY¦8)*‰óÅBkÞ¡1jI ÑAÎåÈÑÅ8‹Sq+˜ô‡„ß@<†šõŠC‰SõsŒ óB÷4‡µí¤]¨ŠKÑÁOZôU‰ß@ÓÈ©!,Ch{`½šAœkÔzp↤˜× ²Ô îRÕNïÓÜœ)RŸ™®yðÐ…Ú:×…UÔJdêioKaÆ])*æÄ»dm´2C?ı¥žÀ’@+*€Nw›xÌøül'«]Pº²³dŽ»Ï&¹y>ø´7g ‰k¾SÄ’¬ÑÄrqÇDÚsH‡.`ͤÁì,-`#o6@a€n‘é`Š›Óÿ8:ýð¯h´!éV|J`fQ›­b[ÝñI_h¬fš5;;Vh5d$ >¦Ò(ýnBÁ_øõ¶"¤Eœ=²aëøŸ5 \·PL…Áé}N¿OOi‡  ‘eèP/±¯'X¢"Å!¬£¨4K¿M>él$0Rá²u}^ÈG.)­EmØË³—¸j ôf!æÍ h·¬?L¤#ùM\A‚ÀÈÌO¸ ˆ³ >3Æ{ǼØH” i“½79Œ‡Ÿt½¿Š»lÀ­‡=3ÎD3 RàÎ<ÆKé‚o|zô—£Ÿ7°é>F³ pÓ)Ý5ƒÊ±Vê³'Gž|¹¹ýåîùÑ£ÿÜÈ£G_à>ûæOðçÉç›9züd‡Šhã(gaÆm$ +qÈH+µX+õ Al è cRmuÖ²BÊblN.ÌýDƒB€ÇvèZÔ_°âŸ“HÆý"ÒÇW‰^îs>*é†: wkz·Åb2„:ª${‡ÕþP_?ϬEX–¬k`‡Ñ÷ñyªúî:Kãü`u]á,}Ï[ëî°eX­~ëãrÉÆŒBœ—&Æ|QÞkükÍiŸ5²‡ßj5µÖƒe }ªyÆ€2Ô¥ÚcÚj•!ª¯ë£U&íkÑÊXø"C‡=ëÅ%ä¼ý[!£p¦3›E5^qêÀé[DiãÂv WvƒíòU¨:lª…>̶f¯—ð8™=yü†Á1ÑÜø¢ÄCï‹ÿköHZ$·¿2»Ù~Èb’Ÿ;Ü,&ÄͰà#%{~é˜9 &&ç™#OT³¢ )L¹l¦q>FÁPÑbŒ‘E=Zg‘íŽÝ,ëUŠ=;ëfÀF‹0áI¢UÉ+¡‘NòºüJ•7,Õîy»ìt¦­5^%òòÚ¢…ÕÍ‹gÊÆ´Ç 2ÜfçcF#¿`ÍÁ¼o$ííŒÍ—&`F$ÀÌCÍJábÎ7¬Ôåì#5)㲄 ÂWti•Κ|Ÿ…ÏRäˆ-†afØ05o´†sï0ˆaf‡Q |QŠ`(RöKMLX˜KS\ þ£.½çà‰æ¨GAN`ÙjöR)p§.1tîš¡³Í'ÊHpb[#{®-§Äž¶KÖYYÔEµuÅ-ò† àç…‹SÅ"FÄÙ‡j±•I¬Ã!|b~ÿ,:LÃ¥0„Ù­?Åóñò#ôpåV ÂÚ®XÉëã{}ÝfMuCo!0VöïÀÈ}æ2l_)•Gý[€ K€ù”_Ç•kŠ€°³—¬³Þ…ÙF®!}9pÈvMg\7g~³ñäP8´f( üÄxz³³<»s IAELêv‡-Þ¥cW u½’/¥ÄΘÄ%âk±ð®N\—³<”§Q·ç¬H®¶]9Û‰å(©ÝÁ˜†³…­±Üs\ö¹“Ú³QqE@æ ·b”å ¢þv€>}`¿8a+è#hèú‡Áq^ˆpñ¡WexÈìßf÷ê¾­Œêm/ôÁ!€Ä`÷‡Qzÿ(—$ÙWþADkÖÙb+‡˜9ûàQ¶EP$ö½ÏŠ,¨¥Q7&3ŸíâZÚl“îlõÒ²V/l¾ÙéŒìí>¡\Ñ~h UU±Ö—–õ®ÇAy¬£r Ä*ÅÊúð-{Ž\˜0èçvá®g°¬>`U$lÆŸÇ$ñœEÜ5šB‹Ì,뿵¢Œ=`u§‡È@~qkŠlòÂK. üº½ !3Ðkä¤/Ëî Y=¾ÉàÑáÞºªµØ©:(G¨m;UÅŸGKùޤ¤ôÒ¾~¤€ÿUŸ;çÍÒFÃÎCûÑPc»QêõaVSÂCû@ÌsÀŠîmEÔsaxoŽ)’£ C fd±®DûKÜdpèa4VùÍqÌa½&gû±aÏλN hÈ©•ëê=”œøùæ r Z5–•6c®.+ïLð*ƒ7¶ˆa³óÃ})s}X=R#I΀ØÖ*Ê^˜•¯ÄpZäv¨r2V±–¾ÄXâÂdÿÏ µž®@TÄ“é{œå-”±ÑBÙ,"ÓÄ¡åc¦|‰d¶ Lw¥;¸XžoÙÂ&žý@x Ê…‰;Í3äSÛñ‚øÒN:–£“¼ßžÿ‚=s—-n?®Ù½• P(0£¬vï4£d<3ï™r†~DªÑ‹ øIÂòï` ÖîТl;rž4e aØ/ ôS6i5æ¿\A-æø£w¾‚:ú{­ C<Õ©* à…Ÿq9ëý:ä ·yûšˆœ*÷æ@,ƒžŒÔ+•Ú7-õÀgGùÃrç8î<ÙÐUyEñUÛ5-Fçë.Ó?ïG®.ò?êl¤¨Âß<Ùçƒ}P?ˆg«œñÔ"¡ƒÅÞõIv…ü2¯I/Ó¡÷â3ñ_9zà ð³ÖsQƒ4Z±Äú¾/ñ†µ“t£uhS#{×(àÂV|˜¼œøªqˆ•6˜œùÃ{]ÙHa×'ÀÓ( «´ò‰Ëá|çòì.{Lš’mmH:µîOû@b5pd)î$NmŠ•Ò§µ\›Y-=‰%‚…  óô[µ²H¡îõÚ–Ö ´8'ƒq"×§žF¦c%‹S¾Ov”˜˜PÍR])jˆñ+—/ \\GšW€bééîPn=ļãðlA·«®•‰Äçp¦¶<ätÝGYÝ?D¤1Þ¡×cîÎfxÖ–Ó:Æv×ÉVÜö’^"ÖoÇ)µŸ¡S[ûêG‘Uv-®yÔ-lõæõouýV?±‚õw¾Ë}¯ÆÁ¨Á[«o'nÑe ß7ë…=”߬[p+¥2“6.¥:É+‚ j°+ªÒ©âFÕ‹œ5žŸòñ(ä·Ç ŒÙKg’æ8oŒm„¼¶ÅCS_M"ÀZ D7ìâÂø°C šC”òÒ«Úó®µÔÆ8ö@!â¹kážoãç-M¤jˆÛıNIÝX1^Ï—å@™ë]»G騄esŽVDÉdñQªåIš _BOsu‚ãSY›È]!&â çÄT%ëƒzX9^ÈIÉ5OšO^ŒŽ)S{€¶´Sö̓I;߀þž3† ûù¢‡Lj,<výö?¶³úu£ÙÅÏÒ’·.¾Ó“«I#߸á0Ob¹Ü‹üeø-ËXdc©vùfIP}D%ÖË+6ž­\üÆãº“!–ÚI6[väïòÇwv˜ð*±HCÏsýH×ìº "[¹ÊZ1ßÕÀR¢†Ô"œ}úm½¼·±ö¼6*E¡U]f Oye¨a ­…šì°´­ì¬‹×®«1®>'ÒEøðšÃ6ØSb Z³Ùº%9óÁðÃRAf« ³Z¡W¨kó`ëß®2ÖvžÉ'm¬è7ä$P¿Tƒy¾þµ>Ÿ×Y'¨ ¼ ²²’ÅRàÕDuZ£.5whQZújÛOÄy"¥¬¥ãÕçÿ¢\,QN™jö+H$^Äp`MÛIæ—þäýEÊո0~ Æq¿$^³<|VŒÓN¬Ay7wçЖGNz€àOñ“oÒÔÒºVA¯Æh)â#êË”dŽ˜Dñp|Ü Gúœ¨üŽ^Ûçw$_>ù´þúÀY½º­_÷ÿ±~Cÿ×ÚÖ~|£ýJæ´š0r»öÓù·9Úo¼_oQÛ¾®W_Ö»kÛÿÔ«¯˜»§ðã§äYîú%‚æ—Þ/m#-Ðôe¹)¦¯–÷NóZØÐ~”ÀÔ»:/ÈpO¾}Qo_–¦:…õÞ«ÒTä›zïÓÒôI~»QÛï¿'? ¢ˆ%qV»®ëØVŠîê®»×»¿¯mÿ¨Wëݹ¶ýiøÍ“”Ÿ/mãw×ãgÖNæˆ@~ÿQÚÚS<‹w%Fu~\2ÁïÛÝOòïVXÕ–úl˜¥÷m_ë½Ú½vz¾c‹Ú¯WÀ%¨ä ¦Ó‘Õ|9Œãb¥I¿Þiåî“A^+àÝo2/Ä2ôrû®Þn\×®Ú–ÿ’VåJ ´ŽCëL|].~«÷êàü¾ql¹¸Ù–åD™!Gp^ê¾^µßÿi°ô’¯³"”j ÆßVygø´úK)þéø”q²áÓÓaÉ(ó*‚b×%ÞçM„‹¶XÏJÓ}“ämÜ$Ú‡ü*±Utm#§rZboÝ’‘Ô*”¶\ˆ6fy¬cÂIa‡¨5…?ßè÷”0\±RjTÉïÀ¼ås¥•|;yY^:T˜“ÁÞF©IL™µ°Ù™j»\­ErÁ¯ýSQ¹+nߌ´P›mÁj]y>H>JcM–ÿåèÿFúñúendstream endobj 1489 0 obj 6227 endobj 1497 0 obj <> stream xœÍÙr·1•G~Å–_²›òq 9Nűã(eW|(•Ë/)æ±¢H[Jå/’N 3=»\YL\.Y# t£o4öÕBtr!âùïã˃Ão”‹ó×bñ9ü9?xu ÓEþëørñÉÓ4L.Bœrfñôì` ½êz¢—¢ÐsyðÝòéj­;¬Ë«µí¼A/OWkÙ9g¥[Þ¬Ö¦S6¸[•Quvy4à„®ý&,Ïjã5B½ÃO˜¤´î¤ÒËË84(ë4…ú•¬U’B ÓŽq,™v‹ÓNW€¦vÆ-Ï@ +oñ%TA½†µ”í´¬;ð}ÄKÛI§Ê|i+bБ@iÑK¤–!ó7é+HiéV_â,z…C_¯4À®_v´ ÆÚþû§‰'ÝzÒk‘NX©ÅZõ[<=#К‚žÏ«•ª¯hãMCÔB©‹ºÓ¼hË^ÚuÆ‹Èdi¹ÌQ¦÷3•°±Á˜J¢¾9˜ ~Nh4fˆ«J®x\ºï´nÜ>tplÖÿ» Гf¯JúÎØ@ó8ãÇó"üYZK_xÓiŸW*Šh_fiØÌs\‡ÞQ6‚Y=ü#ÃO@_Ô‘D&÷`Øç+À_ AGÆ…4»î ­ ñ:Îq]9Šëvwq’‚-Eæ‰ÂcUa•£àktðp&åtâ.´è¬T” W±_{ç–o󊽡ýg+:/•§gsŠýÇø™ 2i›„žEß ?søçqƒ¦ëLÂ){ΤuØA·˜ôÂ(5åê,¯æ„å¥\yp@8Dmž(¹©ÒLäö- þÅdØJÆž¼ˆ{ÀW¨_€ˆƒFV¡Qùµ `ï§Õÿåg¥9)zèGnç…ù¨ h¨\ÓmíMºO& ÓwIð†Û aí¢”ôÂJÊúDnÙùo9]p=©p ŠˆÆI–q ga²;²æUb/³~‚¥ãm£ª Ô›$ùøkçH„˜ˆàEsfÛÅE{Vá_r$†hT.kô¥¶,±¹&òzs¼j) +¯Öwâe’ï/Žr§<²† Lø]£VŒ“¦Z1¶¶/ƒïœ”÷ѹ•g˜r$sz›ÐOã†ðÎÉØu<ß-v hýÝ1›Îr”3ÿ°ÓTý³áÇ®jgâ›O)O›lð×…X±ŸQß/"µž×½œ³k‘YEvŒâ­Â«à'ýqÛ(<†Åïlý©JÀ9µ[å1Ú?k:àhM"U¹e×°{®ªC-ÿ‹&ªÃ®ÌŒ‚'þX·r¡ÓÀ¼Ëÿ0‚) PÖ©$˜ZHÌÅH¨ ø8iÓ:Nò½vDUA;¯ú¥Y­Cè0jù9 #ÀØÄy\;/mtâ5 ö½£7øy„€“·8;}³R3=pö]‘u!!¨@{8–%‹nÒÈ>ÈȲ³^Ì—qR/\ ÊBÞ`Z$«?ÚjIh3€§“›GöÅÁÓßVü­ ÿ^›ˆ>Ó*#QÀ­&>¢“žËA\; ²O|ççYÝ¢à4lðeíÙ”DŠ À.¡ŠôŠÁ-Ï‘ª’q¸hÌ|õîJ);Sïaâ“ÖÏÂÔ¶™6Â1k0Þ`ž?¯ÏÇ)Q¬Å¼·6 ašHêbNÜ}0Y8«¶Ó £uQ ²n^‰¾Ÿó‡'S‘@’äÈšƒòJ%OtÌy³dŽ9É’%¶õÔñ&„˜qR‡p¼·3De<çx?Eê…ð®¡oË0q_^¸zXEuû$8HQç$8˜œ=ègÂaBÙMqÿõ–jJNÑ=Ö¼€dÜ~pƒhëÅD„b+ÑðnÎÁIF&Xg.XƒóѹJÌð=¥ˆx.Â4´ŒrØëÎ ›S=·Äe![äg4‰sñ§™Ç^-ßP•2ìD„ƽ«sØläU#îªwfFw4IкÖÝ.¥vÁ¶þÏ¡‘'€+;Só¬ÓH5-j^5ih˜‹"[E†5 }ç<È&ŠšMÄÃsr¤ÖyúÀ‡¡›Fäƒ$C_°AQ¤õ˜ Õ˜¡‹Çæ^9V2é\gôÉ §,yln§|iR²`ÆÂBÕxÌ ßlb+Aµ’N›Ð+)ž ÌÔ´AjÝJ¯¼‡D/ÏX˱š»Í~'8720F°6±›ÖmÎõªÍ^rëòJjFoäÕR‘iIu¡; ›]KÕdJ¢OŸ”­;C½Fĺµ²[óm Oˆ aï>Š¿YY ® CGEÙûøRôÂ$ÏÚ°z a!Óµ7MÃÝJX>[¶C~d­Œ¦³k €ŸWUÅÓšì%,Ï;$µ@v@†O(opx\2”aO=Sâ*éF™µ­ §Ì¶Âï]WHy•µVL^y\ìO+ÜíáhHúø/Ž.á|jawM8 ë@¬G×gó½dP.‚õ6¢?ÜK^®Lçµµ1@/_çé+ƙҗÐâƒÚöQm»¬_§µ÷umï£Ú{Nf¬Ø)•Dc æMmÃÞkïµíqùbã,¼]EMÆyŸ KaÐu3Ü¢DU­ ¬ &^‚HNà$‡6+l%¥!Ãr° ;?®mµ—µË[ã3 ëûª‡+ã"Þglk“¾)W¬¤Ç`*cþçr]}-ßš<ýiĆ(×ò:/fõzC¯˜æc¶ëx&}qÌ]U/d×Ò‡”ý¸§‚ÌI2kä˜`y„$Œ¸yÕ2y•²&Dø‰Jà/Çø±“L½Aél'¬m±4•Åt!Ñ›¹üº\½‰ààB£' ,ò9u͆’šÐ»Œa"Vþæ¶Én÷džY©‘Yçl#^ÉN£÷J. Oу"6 çGíúTÀúYN½qcï%Éi !#aXüÍæ’øè@9ƒ¿BåɆ´‰_”gµ0 Ù ’cpšœèŒAŸ‰u6h‚ˆÒÚ- ›¨PÁLëSE­ ácsA=U^8°MƒoZ=9MÎSË)»œ:m (¢æÐsá³P ƒ ¹s?v’R…‹j¼×SVá\ä,³U3 P#]±lójœ_(~˜p`½–#;ø¬§=–_ < æ¿-‚ƒW¿òxìAWRDN³09^ ûX…:Ëõ1ûá¼m£§œ§c•ž2%ft½™N³'k¡Œª—Äœ dúÛ²~síuÇ*©Íd€CŒAæ³ÞEòQ9 ä´ž»ÆÜ߆ÕCN¤Ñì ­1K¬¡†4WÊÏÙ™|ÙØ­ÆÈLÐfˆ¶&ª¢äb Ô|:îå䦶½¶©†Xz"ÜL–‡-›C-×ÊÝ+[ر¹8{>‰ kaQÍXÑÂ"& .!Ô~éã±YUÜË$!9ò†&?±¿n°Nöàa•hæË8HƒŽmN§IZÉó¦uZ£5õvÌTÉ¥ 3&B-CM£ÄÇ»ª†Ö2Cö´lð>7ëÉågš]ÑL^è™ AÊ &¾úxÁ˜?0@;,Mõã§Ú÷SÛÔÇãkô>Z“üq]ûnJÓítÞui‚C ñ–¯×9¼«{ˆÃ6©WÆ;¤»Òû¼ö®cØ á\nìcάô^áÜŠF•/±÷{c›¶©¸ÂE‡žÖÞ#Ü|wŒà^L±Í½àÌ·û¬ÈJÌÆ²EÁ ¸ÀÒÐ>£êš*qÈ­«ÜgÞÙoUL*{šØƒUeÊºjŽÉ–—«-TS© Xæàcû…µÚö‘0Õ×$†€TÌ¢$c#q0³u"l½`ú“€žÛuc'†TÙŒ~a}Ô‘¯›ª $5› ;)¶rl\RcÏoðþé·6 ‹WÞ UK&0šÌjž6V a˜ôÊãø›Ë¶7ûzlP<Ð0VKÀ[¯6æ³mkˆ_|4Ck?rA—º‰ZIáïèÆ)—›°{”µñ4zßQ²o\2*§šÜ¾-zñQ…?V$6ÏŸ¯ùJï³§_¼Z¨ÞèDP±XÇÊ#é†H¨T[r|yðÉ“ƒÃ'_.noîNÿ¾‡Žÿûä«?Â_O>]üêà³'‹k¨\Q’E±€¢3½ ý[ÄDlb“¸\R¬cBMн¶q„< JJú>æ%8CØIƒÒlÔî”Ò˯*Î|– “(oõË!j¢­ï„è,C© Þ,8и¿ŸÍœÈìÉåû2'(WXFÖw@“ŠÿQ¹ {UM Æ«§WØôÁ‘‹wÔÁ5Ø¡åá“…¢5kã!¢|ˆ­4SÒ~ÛªóÔ8°á=±HÛÞ=ŽRa3—{;DóvhþˆJ&¨3ÄÇé‡M$±Mnßáäçe­ïm䦟/k}S(kÀöy‡—[$ñ—òŠ:¾X@¿S‚zËÑ›mù=JáÓ¹ Ä›á¯aù:[âóN§äàÏ÷~ñ»â“_äò³rìÍ®QÃŽKo˳¦#Ö5âq:®*l)Ýï·ÀÝmø¿‹ð¥ìUØ)Æû³ß¼;»7,^Œñk2½HVü­™ QÚ¸ø=)\6wÄy»¼”?4F1Ž-F#å,—~&1ø¸x‹Ð1ZQ.qþ.Âþ®7S£J€bòŽØÔP[ZkFôÛ&ʧÁº!+2‹ÞïQN#G:øÊ«†Ú¢­Â»?WÍ ¯U{Ãâ…ׯû¿õwa]³ˆ/ÓD6hl]iœ”çд>ÿv˜²åNé~h”•² ¾4‘2ñG9ø]D#´wµåy } œ­õ•RL• åÃæÿæ¤Ó/XÉçSìÕ&ÉÆ¨(¾nŒw½'Îuþc9å5^îbªõ úDŸÔ¾-gvªˆýYs^E±7,^E˜á™Îƒæk¬×WƬo®A«§2ýµ‰ùrš¶Ðs«xh¤¢oLƒÔ{”²9»Noâ ýxw`áo‘/سA/_å³³ ˆ£9m-Pt)êUZý䢂=ãñ}ýoÓ9J†Nç‹*öÉ,2%¹ÄÇ$ÆN‘|h<âãÕâñEòºõD’‹Jdíòó•`$8ÿ9§£ÀöÖÌ8ÐXÌ¡V2Õ_¢ÙÙgsàÎZÛü&ÎÞiµö?¸y©voX¼T€ixàä’…sJô“…"ñœÑP<ó?ôvcA Ùí{düm?º2òÖøpó–µE|Š)C¤ù›4ž±wjïhø&Õ”£Ÿ>¸«™56Ve=üüÄt“7. †Àâk¬ù'F¹ˆOò–üŠ[j§fØŸ«ç5ƒÐ{Ãâ5ƒÐâóUàú-bÁË— lÓÅN2VåðÐ;Ö`U³ã÷§vòÈþÈÍòˆþ|O.Dû4‡<‘Ù÷áò6'+­vSŸãœÖ¯³úætT£Õ¶]‘º¥i/ÖŒ}T{±èêæ`­Õ[æ}÷l_}\¿>€ZÁ?t^¯©ñ:)M—Ç0^Æ ‘åwÓ*­ÓÒt†E]“jµ:hLÚ7¦­èÊ4£Åco§s·Ó=\NÐÙ…~d ­Mg}Õ¾„eÜ÷¹‰}JFøTˆO?®Yè³T(`‚£¤ sV†ÝÔ‹‡ÙŹ/;=üTaÎþ½ñôðS&ÈPåàoGçÇmro_ª÷Ñc7G'â[£ÙÞ>­}ß–&S>dí““RÏ“iYf]ž â}‘ ­Õ‹#ï¨R(Å‘UH® µ÷ñÀÏVAêágÏ÷®µò©³ü‘M”ÃHÙ>KüCýúªö>ÎçTf¤KìÆæ4×û¨öâÃõŠ(6µMéìª9Û2þYH”67]©² jÈщ6Pë!3Ú³ÖúOûM™ã¦mj潘Àd”ûë-b™»¬å{&¶Qb_"¥D—€Rƒ+‘ùãÙ*}í*ÂUÁƒ;¾ˆoZBÈZ+ù> stream xœí\ÉŽÇäÛ\ü ]Üm°‹¹/’,À²$C†áEŸDfá ÏÆ¡†¼#²r‰\ª»‡$x A`!3++—ˆ/–žW+6ñÃÿâ¿g×GO¿†­._±ÕŸáÿË£WG< YÅήW_Ã0mÔÊOÞø÷øâˆMNÏÃV^LÂ1¾²œM :¯~\ŸlÔä¤Öj}•Ÿž‡'˜`}ž”ãëŸ6[ÃÝd<¥¶³<î.öZ'Äî›Üýº™š4_ì/os÷—ó+Êõ3âS𑹵Ö®yyåÙ:5^çW^§¦ËôðYîû45}—¾Î}?¤¦ü!—ûljzš.ȉŦ»ôPv÷sjz(ïmý$…W²}Ç‹ÐË5k“zYîÝ–Þ7©÷99´Ü{¹ù÷ñ_Ž¤Ò“sDâø$à*|YFÞ”5c›Ô"Žƒ¦—é!Îl}ÙÆ/éáÓÜ÷9\‹ÕNñìYìÆel¥àa[.æ•”³»ÊÂQ.ÿ²¹Iì-7øÇüôÜ‹_–brFDQÅîÛÜ}Ó\>=ßÙûYîý4·ý7íXæ&žšÎú»’EZãÃyî;…õ:?i¡ÛaE۠ɧ‡ÓÜÇR“J&î]Êòbù’+ ›uÆïü"Û±Çó~5ùH²ZáM(;1doŸÃÝ[oWÇ=:þýhÊ \4møtŸ{©€÷€Tz‹ˆœ `ídðî‹ÁÌ/so9Ä (OŠîñ#kÕAr/Q”û^/ê&xhÏ,hd%yUßgýEeµÍXd=/á$=¼Ê}OäÂꕱ²ÈϾ½%óîKï›ÁÌOrò·Ü[<ß$+wÏJÛ™³ÂèÑùd½ý<÷>Û°ëoÕ ”Æk-ЬóhÓ­X‰æ~6çr³EÅÒܯ§Í–M^Z©`öQ+Œõ^OÚ+¸ÿ0@y# x/AÔ%*®ÀpJ,„š¤aùñ=áµô @[´08ÅsœØÍÍ<ÇrÂá(¼_®§¸™Y*‘‘¼Ì§rž.c¸¦t*Žpt®ÿlÌÄä(Ð)|D¤uþ¼³•Zj°¹ñ~³U°.<‰-¬câÎ"µH­—£}¢UÄVgic™ê¤4þ´«0p¡¼ù*,dÒ@c^–çeÆVØHä#*XiYÌnée—q%mA8¨­$2Ó´wƒ%Ëô†Ø(ª9Â,‘çeͬzœ—¿„•én€fœQ¡oX«e€;qÞ€ Ý ñaYª,˜uOmÀm™ mGÅÏÂv y*ËA¾ù$#ûYƒó­go2NÊ@d{ŒPZ- ¸-­D±ZhYÖÆbéñŽp^.¨2ß”¡xVÚMhYg«ZM³Û1âgEJo«ycï7À`<¸a‰ dóÔN’;LŸe•º5#Ÿ}ZZ3šFæÐRÇóŽªÔM”7#—)!½®ROJ%˜x}’l'Rh§ªÕlp€e²jS(­Üš½‹&+x¨´(}–¬v‰¡mzb×=ßIk•oTZʉóa ,JCÜDé( @V8ÀF ÎX1U·t“•‡çXVM8Ás˜h`ƒ’3ÆÌ"“1æ²€Ecæ½Ùèt­;§#¼²ßéð|¼¥ˆ*¬RyBHÆdŒ-*I`é ¦e2pÓe°ÂM1K§½ÀV,ÒÓÖ,rv¸rA–p[ *8lNQ>Й† ÞûLCcªugØÀ+uØ®«4ääå NŒ”5Œ >fÑúý™ˆHCÖx5¿ã™í-ÜÀÅ&¸ pÂ'C,¸ªÏ/Ñ™LÓ^y’Ìe&Ïj—$›4ýQ X|8V¨ž^Æ÷g "ëK¦0òeC%*I§ÓËê=oH'UÑ1ªãòñ>Î,'ÛEq)D㡨áiâã¼5öüŒø0±Uùúx ™qèO@e<çàjNX1A‘ïæw Ý©3QcÈRÂ*£WÙ†N6„´ßd ÚvFI¬•£x ×ƒSñyåáÍX‰?iâM7ž 2 ¸¼©`!MϘÅÀ²°,6æ•cVsó›HO(SøeòÒà0‘°hŠ1Â8¦)ä³Å !sÝÌçâ˜Yöm!‘ßeÈL–|þ.4 Ý}˜Ö¬![ÕwÉ Ä,=-­ï,‹¼ Ç*Nd ¦V´Q°u­m™ 3™¼4;³&ƒÆÑˆq”å¬8SD‰Ô²0f«”Áb™VA™´t@ŸÎ{Ÿ‰Mžàaø±ÄN•%ˆK>;ŽûXsÚ¨%—É/ét+,ÖEg‡ÆkrLF·Û§pãåBÇý,žlà” ºÿh\8Í4E”)1|¦M!z¶Ó»8(fz•ðê  R´Á\Ä»@M”íå› {½¬Ø\X;ÔŽ.V‡!ç¡%¾¶X-ÆðÙiOp†j¾6@–¬=j7Ø'(jÏ!ЮŽ+­dÎD-'o mgòÆyX;«g[ö¤LßÌ´÷´Ž­ ?o%Å…‚^„~äL Là`Lx)ÀL‚L€H Ë2ïá©%,¦öE+l%Ù²Ì$ Â7x€þ1çàAzýQ\iÉwˆóî$xqªo?gÚ[QÊÉѱ$I¡pŽ^†y@g“-  ³›NÔܪ‹¦5£r‰= 4°N (²¡„€u6 j¡5F8ÀDŠfN Å$`ÚŒEb°˜Ê û‹V²/ÃÈž¦¶¾gGØÚ±£Ö(аÍjLð°èée¥œ¸c%+%\à.FTFöù=(ù•Ö€Eï²éÚªiÛMÍù‰K1‡;Éf†r™nFùñLK4>5Æù%_"UÚc&Œ¸7ñXi.6Iª÷$—;vˆoO %9¾: Û; C7ä>E¦vÄ:¢* =¶³bqo«·7}ËUdb)šœEAK…1X‡‘+pÒ'‘ƒßnC¿¤JTÜ~ ªéÐÝ9)Ý?% Ú[ƒ D•ñÈû†vŸr©°ù"·]*lJµg[ÏSWf•ú£[2nk€ s§Gu ë/s[®ž'©˜Q ­XFƒûûfƒÉaåM“ôM‡—ô.ƒ{ÇÉõ-!Z.Œó„6VðÈ 4ƳjF‘‚6èwÊ,zô°8WÄû`ýÐ=³ÎÖ¿8êéÈTGQûAÛšP̬ΞŒ¼ˆ¡ #ˆ»UûKûñ‰d^[­Ý¯M}hók)·îJG«rë¶Î–Ö$¶U¶ã¾\¦˜‹G¿Ê}¯›ò Yùg”0ªT3öt±L_Ê\›º½ª€¯ïãÝ­ÔPk ”X»ìB¾þy¼Žtû´Âs®Uä Í‹¹Pp¦t‡Õ ¯ä;Ô ªR'ˆH2)#æbñƒë…ú€u‚`þ°NP ;qAýƒw*d| :×û ‚ûÂx*Àbw£q5¥™ªã÷XšÇýÄ´ Ü ­É«U-ÐÊŒð3ߦŪõ0¨ýaZó¨2<Ø¢#ï‰þT00?W D >$ äúʃëÐæQ|9•qíImÑ#˜3åÆXLU§ôȯè[@}Lå‚§ÔIð‡á%Ýu ›«ƒ½h:  –¶²EH‚"!BŒ¤¶M-GÇò•ÍT¾â¼È³â=;¾N€û 'å¤Ð颤ãÄåÛ P)ŒÎ‘!ûQCdä[]mZCíú¸Ðã#b‰î}ÌÈÆ£=À5×®¿”xSÛÃ1ð #ÐÅ¡Sý:BCJÄÐPZLL-¨¶C:  ¦b`ךÎMTÞ(· 6‡%õ¨1¿Í.Jº·ê |d¥øá Í•“;eŽÄ‹ì±ê1•&|Ÿ=¶¾à×,T݇ÒJ­t•¾J>ƒÏ_§¸Saé}*éCõNš}1·'κtÞs| Pç‘ð ϼ9ÆæÌyq"YwªÎ’К/ÝãÇ'%¶¶8–;‚På‚=Ërm1o>0-mqó8“×Ñ•t³Š\G0[¬z‰áµGñ™TUVXýZcP¾)Z÷³(˜Ú­ÿEâ‹v-T\ì„«¡U>ë(D* škWÞ…ØÎ¿”õ`= ø.Çè±ÔV°£GJ™1³!™®ÃÂîµ9é£î1¾RáV~¨¨{$&±ª4Œ Û’;–´õn¤uÞ>’•:޳ÜcÂ>®mNÉÕa!ÄR›HN—QOå P’¶‰ŽÍ?@ŒšÐd' ß V±üãÔ{0½þ® ýºòMˆO¦À§S@Sñɶؒ±øs‚ÔÚßüÐ[âM¾ ™z û{‹“/JÁ ñ¯®b­W‡ý,+ý„㮽ªòá (a?ó/4¶m*Ï!•Ýóû‡1\=y> stream xœÝ\[sÇuNé¿bË/ÙM¼£é{7•R•dËSv"ÛHü`å\‚ M€€P&ýësNO_NÏœÁî‚» âRQ˜ê™é˹|眯{öÇE߉Eÿ¥¿›«“/ÿ(m¿¸¸;é¿…'?žˆøÈ"ýÙ\-¾=ÅÇœ^ÑcäâôÕÉÐX8¹p¢ïz½8½:ùËR­Ö¢óΈ°ìVë¾ Ê)½Ôl«Y­C0 zy»’²ÓÊ/ÏWBvÊiµüixG[ÿ¿§ÿ§)¡ VZãKÝ)üâôw'§ÿò—åéj­:Œ Ë׫µé¼AAoЇµFØ¡ï’>úΛ´ŒÐwN„°°ÞtÖk¹]éÎ+c4ôƒWÚ ˜^A줲PDºÞ7½]ÙNX%,.±ï”waù±Îôo+­2Ê,¯kãíj­;PZ¾\­eÐ8ÐòÍ ägA by‹–°@½|__º[©Î€Lu^½ ñ}%`NÖ/ïëûשÕHÚÁ»zIÆú1¶!L~Ö;:Âe|TõNà²âdApojëKî­wµW2/òÖ«(zÝBS׃“`„A£åˆ^£Á¤ÈûQ¶·Mãuy’Œ‡³vð°&÷_ᘵµüÓ Œ_á@ä¥ú$™Ò=ŠUvÂÚZ¥FDu¾B;’Z‚¥0Ó—`*uÎà,¦÷`pnùG0<=…´biħ¯8?ùK4$ö–gƒr,øâec)ù-ÒÁEÒ<ð7tk×÷Þ j5D©¯« FQÂZQÆËÛªt”epem}_Ÿ%“<ÇÀ=e SxYŸýç•1`–B¦¥ƒ–âÒ5 ÜÌÒ)’W’.¸–PÀ„ÅZH¢Ãè…d*c' =øHVÃå .ú@²Â@ųh®:t*”°•ø.B†Û‹yÉ!"Qÿ¦6ֱȼoêû/Õ2؉y% ZKåÔìs¤à7{ÑLKÝñ4®]pâ ÎùZ|‹‹5Y#p!Âà¸á¼“ôµ©¶1VÛÎ÷–q€ØEëqåh¾Ùë!–&§¿i&›æB,ò¾±óÑ\h}Gñ+/–…ª+¼ R ?3Ö6 éÐç ²å á2àx» V0&—¥®N–=•Až¨D˜aõß×±½™¢®Ik;0úZa·Ò3Òj7ÀKúnGæ ß–œ@ŽeAt)“¸+iÉ›’–¼Ìm¦%>tÎöMgCZ"ylZ’»Õ‚N.X–¤^R£E£í{1MVƒ6õÑà&Ú¿W˜yÒ¹tÐ)L[Ï´ËÞ¹å«<×$9×(a-Ü 2ˆ §>¡ûoV”ï!\^W¿­8~ËöAÇhšoß·=ŠÊNú^,ÀŽá‚OEñª¤¢ËgÅþ­´Ý–6&y%–sW®Þ”»×¥ 䋯"c<¨ùÁ{f‹r·¶ÕÉ|]î~•ÛXÁ“òÂ85Ội0€U«DÂEê7%Z\NP³Ô#™/"F–BZu—“PŽFœ,›DÏv:RõÝírTwcH”4(¿Ÿí Êš–lÈ6ÀRÁ .•XŒ½ ÷Êy¥qJš©Î¤¼e]Ìi¥ÒਢMÝ¥6nKQøÝ½„} xV|ïrä­Ç0,L,¶rÛ¦èk{‹˜½›^^§Š¯h?í¯r8ûظ××W®S㦼r›Þ勱«ó÷žå¦_ä‹o˽ÿj›ÊCxï«gd…wùî8ºASé^”{}]Qs÷Bn*ËV“JŠs®AJ´±ÞxŸS4fô¯rđ᪢O–hoÁÞö'Kl%K6+Ù) V f€Õ넃‰.‰ Òi+›Ò¥ŒF)ÀC¤Š6”½Ç‚þ%Ú1tjz³'8îΰ@òáÑ¡`6]ZÿfäO(ѳbê52Ý1çc¹º™œ‡Éåé$>˜· [áâ„»03» h½o°-¶I³¡¹r§mÁF. ÎñÅ4Ï¿·é@ж1ä`L‚¤w;q‘—£URYw˜Ò=|ƒ­“|/Ž@ÄÙRB…ëݨÒËàŒíŒ\N‹:¼|[{ Ͼ 5l`B š`2® m¨JÜ’š’(®å6¤€'š‚ÖR2ª1AÊ&  ™QmV"@ÑWbdbqtÎΦa?†‰55ÙG¶hËv Âü"í“˳‰!àåÛÒYäW„z…0—“®0¯¾V¯M­gV“¼&º'ëßÈ?)Û©^Ñ<®Þ¿.èñ›1N©—ä' äãúX!ìFf—§i^­ ¼*Ðì’Ïq²Úƒû9’15î7ÜWjDqxØéOðñN A[yeІ—’Ÿ! ÆÀz}hÝpäHÉù”xM[oµ" ïì±çUÄËêDF49¬DøÌMÁƒH;k°eeø)OØbÞD8ÏOdý˜yõáŠÝÈÕõÉR*hȎݸLHâ©“~sGüÄ’ñ®0½)EæK h9B¤šð\<ÅâäpšFz[ü›”ïIÍdqË›¤f$ãz›*þ‡ó¹vCû)ò9¡0'ž)ÚÆûÕã< ÞÁC\5tüc"“ôž§M†b]-ù­m– e7jPf€9Pü„¦‚çéQ)ºhJÂÀ­H'êÁ^ •¹ñY:8nåžµTtnnwgõªÑ»læDSÐùÕ*Ÿsz`SŒ„EßâA-—ËïÕÍœïz¡"¾;=ùÃÉ &c6‚ð Ñ{‡e‹CÆÏW6W'ß>?ùòùï÷·ïÏO¾üóBœ|ùïø¿o¿ÿüyþëÅ?|÷|qè¾tîHHüÉÇ„SxŽdŸŽæ¾gš9"ð0ÆBX“ˆ ÚCÆõ¤¦n#%œ)éÉÇ"ü›²›Ñ,¦õ4 Æ’ÁÒõΘ~5Í ëç“ïøª‡;J>' Þ†ÅÚÑ¡-&±Tß—:;ÅN-ÜþÁu||bn¡¦Wâ‘ ÷;+þ=H_&¸}ûâ}ØÄ:üø>l "ÒyëbKmCB>I"ø/_ȳ5{]—86¹ï“^'”>°Ž-µDhß$˜§ªäSÞÿ™ê Â8£ s"¬Ñw-ìÙ`2Eþ\ÓýœëJôëûi`“¦ƒTÕðg“›L*W_MÎH¹åoÉRɬX‚l+Û´ˆ7æÀ×CŽ›½ÞãöŸþ<.iEò¹úâ1N[¿gÂó8ŒS•É|JŒ{èXkS6m…µc *Á‘ÓSÀÚ“1ØÃ\ùœ ˆíÉQGV·‚αu•A‡(ë ³ÿôçÏd*I{D_<èà‘¾ý2´ÇŽ´¨¦¨6—¡PtÃÕ?ôœZidï“þy|# Sá‰ðÇd€š?úlÂdŽp+€[è ÀˆÌŸW˜¨K"¾M€jˉ1ö6že(Ûƒ†PìçÁ$èí?ýy ’0ÇCemè‹=LÞ÷KÙzB!=õCŠÀ ¿“´á¾*ZR˜;Ë÷Ê ÿÚÖ ^ðëØòKøEÄWžë} ‚c’V\f•%‚oôxgöWrJµ5a‹ç úÉ6å+­u7êV÷Œõ 9ƳÅ;Ò½;aÛ±uŸ±(ÿضÿôçñHôò`Éá#úâ±­îIØî^t:ÿºD®æ¦'T G—5‰"”0Á þl\Å>þ>7ÛpØ·ÛŽ-¿„mU|ßÕmù¸1æz3—˜¼AÛØÏ_p8Q¨7S™~<†<º-·úä5Û£;V“ÇVNŸªCbÏþ³ŸÅ‹à¡R´GtÅ"Opú)(z³Õ½Ca—6,Œ2¶ßÈÏ¿^Ž_×ûgË=Ylñ ¸ÓH¯îr“ýè©ôTÛúPÙz~Hz9»úy0öñ{¹c2gá |ý± "a]cD»ý§?‹PÞ˜CålèŠ;oú§àê…QzñÁnüùócIûc l€·F^Oo;1÷ÆuP{üÿaî­°?Æ?ûO3œ‡JÛÑ ?Nú§Èµ¬îÊ!•åâÿʲN„ g;°EZr«Ä Ù59%³K†ul¡ ÔÈ ÏÝÕ!üçV2º–\,õ¶’@§«ø1IûýV}é¯lqø®n5þ,‹»c«'N£ŸÎþÓŸE ÛcWâ³õÅB~tü¶9åb¼†Øi4‚”ÉaÄö§;^q‡¦yÐ–Ã í©Æm(tl9(Ôˆ‘æ'ÌÁÞé/?Ìÿ|1÷c<fGúô`ñ՘ЪÑãÑjÿéÏ"ŒöŸ³+«´ß÷룰 ìÛ•PBF•H•’å$²/Èÿêk³/8þÄmŸ}½Ùl×/÷Òwm±°ŒsÇÖÁ€s þ¼òøƒíªÙxQtˆÒPã3&ão1&lý9Åm¿0»ýôØôíª°w£cË:Q#ì‚ÑþÓŸEeluø äw‘`¹þV°¯«—ÝýáäÿE|Šèendstream endobj 1512 0 obj 4504 endobj 1518 0 obj <> stream xœí][o·.ú¨_±È“¶Åއ·™aZˆ7u‘´N¢"â>È’, ‘eÅ–“¨¿¾‡^9gvvFKɽ €ÅÌ…CžËLJ‡ÜŸVuÅVµùÏý=ysðè[ÞÔ«ó÷ðÏÁO+¡eSuöæFBÕ][Õݪeµ2áÇÏ=ûzuóîÃÙÁ£ïWìàÑŸÍ?Ÿ??ϾXýæàé³Õ7P—ô1^›ŠdÕØŠêŠÏ©¨^}yðÓ³í^¹?'oVlÛÙJWºá\½:è{ÅVŒÉªå«¶f•¹ñæà‡Ããõþ§Q¬9¼Y×ðŠRœáâY|àÍú®¹jÄáõz£ª®ÓZŒ<{Ú?е‡óSøk楷±ø~-*¥´”ÿ<úËÁÓ£ƒˆ  E4S<¼­«&‘ÎçëM]µuÝ5^&¢n)ñ4¢óâ¬sâÑŒ©‘gA,ªmåáèî b¹ŠU\Ä*Žc—P…€^p/Lõ+S­ªXÿ[³J VKüÙwVJ×ÝáÏdý'±ñµ1ÅH°„JÞƒb$|ÇÒ ²ÅT¬D§>Ä«ñµ±N©Z°…E‰Fw¶Î‡ª‹DœF·ù[LkmšN9Þ;Úô¶Þ0%°[Ä—]…â—ZBXh÷BÏ¢°®0šø‹bXÑ·.¡o]ÄÖÆ  ~Πòð«õFT\ ¥p«Ž£²~ô/M!Pq­8Âj)Ž@ :5ŽjA’V@3ÉÓ29jÞkíetúãíøñ‚o’è*¼ôvÍºŠƒr1®Úh°y5SJËÁa ÃóÀÞN¡Dì&íÙÈ_/ãUT¼u0Ó±ÃÇkY)h¤ÆoyÒúðh-xÕq• 7zô՚骭8ümèÀÉÎ<¥¸œ=J A—G‰ù÷ìVȽqžu…r‰P¢õ½ð”l³éµ†f*ˆe¼Z·`¥¼Õ:L\’”&" º¸Çy,"[@+¸} ,¹n(³2R˜TZê“Ð÷Âs6Bv•à ×ÂŽQñšcXŠŒä<”¬]™ªD•¾ ·oÝ5@÷cS§y˜£Áµo`+¾ƒ'¶²¢© cTÕÏŠ;Î1yEÓ77=lj…¹WŠ6‚ƒg6 ~Í*OC ƃïÖluôÕÁÑï~@&ƒ^¶mjê·î—5¼)hIO·18co›KÛ›ÇfdpE°Ùt*`óüNã©Ôlo nA]4ƒ“}…űYÖàÔÛ°ù*óa-1÷/€œNk^E·£Á£/½ OþL"7šaÆ·&)`iA:¸Er‰;!ÜN›wß9:G¦ŽM‘WJê9ôe›Ø9”ò1µ IéÇðIVZZõùî˳ÒùG+Ñt{c¥ ꢑOôÚ+Ž|¼…{­!ý„ø9Fžœ=€\ Îs'¡«´$t!A| þY QËn(CJ \Á8¯å¤rè¿óBO¥»ïÝ—6„Bî;¿Sã.Ç{;y¨ºh÷5ãÇ<´Ì}™ªœÒÐŒnyN"OÑ£i7E5!2tœÏRŽyÍuNÕë¤M7ä<5‰œ701’J#Z5 ¥%î`" ¼$Ááú¤2ú!`jÈ¥%8ÀûãIˆ0¸á@å)ÕDí;Î9‘y ¹ù¨ÊY×X‚5PtJzo¨î!I FÊU‹ªí4¾úÎ÷ÚLSA&’óèXGƒä›Mõ0?sÃF„h\uU'šÃoò@\—xbjê* ÅoPS>àOs»ÛÝç]¥eêÁ µ<ºÌïÔ("(­Û}‘À%u‘èñûX c2(mµù؇ºd9Èûã[qlG+êÑéÐÔiFæåJSXJq0gÇõÁâBsˆ€¥VtjÜ‹»Vì‹»,©‹F„®Ñ÷ƒVmƒÔ"B$9CŽ!ÈYeJR.ÉÉä;»PÅTƒ"óFÛ¦¢¡Ÿ^ó^? O¥uæà © %c ÞwJ ´xææo¢Eà³KçMÌ©©Ùz2UqåxDÚ)ƒó;5]­Ú[jè’ºhlaÀ¼‡€4P{—ÿ;`ð‚œì]äar“/)Íéä#à\i¥8œC:¹gðá¼jY»Oô)-2>HfåÑg~§Æ:´7B· .}>7£`ú( [À'" ŠÓЋód”›¬ ¡OÌ;D82ÌCÈòCK£RàÐÌHõ$•Ö¢¨žÏ OKò†óäšÚ2ƒ#Á'© [k³¾rõäÂC³ÑQõøà}ŸÚ$ÒðŸù–Ô•è:ï‹ÎV;™Rêôð±´&=>FU–‡Çù}‡4¨toDoA]d«’Zß 9“ Oùø¸5Ç5ÍÎÚž “Q‹‹Ï¡’θêóGY̆Ì™öé-¸„û p…Zw‹2T©´Ñ ­Ož÷b'°ÞŸ  ,Å>›´€*нÁó)®-ãfBn2ü¥VΨLŒÈOÔv4ûÕ®C¨ö`|‡t×âíQ™tñtׇ^ÐüCÖE³\®Ô½°\ÖVƒHã-…¼“¹ÿ‘c"h§ób‡ÓíÑ•Mú³'Ô“Ì´´L¶G‘’Ìô–B¾Q\7‹K!YÑ@2…o%måǃC ›,-}CQüåÙäü>CZ CLðûȰP5|Þ ônÈœxdlskþ} ItTŽžX“›«f$v HÂZ1Uˉk&'ࣲ]#…¥uê`©á Ä?/HlÁûAû•[1M²f1T¿[4Kq› >PŠ¢êÿsľ{n2i%OóÙüºrÖI -­:¡HwåAt~§Æ¯f{Ë&^R=%‡¹Ý}$’HÍM{­Öðöpmqƒ!šHÓ)g¨H#&Íò8•OЧ¶›‡]¹XsUÕ²å#[¡9¹š ,­—±Zð\¸zeë ƒšÇom“%ÒÚ´6n`—„¡H¢ÍnûíSg2òöÛ °=€åŸ©pé%‰»ƒm¦¹F+ÍV½YWɦë;Íÿ1m|éÓü’¥%SpE³“ÕVÜÖ2²@÷1š|ßmHNæè¥-Ñá:6ÅòsôùÅbÙ6{Ke^RIŽ¡¢¹'²-Ãõ¦«˜›ÒÐøK`áÕeÌ+æ2æEºLNÞ)Y¼÷=Q翜Ìû£¡%šÖ¥= YÁý~/ÞО÷êšo•_Ö€Ýw— –fÿ9`20eàM§¨Ú‚6»a#÷–?¼¤.Ú¥9÷ȳe.­TÕîi¯å6Â$t·•0Ùb ÷Mú|iñ8ŸGÒ™±ó˜$TÉ(me¾Ù ¹w剗–ˆ÷b$’;{ñü6{žâ{Ëù]RíÅ&xÁs)Á[.éàu¶PBá¹PL0û‘¶ ÒH×îç~—ˆsÜ(à̇¿N6!Æ’È@ÞñÔ©ôÜ«£´&<`DUÜ/æ7yÜÇ…Þ[rì’ºh¼€/ÜG”[š…÷!`Ðû¡) ‚àwË®ÀUM‚Hi19ARÂ.Œ7‡¥®è—[ ²q~f¾p®Uá‹ËÖÃîqa~›Ç}™·{K[]R ¼½—TSÉl Ä*åšb»ž˜%¥O­„¡GÑ$d¸9=õꔢ*Éâ=«+Så°Uî48s¤ƒêæìâ)® =Hû 6ÄÝÆ³GÈÄç–•ºV¡°E|i«"Ó ï©‹ÞòÑã±¶lÁÆØßJ+ÐãÒàñm~›Ç1‰©­‹Æ7&çQµ ßê&œFž8‘Ž>—ô|r¨}ûŒgiñ8ÐAÒy˜Tv2 ‰†4jù\œ GÅÕç!éïÎ3¿Íã0Q󭋆œšÏ=VkäjZwÛŠÂ6±t*f•&åÂóÕ‹w¯‡ Ü»¿§éã®OñPÈÁáñuÛ&+¨~o]éNiÑ8wIJ¹³;Îoó¨ ]?h]¤;BEsbZæŽ3¬RnÈ(¹n¹%i.wgz‡n² ²%e|4ñž]\Rγ‘ 8Š›^Ÿ ŒúJÁF¦ W™ÌòY =ÖÒ{,J|”c}qíȆgÚ!ÏžK‡êscôahAïÆ¡£í²®1©·’’ºA—¯¿_7u%[iMÏf­Ì|Ú†¤ QÀ¨Äu—å{ú‹h¯‘ü@ç€ùBéÎ'ÿ8ßS È×Þôu¨&éA]uÊuBÃsf?¸oXÂ;'îÀ›ÍæQS’6Õ”L ×ûpí}¸v®Ý†Òu¸{毑 `ܯûᆠ(¤új6e-Œ˜FÒÍLU2Æ&2¼F>që*£swÏLM¬b:‰'¡Ä°†bÆœŸÒ yЀ¶,Nè2€'kUédÊôšJ¾1Ov•jUrß$”ô«ó(¡Ävn¿¤04 Bõki¸½¢nŸº×ƒ§øM~l·44»’‰õfÚ yÛ|kKÌÆÆÜÍ_¨|áÄÞ¦0Ë6ûK[-Z*#…¤-/£’n Mo×öÒIö<½‹zm“”ªµ9wfèùÛ» s…s$„²\J›±autºE̵÷YÉܽ×^e× Šœdµ˜ÒM¸{‘éÖ”®üÝ Üi¬ÌèygÜqæ\A ˜™Ãý.·ölQ-F—ÌïŸpSnÆÎ«õÎH&ˆ¾fvœ5÷ (Bt&亗_j1-øX¬„PÙ_r1 SÉ2¸àº’irñG•fKn[wËЦµ‹ÏØx‚åfß¶Šr£o[¿N‚ï… nežŒY =úИ7³>Œ0Ži@®tê-4§æ`ÍE⫈žyÓ$‰پèô€‹ Ðœ:/#õò?·¦;¢…泘Œþ«äÔ¦™LÖúEßFŽ­‘e¾›­ˆÓá⎮L¢™–Jù() ÇZ™ƒÃ^˜ŸóŒP˜÷»V¹© ‹×¢ÁKòj»Þh­,<\÷à"7œ•wªMÿ€[Ö0LX76¯›üöì¶ì¡Ñ˜ƒÁƒÛðà{岿ûb¯† (anf}ܯQúQä1ŠÄÑá1väªþÜOP±% ÏÿB&q>X´›Ë2a‰c·ç U¨ª>XŽäR#Ÿ¤z¶kÏÑSê0ÙÝ`*5xKf‡3Ñ@ì©Xɪb~ªY>©Ž¢0&¯yU3†7¦LYïìI%X#39@ì­/\‡{g»Ð>{‚EÚ„ÀëD,fŒ‚çÙxÖÏLœy´Ø<ö0Þ÷ –xeg`LyT†~à&nnñÖM|q&×pûAd(‰x‘›70àþ Ëî zot™²¬ÿ)º¬LÄ‘iÄpgºübm°¼&#4$${øÜn[9r2}øu:UõÙx,&Ð ù*½ÊˆÌsàX~®=‹4Ý Fîk·-¬y>Bò’ÊÒML“Åm¤O΂áÊ̤UÈÓÝýu@ïFÏ÷Iª5Å%³Q:kì.sÍp;2OöŒ¤õ'‘¾îuÜÕÍá0å5,PûkÇÆÙgFŽÂ¹uë¸Eþ+V |/I8ÊêœÛý²VD`x¦ò¶`6K ˆsÅl¸ÏˆíOk^›a6üöHb´ß”ÊøÈXK#7žƒNFÍ>çÚ88¯:šJ™Ò¨Ôá§áÚ‰0aN×":ÝxVn~“\ñÝ€†ãGp‡ÆÉ¥ ú,ÜûC:à‚8¼?Ã÷©]‘ºqþâÌk$hézâ Å$÷uÕuMÿ×6#—¡tFˆ ¤±yIHJ'á¹kw·åh¹Jä8¡Øè]÷ò&Üþ¬EvÃ{kékÇì¼>êø ðwñMxå}ªS(DCûÄ_úÞž†{ý¥/|î=ó—¾ó…'ЈÆD@•³Y¸ö:<ÿ*6;›¬'œòlØúëôq(|‚ÌoÓȶªy¤‰=·+Ì/º2±þ¹OýsŸûÂï}ÁÔo–Õr_¼ÀôDÈÚV–Ñ“Ô%¯²þEg»ûi¸ûøˆ°ºèœÑ›7áîKân4ºGCÉÂhaØŠ–ˆ–¥B¶ØÁã9Ú`ŽGÜËæ ‰ÔY´âU ñABçrƒJÕŸïvúÎ]ø©/ü#Ü{î/}å ºðQï¹æw¯Cü+ *èüÔ~ â :ÿyËhÙ÷åÀV~öÂûœÌ|Îhß{Ûi&˜thýámQ\qðbá.׺¶Žœû2¼rœ5aû‚9KŽ>OA°Ë„ÕAg¡ªDK¡Î ¥Mtêãôf_—¹ËTÍ£—^%}¿—2®î¼j9”Ã\V5+ ž0ÕrÌ‚®ÜEÎ)ißü$–fÿendstream endobj 1519 0 obj 4865 endobj 1523 0 obj <> stream xœí<Ùn$·µAõ?ÆiV-8¼ÖbqüöhÀV,,gS‹ã룿/åjÍg5÷Ëaµfƒ—Vª¥êŽºÕÚ{=h¯–×8ʹÜ.᪎ •Wny¿âƒ5BšåÉ@·<[I|_(:Ø›ùãß…Ýñ…¼Fá²…¤önqüõÑñ¯þ¾<^­å ¼–~y±ZëÁ9ï%¬`£¹ahx—À`ƒÓq÷ÎÃg™X§ãF\¯Ôà¤Ö àà/å8¬X_;ëŒÝç_'éiw û\ŠÁ©êó÷+À¯*ñaËóÕZ1X:vUf’Ÿ·+îî”Zþ ‰b¼7R/ßãûz.@J Zùå»ÕZ À?rùP°G`"@SžÀ,cÎðô×ryY& —ÌòD Ð`®r€Ò ·8ª«{p½ÐF._‡õxÎ5p†ë=iðGÓÜñ§ƒ]^–Œ^VKˆSoÊûê~ ÆeõÖM~ëmABE07#¹KPt»¬…{7 IÈZ6nWÈPBºAŸÇ<”§÷qÑð}‚í‹  *Ù ¹ K}Èϯ&4ÄE‚PQR*\>–ÏÞ•Ÿ„!N ‚>×>Fþf‚B¸Il”Ÿr½ünenÆ57Hì@³Óž¹åA¼õ3 x¨¸L03(ç·Àm™ð®Œ>í“”¤¼bÆ"±ÖÂ{T°k.F‚ýtƒÊ›„d,²Ø×=´T"S´Þ „"'sSƒ´;Q,¹I(>µ‰äü›2á,‘ÓŽ4¬0t£º&z[–/ÀÑY6ÀTÒ#aËúÆE[ÝÁB"ºéi‡2u¬ñsªê/`¥¼äLQ•Ñ~”Caa•â›JO%üœP]d[34Q¸‰Äá$Ìðì©ÖNJJ"¼geýõ®…2ƒ…¯—|Fã4ö£¼EG!n;2» ËÑöhƒƒ’©?õû•8 º/®™—¨°‘­\L,î*™@`nMö@W77÷–®° Œ%2âÁQ¹j•vA|˜ºñª•]D¼ç[79ꎑÖàº9ÇøÈ}ù~ÝÚpå™û0ÉJç&mfÆ Ö –*·+Ð÷Ž«dåX¥^N»êãrdd€Z:;"ÿq`+Ìœ—åMÒ¯Æ%Ðnp‚nÿ1‚“ºŸÌ`YÅ7­çÑë„©~I^W&ñþ0qˆ5!,Cöµ.s'ö¨ïi ÞûdÔ Š2»Ôsë{EqÝÁN¼0cÆin‚íÜ@õ/3{†e ­eiš°–e6t+Eô+¯‰Ð÷šÏ°–¥õà·‚/6mU¨sRŒ7zPX9¨ “iw=P—•äv0Õ4¡„Z éo¥Ê¥elæ;%œ0’Í‚ù uLÿŒ³ñ‡eÏæŒ¤S¦Åç¦w¢i3ï¹ :!Õ\É'æ”a] ¤Íš ZË(‡Öuú¼ËWàz¯©¤ß• -y‰›$±I(½|µ$õHllb^ô['R¿WÕöWe‡Ì'=í³§wÝmÞ׬ŒÅY¡-ÿ1ÒÈÿ&®&)œºÇêsO17 ¢ s½Z| Q0ôó¢:è~DtŸO J+ù•Û”ƒD¯kKÇÖ\ëiHF͘é©[ØÐíj*ÞS± tlCçÒÈq®ãA5ÝUY¦LÇ…jãÀÈ©¤u\(`ž‡®nšh€@ͺ‘*zW%Ðí£j«ûuñ½ FÇØF «ŸÜÌE\ÊÀðs¦=J•Nô¸Mpébdb«ˆH -yjÅÿíJ‚É<ÃÆ¦ÖÔWr½ÂÀv4‘éñ}Ò€s½þBîÐëœ^£¶zwQ1€u·‰ÂÑ7 ¾²®¸¡ßÍv;ò¡ ý2 71|'ÛU¾Á‘•a"ÐÒÛÊ¢ O¬0¬Èë„¡‹â{ïOx·‹b”ÒgºÏˆt^ãT6ð1—*#°gÊÈS«ÖDßWCF °™ÝŽÁŽdÎ$×ÒŠ (fmb!,?4¡Æˆ¢b»È‡ 0d¢´è& ‘@›úPCßSÙ³-,•»N=¯æ'4Áû»/Mt'£ùmmqÿZú”z®Ýଧê?A¶fƒ»v¼Ž„Ì®Ú$öAmÒon»)rOŠN¤Ž\`Õ-¹ Ày#BÉ}û-ßnÁ|[Ã\ĺÔS÷ ½Çò¡Ô»çÌŽ]ŸÁž›Mßûõh³ÚÇì–#^T¥®ÆnùP¯Šbß÷ýʪ‹?µ-Éç£uƒ]ûý“a:˜°'Ÿ [~–Ǿëäó_­ Ää"DúS0Wy졆ç±_ÓD#J×hWÿÇwµëk´ˆ_³–ìã* =LAˆ4ôëø£ë J2=Än‹ù¤ÏU6i©ìÝeË3çDŵ+ß tlã*N2]¯Z×yêûˆ#GèzšçÝŧVÄÝ® ƒÝòÙ§ñåu~üã+ÊM!Ž´!‚ q‰¬¼ñs¼Î¯¼OCçéGáÆ_¦¡¿¤ ÛY‘QÑ´“Q¢±ü:=-ý¯'o–­ä¡ÇÄ£¡i0ZÅ{o ‹¾Hc?N—x~Üõ@ H´ 6ûB¿$`\øª¯^nߨ££‚×Â-­Ä?M3<¥ÿ-h n,)¶\t>Ü¥`–àD‡ëé¬ûš€Ö–^œ2ÔLÂgŸ¥¡Ì|·ÍN¨¨ìÄR¦±U˜µTü!ó3•†t­‡ðÙ«%¢P üH÷“Èÿ$ò?‰¼µÅ=Ø*ž‘?‰çÇϯÒãüì8 ý9Ê"¸‰YŠ 3é³SwÙ ŠH™óÏ/ŒñÀ ŸxBGø$Ÿ­(šððc‰â‡u+¬Õ¢Kï›_9óâ°éBE±ÿ}$¾ÜGòeLõ…†ÏtÉM¾y$ŒéOJÉe$Ø@ a*¡ßÆ(ZO<äׯ0ÄTª²(7h˜ûMùf™zY¦žæo}‡/EàÆ;ÅË‚Þæ‹PèÞK`ËPÙÉiŸ ­ú]$ÃÐ?~àúˆ)z@,t_¢éö*žSjŸúO)‰ìw2h,±mLÆ8ÛfÀš¦å³iZ–c%«ïµÇÌçÞïÝhz0@´ƒÎëÐÐpž·‹3q:Vw8´¶cökÃñ6n}èzþ9Smì r~¶åC:ê´Í—=ëÙ6ÍõSñ0ÃqÌî}ªãÙ‰½›(![¨"L@æg?còä]J9µ®Wåg÷XW›Eä`ËÝ "e­±£¬ëõ=IOó¹Ej𞇭®ªªCóA’¬¶wˆ—¦4îÀÇ`ÕkuËB¸÷àª'£çͯ¶ÃŽÇóê.…™³%ñ²‰þÍ }óÚoC¨/ÁAä*1cµËºÍ™© €»ùjOÀ¹€ .a½y}$wu0$ÙH1á¼ ”|õ¶ì¥ßñØG}ê r®}©»³x]KXv.^Í÷æÄÆ–nñ„<&-ZÒ—õ’ž²$ÕE‚Ø»r`jÚ+"ÔSygs ª”lmöW)}•ìÀy=„Õz œŽfwBÃöø³kv‹WÒ°èQ¼ëDno;)–w$‰2 ãO§O·†Ãívƒa¨¶ºÕ6ô;ÞvGûs‹Öª/Ù²©g/ÁÙÙ¼Ä;Žú"VˆtmÕ7©WîÔäÑöïʪ«/iBÙößÖûŸ½›§î){‰Õ3R Ø‚±ô¬½žºuss{éVøqK3ÕÿÓ›ÇÖòx]ÉLåºßcA6ð]¹£gkû> stream xœí][Çqò¸¿â(/9xGÓ÷n)0 Å´C#vd›€L?¬–Ë%#r¹"— iøgø§ª§/Õ=Õç²<Œ À=˜é{w}õÕ¥G?næIlfü/ý½z}öåï¥77ïÎàŸ³7ZαÀæBO~L˜¼ß81›iöXüÛÇg_>þÍæþíûë³/ÿ¸g_þ;þóíwÿÿbógo~‡ AõØŽ3´ã'Û™'yL;óæWg?ž‰eHéÏÕëÍ·O`ÜÆêM˜‚•ð÷Éó³yòf)åÆÍb¯Ïþ´}w£QÚ‹íËø ªlŸåg~òë³GOÎVc.¸I?dУK+è€E­·ÍhŸœ_¨IíüöÅù… Am¯Ï/¤–“±¦£àïlLg†öÔìÌÞÛÉ9½ýáÜNÂ*a¡’˜'å]Ø~\ZònûßçBLʈí›òèí9ì6ŒÎ¨ØŒÒ“SMãï°ñ0)g·ïK­8 ã¥Ä±Áð­ *ÃÏv{_ë¿IƒóÔ¿¿‚&ueŒÛëÓZ”t𪶠s’RN6Èn!ÖµH_÷µ/Rëy\f›Å%0zû‡s1%fM`×í+ÁæÊæi6VÝÉ êOAãFçÑóÐóÈKµ ^`ƒŸ†x°ÁYüûé’¶¬¸€QØÞh¸.ÐðÓ¡Ðpºï€:Ú½Ð@ÎÞõ9ȆƳûS•éÿ‡†SAÃh¥SÍ 1pý†›+®¥r“R2½OŸã ™I˜°àtÚážS,b$œš'Ïâ±.c.ÈdèÓ÷µþ«:ë´,Vù4j%äÐôy Їýß«¡<5©+4y£OCö@,`‹°_hzU é²<{×ý·÷åÙÇò뮼½Þk8×k'›ì.X#3ššåuÅÊøe§G#ÞTa»oÐ ÛE%`ú2|2(Sì@QIœ €¢aš­ï@1>…^ÉÜ/«tÞS™Å1[¥·7¥+‚DæÉÿR[EíæÉÁ .qØ›8„ÄÄÍØnöa™·ö kã®ã.O—9:!S7k‰ë¹à@J†5‚z787ÍRÐu¹ÍË9Z-òó²@üùCjWXZöEí¸iz““Žª©‚œ8ü‹eüp†¼ŸÅ2»zÈSkºKK>W2 {Z]VË>E…¯Ãö5Vl‡ ³çóº½éµ_Z°õCrf.©èN4º_¶¤š'£Üpü¹QÒÒ=+Úäüÿ¨Bx "ìVdˆ€E‘€ý›pŽý†8Žm-þ78¶‘ØM„÷»¢ŒÞeô²<{³óm¯Òàí^V~²)îR_d~{Yù'™,\½' E‰­›OÆå÷ æMÇY¥¶PV½ ˆ î_­¾pcþ¤^qü†8¬½;Òø0øÐp ;|͘è*#~ưä¾Ü>ö{²)î‚2¿1|?Á¾QÍjΈOvDe]6¶ëå'òJ´:]üŠ t(¼±Ðæ0Íyövq˜xh¤ `k ˜±¨tM[{a³… u6¦‡hÙ7윬ü÷+>›}¸ Æ 6ü|Y©íÊÑÖ~K·q¡Áå/ñ`¸YEöMê“JÄgÁÛdfzHjb}|C#”vz#40+)J;¹C¡e® w ØÜ„À”õBæü"€Ú`Ô|wîшÖzYí¥ìÇúóúîlˆ™Ÿ‘’Ñ; ‹ GàçÀ-µ xj[œ‡]@›PLÀͬ¡O¯âO§¢OµxÉtu›Û×Ûß—öß¹ *X‘FçCD7¤I×Bës02 r“‹ö¹Ùš¶§\òž@¡ŒŠbŸ–jÀéÃ¥V€fÿqöä_Êêòê:°} ûTà’›ÉÀ˜®`"Jà ®ÝÛÔ½“*`GԹƂf6«—RÙ4´VWK8xH_RÑF…ÞA…î«3€ ÿ¦¸­?׎,Û€ÆPtw¢–LŠYÚUEÈgÙaZ§Ä…ëÛU°è˜'šfŸãÓ€hÃ;C°–òѹ|€'";—n’Z™6ÎsS-‘⌠¯WÈÞñ¡÷ƒ±R—Ö&+DëËPZDÇõlÑÒcÜTû¦afVrû¸‰&*e'5Ô‡°+¥€!Щ¾hœŸq³©>­ÿëê{›fJÇŒÞIP±ÂºUâƒÑƒ¼qXœ‡V Ûåª %ø\6ÀhᨛñÖ“˜÷S¥…±,ûÛºñs9hMzDº(h£©$þcŒáàßWIxÄnøðî(ôh ¡2x…S¬,¾¼O²ñ¾*9tI“!ä~•4PÙNsdóÖ4ã–ÌC™HRz/ï#ïÝ®ŽŠ–µ¿M¨æìPè³Ñlj2uŸ~†·ïc÷HT$\Òs^#åá³,Sºí'>T†ãÑ’@(åä™=yŠè ã·ûXû Uï-Ц§Ñû"³O‡0ðä=VhãÒ¨]옺Ø×vš ÄóOð§‰Î¦3®h w´À~ë%Gî°Â xÏxY²iâv›&+¶¹¸»–Vu˜E‡ɤ°¢SÙKdÝð¥êüçåK x³Z&à 6˜1Pd[ì[8(†P•yÊÇÁø`±=°ÇléÀP~ƒ6‡R³nŽÁ0t‘<w{ŽôÐÒÏmÝV£m—YÔƒ/jÄpŠ>O]±ãüS\+cŸMqŒMºÎ²À!q4.…ÖCn·úé¶Nzêæº†ìm27@€ûvy*àà‘eÇò-Õ>fgV&ÜÆl?°Ã#Så /Ï¥|ÑŠ‡Æ§çÉùäÍ`jS+ŸIO?:vl„. v6:7«K¶Š£ðÁX‘ ¢ÜoV*Ë®Š¸»ƒ )Û1¾˜ãÑàû-žgeevYÆÎ¨a·‚ÙÞÊ©OKþœÂKr[ÀWÖ¾òHLˆ$¶ &Ý Ïë¬PkcDà¡R[šýçs0[‚öÑ(”NUY(½A8__´#<Ð…wzÿlxˆ ‰F0D ˜î{Mޤ$²䀱íWãùÀš†¡êiVj‡ÆÇ­ 3çêü„ä+¢†2â6øpÈ ï³<µ¹NÿÉl 怄.1Ä@k;^ÚŠCÂCX´ÈjõøïHðlÅ:ƈ‡©J,Äà^{3™†¡Ü)3`¸D_ö˜ÈM‹&¹ì„F—„Ò>quåtÙãhŽd޳xUjÇž.P’Æ8niGcî¤@£Í:J!­¢‘À+BˆÆ“ý²ŒCïrã\h-.ÁÙ2ص¹›ýG‹)à(ô]²ˆ›ƒVbȣຜ-½NáÌŠÛk?×U+&-49¼=’üÎ1 xÅGR’õ€p²nî¸âìfKXà× ÃØ‰÷ óõ(vYâ‘â à.i¯›$œ¼ü¶ó¥àD€Ë ËEžW®ý¢ÁbêN‡çéeóåÁ¤Hìt)éar&K)βå`‹”êOYãGZù5õž е_Ô0Úõˆ9ˆ ¦‹s¬[‰@ÅÊïP²³â¾ $y•¦ÙC‹¾™¯¡Š‚gœ33à=lu/¥`óîV%-oHŽÊ&¿ÇÑÐAkNK#ùø"ÈÅ,Jáè@dF¶YcZˆ[çÉòIÖ™{Ñ*‚ØOy¯8›ÆØSÖ>Á}Ÿ©]üU]úîrr<¾/ |¤ˆÁ‘³Ò™( 6(úË+I:´b ¢Q÷Œ…–GQþÇ`£pÉe¨<Éêø'ê4P¾Ÿ‰÷°@“VFذ­è“²^S—n+è¬è(¦­E$Â(ȤÖÖÈT‹çÀ DïëÏTMgÀ{ÕKè7ÐH«Ïªk„µ“ ìåŒæ”æ{ •–¼àJòqd*{,_kØ›Nø‚*™ë(ñ(ÇÔV{¸œë%NnȾbÏ"Áá*û¬‘™ï€ˆ‘Ÿï(Ú§çÌ'ˆP.É0Œ†AÂh† cÉ2x§I[¼/8ºË¥'Íä3vþñ˜W …lò R0Ü,é{|0œhä%7!׸rθ4T.*€ Š>m*Êâ;X“Ð8Þ…„:©z*I(ÃAeæÚÙæHWn†²žÃ&7x_÷JY7—G­8ħc0Ns<Í¿þiçw¢¨ ”Õ€HçOõYH§9±wˆ·ˆ˜qÞ¿<— ø¾$ÎDzð¶Æ_Ÿ#ðêhÛå×÷Y÷­s0“Yl"ÒôëSÆèôüuËÜ¿¯wòo™[÷_•·*ÏŠ½²ýsy[öpû¯å×Uy[?Ò÷±|×ê \‰v!}}Î3Z’/eÕq-Ÿq.}iÄ9Rõ&?úyþQG÷uzTï3ò;'BÔ.q%•„ù ¶æm*[wW¼4#^—PþÐýÖ#}£¸,»øªüª{÷¶Y8q&²Zu'îÒÛ©o7_L2)†oSå‹òúçKÌòïë,_}YZö#òv¨ò6Ô·O·ùuýnÚ›vs[[þÝWíÆÃ¿–w¦vsa­í%·s~6—b;[7ÑoÞ=n5mΫwß­û›£P¨¬Mñ¶1ãz¥F[§ú®âEz€>›vYKïpÂëòd±À@v‹< °é&›„ÿס§‹”ª|–Ã÷Å~~Uw/ýxRÞ 7ƒx† Ÿá ´«Ü“œn¯¦ñ¬ôÃi|-}JBx×Þƒ½ž[’þ³~4 X¼Ç•AS©cò{iÐ,Ô5ÕtúÁ®õ5×÷´Sx«‰´Æ´ÂUØ ñ €²q举c.…t©†­³Žæo‚ ssví„m¯Rò·‹[€ò"†âÛ{ÜÝÍw`ÿÞË\SØ‘PÜÝzǘ£òð†w"\LHä¯òo-ý € v_Ê_’Å“ÔÚ½ï (OEÙØÀÛ-ü÷ûªå°JÚ‰.»6É9j( ÆB]ªú¸Ê²¯§‰™çþqÕæyҲɲÃCCqbàsÞ:!¾ÃlnÞ8€Yò̼ÕnÇ3ó/:‚¿¾a˜ù×™ðà'(ò×LÇ/˜··]Ç•JáÛ™tÒlÖ¤­¡ÛUyðeGFf²gDÈP‘l´K‘L¼©Þ¹#’Ú²›;˜¸òÇ4YGßQ×î£[E¸Ïµ„]òuüÀu =¼©¹¹«Sø†¸ßÿ–]Uý÷®rê Ÿ ÕD,S25¸õfËò…Æekb®x ‰1ìMöéäX—ÞÐ… jŒqhñòÒŽ:œýì;O]úö±)ç4Ï£ROó 9ÌŽš TÕÓµÛ÷Õ¯—EKêÓ‹£SáØÐÑý2Èx_l÷Ç©÷)&…ŸŽ Jõº<Ë.‹áxß>¢?îQZÅïÌ7=_¶›HŽ,«­÷gÞ^Ô§ÄWüž­Vµ;É~›’¸[3¢~!Ü…‘AÛuvÝ)¾/ÕYÇßA^¬¢ì1=Þ,™jZû? 9ÎÀ’ÁcúýŽJgB”óíëzI/³ÿÝÙÿÔPendstream endobj 1531 0 obj 5396 endobj 1535 0 obj <> stream xœÍ\Ys·Nù‘¿bËO»)ïhpNUìȱ\qùb*v(’:J¼$‘–™_Ÿn ŽÆ †;³Üab—¥1fèn|ÝèÐý~Õ6lÕâ¿áïÓË£g?sÝ®^ÝlY£µbz}ÝëJ°V®o7[Ùb}ž¿,^s!&øúej$_¾I'fæ˜Yÿ^¥ŽŒþ¡û½pâßÇßy12*.¡œ]ÿãèøÏ¿®7[Ñp§„ƒÑR™†®¥ ·UAÌ®]i«m;1Ÿndc…R(Â'iQrø¿~cÛyj»Jmém•î8¯Œ[œT:è»n˜ °ó L¹°Æ­ï33Ÿ6ŒÏBõ¤fæ 'A6F*“< ñÓáñ•l:ºÓ·wùñ»u\i3ê[­‰Òݰ~Æa"¯ÓûW(,púûüþÌ?9ÆòÏúˆÑ¦þ’ ôDÂÈ A L‰06~܈F)ËùºŽoZ!"d`–ƒÀ€ƒÙta¶…Ñâw¹±ãµÕA+ZÙ´†EÐJcëv.HÐI™¦Èˆ ’ñWP¬$wú‰Ô1á÷¤°)ñSbi¾ô¤ àçŽÝp»q€íq®›¾ãeMË£½½Ìø¸(f§“‰\‹DÚ„ÆI âW©ñK”yëÙ×`Ðæ_D­†“"»JŸ†¹w­Y# ˜K»·E‰ú•4Åòüøè§£÷+¦mçSÀWvÅ9s0 æUâÎÈW/Žž½ø~uûáîüèÙ¿VìèÙ·øÇW?~ ½øÛêOGÏ_¬°'ü½ïˆñ;2ÄŽºgt4æëÔ×DS«gº['-"£‚3Ѫ§á  N9û¥Fîiïm}Å9*Ð7Ê™uûr6#Ñ‚–¤'ÞÑöx@âR>Ù{’·H´Ÿ·¬Ôdù"óv’g3[ïó‘}†KóãaHøÙaC£Rfͧ#n>c8aFÌÅn'L»™ÐÝ'­…U¢“+YÊNü:iÀéþB7«qªïw-$ H;ѳ4—=„ËéèÓÑ3Ÿ‰1ô´ªE_áñèi!¨™g®æ£G9t¬:¹fG‰Àà†øiqxwbci”‡éØÓ±1Ÿ‰l(ÇõA\"èˆ-î) f°+ ¶‘Œy^ecS[t^v¡dqncHâæB?s#´=‚{bÁ|SóIÈãM‚J@Jo«•4 ¯¢Ò `(íÄÆ]ô£mÿxÞ7%Ÿc,i0 ú)X2¼]f)$:=«D;ti y%”OWP;]Aç31¦ RðƒDJò¹{(¨ÐVP!ö`‚‚Ú‰‚8gø]ušá¯,=ä„¡é wÓA>Ÿ‰1‹Ö&$/¿ ñC/A|ö&ù~ç·ˆF×îcàåéÕ =íDïâê¸4l¼:òÙ Ë|µ;ܨ•óyÓJfg÷T×JfÙòKOë-¬˜lö±Ã~ŠY¥lÀ‘P™œA÷Ï/§7->ë„¡½àÎ&Ã}>;cpoõìžêpGI/½/'}n wèsa±ƒ;¥ý‘KÑò$wKQ]Ü ièÒøA ¥ í¥¡|²†ÎggDC¥³{ªj(t$ß•¸zxA‚>öoƒ†ÚÉýêÆ>a®úïBûâsáÑNøÙ íb*Ú÷`g í–Ív vuéM\ixºKz0´±°ßÐNh¿«Ý{;ùkqY{4z÷B³œŒæù쌡Y»Ù=ÕѬ­Y<Ä—<‘GùÐçÂna@3¡ý±ÞÕâ$ïŠüX\^ ½{) š¬€óÙS@¥g÷TW@ðæ%`Ùx#YJ»°×оëà{™ó{m˯¥Ÿ]B|}Û­vCh§V.¯•„ô½´ROÖÊùìŒi¥”³{ªk¥Ëß–B5‡VJ¡vNƒRfÒ§“‹Ót2ÓN‚±ÌFέ٩‡K£Äëa&w/54“Õp>7cj(øìóÚº ¦—ßYà¢á!š}µ­m™¤ΙLùą̂rô&1=oÙфҞ¯•’»ëäªÏmõBq 'ßúY|Z<î k{ßMþ|vÆ€Ïf§C=¶{=šÁ«[¾3ƒ×'*æLÆÖ'å¦Hn^‘ëÚÏ‚“îùµœ7†C2ËÈ£O£d÷ažv @*¥ßr5¼JW°Ê8•äF^ª“Tém½A´ö° ÇœmòÁuHz´Ž¬mƒTKßA=Õ’\FNi›²¾SY,÷ð©CxÕ?=ïòae§‰>é/§P‘‹«Õ¼Ãœ{™YzSûÍ@Öž£˜WÍü«âÜ© 14uY”û)µû¥¹æ$¸Ó˜æ¨iYø~Ö É4$òý9`IÇ%yѹè§î‹ÆÌdŽ»\ŠrÖO¦ò‹)!1ð³íбehèZÖdªÉÀ|ߪÉxLâl̹ç Ö ó€Ò‡Lü›šÕ iÔŠí.˜wm+»ª0ëÀMè,JZøË\–60&Ô=ÈUŒIï¬z€Š-tÄG¦ÇšäææU6b#Ö$Í/é+‹ï¢j0³¿8,ëul™ò¹Ø`Q·À#}~¼M¯ÿÚýDÚaø{sÈ£ö°ü“ßÖ±ñ²7]ãÌððez÷ylú&>§w?B·‚ƒÝúçøö‡ôö‡òðð9C÷K΃¨ŒÔB!ZÿE¨ÑúÏøðKz÷<6ý Cƒþ:'Ãú¡ BãD˜è\—#1@^€ÐUÒ§éû“Øô±dÄ÷~Û”¦mÔËFsJ¢É^¶È^öô˜%Ä*Ñ£Z'O*,°Ýðûìrß‚nÍ…îÓdwã$²“+›C‚O;¨ÕÝyÀ“P«}6%¸âö'ú]|xÛ+…¸#þNãù0æ‹^\=N£ìòñÀB ìÀ‚äÂKõ)¤+ù€íŒ h`EªLA°ìŠV< ÁxRT—ôyI8ó lÿ݇)`F7­pû¢ÁòÁ¯ÕrÏê)¤«`Ypü‘p{¬Ÿ ¿ŠcSÊú®?×Á°‘‚­4Næ"us^uúN³S5ôÇq[‰lÜ&\Qÿïd¬ß\”6øu†.ÚW1Nz¤Ð"9ÿÀ®ú{ð¾”ddÑßW#ZB_}g÷ªpBåIJî*z­|ä …x¨»¢ÈoÉi©JÄÁlã¬.Ü$—÷5‡ö¼·î÷¯~D'_é2ìëbQf­rÔx¬T' zpÕwI.Òðܾï°B`äÒè±jÙ†ð¨«Qnèo ¡UÞ3ěЦx?IÓ92gcÇ |Õ #³K`Z­š¥UÅ&LŒÀº…0Ýw5/K…̤=ÂÉ®€œ8罤gÕ(½êu¾ZÓÁ÷õŸAa$ñ,ú§rŠìÙí´®zÄ~<ÈøîB$ ò~å~œºPb„UÒAÏéVªá¬Wl.6VwOð&‹qÜ8ÚýX”CXÊÓฯðàJ.°"ƒEÑð«!pšîGö Éfî÷Ãzw’Œ[nQÒ(ƒX2ƒ8/Ò6 >®-±ö†¼Ñ‘­FÓnLÿÈÖ„Xˆ‹þR"]ëâø¸X’V2ƒäg÷X*@Ð,•ÊæjwÕáªez•«¦…|¼>)ÔÎKpvð¥hŒß5ÈhÁä$Ë|Jm/ɹK|Û/à^œˆ=|€‰‘roüÇ^+(*¬ÇòÄû]¿ÃTwÊFNIwì:T A·ý ó‚;ÕM݉¼;â#•¡³¬¥©ü#Ù­wp6˜ßé ‘õht5ˆ×,²µ+·aý"þ’”q¸ìDhtÅ H÷@¼»fG.oÝÁ®~Â]‡ÖBÛ®ž6Ú|gþ2#ÞJfþ‰5nO=Ÿ,¶…µWÞ«OŸ’®ÎÖßÁ9öˆ&;‹K³ö…Ä%)åÔª\Iÿé迼g¦wendstream endobj 1536 0 obj 4038 endobj 1558 0 obj <> stream xœí[Y·ò8¿bàÏŠ7›¶a NìDA+Y ¶àì©5¬=$íêòãSÅæQd³gö²;†°‚ì.‹Åº>ö‹%gbÉñ_ü=<[<ú‡´|ùìÕ‚/ÿÏ/"<²Œ?‡gË/öð1§—žy+­^î,FbéäÒ Î8tž-¾Y}¹ÖÌHííêízcØ0x¯Vû¡é¹Ñ«³µ€–ö«Khx%¸^=_s kŒ«ãõF0k°O÷þXtN©™2~Xîýe±÷›oV{ëbÒåW§e²ï ¹Wë °Â”×@˜Tƒó‘¯ÀÌ~žøÚhæ¥ÖÀX&Us&gؼêñKŸ}Þ值F¸EºZ29,Ä.Êçcsp3óž—G¯G—ttd‘„ÂØTÜeb ž}‰R¡›0¯Tš9å’lŒÍÄT˜-S8,½ãÒ¼¦¡+µaÂzúÚöZæE–zã‚Kë‡ø¤÷5i@‹œ¦TOó[ÇkÔ"©áùtuïô“¬p?¨„SrõÉÃS¼’Ëø¨ñ|H“Z5¬NÖ³AJ»úuÖàÃ2ü[$¥Ø`’"Re_­3–[7³d¦£$*“\³cÂû¹5úd$¾ßlRyuB‘jx ÿìQÔ[iïV¹˜Q, á –À ,à²Ð'¯_¬-è.àu'çwž+),auPx7JkàbzÒ ¨›¨!GÅØ[ÛUÉÍêóêÌ–59á#³íähCÝöåÚ˜X`@–y­•í ±•íå _ÑüzÉ$¬yiaír4Áû`‚e ZÖÔ:-x&Á–PL+´Rßa~î2Ž: âðyq[¦^ÌŽÆ—7yøóñ=L)b+Q½¡Ó¹•(¯|»Jgù•W©ëYj|’Ç>J]{©qœÇž§®óéJE;ÆA»þ–FÿžG¿N]™ü§YЇ©ë¢YsQÂÕDÓ±óÿI¯òØW0¡L8MTe5³Æ' 'ò“ãË”lÂ-4_¦¾ýÔx“Ÿ?H]ïfà\þ§ùµo×±/zoˆ8?MÄ`EÔU…Ú?8çtØc½2Ý^½Þxo˜_zV:%*¶„˜€Ð×ÔuÈYoœ¦¾n41B )iŸMg(œTmª¡66\ WpXhÙêx¼+/½Yƒ\”Q†…èšx0­¼w?¸X§b€Àå ŠÊzp &ÄÒ€ip[â\¢3dÞëÙÐ'HCŽS8Î+¨'ýþq…”‚qcZÿî|Uq‹—Ý‚xX2ÙIaá]’=ñ…A4¡‚7ôŸ|šÈžRL€òTN{ ,³él5Ì/(%Y^æÉ÷[—f zḩ¤ƒNDÀk°ÝÿÌ1Åy‘CñþDæé%háö^º.Ï+ߊü[Ÿ„¯Àâ/»_â„è±µp4zHÚ{zB]:uôaÓí¼C!µ0„ƒÉö‡¹úÛ_°~t@h‘ݘÁ4¢ÆH€B6!ºdc\ P-rô°ÍL„ÞÆL ÚkC#ëit[7.VKo§‹E“€Ç\9¦¤ÙrÌczqÙ³4`>%ÓEǬ͠W×$† põïLéö٠ʺGëã¨8n›\²¢¢@Rðª\‰§œckü #´ÊÚŸwí[­`"!>—ÔÃ1«yÔ‘ßa讘†î¨.D°')£Bg)͆ ÊC9ÓٶƦçÈþ&Ùì˜eAÐZ§@µëÁH*zUiӘƑ;ïZ§w‰?q‹Ô¸ƒJ#‚mß¹ÝwsA³6(fn]‡P™ àd@À$E/3Ÿ#Q§+7Lt»of ³ç)G²;¥QÖEX É먰BSøªÓ±ÔìŸüdº ý&>#©µñ[œFÌoûæ=NlyÔ'ǵÌS`oaÏ™÷qCÂVXqŠ8ˆ]êak€•ÎõèÝäL¶wÙ˜¾!…‡@_š¶ \+ËÄß}¼Pt˜’{Æ¥ f•m5e›¸¦¡2äÝø&+è®´Y:È ìÒh¬S‘û¦oÝ#匌g'–žä>»¤wb¼ÃgcþäBq–lò–3¡êÚNÇCxçgÈ^O×Ç¿:ó1Í)´DØ0çТO /Å5ãÖo©Ð¡òYÓA§ð¤½íE/]_—¤%Å]-9à)ò÷·5&£´R)ÍFSIÁ¨ØÍÄí$,ÊÖßÞ;yç°OÚæwLáÒäNÕë¼Q޼s·£ú9sß—êáÄGè4¥i}bÅ^Ä$[¥$§¡<Ú C˜%yÓÏ‚1z2š!bRÞŸ m¨ ó†+šè‰¶©œð‡Í»žØm§›ˆ0½uÒíí?[ r?=n˜+´dÙ]¶'•å°‚ýè9$¨‹H®£XùÚa¤Ô¦…ý›JS…·™~r×–=ÔN¿+…ˆ‘ø®ÀQyƒ.l iFÂô@fªRäxLÆ/÷O/–j¼»«–ZXÃø€ä,Bž‡g‹//=þëòêåõñâÑ¿–bñèOøß_ÿ~ÿaù«Å——Of¯‚̳®…ÛCXÏ¡îÛ:ca§[ êðVi•6WDfû!CÊqëMU‹h¬^Ü'³Çe§lâüh9%J%›øHâwJæ| ð7¢Ð”„ ÞïºøÄî5™ RÜÜÒQ’IpFéÆÌWk †w°©¿,Y@¾Cnì\%#tS(Z ÉšïÚ„*gB‰ ì|šû úMn}–G Z|[gyô ÷•4ýeý¼ÁEkʯ×pmJœ./†Ø‘ÂÂ>a!Œ.‹¶—éž–ÑOoˆBòÆìíRSÒ‹ñmÃÍ 0'RYÒB_ù» ²ŠjÆMgï^YtÓÛî^b)Èòª`ãÕ¡-‰næü¥Rduÿâ—R‚ qüTAÄ…àÁ,°Vjå?%5‡ä8F¡¸ûà§°ZfÙdhp¢À}> ~ª4$ަfrâ¾€ צæEÍ×XÓv`’£îÞ{êû|Ô=PëÞéØ$‰¹cX«u³‚ÕŒê3n³y4q”±ìTð[³‹À-ÃnÎT;AÎÞ Ý’ª®Å‡c Ü’¢X+.¤bñ<ì|Nì’ûãrZ_b[ñéæüø–0gÈ6§ars_$ãœ[íÝrµó˜¯ÈÝHÏÁœ]”$±Q®ž?‘Îl SŽJû§}Š[ÚÂg»ÉÙY£×V¹fÒmE†€JS'¬h°Î[£¦3^²s{™ö„ v†ÂMep€ÔþœÒ¸ÛR§¾×GH0À ¦ažûßœ«.}dòÈŠ´öpßË7¨,èé„jÏy°¼3|ÜkÃݾ{Bì ìRq‹èç{J¯F§ó=ì‰×ì­š•ò ìï `O«Wª=QwĨFq'7¼)î™÷.Ü3x™IÕ!(Ұ太Æ<sýpOÎ1ü£›~‘´æ¤nˆŸµ˜èTË(8ÐÕ$³@ƒFÓÒÔX5ÿDàá ÑøÑЇ‡FÍÅý¡Ñ’úþÓg£_ôjSÎk 34€ƒ¢é.jƒ`Æ øþ€E†)vÔ?~*~*þ߀ ð©âû@(’|_@aý=d¶Ÿ*P! ŒB¯zß F!¼À…'&&êÖhïjP¡.Z¸G?ë|ÜvGË×k-\Q×Â#å R¼n`ˆñåR|×aa¿ÀgÓ¸þó2ú´þ° F»ÛFà Ø>–¾èúð€'LêK]-mC ­«B i§Hµ”©Ùn¾¸¾Ågåű’µŒqYˆôê°,–CIQ9vt[ŠV=ÍÂo¾9o’bŠÛè~ÎÜøšxOs[JÔ8¶®‹&ã˜è©vÆUk D9ЀbÓ;õ IÌk(¤uÔ®­d{s;ùÏñ3 }wÔ"]ÎßR’m«Duz#ÓÇhÁÏåSá!+ÞûTø0¿’3Ц€QÌoì“ÔõÑ”fþêøûÔ(+8˜ŒöÕ—Õß`ؽV%Cþ(?í”Y¶‰4ŽæšDº„^áÓâ𥰑x}+ ]Í€=ËÛÝP.ÒÉ_lóÚyô¾ ž+ x[‚"Ì™GõYù‡r:]êÌQä“ÅÔÄ„:endstream endobj 1559 0 obj 3461 endobj 1563 0 obj <> stream xœí\Y·ü¸¿b÷žïÃX¶l+H;Y –aì¥#öZíZàŸ*v“,=³«] Hbö6È&Yd«>ÖÇžW+6òÃóߣӽÿ†­ž¿Þc«¯á¿ç{¯öxxe5ÿ9:]=ÚÇ׬Zq>z­ÅjÿÙÞÔ_Y±²œL­öO÷¾äzÃGg5÷øްÑK+Õ »¥f½ñ^Ú«áx-±P¨áåz#¡7ïåðz½£2ÂñájÍGk„4ÃÁÔ•2n8KŽÖb”šéá”Wî‡ý¿„©ñ•½F¡ÌBÁ[Þ­öÿº·ÿ§ï‡}Jx-ýðb½Ñ£s8ê ”r5:aA*,õL£X µ¹sKŽÚ0í**ág±ŒÑÜ€X¡/gA¬T{UrøimFnd(„•“ÎúámÿÍVYj©‡ó\x¹Þ¨%Q&áΉŽùs<ž¯¹¹S :…U7Þè–U l(ç „w;+ y—k9\§iM#Hfy^,3 as¦hFîªh$˜¦&¹•,^€¹KÉGæ\\oc‡‹IœkÚÁ¼ÊF::س,,.ô92®â,aamôôÇ—£ƒåx¶¶£cøÞÁ Hh9rïÁÎ÷Á¶£¤"šC4«»Ÿû‘Áàr|c–_=È2å™˰؈Lï »(ÇðOØ^r¦æAÃJœ§Nɪc#»\ûyù ‹yò¤‘7`Ä×¹”˜Îñ<S,êóün#AxœDО¹`LŒÖóá°ÑNüY~w±áÁ¦Œ"“ &K‘´"/ɉ¸Ï£n ûÏ" æ7Qõ.&å ÀU©8¥ÝQã鶇% ”ÏL4HØÂå¾FZÞ‰B«üÿ¢¨¯vJ¦ýZŒðNÐWÑ…H5Z¥i_d.Wõž 'õdq.gÓ­U¤ð¤vLaOP›N¥/×Bƒ¿·bø…øE:©;î)¡]ð5¤4ïhl¥Ä¨•§“%ŠOóVdÓ<ÃV;{½èí´“ÉSH3B\œÅ/éÅ—…øs!Ùqâ`þ„úΡÑDÇ{FIÎæéI;œb©°cV8âF ¸^im§= ¡v€MÀVSëÇÌ":B; ÌP“<È{æ,[ßaié¨r©¶Ù49=Ï…äUp~àØ!~­žÍ[M¦ÅUŽDã_»»â¨^Inx‹Ê£qj§)å˜F”M´–v€ïwÕ?ϳ­§úÂêÁ:.“Y¨2üaG?<ò›9‘7ç ü(TÜ Í‹UÄ+Aå‹QÎh,`œ2ÎfêÀÓèºl ö§‡§ë,ó'¸ú2XE£éŒÕP>2'‚8ˆU˜ô¨µÞ&¶ŠgqˆŸ»Q¬]Á-‚UMnqÞö“Qè*p…%ÒªÝ91ä³Ó‚JPùE°[ î–â´_Äî~ûÓéíɱ(å9¶^dœMEãû”gžFß2 -º¾*¢µÑÙzÛB7@bÐíÇÁƒ2¨b_®q:!ºl ð³K(œ!Ú§Q…ƒk%œöGTÇ"Ø ºeö®1ïV5uZ†sI„AÅ(&nTÀf$œ§Ó“ÐúOO¸w8;¡ ŠqØ—x€`L.ôuÝ…i)àS@xÙƒ†§“’ ˜l²3Iºz Ú–´PÀò€( ªî)´ÏÊ^a©LT¡¼Ái:˜’ÑÓ‚ú—¿\°ˆZ1Ÿ±§ÝÆ:Ë;7ÎYª¼Ñ ûÉa@+ˆ]¾ñµÁaà¨-2'of•.ïËàµEkHh'7_7û2ƒí ¦VϺ¥ýw›4Eu€®„Ec²tÚ]±›ƒÿŒü'dØHñ ò ù÷‚41e2¿-ª³OÀhšð6ªumåöSZIEÓJ @Áœ “^Ãy•¯ ‹sSJìp­Àú,ƒ*¤³ð‰;œ*±ãÇû{ßí½ZÉ)ïÓs+Å Àýy9*‡ »GOö<ùÛêêòúdïÁ¿V|ïÁ7ø¿Gß~ž|¹úÃÞã'«ïÓx˲+€„¨*{t0?dÑ/cÑA|8*_šfÕdábæPip ®î'‚u‚öÁ}½Ív8;w¾/ˆÎ‰ÊŽ'åvÙ5ŽÉˆe–C)¥_Ü€|8ƒ Håã)K××üÜųCURÏ+e åH1ŠÐïäa¿Z  ÎD :¾ÌxèÀ¶ó*8§X}ýÐ.ËõóXZ!ô˜ÔqÔ¨Cú3>½O&£9¤²³Tv”žNRí§©ìûôôçT{˜Êꂵ'©ìÇj ¬…x ˜u°è±úŒˆŠÕ|ÉÃTû!Ôj†¾¸°i¬½Ìµ?ÆÚ32õT{k³¨sí±ö³XÛU9I«kØbRÄch£žÊ£iÔrÒüE:ou îNYñÇobàñÝÃUqzNÃ}ƒ»×C+±€á3MÇ«:ƒ7›)LÍ–f¥Ð¥XAA5ÁíF’ëä\‘‘îôò™:?u“Bgñ¶ÔäFŸ“Lû£`†ûá‹ðäŒ"çã¨oQè›c1 ?‹ƒum‚@¼tœçõËbËËÏoÓó—dN' w./Úóƒ¥3ÅMœšÒ“a/$WöszÊ.ê’¸žÛ4Ž8ºìp.æZ+ˆ«È‚–a ¾X;7ÞP_M”k{œ|âÔ#˜×Aë†HíÓ¡ ÇX}^¶H:»ç~ݧ±èñáóT÷(}Q¾„uŸ8V‡Í–0Áy5)ˆÇlërÐHB|§º¯I?  S‚G°2ZÙq¬|™¾Nx&xЬÈQ)h’ ›ñÒ±ÃÃÓu ‰Sþ]ˆS›‰ÓȺ)-(ušùÒ=f51§Ý­¹= üg" ,”k9¾:ÍQÁ1ôÒ÷B„Î9Ÿ*S`ø¨À!c0&ðœäIúª™»‘DPJó ¦ì¨»y˜zÙÏËÙ§Û£HØÃ ÔÈ8_È臔Θ:Å€ÉgH̹^ TAŸœßH<ÛLŽBÃä¿û¢ž“‡d’‰óÉÚ ÇF¡muË)×Z-SHægüÂÉ“°f¹[Òé–’ÖäŒó©½’`¿¢©å%ëØ2ÓQhÕ9•—‡•(YÒ³/¥x„Y>Ë”Ôaÿ+†v&BƒšË3ζý4;ꕘ©r.ÖŒØïîœ xd(6À9@·ÄC¼„(é~5™UŸD.ç†U<&ݰ´ !:ÌŸ[i[Pð†R.¸Õ'”ÃO¼ÖZ™É¿y V³Ï©l»‹2#.´!KXå ñ¢ ´bERÿº³·g H3ÌY¤˜;õÎkÖ*ÞÉ 9r®Ï’þ»— ëf¯­u0¶xht±ñÉ»å–óßÊ«àõµàýwÝY ›ò(ïêØ«Œ„[pµ½†W·ÌÜ2Àô–ÇY¶<’Úmìµ.5!ÀÀ¿`¯ÓæÔ£õo4>$Dâ{Hú‚\@h´øž¾)'%­rÒ7¦à(XŸ»Ó èTõB6úF¼‚•£²ú¼và=Þv¯d47:K v;QAÜQ–Æzlï`¹xqëäU¶”뺫‰M¡òBh·rŠºí Öá`SFÎ[ ÂtsãäÆSåæiwÆrèÅV^·T;¶ê£™þU2¥#t7Ú¾S¦vYÖ…$CüÚõdä]²ß‘ Ò6,B¡Æ-V/ÅâJQBDžÈú…n¯Ëù Ä×|çm²™x©Ì´Þ½¹ð9­„UîÌ>ö;7¹n'W×os…;ÖßɹßɹÿCr¯ãuäœo*rŽÊþÈ9:Ü+9'Þ/Ç còAx9t“|¦ƒÞtx¹Ì”½H–ü²ÃËÕÖþ9•Õ\ÉóÕÖÖIf|º&ã&^.wó0Uÿ–x¹,Â/=n-™s&ÿÎrm²ñS"jª}k ùé:AÛ§àðªŽ7÷ËÁå´ÈÆ ÛÛØ¸þ}ÛÛs»2¢;â&‰ëK7ç’X;o¾uc|·˜ìÜÝÛõÝûv]ék¬æ£v¦>c¼âÉ/–’¿$‘rž£R÷\’~+`v‰>ØŒ0 ¿mæ3𞨤[ç»FßuÕo‰VˆÍà˜äîçVùM|·¿suÿ+\ÝãøðUªûúF\Ý›–«ËðæEYIW$­C"æXjv{ŠŽÃÆw·gè\fè2—I¹ütA™¸ˆ1MƘ³½€-9åÎÜc.Ì•K‰¹2ߣø-%¦f"sHHÄ“øÑåY5C.gcð³ƒ1¤•èd“Œç“ÂðÒüÕéÛTØ Ê/GØZmÒe™ª_PÀ×£‰rúsáŒÁ™áaÅpÞÏcðsú‡qÐ fèÞ_vAMÁ•ÒËþ½9Éà«?ÀœBˆ-æD² 6§Ml%ü=ðR½\!§ç¸»‹ÿ蟕i}øBÇyq/Ü4ùñFlp?AH/-@$éÓ €ìšãy—djÔôÕœa¸·cü¹Å熇=ÔH–Uõ bU]$:Ï"®åÃ7‘|î~F¶ßbÇЧ«¸u³VÌSĶR ý lMÚ¾¥¡;4׌ù@'ÓYܽ _ÓÒ¤äçä ¨›;OnElÏdžwõ=\!¨ZýîQ/Dª³µJÇ1SVøaG³µæOf¹ˆªœ%÷ó»ÌÆÏ,|~ NFÁ^¼ÕG§ó~Ù…Ç’ÒÒ¯‚$Lp7„¸5ç$Ò?t¸-ê…)U§je²j>Á¥‡SŸY>-dc[Ý÷Xï+ìßÆëŠ r@+ò*|4t_÷+76\j*ÞO›Þî)̨ø q™¼ ’ßåÃ}nA]\ çÒtË`(~‚ßšá·WnåÝ}¡Ç¾!j(]a÷ïè]w@!-™3ïûŸDuÍ錈jÛ …7H6âã’ES€a°³’FësZÛ~¶€Ü¹Q¥‡_úÙ‚›p^;è Û?•/È©.p"œWy{8æH_'ž²†ÊÙÿ±¨]õ¾¬m›M_›z}Ù{VõÝêEíå–/:UD rJê†÷d´ñ “’V(7ú«%]·°t'DKÎû—ŸšÉæí˜ðä»'À'1»Ë襔xM(Ì~áþÃ-'…ù9ãæÏxN÷ÎM}Ý‹’g!aHtÆÙ÷ý-˜4!ëPH~ÜÆ÷‹&ö'òak¤—MÕý®Ð˜QUd< ϵ͌È彨iÛî`<C¤¢À{W¨šoìÅë%ÆBTÜþhQþ„:è«|a ý ¼ûívŠ·rénr×”DÓ Äj¦Ã¢Çc‰NËß܇‹WÄ3Nns’½Ê´x<¦ëw^oî[Üù >½'mñ^çz7÷ñU#û¨ò§xƒ·ts(<ÏNœ­1Á¾ÂTîÃO3ô÷Þý„°ª‘ü>ýCF ì¾Š'ÁPräªyÿ#xòe}æfª_Á‘ˆ.´\m@IÜijk~Ýåýí¨Âƒb¾Ûûák·×endstream endobj 1564 0 obj 4172 endobj 1571 0 obj <> stream xœí\鎷òsŸb’_3A¦Åû°–,Û |GØ!íJ² iµZI‘õyàT±yÙì9vgÖ öÒìn²H«¾ºæÕ‚ |ÁðŸø÷ôÅÉ­ï…a‹'¯OØâsø÷ÉÉ«^YÄ?§/·ïãkV-üà0jqÿñÉ8_X±°œ :_œü¸ül%Ø`ñË—«µœgZ-/Wk>£ ùbÅ¡SùåƒòøÍj­ Bþûþßa"mª‰ØàtœË‹A8ÆÆéÁ¸qÂ_VjpR‡aê °¼-åøòçÜwšûžçÖÓüôQî;Ï­2ÞϹïan½ÌOÏrßûÜú8=7¿‹FËA‹qQwá#-”7Ë_Ã69ï%ݱ¼‹Ðð’3ka0¬Ö‚ÃÂvkn–¯W0¨öJÅÙ §³ 5Hía#¿<¹ÿ——÷Wk9¯¥‡]ÍÓ>-¿^­…´ðÁ#…3Óúm¡«&B(1h£aÃ3=/˸çcÓÙB$ltþþ21®;}Nh9/#²Èd ‰ذ2Ù¥8ƒ„WË´„ê_ð{38f–ós²”K$@¯ó㿟(7q”~㈰.tZ»d哟–©ó´¢Ðuže%6<û(uý95>ÉÏn§®;õK£X^ÃçT$ÂÚHCYJžÈÚ‰Z Ï>ÊÏ2wSã³üìó ¥‰§áÒ!{Hííò+«ÌSúŒoÿ\ï!4ž§ÆÓšh.SKtþþa½|hœåÏÞRcã§Ul%…" E¬³œª3¼¼ÐÚ ´Œ¬ðš€¬T®("žùðÌãf\úŸV Xnܵ0\6 k]½ýu¸dR‚2úf%ÉŒö(Ä ˜æ壀÷½ ³ß½òÝÉ«…R 3L ®»[¸Q¸i- ‚ €F·ïܺ÷ÕâÍåÛG'·~Xð“[_àn{þÜûtñ‡“»÷a¨Áãp¥È8°â½Æ™^µÒN{ìÙB+9È(*úÊ»(¹mâ‡3Ø U ùKžÌЊì©de?A$JÜÑd;ÀFl öº!¾EyHüÓF¤Ô’îͶàtsC 2zLH´#àì½Ä3Ü9¸Õ°/PÙyŠ‹"š³¢áæúcD/"øaT¯¡J1†øwÞƒ¨n9üÒTç…ýœâP@ %  @:ÃÁp€ká ö+L£)•xÁŸNˆÞ˜.è¬d‰5ÖL°fIÅq·]C©Q(ѺL¢·hÚwÙý¾¹ªYø[\Þ.¬¡”ô›yƒ ¹.oÀØ-opoïp ŠŒ•™GN¡{ÂWἬ%øŠ€gBbzÕÙ„ñ2YD{†éq2ËT>ó€à*88á’ö "_ «¯(ógÕtÿ@}€Å jÓk4.+‹SÃ΋¨ ePеå€ìîØ«¥îöúÕÚ{=€'%±S éÆk„4¤u‘žR‰j¨Šð6,–Á_uÄÅr°ÎðœÈ‚OWb r.R“š €ô³¼²§¨Y™Õiü¨{•(Ã,L,ÖhXht2«™…d`å»Äî£+¤±Có"6§š˜a¨š”Óò¨ ƒ30^º´‘=ë¾XwϺ®„,‡q§ (%ÉÑ÷‚¥³-ˆôÑ»¨ÔR7w4Óœ6]O…B£&›ßÛ}ó›>•è„©Útv_­)à¦Ù×D)â¬Âžúy£XéD"¯JN»NÜ+¡ábÌ{QAî–©ÈJ¦ÎœõttHÞ–dРšxn…oõ4öêyå™( òkïÐÈü„ªSº•½>‹ÚÛ–¢ÎQToæ³¢BžV*d¼ËªrUL7 ›geˆ?XÝפijvVv,iâªîhýZè=íŽðv¢Ì›Mù$¿‹ºV —rÍQNz› ÕVu³à¨È¯îM¾`âØ;ë™,ô’wù,ÞÂÑ›7§ _qyÇñGö$9¡t5™6m{í¦ìHtàÓ;Ùû}hP _oÕgÑ[%wðøA3õ~Î: L-¯>ùÜr»õ¢M ksÓ‰¤«Éý •ãmôš$λŸþ´JßÖ~AìŠ ñÝœ`¢!êÜÕ8•ó3woO` FmQoX˜È á×Y˜;¥·0O¦¨…H’ÿA¥ 6"o…Lœ·ïã,£^LÄ rv=F G½æûde’ó»Éhí)*E˜ÓÄmUߣàôND¡…}o{˜\ðÉ ÍzxnñÓÎÇQ0‡…S3ØIoEoË{™„*|‘$ÓEïÖUê Ì)×` ‹üj4O :éD‡¿AëY°Ñw—Ù_ð`mu‰à ÷Ë(ÍP†•»9щØYß«ð9Ø÷G€¾·äjðÀ3&Áð¸ o² éHáeW† a¦2ó>øx¾+û¢Ý= Cè$ríQ„ÅT”6–3¹t³†o‘L  V“‘¸%Á¯Êm|Û•RÝ%n¶€Ëú¦ÉV+÷¸z¥<úäÂ&ü£qPÖ×¹“Ÿ¾l¼‚Øz¶ÑáùQž1ôl Š7úôrBW’p^1{Ы­¶ÌDÿàjCÆË®t4dIgL´ˆxÞE}€3]¡ÁHd¤.ÕSom#­¼…Uõ$Ð<Í0'c$!|[$ôÞ”p D÷ñf¸|›ðf+ƒ*庶È.S¤‡»åP#‰Žš¢/,Æ·½ûHÌ‘…õý5Ï@*‹®[O¥JŸ†YÌ# èQ`µÀI vJ œÓ"pÆ%(Ï<…0g­.‰¶S²ëaÇðùöœˆÎÅUÖ¥&Fõsx]ôƒKÓ›Ó3å¼ï£…vhÇ\ƒûú€{/pã1x•nŸDM!TQˆ¼ç`Æ=¯Fܹ×öIÌŒÒ ï|¶0áj+ØÚMñ—‚©@™™©#)n,þu¶‚ŸèÈt&dßÌÞ·DÁe÷ÁRTpè`Ità]ªÄÊrp›æƒƒÁp‚Sׂ†ë®„ߨÌl…¨¦Ûp¾°¦x¼¼ÖikÊÙü÷³5æ3:=ö‚,”BÑÃï…£ïƒ6^׬ðù˜C—‘`×IÄc›k3cnlëGEëÇÃa± ñ™q1–*ÂM^Z <¥ µòuNMÕ­S¥¯ý— C½Éö‚ðQÇÁ®™ ŽuÎÆÁ>O:F)´Øt;vãï„…˜Í3Ôr x¤,Ÿš¦T' k D;üQW-€·˜ä¤+u3›r(x~}™,¿…hE~ÞèŽÞB–ìšäåZMrýø N ¤zU£Xi1e¶I­r¿5Õ96¹R(+L¢Åϳ`–í%“:°=³Gg{ ö²SÕb:J!_€†íÛÅÌò=HŸ`ØTÓl–Eï>‰L¤¨+ä‚ Ñž¶5`«éX>;ÅæùÕ£ãÒÏtϨì'R³KT"pu¸‰m¾Dxã9m‚ˆxÂf4ÁèH4Áö¬í÷6ÔFM Ü~ЕSo °n04ÚZ®’ÄIGˆ_Þ}GóG <00Þb=Y²¿±°‰äÝÅY™H«sqÆqÅ~¬^;¹'±í£ÛQa$̼{åÕÇ;;¢btIzøð8Mb¦p?LzÅffªµGž1\¦9zr&ç]¢˜Æ\ß‹AN™x1¶·+„ {à²ÛÍRŽÃ2µœIÚ!чg]Ÿ ²ä\v°ç`‡Š©ânã¢ÙQ#(®½H»­JH½ûú+…qxÙ‡på˜i°•q$¿ÐË€“@䙞”"aN·Õr㣒–N6´N¥,©j%k±¤aæ/f-YHÁ•1급–3Yè‚Ú¤ôÚÍú,·:5C›]ªèÈ®§j2V”¤uó7ëÄÑ.ªPMŠ®%:ëÝmÐMnë¥7ÆX'Ë}ƒ7ê¦ø#(Î{Zˆ‹f–&•6pƼ½Êt ķHÆ: â±K¸~R즳G¹ÕÁ9ºáð÷±Ä•Òì¦_)7ÌžaɃLøÙäÙå.g¶/æ&ÒYj/çZ±p{‚“‹¶dƪ»Ýr'!ö7•Šm͆ä¸ì™öÐU^ç«x’ùŒC´É”Šu{äÞ—³:Eisëk¢Ã¿!íeù JJ¦\v;ã $ør¯¸¯þU<êwË Ÿ’ﲞñ<¤Å³ )m1RÐþ¸AK³Ѹ9òCEôFý¡"zõÛTD?Šy˜C•ÄëQ’’õ•ó¯âú:Î?’ìP›UÃwËHÖ ÃÊ«”3jýþYŽ!ØlfÒ—ŸN.öïµ–óêå‡ZîµÜûÖr¿œ4žå·§IwW©ÎæcDçÿ¬:›ƒœ¿ru6¹†Œt ûq¾>êü`õÙseé×®ÏF)ƒ#šã×g×”ÍÅfô T5Õòk‚³¦Å}Vjƒ[T·ªnFí*M U,l1¬ëáŸð¾¯3¨ê…ëzåÍ8×|…ØŽk) z>7TÞ,G¡G&îåöl¥ßËö>žÒÿzâÔšóeqycWPq[Ñ}QÓ]¹à¦›œOé¼Q0}—–ÆrÂÍ×ð ¥äÅlQµ¡ª\ÛAð^QI'Ò,M 7‡^ŠIô€ZÝ´Ö,:±v«(mmPb©Máeôúµuæ£òJ•æWÐ^³*U3㨕æ\ˆ+Ušó±«„Y*:××-:ÇŸXÀu£Gè¸Eç»tí—¹èüÁ¸2,:OòWi1G²aÁç}|’ŒóµNÞÃE@óhÇ:ùPi²çuòãÙ{wü2y³ð±÷éè‹÷&ê š=2‹ÑT8ø£Ó+ tÖ_¹®?äxêCäPcs,Ó¹ùèR¨ë¯”û³ôвì eýAÏx¾š²~&ÑÏ{ÌÂþX7‹Ûbúð*ûƒÒ(…ý!M˜·?À3&opÆ#Ü»°ŸTF6«®ÃÛ‡»ÿ“€Ü¯gÚÓBŒ1Â#°¾²áAßÕ4ƒn¬»å…O‘"¸WN勞©1UÄ…ßêÊxå Rð°_®HíâÛJ«\|¹6t&Ú»–“œvg›zø&°©ñð¡È˜ôÕõ 3wk¬Ðöm¥XùEÊäòÝ«ò¼{£&ÚΘƯæ=`\¸¯†9 c`aðI˜‘ò 5sëßT9@Fá¾ÑÅðSbÆãü›ÄÑ?tÌp ¬º¿Žþ7%N¡®Èv‚=½§Xƒt%NÓ*——8í²¡¤0Qð•8I¿0nŒÜL‘³ÍŒêœv¯s õr½;ô{¯sB©Púõ 8š˜ÆÈÒÜ\ç$Z†½œ¸¥Þmq¢aV È› X8Knã¥>Pm–\Ü­ÌŠG«Ì‹¡ån•YH Øb×ÿ7¬ zf­}ðzíÊ,LbÚÔði,Ÿ¸~e–Ácöä[Ç ¼)ÒÚ¸Ãøî6,”¬§ y”X ?è${ÀÊth¨ÉBöÇßP›ÿQ¬5Ðâ5Yág̵~).ü´…Ý©&+V#ìV“K"j­•~—!ÞmØòs몶'€UM~aSú’*¿x°9ß4¤÷ìX˜5æ¦îT—5fút ›ç’¼TUkµo]ÖHY?ãâk;xYVü‰¨` :‹µLZ Šç—]™Á§Î,…¾;ù ¡eÖendstream endobj 1572 0 obj 4743 endobj 1579 0 obj <> stream xœí\鎷òsžb’_=§Åû°–½¶Øò Äywe –´«Õ*²óyàT±y»Ù3³3£µ³4»›,’u|UüƯ–¬çK†ÿ‹Ï^,î}' [þôzÁ–ŸÃ??-^-xxeÿœ½XÞ?Å׬ZúÞaÔòôÉb€/­XZÎz/ßwŸ­ë­3¾»\­uï<Óª»^­yoŒ‚拇Nå»ÇåñÍj­zBþëôo0‘6ÕD¬w:ÎåE/ãKãtoÜ0áÓ•êÔa˜ºtW¡¥ïå¾ëÜ÷8·Þæ§rßYn]æ§—¹ïçÜz–Ÿ^ä¾RkXÒüÞ-{-†¥œÀGZ(oº_Âæ8ï%ݧ¼wWÐð’3Õ=_1VkÁaò°Éš›îõ Õ^©8»átv¡z©=lß—‹Ó¿|ֲ߮^K{™§}V~½Z +{e$œ”öp¼oŠ\µºނgEžË2îË¡élŽ+T×>'²¼,#±Èd I2Ù£8¾„ˤDfH8Ñ{n»'ùyÔiÎ5~$}LÓKfóô°¼<ûUîŠSYIL¾¾˜ÈÄuØ2aÑý·¼p2›al.©Ãç«5XcÎp|Wxø·¼ÁaŠË¸,8íÍb_¬Py„2 ©§ç ¿äwȇDL²¡g¥Ù^Ýy\’•Ý߉ÈE9^–¾Ìd²ØôB›jÞçe2¢3ÿ)Û>A»Þ)Ù}ìNZEÏ—4š†éaXË”EÕE÷YÃE™œ÷y‚¼€:d<,IvÄ3„µ)úœŠëaɺòÉ „]Ù «¥‰Æí”IMpÝ7i2<â5žñšƒkA׎š˜áYÓ׋?.$8©©£ ï¾*ᄀ7ñ[Ô>zµ÷Jk»kxОGŸú8…ç¹uÑ »á®ΤCžZAbÆËüøWxÌ@‡øìÓøñ:?þëð‰rÓ±•Fd®s¡ÓÚŽ•O~èRç8HYG±–¬äbóSןSããüì~êú¤~iqkcxÏŠBÀÓËÑRòDÖ’à8}öa~–…8IÏò³Ï'’&œ†ê!Á¤µsÉg•Uæ©DÀA¥®ëÔxœoSãQ~{´FÚø95žÕkÅÏ>J]?¬b+Åd±„@lå€kK­T†7 ­,F¹ËnyæÃw¾7K gÀ¸Vü§UBQÆÃøÅu˜lLBÐ_Wo? ¶%%˜é×+ ºe´GG!zÅ4÷d¼ïm˜ýätñíâÕR)i{#wK§xÏH-4þLyÿÁâÞƒ¯–7×o.÷þ±ä‹{_àÿÝÿæøóàÓå'–a¨Þ ãê!ËHÔü6#ÍaÖù¤]öl©%îtØâ6*ni›ÛáÌ"„##>©z¢Š“’=•¬ì'Ç çü{ø6l]ÂNSÑÇàE»M`e‡s» 5ëE%ñ0½ “’p8kèLtD{ž#Ù €²!œHV‡{î0†§X âX†>ÌüCb—JêEÂóó§ˆ,s8pX}‘ÍÃ95 `­}ñ‚o4ÌÌÕäˆ$gÍâcÚ+¯fÑXå‡Ã\Óרby6Ô¥é½÷)Ç‚ª2½cf =¡×º õÈx‚ECŽUŠŒ•¹ CFTÆÃóäb—2^Ò’¬¦“ŠFFí‹òºJzAUXÑôÑÌÓê¾ð’æé…¡*hUϬUw¬ëwvQn}hao¨ ;ƸƒBR“ «6ÎL§¥*0êÓRùÆUK×{§ÛEþâ*þŽFzçÆn7›¾Ø,G–þÔwøÊQ_%ä%<é²F^Q…&3¬zƒñÕÞ ¿"ÊR¼Sñ3?•Ç%mkÛ™”hG=~È -ñsIAM]h¾‰×6x)¿¢XõA†ñ“Û L,'[…zzV;EtÄÂw"¿ñšƒœtˆë &Æ‚ u¸¼5Ê æ(•·C±,,âã¸J æê‚Ë)n :_‡!¨†ƒ"å¸UA¥FÃ;ß§#…L]AR¢ˆÁ­@ðGx«F7–GzQ$¸j)`(HÈÀAÖ¢¤ ;ßPÿmj[²ÓC§SRª™™Þº ½1k°¢šnÃù:›Ž—.“lM9›pï9¬y´o±×.Š~«bƒ…$ ‰  öºÊãÀ¥j´ÍÝlK¹h€úG··¡öÃZæ“ô(,Æ’dŸ*Åè¾;HÎãròÑg<)#4‹äÝ­õ$H_úÓ‰Bí\¶ÑÌȀإôÇI÷æE×ÚµhK~Q×xps%…6y%fÁq†6ŸÄÓQVpVÃBÞ—Óщ+ò2pÕÜ{!'ŽùØniØ\޲&1äíÚB—–Ù'Sâ3{‚-37"núô¦?û5Ânok_¶éCÚ¿&íïÂU¹á¾û ·]JQñcò—’’8ÿÏÙNÊ Ÿ’ï°‚*iVd„±v¨í‰ÊžX)àŒ³™ñpj‚pgÙN°©U#ß–Hl”\ÐW'pÉrá\ò,Ò0X|–ÀDÆ%0ªÝ;Wa†øBà#Ô«gÂ-×Rô,ƒ­;¡Ie{µ/{¬ÜíüP®ÊÎO¯óÓYa’k¼åú½³Â 3C“ÂyV3½âêNXaQ¬ùÊ2Ê"Ýþ¼0̉´ž-msoz¿‰æ¢aƒð”зf†á(Ý*1è¶ø7.rà óf™jqdzØpGÈ[5éå´&3 áŒj—àæK2öÎè‘çÆÂ'HVáì쎩TÉ^o_‘$¸CÕF­±îBr}‚ó/^>Žåø„ĈkcC©4(Åíùcƒ¬yÄZ³RZQ1”bœ1-œ#äLé–رY×(q—(å4£Þ³ÈÞ³Èvc‘ÍeUÖFTÀCô_ÔîC †úÿÆlø»? p†Çì08ªÌ =œæªñ&‡…Õs¯äqnL7“ÃÜœðÅýÏ3F¿•sÜL¶2j<ÕJ™Ã-[«af¹VÃíÄq¨VCŠíÇ(+Þw5ïíT«t‰¶Õªqã¶ÕJ†kzzD ¡q‚”é}ÖRNÊ Ÿ¢< Ó¨H„"½Æd,8—f&wi*j¤Œ3WH¤Ÿ¯1‚aÅ —Ýx:$þm¡"Æ¿çO #‘¯EH¦´+Óª„ᑊ|€dÚ¶Aêv“²×ˆ´ÍºÉMOñ9- ¹ »)¬Öˆ‹Áí~í\¤Ûݪµ£þQoÕœ‘G¿) ÚgÍfR þ´Øó-R¤ Ý iJD92 )Ä ±=¢~+’ô3~ç4$$hÒ ß‘v'"B[Ë‚~ïD$ô ôÐ#"…Ÿ®pfŽ”,n&"‰‘¾ÎýòšÏffx*…w!±p=ç3›}Tîh; ëß–<5¡$H¬îcÞ=î†aÑáŠ}ù»þ×}¨dOx3‚•6KðÈÈHÖóçòŰԙuþÛÅÿ œe¯endstream endobj 1580 0 obj 3511 endobj 1587 0 obj <> stream xœí[ioœ·.úqŶŸv‹,Íû°v";r 4. Y‡eÔ²dqü?òƒ;×Çð=V+k¥¦@aØ¢I¾äœ>ó õaΙ˜sü“~îŸÌ¼–Ïß\Ìøüü}3û0±Ë<ýØ?™?ÙÅnNÏ VZ=ß=šuˆ¹“s'8ãPy2ûe±³ÔÌHìâ·åÊ0ïCP‹½X ÜèÅÉR@I‡Å‚\/Þ-9 kŒ‹ÃåJ0k°‹‹¥bÆ­ÿµûMRÐÙ¥fÊ?ßýv¶û·_»Ë•b2ÇuÚ·uà‹åJrÁ$·‹óåJ3i‚ ‹«*W+ôcZèÅ~•ç´Žû¾+zW…\\Öï» ,ëΟYÞבˆXd²„,‹òd.²Ki]ë´DjJÂéÀ¸‹£ÒN–‰`Yð>  ¸+Àq~á™v,W¦I­òTjòýá@*aâ¶‰à™•fñ{í°Óåbñ´¨Ä³åŠ3ǹ·ûÆ-ІNkR2'ô´àiã—¨BRyÆ=¨ìî¨éo¥#ùšÈJöu¿Ç—xÖ%Äâk"7éA6ì€J˜+ó)X½øsÙÒN”³û>a¢òØ;kò‰Â¨G¸îÀ8³—ÏÎ5r%[ñÚæ¢íø¿“ÌÃlû£¿X)vx_ŹÄs^ãžöýPû^Õb×Á ™4Ü*!óX^de]ÏÓÚ`ؽ¬- ¶Ž5z’UÒƒ•& ÌJM}įKË„òÖR³CI”bB*ÚuÌ{³zÎŒ˜5ƒñÔ)Óy?cßË™7Éýɤçbnµe²sÁ{à‚=,Z.Æ|òbI{4Ø•ý°hŹn¿ô;K­N¦±ù}iþÍ\½˜lM¯Jóß»O´Žˆ¥<"œ®• ·¼~òr‘+÷Ë'§¹ê}.Ô•®i{˜«þš KÛ“\õeÛ Û8V0au¹$C]J™È¹$ÃxÛÃÒV„ØÉ…§¥íÙ@Ò,ƒ7àíP;”ñÌøâÙê*ËTg± @Ù^åªó\ØË…¹ðªô>n×A{ šÎËgrÕËe*å+\ÎáÞvÞ Z–R`®?,¨–5…dšð:’pÀÁÅÙwvg?Í>ÌÁL‹ò‚±û¹×}Ô#Šzò|öàùwóËó«ÃÙƒÌÅìÁ×øÏ“¿„Ï¿šÿi¶ó|‡b¾0 YFr¤¼ÉHS(­ÅIy“Ÿ£ŽÄ KÕû\çrwñêxÇ=CPµð,—È~*^÷¿„Ãiüyû-X#¹LWÁ«+Ü+‚¼N\íº»q gRmtuçÕ“Œ´žÓÕL*‡€p¶Îs‚WZpÓ;«"— hmãpá ìN05DÄ”°®ðèÓ?ˆ ˜s‚¢¯wu€wýÁí.Ïkq!&ó–§û Ñ0ÈøºÁa o,©ÀÞK9 ô|3-Yc âsç)€šÆ½ÎÞ¨µ·žïÆ/Îûu.|^ÅU_l¤*€ Dû¾è0‰1îZƒiô©Ü#ý» o‹3rGŒØ›ÖÜ—½iÆåîÝ"êÂøX/»ÑMÕo—:E‹nh¾nµ…ÛÊ×AŽ×óE‘óòšíõ äýl/$ûl öå@ìáö(µvŸñ¾s¶ug\ÞÜ%°ŸgtaÒ0Å©hZjÄ[ÎkÉŒ÷– ‰ÚÒæZâr”?é·G÷ÃÎ覅$F:ó™˜d(9n”ÖP쬶GB­ºãV?:s ½tPNé…­]­†> à·pÃáh ]âÝ’•Ê’ÒYn¥&EÖ,”qqÑZmɤ&-T€¸.ü×% &h6’) š^—uZ—}@W30§•u0—¨‰p;X‡ %¨Œëh§L¬ ¢X<+ŸMá,~½b~‡ÈXðÀ h=†«z€ˆA[te^pùàîÀü9«r€7”wÃÛüÍÇ%œ¦2Êô|Gr(y ïû fàm#é'árvÊ }C¼JFmŸÚsYØàÐ×­)ID™}Ò¸ÀÄ8Þ!˜'õ€ß¤¡”‘¯#‚¸bçˆ,„¬ºÙ¬5ì ª*™‰,eHªâ¤û¨Á^l¶‘^ ˆt0k›ž=_Õ›3’½5“d rfñz|pÞàÈ´ÅÏ×€o“©Zn¨á¯ ™nºHæ^ô=éN>@„T‚‰ 6¤½c¢ªñÍ)ÇÜ¡£ö ¹•sÑÑ8?÷¡Ip”Ùo¯OXžAâ„pé¡—Œ>N —Ú~_¨¡ûˆ3¶.l‡Ø‚ÿ©9ÙÞ–U ôSsq«P/a#ádÔ4²ÀÓ}Y3²ìLú& *?Úø }ɯ=Q²¥JB$S¾>ÃÁ «×¸‰2½-›·‹JÔ,nÍùz——.“lM=›/pïAãí„ÇÏÂ`­G— éáE¾;@„€ˆÚhÙGlAÕˆäHn| •à°Ô÷2e1†æcæ“õ(.ÆQßD”¢—[Œ’‹´’~ˆŽåhÔ»æ2®Ð¼Aò±9ôãBmnâgÎlGO‹nµêz2ƪäÇ­åjx­M`×èìÒ =œqˆr~˜Diyʬuºõ£ÑOÁeÓ§nòýÜJ/¯ ñ° ™å§K ÞÜÃíqZ½öy¸ä³IŽû2»âM“7Zöû¸¤l.{¥.)“]ЫRwÒãýZ"¶r†Õµ”ÖG=&h2ů¯é?~Š¢Oe6Lñcn¯®·‘âObÝ€¸aŠ_[æ¹&%0W9EÓìÛHð£$Îišà§¹|’ì'@ð÷$ƒq}£ùp­ä)Ãÿ“w”á—Ì;XA‡§מv° ñ{P£*Á4š†ãr6CÈ¡¡n†¦•g¶ë |¨¶’Àïƒæ €Yv‡JE¢ðÿÉìžgÿŸJf—ÌõNiÛHºdö>Âqé=À'Ÿ•§–˜„Þ8K-ÀÑÙ³Ô¤÷6³ÔÒû›‚Ɖ,5Œt·\\àsÙ‘Î[JT#ÉÔ yë\5ºÑ¡‡ºÛ\u+yæµ’÷a¶ÐÕLóŸÖ`’¹êÖ¤@Nƒôð™SLO§!Þg!Øí¤%x¯lQ -ëjÚxÉ ±Aú7ªÕféߎĽuö.uï›ó¹¯pçñÈÄc„ÄõÉ`Õ7£¡üƒÈr2¬î͵pÜw™°ÔŸ)­7ÃÌÌNQòøÆ±GÉgW¢j=MsHã˜}-%‘kU6Ê;òŒrÇ4!¾¿]:35‚-7Êg~Æí5y¥Z%ï4µ7úVM½íŒ¦TíÝuF“,ýª~ŽMÃQëpÃÙNÊ2ñ[IYÆç€D»ó”%ó”_»¸K¼MÙBBßÚOÐt$LÝ‚mÃTÎa+ùÈiÚ£—DàátŸ&ßf6²¡€¦™Œå#K-¡€¸ÓýÞCÔ’P­Ÿÿ{l~ å‘ó³àkò˜tø¶2ÏëóÏZ»SY‹¯ðCÌÎnå7¬f¾úÆòÝŠ^@Qá%$PÌ J1G/Éöw+2Àc˜È„aaŸ~&«¬óȾ(â›|‚ph]nÒY„Aå¾\g)}'DÒ’M‡l*ÕR‰g;É\g£7*YW+WG€SŒd®wô{@é’Ç·å°… ½2Ôî ­–á8Žõ)Ñ~!iÖËãž !p; w9á›%*ÀEÜÝúf|æ5ÎÓ÷Ím¯øf¹=O×{lÝó—“|vu9„ömŸÀdvv:Ån‚‰W³kÍÃyAÏvbŠÔƒä"v}0$6ó0”ÀMü}ÊÊ×$¯m}Ü[uˆYÀ¼\P¤=ò)>Ï"$|&×å%¢ÐÖÑ"ÀËÂ’ZYkùRq&%ØâËe å[W*XŒïã•ÑPÿÆån,Y?|£ÇôؤH©‚1Š ÓkcBx‹tDûF¡#Ö<Jüž(@4hç˜}×÷ñ@!`¾N·µ ¨ÜÈ·ÜìÂÈÉO3˜rC_â‚çÁgu$¢Øu¨ _*‹:þ4ûÇX”£endstream endobj 1588 0 obj 3299 endobj 1593 0 obj <> stream xœíZën\·.úsŸâ´¿ÎÙcÞ/)P NdGEâ$Ž‚ CÑJ¶QKZëÇïÑî /sn»+i¥¢­`ØK“<Ãr8óÍ ?T¬áÃ?ñ÷ètöä¥0¬zs9cÕsøûföaÆÃ”*þVOpšU•o¼FU'³–¯¬¨,g ƒÎÓÙÏõÞ\5Z(oêßæ Ý8罬CÓ3­êÓ9‡–òõ ^r¦ê÷sdµ¼>ž/xcŒæ¦¾œËFk¯Ô?þ˜ätu¡©½«¾™üéçú`¾ðZúúmYö]!|9_iáS_̪Ú__¾ºL%mt}Tø9/tÏÚ¦³…Éúª|ß.`X;}Nx9+”[„!ñVÖ"»W0µ,K¸~‹ß›Æ1SŸäq"Ê2 ——ÌæåA<²ú*wÆ%t”gòýñ€'®Ã¦!'Öªú_eÂ^{p†ñúYVˆçók,cÎpœXЖ.q‰9?͸V hKýbŽ $”j¼…=X‚’~GxÖp_ 5R2åê/È„oZ¥Öõ~Tæê¿Æ÷Ê„¯€„ð :ªþitý²! .çHÖj8|D5œ5NÇ+æE#ã•Ñ®a®½g‡@ÒÁ’¨¹©uZ(ôEh)‡ç²0Ü5+õåy«8jE$ˆÃgyø 3`OŽÆyø/í'Ê )b+Q„t¡ÓÚš•O^Õ©ó(ržºÎR£Hr¼fìóÔõÇÔø"=M]_v'áØŸÃgx”FÏ{¢ä…¬<Œ}žÇ2{©ñ,=pšxp”ÕCÂÑkç’)óR«Ðàp§^§®ëÔ¸Hwe4ûÕ<ö%;+*0®ÖYN­¼¬ iÕOá ¢\1Ïà<óá3ó4l!ã¦eøsµÜ9Ð{Îu †@‚_tf¿WCJ0ÑßÍ%¨†Ñm¼hÓp‹ö°É·aõ½ƒÙ³•R`IMàœâx[ gÀ©CW÷tödÿÛêêâúxöäoŸ=ùÿyúý—ð³ÿUõ»ÙÞ~H5®¥Ã•Êt˜wp oBgÊ‘v]YÚbÏ*í=²vxÜ¥Ó¿Éhpà™Ò{ÛS¼ÁEV©E6T²²™\8 7vIü½û.¬á\†£Ì_gF/2óï(Ë“»Êè¢ê;Eì…6O¸ÌΣuÕ Œ{ýû쓈ÏÍ>³‡/`%iuï-yÔu´ÃB‚ºì÷Åw½§Î ¬*\}S$>„xÕeô~ÞOøÄ_¼îuµ8!Fˆ"R Ë¾+ tJš<å#ÝMj*oBÒóÉÖª8©ë—Ôø4´€Ù\n¥ÒH°^3@–e9DràÍ@<”5㤸ùBGØ9«†`/O‡¥E{DFrAáa/cTžÐN úÖj!àÝ.f™Êçmá6§ ­nfn"(aÆRËJÍ¡VßÒN™híµÞQÁ\ нÐ<žv8fœ—EOÒ ª{i¥ªõh/o{(˜à½n€[84‰ãOô×iHk•F©1%bs©m톮éfrs°8xdDö‹9`\~»U,g¥)^i1Å2~‘À2Ðë–¯ófæ5ËΑiæõè_xÐrDÌ‹'.×¹Ôî½-ñà ´ ÍUþlÊO2Ó:/%ؽ¢Î|P!¸AÚ¤£-q'`1رö`û¬'» wïþ6è"aøº‡FÞßEG©ëÎ €< ÷8Èã¬Çø!}òqê#µÔ½x6ÒA&Dc'¼ôa‰7ùã¡-‡•,èØõª9àšXEclÂ^ë@ÀŽSRd*áäh4 ¤&¦se-"Ê03Ë•Þq qÞ†ë L•hgýú4Ô~1цüö® ù!¸–c!¿Sf$äÇ8¯L !ÿE™K6âC9þ뎯Ož¸øz†úÛJ]åìÑŠhҺЇ]µ#Ø8Í: ÁFôôµJZ#I> à°vÜCp, ÎçÝÍžÊÙñJOÜV qNG2ã §” ¥v1ÞÕ5ñ­§ñ®Ÿ.H¢{Q2ñn¡H 0ߥTól@Ó:ã“®¢C¹( ç)]%/±m¦\a@IµW*ÝV›OÆñõHò¼Ÿ€ÀÑ×¹omR*fXKb²z¦àôÅÃWÏ zþÇêÙcõlmõì§‘êÙöû¶U5±Q¶[TÕ¶TÉVH‹€ú±ªöXUÛ®ª6…) ñ:ÏÞXzƒÆ–•7P¨¦Bcblûê(7s[WßÈì]Vߤ÷onY}CØb %2^÷Y“\æû.êo”Þnêo@qG©òõ7Ê|!ó7±¬¬ŽtîŸeͰŠDY¾CÉи¸Õ™ØŽK†Áß"zÁèˆ+‰þ§+†`m’w®*øÏˆvÞÁL1ï*Ùg[¿á‘˜#¡ã]{~g2®V̳úwKgQ#Wëæ1ªÂx×tHæ+6&)¤ƒþ“S¾Ì¾øjÃ^jªq²—FÀèp¾p~5à¼hjÞñ3"Ôä†kÄ ëÌXØxRŸXtÎ`¡8¯•HŸSq!&=1‰ô˜ïKy¼I!G‘ÎY¹?½’>è°Îð_nè›Á[ŽNñ¤\!èXF,Ç×øG!xÃÖ¸èVåu†ÿÎt2!ƒ¤HøŽ> stream xœí\ën\·.úSO±íïÑ ï—(¤në¢MsP I(–,¶lŶrésô;ÃËá‡Ü]I+-ŠÀÑÁ¹Cr8óÍÌÇý~Å&¾bø_úûôêèÃ/…a«‹·GlõGøwqôý¯¬ÒŸ§W«ONð5«V~òFµ:yvà++V–³‰ÁÍ«£¯×7jÒBy³þis¬'ç¼—ëÓpé™Vë« ‡+å××pá%gjýràY­_ŸoŽùdŒæfýv#'­½Rÿ<ùs’ÓÞ…š¤önuò—£“ß|½>ÙËIx-ýú²tû¼4üvs,¤…oÌúÍæXMB{ã×7E®Z¡Ä¤^?-ò¼.í¾Š—Î!×ïÊ÷±øóçD–W¥%"i€ !ËVú"³”zðjé–H}‰ß›É1³~6?'Cyƒȉ§î%³s÷0<Òûõ|3ui¤£2“ïÏ2q& %±V­ÿ]^q8×k6÷ÀÊÍ£| 4ÊÒ^§¶œß)÷ùõGH71úzr:úÓü"ùšˆJ&õi¹ìð T“5|ýÕ¬ÑäÕÓn7Dƒ@T?I¯ÖŸ†­c¸Ï ÏÊTäAi»þåÜÓyY ¢ÁgeÕ_—žá]=qíQ*¡Õd„[ÿisÌ&˘ƒ¤mä”É—Rëõç8D7y—tÐH.hÇyC1·þac&.MÙÉéyÐ1!è«ä…Òêu‘6 n˜N&Üí 0A“W03ÑVhSY*69Œ•“pŒ¯Œú,Ö)L»ƒq¢ ÈWçá ‰ñJ9ÔðcÃÝdPíó½§ó{×é©©A|üj~ü3û-ˆcøÄJBÀÓ×ÍP掬M2ôŸ}4?›…eØù[Hšep쪇„¥×n¶e”sW×á‚ÃŽý6ßz»ç´¾S½Ý Öâ6®†äÊŸ}³I÷²£+ðnÖYNݬÍ].&µV¡úƒ W®øGpÞùð™‡÷`«ÆMç¯62m ÍÁvÝÚ‡M$Á‘Wov””à#ÿ¶ó¦ ¼©˜õ/¹ñ6ôþøäè‹£ïWJ+3A^ØånåÇMf8IbOž}øä¯«wonÎ>üûŠ}ø'üß'Ÿ žü~õ‹£ÇOV¡©ÉÅvÐ6š¹%æìßÛ´4Â25šÈ“ìÙJ{†9â}wYÎ@\U5yÙ¨îþ¢‚×ùŠÌªdeF¹p¡)Ø„]~€‰Ø"¼„•ðo;Ÿ6÷¶¯ZÏ÷#¼6•ä­ DÉÏÛ—$*·Q.mö Ý™à(¦:›½w}JîºlôŒÆƒCäéÕX˜"O€&qãïð#51Y•—åû—([ÛgÖ?7ßÀ0ˆ0#-¾²00®ï*Pequ_”:!z*YuK†Xƒ]áÐÙ!–KíîÚnRäUëó¦¶Ö¸Ö?æ[ß募—༶û»4CzÀ¢õV)®àÊ]ò+fGVÍ<[¸›·³ßxGÜFg»)át4š¿Ý”ä­ä×[åržç…zÕøÂî|+ËvîİUz&ñWØŠÐt»32Í"•gå.i¶¼‹bKÄ9æèæ\&\Ñ„s!Êì†s$JLÈ1"tíw¡ïºñ3‰2É 5TÎŽ»ö¶lé;ºÛÐNù[b€-Y˜h£i²Zë¨ 2@#‹8eBó㥕j­»wy¼«ÕÛͱ÷:Ìø%¬ <É¡f‹`óÕu~Jw3—Ú†Ak ±pÐ\úI©2ð· APlj´§e„óÍ‘àÚY4/¸eÁ¯pA8’[:ˆ‹Yô®98ö Zaõ6eƒÎ¶¡6a b]º Œpy=6‚2 0ì -yP卵Ֆl2*/r'åDLH¹;‘2ªçƒ /¢[$Â3]Æq‘óë˜?€ðÞÀzA4#õèæEüq"ƒ›×M +åµÎJŠ©Iý+ôÒ¨F.j°ì­Qm³=ôyDa€q–(°NÜ´®§‡Áb.û¨J!3°jŽæ«ˆ€1?ÂÌ(µEdyÚÍãálA¼ }œZhIOd(Ët$vJ’h— Yºn†²hÍõŸ£Î‹vÜ>—× ˜H?ƒasy#„W-SB¤¶,DaôîMITeäšðW4cR8–—'|VÒWåŠäS/êlªªÕ}¼Òdû‚&xåMº\E]sÖ‘~#ŠaÑŠqr^P(GMjºTÐÀœ4ýÜtÙ˜1-èk‡t$}±—ÿ'©ç%üñ^ö;O@GI£ƒ‘pï¸ ð}FãÇdŒ°v¢kn;©øà+j“Þýº·ÅâÓ‚bÐ<.’CER÷ 6Ó|s+ÑBS`ža¢3줈Y‚²•ñà¯1„ý¡%‡’éæM›ÅÛ±+$‚…A—½Ò«K ÷<âÖ¸B80­–ô¶eqa@imy7Ø# óN<‡MjÇhžwW¾y¿Ãö¸p­¢õð¹ É~îÕ¤§–øÖ^/'¸±ÁƒÖ-s§MoïTJd©]"ÑÔƒä< gn!™¾]AywgÈ À³ŸóŠ_.”©„­×ÛnÍÐo†¶„žÇrkÀ…‚jê(A½G¢ð `ö}È-e-÷Õ"Ã~‘åÞºUW*4‘"6ÓÀ½½»¥ ©Ó·y7¨Ú¸Gwë]›ÒÊ ló,rw‚¡Û¯æ^vÁø¼çs½8¡³0$Snÿ»ù…‹ J¥üB×[4ø"b¶Í3,D…j_ÒË‹¹Í¶ˆŽ›ß ¸m/Â"ð÷´túªk]~.¯/õ,%bÏP/5»FÐ7›g¤¥ˆu |±n‰[T -1TS k‡Éå2™Â¢\Ðv“r¨ÛãŒEɶÌý(A<%¨&‰~”¬•«FIt¡‘½äù.½ì‚ŸW¥"ߨ*ÜÎ¼ŠÆž9Äe—’(ÄÉÿ)žE82=Aø±Û (ܪ±ëŽ1³®¨Û2'á»'¥»ný~9¥8ö§½+Ä'!Œ+ñÉ7ëÂãYDŠäZíÌ2A_¬wºÛØôµÁ’‰`à‰¾ÙÌ8½e4\(,• *"éóäL¶F¡ã7E²™ExQïr_ûR ˆÁ­JP‹ÍÔW‘šáð·ó½¶”‡W§Šä·óÕUçÛ RêOO»óC¼¶DOòÞ©bdqö¡ŠI€WÈÃÙ‡*&59aßU,‹5¤ŠY4¿3U `×ÄŒ[PŲ¥€q”tC™û?Y žŒ¨ÈbŸûSD!J‚ur°ó¸£¡M?î,«AÒsH1óЮF(–³<{ghIJrn»Æý`è&N†¹3ÅL xfåY©¨ïjŸ¬TV§šƒ”(‚])À%úý(h˜­Y·ï@A£»¼Â³3!½µ+†s½.»±¹ÃÝ=rPûuÉ`BÔÿyiÿÕ¼´Ï–m¾K=ùÃòéM˜6wu¶ì˜#pÚvç+îJcÅæ3{-b¤&\³×êÊ[Ñ×´·vúZyûô5p+·Fô5hI¨>¤¯…„©:}ÍT-Þ—½æ&å@…ÇíìµÐ•#…Ó¥ð·a¯I´ÑïGxmp£Pá¯fAßÎÂ_P‘·ÐÖ0ük»?m –R ÝÐÖ@ebÌ[sn­: o-c¢š·–ac• ÇÚ–õ|ÞZnt/ÞZG‚»ñÖD0d…ÞqMãÉ…ªë»2×xÓν¨kHµ|?{ ©kLÕ¢?(wÍxL²oÝŽ÷䮲ƒÞ“»fƒ8ÿsܵ;øÚ!Ò(9ä® &‘@yúš;4}M0%ĶßJ_£c?ß„’¥Âœ!JéViò½×e´góÃ'šé>EÌ §$SÄL®ûßyò«ê§àjœ±ñÈÅ‚ÝC×à8ðBQÙÛøÆ„Y¯£3¼:›ŸîɘW¸ŸHG÷§w!=GïY‡B°!GAH•¹9Šyo­p¥Ÿ¹ZhÏÙ@v ÔzZ¬'É–.­*3|dSß -Y9b¿ØßÂ<"_x~1Ï2J!=\S€“Ï ˆ!MU²A[Ô ,kbuA&þ4åê¤ÝóÜ"xƒª¶BøùÂõà 5×!’íä‚õ÷‹BL©f4‰µùÐÆ¢øâ@åC2,0Û<ï3°¢ xV™7>¼[!i®˜&sÆ´”¬pRSnˈݞ”•qCªÙàfîWä‰;ÏCï‚¥Ž_ªÞ7=»²ÈQ·»·.È ˜oË,Ù‰ù`­Y7l+‘Õ‘IµÕêÙLL‰Ë¥,x5$Ìð.nâÑa“ÎC£Îä½– ]¸kk«Á1!¹'¹¡fþeå3›ÈS¬X1þð9çµÊ §Lñ¨¥Éat>&-¾ÄvÔ¤ôHÄ´äpÜ:í©¡X[ýºkuŸoÉÑw¸§¢)Ý~±'! l%ÐéÀuWÜžA¬2©ÍÙ×ad&,T…Ù‡?T$øx[‹ÞdƒKª{yØ–&·Á˜wäu?° ,’»[WÅ£Z»‘g]3ëGåùMï#b™È«À%Ǥ—Lwƒ]¹lý¥i'½Ë ‚~DùÓ†œ§]7™5WÓ~ûtrù¢ôû¼p©‰ïÄ~-XÍ›AØÎá&’“¸ºujž`$3ƒ"ÌU¡a,ñM¡÷ãHK…?ðá÷¡YQÃnРù«qé9g¥Á÷Tóy0nÔ ˜Ùû”‚ñ{%r)5¬Ò` Á±æÁçÙèV}Ézô92Ä^mÙµœØ­€`ÂŒ@ýo¨TÚ} o×ý(uDö£cS3¤h)°œ«\ßR1+‘mújDù ´6°âž«j»‘Y$T£aÀDvS/­§ãÁ#€r£[ÌŸsè®8Žžé"l£~æ|ÖÌšb“àœÞ}Õ¶rwD¿å’¿—YÑ£—1ㄚÖQù2:|Xò™¢Ñ_׺baæwÍäô1yתÀ-Qgw"’Z/D°š J·ÆêäO 5lY(È &{k·ŒþD®íçaJ5ˆ|Õg6+v–Ò+#à;L© ƒ™Ëé¡¿¥üo»À³~ݨrËéîsôöÉ ‘\‹SãDÅW,ëtÑZÇÆZ ùãégæš_Š g]L£ŽšjHŠç¶¿ “úZØñÜÄ®ClU¶7o‰}Û]‘•mÒfªÀ>Ü"SåÕIh[’ˆxYeÃ!7+è«$¹XC¢$¹ÙÜBñ̤¯n>Џ‰*ÝÕëë_å…>–;|¬7ø#üáŽç±ŸT€‹)¨Þî?­tp¸9S¡;+Ù#œU˜"Ý8ϼµ§¸’¦`Þ±¢ÒΧays”ÕÅULnjf!@ê5.»ª÷S¾9 ±ó¨Þô¢¼~!jqˆ¹Uësù_$©À~î•… Íò11:ž;ͧ¤£°a÷ƒç"‹lÿX røƒ:¬ææF;K«ƒç¸òÙ´*ÆÂ†Ûâ±ÓéÔýµÝ¦Å*t*E7têÛ(âÙ_´Váoi0ëºUˆ2uU.Í?>«ø ¦X$>šø¤œUäãPÝ÷¢1ƒÑ¿Ü®„“¾YØÞ£ü'Ùù‚Ëp\àQ/&!ýúnûÎ2&ž©uê,%2M‰‘íeN^”›ËZh ³ƒÚ¸qô—‹az6°kb–þ¬©«/ýYmÅG§µ ±âƒO5L0æü;Õ•; “ó“Ë¥8m ^€$(\ZúCʤÚ׿»8â Ò„„F›ékLD ÂV&mxž?þœvõK;Ûöî èjšPsÌü>°ú¹ú’"MD4ñÕwU¶*G:‘ ¦3T+›l|`T;°³ËT9_ˆcRr`‰wfŠú‘W E²Q”UþgþÅèmåøt.zÏò¸—wý R>Î !g‡ éõÞ¯SÈÊ‹ Ëì–‘S£Ê‘ä€Íƒ,A›ÌÂÖágþaorhÿcòÂ_Êp'àñ.¶Çå…ß“ïÚÈà+ØÕ±1„ìÆgñ}_曳5ýâè?„@endstream endobj 1600 0 obj 4875 endobj 1607 0 obj <> stream xœí]mo$7r’oúãû4¬ÚÍwÒ6 œï|¹ ßo|° cw%­”ÕJZ­dG€ÆýàT±ùRd³g¦¥™¹\lXµ›Ýìb±ê©9ï}Ç=þþ¾~wôñ×\÷‹7ŽàŸ£÷ ɸê´o<–]nºÿô ÿ _þ¯;úøøÏþüyþûÅ?}ù|ñì ^÷ý0ÞC²ÓÐsºãsúéÿvôþˆyªáÏëw‹/^ åF.\ç4×rñâìh[ÛÁw|ŒuZÞ}»üÓ †ã¸êùòfÅàÊY¾¼Ã›\9í–«:RгåõêXuÖ:'–WñÑï_üûÑ—/ŽFÃbÒõ8žùãš9&¦Ôð<¤ß¯ŽûN;§…Zž®ŽY§µbzùa%:¥{m–¯óÍÛ|IFZsB÷b#ëå#¤UeĤÌõÆtrG])³ñ하IÒÄ4+]LsßYUI¯FÚ0Õ÷+ F(%a"ñJZîm”ÍÍ5[#›”àßqŠK§—çYˆ‚ ¸$¢ùvuÌ%¼ÙëåY’B"z º\ˆŽŒ&É:uŒyÉç’wJ:"ù7E{õQ-,•òŽ¢Åö“(|&\ån_ç»×ùîÉ@¶5ôä­7Ð-ç c½aˇôÎMºŠƒ22täŸ„Ž¸²åzùGÔ}Ó÷V³å‹Õ±è¸Q —F¶ÙÎYMi½Ì½‘ŽGCDî°˜map p^˜*æð}zô¾Éî<©«å7+”V®d×K' +_{Y0Öç8lÕ1¸ô³Ÿ,få23õ$²ƒ·:'áCÁi¾&L!Švb~W‘&.¢hÀ_`âaÅJ$Ù+èyB”Ó„(/Ó½“ª:ÍÈÓâ2Ž(âÍoÈp~Å›'ãè;%L7ž(7ov×é8+\nI‹ÕK­ }ó8„ïÃGãt ƒu¯(/ó£‘[pó|4ìõ¥¿4Œ[ŠSäÛàxö©;äƒsgmÏ*Gr‚Â;B@/²p¢\'Œ]~·L2}2Ò졘ôx3£>¡wZ¤XsFf'JŠsTÒÎGö ”&ÿeæ‘î·+  W…" Dîºå¿$¦\¯˜í8¸ˆËŸˆ<|·J²7SÑ<¦&vލ1ÐvGQÄÆ@÷)’xàþ:ƒëtïmººHÆàtkc°³!m0d8¿ƒ_AƒGŒÜ¥-@ PœÎðu³ƒ·MlÍ$[ ÑmèK0ŠíËÌ©6Ê'¹}ŒÑÉŠà¬Ô¿Ú–ñ_¤™p“fDÊù F–úáø÷ fDà4ÔYŠ»dFÎÒ=»m¾bwäo0„ô}˜Œû|X³¬Y6Cê^p¾Þ›4k?†ìÕ gÀªûôѳ ½ä³¦‘¸]«„4°„ÈL*¡àb¶[ØRBƒ›ç>^ ¹¼$Ÿ4|¹¬˜¯ÒÕåZ_Nô™1¬w aI£Þsª‚1ÞÙb<9=q•(~]y©xu²oZÍΦhÐáìhˆ '0‘õìU¾yYøÞÍë&üï€> ´†ëLô™/G“èDÎö&ZèƒË0‡rë˜Äûª>W ÃOñÅIé¹ÈØÞƒ_gÀSw¶ ùe"ôC`.ª+hÝ+;ãýX!ƒØ¬\5a%ûøÇYm~K|ç¿&]ˆv`b?ä»|Ž»gæWØy"ìÌ—³IØéÍü®Z°Óq(§ô¸µ·€÷êìÎ÷Izn{oagc[¯Öd\{ŽJ޳Vn©Š[‡ö¿´øc¾lL©¢rj~W UTNºC•*(«aÊ™ÍF6¬·•~®ñÜ@¼5sÝ ù¡F!cƒt$ø!ÅÝ| Øç7!}Hñ*ß#9¶Û4b•«¤TYiïÊ`#<úÁêÿCÍ#¤kj,ŸßU j,W‡ªa ê8uÜU>$%Ͷþ¢ºÚÂqßÝ86(nÃ>ôöåšZ@ì“èÊŰPîœ>ˆZ†â¥ÿ—j9_v&ÕÒôó»j©¥ w Õd¥Yªý«5/‡Ös Se{Žb€’¼Ç$ãîfa¨áìUž§Ö|õ×°´ Sý É\Uðà5}’Dýß×¢÷/ÈC˜/q“P°¶×²vÃJxª½àþaÅAЬvqŠ{_òì™ áò0Ö‚„6.6§ÒuäËZÅÇ¡ôl¡^¯Ë ïª+Tò›¤ø?Œ?@Eö:°µ†Š8`ë'éÞgéê¼jä+:mˆ¢"ÑÉ}zå¬Zg-âdœAÓ±kcB`3ônÆ‹ÏSÛ³ôâ·±ñ£Ôø}¼õYÙCf‰1#pQ3Ę`Œ! -Õ€_̈™¤âœcÕœqfñâ?Ž^üëßoJ¿mÌO]­W?§V@× Þ;*ÂrTØÌŒ+¦4wã[qCKƒÙ×¹õmÉ÷üÔšfóY”4¾vÒSÛgÕpÉS—…ÑÆ[?Ç‹Bc¸•:È"~9šò*æ{ùÁéœíz.¡ çuÅ¥<öŽD•ðïjÌ¿«ÜúCl}éï Ń7CÅü"ÍÕÅhÄ÷Õ<&É÷Ķë’AžÖØösÉ D ¶Ý68ÛÒãyŠF´ü<îsÞømÆ´NÍŸ¯H;îqH =ö64@NZ¿[Ææw©9ÉÅ›x‘ñó7ñÖ7ñâEjûC¼•ðäãÔ–ÿrLN…ŒüœÀãjóÃ9Ö‚ÃµÈÆê–|ÉK.D¿ÊÚ(¹‰ 뙀4ñäÓð̓}£OÝE%Èÿ¡ì½T»bdÌ×ÖO2Âæ„3éµg£‡ˆ@ý•Úˆ† x: ~o}· W¾v2²8UOþªc:öU‚$¹[éÝoR[I>ÉìÂS‹deÀ ™,œ‚†ÉžÊA'£Ž_ hvd¦D•;IDµ–¯l`4_p°@Ö0j`0JZëkÐ<¸K4`W¤ïá‚Cçzçßs¸ò€&b,OéG«¾èwgú€©$ºxú+¿ãMˆ“þ´ GZ9,yæìs€gpÉ´3–ÆŠh|Hˆg¥ß³T³Gg›„Á¨1õ„Qí3®_ÃR°øUH9p‰þ3pW@€P\­Z ¥&KSœc NkŸ?J©¬ZùbÒ/©‘ÀøÞ€Íw 7›§Ù_'g#oÍÙä.0#­t¬?GÎâÔJ,Y¼ˆts'@ÀîM3/t›†K|îhº¸b]U+ȤÙÒW~”¤hòÒò]HG[G”0c›iIÛày!öòq,êÎ(Ûƒó¢ÅD )õßù­ûŠR¼z]3…È“©¬d÷Ùn[Ô•“gË %‘îÓ&ÛÝça4¶`[;‰E–ì¸vrK~õîzØ )©´3.>)írrà ٬°N†±–]”B¼ç2‘–ÚcØÜùÙ biü ”ò)‹Å¼$µ-Ö0–I]U}­ã~Ë‚öc{4SŠ®¦æj ïëH†ï'O秘 oÊÌÙx/`—ÈLgâ.il•(˜Õ•¬²c!ÑôÙiRtLzw‹–æ Èìë+5Õ¯v6–ì5";dæ˜èCÁ†F†VûŽbÿoã`K¥oÔÙ> ;‘ß¶|Ô¿.Ô¤öú9à;)ÎõŠŽ’õüMà©)>?±Ì2‘Ô.wù!I>FüHœ@ó1ú‡zø–TÕì ÿ "BC.oâÌagü²¿,¤Ø§0Xâ¤ÀqSlØ *8–º´kËs·±×Ÿ®rš3Øí­Wá)T+¹?xYŠÃŸÇ¹Y“¾ÜßÑ‚·‘ ¼SXç^$^à” U*Â{Å]Ô‘Å #äR5ï²á.ÿÒ‡îT§œŸBè‹à„ í¼ç«¹;B;µ#dà E F,@ v·°Ñ9¾ ’Žþ|—”öD0¹:]qˆ!v‰„X@‰ª^n•c+¾ xàØöÁ(|Wµ÷nL[õ`k¡WŽà ò~®VÝôuS[[Ip°:´û.Og YAiϹÿ—cŠG•^e†àj;\ úÁÁ¢ ¦I|ò'b01Jžya³½[È‹BKv\ÂÖ^DÏ;èt“cK@~ò¬k}Qö»pP–Þ\óÙ´èBZtjlÛ²†èï½AÈ묧M';f6i/‘ïF˜]òb+×½] ^•_säw'ïá>ƒÃ:@½h”/ ÂüpüÒuY µëAž^–hFm]±C™Fé­¶¦çùkӛߑH  `:Ûƒ=¥–?SçY9jAG!fM@ó¼ â: )?Á=KÓ…¸O¾ˆL¬”®O ƒwϳ¿LìôíJ)`p§Cê%øŸŽlmX&¹ÓãøPy}J´3/‚pÜ{ÐÞÁ<5ŽGeR¼}Iyæ·5[ghÍ&é‹jS)Àý˜ŸûÝåû|ó,Фy˜óžIªÑ9,¡¼Óí­Ú£)¯’h ª“^¹G›Ñ«¾Ú2C0mÈrš>¥â¯68á#Q%4=ôwÅ[±àd"…² œœ·Pr9AJ¸zÓ ‹Z‡)´+Ê…‡xJL/y ÄqRgm }!ñ±þÈ ðÂÉ ä/µ!‘Ïð5f¹„«AÊ@+é'AnDÄH–¢À±_F69"/J%¤>«Bqô¾„£ËÇ\k¸AZ"¤Ê? Ñý”c1Ž'9(ÓqÎ)¾43—íH,žØ%kvÑI0 cã_º$µþÖD¥ºôËà}n¿áNîß²€oòb6ψi] ¬”®ÜF„Û…S•ÚQzÑžôè_ i7|hQB2™,-³™™~¯ir3'2El¦5&¡tÁ©2¾52Ø‚ Ô­±W‹2hí„þgíªâQÒ×èè*Qñõ•o5d‰Uå[y*VfNÓ÷5b¦cÀ{]CcøDžå!{0HÃqªd:ñÑJ âÃ¥›Õ8‡tZ€.9áx”¹»Á„möQ. NUÚŽ—ojñ‹³®Wjؕ٥|†µ÷ȳ/¦Órcìë7½{è÷ŒQ”%ASzbÞŠÅ’vâr¹l"£Ãa7aÛ}F’ùO+ýáª}±ÙøT«$8ë|$ÿX'ËL;kk%Aƒx¶No¶Éˆâ·pE§‰\ùýÒGbÖ¯˜qT|ò² Æ-¼^$lº&‡–a)gÊ/ggÁqÎAý@Ó BÑ€¼Z¬©¢é,.é¬ô·q²­iN•ÛnwýéK¦@»4/¦í7­¯°fgÕÓ‚¯¸bÓÇt¢ øñ ÈlÈHâu¿fIjœµm¦ecÂÒêåèÚ) ¢"RaÇCÈ<˜5>Dé·ñ¼|¨<¹vIMH¨ÜcÛàã´/^."dºÈ_˜mtPá©„¨þÈÑ]³U"hŒ\ºÚÚ[_ˆe†J]? ¿%¥©£´Vç–‡¤Ÿ¾vÌðxé&º™ÉvÒ·.%ªü‹*#á#"]»bz7á6ÝÙâ´èl‰ÐÚ/%±j˜™uÅ\õ¸”Y‘~B¢±‹n¼!cÍfµ…¸¢lÊï­™`kâü²vš6OÎ3ô¿•äוV+j$>"³ßZ›Šáàh©mÞ¡¦0º‰åÂ:¿J2çÌÛºúr+žK0k²úà69!ÞÔÔ¡ ~ȺzÅZú8˜‰:qá#ñMÚ`fÑØö=6zEÛ—ñ¢Ð–ø7]þSl¸:åûâ]èpïGS95¸Q”ø›Šø=Ôÿáa…|´‚_ -Œ¦ŽÚ•øÄ¯« nhEau}¦ÿªQí<ýe3¬mÿ:ÈT98›>ctNPÑê/o†á>eu"®’I`ÝãÈŽqåîðC85aüK8€sþ“ôúÆ­_‘’ø”­_VùZñC(®´® {| @Þ4_«²õ¾/æj5}VÙ°uùþJ®–?¸Ò8êf²¿Üq&öˆÌo4¡Äß6ñ§M$sï׆dÁ}ÈNH¾¯\D$ùb;p;neÑY˜õ°çg-%J4¦½œlzdÔq¸i7z'Óîøá¦$¬šöóÊ:gâÛçÜnƒ1LKÄ8€‰gÖ"rý SÑ™b€½XYQžÂ­ý´`Óáä!6¢ž§æy[áVó´­-Ä·ðGJz¶BïJ„臈áÌBxcH(7Ö§Dùù˜ñ'[1W‹ñÅ]m±,hWܵNŒ»Žãq”òcÊ_–·ÂQ'-G ³[BaÉ4þdÒ­KÐK3ÄëóÁÖÌÇI”¬6àO:Îàp ½q»V ô2'6eò¤Õ‡£ÜºÚ't¨N9"ôLž¶P1¡Ì~âÑ'OâžëGdO&S:½û[Á“‰˜é³ˆðü¹ÌÛFÄt?&´m¾+?½Ë|—Oøešî‚ùéd{Mw)äLäñ“ó]èÑȲÏ'&¼¸õ?×§ÄŽöø¯•À©+ˆ?D «ʯîb-wº01ñЧ<•yxÜ&"í9­p|ϬchM…?NEH²ãb«ò¯Ñßᦦ¸œ%¶['»¶ª*^LAé™ûÕë÷yç5—Xa>ÚùEÿb×g½:•ùjüè‰ßV¥Æ9ÏT·®e× 13%‡k{˜¬&÷x)±Ý†m•wFoH#ÉžhMþ­÷ú@érNÇš¼^C¹ÿQöâ[3Ò‹Ë·[G0ß4P%ª½á¸†ŒÇÒ§¼'4AßÅ:È&˜X9ZŒm=õÎbdZÍdU ë ׯõ:ŒpŠŽbNâØqvQ!ö¦”‡¬änŽ ö‹>yì?-e¾Ç‚x½–ÃAó,a™Ëê/ãÍ4ü¿ý/ !åendstream endobj 1608 0 obj 6044 endobj 1612 0 obj <> stream xœí\{oÇ‘?äO~ŠÍvsâhúÝí9X¶lS~}4\|h‰S$ES¶™Ïᜪ~V÷ô쥖 í`z¦§úQU¿zõ«Õ8°ÕˆãïÓ—¿âz\=ÿþ`\}ÿž¼:`þ‘Uüyúrõè3rå§¹–«ã³ƒÐ[¾2lF¸ùòà¯ë7|ŒÕn}µ9Tƒu£’ë›Í!´–pùrÃà¦të“Ò|»9”P!þÿø‰§‡Ñq9åìêøÓƒã?þu}¼9wJ¸õ¹ïÂ:'Ö§á ŠéЇÒ±ã`U¤×ƒÐ#_i«mÑg9X¡€”%-[ﯠ /Þî|yðj%ÂÜÝvÅàÏ0ZèQ³AZœÔGG>[ÝÞ¼>=xø—;xø1þ÷èÞ‡Ÿ£VÿqðøhõåìTÏSÏÌ”¬ˆ¿Î$ŸLI&W§¹õ&ß»¤C›Ì|Zb¦ø ë^•©¿.—·›ÞVгõ‹rIž½Üreñ“ë§yÅp+¤K|ÀòÁ ¾þ¶Z]n,|\­_‡»ÖÀ‰A)ËyZ|O>Ã'a¾lêo^xZÄh2-ðúeØŒ)ß½Öƒ6¤ù aƒ`œÜ¼.ïL†:ß}Ÿ’‹ÒÁ]š»õ×¾ÛèiógÂÐÖ›ŒQZ¬ŸçÏ¿.Ÿ‰Üå8¶“‰ºÌ’Oú)Õ#LÄ\fô ¤Xÿöˆ–‰ßàº#¿b ¾‰»ˆ+5€LWÇÏ`Ÿ„qÃ+†q;]$-,«B|½J©ƒØlTcè:œ×+ŠÓ4òÎðñkäÃñzTa%Í(aO‘»ÏãòÀ ]ý=Ž[ Š+2HÒN¾K¶M½êñ.NÛ¡0ÝzuÈx˜¹Ûj>¸Ôƒñsœ¥f\¬1ŒVÉA99ŽÌ?’ Änà'%å[²œ„-É`~RÛqg'¼†dÙê­šÛ«=æ»:­˜½HŽCÎ ŒŒ œbéaÕîqØqd’rFØ¿‚18Æm ݤ§”ɼŽb*ìx!#L7>0Ù´ oÍð^6‡äÔRHª™J2œFƒ £2£‘© ¤iyÑ¥ØXW*ev©M`i-ÍÀwjLåzºú[n½î¼qÛQX§ùê&·f5µþÓ"…eø`˜s+ÍQÊŠgqƒyãzÖš¨4ÉžWiõvÂ{E#«îA 0! j|ÿu¹Œ"xsŽI»V‹:s¼ÿU£ôq^/ò½»e@ÀÒíR5”Æ=´¸×)¡tÒKý¢¨®[A¥r6Y5ÂbwQ9U3V³–"Š&kÆgÍ*yÂ7d|D©±@´;Q(E­vaH8‚ÎÞ²:þ¥Yý—'L©r£¥c¾ÉH€eµSQ }Q¹\¾Ÿ–¾DÖ|›§ê¸)´¦ýÉ ÕÓýÎÈ^:o7›ŸŽØ¯d&(rrô8Ø9vdað']~~–64ÑÊD6]u…D³àq.»¯å9Ó š#HHWœãú‡ ³GQK±ü)B@ÅY8v¸WˆV™;‹éE$`ªâ sŒz{ªNJ I%Uʈ®hÛ%H˜Ð1í0wɯ³ÃBüêø0 |Ô³ À0ë"«Ôú߉ApÜp`e “öSÀLàæ¼ÒO_gŽŽî G§à 2¯ ±ïzSy…›…AO?naqÆ _ÊR„c¦PõmÁÙ„.麂XÐÃh*ó¥+—n‘Øq` 7¾­å n-g BcŸí‰àÈ|*é&¹Ä˜F=/Ûb^.Ä5Îÿºà“â¹+w'„SöC–Bº`SÀ¢6tÓøSà?•Kµ×ë£þå”°3„Å$¾˜¡| ÄB€ÅALi+évM \ñy­,ÆAÁéþ»“\µOŠ<~E‘s`É 7µ•Ÿ2`+Wü„“$œç‡¢ÍO¼À΂À%&=퉫!lë€ñâ¸(º£#£ï[ŸÉ2°Œ` ²» l!w Í”úž.½Kë£Z°×g‹–i|"„Ág™’CR‹-xÂOŒ¢$öñRz–;*¶i—-Þ‰!º$`N¤âU·7BeÕ裉hÖ߬ËXyø›M¾MØ4=OÂy‘.É饳ݡƊŸ‰ðxQxÔ{+%yŒÜ'-u-§¢ß?PöcÌ Fg!Lšã¤tUª-T¹§'kQÝ\ñ=áG`f˜kUs;újÐúê¾^z'ª8(÷á¼ÈÔäÁ†,`Nº¯²|–÷õizVœžÝ^Y‚r=/ë#Ëæg‡e€ßRb?–W$k´·Ó´çó@ù ©àe½W‰²ïšj­s³ë¥$H¬Ý­d½ „aÓ†c.‹ ¹¬X³øBô¢\Àq£€Ó  xy åúâÁ”©;C@ŒlN¼)„ͧKÝ'{U=‹aÖ#ÒÒÔöGÀ«Em’;‰-q˜ BU•û“|)= ]žddm‘»õ“M·wd›)xl¨$eH÷7üÖ BS¶òÑtÁ”ÇýÂÔí‚é™<\QqÕ2QW¤/Ã'…û/’ã¨r2\U‹Ò1>ƒ¯]39#¡º‚pž Î'Û¢ò©ìò"ªÑ¬”AHO]ˆÆDïo¾`^+Ç[§éâ6^lõ(*Γ«Ï<¸SZi–_|–]̧·sqJŸ/rv: ¬ê>Ò%ÝÎ3®ºCRô"»_¿ïDiO:Nï§Óîv7­„íQž¸›:Ú¾eJ·£ø±3ŠBûy§ua„Ù‚f«¾#R¨%› „B~ÕÈÄ;ùêªÓÚzÚ±õ~± …ZwW(‘eFñû e ++åúˆ28ý»‰>Ë÷ΚEÇÖÓfYñêÏùêAX曆‹fɉ+ikÔ}·=\üyÑ‚¢[œK:¢Y…è‘(s—Þ7v $ˆQë>”ÞK %¸$†‚FˆKbÑ.8éáú*Ìг1fUtÚVÆ>ú¬´ ´ÍŸàÍ5»'¯¦w QÍ= ðø¾*E°Ó4èq—0YÝo§Ô²_iÃQ$û@Šq@)ScûÝ™dsùIë9/’gÁÄ&1ùl}ûPGƼŽJ©>‚ïcñ¬Ê²MemÇlkú"}’Ñzu Œr —IæJc©Ìmbb¤¶MÌÀßuo2ˆaäÖSïS“Æ-®O?ÿ{Étˆ³úb‚é…q?vÝ™7µ¬ˆ=mÉÆÂ«çÿϘ21¶|OYÒLÊ[H’è!h$‰ÏÛ"H¢¥¿Ÿð¥^Ï$$M²¦ˆ£×sÿÄыҡ\Í;zýlVÄ^Õ‚$n‹ì|,ìN¼ƒJºÑ‘„¦³Ì×雊­.J€FÙ8d*^u1ɉÔ|_H-W?G‡³ë¬kÛŽX"˜j/ió–53ùVdŸG÷ºÛÂíÑ¡ØÏôëÛž}~íõK=¼Ê#Z…PÛëÙl\  ØF’/xÛ/2¦9ÍÎFlŸ¸&¶DŒ;_Ðr¯™bMèªrgöd’ %ETimo+U"DÚ‡ë•hС˭y©Ñõ¯bȽ›[¯:öÅYÇŽ§–Æ¡ƒ¡ ÙDM ¼)`]‹sAÌleÆbž72ô³N ŽhKg _qXIkµ<@kÂsÏo~Š%®$i‹ÅÂ`Gçßsh“£'˜éÀ¿ß$§þ0ó„)ÿ†Ah»:¬žþܯ¼€ï¾ØÀÆ’¶ñ1Þ”£Hó/™vÆ’Äz°øÍ Kr½•>·^2wßÜú¾îûI+ýXƒ¹koŸ£?ç5WrD`¾ËT÷2FQóûž‰ô}SX>ýÏ1Õ‹^Üi´[°Vt5Kòw8 ùèS÷: Ãì좓s% ´Çìhyžú=[Ž'îÎ_ѳÒydf~úZtc­ø¯{:@l‚æïжë%+=í¾?±SƒïCQyºvET)6¸0“à Ü®¸QoÈî³hÓ}Ü‹ä˜-¤FeÙü–\q šý§Ê8NVv.¤ºÎù‹‰†¯`í›WWõSãnŠw€”%4 >{¯—ûCp¼¥ å9ep>ÿ?F{öâAˆ‘!biåö'™ÂO0¿CæjýiI%ü w¥#Àšò¹þ9e¥ñè†D2Ù8úâ£Ëc4¯¿"¡9üœRÿf**ÊÒôý|õAhùŽPÙ°ëúÃ,N?"ïL®É'˜uÒËÉTi!òóXÌœCÍ0+ŸÆ.žf3§G#OWwñeÃg›Ãˇ$,âïI;ÿJìÑææ±¼óÍ:!–³¼š Öë·½“nýgºx/·=J·ÞOä¶ÇéÖ‡éâ£Üöñ¤Ï?ñÖ JèHr…ü²rx»ßV,ÇÜý‘——`ñû¨$/Ÿäç>IÏ}š.>ËmŸ§[_ÔDsïPVZLzRƒSæee¼õ·tq=yú¶¾`^­Æ[7“åIv&æ‹,@ì)xÉÁPz›IÔEô£)½ bDÿÜÄÓˆ zGtgîµ)­ôiªÓÄF‚+¦Siš!HÌÄÝKê#@xô,ÿ\”ØQQŽO2Bþ„húûc$X˜ù’CÎ|&Ò®Äê5—>Üu?Të!³4Øtw¯fçþÈ ŒR©yÒo 9”šà&šÝ;æKí)‚èwÈýˆy¢“O6gî·éKMðÄûoMbôÛÇ- 1ú)än¶L¬Î[–­ŸyËuͯQ”ãKaZ󻄱‡øb(”œvÐÔ…ùÂꪘ£©ëBÎb[K¸ºÉõóLؼÄÍßÔ9ørl™ÛéaQ˜·›7+€·Õ³Û}DN#È®>¸¤Ê,ºü÷Pe¶ÜÛ³ù ü î^ÖTç©g^øU‘¦kb‚£jùeå;r/ókéÖ]¡òÍð'÷9WËñ'Ê9'—áÏèÉcüécf'þ$fçÄ…6ì§Å† 0;‹‘Šá:³3b}WHõßõÜŽn ÁãÐÕ–Ô%õ{‡lõqh° ÕFMbH{ŒÏE¾c{ÔÊ ®Ï­ÎBM,Üè51a…Ý®bÞûibÉ-B¿÷Ë”äù}£›”÷¸Çeb#¼{TÈy’lDz²R'–²°[,«Ôóý`À8âñZ¿Á€ß`ÀaÀ¯¤ÅYºx_S;•·‘+‚SaÃäïtäœðÉ 3ä:'ŒÐyï.w1v¡sÊŸûð˜Ú920s8Þ8|T£Cë<Þ»*/_æ7n7 ƒ1ÂǰÖ[v[»qOÇrL±`’ç ™×`¨+/ZN«³\zçvZwÔ™ŒÇS’èIu)|WÆûãÖY(Qå=+;e5·%Ž> #çRðHùçÿfç}·ˆŒà‹|Ø[dbÿ¢Ê]¸bòjj\E¤½[Llð~ä~§c 5C)ì<š‹“5§Ç¾Ú`„DGwâ{}‡#Q¡ÿWðçãòÀø=š!Ÿ ¤ &)ŒU üªW#þ¤éY@L¬¿lÚWp)0Ŭt˜I·œ®v‰ã]@·Âä#bPóÏãÓ½»IàÖnY8l“ŒDŒ˜Ûk—˜õ™!ýÃyNKŽÔÝ’êøÆàˆÅÇ]ƒczHÌÉöùÆ[ñ åX’€ò’Ì8oÄN¬wMEQïôU7æe0Œ¡ï%³k[-’A¤F‰ -¹„/–IOŸ¬]u6IÕmŽci«Dé9 )ŒõælRóãæÝ}üv°ó€“*òþ¹Ž;c`èõ·h˜¨Lf2…ˬ![{ ¥+)F$eÀ“:Ú$j«ˆ~.ÃÀ2à¤BSÊ£vž«@7Èm¡þÄðiòÄF·ÈÈ¢v‘Ÿƒ¹Täæ ”'cç´¡öH¥~‚׳‰öSn.av%äE™ës]Ã:T=)*žŒ3K|?˜ä¯B vaü³ýØTL‡hj/ÿ^è× <@=&}‰TÑDn×{Ð6Vª¡j&MéS™뎒׶C,îEb%bû‡V’€esbŽa·ãùë®yrTàNÏ›{¶yhÑr8ëJ¬P¢‚X½v×>fÀ1poŒkúᆠ¬`žÔ†!´)Ïô`?œ£’fO‚ÑýŒÝì¥îdòµç^Müûaf0µ­¤­¾Si¼­-Xù«Aôøõ0ûJÝMñ1ö|×ÿB©Ã˜ï Ͷþ¡ñcâ´µøKΪmFcI×s󹲿EƒNÃU®¬É(ö!!?·æ(=¸#·fïØËÜ*J+Ÿöü´´¾L­ÏÈÄL{þ‰8mrëoíù¿Rë½w“#oQMètH`F.« W’ñ™#!IêÆÄd¥’@Ñ/*œú§dNŠYýÝšq0ŠaÁç Qry<Ë¢ÆÝ¡ÒÍl¯~yð2Þe‹endstream endobj 1613 0 obj 5190 endobj 1617 0 obj <> stream xœÕ\éo·/òqÿŠM€»mvÄûH uã4.rWEÐ:þ K–íÄ’lYJ¢"|ßãðxœáì!¯RA"fÈá¿w?î›9ëøœá?ñïñÙìà;aØüùÛ›ÿ þ}>{3ãaÈ<þ9>›?8„aÚ¨¹ï¼ð÷ðtÆ:§ûas/:áŸ[Î:g³Ç‹ƒ¥êœÔZ-~É­—¡,ÎCK9[øì*?;È­·¹÷fð [W¹÷Y~v–[2÷ŠÆÌǹ÷l¹ò̺ÅIîîÈÔØÍ­_üš{Ëç>é{5qnkãÔØûçÒûsê-ï^ÆGOÿNSòòH[+:˽Ÿ':iû—åŠu–1¡Ðo¥;ç¼—‹‹Ðô (}µd0•Ö‚/^”§°Þ£ y¹\ );.<…c“.l0ÏuÔÕ<ÐGu^(µx]ú_•<+C?ÄYyg½¯ ¼c…V~ñOÜ„ñÞH½ø(¡…òfñ?€”‹ò=}6ÃÏh ç~ǹõ<ŸéË|«üìi~ö²Îœ£A {‡ÏvëÍð›îFøµ§É;Jû=zJo—z»ÜûÇÒ+R¯Î½¢ôž¦Þ×­wMêu¹÷´ô~²÷Û‰_÷¼,(í­<óÐ\ Í;ï2-湊ýÞŒÙ/4/3Š#óh“YJfîQº‚ÿ”„§Nàc¶ÁªÕ’ïN#KØ}´÷¹sö)'ý"÷žq[[ª†7ýŠ¿‡7áð˜šx@0î]g8ï%O9)B\BÑ—å¤"ÉETpg:­‘“›È̥Ö|=P5m‹¹hèÍ¢-Ÿ­ë]KGî\§ªr\o#ë™…-ÙÌQÎð4× ŠJfû)¼ê¤ñôé‹L\ì]'b/3DÔmœkrƒYãPÚ¿Á +ÓíOŽÄ¡4(¦›ÜO>zŽÜÀn9郎9ú¼ MSÙjÛŒ/Þ[‚ìœ)úÖIéYÞ:/O'‰ÄTŒïF¬ ñ™I?ÒÊØÎØ†ê3-KBÚN9@Ïá À%SÍN¼”×'{}AÒë{iê{î ˆZS¡h$—c ';ë<ˆ›á7¤s”ž„=$µ :ÇF:ú‰±8ÆÏJó¤Ÿ×¦:XNç3A­¤–@ÊùŠ‹ž8Ÿ-¹ì<"Šfhw) ü62»B÷QX;š]p®5]ÿ)j)Ûq¿øÇpÓê 5›IL}÷ší-j6ÝáØ“ŒC~"J{S¦¥ì' oÝDÕI0-¡S¡ ùyiàHd8•<;™èíRvÚÀAO &ôk'D8 8PtOøÐ€Yìª=c>rÑE%;˜*ÎɈ3)ú¯sÿIÅÁÔÖöÿƒº’‹uÔ ý‘ã`Oク!€ã@n)Ùî_ÀW –xå]§pi‡@Âmçq~ó Ùí¢:øÊ©Ýv“ˆ÷•8R*:ÙE“9±ª³hQ¥ÅÔ¼d5“Ê$9gç»c]²*‡79É:)>O9–ØÌŠQîÁÌüiï=Í7‰x”Ÿ clïðíç 6Óú9‘tÆL à[J¿¦¢£¥ÄFŸ Mä#0û™”‹…e‹žèW`¹py °ÅÐ窨B<.Ím–г!FgªÕô\ ^bë)_r×±i?,ój7ÙÛÙI Õ21¸uÐõ»R»:kÃSï`p „¢ZÒXaó¼àêé8zb+ÓcÔ+5àœm<*ÏÚRìEL'Cù­øFñ]ñuVTœÆP“PÓ<¢UCqIZ”÷‰N#Ëo€Õ@¢~¢q!™ŽšÇÿ<øæ¯ðçѧó?Ì>šãLø~˜ˆ †/&¹°ÓD¹‹ Ü qªcôû#!Rµ5G¿ÏÖ€‹ª­ u;ÕÝk¤» þ “[sþ¶[›’cøõýÌ„QÎ=@Òö›¼[HZ®1"×´Äɹ Å'z©µšY‹Ã»ÞOÀ!ÙOSPêáC´úÄöˆÛ}S81ÖíŠÝ6NŒ•;B÷8Ѿ'êÉÐÀ@8¼niŒlŠlÆ]o #m`{T¨íQ±û¦P¡µFAúî¨Ðší(†n 0@S‡ZḴN[q­g-M°#w½€²ía¢·‡É‚‰’|?v?ñÎí©pÛùAœ¡Ž«¦[4¶ÆëÈÍFôÜõ.zÈ.·GÙ=»ob =@ß]ÅU=’É¥Õ-Ð#0T'ÔKâ&@¥ç°·ÐEw½£€²£í‘b·GÊB wj?Æ,fGïܘeÄHO×Ó%@œ1®¨)1Ö‚BLI) D0Ïgw¬GUp<èÚ‹9uÔŒx¶ÝòËF¤|#ÜïúXÜÉÖ¶‡;/Œì7n'÷íLŸv§#ÅŒ%XŽIĨ•–žfhˆ‹ÙéÍ8‘¤íº°xpžó6±¶ÀêvÎõ'õ]a.^ªaYP`§qåúKñPFÍh¿/™À>µÅ0ÈívÊ E›7åL>'“ÅsZÓæ7})2•ÖI©bÄTÉT¾3'X ¯·³¤d®Ë˜SBˆ#Œ†ݦiDd^Y`JÌwlëõ£,Úœ:)9…:·œ"ÖëBD;¥w´ Î{Û¥¯­­”Þ©ó»À¦¶ ÃQƒØg|¾’¢ã:El?[ @‰3ÃB‹RIÁá¡Â ÊÜ}•xjÛê8‰*³EªK›÷R¶µø(÷>ÎÏÞÏ­'¹÷ƒüì^£´ù¢Ô–?R—6ÓÞ•q ”ˆ…Ö9‡@K–ã~­%o>Oî§FYÜǃ,„ Gf9•¾H=«§³Â#ù¢\I^pÀóá5ß™¹ÆÃaï/ÓiZ˜€8 ó0¼¿ªF°&±íë%H_e´GÉ":Å4÷‹‡ØäÆÛ*–«@暢™œâhÓ ãw5d])`µež=Ù5k öŸöؔݖ×gD•Ä “M&DëDÈ ô!å<¤H˜ŽS‹¾O“VŽo(\š”ž¡Ú¥®ˆe=G•×»ŽüNZÐýf–*ÕÕ¿¤GOSãf@֜볶܇XKhÑû äÃ{H¶%U½ŸëÛD*0—ΘR4Tç‡ã+“ö€dæ´ða]v5-“ΠB·3"¤ë<èÀQ†ÉÄ!U†åÃŒY®[Âz ¡¢•úÓÆsÍé°pñ:™Ubª8²|"ZUÖVæZ™¬Ïwú‚\¢8*P¥¹®Xž„+GöÛ–—<¾šhݼÒ§â€j¦¿î|ÑŸšFì½—§û&VÌ~ŠäC/GM˜qo2r®›Æ€­€Ÿ:¦B«rý[ßASÂX0{a1Âg;×f’5&`JÕ‚Z6kŽbeÐ;W€…äж‰û_Œ•{-¯‰¶nxáRqd‰²{ à­Y¸B¿ˆ.|¼œZ¯a!!ù»¬×`qYîuZîP¿n*Ép!gFfÚ‡¼‘È|ËI[ST›P¦ð°]ó j%Û‹<¨ì¡&Û­hE½XCƒˆÎw(Œ+È0ª–šVßÒT›´1ô¸ŸxøK`ízØaÖ˜ ^.yÈ`W[4r;‚—V*Œ÷4žŠþ©2c?ÞkF¨˜$ö ¬ ¥5CôÜešy¬Á¦êUAì>Oo4Tà},àýbvø§©K) Ý„C‡Ñ"†÷[l·±ò­ÖWë,Ù }+ùÒšÂ)ÜE¬œ’žlf6ƒ:Óú6H·ªô'ʱh¡A©Î/ª§£LP¼EŒ—:^Š#ŸWzV€ß¯¬Þg#…Åäc2Ú&£{¯uhwòlH–µ¨«ñ._‰WesJóRyH†“欷Էé¸×º¢¹¹Êf©Þ¸óÓ×Ä‹‰ë6¿6uÖú¥ƒ5´Ÿ¥Óë`’´†y/.hè.ÝÕ1à.I•­zãN©/ÀŽ—{«­bñÓ4™ž¾ùœ,Èö­Ñ׊ÜÖ‚d*¥¾–…µ©¤¤Qs„yksŸhG &””rñ ¬Ûð Ûhb˜­]†‚9 b†:Éô„_Qû£¿Wk×T ƒSÔõÇÈÇV'IXâEúT5–½®«¦Jà2²Y"Qårãª|`"Ü=¸´DcÚÐAÚ‰rS†?)ä’_áeW@qÇ©;uC¶dµÖ-ö`3•òÚWUyíZSQ49S)Ñr/Y“™‡tË0"’å;ä÷·15c“¾úðµ‘>eÛH“%q”‡TŸ7 ¥Mºˆ©Kürv¾oŠÈ râ:æ‚”Þ|S©¸ï$Û4Ö›8A}/0Ú7e*zI`ls•² ¤!â‰ü¢Äư@1C"óö¼ úÑ´cIÍ*ÈÝïuN\3¢ñ=fo)úÝS!WÒÞ7ò{Ì'% ³1'Cÿù¼d·U>d­móå‡[ê+ðeܽÜ{ðFýså7ZJÞäÃÜ{¯äCÚwïS>¤üšAG~{"g8ž43<{2û!Íc²ôì·ÜºŸ{Ÿ ÈU_`ºnîé HsÙ˜úq&͇\Ò 2DýGrï@j÷ßȽORïÇÔ÷2šg=IïeB‰[cçicãÕW 0“øK+ i’®*D+·m.äë³oý,àÿ¼äA”ÏúÁàú7`rpÿºÉ% ügü»¦&! ££ ö*‘•UB´zJ¿NÜ« Ï ¤ÝÇÏõ^%ŸúîÀˆê‘e[Óeé‹e¾Ò9þõ´]I9UqL]Ž­+"™©¥½NayU'ŽöBÛ‹%gë21Sê_|ÁËoï6…Àªž_òå¥|E)Ç»¾ýã™Ýendstream endobj 1618 0 obj 3912 endobj 1630 0 obj <> stream xœí[[o·ú¨_qœ§sŠœ ï'i›¢n¢¶vŽ$Kr-[Š,ÇUÑŸ‘Ü./C.wu¤*H †¡¹KÉ™o¾™áùažbø/þ=~sðٷ°ÕÙ»¶ú#ü?;øá€‡WVñÏñ›Õïá5mÔÊÞø{xzÀ§Ç×V^ Â1¾²œ :ß<_¿ß¨ÁI­Õú:?½ O0Àú"<)Ç×/sÛÛÜö4?éÜûyjûþðÏAfN…áQ+˽_'%9Ülå ¼–~}¾ÙêÁ9ï%Ì»J Úèõéf«¡½ñëËð‚g ìņÁøZ N/7Ü ‚Y»þ°Ù²Áxo¤†…åÞ–)Î` ©+-Ì[#õë•þÝfËc47ë7(‚J­¯J?™¥•lÀÇ™y+q·BóÁ»4¬6Õd7åÕã±UÂlçQZÃ×Ã),cž¿…}×°Û~ýMØ&õ\¿ÃÍóƒ´i0É,O»ël𠇽‰ÂXE[¯ËXé ”‡a%36å9×ñHpTòÑMµ58ª‘_RœÙ;Åz‹³šÁz:†*%´ýò E‡' 4Gù£Û"JÖ"õÓ<騤w[ŒÑ Õj1_ä^Ûîi;Ââ£íüŸÙÎYÏL^–¯vEa]ƳÚAJÑL>;‰[«’V±ÈŠùáX†JȽVŒç~6. ì2® °Ÿýk'Ähÿ–)!öµíý`~&ùEnû2?ñÜˈ¸ùˆÑáèÀŒEp`ÅžX±í‡AÆûüU1‰Ƅ¡Î¢P ï]ùÉ^½Í—åûë¨É¬wô(Ñ"Á¿Ë dˆiíItBÂy~ƒG ^˜#Ypúý¾Hsºá~p\‹laÌ5§•ZŸfaöÆ$b˜ÇĤ/;œ„5OØûin+£\æÞëÜö¦Á.èÝ»¸ÎØõ»~Ø59|øþª|?Á“ 49ÒzÓxh½ X‘ èïÛ2|ÚJO.ñÝà„£à4N&¹(ÖT‰Hb»ô¬]Ø O°„d=íûÅR9Pö_( (îrï‡R;äÙ.Â#QŽdì^Qx$8ÕשËòBæà 0ç`VÓîhìL®_—Æd?Ê5Š:Zm²ijz¦h`ÿ,½ŸôããqçÜx„ý¨}ÃHÞlÁZĸÕåsVƒP[¼´RhôZÅØªŒÃGïõ =’Ð&¦’Q ÊØ¢ØxøJD·<~u³A\ÒÐÆ^e„d ÷_û|ýww 6“Míºp-²Ç§ЕY@`7õ#-gB}6j`Ìϼ‹†fÝ`)V‘ïo³\tž¼z’ÜŸ‘7ÖJ0‰ïv…ÍSìPn35áIÖ Ì… å~dãÀ}õš‡’q%f¼Äš¯oøWel’n"u5R@éÝêIv‡ÈLë6‹4ýE•§×eÔyÚƒCAH¬2ÒÂxÐ\ž¸ÐÉf§òùºº6äÜ^ kÖ?nÌÀM̃…Qny™CH ¼+~F$h²n žâÜ)Ž ~z‰ÌÅA+OAxxK%. ·ñd®–N¢Ó@ýØFÙ>:ä`AO–¼~ %S2® µz!zÁ½ƒ#l-Þ»áedŒÿ°àà]Y^ÁÞ€­:L`WI8‚á¾ìT‚·0nds¯2'}—ŸN2_Üe¾xÓiëõÆú«ÃUÆð‹‰Bƒ>î«èFR w—õá"?•=¾&‹ßà+ÁÛ§¶ãüÞU쵂ìåÛÜ ˆl¬‘ÏöÆ·D#Â'ÊMGħ4"  O[ÏI–;÷¾X§îã&¥dm¯Rœ— }OSÓ'éáYîû*5}W?`ß'E9¢F뢠E‡Nju¬¦Þ-ôe±tz(!ã§E×Q;¤óÙ¿›¸˜Ÿ‡ /ÛÚ¦2V–mÂ%A¬ÁÕ¼xAt+… Sm¹H =Méõ° !·‹ÅÞ'ÍþӮ˻Noù" ›_Mmþ<=”¾¬!Í”PàÁúÅæ^±8ú¹„Þ{ÅâÀ „£Dú}7i‰NŒMy>ÃoÉãkOÂW&¤¼ŽÕCäfäéÆimòç^U^¹ûËISðÏ6â& pøÉy–(î;”Å žwò«ÎRÆÚÍŠå½´m¼æëÙè=®ïªG ‘~äÍ2]1É H™¹‡€JÍNU²•#g5ÄhÓ#7”ÀNÈ‹„q’EMBƒÁQ—îš½ÉÖÆå¿šl%¸º6¤ªågʹ;*JJ$z”®S°À(³÷¬×Ž+ôšžÉÎg‘ƒŽ/Ðß°vSǪOêqX§ÆÅ$•Y˜N|6ˆ‰#ƒV ³–—“=ÉÑž,cb”`Oƒû-‹A?j¦Æ¡æÂpÑ甜jd‰øƒŸ(d ¢1å§;ß þÁ¼TwKX$ ©·N‚Óºu·"˜æ Ê-4íಊ¡`°#½«rƒDçû‡•K:¶©ÂtÂ_b€¤µŸºªí6”CöL[މ>†×”"ÄL3¯˜ÕÔí= ,¢<¬4Rl´¥A}p7]…‹•ÑÅô_=*î€XŠÃ‰ºdBeóÀÍÍÃðÑÝ`*VòÿÙ<›(2X*Xé–Û–åÆÍÿÐåØÈyqðuPR:vÁï/p®p~Á|¾Õ¹\n8"ü<õ¶ÄŸÞ¥ÞE*ĵÅPŸNO‚sÂ>JêeÜa% ”êbÉuT'kZKÇ4ç[‹¹£½ª£—o8™jS/”X<ÉPå«™Á!€c šÅe9Këî‘Khk|Ë0™Ënm„”S†¡~@‚õC-<ŽÒ²<ÿÉ‚§ ¾Ô𥫼1tbþý;&‹UX¼ ¶£$k*™O-©¸“²0Gç%ïÎÏ®,trêó;2b˜@YØF,õ•cN.ÞéAK“dAP›ðR$G1ôQi½Ï{eý+déÁ&q]³™Ó´…­f¢ò"`½+‘RÒÂÞy÷(@×A@ª€]T"ëTj®Œ8Ê%ò¹5Ùï´A¯ãþ ½g)_æÍ}Œñ¾…Á¸7'(’)Þ‹R¢P+îm㫪Ôß\šãŽ”á2.ZLXV3?Ö!)G-+[‰ž†î-ªœ% gF˜ç=h%L”¦ïæ³ö(F¦ÖšmÚA¤]ár÷ª=é­2àä1ËCî¢àX•}6ȬýLš¸_Ý}™£P‘£Ðëz2ü^Té'ÜD£3‚@Ú¯éÍ”æØô†\sÛî-AD}sp‚ù-V¶•…—M&h&\ ÿ°á|6mŠöÜüc\ÛM¯b¤ $ 悉«-8ó¾5Ùix•Í2»†‚j«$å©*õ‹1¬¬%ô?N¤ërZ_¹™¹i_)IçrÛétÌ\ú«jrÀM¸ûyjrO¦ÕÉ\"Źj<ìtp¬¾që»L5õ5õç¾ûUM»Úÿ–ß·èEÔ7%6dÅN§ú=ÁÕxÿ¼Ê½œFªÛ«µÑk§Fè9.(@ëm 5K:›$Ⱥy_r„Ø|âYܧ_‰akNoÚ&-ŸÍpŠ1¿YaE)§M¿j2V?õ¾šVîÀ|ÚäßUX2÷}Ç „ZÆÂ]Õ ƒ¦ÑÞ¡k@ÄkæšHS×jr¤òSkzþÞ ¹:9^˜/Ý<ðʤ,W&¯òåÈã¶ÂpÏB–ŒŒ©|bÍË— ç|‚ѯ\ÛñœêÆÛ‚¯Iy%ù%¢Œ£acÈ×MH¤€ÎQ­\ø• wà×è¯MRrÂê%Õê5ùª¹¸æÁYZ9ˆÛb\[˜Ô4 çhÝ]] ɇ{ÿz,~tÕSHb:%eH¨&13âp'Æ3²ðô‹Z+êŠKXÕQ϶’:47·S´ü‚¦è»j%c~ÈÝõ•%Ö8þ7=M.‰¶|¸PMdaÎ…`;²0ÉŒŠwû|»Á°˜Ëè'CûñPõã©xùV7rÙ+Q©ã\64æÂiâ£ÊݦÄÇÈ€ÇSÏø¨æ½è¬¬\Ì‘æwÿ ~,/¼ªÖ›<ßn‚åÍÏ ¦þÒÖ©Ó˜Ó ñußúëÊåxÓŸ÷ÉôR’¶Ü ¨ó­û\E–<$Ïû•Õ~™çu¹ùqÙ3£R¾«@ù,ÓçßoÒ¯çÊïè¾FÃsàjµ"B•DÕ»ˆ&ì`D7z¿3ƒ qˆR+eòhÈ Ï§Ì6î«)óþ,5å‡RüP7…Ÿ=¤¾<Ôñ#j6O_:Û‡ô ï#‚³Ä´×¸¾òÛ_NÔ¦Fîëÿ¿ÿžXþVendstream endobj 1631 0 obj 3745 endobj 1637 0 obj <> stream xœí\[“\·qN%oû+Æ*We&Å9Äý"9t™²"1ŽcZZ•Ëeé"—ܵ—ܹ“•ä]?@?8Ý8¸4p€™Õ®žR*jO ÑèþúCã|¿b_1ü/þ}þúèá—°իwGlõ9ü{uôýMVñÏó׫ÇÇ¡_ùÉaÔêøåÑÜ_ ®&ãV–ÉI¬Ž_ýe}¼q|b\òõ³Í–OÆH/×ßm¶zržs½>ß0èFkÁ×'›­Ðð{Î×24pή'(œ¼rL®m.ü ›øúé†O^r¦ðÇØ»‘nýv³U“О9躄&ޝŸ—×_”׿ƶ^h#×—¹{2Ò«0<É,_Ÿ•ÇïrÓóRˆÃçnRNÐ^/rÓå­geÒÿ¸gï Wi'©Äúe(5\Ó^ßæÂoÿFÂ…a“Óqm¤50&º6—59i-ÈHém*:‰ØëgÇG<ú~%µ6“ ½Á;ÝŠ XZ…«Í8 õçñ“£‡O~¿ºz{}rôðO+~ôð üß㧟Ÿ'¿]ýÃÑgOVØ—JqcÖOÌ­Œ÷ÿÐÑaêÉ¥Aõ4žO2Ê ,™i=:eíÏ3:-'§ªÑE¥ÕÜ$¥ÄÇw9iÃŒ-[ÆQz3k‡ý MµWY½P©»õä÷Wåñl#ôÄ´ÒëÿÚ˜‰ ¯/=D¦œÄÜFdC-3κIÜ…–9+±Ã{Õ2|Œ×›y³˜÷*Ù½.*\_sˆê}]¼È6µP²©éàd#Ĥ_ÿ}³e¨‚‘šÚËÅkƒi$jšLŸÐÔöB[¡Ìd§Æù´ n aȉſÂ^A0••>éZ|âžã|ÚóÅ ~uUù¹¥¡ß»•WŒñV²:¸é[m%šãÊf²ÊhûÝL ÌÎ Ä5Eu-ËÖ“Y^ÚN÷>¼¸ÊðƒãÔBy³þ°Ù L<ûþ¸-ò¾z¹±“õ IjÜÉ;ïšäØ­­ê¿”DüiI4µ¿_AJ‚ÐÝvï°TOV‹eg¨­îã'²Ç^ÄWhÚ4½ÁojË è³×‘¾ÊÞÄÈ)ò¦—øs>ii)T<-?úi»}þj¬P¨2¨@Ç/’k‹PW#XÓô®1”«ld°W2” ä‡UþeR3O-Ú³î`j3zè·ÄnÓH·ñãó€Iw§•ZÀEZ¹”³I˜Æ«RØ÷7oš5U¶P)|…è܈TäµDØ Ûƒ:©ÁRiê€Ã2^ÔJ!$è”Pcgg}ëÍF/&~ëO`B”óJÖo"s 35\Àžqð£z¯Ç)} ; ñ`3¯2hÌq®ûåûËø[¥Ò¸ ÝÚ£ka ]©Uož@…:IWKÏŒ?ëP}E'?#VôCîaÖïy¬àgçÑÆ‹åøª1Âäñb¡ž`(QtÓ×lXcî MûÕ |hX@ùÕ^{K "ˆ€;–Å+J¤õ²Xtš;ïÕ$©¢( ^/lTC·ôŒ¥w³¸ bt†ß ⻬i ¾!¯xgSb nÑQ„e‚½&{š&,DêÊJƒYtBž(+ ÑUVnØU ,ÙrÃ{ ˜–¦šÕBîQw 1Œ@ª±¹ ¹4«I‚€Ñ1þ" Û’–¹¸é%´ÓgÝ_µž`Þ—…~‘ 8_F…ØômÞGŠ¥8v­JmuÁªq#öBüÛ-0¸K¯œKä’Öv %3?Jޏ°âÖ±¬P$–ƈä…ß: ¤,#À}ŸW¯'´0º„¾ï}t}“ÑQsLàIŸÝ :YˆˆÕ$FíͰœ˜}/ôlnjœ¾GL™†ÆÄ€~IÞZKZ.wÄËž…-º˜yóÚ¾s!#ÀwY†] f–d×àö ì7ñz?ÄxßäuĘ¢¨÷ù÷Dld¤—Ùˆ›P@fjb‰¦ˆ6|»"üÆwzZVLíüJ‹f‡HïrÁl¤ÑãšpÑÌíƒyÃmE[mX‹Î»„^~ÎŒaPN% ÚMöÌr ™ì쉺%¯Bªó.p™ÇíÒ#ó’-òáæel‘™¸_S…ˆE¨è àÞ;?q‹£ØîåpäÓÀIî×_æ§ÏPóÁwzñÿG#·©çð³Qi•D 5¶‡’v g=«'t$îÙÏCȹÒ:äü¦8Ò¤µüyF~ÞT£“Ѥ].욬…3ka@1to6½ · Ìb°®â!£7¦Ù)5 Ha|—ïªãÖ¸½¯»™liÇž=J£KNô]tšó"òøªÛ!òH=|³¦p&™ ´ŽŠÃ;­ªýÈ̱™â㈃‡(ò›Me„ûm•zdÔü÷VV@jGÜ”V3î¿O¼¿Ò T:@‚—€ðÔC(Ô“W\2÷>¸Ù á}Õºˆy“o¥ÀU6E’“WñõÅ\ʺŒic&ê +AÙÍ6,ìpî¦Ù°Rxr¸‹$áê E5¬/Ž –¥ð“2|o¯eK]—N‹Çþkß?¯'$ëî‚îÔCt'Cv¬:oèÓ!eÖŸ࠸˜¸÷I[2ë³=síY4ÅèdÝ œ¿HôøœzöC8;a{RæXnJêp6íÂÕî|ÁC…Rt%¸kõíé?‡]jù"¼‚ÞÈú?£c‚†v“¼ÏØXÔ•hÖËf1QëÛŒ›¹n™t§ÁÜ'”âä»à5ƒaäÔã×É6•vÏþ |‘JjÜ“S$+«â6K«+²pfvMD!!æ®_; -ûGÜÛ8“´Zo« íɈ )=нKä$gP$†Jªeg7–ÿánläøOüDš/º}ÎÍÏÿ15,ìÏwÃÿHóÉŸgt³ß'£{B`ºdøäöQÑWÔÊÏDYO}“:y¼½þ±tõj'µï˜æMÏà?ZŠãF´ ÷‚Ýý4Þ÷“l­é›îî%]Þ¢—ÞÒƒ‹yºl´µã†Äè}ˆD™¹ƒj•gKx–h)ûˆ/…5+(dçB’3GÃt ·ÔÀæRAYŒÊì6IXHf˜äAN&¶qV3,‚,OãAUÁ·„]áyBƒ&¤ ‰\Kµ!ÛBFØ4÷ß:\Œ¿ô€§!îr|º<\KGG†’N$Rþ±4ýu,)Ý}ú™ÆÛZ¸KPÎÚ;JH²ªg+­X)H§`(ÿm.È:“}6˜ýv–‚Ç×°ÕWA9SõU²™ûh3‡XŒ¯”À Ê›ièæy~š‰3<®;ÉdÚǹì/¹ìùéÛ\ûQ.¤”æê_5ì>äÚWM>½Ïµ6[?IP1;ÄêÿÉÕ¯C5‡[^ò‚tj5 ÈóÄ žåÚ×¥öQª¥C͵‰J¬†škß§ÚG¹öW¥öEÍGbíy©=Kµ¯sí£R Ø(VñŸ•êwË¿/µ¿IµŸåÚσñ•LaúR²¾_¦v_çvK/OSí¹ö÷¥öÓTû‡\û¤Ôþ6Õþ.”I0-NE_¥‡oó~”Š>!ÌínXðüM®¤×™h8ž#K-}o4:ôàþ!¶µ’ƒeÛ#Xà É$ZRä¾)B4·ðÔ5æAG-4„:DðÈ”ÌÌ¥¦G@KßPNE›Èó¼ 7Ãj6²Ü&¹Á¢þSžqÅùà ”ŸãCŽf÷Ñ’•Cxa¥ ïé;ä:g"¼ˆQxò>“*§<‘¿>ºh_x"Þ²K-¡«‚¨IÙåˬˆUžÚâXiy,C’/QÎRÙÑÝ›š‚Ì™hh`el™8ûÒµC® +ÉeuÎK/§ÌúòÉóqøŠË¼À¯‚ªŸW‹™ú ’·LAƒË‚õ®Jé…$ù oJ۸ɄմÁË6ìµÉ«!{ðYqÆõ1,Nܱr¦ÀÄmÍA“î£`´b%@üÎò`ÿÖƒåÓd…ÝÀû”+šyæÃ/<†e˜•ÄÍÜþ›,F¯Š"t ƒ‘Þ­¶Uëÿ ã‘ÐÉ6íÑÒ Øï:QB{_“Ï*žßGdå2¹+ÐÜŸkC4hJOFßë ÏVHÛ½®O|Ù]ûƒpbÊÁ7o1 IÐIküQúýÒ 6ù|IȲÎ%!l‰<Ì|z´Ì'Ëf æ“=NÃÒ3F6ì³`}A\U\PEè¶kÃÀШK±#¼Œ™fCÒ-ýUÔfÐDÞؽ 2QM>áYÌ«åx6½Ì«=M97ãtL”­mì´ ”ù¾»/ÈH¢¦¦§O7Óf5i}Q-ïèt¤¼ït_ZÂÊ7MòmN£àTEÑ'–Þõ5™:%c'Œyž”·%¯b|ºá¨aPßáóÔù6I>B¹âï,ÔÂ^f©à ˜#UJÏÀ+#¤éïú=|…bÁ»[b¹™ÚäÌ?o¸„!/,ÿ"Ô æOƒ»¥ýeÁô£Ý4ïÒiedIR¤‘mŽv/³<_Øg7<O)Á¯Žÿãèø_Ff›(xR`m)ja0dùº0»Iÿ‰ì.+±4ñÝöRMvhÂ-37×IÝ8M…ÛÜ뎻§í݃bF 2[$gÆÐ½ ¦*U^eyߢóˆXñ&é"âªa<söECË/ù$[ý4îXg*;T2±žÜ?ꢢ> !A˳ùø¹ˆ]î o:iQ íùÒB5Æ®â¿u;‰^\(Îê…#B"§Ñýÿb0b¼F F ôŽWßú, 8‹ü¬${4)ÓKFoxœó@{é©Ë ÷ -!Æ®%sӌ衸¥• qO˜Qa1ôA0Ôi7bÌ€õƱ6Äõ4’ΔëaÚJz8©´€a»Ö!eçb]¹–A¹ß]7hÆ_(YÇ_æî$žÅ~8ÊÍò¯soš¼HÀ–BÑBñ³¬`å" >—m°·Š–ÆÂYRÜ41³¹³2¼›>—yá(?!`YƒI¶ ~¦@_$?É •& ÔÃ2N׬®\ôyë¹ÙÄ„Š)S`„Á§´€þ¹nÔhTu ‘Ž6Í; _XmŽxöɉÁ®¼ütR}íßsc|'z–mzü,‚¨ ¦Åš'),ŸÞqPH“¤ À näΤÃ@F°ÐºîçÂbäC„}GvÃï(„#M÷éêmK dg‚¸ƒ{¯` @L—cÞ“ p["¨n܆hR‹;û>̤Í\NȸÒŽ!¥uC¤MZß)Òf`¦nû• i`Ê¥'}¿_N¤íu$eóµá8œnVà?‡s2=㼆dðò:$¡[ëûìMRE/d=B:Lßw>Ü^Þ3ˆ¼bÈJÜ/Æí¥p “o’­†éø?Q'÷_0T °Ž[rVE t}ú< œ]ˆCŽDF.ÍÀCüm–qå±w/qçÀ;ƒW¹”lêrkxyY÷Fiæä|̘ˆŠmŸæóY8Òª(|"ÂYÞ;nϰßDű’€0J ß \IÀ’­-.V„ÇëZî6x;â¶öf…±UÈuK›ñ:3t…—;Ë4ZËtÍGm…¿«¹®Aíΰƒ+$îë1õ#ÕæOÀ;áÕøãx{¯d¤¯]©1Ñ,5 ç<‹W9¸$€Ò«ý}Šß3†–&¨ÄÄ0®í¶ð½¬êFàEéiŠÎ“ò7·ش†É¤ÿnbu‘Êν,IT¢D –çÃV¬Ãù,]o\Jw29D,;¿Ñ˜Bhz]o²ù#kbiõ›ÝMðóh÷IÙ èîÝñÍRâׯl»Í·’-¥—•ú˜“ì¡þµÚªDñ¶Ü"ÉCÊéèùºª_5íKÖ›vãõǺ;xF3gF˸ûý> stream xœí]ûܸ‘îÇù+ûS7p#‹oÒˆw7±³·È&ñá$‡`Ö3~`ý¿nÏùëSEñQ¤¨î–F=çl ï’š*ŠU_}UE‘ï6}Ç6=þþ>}}vï\÷›çÎúÍoáßó³wgÌß² ž¾Þ<|âoc×9͵ܾÿtuvï¿7ììÞ#üßþ†?¿ÙüêìÛÇlKƆï±!Ñõv£3øwFCó‘  ÏaïàÐOÅ¥Ó¤£¥pðZ°w§”G–Â}j.D/-µ“Y{‚N*¦·/ÐNtg{uŒã*_'&u‘Ï’¶^î@Ïziøöw¬HÀe4>ÑwŠñp§è CíÃG0röEÒÉ«` \Sû!–x‰ÍÊÎHI4ù¶ª¼ùN¶Š@ ]è‹¿NÞK6`4jv˜q~‘í‹ôš<ŠÈJâMè,´EÌz4¾…§ùì‹Ü[+Ç»^ˆí_·¹áŒQÈ#^ævÇc7 ê,¶Ó¨¯O.AcÚ£t™^yÔðºDÚºy2^C¿ ã–¢Ôýü³>ßû ŸýënÀ1ÉÌ”uI+—Z×$iklÇâ‘Pvhj@$ å‰ lvz°ùÿÚ÷¼-Të¥ù"(\¾JDÀ™ $´(&Ø´s èúeq&*1§·xdDˆ×ᤢcB /|’Õ, »fnûn0ïž|„÷Ÿø0×YTpâeÛ€ð¥:£øÚæ ¯ByÔ,­xñ {Ú+?©OÑ™¿Oþýeéòáàmºö&žúX’€æµAœ ­å/d¹˜rÇõNöÎÛ#iñÅHÜá€Á#®ì¥ÏH!¹ó¡“3‘bÂ|öH.xý.ªq1& H¾÷µJië—!©"ø *.AÙž€.uÐI©©#j?>Ü“@^ˆ˜¦]Š©Åa`E»ŒÂiAA@XgB¬õ8õ¬ëäâÖEěɺJ4k¨(Ï'{Ú•~ùËÃ3”Â8{*Ò"PLúpMK17õ3Ÿ@1Ó\²'ât~>$±J݆Ā.Ú/¦| ¤-Zª B×£šÍøL'4[•òqäè½T”Ïg/Å4åãè6¤Z‡òqÁ3`äQ”s‘öžtSH}G¸Œ§kï`Œ(ÿÆT§YYjOø@|ï0Ý¢‘8ª­G0£)ÿ+Ý çàW©‚ø¶° ÁvrêŠ@$éÎUÊW Ê>È]R;â/ßÖ>03ªX‚ˆ·-&7Ì¢\óÉÃ4å6½8ÓUdÞÚ dp©Ž£é}’ÂÙFfÞO.\ [D¸…™÷›ª”ªŒ"VeSò‰U•Ы`•€kwaÌÞãsHøs·:-¢¡ØLR¤uîûaN4™SV{-…æÜ:)Ù}t®/ÄNɼWãDßUJŠ5sxÍìX?dÇn¡'’K?¤3?–™Iƒ>)váó1ÙG)e5iB°ý=X”˜<ðÚó6¡p~C‹ PatÞÝov ‚£tñÅ:bóaGŒÑnì–=ff ÉGÄ®Ÿ·rüÿŽÏf-ͬÄù:˜se=Ŧjñþ¥˜uÕOKàö5Ÿh¿9…!ÿ>û¡!1e9§4w2„Ÿ á4Dû—"©ûÌï÷`æâ5#ª‘Êê˜xU”YßÊé!MõèV¨À7‡4Ó×/a!¤-@¢)ö v+%ü )uò™k–ãÐø÷÷hNõôòÜ%Τ †irÜ8Î&lÙÁˆ³ÔJ‰íî%›x/¢ée§zsÛ4îY‡mjg:²ÄDÃ5¾Ð5„Y ðÌl¢LÄ·uQ¼¸ªƒ æœ)‚ç#ØÙc8>`GÝ4}ÒÍ=ŠÖñÜu<š@cfÔ`U¦Ÿ[1˜ÆÌXÌô·…¿JÂ_¤s—«ïi‡¦§9ö~,è£H{5ÃdØ(Ž>QÉ©dÏ›q»ÆTÂ2/ç ;ååx;Õ¿zZ3mV­”–óY uk•Xp$£” Ë€¥ ÄÁl+1XAÆç]"R.eÖF@èŸÛš¯åÓ[ô®—CzË83´ÑäêÄçE!¥±ñP÷,'q5o÷Í% s@Š”n®=@ òWœVK¹î7UšÒ?LðiŽ_gšs›qM Å_ùÿUü]@jrS\æðV)iæV‘ˆ"ÍšßÐ2šñ —ûÃ[ (âLÆŒç[™Fx›x„×þYá­LÖóÃ[ œ†ÙéP<ˆºØúü«Y¦ "^_ƒàÁ`fªö>–p6bGþ0Cè>JÁ¸ÛIÒåqÙZœ3ßjdj&I—ÛÙ›‘.ˆ[„¦aoNî!39Lµzæc5¸çÔ3Ý ·…ȧ£Z+:ôQÕÚƒ‚ˆ8 @×d< ¦¹«xX` ðôñ0<õ›YÁðÉ… ºÏ—EÂø“GÖbN2³E€w\@ªômº180À<{}|[C$+˜[5:Ù9ÅѱÏzÉéèxj??x!Pã+êÝÍ€T{Íк¶N¢ÿph%ϳÄ/’ä?’×É!3yò:ALëM_U’§k1‡ýý1™V̺“Ѭ¼ŠtXH8.~i•6«ðHWuï 'xÿ-¤r+ð`ƒX1>*€G?Ø3="‰žûÏ’æcq3Uéÿžo(S•ÜÍTe#Vw®cÎMÄêçå”a ¿Ës¨Þe7CœÏ(,Àè9VÎy='à¨Hý¨2þÍŠA_f¨þèŸ5T’4Q¾©‚öùäk’°J È‹´¾ ±&ç Ò*üN¥"…‡æ^º´¥›5èÈâÍ!DÜ_¼Áüª9¶x³þT¡vƤi£e>~2üÅÍ ¢¿Â " ²N±qÿ "*öë1]Jb¿Hµê·5»Ú_´æ=fÙècª¯nöUªXí4ÐY>»­‰ÈÞŒ>ñLI¿FÄs†—öõ¾% ÊÐüôÒ¨ËÒýrÊÔ½í [èLï|ëˬR·) 9ü©IÓ°LUôêË.SKO¹f(.1½};¡8‘=/Éò6Éž?Õþ©‘ ¾¢ý9T¤&Oº«QßÕ¨o¯FÍ¿àòô>dÄM£o€ñDQïwÿ¬Qï Ô ØÌ4”Ê-Žu+ (ÕJ«Fì-ÎHaÐdszù‚§%Þ•h~ %šåÔP9P=5M ¿ˆäèfV冘Ó;yY}à†Dø›TjnEä¡RCE®ùl>2&ÐÙ4¡?—tŽ*ÖÐÇÜÕkîê5ÿ’õš/•»~V`;й†Ï§Öà®x«27®Øô7­Ø, cÓ,¶w³q»bÓ»•–ÁØÿÁ·P ,ýéØï½O/[ Y¶…åšëi¬žrˤÆí)£ŸHK~µ+2±Â¢·#»þr67¨ºGÇî&åÌ`VŒŸ:Å$mPî$ø‡±àå©=¥"áIÜ­nCi*xcíÈjºÍ¡ÊyÇi“s CóáaO…àðÆx*œ^i~íÞœ€°‘Ë¿²?ïÏ PD=½t¢RñþU!õæD’³:âŽÉÕñ˜«ü¬:À7Á]#=|Ass“róá˘Zò›/¨ÝmIàŽÀK%OeúÔ…çÇ-#Ætýf îø˜F\;û ü ĵr¥§û ñÂøÀ¿³‡û*ñàž\¸¸D82‡?­ýnäD¡=ƳÌÑÐ7Ç»$€š^+àÔhAîùkwû©=èß|iîX2¼ðŒ ì.v¬Çl1/r/ye‘Ï4éCñø°ì H2ë ‰ÎW¸iÅÏÐÖYך:õB®ži‘ÖGüýœRÉéå vÚ°Üi#²¡\ÙÌGDq˵ò¹Ö˜ÁžåõCòîP$'užçËÍ+Ó5à²,Ùgãi3'„¢â®šÏ^¼‚l\ßÙcÅíljµ fHµûÒÒNXw1ïÔNniIÝ©Ø9(ÖâÉcË¡¹Öé}&›Oø€éÕECʯ<2Âùíÿe ½nMþj¦`óѨ?±lèû#s®¢ØÏ-hi4š…cmÛÎëcsôª×T‰'U"ûS±ú$úT1ø9cF bxQ™!Êg“6LT)+3Ѻö,[r–Üû9*§j™Ã“C%€ÂAS øÒÁºÂ«°‘$ßÚa*­ê õ¹mM-·‹jpµã¼“œk€ä¸v}»†AŒ­½£yAœ ªƒ… M¥ˆƒKÉ;yÚrñVS˜T{§§1ï¨xÔ›ÀÈ„iÓäW‡vE+‹;#K8œ>_ࢧ™ úáu¾0ràæ ·Ô݃çN§Y;o–Ý¡bÖ ¹Uͳ|8+µÝÊݹsÊï p ¯®s¹ý)}Üa\ÈB„&½Ìg5A’µ­j÷– KjÓ_&)/r’Àäd3\=÷û0pü°»Æ’? h1Žª|+L'Ò"®W’ÚÁ ñ~õêiçác2j> 'O¶¼bm´ÄR?µü\6®Æö‚O†f”~…¼Y½SEòà!niiíd®÷ ŸeÌÜ .¼¢©È‰ƒõc¶üž¸™b›²Áy8ÌPçq ØØþÑRßIZÿÜr¨oë;«âJxóÙJå×Z7HÕí 㯃§âû€aW Ÿç7ÌâÙ«jG5qé6~Bá¼R4¿áTÑÒ•ÊÕÚ9ò„õZØñYJQõ_ºÄö9®[!o½WIËx[¡¹ñ â"›Ÿ#U3½¢Œ0bGÍßÊuR³úú X ƒ^±Yè°5Y¥íÃ0ó¦)0?¬,/ “†[Ð{?Sãm³ÝñÅѰ]UØñÈ:îÃŽ±¦GX~›Ï–Ë   ^^{¥}`è'7̘äx±›dPˆ®¼j="DLóÕüè¶#,SºÞmËÿ,ú)9µõ^Æc&Qµw<"r¿¢n 1?—9—ýSñàÎ ¢¤ i®]˜VÌÄ›šÌ/© ǹ_'NÃ3퇆Š|YÕ ÊɃTøéÌãÕ‹(•*Ʋ86ÔxsZ¦ óülò†bÏqm#$O‰•5#ÉÏ!ÝãTíí}̸ÇÛ×=(}½1~;E”yÚPÚ&`{/7Nw– Ë·amКŽI·‚;GìµÜ–PÊ-ëkÄ´)+Ž]M߬ÔhÏ–óÎ@sO$Æp$iÅâ½×ˆñ¸ÁX1™·¡œ¬H™]T®!ÕU1yV°Ò,Âðiˆ²«ë×ÚÜàÕwê REêa1.ƒXOžÉK'O¸>T.Ù÷vΠÔñ™|>ÅÕÒÏFõi|¬Ÿ2‡á¯ilÔÕöɺ±º£ÒoB›ödýXŽ?1e™…–ÃIµË°®U¼1m7é“™1KhŸNI¬&ëb5ßèvOâöÒNS isr–4›Ÿ[Ü GA| g½(¥“4Tø”Í¢d~ĵ¢Z½YLȄխ~“G—„$+5#–¥×1-^pT(©2V…-úê&aÑâF™ùòÇQØ0eŒ)}ÿÚþ­šâU®àW“¼ú ¢?e—I¦Œñ\û6VÖim€ô.õø:Ñ1™=<²óÖ y¦°5qìÄ«ñÇ´ä[‹ÃJ—>¡Ï=%+1žküÜœð¿°ã ^ý~køäåáÇçqbÇ §¤¿0&üàs!«áÀs8z.VSGàà~ºöU<õëxðãøwé³¼ÛLÚÞŽl}®êxßïã¹Zoè6Ô/Æ2<À%49Œ]šND¾{N-ü­\“¢9™ΠbÜ-K¨è3°}ÜÆ‹zFcz™ÌCc5µ±±QöýxðUúÙÃxê?GïôQywè*.¦‰ÏÊæ³e,A_¿>Ídz3ó†õ2´)Öh3þ \gž(ußlŠ_ïlj¬Ï?ăïÒµ'aÜ ®B]¨ÉpµÖœ¯Òµ¡óz ã z‹sGìϼìÊv¢O\ì(óxV¶O «@ ‘ñë6ºåKâÅèڛу+UÆŸ=HZ©òЙ2¹Óç;}^AŸK ³6‰ÊÝ¡ç/CÛR«ù³×´ñoÞï~KÛR‡ïŃJµŠ…¸ÒM/ËNNkÛôÇ´Ã=¸ú „$5ΓW\Žn]<™’³8ûÓâ© endstream endobj 1646 0 obj 5287 endobj 1651 0 obj <> stream xœí=Ùn]Ç‘ƒ<ò+.üt9Nï}ì €Ëc ’ØNäÁ6Š%(’¦H'Ò×OU¯ÕÛ]hRÁut–îêêÚ«ºîÏ«yb«ÿ Ÿ¼=xô®çÕËwóêàÏ˃Ÿ˜{eþ:y»zü _3rÅØ´(ÅWÏÎüleøÊ°yšåêÙÛƒÖâðˆMÖ(¶¬§Ã£yZ„r­ºw¹¿+µÅ–EMjQëß |ÎåúüðHÀÀË"Ö/ù$ä"íOÏþ÷àɳƒï~^ í@8’“]1¾Ø‰[EM³Å…=~zðèéŸV7×·/ý}Å}ƒÿ{üÝ௧_­þëàÉÓÕ÷û.— 1IY,ù4|œtsÈ&£¹Ðä&ÂŽèf«eZ4×>Ò œùêˆËI¨Å®žÂ Ïpí|QbY¿: ðõIá6¿p}Û„&ü\zÖ†Âr°°IÍŠ~Ô€%àæ)N¥&f×g~L¦" ¬5n$…Ÿá‹á^øZ KÁ'wOòðþ1›ÚÆTB›2ôÝKÄ™8lW†å"…È„“çgV#éP¯(ÜB‹rHC\!§,@ŽTÎó·çd1³þ'rœ™g«ãšÜ»iž—›ëçþ+ا[&ƒ½g¼À8Ù‘ë|7oîçð9Ó8ך¥‘€÷5_€OÍúï‡r’v‘"¬7b)nÉ…ßfÎdKr £Žä šô°¨e¶žïü`~e p4€*qËÝç@(Ï»Ý'ûø2ì>úi÷³Mf‡î3KÎà în 7ø(îðã~+Æçð\6–KKåE¸”Æ®¿ÃwáVÑnð.n™Þ‰óAâiÛÙ†Äù $°b-íàó@<2ÒÎ,èLÈ­ °…-6‘†ß"¾g ÷?:R‚O˼$ q‡…ÝÐK‚ƒë.ýf¢½Ê[Zs1^ydY¿sb擱K |L„D–=ïñM3Íõë<}Ë“ag:b ƒr›gÀ=œA«ˆË  cË(£ÜöäÑ›tsHçáù£ “d­oqU WÀéWT G>$l1Q9”²ñòQ@ò.™‹Àr|*ZèB&’¹>d¨Ž»Ü;‚KOLê™­<<6‘ÏòÐ(hG$L> t0­Ô]´Yr”æ…‚ßá#°J¬™ßh¢n WÞf“à"ß}ãל² LÍ¥žÌbˆ’&ϳ„¸ª)2X]uÍ•œÀĉì±$šq—pe' Šà¤`pa4X|ÆãQ/@‚ŠJ¶p‰;xä E`…®ÎßH¶ ‰«.-m¡ÛÒ$AÚYß«„©P¸AÂD –&J+Y)~DÚ¨{ýEaJ T gŒ_´V¬e+ 6«õÆïkÐãV\^H‹:#ܺŠ/Ò³“xë&\P{~Îö¼°‹ûfâ´Ï=ØóVµñÌŪ^F0?$È_—«b‹èšóÑO`ü̲BU«Ü€#a ‘sۥË®l8 »—}±™ä LÄKÍYÛ$”ã,-ö½ L"|+i&¤tê™8²$K– ÉÐòcbÖÙÌÓË}ˆªÐ Ì.¢Ê«r•mš<ȧÒ.Š`%öÞÆ^ÌÂ?äJË%’LfªKw…âà:Ý{›®ŽÓÕy$Ó×- ¿ˆ·N73 Et¦µšœù@kN‚Ó5ÿ_„2/ê—ò–1AÆåº\9>»êI›!Ër ® …„8KÑèóšØhÙ´"rÿ¢'c‘]à0 ºþ!r«·„ g퉹¼Ë­ClôþÖùëð†Ò÷ÀÏ}cªQ¸fpo7©UÁx«A±Ò,¿VR¿­QŒîûÖövPÛ{è|î¨ Œ0€'ʯ „Õe"Âëtïmºªùïe²ýx=)Χ2f§&…EÍü œÊ€þE¹ÜÛòMùŒ‚<ä5&ØÏb°J=‚þWZ·ê± ']tE.’žØ (§Aï Á‰g ì&…†yÕúKB$E€%¹]EÇ%—a'ê˜ãÌÛù‚avJ:¸:wŠt|ã¤9€"¥4ðA@iº(p¶ÁDžo ŸÀæºø‰`³‹Ÿøï‰yºKô„[î¢`{Eç|ÐËQL0d Ì•”Åñ™éR_ÿ5Åþ7œ-ì:±}¾Kë#^çwé£o Qt_}šñG&ø²ø €Y&¶,UDÜ@+$]1¨‰æeÒó2Œ…ϼÅÍ&V2³\”¦7ÔIŒQ˜¡¶¬€.Ø¢šì8NÃAÔ®«8˜Á̃ÁþšÐå÷m©B$/–7˜w}K¬¬óÜÀ€ydâ€xØ1øô@È] û4ÃÝ÷ýñ]=I.vp¾Ø‚ i ç«OþÄ=ïyØQ˜–YíÂÅO²NïëiÀ9.F€ƒ/[IAž<§ 0ùŒM¤×‘÷;èXI:ÀE#Ä ÙtÇqwŸ ˆvB¹UθyÜ~Ô„ÄZ[³/‡²ÉaW±Zv0@µ¿ÂQóRDÃ)ž@¥äØL—!% åiærýD¾âÂHºÓµ¼p ×y&YG–ýæ&ypš¥ñµH,¦ñ…êw“²íNW ùÄ/FhKÅÄ „” ã m h‚~ëlù ˜ ™“¹»¿¶_<„3ðÀac"Y1ϣˡ“m$·x[Ü gÃ1ùà6xv~ª pô{AšËÒa¤>äh1š Ì¿~”ÅhålÈÍ‹i|@Øõ],T´èl‰ªÒô6…$¡ò~ð¯¯bˆ„¸FåÏ0yÓ7ÕJù­º£/fu‰“Yö}Ì~6¨y5º“#ægÂÚþÑn—ƒ»¿„Bx9Û[àƒ`yï$ÄÐÂöÁ„˜Ôz*‰øç:½3`fiŒÄèñÇ`f ¨—=é”L¸8‰‰›Ú®!/ Ö¢À3ÿX‚I1éÌškII¨Ú¬Ùã$2Hr™„‰É™ùm¢Ef¯²ÝËxbb³mƒÔï{L@%ñǪPT3šNAb #&=±ÿÉâþ•ïæ9ú‘Œü|§a9ç“aæ^dKuª»¼Üdý¿ÆËS˜ ͇E)Ô÷ö‚‰!3É´GÊ|MJq·‘\o·ØB03ÂÇÎrB8&_æÇýJ¯Hh¥ÑPû(k³Ãn]Ì]½"±§ödHòŠœ ÑQ†Œk*vr‹íå¨ð¸ÐgöЀ;FüVæ×Šì³+¤1˜Ð ·_’b:W壹*RHýœóy7`QԡʆW±ý|¯Š`C1Šd¥»¥³çuXª®þM“ ‚:µ™UËò2¢³mر’W}ÉTÅx xV÷^çbéûeLÉzò¨EÐЇFÑÚJ•·9RÒ- ’º%ÖÊn—‹x¯V3‚ëÏÁç÷Û,ìL)µ¥jËŸ( ˜˜½ê²ÓûœC=Ïåª$3KÞMƒ-ƒxì>±ã´Q›H&[^šÿ®2s)Êö®ºèÛZz˜Ê±Bè$ŒZª¼V6ÍÙBBc éQ€(Š&WHÑ>~\¿íí­$Ì8ñ¬çI… UÊdž°:µç•âÚä‘[gÄÈ˃'˜ÑÄ(`Ï ö8Á~SÝÛšiI£–DæmO—ò õvÙ ¿íŠY¨’»,ñ ´¾ØQ¤„-̶«š4‘ÇINè}Ðg²8p µƒ?Ñù':@:/)1·%¤øIÚþGSaJPçŠÂë¾Ø€ƒG%ÉåªÄDrH…Ê…ìE…\ø,[6î^$ÒÈîÇeE²e¼)ôýgº—Qœ)èe°á¸ '‚o;äÂÉ©Ù\àxLðÛòÅ«ê O‰|ÎJtúQüŠg»mY=ód j¡ÑÙA·]µk•XXÞ¯ÚgáC]¿Ewn¶}RßD‹»’}ØÁ|hà¶\/s tj¦ºN`§AêN³\iëU.Ò 7Í òƒ’°ÿ¼\["Íì³·E’dI»IÉãèKý^µt®¥~]Éÿ¸iœ”ôæi–2o:< ’ËîÇï+ X²qf°«Â€B©7SY1‘ Í·ÕƤ%)ž·¸.W¦§\)(‰Ù7í‡ÿÈDÕHjýK+ép_‚õ<ÃzáÏ¥&ÇD…É“µ“²©þ¬Ë¦'-®Ò\ï!&T]gú»-_£ô—8J.µ´ cøjýÌLûU*EßëfÈÈš°Åe6&vaDTb•¬•þÐò]û*=͆ÔûŽÙFÎá©KQa·ÃÅÄß'í?Ó@û7q’;\I²‚+IÖ.’Þ!Á£;«ÐbY†ÆÆž7ó]wV‰«0;7µ`Ådпª«Î-XŸ÷:šbp’š¬ ÝXñ£ø\¦ËQV¹¸Ó‡«;¶ôp=Z•;–Iq’{´:رèð$-â2/¢}¯ß´ÕÎ0ClÚê;WYàqb¹¹k«;à3®œ`8yÓâÀSÖ;UF`¡ùRä±.c%»¦§ã_4‰¡\ÊN›#Åw§s‘Zªª@¢J£HõMs¹*ÙÑéMÞ«i¯O×ïPlïÏdÓSNÃVñn<‰-Ä '½i£}ÎÙWÒ/«¹©ežýfÛ:!ÏAèÍœäÞ œ¤©)Z©+­º sRþBrë$û»5eÝÖxgMM”/*õ- ìR¥`ãi r.ª¦ÔiI©TÌör6Íà8îÖÛ —šº¬ œ¸êκ¡Ðwf³š¤¤okÚtcåÉ|Q©¬ JI66e‘mìõʱŰ-ª~ú5áM uyøðu–Bšê¦¾}$¦p/g[‰€Î¡Æ¾À©:F;1–z!ŒªB*D¸^ßµê#Öv‹ e$LBˆ&pìð€f,l“ËòÈË1¥Ånž>xåQ ÏBw;º4®ÔÆm”k”µlM¦üÈ/ë¬/î<\ÝC—0­&]ŸÐÎ&ÿ»t/;-uk‡^Õ@qܹ9OëÓCxõCzúyu¯žï$Þ»!£-ØfCº£Ú.àï¨õïvþºñ^’Õ|SAß ´^n}œË¿OÏ~Š·~ˆ¿ à ]?,`¨²Äã@BˆOü.Ãåü$TžtñY3l-¥–}¿€:øFGr½r­ üÒ€ÿSzû§òq¨¹m­šˆÉm¸+cÒÅÝÃâ^IwyÆ@ ã¸ï™Ô÷t `T#ƒ}Ë‚Ç"S~*lµ{DÝäå‘þ ¯ä+bX .?Â’°VÒ}EŽ•ÖÍKù{R(ÁxIÖYã!«ì.°vh„ðç!± Åö¬Q%æ;Ó-ØDn$O¹‚?xád"^ô y­Rj¡[ª”wQ8÷6ʯ$Qì½-eØ›ÑQ,YÅŸ ɶãXüÞØ ±»?_ˆ•~ üê… µýÇ=N céüªŒ¿Àq/Ž þòżØýÎÚùŸ^‘…9w~±b47Ü,LÌjb‹ÞÉÎ ¿S¸mXë“»wd‡óáàÀÀüœ.Œÿ† ðmÆ] |P¥’–ePw[uÿ÷gÿš3³vÅŸÔUÜîTxa_Ô˜Dÿ2tËw ¥88)Wí~ÍçþÛîÓ¥?rŽ#Ûþ’ÎVúíŸÈ-O¾b GŒ´5 Ô^ÄûC…|¨Uê¬véýeïpN,ö5¾«—ÏG÷GÍ.šÄ8úâ©‚»jßž¨zvÞÆþàà(ÒÒr$®ã¸$pù“½@.‘€ßäU dˆÁûÂÒ&4£HEËŠMù¨¦8ßíÂŽž"t‰–7uç«dðipcUág÷]ùx@‰ üûóˆÇ—†iÎkz“Æ#†°*l„ºÍ'î‹ùØ[ÌÒÍ<Ë£nov9Ë|$´Ò÷uS£!Vçð½˜\÷ÃŒºÿt€M{ÇKÚs5â%F•¼›Cáûnôð¤’òfVÅy´tœù¾»ÊR¥…Zˆù•¥Ä".hS§¬*^Ý@n(Ï,ô­¯d(ïo}¬[+1 ÂîfÝb–-Y·VîëÞÝٸŞy.TùÖQU´_³ ~VÙ´ÙÎ-ަõ0í×íÜ{[ÔF3·XÏÀ5ö8 HÌ©FTtt?Fœæ²ÝFE¢!RÍåÏh•?¶V²'ö„7ŒäO?Î_$ º K˜ÅSHõyt×2W¿..å´gd¨FÝDßÑ+5€1ù€¤àú£À£‚²t,¤ÇFØ;u*v…Ç-Ø#Rå¹Ä­§µm×·=HU„þFA*¹åÔ®¹)ê¹KÿÅ5’=ßý=Òùn?[°pŒ?Ž™,¨2íÁÁŸY_§Ü¹ÁOÈuö“¬[S¤9éÑ&#«Ä\ìæeT¥æ].̌ͫ0ÕÍ—ÂÓýïß÷‹—õ›1!í’œ•hñ¨’EhÁý¤› =w«£ö!CÜí"¹ÝÕðí8itÖO ¶Z5Àý¾™îèø… z6î{’´È7úåUí¿7;$,Q%À1︵ŸDÓƒ@[}‡¡oƒk¥vˆKP•ë2r!¤ZG#Üvô³V!adÅàbžãz,ï¤ë7äd’lí7¦¸ÌÅMèaø³eäÊ¡¢øÚQàÁsƒ%¿ºQæïúæ[4”÷7ßFv²´jßÐt/y!A×ÞKÕÑv#ü#‹ÕADÏf38+Ú²ì2Ÿ,Î{¿T)¨A€˜&4îm™Íæb…ù·=H%S[;TE½+¯nª" a¾­Ýû¸~vÙš ¢@±/é] špx1ø1Æ}»‡†b… š|Y‡-B¿¨{u¼ ÑXŽ×jÔËÐä€oø¢¦,bÿAÎÖ¥¢ä,4c6nÉ}+þúP©iA±YÒÄÜþì<£ <ö 7ìëE9]›20 "ÿtÕœQ2Ç›iñßü?ôøPendstream endobj 1652 0 obj 6350 endobj 1656 0 obj <> stream xœíio·µèGýŠmлEv<¼I ('Jã"‡“hº(d]v+¯ly•Ôùõ}Ãã‘ÃÙ]Ù+;(‚ ÃkùîƒûzÖwlÖã?áïé˃?pÝÏ.ßô³¿À¿—¯˜Ÿ2 N_Îûilæ:§¹–³ã‹ƒa63¼3̹™a}×ÃÈ˃ÌKÑq§„›?_,Ug­sb~¾XrÉ;¥Õüd±dÖŠéù³<áz¡;¦¤r󟰥 ã"ÑwŠqºèfa:c´Õó˼ü67_.–²s\J\­òøzÑÃI”âlþ>ÀZYô^§¹ÿ<þ+^Á¡ÉáûΪp~fúÎèâøÏ²³BZ c VÁgbßyjé4*c~íèøàûƒ×31\?ÄÎxÏüŠêz‹x{ôøàÁãofë›Û󃛱ƒ_á=ùþ<þbö»ƒ£Ç³ï'±9} ÞÃeq 3ž1öÓØugÕ ®n‚n¸0õg‚ è+U&é"V¬™¿ò-ǘ¢X{ᛢ7ŒL]å©äWyjèœT*Ìg\vƆ/™RÀ¾ºãÂÙÙñÀ*q+ ió)á(®w~‘ëôLuÜö}˜ÿ‡E¤$§‡ï<þ: ÜtYÌþÖƒ$„vóïBvRSc§ìsó#l2íŒ%#%\©ÎDc%CZÑøG߉ff¸Üï£{Ûɼ7û¡¾ špýLkŽ„¾AŒ¼(y—ãÅ~ ¤Q³ù‹o#mpÀš–: Š“Bfp¸’äY)É\ å|ë…5nþßæwÇòÇ"«Ð­âøYŽ».ÙC x<l@Ø#úºEýáXZXÒIˆ¯°gP^,A” ê‚“ÈažX¸›_´ ûž¥N²U¾ËpV-:¡×ÅÌ À•´÷*ƒr²@ÊçÂ"i÷×Ü x¢c¬¾‹x_‘âJÑæ“C|rã¥s Úåüq>ëEü„ÚÛ ¨š¢‹…(äÖ5•v° þG**zP®·‘ áÃÍ PC§aÀ)«ñ^ªÂqOºW¶òûŸä]’EŠó½H/œwÚñp[Âë܈Íe@ç’ñ¡˹^ÉÈ“š™`óèÌR2 \˜ íšÕ‘›™R\K$ÄšÒä ©ŒxI;ÀzÞ+Ú(AJ1åY=”3Ÿ' "˜XµçÕ9º4\Ç•I°ÃTr='y.!1"}iåzIaô’RW=Î$|zÛ’n«Ì¼×tÜ3!—p‹^ (<\ä¾W%1{ëSRÎ% f¼zÍÚ_}–: ÎÉIݪ~F›áÈn·c6Õ IjŠŸ®š¤v½ðl´ hÈ5],kzNxžHÂó§cBÒzwXJÜ]rNö@äp´|‚]&…Âå`(YÛƒqõõÁñŸv´ ŒÊ{/ã@Y´i)[f-)&Nˆv¬r(8x V ƒ2ORïÅ_¼rÙ{‰4‰ØJp‹–¢ 5‚¬oþÝâ´K}·i+“rÆô‹Ôú%Ö†yI—”Õ–Ú‚"íÁåq—ßLˆ:7¢%–V#qQó0«/º>‹Ûê0Ðõ|ü½›Øõ"6~i‰®¥ëÀû0"O+nF™’|gëL€H4“yáëAÜ¥¨lŠÖ&º£Âƒ À0D#úk᜙[µxƾÌ[- Vk:­•I)7o£W[È /‹c¼ï'²;ñÖãŠÒ‡{ÒBƒÞ3÷CMB¨…ÎiìÇØõd >”“‘ZJ ƒ7l@1hë uß à¤ºŽâ—MކÅË4L¤s½¦è›Å}£0\‹Qc‚ýò¢˜”9ÊCd玔1¶)ô6rÖчQ8IBÔ2%D¨RðN¹Ê([W[Ì–"ƒL­Ú ÒØB·9Œ&!/‘Vªq&†gM²:ËÓ·ÕÕ”;¿ÉÊ¥Nž&~šxJפܔ’Ý ËbPšd©ªPz¨ì{Ï­­I"¬e´k‡¹¢ ÙIzÒJ´VYbh*΄éŽ—Õá]–¿w^ˆÓÉrÏ"õ“p²¶@@"2Ibö)“Q'a½íc½Cª¬ñ$ÔÈ: ùÖuŪ"Ï)Œ$H¶†äp2XeÆ [»;À?Yˆâ·2r¿¹©2[4Ôh¸&Ú1¦ºI6–à ½X¦¤Y(µð}í”ØŠNðq2àÔ^²¨ª¹Æ)Üe_‚õ”:Ä%½ÅWe¸žg1HêO6”òÐLw#Yr`÷›¬Â©![•êCúbu,ÿ ×|‘%+‘ø7­åMÉéwÂe*¬÷ÕÕô3ƒ‚ÚY/10f‘76é¥ÍåÀŠÞçõèjÅPóÀ@1Ái©Ä5ýLpvr¢ìã?´â›Y°=¸œ…˜˜ÇvÖ§œ=\;W„{*& ó¼‘2ª w´F°dN+ -eaDÊÉÔûÖ‘ÎWV£Õ-ø½ÔRpë;ø‚ÙOötC-…`˜=¥‡¹jt¡%îO?“i£¬˜+K~Bö &+õÈ࢔¦c‘ RI^U_E*5IIáÐß§Ì0ë,~Š•J"MØV~éç8<“Óz(l¶þ¤µâ›èϘ@~Ì‹‘‚þ ±…üÀ½ÞÇøä§Pa´©¯rŠ™Ïäï@jèÈq›öÛQ:K×»J:ÇeeܨÈÆ°Ì—  Å–Já&ëãT@jÖQmÃ;Œ|–@q¾¿P+d–䇱oËÝ•ШÐwxd°ƒ‡·¥pððˆj—“W£z¬ÁŒêÕž°C&}9bÇdë$ZgãÛ(0ÊUå•%£°ãú¢R‚¶ëGS«2Ü}V^ø8&øô_ø0$Ý_ø0Ý#½ïøÂ‡ÌÞç Þ;´Éßí…S=Ù‡ï)h3ù¾®]VÏz_.Àývf7£Ê¦ì>*Êmm¾i¿¸É´¾ÊTIXl$O³%8ñx'زœƒæq{eç­ß2„Õs|EÀézbu^QsXˆY¥ë'•“lœÛñ)Ð8"Y…¼DÑwa㡤c ÷ðºg·bA$èX*ø=ÅdÌIqߥ‚Lëdì«Tp×AÇt÷U ø[Î44>vΔËfAY™N[U‡Ë^ÔÔèÇH™ú«2¦Âæò”„À˜0•ü£'Ly™+Ý\ï­ÆsñŸ+5!W gÎ¥zŸfVKxÉ Ò°ŸÈ”dû¥ˆþëÏ“ÞsÞ{ž´gc™ÇR)ÑÃØxŸ)8xCòî=’¤¶•$}ÛÊ)¦éT6ÃJÜT`õXvÙPéE¡8}LšßMÃít¨¶°a# ý`±WF¬w{E>'9·CÜÈ·M¯9¹FŒ£[øb×Ä7D²°¸/Gî(}xb½—þ…· …6¿ùÏ"?ÆÏÖQ9î@F†­±­Ý¶q~K]‚á$Ú&É Þøx4Ü1±×Œ*Ÿ7½ NóGÈTà¼#D»ÌÅŽöù­SÍÝëUÊ/ñTåI†s´ ‹û“Àx†2øŠ¾"ßcd|ò™}È =k9'yfû­óÛƒ¡§Ú¼]û.¼Ÿs£ùF忣_hi;|Ë¿…C. ‚°~j¥õLð ›íá‡ê”Îè)ÌHVœf(âÈ¥õæ«´ ¼œÆã´›—T þ7/ÎÞèm¦½(¾;¤ ‰×¡íì'Z£_x]§³ö÷ "w›Œ%»RØC¶XV „Ø#nzm*òÏ6a<¥ôñ9×þé8wÄuái‹>ÎbgRÉßü> stream xœíÙr·1•G¾äÖ/önÊáÆÀ–UÛJ¢”cù`’É•¢xH,óÒŠ¤­*€?;ÝÌ,w¹¤óàrÙ„± »Ñ7x;c Ÿ1ü'ü=8Ûyô0löúÝ›ý þ}½óv‡û!³ðçàlöùžÆg®qF5Û;Þé&à3+Ë›Yοœí¼˜ÿuÁeã¬ró‹Å®nZÇ´š/»B醛ù>´´j`¦ùÙbW5Nh#ÃÐÖ9‰CU`Éù •¬Ñ\ÌóïÐËc4Ìuµ`“Ö‚ã´Ø+aÀ‰ïU™ùi@>;D`Lc…^€\¶ÖÍÎ+\ææiu…ó<`¿ ÍInÌÈgÌ6–‰¸ZkÃb’Ù­Ì+ÙÎß-d£ 3Ö“©ÈÛH/®eå+l"ºR5Öðù÷ Þ8É™ŠCqÖƒ<ô*C0D <”ãs™:èlœjaÇ\¿Sk;× Þ6€-vþ°÷ä&«(7í2ÏEBÌv¥h¸vílïÐs’€_ZÓç$„VAó °i0Ú~þù*rO·’†,p#ãWbM«ë¶ÓÌh“øöB,à<Ÿ›W¹y䛚i=ÿon†­-¼Ë½W¹÷“Ü|œ¼Ê½ï«Ÿå^˜W×0£è aªQÖàf’ÞøÙy»¬.ü$÷ÃêÖ4-ãóÝ!õüƒÜü!}œ{/ró27 BËÜ»Ÿ›WÕOrïÇI8]ö¦?«ÿè4÷^÷ñÍ!¾Èé:ÈVÂKi läÙô8uœ‡¾«®pU À¹å ô¾|™Fàü cmca]{êŒëÖy‘7æã¼áË*Ÿœæ^B²µ'¹÷¦:ù·\¸ã?ÉÒûŒpÚaî=©‚CÆ>™Z8î2î‡)(Kød9X {Ïsóõp2 ßãêØë<ÙYî}UÝÒežŒ€ó¾ÏøTâ2¯ÑñÍ%"©[(éT¥ˆÌð©gÑ]áÀ2ï‚îu†‰Ž…ÖÑq@f ªözþYÇn0ÿœçænÜ…½ñ3– B8€[Æ@Ÿµ³÷çQ%áJ—ýE}“pó~UÇ^:‹ƒ|6’S?ªêج`™~©Žý¬ë… ÿKF‘Œ}26¶›WDZ¸„¿>€ƒÚ´þÙ“Í>û07kc-Æ’=úÉ[²Ÿ›§¹y]H…QX•QTþLd¼\îUÕ^“{íªtjFd×W›ïúª,qsàXüµ[…J÷×÷½²è4¨nSÌ+k½ˆâÓ½owÞΔ0¢QÞ»¨ßÜ‚ò˜éV K†ÞþçÏv=ûçìjy}´óè?3¾óèïøŸÏ¿ùþ<ûrö‡§Ïf~*øÜÏÃyÀÏôópœoyÆb‰ÒûK±DÛÅÚÊÆŠÎ'{"ï&ƒë*\+‚‹§Á.ŽúÙa(¥E‰ÞßàÄ jߥ/àî^¶¦1Ivírç27 ¦CJ°vH ǹî(þþ%”k7¥Ä(ÃAPƒSnc*ÓòyW¨Ì»Æ¶k‚4²ÏO}&ñDb_í)bHÐH aÉ{ßR J®RßQj½ó-˜”l“d™°ÚÓC;»&=ÖÆƒcXj 4®ð«å­òìô€Ç*Uz0D öݤÖQúuÙÛhÕDy))­1ÓHR%* ‚Ø×Di\gEG(¯Rä}TèrÝYšð;Ú=).ùè}ÖWƒœI—z€©t#œ¦I´¬˜÷'§1Nòï$µðã"e!®ÓÐËÜyœÓˬֈ.;ëÕ@!xCñŽÙ¢ Ë~5ÍñãÂ4Ü2]äYȤ˜¼p¢aÀ {àÜÖ ¦a)K\KXšh!ù›SJ#pÁy«Íü'ÜE î°)&ù™›.UÂäpZ¿!×yo|TªaƒR‚8!g¢‘ö.;®*Ýñ¸¡öò¼‹ª‡7Uhº,Ä!–íÀ‚X·i­³t„‡½áÓN©>I:ºhõ‰‘#002—gËûšSBu"„@3­•EÅâïÐkk‰j9 ]!•U—a!Aÿ©b*`*ÉïæÏ2§£,bZT pG‘Vˆ)Š„- ²V¥ÈJ”lŒÚ ÊvÕ#™j;²áùÑMɆŸëº¯£Ú‚­RЯʔ©P¢Ñ栂 0;«dÓ‚^«† `ÏrÂÖ`ì{súsÌœ$Ïk}s2ê.)¹þTÉ4 á*yLJú¿â1IïÜx޹H>Ñeû´ÏýÆÖ~²à}ç[ËŠ›ÒG4™ó­aºÂœ,ŸFŽªºß7Qþdcô„!š’ž•-ܵ.kBB ±ÂY—`¢Öƒ‚pU=ÃÈÑ ¿šãùиò¸‘À’è••(6EÏ05æï¼%úS"^T•Åxl2n¢U}Œ£¹²ª® Y“ì/¦ ´m—#Ç:™$¨£øz­©“¤ªwªØí ÖpLöÝÇ'›àøºÆ,õC¬º¹ ^)ñî6%‚`rûm½.ñ?ó¦âþ¶;Z¿B£ÿNæ›mÏu*¤ïé´\ìrŒúî•s&‰öÀü•dIU@-žª=Bõ¨ŠÄÒ`;¬öC ­Ù&q=&ãáëz@~ØA†&†ìjŽ/~ªo=Y¿­å17Zcæ!c¿&í/s{z“ê`½_3áï ½çdìw L5î&Ü—ä>®ï¾Œ¹²e¼QwÏKëÌCùŽÒú Ã{U7=ï=ÁÓÔwÝË»y‡$=¼=D¦]CŠÄ¿>NjʒA º‹ž{¬ìGðÞÙ³ÛôÅHò¤H/Kp$ÃÄD¶âÛ'¶ ÆNàPÀÿ¬çìuhÙë Õ ÈOp^Æ×450•߀FÅÌØus£u13VnçðâbåD?D;NbvÜKeb6Z-nk(­8‚ÎR«èoHÑK­'bÍÔjÈQTùue U•Øjô}­Öì¢æ$Ť¤V#ëפh$ÇõL‘%^Ö"̓ êˆïScÄž’dLr#WÊóúœ6*ÏÀì›g]ˆ<î­i~7—gØDm:Xö$¶4›û©u•äùdêHe¥Œo Í2NPü‘ñ"ßÜÕPRS›B.Kó*Ç p[LÓ’IáÇå È @%Ç"™Óª´…—¼}eEiT£\×¥±>kÕÔWÑLuSM‰ñ H´dâ7”IéIá\ŸEF…S‡²®ÝŽ0arFTªµë(6O o0O9ù™2SßI%!z>em;”’,n §²˜ñyÚ§)ÛÒrhRÞM{O,ÏV%¦õ²æV-ó*Ù /9m›r‚xxw€Ûáï(_£æÊc¥Ô­ª¸ãgwÏqŽž©;‰Ž‘ä*$¯Û${MYlü Œs/8d2’Àø&•¢oè ¤,Úá …¶_ ÈÕ8þuæ8@yð3üª’fnþržQ<¬±Ïñb>ÛS£„ýN«êùå"M;’ …Y1ãqGvqmd0¥§vÈG0Wñìð´ç¬:.¦¿Ðÿ'«œR;]Û2Y™Ž—^6f¦qǶSêÉz®¯ÔǬ§°0å¦Ö“¸¶0|(Û),ëè]Ïs̓¥å<¯«µ)v{øLÛÍ„ -¬ß8"תŠTcǹ¶%~o™,šL»“ã÷24ŒÉ\ãv/Lp‹Ǫ‡¹+€E»bÿ\w¬Zå¡nÀ£2[¹v$aÅÚ˜$eƬ›¿Ý\ʴźÏœç½+ ÚYê{Õ /»ª;ÐY¢i•Í÷éçþÑÿˆDvÈ'™Üö+d’`¾·hyÃ8w1±Ò»=½JÝ &ã]È]M_¬»®§éEƒß‡§9qȺʵ6UF¿©Ôgþ¼Ž§I'#îÃñ8¥¸Èˆ™k-Ä2×X-vw¸†KBT]Rìfd?«‰¶¾{Ô/2«æ+•ŠZ¨]PáÅZ#U¼X["8ð‚{ú™mhns¨¹-×—ã±5©‹+Ùó`-öÌsýοwÞŽéüWu·ã´pîéxWèúϘÊ[±¾;¡Âô6ú 0{¨›6ÜÊä‰å”h¿júj´ì ŽÎãöÀžv)È_åLhñ¤Ew~ ŠD盡O©-}!òü4ßXx”ù1Õ”lÊ0•aR--s^%$—Ybë5ˆF­ÊVÖÅT‚¹†ÉJ†l²ê+@4võ5^}×G]oqv§ªÆ¬UHZå.Ž(w»»Ï!Q¢BR %DW*jÝÕ5Gï’HéØ%WåX¯S ÕSEµ‡oæ ÑîŠÛpÇ@µxÙ<Ü3Øpdvnfx–%29ޕТ½Z²a5¦¼‰R1êSOšD´„õâü…â°1äM“A'†särŒ^̈cûl3Â#ƒK ='Œ}Y³Jã†Øoü C Àà=œÒ![õlM¬jЦH‹Ž·CÓx›ÐUd¨¦©íâ±¾öIäæÃÂHß$D"Tþ1–M×ÏÈÞW{—þ`X:E~Oxx “D>'ç^CU‰b^ŸÉ÷H:#‚ ŒØ¨C î9™Žâï´w1Vx …gƒ¨@Dx™³M»Ì|éH’ó bÜLQ#©—ÉËlì5§êãTÉÙ¤¶{'–A¨ê•|9!{†ÚJYKŸMª%q‡…Cc°QÒ´j›ïƒÁùQ¯b;•ú÷ªZ#ë§û”²53Tá>¶¼‘lâ\¶ÜÆîÖhe­©+3½:§TìíúáøgÅ0Q,è™å=”ATãÕÂðr¦ ¦ÌšF Ý»øG´Eu›˜ºõ61ÿÆJ]Å([–ñ,-Ý(‚¬ÙÞ`-ÜXyóÔÍ̾.Ž4e…/EÇŸÕ_&O$Ìà{= –)«ó¼×²\H|NÀä ~ÒŒ€;¼ÏêVv¥OxfÅ>üžiE½I¢µ†ê'ûEž…n£bÙáªcž^PÕ?N×§­ò` QDËø,]C@ƒÆd=é`ºÜz]IrEDÛZÿ Û®£ æ t|J+€Qm^|Çï òÍ %‹òƒPD°-X 6È‹ —v‹Ñ_{€¤‰¾Àz£ÞíãÇt4 Ô¶¥vVù€;ÇVù72Zn7>°ÍmšÊà÷ge›Y°ãyý>=B,KÕ´ÅÓ5·òž6qòVF«mª¶Q\Ü£Eæ%):âLö=C”‘{E¥1‹¥k•UóH½ -Ù¯a"ÊÈnpý†ùÔUáÀ¡JºY¾Þüþ•—·l¦Ãóõ,ßê;óTø¨üùí~|í 0k…íÿiJt‰±jÄÉ;ÌsõBíaXÞ{_"DûÝK.Fâ°t‡¨H$¦¯B|î•b÷êtòƒ7L‹˜q@_O› Pí½ùÂñsGª©²¢Üo?7{ùÝP|En–ÝŽvülx9¦¬ÔÏÑT5iOGا1µ(mòÌkštämÁ@9AL¥ÛV-L=ïφTÚ5ÚAtµ0•”ÛYýÉ…ªš¨¦Ôò¥Mᓪ´ù§=7·G{à ¶:Ps²z¿³œZX½¡é3çZmë °‘ýp-¢Ïfát:ç”XÞ1@ÿÛÿ+«%endstream endobj 1662 0 obj 4287 endobj 1669 0 obj <> stream xœí[ë· /úqÿŠMл…w[\SÝ!µ;ÔF/þDä"ÿ‡êv Ôo¨î+*ý…¨_PÝ÷Y;¤îˆžWÞ«J×:ΩigD} Ôä]·‹U¢>ìël›˜†ºÏ鋤ª/Sa'㪾ӣAèaŠ”‹gÏ"—MÛùJéùî!,ɳ5_ÓD/©î„JŸõãLpXú’¨#K^ÃB%ò‘7Tw@%VCª».| jèmSÕÚ,PÝPWÆ4q˜ø úd“ªN¢œæºWÙ¸Pu‘ ÇD{‘ªè»ŸˆöqªzªÍPÀ Œ u÷‹Ù3ÝÐ\x•® r(QK ð_*ÕD­#SÊÅJ$[V¿@•†+Ÿ¤)™¬o¨L·7ËálõšhÍsÚR “in4ÑÃTuJÍ/SÕU*ìí,U¤ÂQ6-¨²¹ú•k0uÿØFãd"-õª·êä¾@‰$Ð|}¦¨—ê'Béõ/ÕC"ßãUQÅåÖÁ$ïѺèTUº‹hw1–>Ù3á$s|:„†ÁwRÕ³¥æ !þ:}{¯ÆCP»^mÀÇ;zµ¤ä\[¬ºu×v—Àþ×ôjwdŠüÙÖ„æƒ?.ß/ñgF€ç­§j¹R!9¹5I¯ˆ,÷dÔk`(aå"”x0!_öë‚Íå™Òº‚ì=²1#©à' û,Ý hü€JÑ*€ü{4 w÷Ì‚—ð™Ejnݺ@õÝŒa˜‘½g‹ø¨ÐáÈ 8°ƒÎáþÿÛ¿{vÀ\¾‹Üãyÿ6úßÛÞoé r}gÜGꄾÿNp¿¹{úžGÐBóèÛÍŸŠøbÁÍóôc¡%ZHUs‰ÉÍÝ1¡ßÔƒpLåˆê©ŽóÑ–¨œ¤“s³ì& ¿o£lïžQ²}¼É ±Ñþœ‰œ|°Ñ@´ý±Póã÷`‹1¹ùaÌÆÏÒßsró˜*yÏ—w(™úˆ¨;ÙXzBÔI«±_?©þ€€&8§³f€»þd×à qÛ8ÕrUWÁ4Æb>Q¨Õ}­{ ËU®rÁÁ¤k‹ö‘èWKU5^Ü Õ•±Á¶ÈÔÎîìëÙ˹ñ/+àv®Œ·•n'™oñýÑÓÙý§_ί.®f÷ÿ=W³ûŸãþùWøyúxþ‡ÙÎÓù×[Ö óV¶;UsNL^ÓÖ8]¥´Q¸‹k£<½’Gæ+ßBµÆó„ʸÐö–½»\™JgPéÄžâßxü^W~®¡ooìDæøÐï? ¤Mâ­…x•2`[Øc¨êÛï4ëJÙ81ÿœX¾&–ÙÈÎ%ó#Ó™aŸ?.}¥¼Q8yUW’T½$Ꟗ°øÆI•K†ö€z‡Ë•nu´Ãkév„¸3!Š›%À…j­…NA-|º½„®CÕ»ª®[å ̯¬mb¦nèþ…ÄWWÜ`ƒµ¸iaSð•Q´úq›ºn½’ƒ2¢³«ÑÅoZÀKâ˜{ØÐhHw(Æ ÎϨéIïD)'Ç5×ÁV¡õ㯺¶\»áÚC9ßD?ä¾Î%‡c¶‡BŒ•ËÞѶ0ÊÓY䦴2—¨`ZvÔä8øÓ¥vUíƒ^¼b–…Ø÷XÀeÝy½t Ætj[[5°œóN›¦ÃÊ~U|„‰n€½¥Ö•°Uõ„;Ø+,¶—¢>/®Û©Ttjp–V dkÌ<ÒhÜ ‹óPiQîÃÓ¼$Täu¤Ø‹X;äÛLh$ÖUÍLà¨1mg½åkNgÜö$Ó«C'lcM¥À xÃĨ\ÓÝ­2›ë¤ô6ƒ’m²ìšâjÈ{”ɳªrÆ (JUÖBŒc%5ö‡’¥9ºþÖ—¯}¨YR(¡#ÙgìñWØ´…¹4U[#¶òE’æ4â¤ÊŸzƒu¨0É^‡=¥–‡,ËSf§ê\wò=%•l5‡²ÐÔ¹•¦vìât¡J» ösôMR5ƒX›Y,.p¸Ï‹‘ø+»€PCÐÔVë-. Žq›î×Ö6QyŒÒÓÊÓ _¡-¡OF1½¢’`€ùîÂ~½)¢»‰Òä„Q0Xˆáÿˆ7u€¼èÚêNánÃfS}x£Tf¾Vt4¼ÅÊ«ÑØÝâ÷Ü«``ä8QÂè8!òÍ;úMêhÒ[‚$ ¬•Ö)¼oÀÇñÙŠû&HXãX˜;L.;tÀGoáᨈ”GE›“öv‘ï!ªhƒB¬öJ›%Xz;0ÀÚó!§¯„s-îîí -~Qd¶ 7ñèŒñhh-%[à¶·HqÝ¢ën*IÍmå2WNk–zKéŒî²EÝà†Ò¯žÎ@¦*™¿t¦ëOv+Œ[à×M J…¶òuH˜ÁÞ0ýÐ jk&"+1Djë½HJPÑ5fèNª¿AÃá ‚Wä _XPÙ5ŽAžïFÐ…áö'"×Ŧû9òD[UDí½€ÄpHÆj¥†3,DÉ_žX½‡LÀ¨f"¹9[šºÒ¦Vo+ä÷!ìTÓ§48Éëž}ÈG38ÇjÔdO%ü¹èá¶ör}Êòí;h”&<·ª‘}¡, w0íðŸË 8äƒf ö±Ð}ípéTp¸rjÛã—>»‰·ñª"§ŽÃ)LcDrs…þPÀ°$»[šÔà Ç3­÷Ò•ì³]¾.BfÙ¦éƒc sбO¿3âëVî| wFâø‚.Âl`}ÕtÛ£)b‘Î"»ÐG  Uܦ ¸y,”Í5Ô@ôZ7“±CG—Ë Y)mj\Ä(®ñåxê6B‹¼X› ½nЀ;!ùVð„2ÏP؆Ê{«"aNdð# úê·¿º-5NAÎFZÓœ®«ÖNdG1¸qZz‡ ¼C²¤ ¥p¼nt{Ì€’£HJlúï­¬-ŰAâÔ;K’ÕÖ÷y£†r|çQ¯&”‰=‘±?‘W!YBÌPúî.™©—ˆ2ÀíΡ®ûuJ˸hT¹1u9Z9³Kø±ó,žå‰ØíEq¥{EnÞ˜’¢2Õ Ø¢ÜÏ(oÛîå^—£(EÕÞ(ŠëìŒþ_”¤¼=FPé%×ÝòŽ•Q+ZX±W:‡þ?0[¬ä-y ¤BÐz¾2ºRtód©Òú\“’Ë¥7“{Ro£öÜôy$@& ÅœÆuŽrq‡9O$°Äoø‘9~JÔüÆôD%Ž„åÝé 4µç•L>èȪ ‚Êç­¯z*0Ù3…xꙨåÁl*guäŸ/àt,Lf™ ÛçùTuòXýÛÒ‘öEÖ)N”ßeìdx*¦<þö;ª¶9¼. GÓá1²Ç"š3=ë Iæ#É.øìÐ¥rž25§X}h¿K…átñB$-ŸŽ¿¤G…G Ù» n]-hx_@Ü ÀU7€LŽ÷Œ§® ¨nNôÖ_ÙùtÄÅ55_§ªìFC#Þä|Ï̤Ï^§ªóÑgcIF†ïúÔ"NfxpRTæ|í†êÊ·ø¦Ë”ºF[âçE¥Q¬b Œ?4C÷t$Ù³-4þ®¼ö>§bÆÆ_ø~ =ÊfðÒ1R‹Âý–çCM)ó°‹æ¬0ްĂ.O%jÙ”Q [ц™>÷@¦ÛZ½º¶×ÀÁ=­›ú5ˆþ-nÒôïH-T*¬¸&µ§·5ÃÛ7ä8+ o81ãa…×ø²æë\žÚñÝA.Aí­A[›¶9ºo˜wÓ4ò ~¤¥7hkšÃ5•^ÎdžÅΦdå×bþàð ™Ò®GÒö¯C1˜±@ o³Î‰q^šÒK+žBîܹTZÂtY*šÅZÂÉÜGãÆ¥ŸûJaìÙ€šâךS<Št)Yûzö?¶nDKendstream endobj 1670 0 obj 3328 endobj 1675 0 obj <> stream xœíko·±Ÿõ+®ùt*rk¾¹lÈ£­‹¶iSýÐ…¬—]K²"K‰ ôÇwÈåcȽ½=Ÿ…~(D‡å.93œ÷ éW¬ã+æÿ‹ÏnŽž}' []½;‚ÿý¸Rª—ƒÕõ++lÇú•qRu¦÷|ùâèÙ‹?­î/ŽžýcÅžýÞÿïË¿|^|½úÅÑ7/VõSÁça.̾7N¸®_2[ýîèÇ# ^Å?g7«/O<äV­\çŒ0jury4àÄW¶ï,wnezXsursôÏõ·Ç€š‰õÝ1‡_®ëÿPhgÜúõ1ƒy´|ýöx£Dçäú6½úÃÉ޾99aÅ{åò,Ek!JÜñŽ)ŒÑ×ÇÖçŒÔë‹ã ïŒÑܬßËNfìúlx(ûá§‘=F4Br¦"! ×rLǹá_"„ÌzìAˆI–ë9÷1•ò-…*¡'Tá^ÛÛ… Ml³6Õ6³®×-óZÖI1ìõËc€Fj­ÖÂ/Õsسôì"ÿz~Á¤h›$+ä€ Ô=†Ýú”xpXš ‡ üÛ9@A°:ñD€ Þ)Uz6D =û)ÿºÈ£÷;À/JT*xÖcev3Àm¼Ês]øqÖi.,§ƒ ÓqË4ÇÄB“v0•99Þ€jr §q©Dã°–È+ø®Ë טF¼ïx¯Íúg¿–±ÞT¤=O”QÀ£þ]güºlÈãh›‡½ñL+´çÖ“sàô1¢¥Z‰&Zó¸¤tx»Ón:î_H ±´G¶Bà ÊíðÔ0íAÚx˜ÀÐ P!Î æN;¥ðœË÷¬¦b'+Z¾°va¬²™ŽmzD(/æF÷YÚ΃*°é“‹øh˜lBpÊ ÕTÀH’¯­_îöòúœÃ6x‚ôB€ sK®Á9ÆäQÖS}œ8 ¬­sƒ8ÆäÄ´Xø±¦’¶“Rà¯îË$9P³ùçþ©ìz³k° Ý–W„ð®*O½ÒèœÒÚN™ìm-7!“.’V½·¸íàkÀ]=‘‹Üï¢;ü6;A—™õ.Ǩ8KÞdo5Ô•s0”f 5Bçc µ·ÉÀ³µ¡öŠÂˆ¥†:²?R·„fÄÖ{Ò¢FA!-ê‡ü°’ïæÍ$ÓÞÞh5±~‰Ð8-¾õ qMås ñÀYѺ,U”. Ÿœ_¥™fçå¬6)ÐJ&bWü@¡í ¬ྑX/Ï×ùÙiþõåùõ6}VƆ匌 ÿŽD¼rc„ÂóŠko‹)Ãbíaæ¢Ç.oaÊÊ#© ¤mÌa OIGöõ1øìLYÄ7Ä€3‚ýäFÁŒ÷°#ô¬XB´ŠV H/¡.Ha¾MލMJR9 ràkgg«h.çIÑ”lyfƒJGgŸÌÖBø'ÔÀ¹7Yú Ù,‰‰×Y6ïš÷ü¯2Z$üÛd– eÉç"UÒ~¹²jÎgå`‡TýmQ§¤æ#­L¦3¶î9nkJà`:£…pòÞ¦”LõÈ ¾&#äÜQ¯~<;Vß6V ˓ؾlÝñ”Ätæ5tI5ó"+NbJ+‹& à ³!„ß/áA}E3“•ÞQxdîÞÈÙˆÌ  ÁÝÖFæ.2hmämk‹nem Ü)ÅÚ´–ïXPm.¡ <ÏW †A¯7e¼ÊWçüÁ%™ØA)ŠŸ9‡ˆ~Ñ)Œ´•FOä*3ë‚ pNsî&/1¤- fW>sÁ»Þ:;âeñçQâþ>:éà|¼çž,ì‚Pr¹ê™4oL/ŸŠò<™–Oåyj¿9uª½ø“WéÙ¬y0ˆ·ëï í_r gϸxÀu²7^ ¶:`§1„³ªöåò…?‘™¸*^ÙEåÍ"ñ5v|}æêûuAñœ2—Ƕ³¶qû˜^“îä÷ÇyÚYpùöNɈvRïí"yØÂ´Íþ2Ò·+0Þ5!&„ x=vòæ„èp(ÍBçHŽ®qÐE1,šìºrSBÜ(½§¤í–£Øc&¥À—x`)4臅¹Žý¥\,À>°Í»†ãKS$ÃÿºÍRpµ³ ¥)@èà–‚Óâ™4ܹ qQâ^kèô[$:û€õu¦qkRïžlZ¨³ni‚KJªÑS)ƒÁñ³z®,ÎJÚr˜”4ðš÷î€À’f`ú'ê€ÐC,°æ+"ø~W·ìp@ÏÈø+NƒT˜ºŸÈ«N-š,™›ž @C€ýѱÀLÑ‚NK2™GoMf[$K Ö1çO‹!Î1@P'TÀ‚#·±‘WD¶±F¨³ ³²»œç&eDå¥9íùó‰Ò…ZY`P\®e÷lgÙ=Ð3²‹þ¿ì>ìî&’á+ÚH_ïnN—³Ò¤H*ÅQ\ÓJê'KqÀR¢-–Ÿ£·Y‰<Ì3Yàý¿@>@’QoÌÖp9ÏLŠžäË{^(Ñ“\×Ps»Õù!¬[ËüH8Kµ·Ui§\ú@/ J>æ6MdhÕÞÆÆšÏ9YPAu˜º¶U…,góIÂÝò.¢þ®yÿd­1öVÅ Óž97ø>3ò ˆÐlÊ/,UlÚ œj´77HM¦"8Ú§DÖãz÷n{Ú–³3í¸ ¢­×þDÍþ¡òû6—PäîPº+\„âjÓ½ç¯)ê£æ7ÚeÝ«çtá)ŽÝªè{h™)#¥œZ>a¤`óT~®êMî ¹ËémÖÛm½dÖHÁ„ŸüÀÝ`¤0èàËlh.$jVõ’oé[ëýx©}kÆ›üíûÖ,oÛ¹oíp<¶Ý¸bàv1®=ˆ-·‡0®Á×õ碇¯8îÌ™R/Ysî°’NçxrE7>Uö½JtŸzw wMï®1!‚©­°q2ª¸¢ð¬”·_GZÕ¬û½ÎàÄîŒÔPµMBW¿Límª3H üÉeR: Ÿ_\†®Ï±xæÆ;k£pò*WwsÑBö¼lÜwg¼)ŽþÅlÛÚËÆ]TqšÐ¶ã½iÜ’ªÅ „L¡Ãy¨»íCù9#ž¸œ ¿S«œŽ sO½‰‘ýwÿ¦˜Që®t5•ùïÈðÊ¡)Þbn}…Ä œA%]ßRÄi”iúRR+¼p˜ª>²y÷5¹CE!íîía & þ{ßH]zÝ ëÍü¹A&Ü6пÚ#‘©öêlYöŒeE ÿq8©¬l檡 d8C"¶´wGýÇR÷Þø|S@?+|—ÇKÖWÞA­úr„RͦÃÓ12Éd½'uOqÂ$ÑtØØ¿Z™$Þ æÔ/çÛæwÈ5¦:Cë礦gbÅç3¨¶=ÃÙâ& R|Ò³d´-è0ø²CçÖSçÆëãZÇ®U:7[¯˜ÑTÜÆcãÔlœFéÞØyíÙ‰mÉö(µRq?k%¼ªª›®k>š·FJXÇK´J¸XGA3ãcÈ:z¦“KÁÙÓC}*:ƒ$î”iXœ<²‚!€'Úóѯ A7 NhœEöuÔ¶¹²mH2­?*—ýj—üꀂˆY†’׈®(g>Míȹ“g¼/%8_ÿHzcˆHˆÊoR!@N¤e.ɧ÷áh tvt aÀ°ÎÕ Y¸-.ÛX]6ùŒK0²ì,7d“NTK{§Þ%VŠ¿D°‡ßäb×ûBÓaçXH¸1]È3%0â=OܹÂùú쉄¸Ò ºZXaÇ·Îl £¸ÿ¿F­@§€J¬‰a€#ŸoòðóáÕgô¿ÒŒÀ$2…:"Úô(ÿ`yì×éQþNå1V¿~lŒ¦€¤YµwO¼MnÓ‡Æ £Ç2Ÿ¥ÿ¡€Øðšå/déÓ3Sž}™žõyºÿ”¥<Hã÷!« ßämýþ{)n¤báµlضßXÔb=5úë<úY`ÁÜ&²‡K]ÊpÆsËÃ@$ùø£ œ¯)eŸwõNUgÚò.žÕ¡uµ /ùæçñ:yúWã±¼N3©K³Šz·²®ýãÑɯp ìÃ8ˆ þWý7‘Ô»AÂ]ãé©<úyÙªBwQ Gá¾'`¸® ] Éëôè§1Åý´R€jsmö£úòª–ÁDCih(ö'5úŽ!ßó »ÈÔŽ”ü¢G|01VuŸ%y?&ᾤŸ`BOºý+ýÏòhÉu—ÅO ÒÇýV%Ê‹&*¬uCN3|,T+áåÃæ½-º4&‚Î¥ïx€aÍb?É€ØYþ$£HfE7¦‡Õ˜ðé*â\?ØÎx3›E_o߯:³VwUÚ™º­qê\}õ!Í)0aÿ©Vœ«¸T—©Ÿ ~Oˆù=!½miáõ‰„“öÇõñšoPPžÂ<”:j&Zj\H.1»òëà Â<éëáuµ—»%†S¶ÙI`°ÙkÖPœ/HXhFÛ7YðëÍd/™öT«îA£ûWé ¼éj Ôtxòº„*‡6P[Lí«QóWÓÐ}[“3ß Ó÷ç~­“KÑÊ6;]¯Hj¢î‡Í¶ŽŸ6¢óJt¾ì<&fæŽdÞc¼–‡ Ö2•ò·@Ï+ëÃfïý +‰¶ÍºÞ<ÊZ¶=í(ïûoÐL‡J%ÓÞ®c+ÁD>YømôЄê1SÛª„3íZK×PážÙ~1º»ñâ;fN¦â0÷>&ìÓß8âcˆG1ðO˜8>àWÉ`-ëû6o@ Äóq8}¢1²€¿Ë¼jõHeâ3ÒÊ¢fõ|R2 ;7dIxA°Ã]ç>º³à¦d&§ïlK ,J5ðÌS§å6¤da_kûúfYª…:âuº']ùÛèVãëÍж¦DeöéK‰†NÔÄ% ]®×c; ºp1PªÐZß]Lå(HmÏÈ# \li´AJ’‡{E¬}"`?M> stream xœí]Y·Îó¾ä/ ü4dZ¼ÙL>äXAœ8Š’}qôìÅW‹û»‡³£gÿYУg_Úÿ}úõgðçÅç‹ß=±ø‡m ^wíPF Ñ)h‡Õ±9íÅŸ¾?¢Nê…ÿsrµøô••\‹…éŒbJ,^ }¢ Ýwð£ƒ'WGß,ÿ¾‚î& [Þ®(\™ž-ïíM&2Ë‹†¤dty³ZË®ïáËëðÓÿ¾úËÑóWG£nÑžr§ŸÙýšÙ'ÚëNˆ¬KŸ¯Ö¤SÆ(.—g«5í”’T-߯x'Qzy2ÜT¼_Þ¥KÔS§ N‰ðšPTò±& ¥rЄýiK’j ZÛEM£#:½§¦¤Þ‹ýÉgŠÔg©²q&]/ óU ÈÞõ›HÃ¥ËGw%z cîÅ«÷î EÃÄIR  ´zPFó™ú˜ÝJt§UÖû(üÍ” ´ÖŒ"(£[XГ± pï‡xuŸÞãW“NcoÆÈÝà4pÇþ†œÆCrtWƒ{ä´S‹ ÷^…ÃÀ0Î;ÊYð½^žÃM°'ª˜ËÞ|Lïß'Wr–Ð{Û”î8gþœhçk˜Pî ¸¥ÐÖEz~’dùÎÿÔ˜ÐøémºyžœÙ÷ð¤ÇÎìjèŒVKð.¶ufÛbX–ãÔƒLÕQHŠ••ô–óM åâ”á󛪸8ží .@";˼‰NìæÉ‚œmÙæ|oӜѠ³‰kmÚå‘C±Mê0S, $ùvSžqǽ =ᵑÀ_ǵ©:` ¦ãà'O'˜×±Ïmi‘“¸Ø@2Hd°o=aÕb‡üß*¯åsÌ,_/SO±{N¡0Dpºà{õØyú׫Øì$÷›?ÂM¤=¿©RÈÓ¯ü¤H|~°»Ë Pî+ÔïrLî&a´·m†êÍ/E—8Öª™+j,wüa:Ùg[¦nçO ÒÈùMU∗͡–›e¯`Ô³9f~R[$l÷'ô„™#§2 S‹Ÿ£ègÐQ Ÿ6Ëç)‡ú,5ð2>Oèú̲*RõK–&†ê¢²âÛdÅux‰O—cMH½ÉšbŒv¤µÀ3ša $çd1H…ˆeu1)äJ6侃²g„FëªZX§e®TÛt‘ÿ Ö)¸l­uB*öÑÂŽ»´¼B[k8>yÞ U$c]YÍ^8Œ÷óôš³M ÒËøÜÙ XHï Äz.kæ3Lgf½ ‘ƒZõZŽ?¤ÝX¾,&‚ºÃQýFúºX-<¯M`aµ´nsÈPÃD¤zû¶j~jRÞÛ ’û„ªW@^9W…tAäïâM¾ô¤JÊpø²ƒ#mNHÖ=2©‰Fç×jÕ’˜Œ¬ÀJ§´Ï ¹úT’aï½›«ˆáö·¯È :{qÏå‚‚m]±¿‘™ð0H¸—5ó€ó,(±émïÒà„9(%,nZ /Õl'²(á…h'TÚŸfá¬3ä„~€3ô%$3KDŒç)ò-/ƒ‚T‘˜TsyövLèózdŒÚ ±Ö£AÑ~ >%*€ˆ•Z{8PgY%‡ÖÁ Àû©¶‘KðB®uøö›pñ庯ËÕ‚ïlàn%?‘}=¤ªÑ"WY ‚R¾+):ðª(i ¬Ï°¬ÞÞ™iw JBb™géÏ>¤‡1â<j~ºGp‹qêìõ1¥¾F¾À—Ioê4S¬”Šm3ìL“ì¥ZRlòÛ½-5­ˆ­>ÝK›$Áïm_8³ÃÄÐbÂè}Í1ÝÞl!To “ÊÞh{÷»¸çÛºnIܱŞæÅðŦhRÙï;­D?l¦ðÉÝw±)ÔÀIÊø¾ʃ ·³~øéxù’Øå•ðø×ê+BÐfk;­Q®(C(C÷”ínìS7Æ.ÊâA{ÓÂó\ô]hsúqɉcq7ï€F¡9÷C©²·ý8}*)¯ºG"…%U@½¶¯HÇ%8çf>ñ €LL:àÊ¢Ã.ñÍÙÌÝÜÂÍ\š ZìŸ:EL‰,d/ÓÂÙ>L´ :1Û2ò3@‹3Â4,YöÑ´ô‰vRæc逬dd„” »Z *ÆŠu.Æ`T5XYf£Y¸ !53¬É>íØ×ÊÞ c‹a-E–¨Ùj¼ŠjjÎö:ËEgï¾(©kØ&æ‚g#Z»¼œêekµµû|³×¦Ê71‹F“x]Ý~ÐI üCòaçg€¿i°ZêAaõ‹êàňɂ”T˜¶0:mBE•¯u™Dc’ØÜ-6|XáOlZ’÷ÇY†gÞ­Bø"픳Î/“-&æ4±…ª‘‹±Mꯔ^VÅLÓiØŒ£F~ÜZýÅe6®Á Œk)†óV†¹_ªbî/ýHs÷â$åîõœÅÌù›èS+^G$• „Q2L œ=yq£áSQö Ÿ@ÒÄ µŸ?²’þ“pë~+Ö+©›<Ð÷ž¦=2>ƒÍ"ß 08;Z¯™Þ2 õ‡jòÏnˆPc¶m…ÚÃú3´³¯¥ÜÍg4 ›Š!5”¼ÁCäÖ…§°š#ÍW›»`Fe5²qÈMtÁé ‡2JÉEÚ’ßS‘}ñYæÞ6çÑ•Mžá—ŠÐ#ß&½ù§rÂÜЙÎâ#üêyžó(}:8ç}Ñ7<Ënž@ÁóP–}é÷£„b{¶—ƒFÒ˧£ôŸß*‹ft_u4e8LÇ%vÍu¡ê¢]jâ(Ð:1’³íÄîÕàvÛPã—‹](2{vF}£;oÆ-ÈšßTÅB;+6å}Ê3?,=cÌ {ß?ù>?JhI^óhï‹>láÑ¡wïÑðOëÐЇfû3ôîü=Ç›0·ƒ¢›˜ëÅü¦j˜ëÅÁ O¹–s¸œV8ÕÒ‰þ¿béÞîU1Ûmƒºh> Iÿa°ÛhÝó;Ô´nÍæ7U³nMVšÉ‡jR§äTv’šÊ5kgý$ÿr\(~ÓY?Á”ÐÍ`J¨—OhJó;Ô4%»;ö‰×#9§qgâóU¨wù)Åò>&2óî\Åv`Ïu¶‰Ìêtg§Yê¯G¯~÷MØÀ&¹Á‰È"…ê³–e.Þ‰5>õNˆF†4n‹£xy&[Æ,·“ÊÃÖ)5¤ËÃÞÉQÚΊrW[‘EÏß´,“µ¢<ŠÎ§/þPÔ¼°¢JA.ÖÌæ±Cû·QcÕQ±—$-K¤Ú'$Rq¸‹Ëòq†?ž­áÓáY Û“·È‘Šö‡E,HV#~œZÇYó(HUûש¥P¨9ï^”Áߢ ª²ÇýõG‡‘Æ&½‘¬ÃÀ®©=_¼ýÏl õUË[”Þà Kвm~<~¹VàwVàZû@+ µ‚öÎugéÆ>›B†ü¸¬»OäFMáU ž}ö&Ž(ª]Éϳ¥Œ¦Á QŠea¿Æ¬àg> stream xœÅ=i7rAòm~ÅCÀïšVó&í…õZÎ*ðµ¶² à]Òh®•4ÍayŒýû=þÁ©bó(ýŽ9²Zd7Y,Ö]E¾÷‹q`‹ÿ ¼Ý{ü×ãâøro\üü9Þ{¿Çü+‹ð×ÁÛÅÏð5#npšk¹xv´7 À†/ ‡ßîý´|²’ƒâÒéå/«}5XëœX¾ðnTrùvÅàIºå9<8ÁF¹|³aX¥8[®öÙ µbú¯ÏþæTº˜s¬ Ó:>p;²…¶jÐvšûÌm…R8d|:ôO0ÀòÂ?IË–W«}Í,|O±í ½wz _þ[ê~’ºÿ'µ=ëôþÚ¾MO¿O½_§¶çÕ{Øû„Œ¼¯5øÈÚŒYž¥ÞèË£]îÇÞϧ6i#ÐÐöÇôÅw±é›øð¤‚š¾mûÁénÉc/Ë3ýeߦO.cÓq|ø4õýklú*>d~ÃJ3ÀŠ¿ß¥ÎòûÓänùr…"””µ@Ï^¼K_\—hc@„±é0¬Šì^•øþa¹8x8oÞN+ú,Œ©+ à¾ÒC¸ÏøãQ‚ñMÚù ÷‡ôôiêÍDšß{žz/SÛazºH½?¯í}Ôé½ìÌ›ÐôrµïÁzh;%Ÿb/S°‰'Ù±÷UîEl5Åó®äµ5h>\Ó×!¯õTlöEh€áÏZh€ 5ÆÃö{‰âÂþz=…rN)ô›Ò+h4Hâ‹–+~nF¥_ÆÝX‘ݘÔ9섽[©sÍÍ '*P[£˜[«}PÓ¹TÝÖð®µÊ/N Ê)Tý±Ä¤æž|e«,õ°4£ŸËAè üzïÙ¿ÿ„ò_ Ü)á@Â$ó:—@\Z®xÌ8ri—?& ã[lÕÎi¡b>8©”We\êÁ8ƒÂ‰ŒlØòÚ2^‘ô^8õ’;ç~0‹œ¼ÏA©Ð¬ˆ3ƒç:·§¯ÈPq=áAkšÕ1¦â»ÖP°ýÄCµ·Ï•‚µ^}1½ª…¥£¾^é™Q¸Â¡ÌàÈJ/—j`zft¼*®ÜhþÄh"þüc‹?aHã6ŠqYN…Ä•¤dQÜî´¦4ÿ#œ¨rdq|á¬À¯'/µ:`ç§×ù#Ä¿0ƒWÐL‰ ƒ¸,àfP%ÌGÁ'H;ÍäC°z]Îäw$|å)‚Žõ¦¦Zÿx_Øj\‹L†Ÿ MƒÆmK—þ‘LA>;¦Sàh¤Ö̱^p¥ÃèSÂÙi§¿Á—@"¯³·AVÚ²ª]Ë•žë`M‚kÜ–¸?øy·ŒàÊ¿p–¶õÇbÞ ‚ãE~„WP,ôeÁâøŠˆ夤„ HèN‰Tu´®¢aßêìò“Lƒ/¨@¬ÚÐ]ai1Ÿ Xn@iž ÷<¿Ùà¥åg0†Q¯á¬€ Â'TœÅ!ã*Ïç -“h0à2FÉP!Ð#¥Ï̵\öÝ]@p¯… ,äeOò½ëAG ©v 1¥Ð0›tšÕ“«€õ$r…ãÀ›l¥Ä :´pv €}A¹¤ X6Þ¡ôHOz`ãWÊÒm=É/àf 3›RP™Á rê¸+:Èff!qÖ¥¡$ãׯãá lJÉU’™ÎPÎêëÙsú‹qP¢åœÏ`M²X‚K”2êØ°µZÌ ø±ˆiBÞ¨)%Š%ÿ™wK“9ÁjÜñq,èèuÏDhM#l š‡GÃ/[‹šr5Ñh×QÅÏJ¹,ûËy%÷ç-B­ñµÝ-B ÿݽ~¿jC¿Ï¤óÙh}ôÔMÆ|Õ’‹sCuŒH‚^²m„ûZÛ 2ƒJÛ`‚@¶¶å<5l–H¤Le >ÅA#q°®¡š¥,µ•ü(™‹¢¿¯¤*KY3`QS±U^B| ù°Ë3op9Œ\Ï ‘í»9Ùè)ØÐƾ}`K ¬›·ø¨G5C ÕNã`¬ØT2ØyÁ«FÅèÄ[’…ûþ3JÎçÉ"‚Ž PÊÁzš΀eƒ(5[ü~Ò^»‚{— Äu¬-+1ITh*j*mt#kûŽ›Ñ›r¤uR“Dâq‹¨“°;ÙÔ Cu Mêf¶1v0·iÁó^rmIRoèÔ¬ÑæÉ¤4ú²ÌZg&YñUtA…\5f²iɤ™Õ7ˆ“‹`(ŽàIt\È~8àU NÅÑMÜtß„þ á!=qÀ’þ²•ƒ¨ÝÀ…'¯¸º~`œ÷œG¸)¨P+ueÝù)$£à–b'‚{Ôm%ïö?‹n4ÀPø–Ññ#à—€¡„-NèyÏoã^õ$I° ýÎ&A@<Ű9£JÚV^È®×yÃûUPˆ„£J®cvRóÐTÉóˆ$;ê;}•TŠý¯bJ¶*Ûñ;óg’¥×$;(‡ø¾ZqЭV;*¦/¦)$M ’¤âU4…¶ÍJZX×YÃËôt–¢¾¬Š'cÛO©íez:íĉ/;Qä‹ê‹œÔÀÞã*Á““>S2LJ›Gc»Ùœ£)Áb\¥—£9ýò×Î y¢Ö ˆSˆº“™HY‹»šRÓ ´Ø]ù÷r¯ŠÔÕ›rHº‚ÓrÚâ³ç)ç&F]f…ɲð'Ïöþ´÷~!Áó²ˆ]n†Ñ.$ˆnbXñÅÓ½ÇO¿Y\]\î=þïÛ{üGüßßÿþzúåâŸöž<]ø;ÃøãH,J€q0·Ë8;Ö^Xï/¤YÍ'qö]ÌÀç¾Ä;R9ªs:"¼JqC—ÄG…‘—‡_ghAKú²ïnM*Óø… ؉bçb“«l"ÎyáÕ9L(Én‹‰r“ÕÒ} $0}wº•BìHÿ3{<¯‰é 5mòˤ|³b¼ê¨æU)ÙG1fœ1´ªp±BÉ‘¶óbÁ‚Å©´ÖZC–‰ëZGbo_£‡Þ<{oûYegkžë›aØ«n´å ë`¥ “£Aš³•{ùƘ%ù&š·Š7á"ßO ÊZ?NY@BòÑ@o,a’ ›ÏÑ®K…Å@"Þïëú×Eô_F®q‹Cäù5õðs†ÂÇÑEâBTªyå[•~oòÎ|¤PÏ8}o'|w ¡±ÈTÑò‰äßÄ”°ƒ؈±yj ëøÔ›®€'è&“5AÅzMéЬÕ»sÞŒhl÷"DX%g“p£»¾…pªÑ¡0ôU’àµ_mYú¿i%✇f÷d’¬‘àŒ¶XÏGáÓ¾%)~o·AŠ“EÞ ÊÄð!ºmYò5ÅØ8Ë~>ÙÈlÊè P9£óŸÕÌ…è°wOqF,D’÷-›§„©ØF" RÊÔ‰bDŠ-rÎUtÔŽ#“D”¡5¡„Qõs³e4kàL† Æ‘“([_žÕبÓ1V #'9NJ^¦"4:Z17X¦ølĆsjªùÐÜ ¨¦žï´d<¬4±:æ,Ó¹f«=‹‡sè•ÏV<ÏÕ˜‚tšeÓ»»e`²òåÄë=£­›µÄ‡0¸PÔ #¬û*{§UxLR ñƒ”ùÆYEAgqVVÝÛ”ùJ=buÇvlå±fî k„;»5Hè¹#°”+I ±*Œ²5ˆî€d§~‘êpLªE½ßÂyð<5Œ®:Žßoí¤"åa©XºÅkýà™åŸ“Œ©ŠÄÃA¨Y£#ä(n/݃KY†l¦C[nsÍ\SØI£ ¸ 渑E"ÕtWI£n¦i½Ï9ÙÔÑç¼…M=ãsJ½»óÚ÷9¥Ví%ŸSX`»º€+—cå|qöHsfáºòÒvò9ƒ—ñà>'YaÎälÂQµÖÒ#½ÚÉç$Síìs’oÆç$ìâsÞ1nð9 xÛ¨/ hcõ¡1̹Yq(ž#Q3¬îQ‚öìSY”‰£XÁ¨Š˜«ÏsK£¯M40ØŸR0YI^íGwQ®j𑸙_ ‚ÂxD¥®…쟿˒ô¬‹é2Y#ÁT–®P̵Á|ÞÖ› R`AuŒ¡ë­î¨Wý h“»ùÕ ü?gDá,^d º¹íþéólÁ¾ÉN*±%›~RðŽd©–þƒtÖͦT™¤“Ρ–Ðõ¡Åõy|0¼¤5 ,X¥™ŒfŠÜ`ÿÑÜ!wip£ëŸ_-qWpË“ïbÀ/èlØ65¶°êŒ¶þÁj¶¯¨Þb*Kâ=¨7¡Ÿ‹èõWnÔËLy€u"¢Ý¸](˜„,ž¸]8#d¥ÓÞų¶Y®Ï'æµÌ[0¢!@}¿Ê¹§EêóŠ/ ~&+ $å÷ UE¹E9u{ÁÍ\€Eq<Û€“>¸ñ©R],¯* -ª·/›%¤Uu/ôHêÓÂγ4qŽà+íü±Àw=‘3Ú¦ %ÞálQbrÌ7‚O%Ô¼îÅ 4ªo«Fcu@÷Ö‡>‹–i*mŒ?¤M‰Og¶aŒ 9sY×fÀBYæå×]†Òë”®/Î=Í:©Ègrø\8[zÐ4› F‘¿û¥tDÛ 3¸${׳úñŒ‘ýøhv:T²ÁÛÝØì;cÜY}ë ^åˆ3#‰Uæ…¼ìB­vNñeoãË®ZNå`2ÜìŒq7>x¥2:ct…ìŒÑ©vuÆè·âŒÑ Ö:c-Fgìþˆq½3FÁÛÆS`V Tzc \:©å¬ÀW`ühaf²…ýz®âü;Êix)wHì[+Åôà¬ÝÊSÅåõBWû ÿ@ð½«Pû×Å%5£…ˆÜîF.½ î@(KR¿ò(DbýéÖE[‚|1ሠïfÕ·7dÆÖ¨Ž÷)¨f8@1>” ð·®íÐÏïlýr0:J‘_˜€sÇ·òa zll[ë—ûàÒ~²~éòÆúµÓ‚ò4sæo •Ï™¿S~Þ=˜ùËGãÝåM¡ú[J®é¹³ pW¶)5`›#ýÀ³ÕåeHñ`Fy’·ËDéOÇ¡;AŽFlÍeÇÂÕq Ÿ”`ËMµ·Åy“) Ö¡ÉÉõ[ÅIæ‹™¬Lv`Q'`”Fw-z‰ßuËß÷vºK†e=¡÷6¤¤J—,‡d^N{×FŽE–²©+­³KX[ ø†Ì»|Öøâïuz/H+Ÿw¿@ñ‘ ÎQWw“Çߊàža•Ü”ô¯<ËwÏ^ONèÃPÓ†R²ÉzPú9À°É€ÀÆÛª%ÓÍâŸDY›¯ŒM¢ù¬U3‡kúÚ‹qÚ1ß•/Å[Xýág¹ìÜœ&bñ!_A›NkŸ¶Ð\–MÅ)ùÓfõÒî9x<ö/µõ‰ûi±éR€tæþQ¾À¶ÒìéSæ Xj¨çûÆÃæñX>*WcÕCƒçcl‹$±V×bh-0BJXràðâ±9j²ŸC¡‡?¸–qWÈÅcxNïPuÑ¿FívEÓÝ{W»e^›"­‚ÿÿ ¼LŽe ¼Ü±œ ¼{_éÂÙŸIÀšGÆï÷gò½4Û^}Â`¡¦Éœoûƒ 9nð*½G~0!ß›bÇŸ+`³½áã|ý6ù5ƒú›éÞïôIÔêÔËrï­ à»R”m¾Y$4‘ÛD&ie˜L¡-ÿ"Dú†ïÃêÁÿºu%Ö_6R«°xE¸åÅë¼®­¯W/+Ø{ÞÔgËðÖE5^yN]ÕŸ5W‘ª—]^‡“”ÌIÐNBç½ÓkcÙTô= ¸Ö÷˜®éèàm½ÄtWLõ³Ô[\Õ¾ÈÞÝãOœ|t޵ygîþC"¿?¦¾ô3&,ü¢¨ÞÚ Ø5B‘x+ývIfŠÊR4ä÷ îðûÞ*Òh$C«1À±êæ ×NFÕo2ÈÑWQ߃U€©ïÁÊ¤Ëø}Œ{ë{°Ö¸öü×þDI÷¬x‘”jìÜ;D°>†@X÷Û ÃŒwúí‘»á`ÅñéOüa¿ÐšüŠÃì6(¼œwÓ6{HÇÂ94„þL®Âû `÷_>ä/3ø;-,½KoÇ_fÀC,²¸0ºoºŸU1›¹×ƒ¾yÀKwq 3çn? ‡i—_¬âaªì®ôKoIx†¸+ïó»ÙA2™'œ\Ëž^ˆôdó×25÷2°ýqÅù¨×Ÿ‰3÷$çö3P< 0VOÕøä›&ÿ¦K:=}šî$%…%áH4ws?Á@â#ïr˜ó"·ö ¿$øBxQï“|Æ©œ¼(B0Ññø“ 6Ý í'îÿFC·;žã2õÙ‹2ôã=ûa«“ïü_äjnr%áâþ=»g=Ö$Â! EØ¿$¸É÷ÇñF цDçgá¢nu øoyÚx~Œˆ/Ûk?ñ£t)0¶–Ãv Š>ý£Å 34ïÇ(ŠóÜñ¤X¹\Î1rbúÑ„þ¯¸¤ƒm çü2+Ê> stream xœí[Y[·.7ýŠ›<]ÑîKäÁ“i2EÛ8ñÀ}¨‹b<;2#˳9þ÷=‡ä%Ï•(ÍRÉ. !H†árHžåãwÈ«÷ ëxÃðŸô÷èj´ó›0¬9»±æ'ø÷lô~ÄC—&ý9ºj^„n¢ª³ÎòæàtðƉN4–‰Î4W£µj<áó^¹ü5 ã ©ó̇aúéŽÆ¡ÿ1ôÿz,cGmAœè<ç:Èç‘Þ5“AïŒ'ÐEJãÛ_ÆRuÊhß`¥bšûv‹Üxfß;ý:zß(%-L‹ë¨Î5NñŽ9X4¬K8T‹ýÑÎþß›Û뻓ÑÎ?>Úùÿóâå.üÙÿ±ùÓho¿ ¢`xÃ5+r˜éÌ“ä,U1o|ç0ŠªØ³ÆxÖY5 Û•ðZúö| êq mÙ^ŒAÉFkÁÛPìXjÓÎJ‡ËÒá®ÔžÅ¢³I€Þ´S¦6íZÓÍM{XŠÓû÷èì!^Šy;áEÇ„i_9ÄgŠ”~F%µoڲ߻<¾Ì}WtXf¿,Z žö±·¹' #‹ªÕž¹Þi|+J3)¾—®]@¥µ¥QNCS «Ÿ›ËàÂ8 .½–0·ªæßFÛGÿ2ò€.©‹i…êB}+(^f•GôÍ·Ñp¬GT3˜‡uN÷ˆ ío „€Pq£1lVjsŸK7¡ÚïBI9Þ~ŸëÞåºY.ÝæÖ‹\WúMsë¹îÏ}‰Ú’+V `Á-ÐÜð'€8…` G¡/€c»'âþ é ì½o N ý šÆ Í( ‚Nx'’½´#/†¾x”ºVý¶¾Ž}7¿'® @tK?Ž'¬3‚^S/@AûºÉNç5ž»JTË¡œy®q—x“k¤ž AýÖ$ìÆeÇe¯–#Cï»Ú«‰.2LsЈ8Ì¥ËJèçÒ$·žÌÁÁ6®sÝÇ0 “ÝmšYBÁ’û­ü-²0eõSRü½{B¦\{štE2È/¸œcYw)û˜ ‡ët,µ&àà ŒÉ%§0sœNa2. F‰!VC²‡qÔ„í®$j‰ØÂ>_qV·6à\v†÷ü5³Ï –0¯óBHT'm¸u¡Á&à8Æ2@f0ÐnÁ‚{[IÕ)JÅ´Bй 7›c=óܬÐß³d"áèJÎ#ƒÿ㙈æ'²Íâþ3‰¯âöîs‰ "Dé«€š†#Ç .`-*UMD©§o¡k4›ä‚Š*E\æ$­sÂñpN–» ±§…‚\à5Aù½âó“ìÇ¢ø1«UVפ8 Ë•²ø‹Ï•&—÷Iˆnå†%^Þ-­¹¾}›‡kb»è’¼ÎAë¾»˜Œ$3H£;À>‡qv‰™Híiµ¶Þ·8ñMh—Öcý âÆíò§Ww‰_2~IŽ;0å~1¸mŽ´›œÛ#HÎýš„ô+èêACF·¼H-ŒÖ>ØAƒ0YšÔ CÛcÑ0|9, A\ØÛjž¹€Á°C¢«AJµ*шgPfO?ƒê„A+6ËOá “¾c‰øïåXÿ£¨‹d9Ó˜ålñr!82óƒÐPM?4š «˜çX:©°`ŠPϸİî(÷›¥V+’ÀaÖÇa°[¾´5 žäæâå%F’%B‹P `¬r+ë«x Ž øœ*¯r¿›¾ê¬/”|뛾j·/¼ÎmlF P¬o÷ûÖy’fmZ8.sÛE_uÜÊ–O†¢¬%ª¾î«>ö…oH&71p.s£Ú7oRs U"ò4÷.t±ä‡ré»ÜZæ.ýþ“[oæV]Öˆ­÷+[¿­´ÞTæÍê8A|ñJ¦Õ[K¸îMhå˜â÷­EðqiE=YÝI-’çBÇû¹dL1vϦ-úÌݳi ùÎëxÉm_5gÚ’›Ûp {F`¾àæ€E—/*e¸ ¶x/Ûá ᥕ 1½R›úÂpä Oð.±](P”…1Ì4¡ ÒõrBdInk¸ä¢âŸz[°E+›åLh¾@~Äâç)`¥5B¦{Ó¸³£~íq:žZ IÄ4HfpŽAÞ'µw1t^ålù¤\$ÚÉe,ç½±ƒü¦ {!x„Ôí ¿åö—yÚ]äݬS*ÜÑbnUl§Bý %WÐ×µä‡ÜToò©2Ÿ1 Þ!õ­Þ®ît;ŸÕ.‘„C­\—ÂÉï Á-•‹$%\:C8Ÿ ¨E¸j¦)B•<.ܜ̱DBÝèís„XXIp”ïÆ—òè¾Ãɘ³N: ›ÔõUºÌ2’,ä²z ޹šÐpÜ×ó¯ùûeLU–æ’15GŸ£ñ8©´µŠªÜ[ù‹€ŒZ O•5«&K»Èb«89‰fš€7xŒï`­g¢¤^JræÖôvµ%ÁŸÝ|Wö0Ë ŸæÒ].]á¾9‡¼Í>&³>·0¹…É-L~)0™ÙÏ3aÒ¬&ªkü»i˜„yð àäMøªÁˆ@Ñ{2YÐñm_Z¶tm=ÊÚüÒ!å@¦K/š&ä÷¶Âˆë¸î<Üâú×·¸þe⺤è_ž‰ë¶à:J’€ÏÂGn!ýðyÇ¡]àða2à#a¶å"yžñ“åcº¡ fñáASȵÝ”/„öKp¿D 5f>3üyÒN†/ÀqßðÛàå#¢Ÿxú¹ø™—±z9úa°[³)ü{¼ãwhÌq/~+fÑ5næWbþÙ°þÒ:@N÷\}@îŸÛ¥þ¡«ó)ð/ê{-èÖ€rßµ­@¤¸b·­qÅ¥äV°O³v­µéÚË%ngi a¼ƒ”¢Âmeú¬y½W»[˜ÞÂô¦× Ók¸¦õë‚iÉæ†ojLÃ<ç·†×%‡6JìõêG-BP·È·E¾-ò}ȧ B°µ!÷|ׯùÂgEüÞ®ÌÀñ«Ÿ•7˜¬[ß æë¶X·Åº `ݳ^™Öñ‚ugµ¡Nòq†áoNø&¡Ö ó$XB¬+Ë,°FžæHh ¸óá"5å‰ÁN:ØÖg|xÁÇ úµëÿ v\[ vä‘,a W»¤×O vµ—ø`#È#þÿÁ.íã1`÷”—— Ý„#þáÉ:ŠG±2Òö•š~ý.,^ endstream endobj 1693 0 obj 2583 endobj 1705 0 obj <> stream xœí]YsܸNåQ¿bgª"7‰<î‘sÕNå!›‡±dYNdKëµì8¿> GlÎ 9Ô±[ªÔFc vïën40?­XÃWÌý/ü={{òì{aØêõÏ'lõ ü÷úä§îoY…?goW_¼p·µjÅycµ«'}|ÕŠUËYÃÔêÅÛ“®åæ”7]«¹]7›SÖXÙJµÖäUÕ_U¦[‹Í©µºÑV¯_ç«6¼if}³‘î!¡þõâO'_¿8ùîä§•4^„SÕt+.A4Õ9QtÃ:§ØÏOž=ÿëêÃûÛW'Ïþ±â'Ïþèþï‹o¿„?Ï¿Zýæäëç«ï¦ªË¥‘ •ßlN%üÃZ¹~Å\_lh!™Z_'}œì®»ùÊ6Ö£\çF@ƒL¬N…j¤¶ÝêÅ94ú¨n…íÄú•{Þ¥•û(´jànèèEÂñõåæT7eá%­ìú×ÏÆZ#õú…“PXÕvëoáÙZ >Â+$ßo A.-ãÛ$(sãÛíœ^á&6ñâY«æ&>å>þ ]  3mÿI[¥ðCïÝûeÃãþ{ôøY~?Rñÿ¨„5±­®…ÎeMÓ éÌ'\óU#.j݆‹–s½fpU@çs7Z©rûNT¥Þšõ6÷ëyú>Hmd‡”>ËûNÓ–uA~ÉZ{žÿ/¾Éª^g‚ÎÜ ‡¶¹[Þmœ9q¸›ÞZÎû®h;RiÊ®µëÿ¦7m³PoPVh#‘$WY4þ?»þÑèPŸ\„>1b}›.öÙ õx—õxõ@:_¦çQï¸w*ÛÈVáî»Ím]å7Dc7wÚMþ80 ¢ƒãÇl"a––Óÿ4ô÷)è!ú>Ÿ‰tr!¤ƒÙbÝß»F:x{Gº›®áÚ }/©`žÁ0Á'Í´ºFÑqŒˆý28€ƒîÃ>áàþZqPeDÈ>r¶«"cH(Zé|=ma"uwŠ„¬q¯Ž÷„ºƒ·-ì þ0.7õ—Œ†Ïòó# ãø†\zä|dpé¦ó.÷À‰ÇK>/y~^öxiZýðÒc ´ÎtÃ/ /±»Ðc0ûÁq€É:ÆÂL½ffݱ÷è1´ŽÎ#’8{»[Ê~t<.ç$>Áã<>ÁãÃãqþ¤ÉØø-xg­²`u^>çW¤W†îuã. ¹þʽ«eLi‘`©F*ïý¥OùÛ1ïp©…ërý]¶šÛ”9 OA÷õº7þÇ I»þ¾e;ų0Øtž( ­0m¾”“©Íþ;€Hf~3‡³¶>·ýмØt¼a\r<_^î4"08I¡OYúô{øºÇZ¸!ä p« ~ÓgòMÈîнçarˆhùPˆ:'ÃôCH;2ûû¥Ðœß5¡üSe„ï³1,ÁÀ|‘ž""}N7~ÚÀÜ’š—pe;B r”`,; V[S))äD?aÁ†àqß ÚéãÚáv¡`¯2øè¸€S¡zY½Ûòç üp³v¸›Ø¡Ç¥®è8ûyºˆ{ën[ë^v÷Šu¦Pì+”#=çz#B“aš‡[ÇúAs=·F,`ëÑ5d€÷¨¡ØÙBåÉÄ­p·9€6lsàûk<Ÿ`â´¦7»³ H"Uç¬Ã}‚GÀ:âµéÓ«]ßRFäôJ“i1ÅvM&¤Ê,_fp¸Ï»Fy*OÌ2p”*¯õUí‹ößCSðYëc)@À3Ð:&KDUWxö‚ì¼þ¼ Îðì¾¶tÓé ¾ƒæ´+‹”s€BkÜÒuà:p¸2Äí}F+a]ìsƒC!4-óÓ>Õ6–~ù¶>ºÑýض\øÁ÷ÁˆwòÓÛaì"6fCçÀx ¨¯r›‡øþ6Å™g¡Ç¥Å·ÝqÂú-Si$üÞa ?L6—tÔát:í•:CëRJc‚¤"¼›º»+‡Ë›uËt1pq´eK?ÿ™økj`Ïã*G»?ØCFBG›¯Ó^×C–LÛÅã#9€l[hÄk²Ì›8­^RAškRÉ—‹Zkš ¡÷Ï©—¢1GWË‚éÄõÓaš&Diõ6D0«´m/R‡²›Yeg%Þ'žÜ&îü”®½LŸ>§ok¶U>›¾ÝDZ˩¸ƒc±~£+Ìk‹çÚÖc+EA]yâ|Æ€G‚Ž0: ¯>šm;·j¤`[Élãk"ÝÁ ¹x³dVç[;„%Á2ré«Û™ €¤>q$ºñ¡ (C {2ðŒ4 ƒ@ý’±†ëÓ‡<Ï_Åd„ÚÿSÚe‘¾eFãHÕ%P‰87Ì€Íèmïœ 0‘8²¶ž={Q!êI‹ÖȘ‰€ë‚¤ŠÅbJÇrS ½·aYº„1a&p^YHå¹Ff`‘dn¨™1Hˆ×=^…z¢æPO™úèAËwÎL3Àm„P\¥à1߬†(f‚YµÌÊÏf2¾PÀ#÷9ÕÝ1ßåÁܳ˜»¸i0ßYÀê"·†‹\”¸ àjìãá– x>šàôQ.6¢CÝ÷îmÚõAÍY¬mW´ÓŒ Ã$´õ9wü%‚4般1;]lÚ¦cΓ|ª„^O>bŠ|®Ã+[ß”ä`ÌZÎg¿>;.Â"¥NÙËXY˜ž{zI÷äÕBdÖÙÞè"”[?,JöÝ`ü2,123¾DèÃ§Ñ ƒ[Øf¦MäÐ¹Š•B:ŸŒ4?`ÀQ“LŽg:¤…2f™XhNCã(#ï%’0m{¸¾N”r‘ç¢ qJ::8µ¸œ6»¨'«2Î<ÎéªV‘]êÜšUƒZyÇr÷6È%‚¦r,/‡²G‡0ïöêámÅ@1‡²ŒÁB^R¾Âð´–jJnéó‹.©'§é¨ †Þ”EO @ÜÓQxJñ¶Ju…D}‚Žuŵcr YÆ`ôZ•FT9³ÍqÒ—q(?Äe/‘,%ööR¼ËÔµÍ<43·™^;&¦ÃϺ ¡– Læ4U“¾š+…XjKâàÎÞëÐäM₟‰ÐdK,G y„¾^ÇÄ‹)¹‹?†{—¦êœB(@X‡Ì”Nœ—ñ¹oÕt¿œUªC˜Å÷ÔQÄâÜY)jb,tA,ŽˆY; m|Th=9âØ¦çW—ù#.Éuc˜^Å6Þ·±7õ±[Ý4Ç„6½&‹…6ärÏ;Ô»”LÑ®€a^R¬>J„Dû¦ 2AºX) ë¨Ø¡èöº6KÇq¡ÔsŸ·p$ç”åvÄ?„²P7ÎDÐN;aÉw°ÕpÅ{¯H«(ŒDbÊšõG¸2L‹zjùìé˜C’BàB‚r13,ùös£×µô§PÁRª?²Œ[¤s}Å!L꙳.B´Õ‹ÜѱC•¸[Ò×*í7J³Ûë)<ù`Ó)œvDgØ"¡ú¬†ˆP]t®2õî=0Ѻ¨¯÷O>X.¿}wh¬¾œ:;|-¬ËÞ`ý˜°#ðÒBŽUµÙÐ…áÒâŠü+–МÌb“Š’ˆÝ#i¡êwhð';c°Ì‰\œièv7=Û‘1Û–NO²¨èkiD7^ÌζÃÎ è˜#ùXðô7÷õ˺¨èú µì´t* ßrÄ"{Q/ÉÅIô¢O¸&=µ^ZD4ÝG€óÕ°;³‡ÐaÚ¦‹a•éÒ,1¼]„P&£;F#ã,à à!&ãb‡jˆb8-î£ä&|׳Âmâ°÷‰ÃÞY„;,ˆ]Ní]LˆteBÞ¹2hÆ "ézöRUä#PWLnZPùèÉà ¸¶­ÆÂÁk¸sbã àÕ í,ijիœÄ­çà°ÊV×¾´øê ;SÕ'ÞR|YÕ/¶ÌçLf‡ƒÌúáà"¹,o ¼Ú†s©°zʪF1¹?úâ„!üþ߀˜BœèÇ6 CÑýT÷]]™K¥ÛC¼Õ«˜hôïh³Å÷0iµpqàó~+˜à’ö{ÊÄÄa¡JãÓgýúÊö"¶A;ü^ѹÀ9œó5¨‘DéãmÊîÛí®o÷mZNÅ]ô^üÞ5M§‡'ågJ-³ù5B¡}0Ó*_ðCCíÈ).ûJÞg•¬$‰Ž½«Ñ3öQˆÛ1«Å«"Ò )ÝïGèSÄióô„] TºÙ·y6°‘AêŒzlt›ñ®ýe3¦Õ”¹®{°†(×V¨ö>–Ï7`s=fÜTnl_¨<¨*ßëž.&ú.¬Crï]ËS—>z ­t=ž…®‰âÃå1´"U,^E'-úç±bZÈ·n°XĨ\Åu$9}Îi𻢆kÊçôêy±úMS/óCWùjì£Ú“ô•ïðià„×ËNe^F0Û0)£=iΜ¨Ïa ½Öܧ©n#,y¥ˆ²¼v¶"2ÛOð=§Oéx‹[Æ÷œÓå{2¶Ðyc»q–ÇÓÆܺƒüAÚs—D‚€æî>ó!œÅdÉ©ìQ]±×^¬ÇwÐCz¯|ø>¢‘!-Ì’C2¢—+Íi š òBsòmqË÷¿¯X„pgR1Ž «èêè×A£Ê-"ÿ®–¹ž ¦Ì>^/9vû,hÍ%D3ŽêCÕ8¡J™ˆ ?®3 ×™2A÷œu™òXI(ž8ÞŠŒ*Q} jõ:ó#º÷ÇM–l‚§>}ÖÓÀÏ»nê¡à 6DxêпOÝåZ”D:v÷y—@"Hø'Ao“ðoÓµ›CÃŒåú} ¹Ç©Ä•ÖÜ]€J|½Ö‚3J%º’‘Ù•/Ýë¸?éX*qÅÇìrrgº þÄ)X—j#÷m͵‘½É÷ô©—©À{óùŸ´âµTzJ4^‘ã â78êQv^Ô42í ™Áò͇r:2 ¼h—Ù5?«!Ê¡tÒ=Ôò>ƒ\©ùq˜eßë.&ð.’@Òîu ‘A~,gjp¡IM/âÓ…ê‹"~ª€a|6GOS‹‘)ŠÄBª|Î*™Q§×hÇçðT—oºáŒL=@ƒe\¾9 Qs˜«{ÙÃ!J‰;GÎ 스¬¯«ì\;wÄ ø‡*DÎõpùm¥ÆÞÍÑ-Öï» iðC½d~u#"Ѿ ÌW(Ïø¥¯ê4Ü®¿ÎqݳÜÀ÷éûü !_ºWAØÆýOm„<ça? BŸ—VÕ«t\Zô}™®üñó!­ó~>D§,î(šn8#ÂÄ2Ûf5DA›|lþ,(²¾b `‘Uαã÷E…Ì×ÕjP2çÚÛƒÁh±žßF… Ohô+A£é–CƒˆeËÝÏi‡À¢nòÏ Ì‚¢÷xêÄ݇a= eyëʦ2uÿrŸäŠûuïû\ù㨞ÎçÜÔgßK.f!; 3 ý„—¿¼œn54̵Ý2õøsÚ!à²m§þFË,¸4¶*ºòi Tu …˜ÆÞ}ÐÛ#f!òÛaœHÿWCÏ…£ÅF`º‹Hùùç<â/•û`àâZrdWètéfþ´d“k‡ƒËt AÁèeªÙç´C€‹™ü3³ÀE›¦?/èXpÑí݇±=¸ŒˆLmʤêÏ)ì>„ï=²Bxê`€ú$õPp1SÙ‚…ÜO(øèPpº Ðè¥å2ÙsÚ!PP‹{ù‘˜›ýo ‹‚JÝ}Ý£`!ò%ábe¤~œáý¡à²Øìú=¬Ë¸<:p™nc¿jÉJ•°ÛΊkÜÑqGTî†;!\LªwòâÐÌ"endstream endobj 1706 0 obj 4867 endobj 1720 0 obj <> stream xœíZYoÇò¸¿bã§Ý@;êûŲà Jl‡@$=,EŠRLRµkY@~|ªzú¨žé¡v)êBÛ}TWWW}ýU;ž³ŽÏþÿ>=ŸÝýE6?}3ƒf¯çJ°0a¾R›{í;çæ–3Ý1‡ÓïÌî<œo.·'³»ÿžóÙÝ¿â?÷ú ü9ø~þ‡ÙƒƒùÏ(–9\0ã:ä°Nì#‡Íœ½žñ^¥øçéùüþ!è­šûΟÍXçt? &йe¼Ãó٣ś%h#•ã‹¡K¯RߓÿÍÎPgIŽÎ¹µxfËßóìûë+àT¥òQVùeVù8÷½k(_œ[o;u‹Oi/ §Úó¤º3•ÞÿZòÎKÎÔâd¹‚n£¹Á¦P¢ÓF/6KB$³|ñ|¹Òà]Άq­:î³…_üÄ3¯…÷ "(M}ÿNiæ 5.µ oV€÷ã­îþ}vøç|šûtðìà=4z9ÞŽîàhñÎ!#\6ÄJ²©2ð?7_–fYTZo0h”€„ã'I›4•¯±Nˆ(xpâ ",ié„yH0Ó)Žºö°c|‚(¸êu ì´¬zYš "DF^ŽkzPòªS¼ë#ýâץ鸑a!œÀO=úa’øv 7W¢é6E#ðC@ïN+Ÿ”Cñg´Î(~q×qš¼Åë1 N[r°EµÁEe1(Áa.ÀWgá¨7 Bž£Š^h“ÀÁp]¦pßÁ-j3ý²à­FêjÎÈdlì%¯Åº@ûi–EÔ"ÇEÑ{³D÷Ê!ÀÃî”7$Þ¯ptÏÑkÒ?! ´„Â,þ8|NQ%r/ˆ%¤ZSHï‹b ‹¬UQ îêx8~²Ú15eýÜYÀøám;È$že]|Š»”áÍÂÀ ˜L±‰ÌÜF=TÆ܉àÁ6ûàYqáãˆ"à ÛÚ›ƒùå ïé0'Ò\ìG¹E‚©a~°ÏØ Ë#4óŠcöè $ðHg¤QLðæ¸×(±´~íAÎIO;æ·ïµÕC|=¥dÊÕ« ÷S}öp°åUf">‰ü Z+38RùÈ«æÜi¿òÝÔ«EŒz6 Ó‹ÿÔÛ–^¢ïÓ&Mª›)Ð2P¼ ]ßKUž‚ …f¸.‰Ta#|Áðú``r„2JƒÓCŠ’;cŽ¢¤.¼P+):&½KÔê‡%äÉðîùdÄ¿Ëz瀹Î÷„% o’ªýÓ9¸å3>WÂ1ÖÆúú»¤Ö:'ܧ‘¥â÷l¬ãèÉ ­{yôQîûSný7~3èÃÖwyô paP›2Ó(DnÃ0²Úó—o²@@ÆÇÉ5Ä£x¼ÈkγìR$*žZ¼í«Ü÷C£˜Ô*5¡Á0q”‚,¹ÌKÖíŠ2'ƒÃ[Kbà«ÔõuÜ‚É?ÖU²…NSãh z–j-Qü^êz8ÜGŠÝö)µµ<ýÙxŸ“‘÷ò+[ÇÆã%-ÓrbYRÛa¥b§Y”9§°¤u†™*Ó×OåµÒì’×â“Â}ÉÈóƒ”Ù( åWržÝòÑP³Õ³ŒÏ½áWgè}ãUBjtÜ—3œª(1¦ ÅTô²>a’@&üµñÓœÈ\6L,5¦(SuÀ6ÑY~´i¹UÙጲ ¡ÁÁÁ\¿»÷´WÅlK°òìã OÜÒ³dK*,/VÕ×瑚‚9¸Oä´qG’*}#œ/•Dý•%)Úœm“ø°L¥©ŸÔrÀûz¶ièñ0C )îq!`„ô†‡ô"\ð*Çís)ÉEv&«‡„ÝY¸+rÑàƒ Å†Ô³½—$õjn ì6rÓÞ2;%4­Ð?²m3·%QFÚ2µÎ ã=GÄÞä$CjÊhGè4`²Ò(yNÉ-²V`,G²ŽBÆÀ÷+€à}áoì½!Ù#@œ— ¯<7w†”tˆ‹‘# Ã}PIK©«šª‰Õ:¼j§é'Ì®k\+Ÿ5t¤ß:š,4×Or€2?Iº ŒîýA‘Rj ЍPG N (ï´ ÌûNáŽß¶:Ëòo³È;…P~×~’û†i¶¶‰›œ ÖIÍ“&S„ÌK{Úð!F*†£íüeL[‹rOòèj°[1Ž^”jÛ °G9…*T–n—S¨'5Ó«ø];s‚÷ô#eNסtô’6ÔÏ fý^”YàS)Šžµf•KÅuWžUH]¯ŒÐ¤þPSžJEÊíêʘfáV«,tÓ|ìö£Yƒ ì½hVàf5VJIÖc}Ez$ù”0%´·†n0üˆ«³™êLìZâBç²ÇdôazW¼ä@¶™Ú0KŒÊä”àjÿþÀâ‡$ïç\Éa;y}|³¿ ¯áÑ„×#¯²}y/²ûÏç÷±¼Ÿßº6QŠø½ÆïÌjÌW„ö-ù¡™Q™ þ,<ús¢)ë\f÷‚x>­©Ç_gŒÈÉ>AÀM·g ÈÆ+¦Ñ£;Eƒó _¬oÃá6ÆáÀ>u8ðKÃödÑ«Ü7 ƒ]in#à6Z ¯{¥°+î;f½š¯„'uü"ƒ>uæßñý<û‹ëÓlendstream endobj 1721 0 obj 2752 endobj 1729 0 obj <> stream xœÕX[oT7–ú¸¿âðv¶êº¶ÇW .1:Áªv(ÊU6ž…ûƒÊz‹ vóÅqï냪EúÐÞáåM‡—ˆè¯)¼:«¼pa°P$oUìH¦wM)ÎÑ IO…Æ×àȯ4Õ¸ÂZ§·\ij,—¾ÓW²Óc&Ðös‘G[åÐCä0ʯ(;¬ÐfØS†ýu]•ÈïmÈ ÒÍTðÔTl·S%›ð¶¬bx;.è`Œð¤¢çwºAÑ;4fÞÊè%*ÌŸæ N÷ßP†%Ë ÎNt0KÁ˜*é„ hSZ'ÆÑ˜Î(kJ/*e÷£“˜…«&ùVÞô œ,‰Q)x´³TœÈn}ˆAÊøìšÛdÜ]PàEc­¯¡Ïo•w[ÊÆ0lúx©ÑPaš1.‡M OQχ‚¢V?9zv%) sŽ:/£ ?+²;Eö¢QœÙu–¯¯Šìu]6Øož“§–c¤a$:=×0p‘E˜¸Y*ÍTLwQ|ÝL„MšØÎ 3˜æzpž—“ûåe Rl e.¾-Ñ7*Ð.-[xÙ ´Ì-‰qŒTý™R×Sž$­‘½šŒÁ ƒ+š‰Ã³ÓT:Ö)a”ëP }Â1­ÒÅЛñû®QV—³kØß)2ó¹àlg4@»™/Èh¦f´ 9ib"v ïÚìŸèP¨±žddVl§„Œÿ<_¡ã„TvŒA¬˜Ý.ùŠQržZ“zaï„* iakÆíh<ËX Ñr˜±˜ô!I­ˆx³ÒÔx‡mi °º1JëQƒ¯¨ÒV6!:+½¯‡ô…M `“ó×4UYLCyãiÙŸÁ.³•uPLè&&>Ÿ•Fï&°ôêŸ÷ÕBCÀylÊ?Õ³˜16˜/I™1®xÈ‘5Aéþ;: Û ÇdÌ–ƒ…¼Â>ç¬nz¶áš{™8™ÊH³Ð8M`Ësì™0%¬ÙËDãˆÆñe‡C'-ùp5:qE…:¹ñbR'Lûͱ[lLh梊ÐçK²"&6qK‹‰‘½É´__ft`°/B—o@i–LÈŠÖboÈN½¸ ösx¤7£ƒ:õ嵬M«n†SµRÛl”°j ÔXóxÒE­33:ì’/fŸ“·YÄ1 œ³õ#i°ªBŠ}LsÔ ˜ÇÂùæ6žj¢¦Íö/ZØf.¡ÓªÔvú¥Ê»¤Û‹/²(Ç!¡ª¶‚qHR_3Á,­ÇúÚ£”öØfx§0X*Y½éÎSt.ó ª—S˜õùƒG›ÉާHüµ•‹3• Ô0øzU^ÞÈåÇå'µ“œ‰†ðÒNÞ‚QTæ†Æ€m–åë¬ÜIÿ'ŒVXeè¡Ä:)•ÜaÝm<|œÙ¼E¡Ñ«òuÞ¢L_'wnQTPåEû_mQvzÉø_v+[Ÿ÷ÇæIY^^>¤fï¢cÀ#"Ìœþ¯„B;#­dá¼»¿=VUb€]bµ¾ž©†¬ŽüÖhl?bc^D>éï*ÆŒݺ»ä½Õ£õâüûÎA‡Æendstream endobj 1730 0 obj 1668 endobj 1734 0 obj <> stream xœÝZYoÇüÈ_±ož °é»[òàDdÈq¬ɃŠ—-IiIÆÀŸª>«gz¹¤$F HôYU]õÕµïWã« ÿ¤ÿ/þøJ˜iu~s0­þÏÞð°d•þ;¾\}}ˆË¬ZqμÖbuxvà++V–OlR«Ã˃9®9sVs?°q=1/­TƒéŽêqí½fÚ«áb\K8Ã{9¼%Î 5\Ç]Ê82x;rff¸ׂ)#ÿÏá·¾òÌa(“Ú»Õá˃Ã?ü8â Âké‡7ãZ3çð²S8C ¦€.Üq¸ øIòÚ8êœp©>!-“Ê oGø‘ÜÀ© é¬>Ôí? =©¥¦gnǵbðr8ƒ„`–Ò‡+ϤuÃ]Ýs²Ð 4…ÔsfŒôq»2ÌM&Q¸Ž£@Èq\ªº–ý|@Z`$2w9Ÿˆ‘“åÃŽjƵŽàS+’ŽÄ˜ÉØ,4ÎõŽc c_À#zÉ'…óá¬^DYp-‡àœM\fa¹æÂ"¡°.½ÂWQ 'Í|§!o¹Q{„° úð”˜Ð…í„ ƒW3M§3TG¯´¶xàOjµæ–5‰xð^%< 2ÐÞøÄMPÂMewC—;&&kAµÀ¦ŒB5¾ªWœ'HÛÑhü\H4ëO^PyF1 ÍPû/‘\/´‘¨YÁ>d­³Ãë%—V>QÁª”Sf¦íYžj LÁXµ° ð%¶•„ô©´êâ—ÌeÅX£^Z&@/_ŠiP§Bu\IÜiäø J“ýdå]b*ß}kî™k´é!Goæršqi»@M £hì`*ϫ΅:)ÈBîÈa¨š6x–‘ëvÏ«er[WˆÂ;Ñjpì»Þy¸¿cÉøèó=®vѧÎ%„ÝV›- öe,]ìÐt8JÁœPTXĶ@ü³ 'Ñ£ªvd×>.29„•…k£ ÖºKsl_s^TÁ  KÇìã0‘Ö7Žäº&Ý!d€‡žÜÔS«…VÂk²Ÿ¿t±–ÜÜW xü†2Ì£ =ªK`|Ó3ê ¤^ûbœ˜žYBÒ™—UbÄÌÉg£¢Ù¡Ty,Á´î—Hˆxït¯qé&v‰î ††>ð®(׊Iþ?I2Ç? å®oFpr^×SCà—JÆ5¿ÃÐKÊIQtñe¥¯ÑÂ:AÒ䆩ŽÊ²ÔÅ(ÜxAAõª.Í~Ïñá/U9Í¿ÐwØiro&“—:_Z>#fFV${¦ÞÊù ~ý4–M;ô/)Ié+ >>&0ÙQ¹®sêQžÛë{+~Ê÷ #×]Qp/N/^¢üäAm³Iɾ85SÒ÷¢Ì=%ÞÄß—ñEor®¥S!^g§t¾èyšBÀ9%vˆ¨Žj2s•E‘\>ÑIQú!=€Ë\È:RŠÓúâHêÏš÷udQPTùeƼQ8!)1ûÓCø¢kt7‰‡mÉ9ÆÞÎ ] uAbÞw l™ãÎd´ia'æl.mH«©`n»Öþ¦ˆ“ƒ ê1ÐŽJv›@ ǰ6/8ÌÔG òR|Z§™nP[¯ÊO m#ìr(Yº9ÌbóÃpý€_AllzÄ^Ç2…²Ìœhj¾ ç&'úáôŠ„R’¬â~ëÀí5\×Ûçˆ#B­Frž´žêgâ볓]D>oûÎgùàè¶zëÓ:J¤öå¾…¢€­aÜuGß…!y®ÞX.\µÌÚ™¢) ¥ ‹Iꎻ„m[,-€á •„¤š&zZdLqK #÷Ö³b1I9†µ¤„ ŸVl«?"kIz‡’C£Öûn–ðv‹¬>x‹ã®ZX_X;·¾Y šjhJê®g$9TRI÷›\„um­ŒÄЗàiœWžzŸÛÖuiÓ\Š«S]Û ÀÈ{$D{`r¡¸}ñ…ƒÈNLò×uøÂRhSÓ«¾S2kK`ÏCÓNÇ/•˜6Å€E) (-e!xŸW¶{ùêÛ&C¤Ü/`jHAhP¥öE·jÓ/>ªéЉuð¬f©/kfH\ó5á*{î’«EJôhwÞ¤D˜¤Î½ù1RãÎóR6>2…A?ù9!sÓ™ƒ'Î~•ÇöÙŠÇšHâ¿G31eUcP¹þbHݹq»yð|^?km êû/€§noSÓÃÜ1‰ô2‹Ø“®æ£R· (wš¼ëÔΆ&d9’óÏÐÐLùØî6QjÒ½¦YAVýOm-ž6áT®Ú¼£W‘@3ä–±—-ên&ß`„€¶ã·èo¡rš`õ)qS;ãg¥ß½“Ê«(ÆÆøyý|]z䤛¾h—ƒÓÿ¤vyãHÀø’Ÿlì¬ÿ–8Ìl¶çeìu»˜AC Q`¶ßˆHWsÀÛÉ5×6MþUšóœb÷›}ºþ6Q£…ì³X3â@U & I.*n´=¦NZJÈ%<Æ‚˜rû«¨m–ݴݳ/줃ÿ y™3ó®ðP$w-&1³FkÍáÝ,õ_üÖá”Ê"–/KÙ,{ÐüŠE ’ß6à¼â‹ÊV)W™ŽàmGMÛY°µÏ?û=°ê÷ø{ò~‡ŠÚGò‰?7ÀñçVÌ;oYÔùsƒï¹ÀÓO;Ã0Ù)sƶD¶KE‡6H’×#ªKl¯F)›ßY. ¿£½ªBQ¢yÿZãœ'ö¿ÉÎNí?c¥‡kSê!ü*\?ºYþê£Ù]üv« ti«Ëñ´Ò~^8šÿu9²kD±âÌñ½Yqþí€< yû“‚…|¸Qb×¶AÔt ŠßéCÅÂ}Ï þ¶qwB;æ„Ùá¾û®¯:_’¥‘c›yΖ¸'KBJK©‰‚ìÉè¢BM<"­ÌüìE);—Ò!àY9)V)1ˆòT l$D¾¸^†x•Bé‡âÆç‡?ÀŸÿNÐÿZendstream endobj 1735 0 obj 2497 endobj 1739 0 obj <> stream xœåZY·¢·ýã·i)Ãð>ìÀ€|(Nbke ý°Ús í¡=b­ï*6b7g/ÅÎC°D°yÖñÕWÅy¿àL,8þ¥ÿ÷N¶þôJZ¾8ºÜâ‹¿À¿£­÷["Y¤ÿöN_íà0§+­^ìn ˆ…“ '8ãÐy²õzùlPÌ{£ÜÏ;‹k‹fgÖsœº³ƒO†•fA.—»ÃJ0kµÑ˫à xXîÕÞãa%•fΊåÙ°2°Ijy ½Ú2\šfŒ868À’–—p4c‚ÖËóæ;î  ™63Â.×u­? ޼¤C÷Ó¶^-ßÔµÈ,r˜ºía–Á®9Á»:ôzìõ&ÁmSpìݺíé`™PÞÚåM’†rY>K@qW$éÔVùåŠ[šÀ}:”—2©©Õí*ëi% W„0ªëi\4p£»ÊÅ&ö±Êj Tˆ‡Øk˜0*¯€º…¼BÀY Ob8K)&¤ºÅ$ŒfpìÿIDídíªF»£z,^wjµ–ÛF“õb}ýeU´úû,é߆®þ<“žsÿ›èï÷Öú†6÷qN8b`ÊyjbI¼QÄiq©ÑØ‚–‚½@†òqzÊ"_)É„år”ü‹Ar0$òNàqx¦,í¸µ#4äÏWùÈãFÆ6qæMÂë qO±°B }8h敉»äÖnl¡jŽbK{âÌ}ëÒwUZ—åëç¥ïui=+_Ÿ–¾ÏJëçòõϹ/Ë×o°m%9èëUgò—ñ³paùEþÚ< ^Æ –b×·0Ç€9Øå‡j7DÆEîçhvJpMÁû ØO×»¤fÊø÷[;O_/w†•b2€€ã®‘fŒ0V)wúÈåï¬ DØPè66 ²u£d!¥tÒ‘Ô‹Ð9ñœKL€3ëÿ*Erc\¦¤cHµ†IAˆ†•žôࣺqSÖ Ñ»ôá Û3ËŸ–H¶‡N€Nôœ¸y…ªŸ†ü<Ø«‡LPé-=Ø(AÕ‹ó“Cæ±ù_Ae´•ˆÖ#…£õàŸ‘úz³ƒtÁû¢úc©ˆûéë*Öü#2åEçt¥æ’ùåMÉNȤDhµ2ÝŠ¬ŠÜoLšR†õµ û¤”awÇ¡Úz¥¼]ó#Ž×vXØï´–Ú}¹jS¼ÈÄ2 Ç`Ž¾Ó +¹ ”dZõÌï•Óf ·8ªF÷·ö~ò‘ÔbéZùN=ðñ|I;©&žMíó;^æ!tˆ$Z‚ ó»|–rÿÇMhn¡ÄôUM/^ økÕÃx18Ä™éÐh¬ëÊ‚N':á]ÇÕqS(D<ø~<­qÿ£ìÿš"&9qöñ:éëRÿ"¾ôbRëŠÇë?Mv 2›JÅ/1>§ð»á§IIÊíO[Ê 7ýìÌ fÍ ÁɪdþER}T –Úe˜w' L|anž›HÖi×UÚ7¹‘ú9Tã÷÷e©ënŸ*óÚXù“Ä¢ù"^9+¡M ¯À÷ÆßEG%KåþªŠ¸¯&‰Þ¡ã@¯Š-V…íàg ¦b¨’êÈ.é¦0îNÓÚöc1`»|´#\ü»dgÀPɶ‹u#v…¾‡8ÈóGËþù  ÓŽSáïéàûäàÏI¸˜ÿޤµû~éÐiÑ騬ÕçœÝY ÄB3­+e}Ã[ʲš¨^P:qÚ·;[?Â߯ «endstream endobj 1740 0 obj 2654 endobj 1744 0 obj <> stream xœÍ[{o\ůÊû)©RvÌûA«J$MÀU !¡ øÃر‰ã` ƒÜsæÎãÌܹkǤj…‚¯îÜ™93çõ;ýqÍ™Xsü/ý=>_Ý~$-_Ÿý´âëáßÙêÇ•ˆŸ¬ÓŸãóõCüÌéu`ÁJ«×‡§«i±vríg^ž¯¾Þ|¹Ýqæ8—Ú{øÏ¸ºh¦I&D0õð>ßmwÒ8&…¢37¶š©ƒÝ|Œ(f•‹ßjijӷ6«Ìærë˜ç\èÍÙvg˜÷!¨ÍãíN0k°›çÓ[ï6/·1FŠDZ{¢]¦m'à->DïÞøDwË)¾‚'¸5p²Ü7ÓðHÎS¿¼¨g¨„öÓV1c‚Öä`›ïëc»”Tš9£¸:i4ýôyýô¤>^l…‡ƒX¹ùæËÀ µÊã§R[æœÞ|³Ùî4ƒµ€¬Oá5SÒsµùb+XÞ„Í$Û2åC"Vq‰•Æ3/íæp»SLeLºB¤ë!Ž Æ•ØÜÇ¥”àzó¬Î?ªtUº½S*l¾+Gx]ÇÉ“Ó|³G0û7‘©{™ßc‰‚ÕUðT¢’œÜ›Îk€È鼯8|)"ìàSí<‘®DovÓåÃ…§O-”gO¨ Lâ£MáL;(O§i[&æÅÿ7Ù‹îû’kh½Ó'õ¦‰\e¹µ"Ù²úA¶ åG•?/ +ÉËÊßgC¦2X5HÆ¥¥» Ššg¹utV:—„>dÖLx»y§\ ¡ä¬Šr'à¨"°ÔAÕ,Ö¢°Æãþ(A 6Lk‘æh¨˜äZ/ñZtS”˜rv|<«$ôHÕXèãíùNæùD 7z(ôøÈ…ýâ.Ò…‘u¿ð=º¯AÂçºå;ë¾D~‰¥mÇ.0©¹TëtÌNäVÅ|Òk©%Ü¥A‰vTä¢\•¿gÔp£ÝåΡÝ-z36×gICÀ?žãÌ€¢¦ÿ¤ÈÊ÷õþ<:åeÑg¼i˜‚Çã:~ÔøÔIBEV&z\§ˆojD(2Ž“n4 ÞEÕ™õ‰‚{ÔØƒüöŒè\gFHºì“fÉÒ^Y•Ìj)ȶç¸Q¬DyÆÎá²øø6ê©`0ÐÒËJ úó‚¤òö>ܯ÷F¹±¡ñ\ t)_—ym2~ˆ’Aøý$19¸J¤·3óÝH\w•‚3ƒç&›éŽÂ)ƒ—˜$NQ‰#³1u[´Én ´ƒP@T­¢•bB+p– å­E(qËE‡(çò6€‰(/åNH,kmæ{7µ™7ä3¹ÏÓ ÇŠÐê=^Gð>^G²;D8 øËF±vD;{/w4TêžÂe78æcfIËÇw‹õò¬=D0~Bìåcà¡çc4Xc6þÿjkb‰§’V¡°FD˜ƒ³‚Ыëplçð duÞq•ˆ®2&; ôÒäæŸ×·'Cƒ‚Ô:>[5λg| Ä77a_¤Æ‘鯖v­Q! ˜vsà,¢¢ˆý‚‚PËÌt‰*ãÖáyP Ô=ÏÔõÁÙ’’ƒöqÑÐÙ^‘ɸ™—€YäÒým”ãFPìL€7.Ô³¾ª[5 zmeÐûÎÝv^I¹ÅèDq‘Í/ Ãz{µ§È"ä#ô‘G+ÛVi-²Åž{qBúù½dHæ,€õ_âÁ‚‹áþtEJH:+iå“öyÏ„tÍÇRþ$‰ hÏtK ¼iÌø æF‡ƒ›&„#˜ï$KA¹p¯-Yªr!ª:æ€Q`‹åÄ»™ÀWcéC¸àÀ.;Ùƒ]¨ ÆDˆ¼Vú%® ´Uº§ /|ùº.Õ!o ‡ÕîXq¤TM’(ˆˆ•‘öèÍG¸•™2ÔmVEÂäLU«ŸD«‡³NÒ EXˆæ‡ÁžÖ ù´ÒUÍÕeuªG“‚¹&&šns¦¤òjˆ aÓ°ÏÏSpÆ›‚ÿŠj·4šYA­fñÇ4U‚rÇ‚ÆdN›;°ˆ 5š8ßBjUgÉíà®6XPȪÒóKÅ›ÌÄ7’®Ñqæ!–\¾º×Í(¸9éBc·ë™¢$X>Ã0s4)}âáN€YDDYùCù£ Oj—̆¦N–ÆO‡8éõ<,j#â1Å9*1ª9(ØŸä%†xè¤SšS¯”ÉKa¼ô7„èo$êTzbUvR7½:Do±xs¨ÙŸùs‰Ó:š"ø…¸`rï‚©CÕXQÊ… |š·SÎÅ“‡¹¿• ®¾Íò\Vgsª¾.Uyøefí´±Í> r&•Z‚Ä8A¬5¦R½åìx¦˜KÊOGñ YÂ'íQ¥ò»Ë»¯ËÓ»eô·òî½òô[}¿¼û¶<ý­ŒÞ/ï¾(OÊèÃ-GJrÀù•á/ËðÝ8,\ˆÉñi”—§¿O£MT;jTI(£÷ó(%¡Œ>Ì£”‚2z7ÞíûmýkÊ©‹i¡Äħ’ñßüÚèw‚"/º´e‡ï‡ñ£Ô ‰(‚ÿZ¾·”ŒìðWn’Ùñpí¿Î´; …´p¢‹w¢»1](ºzš¢5Å6Ë=(6–f4]A^µBWƒÀskbÇêÑ´°€m7ÏåtkCdý±ðbCi’á~Œ$GVE¼ëB‚*‹9»”w¹ î‚x ¨ÂÌ*o+"ü¬ðò¬lC(!ª´Ë>%†:GÞ$øËÎ¥L[j˜åþð%&Á‘9íÀïfÉ#ñ1Éh^³¬JZ>MíøÔ$áH·ºê±C·ãûdš:ɹeHÙâ@ˆŽÍ à:•@'ð60¥Ókà`€#vÉ ©’¨Ú"h†F bM¥ÑÞ†í.0AoÞ=„—ÛO@µŒ•59®\Ì Àõ{óB(ÀtÄT‰µü¦M ‡­¦\vEðØzܧ¢R«Ù0¹Óá¤&ñ2ù@ !;Á•hòÄ„¿Nìh÷0›“EÌÎÛ+»âà¾F€ "·]VªÕð%‚‰¤V[o³4“~íÒæ Ô·h7¬a¥j¿É¡»Ù©t¾·ÑRÕJNçÆéœ—Cf䪭r]p—Û;þR¨ý„ç3ò<ý˜HÁ=v-A Q*^! Vúµðܼ% 8´Â¬~ÀJJFµ¤Þ€IVüÙˆ “ŒÃ§y[V÷k¥ÂŒÊF"õ8fõd×¥6û¹A˜Óvf"*XˆîDYO]üÉ‹Y™ÃÙ(j£¿ËÚ–ñoÆîäª_˵¿©È5h.5¯sæDnúµ]mÁ¬&•XÄóÉœ8;hÆ|cs2ÒÁJÿóî©—‚ŽÉ:xS§$¿Jºª‡ãÚÊí\©¡Ø3€ž°þ¿«¡J*ÌÀ>ûmóá¾ ^©ÎyÇäD˜|w¬¨\ïÇAóö[Þ¨0ñ‹ß }(ÁUÕ­, ç¤=8œ‹B²ô¥6/S~ŒéÞ,ëïÌìÿé̺*ã#Ák´ÆÀ0-’òq.e|´}ÙϹTõñRö{ÖU²7+„h#›éÏPrx6o§÷|ö3ÁôéñïšÚ¯$Ÿz³ A—c§Ü‹]4$ð˜Záé2ü…é¬SÍ·}³ßiöñʾNFË›NÆ"ë‚Vj5ŸüZ{há²m‹e’†)ƒA{~¬„·öÌ׫ù[zh19FrÀ*¿,FóóÕÚ]pendstream endobj 1745 0 obj 3966 endobj 1750 0 obj <> stream xœí\mo·.’oú× (îŠÜšï»LÚqâ$.êÄITäC²Þ¬F:ÉÖ9Ž‹üø¹$gÈåÞ‹tRÒ -È]rHÎóÌ 9¼—Öð sÿ…¿‡{¾†MN¯÷Øä3øwº÷rûW&áÏáÅäá¾{­UÛX#ŒšìŸìõ ðI+&-g ƒÂ‹½ï¦_Îæª±B31½šqx²˜.]¡ÐÖØéÙŒAZ >½œÍuÓY¦Õtá^•LÉéõL6Ú0Ó~¿ÿ½Gû{_í½œ(!L£|ÐNýÙ¦ë&Æ*ӘΠâá㽟L–¯^ï=øvÂ÷|îþ÷ðéÇðçñ'“?ì=z<ñMÁç¾.´Ó6Ê·#¶U;[NôÑÁPo8Cµ²Ÿ!÷*:®¡ v£áF5PBFôÉlÎc­‘zz<›óÆÍ .åô _á#h9†ÉЦp®ƒ¦p¦ÆæA¹ñw7š‡QEëÄîšb^º[ëlkínVY›l•YÓi¢¶-o´èWy9A¤´^ú'Õq²’áX»ÎãÒ„1ߥŒ”©c<ô0 zerOÐ(h,[¤²ee@upílÚ…á«ÀE†³?“¢é„rÐBã)‚<g€R6\ÈœNæØ†C`¾2² }i˺é3ÓpÙë%|ŸZMbq-é Øê‚7е®ÿðä_Ôù×Ð|ÛHe§'Ø<Š0ÂE/JkÔô#7*hƒqXR7E’µž=„î` Íô!,´†ÆìZöØ~¡G! Úˆ@Þ´Úý½kÈkÛpsSȃÛr¬7‡<ô: Šð~•àýc*;Ne¯6†üΦ} äÉpîò‡ˆ´sÄÉ>("R—®Y€lG0ÿ2½úáYå‚Îum¶†º–ãªênŒÝêÛ/ð(ÔµÞGª5¿kËé S\¸“ Œ€yWvŸFÐo»^lÕŠ-‡¿µØœù™!¢&ÏºÏ ÄßÔÜïlÖ`Gó;ôïúÛ¯ï(ô•Ü>F¨A_‰î®-¨ƒ¾TR»Ä>øjwDìÙ¯W™ö[þ­Äð“áüîëÿ¾þö =Ê’Ù­}‰ H¦îÚ’:ÂiºW½ã„xÄúÿééyBR]»§ëTû¢b‚bíZìílük°G&à®°u÷{ëÞU Æ<‡I„i‰-™%~€à}ž¾˜sÿ*~ÿ"½Iš?Šrÿ\6ÂÂ"O?ŽÐ™>uxâ “œzÙ~\óÒ𓯖U«m%©×bw{EÅ.w;š;À.ïø}lÍÓ´a‹h1ŒÓ»cv8×!-Õ;ØÁ»•6¹¤›Ì/tãžî‡nv¶dkè†LÀ/C7oÜV}ËXÏBp|YÈL±þ©éWÁh»¥A‹ó!Àÿ”­¹_î 2­e©íõk”¥˜7ÞM YŠ›t÷†¶àÙ 6éJ cnáå?®@>ù)µéwCMðÞÙXWÛvðVºéŸÂ÷Ç3Î@ÅEü´ñ êÅUY€€v‚£'râàÜ6àNИa@h±0õ¸þ Šf÷•1®|Ë®ÂGÕ®ê à¢ïÀµu•Z%_¡(‡8?ÕØÙà’6Ô/“˜>›b£¯sG&\NM3æôfÿȇÞiÑ^ÓEótj­¡/ ŒÝ¶ŠF\Dú±´\tÓ\H×2)À’’\Oi|é‹j³nȸØÍÃ.Ü`çq´sî| xðƒ>ªj<ÎT'‹êWGÁ´Évd/èp NäbbH*”ÜžGDo2U" ‚ JŒÐ¢f$Rt+Ö HÔò fŰ×g³ôêù%Û³=ùÙÝñ훪xÈÐŽ¾Y·Î?õWŸdÁÇÛF7>É¢‚ÖŒ$žd†Ó•]lº¡µ»i_cÉphjHTúVQ0ï5î2óŒŠJªð"šÀÓªCÝãz|]·Ïg Þ‚1ÊßÞÄGŒ‚ŠöV ¼ãœX¥ûWü]˜ÕH0Bo`‚Rã†G8c)éVÜÐܵ&’xÆ „¸ÿ›SÏ«º¥3°æ°m€\¢9Œ»]ð½äb¨ …¥¡óFˆ[ã°[ºïÖyê7ÀÈ([»}S5¶4Àwî*bZÜý_‡k®ìíf'Úðm#•›žPÙËÝËüDàvº³•XC d8_%¬YD÷VgÍÍY³’fZ%„í×|”t»}S5BЦ½‡ì­ºFÝÔ{RÝï.$ï å¬d"ÎO7ÆùÎ&x ÎQòß¼ŸT?Ú#à= ‘œ÷îízÜjëóï:¸•R÷pþ¯¥I)û»±öÒÜyL­=‘ý¤$ááÁæˆßÙ¬¯A<ý·iÙ8ß~yGqÖŽ|ÀÑû4š©@:à vÆÒë2á…òé9€ «ü†\¬Nw(ܼ¬4¡ÎAªZ›N´¡ç…ÕwØz“°õA*û.•A:L¸)òÜ(?/('OÖÇoËó=W ᢅÀ—µÝôçJšß¥¯æ­%ÿ›4ãkÝ5œ¾—¶ÍLµÏc-pøí‹ZËG±廯Úe¬= S”j‡ýÖdÆ)ran¬þ>Tû [94ô6®ÕûižÈªáà’ã”Ý"Ó’LÀ’,ÐpYðx§Ì䆱þØ/8 gçé" ÿdX{‰µ±–-ÕžÇÚ³Ú¼/†ºr›~¯+ëMó×VÕŽ­wÚlÿçÞþ_Ö.ù‚H:\ò[DÓdɱåÒÃpOoGûõÓœ–<©ív8¹0-±:›±“ ÙÐáƒÏµ¼¼«}[ÁÀIeªâðNqBÂH¡ðûôÞ‡dÈ«lŒ-‰©fî _ñú!Äž$s/ßUÎÓ޶Jmjxd‡'¦xŒ†§–Ô aü9àazï*Ô¶búÇTý§Týy*û2==Iµ*‹ñE¥v:QmØ&k« ~›®Áñ™Çú{_¦:¤²R(zJQ è‹aÄ3k;±–cOA«¡Q™u>HuïÅ¢Ãøp:2ÐaÛ’¦×.‡ý¯÷šÛ:ò»¿Rwû‹°N†±/âþð-ãÝTçe 亮?ô 4}öŒ a.ÁítÝ%cˆXF<"Zk®N‰þœ%pð¥ÍË_Bý^ƒï±$“g‰r阎”t]>©Ýb9 Žkp«¥.Õø}w`§Ô.™/½Ùº rrºÝ6F± àëB‚ÄóÆß”L8KvPS¬¦Þ2è…RG2ÿ6S±¹è'€è[û÷è¾C›Ú;‡¢£˜¨_¤%2½g+´®¼rä¦Ámô¨Í\ñþe³SÇë®:—¹ßMŸ8’)ª"ôòtZ¡m¯ÕtG§üÑ1„úïnn‘Á«k½ÍpTqoÄ¥²Z0Zþî4b5dåÖéÕÌ2+ˆ¸çÕÛ<¤«w’ë;¼QX€—l¹ /ÔSe&VÝ7oVæ7érg¢oÚ¿«R0?ÆÂú¶ÞIz…õ=¸_úhmq…d•»©t,U–y> ©ªÕÙ™V¹—:L‚ª¨ÒáÀ?ÆDõ.ØgÌ7å¶óÛ'ÄJ é‹Ü,é}j`ÕŠò–KüÊÑe ® 4û ÁbªÏ—U0Ó(БÕµ‘¢xÝó`áF®Íл.n¢”$ù(UKAÜ´«Ð¼¦vTOcWq:áw¯UçÎÃ^NДòß³0z£hp‰…w%´_¥)½$Ò·Lz7–ª®G§ß Ó¹çUDî?ÊÉ Œƒ§h*¤ô½œ¹äÚÿ,Çó*]¹ÑEÇ´¦@ ý"'¸ð/[ðvL†ëƒGˆøc$Š“Y ¬%ro¡î×F'/`æ–œ€qr•!W pL绤…Ž5­¯º+õŒÃu²æm…›¤7´Ýý¨G¯Ò-Âl!a®lŒá}ðg ÿ±_C9 þ €_ºjÿ+0@Y$…EA¤©úÐ&X˜íH!¦¥¶ÓO‹#ó0:cyçpƒéw7.…ÙÈŒ÷BÛáf‡ÿì(^’f Ö·ñòqõ·r¶“yÐ%":»w”t$ʨd)úýb&ðŸ—(ñ–?ŠÅÄ…÷HýeÉ$ý®ÔÂÿF’í:šŸY> º©>–n±éU·xDûr&ˆ6¾ê­Ú@ ·Ïãï¿T7¬ë?‡üFœÓA¾4¦{fÑcýǧªÞ7éc·"9H­È=4¢øfp ¤‹ï*Á°ÉÎÁ7O¸›VƒÄú•£üv¯øe-ïfåaò ³g†¼ã¥®égˆbóÒO‰Qn¬? &%n¬•y¨ÑøÅïû!­9ý|ëDTð|·ËBÝðÌŽYW©-3Oò®2 !φû©–„úšäuÄ$Ôz3)íç‹_§¦RÖÇ¿äÒgEŽHUšA8‹‘‡ßÏ&ÏÒ"â:äÌ•!ì0Qâo!˃“ÜoÌøFíG "Ë/r(¢¦|È<óå.wæNäþsEîƒÍåM2n_ÁLÀ á6fˆdI8Ú$ Ó‰¯öþŠð«endstream endobj 1751 0 obj 4428 endobj 1756 0 obj <> stream xœí[Ks·N%·ý{rí¦Dï‡|ŠdYQ*Nl™.d(R”T¡H‰#ñß§Á£g˜ÝYŽXrJå*q<ÀÝ~}Þ÷KJØ’úÿâßã·‹ûϸ¦ËWW øgñ~)¬UD‡ÁIìÒpC¨ÿC™ÿ <|º¸ÿô‡å‡Ëë—‹û¿.Ùâþßý?|ž~·üÓâñÓåO°”ÿ<¬Ã8…$Ѱsšð)ëÐå“Åû T/ãŸã·Ë‡‡žr#—Ž8͵\ž.:žØÒXû8ØŒ#oÏWÿ^;Ž+ÊWïÖ žœå«þ%WN»Õ›5……”âlu±>PÄZçÄê+'%¨+÷Ë x<®ªöŸ³j£©'~UG¨TÈJ:5luT¦¢·hO7‡ÿ‘vuÚY S"Ù‰5ÞÌUDØÞ²¯ó8b븬zÆcÊ/µñ1l€(8/sÁf¹µ„ÁÜ¿dy_¬™%,gõÑï%ˆÕó…¾ÏÒxB'nË9Ñ›ÂË«ÌËyü\Û&¯iÍ·^,šPåµÖ«+W"˜†¸¤ym‘aÏC@á ãÊË+¢O,È^ñq†o†ÿ¨©Ú–ïafM¿¥Ý,Lk;VÙÁoišËuvRçÙq ™êœ,ºÕ…ÍÆÈ¸ C<àp^KãSë5e×x Ú’üJÊгy³æàë„‘›õ¤èöBV³ÙJ—{œRÓ xÏyòÒF;_*)Òåå " ƒn¦6,Ïö†â€ M9þsqø×ç«Cp|„;%“ƒ„¯àPY­?®TŒÖ8_ÓK}\ƒ4…jP'ŒQö¤VýkøCM¯^T‰Ìu”{¦».›«O ¢°äïÒýV»‰ƒN£ƒ¼®¦8©@ ~m¿{ÎpVŒ©e²@+5¦v`±\ÙY`—Ü [¼)E ì¥Õ|­Ë@â÷›tz¡€Ab@¹‰ C‡‡‘éç*%2±ºi_׬ñ¼¿¸ž/¼ÃWÕ\mÐOvF£>_Jã2¦ÿ9‡ô›JÕ¢ÜãåÑܲz€“¯‚*ëJÁø´».2ìú˜×{‘ß½Ù„b1ùð£ïJÝD‡ûøôî^eå£Ñ•Ÿ¯àè¸/·—_!„è‡ØEÁ”×ùé]7ê;/‰åó<~©Ô‡ 4-wb%ñz€›oÊz8_þ’„\[™åÑ{EÈ'y¸zœ…ü-Ö*–ãô—Î)Ï£ßN_äá7héÄ©¨lrRÔé"ªÈ&~‹4,ëA'Ÿï³TJ!ò²Rj„í5„NmQåã:Ï;C²èæ)±E@WebÝ¢ yb x>M}¬æQ-ŒAfvÜ*j£ƒÈκNïD»ÍëÆ Ã:îïd j!Ðþæ `ìe}?zVëèvµõ?¤WY6<ÊÆ˜ åW¼L;ªS…€ñ* ƒ÷/Èß2ˆ ".(]Ü.,Ø’tP±n6”sžÄB¦Ö“³ñ—Èå%r²Ë+Áåb¸ù†õz ûûᢽ ¿õøõÀvúžøi˜`ÚŽõ4&’¸í¬ºƒoUÐ:7º†ØEy"xi‚ _ãr'1;$>´ %UH¤œ‰|I_é ‘‡²Âì‰"”Þ Å;ã$ °{"" -O˜¿Oy%ògÃop½ßzíxÔ#ès³V2$±$5f¸t$`K#9r<’‰–)9F-žË. ñÄ£ž‡J÷å TÉÈŸ£•Pø ¹2\͸±nýMÐ…z¿# K?Zâà Åxy„’€NÉ z6ðóÙ${à;þ(ß–íbѦd[Ú»ùE5ÕE©ýgD=ŸOžŸ¾©(]NCË"½º‰ Á¸`¾bžôê+æùŠy¦ažb¨Y'w–üÆñ‰r|cÊp¯¢ Ìt^Ѫ‘éqLÅÊNùø¯Ê ä­°µw¿ÜK¦¡Êæ7eÕËN%-'ÊæFàëþV¬KS’nòšá<æ É?yI¿Êè~AO¥ƒ~ºëšãL(C,î ÁB?Ã1®²×®NëÝU‘ãìN(°›;Û¯¾ã…ŒÐ†pÁÚ?ÚV~·pG¦ÅÜ ÉBS~ë—ÛŠ0’*µ"šñ&\ì:KBcíÝŒlâF!Uh-©·áœùæN¤p» ÃpdÖ !8Tàf¤M=í7ÞB ¯É«ßV…•Mà8~™Ö‡³t¯~¯5'tümÝ­ Y€¿š;ÂwB‘q‡Ø†ޏŸ®·Í<´hæ<‹f€åÀ½K3jË],ô¸LcBäΓÙ$3Þñð6Þé§·A’×J·6&o܈ô³án[/r¾ VÊ‘”ߤúºË+x2\-Áã!(ŽÜä ?I·w·DÅEKÆ®o/ß._¹€#²»¢dϘW“G6 ;B§0†“4š* QþÁ…·+ôNIh5=L¹'ÄïÙ 0çb­ŒçËJlQéen3ûiñ?"4ùÊendstream endobj 1757 0 obj 3283 endobj 1761 0 obj <> stream xœå\Ko¹67ýŠ93†á›M›CÁÂA.I”Ón²^,´z¬" ?>E6E6gºå)-C4›,V?ëAû—%lFÝOø}òõàÿàšÎ.îèìGøsqðËóCfá×É×ÙŸ`˜Òrf‰Õ~PÒ©~ج3„ ÛÍ £„Âǯ?ÍXHÒ ¥äüÊ·dÇæg¾æÇ©ïv±Ô¬#º›J}—iÜ}êcaœhò* <…ÏTÅFÈðØú÷Ñ_¸ ±fvô·ƒ£?ü4?o°|h<¦¾O©ï2õåîÒ×À“à¤Ó|þÐ`ù®ÒK&㾆É\"y¯ÒçÌáaVÌiŶkø–1N^Æ£¨GIÔÏ uÝe’'µ3»xëÉZ¬a|ÚF!.‘òüdÙñ0Ò$ÀY\ÙMÀW¬ˆ~aÚÍ/â×ÛJaÐõ7éA*„ÓbŠcÀÂ0|¦%ﱿXJ•F®KE:KAÓ¾ÙY+BÓ÷^-(SŠ{þp¯˜+i†Wâ’MÓ~Ì‹œ/–\[µžÿnÁˆåt½]p ’<.–”J¹t‡,1q™W†¹‚‰]‡{a ¸DZ×D)+%bf¥¡‡n(ðjÔÓ «Üô4Õ¦$|K0¬d&5Éb)`ï‚´š ,l%Á’ °Õ™À•eL ¹Ò¢«ÅÒ†8¹× úšPÔ´ùgpâ:F(,@Âqr‘9¹HW™Ò™Û€¬ujçœHؤù¯ M˜LGF¨÷¶WƒÓò´èMü]:p"?%ò£½Îü¡ÒÝdžý“,3Rïwl‚Q‰urê˜îHÇ,’ô6lšˆ¨ñ Ôš¨tR § ÍœÍI\!U]eYþ?Âdð‚2|ov6šÉ 0­Üfí§fò6C0+×¹÷!7o‚>¸˜ÿ<σ ‡²Ól ©‰1zþÕµ\y}¨,O›*–3ïÇ2¢cén‡›ln³] ³¤’Cà:WyÒÞÏ‹tVÿÜrÏÌ­4]Ø•Ú9¥ C„Òó/âàR¸¤ÖiÒã‚1'TÍ'€ @ϱâlÍÕ‚ 6ЄéÂ(üù ›ªžÁÑÙó¨{Àp•:#%®ð$´ÛÍÃæ´6G©pã¬w¼àÒQ¦K>×?Ó­þTùÊoQlå{ù?©ïvŒ˜q—|°à!9ìÞ?~Íô.R_nµ|ÃÆºÇˆòÒ×2Ùß*]¡·.ÕqÃç»ÊRVÝÀ[ÿ™‹ÜŸìÞ wf™vÚùÂeýNÿ+éä®âCyG&¶2¿b_ þRÈIžõvJîÉ(>|ÄÖïÓ×z8Zu˜¼n4ý¶¨‹óìÍNŽ}.‘6Òl fÄ‚vml䦛±uøÈ:,®c!c6ÏKŸ»p¯ÏbWRyàºÎ«­ND=…6üý¤÷+ð°dòãóÎcª‡UÌiÌoÐÅ‚à¶\(ë¢ÿj³$«Ø(4î0 )…ÇDw¬B £Ï#iÓ\ŽÆ>Œ,#YðöÃDO6f§iàu2f)u²—QìuÅIÉæi48 û–åý\ÌÞEì:1þŒ ÝÌ&ô!´¤gˆ§Ðu2\<®qª”¥Ç:/ôiÈõ¯Ã‰S£f) L LáF‡3Ä&TU¡cðR×ÅÊ\R”îðΧ9ÑùäJmë|ždnÑ¢Ã Ê øRºŸ\AÌèÝWõøÛf]Ü.@ìš.ÈP8í.|”ãÑc]õĽµo†©éx–pJMÞù¨¥³íè…·ˆìy`Œy«º ….Æ¢uÇByŠ3|ñYÜû>X–š­3RRÒ‹¹ý\rà\VѲßAÚ0¤£”É5qo!¶§d$ڮ㬋¦‚NÃY†#ÏUß Nˆ`Ú­¥ƒ­Ø…î¨9LI¹è· ±QB¤?H·O®©iP²¡’ó ¯a¼ƒÐ& È>! &/O½˜C\Úòòëx¦Y3@›™~­}Ÿ:ÿ”o†.Zr¹Ò­ó%]k†7³»È'¬\ÈUõ”/Ʀo—2Ä-'+Ý‘µšêôù›ß¾ìgíÃö¾àÆíC{þãL7/•ˆŒíhš½ÑmmÅtÙ ¡úOöxs9¦Îžå÷±ëMÀ`›S<^Ö~\zfÜp1Åd!]ªÅ…Þú0¹Ø¸ç`ÛÆæ| ê`[ý9ðÜ–…­Mœ[ D§ã¯s€Þ6Ñ÷~¼™œÓûoúZÏ(ä)nAùcìCi½´) <}.w®?HÁ°æ¥Q¦­J%¶§ò†§ù?^¯}6 N±Ü˜‘±œp»ŠÐy¹ŽjC†S÷µˆÜ=‡Üú4ò¶KÛ]‘óKÛ?-ñÙ¸šcj.ß1¤U4J-Ðx>äÌ‹B.Ýp8]Ùb|¢õXjÃ,[*W¤$yu1Ÿù©lùž:#^jýJÉ <ɉש@ÿ&·1|m]à»IÊ~[tY@½1Ê£ßh—èŠèß•u T÷]Ï|·-ºš~âfgo /r'ïÖ"D'[Þ/d\³u;Äfál>”‹±zof*7• \2Po¨¬Ð÷” GñšXîcÞ~ʃ»IE—¶rEΉi7EV»,,Äb~¶âòþÔòaâß•òÀB=\PR1wžŠ ›j4³ï¼óí"ûÞWx‘HÍœûhÝ! ¶FÄþ±#ÑTÜmÕ'ž•ÈäÝûCå$óv-dj ŦçUÂc¼JÊÖÙ¡þ\î>·ª”N«›X/Þ•m|7åˆ9¥tË~Ìc󺨺€J÷ž‹¾ŽY4éå˜x>bë ~×ãQš²°âᆅ)›Míš ~±' Œ­^d}—Œzj[U3Nú-—ÜøJá,5^ª4µ~©üì3¼îëK…-CN±%$Ra;°U-óІfn+at‹µÅÒ†ázÖ[;f(1ú}Õ†VÕ¥6îŸu–(>ö7¢lÛØ«gÓC,óðEEYlŠz‡‘ÅÛ/+í|ç×öpçK¯B¾#ÉùL¯[uDu]éuÇÐ,|û&¾v„‘ñÜ@ÀÈ3#œ=€ÔVõ«DÚ¥¬‚ƒ"‹Ê2íw…Óë û|M§Þ-·±m ÈõØfm#ªž Öݽ|R£{E¯WqÓê’Xf[²:á¡g±|L}]çü#ñÙ2òðÜ‚çUË^û[,Ûà<¾ß`©ìù(#ÎòæÔo´ŽkZuå;›—4Éa½÷‚»ßxǸ{¶w”Hip¨Ö~æP@ðu le‰+ظË©gš0fmø_,xJ²²œ–Ö±Ó‘ûËÑÁßáçómù­endstream endobj 1762 0 obj 2585 endobj 1766 0 obj <> stream xœÍZ[o\·š7ýŠEžÎ^–÷‹Ýhƒ4pâ¶i£>9A ­¬µ ûJ©£Ÿá}x´¶d' ¼ ‡ÃùæÎÙë%lAý_ú}¾÷çÿrM››=ºøþmö®÷X˜²Hÿ­Ïß÷ÓŒ\8â4×r±¼°…á Ã(¡Ðy¾÷z¸X2⸳|¸\®±Ö91„¦£JgK 2”âlx³\1¢µbzØÆ¦„ ·Ë•$ ’øiÿÛ ûrI„rv±ÿjoÿ‹×Ãþr%wJ¸ámÝî¤îq³\q#ˆÔv8]jÂ4W 6……5n¸«‹Þ-ÙBaÅ·Y™áÈ ¢Ðmýi²ÞgK&¥Ü¤åÂ(<ŒÄ{E¬"Š#™È·Uå_zÛ_´’4#RØáxiˆ¥”ÉV'tzA”¦Úä­4," ”q"­^FùL ovn-a¬@À^Q– †áæå’ÁL«4œzE‰¡Ôêjj0A:‚5Qe9ψz,¿m5Ë-–œ8¸U¼Z†n­ƒ-¸ƒéRÂ\ï>\Â9ÁK÷À3«RgÍ’¬ÒÉ|[V!³xcM(8C×Äè6Ÿ‡RI¨Hx›Î{‡õÜPH$à(‹ãe—u¦Ûlqȵ&à<ÃaИ8øu¶¹É%„æÛ*)ñKmzi,BÖ>NÓ¦7Þ¾r´pd© Ž¡| IØdÜâUÕ|ÞKVÑMVŒGGécéM Q–h{€•p’å¨$J‚ƒ4@ШWb`ßs¿ƒãJ ª¯ÜzÞ‡‹6îÜú¸(‹fžÁzˆ TÇÛ¸'˜ 1&ܸv…Þ ê½h¼N0 !‡Ï<;FeŒ!œÓ¸ÔaÈI•z›”e‡€àl¬Å.pÖzŽÅÚ‡)®( ’XFª†™ íáü:[Åw"l ÏF÷ŽÜ5ßVkì> Ž—°Ä[=ü©Øzí×Kb¥˜!ù†¢`;|™§Ýö‚{ {eUº€ÃAèºK˜è莺±$îfoæú«§Ž(çð\¤C$k®ÕÃ:NU€¨’¢Fp‚ˆ²–²ÇÄŽ \’èB»™(Ò&M5‘ð1Li5Î}¤#ÂXœ>xr•šg2ÚFÁÉÇgŒ£ZW¼­«._ð„…¦¥]­hJL!~²¥º]´ªœQ§üN€2“üÎæü¬Á% &G¥.Àq›óO¥›¬˜D¥ÄH—/´`ö˜ú/cB…$×·¤õ»å¾w¥uZ ’çÝ–ÖM}^ú.FòüèAé«»½)£ÛŽäy4eÖ³ù¼¦žÙ¶Å”ÈñR¬ü3Ø[íº‰ûÎÙº0pMú ²uΉé'Û]žŒž&¹ÓÅ©¬šÁ3dñ”Y¼ýñ2Å„i:”‘P*ÒM=ÀÆÇŽœ¡½tË.œÐè €+IüýoX¸"T9ü³@^>CÎ\Â\Ê0êòIo-‡vG«*£ |ùT©L¦•€¯&É!Š9>cNP}¯ý†>‰–œÿZú ç4ëMÁ§“,ø½Pc²Ê°mŠ‚.oyêqçÊ& ÎW2—ÄO‰AŽ2¶xÑ‘’0Dýè8ýÌþª¦Ý$=[À…ê­ÔXß“ûyƒDZ_è§â£§6PäüS;ïIžÚ€^¼%¬Úö2j´Á‡s¸ ð¶Âᓌ9R8bK‹¹„Ð0ÕfNËî»Hc蛶˘?ú-åÑË2º®£›<ºYÇdÀ“ðžP~ßëAú°Ÿâè×°HAp×{_Îg¬ƒ„øªNÿAI˜Šã^e>êHHÿZÔ@s6 4ã§R¾Ä[d¦<ï*ŽÂþE¾+^Äʨ,£¢.^õœl,Ñ·îê ÔïŒþ8äáó©‹–Ë­!îóÜõ27þYÆþ–»¾ùÒ@Æ%’Õï)RO¦šñ/P|à¨Àºî€ðÝÂß½ÑçeôóÒ÷ïÒú.©/øðj4ì—|Sú^–Ö¿:_¤Ð¡v „ À~¬Ø¸Õ¼t5¡¥LvÏ~›¶Qm]ê?#]<+Š\ÍÝ$8׈]ë Þõ¾èO\½~\bÝWÞ³|®ØçèÓÃ}nôpgù–dŸî¯Úù~Ú¹k?7ZˆvKÆkâDñ·â×oîëè|¿2Þ„²„òò™+VÃÏJf2Èáï'ч”)*V*È7ÕˆÑð°óxgŠòÞ3|¢]"‘Còæ”gˆÈáàˆ*<[£˜óo*`ha„t·—Å^ÿÍšÎ)¢B1žbRó`ሪáXÖp9û­_S~ÿ·~Túž”õ|½ýºžïy\îXRô…2afÞç}ˆ;¿ˆó‡Úø”ÇÕôi­`Tn?MÊÀ{¶m*Ћ‚­¬“­Ì—±uøjés< >ð},RQ1S»îUÛZdGšäºÈ¿è­?µm Ï! ÖDš(å¿Û\PÊtSÙU”µÚgá§&^ä?–œ‚AY³Wô«•’È¢ävôK–‡sV.T.@ÜŒ˜KWžÆš¿tR¤úF?/£‡ø³-£_ŽbæY>§‚hù´Yþ“|8¨Øþµj€ …ékûQkôkˆP‡k¾O^6Å·Ü> stream xœíZ[o\5–x̯XÞÎ"ÖØã;­ú* ¼¥}H³i•\šnI[ñãûø2>ëMv›¶ @UÇ×ñx¾ïûäåŒ31ãá_úyt¶÷Õo`øìäÕŸ}ÿOö^î‰Øe–~;Ùݬšyæ 5Û¶7N ffVpƱòlï`x8WLƒòfx3_hæœ÷r8ŒEϵÎæKÊ—XðRp5ü>ç8­Ö †ãùB0c´0OöŒ¦ º&(&µw³ýŸöö¿8öç ÉÀké‡çu±Ó:Ý«ù¤Å1gF#¥³>Ù9,Ë¡] Å<(…†•©ZË@rФö¢ö%ÅcÑÙb€”󰺺éyÚ%ÁЊáFó®”u÷ř¿„vÁ¸Ôè£Z¬kžûBãJÂ1ápû×óg–sg²ý’Ûâo‰¦,Ë'u‚°kœB9HÓ†ö×µ=yM9<-ídÒ°?@³]Þ46£#@i& ¼T2¬d^9.ǃצ 6ΜNñæãbf´ÃyÇ ;D?9©ñDJéE,‡~KÊ \/×ÝËu)Î0¶Æ#ê$¶ H´p\F†9«…ö¢¥•j0ÝZ1Ö*ãÂ0ï5Ó^—cP0Nñœ¹ ap>—a(<…\º˜ãÑižê¢b3Âñ)`ÚÔ•A9ŠóÚyIc ]‡ô8 C šKoë˜ë9:Pj©'ñ‚~&f§ð4‚) ¤×uÌ+tÖ‘ØF'HÅ,ºcÕÀ0 Ø …Ð÷y¿¹6u0Ò¬ÄÉð*…–$B¯R„Zq<ˆ„í2ÜØÄ7,@öøY¡¹£q!òiaœ&ˆ qŠÖÓŠÖ Á ÖtTºž”"–žÎCÄ€EüH!½¿Ä0~Wm>®6'jm+$H-ò$ —„Ã\ßÍ-uÆ'÷EZ½gU”rPl u­äÀë‚îÓR:/˜^œ_”ºëRWYà ´~^êž”ÒýÒz^ê^—ÒYi}ZêŽK骴>@Ì3 I¼C5}Õˆ*÷)dô¿«XÆ#žô: F@o¬ËOã]ÁÓ¥R×%]©ä½Ê)0oÇ‹ œè>$dtiÕ¥ÎudµÖm-° “:s7UU`‰¨®åÛ•Ê]/‹¾ÏI…)Çûk*‰ Q””ç&^®CÈ~!UÈ7öÛ©2Ìq3R¬ECHJÙnzƒŽ†QÎoÖÑ)B?„Š?Z5üP׬*ús@‹DÈ‚{i«­o‹y—4cÍ“þQϹÌ' —Åá¯GE5¨z& ê.*:üDT*LdG˜U&X•ÒÛ‚áˉ°µ)ôY)v„ò~)=(­uÄa)½é'âòÕî.&t´üωaUóCk5{ªùí¦šZ¯ªÒשïåæÛ4¼gæS] ‡çÕ9[ržî²—$¹Ar¼nŽy§wà†Êl™zwVX­L¨Í6sKW}^¦%”sžÙU\ÏvÏ @Ù"´wWrYZùîºB2u7Ý×]Ý?Ê¢%w]¶º¯¹Þ„·=0õ3"œ$J—í°ƒ»gáú*ÿÏvÉÈ ÁE/ßÏçÃõÖI€z¯ @Eù˜ütò/pI3}-«éÿòFð\ùÇ}F¯Ls€Ýíüæ-ÓT&dVx?óˆ‘ð3žÐFÞiþ†CÇ~Á‘ͤ÷‹P§o´Lp¼³B;á£Ë.3T–"²¼êª>v•Â2%Åä*.ex1núZ/È Ü  #=®ä² = †ÿÆ"U’Wl‚÷0\ z„Úõq±f0bÔ(Á35>3áðnr“Rã/[‘›¤|·émqÍÙq‚õƒÁ¨Öæ# T>r"êñôb´ §]¦•€kë¡l_û©"ìЇ8J{î’¼Z,½©=‰)$%_5FÑtÞèA3n•@I’M¾™„áçu)ä}‹yp†¯S†ú²ÉÑVˆœÞ(xð%ÆÜð%¶lw†T’ºªË®g “ô3nÑr…»S oÆäg†„pn]á´Nõ‰  &W!êCºÒR{'smï$W÷Šdà ƒç1Í!m#2΀¬»&Øa…µÃ-ÓÚ°q5±†¤lqZãIö´æü”Û9¿Ü-ò´ýpJ!•óÙîš½hú]ûN$¼©l™õ`¶ç7<}(¤[ÎðˆpLå»U³ílÖm;\…˜rÈzã%‡˜€®…Iþj‰bº¶ÃÍ-4Š-V¢O‘ÚÛ„YiL[a†©šºˆjl-ÞlÆÂª¬`íd†þfš»vü,¡ÃþÓð“ä.°½Ý¢—¨ä3ª’D4ª„œŽÖ«H2x„ÁÞEÈí¬·cÔÜtWŠü“¯XަÄÏÒUåî] ¥Ÿ*óã]Æöo8O[>ˆOö>‹ÝF(Èæ®é•Öx˜2Vú^¹™óÒ+ñMÚ·þ•>···sKîÇ»¿â‰è‘oÁd#>Ö¥`܉ßüåACxB´°#!W D¯i8ìk>+èÕdâõeWú –ïÖf»<)_£ûïA;ÜsWÙs !æ€u¾}"ïIŠ}Rsš²ƒ§Õ¬æ½.ò|Ì,3ÏosÏŽïif«{vĶØBq:›.ƒ°þ7'ù¥gHz·¼–þ®€'g×tT†÷÷~Åù¶endstream endobj 1772 0 obj 2121 endobj 1776 0 obj <> stream xœíZYo7.ú¸¿bw ,ÍûHÒ<äh뢒V@’¢pdÇ1Å–mµi}gv—ähµ²åCMÃÁc8~óÍ ­yÉ™(9þôŸÓY±÷«´¼<¾(xù#üóB´SÊþc:+ŸL`š±º ,X Ÿ“wgÞtÓÊ ™ô\”NpÆapV¼®Njͼ2FWÓÔ:m[  :l[Ú‹ê(õ=H}³Ô:I£ŸRߣÔzœFóŠƒÔúGÿ˜ü\H]6B–“CP­ISDÝX®™ö’Hý>wŽ+Ò1¾D¦N“–èØ‡šd ÔÌ»à:zMÌuz$¡Ÿo®‡¥z 5~)&ß½®ÞTËã\jÇÆ ϬQ`¹ÆΔ ×ÜÑ›:/z&èö ­!ÊF*æ=­î›¼ýboGÖžS(Dx>è¨uo³Uc•d^êÍïË,Lߣ­ ¬†£‹|›FRßZ«‰¯Âjv{V{¼ «}X[â(ˆ n‰ìEÏôN–Fi¦lGòÏa‘‘:´ldÀÈ!(`lvÕÀqA‡ê A ®«5±ÆHT¸ÌZ#luQ+fLкßÝ º»Äyâ«IÝ(&ƒƒ½ÏÛždÁ5\¹cÊ ý!&)àÙ^ÃV­ƒ¼ñ¬n4ðÖ bµ¬£Tœa“ôžæ¹¤ù¡kz—Pªz‡@„]šyŽãŠ ª Äi<ÞAµŸÖµØ²{È,²«4ÊSßÃ,£0ûs"„R˜Ý©´"u`*è/ˆHi@G»‘Ú0áì“í=ºM0iãRn„I<7_ “ÿæÞeY P±G½ãÜe ä4xÐéHhí¾Dó–Ð,·hù–ðÁµ5yGù›èŠâ­¸7ÿ‘@GòîDsç8:LÈ7u/1¸ÓAˆ0Ñ+«Ð*ÞðÔ`6å€!íh¯èzµõ8!ÃL0p\pN®åÓðªàu†«„J8ð3…d|žOŠWżl º¸PÁÁ ZxX4=Ù/öö_”—ç‹£bï÷R{?áŸ'/ŸÂÇþ³ò›âù~ùjm)µæèB+ 9zz¢û!Õr…œ'f:)MðÊÆY)†k(AMWÈXEˆš†Ón``®h÷ašqÒü a=xE´MÒþ0ú+0žeÂ*A#ÿ?ùð×`ve”p_Om(G½©Û‚qÁíyMJX¨Ó÷jxn)]%2¡Ìø>;30Ílô¡§##a#7žRÂ$„ÝÞ(äY™vήۀñÛ”M‘Æ5³BDÂÇ];Æ·àlã£¨ÌøŠN}†ºÀpÕPJÎe6– ¢VËÌÖh 2È”³šË«P=kow9@.hnP"[HÝÆ5[d Äè£ÂúRß0RWŸåôš,'yœ'HîÕE å uétÄ”ÓvLqCk±ê’¸fÒ¢wê®@½MÚ¦Ýÿg ¥ƒkÂÛåøƒâ[óm}'…|)l³çe˜Jp bV(Ó=Š|7!v¦4öUñ‹î8endstream endobj 1777 0 obj 1785 endobj 1781 0 obj <> stream xœÝZ[o\·.ú¸¿âô©g /Åû%Ô®ãªHZ;UáÇ0lI– k%Y—¸òã;ÃÃËð,W’/0Š"pD<ÃÎÌ7îû31pü/ýÝ_/v~‘–G ><‚G‹÷ · éÏþz¸¿‡Ûœ VZ=ì½^LÄàäàg&׋gãÃ¥fFê`Çÿ,W†y‚_ÆaàF륀‘ã ‚\ÇKd‘b<\®³Öû|ïï‘5AÏ”š)ü°÷Óbïγqo¹RL£Âø¦ö¶’»X®¤rðÊÀ¤ò.$¾"3/ËqÀ×J³ µÆ ©–3©8Ã!™=­{ÉðÝ4ô®0 Ôø€«nvžãºb‚rrsÆ3¯ô¸[¾yP®õgX‚\ûñ1~íYðfüW¹Ít…Vùñ}á㪌ÈòI™ÜŸ&pTä ™OXÞ¥6LX9ò2É‘ =W“®Œmìƒ3o’‰ɤçb° ÷“¼¼2 „ý2ZÇàH{1¾(seޗÕïÊ/£{y5°€kÍÍ ØJ2MŒ)¼ ïŒ(!hZ9ЄíΊiV[?úå*ÃL0 TrZ wJ¦ 7]³Þn˨ á™MlÁ’…F ÍIn™u¾[ZÐÔÖ?VR– »2ÊÌì/؈<³ÒÌH¦`ÃUýêÄ2&èblh8È*gðÝxÙ8ˆ”’9àj¿šx+a¦@6¼KÄà6’ߣˆA¢ßHÁ¸Ø¯È™ñ—è$tô¸¸ÃÜ °öü²•nP“݈N~­¸ô ö«Ã—ݽ§•lu®»¨"WÆßˆŠ ©ó*`¼XË­KD#ýÓ% ø>XëÞXèI=%Ѷ`u„9²!kÅ9Ï{7JÄl•Ú H¤™-‘O[=X¶D`²5¡ª=½ª³ƒ-´5.ü£Wz’ ÈM|ëñß肎soÅø2ž \¯g:(.ÿ…|ôÓäy^[J ±‘oÙ jâj.Ò' *!©ÔÉ„™ aÔ)€ªdVÂ1@–0©÷éRƒÂ`‰^Ãd›:ðuZIê×€ SWŸ"‘ö4ÖÔ­ˆ4Z2£ÑJÁŸ$çŠî$A°…æ¥-sá†ðöª'ɽɄܦ“´ŒVðÙp<4>´¥™³âÀ 5Òu—˜ [ÞÒ%HTÞ€ƒˆ¾`V¯X8ÃÀÇ|e„÷év¼”3ʧUéÿ\ºS¾'“÷ >IЂÃxÀxUŠî‘©—à?ÎÛœ=Ä u^m³¤$%¼Ìº½ma0$Ù)\Ÿ—ìál–Q´YÁ÷eîe™;›põ¸Ì½-£ýη—³}¸zZæàÆ­31ñ<)“WeãºÌ½š%5¸z^æ~ˆ#cˆ…{öG>Ësß—m¿å©Ã<¨$.òÔÛ;ÀÁìf)ÃzæVÙDPsá(‰™l0¸S>{¾±é^t}…¤š:@°ù¥Òõ9%"½5 ´cNIÜõxvÄÆ¨¢~Àài¤'feâG)hoT]YÄÿ­ª+Eˆ©ê²[ÓHÖšÓ¨qÚ $5$Xß&Ÿ9D="yÈÃI[€`Yq8¬,ü³It,€ dùÒLxK 'ó0%,1œ8ȶ²3ÕÔ“ðŸÒcÜm¡Yk ™Z/ —Qåÿ-Ø–õT+䞥U' úž”eˆ‚–ƒ¾ÄÖÕôñŠ jüDûMŠ8ÊA•"{·(«¢®þ:nÂmA³]ß‘OÓoµhí¯!~ZÁ„S\ïVT AøÅ¯ËO†%Jiþti9ÔSº£óèÉVc@Ã4<øYŠ‘'ŠŸmÅ¥ûøkfÐÏe¯*ÉByÌ·•¹Œ¤^ýgÓRÎK|Ógö:æ9M ¨f–`‘P/€?;ŠKd+9à²É$_`_b¼Mýú´6Jäè­Û3¹ä»»‰îQñ|RLžôRλ(®g¢”îqëº5_ÜlT˜õf®éAx—[¢-ä3hL dÔj•çxŠˆ-ŠUÇ´LÎUË”mb=Ù‡îKÙóŒ[ÑžÐ?ŽÞÝVMPt¾®1¢ŠCªèõ¦Ùæêrº}5¯oc-Œ·©¡Ór*ÜDp¥Õ¥ ‰›%kÜ€Ñ2@j­Ñ?æ+Pô³ZÉn•‡vjt­’2WB6 ôæ&TÌB²‡pÙÖžN€Ãº!ªU÷½‘¤&—‰Vø o¬¾¤e°äÔŠy9djeºMGˆû2·¯?³Ój§ñ-æ \‡@ZxìýœÅûAÙð ¦6pµ”ò{ûëÅýÝÅÎîÏÃåùÕábçé ;ÃÿÝüþìþuøÃâáîðäÚ÷€N;U ’X<‡™”èÖ6èùÒBlVžVy.Á”•Ê’ÉnèXö„جðj{–Ló P;§ôšx½¦à1ÀáÞÖW¸¥V†rK\ б¥Ï·ÔiËö»%ØUõ÷Ë»¾™P¿×3/„‡ðH €‚·oðÚØ¬¦Éºs’"ðQÅ2Û d4sRÀ£pÛã¨çß­q_QBܼ±!tÙ‹D¨:‰ˆå,ãÆ¶Çw:É <+cðqÅL­ŸØ)ä¹Ë"À£œ±m$…Š©©·’åì÷´k—3!A­³çž)$]Û5Ž,_Ϋ²8»q'&^Ç •îxؼ 8S:R@9‡ì¤Ù¸ác ± CÛdŽ—hÿõl~Ù±iKØ%—ôÇÞ“ÚA çm°LÃ)ì¹½°GR[ëHŒ}€äæ3‹™z¢Ò@ÖºÓuý¶3ÇÀÛâ̬լښûxnSÈm/„d%¢xЂߤcˆÁÏÙùËcí¾ åfÛäjûzµ@=íôŸ•ÑŸÊjmŒýPF¿—ÕÚ{^;†u²²µP­½ÃÃR7ŸÖB´”…_ÜÒ+åäMµ£èÉßæù ûÿwÏÿõ¡ÿ‰­³§~#o‹Ûê¿D”×KÈÛÛ-A0‚pŸÞÓ¾ýìžNm£Ÿmï»Ìz5×7znÕÉéRt®ßç©Êmšz‘sh(­jç6€¡4~šGyj½I3wjjóæ¦_-¨c´þô_-Èš{óZK ­2m¥OmÑiÃ?B‚Åô†­eG÷÷:êoìGײ'Û0ØæôñÌ«¯ Ç®õ¤Â:0Í©c^mƒ“Úuš0BšY~9 hä}ÓÍÛ´:¶–¤¹2þ|Ǹ˜ämË‹óÛoM¦I:wÕKg¿Âï½ §žUÚ6^’r¶åeêýp,¾R’Û劤}$$IɬóQÞÞ(ö¬‘NK¼ß÷øÄ_†LO°¹ ‰¡Ç`›`±JoôÆ»ëtK«’G}³wWЦ‰'®ãƒAÆÿê¸jbQŸGçXWS‹~,ƒ‡ópiB:UEÉz£å7i¥¨²ø/™²™zendstream endobj 1782 0 obj 2673 endobj 1786 0 obj <> stream xœÝ[YsU7žšÇû2ádžÎâ í  $a¶„Œ«ò@R)ïvm° ?~Z:ZZçè\ï5EŸÒÒjµÔË×-¿í(aõÿâïí£Åý_¸¦ÝþÙ‚v?ÀÏþâí‚…!]üµ}Ô=ÙðÃŒìqškÙmì-¬3¼3Œ G‹—ý³¥$ŠK§ûÿ.WŠXëœè7ç£JöGK_Òõoàà FeÿzI¬Rœõ»Ë#Z+¦ßø{`á5¹$B9Ûmüs±ñ·—ýÆr%wJ¸þ ,vXÈ-W\˜£20)¬q‘¯ÀÌf^øZI⸔ÀX&UsÆ%þµž”±èóÕðiMf@ˆ~Ï/¢®Fžú~Aæäx© ÎÚþ#ôJMŒ‘ýyYó4B“ö–ÌË™ìÿœåºí§s¢,ë?,W”J­fITÀ]”¶6UŽÚ¼Sa⪂šÑ¬@Îð?y­aOŽ1Õ¿Ë##§L Ï‹_JÀžÑüçeÀÏ~UKœÑi[~ìq!»…»¹ˆ­ï–þöpä4ÜѸ—»…èÙR¥,çXª‡…æq¦¹YÔz’‡GöÜÜ®Ð,+¤#Zg·¢$[?ðª㘗xW¡=nË0n{³ˆ“T›Aw”®ô•«¢Ê:N¸¥¬ÓšõvôÖ ¥¼:¦¯ÝðåÙ8 _2È~¥™%Ú†RhŒ¦’HË#ßxœ'ŒSÌ|7ÌV¬_åÞÇW¤hLìõãA¸Ë¿õ©û,wçGéc7÷¦¦7éãaîûmÛ¢isÈàúÕ™CàD© <Ö(æüñÀQ #d¯›­|h• Z¶\9§ˆr*Ü"5¢gÄh.üqphdÖ›5N„tÒ÷áƒ-ÏÀêXÏë³Å‹ÅÛNèÀ"\Û1 ä©õ¬ú³ô~àÉóÅýçÿêÎOßí.îÿÚ±ÅýýO~~ ¿ž×ýiñìy÷b­whˆ”€°J$ï¶YGÛEŸa¨¢*íŒ fú-P ÷7ü•.—adÓ}¬,f¨èVÞ‘hÊÓÐv#Éžh †“ 3¬œvÈk5< h)>Нˆ0ã¡Þo>NÃ!PžÝtq"mæ»¶m~·µ78†9w¥÷Êû30aØ,“>,áÚ%ÔÈ/Fö¼Ù‡ c°Wx]Œækl‹Á$0 ¾{»ä¹ò’YEž©¸+D+³/±…>I.Èaw‚|âq«´6Äb±ëðA€T #îw+w‘Îù€­ul+“.5ØñþiÉ4XïŽ#T`¢hƒ§ƒã”ζá8ÑöŽž-cX–í±Åß–Ew›Þ¬-4 IŒªÂŒèpÁa m½]Z (¢3Ü«AÑÐvjñ1êRCÐ2x©±Cæšw`xŒ5,X#naMÙ­èsn· ¶ÐY,& ´ÆQ&9¢;U(ÓÃøo–"º{ªëÁ‚îDv«jô¿KB€Ñúi »”Z9UÀÐRùO¦ÁŽCJP ä<¬dÞ\n§W2[Ÿè0E ¸owiþí šñ¬Óws?o0/¶öBk¯¸Dy—ÖN°öxË_ÐÚ##Ž€Ô$zÆè)FÏ^é4›‰“«¡kl„öñ0ÀÎõï½Gà”VÖè°é<&–{Ʋ‚U¸K¥ÍHyax_Te…1KTkã›ÎCŵ¸Kâ®q²ÈoŠàÐ 'Ñ䃋ÍX©këÌøIE“sPh3àáåH@µÇ øeÖc¦i;e@4­àè°ÂÆEq£®i]f žtÖkðíËíT lÙDÐÚï—· ¶ú¤¤,NyHœJAé•ó¤é—Å€Ò™™Ÿeàwž¿N3æÚ(ßv”ÛþÈ_ó3dêSodeÜQîÝÊm¯Gã|ïÀGÒQcûGîãÐÍŒC c‚¡WQ§Êûœ{wJoƒ;æÞ­Ô‹̽Sï=£Öáà‘ÕŠ^fà4}¼_ÓW¸Ü®7¡ñ<ï8}œç¾Ï©i+¨=Xðö2éý BùqÜAúxœû^†]‚³as fàÙÊb'HX“,˜“ñžòJ¿§—y´'/ DY±g³ Že Ø7'”ê%ü´‡5”‡À¬¡ŽÖtÒ0ŸC êñ—¬eMpé?}œE+P)G!‹h¯ã(]F(9åt±—©½7xS%kr’Õ§(MK÷NG—¾šòÈስuâEÑ~Ñ&&yÍfª+¸¢óÊ1§Ö”L{0D¬@½âË*œ•¤goŒË1"zî7"ä„4㊵‰ÛÍ9…+G+xŠÒ•m`]Ë5m6q ©0(&lÑU> (\“YØ6$Nä( á7”û,iÒèÂ) ¨¢ï7êý_ ÿÿ£Ú€1Rп×pØgSå–³VüÒ{z×+¹‰T«¯Óñ1Œ¾ª’û0S©+y ¾Q@Z¥eÆ×ž›uF ¢¨nSǯWhiGô8‡3h•‘h{%¯t}$Ê:Å2]hým¬µó—ÑŠÁ{É cÕdp®¼[ ˆjE»óZbHµÄï—LxùƒíA‚kˇC,~aù0éD5¬Q KÍ_&e‰…+¶3SËLÈ|ŠUgาØV=ÍÒDiÀ+ffrw‚ÍÁ7”»Û+wxšûˆ¿ÝôC‡M+PnfRMaf ô4]–îJEÒÁ)ý¢@OšÔíFÒŠýpˆ!uïGDemÑg:/.|‘(òE‹¼iaç'DìU*ëþ—pö#^œfL hªfT¶ MwËè†Ù®©û‹Î`bIô$¸Äêh¾§‹&OÿÀ²¡’óË"\‘'·×­rO¸Ç½¹lAÓæ^Z šwYåÜ…îÁLJÜ÷`‘ hû#5 fUݲ“IeL¨Ê°qØaÚég,[Í;˜,½“û˜H(ã…é!­%À¢*‹Ôv¼ïÝŒ§}YJ̓xj¢åc¥5û%@õbÛ?¦1Þ„”­Ä ±9O}¿ÒÄK‘ÿ!Z$'@šç;M¼ÜCê•{›IÜÛHkÜkôâ<Ä”ò.[îÍG¢¿àÊ–›Týù—ªú¯î–*.k«þX&hG‡¥\ÿ)öóŽ.Q¸/ÀÖî%&E/wR¸÷‹ASw[ÊáÔÓ‡uüqE9¦-¡ØðSa>î^[y …wª6­_Á…Ê{І´ƒ(l¸ÃFi†Ê»ƒ¸D˜KeN´&Sd¨e}åÒ5²#°ˆâȃ8]?6ô¼¨*u‚PO6¡šõü¼î§ n³³¸Í_pDè]|ñÆ ÊKÞnZµ+ù™„¤•!̱fÔŽxsƒú8GÕ*ͤ³¶• ¶F±Æâ£ÜÕ{W Us *Ïc…õý²,¦Px,¢Ðæ­‹„Ô~P³3œ–hËfpîÔ |a<%—;"ðÌØ€ÑüûñSqMö-:{lúÊ+ÒÜ:z{_±¢ˆBÁ±[M²Å>®bÊM Õ|禇‡G\$Ã}¹GÊsùGeôm>ràŠó+Öüšà,oë¡Ýì#.ý#”¯â‘¬"®ø6äZð–/ã=:g7ÈÏo šnÛHåŽò2_Û#…K>§þ)äÖk¾Mr8A£{l¿3¹þ»¾½R¸†y˜µX`÷nIõf_)pj³Ú}‘W \Â©Þæ3…‚‡ ÈüÔD¼©íQc.†‘éë=êÍh¹tÎÝÛù™Â8År1âýÜxˆ€Ë÷¹7'N>·(N)4PzáþqéEÅÿGSr=¾AdZ¢?É1?8)‚á©B¨V&íÍ+– Ô»Ô”ßõo¡-WLTïÆošþÆp”°<„Ã-üfIGÁ(ÖA]ºö•+M–t f¯ÓÆmÏ4­ÅÖüsÞtW¨Rv…Þ£¹–´fq“Í<ÿäÉvŽ ¦òWsP)~=ÈÝí×r0+Ÿ|Èç¸Â«êI£ ï#?šIÓ.‡€6Ž\•úE»ÚS¢/yÍÀéónN¢w;SÄöïù}íj}{ý_gû­LÁ4V,ˆ\r§G÷7¼Ñ ö a})ÿÛáÚ:çÂ.sVmèí%­/Ï™LëÝ„ÉoJÂêÛ¡NB!¸@§‚´©lªŒ1wg2ÎܾzbgŽç ŠæMœU—ºcÃ;36©î{k’c"ÿ;UÚ %÷¥Õ÷nDë›æþ¯™Òßp•º(/ñ7Ã$„ß/ÿ†Îendstream endobj 1787 0 obj 3216 endobj 1791 0 obj <> stream xœí]ë7r’oûW òi&¸i7ߤ/[¾;å|9Û·A>Ü´»Z Þ‡´’r'ÿõ©bóQì!g¦{Z»‚ Ò4ØM²Hõ`‘|»ê;¶êñoø½¸=ûâ®ûÕõ»³~õ[øw}ööŒùOVáçâvõÕ9~fäÊuNs-Wç¯Î†ØÊð•a}×CâíÙŸ×ßld§¸tzý·ÍVuÖ:'Ö/ü£ë•\ßnÅaL‡×ÆÔßþe_¿#m Iñá*½K¥ÝƇÿNïÞŤ×ñáçôî*&}.Ò»›|W£&Ï%0¡¤6Æ>¤ýsúìWþ-S=‡©Þþ:½ýË&¤p@fÀp0=F€¬9°Ty,dbnÝm¶=N;!qâURù*aø!›sªSN­ÿ?0}/Gt‰_Ü—B6.a8Ì+.ôú»í•æûðáÇüx³Ù c*ùög©†6­Ÿ‘Z¯6€¿G<ˆ5ù$i¥‚À—\IòöõP€HI1ÌPézýý€ýJ ˜w±$×E¬q[šõHvV²LÌ«’LzØp¨MNÊݔʼŠW…ãýjË]'Ü:ßXÖõ êE–/3D–ËC H`ÃË;'-È–óÓ—ðÚÚŽñ<ÎV')bM8_Õ6#웜JýcÊEpó~,÷pœA:ÃsëÀA…Ș‰ðódÝÑóæ! ‰5 ±ßDj‹!ľ©J¡×µvÝEÙ΀]4¨¢Ð>r¯üuóU(š—Ðv™kˆ`9ä›ó³ïÏÞ®$ï… 2Ø•S§¸²€Ü¢"÷Õó³/žÿaõþáÃÕÙÿ¹bg_üÿû껯áçù³Õß}ó|µlAÊA–u ÅÆJ¬;©œ–¾9šÞXÏ¡Ý3àÛï7vÂH³Ûã3¡Ë…i[A»L‰´§i»˜qôéfuѰgä·©ºúw‘'á"2¦±pø´ÕŠ©¹ýÐà8m{ä˜Ï© cPczš‚bgs™'(K'eƒçÚÚ¢ŸOh%îUR7’ê–U³ëôtŸÞæ¯F:¾½écðTc1lušj‹5{ßT#m>GÁÏ46ˆ(@a•Ž5Ì "Ï®ÓLÊs ôàÖÉž§ïUiõ`›X}ª‰BõEÕ„)¤24Y¥¡Ì,ö£eÅU]ˆ]êúûF¼üMHh"‹o³¶õ¦f’6` ½îdÃŒŒ¢šñõóœé;Hå 5 wìHÉ"JÆEMoG‚U×ËhG’f…VÑ õU%Ñ]ª3ÐoM¯ÿÝ@Ÿ¤¯‰wú’»ÑCªA¶òHnz †b Z÷Dw  Í؆vš-!Ž†Ë‚ë£¨!ƒI„鵂Ë£^Êõÿ k,¶¸ðCMá jªR¦…IMG‡JK!–‘ds ªéN’Û‰‚lÜ ´¸è{?‚g„ì›}@]èD‹¼¨ µm FFÖŠ‚Qyn‚kÆž¬ s°ïZ.²œËÁ ±½c§7S ·ÓäÆT¢ðý”³òfpA€µì§:"»ï}MyÜæn¨žÉU׃f€û|F‰´ ÃD¡§NçÍÆì½ÿ}š‚j0!z5Q»œÀë(+J˜Èzß»£ab1‚÷Á¡v LÜ“Y›”ŸSQ%xÓ•þØ8T³&N(ÙápŽpBXÐ-4ºŸ wïôúDOüSø@óA¡ñë8m…ƫڂêfEÏ¡_žyu$’U˜7ãzŇ4€W¦ä":Âô3ÌT§¼2§U'“2Gè<o¦3y&€›—ÑoæTÃfÙ2žxðh‚óãu›ˈ7Qf12÷¡ ¡ñ Ê”‹?qú~Žˆ_%Ô‹#Ë^ „¤>Ão¡`¦?!œ Í½'Ô­<Njä} Ã:ž@fœLçæ ôš/£Í)¨'=´pš4 N$ÂÂMÞ$íå~”Vš@Çë6‹µfê¦Lìk9´¬Ú:JÜ_”ê²b^…@ ÅEˆQ±ûB6ÀnòºRZÃò KE„GêOI {¾*À]Až±[ÊëQwUZHAo©éÌ_Çé„[DyšUPÅóå¨ÇÐy¤U)têXÏûËôöõ®o={ÞyÙ—kâ>ä"í[ÒËž£…È̃Ú`F/äQ¢eÏ´àÍ=è/? ÐPùcr h¨ðxôÑý·ëèÉÁLc< ±ŒÈL ƨW‡XÀ!BâUˆ×]‚®ªdñ>%`ó"> —¢9+¶® (¬3¨¶CŸ#ö ®å*êvhÐÌb<–o!¡"¿³²Üñ¡Kµ:Òð¢à³ ïJ¸-:âAýÆù>Ž3#w£`fºRAJÐDãù¾»+¬±x§)06Îú@Bs88®„¾¸©‚8‰ê‘€¹5!ìØÓšÂŽï2/Èù—U~ Ì÷dËqdw”eJþd¹ˆKÞbÝwÒP¥ÿ_I¦oóÚÔ·(Ö$H87:s4’û¶-ÙØ HæWL̇­ ù›Ju\‡™ý„U,(‡=†%ÀîvN‹zSñkJ?ãÚi̧wቯ”̼òõPñTWŽØ;d,×Õ{DiÀ¬ÃgZú>.©Xn$Zú> CEtf¹T9©Aœ.–C1§ÌpsOþšÔÿ‡c»qšq]éŒ,îÇp'^ —g»Í!­~Æ|k`­OXPE«çfp†|rÐÖ²zìyQqßäsãsSÍ¥SÕù—kÎ>`$miï54ªëÁàÎÓ‡èwõSXJ r}²XhÓq~Êža™7,&îF ¹F±Qf²÷"f+7S ëÀ¬RM0Âh{܈™‡à~¬ çþòšðE ̯…a*oÖŽáMM£ƒ¹€fPKm¹/pXÅ3ƒ›òqGaØ“š6kJ¹é°<‡=äÚJBíCn¼ëUÈ–ùwFtwÓ31–Ãe¶urƒÛžº)‡%-ÑK[8"Ñö[±»{ ¥+_žQ™×d†~Ü(! £&2Lªß‘ZIhþypB[9ˆêArg÷éoIþç™ ªwÏÕzÌŸ"YŽw=× <%Ð SQ´–¼ÐÑá`´÷<§ÈhÁÑ¡á~Yd䤨ɖ{©j 4:cÊr Î*ËÜ¢‰Ø÷­oGgúú%š‚‚}g·×*‚÷ÞòHá÷@&J¡û"¥)Xoãî|`A] ¦.Âã:³@„K Ü©7ð̰Ì>QIN 0ãNôËêv„6¾·£lëX«›t»gKõØ•Ûu£é:ÄôŬ­8^2)ˆy´s»à¸Åó¥è¼Ç›äÆ—¢GI.`'—²¿{ìÕÒÒ„:oý%è•Qž[âÓuòÙÔnŽù2¥ýãèîÀò\”›‘7¨ÜÉ–7ÞÞVnÌ%ÿšºÓÛnbgq¹ p´µÐ2žF†ç‘I‰ÉXýþì4€¦endstream endobj 1792 0 obj 5024 endobj 1796 0 obj <> stream xœÕ\Ko$I–8ίð±mù~âZVBHÀbÄaá`»mÏBíõ']íñ|åÝ$|€GJ´òb Îú¾ŸÇ >÷ÔÂËB”´zs5¹nÚ#NàÌ$¤,ÄÀóž¥ÊFêy}p¦п¯ó˜Nwä]å#1as׿ŸI±Q„¼kQJ»y‡}áÌá1Ÿ¯¶vó»­rÀwÆ¥ÚIcýu l¬¥¨Ç‹Ó¾ß"ë(«'£#pöå¸y<é´•ê‡6}ë n„€Q%ämëÚoEYUe¿@7xèàÃäq¥fŠÊºî(Ó´ƒ]{)\Sχ :/u8•¹†‡Å‡\ "ê…N2tcgr…n+óhÙ;?z ÇöÐ çsp÷YZ¤_›¸cŽ™Ëtay²ùmâ4[¦ÑH†xÄ»rÆ;©æSÎã[Ò²0ÓÂŒš¬‰”%gáái”9EÌ+K­¸2m&ï¨L"87ùnÔÛFÁ¡ëJÀ©t Ÿ}cé)hO@ãÀbÒ= dKœIšÎôÔwÄI­@K/‹§¬0Ä'‚~„Qó®Èî¼Ië²E‘ˆÕíÀ¿©±qò‰Gù„1ãd„¤¢œ[5Këó ØÀLxÉôæŸ:‚Y­ç¡Í>¡V‹ÆZ?ó%n¿¶ô(Ê8϶ª«Žp¬³K–Æóä9ú-§yÈä«+r²Eó™xÍC:\·©ó+-`ͪ'ÛOÞ»à(ë5—Q°éhü訮’ð Ð{D_T0eº{rÂ;¥ì„ CεûHi=Iª4ßÖ·¸Fk&0H>›¥Gø0Ž|>Ág•/ è©Éa†Sjî—µëlhÁ˜ÔÐSÂf»P;=mè,nþl>2¬Â½Âp¾ÜôP>ÔwW¥éº<ê»ÛÜÄš{Å45"N"t$|щÜ1ú4  »+Õ2êFìsyx9‹DcÆ]B"#5ošÆ=I¸ÈtÈ«~ë~œ:0˜ú‘È2Bã#d9#ÔyujQÌÖ:ÈÅ„¾Fc Zw䩇Úö¡¶]Õ¶ëút¨ooKÛÑõK ŒJÈgô2¸„¥½¿ÀÀ"Œ*c˜ØOÜXDT)ìQÝ&C¬ˆ(¤R¿Sp|Aœe‡Ë>Tp<º34ê׺" öW8ÃMÑM1ȼ«€(üJȦíó¦Iº)¬1f4®ú0ê°D9 eyø¾Í¨ {¤ *wª!­Ä›¢ÉF¨ÎŠ¿fWUûºÁy›D3*Ž@ žÐŠ"U2¡³¤ãx;ÿ$Ôxƒ^>~Œ´Â&{})†³rKbzž¬|PêãÑïkëŒbzpžš‘OÌ«…Ýœ:­‰ÓàØ×I?±Y@84l™1¶ˆ\ŒÕË€Ë$¢&Ö–&Mé ¥¦voÜóå ’Á7Äègq‹—B-0•€í´Ó{Š©”I%*WOûjiÎá87Ô_d¤Ï´5(f¥hˆÀÐ5ƒg¼iEZ;@ýÁì—'¦ŠŽG´Ö¸k¤>qô/ùw˜•m[KoGj‹ÿ‹4ð³pÔGï›´Þ°ÌÃpáÎÌê'’UôNL’ ½ôlFü#<ãÞÆÉÅ}gOÏ¢=“|f˜ó{6±o1 2ü ;Ó)e3ãxWÀ ‡ˆgóÝ( |¾Ý‚KG“2ð=…“ÃbG')…-Tt}üª3‘1îKd |aIb©¿ß*Ú¾«4KÔôÝy7ùŽ23®œ´€“ `Ã,¾ï«x[ŸÞW£î=c>Ö¶f$þ²¾ý¦¶=Õ§çúö[æÛó Ì]cã­ÿ:ÎCãkŒg·¡¯ é­ªjH2ÊU{{Xã?ÛÛ_õÙŸ#‰ß[`¢ã÷_¦€©Žø¾Såìêy>Õ *Ëe«qx‡n©8|ŽbÜ5åK¸ka¢ek(E$|Ž"º eWÔ!æ@Öü2è=èãd &8ºIáÂn@Ð~‚CZÑÆ`SCXü OYü ;’‰ä@Kw>ÆÏëŠû.‚‹Qv *Ež“t ±¦BA¡ðÀ-†¼ÿP¹™ÔM­]-¿IÚÝ +ûVnç ñà!eð9TÈy¬O°#øÎѸÅM•r × '*ÛõíËÉ·idµùu}ý›ùÔ‰UݾøÇ¦46 ¼í›ºwÕ‚ìMù¡Þÿ1À-„0ã¼Þüc{Ž6µÇˆ©1Žm>­¯²Í LÈj̾åUÖ qŽ7w’Y[=(¹‚u²œ)¡â*ÀÊ;ǘOÒàõ2·ˆ]Çð¾^Ï-Îé®ÑSäXXò DÐAד¥YÅI5׵ѴF[1:%ãäáýû!¸Ž¡#›\$"L¬£§£Àik3Ò—¸Ôà ?ÌY>GÌ<U^8:Çžˆ/û¬L¤'¨K|ÑU³~Þµ ×Ü–>p¤’Ã}™iqÐ᮵žŒd\þ;šþqQŒQµ›.M¦<ØÏŽAdW1¨Þâ)ù–!šÕDhÎþhœÜ[óˆK §¤÷J&®dÕÝ«(ŒW.F¹it úkI¢%4- tAO?y«H)13ÙèKÉüIÂÕó˜)à×"…ÐÙ†lÈ„M¶í‰¶à@öT˜äekMŠ"}‘• ì¾»XT”èHQ@ÙÎûd)™° ]ˆTÕ ¯ ½Éå*ÉRõC de>ß”ÐÎלñU-ûf¡®…šçìùǵ¬·ºkI|qÁâ6ég뼚ݳÊþx³,—¼€EQJJcBÉPí=èÀy£´Z5…ÓF{³ùÙ¡=ð¶|¦%1ò+gu J…Æ•š,²)¹´Úh<¬Yrgåm•Ƽ-êóó¶9ÿG|½ÇÅ>èç‘°U¦Kì’¾5ñê׃F³¬.Êû‚KƬ‚8·æo¼ðcŸn\ŸìúTíP<˜ÝeNgˆÛ+!'¯W1L†•ªo…Y>»æµÁ’˜q–RB¤žõ (-ë IˆÉh¢ŸWÕž?V*“ ÈP/ÜJŸ·XÑš3yÍ,Õ!Q:Õ‰Ì&ev°çzɾà²_KÒÌXþ*À/æh_Rl¤Kp¬%Ž!ŸŽ.hÖ3CPSù)‚[Á£~lY®~t¤hç2“ŒEû¦ ‰"YÛ«ï—v«é¸$œûCB:4à¼ÄÆR󈨘üTô6‘/Â#4p¦?éyòôÈIï[)ãç†VI@x½|9¯ðD çžE˜f•gmJþh¸˜ ª†rA·ÛÏÉ`Mu cI&ÐO¯r×@+—êîûúÍîÓÑÂÁh€¬øl[> 9Æ>>'éƒe¶£Ñ ½XH%­7¬øÌ!Y fJWx›v%„q:‹%±>Áþ±NqQP¤%Ø v¥0³/]ÒÚMZ"·3VÞa|¬E`¹^:ÝUÕ(½Ëš'ÍsÇ.¹­‰(ÞÕ쌊&¥ç_­läú8aZíëm¹JÁÚȧ I¥õ+@Ÿ¹C*K©lw' ú÷y1n@š×y:lçòvU2b&€2{3‚ú™È©˜ýDŠŽfª”hîòéöî _C´PWc¸ˆäD ¾1_Ä,z)5_F./¿”o,O-­Ú h Šl­’í ³‹ç¸êàáýï¨jå¯5™\YÙ+Vx]`Žê‚«ùíÜJãØWï”^Ï|Ÿu-Ÿ2¯ˆÕÒ¡êœÑQ¯"ÈÖÀ«(ˆ9# QÂ?VC fÒ«h&S½ZÜšsg¬÷Oì%­9FÜ*ëÊ%4#É}“ÛBÏP% €gi“‚.WŽÜ·Á “v¼xOÁ%ÈbÒ*ë±øˆ÷=W¯¥@†`\R’CÇ€8BDtElY:¸,ÜÆDÙ 9óÖte[¼ó°8†nbmŽ8vÉòwë4,?Ë $±Aõzˆ˜ðq6@ÔL‰ ã…É–•êM’_“ä•Ä1è=l"¸R_×ò£%ì‘ §öŒ>’HËéÈO_S-p¨âæT†vÕÚ(Q?V¬x{,^ñ ×„ͨ°2¯d ÅGGz‰ÈW…–†Æ£ú8š¿e›ÇGu£‡Ž”$ÈÎÍJsÁµÕ7 ú KZ™k Ó¢T³³íI*à˜±+›¿C‹Càeøý¼ o›ÉQM‰bià ÷ûú¸š€\·*"À¾ÕÌÚQNJ.R½*w¦‘okn}èO“bH*DSz‰•„uÖí ¼/Õˆøèù°’Tª>’âù›»o}Ê*(ù/¹ù§ô»$ŠëÖÜiÆÓé>®“ÎÙ©nJ½K3(NGuæ¤Z‰Æ^êÊ—,ž ððaKÂS«&EZv÷ä“£ý%£°"DnþÔ§ŽËw7=h¥)ÿ€Ùf¹3cÎ-z8ŽoÇ›mûf-·ly ŸlYéÛ_wÜe>è]R"ªÄ3#!V>¹GUþ*[ù·!ürÑ®¿C|·=(IÓW7y'‡²T0Dáë@î"?²¨ñ©µ®—'û×±‹4æJPå#‡}Îqþ»ªÁË¿àb£Ü/f°""¼~ïd—ëÛà ;T˜*t4XÉÎÎpе •3vðŒ#X ¢–øvåÌNsî÷U-Ýs·ôûë\KßÛ—ÁQê%xóÞ®„ RwÑ"e÷ÜFï3Òë¸wĢȌ vâÏjBç&ZôœH aUi1lY§ #%ë¨6†s#µ9¼CCrN‡U/ ªØ ¢®é²î†xY0˜­­îΑÀx*˜ 鞥Ö.=rܯY Ÿ­„0ÈWÅÁàËnGÁL[A®i-¤1]Åá­´Nks~ÜN.,pJÔàPßçÓ­Å›ß?¡hFü½¥ZAöƒ/YèêÁºÜSþeBrŒ××[+^!:ïW"ާ׋WxþÏ?ðй+ú+×¶ëRHˆëcG`J¸v!0²Y4áÕ©Rî×y¿£/Ǹ _{Lf;IC^sí ÖŸ<3`o$ ?cÓ–Í¿¢%'‡ÛñxÎ~¥Ð,_Ø3K{Š/°Zn”°0‘ìTïhn±Áþb0àêï—È™ì.‡ð™HÖ=Z»þ<°ncíZ“X×ñÉW™¦ÍËæ‰z™å}ùs†ˆ\¶ðŒVCµ…á_R]ƒŽe²­lµ¥¾"O>µ“š;õ?ùt ô•1ºp±Ã[æór[Ô‡»s‚_}yùæ/ðçÔuÒendstream endobj 1797 0 obj 4516 endobj 1803 0 obj <> stream xœí]Yo%7vò¨—ü…‹<Ýô­æ¾Ø†Ûã™tf‰+ Ü~Ð.Ãj©[‹ÛýïçV‘9«Æ`-,W¬ú9Vļ]í§váééüËÛX8«fU©ÇŸÓ³›Xu=ïñó© ·‰‹ÅáŸÿc÷ ¸kLù®ñ´K¹Â?ó7|ìÙ6 &ÿ&==›-ÚnÛôS¬ú1"…I‘ým¾9W±ðP-RÚ/(ü:_êðóøld+®¤í0°Qn*òÓ¸L#ýÈÅ·¹xŠ ÚÛFÐf¥N½[¬Qh(žB«ÿ¸Ýy¿•Ç9wƒ[a5qø]5GÜ¿špò.”{]®0¼µ\àUÑéf©í ¸\þiµ–ƒðʺI¦á4€Ä×B*˜bXœX{4J:Í ld(J¨ýeen™Æ¤ç÷+#ÑZà -;H¡aX+™Å±Ã`1D|7Ô^Ž96B‰Aƒ0½[ÉAflìÀHG*CI;!¦æC§7©!ìH™ÁzÞîè(Ï©CóÁ[Õî3>÷†´¾â~p\8(ÁDåÐé‡LèvT V÷!=¿Ê¥!5‰p Û¸æzàÜûG ƒ4#-\V©$ÀûÝHLÁx‹Vÿ¯(ìÓE$·]IX6i鬎2ae*ÈÄœ‰ßHÂvû És2€‹f7S­óôÝJïi‰^ Bøu$$“å )ñÆÁ¼^¶ýn…´$”˜õ@>‚ ΆäâuÒTD«mVZ ¨`Éíãd†¶b0“ý¢¡–®ç2ƒ¨´‹ªK·éé—»Ic‰Ó ˜Q ­Y~mh\*e¨ˆ•‘•¤ÉÎÂäoóžŸ5Y¤¦ÉYA ‘u]Á±/g°Vh5Œ+ûP¬H‹Ç”ácS·ÕºB%«¤Q/@M¾„qó¬Ø Ù“/ÿwµ¤Ã˜3œŒ°`Ñ@ZÁ£b€‘‡›:ý)—˜¼z=J- " " .g½BS‘ îá°9È=S_à‡\îš´j‡ô&Ù¹³¦D"R‚ üdóp@ ú‰ØÉ—›‡ƒ¶+Ú”ÓÛMau•û&"n@™âìPGlÁ#h{*ØEœs‰¤C‘ îÛ,µ~εQØ9µu›(!÷`hþŒbãm’AGI¤º_òë~ÉwݤO‚ˆW8àÅ;QG{;§Ó ¶æÐk‰°£Ø$1åK*áØb'Ueç™§³ÔÉŒÞæ#&Ðþ(Ùȹb"ƒiʵ¼nmÖxйdÞ°Èx’ok`GF£V°(­sÒsÏàñGÂzÍmòµìÊ“ ê—^ƒÓG’8éôŸ4þMãM£·=¶Œ20O‹ûœ$+¬'ó8쇆œ®ýpðt‹ ûnŠºüDäÉY oæ;²?9£“E?šš¥ù‡¥æ —?´:l:“:XG€Œ•vÓÄ7—-Wâ„zºÐPZ¼=B8$X pÀtµÐ¿ ý­Ôï\ÑR¿—Á«Ò¥~‘ù§ñàX9(«·Ê›¶‡£ô,ÎÍ”\‰Ã¶°Œ®ïK±°°„ËšDLÌ2âékÅWù…ï°VLvtÈlŸ¶šípü¸P^Tölä¢?'¾VÚǘ5 Gç”L|Ùuz97p Ÿ‹–±Å€aE-1ŠÈÛl{}È®oÚ…‰«Ò2ìÂÙSd™±:Á¢w÷ WLž°4 ˜à±YþŠËeˆÏ–L¬7`P)Ÿi¿üï™Q^&†X–X¸Üz4÷ ;ùà’ç6ù: S]Ñ•Âa2 •™Ï߬<"$xiBŸhŽï¢¼’G從Dx•ˆ¨mÏû²ÝZÙ¨Zw@uTr&9”VI&Ö¹€›,±€+hc{À‹'°BÂ%4¾@6ói,žñ¤ÑŠNiå<²C>oóoÛÝÇBpPªÍÒ»›'Í…PµhƘØîº§¢9Y—h€ª®Œžb {„#žS2 XÞ@ÆI2ã¼µx"Ñ&ä-š…cÍ`tƒ‰ åý…ò£í@…+3ŠÑlèýÖðt\U™ex3§cü:OàØ%AƱ‹8G´"Õ#ÄùÌ›”"žE¤»M¯Aî^‰ëûÛ&—²ÓHÀf”x¼Û’™Ìð²Éêd Y^t¡MÉael^…àãªÉžÜ/ÂõÈÒ¸@ÍØè‰Pr°Iš'Þ–-ÞvÑðGD_O9L4?ÞìÇò|Îûá…·sQlM“÷FÕà â·5XKPaÀ$ë´sÿË´öB ã8š“8"fÀÂházr±Æëê ÑIDo[\ÎÞBUÜ›ÁûHS^ÅÙ‡W+!ˆIWïò›”‘Ú²[« è\®fºk³F©—PMMcBi*&ªDÍ'•@']¨DøˆÖÒH!ô¶®'¸ ŽJšå{ÂaDî)^M;'9>·#³ˆäÙoô°¦Æ\XP#!"£ÕFøñWìxîo13‰©¢ÔóÖMIáÞ ÐqŽuå#Qû"‚wS¼Ð(öùÈîå)FHøþ¸/ÂßeÄøÐœCƒÊT Éâî1ð‚¡#LTÆñF¶RZÍØª”zn$` $ UpÐ|Ô¤"ýÖ˜iAØÝGQñ’®Èˆ’-d[JM»/¨aTmX:“bY]ïs å¶ç.K£"Êù²W©”CQ9½Flšøîs¢ëÛé©SƒeÌ 4šajмûtú8g¬|9~¢œXòTÉRiˆ ¦<†ô¬ª /¥¬Ú£2·x KŒ£Ã4 ×$½X¨l/¼^¦×ÏÓÀ3hͺ÷ééq¾æï n?«Þ+Ÿ^W}t¢ÜÍø‹œ. x^ ´1ÒüsªÏExÊ5#¹ÀÙƒò9¬Žóƒ8“Ò‚ë¸$ÍH>Ûð,OõßcÕù¼Í”þ} ™jR&yjÇgõ %IÏm”MX;[²©‰ÅŽû;¯s½£¬JY畵Rfù¾O¥ãô´ÞøÒ#U§¥oÞÆ’|òŠ\T¥2¹ý4ì­2`1Æ…Ò"oHÝLÚ#(Ô§iíÒŽ4fb!3)‹U/ÊŠÅßDTdôwe[ãª%º½-[›è6>}½"\Ý5-:BÀÐ…oR~ìW_Qý%òM S$݉Àw†—£VÆ Fõâ^9΢¶<Œa¨ƒ L¤ Ækéw8 àLUØ,æ³MÃ2²¡è£E<Í1›ko)R¨`L[͖ݨÞ|mÚb«£G°CÎu7Û-w ‡lq‹ œ0p(§C™'†Ufò‚µŽ ¸L ãätÍz&<è!/ClŸÜu­6é|騠 ¢~;çþÄ„¿ÌÅø}Íý¹Hñp,Šö÷"ç)fø¸mØ Ð¢(Û©¤VÒaœ¼ü낼üOüÏ×ß}^ýnñ/ß¾Z|ß=›¶a.&Dè7ìA’\<˜*õ\î·ÌL@ ’¹€¹ªJzJ‡„Ò‰ 7i.?·¦Ð%-09¸h|n Îñ}t63Cim$ävœÅrŒ3FÌ*'Uv¢£ÈCǸîתÂéÀ‘ Qô¾ _2‚wƒo#~¯ Y‹S» oŽ›Þ“Û)²Ì Õs>e(×ìÙ‚Ûh^‡Ôþè€táq¥£Ž3°â¤ C9*äa4ĉ<·k?ã{7u®uX _PÔeá‹ù‡™È1­^ô³¦7·JiCÐ>˜L¤7—ÅX*̘Óýä43Ð딣|bƒ<àÈ&e; ·(¹ŸªÝk” Zõeë$ç|–ò\¥#dXM7ðˆ’ÍH—=§qg\g™Ð>Ð2ç ,^6£tÝHÌZZ¦\Ú‡ãé,-}-8­È£b.zOÎWp—°¾áððÉ=^¹]·g4±Á,èOUœ.µk»¤´n’}ÙQi\]*ƒ^"ó¼7!§1µèÓLÈ…”3:¡ìªÈN†7Uµë6r¥à*‹ö›!‚Û Oûh9j $>´K‘^Õ™IÌd-xÝFÁAWM/´ï]çŠ:!Ìéùi²œ5Û£`ÐÉZ„GÔü$|£Áû5˜Û.èŽ'‰H¶GÈEEÅà”MFïønÚÆ­±•OPppeý^dÙ1K¢ )?µpIg45ó$9“ ãiSɆ`ý;=džàkc¿RL„¶Œ˜Kþʵ·Ux8†·&¡Ë<Æß\q΂} 쟀Õ/Îc+¥ƒÍúI抳ؙ'„VHÖ¶X§GG悱Xäi©TœÙlU®ýŽ&[Íb@S»JƒÄ°ôÕ„âBgxHjèåïˆ3÷¦ÒÎÁop]oî½Sbôïë^*U6ù‰/}ˆñ8Z{dE"ÿt^Kì‡Ç„ŽD?¿f#yç;Þ÷³JD+3×y×ðMN‚ FÌ×A™~›µûa“)V{¾ïÅ0S »¦Ë‡4ÐÈò÷t„©×íRÚ‡hæÚÁö7'îJ0é1/˜´Ryö ìYyö·Š0ciË}¯Þ”ϰ[¦jøûv²-I¾+=€!P_¤½?4¿êÝ&7Qié÷ .´þ­y»Æ…- §+µ‡ë„›es옛Ñu¢Ô³kD„vF“yÚ8¸f£'ÿSÌEãAb.OWϔ㙃!S ý¿Ìô_ãüü˜ÊÚ£-å‚Ä|çÝù%L½õAtv¦ír3Õæ«ZsêixP× ¨°1CDH’ž5 2^¢D'ô "iüØË'˜Â|„bB»DˆŠÄ-ç®ÜP¶ÿ~&”–ºF‚Ê@(ô,¥Ù5\#TÇ>³W`Î*—avŸZÒx1V>ùC e5åi6ÞÚàó|ÁƒéLïi_Å–½çÙK‚®,ta+¯GÈR1DãþsªÅe´i©î:ª!l›îâÕªèV’[ÌiGˆ—¿)DÅå62¹ek¬œ¦,úÉñ> ѦSÖK\Ò.Ñø½“ÔqÇ$(Efì] L„3^m[ƒäÞäv¯@¹¶¸Q¤ '©î&•j<©CÔ.p÷«ÓNK¬¾# o£¢Í<õý@.ø,rûíƒô+')¾$úFlÐ]Zp`0ž0n\ó':kQŸŒÀÇõ9ˆ|ZŸÖuXRõéˆÞáu1³ÃEÚ÷SŸÍÀÉß8›A]„ä€FëþõúÚÓ2K¾õ´>«€¥Ãôô«T÷‡Túszú·T÷]*}•ž~“êþ'üm> që~ H©ìÏœÄ_eìã³Bo„"Š6IÂ~JâožHskžHOIêÂçRÒÞu~ñtÞÌ‹ü4 ë6ÔáB¦–ão Ä<ÝìÝýÙ h3%¦}»ŠWÛþ–E ù‰‰ô³o«S›ÕQÒ¦| wÂ¥Vã´óÁ*=×fʲtÖOãªÏææìRrà½rˆK zóŽ÷¸zÒíäÉä´™ìpb}ºäB°Uºm¥é‡ßç¼i¨¾tŽÄ;y?6éAuƒn˜çÈxp£õ=èç6ÀæD»„Næi½ò’–ϧ˜Œ!»˜ÍSæ<¨r¡èÝêeâq™Ïî]) é]ûduºXº—%6q7³1¬\ÃI<’*E2°²Ëú>G þÄ+ÒCti_0ZÐwä’_ù%â«WµíWgᦫpTÛØëÆ…XÜÿØ,g,]:ùÿëÜì:=&Ьþ&â©é¬«ˆ”-ó'ŠJç2óaÇù±›BÉ'À‘QKRçßd”Ÿ}>ýü ߯4Î ÞÍŸ%^møÏÓh€õŬMjE´¡9º{#ڸɦ:«ˆ •Zéã‰Í'­iì¯ð•ò $¹T£ƒŠ:ºÈü’®Ð°Ó]I—??—ÏùßMz:dI´1ÀNJ~çL²»Ç§ODª«5X•,t Û|7ӯȹ¬VŸMDÄðéù}¼ ˆùä¯Þ÷§ò’Ÿ‡Ü>±JxY˜p-ßD€ùÌŒÈRAÅÊdv}ðw ~Gendstream endobj 1804 0 obj 5743 endobj 1809 0 obj <> stream xœÍ[éoIGûÑňO3h§S÷±‹V"°@H,XBhƒcÇN´Žíø‰?ž÷ê|Õ]53Î%9Óê®®ª÷ê¿wôÛ›øŠá¿ô{úæèÉß„a«‹»#¶úü]½=âaÈ*ýœ¾Y==ÆaV­8Ÿ¼Öbu|~'à++V–³‰©Õñ›£×r³å“³šûõ´Ù²ÉK+ÕÚvïšÍÖ{=i¯Ö'q€2n}º“ÔL¯ï7|²†ÃÀ×3yÇ™Z¿Û¸‰k#<}#Ò¬_â»Ê+·¾ÛlŤ ·þ_Ç Dò•Ÿ¼Fáî…‚5¼[ÿùèøW?®7[9 ¯¥_¿Úlõäœ÷fƒ%ŒÑÜÄ94¼Kæ`“Ó‰ žM–{¿2NOÆENœlÔä¤Ö (Â+å8ì¯` )ß{WîÌÆáÕËòô.ß딃K; ù ¸ÇäÈ8)é¬_¿¯Tþg§*µÔëëzóv³U†\Ÿ#½Â…"Ë?Ö—8D¢Àéåõ†Ãñ8¥`R8eã½iá(¤À%Ð…c%³<óÙYd³ä@›æyY®åú¡<¿¬/å¡Àް‚eÌ™æµ×u7÷Í{a‘2)üå¦ ¸Æ‰ýÄ`w9iÃŒ]ß„-xÎ5à4^éèbçu ïÓ\*ˆµÉx iý}Ô-œÕÕÅ(Gîæí^µK<¿Û @ #&f=ÈÐñÈÌ’tœ OúW ~^¢vž&r­Áµ:Ü×·’Øñ$uadä‘öÌÐn R+@•0æ]dr ‰ªüþ=¾¶M{:ëéœË…K‡0_6¾äí” â ÷Gáè]¶^"û‚LY³ÚrßñNä*‚¢@„¯©…M1 d e&ë9ÚÔ¬—š5¯¨•èÞ›*¤š,XÈó¢Ã­b )'¾~ƒO½bûzÿדVžnðªMŸn’ùO#¥•f"Jk› žm¬¯( "[ðßoà°¬3žòð¶²þ œ‡ó*øüø>ov¯y“pŒ¯ÀÀ¢}ó®Ã„ŸÀ¼¯¿)W¼<ývfü‡¾X;`šy¼/¶ŸÑŸRÁ*Báæ¿?>úáèíJš°g8·âZY8~Ø;H®pˆJž>;zòì/«ûÛ‡—GOþ±âGOþˆÿ=ýëoáçÙïV¿8úþÙê‡Çb®Ý¤½È[C«hèú×­3“b€r¶‚࡚à&Ó°³`},n8£¢“¹Ï÷¥‘îƒDÌðñÜ“›Ð ¡öEÙñû¼ãÝøF ´³d†‡7–}(¼‘¢qµˆ4mið#x#¬›ì! Û÷àFx äÚˆÎÚ„pá÷ÕÒ^•›'Õ¿%û-yöõaªÓº»`W +8&§$Ý"±ðѼ¨wÉd‰#&®&eËGò1` œ‘Í ´ Ò–…Á 4Äh(ÌdåÕi ½Þ=1é¨5 ™·ž¾t¿à‰e‚â–‡!ÿpZÑfšÎK& c-ȵ¾ˆópÛ8@qäÀˆÌ&:ÇÀÝ‹ê] îÉsƒw®¦1Ëb0àd·8þ‘¡HˆVXÊþóUXë*!$ŸVf°Rzâ€}V’‹AT«j!‰%*2"ROT³/#¯Ýÿ hE‚ã/­È©ø<Ȫ8Àõ¿ËÕ‹òôý§Á]Jèrt´t‡Jc@«3:¹*W‰}‰¼†Ã à‰e7)ÃSåº0ì¡0ìj‰Yvûs€ÔÊ5 |´Cç|X7¢‡uhïAH…@ä™ýO掬 ˆœ¿¥¨/Cð±©ñsEŽFPwIR²¯E=»–€xHâÏGêè£@ÑK Ä«%Ž0KZwŸ„H¦ÑÑó‹Ú`cŽ_­MÚ ïʳ2¼ zYž¥[è ¡‰Á€Aa~‰}^è*µj¨|‘wû~f"úrêü9‡#˜åGf. â8´åÆèò¬ºð"Ún'NÛk“R˜ ABAO¬= ˆàX/:жbm#ü h+'.„¥û¹Žh8|\;/¨&#bÀ:à d†+WÕ»Ž ˆ}‘¡`Ú¢Ó¬I“^áªs £ÆÉœV VådaPÕƒ`XÌù½ìâ<i'Ù¸ëœ0š1>OpÓhš§4šL¸*%y‡\ŒaPM,1‹3ØCú¸O-k°¡jˆ†b‹LJŽ££Ñ³Ø|ºQô.òXùIZC—÷e€X_2¨Ç ÆäÀˆ·ÄRd†@XÊ%ÐMYÇ„yÿù釱Lµ¡¼À•lŒ C»ó›€—ÙÅ »mÏ…y»DÁó\k-–Æ0v¸D¾»Ì1v0M­Öx—"a@]$¼Í‡º-éF<Û/‚ˆ1-Ãÿ/!ñÖX š¡‰ƒ¿.ʽ$êì?Y¹õ-ñö»°¶NýñpÛW¸}ŒaP¨Œ»oÄÆúË%¢f¦™×Ý\hyå‹T9„E²r|q[ Â¤›ÂßˬÂ{§3Ø_Bd“RÍ¢ ÉaÃ1ì, !ŸœÄib`lÏi”\]WÏ >ô€–Ñ‚9¨Î®c‡‰¡'lá :%:#gH]øÒ÷ñûe×·µ±~媓5p–º†<”ÙA¥¯Ÿ¦{•¶Öh4¨c”é«_úY²d½ÚüVõ9sl¥´j€» lS±_ä™KИò¹c°aú/ê]šÚ$¸³Bä”W#!ö"-‰ö _…$ ¥—Š.—ë§`è4ˆ|Ø)zþ”% ÑåX†F:ôáãAÒdB™¨Ÿ±oO7,/pIœ%,ïøxƒ‰ÓýÃU‚¤%dåìƒÏJ`9GÇFMLñ9:6|R\ÑY¯+Y­EÎkÝô c^ph;iG£½Œßá°‰ZEn¿mˆÇêÆF ¨ó/k"¸“4Tû^¸5kK¸  ½uQrÓp¥×ÿÿj!žô4c[›v²X¬„®ñÜ{¡kä‹ÊA ÐšÆx$Š]yss@Dû¦;6§¹™nsßYóûoõCbòZ{ÄŒtô<%1$“‡Ù·j³¨Ú†0‰]ûjPyë_ã[2^7O$ý†*x>Ûµ*5ÔõªÁû4¼<Ÿ—öÇ#hò˜ëƒP¼z4MÁ>ýe¹÷ëruWžÖæ¶\½îdœ/ÊÕwdæ-DñýúÁ¹|LU9÷øø‚×`åPC×î‡8´ÝåVÍÿ׊×!Q>wžúj_7…aJp/1õùº)À/€´Pn}Uh½¬{﵄Ü&ºû½ rFA°ÝöZœuk‹KŒCLG <óˆ>‡IýCDZgÒ"s4Ãèh]”ð¦CsîlÄjв´´J˜òÕ ’Óç2Ô8¶dGǸwÖ“ÉF}\¥q±Å}k: LR‡ßØÃk'‚‡G< ÁI\–—•4&ý¹º"ÁÞj· nÏÐóç¦ U£˜9 lÓÜ`þ“ÁTª`²—Ü®[¯Pó¶3ßËÓy³b¥Mªßµ%íŠHáÖ×)}® ©1áÍK+óáYõ%õ¿+÷pE¦Bñµ6×ZÀ|¹ºÈœ¨­‘äL¤õ¬%óúfIü¾ê[¿—áL–sí˜'–±­¯ä&2tCÒ„°îå8Ñ;kä|XX‰ªbÁÎÌ~²bi5wŸâAøŽÄPšÎ:üž×c>HïF¶Ûs$ÃDØgîå ä\Cîygó—;Ú;n‘!ÜA]ç¤=))A šÏfÚ‹$–‹ô çÔ´©â²¹ÚD–„˜ž×ŠGlÛ“ŠOZÚñVÒÇ@]œ·ôs¨è N»´@௺˜°Bº6S!5xýè²zø¢Ê¶ŸêtÚXÚH·5.ݶ©´ó̸ÿ8¸ éñC‹ ‡†y?1î@Pв¥šdÝMwµ½•èr"Qz<¾êûž¯«õ£É4 |¼ö´ïö¤†¾Äd’àùr`òrö—“P :Oi(³MÝÌí÷¬ïn‘~ {w놮û›™CÊy+\?ÓvP ]¿„“³…û* ‡´±cúTØý±f”y†8š5µ!ôâåóM]´D~ýBmN§;߯H6Á`, óš‡öZŽù åLPÏÙx‹™ÙÓ`x/¢ÏäÃxGqZ½@—É?«ÏTøE¡ô-©ç‹½_æ-wh>Èg*-—ëÌ>ÝMjð¥g¿É¦Ÿ7ï+éà.‘µíK›_k×[éÐß¡´1e„ÿûÚtñs76$uŽE"Æl@¶)Ð䣲g¯ŽXé~%…|Ò0(M´uù¨”Äœµ%¶P´Ë9ÏD¬¬éÛå²Z°c˜ÚÛ81Ë ÅÊ*y^íÃE¯[!ïÔªAÚª;ˆ`V¸“Í—moiZ*Æ•‚„7±k ¿Ôáe&ÖÔçr\}¾¯W®;Kýªö?DÞ™P0ƒï:H)i_ýò¦¦ÃÂAÅ~Ûq¹:T£Í~kÑÇ9ÙEïžGÍâ o¦eQp¡œ±Ä¡¥·¤HÏLàëÖl ›(¾"¶áœÆ™½Úi#]âTX¢¢díQ¯É§H¬*îBqý¾‰h?¬Êút9?ŽyÓÄ »$Ýïgúûì¨!éÈÔ¶9,ˆ0 Ûjx%BU#QPç›Å}ÿpô?·t*endstream endobj 1810 0 obj 3894 endobj 1817 0 obj <> stream xœÍ]é¯7ròñý“ý4xÚÍ»i|%V®õ¡ ÖÁâé’ÖÒ“¬ÃZùãSE²É"»8—æÉ ~­n6›Eu²æ×Õ8ˆÕˆÿ¥¿W/.>ÿQÚqõäÍüïâו–ch°ÚêaZyã‡iZ99Šaœ°ùW/>ø«·¯ßÝ\|þß+qñùwø¿¯¾ÿþ<üfõwß>\ý€Áë¡!GèÇ úÞò˜~ÆÕ¿\üz!âÒŸ««¯…q‹•¼•V¯Ý^DŠ´’ð!1H¸ûââOë?n¶ã`½·Ê¬_m¶ò^­ßnFx×)ÖÏÊåËÒà._þÏ£½øöÑÅ‚*áü‰dKÒd+’¾!$Ýl¶b°Ö»~³Qƒ±£uë«xÓªiýz+ ýEéŒá…0ˉP£Ë1¹4Ø´7Fœº¼=~]èð)ü{ã*3…ž"m£õGnÎX[²Æã0¹ÖOƒ‘q™ßn`,JO¯à•õe¾w•¯~™Ÿâ xùß/ýãŸÖsƒ´AZAEfKi;­ìdý‘Óu<‘¸ ¿”É|ÃYˆû¿|õ8?ý0ßëÑ£m`ÄOBŸ ]ç!¿ÉC~Ë ¹á´ 'gcµpBùìG›‘Ú#we0!°#aBN(B¼»°»´OMÃ͈6ÆÓÜbP‚#¨úËÆÂ*øÀM¹y ]á¨ê.ùùÂÓ L¤ék¡$tð8?ÿPz-Èø²ß»Ü’`$*’mô`Å´~X|dXŸLa¢`îöšë–ŒµŒg¸G9Oà–rÝ’ŠsY^'“B½À5ß–LÆ]š,á±a ¿ß »J-‡QyàG×À.dad{;š™ ´˜®„$WÃf«,´ìú\ÒOÚ¦%½’ÁâlY1hØL/ð^BtfȸîÊ`òÇ’íLÊa‰¹*Odÿ;FúÁn¥‚í$¿ Ȩ.Y.¾Ë½’åØ×ô¦šm©íàXn kÕ¬ÒJŠŠßø}ø4­·îK&þWnËàæ€¹4äκ¹¬F#ο¹ÂûiŠ@QépÎUaا‘ùÍ8h=óþ»jÇ2Y ÉlbÚ]m&)#k¸QÃå®]FÈ·}É1r¤%3šù1N¼š ³‰Ê€'~&v·¼6Æõ…^Öz¼Ê33­„Îc’:Û*F„:ѽ+|V‚@Œ‚¸h=/³âð.ß»ËW€D°q`tå n†‘šY©89»” BKÂsí¦Ydû´íQ•P=¸ü+»«H[²_ஂ(Eð²~>¿õ¸ÅÓYk€÷…ÑDo‹ü%œ^àìyéLÌÔ!†À| ½ Ä Å›8ƪ,hœ!›í†÷àÀËž¡q²t°„°çÔF“’ë÷htºqœ¬h…ކõ˜…¶Û¢NT@ÀÕ€²¬YÌ0é*õ³ž¯¨‰šŽÖZ+ê‡B& v„Ì4Â-˜ßÓ4Š8п߈Á+1ê4UZúVcn™ ôšç¬FX§Òx­á#¹ßÙ*€¯9:ŠRü.€Ÿš@æý5?&¾€›JþÖJ\³7Èô"Œ;†ò5~´`¶dä¬"Æ’²Ô 4,¯&lÉòêÿ²c~ÍrÒn)ƒ8˘0°#c´u'»ˆ? úQŸÄ© ¬Dkmß0ÖöËFÚàSjÎn­’з,ÝìsŽÆ]‚‡øhƒC”º³Çf&´vöÖJ6a2Ö†x§ôà,ÞœmÙß8«w¾Rƒ€¡Pì,쳞x˜?ÀCz×8‘À”¾µMP¦MþŠ•¬°cQbÆøVòʘ¥Ãk˜°…TGÒ, ‡>´£±…–ê› :ȬTàµy´yfy³„™††ê=ã;0£´>_¹^Â@¬?ᘉÿÊ€Zô:_…ôUR>"Ê«êñ¨°àD~:æ§C¾Wžù©lî•vøt$ým­vÃ8â-€õ!ÐÉõ?Áz‰Ê¥Žœ#ý ó­ü¬ýn¾•zBWi *îÉ8z’ëŸ×éÚûõÏ?§Ñ£RŒ°Œ·ðI¾÷E¾úC~úS¾W®¾KÐ ºðWŒ?µXeÍn²ñÏŒÝñºY[çÈ _ηÞ6ý†Vé¢öªnÈÏiÉ:Vt`ßæFÏó°Š€zßÌ>½iæ² ¬ö?fz~Ƽû”鹈ÃÏ–ÞÝ4> ðÏ›-¨Ø`©Ô_žš¸2øT˜QDîzúæÜ™AÈ­8¨¸ù9£ñ®¡¾÷ÜÓ2‡eiZ>çß5ü—pkÄɮË`Ê/gR[%n=˜u‹2…eýoë«ÉÊ<õÅrƒçN}Z¶êÍ%[>mænév€°Ãª•À5¸ff¹ù&ËÓgÌ”•iüs35§>g¸œ²ÑruÛ˜vY85oõ_€ØÉFË´Wœ+Q—4(º Z|6£…/÷Êî}7ߺ+‹0£‹Z.äÜ™õ 4ýç^Ëv cÍã±<§¤Ôû¬†¤Â¸Ïò”^7ÓÜ—ZõUïiy÷A/Á^^rØo;?ü ßûyCêêÑNNxj ¨ªI—þ í\é'Î9‚VôG —¨€¤u (;ñ©óæñÛàY±ªzch@Ìn óLõEÆ ƒ^Ì;TΕŸ&Úôf#å ÁÄ^êîñnX³ àä= Á?k='iˆ[5ŽÐuk;dB2žÑ²Y¿ÿ2¨Ö8—x»ý³¢§—×" ôõA³0ȹöWËgÏ–»þŽ0"·U¹ÂaÛÝ«â«ÀZò5¡·õÈ ÀRÑÂëž]¥ÐþÒÕgÞo€:¥, ݯ%a¡ëį‚÷—¾Xr>2ÎbÄËÉcç[û ·/Øld,Åè"<•‡¯Ý B¸ë<50YÇÚú/Å G‚$Än#=ìÊÓ©"—02jf“Ƭ/1z÷@ÆÑ€È%‡û¶Ì¤¢ˆÐ`BÍk¹ §ßàÆ{­¶#3côÁeĽï!+2ŠVÄ]«sÔ2)Ë©»BhÓ~êmµ¸ÁËég§Ä¨(6_sqZÇEVVã`F³\ù„@_ö§Ç $&Ä5atóÚ?çÜFOš«Öý?»•¤ß%šŠÄlS·zQ7\¹’Ðóä.(±QÎotŽó5~fGOeá³üèÃ[~¨„±ŒÞÁöÿ°™÷…ƒEŒ&¬°ÀàδÚV­ÿ3Œ 0ϯÿ¸2µ5ÁytŽFøõ·x)¬wu®håà³y/L:$!jèödç+Æ=lî ÷™·çG "¸r‹™àIj øn•‚•`rúäT éìÌS,,šö0`Ð ¦=¦Š¬¾Á€4«ÿ€îwüôSŽuÜÑ×óeÙ£oñ%XÇ©æáC=€—,ès©/{•­P¶Ó¹ÿtJ ȹkTG&1 ÙÒ+ ¸RBïE‰‘®úYIäcÀB«§u/IKI‹×tÑ«J>l ;(Qßä´ÜWØö°o ¬XÀ&_l†[%€\£î3z¨,¿æÒ‘RÅÜ€÷Sã,HTë¦F»ŠÓÌ]ò›?²ÍúaTv”+šÎu1ânŠ·œ"[y­M¸äVlÞpbSéNAâ®xPúL9ŸÒiЉ@ÏŬTe›ey@£‰Ï”E|G%DÈŒòãAo#Цu¶ü|xªá àÐAÜù}:âô \•{NJ Ðçu?g±Üãb²­·æ€DÅó¶ Ï U}@*{'Í›;h±t &Ý=xÑ?ZwŸ­&³0œ®A§âìà+&È""šsšÓ*>§™K_^@dÕ2qFVü€rlN2“•m=1Nxäe±É©+>IðELùÄ(Iüzƒç+A•Çl ˜¬J¤Ðºº^ÜùÈQóªûŽø,cÉUºSë=žë;ø"ä±îÎ3vÄ•Ù÷TÑͶ4—¥QàéÕÁPt¶¡ï‚"2î½P´ïÐ׫lüGƒ”Cjölêt>rm'O‚×RIæ %Ãxýñˆ^¶z˜=ŠNnyS\ëÆ''«£A‹$–H`DPo> 2ÙV³ ‹Uù’[Ý6º§Ÿ”ÐO·Í¯-ÑÌÉ>aGñè$½?Ö½|ÆŽSú9Sñ‘Ý0'½„ìÃW˜‚Ën`méó±ð(<àÕŒ¬€uK>ДVƒ¨’ÄXÀá-ŽetxW @2bðeÕVY{Øwœä„èÅ5‚šsêPèÌØî teÃпæ·çaO²AZåü6GöðZ0zfaZc5Nè€ÀÛ„z£ #9íTµ+ìIý7²/—C™t';‹ô@(XœMÅ;JÒC:Ó†Î'ÂnŠ#>0f?;VâÁ¡#‚ u‘$ø—ˆüÁöÙŸzŸî8IxÓ±¢Mã’ÝV×Ef²2»=VÛî¤òüIêÉéjJšßñ’ÝËüÑ02€Ã]'`kGb9ó;vĉ>ÊÉ'ÐðñÈñœúPÅ—K7ò^1w¶ïsd´{õz¾ q‰Éupè9s,ïñãÐx‡ =>Ÿb^_ßçû#ÍC’÷9xï &þ…KtªR^‚ÕåeöÌüÑòÒ¢LLën¼·ál¸¢>ÙË,äl)ëCÒ\Îî$Ï¢E¤’}LÛ{2²´´°ÏÞÔÏ+]8¾O÷ûž°Ã;iÄñ•ëÎÖ¶fü$ð’Ó?å™Õ6EïàÔoŒÂ%'ï<´^õÙˆÝÔ„ÒCì‘_ϲ;’³‹a_ k>Hp`vJ82Tácþ¼ïý¸“d/*Xy¨ú*c’"¶Í‡9‚X]ÇQÆ«[C-Äe•k¼:® ²f)•B=9é­KLû•ÁçZ0®DÀ®Ê¥¶Ý˜/m¢ai†âtàÅuRU~)jÂ1©ïs€Âç|a‚îD’Æ(I`{ÁýxTè`2îÁ³hÒ§tÄ{¨ªó ÀÅÞ¸_3à^u>¬"`ï½;Ì@Q5¹»«±òRèl«²K ‘1$…R‘ª•BIíþ)ÒO;ŸK–QÅëc¤Ö Óª…ûT»«Ä?pî " ’¢ÄÔñì:ÞÚ~(Q:Ê•Mµ/SöÇ(s¦‰CÎ^–CdÞ¹Â7­I΢xMµ½Î »*Ys]‹‹éå·KƒµB'þKÍ Q±“ÙðlÚ²†hªÓs`FPÿ Ù.k‰ä<bË?)5ÊóäòžÔQ[Î; ¼Q~’Ê[«œ÷zxuÇò¡.}>2vHJç´S–‡ú;…æÂ1{Ó–Ä Ê«<$f\fžý*ñøœî¸¢Ù#¢lýÞ]E˜™lû`œ1™ÛHÌÓy„¶+Åa'þ•÷x—®r®Ó’ kDža­Ó­\·æ²nDÔ]ϯut2­M€áõ±NŠ£·#`ÃÒϔЦ¶ÉžcpÚÊA6=D&ИÜ*ã.o­:–­•Œ“´wYñ(Éœ #à¬ó‡ý“ú¤õB}  }¿c°#‹ ÍM?F}‚)U¦Íµ'åŒ8«_ˆ S#Ã"…BH_Ç5V™¬-ɳd /×àeAž¥/2Öª&²œ‹Ò5ð DÌ ÊЫsÓƒRƒC7 [­I•¬«I dÎîU„mœqÜu`“ðû-9wÜ~ŸÏ)~ÎÖ=îV· XÊ1êÅ•[½ÐuŠî-ËrLUìä;¯9 kÏs”䤎ôsìI’Ó0˜H»#;/çä‘"%²wÕ¼q€ëø|„íRÉUå×;ó·y%m¦}T†Ùðn­IÀsŒ¬½âT5V•ç t@­§–Æîæ‡Õ%ýÞ~#ÒçРþhS·$ˆwøÇÞIzBôÁ‚¼7]QÆé5{’”¡Íd`¶:•z‹C±´H@Ê€ù+f ИáaÔŠ˜ÜKgÄœ}„\âtßùP$)$¥¿Ü8*¢©H'JqN>»8Ø ä´"Rò‚; ÜþèÆ-fUy¾~wíŸ3dØpr]u 8„_³ žU½&/í1¥®O@¡Þky|µ•³uÄ -ÎT´eàP FÍ:¹¼ãW5ŒáXÇ©®jJîGV}Ú)϶z»¤#¡%W/ñ&Þó‡Q¨ôkQçý ©ô»/¿ð”ÒëîýwúIué7¦¾Î?¸aû¢uΚ;Ä»šÏ|Z]%û¢;[£~½Loï”’« âÍ™5gIÈá—‚£õNIÎí@Áž¼—º°]ÌNrýùNÞì}*Vñ¸?Ù³'˜°ÖKÚ`·g½¶Öˆ ×ÑÜê2œñœ ð#;B¼c©(ÜïÖÑ®²7 phÛ–½1wº¬Jߨ¨–Àt+;I·ž°´ƒ¹•`˜À*ƒ$³©˜ÌäPŒàºù)nè2ÕV[üå7lèƒÿHÀL‹àLMPË„уPZÓ–/Ë@rï×ùƒéesAªŠÙ·FÅQÅðŒwîðbx¥õ9‹á iNWª`°¹›û=úêÇUøqa³¾kõóPP ¸C ¬(î:xƆŒ~¯uåäãôRB3ë'ÔLɪôIè}õÑ…M\‰h{ëÛ]Ç3ª/>•eMw Ööô8æ!{¹æÐþdi5 ¤*zô˜¸ ©‹"d…~â¶fœ`ñLÇÔØWZ˜AK7祢>’_Ür2Ÿôß7°ûÃtòPÏçy¶eéÚ`ÆMú_•7½®’;ËæÑ5 ÊÖ»âz?)a—¦F!¶4% sõóa—I·¢Da6ªû »LÁUUz»úóLè2ˆtP‰B#Â/UŸ©~ú“«ÔªŽm‹»Jxs:ŒÎuìŽÇѰo…?(|o,ñ€í*Ö€M2½”>“eƒÛùfžÅ.þ'Ö`endstream endobj 1818 0 obj 5794 endobj 1824 0 obj <> stream xœíko·±èGýŠCP w…µ^¾I;͇4ië¢E’Ö@?ÄE*K¶,D–dédÇE~|g¸| {ç“%£Hþ5É%g†óæpß,Æ-Fü~_ï=ü;×ãâøjo\ü þï½Ùc~È"ü¾^|ùÔc 78͵\<}¹7MÀ†/ ‡_ï}¿|ºÚwJ¸å«Õ¾¬uN,_¬öÙ µbzyµƒÒ㨰Qp=XçF夤/OÖ,¯sãéj”âlyï 60˜ê$·žå±‡yÕ<×åj_€‹Ë‹Ôxž_ ý£Xä××y~„zäƒq´±DU;8®fäU´°‘*Ú„‘Ž1E€ž°£™°fè-Ö¾õ, ]çÆó‰@£µ´õUJ@%T¹î­@ÿýÊ,ÿ¸bbpFU´’ J˜¶=ýË—V–yzl’ñ%äEÎ2s+â.lì8¾¶~¨\¾Ì#Kø™$lÈ¥RÜ¥’ bëa5ÀŒ’ó–%=2ÇgÖ¶¡óžÛïÇÂãk„Ô‰+qµ³•˜ÐðÖûÀÆR9/Ö%`q…‹<à bKeyP-_¾[16=Z:ÿDxåÆH9lÅmßû¾Ïø´ó}©j)‹"Ú#²ŠDÆ^­öaý†µ$€0ÜŒ^Ç4r‡ýoò´™a& IîtùWrõG—ê*ª52êŒ žep;²ÅÓ¿î=ýÝ÷àwðq0VGãnãl_¯€{ðÅAî^GªL (],zDgÖ…µ4·ƒà“G»^ÉÁ‚¦Dž‰O—þ mÁ ÿ$-"Û^¥¶óôtšzRÛ£Õ¾–f@_øÙ³Ø:ùJ“x´ øÎû4ÏEjZêQ|¡Ï; ž¤¶×éé$õæ©NOë*—d¹Ø{•ÚæQ6&` y°À'̸0ÞÈ«©Íþ±ü=m<´2ž]Э˜c]Ф¶Ãôô#ÌÄì–ísN|ã}jû¡³³—ù~N½Ï«]ʳ”û~Õ¢\àiÔ€–¹À1<¬ˆŒ³^§¶3²}-†‡é/RÛƒÌ7y'óîÖËåEjtö5©U‘ýŒ!ó%Ìl¾~º÷ÝÞ›…4 -´—=P ¤¦_(°j=F§_>Ù{øäo‹õåõ‹½‡ÿ\°½‡Æ¾üöðóä«Å¯ö¾~²ðSÁë~ÆG˜œx?F?»Ì3û–*)ž°¸Ÿ&hŠo¨»ÊàÉYt7D'µkîUöYJ C±ál4ˆÆ£Ã™†Æ¥¯Vû mÇÑêBe縀x‡—Ù¢L=%“F“ÐP"¸‡aè%”Ô7¥Ä,¯ óog*co̶ÊY?Óĸ Ü.{;=oêw¥ÅU*+—u×Ej{4Šw¢[RÛ•Ò†Ôv%Û‹R¥~Œ)¥–%öžÏ®ÌlÍbÓ$q»µM˜ÉœEq+va[|$l›#Ã…/æNæ¸öRµHÁ›b ðQèì…»ÙóòˆC¸.=Fa!¨Ç‰N0ç J¢»àü3‘ ÃŒZ¾+1àGˆy?73=Æí$ £0söC"yg`Z¹“âÜç°Õ£¹¹²Äü'›Òc0/5§!9Ïä6»2句4=u“âí§x.ä[¿p¦çQéY“yaFݲ»SÈ$‡ÜìRö`÷Àn.ä—ìݮك•P$䇙þÞqÈ/Aù]‡ü9?Hm‡é)'Lë'¬AÈ-ÆLðº=:Òº]Ó+;£Ê}ŠÚUåX–éÌ^²à}'1P ¤ø´ãŸ!¥1¼¦ÕÉã"sßcù‰¹b.ãö¸ks.ƒ‚L¤·œO …­=OÛ/´Qa]“øcÏøà!ÒAèC¼Íø\Æ£[MN¹SM üÎkÍ[Õ•U,¾’€ÙpDë|‹³*_¬sP`PŸjÚnšS!hgAé9ÅËP7"Õ­r¡™”-å,ÄŠõÇ–.#’ÍÒS:@ :™CÄÃ%¶›ÞÀ ’E¨ýú9 ÊOñ0œ‹Xñ`¥ÞVñ fâ°ƒÆß“aœJ†‘ìz—Aªà‰Á”¨¥!œ¨¶÷³^e¿¦ª;ôEAmÐ@ÎÙ ¢WXè¾,¾ ¹!îú¨ª¿éQ ŸÜXÀÂû•€a½•ÑlGël Ø ˆ š)O@—Á#ô§AÚ‘£33 Hb®†Øu|¶‰ÚY$² Æú`¿ ŽVep”®[þAy³Ìû#«÷Qùûe÷l J°ö£ÀEã)V?ÊX·"«]%<¡ˆ¢¨rÄÐÃjMrÛ23Ýä2ÿ”BB"ÒÉä ¡$OL©wªu(!)„F9UÕA Ù©a5ïºDoý®Ë¬·®ÙŠËt®,õènç v³¯®8žáxg*{ã9tÚÎÒS>ú?Üä"2É7¼5l¶ø†ÌcDg÷¼¶OÑóI ^%×qW¸¤ì<[üˤ? êÛR"z¥5ë¨Ò*zÆ E:árêKrÕ”8æ~º~’¨ï%de…†3Án¡wõD ¬‘sEÞ˜@H²€§!žéI*¾D¨‰¹èÙ¾m¹M)TÍ)Ñÿ¶Lý3¯‹ãÈ¢f„eR ÁÙ] ¤ÔÒë‚ÂËæøô4¡°.±2&qlNÚ:Þb‘¦hµÎ­™(¿ç¼,¨Ž×\«nFÇÂÿ„ËžëT\h[þ´%بöJl }_Vúm8¿Vn˱R[èÑNñ¡­3¦GÅ“Y+‹˜ƒ­ìšÂÜøŸ.=ˆU<Ÿ,4˜)ÅǺ03 ãuM:œusV •x²’»+ñY+) J»iN‹T_I¡Õ§Èhq‹Ù’ö™ VÊ·l9³½œ­b»Úd:iEÖí¡¸Åtwɵö*GfŽáΩµ‰^÷yJªtsû) ‘…‰éº­]ƒºõHÌÇúQ 4~1µÙØVÅ"„?Å¡³÷#o"±ýó˜®çÑÕ‹®…U^6ì½E<ÅKóÐÛðZFãàYÈ貌£/Ñh•`Ådµdθ™ÃÈëž}Ú¢i]à äqV bþnÅ|;ÖŽr_ʧ¾†­UÀo:šÛpMH… öTÕžË)ÛCÜâ†C—IÐÇÎÆ’éþeÍ*)†åYJ§Õ)Ï€p•@x¦Ñª½ƒæç%×â¼Ò¶Nñe¼mõë„1³¢âÓ. õN"ÃÕŠ8{ª+àKf`ª”C([ûGä(¾B 0¨¶œÞÅ+ÌR'Iã…÷ñ±Ík|˜Š÷!08p:ÖD3zZ™Û²œ3‡¢ëÊO·¦^׿éÔžÿÔ©Ýì-’‹ÞRo®Pý¡W^Ø@5§Œ‡—“ ™N¸|q¼ ¶{¿ó6]Ô0­Kóc ¹¢ñCY֔₢öé톾« ìM—¾hMçeóÞU¸“"ü=‹t%DÏ–Uíhy ä8==J½Ÿ¥¶wÌ'Šû™s¥j^ãp"³Š°ÁygÂÎÅ’Dü¡íû)7…[9"³Å!Y¾Žë®Úé?‹ƒS)DO[ßŇG펦Aõ}”6¶Ä¾·úÒiÙƒ>­xà·]€¡˜‰ÙéL×ªŽ˜òô«þ¦ù()pq#Ê‹-ûq¡ÄdùJK>¼ÍœÐ»sV!QòX¯·ÇŸ;ëfQ©«¼;E8 ï.q'I €*³t³©à‘p³)9°çº~Wš{A§ðªÖÕ…”8ìeÙT°DjJK¶}ZíXñOÖuÓ÷ õ±Ø4NLÆÔîGd2‘{ã [‘]Ûð-S[`à/í¦Út.r;yg1Ò–È&_ú&!Ë34ò¡‘Í”çÙ1pÂlshrN»Ã ñmÓÇ^¸9È!ä­†S‘À'ákS-c}Ì}+xøÌ)¥ÎCA“,¢Ñ¸*>s÷ŠžxOLá3×\ª/|©Àž^ò¤ó½Ÿ«z®.rêMZÍ—6”ûîS¬®Dò䀱º b·Nƒ¬Ð¯h''eMGš=kÙ~•ƒúó9™‹Ú³Dl ük€¿‰* ¸nýe’ë¥É\G¹Ù@³o0•«°†¢¢_Õ× Sͧ+|±Ý®WFÂ]½¾–8í¥¨«§ê¦QñJ›äTÐò'„T8‹l¬\Ñc¡Än7Å>) FÊÀI²}Û'±æ/PRÍVm¡n0š¾µùréò÷ÈëŒa¡|WKl¨«ñ ¦öƒ5øX~]e÷3Á˜Œâl¼ÏDÝg¢Ò«÷™¨&ܺÏDù‡ûLÔ}&ê>uŸ‰ºóL¡“‰úØËí^]Ê­©§Ý?€µ9YµñÎQJ¡)~ƒïRáK~̃˜Àêº&7Ï[¥ÇÏ]¹_l⊠™JßþWÅWÃGåÌ÷SÛ#}§«,­ðŸMq7Ë]ív&ñøÈB¹™lNYÎëibäLŽç ˆJ2‚@ŒCóý«‡«³#å¥@žÛHúÜÎÄÁ)Á§*hM¼\ÝÝi#Nض8Ùè?`rtþ¿ôƒ´÷‘ç}äyy¦ÞûÈó>òlzï#ÏOy’ÏDu"Ïæ‹Q©ÆÀæ¾OQø°=–üˆÂ‡Ø8¦WbDc'>.”¤<ð -à,‘^hünbtyyrÞyö¢MlLEùßíýÏ”ÿ×endstream endobj 1825 0 obj 4556 endobj 1829 0 obj <> stream xœÝ\Ûn$Gr5ö‘_ÑØwÛêšÊ{¦d,`­µ»cX¶$Þ‡cÁ!‡Bœ&Å!µ¢¿C숼F^ª»9?ˆ¬¬¼FœŒ8Y?­æ‰­fü/þ=wòâ®çÕÕû“yõGøwuòÓ óUVñÏù»Õ×§XÍÈ““š¯N/OBleøÊ°yšåêôÝÉ_Öb³e“5B«õ´ÙΓÚr³v›­sf⚯ÿ¼ÙŠÉH#Øú~3OÚX¦ÌúzÃ&§]?`Êrh —í6²F¯¯6[®ød[ÿ^žfjëÛÒ+ùy•¥™f¨ðÆOZ§×¾-xo}ã›·N­ßøq¸y¶ë÷›­œ˜P‚ý÷é¿úÅa+Õ¸–8kn&§œ]þÛÉé?üe}ŠsáN ·~»ÙªÉZç4CÐZ1 3„渂Y`)ó¤¸]Ÿµôìßâ’OJ:„˜”rRâlR«ï°¦ãP˜j*‹ë1èuJ­é‡‚=‘îopP0?Ø¢óRJz-M‘ç¤Õ»RõVÑi¥8ÃUä\M^ ¥b6 ›åROƺõ=1-J[¢Ì@ ‹Í†ª ¤ 7°+ ÄÕPZ4âh/bU#×C94°¹°çoÛ•ÁΰY!A&%¾–Ÿs>IÒ÷óh¬7Õ´â;a1c(»(?\)”P”Ó PŽ]yŽ‚ ˜Ù¬ÿåP°YÒç¥Ñ¸oLá ÃKjÐÂÇ\“Œ‰Œ÷B˜IpÕî…²è]ʳòÚ/t.yc»e÷¥ÿSÖ2I¹pt…/7ÌÒ*¾þ N.“<ácÒT½-iç€a•Z?Ž‚öφU/ÒfF5‚ãtcB†qKûº(¶øä¤R&"â †‡°M{º…^xØ×zйzFHļA)C$Th÷ú÷Q0%¬K„-©Ú.a¿Ød4(y|jVÕCŠ›@ ÖßÂúI£,3aQB;ám&p©ãÛoóÛ׈\³ *ž ¯òËcðô×3Oàçå–;Ë“ÚacAnݬ$Å>«˜áÐQ."© gAç±Ñ&_ˆ2laÑ` å¥Çòü¦ Ä&| ¥õúu©û„cS¶šô0 A4Rz^”ä–aËžfÑWëÜ‘l"ƒ_À¸PˆJ’vïò"`UøÚûHÁ-5Uלå„-]%º[Þzµ)H’ú¢ƒêS„C!,a^XxþT ïøIbžÁï¶ :IÆliWy»d^AU½„©‹³j4TùD£á¨5I²²á䵜ãt˜;–Q!rF†uUð¶ü$ÂC^#«t1DØ•Âø•W‰ Õý°tGû]áâÕpÉê_ û%peÂ÷A¤ŠLèm‹§iµXø Où' Å6IÅ0ÕÚ™áèÛF€¸¥L"ܘNNví`—«™tmaÐ@¶( Í“UÑŒe̬4 IG;ö|{/¤Å•Ã_ð Ì/•=ä_oö=¢h2œœ#PB;%†Ô‹"¨Ã©uˤgm²üòÁ2‰åí,vGQ ¢£pI‹Ç¯]ÿaÃàÜ0J×¶Š˜œÔæ¹JT|j«ë¡-» ¸Á¶wwk—ŠÒ7ËÏöî¨ÃÜ!Úª†u°Þè÷¢*+j¸6dÁ‰\oËŠü&8ø0l€¬3Ù4y-˜9‚Ì?Ôå‡!2tzïí¨´ëÆÑá¾ÇR¯ëq’þµ‚¥¤‹õ‘+ g%º·ü`úCKÏK³hu0>ñ™SÔ$ƒ·Å‘/èÈp™¸I °eÑ0$Xvæý É¢;Vd¶•aZgÅù#~Ññî¼£¦HôÉHc©ô!úw`öû¬êõî;¶&n¨äŽz•Ùy±Ô°:£–¡T˜,s%b$ß ô¬AyèÜ]-m¡ßÈÞDóuw#D{Ó-l‡xÜÀ GíH)lÕ’hÇ.šHd"YHWÑguì¹è}íËòV…É\ˆ‰E–+AfA-æJ¬Hë-¼4ˆ@6¥ÞIè@[í×âã_:KªÔªÆ´lå¯Ô‹4àÐÛÙÒah ­þZ¼Ð»zKŽÍ¬]q9? Vúݯío8(„¨ÛÊӉƒ—Œ'—Å¥"Žq„v¥ô"yø ¦rg¤–µ0Ž¥¢¦RáóT:"Š=þ_7 ¥jv*µëFKÀ*ÀV´žQ )(ü÷àâZÉh*ìC ‰™Qûç£×ßxvJÏùKyý®™šiþº 47¿”ù `MÒþ7¤Jq}*ÂÖ§±”:ñÅÄ3·$Ãÿ™ù®°Zr^È[8~HÝêbB/lŽº”‹n—:#˜_òÆ Õè ‰F‚×ÍiL‚­uHNµ§’ ¼ÁPcŽ Eãû—Cuœ#B, §7ô¸"†Þ0±¥KI÷Í“â+î×Ç #4Î/£`Ì8Æ9^Å`_JÁÜ2“–sÄ­˜î'«Ìƒû]’ÝpbÒS–—r}åîãaäbÖý,Z#èÇD·ÈEgÊÇl™ßº$<Eü¹£éšávWlŠ »,±M, e²…d%B­ìMŠ w]ÈâÛcúBÝVâ§š”c°Û«‘Wä—zÍ=F ½xmeÁ kLBôhX5ü¿jS ·˜hL²Â‡sÒ¶Ey³Vô~ãQ]—zŽ*Ga)6N*$5·1¡]mæA’pïŠå¨ôë!4Ô&> G¤˜mi,†Æ›tÅ?+þÈøVÜ8QH:ƒ3ç80ä_lúkÎC±s?)‰8\Zz$_‡°³ ûŒF¡ß ç¸ByY¡Õh±Äƒ&úgx©÷÷ãÈ”³¼Dš¤A‘1€ž j^­ÎÂ2ÙX Ï6T5â#"P, }­’p¬5ÑŒCvÌ6x# è°Ñ‡² Нºè­acG¥¥ºg}©ZŠÅõ6]“’à -¡; ÆËkaPšDƳ‚Sû²¥RµW·/ÊçåÈ&ãA)zíðùÆLÉÖHÂ4±½‚J{¯ñ̪‚-Â*Ué¨,Bæë‚R¨¡¿à6<ÇõŸÏõûh‰iŒå¥ç›ÁÍÀÒ),! ŽeêR]öØÀûSS÷¶HÃhoF¢>1.kß/½N ÃT¹ªjÞ„q SFüÍÝ‹¡×?¿³u„}+éâå1"¿EQàÙjøî2uüDÌ4·mæmµ?­úÀ^:ƒ!k?ì©01·Çã.?Ê÷ÖäÆà¸Ç£®ìPn ÂÄØàå½Ä0IÇpíÓyû€õwJ›äÔ·7è;Â;]°ÂɤĂî«îã„Ûàͤúlj¨ïrvp#5XÈþ_•ú ó„Èé_íÙŠŽ¨¢"V/YëÛjßüi¢Ç@L¦ßÝ!m+¨%‹˜̆G2ÌèE;ÄÚ æÐ&Ä÷‡·‚v•y,ăiiùòµbËyù½ºzK“Dz—7FÇ©w‹¹ê‡i¢£ãk¯ ÔÎa…­‚ ¾æ—ÕQº„v¾‘Oç.Za¡•_³>A–LƒÁ¤½½˜Øæ÷ùqa ï.Ÿžå²wƒÈí_sÙÛÁÓû¦ìP\×pï~¬0GHÅ©ýs8f´X¸¨TGqxH%[{„“(ñ6Ã)8úÇñ"¾ªYæEü­ [4Oß…ËœÙûæí‚YØ¢½mð,Ç—ýšçÝ_^`o.Ç/]Œ—¡Bh¼×£#áùú#„a¦¤‹¤7C}(éA3,IK8ÏõîâSÉÍ€ÿÉ{ã§ñåm~ü»ðŠ´}‹!Ÿ#´èïZÅ`Ðð)OOYiðÕºŽ;•[Ô¹•[**9~öe*úmúÑGŽ\ùÐ×Vk61«âÒV!¯ÛºùÜ(>û*½ÚÒËøÀ^Ðò[íóªØé 1çF½=Û¤n‡È¦^º¬™3+’$VcÓq1þZ•R0blÙ†njn˜¦ó=gE¹‹>c~f¨Ž68û Øˆ§¡Â-š£˜ˆ¨r} ¹Òʯkr ±Gðå[˜˜`ô¸r6,|b@dìFÃoròü'§ªë'£™4©,hŸ„[Ni}LÈpÃN™qI)ü¸/1ìÛÓ֭ƤlÐÐ1©YÛ}㨭_Œ¹z­é÷½„8uë³7ö\nHW¹ÈkÕÏôE¢ƒ_ǬJ})LßÊN;£JŒ‰=ºy¯L$áûÔŸÄÁ¦Ízá»Q$²X1.1\`b—Cv`Y¯9}zPL&ö·Þ€çYŠï%Q»gzÏÁ÷Ñ×}lfñÃWžÆ±òØ( ا Çi)i‹¬ÁÛ’¨DÄï2ë §54‘ÇQŠÛÀø³ôù™ÁGÞ–¯† ²¢>LöˆœOßU_gJßYèï7UGò«–xD|gëÏ<!Óå$ ¤†OVë…s¬´óežÑ±Æ6Sì¹¾ç}câãb&V™¿™Aßgé‚ÎÖ?Û¨ÓEãã†žÚø§A¢xq@^ç§¿PÇtÐ\wËP\N7–a¤ÙcY¸ð±t‚ÖŸUX8rjãb9›óà ª'l?´’¿žqä åÞ2ar´KÇ+ñhê÷øû ãð]öÞøz˜UÑ^€ž©1Ùå¿ÆÒÙ9º·s×G‚–?´R»<Ϥõjæ1l_>Ç£ -_. ¼ß>^¯a‘ÇÝböêÛo~ËõÉÜû­Ü‰~Q„ %-»þd¼À˜þÿÂÚíçå.ó+75MæÍÚŽ{{¨+᳿¦¢†„+'6ý¼çÙý³÷] ˜:w_§²›\ÿÚ?eH¸çW)ùŸŸ^¤§_ÁbX‹ñŠð|ôß'ùòc\;|úÛfî-™ø>ý*ò™>_´°6ªaLì·´E/ŽcNÓ³¼0¥Ö?öÛw[ÿ(ðâÊKmD¹@™Ö¼/Çq­ÜYt]ÁvÀ„°  > stream xœ½\Y·’7½ä/,ü4x;Í»©  ‚Fdyˆó`íjW‚¤]YGì5ò/ìœ*6"Yì™Y­AШ6:¾úªÈïÎæIœÍø'þ{ñæÑožH;Ÿ]¿4Ÿýþ^?úÅ.ÞœýñixLœùÉ[iõÙÓ«GkâÌÉÉ ïÏœ˜§î¼yô¯ÝÓý¹š¤7Êï^ìÏÍ´,Þ«Ýóý¹˜¬5ÂîÞíÏõ$·¯J-'cÍîÛö;«|_{¼/ž »+r_ÊIÏ^î¾Ç'¡ÝËý ý4FŠÝ|ÎKcÕîméÉmùY>ô¡¼E:r³>º8¸.ü¶‚>JÆG>{S®^—Ÿï¡å&¥—Ø‚šÀÎHm'·xò±µ‡^C?–æÂéø±ÐÀMi€4û"·EÅh?)—gXµû˜}]«¥ ßóÕ?ý[YI´³Ìâì\ºÉž=½øÕÚýÙèôF%;øsä'<ÅE»¥©æÉÈ…,ÒÇrÿu?/ C¤²ŠiÜÖ“«k×LÝ5³LÆø%uí—¬Ð|¿×Ð/+<;:á§ç#6AÞ#"HV•È y¶È—8bZæe÷Ÿ½„U0"²r«Mî»rõcÝ•ENÊX¢òDœˆñÛÜ0mÍýx±Fé«aÖ4µnäÑyáåç«Úüx9ÍJ%3±hK?VÙÇÕ¾‚´,µF…'ß²ëÄ&ϵ@¨sv.4Z}3b¼ E^彤ÂDî¯ØÒ®ÜF¯b*ÛEìÜkú¬X&±ÀgÌ£Ô«`á¯ödiº6(m>8Ux2Xqj|¶–°Ž™ÜÄR'®òÃHI%B Nf6fà÷Y¿þº³ÌDÈÖ.¬Ã­áÄá"C|sF¯2hŠÅYÏ0(›"iXT9ÏÕT‘ÆËùUy9°Q¸v1¼Ë uW%"~öúDÌP%îµ áʇ‚lÖeqÿ §š¬[J"ܨ½Š5ôk'ø•^žUj­Që€p5Ö·¬‘%¿Œ–ѵN5á²áÆY Ö (†Öç‚ ,BçÞfHEµ÷®‘Á6ªàmRÄtZÓ%|öY@]BjÇ€:X íŨ“y‡#@]î1mܽۃ)°Îb¥GÁž}è`À€õæA›‡pÖëƒ&§’6*‹‹ñç"–Ð=²³ƒ6IŸ[çê!ù@Ò½ÔN!2.j@Lgk$Á±-Š·oIŽIÁ¤Qb½²ô üÓ·¬×«ÚZ ¯l®úh!F röq–Ý7»blztÛ®=én‚·v$¬güX™®ÚÜrígú _ûf_:ŸåF ìçª N q).S0o—=+6ò.EèÄμe•{­o+GgñºÓ[ÒB)ÁÕ­jjrZ F ^쌴Ógà<´Œ´Ôhp!ò†aÆñ+|{qÜ„óç•SzçÙ«zî!RDkñÕ Ñ4Lõ[è Ü—ˆ‰À³ZÓ0(°ä³Æ‘¼Á÷…PJ-ôò{Œ1fC¯Ýä–®WÆY¿{WU ²—x]ÞzžZBÁ›´• ï¹að i»§ôô×´´vuÜŽã)òИ†n Қȓ¯µxRKo*Î,ئèê¡O Mz±›õ ¿®Ô‡) ´aèÜæ0Ž’n†ÿTˆ¾vZ=Þ¾©ú‡)±Nóƒbâ÷Ê ?ḭ̈ÖS ‰Ñ#ñoq(ã‘àô ßF!`û"xuÿÊH.YÛGÆ÷mZŠ+: 2Å(Ï9ˆ eФ]ãá¯§ä ··Š\åïÚ($¨[¢çyÒ`ž^AòÇÑèèB-`n”`à*¢YUm®ÆEÖ*Ií,©( qÿùºüCSÅ#0š ªS¹ä#’´¿×í(Mó²°ê7å5ò‰TÅ`68|JAGé¨!31 Ù™ÓFÄŒ|,ÏWч€*q¤™è­PnÅ ­]0ð~쾪ê^㳆Mñ´–è¶Š§k€òÂSoBl-ò'ƒaç£r>Óz‰/á,éA¹Ò³f×q¿š!X_Ìî'Ö£ý\™%0.Ë^öH³¶—/YƒÅÇøÄú¡÷ó˜=‘žÔÄfQØ|Ka0<úSy”dÍÈ| ³ê-¸x·ûç^CdÆ4Š$¬9˜Á$‰ù劸sð#‚<ÿ¼71^ J F`|N1ã±p¹©€½-Wɳi¶AÔbilëéV4URò’Çⵆ¬KëOŒæ,£C/œ=ºS"œ\,oçIÓX¾_ï&–'Ö€Í/RT]Ð9‘ÕD1`›µ¨ìų@0ùeI‘dcšXDHàúQH5Rýc’!¢Cždب€iõŸjª‹È0º0‹q*n6à› `ª•X¬‡µs+Øt¤Ø 1x÷ÝÃWqÄz÷Êो bOc&?;Ò@O66Š]q¤Ì}Í/l0g ›®Ñ™Í5HF‹¶êeîÿÌv ¯§g5HlðGøÑŽ%žX!Ayí<诇¥¯ãužŠ#ɬu±µíË"bdàQÐ=riM¥ëš¦xVÔ—„Ÿ$j§8 Ãs ÜåØ55¼Q&×Ï• I$ÃrD#¤ó›Õw퇰l¥vÇG³D1´CÆQ¤Xá?Åt+¸âŒS¶·1–ßÊy±[J2ÊÎ%uûµÖ¤™ºB…LÆ”Ùj Jhìt†E)””5¾È¼ÊmþU(–ƒÀk7M_X¼[(€ÿæ_"ßUÌÝ/ò]$ „°!1šn¿Ï· ð#Ó­ÇÍç2I •l-5€Ñµ‰³òÇH˜0¨4ÖQ-ËQy½ª35g±Àä$λ³cÔ!€gIˆä¶Õ·Œ¶›È›BÍífd“í*–ˆy¢Ïrâ|!«鬱Ü|èØb¤rÄ^ëQ_ôMÂŒX –©Ý9Ybã&)Âò†ÈÊÕõ[®2Ë›¨ù.%Ç1³ªÄùITV¥ŸmÑRSÞG²YD4n¸c ÁýÄð]­s @îçrõ‡òSNA•«S$¤Ìî¯d¸·¹Ê®Žƒ6#úµ„ÞS÷åéh:œˆŠ#¢œ*Kà[ÔOŒÂUvÇõ ÖÅP€E¥cݤ¦9‹°VãD§ÄGì[R×d¯ž¹‘:œ™k¾6—Ÿ2wWGØî° Wy©¢Ñ}tÂumMÌÄÌùb'^xQ•’qw„Sc RÔ¤5}«“ŽnÇZâ§É÷‰øËÈ$ ²ý\ÅɶªµX¢|ør¨º)>ú UXÃÏ65» B°yÄÎS²Ä]DЊC’Y¥â›\}p©I ÃÕjIñ¡så‘2XCq;ü:çv-<­xÃum3mxY”:ªòlPSàÁf;®z8â&‰^÷%÷ŽfÔÈPæóú Ž»òó÷ð(1@ã cÇÔð·?—³¡µ˜Êתc‰TÐÄø’²5›•|Ùi@±Â·9÷¬UH9jƒe.âAÖºð“Ñ´Œ:Bbå4'Ã>G¨P˜ 6À¯UV+zíĺÂÕkˆS³a0Ë©5}Ö¡oXÿàa]âll€»ÎfÿÿáPŠe«’0–¢>„’ p A?”Ÿ•–ã†I¤7²¥œĽ‹µšã¾V©NSó´a“xԮ‹=&;^cϗโ­ò÷Ч’wg”‹ŸøªcƒFHjgœkÚO®îK_Hêá\c¢ÒO¢ÿy6Ú¸÷Ív”3VÍB¯ÙŠ¡Æ*u¬Áç%I†‰´ +æ=•&&›ÓR~d_{ ½ãP%™hªãGUÓ8'r‘lö g.p/$Æ](±ø÷Ä:ØPyT@ÿ½ÈçSÌÛš””dMg‚ÛÛ€uYÇmâ·Qw>ï{¢mµ|x*Ž¥|ø“ÌÕñ¯©ñäd/YUaw‹5t(x«D¨l0âR.V }òùi_Ÿu¡h(zV×eß\&á=Ÿð..îbä?ø4V*59¸Kg°… fÛ…`:nÊo0tù:MÕQÕ&€´Õ˺ôH´›Âö ¤N«‘—Oã^š³¥RˆM‘Â¥šHcVóyk`+æ}¬ êÅ:þ«Æ†½µ•%ºJf§O¥~S!šÄ¤`èn§Bò¼$#¿ÎŒ¥Í–×¢‘—® ôþ:—„w×­}è3q`V6ŠÐÇãŽÏQá~†í|RzÈ´†ÕerRoî•ØÎËÉÍzGÁÇn³e'§§²ð <“6—9õ>ÿz™óCÇäŒR媒ðÕU玲_Ÿ;7¶vë„*Wå0ë¤üU£ÌzBòÁèý*ð7 …æþx¯Â »Ç°¿kz¢.Da|^µƒ3»·æ³ H›ÇĘÁˆ w"“^êlk0 â¾e™F ÜÏV@kðü•Ûp>ÔE6›Þ‚ïÜØ¿Xy¨\×z„/LîíD·žNih0oXÛnú9Ð-ŸÖÔ¡¤"[óI„J§3 œ`DcÃaçq¥ V–EÄ}ºˆÍýéé£ÀŸÿpb8'endstream endobj 1835 0 obj 5167 endobj 1839 0 obj <> stream xœí[Ks#·Ι—ü…¹e˜2!¼›T*µŽËQÊIy]*û`ç@IÔJÉR×ý{7f@”¨©åfU.[ã4Ðè¯ûë4º©(aõÿt?O–“ƒ¸¦ÕÛÛ ­¾…ßNn&¬Ru?N–Õë£f¯qškYMÚ XeMe%„ËÉÏõï§3E¬£Jþûè ¥`4ҢĪNÑiSÞÓ¾˜Jb…R²>iž@­^6OÒ²ú:<ù©¿9š¼™ÜT¢5ro*ÆŒ!Ôú•ÿ »{}898ügµzÿa19ø©b“ƒ¿ûÿ¼þþkøqø·êw“o«7k÷¼ÞzÆádÁxoèi0¾õÁzÏiHð±žÃÚÛñÌ6<‹ç°ñ·ÑÐE4þ›|¯ %ã]˜”K¼Ê í™ø a æ¶£-CÚÉ´Í#KP"ôèÅ‘vZüºà—Yõ*¾½Ý:È9š8°vÁÈu¡NöŽm·s’ Aˆ Mþz_ðæ*>]m ´‚o·Þ®…7A@ì†Ì•ÓV !6øàpX3Vk¢a†«4Ãuz\¥±é½l­ÛQ€PŒ¹žéÚnœ@8:ðÓ wÞ;Z+¦ñj‹V*œX×W(£ˆ´ÄGS2¶ÑW°Rn1 %[Ã:œD¦ÏÍôÆÇý£÷E8ÜR\1OS\&¯œ¿½Éàôàá‘ÞÔ®ñ&gìy¼É™ô½òæ35¬ RLË.9­f!ƒ+òœà€0XçŠH1ÅP— š)c^‹Þ`4Eú*Wt§‡Œ+ „âðXHîë¬Ñ„…¦Ú„O§-uOð* CÞR “ÂüÀ¥ ÿ(k‘ô2-ñ6Y‹fHn—&@Îó¬$‘”ÕgI«g.W†p&ÐÆÞç#V9‰4Ò“äÏNªuc •œ „vx†ó4Ã<Íœ‰oœTªi É.9gßÜÚÖ#‡©¾LË\¥½£~-Žé7Ê™çÒ>—5 šlÜ÷Z¹l¦Î¥¾qTSèü"î„Û#Ú¼ëµÕÃÖÔö¦è÷•¸Kë'ô}|}enqè+)'p¾é\½ZÓË„Hô¤*œ?‚á@BÉŠŠÁq„ð®˜Á÷תí«wï¥@ÈzžX×a#^k“ù!k˜»¢—Ô”ä•ΨžÊ…©]Ói"Ìþ0õ;1BD†æ?ý¬W3Y¹RÚÏT“ý"bϾþÞ8ƒ0ý¢m ½ÿWªiïŠm¯)o‹·î7©YÓžrÙA­š mfž ÛEjŸ/SSjÜ*öÁ:$ËÍu(ë½9T"?=2»¼~ÞÙBe×’QCXøCqcF¢ÄEên9ÿZ,W¨´!µ*Cù&Í N–¤æqÍ1"÷»,Mòæ =ÍKV3à¬+½úa œÝõ -³ÚÝJîz ¼Ên8Ö_0^q#⥟w‹n:Óp,‘–×´$tñžñ$ Óå#ÏÕ½>‡Ð˜e#׌cIfƒÌd¢NÙàMëNF¢¥™èùßùXðÝg{;™Pl¹(\‹À|¨²mC=˜ðºHÆ‘l¡nLÝÂ,Kˆò(´I(Jˆ²&/ZH¢ßûdBتJ2d²0ŽƉ‚ŒtO ²³ó_ƒì—:šúj$^Ë Z„‡òI'º éWÍï‚èª˜Ò k—ïÙ åü„ì½YÀúbË~°w?··Fá;Ê’0R适Œ2P?ßïÅÑòñÇi!··ˆ[Nðôj#ÅEðí—ë/=·÷¨\÷ Þ{õ È_oÖ.|B¼åg€wäoQ={Ô›²‘6 çV/´Û†zp&üÿ‡úä‘ Çí?ÈÛåït¸^¼4eû‰÷>÷ßéÂæ¸tÖÚÓ{”'Cö§øn»×(þPg^îR¶œÚ{{—²Ï©ýyB½¯,þòòçt´FW)& E.„ º‚¬4•#dª ;ý¤xÇR|×/ÎþÝ*ˆb-_>€÷¶ø;uáÈc<  ÏÆ«·-Ò@V·ݧB}°Ãw¿Ó¯,›( 3@tò’Е„ÍYLݤ>8o?WË<´[àï9âpÒßî_ÀJ9{¾Cþþs„ö6³%ý½`úûfÿö/AVþt2|€ç¬ÿs!M˜ÿШýê…ÇÏiDúªŠâ9›OßL~+ T'endstream endobj 1840 0 obj 2368 endobj 1844 0 obj <> stream xœí\Ko$·rœKþÂÀ>x&Xõ6ßM9ÄŽoà¶#À‡8´Òê•FïÈ¿H~pªºIV‘͞ɒÖ1Œ…v$›¬*V}U$‹}9o1oñ_øÝ?›½üNÚv~t=kç‚¿£ÙåLôMæágÿlþùnßLÌ}ã­´z¾{8:s''¼Ÿ;Ñ6-ÔœÍþ¾øz¹£éò‹7ËÑX«^Ü,[x]ûÖ/>YÓxãÔâz¹#µot+¯—;¦é| M¯–;ººT|߻ؕW‹·ð–ÒÓ&ôjŒ‹ã¾ƒÎCƒ* #(×-n©Á=¾Àªé´^P)øz©c[ëûTH$²±^gïKÕ6¦5ðqŸØ9F lÓµvq>ôйÅ!šFXxT­KÅ=Ž 2ÃñÛ À'8p&5Ћ–Ú2Ü ¥¶5¼Á¶øš R6pFà¡j¦`ì„H Äa¨ó3ý[BfU#ÌŠF(ÄÝi#‰kgÉH™]Û•F0vF[k¯Æf+Á¯YÍÍà"SøH s¡lf‘ï7›1eÌtxÉ]…®*&}L¼ä±[ohnzTt7B‚z;kÒ]ÔöN=¶aQ) "¨¨Ëã•*«$õ=ÔtìØë›w®âñê¸sŠM¡ÜÆÅÖoµÁzº2<@ ƒåÆE]®²ÈH¸Ü ÔqsÎrÙU”'”!Ù ;BzpN+¢ÃèdÔDô†B¬~v!ØÕ¼é`3øRFC!‹ØKl‰ÀâªUô<îÓ¡©ÛÊKöþ.kz^êæ ™F^qœB”Â` ^ÑÈ5î6,al'q‰ð¢…i,+ü/ »Ñ÷a,Œˆ˜§üø=]2ö~Ao3ñ¡á(×(ˆýžÊ#³RE–eµô0,CÀGÙ¥m„i½àM[,Tæ… /€^~wÙmÓ™´©1·mר°ŸÑADß–è…_îØTBÇ•Bßê®_ûÅÂ7©Ÿ÷FÈÅÎPŠkû'4PA Óem‹ÕoRõe*»-jñéºr¨³C/ ‡'±ì 5{jm?å JÐ8†shE±á*ס-Æ:=­’°Æ’çÂXÙ›7ñA1Q„¢Deêb•š%Â/ãg9 ~C¤bÏXÙEÇaP#‰ã74ꇖà)‚»5».¹ë1<¾–@œô¤­)Ϩéœ*)iÇEÒŽ}RÒ­÷©ú"“Ž+ð‘™ýT½‹Né!LÕâwñU ˆ.dšiåÅX‹V#‘Æ©UŠ%bõËø.Ê%ýõl÷·(ëš¡nõ»Š¡^ì“FëÞe&uO&@!S»Àí `à:çÝ– *ìR®VØÝŸcÒ¤«TM“zTÔf*uVã˜Ä—eu©(iç,+êv,¬[`«¦H•n0q¬ PÉûHºJðr@ìMcajôäJ¼÷¡¦ôÝØü"\E“ÙZ½y¸RlU··­RŒ,¯ß¥{äi=Má$ÿ¤uÉñÀ"ˆýGãVub½ÜŸÜ j’Þ¯ˆ²[êœ{=Iµ„§[XrFOÇv“ŒåœQñ†æƒ!9“]êå¶ ªq¢\H•ÿ©A%Ôº«OÈ#L…ä…£©8]+죂C¬=Ž fÒ;¤ñžH<àZ’Uíûߣs­UIª«DW*o¦Bª Š>Nð1ñ~“ 3KGQ·ž1F¾c\âUáCç¯S!–7ECØy" q;«Dªj»§›È` ë'’ù€Jº¦ô2vTHÜ£BQ3d Äå* ‹üåÅí5:«ÎÃx–ˆUzã"ˆdƒÎêq]Rãz©b$²µÛzàÑÙq·ãhOÔÈIÖÊFJ€L"zMÚ–‘™ð ç_u²Ñ:- i¼Oã+¦À‹R]F”¶÷š›ö€=è8¼ èÇCË›Ô,‹Rv"‰;)^yÔUè^E]ܽ‡SuàÞ°)’Öñ4òI>£™ÅG4³$½êž@x¨í)D¢¢Ò|B«^Á¶Œ£ö–Ä߆æàs@2£BC…&u¢Ë–!"·TµÂ¶öú~­ð°VèË>{)ô«´8*¸ßiT¹¸Su–Ox²Ù²;m;¤Ý R¼¤;|'}ìö í{mã¬Á{‚ñ0³FÔ-ä~û‚ñÀHNM?"§x;–b2®¢ND7ùÂéñ#ùš~ÞB|¢ÕgM’dQw‰qBd¾öøUî ä RäEz£²#}Mx£8¤~ IŒ–$ë7õhæSíIñF\Ï…Ý̬Ã7 _ F<|pˆ¼¿xšSé†Íݰ¥ÞŽÁzê­²½›¿Xé?j?ÃsÝfWRòñ¯ÉP hGMí_TVA¹äCí$¿1«$ÞÈál250&æ©Eòl‹];҈ƻ, /¥¹®9×ùg,g·žGûOý\k'‡UÀ¢ÒYÁÇ­f#_RS:F­æw!Ò5ŸHäe®IDš%[°NorÂÙìEÙU>þ€ÂÒZè8¾HníS&-ëôª–þÆòrb¦™h´òì8z|p}E§¶(ÞÖ6$) fQM~&Fò܌В%¿U€¨e8þíZò_‚óدB^±ìóyú#sïR¶1–i«0M`ù)4Y†÷ÕR ÌÙÐ}’ ˜O"æIYȹë=% ù©ìœÞ( ­’B“4´ïèÝHññt”æ1•ÊŒ‰%°Ÿð´›$Øz‚õ{Ò&6 ¨¢é3¶Q|«›VˆG˜ï˜œ;ÊÙè5éc5½©v qуŽC'QÓøÉüAH†k±˜KbñQË"AF„çénŒ‘¼³>I1¡Y%õ«§•™-Ó“MÙKy¹r|ª âSBŽgªÏí(Yt­ZQƒ$¤‰ùYñ©ƒ•YÊè*¥y¼ ¢ ”‰M/«¹eC'dǸ!nP Å~ G„­3åݺä­àlØ“µ3Tdb±~‡Ë5ºë’S‰š¥Ý–¾±MØ\Ï×&9çV# á×˦ßò{vyƒ]"sd3”_“‰¥!»»jøM–Ça>¶– ü GÔ–ºÍŽšFO Ø.Ë[]…-—¢ZžÎWøDòóÇ!gòaw€ò;8‘ŒËÚ¬>Rú0©vÙŋʅ›ÞÂJ0ØxºpãÇy{1èÓ[7aúõ„Êò øG% þGLµ–"sF3ÆjvdôÕ $¥¯ú´ªy¡˜õ(G”á ƒCfL}Ì ÄwyRp¤‘ÙíøNÆ$ž°þSH)ëúÇf¢G® ¯£çîõÆ•®¿‡ìÚ^¼þjQ¿8ߢŠºWõX,"Ù>«Ч¿f#;Ñ8;¬jöÓºò<=Ñ™Ky¤5uüûiªý(•ý›­Cc-.SÁ‹ gï±-Sž¨cGÔùGqe÷YÚZ9¯:Ó¶Ãu¾"Ìv Ò9mÛ~F©ã7Óžj±Ñˆh"ð>+O4GÝmXzVa¼ÖhÅÈ’RneÉá:f5zCc=²!‡uì3ä†[Øgꬾ¼|ÄUÝÖf/q+è'cö÷IÍ{³¯œž~V9"&ûoUºOþ‹ýÿììS8{ïí'\óØûì>áÍ/ÕÀx©©×µ‘ºwõkµe<“0ã„EtÅeè µ2ÑV}Qe€EÕ™(Òj–]ùŸA=ªÞJÉþ?#(ñìPjyïJ…üI?’Ž6;ùEg›]¶Ê>’1qCðËÝÙ·³Ë¹¾Ì¼w°˜‘h”0ÉxW±ÃOº|þjöòÕ_æ7W·of/¿Ÿ‹Ù˯ð¿Ï¿ù~^ýaþ«Ù—¯æßÞ÷C/P€iRõ[qßÑZo¿ ¹šTà²z럹&&»Sî°Ø½úûšÔ?¥ñ§k² ýƒÂšïaÛ0]ß/;Ü+ÒĤo§â*¡¿?›_OŸ,ø±Nvi›„öë‹ÏõäPcm\OœœŒ>áÙÑžÕ•öèG=ùb§®v—‘PU‰Ì˧ã(´âgv†ì²1o”v£UdÖ*v+µ~ç;ö0 ùp‹ßrÞVï v`±øRܧÍvlˆài臃4|ñ=£>:ÛâÁaO’ŸÚ\®~à-¯{qªîó9Ž1ùx‚Øö9?Fç›¶}ô-²›Ýƒ­ß}ÇÁ¬oð˜bú;òÒÊü¶p~Hf†K–µCF ã</•ÅOÝØ~tÚòÁŠ£<|³Å'¼ÂÑ̰ëk%~‡ƒnX>ô,†™ìûê‘MÚ„óÂ:Ü¥ê,~ÁG<óÂ7FÂ8 òÆ„¦|‹°½v~ ãAšÈ΄è-¦¨ô©¦ú±r<ÑQªþ}“ñEüVñú "È¢#SM.ÎÂâôáßñŸ´yÐù ÿˆÙúf¢„ñW7xÌ•­:>ÿþAø¢Hþ9‘žËøù³˜“ðs³pFqR‹¹Ê/^­½bo|8P={¢uÚÇ¥Icác§Iç©y)ª%I÷ظìÇ¥H³ÈéREŸ¹p:1üʸdŸ"“9„îkc^ð™`as0CˆzþÓ7¼Ø—3ÒvVòXßÎþøÙ}Íendstream endobj 1845 0 obj 3973 endobj 1849 0 obj <> stream xœí[Y·~ÈÛþŠ_Òmìм ÈC#p$޼@â ö¶ö’´ëxüøÙ<ŠlöìÌZVVÎBÔbsÈb±Ž¯Ž~·¢„­¨ÿÿ=¼Üûê×tuúa®þO÷Þí±0eÿ9¼\ýþ Lc+GœæZ®Nö¦ØÊpb˜s+Ã(¡ðærïÃßGk‰e\ÇãZKWÿGƈÚ ¯Ç5#Z+¦‡«q­ˆµÎ‰á¦2N8‡' û(ÅÙpíϵnx?®%Z…_4ý-uäïUnñѨáMÙàï•wˆ‹ ý0 ¢”“r؇$%œ*<õ®,Pˆ¹JÛòá¼Lõ‡á~†Ž£‚–NkM\5 ^§˜?àÚÏ@S§]cj¸ô»/µHç‚÷èïGà•UF„PIüú¯Ëû«²Tâö‡BË]^muS¸‰È>ËSÑñAðÿ<øÓ¡‘ =G ,÷žTC(“èP÷…Òù]iaᮀUð ädº ¦„çe\à}œOS‹ Aïò<ט& dpN¾ßõm! ]6bëi< ŒiÒÀ|ƒÓ¶Ê1^5˜$–í¼ÃÛ¶†q–E;\aÎ1 ê 'eßëŠÁ ‘BcÎÊ„Âpmkn0gµ†¿áên¦™TÉD­„Ç£2zT4fÎ/?øÅ¹·  ÂÏ‚Ãq¸bÄ>¼%Q\:=|;ˆ`T€×ÒIUßT¼+‹1Ÿ¨’Vêþ胧OÁX’-7é—šgÍ@ô—¥¥$î? Õf Ec¿)²yâwRp…ÄxM‰¡Ôê \I¶I/È…$F³-ô4¿ß÷;ˆ † ;ôµÆOœ(é­º™%œycô\i"xRôþþ/ò£ÿÅW¯¸äf(سìiVÚP"£“¡£WBDǵÖIË7 JËžÚ 1ÿñH•ç:ØG ¼:øóÞÁ—•³þ ®rºÚ¼œ.7‰"h4¶Q]˜ÇÃbpÎ’:ºËq“ô¦¼?ðµUžvÀx"i€ ¶ éÐñðH“‡ŸºV>”sCÕÃEEAúš‹|"á¼ñäW…IeЛámºì› t‚Öf†™•ëäà·ŒÕË+Esñc0”VÀà¢B2‡ec›&㉦,Y—/Åàñl }¼Á^)Öa®Î (l/0ÀSV›'•2“ƒŒ4­Á«jI£›ü&:_L%fµ¾ƒO¸SÂaù;-¾ñ¢½ÑðX’´lÄÍÄ(íà€z@ žþÄÀp‹èÔ’PÑÂo®Ês³ üS…ôð;ë ¹ÅKšj– ~µ±—ç=íagÄh%ÑE÷ò(™&4Ìeoê- ?a¶CÑÞ Ù‰q&@>„ƒô¾,»[ ?3`lDÒ9*°ÿ*–d™ùýËë®wéû ¤s§Î-ªäiÁ˵›Ü¢‘¢ÉxCf«À59²2u¿5vâh3†FXü~’h4)º{0Z#™(ò­+İK6lLžóuaÉw>š$>Çu×2D˜ãshY‘‹®bgO§ûáJµDeQRØC%çŽnÁ›Â¯0Ó7ßç§Ûsa›}ÿ•Ç~Ècwùé2¿½Éc/ò“Ìo÷ó˜ÈOºóöu~ºÈoÏÇ5@N·JéõU~ýbswÍ# æ†Ü›£ã‚ÇÔÄ8©Î6hÄ©ÚÅÞÆèñm‰Ð—lP¾{D«(é‡üÀQÑýÚIû`]û¨Aˆ–Š­Å à±Ž¼>ÌBvŸÊÞæ{=ÎcWyì¶-ÿö‹<öŸy”‚8ÍèGÆ·i¡²ø)à| ¿ðói†8tÞ CgówWièEzùÝË8´• KÇr†ú/H.CÒ&ìÌ%ˆã‚ˆ÷sQ-àŽrSy_ÀsR2ˆ|Àµ‚=Òx"Z‰õEÜÀÚ‡Eô¨-$öœóawJƒ!k|!àð~ÌÙ…šo¯ÓsÕý˜µ%¤[Ìò3 ÖH4¨9­ÂÅÛ^twÝŸ¯°>ÐJž·?9Ïߎày"OIâÐP´‚iùˉ~ofú¸'‹‰ê°¶`œzÕ&UÐÍõ¯üQ4kÂÛmŒ—Ô"gè~Æë: äY'ièCz8ž¶®ñZkÁ…^ƒg¿¼ICm,,É‹q:§LÞ¸V˜mó é ÚOt,¿ãxui AÇG½ Újñtîc{`Ÿü>ô/OI5žÞUð†ô_ò*ü%ü:£©ÏYéŸ8†Fj'xqPè\¬ULèþ¾¤àQè¶œy‹°·;vÛ@jL~¯ÄÎÕáTˆan?A‡–Bhþ¬D¼lÑ("å. Mi£Pæ¬d½ª&†¼bÛÜ’ÒDÇÝ¢.»ø¹–b0¿ !OPÕ·¼è˜·öÏÔ×H€—žy ¿çä[ªs—Ä,?Ýø‹:à/›W¤ºª0ïÙéæ#=)‚E;}6›såAÞS°Þ÷ ƒý\y®Ÿïàƒ€÷"›ØØ%PmÓ⥚*A¸y9w“î˜U·pÞ¥ýEÝ6¾Ä>"‹¾þ9yD>`íàÏì}a ±0ôùÄ5öM{†ÔOM|Ÿ8¤ŽMÁQ¢N_ÌP†Ô˜ºÞS§€rë~5k%îÞ£üÊR(“]ó ‚ k„»"QÊ©~‰)µX•–jýÅŒÀ7)9#”]€]%îÀ¹Ül*Ù¥¡$µD•ÜôÉÈœo¢·8õ]5{ÇÖu®*Tõ…Nð›Ü,;5jR3Õ<¸¨W÷Xa°=•¡™/JE0«¿¬‰0„/\ªâoî™N‹=Tr?ì&Áûµƒn³ý”¤—Öâ$ýˆ­lú!TŒÙšVIx¿TÝ?xØ}`Žv@h‘˜uT7åý¶¼†m›Á‡°´±ÌëõM\ZÛê ¦öcì?ª‚¢.–¿B÷¼ªFÑ %š»ídêë”ûØ{17>V˜uå„ uWÎCí'æ.uLîöY…ïÙ±ZÿŒ¯)('?òס£]¤vpÍ}ò&Útƒ¥ws‹p;IËŽ ›‰+K&&ÑÒo;™5ï·Ìœ‰qRÐðÅb\›åí£[¡´lómIøÒH,~ÞâÅHWGŸt}º¹¬ëÅMÏ’a< Öèú£¨P¬Ôr¨Z'Ÿl,V4¤É‹Í hnÊè¡Û«ZÊ   û§ÝRy,sJ¡üiiÀEœ‡.^å!R8sl¨b®4T1ü­Ë¬¥jc^ž°¡uwÖ,ÓOBv²Q _³4íº1]8ïcÛþk¹Ü¯ŽÀfVW4_ !CqÛ:ðu¥ö<ÕvÇ,ÞŽ]À¡#‘÷Mq?aùP;î~˜ EæmÇŽÛ˜¹D£w=ë›Z2¯û(ÅÚê|¨ooÓ׆Þ~¿)gž{ƒäOÖÏp‰ÍI?ø`÷AnÁìu¨ÎÌT¸ `ÇŸÛM&IwM¥>Ær†…(AÖqf¥²}j¦6[)£+¢0 ßY§ûX í;á\ŸF8·§Ýô´V@n…8¤þr o÷Їs¼L …±´Ô^vÒïdu¾‹®ô¿¨Cô]‡f·Ü¨]Ï^³Y¡nǪ;|wO`3ÇÛrÚ&@üÓ‡ÎÛÍßå§ýü¶-×ùý’Ñ饃vk9eZ’ØHôWÔ­WŽ©ß2ÞªîoÚéBËþ¥ïCQqGÏ%»þD,‰þ#@hò\ÀXί~‚ÆÉ5þŸ—.žRé¹jñ¨›íW-W¯ø¬½w\Ë ¬1'ëÎ3`0äA¿Ü×{ƒ?ÿÿlލendstream endobj 1850 0 obj 3064 endobj 1854 0 obj <> stream xœÝ[YoÇò¸¿bhÎ¥Y]®7\ñÁ1±’yÒO{JûËÁXÃp¥)œ]î½Zì}ñÃjFk¥a‰XVÀvu¾ÞŒƒ‘Lk $øVÁWg0RŒÆ8³:}Gé û÷“rõgrV¬.ò¬÷d­kò}ê—°ÎŽ¾º‚Yfdc"\³¥ƒ“räniG–‹\àg—WN»°˜ÖŠid˜¬uNоÕJ"éi,™vµƒÒ£6áK98ÙE»”é~<nOàiÓH²æ8ç´Rœ¥VºNü§äN§mGçÈe;ÀYɤýÉYa$i|Wh9)럶[ùÏ pѱᴖsZ… ‹´öŸ¾2¦žXæ·pæ:“x:³0Ñ rdéŒØwÐÂfÀ²çy-3;pØôŸAqà»5ŠãÀUÛ{ê;q­AÛlº#/zœ{eXýc­¦EÜœZ®âc9(Šg cÜQ¦à™4$dÓ›²Ày{mHþòÌqÁ,½Š>ONÛ{õco 1dÀEÙ—¬ð¾m5ŒÛ(:¾õ´’]®ä Y&RiA×%‹…ëvzŒ+˜Qr9æ·@Þ Á©ðÁbÜŒƒÕ**¢”#²uQ–J-™¡ ë€ÒR{ð9@HÚ\œ¥d“ÄdÃx”÷ nŠ—ÖÈ< Ÿ‰ #§ºW%üŸR«gxÚÁ½¨€W‚rµ ´>º)H!²tш4ž—IääW¸­ìè‘AÀÍK:œÀFQZ¿™}T”¶ˆý%ö#ôµb¿R…ÄkÂr‡Ç¸”‚+’¡BX°z–’E¶%‚œŒÀh麤uø[=° É„+5î¥síwA¤âà{À6q­® ·0!±Ë&9÷ýˆm„QÃhô/ÐJÏEaUÚ \²4 W˜Š®Q ëþ«h{"2x ‰ù‡Ý{ [‹ªe)pÄEYõÓ®[ òŸd·>éÝiÙÜW¾aà¢ûn>]—vjI¥]º£Æ£“Ú ¡ˆŒE˜•\8G/”öébÆHâµ®8ÂË‘üªÊ™ .µ¹p¼K)…BŽÀÁ™sœK ØÔ1bgD\%\{ca†žñÔîsÊ[‰CçW;UAϲÁ-¸–ŒÍ0ú¤OnÄ £L!c‰FÌž:v”µ;€“ ¢ê•€‚&Cs#1b'n~(Þ¶–Ã(Ä,|øÛ!œÝïêÌ~¨­"V‰,ÙõõˆÛ²n™·Ÿ%ø¼nå§7^!Þ‹f·8›$Ø÷Œ ielQ ƒŽzž·¤v‘¢±vPœŒ²hq]ˆÃ“(e¦U`l•œâttLˆŽ)±IÛGà‹x¦³†7D‚Ž%ÈK¶è »Tàž¦•“—¯‹îR¥ÿI€¥LôÈÏ òëyd‡Å÷ê«ÞA;Àñî“OçÝd©fœ«ãF[,jý´ °Êjüò€mAäëÒÚ=Vr–¹¢ËÆIXßê]s®çâàœHmIXI\—"æÇsçÙªE‡‹${Ô§8ö Ô~=’ÚþølJÊóµ°DG⊃ÕB;ʹ¾úÌã>v¸Ó2÷ýßfØ!W~[˜Ý‘Iâ‘s®¸LCB}0ˆ¼™O$ߎ3µ°8ö¦ÜÔ»Êø ^åYƇÿ¥M­Ló;Í‹¯ZG‰š†j$W‚³þž4ÈÍ´xI•Ѿ;h¦MÆçcOæÚH¿é&вOm ¼úX^Ó”ÈïGJä¨è=10"L·fLÄG]ˆ¾Œ·bäTžÓ®žUŠS_W+¤uûfâ¼+ÓƒáXࢤ³î©]ÿÜ[B¶“ÉAHÍ1iè³¢z¹ø¦ø©‰²‚pœ[ m¹Y±õÆ9ˆx@Šw0±*‹ár»õ)X€°ˆ·œxµúHqÂy¸Ëý—˜UW¨;Øo §ÜH†^çù—k@39j„¯<ò ùÎ8ݤ(pÜ©’Í}–Ò`†¦,ˆ}!)‹ws¨Â9ƒpÒµ¾´Wp |P?…ÊÐ)éïš½~.” ˜É޳(íÜãÐa&âkmÇ‘m§E¼ûfí.0šuO´ 1 ®d ¤ Êí©«–Ó0(+µ>u$p 2–Ósî­· Jö!ž`aPá)Ä%$¼2úþä“î”bij¼ önŒë£ä$‡aË£1MϯwÃŒ|âùÎxWy[²#·bfh&.Á8†ƈqáN7`6B…„€œb.œ1®ßêœ@UùÂq%0ì& FWðÜ£”á2"6žáXÆÀƒDA‘ePf>5bÊsƒ‘—U˜ˆÎÝ×y©ã²™^¶z ,’FYæSõ çNZ_ý2ZRBúÈF@#âdœÍMDØk¨z LÒ£™´e‡¤|nJ¤q^A"AÚ&ôOÙáToIÒ¤ˆÎ»m­ÝÉ¥Ö×X3„ÐÑR•Ü–¥öÓR]YÁü˜CñGëä+4.óƒ”>a†¾ÅÙÃ²Ž®Pù¦ãÃuýZ5eÀãw6áA!°›¤aqIvZ 8eV?®ŠQè:¡ä¶ïða§ÉÖ\Ì#5N,ëU~#°®÷I4K%1!w{ÝÑn6  iTÏ~=ã2öã†âiÊyôÝÖã¸$uM`˜Lûq]ŸŠ¾¼“ÆíšÀ!xIj„¼ðdÑù°4^Q¢*ä1ê@Äfg¥GYs»Õë~Îõ!ñé¤@cYשŽ@¢¤)Óþn0ôvèm½H­|VûøúV1"Òä H¬Õ×Bâ/¯ݬ_€^Ÿ¬³ò¾(ˆ‰#1è OŠ÷>2C?F­ë¦|¶ÚîwËÞ–ßHM77DX;->6™ÛmL|·n6ÍŒ 0â€ÿ3ÖIQ(FðÆ\QPŸVð3V¥‚a›½óe:±P餉úL ?Ét+øi1Ï}S•–2œ†-Exa‡³K±8ÍâӼ绋§»¯—ÛËëÃÅÓ?/Ùâéñ?Ïß¾€?»;Ëß,^î.¿™}°w ÚZ”Î÷‰Î›D';6í§³Üw’šâÇÌ©äÁÜø¿9– T§:Kd¦­ÿ`ÞJĦ!}| g™„é½£¤¶Úe¿_ï*~™5õ.©ôÃâ`Zíwž ¥d¼d÷an;Ê_'ÍE©PXÒ‚ÃÒ‚ªÔýÌ¡JŸÛþš¿ÞäÞg¹­Ì}™{ËŒWÞ7°±DC¬ OÝcîæ¹MR5ààQ§tò½Üý—LÀÛ†æÂì}Ùp¿þ{w;½/ãy§ÄÆŸó”ÒÆèyÿìGÝéôîuñ¢Ó[ñ5aÉFk†o€î`'ÊõY9Pz¿ír¯÷ëÜû¢³òw¹÷»¾R„0‘€3?7M’p§ÑŠm>væ„·³13ê*wo3Á—¹í:ä^p5ø˜”(Ê¿“»[C_û¹·5õ҅˧ Ø{<53e‹×3^¶\,ºöïÄŽÄ\e]ð7s’ñ$s¬Y:>Ýà&Óø±á6~}•z“Œß¾ìY‡mËmùë2÷~U «Ää¾{äÕΰ¿ß6ï:·Yî¿Üõûþ6¸ÁA^öCþ*ü¹Œ[ùÇ/µüÕ{}êPRnêM‡õ…Eeܹ·5§øõ}îmÍimv©9Ý8¬é™¤R ¾¯š^†ñÍ›ÔûS#]Q¸S°ôêa<û¢¹‹šgåöŠì7mµ¼møXÃˇ†öxË›¢ƒ1‹ô p”ƒŠèRcÝys$å_,O©?È_oso‹.øuÜ™ÛÂK---ÀLävRÊ ?Ž1<æïÏXÌà¿z1ã2¼.‘´,ñ1”y½ØøÇ[!¦K«çeÊ ¹©¹eô“̹LsvB)ÁJF ….ôêÿ©r¹†8ÁŒ¬JŒVÏäbuýOÊS"f êg~Ê“ÂèB ¡».jÇÖ~Œ",mUIyøóÈÎ «:ðK )ñâl!%æ/º¯Ð·Ý$¡ïhmc•¬^Õåܵò®JÎçJ „w7£i_rú9ÍÃä¥`mŠ,þt¥_&Žî†,)ýðÓ¢z¨…lðù’3|®$]gI=14°¾ÇÏhÂu’mÛI@ÎóéMªK;‰ìTS’÷~ðMJÉñg|Óßó¯d<·å¯ÿ«T³ìÒ_Öƒkrà-±›<)ÿJP.7Ý9ôå™ù¢Ì4ãíÓºß,þ è"'endstream endobj 1855 0 obj 3749 endobj 1859 0 obj <> stream xœÝ\m· .Úoû+è—Ý +ÞFRó)~‹]Äc;M 0Î{¯ðùιÛKêýï%gF"¥Ñìî%g-ŒóÉÒŒDRä#’Cù§y#ä¼Á?Ãïõ»Ù½ªmæ'׳fþüœÌ~šÉî‘ùðkýn~ÿU÷˜œZÕšù«ãY?œ;5w² t¾›ý°X/WR´­•íâ|ÙÀãÖ*¹¸Y®¬ð>½8ìš¡±fqÔ?k y½\ië„oÚÅñreФù[ÔVÐÐÜt+ÚÅ-v™½¦['”qóñí‚PÎqÙk'ÃkÊ,Þ!5AÙVGr‘µë¥¶mZ×·l0fq@Ã'4Uõ¥ÏaҦƴq¹¹ê—6kdyÇ;ÇSé‚C62‘B"Ò“¼÷% „Qæ.ÐÞ Ó(¾@¿_AJ‹Þ SKhþøê¯3e”° ”çÕ!(̰~«ýâÍRz!CÚxXò„æ9IgÄÓR[+¤¯×ËUëœ0vñ”†7ƒlr9žÓ¤Ä{T$Ÿéã}M̬! '6{A8©Q˜³Õ£ž³²55aî ¬N·œ³.{ëQ q¬÷4­D[ìW‹—K)‚–áO2Õc«2ûa ùårÕ×4”èyšŒY ²h¡r Ì ¥Ç+à,p„Y=ZpÛPT&Á ÑZPq Âú¹†)‡œkàJ«Î>9M̾÷‘;ì´ÛWîzÁ[.€Û}]!¥¹‡ƒr+Ëi¨õûHºá«À߉š g32k|€1Ä&«£½6@H§+)…wÁõŠÁŽ6 ô*çEëm<‚‹o/e^æ™°S —lTÄ3Q.^AS¨`œç(tÆ V×´žÃ³í¥†-ÆÆ¯j®Óº:ÕM z€-Õ¶¨ÅLqOKµCË`GÛÐC¤¯'@̆¢t«sf·…¦ŽÝ–Ô»U•uïg*¯Dnñ iˆh8êˆ\ ; ƒÈÌ®°ÕßW ”™í.°ÙïªW*w2ØTÊ¢_*ëûÃDU'‹6¨Ž oªdTóCš«Ðfoá·c׺´ãºïÃz3Ò.µÝº\¬TVÍÈWæíVû#ž4 ÃQ%‡>d'ÔT•{/,€ €yKQPë `]]/ð€ŽˆØ2^â ^;ý4×}`ù¹W`o_náLÇ€ìþÓÙ½§Ï曫›£Ù½ïçrvï þuÿùøõôáü³GOçßN†iÓ4¾øŒÊÃDå‡H%°ûRß»®3‚lbßz_RÉOƘTxìe¬½O„^%âR_môrÌÚðŽ^§>j]¦Ñ«Ô'Rë4Žöª3=Ë`Ag3ÒEtðÜâÌaáÍCPÅåx Ú ‚Æøy¸Ð¿6SdQ˜Ç€'JÃaÞÛQç±14Æé-ÐL=зál–n7yŒ©›*Õ‘5„‚èÉëº+GÜâ"^.2€‚ÆXë†Mvf¾G€—q“!”ADšƒ$† Æ ÞYØR§RÐN›…¬öêå*€z P'˜± qF‡áxV žMßùŸ•°´D¶ÀûhLï(ž¤]<ê”ÊhË^?¡×Ù+4~_æ„°57 R×NGUíÁPÁ3Y|={õÙÑ9²:p爜«ˆº¹é@ÀÏëHŽ2¾—KÙд\Úûi9Æ3÷èùjyÀWqÛ.jôöô k$"rnx­*j«ƒìÝ‘“7òRb(··yÆ~K¤Øêº¯·É£âª` ËykôD•hø8¢H©²Q.FÉÃÒ™,’!˜Q fhvd¤"±Ö² /sû@fcSƆ]ò²È$ô±¯KŠz²3:I Q'C8Á]d¶›øt Æ¶,ó3IÛ&µ‘ŽBñ‰Y«I$æ9²,&ëZ˃*oZîýžU¦íÂBÜ…!*ôäéîåa¨·¦±'„&ì—½n‚Àƒú޳×IkV*8`‰§ÇÙ“˜–k,ìdÅí.A¬ÔÚŽ€<Ú8Ñ€@ǹï©…é×IiŒù;1·£¦ àv™gp2åmßp)=yïÌKô(óÚƒ‰s“é* 4À¡jêPõ{óÞ1ÎÝ#ñÝÑa3‘ÄÌGº=Fù™À÷œM° !íaŽ&K!b$ÊNºD¯Îó‹¥ñ\H5ÛŸ†Ep„Qr:o5ÐÕ'•z]HyivÔV"è–[/<ĵJÇê%n·jܘÜ…7U7£šÙ1?ªY ½^#yòè¼öþå¹»Êç…Ò›Øö©qÿ} œø tèì0&’γmx‹¡à¶ÏcσBqLvÜdI«MíýÜ Â€¥ÞR/Ù_ÛDZW5óÏü­>¥MJ)½É@åãÛAÉ÷CæWe6X™Î¿{­‡xÊËÛ°‡¶R˜´…k—¡+ÈÚ™‰ìPJ%ÞE"èsdGCÀ?m±½™¶Ó[<;•ŽÃïÈãÏU$©'’PJÚ ­Õ„[µ&F_–rçdЖ/9þõú^:b̉ZÌœ˜Ü/àaüm€ª¥ òë(7‰æBVJ ð2Ü›ü6ÐS^ùÞ6à‡‚ ØåŸÍ·~Èsíl®ú™Ï2 ‡5»)²êø(èò›šn+Cúvó¸šy¨ú˜J4°3ù§e¥ñ4ÉÎêhvrÂ=àY/FÈÚ÷s&Õš+°+‡‰NLãçÖáÏc:·3©5„®^û¨é>mº%8‡‘Î2‘ÙùdCã];‹]ë¡1Å•sŸŽ+/3–Ž"‰ì“Øu6K‹Ø8e¼Mæ 8sÅžÔ0ë/É\öÈ„Ãcà!ö³m*9æ÷©ï(µ NúÜùªÕ ¦V,뺩d]oŠÜ-Ž‚­µ`Ì肼NÃÓp©(Ø:H£¥ªäS?ª¼{RÉ‘'<*àZ¹)–ï7L¦Ù¿¢8zÓiø@§ÅY%î#ç޵q&›¤v]0™gÁ‰µ/x&;Ñ=u7iÕשE³Ñ´k>õ½f£ýFk½ø¬²çÅ4غŸFió‹Vžô¿š`(Iú»ÄÁU…—§…d°¼$U%n*B?»®Óè©ïYj}™FÿQôí»Ôõ"vÁ n©i¸„¾¿¥Çw£Ò6jñM}™F¤Ñ/˜þ¢<_T̼f&Ä moÉ4޾¨Øû9Óª…S½çr:*Ëø¤b%ød}»8û…•ܵ$îWÔ mÈ8ðvÓ"ö/©õ¦BÂæVÒ!¢’í!œdq’4N á²ôîmê{\°–‡+YË·qCr7zFO‹íJ®Q¿]CV4„0“ÊÏ·ÜÜsý!䕃^4–}Ñ­?[+ — ™oN`ë׉«ËŠ<«FªF{~S!{MüÕT‚¦Ù¾È±Ñë“P\3î«ßBq¡NŸ„x2":ªKo&7±ráÜqÊJª³®€Ä“VïìXî:¦a¢¢¤ G¬b‹Š¨J€ž;c ç1e+´Åä|rH@çŽíáW[!áyeÚÛ8Æ—GjnéßTf&ZzA5γiÈKZ÷.‚ é¶Î m5Å2%Ä@×óØ(eÜtŽÆ.sÈ…FI.?œJõNQT†ÙéP+š—[w¥tQ¦<Bغ‚¦£üºx9×­»Z®¦d€ÛñÎY>ù¯±\`íL&‡€4}XóÑRóFV½“2Æá7•—÷]8ÖÕ(†üs⎜œãÔwXH¡bkµx’:)êø{ê£Hùuý>õ=H­'i”œ™•wŸpNFŒÜ~Èbbø÷ž˜èý–- tn4 t=‹r÷ c{Ï¿…ÿ¹)f®õÈös>ý²øÆÞ'ögi¸d[Ó›H›“jåæä.|íˆÛæNmϲÔüŽ’ö\9öuJ¿.v?W,Z#sºq;ºâ÷žöç‰bжèØ'¥`†Jƒ½ßSŠ»1MÁYæGÓTs©¦ÉJÎ@fç±QJ§<Õö•ËËÔ·©ðF;N>Ýn8œWÞ[·'¡ôZöeöQêûg…¢rï£l_÷]xâ(K'7ÂÏ¿aùÆË΃éúflm­of¤•ÙÞ݆¹2bkTGÊ®ÚJp’ôP(|›ZRCµ¤/SUçc|TÁ³ŽuRÑç%Õw^aý§ &VzbýÌ󥨷¼4U™¾]J˜§•²¯Íßýxµ¡ÈñÃØKú"ú˜ ;_V«²øGøJÉ%°*!ä՚ד«xuó;X˜Ë?UnŠ&³`A†pÇ…žãÛ<¡énœ±¯¿gµv] õgYb^ô)A…-¿˜2*,&ÅÚÀ¦Ò¼Úâl;Q÷ù¿Ô[ë³r…ø~Ë+ÑFw‹Ê‡zèd¡l£„óa1]×Õ•Ê™;½gØ_ 5ûÓþ‘tú–÷ ±¤JeŠÂJªêwòX+Ö8Žõ…™‚×;ÈîL~oïä$ç'/¼…aÝk®1*[tegÔËž-¾„ÐxW^ç3ßWˆÊV4®ô‹OAΖÊBt%mvð AðÆÙ§àA¡ä<¤ŒãAáKBWúTIzuä Ö 7ð¾€ñùÒ©.ÔdwìI4jL·_„¨ :œ2€Cçä^ߣ¿<0B®(]úZWçªß +ŽÐ7Ú‰ñ³ü¾kÁ¶vnÏ ¤YÙpèJ‡vÔõ]Ž3ä;®öÖŸ­ß-@nt#Š[“ð_ÞòkbÉäôÿM±)U¥$õž÷7òBÓ2ìc<äWÈã[yÁ3Dt pþÿy%²÷ôÀ¢££÷?52/…¤K’`€nÁÍW˜êâ=äW¥94Íaø™×!ý·³ÿÚÈVendstream endobj 1860 0 obj 4005 endobj 1864 0 obj <> stream xœÝ[Y·ü8¿b€¼ôžVólz’uDkH>ÖkäÁ ŒõîÌj‘½¼‡œuÿž"›dÙ왑¼’‘@† ÙdU±ê«bõë¼kÙ¼sÂïÑùìñ>×ÝüäfÖÍÿOf¿Î˜Ÿ2?Gçó¯Ü´^Îk­R|~°ž °yÏç=ëÚNÎÎg?5r±d­é³M»Xv­½ «öªÅÒZÕ*+›ç®·ï:©xs?L–Ú4 áærÙb繛ˬoNK{[+š£Å’KÓ*Ó7ûdµ»´ÄÎ]-x+T§šø¨•šöƒ¯½,ØÜ¶Vs-“\Â4kæ¯g~jžV´’ñæx±T­±’Ž^h·îöz‚µ–Ђek¹Òèæ5ˆ9z™2-—¢¹vàP›Ö:é+˜j€b ôŠVÀdóg^M`¼þ9ÐÊzÙªNÒ ¸”[Þ§ÚFªÓÀ‹n™°ÆøqßÛ—øýÚ| ÕÜú½D׳HЉɯþ˜¢´žáG„ÖË™t}ßüÑhÄæç^¤N¬ãÔЪüª‡Q€v`[wº§T_#wi©£a)¼’©8N>Z-œúpÙ2[0‹ƒc0…AÀ†s§ó¼µ²º9pJÈAh*ˆÊ2¦’¬„ý„²Ò é½zp(ÛÏ@û;–¾eÀ79Œb®WŒ>ZQA˜ûÅ`ˆ‘ÑžŠñ¨Ï YÄžpî`Ê L˜˜r× KÂÇVÙ¹6ªÕfÀ­›…lQ®CÃ-òâ`öýì×¹€0si”n¹o5k¥qúÕÞìñÞ›ùíõÝjöøïs6{üÊýóÕwÏàgïùü/³{óï'quÆ´ý±qé€K ãÐu»™Ťr´ëÛÞæ<\E:Ïbã.ñp»NKF§˜‘泈RÎåÌF:¯rÊ3mìzGx9™èIXMW¬î£µR©øiŸÑ¶æ¿Y Þ2Ýñy¢ÿ¢uÆd /Êàœvq{³ ñ:«ä*¢½å\î2Ã}\cÚÇÑåJ’ø'à/ÃVç¼ÊWÝèz42•LÀ¯€ÑqP×èOr6\¬‹¸DÇ…÷¨ð½ èV¹È¿`ç!…ÎÍÄÁ@} v*½F²qU/° K)F–Z;¢T+çÇ«¬—â:2 0þqd»eA¡ʼn¹Ä Hq.d­*.^³=INƒ#H™®x©Q“˜l…Æ©+G€u9çeêR«ú àǽÃ#L7H(¨-§ÔÓS±qÖ,(ÑHÉü„ÜrÀ`3"š‚9i¡¿0‡ò;4{Æ]üQ\¼µò” ®agJÌjÑÿª©©;¡%Ô|¾d²¢`tÄDWñÁƒ¢åmÇÕ4R›_r¦øŽÏ©Ä‡³*>Só‰Sv ‚/ ¸_'ß–ÇH·E›(ñðK·Cßj«(;Ç5º²@” QÔå@,³lÚV9\êúÈé'´ÖɳmotÝ@«á+!0h½`f£ÖûUq‹Á¬H\$—2Í ¨Ÿîw0^ ¸k™ÖéÈÛ#êpVECzšñZACæ#¤åa%6æy÷Ò_*ñw˜«»¬—(I}ã\¡˜Õ0ÀèÜŠF2!FÊOª”"rݸÍtT˜;¤;+YOàÎÄZ­\‚HÏtløpÁé9 ­0‘ ¸üq&(­À‚ì,oÞ£Ùf@¿ É&8­që3¸Žƒl«pSÿ¾:Nä~¡ Г| ¿“mD×ñðB_®‰ý_¤x“¬Dy!Š(¸iá¶²=ƈŽÈ˜qD„íÌ&ús­ëþ¼§ëjïuP3ÖöIÍV%­ä.þµ°ê· \ü›ë0Ç{ع±T„Y\ì28è©l@m$Ç×òÞÆØëc¤IÜ’â‰jsÏ?„š–®pU€·‚[b¢ŸF¯S¼„¦A¢âh8 A*¸Ñt¡ñüöä|@!íoè)< „C`þÞ%}àbÕS›¬G.YT'¹ÕÖ8ÀÕ&eëòkÔ8bBcökmƒ°ò&;}Ë¡(Wà¿ú»³‚hðØ·¤q*ûÖ©ušF/R¨Ž†›±Q. qøGß‚›×©ïEjýœFߤ¾§©uFŸ¥¾Wa);îì† ôŸÆÂ7©ïÛÔz“FK¶\ëYulI®ªé([\Ï8ðv›(½O‹\ê7sžx»I÷‰‚ëÔw—ZGi€Eƒ)€"†Ýð~ÆOΊaÔËøøw¤*ò¨ŒEûÛK4—Z{i¯‹´Ã:õ]Þ8=Ö«4ü¤®)ûiõ»Ô:K­ÒBÓ{»ÖeE„ç©uHDûN+ß‚íê0ºW#ÅtÃåv®õ„ Ø ±·ý‡²ömê»*t Œ4 š qÝ£Ôù¨2±\ЖœçLÞÖÒ&cZïôAØ$!Øù&öý˜¾x»^MUÝrLàØ'½#ûyN ( o ‘’œ3Pï_H¸ßw*º·´S:+6 ©lÌœfó±^Ú¡/Êß{ʸÑ2áÒNØMÙ^¤¾÷…} ãnôeŠPKÀ#j ìž.ý> — ºÖË P¡)#Êe8áÌè(ñó.µÐ¢¯£ª‰ªÍb_Í¢jtâèï…æ¹Ö1¡ÓtÜEÕ<6kU2½\%€\Áò“¢…û}¤´è¾Œ®£Þìà „Ž »m€F7¶Û³1ß÷h·…jÜ*ñÏ©…'SÒäúDêã©…qÁmäã»4Œ¾¢4ô]¼Fìc§àD9&”0N«E¹WðñA0™lpŒ=ÈÕ—éÃ?C9*ày˜YWÁ¯ìŒH2áÓâ²Ð‰0‚"ƒVRh—u«ðË1£‰÷”ãoc+Nr|V³´ð™6¨H²üè„}l¶Ýþ‡=?•ù×OuðlE|ú>ãeŽñD1ºNÃáæyq*9’`ß÷Â4h=åW9×áøÊ§ý2ÂñUŠQb=žïõ°§êLÀt/Íiá#œ¥s<Š7\¡äÝwE¸S1*P×b³¤|7aC1iã;Ç›£ÈÏ1¿beÑ÷d™¹çCaÖaF¸bOx¹ä-ÜÅwªÎĹEª‚;ß5U±kN Ùöú¡31’×ʸ´p2•špz«BkÂ&«Z¥lÊd¾ËŽí qi'>Ó]µkámÐ5æªhÛcÌ/5°N?\ôûv‘:]`6©§ˆàt±„C’º÷e1kU$ª"ËlÖÅzOÌé»B|ŸŠÃã‚Q?$+z™Z¾eÉöÕBÀw &Z«Lfm$õþO÷¦,Qê]I“÷íG? rvThš.Ín{ÕãV3fxÔãßá|ࣸGÅÊÌEš¹^’nm“—ˆ¢ÆœÃLc•òyo,^o.1]Äãš|Gä%ý‘wD ®÷Ž(OºÌ'¬'JeQ`þu±¶pú* "éýDþ‹²†ìý¯/‹÷6”ÅýÆeí°$wú©)\ƒ¥Çͬx¿± íÀ­ña Ú“ÐàÉ•æË‰WCPÆ÷/7ôT¬P«Ý“¨ã¤¡lxÙU¼Þ‹ü‰ f7„þâ;”GÛNϹTàtùìËGûÌát´¶Ý öÁ‡›NìÄ3«b ù?Y/ ‰Ù> stream xœå[[o\·.š·ý 7»†—â‡ð“/J¼©/ki“4 CÑÅ ›e©…[ô_äwxÉ™ÃÃ]KŠm©( { Î!9óqf83¤ß9cþÄßÝãÑÆ–´|üöÈ¿‡¿oGïG¢ýdvÇ—á3§Çžy+­/FÝbìäØ Î8t~lMgœ9Î¥n&—SÁ¼ôœM9Œ4FŠÉþt&˜µÚèÞ·±Û;9˜Î4¦í<ŸÂ"ÊIÚwæW‚ëÉ.v"ýïËZée[j¦ŒoÆËç£åý_'ËéL1éò“wÓ™aMã½Ìaúsˆ$_îuÒ¦á—8|(m`,~«]!líÛó©òÌz]ˆ›Wˆòª ¯…¼–3©|føÃT1c¼Ö“ \ø<~9X",L>%œÓm’Š3#äd¯âäÏy£¢ Kd«` Æ;¦”œì@SKf´ïXµÜºÉa»¾âNñoÛ–ÂxK£™Y*a²X0ê§J\KG?ÝGdª½õo‘¯]”‹Ð„Ås^×¥!JXD¾÷PÚC”ö{)%X“‹ÛÕNðŽÂ=ö#Žÿ0 ê#eÃÀ £²\ôÀJüˆkŒ!üï ÔÇ /¹CÅš~@¸Þ \Yæq5ž7T5ê½×ø–¬Öß)¦Gñ$(×g –@†µê *¡ûÜü3nÂ`-æµ1.y“ž#å%úRk&;Wz1Õ¬QåǶ¥19Ë}û¹µ—©ØY%af ;›ÈÝ„°.0—ú.sk7S/`0€bLÞdòV&ã£bå@Ý*úBë S±ï¼2ö¤`Æ9°´‹ä¼ÿÄmUW´Ï„ì´w7ƒñ.·vŒ`Æ÷óª2ùcÑׇ¥8έ—™ºS¡¢Œ{É$Ë ¸=¯ðs[óL-õ#´NÈf§¾ÃÊ~VÆž×e™á¤m Ûð`kf¢b¹Jê«óÖZ±ö &ëÄÚ­P&j<)W4Æ6Îó‰¹À;»„ëp\Ï [tÚ9 Þ)f5±\þ±ÄuGO=®ÏúÄe˜nžOhtÔ]¼¡¥·‘Mè¬s +|À!xag®8z8‹Bä Òµú0¦Ð¤~n’ÓxàÜÛÞz2Ãd€9.’|@Lr ¿»ÆÙ½[ 4êLÖ¾>ëðžÆ2yÛÃ()ã)<¸FÜ´C .~°,‡ápWš9ýÇcžbËh¸VŸ tΨ¤ ŸÓêi~Zb¯å1Æt\KÙÆrÜAxnb(¥@»È »‘#iԳ׋zÒ´q˜) vB6dÚ$-êY%‚jANâ¶½D‘7Ç£~EÐÓÙ{âÎ2‹—w!ØÁcv`5ÚsOÍu§ê؃» ÃZiLoñ {Å–Y"z© œ¥3ôfJÚy†½§575Ä­Y3i´dÂôaÍc¬w«dˆPØ"4ŸVzÉ8¤:ÛÙM’/‰‹"&‹Ö:R¯6¤è:1c¸¨:Æ“R·»”  Ë,ÓÉ#ב²~ÅìïWqšq¡t4n5Oi«ÿ1…óFrÞsÛuOK>øm…,Ž¡`°ƒiS>Òai¨•Ö–=¶.¡< KzQpˆM0X© ®Èº,üˆm!C†€È¶Ú A‹³bò,Öbh¿"í!yQ²Ä6»È¢ÑmH²¹½½«®H‚4c" øÕ!lBuéñ|´11¾8¿Ümü<£gáŸÇ‹'ð3:þÓhs>~½ºæTD=1D3°‰í:­+jô—„gd‚+Û0ߨ.Ç,l¦!í„)ÚXÕy×éç3R"aÙ¿E*i­€>H*ÇFqÃøD@pδëäÊ:(¿å!kk*Íåä§ ›õ ¼&} Ñ6äç@mçj]€Ê:˜ÌtˆÄQ†%®°HË®@D8Õ)ŇÄÙ¸N†$óÖ©t”ckjÃã•Ñ Ò‡Ôx=°‹‰=ØÆ{Ã!$°w1³ÇLqQôõS*LÂNë9ìŠ|œfƒ—YŽ7¹uXÉÿQ &÷½!Ô0ë³JZzZLƒ,÷3CüÒ^31Ÿ ç ÉÆœW–E9pÜé½ÊدÊÔYÇóÑŽ©™ÕŽq©&™|¿Ëö5x›ÞGÍq®7cWàMÜõõ©ËD}’©‹Ôµ‘?fÚÓÔµHv+&ùóz-铈*á¤öd yXl F7¬° :¢Î? ‹‹R0«Å®Yjü«`ùÈY;.›Ìaêû€óÿ–úÅ<íÞ–§Í ¡&]ô?¯ó¼“S[+˜X½O7)‘e¥ÇÝÂÚîÇ-YâU™ú?±ÄOçØò|2mʘZ¸zûÕF¥hòÉ#ëçlj0Rß>žÂ2KÀ¿Tv©›¹–%ìÒä^EÑ7|LÈÝ£¡m|&Yžeò«ÌċܷYH¨/+T ÔÎAÚ@¤ú6)©Ê5 ëMj”+@ײЯgÄeù[f{Y‘t«‚êÃóL-µgéf†„ òk«x•Ìdz˜l ñz”ºž÷AE> ks8ç½Ø•ŽÉ6?º›Ydê«ó•zv'¬gYÑšE!_ n¯Õ©ŸÖR·×kMÉLo‡³ßÎVVrB5ªäƒÒpÕš[ûJ¥é•U–Á±ø,W¥ Ñ5{šˆ6öùÏ%Ü™·¯%3_U×]õIç™×»ô*VW¹„0-•.ªEKRS>¡Å’/ô6 Ú<ßÁ\ç­‘’øº¢}*5«RiÏ”ðþK_$*Ê?Í䯉J)Øü¶²¯TööÆOÚñWzÔ~©IUž”‡ë÷‘ø)0À2n{µê ‰6ÌYYTÕVL(sóµ”`Ü7´ö±˜*^´[áÔêj|ËŠqêóî¶ÀÀWùºàŠo±®üâG ð R÷~-3ùò\ §{Çbï>’ÔÕɰ$ŽPäï¬Z®'Œ•‰ÒƒÆ4Õu¸­òÕæX œ‹ ×väÒm­·—y[o‡±P®Ð ~žÖ“ɽ±ßwñ—Ót²k:™vï¨3$«­m«œßdDɧoq‚0 ”æ|¢KÄ®ã[µ†Ûú}YïÀL˜ÍiZ.®ÞâÕ/Ôªî&Ih,qLõjÇ_A½Ò3ÉBaÐÛÎuˆ­Ñqg¨V¾&h¯®…ÏM½Q{¡7ð|AÕØÉ?Ém…ìæQd¡±Tî0…LwÆÜBÆú;~@¯™ê/ ~·ÿÃ7ù]`Ú<*XlÚ‹º%^YõO;U_ˆ‡®þÒís¿üBô&ëšx޵öuzÎŒ$Ùqg¼ýÓ7¼è¶ÚQ{¬?H×§Ê ý^~æÓ¾²ê]@yëâíÑrâ}¢n‡7i¡\ªS¿J®>d©Ÿ«BŠöZ¼1_Ȉ"^ý…ªäŠéÏzU{¿‡·WÇ©z)cI3ú~–_¾»ì¿_Ä5–¶ðò¨¬Ñ÷«ˆ¸Æ²àÀ¹8I[ ŸÙƃšxÖeÒ‡D‚½˜•byçWøÄ’Λ‚“~á“:,.•Å”~Ú¶¹–Šœ>!3ÏÀÀa¯H¶µM˜dò¢œ•=HÔJ²{[`¬Ž~_3¶;¦tÈívefq÷”MÿÇŠ•lWÖÝ*„¸[® •O+—r÷K››„šUí¯wUÕçÖ/•uk×S5ê6JºÆ‡Ü½¾¸?ªZ/PÜÅ qÿ7¶¼ëÖÍ’¢þ£{z‚¡I®è÷p¸MÊŠwÝšãS畨]˜=ˆbß!^™¹äepzܾÂâ…õ£LÍŠX-ƒ§;HòÃ;@Ë„ðéñªÌI™Â¤ÌÒÿžÓ>¬|=ú/·¸ç&endstream endobj 1870 0 obj 2969 endobj 1874 0 obj <> stream xœÕ\[o·š7½ô/(Pœôlxç2~Šc;uáØ©¬m“"u5"KʱäÄ)ò7ú{;\.9CîìÑÅNàÀ´ yÈ™áÌ7ßp¹ùa[tr[ÄãßýW[Ÿì('¶_o‰í/à¿ã­¶ä0d{ü³ÿjûþ. ³Îl‡.8w¶D×Û4lÛ«m/E' ýÕÖ7‹_–¦ëµµfqox2½üÏîß¶”îzüöî“­Ý¿Y\–Qoó¨ÅEi;,O¥ÛŽ–+§ ¯KwšÄ[¬KÛUyÚ/½—ðcÙwÎéÅw¥{§tãON›•cï³FÖzá—¥í¼<åÞh©²úÿÍÊdÓØ>l¯bÿ˜ðeQõ¬h:ÜÐw>E‡gõðY_ Ìiä‹¿$Zd߉"F&QíÔjÂS˺)UG"ØòçšÍ?+3·üå› üŠÈEQˆ×ü©¬À× ùée3o’®TO›mˆ¢ì2BìÅhBtûb¹ NËNº…È›ˆ%s“¨bŸ¸M_4C¬Þ$-Ëd©É:/CØ6 j=• ³çKÙz£×‚ýBЋWË•V+T4„²¦s¢p—K+Y«âV•G2ö,=ö>f¥l§BD§•„rËʘlʯ^/ugm0f€ÛG-! ÊPvV"™•ÈraÉu¾×Mkžë(ª ¯¦ ¬Kãh -û¼€ÓýTo-|ÑÄŠ«ªhð,áÐRúÇ©ô`Bˆ"Ø/íéTÑZNvFÚŠz“F^²Â)¶üŒÚâØƒd®^Ä]Ja%:p$‘Â; kÁg¼É&’€÷W•ÞÑÚÞP½ÉªÙ¹ Ö>Dþ2ä8¼À (jÓ¬AñÝGO¨€¥5›KiÞÞÑ‘ ä&è\ç¸Â(—ðÙ½ƒ6 î…QŠ:*<šK›Îü_ ±ä`Ãb†·Jƒ vÊÓÃ(`Þ¯¦n8ÜÐÑS±ÖØJ,·ÉI3%¢•eè¼K¥Iì|é–¢µÞâH¢áz ?éU‹U‘e„~ ™®©Õ¿„%: ˆâ³ ši`Ùà°'à\VØÛDù!=£8ñæa¹w rbÛ8ÿMÁ->ÛV˜x‚ˆò@üöp)E§=0¿cêÁ¸%`8ÝIá’• |€!Òemc+BRü•±ôCà °Ùê£èµZЏIüS@:ùq¹¢w±ö™Eœá1ê ŽÐKGQ„ áÖ €"†4¤xŽï ½Ož³»\i«g5g©?M‰Yev†­¶ó-›Ìk<ѾӺr²ß9­HâF‡l^ã=ŠŒ=@ÐÄH†âW(À>kí+ºÝÙ½ k©(zÖc³›òi#IØ"N•Ɉs7øÖ ÎyOé.E×ÿqiÀ‘‘à"€ÁX[¸Œª¸ ˆ±°”€Î‹g°(> ér {½ÛÐÌÞ…ÉÄÇÝe/;¡|½#} y× kÇ´`ÂFŒ<™ü¾Á¸HŒ^ü9År4òóÀd’6ø,z —ù´ MÖµ ½‘úlÛ¤¢“¡¦B5ĵÓš`ê1jP%I&ű›¾Jr­¤M¬—bŒ;™ìD"¯`iN¨ZÅwÙÅ¢Âã×U¦bœUÑB‚Ý:@"*D7ï| ëi,ÿ¡øÞ×ÁÆëÎôš‚MäÙ¶wÄI.X'™¥Ö=€„œOsªøº n´Ÿ!}¬çM·mèOaÜ~J4å±´f­yQ€8£¢õ4{Çú¾‹X¾Oæ:åb÷`BÞܧ7*`dð ;É¿LeèNð4“â5¯‘xpY¯ãÏ×¾D®}2n±öT2ï8§è©ª„ªé´_1á²êDƒ47ók"´WÇ÷š=x "yþc ‚@«a?ß.8zV!‘Ž™ÍWåöQl q‰˜©‹ÉW$´a€f&‚§ôöŠJ–=ù2u‘}‘Æ Ö£öÑFdY‰5lƒ0UXUbZ÷Qàã´€÷‚ãˆÍFë8½ï ¬ÿ¿¤ ”UÐíöX[!_n»S²¢† ±²A’dw‡·©ÍNSô9˜#G‰íŸQ©š>Ao' ŒŒúAQ\—çc£3›ÈGŽò™Ñch%Aÿí5TÒIÍâ3b¢ƒI BµhpmýY™¶vÆ~TêfÒŒ¿ŠÕŽ ýLá´O§mÒY+ùa1Dªa‡½)±|Æ–¬zIˆcº%L~¬†|oîX¼\;àÍP—k¬«šù¯X™B¦¼\·LyO©â¦ÅNÛ±ØÙÃú€¥è”ÄÕ±ŠÅ@ºåaZ,áì ¤ð‡iìÐæ„Í€ wv02@s…oÍò„áBÍæÕ¡œ¬êJi°¯7±æâOꮫ÷qSȦžcê%HAö"×À&¢2è$)è¶afͧ‚Á½ú0ì¶Ž'DJu@D¤ |¨A„‹ö;Žu#Ð:— ½q EçMÐ1zC}þE º:Ó -¯àÊV^UA ¹«iü]Í( ¨é¤–S‚8Œ­à*éÞ@OŠØ «)pÊlŽ G$h¤æà¡áÂÇaÚœ„áRÑzÒÛÎÎ×q«E^°§Ý„‰gmUs,=L e>M‡Ü­ ¸àhÚõ ʽ˜Y] 5@É”ŠÌÈ‘-i(ÆØº7ÎäL`bñ}LX^X9O´£‹‰@‘ã„Å#²­$ÆÆÂÒÀ‹*,³ˆ< #Ðò}9ën¬†z4\{?¾e¶°†„Â[ž\f¦CˆøäÏìšž ’:•‘Œý¦hþ­ÚÕdUô‡ÍǦ£›Åz5¾;}}`1°|«æYþèìäËÈ«¶BRÏ>ŸðG]³I ™5Lsú0à˜Ã†3NW èõøò¬GÏá~^(ÝnFV½Réª lù×$žŸ7G3$Äš£>. ¨¦¸J.)úPÎßÚS3ÈÆÔ‡féu—|7 ¶‡ïz2hÁˆä<²˜æØlæü´ñº+)(,ÕU VJ't_!ªc)’j ¸ÉÖã«fWÕ$ê§/.@ ì×99 E }bݸAz?¬®=Éï|µŸN[ΤÆRƒ=MÎýÖß,42[¾îñi• '…Ëq%‰P¼T‚¼—CDZ˜¨r}B–Á_-\é퇗`rÎTÄKNÇ=ìå]ëÊ©éÛœù‚‹/iÔ¶rñl#]Ni¿˜»˜ŽWð°íh¼îø9@¼ý£ ¹ßsûˆÌMíǹ©ôÑësx‡gãG¶)9P…ïŠí¥¦ZÆž¹¿t¹ùž4wÑ—SzÝ,<¹1†_ ÜFb]ÚóÛK¼ÏÚÞõš»Wv2/]+I}a®•$öVV”=lÓð }1ÄÝ~ÍÈÙÞêãoCþŠÆCñðÚf{¸¾«{N¥Ýâ“ìÒdô ÝØvÕüvˆŠ¡VáÕt”~?7N§8ÈMåš^Ì0u; ¹äóÜ‹×7Ÿæ¦ÝüðpCîæýÜôu~xÔšþ B8 \áÏl‹:–¯ýŽE ©;H@ÜÍst'¼ƒŽ®³näš»îY®™¾_û¥ý ÂØr¹öQ~h?<ñsæ~÷¯dˆF{¤{j nsqáY”ëÅx)•Þ*Æ¹Š žLWÒ°‰Ðiã¼ÆéO˜Â{ä¿¢Õ8PÞüíΫ¦áZí'ÞuR;N¾xMóðÅÊx:Rø>0CT&N­ÌÜè–1å§—Ì2‡…O¡*x!/IãÕè‡{¿cz°‘láêçdfH0NtÒs—©KS¾UÍ Ü‡i îã¶'Œ%ð·øáØ?²ÖcFv¡ƒjp“q5Žú°íòui{Úh{ÛÕâÓƒf ¢0AÎå¦]D¹xM×x»Ñvæ÷æXïÅ€æý°ÿ92¾Šæ¾ùªùå–íúдƒ¶{:o»É'"9ç~˜Vkù5úT]/¡/¡ÒRp60–v>tVrFRœ‘®ù,èð׼j{qÉr'kýe~@O-ìæ1zÙ¿§f}e«êMü? Üîó¤©0~»NÆûÞéLG•³#ÇD>7Æéînýþý‘â…endstream endobj 1875 0 obj 3533 endobj 1879 0 obj <> stream xœÝ[YoT9M¿ÕKÿ…’FU!Êñ¾4O]#šf)­éJgEÊ$aÑhþ{ß{ís®¯«’J#b|¼œÝÇß5ïÆœ‰1ºß;Ç£gÒòñÁÙˆÂÏÁèÝH4CÆÝ¯ãñ憫Ç+á÷bÄ™7í°q°ÐÍåØ Î8Gÿžücª™WÆèÉnÓ‚i“½¦¥½˜ìçÖ›L=É}{Ó™žÙ0¹—û~Íãç¾Enm­¤¾ÎÔÍÜ÷"·dêëÜ÷,·îæÖËéÌhk&¼éqnò)“dêâýÐþ³ø×HÈñâÑhqë{×Ê‹Š~æËµ¢Wk%:ž¤%:wònlaʶžô#ìÀ|àF§Y‚ΊM.,Ì\ìÂè_§3: V™ÉÛf¦AMΧÆ#£nsóœ`s1õ‚qéüä3v’µÀ‚Y« ùÓt&eܘɓ©`A ®ó©ƒmÔÔ¶¶` ± ~&ÿŒMǼU“çyNËŸ–0ôýt¦Ĥš\´{z7Ùi·´Êw#w‚л9ÂÜ¥¡­æL_sB)&“ÞžLgð¯¾ÙñoEþsç6ç¸ÙIæ`Ù:MU{ÍÚmgÂ0í¹hw_´«kÐùá@ÑFØ:ÿ¾`>N§Êo:Á9ó‘>ÏÚ%߯¹D•{­˜V!o|6U̘ 5u°ã;Y:” ÀY ¶Tœ!!K”ʈ.ð÷ì6¨B>‹óSJN¶Ñ`¨Ô–¹Ð@W!Ì0Bú¶læ+Íœy*;À)uA© ÎÆ]¥Ñ,&2*Z¯J­¦Õ¤å¶' aŸxøö"ÿ lÌ5‹L=;ˆZTª“2°âZGµÀÚÅ H`E KÃd/‰-¢ïDm+‹. \OIÊéN±a=¸¨„ÉpŠ**ù„{;µŠ0û¾Í£#z);E*pžA¢kæŸ`ó6ì*BcR²É5Õ½¢l[‹ÑÓÑ»±j+äÇ:@Îæ~lÁ…!²ci±9mÌŸ¿¿Øm¼‹ÑÆÏñ¯Í'÷à×üþøo£­ùøéÒ‚£½t<Ι[@Ùí ñCÖí6ò~€EséÀ¸>jç¢”Ø é‰CE1g:Ê¢!Y Ø,%«m åjÚÓï (Ü:v¡aöŠ¡M.ÁV´‰ ¹r×(7• Dqlív±¬ u’áÆ3/Ýåa›Îˆ:É‚6ÆÑXŒlC¦ôý&ž·Û%#¨~È[ Œc)iXk§‰Uªá·ÕX%îLd%)ìsR†^Í9›ý1…LòÞѼ?…òÑwö»°÷Q)ì÷hKí=QZ:×.«¬mÌ6­³oäòV*Ñš3yh[h¾Í£vr!÷ž”’©Å2õ°+/­ê&GòûL>Í}*Uênei°œUþ¡Ha{”§lç¾2%Q¢•¢ÔI¬'Y¬{y(Ö¢[•Úke¬äŸg*ÎxT©šŸ3R9ßWõú<ýR©¨e*Vèó û9î_6Ögì~q±À C¤Þ­(ëÝúz›b߫ʦ[yïW¨™õ±ÐÝÊ®8÷犚ž]ÊÓ Û]­q·ÂÎëÊÊW®ü¸²òo7ªÞõ>\9w«ÂñouõÞÊìlP甪Çôyõ9/y³Xýžžnâg¹ï¼’f/r “ðy—¥&–yRIW¥úÁßÂΑÔzÚuõµñß$gÒÃeéñxÚɳ+‰ù},©T@¡S*ª&Ä›~íÀ¸³Âc>LÇñoˆÊ+Û¢ñ$:.è/sTaÏ©×IhÖO©ëmj )ïT•ûËq>”c;uõë¸à’TÅâ}vB—W¹OVæ&—·’ø*¬”¾_Y”ÒãÒ:#f ÎQj”e…s]f™ ã Ê»~ásóÃFâûôÁÕV{Ù) ú.й¹Ûa¡ãÞ9ÂüÎ@S¸Â.úP»¹‰µx»VBZžеHòl¡44×fêz‘†Žü ¶¶ÊlÙ… ômPËÍiìP¸5«Ð¥Òþy];P晊:*sé ­‚,Õ÷Y>ÈW¯#„OãGÀÀ„­?p)ÂKWcLS›æ>¶Ól€„Á½»áê&QÍaˆN·ðªzTCµ>NÓ¥vG¤ˆ!–9JCî´1¡5´áñF0P&D…¸q£ªÏ´òFxt‡¾AC ä(Ä1Ó%€o¼;q¼´» ïÖðÐ+À¥Mr.—Ö6w`„%NÛK¿smD8ν)"`©·4Í´ª³×†[)²)ÁÎڔȦՌkqÓÈf•]†àV¸9Ž il6 X›ˆµß~ü—í¯ß^ós’ 'íNžà{«lшRd§¨ ©(ƒ5ªçb‡=½´î`(€:€™à°ËpZ$u4½ÍºŽk¹mÁ§0ù}‚iaJ⨄ÉÛ=i¦„”k{ÕXú”’à:mi€‘X¯¢˜; ÞG;IÖ94½£gqÀ¸”1x®«a£{åéÑ,EÓê|ôÚÓj0b–¬ß¸êïS´Òú8žBïf>cý„xÖi/‹Ê«‡¬} ~^)•à`ÒÍÇ UûÊ›»Dq£ ÷½oSÖ QƒãÁÌ])¼¤Âßðçþ›–ûpD_»µ¾3%¾J š(áÛ©%¾»¾Ù}áóäýýÿ¸²ò¢2n ovpórœU_}¤4ißCHÔnˆkúÄà з˜òp•»™Z~ ‰­gT Â[‡ã•žý|7BýðKÔW`{(|˜¨JíkR˘3>ðBˆ !É™ŠÃ2ªtž»2ö4OMqîkÓûר¯IÔn²pߌ¾í¥Æ*”û¢Ø¨ïƨDŸ©¯ B ´"‘Ñá=¢ŠÔÚ&öJˆ«œôy/írU®E¦Ú"”ÿ.­\õñ4¥§¶uvU™Z"¯Å®×A^—›òîxP N4ÂE%`JFS"8¾ÄåÖ¶Û%Þ†žõ¡")FÖD]ׂ—úMz4p«² ~÷8«s²ôSÆ_R NA»W¸¿ £º±ó!Q Ù ­÷¿}Ì-<ÝÊ|Ö÷ïòãa?gžÖÙ\ùHW1/µÿW·Ô0«>Œ~•07K;8aíÒ'·©—<(LXæíôbXõÐd\”ðßs,½dAôž¶v`^÷Ÿþ50ðª7ˆ dß Í‚ë¹TEGïà’*èMé~å³àÁÿ¨çÖ EG¹¤ëAÑûØ$w7ÏrC ÿ%/ƒà!¾Ö^3û%‹æûî^W1t¢¦1ÀÙ'úô>aKˆ] Ÿuæ Jè^¢ÁMó$ZÙ/«Á!Èõ8}…®~À„Óʼ¯“; ;6&/,ZÍ‚äŒ$ߌJßk1†Oõ0ȯ”ª‹‚ó‘<,ú9+}p½ìr^ ôÞ÷¼±«ˆe™„r-rMæ=îáéçÐÆžŽþ¡›žWendstream endobj 1880 0 obj 2725 endobj 1884 0 obj <> stream xœÝ\ëo·ÚoúÒA@âø˜%¹|5m'±ânåÆê Ma(:IV-KŽiŒ¢ÿ{g¸KÎË;ßÙçÚ.A4_;oÎü–ëv;!w;üÿ¿Øùô[e»Ý³›n÷+ø=ÛùaGÆ)»ãŸã»ŸÂ4cûÝ ‚Uð÷ðt§Þ Óvƒ…îNí:Ù‰_ìü}ö˽^xmL?[Ä,›ÄVïåì4·Îóèeî;Ù›[é… ³ýÜ÷(Ï;È}É­§yôAî{’[‡yô~îû¼±ó×µskØÙ¹Ù—@ž3˜›u©ï§ ’ë`ìŠq%7¯hÂ%5÷¼r} u²½ Ia­†æ¯!çqVt§ßg~²'Eвë!\P¯€É"ôÆ8H2!W²òÇÙ¯° [Ç@œ– äö* õÏ{õ“kŠ‚Ò€ùg†©ºsrœà½K‹¤©¨MSIšR’RáT$𣅠X‚ÜìiaŒW*IÉGÆFNÏ £8#4‘Ñw²§”èeŒ“ ú›êTÍ¥Á?w8×ƒŽžMc¤mó¦â7¸ }Ïm@Rsà¯6™‹w|&³¬‘?k@ oògÆ(:ÒEİ}kˆÏ=n=‚O U Ý)°6¾‰ƒQVVûÙϲÙ]¶†opu@×å3>UKpk“\+ŽÓV§d‹W-}Í ´ô<òS'w-4 <º“Zú-èuÞU^®e•ƒ¿º®óVÖþ:öÊ4Ù³}_’¯Abš ®$œ×TdjoñJH’ŒÕ<> R‚°ŒG|ñCŽ"’Tž„»|ÓkTn™\_åtµå•tzŸpOŠ;]à‚,YXŒîÉôâ$”ñ°“ž‹¾äx ÓNtY.ÁÄL|½J– gË^ ¤cÀbz%r?m&Ÿ×{Ò¹’G´i…\rbV‡HB‡âð,•i–ùÏɘHH~¼ÓÁÄhZÔ‡FuQ¡`ºXÅP°Êg3 *,O8%Ë~5f?*,i#@1A³móAß3Og>0È_…À=æ8ç“Pß8ÚÑ‚sþ{ÛYQJÕdqØf¹yþàÉßoÜRvÐöù;š›äáÓ 95&(ƒ œÄvtX•Ù52‘Ô¼—ßîbP}NÈÝØNí·>íÃ7åsf"Ę&,ñý‰qT/C“0Qe'GGâqÄ·ëò¥ÐК7®xòL^ç­Z¨¯|P€8+´äºÌ\U£Î±[¶Ô›^j xKÀpµ O}5zUâàñV ìol|X[Ô‡Uo„µÍ{¯âœÖe®|s«6,èÊ«Î+w­&ÓzïqB÷¼òè)=ó‹ÔW߆®ÃÔ¨ï¯ñ1Rd¾6ý§Ôد]…GÃÁ¢:Uß sn=’ÞòÜ5|ˆŒäª1Z[i`d~Ÿ¥Ñ×áŽ2T(Ÿ?&Ü‘ŠœëFrÛ|*Kç®x  t×Ï2vX¦zT¤?Óê˜Î%õA“PÅPæõÕ[ ¶qÊñØøËVaJÕd3;ŽyF§ðóܹ«èŠX%žPou›ÉÉ Gõ±C0É×›ë*DMaä2¨Äe&­¾Óä!©éô;Ã/âAÿÖ·šÚ÷ƒÞ4[IëË !öùz4¥ÂÏi¨•Åg0û\áýY“ü;Ñ÷=$ÅZMº‚C¦ž?Ö º3Bû~+X‘þÀªû—ã&üw2VŽ·‹‘¢X‰×˜`|ƒäžñé¤QÙ ]Ð yÑ[GÐÞð~Õz€£†3v8CãWF(g4¬ŠÐµßb„ÖžmrÃ(Á†¦Ö…;OÚgùzL<§r£|ñÆN¾›eóJ¡°<ÎA°9Öÿw½·íìhæ½I=Qì ÌA|Í/¸~÷ûÎ~‹M)±¢g½'Í…†ïöÈŸpD税NõìZ/*˜ÅãVˆ wž_QcEh5¦Ãñ9AQmÔƒE³ªnÃVñʇo¥;at²(Õè–9ü˜§_—Øà8•,é4½ QÓGÕï<š9>,úñò$\¬ np²xò¤)$ö…ÅDo[ºFØ ŒÛ³©gKÐÓ Ëe)¾HÝâ%AJ×7 GúðõËF³©ï—­üÝwþ²>~éèàÀê75¤~+†túN+Á²oó*«¹u“Šf㬀_zÃÛ0¯ÌÖˆý.ÃÊÒ^‡ýÌé >nD:”[ÿÆÈóñ]û†&c6? ²}ìšÏ…¬äúã{Øužºæ´ë9Ÿ6ö]mú¤d‰?‘ØÐú®ã攉;Îv•?MÍŸòN-m±ôˆ--=¦De?$s£ì‚ŒìQ”–!ljFvs3ʈ8!ô/HÐ9±”#/½˜.ý‘/Åiá#I>x–ÇÜù õàÞBõ­ìR­—!Oh^Zš_œe…ŽŽëmý2%Mêýô Aø•…*Á‚X;©\zj*ÌBêÄíîü~þ iùXÐendstream endobj 1885 0 obj 3491 endobj 1889 0 obj <> stream xœíko·h¿éKÿŠ» G/_K²n Ä‘üŠ-;öµIÐ…¬—ëeKr-ýïÙ]Îp¹¼“Ý9r†ˆ>†óÞÞ»Q%ä¨ÂÝßíõ;/T]öOתÑø¿¿önM6SFÝŸíÃѽL³µjg{k•ð¶6 5€+5r² ×þ9þãį­5ãfËÆ»ÍÈx9Þ£ÑÂlw2­¥u?"Øsš÷o‚=¤Ñ:a_Œç=#ìs‚Íhô5ay¿ ‹£oš‘sÝÆ0xJ¸¯"èåd„6µÓ0Z;+´Uã*¢?Ò eæŽsÿš=^SZxÜhödmöŲØZºüóãv`9ƒûU‘]Sk,h‰¾Úõe‚›J¥¼¨äøNÄ~´WF¯:âÆg=o±¶ò,‰m¾íî ÿGÄnö ‚Îã òÉéèNœŽ"‘êvKãeA¿½¦4Ôr¤ñ’y±ï–,Û+‡û{’9 Ä> ø >XØ«‰F_U4÷#ì€VlEÐ~œ{O‡²:cI¾‰Ø£KeßI÷áp?:~gˆ{Wærný ”ÂûJÞnË{–ð!Žf„å`Æó6S-ЕƒÀ\_M Ìr,ôYÄž$Rï@$ócÂ¥z£äãiMùÌ7é´v|õ“dОµúðq‚  ½ÚÕpÌv ¿øX8ŒˆÛ¦]†þ$S½Ò^Eë²êMãÑSôü;KKn–­}ߌ5móš~ß.G«¾ë ¶§9$ÖªÿtPê³sò‹Mþël¿Rn wÍRKÄ= ¯8£|É󧵚+¦–{\“ZšåzÓGÖ>-°‡™—'ðÌä~¢ÏläT~=aè‚ø)̨f,TñGC'©Ä8ÉýÏŽs$~6„d>í?' ]E<\Ùì~(˜ÝB ªÛ+Ar‚„<¹º—ü±:á=Jæ- 'zå’¢ië¼4~-'fôž#Ñânw£?Ì$J•èíæ˜gÐôy›ã¤6‘ AÔ.æ1Ù90xÆ Ñó«`t'€m$L¤t¡û¸Ðæä1íÉKNcV§wù‡,báCÖxkÑú h~ÓÀâæ­ÞiጌŠ7ïœk`KÃÃWSÖúô0Ïñ›ç‘¥/eî7Ùù (³Kê‡qZÌñT1Ç#•+*:sˇIšpFœ¾ ›œ$¼Œ£²"§O vFóÞìœFÛ„=‹ ¾)¦Ø;‰Ýô™Þ'ð¬ÏV½Ž úœK Ì޶ÿ<ˆü±Þ²OdêYOò˜þ͹pYÖÆ›×ª#µÏ^¾/W‹Þ˜­ÅÑ]php=¡ëÅå&ŸxDŸÅ;Tþ!ÞGPèX °×Ã-÷vrI¹´Ÿ©^ŸÁ\ðR‹Ìî÷„Ðw1c©àûÝ.þŒ]œÁQíb—n3ÃâÒâ=¸²ù¾/ç3¢í±èaœ¨ªA)b4®½EhV@>x7å2üÅÕE._³Ð»P¯Éí]ÞâÃõ¨Èj¥½¯‚¬ä„8*ŸFFÚr \±ì ²cE{[XœK»ïnÆtƒ»ŽjU”õ«¡Û!yž.¶¨k ¨§&y-p?c'i Øéî^VxútÎk/»3¢™|ÓÄèB§ƒHö?ð|¡Z‡$1)ENoNÂ",µý¸”Û]Ø^VißXvMcïFFIQù¶_ü VøPµaWÉt+IÕßg“i™H¨Á­Ÿ4+}€ølRÁÛ>Ÿ¥©±…ß±ù¸u¡$Kx]Ü¢Ö>»n„®·"ñý™ÌehQÂÓîè©„Y¦ê”xÖR`@L¯²†–/áÛ÷ý[˜VÔQÃ[ t=Q¬­¢„Z¼†‘B¡ÃèÎNåM[t’ ÎGlIK&ð* Wk¸£²˜¿eLAYüŽ´èˆÔ!AƒÖÆÂ‡˜M5çu:U[„«ÎŒø”¨lPËä„@?è`º×ÑÀ5¡Ôr]Žì*PõRåâìÏÅ}ÛjB…" òŽ(ˆ¤†ÓñlðUÉ… ÃTÀ÷ôB(¡bŸ¬šëôûƒöþ%úw)\PQeð¬#„áêô¨rÔa{ß*º†¹bTˆ;PäÇlG{,½d2Þc0d=K´" Y ‚ñ•ŽnºŸ 8/|´€¿à©Ò@ ,ºUÇ3»]­uÅ]•°2rþûûŽÿŠC) )t·p“0üㄎëdÎ5C Ëà'Ä&U±LuÓ£.DïÄ]wšä+Ÿ9ŸV“Rº73=ÚRâC[s®êy7 ýeêr˜”Ä„Ëê—ø¡ƒlBëqzÞ ò@LäP-Ó(Ñ÷©Í o¿Ç€·1éÔ}žÚóX¾ð^]îàMùFu}…]'´ÂϪ¶Z©]Ô—óÒñÌ ÆC¸,ŒÙC±(}’$ Þ#WpyRp‘q¯¨l¯HÙÎS·ÖhˆIöì¹Bb`±ùˆzo´VvÙëOŒZ-óõg^YÅyó_fök¶½§oNéhëUF—×x» ™›Á]‹£®!”5u¯WÑ/¼ Ùü mÆÜU)±rÏVoBñƒÅú3`/¯%­0 Ù·ƒà‹ ¶™f,ýáÂMhçÇË›„]gÚë[ª#ßgõľ`²Ý­ÓæóÂ>a‚ýç¡#³„ö¾ëæyˆ}™­èÚ6»Ë¢‘(ãì8ÜR-Û̈Gl³°ð CÈßYuÕ¿ÛÜ~¼Gè‹lC&¦ÿÐŒÊÿgЕZŒiÏ{…•äW„¾HÐC.§•ä…íÒV&šz/Tîï¿êŠê¥*?­ÈÙž6NVùiÚÇáÔùáâ9õŽæ¶f ?3ýÕô'ó™–®¦Ù ¾ä^ÑâG2—wšñKlèç Å´£}N³w›Ã‘.ÜoÔ›uPõé^ægêÓz{ŽS¹ö#‘Í5ÿz€^Ý]W‘2uV¡OFÙ-ÑMdSÍËÚ\wð‹„zÐ%qÏËÝmŸÆëO)³B.äÊÞ¹²÷ƒ3||¡M†DŸöh"ç&ìv ‡ ÚWÊaX/©=½DÛËÎ ¿Ó‹¡gØû¼×Â_ÇM# 7xǶҗ ƒÉõ<[Û¥l¨ !ƒÌ÷`¸Eï·mÖ·µ+ðÃÌÂG%] pù‡€È:îg Ð÷hX5|)™9®cÚûN ¼â¸G».Îë× RÉ¿X®õNÏÇ ï¯ô¡ÆcªÉ›†'\r¿M5¬ù ‡OôN£9Ÿi4eÿ†æFÒL¸ì•Fͽ·«<ÑhÚM=%x¡\ãB‹ïjÒÌ€|í…©ø…KÒZMڼǓZH‹‡}ÀQ­{·ôF2Ë™ÖØ6®Ð’›÷=¡=ê31œ¢(ñ±ˆ=Ô¦qœ­aߦ° zO7šVº© ‚¡o*d¿´UÜÌko…íïtWÐqë}Ò@íõÎ#🞾‘>q™gOHÇríiŽšû5R'CXž>$ˇ®Ú.%s#k‹¿{4e—Cgiø%Ö¬M*l7ަÐM»©"ž–N•ò|c¶ö-üû?§Õ‡endstream endobj 1890 0 obj 3049 endobj 1894 0 obj <> stream xœå‡#w^ãGLÕ‚¤ìP þýq¬¿k޽Z Ó™aXÎc*Òz`¤> <âú~°t‚C:õ†eœÃö` žÓ€cÀ—8æÛÙN¨ÁZvœ&‡¯FÚ¬à Êøa$ѱÛiÅšFØ6‘ŒëÅ™›~>CŽd‚rRIÒàš'P¾Âû´odJãµæô©x>ì°Æóð¡lÍ:âÕwFÈÅQ !‹_ài‰ÐŒJ×a¾ë”’œ½NùP©eg´Ÿø ös®GQ¸l å&üôR‰Èª =k‰ ¬/¥ìœ˜ß hálX5HRÌ·ZI(ýrÉ¡Žó­¬ä;²ÿð¥¡w!ðË/ þPYëÕ20OÔ‘¨‰ÖßfûK3DýùŠHcÇK@š–ÐÿÃR ðÎs¬Ÿ—¼ç·ÉÂ0x”ˆ!'Âß|À› ˜Ô:® ³¦u]MbëMcÝ.î”ðbÑ+èlûAÛ ³ÙÉA—œ—2ÉtwüI0l¯¤Ý+!G„_¢µ½¯ùƒÜË„Æ rmñ Œ"àJshÙºßÍèz‘/~ÚEêÈÞvú%™[û—:€1%j$44›ðCg…à Ș9| ¦°¯iÒyËUŒ0c@¨BË%”±u& (ìl@°aƒ ásCÂÁfö¶wÀ«þ½O˜y£ˆúN' ôš±Šó<-².€y QeÊúðüz¹”~‡ìâǶyeÃÆk†®ç~ߦ¦/­,èA/¾HmŸÁ½îô ߤ¶ÙÕ²¾³Ô„H eAB¼× @§6BÎyjºI?Ž'(‘g&pž¦¶¸Ä˱×ô­V²‚‹þ^\×ÈÅ_©ÁýMü!¢yË¡ ôWƒìToH/—ÃþºœØÓʉИP…?-‘{Ÿ(7€9bLÿÝìšL³ŸsA6õ¬î{äZ~’,‚+¿Hm_SÛqÅðGÈJ‘#‚àq0޼ÔË'Jø³0ëZàÁ7D–JÃr-#‚Y†`‹ažÕLQl™­_l™Í gÒ®ë?^Ò—¢1CHÍ$‚rðŸÈ/¿!v©õè‡]U§ŸÃR¹1ˆ™òsúi‚Má¿7xã<õ*l“¹oIC¶L40‰ï{h2ÉAj»-æ22٤㺦Ԇ(U± bÉ@ÎÊ%¡xd´^MŽD¶üÕ½Ùä-%ãü@»MÐE5—µ3œVÁ*gHit|~‡€Þ qHòK\ä½¥Ÿz¹£5!kòðnþòír ô[lBóm.ã´D©#À÷n²Ú×$ûq¢”õ´Ê%ÍØÔ3Pÿ0æ\×ÀáY®ë%®Ò¦Ä‡Ú é”Ö?ËOJŠ:SŒg¢f²ºSÎVš)cŸLnsé:¯&\âžoš&+isT:»D,)v/xÙ`*n!“ÚoyÎ4ãU±à›,Sô¦áŽ÷Á_}]“¸–è’tQŒ0MÞC½„š^Ö} ì´ê¯§Å¼çª)§×>>B}0Ú–< ³Ê‘÷<¿GÞ« t­ßØJP–‘½;Õ™StnÃZÎ8ÐÊø¾SŠíwZq è€ýÈ‚çaXÜ\8Õ)kÞÇÒÅŒäûL˜)'ç –¶Ð[zIyïO5Sq®×! ¢L“ëŸï†«ÆÍ  +3»†ž×}?å’ ’dð¯ZàT"}UísKh¦{jïCäÀ“ Š×#Ï;ÛI…WÉšÕÉð£U‹ÞÛ6¾J«~ ï úyƒ^7T*°ˆ áÉ™ã:ÇÁ Û+B$θÉ_p&2UK]ät!ku“Iý®B_;è×HÐÚx¼Í¹˜­NüuMËgkŠ˜ @¾  Uß ‹i§ê…&ò6¸JŠðŸIúI|s¯tßÉóË/Žeˆmd¦ «ê(QµõÝ0ÆVå4I8yL Ü6㢳áÖÆØXk,•jífs6ÍcjøýŠÀT/;çëoˆ]ïPæ]gl#8 «½l±ë¬®ê2À¼.Ír#”‰  `:á³úˆÓÖ±/h©ã¥ ïX+¶Ä³°„˲°±Ub>æ ^O‡‘†åžnyª"Fžµì¤ó¬Œ‘Hõ¾¾™/b\  ‘"LUñÙÈ{°Jв’a,ªXÓ€]*>gkb¦cNuöÎþO)V6RÇ–™`dàt_¨±ïc'A0v©NVZu1•3›þ›¯§8,y Ö1o-îÂwAå†M‡¼¶Te§ôCj;¶Õ^)m:§æEÛ„vÉÀc¤a}UÊДtUÒÃu‚‹þIXHêô³·˜‡j@>_Æ»¢Ê*µHU!²­À/L ñ2Ð(V4 y]Yð¥”ÌÚL`·%üMk(Óf¦T`WÐx¼añA1К+Æ×\2&êq!iWG±¢à ÕLÝR­ï j…}À(úFmAÚmd– ÄRy)c–‰FÎv8póYeZ^¥ÅÒÊRú'b¢ï›’ÖÖs›~ÂMc]´Åk Sžê,†,ïš*| ¬‡+¸>OX…æmK0ÕÒ.!còÎ<”vMÅÝňeBxèÕ® a-CmØ'˜~ŒÝ·Å‚yZkÛÞÕ>*[‹Ý/Yü3ÞÅ(Du˺kägw±1åk›w±¯RÑMv#Taö®Ä%5òI Çm½«—(•ÅEßb|«† ž‚ó.Q°2!D–ô½YäE @uáÙÕèžTÈ9‘6ù2úÔ.HC‹2/¿ùüöxÌJ”9Éñ•Ý\7 <=ƒ`”ŽŸ‘ÿ7…ŠÈS¡­H©¦2ÒU]§_Rì¨E•?ÔH«/÷´>Þä³xÒÃJ$^ñ%&pqK–Æšâ¼Uà*¶©¡>Ïc1éX1ެÑÈt Ò¦£DßVçÜà0ĦÔ# 2žûHb>( ¶MõnrÐÜI›ÍGJQrÏë%0ˆHÿC øÿ.õRŽ-¦\÷·ô•¦šþ7ýxZ šþDÜ>¯–Y2’ ïiÉIƒÿkL¹Ÿ‘~Qœ*‹`Û^¸Pš½5õÜÊø0(Yj.`\³€åZ£È_dkœ¢¬2b=Ée)ËÀ d’F<«"BÙ«l^«ŽKEêðæ *rÝ!§d~À])DHè8jÑ·UÕ²i,CÆŽÐÕª$;db^!±‘õúrB }ÇÌGévÍê¹pž SSH|6zß§ÄY8tŒs›Î §äŒ ECÙœ•'v僠6\Ul4†ÌŽh$ Ê×̳!1ö<1RÄnyW™…±•í d1y«£ëE˜¨~Çæ§qÓW9ž¦ÔAº¦LÞù>qÉ%¸J4„D×1†ÜŽ\gñÞhqr rrX¼@ þ¿D"žùûÂæÐ<ÓUe6Š—9,ÿÄ´Æ:<°´@}ƒçUL„n€ï ÊOÌÿdÒ|ÕÌälÆs{3fr¦ÄÛ«IpxTN°5 ž‡éÚ!äœgð’´Ï~úLnørË›^Ù©³§ë ‘IÔ”ƒ™øF.rz^|F6÷ù¸”‹™£^Ò+ØJ‰V M;D¼\uÔ´âáóÖ@.°GæÞ͇~œž`†H{ßÐZ廽{äºðí–*Ô‹Ô$†ÛIæ]ÔÇIòßâ©>5¼ñøpè¼E ¸wB Ÿ µ­) ‰¡þ˜©`j»•­9d(eJhUy ,uð)¼Ä&mÄØú‹—Òé=¡ƒW*ybÁÉ=«ÆëO¼÷èpmœ²ñ—-e逿WÞ;¸Jðre–'FöÃ'¨aÜâû%,¢ oÃ/¿ë ÷uëÃý,¢îm6#Üšag×Ó§ËX-Œf³/pÅ5M Õ1¤5´ú%A|³¯Ã•S(£Úy„ð]¯xäQʧË8ûÌŠ6šg6N§ÐÃXoÝõÞÅÚ?›tX!/EYt$sÄÂHÑ(+õÙ׉Óuûžoã0š‡IôíS-¼áq“} ñž_bŸÒ™ÿc þ†ÊvêàÎJ{±ïï|;ø6ÊæÛqÙö[Ùç¡~\‚•QÊμgø.1›Îòíï+±f¿&Ôø´V9£7YíûcMY˜0$pzW§üßws1™•RáÓË š¥gþ›D¤hš)Rc˜¸ðèðç_:5¹8endstream endobj 1895 0 obj 4892 endobj 1899 0 obj <> stream xœí\[sÅNÁ›^òÎ㊳޹Ϥ’Taì€c©äA²dÙñEB–ÌÉïM÷\{vgÏE–“¢R‰7{fçÚýõ×—ÑO‹¡g‹ÿÿ}ôbïÎC®‡Å髽añü÷tï§=æ›,â?^,î`3#ŒõN)¾8x¼:` Æ ý /ö~èärÅzks]¿\ ½FÈŽ7ß²åÊ9Õ+'»Ø€C Ó],9ï%c²;Yò^H'mw¾ðå:þ*Û…>¥¶Ý#l¨E¾xµ\A;Í-KÌ8úÍŸ)üþσ/ü~°…ëæZâB¹„¾]|¹wðÑÝýåJôÜ)áºCìMk©$ÌÀ?*¦»'Гø}w¼\©Þº¼ñÖ9ѽ Ö¤ð«Ë|ÕÝÓ%l†mfØ-7¶×ðÕyéàÛ© Xoîà<÷fJàzãK2AòÑ+ØWû/Ó´IßÄ`aµÕü®JƒòÕ%lËb¥\\5GÒÂv,At$Yþ îÔÐØ©K¿f1†û7ú]˜îqkMÏËGÏËž-™íù`L÷o53 V³¸©¾m™Ài9*òûeé‹,€l@Y5³ÔÊ@w°DéáJõôâàt!¬Ä1¦RG¢Ú³Ü3ÞÇÛ Ó §c9§»{ÔÚ¾]¶<ý|œï¨Ä½Ä‘L?€p}¨W’&}ZÞVûŸß•Ç ê†q mA¨u?(÷B0žä';РÏçÍqÉqÙ+SjPº%M¯J·AC”dI/ü¼ÊÞàI®ÂQ®‡éw“;ËéZñ”ôöc:Åý$Ö#¸€‚ ½Á·Žh2¢‚Dó2ãLîì}³÷ÓB8†Aì‚q®úÁ.´‘¬—qüîþÞý¯—W'{wþ¾`{w>Çÿ¹ûàSøgÿÞâw{÷÷ßÌ£{ z ÝŒ#aÑkþd h/,€éÏe¾S «×ó|¢Rdo”Êð„úñã2Ã[i™ÓI®„…É0Á ,Óï3ä†OT½.|ÙNJPñ¬Ðåp@¹€¯¹iKú(5PÝW )ÖI¨O‚­Æv_”‘þ†°¤ êæs'­5ô'-µÆ3xû“V3'­—(©{Núû2ûhô`ëÈŒ»oËê÷ó™ÑÕ}½ÝÉjÖ•á=cÎŽ)<–¨he€'e²éh¯…£¬ÛÊC°–œ/é ¨rË+.]/Ì÷R¯\ò^IGÁšþ¿Æ˜M¨=ã¢{½Ô=Tª,p„"7Xbˆ1*Öî%ö$îéKÄ?© Û5&4κIȬ%“"Jttlμ‘SˆØÀ¨³ƒÞ¨ÌI5W žP,Þ?}.R$Q}GmVÊk3koU›5â0½xgÚ ;/A‰½6{Âü«Óæ¶$ü¦ÍÿOÚ|wi{#ÝwD¶‹Ä™Yó½òû¬:ƒ0€ÑTÐ!þ{‹êŒV†é¥|Gê t€guþç£àþ •ŸJú'T=  ;@e×(3nÛuuÙC…œ×ep`¿Óå9]~”} rÖ‡5ƒƒÂA­?*o}ØÔ’ªà½LVªñi²îszïOÆ•ÿ›ß¦Þƒo ¯ÀÑQ:(þ×Kÿ×½ ¡(E¹Ÿ_¶ÕÚéà,ýÚÔúxfZ£¹ä¨Ä ÕaêMÔQ©¦ñ·Qx'ªÌo¦yN_7Õùi­ÁŒ ÕKźdËêe ©‡Ü¢Ùæ„‚NwBÙS@GÐ5’u"ñ¨r ®&Û?Þ•¼ýn.kP[(lŒX{Þ²%d.ÏX uŸŒ…,žVR®ˆF®È¨ämð°1CÉ>ª+õÀ,ÕÈžŠ@Ǧ³ÃÔÔE3p}[ù$´r›|R`é¸éü…Ú…æcW°3vÇ£Õœ£Â»‘FL†„(ágmõAá칿v‚ÇSIG}óT#CQ=6-õÛÑ@~vg-){}Ô§&õ"‹“ÐUÑ)“AC3zŸ߷õº'Ñr56Eˆ4Dq™—†F2,ìQR_ÿöMy|Y’Nm)%{A¨19ÝFV²ŒÐ»Êo D€ Åô·3Ÿì¤¤²':<¤³NhÁÀ‰pÖΜÀQ¥ïÑhSX^¾Á®€2;ÃÿÉW—Ø–0cZV!„Qô÷¤+¢ÊÅ73å‡c$öæ¾6Ìj´QÔí¸¯Ëoù\^Ùw`ÖØXð ¥°»©3–OÁ¯Ö2bâ n¤”#÷¤›ÈÉçÌW°Ÿ }ΈÏÊäÈöV°c}Aµ~gcEÀ¦µHþøªµâÉAù%MxYê|3 Éœ PÛz¯\–×d v‚õ̺”×ûséõ||&ãôq»VÈxÏ…îkÌiÚo‰¸²Ýh?‡†Âä2'{ ’á ö±!XcØHƒî%‹9 œW¥élô,6ä%çˉnªx– ¢Œèó²4~Oô*Lx4y$L³AGüSƒôÙ)ñM§¡äX3?Ú´(Ž!AmW`Ǫ´3šFŒK›w”žˆÍzCivvm»ø +Û_ÉgŸ•ççV  v!Z¦[¬`Ž“ã8=±óìxw<Îùkòü—¼ªýG[,J3ޏýEi˜Tµ¦K°¤Ü€Ð}²Ää¢ÚvP\óÏÉâþ„ÞcÒŠé©âCÜ…<^Dþ?¢Œ@cÝöÎMq² !ž"Î6MôZ¾ â'm&Hdø#p~§Ù­Ì ’'_ÃÏöNyK{Vë5-^"ÜËlN+Ôœl>¸åeCÿ¶øÑ¦­ÿC^M;ä'¥AIñ‥š»GüˆÃø¬ la«ŒukCýøøAe|’¶ûÏ$ƒ|HJò¤O)V{ÔŒ†‚§©[O+J~îU3º/‚–ÝnVx4B ¨«Žj\Uy d{r6â¢ÀdÃ’¦Ny¬`kÿ)¸É)ú‡¹–˜N‚ö⋇ü²>ŒaÈ9¿±t†²f°!'§7ÑŠ†/8ñRXX'±„Ù§smz<µƒ5jzà5× $0ôF…ǺüjæÈ4ÙÅ2ʼn+}ÈÄl ÷_¡r`C¸À繇ŠÚOV°Êšx²·CÕznŸ áZÇøú¹wˆŒ=nO¼A@´Rb"B ·šî´Ó²é9@,•º%Ly}Dz‰ñ:¹ð.ñ‚(B¸ÛŒ[ŽåUp>@GÛcUÄMƒcL$Ÿ‹†Ôš¤ízðk,ñE@D)`üO±oûDp}ƒ°ÏbÆo[4äê].ððrç^t0¤âá^ǹ\¢"s¡ÉÅœGù©üú•AF€J7t0àÖª»ïØKÈpϤSKò}ù=yc·zP‹LŽô¾Ý­ž("Ç&4 ¦]Xq9Vd¬+’b⤠ãÔá˜/%Ú0¨µ 1–Ý ±ùžKÌúìt‰(æ7f\óQPwÕÃ!4ô½—!ã\Ñ#™Ø¤é9N+ËJ€†\:ZOiààp®$¸¡ÙTBYJ$‰ð•|Ï÷K†±'©ì],ÁÂ*ëx;¾Ö¬ ‹õ~#I1¦ÏÔ±¬Q]Ø Ò¸Ö»4Rœñ|b×ÃY6bä8JµJ;±{s<—¦mQêIH¥÷ Æ¡™@¹âj'ßp~O§Œ¡%8,^\Sí/b=—Y“èó*š÷¤9jÛ¸—i›§ì† @SsìwmÒÿýÖI·3¨ä-ÑωIñÂø ½™dTMÍ×hÜÚ~¥Æh5æ¼ e†&È»™Ž= È‹v”œèY)Ť=4‹v&¿¿GFðÑ/]ÂðY0ͨåóžKûض¢FIU%DíDP(4ur3 mQ‡“G³Öê¢eý'»4Š?Õ²–°¤®&"R‹ANüK³XwØw$÷{-á8eëDo·*P¸ƒ¢4ò-.—ú讀‰µT´R`ìG°:ÆP2véJÀë¦|N™{D}ž!S6¤Ñ¦$¤–?á°”a·*¡±þÏlt/Û^õ˜CO¯§¯0{5[uÖ–:¿—ÃMpßo4š `œ±|¾@HhÓsÁvr!HŽ^h×[  sªâÌ$`»ì»gwÇÌò—¨|MÂ'UmJ!í—<N×"­HÙNÒõàý¨:c?õìz·çaüMøãØ´ƒ7qk­EŒÚ•£ê¢un²;Õk5ð_ONèEË µ+i å|ûØÚˆvI¡š´‹©Ûó¶È–“%À¸Ôõßh^‡˜FÂÊ’½"%ëEMÉ͉I¸ ;%Li‹ï}ˆ¶ŽÜÌ!å–ÿÛ±”^éñ[¬Ó¢½lëcõÕ “ïñ n¤‹>Ž/ÜŒh^8« ߪ\ŽŸx›š©³¦Kû$LU¹*¹Ø®`Žm±H¯ÉlF5V8?&FôÀ‡EØæb¸¶£DÃCùåÇ‘¨˜^® Ê´ XÈ[bFÚÃÿR…¬ýT¥ªû…#†áÔ¤`Ý<½ |Ò4ŽÏãWsÅ=¤žÔw tC‚ó€v11Ay?ò'YÚeú÷kÊj°¯q,5!Æ)ÔÖ ÇóÓ}”€¡gá4ñ¦Œ¬*Õ}¹›ÄbÆ%rm¯ Yt,“\”v<±>##Ò€«ÃB€â”Ï'V&·3øµ:^3ë>ÌDeD"¥!=sAéF¬ÎÛÎx©;™·¢ÛX·¥Ûƺù#;¿©VcÓ-ŠÍÖ ˆ4ÃS W˜´mxAäfõ'È &§‘—¯¤)Ùbái»V¥é8ö1âó” iI 9&! ¢·qLR&©vLÒŽòÕ.5ˆí)®­êYàvþöysˆ¦Y5ÔþÀ½•²í‚çu†0ëk¸€K^æ[Ì›±c Ë7ÕŠ"o;>×DŠÌ­0ŸnEí3ý –Ñ(K3öMd ÉubÉÛ‰…Æ_ÃÎêX;º`#u4<$ËHùe®¤ùfï¿çcŒ{endstream endobj 1900 0 obj 4031 endobj 1904 0 obj <> stream xœí]I“ÝFrvX·¾ø/ôͯÓjCUµP’µ˜ž9Ìø@±¹ØEŠ¢þ‘ù½Î¬•µ=à=Ý”Ç1¡á 4€ÊªÊõˬÄO—ãÀ.Gü_ø÷Ñó‹¾åÓxùôç‹ñòßà¿§?]0wËeøçÑóË¸Ûø¥ìÄ'yùàÉ…»4úR³qáâó‹¿þåêZ ÆŽJþ׃Ïá)51úþÙO>¸»ÿûj„ JqvøÑ=h¬‡×W×\ÀêðêJ JY)¿¤?ÿz|u͆ipõË+ãJn雿[]•Bóóôç¿®®åó‡_ý››/ü Fò$·Óáhâ|˜Œ<¼Ÿ^ð2ýü $ŒúðíÕµ¸•ÚôÉæ’ʰø2ÌÏÕp‚kþ1êlª»òd3%ü"ó|‘™4³öòÁÞÿëáA"‡Ì,ýÏHŽ„•åU-i]Fòœ…’Œzx2¯#™0ÙÑG‰ø×iMÉ`/²Ç¸œm5÷R3f’0.l„äŠÁ¦13ð†}˜¶¬sZÈð÷IúÒ8Æð>MH#lD\ÝîN¸§Ffà®>ÁXxN…ÜÕgó Èj­iboæ¿û²Œ)Ê dë~lÝŠ¢¤Ø`aµŸ‘ÅÀÖÀ"q Ûl¢LBÉô^׌1)nÀoW×ã ÇÑLN”¹2ƒQ rP0S{|¢°è÷<“ ¥â®êlת]uÓkokÅWîÞÀW¶íSÐÈ’ô]?¦ŸN{mü9À$¨VàÜ sFÆuw74dÎXJÃϨ&ÁxØcÍ@ŸÍë-jA¤üäân^‡í¼f `¶Ç4í Õ\ £gŠ–’ ·VbåÅâ1bke†ÂU ñÖ)…®ÿ¡¹i„"A¨Ø…4ðíwTXŒç¹ü7¤ÅÂNÉ8Y”åd7^áæªé‰ŽD˜•,Á³È–Ôð< /˜x_™ ‘v•2Á[Öôþ—TC8 `óMn–Ýãé™)›†½˜%PÌ{ånˆ‹ †ûYÉ,8ÿ´­7é¡¶]DZ„„ätªä†—-AèÈmvù];ýz5ÁJǵã rP û4%¯GÉ3Yý‘.,,’ÆYær%<ýú¥œAûøwÐ+|°rœ´—o¿W׳™Ç-»—Œ<ÊGéç³Y)ñ‰FK¨#6^›Aï(Ô¨u”="œ…-ÂÒ§„3mŽ "ó •Éxk>þÄÀ4U#¬üdÿILÙÉ,% …»pïÁÅ7?] ï#ëÍ%ŸŒÅ™`ÿàõè\tÿâƒû_^¾~õËã‹þrÉ.>ø ÿ?†îrùO÷î_~sÄåf-—›ãûap’¸÷º¿Db”æð!ø¹ÈWÑ!íÏvø3ÜPí$óDçűAG…²VkÇzb:<Ç]°øšj2f®;Û2ª¯‰jùyv£‰6¸‰Þ£*=¼ªÜ‡õþI¦ˆ¸z¦Rv4ôçãRÑ•®yy¬­§÷ïõÚ'z®0‹ϸ;2‚ŠW|02ªxò®¤h^´fætŽM6¡Îáþñ—s˜GÛ¿ ôT=—Uê`Ž¡ UY7_Ah¤ ¥P!Ò2x#D—àŸ lV˜Ÿ x»@·ÔJYsjõŽâ­Ù»æªPv~Þ­¢daJ燲Ìõ¼ßgÜp!ÑwMz£é´Ù´œ´“ëû‰ßÈ ž4]ê÷}¬­!”&ê 2ÃÅKO¤ø{`.me² M.˜bAÅ¢;?m¡ÉU[“ ˜¦à0˜3¯É‰mÎÂ,‘.Œóö']‚¦”ÏÂ` [½_UböÚƒž7FYmˆòÈÔP¼¸zxx44G=« «aˆí1 `!kÔéh…µ ÛèÆzL­Ü5‡VNý ;¯X¥~ .zÚsµÅÂfÙÂDбºY ¯(ÕO‰Žr!¨–Á%l*â=‹°[nø õßãã౎Wø§{ð!iøEǃÔï µJì‚{êi ”«îBˆQ—}Ç#nÊc¯íÁ‰û½$Dë}L tÁz6¼Ül§Ÿ,‘•Á-pï80e7 •ãˆÊ“ÙTÃíÖì<¢05"^çQ' ßpáG’¼‰ A°ˆÒ5óTZE®EÈ =“8_}1çca6ÒjXW»æ^žó‹)*5XPðÎ…²|9µùÍà©£¦=^QE’Mò÷¦fZ6d†ü=úÿŒ˜qê½Ü<ÃÀ€Q¶»è/Ðã`zy¥OŽ9Ë.â·Ã¥&qñIm?I‚²†LW;v·X+½d¥"ŠàV(·—qA0¼®#'DNP#•­iȲüž{ɘÎ2®]nckÜå0z¡B×Êh†&|n3!üì6ˆbÛJV‘`É iwJ )œêù#«Ãöp1Qöz¹c"·žzY(£"”'nð"v—½`6™Ê6R‰”LV£Ø“7µG%«Q¸Q­Ü«Òï‡ìئŰ=Õ—IÔÚ ?0çýÊÔü‹$Í™­ev0 ¸'­H¼dæ"\º×âƒ}DdPbÄ»O Ûˆ>‰Ü>rþ.Ó½¤xñÓä‡ÿPn™{Áo³Y=ÈÖ9 ¯¶§:);‡²Pø4¡a?´$ü·Ùìµï|8»¤O3uØ4 yÞK÷Þþñ]áÓˆôQK„x'"05õöéIÞ­#ß/ÒÁ5Ë©÷0­'Ø(c^RkC¤Š«¼”ª!í¤˜$ø(o”, wT”n1|éN{ø{€sáúÄ|WðKqëŸAQÀÂŽœÞÚfZÛpH»ôkii[òϵ_F²>JBýæ˜7ˆWI.ú÷æVùU']–3™AÈú.‘õ¦ùR²5±51¦7þ|c´öfZ½¸µ˜¶PjÜ(}ÑCŽwã€6Šù‹·F½¤uh×þ´£œLíMÜ«rÖ½®qÂcíÛc]Bø`ŒÀlèW™€:ÙÚøàøñìdî?aÛ8j;Gùº2Wrd}µJGRèMÓI,Œ ÁÉRkð* ¹ãž{Ë`$­ :É08Án€Vƒ)—¦"Ö2n&§!y ÷È•÷Ýb͵%øçÙl‘)z­ÌæëyÍÍ›#ø Ѧ¨„oîYþz¢>u6Õ5sÈâ\lAÝñvǰP\·Ÿ¬Ðä~AL#x\&ŠIK×î–Ýy¾úìA;©1ÿùzV;Ä3|XZ!R‘FËŽùª ÞìUN‚Q6£XF‹v³ÊÕÊNcJ––AðHMræÎvâD8læÂáÓIo8e!.¿ßª!}’§fB–p+(`ŪJì,×7 “ÈIÛ}á6a1ŒƒÒ¾Q“ƒ›ovøíw^âË)Î}Äh‘Û6÷°ÈÔ?ñ†HYÆÿTŽÑœà(‚Ã@¡²ýòcWcì¹u¡°E®…_ÖN¤V £êhPªë›P¦ î@Ïž[j§ÚÑ ÄÇ‹a:ÝvCN`Q¥=ü;1ÚÉÇý +³Ä`&qúZϵ Xå¥8jÊb÷©b^“ÔËVó¶²¶+Xx{ý WkÆ +(˜OJìY˜á÷k†~îÏ2.™ÕAá+Õ)¯ x ñê“UsmBy^,úZ\Ñà»Î ŸQ:‡~‘8RC¨ôÀ™è‡M«]†EO f44Æ€¿™sÉ|n(Í–B“Œš‹ðþ“Ê‹"®›Jò³-aƒÞþl‹æ,¹äÿÝíl‹˜$aR&)§zê+òÛzáàχ^8=xùñá¡<1ijž½9W¹úøGÝ Çøš«ÉaÄx -;F80‹ŸL¨ô ñSï\¤/¿b`6Ÿ0<[ü£ÏO_ éˆØM®¹0Õ¦µ–uð”,DˆÎƚȣwSv.¤ç+Oj¬:R@Ž]rš)&tÌI¹«Ïgu–ö†ðÏËúýúXÝh@=jÓ>”D86[z:ïM§ ‹Ê5ÜDa#f­8qMHê¦r‹*Òh ™í[d/·hdF¶µ Ï›Då …u:@ŒÓS~ÝݼÆÎñQRáMfÞ,lK¿äUI ½Âñ[•+œú4_ÿ¼VÚœS ]vƒ.Î*c»M<£\ËO8¡õ gp)ÆòkiŒ¿…1hä¶)\Èä·@:l¤””ô;©[Ác¤òœCZû–..%vÚ}0Ú:¯Õ» c¦23Šä;eÛ¤Ìñ\Äû{Yz}ާu5ôq°â°B¤çG?JG²SãNÓŠY÷ šC’ÜvsQ6ö‚Ú+ƒ½~évf¯]æ<5nègÎ¥Ü=s~–¡»“ÚÍ~íö)Å›Ÿø„‘‘,Ð^ºÔ[éíSª3?!’RÐŽ'r#f˜Y6bãäìî6vÏŒX‡¥Œuñ*3&æ‹|i´šÛ˜†p]Žè,ˆE#ìG¸ ÝD*TISb9¶¼]zÔ·3O-[œ°[‹N‡Áãÿ·A»u•¾å¹Þ~ü˜×‘ò&†=åQ Ðb·CKß1çärÙ}ÝŽ6¢ªt–²ð5RÕ^ájp5ˆ±ŸB ·6­ ƒ¸ŽÏÍAN“žüÅÅÚsé{n„7h@(í[òx*÷LÌæ¨€DçâGÙ>|–9D œ•t+ªÑ»õUˆ…™hX-ruÉS`à ¾ïÙ.;îÙ>¸̦¨+ÑÌíØcÓ–ö³ø.ì•lÜG-ù¢‰Ýı ‰lßVØ„L÷f]H˜·B:€\Òï"¬eVûj¦sÃÚv!59FË šUÛ/+‰IJ? whDpbÌò¢ìÔ²°¨Ï÷þhñt!#±l¯QÜq‡h+\zëÈ:ç÷È˪fqe¥d[Ïçu¡ý¼n §L7¦ægý\N;ÎuMùµšö=ô{Šiøü V*¡©¯ôœðoâÏÍÆÜ<œvÚïk@ë`42»sÀÈAPpD7²ÆÞíÜå‘)íw^Ä5 ì–þÿÆâÿŒ±HÑ.<*s4+ñÚH?Lу òM´§X¹s2ðÓ#ÊEèC¼Å¾·¡RŒ"‹YÆùÉ*AåàÄ­„ÔG`Å`%¾n5Hý¶U³*UvìPáx¿,àÛÙ™›Ý,ã„þ„*“kîÔÿŽQPŒÃ #¿ÖC]ëïTºëk)÷lÚáÚ*ÊMúâóÙ £n­Jìš×m»Ç´ëö|fÿÁXºÁY'Œ\ûíŽ}tà²Cyµ5”Xv<ñÅu¨·¹ý [ùñöíãNý‘®ÞÉ¡Eº^RÑìöur–6ÑÝ¯Õ ¥ÛGZ†ôÝݶ$üzNb¦ú”oç_÷’ŽY®÷ãèc­Áþû †y§ß`CdûXbå&E”Û·$û»¾Ý`hm°[U{ ¶’9D[Y³‹_ÚÈ6lÑn{ð¡—l•xŠ ÆV:©,C©e/õÃä…¦%OòËæ_e³nÒ©®ÊRÄœÖßÈ•çPÿèaK¢k¥±OÉœŽÁ;C]¿/n!à"Žƒèö6,G á6hç®Á¥}]ætãz­QÎÎÞ¥z­Ý[Íåj9ú|à?f«KÏ'$­‡Âq&šìmCßy{GÖ‘ 5;Uçí™ä•Ý»¯k÷ä ßù¢û•¾J9Ë–N‹´û|ÖçÁÁÉÉÚËøï_ëQäLúÔ-w8«UP˲ژ+~·ªÊ>#¸ä aè˜5þªNèÐÛÙØnõg„OJÂÐÚÒSGÍöºÉô¶*.ÂjŒ°Zß'‘MD†k¾ý„üÁÝUþàª|©¸ä.Tç¿:Y–&ÊéÞ¿j)þfKÕߨÃÜáS| ¢áTÝ.ÍC”pfD‡'ß“øzE£÷AÃi·ZܖНE·T¦µð–ú<©þæGkèÅéã †ÃWÙZ¨;Û] ·;X‘Ÿ‰§î¥H†¨Î‡„i*-{RZVš¥Þúðið2/tÙã­…Û…&j´Ù"«©[c–Uée¸]›Ad¦…öl7Á ÃôÓøÝm¢n=¾;íîK <£½­Ü&Þn‚ôÜ*Ciw˜ak¼]b>µ×*Ï½Ö Ûö­ÚneÓŒ¤0‘àíðŒe}k)À!O!Ù²”]þدÀNEòUÂÕkVmOÕÉ"ή¸û‚BÑø× "³ðµì(8kÝ­c˜¸5²0`î*›§nh5íÔ^Ó8Ìí#Sý(fÖn…LÜå–ØÏ•/ÊÿΗº-ÈÏ—+B¤éì¯ ÆÖ^í "ædÜ Þ=Þ5| êɱ%ª[3¨« ƒK–Ñ¢.Öž0{ v߉s»Y#P00zäÙÇ"«F¡Zv…~• ¿ÚÑ&)+ȲñV’Z©\*’ÆtûAëT~m9í¹K…hTvêG®ád)a u3sd±b9r†¨Ú¦¦,YÉ«ÃâãŸg‘²=½ªnÄOć$O’ÌMnÎh‘<²Ž‹ µà˘ݵtÁâC¶M¼@9ZWu±;é’¹#Ì”vÒ¹›ø~•èrÂÕÉDÞúäužï»`ÇFù{á³ì]Ð#|®©‰5ôôu/þû*Í1§m9„9º' 2tPz…eDßËï64h ]‹i˜UÌžPFQEèÒø°ñ+i.Éú8ÉÇÚ-9Þñ£Ñ­-ŽÕJН7võ9ÅD´“¿³Â<¯¿ªñÊuáJº œ«2޵eÉ=Ã=C—Òi5k³$‘ahKþ*c½™_NÝÝ…_xnªm Xtï—ºÒº³kœTáßÛª†/Þ¯ÌÒ««Z¾$èa5£6ˆÕX¶QµÌÄFür#Ç­p&lO4ÞíoÚ‚ö%œ©]•ö¼åöfü>Äî³›Œ[D:»#(™ûüTÇÊâi^kØ)eÅb®ýÀÞ³£ka»)ÿ ôzä-ÐŽÃÈšÿîö4É;꘻ÿ T` =þÖ4î ßh-މcÓ´IÔs¸…Iú§îyZÔ óz ·³íVfW1m(¥ÎÓ†ÑÕ~û¯ªWµˆV–+ žÄM]„!¬Éˆòþ­&i= Å’&¦±Ç*ùôÕÙm‡\'½é‡nU'½ðÝ¥®‚o4Fl”™ÈÕö·Þ$zQ?ñJ@ÞØ>TeŸ¸jºæ»…O;dßBOƒWûº,Š–2]RREÔYk nfE§ò®Ÿû€§8}42“!§jÈóÙÔó¾É',ûlâ– äVs|ô_5ôE‡;úU°•Ó¥´#ÙÄ'Ö½;í’cÚ4£}É&oàjíúì>;L>ç“ÛÀ% ½a—¿¡æ¹÷$3ÃÆÜ'„t˜çÆoQœÂ}û$¼[g(ôZW–¾ÓÓî”yr®èpìÔo‘;É÷ýÚŽ)­í@¥ ÀÍ38èØl_LòBñ”‹Î[íÇÚŽóXy?E%LæüT(ò¯F él÷/$ïŸÓ9Çû‹?‹o'L( _^sK£¹gÝA¦'E¥B¾¹ø_š |endstream endobj 1905 0 obj 6108 endobj 1909 0 obj <> stream xœÍ\Ýo·/Ú7½ô_¸¦/wAn³ü&ô¡‰ÝÔã8Ž’¶HƒB–d[ˆeɲ”Zýë;Ã%9Ã]îÝÉ–œ pD,¹Üápæ7ÞëE߉Eÿ¥¿‡§{Ÿ>‘¶_<³×/¾„Ï÷^ï‰8d‘þž.>ßÃäBêÎy'ûÏö† Œ²’ ×ËÎ.öO÷~\êÕZt>íÚÿ*¾ˆ£ºÐ‡øb€q¦¶0þÆÿi¥†ÆÁ„² B˜øÑYÝËźýhµ†!JÙ°üf¥t§­ Ë}|¨{#Âò>6… .~ýþþÞ·{¯Z+ŸEŠ×ºó‹`C§ýÂí:ï‘ Ÿ?ØûôÁ׋ˋ«ã½Oÿ±{Ÿþÿ÷ùã/àσ{‹ßíݰˆSÁëqå}5“îäfše³X„.XiuÍfÙy½°^g6?XÁR`ïÔòÙj­zÓ)o–×+à–æ«å5¯p€ëz¡—Gôô÷ÉZ#ìòph*xz²‚­²ÆH1«€–—Ô–§5Ëÿ®Ö}gC°Ê,/ al.öÎ%€ržZlz‡3 sÐ/|'{˜4~Êõ½·bùŠ–¾* Ÿàeü* e>@S‚´H#–¿”Yˆì%š)õ[åùRNhèY DÉ »à-îÌ”¨W¥ux£I¡…ª±üW¢;ì?oÓ‡’/µ…Y@v¢Ö\VŒÈ+e<#¢Þ ù®3Öñ·^Œ¿„ï_âN‚¶…À(e‹bbuEô_àT§”[ž"A› ²Lè=É]%A/h,[wË'cŒÈqBVó2Ød×4YMNðf¥€G°|¾´—\àoW¢÷h6i-ä°MÏV€G=Šó)'›4~ÔÖ %dWø½âj @«¬vËçôMUI™4]¯‚%°˜ º"З:ø’u€Ê³^K Åæü_‡y|¡É™Dˆ¼xK„°¯FÀLLˆ®QˆíDÍþøË%öZ‚>;`ÚDH“X¤‡GÍ:N¨¶¸3mDÍ È6i÷{[õ_nªùO*e²—Â_z5h³´ÑîD)9B:n#ƒIæASÁs_ Ÿ±Ar€:ã°+ûÐõÒ¶YÂöyª<£…24`Z{Lš˜cLB³±Z_Α†€¼J“Ùj†çãyã‡ã¸^K‰¯‰à;<ßàTª âMe:4moX?£ë5 ½j.A­lÀ…¸Ýkð€¼ïŰë¤2W¤R#9V}g`bfLÏ›ê7¿8 ¶à1)¥ÚÄÞ‰CÁa1#Ï@p¤kHȈé)‰‚N€O };й @@˜pPˆ5–éJ‚ÝFj”@ÀaßÛ´¥YƵìŒ+.StBFf%D¾ƒÌjŠ›ü¬µñQ-Ö”)kó›•9¬=ø… ø@%Ø@Põ SÊœiñ΋åã•ÇZôzùÅJƒYÀù'¥…~µ± gœ¡çÍ…Ì‚[nÆÅƒæuÑ›×°cÜ[¯]lAúÖïàcÏ:þ–boÅ]wzj`µÜ]wraÁ¾Â'XHä0>éÐ} Ê)½”ͧjµÁiàþàêjƒÀ£p€Ô¨qªëõ`ï%È} €¬ô‚b.E@ܦ,„Rû÷ö?þ÷UʨbȵÑ#EÞÂe›ÙCÿu )˜N3M?©Õ @jµ ‚‘û„N¸ÊýaÓ>¥*_"O@lá@ŠA®…ŒK ñi0Lé¢ÿ¾hH¥þÂÃ.è0k,c?l\X´ñ’ëM Lœ«Âæk`Ý„•Ñ¿¸±Dy.B &¤·‘SÙ)ÿð>áóÛ‰G´a\?o-›$¸íÜÒÚob^ Ž…ØJ÷âf;”º’,€ÆÕNy”vkg‚Œ²‡nøÐ¢‡ þÙô”È­cÚ×wÞ$\ÐÚÃë Û LšDlxëìô³Üx"‚zt‘—©ÁàRõ„oÚAè†×‹›f6fnÃZ¼ªr”i¼ž.ä ?:Í“Ü8ܼ"#Àس"^±íE×; "úŽ–Pv‡Vw6áÅÜ:­ï?Ø:€x'T }9!ýiYh×Ú«ÙT• `[G³';oL|umÀ áÚÃÝ'³ô¢J=EOÌR´Ñ?íÖ ³ZË ÀQËD1õ>Èî²àX,Í<£*ìnÌuÅ¢á%•Á¸¶vl~æã±Ìzæ1bó3F}Lm¢¹œØ‡`¤ÎùKV-Ì¥cóãÝrg—ŽŒDÒ‘R€YyW}prUŽU²K[|õ…¼Ñ-» Ò¸”@•wEë&¤ë(BdÀ¾Á½7H~ ¢ó;÷\oÐP¾¬»x­µÃÕ|UÁ§‚™YÕ]#¼*|°…‚ ]½ÐþÅNùóÑì5ÂÇEìÕµV&¾³†p½”A‰ÿX‹¬fÕ±‰'?Iå'‰Ô”×Ȉ‡EÑOQ '~X‰œËPÁøÅJ@°…2¡ü¶ôÈ¿—÷ØÉÇõ8ÄÎù×Ü %ëÞ”ÏêȤˆÏ€‚¼Ëß>à{ €1wˆ ƒ|펿PhnOÜ?Ö¯(µ @Ìa±Ó³²‘ž5Ï…ê£áH«™QÎ×-G˜­»ýÖ êƒ/¶½¸Xi0ÊÚ’­Þ>í5ƒ†ŠÔ!¯NvQg ("iw“K?—þŠG>Ú·ÿö™ÑDÀ¶œÊ)Ý9 ÿˆ»qÀs:ª•òSvD°)›yÛ£7È^Ýèrt»jãmïw4àçx>L¥¨íTðå°}Bˆ8.üˆ¨1 RÁ3Bíàû@ 価ù¨Âö¦e7,»žIœÖÝð a ‰9#š`‡Â›¼Èu ('N;\åg‘zƒÃë„L¼¿5.Ò€qz޵ʬx™Îêcx—4è¬5éQÅÉúi>þÍö½šÑlŒ$õ Ù"„»Ðì-¯¹-Yì)óe&H…û㊔GŽ"mÍŸÖªMÊYvwɲÆ÷ïçÌ`âÇk}ÛZ® 趨ÄJ'g|Yµ6¿h¢L³©ú&¬M5"Ê<×Ù©²ÎA\mÆù³8Á†8&¾åì WyÌûÛ^¬s.b´`—“ºŠ´†L$Ö˜NU|¶À ó²Y°ƒòºÓ^Õ™de]'#ìJ0ê„+{ýV*hò kzÚ®‘›q4Ë|ò'”нäc§åè.]¶NÖÚÕ2±ÒûNùÀW‘T¦÷3ñÕëlcH*Ó‹Û]ÊôþP"ŠÑ9m°§Û“tö´ Sn3ÈÇà.Y­rñ HÖGcFm÷Cú6;ûO Ï›^Š‹*‚pU¾wvvÙ\„Bg%„ú¥É¦i—³±æMTœn³÷EòØeŸ³þFÇ •º¥2[HÚÖ{fŽû³ÛæÛxH4‘fgVÖ¹¢÷9ÚÇÄnžì¥Æo¨JAÐU›Ò±oe¶'°n© bœâÈ!¡5t܈EùìÈÎMÜv€ë/giÛì,Éé¹nb£r¶žf¨­`»mxZåÊ :°À{8~-¹ø©Ãú°±Ð‘#aC¶§Þ¤ ¶é¿ 3­›¹®OÈ9Û\ Ù—÷@~¾±—1òÈKë§ÜÚ%AþWÜq˜ o«¬úžµÒâX݉Vª¢ößÚQg7ûÎY‹•›IDpgrˆ{¬æ0ÿ,e§-« œóÙrÎlêÅþ¦Ï×ÎÊ\mc îÌax£fî6ŒŠ½u'âvÒä"òQvÆ; ôîgÕuV•üÁBDP?må"Z°5‹5¬VÆìÅ•!*krÁ¡ÅÝXq®¦•ùö”¶‹¹òàjž¢àê¡– ƒE˜F9 èv¡…öÂĨdZim›úÚß8P9-j|y1ƨvqbÿb¸Uç`S‰Æ-ú',)s°ªOhÆGÓz¸|%ݙܣ¨ï6ìPZxÝÄ€¢Ã±&8‰¸‰aj€žëËáÄí»¥“A]@©ãÙZ¼¾ Ô_&|Ü2*ÃÜ hÇv¹©ÆTO¼N+_+¼ð•-u»œX5Ÿ *'~Œ$ŒÀÁ#|!ôPB¬ƒöI¡½´©W ›‚sâ¢s­1½AUǹ)\àï\ ÷†úq´÷-õP3¦Œ e!¬Ôö¢”:ïRß<¥;ŒÏÈg9+žß yÇswÔ‡ñæhÖ(U$a¿«˜ ¤&´ïJMëª7Æflߟö·$lXá( ].)Ê9¤§/˜ƒ1‰j7Ô‹LÐ|€q3)²5C‘yð%å[R‹#_¥vís'd!H<tXtë·ä‰Þ=³ú.A2ßß!•©ñm8}·ãþ£„¼z¦B¢ ecÅ4÷@¢–3É, 3Sÿ'ñÜú…€á·Uÿ×,ÏÃÛƒàu.bå|*Ï£;ïo‰Dü)K~Ìh¥zË\–vjše ÆcüĵYolØ= ¿”R ºf¦Ò i´Ømˆ<¢ ¨¯^>3_B0Mn§ÓÀuJÌ]×iNÑ–4‰ËÊ,Ûz’$>« °U*$îÇÝËŸ ÿ¹øÕy¯Q EÊ{µDqZ•d­YHüÑ/md¼½ÀX9t»¾ª©ºèègí¨#Æ”¦z)ß©@¿ñ€G!ÒƒyÖ<HG³ÉR¥D'duÿúçj@Þ¤t"¤Åp‹C£ÚNnql2nÑ„ Ýë\œâ9á{?c6F·‹ãEÙ­wg$E€yÀ›¤Â9y·¿Ú‚at.V>¥»9%@çÆÌ]“ûí` qÉr0·bgLöVìÂxÅÍ, 3ØÍ˜â\nv‚ײÆÞF´¸kŽ`q óœ#ïŸÕÉ\``A !s6ºv%lVÀ ?¬Õõ^B[©=÷wÉešËS[àæV¿¦¡”aYº9Ï6xN ·ºGMýiý¨éïQâ=†Ì’3'æé–Í™\s/Yžù‹N":³òçxî©àu¡ãòìYi”ÞWåPb•„©åòËÒ}?¶pžaëIéýky¶_Zß”Þ'åÙ3ÿ³<£Y¾.½Ë³‡ìݵu&þ$Ì7QLéµìNŠ(IbÃÛ2ò’->·.kÖöÙZ RŸ^Â^•g¥uZz‰Ã‡¥õ¸ôÒGŽKë¼Ñ{6šeÈñ֗Ĩ…½ Ì¼©Þy6Í=F*v ŒlËÕ$xf=DüZ¦íqމÏyýŸå¾¡J7Ùòˇ…gŒùÙ›ÒºL¼—èê\¬m¯“ p`ïW#«E‘D쇆°‘(~WZJ/Í÷(°”\-ÿ’ˆYŠ&Š7sç :ýJèÛw¶øÏKï÷¥÷Aîýj‹Çe*¼(Ÿ'¹HÁ³ù¸OF+›ë¥õ|Ñà ©Ö×lfÎ0k·aùQæ±ïoùQ1Zòk¬c¬œÞü$3îçöôêèyé+w#Îi ƺÌõ˜³7£àñtÖ{6%m8aRx"i%xÒ8‚ä3š¥\Øý¨ô~–E?+O¶.`zt{¶œ$ämCÐNG8½/GŸ#m©ÍÏei]•^p@­²u$ÿjàVËÔ“bQËÉ·sI¼‹l´ûÆ’ÏÅ“D·H×>‰Ë÷qÙx·UâÙ…ífM/LGOS„¡'é¾o÷þZôâendstream endobj 1910 0 obj 4586 endobj 1914 0 obj <> stream xœíZm5–ø˜_*’êâ®ßÖëh{ªŠZ(mBÂå.­Ú»IZÚÿ{מ{ËW ªèt–Çë—ñã™gìùmX1>¬ü/ü?<Üx,êj¸Xªá=÷·ü6àm“aøwx2¼=m›ñ¡e¶µN]|h3Üڡ᫜ädðóèîxR1SUB5££ñ„³ºVZ>sf…mÄèt<Ѭ±•«tr¡sÝŽ6ãÊõ¯µà£gmƒÆZÙ6P‚ieGO|’W*öªyòÕ+üêÌU3cGÇã‰bn’ŠO±xØu%]±ëJ [žc¯Ëä3!«E‡]ÂX+ëhìô!-ðkÒçz,™®«Ú„~dex\”ŸÉÊw©¯m´Òª”ç(?9©$%µ3ë%Ö’¾ëÔ²¡m7Ŷ†,çºÕ×Eãâ¹Í»‰Ž™~3¢a\8üLç.‡8Ty²Kò9ŒÄÜHÌ*­ïñÆcípIðY±FD‡u#˜ è|=V¬‘ÚaoÙ–Tã‹uóñ¤æ «Ý¬÷Aü¦-yŒÎ îJg } uGPºÒÓl8_Ú€ôé*_AéÄëÂÇ‹B×8°_Ic™–µÓ°¯4Æ!(Jg±j,F×cÝÓ1´»ê¼’Ý–M ¦×?¸tu8ð!Hñ‹uVÊ4ü:ëÆ‹Ÿ÷4WÙ _¹ç*+Å”3_¯£žòÅ»ªyhfwjSHÖkþ#•>)(m“!ÐKÏ Ž¨/¬ÈÉ[Xpw8+òGœt\¤nìpâ±ãûYR,áLç0+l9Α»¶ÎÖ‘® {)騠5w0,“¢2MkN^ÎÙ¿FKo;©®D8œt—@ È9éJ¢ô 9¹ =‰RÜ¥—…oq~{ÙBe=‡ªb¿¡ z½ŸY)cp-ˆ$éÝa¥£É§ç`e–Hó–DDxìCé6hÿàÔ@ÝPz Ò¯3H§ãnÇ%¶ëPHùµp„”‡°.pÃÂtœþî‚xÅ·£”.¤QŠË{€Ò¢ôHï£ôÛ(øP"€&éoÕÃÀY_¶ì㚯ÓÚßÖprÓͧæŒ7ú xÔR8+„è\£)_÷–ÔA—[vzõ–üi,äAMÁ&úoeu®”^*GíÅ¿¨ÉÜIµµ¶Lt\f:žH&¬–¶D™kMY!ݤ¶Ç¸Úâ ùõ˼AËß!'œ¹øvÝÒCùx¹nX#üB[2]¤ëÈÇ£î´Ùɼ_Œk·’×í;oîÍ~høûØùE©){]!#žC¥£ànM#Œ¹kªmÕPv}âk­ÐµÜÅy…­˜æ VÖ)v³Ã×3Ü,=Ç ÛôXoÅ­TNé\.EÞµtÖ}÷ \Úk$I§PÂep¨«‰¦yŒƒ‹³Î2­¤;œ‚õqJÏ Ô á ÞŠu‘$õ1@Ù à*¹‹¾oó›/[*t¼ I£ºŸAiF`[p=›oŠš”nE©ÓOâ½°_Ðõ¼<~FØñPá¨é2»é’”eËÂ' \ÛEÏ\2{¡âÄ/Kä3K—U¦gü_+h=§%x»0 ("=ƒÀ¶hàг²ÏIâÍÃ ÍÆ"MÉãJaòšø<|¦Œ õµ œÌÈ ¹†€\Õ«þl`›þwËŽ:/«:RC(²dðœ•å±÷$v–Æ3€Ñ J®fô¥sÄέJG¶J±f ¸ëh•FÙ¢·h<ƒ{Qåµ[YË]5]6‰¶ú•´[]T=™CBçs %:}Z˜ñ&4gÙU/EYraÅcˆâ%´|C¼øÄb^§F;†&©«éA)<êêH‹†¤`Ào¢+zØ7À}w€204‹‚'¢^#·ïÿÈn÷îÿÊ7Ÿ\©î¢á¦V\å"ÆÍ!{}>–‰]ÿ<®ü²ŠJýÚý‰}ïÞ›Àù¿ŠÛdCçÖ ¡¡ŽU²/Kéé’ºg3ÄGsqYsq¿ï!à}dÖŸIòPr!sHø,Åü¾“^vûOëtä²qþØDr¹íâN;Öhê-Öç"&'–®v‹Ð9oI ×å"©ˆû,’º àß[$å/ý}¹g>ÏkÜSóoÁ!¦Ùt\ÕXÀ[ °àh^VQ"&·¿h’buÐu–0R”ÑP¸Ðø_[4_Ú~ƒÕF¯-©·JæïP¾Ù#4P«¾ô¬ ¥ïy ½‚«Ù´î­a‰SO•gÈ+š#6ÕäkªýBÐ0&š´Z7Ѥ"šÄ´ÆÍ·/¿Jd!á €äuôé³cÑÅ:©–Ð&¤a"}©"ƒbjCæ|è<¨Ëra¸•ÇŸq*zŸÁj!Äÿ¤(Ëš f‡WìÚ†Gþ6ûà ünæ&I3ÀÜ[òÄïúËâP${¸}ø×V©ö^B'9åDär:¡M 0•N’z7~§XihJ-Ii‡*E“r1`kTÖA§»%«7Í+Ž~6š3Û$)ÄÇ!ñXïN<&ÝöÒÃW](ââxË)ÎgÐ=Éu Dq˜±%-™lÂ3쌌‹©! ¡©ÚlŠ ×Ì:$ 'Jºð2ºsSØŽ•þÃýéà{÷ûÂÒendstream endobj 1915 0 obj 2382 endobj 1919 0 obj <> stream xœíkS¹1•û+öœû°¸Øaôœ»|U6à3>Œ1lœTÅ) ³¼ 6?*—ÿžÖŒÔÝÒh1W‡B®\6r·Fê÷C†e!†¥ûãî6¤-‡ûçƒrø3üÝ|ˆvÊÐÿØ9>™À4cõ°)+áçdoPµé¦ +9¬DY”?ücô—9]ÔÊ=š¶#]‹Ñ.ÂöptˆØ„íέ’°´m"z£ÁÆ£E„máh±/“/Üh‚XúâŽ#v‚0ÚãÙÜXHc ¥F"ÿ9y>r8YLîß)VûßnfVÞ¢+S(kG÷Z`Uy†Ý¼Ï´Lj{@ïúßmN:KÄ™ÇÐNÍó:Ÿ7…Ò¶R4Ÿ–x ÕMa¤¤/»ØR¦¬a{§z%ëšÌ~2S?Å™gáã øD¸IÒ3âpÓ.z .Ôí3…(ꪩºýnÈÞ–ÇVñ]Kr׺A§º LþáTÓ+¹@—ªƒC!=3< œQ7¿Û±jp+ÙmøM‡v’‘ Ÿö'ÕZwQŪqiE!KI·“M-G|öàú"ºž&0”X$ij¾ Ö{!%ÝÍ{ )jCÊò¢Ž"ÈQ£‡L!N ä{Ä$ãíäLlŒ£Ÿ2öIót&V’ïft“&‡N¯]$­ÌèWDÿJÄ"·)YBëN‰ÆÒ”$®…” ®½Ì~W…^ôÇSïÀÊzéìñ³`ë}ëØJk“„ŒE¸Å.*+]¨Ò†¸¼{êª(•ô‚…‰L®?ô˜ê"†û!úý ùºÏfÉ—Û6Š×4|×ÅxOgé®’osÚLÃÛÌœª/­¼y¨¯ò‹• ™èvÆ\2õ28ïËl(ß±ò$íSׄΛCqj EÇl§@5ÍØ…Þ"“)Ò½gUTÍO3+{óvèŸHUáb †!øq[.ËF«4wÓV˜RR ¤EþNØÇKÈ:aWûßÎS!ŽEõ6hç¸+¥‘—ñôÈQ¶b2Zþ2iÄž1jÈOjUT¢báFDD{‡(s@Å­0òœÿ*wøÝfÍ N²+P´õ¼ÅÕ¯¸Æ$"8¾S°gÅ÷ï öä®ÔÉ\$Bû¿ öKÉ~³Dt˜QdÚ÷ÆU5 ð„ʶk¦‡ß|jõGr¸Éa)Ž]Q¨ûßO·€»»“ƽã—½°!* ª1Fº{"A—DJC·Ý%‘ž»ƒm#ðÊqY4ªR´—ƒJ0ãÆ¦ÑÎÊ¢*K êrN¹ RƒUQê¦me¡LiÜ ¥,´•?î–Kðë+ ¢-1~OÜ ²1ªÐ66 Òn±±4º€y.õéBšÆ6®'‡ MiÜÆ@£NžÎAÀ’%hï“#×6Uâ3N8¡- JèV+Uñ ŽxHwZˆT kpºrj§$ L”…‚–lô™ÖbS¹ÔÚG<#Ñq¦Ê¢£'ì¹ ªB4.øw¬·IIÆ–6P¨ÊJ„ LÛx´ Ô•ß ÅïÒ÷g­è¬€ÖãrÆTG¶æÝWÆY˜-Nئ GsLH Ë7Ø£ μš »x5 !+5üGóU¶ÔmuIߟµG"Ò@RÓáD„qÅ8¡.œˆÁâäu µk&k¿¨Uµ'ºÕ›­œÙC$'S¢Ô£Zɱ¢ « Ä̰UID54sgá¿@+5GµÎO²ö(8´gíº±•Ø\Ä•ûlêÝC7|©wYƒ‡A¬QÊ*®ofGN¶¶¨ püäcGm#.غ¸Dé:…c ëÏ,»+§V{@â4‚:´ÑΜ‡îÐMèèÒ²±Á/ëªõûV†/?5d‚·CXdáÀ›eéD¼ê#¡ÙRÓh©`ëN7R‚DëYq.˜ÓC]òxÂÔOÜ2oaß.œ7Ú˜6ýEÓH º© ¦î4;Š·îeº­!h.ÓœHzÞ[¢ófB©_>–~kwÍWwbžÁÝ;'Ü &«ÞÊkŸØÔv™ðʇà5ÀJ—£·CbïÉv†#,ÑEï©«ÄÃá舥«Qªt©n]F,UökìÄ·7’=Ðð÷É­¦qdûa"[xMe$^Xj¥ÆöÕ˜?æjó¨Ô‹pXó­õëH,Õ·âIÄ{»¦¿{’ÔFQ-÷…š¬7oXÙ˜\«ù®Åé϶#’Õ=„=É´Ft÷ý Ž–2ªŽÚ›p=EäçŠ×·IÛU&]§ %`zgL½ñÇdÞ¹?¤Æu/ÀÈòñÄàSTp:¶­Ôðb?ê<ïÓ€ßeèCÜ|ÇîÒn»múŒìù–¸ènÚúe¨`©;Äex_Ø)뵌ÍjVÆT¹ƒfÂ#(`„ÑîL¬ƒ=@UÞËÄœ•Qr+‰·kvºVKõ_Ete ‹{¦”èØêvò£“”³Tñ»ÛƒØ«*ºÈG…ãËÐ1³èV’Ò0¨1¥áñ Yõ6-ܳN<öùï¹´NК–°…ªðº¢Éao}bx|…0.bDžqHÎHt0maP­é©§”"]*hŠyn$˜|¬‰LÉGœ)Ù.( aÓÍýl¿Jmt[ú Ec‹²îòt¾ìIÊw âitZÕýÊ6*œÚ7iùž¬ô˜b)—¯G¶ý²¦žYÚH¥ŠLe>‹/àà7Ti¬óbk½Í¶ÛÔŠ0è—9h•hº~L4Ee5c›õ/Æ&í$‡ÆöFóÞ§†z->¹h+ŽàiÙ]ó½ëm/²"`TDÂòdðjða¨º÷À …z¨ôÓ``†ÆQ³s´›ÎÊÏÌÂZPÜÄåç´-éúìZÒ#‡ø“k'üm §˜ðÓ· ËßJâó4öØ-!:ž'\ØŠÒû=8‰¾lä/ nÈMé5¹é«Œ«–œ‰Þ¬d°ËÉ*qXK6>JÍýþÊó$(´.‚!Ýà5# }i“€X\o"¢ØøM’Ñm—|nåï!ù¨ ¸é¬t;…žæ§¸ [¿"SåòÓÓÚêãðè>y0âpý÷%iÆÎß ,öpi¶æw\¢x$†X.QV d’íÏ“ÒÌ3(ÙÔîŽÈÂ]Âu­¤ÄþUÓ)‚í"¼ü¾I§Dendstream endobj 1920 0 obj 2985 endobj 1924 0 obj <> stream xœí[Yo]·.’·ûÒ¿pà‡âÞÀ—æ¾´èƒeˉ GÞTmªv@Ò•µÄqÛü‹þày¸ ÏáQ$YN\ r8óÍÊ›w%¬£þŸøwçdöè5×´;¸˜Ñîkø÷`önÆÂ’.þÙ9éÖ¶Â2Ö9â4ײÛÚŸõ°Îpb˜sa”P œÌ¾Ÿo-–‚p§„›.–ŠX뜘ï-–\r¢´šï†YG•ô³Œh-aøÅ‚ÇåóÓòÕт¡Jq6¿,C4»*ká3.$1JàÙ}®"L§³ ·Ëp§ Xzè—jb©Ž,† ÐZÄÂv¼Žó‹… J9)1ý|±”d+æWe«æVq5é#¦zq Jãþiv…—†k™´• †%yý¨L^ø¥ŽXŠ(§—¥YIrb4{š6øaë/U„3åA»­]€D‘¦ºâk7sÀz@0¦æ4Oº<"p>qÒR´ÕŸ:€¥=ã±ñC¥p KŒî–ÌØÁökž.–”JˆÑˆTu\i=Íö¢TN»1B$wºR¸J¨fmŒ"X lGI·ü-€é”¯­Ö‚öjá•·€o-eÝ’³äŸÝ@S—~H™Nº|æÝƒ`TF}¯Ìü½÷·¾°TÏÊð&¾£€ k%åÝÖóÙÖW!Új¾ý™¡ÓJSÌr"¸œVeÜ i6 9iœ)—®T‹Qˆø~¿DqêñÒ  í…X `÷ |”qÑ”»T•Õ~ÇÆ <˜`‘å<À®¡†ƒ+oƒ¶½ð \Ëaç½*;$Ó¤vxp\Û_Ìrž0ÌT6ŠxûÓŒ•(S¿²©LÆA#Ù¾î$”Š‚ ' µFµ°ó=ä¬d‘ðv„âÀN‹ñ¶b5áØ3*XlÔüeÆ1bäÆœö(j‡—Îcø€4@Áç?å•—^ßÜ2ŸÿÀã :))«÷'VŽŒ4Ü)æ¡?_€Gdó/CÞ ™ì½§ÆxwÀ,C«Žt1¦"ˆ„!:ëÄÏ:ìxY®oÍ^ÍÞu¢Ï‰€b;iµ¿a§¥3þ/$Sk³Gßv—çW{³GßulöèÿŸµ—OàÏÆÓîw³õîÕmS, , åüA ï>Å*’jK2HZh>´`þvÚK/ºkL/›^Ž"ž§ÿ£‰ÚJ¾iƒÃ²°[f‡2|wJ¬Š×(g¬Á˜@Ìñú 0$>?òq;Œ¤eqÎŽ2…pà(ù8“Wyî}=ËÔã ¢¯3ùª½”ÕÕ-fÖ‚- #±– àÐ^1¿§:ö½´ó½¸ìœOKÿuMÂ*ÜYBNêlà+’; _ìUνê°UÕÚbŽX(Îö³mÓGç Ýú$¡¥¾´lKßÉÃ…A|‘»ƒ*rµ”ÄŽ\ˆŠ`¬r‰‰'#¦} ìC(“èÐlüä²8Q¤òq¿q„žW„&¯ÉuoZ&ˆ.€œØÎ¢Ï78ÑÙI–KÕ-Ì™‰Î32á¦$Ð¥K‘o:*.Ãÿ,\×%%·€uÁ¡< ½@ã°yDø)Ž+þ†;â—·Ò®YÑgû CŒãÆa¾Û¾émÔ%5UÑËTn\cgð—휫>kíÀz5Ý1‹Bí½B(íÓÓŒ•—è­>8 ÂS¼8dŽ×¤8ä #Œ™s ²ç‹Úœ!ŽñpÉC&U“ó#ª‰÷¹¨ÿ82~ pv9ŸÚa…—µÓ©LI£‚Â-õ†°Ý ö—‘U©ÃloÖZ†xêÙ‚:«†} ² úñjÔ¸/§àý™m¿ÁÝ¡h—d,U'õwTbø6Þ,ô¶A¤x…°g¶ïf†Q§>£Ä*pïù PoÀ•ÚIÚCYczGÉ'×¥EÄCj¢v/µ¯ë!ÖxÙ›ìÖ©«¸0™Ði–¸èõ6Hu=c¦JnV™ÝûÈm&œF€ºZ<,ÇölRBúYÅ®ôÖ¹]^º¾Ì± …þƒþ‰oý|Ö[w3WV€5+"\ëmæÙ­|ìzyQý+õD[!Òv’Á¹ú>ÚÂÃÔ?VÌ\º çX4?[0f@¤rþ¸oŠÆòÍ&Xç^ ú×`†Ó˜õ— ËÀI ß+ñ½TN¦(b¤(þqÑÓkG3×.N§à0ÚoÂ7é< ëü³ñÇwžŸ z-ž|ÚøxïZêFƒºvî|âfÝèvƒoçš&^îôíµhK­!Y`p«_L/ä73Ã{ ¬eêÕ æG2’vG`ÍÍ%¿!‘—–Çî¥1#¶oyž¦NcÃ_•U«²ëÅøËí4u^ ØÓ<Ê À ‰øŽÔG¸ñ–l/Þ¢Jÿ>&@„5¯¾;fòltõÄš:œßúÜÜ9.€Í×nî2J‚P›x±ªVÏ·ô†×¯¥–wòžñ×FW·t„7ç–Æý·ƒîoÝÞH·ù{鯧¹§XšÚúœ7¥Ùx3ÊP;(bý-ÖÚܾæû9f1È?ˆi²v8óqšj€ï¼(z `_Eýäˆú¡Þ.›™§eÖNÆß­êåaƒì;ó3ÆÐÇFc÷US¨,†ñ¿"Íc¸Wny>>â¬!¼Úc… ÃXö¹ÙÝ”(…ß—NûxÂBK){Ž,–in³>‘…")N­¥ÁÕÈÑ<ˆrb¨È·îè]?•ºŽÇßæÐ{0–g --áÝ¿îY(Óںό±ðõjjüjX«¾­|@Æ"~Ue4<Ä΄`<ídB08Ì)w_ oõ|Yÿÿ|=•ùò»?_çBø·z¾þø$éOÕøÂ÷ó^½ÓÄB­½ºZhTNƒ×lþ©²™tù·ð·{Èö†Ó·PosÐöñ¿í•ÕoŽQu7¶GB u®´ü¬¹ô« +[=POþª½:ÜdÓ¦›®qAóGÇû­ÉæJt*j¿ºÆ±) …ºiS€Qs?M›:Ë× ïÖyêyãÛStp¡ÆZí¡a†ßìL;ÒF˜Ë1ómAœ×Sƒ2¸ŠŠm^.b9DÍÝpé1l7DV˜-ç°áSZ!g¢Á%$ä`9,ãä$»Ö’„¡þB™áo\®#”!–¼¶!S`mF~«+§"WCަJÉÏú·rŸÐ~²4†9 N1‡¿þ4fhHåLc†mOû>MýÐND&AÌõ¿Ñ„1—~aÅó{‡,bƒÿ/ˆÐ!~5û/‹Òfendstream endobj 1925 0 obj 2971 endobj 1929 0 obj <> stream xœÍZëo·ÚoúÒáÅžá£ù&·A $uФqcW8-#Pîô0ª‡#(Eþ÷wÉáp—{w’U§Œ£ùçñ›ár~œq&f<üÅßÕÅÁ“Ciùìôæ€Ïþ ÿN~<Ý”YüY]̾XÂ4cõ¬e­•ð»<9àÌ›~Ú¬µÐÍåÌ Î8 ^¼jþ3×Ì+côëåߤ‚É0}!äl¹†Ñ?v£Ú‹æ¦kÑæ ö­±%p”c_‹­k=ƾl}£Gƒ¡u„£+ì;ÃÖå$WÎË‹–)ÙjÕ<Ž}áB0ïZ7[>;X>zÕ|‹ _"±g؇­°r1’ϯIzͧiq˜t%¨Ä@Ö¦}¯å|¡pé<la˜÷m«@R°gFúæ|Îa•1RÀ)±y3W̘VëfS­Šæ*8^m˜° Ì…f`<ªy—‡ Q²Yÿ677UÈÜ˾éáŠÕV2.\s²1R·61ûýwýþF³ ø+ï·o…0ãí»Uyêež *—Ò€4 ÎB0k° L/V-™Ñ-4¥dZѼŸ Ï$‘E„ÁÌu·ÊS®Žsï:ÈR3 ¼^†]-s¾ËºÞ3$[•Àõ¼wIÇ,ØNgnkº"my¶TLð(}Ëm!¾ã|¦U^Eù»¹`­\· Šd­6Æõ¦½_¬ô,÷!:È;ô®sô® Ïqô-öm°õG¯ˆë/¬’̃w?z”ºÚƒ…<Ϲ>Ф±W©ë5pç ƒ“7ŸQì‘ v&p°Ésñà»Ï±†’S~Lq0ðÿÛ3'§™»¦§¸ð!ÀnÀÍ•ÝØ÷æVÖPwÝÔb@ô\#,%p‚<cXËmóÓ|Á™m„¦ÈžõpåarÙKÏQ”„‰|œ b›`º" Û‡®Æ4“@óº n×s4¨MwXÑ2gusxj¥±ŠN%\壬wÀüQDi!šïšR2èÄÏ´3l h­htéý4¡º“öŠõRÖ©gÄ&$ëL‰=m'dUc…luZÓU Êp¾)„+bßÍ;Qš–û{„#OûÅš…åšéV¼Î3D¬Ðâ8ÚÆ`#u„óˆˆ×[A=&‹Oð£È‹—÷®+h·© åjÐZç‘?¥Hr|\I¬×•Ñœl?ŽdL\ìßYuq/J2²]Wù@)Ü5Î}8/ó¸a!ë²¶Í{el¿í×î§FãÚEe·ûÐk9‡8f8Ü¿n^Òó(ïäðKÛ]a!< :$Du-Fÿ+QwÀY¶£”Ö´t±y]Rq.¦”¢¿õLºzÞ03õÄ’h¡µÒZ¿=䓞nÑÂ.È6tßmÚàsXñ~´ï0¡z`a±5¤Î‘ðE3Twh­ptQqžçƒV=LÉ€"Y} fcÂM¢,ÿmÈû}袣8:_—ðÅØ•¦‚FP¸÷ñÎL¬Tù}®·©ïº"¾“BV\¸¸Õ„6„^¼ÆW¶†.'eWatØ… ¿ݤÃS©áÞ±<쇈4§o·âS¾á_ïµrJáZôÙΩÅõ7|ôüá÷Ù©¬| „m(u÷G¸Ć(Y—ÂË1òg)£³TŒmœh†¯,"t«óüŒÅ´^z'cËíUa&/©÷+%¹d¢zþ¯ÆAVÒl4üÝçrLa“%x;¦±Éy\E¾ã(ñ¦&¯ÑØ/#½¬© :°£¼ç‹þ#qǘ1†ìô9\¡x:iÌ`Ný0Ø092úˆj»³›¦˜·¾›V’}ü²PÍé‘éä»}NtŸîï*{½_ÊýÛxÎøKäðÉ“Ú[)Ý^-»„ãmJº'¥@::=}^N ËJ]˜j1 ‡q¦8|%Ý ‚ó òÿ‘NwÅȨ†u)×B G”j7{(Ϲ·n«BO›²ö´éÝLÀõœÇý?ôoG¼ä=ˆ†&X±°ó ôYž0YÜbD¸ß·¶%½‹†Ú·iÒë\d%Mȯj—£ñøìØWq(0nœp+>lzBÔv¸Àn™rÈwx?œª‰ÉpÈ7™@„õC~Í»ÎoiäŽôÞ¦Í:?3L…G´èlÓº ¯ž\‚7æ—ã—¤Mtø,Ô"ùðŸJŒ)FžÉaˆèòª:­ ャîS"å,㎾8+²-“êŽêH¯ ,|´×L •DÊ=ΊÇii- *ø:opY3ú‹m½‰œð—¬dÂâÓ ǹ·ç›êyVwy6î¿$‚Ì|rðúŽ«Æ·³z*˜ºL ]÷%¢¦ÌUVØiýYòÕ⬄þØNÈÎØ¥ã@"ª)§#ÑŽÔ  #(´,ÈÕ]>¼[Ëq¹Dav«¡Z%d6TC™%ïõÉæeÅkº õ’Ž®×q-e¤Ûü<÷n3ªn.ò¯Ðà zgÈ*»mµp°îá È„T^ÐÊæ÷ˆÙW}D5ZàB€zW j8ZÔ²ªA1©È‹ç~ÂÕH…F,oð\í[Þ t®Ôíƒ~(oøs¡Í ƒÈyLÿ!擊¼ËLÕFt¹Œú /Ÿ¦V™Äý?0ž]Žº:ãáë¹Bì]Uò¨raÞX~XÖ †ÖëœVçG«½kíKÖâh~dru²ƒûÚG-Æ–­µC– Ѷ²w2‰€¤3¤zš4}¹<øüýÎÿendstream endobj 1930 0 obj 2502 endobj 1934 0 obj <> stream xœ½\YoÇœ7þŠ}ó®aŽú>8Hdɱc~°ò@qy¤H‰"%ëw$?8U}V÷ôìÒŠ6==}V}õÕ1~³b_1ü'ý=yuðè°ÕùÛ¶ú+ü{~ðæ€‡.«ôçäÕêñv³j%ØdŒ0«£³ƒ8_Y±2ÂOF­Ž^ü´þzÃ'§ë‹Í!Ÿ´d\¬7lÒJ;ÇׯkëtõÆÀ¯Ó˜ŒÊ®o7‡B‹És¹Öå¥ý-ϯ&ë,Çùµž”ônuôÝÁÑ?­Ø²É*nŒ[_§ßJˆõ L"µp‡†Ÿ^Xœù&›¼rë'0‹ÑÆ\—jýnÃùĤsÐÞ‘‚¯¯`L3îÒR ÜL™ô $™¾¼dyY v¸Ãf¦Ói?†¯<€À£ƒýØI9Æó~¾Þ¨I åÍú~s¨'ç¼[P\Wþ¥½IÓ£¹Áér×;XŽ7JÀWá§Ö°‰­&)5_¹9”LM ¸«Ï/ê?×Ö·p\ÞNÚ˜õIŒô=Ž­°g<’v a²Æ[œXOÒén É@Š`kdÜöµ´õS\ œªÉÓâãü>ÇFÉÈ Ïkq6d–Óµ¦Í.Z2ÂåóüðÖMøå9×ô ·µõ´Žu»ô0ÁJ- ÅøúY\4×x°,1q˜à} Ætþ¹.ŒLq; †“pðÌ4«yµAJ‚mAëÈB¶eùÇu{ðÌ [Þ4v%#^—·î†GEÖyÇòùRpdgÃÖqß:o{ù9ŠžÓ“fº[-,ebE C+襛OX8n“á žª%nn>k+ób+9»VŒƒ”xžž¤@À"+q^@¶ÉÁæR2+·ÆÕX.R˹~nVÞ^”7EQ¹ˆRåÝ3­¨0ü8¯Èè×µ[ùIZª[U¶ÏnrÜSEot3¿U•ÜüMÝØó”ª1H»öJÍä¾›¨vu“ÂM\éõSø9lZ7Z³°ù(`úø¾bADóA€oGxPåöó,ráî…D×bA؉>]õz~~ÈK5d‚Ó¡bä])I5V(,›œ‘ë—d€ˆ O,#ÆÞžË ¶žãP2NWPÑ“@ž¦áXdr¯3Ó’¡v)N€7\6¶>Š7/µ¦€Ð™0¼O@„®ÕJ°»nac}%fj´xÆ~·ø/§Y$—(íët½ÒµSd¤y·17xJã÷ɽ.1ÁžâD¢D99䬷Q\r¤ üÌppŒ VÀâL’¼Ð÷¸Sípñä¨Oð ÎNaªUÞV Z.Pa€œó"t5‚¨Q&”fTP9 8g¸> '¶ñ šzùÜ ¤Í¤ƒëÐcY¡$\ØMÅÉëÔ\áMi¼EŒÚåˆùDò⃚[imñÊŒpï…€+·p,Y“g•bâ18à´pâêå’sºÏÀE¿¥lÆà9åóð…~ôd³½’8èH‰TF¸D…u“qj>¶ªµOâ¬íþ*$À^€8K¹DäZ>VëÀ?gGr¦è×k¾m˜b˜@ñFúƒæ{—4_V»Ù™“:&QüW8¼Ú,/‚º_¢Àqà8jÌŸ“5ÑàÅñbM]j>\J9¿™á BaÇæ£®³ºK¹îÀ«6yúo7‡†`Ú €Aµkÿ—Úú$ÞWV/ë@g2÷rt/ÇC@¸ÛE5ÉD×QwŒŸ„lXç»Ú¡ž4kÐ]]ÿ¸qH³¤¤øþùFI¸EçZøªÕ²ÖmAOÅp^²Ò—Cw‡ÌO¤¨µRg¼2ÑVŸ£>¹¹£™íI°ÊS;´¨ x~£_U¿Wˆð¼Ý`˜ßqbNˆ5ªÂ@öO6HÁ ½8² óø:FàNC£°À‹S—ZòñIÁ- ð¤ÐúsŒó{«Œü]Æ5ÙÇ’ sîÉUŠ$u —㺤ñXÄc¯nq˜ h×çSôÝ•™Ê´3á¼6”s7‘hðw´v7LXEqAì;me2©¾Ù0§·­—!—&'«£p^Ï ëY<ø9>°Ô˜¶Ä6‘ûò§2ÍûH¡Ä ±=&±FòÚ¸/º×ÌOÈŽÇѾ&¤½‡ t+‡ÇpæØÛoÌ}ôÜ£À´Öô³‚/  ’#}µc[ ‘}ÜY”>Õž”ÌÔ²Ò6QGêF€AšEt¢ÃgjŒ…KȲNèû£ }ëó'¹?ë`©„]PZ)Ð×Äñ1£€°»QHÛ³û2ù#˜"@m¼š«½×­Z€Át¾”¶\WW|olŽ¡ônʲìU¥aãùÎR]Æz¦Š] 6[§é¢'šáÓî\aͤà‘] êøFþérÆÜ)“JÍ0*ø<ÏZÖÞ¦»cŠÒ¯ÿIBuOÈï<ã4ãÐ n†£&ešq´å[pvvR15Y¢Cž¸íÑè(í[…¥”BŠp?‹ñ6) ^Ï2zJ«Šü¯õµûA‡ìcV½ƒ#]¤,»¼¼¼þF;0Èm¥ #5Eƒ ÿÞ®mÚ¾¡4ä'84‚3lô“2| .dü½Y«&Ês ‚ð“J †•tdÌ&§YH?­u%ÇCå¿Hñ.?ñNHŒvß`}V£îu©g?¢24¤ý¦øÿC†“$¬©¦É·:ÒšA*"L* =—Ù‡eÏÌ/•+©†Q‰”2ŠljÊ êçÜåÆPKSÙB½úS1Hê ߯"E1”üºÈ^uV×ÓÇ/s‘ÈBD3Aª’z^ïñ)A•;7eA•h)ÖWHŒA•;3i+ª‚aŽA| Tå8‘°ƒ²À´ƒ!)ØUÝùàâ¶°om:ÞÓÚý¹g^'¾„wn,¸…â8ìê‡Àf¢ß§'Vr¶ÿï]áRµé w@Û†EP(šÖN9[Ästò wKÜz Cž¾uÞø¹&wI,’FVãX;ÈjG,ÌT2éØ »€ù„„ ÈŒ}Äy45–ü>hèܾC ›,Ów —Þ¾N3ºû]¼_• ~° !Ú*–Õ3=/ø[ƒYWµ,dfÍsÝ2âMÝò¢T梄†Dź1÷rýFÚþ%ñðH¡Cê¸;(µÍA©aaÙL,:?°‘Šè§HѲÎÈÙ\WNÖ9ç­÷8ŒÏŒ%„A/B¹ÞƒŠ„q…m0k\ªkœ6MÍBª°Ú¸¥Ù¤íxWõ—ªÇúC±¦‚–H@e^z˜ENá—á=Ž ‡¼¬¨uU[ ãLÄ8+‰ƒ†ÀD1vžîý´G4‘shÍ‘s O [CšZ‡Üsì   oˆlpd `5~æõ:ÆØ…IOe¤Þ8¦2¨kh^B"(¿×Šp<ÿ,¦ïÜö]áù8ý¬&IÒÏßž•Ð3C9 $QÑ_êóã †5G´XÏ–a ãñÌÝsT¥Ž*ÜÔ¯ÌÐm—n¦)½#h9Óˆ,W¹C…¶yð^¸~/ò[¸G­Õ—]Èæ~„/ó˜ט‘äÜŸ>Ô óØ\(JÉî«)îëu ô“ù3ôëп+f¾+¶)Sô”ëðÉðë—a Ñõ¨'Ž$,4Ë6F<üŽ!®Y×ì…^S%Y—™޵_ë¥hÚ¡JEsuÙÓÜÆÄr ¬M.G°T ·ÓU5ªºªäŠR½é(#ûM¤ÃåÜÖt_(Te_*ÙŠVgbf4&lµV%c \èź´¾îò²˜þSi»+m'¥­¾qQž~UÚ¾d›ïKÛU÷ Ÿ¾ØäFܸ»À×DGIoËzOk«ãß–¶š‹þ#~1©Œ_ƒ‚ǽòH÷ào8¼F VŒ˜kRLìÉ›®Ù|á+8xf—;;,5d”sG)b}.€)«"FdSay– ™tâ%Ï…‡þôèàûƒ7+¿U‡Uº¬¿¥†ãÆÑñ÷ÇÏ=ûûêîöþôàÑ+~ðè[üÏãç_ßgOV¿;xúlõýò—ï µ,|öÞÜêï ÿŸyÉ Ù³ Bóè» Æ;û.x\r=û6£\ÎÐ.!~œöE„âló%a¼q³ïKÊmzY7é›jÌæå-]ˆù29âBS9ûhk†!"×Ðú’‚ë}æ}D{%ûjŠâ£e7]RË´Ÿ÷ý':ô²¸y …aKøžm`®Y§±ÚÓ±m"¹C,r²1V„ÇŽS°•Ð"¡ÅGà¶3|"QÎ÷­ù£à73³j&¢4õ6 ¤r­EpM¾Ú¨êfŸ¦\Ò#Ú eVaq‘S¿1”ñPðæ²/jÐaßÿ3 *Åü3Ì.Ô×§ürÂ…¤ü\€C/›"Ó¢L¤ê@>7–£ûþà¿éÉ…endstream endobj 1935 0 obj 4377 endobj 1939 0 obj <> stream xœíÛn·ð£¾â¼uOÑÃò~é[‚ØqŠIc9}pò ëèË’r,ÙÖßw†ËËp—+[íº@!Z Éápî3äŸ+ÎÄŠãOú{øzïï¿HËW'oöøê{ø=ÙûsOÄ)«ôçðõêÛ}œæôJŒ‘«ýã½X9¹r‚3®Wû¯÷^ f½Ì;#ÂÀÖ΂rJr ‚a&èá;„:ε‘ÃÑZ2e¸®×‚9+•A:h?–¯:z¶Þ( 5\Ži뇋õFp3üŒP û»á¼Î½Y+$Dê᤮"¸.Êø@Å´•^ü¾ÿÏÈ1± ,Xi5²Bj 7øÕþ{û}1|»ÖÌHìp€x­ÕQ(fà¤v€ó[ࢀÃÄq#š©çq‚<äO ¸n×¶‘Πä7G\pr€ùÄ„üù çzæÛu³k„‚(¤Ð‹:÷h "UÞ…á}ÅE¯§¹®@2~QW$¬†’uS? ‚« B˜<Á»H«fÃ^W8ž[q'ÈÌ“º¼%EjË\ù¬*ʶÌݦ ¾ÈCÆ WkË„10~[ÎrV @­é,z™¦Ê(Zi-â…mQ¤VLY°žý-X è6(— ~x‡k³Ê·øËYŽFúpÂëQ»½ó÷:ÖiÐ_vRØy„$3:Я7šþ•ç $„pBíé’<Ú½âgT(«„Dÿ ¤gÌöG´E¼.æ1Ùðc·V`ÂVÊj éŠ^ÅÛfî_ÖŽ9ç¹§ösžÄãÛJQƒ‘‹NHŸt.B_#?‚Úéä•\ý&É~#ä(ýL¢vZ­bb¬hà;çÌåFç}qîÈFnGéÃ0Ád‘ñ"± £Ä4¬š£œšzkÊù=¢4L AIÝ‘ ¡óóU&9Ï6Ž(à¹ç";ÏûÄUãÇO£´Ä­×qU`t8˜êKÄËe>â÷DäGÕí_Ì$ŠÐÊÒY„HjÛÊH& •Þ(|ðRïp"6ÛGºdtÍøF) ËÃ$4ÝÌTÖŸUB/ ð bRÀŒ@BÊéÔüêöHvKU`PBK²ÓeªÆM×M[/­ÀWH.)ô”ú@dHrxY€Ôë tLàhò%”·(‡»g"Ñ"0n){wcd@©éêéÿ¨ÄU·}Hâ(0÷]õÐÄÅ//ïi‚åúSÛh™&Ä™ö ,0-šzDâS WÒ ÍÈ0YôG7v#x Ë  uÿ^{ˆÇBEç¤,X1— *'0íM—°vÙ€jîm™0†…Qð%,Ìð|v\tmÞÖúí˜:NR0p³Nêãç¶ 2[!Å!‘õtfɦÜBäh²t8ho׃‘ñ&®uùB&¼ì:²ÁìS~/&”Ò±À1°«îú³ÆS¤©D´5ܦ gŒ#A¼1…ä ΨZ!¤ §@¿R8³^º1ž9°]9<‡2Çj%Fïa`LòÄGbRÃ!%ñ×¶Ì“˜É\ž¬c/Œ®«ÏóGL8Ã0ôd Á\û‘%™´]Dî·˜å(j—±qü? d¸¦õ€Ç¤*zN¢^_c!aŠë&{Èilñ\øét?Ñ 6sIüjñ†[v0{ÁX4 ;Ô4ڨ׆lP]ƒ"9Û˹m¸ÆªÕ¯y‚©Dã_¶•“¢#æü„«²«ž„CRŸT×N‚X<¢rbf“„C\žI_ŒúoHNê¶óTƒZ îaŒ}«´üUÝjl‹âTŽ)%骭TŠÏ¨<¾îw»(£*J¦,LÜ&>ᨇޭ!åUF,¿W™ÛYpqÂm×)yÚdÛ.1­lª¯ŠI0q{¸žÐ7­¹Že¯˜5bºJ2Ó¤­µXïxoˆÚ«~¡6±þÓÚ7¬wLdËí•ðñ±Q] •ÂÈ«]vBIÆøuXDr9"¶Iî±a™‡oËðQÎ ‚Ñr4¤+J€ ›š–Œ&–@GùãMk}Ńˆ=ïXM5ó“ 58zšlêAÔϪЪ´Ì ¨.¤SL$iзs sŽ“Ü;ÒE¼¼#]ÄÄ~¡7~¿’5Ö8j±áŽýþQ'ú‰ñdS¦…6©SiùÊÀZQÞ6WjyÛgÓÌyÒT#•SSÛe ˆö9)k·–,›åæ©6ËÕiÌzœHÌAwUÓÅI{>k,I9“¹ Ýo£À n¶PD:04)S/ºSGµñ&ÌO‚‹ŠÖˆ…‚´QÙÖ€“[OdÀìÞ ÝC”^Éæ¾¬œ¦Áj^ðk wzK·s…²~{·_5/^FîÔÊ—¼éÓòtWถ²sï^u"Þê]wçþ^¼©p†Iêæœ¢–\7+sëªÖº¯ºn䪊‹Xo·I”ïîýÐo“{_2`Þ¢çvtä©6ý— äšs¹°O…÷iדÜôüÛìITË X¢òÙêæJŸÜ&h÷¨å&6ê¦í¢ûÚ‡ºÁEˆO/xæ!¾ÏN¼1l»Ý4ƧNéÓþ뎃Ù: }‚ÿQ\þÇfóRØ1yüµäÄåë¼$³74/Ç´–q zš×:s)¡NÝ…ýy.|5Í…s©¼)M¿é¦ X†-n˜>“Ä’_ѱNq/9wXÛ>¼¼vnÞ pŽtZ3èUËpZ´¥“û|ôýaµ¨ÏmPèÇyôíDלKû;W ÉN;Í…=½†ÚÕˆ¯ó ¹¹QÕ6Ží E”£ñò¥sÕü)ú4Ÿã°¢~2ð×ù‚ݬNT:—ÜJÄZH“öÛšªÂ“Ì×Τ»4a#¤P ô/ÁÁ‰›ªÌ¤lýlÌ,ìz?sOõ€Ó®`ãé®[PiÞÝS„œ1,.gµ˜C@ÌÑ׆á~üîdþfRÕ—`$)=­›»W|“Û}œªéåÕ¬¨!ÉÛä9ˬ)”Sa+˜Öw¤Yé-YÕ¯¬Iž5¹åŽL ’M~ÛA{Z«Ð*„ãñ¡1ÈùƒtD‚;fµ`%9©í÷,ÀV ªJõ%l*Û\??¤ÙgçñÀ¶›{Nz ©Šþ$IñØV ͆ÜdŸ*)Ž/û¤8ŠÙ7šL”£¾Ð&«ˆÕ׃OŒÈ$ô%ËU6A?é’4á°®“õ!Üâ“ç\6Ïfñq‚Õ–>N(ª¢ç’j[¨äÜÔ1¤êE‚²”¡yX{Ïש®|J‘ɳ崲˵±j=åøÀAB(mÊŸˆ.> stream xœåZÛn7ú¨¯Ð[w ,Cï@Q E‚¢EZ¤­Ú—¤@É‘ _c;ò÷Ù]^vE«¶$;6‚ 0Ã%‡sæFΉ?L9SNúŸó“ɳ?Àðéòr§?áßåäÃD´K¦ýùÉôÇ-³j*óZÃtö~Ò S S+8ãj:;™¼©tÝæ¬¾buÙ—VªJg¡n¼×L{UýE³–s¥¡:­%-UÖDÉÞËê›8¹_“šëj§P`NW¯kǬòZV{ݑʸjvÕ·!:!Ê+W]Õ‚YÒü3ûQj£¦×þD”…ö@=0p\LÓ̸íe­˜“Z“VatÚŽP@ÿU9QŹ‹º1UmÑ…Ï 4ç–S©ºÑž3)mõ®ýnmõ9.¼ SûaÏ õzæÕdöÝ›L둊¤Äi&°1Â!ž‘6FXÆÅ–Ú ýÉ`«”ì—ÖÍG6¥Q²ø"Î]¢£Èûb&=‰s‡ý/ Ñ1FL£yü:FÜ9+ím¤1š!Ì]ºí8‚=,„øÑH*Í¥“Î38S •ƒ]¹ãaê‡~ЕX0"/±é"aVx?ÕÎ`˜tõõ9v¤f¸!kö):ƒ”î…Ão£<÷xEàí$§´ÄÚ¹ ¨"Ä¥tKàMeŒÄk‚.«MwMtKçixT&´îЇIôpɬSý©x¶…P`í>Oga™W8Ç%&-Š2÷_µn÷g ögIâ¬@;  Õ'n¼7Rçû®Òð ¦u.¢Gf¤ Èh6[,êŒu¶?Br+V Úk†+½š *o– î·?Šy¬çiv¤àVAÒ÷,؇‘V•­§ÙlÁǤã%>Ú4¦ä‡-Bf¶b;3ÙÎa šqé]]fd¤] hÍð¢hè&³Þva/>` e'R¶Prg%%ËU`^)ß¾y[ €$ã[Mqè$ß¶2q%×T&‡Þ¼29‡˜!+<ûÅýg1 ³ä[ÄIŠb#˜R¶°ÉÇD¦¥™™2U³<;íQÉ›Rz,«ý,#²ìв ¼­´7ˆ=&úŒK-§#2Üïi¿¤×ÿ͉ÚËß´<€5Œ;JŒ®:á3Ô„òt0–9Ú“‰_É ÎC’®€QQ¯èNÍ¥£‰õeF¦ûŠ‚!Sõ¶J“]Xj§ – a–ܯÔ•®^dwÍ rŒcˆfßÖÁEÃgwÈ"„ƒvlÎ4è-Š^¯ðq[,4yu*ȾÑcëE_*ú(å:VJ¥vÔ`Ò¶!›éµš•4\ÆHé‹—ÖáÝ5là%ú6<¦ïÒµËÝwí?“¦Ê¦ì‹þµ£¤¨þÄi —øzDŸJzÌ:ªÜ*ïß»s]û¾c'¯ð…êqvòÛöÎ÷ÐÎoÑ oÒÉ7]Éä—6äÃ4ñÂ;›a¡Ý‘‹R8§®}YÀYj#?ŽÐÑWjÆÈadYànëÈ"…—kóo¿ ÒÞHüjvޛ£ ºGc§øJQšZú„ì2~=£‹´F¼@øÎâk&~(Á»\«×ûµ5vëL_ªÂ顃Ø(쨹ùw˜Æ5“?÷·„ÇaKÔlˆ ã0E> ÇžØAñêݰBWÇ·®»°V«Dd¥¸¾,˜/|œF·‹ŽUUl 7fûY}ÌêNÑ á¥p^ðÆE÷³²”#'ñëy/þyÌ¥ÏÉÌp YGÛ쯋BÅNéž´añ*½ð}?&†ÿ@-Bä–ào* gØi®ôÐ9N|¸¸›F!"[bcœa'Y®…ã÷F6QÊï3V·,¥¼‰ž…"pÇ…Ìnr2ù.žt\ðTòÊQ–¨Y…>É69ý9n0Ë`×yì†>R†Y«¨“êéŸmL”tÌ[ˆZeÝ*Q»Âƒ5ÿ!ÆM61DBßЋ.K½èPq@Õ€¨˜È’çÔ9`fkšž€è¹èë(T,Å,ø»ñÏ¥¾úSFPd¼S™ûLdRâezkùêïLÒ«¤Öólú7\«%3R ù¸7–ò_©–èq‡¸[ ÉJ¦¬R&6¸6Òc-ù`À§æ,ÝÒ¸uÐà¿ÅqÓ‘‹;þÇ¿z¼:Æ3td.ð5gÐÆ&þVÁmIê7<za}¿9³ Âq&I»öãy†+äÿ×È5|¥,Ã- ŃÛ5òÁ5ÜØsƒwL›)6…ôËÝCb§£Sû#Â$‰{9›üŽþ ‡›Kendstream endobj 1945 0 obj 1960 endobj 1949 0 obj <> stream xœåZËrܸMyÙ›ü³ ;U„ð~,ãŒ+QjfâI”Éb& Y’e×èeIVÊ?’ï͹ €l¶^ÝòXq¹ì†Aðâ>Î.ñ¡áL4œþ¤ßƒÓÅÎߥåÍñÕ‚7ÆßãŇ…ˆCšôspÚ¼ÜÃ0cuX°¿{oœyÓk‚dÒsÑ8ÁÇÃÓÅOíû¥f^£ÛÓܺˆ-h÷cK{Ñä¾ëe'82׊eggJ¹öM|î\û)¿r=t¥Æ¿÷þº²Ùûv±÷‡ŸÒ4ßInçY²˜_rßQî;$¤æÌ°²ýM`“<Å•Ô!ôÀþuÑ{¿˜^‚p\,¨Z¹¦ e4kÐÆ pwº˜oÜ; |+ÛtJ3î‚ëµ64©w€ad+|¡t«f{160¬m$”Q4@jh¹&½ÈGKøÂp ]´6¬EZ$ÓVÎÃÚÐJDi„hf¤Axn–ž<«E/N‡¸.IžïÉIšÀ°0ÚŸ[8ÜY©,BgmQárh\õórpD¯´á!b„ÌÖ6.zÒ@–žŸ—ƒäÞ½w3®%Ú#6¹ÊTw”[g™à®2o"˜¬‚‡¢S+þ œ;`¤Õã¿2éN<\¹™(GÓŸU¢:+<ƒýc=¬pŒ‹_Câ®2î`âBjC_‡°ü›é‹Åä)®)•=\õÓÜ÷~FõËL'婱)8I736§ì‚Þ²m8ž±s¿Ú, }'Öõ ½³è‘jŒ)'¹ßS£Hn½îÇ·®¼£íö'3­®Ë§Óýs¸¼ ¬`õf‚Kj]å§ï'~èñÖ)« qC”‘±3[ÂbØÕ­½½uEMcy‹5Ö &¼GUK°\ð[e‹lãå$Èã}9£q ò§”Ô‡+¹-ô]`B®™Æs._MA7æ©#J\›²ïZ}g}5ã³âåéºB8XUl eŸçÖÇŠlf]9l .fùiÕîËÊ9ÍO/’hl`k •ÇÅÍðR1ì>åvpv8CÓe¹mXN¥Oa|bÈéf¢ßBTÆcê±ÜÐø»iá|ÆsgåÓÚ™áØè”þ¨úÀ€Ë·•:«¯$¥£â£•Û¤x1ŽÔ¯WÁ(ñ™^´éɯ_%ØžL˜Ž¿™ðeŽÇ¶q+G‹›•ÙÏŠrï'~87=Ñ¢ÚϭÙ5=—ŽK¨6Réβ“2ŽÉ­–$$ßRtB˜q‚`͉+æy<^b\ :‹†Q¡è2?¾Âéܘ u]·¨JNtÀЫ?d½8dwR!µ€‡÷§bùøÑΤZV¬œO &“ÒIUU:Ló³¾”%ãVÝUÊÒEÒEîLJ[åAyÒ_æê[Ué'µ$ÔE­wYìû¾àdU(SÁ©’ÿnpæhÖó″ªæ5WpªÊgg AÜÕÊ®Ô×b³(X <ˆÞÛ a^Û Gáje³3W–£÷¦e9äïV"NqèÍtBú´P¦*tEÔZ*.R5-Hltû·j¶ùââ¼°Õúdª`s”×(º4š ÛtÄóàýeì"^Ú1(ÍœºW¦êö ÎÃóTÖÔÊ t* C¼‘N9“ £L™F¿éX´ AûBÀ/Å7³ Õi9|Çÿn©RIϘ1BEC|ÓFõQÊÕÖ„v/Ö9L_QS€ãì¯ö?,>4P\™¾÷ׄïFqëè÷àtñrw±³û]s}ùñh±ó¯F,vþBÿ¼|ý'üì~Óüfñj·‰¢ðz”c|-‡jŽ‘³æ;yw&Y n,Kyê·9<³)Žšä/ž=–Qv^C'#‘Wà `uűU.¸¦±À¯Òt TrK}ÿ÷KÇœõr„Blu°öp’ 5Ž+ì“…R‚ÁúšõÎû^îý<ñ÷ ¡¥u Í,Dýw sy6÷ú›Üy2òÐð¼+ sJÍ Á&I“ÈF'ã…@ŽÖ­1à®tñ"Óv•N‹‡/KФ ]}z²É0ÕùÜ[‡)±!ù©0fL§ 쮵]cÀ»Ê…H[ ¶'-0¬ÍÀ  7úFf…®?žŒ“ÎàÕaVõæÇ·¢S×RFpd˜~“‰:…õ9"©rŸ¨õ°w"ÓÔSƦtÒ;µË»bòm hùj–;˜·Zåݰ̱;dœˆ2NðÜ0løîà ñëhpæ)0À¨{qÃðMôz”ãbšÅIc«KKÍ(å”çŒ+ö€õHIcUÓKéx`ýCvÏk?<Æ=§»ßwØè¶§ŒÜ ª¯¬is¹²Œ e¦Mu¢á*+^r°Âaiߘ~·‘nC¾îŒ ‘ù¶ƒñ…RˆjâÚöxÈû n„T_“Ò[£û{H§HñE] ꋼ4²ñå‡íß)õðçt‹ä+¸:2¾ƒñ¼îÈgyu䫺42¡¢ÿ÷û#ò]y‚K#b˜ÈicæK¸H²%Ãf.}•—IÆþo”ÜJŸû2ÉÚS§ žÎý›´×•ùŒfÊQ3wæÃÖ‹ÿåkÏendstream endobj 1950 0 obj 2385 endobj 1954 0 obj <> stream xœÍ[YoÇô¸/þ “§ìÙQßGˆ"ÙQ ÉvL'q(.Eâ%’’Ì?’ß›ªž>jfz¸%†ÌAOOuu_Ýû¡a-oþÿ]ÌžþCÖœÜÎXóü;™}˜ñ0¥‰Ž.šg0MÕøÖÞÍXët7­ñ¢ŽñÆrÖ2xy1û÷ül¡Z'µVó‹ütž€Àü0<)ÇçGyìn±4R´N¨ù»üú¼òÉÉbi·­”s¾XjÏàÉÎ߆÷ÖÎïóÄ»4tþsð÷ÍÁ«ÙÁïwd‘3˜ØÚVæ­³Þ¦åßæEÏóÓU^ê(ÓzŸÇŽóØ еz? 7^¸ÁõnA#ܵFË8ˆóë·yì˜èké”0­1sµc°Z|‡,"sŸ**«_æÎrá`s±Ïò¨*´è(¦ëÁúø´Êœ¬2Õ3±֤ª½XB?åÔyô>+Z˽oŒ­q÷ý¼X²Ö2Xס 4ìÆ{ƒï•g~þdÁ[/™’°Ü’ƒ¾4Çä©À«ôxuó—‹¥j$äü9’5Þ©ç?Á'[ÍÄü<¶Â+ë@g¦å–iNÉÀƒ$0¬”&d@^„wbnâªðú—y~ÿÏgÖµ”èM~}»6´W*îOkÁÁ“šÎâêÒz@(Ð þ²@ö= ==•À^$Êu‹t¶åÉJf)Ù“Á“ç\'þÈRÛ mÎ2ÕòýMÇ€eª7 èÞ#¼¢–•m1’PøØÕÂÜÃb›ÉÀÀÖ!†ç „îÇl;¿[ØÖ°p^¨B¦Þßrç©™ãÄÉ[Ø>…Õ«n”·Õ¸ÐA 3˜HÀL {—óÿæ™—.kŸ¿Íƒç= ¥÷Ëføè!Ô¥üèœÂÎRx ÜØ‰ ¬‹&uˆ£ â6뛸ÔUí«Uµ…úd0ƒP%‡Rfb§D„ˆ)ðØÓãM6,è—¢ÓeÙH?$%©& ©>É_¡Z¦„ˆ#¼¦øœvê§ãgde­ufÓ3Ü‘‰ £\™Û´(ÔeNªQ¶Õ0BV!%B¯’º@/ñòeró%ñ!ÂïÀõ†²z#l‚dìÎØ 8LÃÜfþ^P¾®b†œàQ]‹{ÕbÌ)ᴯGS™vz‹¸Ü7ò4z‚²ÝÙ^"K\¿¯­ Ñck47<‡>î°A…¼,ÚË n=ߎݨ@fÌA" “@,Y ÂPEYŒ¾Z2Qô1¢gµPÄäF`Ü¥9X% ëêaU’ ó]Ï©+ÛPÌáÞ¿ü6çQ\yDÅ÷…åë*:a(â Jí°+ê8Àê§*£%N˜…RìkˆÂü× ™|§P4ÀQ ßP¡Îñ¯b—Ê'â1Ú@¢$¨5¼)UÕIVI‘QÇø³~JŽ+'U¡uT'2Ž‹Ìx³a©ë‡²ÄÂX,¦´žæâZX½c2>YpáѵÁ¬jÀ}=l¶ßÂk“êu(›,Ö0-º—RlYµ‹¥ÇªÞ«ÜñRZ€•Kœ °!&S(Ä'y|¤•réUÂxd\¨›T«…†êõ×nIeЮ8(JHì:Á· jº®h†O ‚NÖ>¬}Uc…·¶•®´C¬¹Í=ÇãütIš´©XšÇ7¥•Þëz†}´=[³ƒÞháéÓ€Ï~ô.ökÝ€%i5ã{²$vç¦È¯Ì;ÈŸŠÄk Z…ïóWìÒÚ¸ok‰ÞNÓПÉéÏC(,ѶÇaWp˜baÚÛЗ2"¦Å±‚¤¤¯3"ð$¯¯ ¸^bgÏÒ‘w]¯Cö-Ž `ÓÒ¯óŠçe°Ä€ÂdµÌäºY†’%U°ßäì&æOµz—w¥1ÛËBRÊ&Î`‚û@^£½K>4Ñ¿-åZ¯jÕûõ=St'ĸïû¡É¦AÖIJˆú;Ü´ A¬¨‚lšØÔè,3µmºªA »=‘™­ú‹™@,+b“b™„¶Ì育[ëhç”#ˆÕÜ>DxšÒí£8ÚXA¾t›e)ˈ wK(áMVœ]ïbëš`jý´$/¦©7¬Òñ•'†ñ.ÉH¬ee—FÎàL um¶€Õ½ï:TP_˜ºA3¥ã˜Vàáp¯ñ£—š¤‘@¿}/ Îrè!è0ƵŠ:îÖ^½ËHàdÐ?Fe¹õ€QÇÙMï#ßÒÔ¥Þñ%¤ÈŽ Ä#¦š®]KT`‘šOKv0ÁÜEñ¶o£·¾Ñi#·åW#¹ ÔEFû=—qv„m€¯œU³ÉqÇÉg¹£¤VÔI€”†™žZô±3¦ïÆ`wC²þíâP$e?7¼ª!n9VèµÚ1M”%3>XäŽH懴î‡)X@±=àûø•ÂJ=Fã‰à>É^=òÅlOl a­ ]EŠç¨Q)fŸ,”ª©!ÑL‚/m7ˆU™’ú\Õ¨¦(&«HW¿»Ôox'C~èlGã6“K®ÊJŽ÷åŒìƒvÔŠ!gZÕ“÷ú5¡ÉXBÞ$Áµ8e$^ûÚ¨^¨ç[ïËáÚÁÂñ–q÷“ íd,äšßãÝ=ênAaouÏGB†¡µëy1^ŒJÞ*92oëô.<V £$Ó™­eÃ{)Ó²E&ºæHEŸH^¹V—?³®µ”Ônw ±Ü36¸½”;Ów ɪ½#qJ*I#'©uw‚¡€§`yµ×_xåî-V'‚1ÚAO6 ­v*ËTÂË*òâ5¹/“@Å’ì¨W0ƒ ÝIÞ Ô_ÒL#iÐÔ§¼‹b‘}œ<.3<Üd9ì:ÝjÙ««èCè’¹—ÕÕV)Uí]Iû¶½3=‚ûä&e™0qN •Ã.î8{¬ÛgÕsJÍ,ž!rËt=Òm²È‡œÎ½~ãšš"öÄ«îq¼€ÔK‚a$±ö ™Ôˇ hÃa2wêUõ<ø°ïid`ÕÚ*|ÏŸ LpßZµ¾%ÿ@z›Ç©‡Z|„¬©ê?ùS¶4úÇLµK2šøµa±¾E.ÊÏät‡Lƒ9 ÿqö?~Ó®Ÿendstream endobj 1955 0 obj 3319 endobj 1959 0 obj <> stream xœíZÉrÇðq.þ…9Î8Ô­®½ú(‘4 …hÃäÈK>@"¶ïÛFh¡Û¾_³Ëîñn¸k­éM¸›7¶ïE+Íìïq‹Š ÏÂÃy|w†ŽÂÃl%ÀTBÌ^àX±×i¡r0̸’óÙAx{ß~ CÒ?¤&â_Ô4¹ƒ“^ ô?ÄÙ‹O?„uïÃëøî%UØÕv,èD⮯ãüÅ'"`£™mµâq7â]Ñ©¢—\ÄwÑ©nÊuÑ+oËw'ƒC·Ì<ñˆ(13Hjj…×z×¼O‹ÊµþZZ}¹ÆŠGéM©è5ëÝåy[^:¢jY|•‹–êÆì.Ë»0ö"N; C œ—^QU¸3íîg¾*¡t”šˆ(ÂÎÞ”ŠÓOÊwŒ·TG©ÑzúM&ê*¡£¾+\(5‹ï;8Eô¶lëSÞzFŠŽ±5TSqŠs;£§(ÎûRœ»Âéã»S¿RϾI 4zýlQSa6ßý"f+õº.(¬Ï-MÛ þ0÷®@Ià•10 QâÖ©à ÕEÁ'‹âŽWèÄì»r‹…:nËqSª‘d]qûmß圜&“Ìg’ÖLÓ­ácùçy£ZÛwJ†UŒ®rÓ°rq³_Λ®Õ}¯…‚ÓX…Í@‚æ)ÅK5\òVÉÔ²¶c¬Ÿ}q”wЧ~ª2³ŸfóF¶% <â'Ÿã𳶬“n‡  N|s![£Pe#ZÞKcgÿà DÜ›x®\t­niºÎjn)â2Ñ™dô§ù¸Sb@H \ Ò›gY*Ëz-A´¿ÂÑ_ܨjáâ§s¨ xúV7t;iEµµÞŒ&Ñü¥ìôtê‡RV0þMÔJ°’SÖ1>Ž—éS~®ê;ëF[جí%ÀcDæÆâH ¯ÿ_=gq”UDßf4š$a?oIW’; ?:]}®Jx…PÐYÕ¿>x¶ÏÏbÎÙŽTïIc ÉÓûë&ã.!ZÆó¹”F”lžw!ªÛ¹€{÷RÒ÷ä\dÂTト:ç9e¡µT[^Bk(Ïôk ]“Yf }neM¸”¶z)y­zW¥avt•Gt¬çv ú”ÝNô0ê½Â©4°›«_—½†yÁô¿¹íaÍ~ÁøtÎy $çE L'†¨^ó2È97ð¶“cÜ%‰ÅÁMæ$>®oÅÁ9=+¥‚¼Ç—Üg5 œðs|ÿ ALÄ"›ÞºU¦P#œã^!±ýèüºÓ†¾ÿo@öJ‹,aû†Àc‰¢,Ý­™ZæL¦LËRm¦LLƒzzS½Ú»Ø~›ü•Düʉ! 3ÛDµË;¶”b5[zÄÔØò w]Eà*npéÅ{2dîò?®åX$ÂY vo¥€«9owh÷ 4x‰3OÙ‰{ÍIÐùòô¡“ݶ½’#ò¼¢1@œTé=7šr=ÓÑ|‚ñÒ¦nÐqÙˆVMÃNºë1ºWK×ÈrîkWDSbÕeA¸ºXæ6xZBL¦ ¾“ƒü\t²u`ñe˜³ãœ‹’;Óz¼@Hä£uƒ™tÍ~J ‚8"Z¬±19 T¦ôÖÎ9nàPЈ@†Ì=AÈX~°CdÞ¤¾”³–ÔMN —¼Înžƒ¢NèND{†FwEÙ?h*J YÛ¯¢—À)Ÿ0´PÖª‹Mr¸z6uáæö¼`*ÏFFPRÙÀ”€Xe%€>P‘ѳÉd[Wl^ ç9ü¿í,àÙøæíîyÞû˜ÒHäqF™w} "™G’}‡îÇA$iY¨?Ôm”'”+Ñjµ¢³±3BX®‘”à¥À Ï°Æl8)îâûeÕyCT Õ½ë‚-Iù‘v‘º?÷q1I÷Æ¢‹m̪y]Ø8ë?1,sP›0‚ßò·9cÀ¹4o CööNe;±Â© Yàrߺé5 eŠ?Þ< &©_²ieË9k;HÄWzÔVnôˆò¹Š_ðÌ‘\Ñ«vt$ÏÙ‘\¤–ý“8ÒP¸­Œ‘v ×;’u?0yGú¼CÖù´>¯µ,0µ;¯¢?¢¬l!<ÀÖ¾{µŸ á͉:Rg ú ZŒ‘BëYë<ÉíœZÝþ)À±¹òx°ÆÆÚþÐ~ñQI±•àk‰4:N€Ú=Æ5E3g˜ºU^ikÃÉç*gÈÏê%y=™€UL äÐ'võ 3yj(©6§öxÛ4–Œ­ I‹2! +i¡ŸåD…6R_V†­ê¢„…ûc‰A=9_äû-äóÁƒ7œãíˆW–¨H½–¼O+íÐA^W~ЦàŸ>ਠl—ÀÙuœíˆ˜ñ{pö”Ø- OUœmê¼M0꒯ƿ{%þýת/ÿCÒ$`Rl8[v=dQ"ÅÅøÍËõC*ÚýYÒZéžPE‡ à"¬·Wçq`§­* ,=ZJQû“ÆC÷5†#L'ÁVïÜàÑìC†r…4þ³\ù¢5àO+Ï5Ãh:wð!½EpüŒÒ'-«»jo²ÚJÝØyL[»/×ÕûŽ˜ïÞ¨&±$šb«|ÔÝwÇàÑÈžDÌýòPs %G°c:ÅhL&v¬Ÿp”Πh!I‘PýjE :êÃ*=W%7¦k>ø‰X/TºÙÛ'žÃïþ y/ëMdÉz¢VV`“º¤n YæS:S)¼•û)›Ú³å·;¼~í]Qù¥ÝÇIó˜ØöÉïócûÞý‚ýØî°¶‘Û|C a­ôÖ]Vðh/:Ù6¿•ô* nA|5 Q‰z¦Šð®·çÈ…ÉèÒ³«‘iGb,¤€H7o|E ÀÑWè/@¨gëà”U…þQ‚¡µÝc’ÞEiu½ç°LÒ*WLÚN¯øTý$FĪ~=+>ö­ö$4r(v ‰=‰| " ü•ÿ0%I+¸{ …† ƒ|/ß$(¹s½-ºeßÕD‹a“ä$o/k܇´‚%³¼>M˯€&¦=Yˆ{&·YÍ ¢“6:盓lÿS5~¡žp€6U¤=mZy‚/ìå]›™AÝ×b‰$£ÓˆV’þwþ±áÞ Ï>6\燯'ë!Z± Þ€Ô"bí¢Ðˆ’v¥_-&ÿ€? iY“endstream endobj 1960 0 obj 2594 endobj 1964 0 obj <> stream xœíÉr·5åÜæ’_èœÒíʀؗäZ*‹)¯ñÄ:Ø9PŠd™")ŠT¢¿ÏÃþºÍ!)¦§R*i 4ðððöo;JXGýŸô{ôfµ÷7®iwònE»/áïÉê튅%]ú9zÓíoÂ2Þ9â4ײۼ^E¬³¦3Œ “oV?õ¿ÖŠXG•üÇæ¯aûü2 ;7[XýlXS¢ÓBõÇÚ­Óý»A¥©6ýÍ@a‡äN÷ga¨gýE8Ä:'úøKÀ°½ö2®µÆïâB£YÿÝÀˆŒÊüÙƒºÖ’12¤°}¯=(ß¿$Q\ÂÜדÞgÐg} ÃX¹)àìiÄqÊÙnóÕjóùOéå´ë_D©S¢¿j¡‰ ßÌ.ìg*qÐì9€…C­ÀdzçÏrDÛo†µ ÜIÖ›øÛ)F¨`’ uÿwÄIÌÕ°Nq.á(¨aýia âŸçÔÄ,-=«“[aˆ®ÿ¬°2‘U W,Ûz,±²AŽÀ‹r:¡…Ž­K=\nÛ¨û«p¢¤C²ŒÎ¼-+7=zy¿e™óÖï÷╇—è:I õˆJ†8$ñY€4߉&ºðy]Z%#Š`Í”2\ï$s2£f+âU úý2h U ó‰3ñæ¤RÆß~®¿öZ£)Tøô:ƒfª{ãu\é€L ‰‘øÜÓ™!óÛŠ"˜…µ~%š€¶£óÛ4j#¸µìâÔ>å²Þü$ßcp’\Œ’Hogr Î侺°,÷3÷ ¬„ qP§P¯õ0ï[½ ºâåDôÃËéH?òZ°÷c›Apb¹Dº7ñ¼µH¤° n9+áS«¶·›tt¡"K *8 -¤mÿ $¨$~ø­wȆR«ñYù FŽu(ãú'€uBª[Ñú£ß/€#ÕGΗ‚’ßFu„K9D¡Ñx‹``1v×UÃïcMÒ®ª$eô)W%äæ(LÌûfW= "ýÛ¢ŒhéIÕꫜw œ:Y8Ç· ×ü1œ˜¹‹˜í¶Ê,SIC•“_ 2 H¨ÃYÜYŽ——Ùÿ‰§M°3Å›ÏA„ Lpí¬ŽÔ< ˆ1þTr‹Œ·ÕÈ 5­æUK˜ÑIÛÄ fÚr]õ9¾y†ÙÙÏ[!­wë~»€ýyî¶Œ_­ØoÁ|Ì£wad 5 ®Ë·³-·x= ž TH, æH$ïZ3 |w`í¸oË× |…\EQ›x3"ÿåŒüWw{ÁJtvo¬žâ\"ox9‘GØw^Dlÿ"OUßç©ã´JñÆ´ÿ³1º/¡5 G Œj"x'´ñ?AÕ¤W]¸´Õ…AŽá¨cÑ…éÎ[*ïÆ‚%ùýƒTA¿AÓÃ`$åÝz´ú›`À¾9 ˆU¤VÎK-ðÎÇÖ;N¾Y}¿zÛI)LÈ$iÈv£i;¡€ÖúÇþÁjïàëîæúöxµ÷²c«½þŸýï¾€ŸƒgÝoVϺ ¶8B["+$ë}¤Å kEfŒ‚M’’ȌávQÃ{Z4_rÛ‡c§ª Ž2Üç §Y‹ÑÀÏiËGeÃóìS Þôª‰×¬X'¨žùr°,°¸Ÿ óÕJí^ òEtbp¡‘+Ôx†–Þá’&ÎiâƒCœŒëè¨3€Vºµë†)0”Åd7¡Õlh Èè´^üp|ås“ÏVA,“Ï®E´Q=rÞi\ kqCC-f·ûÎ ³ùáΰ˜Ì¤âöÁ\‰Û(±ô/<¶¥¶SêÛšÉ^‹Dæ¢9\îKø •bt^ÎíÂ6tµöDóuA2µ+—Ö,u*Ú©E-°ØbÀgZ³6"Š£ü~ž–Ú¹~!×i=$!¡ •/ÁYP0ÁÀ<*ö$ bH(ˆÄ¸¡' ·0µM4©ÇÚho‹N}Õ¬• ÐŒ›àÕÖVÄä O`¬ Å:Áµ_qmŠè%#ÔT’ôÚ¦ÐA>këÇÖFpøÒVÖx„Æ Û©kË æ@jL ŒcÂEA·œ£Ï³^ýô¨|3Í&–Cp°®Êâ4â¶y…EdÓ0ªj¤|QÕª”§3UwGPéár€ ÒÅq}%«)Ï‘Bá fy(ˆTè±qÎ=øˆ ô1Å¥ø„BPiQC •¹Hï*Ôh8(UµK-áç¾Ô~döäx ‹æöY8\ÿyÈ %-ôpbR”(ž+öNÿWóÈf«ì‡r …©è¦Šsçcoê»Å|äÔH-²H¼.(NoA§ÞÄ‘ѲßÕn¶jF¿àÚ4‡Í:B£^5é[G_¯wâ÷´}áFúWÐ!þ1¤|×n¹dD9ŽH¡míbåxßÔˆö³‹³‘qOcYôÐ"újY´R–ò¾%ï“—P)ðþý]í¨¢öƒ?^ðÓ!ûÈW"5j _üö‹ÄqÏ6¼W¨.â €û±v³$)=DB±~õZ“ü6oÇ$¢l˜Hüõg Ç•˜C-=dBrtÜÎ%˜× =î§o?Ç›ó¬Ó–6ŸÖM²r®ˆ<ÛbŽTæWæj¸­¤hÖ «Æç¸ãZ^ÿ€ïµ ÔÚ&o”F{š!·S›¨ë‡0jö®Î»&æL·æ`…¹ŒðLÕTž,ì÷«jÎSendstream endobj 1965 0 obj 2420 endobj 1969 0 obj <> stream xœ5Œ± Â@DûýŠ)/…ëíâ­·­ ;e;± ˜êŠàÿCↆÇ,È,È_í95:>Ô2æeŒ›gZH:‚=¦†KtLàì¦vB¼éw P¯\ Æ"îŠhôL: ×ZÏ©ôæ"%Ù|Å®A÷M+Lªendstream endobj 1970 0 obj 115 endobj 1974 0 obj <> stream xœ½YYoG~ß_13‘vÒ÷ñÈ%W€¬@åÁWlËöŒ˜_Ÿê9º«{jv×" ±Úî®úªê«¯k>U¬å Ãÿ‹ßßêãÏ V=†Ç‹O Þ=R ÿ\T÷Wá1«*®Z©Œ¨Vÿ,ú xeEe9k™ªV‹µn–¼uV]·Í’µ^'l­š¥÷¶FÔ«f)Zn”1õI#áox}_j¿ëúÏøåºû䬩/Ó®W ku\Ûúß{ØÔùÖ)vŠ¿ï¥UÍR¶Jù÷êéà‹o½F_L§·Z{W­Á‰Ár˘PÎïd8ã(lgŒæ&ì¬[ç¼—ÁÕ íVŽß^iܵÊIüìºáàgª> þò–q]?oT«…ò†8ÀÙø$³õ½`–ñÞHÌ:H«Nâþ§€‚7Z >h˜Äû£Eñ÷Ã14BX°"Ýó"ÄNJ¸ìõ;ÈÞÙ°×xî <«Lk½¯ßt.!¿cŒtõgˆ³6ÌØÑ¬°éI÷¤ç\“![†Á½i•VŒžéqéZo!ÁF”ºxï²ë*CFhHZfê‡ú£ýׯ@&Kž…îšrÄ ‰ÃÄG¨àIM0†¨ë¬=,˜ã’å¨c§^‚B°‡ÙÊÝB1õcr/îCŠp)”f…ðÎÙì3k¾PNþÍtI“-ºÇ“Ý‘M®’µ¨±ˆ îÎã%ðݳ])ÉrÜ&܆hrLÐ$ iŽMõ¦‚!sý„ðùö´³j\fHž_,‚¨qœ£“¿P©yL•Þ<ÏgB¾ë†RÔÿ~ÜÏhZ¦/:¨eòýGE‘B‘8Ûà´íÖi y¹žÜƒ;çç®Ä¿ˆÄ ª "XJ¸A ìJõI³Ì¥ú–n¸-€ô™S²îÌ^eQ´™p}Ö€.F \Q¥(aMšˆÒ6å>w/6÷´+jÙh}úvÌû»Ì—mÅ”¤˜*QH´€m÷ I¾Xƾ„lÛЖÊ&ž[‡·MôbР ¨NX½$›Ýá§Ró6Zü:ëq¦Ž½ë¦ŒII4¹œSs`§0ˆ'#ˆ”ø¤n‰é\‹"ýªœ®æöú(lЈΆ¡FFÒ£ÈÃÂÍ"ê+Áx˜e]" ¢Iƒn(î¢ts­A’ ·z…*éÑ?}!…Ò ¨U|ßDú»gÍ Ï=£DƉéœá7É™Ÿüö*UkÅÖYþ9f…Èlß'4¿õ®x“ "ï÷è ³òMÈÖÁmr"Ó&cgþ–7¶Àd:ɹýŒÐ3ÇeÃ5Ïà ZÀÂ$DGÀÞ#›&¯~Šaò{ðšôMd=“š³ýpFÊó°°ÀNàÄ_é&‡ H‰.5Z5ç··goïd"´Íç>ãÄM¦ù²H¹þ"§<3O±ÊõC-àªÊ„Ô.³½[½w[SJLT……«‘ o³)áú±hñrtã(s&D).èËãôñ®1ø?6;æóBñ®1¬UVfóÝý_3À½ãp”Vª´ò›Lpóûü¬šÈî/ãkÓQ-m½ôI¿²˜¼ÒQÌõY¢Ò%H–®#Œ›÷Ð)•,^øhµx ÿ™~xVendstream endobj 1975 0 obj 1909 endobj 1979 0 obj <> stream xœµYÛnG ú¨¯ØÇšîÜgs«;mÓTHP}°-ÙVˉmÅp¿¾3Ú 9»\IqSy—<$9£/EÅEQ¥Ÿæ÷ùõä§wÒVÅåݤ*Žâ¿ËÉ—‰Ø>R4¿Î¯‹ç³ô˜ÓEàÁJ«‹ÙŤ6 ç¹!Nn‹Ùõä¯ò¦¹U¥ËS65܇Êèò#›j.M°¡¼OoÙTjÉå 6­¸ Á*Ó<áCPåš ”ˆÆî·l¥Ò[Ñ™5–KVELÆHQž1iy%+Qnúï£Z›Þá×ï˜âÆ­ÿžoS!pŒRúãlczŦŠË ŒI¯·6µ%q®b$Js'Cù,EâªÊ[QÎ;¯§õ³Vùò:YÒXU°•u @L¡÷•(fo&³S§’+UiÃ<;W”q„éSÂã12ÃôikLUNÄütv—ðé?`b†o› V~‹U¶0Ÿ±`¸uåc‡gS—X6p·.dÒeÈ.©€ÀoùÀbŠ”íŸë [Ü V ,®;‹sðŽ,.˜”\«lO¥ ª.ŸG›Xá€ý¬˜åBykq† Dýþèhˆj4¼ÇeèÒñ‚òóÂ8ëL-¨tô2ƒð•ÃPîש?-w>ÐÀêþñR¦ôuIß'yhså‚k1½D¯/©wšh·#À˜«¦£€JvÈàÃ! YÇ}S.@6-T#ô_ Pñ’莖¼ÿ‘4¨uQÄ!@ã&<—UÔS\;h×n×~éÍßuÎo¨dôØ”J¤uVožt.hc\žúï©Øßé¶çe”‘¯T§AI¨ÛÆ!3½Ø×³^TÉC%1—¢D*CÝYSMÏ+A5Ô@;šäÕMâly„ Ð3s1æ9ù|w3"ݘX „RUÜy€ÿ5Uþ'cIµ×VŒdCùÜÅ…m¬£ýTÛ“,”¢y«ä¢|õBçn »=<„jƒ'rࣰPŠP뼦[…ˆ”«r¾eBñàŒi zÈ!YÁI 2ñ¹?t‡«Ñh hò¢Ú>‚@æ©ië^ã#jpj?R*ºº@(7dÎÉÁ<ÂÍ÷ÌÄKêlÊŸ“ð³…]jÃE’qhK y¨.G{¹¦´žVà5EþºAN¯Cs80œ0©¢dƃÏPsy[æ[J^ÒCÎ)^©½.QßÝC#/*iŒ–·+赦 ×:xz@!Sçã©hD7S†<+\<£JZÙiç´Pœ¶Ã%ߪx˜üÚ-TˆcªµgGEr}²wŽ¡T7b¢ÄÈ|¤› OS¸¸;÷¦v»SÏnôÀ&cÏþ%òŒì;$ƒÜ?3ìéì¼"˜®¸•Fï7F–P{!d´6£(äí"Û=¾Ë±Ú‘QézG-ÉÙwÁDà^ÆZ^€šÿJÛ\/ÈáDgÔ2çÍJf\æ94í³ä D½o~¹Ï}ïTÕˆz|°€ÁÉ=òÂpéËßÈÓß}ŸÄ78ζTýž­D®w¨P«.ƒ‡nîO:Í€@ÑÂ;§9ù’f8=jX Ú“¥Œ R2¸¡êCBa“—*hö·„ A"O3»tþI¹‡;t…HOó‡úÙç æ7 yžôåÎø9åm\÷¦Ï‹ rê§­X©XqŒŽ>IÖ⫵1º ½> stream xœÍVMoÛ0 ½ûWè( °*J¢>v,0 vÙà[ÑÃÚ¤IÐfiÓ Cÿý(DZ˜Ä]OŠ AIäÓ#•'a4S>Ãïíº¹ønƒ‹çƈÏô]4O ô[Äðs»—]Ù½°^ÇAtwÍD´"·ݺ¹’—ªmRN(WÊjãsHòFµFGì‡âE‰­oh‡ÎY¹­mrÙY?Fç#Z*p%›$_úuëüu÷¥¯DÖ9ØàK¢¨ËÉ‹Q'ÑÍ(É+Õzm1‡,Aµäν¼&o ÚÄ@Ø£w§ a!RÌ|ì7¤œüX½“&Ûû£B·Õ¼WACpdÍ«“{VN#f”̦¢nûr‚qr]¬l18©Uk5qÈÎÏÏâÃò×Ôªåmònt¾(ôÚ9? —I¥È3aT¬UÔ@çÓ‰~±'Y#R\ ‡Ë( [:cÁdÇYøûqçÈ™8!&x¨èÇB¤¼IÚ½R*¢/0ÑPéùÕ(ýúq9%´{4ãr8X%l;Äm¤ 9Ÿ Õþ{¡þ.Ý2U„'6fMšIüÖV`v×Là,2;v$Û¨“1àg¡bdàkÓ}8âÀý×femqS͇ºwUMÖͬؿv¾;Æe­ÉB0sÀEŒîICÓƒÕ3›Œ0«-w^Dé$Ö»*òyõÎ&›–!¬x¥ tå4„³O‰W³¬P»“QTäÀAI ¨ãDþµß°¬AV“Y°YNJeò8½eëæ¬}ÿZC¬±Ý„ïŒ:öâT³ Wo©š¤ÝYßL Ÿ˜<­×áÃ3¯t×\6U¨Û:Ðw'Bïþ Ÿí¯´ðή€3â럂ùä˜{ƒÖ^…4Òëæƒ£‡ûÇÍŽÄb%6sâ>uÍ7úüWï<Æendstream endobj 1985 0 obj 698 endobj 4 0 obj <> /Contents 258 0 R >> endobj 266 0 obj <> /Contents 267 0 R >> endobj 271 0 obj <> /Annots[275 0 R 276 0 R 277 0 R 278 0 R 279 0 R 280 0 R 281 0 R 282 0 R 283 0 R 284 0 R 285 0 R 286 0 R 287 0 R 288 0 R 289 0 R 290 0 R 291 0 R 292 0 R 293 0 R 294 0 R 295 0 R 296 0 R 297 0 R 298 0 R 299 0 R 300 0 R 301 0 R 302 0 R 303 0 R 304 0 R]/Contents 272 0 R >> endobj 307 0 obj <> /Annots[310 0 R 311 0 R 312 0 R 313 0 R 314 0 R 315 0 R 316 0 R 317 0 R 318 0 R 319 0 R 320 0 R 321 0 R 322 0 R 323 0 R 324 0 R 325 0 R 326 0 R 327 0 R 328 0 R 329 0 R 330 0 R 331 0 R 332 0 R 333 0 R 334 0 R 335 0 R 336 0 R 337 0 R 338 0 R 339 0 R 340 0 R 341 0 R 342 0 R 343 0 R 344 0 R 345 0 R 346 0 R 347 0 R]/Contents 308 0 R >> endobj 350 0 obj <> /Annots[353 0 R 354 0 R 355 0 R 356 0 R 357 0 R 358 0 R 359 0 R 360 0 R 361 0 R 362 0 R 363 0 R 364 0 R 365 0 R 366 0 R 367 0 R 368 0 R 369 0 R 370 0 R 371 0 R 372 0 R 373 0 R 374 0 R 375 0 R 376 0 R 377 0 R 378 0 R 379 0 R 380 0 R 381 0 R 382 0 R 383 0 R 384 0 R 385 0 R 386 0 R 387 0 R 388 0 R 389 0 R 390 0 R 391 0 R]/Contents 351 0 R >> endobj 394 0 obj <> /Annots[397 0 R 398 0 R 399 0 R 400 0 R 401 0 R 402 0 R 403 0 R 404 0 R 405 0 R 406 0 R 407 0 R 408 0 R 409 0 R 410 0 R 411 0 R 412 0 R 413 0 R 414 0 R 415 0 R 416 0 R 417 0 R 418 0 R 419 0 R 420 0 R 421 0 R 422 0 R 423 0 R 424 0 R 425 0 R 426 0 R 427 0 R 428 0 R 429 0 R 430 0 R 431 0 R 432 0 R 433 0 R 434 0 R]/Contents 395 0 R >> endobj 437 0 obj <> /Annots[440 0 R 441 0 R 442 0 R 443 0 R 444 0 R 445 0 R 446 0 R 447 0 R 448 0 R 449 0 R 450 0 R 451 0 R 452 0 R 453 0 R 454 0 R 455 0 R 456 0 R 457 0 R 458 0 R 459 0 R 460 0 R 461 0 R 462 0 R 463 0 R 464 0 R 465 0 R 466 0 R 467 0 R 468 0 R 469 0 R 470 0 R 471 0 R 472 0 R 473 0 R 474 0 R 475 0 R 476 0 R 477 0 R 478 0 R]/Contents 438 0 R >> endobj 481 0 obj <> /Annots[484 0 R 485 0 R 486 0 R 487 0 R 488 0 R 489 0 R 490 0 R 491 0 R 492 0 R 493 0 R 494 0 R 495 0 R 496 0 R 497 0 R 498 0 R 499 0 R 500 0 R 501 0 R 502 0 R 503 0 R 504 0 R 505 0 R 506 0 R 507 0 R 508 0 R 509 0 R 510 0 R 511 0 R 512 0 R 513 0 R 514 0 R 515 0 R 516 0 R 517 0 R 518 0 R 519 0 R 520 0 R]/Contents 482 0 R >> endobj 523 0 obj <> /Annots[526 0 R 527 0 R 528 0 R 529 0 R 530 0 R 531 0 R 532 0 R 533 0 R 534 0 R 535 0 R 536 0 R 537 0 R 538 0 R 539 0 R 540 0 R 541 0 R 542 0 R 543 0 R 544 0 R 545 0 R 546 0 R 547 0 R 548 0 R 549 0 R 550 0 R 551 0 R 552 0 R 553 0 R 554 0 R 555 0 R]/Contents 524 0 R >> endobj 558 0 obj <> /Contents 559 0 R >> endobj 567 0 obj <> /Contents 568 0 R >> endobj 573 0 obj <> /Contents 574 0 R >> endobj 578 0 obj <> /Annots[581 0 R 582 0 R]/Contents 579 0 R >> endobj 585 0 obj <> /Contents 586 0 R >> endobj 590 0 obj <> /Contents 591 0 R >> endobj 595 0 obj <> /Contents 596 0 R >> endobj 600 0 obj <> /Contents 601 0 R >> endobj 605 0 obj <> /Contents 606 0 R >> endobj 610 0 obj <> /Contents 611 0 R >> endobj 615 0 obj <> /Contents 616 0 R >> endobj 620 0 obj <> /Contents 621 0 R >> endobj 625 0 obj <> /Contents 626 0 R >> endobj 630 0 obj <> /Contents 631 0 R >> endobj 635 0 obj <> /Contents 636 0 R >> endobj 640 0 obj <> /Contents 641 0 R >> endobj 645 0 obj <> /Contents 646 0 R >> endobj 650 0 obj <> /Contents 651 0 R >> endobj 655 0 obj <> /Annots[658 0 R 659 0 R 660 0 R]/Contents 656 0 R >> endobj 663 0 obj <> /Annots[666 0 R]/Contents 664 0 R >> endobj 669 0 obj <> /Contents 670 0 R >> endobj 674 0 obj <> /Contents 675 0 R >> endobj 679 0 obj <> /Contents 680 0 R >> endobj 684 0 obj <> /Annots[687 0 R 688 0 R 689 0 R]/Contents 685 0 R >> endobj 692 0 obj <> /Contents 693 0 R >> endobj 697 0 obj <> /Contents 698 0 R >> endobj 702 0 obj <> /Contents 703 0 R >> endobj 707 0 obj <> /Contents 708 0 R >> endobj 712 0 obj <> /Annots[715 0 R]/Contents 713 0 R >> endobj 718 0 obj <> /Annots[721 0 R 722 0 R]/Contents 719 0 R >> endobj 725 0 obj <> /Annots[728 0 R 729 0 R 730 0 R]/Contents 726 0 R >> endobj 733 0 obj <> /Contents 734 0 R >> endobj 738 0 obj <> /Annots[741 0 R 742 0 R]/Contents 739 0 R >> endobj 745 0 obj <> /Contents 746 0 R >> endobj 750 0 obj <> /Contents 751 0 R >> endobj 755 0 obj <> /Contents 756 0 R >> endobj 760 0 obj <> /Contents 761 0 R >> endobj 765 0 obj <> /Annots[768 0 R 769 0 R]/Contents 766 0 R >> endobj 772 0 obj <> /Contents 773 0 R >> endobj 777 0 obj <> /Contents 778 0 R >> endobj 782 0 obj <> /Contents 783 0 R >> endobj 787 0 obj <> /Contents 788 0 R >> endobj 792 0 obj <> /Annots[795 0 R]/Contents 793 0 R >> endobj 798 0 obj <> /Contents 799 0 R >> endobj 803 0 obj <> /Contents 804 0 R >> endobj 808 0 obj <> /Contents 809 0 R >> endobj 813 0 obj <> /Contents 814 0 R >> endobj 818 0 obj <> /Contents 819 0 R >> endobj 823 0 obj <> /Contents 824 0 R >> endobj 828 0 obj <> /Contents 829 0 R >> endobj 833 0 obj <> /Contents 834 0 R >> endobj 838 0 obj <> /Annots[841 0 R]/Contents 839 0 R >> endobj 844 0 obj <> /Contents 845 0 R >> endobj 849 0 obj <> /Annots[852 0 R]/Contents 850 0 R >> endobj 855 0 obj <> /Annots[858 0 R 859 0 R 860 0 R]/Contents 856 0 R >> endobj 863 0 obj <> /Annots[868 0 R]/Contents 864 0 R >> endobj 871 0 obj <> /Contents 872 0 R >> endobj 876 0 obj <> /Contents 877 0 R >> endobj 881 0 obj <> /Contents 882 0 R >> endobj 886 0 obj <> /Contents 887 0 R >> endobj 891 0 obj <> /Contents 892 0 R >> endobj 896 0 obj <> /Contents 897 0 R >> endobj 901 0 obj <> /Contents 902 0 R >> endobj 906 0 obj <> /Contents 907 0 R >> endobj 911 0 obj <> /Contents 912 0 R >> endobj 916 0 obj <> /Contents 917 0 R >> endobj 921 0 obj <> /Annots[924 0 R]/Contents 922 0 R >> endobj 927 0 obj <> /Annots[930 0 R 931 0 R 932 0 R 933 0 R]/Contents 928 0 R >> endobj 936 0 obj <> /Contents 937 0 R >> endobj 941 0 obj <> /Contents 942 0 R >> endobj 946 0 obj <> /Annots[949 0 R 950 0 R]/Contents 947 0 R >> endobj 953 0 obj <> /Annots[956 0 R 957 0 R]/Contents 954 0 R >> endobj 960 0 obj <> /Annots[963 0 R]/Contents 961 0 R >> endobj 966 0 obj <> /Annots[969 0 R 970 0 R 971 0 R]/Contents 967 0 R >> endobj 974 0 obj <> /Annots[977 0 R]/Contents 975 0 R >> endobj 980 0 obj <> /Contents 981 0 R >> endobj 985 0 obj <> /Annots[988 0 R]/Contents 986 0 R >> endobj 991 0 obj <> /Contents 992 0 R >> endobj 996 0 obj <> /Contents 997 0 R >> endobj 1001 0 obj <> /Contents 1002 0 R >> endobj 1006 0 obj <> /Contents 1007 0 R >> endobj 1011 0 obj <> /Contents 1012 0 R >> endobj 1016 0 obj <> /Contents 1017 0 R >> endobj 1021 0 obj <> /Contents 1022 0 R >> endobj 1026 0 obj <> /Contents 1027 0 R >> endobj 1031 0 obj <> /Contents 1032 0 R >> endobj 1036 0 obj <> /Contents 1037 0 R >> endobj 1041 0 obj <> /Contents 1042 0 R >> endobj 1046 0 obj <> /Contents 1047 0 R >> endobj 1051 0 obj <> /Contents 1052 0 R >> endobj 1056 0 obj <> /Contents 1057 0 R >> endobj 1061 0 obj <> /Contents 1062 0 R >> endobj 1066 0 obj <> /Contents 1067 0 R >> endobj 1071 0 obj <> /Contents 1072 0 R >> endobj 1076 0 obj <> /Contents 1077 0 R >> endobj 1081 0 obj <> /Contents 1082 0 R >> endobj 1086 0 obj <> /Contents 1087 0 R >> endobj 1091 0 obj <> /Contents 1092 0 R >> endobj 1096 0 obj <> /Contents 1097 0 R >> endobj 1101 0 obj <> /Annots[1104 0 R]/Contents 1102 0 R >> endobj 1107 0 obj <> /Contents 1108 0 R >> endobj 1112 0 obj <> /Contents 1113 0 R >> endobj 1117 0 obj <> /Contents 1118 0 R >> endobj 1122 0 obj <> /Contents 1123 0 R >> endobj 1127 0 obj <> /Contents 1128 0 R >> endobj 1132 0 obj <> /Contents 1133 0 R >> endobj 1137 0 obj <> /Contents 1138 0 R >> endobj 1142 0 obj <> /Contents 1143 0 R >> endobj 1147 0 obj <> /Contents 1148 0 R >> endobj 1152 0 obj <> /Contents 1153 0 R >> endobj 1157 0 obj <> /Contents 1158 0 R >> endobj 1162 0 obj <> /Contents 1163 0 R >> endobj 1167 0 obj <> /Contents 1168 0 R >> endobj 1172 0 obj <> /Contents 1173 0 R >> endobj 1177 0 obj <> /Contents 1178 0 R >> endobj 1182 0 obj <> /Contents 1183 0 R >> endobj 1187 0 obj <> /Contents 1188 0 R >> endobj 1192 0 obj <> /Contents 1193 0 R >> endobj 1197 0 obj <> /Contents 1198 0 R >> endobj 1202 0 obj <> /Contents 1203 0 R >> endobj 1207 0 obj <> /Contents 1208 0 R >> endobj 1212 0 obj <> /Contents 1213 0 R >> endobj 1217 0 obj <> /Contents 1218 0 R >> endobj 1222 0 obj <> /Contents 1223 0 R >> endobj 1227 0 obj <> /Contents 1228 0 R >> endobj 1232 0 obj <> /Contents 1233 0 R >> endobj 1237 0 obj <> /Contents 1238 0 R >> endobj 1242 0 obj <> /Contents 1243 0 R >> endobj 1247 0 obj <> /Contents 1248 0 R >> endobj 1252 0 obj <> /Contents 1253 0 R >> endobj 1257 0 obj <> /Contents 1258 0 R >> endobj 1262 0 obj <> /Contents 1263 0 R >> endobj 1267 0 obj <> /Annots[1270 0 R]/Contents 1268 0 R >> endobj 1273 0 obj <> /Contents 1274 0 R >> endobj 1278 0 obj <> /Contents 1279 0 R >> endobj 1283 0 obj <> /Contents 1284 0 R >> endobj 1288 0 obj <> /Contents 1289 0 R >> endobj 1293 0 obj <> /Contents 1294 0 R >> endobj 1298 0 obj <> /Contents 1299 0 R >> endobj 1303 0 obj <> /Contents 1304 0 R >> endobj 1308 0 obj <> /Contents 1309 0 R >> endobj 1313 0 obj <> /Contents 1314 0 R >> endobj 1318 0 obj <> /Contents 1319 0 R >> endobj 1323 0 obj <> /Contents 1324 0 R >> endobj 1328 0 obj <> /Contents 1329 0 R >> endobj 1333 0 obj <> /Contents 1334 0 R >> endobj 1338 0 obj <> /Contents 1339 0 R >> endobj 1343 0 obj <> /Annots[1346 0 R]/Contents 1344 0 R >> endobj 1349 0 obj <> /Annots[1352 0 R]/Contents 1350 0 R >> endobj 1355 0 obj <> /Annots[1358 0 R]/Contents 1356 0 R >> endobj 1361 0 obj <> /Annots[1364 0 R]/Contents 1362 0 R >> endobj 1367 0 obj <> /Annots[1370 0 R 1371 0 R 1372 0 R 1373 0 R 1374 0 R 1375 0 R]/Contents 1368 0 R >> endobj 1378 0 obj <> /Annots[1381 0 R 1382 0 R 1383 0 R]/Contents 1379 0 R >> endobj 1386 0 obj <> /Annots[1389 0 R 1390 0 R]/Contents 1387 0 R >> endobj 1393 0 obj <> /Contents 1394 0 R >> endobj 1398 0 obj <> /Contents 1399 0 R >> endobj 1403 0 obj <> /Annots[1406 0 R 1407 0 R]/Contents 1404 0 R >> endobj 1410 0 obj <> /Contents 1411 0 R >> endobj 1415 0 obj <> /Annots[1418 0 R 1419 0 R 1420 0 R 1421 0 R]/Contents 1416 0 R >> endobj 1424 0 obj <> /Contents 1425 0 R >> endobj 1429 0 obj <> /Contents 1430 0 R >> endobj 1434 0 obj <> /Contents 1435 0 R >> endobj 1440 0 obj <> /Contents 1441 0 R >> endobj 1445 0 obj <> /Contents 1446 0 R >> endobj 1450 0 obj <> /Contents 1451 0 R >> endobj 1455 0 obj <> /Contents 1456 0 R >> endobj 1460 0 obj <> /Contents 1461 0 R >> endobj 1465 0 obj <> /Annots[1468 0 R]/Contents 1466 0 R >> endobj 1471 0 obj <> /Annots[1474 0 R]/Contents 1472 0 R >> endobj 1477 0 obj <> /Annots[1480 0 R 1481 0 R 1482 0 R 1483 0 R 1484 0 R]/Contents 1478 0 R >> endobj 1487 0 obj <> /Annots[1490 0 R 1491 0 R 1492 0 R 1493 0 R]/Contents 1488 0 R >> endobj 1496 0 obj <> /Annots[1499 0 R 1500 0 R]/Contents 1497 0 R >> endobj 1503 0 obj <> /Annots[1506 0 R 1507 0 R]/Contents 1504 0 R >> endobj 1510 0 obj <> /Annots[1513 0 R 1514 0 R]/Contents 1511 0 R >> endobj 1517 0 obj <> /Contents 1518 0 R >> endobj 1522 0 obj <> /Annots[1525 0 R 1526 0 R]/Contents 1523 0 R >> endobj 1529 0 obj <> /Contents 1530 0 R >> endobj 1534 0 obj <> /Annots[1537 0 R 1538 0 R 1539 0 R 1540 0 R 1541 0 R 1542 0 R 1543 0 R 1544 0 R 1545 0 R 1546 0 R 1547 0 R 1548 0 R 1549 0 R 1550 0 R 1551 0 R 1552 0 R 1553 0 R 1554 0 R]/Contents 1535 0 R >> endobj 1557 0 obj <> /Contents 1558 0 R >> endobj 1562 0 obj <> /Annots[1565 0 R 1566 0 R 1567 0 R]/Contents 1563 0 R >> endobj 1570 0 obj <> /Annots[1573 0 R 1574 0 R 1575 0 R]/Contents 1571 0 R >> endobj 1578 0 obj <> /Annots[1581 0 R 1582 0 R 1583 0 R]/Contents 1579 0 R >> endobj 1586 0 obj <> /Annots[1589 0 R]/Contents 1587 0 R >> endobj 1592 0 obj <> /Annots[1595 0 R]/Contents 1593 0 R >> endobj 1598 0 obj <> /Annots[1601 0 R 1602 0 R 1603 0 R]/Contents 1599 0 R >> endobj 1606 0 obj <> /Contents 1607 0 R >> endobj 1611 0 obj <> /Contents 1612 0 R >> endobj 1616 0 obj <> /Annots[1619 0 R 1620 0 R 1621 0 R 1622 0 R 1623 0 R 1624 0 R 1625 0 R 1626 0 R]/Contents 1617 0 R >> endobj 1629 0 obj <> /Annots[1632 0 R 1633 0 R]/Contents 1630 0 R >> endobj 1636 0 obj <> /Annots[1639 0 R 1640 0 R 1641 0 R]/Contents 1637 0 R >> endobj 1644 0 obj <> /Annots[1647 0 R]/Contents 1645 0 R >> endobj 1650 0 obj <> /Contents 1651 0 R >> endobj 1655 0 obj <> /Contents 1656 0 R >> endobj 1660 0 obj <> /Annots[1663 0 R 1664 0 R 1665 0 R]/Contents 1661 0 R >> endobj 1668 0 obj <> /Annots[1671 0 R]/Contents 1669 0 R >> endobj 1674 0 obj <> /Annots[1677 0 R 1678 0 R]/Contents 1675 0 R >> endobj 1681 0 obj <> /Contents 1682 0 R >> endobj 1686 0 obj <> /Contents 1687 0 R >> endobj 1691 0 obj <> /Annots[1694 0 R 1695 0 R 1696 0 R 1697 0 R 1698 0 R 1699 0 R 1700 0 R 1701 0 R]/Contents 1692 0 R >> endobj 1704 0 obj <> /Annots[1707 0 R 1708 0 R 1709 0 R 1710 0 R 1711 0 R 1712 0 R 1713 0 R 1714 0 R 1715 0 R 1716 0 R]/Contents 1705 0 R >> endobj 1719 0 obj <> /Annots[1722 0 R 1723 0 R 1724 0 R 1725 0 R]/Contents 1720 0 R >> endobj 1728 0 obj <> /Contents 1729 0 R >> endobj 1733 0 obj <> /Contents 1734 0 R >> endobj 1738 0 obj <> /Contents 1739 0 R >> endobj 1743 0 obj <> /Annots[1746 0 R]/Contents 1744 0 R >> endobj 1749 0 obj <> /Annots[1752 0 R]/Contents 1750 0 R >> endobj 1755 0 obj <> /Contents 1756 0 R >> endobj 1760 0 obj <> /Contents 1761 0 R >> endobj 1765 0 obj <> /Contents 1766 0 R >> endobj 1770 0 obj <> /Contents 1771 0 R >> endobj 1775 0 obj <> /Contents 1776 0 R >> endobj 1780 0 obj <> /Contents 1781 0 R >> endobj 1785 0 obj <> /Contents 1786 0 R >> endobj 1790 0 obj <> /Contents 1791 0 R >> endobj 1795 0 obj <> /Annots[1798 0 R 1799 0 R]/Contents 1796 0 R >> endobj 1802 0 obj <> /Annots[1805 0 R]/Contents 1803 0 R >> endobj 1808 0 obj <> /Annots[1811 0 R 1812 0 R 1813 0 R]/Contents 1809 0 R >> endobj 1816 0 obj <> /Annots[1819 0 R 1820 0 R]/Contents 1817 0 R >> endobj 1823 0 obj <> /Contents 1824 0 R >> endobj 1828 0 obj <> /Contents 1829 0 R >> endobj 1833 0 obj <> /Contents 1834 0 R >> endobj 1838 0 obj <> /Contents 1839 0 R >> endobj 1843 0 obj <> /Contents 1844 0 R >> endobj 1848 0 obj <> /Contents 1849 0 R >> endobj 1853 0 obj <> /Contents 1854 0 R >> endobj 1858 0 obj <> /Contents 1859 0 R >> endobj 1863 0 obj <> /Contents 1864 0 R >> endobj 1868 0 obj <> /Contents 1869 0 R >> endobj 1873 0 obj <> /Contents 1874 0 R >> endobj 1878 0 obj <> /Contents 1879 0 R >> endobj 1883 0 obj <> /Contents 1884 0 R >> endobj 1888 0 obj <> /Contents 1889 0 R >> endobj 1893 0 obj <> /Contents 1894 0 R >> endobj 1898 0 obj <> /Contents 1899 0 R >> endobj 1903 0 obj <> /Contents 1904 0 R >> endobj 1908 0 obj <> /Contents 1909 0 R >> endobj 1913 0 obj <> /Contents 1914 0 R >> endobj 1918 0 obj <> /Contents 1919 0 R >> endobj 1923 0 obj <> /Contents 1924 0 R >> endobj 1928 0 obj <> /Contents 1929 0 R >> endobj 1933 0 obj <> /Contents 1934 0 R >> endobj 1938 0 obj <> /Contents 1939 0 R >> endobj 1943 0 obj <> /Contents 1944 0 R >> endobj 1948 0 obj <> /Contents 1949 0 R >> endobj 1953 0 obj <> /Contents 1954 0 R >> endobj 1958 0 obj <> /Contents 1959 0 R >> endobj 1963 0 obj <> /Contents 1964 0 R >> endobj 1968 0 obj <> /Contents 1969 0 R >> endobj 1973 0 obj <> /Contents 1974 0 R >> endobj 1978 0 obj <> /Contents 1979 0 R >> endobj 1983 0 obj <> /Contents 1984 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 266 0 R 271 0 R 307 0 R 350 0 R 394 0 R 437 0 R 481 0 R 523 0 R 558 0 R 567 0 R 573 0 R 578 0 R 585 0 R 590 0 R 595 0 R 600 0 R 605 0 R 610 0 R 615 0 R 620 0 R 625 0 R 630 0 R 635 0 R 640 0 R 645 0 R 650 0 R 655 0 R 663 0 R 669 0 R 674 0 R 679 0 R 684 0 R 692 0 R 697 0 R 702 0 R 707 0 R 712 0 R 718 0 R 725 0 R 733 0 R 738 0 R 745 0 R 750 0 R 755 0 R 760 0 R 765 0 R 772 0 R 777 0 R 782 0 R 787 0 R 792 0 R 798 0 R 803 0 R 808 0 R 813 0 R 818 0 R 823 0 R 828 0 R 833 0 R 838 0 R 844 0 R 849 0 R 855 0 R 863 0 R 871 0 R 876 0 R 881 0 R 886 0 R 891 0 R 896 0 R 901 0 R 906 0 R 911 0 R 916 0 R 921 0 R 927 0 R 936 0 R 941 0 R 946 0 R 953 0 R 960 0 R 966 0 R 974 0 R 980 0 R 985 0 R 991 0 R 996 0 R 1001 0 R 1006 0 R 1011 0 R 1016 0 R 1021 0 R 1026 0 R 1031 0 R 1036 0 R 1041 0 R 1046 0 R 1051 0 R 1056 0 R 1061 0 R 1066 0 R 1071 0 R 1076 0 R 1081 0 R 1086 0 R 1091 0 R 1096 0 R 1101 0 R 1107 0 R 1112 0 R 1117 0 R 1122 0 R 1127 0 R 1132 0 R 1137 0 R 1142 0 R 1147 0 R 1152 0 R 1157 0 R 1162 0 R 1167 0 R 1172 0 R 1177 0 R 1182 0 R 1187 0 R 1192 0 R 1197 0 R 1202 0 R 1207 0 R 1212 0 R 1217 0 R 1222 0 R 1227 0 R 1232 0 R 1237 0 R 1242 0 R 1247 0 R 1252 0 R 1257 0 R 1262 0 R 1267 0 R 1273 0 R 1278 0 R 1283 0 R 1288 0 R 1293 0 R 1298 0 R 1303 0 R 1308 0 R 1313 0 R 1318 0 R 1323 0 R 1328 0 R 1333 0 R 1338 0 R 1343 0 R 1349 0 R 1355 0 R 1361 0 R 1367 0 R 1378 0 R 1386 0 R 1393 0 R 1398 0 R 1403 0 R 1410 0 R 1415 0 R 1424 0 R 1429 0 R 1434 0 R 1440 0 R 1445 0 R 1450 0 R 1455 0 R 1460 0 R 1465 0 R 1471 0 R 1477 0 R 1487 0 R 1496 0 R 1503 0 R 1510 0 R 1517 0 R 1522 0 R 1529 0 R 1534 0 R 1557 0 R 1562 0 R 1570 0 R 1578 0 R 1586 0 R 1592 0 R 1598 0 R 1606 0 R 1611 0 R 1616 0 R 1629 0 R 1636 0 R 1644 0 R 1650 0 R 1655 0 R 1660 0 R 1668 0 R 1674 0 R 1681 0 R 1686 0 R 1691 0 R 1704 0 R 1719 0 R 1728 0 R 1733 0 R 1738 0 R 1743 0 R 1749 0 R 1755 0 R 1760 0 R 1765 0 R 1770 0 R 1775 0 R 1780 0 R 1785 0 R 1790 0 R 1795 0 R 1802 0 R 1808 0 R 1816 0 R 1823 0 R 1828 0 R 1833 0 R 1838 0 R 1843 0 R 1848 0 R 1853 0 R 1858 0 R 1863 0 R 1868 0 R 1873 0 R 1878 0 R 1883 0 R 1888 0 R 1893 0 R 1898 0 R 1903 0 R 1908 0 R 1913 0 R 1918 0 R 1923 0 R 1928 0 R 1933 0 R 1938 0 R 1943 0 R 1948 0 R 1953 0 R 1958 0 R 1963 0 R 1968 0 R 1973 0 R 1978 0 R 1983 0 R ] /Count 260 >> endobj 6 0 obj << /Count 5 /First 7 0 R /Last 242 0 R >> endobj 1 0 obj <> 1 << /S /D >>] >> /Metadata 1998 0 R >> endobj 8 0 obj << /Title(Getting Started) /Dest/section.1.1 /Parent 7 0 R /Next 9 0 R >> endobj 9 0 obj << /Title(Sniffer Mode) /Dest/section.1.2 /Parent 7 0 R /Prev 8 0 R /Next 10 0 R >> endobj 10 0 obj << /Title(Packet Logger Mode) /Dest/section.1.3 /Parent 7 0 R /Prev 9 0 R /Next 11 0 R >> endobj 12 0 obj << /Title(NIDS Mode Output Options) /Dest/subsection.1.4.1 /Parent 11 0 R /Next 13 0 R >> endobj 13 0 obj << /Title(Understanding Standard Alert Output) /Dest/subsection.1.4.2 /Parent 11 0 R /Prev 12 0 R /Next 14 0 R >> endobj 14 0 obj << /Title(High Performance Configuration) /Dest/subsection.1.4.3 /Parent 11 0 R /Prev 13 0 R /Next 15 0 R >> endobj 15 0 obj << /Title(Changing Alert Order) /Dest/subsection.1.4.4 /Parent 11 0 R /Prev 14 0 R >> endobj 11 0 obj << /Title(Network Intrusion Detection System Mode) /Dest/section.1.4 /Count -4 /Parent 7 0 R /Prev 10 0 R /Next 16 0 R /First 12 0 R /Last 15 0 R >> endobj 17 0 obj << /Title(Configuration) /Dest/subsection.1.5.1 /Parent 16 0 R /Next 18 0 R >> endobj 18 0 obj << /Title(pcap) /Dest/subsection.1.5.2 /Parent 16 0 R /Prev 17 0 R /Next 19 0 R >> endobj 19 0 obj << /Title(AFPACKET) /Dest/subsection.1.5.3 /Parent 16 0 R /Prev 18 0 R /Next 20 0 R >> endobj 20 0 obj << /Title(NFQ) /Dest/subsection.1.5.4 /Parent 16 0 R /Prev 19 0 R /Next 21 0 R >> endobj 21 0 obj << /Title(IPQ) /Dest/subsection.1.5.5 /Parent 16 0 R /Prev 20 0 R /Next 22 0 R >> endobj 22 0 obj << /Title(IPFW) /Dest/subsection.1.5.6 /Parent 16 0 R /Prev 21 0 R /Next 23 0 R >> endobj 23 0 obj << /Title(Dump) /Dest/subsection.1.5.7 /Parent 16 0 R /Prev 22 0 R /Next 24 0 R >> endobj 24 0 obj << /Title(Statistics Changes) /Dest/subsection.1.5.8 /Parent 16 0 R /Prev 23 0 R >> endobj 16 0 obj << /Title(Packet Acquisition) /Dest/section.1.5 /Count -8 /Parent 7 0 R /Prev 11 0 R /Next 25 0 R /First 17 0 R /Last 24 0 R >> endobj 26 0 obj << /Title(Command line arguments) /Dest/subsection.1.6.1 /Parent 25 0 R /Next 27 0 R >> endobj 27 0 obj << /Title(Examples) /Dest/subsection.1.6.2 /Parent 25 0 R /Prev 26 0 R >> endobj 25 0 obj << /Title(Reading pcap files) /Dest/section.1.6 /Count -2 /Parent 7 0 R /Prev 16 0 R /Next 28 0 R /First 26 0 R /Last 27 0 R >> endobj 29 0 obj << /Title(Timing Statistics) /Dest/subsection.1.7.1 /Parent 28 0 R /Next 30 0 R >> endobj 30 0 obj << /Title(Packet I/O Totals) /Dest/subsection.1.7.2 /Parent 28 0 R /Prev 29 0 R /Next 31 0 R >> endobj 31 0 obj << /Title(Protocol Statistics) /Dest/subsection.1.7.3 /Parent 28 0 R /Prev 30 0 R /Next 32 0 R >> endobj 32 0 obj << /Title(Snort Memory Statistics) /Dest/subsection.1.7.4 /Parent 28 0 R /Prev 31 0 R /Next 33 0 R >> endobj 33 0 obj << /Title(Actions, Limits, and Verdicts) /Dest/subsection.1.7.5 /Parent 28 0 R /Prev 32 0 R >> endobj 28 0 obj << /Title(Basic Output) /Dest/section.1.7 /Count -5 /Parent 7 0 R /Prev 25 0 R /Next 34 0 R /First 29 0 R /Last 33 0 R >> endobj 35 0 obj << /Title(Multiple Encapsulations) /Dest/subsection.1.8.1 /Parent 34 0 R /Next 36 0 R >> endobj 36 0 obj << /Title(Logging) /Dest/subsection.1.8.2 /Parent 34 0 R /Prev 35 0 R >> endobj 34 0 obj << /Title(Tunneling Protocol Support) /Dest/section.1.8 /Count -2 /Parent 7 0 R /Prev 28 0 R /Next 37 0 R /First 35 0 R /Last 36 0 R >> endobj 38 0 obj << /Title(Running Snort as a Daemon) /Dest/subsection.1.9.1 /Parent 37 0 R /Next 39 0 R >> endobj 39 0 obj << /Title(Running in Rule Stub Creation Mode) /Dest/subsection.1.9.2 /Parent 37 0 R /Prev 38 0 R /Next 40 0 R >> endobj 40 0 obj << /Title(Obfuscating IP Address Printouts) /Dest/subsection.1.9.3 /Parent 37 0 R /Prev 39 0 R /Next 41 0 R >> endobj 41 0 obj << /Title(Specifying Multiple-Instance Identifiers) /Dest/subsection.1.9.4 /Parent 37 0 R /Prev 40 0 R /Next 42 0 R >> endobj 42 0 obj << /Title(Snort Modes) /Dest/subsection.1.9.5 /Parent 37 0 R /Prev 41 0 R >> endobj 37 0 obj << /Title(Miscellaneous) /Dest/section.1.9 /Count -5 /Parent 7 0 R /Prev 34 0 R /Next 43 0 R /First 38 0 R /Last 42 0 R >> endobj 43 0 obj << /Title(Control socket) /Dest/section.1.10 /Parent 7 0 R /Prev 37 0 R /Next 44 0 R >> endobj 44 0 obj << /Title(Configure signal value) /Dest/section.1.11 /Parent 7 0 R /Prev 43 0 R /Next 45 0 R >> endobj 45 0 obj << /Title(More Information) /Dest/section.1.12 /Parent 7 0 R /Prev 44 0 R >> endobj 7 0 obj << /Title(Snort Overview) /Dest/chapter.1 /Count -12 /Parent 6 0 R /Next 46 0 R /First 8 0 R /Last 45 0 R >> endobj 48 0 obj << /Title(Format) /Dest/subsection.2.1.1 /Parent 47 0 R /Next 49 0 R >> endobj 49 0 obj << /Title(Variables) /Dest/subsection.2.1.2 /Parent 47 0 R /Prev 48 0 R /Next 50 0 R >> endobj 50 0 obj << /Title(Config) /Dest/subsection.2.1.3 /Parent 47 0 R /Prev 49 0 R >> endobj 47 0 obj << /Title(Includes) /Dest/section.2.1 /Count -3 /Parent 46 0 R /Next 51 0 R /First 48 0 R /Last 50 0 R >> endobj 52 0 obj << /Title(Frag3) /Dest/subsection.2.2.1 /Parent 51 0 R /Next 53 0 R >> endobj 53 0 obj << /Title(Stream5) /Dest/subsection.2.2.2 /Parent 51 0 R /Prev 52 0 R /Next 54 0 R >> endobj 54 0 obj << /Title(sfPortscan) /Dest/subsection.2.2.3 /Parent 51 0 R /Prev 53 0 R /Next 55 0 R >> endobj 55 0 obj << /Title(RPC Decode) /Dest/subsection.2.2.4 /Parent 51 0 R /Prev 54 0 R /Next 56 0 R >> endobj 56 0 obj << /Title(Performance Monitor) /Dest/subsection.2.2.5 /Parent 51 0 R /Prev 55 0 R /Next 57 0 R >> endobj 57 0 obj << /Title(HTTP Inspect) /Dest/subsection.2.2.6 /Parent 51 0 R /Prev 56 0 R /Next 58 0 R >> endobj 58 0 obj << /Title(SMTP Preprocessor) /Dest/subsection.2.2.7 /Parent 51 0 R /Prev 57 0 R /Next 59 0 R >> endobj 59 0 obj << /Title(POP Preprocessor) /Dest/subsection.2.2.8 /Parent 51 0 R /Prev 58 0 R /Next 60 0 R >> endobj 60 0 obj << /Title(IMAP Preprocessor) /Dest/subsection.2.2.9 /Parent 51 0 R /Prev 59 0 R /Next 61 0 R >> endobj 61 0 obj << /Title(FTP/Telnet Preprocessor) /Dest/subsection.2.2.10 /Parent 51 0 R /Prev 60 0 R /Next 62 0 R >> endobj 62 0 obj << /Title(SSH) /Dest/subsection.2.2.11 /Parent 51 0 R /Prev 61 0 R /Next 63 0 R >> endobj 63 0 obj << /Title(DNS) /Dest/subsection.2.2.12 /Parent 51 0 R /Prev 62 0 R /Next 64 0 R >> endobj 64 0 obj << /Title(SSL/TLS) /Dest/subsection.2.2.13 /Parent 51 0 R /Prev 63 0 R /Next 65 0 R >> endobj 65 0 obj << /Title(ARP Spoof Preprocessor) /Dest/subsection.2.2.14 /Parent 51 0 R /Prev 64 0 R /Next 66 0 R >> endobj 66 0 obj << /Title(DCE/RPC 2 Preprocessor) /Dest/subsection.2.2.15 /Parent 51 0 R /Prev 65 0 R /Next 67 0 R >> endobj 67 0 obj << /Title(Sensitive Data Preprocessor) /Dest/subsection.2.2.16 /Parent 51 0 R /Prev 66 0 R /Next 68 0 R >> endobj 68 0 obj << /Title(Normalizer) /Dest/subsection.2.2.17 /Parent 51 0 R /Prev 67 0 R /Next 69 0 R >> endobj 69 0 obj << /Title(SIP Preprocessor) /Dest/subsection.2.2.18 /Parent 51 0 R /Prev 68 0 R /Next 70 0 R >> endobj 70 0 obj << /Title(Reputation Preprocessor) /Dest/subsection.2.2.19 /Parent 51 0 R /Prev 69 0 R /Next 71 0 R >> endobj 71 0 obj << /Title(GTP Decoder and Preprocessor) /Dest/subsection.2.2.20 /Parent 51 0 R /Prev 70 0 R /Next 72 0 R >> endobj 72 0 obj << /Title(Modbus Preprocessor) /Dest/subsection.2.2.21 /Parent 51 0 R /Prev 71 0 R /Next 73 0 R >> endobj 73 0 obj << /Title(DNP3 Preprocessor) /Dest/subsection.2.2.22 /Parent 51 0 R /Prev 72 0 R >> endobj 51 0 obj << /Title(Preprocessors) /Dest/section.2.2 /Count -22 /Parent 46 0 R /Prev 47 0 R /Next 74 0 R /First 52 0 R /Last 73 0 R >> endobj 75 0 obj << /Title(Configuring) /Dest/subsection.2.3.1 /Parent 74 0 R /Next 76 0 R >> endobj 76 0 obj << /Title(Reverting to original behavior) /Dest/subsection.2.3.2 /Parent 74 0 R /Prev 75 0 R >> endobj 74 0 obj << /Title(Decoder and Preprocessor Rules) /Dest/section.2.3 /Count -2 /Parent 46 0 R /Prev 51 0 R /Next 77 0 R /First 75 0 R /Last 76 0 R >> endobj 78 0 obj << /Title(Rate Filtering) /Dest/subsection.2.4.1 /Parent 77 0 R /Next 79 0 R >> endobj 79 0 obj << /Title(Event Filtering) /Dest/subsection.2.4.2 /Parent 77 0 R /Prev 78 0 R /Next 80 0 R >> endobj 80 0 obj << /Title(Event Suppression) /Dest/subsection.2.4.3 /Parent 77 0 R /Prev 79 0 R /Next 81 0 R >> endobj 81 0 obj << /Title(Event Logging) /Dest/subsection.2.4.4 /Parent 77 0 R /Prev 80 0 R /Next 82 0 R >> endobj 82 0 obj << /Title(Event Trace) /Dest/subsection.2.4.5 /Parent 77 0 R /Prev 81 0 R >> endobj 77 0 obj << /Title(Event Processing) /Dest/section.2.4 /Count -5 /Parent 46 0 R /Prev 74 0 R /Next 83 0 R /First 78 0 R /Last 82 0 R >> endobj 84 0 obj << /Title(Rule Profiling) /Dest/subsection.2.5.1 /Parent 83 0 R /Next 85 0 R >> endobj 85 0 obj << /Title(Preprocessor Profiling) /Dest/subsection.2.5.2 /Parent 83 0 R /Prev 84 0 R /Next 86 0 R >> endobj 86 0 obj << /Title(Packet Performance Monitoring \(PPM\)) /Dest/subsection.2.5.3 /Parent 83 0 R /Prev 85 0 R >> endobj 83 0 obj << /Title(Performance Profiling) /Dest/section.2.5 /Count -3 /Parent 46 0 R /Prev 77 0 R /Next 87 0 R /First 84 0 R /Last 86 0 R >> endobj 88 0 obj << /Title(alert_syslog) /Dest/subsection.2.6.1 /Parent 87 0 R /Next 89 0 R >> endobj 89 0 obj << /Title(alert_fast) /Dest/subsection.2.6.2 /Parent 87 0 R /Prev 88 0 R /Next 90 0 R >> endobj 90 0 obj << /Title(alert_full) /Dest/subsection.2.6.3 /Parent 87 0 R /Prev 89 0 R /Next 91 0 R >> endobj 91 0 obj << /Title(alert_unixsock) /Dest/subsection.2.6.4 /Parent 87 0 R /Prev 90 0 R /Next 92 0 R >> endobj 92 0 obj << /Title(log_tcpdump) /Dest/subsection.2.6.5 /Parent 87 0 R /Prev 91 0 R /Next 93 0 R >> endobj 93 0 obj << /Title(csv) /Dest/subsection.2.6.6 /Parent 87 0 R /Prev 92 0 R /Next 94 0 R >> endobj 94 0 obj << /Title(unified 2) /Dest/subsection.2.6.7 /Parent 87 0 R /Prev 93 0 R /Next 95 0 R >> endobj 95 0 obj << /Title(log null) /Dest/subsection.2.6.8 /Parent 87 0 R /Prev 94 0 R /Next 96 0 R >> endobj 96 0 obj << /Title(Log Limits) /Dest/subsection.2.6.9 /Parent 87 0 R /Prev 95 0 R >> endobj 87 0 obj << /Title(Output Modules) /Dest/section.2.6 /Count -9 /Parent 46 0 R /Prev 83 0 R /Next 97 0 R /First 88 0 R /Last 96 0 R >> endobj 98 0 obj << /Title(Configuration Format) /Dest/subsection.2.7.1 /Parent 97 0 R /Next 99 0 R >> endobj 99 0 obj << /Title(Attribute Table File Format) /Dest/subsection.2.7.2 /Parent 97 0 R /Prev 98 0 R /Next 100 0 R >> endobj 100 0 obj << /Title(Attribute Table Example) /Dest/subsection.2.7.3 /Parent 97 0 R /Prev 99 0 R >> endobj 97 0 obj << /Title(Host Attribute Table) /Dest/section.2.7 /Count -3 /Parent 46 0 R /Prev 87 0 R /Next 101 0 R /First 98 0 R /Last 100 0 R >> endobj 102 0 obj << /Title(Format) /Dest/subsection.2.8.1 /Parent 101 0 R /Next 103 0 R >> endobj 103 0 obj << /Title(Directives) /Dest/subsection.2.8.2 /Parent 101 0 R /Prev 102 0 R >> endobj 101 0 obj << /Title(Dynamic Modules) /Dest/section.2.8 /Count -2 /Parent 46 0 R /Prev 97 0 R /Next 104 0 R /First 102 0 R /Last 103 0 R >> endobj 105 0 obj << /Title(Enabling support) /Dest/subsection.2.9.1 /Parent 104 0 R /Next 106 0 R >> endobj 106 0 obj << /Title(Reloading a configuration) /Dest/subsection.2.9.2 /Parent 104 0 R /Prev 105 0 R /Next 107 0 R >> endobj 107 0 obj << /Title(Non-reloadable configuration options) /Dest/subsection.2.9.3 /Parent 104 0 R /Prev 106 0 R >> endobj 104 0 obj << /Title(Reloading a Snort Configuration) /Dest/section.2.9 /Count -3 /Parent 46 0 R /Prev 101 0 R /Next 108 0 R /First 105 0 R /Last 107 0 R >> endobj 109 0 obj << /Title(Creating Multiple Configurations) /Dest/subsection.2.10.1 /Parent 108 0 R /Next 110 0 R >> endobj 110 0 obj << /Title(Configuration Specific Elements) /Dest/subsection.2.10.2 /Parent 108 0 R /Prev 109 0 R /Next 111 0 R >> endobj 111 0 obj << /Title(How Configuration is applied?) /Dest/subsection.2.10.3 /Parent 108 0 R /Prev 110 0 R >> endobj 108 0 obj << /Title(Multiple Configurations) /Dest/section.2.10 /Count -3 /Parent 46 0 R /Prev 104 0 R /Next 112 0 R /First 109 0 R /Last 111 0 R >> endobj 113 0 obj << /Title(Enabling Active Response) /Dest/subsection.2.11.1 /Parent 112 0 R /Next 114 0 R >> endobj 114 0 obj << /Title(Configure Sniping) /Dest/subsection.2.11.2 /Parent 112 0 R /Prev 113 0 R /Next 115 0 R >> endobj 115 0 obj << /Title(Flexresp) /Dest/subsection.2.11.3 /Parent 112 0 R /Prev 114 0 R /Next 116 0 R >> endobj 116 0 obj << /Title(React) /Dest/subsection.2.11.4 /Parent 112 0 R /Prev 115 0 R /Next 117 0 R >> endobj 117 0 obj << /Title(Rule Actions) /Dest/subsection.2.11.5 /Parent 112 0 R /Prev 116 0 R >> endobj 112 0 obj << /Title(Active Response) /Dest/section.2.11 /Count -5 /Parent 46 0 R /Prev 108 0 R /First 113 0 R /Last 117 0 R >> endobj 46 0 obj << /Title(Configuring Snort) /Dest/chapter.2 /Count -11 /Parent 6 0 R /Prev 7 0 R /Next 118 0 R /First 47 0 R /Last 112 0 R >> endobj 119 0 obj << /Title(The Basics) /Dest/section.3.1 /Parent 118 0 R /Next 120 0 R >> endobj 121 0 obj << /Title(Rule Actions) /Dest/subsection.3.2.1 /Parent 120 0 R /Next 122 0 R >> endobj 122 0 obj << /Title(Protocols) /Dest/subsection.3.2.2 /Parent 120 0 R /Prev 121 0 R /Next 123 0 R >> endobj 123 0 obj << /Title(IP Addresses) /Dest/subsection.3.2.3 /Parent 120 0 R /Prev 122 0 R /Next 124 0 R >> endobj 124 0 obj << /Title(Port Numbers) /Dest/subsection.3.2.4 /Parent 120 0 R /Prev 123 0 R /Next 125 0 R >> endobj 125 0 obj << /Title(The Direction Operator) /Dest/subsection.3.2.5 /Parent 120 0 R /Prev 124 0 R /Next 126 0 R >> endobj 126 0 obj << /Title(Activate/Dynamic Rules) /Dest/subsection.3.2.6 /Parent 120 0 R /Prev 125 0 R >> endobj 120 0 obj << /Title(Rules Headers) /Dest/section.3.2 /Count -6 /Parent 118 0 R /Prev 119 0 R /Next 127 0 R /First 121 0 R /Last 126 0 R >> endobj 127 0 obj << /Title(Rule Options) /Dest/section.3.3 /Parent 118 0 R /Prev 120 0 R /Next 128 0 R >> endobj 129 0 obj << /Title(msg) /Dest/subsection.3.4.1 /Parent 128 0 R /Next 130 0 R >> endobj 130 0 obj << /Title(reference) /Dest/subsection.3.4.2 /Parent 128 0 R /Prev 129 0 R /Next 131 0 R >> endobj 131 0 obj << /Title(gid) /Dest/subsection.3.4.3 /Parent 128 0 R /Prev 130 0 R /Next 132 0 R >> endobj 132 0 obj << /Title(sid) /Dest/subsection.3.4.4 /Parent 128 0 R /Prev 131 0 R /Next 133 0 R >> endobj 133 0 obj << /Title(rev) /Dest/subsection.3.4.5 /Parent 128 0 R /Prev 132 0 R /Next 134 0 R >> endobj 134 0 obj << /Title(classtype) /Dest/subsection.3.4.6 /Parent 128 0 R /Prev 133 0 R /Next 135 0 R >> endobj 135 0 obj << /Title(priority) /Dest/subsection.3.4.7 /Parent 128 0 R /Prev 134 0 R /Next 136 0 R >> endobj 136 0 obj << /Title(metadata) /Dest/subsection.3.4.8 /Parent 128 0 R /Prev 135 0 R /Next 137 0 R >> endobj 137 0 obj << /Title(General Rule Quick Reference) /Dest/subsection.3.4.9 /Parent 128 0 R /Prev 136 0 R >> endobj 128 0 obj << /Title(General Rule Options) /Dest/section.3.4 /Count -9 /Parent 118 0 R /Prev 127 0 R /Next 138 0 R /First 129 0 R /Last 137 0 R >> endobj 139 0 obj << /Title(content) /Dest/subsection.3.5.1 /Parent 138 0 R /Next 140 0 R >> endobj 140 0 obj << /Title(nocase) /Dest/subsection.3.5.2 /Parent 138 0 R /Prev 139 0 R /Next 141 0 R >> endobj 141 0 obj << /Title(rawbytes) /Dest/subsection.3.5.3 /Parent 138 0 R /Prev 140 0 R /Next 142 0 R >> endobj 142 0 obj << /Title(depth) /Dest/subsection.3.5.4 /Parent 138 0 R /Prev 141 0 R /Next 143 0 R >> endobj 143 0 obj << /Title(offset) /Dest/subsection.3.5.5 /Parent 138 0 R /Prev 142 0 R /Next 144 0 R >> endobj 144 0 obj << /Title(distance) /Dest/subsection.3.5.6 /Parent 138 0 R /Prev 143 0 R /Next 145 0 R >> endobj 145 0 obj << /Title(within) /Dest/subsection.3.5.7 /Parent 138 0 R /Prev 144 0 R /Next 146 0 R >> endobj 146 0 obj << /Title(http_client_body) /Dest/subsection.3.5.8 /Parent 138 0 R /Prev 145 0 R /Next 147 0 R >> endobj 147 0 obj << /Title(http_cookie) /Dest/subsection.3.5.9 /Parent 138 0 R /Prev 146 0 R /Next 148 0 R >> endobj 148 0 obj << /Title(http_raw_cookie) /Dest/subsection.3.5.10 /Parent 138 0 R /Prev 147 0 R /Next 149 0 R >> endobj 149 0 obj << /Title(http_header) /Dest/subsection.3.5.11 /Parent 138 0 R /Prev 148 0 R /Next 150 0 R >> endobj 150 0 obj << /Title(http_raw_header) /Dest/subsection.3.5.12 /Parent 138 0 R /Prev 149 0 R /Next 151 0 R >> endobj 151 0 obj << /Title(http_method) /Dest/subsection.3.5.13 /Parent 138 0 R /Prev 150 0 R /Next 152 0 R >> endobj 152 0 obj << /Title(http_uri) /Dest/subsection.3.5.14 /Parent 138 0 R /Prev 151 0 R /Next 153 0 R >> endobj 153 0 obj << /Title(http_raw_uri) /Dest/subsection.3.5.15 /Parent 138 0 R /Prev 152 0 R /Next 154 0 R >> endobj 154 0 obj << /Title(http_stat_code) /Dest/subsection.3.5.16 /Parent 138 0 R /Prev 153 0 R /Next 155 0 R >> endobj 155 0 obj << /Title(http_stat_msg) /Dest/subsection.3.5.17 /Parent 138 0 R /Prev 154 0 R /Next 156 0 R >> endobj 156 0 obj << /Title(http_encode) /Dest/subsection.3.5.18 /Parent 138 0 R /Prev 155 0 R /Next 157 0 R >> endobj 157 0 obj << /Title(fast_pattern) /Dest/subsection.3.5.19 /Parent 138 0 R /Prev 156 0 R /Next 158 0 R >> endobj 158 0 obj << /Title(uricontent) /Dest/subsection.3.5.20 /Parent 138 0 R /Prev 157 0 R /Next 159 0 R >> endobj 159 0 obj << /Title(urilen) /Dest/subsection.3.5.21 /Parent 138 0 R /Prev 158 0 R /Next 160 0 R >> endobj 160 0 obj << /Title(isdataat) /Dest/subsection.3.5.22 /Parent 138 0 R /Prev 159 0 R /Next 161 0 R >> endobj 161 0 obj << /Title(pcre) /Dest/subsection.3.5.23 /Parent 138 0 R /Prev 160 0 R /Next 162 0 R >> endobj 162 0 obj << /Title(pkt_data) /Dest/subsection.3.5.24 /Parent 138 0 R /Prev 161 0 R /Next 163 0 R >> endobj 163 0 obj << /Title(file_data) /Dest/subsection.3.5.25 /Parent 138 0 R /Prev 162 0 R /Next 164 0 R >> endobj 164 0 obj << /Title(base64_decode) /Dest/subsection.3.5.26 /Parent 138 0 R /Prev 163 0 R /Next 165 0 R >> endobj 165 0 obj << /Title(base64_data) /Dest/subsection.3.5.27 /Parent 138 0 R /Prev 164 0 R /Next 166 0 R >> endobj 166 0 obj << /Title(byte_test) /Dest/subsection.3.5.28 /Parent 138 0 R /Prev 165 0 R /Next 167 0 R >> endobj 167 0 obj << /Title(byte_jump) /Dest/subsection.3.5.29 /Parent 138 0 R /Prev 166 0 R /Next 168 0 R >> endobj 168 0 obj << /Title(byte_extract) /Dest/subsection.3.5.30 /Parent 138 0 R /Prev 167 0 R /Next 169 0 R >> endobj 169 0 obj << /Title(ftpbounce) /Dest/subsection.3.5.31 /Parent 138 0 R /Prev 168 0 R /Next 170 0 R >> endobj 170 0 obj << /Title(asn1) /Dest/subsection.3.5.32 /Parent 138 0 R /Prev 169 0 R /Next 171 0 R >> endobj 171 0 obj << /Title(cvs) /Dest/subsection.3.5.33 /Parent 138 0 R /Prev 170 0 R /Next 172 0 R >> endobj 172 0 obj << /Title(dce_iface) /Dest/subsection.3.5.34 /Parent 138 0 R /Prev 171 0 R /Next 173 0 R >> endobj 173 0 obj << /Title(dce_opnum) /Dest/subsection.3.5.35 /Parent 138 0 R /Prev 172 0 R /Next 174 0 R >> endobj 174 0 obj << /Title(dce_stub_data) /Dest/subsection.3.5.36 /Parent 138 0 R /Prev 173 0 R /Next 175 0 R >> endobj 175 0 obj << /Title(sip_method) /Dest/subsection.3.5.37 /Parent 138 0 R /Prev 174 0 R /Next 176 0 R >> endobj 176 0 obj << /Title(sip_stat_code) /Dest/subsection.3.5.38 /Parent 138 0 R /Prev 175 0 R /Next 177 0 R >> endobj 177 0 obj << /Title(sip_header) /Dest/subsection.3.5.39 /Parent 138 0 R /Prev 176 0 R /Next 178 0 R >> endobj 178 0 obj << /Title(sip_body) /Dest/subsection.3.5.40 /Parent 138 0 R /Prev 177 0 R /Next 179 0 R >> endobj 179 0 obj << /Title(gtp_type) /Dest/subsection.3.5.41 /Parent 138 0 R /Prev 178 0 R /Next 180 0 R >> endobj 180 0 obj << /Title(gtp_info) /Dest/subsection.3.5.42 /Parent 138 0 R /Prev 179 0 R /Next 181 0 R >> endobj 181 0 obj << /Title(gtp_version) /Dest/subsection.3.5.43 /Parent 138 0 R /Prev 180 0 R /Next 182 0 R >> endobj 182 0 obj << /Title(ssl_version) /Dest/subsection.3.5.44 /Parent 138 0 R /Prev 181 0 R /Next 183 0 R >> endobj 183 0 obj << /Title(ssl_state) /Dest/subsection.3.5.45 /Parent 138 0 R /Prev 182 0 R /Next 184 0 R >> endobj 184 0 obj << /Title(Payload Detection Quick Reference) /Dest/subsection.3.5.46 /Parent 138 0 R /Prev 183 0 R >> endobj 138 0 obj << /Title(Payload Detection Rule Options) /Dest/section.3.5 /Count -46 /Parent 118 0 R /Prev 128 0 R /Next 185 0 R /First 139 0 R /Last 184 0 R >> endobj 186 0 obj << /Title(fragoffset) /Dest/subsection.3.6.1 /Parent 185 0 R /Next 187 0 R >> endobj 187 0 obj << /Title(ttl) /Dest/subsection.3.6.2 /Parent 185 0 R /Prev 186 0 R /Next 188 0 R >> endobj 188 0 obj << /Title(tos) /Dest/subsection.3.6.3 /Parent 185 0 R /Prev 187 0 R /Next 189 0 R >> endobj 189 0 obj << /Title(id) /Dest/subsection.3.6.4 /Parent 185 0 R /Prev 188 0 R /Next 190 0 R >> endobj 190 0 obj << /Title(ipopts) /Dest/subsection.3.6.5 /Parent 185 0 R /Prev 189 0 R /Next 191 0 R >> endobj 191 0 obj << /Title(fragbits) /Dest/subsection.3.6.6 /Parent 185 0 R /Prev 190 0 R /Next 192 0 R >> endobj 192 0 obj << /Title(dsize) /Dest/subsection.3.6.7 /Parent 185 0 R /Prev 191 0 R /Next 193 0 R >> endobj 193 0 obj << /Title(flags) /Dest/subsection.3.6.8 /Parent 185 0 R /Prev 192 0 R /Next 194 0 R >> endobj 194 0 obj << /Title(flow) /Dest/subsection.3.6.9 /Parent 185 0 R /Prev 193 0 R /Next 195 0 R >> endobj 195 0 obj << /Title(flowbits) /Dest/subsection.3.6.10 /Parent 185 0 R /Prev 194 0 R /Next 196 0 R >> endobj 196 0 obj << /Title(seq) /Dest/subsection.3.6.11 /Parent 185 0 R /Prev 195 0 R /Next 197 0 R >> endobj 197 0 obj << /Title(ack) /Dest/subsection.3.6.12 /Parent 185 0 R /Prev 196 0 R /Next 198 0 R >> endobj 198 0 obj << /Title(window) /Dest/subsection.3.6.13 /Parent 185 0 R /Prev 197 0 R /Next 199 0 R >> endobj 199 0 obj << /Title(itype) /Dest/subsection.3.6.14 /Parent 185 0 R /Prev 198 0 R /Next 200 0 R >> endobj 200 0 obj << /Title(icode) /Dest/subsection.3.6.15 /Parent 185 0 R /Prev 199 0 R /Next 201 0 R >> endobj 201 0 obj << /Title(icmp_id) /Dest/subsection.3.6.16 /Parent 185 0 R /Prev 200 0 R /Next 202 0 R >> endobj 202 0 obj << /Title(icmp_seq) /Dest/subsection.3.6.17 /Parent 185 0 R /Prev 201 0 R /Next 203 0 R >> endobj 203 0 obj << /Title(rpc) /Dest/subsection.3.6.18 /Parent 185 0 R /Prev 202 0 R /Next 204 0 R >> endobj 204 0 obj << /Title(ip_proto) /Dest/subsection.3.6.19 /Parent 185 0 R /Prev 203 0 R /Next 205 0 R >> endobj 205 0 obj << /Title(sameip) /Dest/subsection.3.6.20 /Parent 185 0 R /Prev 204 0 R /Next 206 0 R >> endobj 206 0 obj << /Title(stream_reassemble) /Dest/subsection.3.6.21 /Parent 185 0 R /Prev 205 0 R /Next 207 0 R >> endobj 207 0 obj << /Title(stream_size) /Dest/subsection.3.6.22 /Parent 185 0 R /Prev 206 0 R /Next 208 0 R >> endobj 208 0 obj << /Title(Non-Payload Detection Quick Reference) /Dest/subsection.3.6.23 /Parent 185 0 R /Prev 207 0 R >> endobj 185 0 obj << /Title(Non-Payload Detection Rule Options) /Dest/section.3.6 /Count -23 /Parent 118 0 R /Prev 138 0 R /Next 209 0 R /First 186 0 R /Last 208 0 R >> endobj 210 0 obj << /Title(logto) /Dest/subsection.3.7.1 /Parent 209 0 R /Next 211 0 R >> endobj 211 0 obj << /Title(session) /Dest/subsection.3.7.2 /Parent 209 0 R /Prev 210 0 R /Next 212 0 R >> endobj 212 0 obj << /Title(resp) /Dest/subsection.3.7.3 /Parent 209 0 R /Prev 211 0 R /Next 213 0 R >> endobj 213 0 obj << /Title(react) /Dest/subsection.3.7.4 /Parent 209 0 R /Prev 212 0 R /Next 214 0 R >> endobj 214 0 obj << /Title(tag) /Dest/subsection.3.7.5 /Parent 209 0 R /Prev 213 0 R /Next 215 0 R >> endobj 215 0 obj << /Title(activates) /Dest/subsection.3.7.6 /Parent 209 0 R /Prev 214 0 R /Next 216 0 R >> endobj 216 0 obj << /Title(activated_by) /Dest/subsection.3.7.7 /Parent 209 0 R /Prev 215 0 R /Next 217 0 R >> endobj 217 0 obj << /Title(count) /Dest/subsection.3.7.8 /Parent 209 0 R /Prev 216 0 R /Next 218 0 R >> endobj 218 0 obj << /Title(replace) /Dest/subsection.3.7.9 /Parent 209 0 R /Prev 217 0 R /Next 219 0 R >> endobj 219 0 obj << /Title(detection_filter) /Dest/subsection.3.7.10 /Parent 209 0 R /Prev 218 0 R /Next 220 0 R >> endobj 220 0 obj << /Title(Post-Detection Quick Reference) /Dest/subsection.3.7.11 /Parent 209 0 R /Prev 219 0 R >> endobj 209 0 obj << /Title(Post-Detection Rule Options) /Dest/section.3.7 /Count -11 /Parent 118 0 R /Prev 185 0 R /Next 221 0 R /First 210 0 R /Last 220 0 R >> endobj 221 0 obj << /Title(Rule Thresholds) /Dest/section.3.8 /Parent 118 0 R /Prev 209 0 R /Next 222 0 R >> endobj 223 0 obj << /Title(Content Matching) /Dest/subsection.3.9.1 /Parent 222 0 R /Next 224 0 R >> endobj 224 0 obj << /Title(Catch the Vulnerability, Not the Exploit) /Dest/subsection.3.9.2 /Parent 222 0 R /Prev 223 0 R /Next 225 0 R >> endobj 225 0 obj << /Title(Catch the Oddities of the Protocol in the Rule) /Dest/subsection.3.9.3 /Parent 222 0 R /Prev 224 0 R /Next 226 0 R >> endobj 226 0 obj << /Title(Optimizing Rules) /Dest/subsection.3.9.4 /Parent 222 0 R /Prev 225 0 R /Next 227 0 R >> endobj 227 0 obj << /Title(Testing Numerical Values) /Dest/subsection.3.9.5 /Parent 222 0 R /Prev 226 0 R >> endobj 222 0 obj << /Title(Writing Good Rules) /Dest/section.3.9 /Count -5 /Parent 118 0 R /Prev 221 0 R /First 223 0 R /Last 227 0 R >> endobj 118 0 obj << /Title(Writing Snort Rules) /Dest/chapter.3 /Count -9 /Parent 6 0 R /Prev 46 0 R /Next 228 0 R /First 119 0 R /Last 222 0 R >> endobj 230 0 obj << /Title(DynamicPluginMeta) /Dest/subsection.4.1.1 /Parent 229 0 R /Next 231 0 R >> endobj 231 0 obj << /Title(DynamicPreprocessorData) /Dest/subsection.4.1.2 /Parent 229 0 R /Prev 230 0 R /Next 232 0 R >> endobj 232 0 obj << /Title(DynamicEngineData) /Dest/subsection.4.1.3 /Parent 229 0 R /Prev 231 0 R /Next 233 0 R >> endobj 233 0 obj << /Title(SFSnortPacket) /Dest/subsection.4.1.4 /Parent 229 0 R /Prev 232 0 R /Next 234 0 R >> endobj 234 0 obj << /Title(Dynamic Rules) /Dest/subsection.4.1.5 /Parent 229 0 R /Prev 233 0 R >> endobj 229 0 obj << /Title(Data Structures) /Dest/section.4.1 /Count -5 /Parent 228 0 R /Next 235 0 R /First 230 0 R /Last 234 0 R >> endobj 236 0 obj << /Title(Preprocessors) /Dest/subsection.4.2.1 /Parent 235 0 R /Next 237 0 R >> endobj 237 0 obj << /Title(Detection Engine) /Dest/subsection.4.2.2 /Parent 235 0 R /Prev 236 0 R /Next 238 0 R >> endobj 238 0 obj << /Title(Rules) /Dest/subsection.4.2.3 /Parent 235 0 R /Prev 237 0 R >> endobj 235 0 obj << /Title(Required Functions) /Dest/section.4.2 /Count -3 /Parent 228 0 R /Prev 229 0 R /Next 239 0 R /First 236 0 R /Last 238 0 R >> endobj 240 0 obj << /Title(Preprocessor Example) /Dest/subsection.4.3.1 /Parent 239 0 R /Next 241 0 R >> endobj 241 0 obj << /Title(Rules) /Dest/subsection.4.3.2 /Parent 239 0 R /Prev 240 0 R >> endobj 239 0 obj << /Title(Examples) /Dest/section.4.3 /Count -2 /Parent 228 0 R /Prev 235 0 R /First 240 0 R /Last 241 0 R >> endobj 228 0 obj << /Title(Dynamic Modules) /Dest/chapter.4 /Count -3 /Parent 6 0 R /Prev 118 0 R /Next 242 0 R /First 229 0 R /Last 239 0 R >> endobj 243 0 obj << /Title(Submitting Patches) /Dest/section.5.1 /Parent 242 0 R /Next 244 0 R >> endobj 245 0 obj << /Title(Preprocessors) /Dest/subsection.5.2.1 /Parent 244 0 R /Next 246 0 R >> endobj 246 0 obj << /Title(Detection Plugins) /Dest/subsection.5.2.2 /Parent 244 0 R /Prev 245 0 R /Next 247 0 R >> endobj 247 0 obj << /Title(Output Plugins) /Dest/subsection.5.2.3 /Parent 244 0 R /Prev 246 0 R >> endobj 244 0 obj << /Title(Snort Data Flow) /Dest/section.5.2 /Count -3 /Parent 242 0 R /Prev 243 0 R /Next 248 0 R /First 245 0 R /Last 247 0 R >> endobj 249 0 obj << /Title(Serial Unified2 Header) /Dest/subsection.5.3.1 /Parent 248 0 R /Next 250 0 R >> endobj 250 0 obj << /Title(Unified2 Packet) /Dest/subsection.5.3.2 /Parent 248 0 R /Prev 249 0 R /Next 251 0 R >> endobj 251 0 obj << /Title(Unified2 IDS Event) /Dest/subsection.5.3.3 /Parent 248 0 R /Prev 250 0 R /Next 252 0 R >> endobj 252 0 obj << /Title(Unified2 IDS Event IP6) /Dest/subsection.5.3.4 /Parent 248 0 R /Prev 251 0 R /Next 253 0 R >> endobj 253 0 obj << /Title(Unified2 IDS Event \(Version 2\)) /Dest/subsection.5.3.5 /Parent 248 0 R /Prev 252 0 R /Next 254 0 R >> endobj 254 0 obj << /Title(Unified2 IDS Event IP6 \(Version 2\)) /Dest/subsection.5.3.6 /Parent 248 0 R /Prev 253 0 R /Next 255 0 R >> endobj 255 0 obj << /Title(Unified2 Extra Data) /Dest/subsection.5.3.7 /Parent 248 0 R /Prev 254 0 R /Next 256 0 R >> endobj 256 0 obj << /Title(Description of Fields) /Dest/subsection.5.3.8 /Parent 248 0 R /Prev 255 0 R >> endobj 248 0 obj << /Title(Unified2 File Format) /Dest/section.5.3 /Count -8 /Parent 242 0 R /Prev 244 0 R /Next 257 0 R /First 249 0 R /Last 256 0 R >> endobj 257 0 obj << /Title(The Snort Team) /Dest/section.5.4 /Parent 242 0 R /Prev 248 0 R >> endobj 260 0 obj <>endobj 264 0 obj <> endobj 265 0 obj <> endobj 269 0 obj <> endobj 270 0 obj <> endobj 275 0 obj <>endobj 276 0 obj <>endobj 277 0 obj <>endobj 278 0 obj <>endobj 279 0 obj <>endobj 280 0 obj <>endobj 281 0 obj <>endobj 282 0 obj <>endobj 283 0 obj <>endobj 284 0 obj <>endobj 285 0 obj <>endobj 286 0 obj <>endobj 287 0 obj <>endobj 288 0 obj <>endobj 289 0 obj <>endobj 290 0 obj <>endobj 291 0 obj <>endobj 292 0 obj <>endobj 293 0 obj <>endobj 294 0 obj <>endobj 295 0 obj <>endobj 296 0 obj <>endobj 297 0 obj <>endobj 298 0 obj <>endobj 299 0 obj <>endobj 300 0 obj <>endobj 301 0 obj <>endobj 302 0 obj <>endobj 303 0 obj <>endobj 304 0 obj <>endobj 305 0 obj <> endobj 306 0 obj <> endobj 310 0 obj <>endobj 311 0 obj <>endobj 312 0 obj <>endobj 313 0 obj <>endobj 314 0 obj <>endobj 315 0 obj <>endobj 316 0 obj <>endobj 317 0 obj <>endobj 318 0 obj <>endobj 319 0 obj <>endobj 320 0 obj <>endobj 321 0 obj <>endobj 322 0 obj <>endobj 323 0 obj <>endobj 324 0 obj <>endobj 325 0 obj <>endobj 326 0 obj <>endobj 327 0 obj <>endobj 328 0 obj <>endobj 329 0 obj <>endobj 330 0 obj <>endobj 331 0 obj <>endobj 332 0 obj <>endobj 333 0 obj <>endobj 334 0 obj <>endobj 335 0 obj <>endobj 336 0 obj <>endobj 337 0 obj <>endobj 338 0 obj <>endobj 339 0 obj <>endobj 340 0 obj <>endobj 341 0 obj <>endobj 342 0 obj <>endobj 343 0 obj <>endobj 344 0 obj <>endobj 345 0 obj <>endobj 346 0 obj <>endobj 347 0 obj <>endobj 348 0 obj <> endobj 349 0 obj <> endobj 353 0 obj <>endobj 354 0 obj <>endobj 355 0 obj <>endobj 356 0 obj <>endobj 357 0 obj <>endobj 358 0 obj <>endobj 359 0 obj <>endobj 360 0 obj <>endobj 361 0 obj <>endobj 362 0 obj <>endobj 363 0 obj <>endobj 364 0 obj <>endobj 365 0 obj <>endobj 366 0 obj <>endobj 367 0 obj <>endobj 368 0 obj <>endobj 369 0 obj <>endobj 370 0 obj <>endobj 371 0 obj <>endobj 372 0 obj <>endobj 373 0 obj <>endobj 374 0 obj <>endobj 375 0 obj <>endobj 376 0 obj <>endobj 377 0 obj <>endobj 378 0 obj <>endobj 379 0 obj <>endobj 380 0 obj <>endobj 381 0 obj <>endobj 382 0 obj <>endobj 383 0 obj <>endobj 384 0 obj <>endobj 385 0 obj <>endobj 386 0 obj <>endobj 387 0 obj <>endobj 388 0 obj <>endobj 389 0 obj <>endobj 390 0 obj <>endobj 391 0 obj <>endobj 392 0 obj <> endobj 393 0 obj <> endobj 397 0 obj <>endobj 398 0 obj <>endobj 399 0 obj <>endobj 400 0 obj <>endobj 401 0 obj <>endobj 402 0 obj <>endobj 403 0 obj <>endobj 404 0 obj <>endobj 405 0 obj <>endobj 406 0 obj <>endobj 407 0 obj <>endobj 408 0 obj <>endobj 409 0 obj <>endobj 410 0 obj <>endobj 411 0 obj <>endobj 412 0 obj <>endobj 413 0 obj <>endobj 414 0 obj <>endobj 415 0 obj <>endobj 416 0 obj <>endobj 417 0 obj <>endobj 418 0 obj <>endobj 419 0 obj <>endobj 420 0 obj <>endobj 421 0 obj <>endobj 422 0 obj <>endobj 423 0 obj <>endobj 424 0 obj <>endobj 425 0 obj <>endobj 426 0 obj <>endobj 427 0 obj <>endobj 428 0 obj <>endobj 429 0 obj <>endobj 430 0 obj <>endobj 431 0 obj <>endobj 432 0 obj <>endobj 433 0 obj <>endobj 434 0 obj <>endobj 435 0 obj <> endobj 436 0 obj <> endobj 440 0 obj <>endobj 441 0 obj <>endobj 442 0 obj <>endobj 443 0 obj <>endobj 444 0 obj <>endobj 445 0 obj <>endobj 446 0 obj <>endobj 447 0 obj <>endobj 448 0 obj <>endobj 449 0 obj <>endobj 450 0 obj <>endobj 451 0 obj <>endobj 452 0 obj <>endobj 453 0 obj <>endobj 454 0 obj <>endobj 455 0 obj <>endobj 456 0 obj <>endobj 457 0 obj <>endobj 458 0 obj <>endobj 459 0 obj <>endobj 460 0 obj <>endobj 461 0 obj <>endobj 462 0 obj <>endobj 463 0 obj <>endobj 464 0 obj <>endobj 465 0 obj <>endobj 466 0 obj <>endobj 467 0 obj <>endobj 468 0 obj <>endobj 469 0 obj <>endobj 470 0 obj <>endobj 471 0 obj <>endobj 472 0 obj <>endobj 473 0 obj <>endobj 474 0 obj <>endobj 475 0 obj <>endobj 476 0 obj <>endobj 477 0 obj <>endobj 478 0 obj <>endobj 479 0 obj <> endobj 480 0 obj <> endobj 484 0 obj <>endobj 485 0 obj <>endobj 486 0 obj <>endobj 487 0 obj <>endobj 488 0 obj <>endobj 489 0 obj <>endobj 490 0 obj <>endobj 491 0 obj <>endobj 492 0 obj <>endobj 493 0 obj <>endobj 494 0 obj <>endobj 495 0 obj <>endobj 496 0 obj <>endobj 497 0 obj <>endobj 498 0 obj <>endobj 499 0 obj <>endobj 500 0 obj <>endobj 501 0 obj <>endobj 502 0 obj <>endobj 503 0 obj <>endobj 504 0 obj <>endobj 505 0 obj <>endobj 506 0 obj <>endobj 507 0 obj <>endobj 508 0 obj <>endobj 509 0 obj <>endobj 510 0 obj <>endobj 511 0 obj <>endobj 512 0 obj <>endobj 513 0 obj <>endobj 514 0 obj <>endobj 515 0 obj <>endobj 516 0 obj <>endobj 517 0 obj <>endobj 518 0 obj <>endobj 519 0 obj <>endobj 520 0 obj <>endobj 521 0 obj <> endobj 522 0 obj <> endobj 526 0 obj <>endobj 527 0 obj <>endobj 528 0 obj <>endobj 529 0 obj <>endobj 530 0 obj <>endobj 531 0 obj <>endobj 532 0 obj <>endobj 533 0 obj <>endobj 534 0 obj <>endobj 535 0 obj <>endobj 536 0 obj <>endobj 537 0 obj <>endobj 538 0 obj <>endobj 539 0 obj <>endobj 540 0 obj <>endobj 541 0 obj <>endobj 542 0 obj <>endobj 543 0 obj <>endobj 544 0 obj <>endobj 545 0 obj <>endobj 546 0 obj <>endobj 547 0 obj <>endobj 548 0 obj <>endobj 549 0 obj <>endobj 550 0 obj <>endobj 551 0 obj <>endobj 552 0 obj <>endobj 553 0 obj <>endobj 554 0 obj <>endobj 555 0 obj <>endobj 556 0 obj <> endobj 557 0 obj <> endobj 565 0 obj <> endobj 566 0 obj <> endobj 571 0 obj <> endobj 572 0 obj <> endobj 576 0 obj <> endobj 577 0 obj <> endobj 581 0 obj <>endobj 582 0 obj <>endobj 583 0 obj <> endobj 584 0 obj <> endobj 588 0 obj <> endobj 589 0 obj <> endobj 593 0 obj <> endobj 594 0 obj <> endobj 598 0 obj <> endobj 599 0 obj <> endobj 603 0 obj <> endobj 604 0 obj <> endobj 608 0 obj <> endobj 609 0 obj <> endobj 613 0 obj <> endobj 614 0 obj <> endobj 618 0 obj <> endobj 619 0 obj <> endobj 623 0 obj <> endobj 624 0 obj <> endobj 628 0 obj <> endobj 629 0 obj <> endobj 633 0 obj <> endobj 634 0 obj <> endobj 638 0 obj <> endobj 639 0 obj <> endobj 643 0 obj <> endobj 644 0 obj <> endobj 648 0 obj <> endobj 649 0 obj <> endobj 653 0 obj <> endobj 654 0 obj <> endobj 658 0 obj <>endobj 659 0 obj <> /Subtype/Link>>endobj 660 0 obj <> /Subtype/Link>>endobj 661 0 obj <> endobj 662 0 obj <> endobj 666 0 obj <>endobj 667 0 obj <> endobj 668 0 obj <> endobj 672 0 obj <> endobj 673 0 obj <> endobj 677 0 obj <> endobj 678 0 obj <> endobj 682 0 obj <> endobj 683 0 obj <> endobj 687 0 obj <>endobj 688 0 obj <>endobj 689 0 obj <>endobj 690 0 obj <> endobj 691 0 obj <> endobj 695 0 obj <> endobj 696 0 obj <> endobj 700 0 obj <> endobj 701 0 obj <> endobj 705 0 obj <> endobj 706 0 obj <> endobj 710 0 obj <> endobj 711 0 obj <> endobj 715 0 obj <>endobj 716 0 obj <> endobj 717 0 obj <> endobj 721 0 obj <>endobj 722 0 obj <>endobj 723 0 obj <> endobj 724 0 obj <> endobj 728 0 obj <>endobj 729 0 obj <>endobj 730 0 obj <>endobj 731 0 obj <> endobj 732 0 obj <> endobj 736 0 obj <> endobj 737 0 obj <> endobj 741 0 obj <> /Subtype/Link>>endobj 742 0 obj <> /Subtype/Link>>endobj 743 0 obj <> endobj 744 0 obj <> endobj 748 0 obj <> endobj 749 0 obj <> endobj 753 0 obj <> endobj 754 0 obj <> endobj 758 0 obj <> endobj 759 0 obj <> endobj 763 0 obj <> endobj 764 0 obj <> endobj 768 0 obj <>endobj 769 0 obj <>endobj 770 0 obj <> endobj 771 0 obj <> endobj 775 0 obj <> endobj 776 0 obj <> endobj 780 0 obj <> endobj 781 0 obj <> endobj 785 0 obj <> endobj 786 0 obj <> endobj 790 0 obj <> endobj 791 0 obj <> endobj 795 0 obj <>endobj 796 0 obj <> endobj 797 0 obj <> endobj 801 0 obj <> endobj 802 0 obj <> endobj 806 0 obj <> endobj 807 0 obj <> endobj 811 0 obj <> endobj 812 0 obj <> endobj 816 0 obj <> endobj 817 0 obj <> endobj 821 0 obj <> endobj 822 0 obj <> endobj 826 0 obj <> endobj 827 0 obj <> endobj 831 0 obj <> endobj 832 0 obj <> endobj 836 0 obj <> endobj 837 0 obj <> endobj 841 0 obj <> /Subtype/Link>>endobj 842 0 obj <> endobj 843 0 obj <> endobj 847 0 obj <> endobj 848 0 obj <> endobj 852 0 obj <>endobj 853 0 obj <> endobj 854 0 obj <> endobj 858 0 obj <>endobj 859 0 obj <>endobj 860 0 obj <>endobj 861 0 obj <> endobj 862 0 obj <> endobj 868 0 obj <> /Subtype/Link>>endobj 869 0 obj <> endobj 870 0 obj <> endobj 874 0 obj <> endobj 875 0 obj <> endobj 879 0 obj <> endobj 880 0 obj <> endobj 884 0 obj <> endobj 885 0 obj <> endobj 889 0 obj <> endobj 890 0 obj <> endobj 894 0 obj <> endobj 895 0 obj <> endobj 899 0 obj <> endobj 900 0 obj <> endobj 904 0 obj <> endobj 905 0 obj <> endobj 909 0 obj <> endobj 910 0 obj <> endobj 914 0 obj <> endobj 915 0 obj <> endobj 919 0 obj <> endobj 920 0 obj <> endobj 924 0 obj <>endobj 925 0 obj <> endobj 926 0 obj <> endobj 930 0 obj <>endobj 931 0 obj <>endobj 932 0 obj <>endobj 933 0 obj <>endobj 934 0 obj <> endobj 935 0 obj <> endobj 939 0 obj <> endobj 940 0 obj <> endobj 944 0 obj <> endobj 945 0 obj <> endobj 949 0 obj <>endobj 950 0 obj <>endobj 951 0 obj <> endobj 952 0 obj <> endobj 956 0 obj <>endobj 957 0 obj <>endobj 958 0 obj <> endobj 959 0 obj <> endobj 963 0 obj <>endobj 964 0 obj <> endobj 965 0 obj <> endobj 969 0 obj <>endobj 970 0 obj <>endobj 971 0 obj <>endobj 972 0 obj <> endobj 973 0 obj <> endobj 977 0 obj <>endobj 978 0 obj <> endobj 979 0 obj <> endobj 983 0 obj <> endobj 984 0 obj <> endobj 988 0 obj <>endobj 989 0 obj <> endobj 990 0 obj <> endobj 994 0 obj <> endobj 995 0 obj <> endobj 999 0 obj <> endobj 1000 0 obj <> endobj 1004 0 obj <> endobj 1005 0 obj <> endobj 1009 0 obj <> endobj 1010 0 obj <> endobj 1014 0 obj <> endobj 1015 0 obj <> endobj 1019 0 obj <> endobj 1020 0 obj <> endobj 1024 0 obj <> endobj 1025 0 obj <> endobj 1029 0 obj <> endobj 1030 0 obj <> endobj 1034 0 obj <> endobj 1035 0 obj <> endobj 1039 0 obj <> endobj 1040 0 obj <> endobj 1044 0 obj <> endobj 1045 0 obj <> endobj 1049 0 obj <> endobj 1050 0 obj <> endobj 1054 0 obj <> endobj 1055 0 obj <> endobj 1059 0 obj <> endobj 1060 0 obj <> endobj 1064 0 obj <> endobj 1065 0 obj <> endobj 1069 0 obj <> endobj 1070 0 obj <> endobj 1074 0 obj <> endobj 1075 0 obj <> endobj 1079 0 obj <> endobj 1080 0 obj <> endobj 1084 0 obj <> endobj 1085 0 obj <> endobj 1089 0 obj <> endobj 1090 0 obj <> endobj 1094 0 obj <> endobj 1095 0 obj <> endobj 1099 0 obj <> endobj 1100 0 obj <> endobj 1104 0 obj <>endobj 1105 0 obj <> endobj 1106 0 obj <> endobj 1110 0 obj <> endobj 1111 0 obj <> endobj 1115 0 obj <> endobj 1116 0 obj <> endobj 1120 0 obj <> endobj 1121 0 obj <> endobj 1125 0 obj <> endobj 1126 0 obj <> endobj 1130 0 obj <> endobj 1131 0 obj <> endobj 1135 0 obj <> endobj 1136 0 obj <> endobj 1140 0 obj <> endobj 1141 0 obj <> endobj 1145 0 obj <> endobj 1146 0 obj <> endobj 1150 0 obj <> endobj 1151 0 obj <> endobj 1155 0 obj <> endobj 1156 0 obj <> endobj 1160 0 obj <> endobj 1161 0 obj <> endobj 1165 0 obj <> endobj 1166 0 obj <> endobj 1170 0 obj <> endobj 1171 0 obj <> endobj 1175 0 obj <> endobj 1176 0 obj <> endobj 1180 0 obj <> endobj 1181 0 obj <> endobj 1185 0 obj <> endobj 1186 0 obj <> endobj 1190 0 obj <> endobj 1191 0 obj <> endobj 1195 0 obj <> endobj 1196 0 obj <> endobj 1200 0 obj <> endobj 1201 0 obj <> endobj 1205 0 obj <> endobj 1206 0 obj <> endobj 1210 0 obj <> endobj 1211 0 obj <> endobj 1215 0 obj <> endobj 1216 0 obj <> endobj 1220 0 obj <> endobj 1221 0 obj <> endobj 1225 0 obj <> endobj 1226 0 obj <> endobj 1230 0 obj <> endobj 1231 0 obj <> endobj 1235 0 obj <> endobj 1236 0 obj <> endobj 1240 0 obj <> endobj 1241 0 obj <> endobj 1245 0 obj <> endobj 1246 0 obj <> endobj 1250 0 obj <> endobj 1251 0 obj <> endobj 1255 0 obj <> endobj 1256 0 obj <> endobj 1260 0 obj <> endobj 1261 0 obj <> endobj 1265 0 obj <> endobj 1266 0 obj <> endobj 1270 0 obj <>endobj 1271 0 obj <> endobj 1272 0 obj <> endobj 1276 0 obj <> endobj 1277 0 obj <> endobj 1281 0 obj <> endobj 1282 0 obj <> endobj 1286 0 obj <> endobj 1287 0 obj <> endobj 1291 0 obj <> endobj 1292 0 obj <> endobj 1296 0 obj <> endobj 1297 0 obj <> endobj 1301 0 obj <> endobj 1302 0 obj <> endobj 1306 0 obj <> endobj 1307 0 obj <> endobj 1311 0 obj <> endobj 1312 0 obj <> endobj 1316 0 obj <> endobj 1317 0 obj <> endobj 1321 0 obj <> endobj 1322 0 obj <> endobj 1326 0 obj <> endobj 1327 0 obj <> endobj 1331 0 obj <> endobj 1332 0 obj <> endobj 1336 0 obj <> endobj 1337 0 obj <> endobj 1341 0 obj <> endobj 1342 0 obj <> endobj 1346 0 obj <>endobj 1347 0 obj <> endobj 1348 0 obj <> endobj 1352 0 obj <>endobj 1353 0 obj <> endobj 1354 0 obj <> endobj 1358 0 obj <>endobj 1359 0 obj <> endobj 1360 0 obj <> endobj 1364 0 obj <>endobj 1365 0 obj <> endobj 1366 0 obj <> endobj 1370 0 obj <>endobj 1371 0 obj <>endobj 1372 0 obj <>endobj 1373 0 obj <>endobj 1374 0 obj <>endobj 1375 0 obj <>endobj 1376 0 obj <> endobj 1377 0 obj <> endobj 1381 0 obj <>endobj 1382 0 obj <>endobj 1383 0 obj <>endobj 1384 0 obj <> endobj 1385 0 obj <> endobj 1389 0 obj <>endobj 1390 0 obj <>endobj 1391 0 obj <> endobj 1392 0 obj <> endobj 1396 0 obj <> endobj 1397 0 obj <> endobj 1401 0 obj <> endobj 1402 0 obj <> endobj 1406 0 obj <>endobj 1407 0 obj <>endobj 1408 0 obj <> endobj 1409 0 obj <> endobj 1413 0 obj <> endobj 1414 0 obj <> endobj 1418 0 obj <>endobj 1419 0 obj <>endobj 1420 0 obj <>endobj 1421 0 obj <>endobj 1422 0 obj <> endobj 1423 0 obj <> endobj 1427 0 obj <> endobj 1428 0 obj <> endobj 1432 0 obj <> endobj 1433 0 obj <> endobj 1438 0 obj <> endobj 1439 0 obj <> endobj 1443 0 obj <> endobj 1444 0 obj <> endobj 1448 0 obj <> endobj 1449 0 obj <> endobj 1453 0 obj <> endobj 1454 0 obj <> endobj 1458 0 obj <> endobj 1459 0 obj <> endobj 1463 0 obj <> endobj 1464 0 obj <> endobj 1468 0 obj <>endobj 1469 0 obj <> endobj 1470 0 obj <> endobj 1474 0 obj <>endobj 1475 0 obj <> endobj 1476 0 obj <> endobj 1480 0 obj <>endobj 1481 0 obj <>endobj 1482 0 obj <>endobj 1483 0 obj <>endobj 1484 0 obj <>endobj 1485 0 obj <> endobj 1486 0 obj <> endobj 1490 0 obj <>endobj 1491 0 obj <>endobj 1492 0 obj <>endobj 1493 0 obj <>endobj 1494 0 obj <> endobj 1495 0 obj <> endobj 1499 0 obj <> /Subtype/Link>>endobj 1500 0 obj <>endobj 1501 0 obj <> endobj 1502 0 obj <> endobj 1506 0 obj <>endobj 1507 0 obj <>endobj 1508 0 obj <> endobj 1509 0 obj <> endobj 1513 0 obj <>endobj 1514 0 obj <>endobj 1515 0 obj <> endobj 1516 0 obj <> endobj 1520 0 obj <> endobj 1521 0 obj <> endobj 1525 0 obj <>endobj 1526 0 obj <>endobj 1527 0 obj <> endobj 1528 0 obj <> endobj 1532 0 obj <> endobj 1533 0 obj <> endobj 1537 0 obj <>endobj 1538 0 obj <>endobj 1539 0 obj <>endobj 1540 0 obj <>endobj 1541 0 obj <>endobj 1542 0 obj <>endobj 1543 0 obj <>endobj 1544 0 obj <>endobj 1545 0 obj <>endobj 1546 0 obj <>endobj 1547 0 obj <>endobj 1548 0 obj <>endobj 1549 0 obj <>endobj 1550 0 obj <>endobj 1551 0 obj <>endobj 1552 0 obj <>endobj 1553 0 obj <>endobj 1554 0 obj <>endobj 1555 0 obj <> endobj 1556 0 obj <> endobj 1560 0 obj <> endobj 1561 0 obj <> endobj 1565 0 obj <>endobj 1566 0 obj <>endobj 1567 0 obj <>endobj 1568 0 obj <> endobj 1569 0 obj <> endobj 1573 0 obj <>endobj 1574 0 obj <>endobj 1575 0 obj <>endobj 1576 0 obj <> endobj 1577 0 obj <> endobj 1581 0 obj <>endobj 1582 0 obj <>endobj 1583 0 obj <>endobj 1584 0 obj <> endobj 1585 0 obj <> endobj 1589 0 obj <>endobj 1590 0 obj <> endobj 1591 0 obj <> endobj 1595 0 obj <>endobj 1596 0 obj <> endobj 1597 0 obj <> endobj 1601 0 obj <>endobj 1602 0 obj <>endobj 1603 0 obj <>endobj 1604 0 obj <> endobj 1605 0 obj <> endobj 1609 0 obj <> endobj 1610 0 obj <> endobj 1614 0 obj <> endobj 1615 0 obj <> endobj 1619 0 obj <>endobj 1620 0 obj <>endobj 1621 0 obj <>endobj 1622 0 obj <>endobj 1623 0 obj <>endobj 1624 0 obj <>endobj 1625 0 obj <>endobj 1626 0 obj <>endobj 1627 0 obj <> endobj 1628 0 obj <> endobj 1632 0 obj <>endobj 1633 0 obj <> /Subtype/Link>>endobj 1634 0 obj <> endobj 1635 0 obj <> endobj 1639 0 obj <>endobj 1640 0 obj <>endobj 1641 0 obj <>endobj 1642 0 obj <> endobj 1643 0 obj <> endobj 1647 0 obj <>endobj 1648 0 obj <> endobj 1649 0 obj <> endobj 1653 0 obj <> endobj 1654 0 obj <> endobj 1658 0 obj <> endobj 1659 0 obj <> endobj 1663 0 obj <>endobj 1664 0 obj <>endobj 1665 0 obj <>endobj 1666 0 obj <> endobj 1667 0 obj <> endobj 1671 0 obj <>endobj 1672 0 obj <> endobj 1673 0 obj <> endobj 1677 0 obj <>endobj 1678 0 obj <>endobj 1679 0 obj <> endobj 1680 0 obj <> endobj 1684 0 obj <> endobj 1685 0 obj <> endobj 1689 0 obj <> endobj 1690 0 obj <> endobj 1694 0 obj <>endobj 1695 0 obj <>endobj 1696 0 obj <>endobj 1697 0 obj <>endobj 1698 0 obj <>endobj 1699 0 obj <>endobj 1700 0 obj <>endobj 1701 0 obj <>endobj 1702 0 obj <> endobj 1703 0 obj <> endobj 1707 0 obj <>endobj 1708 0 obj <>endobj 1709 0 obj <>endobj 1710 0 obj <>endobj 1711 0 obj <>endobj 1712 0 obj <>endobj 1713 0 obj <>endobj 1714 0 obj <>endobj 1715 0 obj <>endobj 1716 0 obj <>endobj 1717 0 obj <> endobj 1718 0 obj <> endobj 1722 0 obj <>endobj 1723 0 obj <>endobj 1724 0 obj <>endobj 1725 0 obj <>endobj 1726 0 obj <> endobj 1727 0 obj <> endobj 1731 0 obj <> endobj 1732 0 obj <> endobj 1736 0 obj <> endobj 1737 0 obj <> endobj 1741 0 obj <> endobj 1742 0 obj <> endobj 1746 0 obj <>endobj 1747 0 obj <> endobj 1748 0 obj <> endobj 1752 0 obj <>endobj 1753 0 obj <> endobj 1754 0 obj <> endobj 1758 0 obj <> endobj 1759 0 obj <> endobj 1763 0 obj <> endobj 1764 0 obj <> endobj 1768 0 obj <> endobj 1769 0 obj <> endobj 1773 0 obj <> endobj 1774 0 obj <> endobj 1778 0 obj <> endobj 1779 0 obj <> endobj 1783 0 obj <> endobj 1784 0 obj <> endobj 1788 0 obj <> endobj 1789 0 obj <> endobj 1793 0 obj <> endobj 1794 0 obj <> endobj 1798 0 obj <>endobj 1799 0 obj <>endobj 1800 0 obj <> endobj 1801 0 obj <> endobj 1805 0 obj <>endobj 1806 0 obj <> endobj 1807 0 obj <> endobj 1811 0 obj <>endobj 1812 0 obj <>endobj 1813 0 obj <>endobj 1814 0 obj <> endobj 1815 0 obj <> endobj 1819 0 obj <>endobj 1820 0 obj <>endobj 1821 0 obj <> endobj 1822 0 obj <> endobj 1826 0 obj <> endobj 1827 0 obj <> endobj 1831 0 obj <> endobj 1832 0 obj <> endobj 1836 0 obj <> endobj 1837 0 obj <> endobj 1841 0 obj <> endobj 1842 0 obj <> endobj 1846 0 obj <> endobj 1847 0 obj <> endobj 1851 0 obj <> endobj 1852 0 obj <> endobj 1856 0 obj <> endobj 1857 0 obj <> endobj 1861 0 obj <> endobj 1862 0 obj <> endobj 1866 0 obj <> endobj 1867 0 obj <> endobj 1871 0 obj <> endobj 1872 0 obj <> endobj 1876 0 obj <> endobj 1877 0 obj <> endobj 1881 0 obj <> endobj 1882 0 obj <> endobj 1886 0 obj <> endobj 1887 0 obj <> endobj 1891 0 obj <> endobj 1892 0 obj <> endobj 1896 0 obj <> endobj 1897 0 obj <> endobj 1901 0 obj <> endobj 1902 0 obj <> endobj 1906 0 obj <> endobj 1907 0 obj <> endobj 1911 0 obj <> endobj 1912 0 obj <> endobj 1916 0 obj <> endobj 1917 0 obj <> endobj 1921 0 obj <> endobj 1922 0 obj <> endobj 1926 0 obj <> endobj 1927 0 obj <> endobj 1931 0 obj <> endobj 1932 0 obj <> endobj 1936 0 obj <> endobj 1937 0 obj <> endobj 1941 0 obj <> endobj 1942 0 obj <> endobj 1946 0 obj <> endobj 1947 0 obj <> endobj 1951 0 obj <> endobj 1952 0 obj <> endobj 1956 0 obj <> endobj 1957 0 obj <> endobj 1961 0 obj <> endobj 1962 0 obj <> endobj 1966 0 obj <> endobj 1967 0 obj <> endobj 1971 0 obj <> endobj 1972 0 obj <> endobj 1976 0 obj <> endobj 1977 0 obj <> endobj 1981 0 obj <> endobj 1982 0 obj <> endobj 1986 0 obj <> endobj 1987 0 obj <> endobj 866 0 obj <> endobj 562 0 obj <> endobj 1991 0 obj <> endobj 1437 0 obj <> endobj 274 0 obj <> endobj 1992 0 obj <> endobj 261 0 obj <> endobj 1993 0 obj <> endobj 1994 0 obj <>stream xœ]1®Â0 †÷œ"7h’¥òÂ[BÀRÇAH£PnOâR†/ÒçØ’7ûÃß!†I6§<â…&éCt™ã3#Én! m¤ 8}Œ_¼Û$šý¿M×W"YÈÏ~´wjκïW\ÓóŽŽÉ"eo$vJÁÎ{ÝÏ×vüÒÙcŒî ¨Æ(cŠ úªí ³Ú¢› 0JuCÕ˜¢®ª¦(V%`”Z#/¶¬Pw¬q—tŸ9Sœø&œ¹& ‘¾gKcªS² ÞgŸk endstream endobj 262 0 obj <> endobj 1995 0 obj <> endobj 570 0 obj <> endobj 561 0 obj <> endobj 1996 0 obj <> endobj 564 0 obj <> endobj 1997 0 obj <> endobj 867 0 obj <> endobj 1988 0 obj <>stream xœcd`ab`dddsö 24±TH3þaú!ËÜý»ïgêÏ&Önæn–ußÏ }·ünÄÿ]W€™‘ÑÍ;Ê9¿ ²(3=£DAÃYSÁÐÒÒ\Á17µ(391OÁ7±$#57±ÈÉQÎOÎL-©ÔSpÌÉQé(VJ-N-*KMÛ윟[PZ’Z¤à›Ÿ’Z”ÇÀÀÀlËÀ Ç`Ã`ÇÀÂÈÈî“Û÷ŸÑ7”ï?3çq†ï’›¿ëmf<üS—ù§ó÷Û¢³æuÏŸ_Ñ]+ÿç5[mEwyù¼îYò?^ý ‘©‘ÿó’­"3Sžï?£èq†ß}›élfüε™ùûäß}¢›µ~é¼Ùü[ö_ ;ªn ãŸM¢¿e“ßüÓÑJþ.ËÆWºð§ýÂßËæ|Ï›Æö;i:û*® Ür\,æóy8Náá¹0Ÿ‡—Èžˆ‰ endstream endobj 563 0 obj <> endobj 1989 0 obj <>stream xœcd`ab`dddwöõõ441UH3þaú!ËÜý;ô§× ¬Ý<ÌÝ<,+Ä }·ünÊÿ]_€™‘ÑÍ'Ú9¿ ²(3=£DAÃYSÁÐÒÒ\Á17µ(391OÁ7±$#57±ÈÉQÎOÎL-©ÔSpÌÉQé(VJ-N-*KMX휟[PZ’Z¤à›Ÿ’Z”ÇÀÀÀbcgmÅÀ Ë ÏÀËÀÏÀ t(;C$ÃJ†OŒÂÿ}Cøþ3sgHYðcí|Æ{?¾3ÿ4ÿÑ&:}⤠ÝÓ8¦5Mièèìn©“û³ï÷̆¶æ¶îzÉîúÉmÓÚ~$f´ôv÷usL›2eÚ´– õåÿ,üÞÊiâ÷ Ñi&OèžÞ=½yBÄ?û¾Ï”¨›ÔÙÝÑÍÑÐÔÔÐ4¡uf‹ü…¿{þqmK[kw“dÔ¦i}½Ý“fÈñýg=Îð;tÁw‡¯Œß=2ï=[´)%«¼(¿`~ášé3ú§L•ëëíéééæèééªuÌðÏÊ’ohèZÁÑ2¡}´Û7¾sB êþÊøð+ó÷¢+Šçåçå-.^±bñâr|¥ Ú/ü½lÚ´l¿§±¯âºÌ-ÇÅb>Ÿ‡sÉD¥aÍ endstream endobj 263 0 obj <> endobj 1990 0 obj <>stream xœ5‘kL[eÇÏézÆ&ɉ¢rZÈȦÑÅ ²1¯[êH3N'd íV(½°RKï÷>½@éí@ å2æ !6YŒÆùèu.ŠñƒûBÜ’abäËâ{ÚœÁ/Ïû<þÏÿÿ{’($IŠemo}v§­ã'ù'D|58RåÅPFAYÑBáv%2?Œ”¨ë!&É×ZÏ÷kM™fȤSõ+ Òò'¥GOžw.û“†Oiô”>„ë„õfË•Þ$*]‚Ÿá*]þ€dn{4hŽBõy9ÃÁŒÑ#öŸçÄÉd`†c…ð«Y´¹ÝŽ"Ìßõ¿×bòø±Zé†ûˆ\¿{ŸÝ#TfyUöÂÛ |Ko­\ø %~ h‡ì»¿yWºãý;@Ic!àœ ;ÒÍßk?³ãR¼7‰AÃzÉdпêó}>ðÐö$6ï^_ ³HøŸ?`êÊUŽ[\ü.JÇb¡Ä.þ…Èñ,lÒB¢¥,ÿ˜@§ýŠB21ËÚå¡mÊ9mæRS¾„%&Áu·Pí­x45SUS–”U0sÙY\y„C ¡tpNUf°Z#VÚ.æp=®¼gCÈ UV‹ÍlNyâ> ªiÂ5¯;}6˜«Ìœ--t"É¢Ê n,öŠý£œƒE€¹ G—Fײ¨:‡Ø ™ÿ ½Ïœ:{±\´sÂK…Ç£avréã_6¿H‡C£cžH}s¡cå½{¾x`Ì´Ûåwº>iüõ¬d;Q2j£q&%娑;äò3ä·ù$Å+òo0î´_PØÀëò:0¿}øQ· | àØ|g 7™0D=IÉV¿Í õ­BñöÓ%BD¬Îå7räj.ÿeŽ*È„³#w#9öà>{p §ð¢ò¢.$G»Õ¾õƒõ¸u r¡VÔŽ4Hšqv`nÅíX#)žÍ¿<[‚Œ‰s¥ëûÙÒ¢™²}¹É²2‚ø´é endstream endobj 242 0 obj << /Title(Snort Development) /Dest/chapter.5 /Count -4 /Parent 6 0 R /Prev 228 0 R /First 243 0 R /Last 257 0 R >> endobj 5 0 obj <> /Doc-Start<> /page.2<> /chapter*.1<> /page.3<> /page.4<> /page.5<> /page.6<> /page.7<> /page.8<> /page.9<> /chapter.1<> /section.1.1<> /section.1.2<> /page.10<> /section.1.3<> /page.11<> /section.1.4<> /subsection.1.4.1<> /page.12<> /subsection.1.4.2<> /subsection.1.4.3<> /page.13<> /subsection.1.4.4<> /section.1.5<> /subsection.1.5.1<> /page.14<> /subsection.1.5.2<> /page.15<> /subsection.1.5.3<> /Item.1<> /Item.2<> /Item.3<> /Item.4<> /Item.5<> /subsection.1.5.4<> /page.16<> /subsection.1.5.5<> /subsection.1.5.6<> /subsection.1.5.7<> /page.17<> /subsection.1.5.8<> /section.1.6<> /subsection.1.6.1<> /subsection.1.6.2<> /section*.2<> /page.18<> /section*.3<> /section*.4<> /section*.5<> /section*.6<> /page.19<> /section*.7<> /section*.8<> /section.1.7<> /subsection.1.7.1<> /subsection.1.7.2<> /page.20<> /subsection.1.7.3<> /page.21<> /subsection.1.7.4<> /subsection.1.7.5<> /page.22<> /section.1.8<> /page.23<> /subsection.1.8.1<> /subsection.1.8.2<> /section.1.9<> /subsection.1.9.1<> /page.24<> /section*.9<> /subsection.1.9.2<> /subsection.1.9.3<> /subsection.1.9.4<> /page.25<> /subsection.1.9.5<> /section*.10<> /page.26<> /section.1.10<> /section.1.11<> /page.27<> /section.1.12<> /page.28<> /chapter.2<> /section.2.1<> /subsection.2.1.1<> /subsection.2.1.2<> /page.29<> /section*.11<> /section*.12<> /page.30<> /section*.13<> /page.31<> /section*.14<> /subsection.2.1.3<> /section*.15<> /page.32<> /table.2.1<> /page.33<> /page.34<> /page.35<> /page.36<> /page.37<> /page.38<> /page.39<> /page.40<> /section.2.2<> /subsection.2.2.1<> /Item.6<> /Item.7<> /page.41<> /section*.16<> /page.42<> /section*.17<> /section*.18<> /page.43<> /section*.19<> /section*.20<> /subsection.2.2.2<> /section*.21<> /section*.22<> /section*.23<> /section*.24<> /section*.25<> /page.44<> /section*.26<> /section*.27<> /page.45<> /table.2.2<> /page.46<> /page.47<> /section*.28<> /section*.29<> /page.48<> /section*.30<> /section*.31<> /section*.32<> /Item.8<> /Item.9<> /page.49<> /subsection.2.2.3<> /page.50<> /page.51<> /section*.33<> /Item.10<> /Item.11<> /Item.12<> /Item.13<> /Item.14<> /Item.15<> /Item.16<> /page.52<> /Item.17<> /Item.18<> /Item.19<> /section*.34<> /section*.35<> /section*.36<> /section*.37<> /page.53<> /section*.38<> /Item.20<> /Item.21<> /Item.22<> /Item.23<> /Item.24<> /Item.25<> /section*.39<> /Item.26<> /page.54<> /Item.27<> /Item.28<> /Item.29<> /subsection.2.2.4<> /section*.40<> /page.55<> /subsection.2.2.5<> /page.56<> /page.57<> /page.58<> /page.59<> /section*.41<> /subsection.2.2.6<> /page.60<> /section*.42<> /section*.43<> /section*.44<> /Item.30<> /Item.31<> /Item.32<> /page.61<> /Item.33<> /Item.34<> /Item.35<> /Item.36<> /Item.37<> /page.62<> /section*.45<> /section*.46<> /section*.47<> /section*.48<> /section*.49<> /section*.50<> /section*.51<> /section*.52<> /section*.53<> /Item.38<> /Item.39<> /page.63<> /table.2.3<> /Item.40<> /Item.41<> /Item.42<> /Item.43<> /page.64<> /table.2.4<> /section*.54<> /Item.44<> /Item.45<> /page.65<> /table.2.5<> /Item.46<> /Item.47<> /page.66<> /table.2.6<> /Item.48<> /Item.49<> /Item.50<> /page.67<> /Item.51<> /Item.52<> /page.68<> /Item.53<> /Item.54<> /Item.55<> /page.69<> /Item.56<> /Item.57<> /Item.58<> /Item.59<> /Item.60<> /Item.61<> /Item.62<> /Item.63<> /Item.64<> /page.70<> /Item.65<> /Item.66<> /Item.67<> /Item.68<> /Item.69<> /Item.70<> /Item.71<> /page.71<> /Item.72<> /Item.73<> /Item.74<> /Item.75<> /Item.76<> /Item.77<> /Item.78<> /Item.79<> /page.72<> /Item.80<> /Item.81<> /Item.82<> /Item.83<> /Item.84<> /Item.85<> /Item.86<> /Item.87<> /page.73<> /section*.55<> /subsection.2.2.7<> /section*.56<> /page.74<> /Item.88<> /Item.89<> /Item.90<> /Item.91<> /Item.92<> /Item.93<> /Item.94<> /Item.95<> /Item.96<> /Item.97<> /Item.98<> /Item.99<> /page.75<> /Item.100<> /Item.101<> /Item.102<> /Item.103<> /Item.104<> /Item.105<> /Item.106<> /Item.107<> /Item.108<> /Item.109<> /page.76<> /Item.110<> /Item.111<> /Item.112<> /Item.113<> /Item.114<> /page.77<> /Item.115<> /Item.116<> /Item.117<> /Item.118<> /Item.119<> /Item.120<> /page.78<> /section*.57<> /section*.58<> /section*.59<> /subsection.2.2.8<> /page.79<> /section*.60<> /Item.121<> /Item.122<> /Item.123<> /Item.124<> /Item.125<> /page.80<> /Item.126<> /Item.127<> /section*.61<> /page.81<> /section*.62<> /subsection.2.2.9<> /section*.63<> /Item.128<> /Item.129<> /Item.130<> /Item.131<> /page.82<> /Item.132<> /Item.133<> /Item.134<> /page.83<> /section*.64<> /section*.65<> /subsection.2.2.10<> /section*.66<> /section*.67<> /page.84<> /section*.68<> /Item.135<> /Item.136<> /Item.137<> /section*.69<> /section*.70<> /section*.71<> /page.85<> /section*.72<> /Item.138<> /Item.139<> /Item.140<> /Item.141<> /section*.73<> /section*.74<> /section*.75<> /section*.76<> /section*.77<> /section*.78<> /page.86<> /section*.79<> /Item.142<> /Item.143<> /Item.144<> /Item.145<> /Item.146<> /Item.147<> /Item.148<> /page.87<> /Item.149<> /Item.150<> /Item.151<> /Item.152<> /section*.80<> /page.88<> /section*.81<> /section*.82<> /section*.83<> /section*.84<> /section*.85<> /section*.86<> /Item.153<> /Item.154<> /Item.155<> /page.89<> /Item.156<> /Item.157<> /section*.87<> /page.90<> /subsection.2.2.11<> /section*.88<> /Item.158<> /Item.159<> /Item.160<> /Item.161<> /Item.162<> /Item.163<> /Item.164<> /Item.165<> /Item.166<> /page.91<> /Item.167<> /Item.168<> /Item.169<> /section*.89<> /subsection.2.2.12<> /section*.90<> /Item.170<> /Item.171<> /Item.172<> /Item.173<> /page.92<> /section*.91<> /subsection.2.2.13<> /section*.92<> /Item.174<> /Item.175<> /Item.176<> /page.93<> /section*.93<> /section*.94<> /page.94<> /subsection.2.2.14<> /section*.95<> /section*.96<> /subsection.2.2.15<> /page.95<> /section*.97<> /section*.98<> /page.96<> /page.97<> /section*.99<> /page.98<> /page.99<> /page.100<> /page.101<> /page.102<> /section*.100<> /table.2.7<> /table.2.8<> /page.103<> /page.104<> /page.105<> /table.2.9<> /page.106<> /table.2.10<> /section*.101<> /page.107<> /page.108<> /page.109<> /subsection.2.2.16<> /page.110<> /section*.102<> /section*.103<> /section*.104<> /page.111<> /page.112<> /subsection.2.2.17<> /section*.105<> /page.113<> /section*.106<> /section*.107<> /section*.108<> /page.114<> /section*.109<> /page.115<> /subsection.2.2.18<> /section*.110<> /section*.111<> /page.116<> /page.117<> /page.118<> /section*.112<> /table.2.11<> /section*.113<> /page.119<> /page.120<> /subsection.2.2.19<> /section*.114<> /page.121<> /page.122<> /section*.115<> /table.2.12<> /section*.116<> /page.123<> /page.124<> /page.125<> /subsection.2.2.20<> /section*.117<> /section*.118<> /section*.119<> /page.126<> /section*.120<> /table.2.13<> /section*.121<> /table.2.14<> /section*.122<> /page.127<> /table.2.15<> /page.128<> /page.129<> /page.130<> /table.2.16<> /page.131<> /page.132<> /page.133<> /subsection.2.2.21<> /section*.123<> /section*.124<> /page.134<> /section*.125<> /page.135<> /section*.126<> /table.2.17<> /subsection.2.2.22<> /section*.127<> /section*.128<> /page.136<> /section*.129<> /page.137<> /page.138<> /section*.130<> /table.2.18<> /page.139<> /section.2.3<> /subsection.2.3.1<> /page.140<> /subsection.2.3.2<> /section.2.4<> /page.141<> /subsection.2.4.1<> /section*.131<> /section*.132<> /page.142<> /subsection.2.4.2<> /section*.133<> /page.143<> /section*.134<> /page.144<> /subsection.2.4.3<> /section*.135<> /page.145<> /section*.136<> /subsection.2.4.4<> /section*.137<> /Item.177<> /Item.178<> /page.146<> /Item.179<> /section*.138<> /subsection.2.4.5<> /Item.180<> /Item.181<> /page.147<> /section*.139<> /section.2.5<> /subsection.2.5.1<> /section*.140<> /page.148<> /figure.2.1<> /section*.141<> /section*.142<> /page.149<> /subsection.2.5.2<> /section*.143<> /section*.144<> /section*.145<> /page.150<> /figure.2.2<> /page.151<> /subsection.2.5.3<> /page.152<> /section*.146<> /page.153<> /section*.147<> /section*.148<> /page.154<> /section*.149<> /section.2.6<> /page.155<> /subsection.2.6.1<> /section*.150<> /section*.151<> /section*.152<> /page.156<> /section*.153<> /section*.154<> /section*.155<> /subsection.2.6.2<> /section*.156<> /section*.157<> /page.157<> /subsection.2.6.3<> /section*.158<> /section*.159<> /subsection.2.6.4<> /section*.160<> /section*.161<> /page.158<> /subsection.2.6.5<> /section*.162<> /section*.163<> /subsection.2.6.6<> /section*.164<> /page.159<> /section*.165<> /subsection.2.6.7<> /section*.166<> /page.160<> /section*.167<> /section*.168<> /page.161<> /section*.169<> /section*.170<> /page.162<> /section*.171<> /subsection.2.6.8<> /section*.172<> /section*.173<> /subsection.2.6.9<> /section.2.7<> /page.163<> /subsection.2.7.1<> /subsection.2.7.2<> /page.164<> /page.165<> /subsection.2.7.3<> /section*.174<> /section*.175<> /page.166<> /section.2.8<> /page.167<> /subsection.2.8.1<> /subsection.2.8.2<> /table.2.19<> /section.2.9<> /subsection.2.9.1<> /page.168<> /subsection.2.9.2<> /subsection.2.9.3<> /page.169<> /section.2.10<> /page.170<> /subsection.2.10.1<> /subsection.2.10.2<> /section*.176<> /page.171<> /section*.177<> /section*.178<> /section*.179<> /section*.180<> /page.172<> /subsection.2.10.3<> /section.2.11<> /subsection.2.11.1<> /page.173<> /subsection.2.11.2<> /subsection.2.11.3<> /page.174<> /subsection.2.11.4<> /page.175<> /subsection.2.11.5<> /page.176<> /chapter.3<> /section.3.1<> /section.3.2<> /subsection.3.2.1<> /figure.3.1<> /page.177<> /Item.182<> /Item.183<> /Item.184<> /Item.185<> /Item.186<> /Item.187<> /Item.188<> /Item.189<> /subsection.3.2.2<> /subsection.3.2.3<> /page.178<> /figure.3.2<> /figure.3.3<> /subsection.3.2.4<> /subsection.3.2.5<> /figure.3.4<> /page.179<> /figure.3.5<> /figure.3.6<> /subsection.3.2.6<> /section.3.3<> /figure.3.7<> /page.180<> /section.3.4<> /subsection.3.4.1<> /section*.181<> /subsection.3.4.2<> /table.3.1<> /section*.182<> /section*.183<> /page.181<> /subsection.3.4.3<> /section*.184<> /section*.185<> /subsection.3.4.4<> /section*.186<> /section*.187<> /page.182<> /subsection.3.4.5<> /section*.188<> /section*.189<> /subsection.3.4.6<> /section*.190<> /section*.191<> /table.3.2<> /page.183<> /section*.192<> /subsection.3.4.7<> /section*.193<> /section*.194<> /page.184<> /subsection.3.4.8<> /table.3.3<> /section*.195<> /section*.196<> /subsection.3.4.9<> /table.3.4<> /page.185<> /section.3.5<> /subsection.3.5.1<> /section*.197<> /section*.198<> /page.186<> /section*.199<> /table.3.5<> /subsection.3.5.2<> /section*.200<> /section*.201<> /subsection.3.5.3<> /section*.202<> /page.187<> /section*.203<> /subsection.3.5.4<> /section*.204<> /subsection.3.5.5<> /section*.205<> /section*.206<> /page.188<> /subsection.3.5.6<> /section*.207<> /section*.208<> /subsection.3.5.7<> /section*.209<> /section*.210<> /subsection.3.5.8<> /page.189<> /section*.211<> /section*.212<> /subsection.3.5.9<> /section*.213<> /section*.214<> /subsection.3.5.10<> /page.190<> /section*.215<> /section*.216<> /subsection.3.5.11<> /section*.217<> /section*.218<> /subsection.3.5.12<> /section*.219<> /page.191<> /section*.220<> /subsection.3.5.13<> /section*.221<> /section*.222<> /subsection.3.5.14<> /section*.223<> /page.192<> /section*.224<> /subsection.3.5.15<> /section*.225<> /section*.226<> /subsection.3.5.16<> /section*.227<> /page.193<> /section*.228<> /subsection.3.5.17<> /section*.229<> /section*.230<> /subsection.3.5.18<> /page.194<> /section*.231<> /section*.232<> /subsection.3.5.19<> /page.195<> /section*.233<> /section*.234<> /subsection.3.5.20<> /page.196<> /table.3.6<> /section*.235<> /subsection.3.5.21<> /section*.236<> /page.197<> /subsection.3.5.22<> /section*.237<> /section*.238<> /subsection.3.5.23<> /page.198<> /table.3.7<> /table.3.8<> /section*.239<> /section*.240<> /page.199<> /table.3.9<> /subsection.3.5.24<> /section*.241<> /section*.242<> /page.200<> /subsection.3.5.25<> /section*.243<> /section*.244<> /subsection.3.5.26<> /section*.245<> /page.201<> /section*.246<> /subsection.3.5.27<> /section*.247<> /section*.248<> /subsection.3.5.28<> /page.202<> /section*.249<> /page.203<> /section*.250<> /subsection.3.5.29<> /section*.251<> /page.204<> /section*.252<> /subsection.3.5.30<> /section*.253<> /page.205<> /section*.254<> /section*.255<> /subsection.3.5.31<> /section*.256<> /page.206<> /section*.257<> /subsection.3.5.32<> /section*.258<> /section*.259<> /subsection.3.5.33<> /page.207<> /section*.260<> /section*.261<> /subsection.3.5.34<> /subsection.3.5.35<> /subsection.3.5.36<> /subsection.3.5.37<> /subsection.3.5.38<> /subsection.3.5.39<> /subsection.3.5.40<> /subsection.3.5.41<> /page.208<> /subsection.3.5.42<> /subsection.3.5.43<> /subsection.3.5.44<> /subsection.3.5.45<> /subsection.3.5.46<> /table.3.10<> /page.209<> /section.3.6<> /subsection.3.6.1<> /section*.262<> /section*.263<> /subsection.3.6.2<> /section*.264<> /section*.265<> /page.210<> /subsection.3.6.3<> /section*.266<> /section*.267<> /subsection.3.6.4<> /section*.268<> /section*.269<> /page.211<> /subsection.3.6.5<> /section*.270<> /section*.271<> /section*.272<> /subsection.3.6.6<> /page.212<> /section*.273<> /section*.274<> /subsection.3.6.7<> /section*.275<> /section*.276<> /section*.277<> /subsection.3.6.8<> /page.213<> /section*.278<> /section*.279<> /subsection.3.6.9<> /page.214<> /section*.280<> /section*.281<> /section*.282<> /subsection.3.6.10<> /section*.283<> /page.215<> /section*.284<> /section*.285<> /section*.286<> /page.216<> /section*.287<> /section*.288<> /section*.289<> /page.217<> /section*.290<> /section*.291<> /section*.292<> /subsection.3.6.11<> /section*.293<> /section*.294<> /subsection.3.6.12<> /section*.295<> /page.218<> /section*.296<> /subsection.3.6.13<> /section*.297<> /section*.298<> /subsection.3.6.14<> /section*.299<> /section*.300<> /subsection.3.6.15<> /section*.301<> /page.219<> /section*.302<> /subsection.3.6.16<> /section*.303<> /section*.304<> /subsection.3.6.17<> /section*.305<> /page.220<> /section*.306<> /subsection.3.6.18<> /section*.307<> /section*.308<> /section*.309<> /subsection.3.6.19<> /section*.310<> /section*.311<> /subsection.3.6.20<> /section*.312<> /page.221<> /section*.313<> /subsection.3.6.21<> /section*.314<> /section*.315<> /subsection.3.6.22<> /section*.316<> /page.222<> /section*.317<> /subsection.3.6.23<> /table.3.11<> /section.3.7<> /subsection.3.7.1<> /section*.318<> /page.223<> /subsection.3.7.2<> /section*.319<> /section*.320<> /section*.321<> /subsection.3.7.3<> /subsection.3.7.4<> /subsection.3.7.5<> /page.224<> /section*.322<> /section*.323<> /page.225<> /subsection.3.7.6<> /section*.324<> /subsection.3.7.7<> /section*.325<> /subsection.3.7.8<> /section*.326<> /subsection.3.7.9<> /subsection.3.7.10<> /page.226<> /subsection.3.7.11<> /table.3.12<> /section.3.8<> /page.227<> /section*.327<> /section*.328<> /page.228<> /section.3.9<> /subsection.3.9.1<> /subsection.3.9.2<> /subsection.3.9.3<> /page.229<> /subsection.3.9.4<> /page.230<> /subsection.3.9.5<> /page.231<> /page.232<> /page.233<> /chapter.4<> /section.4.1<> /subsection.4.1.1<> /subsection.4.1.2<> /page.234<> /subsection.4.1.3<> /subsection.4.1.4<> /page.235<> /subsection.4.1.5<> /section*.329<> /section*.330<> /page.236<> /section*.331<> /section*.332<> /section*.333<> /page.237<> /page.238<> /page.239<> /page.240<> /page.241<> /section.4.2<> /page.242<> /subsection.4.2.1<> /subsection.4.2.2<> /page.243<> /page.244<> /subsection.4.2.3<> /section.4.3<> /subsection.4.3.1<> /page.245<> /page.246<> /subsection.4.3.2<> /page.247<> /page.248<> /page.249<> /chapter.5<> /section.5.1<> /section.5.2<> /subsection.5.2.1<> /page.250<> /subsection.5.2.2<> /subsection.5.2.3<> /section.5.3<> /subsection.5.3.1<> /page.251<> /subsection.5.3.2<> /subsection.5.3.3<> /subsection.5.3.4<> /page.252<> /subsection.5.3.5<> /subsection.5.3.6<> /page.253<> /subsection.5.3.7<> /subsection.5.3.8<> /page.254<> /page.255<> /page.256<> /section.5.4<> /page.257<> /page.258<> /page.259<> /appendix*.334<> /cite.phracknmaparticle<> /cite.nmaphomepage<> /cite.cidrnotation<> /cite.whitehatsurl<> /cite.snortdb<> /cite.pcre<>>>endobj 1998 0 obj <>stream dvips + GPL Ghostscript 9.04 () 2013-12-31T11:41:49-05:00 2013-12-31T11:41:49-05:00 LaTeX with hyperref package ()()() endstream endobj 2 0 obj <>endobj xref 0 1999 0000000000 65535 f 0001196098 00000 n 0001421007 00000 n 0001193736 00000 n 0001144227 00000 n 0001318288 00000 n 0001196041 00000 n 0001200566 00000 n 0001196294 00000 n 0001196383 00000 n 0001196482 00000 n 0001197051 00000 n 0001196588 00000 n 0001196694 00000 n 0001196824 00000 n 0001196949 00000 n 0001198007 00000 n 0001197216 00000 n 0001197311 00000 n 0001197410 00000 n 0001197513 00000 n 0001197611 00000 n 0001197709 00000 n 0001197808 00000 n 0001197907 00000 n 0001198345 00000 n 0001198151 00000 n 0001198255 00000 n 0001199043 00000 n 0001198489 00000 n 0001198588 00000 n 0001198700 00000 n 0001198814 00000 n 0001198932 00000 n 0001199375 00000 n 0001199181 00000 n 0001199286 00000 n 0001200118 00000 n 0001199527 00000 n 0001199634 00000 n 0001199763 00000 n 0001199890 00000 n 0001200025 00000 n 0001200257 00000 n 0001200361 00000 n 0001200473 00000 n 0001208717 00000 n 0001200970 00000 n 0001200690 00000 n 0001200778 00000 n 0001200882 00000 n 0001203502 00000 n 0001201092 00000 n 0001201179 00000 n 0001201281 00000 n 0001201386 00000 n 0001201491 00000 n 0001201605 00000 n 0001201712 00000 n 0001201824 00000 n 0001201935 00000 n 0001202047 00000 n 0001202166 00000 n 0001202265 00000 n 0001202364 00000 n 0001202467 00000 n 0001202585 00000 n 0001202703 00000 n 0001202826 00000 n 0001202932 00000 n 0001203044 00000 n 0001203163 00000 n 0001203287 00000 n 0001203402 00000 n 0001203848 00000 n 0001203643 00000 n 0001203736 00000 n 0001204524 00000 n 0001204005 00000 n 0001204101 00000 n 0001204211 00000 n 0001204323 00000 n 0001204431 00000 n 0001204999 00000 n 0001204667 00000 n 0001204763 00000 n 0001204880 00000 n 0001206063 00000 n 0001205147 00000 n 0001205241 00000 n 0001205346 00000 n 0001205451 00000 n 0001205560 00000 n 0001205666 00000 n 0001205764 00000 n 0001205868 00000 n 0001205971 00000 n 0001206535 00000 n 0001206204 00000 n 0001206306 00000 n 0001206429 00000 n 0001206870 00000 n 0001206684 00000 n 0001206775 00000 n 0001207362 00000 n 0001207016 00000 n 0001207117 00000 n 0001207241 00000 n 0001207889 00000 n 0001207525 00000 n 0001207643 00000 n 0001207774 00000 n 0001208583 00000 n 0001208045 00000 n 0001208155 00000 n 0001208272 00000 n 0001208380 00000 n 0001208485 00000 n 0001220922 00000 n 0001208860 00000 n 0001209605 00000 n 0001208950 00000 n 0001209047 00000 n 0001209155 00000 n 0001209266 00000 n 0001209377 00000 n 0001209498 00000 n 0001209751 00000 n 0001210794 00000 n 0001209857 00000 n 0001209945 00000 n 0001210053 00000 n 0001210155 00000 n 0001210257 00000 n 0001210359 00000 n 0001210467 00000 n 0001210574 00000 n 0001210681 00000 n 0001215972 00000 n 0001210947 00000 n 0001211039 00000 n 0001211144 00000 n 0001211251 00000 n 0001211355 00000 n 0001211460 00000 n 0001211567 00000 n 0001211672 00000 n 0001211787 00000 n 0001211897 00000 n 0001212012 00000 n 0001212123 00000 n 0001212238 00000 n 0001212349 00000 n 0001212457 00000 n 0001212569 00000 n 0001212683 00000 n 0001212796 00000 n 0001212907 00000 n 0001213019 00000 n 0001213129 00000 n 0001213235 00000 n 0001213343 00000 n 0001213447 00000 n 0001213555 00000 n 0001213664 00000 n 0001213777 00000 n 0001213888 00000 n 0001213997 00000 n 0001214106 00000 n 0001214218 00000 n 0001214327 00000 n 0001214431 00000 n 0001214534 00000 n 0001214643 00000 n 0001214752 00000 n 0001214865 00000 n 0001214975 00000 n 0001215088 00000 n 0001215198 00000 n 0001215306 00000 n 0001215414 00000 n 0001215522 00000 n 0001215633 00000 n 0001215744 00000 n 0001215853 00000 n 0001218572 00000 n 0001216136 00000 n 0001216231 00000 n 0001216333 00000 n 0001216435 00000 n 0001216536 00000 n 0001216641 00000 n 0001216748 00000 n 0001216852 00000 n 0001216956 00000 n 0001217059 00000 n 0001217167 00000 n 0001217270 00000 n 0001217373 00000 n 0001217479 00000 n 0001217584 00000 n 0001217689 00000 n 0001217796 00000 n 0001217904 00000 n 0001218007 00000 n 0001218115 00000 n 0001218221 00000 n 0001218338 00000 n 0001218449 00000 n 0001219906 00000 n 0001218740 00000 n 0001218830 00000 n 0001218936 00000 n 0001219039 00000 n 0001219143 00000 n 0001219245 00000 n 0001219353 00000 n 0001219464 00000 n 0001219568 00000 n 0001219674 00000 n 0001219790 00000 n 0001220067 00000 n 0001220785 00000 n 0001220176 00000 n 0001220277 00000 n 0001220416 00000 n 0001220561 00000 n 0001220676 00000 n 0001222529 00000 n 0001221619 00000 n 0001221069 00000 n 0001221171 00000 n 0001221293 00000 n 0001221409 00000 n 0001221521 00000 n 0001222056 00000 n 0001221753 00000 n 0001221851 00000 n 0001221966 00000 n 0001222402 00000 n 0001222207 00000 n 0001222312 00000 n 0001318156 00000 n 0001222673 00000 n 0001223084 00000 n 0001222771 00000 n 0001222869 00000 n 0001222985 00000 n 0001224181 00000 n 0001223232 00000 n 0001223339 00000 n 0001223453 00000 n 0001223570 00000 n 0001223691 00000 n 0001223822 00000 n 0001223957 00000 n 0001224075 00000 n 0001224334 00000 n 0000000015 00000 n 0000000521 00000 n 0001224428 00000 n 0001313805 00000 n 0001314293 00000 n 0001316740 00000 n 0001224471 00000 n 0001224506 00000 n 0001144391 00000 n 0000000542 00000 n 0000001199 00000 n 0001224554 00000 n 0001224589 00000 n 0001144557 00000 n 0000001220 00000 n 0000003523 00000 n 0001313650 00000 n 0001224637 00000 n 0001224772 00000 n 0001224910 00000 n 0001225047 00000 n 0001225185 00000 n 0001225320 00000 n 0001225460 00000 n 0001225602 00000 n 0001225745 00000 n 0001225888 00000 n 0001226026 00000 n 0001226168 00000 n 0001226311 00000 n 0001226454 00000 n 0001226597 00000 n 0001226739 00000 n 0001226882 00000 n 0001227024 00000 n 0001227167 00000 n 0001227305 00000 n 0001227447 00000 n 0001227589 00000 n 0001227727 00000 n 0001227870 00000 n 0001228013 00000 n 0001228156 00000 n 0001228299 00000 n 0001228442 00000 n 0001228580 00000 n 0001228723 00000 n 0001228865 00000 n 0001228900 00000 n 0001144971 00000 n 0000003545 00000 n 0000006069 00000 n 0001228948 00000 n 0001229086 00000 n 0001229229 00000 n 0001229372 00000 n 0001229515 00000 n 0001229658 00000 n 0001229801 00000 n 0001229940 00000 n 0001230079 00000 n 0001230218 00000 n 0001230354 00000 n 0001230492 00000 n 0001230635 00000 n 0001230778 00000 n 0001230921 00000 n 0001231059 00000 n 0001231202 00000 n 0001231345 00000 n 0001231488 00000 n 0001231631 00000 n 0001231771 00000 n 0001231911 00000 n 0001232051 00000 n 0001232193 00000 n 0001232335 00000 n 0001232478 00000 n 0001232622 00000 n 0001232766 00000 n 0001232909 00000 n 0001233053 00000 n 0001233197 00000 n 0001233341 00000 n 0001233485 00000 n 0001233629 00000 n 0001233773 00000 n 0001233917 00000 n 0001234061 00000 n 0001234204 00000 n 0001234342 00000 n 0001234377 00000 n 0001145449 00000 n 0000006091 00000 n 0000008834 00000 n 0001234425 00000 n 0001234567 00000 n 0001234710 00000 n 0001234847 00000 n 0001234990 00000 n 0001235133 00000 n 0001235276 00000 n 0001235419 00000 n 0001235562 00000 n 0001235700 00000 n 0001235843 00000 n 0001235986 00000 n 0001236129 00000 n 0001236267 00000 n 0001236410 00000 n 0001236553 00000 n 0001236693 00000 n 0001236836 00000 n 0001236978 00000 n 0001237121 00000 n 0001237261 00000 n 0001237404 00000 n 0001237547 00000 n 0001237684 00000 n 0001237827 00000 n 0001237970 00000 n 0001238110 00000 n 0001238248 00000 n 0001238391 00000 n 0001238533 00000 n 0001238668 00000 n 0001238811 00000 n 0001238954 00000 n 0001239097 00000 n 0001239236 00000 n 0001239380 00000 n 0001239524 00000 n 0001239668 00000 n 0001239807 00000 n 0001239951 00000 n 0001239986 00000 n 0001145943 00000 n 0000008856 00000 n 0000011202 00000 n 0001240021 00000 n 0001240165 00000 n 0001240309 00000 n 0001240452 00000 n 0001240596 00000 n 0001240732 00000 n 0001240870 00000 n 0001241008 00000 n 0001241151 00000 n 0001241294 00000 n 0001241437 00000 n 0001241580 00000 n 0001241723 00000 n 0001241865 00000 n 0001242003 00000 n 0001242141 00000 n 0001242283 00000 n 0001242426 00000 n 0001242569 00000 n 0001242712 00000 n 0001242855 00000 n 0001242998 00000 n 0001243141 00000 n 0001243284 00000 n 0001243427 00000 n 0001243565 00000 n 0001243708 00000 n 0001243851 00000 n 0001243994 00000 n 0001244137 00000 n 0001244280 00000 n 0001244423 00000 n 0001244566 00000 n 0001244709 00000 n 0001244852 00000 n 0001244996 00000 n 0001245140 00000 n 0001245284 00000 n 0001245428 00000 n 0001245463 00000 n 0001146429 00000 n 0000011224 00000 n 0000013716 00000 n 0001245511 00000 n 0001245655 00000 n 0001245799 00000 n 0001245943 00000 n 0001246087 00000 n 0001246231 00000 n 0001246375 00000 n 0001246518 00000 n 0001246662 00000 n 0001246805 00000 n 0001246946 00000 n 0001247090 00000 n 0001247234 00000 n 0001247378 00000 n 0001247522 00000 n 0001247666 00000 n 0001247810 00000 n 0001247953 00000 n 0001248097 00000 n 0001248241 00000 n 0001248385 00000 n 0001248529 00000 n 0001248673 00000 n 0001248817 00000 n 0001248961 00000 n 0001249105 00000 n 0001249249 00000 n 0001249393 00000 n 0001249537 00000 n 0001249681 00000 n 0001249825 00000 n 0001249969 00000 n 0001250113 00000 n 0001250257 00000 n 0001250395 00000 n 0001250538 00000 n 0001250678 00000 n 0001250821 00000 n 0001250964 00000 n 0001251106 00000 n 0001251141 00000 n 0001146923 00000 n 0000013738 00000 n 0000016092 00000 n 0001251176 00000 n 0001251319 00000 n 0001251462 00000 n 0001251605 00000 n 0001251748 00000 n 0001251892 00000 n 0001252036 00000 n 0001252180 00000 n 0001252324 00000 n 0001252468 00000 n 0001252612 00000 n 0001252756 00000 n 0001252900 00000 n 0001253044 00000 n 0001253188 00000 n 0001253332 00000 n 0001253476 00000 n 0001253620 00000 n 0001253764 00000 n 0001253902 00000 n 0001254045 00000 n 0001254188 00000 n 0001254330 00000 n 0001254473 00000 n 0001254616 00000 n 0001254759 00000 n 0001254902 00000 n 0001255045 00000 n 0001255188 00000 n 0001255332 00000 n 0001255476 00000 n 0001255614 00000 n 0001255752 00000 n 0001255894 00000 n 0001256037 00000 n 0001256180 00000 n 0001256323 00000 n 0001256466 00000 n 0001256501 00000 n 0001147401 00000 n 0000016114 00000 n 0000018018 00000 n 0001256536 00000 n 0001256672 00000 n 0001256810 00000 n 0001256953 00000 n 0001257093 00000 n 0001257236 00000 n 0001257379 00000 n 0001257521 00000 n 0001257658 00000 n 0001257801 00000 n 0001257944 00000 n 0001258086 00000 n 0001258224 00000 n 0001258367 00000 n 0001258509 00000 n 0001258645 00000 n 0001258783 00000 n 0001258921 00000 n 0001259064 00000 n 0001259204 00000 n 0001259347 00000 n 0001259485 00000 n 0001259628 00000 n 0001259771 00000 n 0001259914 00000 n 0001260057 00000 n 0001260200 00000 n 0001260343 00000 n 0001260483 00000 n 0001260626 00000 n 0001260761 00000 n 0001260796 00000 n 0001147815 00000 n 0000018040 00000 n 0000022469 00000 n 0001314954 00000 n 0001313320 00000 n 0001315931 00000 n 0001315111 00000 n 0001260844 00000 n 0001260879 00000 n 0001147981 00000 n 0000022491 00000 n 0000028580 00000 n 0001314888 00000 n 0001260979 00000 n 0001261014 00000 n 0001148155 00000 n 0000028602 00000 n 0000034761 00000 n 0001261101 00000 n 0001261136 00000 n 0001148329 00000 n 0000034783 00000 n 0000040422 00000 n 0001261197 00000 n 0001261336 00000 n 0001261480 00000 n 0001261515 00000 n 0001148527 00000 n 0000040444 00000 n 0000046144 00000 n 0001261615 00000 n 0001261650 00000 n 0001148701 00000 n 0000046166 00000 n 0000050421 00000 n 0001261737 00000 n 0001261772 00000 n 0001148867 00000 n 0000050443 00000 n 0000053777 00000 n 0001261833 00000 n 0001261868 00000 n 0001149033 00000 n 0000053799 00000 n 0000056989 00000 n 0001261929 00000 n 0001261964 00000 n 0001149199 00000 n 0000057011 00000 n 0000062510 00000 n 0001262025 00000 n 0001262060 00000 n 0001149373 00000 n 0000062532 00000 n 0000065560 00000 n 0001262134 00000 n 0001262169 00000 n 0001149539 00000 n 0000065582 00000 n 0000069794 00000 n 0001262230 00000 n 0001262265 00000 n 0001149705 00000 n 0000069816 00000 n 0000072767 00000 n 0001262339 00000 n 0001262374 00000 n 0001149871 00000 n 0000072789 00000 n 0000076859 00000 n 0001262448 00000 n 0001262483 00000 n 0001150045 00000 n 0000076881 00000 n 0000081772 00000 n 0001262557 00000 n 0001262592 00000 n 0001150219 00000 n 0000081794 00000 n 0000084931 00000 n 0001262666 00000 n 0001262701 00000 n 0001150393 00000 n 0000084953 00000 n 0000090418 00000 n 0001262801 00000 n 0001262836 00000 n 0001150559 00000 n 0000090440 00000 n 0000094412 00000 n 0001262897 00000 n 0001262932 00000 n 0001150733 00000 n 0000094434 00000 n 0000099312 00000 n 0001263019 00000 n 0001263054 00000 n 0001150907 00000 n 0000099334 00000 n 0000104342 00000 n 0001263128 00000 n 0001263265 00000 n 0001263426 00000 n 0001263610 00000 n 0001263645 00000 n 0001151113 00000 n 0000104364 00000 n 0000107301 00000 n 0001263732 00000 n 0001263876 00000 n 0001263911 00000 n 0001151303 00000 n 0000107323 00000 n 0000111491 00000 n 0001263998 00000 n 0001264033 00000 n 0001151469 00000 n 0000111513 00000 n 0000114362 00000 n 0001264094 00000 n 0001264129 00000 n 0001151643 00000 n 0000114384 00000 n 0000117244 00000 n 0001264190 00000 n 0001264225 00000 n 0001151817 00000 n 0000117266 00000 n 0000123995 00000 n 0001264286 00000 n 0001264431 00000 n 0001264568 00000 n 0001264708 00000 n 0001264743 00000 n 0001152023 00000 n 0000124017 00000 n 0000127504 00000 n 0001264804 00000 n 0001264839 00000 n 0001152197 00000 n 0000127526 00000 n 0000131747 00000 n 0001264913 00000 n 0001264948 00000 n 0001152371 00000 n 0000131769 00000 n 0000134183 00000 n 0001265022 00000 n 0001265057 00000 n 0001152545 00000 n 0000134205 00000 n 0000138977 00000 n 0001265131 00000 n 0001265166 00000 n 0001152719 00000 n 0000138999 00000 n 0000145262 00000 n 0001265240 00000 n 0001265384 00000 n 0001265419 00000 n 0001152909 00000 n 0000145284 00000 n 0000152267 00000 n 0001265493 00000 n 0001265632 00000 n 0001265771 00000 n 0001265806 00000 n 0001153107 00000 n 0000152289 00000 n 0000159434 00000 n 0001265880 00000 n 0001266024 00000 n 0001266168 00000 n 0001266312 00000 n 0001266347 00000 n 0001153313 00000 n 0000159456 00000 n 0000166187 00000 n 0001266408 00000 n 0001266443 00000 n 0001153487 00000 n 0000166209 00000 n 0000173401 00000 n 0001266504 00000 n 0001266680 00000 n 0001266872 00000 n 0001266907 00000 n 0001153685 00000 n 0000173423 00000 n 0000179012 00000 n 0001266994 00000 n 0001267029 00000 n 0001153859 00000 n 0000179034 00000 n 0000184132 00000 n 0001267116 00000 n 0001267151 00000 n 0001154033 00000 n 0000184154 00000 n 0000190302 00000 n 0001267212 00000 n 0001267247 00000 n 0001154207 00000 n 0000190324 00000 n 0000196217 00000 n 0001267308 00000 n 0001267343 00000 n 0001154381 00000 n 0000196239 00000 n 0000204358 00000 n 0001267404 00000 n 0001267543 00000 n 0001267683 00000 n 0001267718 00000 n 0001154579 00000 n 0000204380 00000 n 0000209357 00000 n 0001267766 00000 n 0001267801 00000 n 0001154753 00000 n 0000209379 00000 n 0000214318 00000 n 0001267888 00000 n 0001267923 00000 n 0001154927 00000 n 0000214340 00000 n 0000219212 00000 n 0001268010 00000 n 0001268045 00000 n 0001155101 00000 n 0000219234 00000 n 0000222606 00000 n 0001268132 00000 n 0001268167 00000 n 0001155275 00000 n 0000222628 00000 n 0000227882 00000 n 0001268228 00000 n 0001268372 00000 n 0001268407 00000 n 0001155465 00000 n 0000227904 00000 n 0000233091 00000 n 0001268494 00000 n 0001268529 00000 n 0001155639 00000 n 0000233113 00000 n 0000238130 00000 n 0001268590 00000 n 0001268625 00000 n 0001155813 00000 n 0000238152 00000 n 0000245842 00000 n 0001268686 00000 n 0001268721 00000 n 0001155987 00000 n 0000245864 00000 n 0000249170 00000 n 0001268782 00000 n 0001268817 00000 n 0001156161 00000 n 0000249192 00000 n 0000251093 00000 n 0001268891 00000 n 0001268926 00000 n 0001156335 00000 n 0000251115 00000 n 0000253565 00000 n 0001268974 00000 n 0001269009 00000 n 0001156501 00000 n 0000253587 00000 n 0000260004 00000 n 0001269083 00000 n 0001269118 00000 n 0001156675 00000 n 0000260026 00000 n 0000263947 00000 n 0001269205 00000 n 0001269240 00000 n 0001156841 00000 n 0000263969 00000 n 0000269966 00000 n 0001269314 00000 n 0001269487 00000 n 0001269522 00000 n 0001157031 00000 n 0000269988 00000 n 0000275683 00000 n 0001269622 00000 n 0001269657 00000 n 0001157205 00000 n 0000275705 00000 n 0000280345 00000 n 0001269757 00000 n 0001269894 00000 n 0001269929 00000 n 0001157395 00000 n 0000280367 00000 n 0000285535 00000 n 0001270016 00000 n 0001270153 00000 n 0001270290 00000 n 0001270427 00000 n 0001270462 00000 n 0001157601 00000 n 0000285557 00000 n 0000290718 00000 n 0001313096 00000 n 0001315259 00000 n 0001270536 00000 n 0001270709 00000 n 0001270744 00000 n 0001157791 00000 n 0000290740 00000 n 0000296637 00000 n 0001270844 00000 n 0001270879 00000 n 0001157965 00000 n 0000296659 00000 n 0000303484 00000 n 0001270966 00000 n 0001271001 00000 n 0001158139 00000 n 0000303506 00000 n 0000308747 00000 n 0001271101 00000 n 0001271136 00000 n 0001158313 00000 n 0000308769 00000 n 0000317398 00000 n 0001271210 00000 n 0001271245 00000 n 0001158487 00000 n 0000317420 00000 n 0000325601 00000 n 0001271345 00000 n 0001271380 00000 n 0001158661 00000 n 0000325623 00000 n 0000330950 00000 n 0001271480 00000 n 0001271515 00000 n 0001158835 00000 n 0000330972 00000 n 0000338208 00000 n 0001271602 00000 n 0001271637 00000 n 0001159009 00000 n 0000338230 00000 n 0000344609 00000 n 0001271724 00000 n 0001271759 00000 n 0001159183 00000 n 0000344631 00000 n 0000348086 00000 n 0001271885 00000 n 0001271920 00000 n 0001159357 00000 n 0000348108 00000 n 0000353521 00000 n 0001272007 00000 n 0001272042 00000 n 0001159531 00000 n 0000353543 00000 n 0000360196 00000 n 0001272116 00000 n 0001272261 00000 n 0001272296 00000 n 0001159721 00000 n 0000360218 00000 n 0000366608 00000 n 0001272370 00000 n 0001272515 00000 n 0001272660 00000 n 0001272805 00000 n 0001272950 00000 n 0001272985 00000 n 0001159935 00000 n 0000366630 00000 n 0000373690 00000 n 0001273046 00000 n 0001273081 00000 n 0001160109 00000 n 0000373712 00000 n 0000376369 00000 n 0001273142 00000 n 0001273177 00000 n 0001160275 00000 n 0000376391 00000 n 0000382450 00000 n 0001273238 00000 n 0001273383 00000 n 0001273528 00000 n 0001273563 00000 n 0001160473 00000 n 0000382472 00000 n 0000387927 00000 n 0001273637 00000 n 0001273782 00000 n 0001273927 00000 n 0001273962 00000 n 0001160671 00000 n 0000387949 00000 n 0000393675 00000 n 0001274023 00000 n 0001274168 00000 n 0001274203 00000 n 0001160861 00000 n 0000393697 00000 n 0000400039 00000 n 0001274277 00000 n 0001274422 00000 n 0001274567 00000 n 0001274712 00000 n 0001274747 00000 n 0001161067 00000 n 0000400061 00000 n 0000404059 00000 n 0001274808 00000 n 0001274952 00000 n 0001274987 00000 n 0001161257 00000 n 0000404081 00000 n 0000407460 00000 n 0001275074 00000 n 0001275109 00000 n 0001161431 00000 n 0000407482 00000 n 0000412352 00000 n 0001275209 00000 n 0001275348 00000 n 0001275383 00000 n 0001161621 00000 n 0000412374 00000 n 0000417770 00000 n 0001275483 00000 n 0001275518 00000 n 0001161795 00000 n 0000417792 00000 n 0000423951 00000 n 0001275631 00000 n 0001275666 00000 n 0001161970 00000 n 0000423973 00000 n 0000427834 00000 n 0001275754 00000 n 0001275790 00000 n 0001162148 00000 n 0000427857 00000 n 0000432006 00000 n 0001275878 00000 n 0001275914 00000 n 0001162326 00000 n 0000432029 00000 n 0000437350 00000 n 0001276002 00000 n 0001276038 00000 n 0001162504 00000 n 0000437373 00000 n 0000441923 00000 n 0001276139 00000 n 0001276175 00000 n 0001162682 00000 n 0000441946 00000 n 0000447024 00000 n 0001276276 00000 n 0001276312 00000 n 0001162860 00000 n 0000447047 00000 n 0000450717 00000 n 0001276413 00000 n 0001276449 00000 n 0001163038 00000 n 0000450740 00000 n 0000455750 00000 n 0001276524 00000 n 0001276560 00000 n 0001163216 00000 n 0000455773 00000 n 0000460965 00000 n 0001276622 00000 n 0001276658 00000 n 0001163386 00000 n 0000460988 00000 n 0000466887 00000 n 0001276746 00000 n 0001276782 00000 n 0001163556 00000 n 0000466910 00000 n 0000470957 00000 n 0001276844 00000 n 0001276880 00000 n 0001163734 00000 n 0000470980 00000 n 0000475634 00000 n 0001276955 00000 n 0001276991 00000 n 0001163912 00000 n 0000475657 00000 n 0000481022 00000 n 0001277053 00000 n 0001277089 00000 n 0001164090 00000 n 0000481045 00000 n 0000486140 00000 n 0001277151 00000 n 0001277187 00000 n 0001164268 00000 n 0000486163 00000 n 0000490514 00000 n 0001277249 00000 n 0001277285 00000 n 0001164446 00000 n 0000490537 00000 n 0000493193 00000 n 0001277347 00000 n 0001277383 00000 n 0001164624 00000 n 0000493216 00000 n 0000500051 00000 n 0001277458 00000 n 0001277494 00000 n 0001164802 00000 n 0000500074 00000 n 0000508501 00000 n 0001277556 00000 n 0001277592 00000 n 0001164980 00000 n 0000508524 00000 n 0000515837 00000 n 0001277641 00000 n 0001277677 00000 n 0001165158 00000 n 0000515860 00000 n 0000522472 00000 n 0001277739 00000 n 0001277775 00000 n 0001165336 00000 n 0000522495 00000 n 0000527814 00000 n 0001277850 00000 n 0001277886 00000 n 0001165514 00000 n 0000527837 00000 n 0000534064 00000 n 0001277961 00000 n 0001278107 00000 n 0001278143 00000 n 0001165709 00000 n 0000534087 00000 n 0000539396 00000 n 0001278231 00000 n 0001278267 00000 n 0001165887 00000 n 0000539419 00000 n 0000543733 00000 n 0001278342 00000 n 0001278378 00000 n 0001166065 00000 n 0000543756 00000 n 0000548721 00000 n 0001278453 00000 n 0001278489 00000 n 0001166243 00000 n 0000548744 00000 n 0000552959 00000 n 0001278577 00000 n 0001278613 00000 n 0001166421 00000 n 0000552982 00000 n 0000555928 00000 n 0001278701 00000 n 0001278737 00000 n 0001166599 00000 n 0000555951 00000 n 0000559570 00000 n 0001278812 00000 n 0001278848 00000 n 0001166777 00000 n 0000559593 00000 n 0000565392 00000 n 0001278923 00000 n 0001278959 00000 n 0001166955 00000 n 0000565415 00000 n 0000569421 00000 n 0001279060 00000 n 0001279096 00000 n 0001167133 00000 n 0000569444 00000 n 0000573283 00000 n 0001279171 00000 n 0001279207 00000 n 0001167311 00000 n 0000573306 00000 n 0000578861 00000 n 0001279269 00000 n 0001279305 00000 n 0001167489 00000 n 0000578884 00000 n 0000583020 00000 n 0001279380 00000 n 0001279416 00000 n 0001167667 00000 n 0000583043 00000 n 0000587298 00000 n 0001279478 00000 n 0001279514 00000 n 0001167845 00000 n 0000587321 00000 n 0000591411 00000 n 0001279589 00000 n 0001279625 00000 n 0001168023 00000 n 0000591434 00000 n 0000594863 00000 n 0001279687 00000 n 0001279723 00000 n 0001168201 00000 n 0000594886 00000 n 0000598495 00000 n 0001279811 00000 n 0001279847 00000 n 0001168379 00000 n 0000598518 00000 n 0000603679 00000 n 0001279922 00000 n 0001279958 00000 n 0001168557 00000 n 0000603702 00000 n 0000608199 00000 n 0001280033 00000 n 0001280069 00000 n 0001168735 00000 n 0000608222 00000 n 0000612387 00000 n 0001280144 00000 n 0001280180 00000 n 0001168913 00000 n 0000612410 00000 n 0000620074 00000 n 0001280268 00000 n 0001280304 00000 n 0001169091 00000 n 0000620097 00000 n 0000626939 00000 n 0001280366 00000 n 0001280402 00000 n 0001169269 00000 n 0000626962 00000 n 0000633528 00000 n 0001280438 00000 n 0001280474 00000 n 0001169447 00000 n 0000633551 00000 n 0000639094 00000 n 0001280562 00000 n 0001280598 00000 n 0001169625 00000 n 0000639117 00000 n 0000645801 00000 n 0001280634 00000 n 0001280670 00000 n 0001169803 00000 n 0000645824 00000 n 0000652230 00000 n 0001280706 00000 n 0001280742 00000 n 0001169981 00000 n 0000652253 00000 n 0000655988 00000 n 0001280791 00000 n 0001280827 00000 n 0001170159 00000 n 0000656011 00000 n 0000658618 00000 n 0001280915 00000 n 0001280951 00000 n 0001170337 00000 n 0000658641 00000 n 0000662571 00000 n 0001281026 00000 n 0001281062 00000 n 0001170515 00000 n 0000662594 00000 n 0000667294 00000 n 0001281150 00000 n 0001281186 00000 n 0001170693 00000 n 0000667317 00000 n 0000669604 00000 n 0001281274 00000 n 0001281310 00000 n 0001170871 00000 n 0000669627 00000 n 0000673135 00000 n 0001281372 00000 n 0001281408 00000 n 0001171049 00000 n 0000673158 00000 n 0000678826 00000 n 0001281483 00000 n 0001281519 00000 n 0001171227 00000 n 0000678849 00000 n 0000683262 00000 n 0001281581 00000 n 0001281617 00000 n 0001171405 00000 n 0000683285 00000 n 0000687087 00000 n 0001281679 00000 n 0001281825 00000 n 0001281861 00000 n 0001171600 00000 n 0000687110 00000 n 0000692957 00000 n 0001281936 00000 n 0001281972 00000 n 0001171778 00000 n 0000692980 00000 n 0000699392 00000 n 0001282060 00000 n 0001282096 00000 n 0001171956 00000 n 0000699415 00000 n 0000702968 00000 n 0001282184 00000 n 0001282220 00000 n 0001172134 00000 n 0000702991 00000 n 0000707256 00000 n 0001282282 00000 n 0001282318 00000 n 0001172312 00000 n 0000707279 00000 n 0000711639 00000 n 0001282393 00000 n 0001282429 00000 n 0001172490 00000 n 0000711662 00000 n 0000715126 00000 n 0001282504 00000 n 0001282540 00000 n 0001172668 00000 n 0000715149 00000 n 0000718753 00000 n 0001282615 00000 n 0001282651 00000 n 0001172846 00000 n 0000718776 00000 n 0000723082 00000 n 0001282739 00000 n 0001282775 00000 n 0001173024 00000 n 0000723105 00000 n 0000726268 00000 n 0001282863 00000 n 0001282899 00000 n 0001173194 00000 n 0000726291 00000 n 0000731463 00000 n 0001282948 00000 n 0001282984 00000 n 0001173364 00000 n 0000731486 00000 n 0000733765 00000 n 0001283059 00000 n 0001283095 00000 n 0001173534 00000 n 0000733788 00000 n 0000736788 00000 n 0001283170 00000 n 0001283206 00000 n 0001173704 00000 n 0000736811 00000 n 0000740997 00000 n 0001283281 00000 n 0001283317 00000 n 0001173874 00000 n 0000741020 00000 n 0000744163 00000 n 0001283392 00000 n 0001283428 00000 n 0001174052 00000 n 0000744186 00000 n 0000747494 00000 n 0001283503 00000 n 0001283648 00000 n 0001283684 00000 n 0001174247 00000 n 0000747517 00000 n 0000751585 00000 n 0001283785 00000 n 0001283930 00000 n 0001283966 00000 n 0001174442 00000 n 0000751608 00000 n 0000755261 00000 n 0001284067 00000 n 0001284212 00000 n 0001284248 00000 n 0001174637 00000 n 0000755284 00000 n 0000758697 00000 n 0001284336 00000 n 0001284481 00000 n 0001284517 00000 n 0001174832 00000 n 0000758720 00000 n 0000761590 00000 n 0001284605 00000 n 0001284750 00000 n 0001284895 00000 n 0001285040 00000 n 0001285185 00000 n 0001285330 00000 n 0001285475 00000 n 0001285511 00000 n 0001175064 00000 n 0000761613 00000 n 0000764810 00000 n 0001285573 00000 n 0001285718 00000 n 0001285863 00000 n 0001286008 00000 n 0001286044 00000 n 0001175269 00000 n 0000764833 00000 n 0000769021 00000 n 0001286106 00000 n 0001286251 00000 n 0001286396 00000 n 0001286432 00000 n 0001175473 00000 n 0000769044 00000 n 0000772340 00000 n 0001286494 00000 n 0001286530 00000 n 0001175651 00000 n 0000772363 00000 n 0000773498 00000 n 0001286618 00000 n 0001286654 00000 n 0001175821 00000 n 0000773521 00000 n 0000779556 00000 n 0001286703 00000 n 0001286848 00000 n 0001286993 00000 n 0001287029 00000 n 0001176025 00000 n 0000779579 00000 n 0000782759 00000 n 0001287117 00000 n 0001287153 00000 n 0001176195 00000 n 0000782782 00000 n 0000789162 00000 n 0001287228 00000 n 0001287366 00000 n 0001287504 00000 n 0001287642 00000 n 0001287787 00000 n 0001287823 00000 n 0001176417 00000 n 0000789185 00000 n 0000793234 00000 n 0001287924 00000 n 0001287960 00000 n 0001176595 00000 n 0000793257 00000 n 0000795529 00000 n 0001288048 00000 n 0001288084 00000 n 0001176765 00000 n 0000795552 00000 n 0000800094 00000 n 0001313580 00000 n 0001288146 00000 n 0001288182 00000 n 0001176943 00000 n 0000800117 00000 n 0000804690 00000 n 0001288285 00000 n 0001288321 00000 n 0001177121 00000 n 0000804713 00000 n 0000809101 00000 n 0001288424 00000 n 0001288460 00000 n 0001177299 00000 n 0000809124 00000 n 0000813631 00000 n 0001288563 00000 n 0001288599 00000 n 0001177477 00000 n 0000813654 00000 n 0000817729 00000 n 0001288674 00000 n 0001288710 00000 n 0001177647 00000 n 0000817752 00000 n 0000818726 00000 n 0001288772 00000 n 0001288808 00000 n 0001177817 00000 n 0000818748 00000 n 0000823316 00000 n 0001288857 00000 n 0001288996 00000 n 0001289032 00000 n 0001178012 00000 n 0000823339 00000 n 0000828315 00000 n 0001289133 00000 n 0001289279 00000 n 0001289315 00000 n 0001178199 00000 n 0000828338 00000 n 0000833673 00000 n 0001289377 00000 n 0001289516 00000 n 0001289655 00000 n 0001289794 00000 n 0001289933 00000 n 0001290072 00000 n 0001290108 00000 n 0001178422 00000 n 0000833696 00000 n 0000839999 00000 n 0001290183 00000 n 0001290322 00000 n 0001290467 00000 n 0001290613 00000 n 0001290752 00000 n 0001290788 00000 n 0001178644 00000 n 0000840022 00000 n 0000844686 00000 n 0001290889 00000 n 0001291076 00000 n 0001291221 00000 n 0001291257 00000 n 0001178848 00000 n 0000844709 00000 n 0000848807 00000 n 0001291332 00000 n 0001291477 00000 n 0001291622 00000 n 0001291658 00000 n 0001179044 00000 n 0000848830 00000 n 0000853410 00000 n 0001291759 00000 n 0001291904 00000 n 0001292042 00000 n 0001292078 00000 n 0001179248 00000 n 0000853433 00000 n 0000858374 00000 n 0001292140 00000 n 0001292176 00000 n 0001179426 00000 n 0000858397 00000 n 0000863002 00000 n 0001292238 00000 n 0001292376 00000 n 0001292516 00000 n 0001292552 00000 n 0001179630 00000 n 0000863025 00000 n 0000868497 00000 n 0001292640 00000 n 0001292676 00000 n 0001179808 00000 n 0000868520 00000 n 0000872634 00000 n 0001292764 00000 n 0001292909 00000 n 0001293054 00000 n 0001293199 00000 n 0001293344 00000 n 0001293489 00000 n 0001293634 00000 n 0001293779 00000 n 0001293924 00000 n 0001294070 00000 n 0001294216 00000 n 0001294362 00000 n 0001294508 00000 n 0001294654 00000 n 0001294800 00000 n 0001294946 00000 n 0001295092 00000 n 0001295238 00000 n 0001295383 00000 n 0001295419 00000 n 0001180156 00000 n 0000872657 00000 n 0000876194 00000 n 0001295481 00000 n 0001295517 00000 n 0001180334 00000 n 0000876217 00000 n 0000880465 00000 n 0001295579 00000 n 0001295724 00000 n 0001295869 00000 n 0001296014 00000 n 0001296050 00000 n 0001180547 00000 n 0000880488 00000 n 0000885307 00000 n 0001296125 00000 n 0001296270 00000 n 0001296415 00000 n 0001296560 00000 n 0001296596 00000 n 0001180760 00000 n 0000885330 00000 n 0000888917 00000 n 0001296684 00000 n 0001296829 00000 n 0001296974 00000 n 0001297119 00000 n 0001297155 00000 n 0001180973 00000 n 0000888940 00000 n 0000892315 00000 n 0001297243 00000 n 0001297389 00000 n 0001297425 00000 n 0001181168 00000 n 0000892338 00000 n 0000895491 00000 n 0001297513 00000 n 0001297658 00000 n 0001297694 00000 n 0001181363 00000 n 0000895514 00000 n 0000900465 00000 n 0001297782 00000 n 0001297927 00000 n 0001298072 00000 n 0001298217 00000 n 0001298253 00000 n 0001181576 00000 n 0000900488 00000 n 0000906608 00000 n 0001298341 00000 n 0001298377 00000 n 0001181754 00000 n 0000906631 00000 n 0000911897 00000 n 0001298465 00000 n 0001298501 00000 n 0001181932 00000 n 0000911920 00000 n 0000915908 00000 n 0001298589 00000 n 0001298734 00000 n 0001298879 00000 n 0001299024 00000 n 0001299169 00000 n 0001299314 00000 n 0001299459 00000 n 0001299605 00000 n 0001299750 00000 n 0001299786 00000 n 0001182190 00000 n 0000915931 00000 n 0000919752 00000 n 0001299874 00000 n 0001300019 00000 n 0001300180 00000 n 0001300216 00000 n 0001182386 00000 n 0000919775 00000 n 0000924765 00000 n 0001300278 00000 n 0001300416 00000 n 0001300554 00000 n 0001300692 00000 n 0001300728 00000 n 0001182599 00000 n 0000924788 00000 n 0000930151 00000 n 0001300816 00000 n 0001300961 00000 n 0001300997 00000 n 0001182794 00000 n 0000930174 00000 n 0000936600 00000 n 0001301059 00000 n 0001301095 00000 n 0001182972 00000 n 0000936623 00000 n 0000940489 00000 n 0001301157 00000 n 0001301193 00000 n 0001183150 00000 n 0000940512 00000 n 0000944875 00000 n 0001301281 00000 n 0001301426 00000 n 0001301572 00000 n 0001301713 00000 n 0001301749 00000 n 0001183363 00000 n 0000944898 00000 n 0000948302 00000 n 0001301863 00000 n 0001302008 00000 n 0001302044 00000 n 0001183558 00000 n 0000948325 00000 n 0000953464 00000 n 0001302106 00000 n 0001302252 00000 n 0001302393 00000 n 0001302429 00000 n 0001183762 00000 n 0000953487 00000 n 0000958240 00000 n 0001302530 00000 n 0001302566 00000 n 0001183940 00000 n 0000958263 00000 n 0000964349 00000 n 0001302654 00000 n 0001302690 00000 n 0001184118 00000 n 0000964372 00000 n 0000967031 00000 n 0001302765 00000 n 0001302911 00000 n 0001303057 00000 n 0001303203 00000 n 0001303349 00000 n 0001303495 00000 n 0001303641 00000 n 0001303787 00000 n 0001303933 00000 n 0001303969 00000 n 0001184376 00000 n 0000967054 00000 n 0000971997 00000 n 0001304057 00000 n 0001304203 00000 n 0001304349 00000 n 0001304495 00000 n 0001304641 00000 n 0001304782 00000 n 0001304923 00000 n 0001305064 00000 n 0001305210 00000 n 0001305356 00000 n 0001305502 00000 n 0001305538 00000 n 0001184652 00000 n 0000972020 00000 n 0000974848 00000 n 0001305600 00000 n 0001305746 00000 n 0001305892 00000 n 0001306038 00000 n 0001306184 00000 n 0001306220 00000 n 0001184874 00000 n 0000974871 00000 n 0000976615 00000 n 0001306282 00000 n 0001306318 00000 n 0001185044 00000 n 0000976638 00000 n 0000979211 00000 n 0001306380 00000 n 0001306416 00000 n 0001185214 00000 n 0000979234 00000 n 0000981964 00000 n 0001306478 00000 n 0001306514 00000 n 0001185384 00000 n 0000981987 00000 n 0000986029 00000 n 0001306576 00000 n 0001306721 00000 n 0001306757 00000 n 0001185579 00000 n 0000986052 00000 n 0000990556 00000 n 0001306845 00000 n 0001306990 00000 n 0001307026 00000 n 0001185774 00000 n 0000990579 00000 n 0000993938 00000 n 0001307088 00000 n 0001307124 00000 n 0001185952 00000 n 0000993961 00000 n 0000996622 00000 n 0001307186 00000 n 0001307222 00000 n 0001186122 00000 n 0000996645 00000 n 0000999155 00000 n 0001307284 00000 n 0001307320 00000 n 0001186292 00000 n 0000999178 00000 n 0001001375 00000 n 0001307382 00000 n 0001307418 00000 n 0001186462 00000 n 0001001398 00000 n 0001003259 00000 n 0001307480 00000 n 0001307516 00000 n 0001186640 00000 n 0001003282 00000 n 0001006031 00000 n 0001307578 00000 n 0001307614 00000 n 0001186818 00000 n 0001006054 00000 n 0001009346 00000 n 0001307676 00000 n 0001307712 00000 n 0001186996 00000 n 0001009369 00000 n 0001014469 00000 n 0001307813 00000 n 0001307849 00000 n 0001187174 00000 n 0001014492 00000 n 0001019084 00000 n 0001307911 00000 n 0001308057 00000 n 0001308203 00000 n 0001308239 00000 n 0001187370 00000 n 0001019107 00000 n 0001024926 00000 n 0001308314 00000 n 0001308459 00000 n 0001308495 00000 n 0001187565 00000 n 0001024949 00000 n 0001028919 00000 n 0001308598 00000 n 0001308743 00000 n 0001308888 00000 n 0001309033 00000 n 0001309069 00000 n 0001187778 00000 n 0001028942 00000 n 0001034812 00000 n 0001309131 00000 n 0001309279 00000 n 0001309426 00000 n 0001309462 00000 n 0001187982 00000 n 0001034835 00000 n 0001039467 00000 n 0001309550 00000 n 0001309586 00000 n 0001188160 00000 n 0001039490 00000 n 0001044903 00000 n 0001309648 00000 n 0001309684 00000 n 0001188338 00000 n 0001044926 00000 n 0001050169 00000 n 0001309759 00000 n 0001309795 00000 n 0001188508 00000 n 0001050192 00000 n 0001052636 00000 n 0001309883 00000 n 0001309919 00000 n 0001188686 00000 n 0001052659 00000 n 0001056708 00000 n 0001310007 00000 n 0001310043 00000 n 0001188864 00000 n 0001056731 00000 n 0001059871 00000 n 0001310105 00000 n 0001310141 00000 n 0001189034 00000 n 0001059894 00000 n 0001063719 00000 n 0001310190 00000 n 0001310226 00000 n 0001189212 00000 n 0001063742 00000 n 0001067823 00000 n 0001310301 00000 n 0001310337 00000 n 0001189390 00000 n 0001067846 00000 n 0001071386 00000 n 0001310412 00000 n 0001310448 00000 n 0001189568 00000 n 0001071409 00000 n 0001074454 00000 n 0001310523 00000 n 0001310559 00000 n 0001189746 00000 n 0001074477 00000 n 0001078086 00000 n 0001310634 00000 n 0001310670 00000 n 0001189916 00000 n 0001078109 00000 n 0001080910 00000 n 0001310745 00000 n 0001310781 00000 n 0001190094 00000 n 0001080933 00000 n 0001084500 00000 n 0001310856 00000 n 0001310892 00000 n 0001190264 00000 n 0001084523 00000 n 0001087648 00000 n 0001310980 00000 n 0001311016 00000 n 0001190434 00000 n 0001087671 00000 n 0001092639 00000 n 0001311104 00000 n 0001311140 00000 n 0001190604 00000 n 0001092662 00000 n 0001096769 00000 n 0001311228 00000 n 0001311264 00000 n 0001190782 00000 n 0001096792 00000 n 0001102976 00000 n 0001311352 00000 n 0001311388 00000 n 0001190960 00000 n 0001102999 00000 n 0001107661 00000 n 0001311463 00000 n 0001311499 00000 n 0001191138 00000 n 0001107684 00000 n 0001110142 00000 n 0001311600 00000 n 0001311636 00000 n 0001191308 00000 n 0001110165 00000 n 0001113226 00000 n 0001311685 00000 n 0001311721 00000 n 0001191486 00000 n 0001113249 00000 n 0001116296 00000 n 0001311796 00000 n 0001311832 00000 n 0001191664 00000 n 0001116319 00000 n 0001118897 00000 n 0001311920 00000 n 0001311956 00000 n 0001191834 00000 n 0001118920 00000 n 0001123373 00000 n 0001312018 00000 n 0001312054 00000 n 0001192012 00000 n 0001123396 00000 n 0001126446 00000 n 0001312116 00000 n 0001312152 00000 n 0001192182 00000 n 0001126469 00000 n 0001128505 00000 n 0001312214 00000 n 0001312250 00000 n 0001192352 00000 n 0001128528 00000 n 0001130989 00000 n 0001312312 00000 n 0001312348 00000 n 0001192530 00000 n 0001131012 00000 n 0001134407 00000 n 0001312436 00000 n 0001312472 00000 n 0001192708 00000 n 0001134430 00000 n 0001137100 00000 n 0001312560 00000 n 0001312596 00000 n 0001192878 00000 n 0001137123 00000 n 0001139619 00000 n 0001312658 00000 n 0001312694 00000 n 0001193056 00000 n 0001139642 00000 n 0001139833 00000 n 0001312769 00000 n 0001312805 00000 n 0001193226 00000 n 0001139855 00000 n 0001141840 00000 n 0001312841 00000 n 0001312877 00000 n 0001193396 00000 n 0001141863 00000 n 0001143408 00000 n 0001312926 00000 n 0001312962 00000 n 0001193566 00000 n 0001143431 00000 n 0001144205 00000 n 0001313011 00000 n 0001313047 00000 n 0001315506 00000 n 0001316174 00000 n 0001317023 00000 n 0001313484 00000 n 0001313735 00000 n 0001313891 00000 n 0001314014 00000 n 0001314694 00000 n 0001315041 00000 n 0001315193 00000 n 0001419389 00000 n trailer << /Size 1999 /Root 1 0 R /Info 2 0 R /ID [<78C7EB20DF22D8271F47EEFBB8C47FBC><78C7EB20DF22D8271F47EEFBB8C47FBC>] >> startxref 1421218 %%EOF snort-2.9.6.0/doc/WISHLIST0000644000000000000000000000236512260355636011676 00000000000000$Id$ SIGNATURES ---- * UDP & ICMP flow. (Client = first person to talk?) * Distance from beginning of the stream * Distance between CONTENT and to NEWLINE * IP Ranges * Port ranges * SRC & DST ports not required for signatures of protocols that don't have ports PLUGINS ---- * unified IP formats (IPs are specified in the same way for every plugin) * Better portscan detection * coffee plugin. (Over $X high priority alarms during off hours = make big pot of coffee) * all plugin alerts contain the following configurations - priority - classtype - references - host ranges (IP ranges, just like rules) - port ranges (port ranges, just like rules) PROTOCOLS ---- * email parsing (i.e. flagging on an attachment name) * HTTP CGI Variables (GET & POST) * HTTP/1.1 decodes GENERAL ---- * method to reload signatures without killing state engine * self healing (dropping lots of packets? drop lower priority signatures) * regular statistic dumps * better access to protocol stats (I.e. 70% TCP, 20% UDP, 10% ICMP) * better access to port stats (I.e. 70% 80 , 20% 25, 10% 22) * multithreading * thresholds for all alerts (signatures & plugins) - X sid:313 alerts from Y hosts in Z seconds - X tcp overlap alerts from the same host in Y seconds snort-2.9.6.0/doc/USAGE0000644000000000000000000002652312260355636011276 00000000000000/* $Id$ */ How to use Snort by Martin Roesch 1.0 GETTING STARTED Snort really isn't very hard to use, but there are a lot of command line options to play with, and it's not always obvious which ones go together well. This file aims to make using Snort easier for new users. Before we proceed, there are a few basic concepts you should understand about Snort. There are three main modes in which Snort can be configured: sniffer, packet logger, and network intrusion detection system. Sniffer mode simply reads the packets off of the network and displays them for you in a continuous stream on the console. Packet logger mode logs the packets to the disk. Network intrusion detection mode is the most complex and configurable configuration, allowing Snort to analyze network traffic for matches against a user defined rule set and perform several actions based upon what it sees. 2.0 SNIFFER MODE First, let's start with the basics. If you just want to print out the TCP/IP packet headers to the screen (i.e. sniffer mode), try this: ./snort -v This command will run Snort and just show the IP and TCP/UDP/ICMP headers, nothing else. If you want to see the payload data in transit, try the following: ./snort -vd This instructs Snort to display the packet data as well as the headers. If you want an even more descriptive display, showing the data link layer headers do this: ./snort -vde (As an aside, these switches may be divided up or smashed together in any combination. The last command could also be typed out as: ./snort -d -v -e and it would do the same thing.) 3.0 PACKET LOGGER MODE Ok, all of these commands are pretty cool, but if you want to record the packets to the disk, you need to specify a logging directory and Snort will automatically know to go into packet logger mode: ./snort -dev -l ./log Of course, this assumes you have a directory named "log" in the current directory. If you don't, Snort will exit with an error message. When Snort runs in this mode, it collects every packet it sees and places it in a directory hierarchy based upon the IP address of one of the hosts in the datagram. If you just specify a plain "-l" switch, you may notice that Snort sometimes uses the address of the remote computer as the directory in which it places packets, and sometimes it uses the local host address. In order to log relative to the home network, you need to tell Snort which network is the home network: ./snort -dev -l ./log -h 192.168.1.0/24 This rule tells Snort that you want to print out the data link and TCP/IP headers as well as application data into the directory ./log, and you want to log the packets relative to the 192.168.1.0 class C network. All incoming packets will be recorded into subdirectories of the log directory, with the directory names being based on the address of the remote (non-192.168.1) host. Note that if both hosts are on the home network, then they are recorded based upon the higher of the two's port numbers, or in the case of a tie, the source address. If you're on a high speed network or you want to log the packets into a more compact form for later analysis you should consider logging in "binary mode". Binary mode logs the packets in "tcpdump format" to a single binary file in the logging directory: ./snort -l ./log -b Note the command line changes here. We don't need to specify a home network any longer because binary mode logs everything into a single file, which eliminates the need to tell it how to format the output directory structure. Additionally, you don't need to run in verbose mode or specify the -d or -e switches because in binary mode the entire packet is logged, not just sections of it. All that is really required to place Snort into logger mode is the specification of a logging directory at the command line with the -l switch, the -b binary logging switch merely provides a modifier to tell it to log the packets in something other than the default output format of plain ASCII text. Once the packets have been logged to the binary file, you can read the packets back out of the file with any sniffer that supports the tcpdump binary format such as tcpdump or Ethereal. Snort can also read the packets back by using the -r switch, which puts it into playback mode. Packets from any tcpdump formatted file can be processed through Snort in any of its run modes. For example, if you wanted to run a binary log file through Snort in sniffer mode to dump the packets to the screen, you can try something like this: ./snort -dv -r packet.log You can manipulate the data in the file in a number of ways through Snort's packet logging and intrusion detection modes, as well as with the BPF interface that's available from the command line. For example, if you only wanted to see the ICMP packets from the log file, simply specify a BPF filter at the command line and Snort will only "see" the ICMP packets in the file: ./snort -dvr packet.log icmp For more info on how to use the BPF interface, read the man page. 4.0 NETWORK INTRUSION DETECTION MODE To enable network intrusion detection (NIDS) mode (so that you don't record every single packet sent down the wire), try this: ./snort -dev -l ./log -h 192.168.1.0/24 -c snort.conf Where snort.conf is the name of your rules file. This will apply the rules set in the snort.conf file to each packet to decide if an action based upon the rule type in the file should be taken. If you don't specify an output directory for the program, it will default to /var/log/snort. One thing to note about the last command line is that if Snort is going to be used in a long term way as an IDS, the "-v" switch should be left off the command line for the sake of speed. The screen is a slow place to write data to, and packets can be dropped while writing to the display. It's also not necessary to record the data link headers for most applications, so the so it's not necessary to specify the -e switch either. ./snort -d -h 192.168.1.0/24 -l ./log -c snort.conf This will configure Snort to run in its most basic NIDS form, logging packets that the rules tell it to in plain ASCII to a hierarchical directory structure (just like packet logger mode). 4.1 NIDS MODE OUTPUT OPTIONS There are a number of ways to configure the output of Snort in NIDS mode. The default logging and alerting mechanisms are to log in decoded ASCII format and use "full" alerts. The full alert mechanism prints out the alert message in addition to the full packet headers. There are several other alert output modes available at the command line, as well as two logging facilities. Packets can be logged to their default decoded ASCII format or to a binary log file via the -b command line switch. If you wish to disable packet logging altogether, use the -N command line switch. Alert modes are somewhat more complex. There are seven alert modes available at the command line: full, fast, socket, syslog, console, cmg, and none. Six of these modes are accessed with the -A command line switch. These are: -A fast - fast alert mode, write the alert in a simple format with a timestamp, alert message, source and destination IPs/ports -A full - this is also the default alert mode, so if you specify nothing this will automatically be used -A unsock - send alerts to a UNIX socket that another program can listen on -A none - turn off alerting -A console - send "fast-style" alerts to the console (screen) -A cmg - generate "cmg style" alerts To send alerts to syslog, use the -s switch. The default facilities for the syslog alerting mechanism are LOG_AUTHPRIV and LOG_ALERT. If you want to configure other facilities for syslog output, use the output plugin directives in the rules files (see the snort.conf file for more information). Here are some output configuration examples: 1) Log to default (decoded ASCII) facility and send alerts to syslog snort -c snort.conf -l ./log -s -h 192.168.1.0/24 2) Log to the default facility in /var/log/snort and send alerts to a fast alert file: snort -c snort.conf -s -h 192.168.1.0/24 3) Log to a binary file and use fast alerting mode, logging to /var/snort: snort -c snort.conf -b -A fast -l /var/snort 4.2 PERFORMANCE CONFIGURATION If you want Snort to go *fast* (like keep up with a 100 Mbps net fast) use the "-b" and "-A fast" or "-s" (syslog) options. This will log packets in tcpdump format and produce minimal alerts. For example: ./snort -b -A fast -c snort-lib In this configuration, Snort has been able to log multiple simultaneous probes and attacks on a 100 Mbps LAN running at a saturation level of approximately 80 Mbps. In this configuration the logs are written in binary format to the snort.log tcpdump-formatted file. To read this file back and break out the data in the familiar Snort format, just rerun Snort on the data file with the "-r" option and the other options you would normally use. For example: ./snort -d -c snort-lib -l ./log -h 192.168.1.0/24 -r snort.log Once this is done running, all of the data will be sitting in the log directory in its normal decoded format. Cool, eh? 4.3 OTHER STUFF Some people don't like the default way in which Snort applies its rules to packets, with the Alert rules applied first, then the Pass rules, and finally the Log rules. This sequence is somewhat counterintuitive, but it's a more foolproof method than allowing the user to write a hundred alert rules and then disable them all with an errant pass rule. For people who know what they're doing, the "-o" switch has been provided to change the default rule applicaition behavior to Pass rules, then Alert, then Log: ./snort -d -h 192.168.1.0/24 -l ./log -c snort.conf -o 5.0 MISCELLANEOUS STUFF If you are willing to run snort in "daemon" mode, you can add -D switch to any combination above. PLEASE NOTE that if you want to be able to restart snort by sending SIGHUP signal to the daemon, you will need to use full path to snort binary, when you start it, i.g.: /usr/local/bin/snort -d -h 192.168.1.0/24 -l /var/log/snortlogs -c /usr/local/etc/snort-lib -s -D Relative paths are not supported due to security concerns. If you're going to be posting packet logs to public mailing lists you might want to try out the -O switch. This switch "obfuscates" the IP addresses in the packet printouts. This is handy if you don't want the people on the mailing list to know the IP addresses involved. You can also combine the -O switch with the -h switch to only obfuscate the IP addresses of hosts on the home network. This is useful if you don't care who sees the address of the attacking host. For example: ./snort -d -v -r snort.log -O -h 192.168.1.0/24 This will read the packets from a log file and dump the packets to the screen, obfuscating only the addresses from the 192.168.1.0/24 class C network. If you want to see Snort's packet statistics without stopping the process, send a SIGUSR1 to the Snort process ID and it will dump stats to the screen or syslog if it's running in daemon mode. This will allow you to see which protocols Snort has been seeing, get counts of alerts and logged packets and counts of total packets seen and dropped. It's a very handy capability if you're tweaking Snort for performance. Well, that's about it for now. If you have any further questions about using Snort, drop me an e-mail at roesch@sourcefire.com. snort-2.9.6.0/doc/TODO0000644000000000000000000000003611314032563011154 00000000000000$Id$ - update the todo list snort-2.9.6.0/doc/README.WIN320000644000000000000000000002013312153454767012165 00000000000000$Id$ Snort Installation for the Win32 environment March 2003 by Rich Adamson ( radamson at routers dot com ) and updated in December 2004, March 2006. Introduction The snort intrusion detection system was written as an application intended for use on a Unix operating system, relying mostly on a low-level independent communications driver referred to as libpcap. Thanks to the efforts by a number of supporters(1), snort has been ported to the 32-bit Microsoft Windows operating systems of recent vintage including Windows NT, 2000, XP and others. Snort requires the same low-level drivers, WinPcap, in order to function on the Windows operating system. (Note: running snort on the older Windows 9x systems should be avoided.) This README file is intended to document the minimum drivers required by snort. The user may wish to install other snort-related components such as IIS, Apache, or Snortsnarf as well. Installation documentation for those components is available from(2): http://www.winsnort.com Snort Following the installation instructions provided with snort. WinPcap Driver Snort requires the WinPcap driver to be installed in order to function. Snort has been extensively tested with WinPcap v4.1. The current installation package can be downloaded from: http://winpcap.org/ The WinPcap installation will install packet.dll and wpcap.dll drivers in the system32 directory. (Note: if older versions of these two drivers exist, the instructions at the above URL suggests manually deleting them from your system, reboot, then install newer drivers. Do NOT use any of the WinPcap "beta" versions as they are likely to fail.) LibnetNT Driver Certain snort functions, notably the FlexResp functions, will also require an appropriate version of LibnetNT to be installed in order for snort to operate properly. Snort 2.6 has been tested with the version of LibnetNT version 1.02f. The current installation package can be downloaded from: http://www.securitybugware.org/libnetnt/ The snort installation includes LibnetNT.dll driver in the snort/bin directory, and relies on the use the WinPcap drivers noted above to function. (Note: the FlexResp routines were being rewritten as of Dec 2004, therefore please verify that work has been completed prior to attempting to use them.) Installation Test Steps: The following steps can be used to test the installation of snort and its associated drivers. 1. From a command line prompt, change directories to where snort was installed (cd \snort\bin) 2. Execute the following as a way to verify that snort can access the WinPcap drivers: snort -W The result should provide a list of available NIC adapters on the system. If more than one adapter is listed, note the interface number (e.g, 1, 2, 3) of the NIC adapter that you expect snort to use for monitoring/sniffing. If the command does not provide any list, the WinPcap drivers are not installed properly; review the installation procedures provided with WinPcap and reinstall if necessary. (Note specifically the instructions at http://winpcap.polito.it/ that suggest removing old versions of WinPcap and rebooting prior to installing a newer version.) 3. Execute the following to ensure an understanding as to which version of snort is installed: snort -V and note the result (version 2.2, etc.). The specific version number will be required if you ask for assistance from the snort mailing list along with the specific Windows operating system that you are using. 4. Next, using the interface number noted in step #2, above, execute: snort -v -n 3 -i 2 where 2 should be replaced with the interface number noted. This will cause snort to operate in a basic sniffer mode (-v), displaying the headers of the first 3 packets observed (-n 3) from the interface specified (-i 2). If packets are displayed, snort is functional and can find the low-level WinPcap drivers. If no packets are displayed, either the packet drivers are not installed correctly, or, the interface number (-i 2 in the example above) is incorrect. 5. If snort is functional, locate and read the contents of the snort.conf configuration file. The default installation places the file in the snort\etc directory. Modify the contents to include: var HOME_NET 10.1.1.0/27 (replace 10.1.1.0/27 with your internal network addresses) var EXTERNAL_NET !$HOME_NET (this tells snort the External Network is everything not Internal) var RULE_PATH c:\snort\rules (this tells snort where to find the installed Rules) Save the text file, and execute the following (adjust each directory path to match your installation): C:\Snort\snort.exe -c "C:\snort\etc\snort.conf" -l "C:\snort\Log" -A full -i 2 -d -e -X Note: Be sure to create the c:\snort\log directory on your machine before executing the above. If the above command line entry does not return to a command line prompt, then snort is running, listening to all packets on interface 2 (-i 2), dumping those packets that match the Rules to files in the C:\snort\Log directory. If after executing the above, snort aborts and returns to a command line prompt, carefully read the data that snort sent to the screen as it will suggest configuration and rule errors, etc. 6. Carefully READ the documentation included in the snort installation, including: snort\doc\snort_manual.pdf snort\doc\FAQ Note: these two references (along with other text files included in the snort\doc directory) should answer 95% of your initial questions. Technical Notes: 1. Snort was written using the C programming language calling various routines provided in the libpcap.lib and packet.lib libraries. If an old version of WinPcap exits on your Windows system, newer versions should be installed from the URLs noted above. At the time this document was written, snort v2.2 functioned properly on Windows 2000, 2003, and Windows XP systems with: system32\packet.dll version reported: 3.0.0.18 dated April 4, 2003 size: 57,344 bytes system32\wpcap.dll version reported: 3.0.0.18 dated April 4, 2003 size: 1208,896 bytes snort\bin\LibnetNT.dll (no version reported) dated May 2, 2003 size 68,161 bytes 2. If you intend to run snort on a multiprocessor Intel system, WinPcap v3.0 or higher is required. Earlier versions of these libraries did not support the multiprocessor systems. Do NOT attempt to use any of the WinPcap "beta" versions as snort will likely fail. 3. If you intend to run snort as a Win32 Service, ALWAYS run snort from the command line FIRST to ensure there are no configuration or rule errors. Snort will NOT report errors when run as a Service; it will simply abort providing no clue why it aborted. The syntax for running snort as a Service can be seen by simply executing snort from the command line (no command line parameters) and reviewing the first several lines displayed. ============================================================= (1) Contributors to this README file include: Rich Adamson Chris Reid (2) Installation Documentation for other Snort-related components: Michael E. Steele, ( www.winsnort.com ) has prepared, written and maintained several excellent documents integrating other snort-related components. The documents can be downloaded from: http://www.winsnort.com As of March 2003, the following configuration / installation documents were available: Snort with IIS and Snortsnarf Snort with MySQL, IIS and ACID Snort with Apache and Snortsnarf Snort with MySQL, Apache and ACID Snort with Slave and Snortsnarf Snort with MySQL, Slave and ACID snort-2.9.6.0/doc/README.variables0000644000000000000000000001144712026730050013320 00000000000000IP and Port lists ----------------- Adam Keeton Documentation last update 2007-08-08 Overview ======== The Snort configuration file allows a user to declare and use variables for configuring Snort. Variables may contain a string (such as to be used in a path), IPs, or ports. NOTE: The behavior for negating IP, IP lists, and CIDR blocks has changed! See the IP Variables and IP Lists section below for more information. IP Variables and IP Lists ========================= IPs may be specified individually, in a list, as a CIDR block, or any combination of the three. IP variables should be specified using 'ipvar' instead of 'var'. Using 'var' for an IP variable is still allowed for backward compatibility, but it will be deprecated in a future release. Lists of IPs or CIDR blocks must be enclosed in square brackets. IPs, IP lists, and CIDR blocks may be negated with '!'. Negation is handled differently compared with Snort versions 2.7.x and earlier. Previously, each element in a list was logically OR'ed together. IP lists now OR non-negated elements and AND the result with the OR'ed negated elements. For example: The list: [1.1.1.1,2.2.2.0/24,![2.2.2.2,2.2.2.3]] Will match the IP 1.1.1.1 and IP from 2.2.2.0 to 2.2.2.255, with the exception of 2.2.2.2 and 2.2.2.3. The order of elements in the list does not matter. The element 'any' can be used to match all IPs, although '!any' is not allowed. Also, negated IP ranges that are more general than non-negated IP ranges are not allowed. Examples of valid uses of IP variables and lists: ipvar EXAMPLE [1.1.1.1,2.2.2.0/24,![2.2.2.2,2.2.2.3]] alert tcp $EXAMPLE any -> any any (msg:"Example"; sid:1;) alert tcp [1.0.0.0/8,!1.1.1.0/24] any -> any any (msg:"Example";sid:2;) Examples of invalid uses of IP variables and lists: Use of !any: ipvar EXAMPLE any alert tcp !$EXAMPLE any -> any any (msg:"Example";sid:3;) Or: ipvar EXAMPLE !any alert tcp $EXAMPLE any -> any any (msg:"Example";sid:3;) Logical contradictions: ipvar EXAMPLE [1.1.1.1,!1.1.1.1] Nonsensical negations: ipvar EXAMPLE [1.1.1.0/24,!1.1.0.0/16] Port Variables and Port Lists ============================= Portlists supports the declaration and lookup of ports and the representation of lists and ranges of ports. Variables, ranges, or lists may all be negated with '!'. Also, 'any' will specify any ports, but '!any' is not allowed. Valid port ranges are from 0 to 65535. Lists of ports must be enclosed in brackets and port ranges may be specified with a ':', such as in: [80:90,888:900] Port variables should be specified using 'portvar'. The use of 'var' to declare a port variable will be deprecated in a future release. For backwards compatibility, a 'var' can still be used to declare a port variable, provided the variable name either ends with '_PORT' or begins with 'PORT_'. Examples of valid uses of port variables and port lists: portvar EXAMPLE1 80 var EXAMPLE2_PORT [80:90] var PORT_EXAMPLE2 [1] portvar EXAMPLE3 any portvar EXAMPLE4 [!70:90] portvar EXAMPLE5 [80,91:95,100:200] alert tcp any $EXAMPLE1 -> any $EXAMPLE2_PORT (msg:"Example"; sid:1;) alert tcp any $PORT_EXAMPLE2 -> any any (msg:"Example"; sid:2;) alert tcp any 90 -> any [100:1000,9999:20000] (msg:"Example"; sid:3;) Invalid uses port variables and port lists: Use of !any: portvar EXAMPLE5 !any var EXAMPLE5 !any Logical contradictions: portvar EXAMPLE6 [80,!80] Ports out of range: portvar EXAMPLE7 [65536] Incorrect declaration and use of a port variable: var EXAMPLE8 80 alert tcp any $EXAMPLE8 -> any any (msg:"Example"; sid:4;) Port variable used as an IP: alert tcp $EXAMPLE1 any -> any any (msg:"Example"; sid:5;) Limitations =========== When embedding variables, types can not be mixed. For instance, port variables can be defined in terms of other port variables, but old-style variables (with the 'var' keyword) can not be embedded inside a 'portvar'. Valid embedded variable: portvar pvar1 80 portvar pvar2 [$pvar1,90] Invalid embedded variable: var pvar1 80 portvar pvar2 [$pvar,90] Likewise, variables can not be redefined if they were previously defined as a different type. Instead, a different name should be used. When defining a port variable or an IP variable, do not use a regular variable in the definition: Invalid definition: var regularvar 80 portvar pvar $regularvar snort-2.9.6.0/doc/README.unified20000644000000000000000000003647512260355636013102 00000000000000 I. Configuring Unified2 Output Unified2 can work in one of three modes, packet logging, alert logging, or true unified logging. Packet logging includes a capture of the entire packet and is specified with log_unified2. Likewise, alert logging will only log events and is specified with alert unified2. To include both logging styles in a single, unified file, simply specify unified2. When MPLS support is turned on, MPLS labels can be included in unified2 events. Use option mpls_event_types to enable this. If option mpls event types is not used, then MPLS labels will be not be included in unified2 events. * Note that by default, unified2 files have the create time (in Unix Epoch format) appended to each file when it is created. Format: output alert_unified2: \ filename [, limit ] [, nostamp] \ [,mpls_event_types] [, vlan_event_types] output log_unified2: \ filename [, limit ] [, nostamp] output unified2: \ filename [, limit ] [, nostamp] \ [,mpls_event_types] [, vlan_event_types] * Note that you'll need to have compiled snort with --enable-mpls as well as use the mpls_event_types to obtain mpls events. Example: output alert_unified2: filename snort.alert limit 128, nostamp output log_unified2: filename snort.log, limit 128, nostamp output unified2: filename merged.log, limit 128, nostamp output unified2: filename merged.log, limit 128, nostamp, \ mpls_event_types output unified2: filename merged.log, limit 128, \ mpls_event_types, vlan_event_types Unified2 also has logging support for various extra data. The following configuration items will enable these extra data logging facilities. config log_ipv6_extra_data This option enables Snort to log IPv6 source and destination address as unified2 extra data events. enable_xff This option enables HTTP Inspect to parse and log the original client IP present in the X-Forwarded-For or True-Client- IP HTTP request headers along with the generated events. * see README.http_inspect for more information log_uri This option enables HTTP Inspect to parse and log the URI data from the HTTP request and log it along with all the generated events for that session. * see README.http_inspect for more information log_hostname This option enables HTTP Inspect to parse and log the Host header data from the HTTP request and log it along with all the generated events for that session. * see README.http_inspect for more information log_hostname This option enables HTTP Inspect to parse and log the Host header data from the HTTP request and log it along with all the generated events for that session. * see README.http_inspect for more information log_mailfrom This option enables SMTP preprocessor to parse and log the senders email address extracted from the "MAIL FROM" command along with all the generated events for that session. * see README.SMTP for more information log_rcptto This option enables SMTP preprocessor to parse and log the recipients email address extracted from the "RCPT FROM" command along with all the generated events for that session. * see README.SMTP for more information log_rcptto This option enables SMTP preprocessor to parse and log the MIME attachment filenames extracted from the Content-Disposition header within the MIME body along with all the generated events for that session. * see README.SMTP for more information log_email_hdrs This option enables SMTP preprocessor to parse and log the SMTP email headers extracted from the SMTP data along with all the generated events for that session. * see README.SMTP for more information II. Reading Unified2 Files A. U2SpewFoo U2SpewFoo is a lightweight tool for dumping the contents of unified2 files to stdout. Example usage: $ u2spewfoo snort.log Example Output: (Event) sensor id: 0 event id: 4 event second: 1299698138 event microsecond: 146591 sig id: 1 gen id: 1 revision: 0 classification: 0 priority: 0 ip source: 10.1.2.3 ip destination: 10.9.8.7 src port: 60710 dest port: 80 protocol: 6 impact_flag: 0 blocked: 0 Packet sensor id: 0 event id: 4 event second: 1299698138 packet second: 1299698138 packet microsecond: 146591 linktype: 1 packet_length: 54 [ 0] 02 09 08 07 06 05 02 01 02 03 04 05 08 00 45 00 ..............E. [ 16] 00 28 00 06 00 00 40 06 5C B7 0A 01 02 03 0A 09 .(....@.\....... [ 32] 08 07 ED 26 00 50 00 00 00 62 00 00 00 2D 50 10 ...&.P...b...-P. [ 48] 01 00 A2 BB 00 00 ...... (ExtraDataHdr) event type: 4 event length: 33 (ExtraData) sensor id: 0 event id: 2 event second: 1299698138 type: 9 datatype: 1 bloblength: 9 HTTP URI: / (ExtraDataHdr) event type: 4 event length: 78 (ExtraData) sensor id: 0 event id: 2 event second: 1299698138 type: 10 datatype: 1 bloblength: 54 HTTP Hostname: Ñрбијаицрнагора.иком.museum B. U2Boat U2boat is a tool for converting unified2 files into different formats. Currently supported conversion formats are: pcap Example usage: u2boat -t pcap III. Unified2 File Format Unified 2 records should not be assumed to be in any order. All values are stored in network byte order. An example structure of unified2 files [ Serial Unified2 Header ] [ Unified2 IDS Event ] [ Unified2 Packet ] [ Unified2 Extra Data ] . . . [ Serial Unified2 Header ] [ Unified2 IDS Event ] [ Unified2 Packet ] [ Unified2 Extra Data ] A. Serial Unified2 Header: record type 4 bytes record length 4 bytes All unified2 records are preceded by a Serial Unified2 header. This unified2 record allows an interpreting application to skip past and apply simple heuristics against records. The Record Type indicates one of the following unified2 records follows the Serial Unified2 Header: Value Record Type ---------- ----------- 2 Unified2 Packet 7 Unified2 IDS Event 72 Unified2 IDS Event IP6 104 Unified2 IDS Event (Version 2) 105 Unified2 IDS Event IP6 (Version 2) 110 Unified2 Extra Data The record length field specifies the entire length of the record (not including the Serial Unified2 Header itself) up to the next Serial Unified2 Header or EOF. B. Unified2 Packet sensor id 4 bytes event id 4 bytes event seconds 4 bytes event microseconds 4 bytes linktype 4 bytes packet length 4 bytes packet data A Unified2 Packet is provided with each Unified2 Event record. This packet is the `alerting' packet that caused a given event. Unified2 Packet records contain contain a copy of the packet that caused an alert (Packet Data) and is packet length octets long. C. Unified2 IDS Event sensor id 4 bytes event id 4 bytes event second 4 bytes event microsecond 4 bytes signature id 4 bytes generator id 4 bytes signature revision 4 bytes classification id 4 bytes priority id 4 bytes ip source 4 bytes ip destination 4 bytes source port/icmp type 2 bytes dest. port/icmp code 2 bytes protocol 1 byte impact flag 1 byte impact 1 byte blocked 1 byte Unified2 IDS Event is logged for IPv4 Events without VLAN or MPLS tagging. D. Unified2 IDS Event IP6 sensor id 4 bytes event id 4 bytes event second 4 bytes event microsecond 4 bytes signature id 4 bytes generator id 4 bytes signature revision 4 bytes classification id 4 bytes priority id 4 bytes ip source 16 bytes ip destination 16 bytes source port/icmp type 2 bytes dest. port/icmp code 2 bytes protocol 1 byte impact flag 1 byte impact 1 byte blocked 1 byte Unified2 IDS Event IP6 is logged for IPv6 Events without VLAN or MPLS tagging. E. Unified2 IDS Event (Version 2) sensor id 4 bytes event id 4 bytes event second 4 bytes event microsecond 4 bytes signature id 4 bytes generator id 4 bytes signature revision 4 bytes classification id 4 bytes priority id 4 bytes ip source 4 bytes ip destination 4 bytes source port/icmp type 2 bytes dest. port/icmp code 2 bytes protocol 1 byte impact flag 1 byte impact 1 byte blocked 1 byte mpls label 4 bytes vlan id 2 bytes padding 2 bytes Unified2 IDS Event (Version 2) are logged for IPv4 packets which contain either MPLS or VLAN headers. Otherwise a Unified2 IDS Event is logged. * Note that you'll need to pass --enable-mpls to configure in order to have Snort fill in the mpls label field. * Note that you'll need to configure unified2 logging with either mpls_event_types or vlan_event_types to get this record type. F. Unified2 IDS Event IP6 (Version 2) sensor id 4 bytes event id 4 bytes event second 4 bytes event microsecond 4 bytes signature id 4 bytes generator id 4 bytes signature revision 4 bytes classification id 4 bytes priority id 4 bytes ip source 16 bytes ip destination 16 bytes source port/icmp type 2 bytes dest. port/icmp code 2 bytes protocol 1 byte impact flag 1 byte impact 1 byte blocked 1 byte mpls label 4 bytes vlan id 2 bytes padding 2 bytes Unified2 IDS Event IP6 (Version 2) are logged for IPv6 packets which contain either MPLS or VLAN headers. Otherwise a Unified2 IDS Event IP6 is logged. * Note that you'll need to pass --enable-mpls to configure in order to have Snort fill in the mpls label field. * Note that you'll need to configure unified2 logging with either mpls_event_types or vlan_event_types to get this record type. G. Unified2 Extra Data sensor id 4 bytes event id 4 bytes event second 4 bytes type 4 bytes data type 4 bytes data length 4 bytes data H. Description of Fields Sensor ID Unused Event ID The upper 2 bytes represent the snort instance, if specified by passing the -G option to Snort. The lower 2 bytes indicate the unique id of the event. The Event ID field is used to facilitate the task of coalescing events with packet data. Event Seconds and Event Microseconds Timestamp represented as seconds since the epoch of when the alert was generated. Link Type (Unified2 Packet) The Datalink type of the packet, typically EN10M but could be any of the values as returned by pcap_datalink that Snort handles. Packet Length (Unified2 Packet) Length of the Packet Data. Packet Data (Unified2 Packet) The alerting packet, of Packet Length bytes long. Type (Unified2 Extra Data) Type specifies the type of extra data that was logged, the valid types are: Value Description ---------- ----------- 1 Original Client IPv4 2 Original Client IPv6 3 UNUSED 4 GZIP Decompressed Data 5 SMTP Filename 6 SMTP Mail From 7 SMTP RCPT To 8 SMTP Email Headers 9 HTTP URI 10 HTTP Hostname 11 IPv6 Source Address 12 IPv6 Destination Address 13 Normalized Javascript Data Data Type (Unified2 Extra Data) The type of extra data in the record. Value Description ---------- ----------- 1 Blob Data Length (Unified2 Extra Data) Length of the data stored in the extra data record Data (Unified2 Extra Data) Raw extra event data up to Data Length bytes in size. All of these Extra data types, with the exception of 1, 2, 11, and 12 (IP Addresses) are stored in plain-text. The IP Address types need to be interpreted as if they were coming off the wire. Signature ID The Signature ID of the alerting rule, as specified by the sid keyword. Generator ID The Generator ID of the alerting rule, as specified by the gid keyword. Signature Revision Revision of the rule as specified by the rev keyword. Classification ID Classification ID as mapped in the file classifications.conf Priority ID Priority of the rule as mapped in the file classifications.conf or overridden by the priority keyword for text rules. IP Source Source IP of the packet that generated the event. IP Destination Destination IP of the packet that generated the event. Source Port/ICMP Type If Protocol is TCP or UDP than this field contains the source port of the alerting packet. If Protocol is ICMP than this field contains the ICMP type of the alerting packet. Destination Port/ICMP Code If protocol is TCP or UDP than this field contains the source port of the alerting packet. If protocol is icmp than this field contains the icmp code of the alerting packet. Protocol Transport protocol of the alerting packet. One of: ip, tcp, udp, or icmp. Impact flag Legacy field, specifies whether a packet was dropped or not. Value Description ---------- ----------- 32 Blocked Impact UNUSED; deprecated. Blocked Whether the packet was not dropped, was dropped or would have been dropped. Value Description ---------- ----------- 0 Was NOT Dropped 1 Was Dropped 2 Would Have Dropped* * Note that you'll only obtain Would Have Dropped on rules which are set to drop while Snort is running in inline-test mode. MPLS Label (4 bytes) The extracted mpls label from the mpls header in the alerting packet. VLAN ID The extracted vlan id from the vlan header in the alerting packet. Padding Padding is used to keep the event structures aligned on a 4 byte boundary. snort-2.9.6.0/doc/README.UNSOCK0000644000000000000000000001077510001575057012362 00000000000000$Id$ It is possible to send alert messages and some packet relevant data from snort through a unix socket, to perform additional separate processing of alert data. Snort has to be built with spo_unsock.c/h output plugin is built in and -A unsock (or its equivalent through the config file) is used. The unix socket file should be created in /dev/snort_alert. Your 'client' code should act as 'server' listening to this unix socket. Snort will be sending you Alertpkt structures which contain alert message, event id. Original datagram, libpcap pkthdr, and offsets to datalink, netlayer, and transport layer headers. Below is an example how unix sockets could be used. If you have any comments bug reports, and feature requests, please contact snort-devel@lists.sourceforge.net or drop me an email to fygrave at tigerteam dot net. -Fyodor [for copyright notice, see snort distribution code] #include #include #include #include #include #include #include "snort.h" int sockfd; void sig_term (int sig) { printf ("Exiting!\n"); close (sockfd); unlink (UNSOCK_FILE); exit (1); } int main (void) { struct sockaddr_un snortaddr; struct sockaddr_un bogus; Alertpkt alert; Packet *p; int recv; socklen_t len = sizeof (struct sockaddr_un); if ((sockfd = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0) { perror ("socket"); exit (1); } bzero (&snortaddr, sizeof (snortaddr)); snortaddr.sun_family = AF_UNIX; strcpy (snortaddr.sun_path, UNSOCK_FILE); if (bind (sockfd, (struct sockaddr *) &snortaddr, sizeof (snortaddr)) < 0) { perror ("bind"); exit (1); } signal(SIGINT, sig_term); while ((recv = recvfrom (sockfd, (void *) &alert, sizeof (alert), 0, (struct sockaddr *) &bogus, &len)) > 0) { /* do validation of recv if you care */ if (!(alert.val & NOPACKET_STRUCT)) { if ((p = calloc (1, sizeof (Packet))) == NULL) { perror ("calloc"); exit (1); } p->pkt = alert.pkt; p->pkth = &alert.pkth; if (alert.dlthdr) p->eh = (EtherHdr *) (alert.pkt + alert.dlthdr); if (alert.nethdr) { p->iph = (IPHdr *) (alert.pkt + alert.nethdr); if (alert.transhdr) { switch (p->iph->ip_proto) { case IPPROTO_TCP: p->tcph = (TCPHdr *) (alert.pkt + alert.transhdr); break; case IPPROTO_UDP: p->udph = (UDPHdr *) (alert.pkt + alert.transhdr); break; case IPPROTO_ICMP: p->icmph = (ICMPHdr *) (alert.pkt + alert.transhdr); break; default: printf ("My, that's interesting.\n"); } /* case */ } /* thanshdr */ } /* nethdr */ if (alert.data) p->data = alert.pkt + alert.data; /* now do whatever you want with these packet structures */ } /* if (!NOPACKET_STRUCT) */ printf ("%s [%d]\n", alert.alertmsg, alert.event.event_id); if (!(alert.val & NOPACKET_STRUCT)) if (p->iph && (p->tcph || p->udph || p->icmph)) { switch (p->iph->ip_proto) { case IPPROTO_TCP: printf ("TCP from: %s:%d ", inet_ntoa (p->iph->ip_src), ntohs (p->tcph->th_sport)); printf ("to: %s:%d\n", inet_ntoa (p->iph->ip_dst), ntohs (p->tcph->th_dport)); break; case IPPROTO_UDP: printf ("UDP from: %s:%d ", inet_ntoa (p->iph->ip_src), ntohs (p->udph->uh_sport)); printf ("to: %s:%d\n", inet_ntoa (p->iph->ip_dst), ntohs (p->udph->uh_dport)); break; case IPPROTO_ICMP: printf ("ICMP type: %d code: %d from: %s ", p->icmph->type, p->icmph->code, inet_ntoa (p->iph->ip_src)); printf ("to: %s\n", inet_ntoa (p->iph->ip_dst)); break; } } } perror ("recvfrom"); close (sockfd); unlink (UNSOCK_FILE); return 0; } snort-2.9.6.0/doc/README.thresholding0000644000000000000000000001715611224514522014050 00000000000000THRESHOLDING AND EVENT SUPPRESSION IN SNORT ** This document describes the 'threshold' and 'suppress' keywords. 'threshold' ** is deprecated as of version 2.8.5. 'event_filter' should be used instead. ** See README.filters for more information. A rule thresholding feature has been added to SNORT. This feature is used to reduce the number of logged alerts for noisy rules. This can be tuned to significantly reduce false alarms, and it can also be used to write a newer breed of rules. Thresholding commands limit the number of times a particular event is logged during a specified time interval. Global thresholding has also been added. This allows you to specify a threshold for every rule. Standard thresholding tests are applied 1st to an event, if they do not block a rule from being logged than the global thresholding test is applied - thresholds in a rule will always override a global. Event suppression stops specified events from firing without removing the rule from the rule base. Suppression uses a CIDR block notation to select specific networks and users for suppression. Suppression tests are performed prior to either standard or global thresholding tests. There are 3 types of thresholding: 1) Limit Alert on the 1st M events during the time interval, then ignore events for the rest of the time interval. 2) Threshold Alert every M times we see this event during the time interval. 3) Both Alert once per time interval after seeing M occurrences of the event, then ignore any additional events during the time interval. All tracking is by Src or by Dst IP, we do not track ports or anything else. Thresholding commands can be included as part of a rule, or you can use standalone threshold commands that reference the generator and sid they are applied to. There is no functional difference between adding a threshold to a rule, or using a separate threshold command applied to the same rule. There is a logical difference. Some rules may only make sense with a threshold. These should incorporate the threshold command into the rule. For instance a rule for detecting a too many login password attempts may require more than 5 attempts. This can be done using the 'limit' type of threshold command. It makes sense that the threshold feature is an integral part of this rule. Suppression commands are standalone commands that reference generator's and sid's and IP addresses via an IP list. This allows a rule to be completely suppressed, or suppressed when the causative traffic is going to or coming from a specific IP or group of IP addresses. Events in SNORT are generated in the usual way, thresholding and event suppression are handled as part of the output system. You may apply only one threshold to any given sid, but you may apply multiple suppression commands to a sid. You may also combine one threshold command and several suppression commands to the same sid. If you try to apply more than one threshold command to a sid, SNORT will terminate while reading the configuration information. THRESHOLDING CONFIGURATION COMMAND: ----------------------------------- config threshold: memcap 3000000 The memcap parameter is specified in bytes. THRESHOLD RULE FORMAT: --------------------- threshold: type limit|threshold|both, track by_src|by_dst, count n , seconds m ; THRESHOLD RULE OPTION PARAMETERS: -------------------------------- threshold keyword to start a threshold command in a rule. This format supports 4 threshold options - all are required. type limit, threshold, both track by_src , by_dst count n : number events used by the thresholding seconds m : time period over which count is accrued. EXAMPLE RULES: -------------- This rule logs the 1st event of this sid every 60 seconds alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"WEB-MISC robots.txt access"; flow:to_server, established; uricontent:"/robots.txt"; nocase; reference:nessus,10302; classtype:web-application-activity; threshold: type limit, track by_src, count 1 , seconds 60 ; sid:1852; rev:1;) This rule logs every 10th event on this sid during a 60 second interval, so if less than 10 occur in 60 seconds, nothing gets logged. Once an event is logged, a new time period starts for type=threshold. alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"WEB-MISC robots.txt access"; flow:to_server, established; uricontent:"/robots.txt"; nocase; reference:nessus,10302; classtype:web-application-activity; threshold: type threshold, track by_dst, count 10 , seconds 60 ; sid:1852; rev:1;) This rule logs at most one event every 60 seconds if at least 10 events on this sid are fired. alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"WEB-MISC robots.txt access"; flow:to_server, established; uricontent:"/robots.txt"; nocase; reference:nessus,10302; classtype:web-application-activity; threshold: type both , track by_dst, count 10 , seconds 60 ; sid:1852; rev:1;) THRESHOLD COMMAND FORMAT: ------------------------- threshold gen_id gen-id, sig_id sig-id, type limit|threshold|both, track by_src|by_dst, count n , seconds m THRESHOLD COMMAND PARAMETERS: ---------------------------- This format supports 6 threshold options - all are required. gen_id gen-id sig_id sig-id type limit, threshold, both track by_src, by_dst count n seconds m GLOBAL THRESHOLDING COMMAND: ---------------------------- The global threshold options are the same as the standard threshold options with the exception of the 'sig_id' field. The sig_id field must be set to 0 to indicate this threshold command applies to all sig_id values with the specified gen_id. To apply the same threshold to all gen_id's at the same time, and with just one command specify a value of gen_id=0. GLOBAL THRESHOLD COMMAND FORMAT: -------------------------------- threshold gen_id gen-id, sig_id 0, \ type limit|threshold|both, \ track by_src|by_dst, \ count n , seconds m or threshold gen_id 0 , sig_id 0, \ type limit|threshold|both, \ track by_src|by_dst, \ count n , seconds m THRESHOLD EXAMPLES: ------------------ # Rule Threshold - Limit to logging 1 event per 60 seconds threshold gen_id 1, sig_id 1851, type limit, track by_src, count 1, seconds 60 # Rule Threshold - Limit to logging every 3rd event threshold gen_id 1, sig_id 1852, type threshold, track by_src, count 3, seconds 60 # Rule Threshold - Limit to logging just 1 event per 60 seconds, but only if # we exceed 30 events in 60 seconds threshold gen_id 1, sig_id 1853, type both, track by_src, count 30, seconds 60 # Global Threshold - Limit to logging 1 event per 60 seconds per IP triggering # each rule threshold gen_id 1, sig_id 0, type limit, track by_src, count 1, seconds 60 # Global Threshold - Limit to logging 1 event per 60 seconds per IP triggering # each rule for each event generator threshold gen_id 0, sig_id 0, type limit, track by_src, count 1, seconds 60 SUPPRESS COMMAND FORMAT: ----------------------- suppress gen_id gen-id, sid_id sid-id, track by_src|by_dst, ip ip-list SUPPRESS COMMAND PARAMETERS: --------------------------- The suppress command supports either 2 or 4 options gen_id gen-id # always required sig_id sig-id # always required track by_src | by_dst # optional - 4 option version ip ip-list # optional - 4 option version SUPPRESS EXAMPLES: ----------------- # Suppress this event completely suppress gen_id 1, sig_id 1852 # Suppress this event from this IP suppress gen_id 1, sig_id 1852, track by_src, ip 10.1.1.54 # Suppress this event to this CIDR block suppress gen_id 1, sig_id 1852, track by_dst, ip 10.1.1.0/24 snort-2.9.6.0/doc/README.tag0000644000000000000000000001121711573541474012136 00000000000000Introduction ------------ Tagging packets is a way to continue logging packets from a session or host that generated an event in Snort. When an event is generated based on a rule that contains a tag option, information such as the IPs and ports involved, the type of tagging decision that should be made (by session or host), for how long to tag packets (the number of packets, seconds and/or bytes), the event id of the packet that generated the alert (to be included in the logging information with each tagged packet), etc. are saved into a data structure so that subsequent packets can be checked against this information and a decision can be made whether or not to tag/log the packet. Tagged traffic is logged to allow analysis of response codes and post-attack traffic. Tag alerts will be sent to the same output plugins as the original alert, but it is the responsibility of the output plugin to properly handle these special alerts. Currently, the database output plugin does not properly handle tag alerts. Snort will only check to see whether or not it should tag a packet if that packet did not generate an event. An exception to this is if the event was based on a PASS rule and that rule does not contain a tag option, that packet will be checked. Format ------ tag: , , , [direction] type session - Log packets in the session that set off the rule host - Log packets from the host that caused the tag to activate (uses [direction] modifier) count - Count is specified as a number of units. Units are specified in the field. metric packets - Tag the host/session for packets seconds - Tag the host/session for seconds bytes - Tag the host/session for bytes direction - only relevant if host type is used. src - Tag packets containing the source IP address of the packet that generated the initial event. dst - Tag packets containing the destination IP address of the packet that generated the initial event. Note that the stream preprocessor is not checked for the existence of a session. A session here is based only on socket (IP address:port) pairs, so that a session could end, but if a new session is started using the same socket pair, packets will continue to get tagged. A tag option with the "host" type MUST specify a direction. Tagged Packet Limit ------------------- If you have a tag option in a rule that uses a metric other than packets, a tagged_packet_limit will be used to limit the number of tagged packets regardless of whether the seconds or bytes count has been reached. The default tagged packet limit value is 256 and can be modified by using a config option in your snort.conf file. You can disable this packet limit for a particular rule by adding a packets metric to your tag option and setting its count to 0 (This can be done on a global scale by setting the tagged_packet_limit option in snort.conf to 0). Doing this will ensure that packets are tagged for the full amount of seconds or bytes and will not be cut off by the tagged_packet_limit. (Note that the tagged_packet_limit was introduced to avoid DoS situations on high bandwidth sensors for tag rules with a high seconds or bytes counts.) Example: config tagged_packet_limit: 512 To disable the tagged_packet_limit: config tagged_packet_limit: 0 Examples -------- tag:host,100,seconds,src tagged_packet_limit = 256 When an event is triggered on this rule, Snort will tag packets containing an IP address that matches the source IP address of the packet that caused this rule to alert for the next 100 seconds or 256 packets, whichever comes first. tag:host,1000,bytes,100,packets,src tagged_packet_limit = 256 When an event is triggered on this rule, Snort will tag packets containing an IP address that matches the source IP address of the packet that caused this rule to alert for the next 1000 bytes or 100 packets, whichever comes first. NOTE: The tagged_packet_limit will be ignored whenever the packets metric is used in the tag option. Using multiple metrics ---------------------- When the metrics used are bytes and seconds, Snort will not stop tagging packets until at least each of the counts for both metrics are reached. Of course, if you have not disabled the tagged_packet_limit, the packet limit will take precedence. The following tag option will tag relevant packets for at least 1000 bytes and at least 100 seconds or until Snort has tagged 256 packets. tag:host,1000,bytes,100,seconds,src tagged_packet_limit = 256 To disable the tagged_packet_limit for this rule, it could be written as tag:host,1000,bytes,100,seconds,0,packets,src snort-2.9.6.0/doc/README.stream50000644000000000000000000004473012026730050012731 00000000000000Overview ======== The Stream5 preprocessor is a target-based TCP reassembly module for Snort. It is intended to replace both the Stream4 and flow preprocessors, and it is capable of tracking sessions for both TCP and UDP. With Stream5, the rule 'flow' and 'flowbits' keywords are usable with TCP as well as UDP traffic. Since Stream5 replaces Stream4, both cannot be used simultaneously. Remove the Stream4 and flow configurations from snort.conf when the Stream5 configuration is added. Transport Protocols ------------------- TCP sessions are identified via the classic TCP "connection". UDP sessions are established as the result of a series of UDP packets from two end points via the same set of ports. ICMP messages are tracked for the purposes of checking for unreachable and service unavailable messages, which effectively terminate a TCP or UDP session. Target-Based ------------ Stream5, like Frag3, introduces target-based actions for handling of overlapping data and other TCP anomalies. The methods for handling overlapping data, TCP Timestamps, Data on SYN, FIN and Reset sequence numbers, etc. and the policies supported by Stream5 are the results of extensive research with many target operating systems. Stream API ---------- Stream5 fully supports the Stream API (partly supported by Stream4), allowing other protocol normalizers/preprocessors to dynamically configure reassembly behavior as required by the application layer protocol, identify sessions that may be ignored (large data transfers, etc), and update the identifying information about the session (application protocol, direction, etc) that can later be used by rules. Anomaly Detection ----------------- TCP protocol anomalies, such as data on SYN packets, data received outside the TCP window, etc are configured via the detect_anomalies option to the TCP configuration. Some of these anomalies are detected on a per-target basis. For example, a few operating systems allow data in TCP SYN packets, while others do not. Protocol Aware Flushing (PAF) ----------------------------- Protocol aware flushing of HTTP, SMB and DCE/RPC can be enabled with this option: config paf_max: where is between zero (off) and 63780. This allows Snort to statefully scan a stream and reassemble a complete PDU regardless of segmentation. For example, multiple PDUs within a single TCP segment, as well as one PDU spanning multiple TCP segments will be reassembled into one PDU per packet for each PDU. PDUs larger than the configured maximum will be split into multiple packets. Rule Options ============ Stream5 adds support for a few rule options described below. stream_size ----------- The 'stream_size' rule option allows a rule to match traffic according to the number of bytes observed, as determined by the TCP sequence numbers. stream_size takes a number of comma-separated arguments in the following format: stream_size:,, Where direction is one of: client - Client side traffic only server - Sever side traffic only both - Traffic from both sides either - Traffic from either side Valid operators are: = < > != <= >= For example: stream_size:client,<,6; stream_reassemble ----------------- The 'stream_reassemble' rule option allows a rule to enable or disable TCP stream reassembly on matching traffic. stream_reassemble takes a number of comma-separated arguments in the following format: stream_reassemble:, [,noalert] [,fastpath] - The optional noalert parameter causes the rule to not generate an alert when it matches. - The optional fastpath parameter causes Snort to ignore the rest of the connection. For example: To disable TCP reassembly for client traffic when we see a HTTP 200 Ok Response message: alert tcp any 80 -> any any (flow:to_client,established; content:"200 OK"; stream_reassemble:disable,client,noalert;) Configuration ============= Global Configuration -------------------- Global settings for the Stream5 preprocessor - Preprocessor name: stream5_global - Options: track_tcp - Track sessions for TCP. The default is "yes". max_tcp - Max concurrent sessions for TCP. The default is "262144", maximum is "1048576", minimum is "1". memcap - Memcap for TCP packet storage. The default is "8388608" (8MB), maximum is "1073741824" (1GB), minimum is "32768" (32KB). track_udp - Track sessions for UDP. The default is "yes". max_udp - Max concurrent sessions for UDP. The default is "131072", maximum is "1048576", minimum is "1". track_icmp - Track sessions for ICMP. The default is "no". max_icmp - Max concurrent sessions for ICMP. The default is "65536", maximum is "1048576", minimum is "1". flush_on_alert - Backwards compatibility. Flush a TCP stream when an alert is generated on that stream. The default is set to off. show_rebuilt_packets - Print/display packet after rebuilt (for debugging). The default is set to off. prune_log_max - Print a message when a session terminates that was consuming more than the specified number of bytes. The default is "1048576" (1MB), minimum can be either "0" (disabled) or if not disabled the minimum is "1024" and maximum is "1073741824". disabled - This optional keyword is allowed with any policy to avoid packet processing. This option disables the preprocessor. When the preprocessor is disabled only the options memcap, max_tcp, max_udp and max_icmp are applied when specified with the configuration. The other options are parsed but not used. Any valid configuration may have "disabled" added to it. TCP Configuration ----------------- Provides a means on a per IP address target to configure a TCP policy. This can have multiple occurrences, per policy that is bound to an IP address or network. One default policy must be specified, and that policy is not bound to an IP address or network. - Preprocessor name: stream5_tcp - Options: bind_to - IP address for this policy. The default is set to any. timeout - Session timeout. The default is "30", the minimum is "1", and the maximum is "86400" (approximately 1 day). policy - The Operating System policy for the target OS. The policy_id can be one the following: first - Favor first overlapped segment. last - Favor last overlapped segment. bsd - FreeBSD 4.x and newer NetBSD 2.x and newer OpenBSD 3.x and newer AIX linux - Linux 2.4 and 2.6 old-linux - Linux 2.2 and earlier windows - Windows 98, NT, 2000, XP (and others not specifically listed below) win2003 - Windows 2003 Server vista - Windows Vista solaris - Solaris 9.x and newer hpux10 - HPUX 10 hpux - HPUX 11 and newer irix - IRIX 6 and newer macos - MacOS 10.3 and newer The default is "bsd". overlap_limit - Limits number of overlapping packets. The default is "0" (unlimited), the minimum is "0", and the maximum is "255". max_window - Maximum allowed TCP window. The default is "0" (unlimited), the minimum is "0", and the maximum is "1073725440" (65535 left shift 14). That is the highest possible TCP window per RFCs. This option is intended to prevent a DoS against Stream5 by an attacker using an abnormally large window, so using a value near the maximum is discouraged. detect_anomalies - Detect TCP protocol anomalies. The default is set to off. require_3whs [] - Establish sessions only on completion of a SYN/SYN-ACK/ACK handshake. The default is set to off. The optional number of seconds specifies a startup timeout. This allows a grace period for existing sessions to be considered established during that interval immediately after Snort is started. The default is "0" (don't consider existing sessions established), the minimum is "0", and the maximum is "86400" (approximately 1 day). use_static_footprint_sizes - Emulate Stream4 behavior for flushing reassembled packets. The default is set to off. dont_store_large_packets - A performance improvement which does not queue large packets in reassembly buffer if set. Setting this option could result in missed packets. The default is set to off. check_session_hijacking - Check for TCP session hijacking. This check validates the hardware (MAC) address from both sides of the connect -- as established on the 3-way handshake against subsequent packets received on the session. If an ethernet layer is not part of the protocol stack received by Snort, there are no checks performed. Alerts are generated (per 'detect_anomalies' option) for either the client or server when the MAC address for one side or the other does not match. The default is set to off. dont_reassemble_async - Don't queue packets for reassembly if traffic has not been seen in both directions. The default is set to queue packets. max_queued_bytes - Limit the number of bytes queued for reassembly on a given TCP session to bytes. Default is "1048576" (1MB). A value of "0" means unlimited, with a non-zero minimum of "1024", and a maximum of "1073741824" (1GB). A message is written to console/syslog when this limit is enforced. max_queued_segs - Limit the number of segments queued for reassembly on a given TCP session. The default is "2621", derived based on an average size of 400 bytes. A value of "0" means unlimited, with a non-zero minimum of "2", and a maximum of "1073741824" (1GB). A message is written to console/syslog when this limit is enforced. small_segments bytes [ignore_ports port list] - Configure the maximum small segments queued. This feature requires that detect_anomalies be enabled. num1 is the number of consecutive segments that will trigger the detection rule. The default value is "0" (disabled),with a maximum of "2048". num2 is the minimum bytes for a segment to be considered "small". The default value is "0" (disabled), with a maximum of "2048". ignore_ports is optional, defines the list of ports in which will be ignored for this rule. The number of ports can be up to "65535". Example: small_segments 3 bytes 15 ignore_ports 33 44 55 A message is written to console/syslog when this limit is enforced. The generated alert is 129:12 ports [all|space separated port list] - Specify the client, server, or both and list of ports in which to perform reassembly. This can appear more than once in a given config. For example: ports both 80 23 ports server 37 ports client 21 25 The default settings are: ports client 21 23 25 42 53 80 110 111 135 136 \ 137 139 143 445 513 514 1433 1521 2401 3306 The minimum port allowed is "1" and the maximum allowed is "65535". ignore_any_rules - Don't process any -> any (ports) rules for TCP that attempt to match payload if there are no port specific rules for the src or destination port. Rules that have flow or flowbits will never be ignored. This is a performance improvement, but may result in missed attacks. Using this does not affect rules that look at protocol headers, only those with content, PCRE, or byte test options. The default is "off". This option can be present only in default policy. If no options are specified for a given TCP policy, that is the default TCP policy. If only a bind_to option is used with no other options that TCP policy uses all of the default values. UDP Configuration ----------------- Configuration for UDP session tracking. Since there is no target based binding, there should be only one occurrence of the UDP configuration. - Preprocessor name: stream5_udp - Options: timeout - Session timeout. The default is "30", the minimum is "1", and the maximum is "86400" (approximately 1 day). ignore_any_rules - Don't process any -> any (ports) rules for UDP that attempt to match payload if there are no port specific rules for the src or destination port. Rules that have flow or flowbits will never be ignored. This is a performance improvement, but may result in missed attacks. Using this does not affect rules that look at protocol headers, only those with content, PCRE, or byte test options. The default is "off". NOTE: with the ignore_any_rules option, a UDP rule will be ignored except when there is another port specific rule that may be applied to the traffic. For example, if a UDP rule specifies destination port 53, the 'ignored' any -> any rule will be applied to traffic to/from port 53, but NOT to any other source or destination port. A list of rule SIDs affected by this option are printed at Snort's startup. NOTE: with the ignore_any_rules option, if a UDP rule that uses any -> any ports includes either flow or flowbits, the ignore_any_rules option is effectively pointless. Because of the potential impact of disabling a flowbits rule, the ignore_any_rules option will be disabled in this case. ICMP Configuration ------------------ NOTE: ICMP is currently untested, in minimal code form and is NOT ready for use in production networks. It is not turned on by default. Configuration for ICMP session tracking. Since there is no target based binding, there should be only one occurrence of the ICMP configuration. - Preprocessor name: stream5_icmp - Options: timeout - Session timeout. The default is "30", the minimum is "1", and the maximum is "86400" (approximately 1 day). Example Configurations ====================== 1) This example configuration emulates the behavior of Stream4 (with UDP support enabled). preprocessor stream5_global: max_tcp 8192, track_tcp yes, \ track_udp yes, track_icmp no preprocessor stream5_tcp: policy first, use_static_footprint_sizes preprocessor stream5_udp: ignore_any_rules 2) This configuration maps two network segments to different reassembly policies, one for Windows, one for Linux, with all other traffic falling to the default policy Solaris. preprocessor stream5_global: track_tcp yes preprocessor stream5_tcp: bind_to 192.168.1.0/24, policy windows preprocessor stream5_tcp: bind_to 10.1.1.0/24, policy linux preprocessor stream5_tcp: policy solaris Alerts ====== Stream5 uses generator ID 129. It is capable of alerting on 10 anomalies, all of which relate to TCP anomalies. There are no anomaly detection capabilities for UDP or ICMP. Check etc/gen-msg.map for the current list of GID 129 alerts. snort-2.9.6.0/doc/README.sip0000644000000000000000000003434112260355636012156 00000000000000SIP Preprocessor ================================================================================ Hui Cao Overview ================================================================================ Session Initiation Protocol (SIP) is an application-layer control (signaling) protocol for creating, modifying, and terminating sessions with one or more participants. These sessions include Internet telephone calls, multimedia distribution, and multimedia conferences. SIP Preprocessor provides ways to tackle Common Vulnerabilities and Exposures (CVEs) related with SIP found over the past few years. It also makes detecting new attacks easier. Sections: Dependency Requirements Configuration Events Rule Options Dependency Requirements ================================================================================ For proper functioning of the preprocessor: Stream session tracking must be enabled, i.e. stream5. Both TCP and UDP must be enabled in stream5. The preprocessor requires a session tracker to keep its data. In addition, Stream API is able to provide correct support for ignoring audio/video data channel. IP defragmentation should be enabled, i.e. the frag3 preprocessor should be enabled and configured. Configuration ================================================================================ The preprocessor configuration name is "sip". preprocessor sip Option Argument Required Default disabled None No OFF max_sessions No max_sessions 10000 max_dialogs No max_dialogs 4 ports No ports { 5060 5061 } methods No methods { invite cancel ack bye register options } max_uri_len No max_uri_len 256 max_call_id_len No max_call_id_len 256 max_requestName_len No max_requestName_len 20 max_from_len No max_from_len 256 max_to_len No max_to_len 256 max_via_len No max_via_len 1024 max_contact_len No max_contact_len 256 max_content_len No max_content_len 1024 ignore_call_channel None No OFF max_sessions = 1024 - 4194303 max_dialogs = 1 - 4194303 methods = "invite" | "cancel" | "ack" | "bye" | "register" | "options" | "refer" | "subscribe" | "update" | "join" | "info" | "message" | "notify" | "prack" max_uri_len = 0 - 65535 max_call_id_len = 0 - 65535 max_requestName_len = 0 - 65535 max_from_len = 0 - 65535 max_to_len = 0 - 65535 max_via_len = 0 - 65535 max_contact_len = 0 - 65535 max_content_len = 0 - 65535 Option explanations disabled SIP dynamic preprocessor can be enabled/disabled through configuration. By default this value is turned off. When the preprocessor is disabled, only the max_sessions option is applied when specified with the configuration. max_sessions This specifies the maximum number of sessions that can be allocated. Those sessions are stream sessions, so they are bounded by maximum number of stream sessions. Default is 10000. max_dialogs This specifies the maximum number of dialogs within one stream session. If exceeded, the oldest dialog will be dropped. Default is 4. ports This specifies on what ports to check for SIP messages. Typically, this will include 5060, 5061. Syntax: ports { [< ... >] } Examples: ports { 5060 5061 } Note: there are spaces before and after '{' and '}' methods This specifies on what methods to check for SIP messages: (1) invite, (2) cancel, (3) ack, (4) bye, (5) register, (6) options, (7) refer, (8) subscribe, (9) update (10) join (11) info (12) message (13) notify (14) prack Note: those 14 methods are up to date list (Feb. 2011). New methods can be added to the list. Up to 32 methods supported. Syntax: methods { } method-list = method|method method-list method = "invite" | "cancel" | "ack" | "bye" | "register" | "options" | "refer" | "subscribe" | "update" | "join" | "info" | "message" | "notify"| "prack" Examples: methods { invite cancel ack bye register options } Add new method "information": methods { invite cancel ack bye register options information } Note: there are spaces before and after '{' and '}' max_uri_len This specifies the maximum Request_URI field size. If the Request_URI field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. "0" means never alert. max_call_id_len This specifies the maximum Call-ID field size. If the Call-ID field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. "0" means never alert. max_requestName_len This specifies the maximum request name size that is part of the CSeq ID. If the request name is greater than this size, an alert is generated. Default is set to 20. The allowed range for this option is 0 - 65535. "0" means never alert. max_from_len This specifies the maximum From field size. If the From field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. "0" means never alert. max_to_len This specifies the maximum To field size. If the To field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. "0" means never alert. max_via_len This specifies the maximum Via field size. If the Via field is greater than this size, an alert is generated. Default is set to 1024. The allowed range for this option is 0 - 65535. "0" means never alert. max_contact_len This specifies the maximum Contact field size. If the Contact field is greater than this size, an alert is generated. Default is set to 256. The allowed range for this option is 0 - 65535. "0" means never alert. max_content_len This specifies the maximum content length of the message body. If the content length is greater than this number, an alert is generated. Default is set to 1024. The allowed range for this option is 0 - 65535. "0" means never alert. ignore_call_channel This enables the support for ignoring audio/video data channel (through Stream API). By default, this is disabled. Option examples max_sessions 30000 disabled ports { 5060 5061 } methods { invite cancel ack bye register options } methods { invite cancel ack bye register options information } max_uri_len 1024 max_call_id_len 1024 max_requestName_len 10 max_from_len 1024 max_to_len 1024 max_via_len 1024 max_contact_len 1024 max_content_len 1024 max_content_len ignore_call_channel Configuration examples preprocessor sip preprocessor sip: max_sessions 500000 preprocessor sip: max_contact_len 512, max_sessions 300000, methods { invite \ cancel ack bye register options } , ignore_call_channel preprocessor sip: ports { 5060 49848 36780 10270 }, max_call_id_len 200, \ max_from_len 100, max_to_len 200, max_via_len 1000, \ max_requestName_len 50, max_uri_len 100, ignore_call_channel,\ max_content_len 1000 preprocessor sip: disabled preprocessor sip: ignore_call_channel Default configuration preprocessor sip Events ================================================================================ The preprocessor uses GID 140 to register events. SID Description -------------------------------------------------------------------------------- 1 If the memory cap is reached and the preprocessor is configured to alert, this alert will be created. 2 Request_URI is required. When Request_URI is empty, this alert will be created. 3 The Request_URI is larger than the defined length in configuration. 4 When Call-ID is empty, this alert will be created. 5 The Call-ID is larger than the defined length in configuration. 6 The sequence e number value MUST be expressible as a 32-bit unsigned integer and MUST be less than 2**31. 7 The request name in the CSeq is larger than the defined length in configuration. 8 From field is empty. 9 From field is larger than the defined length in configuration. 10 To field is empty. 11 To field is larger than the defined length in configuration. 12 Via filed is empty. 13 Via filed is larger than the defined length in configuration. 14 Contact is empty, but it is required non-empty for the message. 15 The Contact is larger than the defined length in configuration. 16 The content length is larger than the defined length in configuration or is negative. 17 There are multiple requests in a single packet. Old SIP protocol supports multiple sip messages within one packet. 18 There are inconsistencies between Content-Length in SIP header and actual body data. 19 Request name is invalid in response. 20 Authenticated invite message received, but no challenge from server received. This is the case of InviteReplay billing attack. 21 Authenticated invite message received, but session information has been changed. This is different from re-INVITE, where the dialog has been established. and authenticated. This is can prevent FakeBusy billing attack. 22 Response status code is not a 3 digit number. 23 Content type header field is required if the message body is not empty. 24 SIP version other than 2.0, 1.0, and 1.1 is invalid 25 Mismatch in Method of request and the CSEQ header 26 The method is unknown 27 The number of dialogs in the stream session exceeds the maximal value. Rule Options ================================================================================ New rule options are supported by enabling the sip preprocessor: sip_method sip_stat_code sip_header sip_body Overload modifiers to existing pcre rule options: H: Match SIP request or SIP response header, Similar to sip_header. P: Match SIP request or SIP response body, Similar to sip_body. sip_method ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The sip_method keyword is used to check for specific SIP request methods. The list of methods is: invite, cancel, ack, bye, register, options, refer, subscribe, update, join, info, message, notify, prack. More than one method can be specified, via a comma separated list, and are OR'ed together. It will be applied in fast pattern match if available. If the method used in this rule is not listed in the preprocessor configuration, it will be added to the preprocessor configuration for the associated policy. Syntax: sip_method:; method-list = method|method, method-list method = ["!"] "invite" | "cancel" | "ack" | "bye" | "register" | "options" | "refer" | "subscribe" | "update" | "join" | "info" | "notify" | | "message"| "prack" Note: if "!" is used, only one method is allowed in sip_method. Examples: sip_method:invite, cancel sip_method:!invite If a user wants to use "and", they can use something like this: sip_method:!invite; sip_method:!bye sip_stat_code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The sip_stat_code is used to check the SIP response status code. This option matches if any one of the state codes specified matches the status codes of the SIP response. Syntax: sip_stat_code: ; code_list = state_code|state_code, code_list code = "100-999"|"1-9" Note: 1,2,3,4,5,6... mean to check for "1xx", "2xx", "3xx", "4xx", "5xx", ,"6xx"... responses. Example: This rule searches for the response with state code "200". sip_stat_code:200 This rule searches for all the 2xx responses. sip_stat_code: 2 This rule searches for either 200, or 180 responses. sip_stat_code: 200, 180 sip_header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The sip_header keyword restricts the search to the extracted Header fields of a SIP message request or a response. Syntax: sip_header; Example: This rule constrains the search for the pattern "CSeq" to the extracted Header fields of a SIP message. alert udp any any -> any 5060 (sip_header; content: "CSeq"; ) sip_body ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The sip_body keyword places the cursor at the beginning of the Body fields of a SIP message. This works similar to file_data and dce_stub_data.The message body includes channel information using SDP protocol (Session Description Protocol). Syntax: sip_body; Example: This rule searches for the pattern "c=IN 0.0.0.0" in the Body fields of a SIP message. alert udp any any -> any 5060 (sip_body; content: "C=IN 0.0.0.0"; within 100;) pcre ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIP overloads two options for pcre: H: Match SIP request or SIP response header, Similar to sip_header. P: Match SIP request or SIP response body, Similar to sip_body. Example: This rule searches for the pattern "INVITE" in the Header fields of a SIP message. alert udp any any -> any 5060 (pcre:"/INVITE/H"; sid:1000000;) This rule searches for the pattern "m=" in the Body fields of a SIP message. alert udp any any -> any 5060 (pcre:"/m=/P"; sid:2000000;) snort-2.9.6.0/doc/README.ssl0000644000000000000000000000762111435274306012162 00000000000000Overview ======== Encrypted traffic should be ignored by Snort for both performance reasons and to reduce false positives. The SSL Dynamic Preprocessor (SSLPP) inspects SSL and TLS traffic and optionally determines if and when to stop inspection of it. Typically, SSL is used over port 443 as HTTPS. By enabling the SSLPP to inspect port 443, only the SSL handshake of each connection will be inspected. Once the traffic is determined to be encrypted, no further inspection of the data on the connection is made. SSL Detection and Decoding ========================== Each packet containing SSL traffic has an unencrypted portion that provides some information about the traffic itself, and the state of the connection. SSLPP uses this information to determine whether or not a handshake is occurring or if a handshake previously occurred. By default, SSLPP looks for a handshake followed by encrypted traffic traveling to both sides. If one side responds with an indication that something has failed, such as the handshake, the session is not marked as encrypted. Verifying that faultless encrypted traffic is sent from both endpoints ensures two things: the last client-side handshake packet was not crafted to evade Snort, and that the traffic is legitimately encrypted. In some cases, especially when packets may be missed, the only observed response from one endpoint will be TCP ACKs. Therefore, if a user knows that server-side encrypted data can be trusted to mark the session as encrypted, the user should use the 'trustservers' option, documented below. Rule Options ============ SSLPP enables two new rule options: ssl_state and ssl_version. The ssl_state keyword takes the following identifiers as arguments: client_hello server_hello client_keyx server_keyx unknown The ssl_version keyword takes the following identifiers as arguments: sslv2 sslv3 tls1.0 tls1.1 tls1.2 More than one identifier can be specified, to either rule keyword, via a comma separated list. Lists of identifiers are OR'ed together, such that if any of them match, the rule option will match. The option will match if the connection is currently in any one of the OR'ed states. To ensure the connection has reached each of a set of states, multiple rules using the ssl_state rule option should be used. The rule options support negation. Some examples: # Not client hello ssl_state:!client_hello; # server hello OR not client hello ssl_state:server_hello,!client_hello; # server hello AND not server key exchange ssl_state:server_hello; ssl_state:!server_keyx; # not sslv2 ssl_version:!sslv2; # sslv3 and not sslv2 ssl_version:sslv3; ssl_version:!sslv2; Usage ===== SSLPP supports the following options: ports - Space separated list of ports, enclosed in braces noinspect_encrypted - Disables inspection of encrypted traffic (default off) trustservers - Disables the requirement that both sides of Application data must be observed (default off) This requires noinspect_encrypted to be useful. For example, to make SSLPP observe ports 443 and 994, and if you trust the servers to not be comprised or potentially malicious, use: preprocessor ssl: ports { 443 994 }, trustservers, noinspect_encrypted By default, SSLPP listens on the following ports: 443 HTTPS 465 SMTPS 563 NNTPS 636 LDAPS 989 FTPS 992 TelnetS 993 IMAPS 994 IRCS 995 POPS Important note: Stream4 or Stream5 should be explicitly told to reassemble traffic on these ports, or else the SSL preprocessor will be trivially evadable. To add reassembly on port 443 to Stream5, use 'ports both 443' in the Stream5 configuration. snort-2.9.6.0/doc/README.ssh0000644000000000000000000000734012232305204012140 00000000000000SSH --- Chris Sherwin Adam Keeton Marc Norton Ryan Jordan Documentation last update 2009-03-16 == Overview == The SSH preprocessor detects the following exploits: Challenge-Response Buffer Overflow, CRC 32, Secure CRT, and the Protocol Mismatch exploit. Both Challenge-Response Overflow and CRC 32 attacks occur after the key exchange, and are therefore encrypted. Both attacks involve sending a large payload (20kb+) to the server immediately after the authentication challenge. To detect the attacks, the SSH preprocessor counts the number of bytes transmitted to the server. If those bytes exceed a pre-defined limit within a pre-define number of packets, an alert is generated. Since Challenge-Response Overflow only effects SSHv2 and CRC 32 only effects SSHv1, the SSH version string exchange is used to distinguish the attacks. The Secure CRT and protocol mismatch exploits are observable before the key exchange. == Configuration == By default, all alerts are disabled and the preprocessor checks traffic on port 22. The available configuration options are described below: * server_ports { port[, port] .. }* This option specifies which ports the SSH preprocessor should inspect traffic to. * max_encrypted_packets * The number of stream reassembled encrypted packets that Snort will inspect before ignoring a given SSH session. The SSH vulnerabilities that Snort can detect all happen at the very beginning of an SSH session. Once max_encrypted_packets packets have been seen, Snort ignores the session to increase performance. * max_client_bytes * The number of unanswered bytes allowed to be transferred before alerting on Challenge-Response Overflow or CRC 32. This number must be hit before max_encrypted_packets packets are sent, or else Snort will ignore the traffic. * max_server_version_len * The maximum number of bytes allowed in the SSH server version string before alerting on the Secure CRT server version string overflow. * autodetect * Attempt to automatically detect SSH. * enable_respoverflow * Enables checking for the Challenge-Response Overflow exploit. * enable_ssh1crc32 * Enables checking for the CRC 32 exploit. * enable_srvoverflow * Enables checking for the Secure CRT exploit. * enable_protomismatch * Enables checking for the Protocol Mismatch exploit. * enable_badmsgdir * Enable alerts for traffic flowing the wrong direction. For instance, if the presumed server generates client traffic, or if a client generates server traffic. * enable_paysize * Enables alerts for invalid payload sizes. * enable_recognition * Enable alerts for non-SSH traffic on SSH ports. == Example Configuration == Looks for attacks on SSH server port 22. Alerts at 19600 unacknowledged bytes within 20 encrypted packets for the Challenge-Response Overflow/CRC32 exploits. preprocessor ssh: server_ports { 22 } \ max_client_bytes 19600 \ max_encrypted_packets 20 \ enable_respoverflow \ enable_ssh1crc32 == Alerts == The SSH Preprocessor uses generator ID 128 and can produce the following alerts: SID Description --- ----------- 1 Challenge-Response Buffer Overflow exploit 2 SSH1 CRC32 exploit 3 Server version string overflow 4 Protocol mismatch 5 Bad message direction 6 Payload size incorrect for the given payload 7 Failed to detect SSH version string == Conclusion == The SSH preprocessor should work by default. After max_client_packets is reached, the preprocessor will stop processing traffic for a given session. If Challenge-Response Overflow or CRC 32 false positive, try increasing the number of required client bytes with max_client_bytes. snort-2.9.6.0/doc/README.SMTP0000644000000000000000000003743312260355636012153 00000000000000SMTP ==== Andrew Mullican Thanks to Dan Roelker , Marc Norton , and Steve Sturges for their help with the design. -- Overview -- SMTP is an SMTP decoder for user applications. Given a data buffer, SMTP will decode the buffer and find SMTP commands and responses. It will also mark the command, data header data body sections, as well as TLS data. SMTP handles stateless and stateful processing. It saves state between individual packets. However maintaining correct state is dependent on the reassembly of the client side of the stream (i.e., a loss of coherent stream data results in a loss of state). -- Configuration -- SMTP has the usual configuration items, such as port and inspection_type. Also, SMTP command lines can be normalized to remove extraneous spaces. TLS-encrypted traffic can be ignored, which improves performance. In addition, regular mail data can be ignored for an additional performance boost. Since so few (none in the current snort ruleset) exploits are against mail data, this is relatively safe to do and can improve the performance of data inspection. The configuration options are described below: * ports { port [port] ... } * This specifies on what ports to check for SMTP data. Typically, this will include 25 and possibly 465, for encrypted SMTP. Default ports if none are specified are 25, 587 (Message submission - see RFC 2476) and 691 (X-LINK2STATE). If alerting on the X-LINK2STATE vulnerability is disabled, port 691 will be removed from the default ports. DEFAULT { 25 587 691 } * inspection_type stateful|stateless Indicate whether to operate in stateful or stateless mode. * normalize all|none|cmds * This turns on normalization. Normalization checks for more than one space character after a command. Space characters are defined as space (ASCII 0x20) or tab (ASCII 0x09). all checks all commands none turns off normalization for all commands. cmds just checks commands listed with the "normalize_cmds" parameter. * ignore_data * Ignore data section of mail (except for mail headers) when processing rules. * ignore_tls_data * Ignore TLS-encrypted data when processing rules. * max_command_line_len * Alert if an SMTP command line is longer than this value. Absence of this option or a "0" means never alert on command line length. RFC 2821 recommends 512 as a maximum command line length. * max_header_line_len * Alert if an SMTP DATA header line is longer than this value. Absence of this option or a "0" means never alert on data header line length. RFC 2821 recommends 1024 as a maximum data header line length. * max_response_line_len * Alert if an SMTP response line is longer than this value. Absence of this option or a "0" means never alert on response line length. RFC 2821 recommends 512 as a maximum response line length. * alt_max_command_line_len { [] } Overrides max_command_line_len for specific commands * no_alerts * Turn off all alerts for this preprocessor. * invalid_cmds { } * Alert if this command is sent from client side. DEFAULT empty list * valid_cmds { } * List of valid commands. We do not alert on commands in this list. DEFAULT empty list, but preprocessor has this list hard-coded: { ATRN AUTH BDAT DATA DEBUG EHLO EMAL ESAM ESND ESOM ETRN EVFY EXPN } { HELO HELP IDENT MAIL NOOP QUIT RCPT RSET SAML SOML SEND ONEX QUEU } { STARTTLS TICK TIME TURN TURNME VERB VRFY X-EXPS X-LINK2STATE } { XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUE XSTA XTRN XUSR } * data_cmds { } * List of commands that initiate sending of data with an end of data delimiter the same as that of the DATA command per RFC 5321 - ".". DEFAULT { DATA } * binary_data_cmds { } * List of commands that initiate sending of data and use a length value after the command to indicate the amount of data to be sent, similar to that of the BDAT command per RFC 3030. DEFAULT { BDAT XEXCH50 } * auth_cmds { } * List of commands that initiate an authentication exchange between client and server. DEFAULT { AUTH XAUTH X-EXPS } * alert_unknown_cmds * Alert if we don't recognize command. DEFAULT off * normalize_cmds { } * Normalize this list of commands DEFAULT { RCPT VRFY EXPN } * xlink2state { enable/disable [drop] } See CVE-2005-0560 for a description of the vulnerability. Enable/disable xlink2state alert Drop if alerted DEFAULT { enable } * print_cmds * List all commands understood by the preprocessor. This not normally printed out with the configuration because it prints so much data. * disabled * Disables the SMTP preprocessor in a config. This is useful when specifying the decoding depths such as b64_decode_depth, qp_decode_depth, uu_decode_depth, bitenc_decode_depth or the memcap used for decoding max_mime_mem in default config without turning on the SMTP preprocessor. * b64_decode_depth * This config option is used to turn off/on or set the base64 decoding depth used to decode the base64 encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the base64 decoding of MIME attachments. The value of 0 sets the decoding of base64 encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of base64 MIME attachments, and applies per attachment. A SMTP preprocessor alert with sid 10 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the base64 encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. This option replaces the deprecated options, enable_mime_decoding and max_mime_depth. It is recommended that user inputs a value that is a multiple of 4. When the value specified is not a multiple of 4, the SMTP preprocessor will round it up to the next multiple of 4. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * qp_decode_depth * This config option is used to turn off/on or set the Quoted-Printable decoding depth used to decode the Quoted-Printable(QP) encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the QP decoding of MIME attachments. The value of 0 sets the decoding of QP encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of QP MIME attachments, and applies per attachment. A SMTP preprocessor alert with sid 11 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the QP encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * bitenc_decode_depth * This config option is used to turn off/on or set the non-encoded MIME extraction depth used to extract the non-encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the extraction of these MIME attachments. The value of 0 sets the extraction of these MIME attachments to unlimited. A value other than 0 or -1 restricts the extraction of these MIME attachments, and applies per attachment. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the non-encoded MIME attachments/data across multiple packets are extracted too. The extracted data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * uu_decode_depth * This config option is used to turn off/on or set the Unix-to-Unix decoding depth used to decode the Unix-to-Unix(UU) encoded attachments. The value ranges from -1 to 65535. A value of -1 turns off the UU decoding of SMTP attachments. The value of 0 sets the decoding of UU encoded SMTP attachments to unlimited. A value other than 0 or -1 restricts the decoding of UU SMTP attachments, and applies per attachment. A SMTP preprocessor alert with sid 13 is generated (if enabled) when the decoding fails. Multiple UU Encoded attachments/data in one packet are pipelined. When stateful inspection is turned on the UU encoded attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * enable_mime_decoding * Enables Base64 decoding of Mime attachments/data. Multiple base64 encoded MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the base64 encoded MIME attachments/data across multiple packets are decoded too. The decoding of base64 encoded attachments/data ends when either the max_mime_depth or maximum MIME sessions (calculated using max_mime_depth and max_mime_mem) is reached or when the encoded data ends. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. Please note, this option is deprecated. Use the option b64_decode_depth to turn off or on the base64 decoding instead. * max_mime_depth * Specifies the maximum number of base64 encoded data to decode per attachment. The option take values ranging from 4 to 20480 bytes. The default value for this in snort in 1460 bytes. It is recommended that user inputs a value that is a multiple of 4. When the value specified is not a multiple of 4, the SMTP preprocessor will round it up to the next multiple of 4. Please note, this option is deprecated. Use the b64_decode_depth to set the decoding depth for base64 decoding instead. * max_mime_mem * This option determines (in bytes) the maximum amount of memory the SMTP preprocessor will use for decoding base64 encoded/quoted-printable/non-encoded MIME attachments/data or Unix-to-Unix encoded attachments. This value can be set from 3276 bytes to 100MB. This option along with the maximum of the decoding depths will determine the SMTP sessions that will be decoded at any given instant. The default value for this option is 838860. Note: It is suggested to set this value such that the max smtp session calculated as follows is at least 1. max smtp session = max_mime_mem /(2 * max of (b64_decode_depth, uu_decode_depth, qp_decode_depth or bitenc_decode_depth)) For example, if b64_decode_depth is 0 (indicates unlimited decoding) and qp_decode_depth is 100, then max smtp session = max_mime_mem/2*65535 (max value for b64_decode_depth) In case of multiple configs, the max_mime_mem of the non-default configs will be overwritten by the default config's value. Hence user needs to define it in the default config with the new keyword disabled (used to disable SMTP preprocessor in a config). * log_mailfrom * This option enables SMTP preprocessor to parse and log the sender's email address extracted from the "MAIL FROM" command along with all the generated events for that session. The maximum number of bytes logged for this option is 1024. Please note, this is logged only with the unified2 output and is not logged with console output (-A cmg). u2spewfoo can be used to read this data from the unified2. * log_rcptto * This option enables SMTP preprocessor to parse and log the recipient email addresses extracted from the "RCPT TO" command along with all the generated events for that session. Multiple recipients are appended with commas. The maximum number of bytes logged for this option is 1024. Please note, this is loggged only with the unified2 output and is not logged with console output (-A cmg). U2spewfoo can be used to read this data from the unified2. * log_filename * This option enables SMTP preprocessor to parse and log the MIME attachment filenames extracted from the Content-Disposition header within the MIME body along with all the generated events for that session. Multiple filenames are appended with commas. The maximum number of bytes logged for this option is 1024. Please note,this is logged only with the unified2 output and is not logged with the console output (-A cmg). u2spewfoo can be used to read this data from the unified2. * log_email_hdrs * This option enables SMTP preprocessor to parse and log the SMTP email headers extracted from SMTP data along with all generated events for that session. The number of bytes extracted and logged depends upon the email_hdrs_log_depth. Please note, this is logged only with the unified2 output and is not logged with the console output (-A cmg). u2spewfoo can be used to read this data from the unified2. * email_hdrs_log_depth * This option specifies the depth for logging email headers. The allowed range for this option is 0 - 20480. A value of 0 will disable email headers logging. The default value for this option is 1464. Please note, in case of multiple configs, this default config's value is used. The values specified in the non-default config will be ignored and overwritten by the default config's values. This option must be configured in the default config even if the SMTP configuration is disabled. * memcap * This option determines in bytes the maximum amount of memory the SMTP preprocessor will use for logging of filename, MAIL FROM addresses, RCPT TO addresses and email headers. This value along with the buffer size used to log MAIL FROM, RCPT TO, filenames and email_hdrs_log_depth will determine the maximum SMTP sessions that will log the email headers at any given time. When this memcap is reached SMTP will stop logging the filename, MAIL FROM address, RCPT TO addresses and email headers until memory becomes available. Max SMTP sessions logging email headers at any given time = memcap/(1024 + 1024 + 1024 + email_hdrs_log_depth) The size 1024 is the maximum buffer size used for logging filename, RCPTTO and MAIL FROM addresses. Default value for this option is 838860. The allowed range for this option is 3276 to 104857600. The value specified in the default config is used when this option is specified in multiple configs. This option must be configured in the default config even if the SMTP configuration is disabled. Example: preprocessor SMTP: \ ports { 25 } \ inspection_type stateful \ normalize cmds \ normalize_cmds { EXPN VRFY RCPT } \ ignore_data \ ignore_tls_data \ max_command_line_len 512 \ max_header_line_len 1024 \ max_response_line_len 512 \ no_alerts \ alt_max_command_line_len 300 { RCPT } \ invalid_cmds { } \ valid_cmds { } \ xlink2state { disable } \ print_cmds \ log_filename \ log_email_hdrs \ log_mailfrom \ log_rcptto \ email_hdrs_log_depth 2920 \ memcap 6000 preprocessor SMTP: \ max_mime_depth 100 \ max_mime_mem 4000 \ memcap 6000 \ email_hdrs_log_depth 2920 \ disabled Default: preprocessor SMTP: \ ports { 25 } \ inspection_type stateful \ normalize cmds \ normalize_cmds { EXPN VRFY RCPT } \ alt_max_command_line_len 260 { MAIL } \ alt_max_command_line_len 300 { RCPT } \ alt_max_command_line_len 500 { HELP HELO ETRN } \ alt_max_command_line_len 255 { EXPN VRFY } Notes: "RCPT TO:" and "MAIL FROM:" are SMTP commands. For the preprocessor configuration, they are referred to as RCPT and MAIL, respectively. Within the code, the preprocessor actually maps RCPT and MAIL to the correct command name. snort-2.9.6.0/doc/README.sfportscan0000644000000000000000000003764212260355636013554 00000000000000sfPortscan ---------- Daniel Roelker Marc Norton Jeremy Hewlett Documentation last updated 2004-09-08 -- Overview -- This module is designed to detect the first phase in a network attack: Reconnaissance. In the Reconnaissance phase, an attacker determines what types of network protocols or services a host supports. This is the traditional place where a portscan takes place. This phase assumes the attacking host has no prior knowledge of what protocols or services are supported by the target, otherwise this phase would not be necessary. As the attacker has no beforehand knowledge of its intended target, most queries sent by the attacker will be negative (meaning that the services are closed). In the nature of legitimate network communications, negative responses from hosts are rare, and rarer still are multiple negative responses within a given amount of time. Our primary objective in detecting portscans is to detect and track these negative responses. One of the most common portscanning tools in use today is Nmap. Nmap encompasses many, if not all, of the current portscanning techniques. sfPortscan was designed to be able to detect the different types of scans Nmap can produce. The following are a list of the types of Nmap scans sfPortscan will currently alert for. * TCP Portscan * UDP Portscan * IP Portscan These alerts are for one->one portscans, which are the traditional types of scans; one host scans multiple ports on another host. Most of the port queries will be negative, since most hosts have relatively few services available. * TCP Decoy Portscan * UDP Decoy Portscan * IP Decoy Portscan Decoy portscans are much like the above, only the attacker has spoofed source address inter-mixed with the real scanning address. This tactic helps hide the true identity of the attacker. * TCP Distributed Portscan * UDP Distributed Portscan * IP Distributed Portscan These are many->one portscans. Distributed portscans occur when multiple hosts query one host for open services. This is used to evade an IDS and obfuscate command and control hosts. Caveat: Negative queries will be distributed among scanning hosts, so we track this type of scan through the scanned host. * TCP Portsweep * UDP Portsweep * IP Portsweep * ICMP Portsweep The alerts are for one-many portsweeps. One host scans a single port on multiple hosts. Usually occurs when a new exploit comes out and the attacker is looking for a specific service. Caveat: The characteristics of a portsweep scan may not result in many negative responses. For example, if an attacker portsweeps a web farm for port 80, we will most likely not see many negative responses. * TCP Filtered Portscan * UDP Filtered Portscan * IP Filtered Portscan * TCP Filtered Decoy Portscan * UDP Filtered Decoy Portscan * IP Filtered Decoy Portscan * TCP Filtered Portsweep * UDP Filtered Portsweep * IP Filtered Portsweep * ICMP Filtered Portsweep * TCP Filtered Distributed Portscan * UDP Filtered Distributed Portscan * IP Filtered Distributed Portscan "Filtered" alerts indicate that there were no network errors (ICMP unreachables or TCP RSTs) or responses on closed ports have been suppressed. It's also a good indicator on whether the alert is just a very active legitimate host. Active hosts, such as NATs, can trigger these alerts because they can send out many connection attempts within a very small amount of time. A filtered alert may go off before responses from the remote hosts are received. sfPortscan only generates one alert for each host pair in question during the time window (more on windows below). On TCP scan alerts, sfPortscan will also display any open ports that were scanned. On TCP sweep alerts however, sfPortscan will only track open ports after the alert has been triggered. Open port events are not individual alerts, but tags based off the original scan alert. -- Configuration -- Use of the "stream5" preprocessor is required for sfPortscan. Stream gives portscan direction in the case of connectionless protocols like UDP. preprocessor stream5_global: track_udp yes preprocessor stream5_udp: The parameters you can use to configure the portscan module are: * proto { } Available options: tcp udp icmp ip all * scan_type { } Available options: portscan portsweep decoy_portscan distributed_portscan all * sense_level { } Available options: low medium high "Low" alerts are only generated on error packets sent from the target host, and because of the nature of error responses, this setting should see very few false positives. However, this setting will never trigger a Filtered Scan alert because of a lack of error responses. This setting is based on a static time window of 60 seconds, afterwhich this window is reset. "Medium" alerts track Connection Counts, and so will generate Filtered Scan alerts. This setting may false positive on active hosts (NATs, proxies, DNS caches, etc), so the user may need to deploy the use of Ignore directives to properly tune this directive. "High" alerts continuously track hosts on a network using a time window to evaluate portscan statistics for that host. A "High" setting will catch some slow scans because of the continuous monitoring, but is very sensitive to active hosts. This most definitely will require the user to tune sfPortscan. * watch_ip { } Defines which IPs, networks, and specific ports on those hosts to watch. The list is a comma separated list of IP addresses, IP address using CIDR notation. Optionally, ports are specified after the IP address/CIDR using a space and can be either a single port or a range denoted by a dash. IPs or networks not falling into this range are ignored if this option is used. * ignore_scanners { } Ignores the source of scan alerts. The parameter is the same format as that of watch_ip. * ignore_scanned { } Ignores the destination of scan alerts. The parameter is the same format as that of watch_ip. * memcap { positive integer } The maximum number of bytes to allocate for portscan detection. The higher this number the more nodes that can be tracked. * disabled This optional keyword is allowed with any policy to avoid packet processing. This option disables the preprocessor. When the preprocessor is disabled only the memcap option is applied when specified with the configuration. The other options are parsed but not used. Any valid configuration may have "disabled" added to it. * logfile { } This option will output portscan events to the file specified. If does not contain a leading slash, this file will be placed in the Snort config dir. * include_midstream This option will include sessions picked up in midstream by Stream4 or Stream5. This can lead to false alerts, especially under heavy load with dropped packets; which is why the option is off by default. * detect_ack_scans This option will include sessions picked up in midstream by the stream module, which is necessary to detect ACK scans. However, this can lead to false alerts, especially under heavy load with dropped packets; which is why the option is off by default. Example configuration: preprocessor flow: stats_interval 0 hash 2 preprocessor sfportscan: proto { all } \ scan_type { all } \ sense_level { low } -- Alert Output -- (unified) In order to get all the portscan information logged with the alert, snort generates a pseudo-packet and uses the payload portion to store the additional portscan information of priority count, connection count, IP count, port count, IP range, and port range. The characteristics of the packet are: Src/Dst MAC Addr == MACDAD IP Protocol == 255 IP TTL == 0 Other than that, the packet looks like the IP portion of the packet that caused the portscan alert to be generated. This includes any IP options, etc. The payload and payload size of the packet is equal to the length of the additional portscan information that is logged. The size tends to be around 100 - 200 bytes. Open port alerts differ from the other portscan alerts, because open port alerts utilize the tagged packet output system. This means that if an output system that doesn't print tagged packets is used, then the user won't see open port alerts. The open port information is stored in the IP payload and contains the port that is open. The sfPortscan alert output was designed to work with unified packet logging, so it is possible to extend favorite snort GUIs to display portscan alerts and the additional information in the IP payload using the above packet characteristics. (logfile) Logfile output is displayed in the following format, and explained further below: Time: 09/08-15:07:31.603880 event_id: 2 192.168.169.3 -> 192.168.169.5 (portscan) TCP Filtered Portscan Priority Count: 0 Connection Count: 200 IP Count: 2 Scanner IP Range: 192.168.169.3:192.168.169.4 Port/Proto Count: 200 Port/Proto Range: 20:47557 If there are open ports on the target, an additional tagged packet(s) will be appended: Time: 09/08-15:07:31.603881 event_ref: 2 192.168.169.3 -> 192.168.169.5 (portscan) Open Port Open Port: 38458 1. Event_id/Event_ref These fields are used to link an alert with the corresponding Open Port tagged packet 2. Priority Count Priority Count keeps track of bad responses (resets, unreachables). The higher the Priority Count, the more bad responses have been received. 3. Connection Count Connection Count lists how many connections are active on the hosts (src or dst). This is accurate for connection-based protocols, and is more of an estimate for others. Whether or not a portscan was filtered is determined here. High connection count and low priority count would indicate filtered (no response received from target). 4. IP Count IP Count keeps track of the last IP to contact a host, and increments the count if the next IP is different. For one-to-one scans, this is a low number. For active hosts this number will be high regardless, and one-to-one scans may appear as a distributed scan. 5. Scanned/Scanner IP Range This field changes depending on the type of alert. Portsweeps (one-to-many) scans display the scanned IP range; Portscans (one-to-one) display the scanner IP. 6. Port Count Port Count keeps track of the last port contacted and increments this number when that changes. We use this count (along with IP Count) to determine the difference between one-to-one portscans and one-to-one decoys. -- Tuning sfPortscan -- The most important aspect in detecting portscans is tuning the detection engine for your network(s). Here are some tuning tips: 1. Use the watch_ip, ignore_scanners, and ignore_scanned options. It's important to correctly set these options. The watch_ip option is easy to understand. The analyst should set this option to the list of Cidr blocks and IPs that they want to watch. If no watch_ip is defined, sfPortscan will watch all network traffic. The ignore_scanners and ignore_scanned options come into play in weeding out legitimate hosts that are very active on your network. Some of the most common examples are NAT IPs, DNS cache servers, syslog servers, and nfs servers. sfPortscan may not generate false positives for these types of hosts, but be aware when first tuning sfPortscan for these IPs. Depending on the type of alert that the host generates, the analyst will know which to ignore it as. If the host is generating portsweep events, then add it to the ignore_scanners option. If the host is generating portscan alerts (and is the host that is being scanned), add it to the ignore_scanned option. 2. Filtered scan alerts are much more prone to false positives. When deteriming false positives, the alert type is very important. Most of the false positives that sfPortscan may generate are of the filtered scan alert type. So be much more suspicious of filtered portscans. Many times this just indicates that a host was very active during the time period in question. If the host continually generates these types of alerts, add it to the ignore_scanners list or use a lower sensitivity level. 3. Make use of the Priority Count, Connection Count, IP Count, Port Count, IP range, and Port range to determine false positives. The portscan alert details are vital in determining the scope of a portscan and also the confidence of the portscan. In the future, we hope to automate much of this analysis in assigning a scope level and confidence level, but for now the user must manually do this. The easiest way to determine false positives is through simple ratio estimations. The following is a list of ratios to estimate and the associated values that indicate a legitimate scan and not a false positive. Connection Count / IP Count: This ratio indicates an estimated average of connections per IP. For portscans, this ratio should be high, the higher the better. For portsweeps, this ratio should be low. Port Count / IP Count: This ratio indicates an estimated average of ports connected to per IP. For portscans, this ratio should be high and indicates that the scanned host's ports were connected to by fewer IPs. For portsweeps, this ratio should be low, indicating that the scanning host connected to few ports but on many hosts. Connection Count / Port Count: This ratio indicates an estimated average of connections per port. For portscans, this ratio should be low. This indicates that each connection was to a different port. For portsweeps, this ratio should be high. This indicates that there were many connections to the same port. The reason that Priority Count is not included, is because the priority count is included in the connection count and the above comparisons take that into consideration. The Priority Count play an important role in tuning because the higher the priority count the more likely it is a real portscan or portsweep (unless the host is firewalled). 4. If all else fails, lower the sensitivity level. If none of these other tuning techniques work or the analyst doesn't have the time for tuning, lower the sensitivity level. You get the best protection the higher the sensitivity level, but it's also important that the portscan detection engine generates alerts that the analyst will find informative. The low sensitivity level only generates alerts based on error responses. These responses indicate a portscan and the alerts generated by the low sensitivity level are highly accurate and require the least tuning. The low sensitivity level does not catch filtered scans, since these are more prone to false positives. Alerts ====== SFPortscan uses generator ID 122 and can generate the following alerts: SID Description --- ----------- 1 TCP Portscan 2 TCP Decoy Portscan 3 TCP Portsweep 4 TCP Distributed Portscan 5 TCP Filtered Portscan 6 TCP Filtered Decoy Portscan 7 TCP Filtered Portsweep 8 TCP Filtered Distributed Portscan 9 IP Protocol Scan 10 IP Decoy Protocol Scan 11 IP Protocol Sweep 12 IP Distributed Protocol Scan 13 IP Filtered Protocol Scan 14 IP Filtered Decoy Protocol Scan 15 IP Filtered Protocol Sweep 16 IP Filtered Distributed Protocol Scan 17 UDP Portscan 18 UDP Decoy Portscan 19 UDP Portsweep 20 UDP Distributed Portscan 21 UDP Filtered Portscan 22 UDP Filtered Decoy Portscan 23 UDP Filtered Portsweep 24 UDP Filtered Distributed Portscan 25 ICMP Sweep 26 ICMP Filtered Sweep 27 Open Port snort-2.9.6.0/doc/README.sensitive_data0000644000000000000000000001332611356637671014374 00000000000000Overview ======== The Sensitive Data preprocessor is a Snort module that performs detection and filtering of Personally Identifiable Information (PII). This information includes credit card numbers, U.S. Social Security numbers, and email addresses. A limited regular expression syntax is also included for defining your own PII. Sections: Dependencies Preprocessor Configuration Rule Options Dependencies ============ The Stream5 preprocessor must be enabled for the Sensitive Data preprocessor to work. Preprocessor Configuration ========================== Sensitive Data configuration is split into two parts: the preprocessor config, and the rule options. The preprocessor config starts with: preprocessor sensitive_data: Options are as follows: Option Argument Required Default --------------------------------------------------------------------------- alert_threshold NO alert_threshold 25 1 - 4294067295 mask_output NONE NO OFF ssn_file NO OFF Option explanations alert_threshold The preprocessor will alert when any combination of PII are detected in a session. This option specifies how many need to be detected before alerting. This should be set higher than the highest individual count in your "sd_pattern" rules. mask_output This option replaces all but the last 4 digits of a detected PII with "X"s. This is only done on credit card & Social Security numbers, where an organization's regulations may prevent them from seeing unencrypted numbers. ssn_file A Social Security number is broken up into 3 sections: Area (3 digits), Group (2 digits), and Serial (4 digits). On a monthly basis, the Social Security Administration publishes a list of which Group numbers are in use for each Area. These numbers can be updated in Snort by supplying a CSV file with the new maximum Group numbers to use. By default, Snort recognizes Social Security numbers issued up through November 2009. Example preprocessor config preprocessor sensitive_data: alert_threshold 25 \ mask_output \ ssn_file ssn_groups_Jan10.csv Rule Options ============ Snort rules are used to specify which PII the preprocessor should look for. A new rule option is provided by the preprocessor: sd_pattern This rule option specifies what type of PII a rule should detect. Syntax: sd_pattern: , count = 1-255 pattern = any string Option Explanations: count This dictates how many times a PII pattern must be matched for an alert to be generated. The count is tracked across all packets in a session. pattern This is where the pattern of the PII gets specified. There are a few built-in patterns to choose from: credit_card: The "credit_card" pattern matches 15- and 16-digit credit card numbers. These numbers may have spaces, dashes, or nothing in between groups. This covers Visa, Mastercard, Discover, and American Express. Credit card numbers matched this way have their check digits verified using the Luhn algorithm. us_social: This pattern matches against 9-digit U.S. Social Security numbers. The SSNs are expected to have dashes between the Area, Group, and Serial sections. SSNs have no check digits, but the preprocessor will check matches against the list of currently allocated group numbers. us_social_nodashes: This pattern matches U.S. Social Security numbers without dashes separating the Area, Group, and Serial sections. email: This pattern matches against email addresses. If the pattern specified is not one of the above built-in patterns, then it is the definition of a custom PII pattern. Custom PII types are defined using a limited regex-style syntax. The following special characters and escape sequences are supported: \d - matches any digit \D - matches any non-digit \l - matches any letter \L - matches any non-letter \w - matches any alphanumeric character \W - matches any non-alphanumeric character {num} - used to repeat a character or escape sequence "num" times. example: "\d{3}" matches 3 digits. ? - makes the previous character or escape sequence optional. example: " ?" matches an optional space. This behaves in a greedy manner. \\ - matches a backslash \{, \} - matches { and } \? - matches a question mark. Other characters in the pattern will be matched literally. NOTE: Unlike PCRE, "\w" in this rule option does NOT match underscores. Examples: sd_pattern: 2,us_social; Alerts when 2 social security numbers (with dashes) appear in a session. sd_pattern: 5,(\d{3})\d{3}-\d{4}; Alerts on 5 U.S. phone numbers, following the format (123)456-7890 Whole rule example: alert tcp $HOME_NET $HIGH_PORTS -> $EXTERNAL_NET $SMTP_PORTS \ (msg:"Credit Card numbers sent over email"; gid:138; sid:1000; rev:1; \ sd_pattern:4,credit_card; metadata:service smtp;) Caveats: sd_pattern is not compatible with other rule options. Trying to use other rule options with sd_pattern will result in an error message. Rules using sd_pattern must use GID 138. snort-2.9.6.0/doc/README.rzb_saac0000644000000000000000000000165111573541474013150 00000000000000#### EXPERIMENTAL #### RZB_SaaC --- Patrick Mullen Ron Dempster Documentation last update 2011-01-05 == Overview == The Razorback SaaC preprocessor monitors SMTP and HTTP streams and extracts documents that are forwarded to a Razorback dispatcher for analysis. HTTP streams have a destination port of 80 and SMTP streams have a destination port of 25. == Configuration == The only configuration that is accepted is rzb_conf By default, all alerts are disabled and the preprocessor checks traffic on port 22. The available configuration options are described below: * rzb_conf This option specifies the name and location of the Razorback configuration file. For information on Razorback functionality and configuration, please visit http://sourceforge.net/projects/razorbacktm/ and http://sourceforge.net/projects/nuggetfarm/ == Example Configuration == preprocessor rzb: rzb_conf /var/tmp/rzb.conf snort-2.9.6.0/doc/README.reputation0000644000000000000000000002653512260355636013563 00000000000000Reputation Preprocessor ================================================================================ Hui Cao Overview ================================================================================ Reputation preprocessor provides basic IP blacklist/whitelist capabilities, to block/drop/pass traffic from IP addresses listed. In the past, we use standard Snort rules to implement Reputation-based IP blocking. This preprocessor will address the performance issue and make the IP reputation management easier. Reputation preprocessor runs before other preprocessors. Sections: Configuration IP list file format Events Shared memory support Configuration ================================================================================ The preprocessor configuration name is "reputation". preprocessor reputation Option Argument Required Default memcap No memcap 500 scan_local None No off blacklist No NULL whitelist No NULL priority [blacklist whitelist] No priority whitelist nested_ip [inner outer both] No nested_ip inner white [black trust] No white unblack memcap = 1 - 4095 Mbytes preprocessor reputation:\ < memcap number >,\ < scan_local >, \ < blacklist < list filename >>,\ < whitelist < list filename >>,\ < priority [blacklist whitelist] >,\ < nested_ip [inner outer both] >,\ < white [unblack trust] > Options: < memcap number >: maximum total memory allocated (in Megabytes). It can be set up to 4095 Megabytes. < scan_local > : Enable to inspect local address defined in RFC 1918: 10.0.0.0 - 10.255.255.255 (10/8 prefix) 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) < list filename > : The IP lists are loaded from external files. It supports relative paths for inclusion and $variables for path. Multiple blacklists or whitelists are supported. Note: if the same IP is redefined later, it will overwrite the previous one. In other words, IP lists always favors the last file or entry processed. < priority > : Specify either blacklist or whitelist has higher priority when source/destination is on blacklist while destination/source is on whitelist. By default, whitelist has higher priority. In other words, the packet will be passed when either source or destination is whitelisted. Note: this only defines priority when there is a decision conflict, during run-time. During initialization time, if the same IP address is defined in whitelist and blacklist, whoever the last one defined will be the final one. Priority does not work on this case. < nested_ip >: Specify which IP address to be used when there is IP encapsulation. < white >: Specify the meaning of whitelist. When white means unblack, it unblacks IPs that are in blacklists; when white means trust, the packet gets bypassed, without further detection by snort. You can only specify either unblack or trust. Note: when white means unblack, whitelist always has higher priority than blacklist. Configuration examples Default configuration # Standard blacklisting. # If running in inline mode the packets will be dropped. preprocessor reputation:\ blacklist /etc/snort/default.blacklist, \ whitelist /etc/snort/default.whitelist Inspect inner and outer IP configuration # Inspect both inner and outer, Also adds a whitelist entry # to make exceptions. preprocessor reputation: n nested_ip both, \ blacklist /etc/snort/default.blacklist, \ whitelist /etc/snort/default.whitelist Full configuration # Blacklisting with scan local network, use both headers, # and whitelist has higher priority. # Also adds a whitelist entry to make exceptions. preprocessor reputation: \ memcap 200, scan_local, nested_ip both, \ priority whitelist, \ blacklist /etc/snort/default.blacklist, \ whitelist /etc/snort/default.whitelist, \ white trust Variable path/file configuration $REP_BLACK_FILE1 = ../dshield.list $REP_BLACK_FILE2 = ../snort.org.list preprocessor reputation: \ blacklist $REP_BLACK_FILE1,\ blacklist $REP_BLACK_FILE2 IP List File Format Syntax The IP list file has 1 entry per line. The entry can be either IP entry or comment. IP Entry CIDR notation line break Example: 172.16.42.32/32 Comment # Example: # This is a full line comment IP List File Example ---------------------- # This is a full line comment 172.16.42.32/32 # This is an inline comment, line with single CIDR block Use case A user wants to protect his/her network from unwanted/unknown IPs, only allowing some trusted IPs. Here is the configuration: preprocessor reputation: \ blacklist /etc/snort/default.blacklist whitelist /etc/snort/default.whitelist In file "default.blacklist" # These two entries will match all ipv4 addresses 1.0.0.0/1 128.0.0.0/1 In file "default.whitelist" 68.177.102.22 # sourcefire.com 74.125.93.104 # google.com Events ================================================================================ The preprocessor uses GID 136 to register events. SID Description -------------------------------------------------------------------------------- 1 Packets are blacklisted. 2 Packets are whitelisted. 3 Packets are inspected. Rule Options ================================================================================ No rule options Shared memory support ================================================================================ In order to minimize memory consumption when multiple Snort instances are running concurrently, we introduce the support of shared memory. After configured, all the snort instances share the same IP tables in shared memory. System requirement This feature is supported only in Linux. Build configuration A new option, --enable-shared-rep is introduced to ./configure command. This option enables the support for shared memory. In order to signal Snort to reload the IP file lists, control socket feature should be enabled also. --enable-control-socket Configuration shared_mem If the build supports shared memory, this configuration will enable shared memory. If this option isn't set, standard memory is used. This option must specify a path or directory where IP lists will be loaded in shared memory. One snort instance will create and maintain the shared IP lists. We use instance ID 1, specified in the snort -G option to be the master snort. All the other snort instances are clients (readers). Syntax: shared_mem: path Examples: shared_mem /user/reputation/iplists shared_refresh This option changes the period of checking new shared memory segment, in the unit of second. By default, the refresh rate is 60 seconds. Syntax: shared_refresh period = "1 - 4294967295" Examples: shared_refresh 60 Steps to configure shared memory 1) When building Snort, add option -enable-shared-rep and --enable-control-socket to ./configure. For example: ./configure --enable-gre --enable-sourcefire --enable-flexresp3 --enable-pthread --enable-linux-smp-stats --enable-mpls --enable-targetbased --enable-shared-rep --enable-control-socket 2) Put your IP list file into a directory, where snort has full access For example: /user/reputation/iplists In order to separate whitelist with blacklist, you need to specify whitelist with .wlf extension and blacklist with .blf extension. 3) In snort config file, specify shared memory support with the path to IP files. Example: shared_mem /user/reputation/iplists If you want to change the period of checking new IP lists, add refresh period. Example: shared_refresh 300 4) Start shared memory master(writer) with -G 0 option. Note: only one master should be enabled. 5) Start shared memory clients (readers) with -G 1 or other IDs. Note: for one ID, only one snort instance should be enabled. 6) You will see the IP lists got loaded and shared across snort instances! Reload IP list using control socket 1) Run snort using command line with option --cs-dir or configure snort with config cs_dir: 2) (Optional) you can create a version file named "IPRVersion.dat" in the IP list directory. This file helps managing reloading IP lists, by specifying version. When the version isn't changed, IP lists will not be reloaded if they are already in shared memory. The version number should be a 32 bit number. For example: VERSION=19 3) In the ./src/tools/control directory, you will find snort_control command if built with --enable-control-socket option. 4) Type the following command to reload IP lists. Before typing this command, make sure to update version file if you are using version file. The is the same path in step 1). /src/tools/control/snort_control 1361 Using manifest file to manage loading (optional) Using manifest file, you can control the file loading sequence, action taken, and support zone based detection. You can create a manifest file named "zone.info" in the IP list directory. When Snort is signaled to load new lists, a manifest file is read first to determine which zones the IPs in each list are applicable to and what action to take per list (Block, White, Monitor). Files listed in manifest are loaded from top to bottom. You should put files that have higher priority first. In manifest file, you can put up to 255 files. Without manifest file, files will be loaded in alphabet order. Here's the format of the manifest file. Each line of the file has the following format: , ,[, ]+ ::= 32 bit integer ::= "monitor"|"block"|"white" ::= [0-1051] Using manifest file, you can specify a new action called "monitor", which indicates a packet needs to be monitored, but does not disable detection. This is different from "block" action, which disables further detection. This new action helps users evaluate their IP lists before applying it. An example manifest file: #ipreputation manifest file white.wlf, 111 ,white, black1.blf, 1112, black, 3, 12 black2.blf, 1113, black, 3, 12 monitor.blf,2222, monitor, 0, 2, 8 snort-2.9.6.0/doc/README.reload0000644000000000000000000001012012260355636012616 00000000000000Reloading a Snort configuration =============================== Snort now supports reloading a configuration in lieu of restarting Snort in so as to provide seamless traffic inspection during a configuration change. A separate thread will parse and create a swappable configuration object while the main Snort packet processing thread continues inspecting traffic under the current configuration. When a swappable configuration object is ready for use, the main Snort packet processing thread will swap in the new configuration to use and will continue processing under the new configuration. Note that for some preprocessors, existing session data will continue to use the configuration under which they were created in order to continue with proper state for that session. All newly created sessions will, however, use the new configuration. Enabling support ================ To enable support for reloading a configuration, add "--enable-reload" to configure when compiling. There is also an ancillary option that determines how Snort should behave if any non-reloadable options are changed (see "Non-reloadable configuration options" below). This option is enabled by default and the behavior is for Snort to restart if any non-reloadable options are added/modified/removed. To disable this behavior and have Snort exit instead of restart, add "--disable-reload-error-restart" in addition to "--enable-reload" to configure when compiling. NOTE: This functionality is not currently supported in Windows. Reloading a configuration ========================= First modify your snort.conf (the file passed to the '-c' option on the command line). Then, to initiate a reload, send Snort a SIGHUP signal, e.g. $ kill -SIGHUP NOTE: If reload support is not enabled, Snort will restart (as it always has) upon receipt of a SIGHUP. NOTE: An invalid configuration will still result in a fatal error, so you should test your new configuration before issuing a reload, e.g. $ snort -c snort.conf -T Non-reloadable configuration options ==================================== There are a number of option changes that are currently non-reloadable because they require changes to output, startup memory allocations, etc. Modifying any of these options will cause Snort to restart (as a SIGHUP previously did) or exit (if "--disable-reload-error-restart" was used to configure Snort). Reloadable configuration options of note: * Adding/modifying/removing text rules and variables are reloadable. * Adding/modifying/removing preprocessor configurations are reloadable (except as noted below). Non-reloadable configuration options of note: * Adding/modifying/removing shared objects via dynamicdetection, dynamicengine and dynamicpreprocessor are not reloadable, i.e. any new/modified/removed shared objects will require a restart. * Any changes to output will require a restart. Changes to the following options are not reloadable: attribute_table config alertfile config asn1 config chroot config daemon config detection_filter config flowbits_size config interface config logdir config max_attribute_hosts config max_attribute_services_per_host config nolog config no_promisc config pkt_count config rate_filter config response config set_gid config set_uid config snaplen config threshold dynamicdetection dynamicengine dynamicpreprocessor output In certain cases, only some of the parameters to a config option or preprocessor configuration are not reloadable. Those parameters are listed below the relevant config option or preprocessor. config ppm: max_rule_time rule-log config profile_rules filename print sort config profile_preprocs filename print sort preprocessor dcerpc2 memcap preprocessor frag3_global max_frags memcap prealloc_frags prealloc_memcap preprocessor perfmonitor file snortfile flow-file flow-ip-file preprocessor sfportscan memcap logfile preprocessor stream5_global memcap max_tcp max_udp max_icmp track_tcp track_udp track_icmp Caveats: ======== When Snort is run on the primary network interface of an OpenBSD system, the reload and failopen operations may not function as expected. snort-2.9.6.0/doc/README.ppm0000644000000000000000000001434412026730050012143 00000000000000Packet Performance Monitoring (PPM) Capability ---------------------------------------------- PPM provides thresholding mechanisms that can be used to provide a basic level of latency control for snort. It does not provide a hard and fast latency guarantee but should in effect provide a good average latency control. Both rules and packets can be checked for latency. The action taken upon detection of excessive latency is configurable. The following sections describe configuration, sample output, and some implementation details worth noting. To use PPM, you must build with the --enable-ppm or the --enable-sourcefire option to configure. PPM is configured as follows: # Packet configuration: config ppm: max-pkt-time , \ fastpath-expensive-packets, \ pkt-log, \ debug-pkts # Rule configuration: config ppm: max-rule-time , \ threshold count, \ suspend-expensive-rules, \ suspend-timeout , \ rule-log [log] [alert] Packets and rules can be configured separately, as above, or together in just one config ppm statement. Packet and rule monitoring is independent, so one or both or neither may be enabled. Packet Configuration Options ---------------------------- max-pkt-time - enables packet latency thresholding using 'micros-secs' as the limit. - default is 0 (packet latency thresholding disabled) - reasonable starting defaults: 100/250/1000 for 1G/100M/5M nets fastpath-expensive-packets - enables stopping further inspection of a packet if the max time is exceeded - default is off pkt-log [log] [alert] - enables logging packet event if packet exceeds max-pkt-time - default is no logging - if no option is given for 'pkt-log', 'pkt-log log' is implied - the log option enables output to syslog or console depending upon snort configuration debug-pkts - enables per packet timing stats to be printed after each packet - default is off Rule Configuration Options -------------------------- max-rule-time - enables rule latency thresholding using 'micros-secs' as the limit. - default is 0 (rule latency thresholding disabled) - reasonable starting defaults: 100/250/1000 for 1G/100M/5M nets threshold - sets the number of cumulative rule time excesses before disabling a rule - default is 5 suspend-expensive-rules - enables suspending rule inspection if the max rule time is exceeded - default is off suspend-timeout - rule suspension time in seconds - default is 60 seconds - set to zero to permanently disable expensive rules rule-log [log] [alert] - enables event logging output for rules - default is no logging - one or both of the options 'log' and 'alert' must be used with 'rule-log' - the log option enables output to syslog or console depending upon snort configuration Example 1 --------- The following enables packet tracking: config ppm: max-pkt-time 100 The following enables rule tracking: config ppm: max-rule-time 50, threshold 5 If fastpath-expensive-packets or suspend-expensive-rules is not used, then no action is taken other than to increment the count of the number of packets that should be fastpath'd or the rules that should be suspended. A summary of this information is printed out when snort exits. Example 2 --------- The following suspends rules and aborts packet inspection. These rules were used to generate the sample output that follows. config ppm: max-pkt-time 50, fastpath-expensive-packets, pkt-log, \ debug-pkt config ppm: max-rule-time 50, threshold 5, suspend-expensive-rules, \ suspend-timeout 300, rule-log log alert Sample Snort Startup Output --------------------------- Packet Performance Monitor Config: ticks per usec : 1600 ticks max packet time : 50 usecs packet action : fastpath-expensive-packets packet logging : log debug-pkts : disabled Rule Performance Monitor Config: ticks per usec : 1600 ticks max rule time : 50 usecs rule action : suspend-expensive-rules rule threshold : 5 suspend timeout : 300 secs rule logging : alert log Sample Snort Run-time Output ---------------------------- ... PPM: Process-BeginPkt[61] caplen=60 PPM: Pkt[61] Used= 8.15385 usecs PPM: Process-EndPkt[61] PPM: Process-BeginPkt[62] caplen=342 PPM: Pkt[62] Used= 65.3659 usecs PPM: Process-EndPkt[62] PPM: Pkt-Event Pkt[63] used=56.0438 usecs, 0 rules, 1 nc-rules tested, packet fastpathed (10.4.12.224:80 -> 10.4.14.108:54321). PPM: Process-BeginPkt[63] caplen=60 PPM: Pkt[63] Used= 8.394 usecs PPM: Process-EndPkt[63] PPM: Process-BeginPkt[64] caplen=60 PPM: Pkt[64] Used= 8.21764 usecs PPM: Process-EndPkt[64] ... Sample Snort Exit Output ------------------------ Packet Performance Summary: max packet time : 50 usecs packet events : 1 avg pkt time : 0.633125 usecs Rule Performance Summary: max rule time : 50 usecs rule events : 0 avg nc-rule time : 0.2675 usecs Implementation Details ---------------------- 1. Enforcement of packet and rule processing times is done after processing each rule. Latency control is not enforced after each preprocessor. 2. This implementation is software based and does not use an interrupt driven timing mechanism and is therefore subject to the granularity of the software based timing tests. Due to the granularity of the timing measurements any individual packet may exceed the user specified packet or rule processing time limit. Therefore this implementation cannot implement a precise latency guarantee with strict timing guarantees. Hence the reason this is considered a best effort approach. 3. Since this implementation depends on hardware based high performance frequency counters, latency thresholding is presently only available on Intel and PPC platforms. 4. Time checks are made based on the total system time, not processor usage by Snort. This was a conscious design decision because when a system is loaded, the latency for a packet is based on the total system time, not just the processor time the Snort application receives. Therefore, it is recommended that you tune your thresholding to operate optimally when your system is under load. snort-2.9.6.0/doc/README.pop0000644000000000000000000001670512260355636012165 00000000000000POP ==== -- Overview -- POP is an POP3 decoder for user applications. Given a data buffer, POP will decode the buffer and find POP3 commands and responses. It will also mark the command, data header data body sections and extract the POP3 attachments and decode it appropriately. POP will handle stateful processing. It saves state between individual packets. However maintaining correct state is dependent on the reassembly of the server side of the stream (i.e., a loss of coherent stream data results in a loss of state). Stream5 should be turned on for POP. Please ensure that the POP ports are added to the stream5 ports for proper reassembly. -- Configuration -- The configuration options are described below: * ports { port [port] ... } * This specifies on what ports to check for POP data. Typically, this will include 110. Default ports if none are specified are 110 . * disabled * Disables the POP preprocessor in a config. This is useful when specifying the decoding depths such as b64_decode_depth, qp_decode_depth, uu_decode_depth, bitenc_decode_depth or the memcap used for decoding in default config without turning on the POP preprocessor. * b64_decode_depth * This config option is used to turn off/on or set the base64 decoding depth used to decode the base64 encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the base64 decoding of MIME attachments. The value of 0 sets the decoding of base64 encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of base64 MIME attachments, and applies per attachment. A POP preprocessor alert with sid 4 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the base64 encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. It is recommended that user inputs a value that is a multiple of 4. When the value specified is not a multiple of 4, the POP preprocessor will round it up to the next multiple of 4. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * qp_decode_depth * This config option is used to turn off/on or set the Quoted-Printable decoding depth used to decode the Quoted-Printable(QP) encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the QP decoding of MIME attachments. The value of 0 sets the decoding of QP encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of QP MIME attachments, and applies per attachment. A POP preprocessor alert with sid 5 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the QP encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * bitenc_decode_depth * This config option is used to turn off/on or set the non-encoded MIME extraction depth used to extract the non-encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the extraction of these MIME attachments. The value of 0 sets the extraction of these MIME attachments to unlimited. A value other than 0 or -1 restricts the extraction of these MIME attachments, and applies per attachment. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the non-encoded MIME attachments/data across multiple packets are extracted too. The extracted data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * uu_decode_depth * This config option is used to turn off/on or set the Unix-to-Unix decoding depth used to decode the Unix-to-Unix(UU) encoded attachments. The value ranges from -1 to 65535. A value of -1 turns off the UU decoding of POP attachments. The value of 0 sets the decoding of UU encoded POP attachments to unlimited. A value other than 0 or -1 restricts the decoding of UU POP attachments, and applies per attachment. A POP preprocessor alert with sid 7 is generated (if enabled) when the decoding fails. Multiple UU Encoded attachments/data in one packet are pipelined. When stateful inspection is turned on the UU encoded attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * memcap * This option determines (in bytes) the maximum amount of memory the POP preprocessor will use for decoding base64 encoded/quoted-printable/non-encoded MIME attachments/data or Unix-to-Unix encoded attachments. This value can be set from 3276 bytes to 100MB. This option along with the maximum of the decoding depths will determine the POP sessions that will be decoded at any given instant. The default value for this option is 838860. Note: It is suggested to set this value such that the max pop session calculated as follows is at least 1. max pop session = memcap /(2 * max of (b64_decode_depth, uu_decode_depth, qp_decode_depth or bitenc_decode_depth)) For example, if b64_decode_depth is 0 (indicates unlimited decoding) and qp_decode_depth is 100, then max pop session = memcap/2*65535 (max value for b64_decode_depth) In case of multiple configs, the memcap of the non-default configs will be overwritten by the default config's value. Hence user needs to define it in the default config with the new keyword disabled (used to disable POP preprocessor in a config). When the memcap for decoding (memcap) is exceeded the POP preprocessor alert with sid 3 is generated (when enabled). Example: preprocessor pop: \ ports { 110 } \ memcap 1310700 \ qp_decode_depth -1 \ b64_decode_depth 0 \ bitenc_decode_depth 100 preprocessor pop: \ memcap 1310700 \ qp_decode_depth 0 \ disabled Default: preprocessor pop: \ ports { 110 } \ b64_decode_depth 1460 \ qp_decode_depth 1460 \ bitenc_decode_depth 1460 \ uu_decode_depth 1460 Events ================================================================================ The POP preprocessor uses GID 142 to register events. SID Description -------------------------------------------------------------------------------- 1 Alert if POP encounters an invalid POP3 command. 2 Alert if POP encounters an invalid POP3 response. 3 If the decoding memory cap (memcap) is reached and the preprocessor is configured to alert, this alert will be created. 4 If the decoding of a base64 MIME attachments fails or when the decoding stops due to exceeded b64_decode_depth. 5 If the decoding of a Quoted-Printable MIME attachments fails or when the decoding stops due to exceeded qp_decode_depth. 7 If the decoding of a Unix-to-Unix encoded attachments fails or when the decoding stops due to exceeded uu_decode_depth. snort-2.9.6.0/doc/README.PLUGINS0000644000000000000000000000621710001575057012475 00000000000000Plugin Info 12/5/99 Martin Roesch Overview: Snort version 1.5 introduces a major new concept, plugins. There are two types of plugin currently available in Snort: detection plugins and preprocessors. Detection plugins check a single aspect of a packet for a value defined within a rule and determine if the packet data meets their acceptance criteria. For example, the tcp flags detection plugin checks the flags section of TCP packets for matches with flag combinations defined in a particular rule. Detection plugins may be called multiple times per packet with different arguments. Preprocessors are only called a single time per packet and may perform highly complex functions like TCP stream reassembly, IP defragmentation, or HTTP request normalization. They can directly manipulate packet data and even call the detection engine directly with their modified data. They can perform less complex tasks like statistics gathering or threshold monitoring as well. Adding New Plugins to Snort as a User: Right now, adding a new plugin to Snort is straightforward but requires you to edit two files by hand. The plugin should consist of two files, "sp_something.c"/"sp_something.h" for detection plugins, and "spp_something.c"/"spp_something.h" for preprocessors. For detection plugins, there are two steps to integrating it with Snort: 1) Edit plugbase.h and insert the line #include "sp_something.h" into the file with the other "#include" statements. Save and close the file. 2) Edit the plugbase.c file and in the InitPlugins() function, add the name of the setup function to the list with the other Setup functions. Save and close the file. 3) Edit the Makefile.am and add the names of the two files to the list of names on the "snort_SOURCES" line. Save and exit the file. Run "automake". All set. Now recompile Snort and the plugin should be ready to use! Adding preprocessors is equally straightforward. The process is essentially the same as above: 1) Edit plugbase.h and insert the line #include "spp_preproc.h" into the file with the other "#include" statements. Save and close the file. 2) Edit the plugbase.c file and in the InitPreprocessors() function, add the name of the setup function to the list with the other Setup functions. Save and close the file. 3) Edit the Makefile.am and add the names of the two files to the list of names on the "snort_SOURCES" line. Save and exit the file. Run "automake". Someday, there will be a nice little program that will do all this work for you! Writing New Snort Plugins as a Developer: This process is also pretty straight forward, and the best place to look for information on doing these things is at the files in the "templates" directory. The sp_* files are setup for detection plugins, and the spp_* files refer to the preprocessor files. The main thing to remember once you've got it written is to put the proper includes and function calls into plugbase[.c|.h]. I should probably flesh out this document more, but I think that the best info is in the template files. If you have any questions or comments, don't hesitate to send me an e-mail! snort-2.9.6.0/doc/README.PerfProfiling0000644000000000000000000002333012260355636014125 00000000000000# To use Rule or Preprocessor profiling, you must build snort using the # --enable-perfprofiling option to configure. # Rule Profiling Configuration # # syntax: # config profile_rules: print [all | num], sort sort_option, filename file_option [append] # - where num is the number of rules to print # - where sort_option is one of: # checks, matches, nomatches, avg_ticks, # avg_ticks_per_match, avg_ticks_per_nomatch, total_ticks # - where file_option is the output filename # - where append dictates that the output will go to the same file each time (optional) # # examples: # # 1) Print all rules, sort by avg_ticks (default configuration # if option is turned on) # config profile_rules # # 2) Print the top 10 rules, based on highest average time # config profile_rules: print 10, sort avg_ticks # # 3) Print all rules, sorted by number of checks # config profile_rules: print all, sort checks # # 4) Print top 100 rules, based on total time # config profile_rules: print 100, sort total_ticks # # 5) Print with default options, save results to performance.txt each time # config profile_rules: filename performance.txt append # # 6) Print top 20 rules, save results to perf.txt with timestamp in filename # config profile_rules: print 20, filename perf.txt When you use this (see configuration info with example output), snort will print the following table at exit. The column info is: - Number (rank) - Sig ID - Generator ID - Checks (number of times rule was evaludated after fast pattern match within portgroup or ANY->ANY rules) - Matches (number of times ALL rule options matched, will be high for rules that have no options) - Alerts (number of alerts generated from this rule) - CPU Ticks - Avg Ticks per Check - Avg Ticks per Match - Avg Ticks per Nonmatch Example, using config profile_rules: print 4, sort total_ticks Rule Profile Statistics (worst 4 rules) ========================================================== Num SID GID Rev Checks Matches Alerts Ticks Avg/Check Avg/Match Avg/Nonmatch === === === === ====== ======= ====== ===== ========= ========= ============ 1 2389 1 12 1 1 1 385698 385698.0 385698.0 0.0 2 2178 1 17 2 0 0 107822 53911.0 0.0 53911.0 3 2179 1 8 2 0 0 92458 46229.0 0.0 46229.0 4 1734 1 37 2 0 0 90054 45027.0 0.0 45027.0 Interpreting this info is the key... The Ticks column is important because that is the total time spent evaluating a given rule. But, if that rule is causing alerts, it makes sense to leave it alone. A high Avg/Check is a poor performing rule, most likely contains PCRE. High Checks and low Avg/Check is usually an ANY->ANY rule with few rule options and no content. Quick to check, the few options may or may not match. We are looking at moving some of these into code... Especially those with low SIDs. By default, this information will be printed to the console when Snort exits. You can use the "filename" option in snort.conf to specify a file where this will be written. If "append" is not specified, a new file will be created each time Snort is run. The filenames will have timestamps appended to them. These files will be found in the logging directory. # Preprocessor Profiling Configuration # # syntax: # config profile_preprocs: print [all | num], sort sort_option, filename file_option [append] # - where num is the number of rules to print # - where sort_option is one of: # checks, avg_ticks, total_ticks # - where file_option is the output filename # - where append dictates that the output will go to the same file each time (optional) # # examples: # # 1) Print all preprocessors, sort by avg_ticks (default configuration # if option is turned on) # config profile_preprocs # # 2) Print the top 10 preprocessors, based on highest average time # config profile_preprocs: print 10, sort avg_ticks # # 3) Print all preprocessors, sorted by number of checks # config profile_preprocs: print all, sort checks # # When printing a specific number of preprocessors all subtasks info # is printed for each layer 0 preprocessor stat. When you use this (see configuration info with example output), snort will print the following table at exit. The column info is: - Number (rank) The number is indented for each layer. Layer 1 preprocessors are listed under their respective caller (and sorted similarly). - Preprocessor Name - Layer - Checks (number of times preprocessor decided to look at a packet, ports matched, app layer header was correct, etc) - Exits (number of corresponding exits -- just to verify code is instrumented correctly, should ALWAYS match Checks, unless an exception was trapped) - CPU Ticks - Avg Ticks per Check - Percent of caller For non layer 0 preprocessors -- i.e., subroutines within preprocessors, this identifies the percent of the caller's ticks that is spent for this subtask. Example, using config profile_preprocs: print 10, sort total_ticks Preprocessor Profile Statistics (worst 10) ========================================================== Num Preprocessor Layer Checks Exits Microsecs Avg/Check Pct of Caller Pct of Total === ============ ===== ====== ===== ========= ========= ============= ============ 1 detect 0 338181 338181 9054573 26.77 64.62 64.62 1 rule eval 1 256978 256978 2570596 10.00 28.39 18.35 1 rule tree eval 2 399860 399860 2520629 6.30 98.06 17.99 1 pcre 3 51328 51328 505636 9.85 20.06 3.61 2 byte_jump 3 6 6 7 1.30 0.00 0.00 3 content 3 1077588 1077588 1123373 1.04 44.57 8.02 4 uricontent 3 106498 106498 79685 0.75 3.16 0.57 5 byte_test 3 9951 9951 5709 0.57 0.23 0.04 6 isdataat 3 8486 8486 3192 0.38 0.13 0.02 7 flowbits 3 135739 135739 35365 0.26 1.40 0.25 8 flags 3 2 2 0 0.20 0.00 0.00 9 preproc_rule_options 3 15499 15499 1939 0.13 0.08 0.01 10 flow 3 394817 394817 36420 0.09 1.44 0.26 11 file_data 3 15957 15957 1264 0.08 0.05 0.01 12 ack 3 4 4 0 0.07 0.00 0.00 2 rtn eval 2 36928 36928 17500 0.47 0.68 0.12 2 mpse 1 646528 646528 5840244 9.03 64.50 41.68 2 s5 0 310080 310080 3270702 10.55 23.34 23.34 1 s5tcp 1 310080 310080 2993020 9.65 91.51 21.36 1 s5TcpState 2 304484 304484 2559085 8.40 85.50 18.26 1 s5TcpFlush 3 22148 22148 70681 3.19 2.76 0.50 1 s5TcpProcessRebuilt 4 22132 22132 2018748 91.21 2856.11 14.41 2 s5TcpBuildPacket 4 22132 22132 34965 1.58 49.47 0.25 2 s5TcpData 3 184186 184186 120794 0.66 4.72 0.86 1 s5TcpPktInsert 4 46249 46249 89299 1.93 73.93 0.64 2 s5TcpNewSess 2 5777 5777 37958 6.57 1.27 0.27 3 httpinspect 0 204751 204751 1814731 8.86 12.95 12.95 4 ssl 0 10780 10780 16283 1.51 0.12 0.12 5 decode 0 312638 312638 437860 1.40 3.12 3.12 6 DceRpcMain 0 155358 155358 186061 1.20 1.33 1.33 1 DceRpcSession 1 155358 155358 156193 1.01 83.95 1.11 7 backorifice 0 77 77 42 0.55 0.00 0.00 8 smtp 0 45197 45197 17126 0.38 0.12 0.12 9 ssh 0 26453 26453 7195 0.27 0.05 0.05 10 dns 0 28 28 5 0.18 0.00 0.00 total total 0 311202 311202 14011946 45.03 0.00 0.00 Because of task swapping, non-instrumented code, and other factors, the Percent of caller field will not add up to 100% of the caller's time. It does give a reasonable indication of how much relative time is spent within each subtask. snort-2.9.6.0/doc/README.pcap_readmode0000644000000000000000000001057211356637671014155 00000000000000Reading pcaps in Snort ====================== Any of the below can be specified multiple times on the command line (-r included) and in addition to other Snort command line options. Note, however, that specifying --pcap-reset and --pcap-show multiple times has the same effect as specifying them once. Command line arguments ---------------------- -r Read a single pcap. --pcap-single= Same as -r. Added for completeness. --pcap-file= File that contains a list of pcaps to read. Can specify path to pcap or directory to recurse to get pcaps. --pcap-list="" A space separated list of pcaps to read. --pcap-dir= A directory to recurse to look for pcaps. Sorted in ascii order. --pcap-filter= Shell style filter to apply when getting pcaps from file or directory. This filter will apply to any --pcap-file or --pcap-dir args following. Use --pcap-no-filter to delete filter for following --pcap-file or --pcap-dir args or specify --pcap-filter again to forget previous filter and to apply to following --pcap-file or --pcap-dir args. --pcap-no-filter Reset to use no filter when getting pcaps from file or directory. --pcap-reset If reading multiple pcaps, reset snort to post-configuration state before reading next pcap. The default, i.e. without this option, is not to reset state. --pcap-show Print a line saying what pcap is currently being read. Examples -------- Read a single pcap: $ snort -r foo.pcap $ snort --pcap-single=foo.pcap Read pcaps from a file: $ cat foo.txt foo1.pcap foo2.pcap /home/foo/pcaps $ snort --pcap-file=foo.txt This will read foo1.pcap, foo2.pcap and all files under /home/foo/pcaps. Note that Snort will not try to determine whether the files under that directory are really pcap files or not. Read pcaps from a command line list: $ snort --pcap-list="foo1.pcap foo2.pcap foo3.pcap" This will read foo1.pcap, foo2.pcap and foo3.pcap Read pcaps under a directory: $ snort --pcap-dir="/home/foo/pcaps" This will include all of the files under /home/foo/pcaps. Using filters: $ cat foo.txt foo1.pcap foo2.pcap /home/foo/pcaps $ snort --pcap-filter="*.pcap" --pcap-file=foo.txt $ snort --pcap-filter="*.pcap" --pcap-dir=/home/foo/pcaps The above will only include files that match the shell pattern "*.pcap", in other words, any file ending in ".pcap". $ snort --pcap-filter="*.pcap --pcap-file=foo.txt \ > --pcap-filter="*.cap" --pcap-dir=/home/foo/pcaps In the above, the first filter "*.pcap" will only be applied to the pcaps in the file "foo.txt" (and any directories that are recursed in that file). The addition of the second filter "*.cap" will cause the first filter to be forgotten and then applied to the directory /home/foo/pcaps, so only files ending in ".cap" will be included from that directory. $ snort --pcap-filter="*.pcap --pcap-file=foo.txt \ > --pcap-no-filter --pcap-dir=/home/foo/pcaps In this example, the first filter will be applied to foo.txt, then no filter will be applied to the files found under /home/foo/pcaps, so all files found under /home/foo/pcaps will be included. $ snort --pcap-filter="*.pcap --pcap-file=foo.txt \ > --pcap-no-filter --pcap-dir=/home/foo/pcaps \ > --pcap-filter="*.cap" --pcap-dir=/home/foo/pcaps2 In this example, the first filter will be applied to foo.txt, then no filter will be applied to the files found under /home/foo/pcaps, so all files found under /home/foo/pcaps will be included, then the filter "*.cap" will be applied to files found under /home/foo/pcaps2. Resetting state: $ snort --pcap-dir=/home/foo/pcaps --pcap-reset The above example will read all of the files under /home/foo/pcaps, but after each pcap is read, Snort will be reset to a post-configuration state, meaning all buffers will be flushed, statistics reset, etc. For each pcap, it will be like Snort is seeing traffic for the first time. Printing the pcap: $ snort --pcap-dir=/home/foo/pcaps --pcap-show The above example will read all of the files under /home/foo/pcaps and will print a line indicating which pcap is currently being read. snort-2.9.6.0/doc/README.normalize0000644000000000000000000001455012260355636013363 00000000000000When operating Snort in inline mode, it is helpful to normalize packets to help minimize the chances of evasion. To enable the normalizer, use the following when configuring Snort: ./configure --enable-normalizer The normalize preprocessor is activated via the conf as outlined below. There are also many new preprocessor and decoder rules to alert on or drop packets with "abnormal" encodings. Note that in the following, fields are cleared only if they are non-zero. Also, normalizations will only be enabled if the selected DAQ supports packet replacement and is operating in inline mode. If a policy is configured for inline_test or passive mode, any normalization statements in the policy config are ignored. IP4 Normalizations ================== IP4 normalizations are enabled with: preprocessor normalize_ip4: [df], [rf], [tos], [trim] Base normalizations enabled with "preprocessor normalize_ip4" include: * TTL normalization if enabled (explained below). * NOP all options octets. Optional normalizations include: * df - don't fragment: clear this bit on incoming packets. * rf - reserved flag: clear this bit on incoming packets. * tos - type of service (differentiated services): clear this byte. * trim - truncate packets with excess payload to the datagram length specified in the IP header + the layer 2 header (e.g. ethernet), but don't truncate below minimum frame length. This is automatically disabled if the DAQ can't inject packets. IP6 Normalizations ================== IP6 normalizations are enabled with: preprocessor normalize_ip6 Base normalizations enabled with "preprocessor normalize_ip6" include: * Hop limit normalization if enabled (explained below). * NOP all options octets in hop-by-hop and destination options extension headers. ICMP4/6 Normalizations ====================== ICMP4 and ICMP6 normalizations are enabled with: preprocessor normalize_icmp4 preprocessor normalize_icmp6 Base normalizations enabled with the above include: * Clear the code field in echo requests and replies. TCP Normalizations ================== TCP normalizations are enabled with: preprocessor normalize_tcp: \ [ips], [urp], [trim], \ [ecn ], \ [opts [allow +]] ::= stream | packet ::= \ sack | echo | partial_order | conn_count | alt_checksum | md5 | ::= { 4, 5 } ::= { 6, 7 } ::= { 9, 10 } ::= { 11, 12, 13 } ::= { 14, 15 } ::= { 19 } ::= (3..255) Base normalizations enabled with "preprocessor normalize_tcp" include: * Clear the reserved bits in the TCP header. * Clear the urgent pointer if the urgent flag is not set. * Clear the urgent pointer and the urgent flag if there is no payload. * Set the urgent pointer to the payload length if it is greater than the payload length. * Clear the urgent flag if the urgent pointer is not set. * Clear any option padding bytes. Optional normalizations include: * ips: ensure consistency in retransmitted data (also forces reassembly policy to "first"). Any segments that can't be properly reassembled will be dropped. * urp - urgent pointer: don't adjust the urgent pointer if it is greater than payload length. * trim: remove data on SYN. * trim: remove any data from RST packet. * trim: trim data to window. * trim: trim data to MSS. * ecn packet: clear ECN flags on a per packet basis (regardless of negotiation). * ecn stream: clear ECN flags if usage wasn't negotiated. Should also enable require_3whs. * opts: NOP all option bytes other than maximum segment size, window scaling, timestamp, and any explicitly allowed with the allow keyword. You can allow options to pass by name or number. * opts: if timestamp is present but invalid, or valid but not negotiated, NOP the timestamp octets. * opts: if timestamp was negotiated but not present, block the packet. * opts: clear TS ECR if ACK flag is not set. * opts: MSS and window scale options are NOP'd if SYN flag is not set. TTL Normalization ================= TTL normalization pertains to both IP4 TTL (time-to-live) and IP6 (hop limit) and is only performed if both the relevant base normalization is enabled (as described above) and the minimum and new TTL values are configured, as follows: config min_ttl: config new_ttl: ::= (1..255) ::= (+1..255) If new_ttl > min_ttl, then if a packet is received with a TTL < min_ttl, the TTL will be set to new_ttl. Note that this configuration item was deprecated in 2.8.6: preprocessor stream5_tcp: min_ttl <#> By default min_ttl = 1 and new_ttl = 0 (TTL normalization is disabled). New Decoder and Preprocessor Rules ================================== 116,424 Eth cap len < hdr len 116,426 ICMP4 Any: len < min ICMP header 116,416 ICMP4 Echo Request: destination is a broadcast address (255.255.255.255/32) 116,415 ICMP4 Echo Request: destination is a multicast address (224.0.0.0/4) 116,417 ICMP4 Source Quench: to prevent DoS 116,418 ICMP4 other: (Other = all not decoded by Snort) 116,427 ICMP6 Any: len < min ICMP header 116,432 ICMP6 Echo request: destination is a multicast address 116,431 ICMP6 other: (Other = all not decoded by Snort) 116,430 IP4 DF set and offset > 0. 116,409 IP4 Dst addr is current network (0.0.0.0/8) 116,412 IP4 Dst addr is unused/reserved (240.0.0.0/4) 116,414 IP4 Dst addr is broadcast address (255.255.255.255/32) 116,407 IP4 offset + len > 64KB. 116,425 IP4 Len < header len. 116,408 IP4 Src addr is current network (0.0.0.0/8) 116,410 IP4 Src addr is multicast address (224.0.0.0/4) 116,413 IP4 Src addr is broadcast address (255.255.255.255/32) 116,411 IP4 Src addr is unused/reserved (240.0.0.0/4) 129,11 TCP: no control flags set on data for established session 129,3 TCP: Data on closed session 129,8 TCP: Data after RST 116,422 TCP: FIN==1 && ACK==0 116,422 TCP: PUSH==1 && ACK==0 129,15 TCP: RST not in window 116,420 TCP: SYN==1 && FIN==1 129,2 TCP: SYN with data 116,421 TCP: SYN==1 && RST==1 116,423 TCP: SYN==0 && ACK==0 && RST==0 129,1 TCP: SYN on established session 116,422 TCP: URG==1 && ACK==0 116,419 TCP: URG==1 && (dsize==0 || urp > dsize) 129,6 TCP: Window Too large normalize_tcp 129,4 TCP TS option: packet fails PAWS test 129,14 TCP TS option: missing but negotiated in SYN snort-2.9.6.0/doc/README.multipleconfigs0000644000000000000000000001412412260355636014564 00000000000000Description: =========== Snort now supports multiple configurations based on VLAN Id or IP subnet within a single instance of Snort. This will allow administrators to specify multiple snort configuration files and bind each configuration to one or more VLANs or subnets rather than running one Snort for each configuration required. Each unique snort configuration file will create a new configuration instance within snort. VLANs/Subnets not bound to any specific configuration will use the default configuration. Each configuration can have different preprocessor settings and detection rules. Creating Multiple Configurations: ================================ Default configuration for snort is specified using the existing -c option. A default configuration binds multiple vlans or networks to non-default configurations, using the following configuration line: config binding: vlan config binding: net config binding: policy_id : Refers to the absolute or relative path to the snort.conf for specific configuration. : Refers to the comma separated list of vlandIds and vlanId ranges. The format for ranges is two vlanId separated by a "-". Spaces are allowed within ranges. Valid vlanId is any number in 0-4095 range. Negative vland Ids and alphanumeric are not supported. : Refers to ip subnets. Subnets can be CIDR blocks for IPV6 or IPv4. A maximum of 512 individual IPv4 or IPv6 addresses or CIDRs can be specified. : Refers to the comma separated list of 16bit policyIds NOTE: Vlan and Subnets can not be used in the same line. Configurations can be applied based on either Vlans or Subnets not both. Configuration Specific Elements: =============================== Config Options: ============== Generally config options defined within the default configuration are global by default i.e. their value applies to all other configurations. The following config options are specific to each configuration. policy_id policy_mode policy_version The following config options are specific to each configuration. If not defined in a configuration, the default values of the option (not the default configuration values) take effect. config checksum_drop config disable_decode_alerts config disable_decode_drops config disable_ipopt_alerts config disable_ipopt_drops config disable_tcpopt_alerts config disable_tcpopt_drops config disable_tcpopt_experimental_alerts config disable_tcpopt_experimental_drops config disable_tcpopt_obsolete_alerts config disable_tcpopt_obsolete_drops config disable_ttcp_alerts config disable_tcpopt_ttcp_alerts config disable_ttcp_drops Rules: ===== Rules are specific to configurations but only some parts of a rule can be customized for performance reasons. If a rule is not specified in a configuration then the rule will never raise an event for the configuration. A rule shares all parts of the rule options, including the general options, payload detection options, non-payload detection options, and post-detection options. Parts of the rule header can be specified differently across configurations, limited to: Source IP address and port Destination IP address and port Action A higher revision of a rule in one configuration will override other revisions of the same rule in other configurations. Variables: ========== Variables defined using "var", "portvar" and "ipvar" are specific to configurations. If the rules in a configuration use variables, those variables must be defined in that configuration. Preprocessors: ============== Preprocessors configurations can be defined within each vlan or subnet specific configuration. Options controlling specific preprocessor memory usage, through specific limit on memory usage or number of instances, are processed only in default policy. The options control total memory usage for a preprocessor across all policies. These options are ignored in non-default policies without raising an error. A preprocessor must be configured in default configuration before it can be configured in non-default configuration. This is required as some mandatory preprocessor configuration options are processed only in default configuration. Events and Output: ================== An unique policy id can be assigned by user, to each configuration using the following config line: config policy_id: : Refers to a 16-bit unsigned value. This policy id will be used to identify alerts from a specific configuration in the unified2 records. NOTE: If no policy id is specified, snort assigns 0 (zero) value to the configuration. To enable vlanId logging in unified2 records the following options can be used. output alert_unified2: vlan_event_types (alert logging only) output unified2: filename , vlan_event_types (true unified logging) : Refers to the absolute or relative filename. vlan_event_types : When this option is set, snort will use unified2 event type 104 and 105 for IPv4 and IPv6 respectively. Events NOTE: Each event logged will have the vlanId from the packet if vlan headers are present otherwise 0 will be used. How Configuration is applied? ============================ Snort assigns every incoming packet to a unique configuration based on the following criteria. If VLANID is present, then the innermost VLANID is used to find bound configuration. If the bound configuration is the default configuration, then destination IP address is searched to the most specific subnet that is bound to a non-default configuration. The packet is assigned non-default configuration if found otherwise the check is repeated using source IP address. In the end, default configuration is used if no other matching configuration is found. For addressed based configuration binding, this can lead to conflicts between configurations if source address is bound to one configuration and destination address is bound to another. In this case, snort will use the first configuration in the order of definition, that can be applied to the packet. snort-2.9.6.0/doc/README.modbus0000644000000000000000000000775511652050543012656 00000000000000Modbus Preprocessor =================== Overview ======== The Modbus preprocessor is a Snort module that decodes the Modbus protocol. It also provides rule options to access certain protocol fields. This allows a user to write rules for Modbus packets without decoding the protocol with a series of "content" and "byte_test" options. Modbus is a protocol used in SCADA networks. If your network does not contain any Modbus-enabled devices, we recommend leaving this preprocessor turned off. Dependencies ============ The Stream5 preprocessor must be enabled for the Modbus preprocessor to work. Protocol-Aware Flushing (PAF) is also required. See README.stream5 for more information. Preprocessor Configuration ========================== Modbus configuration is split into two parts: the preprocessor config, and the rule options. The preprocessor config starts with: preprocesor modbus: Options are as follows: Option Argument Required Default -------------------------------------------------------------- ports , or NO ports 502 { port [port] ... } Option explanations ports This sets the port numbers on which Modbus traffic is inspected. A single port number may be provided, or a space-separated list enclosed in curly brackets. The default is port 502. Example preprocessor config preprocessor modbus: ports { 502 } Rule Options ============ The Modbus preprocessor adds 3 new rule options. These rule options match on various pieces of the Modbus headers. The preprocessor must be enabled for these rule options to work. modbus_func --------- This option matches against the Function Code inside of a Modbus Application-Layer request/response header. The code may be a number (in decimal format), or a string from the list provided below. Syntax: modbus_func: code = 0-255 read_coils read_discrete_inputs read_holding_registers read_input_registers write_single_coil write_single_register read_exception_status diagnostics get_comm_event_counter get_comm_event_log write_multiple_coils write_multiple_registers report_slave_id read_file_record write_file_record mask_write_register read_write_multiple_registers read_fifo_queue encapsulated_interface_transport Example: alert tcp any any -> any 502 (msg:"Modbus Write Coils request"; \ modbus_func:write_multiple_coils; sid:1;) modbus_unit ----------- This rule option matches against the Unit ID field in a Modbus header. Syntax: modbus_unit: unit = 0-255 Example: var MODBUS_ADMIN 192.168.1.2 alert tcp !$MODBUS_ADMIN any -> any 502 (msg:"Modbus command to Unit 01 \ from unauthorized host"; modbus_unit:1; sid:1;) modbus_data --------- This rule option sets the cursor at the beginning of the Data field in a Modbus request/response. Syntax: modbus_data; No options. Example: alert tcp any any -> any any (msg:"String 'badstuff' in Modbus message"; \ modbus_data; content:"badstuff"; sid:1;) Preprocessor Rules ================== The Modbus preprocessor uses GID 144 for its preprocessor events. SID Description -------------------------------------------------------------------- 1 The length in the Modbus header does not match the length needed by the Modbus function code. Each Modbus function has an expected format for requests and responses. If the length of the message does not match the expected format, this alert is generated. 2 Modbus protocol ID is non-zero. The protocol ID field is used for multiplexing other protocols with Modbus. Since the preprocessor cannot handle these other protocols, this alert is generated instead. 3 Reserved Modbus function code in use. snort-2.9.6.0/doc/README.ipv60000644000000000000000000000372712026730050012236 00000000000000IPv6 configuration ================== All configuration options are consistent with past versions of Snort, with the obvious exception that IPv6 addresses can be used in place of IPv4 addresses at will. IP lists are allowed to have IP addresses from both families simultaneously. For example: ipvar example [1.1.1.1,2::2] alert tcp [3::0/120,!3::3,4.4.4.4] any -> $example any (msg:"Example";sid:1;) See README.variables for more information. Miscellaneous - BSD Fragmented IPv6 Vulnerability (CVE-2007-1365) ================================================================= Some versions of BSD are vulnerable to an attack that involves sending two fragmented ICMPV6 packets with specific fragmentation flags (see Bugtraq ID 22901 or CVE-2007-1365). Snort will, by default alert if it sees the both packets in sequence, or the second packet by itself. Snort will keep track of multiple simultaneous IPv6 fragmented ICMPv6 sessions, up to a user-configurable timeout or until a session can be confirmed to be safe. To configure this module's behavior, add a line to snort.conf with: ipv6_frag [, , ...] Options: bsd_icmp_frag_alert [on/off] - Whether or not to alert on the BSD fragmented ICMPv6 vulnerability bad_ipv6_frag_alert [on/off] - Whether or not to alert if the second packet is seen by itself frag_timeout [integer] - Length of time to track the attack in seconds. Min 0, max 3600, default 60 (consistent with BSD's internal default). max_frag_sessions [integer] - Total number of possible attacks to track. Min 0, default 10000. To enable drops in inline mode, use "config enable_decode_drops". snort-2.9.6.0/doc/README.ipip0000644000000000000000000000250510766035100012307 00000000000000IP in IP Tunneling ================== Snort now has the capability of decoding IP in IP encapsulated traffic. Payload and Delivery header support =================================== Proto Delivery Payload ----- -------- ------- IPv4 x x IPv6 x x (only with IPv6 compiled binary) How to enable the decoder ========================= $ ./configure --enable-gre Note on multiple encapsulation ============================== Snort does not support more than one encapsulation and will alert if it sees multiple encapsulations. For example, the following will cause Snort to generate an alert: -------------------------------------- | Eth | IP | IP | IP | TCP | Payload | -------------------------------------- Logging ======= Currently only the encapsulated part of the packet is logged, For example: ----------------------------------- | Eth | IP1 | IP2 | TCP | Payload | ----------------------------------- gets logged as ----------------------------- | Eth | IP2 | TCP | Payload | ----------------------------- Alerts ====== Alerts pertaining to the IP in IP decoder fall under the more general case of decoder alerts, with GID of 116. (More general IP alerts are not mentioned here.) SID Description --- ----------- 161 Alerts if multiple encapsulations are encountered. snort-2.9.6.0/doc/README.imap0000644000000000000000000001674412260355636012320 00000000000000IMAP ==== -- Overview -- IMAP is an IMAP4 decoder for user applications. Given a data buffer, IMAP will decode the buffer and find IMAP4 commands and responses. It will also mark the command, data header data body sections and extract the IMAP4 attachments and decode it appropriately. IMAP will handle stateful processing. It saves state between individual packets. However maintaining correct state is dependent on the reassembly of the server side of the stream (i.e., a loss of coherent stream data results in a loss of state). Stream5 should be turned on for IMAP. Please ensure that the IMAP ports are added to the stream5 ports for proper reassembly. -- Configuration -- The configuration options are described below: * ports { port [port] ... } * This specifies on what ports to check for IMAP data. Typically, this will include 143. Default ports if none are specified are 143 . * disabled * Disables the IMAP preprocessor in a config. This is useful when specifying the decoding depths such as b64_decode_depth, qp_decode_depth, uu_decode_depth, bitenc_decode_depth or the memcap used for decoding in default config without turning on the IMAP preprocessor. * b64_decode_depth * This config option is used to turn off/on or set the base64 decoding depth used to decode the base64 encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the base64 decoding of MIME attachments. The value of 0 sets the decoding of base64 encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of base64 MIME attachments, and applies per attachment. A IMAP preprocessor alert with sid 4 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the base64 encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. It is recommended that user inputs a value that is a multiple of 4. When the value specified is not a multiple of 4, the IMAP preprocessor will round it up to the next multiple of 4. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * qp_decode_depth * This config option is used to turn off/on or set the Quoted-Printable decoding depth used to decode the Quoted-Printable(QP) encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the QP decoding of MIME attachments. The value of 0 sets the decoding of QP encoded MIME attachments to unlimited. A value other than 0 or -1 restricts the decoding of QP MIME attachments, and applies per attachment. A IMAP preprocessor alert with sid 5 is generated (if enabled) when the decoding fails. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the QP encoded MIME attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * bitenc_decode_depth * This config option is used to turn off/on or set the non-encoded MIME extraction depth used to extract the non-encoded MIME attachments. The value ranges from -1 to 65535. A value of -1 turns off the extraction of these MIME attachments. The value of 0 sets the extraction of these MIME attachments to unlimited. A value other than 0 or -1 restricts the extraction of these MIME attachment, and applies per attachments. Multiple MIME attachments/data in one packet are pipelined. When stateful inspection is turned on the non-encoded MIME attachments/data across multiple packets are extracted too. The extracted data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * uu_decode_depth * This config option is used to turn off/on or set the Unix-to-Unix decoding depth used to decode the Unix-to-Unix(UU) encoded attachments. The value ranges from -1 to 65535. A value of -1 turns off the UU decoding of IMAP attachments. The value of 0 sets the decoding of UU encoded IMAP attachments to unlimited. A value other than 0 or -1 restricts the decoding of UU IMAP attachments, and applies per attachment. A IMAP preprocessor alert with sid 7 is generated (if enabled) when the decoding fails. Multiple UU Encoded attachments/data in one packet are pipelined. When stateful inspection is turned on the UU encoded attachments/data across multiple packets are decoded too. The decoded data is available for detection using the rule option file_data. See file_data rule option for more details. In case of multiple configs, the value specified in the non-default config cannot exceed the value specified in the default config. * memcap * This option determines (in bytes) the maximum amount of memory the IMAP preprocessor will use for decoding base64 encoded/quoted-printable/non-encoded MIME attachments/data or Unix-to-Unix encoded attachments. This value can be set from 3276 bytes to 100MB. This option along with the maximum of the decoding depths will determine the IMAP sessions that will be decoded at any given instant. The default value for this option is 838860. Note: It is suggested to set this value such that the max imap session calculated as follows is at least 1. max imap session = memcap /(2 * max of (b64_decode_depth, uu_decode_depth, qp_decode_depth or bitenc_decode_depth)) For example, if b64_decode_depth is 0 (indicates unlimited decoding) and qp_decode_depth is 100, then max imap session = memcap/2*65535 (max value for b64_decode_depth) In case of multiple configs, the memcap of the non-default configs will be overwritten by the default config's value. Hence user needs to define it in the default config with the new keyword disabled (used to disable IMAP preprocessor in a config). When the memcap for decoding (memcap) is exceeded the IMAP preprocessor alert with sid 3 is generated (when enabled). Example: preprocessor imap: \ ports { 143 } \ memcap 1310700 \ qp_decode_depth -1 \ b64_decode_depth 0 \ bitenc_decode_depth 100 preprocessor imap: \ memcap 1310700 \ qp_decode_depth 0 \ disabled Default: preprocessor imap: \ ports { 143 } \ b64_decode_depth 1460 \ qp_decode_depth 1460 \ bitenc_decode_depth 1460 \ uu_decode_depth 1460 Events ================================================================================ The IMAP preprocessor uses GID 141 to register events. SID Description -------------------------------------------------------------------------------- 1 Alert if IMAP encounters an invalid IMAP4 command. 2 Alert if IMAP encounters an invalid IMAP4 response. 3 If the decoding memory cap (memcap) is reached and the preprocessor is configured to alert, this alert will be created. 4 If the decoding of a base64 MIME attachments fails or when the decoding stops due to exceeded b64_decode_depth. 5 If the decoding of a Quoted-Printable MIME attachments fails or when the decoding stops due to exceeded qp_decode_depth. 7 If the decoding of a Unix-to-Unix encoded attachments fails or when the decoding stops due to exceeded uu_decode_depth. snort-2.9.6.0/doc/README.http_inspect0000644000000000000000000013210112260355636014060 00000000000000HttpInspect ----------- Originally authored by Daniel Roelker Updated by members of Snort Team -- Overview -- HttpInspect is a generic HTTP decoder for user applications. Given a data buffer, HttpInspect will decode the buffer, find HTTP fields, and normalize the fields. HttpInspect works on both client requests and server responses. The current version of HTTP Inspect only handles stateless processing. This means that HTTP Inspect looks for HTTP fields on a packet-by-packet basis, and will be fooled if packets are not reassembled. This works fine when there is another module handling the reassembly, but there are limitations in analyzing the protocol. Future versions will have a stateful processing mode which will hook into various reassembly modules. - Configuration -- HttpInspect has a very "rich" user configuration. Users can configure individual HTTP servers with a variety of options, which should allow the user to emulate any type of web server. ** Global Configuration ** The global configuration deals with configuration options that determine the global functioning of HttpInspect. The following example gives the generic global configuration format: preprocessor http_inspect: global [followed by the configuration options] You can only have a single global configuration, you'll get an error if you try otherwise. The global configuration options are described below: * iis_unicode_map [filename (located in the config dir)] [codemap (integer)] * This is the global iis_unicode_map file. THIS ALWAYS NEEDS TO BE SPECIFIED IN THE GLOBAL CONFIGURATION, otherwise you get an error. The Microsoft US unicode codepoint map is located in the snort /etc directory as a default. It is called unicode.map and should be used if no other is available. You can generate your own unicode maps by using the program ms_unicode_generator.c located in the HttpInspect utils directory. Remember that this configuration is for the global IIS unicode map. Individual servers can reference their own IIS unicode map. * detect_anomalous_servers * This global configuration option enables generic HTTP server traffic inspection on non-HTTP configured ports, and alerts if HTTP traffic is seen. DON'T turn this on if you don't have a default server configuration that encompasses all of the HTTP server ports that your users might go to. In the future we want to limit this to particular networks so it's more useful, but for right now this inspects all network traffic. * proxy_alert * This enables global alerting on HTTP server proxy usage. By configuring HttpInspect servers and enabling allow_proxy_use, you will only receive proxy use alerts for web users that aren't using the configured proxies or are using a rogue proxy server. * compress_depth * This option specifies the maximum amount of packet payload to decompress. This value can be set from 1 to 65535. The default for this option is 1460. Please note, in case of multiple policies, the value specified in the default policy is used and this value overwrites the values specified in the other policies. In case of unlimited_decompress this should be set to its max value. This value should be specified in the default policy even when the HTTP inspect preprocessor is turned off using the disabled keyword. * decompress_depth * This option specifies the maximum amount of decompressed data to obtain from the compressed packet payload. This value can be set from 1 to 65535. The default for this option is 2920. Please note, in case of multiple policies, the value specified in the default policy is used and this value overwrites the values specified in the other policies. In case of unlimited_decompress this should be set to its max value. This value should be specified in the default policy even when the HTTP inspect preprocessor is turned off using the disabled keyword. * max_gzip_mem * This option determines (in bytes) the maximum amount of memory the HTTP Inspect preprocessor will use for decompression. The minimum allowed value for this option is 3276 bytes. This option determines the number of concurrent sessions that can be decompressed at any given instant. The default value for this option is 838860. Note: This value should be specified in the default policy even when the HTTP inspect preprocessor is turned off using the disabled keyword. * memcap * This option determines (in bytes) the maximum amount of memory the HTTP Inspect preprocessor will use for logging the URI and Hostname data. This value can be set from 2304 to 603979776 (576 MB). This option along with the maximum uri and hostname logging size (which is defined in snort) will determine the maximum HTTP sessions that will log the URI and hostname data at any given instant. The maximum size for logging URI data is 2048 and for hostname is 256. The default value for this option is 150994944 (144 MB). Note: This value should be specified in the default policy even when the HTTP inspect preprocessor is turned off using the "disabled" keyword. In case of multiple policies, the value specified in the default policy will overwrite the value specified in other policies. max http sessions logged = memcap /( max uri logging size + max hostname logging size ) max uri logging size defined in snort : 2048 max hostname logging size defined in snort : 256 * disabled * This optional keyword is allowed with any policy to avoid packet processing. This option disables the preprocessor. When the preprocessor is disabled only the "memcap", "max_gzip_mem", "compress_depth" and "decompress_depth" options are applied when specified with the configuration. Other options are parsed but not used. Any valid configuration may have "disabled" added to it. Please note that if users aren't required to configure web proxy use, then you may get a lot of proxy alerts. So, please only use this feature with traditional proxy environments. Blind firewall proxies don't count. ** Server Configuration ** This is where the fun stuff begins. There are two types of server configurations: default and [IP]. The default configuration: - preprocessor http_inspect_server: server default [server options] This configuration supplies the default server configuration for any server that is not individually configured. Most of your web servers will most likely end up using this default configuration. Most of the time I would suggest setting your default server to: - preprocessor http_inspect_server: server default profile all ports { [whatever ports you want] } In the case of individual IPs the configuration is very similar: - preprocessor http_inspect_server: server [IP] [server options] Multiple server IPs (and/or networks using CIDR notation) can be specified by using a space separated list of IPs encalosed in braces {}'s: - preprocessor http_inspect_server: server { 10.1.1.1 10.2.2.0/24 } [server options] NOTE: There is a limit of 40 IPs or networks per http_inspect_server line. Now we'll talk about the server options. Some configuration options have an argument of 'yes' or 'no'. This argument specifies whether the user wants the configuration option to generate an alert or not. IMPORTANT: The 'yes/no' argument does not specify whether the configuration option itself is on or off, only the alerting functionality. * profile [all/apache/iis/iis4_0/iis5_0] * Users can configure HttpInspect by using pre-defined HTTP server profiles. Profiles must be specified as the first server option and cannot be combined with any other options except: - ports - iis_unicode_map - allow_proxy_use - server_flow_depth - client_flow_depth - post_depth - no_alerts - inspect_uri_only - oversize_dir_length - normalize_headers - normalize_cookies - normalize_utf - max_header_length - max_headers - max_spaces - enable_cookie - extended_response_inspection - inspect_gzip - normalize_javascript - max_javascript_whitespaces - enable_xff - unlimited_decompress - http_methods - log_uri - log_hostname These options must be specified after the 'profile' option. Example: preprocessor http_inspect_server: server 1.1.1.1 profile all ports { 80 3128 } There are five profiles available: - all: The "all" profile is meant to normalize the URI using most of the common tricks available. We alert on the more serious forms of evasions. This is a great profile for detecting all the types of attacks regardless of the HTTP server. - apache: The "apache" profile is used for apache web servers. This differs from the 'iis' profile by only accepting utf-8 standard unicode encoding and not accepting backslashes as legitimate slashes, like IIS does. Apache also accepts tabs as whitespace - iis: The "iis" profile mimics IIS servers. So that means we use IIS unicode codemaps for each server, %u encoding, bare-byte encoding, backslashes, etc. - iis4_0, iis5_0: In IIS 4.0 and 5.0, there was a double decoding vulnerability. These two profiles are identical to IIS, except they will alert by default if a URL has a double encoding. Double decode is not supported in IIS 5.1 and beyond, so it's disabled in Snort. Profiles are not required by http_inspect. * ports { [port] [port] . . . } * This is how the user configures what ports to decode on the HTTP server. Encrypted traffic (SSL) cannot be decoded, so adding ports 443 will only yield encoding false positives. * iis_unicode_map [file (located in config dir)] [codemap (integer)] * The IIS Unicode Map is generated by the program ms_unicode_generator.c. This program is located in src/preprocessors/HttpInspect/util. Executing this program generates a unicode map for the system that it was run on. So to get the specific unicode mappings for an IIS web server, you run this program on that server and use that unicode map in this configuration. When using this option, the user needs to specify the file that contains the IIS unicode map and also specify the unicode map to use. For US servers, this is usually 1252. But the ms_unicode_generator program tells you which codemap to use for you server, it's the ANSI codepage. You can select the correct code page by looking at the available code pages that the ms_unicode_generator outputs. * extended_response_inspection * This enables the extended HTTP response inspection. The default http response inspection does not inspect the various fields of a HTTP response. By turning this option the HTTP response will be thoroughly inspected. The different fields of a HTTP response such as status code, status message, headers, cookie (when enable_cookie is configured) and body are extracted and saved into buffers. Different rule options are provided to inspect these buffers. When this option is turned on, if the HTTP response packet has a body then any content pattern matches ( without http modifiers ) will search the response body (decompressed in case of gzip) and not the entire packet payload. To search for patterns in the header of the response, one should use the http modifiers with content such as http_header, http_stat_code, http_stat_msg and http_cookie. * enable_cookie * This options turns on the cookie extraction from HTTP requests and HTTP response. By default the cookie inspection and extraction will be turned off. The cookie from the "Cookie" header line is extracted and stored in HTTP Cookie buffer for HTTP requests and cookie from the "Set-Cookie" is extracted and stored in HTTP Cookie buffer for HTTP responses. The "Cookie:" and "Set-Cookie:" header names itself along with the leading spaces and the CRLF terminating the header line are stored in the HTTP header buffer and are not stored in the HTTP cookie buffer. Ex: Set-Cookie: mycookie \r\n In this case, Set-Cookie: \r\n will be in the HTTP header buffer and the pattern mycookie will be in the HTTP cookie buffer. * inspect_gzip * This option specifies the HTTP inspect module to uncompress the compressed data(gzip/deflate) in HTTP response. You should select the config option "extended_response_inspection" before configuring this option. Snort should be configured with --enable-zlib for this option to work as expected. Decompression is done across packets. So the decompression will end when either the 'compress_depth' or 'decompress_depth' is reached or when the compressed data ends. When the compressed data is spanned across multiple packets, the state of the last decompressed packet is used to decompressed the data of the next packet. But the decompressed data are individually inspected. (i.e. the decompressed data from different packets are not combined while inspecting). Also the amount of decompressed data that will be inspected depends on the server_flow_depth configured. Http Inspect generates a preprocessor alert with gid 120 and sid 6 when the decompression fails. When the decompression fails due to a CRC error encountered by zlib, HTTP Inspect will also provide the detection module with the data that was decompressed by zlib. * unlimited_decompress * This option enables the user to decompress unlimited gzip data (across multiple packets).Decompression will stop when the compressed data ends or when a out of sequence packet is received. To ensure unlimited decompression, user should set the 'compress_depth' and 'decompress_depth' to its maximum values in the default policy. The decompression in a single packet is still limited by the 'compress_depth' and 'decompress_depth'. * normalize_javascript * This option enables the normalization of Javascript within the HTTP response body. You should select the config option "extended_response_inspection" before configuring this option. When this option is turned on, Http Inspect searches for a Javascript within the HTTP response body by searching for the The above javascript will generate the preprocessor alert with SID 9 and GIDF 120 when normalize_javascript is turned on. Http Inspect will also generate a preprocessor alert with GID 120 and SID 11 when there are more than one type of encodings within the escaped/encoded data. For example: unescape("%48\x65%6C%6C%6F%2C%20%73%6E%6F%72%74%20%74%65%61%6D%21"); String.fromCharCode(0x48, 0x65, 0x6c, 0x6c, 111, 44, 32, 115, 110, 111, 114, 116, 32, 116, 101, 97, 109, 33) The above obfuscation will generate the preprocessor alert with GID 120 and SID 11. This option is turned off by default in HTTP Inspect. * max_javascript_whitespaces [positive integer] * This option takes an integer as an argument. The integer determines the maximum number of consecutive whitespaces allowed within the Javascript obfuscated data in a HTTP response body. The config option "normalize_javascript" should be turned on before configuring this config option. When the whitespaces in the javascript obfuscated data is equal to or more than this value a preprocessor alert with GID 120 and SID 10 is generated. The default value for this option is 200. To enable, specify an integer argument to max_spaces of 1 to 65535. Specifying a value of 0 is treated as disabling the alert. * enable_xff * This option enables Snort to parse and log the original client IP present in the X-Forwarded-For or True-Client-IP HTTP request headers along with the generated events. The XFF/True-Client-IP Original client IP address is logged only with unified2 output and is not logged with console (-A cmg) output. NOTE: The original client IP from XFF/True-Client-IP in unified2 logs can be viewed using the tool u2spewfoo. This tool is present in the tools/u2spewfoo directory of snort source tree. * server_flow_depth [integer] * * flow_depth [integer] * (to be deprecated) This specifies the amount of server response payload to inspect. When extended_response_inspection is turned on, it is applied to the HTTP response body (decompressed data when inspect_gzip is turned on) and not the HTTP headers. When extended_response_inspection is turned off the server_flow_depth is applied to the entire HTTP response (including headers). Unlike client_flow_depth this option is applied per TCP session. This option can be used to balance the needs of IDS performance and level of inspection of HTTP server response data. Snort rules are targeted at HTTP server response traffic and when used with a small flow_depth value may cause false negatives. Most of these rules target either the HTTP header, or the content that is likely to be in the first hundred or so bytes of non-header data. Headers are usually under 300 bytes long, but your mileage may vary. It is suggested to set the server_flow_depth to its maximum value. This value can be set from -1 to 65535. A value of -1 causes Snort to ignore all server side traffic for ports defined in "ports" when extended_response_inspection is turned off. When the extended_response_inspection is turned on, value of -1 causes Snort to ignore the HTTP response body data and not the HTTP headers. Inversely, a value of 0 causes Snort to inspect all HTTP server payloads defined in "ports" (note that this will likely slow down IDS performance). Values above 0 tell Snort the number of bytes to inspect of the server response (excluding the HTTP headers when extended_response_inspection is turned on) in a given HTTP session. Only packets payloads starting with 'HTTP' will be considered as the first packet of a server response. If less than flow_depth bytes are in the payload of the HTTP response packets in a given session, the entire payload will be inspected. If more than flow_depth bytes are in the payload of the HTTP response packet in a session only flow_depth bytes of the payload will be inspected for that session. Rules that are meant to inspect data in the payload of the HTTP response packets in a session beyond 65535 bytes will be ineffective unless flow_depth is set to 0. The default value for server_flow_depth is 300. Note that the 65535 byte maximum flow_depth applies to stream reassembled packets as well. It is suggested to set the server_flow_depth to its maximum value. * client_flow_depth [integer] * This specifies the amount of raw client request payload to inspect. This value can be set from -1 to 1460. Unlike server_flow_depth this value is applied to the first packet of the HTTP request. It is not a session based flow depth. It has a default value of 300. It primarily eliminates Snort from inspecting larger HTTP Cookies that appear at the end of many client request Headers. A value of -1 causes Snort to ignore all client side traffic for ports defined in "ports." Inversely, a value of 0 causes Snort to inspect all HTTP client side traffic defined in "ports" (note that this will likely slow down IDS performance). Values above 0 tell Snort the number of bytes to inspect in the first packet of the client request. If less than flow_depth bytes are in the TCP payload (HTTP request) of the first packet, the entire payload will be inspected. If more than flow_depth bytes are in the payload of the first packet only flow_depth bytes of the payload will be inspected. Rules that are meant to inspect data in the payload of the first packet of a client request beyond 1460 bytes will be ineffective unless flow_depth is set to 0. Note that the 1460 byte maximum flow_depth applies to stream reassembled packets as well. It is suggested to set the client_flow_depth to its maximum value. * post_depth [integer] * This specifies the amount of data to inspect in a client post message. The value can be set from -1 to 65495. The default value is -1. A value of -1 causes Snort to ignore all the data in the post message. Inversely, a value of 0 causes Snort to inspect all the client post message. This increases the performance by inspecting only specified bytes in the post message. * ascii [yes/no] * The ASCII decode option tells us whether to decode encoded ASCII chars, a.k.a %2f = /, %2e = ., etc. I suggest you don't log alerts for ASCII since it is very common to see normal ASCII encoding usage in URLs. * extended_ascii_uri * This option enables the support for extended ascii codes in the HTTP request URI. This option is turned off by default and is not supported with any of the profiles. * utf_8 [yes/no] * The UTF-8 decode option tells us to decode standard UTF-8 unicode sequences that are in the URI. This abides by the unicode standard and only uses % encoding. Apache uses this standard, so for any apache servers, make sure you have this option turned on. As for alerting, you may be interested in knowing when you have an utf-8 encoded URI, but this will be prone to false positives as legitimate web clients use this type of encoding. When utf_8 is enabled, ascii decoding is also enabled to enforce correct functioning. * u_encode [yes/no] * This option emulates the IIS %u encoding scheme. How the %u encoding scheme works is as follows: The encoding scheme is started by a %u followed by 4 chars, like %uXXXX. The XXXX is a hex encoded value that correlates to an IIS unicode codepoint. This value can most definitely be ASCII. An ASCII char is encoded like, %u002f = /, %u002e = ., etc. If no iis_unicode_map is specified before or after this option, the default codemap is used. You should alert on %u encodings, because I'm not aware of any legitimate clients that use this encoding. So it is most likely someone trying to be covert. * bare_byte [yes/no] * Bare byte encoding is an IIS trick that uses non-ASCII chars as valid values in decoding UTF-8 values. This is NOT in the HTTP standard, as all non-ASCII values have to be encoded with a %. Bare byte encoding allows the user to emulate an IIS server and interpret non-standard encodings correctly. The alert on this decoding should be enabled, because there are no legitimate clients that encoded UTF-8 this way, since it is non-standard. * iis_unicode [yes/no] * The iis_unicode option turns on the unicode codepoint mapping. If there is no iis_unicode_map option specified with the server config, iis_unicode uses the default codemap. The iis_unicode option handles the mapping of non-ascii codepoints that the IIS server accepts and decodes normal UTF-8 request. Users should alert on the iis_unicode option, because it is seen mainly in attacks and evasion attempts. When iis_unicode is enabled, so is ascii and utf-8 decoding to enforce correct decoding. To alert on utf-8 decoding, the user must enable also enable 'utf_8 yes'. * double_decode [yes/no] * The double_decode option is specific to IIS 4.0 and 5.0. The versions of IIS do two passes through the request URI, doing decodes in each one. In the first pass, it seems that all types of IIS encoding is done: UTF-8 unicode, ASCII, bare byte, and %u. In the second pass the following encodings are done: ASCII, bare byte, and %u. We leave out UTF-8 because I think how this works is that the % encoded UTF-8 is decoded to the unicode byte in the first pass, and then UTF-8 decoded in the second stage. Anyway, this is really complex and adds tons of different encodings for one char. When double_decode is enabled, so is ascii to enforce correct decoding. * non_rfc_char { [byte] [0x00] . . . } * This option lets users receive an alert if certain non-RFC chars are used in a request URI. For instance, a user may not want to see NULL bytes in the request-URI and we can give an alert on that. Please use this option with care, because you could configure it to say, alert on all '/' or something like that. It's flexible, so be careful. * multi_slash [yes/no] * This option normalizes multiple slashes in a row, so something like: "foo/////////bar" get normalized to "foo/bar". If you want an alert when multiple slashes are seen, then configure with a yes, otherwise a no. * iis_backslash [yes/no] * Normalize backslashes to slashes. This is again an IIS emulation. So a request-URI of "/foo\bar" gets normalized to "/foo/bar". * directory [yes/no] * This option normalizes directory traversals and self-referential directories. So, "/foo/this_is_not_a_real_dir/../bar" get normalized to "/foo/bar". Also, "/foo/./bar" gets normalized to "/foo/bar". If a user wants to configure an alert, then specify "yes", otherwise "no". This alert may give false positives since some web sites refer to files using directory traversals. * apache_whitespace [yes/no] * This option deals with non-RFC standard of tab or carriage return for a space delimiter. Apache accepts this, so if the emulated web server is Apache you need to enable this option. Alerts on this option may be interesting, but may also be false positive prone. * iis_delimiter [yes/no] * I originally started out with \n being IIS specific, but Apache takes this non-standard delimiter was well. Since this is common, we always take this as standard since the most popular web servers accept it. But you can still get an alert on this option. * chunk_length [non-zero positive integer] * This option is an anomaly detector for abnormally large chunk sizes. This picks up the apache chunk encoding exploits, and may also alert on HTTP tunneling that uses chunk encoding. * small_chunk_length { } * This option is an evasion detector for consecutive small chunk sizes when either the client or server use Transfer-Encoding: chunked. specifies the maximum chunk size for which a chunk will be considered small. specifies the number of consecutive small chunks <= before an event will be generated. This option is turned off by default. Maximum values for each are 255 and a of 0 disables. Events generated are gid:119,sid:27 for client small chunks and gid:120,sid:7 for server small chunks. Example: small_chunk_length { 10 5 } Meaning alert if we see 5 consecutive chunk sizes of 10 or less. * no_pipeline_req * This option turns HTTP pipeline decoding off, and is a performance enhancement if needed. By default pipeline requests are inspected for attacks, but when this option is enabled, pipeline requests are not decoded and analyzed per HTTP protocol field. It is only inspected with the generic pattern matching. * non_strict * This option turns on non-strict URI parsing for the broken way in which Apache servers will decode a URI. Only use this option on servers that will accept URIs like this "GET /index.html alsjdfk alsj lj aj la jsj s\n". The non_strict option assumes the URI is between the first and second space even if there is no valid HTTP identifier after the second space. * allow_proxy_use * By specifying this keyword, the user is allowing proxy use on this server. This means that no alert will be generated if the proxy_alert global keyword has been used. If the proxy_alert keyword is not enabled, then this option does nothing. The allow_proxy_use keyword is just a way to suppress unauthorized proxy use for an authorized server. * no_alerts * This option turns off all alerts that are generated by the HttpInspect preprocessor module. This has no effect on http rules in the ruleset. No argument is specified. * oversize_dir_length [non-zero positive integer] * This option takes a non-zero positive integer as an argument. The argument specifies the max char directory length for URL directory. If a URL directory is larger than this argument size, an alert is generated. A good argument value is 300 chars. This should limit the alerts to IDS evasion type attacks, like whisker -I 4. * inspect_uri_only * This is a performance optimization. When enabled, only the URI portion of HTTP requests will be inspected for attacks. As this field usually contains 90-95% of the web attacks, you'll catch most of the attacks. So if you need extra performance, then enable this optimization. It's important to note that if this option is used without any uricontent rules, then no inspection will take place. This is obvious since the uri is only inspected with uricontent rules, and if there are none available then there is nothing to inspect. For example, if we have the following rule set: alert tcp any any -> any 80 ( msg:"content"; content: "foo"; ) and then we inspect the following URI: GET /foo.htm HTTP/1.0\r\n\r\n No alert will be generated when 'inspect_uri_only' is enabled. The 'inspect_uri_only' configuration turns off all forms of detection except uricontent inspection. * max_header_length [positive integer] * This option takes an integer as an argument. The integer is the maximum length allowed for an HTTP client request header field. Requests that exceed this length will cause a "Long Header" alert. This alert is off by default. To enable, specify an integer argument to max_header_length of 1 to 65535. Specifying a value of 0 is treated as disabling the alert. * max_spaces [positive integer] * This option takes an integer as an argument. The integer determines the maximum number of whitespaces allowed with HTTP client request line folding. Requests headers folded with whitespaces equal to or more than this value will cause a "Space Saturation" alert with SID 26 and GID 119. The default value for this option is 200. To enable, specify an integer argument to max_spaces of 1 to 65535. Specifying a value of 0 is treated as disabling the alert. * webroot * This option generates an alert when a directory traversal traverses past the web server root directory. This generates much less false positives than the directory option, because it doesn't alert on directory traversals that stay within the web server directory structure. It only alerts when the directory traversals go past the web server root directory, which is associated with certain web attacks. * tab_uri_delimiter * Both Apache and newer versions of IIS accept tabs as delimiters. However, this option is deprecated and has been replaced by, and is enabled by default with, the whitespace_chars option. For more details on its use, see the whitespace_chars section above. * normalize_headers * This option turns on normalization for HTTP Header Fields, not including Cookies (using the same configuration parameters as the URI normalization (i.e., multi-slash, directory, etc.). It is useful for normalizing Referrer URIs that may appear in the HTTP Header. * normalize_cookies * This option turns on normalization for HTTP Cookie Fields (using the same configuration parameters as the URI normalization (i.e., multi-slash, directory, etc.). It is useful for normalizing data in HTTP Cookies that may be encoded. * normalize_utf * This option turns on normalization of HTTP response bodies where the Content-Type header lists the character set as "utf-16le", "utf-16be", "utf-32le", or "utf-32be". HTTP Inspect will attempt to normalize these back into 8-bit encoding, generating an alert if the extra bytes are non-zero. * max_headers [positive integer] * This option takes an integer as an argument. The integer is the maximum number of HTTP client request header fields. Requests that contain more HTTP Headers than this value will cause a "Max Header" alert. The alert is off by default. To enable, specify an integer argument to max_headers of 1 to 1024. Specifying a value of 0 is treated as disabling the alert. *http_methods { } * This specifies additional HTTP Request Methods outside of those checked by default within the preprocessor (GET and POST). The list should be enclosed within braces and delimited by spaces or \t\n\r. The config option, braces and methods also needs to be separated by braces. Example : http_methods { PUT CONNECT } Please note the maximum length for a method name is 256. * log_uri * This option enables HTTP Inspect preprocessor to parse the URI data from the HTTP request and log it along with all the generated events for that session. Stream5 reassembly needs to be turned on HTTP ports to enable the logging. If there are multiple HTTP requests in the session, the URI data of the most recent HTTP request during the alert will be logged. The maximum URI logged is 2048. Please note, this is logged only with the unified2 output and is not logged with console output (-A cmg). u2spewfoo can be used to read this data from the unified2. * log_hostname * This option enables HTTP Inspect preprocessor to parse the hostname data from the "Host" header of the HTTP request and log it along with all the generated events for that session. Stream5 reassembly needs to be turned on HTTP ports to enable the logging. If there are multiple HTTP requests in the session, the Hostname data of the most recent HTTP request during the alert will be logged. In case of multiple "Host" headers within one HTTP request, a preprocessor alert with sid 24 is generated. The maximum hostname length logged is 256. Please note, this is logged only with the unified2 output and is not logged with console output (-A cmg). u2spewfoo can be used to read this data from the unified2. -- Profile Breakout -- There are three profiles that users can select. Only the configuration that are listed under the profiles are turned on. If there is no mention of alert on or off, then that means there is no alert associated with the configuration. * Apache * server_flow_depth 300 non_strict URL parsing is set chunk encoding (alert on chunks larger than 500000 bytes) ascii decoding is on (alert off) multiple slash (alert off) directory normalization (alert off) webroot (alert on) apache whitespace (alert off) utf_8 encoding (alert off) max_header_length 0 (header length not checked) max_headers 0 (number of headers not checked) max_sapces 200 (number of allowed white spaces) * IIS * server_flow_depth 300 non_strict URL parsing is set chunk encoding (alert on chunks larger than 500000 bytes) iis_unicode_map is set to the codepoint map in the global configuration ascii decoding (alert off) multiple slash (alert off) directory normalization (alert off) webroot (alert on) %u decoding (alert on) bare byte decoding (alert on) iis unicode codepoints (alert on) iis backslash (alert off) iis delimiter (alert off) apache whitespace (alert off) max_header_length 0 (header length not checked) max_headers 0 (number of headers not checked) * IIS4_0 and IIS5_0 * server_flow_depth 300 non_strict URL parsing is set chunk encoding (alert on chunks larger than 500000 bytes) iis_unicode_map is set to the codepoint map in the global configuration ascii decoding (alert off) multiple slash (alert off) directory normalization (alert off) webroot (alert on) double decoding (alert on) %u decoding (alert on) bare byte decoding (alert on) iis unicode codepoints (alert on) iis backslash (alert off) iis delimiter (alert off) apache whitespace (alert off) max_header_length 0 (header length not checked) max_headers 0 (number of headers not checked) * All * server_flow_depth 300 non_strict URL parsing is set chunk encoding (alert on chunks larger than 500000 bytes) iis_unicode_map is set to the codepoint map in the global configuration ascii decoding is on (alert off) multiple slash (alert off) directory normalization (alert off) apache whitespace (alert off) double decoding (alert on) %u decoding (alert on) bare byte decoding (alert on) iis unicode codepoints (alert on) iis backslash (alert off) iis delimiter (alert off) webroot (alert on) max_header_length 0 (header length not checked) max_headers 0 (number of headers not checked) The following lists the defaults: Port 80 server_flow_depth 300 client_flow_depth 300 post_depth -1 non_strict URL parsing is set chunk encoding (alert on chunks larger than 500000 bytes) ascii decoding is on (alert off) utf_8 encoding (alert off) multiple slash (alert off) directory normalization (alert off) webroot (alert on) apache whitespace (alert off) iis delimiter (alert off) max_header_length 0 (header length not checked) max_headers 0 (number of headers not checked) -- Pattern Match with HTTP buffers -- -- Writing uricontent rules -- The uricontent parameter in the snort rule language searches the NORMALIZED request URI field. This means that if you are writing rules that include things that are normalized, such as %2f or directory traversals, these rules will not alert. The reason is that the things you are looking for are normalized out of the URI buffer. For example, the URI: /scripts/..%c0%af../winnt/system32/cmd.exe?/c+ver will get normalized into: /winnt/system32/cmd.exe?/c+ver Another example, /cgi-bin/aaaaaaaaaaaaaaaaaaaaaaaaaa/..%252fp%68f? into: /cgi-bin/phf? So when you are writing a uricontent rule, you should write the content that you want to find in the context that the URI will be normalized. Don't include directory traversals (if you normalize directories) and don't look for encode characters. You can accomplish this type of detection by using the 'content' rule parameter, since this rule inspects the unnormalized buffer. -- Http Content Match Keywords -- * http_client_body * The http_client_body keyword is a content modifier that restricts the search to the body of an HTTP client request. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_client_body' is specified. The amount of data that is inspected with this option depends on the post_depth config option of HttpInspect. Pattern matches with this keyword wont work when post_depth is set to -1. * http_cookie * The http_cookie keyword is a content modifier that restricts the search to the extracted Cookie Header field (excluding the header name itself and the CRLF terminating the header line) of a HTTP client request or a HTTP server response. The Cookie buffer does not include the header names ("Cookie:" for HTTP requests or "Set-Cookie:" for HTTP responses) or leading spaces and the CRLF terminating the header line. These are included in the HTTP header buffer. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_cookie' is specified. This keyword is dependent on the 'enable_cookie' config option. The Cookie Header field will be extracted only when this option is configured. If enable_cookie is not specified, the cookie still ends up in HTTP header. When enable_cookie is not specified, using http_cookie is the same as using http_header. The extracted Cookie Header field will be NORMALIZED if the normalize_cookies is configured with HttpInspect. * http_raw_cookie * The http_raw_cookie keyword is a content modifier that restricts the search to the extracted UNNORMALIZED Cookie Header field of a HTTP client request or a HTTP server response. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_raw_cookie' is specified. This keyword is dependent on the 'enable_cookie' config option. The Cookie Header field will be extracted only when this option is configured. * http_header * The http_header keyword is a content modifier that restricts the search to the extracted Header fields of a HTTP client request or a HTTP server response. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_header' is specified. The extracted Header fields will be NORMALIZED if the normalize_cookies is configured with HttpInspect. * http_raw_header * The http_raw_header keyword is a content modifier that restricts the search to the extracted UNNORMALIZED Header fields of a HTTP client request or a HTTP server response. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_raw_header' is specified. * http_method * The http_method keyword is a content modifier that restricts the search to the extracted Method from a HTTP client request. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_method' is specified. * http_uri * The http_uri keyword is a content modifier that restricts the search to the NORMALIZED request URI field . Using a content rule option followed by a http_uri modifier is the same as using a uricontent by itself. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_uri' is specified. * http_raw_uri * The http_raw_uri keyword is a content modifier that restricts the search to the UNNORMALIZED request URI field . As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_raw_uri' is specified. * http_stat_code * The http_stat_code keyword is a content modifier that restricts the search to the extracted Status code field from a HTTP server response. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_stat_code' is specified. The Status Code field will be extracted only if the extended_response_inspection is configured for the HttpInspect. * http_stat_msg * The http_stat_msg keyword is a content modifier that restricts the search to the extracted Status Message field from a HTTP server response. As this keyword is a modifier to the previous 'content' keyword, there must be a content in the rule before 'http_stat_msg' is specified. The Status Message field will be extracted only if the extended_response_inspection is configured for the HttpInspect. * http_encode * The http_encode keyword will enable alerting based on encoding type present in a HTTP client request or a HTTP server response. There are several keywords associated with http_encode. The keywords 'uri', 'header' and 'cookie' determine the HTTP fields used to search for a particular encoding type. The keywords 'utf8', 'double_encode', 'non_ascii', 'uencode', 'ascii', 'iis_encode' and 'bare_byte' determine the encoding type which would trigger the alert. These keywords can be combined using a OR operation. Negation is allowed on these keywords. The config option 'normalize_headers' needs to be turned on for rules to work with keyword 'header'. The keyword 'cookie' is depedent on config options 'enable_cookie' and 'normalize_cookies' This rule option will not be able to detect encodings if the specified HTTP fields are not NORMALIZED. -- Conclusion -- My suggestions are to stick with the "profile" options, since they are much easier to read and have been researched. If you feel like giving us profiles for other web servers, please do. We'll incorporate them into the default server profiles for HttpInspect. Alerts ====== HTTP Inspect used generator ID 119 and 120. HTTP Inspect can generate the following alerts under generator ID 119: SID Description --- ----------- 1 ASCII encoding 2 Double decoding attack 3 U encoding 4 Bare byte Unicode encoding 5 Base36 encoding # Deprecated in Snort 2.9.1 6 UTF-8 encoding 7 IIS Unicode codepoint encoding 8 multi-slash encoding 9 IIS backslash evasion 10 self-directory traversal 11 directory traversal 12 Apache whitespace (tab) 13 Non-RFC HTTP delimiter 14 Non-RFC defined char 15 Oversize request-URI directory 16 Oversize chunk encoding 17 Unauthorized proxy use detected 18 Webroot directory traversal 19 Long header 20 Max headers 21 Multiple Content-Length headers 22 Chunk size mismatch 23 Invalid True-IP/XFF Orginal Client IP 24 Multiple Host headers 25 Hostname exceeds 255 characters 27 Chunked encoding - excessive consecutive small chunks 28 Unbounded POST (without Content-Length or Transfer-Encoding: chunked) 29 multiple true IPs in a session 30 both true_client_ip and XFF hdrs present 31 unknown method 32 simple request (HTTP/0.9) The following alert is generated with generator ID 120: SID Description --- ----------- 1 Anomalous HTTP server on undefined HTTP port 2 Invalid HTTP response status code 3 No Content-Length or Transfer-Encoding in HTTP response 4 UTF Normalization failure 5 HTTP response has UTF-7 charset 6 HTTP response gzip decompression failed 7 Chunked encoding - excessive consecutive small chunks 8 Invalid Content-Length or chunk size in request or response 9 Javascript obfuscation levels exceeds 1 10 Javascript consecutive whitespaces exceeds max allowed 11 Multiple encodings within Javascript obfuscated data 12 Too many pipelined requests snort-2.9.6.0/doc/README.ha0000644000000000000000000001134212243745447011753 00000000000000Stream5 High Availability (HA) ------------------------------ Michael Altizer Documentation last updated 2013-11-21 ########################################## # THIS CODE IS STILL EXPERIMENTAL! # DO NOT USE IN PRODUCTION ENVIRONMENTS. # Please send any issues to the Snort team ########################################## == Overview == Starting in Snort 2.9.5, there is limited support for sharing of session state for the purposes of high availability. Currently, it supports sharing the following state from Stream5 lightweight sessions: * The Session Key * Session Flags * IP Protocol (requires TARGET_BASED) * Application Protocol (requires TARGET_BASED) * Direction * Ignore Direction There are two types of Stream5 HA messages: updates and deletions. Both types use a serialized session key to describe the target session. In the case of a deletion message being received, there is no additional data and the target session will deleted from the session cache if it is present. Update messages, on the other hand, may contain a number of data records, including the non-key HA state enumerated above. If the session to be updated was not present in the cache, it will be created, otherwise it will be updated. In either case, the session will be placed into "HA standby" mode, indicating that the current Snort instance is not the owner of the session. Sessions remain in "HA standby" mode until Snort receives a packet on them and will not time out normally, although they will be pruned as normal when a cache is being overrun. An HA update message will be generated when a session is marked as requiring synchronization (the criteria for which differ per session type) and the time is appropriate based on the configuration. The two configurable time constraints are Minimum Session Lifetime and Minimum Synchronization Interval. In general, no HA update messages will be sent for a session prior to the Minimum Session Lifetime having elapsed, and update messages on a given session will not be sent more often than once per Minimum Synchronization Interval. Certain critical changes to a session will result in these time constraints being ignored. A configured value of 0 for either time constraint will also effectively result in it being ignored. == Extensibility == There is a framework for preprocessors to register to generate and consume HA data records built into the current implementation. In order to register, a preprocessor must call RegisterStreamHAFuncs() with a preprocessor ID, a subcode unique to that preprocessor, the maximum size of its data record, and pointers to the functions for producing and consuming its own data records. Multiple different data records may be generated and consumed by a preprocessor simply by registering additional functions with a different subcode. The return value from RegisterStreamHAFuncs() is a bit index that must be passed in to Stream5SetHAPendingBit() to indicate that a session has changed and that an update message should be generated. NOTE: The current implementation is limited to a maximum of 8 such data records being registered across all preprocessors. (Determined by the width of ha_pending_mask in the Stream5LWSession structure.) == Configuration == In order to utilize the functionality, Snort must be configured and compiled with --enable-ha. In order to enable Stream5 HA, the 'enable_ha' option must be given to the 'stream5_global' directive. There is a new preprocessor 'stream5_ha' configuration directive which accepts the following options: * min_session_lifetime - The number of milliseconds a session must have lived before it will generate HA update messages. It must be an integer between 0 and 65535. Default: 0. * min_sync_interval - The number of milliseconds since the last update message was generated before a session will generate another. It must be an integer between 0 and 65535. Default: 0. * startup_input_file - The name of a file for Snort to read HA messages from at startup to prime the session caches with saved state. * runtime_output_file - The name of a file to which Snort will write all HA messages that are generated while it is running. * use_side_channel - Indicates that all HA messages should also be sent to the side channel for processing. No value. NOTE: Requires that Snort has been compiled with the Side Channel feature and it has been enabled. == Example/Default Configuration == preprocessor stream5_global: track_udp yes, track_tcp yes, enable_ha preprocessor stream5_ha: min_session_lifetime 1000, min_sync_interval 100, startup_input_file ha.in, runtime_output_file ha.out, use_side_channel snort-2.9.6.0/doc/README.GTP0000644000000000000000000007364412260355636012026 00000000000000GTP Decoder and Preprocessor ================================================================================ Hui Cao Overview ================================================================================ GTP (GPRS Tunneling Protocol) is used in core communication networks to establish a channel between GSNs (GPRS Serving Node). GTP decoding & preprocessor provides ways to tackle intrusion attempts to those networks through GTP. It also makes detecting new attacks easier. Two components are developed: GTP decoder and GTP preprocessor. GTP decoder extracts payload inside GTP PDU; GTP preprocessor inspects all the signaling messages and provide keywords for further inspection When the decoder is enabled and configured, the decoder strips the GTP headers and parses the underlying IP/TCP/UDP encapsulated packets. Therefore all rules and detection work as if there was no GTP header. Example: Most GTP packets look like this IP -> UDP -> GTP -> IP -> TCP -> HTTP If you had a standard HTTP rule "alert tcp any any -> any $HTTP_PORTS (msg: "Test HTTP"; flow:to_server,established; content:"SOMETHINGEVIL"; http_uri; .... sid:X; rev:Y;)", it would alert on the inner HTTP data that is encapsulated in GTP without any changes to the rule other than enabling and configuring the GTP decoder. Sections: Dependency Requirements GTP Data Channel Decoder Configuration GTP Control Channel Preprocessor Configuration GTP Decoder Events GTP Preprocessor Events Rule Options Dependency Requirements ================================================================================ For proper functioning of the preprocessor: Stream session tracking must be enabled, i.e. stream5. UDP must be enabled in stream5. The preprocessor requires a session tracker to keep its data. IP defragmentation should be enabled, i.e. the frag3 preprocessor should be enabled and configured. GTP Data Channel Decoder Configuration ================================================================================ GTP decoder extracts payload from GTP PDU. The following configuration sets GTP decoding: config enable_gtp By default, GTP decoder uses port number 2152 (GTPv1) and 3386 (GTPv0). If users want to change those values, they can use portvar GTP_PORTS: portvar GTP_PORTS [2152,3386] GTP Control Channel Preprocessor Configuration ================================================================================ Different from GTP decoder, GTP preprocessor examines all signaling messages. The preprocessor configuration name is "gtp". preprocessor gtp Option Argument Required Default ports No ports { 2123 3386 } Option explanations ports This specifies on what ports to check for GTP control messages. Typically, this includes 2123 3386. Syntax: ports { [< ... >] } Examples: ports { 2123 3386 } Note: there are spaces before and after '{' and '}' Configuration examples preprocessor gtp preprocessor gtp: ports { 2123 3386 2152 } Default configuration preprocessor gtp GTP Decoder Events ================================================================================ SID Description -------------------------------------------------------------------------------- 297 Two or more GTP encapsulation layers present 298 GTP header length is invalid GTP Preprocessor Events ================================================================================ The preprocessor uses GID 143 to register events. SID Description -------------------------------------------------------------------------------- 1 Message length is invalid. 2 Information element length is invalid. 3 Information elements are out of order. Rule Options ================================================================================ New rule options are supported by enabling the GTP preprocessor: gtp_type gtp_info gtp_version gtp_type ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The gtp_type keyword is used to check for specific GTP types. User can input message type value, an integer in [0, 255], or a string defined in the Table below. More than one type can be specified, via a comma separated list, and are OR'ed together. If the type used in a rule is not listed in the preprocessor configuration, an error will be thrown. Same message type might have different message type value in different GTP versions. For example, sgsn_context_request has message type value 50 in GTPv0 and GTPv1, but 130 in GTPv2. gtp_type will match to a different value depending on the version number in the packet. In this example, evaluating a GTPv0 or GTPv1 packet will check whether the message type value is 50; evaluating a GTPv2 packet will check whether the message type value is 130. When a message type is not defined in a version, any packet in that version will always return "No match". If an integer is used to specify message type, every GTP packet is evaluated, no matter what version the packet is. If the message type matches the value in packet, it will return "Match". Syntax: gtp_type:; type-list = type|type, type-list type = "0-255"| | "echo_request" | "echo_response" ... Examples: gtp_type:10, 11, echo_request; GTPv0 message types: Value Message Type ********************************************** 1 echo_request 2 echo_response 3 version_not_supported 4 node_alive_request 5 node_alive_response 6 redirection_request 7 redirection_response 16 create_pdp_context_request 17 create_pdp_context_response 18 update_pdp_context_request 19 update_pdp_context_response 20 delete_pdp_context_request 21 delete_pdp_context_response 22 create_aa_pdp_context_request 23 create_aa_pdp_context_response 24 delete_aa_pdp_context_request 25 delete_aa_pdp_context_response 26 error_indication 27 pdu_notification_request 28 pdu_notification_response 29 pdu_notification_reject_request 30 pdu_notification_reject_response 32 send_routing_info_request 33 send_routing_info_response 34 failure_report_request 35 failure_report_response 36 note_ms_present_request 37 note_ms_present_response 48 identification_request 49 identification_response 50 sgsn_context_request 51 sgsn_context_response 52 sgsn_context_ack 240 data_record_transfer_request 241 data_record_transfer_response 255 pdu GTPv1 message types: Value Message Type ********************************************** 1 echo_request 2 echo_response 3 version_not_supported 4 node_alive_request 5 node_alive_response 6 redirection_request 7 redirection_response 16 create_pdp_context_request 17 create_pdp_context_response 18 update_pdp_context_request 19 update_pdp_context_response 20 delete_pdp_context_request 21 delete_pdp_context_response 22 init_pdp_context_activation_request 23 init_pdp_context_activation_response 26 error_indication 27 pdu_notification_request 28 pdu_notification_response 29 pdu_notification_reject_request 30 pdu_notification_reject_response 31 supported_ext_header_notification 32 send_routing_info_request 33 send_routing_info_response 34 failure_report_request 35 failure_report_response 36 note_ms_present_request 37 note_ms_present_response 48 identification_request 49 identification_response 50 sgsn_context_request 51 sgsn_context_response 52 sgsn_context_ack 53 forward_relocation_request 54 forward_relocation_response 55 forward_relocation_complete 56 relocation_cancel_request 57 relocation_cancel_response 58 forward_srns_contex 59 forward_relocation_complete_ack 60 forward_srns_contex_ack 70 ran_info_relay 96 mbms_notification_request 97 mbms_notification_response 98 mbms_notification_reject_request 99 mbms_notification_reject_response 100 create_mbms_context_request 101 create_mbms_context_response 102 update_mbms_context_request 103 update_mbms_context_response 104 delete_mbms_context_request 105 delete_mbms_context_response 112 mbms_register_request 113 mbms_register_response 114 mbms_deregister_request 115 mbms_deregister_response 116 mbms_session_start_request 117 mbms_session_start_response 118 mbms_session_stop_request 119 mbms_session_stop_response 120 mbms_session_update_request 121 mbms_session_update_response 128 ms_info_change_request 129 ms_info_change_response 240 data_record_transfer_request 241 data_record_transfer_response 254 end_marker 255 pdu GTPv2 message types: Value Message Type ********************************************** 1 echo_request 2 echo_response 3 version_not_supported 32 create_session_request 33 create_session_response 34 modify_bearer_request 35 modify_bearer_response 36 delete_session_request 37 delete_session_response 38 change_notification_request 39 change_notification_response 64 modify_bearer_command 65 modify_bearer_failure_indication 66 delete_bearer_command 67 delete_bearer_failure_indication 68 bearer_resource_command 69 bearer_resource_failure_indication 70 downlink_failure_indication 71 trace_session_activation 72 trace_session_deactivation 73 stop_paging_indication 95 create_bearer_request 96 create_bearer_response 97 update_bearer_request 98 update_bearer_response 99 delete_bearer_request 100 delete_bearer_response 101 delete_pdn_request 102 delete_pdn_response 128 identification_request 129 identification_response 130 sgsn_context_request 131 sgsn_context_response 132 sgsn_context_ack 133 forward_relocation_request 134 forward_relocation_response 135 forward_relocation_complete 136 forward_relocation_complete_ack 137 forward_access 138 forward_access_ack 139 relocation_cancel_request 140 relocation_cancel_response 141 configuration_transfer_tunnel 149 detach 150 detach_ack 151 cs_paging 152 ran_info_relay 153 alert_mme 154 alert_mme_ack 155 ue_activity 156 ue_activity_ack 160 create_forward_tunnel_request 161 create_forward_tunnel_response 162 suspend 163 suspend_ack 164 resume 165 resume_ack 166 create_indirect_forward_tunnel_request 167 create_indirect_forward_tunnel_response 168 delete_indirect_forward_tunnel_request 169 delete_indirect_forward_tunnel_response 170 release_access_bearer_request 171 release_access_bearer_response 176 downlink_data 177 downlink_data_ack 179 pgw_restart 180 pgw_restart_ack 200 update_pdn_request 201 update_pdn_response 211 modify_access_bearer_request 212 modify_access_bearer_response 231 mbms_session_start_request 232 mbms_session_start_response 233 mbms_session_update_request 234 mbms_session_update_response 235 mbms_session_stop_request 236 mbms_session_stop_response gtp_info ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The gtp_info keyword is used to check for specific GTP information element. This keyword restricts the search to the information element field. User can input information element value, an integer in [0, 255], or a string defined in the Table below. If the information element used in this rule is not listed in the preprocessor configuration, an error will be thrown. When there are several information elements with the same type in the message, this keyword restricts the search to the total consecutive buffer. Because the standard requires same types group together, this feature will be available for all valid messages. In the case of "out of order information elements", this keyword restricts the search to the last buffer. Similar to message type, same information element might have different information element value in different GTP versions. For example, "cause" has value 1 in GTPv0 and GTPv1, but 2 in GTPv2. gtp_info will match to different value depending on the version number in the packet. When an information element is not defined in a version, any packet in that version will always return "No match". If an integer is used to specify information element type, every GTP packet is evaluated, no matter what version the packet is. If the message type matches the value in packet, it will return "Match". Syntax: gtp_info:; ie = "0-255"| "rai" | "tmsi"... Examples: gtp_info: 16; gtp_info: tmsi GTPv0 information elements: Value Information elements *********************************************** 1 cause 2 imsi 3 rai 4 tlli 5 p_tmsi 6 qos 8 recording_required 9 authentication 11 map_cause 12 p_tmsi_sig 13 ms_validated 14 recovery 15 selection_mode 16 flow_label_data_1 17 flow_label_signalling 18 flow_label_data_2 19 ms_unreachable 127 charge_id 128 end_user_address 129 mm_context 130 pdp_context 131 apn 132 protocol_config 133 gsn 134 msisdn 251 charging_gateway_addr 255 private_extension GTPv1 information elements: Value Information elements *********************************************** 1 cause 2 imsi 3 rai 4 tlli 5 p_tmsi 8 recording_required 9 authentication 11 map_cause 12 p_tmsi_sig 13 ms_validated 14 recovery 15 selection_mode 16 teid_1 17 teid_control 18 teid_2 19 teardown_ind 20 nsapi 21 ranap 22 rab_context 23 radio_priority_sms 24 radio_priority 25 packet_flow_id 26 charging_char 27 trace_ref 28 trace_type 29 ms_unreachable 127 charge_id 128 end_user_address 129 mm_context 130 pdp_context 131 apn 132 protocol_config 133 gsn 134 msisdn 135 qos 136 authentication_qu 137 tft 138 target_id 139 utran_trans 140 rab_setup 141 ext_header 142 trigger_id 143 omc_id 144 ran_trans 145 pdp_context_pri 146 addi_rab_setup 147 sgsn_number 148 common_flag 149 apn_restriction 150 radio_priority_lcs 151 rat_type 152 user_loc_info 153 ms_time_zone 154 imei_sv 155 camel 156 mbms_ue_context 157 tmp_mobile_group_id 158 rim_routing_addr 159 mbms_config 160 mbms_service_area 161 src_rnc_pdcp 162 addi_trace_info 163 hop_counter 164 plmn_id 165 mbms_session_id 166 mbms_2g3g_indicator 167 enhanced_nsapi 168 mbms_session_duration 169 addi_mbms_trace_info 170 mbms_session_repetition_num 171 mbms_time_to_data 173 bss 174 cell_id 175 pdu_num 177 mbms_bearer_capab 178 rim_routing_disc 179 list_pfc 180 ps_xid 181 ms_info_change_report 182 direct_tunnel_flags 183 correlation_id 184 bearer_control_mode 185 mbms_flow_id 186 mbms_ip_multicast 187 mbms_distribution_ack 188 reliable_inter_rat_handover 189 rfsp_index 190 fqdn 191 evolved_allocation1 192 evolved_allocation2 193 extended_flags 194 uci 195 csg_info 196 csg_id 197 cmi 198 apn_ambr 199 ue_network 200 ue_ambr 201 apn_ambr_nsapi 202 ggsn_backoff_timer 203 signalling_priority_indication 204 signalling_priority_indication_nsapi 205 high_bitrate 206 max_mbr 251 charging_gateway_addr 255 private_extension GTPv2 information elements: Value Information elements *********************************************** 1 imsi 1 echo_request 2 cause 2 echo_response 3 recovery 3 version_not_supported 4 node_alive_request 5 node_alive_response 6 redirection_request 7 redirection_response 16 create_pdp_context_request 17 create_pdp_context_response 18 update_pdp_context_request 19 update_pdp_context_response 20 delete_pdp_context_request 21 delete_pdp_context_response 22 create_aa_pdp_context_request 23 create_aa_pdp_context_response 24 delete_aa_pdp_context_request 25 delete_aa_pdp_context_response 26 error_indication 27 pdu_notification_request 28 pdu_notification_response 29 pdu_notification_reject_request 30 pdu_notification_reject_response 32 send_routing_info_request 33 send_routing_info_response 34 failure_report_request 35 failure_report_response 36 note_ms_present_request 37 note_ms_present_response 48 identification_request 49 identification_response 50 sgsn_context_request 51 sgsn_context_response 52 sgsn_context_ack 71 apn 72 ambr 73 ebi 74 ip_addr 75 mei 76 msisdn 77 indication 78 pco 79 paa 80 bearer_qos 81 flow_qos 82 rat_type 83 serving_network 84 bearer_tft 85 tad 86 uli 87 f_teid 88 tmsi 89 cn_id 90 s103pdf 91 s1udf 92 delay_value 93 bearer_context 94 charging_id 95 charging_char 96 trace_info 97 bearer_flag 99 pdn_type 100 pti 101 drx_parameter 103 gsm_key_tri 104 umts_key_cipher_quin 105 gsm_key_cipher_quin 106 umts_key_quin 107 eps_quad 108 umts_key_quad_quin 109 pdn_connection 110 pdn_number 111 p_tmsi 112 p_tmsi_sig 113 hop_counter 114 ue_time_zone 115 trace_ref 116 complete_request_msg 117 guti 118 f_container 119 f_cause 120 plmn_id 121 target_id 123 packet_flow_id 124 rab_contex 125 src_rnc_pdcp 126 udp_src_port 127 apn_restriction 128 selection_mode 129 src_id 131 change_report_action 132 fq_csid 133 channel 134 emlpp_pri 135 node_type 136 fqdn 137 ti 138 mbms_session_duration 139 mbms_service_area 140 mbms_session_id 141 mbms_flow_id 142 mbms_ip_multicast 143 mbms_distribution_ack 144 rfsp_index 145 uci 146 csg_info 147 csg_id 148 cmi 149 service_indicator 150 detach_type 151 ldn 152 node_feature 153 mbms_time_to_transfer 154 throttling 155 arp 156 epc_timer 157 signalling_priority_indication 158 tmgi 159 mm_srvcc 160 flags_srvcc 161 mmbr 240 data_record_transfer_request 241 data_record_transfer_response 255 private_extension 255 pdu gtp_version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The gtp_version keyword is used to check for specific GTP version. Because different GTP version defines different message types and information elements, this keyword should combine with gtp_type and gtp_info. Syntax: gtp_version:; version = "0, 1, 2' Example: gtp_version: 1; snort-2.9.6.0/doc/README.gre0000644000000000000000000000640412232305202012116 00000000000000Generic Routing Encapsulation (GRE) Decoder =========================================== Snort now has the capability of decoding GRE encapsulated traffic. RFC 1701 is supported which seems to be the most complete implementation of the header (see RFCs 2784 and 2890). It also supports GRE version 1 as described in RFC 2637 (PPTP) (Note that decoding of PPTP is not currently supported on architectures that require word alignment such as SPARC). The decoder performs some basic checking of the GRE header fields, and moves past the GRE header to the beginning of the payload header for further decoding. Payload and Delivery header support =================================== Proto Delivery Payload ----- -------- ------- IPv4 x x IPv6 x x Trans- Bridging x Arp x ERSPAN.2 x x ERSPAN.3 x x PPP x (only on architectures that do not require word alignment - so this is supported on Intel and PPC, but not supported on SPARC) How to enable the decoder ========================= Decoding of GRE is enabled by default, to disable, use the following option to configure $ ./configure --disable-gre Note on multiple encapsulation ============================== Snort does not support more than 1 layer of GRE encapsulation and will alert if it sees multiple encapsulations. For example, the following will cause Snort to generate an alert: -------------------------------------------------- | Eth | IP | GRE | IP | GRE | IP | TCP | Payload | -------------------------------------------------- Logging ======= Currently only the GRE payload packet is logged, i.e. the headers and payload after the GRE header. For example: ----------------------------------------- | Eth | IP1 | GRE | IP2 | TCP | Payload | ----------------------------------------- gets logged as ----------------------------- | Eth | IP2 | TCP | Payload | ----------------------------- and ------------------------------------------------- | Eth1 | IP1 | GRE | Eth2 | IP2 | TCP | Payload | ------------------------------------------------- gets logged as ------------------------------ | Eth2 | IP2 | TCP | Payload | ------------------------------ Alerts ====== Alerts pertaining to the GRE decoder fall under the more general case of decoder alerts, with GID of 116. The introduction of a GRE header can produce the following alerts: SID Description --- ----------- 160 Alerts if the GRE header length (as determined from the header flags) is greater than the length of the rest of the packet. 161 Alerts if multiple encapsulations are encountered. 162 Alerts if an invalid GRE version is found, i.e. not 0 or 1. 163 Alerts if a GRE v.0 header contains invalid data - the Recur or Flags fields are not zero. 164 Alerts if a GRE v.1 header contains invalid data - the Recur or Flags fields are not zero, the Checksum, Routing or SSR flag is set, the Key flag is not set or the Protocol field does not contain 0x880B (PPP). 165 Alerts if the Transparent Ethernet Bridging header length is greater than the length of the rest of the packet. snort-2.9.6.0/doc/README.ftptelnet0000644000000000000000000004015612260355636013371 00000000000000FTPTelnet ========= Steven Sturges Thanks to Dan Roelker , Marc Norton , and Andy Mullican for their help with the design. == Overview == FTPTelnet serves two purposes, decoding and normalizing Telnet traffic, and decoding and interpreting FTP traffic. FTPTelnet handles stateful and stateless processing. It saves state between individual packets. However maintaining correct state is dependent on the reassembly of the client side of the stream (i.e., a loss of coherent stream data results in a loss of state). -- Telnet -- Given a telnet data buffer, FTPTelnet will normalize the buffer with respect to telnet commands and option negotiation, eliminating telnet command sequences per RFC 854. It will also determine when a telnet connection is encrypted, per the use of the telnet encryption option per RFC 2946. -- FTP -- Given an FTP command channel buffer, FTPTelnet will interpret the data, identifying FTP commands and parameters, as well as FTP response codes and messages. It will enforce correctness of the parameters, determine when an FTP command connection is encrypted, and determine when an FTP data channel is opened. == Configuration == FTPTelnet has a very "rich" user configuration. Users can configure checks for a few specific telnet exploits, and specify individual FTP servers and clients with a variety of options, which should allow the user to emulate any type of web server or client. It is VERY IMPORTANT to understand the configuration semantics, so an administrator can know what to expect from the normalization routines and protocol correctness checks. Within the discussions of each option, occurrence of a / in the option parameters implies that one or the other parameter must be specified when that option is used. For example, with a yes/no option, the presence of the option causes detection to occur when tracking state. A yes results in an alert being generated. -- Global Configuration -- The global configuration deals with configuration options that determine the global functioning of FTPTelnet. The following example gives the generic global configuration format: preprocessor ftp_telnet: global [followed by the configuration options] There can only be a single global configuration. An error will be reported otherwise. The global configuration options are described below: *inspection_type stateful/stateless * Indicate whether to operate in stateful stateless mode. * encrypted_traffic yes/no * Detect and alert on encrypted telnet and FTP sessions. * check_encrypted * Instructs the preprocessor to continue checking a data stream after it is encrypted, looking for an eventual decrypted data. This is really only applicable if the encrypted_traffic is used, however that is not enforced. -- Telnet configuration -- The telnet configuration deals with configuration options relating to the telnet protocol. The following example gives the generic telnet configuration format: preprocessor ftp_telnet_protocol: telnet [followed by the options] There should only be a single telnet configuration, however, subsequent ones simply override configuration options established prior. The telnet configuration options are described below: * ports { port [port] ... } * This specifies on what ports to check for telnet data. Typically, this will only include 23, however, additional ports may be specified since certain network routers and other devices employ telnet as a means of administration. Because encrypted traffic (SSL) cannot be decoded, adding ports 22 (SSH) could yield unexpected results. * normalize * This turns on normalization for the telnet connections. Typically, it should be turned on. * ayt_attack_thresh number * Detect and alert on consecutive are you there [AYT] commands beyond the threshold number specified. This addresses a few specific vulnerabilities relating to bsd-based implementations of telnet. * detect_anomalies * In order to support certain options, Telnet supports subnegotiation. Per the Telnet RFC, subnegotiation begins with SB (subnegotiation begin) and must end with an SE (subnegotiation end). However, certain implementations of Telnet servers will ignore the SB without a corresponding SE. This is anomalous behavior which could be an evasion case. Being that FTP uses the Telnet protocol on the control connection, it is also susceptible to this behavior. The detect_anomalies option enables alerting on Telnet SB without the corresponding SE. -- FTP configuration -- The FTP configuration deals with configuration options relating to FTP servers and FTP clients. Each of these will be discussed individually below, as the configurations are different. ** Server Configuration ** There are two types of server configurations: default and [IP]. The default configuration: - preprocessor ftp_telnet_protocol: ftp server default [server options] This configuration supplies the default FTP server configuration for any server that is not individually configured. It is suggested that you start with the default configuration and craft individual server configurations as required by the environment. For specific IP's (i.e., FTP servers with known behavior), the configuration is very similar: - preprocessor ftp_telnet_protocol: ftp server [IP] [server options] The server options described below may be used in both the default and specific IP configuration. * ports { port [port] ... } * This specifies on what ports to check for FTP data. Typically, this will only include 21, however, additional ports may be specified. * print_cmds Useful for debugging. This turns on printing of the configuration information for each ftp command listed for this server. By default it is not in use, as it generates a substantial amount of output when snort is run from the command line. * ftp_cmds { cmd [cmd] ... } * This specifies additional FTP commands outside of those checked by default within the preprocessor. The preprocessor may be configured to generate an alert when it sees a command it does not recognize. Aside from the default commands recognized, it may be necessary to allow the use of the "X" commands, specified in RFC 775. To do so, use the following ftp_cmds option. Since these are rarely used by FTP client implementations, they are not included in the defaults. ftp_cmds { XPWD XCWD XCUP XMKD XRMD } * def_max_param_len number * This specifies the default maximum parameter length for all commands in bytes. If the parameter for an FTP command exceeds that length, and the preprocessor is configured to do so, an alert will be generated. This is used to check for buffer overflow exploits within FTP servers. * alt_max_param_len number { cmd [cmd] ... } * This specifies the maximum parameter length for the specified commands in bytes, overriding the default. If the parameter for that FTP command exceeds that length, and the preprocessor is configured to do so, an alert will be generated. It can be used to restrict specific commands to small parameter values. For example the USER command -- usernames may be no longer than 16 bytes, so the appropriate configuration would be: alt_max_param_len 16 { USER } * chk_str_fmt { cmd [cmd] ... } * This causes the preprocessor to check for string format attacks on the specified commands. * cmd_validity cmd < fmt > * This specifies the valid format for parameters of a given command. fmt is as follows: int Param must be an integer number Param must be an integer between 1 and 255 char Param must be a single char, and one of date Param follows format specified where # = Number, C=Char, []=optional, |=OR, {}=choice, anything else=literal (i.e., .+- ) string Param is string (effectively unrestricted) host_port Param must a host port specifier, per RFC 959. long_host_port Parameter must be a long host port specified, per RFC 1639 extended_host_port Parameter must be an extended host port specified, per RFC 2428 {}, | One of, alternate values enclosed within {}, [] Optional value enclosed within {}, optional value enclose within [] Examples of the cmd_validity option are shown below. These examples are the default checks (per RFC 959 and others) performed by the preprocessor. cmd_validity MODE < char SBC > cmd_validity STRU < char FRP > cmd_validity ALLO < int [ char R int ] > cmd_validity TYPE < { char AE [ char NTC ] | char I | char L [ number ] } > cmd_validity PORT < host_port > A cmd_validity line in the configuration can be used to override these defaults and/or add a check for other commands. A few examples follow # This allows additional modes, including mode Z which allows for # zip-style compression. cmd_validity MODE < char ASBCZ > # Allow for a date in the MDTM command. cmd_validity MDTM < [ date nnnnnnnnnnnnnn[.n[n[n]]] ] string > MDTM is an odd case that is worth discussing... While not part of an established standard, certain FTP servers accept MDTM commands that set the modification time on a file. The most common among servers that do, accept a format using YYYYMMDDHHmmss[.uuu]. Some others accept a format using YYYYMMDDHHmmss[+|-]TZ format. The example above is for the first case (time format as specified in http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16.txt) To check validity for a server that uses the TZ format, use the following: cmd_validity MDTM < [ date nnnnnnnnnnnnnn[{+|-}n[n]] ] string > * telnet_cmds yes/no * Detect and alert when telnet cmds are seen on the FTP command channel. * ignore_telnet_erase_cmds yes/no This option allows Snort to ignore telnet escape sequences for erase character (TNC EAC) and erase line (TNC EAL) when normalizing FTP command channel. Some FTP servers do not process those telnet escape sequences. * data_chan * Causes the FTP preprocessor to force the rest of snort to ignore the FTP data channel connections. This means that NO INSPECTION other than state (preprocessor AND rules) will be performed on that data channel. It can turned on to improve performance -- especially with respect to large file transfers -- by ignoring traffic. Use of "data_chan" is deprecated in favor of "ignore_data_chan". This option will be removed in a future release. * ignore_data_chan yes/no * When set to "yes", causes the FTP preprocessor to force the rest of snort to ignore the FTP data channel connections. NO INSPECTION other than state (preprocessor AND rules) will be performed on that data channel. It can be turned on to improve performance -- especially with respect to large file transfers from a trusted source -- by ignoring traffic. If your rule set includes virus-type rules, it is recommended that this option not be used. ** Client Configuration ** There are two types of client configurations: default and [IP]. The default configuration: - preprocessor ftp_telnet_protocol: ftp client default [client options] This configuration supplies the default FTP client configuration for any client that is not individually configured. It is suggested that you start with the default configuration and craft individual client configurations as required by the environment. For specific IP's (i.e., FTP clients with known behavior), the configuration is very similar: - preprocessor ftp_telnet_protocol: ftp client [IP] [client options] The client options described below may be used in both the default and specific IP configuration. * max_resp_len number * This specifies the maximum length for all response messages in bytes. If the message for an FTP response (everything after the 3 digit code) exceeds that length, and the preprocessor is configured to do so, an alert will be generated. This is used to check for buffer overflow exploits within FTP clients. * bounce yes/no * Detect and alert on FTP bounce attacks. An FTP bounce attack occurs when the FTP PORT command is issued and the specified host does not match the host of the client. * bounce_to { CIDR,[port|portlow,porthi] } * When bounce is turned on, this allows the PORT command to use the IP address [CIDR format] and port (or inclusive port range ) without generating an alert. It can be used to deal with proxied FTP connections where the FTP data channel is different from the client. Two examples of the bounce_to command: 1) This allows bounces to 192.168.1.1 port 20020 -- i.e., the use of PORT 192,168,1,1,78,52. bounce_to { 192.168.1.1,20020 } 2) This allows bounces to 192.168.1.1 ports 20020 to 20040 -- i.e., the use of PORT 192,168,1,1,78,xx, where xx is 52 through 72, inclusive. bounce_to { 192.168.1.1,20020,20040 } 3) This allows bounces to 192.168.1.1 port 20020 and 192.168.1.2 port 20030 bounce_to { 192.168.1.1,20020 192.168.1.2,20030 } 4) This allows bounces to IPv6 address fe8::5 port 59340. NOTE: IPv6 support must be enabled. bounce_to { fe8::5,59340 } * telnet_cmds yes/no * Detect and alert when telnet cmds are seen on the FTP command channel. * ignore_telnet_erase_cmds yes/no This option allows Snort to ignore telnet escape sequences for erase character (TNC EAC) and erase line (TNC EAL) when normalizing FTP command channel. Some FTP clients do not process those telnet escape sequences. -- Default Configuration -- The following gives the default configurations: # Global preprocessor ftp_telnet: global \ inspection_type stateless # Telnet protocol preprocessor ftp_telnet_protocol: telnet \ ports { 23 } # Default FTP Server # The default FTP server configuration for FTP command validation. # Most of this comes from RFC 959, with additional commands being # drawn from other RFCs/Internet Drafts that are commonly in use. # # The default_max_param_len is somewhat arbitrary, but is taken # from the majority of the snort FTP rules that alert on parameter # size > 100 characters. This was the case as of 18 Sep 2004. preprocessor ftp_telnet_protocol: ftp server default \ ports { 21 } \ def_max_param_len 100 \ ftp_cmds { USER PASS ACCT CWD CDUP SMNT \ QUIT REIN PORT PASV TYPE STRU MODE RETR STOR STOU APPE ALLO REST \ RNFR RNTO ABOR DELE RMD MKD PWD LIST NLST SITE SYST STAT HELP NOOP } \ ftp_cmds { AUTH ADAT PROT PBSZ CONF ENC } \ ftp_cmds { FEAT OPTS } \ ftp_cmds { MDTM REST SIZE MLST MLSD } \ alt_max_param_len 0 { CDUP QUIT REIN PASV STOU ABOR PWD SYST NOOP } \ cmd_validity MODE < char SBC > \ cmd_validity STRU < char FRP > \ cmd_validity ALLO < int [ char R int ] > \ cmd_validity TYPE < { char AE [ char NTC ] | char I | char L [ number ] } > \ cmd_validity PORT < host_port > # Default FTP Client preprocessor ftp_telnet_protocol: ftp client default \ max_resp_len 100 == Writing rules == {TBD?} Writing rules for normalized telnet changes from the telnet_decode preprocessor. The content parameter in the snort rule language searches the NORMALIZED telnet and FTP buffers. This means that rules that include things that are normalized, such as telnet option negotiation for encryption, i.e. |FF FA 26|, these rules will not alert. They should be changed to add the rawbytes parameter to specify look at the raw data, not the normalized data. == Conclusion == While some of this configuration information can be overwhelming, the defaults are sufficient to get started. Some of the examples provided, especially with respect to the FTP command validation, are derived from tests conducted with traffic generated from various publicly available freeware and/or trialware telnet & FTP client and server implementations. == Alerts == FTP Telnet uses generator ID 125 for FTP and generator ID 126 for telnet. The following alerts will be generated for FTP: SID Description --- ----------- 1 Telnet command on FTP command channel 2 Invalid FTP command 3 FTP parameter length overflow 4 FTP malformed parameter 5 Possible string format attempt in FTP command/parameter 6 FTP response length overflow 7 FTP command channel encrypted 8 FTP bounce attack 9 Evasive Telnet command on FTP command channel The following alerts will be generated for Telnet: SID Description --- ----------- 1 Telnet consecutive AYT overflow 2 Telnet data encrypted 3 Subnegotiation Begin without matching Subnegotiation End snort-2.9.6.0/doc/README.frag30000644000000000000000000002405612260355636012367 00000000000000# $Id$ -------------------------------------------------------------------------------- Frag3 -------------------------------------------------------------------------------- Author: Martin Roesch Overview -------- The frag3 preprocessor is a target-based IP defragmentation module for Snort. Frag3 is designed with the following goals: 1) Faster execution with less complex data management. 2) Target-based host modeling anti-evasion techniques. Frag3 uses the sfxhash data structure and linked lists for data handling internally which allows it to have much more predictable and deterministic performance in any environment which should aid us in managing heavily fragmented environments. Target-based analysis is a relatively new concept in network-based intrusion detection. The idea of a target-based system is to model the actual targets on the network instead of merely modeling the protocols and looking for attacks within them. When IP stacks are written for different operating systems, they are usually implemented by people who read the RFCs and then their interpretation of what the RFC outlines into code. Unfortunately, there are ambiguities in the way that the RFCs define some of the edge conditions that may occur and when this happens different people implement certain aspects of their IP stacks differently. For an IDS this is a big problem. In an environment where the attacker can determine what style of IP defragmentation being used on a particular target, the attacker can try to fragment packets such that the target will put them back together in a specific manner while any passive systems trying to model the host traffic have to guess which way the target OS is going to handle the overlaps and retransmits. As I like to say, if the attacker has more information about the targets on a network than the IDS does, it is possible to evade the IDS. This is where the idea for "target-based IDS" came from. For more detail on this issue and how it affects IDSes, check out the famous Ptacek & Newsham paper at http://www.snort.org/docs/idspaper/ The basic idea behind target-based IDS is that we tell the IDS information about hosts on the network so that it can avoid Ptacek & Newsham style evasion attacks based on information about how an individual target IP stack operates. Vern Paxson and Umesh Shankar did a great paper on this very topic in 2003 that detailed mapping the hosts on a network and determining how their various IP stack implementations handled the types of problems seen in IP defragmentation and TCP stream reassembly. Check it out at http://www.icir.org/vern/papers/activemap-oak03.pdf We can also present the IDS with topology information to avoid TTL-based evasions and a variety of other issues, but that's a topic for another day. Once we have this information we can start to really change the game for these complex modeling problems. Frag3 was implemented to showcase and prototype a target-based module within Snort to test this idea. Configuration ------------- There are at least two preprocessor directives required to activate frag3, a global configuration directive and an engine instantiation. There can be an arbitrary number of engines defined at startup with their own configuration, but only one global configuration. Global configuration - Preprocessor name: frag3_global - Available Options NOTE: Global configuration options are comma separated. max_frags - Maximum simultaneous fragments to track, default is 8192 memcap - Memory cap for self preservation, default is 4MB prealloc_memcap - alternate memory management mode, use preallocated fragment nodes based on a memory cap (faster in some situations) prealloc_frags - alternate memory management mode, use preallocated fragment nodes based on a static number (faster in some situations) disabled - This optional keyword is allowed with any policy to avoid packet processing. This option disables the preprocessor for this config, but not for other instances of multiple configurations. Use the disable keyword in the base configuration to specify values for the options memcap, prealloc_memcap, and prealloc_frags without having the preprocessor inspect traffic for traffic applying to the base configuration. The other options are parsed but not used. Any valid configuration may have "disabled" added to it. Engine Configuration - Preprocessor name: frag3_engine - Available Options NOTE: Engine configuration options are space separated. timeout - Timeout for fragments, fragments in the engine for longer than this period will be automatically dropped. Default is 60 seconds. min_ttl - Minimum acceptable TTL value for a fragment packet. Default is 1. The accepted range for this option is 1 - 255. detect_anomalies - Detect fragment anomalies bind_to - IP List to bind this engine to. This engine will only run for packets with destination addresses contained within the IP List. Default value is "all". overlap_limit - Limits the number of overlapping fragments per packet. The default is "0" (unlimited). This config option takes values equal to or greater than zero. This is an optional parameter. detect_anomalies option must be configured for this option to take effect. min_fragment_length - Defines smallest fragment size (payload size) that should be considered valid. Fragments smaller than or equal to this limit are considered malicious and an event is raised, if detect_anomalies is also configured. The default is "0" (check is disabled). This config option takes values equal to or greater than zero. This is an optional parameter. detect_anomalies option must be configured for this option to take effect. policy - Select a target-based defragmentation mode. Available types are first, last, bsd, bsd-right, linux, windows and solaris. Default type is bsd. The Paxson Active Mapping paper introduced the terminology frag3 is using to describe policy types. It has been extended to address differences between a true "first" policy and how Windows and Solaris platforms handle fragmented traffic. The known mappings are as follows. Anyone who develops more mappings and would like to add to this list please feel free to send us an email! Platform | Type --------------- AIX 2 | BSD AIX 4.3 8.9.3 | BSD Cisco IOS | Last FreeBSD | BSD HP JetDirect (printer) | BSD-right HP-UX B.10.20 | BSD HP-UX 11.00 | First IRIX 4.0.5F | BSD IRIX 6.2 | BSD IRIX 6.3 | BSD IRIX64 6.4 | BSD Linux 2.2.10 | linux Linux 2.2.14-5.0 | linux Linux 2.2.16-3 | linux Linux 2.2.19-6.2.10smp | linux Linux 2.4.7-10 | linux Linux 2.4.9-31SGI 1.0.2smp | linux Linux 2.4 (RedHat 7.1-7.3) | linux MacOS (version unknown) | First NCD Thin Clients | BSD OpenBSD (version unknown) | linux OpenBSD (version unknown) | linux OpenVMS 7.1 | BSD OS/2 (version unknown) | BSD OSF1 V3.0 | BSD OSF1 V3.2 | BSD OSF1 V4.0,5.0,5.1 | BSD SunOS 4.1.4 | BSD SunOS 5.5.1,5.6,5.7,5.8 | First Solaris 9, Solaris 10 | Solaris Tru64 Unix V5.0A,V5.1 | BSD Vax/VMS | BSD Windows (95/98/NT4/W2K/XP) | Windows Example configuration (Basic) preprocessor frag3_global preprocessor frag3_engine Example configuration (Advanced) preprocessor frag3_global: prealloc_frags 8192 preprocessor frag3_engine: policy linux bind_to 192.168.1.0/24 preprocessor frag3_engine: policy first bind_to [10.1.47.0/24,172.16.8.0/24] preprocessor frag3_engine: policy last detect_anomalies Note in the advanced example, there are three engines specified running with linux, first and last policies assigned. The first two engines are bound to specific IP address ranges and the last one applies to all other traffic, packets that don't fall within the address requirements of the first two engines automatically fall through to the third one. Alert Output ------------ Frag3 uses generator ID 123 for generating the following alerts: SID Description --- ----------- 1 IP Options on fragmented packet 2 Teardrop attack 3 Short fragment, possible DoS attempt 4 Fragment packet ends after defragmented packet 5 Zero-byte fragment 6 Bad fragment size, packet size is negative 7 Bad fragment size, packet size is greater than 65536 8 Fragmentation overlap 9 IPv6 BSD mbufs remote kernel buffer overflow 10 Bogus fragmentation packet. Possible BSD attack 11 TTL value less than configured minimum, not using for reassembly 12 Number of overlapping fragments exceed configured limit 13 Fragments smaller than configured min_fragment_length snort-2.9.6.0/doc/README.flowbits0000644000000000000000000001253212232305204013173 00000000000000Flowbits Detection Capability ----------------------------- The flowbits detection plugin uses the flow preprocessor to track rule state during a transport protocol session. This is most useful for TCP sessions, as it allows rules to generically track the state of an application protocol. The general configuration of the flowbits rule option is: flowbits:[bits/bats>],[]; bits ::= bit[|bits] bats ::= bit[&bats] : This specifies the group to which the flowbits belong. When the GROUP_NAME isnt specified the flowbits belong to the default group. A particular flowbit can belong to more than one group. The group name should be limited to any alphanumeric string including periods, dashes, and underscores. Flowbits Keywords ----------------- There are several keywords associated with flowbits, most of the options need a user defined name for the specific state that is being checked. This string should be limited to any alphanumeric string including periods, dashes, and underscores. set --- This keyword sets bits to group for a particular flow. When no group specified, set the default group. This keyword always returns true. Syntax: flowbits:set,bats[,group] Usage: flowbits:set,bit1,doc; flowbits:set,bit2&bit3,doc; First rule sets bit1 in doc group, second rule sets bit2 and bit3 in doc group. So doc group has bit 1, bit2 and bit3 set setx --- This keyword sets bits to group exclusively. This clears other bits in group. Group must present.This keyword always returns true. Syntax: flowbits:setx,bats,group Usage: flowbits: setx, bit1, doc flowbits: setx, bit2&bit3, doc First rule sets bit1 in doc group, second rule sets bit2 and bit3 in doc group. So doc group has bit2 and bit3 set, because bit1 is cleared by rule 2. unset ----- This keyword clears bits specified for a particular flow or clears all bits in the group (Group must present). This keyword always returns true. Syntax: flowbits:unset,bats flowbits:unset,all,group Usage: flowbits: unset, bit1 Clear bit1. flowbits: unset, bit1&bit2 After this rule, both bit1 and bit2 are cleared. flowbits: unset, all, doc This clears all bits in the doc group. toggle ------ If flowbit is set, unset it. If it is unset, set it. Toggle every bit specified or toggle all the bits in group (Group must be present). This keyword always returns true. Syntax: flowbits:toggle,bats flowbits:toggle,all,group Usage: flowbits: toggle, bit1&bit2 If bit1 is 0 and bit2 is 1 before, after this rule, bit1 is 1 and bit2 is 0. flowbits:toggle,all,doc Toggle all the bits in group doc as described above. isset ----- This keyword checks a bit or several bits to see if it is set. It returns true or false based on the following syntax. Syntax: flowbits:isset, bits => Check whether any bit is set flowbits:isset, bats => Check whether all bits are set flowbits:isset, any, group => Check whether any bit in the group is set. flowbits:isset, all, group => Check whether all bits in the group are set. Usage flowbits:isset, bit1|bit2 => If either bit1 or bit2 is set, return true flowbits:isset, bit1&bit2 => If both bit1 and bit2 are set, return true, otherwise false flowbits:isset, any, doc => If any bit in group doc is set, return true flowbits:isset, all, doc => If all the bits in doc group are set, return true isnotset -------- This keyword is the reverse of isset. It returns true if isset is false, it returns false if isset is true. Isnotset works on the final result, not on individual bits. Syntax: flowbits:isnotset, bits => Check whether not any bit is set flowbits:isnotset, bats => Check whether not all bits are set flowbits:isnotset, any, group => Check whether not bit in the group is set. flowbits:isnotset, all, group => Check whether not all bits in the group are set. Usage flowbits:isnotset, bit1|bit2 => If either bit1 or bit2 is set, return true flowbits:isnotset, bit1&bit2 => If both bit1 and bit2 are set, return true, otherwise false flowbits:isnotset, any, doc => If any bit in group doc is set, return true flowbits:isnotset, all, doc => If all the bits in doc group are set, return true noalert ------- This keyword always returns false. It allows users to write rules that set, unset, and toggle bit without generating an alert. This is most useful for writing flowbit rules that set bit on normal traffic and significantly reduces unwanted alerts. There is no bit specified with this keyword. Usage: flowbits:noalert; reset ----- This keyword resets all of the states on a given flow if no group specified, otherwise, reset all the bits in a group. This always returns true. There is no bit specified with this keyword. Syntax: flowbits:reset[,group] Usage: flowbits:reset => reset all the bits in the flow flowbits: reset, doc => reset all the bits in the doc group Sample Rules ------------ alert tcp any 143 -> any any (msg:"IMAP login"; content:"OK LOGIN"; flowbits:set,logged_in;) alert tcp any any -> any 143 (msg:"IMAP lsub"; content:"LSUB"; flowbits:isset,logged_in;) alert tcp any any -> any 143 (msg:"IMAP LIST WITHOUT LOGIN"; content:"LIST"; flowbits:isnotset,logged_in;) alert tcp any any -> any any (msg:"JPG transfer"; content:".JPG"; nocase; flowbits:set,http.jpg,file_type;) snort-2.9.6.0/doc/README.filters0000644000000000000000000002613411731203273013023 00000000000000OVERVIEW OF FILTERS =================== This document describes the detection, rate, and event filtering, introduced in Snort 2.8.5, which control the generation, processing, and logging of events as follows: * detection_filter is a new rule option that replaces the current threshold keyword in a rule. It defines a rate which must be exceeded by a source or destination host before a rule can generate an event. * rate_filter provides rate based attack prevention by allowing users to configure a new action to take for a specified time when a given rate is exceeded. * event_filter is a standalone command which replaces 'threshold', which is now obsolete. event_filters reduce the amount of data logged. * Events can also be completely suppressed with the standalone suppress command. Note: this README supercedes README.thresholding which is now deprecated. DEPRECATED ITEMS ================ * detection_filter replaces the existing in-rule threshold, which is now obsolete. Furthermore, the existing threshold when used within a rule was not part of the detection process; it was equivalent to a standalone threshold. To retain the functionality of existing in-rule thresholds, reformat them as standalone event_filters (see below). * event_filter replaces the existing standalone threshold, which is now deprecated. Furthermore, even though event_filter is an alias for threshold, which is allowed to appear in a rule (although that use is now also deprecated), event_filter will not be allowed in a rule. Such use will result in a fatal error during initialization. DETECTION FILTERS ================= detection_filter is a new rule option that replaces the current threshold keyword in a rule. It defines a rate which must be exceeded by a source or destination host before a rule can generate an event. detection_filter has the following format: detection_filter: \ track , \ count , seconds ; * Track by_src|by_dst: rate is tracked either by source IP address or destination IP address. This means count is maintained for each unique source IP address or each unique destination IP address. * Count c: the maximum number of rule matches in s seconds allowed before the detection filter limit to be exceeded. C must be nonzero. * Seconds s: time period over which count is accrued. The value must be nonzero. Snort evaluates a detection_filter as part of the detection phase, just after pattern matching. At most one detection_filter is permitted per rule. Example - this rule will fire on every failed login attempt from 10.1.2.100 during one sampling period of 60 seconds, after the first 30 failed login attempts: drop tcp 10.1.2.100 any > 10.1.1.100 22 ( \ msg:â€SSH Brute Force Attemptâ€; flow:established,to_server; \ content:â€SSHâ€; nocase; offset:0; depth:4; \ detection_filter: track by_src, count 30, seconds 60; \ sid:1000001; rev:1;) Since potentially many events will be generated, a detection_filter would normally be used in conjunction with an event_filter to reduce the number of logged events. RATE FILTERS ============ rate_filter provides rate based attack prevention by allowing users to configure a new action to take for a specified time when a given rate is exceeded. Multiple rate filters can be defined on the same rule, in which case they are evaluated in the order they appear in the configuration file, and the first applicable action is taken. Rate filters are used as standalone commands (outside any rule) and have the following format: rate_filter \ gen_id , sig_id , \ track , \ count , seconds , \ new_action alert|drop|pass|log|sdrop|reject, \ timeout , \ apply_to This format has the following options - all are required except apply_to, which is optional: * Track by_src|by_dst|by_rule: rate is tracked either by source IP address, destination IP address, or by rule. This means the match statistics are maintained for each unique source IP address, for each unique destination IP address, or they are aggregated at rule level. For rules related to Stream5 sessions, source and destination means client and server respectively. track by_rule and apply_to may not be used together. * Count c: the maximum number of rule matches in s seconds before the rate filter limit to is exceeded. C must be positive. * seconds s: the time period over which count is accrued. 0 seconds means count is a total count instead of a specific rate. For example, rate filter may be used to detect if the number of connections to a specific server exceed a specific count. 0 seconds only applies to internal rules (gen_id 135) and other use will produce a fatal error by Snort. * new_action : new_action replaces rule action with alert|drop| pass|log|sdrop for r (timeout) seconds. Drop, reject and sdrop can be used only when snort is used in inline mode. sdrop and reject are conditionally compiled with #ifdef GIDS. * timeout r: revert to the original rule action after r seconds. If r is 0, then rule action is never reverted back. Event filter may be used to manage number of alerts after the rule action is enabled by rate filter. * apply_to : restrict the configuration to only to source or destination IP address (indicated by track parameter) determined by . track by_rule and apply_to may not be used together. Note that events are generated during the timeout period, even if the rate falls below the configured limit. event_filters (below) can be used to suppress excessive rate_filter alerts, however, the first new_action event of the timeout period is never suppressed. Such events indicate a change of state that are significant to the user monitoring the network. Example 1 - allow a maximum of 100 connection attempts per second from any one IP address, and block further connection attempts from that IP address for 10 seconds: rate_filter \ gen_id 135, sig_id 1, \ track by_src, \ count 100, seconds 1, \ new_action drop, timeout 10 Example 2 - allow a maximum of 100 successful simultaneous connections from any one IP address, and block further connections from that IP address for 10 seconds: rate_filter \ gen_id 135, sig_id 2, \ track by_src, \ count 100, seconds 0, \ new_action drop, timeout 10 EVENT FILTERS ============= In Snort 2.8.5, a new command event_filter was added with the following format. It functions the same as the global threshold command does in Snort 2.8.4 and earlier, except that it is not permitted within a rule. event_filter \ gen_id , sig_id , \ type , \ track , \ count , seconds This format supports the following options - all are required: * gen_id, sig_id: specify generator and signature ids of an associated rule. A sig_id of 0 will apply to all sig_ids for the given gen_id. If both gen_id and sig_id are zero, the event_filter applies to all events. Only one event_filter may be defined for a given gen_id, sig_id. * type : type limit alerts on the 1st m events during the time interval, then ignores events for the rest of the time interval. Type threshold alerts every m times we see this event during the time interval. Type both alerts once per time interval after seeing m occurrences of the event, then ignores any additional events during the time interval. * track by_src|by_dst: rate is tracked either by source IP address, or destination IP address. This means count is maintained at either by unique source IP addresses, or unique destination IP addresses. * count c: number of rule matching in s seconds that will cause event filter limit to exceed. C must be nonzero value. A count of -1 disables the event filter and can be used to override the global event_filter. * seconds s: time period over which count is accrued. S must be nonzero value. Example 1 - rule event_filter - limit to logging 1 event per 60 seconds: event_filter \ gen_id 1, sig_id 1851, \ type limit, track by_src, \ count 1, seconds 60 Example 2 - rule event_filter - limit to logging every 3rd event: event_filter \ gen_id 1, sig_id 1852, type threshold, track by_src, \ count 3, seconds 60 Example 3 - rule event_filter - limit to logging just 1 event per 60 seconds, but only if we exceed 30 events in 60 seconds: event_filter \ gen_id 1, sig_id 1853, \ type both, track by_src, \ count 30, seconds 60 Example 4 - global event_filter - limit to logging 1 event per 60 seconds per IP triggering each rule: event_filter \ gen_id 1, sig_id 0, \ type limit, track by_src, \ count 1, seconds 60 Example 5 - global event_filter - limit to logging 1 event per 60 seconds per IP triggering each rule for each event generator: event_filter \ gen_id 0, sig_id 0, \ type limit, track by_src, \ count 1, seconds 60 EVENT SUPPRESSION ================= Suppression commands are standalone commands that reference generators and SIDs and IP addresses via an IP list. This allows a rule to be completely suppressed, or suppressed when the causative traffic is going to or coming from a specific IP or group of IP addresses. The suppress command has these formats: suppress \ gen_id , sig_id suppress \ gen_id , sig_id , \ track by_src|by_dst, \ ip * gen_id, sig_id: specify generator and signature ids of an associated rule. A sig_id of 0 will apply to all sig_ids for the given gen_id. If both gen_id and sig_id are zero, the event_filter applies to all events. Multiple suppress commands may be defined for a given gen_id !=0, sig_id != 0. * track by_src|by_dst: rate is tracked either by source IP address or destination IP address. This means count is maintained for each unique source or destination IP address. If ip is provided, track must be provided as well. * ip : restrict the suppression to only source or destination IP addresses (indicated by track parameter) determined by . If track is provided, ip must be provided as well. Example 1 - suppress this event completely: suppress \ gen_id 1, sig_id 1852 Example 2 - suppress this event from this IP: suppress \ gen_id 1, sig_id 1852, \ track by_src, ip 10.1.1.54 Example 3 - suppress this event to this CIDR block: suppress \ gen_id 1, sig_id 1852, \ track by_dst, ip 10.1.1.0/24 MEMORY CAPS =========== Memory caps can be configured for maximum storage of run-time data (excludes configuration) as follows: config rate_filter: memcap config event_filter: memcap If the rate_filter reaches its memcap, it will recycle memory by releasing the oldest tracker and using that memory for a new tracker. The event_filter works the same way. The default in both cases is 1048576 bytes (1MB). (Internally, global event_ filters (sig_id = 0) are tracked separately from local event_filters (sig_id != 0) and the memcap limit is applied to each group separately, yielding 2*memcap total for event_filter.) snort-2.9.6.0/doc/README.file_ips0000644000000000000000000001231712260355636013154 00000000000000# File IPS ########################################## # THIS CODE IS STILL EXPERIMENTAL! # DO NOT USE IN PRODUCTION ENVIRONMENTS. # Please send any issues to the Snort team ########################################## ## Synopsis This README documents the File Type for IPS rules set of keywords. These keywords provide rule writers the ability to leverage Snort's file identification capability in IPS rules. These new keywords are the indented replacement for existing 'flowbits' rules that solve the same problem. ## Compiling Snort To use the new file keywords, users must compile Snort with the configure flag `--enable-file-inspect`. ./configure --enable-file-inspect ## Configuration You're running configuration must contain a set of `file` identification rules. These rules perform the magic identification of files seen on-the-wire. It is recommended that you configure Snort to use the prepackaged file magic rules. See 'README.file' to learn more about file identification rules. Note that file type detection will be enabled automatically when Snort parses a rule using either of the new keywords. There is no need to specify `config file:` of `preprocessor file` in the Snort configurations. ## file_type The file_type rule keyword allows users to write rules constrained to a given file type, a specific version of a file type, several different file types or several file types of varying versions. ### Syntax file_type: FILE_TYPE ::= [,][|] TYPE ::= The type name, as configured in a file rule. TYPE must match an actual configured file rule. VERSION ::= A specific file type version to match. Omitting VERSION will cause the IPS rule to match all versions of the configured TYPE. ### Example 1. Single file type alert tcp any any -> any any ( msg:"PDF"; file_type:PDF; ) 2. Single file type with version alert tcp any any -> any any ( msg:"PDF version 1.6"; file_type:PDF,1.6; ) 3. Several file types alert tcp any any -> any any ( msg:"Random documents"; file_type:PDF|DOC; ) alert tcp any any -> any any ( msg:"More random documents"; file_type:PDF|DOC|XLS; ) 4. Multiple file types and some versions alert tcp any any -> any any ( msg:"Only PDF versions (1.6,1.7)"; file_type:PDF,1.6|PDF,1.7; ) ## file_group The `file_group` keyword provides the same capability as the `file_type` keyword, but allows for more appropriate collections of common file types. Many file types can belong to a common `group`. See README.file for more information on file groups. # Syntax file_group:; GROUP ::= Match several file types who are contained in the same GROUP. ## Example Given the following Snort configuration file type:MSEXE; id:21; group:windows; msg:"MS EXE"; rev:1; content:|4D 5A|; offset:0; file type:MSCAB; id:26; group:windows; msg:"MS CAB"; rev:1; content:|4D 53 43 46|; offset:0; file type:MSOLE; id:27; group:windows; msg:"MS OLE"; rev:1; content:|D0 CF 11 E0 A1 B1 1A E1|; offset:0; The following two rules work exactly the same alert tcp any any -> any any ( msg:"This uses file grouping"; file_group:windows; ) alert tcp any any -> any any ( msg:"This uses file list"; file_type:MSEXE|MSCAB|MSOLE; ) ## Converting existing flowbits rules As mentioned above, the file_type and file_group are the intended replacement for rules currently using flowbit setter's. What follows are existing flowbits setter rules and an example checker. alert tcp $EXTERNAL_NET $FILE_DATA_PORTS -> $HOME_NET any ( \ msg:"FILE-IDENTIFY Adobe Shockwave Flash file magic detection"; \ flow:to_client,established; \ file_data; content:"CWS"; within:3; fast_pattern; \ flowbits:set,http.swf; flowbits:noalert; \ classtype:misc-activity; sid:20495; rev:3; ) alert tcp $EXTERNAL_NET $FILE_DATA_PORTS -> $HOME_NET any ( \ msg:"FILE-IDENTIFY Adobe Shockwave Flash file magic detection"; \ flow:to_client,established; \ file_data; content:"FWS"; within:3; fast_pattern; \ flowbits:set,http.swf; flowbits:noalert; \ classtype:misc-activity; sid:20496; rev:3; ) alert tcp $EXTERNAL_NET $FILE_DATA_PORTS -> $HOME_NET any ( \ msg:"FILE-IDENTIFY Adobe Shockwave Flash file magic detection"; \ flow:to_client,established; \ file_data; content:"|46 4C 56 01|"; within:4; fast_pattern; \ flowbits:set,http.swf; flowbits:noalert; \ classtype:misc-activity; sid:20497; rev:2; ) alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any ( \ msg:"SWF nonsense"; \ flowbits:isset,http.swf; \ content:"|BA D0 1D EA|"; \ sid:1000000; rev:1; ) Would be replaced with file type:SWF; id:1; msg:"Shockwave Flash File"; rev:1; content:|43 57 53|; offset:0; file type:SWF; id:2; msg:"Shockwave Flash File"; rev:1; content:|46 57 53|; offset:0; file type:SWF; id:3; msg:"Shockwave Flash File"; rev:1; content:|46 4C 56 01|; offset:0; alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any ( \ msg:"SWF nonsense"; \ file_type:SWF; \ content:"|BA D0 1D EA|"; \ sid:1000000; rev:2; ) snort-2.9.6.0/doc/README.file0000644000000000000000000003257712260355636012313 00000000000000File services ================================================================================ Hui Cao ########################################## # THIS CODE IS STILL EXPERIMENTAL! # DO NOT USE IN PRODUCTION ENVIRONMENTS. # Please send any issues to the Snort team ########################################## Overview ================================================================================ With the volume of malwares transferred through network increasing, network file inspection becomes more and more important. This feature will provide file type identification, file signature creation, and file capture capabilities to help user deal with those challenges. There are two parts of file services: file APIs and file inspect preprocessor. File APIs provides all the file inspection functionalities, such as file type identification, file signature calculation, and file capture. File inspect preprocessor provides users ability to control file services, such as enable/disable/configure file type identification, file signature, or file capture. Supported protocols: HTTP, SMTP, IMAP, POP3, FTP, and SMB. Supported file signature calculation: SHA256 Sections: Dependency Requirements File Services Configuration File Inspect Preprocessor Configuration File Type Identification File Signature File Capture Dependency Requirements ================================================================================ For proper functioning of the file processing: Stream session tracking must be enabled, i.e. stream5. TCP must be enabled in stream5. The preprocessor requires a session tracker to keep its data. IP defragmentation should be enabled, i.e. the frag3 preprocessor should be enabled and configured. At lease one of preprocessors supported protocols must be enabled. File Services Configuration ================================================================================ File services are configured through snort "conf" keyword. The configuration name is "file": config file: Option Argument Required Default file_type_depth No 1460 bytes file_signature_depth No 10485760 bytes file_block_timeout No 1 day file_capture_memcap No 100 megabytes file_capture_max No 1048576 bytes file_capture_min No 0 bytes file_capture_block_size No 32768 bytes depth = 0 - 4G bytes timeout = 0 - 4G seconds memcap = 1 - 4G megabytes max = 0 - 4G bytes min = 0 - 4G bytes size = 8 - 4G bytes config file:\ < file_type_depth depth >,\ < file_signature_depth depth >, \ < file_block_timeout timeout >, \ < file_capture_memcap memcap >, \ < file_capture_max max >, \ < file_capture_min min >, \ < file_capture_block_size size > Options: < file_type_depth depth >: Maximum file depth to identify file type. If file type is not identified beyond this value, file type will be set "unknown". 0 means unlimited < file_signature_depth depth >: Maximum file depth to calculate file signature. If file size is larger than this value, file signature will not be calculated. 0 means unlimited < file_block_timeout timeout >: When a file transferred through HTTP is blocked , browser might resume file transfer with partial content in HTTP protocol. Snort block file even if it is transferred through resume. This timeout is to set how long it will keep blocking that file. < file_capture_memcap memcap >: This sets the memory limit for file buffers, in megabytes. < file_capture_max max >: Maximum file size we can capture. If file size is greater than this value file will not be captured. < file_capture_min min >: Minimum file size we can capture. If file size is smaller than this value file will not be captured. < file_capture_block_size size >: This sets the memory block size for file buffer. Smaller value might save memory but may hurt performance. Default is 32k bytes. Example: config file: file_type_depth 16384, file_signature_depth 10485760, \ file_block_timeout 3600, file_capture_memcap 200, \ file_capture_max 1048576, file_capture_min 200, \ file_capture_block_size 65536, This set the file type depth 16K bytes, file signature depth 10M bytes, file block timeout 1 hour, file capture memcap 200M bytes, maximum file size to capture is 1M file, minimum file size to capture is 200 bytes, file block size is 64k. File Inspect Configuration ================================================================================ File inspect dynamic preprocessor can be enabled during build time. The following options must be included in ./configure: --enable-file-inspect The configuration name is "file_inspect": Option Argument Required Default type_id NONE No DISABLED signature NONE No DISABLED capture_memory NONE No DISABLED capture_disk No DISABLED capture_network No DISABLED capture_queue_size No 3000 blacklist No NULL greylist No NULL portno = 0 - 65535 size = 0 - 4G files disk size = 0 - 4G megabytes preprocessor file_inspect:\ < type_id >,\ < signature >, \ < capture_memory >, \ < capture_disk dir >, \ < capture_network hostname portno >, \ < capture_queue_size size >, \ < blacklist file>, \ < greylist file> Options: < type_id >: Enable file type identification < signature >: Enable file signature calculation < capture_memory >: Capture file to memory (file buffers). File analysis can be done on file buffers directly without the overhead of storing to disk. < capture_disk dir >: Store files to the directory specified in dir, and capture no more than disk size (in megabytes). If this limit is reached, no more file capture. < capture_network hostname portno >: Send files to other host, specified by hostname (or IP address) and port number. < capture_queue_size size >: Set the maximum number of files can be queued to process (saved to disk or sent to network). < blacklist file >: Specify a SHA256 list file. Files match SHA256 will be blocked. < greylist file >: Specify a SHA256 list file. Files match SHA256 will be alerted. SHA list file format one SHA per line. Use # for comments. #start of block.txt BDC68D4C856558E618BB5C992A2A6B0276D4809F46A8C44E4D4993DDC31E91B2 69DABBDB754B358AC4FE4B22DE04C0E4C93076816F14BB0730CAA9FD223996FC #end of block.txt Example: preprocessor file_inspect: type_id, signature, \ capture_disk /home/file_capture/tmp/ 300, \ capture_network localhost 8000, \ capture_queue_size 5000, \ blacklist block.txt File Type Identification ================================================================================ File magic rule: file type: ; id: ; ver: ; category: ; \ group: [,]; msg: ; \ content: ||; offset:; rev: type: defines the name of file type. Name should be limited to any alphanumeric string including periods, dashes, and underscores. id: used to uniquely identify different file types, similarly to rule ID. ver: used to indicate different versions for the same file type. category: defines the categories of file type. Name should be limited to any alphanumeric string including periods, dashes, and underscores. Categories can be Executables, PDF files, FLASH files, Office Documents, Archive, Graphics, Multimedia etc. group: logical grouping of file rules, used for IPS rule keyword `file_group`. See README.file_ips for more information on 'file_group'. msg: the message to print when file type information needs to be described. content: defines the file magic using binary data. The binary data is enclosed within the pipe (|) character and represented as bytecode, i.e hexadecimal numbers. offset: defines the location of file magic relative to the start of file. rev: used to uniquely identify revisions of file type definition. Similar to snort rule, it can be used through include directives. Similar file types can be put into the same file. Multiple file type configurations can be included in snort configuration. Pre-packaged file magic rules: A set of file magic rules is packaged with Snort. They can be located at "etc/file_magic.conf". To use this feature, it is recommended that the these pre-packaged rules are used; doing so requires that you include the file in your Snort configuration as such: include etc/filemagic.conf Example: file type:GIF; ver:87; category:graphics; msg:"GIF87a"; id: 1; content: |47 49 46 38 37 61|; offset:0; rev:1; file type:GIF; ver:89; category:graphics; msg:"GIF89a"; id: 1; content: |47 49 46 38 39 61|; offset:0; rev:1; The previous two rules define GIF format, because file magics are different. Full set of file type magic rules are not included. Future release will include file type magic and rule options to use file type information. Enable file type File type events are generated when file type preprocessor rules are enabled. Each file magic rule requires one file type preprocessor rule. File type use 146 as generator ID. Example: alert ( msg: "GIF87a file "; sid: 87; gid: 146; rev: 1; metadata: rule-type preproc; ) alert ( msg: "GIF89a file "; sid: 89; gid: 146; rev: 1; metadata: rule-type preproc; ) preprocessor file_inspect: type_id File Signature Calculation ================================================================================ File signature events are generated when file signature preprocessor rules are enabled. File signature use 147 as generator ID. Example: alert ( msg: "File signature "; sid: 1; gid: 147; rev: 1; metadata: rule-type preproc; ) Enable Openssl support File services provide its own SHA calculations, but users can optionally enable openssl implementation. Openssl might provide performance optimization based on the platform snort runs. To enable it, the following options should be included in the ./configure command. --with-openssl-includes= --with-openssl-libraries= Example: --with-openssl-includes=/usr/local/ssl/include --with-openssl-libraries=/usr/local/ssl/lib File Capture ================================================================================ File capture relies on file type and file signature enabled. If file type is unknown, that file will not be captured. File signature is used as file ID to avoid downloading duplicated files. Example: preprocessor file_inspect: type_id, signature, \ capture_disk /home/file_capture/tmp/, \ capture_queue_size 5000 All files captured will be saved to directory "tmp". File capture queue is set to 5000 files. Sending captured files to another host File inspect preprocessor provides a simple way to sending files to another host for further analysis. In tools/ directory, file_server is provided to receive and save all the files to disk. Example: preprocessor file_inspect: type_id, signature, \ capture_network 192.168.1.1 8000, \ capture_queue_size 5000 All files captured will be sent to host 192.168.1.1, to port number 8000 On the host 192.168.1.1, you can start file_server before starting snort: file_server 8000 All the files will be saved to the directory where the command is running. File Events ================================================================================ File inspect preprocessor also works as a dynamic output plugins for file events. It logs basic information about file. Format output filelog: [ []] ::= [(’G’|’M’|K’)] filename: the name of the log file. The default name is /file. You may specify â€stdout†for terminal output. The name may include an absolute or relative path. limit: an optional limit on file size which defaults to 128 MB. The minimum is 1 KB. Example: dynamicoutput file / path to /libsf_file_preproc.so output filelog:file All file events will be logged in "file" in the log directory. File event example: 07/02-16:42:50.253157 [**] [File: /wp-content/themes/images/logo.jpg, size: 4633 bytes] [signature: 8D68FA32E67624D409247FEF10D32A413D55C125970AFA533B9CA5E7DDF07A5E] [**] [147:1:1] [**] {TCP} 108.161.189.192:80 -> 10.4.33.54:40736 snort-2.9.6.0/doc/README.event_queue0000644000000000000000000000366510517230427013706 00000000000000Snort Multi-Event Logging (Event Queue) --------------------------------------- Author: Daniel Roelker Snort supports logging multiple events per packet/stream that are prioritized with different insertion methods, such as max content length or event ordering. This document explains how to configure the event queue that facilitates logging multiple events. The general configuration of the event queue is as follows: config event_queue: [max_queue [size]] [log [size]] [order_events [TYPE]] Event Queue Configuration Options --------------------------------- There are three configuration options to the configuration parameter 'event_queue'. max_queue ---------- This determines the maximum size of the event queue. For example, if the event queue has a max size of 8, only 8 events will be stored for a single packet or stream. The default value is 8. log --- This determines the number of events to log for a given packet or stream. You can't log more than the max_event number that was specified. The default value is 3. order_events ------------ This argument determines the way that the incoming events are ordered. We currently have two different methods: * priority - The highest priority (1 being the highest) events are ordered first. * content_length - Rules are ordered before decode or preprocessor alerts, and rules that have a longer content are ordered before rules with shorter contents. The method in which events are ordered does not affect rule types such as pass, alert, log, etc. The default value is content_length. Examples -------- # this is the default value configuration config event_queue: max_queue 8 log 3 order_events content_length # reconfigure the entire event queue config event_queue: max_queue 10 log 3 order_events content_length # leave defaults but change the way events are ordered config event_queue: order_events priority # change the number of events logged config event_queue: log 2 snort-2.9.6.0/doc/README.dns0000644000000000000000000000317510727307636012153 00000000000000DNS --- Steven Sturges Documentation last update 2006-08-25 == Overview == The DNS preprocessor decodes DNS Responses and can detect the following exploits: DNS Client RData Overflow, Obsolete Record Types, and Experimental Record Types. DNS looks are DNS Response traffic over UDP and TCP and it requires Stream preprocessor to be enabled for TCP decoding. == Configuration == By default, all alerts are disabled and the preprocessor checks traffic on port 53. The available configuration options are described below: * ports { port[, port] .. }* This option specifies the source ports that the DNS preprocessor should inspect traffic. * enable_obsolete_types * Alert on Obsolete (per RFC 1035) Record Types * enable_experimental_types * Alert on Experimental (per RFC 1035) Record Types * enable_rdata_overflow * Check for DNS Client RData Overflow == Example/Default Configuration == Looks for traffic on DNS server port 53. Check for the DNS Client RData overflow vulnerability. Do not alert on obsolete or experimental RData record types. preprocessor dns: ports { 53 } \ enable_rdata_overflow == Alerts == The DNS preprocessor uses generator ID 131 and can produce the following alerts: SID Description --- ----------- 1 Obsolete DNS RData Type 2 Experimental DNS RData Type 3 Client RData TXT Overflow == Conclusion == The DNS preprocessor does nothing if none of the 3 vulnerabilities it checks for are enabled. It will not operate on TCP sessions picked up midstream, and it will cease operation on a session if it loses state because of missing data (dropped packets). snort-2.9.6.0/doc/README.dnp30000644000000000000000000001724611652050543012225 00000000000000DNP3 Preprocessor ================= Overview ======== The DNP3 preprocessor is a Snort module that decodes and reassembles the DNP3 protocol. It also provides rule options to access certain protocol fields. This allows a user to write rules for DNP3 packets without decoding the protocol with a series of "content" and "byte_test" options. DNP3 is a protocol used in SCADA networks. If your network does not contain any DNP3-enabled devices, we recommend leaving this preprocessor turned off. Dependencies ============ The Stream5 preprocessor must be enabled for the DNP3 preprocessor to work. Protocol-Aware Flushing (PAF) is also required. See README.stream5 for more information. Preprocessor Configuration ========================== DNP3 configuration is split into two parts: the preprocessor config, and the rule options. The preprocessor config starts with: preprocesor dnp3: Options are as follows: Option Argument Required Default -------------------------------------------------------------- ports , or NO ports 20000 { port [port] ... } memcap NO memcap 262144 check_crc NONE NO OFF disabled NONE NO OFF Option explanations ports This sets the port numbers on which DNP3 traffic is inspected. A single port number may be provided, or a space-separated list enclosed in curly brackets. The default is port 20000. memcap This sets a maximum to the amount of memory allocated to the DNP3 preprocessor for session-tracking purposes. The argument is given in bytes. Each session requires about 4 KB to track, and the default is 256 kB. This gives the preprocessor the ability to track 63 DNP3 sessions simultaneously. Setting the memcap below 4144 bytes will cause a fatal error. When multiple configs are used, the memcap in the non-default configs will be overwritten by the memcap in the default config. If the default config isn't intended to inspect DNP3 traffic, use the "disabled" keyword. (See README.multipleconfigs for more info) check_crc This option makes the preprocessor validate the checksums contained in DNP3 Link-Layer Frames. Frames with invalid checksums will be ignored. If the corresponding preprocessor rule is enabled, invalid checksums will generate alerts. The corresponding rule is GID 145, SID 1. disabled This option is used for loading the preprocessor without inspecting any DNP3 traffic. The "disabled" keyword is only useful when the DNP3 preprocessor is turned on in a separate policy. (See README.multipleconfigs for information on Multiple Policies) Example preprocessor config preprocessor dnp3: ports { 20000 } \ memcap 262144 \ check_crc Multiple policy example: snort.conf ---------- preprocessor dnp3: memcap 262144 disabled config binding: snort.conf.dnp3net net snort.conf.dnp3net ------------------ preprocessor dnp3: ports 20000, check_crc Rule Options ============ The DNP3 preprocessor adds 4 new rule options. These rule options match on various pieces of the DNP3 headers. The preprocessor must be enabled for these rule options to work. dnp3_func --------- This option matches against the Function Code inside of a DNP3 Application-Layer request/response header. The code may be a number (in decimal format), or a string from the list provided below. Syntax: dnp3_func: code = 0-255 confirm read write select operate direct_operate direct_operate_nr immed_freeze immed_freeze_nr freeze_clear freeze_clear_nr freeze_at_time freeze_at_time_nr cold_restart warm_restart initialize_data initialize_appl start_appl stop_appl save_config enable_unsolicited disable_unsolicited assign_class delay_measure record_current_time open_file close_file delete_file get_file_info authenticate_file abort_file activate_config authenticate_req authenticate_err response unsolicited_response authenticate_resp Example: alert tcp any any -> any 20000 (msg:"DNP3 Write request"; dnp3_func:write; sid:1;) dnp3_ind -------- This option matches on the Internal Indicators flags present in a DNP3 Application Response Header. Much like the TCP flags rule option, providing multiple flags in one option will cause the rule to fire if *ANY* one of the flags is set. To alert on a combination of flags, use multiple rule options. Syntax: dnp3_ind:[,...] flag = all_stations class_1_events class_2_events class_3_events need_time local_control device_trouble device_restart no_func_code_support object_unknown parameter_error event_buffer_overflow already_executing config_corrupt reserved_2 reserved_1 Examples: # Alerts on reserved_1 OR reserved_2 being set alert tcp any 20000 -> any any (msg:"Reserved DNP3 Indicator set"; \ dnp3_ind:reserved_1,reserved_2; sid:1;) # Alerts on class_1 AND class_2 AND class_3 events being set alert tcp any 20000 -> any any (msg:"Lots of DNP3 events"; \ dnp3_ind:class_1_events; dnp3_ind:class_2_events; dnp3_ind:class_3_events; \ sid:2;) dnp3_obj -------- This option matches on DNP3 object headers present in a request or response. Syntax: dnp3_obj:, group = 0 - 255 var = 0 - 255 Example: alert tcp any any -> any any (msg:"DNP3 Time and Date object"; \ dnp3_obj:50,1; sid:1;) dnp3_data --------- As Snort processes DNP3 packets, the DNP3 preprocessor collects Link-Layer Frames and reassembles them back into Application-Layer Fragments. This rule option sets the cursor to the beginning of an Application-Layer Fragment, so that other rule options can work on the reassembled data. With the dnp3_data rule option, you can write rules based on the data within Fragments without splitting up the data and adding CRCs every 16 bytes. Syntax: dnp3_data; No options. Example: alert tcp any any -> any any (msg:"String 'badstuff' in DNP3 message"; \ dnp3_data; content:"badstuff"; sid:1;) Preprocessor Rules ================== The DNP3 preprocessor uses GID 145 for its preprocessor events. SID Description -------------------------------------------------------------------- 1 A Link-Layer Frame contained an invalid CRC. (Enable "check_crc" in the preprocessor config to get this alert.) 2 A DNP3 Link-Layer Frame was dropped, due to an invalid length. 3 A Transport-Layer Segment was dropped during reassembly. This happens when segments have invalid sequence numbers. 4 The DNP3 Reassembly buffer was cleared before a complete fragment could be reassembled. This happens when a segment carrying the "FIR" flag appears after some other segments have been queued. 5 A DNP3 Link-Layer Frame is larger than 260 bytes. 6 A DNP3 Link-Layer Frame uses an address that is reserved. 7 A DNP3 request or response uses a reserved function code. snort-2.9.6.0/doc/README.decoder_preproc_rules0000644000000000000000000000611211763666770015742 00000000000000Decoder and Preprocessor Rule Eventing ====================================== Decoder and preprocessor rules allow one to enable and disable decoder and preprocessor events on a rule by rule basis. They also allow one to specify the rule type or action of a decoder or preprocessor event on a rule by rule basis. Decoder config options will still determine whether or not to generate decoder events. For example, if 'config disable_decode_alerts' is in snort.conf, decoder events will not be generated regardless of whether or not there are corresponding rules for the event. Also note that if the decoder is configured to enable drops, e.g. 'config enable_decode_drops', these options will take precedence over the event type of the rule. A packet will be dropped if either a decoder config drop option is in snort.conf or the decoder or preprocessor rule type is 'drop'. Of course, the drop cases only apply if Snort is running inline. See 'doc/README.decode' for config options that control decoder events. Configuring =========== The decoder and preprocessor rules are located in the 'preproc_rules/' directory in the top level source tree, and have the names 'decoder.rules' and 'preprocessor.rules' respectively. These files are updated as new decoder and preprocessor events are added to Snort. To enable these rules in snort.conf, define the path to where the rules are located and uncomment the 'include' lines in snort.conf that reference the rules files: var PREPROC_RULE_PATH /path/to/preproc_rules ... include $PREPROC_RULE_PATH/preprocessor.rules include $PREPROC_RULE_PATH/decoder.rules To disable any rule, just comment it with a '#' or remove the rule completely from the file (commenting is recommended). To change the rule type or action of a decoder/preprocessor rule, just replace 'alert' with the desired rule type. Any one of the following rule types can be used: alert log pass drop sdrop reject For example one can change: alert ( msg: "DECODE_NOT_IPV4_DGRAM"; sid: 1; gid: 116; rev: 1; \ metadata: rule-type decode ; classtype:protocol-command-decode;) to drop ( msg: "DECODE_NOT_IPV4_DGRAM"; sid: 1; gid: 116; rev: 1; \ metadata: rule-type decode ; classtype:protocol-command-decode;) to drop (as well as alert on) packets where the Ethernet protocol is IPv4 but version field in IPv4 header has a value other than 4. See README.decode, README.gre and the various preprocessor READMEs for descriptions of the rules in 'decoder.rules' and 'preprocessor.rules'. Reverting to original behavior ============================== The following config option in snort.conf will make Snort revert to the old behavior: config autogenerate_preprocessor_decoder_rules Note that if you want to revert to the old behavior, you also have to remove the decoder and preprocessor rules and any reference to them from snort.conf, otherwise they will be loaded. This option applies to rules not specified and the default behavior is to alert. Suppression and Thresholding ============================ The use of decoder and preprocessor rules does not change suppression and thresholding behavior. snort-2.9.6.0/doc/README.decode0000755000000000000000000002544312232305204012575 00000000000000Overview ======== Decoding is one of the first processes a packet goes through in Snort. The decoder has the job of determining which underlying protocols are used in the packet (such as Ethernet, IP, TCP, etc.) and saves this data along with the location of the payload/application data in the packet (which it doesn't try to decode) and the size of this payload for use by the preprocessor and detection engines. As the decoder steps through the packet headers, it also looks for errors or anomolies in the fields of these headers, which if configured in snort.conf, can be alerted upon and even dropped if Snort is running in inline mode. For example, if the Ethernet protocol field points to IPv4, but the size of the packet that was captured (after the Ethernet header) is less than 20 bytes (the minimum length for an IPv4 header), Snort will (by default) generate an alert and move the packet out of the decoding phase. While Snort doesn't alert on bad checksums, whether or not Snort is checking them affects how the system responds to packets that have been flagged as having bad checksums. Stream and Frag will not process packets that have been flagged as having bad checksums. Note: To disable decoding of GRE encapsulated traffic, pass --disable-gre to configure, and to disable decoding of MPLS encapsulated traffic, pass -disable-mpls to configure. Configuration ============= The following lists the options available for configuring the decoder. "disable" options mean that those alerts are enabled by default and "enable" options mean they are disabled by default. Snort must be running in inline mode for the "drops" options to have any effect. Also, note that alerting must be enabled for the particular alert/drop option pair in order for the "drops" options to work. - Options: disable_decode_alerts - By default, decoder alerts are enabled - use this option to disable these alerts. enable_decode_drops - If in inline mode, drop packets that are alerted on. disable_ipopt_alerts - Disable alerts generated due to bad IP options. enable_ipopt_drops - Drop packets that are alerted on due to bad IP options. disable_tcpopt_alerts - Disable alerts generated due to bad TCP options. enable_tcpopt_drops - Drop packets that are alerted on due to bad TCP options. disable_ttcp_alerts - Disable alerts generated due to detection of T/TCP. enable_ttcp_drops - Drop packets that are alerted on due to T/TCP detection. disable_tcpopt_obsolete_alerts - Disable alerts generated due to detection of obsolete TCP options - Skeeter, Bubba and Unassigned. enable_tcpopt_obsolete_drops - Drop packets that are alerted on due to obsolete TCP options. disable_tcpopt_experimental_alerts - Disable alerts generated due to detection of experimental TCP options (kinds 9,10,15,20,21,22,23,24 - see http://www.iana.org/assignments/tcp-parameters for what these are). enable_tcpopt_experimental_drops - Drop packets that are alerted on due to experimental TCP options. enable_decode_oversized_alerts - Enable alerts generated due to the length field (IP, TCP, UDP) indicating a larger packet than we captured. Note that this is the only decoder alert option that is disabled by default. enable_decode_oversized_drops - Drop packets that are alerted on due to the header length field indicating a larger packet than we captured. checksum_mode: all|none|noip|notcp|noudp|noicmp|ip|tcp|udp|icmp - By default checksums are computed for IP, TCP, UDP and ICMP. Use this option to disable checksum checking of specific protocols. Use a space separated list. checksum_drop: all|none|noip|notcp|noudp|noicmp|ip|tcp|udp|icmp - By default packets with bad checksums are not dropped if in inline mode. Use a space separated list. Note that Snort must be doing checksums for a particular protocol in order to drop packets with bad checksums for that protocol. Example configurations ====================== To enable oversized alerts: config enable_decode_oversized_alerts To enable drops on decode events: config enable_decode_drops config enable_decode_oversized_alerts config enable_decode_oversized_drops To disable TCP option alerts: config disable_tcpopt_alerts config disable_tcpopt_obsolete_alerts config disable_tcpopt_experimental_alerts To disable IP and TCP checksum checking config checksum_mode: noip notcp To drop all packets that have bad checksums config checksum_drop: all Alerts ====== The decoder uses generator ID 116. The list of SIDs is as follows for each type of alert: decode_alerts SID Description --- ----------- 1 Ethernet protocol is IPv4 but version field in IPv4 header has a value other than 4 2 IPv4 header length field contains a value that is less than 20 bytes (the minimum IPv4 header length) 3 IPv4 length field contains a value that is larger than the captured length of the packet (starting from IPv4 header) 45 The length of the captured packet (starting from TCP header) is less than 20 bytes (the minimum TCP header length) 46 The value of the TCP offset field is less than 5 words (20 bytes) 95 The length of the captured packet (starting from UDP header) is less than 8 bytes (the UDP header length) 96 The value of the UDP length field is less than the size of a UDP header 97 UDP length field contains a value that is larger than the captured length of the packet (starting from UDP header) 105 The length of the captured packet (starting from ICMP header) is less than minimum header length for that ICMP type 106 The length of the payload (starting from ICMP header) is less than minimum header length for ICMP Timestamp Request and Reply types 107 The length of the payload (starting from ICMP header) is less than minimum header length for ICMP Address Mask Request and Reply types 109 The length of the captured packet (starting from ARP header) is less than the length of an ARP header 110 The length of the captured packet (starting from EAPOL header) is less than the length of an EAPOL header 111 The length of the captured packet (starting from EAP key) is less than the length of an EAP key 112 The length of the captured packet (starting from EAP header) is less than the length of an EAP header 120 The length of the captured packet (starting from PPPoE header) is less than the length of a PPPoE header 130 The length of the captured packet (starting from VLAN header) is less than the length of a VLAN (802.1q) header 131 The length of the captured packet (starting from VLAN header) is less than the length of a VLAN (802.1q) header plus the LLC header 132 The length of the captured packet (starting from VLAN header) is less than the length of a VLAN (802.1q) header plus the LLC header plus the SNAP header 133 The length of the captured packet (starting from 802.11 header) is less than the length of a 802.11 data header plus LLC header 140 The length of the captured packet (starting from Token Ring header) is less than the length of a Token Ring header 141 The length of the captured packet (starting from Token Ring header) is less than the length of a Token Ring header plus LLC header 142 The length of the captured packet (starting from Token Ring header) is less than the length of a Token Ring header plus LLC header plus MR header plus value of length field in MR header 143 The length of the captured packet (starting from Token Ring header) is less than the length of a Token Ring header plus LLC header plus MR header 150 The source and/or destination IPv4 address are the loopback address (127.0.0.1) 151 The source and destination IPv4 addresses are the same 250 The length of the captured packet (starting from the ICMP encapsulated IP header) is less than the minimum length of an IPv4 header 251 The encapsulated IPv4 header of an ICMP packet has a value other than 4 in version field 252 The length of the captured packet (starting from the ICMP encapsulated IP header) is less than the ICMP encapsulated IP header length 253 The ICMP encapsulated IP payload is less than 64 bits (at least 64 bits must be included - RFC 792) 254 The ICMP encapsulated IP payload is greater than 576 bytes 255 The ICMP encapsulated IP was fragmented, but the fragment offset is not 0 (an ICMP message is only returned for the first fragment) If GRE is enabled (--disable-gre was not given to configure) 160 The length of the captured packet (starting from GRE header) is less than the length of a GRE header 161 There are multiple GRE encapsulations in the packet (currently not allowed) 162 GRE version in packet is not 0 or 1. 163 Flags in header are set that should be unset. 164 For PPtP, the ether type is not PPP. 165 For Transparent Ethernet Bridging, the length of the captured packet (starting from the Transparent Ethernet Bridging header) is less than the length of a Transparent Ethernet Bridging header. ipopt_alerts SID Message --- ------- 4 A bad length was found in IPv4 options 5 Truncated IPv4 options tcpopt_alerts SID Message --- ------- 54 A bad length was found in TCP options 55 Truncated TCP options ttcp_alerts SID Message --- ------- 56 T/TCP was detected tcpopt_obsolete_alerts SID Message --- ------- 57 Obsolete TCP options found tcpopt_experimental_alerts SID Message --- ------- 58 Experimental TCP options found decode_oversized_alerts SID Message --- ------- 6 The IPv4 length field contains a value that is greater than the length of the captured packet (starting from the IPv4 header) 47 The TCP header length field contains a value that is greater than the length of the captured packet (starting from the TCP header) 98 The UDP header length field contains a value that is greater than the length of the captured packet (starting from the UDP header) snort-2.9.6.0/doc/README.dcerpc20000644000000000000000000014227312260355636012711 00000000000000DCE/RPC 2 Preprocessor ================================================================================ The main purpose of the preprocessor is to perform SMB desegmentation and DCE/RPC defragmentation to avoid rule evasion using these techniques. SMB desegmentation is performed for the following commands that can be used to transport DCE/RPC requests and responses: Write, Write Block Raw, Write and Close, Write AndX, Transaction, Transaction Secondary, Read, Read Block Raw and Read AndX. The following transports are supported for DCE/RPC: SMB, TCP, UDP and RPC over HTTP v.1 proxy and server. New rule options have been implemented to improve performance, reduce false positives and reduce the count and complexity of DCE/RPC based rules. Sections: Dependency Requirements Target Based Configuration Events Rule Options Dependency Requirements ================================================================================ For proper functioning of the preprocessor: The dcerpc preprocessor (the initial iteration) must be disabled. Stream session tracking must be enabled, i.e. stream5. The preprocessor requires a session tracker to keep its data. Stream reassembly must be performed for TCP sessions. If it is decided that a session is SMB or DCE/RPC, either through configured ports, servers or autodetecting, the dcerpc2 preprocessor will enable stream reassembly for that session if necessary. IP defragmentation should be enabled, i.e. the frag3 preprocessor should be enabled and configured. Target Based ================================================================================ There are enough important differences between Windows and Samba versions that a target based approach has been implemented. Some important differences: Named pipe instance tracking A combination of valid login handle or UID, share handle or TID and file/named pipe handle or FID must be used to write data to a named pipe. The binding between these is dependent on OS/software version. Samba 3.0.22 and earlier Any valid UID and TID, along with a valid FID can be used to make a request, however, if the TID used in creating the FID is deleted (via a tree disconnect), the FID that was created using this TID becomes invalid, i.e. no more requests can be written to that named pipe instance. Samba greater than 3.0.22 Any valid TID, along with a valid FID can be used to make a request. However, only the UID used in opening the named pipe can be used to make a request using the FID handle to the named pipe instance. If the TID used to create the FID is deleted (via a Tree Disconnect), the FID that was created using this TID becomes invalid, i.e. no more requests can be written to that named pipe instance. If the UID used to create the named pipe instance is deleted (via a Logoff AndX), since it is necessary in making a request to the named pipe, the FID becomes invalid. Windows 2003 Windows XP Windows Vista These Windows versions require strict binding between the UID, TID and FID used to make a request to a named pipe instance. Both the UID and TID used to open the named pipe instance must be used when writing data to the same named pipe instance. Therefore, deleting either the UID or TID invalidates the FID. Windows 2000 Windows 2000 is interesting in that the first request to a named pipe must use the same binding as that of the other Windows versions. However, requests after that follow the same binding as Samba 3.0.22 and earlier, i.e. no binding. It also follows Samba greater than 3.0.22 in that deleting the UID or TID used to create the named pipe instance also invalidates it. Accepted SMB commands Samba in particular does not recognize certain commands under an IPC$ tree. Samba (all versions) Under an IPC$ tree, does not accept: Open Write And Close Read Read Block Raw Write Block Raw Windows (all versions) Accepts all of the above commands under an IPC$ tree. AndX command chaining Windows is very strict in what command combinations it allows to be chained. Samba, on the other hand, is very lax and allows some nonsensical combinations, e.g. multiple logins and tree connects (only one place to return handles for these), login/logoff and tree connect/tree disconnect. Ultimately, we don't want to keep track of data that the server won't accept. An evasion possibility would be accepting a fragment in a request that the server won't accept that gets sandwiched between an exploit. Transaction tracking The differences between a Transaction request and using one of the Write* commands to write data to a named pipe are that (1) a Transaction performs the operations of a write and a read from the named pipe, whereas in using the Write* commands, the client has to explicitly send one of the Read* requests to tell the server to send the response and (2) a Transaction request is not written to the named pipe until all of the data is received (via potential Transaction Secondary requests) whereas with the Write* commands, data is written to the named pipe as it is received by the server. Multiple Transaction requests can be made simultaneously to the same named pipe. These requests can also be segmented with Transaction Secondary commands. What distinguishes them (when the same named pipe is being written to, i.e. having the same FID) are fields in the SMB header representing a process id (PID) and multiplex id (MID). The PID represents the process this request is a part of. An MID represents different sub-processes within a process (or under a PID). Segments for each "thread" are stored separately and written to the named pipe when all segments are received. It is necessary to track this so as not to munge these requests together (which would be a potential evasion opportunity). Windows (all versions) Uses a combination of PID and MID to define a "thread". Samba (all versions) Uses just the MID to define a "thread". Multliple Bind requests A Bind request is the first request that must be made in a connection-oriented DCE/RPC session in order to specify the interface/interfaces that one wants to communicate with. Windows (all versions) For all of the Windows versions, only one Bind can ever be made on a session whether or not it succeeds or fails. Any binding after that must use the Alter Context request. If another Bind is made, all previous interface bindings are invalidated. Samba 3.0.20 and earlier Any amount of Bind requests can be made. Samba later than 3.0.20 Another Bind request can be made if the first failed and no interfaces were successfully bound to. If a Bind after a successful Bind is made, all previous interface bindings are invalidated. DCE/RPC Fragmented requests - Context ID Each fragment in a fragmented request carries the context id of the bound interface it wants to make the request to. Windows (all versions) The context id that is ultimately used for the request is contained in the first fragment. The context id field in any other fragment can contain any value. Samba (all versions) The context id that is ultimately used for the request is contained in the last fragment. The context id field in any other fragment can contain any value. DCE/RPC Fragmented requests - Operation number Each fragment in a fragmented request carries an operation number (opnum) which is more or less a handle to a function offered by the interface. Samba (all versions) Windows 2000 Windows 2003 Windows XP The opnum that is ultimately used for the request is contained in the last fragment. The opnum field in any other fragment can contain any value. Windows Vista The opnum that is ultimately used for the request is contained in the first fragment. The opnum field in any other fragment can contain any value. DCE/RPC Stub data byte order The byte order of the stub data is determined differently for Windows and Samba. Windows (all versions) The byte order of the stub data is that which was used in the Bind request. Samba (all versions) The byte order of the stub data is that which is used in the request carrying the stub data. Configuration ================================================================================ The dcerpc2 preprocessor has a global configuration and one or more server configurations. The global preprocessor configuration name is dcerpc2 and the server preprocessor configuration name is dcerpc2_server. Global configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ preprocessor dcerpc2 The global dcerpc2 configuration is required. Only one global dcerpc2 configuration can be specified. Option syntax Option Argument Required Default ---------------------------------------------------------------------------- memcap NO memcap 102400 disable_defrag NONE NO OFF max_frag_len NO OFF events NO OFF reassemble_threshold NO OFF disabled NONE NO OFF smb_fingerprint_policy NO OFF memcap = 1024-4194303 (kilobytes) max-frag-len = 1514-65535 events = pseudo-event | event | '[' event-list ']' pseudo-event = "none" | "all" event-list = event | event ',' event-list event = "memcap" | "smb" | "co" | "cl" re-thresh = 0-65535 fp-policy = "server" | "client" | "both" Option explanations memcap Specifies the maximum amount of run-time memory that can be allocated. Run-time memory includes any memory allocated after configuration. Default is 100 MB. disabled This optional keyword is allowed with any policy to avoid packet processing. This option disables the preprocessor. When the preprocessor is disabled only the memcap option is applied when specified with the configuration. The other options are parsed but not used. Any valid configuration may have "disabled" added to it. disable_defrag Tells the preprocessor not to do DCE/RPC defragmentation. Default is to do defragmentation. max_frag_len Specifies the maximum fragment size that will be added to the defragmentation module. If a fragment is greater than this size, it is truncated before being added to the defragmentation module. The allowed ranges for this option are 1514 - 65535. events Specifies the classes of events to enable. (See Events section for an enumeration and explanation of events.) memcap Only one event. If the memcap is reached or exceeded, alert. smb Alert on events related to SMB processing. co Stands for connection-oriented DCE/RPC. Alert on events related to connection-oriented DCE/RPC processing. cl Stands for connectionless DCE/RPC. Alert on events related to connectionless DCE/RPC processing. reassemble_threshold Specifies a minimum number of bytes in the DCE/RPC desegmentation and defragmentation buffers before creating a reassembly packet to send to the detection engine. This option is useful in inline mode so as to potentially catch an exploit early before full defragmentation is done. A value of 0 supplied as an argument to this option will, in effect, disable this option. Default is disabled. smb_fingerprint_policy In the initial phase of an SMB session, the client needs to authenticate with a SessionSetupAndX. Both the request and response to this command contain OS and version information that can allow the preprocessor to dynamically set the policy for a session which allows for better protection against Windows and Samba specific evasions. Option examples memcap 30000 max_frag_len 16840 events none events all events smb events co events [co] events [smb, co] events [memcap, smb, co, cl] reassemble_threshold 500 smb_fingerprint_policy both smb_fingerprint_policy client Configuration examples preprocessor dcerpc2 preprocessor dcerpc2: memcap 500000 preprocessor dcerpc2: max_frag_len 16840, memcap 300000, events smb preprocessor dcerpc2: memcap 50000, events [memcap, smb, co, cl], \ max_frag_len 14440 preprocessor dcerpc2: disable_defrag, events [memcap, smb] preprocessor dcerpc2: reassemble_threshold 500 preprocessor dcerpc2: memcap 50000, events [memcap, smb, co, cl], \ max_frag_len 14440, smb_fingerprint_policy both Default configuration preprocessor dcerpc2: memcap 102400 Server Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ preprocessor dcerpc2_server The dcerpc2_server configuration is optional. A dcerpc2_server configuration must start with default or net options. The default and net options are mutually exclusive. At most one default configuration can be specified. If no default configuration is specified, default values will be used for the default configuration. Zero or more net configurations can be specified. For any dcerpc2_server configuration, if non-required options are not specified, the defaults will be used. When processing DCE/RPC traffic, the default configuration is used if no net configurations match. If a net configuration matches, it will override the default configuration. A net configuration matches if the packet's server IP address matches an IP address or net specified in the net configuration. The net option supports IPv6 addresses. Note that port and ip variables defined in snort.conf CANNOT be used. Option syntax Option Argument Required Default ---------------------------------------------------------------------------- default NONE YES NONE net YES NONE policy NO policy WinXP detect NO detect \ [smb [139,445], \ tcp 135, udp 135, \ rpc-over-http-server 593] autodetect NO autodetect \ [tcp 1025:, udp 1025:, \ rpc-over-http-server 1025:] no_autodetect_http_proxy_ports NONE NO DISABLED (The preprocessor autodetects on all proxy ports by default) smb_invalid_shares NO NONE smb_max_chain NO smb_max_chain 3 smb_file_inspection NO smb_file_inspection off net = ip | '[' ip-list ']' ip-list = ip | ip ',' ip-list ip = ip-addr | ip-addr '/' prefix | ip4-addr '/' netmask ip-addr = ip4-addr | ip6-addr ip4-addr = a valid IPv4 address ip6-addr = a valid IPv6 address (can be compressed) prefix = a valid CIDR netmask = a valid netmask policy = "Win2000" | "Win2003" | "WinXP" | "WinVista" | "Samba" | "Samba-3.0.22" | "Samba-3.0.20" detect = "none" | detect-opt | '[' detect-list ']' detect-list = detect-opt | detect-opt ',' detect-list detect-opt = transport | transport port-item | transport '[' port-list ']' transport = "smb" | "tcp" | "udp" | "rpc-over-http-proxy" | "rpc-over-http-server" port-list = port-item | port-item ',' port-list port-item = port | port-range port-range = ':' port | port ':' | port ':' port port = 0-65535 shares = share | '[' share-list ']' share-list = share | share ',' share-list share = word | '"' word '"' | '"' var-word '"' word = graphical ascii characters except ',' '"' ']' '[' '$' var-word = graphical ascii characters except ',' '"' ']' '[' Because the Snort main parser treats '$' as the start of a variable and tries to expand it, shares with '$' must be enclosed quotes. max-chain = 0-255 file-inspect = file-arg | '[' file-list ']' file-arg = "off" | "on" | "only" file-list = file-arg [ ',' "file-depth" ] Option explanations default Specifies that this configuration is for the default server configuration. net Specifies that this configuration is an IP or net specific configuration. The configuration will only apply to the IP addresses and nets supplied as an argument. policy Specifies the target-based policy to use when processing. Default is "WinXP". detect Specifies the DCE/RPC transport and server ports that should be detected on for the transport. Defaults are ports 139 and 445 for SMB, 135 for TCP and UDP, 593 for RPC over HTTP server and 80 for RPC over HTTP proxy. autodetect Specifies the DCE/RPC transport and server ports that the preprocessor should attempt to autodetect on for the transport. The autodetect ports are only queried if no detect transport/ports match the packet. The order in which the preprocessor will attempt to autodetect will be - TCP/UDP, RPC over HTTP server, RPC over HTTP proxy and lastly SMB. Note that most dynamic DCE/RPC ports are above 1024 and ride directly over TCP or UDP. It would be very uncommon to see SMB on anything other than ports 139 and 445. Defaults are 1025-65535 for TCP, UDP and RPC over HTTP server. no_autodetect_http_proxy_ports By default, the preprocessor will always attempt to autodetect for ports specified in the detect configuration for rpc-over-http-proxy. This is because the proxy is likely a web server and the preprocessor should not look at all web traffic. This option is useful if the RPC over HTTP proxy configured with the detect option is only used to proxy DCE/RPC traffic. Default is to autodetect on RPC over HTTP proxy detect ports. smb_invalid_shares Specifies SMB shares that the preprocessor should alert on if an attempt is made to connect to them via a Tree Connect or Tree Connect AndX. Default is empty. smb_max_chain Specifies the maximum amount of AndX command chaining that is allowed before an alert is generated. Default maximum is 3 chained commands. A value of 0 disables this option. smb_file_inspection Instructs the preprocessor to do inspection of normal SMB file transfers. This includes doing file type and signature through the file API as well as setting a pointer for the "file_data" rule option. Note that the "file-depth" option only applies to the maximum amount of file data for which it will set the pointer for the "file_data" rule option. For file type and signature it will use the value configured for the file API. If "only" is specified, the preprocessor will only do SMB file inspection, i.e. it will not do any DCE/RPC tracking or inspection. If "on" is specified with no arguments, the default file depth is 16384 bytes. An argument of -1 to "file-depth" disables setting the pointer for "file_data", effectively disabling SMB file inspection in rules. An argument of 0 to "file-depth" means unlimited. Default is "off", i.e. no SMB file inspection is done in the preprocessor. Option examples net 192.168.0.10 net 192.168.0.0/24 net [192.168.0.0/24] net 192.168.0.0/255.255.255.0 net feab:45b3:ab92:8ac4:d322:007f:e5aa:7845 net feab:45b3:ab92:8ac4:d322:007f:e5aa:7845/128 net feab:45b3::/32 net [192.168.0.10, feab:45b3::/32] net [192.168.0.0/24, feab:45b3:ab92:8ac4:d322:007f:e5aa:7845] policy Win2000 policy Samba-3.0.22 detect none detect smb detect [smb] detect smb 445 detect [smb 445] detect smb [139,445] detect [smb [139,445]] detect [smb, tcp] detect [smb 139, tcp [135,2103]] detect [smb [139,445], tcp 135, udp 135, \ rpc-over-http-server [593,6002:6004]] autodetect none autodetect tcp autodetect [tcp] autodetect tcp 2025: autodetect [tcp 2025:] autodetect tcp [2025:3001,3003:] autodetect [tcp [2025:3001,3003:]] autodetect [tcp, udp] autodetect [tcp 2025:, udp 2025:] autodetect [tcp 2025:, udp, rpc-over-http-server [1025:6001,6005:]] smb_invalid_shares private smb_invalid_shares "private" smb_invalid_shares "C$" smb_invalid_shares [private, "C$"] smb_invalid_shares ["private", "C$"] smb_max_chain 1 smb_file_inspection on smb_file_inspection off smb_file_inspection [ on, file-depth -1 ] smb_file_inspection [ on, file-depth 0 ] smb_file_inspection [ on, file-depth 4294967296 ] smb_file_inspection [ only, file-depth -1 ] Configuration examples preprocessor dcerpc2_server: default preprocessor dcerpc2_server: default, policy Win2000 preprocessor dcerpc2_server: default, policy Win2000, detect [smb, tcp], \ autodetect tcp 1025:, smb_invalid_shares ["C$", "D$", "ADMIN$"] preprocessor dcerpc2_server: net 10.4.10.0/24, policy Win2000 preprocessor dcerpc2_server: net [10.4.10.0/24,feab:45b3::/126], \ policy WinVista, smb_max_chain 1 preprocessor dcerpc2_server: net [10.4.10.0/24,feab:45b3::/126], \ policy WinVista, detect [smb, tcp, rpc-over-http-proxy 8081], \ autodetect [tcp, rpc-over-http-proxy [1025:6001,6005:]], \ smb_invalid_shares ["C$", "ADMIN$"], no_autodetect_http_proxy_ports preprocessor dcerpc2_server: net [10.4.11.56,10.4.11.57], policy Samba, \ detect smb, autodetect none preprocessor dcerpc2_server: default, policy WinXP, \ smb_file_inspection [ on, file-depth 0 ] Default configuration preprocessor dcerpc2_server: default, policy WinXP, \ detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server 593], \ autodetect [tcp 1025:, udp 1025:, rpc-over-http-server 1025:], \ smb_max_chain 3, smb_file_inspection off Complete dcerpc2 default configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ preprocessor dcerpc2: memcap 102400 preprocessor dcerpc2_server: default, policy WinXP, \ detect [smb [139,445], tcp 135, udp 135, rpc-over-http-server 593], \ autodetect [tcp 1025:, udp 1025:, rpc-over-http-server 1025:], \ smb_max_chain 3, smb_file_inspection off Events ================================================================================ The preprocessor uses GID 133 to register events. Memcap events SID Description -------------------------------------------------------------------------------- 1 If the memory cap is reached and the preprocessor is configured to alert. SMB events SID Description -------------------------------------------------------------------------------- 2 An invalid NetBIOS Session Service type was specified in the header. Valid types are: Message, Request (only from client), Positive Response (only from server), Negative Response (only from server), Retarget Response (only from server) and Keep Alive. 3 An SMB message type was specified in the header. Either a request was made by the server or a response was given by the client. 4 The SMB id does not equal "\xffSMB". Note that since the preprocessor does not yet support SMB2, id of "\xfeSMB" is turned away before an eventable point is reached. 5 The word count of the command header is invalid. SMB commands have pretty specific word counts and if the preprocessor sees a command with a word count that doesn't jive with that command, the preprocessor will alert. 6 Some commands require a minimum number of bytes after the command header. If a command requires this and the byte count is less than the minimum required byte count for that command, the preprocessor will alert. 7 Some commands, especially the commands from the SMB Core implementation require a data format field that specifies the kind of data that will be coming next. Some commands require a specific format for the data. The preprocessor will alert if the format is not that which is expected for that command. 8 Many SMB commands have a field containing an offset from the beginning of the SMB header to where the data the command is carrying starts. If this offset puts us before data that has already been processed or after the end of payload, the preprocessor will alert. 9 Some SMB commands, such as Transaction, have a field containing the total amount of data to be transmitted. If this field is zero, the preprocessor will alert. 10 The preprocessor will alert if the NetBIOS Session Service length field contains a value less than the size of an SMB header. 11 The preprocessor will alert if the remaining NetBIOS packet length is less than the size of the SMB command header to be decoded. 12 The preprocessor will alert if the remaining NetBIOS packet length is less than the size of the SMB command byte count specified in the command header. 13 The preprocessor will alert if the remaining NetBIOS packet length is less than the size of the SMB command data size specified in the command header. 14 The preprocessor will alert if the total data count specified in the SMB command header is less than the data size specified in the SMB command header. (Total data count must always be greater than or equal to current data size.) 15 The preprocessor will alert if the total amount of data sent in a transaction is greater than the total data count specified in the SMB command header. 16 The preprocessor will alert if the byte count specified in the SMB command header is less than the data size specified in the SMB command. (The byte count must always be greater than or equal to the data size.) 17 Some of the Core Protocol commands (from the initial SMB implementation) require that the byte count be some value greater than the data size exactly. The preprocessor will alert if the byte count minus a predetermined amount based on the SMB command is not equal to the data size. 18 For the Tree Connect command (and not the Tree Connect AndX command), the preprocessor has to queue the requests up and wait for a server response to determine whether or not an IPC share was successfully connected to (which is what the preprocessor is interested in). Unlike the Tree Connect AndX response, there is no indication in the Tree Connect response as to whether the share is IPC or not. There should be under normal circumstances no more than a few pending tree connects at a time and the preprocessor will alert if this number is excessive. 19 After a client is done writing data using the Write* commands, it issues a Read* command to the server to tell it to send a response to the data it has written. In this case the preprocessor is concerned with the server response. The Read* request contains the file id associated with a named pipe instance that the preprocessor will ultimately send the data to. The server response, however, does not contain this file id, so it need to be queued with the request and dequeued with the response. If multiple Read* requests are sent to the server, they are responded to in the order they were sent. There should be under normal circumstances no more than a few pending Read* requests at a time and the preprocessor will alert if this number is excessive. 20 The preprocessor will alert if the number of chained commands in a single request is greater than or equal to the configured amount (default is 3). 21 With AndX command chaining it is possible to chain multiple Session Setup AndX commands within the same request. There is, however, only one place in the SMB header to return a login handle (or Uid). Windows does not allow this behavior, however Samba does. This is anomalous behavior and the preprocessor will alert if it happens. 22 With AndX command chaining it is possible to chain multiple Tree Connect AndX commands within the same request. There is, however, only one place in the SMB header to return a tree handle (or Tid). Windows does not allow this behavior, however Samba does. This is anomalous behavior and the preprocessor will alert if it happens. 23 When a Session Setup AndX request is sent to the server, the server responds (if the client successfully authenticates) which a user id or login handle. This is used by the client in subsequent requests to indicate that it has authenticated. A Logoff AndX request is sent by the client to indicate it wants to end the session and invalidate the login handle. With commands that are chained after a Session Setup AndX request, the login handle returned by the server is used for the subsequent chained commands. The combination of a Session Setup AndX command with a chained Logoff AndX command, essentially logins in and logs off in the same request and is anomalous behavior. The preprocessor will alert if it sees this. 24 A Tree Connect AndX command is used to connect to a share. The Tree Disconnect command is used to disconnect from that share. The combination of a Tree Connect AndX command with a chained Tree Disconnect command, essentially connects to a share and disconnects from the same share in the same request and is anomalous behavior. The preprocessor will alert if it sees this. 25 An Open AndX or Nt Create AndX command is used to open/create a file or named pipe. (The preprocessor is only interested in named pipes as this is where DCE/RPC requests are written to.) The Close command is used to close that file or named pipe. The combination of a Open AndX or Nt Create AndX command with a chained Close command, essentially opens and closes the named pipe in the same request and is anomalous behavior. The preprocessor will alert if it sees this. 26 The preprocessor will alert if it sees any of the invalid SMB shares configured. It looks for a Tree Connect or Tree Connect AndX to the share. 48 The preprocessor will alert if a data count for a Core dialect write command is zero. 49 For some of the Core dialect commands such as Write and Read, there are two data count fields, one in the main command header and one in the data format section. If these aren't the same, the preprocessor will alert. 50 In the initial negotiation phase of an SMB session, the server in a Negotiate response and the client in a SessionSetupAndX request will advertise the maximum number of outstanding requests supported. The preprocessor will alert if the lesser of the two is exceeded. 51 When a client sends a request it uses a value called the MID (multiplex id) to match a response, which the server is supposed to echo, to a request. If there are multiple outstanding requests with the same MID, the preprocessor will alert. 52 In the Negotiate request a client gives a list of SMB dialects it supports, normally in order from least desirable to most desirable and the server responds with the index of the dialect to be used on the SMB session. Anything less than "NT LM 0.12" would be very odd these days (even Windows 98 supports it) and the preprocessor will alert if the client doesn't offer it as a supported dialect or the server chooses a lesser dialect. 53 There are a number of commands that are considered deprecated and/or obsolete by Microsoft (see MS-CIFS and MS-SMB). If the preprocessor detects the use of a deprecated/obsolete command used it will alert. 54 There are some commands that can be used that can be considered unusual in the context they are used. These include some of the transaction commands such as: SMB_COM_TRANSACTION / TRANS_READ_NMPIPE SMB_COM_TRANSACTION / TRANS_WRITE_NMPIPE SMB_COM_TRANSACTION2 / TRANS2_OPEN2 SMB_COM_NT_TRANSACT / NT_TRANSACT_CREATE The preprocessor will alert if it detects unusual use of a command. 55 Transaction commands have a setup count field that indicates the number of 16bit words in the transaction setup. The preprocessor will alert if the setup count is invalid for the transaction command / sub command. 56 There can be only one Negotiate transaction per session and it is the first thing a client and server do to determine the SMB dialect each supports. The preprocessor will alert if the client attempts multiple dialect negotiations. 57 Malware will often set a file's attributes to ReadOnly/Hidden/System if it is successful in installing itself as a Windows service or is able to write an autorun.inf file since it doesn't want the user to see the file and the default folder options in Windows is not to display Hidden files. The preprocessor will alert if it detects a client attempt to set a file's attributes to ReadOnly/Hidden/System. Connection-oriented DCE/RPC events SID Description -------------------------------------------------------------------------------- 27 The preprocessor will alert if the connection-oriented DCE/RPC major version contained in the header is not equal to 5. 28 The preprocessor will alert if the connection-oriented DCE/RPC minor version contained in the header is not equal to 0. 29 The preprocessor will alert if the connection-oriented DCE/RPC PDU type contained in the header is not a valid PDU type. 30 The preprocessor will alert if the fragment length defined in the header is less than the size of the header. 31 The preprocessor will alert if the remaining fragment length is less than the remaining packet size. 32 The preprocessor will alert if in a Bind or Alter Context request, there are no context items specified. 33 The preprocessor will alert if in a Bind or Alter Context request, there are no transfer syntaxes to go with the requested interface. 34 The preprocessor will alert if a non-last fragment is less than the size of the negotiated maximum fragment length. Most evasion techniques try to fragment the data as much as possible and usually each fragment comes well below the negotiated transmit size. 35 The preprocessor will alert if a fragment is larger than the maximum negotiated fragment length. 36 The byte order of the request data is determined by the Bind in connection-oriented DCE/RPC for Windows. It is anomalous behavior to attempt to change the byte order mid-session. 37 The call id for a set of fragments in a fragmented request should stay the same (it is incremented for each complete request). The preprocessor will alert if it changes in a fragment mid-request. 38 The operation number specifies which function the request is calling on the bound interface. If a request is fragmented, this number should stay the same for all fragments. The preprocessor will alert if the opnum changes in a fragment mid-request. 39 The context id is a handle to a interface that was bound to. If a request if fragmented, this number should stay the same for all fragments. The preprocessor will alert if the context id changes in a fragment mid-request. Connectionless DCE/RPC events SID Description -------------------------------------------------------------------------------- 40 The preprocessor will alert if the connectionless DCE/RPC major version is not equal to 4. 41 The preprocessor will alert if the connectionless DCE/RPC pdu type is not a valid pdu type. 42 The preprocessor will alert if the packet data length is less than the size of the connectionless header. 43 The preprocessor will alert if the sequence number uses in a request is the same or less than a previously used sequence number on the session. In testing, wrapping the sequence number space produces strange behavior from the server, so this should be considered anomalous behavior. Rule Options ================================================================================ New rule options are supported by enabling the dcerpc2 preprocessor: dce_iface dce_opnum dce_stub_data New modifiers to existing byte_test and byte_jump rule options: byte_test: dce byte_jump: dce dce_iface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For DCE/RPC based rules it has been necessary to set flow-bits based on a client bind to a service to avoid false positives. It is necessary for a client to bind to a service before being able to make a call to it. When a client sendsa bind request to the server, it can, however, specify one or more service interfaces to bind to. Each interface is represented by a UUID. Each interface UUID is paired with a unique index (or context id) that future requests can use to reference the service that the client is making a call to. The server will respond with the interface UUIDs it accepts as valid and will allow the client to make requests to those services. When a client makes a request, it will specify the context id so the server knows what service the client is making a request to. Instead of using flow-bits, a rule can simply ask the preprocessor, using this rule option, whether or not the client has bound to a specific interface UUID and whether or not this client request is making a request to it. This can eliminate false positives where more than one service is bound to successfully since the preprocessor can correlate the bind UUID to the context id used in the request. A DCE/RPC request can specify whether numbers are represented as big endian or little endian. The representation of the interface UUID is different depending on the endianness specified in the DCE/RPC previously requiring two rules - one for big endian and one for little endian. The preprocessor eliminates the need for two rules by normalizing the UUID. An interface contains a version. Some versions of an interface may not be vulnerable to a certain exploit. Also, a DCE/RPC request can be broken up into 1 or more fragments. Flags (and a field in the connectionless header) are set in the DCE/RPC header to indicate whether the fragment is the first, a middle or the last fragment. Many checks for data in the DCE/RPC request are only relevant if the DCE/RPC request is a first fragment (or full request), since subsequent fragments will contain data deeper into the DCE/RPC request. A rule which is looking for data, say 5 bytes into the request (maybe it's a length field), will be looking at the wrong data on a fragment other than the first, since the beginning of subsequent fragments are already offset some length from the beginning of the request. This can be a source of false positives in fragmented DCE/RPC traffic. By default it is reasonable to only evaluate if the request is a first fragment (or full request). However, if the "any_frag" option is used to specify evaluating on all fragments. Syntax [ ',' ] [ ',' "any_frag" ] uuid = hexlong '-' hexshort '-' hexshort '-' 2hexbyte '-' 6hexbyte hexlong = 4hexbyte hexshort = 2hexbyte hexbyte = 2HEXDIGIT operator = '<' | '>' | '=' | '!' version = 0-65535 Examples dce_iface: 4b324fc8-1670-01d3-1278-5a47bf6ee188; dce_iface: 4b324fc8-1670-01d3-1278-5a47bf6ee188,<2; dce_iface: 4b324fc8-1670-01d3-1278-5a47bf6ee188,any_frag; dce_iface: 4b324fc8-1670-01d3-1278-5a47bf6ee188,=1,any_frag; This option is used to specify an interface UUID. Optional arguments are an interface version and operator to specify that the version be less than ('<'), greater than ('>'), equal to ('=') or not equal to ('!') the version specified. Also, by default the rule will only be evaluated for a first fragment (or full request, i.e. not a fragment) since most rules are written to start at the beginning of a request. The "any_frag" argument says to evaluate for middle and last fragments as well. This option requires tracking client Bind and Alter Context requests as well as server Bind Ack and Alter Context responses for connection-oriented DCE/RPC in the preprocessor. For each Bind and Alter Context request, the client specifies a list of interface UUIDs along with a handle (or context id) for each interface UUID that will be used during the DCE/RPC session to reference the interface. The server response indicates which interfaces it will allow the client to make requests to - it either accepts or rejects the client's wish to bind to a certain interface. This tracking is required so that when a request is processed, the context id used in the request can be correlated with the interface UUID it is a handle for. hexlong and hexshort will be specified and interpreted to be in big endian order (this is usually the default way an interface UUID will be seen and represented). As an example, the following Messenger interface UUID as taken off the wire from a little endian Bind request: |f8 91 7b 5a 00 ff d0 11 a9 b2 00 c0 4f b6 e6 fc| must be written as: 5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc The same UUID taken off the wire from a big endian Bind request: |5a 7b 91 f8 ff 00 11 d0 a9 b2 00 c0 4f b6 e6 fc| must be written the same way: 5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc This option matches if the specified interface UUID matches the interface UUID (as referred to by the context id) of the DCE/RPC request and if supplied, the version operation is true. This option will not match if the fragment is not a first fragment (or full request) unless the "any_frag" option is supplied in which case only the interface UUID and version need match. Note that a defragmented DCE/RPC request will be considered a full request. Using this rule option will automatically insert fast pattern contents into the fast pattern matcher. For UDP rules, the interface UUID, in both big and little endian format will be inserted into the fast pattern matcher. For TCP rules, (1) if the rule option "flow:to_server|from_client" is used, |05 00 00| will be inserted into the fast pattern matcher, (2) if the rule option "flow:from_server|to_client" is used, |05 00 02| will be inserted into the fast pattern matcher and (3) if the flow isn't known, |05 00| will be inserted into the fast pattern matcher. Note that if the rule already has content rule options in it, the best (meaning longest) pattern will be used. If a content in the rule uses the fast_pattern rule option, it will unequivocally be used over the above mentioned patterns. dce_opnum ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The opnum represents a specific function call to an interface. After is has been determined that a client has bound to a specific interface and is making a request to it (see above - dce_iface) usually we want to know what function call it is making to that service. It is likely that an exploit lies in the particular DCE/RPC function call. Syntax opnum-list = opnum-item | opnum-item ',' opnum-list opnum-item = opnum | opnum-range opnum-range = opnum '-' opnum opnum = 0-65535 Examples dce_opnum: 15; dce_opnum: 15-18; dce_opnum: 15,18-20; dce_opnum: 15,17,20-22; This option is used to specify an opnum (or operation number), opnum range or list containing either or both opnum and/or opnum-range. The opnum of a DCE/RPC request will be matched against the opnums specified with this option. This option matches if any one of the opnums specified match the opnum of the DCE/RPC request. dce_stub_data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since most DCE/RPC based rules had to do protocol decoding only to get to the DCE/RPC stub data, i.e. the remote procedure call or function call data, this option will alleviate this need and place the cursor at the beginning of the DCE/RPC stub data. This reduces the number of rule option checks and the complexity of the rule. This option takes no arguments. Example: dce_stub_data; This option is used to place the cursor (used to walk the packet payload in rules processing) at the beginning of the DCE/RPC stub data, regardless of preceding rule options. There are no arguments to this option. This option matches if there is DCE/RPC stub data. The cursor is moved to the beginning of the stub data. All ensuing rule options will be considered "sticky" to this buffer. The first rule option following dce_stub_data should use absolute location modifiers if it is position-dependent. Subsequent rule options should use a relative modifier if they are meant to be relative to a previous rule option match in the stub data buffer. Any rule option that does not specify a relative modifier will be evaluated from the start of the stub data buffer. To leave the stub data buffer and return to the main payload buffer, use the "pkt_data" rule option. byte_test and byte_jump ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A DCE/RPC request can specify whether numbers are represented in big or little endian. These rule options will take as a new argument "dce" and will work basically the same as the normal byte_test/byte_jump, but since the DCE/RPC preprocessor will know the endianness of the request, it will be able to do the correct conversion. byte_test --------- Syntax ',' [ '!' ] ',' \ [ ',' [ ',' "relative" ]] ',' "dce" convert = 1 | 2 | 4 operator = '<' | '=' | '>' | '&' | '^' value = 0-4294967295 offset = -65535 to 65535 Examples byte_test: 4,>,35000,0,relative,dce; byte_test: 2,!=,2280,-10,relative,dce; When using the "dce" argument to a byte_test, the following normal byte_test arguments will not be allowed: "big", "little", "string", "hex", "dec" and "oct". byte_jump --------- Syntax ',' [ ',' "relative" ] \ [ ',' "multiplier" ] [ ',' "align" ] \ [ ',' "post_offset" ] ',' "dce" convert = 1 | 2 | 4 offset = -65535 to 65535 mult-value = 0-65535 adjustment-value = -65535 to 65535 Examples byte_jump:4,-4,relative,align,multiplier 2,post_offset -4,dce; When using the dce argument to a byte_jump, the following normal byte_jump arguments will not be allowed: "big", "little", "string", "hex", "dec", "oct" and "from_beginning". Example of rule complexity reduction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following two rules using the new rule options replace 64 (set and isset flowbit) rules that are necessary if the new rule options are not used: alert tcp $EXTERNAL_NET any -> $HOME_NET [135,139,445,593,1024:] (msg:"dns R_Dnssrv funcs2 overflow attempt"; flow:established,to_server; dce_iface:50abc2a4-574d-40b3-9d66-ee4fd5fba076; dce_opnum:0-11; dce_stub_data; pcre:"/^.{12}(\x00\x00\x00\x00|.{12})/s"; byte_jump:4,-4,relative,align,dce; byte_test:4,>,256,4,relative,dce; reference:bugtraq,23470; reference:cve,2007-1748; classtype:attempted-admin; sid:1000068;) alert udp $EXTERNAL_NET any -> $HOME_NET [135,1024:] (msg:"dns R_Dnssrv funcs2 overflow attempt"; flow:established,to_server; dce_iface:50abc2a4-574d-40b3-9d66-ee4fd5fba076; dce_opnum:0-11; dce_stub_data; pcre:"/^.{12}(\x00\x00\x00\x00|.{12})/s"; byte_jump:4,-4,relative,align,dce; byte_test:4,>,256,4,relative,dce; reference:bugtraq,23470; reference:cve,2007-1748; classtype:attempted-admin; sid:1000069;) snort-2.9.6.0/doc/README.daq0000644000000000000000000000733012153454767012134 00000000000000Snort 2.9 introduces the DAQ, or Data Acquisition library, for packet I/O. The DAQ replaces direct calls to libpcap functions with an abstraction layer that facilitates operation on a variety of hardware and software interfaces without requiring changes to Snort. It is possible to select the DAQ type and mode when invoking Snort to perform pcap readback or inline operation, etc. This README summarizes the important things you need to know to use the DAQ. See the README in the DAQ tarball for information on building and installing the DAQ and for information specific to DAQ modules. See README.active and README.normalize for more information on the other packet handling changes in 2.9. Building Snort ============== If you install the DAQ libraries in a non-standard place, you can configure Snort accordingly with: ./configure --with-daq-includes= --with-daq-libraries= By default, snort will be built with a few static DAQ modules including pcap, afpacket, and dump. If you don't want any static DAQ modules built into Snort, you can use this configure option: ./configure --disable-static-daq pcap is the default DAQ, but you can change that like this: ./configure "CPPFLAGS=-DDEFAULT_DAQ=" You can also do this: make "DEFAULT_DAQ=" If you used --with-libpcap-includes or --with-libpcap-libraries when building the DAQ, you will also need --with-libpcap-includes and --with-libpcap-libraries when building Snort. Note that configure runs daq-modules-config which must be in your PATH. If you configured the DAQ with a non-standard prefix then you may need to put that in your path like this before running configure: PATH=/daq/install/prefix:$PATH Configuring Snort ================= Assuming that you did not disable static modules or change the default DAQ type, you can run Snort just as you always did for file readback or sniffing an interface. However, you can select and configure the DAQ when Snort is invoked as follows: ./snort \ [--daq ] \ [--daq-mode ] \ [--daq-dir ] \ [--daq-var ] config daq: config daq_dir: config daq_var: config daq_mode: ::= pcap | afpacket | dump | nfq | ipq | ipfw ::= read-file | passive | inline ::= arbitrary = passed to DAQ ::= path where to look for DAQ module so's The DAQ type, mode, variable, and directory may be specified either via the command line or in the conf file. You may include as many variables and directories as needed by repeating the arg / config. DAQ type may be specified at most once in the conf and once on the command line; if configured in both places, the command line overrides the conf. If the mode is not set explicitly, -Q will force it to inline, and if that hasn't been set, -r will force it to read-file, and if that hasn't been set, the mode defaults to passive. Also, -Q and --daq-mode inline are allowed, since there is no conflict, but -Q and any other DAQ mode will cause a fatal error at start-up. Note that if Snort finds multiple versions of a given library, the most recent version is selected. This applies to static and dynamic versions of the same library. ./snort --daq-list[=] ./snort --daq-dir= --daq-list The above commands search the specified directories for DAQ modules and print type, version, and attributes of each. This feature is not available in the conf. Snort stops processing after parsing --daq-list so if you want to add one or more directories add --daq-dir options before --daq-list on the command line. (Since the directory is optional to --daq-list, you must use an = without spaces for this option.) snort-2.9.6.0/doc/README.csv0000644000000000000000000000246410001575057012147 00000000000000SPO_CSV Usage Guide Brian Caswell $Id$ Overview: ---- The CSV output plugin gives an interface for users to specify what information they see for alerts. csv provides this by outputting the data in comma separated value format, configured by the user in the snort configuration file. Using limited output configurations can greatly increase the speed of snort. Usage: ---- The CSV output plugin can be configured to output specific portions of a snort alert. spo_csv requires the following format. output alert_CSV: location_to_your_file fieldname,fieldname2,fieldname3 The following line is an example CSV configuration: output csv: /my/snort.log msg,proto,timestamp,src,srcport,dst,dstport That configuration will append the following output to /my/snort.log WEB-MISC phf access,TCP,02/23-11:06:59.600820 ,192.168.0.1,1021,192.168.0.2,80 Possible Field Names: ---- The following field names are available (As of 01/13/2004) timestamp, sig_generator, sig_id, sig_rev, msg, proto, src, srcport, dst, dstport, ethsrc, ethdst, ethlen, tcpflags, tcpseq, tcpack, tcpln, tcpwindow, ttl, tos, id, dgmlen, iplen, icmptype, icmpcode, icmpid, icmpseq, and default By specifying "default" as a field name, a default set of field names is used. `grep DEFAULT_CSV spo_csv.h` for the default set of fields snort-2.9.6.0/doc/README.counts0000644000000000000000000002013112260355636012666 00000000000000Snort does a lot of work and outputs some useful statistics when it is done. Many of these are self-explanatory. The others are summarized below. This does not include all possible output data, just the basics. ----------------- Timing Statistics ----------------- This section provides basic timing statistics. It includes total seconds and packets as well as packet processing rates. The rates are based on whole seconds, minutes, etc. and only shown when non-zero. Example: =============================================================================== Run time for packet processing was 175.856509 seconds Snort processed 3716022 packets. Snort ran for 0 days 0 hours 2 minutes 55 seconds Pkts/min: 1858011 Pkts/sec: 21234 =============================================================================== ----------------- Packet I/O Totals ----------------- This section shows basic packet acquisition and injection peg counts obtained from the DAQ. If you are reading pcaps, the totals are for all pcaps combined, unless you use --pcap-reset, in which case it is shown per pcap. * Outstanding indicates how many packets are buffered awaiting processing. The way this is counted varies per DAQ so the DAQ documentation should be consulted for more info. * Filtered packets are not shown for pcap DAQs. * Injected packets are the result of active response which can be configured for inline or passive modes. Example: =============================================================================== Packet I/O Totals: Received: 3716022 Analyzed: 3716022 (100.000%) Dropped: 0 ( 0.000%) Filtered: 0 ( 0.000%) Outstanding: 0 ( 0.000%) Injected: 0 =============================================================================== ------------------- Protocol Statistics ------------------- Traffic for all the protocols decoded by Snort is summarized in the breakdown section. This traffic includes internal "pseudo-packets" if preprocessors such as frag3 and stream5 are enabled so the total may be greater than the number of analyzed packets in the packet I/O section. * Disc counts are discards due to basic encoding integrity flaws that prevents Snort from decoding the packet. * Other includes packets that contained an encapsulation that Snort doesn't decode. * S5 G 1/2 is the number of client/server sessions stream5 flushed due to cache limit, session timeout, session reset. Example: =============================================================================== Breakdown by protocol (includes rebuilt packets): Eth: 3722347 (100.000%) VLAN: 0 ( 0.000%) IP4: 1782394 ( 47.884%) Frag: 3839 ( 0.103%) ICMP: 38860 ( 1.044%) UDP: 137162 ( 3.685%) TCP: 1619621 ( 43.511%) IP6: 1781159 ( 47.850%) IP6 Ext: 1787327 ( 48.016%) IP6 Opts: 6168 ( 0.166%) Frag6: 3839 ( 0.103%) ICMP6: 1650 ( 0.044%) UDP6: 140446 ( 3.773%) TCP6: 1619633 ( 43.511%) Teredo: 18 ( 0.000%) ICMP-IP: 0 ( 0.000%) EAPOL: 0 ( 0.000%) IP4/IP4: 0 ( 0.000%) IP4/IP6: 0 ( 0.000%) IP6/IP4: 0 ( 0.000%) IP6/IP6: 0 ( 0.000%) GRE: 202 ( 0.005%) GRE Eth: 0 ( 0.000%) GRE VLAN: 0 ( 0.000%) GRE IP4: 0 ( 0.000%) GRE IP6: 0 ( 0.000%) GRE IP6 Ext: 0 ( 0.000%) GRE PPTP: 202 ( 0.005%) GRE ARP: 0 ( 0.000%) GRE IPX: 0 ( 0.000%) GRE Loop: 0 ( 0.000%) MPLS: 0 ( 0.000%) ARP: 104840 ( 2.817%) IPX: 60 ( 0.002%) Eth Loop: 0 ( 0.000%) Eth Disc: 0 ( 0.000%) IP4 Disc: 0 ( 0.000%) IP6 Disc: 0 ( 0.000%) TCP Disc: 0 ( 0.000%) UDP Disc: 1385 ( 0.037%) ICMP Disc: 0 ( 0.000%) All Discard: 1385 ( 0.037%) Other: 57876 ( 1.555%) Bad Chk Sum: 32135 ( 0.863%) Bad TTL: 0 ( 0.000%) S5 G 1: 1494 ( 0.040%) S5 G 2: 1654 ( 0.044%) Total: 3722347 =============================================================================== ----------------------------- Actions, Limits, and Verdicts ----------------------------- Action and verdict counts show what Snort did with the packets it analyzed. This information is only output in IDS mode (when snort is run with the -c option). * Alerts is the number of activate, alert, and block actions processed as determined by the rule actions. Here block includes block, drop, and reject actions. Limits arise due to real world constraints on processing time and available memory. These indicate potential actions that did not happen: * Match Limit > 0 means that rule matches were not processed due to the config detection: max_queue_events setting. The default is 5. * Queue Limit > 0 means that events couldn't be stored in the event queue due to the config event_queue: max_queue setting. The default is 8. * Log Limit > 0 means that events were not alerted due to the config event_queue: log setting. The default is 3. * Event Limit > 0 means that events were not alerted due to event_filter limits. * Alert Limit > 0 means that events were not alerted because they already were triggered on the session. Verdicts are rendered by Snort on each packet: * Allow = packets Snort analyzed and did not take action on. * Block = packets Snort did not forward, e.g. due to a block rule. "Block" is used instead of "Drop" to avoid confusion between dropped packets (those Snort didn't actually see) and blocked packets (those Snort did not allow to pass). * Replace = packets Snort modified, for example, due to normalization or replace rules. This can only happen in inline mode with a compatible DAQ. * Whitelist = packets that caused Snort to allow a flow to pass w/o inspection by any analysis program. Like blacklist, this is done by the DAQ or by Snort on subsequent packets. * Blacklist = packets that caused Snort to block a flow from passing. This is the case when a block TCP rule fires. If the DAQ supports this in hardware, no further packets will be seen by Snort for that session. If not, snort will block each packet and this count will be higher. * Ignore = packets that caused Snort to allow a flow to pass w/o inspection by this instance of Snort. Like blacklist, this is done by the DAQ or by Snort on subsequent packets. * Int Blklst = packets that are GTP, Teredo, 6in4 or 4in6 encapsulated that are being blocked. These packets could get the Blacklist verdict if config tunnel_verdicts was set for the given protocol. Note that these counts are output only if non-zero. Also, this count is incremented on the first packet in the flow that alerts. The alerting packet and all following packets on the flow will be counted under Block. * Int Whtlst = packets that are GTP, Teredo, 6in4 or 4in6 encapsulated that are being allowed. These packets could get the Whitelist verdict if config tunnel_verdicts was set for the given protocol. Note that these counts are output only if non-zero. Also, this count is incremented for all packets on the flow starting with the alerting packet. Example: =============================================================================== Action Stats: Alerts: 0 ( 0.000%) Logged: 0 ( 0.000%) Passed: 0 ( 0.000%) Limits: Match: 0 Queue: 0 Log: 0 Event: 0 Alert: 0 Verdicts: Allow: 3716022 (100.000%) Block: 0 ( 0.000%) Replace: 0 ( 0.000%) Whitelist: 0 ( 0.000%) Blacklist: 0 ( 0.000%) Ignore: 0 ( 0.000%) =============================================================================== snort-2.9.6.0/doc/README.asn10000644000000000000000000001417312260355636012226 00000000000000ASN.1 Detection Capability -------------------------- Author: Daniel Roelker The asn.1 detection plugin decodes a packet or a portion of a packet, and looks for various malicious encodings. The general configuration of the asn.1 rule option is as follows: asn1: [keyword [argument]], . . . Multiple keywords can be used in an 'asn1' option and the implied logic is boolean OR. So if any of the arguments evaluate as true, the whole option evaluates as true. ASN.1 Keywords -------------- The ASN.1 keywords provide programmatic detection capabilities as well as some more dynamic type detection. Most of the keywords don't have arguments as the detection is looking for non-configurable information. If a keyword does have an argument, the keyword is followed by a comma and the argument is the next word. If a keyword has multiple arguments, then a command separates each. bitstring_overflow ------------------ The bitstring_overflow detects invalid bitstring encodings that are known to be remotely exploitable. double_overflow --------------- The double_overflow detects an double ascii encoding that is larger than a standard buffer. This is known to be an exploitable function in Microsoft, but it is unknown at this time which services may be exploitable. oversize_length --------------- This detection keyword compares ASN.1 type lengths with the supplied argument. The syntax looks like, "oversize_length 500". This means that if an ASN.1 type is greater than 500, then this keyword is evaluated as true. This keyword must have one argument and that is the length to compare against. absolute_offset ---------- This is the absolute offset from the beginning of the packet. For example, if you wanted to decode snmp packets, you would say "absolute_offset, 0". absolute_offset has one argument and that is the offset. Offset may be positive or negative. relative_offset ---------- This is the relative offset from the last content match, pcre or byte_jump. relative_offset has one argument and that is the offset number. So if you wanted to start decoding an ASN.1 sequence right after the content "foo", you would specify 'content:"foo"; asn1: bitstring_overflow, relative_offset, 0'. Offset may be positive or negative. Examples -------- alert udp any any -> any 161 (msg:"Oversize SNMP Length"; \ asn1: oversize_length, 10000, absolute_offset, 0;) alert tcp any any -> any 80 (msg:"ASN1 Relative Foo"; content:"foo"; \ asn1: bitstring_overflow, print, relative_offset, 0;) Background on ASN.1 ------------------- The following comments were compiled by Chris Reid circa Feb 2003. ASN.1 - Abstract Syntax Notation number One * * * * * * An interesting site about ASN.1 (and its primary author Professor John Larmouth) can be found here: http://www.oss.com/asn1/larmouth.html including an electronic copy of Professor Larmouth's book titled "ASN.1 Complete". * * * * * * The following descriptions are copied from the website: "http://asn1.elibel.tm.fr/". I have no affiliation with this website, but reference it here because they provide a large amount of useful information about ASN.1. "Abstract Syntax Notation number One (ASN.1) is an international standard that aims at specifying data used in communication protocols. It is a powerful and complex language: its features are designed to describe accurately and efficiently communications between homogeneous or heterogeneous systems." "ASN.1 is a formal notation used for describing data transmitted by telecommunications protocols, regardless of language implementation and physical representation of these data, whatever the application, whether complex or very simple. "------------------------------------------- Abstract Syntax Notation number One is a standard that defines a formalism for the specification of abstract data types. ------------------------------------------- "The notation provides a certain number of pre-defined basic types such as: - integers (INTEGER), - booleans (BOOLEAN), - character strings (IA5String, UniversalString...), - bit strings (BIT STRING), - etc., "and makes it possible to define constructed types such as: - structures (SEQUENCE), - lists (SEQUENCE OF), - choice between types (CHOICE), - etc. " * * * * * * My own notes about ASN.1, as understood from skimming through Section 3 ("Encodings") of the book "ASN.1 Complete"... - Data in ASN.1 is represented by groupings composed of T-L-V (Type, Length, and Value) - Datatypes are identified by the bottom six bits of a single byte. Datatypes values 0 through 30 are represented in a single byte. Value "31" (0x1f) is an escape marker to indicate the datatype value continues in the following bytes -- as long as successive bytes have the high bit set. - The length of a given datatype can be represented in any of three ways: Short Length, Long Length, and Indefinite Length. - Short Lengths are stored in one byte, and can indicate data lengths of up to 127 bytes. Note that Short Lengths are identified by an upper bit of zero. - Long Lengths are stored in multiple bytes. The first byte indicates how many bytes are required to contain the Long Length, and the successive bytes contain the value of the Long Length. Note that the first byte of Long Lengths are identified by an upper bit of one, and that only the bottom seven bits of the first byte are used to represent how many bytes are required to contain the Long Length. Also, note that the maximum allowed value of the bottom seven bits is 126 (0x7e), and that 127 (0x7f) is reserved for future use. - Indefinite Lengths are conceptually like BLOB data. The upper bit of the first byte is set to one, and the bottom seven bits are zero. The data value follows immediately, and continues until two zero-bytes are encountered. Alerts ====== ASN.1 uses generator ID 115 and can produce the following alerts: SID Description --- ----------- 1 Indefinite ASN.1 length encoding 2 Invalid ASN.1 length encoding 3 ASN.1 oversized item, possible overflow 4 ASN.1 spec violation, possible overflow 5 Datum length > packet length snort-2.9.6.0/doc/README.alert_order0000644000000000000000000001156107744774446013703 00000000000000ALERT ORDERING -------------- The Snort 2.0 detection engine changes how the ordering of rules affect which alerts fire. Before Snort 2.0, knowing which alerts would fire first was determined by the position of the rule during initialization. If the rule was read before another rule, then the rule that was read first would be the alert that was logged. This has all changed with the 2.0 detection engine. There are now two stages that determine which alerts will fire for a packet. Ideally, Snort would have the ability to log all alerts in a packet, but the current output modules do not allow for this. The first stage in the 2.0 detection engine is rule set selection. Depending on the rule set that is selected, different alerts may be generated. The rule sets are select first by transport protocol and then by characteristics within the specific transport protocol: * TCP/UDP: selection based on source and destination ports * ICMP: selection based on ICMP type * IP: selection based on IP transport protocol (if not TCP/UDP/ICMP) Each protocol also has a generic rule set associated with it. This provides for the case where a packet does not match any unique properties of the transport protocol. It is important to note that every packet matches against a generic rule set, since every unique rule set includes the generic rule set. For example, if a packet with a destination port of 80 is inspected, the rule set that contains destination port 80 rules is selected, not the generic rule set. The rule set selected is important. In the second stage of the 2.0 detection engine, which rules get matched are determined by the rule set that is selected. Once a rule set is selected, two general types of rules are matched against. These rules are content and non-content rules. The content rules have higher rule ordering priority over non-content rules, so if a content rule matches a packet and a non-content rule matches a packet, the content rule will always win. If no content rules match, then the non-content rule that is first in the file (the old snort way) will win. This doesn't apply when a unique rule set has been selected because the unique non-content rules are first in the inspection order. For example, if an ICMP packet of type 8 is inspected, two rules will match the packet. One of the rules is a generic ICMP Echo Request with no type indicated, and the other rule is an ICMP Echo Request with a itype:8. The itype:8 rule will always fire regardless of it's position in the rule file because it is the more unique rule (since it has an itype:8). -- Examples -- Which rule fires when there are two identical rules: alert tcp any any -> any any ( msg:"foo1"; content: "foo"; ) alert tcp any any -> any any ( msg:"foo2"; content: "foo"; ) foo1 fires because it is first in the rules file. This applies for all rules (uricontent, content, no-content) that are exactly the same. The first rule in the rule files alerts. Which rule fires when there are two rule with the same content, but one rule has any any ports and the other has a specific port? alert tcp any any -> any any ( msg:"foo1"; content: "foo"; ) alert tcp any any -> any 80 ( msg:"foo2"; content: "foo"; ) foo2 fires because it is considered a unique rule because it specifies a port and gets put in the unique rule group for port 80. foo1 is considered a generic rule because it has no specific port characteristics. Which rule fires when a uricontent rule and a content rule both match a packet? alert tcp any any -> any 80 ( msg:"foo1"; content: "foo"; ) alert tcp any any -> any 80 ( msg:"foo2"; uricontent: "foo"; ) foo2 fires (as long as http_inspect is on) because uricontent rules are matched against the packet first, and if there is a uricontent match then this rule takes priority over content and no-content rules. Which rule fires when a content rule and a no-content rule both match a packet? alert tcp any any -> any any ( msg:"foo1"; content: "foo"; ) alert tcp any any -> any any ( msg:"foo2"; ) foo1 fires because content rules are matched against a packet first, and if there is a content match, then any no-content rules that match the packet also will take a lower priority than any content rule that matches a packet. Which rule fires when two content rules match a packet? alert tcp any any -> any any ( msg:"foo1"; content: "foo"; ) alert tcp any any -> any any ( msg:"foo2"; content: "foobar";) foo2 fires because the content rule with the longer content string takes the higher priority. Which rule fires when two ICMP rules match a packet? alert icmp any any -> any any ( msg:"ICMP-No-iType"; dsize:>800; ) alert icmp any any -> any any ( msg:"ICMP-iType"; itype:8; dsize:>800;) ICMP-iType fires because it has an 'itype' parameter, which specifies the ICMP rule as unique ('itype' is the only parameter for ICMP rules that specify uniqueness, otherwise it's considered generic). snort-2.9.6.0/doc/README.active0000644000000000000000000001257612260355636012644 00000000000000Snort 2.9 includes a number of changes to better handle inline operation, including: * a single mechanism for all responses * fully encoded reset or icmp unreachable packets * updated flexible response rule option * updated react rule option * added block and sblock rule actions These changes are outlined below. ENABLING ACTIVE RESPONSE ======================== This enables active responses (snort will send TCP RST or ICMP unreachable/port) when dropping a session. ./configure --enable-active-response preprocessor stream5_global: \ max_active_responses , \ min_response_seconds ::= (0..25) ::= (1..300) Active responses will be encoded based on the triggering packet. TTL will be set to the value captured at session pickup. CONFIGURE SNIPING ================= Configure the number of attempts to land a TCP RST within the session's current window (so that it is accepted by the receiving TCP). This sequence "strafing" is really only useful in passive mode. In inline mode the reset is put straight into the stream in lieu of the triggering packet so strafing is not necessary. Each attempt (sent in rapid succession) has a different sequence number. Each active response will actually cause this number of TCP resets to be sent. TCP data (sent for react) is multiplied similarly. At most 1 ICMP unreachable is sent, iff attempts > 0. ./configure --enable-active-response config response: [device ] [dst_mac ] attempts ::= ip | eth0 | etc. ::= (1..20) ::= nn:nn:nn:nn:nn:nn (n is a hex number from 0-F) device ip will perform network layer injection. It is probably a better choice to specify an interface and avoid kernel routing tables, etc. dst_mac will change response destination MAC address, if the device is eth0, eth1, eth2 etc. Otherwise, response destination MAC address is derived from packet. Example: config response: device eth0 dst_mac 00:06:76:DD:5F:E3 attempts 2 FLEXRESP CHANGES ================ Flexresp and flexresp2 are replaced with flexresp3. * Flexresp is deleted; these features are no longer available: ./configure --enable-flexresp config flexresp: attempts 1 * Flexresp2 is deleted; these features are no longer available: ./configure --enable-flexresp2 config flexresp2_interface: eth0 config flexresp2_attempts: 4 config flexresp2_memcap: 1000000 config flexresp2_rows: 1000 * Flexresp3 is new: the resp rule option keyword is used to configure active responses for rules that fire. ./configure --enable-flexresp3 alert tcp any any -> any 80 (content:"a"; resp:; sid:1;) * resp_t includes all flexresp and flexresp2 options: ::= \ rst_snd | rst_rcv | rst_all | \ reset_source | reset_dest | reset_both | icmp_net | \ icmp_host | icmp_port | icmp_all See README.flexresp3 for more. REACT CHANGES ============= react is a rule option keyword that enables sending an HTML page on a session and then resetting it. This is built with: ./configure --enable-react The page to be sent can be read from a file: config react: or else the default is used: ::= \ "HTTP/1.1 403 Forbidden\r\n" "Connection: close\r\n" "Content-Type: text/html; charset=utf-8\r\n" "\r\n" "\r\n" \ "\r\n" \ "\r\n" \ "\r\n" \ "Access Denied\r\n" \ "\r\n" \ "\r\n" \ "

Access Denied

\r\n" \ "

%s

\r\n" \ "\r\n" \ "\r\n"; Note that the file must contain the entire response, including any HTTP headers. In fact, the response isn't strictly limited to HTTP. You could craft a binary payload of arbitrary content. When the rule is configured, the page is loaded and the %s is replaced with the selected message, which defaults to: ::= \ "You are attempting to access a forbidden site.
" \ "Consult your system administrator for details."; Additional formatting operators beyond a single %s are prohibited, including %d, %x, %s, as well as any URL encodings such as as %20 (space) that may be within a reference URL. This is an example rule: drop tcp any any -> any $HTTP_PORTS ( \ content: "d"; msg:"Unauthorized Access Prohibited!"; \ react: ; sid:4;) ::= [msg] [, ] These options are deprecated: ::= [block|warn], [proxy ] The original version sent the web page to one end of the session only if the other end of the session was port 80 or the optional proxy port. The new version always sends the page to the client. If no page should be sent, a resp option can be used instead. The deprecated options are ignored. RULE ACTION CHANGES =================== The block and sblock actions have been introduced as synonyms for drop and sdrop to help avoid confusion between packets dropped due to load (e.g. lack of available buffers for incoming packets) and packets dropped due to Snort's analysis. snort-2.9.6.0/doc/README0000644000000000000000000001030712260565731011357 00000000000000Snort Version 2.9.6.0 by Martin Roesch and The Snort Team (http://www.snort.org/team.html) Distribution Site: http://www.snort.org ****************************************************************************** COPYRIGHT Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. Copyright (C) 2001-2013 Sourcefire Inc. Copyright (C) 1998-2001 Martin Roesch This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 2 as published by the Free Software Foundation. You may not use, modify or distribute this program under any other version of the GNU General Public License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Some of this code has been taken from tcpdump, which was developed by the Network Research Group at Lawrence Berkeley National Lab, and is copyrighted by the University of California Regents. ****************************************************************************** DESCRIPTION Snort is an open source network intrusion detection and prevention system. It is capable of performing real-time traffic analysis, alerting, blocking and packet logging on IP networks. It utilizes a combination of protocol analysis and pattern matching in order to detect a anomalies, misuse and attacks. Snort uses a flexible rules language to describe activity that can be considered malicious or anomalous as well as an analysis engine that incorporates a modular plugin architecture. Snort is capable of detecting and responding in real-time, sending alerts, performing session sniping, logging packets, or dropping sessions/packets when deployed in-line. Snort has three primary functional modes. It can be used as a packet sniffer like tcpdump(1), a packet logger (useful for network traffic debugging, etc), or as a full blown network intrusion detection and prevention system. Please read the snort_manual.pdf file that should be included with this distribution for full documentation on the program as well as a guide to getting started. ****************************************************************************** [*][USAGE] Command line: snort -[options] Options: The full list of options supported is displayed using the option --help. [*][FILTERS]: The "filters" are standard BPF style filters as seen in tcpdump. Look at the man page for snort for docs on how to use it properly. In general, you can give it a host, net or protocol to filter on and some logical statements to tie it together and get the specific traffic you're interested in. For example: [zeus ~]# ./snort -h 192.168.1.0/24 -d -v host 192.168.1.1 records the traffic to and from host 192.168.1.1. [zeus ~]# ./snort -h 192.168.1.0/24 -d -v net 192.168.1 and not host 192.168.1.1 records all traffic on the 192.168.1.0/24 class C subnet, but not traffic to/from 192.168.1.1. Notice that the command line data specified after the "-h" switch is formated differently from the BPF commands provided at the end of the command line. Sorry for the confusion, but I like the CIDR notation and I'm not rewriting libpcap to make it consistent! Anyway, you get the picture. Mail me if you have trouble with it. You can use the -F switch to read your BPF filters in from a file. [*][RULES]: ------------------------------------------------------------------------- NOTE: The "official" rules document these days is available at: http://www.snort.org/docs/writing_rules/ and is also usually distributed as snort_manual.pdf in the distro. If you don't have this file in your distribution of Snort, you can get it from www.snort.org. ------------------------------------------------------------------------- Please read the USAGE file or the snort_manual.pdf for more info! ****************************************************************************** /* $Id$ */ snort-2.9.6.0/doc/PROBLEMS0000644000000000000000000000220512153454767011652 00000000000000$Id$ This is the Snort problems file. It is used to document bugs that we can't work around and provide a bit of documentation in case someone finds a way to work around the problem. Platform: Linux/x86 adapter dropping out of promiscous mode if you see syslog messages complaining of obsolete (PF_INET,SOCK_PACKET), upgrade to libpcap 0.7+ and things should work correctly. Platform: Mac OS X - TCP traffic checksums are not handed up properly from pcap when the checksum is generated from the host that is doing the sniffing. Passive mode should work fine. Platform: Linux/SPARC Linux/Alpha? - Bus Errors ( Rumored to be compiler problem ) Alignment problems. Patches welcome. Platform: HPUX - Bus Errorrs with Stream4 Compiler doesn't like bitpacked notation access - HP-UX 10.x note from Chris Sylvain: if you run snort and receive the error message "Can't start DAQ error... recv_ack: promisc_phys: Invalid argument" it's because there's another program running using the DLPI service. The HP-UX implementation doesn't allow more than one libpcap program at a time to run, unlike Linux. snort-2.9.6.0/doc/NEWS0000644000000000000000000007147712260355636011216 0000000000000004-06-03 Wow, over a year since the last update. Well, this is "2.0" but not quite the 2.0 we were expecting. It's vastly more capable than the 1.8.x and 1.9.x releases, more stable, audited, well tested in a commercial test environment (thanks to Sourcefire) and generally just "better" than what has come before, but it's not the revolutionary leap that I had envisioned. Will that leap happen someday? Probably, but the timeline will shift and things will look different than we have been talking about for the last 18 months. Snort is pretty high profile now, we've got new open source IDSes nipping at our heels (amazing how they all claim to be "better" than Snort, yet usually only encompass a small subset of it's features). I continue to be amazed by the robustness of the architecture that was developed over three years ago and the latest and greatest improvements that have been added, the new detection engine from Norton & Roelker has racked up impressive performance numbers, Chris Green's sheparding of the stream4 and frag2 preprocessors as I've been out doing "business things" has been great as well. Speaking of business, if you like Snort but are interested in a commercially supported version with enterprise scalability, take a look at Sourcefire (http://www.sourcefire.com). There are other companies that put "Snort on a box" out there (google for them), but Sourcefire is taking Snort in new directions (and I started it). Snort is still free (and always will be), but if you find yourself saying "I need to deploy and manage [5|10|20|100] Snort sensors, is there anyone who can help me?", give us a shout. As for features, we've got quite a few new ones for 2.0: * Higher performance (due to a new pattern matcher and rebuilt detection engine) * Better decoders * Enhanced stream reassembly and defragmentation * Tons of bug fixes * Updated rules * Updated snort.conf * New detection keywords (byte_test, byte_jump, distance, within) & stateful pattern matching * New HTTP flow analyzer * Enhanced anomaly detection (HTTP, RPC, TCP, IP, etc) * Better self preservation in stateful subsystems * Xrefs fixed * Flexresp works faster and more effectively * Better chroot()'ing * Fixed 802.1q decoding * Better async state handling * New alerting option: -A cmg!! * Major tagging updates 03-14-02 Ok We're going to start being better about doing this more regularly. This release has many many fixes over 1.8.3. Lots of bugs in stream4 have been ironed out thanks to Phil Wood. The ICMP decoders have been rewritten. The major "gotcha" with this release will be that rules with <- used as the direction operator are no longer accepted. This is a bug fix in that it was assumed to be -> before ( unless you compiled with a specific define set ). * (This is a summary of recent changes -- not all mine) * Fixed stream4 offset initialization * Double Open of snort log file * Lots of new rules * Fatal error on problems other than -> and <> * Fixed stream4 several low memory conditions * Error checking in stream4/frag2 argument parsing * snortdb schema updates to 1.05 * --with-pcap-includes should now look at specified pcap * packet statistics now should be more accurate with regards to lost packets werwerwerwerwer * double PID file write * S4 alignment problems on Sparc fixed * new snmptrap code * documentation updates * Stability fixes in frag2 11-29-01 And the hits keep on coming. There were some other things broken in 1.8.2 that needed to get fixed (flexresp was totally inoperative, crashbug in frag2, etc). Anyway, this one has had some pretty decent testing done on the core functionality and everything seems to be running nicely now. Major repairs include a fix to frag2 on Linux platforms, the icmp decoder and printout routines were updated to match the data structures that I implemented in 1.8.1 and the flexresp code was repaired and should now be faster, plus the usual rule updates. I also added a new "-B" command line switch to convert IP addresses in a pcap file to a new specified IP subnet addresses. On to 2.0... 11-02-01 Ok, I lied. There was enough little stuff to fix in 1.8.1 that I decided to do a 1.8.2 release. This is just about fully a bugfix release, but Snort is now more stable and more usable than it's been in quite a while, and should do a good job of tiding people over while we transition to 2.0 and the codebase gets a little more "fluid". Here's the list of fixes: * fixed UTC timestamps * fixed SIGUSR1 handling, should reset properly now after getting a signal * fixed PID path generation code, PID files go in the right place now * fixed stability problems in stream4 * fixed stability problems in frag2 * tweaks to spo_unified for better integration with barnyard * added -f switch to turn off fflush() calls in binary logging mode * added new config keyword to stream4, "log_flushed_streams", which causes all buffered packets in the stream reassembler for that session to be logged in the event of an event on that stream (must be used in conjunction with spo_log_tcpdump) * added packet precacheing for flexresp TCP packets, responses should be generated more quickly * fixed rules parser code for various failure modes * several new rules files and a new classification system After this release we're going to reorganize the whole source tree and do a quick 1.9 release with the new code layout. Once that's done, we're going to begin coding 2.0 in earnest in December, hopefully doing our initial release sometime in the February time frame. 08-14-01 I was planning on getting this release out sooner than this (since it's largely a bugfix release) but my wife and I went and had a baby 2 weeks ago, which effected the schedule a little. ;) Anyway, barring any major problems the Snort 1.x code will now be going into maintenance mode as we begin development on 2.0. This version adds the following: * SNMP alerts * IDMEF XML output (the Silicon Defense plugin is integrated into the main codebase now) * Limited regex support in the rules language * New packet counters for stream4 and frag2 * New normalization mode for http_decode And a slew of bug fixes. We should get to work on 2.0 shortly, so hopefully the next release of this NEWS file will be talking about that! (knock on wood...) 07-09-01 Well, this one was a long time coming, but I think it was worth the wait. Snort can now perform stateful inspection, has improved defragmentation capabilities, uses less memory, leaks less of the memory that it does use, is faster, and has a bunch of other good stuff. Truely, this is probably the ultimate development of the 1.X series of Snort. After this version we will begin development on Snort 2.0, which will have a great many new features, be faster and more flexible, and generally be about the finest network intrusion detection system that an open source community can build. See the Changelog (read all the way back to January of this year) for changes and additions, there are far to many to list here. Some of the highlights include * stateful inspection * new tcp stream reassembly code * new ip defragmenter * new protocol available for the rules language: ip * more extensive printouts of cross reference and info in alerts * new normalizer preprocessors for telnet, rpc * 2 new output plugins (unified, csv) * 5 new preprocessors (stream4, frag2, bo, telnet_decode, rpc_decode) * 10 new rule options * unique rule IDs * A whole slew of command line options (7 at last count) * Mega bug-fixes from 1.7 Snort can now leap tall buildings in a single bound. The future holds 2.0, which will revisit most of the code in Snort. It probably won't be released for another 6 months or so, but for the time being I'm happy with what we've produced here and I think most people will be happy with it too. Please read the USAGE, FAQ, README, man page and any other docs you can before asking your questions, there's a good chance that the answer you're looking for is in there. Commercial plug: If you decide that you need or want to take your Snort installation to the next level, Sourcefire Inc. (http://www.sourcefire.com) is now producing commercial network intrusion detection appliances based on Snort with data analysis, management, and rules GUIs built-in. See the web site for more information, if you want to have a commercially supported, professional Snort deployment, Sourcefire is the company to call. 01-02-01 Welcome to version 1.7. This version features clean compiles on following architectures and platforms: * Linux 2.0.X, Linux 2.1.X, Linux 2.2.X (i386) * FreeBSD 3.x, 4.x (i386) * SunOS/gcc 5.5, 5.5.1, 5.6, 5.7, 5.8 (sparc) * OpenBSD 2.7, 2.8 * Tru64/gcc * HPUX 11.0/gcc Other platforms/architectures should be supported as well, we just don't have them available for testing on the moment. There are a ton of bug fixes and new features in this version, have a look at the ChangeLog to see many of them. I think that this will be the last full point release of the 1.X codebase, we're starting design work on the 2.0 series and I hope that we'll be putting it out there in the not too distant future (less than six months!). It's been a long road to 1.7, the amount of code in the program compared to the initial release over two years ago is incredible. We're just getting rolling though, and 2.0 is going to bring a great number of changes including more plugin interfaces (packet acquisition and decode), faster/cleaner code (I hope ;) and a better design for performing more types of analysis. Big changes in this version: snort-lib renamed to snort.conf, IP defragmentation plugin now 100% on all architectures, tcp stream reassembly, statistical anomaly detection, three new command line switches (-L,-I,-X), IP address lists, a cool "automatic variable" in the rules file that automatically picks up the IP address and netmask of a named interface, more packet header printouts, detection plugins for TOS and the IP fragment bits, as well as a plugin that allows reference data to be attached to rules and a completely rewritten active response module, etc. I hope everyone likes this release, we've put a ton of work into it to make sure that it's functional and stable while still being easy to use for everyone. 07-22-00 Welcome to version 1.6.3. This version features clean compiles on all architectures and OS's that I have access to, some elusive bug fixes in the decoders, a little bit better packet printing, full-time ARP packet decoding (instead of only when the -a option is spec'd), and an upgraded portscan detector. The moral of the story with the 1.6.1->1.6.2.2 release cycle was "don't release when you're working on the road". This will be the last version release until the Hiverworld IDS ships as I need to dedicate myself fully to that cause. Please watch http://www.snort.org for information on the availability for an upgraded defragmentation preprocessor, the one shipping with this version should be treated as *beta* code! 07-08-00 It wouldn't be a relase without a disaster, and in that vein we lost the ability to compile cleanly on Linux boxes with version 1.6.1. Typical. Lessons learned: I need to reinstall a RedHat box at Snort Labs so that I can do compile tests before release. C'est la vie. 07-06-00 Version 1.6.1 is finally ready to see the light of day. This release is mostly a bug fix with a few minor feature additions for runtime security. Version 1.7 is a few months behind in development due to my busy schedule at Hiverworld where I'm putting together a completely new (not Snort-based) IDS. Version 1.7 is in development and you can check the latest beta functionality by checking it out from the CVS repository. The features that have or are going to be added include dynamic rules (rules that turn on other rules), variable alert levels, port and IP sets for rules, and a few other goodies, plus a slew of new plugins. Additionally, the snort.org web site has gone live since the last release, and it's pretty much a one-stop-shop for all things Snort related (that and www.whitehats.com). I hope to have version 1.7 available by the October SANS Network Security 2000 conference. 03-20-00 Bang! Here's version 1.6, marvel at its glory! :) I'm going to keep this short since it's 3AM, but I think that everyone is going to like the changes and additions since version 1.5. Be sure to check out the new rules writing document at http://www.clark.net/~roesch/snort_rules.html! 02-26-00 1.6 is still in the works, but this one fixes a few problems with people trying to compile on SunOS/Solaris/HP-UX boxes. This release really falls more into the "tweak" category, but I think it's important enough to put out. Version 1.6 is coming RSN, but will probably be a couple more weeks! 01-03-00 This one is a minor bug fix in preparation for the impending release of version 1.6. Version 1.6 is in beta, but I couldn't hold back doing a release of this bug fix version any longer. Speaking of 1.6, it should be out in about two weeks, and will incorporate a bunch of cool new functionality. Stay tuned! 12-8-99 Wow, almost two months since the last major release. Well, if you thought the last one was big, this one is HUGE! There are nine major additions to this release, including plugins, session recording, improved flexibility in the rules files, better packet content analysis, and a bunch of other stuff. Snort is faster, more efficient, more flexible, and more powerful than 1.3.1. Not bad for two month's work, eh? :) What's down the road from here? Well, the Token Ring decoder needs to get finished, and then there are three big topics that Snort needs to address: IP defragmentation, TCP stream reassembly, and port scan detection. Fortunately, the new plugin architecture implemented in this version of Snort makes the addition of these huge features relatively painless from a development standpoint. The modules can simply be developed and then dropped right into every copy of Snort out there. The really cool functional (user level) things about version 1.5 are session logging with the new "session" keyword, multiple content tests per rule, rules file variables, and the IP options inspection keyword "ipopts". Check out the RULES.SAMPLE file (at the bottom) for more info on the new stuff. 10-13-99 Welp, here's the bug fix release. There was one really big stupid bug in this one plus some other minor annoying stuff, so here's a patch to clean things up a bit. I also added some functionality to the dsize option keyword, you can specify ">" or "<" now to select ranges. 2.0 is progressing slowly in the face of various conference activity I have over the next few months. I'm looking at a late November or mid-December release now, but hang in there, it's coming. 09-18-99 This is probably the last 1.x release of Snort (barring a possible bugfix release). The next planned version is 2.0 and it will be radically changed for the better. It will include a faster, more flexible detection engine, plug-in support for detection, output, and monitoring modules, and a plethora of other options. Look for it in late October or early November! This version includes an enhanced logging/alerting engine that is several times faster than the Snort 1.2.1. The logging and alerting command line options are also more streamlined so that people may have the flexibility to choose how they log. Enjoy! 08-06-99 This is the official "mea culpa" version of Snort. Version 1.2 wasn't exactly a high quality release for non-Linux platforms, and so here we are five days later with version 1.2.1. Thanks to everyone's bug reports and a small band of volunteers, this release is much more stable than version 1.2 and should configure and build cleanly on all platforms and architectures, including Sparcs and OpenBSD. While all of the bug fixing was taking place, I actually found time to integrate some patches that people generously sent in during the week. That kind of makes this release value added, it's not just a bug fix there's actually some new stuff in here! If this version proves to be stable and everyone is pretty much happy with the way things are working, this will be the last release for a month or so. I'm writing a paper for the LISA '99 conference about Snort, and I need to concentrate on finishing it and getting some facts and figures about the software together. After that is done, I've got some enhancements for the detection engine thought up that are truly radical, stay tuned..... :) 08-03-99 Oops! 08-01-99 Well, here it finally is, the big performance release. This version has a slick new packet decoder and a brand spankin' new, fully recursive, detection engine. It kicks ass! :) Large sections of the code have been restructured to eliminate global data structures and streamline how much real data has to be passed around. Two major global data structures have been eliminated to make the code more thread friendly in case I ever get motivated enough to multi-thread this beast. The SMB alerting code is now an option, use the "--enable-smbalerts" switch to the configure script if you're interested in using it. Preliminary performance testing has shown this version to be about twice as fast as version 1.1 in most cases, sometimes up to 500% faster than 1.1! There's a lot of new code in this release, so if anyone finds any bugs I'd appreciate hearing about it. Thanks! 06-21-99 Tons of new and improved stuff this release. Three new command line options, six new rule options, eight big bugs squashed, and a shiny new content parser. The WinPopup stuff was donated by Damien Daspit. It breaks one of my cardinal rules of security software coding (thou shalt not exec a program from within another), but it was so I cool I put it in pretty much unmodified. Probably in the next version I'll rig something up so that it will be a compile time define where you have to specify a switch when you ./configure, but for now it's in. It shouldn't be too much of a problem since you have to be root to run Snort anyway. Trinux users can rejoice a bit, I hardcoded the netmasks into the program, so it no longer needs to be linked against libm, which was quite large to be putting on floppy disks. The new tcpdump file read option is cool, and as soon as I get my tcpdump file defragmenter working, Snort will have the ability to decode and alert based on fragments. C'est cool, no? 05-18-99 This release is primarily to fix some bugs that made it out in version 1.0. At the time of release, my Sparc was broken and I didn't have a good way of testing the big endian/non-x86 stuff, so some little bugs made it out the door. This version has been tested on a real live SPARCstation 10 (Sol 2.5.1) and seems to work as advertised, so I'm putting it out the door. This release also features support for HP-UX and S/Linux thanks to Chris Sylvain's nice work. (Thanks Chris!) There are some other small additions, like the packet counter statistics on exit and the "-x" command line switch which allows you to specifically turn on IPX packet notification (since I still haven't written a IPX decoder). The next release is going to have a new and improved content parser, I've discoverd that the current one, uh, sucks. See the Changelog for specifics on what's fixed in this version. 04-28-99 Woohoo! One point oh baby! New stuff: now does SLIP and RAW (PPP) packets, so all you people out there with modems can use Snort now too. I also added in options to send alerts to syslog. The stability/functionality of the last release was good enough for me to decide that 1.0 was ready to ship, so here it is. Enjoy! 04-17-99 Well, I guess I decided to change things around a bit. I have rewritten about half of the rules parser so that future addition of rule types people find generally interesting will be much easier to do. I also totally rewrote the logging section so that it was more sane to write follow on code with. Those are the major big changes. I'm finally happy with the way this software is laid out and operates, so if this one works pretty well, I'll slap whatever bug fixes need to be made onto it and it'll really truly be version 1.0. 04-06-99 Ok, this is the big one, I think everything is stable enough now for a general release. If this one doesn't do anything bizarre once it gets out into the real world, it's going to be version 1.0, and this time I mean it! :) Note that I'm including the snort-lib template file, which has some useful patterns and rules that people may want to use. Also note that this is version 0.99 rc5, there was no version rc4! Ok, that's it for now, if anyone has any problems with this version, let me know! 03-24-99 Let me just say that I think I might need to implement some sort of formalized testing regimen before making major releases. Please pardon the last two crap releases, not enough time and too much work for one person to do. (lets all have a pity party...) Anyway, I beat the crap out of this version with iptest and nmap, and I think it works pretty damn good now. Lets hope it continues to work well tomorrow... 03-21-99 Ok, good size update, I think this may turn out to be 1.0, but I'm done thinking that seriously for the time being. Added TCP flag-based rules, port range rules, IP and TCP option decoding, truncated packet handling, improved fragmented packet handling, and some bug fixing. I'm not quite sure what else I'd like to put in before the 1.0 release, so I thinking this is going to be it. If there's any big feature you've been wishing for, now is the time to ask! 03-08-99 Got a request to do more precise timestamping, so I ripped off the TCPDump timestamp routine and stuffed it in Snort. You can now see which particular millisecond packet XYZ showed up in. I'm working on the rest of the stuff.... 03-06-99 Well, no new rules yet, but this program is a lot faster than the last release. The two biggest bottleneck routines have been rewritten and are now faster and more efficient. I've also started doing more complete decoding of the IP header, starting with the fragment data. For those of you not using Linux, collected/dropped packet statistics are now being generated when Snort is exited. The next release will (hopefully) decode the fragments and be able to apply the rules set to them. I'm also planning on having IP Option decoding in the next release, plus the new rules set. Stay tuned! 02-18-99 I've started a new job and gotten one of those ergonomic keyboards, so development has slowed a bit. This release focuses on minor bug fixes and code cleanup. I'm thinking about changing the rules format to something with one rule argument per line. This will make for larger, more readable rules files at the cost of more typing for the user. It sorta sucks, but this is the best way I can think of to do it... 01-28-99 Content based logging is done. With this addition, this thing can finally be used for light duty IDS tasks and catch most things. There still needs to be some additional work done to add rules for things like TCP flags, fragments, and IP options, but the base structure is there. Automatic rules sorting is implemented now too, so you can make your rules look as disorganized as you want. If nobody finds any show stopper bugs in this release, this is going to be 1.0! 01-19-99 Rules based packet capture is a reality now. Added it pretty much all in a day or so of serious hacking. The code is modularized now into excitingly chunky files. I did this to avoid insanity, and I highly recommend it. Look at the README file or the "RULES.SAMPLE" file to see how rules work. I also fixed the seriously porked logging code, now all conversations end up in single files based upon the homenet address command line parameter, or in its absence, hi port/lo port. I highly recommend using the homenet capability (-h option). Coming soon: Content based logging! 01-08-99 I'm thinking about putting in some "capture/pass" logic into the program to facilitate rules/content based traffic capture. In other words, make some kind of light intrusion detection capability. Look for it by version 1.0. snort-2.9.6.0/doc/INSTALL0000644000000000000000000003734412260355636011543 00000000000000The "generic" notes for putting this thing together are below. Here's the short version. 1.) If you are upgrading from a prior version of Snort, it is generally a good idea to start with `sudo make uninstall` in your old source tree to remove any dynamic modules that could cause you grief later. 2.) *** Make sure you have libdnet, libpcap, libpcre installed!!! *** Also make sure that dnet-config, pcre-config, and daq-modules-config are in your PATH (e.g. you should be able to `which` these). 3.) ./configure 4.) make 5.) sudo make install 6.) Check your rules file. By default, step 3 configures Snort for the features required by the included etc/snort.conf. You can validate it with: src/snort -c etc/snort.conf -T 7.) snort -? 8.) If you've used previous versions of Snort, you may need to rewrite your rules to make them compliant to the rules format. See snort_manual.pdf or http://www.snort.org for more information. 9.) If you used previous versions of Snort and the new Snort dies upon startup, try this and then restart: sudo make uninstall sudo make install 10.) Have fun! Any questions? Sign up to the snort-users mailing list at http://www.snort.org! Snort Configure-time switches ============================= `--enable-debug' Enable debugging options (bugreports and developers only). `--enable-pthread' Enable pthread support (causes snort to be linked with libpthread). `--enable-rulestate' Enable rule state configuration feature that separates the rule state (enabled/disabled) from the action (alert, drop, log, etc) and definition. `--enable-so-with-static-lib` Enable linking of dynamically loaded preprocessors with a static preprocessor library. `--enable-perfprofiling' Enable performance profiling of individual rules and preprocessors. `--enable-linux-smp-stats' Enable CPU performance statistics through proc. `--enable-react' Enable interception and termination of offending HTTP accesses. `--enable-flexresp3' Enable the 'Flexible Response, version 3' code, that allows you to reset hostile sessions. See README.active for details. `--enable-gre' Enable GRE decoder. Allows Snort to decode GRE encapsulated traffic. Only supports GRE over IP. Only one layer of encapsulation will be decoded - packets with multiple GRE headers will be alerted and discarded/blocked. `--enable-sourcefire' Enable Sourcefire specific build options, encompasing --enable-perfprofiling and --enable-ppm. `--with-snmp' Enable SNMP alerting code. `--with-dnet-includes=DIR' Specify libdnet include directory. `--with-dnet-libraries=DIR' Specify libdnet library directory. `--with-libpcap-includes=DIR' If the configuration script can't find the libpcap include files on its own, the path can be set manually with this switch. `--with-libpcap-libraries=DIR' If the configuration script can't find the libpcap library files on its own, the path can be set manually with this switch. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. The following configuration switches are available for Snort: Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. Platform Specific Notes ======================= * Linux: -------- With kernels 2.2.x and higher you may get `snort [pid] uses obsolete (PF_INET, SOCK_PACKET)' warnings. This is because you use some older implementation of libpcap library and you need an upgrade. The recent version of libpcap could be found at www.tcpdump.org page. On linux with kernels 2.2.x and higher you may also get feature to monitor several interfaces down to network level (session + TCP + IP) if you link your snort with the latest version of libpcap which incorporates Sebastian Krahmer's patch for interface 'any'. (Consult http://www.tcpdump.org for details). * IRIX ------ [ noticed by Scott A. McIntyre ] There's problem with GCC on IRIX platform which causes certain misbehaviour of snort. From the SGI web site: Gcc does not correctly pass/return structures which are smaller than 16 bytes and which are not 8 bytes. The problem is very involved and difficult to fix. It affects a number of other targets also, but irix6 is affected the most, because it is a 64 bit target, and 4 byte structures are common. The exact problem is that structures are being padded at the wrong end, e.g. a 4 byte structure is loaded into the lower 4 bytes of the register when it should be loaded into the upper 4 bytes of the register. Gcc is consistent with itself, but not consistent with the SGI C compiler [and the SGI supplied runtime libraries], so the only failures that can happen are when there are library functions that take/return such structures. There are very few such library functions. I can only recall seeing a few of them: inet_ntoa, inet_aton, inet_lnaof, inet_netof, and semctl. A possible workaround: if you have a program that calls inet_ntoa and friends or semctl, and your kernel supports 64-bit binaries (i.e. uname -a prints IRIX64 rather than just IRIX), then you may compile with gcc -mabi=64 to workaround this problem. More information is available at: http://freeware.sgi.com/2000Feb/Installable/gcc-2.8.1-sgipl2.html * MAC OSX --------- On Darwin (maybe others), the configure script shipped as part of the source distribution may need to be recreated. To do this, run the following commands: glibtoolize --force aclocal -I m4 autoheader automake --add-missing --copy autoconf Snort needs to be linked using the two level namespace. To do this, set the LD_TWOLEVEL_NAMESPACE environment variable to something prior to running configure. An example: $ export LD_TWOLEVEL_NAMESPACE=1 $ ./configure $ make * MAC OSX TIGER & LEOPARD ------------------------- For users of MAC OSX 10.5 (Leopard), the following environment variables must be set before running configure & make. For users of MAC OSX 10.4 (Tiger), this also applies if the compiler has been updated, otherwise, the instructions above may be used. Reference information for MAC OSX can be found at these two links. http://developer.apple.com/releasenotes/Darwin/SymbolVariantsRelNotes http://lists.apple.com/archives/xcode-users/2007/Jun/msg00163.html $ export LD_TWOLEVEL_NAMESPACE=1 $ export MACOSX_DEPLOYMENT_TARGET=10.5 $ ./configure $ make * Open BSD / Free BSD / MAC OSX ------------------------------- For Open BSD and some versions of Free BSD, use the --disable-static-daq option to Snort's configure script. This is a work-around to an issue with building shared libraries that link against a static library. Without this option to configure, libsf_engine.so and the dynamic preprocessors may not be built correctly. On certain BSD-based platforms, the make install may not symlink the version specific shared libraries to the non-versioned shared library. This could cause a failure to load when using dynamic libraries. Workarounds: 1) Create the symlinks by hand after make install. The shared libraries can be located under /usr/local/lib/snort_dynamicengine and /usr/local/lib/snort_dynamicpreprocessor. If necessary, symlink the .so.0 or .0.so files to a corresponding .so. 2) Use the --dynamic-preprocessor-lib (rather than --dynamic-preprocessor-lib-dir) to load the version specific shared library. 3) Use the config directive dynamicpreprocessor file (rather than dynamicpreprocessor directory) to load the version specific shared library. Note that on FreeBSD and OpenBSD, divert sockets don't work with bridges. Please refer to the DAQ distro README for workarounds and more details. When using the alert_unixsock output plugin on FreeBSD, please refer to the Output Modules section of the Snort Manual. * FreeBSD 6.x ------------- If you run the auto tools (instead of using the delivered configure script), you may need to include -I /usr/local/share/aclocal (in addition to -I m4) as arguments to aclocal. This is required to set up the correct info for using LIBTOOL with aclocal version 1.9 that ships with FreeBSD. In this case, the following recommended commands should be used to configure snort prior to using make: libtoolize --automake --copy aclocal -I m4 -I /usr/local/share/aclocal autoheader automake --add-missing --copy autoconf Then run configure with any desired options. snort-2.9.6.0/doc/generators0000644000000000000000000000401410662351160012562 00000000000000# Master Registry of Snort Generator Ids # # # This file is used to maintain unique generator ids for files even if # the default snort configuration doesn't include some patch that is # required for a specific preprocessor to work # rules_subsystem 1 # Snort Rules Engine tag_subsystem 2 # Tagging Subsystem portscan 100 # Portscan1 [ removed ] minfrag 101 # Minfrag [ removed ] http_decode 102 # HTTP decode 1/2 [ removed ] defrag 103 # First defragmenter [ removed ] spade 104 # SPADE [ removed ] bo 105 # Back Orifice rpc_decode 106 # RPC Preprocessor stream2 107 # 2nd stream preprocessor [ removed ] stream3 108 # 3rd stream preprocessor (AVL nightmare) [ removed ] telnet_neg 109 # telnet option decoder [ removed ] unidecode 110 # unicode decoder [ removed ] stream4 111 # Stream4 preprocessor arpspoof 112 # Arp Spoof detector frag2 113 # 2nd fragment preprocessor [ removed ] fnord 114 # NOP detector [ removed ] asn1 115 # ASN.1 Validator [ removed ] decode 116 # Snort Internal Decoder scan2 117 # portscan2 [ removed ] conversation 118 # conversation [ removed ] http inspect client 119 # HTTP Inspect http inspect anon server 120 # HTTP Inspect flow portscan 121 # flow portscan sfportscan 122 # portscan frag3 123 # ip frag reassembler smtp 124 # SMTP decoder/normalizer ftp 125 # FTP decoder telnet 126 # telnet decoder/normalizer isakmp 127 # ISAKMP ssh 128 # SSH stream5 129 # Stream5 dcerpc 130 # DCE/RPC dns 131 # DNS snort-2.9.6.0/doc/CREDITS0000644000000000000000000002702311777055364011532 00000000000000$Id$ Dilbagh Chahal * HTTP & FTP/Telnet Multiple IP/CIDR configuration support * Detection filters, Event Filters, Rate Based Filters * Multiple Policy support Ryan Jordan * Application preprocessor adaptive support * SSH preprocessor updates * Shared library rule processing performance improvements * CVS repository maintenance Kevin Liu * MPLS Support * SSL preprocessor updates * FTP/Telnet preprocessor IPv6 support * DNS preprocessor IPv6 support Russ Combs * Major cleanup of pedantic warnings and compiler issues * FTP/Telnet preprocessor IPv6 support * Overall Performance improvements * Detection filters, Event Filters, Rate Based Filters Todd Wease * DCE/RPC preprocessor updates and improvements * DCE2 preprocessor * SMTP preprocessor updates * CVS detection plugin * CVS repository maintenance * 64 bit compilation cleanup * Snort Manual preprocessor documentation * Reconfiguration without interruption of detection Adam Keeton * IPv6 support * SSL preprocessor * Snort Manual preprocessor documentation Chris Sherwin * SSH preprocessor * HTTPInspect updates Steven Sturges * FTP/Telnet preprocessor * DNS preprocessor * Dynamic library preprocessor and rule APIs * Stream4 performance improvements * Frag3 performance improvements * Frag3 OpSys policy additions * Stream API * Stream5 * Rule and preprocessor performance profiling * Rule processing performance improvements * HTTPInspect performance improvements * Target-Based processing * CVS repository maintenance Anderw Mullican * SMTP preprocessor * DCE/RPC preprocessor * Dynamic library preprocessor and rule APIs Marc Norton * Snort 2.0 detection engine * Aho-Corasick pattern matchers * Wu-Manber pattern matchers * Pattern Matcher CPU cache performance improvements * sfxhash, sflsq, ipobj libraries * Thresholding/suppression * Performance monitoring preprocessor * Packet performance monitoring Daniel Roelker * Snort 2.0 detection engine * HttpInspect detection engine * ASN.1 decoder and detection plugin * Multi-event queuing, prioritizing, and logging * sfPortscan detection engine * Snort-inline integration from snort-inline project * Performance monitoring preprocessor * Frag3 integration Jeremy Hewlett * CVS and release manager * Snort testing * Bug triage * Documentation Sebastian * Added TOS decoding and logging Franck Debieve * Numerous bug reports and feature testing * Documentation Ron Gula * Provided lots of signatures Mike Borella * Made some libpcap code that was actually easy enough to follow along in so that even idiots like myself could do something like this. Mike's a cool dude (and he listens to Slayer), check his stuff out at www.borella.net Jed Pickel * Sent in the RAW packet decoder routine * Database output plugin module * XML output plugin module Chris Sylvain * Added HP-UX and S/Linux code, plus the "-x" command line switch. Damien Daspit * Provided the WinPopup code and some other bug fixes, plus helped me debug a nasty problem with the rules parser. Sebastien L. * Ideas guy and RPM guru, he's been a help behind the scenes lately. CyberPsychotic * configure.in Sparc alignment updates * daemon mode code * lots of help debugging the 1.2 release on OpenBSD/Sparc * new ftpd buffer overflow rule * UnixSock alerting code * NULL/Loopback decoder * my right hand man in Snort development, constantly working on new stuff and enhancements for the system Nick Rogness and Jim Forster * lots o' rules, bug reports Scott McIntyre * Happy 99 virus rule * wacky FBSD bugs and attendant help with said bugs * also spotted the otn_tmp NULL bug in 1.3 * tons of debug info and help! Ron Snyder * IP address negation operator code * Bug hunter extrordinaire Jonathan Emery * Ran Purify on the Snort source and tracked down some nasty buggage Aaron Smith * non-promiscuous mode patch * logging code streamlining Dug Song & Torbjorn Wictorin * Torbjorn spotted it first, but Dug sent in a kick ass bug report so they both get credit for finding the otn_tmp NULL bug in LogPkt. Max Vision * Ideas, debug help, lots of rules Dragos Ruiu * Ideas guy, keeps me honest :) * Author of defrag preprocessor Colin Haxton * Timestamp bugfix, debug help Worm5er * Master Debugger, he's always got the best bugs! :) Lance Spitzner * Thank Lance for the session keyword! * Lots of debug help, suggestions Christian Lademann * The Man! Added the rules file variable and include code. This man should have a place in every Snort user's heart. ;) * Added the ISDN for Linux support/decoders Christian Hammers * Maintains the Debian distro of Snort, sends me nice bug reports. Michael Henry * Sent in the URL decoder that eventually became the http_decode preprocessor Bob Beck * Sent in a few security patches, some advice Sebastian * Linux PPC testing. * Great help with tracking down `loopback failure' problem. Patrick Mullen * snort portscan preprocessor. * great helper on the project. Herb Commodore * `--with-libpcap' fixes to configure.in. John Wilson * New implementation of insensitive pattern match code. Mike Caughran * Great help with porting snort to AIX platform. Astaroth * Added Tru64/Alpha support. Daniel Monjar * More Tru64/Alpha diffs. Ralf Hildebrandt * HP-UX debugger and ombudsman. Stuart Staniford-Chen * Ideas guy, he's been bouncing around ideas for better output classification in Snort. * Wrote snortsnarf.pl, a CGI/HTML program for organizing Snort output. Yen-Ming Chen * Wrote the excellent snort-stat.pl statistical analysis script for Snort alerts. * Wrote a nice PHP front-end for the Snort alerting mechanism. Erich Meier * Lots of help debugging debugging! * ip tos plugin. Denis Ducamp * Solaris debugging and patching. Boa * Great help with the addition of Token Ring support to Snort. Anthony Stevens * Contributed the Guardian firewall response system to Snort. Andrew R. Baker * Contributed the snort-sort alert analysis script. * Tweaked various other Snort analysis scripts. * Added variable level alert support, officially joining the ranks of the bad-asses :) J Cheesman * Enhanced the PID logging code to be more robust. "Mark Hindess" * Added the RPC application layer detection plugin Dave Wreski * Provided support and help diagnosing problems with the 1.6.2 config scripts * Snort-HOWTO paper. Bo * Provided fixes for my idiotic configure.in antics in version 1.6.2 Peter Weinberger * Added code to fill in full transport protocol names Dave Dittrich * Provided a little patch to fix daemon mode alert filenames Christopher Cramer * Author of the TCP stream preprocessor! (spp_tcp_stream) Joe Stewart * Added UNICODE and NULL byte attack detection to http_decode preproc Thomas Zajic * Provided some sanity check fixes for the PID file Jason Ish * Cleaned up the plugin template files Paul Herman * Contributed a patch to clean up sloppy strlen/strncpy interactions Todd Lewis * Big new addition to the project, idea/code generator extrordinaire :) Phil Wood * Master debugger, got the IP/bidirectional code back on its feet after the addition of IP lists * Numerous other bugpointers, tweaks etc. * pointed out signature logic errors Dr SuSE * Helps out with docs, answering questions on the mailing list, etc. Joe McAlerney * sp_reference plugin, constant helper on the project James Hoagland * SPADE statiscal anomaly detection plugin, lots of other help and advice Maciek Szarpak * Author of the react plugin Paul Ritchey * Provided the -y year printout command line switch code Eugene Tsyrklevich * Added smalloc.h and fatal.h * patches for stupidity in various files * strl* functions/patches. A bunch of of other minor tweaks. * ideas for new debugging code. Markus De Shon & Jon Ramsey * tracked down tricky false positive condition in sp_pattern_match Koji Shikata * spp_http preprocessor patch which allows to catch broken unicode (which still works on IIS 4.x servers). Achim Gsell * some pointers/fixes on problems in spp_defrag.c piece. Tomtom * Added PPPoE decoder Chris Green * documentation * testing on #snort * code maintenance * flow-portscan * flow Bill Gercken * lots of patches and testing on his busy network HD Moore * testing, keeping me honest :) Matt Scarborough * another good tester/bug reporter Jeff Nathan * added spp_arpcheck code, watches for ARP stuff, RTFS * updated man page for 1.8 Brian Caswell * Snort Rules Nazi, keeps the rules trains running on time * wrote spo_csv * constant companion on #snort Glenn Mansfield Keeni * Added SNMP output support plugin for Snort, cool! Chris Reid * win32 support patches. * ms-sql support for spo_database * create_mssql script * other minor fixes/tweaks Robert Hughes * rules fixes Jimmy Stags * pointed out duplicate signatures Zeno * a number of signatures included in web-attacks.rules Ryan Russell * a zillion signature corrections. Mike Davis * original win32 port Ofir Arkin * Helped with cleanup and correction of ICMP decoder subsystem Fabio Bastiglia Oliva * Rules cleanup! snort-2.9.6.0/doc/BUGS0000644000000000000000000000354310277202365011163 00000000000000Security Related bug reports (evasions, overflows, etc) should be sent to bugs@snort.org and Marty Roesch . Bug reports should be sent to bugs@snort.org and cc'd to snort-devel@lists.sourceforge.net (Snort Developers mailing list). Please include the following information with your report: System Architecture (Sparc, x86, etc) Operating System and version (Linux 2.0.22, IRIX 5.3, etc) Version of Snort What preprocessors you loaded What rules (if any) you were using What output plug-ins you loaded What command line switches you were using Any Snort error messages If you get a core file, here is a procedure that would be very helpful for me to debug your problem faster. When it crashes, try the following steps: 1) At the command prompt, type 'gdb snort snort.core'. This will load snort and the core file into the GNU debugger. You may need to give the path to the snort binary file, and your core file might have a different name (like "core" or something). 2) At the (gdb) prompt, type 'bt' (without the quotes). 3) At the (gdb) prompt, type 'quit'. This will return you to your shell. 4) Cut and paste the output from gdb into the email you send me! If the problem could be reproduced, coredump analysis and snort output of 'debug-enabled' build would be appreciated. Hints: To build debugging-enabled snort: make distclean; ./configure --enable-debug; make If you are having trouble compiling, please try the following: make distclean; aclocal; autoconf; automake These solve a good percentange of autoconf portablity problems. To debug some particular part of snort functionality: export SNORT_DEBUG= and run snort. See debug.h file for details on debugging levels. (those could be combined, f.e. if you want to see IP and TCP/UDP related info: debuglevel would be: IPdebuglevel + TCPUDPdebuglevel) Thanks! -Marty snort-2.9.6.0/doc/AUTHORS0000644000000000000000000000007207322466264011551 00000000000000Author(s) of Snort Martin Roesch - roesch@sourcefire.com snort-2.9.6.0/doc/Makefile.am0000644000000000000000000000267112243745447012545 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies EXTRA_DIST = \ snort_manual.pdf \ snort_manual.tex dist_doc_DATA = \ AUTHORS \ BUGS \ CREDITS \ generators \ INSTALL \ NEWS \ PROBLEMS \ README \ README.active \ README.alert_order \ README.asn1 \ README.counts \ README.csv \ README.daq \ README.dcerpc2 \ README.decode \ README.decoder_preproc_rules \ README.dnp3 \ README.dns \ README.event_queue \ README.file \ README.file_ips \ README.filters \ README.flowbits \ README.frag3 \ README.ftptelnet \ README.gre \ README.GTP \ README.ha \ README.http_inspect \ README.imap \ README.ipip \ README.ipv6 \ README.modbus \ README.multipleconfigs \ README.normalize \ README.pcap_readmode \ README.PerfProfiling \ README.PLUGINS \ README.pop \ README.ppm \ README.reload \ README.reputation \ README.rzb_saac \ README.sensitive_data \ README.sfportscan \ README.SMTP \ README.ssh \ README.ssl \ README.sip \ README.stream5 \ README.tag \ README.thresholding \ README.UNSOCK \ README.unified2 \ README.variables \ README.WIN32 \ TODO \ USAGE \ WISHLIST DISTCLEANFILES= snort_manual.log snort_manual.toc snort_manual.aux snort_manual.pdf snort_manual.out snort_manual.idx docdir = ${datadir}/doc/${PACKAGE} SUFFIXES = .tex .dvi .ps .tex.dvi: pslatex $< && pslatex $< && pslatex $< .dvi.ps: dvips $< -o .ps.pdf: ps2pdf $< .tex.html: latex2html -local_icons $< # perhaps one day, we will have a Makefile in the signatures directory... # SUBDIRS = signatures snort-2.9.6.0/doc/Makefile.in0000644000000000000000000003714012260606517012546 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(dist_doc_DATA) AUTHORS INSTALL NEWS README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(docdir)" DATA = $(dist_doc_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = ${datadir}/doc/${PACKAGE} dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies EXTRA_DIST = \ snort_manual.pdf \ snort_manual.tex dist_doc_DATA = \ AUTHORS \ BUGS \ CREDITS \ generators \ INSTALL \ NEWS \ PROBLEMS \ README \ README.active \ README.alert_order \ README.asn1 \ README.counts \ README.csv \ README.daq \ README.dcerpc2 \ README.decode \ README.decoder_preproc_rules \ README.dnp3 \ README.dns \ README.event_queue \ README.file \ README.file_ips \ README.filters \ README.flowbits \ README.frag3 \ README.ftptelnet \ README.gre \ README.GTP \ README.ha \ README.http_inspect \ README.imap \ README.ipip \ README.ipv6 \ README.modbus \ README.multipleconfigs \ README.normalize \ README.pcap_readmode \ README.PerfProfiling \ README.PLUGINS \ README.pop \ README.ppm \ README.reload \ README.reputation \ README.rzb_saac \ README.sensitive_data \ README.sfportscan \ README.SMTP \ README.ssh \ README.ssl \ README.sip \ README.stream5 \ README.tag \ README.thresholding \ README.UNSOCK \ README.unified2 \ README.variables \ README.WIN32 \ TODO \ USAGE \ WISHLIST DISTCLEANFILES = snort_manual.log snort_manual.toc snort_manual.aux snort_manual.pdf snort_manual.out snort_manual.idx SUFFIXES = .tex .dvi .ps all: all-am .SUFFIXES: .SUFFIXES: .tex .dvi .ps .html .pdf $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(docdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_docDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_docDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-dist_docDATA install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-dist_docDATA .tex.dvi: pslatex $< && pslatex $< && pslatex $< .dvi.ps: dvips $< -o .ps.pdf: ps2pdf $< .tex.html: latex2html -local_icons $< # perhaps one day, we will have a Makefile in the signatures directory... # SUBDIRS = signatures # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/ylwrap0000755000000000000000000001553612260606526011205 00000000000000#! /bin/sh # ylwrap - wrapper for lex/yacc invocations. scriptversion=2012-12-21.17; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . get_dirname () { case $1 in */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';; # Otherwise, we want the empty string (not "."). esac } # guard FILE # ---------- # The CPP macro used to guard inclusion of FILE. guard() { printf '%s\n' "$1" \ | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \ -e 's/__*/_/g' } # quote_for_sed [STRING] # ---------------------- # Return STRING (or stdin) quoted to be used as a sed pattern. quote_for_sed () { case $# in 0) cat;; 1) printf '%s\n' "$1";; esac \ | sed -e 's|[][\\.*]|\\&|g' } case "$1" in '') echo "$0: No files given. Try '$0 --help' for more information." 1>&2 exit 1 ;; --basedir) basedir=$2 shift 2 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . EOF exit $? ;; -v|--v*) echo "ylwrap $scriptversion" exit $? ;; esac # The input. input="$1" shift # We'll later need for a correct munging of "#line" directives. input_sub_rx=`get_dirname "$input" | quote_for_sed` case "$input" in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. input="`pwd`/$input" ;; esac input_rx=`get_dirname "$input" | quote_for_sed` # Since DOS filename conventions don't allow two dots, # the DOS version of Bison writes out y_tab.c instead of y.tab.c # and y_tab.h instead of y.tab.h. Test to see if this is the case. y_tab_nodot=false if test -f y_tab.c || test -f y_tab.h; then y_tab_nodot=true fi # The parser itself, the first file, is the destination of the .y.c # rule in the Makefile. parser=$1 # A sed program to s/FROM/TO/g for all the FROM/TO so that, for # instance, we rename #include "y.tab.h" into #include "parse.h" # during the conversion from y.tab.c to parse.c. sed_fix_filenames= # Also rename header guards, as Bison 2.7 for instance uses its header # guard in its implementation file. sed_fix_header_guards= while test "$#" -ne 0; do if test "$1" = "--"; then shift break fi from=$1 # Handle y_tab.c and y_tab.h output by DOS if $y_tab_nodot; then case $from in "y.tab.c") from=y_tab.c;; "y.tab.h") from=y_tab.h;; esac fi shift to=$1 shift sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;" sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;" done # The program to run. prog="$1" shift # Make any relative path in $prog absolute. case "$prog" in [\\/]* | ?:[\\/]*) ;; *[\\/]*) prog="`pwd`/$prog" ;; esac # FIXME: add hostname here for parallel makes that run commands on # other machines. But that might take us over the 14-char limit. dirname=ylwrap$$ do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then for from in * do to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"` if test -f "$from"; then # If $2 is an absolute path name, then just use that, # otherwise prepend '../'. case $to in [\\/]* | ?:[\\/]*) target=$to;; *) target="../$to";; esac # Do not overwrite unchanged header files to avoid useless # recompilations. Always update the parser itself: it is the # destination of the .y.c rule in the Makefile. Divert the # output of all other files to a temporary file so we can # compare them to existing versions. if test $from != $parser; then realtarget="$target" target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'` fi # Munge "#line" or "#" directives. Don't let the resulting # debug information point at an absolute srcdir. Use the real # output file name, not yy.lex.c for instance. Adjust the # include guards too. sed -e "/^#/!b" \ -e "s|$input_rx|$input_sub_rx|" \ -e "$sed_fix_filenames" \ -e "$sed_fix_header_guards" \ "$from" >"$target" || ret=$? # Check whether files must be updated. if test "$from" != "$parser"; then if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then echo "$to is unchanged" rm -f "$target" else echo "updating $to" mv -f "$target" "$realtarget" fi fi else # A missing file is only an error for the parser. This is a # blatant hack to let us support using "yacc -d". If -d is not # specified, don't fail when the header file is "missing". if test "$from" = "$parser"; then ret=1 fi fi done fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: snort-2.9.6.0/src/0000755000000000000000000000000012260606567010603 500000000000000snort-2.9.6.0/src/side-channel/0000755000000000000000000000000012260606567013135 500000000000000snort-2.9.6.0/src/side-channel/plugins/0000755000000000000000000000000012260606570014610 500000000000000snort-2.9.6.0/src/side-channel/plugins/sscm_logger.h0000644000000000000000000000202412260565733017210 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifndef __SSCM_LOGGER_H__ #define __SSCM_LOGGER_H__ int SetupLoggerSCM(void); #endif snort-2.9.6.0/src/side-channel/plugins/sscm_logger.c0000644000000000000000000001270112260565733017206 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #include #include #include #include #include #include "sidechannel.h" #include "sscm_logger.h" #include "util.h" #define CONF_SEPARATORS " \t\n\r," #define CONF_RX_FILE "rx-log-file" #define CONF_TX_FILE "tx-log-file" #define CONF_PRIMER_FILE "primer-file" enum ConfState { STATE_START, STATE_RX_FILE, STATE_TX_FILE, STATE_PRIMER_FILE }; static char rx_log_file[PATH_MAX]; static int rx_log_fd = -1; static char tx_log_file[PATH_MAX]; static int tx_log_fd = -1; static char primer_log_file[PATH_MAX]; static int LoggerRXHandler(SCMsgHdr *hdr, const uint8_t *msg, uint32_t length) { SideChannelWriteMsgToFile(rx_log_fd, hdr, msg, length); return 0; } static int LoggerTXHandler(SCMsgHdr *hdr, const uint8_t *msg, uint32_t length) { SideChannelWriteMsgToFile(tx_log_fd, hdr, msg, length); return 0; } static int ConfigLogger(char *args) { char *token; char *argcpy = args; enum ConfState confState = STATE_START; for (token = strtok(argcpy, CONF_SEPARATORS); token; token = strtok(NULL, CONF_SEPARATORS)) { switch (confState) { case STATE_START: if (strcmp(token, CONF_RX_FILE) == 0) confState = STATE_RX_FILE; else if (strcmp(token, CONF_TX_FILE) == 0) confState = STATE_TX_FILE; else if (strcmp(token, CONF_PRIMER_FILE) == 0) confState = STATE_PRIMER_FILE; else FatalError("Invalid logger side channel configuration token: '%s'\n", token); break; case STATE_RX_FILE: snprintf(rx_log_file, sizeof(rx_log_file), "%s", token); confState = STATE_START; break; case STATE_TX_FILE: snprintf(tx_log_file, sizeof(tx_log_file), "%s", token); confState = STATE_START; break; case STATE_PRIMER_FILE: snprintf(primer_log_file, sizeof(primer_log_file), "%s", token); confState = STATE_START; break; default: break; } } return 0; } static int InitLogger(void) { if (rx_log_file[0] != '\0') { LogMessage("Opening '%s' for side channel RX logging...\n", rx_log_file); rx_log_fd = open(rx_log_file, O_WRONLY|O_CREAT|O_TRUNC, 0664); if (rx_log_fd == -1) FatalError("Could not open Logger SCM RX log file '%s': %s (%d)\n", rx_log_file, strerror(errno), errno); SideChannelRegisterRXHandler(SC_MSG_TYPE_ANY, LoggerRXHandler, NULL); } if (tx_log_file[0] != '\0') { LogMessage("Opening '%s' for side channel TX logging...\n", tx_log_file); tx_log_fd = open(tx_log_file, O_WRONLY|O_CREAT|O_TRUNC, 0664); if (tx_log_fd == -1) FatalError("Could not open Logger SCM TX log file '%s': %s (%d)\n", tx_log_file, strerror(errno), errno); SideChannelRegisterTXHandler(SC_MSG_TYPE_ANY, LoggerTXHandler, NULL); } return 0; } static int PostInitLogger(void) { SCMsgHdr hdr; uint32_t length; uint8_t *msg; unsigned int messages; int fd; if (primer_log_file[0] != '\0') { fd = open(primer_log_file, O_RDONLY, 0664); if (fd == -1) FatalError("Could not open Logger SCM Primer log file '%s': %s (%d)\n", primer_log_file, strerror(errno), errno); messages = 0; while (SideChannelReadMsgFromFile(fd, &hdr, &msg, &length) == 0) { if (length == 0) msg = NULL; SideChannelEnqueueDataRX(&hdr, msg, length, free); messages++; } close(fd); LogMessage("Primed the side channel with %u messages from '%s'...\n", messages, primer_log_file); } return 0; } static void ShutdownLogger(void) { if (rx_log_fd != -1) { close(rx_log_fd); rx_log_fd = -1; SideChannelUnregisterRXHandler(SC_MSG_TYPE_ANY, LoggerRXHandler); } if (tx_log_fd) { close(tx_log_fd); tx_log_fd = -1; SideChannelUnregisterTXHandler(SC_MSG_TYPE_ANY, LoggerTXHandler); } } static SCMFunctionBundle loggerFuncs = { .configFunc = ConfigLogger, .initFunc = InitLogger, .postInitFunc = PostInitLogger, .idleFunc = NULL, .statsFunc = NULL, .shutdownFunc = ShutdownLogger }; int SetupLoggerSCM(void) { RegisterSideChannelModule("logger", &loggerFuncs); return 0; } snort-2.9.6.0/src/side-channel/plugins/Makefile.am0000644000000000000000000000023112153454771016565 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libsscm.a libsscm_a_SOURCES = \ sscm_logger.c sscm_logger.h INCLUDES = @INCLUDES@ snort-2.9.6.0/src/side-channel/plugins/Makefile.in0000644000000000000000000003770712260606526016614 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/side-channel/plugins DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libsscm_a_AR = $(AR) $(ARFLAGS) libsscm_a_LIBADD = am_libsscm_a_OBJECTS = sscm_logger.$(OBJEXT) libsscm_a_OBJECTS = $(am_libsscm_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsscm_a_SOURCES) DIST_SOURCES = $(libsscm_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libsscm.a libsscm_a_SOURCES = \ sscm_logger.c sscm_logger.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/side-channel/plugins/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/side-channel/plugins/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libsscm.a: $(libsscm_a_OBJECTS) $(libsscm_a_DEPENDENCIES) $(EXTRA_libsscm_a_DEPENDENCIES) $(AM_V_at)-rm -f libsscm.a $(AM_V_AR)$(libsscm_a_AR) libsscm.a $(libsscm_a_OBJECTS) $(libsscm_a_LIBADD) $(AM_V_at)$(RANLIB) libsscm.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/side-channel/dynamic-plugins/0000755000000000000000000000000012260606567016240 500000000000000snort-2.9.6.0/src/side-channel/dynamic-plugins/sf_dynamic_side_channel_lib.c0000644000000000000000000000416212260565733023764 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "sf_dynamic_define.h" #include "sf_dynamic_meta.h" #include "sf_dynamic_common.h" #include "sf_dynamic_side_channel_lib.h" #include "sf_dynamic_side_channel.h" #include "sf_side_channel_info.h" DynamicSideChannelData _dscd; SIDE_CHANNEL_LINKAGE int InitializeSideChannel(DynamicSideChannelData *dscd) { if (dscd->version < SIDE_CHANNEL_DATA_VERSION) { printf("ERROR version %d < %d\n", dscd->version, SIDE_CHANNEL_DATA_VERSION); return -1; } if (dscd->size != sizeof(DynamicSideChannelData)) { printf("ERROR size %d != %u\n", dscd->size, (unsigned)sizeof(*dscd)); return -2; } _dscd = *dscd; DYNAMIC_SIDE_CHANNEL_SETUP(); return 0; } SIDE_CHANNEL_LINKAGE int LibVersion(DynamicPluginMeta *dpm) { dpm->type = TYPE_SIDE_CHANNEL; dpm->major = MAJOR_VERSION; dpm->minor = MINOR_VERSION; dpm->build = BUILD_VERSION; strncpy(dpm->uniqueName, SIDE_CHANNEL_NAME, MAX_NAME_LEN-1); dpm->uniqueName[MAX_NAME_LEN-1] = '\0'; return 0; } snort-2.9.6.0/src/side-channel/dynamic-plugins/sf_side_channel_info.h0000644000000000000000000000231312260565733022446 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifndef SF_PREPROC_INFO_H_ #define SF_PREPROC_INFO_H_ extern const int MAJOR_VERSION; extern const int MINOR_VERSION; extern const int BUILD_VERSION; extern const char *SIDE_CHANNEL_NAME; extern void DYNAMIC_SIDE_CHANNEL_SETUP(void); #endif /* SF_PREPROC_INFO_H_ */ snort-2.9.6.0/src/side-channel/dynamic-plugins/sf_dynamic_side_channel_lib.h0000644000000000000000000000243312260565733023770 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifndef SFSNORT_DYNAMIC_SIDE_CHANNEL_LIB_H_ #define SFSNORT_DYNAMIC_SIDE_CHANNEL_LIB_H_ #ifdef WIN32 #ifdef SF_SNORT_SIDE_CHANNEL_DLL #define BUILDING_SO #define SIDE_CHANNEL_LINKAGE SO_PUBLIC #else #define SIDE_CHANNEL_LINKAGE #endif #else /* WIN32 */ #define SIDE_CHANNEL_LINKAGE SO_PUBLIC #endif #endif /* SFSNORT_DYNAMIC_SIDE_CHANNEL_LIB_H_ */ snort-2.9.6.0/src/side-channel/dynamic-plugins/snort_side_channel.pc.in0000644000000000000000000000072712153454771022757 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ libdir=@libdir@ package=@PACKAGE@ includedir=@includedir@ datarootdir=@datarootdir@ datadir=@datadir@ mandir=@infodir@ infodir=@infodir@ Name: Snort Description: Snort dynamic side channel modules URL: www.snort.org Version: @VERSION@ Libs: -L${libdir}/${package}/dynamic_side_channel -lsf_dynamic_side_channel Cflags: -I${includedir}/${package}/dynamic_side_channel @CONFIGFLAGS@ @CCONFIGFLAGS@ @ICONFIGFLAGS@ snort-2.9.6.0/src/side-channel/dynamic-plugins/Makefile.am0000644000000000000000000000154612165114052020205 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies if SO_WITH_STATIC_LIB sidechannellibdir=$(pkglibdir)/dynamic_side_channel sidechannellibincludedir=$(pkgincludedir)/dynamic_side_channel sidechannellib_LTLIBRARIES = libsf_dynamic_side_channel.la libsf_dynamic_side_channel_la_CFLAGS = -fPIC -DPIC libsf_dynamic_side_channel_la_LDFLAGS = -static libsf_dynamic_side_channel_la_SOURCES = \ sf_dynamic_side_channel_lib.c nodist_sidechannellibinclude_HEADERS = \ ../sidechannel_define.h \ ../../dynamic-plugins/sf_dynamic_common.h \ ../../dynamic-plugins/sf_dynamic_define.h \ ../../dynamic-plugins/sf_dynamic_meta.h \ ../../dynamic-plugins/sf_dynamic_side_channel.h sidechannellibinclude_HEADERS = \ sf_dynamic_side_channel_lib.h \ sf_side_channel_info.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = snort_side_channel.pc endif snort-2.9.6.0/src/side-channel/dynamic-plugins/Makefile.in0000644000000000000000000006162112260606526020226 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/side-channel/dynamic-plugins DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/snort_side_channel.pc.in \ $(am__sidechannellibinclude_HEADERS_DIST) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = snort_side_channel.pc CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(sidechannellibdir)" \ "$(DESTDIR)$(pkgconfigdir)" \ "$(DESTDIR)$(sidechannellibincludedir)" \ "$(DESTDIR)$(sidechannellibincludedir)" LTLIBRARIES = $(sidechannellib_LTLIBRARIES) libsf_dynamic_side_channel_la_LIBADD = am__libsf_dynamic_side_channel_la_SOURCES_DIST = \ sf_dynamic_side_channel_lib.c @SO_WITH_STATIC_LIB_TRUE@am_libsf_dynamic_side_channel_la_OBJECTS = libsf_dynamic_side_channel_la-sf_dynamic_side_channel_lib.lo libsf_dynamic_side_channel_la_OBJECTS = \ $(am_libsf_dynamic_side_channel_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_dynamic_side_channel_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libsf_dynamic_side_channel_la_CFLAGS) $(CFLAGS) \ $(libsf_dynamic_side_channel_la_LDFLAGS) $(LDFLAGS) -o $@ @SO_WITH_STATIC_LIB_TRUE@am_libsf_dynamic_side_channel_la_rpath = \ @SO_WITH_STATIC_LIB_TRUE@ -rpath $(sidechannellibdir) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_dynamic_side_channel_la_SOURCES) DIST_SOURCES = $(am__libsf_dynamic_side_channel_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(pkgconfig_DATA) am__sidechannellibinclude_HEADERS_DIST = \ sf_dynamic_side_channel_lib.h sf_side_channel_info.h HEADERS = $(nodist_sidechannellibinclude_HEADERS) \ $(sidechannellibinclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies @SO_WITH_STATIC_LIB_TRUE@sidechannellibdir = $(pkglibdir)/dynamic_side_channel @SO_WITH_STATIC_LIB_TRUE@sidechannellibincludedir = $(pkgincludedir)/dynamic_side_channel @SO_WITH_STATIC_LIB_TRUE@sidechannellib_LTLIBRARIES = libsf_dynamic_side_channel.la @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_side_channel_la_CFLAGS = -fPIC -DPIC @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_side_channel_la_LDFLAGS = -static @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_side_channel_la_SOURCES = \ @SO_WITH_STATIC_LIB_TRUE@ sf_dynamic_side_channel_lib.c @SO_WITH_STATIC_LIB_TRUE@nodist_sidechannellibinclude_HEADERS = \ @SO_WITH_STATIC_LIB_TRUE@ ../sidechannel_define.h \ @SO_WITH_STATIC_LIB_TRUE@ ../../dynamic-plugins/sf_dynamic_common.h \ @SO_WITH_STATIC_LIB_TRUE@ ../../dynamic-plugins/sf_dynamic_define.h \ @SO_WITH_STATIC_LIB_TRUE@ ../../dynamic-plugins/sf_dynamic_meta.h \ @SO_WITH_STATIC_LIB_TRUE@ ../../dynamic-plugins/sf_dynamic_side_channel.h @SO_WITH_STATIC_LIB_TRUE@sidechannellibinclude_HEADERS = \ @SO_WITH_STATIC_LIB_TRUE@ sf_dynamic_side_channel_lib.h \ @SO_WITH_STATIC_LIB_TRUE@ sf_side_channel_info.h @SO_WITH_STATIC_LIB_TRUE@pkgconfigdir = $(libdir)/pkgconfig @SO_WITH_STATIC_LIB_TRUE@pkgconfig_DATA = snort_side_channel.pc all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/side-channel/dynamic-plugins/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/side-channel/dynamic-plugins/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): snort_side_channel.pc: $(top_builddir)/config.status $(srcdir)/snort_side_channel.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-sidechannellibLTLIBRARIES: $(sidechannellib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(sidechannellib_LTLIBRARIES)'; test -n "$(sidechannellibdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(sidechannellibdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sidechannellibdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(sidechannellibdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(sidechannellibdir)"; \ } uninstall-sidechannellibLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(sidechannellib_LTLIBRARIES)'; test -n "$(sidechannellibdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(sidechannellibdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(sidechannellibdir)/$$f"; \ done clean-sidechannellibLTLIBRARIES: -test -z "$(sidechannellib_LTLIBRARIES)" || rm -f $(sidechannellib_LTLIBRARIES) @list='$(sidechannellib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_dynamic_side_channel.la: $(libsf_dynamic_side_channel_la_OBJECTS) $(libsf_dynamic_side_channel_la_DEPENDENCIES) $(EXTRA_libsf_dynamic_side_channel_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_dynamic_side_channel_la_LINK) $(am_libsf_dynamic_side_channel_la_rpath) $(libsf_dynamic_side_channel_la_OBJECTS) $(libsf_dynamic_side_channel_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< libsf_dynamic_side_channel_la-sf_dynamic_side_channel_lib.lo: sf_dynamic_side_channel_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_side_channel_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_side_channel_la-sf_dynamic_side_channel_lib.lo `test -f 'sf_dynamic_side_channel_lib.c' || echo '$(srcdir)/'`sf_dynamic_side_channel_lib.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) install-nodist_sidechannellibincludeHEADERS: $(nodist_sidechannellibinclude_HEADERS) @$(NORMAL_INSTALL) @list='$(nodist_sidechannellibinclude_HEADERS)'; test -n "$(sidechannellibincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sidechannellibincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sidechannellibincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(sidechannellibincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(sidechannellibincludedir)" || exit $$?; \ done uninstall-nodist_sidechannellibincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(nodist_sidechannellibinclude_HEADERS)'; test -n "$(sidechannellibincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(sidechannellibincludedir)'; $(am__uninstall_files_from_dir) install-sidechannellibincludeHEADERS: $(sidechannellibinclude_HEADERS) @$(NORMAL_INSTALL) @list='$(sidechannellibinclude_HEADERS)'; test -n "$(sidechannellibincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sidechannellibincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sidechannellibincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(sidechannellibincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(sidechannellibincludedir)" || exit $$?; \ done uninstall-sidechannellibincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(sidechannellibinclude_HEADERS)'; test -n "$(sidechannellibincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(sidechannellibincludedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(sidechannellibdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(sidechannellibincludedir)" "$(DESTDIR)$(sidechannellibincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-sidechannellibLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-nodist_sidechannellibincludeHEADERS \ install-pkgconfigDATA install-sidechannellibLTLIBRARIES \ install-sidechannellibincludeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nodist_sidechannellibincludeHEADERS \ uninstall-pkgconfigDATA uninstall-sidechannellibLTLIBRARIES \ uninstall-sidechannellibincludeHEADERS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-sidechannellibLTLIBRARIES cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man \ install-nodist_sidechannellibincludeHEADERS install-pdf \ install-pdf-am install-pkgconfigDATA install-ps install-ps-am \ install-sidechannellibLTLIBRARIES \ install-sidechannellibincludeHEADERS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-nodist_sidechannellibincludeHEADERS \ uninstall-pkgconfigDATA uninstall-sidechannellibLTLIBRARIES \ uninstall-sidechannellibincludeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/side-channel/sidechannel_define.h0000644000000000000000000000374012260565733017020 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifndef __SIDE_CHANNEL_DEFINE_H__ #define __SIDE_CHANNEL_DEFINE_H__ #include #define SC_USE_DMQ 1 /* You get 16 bits worth of types. Use them wisely. */ enum { SC_MSG_TYPE_NONE = 0, SC_MSG_TYPE_FLOW_STATE_TRACKING, SC_MSG_TYPE_ANY = 0xFFFF }; typedef struct _SC_MESSAGE_HEADER { uint16_t type; uint64_t timestamp; } SCMsgHdr; typedef struct _SC_MESSAGE_QUEUE_NODE *SCMessageQueueNodePtr; typedef void (*SCMQMsgFreeFunc)(void *); typedef int (*SCMConfigFunc)(char *); typedef int (*SCMInitFunc)(void); typedef int (*SCMPostInitFunc)(void); typedef void (*SCMStatsFunc)(int exiting); typedef void (*SCMIdleFunc)(void); typedef int (*SCMProcessMsgFunc)(SCMsgHdr *hdr, const uint8_t *msg, uint32_t length); typedef void (*SCMShutdownFunc)(void); typedef struct _SCM_FUNCTION_BUNDLE { SCMConfigFunc configFunc; SCMInitFunc initFunc; SCMPostInitFunc postInitFunc; SCMIdleFunc idleFunc; SCMStatsFunc statsFunc; SCMShutdownFunc shutdownFunc; } SCMFunctionBundle; #endif /* __SIDE_CHANNEL_DEFINE_H__ */ snort-2.9.6.0/src/side-channel/sidechannel.h0000644000000000000000000000575112260565733015512 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifndef __SIDE_CHANNEL_H__ #define __SIDE_CHANNEL_H__ #include "sidechannel_define.h" #include "snort.h" void SideChannelConfigure(SnortConfig *sc); void SideChannelInit(void); void SideChannelStartTXThread(void); void SideChannelStopTXThread(void); void SideChannelCleanUp(void); void RegisterSideChannelModule(const char *keyword, SCMFunctionBundle *funcs); void RegisterSideChannelModules(void); int SideChannelRegisterRXHandler(uint16_t type, SCMProcessMsgFunc processMsgFunc, void *data); int SideChannelRegisterTXHandler(uint16_t type, SCMProcessMsgFunc processMsgFunc, void *data); void SideChannelUnregisterRXHandler(uint16_t type, SCMProcessMsgFunc processMsgFunc); void SideChannelUnregisterTXHandler(uint16_t type, SCMProcessMsgFunc processMsgFunc); /* RX Functions */ int SideChannelPreallocMessageRX(uint32_t length, SCMsgHdr **hdr_ptr, uint8_t **msg_ptr, void **msg_handle); int SideChannelDiscardMessageRX(void *msg_handle); int SideChannelEnqueueMessageRX(SCMsgHdr *hdr, const uint8_t *msg, uint32_t length, void *msg_handle, SCMQMsgFreeFunc msgFreeFunc); int SideChannelEnqueueDataRX(SCMsgHdr *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc); uint32_t SideChannelDrainRX(unsigned max_msgs); /* TX Functions */ int SideChannelPreallocMessageTX(uint32_t length, SCMsgHdr **hdr_ptr, uint8_t **msg_ptr, void **msg_handle); int SideChannelDiscardMessageTX(void *msg_handle); int SideChannelEnqueueMessageTX(SCMsgHdr *hdr, const uint8_t *msg, uint32_t length, void *msg_handle, SCMQMsgFreeFunc msgFreeFunc); int SideChannelEnqueueDataTX(SCMsgHdr *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc); /* I/O Functions */ int SideChannelWriteMsgToFile(int fd, SCMsgHdr *hdr, const uint8_t *msg, uint32_t length); int SideChannelReadMsgFromFile(int fd, SCMsgHdr *hdr, uint8_t **msg_ptr, uint32_t *length_ptr); #ifdef SNORT_RELOAD int SideChannelVerifyConfig(SnortConfig *sc); #endif int ConfigureSideChannelModule(const char *keyword, char *opts); void SideChannelStats(int exiting, const char *separator); int SideChannelPostInit(void); #endif snort-2.9.6.0/src/side-channel/sidechannel.c0000644000000000000000000006763212260565733015513 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifdef SIDE_CHANNEL #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "dmq.h" #include "rbmq.h" #include "sidechannel.h" #include "sscm_logger.h" #define DEFAULT_RX_QUEUE_DEPTH 1024 #define DEFAULT_RX_QUEUE_DATA_SIZE 10485760 #define DEFAULT_TX_QUEUE_DEPTH 1024 #define DEFAULT_TX_QUEUE_DATA_SIZE 10485760 #define CONF_SEPARATORS " \t\n\r," #define CONF_RX_QUEUE_DATA_SIZE "rx-queue-data-size" #define CONF_RX_QUEUE_DEPTH "rx-queue-depth" #define CONF_TX_QUEUE_DATA_SIZE "tx-queue-data-size" #define CONF_TX_QUEUE_DEPTH "tx-queue-depth" #define CONF_DISABLE_TX_THREAD "disable-tx-thread" #ifdef SC_USE_DMQ #define RBMQ_Ptr DMQ_Ptr #define RBMQ_Alloc DMQ_Alloc #define RBMQ_ReserveMsg DMQ_ReserveMsg #define RBMQ_CommitReservedMsg DMQ_CommitReservedMsg #define RBMQ_DiscardReservedMsg DMQ_DiscardReservedMsg #define RBMQ_CommitExternalMsg DMQ_CommitExternalMsg #define RBMQ_ReadMsg DMQ_ReadMsg #define RBMQ_AckMsg DMQ_AckMsg #define RBMQ_IsEmpty DMQ_IsEmpty #define RBMQ_Stats DMQ_Stats #endif enum ConfState { STATE_START, STATE_RX_QUEUE_DATA_SIZE, STATE_RX_QUEUE_DEPTH, STATE_TX_QUEUE_DATA_SIZE, STATE_TX_QUEUE_DEPTH }; typedef struct _SC_CONFIG { uint32_t rx_queue_max_data_size; uint32_t rx_queue_max_depth; uint32_t tx_queue_max_data_size; uint32_t tx_queue_max_depth; bool disable_tx_thread; bool enabled; } SCConfig; typedef struct _SC_MODULE { struct _SC_MODULE *next; char *keyword; SCMFunctionBundle funcs; bool enabled; } SCModule; typedef struct _SC_HANDLER { struct _SC_HANDLER *next; uint16_t type; SCMProcessMsgFunc processMsgFunc; void *data; } SCHandler; typedef struct _SC_MESSAGE_QUEUE { RBMQ_Ptr queue; pthread_mutex_t mutex; pthread_cond_t cond; uint32_t max_data_size; uint32_t max_depth; } SCMessageQueue; static struct { uint64_t rx_messages_total; uint64_t rx_messages_processed_ib; uint64_t rx_messages_processed_oob; uint64_t tx_messages_total; uint64_t tx_messages_processed; } Side_Channel_Stats; static volatile int stop_processing = 0; static volatile int tx_thread_running = 0; static pid_t tx_thread_pid; static pthread_t tx_thread_id; static pthread_t *p_tx_thread_id; static SCConfig sc_config; static SCMessageQueue rx_queue; static SCMessageQueue tx_queue; static SCModule *modules; static SCHandler *rx_handlers; static SCHandler *tx_handlers; #ifdef PERF_PROFILING PreprocStats sideChannelRxPerfStats; #endif void RegisterSideChannelModules(void) { if (!ScSideChannelEnabled()) return; SetupLoggerSCM(); } void RegisterSideChannelModule(const char *keyword, SCMFunctionBundle *funcs) { SCModule *module, *tmp, *last = NULL; if (!ScSideChannelEnabled()) return; if (!keyword) FatalError("No keyword given while registering a side channel module!\n"); if (!funcs) FatalError("No function bundle given while registering side channel '%s'!\n", keyword); for (tmp = modules; tmp; tmp = tmp->next) { if (strcasecmp(tmp->keyword, keyword) == 0) FatalError("Duplicate side channel keyword: %s\n", keyword); last = tmp; } module = SnortAlloc(sizeof(SCModule)); module->next = NULL; module->keyword = SnortStrdup(keyword); module->funcs = *funcs; module->enabled = 0; LogMessage("Register SCM '%s' with configFunc=%p, initFunc=%p, postInitFunc=%p, idleFunc=%p, statsFunc=%p, shutdownFunc=%p\n", keyword, module->funcs.configFunc, module->funcs.initFunc, module->funcs.postInitFunc, module->funcs.idleFunc, module->funcs.statsFunc, module->funcs.shutdownFunc); if (last) last->next = module; else modules = module; } int ConfigureSideChannelModule(const char *keyword, char *opts) { SCModule *module; for (module = modules; module; module = module->next) { if (strcasecmp(module->keyword, keyword) == 0) break; } if (!module) return -ENOENT; module->funcs.configFunc(opts); module->enabled = 1; return 0; } static int SCRegisterHandler(SCHandler **handlers, uint16_t type, SCMProcessMsgFunc processMsgFunc, void *data) { SCHandler *handler; if (!ScSideChannelEnabled()) return 0; handler = SnortAlloc(sizeof(SCHandler)); handler->next = NULL; handler->type = type; handler->processMsgFunc = processMsgFunc; handler->data = data; handler->next = *handlers; *handlers = handler; return 0; } int SideChannelRegisterRXHandler(uint16_t type, SCMProcessMsgFunc processMsgFunc, void *data) { return SCRegisterHandler(&rx_handlers, type, processMsgFunc, data); } int SideChannelRegisterTXHandler(uint16_t type, SCMProcessMsgFunc processMsgFunc, void *data) { return SCRegisterHandler(&tx_handlers, type, processMsgFunc, data); } static void SCUnregisterHandler(SCHandler **handlers, uint16_t type, SCMProcessMsgFunc processMsgFunc) { SCHandler *handler, *prev; if (!ScSideChannelEnabled()) return; for (prev = NULL, handler = *handlers; handler; prev = handler, handler = handler->next) { if (handler->type == type && handler->processMsgFunc == processMsgFunc) break; } if (handler) { if (!prev) *handlers = handler->next; else prev->next = handler->next; free(handler); } } void SideChannelUnregisterRXHandler(uint16_t type, SCMProcessMsgFunc processMsgFunc) { SCUnregisterHandler(&rx_handlers, type, processMsgFunc); } void SideChannelUnregisterTXHandler(uint16_t type, SCMProcessMsgFunc processMsgFunc) { SCUnregisterHandler(&tx_handlers, type, processMsgFunc); } static int SCPreallocMessage(SCMessageQueue *mq, uint32_t length, SCMsgHdr **hdr_ptr, uint8_t **msg_ptr, void **msg_handle) { int rval; pthread_mutex_lock(&mq->mutex); rval = RBMQ_ReserveMsg(mq->queue, length, (void **) hdr_ptr, msg_ptr, msg_handle); pthread_mutex_unlock(&mq->mutex); return rval; } int SideChannelPreallocMessageRX(uint32_t length, SCMsgHdr **hdr_ptr, uint8_t **msg_ptr, void **msg_handle) { return SCPreallocMessage(&rx_queue, length, hdr_ptr, msg_ptr, msg_handle); } int SideChannelPreallocMessageTX(uint32_t length, SCMsgHdr **hdr_ptr, uint8_t **msg_ptr, void **msg_handle) { return SCPreallocMessage(&tx_queue, length, hdr_ptr, msg_ptr, msg_handle); } static int SCDiscardMessage(SCMessageQueue *mq, void *msg_handle) { int rval; pthread_mutex_lock(&mq->mutex); rval = RBMQ_DiscardReservedMsg(mq->queue, msg_handle); pthread_mutex_unlock(&mq->mutex); return rval; } int SideChannelDiscardMessageRX(void *msg_handle) { return SCDiscardMessage(&rx_queue, msg_handle); } int SideChannelDiscardMessageTX(void *msg_handle) { return SCDiscardMessage(&tx_queue, msg_handle); } static int SCEnqueueMessage(SCMessageQueue *mq, SCMsgHdr *hdr, const uint8_t *msg, uint32_t length, void *msg_handle, SCMQMsgFreeFunc msgFreeFunc) { int rval; if (!msg_handle) { SCMsgHdr *hdr_ptr; uint8_t *msg_ptr; rval = RBMQ_ReserveMsg(mq->queue, length, (void **) &hdr_ptr, &msg_ptr, &msg_handle); if (rval != 0) { ErrorMessage("%s: Could not reserve message: %d\n", __FUNCTION__, rval); return rval; } memcpy(msg_ptr, msg, length); memcpy(hdr_ptr, hdr, sizeof(SCMsgHdr)); rval = RBMQ_CommitReservedMsg(mq->queue, msg_handle, length, msgFreeFunc); if (rval != 0) { ErrorMessage("%s: Could not commit reserved message: %d\n", __FUNCTION__, rval); return rval; } } else rval = RBMQ_CommitReservedMsg(mq->queue, msg_handle, length, msgFreeFunc); return rval; } static inline void SCProcessMessage(SCHandler *handlers, SCMsgHdr *hdr, const uint8_t *msg, uint32_t length) { SCHandler *handler; for (handler = handlers; handler; handler = handler->next) { if (hdr->type == handler->type || handler->type == SC_MSG_TYPE_ANY) handler->processMsgFunc(hdr, msg, length); } } static int SCDrainAndProcess(SCMessageQueue *mq, SCHandler *handlers) { SCMsgHdr *hdr; uint32_t length; const uint8_t *msg; void *msg_handle; int rval; /* Read a message from the queue. */ pthread_mutex_lock(&mq->mutex); rval = RBMQ_ReadMsg(mq->queue, (const void **) &hdr, &msg, &length, &msg_handle); pthread_mutex_unlock(&mq->mutex); if (rval != 0) return 1; /* Handle it. */ SCProcessMessage(handlers, hdr, msg, length); /* And, finally, acknowledge it. */ pthread_mutex_lock(&mq->mutex); rval = RBMQ_AckMsg(mq->queue, msg_handle); pthread_mutex_unlock(&mq->mutex); if (rval != 0) WarningMessage("Error ACK'ing message %p!\n", msg_handle); return 0; } /* Called by an out-of-band thread (probably a Side Channel Module). */ int SideChannelEnqueueMessageRX(SCMsgHdr *hdr, const uint8_t *msg, uint32_t length, void *msg_handle, SCMQMsgFreeFunc msgFreeFunc) { int rval; /* * Because the Snort main thread relinquishes control to DAQ_Acquire for up to a second, * we potentially need to preempt it and process RX messages as they are being enqueued * to avoid backups and overruns. * This should be safe since the main thread holds the snort_process_lock mutex while it * is not in DAQ_Acquire(). */ while (pthread_mutex_trylock(&snort_process_lock) == 0) { /* If there are no more messages in the RX queue, process the new message without enqueuing it and return. */ if (SCDrainAndProcess(&rx_queue, rx_handlers) != 0) { SCProcessMessage(rx_handlers, hdr, msg, length); if (msgFreeFunc) msgFreeFunc((uint8_t *) msg); if (msg_handle) { pthread_mutex_lock(&rx_queue.mutex); RBMQ_DiscardReservedMsg(rx_queue.queue, msg_handle); pthread_mutex_unlock(&rx_queue.mutex); } Side_Channel_Stats.rx_messages_total++; Side_Channel_Stats.rx_messages_processed_oob++; pthread_mutex_unlock(&snort_process_lock); return 0; } else Side_Channel_Stats.rx_messages_processed_oob++; pthread_mutex_unlock(&snort_process_lock); } /* Finally, enqueue the message if we really have to. */ pthread_mutex_lock(&rx_queue.mutex); rval = SCEnqueueMessage(&rx_queue, hdr, msg, length, msg_handle, msgFreeFunc); /* TODO: Error check the above call. */ Side_Channel_Stats.rx_messages_total++; pthread_mutex_unlock(&rx_queue.mutex); return rval; } /* Called in the Snort main thread. */ int SideChannelEnqueueMessageTX(SCMsgHdr *hdr, const uint8_t *msg, uint32_t length, void *msg_handle, SCMQMsgFreeFunc msgFreeFunc) { int rval, empty; /* Only bother queuing if the TX thread is running, otherwise just immediately process. */ if (tx_thread_running) { pthread_mutex_lock(&tx_queue.mutex); empty = RBMQ_IsEmpty(tx_queue.queue); rval = SCEnqueueMessage(&tx_queue, hdr, msg, length, msg_handle, msgFreeFunc); /* TODO: Error check the above call. */ Side_Channel_Stats.tx_messages_total++; /* If the queue was empty, signal any waiters. */ if (empty) pthread_cond_signal(&tx_queue.cond); pthread_mutex_unlock(&tx_queue.mutex); } else { SCProcessMessage(tx_handlers, hdr, msg, length); Side_Channel_Stats.tx_messages_total++; Side_Channel_Stats.tx_messages_processed++; if (msgFreeFunc) msgFreeFunc((uint8_t *) msg); if (msg_handle) { pthread_mutex_lock(&tx_queue.mutex); RBMQ_DiscardReservedMsg(tx_queue.queue, msg_handle); pthread_mutex_unlock(&tx_queue.mutex); } rval = 0; } return rval; } static int SCEnqueueData(SCMessageQueue *mq, SCMsgHdr *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc) { return RBMQ_CommitExternalMsg(mq->queue, hdr, msg, length, msgFreeFunc); } /* Called by an out-of-band thread (probably a Side Channel Module). */ int SideChannelEnqueueDataRX(SCMsgHdr *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc) { int rval; pthread_mutex_lock(&rx_queue.mutex); rval = SCEnqueueData(&rx_queue, hdr, msg, length, msgFreeFunc); /* TODO: Error check the above call. */ Side_Channel_Stats.rx_messages_total++; pthread_mutex_unlock(&rx_queue.mutex); return rval; } /* Called in the Snort main thread. */ int SideChannelEnqueueDataTX(SCMsgHdr *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc) { int rval, empty; /* Only bother queuing if the TX thread is running, otherwise just immediately process. */ if (tx_thread_running) { pthread_mutex_lock(&tx_queue.mutex); empty = RBMQ_IsEmpty(tx_queue.queue); rval = SCEnqueueData(&tx_queue, hdr, msg, length, msgFreeFunc); /* TODO: Error check the above call. */ Side_Channel_Stats.tx_messages_total++; /* If the queue was empty, signal any waiters. */ if (empty) pthread_cond_signal(&tx_queue.cond); pthread_mutex_unlock(&tx_queue.mutex); } else { SCProcessMessage(tx_handlers, hdr, msg, length); Side_Channel_Stats.tx_messages_total++; Side_Channel_Stats.tx_messages_processed++; msgFreeFunc(msg); rval = 0; } return rval; } /* Called in the Snort main thread. */ uint32_t SideChannelDrainRX(unsigned max_msgs) { uint32_t processed = 0; if (!ScSideChannelEnabled()) return 0; if (RBMQ_IsEmpty(rx_queue.queue)) return 0; while (!max_msgs || processed < max_msgs) { if (stop_processing || SCDrainAndProcess(&rx_queue, rx_handlers) != 0) break; Side_Channel_Stats.rx_messages_processed_ib++; processed++; } return processed; } static void *SideChannelThread(void *arg) { struct timespec ts; struct timeval tv; SCHandler *handler; SCModule *module; SCMsgHdr *hdr; uint32_t length; const uint8_t *msg; void *msg_handle; int rval; tx_thread_pid = gettid(); tx_thread_running = 1; pthread_mutex_lock(&tx_queue.mutex); while (!stop_processing) { /* If the message queue is empty, we will stop without unlocking it so we can immediately start a timed wait. */ while ((rval = RBMQ_ReadMsg(tx_queue.queue, (const void **) &hdr, &msg, &length, &msg_handle)) == 0) { pthread_mutex_unlock(&tx_queue.mutex); for (handler = tx_handlers; handler; handler = handler->next) { if (hdr->type == handler->type || handler->type == SC_MSG_TYPE_ANY) handler->processMsgFunc(hdr, msg, length); } pthread_mutex_lock(&tx_queue.mutex); rval = RBMQ_AckMsg(tx_queue.queue, msg_handle); if (rval != 0) WarningMessage("Error ACK'ing message %p!\n", msg_handle); /* Again, not unlocking so that we're already locked for the three places we can go from here, which are all expecting it (dequeue, timed wait, or done). */ Side_Channel_Stats.tx_messages_processed++; if (stop_processing) goto done; } gettimeofday(&tv, NULL); ts.tv_sec = tv.tv_sec + 10; ts.tv_nsec = tv.tv_usec * 1000; rval = pthread_cond_timedwait(&tx_queue.cond, &tx_queue.mutex, &ts); /* If we timed out waiting for new output messages to process, run the registered idle routines. */ if (rval == ETIMEDOUT && !stop_processing) { for (module = modules; module; module = module->next) { if (module->enabled && module->funcs.idleFunc) module->funcs.idleFunc(); } } } done: pthread_mutex_unlock(&tx_queue.mutex); LogMessage("Side Channel thread exiting...\n"); return NULL; } static void SCParseConfiguration(SnortConfig *sc, SCConfig *config) { long int value; char *token, *argcpy, *endptr; enum ConfState confState = STATE_START; memset(config, 0, sizeof(SCConfig)); config->enabled = sc->side_channel_config.enabled; if (!config->enabled) return; config->rx_queue_max_data_size = DEFAULT_RX_QUEUE_DATA_SIZE; config->rx_queue_max_depth = DEFAULT_RX_QUEUE_DEPTH; config->tx_queue_max_data_size = DEFAULT_TX_QUEUE_DATA_SIZE; config->tx_queue_max_depth = DEFAULT_TX_QUEUE_DEPTH; config->disable_tx_thread = false; if (!sc->side_channel_config.opts) return; argcpy = sc->side_channel_config.opts; for (token = strtok(argcpy, CONF_SEPARATORS); token; token = strtok(NULL, CONF_SEPARATORS)) { switch (confState) { case STATE_START: if (strcmp(token, CONF_RX_QUEUE_DATA_SIZE) == 0) confState = STATE_RX_QUEUE_DATA_SIZE; else if (strcmp(token, CONF_RX_QUEUE_DEPTH) == 0) confState = STATE_RX_QUEUE_DEPTH; else if (strcmp(token, CONF_TX_QUEUE_DATA_SIZE) == 0) confState = STATE_TX_QUEUE_DATA_SIZE; else if (strcmp(token, CONF_TX_QUEUE_DEPTH) == 0) confState = STATE_TX_QUEUE_DEPTH; else if (strcmp(token, CONF_DISABLE_TX_THREAD) == 0) config->disable_tx_thread = true; else FatalError("Invalid side channel configuration token: '%s'\n", token); break; case STATE_RX_QUEUE_DATA_SIZE: confState = STATE_START; value = SnortStrtoul(token, &endptr, 0); if (errno != 0 || *endptr != '\0') FatalError("Invalid argument for side channel RX queue data size: '%s'\n", token); config->rx_queue_max_data_size = value; break; case STATE_RX_QUEUE_DEPTH: confState = STATE_START; value = SnortStrtoul(token, &endptr, 0); if (errno != 0 || *endptr != '\0') FatalError("Invalid argument for side channel RX queue depth: '%s'\n", token); config->rx_queue_max_depth = value; break; case STATE_TX_QUEUE_DATA_SIZE: confState = STATE_START; value = SnortStrtoul(token, &endptr, 0); if (errno != 0 || *endptr != '\0') FatalError("Invalid argument for side channel TX queue data size: '%s'\n", token); config->tx_queue_max_data_size = value; break; case STATE_TX_QUEUE_DEPTH: confState = STATE_START; value = SnortStrtoul(token, &endptr, 0); if (errno != 0 || *endptr != '\0') FatalError("Invalid argument for side channel TX queue depth: '%s'\n", token); config->tx_queue_max_depth = value; break; default: break; } } } #ifdef SNORT_RELOAD int SideChannelVerifyConfig(SnortConfig *sc) { SCConfig config; SCParseConfiguration(sc, &config); return memcmp(&config, &sc_config, sizeof(SCConfig)); } #endif void SideChannelConfigure(SnortConfig *sc) { if (!sc->side_channel_config.enabled) return; SCParseConfiguration(sc, &sc_config); rx_queue.max_data_size = sc_config.rx_queue_max_data_size; rx_queue.max_depth = sc_config.rx_queue_max_depth; tx_queue.max_data_size = sc_config.tx_queue_max_data_size; tx_queue.max_depth = sc_config.tx_queue_max_depth; LogMessage("Side Channel config:\n"); LogMessage(" RX Queue Max Data Size: %u\n", sc_config.rx_queue_max_data_size); LogMessage(" RX Queue Max Depth: %u\n", sc_config.rx_queue_max_depth); LogMessage(" TX Queue Max Data Size: %u\n", sc_config.tx_queue_max_data_size); LogMessage(" RX Queue Max Depth: %u\n", sc_config.tx_queue_max_depth); } void SideChannelInit(void) { SCModule *module; if (!ScSideChannelEnabled()) return; pthread_mutex_init(&rx_queue.mutex, NULL); pthread_cond_init(&rx_queue.cond, NULL); rx_queue.queue = RBMQ_Alloc(rx_queue.max_depth, sizeof(SCMsgHdr), rx_queue.max_data_size); pthread_cond_init(&tx_queue.cond, NULL); pthread_mutex_init(&tx_queue.mutex, NULL); tx_queue.queue = RBMQ_Alloc(tx_queue.max_depth, sizeof(SCMsgHdr), tx_queue.max_data_size); for (module = modules; module; module = module->next) { if (module->enabled && module->funcs.initFunc) module->funcs.initFunc(); } } void SideChannelStartTXThread(void) { const struct timespec thread_sleep = { 0, 100 }; SCModule *module; sigset_t mask; int found, rval; if (!ScSideChannelEnabled()) return; if (sc_config.disable_tx_thread) return; /* Avoid starting the TX thread if there are no TX handlers or TX idle tasks registered. */ found = 0; for (module = modules; module; module = module->next) { if (module->enabled && module->funcs.idleFunc) { found = 1; break; } } if (!found && !tx_handlers) { LogMessage("Not starting unnecessary Side Channel TX thread.\n"); return; } /* Spin off the Side Channel handler thread. */ sigemptyset(&mask); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGQUIT); sigaddset(&mask, SIGPIPE); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGNAL_SNORT_RELOAD); sigaddset(&mask, SIGNAL_SNORT_DUMP_STATS); sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR2); sigaddset(&mask, SIGNAL_SNORT_ROTATE_STATS); sigaddset(&mask, SIGNAL_SNORT_CHILD_READY); #ifdef TARGET_BASED sigaddset(&mask, SIGNAL_SNORT_READ_ATTR_TBL); sigaddset(&mask, SIGVTALRM); #endif pthread_sigmask(SIG_SETMASK, &mask, NULL); if ((rval = pthread_create(&tx_thread_id, NULL, &SideChannelThread, NULL)) != 0) { sigemptyset(&mask); pthread_sigmask(SIG_SETMASK, &mask, NULL); FatalError("Side Channel: Unable to create thread: %s\n", strerror(rval)); } while (!tx_thread_running) nanosleep(&thread_sleep, NULL); p_tx_thread_id = &tx_thread_id; sigemptyset(&mask); pthread_sigmask(SIG_SETMASK, &mask, NULL); LogMessage("Side Channel TX thread started tid=%p (pid=%u)\n", (void *) tx_thread_id, tx_thread_pid); } void SideChannelStopTXThread(void) { int rval; if (!ScSideChannelEnabled()) return; if (p_tx_thread_id != NULL) { stop_processing = 1; pthread_mutex_lock(&tx_queue.mutex); pthread_cond_signal(&tx_queue.cond); pthread_mutex_unlock(&tx_queue.mutex); if ((rval = pthread_join(*p_tx_thread_id, NULL)) != 0) WarningMessage("Side channel TX thread termination returned an error: %s\n", strerror(rval)); } } int SideChannelPostInit(void) { SCModule *module; if (!ScSideChannelEnabled()) return 0; for (module = modules; module; module = module->next) { if (module->enabled && module->funcs.postInitFunc) module->funcs.postInitFunc(); } return 0; } void SideChannelStats(int exiting, const char *separator) { SCModule *module; if (!ScSideChannelEnabled()) return; LogMessage("%s\n", separator); LogMessage("Side Channel:\n"); LogMessage(" RX Messages Total: %"PRIu64"\n", Side_Channel_Stats.rx_messages_total); LogMessage(" RX Messages Processed (IB): %"PRIu64"\n", Side_Channel_Stats.rx_messages_processed_ib); LogMessage(" RX Messages Processed (OOB): %"PRIu64"\n", Side_Channel_Stats.rx_messages_processed_oob); LogMessage(" TX Messages Total: %"PRIu64"\n", Side_Channel_Stats.tx_messages_total); LogMessage(" TX Messages Processed: %"PRIu64"\n", Side_Channel_Stats.tx_messages_processed); for (module = modules; module; module = module->next) { if (module->enabled && module->funcs.statsFunc) { LogMessage("%s\n", separator); module->funcs.statsFunc(exiting); } } LogMessage(" RX Queue Stats:\n"); RBMQ_Stats(rx_queue.queue, " "); LogMessage(" TX Queue Stats:\n"); RBMQ_Stats(tx_queue.queue, " "); } void SideChannelCleanUp(void) { SCModule *module; if (!ScSideChannelEnabled()) return; while ((module = modules)) { if (module->enabled) { if (module->funcs.statsFunc) module->funcs.statsFunc(1); if (module->funcs.shutdownFunc) module->funcs.shutdownFunc(); } modules = module->next; free(module->keyword); free(module); } pthread_cond_destroy(&tx_queue.cond); pthread_mutex_destroy(&tx_queue.mutex); pthread_cond_destroy(&rx_queue.cond); pthread_mutex_destroy(&rx_queue.mutex); } /* * WARNING: Messages are being written in and read assuming host byte order. */ static inline ssize_t Write(int fd, const void *buf, size_t count) { ssize_t n; errno = 0; while ((n = write(fd, buf, count)) <= (ssize_t) count) { if (n == (ssize_t) count) return 0; if (n > 0) count -= n; else if (errno != EINTR) break; } return -1; } int SideChannelWriteMsgToFile(int fd, SCMsgHdr *hdr, const uint8_t *msg, uint32_t length) { if (Write(fd, &hdr->type, sizeof(hdr->type)) != 0) return -1; if (Write(fd, &hdr->timestamp, sizeof(hdr->timestamp)) != 0) return -1; if (Write(fd, &length, sizeof(length)) != 0) return -1; if (Write(fd, msg, length) != 0) return -1; return 0; } static inline ssize_t Read(int fd, void *buf, size_t count) { ssize_t n; errno = 0; while ((n = read(fd, buf, count)) <= (ssize_t) count) { if (n == (ssize_t) count) return 0; if (n > 0) { count -= n; buf = (uint8_t *) buf + n; } else if (n == 0) break; else if (errno != EINTR) { ErrorMessage("Error reading Logger SCM log file: %s (%d)\n", strerror(errno), errno); break; } } return -1; } int SideChannelReadMsgFromFile(int fd, SCMsgHdr *hdr, uint8_t **msg_ptr, uint32_t *length_ptr) { uint64_t timestamp; uint32_t length; uint16_t type; uint8_t *msg; if (Read(fd, &type, sizeof(type)) != 0) return -1; if (Read(fd, ×tamp, sizeof(timestamp)) != 0) return -1; if (Read(fd, &length, sizeof(length)) != 0) return -1; if (length > 0) { msg = SnortAlloc(length); if (Read(fd, msg, length) != 0) { free(msg); return -1; } } else msg = NULL; hdr->type = type; hdr->timestamp = timestamp; *length_ptr = length; *msg_ptr = msg; return 0; } #endif /* SIDE_CHANNEL */ snort-2.9.6.0/src/side-channel/rbmq.h0000644000000000000000000000353412260565733014173 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifndef _RBMQ_H_ #define _RBMQ_H_ #include #include "sidechannel_define.h" #ifndef SC_USE_DMQ typedef struct _rbmq *RBMQ_Ptr; RBMQ_Ptr RBMQ_Alloc(uint32_t msg_ring_entries, uint16_t msg_ring_header_size, uint32_t data_ring_size); int RBMQ_ReserveMsg(RBMQ_Ptr mq, uint32_t length, void **hdr_ptr, uint8_t **msg_ptr, void **msg_handle); int RBMQ_CommitReservedMsg(RBMQ_Ptr mq, void *msg_handle, uint32_t length, SCMQMsgFreeFunc msgFreeFunc); int RBMQ_DiscardReservedMsg(RBMQ_Ptr mq, void *msg_handle); int RBMQ_CommitExternalMsg(RBMQ_Ptr mq, const void *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc); int RBMQ_ReadMsg(RBMQ_Ptr mq, const void **hdr_ptr, const uint8_t **msg_ptr, uint32_t *length, void **msg_handle); int RBMQ_AckMsg(RBMQ_Ptr mq, void *msg_handle); int RBMQ_IsEmpty(RBMQ_Ptr mq); void RBMQ_Stats(RBMQ_Ptr mq, const char *indent); #endif /* !SC_USE_DMQ */ #endif /* _RBMQ_H_ */ snort-2.9.6.0/src/side-channel/rbmq.c0000644000000000000000000003166012260565733014167 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifdef SIDE_CHANNEL #include #include #include "rbmq.h" #include "util.h" #ifndef SC_USE_DMQ #define RBMQ_MSG_FLAG_EXTERNAL 0x01 enum { RBMQ_MSG_STATE_UNUSED = 0, RBMQ_MSG_STATE_RESERVED, RBMQ_MSG_STATE_COMMITTED, RBMQ_MSG_STATE_READ, RBMQ_MSG_STATE_ACKED, RBMQ_MSG_STATE_DISCARDED }; typedef struct _rbmq_msg { uint32_t length; uint8_t flags; uint8_t state; uint8_t *data; SCMQMsgFreeFunc msgFreeFunc; } RBMQ_Msg; typedef struct _rmbq_internal_data_hdr { uint32_t msg_index; uint32_t prev_offset; } RBMQ_InternalDataHdr; typedef struct _rbmq_msg_ring { RBMQ_Msg *msgs; uint8_t *headers; uint32_t last_reserved; uint32_t last_read; uint32_t last_acked; uint32_t entries; uint16_t header_size; } RBMQ_MsgRing; typedef struct _rbmq_data_ring { uint8_t *data; uint32_t read_offset; uint32_t write_offset; uint32_t size; } RBMQ_DataRing; typedef struct _rbmq { RBMQ_MsgRing msg_ring; RBMQ_DataRing data_ring; } RBMQ; static inline uint32_t IncrementMessageIndex(RBMQ *mq, uint32_t index) { return (++index == mq->msg_ring.entries) ? 0 : index; } static inline uint32_t DecrementMessageIndex(RBMQ *mq, uint32_t index) { return (index == 0) ? (mq->msg_ring.entries - 1) : (index - 1); } /* Returns 0 if the message handle is within bounds for the control ring, non-zero otherwise. */ static inline int ValidateMsgHandle(RBMQ *mq, void *msg_handle) { return (msg_handle < (void *)(&mq->msg_ring.msgs[0]) || msg_handle > (void *)(&mq->msg_ring.msgs[mq->msg_ring.entries - 1])); } RBMQ *RBMQ_Alloc(uint32_t msg_ring_entries, uint16_t msg_ring_header_size, uint32_t data_ring_size) { RBMQ *mq; mq = SnortAlloc(sizeof(RBMQ)); memset(mq, 0, sizeof(RBMQ)); /* Initialize the control ring. */ mq->msg_ring.msgs = SnortAlloc(msg_ring_entries * sizeof(RBMQ_Msg)); mq->msg_ring.headers = SnortAlloc(msg_ring_entries * msg_ring_header_size); mq->msg_ring.entries = msg_ring_entries; mq->msg_ring.header_size = msg_ring_header_size; memset(mq->msg_ring.msgs, 0, mq->msg_ring.entries * sizeof(RBMQ_Msg)); mq->msg_ring.last_reserved = 0; mq->msg_ring.last_read = 0; mq->msg_ring.last_acked = 0; /* Initialize the data ring. */ mq->data_ring.data = SnortAlloc(data_ring_size); mq->data_ring.size = data_ring_size; memset(mq->data_ring.data, 0, mq->data_ring.size); return mq; } void RBMQ_Destroy(RBMQ *mq) { RBMQ_Msg *msg_info; uint32_t idx; /* Free the data for any unprocessed messages. */ idx = mq->msg_ring.last_acked; while (idx != mq->msg_ring.last_reserved) { idx++; if (idx == mq->msg_ring.entries) idx = 0; msg_info = &mq->msg_ring.msgs[idx]; if (msg_info->msgFreeFunc) msg_info->msgFreeFunc(msg_info->data); } /* Release all of our resources. */ free(mq->data_ring.data); free(mq->msg_ring.msgs); } int RBMQ_ReserveMsg(RBMQ *mq, uint32_t length, void **hdr_ptr, uint8_t **msg_ptr, void **msg_handle) { RBMQ_InternalDataHdr *idh; RBMQ_Msg *msg_info; uint32_t msg_index, msg_len, start_offset; /* Find the next entry in the message ring to reserve. */ msg_index = IncrementMessageIndex(mq, mq->msg_ring.last_reserved); msg_info = &mq->msg_ring.msgs[msg_index]; /* Bail if the entry is in use. */ if (msg_info->state != RBMQ_MSG_STATE_UNUSED) return -ENOMEM; /* Make sure that we can reserve the requested space in the data ring. */ msg_len = length + sizeof(RBMQ_InternalDataHdr); if (mq->data_ring.write_offset < mq->data_ring.read_offset) { if ((mq->data_ring.read_offset - mq->data_ring.write_offset) < msg_len) return -ENOMEM; start_offset = mq->data_ring.write_offset; } else if ((mq->data_ring.size - mq->data_ring.write_offset) < msg_len) { if (mq->data_ring.read_offset < msg_len) return -ENOMEM; start_offset = 0; } else start_offset = mq->data_ring.write_offset; idh = (RBMQ_InternalDataHdr *) (mq->data_ring.data + start_offset); idh->msg_index = msg_index; idh->prev_offset = mq->data_ring.write_offset; /* Update the write offset in the data ring, wrapping as necessary. */ mq->data_ring.write_offset = start_offset + msg_len; if (mq->data_ring.write_offset == mq->data_ring.size) mq->data_ring.write_offset = 0; msg_info->length = length; /* Type is filled in during the commit. */ msg_info->flags = 0; msg_info->state = RBMQ_MSG_STATE_RESERVED; msg_info->data = (uint8_t *) idh + sizeof(RBMQ_InternalDataHdr); msg_info->msgFreeFunc = NULL; /* Update the last reservation index in the control ring. */ mq->msg_ring.last_reserved = msg_index; if (mq->msg_ring.header_size) *hdr_ptr = mq->msg_ring.headers + (msg_index * mq->msg_ring.header_size); else *hdr_ptr = NULL; *msg_ptr = msg_info->data; *msg_handle = (void *) msg_info; return 0; } int RBMQ_CommitReservedMsg(RBMQ *mq, void *msg_handle, uint32_t length, SCMQMsgFreeFunc msgFreeFunc) { RBMQ_Msg *msg_info; if (ValidateMsgHandle(mq, msg_handle)) return -EINVAL; msg_info = (RBMQ_Msg *) msg_handle; /* Sanity checks... */ if (msg_info->state != RBMQ_MSG_STATE_RESERVED) { ErrorMessage("%s: Attempted to commit an unreserved message! (State: %hhu)\n", __FUNCTION__, msg_info->state); return -EINVAL; } if (length > msg_info->length) { ErrorMessage("%s: Attempted to commit illegally enlarged message! (%u vs %u)\n", __FUNCTION__, length, msg_info->length); return -EINVAL; } /* If the committed length is less than the reserved length and it was the last message reserved, truncate the internal data ring usage. */ if (length < msg_info->length && msg_info == &mq->msg_ring.msgs[mq->msg_ring.last_reserved]) { if (mq->data_ring.write_offset != 0) mq->data_ring.write_offset -= (msg_info->length - length); else mq->data_ring.write_offset = mq->data_ring.size - (msg_info->length - length); msg_info->length = length; } msg_info->state = RBMQ_MSG_STATE_COMMITTED; msg_info->msgFreeFunc = msgFreeFunc; return 0; } int RBMQ_DiscardReservedMsg(RBMQ *mq, void *msg_handle) { RBMQ_InternalDataHdr *idh; RBMQ_Msg *msg_info; uint32_t idx; if (ValidateMsgHandle(mq, msg_handle)) return -EINVAL; msg_info = (RBMQ_Msg *) msg_handle; /* Sanity checks... */ if (msg_info->state != RBMQ_MSG_STATE_RESERVED) { ErrorMessage("%s: Attempted to discard an unreserved message! (State: %hhu)\n", __FUNCTION__, msg_info->state); return -EINVAL; } msg_info->state = RBMQ_MSG_STATE_DISCARDED; /* Working backward from the last entry reserved (in order), release discarded messages as allowed. Any discarded messages that we can't release here will have to wait until something gets ACK'd. */ idx = mq->msg_ring.last_reserved; msg_info = &mq->msg_ring.msgs[idx]; while (msg_info->state == RBMQ_MSG_STATE_DISCARDED) { /* Clean up the data ring state if this was internally allocated. Only internally allocated messages can be discarded, so this should be safe. */ idh = (RBMQ_InternalDataHdr *) (msg_info->data - sizeof(RBMQ_InternalDataHdr)); mq->data_ring.write_offset = idh->prev_offset; /* Reset the state to unused so that it can be reserved again. */ msg_info->state = RBMQ_MSG_STATE_UNUSED; /* Finally, update the last reserved index. */ idx = DecrementMessageIndex(mq, idx); mq->msg_ring.last_reserved = idx; msg_info = &mq->msg_ring.msgs[idx]; } return 0; } int RBMQ_CommitExternalMsg(RBMQ *mq, const void *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc) { RBMQ_Msg *msg_info; uint32_t idx; /* V Reserve and commit the message all in one step. V */ /* Find the next entry in the message ring to reserve. */ idx = IncrementMessageIndex(mq, mq->msg_ring.last_reserved); msg_info = &mq->msg_ring.msgs[idx]; /* Bail if the entry is in use. */ if (msg_info->state != RBMQ_MSG_STATE_UNUSED) return -ENOMEM; /* Require a header if there is a header size specified for the control ring and copy it over. */ if (mq->msg_ring.header_size) { if (!hdr) return -EINVAL; memcpy(mq->msg_ring.headers + (idx * mq->msg_ring.header_size), hdr, mq->msg_ring.header_size); } msg_info->length = length; msg_info->flags = RBMQ_MSG_FLAG_EXTERNAL; msg_info->state = RBMQ_MSG_STATE_COMMITTED; msg_info->data = msg; msg_info->msgFreeFunc = msgFreeFunc; /* Update the last reservation index in the control ring. */ mq->msg_ring.last_reserved = idx; return 0; } int RBMQ_ReadMsg(RBMQ *mq, const void **hdr_ptr, const uint8_t **msg_ptr, uint32_t *length, void **msg_handle) { RBMQ_Msg *msg_info; uint32_t idx; /* Find the next entry in the message ring to read. */ idx = IncrementMessageIndex(mq, mq->msg_ring.last_read); msg_info = &mq->msg_ring.msgs[idx]; /* Skip over discarded messages -- the next ACK should clear them out. */ while (msg_info->state == RBMQ_MSG_STATE_DISCARDED) { mq->msg_ring.last_read = idx; idx = IncrementMessageIndex(mq, idx); msg_info = &mq->msg_ring.msgs[idx]; } /* Return an error if there is not a committed entry ready to be read. */ if (msg_info->state != RBMQ_MSG_STATE_COMMITTED) return -ENOENT; if (mq->msg_ring.header_size) *hdr_ptr = mq->msg_ring.headers + (idx * mq->msg_ring.header_size); else *hdr_ptr = NULL; *msg_ptr = msg_info->data; *length = msg_info->length; *msg_handle = msg_info; msg_info->state = RBMQ_MSG_STATE_READ; mq->msg_ring.last_read = idx; return 0; } int RBMQ_AckMsg(RBMQ *mq, void *msg_handle) { RBMQ_Msg *msg_info; uint32_t idx; /* Sanity checking... */ if (ValidateMsgHandle(mq, msg_handle)) return -EINVAL; msg_info = (RBMQ_Msg *) msg_handle; if (msg_info->state != RBMQ_MSG_STATE_READ) { ErrorMessage("%s: Attempted to ACK an unread message! (State: %hhu)\n", __FUNCTION__, msg_info->state); return -EINVAL; } /* Call the user defined free function to release the message data if it exists. */ if (msg_info->data && msg_info->msgFreeFunc) msg_info->msgFreeFunc(msg_info->data); msg_info->state = RBMQ_MSG_STATE_ACKED; /* Working forward from the last entry ACK'd (in order), release ACK'd and discarded messages as allowed. */ do { idx = IncrementMessageIndex(mq, mq->msg_ring.last_acked); msg_info = &mq->msg_ring.msgs[idx]; if (msg_info->state != RBMQ_MSG_STATE_ACKED && msg_info->state != RBMQ_MSG_STATE_DISCARDED) break; /* Clean up the data ring state if this was internally allocated. We are guaranteed that internal allocations will be sequential in relation to sequential control entries.*/ if (!(msg_info->flags & RBMQ_MSG_FLAG_EXTERNAL)) mq->data_ring.read_offset = msg_info->data + msg_info->length - mq->data_ring.data; /* Reset the state to unused so it can be reserved again. */ msg_info->state = RBMQ_MSG_STATE_UNUSED; /* Finally, update the last ACK'd index to accurately represent how far processing has gotten. */ mq->msg_ring.last_acked = idx; } while (mq->msg_ring.last_acked != mq->msg_ring.last_read); return 0; } int RBMQ_IsEmpty(RBMQ *mq) { RBMQ_Msg *msg_info; uint32_t idx; /* Find the next entry in the message ring to read and return true if it's not committed. */ idx = IncrementMessageIndex(mq, mq->msg_ring.last_read); msg_info = &mq->msg_ring.msgs[idx]; return (msg_info->state != RBMQ_MSG_STATE_COMMITTED); } void RBMQ_Stats(RBMQ_Ptr mq, const char *indent) { } #endif /* !SC_USE_DMQ */ #endif /* SIDE_CHANNEL */ snort-2.9.6.0/src/side-channel/dmq.h0000644000000000000000000000350312260565733014007 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifndef _DMQ_H_ #define _DMQ_H_ #include #include "sidechannel_define.h" #ifdef SC_USE_DMQ typedef struct _dmq *DMQ_Ptr; DMQ_Ptr DMQ_Alloc(uint32_t msg_ring_entries, uint16_t msg_ring_header_size, uint32_t data_ring_size); int DMQ_ReserveMsg(DMQ_Ptr mq, uint32_t length, void **hdr_ptr, uint8_t **msg_ptr, void **msg_handle); int DMQ_CommitReservedMsg(DMQ_Ptr mq, void *msg_handle, uint32_t length, SCMQMsgFreeFunc msgFreeFunc); int DMQ_DiscardReservedMsg(DMQ_Ptr mq, void *msg_handle); int DMQ_CommitExternalMsg(DMQ_Ptr mq, const void *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc); int DMQ_ReadMsg(DMQ_Ptr mq, const void **hdr_ptr, const uint8_t **msg_ptr, uint32_t *length, void **msg_handle); int DMQ_AckMsg(DMQ_Ptr mq, void *msg_handle); int DMQ_IsEmpty(DMQ_Ptr mq); void DMQ_Stats(DMQ_Ptr mq, const char *indent); #endif /* SC_USE_DMQ */ #endif /* _DMQ_H_ */ snort-2.9.6.0/src/side-channel/dmq.c0000644000000000000000000001454312260565733014010 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * Author: Michael Altizer * */ #ifdef SIDE_CHANNEL #include #include "dmq.h" #include "util.h" #ifdef SC_USE_DMQ #define DMQ_NODE_FLAG_EXTERNAL 0x01 typedef struct _dmq_node { struct _dmq_node *next; uint32_t length; uint32_t allocated; uint8_t flags; uint8_t *data; SCMQMsgFreeFunc msgFreeFunc; } DMQ_Node; typedef struct _dmq { DMQ_Node *head; DMQ_Node *tail; DMQ_Node *free_list; uint16_t user_header_size; uint32_t length; uint32_t internal_size; uint32_t external_size; uint32_t overhead_size; uint32_t length_limit; uint32_t internal_size_limit; uint32_t max_length; uint32_t max_internal_size; } DMQ; DMQ *DMQ_Alloc(uint32_t msg_ring_entries, uint16_t msg_ring_header_size, uint32_t data_ring_size) { DMQ_Node *node; DMQ *mq; uint32_t i; mq = SnortAlloc(sizeof(DMQ)); mq->head = mq->tail = mq->free_list = NULL; mq->user_header_size = msg_ring_header_size; mq->length = 0; mq->internal_size = 0; mq->external_size = 0; mq->overhead_size = 0; mq->length_limit = msg_ring_entries; mq->internal_size_limit = data_ring_size; /* Preallocate the Queue nodes. */ for (i = 0; i < mq->length_limit; i++) { node = SnortAlloc(sizeof(DMQ_Node) + mq->user_header_size); node->next = mq->free_list; mq->free_list = node; mq->overhead_size += sizeof(DMQ_Node) + mq->user_header_size; } LogMessage("%s: Preallocated %u bytes for queue node structures.\n", __FUNCTION__, mq->overhead_size); return mq; } int DMQ_ReserveMsg(DMQ *mq, uint32_t length, void **hdr_ptr, uint8_t **msg_ptr, void **msg_handle) { DMQ_Node *node; if (!mq->free_list) return -ENOSPC; if (length > (mq->internal_size_limit - mq->internal_size)) return -ENOMEM; node = mq->free_list; mq->free_list = node->next; node->next = NULL; node->length = length; node->allocated = length; node->flags = 0; node->data = SnortAlloc(length); node->msgFreeFunc = NULL; *hdr_ptr = (uint8_t *) node + sizeof(DMQ_Node); *msg_ptr = node->data; *msg_handle = (void *) node; mq->internal_size += length; if (mq->internal_size > mq->max_internal_size) mq->max_internal_size = mq->internal_size; return 0; } int DMQ_CommitReservedMsg(DMQ *mq, void *msg_handle, uint32_t length, SCMQMsgFreeFunc msgFreeFunc) { DMQ_Node *node = (DMQ_Node *) msg_handle; if (!node) return -EINVAL; if (length > node->length) { ErrorMessage("%s: Attempted to commit illegally enlarged message! (%u vs %u)\n", __FUNCTION__, length, node->length); return -EINVAL; } node->length = length; if (mq->head) { mq->tail->next = node; mq->tail = node; } else mq->head = mq->tail = node; mq->length++; if (mq->length > mq->max_length) mq->max_length = mq->length; return 0; } static void DMQ_DestroyNode(DMQ *mq, DMQ_Node *node) { if (node->msgFreeFunc) node->msgFreeFunc(node->data); if (!(node->flags & DMQ_NODE_FLAG_EXTERNAL)) { mq->internal_size -= node->allocated; free(node->data); } else mq->external_size -= node->length; node->next = mq->free_list; mq->free_list = node; } int DMQ_DiscardReservedMsg(DMQ *mq, void *msg_handle) { DMQ_Node *node = (DMQ_Node *) msg_handle; if (!node) return -EINVAL; DMQ_DestroyNode(mq, node); return 0; } int DMQ_CommitExternalMsg(DMQ *mq, const void *hdr, uint8_t *msg, uint32_t length, SCMQMsgFreeFunc msgFreeFunc) { DMQ_Node *node; if (!mq->free_list) return -ENOMEM; node = mq->free_list; mq->free_list = node->next; if (mq->user_header_size) { if (!hdr) return -EINVAL; memcpy((uint8_t *) node + sizeof(DMQ_Node), hdr, mq->user_header_size); } node->next = NULL; node->length = length; node->allocated = 0; node->flags = DMQ_NODE_FLAG_EXTERNAL; node->data = msg; node->msgFreeFunc = msgFreeFunc; if (mq->head) { mq->tail->next = node; mq->tail = node; } else mq->head = mq->tail = node; mq->length++; if (mq->length > mq->max_length) mq->max_length = mq->length; mq->external_size += length; return 0; } int DMQ_ReadMsg(DMQ *mq, const void **hdr_ptr, const uint8_t **msg_ptr, uint32_t *length, void **msg_handle) { DMQ_Node *node; if (!mq->head) return -ENOENT; node = mq->head; mq->head = node->next; if (!mq->head) mq->tail = NULL; node->next = NULL; if (mq->user_header_size) *hdr_ptr = (uint8_t *) node + sizeof(DMQ_Node); else *hdr_ptr = NULL; *msg_ptr = node->data; *length = node->length; *msg_handle = (void *) node; mq->length--; return 0; } int DMQ_AckMsg(DMQ *mq, void *msg_handle) { DMQ_Node *node = (DMQ_Node *) msg_handle; if (!node) return -EINVAL; DMQ_DestroyNode(mq, node); return 0; } int DMQ_IsEmpty(DMQ *mq) { return (mq->head == NULL); } void DMQ_Stats(DMQ_Ptr mq, const char *indent) { LogMessage("%s Length: %u (%u max)\n", indent, mq->length, mq->max_length); LogMessage("%s Size: %u internal (%u max), %u external, %u overhead\n", indent, mq->internal_size, mq->max_internal_size, mq->external_size, mq->overhead_size); } #endif /* SC_USE_DMQ */ #endif /* SIDE_CHANNEL */ snort-2.9.6.0/src/side-channel/Makefile.am0000644000000000000000000000036012153454771015107 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libsidechannel.a SUBDIRS = dynamic-plugins plugins libsidechannel_a_SOURCES = dmq.c dmq.h rbmq.c rbmq.h sidechannel.c sidechannel.h sidechannel_define.h INCLUDES = @INCLUDES@ snort-2.9.6.0/src/side-channel/Makefile.in0000644000000000000000000005061412260606525015122 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/side-channel DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libsidechannel_a_AR = $(AR) $(ARFLAGS) libsidechannel_a_LIBADD = am_libsidechannel_a_OBJECTS = dmq.$(OBJEXT) rbmq.$(OBJEXT) \ sidechannel.$(OBJEXT) libsidechannel_a_OBJECTS = $(am_libsidechannel_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsidechannel_a_SOURCES) DIST_SOURCES = $(libsidechannel_a_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libsidechannel.a SUBDIRS = dynamic-plugins plugins libsidechannel_a_SOURCES = dmq.c dmq.h rbmq.c rbmq.h sidechannel.c sidechannel.h sidechannel_define.h all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/side-channel/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/side-channel/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libsidechannel.a: $(libsidechannel_a_OBJECTS) $(libsidechannel_a_DEPENDENCIES) $(EXTRA_libsidechannel_a_DEPENDENCIES) $(AM_V_at)-rm -f libsidechannel.a $(AM_V_AR)$(libsidechannel_a_AR) libsidechannel.a $(libsidechannel_a_OBJECTS) $(libsidechannel_a_LIBADD) $(AM_V_at)$(RANLIB) libsidechannel.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LIBRARIES) installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool \ clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-examples/0000755000000000000000000000000012260606567014043 500000000000000snort-2.9.6.0/src/dynamic-examples/dynamic-rule/0000755000000000000000000000000012260606567016434 500000000000000snort-2.9.6.0/src/dynamic-examples/dynamic-rule/detection_lib_meta.h0000644000000000000000000000300712260565732022335 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /* * detection_lib_meta.h * * Author: * * Steven A. Sturges * * Description: * * This file is part of an example of a dynamically loadable preprocessor. * * NOTES: * */ #ifndef _DETECTION_LIB_META_H_ #define _DETECTION_LIB_META_H_ /* Version for this rule library */ #define DETECTION_LIB_MAJOR 2 #define DETECTION_LIB_MINOR 0 #define DETECTION_LIB_BUILD 1 #define DETECTION_LIB_NAME "Snort_Dynamic_Rule_Example" #endif /* _DETECTION_LIB_META_H_ */ snort-2.9.6.0/src/dynamic-examples/dynamic-rule/sid637.c0000644000000000000000000000746412260565732017550 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_snort_plugin_api.h" #include "sf_snort_packet.h" #include "detection_lib_meta.h" /* * C-language example for SID 637 * * alert udp $EXTERNAL_NET any -> $HOME_NET any \ * (msg:"SCAN Webtrends Scanner UDP Probe"; \ * content:"|0A|help|0A|quite|0A|"; \ * reference:arachnids,308; classtype:attempted-recon; \ * sid:637; rev:3;) * */ /* content:"|0A|help|0A|quite|0A|"; */ static ContentInfo sid637content = { (u_int8_t *)"|0A|help|0A|quite|0A|",/* pattern to search for */ 0, /* depth */ 0, /* offset */ CONTENT_BUF_NORMALIZED, /* flags */ NULL, /* holder for boyer/moore info */ NULL, /* holder for byte representation of "\nhelp\nquite\n" */ 0, /* holder for length of byte representation */ 0, /* holder of increment length */ 0, /* holder for fp offset */ 0, /* holder for fp length */ 0, /* holder for fp only */ NULL, // offset_refId NULL, // depth_refId NULL, // offset_location NULL // depth_location }; static RuleOption sid637option1 = { OPTION_TYPE_CONTENT, { &sid637content } }; /* references for sid 637 */ static RuleReference sid637ref_arachnids = { "arachnids", /* Type */ "308" /* value */ }; static RuleReference *sid637refs[] = { &sid637ref_arachnids, NULL }; RuleOption *sid637options[] = { &sid637option1, NULL }; Rule sid637 = { /* protocol header, akin to => tcp any any -> any any */ { IPPROTO_UDP, /* proto */ EXTERNAL_NET, /* source IP */ ANY_PORT, /* source port(s) */ 1, /* direction, bi-directional */ HOME_NET, /* destination IP */ ANY_PORT /* destination port(s) */ }, /* metadata */ { 3, /* genid -- use 3 to distinguish a C rule */ 637, /* sigid */ 3, /* revision */ "attempted-recon", /* classification */ 0, /* priority */ "SCAN Webtrends Scanner UDP Probe", /* message */ sid637refs, /* ptr to references */ NULL /* Meta data */ }, sid637options, /* ptr to rule options */ NULL, /* Use internal eval func */ 0, /* Holder, not yet initialized, used internally */ 0, /* Holder, option count, used internally */ 0, /* Holder, no alert used internally for flowbits */ NULL /* Holder, rule data, used internally */ }; snort-2.9.6.0/src/dynamic-examples/dynamic-rule/sid109.c0000644000000000000000000000777512260565732017547 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_snort_plugin_api.h" #include "sf_snort_packet.h" #include "detection_lib_meta.h" /* * C-language example for SID 109 * * alert tcp $HOME_NET 12345:12346 -> $EXTERNAL_NET any \ * (msg:"BACKDOOR netbus active"; flow:from_server,established; \ * content:"NetBus"; reference:arachnids,401; classtype:misc-activity; \ * sid:109; rev:5;) * */ /* flow:established, from_server; */ static FlowFlags sid109flow = { FLOW_ESTABLISHED|FLOW_TO_CLIENT }; static RuleOption sid109option1 = { OPTION_TYPE_FLOWFLAGS, { &sid109flow } }; /* content:"NetBus"; */ static ContentInfo sid109content = { (u_int8_t *)"NetBus", /* pattern to search for */ 0, /* depth */ 0, /* offset */ CONTENT_BUF_NORMALIZED, /* flags */ NULL, /* holder for boyer/moore info */ NULL, /* holder for byte representation of "NetBus" */ 0, /* holder for length of byte representation */ 0, /* holder of increment length */ 0, /* holder for fp offset */ 0, /* holder for fp length */ 0, /* holder for fp only */ NULL, // offset_refId NULL, // depth_refId NULL, // offset_location NULL // depth_location }; static RuleOption sid109option2 = { OPTION_TYPE_CONTENT, { &sid109content } }; /* references for sid 109 */ static RuleReference sid109ref_arachnids = { "arachnids", /* Type */ "401" /* value */ }; static RuleReference *sid109refs[] = { &sid109ref_arachnids, NULL }; RuleOption *sid109options[] = { &sid109option1, &sid109option2, NULL }; Rule sid109 = { /* protocol header, akin to => tcp any any -> any any */ { IPPROTO_TCP, /* proto */ HOME_NET, /* source IP */ "12345:12346", /* source port(s) */ 0, /* direction, uni-directional */ EXTERNAL_NET, /* destination IP */ ANY_PORT /* destination port(s) */ }, /* metadata */ { 3, /* genid -- use 3 to distinguish a C rule */ 109, /* sigid */ 5, /* revision */ "misc-activity", /* classification */ 0, /* priority */ "BACKDOOR netbus active", /* message */ sid109refs, /* ptr to references */ NULL /* Meta data */ }, sid109options, /* ptr to rule options */ NULL, /* Use internal eval func */ 0, /* Holder, not yet initialized, used internally */ 0, /* Holder, option count, used internally */ 0, /* Holder, no alert used internally for flowbits */ NULL /* Holder, rule data, used internally */ }; snort-2.9.6.0/src/dynamic-examples/dynamic-rule/rules.c0000644000000000000000000000262512260565732017655 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /* * rules.c * * Author: * * Steven A. Sturges * * Description: * * This file is part of an example of a dynamically loadable rules library. * * NOTES: * */ #ifdef HAVE_CONFIG_H #include #endif #include "sf_snort_plugin_api.h" extern Rule sid109; extern Rule sid637; Rule *rules[] = { &sid109, &sid637, NULL }; snort-2.9.6.0/src/dynamic-examples/dynamic-rule/Makefile.am0000644000000000000000000000142611573541506020410 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include noinst_libdir = ${exec_prefix}/lib/snort_dynamicrules noinst_lib_LTLIBRARIES = lib_sfdynamic_example_rule.la lib_sfdynamic_example_rule_la_LDFLAGS = -export-dynamic @XCCFLAGS@ BUILT_SOURCES = \ sfsnort_dynamic_detection_lib.c \ sfsnort_dynamic_detection_lib.h nodist_lib_sfdynamic_example_rule_la_SOURCES = \ sfsnort_dynamic_detection_lib.c \ sfsnort_dynamic_detection_lib.h \ rules.c \ sid109.c \ sid637.c \ detection_lib_meta.h EXTRA_DIST = \ rules.c \ sid109.c \ sid637.c \ detection_lib_meta.h sfsnort_dynamic_detection_lib.c: ../include/sfsnort_dynamic_detection_lib.c cp $? $@ sfsnort_dynamic_detection_lib.h: ../include/sfsnort_dynamic_detection_lib.h cp $? $@ clean-local: rm -f $(BUILT_SOURCES) snort-2.9.6.0/src/dynamic-examples/dynamic-rule/Makefile.in0000644000000000000000000004760212260606520020417 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-examples/dynamic-rule DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(noinst_libdir)" LTLIBRARIES = $(noinst_lib_LTLIBRARIES) lib_sfdynamic_example_rule_la_LIBADD = nodist_lib_sfdynamic_example_rule_la_OBJECTS = \ sfsnort_dynamic_detection_lib.lo rules.lo sid109.lo sid637.lo lib_sfdynamic_example_rule_la_OBJECTS = \ $(nodist_lib_sfdynamic_example_rule_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = lib_sfdynamic_example_rule_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) \ $(lib_sfdynamic_example_rule_la_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(nodist_lib_sfdynamic_example_rule_la_SOURCES) DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_libdir = ${exec_prefix}/lib/snort_dynamicrules noinst_lib_LTLIBRARIES = lib_sfdynamic_example_rule.la lib_sfdynamic_example_rule_la_LDFLAGS = -export-dynamic @XCCFLAGS@ BUILT_SOURCES = \ sfsnort_dynamic_detection_lib.c \ sfsnort_dynamic_detection_lib.h nodist_lib_sfdynamic_example_rule_la_SOURCES = \ sfsnort_dynamic_detection_lib.c \ sfsnort_dynamic_detection_lib.h \ rules.c \ sid109.c \ sid637.c \ detection_lib_meta.h EXTRA_DIST = \ rules.c \ sid109.c \ sid637.c \ detection_lib_meta.h all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-examples/dynamic-rule/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-examples/dynamic-rule/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-noinst_libLTLIBRARIES: $(noinst_lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(noinst_lib_LTLIBRARIES)'; test -n "$(noinst_libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(noinst_libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(noinst_libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(noinst_libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(noinst_libdir)"; \ } uninstall-noinst_libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(noinst_lib_LTLIBRARIES)'; test -n "$(noinst_libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(noinst_libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(noinst_libdir)/$$f"; \ done clean-noinst_libLTLIBRARIES: -test -z "$(noinst_lib_LTLIBRARIES)" || rm -f $(noinst_lib_LTLIBRARIES) @list='$(noinst_lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } lib_sfdynamic_example_rule.la: $(lib_sfdynamic_example_rule_la_OBJECTS) $(lib_sfdynamic_example_rule_la_DEPENDENCIES) $(EXTRA_lib_sfdynamic_example_rule_la_DEPENDENCIES) $(AM_V_CCLD)$(lib_sfdynamic_example_rule_la_LINK) -rpath $(noinst_libdir) $(lib_sfdynamic_example_rule_la_OBJECTS) $(lib_sfdynamic_example_rule_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(noinst_libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool clean-local \ clean-noinst_libLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-noinst_libLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-noinst_libLTLIBRARIES .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-local clean-noinst_libLTLIBRARIES \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man \ install-noinst_libLTLIBRARIES install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-noinst_libLTLIBRARIES sfsnort_dynamic_detection_lib.c: ../include/sfsnort_dynamic_detection_lib.c cp $? $@ sfsnort_dynamic_detection_lib.h: ../include/sfsnort_dynamic_detection_lib.h cp $? $@ clean-local: rm -f $(BUILT_SOURCES) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-examples/dynamic-preprocessor/0000755000000000000000000000000012260606567020213 500000000000000snort-2.9.6.0/src/dynamic-examples/dynamic-preprocessor/sf_preproc_info.h0000644000000000000000000000302512260565732023457 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /* * sf_preproc_info.h * * Author: * * Steven A. Sturges * * Description: * * This file is part of an example of a dynamically loadable preprocessor. * * NOTES: * */ #ifndef SF_PREPROC_INFO_H_ #define SF_PREPROC_INFO_H_ #define MAJOR_VERSION 2 #define MINOR_VERSION 0 #define BUILD_VERSION 1 #define PREPROC_NAME "SF_Dynamic_Example_Preprocessor" #define DYNAMIC_PREPROC_SETUP ExampleSetup extern void ExampleSetup(); #endif /* SF_PREPROC_INFO_H_ */ snort-2.9.6.0/src/dynamic-examples/dynamic-preprocessor/spp_example.c0000644000000000000000000001723012260565732022615 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /* * spp_example.c * * Author: * * Steven A. Sturges * * Description: * * This file is part of an example of a dynamically loadable preprocessor. * * NOTES: * */ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "preprocids.h" #include "sf_snort_packet.h" #include "sf_dynamic_preproc_lib.h" #include "sf_dynamic_preprocessor.h" #include "snort_debug.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "profiler.h" #ifdef PERF_PROFILING PreprocStats examplePerfStats; #endif #define GENERATOR_EXAMPLE 256 #define SRC_PORT_MATCH 1 #define SRC_PORT_MATCH_STR "example_preprocessor: src port match" #define DST_PORT_MATCH 2 #define DST_PORT_MATCH_STR "example_preprocessor: dest port match" typedef struct _ExampleConfig { u_int16_t portToCheck; } ExampleConfig; tSfPolicyUserContextId ex_config = NULL; ExampleConfig *ex_eval_config = NULL; static void ExampleInit(struct _SnortConfig *, char *); static void ExampleProcess(void *, void *); static ExampleConfig * ExampleParse(char *); #ifdef SNORT_RELOAD static void ExampleReload(struct _SnortConfig *, char *, void **); static int ExampleReloadVerify(struct _SnortConfig *, void *); static int ExampleReloadSwapPolicyFree(tSfPolicyUserContextId, tSfPolicyId, void *); static void * ExampleReloadSwap(struct _SnortConfig *, void *); static void ExampleReloadSwapFree(void *); #endif void ExampleSetup(void) { #ifndef SNORT_RELOAD _dpd.registerPreproc("dynamic_example", ExampleInit); #else _dpd.registerPreproc("dynamic_example", ExampleInit, ExampleReload, ExampleReloadVerify, ExampleReloadSwap, ExampleReloadSwapFree); #endif DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Preprocessor: Example is setup\n");); } static void ExampleInit(struct _SnortConfig *sc, char *args) { ExampleConfig *config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); _dpd.logMsg("Example dynamic preprocessor configuration\n"); if (ex_config == NULL) { ex_config = sfPolicyConfigCreate(); if (ex_config == NULL) _dpd.fatalMsg("Could not allocate configuration struct.\n"); } config = ExampleParse(args); sfPolicyUserPolicySet(ex_config, policy_id); sfPolicyUserDataSetCurrent(ex_config, config); /* Register the preprocessor function, Transport layer, ID 10000 */ _dpd.addPreproc(sc, ExampleProcess, PRIORITY_TRANSPORT, 10000, PROTO_BIT__TCP | PROTO_BIT__UDP); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("example", (void *)&examplePerfStats, 0, _dpd.totalPerfStats); #endif DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Preprocessor: Example is initialized\n");); } static ExampleConfig * ExampleParse(char *args) { char *arg; char *argEnd; long port; ExampleConfig *config = (ExampleConfig *)calloc(1, sizeof(ExampleConfig)); if (config == NULL) _dpd.fatalMsg("Could not allocate configuration struct.\n"); arg = strtok(args, " \t\n\r"); if(arg && !strcasecmp("port", arg)) { arg = strtok(NULL, "\t\n\r"); if (!arg) { _dpd.fatalMsg("ExamplePreproc: Missing port\n"); } port = strtol(arg, &argEnd, 10); if (port < 0 || port > 65535) { _dpd.fatalMsg("ExamplePreproc: Invalid port %d\n", port); } config->portToCheck = (u_int16_t)port; _dpd.logMsg(" Port: %d\n", config->portToCheck); } else { _dpd.fatalMsg("ExamplePreproc: Invalid option %s\n", arg?arg:"(missing port)"); } return config; } void ExampleProcess(void *pkt, void *context) { SFSnortPacket *p = (SFSnortPacket *)pkt; ExampleConfig *config; PROFILE_VARS; sfPolicyUserPolicySet(ex_config, _dpd.getRuntimePolicy()); config = (ExampleConfig *)sfPolicyUserDataGetCurrent(ex_config); if (config == NULL) return; // preconditions - what we registered for assert(IsUDP(p) || IsTCP(p)); PREPROC_PROFILE_START(examplePerfStats); if (p->src_port == config->portToCheck) { /* Source port matched, log alert */ _dpd.alertAdd(GENERATOR_EXAMPLE, SRC_PORT_MATCH, 1, 0, 3, SRC_PORT_MATCH_STR, 0); PREPROC_PROFILE_END(examplePerfStats); return; } if (p->dst_port == config->portToCheck) { /* Destination port matched, log alert */ _dpd.alertAdd(GENERATOR_EXAMPLE, DST_PORT_MATCH, 1, 0, 3, DST_PORT_MATCH_STR, 0); PREPROC_PROFILE_END(examplePerfStats); return; } PREPROC_PROFILE_END(examplePerfStats); } #ifdef SNORT_RELOAD static void ExampleReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId ex_swap_config; ExampleConfig *config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); _dpd.logMsg("Example dynamic preprocessor configuration\n"); ex_swap_config = sfPolicyConfigCreate(); if (ex_swap_config == NULL) _dpd.fatalMsg("Could not allocate configuration struct.\n"); config = ExampleParse(args); sfPolicyUserPolicySet(ex_swap_config, policy_id); sfPolicyUserDataSetCurrent(ex_swap_config, config); /* Register the preprocessor function, Transport layer, ID 10000 */ _dpd.addPreproc(sc, ExampleProcess, PRIORITY_TRANSPORT, 10000, PROTO_BIT__TCP | PROTO_BIT__UDP); *new_config = (void *)ex_swap_config; DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Preprocessor: Example is initialized\n");); } static int ExampleReloadVerify(struct _SnortConfig *sc, void *swap_config) { if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("Streaming & reassembly must be enabled for example preprocessor\n"); return -1; } return 0; } static int ExampleReloadSwapPolicyFree(tSfPolicyUserContextId config, tSfPolicyId policyId, void *data) { ExampleConfig *policy_config = (ExampleConfig *)data; sfPolicyUserDataClear(config, policyId); free(policy_config); return 0; } static void * ExampleReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId ex_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = ex_config; if (ex_swap_config == NULL) return NULL; ex_config = ex_swap_config; return (void *)old_config; } static void ExampleReloadSwapFree(void *data) { tSfPolicyUserContextId config = (tSfPolicyUserContextId)data; if (data == NULL) return; sfPolicyUserDataFreeIterate(config, ExampleReloadSwapPolicyFree); sfPolicyConfigDelete(config); } #endif snort-2.9.6.0/src/dynamic-examples/dynamic-preprocessor/Makefile.am0000644000000000000000000000131711267157122022163 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include noinst_libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor noinst_lib_LTLIBRARIES = lib_sfdynamic_preprocessor_example.la lib_sfdynamic_preprocessor_example_la_LDFLAGS = -export-dynamic BUILT_SOURCES = \ sf_dynamic_preproc_lib.c \ sfPolicyUserData.c nodist_lib_sfdynamic_preprocessor_example_la_SOURCES = \ sf_dynamic_preproc_lib.c \ sfPolicyUserData.c \ spp_example.c \ sf_preproc_info.h EXTRA_DIST = \ spp_example.c \ sf_preproc_info.h sf_dynamic_preproc_lib.c: ../include/sf_dynamic_preproc_lib.c cp $? $@ sfPolicyUserData.c: ../include/sfPolicyUserData.c cp $? $@ clean-local: rm -f sf_dynamic_preproc_lib.c sfPolicyUserData.c snort-2.9.6.0/src/dynamic-examples/dynamic-preprocessor/Makefile.in0000644000000000000000000004770612260606520022203 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-examples/dynamic-preprocessor DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(noinst_libdir)" LTLIBRARIES = $(noinst_lib_LTLIBRARIES) lib_sfdynamic_preprocessor_example_la_LIBADD = nodist_lib_sfdynamic_preprocessor_example_la_OBJECTS = \ sf_dynamic_preproc_lib.lo sfPolicyUserData.lo spp_example.lo lib_sfdynamic_preprocessor_example_la_OBJECTS = \ $(nodist_lib_sfdynamic_preprocessor_example_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = lib_sfdynamic_preprocessor_example_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(lib_sfdynamic_preprocessor_example_la_LDFLAGS) $(LDFLAGS) -o \ $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(nodist_lib_sfdynamic_preprocessor_example_la_SOURCES) DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor noinst_lib_LTLIBRARIES = lib_sfdynamic_preprocessor_example.la lib_sfdynamic_preprocessor_example_la_LDFLAGS = -export-dynamic BUILT_SOURCES = \ sf_dynamic_preproc_lib.c \ sfPolicyUserData.c nodist_lib_sfdynamic_preprocessor_example_la_SOURCES = \ sf_dynamic_preproc_lib.c \ sfPolicyUserData.c \ spp_example.c \ sf_preproc_info.h EXTRA_DIST = \ spp_example.c \ sf_preproc_info.h all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-examples/dynamic-preprocessor/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-examples/dynamic-preprocessor/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-noinst_libLTLIBRARIES: $(noinst_lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(noinst_lib_LTLIBRARIES)'; test -n "$(noinst_libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(noinst_libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(noinst_libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(noinst_libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(noinst_libdir)"; \ } uninstall-noinst_libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(noinst_lib_LTLIBRARIES)'; test -n "$(noinst_libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(noinst_libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(noinst_libdir)/$$f"; \ done clean-noinst_libLTLIBRARIES: -test -z "$(noinst_lib_LTLIBRARIES)" || rm -f $(noinst_lib_LTLIBRARIES) @list='$(noinst_lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } lib_sfdynamic_preprocessor_example.la: $(lib_sfdynamic_preprocessor_example_la_OBJECTS) $(lib_sfdynamic_preprocessor_example_la_DEPENDENCIES) $(EXTRA_lib_sfdynamic_preprocessor_example_la_DEPENDENCIES) $(AM_V_CCLD)$(lib_sfdynamic_preprocessor_example_la_LINK) -rpath $(noinst_libdir) $(lib_sfdynamic_preprocessor_example_la_OBJECTS) $(lib_sfdynamic_preprocessor_example_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(noinst_libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool clean-local \ clean-noinst_libLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-noinst_libLTLIBRARIES install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-noinst_libLTLIBRARIES .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-local clean-noinst_libLTLIBRARIES \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man \ install-noinst_libLTLIBRARIES install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-noinst_libLTLIBRARIES sf_dynamic_preproc_lib.c: ../include/sf_dynamic_preproc_lib.c cp $? $@ sfPolicyUserData.c: ../include/sfPolicyUserData.c cp $? $@ clean-local: rm -f sf_dynamic_preproc_lib.c sfPolicyUserData.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-examples/Makefile.am0000644000000000000000000002407212232305217016007 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies BUILT_SOURCES = \ include/snort_bounds.h \ include/snort_debug.h \ include/preprocids.h \ include/profiler.h \ include/cpuclock.h \ include/sf_dynamic_common.h \ include/sf_dynamic_engine.h \ include/sf_dynamic_define.h \ include/sf_dynamic_meta.h \ include/sf_dynamic_preprocessor.h \ include/sf_dynamic_preproc_lib.c \ include/sf_dynamic_preproc_lib.h \ include/sfghash.h \ include/sfhashfcn.h \ include/bitop.h \ include/sf_ip.h \ include/sf_ip.c \ include/sf_ipvar.h \ include/sf_vartable.h \ include/ipv6_port.h \ include/sfsnort_dynamic_detection_lib.c \ include/sfsnort_dynamic_detection_lib.h \ include/sf_snort_packet.h \ include/sf_protocols.h \ include/sf_snort_plugin_api.h \ include/pcap_pkthdr32.h \ include/stream_api.h \ include/str_search.h \ include/sf_types.h \ include/sfrt.h \ include/sfrt.c \ include/sfrt_dir.h \ include/sfrt_dir.c \ include/sfrt_trie.h \ include/sfPolicyUserData.c \ include/sfPolicyUserData.h \ include/sfPolicy.h \ include/treenodes.h \ include/signature.h \ include/plugin_enum.h \ include/obfuscation.h \ include/rule_option_types.h \ include/event.h \ include/sfcontrol.h \ include/idle_processing.h \ include/file_api.h sed_ipv6_headers = \ sed -e "s/->iph->ip_src/->ip4_header->source/" \ -e "s/->iph->ip_dst/->ip4_header->destination/" \ -e "s/->iph->/->ip4_header->/" \ -e "s/->iph$$/->ip4_header/" \ -e "s/orig_iph/orig_ipv4h/" \ -e "s/ip_verhl/version_headerlength/" \ -e "s/ip_tos/type_service/" \ -e "s/ip_len/data_length/" \ -e "s/ip_id/identifier/" \ -e "s/ip_off/offset/" \ -e "s/ip_ttl/time_to_live/" \ -e "s/ip_proto/proto/" \ -e "s/ip_csum/checksum/" \ $$dst_header.new > $$dst_header massage_ipv6_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_ipv6_headers); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_ipv6_headers); \ fi sed_headers = \ sed -e "s/Packet /SFSnortPacket /" \ -e "s/decode\.h/sf_snort_packet.h/" \ -e "/sfportobject\.h/d" \ -e "s/PortObject \*/void */g" \ $$dst_header.new > $$dst_header massage_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_headers); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_headers); \ fi sed_debug_header = \ sed -e "s/DebugMessageFile = /*_dpd.debugMsgFile = /" \ -e "s/DebugMessageLine = /*_dpd.debugMsgLine = /" \ -e "s/; DebugMessageFunc$$/; _dpd.debugMsg/" \ -e "s/; DebugWideMessageFunc$$/; _dpd.debugWideMsg/" \ $$dst_header.new > $$dst_header copy_debug_header = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_debug_header); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_debug_header); \ fi replace_policy_globals = \ if test -f $$dst_header; then \ sed -e "/SharedObjectAddStarts/d" \ -e "/SharedObjectAddEnds/d" \ -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" \ -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" \ $$dst_header > $$dst_header.new; \ mv $$dst_header.new $$dst_header; \ fi copy_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi sed_treenode_header = \ sed -f $(srcdir)/../dynamic-preprocessors/treenodes.sed $$dst_header.new > $$dst_header copy_treenode_header = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_treenode_header); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_treenode_header); \ fi # From main src tree include/snort_debug.h: $(srcdir)/../snort_debug.h @src_header=$?; dst_header=$@; $(copy_debug_header) include/preprocids.h: $(srcdir)/../preprocids.h @src_header=$?; dst_header=$@; $(copy_headers) include/profiler.h: $(srcdir)/../profiler.h @src_header=$?; dst_header=$@; $(copy_headers) include/cpuclock.h: $(srcdir)/../cpuclock.h @src_header=$?; dst_header=$@; $(copy_headers) include/pcap_pkthdr32.h: $(srcdir)/../pcap_pkthdr32.h @src_header=$?; dst_header=$@; $(copy_headers) include/snort_bounds.h: $(srcdir)/../snort_bounds.h @src_header=$?; dst_header=$@; $(copy_headers) include/ipv6_port.h: $(srcdir)/../ipv6_port.h @src_header=$?; dst_header=$@; $(massage_ipv6_headers) include/sf_types.h: $(srcdir)/../sf_types.h @src_header=$?; dst_header=$@; $(copy_headers) include/obfuscation.h: $(srcdir)/../obfuscation.h @src_header=$?; dst_header=$@; $(massage_headers) include/rule_option_types.h: $(srcdir)/../rule_option_types.h @src_header=$?; dst_header=$@; $(copy_headers) include/event.h: $(srcdir)/../event.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfcontrol.h: $(srcdir)/../control/sfcontrol.h @src_header=$?; dst_header=$@; $(copy_headers) include/idle_processing.h: $(srcdir)/../idle_processing.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins include/sf_dynamic_common.h: $(srcdir)/../dynamic-plugins/sf_dynamic_common.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_engine.h: $(srcdir)/../dynamic-plugins/sf_dynamic_engine.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_define.h: $(srcdir)/../dynamic-plugins/sf_dynamic_define.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_meta.h: $(srcdir)/../dynamic-plugins/sf_dynamic_meta.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_preprocessor.h: $(srcdir)/../dynamic-plugins/sf_dynamic_preprocessor.h @src_header=$?; dst_header=$@; $(massage_headers) # From dynamic-plugins/sf_preproc_example include/sf_dynamic_preproc_lib.c: $(srcdir)/../dynamic-plugins/sf_preproc_example/sf_dynamic_preproc_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_preproc_lib.h: $(srcdir)/../dynamic-plugins/sf_preproc_example/sf_dynamic_preproc_lib.h @src_header=$?; dst_header=$@; $(copy_headers) # From Utils include/sfghash.h: $(srcdir)/../sfutil/sfghash.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfhashfcn.h: $(srcdir)/../sfutil/sfhashfcn.h @src_header=$?; dst_header=$@; $(copy_headers) include/bitop.h: $(srcdir)/../sfutil/bitop.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ip.h: $(srcdir)/../sfutil/sf_ip.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ip.c: $(srcdir)/../sfutil/sf_ip.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ipvar.h: $(srcdir)/../sfutil/sf_ipvar.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_vartable.h: $(srcdir)/../sfutil/sf_vartable.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt.h: $(srcdir)/../sfutil/sfrt.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt.c: $(srcdir)/../sfutil/sfrt.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_dir.h: $(srcdir)/../sfutil/sfrt_dir.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_dir.c: $(srcdir)/../sfutil/sfrt_dir.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_trie.h: $(srcdir)/../sfutil/sfrt_trie.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfPolicyUserData.c: $(srcdir)/../sfutil/sfPolicyUserData.c @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/sfPolicyUserData.h: $(srcdir)/../sfutil/sfPolicyUserData.h @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/sfPolicy.h: $(srcdir)/../sfutil/sfPolicy.h @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) # From dynamic-plugins/sf_engine/examples include/sfsnort_dynamic_detection_lib.c: $(srcdir)/../dynamic-plugins/sf_engine/examples/sfsnort_dynamic_detection_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfsnort_dynamic_detection_lib.h: $(srcdir)/../dynamic-plugins/sf_engine/examples/sfsnort_dynamic_detection_lib.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins/sf_engine include/sf_snort_packet.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_snort_packet.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_protocols.h: $(srcdir)/../sf_protocols.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_snort_plugin_api.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_snort_plugin_api.h @src_header=$?; dst_header=$@; $(copy_headers) # Stream API/String Searching, massage it to use SFSnortPacket include/stream_api.h: $(srcdir)/../preprocessors/stream_api.h @src_header=$?; dst_header=$@; $(massage_headers) include/str_search.h: $(srcdir)/../preprocessors/str_search.h @src_header=$?; dst_header=$@; $(massage_headers) include/treenodes.h: $(srcdir)/../treenodes.h @src_header=$?; dst_header=$@; $(copy_treenode_header) include/signature.h: $(srcdir)/../signature.h @src_header=$?; dst_header=$@; $(copy_treenode_header) include/plugin_enum.h: $(srcdir)/../plugin_enum.h @src_header=$?; dst_header=$@; $(copy_headers) include/file_api.h: $(top_srcdir)/src/file-process/file_api.h @src_header=$?; dst_header=$@; $(copy_headers) INCLUDES = @INCLUDES@ if BUILD_DYNAMIC_EXAMPLES SUBDIRS = dynamic-preprocessor dynamic-rule endif clean-local: rm -rf include build snort-2.9.6.0/src/dynamic-examples/Makefile.in0000644000000000000000000007067312260606517016040 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-examples DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = dynamic-preprocessor dynamic-rule DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies BUILT_SOURCES = \ include/snort_bounds.h \ include/snort_debug.h \ include/preprocids.h \ include/profiler.h \ include/cpuclock.h \ include/sf_dynamic_common.h \ include/sf_dynamic_engine.h \ include/sf_dynamic_define.h \ include/sf_dynamic_meta.h \ include/sf_dynamic_preprocessor.h \ include/sf_dynamic_preproc_lib.c \ include/sf_dynamic_preproc_lib.h \ include/sfghash.h \ include/sfhashfcn.h \ include/bitop.h \ include/sf_ip.h \ include/sf_ip.c \ include/sf_ipvar.h \ include/sf_vartable.h \ include/ipv6_port.h \ include/sfsnort_dynamic_detection_lib.c \ include/sfsnort_dynamic_detection_lib.h \ include/sf_snort_packet.h \ include/sf_protocols.h \ include/sf_snort_plugin_api.h \ include/pcap_pkthdr32.h \ include/stream_api.h \ include/str_search.h \ include/sf_types.h \ include/sfrt.h \ include/sfrt.c \ include/sfrt_dir.h \ include/sfrt_dir.c \ include/sfrt_trie.h \ include/sfPolicyUserData.c \ include/sfPolicyUserData.h \ include/sfPolicy.h \ include/treenodes.h \ include/signature.h \ include/plugin_enum.h \ include/obfuscation.h \ include/rule_option_types.h \ include/event.h \ include/sfcontrol.h \ include/idle_processing.h \ include/file_api.h sed_ipv6_headers = \ sed -e "s/->iph->ip_src/->ip4_header->source/" \ -e "s/->iph->ip_dst/->ip4_header->destination/" \ -e "s/->iph->/->ip4_header->/" \ -e "s/->iph$$/->ip4_header/" \ -e "s/orig_iph/orig_ipv4h/" \ -e "s/ip_verhl/version_headerlength/" \ -e "s/ip_tos/type_service/" \ -e "s/ip_len/data_length/" \ -e "s/ip_id/identifier/" \ -e "s/ip_off/offset/" \ -e "s/ip_ttl/time_to_live/" \ -e "s/ip_proto/proto/" \ -e "s/ip_csum/checksum/" \ $$dst_header.new > $$dst_header massage_ipv6_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_ipv6_headers); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_ipv6_headers); \ fi sed_headers = \ sed -e "s/Packet /SFSnortPacket /" \ -e "s/decode\.h/sf_snort_packet.h/" \ -e "/sfportobject\.h/d" \ -e "s/PortObject \*/void */g" \ $$dst_header.new > $$dst_header massage_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_headers); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_headers); \ fi sed_debug_header = \ sed -e "s/DebugMessageFile = /*_dpd.debugMsgFile = /" \ -e "s/DebugMessageLine = /*_dpd.debugMsgLine = /" \ -e "s/; DebugMessageFunc$$/; _dpd.debugMsg/" \ -e "s/; DebugWideMessageFunc$$/; _dpd.debugWideMsg/" \ $$dst_header.new > $$dst_header copy_debug_header = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_debug_header); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_debug_header); \ fi replace_policy_globals = \ if test -f $$dst_header; then \ sed -e "/SharedObjectAddStarts/d" \ -e "/SharedObjectAddEnds/d" \ -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" \ -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" \ $$dst_header > $$dst_header.new; \ mv $$dst_header.new $$dst_header; \ fi copy_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi sed_treenode_header = \ sed -f $(srcdir)/../dynamic-preprocessors/treenodes.sed $$dst_header.new > $$dst_header copy_treenode_header = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_treenode_header); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_treenode_header); \ fi @BUILD_DYNAMIC_EXAMPLES_TRUE@SUBDIRS = dynamic-preprocessor dynamic-rule all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-examples/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-examples/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all check install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool clean-local \ cscopelist-am ctags ctags-am distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am # From main src tree include/snort_debug.h: $(srcdir)/../snort_debug.h @src_header=$?; dst_header=$@; $(copy_debug_header) include/preprocids.h: $(srcdir)/../preprocids.h @src_header=$?; dst_header=$@; $(copy_headers) include/profiler.h: $(srcdir)/../profiler.h @src_header=$?; dst_header=$@; $(copy_headers) include/cpuclock.h: $(srcdir)/../cpuclock.h @src_header=$?; dst_header=$@; $(copy_headers) include/pcap_pkthdr32.h: $(srcdir)/../pcap_pkthdr32.h @src_header=$?; dst_header=$@; $(copy_headers) include/snort_bounds.h: $(srcdir)/../snort_bounds.h @src_header=$?; dst_header=$@; $(copy_headers) include/ipv6_port.h: $(srcdir)/../ipv6_port.h @src_header=$?; dst_header=$@; $(massage_ipv6_headers) include/sf_types.h: $(srcdir)/../sf_types.h @src_header=$?; dst_header=$@; $(copy_headers) include/obfuscation.h: $(srcdir)/../obfuscation.h @src_header=$?; dst_header=$@; $(massage_headers) include/rule_option_types.h: $(srcdir)/../rule_option_types.h @src_header=$?; dst_header=$@; $(copy_headers) include/event.h: $(srcdir)/../event.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfcontrol.h: $(srcdir)/../control/sfcontrol.h @src_header=$?; dst_header=$@; $(copy_headers) include/idle_processing.h: $(srcdir)/../idle_processing.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins include/sf_dynamic_common.h: $(srcdir)/../dynamic-plugins/sf_dynamic_common.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_engine.h: $(srcdir)/../dynamic-plugins/sf_dynamic_engine.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_define.h: $(srcdir)/../dynamic-plugins/sf_dynamic_define.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_meta.h: $(srcdir)/../dynamic-plugins/sf_dynamic_meta.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_preprocessor.h: $(srcdir)/../dynamic-plugins/sf_dynamic_preprocessor.h @src_header=$?; dst_header=$@; $(massage_headers) # From dynamic-plugins/sf_preproc_example include/sf_dynamic_preproc_lib.c: $(srcdir)/../dynamic-plugins/sf_preproc_example/sf_dynamic_preproc_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_preproc_lib.h: $(srcdir)/../dynamic-plugins/sf_preproc_example/sf_dynamic_preproc_lib.h @src_header=$?; dst_header=$@; $(copy_headers) # From Utils include/sfghash.h: $(srcdir)/../sfutil/sfghash.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfhashfcn.h: $(srcdir)/../sfutil/sfhashfcn.h @src_header=$?; dst_header=$@; $(copy_headers) include/bitop.h: $(srcdir)/../sfutil/bitop.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ip.h: $(srcdir)/../sfutil/sf_ip.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ip.c: $(srcdir)/../sfutil/sf_ip.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ipvar.h: $(srcdir)/../sfutil/sf_ipvar.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_vartable.h: $(srcdir)/../sfutil/sf_vartable.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt.h: $(srcdir)/../sfutil/sfrt.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt.c: $(srcdir)/../sfutil/sfrt.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_dir.h: $(srcdir)/../sfutil/sfrt_dir.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_dir.c: $(srcdir)/../sfutil/sfrt_dir.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_trie.h: $(srcdir)/../sfutil/sfrt_trie.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfPolicyUserData.c: $(srcdir)/../sfutil/sfPolicyUserData.c @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/sfPolicyUserData.h: $(srcdir)/../sfutil/sfPolicyUserData.h @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/sfPolicy.h: $(srcdir)/../sfutil/sfPolicy.h @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) # From dynamic-plugins/sf_engine/examples include/sfsnort_dynamic_detection_lib.c: $(srcdir)/../dynamic-plugins/sf_engine/examples/sfsnort_dynamic_detection_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfsnort_dynamic_detection_lib.h: $(srcdir)/../dynamic-plugins/sf_engine/examples/sfsnort_dynamic_detection_lib.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins/sf_engine include/sf_snort_packet.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_snort_packet.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_protocols.h: $(srcdir)/../sf_protocols.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_snort_plugin_api.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_snort_plugin_api.h @src_header=$?; dst_header=$@; $(copy_headers) # Stream API/String Searching, massage it to use SFSnortPacket include/stream_api.h: $(srcdir)/../preprocessors/stream_api.h @src_header=$?; dst_header=$@; $(massage_headers) include/str_search.h: $(srcdir)/../preprocessors/str_search.h @src_header=$?; dst_header=$@; $(massage_headers) include/treenodes.h: $(srcdir)/../treenodes.h @src_header=$?; dst_header=$@; $(copy_treenode_header) include/signature.h: $(srcdir)/../signature.h @src_header=$?; dst_header=$@; $(copy_treenode_header) include/plugin_enum.h: $(srcdir)/../plugin_enum.h @src_header=$?; dst_header=$@; $(copy_headers) include/file_api.h: $(top_srcdir)/src/file-process/file_api.h @src_header=$?; dst_header=$@; $(copy_headers) clean-local: rm -rf include build # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/file-process/0000755000000000000000000000000012260606567013176 500000000000000snort-2.9.6.0/src/file-process/libs/0000755000000000000000000000000012260606567014127 500000000000000snort-2.9.6.0/src/file-process/libs/file_sha256.h0000644000000000000000000000352012260565732016225 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** The code is based on DotGNU Portable.NET GPL ** 5/1/2012 - Initial implementation ... Hui Cao */ #ifndef __FILE_SHA256_H #define __FILE_SHA256_H #include #include "sf_types.h" #define SHA256_HASH_SIZE 32 #ifdef HAVE_OPENSSL_SHA #include #define SHA256CONTEXT SHA256_CTX #define SHA256INIT SHA256_Init #define SHA256UPDATE SHA256_Update #define SHA256FINAL SHA256_Final #else typedef struct _Sha256Context { uint32_t inputLen; uint32_t A, B, C, D, E, F, G, H; uint8_t input[64]; uint64_t totalLen; }Sha256Context; void SHA256Init(Sha256Context *sha); void SHA256ProcessData(Sha256Context *sha, const void *buffer, unsigned long len); void SHA256Final(unsigned char *hash, Sha256Context *sha); #define SHA256CONTEXT Sha256Context #define SHA256INIT SHA256Init #define SHA256UPDATE SHA256ProcessData #define SHA256FINAL SHA256Final #endif #endif /* SFSHA256_H */ snort-2.9.6.0/src/file-process/libs/file_sha256.c0000644000000000000000000001727712260565732016236 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** The code is based on DotGNU Portable.NET GPL ** 5/1/2012 - Initial implementation ... Hui Cao */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "file_sha256.h" #ifndef HAVE_OPENSSL_SHA #include #include /* * Some helper macros for processing 32-bit values, while * being careful about 32-bit vs 64-bit system differences. */ #if SIZEOF_LONG > 4 #define TRUNCLONG(x) ((x) & IL_MAX_UINT32) #define ROTATE(x,n) (TRUNCLONG(((x) >> (n))) | ((x) << (32 - (n)))) #define SHIFT(x,n) (TRUNCLONG(((x) >> (n)))) #else #define TRUNCLONG(x) (x) #define ROTATE(x,n) (((x) >> (n)) | ((x) << (32 - (n)))) #define SHIFT(x,n) ((x) >> (n)) #endif /* * Helper macros used by the SHA-256 computation. */ #define CH(x,y,z) (((x) & (y)) ^ (TRUNCLONG(~(x)) & (z))) #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #define SUM0(x) (ROTATE((x), 2) ^ ROTATE((x), 13) ^ ROTATE((x), 22)) #define SUM1(x) (ROTATE((x), 6) ^ ROTATE((x), 11) ^ ROTATE((x), 25)) #define RHO0(x) (ROTATE((x), 7) ^ ROTATE((x), 18) ^ SHIFT((x), 3)) #define RHO1(x) (ROTATE((x), 17) ^ ROTATE((x), 19) ^ SHIFT((x), 10)) /* * Initialize table of round constants * (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311) */ static uint32_t const K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; void SHA256Init(Sha256Context *sha) { sha->inputLen = 0; sha->A = 0x6a09e667; sha->B = 0xbb67ae85; sha->C = 0x3c6ef372; sha->D = 0xa54ff53a; sha->E = 0x510e527f; sha->F = 0x9b05688c; sha->G = 0x1f83d9ab; sha->H = 0x5be0cd19; sha->totalLen = 0; } /* * Process a single block of input using the hash algorithm. */ static void ProcessBlock(Sha256Context *sha, const unsigned char *block) { uint32_t W[64]; uint32_t a, b, c, d, e, f, g, h; uint32_t temp, temp2; int t; /* Unpack the block into 64 32-bit words */ for(t = 0; t < 16; ++t) { W[t] = (((uint32_t)(block[t * 4 + 0])) << 24) | (((uint32_t)(block[t * 4 + 1])) << 16) | (((uint32_t)(block[t * 4 + 2])) << 8) | ((uint32_t)(block[t * 4 + 3])); } for(t = 16; t < 64; ++t) { W[t] = TRUNCLONG(RHO1(W[t - 2]) + W[t - 7] + RHO0(W[t - 15]) + W[t - 16]); } /* Load the SHA-256 state into local variables */ a = sha->A; b = sha->B; c = sha->C; d = sha->D; e = sha->E; f = sha->F; g = sha->G; h = sha->H; /* Perform 64 rounds of hash computations */ for(t = 0; t < 64; ++t) { temp = TRUNCLONG(h + SUM1(e) + CH(e, f, g) + K[t] + W[t]); temp2 = TRUNCLONG(SUM0(a) + MAJ(a, b, c)); h = g; g = f; f = e; e = TRUNCLONG(d + temp); d = c; c = b; b = a; a = TRUNCLONG(temp + temp2); } /* Combine the previous SHA-256 state with the new state */ sha->A = TRUNCLONG(sha->A + a); sha->B = TRUNCLONG(sha->B + b); sha->C = TRUNCLONG(sha->C + c); sha->D = TRUNCLONG(sha->D + d); sha->E = TRUNCLONG(sha->E + e); sha->F = TRUNCLONG(sha->F + f); sha->G = TRUNCLONG(sha->G + g); sha->H = TRUNCLONG(sha->H + h); } void SHA256ProcessData(Sha256Context *sha, const void *buffer, unsigned long len) { unsigned long templen; /* Add to the total length of the input stream */ sha->totalLen += (uint64_t)len; /* Copy the blocks into the input buffer and process them */ while(len > 0) { if(!(sha->inputLen) && len >= 64) { /* Short cut: no point copying the data twice */ ProcessBlock(sha, (const unsigned char *)buffer); buffer = (const void *)(((const unsigned char *)buffer) + 64); len -= 64; } else { templen = len; if(templen > (64 - sha->inputLen)) { templen = 64 - sha->inputLen; } memcpy(sha->input + sha->inputLen, buffer, templen); if((sha->inputLen += templen) >= 64) { ProcessBlock(sha, sha->input); sha->inputLen = 0; } buffer = (const void *)(((const unsigned char *)buffer) + templen); len -= templen; } } } /* * Write a 32-bit big-endian long value to a buffer. */ static void WriteLong(unsigned char *buf, uint32_t value) { buf[0] = (unsigned char)(value >> 24); buf[1] = (unsigned char)(value >> 16); buf[2] = (unsigned char)(value >> 8); buf[3] = (unsigned char)value; } void SHA256Final(unsigned char *hash, Sha256Context *sha) { uint64_t totalBits; /* Compute the final hash if necessary */ if(hash) { /* Pad the input data to a multiple of 512 bits */ if(sha->inputLen >= 56) { /* Need two blocks worth of padding */ sha->input[(sha->inputLen)++] = (unsigned char)0x80; while(sha->inputLen < 64) { sha->input[(sha->inputLen)++] = (unsigned char)0x00; } ProcessBlock(sha, sha->input); sha->inputLen = 0; } else { /* Need one block worth of padding */ sha->input[(sha->inputLen)++] = (unsigned char)0x80; } while(sha->inputLen < 56) { sha->input[(sha->inputLen)++] = (unsigned char)0x00; } totalBits = (sha->totalLen << 3); WriteLong(sha->input + 56, (uint32_t)(totalBits >> 32)); WriteLong(sha->input + 60, (uint32_t)totalBits); ProcessBlock(sha, sha->input); /* Write the final hash value to the supplied buffer */ WriteLong(hash, sha->A); WriteLong(hash + 4, sha->B); WriteLong(hash + 8, sha->C); WriteLong(hash + 12, sha->D); WriteLong(hash + 16, sha->E); WriteLong(hash + 20, sha->F); WriteLong(hash + 24, sha->G); WriteLong(hash + 28, sha->H); } } #endif snort-2.9.6.0/src/file-process/libs/file_identifier.h0000644000000000000000000000547412260565732017351 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.2012 - Initial Source Code. Hcao */ #ifndef __FILE_IDENTIFIER_H__ #define __FILE_IDENTIFIER_H__ #include "file_lib.h" #define MAX_BRANCH (UINT8_MAX + 1) /* 256 identifiers pointers*/ typedef enum _IdNodeState { ID_NODE_NEW, ID_NODE_USED, ID_NODE_SHARED } IdNodeState; typedef struct _IdentifierNode { uint32_t type_id; /* magic content to match*/ IdNodeState state; uint32_t offset; /* offset from file start */ struct _IdentifierNode *next[MAX_BRANCH]; /* next levels*/ } IdentifierNode; typedef struct _IdentifierNodeHead { int offset; /* offset from file start */ IdentifierNode *start; /* start node for the trie at this offset*/ struct _IdentifierNodeHead *nextHead; /* pointer to next offset head*/ } IdentifierNodeHead; /* Initialize file type id states * * Args: None * Return: None */ void file_identifers_init(void); /* Insert one file rule to file identifiers trie, update file identifiers * * Args: * RuleInfo *rule: file magic rule information * void *conf: file configuration * * Return: * None */ void file_identifers_update(RuleInfo *rule, void *conf); /* Memory usage for all file magics * * Args: None * Return: * uint32_t: memory usage in bytes */ uint32_t file_identifiers_usage(void); /* Main process for file type identification. * This identification is stateful * * Args: * uint8_t *buf: data buffer pointer * int len: length of data buffer * FileContext *context: context for saving state * Return: * uint32_t: file type ID */ uint32_t file_identifiers_match(uint8_t *buf, int len, FileContext *cxt); /* Free file identifiers stored in conf * * Args: * void *conf: file configuration * * Return: * None */ void file_identifiers_free(void* conf); #ifdef DEBUG_MSGS void file_identifiers_print(IdentifierNode*); #endif #endif snort-2.9.6.0/src/file-process/libs/file_identifier.c0000644000000000000000000003374312260565732017344 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.2012 - Initial Source Code. Hcao */ #ifdef HAVE_CONFIG_H #include #endif #include "sf_types.h" #include "file_identifier.h" #include #include #include #include "parser.h" #include "util.h" #include "mstring.h" #include "sfghash.h" #include "file_config.h" uint32_t memory_used = 0; /*Track memory usage*/ static SFGHASH *identifier_merge_hash = NULL; typedef struct _IdentifierSharedNode { IdentifierNode *shared_node; /*the node that is shared*/ IdentifierNode *append_node; /*the node that is added*/ } IdentifierSharedNode; static IdentifierMemoryBlock *id_memory_root = NULL; static IdentifierMemoryBlock *id_memory_current = NULL; #ifdef DEBUG_MSGS static char *file_type_test(void *conf); #endif static void identifierMergeHashFree(void) { if (identifier_merge_hash != NULL) { sfghash_delete(identifier_merge_hash); identifier_merge_hash = NULL; } } static void identifierMergeHashInit(void) { if (identifier_merge_hash != NULL) identifierMergeHashFree(); identifier_merge_hash = sfghash_new(1000, sizeof(IdentifierSharedNode), 0, NULL); if (identifier_merge_hash == NULL) { FatalError("%s(%d) Could not create identifier merge hash.\n", __FILE__, __LINE__); } } static inline void *calloc_mem(size_t size) { void *ret; IdentifierMemoryBlock *new = NULL; ret = SnortAlloc(size); memory_used += size; /*For memory management*/ size = sizeof(*new); new = (IdentifierMemoryBlock *)SnortAlloc(size); new->mem_block = ret; if (!id_memory_root) { id_memory_root = new; } else { id_memory_current->next = new; } id_memory_current = new; memory_used += size; DEBUG_WRAP(DebugMessage(DEBUG_FILE,"calloc: %p (%d).\n", ret, size);); return ret; } static void set_node_state_shared(IdentifierNode *start) { int i; if (!start) return; if (start->state == ID_NODE_SHARED) return; if (start->state == ID_NODE_USED) start->state = ID_NODE_SHARED; else { start->state = ID_NODE_USED; } for(i = 0; i < MAX_BRANCH; i++) { set_node_state_shared(start->next[i]); } } /*Clone a trie*/ static IdentifierNode *clone_node(IdentifierNode *start) { int index; IdentifierNode *new; if (!start) return NULL; new = calloc_mem(sizeof(*new)); new->offset = start->offset; new->type_id = start->type_id; for(index = 0; index < MAX_BRANCH; index++) { if (start->next[index]) { new->next[index] = start->next[index]; } } return new; } static void verify_magic_offset(MagicData *parent, MagicData *current) { if ((parent) && (parent->content_len + parent->offset > current->offset)) { ParseError(" Magic content at offset %d overlaps with offset %d.", parent->offset, current->offset); } if ((current->next) && (current->content_len + current->offset > current->next->offset)) { ParseError(" Magic content at offset %d overlaps with offset %d.", current->offset, current->next->offset); } } /* Add a new node to the sorted magic list */ static void add_to_sorted_magic(MagicData **head, MagicData *new ) { MagicData *current = *head; /*Avoid adding the same magic*/ if (!new || (current == new)) return; if (new->offset < current->offset) { /*current becomes new head*/ new->next = current; *head = new; verify_magic_offset(NULL, new); return; } /*Find the parent for the new magic*/ while (current) { MagicData *next = current->next; if ((!next) || (new->offset < next->offset)) { /*current is the parent*/ current->next = new; new->next = next; verify_magic_offset(current, new); return; } current = next; } } /* Content magics are sorted based on offset, this * will help compile the file magic trio */ static void sort_magics(MagicData **head) { MagicData *current = *head; /*Add one magic at a time to sorted magics*/ while (current) { MagicData *next = current->next; current->next = NULL; add_to_sorted_magic(head, current); current = next; } } /*Create a trie for the magic*/ static inline IdentifierNode *create_trie_from_magic(MagicData **head, uint32_t type_id) { int i; IdentifierNode *current; IdentifierNode *root = NULL; MagicData *magic; if (!head || !(*head)||(0 == (*head)->content_len) || !type_id) return NULL; sort_magics(head); magic = *head; current = calloc_mem(sizeof(*current)); current->state = ID_NODE_NEW; root = current; while (magic) { current->offset = magic->offset; for(i = 0; i < magic->content_len; i++) { IdentifierNode *new = calloc_mem(sizeof(*new)); new->offset = magic->offset + i + 1; new->state = ID_NODE_NEW; current->next[magic->content[i]] = new; current = new; } magic = magic->next; } /*Last node has type name*/ current->type_id = type_id; DEBUG_WRAP( if (DEBUG_FILE & GetDebugLevel()){file_identifiers_print(root);}) return root; } /*This function examines whether to update the trie based on shared state*/ static inline bool updateNext(IdentifierNode *start,IdentifierNode **next_ptr, IdentifierNode *append) { IdentifierNode *next = (*next_ptr); IdentifierSharedNode sharedIdentifier; IdentifierNode *result; if (!append || (next == append)) return false; sharedIdentifier.append_node = append; sharedIdentifier.shared_node = next; if (!next) { /*reuse the append*/ *next_ptr = append; set_node_state_shared(append); return false; } else if ((result = sfghash_find(identifier_merge_hash, &sharedIdentifier))) { /*the same pointer has been processed, reuse it*/ *next_ptr = result; set_node_state_shared(result); return false; } else { if ((start->offset < append->offset) && (next->offset > append->offset)) { /*offset could have gap when non 0 offset is allowed */ int index; IdentifierNode *new = calloc_mem(sizeof(*new)); sharedIdentifier.shared_node = next; sharedIdentifier.append_node = append; new->offset = append->offset; for(index = 0; index < MAX_BRANCH; index++) { new->next[index] = next; } set_node_state_shared(next); next = new; sfghash_add(identifier_merge_hash, &sharedIdentifier, next); } else if (next->state == ID_NODE_SHARED) { /*shared, need to clone one*/ IdentifierNode *current_next = next; sharedIdentifier.shared_node = current_next; sharedIdentifier.append_node = append; next = clone_node(current_next); set_node_state_shared(next); sfghash_add(identifier_merge_hash, &sharedIdentifier, next); } *next_ptr = next; } return true; } /* * Append magic to existing trie * */ static void update_trie(IdentifierNode *start, IdentifierNode *append) { int i; if ((!start )||(!append)||(start == append)) return ; DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Working on %p -> %p at offset %d.\n", start, append, append->offset);); if (start->offset == append->offset ) { /* when we come here, make sure this tree is not shared * Update start trie using append information*/ if (start->state == ID_NODE_SHARED) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Something is wrong ...");); } if (append->type_id) { if(start->type_id) LogMessage("Duplicated type definition '%d -> %d at offset %d.\n", start->type_id, append->type_id, append->offset); start->type_id = append->type_id; } for(i = 0; i < MAX_BRANCH; i++) { if (updateNext(start,&start->next[i], append->next[i])) { update_trie(start->next[i], append->next[i]); } } } else if (start->offset < append->offset ) { for(i = 0; i < MAX_BRANCH; i++) { if (updateNext(start,&start->next[i], append)) update_trie(start->next[i], append); } } else /*This is impossible*/ { DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Something is wrong .....");); } return; } void file_identifers_update(RuleInfo *rule, void *conf) { IdentifierNode *new; FileConfig *file_config = NULL; file_config = (FileConfig *) conf; if (!file_config->identifier_root) { file_identifers_init(); file_config->identifier_root = calloc_mem(sizeof(*file_config->identifier_root)); file_config->id_memory_root = id_memory_root; identifierMergeHashInit(); } new = create_trie_from_magic(&(rule->magics), rule->id); update_trie(file_config->identifier_root, new); DEBUG_WRAP( if (DEBUG_FILE & GetDebugLevel()){file_type_test(file_config);}); } void file_identifers_init(void) { memory_used = 0; id_memory_root = NULL; id_memory_current = NULL; } uint32_t file_identifiers_usage(void) { return memory_used; } /* * This is the main function to find file type * Find file type is to traverse the tries. * Context is saved to continue file type identification * when more data are available */ uint32_t file_identifiers_match(uint8_t *buf, int len, FileContext *context) { FileConfig *file_config; IdentifierNode* current; uint64_t end; if ((!context)||(!buf)||(len <= 0)) return 0; file_config = (FileConfig *)context->file_config; if (!(context->file_type_context)) context->file_type_context = (void *)(file_config->identifier_root); current = (IdentifierNode*) context->file_type_context; end = context->processed_bytes + len; while(current && (current->offset < end) && len && (current->offset >= context->processed_bytes)) { /*Found file id, save and continue*/ if (current->type_id) { context->file_type_id = current->type_id; } /*Move to the next level*/ current = current->next[buf[current->offset - context->processed_bytes]]; len--; } /* save current state */ context->file_type_context = current; /*No more checks are needed*/ if (!current) { /*Found file type in current buffer, return*/ if (context->file_type_id) return context->file_type_id; else return SNORT_FILE_TYPE_UNKNOWN; } else if (current->offset >= end) { return SNORT_FILE_TYPE_CONTINUE; } else return SNORT_FILE_TYPE_UNKNOWN; } void file_identifiers_free(void *conf) { IdentifierMemoryBlock *id_memory_next; FileConfig *file_config = (FileConfig *)conf; if (!file_config) return; /*Release memory used for identifiers*/ id_memory_current = file_config->id_memory_root; while (id_memory_current) { id_memory_next = id_memory_current->next; free(id_memory_current->mem_block); free(id_memory_current); id_memory_current = id_memory_next; } file_config->id_memory_root = NULL; identifierMergeHashFree(); } #ifdef DEBUG_MSGS void file_identifiers_print(IdentifierNode* current) { int i; DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Working on pointer %p, offset:%d\n", (void *) current, current->offset);); for (i = 0; i < MAX_BRANCH; i++) { if (current->next[i]) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Magic number: %x ", i);); file_identifiers_print(current->next[i]); } } if (current->type_id) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Type: %d\n", current->type_id);); } return; } char *file_type_test(void *conf) { uint8_t str[100] = {0x4d, 0x5a, 0x46, 0x38, 0x66, 0x72, 0x65, 0x65, 0}; unsigned int i; uint32_t type_id; FileContext *context = SnortAlloc(sizeof (*context)); static const char *file_type = "MSEXE"; printf("Check string:"); for (i = 0; i < strlen((char*)str); i++) { printf(" %x", str[i]); } printf("\n"); context->file_config = conf; type_id = file_identifiers_match(str, strlen((char *)str), context); if (SNORT_FILE_TYPE_UNKNOWN == type_id) { printf("File type is unknown\n"); } else if (SNORT_FILE_TYPE_CONTINUE != type_id) printf("File type is: %s (%d)\n", file_type_name(conf, type_id), type_id); free(context); return ((char *)file_type); } #endif snort-2.9.6.0/src/file-process/libs/file_config.h0000644000000000000000000000574212260565732016472 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.2012 - Initial Source Code. Hcao */ #ifndef __FILE_CONFIG_H__ #define __FILE_CONFIG_H__ #include "file_lib.h" #include "file_identifier.h" #define FILE_ID_MAX 1024 typedef struct _IdentifierMemoryBlock { void *mem_block; /*the node that is shared*/ struct _IdentifierMemoryBlock *next; /*next node*/ }IdentifierMemoryBlock; typedef struct _fileConfig { IdentifierNode *identifier_root; /*Root of magic tries*/ IdentifierMemoryBlock *id_memory_root; /*root of memory used*/ RuleInfo *FileRules[FILE_ID_MAX + 1]; int64_t file_type_depth; int64_t file_signature_depth; int64_t file_block_timeout; int64_t file_lookup_timeout; bool block_timeout_lookup; int64_t file_capture_memcap; int64_t file_capture_max_size; int64_t file_capture_min_size; int64_t file_capture_block_size; #if defined(DEBUG_MSGS) || defined (REG_TEST) int64_t show_data_depth; #endif int64_t file_depth; } FileConfig; #if defined(FEAT_FILE_INSPECT) /* Return all rule id's that match a a given "type" string. */ bool get_ids_from_type( const void * conf, const char * type, uint32_t ** ids, int * count ); /* Return all rule id's that match a a given "type" and "version" strings. */ bool get_ids_from_type_version( const void * conf, const char * type, const char * version, uint32_t ** ids, int * count ); /* Return all rule id's in a given file rule group. */ bool get_ids_from_group( const void * conf, const char * group, uint32_t ** ids, int * count ); #endif /* FEAT_FILE_INSPECT */ /* * Parse file magic rule * * Args: * char *args: file magic rule string * void *file_config: pointer to file config */ void file_rule_parse(char *args, void *file_config); /* * Get rule information * * Args: * void *file_config: pointer to file config * uint32_t rule_id: file rule ID */ RuleInfo *file_rule_get(void *conf, uint32_t rule_id); /* Free resource used by file rules * * Args: * void *file_config: pointer to file config */ void file_rule_free(void* conf); #endif snort-2.9.6.0/src/file-process/libs/file_config.c0000644000000000000000000004744712260565732016475 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.2012 - Initial Source Code. Hcao */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "sf_types.h" #include "util.h" #include "mstring.h" #include "parser.h" #if defined(FEAT_FILE_INSPECT) # include "sfutil/strvec.h" #endif /* FEAT_FILE_INSPECT */ #include "file_lib.h" #include "file_identifier.h" #include "file_config.h" typedef void (*ParseFileOptFunc)(RuleInfo*, char *); typedef struct _FileOptFunc { char *name; int args_required; int only_once; /*the option is one per file rule*/ ParseFileOptFunc parse_func; } FileOptFunc; #define FILE_OPT__TYPE "type" #define FILE_OPT__ID "id" #define FILE_OPT__VERSION "ver" #define FILE_OPT__CATEGORY "category" #define FILE_OPT__MSG "msg" #define FILE_OPT__REVISION "rev" #define FILE_OPT__CONTENT "content" #define FILE_OPT__OFFSET "offset" #if defined(FEAT_FILE_INSPECT) # define FILE_OPT__GROUP "group" #endif /* FEAT_FILE_INSPECT */ #define FILE_REVISION_MAX UINT32_MAX #define FILE_OFFSET_MAX UINT32_MAX static void ParseFileRuleType(RuleInfo *, char *); static void ParseFileRuleID(RuleInfo *, char *); static void ParseFileRuleVersion(RuleInfo *, char *); static void ParseFileRuleCategory(RuleInfo *, char *); static void ParseFileRuleMessage(RuleInfo *, char *); static void ParseFileRevision(RuleInfo *, char *); static void ParseFileContent(RuleInfo *, char *); static void ParseFileOffset(RuleInfo *, char *); #if defined(FEAT_FILE_INSPECT) static void ParseFileGroup(RuleInfo *, char *); #endif /* FEAT_FILE_INSPECT */ static const FileOptFunc file_options[] = { { FILE_OPT__TYPE, 1, 1, ParseFileRuleType }, { FILE_OPT__ID, 1, 1, ParseFileRuleID }, { FILE_OPT__VERSION, 0, 1, ParseFileRuleVersion }, { FILE_OPT__CATEGORY, 1, 1, ParseFileRuleCategory }, { FILE_OPT__MSG, 0, 1, ParseFileRuleMessage }, { FILE_OPT__REVISION, 0, 1, ParseFileRevision }, { FILE_OPT__CONTENT, 1, 0, ParseFileContent }, { FILE_OPT__OFFSET, 1, 0, ParseFileOffset }, #if defined(FEAT_FILE_INSPECT) { FILE_OPT__GROUP, 1, 0, ParseFileGroup }, #endif /* FEAT_FILE_INSPECT */ { NULL, 0, 0, NULL } /* Marks end of array */ }; /* Used for content modifiers that are used as rule options - need to get the * last magic which is the one they are modifying. If there isn't a last magic * error that a content must be specified before the modifier */ static inline MagicData * GetLastMagic(RuleInfo *rule, const char *option) { MagicData *mdata; MagicData *lastMagic = NULL; if ((rule) && (rule->magics)) { for (mdata = rule->magics; mdata->next != NULL; mdata = mdata->next); lastMagic = mdata; } if (lastMagic == NULL) { ParseError("Please place \"content\" rules before \"%s\" modifier", option == NULL ? "unknown" : option); } return lastMagic; } static void ParseFileRuleType(RuleInfo *rule, char *args) { DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Type args: %s\n", args);); if (args == NULL) ParseError("Type rule option requires an argument."); rule->type = SnortStrdup(args); } static void ParseFileRuleID(RuleInfo *rule, char *args) { unsigned long int id; char *endptr; DEBUG_WRAP(DebugMessage(DEBUG_FILE,"ID args: %s\n", args);); if (args == NULL) ParseError("ID rule option requires an argument."); id = SnortStrtoul(args, &endptr, 0); if ((errno == ERANGE) || (*endptr != '\0')||(id > FILE_ID_MAX)) { ParseError("Invalid argument to 'id' rule option: %s. " "Must be a positive integer.", args); } rule->id = (uint32_t)id; } static void ParseFileRuleCategory(RuleInfo *rule, char *args) { DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Category args: %s\n", args);); if (args == NULL) ParseError("Category rule option requires an argument."); rule->category = SnortStrdup(args); } static void ParseFileRuleVersion(RuleInfo *rule, char *args) { DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Version args: %s\n", args);); if (args == NULL) ParseError("Version rule option requires an argument."); rule->version = SnortStrdup(args); } static void ParseFileRuleMessage(RuleInfo *rule, char *args) { size_t i; int escaped = 0; char msg_buf[2048]; /* Arbitrary length, but should be enough */ if (args == NULL) ParseError("Message rule option requires an argument."); DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Msg args: %s\n", args);); if (*args == '"') { /* Have to have at least quote, char, quote */ if (strlen(args) < 3) ParseError("Empty argument passed to rule option 'msg'."); if (args[strlen(args) - 1] != '"') { ParseError("Unmatch quote in rule option 'msg'."); } /* Move past first quote and NULL terminate last quote */ args++; args[strlen(args) - 1] = '\0'; /* If last quote is escaped, fatal error. * Make sure the backslash is not escaped */ if ((args[strlen(args) - 1] == '\\') && (strlen(args) > 1) && (args[strlen(args) - 2] != '\\')) { ParseError("Unmatch quote in rule option 'msg'."); } } /* Only valid escaped chars are ';', '"' and '\' */ /* Would be ok except emerging threats rules are escaping other chars */ for (i = 0; (i < sizeof(msg_buf)) && (*args != '\0');) { if (escaped) { msg_buf[i++] = *args; escaped = 0; } else if (*args == '\\') { escaped = 1; } else { msg_buf[i++] = *args; } args++; } if (escaped) { ParseError("Message in 'msg' rule option has invalid escape character." "\n"); } if (i == sizeof(msg_buf)) { ParseError("Message in 'msg' rule option too long. Please limit " "to %d characters.", sizeof(msg_buf)); } msg_buf[i] = '\0'; DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Message: %s\n", msg_buf);); rule->message = SnortStrdup(msg_buf); } static void ParseFileRevision(RuleInfo *rule, char *args) { unsigned long int rev; char *endptr; DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Revision args: %s\n", args);); if (args == NULL) ParseError("Revision rule option requires an argument."); rev = SnortStrtoul(args, &endptr, 0); if ((errno == ERANGE) || (*endptr != '\0') || (rev > FILE_REVISION_MAX)) { ParseError("Invalid argument to 'rev' rule option: %s. " "Must be a positive integer.", args); } rule->rev = (uint32_t)rev; } static uint8_t* convertTextToHex(char *text, int *size) { int i; char **toks; int num_toks; char hex_buf[3]; uint8_t *hex; toks = mSplit(text, " ", 0, &num_toks, 0); if (num_toks <= 0) { ParseError("No hexmode argument."); } hex = (uint8_t*) SnortAlloc(num_toks); *size = num_toks; memset(hex_buf, 0, sizeof(hex_buf)); for (i = 0; i < num_toks; i++) { char *current_ptr = toks[i]; if (2 != strlen(current_ptr)) { ParseError("Content hexmode argument has invalid " "number of hex digits. The argument '%s' " "must contain a full even byte string.", current_ptr); } if(isxdigit((int) *current_ptr)) { hex_buf[0] = *current_ptr; } else { ParseError("\"%c\" is not a valid hex value, " "please input hex values (0x0 - 0xF)", (char) *current_ptr); } current_ptr++; if(isxdigit((int) *current_ptr)) { hex_buf[1] = *current_ptr; } else { ParseError("\"%c\" is not a valid hex value, " "please input hex values (0x0 - 0xF)", (char) *current_ptr); } DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Hex buffer: %s\n", hex_buf);); hex[i] = (uint8_t) strtol(hex_buf, (char **) NULL, 16)&0xFF; memset(hex_buf, 0, sizeof(hex_buf)); DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Hex value: %x\n", hex[i]);); } mSplitFree(&toks, num_toks); return hex; } static void ParseFileContent(RuleInfo *rule, char *args) { MagicData *predata = NULL; MagicData *newdata; char *start_ptr; char *end_ptr; char *tmp; if (args == NULL) ParseError("Parse File Magic Got Null enclosed in vertical bar (|)!"); DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Content args: %s\n", args);); while(isspace((int)*args)) args++; /* find the start of the data */ start_ptr = strchr(args, '|'); if (start_ptr != args) ParseError("Content data needs to be enclosed in vertical bar (|)!"); /* move the start up from the beggining quotes */ start_ptr++; /* find the end of the data */ end_ptr = strrchr(start_ptr, '|'); if (end_ptr == NULL) ParseError("Content data needs to be enclosed in vertical bar (|)!"); /* Move the null termination up a bit more */ *end_ptr = '\0'; /* Is there anything other than whitespace after the trailing * double quote? */ tmp = end_ptr + 1; while (*tmp != '\0' && isspace ((int)*tmp)) tmp++; if (strlen (tmp) > 0) { ParseError("Bad data (possibly due to missing semicolon) after " "trailing double quote."); } if (rule->magics) { for (predata = rule->magics; predata->next != NULL; predata = predata->next); } newdata = SnortAlloc(sizeof(*newdata)); DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Content args: %s\n", start_ptr);); newdata->content = convertTextToHex(start_ptr, &(newdata->content_len)); if (predata) { predata->next = newdata; } else { rule->magics = newdata; } } static void ParseFileOffset(RuleInfo *rule, char *args) { unsigned long int offset; char *endptr; MagicData *mdata; DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Offset args: %s\n", args);); if (args == NULL) ParseError("Offset rule option requires an argument."); offset = SnortStrtoul(args, &endptr, 0); if ((errno == ERANGE) || (*endptr != '\0')|| (offset > FILE_OFFSET_MAX)) { ParseError("Invalid argument to 'offset' rule option: %s. " "Must be a positive integer.", args); } mdata = GetLastMagic(rule, "offset"); mdata->offset = (uint32_t)offset; } #if defined(FEAT_FILE_INSPECT) static void ParseFileGroup(RuleInfo * rule, char * args) { char **toks; int num_toks, i; DEBUG_WRAP( DebugMessage(DEBUG_FILE,"Group args: %s\n", args); ); toks = mSplit(args, ",", 0, &num_toks, 0); if (num_toks < 1) { ParseError("Group rule option requires an argument."); } rule->groups = StringVector_New(); for (i = 0; i < num_toks; i++) StringVector_Add(rule->groups, toks[i]); mSplitFree(&toks, num_toks); } #endif /* FEAT_FILE_INSPECT */ static void parse_options(char *option_name, char *option_args, char *configured, RuleInfo *rule) { int i; for (i = 0; file_options[i].name != NULL; i++) { if (strcasecmp(option_name, file_options[i].name)) continue; if (configured[i] && file_options[i].only_once) { ParseError("Only one '%s' rule option per rule.", option_name); } if ((option_args == NULL) && file_options[i].args_required) { ParseError("No argument passed to keyword \"%s\". " "Make sure you didn't forget a ':' or the " "argument to this keyword.\n",option_name); } file_options[i].parse_func(rule, option_args); configured[i] = 1; return; } /* Unrecognized rule option */ ParseError("Unknown rule option: '%s'.", option_name); } #ifdef DEBUG_MSGS static int file_rule_print(RuleInfo *rule) { MagicData *mdata; if (!rule) { DebugMessage(DEBUG_FILE,"Rule is NULL!\n"); return 0; } DebugMessage(DEBUG_FILE,"File type Id: %d\n", rule->id); DebugMessage(DEBUG_FILE,"File type name: %s\n", rule->type); DebugMessage(DEBUG_FILE,"File type Category: %s\n", rule->category); DebugMessage(DEBUG_FILE,"Rule revision: %d\n", rule->rev); DebugMessage(DEBUG_FILE,"Rule message: %s\n", rule->message); if (!rule->magics) { DebugMessage(DEBUG_FILE,"No megic defined in rule!\n"); } for (mdata = rule->magics; mdata != NULL; mdata = mdata->next) { int i; int buff_size = mdata->content_len * 2 + 1; char *buff = SnortAlloc( buff_size); char *start_ptr = buff; DebugMessage(DEBUG_FILE,"Magic offset: %d\n", mdata->offset); DebugMessage(DEBUG_FILE,"Magic length: %d\n", mdata->content_len); for (i = 0; (i < mdata->content_len) && (buff_size > 0); i++) { int num_read; num_read = snprintf(start_ptr, buff_size, "%x",mdata->content[i]); start_ptr += num_read; buff_size -= num_read; } DebugMessage(DEBUG_FILE,"Magic content: %s\n", buff); free(buff); } return rule->id; } #endif #if defined(FEAT_FILE_INSPECT) static inline void __add_id_to_list( uint32_t **list, int *list_size, const uint32_t id ) { uint32_t *_temp; (*list_size)++; _temp = *list; if ( (*list = realloc(_temp, sizeof(**list)*(*list_size))) == NULL ) { free(_temp); FatalError("Failed realloc!"); } (*list)[(*list_size)-1] = id; } bool get_ids_from_type(const void *conf, const char *type, uint32_t **ids, int *count) { const FileConfig *file_config = (FileConfig *)conf; bool status = false; int i; if ( !file_config ) return NULL; /* Search for the matching rules */ for ( i = 0; i <= FILE_ID_MAX; i++ ) { const RuleInfo * rule = file_config->FileRules[i]; if ( !rule ) continue; if ( strcmp(rule->type, type) ) continue; __add_id_to_list( ids, count, rule->id ); status = true; } return status; } bool get_ids_from_type_version(const void *conf, const char *type, const char *version, uint32_t **ids, int *count) { const FileConfig *file_config = (FileConfig *)conf; bool status = false; int i; if ( !file_config ) return NULL; /* Search for the matching rules */ for ( i = 0; i <= FILE_ID_MAX; i++ ) { const RuleInfo *rule = file_config->FileRules[i]; if ( !rule || !rule->version ) continue; if ( strcmp(rule->type, type) ) continue; if ( strcmp(rule->version, version) ) continue; __add_id_to_list( ids, count, rule->id ); status = true; } return status; } bool get_ids_from_group(const void *conf, const char *group, uint32_t **ids, int *count) { const FileConfig *file_config = (FileConfig*)conf; bool status = false; int i; if ( !file_config ) return NULL; /* Search for the matching rules */ for ( i = 0; i <= FILE_ID_MAX; i++ ) { const RuleInfo *rule = file_config->FileRules[i]; const char *_group; int j = 0; if ( !rule || !rule->groups ) continue; /* Check if this rule belongs to the caller provided group */ while( (_group = StringVector_Get(rule->groups, j++)) ) { if ( _group && !strcmp(_group, group) ) break; } if ( !_group ) continue; __add_id_to_list( ids, count, rule->id ); status = true; } return status; } #endif /* FEAT_FILE_INSPECT */ /*The main function for parsing rule option*/ void file_rule_parse(char *args, void *config) { char **toks; int num_toks; int i; char configured[sizeof(file_options) / sizeof(FileOptFunc)]; RuleInfo *rule; FileConfig *file_config = (FileConfig *)config; if (!file_config) { return; } rule = SnortAlloc(sizeof (*rule)); DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Loading file configuration: %s\n", args);); toks = mSplit(args, ";", 0, &num_toks, 0); /* get rule option pairs */ /* Used to determine if a rule option has already been configured * in the rule. Some can only be configured once */ memset(configured, 0, sizeof(configured)); for (i = 0; i < num_toks; i++) { char **opts; int num_opts; char *option_args = NULL; DEBUG_WRAP(DebugMessage(DEBUG_FILE," option: %s\n", toks[i]);); /* break out the option name from its data */ opts = mSplit(toks[i], ":", 2, &num_opts, '\\'); DEBUG_WRAP(DebugMessage(DEBUG_FILE," option name: %s\n", opts[0]);); if (num_opts == 2) { option_args = opts[1]; DEBUG_WRAP(DebugMessage(DEBUG_FILE," option args: %s\n", option_args);); } parse_options(opts[0], option_args, configured, rule); mSplitFree(&opts, num_opts); } if (file_config->FileRules[rule->id]) { ParseError("File type: duplicated rule id %d defined!", rule->id); } file_config->FileRules[rule->id] = rule; DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Rule parsed: %d\n", file_rule_print(rule));); file_identifers_update(rule,file_config); DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Total memory used for identifiers: " "%d\n", file_identifiers_usage());); mSplitFree(&toks, num_toks); } RuleInfo *file_rule_get(void *conf, uint32_t id) { if (conf) { FileConfig *file_config = (FileConfig *)conf; return (file_config->FileRules[id]); } return NULL; } static void _free_file_magic (MagicData *magics) { if (!magics) return; _free_file_magic(magics->next); free (magics->content); free (magics); } static void _free_file_rule(RuleInfo *rule) { if ( !rule ) return; if ( rule->category ) free(rule->category); if ( rule->message ) free(rule->message); if ( rule->type ) free(rule->type); if ( rule->version ) free(rule->version); #if defined(FEAT_FILE_INSPECT) if ( rule->groups ) StringVector_Delete(rule->groups); #endif /* FEAT_FILE_INSPECT */ _free_file_magic(rule->magics); free(rule); } void file_rule_free(void *conf) { int id; FileConfig *file_config = (FileConfig *)conf; if (!file_config) return; for (id = 0; id < FILE_ID_MAX + 1; id++) { _free_file_rule (file_config->FileRules[id]); file_config->FileRules[id] = NULL; } } snort-2.9.6.0/src/file-process/libs/file_lib.h0000644000000000000000000001021212260565732015757 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.12 - Initial Source Code. Hcao */ #ifndef __FILE_LIB_H__ #define __FILE_LIB_H__ #ifdef HAVE_CONFIG_H #include #endif #include #include "sf_types.h" /* for bool */ #include "file_api.h" #define SNORT_FILE_TYPE_UNKNOWN UINT16_MAX /**/ #define SNORT_FILE_TYPE_CONTINUE 0 /**/ typedef struct _MagicData { uint8_t *content; /* magic content to match*/ int content_len; /* length of magic content */ uint32_t offset; /* pattern search start offset */ /* Used in ds_list - do not try to iterate after parsing a rule * since the detection option tree will eliminate duplicates and * the list may have missing pmds */ struct _MagicData *next; /* ptr to next match struct */ } MagicData; typedef struct _RuleInfo { char *message; char *type; char *category; char *version; MagicData *magics; void *groups; uint32_t id; uint32_t rev; } RuleInfo; typedef struct _FileContext { bool file_type_enabled; bool file_signature_enabled; uint8_t *file_name; uint32_t file_name_size; uint64_t file_size; bool upload; uint64_t processed_bytes; uint32_t file_type_id; uint8_t *sha256; void * file_type_context; void * file_signature_context; void * file_config; time_t expires; uint16_t app_id; bool file_capture_enabled; FileCaptureInfo *file_capture; uint8_t *current_data; /*current file data*/ uint32_t current_data_len; File_Verdict verdict; bool suspend_block_verdict; FileState file_state; uint32_t file_id; } FileContext; /*Main File Processing functions */ void file_type_id( FileContext* context, uint8_t* file_data, int data_size, FilePosition position); void file_signature_sha256( FileContext* context, uint8_t* file_data, int data_size, FilePosition position); /*File context management*/ FileContext *file_context_create(void); void file_context_reset(FileContext *context); void file_context_free(void *context); /*File properties*/ void file_name_set (FileContext *context, uint8_t *file_name, uint32_t name_size); int file_name_get (FileContext *context, uint8_t **file_name, uint32_t *name_size); void file_size_set (FileContext *context, uint64_t file_size); uint64_t file_size_get (FileContext *context); void file_direction_set (FileContext *context, bool upload); bool file_direction_get (FileContext *context); void file_sig_sha256_set (FileContext *context, uint8_t *signature); uint8_t* file_sig_sha256_get (FileContext *context); char* file_type_name(void *conf, uint32_t); #if defined(FEAT_FILE_INSPECT) bool file_IDs_from_type(const void *conf, const char *type, uint32_t **ids, uint32_t *count); bool file_IDs_from_type_version(const void *conf, const char *type, const char *version, uint32_t **ids, uint32_t *count); bool file_IDs_from_group(const void *conf, const char *group, uint32_t **ids, uint32_t *count); #endif extern int64_t file_type_depth; extern int64_t file_signature_depth; #if defined(DEBUG_MSGS) || defined (REG_TEST) void file_sha256_print(unsigned char *hash); #endif #endif snort-2.9.6.0/src/file-process/libs/file_lib.c0000644000000000000000000002241512260565732015762 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.12 - Initial Source Code. Hcao */ #ifdef HAVE_CONFIG_H #include #endif #include "sf_types.h" #include "file_lib.h" #include "file_identifier.h" #include "file_config.h" #include #include #include #include #include "file_sha256.h" #include "util.h" #include "file_capture.h" static inline int get_data_size_from_depth_limit(FileContext* context, FileProcessType type, int data_size) { FileConfig *file_config = (FileConfig *)context->file_config; uint64_t max_depth; if (!file_config) return data_size; switch(type) { case SNORT_FILE_TYPE_ID: max_depth = file_config->file_type_depth; break; case SNORT_FILE_SHA256: max_depth = file_config->file_signature_depth; break; default: return data_size; } if (context->processed_bytes > max_depth) data_size = -1; else if (context->processed_bytes + data_size > max_depth) data_size = (int)(max_depth - context->processed_bytes); return data_size; } /* stop file type identification */ static inline void _finalize_file_type (FileContext* context) { if (SNORT_FILE_TYPE_CONTINUE == context->file_type_id) context->file_type_id = SNORT_FILE_TYPE_UNKNOWN; context->file_type_context = NULL; } /* * Main File type processing function * We use file type context to decide file type across packets * * File type detection is completed either when * 1) file is completed or * 2) file type depth is reached or * 3) file magics are exhausted in depth * */ void file_type_id( FileContext* context, uint8_t* file_data, int size, FilePosition position) { int data_size; if (!context) return; /* file type already found and no magics to continue*/ if (context->file_type_id && !context->file_type_context) return; /* Check whether file type depth is reached*/ data_size = get_data_size_from_depth_limit(context, SNORT_FILE_TYPE_ID, size); if (data_size < 0) { _finalize_file_type(context); return; } file_identifiers_match(file_data, data_size, context); /* Check whether file transfer is done or type depth is reached*/ if ( (position == SNORT_FILE_END) || (position == SNORT_FILE_FULL) || (data_size != size) ) { _finalize_file_type(context); } } void file_signature_sha256(FileContext* context, uint8_t* file_data, int size, FilePosition position) { int data_size; if (!context) return; data_size = get_data_size_from_depth_limit(context, SNORT_FILE_SHA256, size); if (data_size != size) { context->file_state.sig_state = FILE_SIG_DEPTH_FAIL; return; } switch (position) { case SNORT_FILE_START: context->file_signature_context = SnortAlloc(sizeof(SHA256CONTEXT)); SHA256INIT((SHA256CONTEXT *)context->file_signature_context); SHA256UPDATE((SHA256CONTEXT *)context->file_signature_context, file_data, data_size); break; case SNORT_FILE_MIDDLE: if (!context->file_signature_context) context->file_signature_context = SnortAlloc(sizeof(SHA256CONTEXT)); SHA256UPDATE((SHA256CONTEXT *)context->file_signature_context, file_data, data_size); break; case SNORT_FILE_END: if (!context->file_signature_context) context->file_signature_context = SnortAlloc(sizeof(SHA256CONTEXT)); if (context->processed_bytes == 0) SHA256INIT((SHA256CONTEXT *)context->file_signature_context); SHA256UPDATE((SHA256CONTEXT *)context->file_signature_context, file_data, data_size); context->sha256 = SnortAlloc(SHA256_HASH_SIZE); SHA256FINAL(context->sha256, (SHA256CONTEXT *)context->file_signature_context); context->file_state.sig_state = FILE_SIG_DONE; break; case SNORT_FILE_FULL: context->file_signature_context = SnortAlloc(sizeof (SHA256CONTEXT)); SHA256INIT((SHA256CONTEXT *)context->file_signature_context); SHA256UPDATE((SHA256CONTEXT *)context->file_signature_context, file_data, data_size); context->sha256 = SnortAlloc(SHA256_HASH_SIZE); SHA256FINAL(context->sha256, (SHA256CONTEXT *)context->file_signature_context); context->file_state.sig_state = FILE_SIG_DONE; break; default: break; } } /*File context management*/ FileContext *file_context_create(void) { FileContext *context = (FileContext *)SnortAlloc(sizeof(*context)); return (context); } static inline void cleanDynamicContext (FileContext *context) { if (context->file_signature_context) free(context->file_signature_context); if(context->sha256) free(context->sha256); if(context->file_capture) file_capture_stop(context); } void file_context_reset(FileContext *context) { cleanDynamicContext(context); memset(context, 0, sizeof(*context)); } void file_context_free(void *ctx) { FileContext *context = (FileContext *)ctx; if (!context) return; cleanDynamicContext(context); free(context); } /*File properties*/ /*Only set the pointer for performance, no deep copy*/ void file_name_set (FileContext *context, uint8_t *file_name, uint32_t name_size) { if (!context) return; context->file_name = file_name; context->file_name_size = name_size; } /* Return 1: file name available, * 0: file name is unavailable */ int file_name_get (FileContext *context, uint8_t **file_name, uint32_t *name_size) { if (!context) return 0; if (file_name) *file_name = context->file_name; else return 0; if (name_size) *name_size = context->file_name_size; else return 0; return 1; } void file_size_set (FileContext *context, uint64_t file_size) { if (!context) return; context->file_size = file_size; } uint64_t file_size_get (FileContext *context) { if (!context) return 0; return (context->file_size); } void file_direction_set (FileContext *context, bool upload) { if (!context) return; context->upload = upload; } bool file_direction_get (FileContext *context) { if (!context) return false; return (context->upload); } void file_sig_sha256_set (FileContext *context, uint8_t * signature) { if (!context) return; context->sha256= signature; } uint8_t* file_sig_sha256_get (FileContext *context) { if (!context) return NULL; return (context->sha256); } char* file_type_name(void* conf, uint32_t id) { RuleInfo *info; if (SNORT_FILE_TYPE_UNKNOWN == id) return ("Unknown file type, done!"); else if (SNORT_FILE_TYPE_CONTINUE == id) return ("Undecided file type, continue..."); info = file_rule_get(conf, id); if (info != NULL) return info->type; else return NULL; } #if defined(FEAT_FILE_INSPECT) bool file_IDs_from_type(const void *conf, const char *type, uint32_t **ids, uint32_t *count) { if ( !type ) return false; return get_ids_from_type(conf, type, ids, count); } bool file_IDs_from_type_version(const void *conf, const char *type, const char *version, uint32_t **ids, uint32_t *count ) { if ( !type || !version ) return false; return get_ids_from_type_version(conf, type, version, ids, count); } bool file_IDs_from_group(const void *conf, const char *group, uint32_t **ids, uint32_t *count) { if ( !group ) return false; return get_ids_from_group(conf, group, ids, count); } #endif /* FEAT_FILE_INSPECT */ #if defined(DEBUG_MSGS) || defined (REG_TEST) /* * Print a 32-byte hash value. */ void file_sha256_print(unsigned char *hash) { printf("SHA256: %02X%02X %02X%02X %02X%02X %02X%02X " "%02X%02X %02X%02X %02X%02X %02X%02X " "%02X%02X %02X%02X %02X%02X %02X%02X " "%02X%02X %02X%02X %02X%02X %02X%02X\n", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19], hash[20], hash[21], hash[22], hash[23], hash[24], hash[25], hash[26], hash[27], hash[28], hash[29], hash[30], hash[31]); } #endif snort-2.9.6.0/src/file-process/libs/Makefile.am0000644000000000000000000000037612232305201016065 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libfile.a libfile_a_SOURCES = \ file_lib.c \ file_lib.h \ file_config.c \ file_config.h \ file_identifier.c \ file_identifier.h \ file_sha256.c \ file_sha256.h INCLUDES = @INCLUDES@ snort-2.9.6.0/src/file-process/libs/Makefile.in0000644000000000000000000004015712260606524016114 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/file-process/libs DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libfile_a_AR = $(AR) $(ARFLAGS) libfile_a_LIBADD = am_libfile_a_OBJECTS = file_lib.$(OBJEXT) file_config.$(OBJEXT) \ file_identifier.$(OBJEXT) file_sha256.$(OBJEXT) libfile_a_OBJECTS = $(am_libfile_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libfile_a_SOURCES) DIST_SOURCES = $(libfile_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libfile.a libfile_a_SOURCES = \ file_lib.c \ file_lib.h \ file_config.c \ file_config.h \ file_identifier.c \ file_identifier.h \ file_sha256.c \ file_sha256.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/file-process/libs/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/file-process/libs/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libfile.a: $(libfile_a_OBJECTS) $(libfile_a_DEPENDENCIES) $(EXTRA_libfile_a_DEPENDENCIES) $(AM_V_at)-rm -f libfile.a $(AM_V_AR)$(libfile_a_AR) libfile.a $(libfile_a_OBJECTS) $(libfile_a_LIBADD) $(AM_V_at)$(RANLIB) libfile.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/file-process/file_mempool.h0000644000000000000000000000701112260565732015733 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** This mempool implementation has very efficient alloc/free operations. ** In addition, it provides thread-safe alloc/free for one allocation/free ** thread and one release thread. ** One more bonus: Double free detection is also added into this library ** ** NOTES ** 5.25.13 - Initial Source Code. Hcao ** ** This is a thread safe version of memory pool for one writer and one reader thread */ #ifndef __FILE_MEMPOOL_H__ #define __FILE_MEMPOOL_H__ #include "sf_types.h" #include "circular_buffer.h" #define SAFE_MEM_SUCCESS 0 #define SAFE_MEM_FAIL -1 typedef struct _SafeMemPool { void **datapool; /* memory buffer */ uint64_t total; CircularBuffer* free_list; CircularBuffer* released_list; size_t obj_size; } SafeMemPool; /* Initialize mempool * * Args: * SafeMemPool: pointer to a SafeMemPool struct * uint64_t num_objects: number of objects * size_t obj_size: size of object * * Return: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ int safe_mempool_init(SafeMemPool *mempool, uint64_t num_objects, size_t obj_size); /* Free mempool memory objects * * Args: * SafeMemPool: pointer to a SafeMemPool struct * * Return: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ int safe_mempool_destroy(SafeMemPool *mempool); /* * Allocate a new object from the SafeMemPool * Memory block will not be zeroed for performance * * Args: * SafeMemPool: pointer to a SafeMemPool struct * * Returns: a pointer to the SafeMemPool object on success, NULL on failure */ void *safe_mempool_alloc(SafeMemPool *mempool); /* * Free a new object from the SafeMemPool * This must be called by the same thread calling * safe_mempool_alloc() * * Args: * SafeMemPool: pointer to a SafeMemPool struct * void *obj : memory object * * Return: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ int safe_mempool_free(SafeMemPool *mempool, void *obj); /* * Release a new object from the SafeMemPool * This can be called by a different thread calling * safe_mempool_alloc() * * Args: * SafeMemPool: pointer to a SafeMemPool struct * void *obj : memory object * * Return: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ int safe_mempool_release(SafeMemPool *mempool, void *obj); /* Returns number of elements allocated in current buffer*/ uint64_t safe_mempool_allocated(SafeMemPool *mempool); /* Returns number of elements freed in current buffer*/ uint64_t safe_mempool_freed(SafeMemPool *mempool); /* Returns number of elements released in current buffer*/ uint64_t safe_mempool_released(SafeMemPool *mempool); #endif snort-2.9.6.0/src/file-process/file_mempool.c0000644000000000000000000002022712260565732015732 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** This mempool implementation has very efficient alloc/free operations. ** In addition, it provides thread-safe alloc/free for one allocation/free ** thread and one release thread. One more bonus: Double free detection is ** also added into this library ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.13 - Initial Source Code. Hui Cao ** ** A */ #include #include #include #include "file_mempool.h" #include "util.h" /*This magic is used for double free detection*/ #define FREE_MAGIC 0x2525252525252525 typedef uint64_t MagicType; #ifdef DEBUG static inline void safe_mempool_verify(SafeMemPool *mempool) { uint64_t free_size; uint64_t release_size; free_size = cbuffer_used(mempool->free_list); release_size = cbuffer_used(mempool->released_list); if (free_size > cbuffer_size(mempool->free_list)) { ErrorMessage("%s(%d) safe_mempool: failed to verify free list!\n", __FILE__, __LINE__ ); } if (release_size > cbuffer_size(mempool->released_list)) { ErrorMessage("%s(%d) safe_mempool: failed to verify release list!\n", __FILE__, __LINE__ ); } /* The free mempool and size of release mempool should be smaller than * or equal to the size of mempool */ if (free_size + release_size > mempool->total) { ErrorMessage("%s(%d) safe_mempool: failed to verify mempool size!\n", __FILE__, __LINE__ ); } } #endif static inline void safe_mempool_free_pools(SafeMemPool *mempool) { if (mempool == NULL) return; if (mempool->datapool != NULL) { free(mempool->datapool); mempool->datapool = NULL; } cbuffer_free(mempool->free_list); cbuffer_free(mempool->released_list); } /* Function: int safe_mempool_init(SafeMemPool *SafeMemPool, * PoolCount num_objects, size_t obj_size) * * Purpose: initialize a SafeMemPool object and allocate memory for it * Args: * SafeMemPool - pointer to a SafeMemPool struct * num_objects - number of items in this pool * obj_size - size of the items * * Returns: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ int safe_mempool_init(SafeMemPool *mempool, uint64_t num_objects, size_t obj_size) { unsigned int i; if ((mempool == NULL) || (num_objects < 1) || (obj_size < 1)) return SAFE_MEM_FAIL; mempool->obj_size = obj_size; /* this is the basis pool that represents all the *data pointers * in the list */ mempool->datapool = calloc(num_objects, obj_size); if(mempool->datapool == NULL) { ErrorMessage("%s(%d) safe_mempool_init(): Failed to init datapool\n", __FILE__, __LINE__); safe_mempool_free_pools(mempool); return SAFE_MEM_FAIL; } /* sets up the memory list */ mempool->free_list = cbuffer_init(num_objects); if (!mempool->free_list) { ErrorMessage("%s(%d) safe_mempool_init(): Failed to init free list\n", __FILE__, __LINE__); safe_mempool_free_pools(mempool); return SAFE_MEM_FAIL; } mempool->released_list = cbuffer_init(num_objects); if (!mempool->released_list) { ErrorMessage("%s(%d) safe_mempool_init(): " "Failed to init release list\n", __FILE__, __LINE__); safe_mempool_free_pools(mempool); return SAFE_MEM_FAIL; } for(i=0; idatapool) + (i * mempool->obj_size); if (cbuffer_write(mempool->free_list, data)) { ErrorMessage("%s(%d) safe_mempool_init(): " "Failed to add to free list\n", __FILE__, __LINE__); safe_mempool_free_pools(mempool); return SAFE_MEM_FAIL; } *(MagicType *)data = FREE_MAGIC; mempool->total++; } return SAFE_MEM_SUCCESS; } /* * Destroy a set of SafeMemPool objects * * Args: * SafeMemPool: pointer to a SafeMemPool struct * * Return: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ int safe_mempool_destroy(SafeMemPool *mempool) { if(mempool == NULL) return SAFE_MEM_FAIL; safe_mempool_free_pools(mempool); return SAFE_MEM_SUCCESS; } /* * Allocate a new object from the SafeMemPool * * Args: * SafeMemPool: pointer to a SafeMemPool struct * * Returns: a pointer to the SafeMemPool object on success, NULL on failure */ void *safe_mempool_alloc(SafeMemPool *mempool) { void *b = NULL; if(mempool == NULL) { return NULL; } if(cbuffer_read(mempool->free_list, &b)) { if(cbuffer_read(mempool->released_list, &b)) { return NULL; } } if (*(MagicType *)b != FREE_MAGIC) { ErrorMessage("%s(%d) safe_mempool_alloc(): Allocation errors! \n", __FILE__, __LINE__); } DEBUG_WRAP(safe_mempool_verify(mempool);); return b; } /* * Free a new object from the buffer * We use circular buffer to synchronize one reader and one writer * * Args: * SafeMemPool: pointer to a circular buffer struct * void *obj : memory object * * Return: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ static inline int _safe__mempool_remove(CircularBuffer *cb, void *obj) { if (obj == NULL) return SAFE_MEM_FAIL; if(cbuffer_write(cb, obj)) { return SAFE_MEM_FAIL; } if (*(MagicType *)obj == FREE_MAGIC) { DEBUG_WRAP(ErrorMessage("%s(%d) safe_mempool_remove(): Double free! \n", __FILE__, __LINE__);); return SAFE_MEM_FAIL; } *(MagicType *)obj = FREE_MAGIC; return SAFE_MEM_SUCCESS; } /* * Free a new object from the SafeMemPool * * Args: * SafeMemPool: pointer to a SafeMemPool struct * void *obj : memory object * * Return: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ int safe_mempool_free(SafeMemPool *mempool, void *obj) { int ret; assert(mempool); ret = _safe__mempool_remove(mempool->free_list, obj); DEBUG_WRAP(safe_mempool_verify(mempool);); return ret; } /* * Release a new object from the SafeMemPool * This can be called by a different thread calling * safe_mempool_alloc() * * * Args: * SafeMemPool: pointer to a SafeMemPool struct * void *obj : memory object * * Return: * SAFE_MEM_SUCCESS * SAFE_MEM_FAIL */ int safe_mempool_release(SafeMemPool *mempool, void *obj) { int ret; if (mempool == NULL) return SAFE_MEM_FAIL; /*A writer that might from different thread*/ ret = _safe__mempool_remove(mempool->released_list, obj); DEBUG_WRAP(safe_mempool_verify(mempool);); return ret; } /* Returns number of elements allocated in current buffer*/ uint64_t safe_mempool_allocated(SafeMemPool *mempool) { uint64_t total_freed = safe_mempool_released(mempool) + safe_mempool_freed(mempool); return (mempool->total - total_freed); } /* Returns number of elements freed in current buffer*/ uint64_t safe_mempool_freed(SafeMemPool *mempool) { return (cbuffer_used(mempool->free_list)); } /* Returns number of elements released in current buffer*/ uint64_t safe_mempool_released(SafeMemPool *mempool) { return (cbuffer_used(mempool->released_list)); } snort-2.9.6.0/src/file-process/circular_buffer.h0000644000000000000000000000657612260565732016440 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Circular buffer is thread safe for one writer and one reader thread ** ** This implementaton is inspired by one slot open approach. ** See http://en.wikipedia.org/wiki/Circular_buffer ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.13 - Initial Source Code. Hcao */ #ifndef __CIRCULAR_BUFFER_H__ #define __CIRCULAR_BUFFER_H__ #define CB_SUCCESS 0 #define CB_FAIL -1 /* Opaque buffer element type. This would be defined by the application. */ typedef void * ElemType; struct _CircularBuffer; typedef struct _CircularBuffer CircularBuffer; /* * Initialize buffer based on number of elements * * Args: * uint64_t size: number of elements * * Return: * CircularBuffer *: pointer to the buffer * NULL: failed * */ CircularBuffer * cbuffer_init(uint64_t size); /* Release all memory used*/ void cbuffer_free(CircularBuffer *cb); /* * Check whether buffer is full * * Return: * 1: full * 0: not full */ int cbuffer_is_full(CircularBuffer *cb); /* * Check whether buffer is empty * * Return: * 1: empty * 0: not empty */ int cbuffer_is_empty(CircularBuffer *cb); /* Returns number of elements in use*/ uint64_t cbuffer_used(CircularBuffer *cb); /* Returns number of free elements*/ uint64_t cbuffer_available(CircularBuffer *cb); /* Returns total number of elements*/ uint64_t cbuffer_size(CircularBuffer *cb); /* * Add one element to the buffer * * Args: * CircularBuffer *: buffer * ElemType elem: the element to be added * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_write(CircularBuffer *cb, const ElemType elem); /* * Read one element from the buffer and remove it from buffer * * Args: * CircularBuffer *: buffer * ElemType *elem: the element pointer to be stored * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_read(CircularBuffer *cb, ElemType *elem); /* * Read one element from the buffer and no change on buffer * * Args: * CircularBuffer *: buffer * ElemType *elem: the element pointer to be stored * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_peek(CircularBuffer *cb, ElemType *elem); /* Returns total number of reads*/ uint64_t cbuffer_num_reads(CircularBuffer *cb); /* Returns total number of writes*/ uint64_t cbuffer_num_writes(CircularBuffer *cb); /* Returns total number of writer overruns*/ uint64_t cbuffer_num_over_runs(CircularBuffer *cb); /* Returns total number of reader overruns*/ uint64_t cbuffer_num_under_runs(CircularBuffer *cb); #endif snort-2.9.6.0/src/file-process/circular_buffer.c0000644000000000000000000001205512260565732016420 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** ** Circular buffer is thread safe for one writer and one reader thread ** ** This implementaton is inspired by one slot open approach. ** See http://en.wikipedia.org/wiki/Circular_buffer ** ** 5.25.13 - Initial Source Code. Hui Cao */ #include "sf_types.h" #include "circular_buffer.h" #include #include /* Circular buffer object */ struct _CircularBuffer{ uint64_t size; /* maximum number of elements */ uint64_t start; /* index of oldest element, reader update only */ uint64_t end; /* index to write new element, writer update only*/ uint64_t under_run; uint64_t over_run; ElemType *elems; /* vector of elements */ uint64_t total_write; uint64_t total_read; }; /* This approach adds one bit to end and start pointers */ CircularBuffer * cbuffer_init(uint64_t size) { CircularBuffer* cb = calloc(1, sizeof(*cb)); if ( !cb ) return NULL; cb->size = size + 1; cb->elems = (ElemType *)calloc(cb->size, sizeof(ElemType)); if (!cb->elems) { free(cb); return NULL; } return cb; } void cbuffer_free(CircularBuffer *cb) { if(cb && cb->elems) { free(cb->elems); cb->elems = NULL; } free(cb); } /* We use mirror flag to detection full or empty efficiently*/ int cbuffer_is_full(CircularBuffer *cb) { uint64_t next = cb->end + 1; if ( next == cb->size ) next = 0; return (next == cb->start); } /* We use mirror flag to detection full or empty efficiently*/ int cbuffer_is_empty(CircularBuffer *cb) { return (cb->end == cb->start); } /* Returns number of elements in use*/ uint64_t cbuffer_used(CircularBuffer *cb) { /* cb->end < cb->start means passing the end of buffer */ if (cb->end < cb->start) { return (cb->size + cb->end - cb->start); } else { return (cb->end - cb->start); } } /* Returns number of free elements*/ uint64_t cbuffer_available(CircularBuffer *cb) { return (cbuffer_size(cb) - cbuffer_used(cb)); } /* Returns total number of elements*/ uint64_t cbuffer_size(CircularBuffer *cb) { return (cb->size - 1); } /* * Add one element to the buffer, * * Args: * CircularBuffer *: buffer * ElemType elem: the element to be added * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_write(CircularBuffer *cb, const ElemType elem) { uint64_t w = cb->end; if ( cbuffer_is_full (cb)) /* full, return error */ { cb->over_run++; return CB_FAIL; } cb->elems[w++] = elem; if ( w == cb->size ) w = 0; cb->end = w; cb->total_write++; return CB_SUCCESS; } /* * Read one element from the buffer and remove it from buffer, * * Args: * CircularBuffer *: buffer * ElemType *elem: the element pointer to be stored * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_read(CircularBuffer *cb, ElemType *elem) { uint64_t r = cb->start; if (cbuffer_is_empty(cb)) /* Empty, return error */ { cb->under_run++; return CB_FAIL; } *elem = cb->elems[r++]; if ( r == cb->size ) r = 0; cb->start = r; cb->total_read++; return CB_SUCCESS; } /* * Read one element from the buffer and no change on buffer * * Args: * CircularBuffer *: buffer * ElemType *elem: the element pointer to be stored * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_peek(CircularBuffer *cb, ElemType *elem) { if (cbuffer_is_empty(cb)) /* Empty, return error */ return CB_FAIL; *elem = cb->elems[cb->start]; return CB_SUCCESS; } /* Returns total number of reads*/ uint64_t cbuffer_num_reads(CircularBuffer *cb) { return (cb->total_read); } /* Returns total number of writes*/ uint64_t cbuffer_num_writes(CircularBuffer *cb) { return (cb->total_write); } /* Returns total number of writer overruns*/ uint64_t cbuffer_num_over_runs(CircularBuffer *cb) { return (cb->over_run); } /* Returns total number of reader overruns*/ uint64_t cbuffer_num_under_runs(CircularBuffer *cb) { return (cb->under_run); } snort-2.9.6.0/src/file-process/file_stats.h0000644000000000000000000000446612260565732015434 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.13 - Initial Source Code. Hcao */ #ifndef __FILE_STATS_H__ #define __FILE_STATS_H__ #ifdef TARGET_BASED #include "sftarget_protocol_reference.h" #include "sftarget_reader.h" #endif #include "file_config.h" #include "file_api.h" #include #include typedef struct _File_Stats { uint64_t files_total; uint64_t files_processed[FILE_ID_MAX + 1][2]; uint64_t signatures_processed[FILE_ID_MAX + 1][2]; uint64_t verdicts_type[FILE_VERDICT_MAX]; uint64_t verdicts_signature[FILE_VERDICT_MAX]; #ifdef TARGET_BASED uint64_t files_by_proto[MAX_PROTOCOL_ORDINAL + 1]; uint64_t signatures_by_proto[MAX_PROTOCOL_ORDINAL + 1]; #endif uint64_t data_processed[FILE_ID_MAX + 1][2]; uint64_t file_data_total; uint64_t files_sig_depth; } FileStats; extern FileStats file_stats; #ifdef REG_TEST #define FILE_REG_DEBUG_WRAP(code) code #else #ifdef DEBUG_MSGS #define FILE_REG_DEBUG_WRAP(code) if (DEBUG_FILE & GetDebugLevel()){code} #else #define FILE_REG_DEBUG_WRAP(code) #endif #endif #define FILE_DEBUG_MSGS(msg) DEBUG_WRAP(DebugMessage(DEBUG_FILE, msg);) #if defined(DEBUG_MSGS) || defined (REG_TEST) void printFileContext (FileContext* context); void DumpHex(FILE *fp, const uint8_t *data, unsigned int len); #endif /* * Print out file statistics */ void print_file_stats(int exiting); #endif snort-2.9.6.0/src/file-process/file_stats.c0000644000000000000000000003072012260565732015417 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.13 - Initial Source Code. Hui Cao */ #ifdef HAVE_CONFIG_H #include #endif #include "sf_types.h" #include #include #include "file_config.h" #include "file_stats.h" #include "file_capture.h" #include "snort.h" /* for extern SnortConfig *snort_conf */ FileStats file_stats; #if defined(DEBUG_MSGS) || defined (REG_TEST) #define MAX_CONTEXT_INFO_LEN 1024 void printFileContext (FileContext* context) { char buf[MAX_CONTEXT_INFO_LEN + 1]; int unused; char *cur = buf; int used = 0; if (!context) { printf("File context is NULL.\n"); return; } unused = sizeof(buf) - 1; used = snprintf(cur, unused, "File name: "); if (used < 0) { printf("Fail to output file context\n"); return; } unused -= used; cur += used; if ((context->file_name_size > 0) && (unused > (int) context->file_name_size)) { strncpy(cur, (char *)context->file_name, context->file_name_size ); unused -= context->file_name_size; cur += context->file_name_size; } if (unused > 0) { used = snprintf(cur, unused, "\nFile type: %s(%d)", file_type_name(context->file_config, context->file_type_id), context->file_type_id); unused -= used; cur += used; } if (unused > 0) { used = snprintf(cur, unused, "\nFile size: %u", (unsigned int)context->file_size); unused -= used; cur += used; } if (unused > 0) { used = snprintf(cur, unused, "\nProcessed size: %u\n", (unsigned int)context->processed_bytes); unused -= used; cur += used; } buf[sizeof(buf) - 1] = '\0'; printf("%s", buf); } void DumpHex(FILE *fp, const uint8_t *data, unsigned len) { char str[18]; unsigned i; unsigned pos; char c; FileConfig *file_config = (FileConfig *)(snort_conf->file_config); if (file_config->show_data_depth < (int64_t)len) len = file_config->show_data_depth; fprintf(fp,"Show length: %d \n", len); for (i=0, pos=0; ifile_config, i); if (type_name && (file_stats.files_processed[i][0] || file_stats.files_processed[i][1] )) { LogMessage("%12s(%3d) "FMTu64("-10")" "FMTu64("-12")" "FMTu64("-10")" "FMTu64("-10")" \n", type_name, i, file_stats.files_processed[i][0], file_stats.data_processed[i][0], file_stats.files_processed[i][1], file_stats.data_processed[i][1]); processed_total[0]+= file_stats.files_processed[i][0]; processed_total[1]+= file_stats.files_processed[i][1]; processed_data_total[0]+= file_stats.data_processed[i][0]; processed_data_total[1]+= file_stats.data_processed[i][1]; } } LogMessage(" Total "FMTu64("-10")" "FMTu64("-12")" "FMTu64("-10")" "FMTu64("-10")" \n", processed_total[0], processed_data_total[0], processed_total[1], processed_data_total[1]); LogMessage("\nFile signature stats:\n"); LogMessage(" Type Download Upload \n"); processed_total[0] = 0; processed_total[1] = 0; for (i = 0; i < FILE_ID_MAX; i++) { char* type_name = file_type_name(snort_conf->file_config, i); if (type_name && (file_stats.signatures_processed[i][0] || file_stats.signatures_processed[i][1] )) { LogMessage("%12s(%3d) "FMTu64("-10")" "FMTu64("-10")" \n", type_name, i, file_stats.signatures_processed[i][0], file_stats.signatures_processed[i][1]); processed_total[0]+= file_stats.signatures_processed[i][0]; processed_total[1]+= file_stats.signatures_processed[i][1]; } } LogMessage(" Total "FMTu64("-10")" "FMTu64("-10")" \n", processed_total[0], processed_total[1]); LogMessage("\nFile type verdicts:\n"); verdicts_total = 0; for (i = 0; i < FILE_VERDICT_MAX; i++) { verdicts_total+=file_stats.verdicts_type[i]; switch (i) { case FILE_VERDICT_UNKNOWN: LogMessage(" %12s: "FMTu64("-10")" \n", "UNKNOWN", file_stats.verdicts_type[i]); break; case FILE_VERDICT_LOG: LogMessage(" %12s: "FMTu64("-10")" \n", "LOG", file_stats.verdicts_type[i]); break; case FILE_VERDICT_STOP: LogMessage(" %12s: "FMTu64("-10")" \n", "STOP", file_stats.verdicts_type[i]); break; case FILE_VERDICT_BLOCK: LogMessage(" %12s: "FMTu64("-10")" \n", "BLOCK", file_stats.verdicts_type[i]); break; case FILE_VERDICT_REJECT: LogMessage(" %12s: "FMTu64("-10")" \n", "REJECT", file_stats.verdicts_type[i]); break; case FILE_VERDICT_PENDING: LogMessage(" %12s: "FMTu64("-10")" \n", "PENDING", file_stats.verdicts_type[i]); break; case FILE_VERDICT_STOP_CAPTURE: LogMessage(" %12s: "FMTu64("-10")" \n", "STOP CAPTURE", file_stats.verdicts_type[i]); break; default: break; } } LogMessage(" %12s: "FMTu64("-10")" \n", "Total",verdicts_total); LogMessage("\nFile signature verdicts:\n"); verdicts_total = 0; for (i = 0; i < FILE_VERDICT_MAX; i++) { verdicts_total+=file_stats.verdicts_signature[i]; switch (i) { case FILE_VERDICT_UNKNOWN: LogMessage(" %12s: "FMTu64("-10")" \n", "UNKNOWN", file_stats.verdicts_signature[i]); break; case FILE_VERDICT_LOG: LogMessage(" %12s: "FMTu64("-10")" \n", "LOG", file_stats.verdicts_signature[i]); break; case FILE_VERDICT_STOP: LogMessage(" %12s: "FMTu64("-10")" \n", "STOP", file_stats.verdicts_signature[i]); break; case FILE_VERDICT_BLOCK: LogMessage(" %12s: "FMTu64("-10")" \n", "BLOCK", file_stats.verdicts_signature[i]); break; case FILE_VERDICT_REJECT: LogMessage(" %12s: "FMTu64("-10")" \n", "REJECT", file_stats.verdicts_signature[i]); break; case FILE_VERDICT_PENDING: LogMessage(" %12s: "FMTu64("-10")" \n", "PENDING", file_stats.verdicts_signature[i]); break; case FILE_VERDICT_STOP_CAPTURE: LogMessage(" %12s: "FMTu64("-10")" \n", "STOP CAPTURE", file_stats.verdicts_signature[i]); break; default: break; } } LogMessage(" %12s: "FMTu64("-10")" \n", "Total",verdicts_total); #ifdef TARGET_BASED if (IsAdaptiveConfigured(getRuntimePolicy())) { LogMessage("\nFiles processed by protocol IDs:\n"); for (i = 0; i < MAX_PROTOCOL_ORDINAL; i++) { if (file_stats.files_by_proto[i]) { LogMessage(" %12d: "FMTu64("-10")" \n", i ,file_stats.files_by_proto[i]); } } LogMessage("\nFile signatures processed by protocol IDs:\n"); for (i = 0; i < MAX_PROTOCOL_ORDINAL; i++) { if (file_stats.signatures_by_proto[i]) { LogMessage(" %12d: "FMTu64("-10")" \n", i ,file_stats.signatures_by_proto[i]); } } } #endif LogMessage("\n"); LogMessage("Total files processed: "FMTu64("-10")" \n", file_stats.files_total); LogMessage("Total files data processed: "FMTu64("-10")"bytes \n", file_stats.file_data_total); LogMessage("Total files buffered: "FMTu64("-10")" \n", file_capture_stats.files_buffered_total); LogMessage("Total files released: "FMTu64("-10")" \n", file_capture_stats.files_released_total); LogMessage("Total files freed: "FMTu64("-10")" \n", file_capture_stats.files_freed_total); LogMessage("Total files captured: "FMTu64("-10")" \n", file_capture_stats.files_captured_total); LogMessage("Total files within one packet: "FMTu64("-10")" \n", file_capture_stats.file_within_packet); LogMessage("Total buffers allocated: "FMTu64("-10")" \n", file_capture_stats.file_buffers_allocated_total); LogMessage("Total buffers freed: "FMTu64("-10")" \n", file_capture_stats.file_buffers_freed_total); LogMessage("Total buffers released: "FMTu64("-10")" \n", file_capture_stats.file_buffers_released_total); LogMessage("Maximum file buffers used: "FMTu64("-10")" \n", file_capture_stats.file_buffers_used_max); LogMessage("Total buffers free errors: "FMTu64("-10")" \n", file_capture_stats.file_buffers_free_errors); LogMessage("Total buffers release errors: "FMTu64("-10")" \n", file_capture_stats.file_buffers_release_errors); LogMessage("Total memcap failures: "FMTu64("-10")" \n", file_capture_stats.file_memcap_failures_total); LogMessage("Total memcap failures at reserve: "FMTu64("-10")" \n", file_capture_stats.file_memcap_failures_reserve); LogMessage("Total reserve failures: "FMTu64("-10")" \n", file_capture_stats.file_reserve_failures); LogMessage("Total file capture size min: "FMTu64("-10")" \n", file_capture_stats.file_size_min); LogMessage("Total file capture size max: "FMTu64("-10")" \n", file_capture_stats.file_size_max); LogMessage("Total capture max before reserve: "FMTu64("-10")" \n", file_capture_stats.file_size_exceeded); LogMessage("Total file signature max: "FMTu64("-10")" \n", file_stats.files_sig_depth); file_capture_mem_usage(); } snort-2.9.6.0/src/file-process/file_capture.h0000644000000000000000000001143012260565732015726 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #ifndef _FILE_CAPTURE_H_ #define _FILE_CAPTURE_H_ #include "file_api.h" #include "file_lib.h" struct _FileCaptureInfo { uint32_t length; bool reserved; struct _FileCaptureInfo *last; /* last block of file data */ struct _FileCaptureInfo *next; /* next block of file data */ uint64_t file_size; /*file_size*/ }; typedef struct _File_Capture_Stats { uint64_t files_buffered_total; uint64_t files_released_total; uint64_t files_freed_total; uint64_t files_captured_total; uint64_t file_memcap_failures_total; uint64_t file_memcap_failures_reserve; /*This happens during reserve*/ uint64_t file_reserve_failures; /*This happens during reserve*/ uint64_t file_size_exceeded; uint64_t file_size_min; /*This happens during reserve*/ uint64_t file_size_max; /*This happens during reserve*/ uint64_t file_within_packet; uint64_t file_buffers_used_max; /* maximum buffers used simultaneously*/ uint64_t file_buffers_allocated_total; uint64_t file_buffers_freed_total; uint64_t file_buffers_released_total; uint64_t file_buffers_free_errors; uint64_t file_buffers_release_errors; } File_Capture_Stats; extern File_Capture_Stats file_capture_stats; /* * Initialize the file memory pool * * Arguments: * int64_t max_file_mem: memcap in bytes * int64_t block_size: file block size * * Returns: NONE */ void file_capture_init_mempool(int64_t max_file_mem, int64_t block_size); /* * Capture file data to local buffer * This is the main function call to enable file capture * * Arguments: * FileContext* context: current file context * uint8_t *file_data: current file data * int data_size: current file data size * FilePosition position: position of file data * * Returns: * 0: successful * 1: fail to capture the file or file capture is disabled */ int file_capture_process( FileContext* context, uint8_t* file_data, int data_size, FilePosition position); /* * Stop file capture, memory resource will be released if not reserved * * Returns: NONE */ void file_capture_stop( FileContext* context); /* * Preserve the file in memory until it is released * * Arguments: * void *ssnptr: session pointer * FileCaptureInfo **file_mem: the pointer to store the memory block * that stores file and its metadata. * It will set NULL if no memory or fail to store * * Returns: * FileCaptureState: * FILE_CAPTURE_SUCCESS = 0, * FILE_CAPTURE_MIN, * FILE_CAPTURE_MAX, * FILE_CAPTURE_MEMCAP, * FILE_CAPTURE_FAIL */ FileCaptureState file_capture_reserve(void *ssnptr, FileCaptureInfo **file_mem); /* * Get the file that is reserved in memory * * Arguments: * FileCaptureInfo *file_mem: the memory block working on * uint8_t **buff: address to store buffer address * int *size: address to store size of file * * Returns: * the next memory block * NULL: end of file or fail to get file */ void* file_capture_read(FileCaptureInfo *file_mem, uint8_t **buff, int *size); /* * Get the file size captured in the file buffer * * Arguments: * FileCaptureInfo *file_mem: the first memory block of file buffer * * Returns: * the size of file * 0: no memory or fail to get file */ size_t file_capture_size(FileCaptureInfo *file_mem); /* * Release the file that is reserved in memory, this function might be * called in a different thread. * * Arguments: * FileCaptureInfo *data: the memory block that stores file and its metadata */ void file_capture_release(FileCaptureInfo *data); /*Log file capture mempool usage*/ void file_capture_mem_usage(void); /* * Exit file capture, release all file capture memory etc, * this must be called when snort exits */ void file_caputure_close(void); #endif snort-2.9.6.0/src/file-process/file_capture.c0000644000000000000000000004142212260565732015725 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.05.2013 - Initial Source Code. Hcao */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "file_capture.h" #include "file_mempool.h" #include "util.h" #include #include "file_sha256.h" #include "snort.h" #include "stream_api.h" #include "file_config.h" #include "file_stats.h" #include "file_service.h" #include #include #include #include SafeMemPool *file_mempool = NULL; File_Capture_Stats file_capture_stats; /* * Verify file capture information and file context information matched * This is used for debug purpose */ #ifdef DEBUG #include "file_sha256.h" static void verify_file_capture_info(FileContext* context, FileCaptureInfo *fileInfo) { /* file capture length should be one of two possible values */ if (context->processed_bytes) { if ((fileInfo->file_size != context->processed_bytes) && (fileInfo->file_size + context->current_data_len != context->processed_bytes)) { FILE_DEBUG_MSGS("File capture size failed w.r.t processed size!\n"); } } else { if ((fileInfo->file_size != context->file_size) && (fileInfo->file_size + context->current_data_len != context->file_size)) { FILE_DEBUG_MSGS("File capture size failed w.r.t final file size!\n"); } } } static void verifiy_file_capture(FileContext* context, FileCaptureInfo *fileInfo) { SHA256CONTEXT sha_ctx; uint8_t *buff; int size; FileCaptureInfo *file_mem = fileInfo; uint8_t sha256[SHA256_HASH_SIZE + 1]; int i; memset(&sha_ctx, 0, sizeof(sha_ctx)); /*Calculator the SHA*/ SHA256INIT(&sha_ctx); while (file_mem) { file_mem = file_capture_read(file_mem, &buff, &size); SHA256UPDATE(&sha_ctx, buff, size); } SHA256FINAL(sha256, &sha_ctx); for (i = 0; i < SHA256_HASH_SIZE; i++) { if (sha256[i] != context->sha256[i]) { FILE_DEBUG_MSGS("File capture buffer is wrong!\n"); break; } } } #endif /* * Initialize the file memory pool * * Returns: * void *: pointer to mempool * NULL : fail to initialize file mempool */ static void* _init_file_mempool(int64_t max_file_mem, int64_t block_size) { int max_files; SafeMemPool *file_mempool; int64_t max_file_mem_in_bytes; /*Convert megabytes to bytes*/ max_file_mem_in_bytes = max_file_mem * 1024 * 1024; if (block_size <= 0) return NULL; if (block_size & 7) block_size += (8 - (block_size & 7)); max_files = max_file_mem_in_bytes / block_size ; file_mempool = (SafeMemPool *)calloc(1, sizeof(SafeMemPool)); if ((!file_mempool)|| (safe_mempool_init(file_mempool, max_files, block_size) != 0)) { FatalError( "File capture: Could not allocate file buffer mempool.\n"); } return file_mempool; } /* * Initialize the file memory pool * * Arguments: * int64_t max_file_mem: memcap in megabytes * int64_t block_size: file block size (metadata size excluded) * * Returns: NONE */ void file_capture_init_mempool(int64_t max_file_mem, int64_t block_size) { int64_t metadata_size = sizeof (FileCaptureInfo); file_mempool = _init_file_mempool(max_file_mem, block_size + metadata_size); } /* Free file buffer list*/ static inline void _free_file_buffer(FileCaptureInfo *fileInfo) { file_capture_stats.files_freed_total++; while (fileInfo) { if (safe_mempool_free(file_mempool, fileInfo) != SAFE_MEM_SUCCESS) file_capture_stats.file_buffers_free_errors++; fileInfo = fileInfo->next; file_capture_stats.file_buffers_freed_total++; } } /* Release file buffer list*/ static inline void _release_file_buffer(FileCaptureInfo *fileInfo) { file_capture_stats.files_released_total++; while (fileInfo) { if (safe_mempool_release(file_mempool, fileInfo) != SAFE_MEM_SUCCESS) file_capture_stats.file_buffers_release_errors++; fileInfo = fileInfo->next; file_capture_stats.file_buffers_released_total++; } } /* * Stop file capture, memory resource will be released if not reserved * * Returns: NONE */ void file_capture_stop( FileContext* context) { FileCaptureInfo *fileInfo = context->file_capture; if (fileInfo) { /*free mempool*/ FILE_DEBUG_MSGS("Stop file capture!\n"); if(!fileInfo->reserved) { _free_file_buffer(fileInfo); } context->file_capture = NULL; } context->file_capture_enabled = false; } /* * Create file buffer in file mempool * * Args: * SafeMemPool *file_mempool: file mempool * FileContext* context: file context * * Returns: * FileCaptureInfo *: memory block that starts with file capture information */ static inline FileCaptureInfo * _create_file_buffer(SafeMemPool *file_mempool) { FileCaptureInfo *fileInfo; uint64_t num_files_queued; fileInfo = (FileCaptureInfo*)safe_mempool_alloc(file_mempool); if(fileInfo == NULL) { FILE_DEBUG_MSGS("Failed to get file capture memory!\n"); file_capture_stats.file_memcap_failures_total++; return NULL; } file_capture_stats.file_buffers_allocated_total++; fileInfo->length = 0; fileInfo->reserved = false; fileInfo->next = NULL; /*Only one block initially*/ fileInfo->last = fileInfo; fileInfo->file_size = 0; num_files_queued = safe_mempool_allocated(file_mempool); if (file_capture_stats.file_buffers_used_max < num_files_queued) file_capture_stats.file_buffers_used_max = num_files_queued; return fileInfo; } /* * Save file to the buffer * If file needs to be extracted, buffer will be reserved * If file buffer isn't sufficient, need to add another buffer. * * Returns: * 0: successful or file capture is disabled * 1: fail to capture the file */ static inline int _save_to_file_buffer(SafeMemPool *file_mempool, FileContext* context, uint8_t* file_data, int data_size, int64_t max_size) { FileCaptureInfo *fileInfo = (FileCaptureInfo *) context->file_capture; FileCaptureInfo *lastBlock = fileInfo->last; int64_t available_bytes; FileConfig *file_config = (FileConfig *)(snort_conf->file_config); DEBUG_WRAP(verify_file_capture_info(context, fileInfo);); if ( data_size + (signed)fileInfo->file_size > max_size) { FILE_DEBUG_MSGS("Exceeding max file capture size!\n"); file_capture_stats.file_size_exceeded++; context->file_state.capture_state = FILE_CAPTURE_MAX; return -1; } /* Check whether current file block can hold file data*/ available_bytes = file_config->file_capture_block_size - lastBlock->length; if ( data_size > available_bytes) { FileCaptureInfo *new_block; uint8_t* file_current = file_data; uint8_t* file_end = file_data + data_size; /*can't hold all, use current block first*/ memcpy((uint8_t *)lastBlock + lastBlock->length + sizeof (*lastBlock), file_current, available_bytes ); lastBlock->length = file_config->file_capture_block_size; file_current += available_bytes; /* We can support any file capture block size */ while (1) { /*get another block*/ new_block = (FileCaptureInfo *)_create_file_buffer(file_mempool); if(new_block == NULL) { context->file_state.capture_state = FILE_CAPTURE_MEMCAP; return -1; } fileInfo->last->next = new_block; fileInfo->last = new_block; /*Save data to the new block*/ if (file_current + file_config->file_capture_block_size < file_end) { memcpy((uint8_t *)fileInfo->last + sizeof(*new_block), file_current, file_config->file_capture_block_size); new_block->length = file_config->file_capture_block_size; file_current += file_config->file_capture_block_size; } else { memcpy((uint8_t *)fileInfo->last + sizeof(*new_block), file_current, file_end - file_current); new_block->length = file_end - file_current; break; } } } else { memcpy((uint8_t *)lastBlock + lastBlock->length + sizeof(*lastBlock), file_data, data_size); lastBlock->length += data_size; } fileInfo->file_size += data_size; DEBUG_WRAP(verify_file_capture_info(context, fileInfo);) return 0; } /* * Save files to the local buffer first for files transferred * by multiple reassembled packets. For files within a packet, * simply using the packet buffer. * If file needs to be extracted, buffer will be reserved * * Arguments: * FileContext* context: current file context * uint8_t *file_data: current file data * int data_size: current file data size * FilePosition position: position of file data * Returns: * 0: successful * 1: fail to capture the file or file capture is disabled */ int file_capture_process( FileContext* context, uint8_t* file_data, int data_size, FilePosition position ) { FileCaptureInfo *fileInfo = (FileCaptureInfo *) context->file_capture; FileConfig *file_config = (FileConfig *)(snort_conf->file_config); context->current_data = file_data; context->current_data_len = data_size; switch (position) { case SNORT_FILE_FULL: file_capture_stats.file_within_packet++; break; case SNORT_FILE_END: break; default: /* For File position is either SNORT_FILE_START * or SNORT_FILE_MIDDLE, the file is larger than one packet, * we need to store them into buffer. */ if(!context->file_capture) { fileInfo = _create_file_buffer(file_mempool); if (!fileInfo) { FILE_DEBUG_MSGS("Can't get file capture memory!\n"); context->file_state.capture_state = FILE_CAPTURE_MEMCAP; return -1; } file_capture_stats.files_buffered_total++; context->file_capture = fileInfo; } if (!fileInfo) { return -1; } if (_save_to_file_buffer(file_mempool, context, file_data, data_size, file_config->file_capture_max_size)) { FILE_DEBUG_MSGS("Can't save to file buffer!\n"); return -1; } } return 0; } /*Helper function for error*/ static inline FileCaptureState ERROR_capture(FileCaptureState state) { file_capture_stats.file_reserve_failures++; return state; } /* * Preserve the file in memory until it is released * * Arguments: * void *ssnptr: session pointer * void **file_mem: the pointer to store the memory block * that stores file and its metadata. * It will set NULL if no memory or fail to store * * Returns: * FileCaptureState * */ FileCaptureState file_capture_reserve(void *ssnptr, FileCaptureInfo **file_mem) { FileContext* context; FileCaptureInfo *fileInfo; uint64_t fileSize; FileConfig *file_config = (FileConfig *)(snort_conf->file_config); if (!ssnptr||!file_config||!file_mem) { return ERROR_capture(FILE_CAPTURE_FAIL); } context = get_current_file_context(ssnptr); if (!context || !context->file_capture_enabled) { return ERROR_capture(FILE_CAPTURE_FAIL); } if (context->file_state.capture_state != FILE_CAPTURE_SUCCESS) { return ERROR_capture(context->file_state.capture_state); } fileInfo = (FileCaptureInfo *)(context->file_capture); /* * Note: file size is updated at this point */ fileSize = context->file_size; if ( fileSize < (unsigned) file_config->file_capture_min_size) { file_capture_stats.file_size_min++; return ERROR_capture(FILE_CAPTURE_MIN); } if ( fileSize > (unsigned) file_config->file_capture_max_size) { file_capture_stats.file_size_max++; return ERROR_capture(FILE_CAPTURE_MAX); } /* Create a file buffer if it is not done yet, * This is the case for small file */ if(!fileInfo && context->file_capture_enabled) { fileInfo = _create_file_buffer(file_mempool); if (!fileInfo) { file_capture_stats.file_memcap_failures_reserve++; return ERROR_capture(FILE_CAPTURE_MEMCAP); } file_capture_stats.files_buffered_total++; context->file_capture = fileInfo; DEBUG_WRAP(verify_file_capture_info(context, fileInfo);); } if (!fileInfo) { return ERROR_capture(FILE_CAPTURE_MEMCAP); } DEBUG_WRAP(verify_file_capture_info(context, fileInfo);); /*Copy the last piece of file to file buffer*/ if (_save_to_file_buffer(file_mempool, context, context->current_data, context->current_data_len, file_config->file_capture_max_size) ) { return ERROR_capture(context->file_state.capture_state); } file_capture_stats.files_captured_total++; *file_mem = fileInfo; fileInfo->reserved = true; /* Clear file capture information on file context * Without this, the next file within the same session * might use this information to change shared memory buffer * that might be released and then used by other sessions */ context->file_capture = NULL; context->file_capture_enabled = false; DEBUG_WRAP(verifiy_file_capture(context, fileInfo);); return FILE_CAPTURE_SUCCESS; } /* * Get the file that is reserved in memory * * Arguments: * void *: the memory block that stores file and its metadata * uint8_t **buff: address to store buffer address * int *size: address to store size of file * * Returns: * the next memory block that stores file and its metadata * NULL: no more file data or fail to get file */ void* file_capture_read(FileCaptureInfo *fileInfo, uint8_t **buff, int *size) { if (!fileInfo|!buff||!size) { return NULL; } *buff = (uint8_t *)fileInfo + sizeof(*fileInfo); *size = fileInfo->length; return (fileInfo->next); } /* * Get the file size captured in the file buffer * * Arguments: * void *file_mem: the first memory block of file buffer * * Returns: * the size of file * 0: not the first file block or fail to get file */ size_t file_capture_size(FileCaptureInfo *fileInfo) { if (!fileInfo) return 0; return fileInfo->file_size; } /* * Release the file that is reserved in memory, this function might be * called in a different thread. * * Arguments: * void *data: the memory block that stores file and its metadata */ void file_capture_release(FileCaptureInfo *fileInfo) { if (!fileInfo) return; fileInfo->reserved = false; _release_file_buffer(fileInfo); } /*Log file capture mempool usage*/ void file_capture_mem_usage(void) { if (file_mempool) { LogMessage("Maximum buffers can allocate: "FMTu64("-10")" \n", file_mempool->total); LogMessage("Number of buffers in use: "FMTu64("-10")" \n", safe_mempool_allocated(file_mempool)); LogMessage("Number of buffers in free list: "FMTu64("-10")" \n", safe_mempool_freed(file_mempool)); LogMessage("Number of buffers in release list: "FMTu64("-10")" \n", safe_mempool_released(file_mempool)); } } /* * Release all file capture memory etc, * this must be called when snort exits */ void file_caputure_close(void) { if (safe_mempool_destroy(file_mempool) == 0) { free(file_mempool); file_mempool = NULL; } } snort-2.9.6.0/src/file-process/file_mime_config.h0000644000000000000000000000303612260565732016542 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #ifndef __IMAP_CONFIG_H__ #define __IMAP_CONFIG_H__ #include "file_api.h" /* Function prototypes */ void set_mime_decode_config_defauts(DecodeConfig *decode_conf); void set_mime_log_config_defauts(MAIL_LogConfig *log_config); int parse_mime_decode_args(DecodeConfig *decode_conf, char *arg, const char *preproc_name); bool is_decoding_enabled(DecodeConfig *decode_conf); bool is_mime_log_enabled(MAIL_LogConfig *log_config); bool is_decoding_conf_changed(DecodeConfig *configNext, DecodeConfig *config, const char *preproc_name); #endif snort-2.9.6.0/src/file-process/file_mime_config.c0000644000000000000000000002052312260565732016535 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "file_mime_config.h" #include "file_api.h" #include "sf_email_attach_decode.h" #include "util.h" #include "parser.h" #define CONF_SEPARATORS " \t\n\r" #define CONF_MAX_MIME_MEM "max_mime_mem" #define CONF_B64_DECODE "b64_decode_depth" #define CONF_QP_DECODE "qp_decode_depth" #define CONF_BITENC_DECODE "bitenc_decode_depth" #define CONF_UU_DECODE "uu_decode_depth" /*These are temporary values*/ #define DEFAULT_MAX_MIME_MEM 838860 #define DEFAULT_MIME_MEMCAP 838860 #define DEFAULT_DEPTH 1464 #define MAX_LOG_MEMCAP 104857600 #define MIN_LOG_MEMCAP 3276 #define MAX_MIME_MEM 104857600 #define MIN_MIME_MEM 3276 #define MAX_DEPTH 65535 #define MIN_DEPTH -1 #define ERRSTRLEN 512 static int ProcessDecodeDepth(DecodeConfig *config, char *ErrorString, int ErrStrLen, char *decode_type, DecodeType type, const char *preproc_name) { char *endptr; char *value; int decode_depth = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "%s config is NULL.\n", preproc_name); return -1; } value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) { snprintf(ErrorString, ErrStrLen, "Invalid format for %s config option '%s'.", preproc_name, decode_type); return -1; } decode_depth = strtol(value, &endptr, 10); if(*endptr) { snprintf(ErrorString, ErrStrLen, "Invalid format for %s config option '%s'.", preproc_name, decode_type); return -1; } if(decode_depth < MIN_DEPTH || decode_depth > MAX_DEPTH) { snprintf(ErrorString, ErrStrLen, "Invalid value for %s config option '%s'." "It should range between %d and %d.", preproc_name, decode_type, MIN_DEPTH, MAX_DEPTH); return -1; } switch(type) { case DECODE_B64: if((decode_depth > 0) && (decode_depth & 3)) { decode_depth += 4 - (decode_depth & 3); if(decode_depth > MAX_DEPTH ) { decode_depth = decode_depth - 4; } LogMessage("WARNING: %s(%d) => %s: 'b64_decode_depth' is not a multiple of 4. " "Rounding up to the next multiple of 4. The new 'b64_decode_depth' is %d.\n", file_name, file_line, preproc_name, decode_depth); } config->b64_depth = decode_depth; break; case DECODE_QP: config->qp_depth = decode_depth; break; case DECODE_UU: config->uu_depth = decode_depth; break; case DECODE_BITENC: config->bitenc_depth = decode_depth; break; default: return -1; } return 0; } void set_mime_decode_config_defauts(DecodeConfig *decode_conf) { decode_conf->max_mime_mem = DEFAULT_MIME_MEMCAP; decode_conf->b64_depth = DEFAULT_DEPTH; decode_conf->qp_depth = DEFAULT_DEPTH; decode_conf->uu_depth = DEFAULT_DEPTH; decode_conf->bitenc_depth = DEFAULT_DEPTH; decode_conf->max_depth = DEFAULT_DEPTH; } void set_mime_log_config_defauts(MAIL_LogConfig *log_config) { log_config->memcap = DEFAULT_MIME_MEMCAP; log_config->log_filename = 0; log_config->log_mailfrom = 0; log_config->log_rcptto = 0; log_config->log_email_hdrs = 0; log_config->email_hdrs_log_depth = 0; } bool is_decoding_enabled(DecodeConfig *decode_conf) { if( (decode_conf->b64_depth > -1) || (decode_conf->qp_depth > -1) || (decode_conf->uu_depth > -1) || (decode_conf->bitenc_depth > -1) || (decode_conf->file_depth > -1)) { return true; } else return false; } bool is_mime_log_enabled(MAIL_LogConfig *log_config) { if(log_config->log_email_hdrs || log_config->log_filename || log_config->log_mailfrom || log_config->log_rcptto) return true; return false; } bool is_decoding_conf_changed(DecodeConfig *configNext, DecodeConfig *config, const char *preproc_name) { if (configNext == NULL) { ErrorMessage("%s reload: Changing the %s configuration requires a restart.\n", preproc_name, preproc_name); return true; } if (configNext->max_mime_mem != config->max_mime_mem) { ErrorMessage("%s reload: Changing the memcap requires a restart.\n", preproc_name); return true; } if(configNext->b64_depth != config->b64_depth) { ErrorMessage("%s reload: Changing the b64_decode_depth requires a restart.\n", preproc_name); return true; } if(configNext->qp_depth != config->qp_depth) { ErrorMessage("%s reload: Changing the qp_decode_depth requires a restart.\n", preproc_name); return true; } if(configNext->bitenc_depth != config->bitenc_depth) { ErrorMessage("%s reload: Changing the bitenc_decode_depth requires a restart.\n", preproc_name); return true; } if(configNext->uu_depth != config->uu_depth) { ErrorMessage("%s reload: Changing the uu_decode_depth requires a restart.\n", preproc_name); return true; } if(configNext->file_depth != config->file_depth) { ErrorMessage("%s reload: Changing the file_depth requires a restart.\n", preproc_name); return true; } return false; } /* * * Purpose: Process the configuration * * Arguments: args => argument list * * Returns: -1: error or not found * 0: no error * */ int parse_mime_decode_args(DecodeConfig *decode_conf, char *arg, const char *preproc_name) { int ret = 0; char errStr[ERRSTRLEN]; int errStrLen = ERRSTRLEN; unsigned long value = 0; if ((decode_conf == NULL) || (arg == NULL)) return 0; *errStr = '\0'; if ( !strcasecmp(CONF_MAX_MIME_MEM, arg) ) { ret = CheckValueInRange(strtok(NULL, CONF_SEPARATORS), CONF_MAX_MIME_MEM, MIN_MIME_MEM, MAX_MIME_MEM, &value); decode_conf->max_mime_mem = (int)value; } else if ( !strcasecmp(CONF_B64_DECODE, arg) ) { ret = ProcessDecodeDepth(decode_conf, errStr, errStrLen, CONF_B64_DECODE, DECODE_B64, preproc_name); } else if ( !strcasecmp(CONF_QP_DECODE, arg) ) { ret = ProcessDecodeDepth(decode_conf, errStr, errStrLen, CONF_QP_DECODE, DECODE_QP, preproc_name); } else if ( !strcasecmp(CONF_UU_DECODE, arg) ) { ret = ProcessDecodeDepth(decode_conf, errStr, errStrLen, CONF_UU_DECODE, DECODE_UU, preproc_name); } else if ( !strcasecmp(CONF_BITENC_DECODE, arg) ) { ret = ProcessDecodeDepth(decode_conf, errStr, errStrLen, CONF_BITENC_DECODE, DECODE_BITENC, preproc_name); } else { return -1; } if (ret == -1) { /* ** Fatal Error, log error and exit. */ if (*errStr) { FatalError("%s(%d) => %s\n", file_name, file_line, errStr); } else { FatalError("%s(%d) => Undefined Error.\n", file_name, file_line); } } return ret; } snort-2.9.6.0/src/file-process/file_resume_block.h0000644000000000000000000000263312260565732016742 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #ifndef _FILE_RESUME_BLOCK_H_ #define _FILE_RESUME_BLOCK_H_ #include "decode.h" #include "file_api.h" void file_resume_block_init(void); void file_resume_block_cleanup(void); int file_resume_block_add_file(void *pkt, uint32_t file_sig, uint32_t timeout, File_Verdict verdict, uint32_t file_type_id, uint8_t *signature); File_Verdict file_resume_block_check(void *pkt, uint32_t file_sig); #endif snort-2.9.6.0/src/file-process/file_resume_block.c0000644000000000000000000001725412260565732016742 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "file_resume_block.h" #include "sf_types.h" #include "file_api.h" #include "snort_bounds.h" #include "ipv6_port.h" #include "sfxhash.h" #include "util.h" #include "decode.h" #include "active.h" #include "file_sha256.h" /* The hash table of expected files */ static SFXHASH *fileHash = NULL; extern Log_file_action_func log_file_action; extern File_type_callback_func file_type_cb; extern File_signature_callback_func file_signature_cb; static FileState sig_file_state = { FILE_CAPTURE_SUCCESS, FILE_SIG_DONE }; typedef struct _FileHashKey { snort_ip sip; snort_ip dip; uint32_t file_sig; } FileHashKey; typedef struct _FileNode { time_t expires; File_Verdict verdict; uint32_t file_type_id; uint8_t sha256[SHA256_HASH_SIZE]; } FileNode; #define MAX_FILES_TRACKED 16384 void file_resume_block_init(void) { fileHash = sfxhash_new(MAX_FILES_TRACKED, sizeof(FileHashKey), sizeof(FileNode), 0, 1, NULL, NULL, 1); if (!fileHash) FatalError("Failed to create the expected channel hash table.\n"); } void file_resume_block_cleanup(void) { if (fileHash) { sfxhash_delete(fileHash); fileHash = NULL; } } static inline void updateFileNode(FileNode *node, File_Verdict verdict, uint32_t file_type_id, uint8_t *signature) { node->verdict = verdict; node->file_type_id = file_type_id; if (signature) { memcpy(node->sha256, signature, SHA256_HASH_SIZE); } } /** * * @param sip - source IP address * @param dip - destination IP address * @param sport - server sport number * @param file_sig - file signature * @param expiry - session expiry in seconds. */ int file_resume_block_add_file(void *pkt, uint32_t file_sig, uint32_t timeout, File_Verdict verdict, uint32_t file_type_id, uint8_t *signature) { FileHashKey hashKey; SFXHASH_NODE *hash_node = NULL; FileNode *node; FileNode new_node; snort_ip_p srcIP; snort_ip_p dstIP; Packet *p = (Packet *)pkt; time_t now = p->pkth->ts.tv_sec; srcIP = GET_SRC_IP(p); dstIP = GET_DST_IP(p); IP_COPY_VALUE(hashKey.dip, dstIP); IP_COPY_VALUE(hashKey.sip, srcIP); hashKey.file_sig = file_sig; hash_node = sfxhash_find_node(fileHash, &hashKey); if (hash_node) { if (!(node = hash_node->data)) sfxhash_free_node(fileHash, hash_node); } else node = NULL; if (node) { node->expires = now + timeout; updateFileNode(node, verdict, file_type_id, signature); } else { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Adding file node\n");); updateFileNode(&new_node, verdict, file_type_id, signature); /* * use the time that we keep files around * since this info would effectively be invalid * after that anyway because the file that * caused this will be gone. */ new_node.expires = now + timeout; /* Add it to the table */ if (sfxhash_add(fileHash, &hashKey, &new_node) != SFXHASH_OK) { /* Uh, shouldn't get here... * There is already a node or couldn't alloc space * for key. This means bigger problems, but fail * gracefully. */ DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Failed to add file node to hash table\n");); return -1; } } return 0; } static inline File_Verdict checkVerdict(Packet *p, FileNode *node, SFXHASH_NODE *hash_node) { File_Verdict verdict = FILE_VERDICT_UNKNOWN; /*Query the file policy in case verdict has been changed*/ /*Check file type first*/ if (file_type_cb) { verdict = file_type_cb(p, p->ssnptr, node->file_type_id, 0, DEFAULT_FILE_ID); } if ((verdict == FILE_VERDICT_UNKNOWN) || (verdict == FILE_VERDICT_STOP_CAPTURE)) { if (file_signature_cb) { verdict = file_signature_cb(p, p->ssnptr, node->sha256, 0, &sig_file_state, 0, DEFAULT_FILE_ID); } } if ((verdict == FILE_VERDICT_UNKNOWN) || (verdict == FILE_VERDICT_STOP_CAPTURE)) { verdict = node->verdict; } if (verdict == FILE_VERDICT_LOG) { sfxhash_free_node(fileHash, hash_node); if (log_file_action) { log_file_action(p->ssnptr, FILE_RESUME_LOG); } } else if (verdict == FILE_VERDICT_BLOCK) { Active_ForceDropPacket(); Active_DropSession(p); if (log_file_action) { log_file_action(p->ssnptr, FILE_RESUME_BLOCK); } node->verdict = verdict; } else if (verdict == FILE_VERDICT_REJECT) { Active_ForceDropPacket(); Active_DropSession(p); Active_QueueReject(); if (log_file_action) { log_file_action(p->ssnptr, FILE_RESUME_BLOCK); } node->verdict = verdict; } else if (verdict == FILE_VERDICT_PENDING) { /*Take the cached verdict*/ Active_ForceDropPacket(); Active_DropSession(p); if (FILE_VERDICT_REJECT == node->verdict) Active_QueueReject(); if (log_file_action) { log_file_action(p->ssnptr, FILE_RESUME_BLOCK); } verdict = node->verdict; } return verdict; } File_Verdict file_resume_block_check(void *pkt, uint32_t file_sig) { File_Verdict verdict = FILE_VERDICT_UNKNOWN; snort_ip_p srcIP; snort_ip_p dstIP; SFXHASH_NODE *hash_node; FileHashKey hashKey; FileNode *node; Packet *p = (Packet *)pkt; /* No hash table, or its empty? Get out of dodge. */ if ((!fileHash) || (!sfxhash_count(fileHash))) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "No expected sessions\n");); return verdict; } srcIP = GET_SRC_IP(p); dstIP = GET_DST_IP(p); IP_COPY_VALUE(hashKey.dip, dstIP); IP_COPY_VALUE(hashKey.sip, srcIP); hashKey.file_sig = file_sig; hash_node = sfxhash_find_node(fileHash, &hashKey); if (hash_node) { if (!(node = hash_node->data)) sfxhash_free_node(fileHash, hash_node); } else return verdict; if (node) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Found resumed file\n");); if (node->expires && p->pkth->ts.tv_sec > node->expires) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "File expired\n");); sfxhash_free_node(fileHash, hash_node); return verdict; } /*Query the file policy in case verdict has been changed*/ verdict = checkVerdict(p, node, hash_node); } return verdict; } snort-2.9.6.0/src/file-process/file_mime_process.h0000644000000000000000000000625712260565732016763 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #ifndef _FILE_MIME_PROCESS_H_ #define _FILE_MIME_PROCESS_H_ #include #include "file_api.h" #include "sf_email_attach_decode.h" #include "mempool.h" #include "sfPolicy.h" #define BOUNDARY 0 /* state flags */ #define MIME_FLAG_FOLDING 0x00000001 #define MIME_FLAG_IN_CONTENT_TYPE 0x00000002 #define MIME_FLAG_GOT_BOUNDARY 0x00000004 #define MIME_FLAG_DATA_HEADER_CONT 0x00000008 #define MIME_FLAG_IN_CONT_TRANS_ENC 0x00000010 #define MIME_FLAG_EMAIL_ATTACH 0x00000020 #define MIME_FLAG_MULTIPLE_EMAIL_ATTACH 0x00000040 #define MIME_FLAG_MIME_END 0x00000080 #define MIME_FLAG_IN_CONT_DISP 0x00000200 #define MIME_FLAG_IN_CONT_DISP_CONT 0x00000400 #define STATE_DATA_INIT 0 #define STATE_DATA_HEADER 1 /* Data header section of data state */ #define STATE_DATA_BODY 2 /* Data body section of data state */ #define STATE_MIME_HEADER 3 /* MIME header section within data section */ #define STATE_DATA_UNKNOWN 4 /* log flags */ #define MIME_FLAG_FILENAME_PRESENT 0x00000004 typedef struct _MimePcre { pcre *re; pcre_extra *pe; } MimePcre; int log_file_name(const uint8_t *start, int length, FILE_LogState *log_state, bool *disp_cont); int set_log_buffers(MAIL_LogState **log_state, MAIL_LogConfig *conf, void *mempool); void* init_mime_mempool(int max_mime_mem, int max_depth, void *mempool, const char *preproc_name); void* init_log_mempool(uint32_t email_hdrs_log_depth, uint32_t memcap, void *mempool, const char *preproc_name); void init_mime(void); void free_mime(void); const uint8_t* process_mime_data(void *packet, const uint8_t *start, const uint8_t *end, const uint8_t *data_end_marker, uint8_t *data_end, MimeState *mime_ssn, bool upload); void free_mime_session(MimeState *mime_ssn); void finalize_mime_position(void *ssnptr, void *decode_state, FilePosition *position); #ifdef TARGET_BASED void register_mime_paf_service(struct _SnortConfig *sc, int16_t app, tSfPolicyId policy); #endif void register_mime_paf_port(struct _SnortConfig *sc, unsigned int i, tSfPolicyId policy); void force_flush_stream (void *ssn); #endif snort-2.9.6.0/src/file-process/file_mime_process.c0000644000000000000000000012471412260565732016755 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "file_mime_process.h" #include "mempool.h" #include "file_api.h" #include "snort_bounds.h" #include "util.h" #include "str_search.h" #include "decode.h" #include "detection_util.h" #include "stream_api.h" #ifdef HAVE_STRINGS_H #include #endif /* State tracker for MIME PAF */ typedef enum _MimePafState { MIME_PAF_UNKNOWN = 0, /* UNKNOWN */ MIME_PAF_FIRST_LF, /* First '\n' */ MIME_PAF_SECOND_LF /* Second '\n' */ } MimePafState; /* State tracker for MIME PAF */ typedef struct _MimePafData { MimePafState state; bool is_data; } MimePafData; MimePcre mime_boundary_pcre; typedef struct _MimeToken { char *name; int name_len; int search_id; } MimeToken; typedef enum _MimeHdrEnum { HDR_CONTENT_TYPE = 0, HDR_CONT_TRANS_ENC, HDR_CONT_DISP, HDR_LAST } MimeHdrEnum; const MimeToken mime_hdrs[] = { {"Content-type:", 13, HDR_CONTENT_TYPE}, {"Content-Transfer-Encoding:", 26, HDR_CONT_TRANS_ENC}, {"Content-Disposition:", 20, HDR_CONT_DISP}, {NULL, 0, 0} }; typedef struct _MIMESearch { char *name; int name_len; } MIMESearch; typedef struct _MIMESearchInfo { int id; int index; int length; } MIMESearchInfo; MIMESearchInfo mime_search_info; void *mime_hdr_search_mpse = NULL; MIMESearch mime_hdr_search[HDR_LAST]; MIMESearch *mime_current_search = NULL; /* Extract the filename from the header */ static inline int extract_file_name(const char **start, int length, bool *disp_cont) { const char *tmp = NULL; const char *end = *start+length; if (length <= 0) return -1; if (!(*disp_cont)) { tmp = SnortStrcasestr(*start, length, "filename"); if( tmp == NULL ) return -1; tmp = tmp + 8; while( (tmp < end) && ((isspace(*tmp)) || (*tmp == '=') )) { tmp++; } } else tmp = *start; if(tmp < end) { if(*tmp == '"' || (*disp_cont)) { if(*tmp == '"') { if(*disp_cont) { *disp_cont = false; return (tmp - *start); } tmp++; } *start = tmp; tmp = SnortStrnPbrk(*start ,(end - tmp),"\""); if(tmp == NULL ) { if ((end - tmp) > 0 ) { tmp = end; *disp_cont = true; } else return -1; } else *disp_cont = false; end = tmp; } else { *start = tmp; } return (end - *start); } else { return -1; } } /* accumulate MIME attachment filenames. The filenames are appended by commas */ int log_file_name(const uint8_t *start, int length, FILE_LogState *log_state, bool *disp_cont) { uint8_t *alt_buf; int alt_size; uint16_t *alt_len; int ret=0; int cont =0; int log_avail = 0; if(!start || (length <= 0)) { *disp_cont = false; return -1; } if(*disp_cont) cont = 1; ret = extract_file_name((const char **)(&start), length, disp_cont); if (ret == -1) return ret; length = ret; alt_buf = log_state->filenames; alt_size = MAX_FILE; alt_len = &(log_state->file_logged); log_avail = alt_size - *alt_len; if(!alt_buf || (log_avail <= 0)) return -1; if ( *alt_len > 0 && ((*alt_len + 1) < alt_size)) { if(!cont) { alt_buf[*alt_len] = ','; *alt_len = *alt_len + 1; } } ret = SafeMemcpy(alt_buf + *alt_len, start, length, alt_buf, alt_buf + alt_size); if (ret != SAFEMEM_SUCCESS) { if(*alt_len != 0) *alt_len = *alt_len - 1; return -1; } log_state->file_current = *alt_len; *alt_len += length; return 0; } /* * Return: 0: success * -1: fail * */ int set_log_buffers(MAIL_LogState **log_state, MAIL_LogConfig *conf, void *mempool) { MemPool *log_mempool = (MemPool *)mempool; if((*log_state == NULL) && (conf->log_email_hdrs || conf->log_filename || conf->log_mailfrom || conf->log_rcptto)) { MemBucket *bkt = mempool_alloc(log_mempool); if(bkt == NULL) return -1; *log_state = (MAIL_LogState *)calloc(1, sizeof(MAIL_LogState)); if((*log_state) != NULL) { (*log_state)->log_hdrs_bkt = bkt; (*log_state)->log_depth = conf->email_hdrs_log_depth; (*log_state)->recipients = (uint8_t *)bkt->data; (*log_state)->rcpts_logged = 0; (*log_state)->senders = (uint8_t *)bkt->data + MAX_EMAIL; (*log_state)->snds_logged = 0; (*log_state)->file_log.filenames = (uint8_t *)bkt->data + (2*MAX_EMAIL); (*log_state)->file_log.file_logged = 0; (*log_state)->file_log.file_current = 0; (*log_state)->file_log.file_name = 0; (*log_state)->emailHdrs = (unsigned char *)bkt->data + (2*MAX_EMAIL) + MAX_FILE; (*log_state)->hdrs_logged = 0; } else { /*free bkt if calloc fails*/ mempool_free(log_mempool, bkt); return -1; } } return 0; } static void set_mime_buffers(MimeState *ssn) { if ((ssn != NULL) && (ssn->decode_state == NULL)) { MemBucket *bkt = mempool_alloc(ssn->mime_mempool); DecodeConfig *conf= ssn->decode_conf; if (bkt != NULL) { ssn->decode_state = calloc(1, sizeof(Email_DecodeState)); if((ssn->decode_state) != NULL ) { ssn->decode_bkt = bkt; SetEmailDecodeState((Email_DecodeState *)(ssn->decode_state), bkt->data, conf->max_depth, conf->b64_depth, conf->qp_depth, conf->uu_depth, conf->bitenc_depth, conf->file_depth); } else { /*free mempool if calloc fails*/ mempool_free(ssn->mime_mempool, bkt); } } else { // MIME_GenerateAlert(MIME_MEMCAP_EXCEEDED, "%s", MIME_MEMCAP_EXCEEDED_STR); DEBUG_WRAP(DebugMessage(DEBUG_FILE, "No memory available for decoding. Memcap exceeded \n");); } } } void* init_mime_mempool(int max_mime_mem, int max_depth, void *mempool, const char *preproc_name) { int encode_depth; int max_sessions; MemPool *mime_mempool = (MemPool *)mempool; if (mime_mempool != NULL) return mime_mempool ; if (max_depth <= 0) return NULL; encode_depth = max_depth; if (encode_depth & 7) encode_depth += (8 - (encode_depth & 7)); max_sessions = max_mime_mem / ( 2 * encode_depth); mime_mempool = (MemPool *)calloc(1, sizeof(MemPool)); if ((!mime_mempool)||(mempool_init(mime_mempool, max_sessions, (2 * encode_depth)) != 0)) { FatalError( "%s: Could not allocate %s mime mempool.\n", preproc_name, preproc_name); } return mime_mempool; } void* init_log_mempool(uint32_t email_hdrs_log_depth, uint32_t memcap, void *mempool, const char *preproc_name) { uint32_t max_bkt_size; uint32_t max_sessions_logged; MemPool *log_mempool = (MemPool *) mempool; if (log_mempool != NULL) return log_mempool; max_bkt_size = ((2* MAX_EMAIL) + MAX_FILE + email_hdrs_log_depth); max_sessions_logged = memcap/max_bkt_size; log_mempool = calloc(1, sizeof(*log_mempool)); if ((!log_mempool)||(mempool_init(log_mempool, max_sessions_logged, max_bkt_size) != 0)) { if(!max_sessions_logged) { FatalError( "%s: Could not allocate %s mempool.\n", preproc_name, preproc_name); } else { FatalError( "%s: Error setting the \"memcap\" \n", preproc_name); } } return log_mempool; } /* * Initialize run-time boundary search, this should be called for every transaction */ static int init_boundary_search(MimeBoundary *mime_boundary ) { if (mime_boundary->boundary_search != NULL) search_api->search_instance_free(mime_boundary->boundary_search); mime_boundary->boundary_search = search_api->search_instance_new(); if (mime_boundary->boundary_search == NULL) return -1; search_api->search_instance_add(mime_boundary->boundary_search, mime_boundary->boundary, mime_boundary->boundary_len, BOUNDARY); search_api->search_instance_prep(mime_boundary->boundary_search); return 0; } /* * Update boundary search string when found */ static int get_boundary(const char *data, int data_len, MimeBoundary *mime_boundary) { int result; int ovector[9]; int ovecsize = 9; const char *boundary; int boundary_len; int ret; char *mime_boundary_str; int *mime_boundary_len; int *mime_boundary_state; mime_boundary_str = &mime_boundary->boundary[0]; mime_boundary_len = &mime_boundary->boundary_len; mime_boundary_state = &mime_boundary->state; /* result will be the number of matches (including submatches) */ result = pcre_exec(mime_boundary_pcre.re, mime_boundary_pcre.pe, data, data_len, 0, 0, ovector, ovecsize); if (result < 0) return -1; result = pcre_get_substring(data, ovector, result, 1, &boundary); if (result < 0) return -1; boundary_len = strlen(boundary); if (boundary_len > MAX_MIME_BOUNDARY_LEN) { /* XXX should we alert? breaking the law of RFC */ boundary_len = MAX_MIME_BOUNDARY_LEN; } mime_boundary_str[0] = '-'; mime_boundary_str[1] = '-'; ret = SafeMemcpy(mime_boundary_str + 2, boundary, boundary_len, mime_boundary_str + 2, mime_boundary_str + 2 + MAX_MIME_BOUNDARY_LEN); pcre_free_substring(boundary); if (ret != SAFEMEM_SUCCESS) { return -1; } *mime_boundary_len = 2 + boundary_len; *mime_boundary_state = 0; mime_boundary_str[*mime_boundary_len] = '\0'; return 0; } void get_mime_eol(const uint8_t *ptr, const uint8_t *end, const uint8_t **eol, const uint8_t **eolm) { const uint8_t *tmp_eol; const uint8_t *tmp_eolm; /* XXX maybe should fatal error here since none of these * pointers should be NULL */ if (ptr == NULL || end == NULL || eol == NULL || eolm == NULL) return; tmp_eol = (uint8_t *)memchr(ptr, '\n', end - ptr); if (tmp_eol == NULL) { tmp_eol = end; tmp_eolm = end; } else { /* end of line marker (eolm) should point to marker and * end of line (eol) should point to end of marker */ if ((tmp_eol > ptr) && (*(tmp_eol - 1) == '\r')) { tmp_eolm = tmp_eol - 1; } else { tmp_eolm = tmp_eol; } /* move past newline */ tmp_eol++; } *eol = tmp_eol; *eolm = tmp_eolm; } /* * Callback function for string search * * @param id id in array of search strings from mime_config.cmds * @param index index in array of search strings from mime_config.cmds * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */ static int search_str_found(void *id, void *unused, int index, void *data, void *unused2) { int search_id = (int)(uintptr_t)id; mime_search_info.id = search_id; mime_search_info.index = index; mime_search_info.length = mime_current_search[search_id].name_len; /* Returning non-zero stops search, which is okay since we only look for one at a time */ return 1; } /* * Callback function for boundary search * * @param id id in array of search strings * @param index index in array of search strings * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */ static int boundary_str_found(void *id, void *unused, int index, void *data, void *unused2) { int boundary_id = (int)(uintptr_t)id; mime_search_info.id = boundary_id; mime_search_info.index = index; //mime_search_info.length = mime_ssn->mime_boundary.boundary_len; return 1; } static inline int is_decoding_enabled(DecodeConfig *pPolicyConfig) { if( (pPolicyConfig->b64_depth > -1) || (pPolicyConfig->qp_depth > -1) || (pPolicyConfig->uu_depth > -1) || (pPolicyConfig->bitenc_depth > -1) || (pPolicyConfig->file_depth > -1)) { return 0; } else return -1; } static inline void process_decode_type(const char *start, int length, bool cnt_xf, MimeState *mime_ssn) { const char *tmp = NULL; Email_DecodeState *decode_state = (Email_DecodeState *)(mime_ssn->decode_state); if(cnt_xf) { if(decode_state->b64_state.encode_depth > -1) { tmp = SnortStrcasestr(start, length, "base64"); if( tmp != NULL ) { decode_state->decode_type = DECODE_B64; return; } } if(decode_state->qp_state.encode_depth > -1) { tmp = SnortStrcasestr(start, length, "quoted-printable"); if( tmp != NULL ) { decode_state->decode_type = DECODE_QP; return; } } if(decode_state->uu_state.encode_depth > -1) { tmp = SnortStrcasestr(start, length, "uuencode"); if( tmp != NULL ) { decode_state->decode_type = DECODE_UU; return; } } } if(decode_state->bitenc_state.depth > -1) { decode_state->decode_type = DECODE_BITENC; return; } return; } static inline void setup_decode(const char *data, int size, bool cnt_xf, MimeState *mime_ssn) { /* Check for Encoding Type */ if( !is_decoding_enabled(mime_ssn->decode_conf)) { set_mime_buffers(mime_ssn); if(mime_ssn->decode_state != NULL) { ResetBytesRead((Email_DecodeState *)(mime_ssn->decode_state)); process_decode_type(data, size, cnt_xf, mime_ssn ); mime_ssn->state_flags |= MIME_FLAG_EMAIL_ATTACH; /* check to see if there are other attachments in this packet */ if( ((Email_DecodeState *)(mime_ssn->decode_state))->decoded_bytes ) mime_ssn->state_flags |= MIME_FLAG_MULTIPLE_EMAIL_ATTACH; } } } /* * Handle Headers - Data or Mime * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */ static const uint8_t * process_mime_header(Packet *p, const uint8_t *ptr, const uint8_t *data_end_marker, MimeState *mime_ssn) { const uint8_t *eol; const uint8_t *eolm; const uint8_t *colon; const uint8_t *content_type_ptr = NULL; const uint8_t *cont_trans_enc = NULL; const uint8_t *cont_disp = NULL; int header_found; int ret; const uint8_t *start_hdr; start_hdr = ptr; /* if we got a content-type in a previous packet and are * folding, the boundary still needs to be checked for */ if (mime_ssn->state_flags & MIME_FLAG_IN_CONTENT_TYPE) content_type_ptr = ptr; if (mime_ssn->state_flags & MIME_FLAG_IN_CONT_TRANS_ENC) cont_trans_enc = ptr; if (mime_ssn->state_flags & MIME_FLAG_IN_CONT_DISP) cont_disp = ptr; while (ptr < data_end_marker) { get_mime_eol(ptr, data_end_marker, &eol, &eolm); /* got a line with only end of line marker should signify end of header */ if (eolm == ptr) { /* reset global header state values */ mime_ssn->state_flags &= ~(MIME_FLAG_FOLDING | MIME_FLAG_IN_CONTENT_TYPE | MIME_FLAG_DATA_HEADER_CONT | MIME_FLAG_IN_CONT_TRANS_ENC ); mime_ssn->data_state = STATE_DATA_BODY; /* if no headers, treat as data */ if (ptr == start_hdr) return eolm; else return eol; } /* if we're not folding, see if we should interpret line as a data line * instead of a header line */ if (!(mime_ssn->state_flags & (MIME_FLAG_FOLDING | MIME_FLAG_DATA_HEADER_CONT))) { char got_non_printable_in_header_name = 0; /* if we're not folding and the first char is a space or * colon, it's not a header */ if (isspace((int)*ptr) || *ptr == ':') { mime_ssn->data_state = STATE_DATA_BODY; return ptr; } /* look for header field colon - if we're not folding then we need * to find a header which will be all printables (except colon) * followed by a colon */ colon = ptr; while ((colon < eolm) && (*colon != ':')) { if (((int)*colon < 33) || ((int)*colon > 126)) got_non_printable_in_header_name = 1; colon++; } /* If the end on line marker and end of line are the same, assume * header was truncated, so stay in data header state */ if ((eolm != eol) && ((colon == eolm) || got_non_printable_in_header_name)) { /* no colon or got spaces in header name (won't be interpreted as a header) * assume we're in the body */ mime_ssn->state_flags &= ~(MIME_FLAG_FOLDING | MIME_FLAG_IN_CONTENT_TYPE | MIME_FLAG_DATA_HEADER_CONT |MIME_FLAG_IN_CONT_TRANS_ENC); mime_ssn->data_state = STATE_DATA_BODY; return ptr; } if(tolower((int)*ptr) == 'c') { mime_current_search = &mime_hdr_search[0]; header_found =search_api->search_instance_find (mime_hdr_search_mpse, (const char *)ptr, eolm - ptr, 1, search_str_found); /* Headers must start at beginning of line */ if ((header_found > 0) && (mime_search_info.index == 0)) { switch (mime_search_info.id) { case HDR_CONTENT_TYPE: content_type_ptr = ptr + mime_search_info.length; mime_ssn->state_flags |= MIME_FLAG_IN_CONTENT_TYPE; break; case HDR_CONT_TRANS_ENC: cont_trans_enc = ptr + mime_search_info.length; mime_ssn->state_flags |= MIME_FLAG_IN_CONT_TRANS_ENC; break; case HDR_CONT_DISP: cont_disp = ptr + mime_search_info.length; mime_ssn->state_flags |= MIME_FLAG_IN_CONT_DISP; break; default: break; } } } else if(tolower((int)*ptr) == 'e') { if((eolm - ptr) >= 9) { if(strncasecmp((const char *)ptr, "Encoding:", 9) == 0) { cont_trans_enc = ptr + 9; mime_ssn->state_flags |= MIME_FLAG_IN_CONT_TRANS_ENC; } } } } else { mime_ssn->state_flags &= ~MIME_FLAG_DATA_HEADER_CONT; } /* check for folding * if char on next line is a space and not \n or \r\n, we are folding */ if ((eol < data_end_marker) && isspace((int)eol[0]) && (eol[0] != '\n')) { if ((eol < (data_end_marker - 1)) && (eol[0] != '\r') && (eol[1] != '\n')) { mime_ssn->state_flags |= MIME_FLAG_FOLDING; } else { mime_ssn->state_flags &= ~MIME_FLAG_FOLDING; } } else if (eol != eolm) { mime_ssn->state_flags &= ~MIME_FLAG_FOLDING; } /* check if we're in a content-type header and not folding. if so we have the whole * header line/lines for content-type - see if we got a multipart with boundary * we don't check each folded line, but wait until we have the complete header * because boundary=BOUNDARY can be split across mulitple folded lines before * or after the '=' */ if ((mime_ssn->state_flags & (MIME_FLAG_IN_CONTENT_TYPE | MIME_FLAG_FOLDING)) == MIME_FLAG_IN_CONTENT_TYPE) { if (mime_ssn->data_state != STATE_MIME_HEADER) { /* we got the full content-type header - look for boundary string */ ret = get_boundary((const char *)content_type_ptr, eolm - content_type_ptr, &(mime_ssn->mime_boundary)); if (ret != -1) { ret = init_boundary_search(&(mime_ssn->mime_boundary)); if (ret != -1) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Got mime boundary: %s\n", mime_ssn->mime_boundary.boundary);); mime_ssn->state_flags |= MIME_FLAG_GOT_BOUNDARY; } } } else if (!(mime_ssn->state_flags & MIME_FLAG_EMAIL_ATTACH)) { setup_decode((const char *)content_type_ptr, (eolm - content_type_ptr), false, mime_ssn ); } mime_ssn->state_flags &= ~MIME_FLAG_IN_CONTENT_TYPE; content_type_ptr = NULL; } else if ((mime_ssn->state_flags & (MIME_FLAG_IN_CONT_TRANS_ENC | MIME_FLAG_FOLDING)) == MIME_FLAG_IN_CONT_TRANS_ENC) { setup_decode((const char *)cont_trans_enc, (eolm - cont_trans_enc), true, mime_ssn ); mime_ssn->state_flags &= ~MIME_FLAG_IN_CONT_TRANS_ENC; cont_trans_enc = NULL; } else if (((mime_ssn->state_flags & (MIME_FLAG_IN_CONT_DISP | MIME_FLAG_FOLDING)) == MIME_FLAG_IN_CONT_DISP) && cont_disp) { bool disp_cont = (mime_ssn->state_flags & MIME_FLAG_IN_CONT_DISP_CONT)? true: false; if(mime_ssn->log_config->log_filename && mime_ssn->log_state ) { if(!log_file_name(cont_disp, eolm - cont_disp, &(mime_ssn->log_state->file_log), &disp_cont) ) mime_ssn->log_flags |= MIME_FLAG_FILENAME_PRESENT; } if (disp_cont) { mime_ssn->state_flags |= MIME_FLAG_IN_CONT_DISP_CONT; } else { mime_ssn->state_flags &= ~MIME_FLAG_IN_CONT_DISP; mime_ssn->state_flags &= ~MIME_FLAG_IN_CONT_DISP_CONT; } cont_disp = NULL; } /* if state was unknown, at this point assume we know */ if (mime_ssn->data_state == STATE_DATA_UNKNOWN) mime_ssn->data_state = STATE_DATA_HEADER; ptr = eol; if (ptr == data_end_marker) mime_ssn->state_flags |= MIME_FLAG_DATA_HEADER_CONT; } return ptr; } /* * Handle DATA_BODY state * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */ static const uint8_t * process_mime_body(Packet *p, const uint8_t *ptr, const uint8_t *data_end_marker, MimeState *mime_ssn) { int boundary_found = 0; const uint8_t *boundary_ptr = NULL; const uint8_t *attach_start = NULL; const uint8_t *attach_end = NULL; Email_DecodeState *decode_state = (Email_DecodeState *)(mime_ssn->decode_state); if ( mime_ssn->state_flags & MIME_FLAG_EMAIL_ATTACH ) attach_start = ptr; /* look for boundary */ if (mime_ssn->state_flags & MIME_FLAG_GOT_BOUNDARY) { boundary_found = search_api->stateful_search_instance_find (mime_ssn->mime_boundary.boundary_search, (const char *)ptr, data_end_marker - ptr, 0, boundary_str_found, &(mime_ssn->mime_boundary.state)); mime_search_info.length = mime_ssn->mime_boundary.boundary_len; if (boundary_found > 0) { mime_ssn->mime_boundary.state = 0; boundary_ptr = ptr + mime_search_info.index; /* should start at beginning of line */ if ((boundary_ptr == ptr) || (*(boundary_ptr - 1) == '\n')) { const uint8_t *eol; const uint8_t *eolm; const uint8_t *tmp; if (mime_ssn->state_flags & MIME_FLAG_EMAIL_ATTACH ) { attach_end = boundary_ptr-1; mime_ssn->state_flags &= ~MIME_FLAG_EMAIL_ATTACH; if(attach_start < attach_end) { if (*(attach_end - 1) == '\r') attach_end--; if(EmailDecode( attach_start, attach_end, decode_state) < DECODE_SUCCESS ) { // MIME_DecodeAlert(); } } } if(boundary_ptr > ptr) tmp = boundary_ptr + mime_search_info.length; else { tmp = (const uint8_t *)search_api->search_instance_find_end((char *)boundary_ptr, (data_end_marker - boundary_ptr), mime_ssn->mime_boundary.boundary, mime_search_info.length); } /* Check for end boundary */ if (((tmp + 1) < data_end_marker) && (tmp[0] == '-') && (tmp[1] == '-')) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Mime boundary end found: %s--\n", (char *)mime_ssn->mime_boundary.boundary);); /* no more MIME */ mime_ssn->state_flags &= ~MIME_FLAG_GOT_BOUNDARY; mime_ssn->state_flags |= MIME_FLAG_MIME_END; /* free boundary search */ search_api->search_instance_free(mime_ssn->mime_boundary.boundary_search); mime_ssn->mime_boundary.boundary_search = NULL; } else { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Mime boundary found: %s\n", (char *)mime_ssn->mime_boundary.boundary);); mime_ssn->data_state = STATE_MIME_HEADER; } /* get end of line - there could be spaces after boundary before eol */ get_mime_eol(boundary_ptr + mime_search_info.length, data_end_marker, &eol, &eolm); return eol; } } } if ( mime_ssn->state_flags & MIME_FLAG_EMAIL_ATTACH ) { attach_end = data_end_marker; if(attach_start < attach_end) { if(EmailDecode( attach_start, attach_end, decode_state) < DECODE_SUCCESS ) { // MIME_DecodeAlert(); } } } return data_end_marker; } /* * Reset MIME session state */ static void reset_mime_state(MimeState *mime_ssn) { Email_DecodeState *decode_state = (Email_DecodeState *)(mime_ssn->decode_state); if (mime_ssn->mime_boundary.boundary_search != NULL) { search_api->search_instance_free(mime_ssn->mime_boundary.boundary_search); mime_ssn->mime_boundary.boundary_search = NULL; } mime_ssn->data_state = STATE_DATA_INIT; mime_ssn->state_flags = 0; ClearEmailDecodeState(decode_state); memset(&mime_ssn->mime_boundary, 0, sizeof(MimeBoundary)); } static inline FilePosition getFilePoistion(Packet *p) { FilePosition position = SNORT_FILE_POSITION_UNKNOWN; if (PacketHasFullPDU(p)) position = SNORT_FILE_FULL; else if (PacketHasStartOfPDU(p)) position = SNORT_FILE_START; else if (p->packet_flags & PKT_PDU_TAIL) position = SNORT_FILE_END; else if (file_api->get_file_processed_size(p->ssnptr)) position = SNORT_FILE_MIDDLE; return position; } /* * Main function for mime processing * * This should be called when mime data is available */ const uint8_t * process_mime_data(void *packet, const uint8_t *start, const uint8_t *end, const uint8_t *data_end_marker, uint8_t *data_end, MimeState *mime_ssn, bool upload) { Packet *p = (Packet *)packet; FilePosition position = SNORT_FILE_START; /* if we've just entered the data state, check for a dot + end of line * if found, no data */ if ((mime_ssn->data_state == STATE_DATA_INIT) || (mime_ssn->data_state == STATE_DATA_UNKNOWN)) { if ((start < end) && (*start == '.')) { const uint8_t *eol = NULL; const uint8_t *eolm = NULL; get_mime_eol(start, end, &eol, &eolm); /* this means we got a real end of line and not just end of payload * and that the dot is only char on line */ if ((eolm != end) && (eolm == (start + 1))) { /* if we're normalizing and not ignoring data copy data end marker * and dot to alt buffer */ reset_mime_state(mime_ssn); return eol; } } if (mime_ssn->data_state == STATE_DATA_INIT) mime_ssn->data_state = STATE_DATA_HEADER; /* XXX A line starting with a '.' that isn't followed by a '.' is * deleted (RFC 821 - 4.5.2. TRANSPARENCY). If data starts with * '. text', i.e a dot followed by white space then text, some * servers consider it data header and some data body. * Postfix and Qmail will consider the start of data: * . text\r\n * . text\r\n * to be part of the header and the effect will be that of a * folded line with the '.' deleted. Exchange will put the same * in the body which seems more reasonable. */ } /* get end of data body * TODO check last bytes of previous packet to see if we had a partial * end of data */ /* mime_current_search = &mime_data_end_search[0]; data_end_found = search_api->search_instance_find (mime_data_search_mpse, (const char *)start, end - start, 0, search_str_found); if (data_end_found > 0) { data_end_marker = start + mime_search_info.index; data_end = data_end_marker + mime_search_info.length; } else { data_end_marker = data_end = end; } */ setFileDataPtr((uint8_t*)start, (uint16_t)(data_end - start)); if ((mime_ssn->data_state == STATE_DATA_HEADER) || (mime_ssn->data_state == STATE_DATA_UNKNOWN)) { #ifdef DEBUG_MSGS if (mime_ssn->data_state == STATE_DATA_HEADER) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "DATA HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "DATA UNKNOWN STATE ~~~~~~~~~~~~~~~~~~~~~\n");); } #endif start = process_mime_header(p, start, data_end_marker, mime_ssn); if (start == NULL) return NULL; } /* now we shouldn't have to worry about copying any data to the alt buffer * only mime headers if we find them and only if we're ignoring data */ initFilePosition(&position, file_api->get_file_processed_size(p->ssnptr)); while ((start != NULL) && (start < data_end_marker)) { /* multiple MIME attachments in one single packet. * Pipeline the MIME decoded data.*/ if ( mime_ssn->state_flags & MIME_FLAG_MULTIPLE_EMAIL_ATTACH) { DecodeConfig *conf= mime_ssn->decode_conf; int detection_size = getDetectionSize(conf->b64_depth, conf->qp_depth, conf->uu_depth, conf->bitenc_depth, (Email_DecodeState *)(mime_ssn->decode_state) ); setFileDataPtr(((Email_DecodeState *)(mime_ssn->decode_state))->decodePtr, (uint16_t)detection_size); /*Process file type/file signature*/ if (file_api->file_process(p,(uint8_t *)((Email_DecodeState *)(mime_ssn->decode_state))->decodePtr, (uint16_t)((Email_DecodeState *)(mime_ssn->decode_state))->decoded_bytes, position, upload, false) && (isFileStart(position)) && mime_ssn->log_state) { file_api->set_file_name_from_log(&(mime_ssn->log_state->file_log), p->ssnptr); } updateFilePosition(&position, file_api->get_file_processed_size(p->ssnptr)); Detect(p); mime_ssn->state_flags &= ~MIME_FLAG_MULTIPLE_EMAIL_ATTACH; ResetEmailDecodeState((Email_DecodeState *)(mime_ssn->decode_state)); p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT; /* Reset the log count when a packet goes through detection multiple times */ DetectReset((uint8_t *)p->data, p->dsize); } switch (mime_ssn->data_state) { case STATE_MIME_HEADER: DEBUG_WRAP(DebugMessage(DEBUG_FILE, "MIME HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); start = process_mime_header(p, start, data_end_marker, mime_ssn); file_api->finalize_mime_position(p->ssnptr, mime_ssn->decode_state, &position); break; case STATE_DATA_BODY: DEBUG_WRAP(DebugMessage(DEBUG_FILE, "DATA BODY STATE ~~~~~~~~~~~~~~~~~~~~~~~~\n");); start = process_mime_body(p, start, data_end_marker, mime_ssn); break; } } /* We have either reached the end of MIME header or end of MIME encoded data*/ if((mime_ssn->decode_state) != NULL) { DecodeConfig *conf= mime_ssn->decode_conf; int detection_size = getDetectionSize(conf->b64_depth, conf->qp_depth, conf->uu_depth, conf->bitenc_depth, (Email_DecodeState *)(mime_ssn->decode_state) ); setFileDataPtr(((Email_DecodeState *)(mime_ssn->decode_state))->decodePtr, (uint16_t)detection_size); if ((data_end_marker != end)||(mime_ssn->state_flags & MIME_FLAG_MIME_END)) { finalFilePosition(&position); } /*Process file type/file signature*/ /* if (ScPafEnabled() && PacketHasPAFPayload(p)) position = getFilePoistion(p);*/ if (file_api->file_process(p,(uint8_t *)((Email_DecodeState *)(mime_ssn->decode_state))->decodePtr, (uint16_t)((Email_DecodeState *)(mime_ssn->decode_state))->decoded_bytes, position, upload, false) && (isFileStart(position))&& mime_ssn->log_state) { file_api->set_file_name_from_log(&(mime_ssn->log_state->file_log), p->ssnptr); } ResetDecodedBytes((Email_DecodeState *)(mime_ssn->decode_state)); } /* if we got the data end reset state, otherwise we're probably still in the data * to expect more data in next packet */ if (data_end_marker != end) { reset_mime_state(mime_ssn); } return data_end; } /* * This is the initialization funcation for mime processing. * This should be called when snort initializes */ void init_mime(void) { const char *error; int erroffset; const MimeToken *tmp; /* Header search */ mime_hdr_search_mpse = search_api->search_instance_new(); if (mime_hdr_search_mpse == NULL) { FatalError("Could not allocate MIME " "header search.\n"); } for (tmp = &mime_hdrs[0]; tmp->name != NULL; tmp++) { mime_hdr_search[tmp->search_id].name = tmp->name; mime_hdr_search[tmp->search_id].name_len = tmp->name_len; search_api->search_instance_add(mime_hdr_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } search_api->search_instance_prep(mime_hdr_search_mpse); /* create regex for finding boundary string - since it can be cut across multiple * lines, a straight search won't do. Shouldn't be too slow since it will most * likely only be acting on a small portion of data */ mime_boundary_pcre.re = pcre_compile("boundary\\s*=\\s*\"?([^\\s\"]+)\"?", PCRE_CASELESS | PCRE_DOTALL, &error, &erroffset, NULL); if (mime_boundary_pcre.re == NULL) { FatalError("Failed to compile pcre regex for getting boundary " "in a multipart message: %s\n", error); } mime_boundary_pcre.pe = pcre_study(mime_boundary_pcre.re, 0, &error); if (error != NULL) { FatalError("Failed to study pcre regex for getting boundary " "in a multipart message: %s\n", error); } } /* * Free anything that needs it before shutting down preprocessor * * @param none * * @return none */ void free_mime(void) { if (mime_hdr_search_mpse != NULL) search_api->search_instance_free(mime_hdr_search_mpse); if (mime_boundary_pcre.re ) pcre_free(mime_boundary_pcre.re); if (mime_boundary_pcre.pe ) pcre_free(mime_boundary_pcre.pe); } void free_mime_session(MimeState *mime_ssn) { if (!mime_ssn) return; if (mime_ssn->mime_boundary.boundary_search != NULL) { search_api->search_instance_free(mime_ssn->mime_boundary.boundary_search); mime_ssn->mime_boundary.boundary_search = NULL; } if(mime_ssn->decode_state != NULL) { mempool_free(mime_ssn->mime_mempool, mime_ssn->decode_bkt); free(mime_ssn->decode_state); } if(mime_ssn->log_state != NULL) { mempool_free(mime_ssn->log_mempool, mime_ssn->log_state->log_hdrs_bkt); free(mime_ssn->log_state); } free(mime_ssn); } /* * When the file ends (a MIME boundary detected), position are updated */ void finalize_mime_position(void *ssnptr, void *decode_state, FilePosition *position) { /* check to see if there are file data in the session or * new decoding data waiting for processing */ if( file_api->get_file_processed_size(ssnptr) || (decode_state && ((Email_DecodeState *)decode_state)->decoded_bytes) ) finalFilePosition(position); } static inline uint8_t* find_boundary (const uint8_t* data, uint32_t len, MimePafData *pfdata) { uint32_t index = 0; uint32_t b_end = 0; MimePafState state = pfdata->state; /* start from end*/ while (index < len) { uint8_t val = data[index]; switch (state) { case MIME_PAF_UNKNOWN: if (val == '\n') { state = MIME_PAF_FIRST_LF; } break; case MIME_PAF_FIRST_LF: if (val == '\n') { state = MIME_PAF_SECOND_LF; b_end = index; } else if ((val != '.') && (val != '\r') && (val != ')')) { state = MIME_PAF_UNKNOWN; } break; case MIME_PAF_SECOND_LF: /* include all continous crlf and . ) in the flushed packet * It might flush for pattern \r\n.)\r\n, but this should be ok * when this is inside MIME body. This won't happen for MIME header * because this means ')' is an illegal header field. */ if ((val == '\r') || (val == '\n') || (val == '.') || (val == ')')) { b_end++; } else { state = MIME_PAF_UNKNOWN; } break; default: state = MIME_PAF_UNKNOWN; break; } index++; } pfdata->state = state; if (!b_end) { pfdata->state = state; return NULL; } return ( (uint8_t *)data + b_end + 1); } /* flush at double CRLF or end of data*/ static PAF_Status mime_paf(void* ssn, void** ps, const uint8_t* data, uint32_t len, uint32_t flags, uint32_t* fp) { MimePafData *pfdata = *(MimePafData **)ps; uint8_t* boundary_end; if (pfdata == NULL) { pfdata = calloc(1, sizeof(*pfdata)); if (pfdata == NULL) { return PAF_ABORT; } *ps = pfdata; pfdata->state = MIME_PAF_UNKNOWN; } if ((boundary_end = find_boundary(data, len, pfdata))) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Find boundary!\n");); pfdata->is_data = true; *fp = boundary_end - data; return PAF_FLUSH; } if ((!pfdata->is_data ) && (pfdata->state == MIME_PAF_FIRST_LF)) { *fp = len; return PAF_FLUSH; } return PAF_SEARCH; } #ifdef TARGET_BASED void register_mime_paf_service (struct _SnortConfig *sc, int16_t app, tSfPolicyId policy) { if (ScPafEnabled()) { stream_api->register_paf_service(sc, policy, app, true, mime_paf, true); stream_api->register_paf_service(sc, policy, app, false, mime_paf, true); } } #endif void register_mime_paf_port(struct _SnortConfig *sc, unsigned int i, tSfPolicyId policy) { if (ScPafEnabled()) { stream_api->register_paf_port(sc, policy, (uint16_t)i, true, mime_paf, true); stream_api->register_paf_port(sc, policy, (uint16_t)i, false, mime_paf, true); } } snort-2.9.6.0/src/file-process/file_api.h0000644000000000000000000005075312260565732015047 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * ** Copyright (C) 2012-2013 Sourcefire, Inc. * ** AUTHOR: Hui Cao * ** * ** This program is free software; you can redistribute it and/or modify * ** it under the terms of the GNU General Public License Version 2 as * ** published by the Free Software Foundation. You may not use, modify or * ** distribute this program under any other version of the GNU General * ** Public License. * ** * ** This program is distributed in the hope that it will be useful, * ** but WITHOUT ANY WARRANTY; without even the implied warranty of * ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ** GNU General Public License for more details. * ** * ** You should have received a copy of the GNU General Public License * ** along with this program; if not, write to the Free Software * ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /* file_api.h * * Purpose: Definition of the FileAPI. To be used as a common interface * for file process access for other preprocessors and detection * plugins. * * Author(s): Hui Cao * * NOTES * 5.25.12 - Initial Source Code. Hcao */ #ifndef FILE_API_H_ #define FILE_API_H_ #ifdef HAVE_CONFIG_H #include #endif #include #include "sfPolicy.h" #define ENABLE_FILE_TYPE_IDENTIFICATION 0x1 #define ENABLE_FILE_SIGNATURE_SHA256 0x2 #define ENABLE_FILE_CAPTURE 0x4 #define FILE_ALL_ON 0xFFFFFFFF #define FILE_ALL_OFF 0x00000000 #define MAX_FILE 1024 #define MAX_EMAIL 1024 #define FILE_RESUME_BLOCK 0x01 #define FILE_RESUME_LOG 0x02 /* * Generator id. Define here the same as the official register * in generators.h */ #define GENERATOR_FILE_TYPE 146 #define GENERATOR_FILE_SIGNATURE 147 #define FILE_SIGNATURE_SHA256 1 #define FILE_SIGNATURE_SHA256_STR "(file) malware detected" typedef enum _File_Verdict { FILE_VERDICT_UNKNOWN = 0, FILE_VERDICT_LOG, FILE_VERDICT_STOP, FILE_VERDICT_BLOCK, FILE_VERDICT_REJECT, FILE_VERDICT_PENDING, FILE_VERDICT_STOP_CAPTURE, FILE_VERDICT_MAX } File_Verdict; typedef enum _FilePosition { SNORT_FILE_POSITION_UNKNOWN, SNORT_FILE_START, SNORT_FILE_MIDDLE, SNORT_FILE_END, SNORT_FILE_FULL } FilePosition; typedef enum _FileCaptureState { FILE_CAPTURE_SUCCESS = 0, FILE_CAPTURE_MIN, /*smaller than file capture min*/ FILE_CAPTURE_MAX, /*larger than file capture max*/ FILE_CAPTURE_MEMCAP, /*memcap reached, no more file buffer*/ FILE_CAPTURE_FAIL /*Other file capture failures*/ } FileCaptureState; typedef enum _FileSigState { FILE_SIG_PROCESSING = 0, FILE_SIG_DEPTH_FAIL, /*larger than file signature depth*/ FILE_SIG_DONE } FileSigState; typedef enum _FileProcessType { SNORT_FILE_TYPE_ID, SNORT_FILE_SHA256, SNORT_FILE_CAPTURE } FileProcessType; typedef struct _FileState { FileCaptureState capture_state; FileSigState sig_state; } FileState; typedef struct s_FILE_LogState { uint8_t *filenames; uint16_t file_logged; uint16_t file_current; uint16_t file_name; } FILE_LogState; typedef struct s_MAIL_LogState { void *log_hdrs_bkt; unsigned char *emailHdrs; uint32_t log_depth; uint32_t hdrs_logged; uint8_t *recipients; uint16_t rcpts_logged; uint8_t *senders; uint16_t snds_logged; FILE_LogState file_log; }MAIL_LogState; typedef struct s_MAIL_LogConfig { uint32_t memcap; char log_mailfrom; char log_rcptto; char log_filename; char log_email_hdrs; uint32_t email_hdrs_log_depth; }MAIL_LogConfig; /* Max length of boundary string, defined in RFC 2046 */ #define MAX_MIME_BOUNDARY_LEN 70 typedef struct _MimeBoundary { int state; char boundary[2 + MAX_MIME_BOUNDARY_LEN + 1]; /* '--' + MIME boundary string + '\0' */ int boundary_len; void *boundary_search; } MimeBoundary; typedef struct _DecodeConfig { int max_mime_mem; int max_depth; int b64_depth; int qp_depth; int bitenc_depth; int uu_depth; int64_t file_depth; } DecodeConfig; typedef struct _MimeState { int data_state; int state_flags; int log_flags; void *decode_state; MimeBoundary mime_boundary; DecodeConfig *decode_conf; MAIL_LogConfig *log_config; MAIL_LogState *log_state; void *decode_bkt; void *mime_mempool; void *log_mempool; } MimeState; struct _FileCaptureInfo; typedef struct _FileCaptureInfo FileCaptureInfo; struct _SnortConfig; struct _FileContext; #define FILE_API_VERSION 4 #define DEFAULT_FILE_ID 0 typedef uint32_t (*File_policy_callback_func) (void* ssnptr, int16_t app_id, bool upload); typedef File_Verdict (*File_type_callback_func) (void* p, void* ssnptr, uint32_t file_type_id, bool upload, uint32_t file_id); typedef File_Verdict (*File_signature_callback_func) (void* p, void* ssnptr, uint8_t* file_sig, uint64_t file_size, FileState *state, bool upload, uint32_t file_id); typedef void (*Log_file_action_func) (void* ssnptr, int action); typedef int (*File_process_func)( void* p, uint8_t* file_data, int data_size, FilePosition position, bool upload, bool suspend_block_verdict); typedef int (*Get_file_name_func) (void* ssnptr, uint8_t **file_name, uint32_t *name_len); typedef uint64_t (*Get_file_size_func) (void* ssnptr); typedef bool (*Get_file_direction_func) (void* ssnptr); typedef uint8_t *(*Get_file_sig_sha256_func) (void* ssnptr); typedef void (*Set_file_name_func) (void* ssnptr, uint8_t *, uint32_t); typedef void (*Set_file_direction_func) (void* ssnptr, bool); typedef int64_t (*Get_file_depth_func) (void); typedef void (*Set_file_policy_func)(File_policy_callback_func); typedef void (*Enable_file_type_func)(File_type_callback_func); typedef void (*Enable_file_signature_func)(File_signature_callback_func); typedef void (*Enable_file_capture_func)(File_signature_callback_func); typedef void (*Set_file_action_log_func)(Log_file_action_func); typedef int (*Log_file_name_func)(const uint8_t *start, int length, FILE_LogState *log_state, bool *disp_cont); typedef void (*Set_file_name_from_log_func)(FILE_LogState *log_state, void *ssn); typedef int (*Set_log_buffers_func)(MAIL_LogState **log_state, MAIL_LogConfig *conf, void *mempool); typedef void* (*Init_mime_mempool_func)(int max_mime_mem, int max_depth, void *mempool, const char *preproc_name); typedef void* (*Init_log_mempool_func)(uint32_t email_hdrs_log_depth, uint32_t memcap, void *mempool, const char *preproc_name); typedef int (*File_resume_block_add_file_func)(void *pkt, uint32_t file_sig, uint32_t timeout, File_Verdict verdict, uint32_t file_type_id, uint8_t *signature); typedef File_Verdict (*File_resume_block_check_func)(void *pkt, uint32_t file_sig); typedef uint32_t (*Str_to_hash_func)(uint8_t *str, int length ); typedef void (*File_signature_lookup_func)(void* p, bool is_retransmit); typedef void (*Set_mime_decode_config_defaults_func)(DecodeConfig *decode_conf); typedef void (*Set_mime_log_config_defaults_func)(MAIL_LogConfig *log_config); typedef int (*Parse_mime_decode_args_func)(DecodeConfig *decode_conf, char *arg, const char *preproc_name); typedef const uint8_t * (*Process_mime_data_func)(void *packet, const uint8_t *start, const uint8_t *end, const uint8_t *data_end_marker, uint8_t *data_end, MimeState *mime_ssn, bool upload); typedef void (*Free_mime_session_func)(MimeState *mime_ssn); typedef bool (*Is_decoding_enabled_func)(DecodeConfig *decode_conf); typedef bool (*Is_decoding_conf_changed_func)(DecodeConfig *configNext, DecodeConfig *config, const char *preproc_name); typedef bool (*Is_mime_log_enabled_func)(MAIL_LogConfig *log_config); typedef void (*Finalize_mime_position_func)(void *ssnptr, void *decode_state, FilePosition *position); typedef File_Verdict (*Get_file_verdict_func)(void *ssnptr); typedef void (*Render_block_verdict_func)(void *ctx, void *p); typedef FileCaptureState (*Reserve_file_func)(void *ssnptr, FileCaptureInfo **file_mem); typedef void* (*Get_file_func)(FileCaptureInfo *file_mem, uint8_t **buff, int *size); typedef void (*Release_file_func)(FileCaptureInfo *data); typedef size_t (*File_capture_size_func)(FileCaptureInfo *file_mem); typedef bool (*Is_file_service_enabled)(void); typedef void (*Register_mime_paf_service) (struct _SnortConfig *sc, int16_t app, tSfPolicyId policy); typedef void (*Register_mime_paf_port) (struct _SnortConfig *sc, unsigned int i, tSfPolicyId policy); typedef void (*Update_file_name_func) (MAIL_LogState *log_state); #if defined(FEAT_FILE_INSPECT) typedef uint32_t (*Get_file_type_id)(void *); #endif /* FEAT_FILE_INSPECT */ /*Context based file process functions*/ typedef struct _FileContext* (*Create_file_context_func)(void *ssnptr); typedef struct _FileContext* (*Get_file_context_func)(void *ssnptr); typedef bool (*Set_file_context_func)(void *ssnptr, struct _FileContext *ctx); typedef int (*Process_file_func)( struct _FileContext *ctx, void *p, uint8_t *file_data, int data_size, FilePosition position, bool suspend_block_verdict); typedef struct _file_api { int version; /* Check if file type id is enabled. * * Arguments: None * * Returns: * (bool) true file processing is enabled * (bool) false file processing is disabled */ Is_file_service_enabled is_file_service_enabled; /* File process function, called by preprocessors that provides file data * * Arguments: * void* p: packet pointer * uint8_t* file_data: file data * int data_size: file data size * FilePosition: file position * bool upload: upload or not * Returns: * 1: continue processing/log/block this file * 0: ignore this file (no further processing needed) */ File_process_func file_process; /*-----File property functions--------*/ /* Get file name and the length of file name * Note: this is updated after file processing. It will be available * for file event logging, but might not be available during file type * callback or file signature callback, because those callbacks are called * during file processing. * * Arguments: * void* ssnptr: session pointer * uint8_t **file_name: address for file name to be saved * uint32_t *name_len: address to save file name length * Returns * 1: file name available, * 0: file name is unavailable */ Get_file_name_func get_file_name; /* Get file size * Note: this is updated after file processing. It will be available * for file event logging, but might not be available during file type * callback or file signature callback, because those callbacks are called * during file processing. * * Arguments: * void* ssnptr: session pointer * * Returns * uint64_t: file size * Note: 0 means file size is unavailable */ Get_file_size_func get_file_size; /* Get number of bytes processed * * Arguments: * void* ssnptr: session pointer * * Returns * uint64_t: processed file data size */ Get_file_size_func get_file_processed_size; /* Get file direction * * Arguments: * void* ssnptr: session pointer * * Returns * 1: upload * 0: download */ Get_file_direction_func get_file_direction; /* Get file signature sha256 * * Arguments: * void* ssnptr: session pointer * * Returns * char *: pointer to sha256 * NULL: sha256 is not available */ Get_file_sig_sha256_func get_sig_sha256; /* Set file name and the length of file name * * Arguments: * void* ssnptr: session pointer * uint8_t *file_name: file name to be saved * uint32_t name_len: file name length * Returns * None */ Set_file_name_func set_file_name; /* Get file direction * * Arguments: * void* ssnptr: session pointer * bool: * 1 - upload * 0 - download * Returns * None */ Set_file_direction_func set_file_direction; /*----------File call backs--------------*/ /* Set file policy callback. This callback is called in the beginning * of session. This callback will decide whether to do file type ID, * file signature, or file capture * * Arguments: * File_policy_callback_func * Returns * None */ Set_file_policy_func set_file_policy_callback; /* Enable file type ID and set file type callback. * File type callback is called when file type is identified. Callback * will return a verdict based on file type * * Arguments: * File_type_callback_func * Returns * None */ Enable_file_type_func enable_file_type; /* Enable file signature and set file signature callback. * File signature callback is called when file signature is calculated. * Callback will return a verdict based on file signature. * SHA256 is calculated after file transfer is finished. * * Arguments: * File_signature_callback_func * Returns * None */ Enable_file_signature_func enable_file_signature; /* Enable file capture and set file signature callback. * File signature callback is called when file signature is calculated. * Callback will return a verdict based on file signature. * SHA256 is calculated after file transfer is finished. * * Note: file signature and file capture will use the same callback, but * enabled separately. * * Arguments: * File_signature_callback_func * Returns * None */ Enable_file_signature_func enable_file_capture; /* Set file action log callback. * File action log callback is called when file resume is detected. * It allows file events to be generated for a resumed file download * * Arguments: * Log_file_action_func * Returns * None */ Set_file_action_log_func set_file_action_log_callback; /*--------------File configurations-------------*/ /* Get file depth required for all file processings enabled * * Arguments: * None * * Returns: * int64_t: file depth in bytes */ Get_file_depth_func get_max_file_depth; /*--------------Common functions used for MIME processing-------------*/ Log_file_name_func log_file_name; Update_file_name_func update_file_name; Set_file_name_from_log_func set_file_name_from_log; Set_log_buffers_func set_log_buffers; Init_mime_mempool_func init_mime_mempool; Init_log_mempool_func init_log_mempool; Set_mime_decode_config_defaults_func set_mime_decode_config_defauts; Set_mime_log_config_defaults_func set_mime_log_config_defauts; Parse_mime_decode_args_func parse_mime_decode_args; Process_mime_data_func process_mime_data; Free_mime_session_func free_mime_session; Is_decoding_enabled_func is_decoding_enabled; Is_decoding_conf_changed_func is_decoding_conf_changed; Is_mime_log_enabled_func is_mime_log_enabled; Finalize_mime_position_func finalize_mime_position; /*--------------Other helper functions-------------*/ File_resume_block_add_file_func file_resume_block_add_file; File_resume_block_check_func file_resume_block_check; Str_to_hash_func str_to_hash; File_signature_lookup_func file_signature_lookup; Get_file_verdict_func get_file_verdict; Render_block_verdict_func render_block_verdict; /* * Preserve the file in memory until it is released * This function must be called in packet processing thread * Arguments: * void *ssnptr: session pointer * void **file_mem: the pointer to store the memory block * that stores file and its metadata. * It will set NULL if no memory or fail to store * * Returns: * FileCaptureState: * FILE_CAPTURE_SUCCESS = 0, * FILE_CAPTURE_MIN, * FILE_CAPTURE_MAX, * FILE_CAPTURE_MEMCAP, * FILE_CAPTURE_FAIL */ Reserve_file_func reserve_file; /* * Get the file that is reserved in memory. To get a full file, * this function must be called iteratively until NULL is returned * This function can be called in out of band thread * * Arguments: * void *file_mem: the memory block working on * uint8_t **buff: address to store buffer address * int *size: address to store size of file * * Returns: * the next memory block * If NULL: no memory or fail to get file */ Get_file_func read_file; /* * Get the file size captured in the file buffer * This function can be called in out of band thread * * Arguments: * void *file_mem: the first memory block of file buffer * * Returns: * the size of file * If 0: no memory or fail to read file */ File_capture_size_func get_file_capture_size; /* * Release the file that is reserved in memory. * This function can be called in out of band thread. * * Arguments: * void *data: the memory block that stores file and its metadata * * Returns: * None */ Release_file_func release_file; #if defined(FEAT_FILE_INSPECT) /* Return the file rule id associated with a session. * * Arguments: * void *ssnptr: session pointer * * Returns: * (u32) file-rule id on session; FILE_TYPE_UNKNOWN otherwise. */ Get_file_type_id get_file_type_id; #endif /* FEAT_FILE_INSPECT */ #ifdef TARGET_BASED Register_mime_paf_service register_mime_paf_service; #endif Register_mime_paf_port register_mime_paf_port; /* Create a file context to use * * Arguments: * void* ssnptr: session pointer * Returns: * FileContext *: file context created. */ Create_file_context_func create_file_context; /* Set file context to be the current * * Arguments: * void* ssnptr: session pointer * FileContext *: file context that will be current * Returns: * True: changed successfully * False: fail to change */ Set_file_context_func set_current_file_context; /* Get current file context * * Arguments: * void* ssnptr: session pointer * Returns: * FileContext *: current file context */ Get_file_context_func get_current_file_context; /* Get main file context that used by preprocessors * * Arguments: * void* ssnptr: session pointer * Returns: * FileContext *: main file context */ Get_file_context_func get_main_file_context; /* Process file function, called by preprocessors that provides file data * * Arguments: * void* ctx: file context that will be processed * void* p: packet pointer * uint8_t* file_data: file data * int data_size: file data size * FilePosition: file position * bool suspend_block_verdict: used for smb to allow file pass * Returns: * 1: continue processing/log/block this file * 0: ignore this file (no further processing needed) */ Process_file_func process_file; } FileAPI; /* To be set by Stream5 */ extern FileAPI *file_api; static inline void initFilePosition(FilePosition *position, uint64_t processed_size) { *position = SNORT_FILE_START; if (processed_size) *position = SNORT_FILE_MIDDLE; } static inline void updateFilePosition(FilePosition *position, uint64_t processed_size) { if ((*position == SNORT_FILE_END) || (*position == SNORT_FILE_FULL)) *position = SNORT_FILE_START; else if (processed_size) *position = SNORT_FILE_MIDDLE; } static inline void finalFilePosition(FilePosition *position) { if (*position == SNORT_FILE_START) *position = SNORT_FILE_FULL; else if (*position != SNORT_FILE_FULL) *position = SNORT_FILE_END; } static inline bool isFileStart(FilePosition position) { return ((position == SNORT_FILE_START) || (position == SNORT_FILE_FULL)); } static inline bool isFileEnd(FilePosition position) { return ((position == SNORT_FILE_END) || (position == SNORT_FILE_FULL)); } #endif /* FILE_API_H_ */ snort-2.9.6.0/src/file-process/file_service_config.h0000644000000000000000000000370212260565732017253 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.2012 - Initial Source Code. Hcao */ #ifndef __FILE_SERVICE_CONFIG_H__ #define __FILE_SERVICE_CONFIG_H__ /* Default file type/signature/capture values. */ /* configure file services * * Args: * char *args: configuration string * void *file_config: pointer to file config */ void file_service_config(char *args, void *file_config); /* Create file service configuration and set default values * * Return: * void *: pointer to file configuration */ void* file_service_config_create(void); # ifdef SNORT_RELOAD /* Verify whether file configuration is valid * changing memory settings and depth settings * requires snort restart * * Return * 0: valid * -1: invalid */ int file_sevice_config_verify(SnortConfig *old, SnortConfig *new); /* Force reconfigure file service * * Args: * true: reconfigure file service * false: no change */ void file_sevice_reconfig_set(bool reconfigured); # endif /* ifdef SNORT_RELOAD */ #endif /* #ifndef __FILE_SERVICE_CONFIG_H__ */ snort-2.9.6.0/src/file-process/file_service_config.c0000644000000000000000000004042012260565732017244 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.2012 - Initial Source Code. Hcao */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "sf_types.h" #include "util.h" #include "mstring.h" #include "parser.h" #include "file_service_config.h" #include "file_config.h" #include "file_lib.h" #include "file_capture.h" #define FILE_SERVICE_OPT__TYPE_DEPTH "file_type_depth" #define FILE_SERVICE_OPT__SIG_DEPTH "file_signature_depth" #define FILE_SERVICE_OPT__BLOCK_TIMEOUT "file_block_timeout" #define FILE_SERVICE_OPT__LOOKUP_TIMEOUT "file_lookup_timeout" #define FILE_SERVICE_OPT__BLOCK_TIMEOUT_LOOKUP "block_timeout_lookup" #define FILE_SERVICE_OPT__CAPTURE_MEMCAP "file_capture_memcap" #define FILE_SERVICE_OPT__CAPTURE_MAX_SIZE "file_capture_max" #define FILE_SERVICE_OPT__CAPTURE_MIN_SIZE "file_capture_min" #define FILE_SERVICE_OPT__CAPTURE_BLOCK_SIZE "file_capture_block_size" #define FILE_SERVICE_TYPE_DEPTH_MIN 0 #define FILE_SERVICE_TYPE_DEPTH_MAX UINT32_MAX #define FILE_SERVICE_SIG_DEPTH_MIN 0 #define FILE_SERVICE_SIG_DEPTH_MAX UINT32_MAX #define FILE_SERVICE_BLOCK_TIMEOUT_MIN 0 #define FILE_SERVICE_BLOCK_TIMEOUT_MAX UINT32_MAX #define FILE_SERVICE_LOOKUP_TIMEOUT_MIN 0 #define FILE_SERVICE_LOOKUP_TIMEOUT_MAX UINT32_MAX #define FILE_SERVICE_CAPTURE_MEMCAP_MIN 1 #define FILE_SERVICE_CAPTURE_MEMCAP_MAX UINT32_MAX #define FILE_SERVICE_CAPTURE_MAX_SIZE_MIN 0 #define FILE_SERVICE_CAPTURE_MAX_SIZE_MAX UINT32_MAX #define FILE_SERVICE_CAPTURE_MIN_SIZE_MIN 0 #define FILE_SERVICE_CAPTURE_MIN_SIZE_MAX UINT32_MAX #define FILE_SERVICE_CAPTURE_BLOCK_SIZE_MIN 8 /*at least 64bits*/ #define FILE_SERVICE_CAPTURE_BLOCK_SIZE_MAX UINT32_MAX #define DEFAULT_FILE_TYPE_DEPTH 1460 // 1460 B #define DEFAULT_FILE_SIGNATURE_DEPTH 10485760 // 10 MiB #define DEFAULT_FILE_SHOW_DATA_DEPTH 100 // 100 B #define DEFAULT_FILE_BLOCK_TIMEOUT 86400 // 1 day #define DEFAULT_FILE_LOOKUP_TIMEOUT 2 // 2 seconds #define DEFAULT_FILE_CAPTURE_MEM 100 // 100 MiB #define DEFAULT_FILE_CAPTURE_MAX_SIZE 1048576 // 1 MiB #define DEFAULT_FILE_CAPTURE_MIN_SIZE 0 // 0 #define DEFAULT_FILE_CAPTURE_BLOCK_SIZE 32768 // 32 KiB #if defined(DEBUG_MSGS) || defined (REG_TEST) #define FILE_SERVICE_OPT__TYPE "type_id" #define FILE_SERVICE_OPT__SIG "signature" #define FILE_SERVICE_OPT__SHOW_DATA_DEPTH "show_data_depth" #include "file_api.h" #endif #ifdef SNORT_RELOAD bool file_service_reconfigured = false; #endif /*Set default values for file config*/ static inline void file_service_config_defaults(FileConfig *file_config) { file_config->file_type_depth = DEFAULT_FILE_TYPE_DEPTH; file_config->file_signature_depth = DEFAULT_FILE_SIGNATURE_DEPTH; file_config->file_block_timeout = DEFAULT_FILE_BLOCK_TIMEOUT; file_config->file_lookup_timeout = DEFAULT_FILE_LOOKUP_TIMEOUT; file_config->block_timeout_lookup = false; #if defined(DEBUG_MSGS) || defined (REG_TEST) file_config->show_data_depth = DEFAULT_FILE_SHOW_DATA_DEPTH; #endif file_config->file_capture_memcap = DEFAULT_FILE_CAPTURE_MEM; file_config->file_capture_max_size = DEFAULT_FILE_CAPTURE_MAX_SIZE; file_config->file_capture_min_size = DEFAULT_FILE_CAPTURE_MIN_SIZE; file_config->file_capture_block_size = DEFAULT_FILE_CAPTURE_BLOCK_SIZE; } void* file_service_config_create(void) { FileConfig *file_config = SnortAlloc(sizeof(*file_config)); file_service_config_defaults(file_config); return file_config; } #ifdef SNORT_RELOAD /* Force reconfigure file service * * Args: * true: reconfigure file service * false: no change */ void file_sevice_reconfig_set(bool reconfigured) { file_service_reconfigured = reconfigured; } /* Verify the file service configuration, changing memory settings and depth * settings requires snort restart */ int file_sevice_config_verify(SnortConfig *old, SnortConfig *new) { FileConfig *curr = (FileConfig *)old->file_config; FileConfig *next = (FileConfig *)new->file_config; FileConfig tmp; /*no file config on both*/ if ((!curr) && (!next)) return 0; /* use default value if nothing sets*/ if (!curr) { curr = &tmp; file_service_config_defaults(curr); } if (!next) { next = &tmp; file_service_config_defaults(next); } /* Enable file type, file signature or file capture requires a restart*/ if (file_service_reconfigured) { ErrorMessage("File service: enable/disable file service" " requires a restart.\n"); file_service_reconfigured = false; return -1; } /* check configurations */ if (curr->file_capture_memcap != next->file_capture_memcap) { ErrorMessage("File service: Changing file capture memcap" " requires a restart.\n"); return -1; } if (curr->file_capture_max_size != next->file_capture_max_size) { ErrorMessage("File service: Changing file capture max size" " requires a restart.\n"); return -1; } if (curr->file_capture_block_size != next->file_capture_block_size) { ErrorMessage("File service: Changing file capture block size" " requires a restart.\n"); return -1; } /*Change depth requires restart*/ if (curr->file_signature_depth != next->file_signature_depth) { ErrorMessage("File service: Changing file signature depth" " requires a restart.\n"); return -1; } if (curr->file_type_depth != next->file_type_depth) { ErrorMessage("File service: Changing file type depth" " requires a restart.\n"); return -1; } return 0; } #endif /* Display the configuration for the File preprocessor. * * PARAMETERS: None. * * RETURNS: Nothing. */ static void file_service_display_conf(FileConfig *config) { if (config == NULL) return; LogMessage("\n"); LogMessage("File service config: \n"); LogMessage(" File type depth: "STDi64" %s \n", config->file_type_depth, config->file_type_depth == DEFAULT_FILE_TYPE_DEPTH ? "(Default) bytes" : " bytes" ); LogMessage(" File signature depth: "STDi64" %s \n", config->file_signature_depth, config->file_signature_depth == DEFAULT_FILE_SIGNATURE_DEPTH ? "(Default) bytes" : " bytes" ); LogMessage(" File block timeout: "STDi64" %s \n", config->file_block_timeout, config->file_block_timeout == DEFAULT_FILE_BLOCK_TIMEOUT ? "(Default) seconds" : " seconds" ); LogMessage(" File lookup timeout: "STDi64" %s \n", config->file_lookup_timeout, config->file_lookup_timeout == DEFAULT_FILE_LOOKUP_TIMEOUT ? "(Default) seconds" : " seconds" ); LogMessage(" Action for lookup timeout: %s\n", config->block_timeout_lookup ? "BLOCKED":"ALLOWED (Default)"); LogMessage(" File capture memcap: "STDi64" %s \n", config->file_capture_memcap, config->file_capture_memcap == DEFAULT_FILE_CAPTURE_MEM ? "(Default) megabytes" : " megabytes" ); LogMessage(" File capture block size: "STDi64" %s \n", config->file_capture_block_size, config->file_capture_block_size == DEFAULT_FILE_CAPTURE_BLOCK_SIZE ? "(Default) bytes" : " bytes" ); LogMessage(" File capture max size: "STDi64" %s \n", config->file_capture_max_size, config->file_capture_max_size == DEFAULT_FILE_CAPTURE_MAX_SIZE ? "(Default) bytes" : " bytes" ); LogMessage(" File capture min size: "STDi64" %s \n", config->file_capture_min_size, config->file_capture_min_size == DEFAULT_FILE_CAPTURE_MIN_SIZE ? "(Default) bytes" : " bytes" ); LogMessage("\n"); } /*The main function for parsing rule option*/ void file_service_config(char *args, void *conf) { char **toks; int num_toks; int i; FileConfig *file_config = (FileConfig *)conf; #if defined(DEBUG_MSGS) || defined (REG_TEST) bool file_type_enabled = false; bool file_signature_enabled = false; #endif DEBUG_WRAP(DebugMessage(DEBUG_FILE,"Loading file service configuration: %s\n", args);); if (!file_config) { return; } file_service_config_defaults(file_config); toks = mSplit(args, ",", 0, &num_toks, 0); /* get rule option pairs */ for (i = 0; i < num_toks; i++) { char **opts; int num_opts; char *option_args = NULL; unsigned long value = 0; DEBUG_WRAP(DebugMessage(DEBUG_FILE," option: %s\n", toks[i]);); /* break out the option name from its data */ opts = mSplit(toks[i], " ", 3, &num_opts, '\\'); DEBUG_WRAP(DebugMessage(DEBUG_FILE," option name: %s\n", opts[0]);); if (num_opts == 2) { option_args = opts[1]; DEBUG_WRAP(DebugMessage(DEBUG_FILE," option args: %s\n", option_args);); } if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__TYPE_DEPTH )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__TYPE_DEPTH, FILE_SERVICE_TYPE_DEPTH_MIN, FILE_SERVICE_TYPE_DEPTH_MAX, &value); file_config->file_type_depth = (int64_t)value; if (file_config->file_type_depth == 0) file_config->file_type_depth = FILE_SERVICE_TYPE_DEPTH_MAX; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__SIG_DEPTH )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__SIG_DEPTH, FILE_SERVICE_SIG_DEPTH_MIN, FILE_SERVICE_SIG_DEPTH_MAX, &value); file_config->file_signature_depth = (int64_t)value; if (file_config->file_signature_depth == 0) file_config->file_signature_depth = FILE_SERVICE_SIG_DEPTH_MAX; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__BLOCK_TIMEOUT )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__BLOCK_TIMEOUT, FILE_SERVICE_BLOCK_TIMEOUT_MIN, FILE_SERVICE_BLOCK_TIMEOUT_MAX, &value); file_config->file_block_timeout = (int64_t)value; if (file_config->file_block_timeout == 0) file_config->file_block_timeout = FILE_SERVICE_BLOCK_TIMEOUT_MAX; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__LOOKUP_TIMEOUT )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__LOOKUP_TIMEOUT, FILE_SERVICE_LOOKUP_TIMEOUT_MIN, FILE_SERVICE_LOOKUP_TIMEOUT_MAX, &value); file_config->file_lookup_timeout = (int64_t)value; if (file_config->file_lookup_timeout == 0) file_config->file_lookup_timeout = FILE_SERVICE_LOOKUP_TIMEOUT_MAX; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__BLOCK_TIMEOUT_LOOKUP )) { file_config->block_timeout_lookup = true; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__CAPTURE_MEMCAP )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__CAPTURE_MEMCAP, FILE_SERVICE_CAPTURE_MEMCAP_MIN, FILE_SERVICE_CAPTURE_MEMCAP_MAX, &value); file_config->file_capture_memcap = (int64_t) value; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__CAPTURE_MAX_SIZE )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__CAPTURE_MAX_SIZE, FILE_SERVICE_CAPTURE_MAX_SIZE_MIN, FILE_SERVICE_CAPTURE_MAX_SIZE_MAX, &value); file_config->file_capture_max_size = (int64_t) value; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__CAPTURE_MIN_SIZE )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__CAPTURE_MIN_SIZE, FILE_SERVICE_CAPTURE_MIN_SIZE_MIN, FILE_SERVICE_CAPTURE_MIN_SIZE_MAX, &value); file_config->file_capture_min_size = (int64_t)value; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__CAPTURE_BLOCK_SIZE )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__CAPTURE_BLOCK_SIZE, FILE_SERVICE_CAPTURE_BLOCK_SIZE_MIN, FILE_SERVICE_CAPTURE_BLOCK_SIZE_MAX, &value); file_config->file_capture_block_size = (int64_t) value; } #if defined(DEBUG_MSGS) || defined (REG_TEST) else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__TYPE )) { file_type_enabled = true; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__SIG )) { file_signature_enabled = true; } else if ( !strcasecmp( opts[0], FILE_SERVICE_OPT__SHOW_DATA_DEPTH )) { CheckValueInRange(option_args, FILE_SERVICE_OPT__SHOW_DATA_DEPTH, FILE_SERVICE_SIG_DEPTH_MIN, FILE_SERVICE_SIG_DEPTH_MAX, &value); file_config->show_data_depth = (int64_t)value; if (file_config->show_data_depth == 0) file_config->show_data_depth = FILE_SERVICE_SIG_DEPTH_MAX; } #endif else { ParseError("File service: Invalid argument: %s\n", opts[0]); return; } mSplitFree(&opts, num_opts); } #if defined(DEBUG_MSGS) || defined (REG_TEST) if (file_type_enabled) file_api->enable_file_type(NULL); if (file_signature_enabled) file_api->enable_file_signature(NULL); #endif /* file capture memcap should not be larger file capture block size*/ if (file_config->file_capture_block_size > (file_config->file_capture_memcap << 20)) { ParseError("File service: file capture block size ("STDi64")" " is larger than file capture memcap ("STDi64") bytes.", file_config->file_capture_block_size, file_config->file_capture_memcap << 20); } /* file capture size should not be larger file signature depth*/ if (file_config->file_capture_max_size > file_config->file_signature_depth) { ParseError("File service: file capture max size ("STDi64") " "is larger than file signature depth ("STDi64").", file_config->file_capture_max_size, file_config->file_signature_depth); } /* file capture min size should not be larger file capture max size*/ if (file_config->file_capture_min_size > file_config->file_capture_max_size) { ParseError("File service: file capture min size ("STDi64") " "is larger than file capture max size ("STDi64").", file_config->file_capture_min_size, file_config->file_capture_max_size); } file_service_display_conf(file_config); mSplitFree(&toks, num_toks); } snort-2.9.6.0/src/file-process/file_service.h0000644000000000000000000000303312260565732015723 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.12 - Initial Source Code. Hcao */ #ifndef __FILE_SERVICE_H__ #define __FILE_SERVICE_H__ #include "file_service_config.h" #include "file_lib.h" /* Initialize file API, this must be called when snort restarts */ void init_fileAPI(void); /* Free file configuration, this must be called when snort reloads/restarts*/ void free_file_config(void*); void FileAPIPostInit(void); /* Close file API, this must be called when snort exits */ void close_fileAPI(void); /* Get current file context */ FileContext* get_current_file_context(void *ssnptr); #endif snort-2.9.6.0/src/file-process/file_service.c0000644000000000000000000007516112260565732015731 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 5.25.12 - Initial Source Code. Hui Cao */ #ifdef HAVE_CONFIG_H #include #endif #include "sf_types.h" #include #include "file_api.h" #include "file_config.h" #include "file_mime_config.h" #include "file_capture.h" #include "file_stats.h" #include "stream_api.h" #include "mstring.h" #include "preprocids.h" #include "detect.h" #include "plugbase.h" #include "active.h" #include "file_mime_process.h" #include "file_resume_block.h" #include "snort_httpinspect.h" #include "file_service.h" typedef struct _FileSession { FileContext *current_context; FileContext *main_context; FileContext *pending_context; uint32_t max_file_id; } FileSession; static bool file_type_id_enabled = false; static bool file_signature_enabled = false; static bool file_capture_enabled = false; static bool file_processing_initiated = false; static File_policy_callback_func file_policy_cb = NULL; File_type_callback_func file_type_cb = NULL; File_signature_callback_func file_signature_cb = NULL; Log_file_action_func log_file_action = NULL; /*Main File Processing functions */ static int file_process(void* ssnptr, uint8_t* file_data, int data_size, FilePosition position, bool upload, bool suspend_block_verdict); /*File properties*/ static int get_file_name(void* ssnptr, uint8_t **fname, uint32_t *name_size); static uint64_t get_file_size(void* ssnptr); static uint64_t get_file_processed_size(void* ssnptr); static bool get_file_direction(void* ssnptr); static uint8_t *get_file_sig_sha256(void* ssnptr); static void set_file_name(void* ssnptr, uint8_t * fname, uint32_t name_size); static void set_file_direction(void* ssnptr, bool upload); static void set_file_policy_callback(File_policy_callback_func); static void enable_file_type(File_type_callback_func ); static void enable_file_signature (File_signature_callback_func); static void enable_file_capture(File_signature_callback_func ); static void set_file_action_log_callback(Log_file_action_func); static int64_t get_max_file_depth(void); static void set_file_name_from_log(FILE_LogState *log_state, void *ssn); static uint32_t str_to_hash(uint8_t *str, int length ); static void file_signature_lookup(void* p, bool is_retransmit); static void file_signature_callback(Packet* p); static inline void finish_signature_lookup(FileContext *context); static File_Verdict get_file_verdict(void *ssnptr); static void render_block_verdict(void *ctx, void *p); static bool is_file_service_enabled(void); #if defined(FEAT_FILE_INSPECT) static uint32_t get_file_type_id(void *ssnptr); #endif /* FEAT_FILE_INSPECT */ static void update_file_name(MAIL_LogState *log_state); /* File context based file processing*/ FileContext* create_file_context(void *ssnptr); bool set_current_file_context(void *ssnptr, FileContext *ctx); FileContext* get_current_file_context(void *ssnptr); FileContext* get_main_file_context(void *ssnptr); static int process_file_context(FileContext *ctx, void *p, uint8_t *file_data, int data_size, FilePosition position, bool suspend_block_verdict); FileAPI fileAPI; FileAPI* file_api = NULL; static unsigned s_cb_id = 0; void init_fileAPI(void) { fileAPI.version = FILE_API_VERSION; fileAPI.is_file_service_enabled = &is_file_service_enabled; fileAPI.file_process = &file_process; fileAPI.get_file_name = &get_file_name; fileAPI.get_file_size = &get_file_size; fileAPI.get_file_processed_size = &get_file_processed_size; fileAPI.get_file_direction = &get_file_direction; fileAPI.get_sig_sha256 = &get_file_sig_sha256; fileAPI.set_file_name = &set_file_name; fileAPI.set_file_direction = &set_file_direction; fileAPI.set_file_policy_callback = &set_file_policy_callback; fileAPI.enable_file_type = &enable_file_type; fileAPI.enable_file_signature = &enable_file_signature; fileAPI.enable_file_capture = &enable_file_capture; fileAPI.set_file_action_log_callback = &set_file_action_log_callback; fileAPI.get_max_file_depth = &get_max_file_depth; fileAPI.log_file_name = &log_file_name; fileAPI.update_file_name = &update_file_name; fileAPI.set_file_name_from_log = &set_file_name_from_log; fileAPI.set_log_buffers = &set_log_buffers; fileAPI.init_mime_mempool = &init_mime_mempool; fileAPI.init_log_mempool= &init_log_mempool; fileAPI.file_resume_block_add_file = &file_resume_block_add_file; fileAPI.file_resume_block_check = &file_resume_block_check; fileAPI.str_to_hash = &str_to_hash; fileAPI.file_signature_lookup = &file_signature_lookup; fileAPI.set_mime_decode_config_defauts = &set_mime_decode_config_defauts; fileAPI.set_mime_log_config_defauts = &set_mime_log_config_defauts; fileAPI.parse_mime_decode_args = &parse_mime_decode_args; fileAPI.process_mime_data = &process_mime_data; fileAPI.free_mime_session = &free_mime_session; fileAPI.is_decoding_enabled = &is_decoding_enabled; fileAPI.is_decoding_conf_changed = &is_decoding_conf_changed; fileAPI.is_mime_log_enabled = &is_mime_log_enabled; fileAPI.finalize_mime_position = &finalize_mime_position; fileAPI.get_file_verdict = &get_file_verdict; fileAPI.render_block_verdict = &render_block_verdict; fileAPI.reserve_file = &file_capture_reserve; fileAPI.read_file = &file_capture_read; fileAPI.release_file = &file_capture_release; fileAPI.get_file_capture_size = &file_capture_size; #if defined(FEAT_FILE_INSPECT) fileAPI.get_file_type_id = &get_file_type_id; #endif /* FEAT_FILE_INSPECT */ #ifdef TARGET_BASED fileAPI.register_mime_paf_service = ®ister_mime_paf_service; #endif fileAPI.register_mime_paf_port = ®ister_mime_paf_port; fileAPI.create_file_context = &create_file_context; fileAPI.set_current_file_context = &set_current_file_context; fileAPI.get_current_file_context = &get_current_file_context; fileAPI.get_main_file_context = &get_main_file_context; fileAPI.process_file = &process_file_context; file_api = &fileAPI; init_mime(); } void FileAPIPostInit (void) { FileConfig *file_config = (FileConfig *)(snort_conf->file_config); if (file_type_id_enabled || file_signature_enabled || file_capture_enabled) { if (!file_config) { file_config = file_service_config_create(); snort_conf->file_config = file_config; } } if ( file_capture_enabled) file_capture_init_mempool(file_config->file_capture_memcap, file_config->file_capture_block_size); if ( stream_api && file_signature_enabled ) s_cb_id = stream_api->register_event_handler(file_signature_callback); #ifdef SNORT_RELOAD file_sevice_reconfig_set(false); #endif } static void start_file_processing(void) { if (!file_processing_initiated) { file_resume_block_init(); RegisterPreprocStats("file", print_file_stats); file_processing_initiated = true; } } void free_file_config(void *conf) { file_rule_free(conf); file_identifiers_free(conf); free(conf); } void close_fileAPI(void) { file_resume_block_cleanup(); free_mime(); file_caputure_close(); } static inline FileSession* get_file_session(void *ssnptr) { return((FileSession*) stream_api->get_application_data(ssnptr, PP_FILE)); } /*Get the current working file context*/ FileContext* get_current_file_context(void *ssnptr) { FileSession *file_session = get_file_session (ssnptr); if (file_session) return file_session->current_context; else return NULL; } /*Get the current main file context*/ FileContext* get_main_file_context(void *ssnptr) { FileSession *file_session = get_file_session (ssnptr); if (file_session) return file_session->main_context; else return NULL; } /*Get the current working file context*/ static inline void save_to_pending_context(void *ssnptr) { FileSession *file_session = get_file_session (ssnptr); /* Save to pending_context */ if (!file_session) return; if (file_session->pending_context != file_session->main_context) file_context_free(file_session->pending_context); file_session->pending_context = file_session->main_context; } /*Set the current working file context*/ bool set_current_file_context(void *ssnptr, FileContext *ctx) { FileSession *file_session = get_file_session (ssnptr); if (!file_session) { return false; } file_session->current_context = ctx; return true; } static void file_session_free(void *session_data) { FileSession *file_session = (FileSession *)session_data; if (!file_session) return; /*Clean up all the file contexts*/ if ( file_session->pending_context && (file_session->main_context != file_session->pending_context)) { file_context_free(file_session->pending_context); } file_context_free(file_session->main_context); free(file_session); } static inline void init_file_context(void *ssnptr, bool upload, FileContext *context) { context->file_type_enabled = file_type_id_enabled; context->file_signature_enabled = file_signature_enabled; context->file_capture_enabled = file_capture_enabled; file_direction_set(context,upload); #ifdef TARGET_BASED /* Check file policy to see whether we want to do either file type, file * signature, or file capture * Note: this happen only on the start of session*/ if (file_policy_cb) { uint32_t policy_flags = 0; context->app_id = stream_api->get_application_protocol_id(ssnptr); policy_flags = file_policy_cb(ssnptr, context->app_id, upload); if (!(policy_flags & ENABLE_FILE_TYPE_IDENTIFICATION)) context->file_type_enabled = false; if (!(policy_flags & ENABLE_FILE_SIGNATURE_SHA256)) context->file_signature_enabled = false; if (!(policy_flags & ENABLE_FILE_CAPTURE)) context->file_capture_enabled = false; } #endif } FileContext* create_file_context(void *ssnptr) { FileSession *file_session; FileContext *context = file_context_create(); /* Create file session if not yet*/ file_session = get_file_session (ssnptr); if(!file_session) { file_session = (FileSession *)SnortAlloc(sizeof(*file_session)); stream_api->set_application_data(ssnptr, PP_FILE, file_session, file_session_free); } file_stats.files_total++; return context; } static inline FileContext* find_main_file_context(void* p, FilePosition position, bool upload) { FileContext* context = NULL; Packet *pkt = (Packet *)p; void *ssnptr = pkt->ssnptr; FileSession *file_session = get_file_session (ssnptr); /* Attempt to get a previously allocated context. */ if (file_session) context = file_session->main_context; if (context && ((position == SNORT_FILE_MIDDLE) || (position == SNORT_FILE_END))) return context; else if (context) { /*Push file event when there is another file in the same packet*/ if (pkt->packet_flags & PKT_FILE_EVENT_SET) { SnortEventqLog(snort_conf->event_queue, p); SnortEventqReset(); pkt->packet_flags &= ~PKT_FILE_EVENT_SET; } if (context->verdict != FILE_VERDICT_PENDING) { /*Reuse the same context*/ file_context_reset(context); file_stats.files_total++; init_file_context(ssnptr, upload, context); context->file_id = file_session->max_file_id++; return context; } } context = create_file_context(ssnptr); file_session = get_file_session (ssnptr); file_session->main_context = context; init_file_context(ssnptr, upload, context); context->file_id = file_session->max_file_id++; return context; } static inline void updateFileSize(FileContext* context, int data_size, FilePosition position) { context->processed_bytes += data_size; if ((position == SNORT_FILE_END) || (position == SNORT_FILE_FULL)) { if (get_max_file_depth() == (int64_t)context->processed_bytes) context->file_size = 0; else context->file_size = context->processed_bytes; context->processed_bytes = 0; } } int file_eventq_add(uint32_t gid, uint32_t sid, char *msg, RuleType type) { OptTreeNode *otn; RuleTreeNode *rtn; int ret; otn = GetOTN(gid, sid, 1, 0, 3, msg); if (otn == NULL) return 0; rtn = getRtnFromOtn(otn, getRuntimePolicy()); if (rtn == NULL) { return 0; } rtn->type = type; ret = SnortEventqAdd(gid, sid, 1, 0, 3, msg, otn); return(ret); } static inline void add_file_to_block(Packet *p, File_Verdict verdict, uint32_t file_type_id, uint8_t *signature) { uint8_t *buf = NULL; uint32_t len = 0; uint32_t type = 0; uint32_t file_sig; Packet *pkt = (Packet *)p; FileConfig *file_config = (FileConfig *)(snort_conf->file_config); Active_ForceDropPacket(); DisableAllDetect(p); SetPreprocBit(p, PP_PERFMONITOR); pkt->packet_flags |= PKT_FILE_EVENT_SET; /*Use URI as the identifier for file*/ if (GetHttpUriData(p->ssnptr, &buf, &len, &type)) { file_sig = str_to_hash(buf, len); file_resume_block_add_file(p, file_sig, (uint32_t)file_config->file_block_timeout, verdict, file_type_id, signature); } } /* * Check HTTP partial content header * Return: 1: partial content header * 0: not http partial content header */ static inline int check_http_partial_content(Packet *p) { uint8_t *buf = NULL; uint32_t len = 0; uint32_t type = 0; uint32_t file_sig; const HttpBuffer* hb = GetHttpBuffer(HTTP_BUFFER_STAT_CODE); /*Not HTTP response, return*/ if ( !hb ) return 0; /*Not partial content, return*/ if ( (hb->length != 3) || strncmp((const char*)hb->buf, "206", 3) ) return 0; /*Use URI as the identifier for file*/ if (GetHttpUriData(p->ssnptr, &buf, &len, &type)) { file_sig = str_to_hash(buf, len); file_resume_block_check(p, file_sig); } return 1; } /* File signature lookup at the end of file * File signature callback can be used for malware lookup, file capture etc */ static inline void _file_signature_lookup(FileContext* context, void* p, bool is_retransmit, bool suspend_block_verdict) { File_Verdict verdict = FILE_VERDICT_UNKNOWN; Packet *pkt = (Packet *)p; void *ssnptr = pkt->ssnptr; if (file_signature_cb) { verdict = file_signature_cb(p, ssnptr, context->sha256, context->file_size, &(context->file_state), context->upload, context->file_id); file_stats.verdicts_signature[verdict]++; } if (suspend_block_verdict) context->suspend_block_verdict = true; context->verdict = verdict; if (verdict == FILE_VERDICT_LOG ) { file_eventq_add(GENERATOR_FILE_SIGNATURE, FILE_SIGNATURE_SHA256, FILE_SIGNATURE_SHA256_STR, RULE_TYPE__ALERT); pkt->packet_flags |= PKT_FILE_EVENT_SET; context->file_signature_enabled = false; } else if (verdict == FILE_VERDICT_PENDING) { /*Can't decide verdict, drop packet and waiting...*/ if (is_retransmit) { FileConfig *file_config = (FileConfig *)context->file_config; /*Drop packets if not timeout*/ if (pkt->pkth->ts.tv_sec <= context->expires) { Active_DropPacket(pkt); return; } /*Timeout, let packet go through OR block based on config*/ context->file_signature_enabled = false; if (file_config && file_config->block_timeout_lookup) file_eventq_add(GENERATOR_FILE_SIGNATURE, FILE_SIGNATURE_SHA256, FILE_SIGNATURE_SHA256_STR, RULE_TYPE__REJECT); else file_eventq_add(GENERATOR_FILE_SIGNATURE, FILE_SIGNATURE_SHA256, FILE_SIGNATURE_SHA256_STR, RULE_TYPE__ALERT); pkt->packet_flags |= PKT_FILE_EVENT_SET; } else { FileConfig *file_config = (FileConfig *)context->file_config; if (file_config) context->expires = (time_t)(file_config->file_lookup_timeout + pkt->pkth->ts.tv_sec); Active_DropPacket(pkt); stream_api->set_event_handler(ssnptr, s_cb_id, SE_REXMIT); save_to_pending_context(ssnptr); return; } } else if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT)) { if (!context->suspend_block_verdict) render_block_verdict(context, p); context->file_signature_enabled = false; return; } finish_signature_lookup(context); } static inline void finish_signature_lookup(FileContext *context) { if (context->sha256) { context->file_signature_enabled = false; file_stats.signatures_processed[context->file_type_id][context->upload]++; #ifdef TARGET_BASED file_stats.signatures_by_proto[context->app_id]++; #endif } } static File_Verdict get_file_verdict(void *ssnptr) { FileContext *context = get_current_file_context(ssnptr); if (context == NULL) return FILE_VERDICT_UNKNOWN; return context->verdict; } static void render_block_verdict(void *ctx, void *p) { FileContext *context = (FileContext *)ctx; Packet *pkt = (Packet *)p; if (p == NULL) return; if (context == NULL) { context = get_current_file_context(pkt->ssnptr); if (context == NULL) return; } if (context->verdict == FILE_VERDICT_BLOCK) { file_eventq_add(GENERATOR_FILE_SIGNATURE, FILE_SIGNATURE_SHA256, FILE_SIGNATURE_SHA256_STR, RULE_TYPE__DROP); add_file_to_block(p, context->verdict, context->file_type_id, context->sha256); } else if (context->verdict == FILE_VERDICT_REJECT) { file_eventq_add(GENERATOR_FILE_SIGNATURE, FILE_SIGNATURE_SHA256, FILE_SIGNATURE_SHA256_STR, RULE_TYPE__REJECT); add_file_to_block(p, context->verdict, context->file_type_id, context->sha256); } finish_signature_lookup(context); } #if defined(FEAT_FILE_INSPECT) static uint32_t get_file_type_id(void *ssnptr) { // NOTE: 'ssnptr' NULL checked in get_application_data FileContext *context = get_current_file_context(ssnptr); if ( !context ) return FILE_VERDICT_UNKNOWN; return context->file_type_id; } #endif /* FEAT_FILE_INSPECT */ static void file_signature_lookup(void* p, bool is_retransmit) { Packet *pkt = (Packet *)p; FileContext* context = get_current_file_context(pkt->ssnptr); if (context && context->file_signature_enabled && context->sha256) { _file_signature_lookup(context, p, is_retransmit, false); } } static void file_signature_callback(Packet* p) { /* During retransmission */ Packet *pkt = (Packet *)p; void *ssnptr = pkt->ssnptr; FileSession *file_session; if (!ssnptr) return; file_session = get_file_session (ssnptr); if (!file_session) return; file_session->current_context = file_session->pending_context; file_signature_lookup(p, 1); } static bool is_file_service_enabled() { return (file_type_id_enabled || file_signature_enabled); } /* * Return: * 1: continue processing/log/block this file * 0: ignore this file */ static int process_file_context(FileContext *context, void *p, uint8_t *file_data, int data_size, FilePosition position, bool suspend_block_verdict) { Packet *pkt = (Packet *)p; void *ssnptr = pkt->ssnptr; if (!context) return 0; set_current_file_context(ssnptr, context); file_stats.file_data_total += data_size; if ((!context->file_type_enabled) && (!context->file_signature_enabled)) { updateFileSize(context, data_size, position); return 0; } if(check_http_partial_content(p)) { context->file_type_enabled = false; context->file_signature_enabled = false; return 0; } context->file_config = snort_conf->file_config; /*file type id*/ if (context->file_type_enabled) { File_Verdict verdict = FILE_VERDICT_UNKNOWN; file_type_id(context, file_data, data_size, position); /*Don't care unknown file type*/ if (context->file_type_id == SNORT_FILE_TYPE_UNKNOWN) { context->file_type_enabled = false; context->file_signature_enabled = false; updateFileSize(context, data_size, position); file_capture_stop(context); return 0; } if (context->file_type_id != SNORT_FILE_TYPE_CONTINUE) { if (file_type_cb) { verdict = file_type_cb(p, ssnptr, context->file_type_id, context->upload, context->file_id); file_stats.verdicts_type[verdict]++; } context->file_type_enabled = false; file_stats.files_processed[context->file_type_id][context->upload]++; #ifdef TARGET_BASED file_stats.files_by_proto[context->app_id]++; #endif } if (verdict == FILE_VERDICT_LOG ) { file_eventq_add(GENERATOR_FILE_TYPE, context->file_type_id, file_type_name(context->file_config, context->file_type_id), RULE_TYPE__ALERT); context->file_signature_enabled = false; pkt->packet_flags |= PKT_FILE_EVENT_SET; } else if (verdict == FILE_VERDICT_BLOCK) { file_eventq_add(GENERATOR_FILE_TYPE, context->file_type_id, file_type_name(context->file_config, context->file_type_id), RULE_TYPE__DROP); updateFileSize(context, data_size, position); context->file_signature_enabled = false; add_file_to_block(p, verdict, context->file_type_id, NULL); return 1; } else if (verdict == FILE_VERDICT_REJECT) { file_eventq_add(GENERATOR_FILE_TYPE, context->file_type_id, file_type_name(context->file_config, context->file_type_id), RULE_TYPE__REJECT); updateFileSize(context, data_size, position); context->file_signature_enabled = false; add_file_to_block(p, verdict, context->file_type_id, NULL); return 1; } else if (verdict == FILE_VERDICT_STOP) { context->file_signature_enabled = false; } else if (verdict == FILE_VERDICT_STOP_CAPTURE) { file_capture_stop(context); } } /*file signature calculation*/ if (context->file_signature_enabled) { file_signature_sha256(context, file_data, data_size, position); file_stats.data_processed[context->file_type_id][context->upload] += data_size; updateFileSize(context, data_size, position); /*Fails to capture, when out of memory or size limit, need lookup*/ if (context->file_capture_enabled && file_capture_process(context, file_data, data_size, position)) { file_capture_stop(context); _file_signature_lookup(context, p, false, suspend_block_verdict); if (context->verdict != FILE_VERDICT_UNKNOWN) return 1; } FILE_REG_DEBUG_WRAP(if (context->sha256) file_sha256_print(context->sha256);) /*Either get SHA or exceeding the SHA limit, need lookup*/ if (context->file_state.sig_state != FILE_SIG_PROCESSING) { if (context->file_state.sig_state == FILE_SIG_DEPTH_FAIL) file_stats.files_sig_depth++; _file_signature_lookup(context, p, false, suspend_block_verdict); } } else { updateFileSize(context, data_size, position); } return 1; } /* * Return: * 1: continue processing/log/block this file * 0: ignore this file */ static int file_process( void* p, uint8_t* file_data, int data_size, FilePosition position, bool upload, bool suspend_block_verdict) { FileContext* context; /* if both disabled, return immediately*/ if (!is_file_service_enabled()) return 0; if (position == SNORT_FILE_POSITION_UNKNOWN) return 0; FILE_REG_DEBUG_WRAP(DumpHex(stdout, file_data, data_size);) context = find_main_file_context(p, position, upload); return process_file_context(context, p, file_data, data_size, position, suspend_block_verdict); } static void set_file_name (void* ssnptr, uint8_t* fname, uint32_t name_size) { FileContext* context = get_current_file_context(ssnptr); file_name_set(context, fname, name_size); FILE_REG_DEBUG_WRAP(printFileContext(context);) } /* Return 1: file name available, * 0: file name is unavailable */ static int get_file_name (void* ssnptr, uint8_t **fname, uint32_t *name_size) { return file_name_get(get_current_file_context(ssnptr), fname, name_size); } static uint64_t get_file_size(void* ssnptr) { return file_size_get(get_current_file_context(ssnptr)); } static uint64_t get_file_processed_size(void* ssnptr) { FileContext *context = get_main_file_context(ssnptr); if (context) return (context->processed_bytes); else return 0; } static void set_file_direction(void* ssnptr, bool upload) { file_direction_set(get_current_file_context(ssnptr),upload); } static bool get_file_direction(void* ssnptr) { return file_direction_get(get_current_file_context(ssnptr)); } static uint8_t *get_file_sig_sha256(void* ssnptr) { return file_sig_sha256_get(get_current_file_context(ssnptr)); } static void set_file_policy_callback(File_policy_callback_func policy_func_cb) { file_policy_cb = policy_func_cb; } static void enable_file_type(File_type_callback_func callback) { if (!file_type_id_enabled) { file_type_cb = callback; file_type_id_enabled = true; #ifdef SNORT_RELOAD file_sevice_reconfig_set(true); #endif start_file_processing(); LogMessage("File service: file type enabled.\n"); } } /* set file signature callback function*/ static inline void _update_file_sig_callback(File_signature_callback_func cb) { if(!file_signature_cb) { file_signature_cb = cb; } else if (file_signature_cb != cb) { WarningMessage("File service: signature callback redefined.\n"); } } static void enable_file_signature(File_signature_callback_func callback) { _update_file_sig_callback(callback); if (!file_signature_enabled) { file_signature_enabled = true; #ifdef SNORT_RELOAD file_sevice_reconfig_set(true); #endif start_file_processing(); LogMessage("File service: file signature enabled.\n"); } } /* Enable file capture, also enable file signature */ static void enable_file_capture(File_signature_callback_func callback) { if (!file_capture_enabled) { file_capture_enabled = true; #ifdef SNORT_RELOAD file_sevice_reconfig_set(true); #endif LogMessage("File service: file capture enabled.\n"); /* Enable file signature*/ enable_file_signature(callback); } } static void set_file_action_log_callback(Log_file_action_func log_func) { log_file_action = log_func; } /* Get maximal file depth based on configuration * This function must be called after all file services are configured/enabled. */ static int64_t get_max_file_depth(void) { FileConfig *file_config = (FileConfig *)(snort_conf->file_config); if (!file_config) return -1; if (file_config->file_depth) return file_config->file_depth; file_config->file_depth = -1; if (file_type_id_enabled) { file_config->file_depth = file_config->file_type_depth; } if (file_signature_enabled) { if (file_config->file_signature_depth > file_config->file_depth) file_config->file_depth = file_config->file_signature_depth; } if (file_config->file_depth > 0) { /*Extra byte for deciding whether file data will be over limit*/ file_config->file_depth++; return (file_config->file_depth); } else { return -1; } } static void update_file_name(MAIL_LogState *log_state) { if (log_state) log_state->file_log.file_name = log_state->file_log.file_current; } static void set_file_name_from_log(FILE_LogState *log_state, void *ssn) { if ((log_state) && (log_state->file_logged > log_state->file_current)) { if (log_state->file_current > log_state->file_name) set_file_name(ssn, log_state->filenames + log_state->file_name, log_state->file_current -log_state->file_name - 1); else set_file_name(ssn, log_state->filenames + log_state->file_current, log_state->file_logged -log_state->file_current); } else { set_file_name(ssn, NULL, 0); } } static uint32_t str_to_hash(uint8_t *str, int length ) { uint32_t a,b,c,tmp; int i,j,k,l; a = b = c = 0; for (i=0,j=0;i 4) k=4; for (l=0;l&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/file-process DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libfileAPI_a_AR = $(AR) $(ARFLAGS) libfileAPI_a_LIBADD = am_libfileAPI_a_OBJECTS = file_service.$(OBJEXT) \ file_service_config.$(OBJEXT) file_mime_process.$(OBJEXT) \ file_resume_block.$(OBJEXT) file_mime_config.$(OBJEXT) \ file_capture.$(OBJEXT) file_stats.$(OBJEXT) \ circular_buffer.$(OBJEXT) file_mempool.$(OBJEXT) \ sf_email_attach_decode.$(OBJEXT) libfileAPI_a_OBJECTS = $(am_libfileAPI_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libfileAPI_a_SOURCES) DIST_SOURCES = $(libfileAPI_a_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libfileAPI.a libfileAPI_a_SOURCES = \ file_service.c \ file_service.h \ file_service_config.c \ file_service_config.h \ file_api.h \ file_mime_process.c \ file_mime_process.h \ file_resume_block.c \ file_resume_block.h \ file_mime_config.c \ file_mime_config.h \ file_capture.c \ file_capture.h \ file_stats.c \ file_stats.h \ circular_buffer.c \ circular_buffer.h \ file_mempool.c \ file_mempool.h \ ../sfutil/sf_email_attach_decode.c \ ../sfutil/sf_email_attach_decode.h SUBDIRS = libs all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/file-process/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/file-process/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libfileAPI.a: $(libfileAPI_a_OBJECTS) $(libfileAPI_a_DEPENDENCIES) $(EXTRA_libfileAPI_a_DEPENDENCIES) $(AM_V_at)-rm -f libfileAPI.a $(AM_V_AR)$(libfileAPI_a_AR) libfileAPI.a $(libfileAPI_a_OBJECTS) $(libfileAPI_a_LIBADD) $(AM_V_at)$(RANLIB) libfileAPI.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_email_attach_decode.o: ../sfutil/sf_email_attach_decode.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_email_attach_decode.o `test -f '../sfutil/sf_email_attach_decode.c' || echo '$(srcdir)/'`../sfutil/sf_email_attach_decode.c sf_email_attach_decode.obj: ../sfutil/sf_email_attach_decode.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_email_attach_decode.obj `if test -f '../sfutil/sf_email_attach_decode.c'; then $(CYGPATH_W) '../sfutil/sf_email_attach_decode.c'; else $(CYGPATH_W) '$(srcdir)/../sfutil/sf_email_attach_decode.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LIBRARIES) installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool \ clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/control/0000755000000000000000000000000012260606567012263 500000000000000snort-2.9.6.0/src/control/sfcontrol_funcs.h0000644000000000000000000000300712260565732015561 00000000000000/* ** ** sfcontrol.c ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2002-2013 Sourcefire, Inc. ** Author(s): Ron Dempster ** ** NOTES ** 5.16.11 - Initial Source Code. Dempster ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** */ #ifndef __SF_CONTROL_FUNCS_H__ #define __SF_CONTROL_FUNCS_H__ #include "sfcontrol.h" void ControlSocketConfigureDirectory(const char *optarg); void ControlSocketInit(void); void ControlSocketCleanUp(void); int ControlSocketRegisterHandler(uint16_t type, OOBPreControlFunc oobpre, IBControlFunc ib, OOBPostControlFunc oobpost); #ifdef CONTROL_SOCKET void ControlSocketDoWork(int idle); #else #define ControlSocketDoWork(idle) do {} while(0) #endif #endif snort-2.9.6.0/src/control/sfcontrol.h0000644000000000000000000000451112260565732014364 00000000000000/* ** ** sfcontrol.c ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2002-2013 Sourcefire, Inc. ** Author(s): Ron Dempster ** ** NOTES ** 5.16.11 - Initial Source Code. Dempster ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** */ #ifndef __SF_CONTROL_H__ #define __SF_CONTROL_H__ #define CONTROL_FILE "SNORT.sock" #define CS_TYPE_HUP_DAQ 0x0001 #define CS_TYPE_RELOAD 0x0002 #define CS_TYPE_IS_PROCESSING 0x0003 #define CS_TYPE_MAX 0x1FFF #define CS_HEADER_VERSION 0x0001 #define CS_HEADER_SUCCESS 0x0000 #define CS_HEADER_ERROR 0x0001 #define CS_HEADER_DATA 0x0009 #pragma pack(1) typedef struct _CS_MESSAGE_DATA_HEADER { /* All values must be in network byte order */ int32_t code; uint16_t length; /* Data length. Does not include this header */ } CSMessageDataHeader; #pragma pack() typedef struct _CS_MESSAGE_HEADER { /* All values must be in network byte order */ uint16_t version; uint16_t type; uint32_t length; /* Does not include the header */ } CSMessageHeader; struct _THREAD_ELEMENT; typedef int (*ControlDataSendFunc)(struct _THREAD_ELEMENT *te, const uint8_t *data, uint16_t length); typedef int (*OOBPreControlFunc)(uint16_t type, const uint8_t *data, uint32_t length, void **new_context, char *statusBuf, int statusBuf_len); typedef int (*IBControlFunc)(uint16_t type, void *new_context, void **old_context); typedef void (*OOBPostControlFunc)(uint16_t type, void *old_context, struct _THREAD_ELEMENT *te, ControlDataSendFunc f); #endif snort-2.9.6.0/src/control/sfcontrol.c0000644000000000000000000006304412260565732014365 00000000000000/* ** ** sfcontrol.c ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2002-2013 Sourcefire, Inc. ** Author(s): Ron Dempster ** ** NOTES ** 5.16.11 - Initial Source Code. Dempster ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "snort.h" #include "sfcontrol_funcs.h" #include "sfcontrol.h" #ifdef CONTROL_SOCKET #ifndef WIN32 #include #include #include #include #include #include #include #include #include #include #endif static char config_unix_socket_fn[PATH_MAX]; static int config_unix_socket; static volatile int stop_processing = 0; #pragma pack(1) typedef struct _CS_RESPONSE_MESSAGE { CSMessageHeader hdr; CSMessageDataHeader msg_hdr; char msg[1024]; } CSResponseMessage; #pragma pack() #pragma pack(1) typedef struct _CS_RESPONSE_MESSAGE_HEADER { CSMessageHeader hdr; CSMessageDataHeader msg_hdr; } CSResponseMessageHeader; #pragma pack() typedef struct _CS_MESSAGE { CSMessageHeader hdr; uint8_t *data; } CSMessage; typedef struct _CS_MESSAGE_HANDLER { struct _CS_MESSAGE_HANDLER *next; uint32_t type; OOBPreControlFunc oobpre; IBControlFunc ibcontrol; OOBPostControlFunc oobpost; pthread_mutex_t mutex; void *new_context; void *old_context; volatile int handled; volatile int ib_rval; } CSMessageHandler; #define CS_MAX_WORK 3 #define CS_MAX_IDLE_WORK 10 static unsigned s_work_to_do = 0; static unsigned s_work_done = 0; static pthread_mutex_t work_mutex = PTHREAD_MUTEX_INITIALIZER; static CSMessageHandler *work_queue; static CSMessageHandler *work_queue_tail; static CSMessageHandler *msg_handlers[CS_TYPE_MAX]; static pthread_mutex_t msg_handler_mutex = PTHREAD_MUTEX_INITIALIZER; typedef struct _THREAD_ELEMENT { struct _THREAD_ELEMENT *next; int socket_fd; volatile int stop_processing; } ThreadElement; static ThreadElement *thread_list; static pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_t thread_id; static pthread_t *p_thread_id; void ControlSocketConfigureDirectory(const char *optarg) { const char *sep; ssize_t len; if (!optarg || config_unix_socket_fn[0]) return; len = strlen(optarg); if (len && optarg[len - 1] == '/') sep = ""; else sep = "/"; snprintf(config_unix_socket_fn, sizeof(config_unix_socket_fn), "%s%s%s", optarg, sep, CONTROL_FILE); } int ControlSocketRegisterHandler(uint16_t type, OOBPreControlFunc oobpre, IBControlFunc ib, OOBPostControlFunc oobpost) { if (type >= CS_TYPE_MAX) return -1; pthread_mutex_lock(&msg_handler_mutex); if (msg_handlers[type]) { pthread_mutex_unlock(&msg_handler_mutex); return -1; } if ((msg_handlers[type] = calloc(1, sizeof(*msg_handlers[type]))) == NULL) { pthread_mutex_unlock(&msg_handler_mutex); return -1; } pthread_mutex_init(&msg_handlers[type]->mutex, NULL); msg_handlers[type]->type = type; msg_handlers[type]->oobpre = oobpre; msg_handlers[type]->ibcontrol = ib; msg_handlers[type]->oobpost = oobpost; pthread_mutex_unlock(&msg_handler_mutex); return 0; } static void SendResponse(ThreadElement *t, const CSResponseMessage *resp, uint32_t len) { ssize_t numsent; unsigned total_len = sizeof(resp->hdr) + len; unsigned total = 0; do { numsent = write(t->socket_fd, (*(uint8_t **)&resp) + total, total_len - total); if (!numsent) return; else if (numsent > 0) total += numsent; else if (errno != EINTR && errno != EAGAIN) return; } while (total < total_len && !t->stop_processing); } static void SendErrorResponse(ThreadElement *t, const char * const msg) { CSResponseMessage response; uint32_t len; response.hdr.version = htons(CS_HEADER_VERSION); response.hdr.type = htons(CS_HEADER_ERROR); response.msg_hdr.code = -1; len = snprintf(response.msg, sizeof(response.msg), "%s", msg); response.msg_hdr.length = htons(len); len += sizeof(response.msg_hdr); response.hdr.length = htonl(len); SendResponse(t, &response, len); } static int ReadHeader(ThreadElement *t, CSMessageHeader *hdr) { ssize_t numread; unsigned total = 0; do { numread = read(t->socket_fd, (*(uint8_t **)&hdr) + total, sizeof(*hdr) - total); if (!numread) return 0; else if (numread > 0) total += numread; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < sizeof(*hdr) && !t->stop_processing); if (total < sizeof(*hdr)) return 0; hdr->length = ntohl(hdr->length); hdr->type = ntohs(hdr->type); hdr->version = ntohs(hdr->version); return 1; } static int ReadData(ThreadElement *t, uint8_t *buffer, uint32_t length) { ssize_t numread; unsigned total = 0; do { numread = read(t->socket_fd, buffer + total, length - total); if (!numread) return 0; else if (numread > 0) total += numread; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < length && !t->stop_processing); if (total < length) return 0; return 1; } static int SendResponseSeparateData(ThreadElement *t, const CSResponseMessageHeader *resp, const uint8_t *data, uint16_t len) { ssize_t numsent; unsigned total_len; unsigned total; total_len = sizeof(*resp); total = 0; do { numsent = write(t->socket_fd, (*(uint8_t **)&resp) + total, total_len - total); if (!numsent) return -1; else if (numsent > 0) total += numsent; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < total_len && !t->stop_processing); if (!t->stop_processing && len) { total_len = (unsigned)len; total = 0; do { numsent = write(t->socket_fd, data + total, total_len - total); if (!numsent) return -1; else if (numsent > 0) total += numsent; else if (errno != EINTR && errno != EAGAIN) return -1; } while (total < total_len && !t->stop_processing); } return 0; } static int ControlDataSend(ThreadElement *t, const uint8_t *data, uint16_t length) { CSResponseMessageHeader response; uint32_t len; response.hdr.version = htons(CS_HEADER_VERSION); response.hdr.type = htons(CS_HEADER_DATA); response.msg_hdr.code = 0; len = (uint32_t)length; response.msg_hdr.length = htons(length); len += sizeof(response.msg_hdr); response.hdr.length = htonl(len); return SendResponseSeparateData(t, &response, data, length); } static void *ControlSocketProcessThread(void *arg) { CSResponseMessage response; ThreadElement *t = (ThreadElement *)arg; int fd; pthread_t tid = pthread_self(); CSMessageHeader hdr; uint32_t len; uint8_t *data = NULL; ThreadElement **it; int rval; if (t == NULL) { ErrorMessage("Control Socket: Invalid process thread parameter\n"); return NULL; } if ((fd = t->socket_fd) == -1) { ErrorMessage("Control Socket: Invalid process thread socket\n"); return NULL; } response.hdr.version = htons(CS_HEADER_VERSION); while (!t->stop_processing) { if ((rval = ReadHeader(t, &hdr)) == 0) goto done; else if (rval < 0) { DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Failed to read %d\n", t->socket_fd, rval);); goto done; } if (hdr.version != CS_HEADER_VERSION) { static const char * const bad_version = "Bad message header version"; SendErrorResponse(t, bad_version); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Invalid header version %u\n", t->socket_fd, hdr.version);); goto done; } if (hdr.length > 4096) { static const char * const bad_data = "Bad message data"; SendErrorResponse(t, bad_data); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Meassge too long - %u\n", t->socket_fd, hdr.length);); goto done; } if (hdr.length) { if ((data = malloc(hdr.length)) == NULL) { DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Failed to allocate %u bytes\n", t->socket_fd, hdr.length);); goto done; } DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Reading %u bytes\n", t->socket_fd, hdr.length);); if ((rval = ReadData(t, data, hdr.length)) == 0) { DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Socket closed before data read\n", t->socket_fd);); goto done; } else if (rval < 0) { DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Failed to read %d\n", t->socket_fd, rval);); goto done; } } if (hdr.type >= CS_TYPE_MAX) { static const char invalid_type[] = "Invalid type. Must be 0-8190 inclusive."; SendErrorResponse(t, invalid_type); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Invalid message type - %u\n", t->socket_fd, hdr.type);); } else { CSMessageHandler *handler; pthread_mutex_lock(&msg_handler_mutex); handler = msg_handlers[hdr.type]; pthread_mutex_unlock(&msg_handler_mutex); if (handler) { static const char failed[] = "Failed to process the command."; DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Processing message type - %u\n", t->socket_fd, hdr.type);); pthread_mutex_lock(&handler->mutex); if (t->stop_processing) { pthread_mutex_unlock(&handler->mutex); response.hdr.type = htons(CS_HEADER_SUCCESS); response.hdr.length = 0; SendResponse(t, &response, 0); goto next; } handler->handled = 0; handler->new_context = NULL; handler->old_context = NULL; handler->next = NULL; response.msg[0] = '\0'; if (handler->oobpre && (rval = handler->oobpre(hdr.type, data, hdr.length, &handler->new_context, response.msg, sizeof(response.msg)))) { response.hdr.type = htons(CS_HEADER_ERROR); response.msg_hdr.code = -1; if (!response.msg[0]) { len = snprintf(response.msg, sizeof(response.msg), "%s", failed); } else { len = strlen(response.msg); } response.msg_hdr.length = htons(len); len += sizeof(response.msg_hdr); response.hdr.length = htonl(len); SendResponse(t, &response, len); pthread_mutex_unlock(&handler->mutex); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: oobpre failed %d\n", t->socket_fd, rval);); goto next; } if (response.msg[0]) { response.hdr.type = htons(CS_HEADER_DATA); response.msg_hdr.code = 0; len = strlen(response.msg); response.msg_hdr.length = htons(len); len += sizeof(response.msg_hdr); response.hdr.length = htonl(len); SendResponse(t, &response, len); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Sent %u response bytes\n", t->socket_fd, len);); } if (handler->ibcontrol) { if (t->stop_processing) { if (handler->oobpost) handler->oobpost(hdr.type, handler->new_context, t, ControlDataSend); pthread_mutex_unlock(&handler->mutex); response.hdr.type = htons(CS_HEADER_SUCCESS); response.hdr.length = 0; SendResponse(t, &response, 0); goto next; } pthread_mutex_lock(&work_mutex); if (work_queue_tail) work_queue_tail->next = handler; work_queue_tail = handler; if (!work_queue) work_queue = handler; s_work_to_do++; pthread_mutex_unlock(&work_mutex); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Waiting for ibcontrol\n", t->socket_fd);); while (!handler->handled && !t->stop_processing) usleep(100000); if (handler->handled) { if (handler->ib_rval) { if (handler->oobpost) handler->oobpost(hdr.type, handler->new_context, t, ControlDataSend); pthread_mutex_unlock(&handler->mutex); SendErrorResponse(t, failed); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: ibcontrol failed %d\n", t->socket_fd, handler->ib_rval);); goto next; } } else { // The only way to get here is if stop_processing is set. // This happens during CleanExit which means that the swap will never happen. // If the entry is no longer on the work_queue, the swap already happened and we can continue normally. CSMessageHandler *iHandler; CSMessageHandler *prevHandler = NULL; pthread_mutex_lock(&work_mutex); for (iHandler = work_queue; iHandler && iHandler != handler; iHandler = iHandler->next) prevHandler = iHandler; if (iHandler) { if (handler == work_queue_tail) work_queue_tail = prevHandler; if (prevHandler) prevHandler->next = handler->next; else work_queue = handler->next; } pthread_mutex_unlock(&work_mutex); if (iHandler) { if (handler->oobpost) handler->oobpost(hdr.type, handler->new_context, t, ControlDataSend); pthread_mutex_unlock(&handler->mutex); SendErrorResponse(t, failed); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: ibcontrol failed %d\n", t->socket_fd, handler->ib_rval);); goto next; } } } if (handler->oobpost) { handler->oobpost(hdr.type, handler->old_context, t, ControlDataSend); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: oobpost finished\n", t->socket_fd);); } pthread_mutex_unlock(&handler->mutex); response.hdr.type = htons(CS_HEADER_SUCCESS); response.hdr.length = 0; SendResponse(t, &response, 0); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Sent success\n", t->socket_fd);); } else { static const char no_handler[] = "No handler for the command."; SendErrorResponse(t, no_handler); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: No handler for message type - %u\n", t->socket_fd, hdr.type);); } } next:; if (data) { free(data); data = NULL; } } done:; if (data) free(data); close(fd); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket %d: Closed socket\n", t->socket_fd);); pthread_mutex_lock(&thread_mutex); for (it=&thread_list; *it; it=&(*it)->next) { if (t == *it) { *it = t->next; free(t); break; } } pthread_mutex_unlock(&thread_mutex); pthread_detach(tid); return NULL; } static void *ControlSocketThread(void *arg) { ThreadElement *t; ThreadElement **it; fd_set rfds; int rval; struct timeval to; int socket; struct sockaddr_un sunaddr; socklen_t addrlen = sizeof(sunaddr); pthread_t tid; if (config_unix_socket < 0) { ErrorMessage("Control Socket: Invalid socket in thread - %d\n", config_unix_socket); goto bail; } nice(2); while (!stop_processing) { to.tv_sec = 2; to.tv_usec = 0; FD_ZERO(&rfds); FD_SET(config_unix_socket, &rfds); rval = select(config_unix_socket + 1, &rfds, NULL, NULL, &to); if (rval > 0) { memset(&sunaddr, 0, sizeof(sunaddr)); if ((socket = accept(config_unix_socket, (struct sockaddr *)&sunaddr, &addrlen)) == -1) { if (errno != EINTR) { ErrorMessage("Control Socket: Accept failed: %s\n", strerror(errno)); goto bail; } } else { DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket: Creating a processing thread for %d\n", socket);); if ((t = calloc(1, sizeof(*t))) == NULL) { close(socket); ErrorMessage("Control Socket: Failed to allocate a thread struct"); goto bail; } t->socket_fd = socket; pthread_mutex_lock(&thread_mutex); t->next = thread_list; thread_list = t; pthread_mutex_unlock(&thread_mutex); if ((rval = pthread_create(&tid, NULL, &ControlSocketProcessThread, (void *)t)) != 0) { pthread_mutex_lock(&thread_mutex); for (it=&thread_list; *it; it=&(*it)->next) { if (t == *it) { *it = t->next; close(t->socket_fd); free(t); break; } } pthread_mutex_unlock(&thread_mutex); ErrorMessage("Control Socket: Unable to create a processing thread: %s", strerror(rval)); goto bail; } } } else if (rval < 0) { if (errno != EINTR) { ErrorMessage("Control Socket: Select failed: %s\n", strerror(errno)); goto bail; } } } bail:; close(config_unix_socket); DEBUG_WRAP( DebugMessage(DEBUG_CONTROL, "Control Socket: Thread exiting\n");); return NULL; } static void SetupUnixSocket(const char * const name, int * const psock, const int listen_backlog) { struct sockaddr_un sunaddr; int sock = -1; int yes = 1; int rval; memset(&sunaddr, 0, sizeof(sunaddr)); rval = snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", name); if (rval < 0 || (size_t)rval >= sizeof(sunaddr.sun_path)) FatalError("Control Socket: Socket name '%s' is too long\n", name); sunaddr.sun_family = AF_UNIX; unlink(name); /* remove existing file */ /* open the socket */ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { FatalError("Control Socket: Error opening socket %s: %s\n", name, strerror(errno)); } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { WarningMessage("Control Socket: setsockopt failed for %s: %s", name, strerror(errno)); } if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { rval = errno; close(sock); FatalError("Control Socket: Unable to bind to %s: %s\n", name, strerror(rval)); } if (chmod(name, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP)) { rval = errno; close(sock); FatalError("Control Socket: Error changing the mode for socket %s: %s", name, strerror(rval)); } /* listen on the socket */ if (listen(sock, listen_backlog) == -1) { rval = errno; close(sock); FatalError("Control Socket: Unable to listen on UNIX socket %s: %s\n", name, strerror(rval)); } *psock = sock; } void ControlSocketInit(void) { int rval; sigset_t mask; if (!config_unix_socket_fn[0]) return; SetupUnixSocket(config_unix_socket_fn, &config_unix_socket, 10); sigemptyset(&mask); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGQUIT); sigaddset(&mask, SIGPIPE); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGNAL_SNORT_RELOAD); sigaddset(&mask, SIGNAL_SNORT_DUMP_STATS); sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR2); sigaddset(&mask, SIGNAL_SNORT_ROTATE_STATS); sigaddset(&mask, SIGNAL_SNORT_CHILD_READY); #ifdef TARGET_BASED sigaddset(&mask, SIGNAL_SNORT_READ_ATTR_TBL); sigaddset(&mask, SIGVTALRM); #endif pthread_sigmask(SIG_SETMASK, &mask, NULL); if((rval=pthread_create(&thread_id, NULL, &ControlSocketThread, NULL)) != 0) { sigemptyset(&mask); pthread_sigmask(SIG_SETMASK, &mask, NULL); FatalError("Control Socket: Unable to create thread: %s\n", strerror(rval)); } p_thread_id = &thread_id; sigemptyset(&mask); pthread_sigmask(SIG_SETMASK, &mask, NULL); } void ControlSocketCleanUp(void) { ThreadElement *t; int rval; int done = 0; int i; if (p_thread_id != NULL) { stop_processing = 1; if ((rval = pthread_join(*p_thread_id, NULL)) != 0) WarningMessage("Thread termination returned an error: %s\n", strerror(rval)); p_thread_id = NULL; } if (config_unix_socket_fn[0]) { unlink(config_unix_socket_fn); config_unix_socket_fn[0] = 0; } pthread_mutex_lock(&thread_mutex); for (t = thread_list; t; t = t->next) t->stop_processing = 1; pthread_mutex_unlock(&thread_mutex); do { pthread_mutex_lock(&thread_mutex); done = thread_list ? 0:1; pthread_mutex_unlock(&thread_mutex); if (!done) usleep(100000); } while (!done); pthread_mutex_lock(&work_mutex); if (work_queue) WarningMessage("%s\n", "Work queue is not emtpy during termination"); pthread_mutex_unlock(&work_mutex); for (i = 0; i < CS_TYPE_MAX; i++) { if (msg_handlers[i]) free(msg_handlers[i]); } } void ControlSocketDoWork(int idle) { unsigned max_work; CSMessageHandler *handler; if ( s_work_done == s_work_to_do ) return; max_work = idle ? CS_MAX_IDLE_WORK : CS_MAX_WORK; pthread_mutex_lock(&work_mutex); for (; work_queue && max_work; max_work--) { handler = work_queue; work_queue = handler->next; if (!work_queue) work_queue_tail = NULL; handler->ib_rval = handler->ibcontrol(handler->type, handler->new_context, &handler->old_context); handler->handled = 1; s_work_done++; } pthread_mutex_unlock(&work_mutex); } #else void ControlSocketConfigureDirectory(const char *optarg) { FatalError("%s\n", "Control socket is not available."); } int ControlSocketRegisterHandler(uint16_t type, OOBPreControlFunc oobpre, IBControlFunc ib, OOBPostControlFunc oobpost) { return 0; } void ControlSocketInit(void) { } void ControlSocketCleanUp(void) { } #endif snort-2.9.6.0/src/control/Makefile.am0000644000000000000000000000025011652017025014221 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libsfcontrol.a libsfcontrol_a_SOURCES = sfcontrol.c sfcontrol.h sfcontrol_funcs.h INCLUDES = @INCLUDES@ snort-2.9.6.0/src/control/Makefile.in0000644000000000000000000004000712260606517014244 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/control DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libsfcontrol_a_AR = $(AR) $(ARFLAGS) libsfcontrol_a_LIBADD = am_libsfcontrol_a_OBJECTS = sfcontrol.$(OBJEXT) libsfcontrol_a_OBJECTS = $(am_libsfcontrol_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsfcontrol_a_SOURCES) DIST_SOURCES = $(libsfcontrol_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libsfcontrol.a libsfcontrol_a_SOURCES = sfcontrol.c sfcontrol.h sfcontrol_funcs.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/control/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/control/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libsfcontrol.a: $(libsfcontrol_a_OBJECTS) $(libsfcontrol_a_DEPENDENCIES) $(EXTRA_libsfcontrol_a_DEPENDENCIES) $(AM_V_at)-rm -f libsfcontrol.a $(AM_V_AR)$(libsfcontrol_a_AR) libsfcontrol.a $(libsfcontrol_a_OBJECTS) $(libsfcontrol_a_LIBADD) $(AM_V_at)$(RANLIB) libsfcontrol.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/target-based/0000755000000000000000000000000012260606566013144 500000000000000snort-2.9.6.0/src/target-based/sf_attribute_table.y0000644000000000000000000003712612260565733017131 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sf_attribute_table.y */ /* * * AttributeTable * * YACC Grammar/language definition */ %{ #ifdef TARGET_BASED #include #include #include "sftarget_reader.h" #include "snort_debug.h" #define YYSTACK_USE_ALLOCA 0 /* define the initial stack-sizes */ #ifdef YYMAXDEPTH #undef YYMAXDEPTH #define YYMAXDEPTH 70000 #else #define YYMAXDEPTH 70000 #endif extern ServiceClient sfat_client_or_service; extern char *sfat_grammar_error; extern int sfat_lex(); extern void sfat_error(char*); %} %union { char stringValue[STD_BUF]; uint32_t numericValue; AttributeData data; MapData mapEntry; } %token SF_AT_COMMENT %token SF_AT_WHITESPACE %token SF_START_SNORT_ATTRIBUTES %token SF_END_SNORT_ATTRIBUTES %token SF_AT_START_MAP_TABLE %token SF_AT_END_MAP_TABLE %token SF_AT_START_ENTRY %token SF_AT_END_ENTRY %token SF_AT_START_ENTRY_ID %token SF_AT_END_ENTRY_ID %token SF_AT_START_ENTRY_VALUE %token SF_AT_END_ENTRY_VALUE %token SF_AT_START_ATTRIBUTE_TABLE %token SF_AT_END_ATTRIBUTE_TABLE %token SF_AT_START_HOST %token SF_AT_END_HOST %token SF_AT_START_HOST_IP %token SF_AT_END_HOST_IP %token SF_AT_STRING %token SF_AT_NUMERIC /* %token SF_AT_IPv4 %token SF_AT_IPv4CIDR */ %token SF_AT_IPv6 %token SF_AT_IPv6Cidr %token SF_AT_START_OS %token SF_AT_END_OS %token SF_AT_START_ATTRIBUTE_VALUE %token SF_AT_END_ATTRIBUTE_VALUE %token SF_AT_START_ATTRIBUTE_ID %token SF_AT_END_ATTRIBUTE_ID %token SF_AT_START_CONFIDENCE %token SF_AT_END_CONFIDENCE %token SF_AT_START_NAME %token SF_AT_END_NAME %token SF_AT_START_VENDOR %token SF_AT_END_VENDOR %token SF_AT_START_VERSION %token SF_AT_END_VERSION %token SF_AT_START_FRAG_POLICY %token SF_AT_END_FRAG_POLICY %token SF_AT_START_STREAM_POLICY %token SF_AT_END_STREAM_POLICY %token SF_AT_START_SERVICES %token SF_AT_END_SERVICES %token SF_AT_START_SERVICE %token SF_AT_END_SERVICE %token SF_AT_START_CLIENTS %token SF_AT_END_CLIENTS %token SF_AT_START_CLIENT %token SF_AT_END_CLIENT %token SF_AT_START_IPPROTO %token SF_AT_END_IPPROTO %token SF_AT_START_PORT %token SF_AT_END_PORT %token SF_AT_START_PROTOCOL %token SF_AT_END_PROTOCOL %token SF_AT_START_APPLICATION %token SF_AT_END_APPLICATION %type MapEntryData %type AttributeInfo %type MapValue %type MapId %type AttributeValueString %type AttributeValueNumber %type AttributeConfidence %type AttributeId %% /* Grammar rules and actions follow */ /* The Main Grammar... Either a mapping table and attribute table, * or just the attribute table by itself. */ AttributeGrammar: SnortAttributes { YYACCEPT; }; SnortAttributes: SF_START_SNORT_ATTRIBUTES MappingTable AttributeTable SF_END_SNORT_ATTRIBUTES { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "SnortAttributes: Got Attribute Map & Table\n");); } | SF_START_SNORT_ATTRIBUTES AttributeTable SF_END_SNORT_ATTRIBUTES { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "SnortAttributes: Got Attribute Table\n");); }; /* The name-id map table for data reduction */ MappingTable: SF_AT_START_MAP_TABLE ListOfMapEntries SF_AT_END_MAP_TABLE { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Got Attribute Map\n");); }; ListOfMapEntries: { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Empty Mapping Table\n");); } | MapEntry ListOfMapEntries; MapEntry: MapEntryStart MapEntryData MapEntryEnd { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "MapEntry: Name: %s, Id %d\n", $2.s_mapvalue, $2.l_mapid);); SFAT_AddMapEntry(&$2); }; MapEntryStart: SF_AT_START_ENTRY; MapEntryEnd: SF_AT_END_ENTRY; MapEntryData: MapId MapValue { $$.l_mapid = $1; SnortStrncpy($$.s_mapvalue, $2, STD_BUF); }; MapValue: SF_AT_START_ENTRY_VALUE SF_AT_STRING SF_AT_END_ENTRY_VALUE { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "MapValue: %s\n", $2);) SnortStrncpy($$, $2, STD_BUF); }; MapId: SF_AT_START_ENTRY_ID SF_AT_NUMERIC SF_AT_END_ENTRY_ID { $$ = $2; DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "MapId: %d\n", $2);); }; /* The table of hosts and their respective attributes */ AttributeTable: SF_AT_START_ATTRIBUTE_TABLE ListOfHosts SF_AT_END_ATTRIBUTE_TABLE { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Got Attribute Table\n");); }; ListOfHosts: { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "EmptyHostEntry\n");); } | ListOfHosts HostEntry; HostEntry: HostEntryStart HostEntryData HostEntryEnd { if (SFAT_AddHostEntryToMap() != SFAT_OK) { YYABORT; } DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Host Added\n");); }; HostEntryStart: SF_AT_START_HOST { /* Callback to create a host entry object */ SFAT_CreateHostEntry(); }; HostEntryEnd: SF_AT_END_HOST; HostEntryData: IpCidr HostOS ServiceList ClientList { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "HostEntryData\n");); } | IpCidr HostOS ClientList { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "HostEntryData: No Services\n");); } | IpCidr HostOS ServiceList { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "HostEntryData: No Clients\n");); } | IpCidr HostOS { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "HostEntryData: No Services or Clients\n");); } ; IpCidr: SF_AT_START_HOST_IP SF_AT_STRING SF_AT_END_HOST_IP { /* Convert IP/CIDR to Snort IPCidr Object */ /* determine the number of bits (done in SetHostIp4) */ if (SFAT_SetHostIp($2) != SFAT_OK) { YYABORT; } }; HostOS: SF_AT_START_OS OSAttributes SF_AT_END_OS; OSAttributes: OSAttribute | OSAttributes OSAttribute; OSAttribute: OSName | OSVendor | OSVersion | OSStreamPolicy | OSFragPolicy; OSName: SF_AT_START_NAME AttributeInfo SF_AT_END_NAME { /* Copy OSName */ DEBUG_WRAP(PrintAttributeData("OS:Name", &$2);); SFAT_SetOSAttribute(&$2, HOST_INFO_OS); }; OSVendor: SF_AT_START_VENDOR AttributeInfo SF_AT_END_VENDOR { /* Copy OSVendor */ DEBUG_WRAP(PrintAttributeData("OS:Vendor", &$2);); SFAT_SetOSAttribute(&$2, HOST_INFO_VENDOR); }; OSVersion: SF_AT_START_VERSION AttributeInfo SF_AT_END_VERSION { /* Copy OSVersion */ DEBUG_WRAP(PrintAttributeData("OS:Version", &$2);); SFAT_SetOSAttribute(&$2, HOST_INFO_VERSION); }; OSFragPolicy: SF_AT_START_FRAG_POLICY SF_AT_STRING SF_AT_END_FRAG_POLICY { /* Copy OSFragPolicy */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "OS:FragPolicy: %s\n", $2);); SFAT_SetOSPolicy($2, HOST_INFO_FRAG_POLICY); }; OSStreamPolicy: SF_AT_START_STREAM_POLICY SF_AT_STRING SF_AT_END_STREAM_POLICY { /* Copy OSStreamPolicy */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "OS:StreamPolicy: %s\n", $2);); SFAT_SetOSPolicy($2, HOST_INFO_STREAM_POLICY); }; AttributeInfo: AttributeValueString { $$.type = ATTRIBUTE_NAME; $$.confidence = 100; SnortStrncpy($$.value.s_value, $1, STD_BUF); } | AttributeValueString AttributeConfidence { $$.type = ATTRIBUTE_NAME; $$.confidence = $2; SnortStrncpy($$.value.s_value, $1, STD_BUF); } | AttributeValueNumber AttributeConfidence { $$.type = ATTRIBUTE_NAME; $$.confidence = $2; SnortSnprintf($$.value.s_value, STD_BUF, "%d", $1); } | AttributeValueNumber { $$.type = ATTRIBUTE_NAME; $$.confidence = 100; SnortSnprintf($$.value.s_value, STD_BUF, "%d", $1); } | AttributeId AttributeConfidence { char *mapped_name; $$.confidence = $2; mapped_name = SFAT_LookupAttributeNameById($1); if (!mapped_name) { $$.type = ATTRIBUTE_ID; $$.value.l_value = $1; //FatalError("Unknown/Invalid Attribute ID %d\n", $1); sfat_grammar_error = "Unknown/Invalid Attribute ID"; YYABORT; } else { /* Copy String */ $$.type = ATTRIBUTE_NAME; SnortStrncpy($$.value.s_value, mapped_name, STD_BUF); } } | AttributeId { char *mapped_name; $$.confidence = 100; mapped_name = SFAT_LookupAttributeNameById($1); if (!mapped_name) { $$.type = ATTRIBUTE_ID; $$.value.l_value = $1; //FatalError("Unknown/Invalid Attribute ID %d\n", $1); sfat_grammar_error = "Unknown/Invalid Attribute ID"; YYABORT; } else { /* Copy String */ $$.type = ATTRIBUTE_NAME; SnortStrncpy($$.value.s_value, mapped_name, STD_BUF); } }; AttributeValueString: SF_AT_START_ATTRIBUTE_VALUE SF_AT_STRING SF_AT_END_ATTRIBUTE_VALUE { SnortStrncpy($$, $2, STD_BUF); }; AttributeValueNumber: SF_AT_START_ATTRIBUTE_VALUE SF_AT_END_ATTRIBUTE_VALUE { $$ = 0; } | SF_AT_START_ATTRIBUTE_VALUE SF_AT_NUMERIC SF_AT_END_ATTRIBUTE_VALUE { $$ = $2; }; AttributeId: SF_AT_START_ATTRIBUTE_ID SF_AT_NUMERIC SF_AT_END_ATTRIBUTE_ID { /* Copy numeric */ $$ = $2; }; AttributeConfidence: SF_AT_START_CONFIDENCE SF_AT_NUMERIC SF_AT_END_CONFIDENCE { /* Copy numeric */ $$ = $2; }; ServiceList: ServiceListStart ServiceListData ServiceListEnd { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "ServiceList (complete)\n");); }; ServiceListStart: SF_AT_START_SERVICES { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Start ServiceList\n");); sfat_client_or_service = ATTRIBUTE_SERVICE; }; ServiceListEnd: SF_AT_END_SERVICES { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "End ServiceList\n");); }; ServiceListData: { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "EmptyService\n");); } | Service ServiceListData { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service ServiceListData\n");); }; Service: ServiceStart ServiceData ServiceEnd { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Adding Complete\n");); SFAT_AddApplicationData(); DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Added\n");); }; ServiceStart: SF_AT_START_SERVICE { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Start\n");); SFAT_CreateApplicationEntry(); }; ServiceEnd: SF_AT_END_SERVICE { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service End\n");); }; ServiceData: ServiceDataRequired { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data (no application)\n");); } | ServiceDataRequired Application { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data (application)\n");); }; ServiceDataRequired: IPProtocol Protocol Port { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (IPProto Proto Port)\n");); } | IPProtocol Port Protocol { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (IPProto Port Proto)\n");); } | Protocol IPProtocol Port { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (Proto IPProto Port)\n");); } | Protocol Port IPProtocol { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (Proto Port IPProto)\n");); } | Port Protocol IPProtocol { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (Port Proto IPProto)\n");); } | Port IPProtocol Protocol { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (Port IPProto Proto)\n");); }; IPProtocol: SF_AT_START_IPPROTO AttributeInfo SF_AT_END_IPPROTO { /* Store IPProto Info */ DEBUG_WRAP(PrintAttributeData("IPProto", &$2);); SFAT_SetApplicationAttribute(&$2, APPLICATION_ENTRY_IPPROTO); }; Protocol: SF_AT_START_PROTOCOL AttributeInfo SF_AT_END_PROTOCOL { /* Store Protocol Info */ DEBUG_WRAP(PrintAttributeData("Protocol", &$2);); SFAT_SetApplicationAttribute(&$2, APPLICATION_ENTRY_PROTO); }; Port: SF_AT_START_PORT AttributeInfo SF_AT_END_PORT { /* Store Port Info */ DEBUG_WRAP(PrintAttributeData("Port", &$2);); SFAT_SetApplicationAttribute(&$2, APPLICATION_ENTRY_PORT); }; Application: SF_AT_START_APPLICATION AttributeInfo SF_AT_END_APPLICATION { /* Store Application Info */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Application\n")); DEBUG_WRAP(PrintAttributeData("Application", &$2);); SFAT_SetApplicationAttribute(&$2, APPLICATION_ENTRY_APPLICATION); } | SF_AT_START_APPLICATION AttributeInfo Version SF_AT_END_APPLICATION { /* Store Application Info */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Application with Version\n")); DEBUG_WRAP(PrintAttributeData("Application", &$2);); SFAT_SetApplicationAttribute(&$2, APPLICATION_ENTRY_APPLICATION); }; Version: SF_AT_START_VERSION AttributeInfo SF_AT_END_VERSION { /* Store Version Info */ DEBUG_WRAP(PrintAttributeData("Version", &$2);); SFAT_SetApplicationAttribute(&$2, APPLICATION_ENTRY_VERSION); }; ClientList: ClientListStart ClientListData ClientListEnd { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "ClientList (complete)\n");); }; ClientListStart: SF_AT_START_CLIENTS { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Start ClientList\n");); sfat_client_or_service = ATTRIBUTE_CLIENT; }; ClientListEnd: SF_AT_END_CLIENTS { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "End ClientList\n");); }; ClientListData: { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "EmptyClient\n");); } | Client ClientListData { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client ClientListData\n");); }; Client: ClientStart ClientData ClientEnd { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Adding Complete\n");); SFAT_AddApplicationData(); DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Added\n");); }; ClientStart: SF_AT_START_CLIENT { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Start\n");); SFAT_CreateApplicationEntry(); }; ClientEnd: SF_AT_END_CLIENT { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client End\n");); }; ClientData: ClientDataRequired { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data (no application)\n");); } | ClientDataRequired Application { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data (application)\n");); }; ClientDataRequired: Protocol { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data Required (Proto)\n");); } | IPProtocol Protocol { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data Required (IPProto Proto)\n");); } | Protocol IPProtocol { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data Required (Proto IPProto)\n");); }; %% /* int yywrap(void) { return 1; } */ #endif /* TARGET_BASED */ snort-2.9.6.0/src/target-based/sf_attribute_table_parser.l0000644000000000000000000002222412260565733020461 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sf_attribute_table_parser.l */ /* * Lex for Attribute Table */ /* Definitions Section. * Definitions required by the rules section are in here prior to first * "%%" seperator */ /* Include code between "%{ %}" separators at top of generated * lexer source file */ %{ #ifdef TARGET_BASED #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "util.h" #include "snort.h" #include "parser.h" #include "sftarget_reader.h" #include "sf_attribute_table.h" /* Generated from YACC */ extern ServiceClient sfat_client_or_service; static int sfat_linenumber = 0; static char* sfat_filename; void sfat_error(char *err); int sfat_parse(void); /* Change flex buffer size from default 8K to STD_BUF bytes */ #ifdef YY_BUF_SIZE #undef YY_BUF_SIZE #endif #define YY_BUF_SIZE STD_BUF #define YY_DECL int sfat_lex(void) %} /* At end-of-file return assuming no more files to scan */ %option noyywrap /* Not using this functionality */ %option nounput %option noinput /* Optimise lexer for interactive use */ %option never-interactive /* Declare exclusive start conditions. * Start conditions are included here to illustrate how to add simple * state-machine functionality to the lexer */ %x waiting_for_comma_prior_to_data %x waiting_for_data /* Define some common patterns for use below */ newline \r\n|\n whitespace [ \t]* comma , digit [0-9] numericValue [+-]?{digit}{1,16} stringValue [ \t_/\-a-zA-Z0-9,\.;:()#"'~`!@#$%^&*()=+\[\]|\{\}\?\\]{1,4096} commentStart \ comment {commentStart}.*{commentEnd} /* Rules Section. * All rules are in here prior to second "%%" seperator */ %% {whitespace} { ; } /* Handle empty whitespace */ \ { return SF_START_SNORT_ATTRIBUTES; } \<\/SNORT_ATTRIBUTES\> { return SF_END_SNORT_ATTRIBUTES; } \ { return SF_AT_START_MAP_TABLE; } \<\/ATTRIBUTE_MAP\> { return SF_AT_END_MAP_TABLE; } \ { return SF_AT_START_ENTRY; } \<\/ENTRY\> { return SF_AT_END_ENTRY; } \ { return SF_AT_START_ENTRY_ID; } \<\/ID\> { return SF_AT_END_ENTRY_ID; } \ { return SF_AT_START_ENTRY_VALUE; } \<\/VALUE\> { return SF_AT_END_ENTRY_VALUE; } \ { return SF_AT_START_ATTRIBUTE_TABLE; } \<\/ATTRIBUTE_TABLE\> { return SF_AT_END_ATTRIBUTE_TABLE; } \ { return SF_AT_START_HOST; } \<\/HOST\> { return SF_AT_END_HOST; } \ { return SF_AT_START_HOST_IP; } \<\/IP\> { return SF_AT_END_HOST_IP; } \ { return SF_AT_START_OS; } \<\/OPERATING_SYSTEM\> { return SF_AT_END_OS; } \ { return SF_AT_START_ATTRIBUTE_VALUE; } \<\/ATTRIBUTE_VALUE\> { return SF_AT_END_ATTRIBUTE_VALUE; } \ { return SF_AT_START_ATTRIBUTE_ID; } \<\/ATTRIBUTE_ID\> { return SF_AT_END_ATTRIBUTE_ID; } \ { return SF_AT_START_CONFIDENCE; } \<\/CONFIDENCE\> { return SF_AT_END_CONFIDENCE; } \ { return SF_AT_START_NAME; } \<\/NAME\> { return SF_AT_END_NAME; } \ { return SF_AT_START_VENDOR; } \<\/VENDOR\> { return SF_AT_END_VENDOR; } \ { return SF_AT_START_VERSION; } \<\/VERSION\> { return SF_AT_END_VERSION; } \ { return SF_AT_START_FRAG_POLICY; } \<\/FRAG_POLICY\> { return SF_AT_END_FRAG_POLICY; } \ { return SF_AT_START_STREAM_POLICY; } \<\/STREAM_POLICY\> { return SF_AT_END_STREAM_POLICY; } \ { return SF_AT_START_SERVICES; } \<\/SERVICES\> { return SF_AT_END_SERVICES; } \ { return SF_AT_START_SERVICE; } \<\/SERVICE\> { return SF_AT_END_SERVICE; } \ { return SF_AT_START_CLIENTS; } \<\/CLIENTS\> { return SF_AT_END_CLIENTS; } \ { return SF_AT_START_CLIENT; } \<\/CLIENT\> { return SF_AT_END_CLIENT; } \ { return SF_AT_START_IPPROTO; } \<\/IPPROTO\> { return SF_AT_END_IPPROTO; } \ { return SF_AT_START_PROTOCOL; } \<\/PROTOCOL\> { return SF_AT_END_PROTOCOL; } \ { return SF_AT_START_PORT; } \<\/PORT\> { return SF_AT_END_PORT; } \ { return SF_AT_START_APPLICATION; } \<\/APPLICATION\> { return SF_AT_END_APPLICATION; } {numericValue} { sfat_lval.numericValue = strtol( yytext, NULL, 10 ); #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "Number Value: [%d]\n", sfat_lval.numericValue); #endif return SF_AT_NUMERIC; } {stringValue} { /* Store the value of the string, but not * more than STD_BUF. */ int i; for (i=0; i < yyleng && i < STD_BUF-1; i++) { sfat_lval.stringValue[i] = yytext[i]; } sfat_lval.stringValue[i] = '\0'; #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "String Value: [%s]\n", sfat_lval.stringValue); #endif return SF_AT_STRING; } {newline} { sfat_linenumber++; } {comment} { ; /* Do nothing -- ignore it */} . { return 0; } /* Error, no meaningful input provided */ <> { yyterminate(); } %% char *sfat_grammar_error=NULL; char sfat_grammar_error_printed=0; char sfat_insufficient_space_logged=0; char sfat_fatal_error=1; char *sfat_saved_file = NULL; static char sfat_saved_file_set = 0; char parse_error = 0; char sfat_error_message[STD_BUF]; int ParseTargetMap(char *filename) { int error; int ret = SFAT_ERROR; parse_error = 0; sfat_grammar_error_printed = 0; if (!filename) { return SFAT_OK; } yyin = fopen(filename, "r"); if (!yyin) { SnortSnprintf(sfat_error_message, STD_BUF, "%s(%d): Failed to open target-based attribute file: '%s'\n", file_name, file_line, filename); return ret; } sfat_filename = filename; if (feof(yyin)) { SnortSnprintf(sfat_error_message, STD_BUF, "%s(%d): Emtpy target-based attribute file: '%s'\n", file_name, file_line, filename); fclose(yyin); return ret; } error = sfat_parse(); if (error) { sfat_error(""); fclose(yyin); return ret; } fclose(yyin); if (parse_error == 1) { return ret; } ret = SFAT_OK; /* Everything parsed ok, save off the filename */ if (sfat_saved_file_set && sfat_saved_file) { if (!strcmp(sfat_saved_file, sfat_filename)) { /* Same filename, we're done. */ return ret; } sfat_saved_file_set = 0; } /* Save off the new filename. */ if (sfat_saved_file) { free(sfat_saved_file); } sfat_saved_file = SnortStrdup(sfat_filename); sfat_saved_file_set = 1; return ret; } void DestroyBufferStack(void) { #ifdef HAVE_YYLEX_DESTROY sfatlex_destroy(); #endif } void sfat_error(char *err) { if (sfat_grammar_error_printed != 0) { parse_error = 1; return; } if (sfat_grammar_error) { SnortSnprintf(sfat_error_message, STD_BUF, "%s(%d) ==> Invalid Attribute Table specification: '%s'.\n" "Please verify the grammar at or near line %d (tag '%s'): %s\n", file_name, file_line, sfat_filename, sfat_linenumber, yytext, sfat_grammar_error); } else { SnortSnprintf(sfat_error_message, STD_BUF, "%s(%d) ==> Invalid Attribute Table specification: '%s'.\n" "Please verify the grammar at or near line %d (tag '%s').\n", file_name, file_line, sfat_filename, sfat_linenumber, yytext); } parse_error = 1; } #endif /* TARGET_BASED */ snort-2.9.6.0/src/target-based/sftarget_protocol_reference.h0000644000000000000000000000315412260565733021016 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sftarget_protocol_reference.h */ #ifndef SFTARGET_PROTOCOL_REFERENCE_TABLE_H_ #define SFTARGET_PROTOCOL_REFERENCE_TABLE_H_ #include "decode.h" #include "util.h" #define MAX_PROTOCOL_ORDINAL 8192 typedef struct _SFTargetProtocolReference { char name[STD_BUF]; int16_t ordinal; } SFTargetProtocolReference; extern int16_t protocolReferenceTCP; extern int16_t protocolReferenceUDP; extern int16_t protocolReferenceICMP; void InitializeProtocolReferenceTable(void); void FreeProtoocolReferenceTable(void); int16_t AddProtocolReference(const char *protocol); int16_t FindProtocolReference(const char *protocol); int16_t GetProtocolReference(Packet *p); #endif /* SFTARGET_PROTOCOL_REFERENCE_TABLE_H_ */ snort-2.9.6.0/src/target-based/sftarget_protocol_reference.c0000644000000000000000000001574312260565733021020 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sftarget_protocol_reference.c */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef TARGET_BASED #include "sftarget_protocol_reference.h" #include "sfutil/sfghash.h" #include "log.h" #include "util.h" #include "snort_debug.h" #include "stream_api.h" #include "spp_frag3.h" #include "sftarget_reader.h" #include "sftarget_hostentry.h" int16_t protocolReferenceTCP; int16_t protocolReferenceUDP; int16_t protocolReferenceICMP; static SFGHASH *proto_reference_table = NULL; static int16_t protocol_number = 1; static char *standard_protocols[] = { /* Transport Protocols */ "ip", "tcp", "udp", "icmp", /* Application Protocols */ "http", "ftp", "telnet", "smtp", "ssh", "dcerpc", "netbios-dgm", "netbios-ns", "netbios-ssn", "nntp", "dns", "isakmp", "finger", "imap", "oracle", "pop2", "pop3", "snmp", "tftp", "x11", "ftp-data", NULL }; /* XXX XXX Probably need to do this during swap time since the * proto_reference_table is accessed during runtime */ int16_t AddProtocolReference(const char *protocol) { SFTargetProtocolReference *reference; if (!protocol) return SFTARGET_UNKNOWN_PROTOCOL; if (!proto_reference_table) { InitializeProtocolReferenceTable(); } reference = sfghash_find(proto_reference_table, (void *)protocol); if (reference) { DEBUG_WRAP( DebugMessage(DEBUG_ATTRIBUTE, "Protocol Reference for %s exists as %d\n", protocol, reference->ordinal);); return reference->ordinal; } reference = SnortAlloc(sizeof(SFTargetProtocolReference)); reference->ordinal = protocol_number++; if (protocol_number > MAX_PROTOCOL_ORDINAL) { /* XXX: If we see this warning message, should * increase MAX_PROTOCOL_ORDINAL definition. The ordinal is * stored as a signed 16bit int, so it can be increased upto * 32k without requiring a change in space. It is currently * defined as 8192. */ LogMessage("WARNING: protocol_number wrapped. This may result" "in odd behavior and potential false positives.\n"); /* 1 is the first protocol id we use. */ /* 0 is not used */ /* -1 means unknwon */ protocol_number = 1; } SnortStrncpy(reference->name, protocol, STD_BUF); sfghash_add(proto_reference_table, reference->name, reference); DEBUG_WRAP( DebugMessage(DEBUG_ATTRIBUTE, "Added Protocol Reference for %s as %d\n", protocol, reference->ordinal);); return reference->ordinal; } int16_t FindProtocolReference(const char *protocol) { SFTargetProtocolReference *reference; if (!protocol) return SFTARGET_UNKNOWN_PROTOCOL; if (!proto_reference_table) { InitializeProtocolReferenceTable(); } reference = sfghash_find(proto_reference_table, (void *)protocol); if (reference) return reference->ordinal; return SFTARGET_UNKNOWN_PROTOCOL; } void InitializeProtocolReferenceTable(void) { char **protocol; /* If already initialized, we're done */ if (proto_reference_table) return; proto_reference_table = sfghash_new(65, 0, 1, free); if (!proto_reference_table) { FatalError("Failed to Initialize Target-Based Protocol Reference Table\n"); } /* Initialize the standard protocols from the list above */ for (protocol = standard_protocols; *protocol; protocol++) { AddProtocolReference(*protocol); } protocolReferenceTCP = FindProtocolReference("tcp"); protocolReferenceUDP = FindProtocolReference("udp"); protocolReferenceICMP = FindProtocolReference("icmp"); } void FreeProtoocolReferenceTable(void) { sfghash_delete(proto_reference_table); proto_reference_table = NULL; } int16_t GetProtocolReference(Packet *p) { int16_t protocol = 0; int16_t ipprotocol = 0; if (!p) return protocol; if (p->application_protocol_ordinal != 0) return p->application_protocol_ordinal; do /* Simple do loop to break out of quickly, not really a loop */ { HostAttributeEntry *host_entry; if (p->ssnptr && stream_api) { /* Use session information via Stream API */ protocol = stream_api->get_application_protocol_id(p->ssnptr); if (protocol != 0) { break; } } if (p->fragtracker) { protocol = fragGetApplicationProtocolId(p); /* Use information from frag tracker */ if (protocol != 0) { break; } } switch (GET_IPH_PROTO(p)) { case IPPROTO_TCP: ipprotocol = protocolReferenceTCP; break; case IPPROTO_UDP: ipprotocol = protocolReferenceUDP; break; case IPPROTO_ICMP: ipprotocol = protocolReferenceICMP; break; } /* Lookup the destination host to find the protocol for the * destination port */ host_entry = SFAT_LookupHostEntryByDst(p); if (host_entry) { protocol = getApplicationProtocolId(host_entry, ipprotocol, p->dp, SFAT_SERVICE); } if (protocol != 0) { break; } /* If not found, do same for src host/src port. */ host_entry = SFAT_LookupHostEntryBySrc(p); if (host_entry) { protocol = getApplicationProtocolId(host_entry, ipprotocol, p->sp, SFAT_SERVICE); } if (protocol != 0) { break; } } while (0); /* Simple do loop to break out of quickly, not really a loop */ /* Store it to alleviate future lookups */ p->application_protocol_ordinal = protocol; return protocol; } #endif /* TARGET_BASED */ snort-2.9.6.0/src/target-based/sftarget_hostentry.h0000644000000000000000000000415712260565733017202 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sftarget_hostentry.h */ #ifndef _SFTARGET_HOSTENTRY_H_ #define _SFTARGET_HOSTENTRY_H_ #include "sftarget_reader.h" #define SFTARGET_MATCH 1 #define SFTARGET_NOMATCH 0 /* API for HostAttributeEntry 'class' */ int hasService(HostAttributeEntry *hostEntry, int ipprotocol, int protocol, int application); int hasClient(HostAttributeEntry *hostEntry, int ipprotocol, int protocol, int application); int hasProtocol(HostAttributeEntry *hostEntry, int ipprotocol, int protocol, int application); int getProtocol(HostAttributeEntry *hostEntry, int ipprotocol, uint16_t port); int getApplicationProtocolId(HostAttributeEntry *host_entry, int ipprotocol, uint16_t port, char direction); #define SFAT_UNKNOWN_STREAM_POLICY 0 uint16_t getStreamPolicy(HostAttributeEntry *host_entry); char isStreamPolicySet(HostAttributeEntry *host_entry); #define SFAT_UNKNOWN_FRAG_POLICY 0 uint16_t getFragPolicy(HostAttributeEntry *host_entry); char isFragPolicySet(HostAttributeEntry *host_entry); #endif /* _SFTARGET_HOSTENTRY_H_ */ snort-2.9.6.0/src/target-based/sftarget_hostentry.c0000644000000000000000000001155012260565733017170 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sftarget_hostentry.c */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sftarget_hostentry.h" int hasService(HostAttributeEntry *host_entry, int ipprotocol, int protocol, int application) { ApplicationEntry *service; if (!host_entry) return SFTARGET_NOMATCH; for (service = host_entry->services; service; service = service->next) { if (ipprotocol && (service->ipproto == ipprotocol)) { if (protocol && (service->protocol == protocol)) { if (!application) { /* match of ipproto, proto. * application not speicifed */ return SFTARGET_MATCH; } } else if (!protocol) { /* match of ipproto. * protocol not speicifed */ return SFTARGET_MATCH; } } /* No ipprotocol specified, huh? */ } return SFTARGET_NOMATCH; } int hasClient(HostAttributeEntry *host_entry, int ipprotocol, int protocol, int application) { ApplicationEntry *client; if (!host_entry) return SFTARGET_NOMATCH; for (client = host_entry->clients; client; client = client->next) { if (ipprotocol && (client->ipproto == ipprotocol)) { if (protocol && (client->protocol == protocol)) { if (!application) { /* match of ipproto, proto. * application not speicifed */ return SFTARGET_MATCH; } } else if (!protocol) { /* match of ipproto. * protocol not speicifed */ return SFTARGET_MATCH; } } /* No ipprotocol specified, huh? */ } return SFTARGET_NOMATCH; } int hasProtocol(HostAttributeEntry *host_entry, int ipprotocol, int protocol, int application) { int ret = SFTARGET_NOMATCH; ret = hasService(host_entry, ipprotocol, protocol, application); if (ret == SFTARGET_MATCH) return ret; ret = hasClient(host_entry, ipprotocol, protocol, application); if (ret == SFTARGET_MATCH) return ret; return ret; } char isFragPolicySet(HostAttributeEntry *host_entry) { if (host_entry && host_entry->hostInfo.fragPolicySet) { return POLICY_SET; } return POLICY_NOT_SET; } char isStreamPolicySet(HostAttributeEntry *host_entry) { if (host_entry && host_entry->hostInfo.streamPolicySet) { return POLICY_SET; } return POLICY_NOT_SET; } uint16_t getFragPolicy(HostAttributeEntry *host_entry) { if (!host_entry) return SFAT_UNKNOWN_FRAG_POLICY; if (!host_entry->hostInfo.fragPolicySet) return SFAT_UNKNOWN_FRAG_POLICY; return host_entry->hostInfo.fragPolicy; } uint16_t getStreamPolicy(HostAttributeEntry *host_entry) { if (!host_entry) return SFAT_UNKNOWN_STREAM_POLICY; if (!host_entry->hostInfo.streamPolicySet) return SFAT_UNKNOWN_STREAM_POLICY; return host_entry->hostInfo.streamPolicy; } int getApplicationProtocolId(HostAttributeEntry *host_entry, int ipprotocol, uint16_t port, char direction) { ApplicationEntry *application; if (!host_entry) return 0; if (direction == SFAT_SERVICE) { for (application = host_entry->services; application; application = application->next) { if (application->ipproto == ipprotocol) { if ((uint16_t)application->port == port) { return application->protocol; } } } } /* TODO: client? doesn't make much sense in terms of specific port */ return 0; } snort-2.9.6.0/src/target-based/sftarget_reader.h0000644000000000000000000001100112260565733016367 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sftarget_reader.c */ #ifndef SF_TARGET_READER_H_ #define SF_TARGET_READER_H_ #include "snort.h" #define SFAT_OK 0 #define SFAT_ERROR -1 #define SFAT_CHECKHOST \ if (!current_host) return SFAT_ERROR; #define SFAT_CHECKAPP \ if (!current_app) return SFAT_ERROR; typedef enum { ATTRIBUTE_NAME, ATTRIBUTE_ID } AttributeTypes; typedef enum { ATTRIBUTE_SERVICE, ATTRIBUTE_CLIENT } ServiceClient; typedef struct _MapData { char s_mapvalue[STD_BUF]; uint32_t l_mapid; } MapData; typedef MapData MapEntry; typedef struct _AttributeData { AttributeTypes type; union { char s_value[STD_BUF]; uint32_t l_value; } value; int confidence; int16_t attributeOrdinal; } AttributeData; #define APPLICATION_ENTRY_PORT 0x01 #define APPLICATION_ENTRY_IPPROTO 0x02 #define APPLICATION_ENTRY_PROTO 0x04 #define APPLICATION_ENTRY_APPLICATION 0x08 #define APPLICATION_ENTRY_VERSION 0x10 typedef struct _ApplicationEntry { struct _ApplicationEntry *next; uint16_t port; uint16_t ipproto; uint16_t protocol; uint8_t fields; } ApplicationEntry; typedef ApplicationEntry ApplicationList; #define HOST_INFO_OS 1 #define HOST_INFO_VENDOR 2 #define HOST_INFO_VERSION 3 #define HOST_INFO_FRAG_POLICY 4 #define HOST_INFO_STREAM_POLICY 5 #define POLICY_SET 1 #define POLICY_NOT_SET 0 typedef struct _HostInfo { char streamPolicyName[16]; char fragPolicyName[16]; uint16_t streamPolicy; uint16_t fragPolicy; char streamPolicySet; char fragPolicySet; } HostInfo; #define SFAT_SERVICE 1 #define SFAT_CLIENT 2 typedef struct _HostAttributeEntry { sfip_t ipAddr; HostInfo hostInfo; ApplicationList *services; ApplicationList *clients; } HostAttributeEntry; /* Callback Functions from YACC */ int SFAT_AddMapEntry(MapEntry *); char *SFAT_LookupAttributeNameById(int id); HostAttributeEntry * SFAT_CreateHostEntry(void); int SFAT_AddHostEntryToMap(void); int SFAT_SetHostIp(char *); int SFAT_SetOSAttribute(AttributeData *data, int attribute); int SFAT_SetOSPolicy(char *policy_name, int attribute); ApplicationEntry * SFAT_CreateApplicationEntry(void); int SFAT_AddApplicationData(void); int SFAT_SetApplicationAttribute(AttributeData *data, int attribute); void PrintAttributeData(char *prefix, AttributeData *data); /* Callback to set frag & stream policy IDs */ typedef int (*GetPolicyIdFunc)(HostAttributeEntry *); typedef struct _GetPolicyIdsCallbackList { GetPolicyIdFunc policyCallback; struct _GetPolicyIdsCallbackList *next; } GetPolicyIdsCallbackList; void SFAT_SetPolicyIds(GetPolicyIdFunc policyCallback, int snortPolicyId); /* Cleanup Functions, called by Snort shutdown */ void SFAT_Cleanup(void); void FreeHostEntry(HostAttributeEntry *host); /* Parsing Functions -- to be called by Snort parser */ int SFAT_ParseAttributeTable(char *args); /* Function to swap out new table */ void AttributeTableReloadCheck(void); /* Status functions */ uint32_t SFAT_NumberOfHosts(void); /* API Lookup functions, to be called by Stream & Frag */ HostAttributeEntry *SFAT_LookupHostEntryByIP(sfip_t *ipAddr); HostAttributeEntry *SFAT_LookupHostEntryBySrc(Packet *p); HostAttributeEntry *SFAT_LookupHostEntryByDst(Packet *p); void SFAT_UpdateApplicationProtocol(sfip_t *ipAddr, uint16_t port, uint16_t protocol, uint16_t id); /* Returns whether this has been configured */ int IsAdaptiveConfigured(tSfPolicyId); int IsAdaptiveConfiguredForSnortConfig(struct _SnortConfig *, tSfPolicyId); void SFAT_StartReloadThread(void); void SFLAT_init(void); void SFLAT_fini(void); int SFLAT_isEnabled(tSfPolicyId id, int parsing); #endif /* SF_TARGET_READER_H_ */ snort-2.9.6.0/src/target-based/sftarget_reader.c0000644000000000000000000010213712260565733016375 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sftarget_reader.c */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef TARGET_BASED #include #include "mstring.h" #include "util.h" #include "parser.h" #include "sftarget_reader.h" #include "sftarget_protocol_reference.h" #include "sfutil/sfrt.h" #include "sfutil/sfxhash.h" #include "sfutil/util_net.h" #include "sftarget_hostentry.h" #include #include #include #include #include #include #include #ifndef WIN32 #include #include #include #endif #include "snort.h" #include "snort_debug.h" #include "sfPolicy.h" typedef struct { table_t *lookupTable; SFXHASH *mapTable; } tTargetBasedConfig; typedef struct { /**current configuration. */ tTargetBasedConfig curr; /**previous configuration. */ tTargetBasedConfig prev; /**next configuration. */ tTargetBasedConfig next; //XXX recheck this flag usage //char reload_attribute_table_flags; } tTargetBasedPolicyConfig; static tTargetBasedPolicyConfig targetBasedPolicyConfig; static HostAttributeEntry *current_host = NULL; static ApplicationEntry *current_app = NULL; //static MapData *current_map_entry = NULL; ServiceClient sfat_client_or_service; extern char sfat_error_message[STD_BUF]; extern char sfat_grammar_error_printed; extern char sfat_insufficient_space_logged; extern char sfat_fatal_error; int ParseTargetMap(char *filename); void DestroyBufferStack(void); extern char *sfat_saved_file; extern pthread_t attribute_reload_thread_id; extern pid_t attribute_reload_thread_pid; extern volatile int attribute_reload_thread_running; extern volatile int attribute_reload_thread_stop; extern int reload_attribute_table_flags; extern const struct timespec thread_sleep; /*****TODO: cleanup to use config directive *******/ #define ATTRIBUTE_MAP_MAX_ROWS 1024 uint32_t SFAT_NumberOfHosts(void) { tTargetBasedPolicyConfig *pConfig = &targetBasedPolicyConfig; if (pConfig->curr.lookupTable) { return sfrt_num_entries(pConfig->curr.lookupTable); } return 0; } int SFAT_AddMapEntry(MapEntry *entry) { tTargetBasedPolicyConfig *pConfig = &targetBasedPolicyConfig; if (!pConfig->next.mapTable) { /* Attribute Table node includes memory for each entry, * as defined by sizeof(MapEntry). */ pConfig->next.mapTable = sfxhash_new(ATTRIBUTE_MAP_MAX_ROWS, sizeof(int), sizeof(MapEntry), 0, 1, NULL, NULL, 1); if (!pConfig->next.mapTable) FatalError("Failed to allocate attribute map table\n"); } /* Memcopy MapEntry to newly allocated one and store in * a hash table based on entry->id for easy lookup. */ DEBUG_WRAP( DebugMessage(DEBUG_ATTRIBUTE, "Adding Map Entry: %d %s\n", entry->l_mapid, entry->s_mapvalue);); /* Data from entry will be copied into new node */ sfxhash_add(pConfig->next.mapTable, &entry->l_mapid, entry); return SFAT_OK; } char *SFAT_LookupAttributeNameById(int id) { MapEntry *entry; tTargetBasedPolicyConfig *pConfig = &targetBasedPolicyConfig; if (!pConfig->next.mapTable) return NULL; entry = sfxhash_find(pConfig->next.mapTable, &id); if (entry) { DEBUG_WRAP( DebugMessage(DEBUG_ATTRIBUTE, "Found Attribute Name %s for Id %d\n", entry->s_mapvalue, id);); return entry->s_mapvalue; } DEBUG_WRAP( DebugMessage(DEBUG_ATTRIBUTE, "No Attribute Name for Id %d\n", id);); return NULL; } void FreeApplicationEntry(ApplicationEntry *app) { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Freeing ApplicationEntry: 0x%x\n", app);); free(app); } ApplicationEntry * SFAT_CreateApplicationEntry(void) { if (current_app) { /* Something went wrong */ FreeApplicationEntry(current_app); current_app = NULL; } current_app = SnortAlloc(sizeof(ApplicationEntry)); return current_app; } HostAttributeEntry * SFAT_CreateHostEntry(void) { if (current_host) { /* Something went wrong */ FreeHostEntry(current_host); current_host = NULL; } current_host = SnortAlloc(sizeof(HostAttributeEntry)); return current_host; } void FreeHostEntry(HostAttributeEntry *host) { ApplicationEntry *app = NULL, *tmp_app; if (!host) return; DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Freeing HostEntry: 0x%x\n", host);); /* Free the service list */ if (host->services) { do { tmp_app = host->services; app = tmp_app->next; FreeApplicationEntry(tmp_app); host->services = app; } while (app); } /* Free the client list */ if (host->clients) { do { tmp_app = host->clients; app = tmp_app->next; FreeApplicationEntry(tmp_app); host->clients = app; } while (app); } free(host); } void PrintAttributeData(char *prefix, AttributeData *data) { #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "AttributeData for %s\n", prefix); if (data->type == ATTRIBUTE_NAME) { DebugMessage(DEBUG_ATTRIBUTE, "\ttype: %s\tname: %s\t confidence %d\n", "Name", data->value.s_value, data->confidence); } else { DebugMessage(DEBUG_ATTRIBUTE, "\ttype: %s\tid: %s\t confidence %d", "Id", data->value.l_value, data->confidence); } #endif } int SFAT_SetHostIp(char *ip) { static HostAttributeEntry *tmp_host = NULL; sfip_t ipAddr; tTargetBasedPolicyConfig *pConfig = &targetBasedPolicyConfig; SFAT_CHECKHOST; if (sfip_pton(ip, &ipAddr) != SFIP_SUCCESS) { return SFAT_ERROR; } if (ipAddr.family == AF_INET) { ipAddr.ip32[0] = ntohl(ipAddr.ip32[0]); } tmp_host = sfrt_lookup(&ipAddr, pConfig->next.lookupTable); if (tmp_host && sfip_equals(tmp_host->ipAddr, ipAddr)) { /* Exact match. */ FreeHostEntry(current_host); current_host = tmp_host; } else { /* New entry for this host/CIDR */ sfip_set_ip(¤t_host->ipAddr, &ipAddr); } return SFAT_OK; } int SFAT_SetOSPolicy(char *policy_name, int attribute) { SFAT_CHECKHOST; switch (attribute) { case HOST_INFO_FRAG_POLICY: SnortStrncpy(current_host->hostInfo.fragPolicyName, policy_name, sizeof(current_host->hostInfo.fragPolicyName)); break; case HOST_INFO_STREAM_POLICY: SnortStrncpy(current_host->hostInfo.streamPolicyName, policy_name, sizeof(current_host->hostInfo.streamPolicyName)); break; } return SFAT_OK; } int SFAT_SetOSAttribute(AttributeData *data, int attribute) { SFAT_CHECKHOST; // currently not using os, vendor, or version return SFAT_OK; } static void AppendApplicationData(ApplicationList **list) { if (!list) return; if (*list) { current_app->next = *list; } *list = current_app; current_app = NULL; } int SFAT_AddApplicationData(void) { uint8_t required_fields; SFAT_CHECKAPP; SFAT_CHECKHOST; if (sfat_client_or_service == ATTRIBUTE_SERVICE) { required_fields = (APPLICATION_ENTRY_PORT | APPLICATION_ENTRY_IPPROTO | APPLICATION_ENTRY_PROTO); if ((current_app->fields & required_fields) != required_fields) { sfip_t host_addr; sfip_set_ip(&host_addr, ¤t_host->ipAddr); host_addr.ip32[0] = ntohl(host_addr.ip32[0]); FatalError("%s(%d): Missing required field in Service attribute table for host %s\n", file_name, file_line, inet_ntoa(&host_addr) ); } AppendApplicationData(¤t_host->services); } else { required_fields = (APPLICATION_ENTRY_PROTO); /* Currently, client data only includes PROTO, not IPPROTO */ if ((current_app->fields & required_fields) != required_fields) { sfip_t host_addr; sfip_set_ip(&host_addr, ¤t_host->ipAddr); host_addr.ip32[0] = ntohl(host_addr.ip32[0]); FatalError("%s(%d): Missing required field in Client attribute table for host %s\n", file_name, file_line, inet_ntoa(&host_addr) ); } AppendApplicationData(¤t_host->clients); } return SFAT_OK; } int SFAT_SetApplicationAttribute(AttributeData *data, int attribute) { SFAT_CHECKAPP; switch(attribute) { case APPLICATION_ENTRY_PORT: /* Convert the port to a integer */ if (data->type == ATTRIBUTE_NAME) { char *endPtr = NULL; unsigned long value = SnortStrtoul(data->value.s_value, &endPtr, 10); if ((endPtr == &data->value.s_value[0]) || (errno == ERANGE) || value > UINT16_MAX) { current_app->port = 0; return SFAT_ERROR; } current_app->port = (uint16_t)value; } else { if (data->value.l_value > UINT16_MAX) { current_app->port = 0; return SFAT_ERROR; } current_app->port = (uint16_t)data->value.l_value; } break; case APPLICATION_ENTRY_IPPROTO: /* Add IP Protocol to the reference list */ current_app->ipproto = AddProtocolReference(data->value.s_value); break; case APPLICATION_ENTRY_PROTO: /* Add Application Protocol to the reference list */ current_app->protocol = AddProtocolReference(data->value.s_value); break; // currently not using application or version default: attribute = 0; } current_app->fields |= attribute; return SFAT_OK; } #ifdef DEBUG_MSGS void PrintHostAttributeEntry(HostAttributeEntry *host) { ApplicationEntry *app; int i = 0; sfip_t host_addr; if (!host) return; sfip_set_ip(&host_addr, &host->ipAddr); host_addr.ip32[0] = ntohl(host_addr.ip32[0]); DebugMessage(DEBUG_ATTRIBUTE, "Host IP: %s/%d\n", inet_ntoa(&host_addr), host->ipAddr.bits ); DebugMessage(DEBUG_ATTRIBUTE, "\tPolicy Information: frag:%s (%s %u) stream: %s (%s %u)\n", host->hostInfo.fragPolicyName, host->hostInfo.fragPolicySet ? "set":"unset", host->hostInfo.fragPolicy, host->hostInfo.fragPolicyName, host->hostInfo.streamPolicySet ? "set":"unset", host->hostInfo.streamPolicy); DebugMessage(DEBUG_ATTRIBUTE, "\tServices:\n"); for (i=0, app = host->services; app; app = app->next,i++) { DebugMessage(DEBUG_ATTRIBUTE, "\tService #%d:\n", i); DebugMessage(DEBUG_ATTRIBUTE, "\t\tIPProtocol: %s\tPort: %s\tProtocol %s\n", app->ipproto, app->port, app->protocol); } if (i==0) DebugMessage(DEBUG_ATTRIBUTE, "\t\tNone\n"); DebugMessage(DEBUG_ATTRIBUTE, "\tClients:\n"); for (i=0, app = host->clients; app; app = app->next,i++) { DebugMessage(DEBUG_ATTRIBUTE, "\tClient #%d:\n", i); DebugMessage(DEBUG_ATTRIBUTE, "\t\tIPProtocol: %s\tProtocol %s\n", app->ipproto, app->protocol); if (app->fields & APPLICATION_ENTRY_PORT) { DebugMessage(DEBUG_ATTRIBUTE, "\t\tPort: %s\n", app->port); } } if (i==0) { DebugMessage(DEBUG_ATTRIBUTE, "\t\tNone\n"); } } #endif int SFAT_AddHostEntryToMap(void) { HostAttributeEntry *host = current_host; int ret; sfip_t *ipAddr; tTargetBasedPolicyConfig *pConfig = &targetBasedPolicyConfig; SFAT_CHECKHOST; DEBUG_WRAP(PrintHostAttributeEntry(host);); ipAddr = &host->ipAddr; ret = sfrt_insert(ipAddr, (unsigned char)ipAddr->bits, host, RT_FAVOR_SPECIFIC, pConfig->next.lookupTable); if (ret != RT_SUCCESS) { if (ret == RT_POLICY_TABLE_EXCEEDED) { if (!sfat_insufficient_space_logged) { SnortSnprintf(sfat_error_message, STD_BUF, "AttributeTable insertion failed: %d Insufficient " "space in attribute table, only configured to store %d hosts\n", ret, ScMaxAttrHosts()); sfat_grammar_error_printed = 1; sfat_insufficient_space_logged = 1; sfat_fatal_error = 0; } /* Reset return value and continue w/ only snort_conf->max_attribute_hosts */ ret = RT_SUCCESS; } else { SnortSnprintf(sfat_error_message, STD_BUF, "AttributeTable insertion failed: %d '%s'\n", ret, rt_error_messages[ret]); sfat_grammar_error_printed = 1; } FreeHostEntry(host); } current_host = NULL; return ret == RT_SUCCESS ? SFAT_OK : SFAT_ERROR; } HostAttributeEntry *SFAT_LookupHostEntryByIP(sfip_t *ipAddr) { tTargetBasedPolicyConfig *pConfig = NULL; tSfPolicyId policyId = getRuntimePolicy(); HostAttributeEntry *host = NULL; sfip_t local_ipAddr; TargetBasedConfig *tbc = &snort_conf->targeted_policies[policyId]->target_based_config; if (tbc->args == NULL) { //this policy didn't specify attribute_table return NULL; } pConfig = &targetBasedPolicyConfig; sfip_set_ip(&local_ipAddr, ipAddr); if (local_ipAddr.family == AF_INET) { local_ipAddr.ip32[0] = ntohl(local_ipAddr.ip32[0]); } host = sfrt_lookup(&local_ipAddr, pConfig->curr.lookupTable); if (host) { /* Set the policy values for Frag & Stream if not already set */ //TODO: SetTargetBasedPolicy(host); } return host; } HostAttributeEntry *SFAT_LookupHostEntryBySrc(Packet *p) { if (!p || !p->iph_api) return NULL; return SFAT_LookupHostEntryByIP(GET_SRC_IP(p)); } HostAttributeEntry *SFAT_LookupHostEntryByDst(Packet *p) { if (!p || !p->iph_api) return NULL; return SFAT_LookupHostEntryByIP(GET_DST_IP(p)); } static GetPolicyIdFunc updatePolicyCallback; static GetPolicyIdsCallbackList *updatePolicyCallbackList = NULL; void SFAT_SetPolicyCallback(void *host_attr_ent) { HostAttributeEntry *host_entry = (HostAttributeEntry*)host_attr_ent; if (!host_entry) return; updatePolicyCallback(host_entry); return; } void SFAT_SetPolicyIds(GetPolicyIdFunc policyCallback, int snortPolicyId) { tTargetBasedPolicyConfig *pConfig = NULL; GetPolicyIdsCallbackList *list_entry, *new_list_entry = NULL; pConfig = &targetBasedPolicyConfig; updatePolicyCallback = policyCallback; sfrt_iterate(pConfig->curr.lookupTable, SFAT_SetPolicyCallback); if (!updatePolicyCallbackList) { /* No list present, so no attribute table... bye-bye */ return; } /* Look for this callback in the list */ list_entry = updatePolicyCallbackList; while (list_entry) { if (list_entry->policyCallback == policyCallback) return; /* We're done with this one */ if (list_entry->next) { list_entry = list_entry->next; } else { /* Leave list_entry pointint to last node in list */ break; } } /* Wasn't there, add it so that when we reload the table, * we can set those policy entries on reload. */ new_list_entry = (GetPolicyIdsCallbackList *)SnortAlloc(sizeof(GetPolicyIdsCallbackList)); new_list_entry->policyCallback = policyCallback; if (list_entry) { /* list_entry is valid here since there was at least an * empty head entry in the list. */ list_entry->next = new_list_entry; } } void SFAT_CleanupCallback(void *host_attr_ent) { HostAttributeEntry *host_entry = (HostAttributeEntry*)host_attr_ent; FreeHostEntry(host_entry); } void SFAT_Cleanup(void) { GetPolicyIdsCallbackList *list_entry, *tmp_list_entry = NULL; tTargetBasedPolicyConfig *pConfig = &targetBasedPolicyConfig; if (pConfig->curr.mapTable) { sfxhash_delete(pConfig->curr.mapTable); } if (pConfig->prev.mapTable) { sfxhash_delete(pConfig->prev.mapTable); } if (pConfig->next.mapTable) { sfxhash_delete(pConfig->next.mapTable); } if (pConfig->curr.lookupTable) { sfrt_cleanup(pConfig->curr.lookupTable, SFAT_CleanupCallback); sfrt_free(pConfig->curr.lookupTable); } if (pConfig->prev.lookupTable) { sfrt_cleanup(pConfig->prev.lookupTable, SFAT_CleanupCallback); sfrt_free(pConfig->prev.lookupTable); } if (pConfig->next.lookupTable) { sfrt_cleanup(pConfig->next.lookupTable, SFAT_CleanupCallback); sfrt_free(pConfig->next.lookupTable); } FreeProtoocolReferenceTable(); if (sfat_saved_file) { free(sfat_saved_file); sfat_saved_file = NULL; } if (updatePolicyCallbackList) { list_entry = updatePolicyCallbackList; while (list_entry) { tmp_list_entry = list_entry->next; free(list_entry); list_entry = tmp_list_entry; } updatePolicyCallbackList = NULL; } DestroyBufferStack(); } #define set_attribute_table_flag(flag) \ reload_attribute_table_flags |= flag; #define clear_attribute_table_flag(flag) \ reload_attribute_table_flags &= ~flag; #define check_attribute_table_flag(flag) \ (reload_attribute_table_flags & flag) static void SigAttributeTableReloadHandler(int signal) { /* If we're already reloading, don't do anything. */ if (check_attribute_table_flag(ATTRIBUTE_TABLE_RELOADING_FLAG)) return; /* Set flag to reload attribute table */ set_attribute_table_flag(ATTRIBUTE_TABLE_RELOAD_FLAG); } void SFAT_VTAlrmHandler(int signal) { /* Do nothing, just used to wake the sleeping dog... */ return; } void *SFAT_ReloadAttributeTableThread(void *arg) { #ifndef WIN32 sigset_t mtmask, oldmask; int ret; int reloads = 0; tTargetBasedPolicyConfig *pConfig = NULL; pConfig = &targetBasedPolicyConfig; sigemptyset(&mtmask); attribute_reload_thread_pid = gettid(); /* Get the current set of signals inherited from main thread.*/ pthread_sigmask(SIG_UNBLOCK, &mtmask, &oldmask); /* Now block those signals from being delivered to this thread. * now Main receives all signals. */ pthread_sigmask(SIG_BLOCK, &oldmask, NULL); /* And allow SIGVTALRM through */ signal (SIGVTALRM, SFAT_VTAlrmHandler); if(errno!=0) errno=0; sigemptyset(&mtmask); sigaddset(&mtmask, SIGVTALRM); pthread_sigmask(SIG_UNBLOCK, &mtmask, NULL); attribute_reload_thread_running = 1; /* Checks the flag and terminates the attribute reload thread. * * Receipt of VTALRM signal pulls it out of the idle sleep (at * bottom of while(). Thread exits normally on next iteration * through its loop because stop flag is set. */ while (!attribute_reload_thread_stop) { #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "AttrReloadThread: Checking for new attr table...\n"); #endif ret = SFAT_ERROR; /* Is there an old table waiting to be cleaned up? */ if (check_attribute_table_flag(ATTRIBUTE_TABLE_TAKEN_FLAG)) { if (check_attribute_table_flag(ATTRIBUTE_TABLE_AVAILABLE_FLAG)) { #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "AttrReloadThread: Freeing old attr table...\n"); #endif /* Free the map and attribute tables that are stored in * prev.mapTable and prev.lookupTable */ sfxhash_delete(pConfig->prev.mapTable); pConfig->prev.mapTable = NULL; sfrt_cleanup(pConfig->prev.lookupTable, SFAT_CleanupCallback); sfrt_free(pConfig->prev.lookupTable); pConfig->prev.lookupTable = NULL; clear_attribute_table_flag(ATTRIBUTE_TABLE_AVAILABLE_FLAG); } clear_attribute_table_flag(ATTRIBUTE_TABLE_PARSE_FAILED_FLAG); clear_attribute_table_flag(ATTRIBUTE_TABLE_TAKEN_FLAG); continue; } else if (check_attribute_table_flag(ATTRIBUTE_TABLE_RELOAD_FLAG) && !check_attribute_table_flag(ATTRIBUTE_TABLE_AVAILABLE_FLAG) && !check_attribute_table_flag(ATTRIBUTE_TABLE_PARSE_FAILED_FLAG)) { /* Is there an new table ready? */ set_attribute_table_flag(ATTRIBUTE_TABLE_RELOADING_FLAG); #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "AttrReloadThread: loading new attr table.\n"); #endif reloads++; if (sfat_saved_file) { /* Initialize a new lookup table */ if (!pConfig->next.lookupTable) { /* Add 1 to max for table purposes * We use max_hosts to limit memcap, assume 16k per entry costs*/ pConfig->next.lookupTable = sfrt_new(DIR_8x16, IPv6, ScMaxAttrHosts() + 1, ((ScMaxAttrHosts())>>6) + 1); if (!pConfig->next.lookupTable) { SnortSnprintf(sfat_error_message, STD_BUF, "Failed to initialize memory for new attribute table\n"); clear_attribute_table_flag(ATTRIBUTE_TABLE_RELOAD_FLAG); clear_attribute_table_flag(ATTRIBUTE_TABLE_RELOADING_FLAG); set_attribute_table_flag(ATTRIBUTE_TABLE_PARSE_FAILED_FLAG); continue; } } ret = ParseTargetMap(sfat_saved_file); if (ret == SFAT_OK) { GetPolicyIdsCallbackList *list_entry = NULL; /* Set flag that a new table is available. Main * process will check that flag and do the swap. * After the new table is in use, the available * flag should be cleared, the taken flag gets set * and we'll go off and free the old one. */ /* Set the policy IDs in the new table... */ list_entry = (GetPolicyIdsCallbackList *)arg; while (list_entry) { if (list_entry->policyCallback) { sfrt_iterate(pConfig->next.lookupTable, (sfrt_iterator_callback)list_entry->policyCallback); } list_entry = list_entry->next; } set_attribute_table_flag(ATTRIBUTE_TABLE_AVAILABLE_FLAG); } else { /* Failed to parse, clean it up */ if (pConfig->next.mapTable) sfxhash_delete(pConfig->next.mapTable); pConfig->next.mapTable = NULL; sfrt_cleanup(pConfig->next.lookupTable, SFAT_CleanupCallback); sfrt_free(pConfig->next.lookupTable); pConfig->next.lookupTable = NULL; set_attribute_table_flag(ATTRIBUTE_TABLE_PARSE_FAILED_FLAG); } } clear_attribute_table_flag(ATTRIBUTE_TABLE_RELOAD_FLAG); clear_attribute_table_flag(ATTRIBUTE_TABLE_RELOADING_FLAG); } else { /* Sleep for 60 seconds */ #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "AttrReloadThread: Checked for new attr table... sleeping.\n"); #endif sleep(60); } } #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "AttrReloadThread: exiting... Handled %d reloads\n", reloads); #endif attribute_reload_thread_running = 0; pthread_exit(NULL); #endif /* !Win32 */ return NULL; } void AttributeTableReloadCheck(void) { tTargetBasedPolicyConfig *pConfig = NULL; pConfig = &targetBasedPolicyConfig; if (check_attribute_table_flag(ATTRIBUTE_TABLE_TAKEN_FLAG)) { return; /* Nothing to do, waiting for thread to clear this * flag... */ } /* Swap the attribute table pointers. */ else if ((pConfig != NULL) && check_attribute_table_flag(ATTRIBUTE_TABLE_AVAILABLE_FLAG)) { LogMessage("Swapping Attribute Tables.\n"); /***Do this on receipt of new packet ****/ /***Avoids need for mutex****/ pConfig->prev.lookupTable = pConfig->curr.lookupTable; pConfig->curr.lookupTable = pConfig->next.lookupTable; pConfig->next.lookupTable = NULL; pConfig->prev.mapTable = pConfig->curr.mapTable; pConfig->curr.mapTable = pConfig->next.mapTable; pConfig->next.mapTable = NULL; /* Set taken to indicate we've taken the new table */ set_attribute_table_flag(ATTRIBUTE_TABLE_TAKEN_FLAG); sfBase.iAttributeHosts = SFAT_NumberOfHosts(); sfBase.iAttributeReloads++; pc.attribute_table_reloads++; } else if (check_attribute_table_flag(ATTRIBUTE_TABLE_PARSE_FAILED_FLAG)) { LogMessage("%s", sfat_error_message); /* Set taken to indicate we've taken the error message */ set_attribute_table_flag(ATTRIBUTE_TABLE_TAKEN_FLAG); } } /**called once during initialization. Reads attribute table for the first time.*/ int SFAT_ParseAttributeTable(char *args) { char **toks; int num_toks; int ret; tTargetBasedPolicyConfig *pConfig = &targetBasedPolicyConfig; DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"AttributeTable\n");); /* Initialize lookup table */ if (!pConfig->next.lookupTable) { /* Add 1 to max for table purposes * We use max_hosts to limit memcap, assume 16k per entry costs*/ pConfig->next.lookupTable = sfrt_new(DIR_8x16, IPv6, ScMaxAttrHosts() + 1, ((ScMaxAttrHosts())>>6)+ 1); if (!pConfig->next.lookupTable) { FatalError("Failed to initialize attribute table memory\n"); } } /* Parse filename */ toks = mSplit(args, " \t", 0, &num_toks, 0); if (num_toks != 2) { FatalError("%s(%d) ==> attribute_table must have 2 parameters\n", file_name, file_line); } if (!(strcasecmp(toks[0], "filename") == 0)) { FatalError("%s(%d) ==> attribute_table must have 2 arguments, the 1st " "is 'filename'\n", file_name, file_line); } /* Reset... */ sfat_insufficient_space_logged = 0; sfat_fatal_error = 1; ret = ParseTargetMap(toks[1]); if (ret == SFAT_OK) { pConfig->curr.lookupTable = pConfig->next.lookupTable; pConfig->next.lookupTable = NULL; pConfig->curr.mapTable = pConfig->next.mapTable; pConfig->next.mapTable = NULL; if (sfat_insufficient_space_logged) LogMessage("%s", sfat_error_message); } else { LogMessage("%s", sfat_error_message); if (sfat_fatal_error) FatalError("%s(%d) ==> failed to load attribute table from %s\n", file_name, file_line, toks[1]); } mSplitFree(&toks, num_toks); /* Create Thread to handle reparsing stuff... */ sfBase.iAttributeHosts = SFAT_NumberOfHosts(); LogMessage("Attribute Table Loaded with " STDu64 " hosts\n", sfBase.iAttributeHosts); /* Set up the head (empty) node in the policy callback list to * pass to thread.*/ updatePolicyCallbackList = (GetPolicyIdsCallbackList *)SnortAlloc(sizeof(GetPolicyIdsCallbackList)); #ifndef WIN32 if (!ScDisableAttrReload()) { /* Register signal handler for attribute table. */ SnortAddSignal(SIGNAL_SNORT_READ_ATTR_TBL,SigAttributeTableReloadHandler,0); if(errno != 0) errno = 0; } #endif return SFAT_OK; } void SFAT_StartReloadThread(void) { #ifndef WIN32 if (!IsAdaptiveConfigured(getDefaultPolicy()) || ScDisableAttrReload()) return; LogMessage("Attribute Table Reload Thread Starting...\n"); if (pthread_create(&attribute_reload_thread_id, NULL, SFAT_ReloadAttributeTableThread, updatePolicyCallbackList)) { FatalError("Failed to start thread to handle reloading attribute table\n"); } while (!attribute_reload_thread_running) nanosleep(&thread_sleep, NULL); LogMessage("Attribute Table Reload Thread Started, thread %p (%u)\n", (void*)attribute_reload_thread_id, attribute_reload_thread_pid); #endif } int IsAdaptiveConfigured(tSfPolicyId id) { SnortConfig *sc = snort_conf; if (id >= sc->num_policies_allocated) { ErrorMessage("%s(%d) Policy id is greater than the number of policies " "allocated.\n", __FILE__, __LINE__); return 0; } if ((sc->targeted_policies[id] == NULL) || (sc->targeted_policies[id]->target_based_config.args == NULL)) { return 0; } return 1; } int IsAdaptiveConfiguredForSnortConfig(struct _SnortConfig *sc, tSfPolicyId id) { if (sc == NULL) { FatalError("%s(%d) Snort conf for parsing is NULL.\n", __FILE__, __LINE__); } if (id >= sc->num_policies_allocated) { ErrorMessage("%s(%d) Policy id is greater than the number of policies " "allocated.\n", __FILE__, __LINE__); return 0; } if ((sc->targeted_policies[id] == NULL) || (sc->targeted_policies[id]->target_based_config.args == NULL)) { return 0; } return 1; } void SFAT_UpdateApplicationProtocol(sfip_t *ipAddr, uint16_t port, uint16_t protocol, uint16_t id) { HostAttributeEntry *host_entry; ApplicationEntry *service; tTargetBasedPolicyConfig *pConfig = &targetBasedPolicyConfig; sfip_t local_ipAddr; unsigned service_count = 0; int rval; pConfig = &targetBasedPolicyConfig; sfip_set_ip(&local_ipAddr, ipAddr); if (local_ipAddr.family == AF_INET) local_ipAddr.ip32[0] = ntohl(local_ipAddr.ip32[0]); host_entry = sfrt_lookup(&local_ipAddr, pConfig->curr.lookupTable); if (!host_entry) { GetPolicyIdsCallbackList *list_entry; if (sfrt_num_entries(pConfig->curr.lookupTable) >= ScMaxAttrHosts()) return; host_entry = SnortAlloc(sizeof(*host_entry)); sfip_set_ip(&host_entry->ipAddr, &local_ipAddr); if ((rval = sfrt_insert(&local_ipAddr, (unsigned char)local_ipAddr.bits, host_entry, RT_FAVOR_SPECIFIC, pConfig->curr.lookupTable)) != RT_SUCCESS) { FreeHostEntry(host_entry); return; } for (list_entry = updatePolicyCallbackList; list_entry; list_entry = list_entry->next) { if (list_entry->policyCallback) list_entry->policyCallback(host_entry); } service = NULL; } else { for (service = host_entry->services; service; service = service->next) { if (service->ipproto == protocol && (uint16_t)service->port == port) { break; } service_count++; } } if (!service) { if ( service_count >= ScMaxAttrServicesPerHost() ) return; service = SnortAlloc(sizeof(*service)); service->port = port; service->ipproto = protocol; service->next = host_entry->services; host_entry->services = service; service->protocol = id; } else if (service->protocol != id) { service->protocol = id; } } #endif /* TARGET_BASED */ snort-2.9.6.0/src/target-based/sf_attribute_table.c0000644000000000000000000023216512260606566017103 00000000000000/* A Bison parser, made by GNU Bison 2.6.4. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.6.4" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse sfat_parse #define yylex sfat_lex #define yyerror sfat_error #define yylval sfat_lval #define yychar sfat_char #define yydebug sfat_debug #define yynerrs sfat_nerrs /* Copy the first part of user declarations. */ /* Line 358 of yacc.c */ #line 33 "sf_attribute_table.y" #ifdef TARGET_BASED #include #include #include "sftarget_reader.h" #include "snort_debug.h" #define YYSTACK_USE_ALLOCA 0 /* define the initial stack-sizes */ #ifdef YYMAXDEPTH #undef YYMAXDEPTH #define YYMAXDEPTH 70000 #else #define YYMAXDEPTH 70000 #endif extern ServiceClient sfat_client_or_service; extern char *sfat_grammar_error; extern int sfat_lex(); extern void sfat_error(char*); /* Line 358 of yacc.c */ #line 100 "sf_attribute_table.c" # ifndef YY_NULL # if defined __cplusplus && 201103L <= __cplusplus # define YY_NULL nullptr # else # define YY_NULL 0 # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* In a future release of Bison, this section will be replaced by #include "sf_attribute_table.h". */ #ifndef YY_SFAT_SF_ATTRIBUTE_TABLE_H_INCLUDED # define YY_SFAT_SF_ATTRIBUTE_TABLE_H_INCLUDED /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int sfat_debug; #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { SF_AT_COMMENT = 258, SF_AT_WHITESPACE = 259, SF_START_SNORT_ATTRIBUTES = 260, SF_END_SNORT_ATTRIBUTES = 261, SF_AT_START_MAP_TABLE = 262, SF_AT_END_MAP_TABLE = 263, SF_AT_START_ENTRY = 264, SF_AT_END_ENTRY = 265, SF_AT_START_ENTRY_ID = 266, SF_AT_END_ENTRY_ID = 267, SF_AT_START_ENTRY_VALUE = 268, SF_AT_END_ENTRY_VALUE = 269, SF_AT_START_ATTRIBUTE_TABLE = 270, SF_AT_END_ATTRIBUTE_TABLE = 271, SF_AT_START_HOST = 272, SF_AT_END_HOST = 273, SF_AT_START_HOST_IP = 274, SF_AT_END_HOST_IP = 275, SF_AT_STRING = 276, SF_AT_NUMERIC = 277, SF_AT_IPv6 = 278, SF_AT_IPv6Cidr = 279, SF_AT_START_OS = 280, SF_AT_END_OS = 281, SF_AT_START_ATTRIBUTE_VALUE = 282, SF_AT_END_ATTRIBUTE_VALUE = 283, SF_AT_START_ATTRIBUTE_ID = 284, SF_AT_END_ATTRIBUTE_ID = 285, SF_AT_START_CONFIDENCE = 286, SF_AT_END_CONFIDENCE = 287, SF_AT_START_NAME = 288, SF_AT_END_NAME = 289, SF_AT_START_VENDOR = 290, SF_AT_END_VENDOR = 291, SF_AT_START_VERSION = 292, SF_AT_END_VERSION = 293, SF_AT_START_FRAG_POLICY = 294, SF_AT_END_FRAG_POLICY = 295, SF_AT_START_STREAM_POLICY = 296, SF_AT_END_STREAM_POLICY = 297, SF_AT_START_SERVICES = 298, SF_AT_END_SERVICES = 299, SF_AT_START_SERVICE = 300, SF_AT_END_SERVICE = 301, SF_AT_START_CLIENTS = 302, SF_AT_END_CLIENTS = 303, SF_AT_START_CLIENT = 304, SF_AT_END_CLIENT = 305, SF_AT_START_IPPROTO = 306, SF_AT_END_IPPROTO = 307, SF_AT_START_PORT = 308, SF_AT_END_PORT = 309, SF_AT_START_PROTOCOL = 310, SF_AT_END_PROTOCOL = 311, SF_AT_START_APPLICATION = 312, SF_AT_END_APPLICATION = 313 }; #endif /* Tokens. */ #define SF_AT_COMMENT 258 #define SF_AT_WHITESPACE 259 #define SF_START_SNORT_ATTRIBUTES 260 #define SF_END_SNORT_ATTRIBUTES 261 #define SF_AT_START_MAP_TABLE 262 #define SF_AT_END_MAP_TABLE 263 #define SF_AT_START_ENTRY 264 #define SF_AT_END_ENTRY 265 #define SF_AT_START_ENTRY_ID 266 #define SF_AT_END_ENTRY_ID 267 #define SF_AT_START_ENTRY_VALUE 268 #define SF_AT_END_ENTRY_VALUE 269 #define SF_AT_START_ATTRIBUTE_TABLE 270 #define SF_AT_END_ATTRIBUTE_TABLE 271 #define SF_AT_START_HOST 272 #define SF_AT_END_HOST 273 #define SF_AT_START_HOST_IP 274 #define SF_AT_END_HOST_IP 275 #define SF_AT_STRING 276 #define SF_AT_NUMERIC 277 #define SF_AT_IPv6 278 #define SF_AT_IPv6Cidr 279 #define SF_AT_START_OS 280 #define SF_AT_END_OS 281 #define SF_AT_START_ATTRIBUTE_VALUE 282 #define SF_AT_END_ATTRIBUTE_VALUE 283 #define SF_AT_START_ATTRIBUTE_ID 284 #define SF_AT_END_ATTRIBUTE_ID 285 #define SF_AT_START_CONFIDENCE 286 #define SF_AT_END_CONFIDENCE 287 #define SF_AT_START_NAME 288 #define SF_AT_END_NAME 289 #define SF_AT_START_VENDOR 290 #define SF_AT_END_VENDOR 291 #define SF_AT_START_VERSION 292 #define SF_AT_END_VERSION 293 #define SF_AT_START_FRAG_POLICY 294 #define SF_AT_END_FRAG_POLICY 295 #define SF_AT_START_STREAM_POLICY 296 #define SF_AT_END_STREAM_POLICY 297 #define SF_AT_START_SERVICES 298 #define SF_AT_END_SERVICES 299 #define SF_AT_START_SERVICE 300 #define SF_AT_END_SERVICE 301 #define SF_AT_START_CLIENTS 302 #define SF_AT_END_CLIENTS 303 #define SF_AT_START_CLIENT 304 #define SF_AT_END_CLIENT 305 #define SF_AT_START_IPPROTO 306 #define SF_AT_END_IPPROTO 307 #define SF_AT_START_PORT 308 #define SF_AT_END_PORT 309 #define SF_AT_START_PROTOCOL 310 #define SF_AT_END_PROTOCOL 311 #define SF_AT_START_APPLICATION 312 #define SF_AT_END_APPLICATION 313 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { /* Line 374 of yacc.c */ #line 59 "sf_attribute_table.y" char stringValue[STD_BUF]; uint32_t numericValue; AttributeData data; MapData mapEntry; /* Line 374 of yacc.c */ #line 267 "sf_attribute_table.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE sfat_lval; #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int sfat_parse (void *YYPARSE_PARAM); #else int sfat_parse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int sfat_parse (void); #else int sfat_parse (); #endif #endif /* ! YYPARSE_PARAM */ #endif /* !YY_SFAT_SF_ATTRIBUTE_TABLE_H_INCLUDED */ /* Copy the second part of user declarations. */ /* Line 377 of yacc.c */ #line 295 "sf_attribute_table.c" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(N) (N) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (YYID (0)) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 8 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 133 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 59 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 54 /* YYNRULES -- Number of rules. */ #define YYNRULES 83 /* YYNRULES -- Number of states. */ #define YYNSTATES 152 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 313 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint8 yyprhs[] = { 0, 0, 3, 5, 10, 14, 18, 19, 22, 26, 28, 30, 33, 37, 41, 45, 46, 49, 53, 55, 57, 62, 66, 70, 73, 77, 81, 83, 86, 88, 90, 92, 94, 96, 100, 104, 108, 112, 116, 118, 121, 124, 126, 129, 131, 135, 138, 142, 146, 150, 154, 156, 158, 159, 162, 166, 168, 170, 172, 175, 179, 183, 187, 191, 195, 199, 203, 207, 211, 215, 220, 224, 228, 230, 232, 233, 236, 240, 242, 244, 246, 249, 251, 254 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { 60, 0, -1, 61, -1, 5, 62, 70, 6, -1, 5, 70, 6, -1, 7, 63, 8, -1, -1, 64, 63, -1, 65, 67, 66, -1, 9, -1, 10, -1, 69, 68, -1, 13, 21, 14, -1, 11, 22, 12, -1, 15, 71, 16, -1, -1, 71, 72, -1, 73, 75, 74, -1, 17, -1, 18, -1, 76, 77, 90, 104, -1, 76, 77, 104, -1, 76, 77, 90, -1, 76, 77, -1, 19, 21, 20, -1, 25, 78, 26, -1, 79, -1, 78, 79, -1, 80, -1, 81, -1, 82, -1, 84, -1, 83, -1, 33, 85, 34, -1, 35, 85, 36, -1, 37, 85, 38, -1, 39, 21, 40, -1, 41, 21, 42, -1, 86, -1, 86, 89, -1, 87, 89, -1, 87, -1, 88, 89, -1, 88, -1, 27, 21, 28, -1, 27, 28, -1, 27, 22, 28, -1, 29, 22, 30, -1, 31, 22, 32, -1, 91, 93, 92, -1, 43, -1, 44, -1, -1, 94, 93, -1, 95, 97, 96, -1, 45, -1, 46, -1, 98, -1, 98, 102, -1, 99, 100, 101, -1, 99, 101, 100, -1, 100, 99, 101, -1, 100, 101, 99, -1, 101, 100, 99, -1, 101, 99, 100, -1, 51, 85, 52, -1, 55, 85, 56, -1, 53, 85, 54, -1, 57, 85, 58, -1, 57, 85, 103, 58, -1, 37, 85, 38, -1, 105, 107, 106, -1, 47, -1, 48, -1, -1, 108, 107, -1, 109, 111, 110, -1, 49, -1, 50, -1, 112, -1, 112, 102, -1, 100, -1, 99, 100, -1, 100, 99, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 144, 144, 150, 155, 162, 168, 171, 174, 182, 185, 188, 195, 202, 210, 216, 219, 222, 232, 239, 242, 247, 252, 257, 264, 275, 277, 277, 279, 279, 279, 279, 279, 282, 290, 298, 306, 314, 322, 328, 334, 340, 346, 366, 388, 394, 398, 404, 411, 418, 424, 431, 437, 440, 446, 454, 461, 467, 471, 477, 482, 487, 492, 497, 502, 509, 517, 525, 533, 540, 549, 557, 563, 570, 576, 579, 585, 593, 600, 606, 610, 616, 621, 626 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "SF_AT_COMMENT", "SF_AT_WHITESPACE", "SF_START_SNORT_ATTRIBUTES", "SF_END_SNORT_ATTRIBUTES", "SF_AT_START_MAP_TABLE", "SF_AT_END_MAP_TABLE", "SF_AT_START_ENTRY", "SF_AT_END_ENTRY", "SF_AT_START_ENTRY_ID", "SF_AT_END_ENTRY_ID", "SF_AT_START_ENTRY_VALUE", "SF_AT_END_ENTRY_VALUE", "SF_AT_START_ATTRIBUTE_TABLE", "SF_AT_END_ATTRIBUTE_TABLE", "SF_AT_START_HOST", "SF_AT_END_HOST", "SF_AT_START_HOST_IP", "SF_AT_END_HOST_IP", "SF_AT_STRING", "SF_AT_NUMERIC", "SF_AT_IPv6", "SF_AT_IPv6Cidr", "SF_AT_START_OS", "SF_AT_END_OS", "SF_AT_START_ATTRIBUTE_VALUE", "SF_AT_END_ATTRIBUTE_VALUE", "SF_AT_START_ATTRIBUTE_ID", "SF_AT_END_ATTRIBUTE_ID", "SF_AT_START_CONFIDENCE", "SF_AT_END_CONFIDENCE", "SF_AT_START_NAME", "SF_AT_END_NAME", "SF_AT_START_VENDOR", "SF_AT_END_VENDOR", "SF_AT_START_VERSION", "SF_AT_END_VERSION", "SF_AT_START_FRAG_POLICY", "SF_AT_END_FRAG_POLICY", "SF_AT_START_STREAM_POLICY", "SF_AT_END_STREAM_POLICY", "SF_AT_START_SERVICES", "SF_AT_END_SERVICES", "SF_AT_START_SERVICE", "SF_AT_END_SERVICE", "SF_AT_START_CLIENTS", "SF_AT_END_CLIENTS", "SF_AT_START_CLIENT", "SF_AT_END_CLIENT", "SF_AT_START_IPPROTO", "SF_AT_END_IPPROTO", "SF_AT_START_PORT", "SF_AT_END_PORT", "SF_AT_START_PROTOCOL", "SF_AT_END_PROTOCOL", "SF_AT_START_APPLICATION", "SF_AT_END_APPLICATION", "$accept", "AttributeGrammar", "SnortAttributes", "MappingTable", "ListOfMapEntries", "MapEntry", "MapEntryStart", "MapEntryEnd", "MapEntryData", "MapValue", "MapId", "AttributeTable", "ListOfHosts", "HostEntry", "HostEntryStart", "HostEntryEnd", "HostEntryData", "IpCidr", "HostOS", "OSAttributes", "OSAttribute", "OSName", "OSVendor", "OSVersion", "OSFragPolicy", "OSStreamPolicy", "AttributeInfo", "AttributeValueString", "AttributeValueNumber", "AttributeId", "AttributeConfidence", "ServiceList", "ServiceListStart", "ServiceListEnd", "ServiceListData", "Service", "ServiceStart", "ServiceEnd", "ServiceData", "ServiceDataRequired", "IPProtocol", "Protocol", "Port", "Application", "Version", "ClientList", "ClientListStart", "ClientListEnd", "ClientListData", "Client", "ClientStart", "ClientEnd", "ClientData", "ClientDataRequired", YY_NULL }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 59, 60, 61, 61, 62, 63, 63, 64, 65, 66, 67, 68, 69, 70, 71, 71, 72, 73, 74, 75, 75, 75, 75, 76, 77, 78, 78, 79, 79, 79, 79, 79, 80, 81, 82, 83, 84, 85, 85, 85, 85, 85, 85, 86, 87, 87, 88, 89, 90, 91, 92, 93, 93, 94, 95, 96, 97, 97, 98, 98, 98, 98, 98, 98, 99, 100, 101, 102, 102, 103, 104, 105, 106, 107, 107, 108, 109, 110, 111, 111, 112, 112, 112 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 4, 3, 3, 0, 2, 3, 1, 1, 2, 3, 3, 3, 0, 2, 3, 1, 1, 4, 3, 3, 2, 3, 3, 1, 2, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1, 2, 2, 1, 2, 1, 3, 2, 3, 3, 3, 3, 1, 1, 0, 2, 3, 1, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 1, 1, 0, 2, 3, 1, 1, 1, 2, 1, 2, 2 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. Performed when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 0, 0, 0, 2, 6, 15, 0, 0, 1, 9, 0, 6, 0, 0, 0, 4, 5, 7, 0, 0, 0, 14, 18, 16, 0, 3, 0, 10, 8, 0, 11, 0, 0, 0, 13, 0, 0, 19, 17, 0, 23, 12, 24, 0, 0, 0, 0, 0, 0, 26, 28, 29, 30, 32, 31, 50, 72, 22, 52, 21, 74, 0, 0, 0, 38, 41, 43, 0, 0, 0, 0, 25, 27, 20, 55, 0, 52, 0, 77, 0, 74, 0, 0, 0, 45, 0, 33, 0, 39, 40, 42, 34, 35, 36, 37, 51, 49, 53, 0, 0, 0, 0, 57, 0, 0, 0, 73, 71, 75, 0, 81, 0, 79, 44, 46, 47, 0, 0, 0, 0, 56, 54, 0, 58, 0, 0, 0, 0, 0, 0, 82, 83, 78, 76, 80, 48, 65, 67, 66, 0, 59, 60, 61, 62, 64, 63, 0, 68, 0, 0, 69, 70 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 2, 3, 6, 10, 11, 12, 28, 19, 30, 20, 7, 13, 23, 24, 38, 32, 33, 40, 48, 49, 50, 51, 52, 53, 54, 63, 64, 65, 66, 88, 57, 58, 96, 75, 76, 77, 121, 101, 102, 103, 104, 105, 123, 148, 59, 60, 107, 79, 80, 81, 133, 111, 112 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -97 static const yytype_int8 yypact[] = { 1, 25, 9, -97, 28, -97, 30, 41, -97, -97, 43, 28, 51, 42, 57, -97, -97, -97, 44, 54, 52, -97, -97, -97, 48, -97, 56, -97, -97, 49, -97, 50, 55, 47, -97, 60, 59, -97, -97, -23, -4, -97, -97, -7, -7, -7, 61, 62, -22, -97, -97, -97, -97, -97, -97, -97, -97, 22, 31, -97, 26, 13, 58, 53, 46, 46, 46, 45, 63, 64, 65, -97, -97, -97, -97, 40, 31, -9, -97, 37, 26, 2, 66, 67, -97, 68, -97, 69, -97, -97, -97, -97, -97, -97, -97, -97, -97, -97, -7, -7, -7, 70, 29, -32, -15, 2, -97, -97, -97, 33, 38, 71, 29, -97, -97, -97, 73, 72, 36, 74, -97, -97, -7, -97, 39, 33, 39, 38, 33, 38, -97, -97, -97, -97, -97, -97, -97, -97, -97, -34, -97, -97, -97, -97, -97, -97, -7, -97, 35, 75, -97, -97 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -97, -97, -97, -97, 85, -97, -97, -97, -97, -97, -97, 91, -97, -97, -97, -97, -97, -97, -97, -97, 77, -97, -97, -97, -97, -97, -44, -97, -97, -97, -5, -97, -97, -97, 23, -97, -97, -97, -97, -97, -79, -76, -96, -12, -97, 76, -97, -97, 32, -97, -97, -97, -97, -97 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 static const yytype_uint8 yytable[] = { 67, 68, 109, 146, 71, 110, 1, 125, 127, 8, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 61, 99, 62, 100, 147, 126, 128, 124, 140, 129, 142, 131, 4, 130, 82, 83, 98, 9, 99, 55, 5, 84, 98, 56, 99, 5, 100, 15, 143, 141, 145, 16, 144, 98, 117, 118, 119, 100, 21, 22, 89, 90, 18, 25, 27, 29, 26, 31, 34, 56, 35, 36, 39, 37, 41, 78, 74, 87, 139, 42, 85, 91, 69, 70, 95, 106, 122, 86, 100, 98, 137, 116, 99, 150, 113, 114, 17, 14, 115, 97, 134, 92, 149, 0, 93, 135, 0, 94, 0, 0, 0, 0, 108, 151, 0, 0, 120, 0, 0, 0, 0, 132, 0, 0, 136, 72, 0, 0, 0, 0, 138, 0, 0, 73 }; #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-97))) #define yytable_value_is_error(Yytable_value) \ YYID (0) static const yytype_int16 yycheck[] = { 44, 45, 81, 37, 26, 81, 5, 103, 104, 0, 33, 33, 35, 35, 37, 37, 39, 39, 41, 41, 27, 53, 29, 55, 58, 104, 105, 103, 124, 105, 126, 110, 7, 109, 21, 22, 51, 9, 53, 43, 15, 28, 51, 47, 53, 15, 55, 6, 127, 125, 129, 8, 128, 51, 98, 99, 100, 55, 16, 17, 65, 66, 11, 6, 10, 13, 22, 19, 12, 47, 21, 21, 25, 18, 14, 49, 45, 31, 122, 20, 22, 36, 21, 21, 44, 48, 57, 34, 55, 51, 54, 22, 53, 58, 28, 28, 11, 6, 30, 76, 112, 38, 146, -1, 40, 32, -1, 42, -1, -1, -1, -1, 80, 38, -1, -1, 46, -1, -1, -1, -1, 50, -1, -1, 52, 48, -1, -1, -1, -1, 56, -1, -1, 57 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 5, 60, 61, 7, 15, 62, 70, 0, 9, 63, 64, 65, 71, 70, 6, 8, 63, 11, 67, 69, 16, 17, 72, 73, 6, 22, 10, 66, 13, 68, 19, 75, 76, 12, 21, 21, 18, 74, 25, 77, 14, 20, 33, 35, 37, 39, 41, 78, 79, 80, 81, 82, 83, 84, 43, 47, 90, 91, 104, 105, 27, 29, 85, 86, 87, 88, 85, 85, 21, 21, 26, 79, 104, 45, 93, 94, 95, 49, 107, 108, 109, 21, 22, 28, 22, 34, 31, 89, 89, 89, 36, 38, 40, 42, 44, 92, 93, 51, 53, 55, 97, 98, 99, 100, 101, 48, 106, 107, 99, 100, 111, 112, 28, 28, 30, 22, 85, 85, 85, 46, 96, 57, 102, 100, 101, 99, 101, 99, 100, 100, 99, 50, 110, 102, 32, 52, 54, 56, 85, 101, 100, 101, 99, 100, 99, 37, 58, 103, 85, 58, 38 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. However, YYFAIL appears to be in use. Nevertheless, it is formally deprecated in Bison 2.4.2's NEWS entry, where a plan to phase it out is discussed. */ #define YYFAIL goto yyerrlab #if defined YYFAIL /* This is here to suppress warnings from the GCC cpp's -Wunused-macros. Normally we don't worry about that warning, but some users do, and we want to make it easy for users to remove YYFAIL uses, which will produce warnings from Bison 2.5. */ #endif #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif #define YYRHSLOC(Rhs, K) ((Rhs)[K]) /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { FILE *yyo = yyoutput; YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULL; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - Assume YYFAIL is not used. It's too flawed to consider. See for details. YYERROR is fine as it does not invoke this function. - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* The lookahead symbol. */ int yychar; #ifndef YYLVAL_INITIALIZE # define YYLVAL_INITIALIZE() #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: `yyss': related to states. `yyvs': related to semantic values. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyss = yyssa; yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; YYLVAL_INITIALIZE (); goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* Line 1813 of yacc.c */ #line 145 "sf_attribute_table.y" { YYACCEPT; } break; case 3: /* Line 1813 of yacc.c */ #line 151 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "SnortAttributes: Got Attribute Map & Table\n");); } break; case 4: /* Line 1813 of yacc.c */ #line 156 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "SnortAttributes: Got Attribute Table\n");); } break; case 5: /* Line 1813 of yacc.c */ #line 163 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Got Attribute Map\n");); } break; case 6: /* Line 1813 of yacc.c */ #line 168 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Empty Mapping Table\n");); } break; case 8: /* Line 1813 of yacc.c */ #line 175 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "MapEntry: Name: %s, Id %d\n", (yyvsp[(2) - (3)].mapEntry).s_mapvalue, (yyvsp[(2) - (3)].mapEntry).l_mapid);); SFAT_AddMapEntry(&(yyvsp[(2) - (3)].mapEntry)); } break; case 11: /* Line 1813 of yacc.c */ #line 189 "sf_attribute_table.y" { (yyval.mapEntry).l_mapid = (yyvsp[(1) - (2)].numericValue); SnortStrncpy((yyval.mapEntry).s_mapvalue, (yyvsp[(2) - (2)].stringValue), STD_BUF); } break; case 12: /* Line 1813 of yacc.c */ #line 196 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "MapValue: %s\n", (yyvsp[(2) - (3)].stringValue));) SnortStrncpy((yyval.stringValue), (yyvsp[(2) - (3)].stringValue), STD_BUF); } break; case 13: /* Line 1813 of yacc.c */ #line 203 "sf_attribute_table.y" { (yyval.numericValue) = (yyvsp[(2) - (3)].numericValue); DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "MapId: %d\n", (yyvsp[(2) - (3)].numericValue));); } break; case 14: /* Line 1813 of yacc.c */ #line 211 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Got Attribute Table\n");); } break; case 15: /* Line 1813 of yacc.c */ #line 216 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "EmptyHostEntry\n");); } break; case 17: /* Line 1813 of yacc.c */ #line 223 "sf_attribute_table.y" { if (SFAT_AddHostEntryToMap() != SFAT_OK) { YYABORT; } DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Host Added\n");); } break; case 18: /* Line 1813 of yacc.c */ #line 233 "sf_attribute_table.y" { /* Callback to create a host entry object */ SFAT_CreateHostEntry(); } break; case 20: /* Line 1813 of yacc.c */ #line 243 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "HostEntryData\n");); } break; case 21: /* Line 1813 of yacc.c */ #line 248 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "HostEntryData: No Services\n");); } break; case 22: /* Line 1813 of yacc.c */ #line 253 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "HostEntryData: No Clients\n");); } break; case 23: /* Line 1813 of yacc.c */ #line 258 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "HostEntryData: No Services or Clients\n");); } break; case 24: /* Line 1813 of yacc.c */ #line 265 "sf_attribute_table.y" { /* Convert IP/CIDR to Snort IPCidr Object */ /* determine the number of bits (done in SetHostIp4) */ if (SFAT_SetHostIp((yyvsp[(2) - (3)].stringValue)) != SFAT_OK) { YYABORT; } } break; case 33: /* Line 1813 of yacc.c */ #line 283 "sf_attribute_table.y" { /* Copy OSName */ DEBUG_WRAP(PrintAttributeData("OS:Name", &(yyvsp[(2) - (3)].data));); SFAT_SetOSAttribute(&(yyvsp[(2) - (3)].data), HOST_INFO_OS); } break; case 34: /* Line 1813 of yacc.c */ #line 291 "sf_attribute_table.y" { /* Copy OSVendor */ DEBUG_WRAP(PrintAttributeData("OS:Vendor", &(yyvsp[(2) - (3)].data));); SFAT_SetOSAttribute(&(yyvsp[(2) - (3)].data), HOST_INFO_VENDOR); } break; case 35: /* Line 1813 of yacc.c */ #line 299 "sf_attribute_table.y" { /* Copy OSVersion */ DEBUG_WRAP(PrintAttributeData("OS:Version", &(yyvsp[(2) - (3)].data));); SFAT_SetOSAttribute(&(yyvsp[(2) - (3)].data), HOST_INFO_VERSION); } break; case 36: /* Line 1813 of yacc.c */ #line 307 "sf_attribute_table.y" { /* Copy OSFragPolicy */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "OS:FragPolicy: %s\n", (yyvsp[(2) - (3)].stringValue));); SFAT_SetOSPolicy((yyvsp[(2) - (3)].stringValue), HOST_INFO_FRAG_POLICY); } break; case 37: /* Line 1813 of yacc.c */ #line 315 "sf_attribute_table.y" { /* Copy OSStreamPolicy */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "OS:StreamPolicy: %s\n", (yyvsp[(2) - (3)].stringValue));); SFAT_SetOSPolicy((yyvsp[(2) - (3)].stringValue), HOST_INFO_STREAM_POLICY); } break; case 38: /* Line 1813 of yacc.c */ #line 323 "sf_attribute_table.y" { (yyval.data).type = ATTRIBUTE_NAME; (yyval.data).confidence = 100; SnortStrncpy((yyval.data).value.s_value, (yyvsp[(1) - (1)].stringValue), STD_BUF); } break; case 39: /* Line 1813 of yacc.c */ #line 329 "sf_attribute_table.y" { (yyval.data).type = ATTRIBUTE_NAME; (yyval.data).confidence = (yyvsp[(2) - (2)].numericValue); SnortStrncpy((yyval.data).value.s_value, (yyvsp[(1) - (2)].stringValue), STD_BUF); } break; case 40: /* Line 1813 of yacc.c */ #line 335 "sf_attribute_table.y" { (yyval.data).type = ATTRIBUTE_NAME; (yyval.data).confidence = (yyvsp[(2) - (2)].numericValue); SnortSnprintf((yyval.data).value.s_value, STD_BUF, "%d", (yyvsp[(1) - (2)].numericValue)); } break; case 41: /* Line 1813 of yacc.c */ #line 341 "sf_attribute_table.y" { (yyval.data).type = ATTRIBUTE_NAME; (yyval.data).confidence = 100; SnortSnprintf((yyval.data).value.s_value, STD_BUF, "%d", (yyvsp[(1) - (1)].numericValue)); } break; case 42: /* Line 1813 of yacc.c */ #line 347 "sf_attribute_table.y" { char *mapped_name; (yyval.data).confidence = (yyvsp[(2) - (2)].numericValue); mapped_name = SFAT_LookupAttributeNameById((yyvsp[(1) - (2)].numericValue)); if (!mapped_name) { (yyval.data).type = ATTRIBUTE_ID; (yyval.data).value.l_value = (yyvsp[(1) - (2)].numericValue); //FatalError("Unknown/Invalid Attribute ID %d\n", $1); sfat_grammar_error = "Unknown/Invalid Attribute ID"; YYABORT; } else { /* Copy String */ (yyval.data).type = ATTRIBUTE_NAME; SnortStrncpy((yyval.data).value.s_value, mapped_name, STD_BUF); } } break; case 43: /* Line 1813 of yacc.c */ #line 367 "sf_attribute_table.y" { char *mapped_name; (yyval.data).confidence = 100; mapped_name = SFAT_LookupAttributeNameById((yyvsp[(1) - (1)].numericValue)); if (!mapped_name) { (yyval.data).type = ATTRIBUTE_ID; (yyval.data).value.l_value = (yyvsp[(1) - (1)].numericValue); //FatalError("Unknown/Invalid Attribute ID %d\n", $1); sfat_grammar_error = "Unknown/Invalid Attribute ID"; YYABORT; } else { /* Copy String */ (yyval.data).type = ATTRIBUTE_NAME; SnortStrncpy((yyval.data).value.s_value, mapped_name, STD_BUF); } } break; case 44: /* Line 1813 of yacc.c */ #line 389 "sf_attribute_table.y" { SnortStrncpy((yyval.stringValue), (yyvsp[(2) - (3)].stringValue), STD_BUF); } break; case 45: /* Line 1813 of yacc.c */ #line 395 "sf_attribute_table.y" { (yyval.numericValue) = 0; } break; case 46: /* Line 1813 of yacc.c */ #line 399 "sf_attribute_table.y" { (yyval.numericValue) = (yyvsp[(2) - (3)].numericValue); } break; case 47: /* Line 1813 of yacc.c */ #line 405 "sf_attribute_table.y" { /* Copy numeric */ (yyval.numericValue) = (yyvsp[(2) - (3)].numericValue); } break; case 48: /* Line 1813 of yacc.c */ #line 412 "sf_attribute_table.y" { /* Copy numeric */ (yyval.numericValue) = (yyvsp[(2) - (3)].numericValue); } break; case 49: /* Line 1813 of yacc.c */ #line 419 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "ServiceList (complete)\n");); } break; case 50: /* Line 1813 of yacc.c */ #line 425 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Start ServiceList\n");); sfat_client_or_service = ATTRIBUTE_SERVICE; } break; case 51: /* Line 1813 of yacc.c */ #line 432 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "End ServiceList\n");); } break; case 52: /* Line 1813 of yacc.c */ #line 437 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "EmptyService\n");); } break; case 53: /* Line 1813 of yacc.c */ #line 441 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service ServiceListData\n");); } break; case 54: /* Line 1813 of yacc.c */ #line 447 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Adding Complete\n");); SFAT_AddApplicationData(); DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Added\n");); } break; case 55: /* Line 1813 of yacc.c */ #line 455 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Start\n");); SFAT_CreateApplicationEntry(); } break; case 56: /* Line 1813 of yacc.c */ #line 462 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service End\n");); } break; case 57: /* Line 1813 of yacc.c */ #line 468 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data (no application)\n");); } break; case 58: /* Line 1813 of yacc.c */ #line 472 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data (application)\n");); } break; case 59: /* Line 1813 of yacc.c */ #line 478 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (IPProto Proto Port)\n");); } break; case 60: /* Line 1813 of yacc.c */ #line 483 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (IPProto Port Proto)\n");); } break; case 61: /* Line 1813 of yacc.c */ #line 488 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (Proto IPProto Port)\n");); } break; case 62: /* Line 1813 of yacc.c */ #line 493 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (Proto Port IPProto)\n");); } break; case 63: /* Line 1813 of yacc.c */ #line 498 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (Port Proto IPProto)\n");); } break; case 64: /* Line 1813 of yacc.c */ #line 503 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Service Data Required (Port IPProto Proto)\n");); } break; case 65: /* Line 1813 of yacc.c */ #line 510 "sf_attribute_table.y" { /* Store IPProto Info */ DEBUG_WRAP(PrintAttributeData("IPProto", &(yyvsp[(2) - (3)].data));); SFAT_SetApplicationAttribute(&(yyvsp[(2) - (3)].data), APPLICATION_ENTRY_IPPROTO); } break; case 66: /* Line 1813 of yacc.c */ #line 518 "sf_attribute_table.y" { /* Store Protocol Info */ DEBUG_WRAP(PrintAttributeData("Protocol", &(yyvsp[(2) - (3)].data));); SFAT_SetApplicationAttribute(&(yyvsp[(2) - (3)].data), APPLICATION_ENTRY_PROTO); } break; case 67: /* Line 1813 of yacc.c */ #line 526 "sf_attribute_table.y" { /* Store Port Info */ DEBUG_WRAP(PrintAttributeData("Port", &(yyvsp[(2) - (3)].data));); SFAT_SetApplicationAttribute(&(yyvsp[(2) - (3)].data), APPLICATION_ENTRY_PORT); } break; case 68: /* Line 1813 of yacc.c */ #line 534 "sf_attribute_table.y" { /* Store Application Info */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Application\n")); DEBUG_WRAP(PrintAttributeData("Application", &(yyvsp[(2) - (3)].data));); SFAT_SetApplicationAttribute(&(yyvsp[(2) - (3)].data), APPLICATION_ENTRY_APPLICATION); } break; case 69: /* Line 1813 of yacc.c */ #line 541 "sf_attribute_table.y" { /* Store Application Info */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Application with Version\n")); DEBUG_WRAP(PrintAttributeData("Application", &(yyvsp[(2) - (4)].data));); SFAT_SetApplicationAttribute(&(yyvsp[(2) - (4)].data), APPLICATION_ENTRY_APPLICATION); } break; case 70: /* Line 1813 of yacc.c */ #line 550 "sf_attribute_table.y" { /* Store Version Info */ DEBUG_WRAP(PrintAttributeData("Version", &(yyvsp[(2) - (3)].data));); SFAT_SetApplicationAttribute(&(yyvsp[(2) - (3)].data), APPLICATION_ENTRY_VERSION); } break; case 71: /* Line 1813 of yacc.c */ #line 558 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "ClientList (complete)\n");); } break; case 72: /* Line 1813 of yacc.c */ #line 564 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Start ClientList\n");); sfat_client_or_service = ATTRIBUTE_CLIENT; } break; case 73: /* Line 1813 of yacc.c */ #line 571 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "End ClientList\n");); } break; case 74: /* Line 1813 of yacc.c */ #line 576 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "EmptyClient\n");); } break; case 75: /* Line 1813 of yacc.c */ #line 580 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client ClientListData\n");); } break; case 76: /* Line 1813 of yacc.c */ #line 586 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Adding Complete\n");); SFAT_AddApplicationData(); DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Added\n");); } break; case 77: /* Line 1813 of yacc.c */ #line 594 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Start\n");); SFAT_CreateApplicationEntry(); } break; case 78: /* Line 1813 of yacc.c */ #line 601 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client End\n");); } break; case 79: /* Line 1813 of yacc.c */ #line 607 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data (no application)\n");); } break; case 80: /* Line 1813 of yacc.c */ #line 611 "sf_attribute_table.y" { DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data (application)\n");); } break; case 81: /* Line 1813 of yacc.c */ #line 617 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data Required (Proto)\n");); } break; case 82: /* Line 1813 of yacc.c */ #line 622 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data Required (IPProto Proto)\n");); } break; case 83: /* Line 1813 of yacc.c */ #line 627 "sf_attribute_table.y" { /* Order independent */ DEBUG_WRAP(DebugMessage(DEBUG_ATTRIBUTE, "Client Data Required (Proto IPProto)\n");); } break; /* Line 1813 of yacc.c */ #line 2336 "sf_attribute_table.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } /* Line 2076 of yacc.c */ #line 632 "sf_attribute_table.y" /* int yywrap(void) { return 1; } */ #endif /* TARGET_BASED */ snort-2.9.6.0/src/target-based/sf_attribute_table_parser.c0000644000000000000000000140205012260606566020450 00000000000000#line 2 "sf_attribute_table_parser.c" #line 4 "sf_attribute_table_parser.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define yy_create_buffer sfat_create_buffer #define yy_delete_buffer sfat_delete_buffer #define yy_flex_debug sfat_flex_debug #define yy_init_buffer sfat_init_buffer #define yy_flush_buffer sfat_flush_buffer #define yy_load_buffer_state sfat_load_buffer_state #define yy_switch_to_buffer sfat_switch_to_buffer #define yyin sfatin #define yyleng sfatleng #define yylex sfatlex #define yylineno sfatlineno #define yyout sfatout #define yyrestart sfatrestart #define yytext sfattext #define yywrap sfatwrap #define yyalloc sfatalloc #define yyrealloc sfatrealloc #define yyfree sfatfree #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 37 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ /* C99 requires __STDC__ to be defined as 1. */ #if defined (__STDC__) #define YY_USE_CONST #endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE sfatrestart(sfatin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern yy_size_t sfatleng; extern FILE *sfatin, *sfatout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up sfattext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up sfattext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via sfatrestart()), so that the user can continue scanning by * just pointing sfatin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when sfattext is formed. */ static char yy_hold_char; static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ yy_size_t sfatleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow sfatwrap()'s to do buffer switches * instead of setting up a fresh sfatin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void sfatrestart (FILE *input_file ); void sfat_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE sfat_create_buffer (FILE *file,int size ); void sfat_delete_buffer (YY_BUFFER_STATE b ); void sfat_flush_buffer (YY_BUFFER_STATE b ); void sfatpush_buffer_state (YY_BUFFER_STATE new_buffer ); void sfatpop_buffer_state (void ); static void sfatensure_buffer_stack (void ); static void sfat_load_buffer_state (void ); static void sfat_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER sfat_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE sfat_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE sfat_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE sfat_scan_bytes (yyconst char *bytes,yy_size_t len ); void *sfatalloc (yy_size_t ); void *sfatrealloc (void *,yy_size_t ); void sfatfree (void * ); #define yy_new_buffer sfat_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ sfatensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ sfat_create_buffer(sfatin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ sfatensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ sfat_create_buffer(sfatin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define sfatwrap() 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *sfatin = (FILE *) 0, *sfatout = (FILE *) 0; typedef int yy_state_type; extern int sfatlineno; int sfatlineno = 1; extern char *sfattext; #define yytext_ptr sfattext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up sfattext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ sfatleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 57 #define YY_END_OF_BUFFER 58 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[8615] = { 0, 1, 1, 0, 0, 0, 0, 58, 56, 1, 54, 56, 53, 53, 52, 56, 57, 1, 53, 54, 52, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 53, 52, 52, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 53, 52, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 53, 52, 52, 0, 0, 0, 0, 0, 0, 0, 9, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 53, 52, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 26, 0, 48, 0, 0, 0, 0, 0, 0, 0, 1, 53, 52, 52, 0, 0, 0, 0, 0, 0, 15, 0, 27, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 1, 53, 52, 52, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 1, 53, 52, 52, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 40, 0, 0, 44, 0, 0, 38, 0, 0, 0, 30, 1, 53, 52, 52, 0, 0, 41, 0, 0, 45, 0, 0, 39, 0, 0, 0, 31, 0, 0, 0, 0, 0, 46, 36, 0, 0, 1, 53, 52, 52, 0, 0, 0, 0, 0, 47, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 53, 52, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 1, 53, 52, 52, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 50, 0, 0, 0, 0, 32, 0, 0, 0, 1, 53, 52, 52, 51, 0, 0, 0, 0, 33, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 1, 53, 52, 52, 23, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 34, 1, 53, 52, 52, 5, 0, 0, 0, 0, 35, 0, 0, 0, 0, 1, 53, 52, 0, 0, 0, 0, 12, 20, 0, 0, 1, 53, 13, 21, 0, 0, 18, 2, 1, 53, 19, 3, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 7, 6, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 6, 10, 6, 11, 6, 6, 12, 13, 14, 15, 16, 17, 18, 19, 20, 6, 6, 21, 22, 23, 24, 25, 6, 26, 27, 28, 29, 30, 6, 6, 31, 6, 6, 6, 6, 6, 32, 6, 33, 34, 35, 36, 37, 38, 39, 40, 41, 6, 6, 42, 43, 44, 45, 46, 6, 47, 48, 49, 50, 51, 6, 6, 52, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[53] = { 0, 1, 2, 3, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 } ; static yyconst flex_int16_t yy_base[12713] = { 0, 0, 11, 0, 0, 0, 0, 8934, 8935, 8931, 8935, 8929, 0, 8922, 8921, 18, 8935, 8927, 0, 8935, 8919, 8918, 8915, 58, 0, 12, 6, 5, 15, 61, 7, 19, 47, 85, 98, 8923, 0, 8915, 8914, 8911, 8910, 87, 95, 24, 53, 60, 96, 105, 93, 99, 125, 112, 101, 102, 123, 127, 124, 142, 128, 8909, 145, 135, 142, 133, 136, 135, 139, 139, 145, 162, 8917, 0, 8909, 8908, 143, 144, 157, 160, 162, 180, 167, 8905, 185, 173, 181, 173, 176, 175, 178, 177, 184, 191, 186, 182, 196, 202, 199, 209, 202, 8935, 8935, 206, 218, 210, 209, 211, 211, 216, 227, 215, 230, 220, 8913, 0, 8905, 8904, 228, 224, 236, 237, 230, 241, 233, 8935, 8935, 241, 253, 246, 246, 248, 248, 253, 265, 254, 269, 258, 266, 267, 266, 271, 261, 8880, 8900, 270, 8899, 284, 8898, 274, 281, 275, 297, 295, 290, 296, 8906, 0, 8898, 8897, 298, 300, 298, 303, 294, 8873, 8893, 302, 8892, 315, 8891, 304, 309, 303, 321, 318, 312, 318, 326, 330, 317, 336, 8890, 328, 8935, 328, 8935, 330, 8935, 346, 348, 8868, 341, 8888, 339, 343, 8896, 0, 8888, 8887, 354, 356, 342, 356, 8884, 348, 8935, 347, 8935, 348, 8935, 364, 366, 8862, 360, 8882, 359, 363, 381, 366, 391, 382, 8935, 376, 380, 385, 383, 393, 398, 8860, 8935, 8880, 388, 8888, 0, 8880, 8879, 400, 384, 409, 401, 8935, 398, 399, 404, 403, 413, 423, 8855, 8935, 8875, 414, 412, 413, 8935, 8874, 419, 425, 8873, 424, 428, 442, 423, 427, 8935, 8872, 8880, 0, 8872, 8871, 426, 427, 8935, 8868, 436, 439, 8867, 441, 444, 455, 443, 449, 8935, 8866, 457, 462, 8935, 465, 463, 8935, 466, 8865, 8935, 8864, 459, 464, 8935, 8872, 0, 8864, 8863, 469, 475, 8935, 479, 474, 8935, 478, 8860, 8935, 8859, 469, 477, 8935, 478, 8837, 490, 493, 8836, 8935, 8935, 485, 492, 8865, 0, 8857, 8856, 492, 8832, 503, 506, 8831, 8935, 8935, 495, 503, 502, 527, 8851, 498, 503, 511, 513, 8859, 0, 8851, 8850, 512, 559, 8847, 507, 512, 523, 524, 8846, 533, 541, 549, 550, 8935, 8845, 532, 554, 557, 8853, 0, 8845, 8844, 8841, 557, 561, 563, 565, 8935, 8840, 549, 572, 572, 8935, 8839, 565, 578, 574, 8935, 570, 570, 572, 8847, 0, 8839, 8838, 8935, 8835, 579, 592, 588, 8935, 586, 585, 584, 8935, 8834, 596, 590, 593, 594, 8833, 8841, 0, 8833, 8832, 8935, 8829, 602, 598, 600, 601, 8828, 8935, 615, 616, 617, 621, 8935, 8836, 0, 8828, 0, 8935, 623, 625, 629, 630, 8935, 8825, 8824, 625, 624, 8832, 0, 0, 8822, 8821, 633, 629, 8935, 8935, 8820, 8819, 8827, 0, 8935, 8935, 8817, 8816, 8935, 8935, 8824, 0, 8935, 8935, 8823, 0, 8822, 0, 8821, 0, 8820, 0, 8819, 0, 8818, 0, 8817, 0, 8816, 0, 8815, 0, 8814, 0, 8813, 0, 8812, 0, 8811, 0, 8810, 0, 8809, 0, 8808, 0, 8807, 0, 8806, 0, 8805, 0, 8804, 0, 8803, 0, 8802, 0, 8801, 0, 8800, 0, 8799, 0, 8798, 0, 8797, 0, 8796, 0, 8795, 0, 8794, 0, 8793, 0, 8792, 0, 8791, 0, 8790, 0, 8789, 0, 8788, 0, 8787, 0, 8786, 0, 8785, 0, 8784, 0, 8783, 0, 8782, 0, 8781, 0, 8780, 0, 8779, 0, 8778, 0, 8777, 0, 8776, 0, 8775, 0, 8774, 0, 8773, 0, 8772, 0, 8771, 0, 8770, 0, 8769, 0, 8768, 0, 8767, 0, 8766, 0, 8765, 0, 8764, 0, 8763, 0, 8762, 0, 8761, 0, 8760, 0, 8759, 0, 8758, 0, 8757, 0, 8756, 0, 8755, 0, 8754, 0, 8753, 0, 8752, 0, 8751, 0, 8750, 0, 8749, 0, 8748, 0, 8747, 0, 8746, 0, 8745, 0, 8744, 0, 8743, 0, 8742, 0, 8741, 0, 8740, 0, 8739, 0, 8738, 0, 8737, 0, 8736, 0, 8735, 0, 8734, 0, 8733, 0, 8732, 0, 8731, 0, 8730, 0, 8729, 0, 8728, 0, 8727, 0, 8726, 0, 8725, 0, 8724, 0, 8723, 0, 8722, 0, 8721, 0, 8720, 0, 8719, 0, 8718, 0, 8717, 0, 8716, 0, 8715, 0, 8714, 0, 8713, 0, 8712, 0, 8711, 0, 8710, 0, 8709, 0, 8708, 0, 8707, 0, 8706, 0, 8705, 0, 8704, 0, 8703, 0, 8702, 0, 8701, 0, 8700, 0, 8699, 0, 8698, 0, 8697, 0, 8696, 0, 8695, 0, 8694, 0, 8693, 0, 8692, 0, 8691, 0, 8690, 0, 8689, 0, 8688, 0, 8687, 0, 8686, 0, 8685, 0, 8684, 0, 8683, 0, 8682, 0, 8681, 0, 8680, 0, 8679, 0, 8678, 0, 8677, 0, 8676, 0, 8675, 0, 8674, 0, 8673, 0, 8672, 0, 8671, 0, 8670, 0, 8669, 0, 8668, 0, 8667, 0, 8666, 0, 8665, 0, 8664, 0, 8663, 0, 8662, 0, 8661, 0, 8660, 0, 8659, 0, 8658, 0, 8657, 0, 8656, 0, 8655, 0, 8654, 0, 8653, 0, 8652, 0, 8651, 0, 8650, 0, 8649, 0, 8648, 0, 8647, 0, 8646, 0, 8645, 0, 8644, 0, 8643, 0, 8642, 0, 8641, 0, 8640, 0, 8639, 0, 8638, 0, 8637, 0, 8636, 0, 8635, 0, 8634, 0, 8633, 0, 8632, 0, 8631, 0, 8630, 0, 8629, 0, 8628, 0, 8627, 0, 8626, 0, 8625, 0, 8624, 0, 8623, 0, 8622, 0, 8621, 0, 8620, 0, 8619, 0, 8618, 0, 8617, 0, 8616, 0, 8615, 0, 8614, 0, 8613, 0, 8612, 0, 8611, 0, 8610, 0, 8609, 0, 8608, 0, 8607, 0, 8606, 0, 8605, 0, 8604, 0, 8603, 0, 8602, 0, 8601, 0, 8600, 0, 8599, 0, 8598, 0, 8597, 0, 8596, 0, 8595, 0, 8594, 0, 8593, 0, 8592, 0, 8591, 0, 8590, 0, 8589, 0, 8588, 0, 8587, 0, 8586, 0, 8585, 0, 8584, 0, 8583, 0, 8582, 0, 8581, 0, 8580, 0, 8579, 0, 8578, 0, 8577, 0, 8576, 0, 8575, 0, 8574, 0, 8573, 0, 8572, 0, 8571, 0, 8570, 0, 8569, 0, 8568, 0, 8567, 0, 8566, 0, 8565, 0, 8564, 0, 8563, 0, 8562, 0, 8561, 0, 8560, 0, 8559, 0, 8558, 0, 8557, 0, 8556, 0, 8555, 0, 8554, 0, 8553, 0, 8552, 0, 8551, 0, 8550, 0, 8549, 0, 8548, 0, 8547, 0, 8546, 0, 8545, 0, 8544, 0, 8543, 0, 8542, 0, 8541, 0, 8540, 0, 8539, 0, 8538, 0, 8537, 0, 8536, 0, 8535, 0, 8534, 0, 8533, 0, 8532, 0, 8531, 0, 8530, 0, 8529, 0, 8528, 0, 8527, 0, 8526, 0, 8525, 0, 8524, 0, 8523, 0, 8522, 0, 8521, 0, 8520, 0, 8519, 0, 8518, 0, 8517, 0, 8516, 0, 8515, 0, 8514, 0, 8513, 0, 8512, 0, 8511, 0, 8510, 0, 8509, 0, 8508, 0, 8507, 0, 8506, 0, 8505, 0, 8504, 0, 8503, 0, 8502, 0, 8501, 0, 8500, 0, 8499, 0, 8498, 0, 8497, 0, 8496, 0, 8495, 0, 8494, 0, 8493, 0, 8492, 0, 8491, 0, 8490, 0, 8489, 0, 8488, 0, 8487, 0, 8486, 0, 8485, 0, 8484, 0, 8483, 0, 8482, 0, 8481, 0, 8480, 0, 8479, 0, 8478, 0, 8477, 0, 8476, 0, 8475, 0, 8474, 0, 8473, 0, 8472, 0, 8471, 0, 8470, 0, 8469, 0, 8468, 0, 8467, 0, 8466, 0, 8465, 0, 8464, 0, 8463, 0, 8462, 0, 8461, 0, 8460, 0, 8459, 0, 8458, 0, 8457, 0, 8456, 0, 8455, 0, 8454, 0, 8453, 0, 8452, 0, 8451, 0, 8450, 0, 8449, 0, 8448, 0, 8447, 0, 8446, 0, 8445, 0, 8444, 0, 8443, 0, 8442, 0, 8441, 0, 8440, 0, 8439, 0, 8438, 0, 8437, 0, 8436, 0, 8435, 0, 8434, 0, 3, 0, 4, 0, 6, 0, 14, 0, 15, 0, 22, 0, 25, 0, 59, 0, 65, 0, 78, 0, 85, 0, 87, 0, 88, 0, 118, 0, 125, 0, 165, 0, 413, 0, 524, 0, 534, 0, 556, 0, 564, 0, 655, 0, 657, 0, 659, 0, 661, 0, 662, 0, 663, 0, 667, 0, 668, 0, 669, 0, 671, 0, 672, 0, 673, 0, 676, 0, 677, 0, 678, 0, 679, 0, 680, 0, 681, 0, 682, 0, 683, 0, 684, 0, 685, 0, 686, 0, 687, 0, 688, 0, 689, 0, 690, 0, 691, 0, 692, 0, 693, 0, 694, 0, 695, 0, 696, 0, 697, 0, 698, 0, 699, 0, 700, 0, 701, 0, 702, 0, 703, 0, 704, 0, 705, 0, 706, 0, 707, 0, 708, 0, 709, 0, 710, 0, 711, 0, 712, 0, 713, 0, 714, 0, 715, 0, 716, 0, 717, 0, 718, 0, 719, 0, 720, 0, 721, 0, 722, 0, 723, 0, 724, 0, 725, 0, 726, 0, 727, 0, 728, 0, 729, 0, 730, 0, 731, 0, 732, 0, 733, 0, 734, 0, 735, 0, 736, 0, 737, 0, 738, 0, 739, 0, 740, 0, 741, 0, 742, 0, 743, 0, 744, 0, 745, 0, 746, 0, 747, 0, 748, 0, 749, 0, 750, 0, 751, 0, 752, 0, 753, 0, 754, 0, 755, 0, 756, 0, 757, 0, 758, 0, 759, 0, 760, 0, 761, 0, 762, 0, 763, 0, 764, 0, 765, 0, 766, 0, 767, 0, 768, 0, 769, 0, 770, 0, 771, 0, 772, 0, 773, 0, 774, 0, 775, 0, 776, 0, 777, 0, 778, 0, 779, 0, 780, 0, 781, 0, 782, 0, 783, 0, 784, 0, 785, 0, 786, 0, 787, 0, 788, 0, 789, 0, 790, 0, 791, 0, 792, 0, 793, 0, 794, 0, 795, 0, 796, 0, 797, 0, 798, 0, 799, 0, 800, 0, 801, 0, 802, 0, 803, 0, 804, 0, 805, 0, 806, 0, 807, 0, 808, 0, 809, 0, 810, 0, 811, 0, 812, 0, 813, 0, 814, 0, 815, 0, 816, 0, 817, 0, 818, 0, 819, 0, 820, 0, 821, 0, 822, 0, 823, 0, 824, 0, 825, 0, 826, 0, 827, 0, 828, 0, 829, 0, 830, 0, 831, 0, 832, 0, 833, 0, 834, 0, 835, 0, 836, 0, 837, 0, 838, 0, 839, 0, 840, 0, 841, 0, 842, 0, 843, 0, 844, 0, 845, 0, 846, 0, 847, 0, 848, 0, 849, 0, 850, 0, 851, 0, 852, 0, 853, 0, 854, 0, 855, 0, 856, 0, 857, 0, 858, 0, 859, 0, 860, 0, 861, 0, 862, 0, 863, 0, 864, 0, 865, 0, 866, 0, 867, 0, 868, 0, 869, 0, 870, 0, 871, 0, 872, 0, 873, 0, 874, 0, 875, 0, 876, 0, 877, 0, 878, 0, 879, 0, 880, 0, 881, 0, 882, 0, 883, 0, 884, 0, 885, 0, 886, 0, 887, 0, 888, 0, 889, 0, 890, 0, 891, 0, 892, 0, 893, 0, 894, 0, 895, 0, 896, 0, 897, 0, 898, 0, 899, 0, 900, 0, 901, 0, 902, 0, 903, 0, 904, 0, 905, 0, 906, 0, 907, 0, 908, 0, 909, 0, 910, 0, 911, 0, 912, 0, 913, 0, 914, 0, 915, 0, 916, 0, 917, 0, 918, 0, 919, 0, 920, 0, 921, 0, 922, 0, 923, 0, 924, 0, 925, 0, 926, 0, 927, 0, 928, 0, 929, 0, 930, 0, 931, 0, 932, 0, 933, 0, 934, 0, 935, 0, 936, 0, 937, 0, 938, 0, 939, 0, 940, 0, 941, 0, 942, 0, 943, 0, 944, 0, 945, 0, 946, 0, 947, 0, 948, 0, 949, 0, 950, 0, 951, 0, 952, 0, 953, 0, 954, 0, 955, 0, 956, 0, 957, 0, 958, 0, 959, 0, 960, 0, 961, 0, 962, 0, 963, 0, 964, 0, 965, 0, 966, 0, 967, 0, 968, 0, 969, 0, 970, 0, 971, 0, 972, 0, 973, 0, 974, 0, 975, 0, 976, 0, 977, 0, 978, 0, 979, 0, 980, 0, 981, 0, 982, 0, 983, 0, 984, 0, 985, 0, 986, 0, 987, 0, 988, 0, 989, 0, 990, 0, 991, 0, 992, 0, 993, 0, 994, 0, 995, 0, 996, 0, 997, 0, 998, 0, 999, 0, 1000, 0, 1001, 0, 1002, 0, 1003, 0, 1004, 0, 1005, 0, 1006, 0, 1007, 0, 1008, 0, 1009, 0, 1010, 0, 1011, 0, 1012, 0, 1013, 0, 1014, 0, 1015, 0, 1016, 0, 1017, 0, 1018, 0, 1019, 0, 1020, 0, 1021, 0, 1022, 0, 1023, 0, 1024, 0, 1025, 0, 1026, 0, 1027, 0, 1028, 0, 1029, 0, 1030, 0, 1031, 0, 1032, 0, 1033, 0, 1034, 0, 1035, 0, 1036, 0, 1037, 0, 1038, 0, 1039, 0, 1040, 0, 1041, 0, 1042, 0, 1043, 0, 1044, 0, 1045, 0, 1046, 0, 1047, 0, 1048, 0, 1049, 0, 1050, 0, 1051, 0, 1052, 0, 1053, 0, 1054, 0, 1055, 0, 1056, 0, 1057, 0, 1058, 0, 1059, 0, 1060, 0, 1061, 0, 1062, 0, 1063, 0, 1064, 0, 1065, 0, 1066, 0, 1067, 0, 1068, 0, 1069, 0, 1070, 0, 1071, 0, 1072, 0, 1073, 0, 1074, 0, 1075, 0, 1076, 0, 1077, 0, 1078, 0, 1079, 0, 1080, 0, 1081, 0, 1082, 0, 1083, 0, 1084, 0, 1085, 0, 1086, 0, 1087, 0, 1088, 0, 1089, 0, 1090, 0, 1091, 0, 1092, 0, 1093, 0, 1094, 0, 1095, 0, 1096, 0, 1097, 0, 1098, 0, 1099, 0, 1100, 0, 1101, 0, 1102, 0, 1103, 0, 1104, 0, 1105, 0, 1106, 0, 1107, 0, 1108, 0, 1109, 0, 1110, 0, 1111, 0, 1112, 0, 1113, 0, 1114, 0, 1115, 0, 1116, 0, 1117, 0, 1118, 0, 1119, 0, 1120, 0, 1121, 0, 1122, 0, 1123, 0, 1124, 0, 1125, 0, 1126, 0, 1127, 0, 1128, 0, 1129, 0, 1130, 0, 1131, 0, 1132, 0, 1133, 0, 1134, 0, 1135, 0, 1136, 0, 1137, 0, 1138, 0, 1139, 0, 1140, 0, 1141, 0, 1142, 0, 1143, 0, 1144, 0, 1145, 0, 1146, 0, 1147, 0, 1148, 0, 1149, 0, 1150, 0, 1151, 0, 1152, 0, 1153, 0, 1154, 0, 1155, 0, 1156, 0, 1157, 0, 1158, 0, 1159, 0, 1160, 0, 1161, 0, 1162, 0, 1163, 0, 1164, 0, 1165, 0, 1166, 0, 1167, 0, 1168, 0, 1169, 0, 1170, 0, 1171, 0, 1172, 0, 1173, 0, 1174, 0, 1175, 0, 1176, 0, 1177, 0, 1178, 0, 1179, 0, 1180, 0, 1181, 0, 1182, 0, 1183, 0, 1184, 0, 1185, 0, 1186, 0, 1187, 0, 1188, 0, 1189, 0, 1190, 0, 1191, 0, 1192, 0, 1193, 0, 1194, 0, 1195, 0, 1196, 0, 1197, 0, 1198, 0, 1199, 0, 1200, 0, 1201, 0, 1202, 0, 1203, 0, 1204, 0, 1205, 0, 1206, 0, 1207, 0, 1208, 0, 1209, 0, 1210, 0, 1211, 0, 1212, 0, 1213, 0, 1214, 0, 1215, 0, 1216, 0, 1217, 0, 1218, 0, 1219, 0, 1220, 0, 1221, 0, 1222, 0, 1223, 0, 1224, 0, 1225, 0, 1226, 0, 1227, 0, 1228, 0, 1229, 0, 1230, 0, 1231, 0, 1232, 0, 1233, 0, 1234, 0, 1235, 0, 1236, 0, 1237, 0, 1238, 0, 1239, 0, 1240, 0, 1241, 0, 1242, 0, 1243, 0, 1244, 0, 1245, 0, 1246, 0, 1247, 0, 1248, 0, 1249, 0, 1250, 0, 1251, 0, 1252, 0, 1253, 0, 1254, 0, 1255, 0, 1256, 0, 1257, 0, 1258, 0, 1259, 0, 1260, 0, 1261, 0, 1262, 0, 1263, 0, 1264, 0, 1265, 0, 1266, 0, 1267, 0, 1268, 0, 1269, 0, 1270, 0, 1271, 0, 1272, 0, 1273, 0, 1274, 0, 1275, 0, 1276, 0, 1277, 0, 1278, 0, 1279, 0, 1280, 0, 1281, 0, 1282, 0, 1283, 0, 1284, 0, 1285, 0, 1286, 0, 1287, 0, 1288, 0, 1289, 0, 1290, 0, 1291, 0, 1292, 0, 1293, 0, 1294, 0, 1295, 0, 1296, 0, 1297, 0, 1298, 0, 1299, 0, 1300, 0, 1301, 0, 1302, 0, 1303, 0, 1304, 0, 1305, 0, 1306, 0, 1307, 0, 1308, 0, 1309, 0, 1310, 0, 1311, 0, 1312, 0, 1313, 0, 1314, 0, 1315, 0, 1316, 0, 1317, 0, 1318, 0, 1319, 0, 1320, 0, 1321, 0, 1322, 0, 1323, 0, 1324, 0, 1325, 0, 1326, 0, 1327, 0, 1328, 0, 1329, 0, 1330, 0, 1331, 0, 1332, 0, 1333, 0, 1334, 0, 1335, 0, 1336, 0, 1337, 0, 1338, 0, 1339, 0, 1340, 0, 1341, 0, 1342, 0, 1343, 0, 1344, 0, 1345, 0, 1346, 0, 1347, 0, 1348, 0, 1349, 0, 1350, 0, 1351, 0, 1352, 0, 1353, 0, 1354, 0, 1355, 0, 1356, 0, 1357, 0, 1358, 0, 1359, 0, 1360, 0, 1361, 0, 1362, 0, 1363, 0, 1364, 0, 1365, 0, 1366, 0, 1367, 0, 1368, 0, 1369, 0, 1370, 0, 1371, 0, 1372, 0, 1373, 0, 1374, 0, 1375, 0, 1376, 0, 1377, 0, 1378, 0, 1379, 0, 1380, 0, 1381, 0, 1382, 0, 1383, 0, 1384, 0, 1385, 0, 1386, 0, 1387, 0, 1388, 0, 1389, 0, 1390, 0, 1391, 0, 1392, 0, 1393, 0, 1394, 0, 1395, 0, 1396, 0, 1397, 0, 1398, 0, 1399, 0, 1400, 0, 1401, 0, 1402, 0, 1403, 0, 1404, 0, 1405, 0, 1406, 0, 1407, 0, 1408, 0, 1409, 0, 1410, 0, 1411, 0, 1412, 0, 1413, 0, 1414, 0, 1415, 0, 1416, 0, 1417, 0, 1418, 0, 1419, 0, 1420, 0, 1421, 0, 1422, 0, 1423, 0, 1424, 0, 1425, 0, 1426, 0, 1427, 0, 1428, 0, 1429, 0, 1430, 0, 1431, 0, 1432, 0, 1433, 0, 1434, 0, 1435, 0, 1436, 0, 1437, 0, 1438, 0, 1439, 0, 1440, 0, 1441, 0, 1442, 0, 1443, 0, 1444, 0, 1445, 0, 1446, 0, 1447, 0, 1448, 0, 1449, 0, 1450, 0, 1451, 0, 1452, 0, 1453, 0, 1454, 0, 1455, 0, 1456, 0, 1457, 0, 1458, 0, 1459, 0, 1460, 0, 1461, 0, 1462, 0, 1463, 0, 1464, 0, 1465, 0, 1466, 0, 1467, 0, 1468, 0, 1469, 0, 1470, 0, 1471, 0, 1472, 0, 1473, 0, 1474, 0, 1475, 0, 1476, 0, 1477, 0, 1478, 0, 1479, 0, 1480, 0, 1481, 0, 1482, 0, 1483, 0, 1484, 0, 1485, 0, 1486, 0, 1487, 0, 1488, 0, 1489, 0, 1490, 0, 1491, 0, 1492, 0, 1493, 0, 1494, 0, 1495, 0, 1496, 0, 1497, 0, 1498, 0, 1499, 0, 1500, 0, 1501, 0, 1502, 0, 1503, 0, 1504, 0, 1505, 0, 1506, 0, 1507, 0, 1508, 0, 1509, 0, 1510, 0, 1511, 0, 1512, 0, 1513, 0, 1514, 0, 1515, 0, 1516, 0, 1517, 0, 1518, 0, 1519, 0, 1520, 0, 1521, 0, 1522, 0, 1523, 0, 1524, 0, 1525, 0, 1526, 0, 1527, 0, 1528, 0, 1529, 0, 1530, 0, 1531, 0, 1532, 0, 1533, 0, 1534, 0, 1535, 0, 1536, 0, 1537, 0, 1538, 0, 1539, 0, 1540, 0, 1541, 0, 1542, 0, 1543, 0, 1544, 0, 1545, 0, 1546, 0, 1547, 0, 1548, 0, 1549, 0, 1550, 0, 1551, 0, 1552, 0, 1553, 0, 1554, 0, 1555, 0, 1556, 0, 1557, 0, 1558, 0, 1559, 0, 1560, 0, 1561, 0, 1562, 0, 1563, 0, 1564, 0, 1565, 0, 1566, 0, 1567, 0, 1568, 0, 1569, 0, 1570, 0, 1571, 0, 1572, 0, 1573, 0, 1574, 0, 1575, 0, 1576, 0, 1577, 0, 1578, 0, 1579, 0, 1580, 0, 1581, 0, 1582, 0, 1583, 0, 1584, 0, 1585, 0, 1586, 0, 1587, 0, 1588, 0, 1589, 0, 1590, 0, 1591, 0, 1592, 0, 1593, 0, 1594, 0, 1595, 0, 1596, 0, 1597, 0, 1598, 0, 1599, 0, 1600, 0, 1601, 0, 1602, 0, 1603, 0, 1604, 0, 1605, 0, 1606, 0, 1607, 0, 1608, 0, 1609, 0, 1610, 0, 1611, 0, 1612, 0, 1613, 0, 1614, 0, 1615, 0, 1616, 0, 1617, 0, 1618, 0, 1619, 0, 1620, 0, 1621, 0, 1622, 0, 1623, 0, 1624, 0, 1625, 0, 1626, 0, 1627, 0, 1628, 0, 1629, 0, 1630, 0, 1631, 0, 1632, 0, 1633, 0, 1634, 0, 1635, 0, 1636, 0, 1637, 0, 1638, 0, 1639, 0, 1640, 0, 1641, 0, 1642, 0, 1643, 0, 1644, 0, 1645, 0, 1646, 0, 1647, 0, 1648, 0, 1649, 0, 1650, 0, 1651, 0, 1652, 0, 1653, 0, 1654, 0, 1655, 0, 1656, 0, 1657, 0, 1658, 0, 1659, 0, 1660, 0, 1661, 0, 1662, 0, 1663, 0, 1664, 0, 1665, 0, 1666, 0, 1667, 0, 1668, 0, 1669, 0, 1670, 0, 1671, 0, 1672, 0, 1673, 0, 1674, 0, 1675, 0, 1676, 0, 1677, 0, 1678, 0, 1679, 0, 1680, 0, 1681, 0, 1682, 0, 1683, 0, 1684, 0, 1685, 0, 1686, 0, 1687, 0, 1688, 0, 1689, 0, 1690, 0, 1691, 0, 1692, 0, 1693, 0, 1694, 0, 1695, 0, 1696, 0, 1697, 0, 1698, 0, 1699, 0, 1700, 0, 1701, 0, 1702, 0, 1703, 0, 1704, 0, 1705, 0, 1706, 0, 1707, 0, 1708, 0, 1709, 0, 1710, 0, 1711, 0, 1712, 0, 1713, 0, 1714, 0, 1715, 0, 1716, 0, 1717, 0, 1718, 0, 1719, 0, 1720, 0, 1721, 0, 1722, 0, 1723, 0, 1724, 0, 1725, 0, 1726, 0, 1727, 0, 1728, 0, 1729, 0, 1730, 0, 1731, 0, 1732, 0, 1733, 0, 1734, 0, 1735, 0, 1736, 0, 1737, 0, 1738, 0, 1739, 0, 1740, 0, 1741, 0, 1742, 0, 1743, 0, 1744, 0, 1745, 0, 1746, 0, 1747, 0, 1748, 0, 1749, 0, 1750, 0, 1751, 0, 1752, 0, 1753, 0, 1754, 0, 1755, 0, 1756, 0, 1757, 0, 1758, 0, 1759, 0, 1760, 0, 1761, 0, 1762, 0, 1763, 0, 1764, 0, 1765, 0, 1766, 0, 1767, 0, 1768, 0, 1769, 0, 1770, 0, 1771, 0, 1772, 0, 1773, 0, 1774, 0, 1775, 0, 1776, 0, 1777, 0, 1778, 0, 1779, 0, 1780, 0, 1781, 0, 1782, 0, 1783, 0, 1784, 0, 1785, 0, 1786, 0, 1787, 0, 1788, 0, 1789, 0, 1790, 0, 1791, 0, 1792, 0, 1793, 0, 1794, 0, 1795, 0, 1796, 0, 1797, 0, 1798, 0, 1799, 0, 1800, 0, 1801, 0, 1802, 0, 1803, 0, 1804, 0, 1805, 0, 1806, 0, 1807, 0, 1808, 0, 1809, 0, 1810, 0, 1811, 0, 1812, 0, 1813, 0, 1814, 0, 1815, 0, 1816, 0, 1817, 0, 1818, 0, 1819, 0, 1820, 0, 1821, 0, 1822, 0, 1823, 0, 1824, 0, 1825, 0, 1826, 0, 1827, 0, 1828, 0, 1829, 0, 1830, 0, 1831, 0, 1832, 0, 1833, 0, 1834, 0, 1835, 0, 1836, 0, 1837, 0, 1838, 0, 1839, 0, 1840, 0, 1841, 0, 1842, 0, 1843, 0, 1844, 0, 1845, 0, 1846, 0, 1847, 0, 1848, 0, 1849, 0, 1850, 0, 1851, 0, 1852, 0, 1853, 0, 1854, 0, 1855, 0, 1856, 0, 1857, 0, 1858, 0, 1859, 0, 1860, 0, 1861, 0, 1862, 0, 1863, 0, 1864, 0, 1865, 0, 1866, 0, 1867, 0, 1868, 0, 1869, 0, 1870, 0, 1871, 0, 1872, 0, 1873, 0, 1874, 0, 1875, 0, 1876, 0, 1877, 0, 1878, 0, 1879, 0, 1880, 0, 1881, 0, 1882, 0, 1883, 0, 1884, 0, 1885, 0, 1886, 0, 1887, 0, 1888, 0, 1889, 0, 1890, 0, 1891, 0, 1892, 0, 1893, 0, 1894, 0, 1895, 0, 1896, 0, 1897, 0, 1898, 0, 1899, 0, 1900, 0, 1901, 0, 1902, 0, 1903, 0, 1904, 0, 1905, 0, 1906, 0, 1907, 0, 1908, 0, 1909, 0, 1910, 0, 1911, 0, 1912, 0, 1913, 0, 1914, 0, 1915, 0, 1916, 0, 1917, 0, 1918, 0, 1919, 0, 1920, 0, 1921, 0, 1922, 0, 1923, 0, 1924, 0, 1925, 0, 1926, 0, 1927, 0, 1928, 0, 1929, 0, 1930, 0, 1931, 0, 1932, 0, 1933, 0, 1934, 0, 1935, 0, 1936, 0, 1937, 0, 1938, 0, 1939, 0, 1940, 0, 1941, 0, 1942, 0, 1943, 0, 1944, 0, 1945, 0, 1946, 0, 1947, 0, 1948, 0, 1949, 0, 1950, 0, 1951, 0, 1952, 0, 1953, 0, 1954, 0, 1955, 0, 1956, 0, 1957, 0, 1958, 0, 1959, 0, 1960, 0, 1961, 0, 1962, 0, 1963, 0, 1964, 0, 1965, 0, 1966, 0, 1967, 0, 1968, 0, 1969, 0, 1970, 0, 1971, 0, 1972, 0, 1973, 0, 1974, 0, 1975, 0, 1976, 0, 1977, 0, 1978, 0, 1979, 0, 1980, 0, 1981, 0, 1982, 0, 1983, 0, 1984, 0, 1985, 0, 1986, 0, 1987, 0, 1988, 0, 1989, 0, 1990, 0, 1991, 0, 1992, 0, 1993, 0, 1994, 0, 1995, 0, 1996, 0, 1997, 0, 1998, 0, 1999, 0, 2000, 0, 2001, 0, 2002, 0, 2003, 0, 2004, 0, 2005, 0, 2006, 0, 2007, 0, 2008, 0, 2009, 0, 2010, 0, 2011, 0, 2012, 0, 2013, 0, 2014, 0, 2015, 0, 2016, 0, 2017, 0, 2018, 0, 2019, 0, 2020, 0, 2021, 0, 2022, 0, 2023, 0, 2024, 0, 2025, 0, 2026, 0, 2027, 0, 2028, 0, 2029, 0, 2030, 0, 2031, 0, 2032, 0, 2033, 0, 2034, 0, 2035, 0, 2036, 0, 2037, 0, 2038, 0, 2039, 0, 2040, 0, 2041, 0, 2042, 0, 2043, 0, 2044, 0, 2045, 0, 2046, 0, 2047, 0, 2048, 0, 2049, 0, 2050, 0, 2051, 0, 2052, 0, 2053, 0, 2054, 0, 2055, 0, 2056, 0, 2057, 0, 2058, 0, 2059, 0, 2060, 0, 2061, 0, 2062, 0, 2063, 0, 2064, 0, 2065, 0, 2066, 0, 2067, 0, 2068, 0, 2069, 0, 2070, 0, 2071, 0, 2072, 0, 2073, 0, 2074, 0, 2075, 0, 2076, 0, 2077, 0, 2078, 0, 2079, 0, 2080, 0, 2081, 0, 2082, 0, 2083, 0, 2084, 0, 2085, 0, 2086, 0, 2087, 0, 2088, 0, 2089, 0, 2090, 0, 2091, 0, 2092, 0, 2093, 0, 2094, 0, 2095, 0, 2096, 0, 2097, 0, 2098, 0, 2099, 0, 2100, 0, 2101, 0, 2102, 0, 2103, 0, 2104, 0, 2105, 0, 2106, 0, 2107, 0, 2108, 0, 2109, 0, 2110, 0, 2111, 0, 2112, 0, 2113, 0, 2114, 0, 2115, 0, 2116, 0, 2117, 0, 2118, 0, 2119, 0, 2120, 0, 2121, 0, 2122, 0, 2123, 0, 2124, 0, 2125, 0, 2126, 0, 2127, 0, 2128, 0, 2129, 0, 2130, 0, 2131, 0, 2132, 0, 2133, 0, 2134, 0, 2135, 0, 2136, 0, 2137, 0, 2138, 0, 2139, 0, 2140, 0, 2141, 0, 2142, 0, 2143, 0, 2144, 0, 2145, 0, 2146, 0, 2147, 0, 2148, 0, 2149, 0, 2150, 0, 2151, 0, 2152, 0, 2153, 0, 2154, 0, 2155, 0, 2156, 0, 2157, 0, 2158, 0, 2159, 0, 2160, 0, 2161, 0, 2162, 0, 2163, 0, 2164, 0, 2165, 0, 2166, 0, 2167, 0, 2168, 0, 2169, 0, 2170, 0, 2171, 0, 2172, 0, 2173, 0, 2174, 0, 2175, 0, 2176, 0, 2177, 0, 2178, 0, 2179, 0, 2180, 0, 2181, 0, 2182, 0, 2183, 0, 2184, 0, 2185, 0, 2186, 0, 2187, 0, 2188, 0, 2189, 0, 2190, 0, 2191, 0, 2192, 0, 2193, 0, 2194, 0, 2195, 0, 2196, 0, 2197, 0, 2198, 0, 2199, 0, 2200, 0, 2201, 0, 2202, 0, 2203, 0, 2204, 0, 2205, 0, 2206, 0, 2207, 0, 2208, 0, 2209, 0, 2210, 0, 2211, 0, 2212, 0, 2213, 0, 2214, 0, 2215, 0, 2216, 0, 2217, 0, 2218, 0, 2219, 0, 2220, 0, 2221, 0, 2222, 0, 2223, 0, 2224, 0, 2225, 0, 2226, 0, 2227, 0, 2228, 0, 2229, 0, 2230, 0, 2231, 0, 2232, 0, 2233, 0, 2234, 0, 2235, 0, 2236, 0, 2237, 0, 2238, 0, 2239, 0, 2240, 0, 2241, 0, 2242, 0, 2243, 0, 2244, 0, 2245, 0, 2246, 0, 2247, 0, 2248, 0, 2249, 0, 2250, 0, 2251, 0, 2252, 0, 2253, 0, 2254, 0, 2255, 0, 2256, 0, 2257, 0, 2258, 0, 2259, 0, 2260, 0, 2261, 0, 2262, 0, 2263, 0, 2264, 0, 2265, 0, 2266, 0, 2267, 0, 2268, 0, 2269, 0, 2270, 0, 2271, 0, 2272, 0, 2273, 0, 2274, 0, 2275, 0, 2276, 0, 2277, 0, 2278, 0, 2279, 0, 2280, 0, 2281, 0, 2282, 0, 2283, 0, 2284, 0, 2285, 0, 2286, 0, 2287, 0, 2288, 0, 2289, 0, 2290, 0, 2291, 0, 2292, 0, 2293, 0, 2294, 0, 2295, 0, 2296, 0, 2297, 0, 2298, 0, 2299, 0, 2300, 0, 2301, 0, 2302, 0, 2303, 0, 2304, 0, 2305, 0, 2306, 0, 2307, 0, 2308, 0, 2309, 0, 2310, 0, 2311, 0, 2312, 0, 2313, 0, 2314, 0, 2315, 0, 2316, 0, 2317, 0, 2318, 0, 2319, 0, 2320, 0, 2321, 0, 2322, 0, 2323, 0, 2324, 0, 2325, 0, 2326, 0, 2327, 0, 2328, 0, 2329, 0, 2330, 0, 2331, 0, 2332, 0, 2333, 0, 2334, 0, 2335, 0, 2336, 0, 2337, 0, 2338, 0, 2339, 0, 2340, 0, 2341, 0, 2342, 0, 2343, 0, 2344, 0, 2345, 0, 2346, 0, 2347, 0, 2348, 0, 2349, 0, 2350, 0, 2351, 0, 2352, 0, 2353, 0, 2354, 0, 2355, 0, 2356, 0, 2357, 0, 2358, 0, 2359, 0, 2360, 0, 2361, 0, 2362, 0, 2363, 0, 2364, 0, 2365, 0, 2366, 0, 2367, 0, 2368, 0, 2369, 0, 2370, 0, 2371, 0, 2372, 0, 2373, 0, 2374, 0, 2375, 0, 2376, 0, 2377, 0, 2378, 0, 2379, 0, 2380, 0, 2381, 0, 2382, 0, 2383, 0, 2384, 0, 2385, 0, 2386, 0, 2387, 0, 2388, 0, 2389, 0, 2390, 0, 2391, 0, 2392, 0, 2393, 0, 2394, 0, 2395, 0, 2396, 0, 2397, 0, 2398, 0, 2399, 0, 2400, 0, 2401, 0, 2402, 0, 2403, 0, 2404, 0, 2405, 0, 2406, 0, 2407, 0, 2408, 0, 2409, 0, 2410, 0, 2411, 0, 2412, 0, 2413, 0, 2414, 0, 2415, 0, 2416, 0, 2417, 0, 2418, 0, 2419, 0, 2420, 0, 2421, 0, 2422, 0, 2423, 0, 2424, 0, 2425, 0, 2426, 0, 2427, 0, 2428, 0, 2429, 0, 2430, 0, 2431, 0, 2432, 0, 2433, 0, 2434, 0, 2435, 0, 2436, 0, 2437, 0, 2438, 0, 2439, 0, 2440, 0, 2441, 0, 2442, 0, 2443, 0, 2444, 0, 2445, 0, 2446, 0, 2447, 0, 2448, 0, 2449, 0, 2450, 0, 2451, 0, 2452, 0, 2453, 0, 2454, 0, 2455, 0, 2456, 0, 2457, 0, 2458, 0, 2459, 0, 2460, 0, 2461, 0, 2462, 0, 2463, 0, 2464, 0, 2465, 0, 2466, 0, 2467, 0, 2468, 0, 2469, 0, 2470, 0, 2471, 0, 2472, 0, 2473, 0, 2474, 0, 2475, 0, 2476, 0, 2477, 0, 2478, 0, 2479, 0, 2480, 0, 2481, 0, 2482, 0, 2483, 0, 2484, 0, 2485, 0, 2486, 0, 2487, 0, 2488, 0, 2489, 0, 2490, 0, 2491, 0, 2492, 0, 2493, 0, 2494, 0, 2495, 0, 2496, 0, 2497, 0, 2498, 0, 2499, 0, 2500, 0, 2501, 0, 2502, 0, 2503, 0, 2504, 0, 2505, 0, 2506, 0, 2507, 0, 2508, 0, 2509, 0, 2510, 0, 2511, 0, 2512, 0, 2513, 0, 2514, 0, 2515, 0, 2516, 0, 2517, 0, 2518, 0, 2519, 0, 2520, 0, 2521, 0, 2522, 0, 2523, 0, 2524, 0, 2525, 0, 2526, 0, 2527, 0, 2528, 0, 2529, 0, 2530, 0, 2531, 0, 2532, 0, 2533, 0, 2534, 0, 2535, 0, 2536, 0, 2537, 0, 2538, 0, 2539, 0, 2540, 0, 2541, 0, 2542, 0, 2543, 0, 2544, 0, 2545, 0, 2546, 0, 2547, 0, 2548, 0, 2549, 0, 2550, 0, 2551, 0, 2552, 0, 2553, 0, 2554, 0, 2555, 0, 2556, 0, 2557, 0, 2558, 0, 2559, 0, 2560, 0, 2561, 0, 2562, 0, 2563, 0, 2564, 0, 2565, 0, 2566, 0, 2567, 0, 2568, 0, 2569, 0, 2570, 0, 2571, 0, 2572, 0, 2573, 0, 2574, 0, 2575, 0, 2576, 0, 2577, 0, 2578, 0, 2579, 0, 2580, 0, 2581, 0, 2582, 0, 2583, 0, 2584, 0, 2585, 0, 2586, 0, 2587, 0, 2588, 0, 2589, 0, 2590, 0, 2591, 0, 2592, 0, 2593, 0, 2594, 0, 2595, 0, 2596, 0, 2597, 0, 2598, 0, 2599, 0, 2600, 0, 2601, 0, 2602, 0, 2603, 0, 2604, 0, 2605, 0, 2606, 0, 2607, 0, 2608, 0, 2609, 0, 2610, 0, 2611, 0, 2612, 0, 2613, 0, 2614, 0, 2615, 0, 2616, 0, 2617, 0, 2618, 0, 2619, 0, 2620, 0, 2621, 0, 2622, 0, 2623, 0, 2624, 0, 2625, 0, 2626, 0, 2627, 0, 2628, 0, 2629, 0, 2630, 0, 2631, 0, 2632, 0, 2633, 0, 2634, 0, 2635, 0, 2636, 0, 2637, 0, 2638, 0, 2639, 0, 2640, 0, 2641, 0, 2642, 0, 2643, 0, 2644, 0, 2645, 0, 2646, 0, 2647, 0, 2648, 0, 2649, 0, 2650, 0, 2651, 0, 2652, 0, 2653, 0, 2654, 0, 2655, 0, 2656, 0, 2657, 0, 2658, 0, 2659, 0, 2660, 0, 2661, 0, 2662, 0, 2663, 0, 2664, 0, 2665, 0, 2666, 0, 2667, 0, 2668, 0, 2669, 0, 2670, 0, 2671, 0, 2672, 0, 2673, 0, 2674, 0, 2675, 0, 2676, 0, 2677, 0, 2678, 0, 2679, 0, 2680, 0, 2681, 0, 2682, 0, 2683, 0, 2684, 0, 2685, 0, 2686, 0, 2687, 0, 2688, 0, 2689, 0, 2690, 0, 2691, 0, 2692, 0, 2693, 0, 2694, 0, 2695, 0, 2696, 0, 2697, 0, 2698, 0, 2699, 0, 2700, 0, 2701, 0, 2702, 0, 2703, 0, 2704, 0, 2705, 0, 2706, 0, 2707, 0, 2708, 0, 2709, 0, 2710, 0, 2711, 0, 2712, 0, 2713, 0, 2714, 0, 2715, 0, 2716, 0, 2717, 0, 2718, 0, 2719, 0, 2720, 0, 2721, 0, 2722, 0, 2723, 0, 2724, 0, 2725, 0, 2726, 0, 2727, 0, 2728, 0, 2729, 0, 2730, 0, 2731, 0, 2732, 0, 2733, 0, 2734, 0, 2735, 0, 2736, 0, 2737, 0, 2738, 0, 2739, 0, 2740, 0, 2741, 0, 2742, 0, 2743, 0, 2744, 0, 2745, 0, 2746, 0, 2747, 0, 2748, 0, 2749, 0, 2750, 0, 2751, 0, 2752, 0, 2753, 0, 2754, 0, 2755, 0, 2756, 0, 2757, 0, 2758, 0, 2759, 0, 2760, 0, 2761, 0, 2762, 0, 2763, 0, 2764, 0, 2765, 0, 2766, 0, 2767, 0, 2768, 0, 2769, 0, 2770, 0, 2771, 0, 2772, 0, 2773, 0, 2774, 0, 2775, 0, 2776, 0, 2777, 0, 2778, 0, 2779, 0, 2780, 0, 2781, 0, 2782, 0, 2783, 0, 2784, 0, 2785, 0, 2786, 0, 2787, 0, 2788, 0, 2789, 0, 2790, 0, 2791, 0, 2792, 0, 2793, 0, 2794, 0, 2795, 0, 2796, 0, 2797, 0, 2798, 0, 2799, 0, 2800, 0, 2801, 0, 2802, 0, 2803, 0, 2804, 0, 2805, 0, 2806, 0, 2807, 0, 2808, 0, 2809, 0, 2810, 0, 2811, 0, 2812, 0, 2813, 0, 2814, 0, 2815, 0, 2816, 0, 2817, 0, 2818, 0, 2819, 0, 2820, 0, 2821, 0, 2822, 0, 2823, 0, 2824, 0, 2825, 0, 2826, 0, 2827, 0, 2828, 0, 2829, 0, 2830, 0, 2831, 0, 2832, 0, 2833, 0, 2834, 0, 2835, 0, 2836, 0, 2837, 0, 2838, 0, 2839, 0, 2840, 0, 2841, 0, 2842, 0, 2843, 0, 2844, 0, 2845, 0, 2846, 0, 2847, 0, 2848, 0, 2849, 0, 2850, 0, 2851, 0, 2852, 0, 2853, 0, 2854, 0, 2855, 0, 2856, 0, 2857, 0, 2858, 0, 2859, 0, 2860, 0, 2861, 0, 2862, 0, 2863, 0, 2864, 0, 2865, 0, 2866, 0, 2867, 0, 2868, 0, 2869, 0, 2870, 0, 2871, 0, 2872, 0, 2873, 0, 2874, 0, 2875, 0, 2876, 0, 2877, 0, 2878, 0, 2879, 0, 2880, 0, 2881, 0, 2882, 0, 2883, 0, 2884, 0, 2885, 0, 2886, 0, 2887, 0, 2888, 0, 2889, 0, 2890, 0, 2891, 0, 2892, 0, 2893, 0, 2894, 0, 2895, 0, 2896, 0, 2897, 0, 2898, 0, 2899, 0, 2900, 0, 2901, 0, 2902, 0, 2903, 0, 2904, 0, 2905, 0, 2906, 0, 2907, 0, 2908, 0, 2909, 0, 2910, 0, 2911, 0, 2912, 0, 2913, 0, 2914, 0, 2915, 0, 2916, 0, 2917, 0, 2918, 0, 2919, 0, 2920, 0, 2921, 0, 2922, 0, 2923, 0, 2924, 0, 2925, 0, 2926, 0, 2927, 0, 2928, 0, 2929, 0, 2930, 0, 2931, 0, 2932, 0, 2933, 0, 2934, 0, 2935, 0, 2936, 0, 2937, 0, 2938, 0, 2939, 0, 2940, 0, 2941, 0, 2942, 0, 2943, 0, 2944, 0, 2945, 0, 2946, 0, 2947, 0, 2948, 0, 2949, 0, 2950, 0, 2951, 0, 2952, 0, 2953, 0, 2954, 0, 2955, 0, 2956, 0, 2957, 0, 2958, 0, 2959, 0, 2960, 0, 2961, 0, 2962, 0, 2963, 0, 2964, 0, 2965, 0, 2966, 0, 2967, 0, 2968, 0, 2969, 0, 2970, 0, 2971, 0, 2972, 0, 2973, 0, 2974, 0, 2975, 0, 2976, 0, 2977, 0, 2978, 0, 2979, 0, 2980, 0, 2981, 0, 2982, 0, 2983, 0, 2984, 0, 2985, 0, 2986, 0, 2987, 0, 2988, 0, 2989, 0, 2990, 0, 2991, 0, 2992, 0, 2993, 0, 2994, 0, 2995, 0, 2996, 0, 2997, 0, 2998, 0, 2999, 0, 3000, 0, 3001, 0, 3002, 0, 3003, 0, 3004, 0, 3005, 0, 3006, 0, 3007, 0, 3008, 0, 3009, 0, 3010, 0, 3011, 0, 3012, 0, 3013, 0, 3014, 0, 3015, 0, 3016, 0, 3017, 0, 3018, 0, 3019, 0, 3020, 0, 3021, 0, 3022, 0, 3023, 0, 3024, 0, 3025, 0, 3026, 0, 3027, 0, 3028, 0, 3029, 0, 3030, 0, 3031, 0, 3032, 0, 3033, 0, 3034, 0, 3035, 0, 3036, 0, 3037, 0, 3038, 0, 3039, 0, 3040, 0, 3041, 0, 3042, 0, 3043, 0, 3044, 0, 3045, 0, 3046, 0, 3047, 0, 3048, 0, 3049, 0, 3050, 0, 3051, 0, 3052, 0, 3053, 0, 3054, 0, 3055, 0, 3056, 0, 3057, 0, 3058, 0, 3059, 0, 3060, 0, 3061, 0, 3062, 0, 3063, 0, 3064, 0, 3065, 0, 3066, 0, 3067, 0, 3068, 0, 3069, 0, 3070, 0, 3071, 0, 3072, 0, 3073, 0, 3074, 0, 3075, 0, 3076, 0, 3077, 0, 3078, 0, 3079, 0, 3080, 0, 3081, 0, 3082, 0, 3083, 0, 3084, 0, 3085, 0, 3086, 0, 3087, 0, 3088, 0, 3089, 0, 3090, 0, 3091, 0, 3092, 0, 3093, 0, 3094, 0, 3095, 0, 3096, 0, 3097, 0, 3098, 0, 3099, 0, 3100, 0, 3101, 0, 3102, 0, 3103, 0, 3104, 0, 3105, 0, 3106, 0, 3107, 0, 3108, 0, 3109, 0, 3110, 0, 3111, 0, 3112, 0, 3113, 0, 3114, 0, 3115, 0, 3116, 0, 3117, 0, 3118, 0, 3119, 0, 3120, 0, 3121, 0, 3122, 0, 3123, 0, 3124, 0, 3125, 0, 3126, 0, 3127, 0, 3128, 0, 3129, 0, 3130, 0, 3131, 0, 3132, 0, 3133, 0, 3134, 0, 3135, 0, 3136, 0, 3137, 0, 3138, 0, 3139, 0, 3140, 0, 3141, 0, 3142, 0, 3143, 0, 3144, 0, 3145, 0, 3146, 0, 3147, 0, 3148, 0, 3149, 0, 3150, 0, 3151, 0, 3152, 0, 3153, 0, 3154, 0, 3155, 0, 3156, 0, 3157, 0, 3158, 0, 3159, 0, 3160, 0, 3161, 0, 3162, 0, 3163, 0, 3164, 0, 3165, 0, 3166, 0, 3167, 0, 3168, 0, 3169, 0, 3170, 0, 3171, 0, 3172, 0, 3173, 0, 3174, 0, 3175, 0, 3176, 0, 3177, 0, 3178, 0, 3179, 0, 3180, 0, 3181, 0, 3182, 0, 3183, 0, 3184, 0, 3185, 0, 3186, 0, 3187, 0, 3188, 0, 3189, 0, 3190, 0, 3191, 0, 3192, 0, 3193, 0, 3194, 0, 3195, 0, 3196, 0, 3197, 0, 3198, 0, 3199, 0, 3200, 0, 3201, 0, 3202, 0, 3203, 0, 3204, 0, 3205, 0, 3206, 0, 3207, 0, 3208, 0, 3209, 0, 3210, 0, 3211, 0, 3212, 0, 3213, 0, 3214, 0, 3215, 0, 3216, 0, 3217, 0, 3218, 0, 3219, 0, 3220, 0, 3221, 0, 3222, 0, 3223, 0, 3224, 0, 3225, 0, 3226, 0, 3227, 0, 3228, 0, 3229, 0, 3230, 0, 3231, 0, 3232, 0, 3233, 0, 3234, 0, 3235, 0, 3236, 0, 3237, 0, 3238, 0, 3239, 0, 3240, 0, 3241, 0, 3242, 0, 3243, 0, 3244, 0, 3245, 0, 3246, 0, 3247, 0, 3248, 0, 3249, 0, 3250, 0, 3251, 0, 3252, 0, 3253, 0, 3254, 0, 3255, 0, 3256, 0, 3257, 0, 3258, 0, 3259, 0, 3260, 0, 3261, 0, 3262, 0, 3263, 0, 3264, 0, 3265, 0, 3266, 0, 3267, 0, 3268, 0, 3269, 0, 3270, 0, 3271, 0, 3272, 0, 3273, 0, 3274, 0, 3275, 0, 3276, 0, 3277, 0, 3278, 0, 3279, 0, 3280, 0, 3281, 0, 3282, 0, 3283, 0, 3284, 0, 3285, 0, 3286, 0, 3287, 0, 3288, 0, 3289, 0, 3290, 0, 3291, 0, 3292, 0, 3293, 0, 3294, 0, 3295, 0, 3296, 0, 3297, 0, 3298, 0, 3299, 0, 3300, 0, 3301, 0, 3302, 0, 3303, 0, 3304, 0, 3305, 0, 3306, 0, 3307, 0, 3308, 0, 3309, 0, 3310, 0, 3311, 0, 3312, 0, 3313, 0, 3314, 0, 3315, 0, 3316, 0, 3317, 0, 3318, 0, 3319, 0, 3320, 0, 3321, 0, 3322, 0, 3323, 0, 3324, 0, 3325, 0, 3326, 0, 3327, 0, 3328, 0, 3329, 0, 3330, 0, 3331, 0, 3332, 0, 3333, 0, 3334, 0, 3335, 0, 3336, 0, 3337, 0, 3338, 0, 3339, 0, 3340, 0, 3341, 0, 3342, 0, 3343, 0, 3344, 0, 3345, 0, 3346, 0, 3347, 0, 3348, 0, 3349, 0, 3350, 0, 3351, 0, 3352, 0, 3353, 0, 3354, 0, 3355, 0, 3356, 0, 3357, 0, 3358, 0, 3359, 0, 3360, 0, 3361, 0, 3362, 0, 3363, 0, 3364, 0, 3365, 0, 3366, 0, 3367, 0, 3368, 0, 3369, 0, 3370, 0, 3371, 0, 3372, 0, 3373, 0, 3374, 0, 3375, 0, 3376, 0, 3377, 0, 3378, 0, 3379, 0, 3380, 0, 3381, 0, 3382, 0, 3383, 0, 3384, 0, 3385, 0, 3386, 0, 3387, 0, 3388, 0, 3389, 0, 3390, 0, 3391, 0, 3392, 0, 3393, 0, 3394, 0, 3395, 0, 3396, 0, 3397, 0, 3398, 0, 3399, 0, 3400, 0, 3401, 0, 3402, 0, 3403, 0, 3404, 0, 3405, 0, 3406, 0, 3407, 0, 3408, 0, 3409, 0, 3410, 0, 3411, 0, 3412, 0, 3413, 0, 3414, 0, 3415, 0, 3416, 0, 3417, 0, 3418, 0, 3419, 0, 3420, 0, 3421, 0, 3422, 0, 3423, 0, 3424, 0, 3425, 0, 3426, 0, 3427, 0, 3428, 0, 3429, 0, 3430, 0, 3431, 0, 3432, 0, 3433, 0, 3434, 0, 3435, 0, 3436, 0, 3437, 0, 3438, 0, 3439, 0, 3440, 0, 3441, 0, 3442, 0, 3443, 0, 3444, 0, 3445, 0, 3446, 0, 3447, 0, 3448, 0, 3449, 0, 3450, 0, 3451, 0, 3452, 0, 3453, 0, 3454, 0, 3455, 0, 3456, 0, 3457, 0, 3458, 0, 3459, 0, 3460, 0, 3461, 0, 3462, 0, 3463, 0, 3464, 0, 3465, 0, 3466, 0, 3467, 0, 3468, 0, 3469, 0, 3470, 0, 3471, 0, 3472, 0, 3473, 0, 3474, 0, 3475, 0, 3476, 0, 3477, 0, 3478, 0, 3479, 0, 3480, 0, 3481, 0, 3482, 0, 3483, 0, 3484, 0, 3485, 0, 3486, 0, 3487, 0, 3488, 0, 3489, 0, 3490, 0, 3491, 0, 3492, 0, 3493, 0, 3494, 0, 3495, 0, 3496, 0, 3497, 0, 3498, 0, 3499, 0, 3500, 0, 3501, 0, 3502, 0, 3503, 0, 3504, 0, 3505, 0, 3506, 0, 3507, 0, 3508, 0, 3509, 0, 3510, 0, 3511, 0, 3512, 0, 3513, 0, 3514, 0, 3515, 0, 3516, 0, 3517, 0, 3518, 0, 3519, 0, 3520, 0, 3521, 0, 3522, 0, 3523, 0, 3524, 0, 3525, 0, 3526, 0, 3527, 0, 3528, 0, 3529, 0, 3530, 0, 3531, 0, 3532, 0, 3533, 0, 3534, 0, 3535, 0, 3536, 0, 3537, 0, 3538, 0, 3539, 0, 3540, 0, 3541, 0, 3542, 0, 3543, 0, 3544, 0, 3545, 0, 3546, 0, 3547, 0, 3548, 0, 3549, 0, 3550, 0, 3551, 0, 3552, 0, 3553, 0, 3554, 0, 3555, 0, 3556, 0, 3557, 0, 3558, 0, 3559, 0, 3560, 0, 3561, 0, 3562, 0, 3563, 0, 3564, 0, 3565, 0, 3566, 0, 3567, 0, 3568, 0, 3569, 0, 3570, 0, 3571, 0, 3572, 0, 3573, 0, 3574, 0, 3575, 0, 3576, 0, 3577, 0, 3578, 0, 3579, 0, 3580, 0, 3581, 0, 3582, 0, 3583, 0, 3584, 0, 3585, 0, 3586, 0, 3587, 0, 3588, 0, 3589, 0, 3590, 0, 3591, 0, 3592, 0, 3593, 0, 3594, 0, 3595, 0, 3596, 0, 3597, 0, 3598, 0, 3599, 0, 3600, 0, 3601, 0, 3602, 0, 3603, 0, 3604, 0, 3605, 0, 3606, 0, 3607, 0, 3608, 0, 3609, 0, 3610, 0, 3611, 0, 3612, 0, 3613, 0, 3614, 0, 3615, 0, 3616, 0, 3617, 0, 3618, 0, 3619, 0, 3620, 0, 3621, 0, 3622, 0, 3623, 0, 3624, 0, 3625, 0, 3626, 0, 3627, 0, 3628, 0, 3629, 0, 3630, 0, 3631, 0, 3632, 0, 3633, 0, 3634, 0, 3635, 0, 3636, 0, 3637, 0, 3638, 0, 3639, 0, 3640, 0, 3641, 0, 3642, 0, 3643, 0, 3644, 0, 3645, 0, 3646, 0, 3647, 0, 3648, 0, 3649, 0, 3650, 0, 3651, 0, 3652, 0, 3653, 0, 3654, 0, 3655, 0, 3656, 0, 3657, 0, 3658, 0, 3659, 0, 3660, 0, 3661, 0, 3662, 0, 3663, 0, 3664, 0, 3665, 0, 3666, 0, 3667, 0, 3668, 0, 3669, 0, 3670, 0, 3671, 0, 3672, 0, 3673, 0, 3674, 0, 3675, 0, 3676, 0, 3677, 0, 3678, 0, 3679, 0, 3680, 0, 3681, 0, 3682, 0, 3683, 0, 3684, 0, 3685, 0, 3686, 0, 3687, 0, 3688, 0, 3689, 0, 3690, 0, 3691, 0, 3692, 0, 3693, 0, 3694, 0, 3695, 0, 3696, 0, 3697, 0, 3698, 0, 3699, 0, 3700, 0, 3701, 0, 3702, 0, 3703, 0, 3704, 0, 3705, 0, 3706, 0, 3707, 0, 3708, 0, 3709, 0, 3710, 0, 3711, 0, 3712, 0, 3713, 0, 3714, 0, 3715, 0, 3716, 0, 3717, 0, 3718, 0, 3719, 0, 3720, 0, 3721, 0, 3722, 0, 3723, 0, 3724, 0, 3725, 0, 3726, 0, 3727, 0, 3728, 0, 3729, 0, 3730, 0, 3731, 0, 3732, 0, 3733, 0, 3734, 0, 3735, 0, 3736, 0, 3737, 0, 3738, 0, 3739, 0, 3740, 0, 3741, 0, 3742, 0, 3743, 0, 3744, 0, 3745, 0, 3746, 0, 3747, 0, 3748, 0, 3749, 0, 3750, 0, 3751, 0, 3752, 0, 3753, 0, 3754, 0, 3755, 0, 3756, 0, 3757, 0, 3758, 0, 3759, 0, 3760, 0, 3761, 0, 3762, 0, 3763, 0, 3764, 0, 3765, 0, 3766, 0, 3767, 0, 3768, 0, 3769, 0, 3770, 0, 3771, 0, 3772, 0, 3773, 0, 3774, 0, 3775, 0, 3776, 0, 3777, 0, 3778, 0, 3779, 0, 3780, 0, 3781, 0, 3782, 0, 3783, 0, 3784, 0, 3785, 0, 3786, 0, 3787, 0, 3788, 0, 3789, 0, 3790, 0, 3791, 0, 3792, 0, 3793, 0, 3794, 0, 3795, 0, 3796, 0, 3797, 0, 3798, 0, 3799, 0, 3800, 0, 3801, 0, 3802, 0, 3803, 0, 3804, 0, 3805, 0, 3806, 0, 3807, 0, 3808, 0, 3809, 0, 3810, 0, 3811, 0, 3812, 0, 3813, 0, 3814, 0, 3815, 0, 3816, 0, 3817, 0, 3818, 0, 3819, 0, 3820, 0, 3821, 0, 3822, 0, 3823, 0, 3824, 0, 3825, 0, 3826, 0, 3827, 0, 3828, 0, 3829, 0, 3830, 0, 3831, 0, 3832, 0, 3833, 0, 3834, 0, 3835, 0, 3836, 0, 3837, 0, 3838, 0, 3839, 0, 3840, 0, 3841, 0, 3842, 0, 3843, 0, 3844, 0, 3845, 0, 3846, 0, 3847, 0, 3848, 0, 3849, 0, 3850, 0, 3851, 0, 3852, 0, 3853, 0, 3854, 0, 3855, 0, 3856, 0, 3857, 0, 3858, 0, 3859, 0, 3860, 0, 3861, 0, 3862, 0, 3863, 0, 3864, 0, 3865, 0, 3866, 0, 3867, 0, 3868, 0, 3869, 0, 3870, 0, 3871, 0, 3872, 0, 3873, 0, 3874, 0, 3875, 0, 3876, 0, 3877, 0, 3878, 0, 3879, 0, 3880, 0, 3881, 0, 3882, 0, 3883, 0, 3884, 0, 3885, 0, 3886, 0, 3887, 0, 3888, 0, 3889, 0, 3890, 0, 3891, 0, 3892, 0, 3893, 0, 3894, 0, 3895, 0, 3896, 0, 3897, 0, 3898, 0, 3899, 0, 3900, 0, 3901, 0, 3902, 0, 3903, 0, 3904, 0, 3905, 0, 3906, 0, 3907, 0, 3908, 0, 3909, 0, 3910, 0, 3911, 0, 3912, 0, 3913, 0, 3914, 0, 3915, 0, 3916, 0, 3917, 0, 3918, 0, 3919, 0, 3920, 0, 3921, 0, 3922, 0, 3923, 0, 3924, 0, 3925, 0, 3926, 0, 3927, 0, 3928, 0, 3929, 0, 3930, 0, 3931, 0, 3932, 0, 3933, 0, 3934, 0, 3935, 0, 3936, 0, 3937, 0, 3938, 0, 3939, 0, 3940, 0, 3941, 0, 3942, 0, 3943, 0, 3944, 0, 3945, 0, 3946, 0, 3947, 0, 3948, 0, 3949, 0, 3950, 0, 3951, 0, 3952, 0, 3953, 0, 3954, 0, 3955, 0, 3956, 0, 3957, 0, 3958, 0, 3959, 0, 3960, 0, 3961, 0, 3962, 0, 3963, 0, 3964, 0, 3965, 0, 3966, 0, 3967, 0, 3968, 0, 3969, 0, 3970, 0, 3971, 0, 3972, 0, 3973, 0, 3974, 0, 3975, 0, 3976, 0, 3977, 0, 3978, 0, 3979, 0, 3980, 0, 3981, 0, 3982, 0, 3983, 0, 3984, 0, 3985, 0, 3986, 0, 3987, 0, 3988, 0, 3989, 0, 3990, 0, 3991, 0, 3992, 0, 3993, 0, 3994, 0, 3995, 0, 3996, 0, 3997, 0, 3998, 0, 3999, 0, 4000, 0, 4001, 0, 4002, 0, 4003, 0, 4004, 0, 4005, 0, 4006, 0, 4007, 0, 4008, 0, 4009, 0, 4010, 0, 4011, 0, 4012, 0, 4013, 0, 4014, 0, 4015, 0, 4016, 0, 4017, 0, 4018, 0, 4019, 0, 4020, 0, 4021, 0, 4022, 0, 4023, 0, 4024, 0, 4025, 0, 4026, 0, 4027, 0, 4028, 0, 4029, 0, 4030, 0, 4031, 0, 4032, 0, 4033, 0, 4034, 0, 4035, 0, 4036, 0, 4037, 0, 4038, 0, 4039, 0, 4040, 0, 4041, 0, 4042, 0, 4043, 0, 4044, 0, 4045, 0, 4046, 0, 4047, 0, 4048, 0, 4049, 0, 4050, 0, 4051, 0, 4052, 0, 4053, 0, 4054, 0, 4055, 0, 4056, 0, 4057, 0, 4058, 0, 4059, 0, 4060, 0, 4061, 0, 4062, 0, 4063, 0, 4064, 0, 4065, 0, 4066, 0, 4067, 0, 4068, 0, 4069, 0, 4070, 0, 4071, 0, 4072, 0, 4073, 0, 4074, 0, 4075, 0, 4076, 0, 4077, 0, 4078, 0, 4079, 0, 4080, 0, 4081, 0, 4082, 0, 4083, 0, 4084, 0, 4085, 0, 4086, 0, 4087, 0, 4088, 0, 4089, 0, 4090, 0, 4091, 0, 4092, 0, 4093, 0, 4094, 0, 4095, 0, 4096, 0, 4097, 0, 4098, 0, 4099, 0, 4100, 0, 4101, 0, 4102, 0, 4103, 0, 4104, 0, 4105, 0, 4106, 0, 4107, 0, 4108, 0, 4109, 0, 4110, 0, 4111, 0, 4112, 0, 4113, 0, 4114, 0, 4115, 0, 4116, 0, 4117, 0, 4118, 0, 4119, 0, 4120, 0, 4121, 0, 4122, 0, 4123, 0, 4124, 0, 4125, 0, 4126, 0, 4127, 0, 4128, 0, 4129, 0, 4130, 0, 4131, 0, 4132, 0, 4133, 0, 4134, 0, 4135, 0, 4136, 0, 4137, 0, 4138, 0, 4139, 0, 4140, 0, 4141, 0, 4142, 0, 4143, 0, 4144, 0, 4145, 0, 4146, 0, 4147, 0, 4148, 0, 4149, 0, 4150, 0, 4151, 0, 4152, 0, 4153, 0, 4154, 0, 4155, 0, 4156, 0, 4157, 0, 4158, 0, 4159, 0, 4160, 0, 4161, 0, 4162, 0, 4163, 0, 4164, 0, 4165, 0, 4166, 0, 4167, 0, 4168, 0, 4169, 0, 4170, 0, 4171, 0, 4172, 0, 4173, 0, 4174, 0, 4175, 0, 4176, 0, 4177, 0, 4178, 0, 4179, 0, 4180, 0, 4181, 0, 4182, 0, 4183, 0, 4184, 0, 4185, 0, 4186, 0, 4187, 0, 4188, 0, 4189, 0, 4190, 0, 4191, 0, 4192, 0, 4193, 0, 4194, 0, 4195, 0, 4196, 0, 4197, 0, 4198, 0, 4199, 0, 4200, 0, 4201, 0, 4202, 0, 4203, 0, 4204, 0, 4205, 0, 4206, 0, 4207, 0, 4208, 0, 4209, 0, 4210, 0, 4211, 0, 4212, 0, 4213, 0, 4214, 0, 4215, 0, 4216, 0, 4217, 0, 4218, 0, 4219, 0, 4220, 0, 4221, 0, 4222, 0, 4223, 0, 4224, 0, 4225, 0, 4226, 0, 4227, 0, 4228, 0, 4229, 0, 4230, 0, 4231, 0, 4232, 0, 4233, 0, 4234, 0, 4235, 0, 4236, 0, 4237, 0, 4238, 0, 4239, 0, 4240, 0, 4241, 0, 4242, 0, 4243, 0, 4244, 0, 4245, 0, 4246, 0, 4247, 0, 4248, 0, 4249, 0, 4250, 0, 4251, 0, 4252, 0, 4253, 0, 4254, 0, 4255, 0, 4256, 0, 4257, 0, 4258, 0, 4259, 0, 4260, 0, 4261, 0, 4262, 0, 4263, 0, 4264, 0, 4265, 0, 4266, 0, 4267, 0, 4268, 0, 4269, 0, 4270, 0, 4271, 0, 4272, 0, 4273, 0, 4274, 0, 4275, 0, 4276, 0, 4277, 0, 4278, 0, 4279, 0, 4280, 0, 4281, 0, 4282, 0, 4283, 0, 4284, 0, 4285, 0, 4286, 0, 4287, 0, 4288, 0, 4289, 0, 4290, 0, 4291, 0, 4292, 0, 4293, 0, 4294, 0, 4295, 0, 4296, 0, 4297, 0, 4298, 0, 4299, 0, 4300, 0, 4301, 0, 4302, 0, 4303, 0, 4304, 0, 4305, 0, 4306, 0, 4307, 0, 4308, 0, 4309, 0, 4310, 0, 4311, 0, 4312, 0, 4313, 0, 4314, 0, 4315, 0, 4316, 0, 4317, 0, 4318, 0, 4319, 0, 4320, 0, 4321, 0, 4322, 0, 4323, 0, 4324, 0, 4325, 0, 4326, 0, 4327, 0, 4328, 0, 4329, 8935, 4330, 8935, 4332, 4335, 4337, 4338, 4340, 4341, 4342, 4343, 4344, 4345, 4346, 4347, 4348, 4349, 4350, 4351, 4352, 4353, 4354, 4355, 4356, 4357, 4358, 4359, 4360, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4372, 4373, 4374, 4375, 4376, 4377, 4378, 4379, 4380, 4381, 4382, 4383, 4384, 4385, 4386, 4387, 4388, 4389, 4390, 4391, 4392, 4393, 4394, 4395, 4396, 4397, 4398, 4399, 4400, 4401, 4402, 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, 4411, 4412, 4413, 4414, 4415, 4416, 4417, 4418, 4419, 4420, 4421, 4422, 4423, 4424, 4425, 4426, 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434, 4435, 4436, 4437, 4438, 4439, 4440, 4441, 4442, 4443, 4444, 4445, 4446, 4447, 4448, 4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469, 4470, 4471, 4472, 4473, 4474, 4475, 4476, 4477, 4478, 4479, 4480, 4481, 4482, 4483, 4484, 4485, 4486, 4487, 4488, 4489, 4490, 4491, 4492, 4493, 4494, 4495, 4496, 4497, 4498, 4499, 4500, 4501, 4502, 4503, 4504, 4505, 4506, 4507, 4508, 4509, 4510, 4511, 4512, 4513, 4514, 4515, 4516, 4517, 4518, 4519, 4520, 4521, 4522, 4523, 4524, 4525, 4526, 4527, 4528, 4529, 4530, 4531, 4532, 4533, 4534, 4535, 4536, 4537, 4538, 4539, 4540, 4541, 4542, 4543, 4544, 4545, 4546, 4547, 4548, 4549, 4550, 4551, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4559, 4560, 4561, 4562, 4563, 4564, 4565, 4566, 4567, 4568, 4569, 4570, 4571, 4572, 4573, 4574, 4575, 4576, 4577, 4578, 4579, 4580, 4581, 4582, 4583, 4584, 4585, 4586, 4587, 4588, 4589, 4590, 4591, 4592, 4593, 4594, 4595, 4596, 4597, 4598, 4599, 4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, 4608, 4609, 4610, 4611, 4612, 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, 4625, 4626, 4627, 4628, 4629, 4630, 4631, 4632, 4633, 4634, 4635, 4636, 4637, 4638, 4639, 4640, 4641, 4642, 4643, 4644, 4645, 4646, 4647, 4648, 4649, 4650, 4651, 4652, 4653, 4654, 4655, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4664, 4665, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4673, 4674, 4675, 4676, 4677, 4678, 4679, 4680, 4681, 4682, 4683, 4684, 4685, 4686, 4687, 4688, 4689, 4690, 4691, 4692, 4693, 4694, 4695, 4696, 4697, 4698, 4699, 4700, 4701, 4702, 4703, 4704, 4705, 4706, 4707, 4708, 4709, 4710, 4711, 4712, 4713, 4714, 4715, 4716, 4717, 4718, 4719, 4720, 4721, 4722, 4723, 4724, 4725, 4726, 4727, 4728, 4729, 4730, 4731, 4732, 4733, 4734, 4735, 4736, 4737, 4738, 4739, 4740, 4741, 4742, 4743, 4744, 4745, 4746, 4747, 4748, 4749, 4750, 4751, 4752, 4753, 4754, 4755, 4756, 4757, 4758, 4759, 4760, 4761, 4762, 4763, 4764, 4765, 4766, 4767, 4768, 4769, 4770, 4771, 4772, 4773, 4774, 4775, 4776, 4777, 4778, 4779, 4780, 4781, 4782, 4783, 4784, 4785, 4786, 4787, 4788, 4789, 4790, 4791, 4792, 4793, 4794, 4795, 4796, 4797, 4798, 4799, 4800, 4801, 4802, 4803, 4804, 4805, 4806, 4807, 4808, 4809, 4810, 4811, 4812, 4813, 4814, 4815, 4816, 4817, 4818, 4819, 4820, 4821, 4822, 4823, 4824, 4825, 4826, 4827, 4828, 4829, 4830, 4831, 4832, 4833, 4834, 4835, 4836, 4837, 4838, 4839, 4840, 4841, 4842, 4843, 4844, 4845, 4846, 4847, 4848, 4849, 4850, 4851, 4852, 4853, 4854, 4855, 4856, 4857, 4858, 4859, 4860, 4861, 4862, 4863, 4864, 4865, 4866, 4867, 4868, 4869, 4870, 4871, 4872, 4873, 4874, 4875, 4876, 4877, 4878, 4879, 4880, 4881, 4882, 4883, 4884, 4885, 4886, 4887, 4888, 4889, 4890, 4891, 4892, 4893, 4894, 4895, 4896, 4897, 4898, 4899, 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, 4920, 4921, 4922, 4923, 4924, 4925, 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, 4940, 4941, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949, 4950, 4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959, 4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, 4984, 4985, 4986, 4987, 4988, 4989, 4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, 5000, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072, 5073, 5074, 5075, 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108, 5109, 5110, 5111, 5112, 5113, 5114, 5115, 5116, 5117, 5118, 5119, 5120, 5121, 5122, 5123, 5124, 5125, 5126, 5127, 5128, 5129, 5130, 5131, 5132, 5133, 5134, 5135, 5136, 5137, 5138, 5139, 5140, 5141, 5142, 5143, 5144, 5145, 5146, 5147, 5148, 5149, 5150, 5151, 5152, 5153, 5154, 5155, 5156, 5157, 5158, 5159, 5160, 5161, 5162, 5163, 5164, 5165, 5166, 5167, 5168, 5169, 5170, 5171, 5172, 5173, 5174, 5175, 5176, 5177, 5178, 5179, 5180, 5181, 5182, 5183, 5184, 5185, 5186, 5187, 5188, 5189, 5190, 5191, 5192, 5193, 5194, 5195, 5196, 5197, 5198, 5199, 5200, 5201, 5202, 5203, 5204, 5205, 5206, 5207, 5208, 5209, 5210, 5211, 5212, 5213, 5214, 5215, 5216, 5217, 5218, 5219, 5220, 5221, 5222, 5223, 5224, 5225, 5226, 5227, 5228, 5229, 5230, 5231, 5232, 5233, 5234, 5235, 5236, 5237, 5238, 5239, 5240, 5241, 5242, 5243, 5244, 5245, 5246, 5247, 5248, 5249, 5250, 5251, 5252, 5253, 5254, 5255, 5256, 5257, 5258, 5259, 5260, 5261, 5262, 5263, 5264, 5265, 5266, 5267, 5268, 5269, 5270, 5271, 5272, 5273, 5274, 5275, 5276, 5277, 5278, 5279, 5280, 5281, 5282, 5283, 5284, 5285, 5286, 5287, 5288, 5289, 5290, 5291, 5292, 5293, 5294, 5295, 5296, 5297, 5298, 5299, 5300, 5301, 5302, 5303, 5304, 5305, 5306, 5307, 5308, 5309, 5310, 5311, 5312, 5313, 5314, 5315, 5316, 5317, 5318, 5319, 5320, 5321, 5322, 5323, 5324, 5325, 5326, 5327, 5328, 5329, 5330, 5331, 5332, 5333, 5334, 5335, 5336, 5337, 5338, 5339, 5340, 5341, 5342, 5343, 5344, 5345, 5346, 5347, 5348, 5349, 5350, 5351, 5352, 5353, 5354, 5355, 5356, 5357, 5358, 5359, 5360, 5361, 5362, 5363, 5364, 5365, 5366, 5367, 5368, 5369, 5370, 5371, 5372, 5373, 5374, 5375, 5376, 5377, 5378, 5379, 5380, 5381, 5382, 5383, 5384, 5385, 5386, 5387, 5388, 5389, 5390, 5391, 5392, 5393, 5394, 5395, 5396, 5397, 5398, 5399, 5400, 5401, 5402, 5403, 5404, 5405, 5406, 5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5421, 5422, 5423, 5424, 5425, 5426, 5427, 5428, 5429, 5430, 5431, 5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5442, 5443, 5444, 5445, 5446, 5447, 5448, 5449, 5450, 5451, 5452, 5453, 5454, 5455, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, 5465, 5466, 5467, 5468, 5469, 5470, 5471, 5472, 5473, 5474, 5475, 5476, 5477, 5478, 5479, 5480, 5481, 5482, 5483, 5484, 5485, 5486, 5487, 5488, 5489, 5490, 5491, 5492, 5493, 5494, 5495, 5496, 5497, 5498, 5499, 5500, 5501, 5502, 5503, 5504, 5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, 5515, 5516, 5517, 5518, 5519, 5520, 5521, 5522, 5523, 5524, 5525, 5526, 5527, 5528, 5529, 5530, 5531, 5532, 5533, 5534, 5535, 5536, 5537, 5538, 5539, 5540, 5541, 5542, 5543, 5544, 5545, 5546, 5547, 5548, 5549, 5550, 5551, 5552, 5553, 5554, 5555, 5556, 5557, 5558, 5559, 5560, 5561, 5562, 5563, 5564, 5565, 5566, 5567, 5568, 5569, 5570, 5571, 5572, 5573, 5574, 5575, 5576, 5577, 5578, 5579, 5580, 5581, 5582, 5583, 5584, 5585, 5586, 5587, 5588, 5589, 5590, 5591, 5592, 5593, 5594, 5595, 5596, 5597, 5598, 5599, 5600, 5601, 5602, 5603, 5604, 5605, 5606, 5607, 5608, 5609, 5610, 5611, 5612, 5613, 5614, 5615, 5616, 5617, 5618, 5619, 5620, 5621, 5622, 5623, 5624, 5625, 5626, 5627, 5628, 5629, 5630, 5631, 5632, 5633, 5634, 5635, 5636, 5637, 5638, 5639, 5640, 5641, 5642, 5643, 5644, 5645, 5646, 5647, 5648, 5649, 5650, 5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, 5659, 5660, 5661, 5662, 5663, 5664, 5665, 5666, 5667, 5668, 5669, 5670, 5671, 5672, 5673, 5674, 5675, 5676, 5677, 5678, 5679, 5680, 5681, 5682, 5683, 5684, 5685, 5686, 5687, 5688, 5689, 5690, 5691, 5692, 5693, 5694, 5695, 5696, 5697, 5698, 5699, 5700, 5701, 5702, 5703, 5704, 5705, 5706, 5707, 5708, 5709, 5710, 5711, 5712, 5713, 5714, 5715, 5716, 5717, 5718, 5719, 5720, 5721, 5722, 5723, 5724, 5725, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734, 5735, 5736, 5737, 5738, 5739, 5740, 5741, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749, 5750, 5751, 5752, 5753, 5754, 5755, 5756, 5757, 5758, 5759, 5760, 5761, 5762, 5763, 5764, 5765, 5766, 5767, 5768, 5769, 5770, 5771, 5772, 5773, 5774, 5775, 5776, 5777, 5778, 5779, 5780, 5781, 5782, 5783, 5784, 5785, 5786, 5787, 5788, 5789, 5790, 5791, 5792, 5793, 5794, 5795, 5796, 5797, 5798, 5799, 5800, 5801, 5802, 5803, 5804, 5805, 5806, 5807, 5808, 5809, 5810, 5811, 5812, 5813, 5814, 5815, 5816, 5817, 5818, 5819, 5820, 5821, 5822, 5823, 5824, 5825, 5826, 5827, 5828, 5829, 5830, 5831, 5832, 5833, 5834, 5835, 5836, 5837, 5838, 5839, 5840, 5841, 5842, 5843, 5844, 5845, 5846, 5847, 5848, 5849, 5850, 5851, 5852, 5853, 5854, 5855, 5856, 5857, 5858, 5859, 5860, 5861, 5862, 5863, 5864, 5865, 5866, 5867, 5868, 5869, 5870, 5871, 5872, 5873, 5874, 5875, 5876, 5877, 5878, 5879, 5880, 5881, 5882, 5883, 5884, 5885, 5886, 5887, 5888, 5889, 5890, 5891, 5892, 5893, 5894, 5895, 5896, 5897, 5898, 5899, 5900, 5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909, 5910, 5911, 5912, 5913, 5914, 5915, 5916, 5917, 5918, 5919, 5920, 5921, 5922, 5923, 5924, 5925, 5926, 5927, 5928, 5929, 5930, 5931, 5932, 5933, 5934, 5935, 5936, 5937, 5938, 5939, 5940, 5941, 5942, 5943, 5944, 5945, 5946, 5947, 5948, 5949, 5950, 5951, 5952, 5953, 5954, 5955, 5956, 5957, 5958, 5959, 5960, 5961, 5962, 5963, 5964, 5965, 5966, 5967, 5968, 5969, 5970, 5971, 5972, 5973, 5974, 5975, 5976, 5977, 5978, 5979, 5980, 5981, 5982, 5983, 5984, 5985, 5986, 5987, 5988, 5989, 5990, 5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999, 6000, 6001, 6002, 6003, 6004, 6005, 6006, 6007, 6008, 6009, 6010, 6011, 6012, 6013, 6014, 6015, 6016, 6017, 6018, 6019, 6020, 6021, 6022, 6023, 6024, 6025, 6026, 6027, 6028, 6029, 6030, 6031, 6032, 6033, 6034, 6035, 6036, 6037, 6038, 6039, 6040, 6041, 6042, 6043, 6044, 6045, 6046, 6047, 6048, 6049, 6050, 6051, 6052, 6053, 6054, 6055, 6056, 6057, 6058, 6059, 6060, 6061, 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069, 6070, 6071, 6072, 6073, 6074, 6075, 6076, 6077, 6078, 6079, 6080, 6081, 6082, 6083, 6084, 6085, 6086, 6087, 6088, 6089, 6090, 6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, 6099, 6100, 6101, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 6109, 6110, 6111, 6112, 6113, 6114, 6115, 6116, 6117, 6118, 6119, 6120, 6121, 6122, 6123, 6124, 6125, 6126, 6127, 6128, 6129, 6130, 6131, 6132, 6133, 6134, 6135, 6136, 6137, 6138, 6139, 6140, 6141, 6142, 6143, 6144, 6145, 6146, 6147, 6148, 6149, 6150, 6151, 6152, 6153, 6154, 6155, 6156, 6157, 6158, 6159, 6160, 6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, 6169, 6170, 6171, 6172, 6173, 6174, 6175, 6176, 6177, 6178, 6179, 6180, 6181, 6182, 6183, 6184, 6185, 6186, 6187, 6188, 6189, 6190, 6191, 6192, 6193, 6194, 6195, 6196, 6197, 6198, 6199, 6200, 6201, 6202, 6203, 6204, 6205, 6206, 6207, 6208, 6209, 6210, 6211, 6212, 6213, 6214, 6215, 6216, 6217, 6218, 6219, 6220, 6221, 6222, 6223, 6224, 6225, 6226, 6227, 6228, 6229, 6230, 6231, 6232, 6233, 6234, 6235, 6236, 6237, 6238, 6239, 6240, 6241, 6242, 6243, 6244, 6245, 6246, 6247, 6248, 6249, 6250, 6251, 6252, 6253, 6254, 6255, 6256, 6257, 6258, 6259, 6260, 6261, 6262, 6263, 6264, 6265, 6266, 6267, 6268, 6269, 6270, 6271, 6272, 6273, 6274, 6275, 6276, 6277, 6278, 6279, 6280, 6281, 6282, 6283, 6284, 6285, 6286, 6287, 6288, 6289, 6290, 6291, 6292, 6293, 6294, 6295, 6296, 6297, 6298, 6299, 6300, 6301, 6302, 6303, 6304, 6305, 6306, 6307, 6308, 6309, 6310, 6311, 6312, 6313, 6314, 6315, 6316, 6317, 6318, 6319, 6320, 6321, 6322, 6323, 6324, 6325, 6326, 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, 6335, 6336, 6337, 6338, 6339, 6340, 6341, 6342, 6343, 6344, 6345, 6346, 6347, 6348, 6349, 6350, 6351, 6352, 6353, 6354, 6355, 6356, 6357, 6358, 6359, 6360, 6361, 6362, 6363, 6364, 6365, 6366, 6367, 6368, 6369, 6370, 6371, 6372, 6373, 6374, 6375, 6376, 6377, 6378, 6379, 6380, 6381, 6382, 6383, 6384, 6385, 6386, 6387, 6388, 6389, 6390, 6391, 6392, 6393, 6394, 6395, 6396, 6397, 6398, 6399, 6400, 6401, 6402, 6403, 6404, 6405, 6406, 6407, 6408, 6409, 6410, 6411, 6412, 6413, 6414, 6415, 6416, 6417, 6418, 6419, 6420, 6421, 6422, 6423, 6424, 6425, 6426, 6427, 6428, 6429, 6430, 6431, 6432, 6433, 6434, 6435, 6436, 6437, 6438, 6439, 6440, 6441, 6442, 6443, 6444, 6445, 6446, 6447, 6448, 6449, 6450, 6451, 6452, 6453, 6454, 6455, 6456, 6457, 6458, 6459, 6460, 6461, 6462, 6463, 6464, 6465, 6466, 6467, 6468, 6469, 6470, 6471, 6472, 6473, 6474, 6475, 6476, 6477, 6478, 6479, 6480, 6481, 6482, 6483, 6484, 6485, 6486, 6487, 6488, 6489, 6490, 6491, 6492, 6493, 6494, 6495, 6496, 6497, 6498, 6499, 6500, 6501, 6502, 6503, 6504, 6505, 6506, 6507, 6508, 6509, 6510, 6511, 6512, 6513, 6514, 6515, 6516, 6517, 6518, 6519, 6520, 6521, 6522, 6523, 6524, 6525, 6526, 6527, 6528, 6529, 6530, 6531, 6532, 6533, 6534, 6535, 6536, 6537, 6538, 6539, 6540, 6541, 6542, 6543, 6544, 6545, 6546, 6547, 6548, 6549, 6550, 6551, 6552, 6553, 6554, 6555, 6556, 6557, 6558, 6559, 6560, 6561, 6562, 6563, 6564, 6565, 6566, 6567, 6568, 6569, 6570, 6571, 6572, 6573, 6574, 6575, 6576, 6577, 6578, 6579, 6580, 6581, 6582, 6583, 6584, 6585, 6586, 6587, 6588, 6589, 6590, 6591, 6592, 6593, 6594, 6595, 6596, 6597, 6598, 6599, 6600, 6601, 6602, 6603, 6604, 6605, 6606, 6607, 6608, 6609, 6610, 6611, 6612, 6613, 6614, 6615, 6616, 6617, 6618, 6619, 6620, 6621, 6622, 6623, 6624, 6625, 6626, 6627, 6628, 6629, 6630, 6631, 6632, 6633, 6634, 6635, 6636, 6637, 6638, 6639, 6640, 6641, 6642, 6643, 6644, 6645, 6646, 6647, 6648, 6649, 6650, 6651, 6652, 6653, 6654, 6655, 6656, 6657, 6658, 6659, 6660, 6661, 6662, 6663, 6664, 6665, 6666, 6667, 6668, 6669, 6670, 6671, 6672, 6673, 6674, 6675, 6676, 6677, 6678, 6679, 6680, 6681, 6682, 6683, 6684, 6685, 6686, 6687, 6688, 6689, 6690, 6691, 6692, 6693, 6694, 6695, 6696, 6697, 6698, 6699, 6700, 6701, 6702, 6703, 6704, 6705, 6706, 6707, 6708, 6709, 6710, 6711, 6712, 6713, 6714, 6715, 6716, 6717, 6718, 6719, 6720, 6721, 6722, 6723, 6724, 6725, 6726, 6727, 6728, 6729, 6730, 6731, 6732, 6733, 6734, 6735, 6736, 6737, 6738, 6739, 6740, 6741, 6742, 6743, 6744, 6745, 6746, 6747, 6748, 6749, 6750, 6751, 6752, 6753, 6754, 6755, 6756, 6757, 6758, 6759, 6760, 6761, 6762, 6763, 6764, 6765, 6766, 6767, 6768, 6769, 6770, 6771, 6772, 6773, 6774, 6775, 6776, 6777, 6778, 6779, 6780, 6781, 6782, 6783, 6784, 6785, 6786, 6787, 6788, 6789, 6790, 6791, 6792, 6793, 6794, 6795, 6796, 6797, 6798, 6799, 6800, 6801, 6802, 6803, 6804, 6805, 6806, 6807, 6808, 6809, 6810, 6811, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819, 6820, 6821, 6822, 6823, 6824, 6825, 6826, 6827, 6828, 6829, 6830, 6831, 6832, 6833, 6834, 6835, 6836, 6837, 6838, 6839, 6840, 6841, 6842, 6843, 6844, 6845, 6846, 6847, 6848, 6849, 6850, 6851, 6852, 6853, 6854, 6855, 6856, 6857, 6858, 6859, 6860, 6861, 6862, 6863, 6864, 6865, 6866, 6867, 6868, 6869, 6870, 6871, 6872, 6873, 6874, 6875, 6876, 6877, 6878, 6879, 6880, 6881, 6882, 6883, 6884, 6885, 6886, 6887, 6888, 6889, 6890, 6891, 6892, 6893, 6894, 6895, 6896, 6897, 6898, 6899, 6900, 6901, 6902, 6903, 6904, 6905, 6906, 6907, 6908, 6909, 6910, 6911, 6912, 6913, 6914, 6915, 6916, 6917, 6918, 6919, 6920, 6921, 6922, 6923, 6924, 6925, 6926, 6927, 6928, 6929, 6930, 6931, 6932, 6933, 6934, 6935, 6936, 6937, 6938, 6939, 6940, 6941, 6942, 6943, 6944, 6945, 6946, 6947, 6948, 6949, 6950, 6951, 6952, 6953, 6954, 6955, 6956, 6957, 6958, 6959, 6960, 6961, 6962, 6963, 6964, 6965, 6966, 6967, 6968, 6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978, 6979, 6980, 6981, 6982, 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, 6993, 6994, 6995, 6996, 6997, 6998, 6999, 7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, 7041, 7042, 7043, 7044, 7045, 7046, 7047, 7048, 7049, 7050, 7051, 7052, 7053, 7054, 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063, 7064, 7065, 7066, 7067, 7068, 7069, 7070, 7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, 7079, 7080, 7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, 7089, 7090, 7091, 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099, 7100, 7101, 7102, 7103, 7104, 7105, 7106, 7107, 7108, 7109, 7110, 7111, 7112, 7113, 7114, 7115, 7116, 7117, 7118, 7119, 7120, 7121, 7122, 7123, 7124, 7125, 7126, 7127, 7128, 7129, 7130, 7131, 7132, 7133, 7134, 7135, 7136, 7137, 7138, 7139, 7140, 7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, 7149, 7150, 7151, 7152, 7153, 7154, 7155, 7156, 7157, 7158, 7159, 7160, 7161, 7162, 7163, 7164, 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, 7173, 7174, 7175, 7176, 7177, 7178, 7179, 7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, 7188, 7189, 7190, 7191, 7192, 7193, 7194, 7195, 7196, 7197, 7198, 7199, 7200, 7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, 7209, 7210, 7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, 7220, 7221, 7222, 7223, 7224, 7225, 7226, 7227, 7228, 7229, 7230, 7231, 7232, 7233, 7234, 7235, 7236, 7237, 7238, 7239, 7240, 7241, 7242, 7243, 7244, 7245, 7246, 7247, 7248, 7249, 7250, 7251, 7252, 7253, 7254, 7255, 7256, 7257, 7258, 7259, 7260, 7261, 7262, 7263, 7264, 7265, 7266, 7267, 7268, 7269, 7270, 7271, 7272, 7273, 7274, 7275, 7276, 7277, 7278, 7279, 7280, 7281, 7282, 7283, 7284, 7285, 7286, 7287, 7288, 7289, 7290, 7291, 7292, 7293, 7294, 7295, 7296, 7297, 7298, 7299, 7300, 7301, 7302, 7303, 7304, 7305, 7306, 7307, 7308, 7309, 7310, 7311, 7312, 7313, 7314, 7315, 7316, 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327, 7328, 7329, 7330, 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, 7355, 7356, 7357, 7358, 7359, 7360, 7361, 7362, 7363, 7364, 7365, 7366, 7367, 7368, 7369, 7370, 7371, 7372, 7373, 7374, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7385, 7386, 7387, 7388, 7389, 7390, 7391, 7392, 7393, 7394, 7395, 7396, 7397, 7398, 7399, 7400, 7401, 7402, 7403, 7404, 7405, 7406, 7407, 7408, 7409, 7410, 7411, 7412, 7413, 7414, 7415, 7416, 7417, 7418, 7419, 7420, 7421, 7422, 7423, 7424, 7425, 7426, 7427, 7428, 7429, 7430, 7431, 7432, 7433, 7434, 7435, 7436, 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7446, 7447, 7448, 7449, 7450, 7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7461, 7462, 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, 7471, 7472, 7473, 7474, 7475, 7476, 7477, 7478, 7479, 7480, 7481, 7482, 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494, 7495, 7496, 7497, 7498, 7499, 7500, 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509, 7510, 7511, 7512, 7513, 7514, 7515, 7516, 7517, 7518, 7519, 7520, 7521, 7522, 7523, 7524, 7525, 7526, 7527, 7528, 7529, 7530, 7531, 7532, 7533, 7534, 7535, 7536, 7537, 7538, 7539, 7540, 7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, 7549, 7550, 7551, 7552, 7553, 7554, 7555, 7556, 7557, 7558, 7559, 7560, 7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 7569, 7570, 7571, 7572, 7573, 7574, 7575, 7576, 7577, 7578, 7579, 7580, 7581, 7582, 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, 7593, 7594, 7595, 7596, 7597, 7598, 7599, 7600, 7601, 7602, 7603, 7604, 7605, 7606, 7607, 7608, 7609, 7610, 7611, 7612, 7613, 7614, 7615, 7616, 7617, 7618, 7619, 7620, 7621, 7622, 7623, 7624, 7625, 7626, 7627, 7628, 7629, 7630, 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, 7641, 7642, 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, 7651, 7652, 7653, 7654, 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7665, 7666, 7667, 7668, 7669, 7670, 7671, 7672, 7673, 7674, 7675, 7676, 7677, 7678, 7679, 7680, 7681, 7682, 7683, 7684, 7685, 7686, 7687, 7688, 7689, 7690, 7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699, 7700, 7701, 7702, 7703, 7704, 7705, 7706, 7707, 7708, 7709, 7710, 7711, 7712, 7713, 7714, 7715, 7716, 7717, 7718, 7719, 7720, 7721, 7722, 7723, 7724, 7725, 7726, 7727, 7728, 7729, 7730, 7731, 7732, 7733, 7734, 7735, 7736, 7737, 7738, 7739, 7740, 7741, 7742, 7743, 7744, 7745, 7746, 7747, 7748, 7749, 7750, 7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, 7760, 7761, 7762, 7763, 7764, 7765, 7766, 7767, 7768, 7769, 7770, 7771, 7772, 7773, 7774, 7775, 7776, 7777, 7778, 7779, 7780, 7781, 7782, 7783, 7784, 7785, 7786, 7787, 7788, 7789, 7790, 7791, 7792, 7793, 7794, 7795, 7796, 7797, 7798, 7799, 7800, 7801, 7802, 7803, 7804, 7805, 7806, 7807, 7808, 7809, 7810, 7811, 7812, 7813, 7814, 7815, 7816, 7817, 7818, 7819, 7820, 7821, 7822, 7823, 7824, 7825, 7826, 7827, 7828, 7829, 7830, 7831, 7832, 7833, 7834, 7835, 7836, 7837, 7838, 7839, 7840, 7841, 7842, 7843, 7844, 7845, 7846, 7847, 7848, 7849, 7850, 7851, 7852, 7853, 7854, 7855, 7856, 7857, 7858, 7859, 7860, 7861, 7862, 7863, 7864, 7865, 7866, 7867, 7868, 7869, 7870, 7871, 7872, 7873, 7874, 7875, 7876, 7877, 7878, 7879, 7880, 7881, 7882, 7883, 7884, 7885, 7886, 7887, 7888, 7889, 7890, 7891, 7892, 7893, 7894, 7895, 7896, 7897, 7898, 7899, 7900, 7901, 7902, 7903, 7904, 7905, 7906, 7907, 7908, 7909, 7910, 7911, 7912, 7913, 7914, 7915, 7916, 7917, 7918, 7919, 7920, 7921, 7922, 7923, 7924, 7925, 7926, 7927, 7928, 7929, 7930, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951, 7952, 7953, 7954, 7955, 7956, 7957, 7958, 7959, 7960, 7961, 7962, 7963, 7964, 7965, 7966, 7967, 7968, 7969, 7970, 7971, 7972, 7973, 7974, 7975, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 7984, 7985, 7986, 7987, 7988, 7989, 7990, 7991, 7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999, 8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007, 8008, 8009, 8010, 8011, 8012, 8013, 8014, 8015, 8016, 8017, 8018, 8019, 8020, 8021, 8022, 8023, 8024, 8025, 8026, 8027, 8028, 8029, 8030, 8031, 8032, 8033, 8034, 8035, 8036, 8037, 8038, 8039, 8040, 8041, 8042, 8043, 8044, 8045, 8046, 8047, 8048, 8049, 8050, 8051, 8052, 8053, 8054, 8055, 8056, 8057, 8058, 8059, 8060, 8061, 8062, 8063, 8064, 8065, 8066, 8067, 8068, 8069, 8070, 8071, 8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079, 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095, 8096, 8097, 8098, 8099, 8100, 8101, 8102, 8103, 8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111, 8112, 8113, 8114, 8115, 8116, 8117, 8118, 8119, 8120, 8121, 8122, 8123, 8124, 8125, 8126, 8127, 8128, 8129, 8130, 8131, 8132, 8133, 8134, 8135, 8136, 8137, 8138, 8139, 8140, 8141, 8142, 8143, 8144, 8145, 8146, 8147, 8148, 8149, 8150, 8151, 8152, 8153, 8154, 8155, 8156, 8157, 8158, 8159, 8160, 8161, 8162, 8163, 8164, 8165, 8166, 8167, 8168, 8169, 8170, 8171, 8172, 8173, 8174, 8175, 8176, 8177, 8178, 8179, 8180, 8181, 8182, 8183, 8184, 8185, 8186, 8187, 8188, 8189, 8190, 8191, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8203, 8204, 8205, 8206, 8207, 8208, 8209, 8210, 8211, 8212, 8213, 8214, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8223, 8224, 8225, 8226, 8227, 8228, 8229, 8230, 8231, 8232, 8233, 8234, 8235, 8236, 8237, 8238, 8239, 8240, 8241, 8242, 8243, 8244, 8245, 8246, 8247, 8248, 8249, 8250, 8251, 8252, 8253, 8254, 8255, 8256, 8257, 8258, 8259, 8260, 8261, 8262, 8263, 8264, 8265, 8266, 8267, 8268, 8269, 8270, 8271, 8272, 8273, 8274, 8275, 8276, 8277, 8278, 8279, 8280, 8281, 8282, 8283, 8284, 8285, 8286, 8287, 8288, 8289, 8290, 8291, 8292, 8293, 8294, 8295, 8296, 8297, 8298, 8299, 8300, 8301, 8302, 8303, 8304, 8305, 8306, 8307, 8308, 8309, 8310, 8311, 8312, 8313, 8314, 8315, 8316, 8317, 8318, 8319, 8320, 8321, 8322, 8323, 8324, 8325, 8326, 8327, 8328, 8329, 8330, 8331, 8332, 8333, 8334, 8335, 8336, 8337, 8338, 8339, 8340, 8341, 8342, 8343, 8344, 8345, 8346, 8347, 8348, 8349, 8350, 8351, 8352, 8353, 8354, 8355, 8356, 8357, 8358, 8359, 8360, 8361, 8362, 8363, 8364, 8365, 8366, 8367, 8368, 8369, 8370, 8371, 8372, 8373, 8374, 8375, 8376, 8377, 8378, 8379, 8380, 8381, 8382, 8383, 8384, 8385, 8386, 8387, 8388, 8389, 8390, 8391, 8392, 8393, 8394, 8395, 8396, 8397, 8398, 8399, 8400, 8401, 8402, 8403, 8404, 8405, 8406, 8407, 8408, 8409, 8410, 8411, 8412, 8413, 8414, 8415, 8416, 8417, 8418, 8419, 8420, 8421, 8422, 8423, 8424, 8425, 8426, 8427, 8428, 8429, 8430, 8431, 8432, 8433 } ; static yyconst flex_int16_t yy_def[12713] = { 0, 8615, 8615, 8616, 8616, 8616, 8616, 8614, 8614, 8617, 8614, 8614, 8617, 8617, 8617, 8614, 8614, 8618, 8618, 8614, 8618, 8618, 8619, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8620, 8620, 8620, 8620, 8619, 8619, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8621, 8621, 8621, 8621, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8622, 8622, 8622, 8622, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8623, 8623, 8623, 8623, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8624, 8624, 8624, 8624, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8625, 8625, 8625, 8625, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8626, 8626, 8626, 8626, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8627, 8627, 8627, 8627, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8628, 8628, 8628, 8628, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8629, 8629, 8629, 8629, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8630, 8630, 8630, 8630, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8631, 8631, 8631, 8631, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8632, 8632, 8632, 8632, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8633, 8633, 8633, 8633, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8634, 8634, 8634, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8635, 8635, 8614, 8614, 8614, 8614, 8614, 8614, 8636, 8636, 8614, 8614, 8637, 8637, 8638, 8638, 8639, 8639, 8640, 8640, 8641, 8641, 8642, 8642, 8643, 8643, 8644, 8644, 8645, 8645, 8646, 8646, 8647, 8647, 8648, 8648, 8649, 8649, 8650, 8650, 8651, 8651, 8652, 8652, 8653, 8653, 8654, 8654, 8655, 8655, 8656, 8656, 8657, 8657, 8658, 8658, 8659, 8659, 8660, 8660, 8661, 8661, 8662, 8662, 8663, 8663, 8664, 8664, 8665, 8665, 8666, 8666, 8667, 8667, 8668, 8668, 8669, 8669, 8670, 8670, 8671, 8671, 8672, 8672, 8673, 8673, 8674, 8674, 8675, 8675, 8676, 8676, 8677, 8677, 8678, 8678, 8679, 8679, 8680, 8680, 8681, 8681, 8682, 8682, 8683, 8683, 8684, 8684, 8685, 8685, 8686, 8686, 8687, 8687, 8688, 8688, 8689, 8689, 8690, 8690, 8691, 8691, 8692, 8692, 8693, 8693, 8694, 8694, 8695, 8695, 8696, 8696, 8697, 8697, 8698, 8698, 8699, 8699, 8700, 8700, 8701, 8701, 8702, 8702, 8703, 8703, 8704, 8704, 8705, 8705, 8706, 8706, 8707, 8707, 8708, 8708, 8709, 8709, 8710, 8710, 8711, 8711, 8712, 8712, 8713, 8713, 8714, 8714, 8715, 8715, 8716, 8716, 8717, 8717, 8718, 8718, 8719, 8719, 8720, 8720, 8721, 8721, 8722, 8722, 8723, 8723, 8724, 8724, 8725, 8725, 8726, 8726, 8727, 8727, 8728, 8728, 8729, 8729, 8730, 8730, 8731, 8731, 8732, 8732, 8733, 8733, 8734, 8734, 8735, 8735, 8736, 8736, 8737, 8737, 8738, 8738, 8739, 8739, 8740, 8740, 8741, 8741, 8742, 8742, 8743, 8743, 8744, 8744, 8745, 8745, 8746, 8746, 8747, 8747, 8748, 8748, 8749, 8749, 8750, 8750, 8751, 8751, 8752, 8752, 8753, 8753, 8754, 8754, 8755, 8755, 8756, 8756, 8757, 8757, 8758, 8758, 8759, 8759, 8760, 8760, 8761, 8761, 8762, 8762, 8763, 8763, 8764, 8764, 8765, 8765, 8766, 8766, 8767, 8767, 8768, 8768, 8769, 8769, 8770, 8770, 8771, 8771, 8772, 8772, 8773, 8773, 8774, 8774, 8775, 8775, 8776, 8776, 8777, 8777, 8778, 8778, 8779, 8779, 8780, 8780, 8781, 8781, 8782, 8782, 8783, 8783, 8784, 8784, 8785, 8785, 8786, 8786, 8787, 8787, 8788, 8788, 8789, 8789, 8790, 8790, 8791, 8791, 8792, 8792, 8793, 8793, 8794, 8794, 8795, 8795, 8796, 8796, 8797, 8797, 8798, 8798, 8799, 8799, 8800, 8800, 8801, 8801, 8802, 8802, 8803, 8803, 8804, 8804, 8805, 8805, 8806, 8806, 8807, 8807, 8808, 8808, 8809, 8809, 8810, 8810, 8811, 8811, 8812, 8812, 8813, 8813, 8814, 8814, 8815, 8815, 8816, 8816, 8817, 8817, 8818, 8818, 8819, 8819, 8820, 8820, 8821, 8821, 8822, 8822, 8823, 8823, 8824, 8824, 8825, 8825, 8826, 8826, 8827, 8827, 8828, 8828, 8829, 8829, 8830, 8830, 8831, 8831, 8832, 8832, 8833, 8833, 8834, 8834, 8835, 8835, 8836, 8836, 8837, 8837, 8838, 8838, 8839, 8839, 8840, 8840, 8841, 8841, 8842, 8842, 8843, 8843, 8844, 8844, 8845, 8845, 8846, 8846, 8847, 8847, 8848, 8848, 8849, 8849, 8850, 8850, 8851, 8851, 8852, 8852, 8853, 8853, 8854, 8854, 8855, 8855, 8856, 8856, 8857, 8857, 8858, 8858, 8859, 8859, 8860, 8860, 8861, 8861, 8862, 8862, 8863, 8863, 8864, 8864, 8865, 8865, 8866, 8866, 8867, 8867, 8868, 8868, 8869, 8869, 8870, 8870, 8871, 8871, 8872, 8872, 8873, 8873, 8874, 8874, 8875, 8875, 8876, 8876, 8877, 8877, 8878, 8878, 8879, 8879, 8880, 8880, 8881, 8881, 8882, 8882, 8883, 8883, 8884, 8884, 8885, 8885, 8886, 8886, 8887, 8887, 8888, 8888, 8889, 8889, 8890, 8890, 8891, 8891, 8892, 8892, 8893, 8893, 8894, 8894, 8895, 8895, 8896, 8896, 8897, 8897, 8898, 8898, 8899, 8899, 8900, 8900, 8901, 8901, 8902, 8902, 8903, 8903, 8904, 8904, 8905, 8905, 8906, 8906, 8907, 8907, 8908, 8908, 8909, 8909, 8910, 8910, 8911, 8911, 8912, 8912, 8913, 8913, 8914, 8914, 8915, 8915, 8916, 8916, 8917, 8917, 8918, 8918, 8919, 8919, 8920, 8920, 8921, 8921, 8922, 8922, 8923, 8923, 8924, 8924, 8925, 8925, 8926, 8926, 8927, 8927, 8928, 8928, 8929, 8929, 8930, 8930, 8931, 8931, 8932, 8932, 8933, 8933, 8934, 8934, 8935, 8935, 8936, 8936, 8937, 8937, 8938, 8938, 8939, 8939, 8940, 8940, 8941, 8941, 8942, 8942, 8943, 8943, 8944, 8944, 8945, 8945, 8946, 8946, 8947, 8947, 8948, 8948, 8949, 8949, 8950, 8950, 8951, 8951, 8952, 8952, 8953, 8953, 8954, 8954, 8955, 8955, 8956, 8956, 8957, 8957, 8958, 8958, 8959, 8959, 8960, 8960, 8961, 8961, 8962, 8962, 8963, 8963, 8964, 8964, 8965, 8965, 8966, 8966, 8967, 8967, 8968, 8968, 8969, 8969, 8970, 8970, 8971, 8971, 8972, 8972, 8973, 8973, 8974, 8974, 8975, 8975, 8976, 8976, 8977, 8977, 8978, 8978, 8979, 8979, 8980, 8980, 8981, 8981, 8982, 8982, 8983, 8983, 8984, 8984, 8985, 8985, 8986, 8986, 8987, 8987, 8988, 8988, 8989, 8989, 8990, 8990, 8991, 8991, 8992, 8992, 8993, 8993, 8994, 8994, 8995, 8995, 8996, 8996, 8997, 8997, 8998, 8998, 8999, 8999, 9000, 9000, 9001, 9001, 9002, 9002, 9003, 9003, 9004, 9004, 9005, 9005, 9006, 9006, 9007, 9007, 9008, 9008, 9009, 9009, 9010, 9010, 9011, 9011, 9012, 9012, 9013, 9013, 9014, 9014, 9015, 9015, 9016, 9016, 9017, 9017, 9018, 9018, 9019, 9019, 9020, 9020, 9021, 9021, 9022, 9022, 9023, 9023, 9024, 9024, 9025, 9025, 9026, 9026, 9027, 9027, 9028, 9028, 9029, 9029, 9030, 9030, 9031, 9031, 9032, 9032, 9033, 9033, 9034, 9034, 9035, 9035, 9036, 9036, 9037, 9037, 9038, 9038, 9039, 9039, 9040, 9040, 9041, 9041, 9042, 9042, 9043, 9043, 9044, 9044, 9045, 9045, 9046, 9046, 9047, 9047, 9048, 9048, 9049, 9049, 9050, 9050, 9051, 9051, 9052, 9052, 9053, 9053, 9054, 9054, 9055, 9055, 9056, 9056, 9057, 9057, 9058, 9058, 9059, 9059, 9060, 9060, 9061, 9061, 9062, 9062, 9063, 9063, 9064, 9064, 9065, 9065, 9066, 9066, 9067, 9067, 9068, 9068, 9069, 9069, 9070, 9070, 9071, 9071, 9072, 9072, 9073, 9073, 9074, 9074, 9075, 9075, 9076, 9076, 9077, 9077, 9078, 9078, 9079, 9079, 9080, 9080, 9081, 9081, 9082, 9082, 9083, 9083, 9084, 9084, 9085, 9085, 9086, 9086, 9087, 9087, 9088, 9088, 9089, 9089, 9090, 9090, 9091, 9091, 9092, 9092, 9093, 9093, 9094, 9094, 9095, 9095, 9096, 9096, 9097, 9097, 9098, 9098, 9099, 9099, 9100, 9100, 9101, 9101, 9102, 9102, 9103, 9103, 9104, 9104, 9105, 9105, 9106, 9106, 9107, 9107, 9108, 9108, 9109, 9109, 9110, 9110, 9111, 9111, 9112, 9112, 9113, 9113, 9114, 9114, 9115, 9115, 9116, 9116, 9117, 9117, 9118, 9118, 9119, 9119, 9120, 9120, 9121, 9121, 9122, 9122, 9123, 9123, 9124, 9124, 9125, 9125, 9126, 9126, 9127, 9127, 9128, 9128, 9129, 9129, 9130, 9130, 9131, 9131, 9132, 9132, 9133, 9133, 9134, 9134, 9135, 9135, 9136, 9136, 9137, 9137, 9138, 9138, 9139, 9139, 9140, 9140, 9141, 9141, 9142, 9142, 9143, 9143, 9144, 9144, 9145, 9145, 9146, 9146, 9147, 9147, 9148, 9148, 9149, 9149, 9150, 9150, 9151, 9151, 9152, 9152, 9153, 9153, 9154, 9154, 9155, 9155, 9156, 9156, 9157, 9157, 9158, 9158, 9159, 9159, 9160, 9160, 9161, 9161, 9162, 9162, 9163, 9163, 9164, 9164, 9165, 9165, 9166, 9166, 9167, 9167, 9168, 9168, 9169, 9169, 9170, 9170, 9171, 9171, 9172, 9172, 9173, 9173, 9174, 9174, 9175, 9175, 9176, 9176, 9177, 9177, 9178, 9178, 9179, 9179, 9180, 9180, 9181, 9181, 9182, 9182, 9183, 9183, 9184, 9184, 9185, 9185, 9186, 9186, 9187, 9187, 9188, 9188, 9189, 9189, 9190, 9190, 9191, 9191, 9192, 9192, 9193, 9193, 9194, 9194, 9195, 9195, 9196, 9196, 9197, 9197, 9198, 9198, 9199, 9199, 9200, 9200, 9201, 9201, 9202, 9202, 9203, 9203, 9204, 9204, 9205, 9205, 9206, 9206, 9207, 9207, 9208, 9208, 9209, 9209, 9210, 9210, 9211, 9211, 9212, 9212, 9213, 9213, 9214, 9214, 9215, 9215, 9216, 9216, 9217, 9217, 9218, 9218, 9219, 9219, 9220, 9220, 9221, 9221, 9222, 9222, 9223, 9223, 9224, 9224, 9225, 9225, 9226, 9226, 9227, 9227, 9228, 9228, 9229, 9229, 9230, 9230, 9231, 9231, 9232, 9232, 9233, 9233, 9234, 9234, 9235, 9235, 9236, 9236, 9237, 9237, 9238, 9238, 9239, 9239, 9240, 9240, 9241, 9241, 9242, 9242, 9243, 9243, 9244, 9244, 9245, 9245, 9246, 9246, 9247, 9247, 9248, 9248, 9249, 9249, 9250, 9250, 9251, 9251, 9252, 9252, 9253, 9253, 9254, 9254, 9255, 9255, 9256, 9256, 9257, 9257, 9258, 9258, 9259, 9259, 9260, 9260, 9261, 9261, 9262, 9262, 9263, 9263, 9264, 9264, 9265, 9265, 9266, 9266, 9267, 9267, 9268, 9268, 9269, 9269, 9270, 9270, 9271, 9271, 9272, 9272, 9273, 9273, 9274, 9274, 9275, 9275, 9276, 9276, 9277, 9277, 9278, 9278, 9279, 9279, 9280, 9280, 9281, 9281, 9282, 9282, 9283, 9283, 9284, 9284, 9285, 9285, 9286, 9286, 9287, 9287, 9288, 9288, 9289, 9289, 9290, 9290, 9291, 9291, 9292, 9292, 9293, 9293, 9294, 9294, 9295, 9295, 9296, 9296, 9297, 9297, 9298, 9298, 9299, 9299, 9300, 9300, 9301, 9301, 9302, 9302, 9303, 9303, 9304, 9304, 9305, 9305, 9306, 9306, 9307, 9307, 9308, 9308, 9309, 9309, 9310, 9310, 9311, 9311, 9312, 9312, 9313, 9313, 9314, 9314, 9315, 9315, 9316, 9316, 9317, 9317, 9318, 9318, 9319, 9319, 9320, 9320, 9321, 9321, 9322, 9322, 9323, 9323, 9324, 9324, 9325, 9325, 9326, 9326, 9327, 9327, 9328, 9328, 9329, 9329, 9330, 9330, 9331, 9331, 9332, 9332, 9333, 9333, 9334, 9334, 9335, 9335, 9336, 9336, 9337, 9337, 9338, 9338, 9339, 9339, 9340, 9340, 9341, 9341, 9342, 9342, 9343, 9343, 9344, 9344, 9345, 9345, 9346, 9346, 9347, 9347, 9348, 9348, 9349, 9349, 9350, 9350, 9351, 9351, 9352, 9352, 9353, 9353, 9354, 9354, 9355, 9355, 9356, 9356, 9357, 9357, 9358, 9358, 9359, 9359, 9360, 9360, 9361, 9361, 9362, 9362, 9363, 9363, 9364, 9364, 9365, 9365, 9366, 9366, 9367, 9367, 9368, 9368, 9369, 9369, 9370, 9370, 9371, 9371, 9372, 9372, 9373, 9373, 9374, 9374, 9375, 9375, 9376, 9376, 9377, 9377, 9378, 9378, 9379, 9379, 9380, 9380, 9381, 9381, 9382, 9382, 9383, 9383, 9384, 9384, 9385, 9385, 9386, 9386, 9387, 9387, 9388, 9388, 9389, 9389, 9390, 9390, 9391, 9391, 9392, 9392, 9393, 9393, 9394, 9394, 9395, 9395, 9396, 9396, 9397, 9397, 9398, 9398, 9399, 9399, 9400, 9400, 9401, 9401, 9402, 9402, 9403, 9403, 9404, 9404, 9405, 9405, 9406, 9406, 9407, 9407, 9408, 9408, 9409, 9409, 9410, 9410, 9411, 9411, 9412, 9412, 9413, 9413, 9414, 9414, 9415, 9415, 9416, 9416, 9417, 9417, 9418, 9418, 9419, 9419, 9420, 9420, 9421, 9421, 9422, 9422, 9423, 9423, 9424, 9424, 9425, 9425, 9426, 9426, 9427, 9427, 9428, 9428, 9429, 9429, 9430, 9430, 9431, 9431, 9432, 9432, 9433, 9433, 9434, 9434, 9435, 9435, 9436, 9436, 9437, 9437, 9438, 9438, 9439, 9439, 9440, 9440, 9441, 9441, 9442, 9442, 9443, 9443, 9444, 9444, 9445, 9445, 9446, 9446, 9447, 9447, 9448, 9448, 9449, 9449, 9450, 9450, 9451, 9451, 9452, 9452, 9453, 9453, 9454, 9454, 9455, 9455, 9456, 9456, 9457, 9457, 9458, 9458, 9459, 9459, 9460, 9460, 9461, 9461, 9462, 9462, 9463, 9463, 9464, 9464, 9465, 9465, 9466, 9466, 9467, 9467, 9468, 9468, 9469, 9469, 9470, 9470, 9471, 9471, 9472, 9472, 9473, 9473, 9474, 9474, 9475, 9475, 9476, 9476, 9477, 9477, 9478, 9478, 9479, 9479, 9480, 9480, 9481, 9481, 9482, 9482, 9483, 9483, 9484, 9484, 9485, 9485, 9486, 9486, 9487, 9487, 9488, 9488, 9489, 9489, 9490, 9490, 9491, 9491, 9492, 9492, 9493, 9493, 9494, 9494, 9495, 9495, 9496, 9496, 9497, 9497, 9498, 9498, 9499, 9499, 9500, 9500, 9501, 9501, 9502, 9502, 9503, 9503, 9504, 9504, 9505, 9505, 9506, 9506, 9507, 9507, 9508, 9508, 9509, 9509, 9510, 9510, 9511, 9511, 9512, 9512, 9513, 9513, 9514, 9514, 9515, 9515, 9516, 9516, 9517, 9517, 9518, 9518, 9519, 9519, 9520, 9520, 9521, 9521, 9522, 9522, 9523, 9523, 9524, 9524, 9525, 9525, 9526, 9526, 9527, 9527, 9528, 9528, 9529, 9529, 9530, 9530, 9531, 9531, 9532, 9532, 9533, 9533, 9534, 9534, 9535, 9535, 9536, 9536, 9537, 9537, 9538, 9538, 9539, 9539, 9540, 9540, 9541, 9541, 9542, 9542, 9543, 9543, 9544, 9544, 9545, 9545, 9546, 9546, 9547, 9547, 9548, 9548, 9549, 9549, 9550, 9550, 9551, 9551, 9552, 9552, 9553, 9553, 9554, 9554, 9555, 9555, 9556, 9556, 9557, 9557, 9558, 9558, 9559, 9559, 9560, 9560, 9561, 9561, 9562, 9562, 9563, 9563, 9564, 9564, 9565, 9565, 9566, 9566, 9567, 9567, 9568, 9568, 9569, 9569, 9570, 9570, 9571, 9571, 9572, 9572, 9573, 9573, 9574, 9574, 9575, 9575, 9576, 9576, 9577, 9577, 9578, 9578, 9579, 9579, 9580, 9580, 9581, 9581, 9582, 9582, 9583, 9583, 9584, 9584, 9585, 9585, 9586, 9586, 9587, 9587, 9588, 9588, 9589, 9589, 9590, 9590, 9591, 9591, 9592, 9592, 9593, 9593, 9594, 9594, 9595, 9595, 9596, 9596, 9597, 9597, 9598, 9598, 9599, 9599, 9600, 9600, 9601, 9601, 9602, 9602, 9603, 9603, 9604, 9604, 9605, 9605, 9606, 9606, 9607, 9607, 9608, 9608, 9609, 9609, 9610, 9610, 9611, 9611, 9612, 9612, 9613, 9613, 9614, 9614, 9615, 9615, 9616, 9616, 9617, 9617, 9618, 9618, 9619, 9619, 9620, 9620, 9621, 9621, 9622, 9622, 9623, 9623, 9624, 9624, 9625, 9625, 9626, 9626, 9627, 9627, 9628, 9628, 9629, 9629, 9630, 9630, 9631, 9631, 9632, 9632, 9633, 9633, 9634, 9634, 9635, 9635, 9636, 9636, 9637, 9637, 9638, 9638, 9639, 9639, 9640, 9640, 9641, 9641, 9642, 9642, 9643, 9643, 9644, 9644, 9645, 9645, 9646, 9646, 9647, 9647, 9648, 9648, 9649, 9649, 9650, 9650, 9651, 9651, 9652, 9652, 9653, 9653, 9654, 9654, 9655, 9655, 9656, 9656, 9657, 9657, 9658, 9658, 9659, 9659, 9660, 9660, 9661, 9661, 9662, 9662, 9663, 9663, 9664, 9664, 9665, 9665, 9666, 9666, 9667, 9667, 9668, 9668, 9669, 9669, 9670, 9670, 9671, 9671, 9672, 9672, 9673, 9673, 9674, 9674, 9675, 9675, 9676, 9676, 9677, 9677, 9678, 9678, 9679, 9679, 9680, 9680, 9681, 9681, 9682, 9682, 9683, 9683, 9684, 9684, 9685, 9685, 9686, 9686, 9687, 9687, 9688, 9688, 9689, 9689, 9690, 9690, 9691, 9691, 9692, 9692, 9693, 9693, 9694, 9694, 9695, 9695, 9696, 9696, 9697, 9697, 9698, 9698, 9699, 9699, 9700, 9700, 9701, 9701, 9702, 9702, 9703, 9703, 9704, 9704, 9705, 9705, 9706, 9706, 9707, 9707, 9708, 9708, 9709, 9709, 9710, 9710, 9711, 9711, 9712, 9712, 9713, 9713, 9714, 9714, 9715, 9715, 9716, 9716, 9717, 9717, 9718, 9718, 9719, 9719, 9720, 9720, 9721, 9721, 9722, 9722, 9723, 9723, 9724, 9724, 9725, 9725, 9726, 9726, 9727, 9727, 9728, 9728, 9729, 9729, 9730, 9730, 9731, 9731, 9732, 9732, 9733, 9733, 9734, 9734, 9735, 9735, 9736, 9736, 9737, 9737, 9738, 9738, 9739, 9739, 9740, 9740, 9741, 9741, 9742, 9742, 9743, 9743, 9744, 9744, 9745, 9745, 9746, 9746, 9747, 9747, 9748, 9748, 9749, 9749, 9750, 9750, 9751, 9751, 9752, 9752, 9753, 9753, 9754, 9754, 9755, 9755, 9756, 9756, 9757, 9757, 9758, 9758, 9759, 9759, 9760, 9760, 9761, 9761, 9762, 9762, 9763, 9763, 9764, 9764, 9765, 9765, 9766, 9766, 9767, 9767, 9768, 9768, 9769, 9769, 9770, 9770, 9771, 9771, 9772, 9772, 9773, 9773, 9774, 9774, 9775, 9775, 9776, 9776, 9777, 9777, 9778, 9778, 9779, 9779, 9780, 9780, 9781, 9781, 9782, 9782, 9783, 9783, 9784, 9784, 9785, 9785, 9786, 9786, 9787, 9787, 9788, 9788, 9789, 9789, 9790, 9790, 9791, 9791, 9792, 9792, 9793, 9793, 9794, 9794, 9795, 9795, 9796, 9796, 9797, 9797, 9798, 9798, 9799, 9799, 9800, 9800, 9801, 9801, 9802, 9802, 9803, 9803, 9804, 9804, 9805, 9805, 9806, 9806, 9807, 9807, 9808, 9808, 9809, 9809, 9810, 9810, 9811, 9811, 9812, 9812, 9813, 9813, 9814, 9814, 9815, 9815, 9816, 9816, 9817, 9817, 9818, 9818, 9819, 9819, 9820, 9820, 9821, 9821, 9822, 9822, 9823, 9823, 9824, 9824, 9825, 9825, 9826, 9826, 9827, 9827, 9828, 9828, 9829, 9829, 9830, 9830, 9831, 9831, 9832, 9832, 9833, 9833, 9834, 9834, 9835, 9835, 9836, 9836, 9837, 9837, 9838, 9838, 9839, 9839, 9840, 9840, 9841, 9841, 9842, 9842, 9843, 9843, 9844, 9844, 9845, 9845, 9846, 9846, 9847, 9847, 9848, 9848, 9849, 9849, 9850, 9850, 9851, 9851, 9852, 9852, 9853, 9853, 9854, 9854, 9855, 9855, 9856, 9856, 9857, 9857, 9858, 9858, 9859, 9859, 9860, 9860, 9861, 9861, 9862, 9862, 9863, 9863, 9864, 9864, 9865, 9865, 9866, 9866, 9867, 9867, 9868, 9868, 9869, 9869, 9870, 9870, 9871, 9871, 9872, 9872, 9873, 9873, 9874, 9874, 9875, 9875, 9876, 9876, 9877, 9877, 9878, 9878, 9879, 9879, 9880, 9880, 9881, 9881, 9882, 9882, 9883, 9883, 9884, 9884, 9885, 9885, 9886, 9886, 9887, 9887, 9888, 9888, 9889, 9889, 9890, 9890, 9891, 9891, 9892, 9892, 9893, 9893, 9894, 9894, 9895, 9895, 9896, 9896, 9897, 9897, 9898, 9898, 9899, 9899, 9900, 9900, 9901, 9901, 9902, 9902, 9903, 9903, 9904, 9904, 9905, 9905, 9906, 9906, 9907, 9907, 9908, 9908, 9909, 9909, 9910, 9910, 9911, 9911, 9912, 9912, 9913, 9913, 9914, 9914, 9915, 9915, 9916, 9916, 9917, 9917, 9918, 9918, 9919, 9919, 9920, 9920, 9921, 9921, 9922, 9922, 9923, 9923, 9924, 9924, 9925, 9925, 9926, 9926, 9927, 9927, 9928, 9928, 9929, 9929, 9930, 9930, 9931, 9931, 9932, 9932, 9933, 9933, 9934, 9934, 9935, 9935, 9936, 9936, 9937, 9937, 9938, 9938, 9939, 9939, 9940, 9940, 9941, 9941, 9942, 9942, 9943, 9943, 9944, 9944, 9945, 9945, 9946, 9946, 9947, 9947, 9948, 9948, 9949, 9949, 9950, 9950, 9951, 9951, 9952, 9952, 9953, 9953, 9954, 9954, 9955, 9955, 9956, 9956, 9957, 9957, 9958, 9958, 9959, 9959, 9960, 9960, 9961, 9961, 9962, 9962, 9963, 9963, 9964, 9964, 9965, 9965, 9966, 9966, 9967, 9967, 9968, 9968, 9969, 9969, 9970, 9970, 9971, 9971, 9972, 9972, 9973, 9973, 9974, 9974, 9975, 9975, 9976, 9976, 9977, 9977, 9978, 9978, 9979, 9979, 9980, 9980, 9981, 9981, 9982, 9982, 9983, 9983, 9984, 9984, 9985, 9985, 9986, 9986, 9987, 9987, 9988, 9988, 9989, 9989, 9990, 9990, 9991, 9991, 9992, 9992, 9993, 9993, 9994, 9994, 9995, 9995, 9996, 9996, 9997, 9997, 9998, 9998, 9999, 9999,10000,10000,10001,10001,10002,10002, 10003,10003,10004,10004,10005,10005,10006,10006,10007,10007, 10008,10008,10009,10009,10010,10010,10011,10011,10012,10012, 10013,10013,10014,10014,10015,10015,10016,10016,10017,10017, 10018,10018,10019,10019,10020,10020,10021,10021,10022,10022, 10023,10023,10024,10024,10025,10025,10026,10026,10027,10027, 10028,10028,10029,10029,10030,10030,10031,10031,10032,10032, 10033,10033,10034,10034,10035,10035,10036,10036,10037,10037, 10038,10038,10039,10039,10040,10040,10041,10041,10042,10042, 10043,10043,10044,10044,10045,10045,10046,10046,10047,10047, 10048,10048,10049,10049,10050,10050,10051,10051,10052,10052, 10053,10053,10054,10054,10055,10055,10056,10056,10057,10057, 10058,10058,10059,10059,10060,10060,10061,10061,10062,10062, 10063,10063,10064,10064,10065,10065,10066,10066,10067,10067, 10068,10068,10069,10069,10070,10070,10071,10071,10072,10072, 10073,10073,10074,10074,10075,10075,10076,10076,10077,10077, 10078,10078,10079,10079,10080,10080,10081,10081,10082,10082, 10083,10083,10084,10084,10085,10085,10086,10086,10087,10087, 10088,10088,10089,10089,10090,10090,10091,10091,10092,10092, 10093,10093,10094,10094,10095,10095,10096,10096,10097,10097, 10098,10098,10099,10099,10100,10100,10101,10101,10102,10102, 10103,10103,10104,10104,10105,10105,10106,10106,10107,10107, 10108,10108,10109,10109,10110,10110,10111,10111,10112,10112, 10113,10113,10114,10114,10115,10115,10116,10116,10117,10117, 10118,10118,10119,10119,10120,10120,10121,10121,10122,10122, 10123,10123,10124,10124,10125,10125,10126,10126,10127,10127, 10128,10128,10129,10129,10130,10130,10131,10131,10132,10132, 10133,10133,10134,10134,10135,10135,10136,10136,10137,10137, 10138,10138,10139,10139,10140,10140,10141,10141,10142,10142, 10143,10143,10144,10144,10145,10145,10146,10146,10147,10147, 10148,10148,10149,10149,10150,10150,10151,10151,10152,10152, 10153,10153,10154,10154,10155,10155,10156,10156,10157,10157, 10158,10158,10159,10159,10160,10160,10161,10161,10162,10162, 10163,10163,10164,10164,10165,10165,10166,10166,10167,10167, 10168,10168,10169,10169,10170,10170,10171,10171,10172,10172, 10173,10173,10174,10174,10175,10175,10176,10176,10177,10177, 10178,10178,10179,10179,10180,10180,10181,10181,10182,10182, 10183,10183,10184,10184,10185,10185,10186,10186,10187,10187, 10188,10188,10189,10189,10190,10190,10191,10191,10192,10192, 10193,10193,10194,10194,10195,10195,10196,10196,10197,10197, 10198,10198,10199,10199,10200,10200,10201,10201,10202,10202, 10203,10203,10204,10204,10205,10205,10206,10206,10207,10207, 10208,10208,10209,10209,10210,10210,10211,10211,10212,10212, 10213,10213,10214,10214,10215,10215,10216,10216,10217,10217, 10218,10218,10219,10219,10220,10220,10221,10221,10222,10222, 10223,10223,10224,10224,10225,10225,10226,10226,10227,10227, 10228,10228,10229,10229,10230,10230,10231,10231,10232,10232, 10233,10233,10234,10234,10235,10235,10236,10236,10237,10237, 10238,10238,10239,10239,10240,10240,10241,10241,10242,10242, 10243,10243,10244,10244,10245,10245,10246,10246,10247,10247, 10248,10248,10249,10249,10250,10250,10251,10251,10252,10252, 10253,10253,10254,10254,10255,10255,10256,10256,10257,10257, 10258,10258,10259,10259,10260,10260,10261,10261,10262,10262, 10263,10263,10264,10264,10265,10265,10266,10266,10267,10267, 10268,10268,10269,10269,10270,10270,10271,10271,10272,10272, 10273,10273,10274,10274,10275,10275,10276,10276,10277,10277, 10278,10278,10279,10279,10280,10280,10281,10281,10282,10282, 10283,10283,10284,10284,10285,10285,10286,10286,10287,10287, 10288,10288,10289,10289,10290,10290,10291,10291,10292,10292, 10293,10293,10294,10294,10295,10295,10296,10296,10297,10297, 10298,10298,10299,10299,10300,10300,10301,10301,10302,10302, 10303,10303,10304,10304,10305,10305,10306,10306,10307,10307, 10308,10308,10309,10309,10310,10310,10311,10311,10312,10312, 10313,10313,10314,10314,10315,10315,10316,10316,10317,10317, 10318,10318,10319,10319,10320,10320,10321,10321,10322,10322, 10323,10323,10324,10324,10325,10325,10326,10326,10327,10327, 10328,10328,10329,10329,10330,10330,10331,10331,10332,10332, 10333,10333,10334,10334,10335,10335,10336,10336,10337,10337, 10338,10338,10339,10339,10340,10340,10341,10341,10342,10342, 10343,10343,10344,10344,10345,10345,10346,10346,10347,10347, 10348,10348,10349,10349,10350,10350,10351,10351,10352,10352, 10353,10353,10354,10354,10355,10355,10356,10356,10357,10357, 10358,10358,10359,10359,10360,10360,10361,10361,10362,10362, 10363,10363,10364,10364,10365,10365,10366,10366,10367,10367, 10368,10368,10369,10369,10370,10370,10371,10371,10372,10372, 10373,10373,10374,10374,10375,10375,10376,10376,10377,10377, 10378,10378,10379,10379,10380,10380,10381,10381,10382,10382, 10383,10383,10384,10384,10385,10385,10386,10386,10387,10387, 10388,10388,10389,10389,10390,10390,10391,10391,10392,10392, 10393,10393,10394,10394,10395,10395,10396,10396,10397,10397, 10398,10398,10399,10399,10400,10400,10401,10401,10402,10402, 10403,10403,10404,10404,10405,10405,10406,10406,10407,10407, 10408,10408,10409,10409,10410,10410,10411,10411,10412,10412, 10413,10413,10414,10414,10415,10415,10416,10416,10417,10417, 10418,10418,10419,10419,10420,10420,10421,10421,10422,10422, 10423,10423,10424,10424,10425,10425,10426,10426,10427,10427, 10428,10428,10429,10429,10430,10430,10431,10431,10432,10432, 10433,10433,10434,10434,10435,10435,10436,10436,10437,10437, 10438,10438,10439,10439,10440,10440,10441,10441,10442,10442, 10443,10443,10444,10444,10445,10445,10446,10446,10447,10447, 10448,10448,10449,10449,10450,10450,10451,10451,10452,10452, 10453,10453,10454,10454,10455,10455,10456,10456,10457,10457, 10458,10458,10459,10459,10460,10460,10461,10461,10462,10462, 10463,10463,10464,10464,10465,10465,10466,10466,10467,10467, 10468,10468,10469,10469,10470,10470,10471,10471,10472,10472, 10473,10473,10474,10474,10475,10475,10476,10476,10477,10477, 10478,10478,10479,10479,10480,10480,10481,10481,10482,10482, 10483,10483,10484,10484,10485,10485,10486,10486,10487,10487, 10488,10488,10489,10489,10490,10490,10491,10491,10492,10492, 10493,10493,10494,10494,10495,10495,10496,10496,10497,10497, 10498,10498,10499,10499,10500,10500,10501,10501,10502,10502, 10503,10503,10504,10504,10505,10505,10506,10506,10507,10507, 10508,10508,10509,10509,10510,10510,10511,10511,10512,10512, 10513,10513,10514,10514,10515,10515,10516,10516,10517,10517, 10518,10518,10519,10519,10520,10520,10521,10521,10522,10522, 10523,10523,10524,10524,10525,10525,10526,10526,10527,10527, 10528,10528,10529,10529,10530,10530,10531,10531,10532,10532, 10533,10533,10534,10534,10535,10535,10536,10536,10537,10537, 10538,10538,10539,10539,10540,10540,10541,10541,10542,10542, 10543,10543,10544,10544,10545,10545,10546,10546,10547,10547, 10548,10548,10549,10549,10550,10550,10551,10551,10552,10552, 10553,10553,10554,10554,10555,10555,10556,10556,10557,10557, 10558,10558,10559,10559,10560,10560,10561,10561,10562,10562, 10563,10563,10564,10564,10565,10565,10566,10566,10567,10567, 10568,10568,10569,10569,10570,10570,10571,10571,10572,10572, 10573,10573,10574,10574,10575,10575,10576,10576,10577,10577, 10578,10578,10579,10579,10580,10580,10581,10581,10582,10582, 10583,10583,10584,10584,10585,10585,10586,10586,10587,10587, 10588,10588,10589,10589,10590,10590,10591,10591,10592,10592, 10593,10593,10594,10594,10595,10595,10596,10596,10597,10597, 10598,10598,10599,10599,10600,10600,10601,10601,10602,10602, 10603,10603,10604,10604,10605,10605,10606,10606,10607,10607, 10608,10608,10609,10609,10610,10610,10611,10611,10612,10612, 10613,10613,10614,10614,10615,10615,10616,10616,10617,10617, 10618,10618,10619,10619,10620,10620,10621,10621,10622,10622, 10623,10623,10624,10624,10625,10625,10626,10626,10627,10627, 10628,10628,10629,10629,10630,10630,10631,10631,10632,10632, 10633,10633,10634,10634,10635,10635,10636,10636,10637,10637, 10638,10638,10639,10639,10640,10640,10641,10641,10642,10642, 10643,10643,10644,10644,10645,10645,10646,10646,10647,10647, 10648,10648,10649,10649,10650,10650,10651,10651,10652,10652, 10653,10653,10654,10654,10655,10655,10656,10656,10657,10657, 10658,10658,10659,10659,10660,10660,10661,10661,10662,10662, 10663,10663,10664,10664,10665,10665,10666,10666,10667,10667, 10668,10668,10669,10669,10670,10670,10671,10671,10672,10672, 10673,10673,10674,10674,10675,10675,10676,10676,10677,10677, 10678,10678,10679,10679,10680,10680,10681,10681,10682,10682, 10683,10683,10684,10684,10685,10685,10686,10686,10687,10687, 10688,10688,10689,10689,10690,10690,10691,10691,10692,10692, 10693,10693,10694,10694,10695,10695,10696,10696,10697,10697, 10698,10698,10699,10699,10700,10700,10701,10701,10702,10702, 10703,10703,10704,10704,10705,10705,10706,10706,10707,10707, 10708,10708,10709,10709,10710,10710,10711,10711,10712,10712, 10713,10713,10714,10714,10715,10715,10716,10716,10717,10717, 10718,10718,10719,10719,10720,10720,10721,10721,10722,10722, 10723,10723,10724,10724,10725,10725,10726,10726,10727,10727, 10728,10728,10729,10729,10730,10730,10731,10731,10732,10732, 10733,10733,10734,10734,10735,10735,10736,10736,10737,10737, 10738,10738,10739,10739,10740,10740,10741,10741,10742,10742, 10743,10743,10744,10744,10745,10745,10746,10746,10747,10747, 10748,10748,10749,10749,10750,10750,10751,10751,10752,10752, 10753,10753,10754,10754,10755,10755,10756,10756,10757,10757, 10758,10758,10759,10759,10760,10760,10761,10761,10762,10762, 10763,10763,10764,10764,10765,10765,10766,10766,10767,10767, 10768,10768,10769,10769,10770,10770,10771,10771,10772,10772, 10773,10773,10774,10774,10775,10775,10776,10776,10777,10777, 10778,10778,10779,10779,10780,10780,10781,10781,10782,10782, 10783,10783,10784,10784,10785,10785,10786,10786,10787,10787, 10788,10788,10789,10789,10790,10790,10791,10791,10792,10792, 10793,10793,10794,10794,10795,10795,10796,10796,10797,10797, 10798,10798,10799,10799,10800,10800,10801,10801,10802,10802, 10803,10803,10804,10804,10805,10805,10806,10806,10807,10807, 10808,10808,10809,10809,10810,10810,10811,10811,10812,10812, 10813,10813,10814,10814,10815,10815,10816,10816,10817,10817, 10818,10818,10819,10819,10820,10820,10821,10821,10822,10822, 10823,10823,10824,10824,10825,10825,10826,10826,10827,10827, 10828,10828,10829,10829,10830,10830,10831,10831,10832,10832, 10833,10833,10834,10834,10835,10835,10836,10836,10837,10837, 10838,10838,10839,10839,10840,10840,10841,10841,10842,10842, 10843,10843,10844,10844,10845,10845,10846,10846,10847,10847, 10848,10848,10849,10849,10850,10850,10851,10851,10852,10852, 10853,10853,10854,10854,10855,10855,10856,10856,10857,10857, 10858,10858,10859,10859,10860,10860,10861,10861,10862,10862, 10863,10863,10864,10864,10865,10865,10866,10866,10867,10867, 10868,10868,10869,10869,10870,10870,10871,10871,10872,10872, 10873,10873,10874,10874,10875,10875,10876,10876,10877,10877, 10878,10878,10879,10879,10880,10880,10881,10881,10882,10882, 10883,10883,10884,10884,10885,10885,10886,10886,10887,10887, 10888,10888,10889,10889,10890,10890,10891,10891,10892,10892, 10893,10893,10894,10894,10895,10895,10896,10896,10897,10897, 10898,10898,10899,10899,10900,10900,10901,10901,10902,10902, 10903,10903,10904,10904,10905,10905,10906,10906,10907,10907, 10908,10908,10909,10909,10910,10910,10911,10911,10912,10912, 10913,10913,10914,10914,10915,10915,10916,10916,10917,10917, 10918,10918,10919,10919,10920,10920,10921,10921,10922,10922, 10923,10923,10924,10924,10925,10925,10926,10926,10927,10927, 10928,10928,10929,10929,10930,10930,10931,10931,10932,10932, 10933,10933,10934,10934,10935,10935,10936,10936,10937,10937, 10938,10938,10939,10939,10940,10940,10941,10941,10942,10942, 10943,10943,10944,10944,10945,10945,10946,10946,10947,10947, 10948,10948,10949,10949,10950,10950,10951,10951,10952,10952, 10953,10953,10954,10954,10955,10955,10956,10956,10957,10957, 10958,10958,10959,10959,10960,10960,10961,10961,10962,10962, 10963,10963,10964,10964,10965,10965,10966,10966,10967,10967, 10968,10968,10969,10969,10970,10970,10971,10971,10972,10972, 10973,10973,10974,10974,10975,10975,10976,10976,10977,10977, 10978,10978,10979,10979,10980,10980,10981,10981,10982,10982, 10983,10983,10984,10984,10985,10985,10986,10986,10987,10987, 10988,10988,10989,10989,10990,10990,10991,10991,10992,10992, 10993,10993,10994,10994,10995,10995,10996,10996,10997,10997, 10998,10998,10999,10999,11000,11000,11001,11001,11002,11002, 11003,11003,11004,11004,11005,11005,11006,11006,11007,11007, 11008,11008,11009,11009,11010,11010,11011,11011,11012,11012, 11013,11013,11014,11014,11015,11015,11016,11016,11017,11017, 11018,11018,11019,11019,11020,11020,11021,11021,11022,11022, 11023,11023,11024,11024,11025,11025,11026,11026,11027,11027, 11028,11028,11029,11029,11030,11030,11031,11031,11032,11032, 11033,11033,11034,11034,11035,11035,11036,11036,11037,11037, 11038,11038,11039,11039,11040,11040,11041,11041,11042,11042, 11043,11043,11044,11044,11045,11045,11046,11046,11047,11047, 11048,11048,11049,11049,11050,11050,11051,11051,11052,11052, 11053,11053,11054,11054,11055,11055,11056,11056,11057,11057, 11058,11058,11059,11059,11060,11060,11061,11061,11062,11062, 11063,11063,11064,11064,11065,11065,11066,11066,11067,11067, 11068,11068,11069,11069,11070,11070,11071,11071,11072,11072, 11073,11073,11074,11074,11075,11075,11076,11076,11077,11077, 11078,11078,11079,11079,11080,11080,11081,11081,11082,11082, 11083,11083,11084,11084,11085,11085,11086,11086,11087,11087, 11088,11088,11089,11089,11090,11090,11091,11091,11092,11092, 11093,11093,11094,11094,11095,11095,11096,11096,11097,11097, 11098,11098,11099,11099,11100,11100,11101,11101,11102,11102, 11103,11103,11104,11104,11105,11105,11106,11106,11107,11107, 11108,11108,11109,11109,11110,11110,11111,11111,11112,11112, 11113,11113,11114,11114,11115,11115,11116,11116,11117,11117, 11118,11118,11119,11119,11120,11120,11121,11121,11122,11122, 11123,11123,11124,11124,11125,11125,11126,11126,11127,11127, 11128,11128,11129,11129,11130,11130,11131,11131,11132,11132, 11133,11133,11134,11134,11135,11135,11136,11136,11137,11137, 11138,11138,11139,11139,11140,11140,11141,11141,11142,11142, 11143,11143,11144,11144,11145,11145,11146,11146,11147,11147, 11148,11148,11149,11149,11150,11150,11151,11151,11152,11152, 11153,11153,11154,11154,11155,11155,11156,11156,11157,11157, 11158,11158,11159,11159,11160,11160,11161,11161,11162,11162, 11163,11163,11164,11164,11165,11165,11166,11166,11167,11167, 11168,11168,11169,11169,11170,11170,11171,11171,11172,11172, 11173,11173,11174,11174,11175,11175,11176,11176,11177,11177, 11178,11178,11179,11179,11180,11180,11181,11181,11182,11182, 11183,11183,11184,11184,11185,11185,11186,11186,11187,11187, 11188,11188,11189,11189,11190,11190,11191,11191,11192,11192, 11193,11193,11194,11194,11195,11195,11196,11196,11197,11197, 11198,11198,11199,11199,11200,11200,11201,11201,11202,11202, 11203,11203,11204,11204,11205,11205,11206,11206,11207,11207, 11208,11208,11209,11209,11210,11210,11211,11211,11212,11212, 11213,11213,11214,11214,11215,11215,11216,11216,11217,11217, 11218,11218,11219,11219,11220,11220,11221,11221,11222,11222, 11223,11223,11224,11224,11225,11225,11226,11226,11227,11227, 11228,11228,11229,11229,11230,11230,11231,11231,11232,11232, 11233,11233,11234,11234,11235,11235,11236,11236,11237,11237, 11238,11238,11239,11239,11240,11240,11241,11241,11242,11242, 11243,11243,11244,11244,11245,11245,11246,11246,11247,11247, 11248,11248,11249,11249,11250,11250,11251,11251,11252,11252, 11253,11253,11254,11254,11255,11255,11256,11256,11257,11257, 11258,11258,11259,11259,11260,11260,11261,11261,11262,11262, 11263,11263,11264,11264,11265,11265,11266,11266,11267,11267, 11268,11268,11269,11269,11270,11270,11271,11271,11272,11272, 11273,11273,11274,11274,11275,11275,11276,11276,11277,11277, 11278,11278,11279,11279,11280,11280,11281,11281,11282,11282, 11283,11283,11284,11284,11285,11285,11286,11286,11287,11287, 11288,11288,11289,11289,11290,11290,11291,11291,11292,11292, 11293,11293,11294,11294,11295,11295,11296,11296,11297,11297, 11298,11298,11299,11299,11300,11300,11301,11301,11302,11302, 11303,11303,11304,11304,11305,11305,11306,11306,11307,11307, 11308,11308,11309,11309,11310,11310,11311,11311,11312,11312, 11313,11313,11314,11314,11315,11315,11316,11316,11317,11317, 11318,11318,11319,11319,11320,11320,11321,11321,11322,11322, 11323,11323,11324,11324,11325,11325,11326,11326,11327,11327, 11328,11328,11329,11329,11330,11330,11331,11331,11332,11332, 11333,11333,11334,11334,11335,11335,11336,11336,11337,11337, 11338,11338,11339,11339,11340,11340,11341,11341,11342,11342, 11343,11343,11344,11344,11345,11345,11346,11346,11347,11347, 11348,11348,11349,11349,11350,11350,11351,11351,11352,11352, 11353,11353,11354,11354,11355,11355,11356,11356,11357,11357, 11358,11358,11359,11359,11360,11360,11361,11361,11362,11362, 11363,11363,11364,11364,11365,11365,11366,11366,11367,11367, 11368,11368,11369,11369,11370,11370,11371,11371,11372,11372, 11373,11373,11374,11374,11375,11375,11376,11376,11377,11377, 11378,11378,11379,11379,11380,11380,11381,11381,11382,11382, 11383,11383,11384,11384,11385,11385,11386,11386,11387,11387, 11388,11388,11389,11389,11390,11390,11391,11391,11392,11392, 11393,11393,11394,11394,11395,11395,11396,11396,11397,11397, 11398,11398,11399,11399,11400,11400,11401,11401,11402,11402, 11403,11403,11404,11404,11405,11405,11406,11406,11407,11407, 11408,11408,11409,11409,11410,11410,11411,11411,11412,11412, 11413,11413,11414,11414,11415,11415,11416,11416,11417,11417, 11418,11418,11419,11419,11420,11420,11421,11421,11422,11422, 11423,11423,11424,11424,11425,11425,11426,11426,11427,11427, 11428,11428,11429,11429,11430,11430,11431,11431,11432,11432, 11433,11433,11434,11434,11435,11435,11436,11436,11437,11437, 11438,11438,11439,11439,11440,11440,11441,11441,11442,11442, 11443,11443,11444,11444,11445,11445,11446,11446,11447,11447, 11448,11448,11449,11449,11450,11450,11451,11451,11452,11452, 11453,11453,11454,11454,11455,11455,11456,11456,11457,11457, 11458,11458,11459,11459,11460,11460,11461,11461,11462,11462, 11463,11463,11464,11464,11465,11465,11466,11466,11467,11467, 11468,11468,11469,11469,11470,11470,11471,11471,11472,11472, 11473,11473,11474,11474,11475,11475,11476,11476,11477,11477, 11478,11478,11479,11479,11480,11480,11481,11481,11482,11482, 11483,11483,11484,11484,11485,11485,11486,11486,11487,11487, 11488,11488,11489,11489,11490,11490,11491,11491,11492,11492, 11493,11493,11494,11494,11495,11495,11496,11496,11497,11497, 11498,11498,11499,11499,11500,11500,11501,11501,11502,11502, 11503,11503,11504,11504,11505,11505,11506,11506,11507,11507, 11508,11508,11509,11509,11510,11510,11511,11511,11512,11512, 11513,11513,11514,11514,11515,11515,11516,11516,11517,11517, 11518,11518,11519,11519,11520,11520,11521,11521,11522,11522, 11523,11523,11524,11524,11525,11525,11526,11526,11527,11527, 11528,11528,11529,11529,11530,11530,11531,11531,11532,11532, 11533,11533,11534,11534,11535,11535,11536,11536,11537,11537, 11538,11538,11539,11539,11540,11540,11541,11541,11542,11542, 11543,11543,11544,11544,11545,11545,11546,11546,11547,11547, 11548,11548,11549,11549,11550,11550,11551,11551,11552,11552, 11553,11553,11554,11554,11555,11555,11556,11556,11557,11557, 11558,11558,11559,11559,11560,11560,11561,11561,11562,11562, 11563,11563,11564,11564,11565,11565,11566,11566,11567,11567, 11568,11568,11569,11569,11570,11570,11571,11571,11572,11572, 11573,11573,11574,11574,11575,11575,11576,11576,11577,11577, 11578,11578,11579,11579,11580,11580,11581,11581,11582,11582, 11583,11583,11584,11584,11585,11585,11586,11586,11587,11587, 11588,11588,11589,11589,11590,11590,11591,11591,11592,11592, 11593,11593,11594,11594,11595,11595,11596,11596,11597,11597, 11598,11598,11599,11599,11600,11600,11601,11601,11602,11602, 11603,11603,11604,11604,11605,11605,11606,11606,11607,11607, 11608,11608,11609,11609,11610,11610,11611,11611,11612,11612, 11613,11613,11614,11614,11615,11615,11616,11616,11617,11617, 11618,11618,11619,11619,11620,11620,11621,11621,11622,11622, 11623,11623,11624,11624,11625,11625,11626,11626,11627,11627, 11628,11628,11629,11629,11630,11630,11631,11631,11632,11632, 11633,11633,11634,11634,11635,11635,11636,11636,11637,11637, 11638,11638,11639,11639,11640,11640,11641,11641,11642,11642, 11643,11643,11644,11644,11645,11645,11646,11646,11647,11647, 11648,11648,11649,11649,11650,11650,11651,11651,11652,11652, 11653,11653,11654,11654,11655,11655,11656,11656,11657,11657, 11658,11658,11659,11659,11660,11660,11661,11661,11662,11662, 11663,11663,11664,11664,11665,11665,11666,11666,11667,11667, 11668,11668,11669,11669,11670,11670,11671,11671,11672,11672, 11673,11673,11674,11674,11675,11675,11676,11676,11677,11677, 11678,11678,11679,11679,11680,11680,11681,11681,11682,11682, 11683,11683,11684,11684,11685,11685,11686,11686,11687,11687, 11688,11688,11689,11689,11690,11690,11691,11691,11692,11692, 11693,11693,11694,11694,11695,11695,11696,11696,11697,11697, 11698,11698,11699,11699,11700,11700,11701,11701,11702,11702, 11703,11703,11704,11704,11705,11705,11706,11706,11707,11707, 11708,11708,11709,11709,11710,11710,11711,11711,11712,11712, 11713,11713,11714,11714,11715,11715,11716,11716,11717,11717, 11718,11718,11719,11719,11720,11720,11721,11721,11722,11722, 11723,11723,11724,11724,11725,11725,11726,11726,11727,11727, 11728,11728,11729,11729,11730,11730,11731,11731,11732,11732, 11733,11733,11734,11734,11735,11735,11736,11736,11737,11737, 11738,11738,11739,11739,11740,11740,11741,11741,11742,11742, 11743,11743,11744,11744,11745,11745,11746,11746,11747,11747, 11748,11748,11749,11749,11750,11750,11751,11751,11752,11752, 11753,11753,11754,11754,11755,11755,11756,11756,11757,11757, 11758,11758,11759,11759,11760,11760,11761,11761,11762,11762, 11763,11763,11764,11764,11765,11765,11766,11766,11767,11767, 11768,11768,11769,11769,11770,11770,11771,11771,11772,11772, 11773,11773,11774,11774,11775,11775,11776,11776,11777,11777, 11778,11778,11779,11779,11780,11780,11781,11781,11782,11782, 11783,11783,11784,11784,11785,11785,11786,11786,11787,11787, 11788,11788,11789,11789,11790,11790,11791,11791,11792,11792, 11793,11793,11794,11794,11795,11795,11796,11796,11797,11797, 11798,11798,11799,11799,11800,11800,11801,11801,11802,11802, 11803,11803,11804,11804,11805,11805,11806,11806,11807,11807, 11808,11808,11809,11809,11810,11810,11811,11811,11812,11812, 11813,11813,11814,11814,11815,11815,11816,11816,11817,11817, 11818,11818,11819,11819,11820,11820,11821,11821,11822,11822, 11823,11823,11824,11824,11825,11825,11826,11826,11827,11827, 11828,11828,11829,11829,11830,11830,11831,11831,11832,11832, 11833,11833,11834,11834,11835,11835,11836,11836,11837,11837, 11838,11838,11839,11839,11840,11840,11841,11841,11842,11842, 11843,11843,11844,11844,11845,11845,11846,11846,11847,11847, 11848,11848,11849,11849,11850,11850,11851,11851,11852,11852, 11853,11853,11854,11854,11855,11855,11856,11856,11857,11857, 11858,11858,11859,11859,11860,11860,11861,11861,11862,11862, 11863,11863,11864,11864,11865,11865,11866,11866,11867,11867, 11868,11868,11869,11869,11870,11870,11871,11871,11872,11872, 11873,11873,11874,11874,11875,11875,11876,11876,11877,11877, 11878,11878,11879,11879,11880,11880,11881,11881,11882,11882, 11883,11883,11884,11884,11885,11885,11886,11886,11887,11887, 11888,11888,11889,11889,11890,11890,11891,11891,11892,11892, 11893,11893,11894,11894,11895,11895,11896,11896,11897,11897, 11898,11898,11899,11899,11900,11900,11901,11901,11902,11902, 11903,11903,11904,11904,11905,11905,11906,11906,11907,11907, 11908,11908,11909,11909,11910,11910,11911,11911,11912,11912, 11913,11913,11914,11914,11915,11915,11916,11916,11917,11917, 11918,11918,11919,11919,11920,11920,11921,11921,11922,11922, 11923,11923,11924,11924,11925,11925,11926,11926,11927,11927, 11928,11928,11929,11929,11930,11930,11931,11931,11932,11932, 11933,11933,11934,11934,11935,11935,11936,11936,11937,11937, 11938,11938,11939,11939,11940,11940,11941,11941,11942,11942, 11943,11943,11944,11944,11945,11945,11946,11946,11947,11947, 11948,11948,11949,11949,11950,11950,11951,11951,11952,11952, 11953,11953,11954,11954,11955,11955,11956,11956,11957,11957, 11958,11958,11959,11959,11960,11960,11961,11961,11962,11962, 11963,11963,11964,11964,11965,11965,11966,11966,11967,11967, 11968,11968,11969,11969,11970,11970,11971,11971,11972,11972, 11973,11973,11974,11974,11975,11975,11976,11976,11977,11977, 11978,11978,11979,11979,11980,11980,11981,11981,11982,11982, 11983,11983,11984,11984,11985,11985,11986,11986,11987,11987, 11988,11988,11989,11989,11990,11990,11991,11991,11992,11992, 11993,11993,11994,11994,11995,11995,11996,11996,11997,11997, 11998,11998,11999,11999,12000,12000,12001,12001,12002,12002, 12003,12003,12004,12004,12005,12005,12006,12006,12007,12007, 12008,12008,12009,12009,12010,12010,12011,12011,12012,12012, 12013,12013,12014,12014,12015,12015,12016,12016,12017,12017, 12018,12018,12019,12019,12020,12020,12021,12021,12022,12022, 12023,12023,12024,12024,12025,12025,12026,12026,12027,12027, 12028,12028,12029,12029,12030,12030,12031,12031,12032,12032, 12033,12033,12034,12034,12035,12035,12036,12036,12037,12037, 12038,12038,12039,12039,12040,12040,12041,12041,12042,12042, 12043,12043,12044,12044,12045,12045,12046,12046,12047,12047, 12048,12048,12049,12049,12050,12050,12051,12051,12052,12052, 12053,12053,12054,12054,12055,12055,12056,12056,12057,12057, 12058,12058,12059,12059,12060,12060,12061,12061,12062,12062, 12063,12063,12064,12064,12065,12065,12066,12066,12067,12067, 12068,12068,12069,12069,12070,12070,12071,12071,12072,12072, 12073,12073,12074,12074,12075,12075,12076,12076,12077,12077, 12078,12078,12079,12079,12080,12080,12081,12081,12082,12082, 12083,12083,12084,12084,12085,12085,12086,12086,12087,12087, 12088,12088,12089,12089,12090,12090,12091,12091,12092,12092, 12093,12093,12094,12094,12095,12095,12096,12096,12097,12097, 12098,12098,12099,12099,12100,12100,12101,12101,12102,12102, 12103,12103,12104,12104,12105,12105,12106,12106,12107,12107, 12108,12108,12109,12109,12110,12110,12111,12111,12112,12112, 12113,12113,12114,12114,12115,12115,12116,12116,12117,12117, 12118,12118,12119,12119,12120,12120,12121,12121,12122,12122, 12123,12123,12124,12124,12125,12125,12126,12126,12127,12127, 12128,12128,12129,12129,12130,12130,12131,12131,12132,12132, 12133,12133,12134,12134,12135,12135,12136,12136,12137,12137, 12138,12138,12139,12139,12140,12140,12141,12141,12142,12142, 12143,12143,12144,12144,12145,12145,12146,12146,12147,12147, 12148,12148,12149,12149,12150,12150,12151,12151,12152,12152, 12153,12153,12154,12154,12155,12155,12156,12156,12157,12157, 12158,12158,12159,12159,12160,12160,12161,12161,12162,12162, 12163,12163,12164,12164,12165,12165,12166,12166,12167,12167, 12168,12168,12169,12169,12170,12170,12171,12171,12172,12172, 12173,12173,12174,12174,12175,12175,12176,12176,12177,12177, 12178,12178,12179,12179,12180,12180,12181,12181,12182,12182, 12183,12183,12184,12184,12185,12185,12186,12186,12187,12187, 12188,12188,12189,12189,12190,12190,12191,12191,12192,12192, 12193,12193,12194,12194,12195,12195,12196,12196,12197,12197, 12198,12198,12199,12199,12200,12200,12201,12201,12202,12202, 12203,12203,12204,12204,12205,12205,12206,12206,12207,12207, 12208,12208,12209,12209,12210,12210,12211,12211,12212,12212, 12213,12213,12214,12214,12215,12215,12216,12216,12217,12217, 12218,12218,12219,12219,12220,12220,12221,12221,12222,12222, 12223,12223,12224,12224,12225,12225,12226,12226,12227,12227, 12228,12228,12229,12229,12230,12230,12231,12231,12232,12232, 12233,12233,12234,12234,12235,12235,12236,12236,12237,12237, 12238,12238,12239,12239,12240,12240,12241,12241,12242,12242, 12243,12243,12244,12244,12245,12245,12246,12246,12247,12247, 12248,12248,12249,12249,12250,12250,12251,12251,12252,12252, 12253,12253,12254,12254,12255,12255,12256,12256,12257,12257, 12258,12258,12259,12259,12260,12260,12261,12261,12262,12262, 12263,12263,12264,12264,12265,12265,12266,12266,12267,12267, 12268,12268,12269,12269,12270,12270,12271,12271,12272,12272, 12273,12273,12274,12274,12275,12275,12276,12276,12277,12277, 12278,12278,12279,12279,12280,12280,12281,12281,12282,12282, 12283,12283,12284,12284,12285,12285,12286,12286,12287,12287, 12288,12288,12289,12289,12290,12290,12291,12291,12292,12292, 12293,12293,12294,12294,12295,12295,12296,12296,12297,12297, 12298,12298,12299,12299,12300,12300,12301,12301,12302,12302, 12303,12303,12304,12304,12305,12305,12306,12306,12307,12307, 12308,12308,12309,12309,12310,12310,12311,12311,12312,12312, 12313,12313,12314,12314,12315,12315,12316,12316,12317,12317, 12318,12318,12319,12319,12320,12320,12321,12321,12322,12322, 12323,12323,12324,12324,12325,12325,12326,12326,12327,12327, 12328,12328,12329,12329,12330,12330,12331,12331,12332,12332, 12333,12333,12334,12334,12335,12335,12336,12336,12337,12337, 12338,12338,12339,12339,12340,12340,12341,12341,12342,12342, 12343,12343,12344,12344,12345,12345,12346,12346,12347,12347, 12348,12348,12349,12349,12350,12350,12351,12351,12352,12352, 12353,12353,12354,12354,12355,12355,12356,12356,12357,12357, 12358,12358,12359,12359,12360,12360,12361,12361,12362,12362, 12363,12363,12364,12364,12365,12365,12366,12366,12367,12367, 12368,12368,12369,12369,12370,12370,12371,12371,12372,12372, 12373,12373,12374,12374,12375,12375,12376,12376,12377,12377, 12378,12378,12379,12379,12380,12380,12381,12381,12382,12382, 12383,12383,12384,12384,12385,12385,12386,12386,12387,12387, 12388,12388,12389,12389,12390,12390,12391,12391,12392,12392, 12393,12393,12394,12394,12395,12395,12396,12396,12397,12397, 12398,12398,12399,12399,12400,12400,12401,12401,12402,12402, 12403,12403,12404,12404,12405,12405,12406,12406,12407,12407, 12408,12408,12409,12409,12410,12410,12411,12411,12412,12412, 12413,12413,12414,12414,12415,12415,12416,12416,12417,12417, 12418,12418,12419,12419,12420,12420,12421,12421,12422,12422, 12423,12423,12424,12424,12425,12425,12426,12426,12427,12427, 12428,12428,12429,12429,12430,12430,12431,12431,12432,12432, 12433,12433,12434,12434,12435,12435,12436,12436,12437,12437, 12438,12438,12439,12439,12440,12440,12441,12441,12442,12442, 12443,12443,12444,12444,12445,12445,12446,12446,12447,12447, 12448,12448,12449,12449,12450,12450,12451,12451,12452,12452, 12453,12453,12454,12454,12455,12455,12456,12456,12457,12457, 12458,12458,12459,12459,12460,12460,12461,12461,12462,12462, 12463,12463,12464,12464,12465,12465,12466,12466,12467,12467, 12468,12468,12469,12469,12470,12470,12471,12471,12472,12472, 12473,12473,12474,12474,12475,12475,12476,12476,12477,12477, 12478,12478,12479,12479,12480,12480,12481,12481,12482,12482, 12483,12483,12484,12484,12485,12485,12486,12486,12487,12487, 12488,12488,12489,12489,12490,12490,12491,12491,12492,12492, 12493,12493,12494,12494,12495,12495,12496,12496,12497,12497, 12498,12498,12499,12499,12500,12500,12501,12501,12502,12502, 12503,12503,12504,12504,12505,12505,12506,12506,12507,12507, 12508,12508,12509,12509,12510,12510,12511,12511,12512,12512, 12513,12513,12514,12514,12515,12515,12516,12516,12517,12517, 12518,12518,12519,12519,12520,12520,12521,12521,12522,12522, 12523,12523,12524,12524,12525,12525,12526,12526,12527,12527, 12528,12528,12529,12529,12530,12530,12531,12531,12532,12532, 12533,12533,12534,12534,12535,12535,12536,12536,12537,12537, 12538,12538,12539,12539,12540,12540,12541,12541,12542,12542, 12543,12543,12544,12544,12545,12545,12546,12546,12547,12547, 12548,12548,12549,12549,12550,12550,12551,12551,12552,12552, 12553,12553,12554,12554,12555,12555,12556,12556,12557,12557, 12558,12558,12559,12559,12560,12560,12561,12561,12562,12562, 12563,12563,12564,12564,12565,12565,12566,12566,12567,12567, 12568,12568,12569,12569,12570,12570,12571,12571,12572,12572, 12573,12573,12574,12574,12575,12575,12576,12576,12577,12577, 12578,12578,12579,12579,12580,12580,12581,12581,12582,12582, 12583,12583,12584,12584,12585,12585,12586,12586,12587,12587, 12588,12588,12589,12589,12590,12590,12591,12591,12592,12592, 12593,12593,12594,12594,12595,12595,12596,12596,12597,12597, 12598,12598,12599,12599,12600,12600,12601,12601,12602,12602, 12603,12603,12604,12604,12605,12605,12606,12606,12607,12607, 12608,12608,12609,12609,12610,12610,12611,12611,12612,12612, 12613,12613,12614,12614,12615,12615,12616,12616,12617,12617, 12618,12618,12619,12619,12620,12620,12621,12621,12622,12622, 12623,12623,12624,12624,12625,12625,12626,12626,12627,12627, 12628,12628,12629,12629,12630,12630,12631,12631,12632,12632, 12633,12633,12634,12634,12635,12635,12636,12636,12637,12637, 12638,12638,12639,12639,12640,12640,12641,12641,12642,12642, 12643,12643,12644,12644,12645,12645,12646,12646,12647,12647, 12648,12648,12649,12649,12650,12650,12651,12651,12652,12652, 12653,12653,12654,12654,12655,12655,12656,12656,12657,12657, 12658,12658,12659,12659,12660,12660,12661,12661,12662,12662, 12663,12663,12664,12664,12665,12665,12666,12666,12667,12667, 12668,12668,12669,12669,12670,12670,12671,12671,12672,12672, 12673,12673,12674,12674,12675,12675,12676,12676,12677,12677, 12678,12678,12679,12679,12680,12680,12681,12681,12682,12682, 12683,12683,12684,12684,12685,12685,12686,12686,12687,12687, 12688,12688,12689,12689,12690,12690,12691,12691,12692,12692, 12693,12693,12694,12694,12695,12695,12696,12696,12697,12697, 12698,12698,12699,12699,12700,12700,12701,12701,12702,12702, 12703,12703,12704,12704,12705,12705,12706,12706,12707,12707, 12708,12708,12709,12709,12710,12710,12711,12711,12712,12712, 8614, 8614, 8614, 0, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614 } ; static yyconst flex_int16_t yy_nxt[8988] = { 0, 8, 9, 10, 11, 1241, 1243, 13, 1245, 14, 15, 8, 8, 9, 10, 11, 1247, 1249, 13, 61, 14, 15, 8, 22, 1251, 52, 23, 1253, 53, 56, 24, 57, 25, 54, 26, 27, 55, 28, 29, 58, 61, 30, 31, 32, 62, 33, 52, 78, 34, 53, 56, 24, 57, 25, 54, 26, 27, 55, 28, 29, 58, 1255, 30, 31, 32, 62, 33, 1257, 78, 34, 41, 63, 42, 64, 43, 44, 59, 45, 46, 79, 1259, 47, 48, 49, 80, 50, 60, 1261, 51, 1263, 1265, 41, 63, 42, 64, 43, 44, 59, 45, 46, 79, 65, 47, 48, 49, 80, 50, 60, 66, 51, 68, 81, 74, 67, 69, 75, 76, 83, 84, 77, 1267, 82, 65, 85, 90, 86, 92, 1269, 91, 66, 93, 68, 81, 74, 67, 69, 75, 76, 83, 84, 77, 87, 82, 94, 85, 90, 86, 92, 88, 91, 95, 93, 96, 89, 97, 98, 100, 102, 103, 104, 105, 106, 87, 107, 94, 108, 109, 1271, 116, 88, 101, 95, 117, 96, 89, 97, 98, 118, 102, 103, 104, 105, 106, 119, 107, 110, 108, 109, 111, 116, 120, 101, 121, 117, 122, 126, 124, 127, 118, 128, 129, 130, 131, 132, 119, 133, 110, 136, 137, 111, 125, 120, 138, 121, 134, 122, 126, 135, 127, 139, 128, 129, 130, 131, 132, 140, 133, 141, 136, 137, 142, 125, 143, 138, 144, 134, 145, 146, 135, 147, 139, 148, 149, 150, 151, 152, 140, 153, 141, 158, 159, 142, 160, 143, 161, 144, 162, 145, 146, 163, 147, 164, 148, 149, 150, 151, 152, 165, 153, 166, 158, 159, 167, 160, 168, 161, 169, 162, 170, 171, 163, 172, 164, 173, 174, 175, 176, 177, 165, 178, 166, 179, 180, 167, 183, 168, 185, 169, 187, 170, 171, 188, 172, 189, 173, 174, 175, 176, 177, 190, 178, 191, 179, 180, 192, 183, 193, 185, 198, 187, 199, 200, 188, 201, 189, 202, 205, 207, 209, 210, 190, 211, 191, 212, 213, 192, 214, 193, 215, 198, 216, 199, 200, 217, 201, 218, 202, 205, 207, 209, 210, 219, 211, 221, 212, 213, 222, 214, 223, 215, 224, 216, 225, 227, 217, 229, 218, 230, 235, 236, 237, 238, 219, 240, 221, 241, 242, 222, 243, 223, 244, 224, 246, 225, 227, 248, 229, 249, 230, 235, 236, 237, 238, 250, 240, 251, 241, 242, 254, 243, 255, 244, 252, 246, 256, 257, 248, 258, 249, 259, 260, 263, 268, 269, 250, 1273, 251, 272, 253, 254, 270, 255, 273, 274, 275, 256, 257, 276, 258, 277, 259, 260, 263, 268, 269, 278, 271, 281, 272, 253, 282, 283, 285, 273, 274, 275, 286, 288, 276, 289, 277, 292, 293, 290, 299, 300, 278, 271, 281, 302, 303, 282, 283, 285, 305, 306, 307, 286, 288, 291, 289, 309, 292, 293, 310, 299, 300, 312, 313, 314, 302, 303, 308, 315, 316, 305, 306, 319, 320, 325, 291, 326, 309, 327, 328, 310, 329, 332, 312, 313, 314, 333, 334, 308, 315, 316, 336, 337, 319, 320, 325, 339, 326, 340, 327, 328, 345, 329, 332, 347, 348, 350, 333, 334, 351, 352, 1275, 336, 337, 358, 359, 360, 339, 361, 340, 366, 1277, 345, 372, 373, 347, 348, 350, 374, 375, 351, 352, 353, 377, 354, 358, 359, 360, 378, 361, 355, 366, 356, 1279, 372, 373, 379, 380, 382, 374, 375, 1281, 383, 353, 377, 354, 384, 390, 391, 378, 392, 355, 393, 356, 367, 395, 368, 379, 380, 382, 396, 397, 369, 383, 370, 399, 400, 384, 390, 391, 401, 392, 402, 393, 403, 367, 395, 368, 404, 410, 411, 396, 397, 369, 412, 370, 399, 400, 413, 414, 415, 401, 417, 402, 418, 403, 419, 420, 427, 404, 410, 411, 428, 429, 430, 412, 432, 433, 434, 413, 414, 415, 435, 417, 439, 418, 440, 419, 420, 427, 441, 442, 445, 428, 429, 430, 446, 432, 433, 434, 451, 452, 1283, 435, 1285, 439, 1287, 440, 1289, 1291, 1293, 441, 442, 445, 1295, 1297, 1299, 446, 1301, 1303, 1305, 451, 452, 1307, 1309, 1311, 1313, 1315, 1317, 1319, 1321, 1323, 1325, 1327, 1329, 1331, 1333, 1335, 1337, 1339, 1341, 1343, 1345, 1347, 1349, 1351, 1353, 1355, 1357, 1359, 1361, 1363, 1365, 1367, 1369, 1371, 1373, 1375, 1377, 1379, 1381, 1383, 1385, 1387, 1389, 1391, 1393, 1395, 1397, 1399, 1401, 1403, 1405, 1407, 1409, 1411, 1413, 1415, 1417, 1419, 1421, 1423, 1425, 1427, 1429, 1431, 1433, 1435, 1437, 1439, 1441, 1443, 1445, 1447, 1449, 1451, 1453, 1455, 1457, 1459, 1461, 1463, 1465, 1467, 1469, 1471, 1473, 1475, 1477, 1479, 1481, 1483, 1485, 1487, 1489, 1491, 1493, 1495, 1497, 1499, 1501, 1503, 1505, 1507, 1509, 1511, 1513, 1515, 1517, 1519, 1521, 1523, 1525, 1527, 1529, 1531, 1533, 1535, 1537, 1539, 1541, 1543, 1545, 1547, 1549, 1551, 1553, 1555, 1557, 1559, 1561, 1563, 1565, 1567, 1569, 1571, 1573, 1575, 1577, 1579, 1581, 1583, 1585, 1587, 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1609, 1611, 1613, 1615, 1617, 1619, 1621, 1623, 1625, 1627, 1629, 1631, 1633, 1635, 1637, 1639, 1641, 1643, 1645, 1647, 1649, 1651, 1653, 1655, 1657, 1659, 1661, 1663, 1665, 1667, 1669, 1671, 1673, 1675, 1677, 1679, 1681, 1683, 1685, 1687, 1689, 1691, 1693, 1695, 1697, 1699, 1701, 1703, 1705, 1707, 1709, 1711, 1713, 1715, 1717, 1719, 1721, 1723, 1725, 1727, 1729, 1731, 1733, 1735, 1737, 1739, 1741, 1743, 1745, 1747, 1749, 1751, 1753, 1755, 1757, 1759, 1761, 1763, 1765, 1767, 1769, 1771, 1773, 1775, 1777, 1779, 1781, 1783, 1785, 1787, 1789, 1791, 1793, 1795, 1797, 1799, 1801, 1803, 1805, 1807, 1809, 1811, 1813, 1815, 1817, 1819, 1821, 1823, 1825, 1827, 1829, 1831, 1833, 1835, 1837, 1839, 1841, 1843, 1845, 1847, 1849, 1851, 1853, 1855, 1857, 1859, 1861, 1863, 1865, 1867, 1869, 1871, 1873, 1875, 1877, 1879, 1881, 1883, 1885, 1887, 1889, 1891, 1893, 1895, 1897, 1899, 1901, 1903, 1905, 1907, 1909, 1911, 1913, 1915, 1917, 1919, 1921, 1923, 1925, 1927, 1929, 1931, 1933, 1935, 1937, 1939, 1941, 1943, 1945, 1947, 1949, 1951, 1953, 1955, 1957, 1959, 1961, 1963, 1965, 1967, 1969, 1971, 1973, 1975, 1977, 1979, 1981, 1983, 1985, 1987, 1989, 1991, 1993, 1995, 1997, 1999, 2001, 2003, 2005, 2007, 2009, 2011, 2013, 2015, 2017, 2019, 2021, 2023, 2025, 2027, 2029, 2031, 2033, 2035, 2037, 2039, 2041, 2043, 2045, 2047, 2049, 2051, 2053, 2055, 2057, 2059, 2061, 2063, 2065, 2067, 2069, 2071, 2073, 2075, 2077, 2079, 2081, 2083, 2085, 2087, 2089, 2091, 2093, 2095, 2097, 2099, 2101, 2103, 2105, 2107, 2109, 2111, 2113, 2115, 2117, 2119, 2121, 2123, 2125, 2127, 2129, 2131, 2133, 2135, 2137, 2139, 2141, 2143, 2145, 2147, 2149, 2151, 2153, 2155, 2157, 2159, 2161, 2163, 2165, 2167, 2169, 2171, 2173, 2175, 2177, 2179, 2181, 2183, 2185, 2187, 2189, 2191, 2193, 2195, 2197, 2199, 2201, 2203, 2205, 2207, 2209, 2211, 2213, 2215, 2217, 2219, 2221, 2223, 2225, 2227, 2229, 2231, 2233, 2235, 2237, 2239, 2241, 2243, 2245, 2247, 2249, 2251, 2253, 2255, 2257, 2259, 2261, 2263, 2265, 2267, 2269, 2271, 2273, 2275, 2277, 2279, 2281, 2283, 2285, 2287, 2289, 2291, 2293, 2295, 2297, 2299, 2301, 2303, 2305, 2307, 2309, 2311, 2313, 2315, 2317, 2319, 2321, 2323, 2325, 2327, 2329, 2331, 2333, 2335, 2337, 2339, 2341, 2343, 2345, 2347, 2349, 2351, 2353, 2355, 2357, 2359, 2361, 2363, 2365, 2367, 2369, 2371, 2373, 2375, 2377, 2379, 2381, 2383, 2385, 2387, 2389, 2391, 2393, 2395, 2397, 2399, 2401, 2403, 2405, 2407, 2409, 2411, 2413, 2415, 2417, 2419, 2421, 2423, 2425, 2427, 2429, 2431, 2433, 2435, 2437, 2439, 2441, 2443, 2445, 2447, 2449, 2451, 2453, 2455, 2457, 2459, 2461, 2463, 2465, 2467, 2469, 2471, 2473, 2475, 2477, 2479, 2481, 2483, 2485, 2487, 2489, 2491, 2493, 2495, 2497, 2499, 2501, 2503, 2505, 2507, 2509, 2511, 2513, 2515, 2517, 2519, 2521, 2523, 2525, 2527, 2529, 2531, 2533, 2535, 2537, 2539, 2541, 2543, 2545, 2547, 2549, 2551, 2553, 2555, 2557, 2559, 2561, 2563, 2565, 2567, 2569, 2571, 2573, 2575, 2577, 2579, 2581, 2583, 2585, 2587, 2589, 2591, 2593, 2595, 2597, 2599, 2601, 2603, 2605, 2607, 2609, 2611, 2613, 2615, 2617, 2619, 2621, 2623, 2625, 2627, 2629, 2631, 2633, 2635, 2637, 2639, 2641, 2643, 2645, 2647, 2649, 2651, 2653, 2655, 2657, 2659, 2661, 2663, 2665, 2667, 2669, 2671, 2673, 2675, 2677, 2679, 2681, 2683, 2685, 2687, 2689, 2691, 2693, 2695, 2697, 2699, 2701, 2703, 2705, 2707, 2709, 2711, 2713, 2715, 2717, 2719, 2721, 2723, 2725, 2727, 2729, 2731, 2733, 2735, 2737, 2739, 2741, 2743, 2745, 2747, 2749, 2751, 2753, 2755, 2757, 2759, 2761, 2763, 2765, 2767, 2769, 2771, 2773, 2775, 2777, 2779, 2781, 2783, 2785, 2787, 2789, 2791, 2793, 2795, 2797, 2799, 2801, 2803, 2805, 2807, 2809, 2811, 2813, 2815, 2817, 2819, 2821, 2823, 2825, 2827, 2829, 2831, 2833, 2835, 2837, 2839, 2841, 2843, 2845, 2847, 2849, 2851, 2853, 2855, 2857, 2859, 2861, 2863, 2865, 2867, 2869, 2871, 2873, 2875, 2877, 2879, 2881, 2883, 2885, 2887, 2889, 2891, 2893, 2895, 2897, 2899, 2901, 2903, 2905, 2907, 2909, 2911, 2913, 2915, 2917, 2919, 2921, 2923, 2925, 2927, 2929, 2931, 2933, 2935, 2937, 2939, 2941, 2943, 2945, 2947, 2949, 2951, 2953, 2955, 2957, 2959, 2961, 2963, 2965, 2967, 2969, 2971, 2973, 2975, 2977, 2979, 2981, 2983, 2985, 2987, 2989, 2991, 2993, 2995, 2997, 2999, 3001, 3003, 3005, 3007, 3009, 3011, 3013, 3015, 3017, 3019, 3021, 3023, 3025, 3027, 3029, 3031, 3033, 3035, 3037, 3039, 3041, 3043, 3045, 3047, 3049, 3051, 3053, 3055, 3057, 3059, 3061, 3063, 3065, 3067, 3069, 3071, 3073, 3075, 3077, 3079, 3081, 3083, 3085, 3087, 3089, 3091, 3093, 3095, 3097, 3099, 3101, 3103, 3105, 3107, 3109, 3111, 3113, 3115, 3117, 3119, 3121, 3123, 3125, 3127, 3129, 3131, 3133, 3135, 3137, 3139, 3141, 3143, 3145, 3147, 3149, 3151, 3153, 3155, 3157, 3159, 3161, 3163, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3181, 3183, 3185, 3187, 3189, 3191, 3193, 3195, 3197, 3199, 3201, 3203, 3205, 3207, 3209, 3211, 3213, 3215, 3217, 3219, 3221, 3223, 3225, 3227, 3229, 3231, 3233, 3235, 3237, 3239, 3241, 3243, 3245, 3247, 3249, 3251, 3253, 3255, 3257, 3259, 3261, 3263, 3265, 3267, 3269, 3271, 3273, 3275, 3277, 3279, 3281, 3283, 3285, 3287, 3289, 3291, 3293, 3295, 3297, 3299, 3301, 3303, 3305, 3307, 3309, 3311, 3313, 3315, 3317, 3319, 3321, 3323, 3325, 3327, 3329, 3331, 3333, 3335, 3337, 3339, 3341, 3343, 3345, 3347, 3349, 3351, 3353, 3355, 3357, 3359, 3361, 3363, 3365, 3367, 3369, 3371, 3373, 3375, 3377, 3379, 3381, 3383, 3385, 3387, 3389, 3391, 3393, 3395, 3397, 3399, 3401, 3403, 3405, 3407, 3409, 3411, 3413, 3415, 3417, 3419, 3421, 3423, 3425, 3427, 3429, 3431, 3433, 3435, 3437, 3439, 3441, 3443, 3445, 3447, 3449, 3451, 3453, 3455, 3457, 3459, 3461, 3463, 3465, 3467, 3469, 3471, 3473, 3475, 3477, 3479, 3481, 3483, 3485, 3487, 3489, 3491, 3493, 3495, 3497, 3499, 3501, 3503, 3505, 3507, 3509, 3511, 3513, 3515, 3517, 3519, 3521, 3523, 3525, 3527, 3529, 3531, 3533, 3535, 3537, 3539, 3541, 3543, 3545, 3547, 3549, 3551, 3553, 3555, 3557, 3559, 3561, 3563, 3565, 3567, 3569, 3571, 3573, 3575, 3577, 3579, 3581, 3583, 3585, 3587, 3589, 3591, 3593, 3595, 3597, 3599, 3601, 3603, 3605, 3607, 3609, 3611, 3613, 3615, 3617, 3619, 3621, 3623, 3625, 3627, 3629, 3631, 3633, 3635, 3637, 3639, 3641, 3643, 3645, 3647, 3649, 3651, 3653, 3655, 3657, 3659, 3661, 3663, 3665, 3667, 3669, 3671, 3673, 3675, 3677, 3679, 3681, 3683, 3685, 3687, 3689, 3691, 3693, 3695, 3697, 3699, 3701, 3703, 3705, 3707, 3709, 3711, 3713, 3715, 3717, 3719, 3721, 3723, 3725, 3727, 3729, 3731, 3733, 3735, 3737, 3739, 3741, 3743, 3745, 3747, 3749, 3751, 3753, 3755, 3757, 3759, 3761, 3763, 3765, 3767, 3769, 3771, 3773, 3775, 3777, 3779, 3781, 3783, 3785, 3787, 3789, 3791, 3793, 3795, 3797, 3799, 3801, 3803, 3805, 3807, 3809, 3811, 3813, 3815, 3817, 3819, 3821, 3823, 3825, 3827, 3829, 3831, 3833, 3835, 3837, 3839, 3841, 3843, 3845, 3847, 3849, 3851, 3853, 3855, 3857, 3859, 3861, 3863, 3865, 3867, 3869, 3871, 3873, 3875, 3877, 3879, 3881, 3883, 3885, 3887, 3889, 3891, 3893, 3895, 3897, 3899, 3901, 3903, 3905, 3907, 3909, 3911, 3913, 3915, 3917, 3919, 3921, 3923, 3925, 3927, 3929, 3931, 3933, 3935, 3937, 3939, 3941, 3943, 3945, 3947, 3949, 3951, 3953, 3955, 3957, 3959, 3961, 3963, 3965, 3967, 3969, 3971, 3973, 3975, 3977, 3979, 3981, 3983, 3985, 3987, 3989, 3991, 3993, 3995, 3997, 3999, 4001, 4003, 4005, 4007, 4009, 4011, 4013, 4015, 4017, 4019, 4021, 4023, 4025, 4027, 4029, 4031, 4033, 4035, 4037, 4039, 4041, 4043, 4045, 4047, 4049, 4051, 4053, 4055, 4057, 4059, 4061, 4063, 4065, 4067, 4069, 4071, 4073, 4075, 4077, 4079, 4081, 4083, 4085, 4087, 4089, 4091, 4093, 4095, 4097, 4099, 4101, 4103, 4105, 4107, 4109, 4111, 4113, 4115, 4117, 4119, 4121, 4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, 4145, 4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, 4169, 4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, 4193, 4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, 4217, 4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, 4241, 4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, 4265, 4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289, 4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, 4313, 4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, 4337, 4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, 4361, 4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, 4385, 4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, 4409, 4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, 4433, 4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, 4457, 4459, 4461, 4463, 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, 4481, 4483, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, 4505, 4507, 4509, 4511, 4513, 4515, 4517, 4519, 4521, 4523, 4525, 4527, 4529, 4531, 4533, 4535, 4537, 4539, 4541, 4543, 4545, 4547, 4549, 4551, 4553, 4555, 4557, 4559, 4561, 4563, 4565, 4567, 4569, 4571, 4573, 4575, 4577, 4579, 4581, 4583, 4585, 4587, 4589, 4591, 4593, 4595, 4597, 4599, 4601, 4603, 4605, 4607, 4609, 4611, 4613, 4615, 4617, 4619, 4621, 4623, 4625, 4627, 4629, 4631, 4633, 4635, 4637, 4639, 4641, 4643, 4645, 4647, 4649, 4651, 4653, 4655, 4657, 4659, 4661, 4663, 4665, 4667, 4669, 4671, 4673, 4675, 4677, 4679, 4681, 4683, 4685, 4687, 4689, 4691, 4693, 4695, 4697, 4699, 4701, 4703, 4705, 4707, 4709, 4711, 4713, 4715, 4717, 4719, 4721, 4723, 4725, 4727, 4729, 4731, 4733, 4735, 4737, 4739, 4741, 4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, 4765, 4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, 4789, 4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, 4813, 4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, 4837, 4839, 4841, 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, 4859, 4861, 4863, 4865, 4867, 4869, 4871, 4873, 4875, 4877, 4879, 4881, 4883, 4885, 4887, 4889, 4891, 4893, 4895, 4897, 4899, 4901, 4903, 4905, 4907, 4909, 4911, 4913, 4915, 4917, 4919, 4921, 4923, 4925, 4927, 4929, 4931, 4933, 4935, 4937, 4939, 4941, 4943, 4945, 4947, 4949, 4951, 4953, 4955, 4957, 4959, 4961, 4963, 4965, 4967, 4969, 4971, 4973, 4975, 4977, 4979, 4981, 4983, 4985, 4987, 4989, 4991, 4993, 4995, 4997, 4999, 5001, 5003, 5005, 5007, 5009, 5011, 5013, 5015, 5017, 5019, 5021, 5023, 5025, 5027, 5029, 5031, 5033, 5035, 5037, 5039, 5041, 5043, 5045, 5047, 5049, 5051, 5053, 5055, 5057, 5059, 5061, 5063, 5065, 5067, 5069, 5071, 5073, 5075, 5077, 5079, 5081, 5083, 5085, 5087, 5089, 5091, 5093, 5095, 5097, 5099, 5101, 5103, 5105, 5107, 5109, 5111, 5113, 5115, 5117, 5119, 5121, 5123, 5125, 5127, 5129, 5131, 5133, 5135, 5137, 5139, 5141, 5143, 5145, 5147, 5149, 5151, 5153, 5155, 5157, 5159, 5161, 5163, 5165, 5167, 5169, 5171, 5173, 5175, 5177, 5179, 5181, 5183, 5185, 5187, 5189, 5191, 5193, 5195, 5197, 5199, 5201, 5203, 5205, 5207, 5209, 5211, 5213, 5215, 5217, 5219, 5221, 5223, 5225, 5227, 5229, 5231, 5233, 5235, 5237, 5239, 5241, 5243, 5245, 5247, 5249, 5251, 5253, 5255, 5257, 5259, 5261, 5263, 5265, 5267, 5269, 5271, 5273, 5275, 5277, 5279, 5281, 5283, 5285, 5287, 5289, 5291, 5293, 5295, 5297, 5299, 5301, 5303, 5305, 5307, 5309, 5311, 5313, 5315, 5317, 5319, 5321, 5323, 5325, 5327, 5329, 5331, 5333, 5335, 5337, 5339, 5341, 5343, 5345, 5347, 5349, 5351, 5353, 5355, 5357, 5359, 5361, 5363, 5365, 5367, 5369, 5371, 5373, 5375, 5377, 5379, 5381, 5383, 5385, 5387, 5389, 5391, 5393, 5395, 5397, 5399, 5401, 5403, 5405, 5407, 5409, 5411, 5413, 5415, 5417, 5419, 5421, 5423, 5425, 5427, 5429, 5431, 5433, 5435, 5437, 5439, 5441, 5443, 5445, 5447, 5449, 5451, 5453, 5455, 5457, 5459, 5461, 5463, 5465, 5467, 5469, 5471, 5473, 5475, 5477, 5479, 5481, 5483, 5485, 5487, 5489, 5491, 5493, 5495, 5497, 5499, 5501, 5503, 5505, 5507, 5509, 5511, 5513, 5515, 5517, 5519, 5521, 5523, 5525, 5527, 5529, 5531, 5533, 5535, 5537, 5539, 5541, 5543, 5545, 5547, 5549, 5551, 5553, 5555, 5557, 5559, 5561, 5563, 5565, 5567, 5569, 5571, 5573, 5575, 5577, 5579, 5581, 5583, 5585, 5587, 5589, 5591, 5593, 5595, 5597, 5599, 5601, 5603, 5605, 5607, 5609, 5611, 5613, 5615, 5617, 5619, 5621, 5623, 5625, 5627, 5629, 5631, 5633, 5635, 5637, 5639, 5641, 5643, 5645, 5647, 5649, 5651, 5653, 5655, 5657, 5659, 5661, 5663, 5665, 5667, 5669, 5671, 5673, 5675, 5677, 5679, 5681, 5683, 5685, 5687, 5689, 5691, 5693, 5695, 5697, 5699, 5701, 5703, 5705, 5707, 5709, 5711, 5713, 5715, 5717, 5719, 5721, 5723, 5725, 5727, 5729, 5731, 5733, 5735, 5737, 5739, 5741, 5743, 5745, 5747, 5749, 5751, 5753, 5755, 5757, 5759, 5761, 5763, 5765, 5767, 5769, 5771, 5773, 5775, 5777, 5779, 5781, 5783, 5785, 5787, 5789, 5791, 5793, 5795, 5797, 5799, 5801, 5803, 5805, 5807, 5809, 5811, 5813, 5815, 5817, 5819, 5821, 5823, 5825, 5827, 5829, 5831, 5833, 5835, 5837, 5839, 5841, 5843, 5845, 5847, 5849, 5851, 5853, 5855, 5857, 5859, 5861, 5863, 5865, 5867, 5869, 5871, 5873, 5875, 5877, 5879, 5881, 5883, 5885, 5887, 5889, 5891, 5893, 5895, 5897, 5899, 5901, 5903, 5905, 5907, 5909, 5911, 5913, 5915, 5917, 5919, 5921, 5923, 5925, 5927, 5929, 5931, 5933, 5935, 5937, 5939, 5941, 5943, 5945, 5947, 5949, 5951, 5953, 5955, 5957, 5959, 5961, 5963, 5965, 5967, 5969, 5971, 5973, 5975, 5977, 5979, 5981, 5983, 5985, 5987, 5989, 5991, 5993, 5995, 5997, 5999, 6001, 6003, 6005, 6007, 6009, 6011, 6013, 6015, 6017, 6019, 6021, 6023, 6025, 6027, 6029, 6031, 6033, 6035, 6037, 6039, 6041, 6043, 6045, 6047, 6049, 6051, 6053, 6055, 6057, 6059, 6061, 6063, 6065, 6067, 6069, 6071, 6073, 6075, 6077, 6079, 6081, 6083, 6085, 6087, 6089, 6091, 6093, 6095, 6097, 6099, 6101, 6103, 6105, 6107, 6109, 6111, 6113, 6115, 6117, 6119, 6121, 6123, 6125, 6127, 6129, 6131, 6133, 6135, 6137, 6139, 6141, 6143, 6145, 6147, 6149, 6151, 6153, 6155, 6157, 6159, 6161, 6163, 6165, 6167, 6169, 6171, 6173, 6175, 6177, 6179, 6181, 6183, 6185, 6187, 6189, 6191, 6193, 6195, 6197, 6199, 6201, 6203, 6205, 6207, 6209, 6211, 6213, 6215, 6217, 6219, 6221, 6223, 6225, 6227, 6229, 6231, 6233, 6235, 6237, 6239, 6241, 6243, 6245, 6247, 6249, 6251, 6253, 6255, 6257, 6259, 6261, 6263, 6265, 6267, 6269, 6271, 6273, 6275, 6277, 6279, 6281, 6283, 6285, 6287, 6289, 6291, 6293, 6295, 6297, 6299, 6301, 6303, 6305, 6307, 6309, 6311, 6313, 6315, 6317, 6319, 6321, 6323, 6325, 6327, 6329, 6331, 6333, 6335, 6337, 6339, 6341, 6343, 6345, 6347, 6349, 6351, 6353, 6355, 6357, 6359, 6361, 6363, 6365, 6367, 6369, 6371, 6373, 6375, 6377, 6379, 6381, 6383, 6385, 6387, 6389, 6391, 6393, 6395, 6397, 6399, 6401, 6403, 6405, 6407, 6409, 6411, 6413, 6415, 6417, 6419, 6421, 6423, 6425, 6427, 6429, 6431, 6433, 6435, 6437, 6439, 6441, 6443, 6445, 6447, 6449, 6451, 6453, 6455, 6457, 6459, 6461, 6463, 6465, 6467, 6469, 6471, 6473, 6475, 6477, 6479, 6481, 6483, 6485, 6487, 6489, 6491, 6493, 6495, 6497, 6499, 6501, 6503, 6505, 6507, 6509, 6511, 6513, 6515, 6517, 6519, 6521, 6523, 6525, 6527, 6529, 6531, 6533, 6535, 6537, 6539, 6541, 6543, 6545, 6547, 6549, 6551, 6553, 6555, 6557, 6559, 6561, 6563, 6565, 6567, 6569, 6571, 6573, 6575, 6577, 6579, 6581, 6583, 6585, 6587, 6589, 6591, 6593, 6595, 6597, 6599, 6601, 6603, 6605, 6607, 6609, 6611, 6613, 6615, 6617, 6619, 6621, 6623, 6625, 6627, 6629, 6631, 6633, 6635, 6637, 6639, 6641, 6643, 6645, 6647, 6649, 6651, 6653, 6655, 6657, 6659, 6661, 6663, 6665, 6667, 6669, 6671, 6673, 6675, 6677, 6679, 6681, 6683, 6685, 6687, 6689, 6691, 6693, 6695, 6697, 6699, 6701, 6703, 6705, 6707, 6709, 6711, 6713, 6715, 6717, 6719, 6721, 6723, 6725, 6727, 6729, 6731, 6733, 6735, 6737, 6739, 6741, 6743, 6745, 6747, 6749, 6751, 6753, 6755, 6757, 6759, 6761, 6763, 6765, 6767, 6769, 6771, 6773, 6775, 6777, 6779, 6781, 6783, 6785, 6787, 6789, 6791, 6793, 6795, 6797, 6799, 6801, 6803, 6805, 6807, 6809, 6811, 6813, 6815, 6817, 6819, 6821, 6823, 6825, 6827, 6829, 6831, 6833, 6835, 6837, 6839, 6841, 6843, 6845, 6847, 6849, 6851, 6853, 6855, 6857, 6859, 6861, 6863, 6865, 6867, 6869, 6871, 6873, 6875, 6877, 6879, 6881, 6883, 6885, 6887, 6889, 6891, 6893, 6895, 6897, 6899, 6901, 6903, 6905, 6907, 6909, 6911, 6913, 6915, 6917, 6919, 6921, 6923, 6925, 6927, 6929, 6931, 6933, 6935, 6937, 6939, 6941, 6943, 6945, 6947, 6949, 6951, 6953, 6955, 6957, 6959, 6961, 6963, 6965, 6967, 6969, 6971, 6973, 6975, 6977, 6979, 6981, 6983, 6985, 6987, 6989, 6991, 6993, 6995, 6997, 6999, 7001, 7003, 7005, 7007, 7009, 7011, 7013, 7015, 7017, 7019, 7021, 7023, 7025, 7027, 7029, 7031, 7033, 7035, 7037, 7039, 7041, 7043, 7045, 7047, 7049, 7051, 7053, 7055, 7057, 7059, 7061, 7063, 7065, 7067, 7069, 7071, 7073, 7075, 7077, 7079, 7081, 7083, 7085, 7087, 7089, 7091, 7093, 7095, 7097, 7099, 7101, 7103, 7105, 7107, 7109, 7111, 7113, 7115, 7117, 7119, 7121, 7123, 7125, 7127, 7129, 7131, 7133, 7135, 7137, 7139, 7141, 7143, 7145, 7147, 7149, 7151, 7153, 7155, 7157, 7159, 7161, 7163, 7165, 7167, 7169, 7171, 7173, 7175, 7177, 7179, 7181, 7183, 7185, 7187, 7189, 7191, 7193, 7195, 7197, 7199, 7201, 7203, 7205, 7207, 7209, 7211, 7213, 7215, 7217, 7219, 7221, 7223, 7225, 7227, 7229, 7231, 7233, 7235, 7237, 7239, 7241, 7243, 7245, 7247, 7249, 7251, 7253, 7255, 7257, 7259, 7261, 7263, 7265, 7267, 7269, 7271, 7273, 7275, 7277, 7279, 7281, 7283, 7285, 7287, 7289, 7291, 7293, 7295, 7297, 7299, 7301, 7303, 7305, 7307, 7309, 7311, 7313, 7315, 7317, 7319, 7321, 7323, 7325, 7327, 7329, 7331, 7333, 7335, 7337, 7339, 7341, 7343, 7345, 7347, 7349, 7351, 7353, 7355, 7357, 7359, 7361, 7363, 7365, 7367, 7369, 7371, 7373, 7375, 7377, 7379, 7381, 7383, 7385, 7387, 7389, 7391, 7393, 7395, 7397, 7399, 7401, 7403, 7405, 7407, 7409, 7411, 7413, 7415, 7417, 7419, 7421, 7423, 7425, 7427, 7429, 7431, 7433, 7435, 7437, 7439, 7441, 7443, 7445, 7447, 7449, 7451, 7453, 7455, 7457, 7459, 7461, 7463, 7465, 7467, 7469, 7471, 7473, 7475, 7477, 7479, 7481, 7483, 7485, 7487, 7489, 7491, 7493, 7495, 7497, 7499, 7501, 7503, 7505, 7507, 7509, 7511, 7513, 7515, 7517, 7519, 7521, 7523, 7525, 7527, 7529, 7531, 7533, 7535, 7537, 7539, 7541, 7543, 7545, 7547, 7549, 7551, 7553, 7555, 7557, 7559, 7561, 7563, 7565, 7567, 7569, 7571, 7573, 7575, 7577, 7579, 7581, 7583, 7585, 7587, 7589, 7591, 7593, 7595, 7597, 7599, 7601, 7603, 7605, 7607, 7609, 7611, 7613, 7615, 7617, 7619, 7621, 7623, 7625, 7627, 7629, 7631, 7633, 7635, 7637, 7639, 7641, 7643, 7645, 7647, 7649, 7651, 7653, 7655, 7657, 7659, 7661, 7663, 7665, 7667, 7669, 7671, 7673, 7675, 7677, 7679, 7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 7829, 7831, 7833, 7835, 7837, 7839, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929, 7931, 7933, 7935, 7937, 7939, 7941, 7943, 7945, 7947, 7949, 7951, 7953, 7955, 7957, 7959, 7961, 7963, 7965, 7967, 7969, 7971, 7973, 7975, 7977, 7979, 7981, 7983, 7985, 7987, 7989, 7991, 7993, 7995, 7997, 7999, 8001, 8003, 8005, 8007, 8009, 8011, 8013, 8015, 8017, 8019, 8021, 8023, 8025, 8027, 8029, 8031, 8033, 8035, 8037, 8039, 8041, 8043, 8045, 8047, 8049, 8051, 8053, 8055, 8057, 8059, 8061, 8063, 8065, 8067, 8069, 8071, 8073, 8075, 8077, 8079, 8081, 8083, 8085, 8087, 8089, 8091, 8093, 8095, 8097, 8099, 8101, 8103, 8105, 8107, 8109, 8111, 8113, 8115, 8117, 8119, 8121, 8123, 8125, 8127, 8129, 8131, 8133, 8135, 8137, 8139, 8141, 8143, 8145, 8147, 8149, 8151, 8153, 8155, 8157, 8159, 8161, 8163, 8165, 8167, 8169, 8171, 8173, 8175, 8177, 8179, 8181, 8183, 8185, 8187, 8189, 8191, 8193, 8195, 8197, 8199, 8201, 8203, 8205, 8207, 8209, 8211, 8213, 8215, 8217, 8219, 8221, 8223, 8225, 8227, 8229, 8231, 8233, 8235, 8237, 8239, 8241, 8243, 8245, 8247, 8249, 8251, 8253, 8255, 8257, 8259, 8261, 8263, 8265, 8267, 8269, 8271, 8273, 8275, 8277, 8279, 8281, 8283, 8285, 8287, 8289, 8291, 8293, 8295, 8297, 8299, 8301, 8303, 8305, 8307, 8309, 8311, 8313, 8315, 8317, 8319, 8321, 8323, 8325, 8327, 8329, 8331, 8333, 8335, 8337, 8339, 8341, 8343, 8345, 8347, 8349, 8351, 8353, 8355, 8357, 8359, 8361, 8363, 8365, 8367, 8369, 8371, 8373, 8375, 8377, 8379, 8381, 8383, 8385, 8387, 8389, 8391, 8393, 8395, 8397, 8399, 8401, 8403, 8405, 8407, 8409, 8411, 8413, 8415, 8417, 8419, 8421, 8423, 8425, 8427, 8429, 8431, 8433, 8435, 8437, 8439, 8441, 8443, 8445, 8447, 8449, 8451, 8453, 8455, 8457, 8459, 8461, 8463, 8465, 8467, 8469, 8471, 8473, 8475, 8477, 8479, 8481, 8483, 8485, 8487, 8489, 8491, 8493, 8495, 8497, 8499, 8501, 8503, 8505, 8507, 8509, 8511, 8513, 8515, 8517, 8519, 8521, 8523, 8525, 8527, 8529, 8531, 8533, 8535, 8537, 8539, 8541, 8543, 8545, 8547, 8549, 8551, 8553, 8555, 8557, 8559, 8561, 8563, 8565, 8567, 8569, 8571, 8573, 8575, 8577, 8579, 8581, 8583, 8585, 8587, 8589, 8591, 8593, 8595, 8597, 8599, 8601, 8603, 8605, 8607, 8609, 8611, 8613, 8613, 12, 12, 12, 16, 16, 16, 18, 36, 39, 39, 71, 113, 155, 195, 232, 265, 296, 322, 342, 363, 386, 406, 423, 437, 448, 456, 460, 462, 464, 466, 468, 470, 472, 474, 476, 478, 480, 482, 484, 486, 488, 490, 492, 494, 496, 498, 500, 502, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568, 570, 572, 574, 576, 578, 580, 582, 584, 586, 588, 590, 592, 594, 596, 598, 600, 602, 604, 606, 608, 610, 612, 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 634, 636, 638, 640, 642, 644, 646, 648, 650, 652, 654, 656, 658, 660, 662, 664, 666, 668, 670, 672, 674, 676, 678, 680, 682, 684, 686, 688, 690, 692, 694, 696, 698, 700, 702, 704, 706, 708, 710, 712, 714, 716, 718, 720, 722, 724, 726, 728, 730, 732, 734, 736, 738, 740, 742, 744, 746, 748, 750, 752, 754, 756, 758, 760, 762, 764, 766, 768, 770, 772, 774, 776, 778, 780, 782, 784, 786, 788, 790, 792, 794, 796, 798, 800, 802, 804, 806, 808, 810, 812, 814, 816, 818, 820, 822, 824, 826, 828, 830, 832, 834, 836, 838, 840, 842, 844, 846, 848, 850, 852, 854, 856, 858, 860, 862, 864, 866, 868, 870, 872, 874, 876, 878, 880, 882, 884, 886, 888, 890, 892, 894, 896, 898, 900, 902, 904, 906, 908, 910, 912, 914, 916, 918, 920, 922, 924, 926, 928, 930, 932, 934, 936, 938, 940, 942, 944, 946, 948, 950, 952, 954, 956, 958, 960, 962, 964, 966, 968, 970, 972, 974, 976, 978, 980, 982, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1018, 1020, 1022, 1024, 1026, 1028, 1030, 1032, 1034, 1036, 1038, 1040, 1042, 1044, 1046, 1048, 1050, 1052, 1054, 1056, 1058, 1060, 1062, 1064, 1066, 1068, 1070, 1072, 1074, 1076, 1078, 1080, 1082, 1084, 1086, 1088, 1090, 1092, 1094, 1096, 1098, 1100, 1102, 1104, 1106, 1108, 1110, 1112, 1114, 1116, 1118, 1120, 1122, 1124, 1126, 1128, 1130, 1132, 1134, 1136, 1138, 1140, 1142, 1144, 1146, 1148, 1150, 1152, 1154, 1156, 1158, 1160, 1162, 1164, 1166, 1168, 1170, 1172, 1174, 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196, 1198, 1200, 1202, 1204, 1206, 1208, 1210, 1212, 1214, 1216, 1218, 1220, 1222, 1224, 1226, 1228, 1230, 1232, 1234, 1236, 1238, 1240, 1242, 1244, 1246, 1248, 1250, 1252, 1254, 1256, 1258, 1260, 1262, 1264, 1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298, 1300, 1302, 1304, 1306, 1308, 1310, 1312, 1314, 1316, 1318, 1320, 1322, 1324, 1326, 1328, 1330, 1332, 1334, 1336, 1338, 1340, 1342, 1344, 1346, 1348, 1350, 1352, 1354, 1356, 1358, 1360, 1362, 1364, 1366, 1368, 1370, 1372, 1374, 1376, 1378, 1380, 1382, 1384, 1386, 1388, 1390, 1392, 1394, 1396, 1398, 1400, 1402, 1404, 1406, 1408, 1410, 1412, 1414, 1416, 1418, 1420, 1422, 1424, 1426, 1428, 1430, 1432, 1434, 1436, 1438, 1440, 1442, 1444, 1446, 1448, 1450, 1452, 1454, 1456, 1458, 1460, 1462, 1464, 1466, 1468, 1470, 1472, 1474, 1476, 1478, 1480, 1482, 1484, 1486, 1488, 1490, 1492, 1494, 1496, 1498, 1500, 1502, 1504, 1506, 1508, 1510, 1512, 1514, 1516, 1518, 1520, 1522, 1524, 1526, 1528, 1530, 1532, 1534, 1536, 1538, 1540, 1542, 1544, 1546, 1548, 1550, 1552, 1554, 1556, 1558, 1560, 1562, 1564, 1566, 1568, 1570, 1572, 1574, 1576, 1578, 1580, 1582, 1584, 1586, 1588, 1590, 1592, 1594, 1596, 1598, 1600, 1602, 1604, 1606, 1608, 1610, 1612, 1614, 1616, 1618, 1620, 1622, 1624, 1626, 1628, 1630, 1632, 1634, 1636, 1638, 1640, 1642, 1644, 1646, 1648, 1650, 1652, 1654, 1656, 1658, 1660, 1662, 1664, 1666, 1668, 1670, 1672, 1674, 1676, 1678, 1680, 1682, 1684, 1686, 1688, 1690, 1692, 1694, 1696, 1698, 1700, 1702, 1704, 1706, 1708, 1710, 1712, 1714, 1716, 1718, 1720, 1722, 1724, 1726, 1728, 1730, 1732, 1734, 1736, 1738, 1740, 1742, 1744, 1746, 1748, 1750, 1752, 1754, 1756, 1758, 1760, 1762, 1764, 1766, 1768, 1770, 1772, 1774, 1776, 1778, 1780, 1782, 1784, 1786, 1788, 1790, 1792, 1794, 1796, 1798, 1800, 1802, 1804, 1806, 1808, 1810, 1812, 1814, 1816, 1818, 1820, 1822, 1824, 1826, 1828, 1830, 1832, 1834, 1836, 1838, 1840, 1842, 1844, 1846, 1848, 1850, 1852, 1854, 1856, 1858, 1860, 1862, 1864, 1866, 1868, 1870, 1872, 1874, 1876, 1878, 1880, 1882, 1884, 1886, 1888, 1890, 1892, 1894, 1896, 1898, 1900, 1902, 1904, 1906, 1908, 1910, 1912, 1914, 1916, 1918, 1920, 1922, 1924, 1926, 1928, 1930, 1932, 1934, 1936, 1938, 1940, 1942, 1944, 1946, 1948, 1950, 1952, 1954, 1956, 1958, 1960, 1962, 1964, 1966, 1968, 1970, 1972, 1974, 1976, 1978, 1980, 1982, 1984, 1986, 1988, 1990, 1992, 1994, 1996, 1998, 2000, 2002, 2004, 2006, 2008, 2010, 2012, 2014, 2016, 2018, 2020, 2022, 2024, 2026, 2028, 2030, 2032, 2034, 2036, 2038, 2040, 2042, 2044, 2046, 2048, 2050, 2052, 2054, 2056, 2058, 2060, 2062, 2064, 2066, 2068, 2070, 2072, 2074, 2076, 2078, 2080, 2082, 2084, 2086, 2088, 2090, 2092, 2094, 2096, 2098, 2100, 2102, 2104, 2106, 2108, 2110, 2112, 2114, 2116, 2118, 2120, 2122, 2124, 2126, 2128, 2130, 2132, 2134, 2136, 2138, 2140, 2142, 2144, 2146, 2148, 2150, 2152, 2154, 2156, 2158, 2160, 2162, 2164, 2166, 2168, 2170, 2172, 2174, 2176, 2178, 2180, 2182, 2184, 2186, 2188, 2190, 2192, 2194, 2196, 2198, 2200, 2202, 2204, 2206, 2208, 2210, 2212, 2214, 2216, 2218, 2220, 2222, 2224, 2226, 2228, 2230, 2232, 2234, 2236, 2238, 2240, 2242, 2244, 2246, 2248, 2250, 2252, 2254, 2256, 2258, 2260, 2262, 2264, 2266, 2268, 2270, 2272, 2274, 2276, 2278, 2280, 2282, 2284, 2286, 2288, 2290, 2292, 2294, 2296, 2298, 2300, 2302, 2304, 2306, 2308, 2310, 2312, 2314, 2316, 2318, 2320, 2322, 2324, 2326, 2328, 2330, 2332, 2334, 2336, 2338, 2340, 2342, 2344, 2346, 2348, 2350, 2352, 2354, 2356, 2358, 2360, 2362, 2364, 2366, 2368, 2370, 2372, 2374, 2376, 2378, 2380, 2382, 2384, 2386, 2388, 2390, 2392, 2394, 2396, 2398, 2400, 2402, 2404, 2406, 2408, 2410, 2412, 2414, 2416, 2418, 2420, 2422, 2424, 2426, 2428, 2430, 2432, 2434, 2436, 2438, 2440, 2442, 2444, 2446, 2448, 2450, 2452, 2454, 2456, 2458, 2460, 2462, 2464, 2466, 2468, 2470, 2472, 2474, 2476, 2478, 2480, 2482, 2484, 2486, 2488, 2490, 2492, 2494, 2496, 2498, 2500, 2502, 2504, 2506, 2508, 2510, 2512, 2514, 2516, 2518, 2520, 2522, 2524, 2526, 2528, 2530, 2532, 2534, 2536, 2538, 2540, 2542, 2544, 2546, 2548, 2550, 2552, 2554, 2556, 2558, 2560, 2562, 2564, 2566, 2568, 2570, 2572, 2574, 2576, 2578, 2580, 2582, 2584, 2586, 2588, 2590, 2592, 2594, 2596, 2598, 2600, 2602, 2604, 2606, 2608, 2610, 2612, 2614, 2616, 2618, 2620, 2622, 2624, 2626, 2628, 2630, 2632, 2634, 2636, 2638, 2640, 2642, 2644, 2646, 2648, 2650, 2652, 2654, 2656, 2658, 2660, 2662, 2664, 2666, 2668, 2670, 2672, 2674, 2676, 2678, 2680, 2682, 2684, 2686, 2688, 2690, 2692, 2694, 2696, 2698, 2700, 2702, 2704, 2706, 2708, 2710, 2712, 2714, 2716, 2718, 2720, 2722, 2724, 2726, 2728, 2730, 2732, 2734, 2736, 2738, 2740, 2742, 2744, 2746, 2748, 2750, 2752, 2754, 2756, 2758, 2760, 2762, 2764, 2766, 2768, 2770, 2772, 2774, 2776, 2778, 2780, 2782, 2784, 2786, 2788, 2790, 2792, 2794, 2796, 2798, 2800, 2802, 2804, 2806, 2808, 2810, 2812, 2814, 2816, 2818, 2820, 2822, 2824, 2826, 2828, 2830, 2832, 2834, 2836, 2838, 2840, 2842, 2844, 2846, 2848, 2850, 2852, 2854, 2856, 2858, 2860, 2862, 2864, 2866, 2868, 2870, 2872, 2874, 2876, 2878, 2880, 2882, 2884, 2886, 2888, 2890, 2892, 2894, 2896, 2898, 2900, 2902, 2904, 2906, 2908, 2910, 2912, 2914, 2916, 2918, 2920, 2922, 2924, 2926, 2928, 2930, 2932, 2934, 2936, 2938, 2940, 2942, 2944, 2946, 2948, 2950, 2952, 2954, 2956, 2958, 2960, 2962, 2964, 2966, 2968, 2970, 2972, 2974, 2976, 2978, 2980, 2982, 2984, 2986, 2988, 2990, 2992, 2994, 2996, 2998, 3000, 3002, 3004, 3006, 3008, 3010, 3012, 3014, 3016, 3018, 3020, 3022, 3024, 3026, 3028, 3030, 3032, 3034, 3036, 3038, 3040, 3042, 3044, 3046, 3048, 3050, 3052, 3054, 3056, 3058, 3060, 3062, 3064, 3066, 3068, 3070, 3072, 3074, 3076, 3078, 3080, 3082, 3084, 3086, 3088, 3090, 3092, 3094, 3096, 3098, 3100, 3102, 3104, 3106, 3108, 3110, 3112, 3114, 3116, 3118, 3120, 3122, 3124, 3126, 3128, 3130, 3132, 3134, 3136, 3138, 3140, 3142, 3144, 3146, 3148, 3150, 3152, 3154, 3156, 3158, 3160, 3162, 3164, 3166, 3168, 3170, 3172, 3174, 3176, 3178, 3180, 3182, 3184, 3186, 3188, 3190, 3192, 3194, 3196, 3198, 3200, 3202, 3204, 3206, 3208, 3210, 3212, 3214, 3216, 3218, 3220, 3222, 3224, 3226, 3228, 3230, 3232, 3234, 3236, 3238, 3240, 3242, 3244, 3246, 3248, 3250, 3252, 3254, 3256, 3258, 3260, 3262, 3264, 3266, 3268, 3270, 3272, 3274, 3276, 3278, 3280, 3282, 3284, 3286, 3288, 3290, 3292, 3294, 3296, 3298, 3300, 3302, 3304, 3306, 3308, 3310, 3312, 3314, 3316, 3318, 3320, 3322, 3324, 3326, 3328, 3330, 3332, 3334, 3336, 3338, 3340, 3342, 3344, 3346, 3348, 3350, 3352, 3354, 3356, 3358, 3360, 3362, 3364, 3366, 3368, 3370, 3372, 3374, 3376, 3378, 3380, 3382, 3384, 3386, 3388, 3390, 3392, 3394, 3396, 3398, 3400, 3402, 3404, 3406, 3408, 3410, 3412, 3414, 3416, 3418, 3420, 3422, 3424, 3426, 3428, 3430, 3432, 3434, 3436, 3438, 3440, 3442, 3444, 3446, 3448, 3450, 3452, 3454, 3456, 3458, 3460, 3462, 3464, 3466, 3468, 3470, 3472, 3474, 3476, 3478, 3480, 3482, 3484, 3486, 3488, 3490, 3492, 3494, 3496, 3498, 3500, 3502, 3504, 3506, 3508, 3510, 3512, 3514, 3516, 3518, 3520, 3522, 3524, 3526, 3528, 3530, 3532, 3534, 3536, 3538, 3540, 3542, 3544, 3546, 3548, 3550, 3552, 3554, 3556, 3558, 3560, 3562, 3564, 3566, 3568, 3570, 3572, 3574, 3576, 3578, 3580, 3582, 3584, 3586, 3588, 3590, 3592, 3594, 3596, 3598, 3600, 3602, 3604, 3606, 3608, 3610, 3612, 3614, 3616, 3618, 3620, 3622, 3624, 3626, 3628, 3630, 3632, 3634, 3636, 3638, 3640, 3642, 3644, 3646, 3648, 3650, 3652, 3654, 3656, 3658, 3660, 3662, 3664, 3666, 3668, 3670, 3672, 3674, 3676, 3678, 3680, 3682, 3684, 3686, 3688, 3690, 3692, 3694, 3696, 3698, 3700, 3702, 3704, 3706, 3708, 3710, 3712, 3714, 3716, 3718, 3720, 3722, 3724, 3726, 3728, 3730, 3732, 3734, 3736, 3738, 3740, 3742, 3744, 3746, 3748, 3750, 3752, 3754, 3756, 3758, 3760, 3762, 3764, 3766, 3768, 3770, 3772, 3774, 3776, 3778, 3780, 3782, 3784, 3786, 3788, 3790, 3792, 3794, 3796, 3798, 3800, 3802, 3804, 3806, 3808, 3810, 3812, 3814, 3816, 3818, 3820, 3822, 3824, 3826, 3828, 3830, 3832, 3834, 3836, 3838, 3840, 3842, 3844, 3846, 3848, 3850, 3852, 3854, 3856, 3858, 3860, 3862, 3864, 3866, 3868, 3870, 3872, 3874, 3876, 3878, 3880, 3882, 3884, 3886, 3888, 3890, 3892, 3894, 3896, 3898, 3900, 3902, 3904, 3906, 3908, 3910, 3912, 3914, 3916, 3918, 3920, 3922, 3924, 3926, 3928, 3930, 3932, 3934, 3936, 3938, 3940, 3942, 3944, 3946, 3948, 3950, 3952, 3954, 3956, 3958, 3960, 3962, 3964, 3966, 3968, 3970, 3972, 3974, 3976, 3978, 3980, 3982, 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004, 4006, 4008, 4010, 4012, 4014, 4016, 4018, 4020, 4022, 4024, 4026, 4028, 4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046, 4048, 4050, 4052, 4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076, 4078, 4080, 4082, 4084, 4086, 4088, 4090, 4092, 4094, 4096, 4098, 4100, 4102, 4104, 4106, 4108, 4110, 4112, 4114, 4116, 4118, 4120, 4122, 4124, 4126, 4128, 4130, 4132, 4134, 4136, 4138, 4140, 4142, 4144, 4146, 4148, 4150, 4152, 4154, 4156, 4158, 4160, 4162, 4164, 4166, 4168, 4170, 4172, 4174, 4176, 4178, 4180, 4182, 4184, 4186, 4188, 4190, 4192, 4194, 4196, 4198, 4200, 4202, 4204, 4206, 4208, 4210, 4212, 4214, 4216, 4218, 4220, 4222, 4224, 4226, 4228, 4230, 4232, 4234, 4236, 4238, 4240, 4242, 4244, 4246, 4248, 4250, 4252, 4254, 4256, 4258, 4260, 4262, 4264, 4266, 4268, 4270, 4272, 4274, 4276, 4278, 4280, 4282, 4284, 4286, 4288, 4290, 4292, 4294, 4296, 4298, 4300, 4302, 4304, 4306, 4308, 4310, 4312, 4314, 4316, 4318, 4320, 4322, 4324, 4326, 4328, 4330, 4332, 4334, 4336, 4338, 4340, 4342, 4344, 4346, 4348, 4350, 4352, 4354, 4356, 4358, 4360, 4362, 4364, 4366, 4368, 4370, 4372, 4374, 4376, 4378, 4380, 4382, 4384, 4386, 4388, 4390, 4392, 4394, 4396, 4398, 4400, 4402, 4404, 4406, 4408, 4410, 4412, 4414, 4416, 4418, 4420, 4422, 4424, 4426, 4428, 4430, 4432, 4434, 4436, 4438, 4440, 4442, 4444, 4446, 4448, 4450, 4452, 4454, 4456, 4458, 4460, 4462, 4464, 4466, 4468, 4470, 4472, 4474, 4476, 4478, 4480, 4482, 4484, 4486, 4488, 4490, 4492, 4494, 4496, 4498, 4500, 4502, 4504, 4506, 4508, 4510, 4512, 4514, 4516, 4518, 4520, 4522, 4524, 4526, 4528, 4530, 4532, 4534, 4536, 4538, 4540, 4542, 4544, 4546, 4548, 4550, 4552, 4554, 4556, 4558, 4560, 4562, 4564, 4566, 4568, 4570, 4572, 4574, 4576, 4578, 4580, 4582, 4584, 4586, 4588, 4590, 4592, 4594, 4596, 4598, 4600, 4602, 4604, 4606, 4608, 4610, 4612, 4614, 4616, 4618, 4620, 4622, 4624, 4626, 4628, 4630, 4632, 4634, 4636, 4638, 4640, 4642, 4644, 4646, 4648, 4650, 4652, 4654, 4656, 4658, 4660, 4662, 4664, 4666, 4668, 4670, 4672, 4674, 4676, 4678, 4680, 4682, 4684, 4686, 4688, 4690, 4692, 4694, 4696, 4698, 4700, 4702, 4704, 4706, 4708, 4710, 4712, 4714, 4716, 4718, 4720, 4722, 4724, 4726, 4728, 4730, 4732, 4734, 4736, 4738, 4740, 4742, 4744, 4746, 4748, 4750, 4752, 4754, 4756, 4758, 4760, 4762, 4764, 4766, 4768, 4770, 4772, 4774, 4776, 4778, 4780, 4782, 4784, 4786, 4788, 4790, 4792, 4794, 4796, 4798, 4800, 4802, 4804, 4806, 4808, 4810, 4812, 4814, 4816, 4818, 4820, 4822, 4824, 4826, 4828, 4830, 4832, 4834, 4836, 4838, 4840, 4842, 4844, 4846, 4848, 4850, 4852, 4854, 4856, 4858, 4860, 4862, 4864, 4866, 4868, 4870, 4872, 4874, 4876, 4878, 4880, 4882, 4884, 4886, 4888, 4890, 4892, 4894, 4896, 4898, 4900, 4902, 4904, 4906, 4908, 4910, 4912, 4914, 4916, 4918, 4920, 4922, 4924, 4926, 4928, 4930, 4932, 4934, 4936, 4938, 4940, 4942, 4944, 4946, 4948, 4950, 4952, 4954, 4956, 4958, 4960, 4962, 4964, 4966, 4968, 4970, 4972, 4974, 4976, 4978, 4980, 4982, 4984, 4986, 4988, 4990, 4992, 4994, 4996, 4998, 5000, 5002, 5004, 5006, 5008, 5010, 5012, 5014, 5016, 5018, 5020, 5022, 5024, 5026, 5028, 5030, 5032, 5034, 5036, 5038, 5040, 5042, 5044, 5046, 5048, 5050, 5052, 5054, 5056, 5058, 5060, 5062, 5064, 5066, 5068, 5070, 5072, 5074, 5076, 5078, 5080, 5082, 5084, 5086, 5088, 5090, 5092, 5094, 5096, 5098, 5100, 5102, 5104, 5106, 5108, 5110, 5112, 5114, 5116, 5118, 5120, 5122, 5124, 5126, 5128, 5130, 5132, 5134, 5136, 5138, 5140, 5142, 5144, 5146, 5148, 5150, 5152, 5154, 5156, 5158, 5160, 5162, 5164, 5166, 5168, 5170, 5172, 5174, 5176, 5178, 5180, 5182, 5184, 5186, 5188, 5190, 5192, 5194, 5196, 5198, 5200, 5202, 5204, 5206, 5208, 5210, 5212, 5214, 5216, 5218, 5220, 5222, 5224, 5226, 5228, 5230, 5232, 5234, 5236, 5238, 5240, 5242, 5244, 5246, 5248, 5250, 5252, 5254, 5256, 5258, 5260, 5262, 5264, 5266, 5268, 5270, 5272, 5274, 5276, 5278, 5280, 5282, 5284, 5286, 5288, 5290, 5292, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308, 5310, 5312, 5314, 5316, 5318, 5320, 5322, 5324, 5326, 5328, 5330, 5332, 5334, 5336, 5338, 5340, 5342, 5344, 5346, 5348, 5350, 5352, 5354, 5356, 5358, 5360, 5362, 5364, 5366, 5368, 5370, 5372, 5374, 5376, 5378, 5380, 5382, 5384, 5386, 5388, 5390, 5392, 5394, 5396, 5398, 5400, 5402, 5404, 5406, 5408, 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424, 5426, 5428, 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448, 5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, 5470, 5472, 5474, 5476, 5478, 5480, 5482, 5484, 5486, 5488, 5490, 5492, 5494, 5496, 5498, 5500, 5502, 5504, 5506, 5508, 5510, 5512, 5514, 5516, 5518, 5520, 5522, 5524, 5526, 5528, 5530, 5532, 5534, 5536, 5538, 5540, 5542, 5544, 5546, 5548, 5550, 5552, 5554, 5556, 5558, 5560, 5562, 5564, 5566, 5568, 5570, 5572, 5574, 5576, 5578, 5580, 5582, 5584, 5586, 5588, 5590, 5592, 5594, 5596, 5598, 5600, 5602, 5604, 5606, 5608, 5610, 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628, 5630, 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, 5650, 5652, 5654, 5656, 5658, 5660, 5662, 5664, 5666, 5668, 5670, 5672, 5674, 5676, 5678, 5680, 5682, 5684, 5686, 5688, 5690, 5692, 5694, 5696, 5698, 5700, 5702, 5704, 5706, 5708, 5710, 5712, 5714, 5716, 5718, 5720, 5722, 5724, 5726, 5728, 5730, 5732, 5734, 5736, 5738, 5740, 5742, 5744, 5746, 5748, 5750, 5752, 5754, 5756, 5758, 5760, 5762, 5764, 5766, 5768, 5770, 5772, 5774, 5776, 5778, 5780, 5782, 5784, 5786, 5788, 5790, 5792, 5794, 5796, 5798, 5800, 5802, 5804, 5806, 5808, 5810, 5812, 5814, 5816, 5818, 5820, 5822, 5824, 5826, 5828, 5830, 5832, 5834, 5836, 5838, 5840, 5842, 5844, 5846, 5848, 5850, 5852, 5854, 5856, 5858, 5860, 5862, 5864, 5866, 5868, 5870, 5872, 5874, 5876, 5878, 5880, 5882, 5884, 5886, 5888, 5890, 5892, 5894, 5896, 5898, 5900, 5902, 5904, 5906, 5908, 5910, 5912, 5914, 5916, 5918, 5920, 5922, 5924, 5926, 5928, 5930, 5932, 5934, 5936, 5938, 5940, 5942, 5944, 5946, 5948, 5950, 5952, 5954, 5956, 5958, 5960, 5962, 5964, 5966, 5968, 5970, 5972, 5974, 5976, 5978, 5980, 5982, 5984, 5986, 5988, 5990, 5992, 5994, 5996, 5998, 6000, 6002, 6004, 6006, 6008, 6010, 6012, 6014, 6016, 6018, 6020, 6022, 6024, 6026, 6028, 6030, 6032, 6034, 6036, 6038, 6040, 6042, 6044, 6046, 6048, 6050, 6052, 6054, 6056, 6058, 6060, 6062, 6064, 6066, 6068, 6070, 6072, 6074, 6076, 6078, 6080, 6082, 6084, 6086, 6088, 6090, 6092, 6094, 6096, 6098, 6100, 6102, 6104, 6106, 6108, 6110, 6112, 6114, 6116, 6118, 6120, 6122, 6124, 6126, 6128, 6130, 6132, 6134, 6136, 6138, 6140, 6142, 6144, 6146, 6148, 6150, 6152, 6154, 6156, 6158, 6160, 6162, 6164, 6166, 6168, 6170, 6172, 6174, 6176, 6178, 6180, 6182, 6184, 6186, 6188, 6190, 6192, 6194, 6196, 6198, 6200, 6202, 6204, 6206, 6208, 6210, 6212, 6214, 6216, 6218, 6220, 6222, 6224, 6226, 6228, 6230, 6232, 6234, 6236, 6238, 6240, 6242, 6244, 6246, 6248, 6250, 6252, 6254, 6256, 6258, 6260, 6262, 6264, 6266, 6268, 6270, 6272, 6274, 6276, 6278, 6280, 6282, 6284, 6286, 6288, 6290, 6292, 6294, 6296, 6298, 6300, 6302, 6304, 6306, 6308, 6310, 6312, 6314, 6316, 6318, 6320, 6322, 6324, 6326, 6328, 6330, 6332, 6334, 6336, 6338, 6340, 6342, 6344, 6346, 6348, 6350, 6352, 6354, 6356, 6358, 6360, 6362, 6364, 6366, 6368, 6370, 6372, 6374, 6376, 6378, 6380, 6382, 6384, 6386, 6388, 6390, 6392, 6394, 6396, 6398, 6400, 6402, 6404, 6406, 6408, 6410, 6412, 6414, 6416, 6418, 6420, 6422, 6424, 6426, 6428, 6430, 6432, 6434, 6436, 6438, 6440, 6442, 6444, 6446, 6448, 6450, 6452, 6454, 6456, 6458, 6460, 6462, 6464, 6466, 6468, 6470, 6472, 6474, 6476, 6478, 6480, 6482, 6484, 6486, 6488, 6490, 6492, 6494, 6496, 6498, 6500, 6502, 6504, 6506, 6508, 6510, 6512, 6514, 6516, 6518, 6520, 6522, 6524, 6526, 6528, 6530, 6532, 6534, 6536, 6538, 6540, 6542, 6544, 6546, 6548, 6550, 6552, 6554, 6556, 6558, 6560, 6562, 6564, 6566, 6568, 6570, 6572, 6574, 6576, 6578, 6580, 6582, 6584, 6586, 6588, 6590, 6592, 6594, 6596, 6598, 6600, 6602, 6604, 6606, 6608, 6610, 6612, 6614, 6616, 6618, 6620, 6622, 6624, 6626, 6628, 6630, 6632, 6634, 6636, 6638, 6640, 6642, 6644, 6646, 6648, 6650, 6652, 6654, 6656, 6658, 6660, 6662, 6664, 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, 6682, 6684, 6686, 6688, 6690, 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708, 6710, 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732, 6734, 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756, 6758, 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, 6778, 6780, 6782, 6784, 6786, 6788, 6790, 6792, 6794, 6796, 6798, 6800, 6802, 6804, 6806, 6808, 6810, 6812, 6814, 6816, 6818, 6820, 6822, 6824, 6826, 6828, 6830, 6832, 6834, 6836, 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852, 6854, 6856, 6858, 6860, 6862, 6864, 6866, 6868, 6870, 6872, 6874, 6876, 6878, 6880, 6882, 6884, 6886, 6888, 6890, 6892, 6894, 6896, 6898, 6900, 6902, 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, 6920, 6922, 6924, 6926, 6928, 6930, 6932, 6934, 6936, 6938, 6940, 6942, 6944, 6946, 6948, 6950, 6952, 6954, 6956, 6958, 6960, 6962, 6964, 6966, 6968, 6970, 6972, 6974, 6976, 6978, 6980, 6982, 6984, 6986, 6988, 6990, 6992, 6994, 6996, 6998, 7000, 7002, 7004, 7006, 7008, 7010, 7012, 7014, 7016, 7018, 7020, 7022, 7024, 7026, 7028, 7030, 7032, 7034, 7036, 7038, 7040, 7042, 7044, 7046, 7048, 7050, 7052, 7054, 7056, 7058, 7060, 7062, 7064, 7066, 7068, 7070, 7072, 7074, 7076, 7078, 7080, 7082, 7084, 7086, 7088, 7090, 7092, 7094, 7096, 7098, 7100, 7102, 7104, 7106, 7108, 7110, 7112, 7114, 7116, 7118, 7120, 7122, 7124, 7126, 7128, 7130, 7132, 7134, 7136, 7138, 7140, 7142, 7144, 7146, 7148, 7150, 7152, 7154, 7156, 7158, 7160, 7162, 7164, 7166, 7168, 7170, 7172, 7174, 7176, 7178, 7180, 7182, 7184, 7186, 7188, 7190, 7192, 7194, 7196, 7198, 7200, 7202, 7204, 7206, 7208, 7210, 7212, 7214, 7216, 7218, 7220, 7222, 7224, 7226, 7228, 7230, 7232, 7234, 7236, 7238, 7240, 7242, 7244, 7246, 7248, 7250, 7252, 7254, 7256, 7258, 7260, 7262, 7264, 7266, 7268, 7270, 7272, 7274, 7276, 7278, 7280, 7282, 7284, 7286, 7288, 7290, 7292, 7294, 7296, 7298, 7300, 7302, 7304, 7306, 7308, 7310, 7312, 7314, 7316, 7318, 7320, 7322, 7324, 7326, 7328, 7330, 7332, 7334, 7336, 7338, 7340, 7342, 7344, 7346, 7348, 7350, 7352, 7354, 7356, 7358, 7360, 7362, 7364, 7366, 7368, 7370, 7372, 7374, 7376, 7378, 7380, 7382, 7384, 7386, 7388, 7390, 7392, 7394, 7396, 7398, 7400, 7402, 7404, 7406, 7408, 7410, 7412, 7414, 7416, 7418, 7420, 7422, 7424, 7426, 7428, 7430, 7432, 7434, 7436, 7438, 7440, 7442, 7444, 7446, 7448, 7450, 7452, 7454, 7456, 7458, 7460, 7462, 7464, 7466, 7468, 7470, 7472, 7474, 7476, 7478, 7480, 7482, 7484, 7486, 7488, 7490, 7492, 7494, 7496, 7498, 7500, 7502, 7504, 7506, 7508, 7510, 7512, 7514, 7516, 7518, 7520, 7522, 7524, 7526, 7528, 7530, 7532, 7534, 7536, 7538, 7540, 7542, 7544, 7546, 7548, 7550, 7552, 7554, 7556, 7558, 7560, 7562, 7564, 7566, 7568, 7570, 7572, 7574, 7576, 7578, 7580, 7582, 7584, 7586, 7588, 7590, 7592, 7594, 7596, 7598, 7600, 7602, 7604, 7606, 7608, 7610, 7612, 7614, 7616, 7618, 7620, 7622, 7624, 7626, 7628, 7630, 7632, 7634, 7636, 7638, 7640, 7642, 7644, 7646, 7648, 7650, 7652, 7654, 7656, 7658, 7660, 7662, 7664, 7666, 7668, 7670, 7672, 7674, 7676, 7678, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 7824, 7826, 7828, 7830, 7832, 7834, 7836, 7838, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934, 7936, 7938, 7940, 7942, 7944, 7946, 7948, 7950, 7952, 7954, 7956, 7958, 7960, 7962, 7964, 7966, 7968, 7970, 7972, 7974, 7976, 7978, 7980, 7982, 7984, 7986, 7988, 7990, 7992, 7994, 7996, 7998, 8000, 8002, 8004, 8006, 8008, 8010, 8012, 8014, 8016, 8018, 8020, 8022, 8024, 8026, 8028, 8030, 8032, 8034, 8036, 8038, 8040, 8042, 8044, 8046, 8048, 8050, 8052, 8054, 8056, 8058, 8060, 8062, 8064, 8066, 8068, 8070, 8072, 8074, 8076, 8078, 8080, 8082, 8084, 8086, 8088, 8090, 8092, 8094, 8096, 8098, 8100, 8102, 8104, 8106, 8108, 8110, 8112, 8114, 8116, 8118, 8120, 8122, 8124, 8126, 8128, 8130, 8132, 8134, 8136, 8138, 8140, 8142, 8144, 8146, 8148, 8150, 8152, 8154, 8156, 8158, 8160, 8162, 8164, 8166, 8168, 8170, 8172, 8174, 8176, 8178, 8180, 8182, 8184, 8186, 8188, 8190, 8192, 8194, 8196, 8198, 8200, 8202, 8204, 8206, 8208, 8210, 8212, 8214, 8216, 8218, 8220, 8222, 8224, 8226, 8228, 8230, 8232, 8234, 8236, 8238, 8240, 8242, 8244, 8246, 8248, 8250, 8252, 8254, 8256, 8258, 8260, 8262, 8264, 8266, 8268, 8270, 8272, 8274, 8276, 8278, 8280, 8282, 8284, 8286, 8288, 8290, 8292, 8294, 8296, 8298, 8300, 8302, 8304, 8306, 8308, 8310, 8312, 8314, 8316, 8318, 8320, 8322, 8324, 8326, 8328, 8330, 8332, 8334, 8336, 8338, 8340, 8342, 8344, 8346, 8348, 8350, 8352, 8354, 8356, 8358, 8360, 8362, 8364, 8366, 8368, 8370, 8372, 8374, 8376, 8378, 8380, 8382, 8384, 8386, 8388, 8390, 8392, 8394, 8396, 8398, 8400, 8402, 8404, 8406, 8408, 8410, 8412, 8414, 8416, 8418, 8420, 8422, 8424, 8426, 8428, 8430, 8432, 8434, 8436, 8438, 8440, 8442, 8444, 8446, 8448, 8450, 8452, 8454, 8456, 8458, 8460, 8462, 8464, 8466, 8468, 8470, 8472, 8474, 8476, 8478, 8480, 8482, 8484, 8486, 8488, 8490, 8492, 8494, 8496, 8498, 8500, 8502, 8504, 8506, 8508, 8510, 8512, 8514, 8516, 8518, 8520, 8522, 8524, 8526, 8528, 8530, 8532, 8534, 8536, 8538, 8540, 8542, 8544, 8546, 8548, 8550, 8552, 8554, 8556, 8558, 8560, 8562, 8564, 8566, 8568, 8570, 8572, 8574, 8576, 8578, 8580, 8582, 8584, 8586, 8588, 8590, 8592, 8594, 8596, 8598, 8600, 8602, 8604, 8606, 8608, 8610, 8612, 1239, 1237, 1235, 1233, 1231, 1229, 1227, 1225, 1223, 1221, 1219, 1217, 1215, 1213, 1211, 1209, 1207, 1205, 1203, 1201, 1199, 1197, 1195, 1193, 1191, 1189, 1187, 1185, 1183, 1181, 1179, 1177, 1175, 1173, 1171, 1169, 1167, 1165, 1163, 1161, 1159, 1157, 1155, 1153, 1151, 1149, 1147, 1145, 1143, 1141, 1139, 1137, 1135, 1133, 1131, 1129, 1127, 1125, 1123, 1121, 1119, 1117, 1115, 1113, 1111, 1109, 1107, 1105, 1103, 1101, 1099, 1097, 1095, 1093, 1091, 1089, 1087, 1085, 1083, 1081, 1079, 1077, 1075, 1073, 1071, 1069, 1067, 1065, 1063, 1061, 1059, 1057, 1055, 1053, 1051, 1049, 1047, 1045, 1043, 1041, 1039, 1037, 1035, 1033, 1031, 1029, 1027, 1025, 1023, 1021, 1019, 1017, 1015, 1013, 1011, 1009, 1007, 1005, 1003, 1001, 999, 997, 995, 993, 991, 989, 987, 985, 983, 981, 979, 977, 975, 973, 971, 969, 967, 965, 963, 961, 959, 957, 955, 953, 951, 949, 947, 945, 943, 941, 939, 937, 935, 933, 931, 929, 927, 925, 923, 921, 919, 917, 915, 913, 911, 909, 907, 905, 903, 901, 899, 897, 895, 893, 891, 889, 887, 885, 883, 881, 879, 877, 875, 873, 871, 869, 867, 865, 863, 861, 859, 857, 855, 853, 851, 849, 847, 845, 843, 841, 839, 837, 835, 833, 831, 829, 827, 825, 823, 821, 819, 817, 815, 813, 811, 809, 807, 805, 803, 801, 799, 797, 795, 793, 791, 789, 787, 785, 783, 781, 779, 777, 775, 773, 771, 769, 767, 765, 763, 761, 759, 757, 755, 753, 751, 749, 747, 745, 743, 741, 739, 737, 735, 733, 731, 729, 727, 725, 723, 721, 719, 717, 715, 713, 711, 709, 707, 705, 703, 701, 699, 697, 695, 693, 691, 689, 687, 685, 683, 681, 679, 677, 675, 673, 671, 669, 667, 665, 663, 661, 659, 657, 655, 653, 651, 649, 647, 645, 643, 641, 639, 637, 635, 633, 631, 629, 627, 625, 623, 621, 619, 617, 615, 613, 611, 609, 607, 605, 603, 601, 599, 597, 595, 593, 591, 589, 587, 585, 583, 581, 579, 577, 575, 573, 571, 569, 567, 565, 563, 561, 559, 557, 555, 553, 551, 549, 547, 545, 543, 541, 539, 537, 535, 533, 531, 529, 527, 525, 523, 521, 519, 517, 515, 513, 511, 509, 507, 505, 503, 501, 499, 497, 495, 493, 491, 489, 487, 485, 483, 481, 479, 477, 475, 473, 471, 469, 467, 465, 463, 461, 459, 458, 457, 455, 454, 453, 450, 449, 447, 444, 443, 438, 436, 431, 426, 425, 424, 422, 421, 416, 409, 408, 407, 405, 398, 394, 389, 388, 387, 385, 381, 376, 371, 365, 364, 362, 357, 349, 346, 344, 343, 341, 338, 335, 331, 330, 324, 323, 321, 318, 317, 311, 304, 301, 298, 297, 295, 294, 287, 284, 280, 279, 267, 266, 264, 262, 261, 247, 245, 239, 234, 233, 231, 228, 226, 220, 208, 206, 204, 203, 197, 196, 194, 186, 184, 182, 181, 157, 156, 154, 123, 115, 114, 112, 99, 40, 40, 73, 72, 70, 40, 38, 37, 35, 21, 20, 19, 17, 8614, 7, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614 } ; static yyconst flex_int16_t yy_chk[8988] = { 0, 1, 1, 1, 1, 1239, 1241, 1, 1243, 1, 1, 1, 2, 2, 2, 2, 1245, 1247, 2, 30, 2, 2, 2, 15, 1249, 24, 15, 1251, 24, 26, 15, 27, 15, 25, 15, 15, 25, 15, 15, 28, 30, 15, 15, 15, 31, 15, 24, 43, 15, 24, 26, 15, 27, 15, 25, 15, 15, 25, 15, 15, 28, 1253, 15, 15, 15, 31, 15, 1255, 43, 15, 23, 32, 23, 32, 23, 23, 29, 23, 23, 44, 1257, 23, 23, 23, 45, 23, 29, 1259, 23, 1261, 1263, 23, 32, 23, 32, 23, 23, 29, 23, 23, 44, 33, 23, 23, 23, 45, 23, 29, 33, 23, 34, 46, 41, 33, 34, 41, 42, 47, 48, 42, 1265, 46, 33, 49, 51, 49, 52, 1267, 51, 33, 53, 34, 46, 41, 33, 34, 41, 42, 47, 48, 42, 50, 46, 54, 49, 51, 49, 52, 50, 51, 55, 53, 56, 50, 57, 58, 60, 61, 62, 63, 64, 65, 50, 66, 54, 67, 68, 1269, 74, 50, 60, 55, 75, 56, 50, 57, 58, 76, 61, 62, 63, 64, 65, 77, 66, 69, 67, 68, 69, 74, 78, 60, 79, 75, 80, 83, 82, 84, 76, 85, 86, 87, 88, 89, 77, 90, 69, 92, 93, 69, 82, 78, 94, 79, 91, 80, 83, 91, 84, 95, 85, 86, 87, 88, 89, 96, 90, 97, 92, 93, 98, 82, 101, 94, 102, 91, 103, 104, 91, 105, 95, 106, 107, 108, 109, 110, 96, 111, 97, 116, 117, 98, 118, 101, 119, 102, 120, 103, 104, 121, 105, 122, 106, 107, 108, 109, 110, 125, 111, 126, 116, 117, 127, 118, 128, 119, 129, 120, 130, 131, 121, 132, 122, 133, 134, 135, 136, 137, 125, 138, 126, 139, 140, 127, 143, 128, 145, 129, 147, 130, 131, 148, 132, 149, 133, 134, 135, 136, 137, 150, 138, 151, 139, 140, 152, 143, 153, 145, 158, 147, 159, 160, 148, 161, 149, 162, 165, 167, 169, 170, 150, 171, 151, 172, 173, 152, 174, 153, 175, 158, 176, 159, 160, 177, 161, 178, 162, 165, 167, 169, 170, 179, 171, 181, 172, 173, 183, 174, 185, 175, 187, 176, 188, 190, 177, 192, 178, 193, 198, 199, 200, 201, 179, 203, 181, 205, 207, 183, 209, 185, 210, 187, 212, 188, 190, 214, 192, 215, 193, 198, 199, 200, 201, 216, 203, 217, 205, 207, 219, 209, 221, 210, 218, 212, 222, 223, 214, 224, 215, 225, 226, 230, 235, 236, 216, 1271, 217, 238, 218, 219, 237, 221, 240, 241, 242, 222, 223, 243, 224, 244, 225, 226, 230, 235, 236, 245, 237, 249, 238, 218, 250, 251, 254, 240, 241, 242, 255, 257, 243, 258, 244, 260, 261, 259, 268, 269, 245, 237, 249, 272, 273, 250, 251, 254, 275, 276, 277, 255, 257, 259, 258, 278, 260, 261, 279, 268, 269, 282, 283, 285, 272, 273, 277, 286, 288, 275, 276, 292, 293, 299, 259, 300, 278, 302, 303, 279, 305, 309, 282, 283, 285, 310, 312, 277, 286, 288, 314, 315, 292, 293, 299, 319, 300, 320, 302, 303, 325, 305, 309, 327, 328, 332, 310, 312, 333, 334, 1273, 314, 315, 337, 338, 339, 319, 340, 320, 345, 1275, 325, 348, 349, 327, 328, 332, 350, 351, 333, 334, 335, 353, 335, 337, 338, 339, 354, 340, 335, 345, 335, 1277, 348, 349, 355, 356, 359, 350, 351, 1279, 360, 335, 353, 335, 361, 367, 368, 354, 369, 335, 370, 335, 346, 373, 346, 355, 356, 359, 374, 375, 346, 360, 346, 378, 379, 361, 367, 368, 380, 369, 382, 370, 383, 346, 373, 346, 384, 391, 392, 374, 375, 346, 393, 346, 378, 379, 395, 396, 397, 380, 400, 382, 401, 383, 402, 403, 411, 384, 391, 392, 412, 413, 414, 393, 417, 418, 419, 395, 396, 397, 420, 400, 427, 401, 428, 402, 403, 411, 429, 430, 434, 412, 413, 414, 435, 417, 418, 419, 441, 442, 1281, 420, 1283, 427, 1285, 428, 1287, 1289, 1291, 429, 430, 434, 1293, 1295, 1297, 435, 1299, 1301, 1303, 441, 442, 1305, 1307, 1309, 1311, 1313, 1315, 1317, 1319, 1321, 1323, 1325, 1327, 1329, 1331, 1333, 1335, 1337, 1339, 1341, 1343, 1345, 1347, 1349, 1351, 1353, 1355, 1357, 1359, 1361, 1363, 1365, 1367, 1369, 1371, 1373, 1375, 1377, 1379, 1381, 1383, 1385, 1387, 1389, 1391, 1393, 1395, 1397, 1399, 1401, 1403, 1405, 1407, 1409, 1411, 1413, 1415, 1417, 1419, 1421, 1423, 1425, 1427, 1429, 1431, 1433, 1435, 1437, 1439, 1441, 1443, 1445, 1447, 1449, 1451, 1453, 1455, 1457, 1459, 1461, 1463, 1465, 1467, 1469, 1471, 1473, 1475, 1477, 1479, 1481, 1483, 1485, 1487, 1489, 1491, 1493, 1495, 1497, 1499, 1501, 1503, 1505, 1507, 1509, 1511, 1513, 1515, 1517, 1519, 1521, 1523, 1525, 1527, 1529, 1531, 1533, 1535, 1537, 1539, 1541, 1543, 1545, 1547, 1549, 1551, 1553, 1555, 1557, 1559, 1561, 1563, 1565, 1567, 1569, 1571, 1573, 1575, 1577, 1579, 1581, 1583, 1585, 1587, 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1603, 1605, 1607, 1609, 1611, 1613, 1615, 1617, 1619, 1621, 1623, 1625, 1627, 1629, 1631, 1633, 1635, 1637, 1639, 1641, 1643, 1645, 1647, 1649, 1651, 1653, 1655, 1657, 1659, 1661, 1663, 1665, 1667, 1669, 1671, 1673, 1675, 1677, 1679, 1681, 1683, 1685, 1687, 1689, 1691, 1693, 1695, 1697, 1699, 1701, 1703, 1705, 1707, 1709, 1711, 1713, 1715, 1717, 1719, 1721, 1723, 1725, 1727, 1729, 1731, 1733, 1735, 1737, 1739, 1741, 1743, 1745, 1747, 1749, 1751, 1753, 1755, 1757, 1759, 1761, 1763, 1765, 1767, 1769, 1771, 1773, 1775, 1777, 1779, 1781, 1783, 1785, 1787, 1789, 1791, 1793, 1795, 1797, 1799, 1801, 1803, 1805, 1807, 1809, 1811, 1813, 1815, 1817, 1819, 1821, 1823, 1825, 1827, 1829, 1831, 1833, 1835, 1837, 1839, 1841, 1843, 1845, 1847, 1849, 1851, 1853, 1855, 1857, 1859, 1861, 1863, 1865, 1867, 1869, 1871, 1873, 1875, 1877, 1879, 1881, 1883, 1885, 1887, 1889, 1891, 1893, 1895, 1897, 1899, 1901, 1903, 1905, 1907, 1909, 1911, 1913, 1915, 1917, 1919, 1921, 1923, 1925, 1927, 1929, 1931, 1933, 1935, 1937, 1939, 1941, 1943, 1945, 1947, 1949, 1951, 1953, 1955, 1957, 1959, 1961, 1963, 1965, 1967, 1969, 1971, 1973, 1975, 1977, 1979, 1981, 1983, 1985, 1987, 1989, 1991, 1993, 1995, 1997, 1999, 2001, 2003, 2005, 2007, 2009, 2011, 2013, 2015, 2017, 2019, 2021, 2023, 2025, 2027, 2029, 2031, 2033, 2035, 2037, 2039, 2041, 2043, 2045, 2047, 2049, 2051, 2053, 2055, 2057, 2059, 2061, 2063, 2065, 2067, 2069, 2071, 2073, 2075, 2077, 2079, 2081, 2083, 2085, 2087, 2089, 2091, 2093, 2095, 2097, 2099, 2101, 2103, 2105, 2107, 2109, 2111, 2113, 2115, 2117, 2119, 2121, 2123, 2125, 2127, 2129, 2131, 2133, 2135, 2137, 2139, 2141, 2143, 2145, 2147, 2149, 2151, 2153, 2155, 2157, 2159, 2161, 2163, 2165, 2167, 2169, 2171, 2173, 2175, 2177, 2179, 2181, 2183, 2185, 2187, 2189, 2191, 2193, 2195, 2197, 2199, 2201, 2203, 2205, 2207, 2209, 2211, 2213, 2215, 2217, 2219, 2221, 2223, 2225, 2227, 2229, 2231, 2233, 2235, 2237, 2239, 2241, 2243, 2245, 2247, 2249, 2251, 2253, 2255, 2257, 2259, 2261, 2263, 2265, 2267, 2269, 2271, 2273, 2275, 2277, 2279, 2281, 2283, 2285, 2287, 2289, 2291, 2293, 2295, 2297, 2299, 2301, 2303, 2305, 2307, 2309, 2311, 2313, 2315, 2317, 2319, 2321, 2323, 2325, 2327, 2329, 2331, 2333, 2335, 2337, 2339, 2341, 2343, 2345, 2347, 2349, 2351, 2353, 2355, 2357, 2359, 2361, 2363, 2365, 2367, 2369, 2371, 2373, 2375, 2377, 2379, 2381, 2383, 2385, 2387, 2389, 2391, 2393, 2395, 2397, 2399, 2401, 2403, 2405, 2407, 2409, 2411, 2413, 2415, 2417, 2419, 2421, 2423, 2425, 2427, 2429, 2431, 2433, 2435, 2437, 2439, 2441, 2443, 2445, 2447, 2449, 2451, 2453, 2455, 2457, 2459, 2461, 2463, 2465, 2467, 2469, 2471, 2473, 2475, 2477, 2479, 2481, 2483, 2485, 2487, 2489, 2491, 2493, 2495, 2497, 2499, 2501, 2503, 2505, 2507, 2509, 2511, 2513, 2515, 2517, 2519, 2521, 2523, 2525, 2527, 2529, 2531, 2533, 2535, 2537, 2539, 2541, 2543, 2545, 2547, 2549, 2551, 2553, 2555, 2557, 2559, 2561, 2563, 2565, 2567, 2569, 2571, 2573, 2575, 2577, 2579, 2581, 2583, 2585, 2587, 2589, 2591, 2593, 2595, 2597, 2599, 2601, 2603, 2605, 2607, 2609, 2611, 2613, 2615, 2617, 2619, 2621, 2623, 2625, 2627, 2629, 2631, 2633, 2635, 2637, 2639, 2641, 2643, 2645, 2647, 2649, 2651, 2653, 2655, 2657, 2659, 2661, 2663, 2665, 2667, 2669, 2671, 2673, 2675, 2677, 2679, 2681, 2683, 2685, 2687, 2689, 2691, 2693, 2695, 2697, 2699, 2701, 2703, 2705, 2707, 2709, 2711, 2713, 2715, 2717, 2719, 2721, 2723, 2725, 2727, 2729, 2731, 2733, 2735, 2737, 2739, 2741, 2743, 2745, 2747, 2749, 2751, 2753, 2755, 2757, 2759, 2761, 2763, 2765, 2767, 2769, 2771, 2773, 2775, 2777, 2779, 2781, 2783, 2785, 2787, 2789, 2791, 2793, 2795, 2797, 2799, 2801, 2803, 2805, 2807, 2809, 2811, 2813, 2815, 2817, 2819, 2821, 2823, 2825, 2827, 2829, 2831, 2833, 2835, 2837, 2839, 2841, 2843, 2845, 2847, 2849, 2851, 2853, 2855, 2857, 2859, 2861, 2863, 2865, 2867, 2869, 2871, 2873, 2875, 2877, 2879, 2881, 2883, 2885, 2887, 2889, 2891, 2893, 2895, 2897, 2899, 2901, 2903, 2905, 2907, 2909, 2911, 2913, 2915, 2917, 2919, 2921, 2923, 2925, 2927, 2929, 2931, 2933, 2935, 2937, 2939, 2941, 2943, 2945, 2947, 2949, 2951, 2953, 2955, 2957, 2959, 2961, 2963, 2965, 2967, 2969, 2971, 2973, 2975, 2977, 2979, 2981, 2983, 2985, 2987, 2989, 2991, 2993, 2995, 2997, 2999, 3001, 3003, 3005, 3007, 3009, 3011, 3013, 3015, 3017, 3019, 3021, 3023, 3025, 3027, 3029, 3031, 3033, 3035, 3037, 3039, 3041, 3043, 3045, 3047, 3049, 3051, 3053, 3055, 3057, 3059, 3061, 3063, 3065, 3067, 3069, 3071, 3073, 3075, 3077, 3079, 3081, 3083, 3085, 3087, 3089, 3091, 3093, 3095, 3097, 3099, 3101, 3103, 3105, 3107, 3109, 3111, 3113, 3115, 3117, 3119, 3121, 3123, 3125, 3127, 3129, 3131, 3133, 3135, 3137, 3139, 3141, 3143, 3145, 3147, 3149, 3151, 3153, 3155, 3157, 3159, 3161, 3163, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3181, 3183, 3185, 3187, 3189, 3191, 3193, 3195, 3197, 3199, 3201, 3203, 3205, 3207, 3209, 3211, 3213, 3215, 3217, 3219, 3221, 3223, 3225, 3227, 3229, 3231, 3233, 3235, 3237, 3239, 3241, 3243, 3245, 3247, 3249, 3251, 3253, 3255, 3257, 3259, 3261, 3263, 3265, 3267, 3269, 3271, 3273, 3275, 3277, 3279, 3281, 3283, 3285, 3287, 3289, 3291, 3293, 3295, 3297, 3299, 3301, 3303, 3305, 3307, 3309, 3311, 3313, 3315, 3317, 3319, 3321, 3323, 3325, 3327, 3329, 3331, 3333, 3335, 3337, 3339, 3341, 3343, 3345, 3347, 3349, 3351, 3353, 3355, 3357, 3359, 3361, 3363, 3365, 3367, 3369, 3371, 3373, 3375, 3377, 3379, 3381, 3383, 3385, 3387, 3389, 3391, 3393, 3395, 3397, 3399, 3401, 3403, 3405, 3407, 3409, 3411, 3413, 3415, 3417, 3419, 3421, 3423, 3425, 3427, 3429, 3431, 3433, 3435, 3437, 3439, 3441, 3443, 3445, 3447, 3449, 3451, 3453, 3455, 3457, 3459, 3461, 3463, 3465, 3467, 3469, 3471, 3473, 3475, 3477, 3479, 3481, 3483, 3485, 3487, 3489, 3491, 3493, 3495, 3497, 3499, 3501, 3503, 3505, 3507, 3509, 3511, 3513, 3515, 3517, 3519, 3521, 3523, 3525, 3527, 3529, 3531, 3533, 3535, 3537, 3539, 3541, 3543, 3545, 3547, 3549, 3551, 3553, 3555, 3557, 3559, 3561, 3563, 3565, 3567, 3569, 3571, 3573, 3575, 3577, 3579, 3581, 3583, 3585, 3587, 3589, 3591, 3593, 3595, 3597, 3599, 3601, 3603, 3605, 3607, 3609, 3611, 3613, 3615, 3617, 3619, 3621, 3623, 3625, 3627, 3629, 3631, 3633, 3635, 3637, 3639, 3641, 3643, 3645, 3647, 3649, 3651, 3653, 3655, 3657, 3659, 3661, 3663, 3665, 3667, 3669, 3671, 3673, 3675, 3677, 3679, 3681, 3683, 3685, 3687, 3689, 3691, 3693, 3695, 3697, 3699, 3701, 3703, 3705, 3707, 3709, 3711, 3713, 3715, 3717, 3719, 3721, 3723, 3725, 3727, 3729, 3731, 3733, 3735, 3737, 3739, 3741, 3743, 3745, 3747, 3749, 3751, 3753, 3755, 3757, 3759, 3761, 3763, 3765, 3767, 3769, 3771, 3773, 3775, 3777, 3779, 3781, 3783, 3785, 3787, 3789, 3791, 3793, 3795, 3797, 3799, 3801, 3803, 3805, 3807, 3809, 3811, 3813, 3815, 3817, 3819, 3821, 3823, 3825, 3827, 3829, 3831, 3833, 3835, 3837, 3839, 3841, 3843, 3845, 3847, 3849, 3851, 3853, 3855, 3857, 3859, 3861, 3863, 3865, 3867, 3869, 3871, 3873, 3875, 3877, 3879, 3881, 3883, 3885, 3887, 3889, 3891, 3893, 3895, 3897, 3899, 3901, 3903, 3905, 3907, 3909, 3911, 3913, 3915, 3917, 3919, 3921, 3923, 3925, 3927, 3929, 3931, 3933, 3935, 3937, 3939, 3941, 3943, 3945, 3947, 3949, 3951, 3953, 3955, 3957, 3959, 3961, 3963, 3965, 3967, 3969, 3971, 3973, 3975, 3977, 3979, 3981, 3983, 3985, 3987, 3989, 3991, 3993, 3995, 3997, 3999, 4001, 4003, 4005, 4007, 4009, 4011, 4013, 4015, 4017, 4019, 4021, 4023, 4025, 4027, 4029, 4031, 4033, 4035, 4037, 4039, 4041, 4043, 4045, 4047, 4049, 4051, 4053, 4055, 4057, 4059, 4061, 4063, 4065, 4067, 4069, 4071, 4073, 4075, 4077, 4079, 4081, 4083, 4085, 4087, 4089, 4091, 4093, 4095, 4097, 4099, 4101, 4103, 4105, 4107, 4109, 4111, 4113, 4115, 4117, 4119, 4121, 4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, 4145, 4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, 4169, 4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, 4193, 4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, 4217, 4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, 4241, 4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, 4265, 4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289, 4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, 4313, 4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, 4337, 4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, 4361, 4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, 4385, 4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, 4409, 4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, 4433, 4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, 4457, 4459, 4461, 4463, 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, 4481, 4483, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, 4505, 4507, 4509, 4511, 4513, 4515, 4517, 4519, 4521, 4523, 4525, 4527, 4529, 4531, 4533, 4535, 4537, 4539, 4541, 4543, 4545, 4547, 4549, 4551, 4553, 4555, 4557, 4559, 4561, 4563, 4565, 4567, 4569, 4571, 4573, 4575, 4577, 4579, 4581, 4583, 4585, 4587, 4589, 4591, 4593, 4595, 4597, 4599, 4601, 4603, 4605, 4607, 4609, 4611, 4613, 4615, 4617, 4619, 4621, 4623, 4625, 4627, 4629, 4631, 4633, 4635, 4637, 4639, 4641, 4643, 4645, 4647, 4649, 4651, 4653, 4655, 4657, 4659, 4661, 4663, 4665, 4667, 4669, 4671, 4673, 4675, 4677, 4679, 4681, 4683, 4685, 4687, 4689, 4691, 4693, 4695, 4697, 4699, 4701, 4703, 4705, 4707, 4709, 4711, 4713, 4715, 4717, 4719, 4721, 4723, 4725, 4727, 4729, 4731, 4733, 4735, 4737, 4739, 4741, 4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, 4765, 4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, 4789, 4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, 4813, 4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, 4837, 4839, 4841, 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, 4859, 4861, 4863, 4865, 4867, 4869, 4871, 4873, 4875, 4877, 4879, 4881, 4883, 4885, 4887, 4889, 4891, 4893, 4895, 4897, 4899, 4901, 4903, 4905, 4907, 4909, 4911, 4913, 4915, 4917, 4919, 4921, 4923, 4925, 4927, 4929, 4931, 4933, 4935, 4937, 4939, 4941, 4943, 4945, 4947, 4949, 4951, 4953, 4955, 4957, 4959, 4961, 4963, 4965, 4967, 4969, 4971, 4973, 4975, 4977, 4979, 4981, 4983, 4985, 4987, 4989, 4991, 4993, 4995, 4997, 4999, 5001, 5003, 5005, 5007, 5009, 5011, 5013, 5015, 5017, 5019, 5021, 5023, 5025, 5027, 5029, 5031, 5033, 5035, 5037, 5039, 5041, 5043, 5045, 5047, 5049, 5051, 5053, 5055, 5057, 5059, 5061, 5063, 5065, 5067, 5069, 5071, 5073, 5075, 5077, 5079, 5081, 5083, 5085, 5087, 5089, 5091, 5093, 5095, 5097, 5099, 5101, 5103, 5105, 5107, 5109, 5111, 5113, 5115, 5117, 5119, 5121, 5123, 5125, 5127, 5129, 5131, 5133, 5135, 5137, 5139, 5141, 5143, 5145, 5147, 5149, 5151, 5153, 5155, 5157, 5159, 5161, 5163, 5165, 5167, 5169, 5171, 5173, 5175, 5177, 5179, 5181, 5183, 5185, 5187, 5189, 5191, 5193, 5195, 5197, 5199, 5201, 5203, 5205, 5207, 5209, 5211, 5213, 5215, 5217, 5219, 5221, 5223, 5225, 5227, 5229, 5231, 5233, 5235, 5237, 5239, 5241, 5243, 5245, 5247, 5249, 5251, 5253, 5255, 5257, 5259, 5261, 5263, 5265, 5267, 5269, 5271, 5273, 5275, 5277, 5279, 5281, 5283, 5285, 5287, 5289, 5291, 5293, 5295, 5297, 5299, 5301, 5303, 5305, 5307, 5309, 5311, 5313, 5315, 5317, 5319, 5321, 5323, 5325, 5327, 5329, 5331, 5333, 5335, 5337, 5339, 5341, 5343, 5345, 5347, 5349, 5351, 5353, 5355, 5357, 5359, 5361, 5363, 5365, 5367, 5369, 5371, 5373, 5375, 5377, 5379, 5381, 5383, 5385, 5387, 5389, 5391, 5393, 5395, 5397, 5399, 5401, 5403, 5405, 5407, 5409, 5411, 5413, 5415, 5417, 5419, 5421, 5423, 5425, 5427, 5429, 5431, 5433, 5435, 5437, 5439, 5441, 5443, 5445, 5447, 5449, 5451, 5453, 5455, 5457, 5459, 5461, 5463, 5465, 5467, 5469, 5471, 5473, 5475, 5477, 5479, 5481, 5483, 5485, 5487, 5489, 5491, 5493, 5495, 5497, 5499, 5501, 5503, 5505, 5507, 5509, 5511, 5513, 5515, 5517, 5519, 5521, 5523, 5525, 5527, 5529, 5531, 5533, 5535, 5537, 5539, 5541, 5543, 5545, 5547, 5549, 5551, 5553, 5555, 5557, 5559, 5561, 5563, 5565, 5567, 5569, 5571, 5573, 5575, 5577, 5579, 5581, 5583, 5585, 5587, 5589, 5591, 5593, 5595, 5597, 5599, 5601, 5603, 5605, 5607, 5609, 5611, 5613, 5615, 5617, 5619, 5621, 5623, 5625, 5627, 5629, 5631, 5633, 5635, 5637, 5639, 5641, 5643, 5645, 5647, 5649, 5651, 5653, 5655, 5657, 5659, 5661, 5663, 5665, 5667, 5669, 5671, 5673, 5675, 5677, 5679, 5681, 5683, 5685, 5687, 5689, 5691, 5693, 5695, 5697, 5699, 5701, 5703, 5705, 5707, 5709, 5711, 5713, 5715, 5717, 5719, 5721, 5723, 5725, 5727, 5729, 5731, 5733, 5735, 5737, 5739, 5741, 5743, 5745, 5747, 5749, 5751, 5753, 5755, 5757, 5759, 5761, 5763, 5765, 5767, 5769, 5771, 5773, 5775, 5777, 5779, 5781, 5783, 5785, 5787, 5789, 5791, 5793, 5795, 5797, 5799, 5801, 5803, 5805, 5807, 5809, 5811, 5813, 5815, 5817, 5819, 5821, 5823, 5825, 5827, 5829, 5831, 5833, 5835, 5837, 5839, 5841, 5843, 5845, 5847, 5849, 5851, 5853, 5855, 5857, 5859, 5861, 5863, 5865, 5867, 5869, 5871, 5873, 5875, 5877, 5879, 5881, 5883, 5885, 5887, 5889, 5891, 5893, 5895, 5897, 5899, 5901, 5903, 5905, 5907, 5909, 5911, 5913, 5915, 5917, 5919, 5921, 5923, 5925, 5927, 5929, 5931, 5933, 5935, 5937, 5939, 5941, 5943, 5945, 5947, 5949, 5951, 5953, 5955, 5957, 5959, 5961, 5963, 5965, 5967, 5969, 5971, 5973, 5975, 5977, 5979, 5981, 5983, 5985, 5987, 5989, 5991, 5993, 5995, 5997, 5999, 6001, 6003, 6005, 6007, 6009, 6011, 6013, 6015, 6017, 6019, 6021, 6023, 6025, 6027, 6029, 6031, 6033, 6035, 6037, 6039, 6041, 6043, 6045, 6047, 6049, 6051, 6053, 6055, 6057, 6059, 6061, 6063, 6065, 6067, 6069, 6071, 6073, 6075, 6077, 6079, 6081, 6083, 6085, 6087, 6089, 6091, 6093, 6095, 6097, 6099, 6101, 6103, 6105, 6107, 6109, 6111, 6113, 6115, 6117, 6119, 6121, 6123, 6125, 6127, 6129, 6131, 6133, 6135, 6137, 6139, 6141, 6143, 6145, 6147, 6149, 6151, 6153, 6155, 6157, 6159, 6161, 6163, 6165, 6167, 6169, 6171, 6173, 6175, 6177, 6179, 6181, 6183, 6185, 6187, 6189, 6191, 6193, 6195, 6197, 6199, 6201, 6203, 6205, 6207, 6209, 6211, 6213, 6215, 6217, 6219, 6221, 6223, 6225, 6227, 6229, 6231, 6233, 6235, 6237, 6239, 6241, 6243, 6245, 6247, 6249, 6251, 6253, 6255, 6257, 6259, 6261, 6263, 6265, 6267, 6269, 6271, 6273, 6275, 6277, 6279, 6281, 6283, 6285, 6287, 6289, 6291, 6293, 6295, 6297, 6299, 6301, 6303, 6305, 6307, 6309, 6311, 6313, 6315, 6317, 6319, 6321, 6323, 6325, 6327, 6329, 6331, 6333, 6335, 6337, 6339, 6341, 6343, 6345, 6347, 6349, 6351, 6353, 6355, 6357, 6359, 6361, 6363, 6365, 6367, 6369, 6371, 6373, 6375, 6377, 6379, 6381, 6383, 6385, 6387, 6389, 6391, 6393, 6395, 6397, 6399, 6401, 6403, 6405, 6407, 6409, 6411, 6413, 6415, 6417, 6419, 6421, 6423, 6425, 6427, 6429, 6431, 6433, 6435, 6437, 6439, 6441, 6443, 6445, 6447, 6449, 6451, 6453, 6455, 6457, 6459, 6461, 6463, 6465, 6467, 6469, 6471, 6473, 6475, 6477, 6479, 6481, 6483, 6485, 6487, 6489, 6491, 6493, 6495, 6497, 6499, 6501, 6503, 6505, 6507, 6509, 6511, 6513, 6515, 6517, 6519, 6521, 6523, 6525, 6527, 6529, 6531, 6533, 6535, 6537, 6539, 6541, 6543, 6545, 6547, 6549, 6551, 6553, 6555, 6557, 6559, 6561, 6563, 6565, 6567, 6569, 6571, 6573, 6575, 6577, 6579, 6581, 6583, 6585, 6587, 6589, 6591, 6593, 6595, 6597, 6599, 6601, 6603, 6605, 6607, 6609, 6611, 6613, 6615, 6617, 6619, 6621, 6623, 6625, 6627, 6629, 6631, 6633, 6635, 6637, 6639, 6641, 6643, 6645, 6647, 6649, 6651, 6653, 6655, 6657, 6659, 6661, 6663, 6665, 6667, 6669, 6671, 6673, 6675, 6677, 6679, 6681, 6683, 6685, 6687, 6689, 6691, 6693, 6695, 6697, 6699, 6701, 6703, 6705, 6707, 6709, 6711, 6713, 6715, 6717, 6719, 6721, 6723, 6725, 6727, 6729, 6731, 6733, 6735, 6737, 6739, 6741, 6743, 6745, 6747, 6749, 6751, 6753, 6755, 6757, 6759, 6761, 6763, 6765, 6767, 6769, 6771, 6773, 6775, 6777, 6779, 6781, 6783, 6785, 6787, 6789, 6791, 6793, 6795, 6797, 6799, 6801, 6803, 6805, 6807, 6809, 6811, 6813, 6815, 6817, 6819, 6821, 6823, 6825, 6827, 6829, 6831, 6833, 6835, 6837, 6839, 6841, 6843, 6845, 6847, 6849, 6851, 6853, 6855, 6857, 6859, 6861, 6863, 6865, 6867, 6869, 6871, 6873, 6875, 6877, 6879, 6881, 6883, 6885, 6887, 6889, 6891, 6893, 6895, 6897, 6899, 6901, 6903, 6905, 6907, 6909, 6911, 6913, 6915, 6917, 6919, 6921, 6923, 6925, 6927, 6929, 6931, 6933, 6935, 6937, 6939, 6941, 6943, 6945, 6947, 6949, 6951, 6953, 6955, 6957, 6959, 6961, 6963, 6965, 6967, 6969, 6971, 6973, 6975, 6977, 6979, 6981, 6983, 6985, 6987, 6989, 6991, 6993, 6995, 6997, 6999, 7001, 7003, 7005, 7007, 7009, 7011, 7013, 7015, 7017, 7019, 7021, 7023, 7025, 7027, 7029, 7031, 7033, 7035, 7037, 7039, 7041, 7043, 7045, 7047, 7049, 7051, 7053, 7055, 7057, 7059, 7061, 7063, 7065, 7067, 7069, 7071, 7073, 7075, 7077, 7079, 7081, 7083, 7085, 7087, 7089, 7091, 7093, 7095, 7097, 7099, 7101, 7103, 7105, 7107, 7109, 7111, 7113, 7115, 7117, 7119, 7121, 7123, 7125, 7127, 7129, 7131, 7133, 7135, 7137, 7139, 7141, 7143, 7145, 7147, 7149, 7151, 7153, 7155, 7157, 7159, 7161, 7163, 7165, 7167, 7169, 7171, 7173, 7175, 7177, 7179, 7181, 7183, 7185, 7187, 7189, 7191, 7193, 7195, 7197, 7199, 7201, 7203, 7205, 7207, 7209, 7211, 7213, 7215, 7217, 7219, 7221, 7223, 7225, 7227, 7229, 7231, 7233, 7235, 7237, 7239, 7241, 7243, 7245, 7247, 7249, 7251, 7253, 7255, 7257, 7259, 7261, 7263, 7265, 7267, 7269, 7271, 7273, 7275, 7277, 7279, 7281, 7283, 7285, 7287, 7289, 7291, 7293, 7295, 7297, 7299, 7301, 7303, 7305, 7307, 7309, 7311, 7313, 7315, 7317, 7319, 7321, 7323, 7325, 7327, 7329, 7331, 7333, 7335, 7337, 7339, 7341, 7343, 7345, 7347, 7349, 7351, 7353, 7355, 7357, 7359, 7361, 7363, 7365, 7367, 7369, 7371, 7373, 7375, 7377, 7379, 7381, 7383, 7385, 7387, 7389, 7391, 7393, 7395, 7397, 7399, 7401, 7403, 7405, 7407, 7409, 7411, 7413, 7415, 7417, 7419, 7421, 7423, 7425, 7427, 7429, 7431, 7433, 7435, 7437, 7439, 7441, 7443, 7445, 7447, 7449, 7451, 7453, 7455, 7457, 7459, 7461, 7463, 7465, 7467, 7469, 7471, 7473, 7475, 7477, 7479, 7481, 7483, 7485, 7487, 7489, 7491, 7493, 7495, 7497, 7499, 7501, 7503, 7505, 7507, 7509, 7511, 7513, 7515, 7517, 7519, 7521, 7523, 7525, 7527, 7529, 7531, 7533, 7535, 7537, 7539, 7541, 7543, 7545, 7547, 7549, 7551, 7553, 7555, 7557, 7559, 7561, 7563, 7565, 7567, 7569, 7571, 7573, 7575, 7577, 7579, 7581, 7583, 7585, 7587, 7589, 7591, 7593, 7595, 7597, 7599, 7601, 7603, 7605, 7607, 7609, 7611, 7613, 7615, 7617, 7619, 7621, 7623, 7625, 7627, 7629, 7631, 7633, 7635, 7637, 7639, 7641, 7643, 7645, 7647, 7649, 7651, 7653, 7655, 7657, 7659, 7661, 7663, 7665, 7667, 7669, 7671, 7673, 7675, 7677, 7679, 7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 7829, 7831, 7833, 7835, 7837, 7839, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929, 7931, 7933, 7935, 7937, 7939, 7941, 7943, 7945, 7947, 7949, 7951, 7953, 7955, 7957, 7959, 7961, 7963, 7965, 7967, 7969, 7971, 7973, 7975, 7977, 7979, 7981, 7983, 7985, 7987, 7989, 7991, 7993, 7995, 7997, 7999, 8001, 8003, 8005, 8007, 8009, 8011, 8013, 8015, 8017, 8019, 8021, 8023, 8025, 8027, 8029, 8031, 8033, 8035, 8037, 8039, 8041, 8043, 8045, 8047, 8049, 8051, 8053, 8055, 8057, 8059, 8061, 8063, 8065, 8067, 8069, 8071, 8073, 8075, 8077, 8079, 8081, 8083, 8085, 8087, 8089, 8091, 8093, 8095, 8097, 8099, 8101, 8103, 8105, 8107, 8109, 8111, 8113, 8115, 8117, 8119, 8121, 8123, 8125, 8127, 8129, 8131, 8133, 8135, 8137, 8139, 8141, 8143, 8145, 8147, 8149, 8151, 8153, 8155, 8157, 8159, 8161, 8163, 8165, 8167, 8169, 8171, 8173, 8175, 8177, 8179, 8181, 8183, 8185, 8187, 8189, 8191, 8193, 8195, 8197, 8199, 8201, 8203, 8205, 8207, 8209, 8211, 8213, 8215, 8217, 8219, 8221, 8223, 8225, 8227, 8229, 8231, 8233, 8235, 8237, 8239, 8241, 8243, 8245, 8247, 8249, 8251, 8253, 8255, 8257, 8259, 8261, 8263, 8265, 8267, 8269, 8271, 8273, 8275, 8277, 8279, 8281, 8283, 8285, 8287, 8289, 8291, 8293, 8295, 8297, 8299, 8301, 8303, 8305, 8307, 8309, 8311, 8313, 8315, 8317, 8319, 8321, 8323, 8325, 8327, 8329, 8331, 8333, 8335, 8337, 8339, 8341, 8343, 8345, 8347, 8349, 8351, 8353, 8355, 8357, 8359, 8361, 8363, 8365, 8367, 8369, 8371, 8373, 8375, 8377, 8379, 8381, 8383, 8385, 8387, 8389, 8391, 8393, 8395, 8397, 8399, 8401, 8403, 8405, 8407, 8409, 8411, 8413, 8415, 8417, 8419, 8421, 8423, 8425, 8427, 8429, 8431, 8433, 8435, 8437, 8439, 8441, 8443, 8445, 8447, 8449, 8451, 8453, 8455, 8457, 8459, 8461, 8463, 8465, 8467, 8469, 8471, 8473, 8475, 8477, 8479, 8481, 8483, 8485, 8487, 8489, 8491, 8493, 8495, 8497, 8499, 8501, 8503, 8505, 8507, 8509, 8511, 8513, 8515, 8517, 8519, 8521, 8523, 8525, 8527, 8529, 8531, 8533, 8535, 8537, 8539, 8541, 8543, 8545, 8547, 8549, 8551, 8553, 8555, 8557, 8559, 8561, 8563, 8565, 8567, 8569, 8571, 8573, 8575, 8577, 8579, 8581, 8583, 8585, 8587, 8589, 8591, 8593, 8595, 8597, 8599, 8601, 8603, 8605, 8607, 8609, 8611, 8613, 8615, 8615, 8615, 8616, 8616, 8616, 8617, 8618, 8619, 8619, 8620, 8621, 8622, 8623, 8624, 8625, 8626, 8627, 8628, 8629, 8630, 8631, 8632, 8633, 8634, 8635, 8636, 8637, 8638, 8639, 8640, 8641, 8642, 8643, 8644, 8645, 8646, 8647, 8648, 8649, 8650, 8651, 8652, 8653, 8654, 8655, 8656, 8657, 8658, 8659, 8660, 8661, 8662, 8663, 8664, 8665, 8666, 8667, 8668, 8669, 8670, 8671, 8672, 8673, 8674, 8675, 8676, 8677, 8678, 8679, 8680, 8681, 8682, 8683, 8684, 8685, 8686, 8687, 8688, 8689, 8690, 8691, 8692, 8693, 8694, 8695, 8696, 8697, 8698, 8699, 8700, 8701, 8702, 8703, 8704, 8705, 8706, 8707, 8708, 8709, 8710, 8711, 8712, 8713, 8714, 8715, 8716, 8717, 8718, 8719, 8720, 8721, 8722, 8723, 8724, 8725, 8726, 8727, 8728, 8729, 8730, 8731, 8732, 8733, 8734, 8735, 8736, 8737, 8738, 8739, 8740, 8741, 8742, 8743, 8744, 8745, 8746, 8747, 8748, 8749, 8750, 8751, 8752, 8753, 8754, 8755, 8756, 8757, 8758, 8759, 8760, 8761, 8762, 8763, 8764, 8765, 8766, 8767, 8768, 8769, 8770, 8771, 8772, 8773, 8774, 8775, 8776, 8777, 8778, 8779, 8780, 8781, 8782, 8783, 8784, 8785, 8786, 8787, 8788, 8789, 8790, 8791, 8792, 8793, 8794, 8795, 8796, 8797, 8798, 8799, 8800, 8801, 8802, 8803, 8804, 8805, 8806, 8807, 8808, 8809, 8810, 8811, 8812, 8813, 8814, 8815, 8816, 8817, 8818, 8819, 8820, 8821, 8822, 8823, 8824, 8825, 8826, 8827, 8828, 8829, 8830, 8831, 8832, 8833, 8834, 8835, 8836, 8837, 8838, 8839, 8840, 8841, 8842, 8843, 8844, 8845, 8846, 8847, 8848, 8849, 8850, 8851, 8852, 8853, 8854, 8855, 8856, 8857, 8858, 8859, 8860, 8861, 8862, 8863, 8864, 8865, 8866, 8867, 8868, 8869, 8870, 8871, 8872, 8873, 8874, 8875, 8876, 8877, 8878, 8879, 8880, 8881, 8882, 8883, 8884, 8885, 8886, 8887, 8888, 8889, 8890, 8891, 8892, 8893, 8894, 8895, 8896, 8897, 8898, 8899, 8900, 8901, 8902, 8903, 8904, 8905, 8906, 8907, 8908, 8909, 8910, 8911, 8912, 8913, 8914, 8915, 8916, 8917, 8918, 8919, 8920, 8921, 8922, 8923, 8924, 8925, 8926, 8927, 8928, 8929, 8930, 8931, 8932, 8933, 8934, 8935, 8936, 8937, 8938, 8939, 8940, 8941, 8942, 8943, 8944, 8945, 8946, 8947, 8948, 8949, 8950, 8951, 8952, 8953, 8954, 8955, 8956, 8957, 8958, 8959, 8960, 8961, 8962, 8963, 8964, 8965, 8966, 8967, 8968, 8969, 8970, 8971, 8972, 8973, 8974, 8975, 8976, 8977, 8978, 8979, 8980, 8981, 8982, 8983, 8984, 8985, 8986, 8987, 8988, 8989, 8990, 8991, 8992, 8993, 8994, 8995, 8996, 8997, 8998, 8999, 9000, 9001, 9002, 9003, 9004, 9005, 9006, 9007, 9008, 9009, 9010, 9011, 9012, 9013, 9014, 9015, 9016, 9017, 9018, 9019, 9020, 9021, 9022, 9023, 9024, 9025, 9026, 9027, 9028, 9029, 9030, 9031, 9032, 9033, 9034, 9035, 9036, 9037, 9038, 9039, 9040, 9041, 9042, 9043, 9044, 9045, 9046, 9047, 9048, 9049, 9050, 9051, 9052, 9053, 9054, 9055, 9056, 9057, 9058, 9059, 9060, 9061, 9062, 9063, 9064, 9065, 9066, 9067, 9068, 9069, 9070, 9071, 9072, 9073, 9074, 9075, 9076, 9077, 9078, 9079, 9080, 9081, 9082, 9083, 9084, 9085, 9086, 9087, 9088, 9089, 9090, 9091, 9092, 9093, 9094, 9095, 9096, 9097, 9098, 9099, 9100, 9101, 9102, 9103, 9104, 9105, 9106, 9107, 9108, 9109, 9110, 9111, 9112, 9113, 9114, 9115, 9116, 9117, 9118, 9119, 9120, 9121, 9122, 9123, 9124, 9125, 9126, 9127, 9128, 9129, 9130, 9131, 9132, 9133, 9134, 9135, 9136, 9137, 9138, 9139, 9140, 9141, 9142, 9143, 9144, 9145, 9146, 9147, 9148, 9149, 9150, 9151, 9152, 9153, 9154, 9155, 9156, 9157, 9158, 9159, 9160, 9161, 9162, 9163, 9164, 9165, 9166, 9167, 9168, 9169, 9170, 9171, 9172, 9173, 9174, 9175, 9176, 9177, 9178, 9179, 9180, 9181, 9182, 9183, 9184, 9185, 9186, 9187, 9188, 9189, 9190, 9191, 9192, 9193, 9194, 9195, 9196, 9197, 9198, 9199, 9200, 9201, 9202, 9203, 9204, 9205, 9206, 9207, 9208, 9209, 9210, 9211, 9212, 9213, 9214, 9215, 9216, 9217, 9218, 9219, 9220, 9221, 9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229, 9230, 9231, 9232, 9233, 9234, 9235, 9236, 9237, 9238, 9239, 9240, 9241, 9242, 9243, 9244, 9245, 9246, 9247, 9248, 9249, 9250, 9251, 9252, 9253, 9254, 9255, 9256, 9257, 9258, 9259, 9260, 9261, 9262, 9263, 9264, 9265, 9266, 9267, 9268, 9269, 9270, 9271, 9272, 9273, 9274, 9275, 9276, 9277, 9278, 9279, 9280, 9281, 9282, 9283, 9284, 9285, 9286, 9287, 9288, 9289, 9290, 9291, 9292, 9293, 9294, 9295, 9296, 9297, 9298, 9299, 9300, 9301, 9302, 9303, 9304, 9305, 9306, 9307, 9308, 9309, 9310, 9311, 9312, 9313, 9314, 9315, 9316, 9317, 9318, 9319, 9320, 9321, 9322, 9323, 9324, 9325, 9326, 9327, 9328, 9329, 9330, 9331, 9332, 9333, 9334, 9335, 9336, 9337, 9338, 9339, 9340, 9341, 9342, 9343, 9344, 9345, 9346, 9347, 9348, 9349, 9350, 9351, 9352, 9353, 9354, 9355, 9356, 9357, 9358, 9359, 9360, 9361, 9362, 9363, 9364, 9365, 9366, 9367, 9368, 9369, 9370, 9371, 9372, 9373, 9374, 9375, 9376, 9377, 9378, 9379, 9380, 9381, 9382, 9383, 9384, 9385, 9386, 9387, 9388, 9389, 9390, 9391, 9392, 9393, 9394, 9395, 9396, 9397, 9398, 9399, 9400, 9401, 9402, 9403, 9404, 9405, 9406, 9407, 9408, 9409, 9410, 9411, 9412, 9413, 9414, 9415, 9416, 9417, 9418, 9419, 9420, 9421, 9422, 9423, 9424, 9425, 9426, 9427, 9428, 9429, 9430, 9431, 9432, 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, 9441, 9442, 9443, 9444, 9445, 9446, 9447, 9448, 9449, 9450, 9451, 9452, 9453, 9454, 9455, 9456, 9457, 9458, 9459, 9460, 9461, 9462, 9463, 9464, 9465, 9466, 9467, 9468, 9469, 9470, 9471, 9472, 9473, 9474, 9475, 9476, 9477, 9478, 9479, 9480, 9481, 9482, 9483, 9484, 9485, 9486, 9487, 9488, 9489, 9490, 9491, 9492, 9493, 9494, 9495, 9496, 9497, 9498, 9499, 9500, 9501, 9502, 9503, 9504, 9505, 9506, 9507, 9508, 9509, 9510, 9511, 9512, 9513, 9514, 9515, 9516, 9517, 9518, 9519, 9520, 9521, 9522, 9523, 9524, 9525, 9526, 9527, 9528, 9529, 9530, 9531, 9532, 9533, 9534, 9535, 9536, 9537, 9538, 9539, 9540, 9541, 9542, 9543, 9544, 9545, 9546, 9547, 9548, 9549, 9550, 9551, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9581, 9582, 9583, 9584, 9585, 9586, 9587, 9588, 9589, 9590, 9591, 9592, 9593, 9594, 9595, 9596, 9597, 9598, 9599, 9600, 9601, 9602, 9603, 9604, 9605, 9606, 9607, 9608, 9609, 9610, 9611, 9612, 9613, 9614, 9615, 9616, 9617, 9618, 9619, 9620, 9621, 9622, 9623, 9624, 9625, 9626, 9627, 9628, 9629, 9630, 9631, 9632, 9633, 9634, 9635, 9636, 9637, 9638, 9639, 9640, 9641, 9642, 9643, 9644, 9645, 9646, 9647, 9648, 9649, 9650, 9651, 9652, 9653, 9654, 9655, 9656, 9657, 9658, 9659, 9660, 9661, 9662, 9663, 9664, 9665, 9666, 9667, 9668, 9669, 9670, 9671, 9672, 9673, 9674, 9675, 9676, 9677, 9678, 9679, 9680, 9681, 9682, 9683, 9684, 9685, 9686, 9687, 9688, 9689, 9690, 9691, 9692, 9693, 9694, 9695, 9696, 9697, 9698, 9699, 9700, 9701, 9702, 9703, 9704, 9705, 9706, 9707, 9708, 9709, 9710, 9711, 9712, 9713, 9714, 9715, 9716, 9717, 9718, 9719, 9720, 9721, 9722, 9723, 9724, 9725, 9726, 9727, 9728, 9729, 9730, 9731, 9732, 9733, 9734, 9735, 9736, 9737, 9738, 9739, 9740, 9741, 9742, 9743, 9744, 9745, 9746, 9747, 9748, 9749, 9750, 9751, 9752, 9753, 9754, 9755, 9756, 9757, 9758, 9759, 9760, 9761, 9762, 9763, 9764, 9765, 9766, 9767, 9768, 9769, 9770, 9771, 9772, 9773, 9774, 9775, 9776, 9777, 9778, 9779, 9780, 9781, 9782, 9783, 9784, 9785, 9786, 9787, 9788, 9789, 9790, 9791, 9792, 9793, 9794, 9795, 9796, 9797, 9798, 9799, 9800, 9801, 9802, 9803, 9804, 9805, 9806, 9807, 9808, 9809, 9810, 9811, 9812, 9813, 9814, 9815, 9816, 9817, 9818, 9819, 9820, 9821, 9822, 9823, 9824, 9825, 9826, 9827, 9828, 9829, 9830, 9831, 9832, 9833, 9834, 9835, 9836, 9837, 9838, 9839, 9840, 9841, 9842, 9843, 9844, 9845, 9846, 9847, 9848, 9849, 9850, 9851, 9852, 9853, 9854, 9855, 9856, 9857, 9858, 9859, 9860, 9861, 9862, 9863, 9864, 9865, 9866, 9867, 9868, 9869, 9870, 9871, 9872, 9873, 9874, 9875, 9876, 9877, 9878, 9879, 9880, 9881, 9882, 9883, 9884, 9885, 9886, 9887, 9888, 9889, 9890, 9891, 9892, 9893, 9894, 9895, 9896, 9897, 9898, 9899, 9900, 9901, 9902, 9903, 9904, 9905, 9906, 9907, 9908, 9909, 9910, 9911, 9912, 9913, 9914, 9915, 9916, 9917, 9918, 9919, 9920, 9921, 9922, 9923, 9924, 9925, 9926, 9927, 9928, 9929, 9930, 9931, 9932, 9933, 9934, 9935, 9936, 9937, 9938, 9939, 9940, 9941, 9942, 9943, 9944, 9945, 9946, 9947, 9948, 9949, 9950, 9951, 9952, 9953, 9954, 9955, 9956, 9957, 9958, 9959, 9960, 9961, 9962, 9963, 9964, 9965, 9966, 9967, 9968, 9969, 9970, 9971, 9972, 9973, 9974, 9975, 9976, 9977, 9978, 9979, 9980, 9981, 9982, 9983, 9984, 9985, 9986, 9987, 9988, 9989, 9990, 9991, 9992, 9993, 9994, 9995, 9996, 9997, 9998, 9999,10000,10001,10002,10003,10004,10005,10006,10007, 10008,10009,10010,10011,10012,10013,10014,10015,10016,10017, 10018,10019,10020,10021,10022,10023,10024,10025,10026,10027, 10028,10029,10030,10031,10032,10033,10034,10035,10036,10037, 10038,10039,10040,10041,10042,10043,10044,10045,10046,10047, 10048,10049,10050,10051,10052,10053,10054,10055,10056,10057, 10058,10059,10060,10061,10062,10063,10064,10065,10066,10067, 10068,10069,10070,10071,10072,10073,10074,10075,10076,10077, 10078,10079,10080,10081,10082,10083,10084,10085,10086,10087, 10088,10089,10090,10091,10092,10093,10094,10095,10096,10097, 10098,10099,10100,10101,10102,10103,10104,10105,10106,10107, 10108,10109,10110,10111,10112,10113,10114,10115,10116,10117, 10118,10119,10120,10121,10122,10123,10124,10125,10126,10127, 10128,10129,10130,10131,10132,10133,10134,10135,10136,10137, 10138,10139,10140,10141,10142,10143,10144,10145,10146,10147, 10148,10149,10150,10151,10152,10153,10154,10155,10156,10157, 10158,10159,10160,10161,10162,10163,10164,10165,10166,10167, 10168,10169,10170,10171,10172,10173,10174,10175,10176,10177, 10178,10179,10180,10181,10182,10183,10184,10185,10186,10187, 10188,10189,10190,10191,10192,10193,10194,10195,10196,10197, 10198,10199,10200,10201,10202,10203,10204,10205,10206,10207, 10208,10209,10210,10211,10212,10213,10214,10215,10216,10217, 10218,10219,10220,10221,10222,10223,10224,10225,10226,10227, 10228,10229,10230,10231,10232,10233,10234,10235,10236,10237, 10238,10239,10240,10241,10242,10243,10244,10245,10246,10247, 10248,10249,10250,10251,10252,10253,10254,10255,10256,10257, 10258,10259,10260,10261,10262,10263,10264,10265,10266,10267, 10268,10269,10270,10271,10272,10273,10274,10275,10276,10277, 10278,10279,10280,10281,10282,10283,10284,10285,10286,10287, 10288,10289,10290,10291,10292,10293,10294,10295,10296,10297, 10298,10299,10300,10301,10302,10303,10304,10305,10306,10307, 10308,10309,10310,10311,10312,10313,10314,10315,10316,10317, 10318,10319,10320,10321,10322,10323,10324,10325,10326,10327, 10328,10329,10330,10331,10332,10333,10334,10335,10336,10337, 10338,10339,10340,10341,10342,10343,10344,10345,10346,10347, 10348,10349,10350,10351,10352,10353,10354,10355,10356,10357, 10358,10359,10360,10361,10362,10363,10364,10365,10366,10367, 10368,10369,10370,10371,10372,10373,10374,10375,10376,10377, 10378,10379,10380,10381,10382,10383,10384,10385,10386,10387, 10388,10389,10390,10391,10392,10393,10394,10395,10396,10397, 10398,10399,10400,10401,10402,10403,10404,10405,10406,10407, 10408,10409,10410,10411,10412,10413,10414,10415,10416,10417, 10418,10419,10420,10421,10422,10423,10424,10425,10426,10427, 10428,10429,10430,10431,10432,10433,10434,10435,10436,10437, 10438,10439,10440,10441,10442,10443,10444,10445,10446,10447, 10448,10449,10450,10451,10452,10453,10454,10455,10456,10457, 10458,10459,10460,10461,10462,10463,10464,10465,10466,10467, 10468,10469,10470,10471,10472,10473,10474,10475,10476,10477, 10478,10479,10480,10481,10482,10483,10484,10485,10486,10487, 10488,10489,10490,10491,10492,10493,10494,10495,10496,10497, 10498,10499,10500,10501,10502,10503,10504,10505,10506,10507, 10508,10509,10510,10511,10512,10513,10514,10515,10516,10517, 10518,10519,10520,10521,10522,10523,10524,10525,10526,10527, 10528,10529,10530,10531,10532,10533,10534,10535,10536,10537, 10538,10539,10540,10541,10542,10543,10544,10545,10546,10547, 10548,10549,10550,10551,10552,10553,10554,10555,10556,10557, 10558,10559,10560,10561,10562,10563,10564,10565,10566,10567, 10568,10569,10570,10571,10572,10573,10574,10575,10576,10577, 10578,10579,10580,10581,10582,10583,10584,10585,10586,10587, 10588,10589,10590,10591,10592,10593,10594,10595,10596,10597, 10598,10599,10600,10601,10602,10603,10604,10605,10606,10607, 10608,10609,10610,10611,10612,10613,10614,10615,10616,10617, 10618,10619,10620,10621,10622,10623,10624,10625,10626,10627, 10628,10629,10630,10631,10632,10633,10634,10635,10636,10637, 10638,10639,10640,10641,10642,10643,10644,10645,10646,10647, 10648,10649,10650,10651,10652,10653,10654,10655,10656,10657, 10658,10659,10660,10661,10662,10663,10664,10665,10666,10667, 10668,10669,10670,10671,10672,10673,10674,10675,10676,10677, 10678,10679,10680,10681,10682,10683,10684,10685,10686,10687, 10688,10689,10690,10691,10692,10693,10694,10695,10696,10697, 10698,10699,10700,10701,10702,10703,10704,10705,10706,10707, 10708,10709,10710,10711,10712,10713,10714,10715,10716,10717, 10718,10719,10720,10721,10722,10723,10724,10725,10726,10727, 10728,10729,10730,10731,10732,10733,10734,10735,10736,10737, 10738,10739,10740,10741,10742,10743,10744,10745,10746,10747, 10748,10749,10750,10751,10752,10753,10754,10755,10756,10757, 10758,10759,10760,10761,10762,10763,10764,10765,10766,10767, 10768,10769,10770,10771,10772,10773,10774,10775,10776,10777, 10778,10779,10780,10781,10782,10783,10784,10785,10786,10787, 10788,10789,10790,10791,10792,10793,10794,10795,10796,10797, 10798,10799,10800,10801,10802,10803,10804,10805,10806,10807, 10808,10809,10810,10811,10812,10813,10814,10815,10816,10817, 10818,10819,10820,10821,10822,10823,10824,10825,10826,10827, 10828,10829,10830,10831,10832,10833,10834,10835,10836,10837, 10838,10839,10840,10841,10842,10843,10844,10845,10846,10847, 10848,10849,10850,10851,10852,10853,10854,10855,10856,10857, 10858,10859,10860,10861,10862,10863,10864,10865,10866,10867, 10868,10869,10870,10871,10872,10873,10874,10875,10876,10877, 10878,10879,10880,10881,10882,10883,10884,10885,10886,10887, 10888,10889,10890,10891,10892,10893,10894,10895,10896,10897, 10898,10899,10900,10901,10902,10903,10904,10905,10906,10907, 10908,10909,10910,10911,10912,10913,10914,10915,10916,10917, 10918,10919,10920,10921,10922,10923,10924,10925,10926,10927, 10928,10929,10930,10931,10932,10933,10934,10935,10936,10937, 10938,10939,10940,10941,10942,10943,10944,10945,10946,10947, 10948,10949,10950,10951,10952,10953,10954,10955,10956,10957, 10958,10959,10960,10961,10962,10963,10964,10965,10966,10967, 10968,10969,10970,10971,10972,10973,10974,10975,10976,10977, 10978,10979,10980,10981,10982,10983,10984,10985,10986,10987, 10988,10989,10990,10991,10992,10993,10994,10995,10996,10997, 10998,10999,11000,11001,11002,11003,11004,11005,11006,11007, 11008,11009,11010,11011,11012,11013,11014,11015,11016,11017, 11018,11019,11020,11021,11022,11023,11024,11025,11026,11027, 11028,11029,11030,11031,11032,11033,11034,11035,11036,11037, 11038,11039,11040,11041,11042,11043,11044,11045,11046,11047, 11048,11049,11050,11051,11052,11053,11054,11055,11056,11057, 11058,11059,11060,11061,11062,11063,11064,11065,11066,11067, 11068,11069,11070,11071,11072,11073,11074,11075,11076,11077, 11078,11079,11080,11081,11082,11083,11084,11085,11086,11087, 11088,11089,11090,11091,11092,11093,11094,11095,11096,11097, 11098,11099,11100,11101,11102,11103,11104,11105,11106,11107, 11108,11109,11110,11111,11112,11113,11114,11115,11116,11117, 11118,11119,11120,11121,11122,11123,11124,11125,11126,11127, 11128,11129,11130,11131,11132,11133,11134,11135,11136,11137, 11138,11139,11140,11141,11142,11143,11144,11145,11146,11147, 11148,11149,11150,11151,11152,11153,11154,11155,11156,11157, 11158,11159,11160,11161,11162,11163,11164,11165,11166,11167, 11168,11169,11170,11171,11172,11173,11174,11175,11176,11177, 11178,11179,11180,11181,11182,11183,11184,11185,11186,11187, 11188,11189,11190,11191,11192,11193,11194,11195,11196,11197, 11198,11199,11200,11201,11202,11203,11204,11205,11206,11207, 11208,11209,11210,11211,11212,11213,11214,11215,11216,11217, 11218,11219,11220,11221,11222,11223,11224,11225,11226,11227, 11228,11229,11230,11231,11232,11233,11234,11235,11236,11237, 11238,11239,11240,11241,11242,11243,11244,11245,11246,11247, 11248,11249,11250,11251,11252,11253,11254,11255,11256,11257, 11258,11259,11260,11261,11262,11263,11264,11265,11266,11267, 11268,11269,11270,11271,11272,11273,11274,11275,11276,11277, 11278,11279,11280,11281,11282,11283,11284,11285,11286,11287, 11288,11289,11290,11291,11292,11293,11294,11295,11296,11297, 11298,11299,11300,11301,11302,11303,11304,11305,11306,11307, 11308,11309,11310,11311,11312,11313,11314,11315,11316,11317, 11318,11319,11320,11321,11322,11323,11324,11325,11326,11327, 11328,11329,11330,11331,11332,11333,11334,11335,11336,11337, 11338,11339,11340,11341,11342,11343,11344,11345,11346,11347, 11348,11349,11350,11351,11352,11353,11354,11355,11356,11357, 11358,11359,11360,11361,11362,11363,11364,11365,11366,11367, 11368,11369,11370,11371,11372,11373,11374,11375,11376,11377, 11378,11379,11380,11381,11382,11383,11384,11385,11386,11387, 11388,11389,11390,11391,11392,11393,11394,11395,11396,11397, 11398,11399,11400,11401,11402,11403,11404,11405,11406,11407, 11408,11409,11410,11411,11412,11413,11414,11415,11416,11417, 11418,11419,11420,11421,11422,11423,11424,11425,11426,11427, 11428,11429,11430,11431,11432,11433,11434,11435,11436,11437, 11438,11439,11440,11441,11442,11443,11444,11445,11446,11447, 11448,11449,11450,11451,11452,11453,11454,11455,11456,11457, 11458,11459,11460,11461,11462,11463,11464,11465,11466,11467, 11468,11469,11470,11471,11472,11473,11474,11475,11476,11477, 11478,11479,11480,11481,11482,11483,11484,11485,11486,11487, 11488,11489,11490,11491,11492,11493,11494,11495,11496,11497, 11498,11499,11500,11501,11502,11503,11504,11505,11506,11507, 11508,11509,11510,11511,11512,11513,11514,11515,11516,11517, 11518,11519,11520,11521,11522,11523,11524,11525,11526,11527, 11528,11529,11530,11531,11532,11533,11534,11535,11536,11537, 11538,11539,11540,11541,11542,11543,11544,11545,11546,11547, 11548,11549,11550,11551,11552,11553,11554,11555,11556,11557, 11558,11559,11560,11561,11562,11563,11564,11565,11566,11567, 11568,11569,11570,11571,11572,11573,11574,11575,11576,11577, 11578,11579,11580,11581,11582,11583,11584,11585,11586,11587, 11588,11589,11590,11591,11592,11593,11594,11595,11596,11597, 11598,11599,11600,11601,11602,11603,11604,11605,11606,11607, 11608,11609,11610,11611,11612,11613,11614,11615,11616,11617, 11618,11619,11620,11621,11622,11623,11624,11625,11626,11627, 11628,11629,11630,11631,11632,11633,11634,11635,11636,11637, 11638,11639,11640,11641,11642,11643,11644,11645,11646,11647, 11648,11649,11650,11651,11652,11653,11654,11655,11656,11657, 11658,11659,11660,11661,11662,11663,11664,11665,11666,11667, 11668,11669,11670,11671,11672,11673,11674,11675,11676,11677, 11678,11679,11680,11681,11682,11683,11684,11685,11686,11687, 11688,11689,11690,11691,11692,11693,11694,11695,11696,11697, 11698,11699,11700,11701,11702,11703,11704,11705,11706,11707, 11708,11709,11710,11711,11712,11713,11714,11715,11716,11717, 11718,11719,11720,11721,11722,11723,11724,11725,11726,11727, 11728,11729,11730,11731,11732,11733,11734,11735,11736,11737, 11738,11739,11740,11741,11742,11743,11744,11745,11746,11747, 11748,11749,11750,11751,11752,11753,11754,11755,11756,11757, 11758,11759,11760,11761,11762,11763,11764,11765,11766,11767, 11768,11769,11770,11771,11772,11773,11774,11775,11776,11777, 11778,11779,11780,11781,11782,11783,11784,11785,11786,11787, 11788,11789,11790,11791,11792,11793,11794,11795,11796,11797, 11798,11799,11800,11801,11802,11803,11804,11805,11806,11807, 11808,11809,11810,11811,11812,11813,11814,11815,11816,11817, 11818,11819,11820,11821,11822,11823,11824,11825,11826,11827, 11828,11829,11830,11831,11832,11833,11834,11835,11836,11837, 11838,11839,11840,11841,11842,11843,11844,11845,11846,11847, 11848,11849,11850,11851,11852,11853,11854,11855,11856,11857, 11858,11859,11860,11861,11862,11863,11864,11865,11866,11867, 11868,11869,11870,11871,11872,11873,11874,11875,11876,11877, 11878,11879,11880,11881,11882,11883,11884,11885,11886,11887, 11888,11889,11890,11891,11892,11893,11894,11895,11896,11897, 11898,11899,11900,11901,11902,11903,11904,11905,11906,11907, 11908,11909,11910,11911,11912,11913,11914,11915,11916,11917, 11918,11919,11920,11921,11922,11923,11924,11925,11926,11927, 11928,11929,11930,11931,11932,11933,11934,11935,11936,11937, 11938,11939,11940,11941,11942,11943,11944,11945,11946,11947, 11948,11949,11950,11951,11952,11953,11954,11955,11956,11957, 11958,11959,11960,11961,11962,11963,11964,11965,11966,11967, 11968,11969,11970,11971,11972,11973,11974,11975,11976,11977, 11978,11979,11980,11981,11982,11983,11984,11985,11986,11987, 11988,11989,11990,11991,11992,11993,11994,11995,11996,11997, 11998,11999,12000,12001,12002,12003,12004,12005,12006,12007, 12008,12009,12010,12011,12012,12013,12014,12015,12016,12017, 12018,12019,12020,12021,12022,12023,12024,12025,12026,12027, 12028,12029,12030,12031,12032,12033,12034,12035,12036,12037, 12038,12039,12040,12041,12042,12043,12044,12045,12046,12047, 12048,12049,12050,12051,12052,12053,12054,12055,12056,12057, 12058,12059,12060,12061,12062,12063,12064,12065,12066,12067, 12068,12069,12070,12071,12072,12073,12074,12075,12076,12077, 12078,12079,12080,12081,12082,12083,12084,12085,12086,12087, 12088,12089,12090,12091,12092,12093,12094,12095,12096,12097, 12098,12099,12100,12101,12102,12103,12104,12105,12106,12107, 12108,12109,12110,12111,12112,12113,12114,12115,12116,12117, 12118,12119,12120,12121,12122,12123,12124,12125,12126,12127, 12128,12129,12130,12131,12132,12133,12134,12135,12136,12137, 12138,12139,12140,12141,12142,12143,12144,12145,12146,12147, 12148,12149,12150,12151,12152,12153,12154,12155,12156,12157, 12158,12159,12160,12161,12162,12163,12164,12165,12166,12167, 12168,12169,12170,12171,12172,12173,12174,12175,12176,12177, 12178,12179,12180,12181,12182,12183,12184,12185,12186,12187, 12188,12189,12190,12191,12192,12193,12194,12195,12196,12197, 12198,12199,12200,12201,12202,12203,12204,12205,12206,12207, 12208,12209,12210,12211,12212,12213,12214,12215,12216,12217, 12218,12219,12220,12221,12222,12223,12224,12225,12226,12227, 12228,12229,12230,12231,12232,12233,12234,12235,12236,12237, 12238,12239,12240,12241,12242,12243,12244,12245,12246,12247, 12248,12249,12250,12251,12252,12253,12254,12255,12256,12257, 12258,12259,12260,12261,12262,12263,12264,12265,12266,12267, 12268,12269,12270,12271,12272,12273,12274,12275,12276,12277, 12278,12279,12280,12281,12282,12283,12284,12285,12286,12287, 12288,12289,12290,12291,12292,12293,12294,12295,12296,12297, 12298,12299,12300,12301,12302,12303,12304,12305,12306,12307, 12308,12309,12310,12311,12312,12313,12314,12315,12316,12317, 12318,12319,12320,12321,12322,12323,12324,12325,12326,12327, 12328,12329,12330,12331,12332,12333,12334,12335,12336,12337, 12338,12339,12340,12341,12342,12343,12344,12345,12346,12347, 12348,12349,12350,12351,12352,12353,12354,12355,12356,12357, 12358,12359,12360,12361,12362,12363,12364,12365,12366,12367, 12368,12369,12370,12371,12372,12373,12374,12375,12376,12377, 12378,12379,12380,12381,12382,12383,12384,12385,12386,12387, 12388,12389,12390,12391,12392,12393,12394,12395,12396,12397, 12398,12399,12400,12401,12402,12403,12404,12405,12406,12407, 12408,12409,12410,12411,12412,12413,12414,12415,12416,12417, 12418,12419,12420,12421,12422,12423,12424,12425,12426,12427, 12428,12429,12430,12431,12432,12433,12434,12435,12436,12437, 12438,12439,12440,12441,12442,12443,12444,12445,12446,12447, 12448,12449,12450,12451,12452,12453,12454,12455,12456,12457, 12458,12459,12460,12461,12462,12463,12464,12465,12466,12467, 12468,12469,12470,12471,12472,12473,12474,12475,12476,12477, 12478,12479,12480,12481,12482,12483,12484,12485,12486,12487, 12488,12489,12490,12491,12492,12493,12494,12495,12496,12497, 12498,12499,12500,12501,12502,12503,12504,12505,12506,12507, 12508,12509,12510,12511,12512,12513,12514,12515,12516,12517, 12518,12519,12520,12521,12522,12523,12524,12525,12526,12527, 12528,12529,12530,12531,12532,12533,12534,12535,12536,12537, 12538,12539,12540,12541,12542,12543,12544,12545,12546,12547, 12548,12549,12550,12551,12552,12553,12554,12555,12556,12557, 12558,12559,12560,12561,12562,12563,12564,12565,12566,12567, 12568,12569,12570,12571,12572,12573,12574,12575,12576,12577, 12578,12579,12580,12581,12582,12583,12584,12585,12586,12587, 12588,12589,12590,12591,12592,12593,12594,12595,12596,12597, 12598,12599,12600,12601,12602,12603,12604,12605,12606,12607, 12608,12609,12610,12611,12612,12613,12614,12615,12616,12617, 12618,12619,12620,12621,12622,12623,12624,12625,12626,12627, 12628,12629,12630,12631,12632,12633,12634,12635,12636,12637, 12638,12639,12640,12641,12642,12643,12644,12645,12646,12647, 12648,12649,12650,12651,12652,12653,12654,12655,12656,12657, 12658,12659,12660,12661,12662,12663,12664,12665,12666,12667, 12668,12669,12670,12671,12672,12673,12674,12675,12676,12677, 12678,12679,12680,12681,12682,12683,12684,12685,12686,12687, 12688,12689,12690,12691,12692,12693,12694,12695,12696,12697, 12698,12699,12700,12701,12702,12703,12704,12705,12706,12707, 12708,12709,12710,12711,12712, 1237, 1235, 1233, 1231, 1229, 1227, 1225, 1223, 1221, 1219, 1217, 1215, 1213, 1211, 1209, 1207, 1205, 1203, 1201, 1199, 1197, 1195, 1193, 1191, 1189, 1187, 1185, 1183, 1181, 1179, 1177, 1175, 1173, 1171, 1169, 1167, 1165, 1163, 1161, 1159, 1157, 1155, 1153, 1151, 1149, 1147, 1145, 1143, 1141, 1139, 1137, 1135, 1133, 1131, 1129, 1127, 1125, 1123, 1121, 1119, 1117, 1115, 1113, 1111, 1109, 1107, 1105, 1103, 1101, 1099, 1097, 1095, 1093, 1091, 1089, 1087, 1085, 1083, 1081, 1079, 1077, 1075, 1073, 1071, 1069, 1067, 1065, 1063, 1061, 1059, 1057, 1055, 1053, 1051, 1049, 1047, 1045, 1043, 1041, 1039, 1037, 1035, 1033, 1031, 1029, 1027, 1025, 1023, 1021, 1019, 1017, 1015, 1013, 1011, 1009, 1007, 1005, 1003, 1001, 999, 997, 995, 993, 991, 989, 987, 985, 983, 981, 979, 977, 975, 973, 971, 969, 967, 965, 963, 961, 959, 957, 955, 953, 951, 949, 947, 945, 943, 941, 939, 937, 935, 933, 931, 929, 927, 925, 923, 921, 919, 917, 915, 913, 911, 909, 907, 905, 903, 901, 899, 897, 895, 893, 891, 889, 887, 885, 883, 881, 879, 877, 875, 873, 871, 869, 867, 865, 863, 861, 859, 857, 855, 853, 851, 849, 847, 845, 843, 841, 839, 837, 835, 833, 831, 829, 827, 825, 823, 821, 819, 817, 815, 813, 811, 809, 807, 805, 803, 801, 799, 797, 795, 793, 791, 789, 787, 785, 783, 781, 779, 777, 775, 773, 771, 769, 767, 765, 763, 761, 759, 757, 755, 753, 751, 749, 747, 745, 743, 741, 739, 737, 735, 733, 731, 729, 727, 725, 723, 721, 719, 717, 715, 713, 711, 709, 707, 705, 703, 701, 699, 697, 695, 693, 691, 689, 687, 685, 683, 681, 679, 677, 675, 673, 671, 669, 667, 665, 663, 661, 659, 657, 655, 653, 651, 649, 647, 645, 643, 641, 639, 637, 635, 633, 631, 629, 627, 625, 623, 621, 619, 617, 615, 613, 611, 609, 607, 605, 603, 601, 599, 597, 595, 593, 591, 589, 587, 585, 583, 581, 579, 577, 575, 573, 571, 569, 567, 565, 563, 561, 559, 557, 555, 553, 551, 549, 547, 545, 543, 541, 539, 537, 535, 533, 531, 529, 527, 525, 523, 521, 519, 517, 515, 513, 511, 509, 507, 505, 503, 501, 499, 497, 495, 493, 491, 489, 487, 485, 483, 481, 479, 477, 475, 473, 471, 469, 467, 465, 463, 461, 459, 455, 452, 451, 447, 446, 445, 440, 439, 436, 433, 432, 424, 422, 415, 410, 408, 407, 405, 404, 399, 390, 388, 387, 385, 377, 372, 366, 365, 364, 362, 358, 352, 347, 344, 343, 341, 336, 329, 326, 324, 323, 321, 316, 313, 308, 306, 298, 297, 295, 291, 289, 281, 274, 271, 267, 266, 264, 263, 256, 253, 248, 246, 234, 233, 231, 229, 227, 213, 211, 202, 197, 196, 194, 191, 189, 180, 168, 166, 164, 163, 157, 156, 154, 146, 144, 142, 141, 115, 114, 112, 81, 73, 72, 70, 59, 40, 39, 38, 37, 35, 22, 21, 20, 17, 14, 13, 11, 9, 7, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614, 8614 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int sfat_flex_debug; int sfat_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *sfattext; #line 1 "sf_attribute_table_parser.l" /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Author: Steven Sturges * sf_attribute_table_parser.l */ /* * Lex for Attribute Table */ /* Definitions Section. * Definitions required by the rules section are in here prior to first * "%%" seperator */ /* Include code between "%{ %}" separators at top of generated * lexer source file */ #line 39 "sf_attribute_table_parser.l" #ifdef TARGET_BASED #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "util.h" #include "snort.h" #include "parser.h" #include "sftarget_reader.h" #include "sf_attribute_table.h" /* Generated from YACC */ extern ServiceClient sfat_client_or_service; static int sfat_linenumber = 0; static char* sfat_filename; void sfat_error(char *err); int sfat_parse(void); /* Change flex buffer size from default 8K to STD_BUF bytes */ #ifdef YY_BUF_SIZE #undef YY_BUF_SIZE #endif #define YY_BUF_SIZE STD_BUF #define YY_DECL int sfat_lex(void) /* At end-of-file return assuming no more files to scan */ /* Not using this functionality */ #define YY_NO_INPUT 1 /* Optimise lexer for interactive use */ /* Declare exclusive start conditions. * Start conditions are included here to illustrate how to add simple * state-machine functionality to the lexer */ /* Define some common patterns for use below */ /* Rules Section. * All rules are in here prior to second "%%" seperator */ #line 6270 "sf_attribute_table_parser.c" #define INITIAL 0 #define waiting_for_comma_prior_to_data 1 #define waiting_for_data 2 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int sfatlex_destroy (void ); int sfatget_debug (void ); void sfatset_debug (int debug_flag ); YY_EXTRA_TYPE sfatget_extra (void ); void sfatset_extra (YY_EXTRA_TYPE user_defined ); FILE *sfatget_in (void ); void sfatset_in (FILE * in_str ); FILE *sfatget_out (void ); void sfatset_out (FILE * out_str ); yy_size_t sfatget_leng (void ); char *sfatget_text (void ); int sfatget_lineno (void ); void sfatset_lineno (int line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int sfatwrap (void ); #else extern int sfatwrap (void ); #endif #endif #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( sfattext, sfatleng, 1, sfatout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( sfatin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( sfatin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, sfatin))==0 && ferror(sfatin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(sfatin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int sfatlex (void); #define YY_DECL int sfatlex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after sfattext and sfatleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 101 "sf_attribute_table_parser.l" #line 6454 "sf_attribute_table_parser.c" if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! sfatin ) sfatin = stdin; if ( ! sfatout ) sfatout = stdout; if ( ! YY_CURRENT_BUFFER ) { sfatensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = sfat_create_buffer(sfatin,YY_BUF_SIZE ); } sfat_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of sfattext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 8615 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_current_state != 8614 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 102 "sf_attribute_table_parser.l" { ; } /* Handle empty whitespace */ YY_BREAK case 2: YY_RULE_SETUP #line 103 "sf_attribute_table_parser.l" { return SF_START_SNORT_ATTRIBUTES; } YY_BREAK case 3: YY_RULE_SETUP #line 104 "sf_attribute_table_parser.l" { return SF_END_SNORT_ATTRIBUTES; } YY_BREAK case 4: YY_RULE_SETUP #line 106 "sf_attribute_table_parser.l" { return SF_AT_START_MAP_TABLE; } YY_BREAK case 5: YY_RULE_SETUP #line 107 "sf_attribute_table_parser.l" { return SF_AT_END_MAP_TABLE; } YY_BREAK case 6: YY_RULE_SETUP #line 108 "sf_attribute_table_parser.l" { return SF_AT_START_ENTRY; } YY_BREAK case 7: YY_RULE_SETUP #line 109 "sf_attribute_table_parser.l" { return SF_AT_END_ENTRY; } YY_BREAK case 8: YY_RULE_SETUP #line 110 "sf_attribute_table_parser.l" { return SF_AT_START_ENTRY_ID; } YY_BREAK case 9: YY_RULE_SETUP #line 111 "sf_attribute_table_parser.l" { return SF_AT_END_ENTRY_ID; } YY_BREAK case 10: YY_RULE_SETUP #line 112 "sf_attribute_table_parser.l" { return SF_AT_START_ENTRY_VALUE; } YY_BREAK case 11: YY_RULE_SETUP #line 113 "sf_attribute_table_parser.l" { return SF_AT_END_ENTRY_VALUE; } YY_BREAK case 12: YY_RULE_SETUP #line 114 "sf_attribute_table_parser.l" { return SF_AT_START_ATTRIBUTE_TABLE; } YY_BREAK case 13: YY_RULE_SETUP #line 115 "sf_attribute_table_parser.l" { return SF_AT_END_ATTRIBUTE_TABLE; } YY_BREAK case 14: YY_RULE_SETUP #line 116 "sf_attribute_table_parser.l" { return SF_AT_START_HOST; } YY_BREAK case 15: YY_RULE_SETUP #line 117 "sf_attribute_table_parser.l" { return SF_AT_END_HOST; } YY_BREAK case 16: YY_RULE_SETUP #line 118 "sf_attribute_table_parser.l" { return SF_AT_START_HOST_IP; } YY_BREAK case 17: YY_RULE_SETUP #line 119 "sf_attribute_table_parser.l" { return SF_AT_END_HOST_IP; } YY_BREAK case 18: YY_RULE_SETUP #line 120 "sf_attribute_table_parser.l" { return SF_AT_START_OS; } YY_BREAK case 19: YY_RULE_SETUP #line 121 "sf_attribute_table_parser.l" { return SF_AT_END_OS; } YY_BREAK case 20: YY_RULE_SETUP #line 122 "sf_attribute_table_parser.l" { return SF_AT_START_ATTRIBUTE_VALUE; } YY_BREAK case 21: YY_RULE_SETUP #line 123 "sf_attribute_table_parser.l" { return SF_AT_END_ATTRIBUTE_VALUE; } YY_BREAK case 22: YY_RULE_SETUP #line 124 "sf_attribute_table_parser.l" { return SF_AT_START_ATTRIBUTE_ID; } YY_BREAK case 23: YY_RULE_SETUP #line 125 "sf_attribute_table_parser.l" { return SF_AT_END_ATTRIBUTE_ID; } YY_BREAK case 24: YY_RULE_SETUP #line 126 "sf_attribute_table_parser.l" { return SF_AT_START_CONFIDENCE; } YY_BREAK case 25: YY_RULE_SETUP #line 127 "sf_attribute_table_parser.l" { return SF_AT_END_CONFIDENCE; } YY_BREAK case 26: YY_RULE_SETUP #line 128 "sf_attribute_table_parser.l" { return SF_AT_START_NAME; } YY_BREAK case 27: YY_RULE_SETUP #line 129 "sf_attribute_table_parser.l" { return SF_AT_END_NAME; } YY_BREAK case 28: YY_RULE_SETUP #line 130 "sf_attribute_table_parser.l" { return SF_AT_START_VENDOR; } YY_BREAK case 29: YY_RULE_SETUP #line 131 "sf_attribute_table_parser.l" { return SF_AT_END_VENDOR; } YY_BREAK case 30: YY_RULE_SETUP #line 132 "sf_attribute_table_parser.l" { return SF_AT_START_VERSION; } YY_BREAK case 31: YY_RULE_SETUP #line 133 "sf_attribute_table_parser.l" { return SF_AT_END_VERSION; } YY_BREAK case 32: YY_RULE_SETUP #line 134 "sf_attribute_table_parser.l" { return SF_AT_START_FRAG_POLICY; } YY_BREAK case 33: YY_RULE_SETUP #line 135 "sf_attribute_table_parser.l" { return SF_AT_END_FRAG_POLICY; } YY_BREAK case 34: YY_RULE_SETUP #line 136 "sf_attribute_table_parser.l" { return SF_AT_START_STREAM_POLICY; } YY_BREAK case 35: YY_RULE_SETUP #line 137 "sf_attribute_table_parser.l" { return SF_AT_END_STREAM_POLICY; } YY_BREAK case 36: YY_RULE_SETUP #line 138 "sf_attribute_table_parser.l" { return SF_AT_START_SERVICES; } YY_BREAK case 37: YY_RULE_SETUP #line 139 "sf_attribute_table_parser.l" { return SF_AT_END_SERVICES; } YY_BREAK case 38: YY_RULE_SETUP #line 140 "sf_attribute_table_parser.l" { return SF_AT_START_SERVICE; } YY_BREAK case 39: YY_RULE_SETUP #line 141 "sf_attribute_table_parser.l" { return SF_AT_END_SERVICE; } YY_BREAK case 40: YY_RULE_SETUP #line 142 "sf_attribute_table_parser.l" { return SF_AT_START_CLIENTS; } YY_BREAK case 41: YY_RULE_SETUP #line 143 "sf_attribute_table_parser.l" { return SF_AT_END_CLIENTS; } YY_BREAK case 42: YY_RULE_SETUP #line 144 "sf_attribute_table_parser.l" { return SF_AT_START_CLIENT; } YY_BREAK case 43: YY_RULE_SETUP #line 145 "sf_attribute_table_parser.l" { return SF_AT_END_CLIENT; } YY_BREAK case 44: YY_RULE_SETUP #line 146 "sf_attribute_table_parser.l" { return SF_AT_START_IPPROTO; } YY_BREAK case 45: YY_RULE_SETUP #line 147 "sf_attribute_table_parser.l" { return SF_AT_END_IPPROTO; } YY_BREAK case 46: YY_RULE_SETUP #line 148 "sf_attribute_table_parser.l" { return SF_AT_START_PROTOCOL; } YY_BREAK case 47: YY_RULE_SETUP #line 149 "sf_attribute_table_parser.l" { return SF_AT_END_PROTOCOL; } YY_BREAK case 48: YY_RULE_SETUP #line 150 "sf_attribute_table_parser.l" { return SF_AT_START_PORT; } YY_BREAK case 49: YY_RULE_SETUP #line 151 "sf_attribute_table_parser.l" { return SF_AT_END_PORT; } YY_BREAK case 50: YY_RULE_SETUP #line 152 "sf_attribute_table_parser.l" { return SF_AT_START_APPLICATION; } YY_BREAK case 51: YY_RULE_SETUP #line 153 "sf_attribute_table_parser.l" { return SF_AT_END_APPLICATION; } YY_BREAK case 52: YY_RULE_SETUP #line 155 "sf_attribute_table_parser.l" { sfat_lval.numericValue = strtol( sfattext, NULL, 10 ); #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "Number Value: [%d]\n", sfat_lval.numericValue); #endif return SF_AT_NUMERIC; } YY_BREAK case 53: YY_RULE_SETUP #line 163 "sf_attribute_table_parser.l" { /* Store the value of the string, but not * more than STD_BUF. */ int i; for (i=0; i < sfatleng && i < STD_BUF-1; i++) { sfat_lval.stringValue[i] = sfattext[i]; } sfat_lval.stringValue[i] = '\0'; #ifdef DEBUG_MSGS DebugMessage(DEBUG_ATTRIBUTE, "String Value: [%s]\n", sfat_lval.stringValue); #endif return SF_AT_STRING; } YY_BREAK case 54: /* rule 54 can match eol */ YY_RULE_SETUP #line 179 "sf_attribute_table_parser.l" { sfat_linenumber++; } YY_BREAK case 55: YY_RULE_SETUP #line 180 "sf_attribute_table_parser.l" { ; /* Do nothing -- ignore it */} YY_BREAK case 56: YY_RULE_SETUP #line 182 "sf_attribute_table_parser.l" { return 0; } YY_BREAK /* Error, no meaningful input provided */ case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(waiting_for_comma_prior_to_data): case YY_STATE_EOF(waiting_for_data): #line 185 "sf_attribute_table_parser.l" { yyterminate(); } YY_BREAK case 57: YY_RULE_SETUP #line 187 "sf_attribute_table_parser.l" ECHO; YY_BREAK #line 6848 "sf_attribute_table_parser.c" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed sfatin at a new source and called * sfatlex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = sfatin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( sfatwrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * sfattext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of sfatlex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { yy_size_t new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ sfatrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; sfatrestart(sfatin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) sfatrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 8615 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 8615 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 8614); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ sfatrestart(sfatin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( sfatwrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve sfattext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void sfatrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ sfatensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = sfat_create_buffer(sfatin,YY_BUF_SIZE ); } sfat_init_buffer(YY_CURRENT_BUFFER,input_file ); sfat_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void sfat_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * sfatpop_buffer_state(); * sfatpush_buffer_state(new_buffer); */ sfatensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; sfat_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (sfatwrap()) processing, but the only time this flag * is looked at is after sfatwrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void sfat_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; sfatin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE sfat_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) sfatalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in sfat_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) sfatalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in sfat_create_buffer()" ); b->yy_is_our_buffer = 1; sfat_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with sfat_create_buffer() * */ void sfat_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) sfatfree((void *) b->yy_ch_buf ); sfatfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a sfatrestart() or at EOF. */ static void sfat_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; sfat_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then sfat_init_buffer was _probably_ * called from sfatrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void sfat_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) sfat_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void sfatpush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; sfatensure_buffer_stack(); /* This block is copied from sfat_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from sfat_switch_to_buffer. */ sfat_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void sfatpop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; sfat_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { sfat_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void sfatensure_buffer_stack (void) { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)sfatalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in sfatensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)sfatrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in sfatensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE sfat_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) sfatalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in sfat_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; sfat_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to sfatlex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * sfat_scan_bytes() instead. */ YY_BUFFER_STATE sfat_scan_string (yyconst char * yystr ) { return sfat_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to sfatlex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE sfat_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) sfatalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in sfat_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = sfat_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in sfat_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up sfattext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ sfattext[sfatleng] = (yy_hold_char); \ (yy_c_buf_p) = sfattext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ sfatleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int sfatget_lineno (void) { return sfatlineno; } /** Get the input stream. * */ FILE *sfatget_in (void) { return sfatin; } /** Get the output stream. * */ FILE *sfatget_out (void) { return sfatout; } /** Get the length of the current token. * */ yy_size_t sfatget_leng (void) { return sfatleng; } /** Get the current token. * */ char *sfatget_text (void) { return sfattext; } /** Set the current line number. * @param line_number * */ void sfatset_lineno (int line_number ) { sfatlineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see sfat_switch_to_buffer */ void sfatset_in (FILE * in_str ) { sfatin = in_str ; } void sfatset_out (FILE * out_str ) { sfatout = out_str ; } int sfatget_debug (void) { return sfat_flex_debug; } void sfatset_debug (int bdebug ) { sfat_flex_debug = bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from sfatlex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT sfatin = stdin; sfatout = stdout; #else sfatin = (FILE *) 0; sfatout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * sfatlex_init() */ return 0; } /* sfatlex_destroy is for both reentrant and non-reentrant scanners. */ int sfatlex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ sfat_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; sfatpop_buffer_state(); } /* Destroy the stack itself. */ sfatfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * sfatlex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *sfatalloc (yy_size_t size ) { return (void *) malloc( size ); } void *sfatrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void sfatfree (void * ptr ) { free( (char *) ptr ); /* see sfatrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 187 "sf_attribute_table_parser.l" char *sfat_grammar_error=NULL; char sfat_grammar_error_printed=0; char sfat_insufficient_space_logged=0; char sfat_fatal_error=1; char *sfat_saved_file = NULL; static char sfat_saved_file_set = 0; char parse_error = 0; char sfat_error_message[STD_BUF]; int ParseTargetMap(char *filename) { int error; int ret = SFAT_ERROR; parse_error = 0; sfat_grammar_error_printed = 0; if (!filename) { return SFAT_OK; } sfatin = fopen(filename, "r"); if (!sfatin) { SnortSnprintf(sfat_error_message, STD_BUF, "%s(%d): Failed to open target-based attribute file: '%s'\n", file_name, file_line, filename); return ret; } sfat_filename = filename; if (feof(sfatin)) { SnortSnprintf(sfat_error_message, STD_BUF, "%s(%d): Emtpy target-based attribute file: '%s'\n", file_name, file_line, filename); fclose(sfatin); return ret; } error = sfat_parse(); if (error) { sfat_error(""); fclose(sfatin); return ret; } fclose(sfatin); if (parse_error == 1) { return ret; } ret = SFAT_OK; /* Everything parsed ok, save off the filename */ if (sfat_saved_file_set && sfat_saved_file) { if (!strcmp(sfat_saved_file, sfat_filename)) { /* Same filename, we're done. */ return ret; } sfat_saved_file_set = 0; } /* Save off the new filename. */ if (sfat_saved_file) { free(sfat_saved_file); } sfat_saved_file = SnortStrdup(sfat_filename); sfat_saved_file_set = 1; return ret; } void DestroyBufferStack(void) { #ifdef HAVE_YYLEX_DESTROY sfatlex_destroy(); #endif } void sfat_error(char *err) { if (sfat_grammar_error_printed != 0) { parse_error = 1; return; } if (sfat_grammar_error) { SnortSnprintf(sfat_error_message, STD_BUF, "%s(%d) ==> Invalid Attribute Table specification: '%s'.\n" "Please verify the grammar at or near line %d (tag '%s'): %s\n", file_name, file_line, sfat_filename, sfat_linenumber, sfattext, sfat_grammar_error); } else { SnortSnprintf(sfat_error_message, STD_BUF, "%s(%d) ==> Invalid Attribute Table specification: '%s'.\n" "Please verify the grammar at or near line %d (tag '%s').\n", file_name, file_line, sfat_filename, sfat_linenumber, sfattext); } parse_error = 1; } #endif /* TARGET_BASED */ snort-2.9.6.0/src/target-based/Makefile.am0000644000000000000000000000201612026730052015103 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libtarget_based.a INCLUDES = @INCLUDES@ if HAVE_TARGET_BASED #BUILT_SOURCES = \ #sf_attribute_table_parser.c \ #sf_attribute_table.h \ #sf_attribute_table.c nodist_libtarget_based_a_SOURCES = \ sf_attribute_table_parser.c \ sf_attribute_table.h \ sf_attribute_table.c libtarget_based_a_SOURCES = \ sftarget_reader.c \ sftarget_reader.h \ sftarget_hostentry.c \ sftarget_hostentry.h \ sftarget_protocol_reference.c \ sftarget_protocol_reference.h \ sf_attribute_table_parser.l \ sf_attribute_table.y else libtarget_based_a_SOURCES = sftarget_reader.c endif .y.c: $(YACC) -d -psfat_ -o$@ $? #### Ugly to get the header file built. #### any other suggestions? sf_attribute_table.h: sf_attribute_table.y $(YACC) -d -psfat_ $? mv y.tab.h $@ .l.c: $(LEX) -i -o$@ $? sf_attribute_table_parser.c: sf_attribute_table_parser.l sf_attribute_table.h $(LEX) -i -Psfat -o$@ $< clean-local: rm -f \ sf_attribute_table_parser.c \ sf_attribute_table.h \ sf_attribute_table.c snort-2.9.6.0/src/target-based/Makefile.in0000644000000000000000000004611112260606526015130 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/target-based DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ sf_attribute_table_parser.c sf_attribute_table.c \ $(top_srcdir)/ylwrap ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libtarget_based_a_AR = $(AR) $(ARFLAGS) libtarget_based_a_LIBADD = am__libtarget_based_a_SOURCES_DIST = sftarget_reader.c \ sftarget_reader.h sftarget_hostentry.c sftarget_hostentry.h \ sftarget_protocol_reference.c sftarget_protocol_reference.h \ sf_attribute_table_parser.l sf_attribute_table.y @HAVE_TARGET_BASED_FALSE@am_libtarget_based_a_OBJECTS = \ @HAVE_TARGET_BASED_FALSE@ sftarget_reader.$(OBJEXT) @HAVE_TARGET_BASED_TRUE@am_libtarget_based_a_OBJECTS = \ @HAVE_TARGET_BASED_TRUE@ sftarget_reader.$(OBJEXT) \ @HAVE_TARGET_BASED_TRUE@ sftarget_hostentry.$(OBJEXT) \ @HAVE_TARGET_BASED_TRUE@ sftarget_protocol_reference.$(OBJEXT) \ @HAVE_TARGET_BASED_TRUE@ sf_attribute_table_parser.$(OBJEXT) \ @HAVE_TARGET_BASED_TRUE@ sf_attribute_table.$(OBJEXT) @HAVE_TARGET_BASED_TRUE@nodist_libtarget_based_a_OBJECTS = \ @HAVE_TARGET_BASED_TRUE@ sf_attribute_table_parser.$(OBJEXT) \ @HAVE_TARGET_BASED_TRUE@ sf_attribute_table.$(OBJEXT) libtarget_based_a_OBJECTS = $(am_libtarget_based_a_OBJECTS) \ $(nodist_libtarget_based_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = @MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ || LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS) LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS) AM_V_LEX = $(am__v_LEX_@AM_V@) am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@) am__v_LEX_0 = @echo " LEX " $@; am__v_LEX_1 = YLWRAP = $(top_srcdir)/ylwrap @MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ || am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = SOURCES = $(libtarget_based_a_SOURCES) \ $(nodist_libtarget_based_a_SOURCES) DIST_SOURCES = $(am__libtarget_based_a_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libtarget_based.a #BUILT_SOURCES = \ #sf_attribute_table_parser.c \ #sf_attribute_table.h \ #sf_attribute_table.c @HAVE_TARGET_BASED_TRUE@nodist_libtarget_based_a_SOURCES = \ @HAVE_TARGET_BASED_TRUE@sf_attribute_table_parser.c \ @HAVE_TARGET_BASED_TRUE@sf_attribute_table.h \ @HAVE_TARGET_BASED_TRUE@sf_attribute_table.c @HAVE_TARGET_BASED_FALSE@libtarget_based_a_SOURCES = sftarget_reader.c @HAVE_TARGET_BASED_TRUE@libtarget_based_a_SOURCES = \ @HAVE_TARGET_BASED_TRUE@sftarget_reader.c \ @HAVE_TARGET_BASED_TRUE@sftarget_reader.h \ @HAVE_TARGET_BASED_TRUE@sftarget_hostentry.c \ @HAVE_TARGET_BASED_TRUE@sftarget_hostentry.h \ @HAVE_TARGET_BASED_TRUE@sftarget_protocol_reference.c \ @HAVE_TARGET_BASED_TRUE@sftarget_protocol_reference.h \ @HAVE_TARGET_BASED_TRUE@sf_attribute_table_parser.l \ @HAVE_TARGET_BASED_TRUE@sf_attribute_table.y all: all-am .SUFFIXES: .SUFFIXES: .c .l .lo .o .obj .y $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/target-based/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/target-based/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libtarget_based.a: $(libtarget_based_a_OBJECTS) $(libtarget_based_a_DEPENDENCIES) $(EXTRA_libtarget_based_a_DEPENDENCIES) $(AM_V_at)-rm -f libtarget_based.a $(AM_V_AR)$(libtarget_based_a_AR) libtarget_based.a $(libtarget_based_a_OBJECTS) $(libtarget_based_a_LIBADD) $(AM_V_at)$(RANLIB) libtarget_based.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -rm -f sf_attribute_table.c -rm -f sf_attribute_table_parser.c clean: clean-am clean-am: clean-generic clean-libtool clean-local \ clean-noinstLIBRARIES mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-local clean-noinstLIBRARIES cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .y.c: $(YACC) -d -psfat_ -o$@ $? #### Ugly to get the header file built. #### any other suggestions? sf_attribute_table.h: sf_attribute_table.y $(YACC) -d -psfat_ $? mv y.tab.h $@ .l.c: $(LEX) -i -o$@ $? sf_attribute_table_parser.c: sf_attribute_table_parser.l sf_attribute_table.h $(LEX) -i -Psfat -o$@ $< clean-local: rm -f \ sf_attribute_table_parser.c \ sf_attribute_table.h \ sf_attribute_table.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-output/0000755000000000000000000000000012260606566013564 500000000000000snort-2.9.6.0/src/dynamic-output/libs/0000755000000000000000000000000012260606566014515 500000000000000snort-2.9.6.0/src/dynamic-output/libs/output_lib.c0000644000000000000000000000542312260565732016772 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Date: 01-27-2012 ** Author: Hui Cao */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "output_api.h" #include "output_lib.h" extern char *file_name; extern int file_line; DynamicOutputData _dod; OUTPUT_SO_PUBLIC int initOutputPlugins(void *dod) { DynamicOutputData* outputData = (DynamicOutputData*)dod; /*Check the version*/ if (!dod) return OUTPUT_ERROR; if (outputData->majorVersion != OUTPUT_DATA_MAJOR_VERSION) { printf("ERROR major version %d != %d\n", outputData->majorVersion, OUTPUT_DATA_MAJOR_VERSION); return OUTPUT_ERROR; } if (outputData->minorVersion < OUTPUT_DATA_MINOR_VERSION) { printf("ERROR minor version %d < %d\n", outputData->minorVersion, OUTPUT_DATA_MINOR_VERSION); return OUTPUT_ERROR; } if (outputData->size < sizeof(DynamicOutputData)) { printf("ERROR size %d != %u\n", outputData->size, (unsigned)sizeof(*outputData)); return OUTPUT_ERROR; } _dod = *((DynamicOutputData*)dod); return OUTPUT_SUCCESS; } void init_output_module(struct _SnortConfig *sc, Output_Module_t *om, char *args) { void *config; if (!om) return; printf("Initializing module %s \n", om->name); om->parse_args(&config, args, om->default_file); if (om->alert_output) { _dod.addOutputModule(sc, om->alert_output, DYNAMIC_OUTPUT_TYPE_FLAG__ALERT, config); } if (om->log_output) { _dod.addOutputModule(sc, om->log_output, DYNAMIC_OUTPUT_TYPE_FLAG__LOG, config); } #ifdef SNORT_RELOAD if (om->rotate) { _dod.addReload(om->rotate, config); } #endif if (om->postconfig) { _dod.addPostconfig(sc, om->postconfig, config); } if (om->shutdown) { _dod.addCleanExit(om->shutdown, config); } } snort-2.9.6.0/src/dynamic-output/libs/snort_output.pc.in0000644000000000000000000000067711746560363020167 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ libdir=@libdir@ package=@PACKAGE@ includedir=@includedir@ datarootdir=@datarootdir@ datadir=@datadir@ mandir=@infodir@ infodir=@infodir@ Name: Snort Description: Snort dynamic output modules URL: www.snort.org Version: @VERSION@ Libs: -L${libdir}/${package}/dynamic_output -lsf_dynamic_output Cflags: -I${includedir}/${package}/dynamic_output @CONFIGFLAGS@ @CCONFIGFLAGS@ @ICONFIGFLAGS@ snort-2.9.6.0/src/dynamic-output/libs/Makefile.am0000644000000000000000000000273712153454770016501 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I$(top_srcdir)/src/dynamic-output/plugins -I$(top_srcdir)/src -I$(top_srcdir)/src/sfutil -I$(top_srcdir)/src/dynamic-plugins -I$(top_srcdir)/src/preprocessors if SO_WITH_STATIC_LIB outputlibdir=$(pkglibdir)/dynamic_output outputlibincludedir=$(pkgincludedir)/dynamic_output outputlib_LTLIBRARIES = libsf_dynamic_output.la libsf_dynamic_output_la_CFLAGS = -fPIC -DPIC libsf_dynamic_output_la_LDFLAGS = -static libsf_dynamic_output_la_SOURCES = \ output_lib.c preprocincludedir = $(top_builddir)/src/dynamic-preprocessors/include external_headers = \ $(top_srcdir)/src/dynamic-output/plugins/output_lib.h \ $(top_srcdir)/src/dynamic-output/plugins/output_api.h \ $(top_srcdir)/src/dynamic-output/plugins/output_common.h \ $(preprocincludedir)/obfuscation.h \ $(preprocincludedir)/ipv6_port.h \ $(preprocincludedir)/sf_ip.h \ $(preprocincludedir)/snort_debug.h \ $(preprocincludedir)/sfPolicy.h \ $(preprocincludedir)/sf_dynamic_common.h \ $(preprocincludedir)/stream_api.h \ $(preprocincludedir)/preprocids.h \ $(preprocincludedir)/bitop.h \ $(preprocincludedir)/sf_snort_packet.h \ $(preprocincludedir)/sf_protocols.h \ $(preprocincludedir)/sfrt.h \ $(preprocincludedir)/sfrt_dir.h \ $(preprocincludedir)/sfrt_trie.h nodist_libsf_dynamic_output_la_SOURCES = $(external_headers) nodist_outputlibinclude_HEADERS = $(external_headers) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = snort_output.pc endif EXTRA_DIST = \ snort_output.pc.in snort-2.9.6.0/src/dynamic-output/libs/Makefile.in0000644000000000000000000006014312260606520016474 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-output/libs DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/snort_output.pc.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = snort_output.pc CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(outputlibdir)" \ "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(outputlibincludedir)" LTLIBRARIES = $(outputlib_LTLIBRARIES) libsf_dynamic_output_la_LIBADD = am__libsf_dynamic_output_la_SOURCES_DIST = output_lib.c @SO_WITH_STATIC_LIB_TRUE@am_libsf_dynamic_output_la_OBJECTS = libsf_dynamic_output_la-output_lib.lo am__objects_1 = @SO_WITH_STATIC_LIB_TRUE@nodist_libsf_dynamic_output_la_OBJECTS = \ @SO_WITH_STATIC_LIB_TRUE@ $(am__objects_1) libsf_dynamic_output_la_OBJECTS = \ $(am_libsf_dynamic_output_la_OBJECTS) \ $(nodist_libsf_dynamic_output_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_dynamic_output_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libsf_dynamic_output_la_CFLAGS) $(CFLAGS) \ $(libsf_dynamic_output_la_LDFLAGS) $(LDFLAGS) -o $@ @SO_WITH_STATIC_LIB_TRUE@am_libsf_dynamic_output_la_rpath = -rpath \ @SO_WITH_STATIC_LIB_TRUE@ $(outputlibdir) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_dynamic_output_la_SOURCES) \ $(nodist_libsf_dynamic_output_la_SOURCES) DIST_SOURCES = $(am__libsf_dynamic_output_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(pkgconfig_DATA) HEADERS = $(nodist_outputlibinclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I$(top_srcdir)/src/dynamic-output/plugins -I$(top_srcdir)/src -I$(top_srcdir)/src/sfutil -I$(top_srcdir)/src/dynamic-plugins -I$(top_srcdir)/src/preprocessors INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies @SO_WITH_STATIC_LIB_TRUE@outputlibdir = $(pkglibdir)/dynamic_output @SO_WITH_STATIC_LIB_TRUE@outputlibincludedir = $(pkgincludedir)/dynamic_output @SO_WITH_STATIC_LIB_TRUE@outputlib_LTLIBRARIES = libsf_dynamic_output.la @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_output_la_CFLAGS = -fPIC -DPIC @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_output_la_LDFLAGS = -static @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_output_la_SOURCES = \ @SO_WITH_STATIC_LIB_TRUE@output_lib.c @SO_WITH_STATIC_LIB_TRUE@preprocincludedir = $(top_builddir)/src/dynamic-preprocessors/include @SO_WITH_STATIC_LIB_TRUE@external_headers = \ @SO_WITH_STATIC_LIB_TRUE@$(top_srcdir)/src/dynamic-output/plugins/output_lib.h \ @SO_WITH_STATIC_LIB_TRUE@$(top_srcdir)/src/dynamic-output/plugins/output_api.h \ @SO_WITH_STATIC_LIB_TRUE@$(top_srcdir)/src/dynamic-output/plugins/output_common.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/obfuscation.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/ipv6_port.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/sf_ip.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/snort_debug.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/sfPolicy.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/sf_dynamic_common.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/stream_api.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/preprocids.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/bitop.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/sf_snort_packet.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/sf_protocols.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/sfrt.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/sfrt_dir.h \ @SO_WITH_STATIC_LIB_TRUE@$(preprocincludedir)/sfrt_trie.h @SO_WITH_STATIC_LIB_TRUE@nodist_libsf_dynamic_output_la_SOURCES = $(external_headers) @SO_WITH_STATIC_LIB_TRUE@nodist_outputlibinclude_HEADERS = $(external_headers) @SO_WITH_STATIC_LIB_TRUE@pkgconfigdir = $(libdir)/pkgconfig @SO_WITH_STATIC_LIB_TRUE@pkgconfig_DATA = snort_output.pc EXTRA_DIST = \ snort_output.pc.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-output/libs/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-output/libs/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): snort_output.pc: $(top_builddir)/config.status $(srcdir)/snort_output.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-outputlibLTLIBRARIES: $(outputlib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(outputlib_LTLIBRARIES)'; test -n "$(outputlibdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(outputlibdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(outputlibdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(outputlibdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(outputlibdir)"; \ } uninstall-outputlibLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(outputlib_LTLIBRARIES)'; test -n "$(outputlibdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(outputlibdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(outputlibdir)/$$f"; \ done clean-outputlibLTLIBRARIES: -test -z "$(outputlib_LTLIBRARIES)" || rm -f $(outputlib_LTLIBRARIES) @list='$(outputlib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_dynamic_output.la: $(libsf_dynamic_output_la_OBJECTS) $(libsf_dynamic_output_la_DEPENDENCIES) $(EXTRA_libsf_dynamic_output_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_dynamic_output_la_LINK) $(am_libsf_dynamic_output_la_rpath) $(libsf_dynamic_output_la_OBJECTS) $(libsf_dynamic_output_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< libsf_dynamic_output_la-output_lib.lo: output_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_output_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_output_la-output_lib.lo `test -f 'output_lib.c' || echo '$(srcdir)/'`output_lib.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) install-nodist_outputlibincludeHEADERS: $(nodist_outputlibinclude_HEADERS) @$(NORMAL_INSTALL) @list='$(nodist_outputlibinclude_HEADERS)'; test -n "$(outputlibincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(outputlibincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(outputlibincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(outputlibincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(outputlibincludedir)" || exit $$?; \ done uninstall-nodist_outputlibincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(nodist_outputlibinclude_HEADERS)'; test -n "$(outputlibincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(outputlibincludedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(outputlibdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(outputlibincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-outputlibLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-nodist_outputlibincludeHEADERS \ install-outputlibLTLIBRARIES install-pkgconfigDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nodist_outputlibincludeHEADERS \ uninstall-outputlibLTLIBRARIES uninstall-pkgconfigDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-outputlibLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man \ install-nodist_outputlibincludeHEADERS \ install-outputlibLTLIBRARIES install-pdf install-pdf-am \ install-pkgconfigDATA install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-nodist_outputlibincludeHEADERS \ uninstall-outputlibLTLIBRARIES uninstall-pkgconfigDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-output/plugins/0000755000000000000000000000000012260606566015245 500000000000000snort-2.9.6.0/src/dynamic-output/plugins/output_lib.h0000644000000000000000000001306112260565732017524 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Date: 01-27-2012 ** Author: Hui Cao */ #ifndef _OUTPUT_UTIL_H #define _OUTPUT_UTIL_H #include #include "output_common.h" #include "sf_dynamic_common.h" #include "sfPolicy.h" #include "obfuscation.h" #include "stream_api.h" #include #define OUTPUT_DATA_MAJOR_VERSION 2 #define OUTPUT_DATA_MINOR_VERSION 1 typedef int (*OutputInitFunc)(void*); typedef void (*LogFunc)(void*, void *); typedef void (*LogDataFunc)(void*, int); typedef void (*LogIPFunc)(void*, int, void*); typedef int (*ActiveFunc)(void); typedef char* (*getConfigFunc)(void); typedef int (*getConfigValueFunc)(void); typedef int (*TextLog_FlushFunc)(void*); typedef void (*TextLog_TermFunc) (void* ); typedef int (*TextLog_PrintFunc)(void*, const char* format, ...); typedef int (*GetConfigValueFunc)(void); typedef int (*TextLog_NewLineFunc) (void* ); typedef int (*TextLog_PutcFunc)(void*, char); typedef int (*TextLog_PutsFunc)(void*, char*); typedef int (*TextLog_WriteFunc)(void*, char*, int); typedef void* (*TextLog_InitFunc)(const char* name, unsigned int maxBuf, size_t maxFile); typedef void (*OutputExecFunc)(void *packet, char *msg, void *arg, void *event); typedef void (*AddFuncToOutputListFunc)(struct _SnortConfig *, OutputExecFunc o_func, int type, void *arg); typedef void (*PluginFuncWithSnortConfig)(struct _SnortConfig *, int, void *); typedef void (*AddFuncWithSnortConfigToPluginListWithSnortConfigFunc)(struct _SnortConfig *, PluginFuncWithSnortConfig, void *arg); typedef void (*AddFuncWithSnortConfigToPluginListFunc)(PluginFuncWithSnortConfig, void *arg); typedef void (*PluginFunc)(int, void *); typedef void (*AddFuncToPluginListFunc)(PluginFunc, void *arg); typedef char *(*SnortStrdupFunc)(const char *str); typedef int (*SnortSnprintfFunc)(char *buf, size_t buf_size, const char *format, ...); typedef const char* (*GetBasePolicyVersionFunc) (void); typedef const char* (*GetTargetPolicyVersionFunc) (tSfPolicyId); typedef const char* (*GetDAQInterfaceSpecFunc)(void); typedef DAQ_Mode (*GetDAQInterfaceMode)(const DAQ_PktHdr_t *h); typedef const char* (*GetProtocolNameFunc)(void*); typedef int (*GetVlanIdFunc)(void*); typedef int (*GetDAQBaseProtocolFunc) (void); typedef char ** (*MSplitFunc)(const char *str, const char *sep_chars, const int max_toks, int *num_toks, const char meta_char); typedef void (*MSplitFreeFunc)(char ***pbuf, int num_toks); /* Info Data passed to dynamic output plugin */ typedef struct _DynamicOutputData { int majorVersion; int minorVersion; unsigned int size; getConfigFunc getLogDirectory; getConfigFunc getAlertFile; getConfigValueFunc getTestMode; getConfigValueFunc getLogIPv6Extra; LogDataFunc logPriorityData; LogDataFunc logXrefs; LogIPFunc logIPPkt; LogFunc logTimeStamp; LogFunc logTrHeader; LogFunc log2ndHeader; LogFunc logIpAddrs; LogFunc logIPHeader; LogFunc logTCPHeader; LogFunc logUDPHeader; LogFunc logICMPHeader; LogFunc logArpHeader; TextLog_InitFunc textLog_Init; TextLog_TermFunc textLog_Term; TextLog_PutcFunc textLog_Putc; TextLog_PutsFunc textLog_Quote; TextLog_WriteFunc textLog_Write; TextLog_PrintFunc textLog_Print; TextLog_FlushFunc textLog_Flush; TextLog_NewLineFunc textLog_NewLine; TextLog_PutsFunc textLog_Puts; ActiveFunc active_PacketWasDropped; ActiveFunc active_PacketWouldBeDropped; GetConfigValueFunc ScOutputAppData; GetConfigValueFunc ScAlertInterface; GetConfigValueFunc ScNoOutputTimestamp; AddFuncToOutputListFunc addOutputModule; AddFuncToPluginListFunc addCleanExit; #ifdef SNORT_RELOAD AddFuncWithSnortConfigToPluginListFunc addReload; #endif AddFuncWithSnortConfigToPluginListWithSnortConfigFunc addPostconfig; GetDAQInterfaceSpecFunc getDAQinterface; GetDAQBaseProtocolFunc getDAQBaseProtocol; GetProtocolNameFunc getProtocolName; GetVlanIdFunc getVlanId; MSplitFunc mSplit; MSplitFreeFunc mSplitFree; #ifdef WIN32 char *(*print_interface)(const char *); #endif /*shared with dpd*/ char **config_file; int *config_line; LogMsgFunc logMsg; LogMsgFunc errMsg; LogMsgFunc fatalMsg; DebugMsgFunc debugMsg; SnortStrdupFunc SnortStrdup; SnortSnprintfFunc SnortSnprintf; GetPolicyFunc getRuntimePolicy; GetParserPolicyFunc getParserPolicy; GetPolicyFunc getDefaultPolicy; GetBasePolicyVersionFunc getBasePolicyVersion; GetTargetPolicyVersionFunc getTargetPolicyVersion; ObfuscationApi *obApi; StreamAPI **streamAPI; GetDAQInterfaceMode getDAQInterfaceMode; } DynamicOutputData; extern DynamicOutputData _dod; OUTPUT_SO_PUBLIC int initOutputPlugins(void *dod); #endif /* _OUTPUT_UTIL_H */ snort-2.9.6.0/src/dynamic-output/plugins/output_common.h0000644000000000000000000000514512260565732020252 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Date: 02-27-2012 ** Author: Hui Cao */ #ifndef _OUTPUT_COMMON_H #define _OUTPUT_COMMON_H #include #include #ifndef WIN32 #else #include #include #endif #ifndef IP_MAXPACKET #define IP_MAXPACKET 65535 /* maximum packet size */ #endif /* IP_MAXPACKET */ #define SNORT_SNPRINTF_SUCCESS 0 #ifndef OUTPUT_SO_PUBLIC #if defined _WIN32 || defined __CYGWIN__ # if defined OUTPUT_DLL # ifdef __GNUC__ # define OUTPUT_SO_PUBLIC __attribute__((dllexport)) # else # define OUTPUT_SO_PUBLIC __declspec(dllexport) # endif # else # ifdef __GNUC__ # define OUTPUT_SO_PUBLIC __attribute__((dllimport)) # else # define OUTPUT_SO_PUBLIC __declspec(dllimport) # endif # endif # define DLL_LOCAL #else # ifdef HAVE_VISIBILITY # define OUTPUT_SO_PUBLIC __attribute__ ((visibility("default"))) # define OUTPUT_SO_PRIVATE __attribute__ ((visibility("hidden"))) # else # define OUTPUT_SO_PUBLIC # define OUTPUT_SO_PRIVATE # endif #endif #endif #ifdef _WIN32 # ifdef OUTPUT_DLL # define OUTPUT_LINKAGE OUTPUT_SO_PUBLIC # else # define OUTPUT_LINKAGE # endif #else # define OUTPUT_LINKAGE OUTPUT_SO_PUBLIC #endif #define OUTPUT_SUCCESS 0 /* Success! */ #define OUTPUT_ERROR -1 /* Generic error */ #define OUTPUT_ERROR_NOMEM -2 /* Out of memory error */ #define OUTPUT_ERROR_NOTSUP -3 /* Functionality is unsupported error */ #define OUTPUT_ERROR_NOMOD -4 /* No module specified error */ #define OUTPUT_ERROR_INVAL -5 /* Invalid argument/request error */ #define OUTPUT_ERROR_EXISTS -6 /* Argument or device already exists */ struct _SnortConfig; #endif /* _OUTPUT_COMMON_H */ snort-2.9.6.0/src/dynamic-output/plugins/output_api.h0000644000000000000000000000554612260565732017540 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Date: 01-27-2012 ** Author: Hui Cao */ #ifndef _OUTPUT_API_H #define _OUTPUT_API_H #include "output_common.h" typedef enum _DynamicOutputTypeFlag { DYNAMIC_OUTPUT_TYPE_FLAG__ALERT = 0x00000001, DYNAMIC_OUTPUT_TYPE_FLAG__LOG = 0x00000002, DYNAMIC_OUTPUT_TYPE_FLAG__ALL = 0x7fffffff } DynamicOutputTypeFlag; struct _output_dict_entry { char *key; char *value; struct _output_dict_entry *next; }; typedef struct _output_module { /* The version of the API this module implements. This *must* be the first element in the structure. */ const uint32_t api_major_version; const uint32_t api_minor_version; /* The version of the OUTPUT module itself - can be completely arbitrary. */ const uint32_t module_version; /* The name of the module (tcpdump, alert_full, unified, etc.) */ const char *name; /* Various flags describing the module and its capabilities (alert, log etc.) */ const uint32_t type; /* The name of the default log file */ const char *default_file; /* load output module*/ void (*load) (struct _SnortConfig *, char *arg); /* Parse the output device configuration --required*/ int (*parse_args) (void **config, char *arg, const char *default_output_file); /* Post configuration*/ void (*postconfig)(struct _SnortConfig *, int unused, void *data); /* Alert function */ void (*alert_output) (void *packet, char *msg, void *arg, void *event); /* Log function */ void (*log_output) (void *packet, char *msg, void *arg, void *event); /* Restart/rotate the device */ void (*rotate) (struct _SnortConfig *, int signal, void *arg); /* Close the device and clean up --required */ void (*shutdown) (int signal, void *arg); void *next; } Output_Module_t; void init_output_module(struct _SnortConfig *, Output_Module_t *, char *); #define OUTPUT_API_MAJOR_VERSION 0x00020000 #define OUTPUT_API_MINOR_VERSION 0x00000001 #endif /* _OUTPUT_API_H */ snort-2.9.6.0/src/dynamic-output/plugins/output.h0000644000000000000000000000334712260565732016704 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Date: 01-27-2012 ** Author: Hui Cao */ #ifndef _OUTPUT_H #define _OUTPUT_H #include #include "output_common.h" struct _SnortConfig; /* Definition of the structures returned by output_get_module_list(). */ typedef struct { char *name; /* Module name */ uint32_t version; /* Module version */ uint32_t type; /* Module capabilities */ } Output_Module_Info_t; /* Iterate through each of the output modules */ void * GetNextOutputModule(void *); const char * GetOutputModuleName(void *); uint32_t GetOutputModuleVersion(void *); /* Functions for loading, handling, and unloading output modules. */ /*Load, unload output modules from directory*/ int output_load(const char *dir); void output_unload(void); int output_load_module(const char *filename); int initOutputPlugin(void *); #endif /* _OUTPUT_H */ snort-2.9.6.0/src/dynamic-output/plugins/output_plugin.c0000644000000000000000000001333412260565732020252 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Date: 01-27-2012 ** Author: Hui Cao */ #ifdef HAVE_CONFIG_H #include #endif #include "sf_types.h" #include "output.h" #include "output_api.h" #include "output_lib.h" #include "active.h" #include "log_text.h" #include "parser.h" #include "sfdaq.h" #include "snort.h" #include "util.h" #include "mstring.h" #include "decode.h" #include "plugbase.h" extern char *file_name; extern int file_line; char *GetLogDir(void) { return snort_conf->log_dir; } char *GetAlertFile(void) { return snort_conf->alert_file; } int GetLogIPv6Extra(void) { return snort_conf->log_ipv6_extra; } const char *GetDAQInterface(void) { return (PRINT_INTERFACE(DAQ_GetInterfaceSpec())); } const char *GetProtocolName(void* p) { Packet *packet = (Packet *)p; return (protocol_names[GET_IPH_PROTO(packet)]); } int GetVlanId(void* p) { Packet *packet = (Packet *)p; return (VTH_VLAN(packet->vh)); } tSfPolicyId GetParserPolicy(struct _SnortConfig *sc) { return getParserPolicy(sc); } tSfPolicyId GetRuntimePolicy(void) { return getRuntimePolicy(); } tSfPolicyId GetDefaultPolicy(void) { return getDefaultPolicy(); } const char *GetBasePolicyVersion(void) { return snort_conf->base_version; } const char *GetTargetPolicyVersion(tSfPolicyId policy_id) { SnortPolicy *policy = snort_conf->targeted_policies[policy_id]; if(policy) return (policy->policy_version); else return NULL; } int initOutputPlugin(void *outputInit) { DynamicOutputData outputData; outputData.majorVersion = OUTPUT_DATA_MAJOR_VERSION; outputData.minorVersion = OUTPUT_DATA_MINOR_VERSION; outputData.size = sizeof(DynamicOutputData); outputData.logTimeStamp = (LogFunc)LogTimeStamp; outputData.getLogDirectory = &GetLogDir; outputData.getAlertFile = &GetAlertFile; outputData.getTestMode = &ScTestMode; outputData.getLogIPv6Extra = &GetLogIPv6Extra; outputData.logPriorityData = (LogDataFunc)&LogPriorityData; outputData.logXrefs = (LogDataFunc) &LogXrefs; outputData.logIPPkt= (LogIPFunc) &LogIPPkt; outputData.logTimeStamp = (LogFunc)&LogTimeStamp; #ifndef NO_NON_ETHER_DECODER outputData.logTrHeader = (LogFunc)&LogTrHeader; outputData.logArpHeader = (LogFunc)&LogArpHeader; #endif outputData.log2ndHeader = (LogFunc)&Log2ndHeader; outputData.logIpAddrs = (LogFunc)&LogIpAddrs; outputData.logIPHeader = (LogFunc) &LogIPHeader; outputData.logTCPHeader = (LogFunc)&LogTCPHeader; outputData.logUDPHeader = (LogFunc)&LogUDPHeader; outputData.logICMPHeader = (LogFunc)&LogICMPHeader; outputData.textLog_Init = (TextLog_InitFunc)&TextLog_Init; outputData.textLog_Term = (TextLog_TermFunc)&TextLog_Term; outputData.textLog_Putc = (TextLog_PutcFunc)&TextLog_Putc; outputData.textLog_Quote = (TextLog_PutsFunc)&TextLog_Quote; outputData.textLog_Write = (TextLog_WriteFunc)&TextLog_Write; outputData.textLog_Print = (TextLog_PrintFunc)&TextLog_Print; outputData.textLog_Flush = (TextLog_FlushFunc)&TextLog_Flush; outputData.textLog_NewLine = (TextLog_NewLineFunc)&TextLog_NewLine; outputData.textLog_Puts = (TextLog_PutsFunc)&TextLog_Puts; outputData.active_PacketWasDropped = &Active_PacketWasDropped; outputData.active_PacketWouldBeDropped = &Active_PacketWouldBeDropped ; outputData.ScOutputAppData = &ScOutputAppData; outputData.ScAlertInterface = &ScAlertInterface; outputData.ScNoOutputTimestamp = &ScNoOutputTimestamp; outputData.addOutputModule = (AddFuncToOutputListFunc)&AddFuncToOutputList; outputData.addCleanExit = &AddFuncToCleanExitList; #ifdef SNORT_RELOAD outputData.addReload = &AddFuncToReloadList; #endif outputData.addPostconfig = &AddFuncToPostConfigList; outputData.config_file = &file_name; outputData.config_line = &file_line; outputData.logMsg = &LogMessage; outputData.errMsg = &ErrorMessage; outputData.fatalMsg = &FatalError; outputData.debugMsg = &DebugMessageFunc; outputData.SnortStrdup = &SnortStrdup; outputData.SnortSnprintf = &SnortSnprintf; outputData.getRuntimePolicy = GetRuntimePolicy; outputData.getParserPolicy = GetParserPolicy; outputData.getDefaultPolicy = GetDefaultPolicy; outputData.getBasePolicyVersion = &GetBasePolicyVersion; outputData.getTargetPolicyVersion = &GetTargetPolicyVersion; #ifdef WIN32 outputData.print_interface = &print_interface; #endif outputData.getDAQinterface = &GetDAQInterface; outputData.getDAQBaseProtocol = &DAQ_GetBaseProtocol; outputData.getProtocolName = &GetProtocolName; outputData.getVlanId = &GetVlanId; outputData.mSplit = &mSplit; outputData.mSplitFree = &mSplitFree; outputData.obApi = obApi; outputData.streamAPI = &stream_api; outputData.getDAQInterfaceMode = &DAQ_GetInterfaceMode; return(((OutputInitFunc)outputInit)(&outputData)); } snort-2.9.6.0/src/dynamic-output/plugins/output_base.c0000644000000000000000000002676212260565732017677 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Date: 01-27-2012 ** Author: Hui Cao */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef WIN32 #include #include #include #include #include #include #include #include #include #if defined(HPUX) #define MODULE_EXT ".sl" #else #define MODULE_EXT ".so" #endif #define dlclose_func "dlclose" #define dlopen_func_name "dlopen" #define dlsym_func_name "dlsym" #else /* !WIN32 */ #include #include #include #include #include #define MODULE_EXT "dll" #define dlclose(args) FreeLibrary(args) #define dlclose_func_name "FreeLibrary" #define dlopen(path, arg2) LoadLibrary(path) #define dlopen_func_name "LoadLibrary" #define dlsym(handle, func) GetProcAddress(handle, func) #define dlsym_func_name "GetProcAddress" #define dlerror() GetLastError() #define getcwd _getcwd #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif #endif #include "sf_types.h" #include "plugbase.h" #include "output.h" #include "output_api.h" #include "output_lib.h" #include "util.h" #define NAME_SIZE 512 #ifdef STATIC_MODULE_LIST extern const Output_Module_t *static_modules[]; extern const int num_static_modules; #endif typedef struct _output_list_node { const Output_Module_t *module; void *dl_handle; struct _output_list_node *next; } Output_ListNode_t; static Output_ListNode_t *module_list = NULL; static int num_modules = 0; static int loaded = 0; void * GetNextOutputModule(void *p_node) { Output_ListNode_t *node = (Output_ListNode_t *)p_node; if (node) return node->next; return module_list; } const char * GetOutputModuleName(void *p_node) { Output_ListNode_t *node = (Output_ListNode_t *)p_node; if (node) return node->module->name; return NULL; } uint32_t GetOutputModuleVersion(void *p_node) { Output_ListNode_t *node = (Output_ListNode_t *)p_node; if (node) return node->module->module_version; return 0; } const Output_Module_t *output_find_module(const char *name) { Output_ListNode_t *node; for (node = module_list; node; node = node->next) { if (!strcmp(name, node->module->name)) return node->module; } return NULL; } static int register_plugin(const Output_Module_t *dm) { /* Check to make sure that the required function pointers are populated. */ if (!dm->parse_args || !dm->shutdown ) { fprintf(stderr, "%s: Module definition is missing function pointer(s)!\n", dm->name); return OUTPUT_ERROR; } RegisterOutputPlugin((char*)dm->name, dm->type, dm->load); DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Registered dynamic output plugin: %s\n", dm->name);); return OUTPUT_SUCCESS; } static int register_module(const Output_Module_t *dm, void *dl_handle) { Output_ListNode_t *node; Output_Module_t *current_dm = (Output_Module_t *)dm; /* Check to make sure the module's API version matches ours. */ if (dm->api_major_version != OUTPUT_API_MAJOR_VERSION) { fprintf(stderr, "%s: Module API major version (0x%x) differs from expected version (0x%x)\n", dm->name, dm->api_major_version, OUTPUT_API_MAJOR_VERSION); return OUTPUT_ERROR; } if (dm->api_minor_version < OUTPUT_API_MINOR_VERSION) { fprintf(stderr, "%s: Module API minor version (0x%x) differs from expected version (0x%x)\n", dm->name, dm->api_minor_version, OUTPUT_API_MINOR_VERSION); return OUTPUT_ERROR; } /* Output modules should have a non-NULL name. */ if (dm->name == NULL) { fprintf(stderr, "Module name is NULL\n"); return OUTPUT_ERROR; } /* Do we already have a module with the same name loaded? */ for (node = module_list; node; node = node->next) { if (!strcmp(node->module->name, dm->name)) break; } /* If so, and this version is newer, use it instead. Otherwise, create a new node. */ if (node) { if (node->module->module_version >= dm->module_version) { DEBUG_WRAP(DebugMessage(DEBUG_INIT, "OUTPUT module with name '%s' was already loaded" " with version %u (versus %u)!\n", node->module->name, node->module->module_version, dm->module_version);); return OUTPUT_ERROR_EXISTS; } if (node->dl_handle) { dlclose(node->dl_handle); RemoveOutputPlugin((char *)dm->name); } } else { node = calloc(1, sizeof(Output_ListNode_t)); if (!node) return OUTPUT_ERROR_NOMEM; node->next = module_list; module_list = node; num_modules++; } /*add all the plugins within the module*/ while(current_dm) { int rval; if ((rval = register_plugin(current_dm)) != OUTPUT_SUCCESS) { if (rval != OUTPUT_ERROR_EXISTS) fprintf(stderr, "%s: Failed to register OUTPUT plugin.\n", current_dm->name); return OUTPUT_ERROR; } current_dm = current_dm->next; } DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Registered output module: %s\n", dm->name);); node->module = dm; node->dl_handle = dl_handle; return OUTPUT_SUCCESS; } int output_load_module(const char *filename) { const Output_Module_t *dm; void *outputInit; struct stat fs; void *dl_handle; int rval; if (filename == NULL) return OUTPUT_ERROR_INVAL; if ((stat(filename, &fs)) != 0 || !(fs.st_mode & S_IFREG)) { fprintf(stderr, "%s: File does not exist.\n", filename); return OUTPUT_ERROR; } if ((dl_handle = dlopen(filename, RTLD_NOW)) == NULL) { fprintf(stderr, "%s: %s: %s\n", filename, dlopen_func_name, dlerror()); return OUTPUT_ERROR; } /* Initiate _dod functions*/ if ((outputInit = dlsym(dl_handle, "initOutputPlugins")) == NULL) { fprintf(stderr, "%s: %s: %s\n", filename, dlsym_func_name, dlerror()); dlclose(dl_handle); return OUTPUT_ERROR; } if (initOutputPlugin(outputInit) !=OUTPUT_SUCCESS) { fprintf(stderr, "%s: Failed to load OUTPUT module.\n", filename); dlclose(dl_handle); return OUTPUT_ERROR; } if ((dm = (const Output_Module_t*)dlsym(dl_handle, "OUTPUT_MODULE_DATA")) == NULL) { fprintf(stderr, "%s: %s: %s\n", filename, dlsym_func_name, dlerror()); dlclose(dl_handle); return OUTPUT_ERROR; } if ((rval = register_module(dm, dl_handle)) != OUTPUT_SUCCESS) { if (rval != OUTPUT_ERROR_EXISTS) fprintf(stderr, "%s: Failed to register OUTPUT module.\n", filename); dlclose(dl_handle); return OUTPUT_ERROR; } return OUTPUT_SUCCESS; } #ifdef STATIC_MODULE_LIST static void load_static_modules(void) { const Output_Module_t *dm; int i; DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Static modules: %d\n", num_static_modules);); for (i = 0; i < num_static_modules; i++) { dm = static_modules[i]; if (register_module(dm, NULL) != OUTPUT_SUCCESS) fprintf(stderr, "%s (%d): Failed to register static OUTPUT module.\n", dm->name, i); } } #endif /*Load all the output modules in the directory*/ int output_load(const char *directory) { #ifndef WIN32 char dirpath[NAME_SIZE]; DIR *dirp; struct dirent *de; char *p; int ret; #ifdef STATIC_MODULE_LIST load_static_modules(); #endif if (!(*directory)) return OUTPUT_ERROR; if ((dirp = opendir(directory)) == NULL) { fprintf(stderr,"Unable to open directory \"%s\"\n", directory); return OUTPUT_ERROR; } DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Loading modules in: %s\n", directory);); while((de = readdir(dirp)) != NULL) { p = strrchr(de->d_name, '.'); if (!p || strcmp(p, MODULE_EXT)) continue; snprintf(dirpath, sizeof(dirpath), "%s/%s", directory, de->d_name); dirpath[NAME_SIZE-1] = '\0'; ret = output_load_module(dirpath); if (ret == OUTPUT_SUCCESS) { DEBUG_WRAP(DebugMessage(DEBUG_INIT,"Found module %s\n", de->d_name);); } else if (ret == OUTPUT_ERROR_NOMEM) { closedir(dirp); return OUTPUT_ERROR_NOMEM; } } closedir(dirp); #else /* Find all shared library files in path */ char path_buf[PATH_MAX]; char dyn_lib_name[PATH_MAX]; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; HANDLE fSearch; WIN32_FIND_DATA FindFileData; int pathLen = 0; const char *full_directory; int useDrive = 0; #ifdef STATIC_MODULE_LIST load_static_modules(); #endif if (!(*directory)) return OUTPUT_ERROR; if ((strncpy(path_buf, directory, PATH_MAX) == NULL) || (strlen(path_buf) != strlen(directory))) { fprintf(stderr, "Path is too long: %s\n", directory); return OUTPUT_ERROR; } pathLen = strlen(path_buf); if ((path_buf[pathLen - 1] == '\\') || (path_buf[pathLen - 1] == '/')) { /* A directory was specified with trailing dir character */ _splitpath(path_buf, drive, dir, fname, ext); _makepath(path_buf, drive, dir, "*", MODULE_EXT); full_directory = &dir[0]; useDrive = 1; } else /* A directory was specified */ { _splitpath(path_buf, drive, dir, fname, ext); if (strcmp(MODULE_EXT, "")) { fprintf(stderr, "Improperly formatted directory name: %s\n", directory); return OUTPUT_ERROR; } _makepath(path_buf, "", path_buf, "*", MODULE_EXT); full_directory = directory; } fSearch = FindFirstFile(path_buf, &FindFileData); while (fSearch != NULL && fSearch != (HANDLE)-1) { if (useDrive) _makepath(dyn_lib_name, drive, full_directory, FindFileData.cFileName, NULL); else _makepath(dyn_lib_name, NULL, full_directory, FindFileData.cFileName, NULL); output_load_module(dyn_lib_name); if (!FindNextFile(fSearch, &FindFileData)) { break; } } FindClose(fSearch); #endif loaded = 1; return OUTPUT_SUCCESS; } void output_unload(void) { Output_ListNode_t *node; while (module_list) { node = module_list; module_list = node->next; if (node->dl_handle) { dlclose(node->dl_handle); } free(node); num_modules--; } loaded = 0; } snort-2.9.6.0/src/dynamic-output/plugins/Makefile.am0000644000000000000000000000053311746560363017224 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies #ACLOCAL_AMFLAGS = -I m4 #INCLUDES = -I ../include -I ../api noinst_LIBRARIES = liboutput.a #liboutput_a_LIBADD = ../libs/liboutput_lib.a liboutput_a_CFLAGS = -fPIC liboutput_a_SOURCES = \ output_base.c \ output_plugin.c \ output.h \ output_api.h \ output_common.h \ output_lib.h INCLUDES = @INCLUDES@snort-2.9.6.0/src/dynamic-output/plugins/Makefile.in0000644000000000000000000004253512260606520017231 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-output/plugins DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = liboutput_a_AR = $(AR) $(ARFLAGS) liboutput_a_LIBADD = am_liboutput_a_OBJECTS = liboutput_a-output_base.$(OBJEXT) \ liboutput_a-output_plugin.$(OBJEXT) liboutput_a_OBJECTS = $(am_liboutput_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(liboutput_a_SOURCES) DIST_SOURCES = $(liboutput_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies #ACLOCAL_AMFLAGS = -I m4 #INCLUDES = -I ../include -I ../api noinst_LIBRARIES = liboutput.a #liboutput_a_LIBADD = ../libs/liboutput_lib.a liboutput_a_CFLAGS = -fPIC liboutput_a_SOURCES = \ output_base.c \ output_plugin.c \ output.h \ output_api.h \ output_common.h \ output_lib.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-output/plugins/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-output/plugins/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) liboutput.a: $(liboutput_a_OBJECTS) $(liboutput_a_DEPENDENCIES) $(EXTRA_liboutput_a_DEPENDENCIES) $(AM_V_at)-rm -f liboutput.a $(AM_V_AR)$(liboutput_a_AR) liboutput.a $(liboutput_a_OBJECTS) $(liboutput_a_LIBADD) $(AM_V_at)$(RANLIB) liboutput.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< liboutput_a-output_base.o: output_base.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liboutput_a_CFLAGS) $(CFLAGS) -c -o liboutput_a-output_base.o `test -f 'output_base.c' || echo '$(srcdir)/'`output_base.c liboutput_a-output_base.obj: output_base.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liboutput_a_CFLAGS) $(CFLAGS) -c -o liboutput_a-output_base.obj `if test -f 'output_base.c'; then $(CYGPATH_W) 'output_base.c'; else $(CYGPATH_W) '$(srcdir)/output_base.c'; fi` liboutput_a-output_plugin.o: output_plugin.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liboutput_a_CFLAGS) $(CFLAGS) -c -o liboutput_a-output_plugin.o `test -f 'output_plugin.c' || echo '$(srcdir)/'`output_plugin.c liboutput_a-output_plugin.obj: output_plugin.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liboutput_a_CFLAGS) $(CFLAGS) -c -o liboutput_a-output_plugin.obj `if test -f 'output_plugin.c'; then $(CYGPATH_W) 'output_plugin.c'; else $(CYGPATH_W) '$(srcdir)/output_plugin.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-output/dynamic_output.dsp0000644000000000000000000000564611746560363017275 00000000000000# Microsoft Developer Studio Project File - Name="dynamic_output" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Generic Project" 0x010a CFG=dynamic_output - Win32 IPv6 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "dynamic_output.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "dynamic_output.mak" CFG="dynamic_output - Win32 IPv6 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "dynamic_output - Win32 Release" (based on "Win32 (x86) Generic Project") !MESSAGE "dynamic_output - Win32 Debug" (based on "Win32 (x86) Generic Project") !MESSAGE "dynamic_output - Win32 IPv6 Debug" (based on "Win32 (x86) Generic Project") !MESSAGE "dynamic_output - Win32 IPv6 Release" (based on "Win32 (x86) Generic Project") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" MTL=midl.exe !IF "$(CFG)" == "dynamic_output - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "dynamic_output - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "dynamic_output - Win32 IPv6 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "dynamic_output___Win32_IPv6_Debug" # PROP BASE Intermediate_Dir "dynamic_output___Win32_IPv6_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "IPv6_Debug" # PROP Intermediate_Dir "IPv6_Debug" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "dynamic_output - Win32 IPv6 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "dynamic_output___Win32_IPv6_Release" # PROP BASE Intermediate_Dir "dynamic_output___Win32_IPv6_Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "IPv6_Release" # PROP Intermediate_Dir "IPv6_Release" # PROP Target_Dir "" !ENDIF # Begin Target # Name "dynamic_output - Win32 Release" # Name "dynamic_output - Win32 Debug" # Name "dynamic_output - Win32 IPv6 Debug" # Name "dynamic_output - Win32 IPv6 Release" # End Target # End Project snort-2.9.6.0/src/dynamic-output/Makefile.am0000644000000000000000000000015712153454770015542 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies SUBDIRS = . plugins libs EXTRA_DIST = \ dynamic_output.dsp snort-2.9.6.0/src/dynamic-output/Makefile.in0000644000000000000000000004441112260606520015543 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-output DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies SUBDIRS = . plugins libs EXTRA_DIST = \ dynamic_output.dsp all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-output/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-output/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/0000755000000000000000000000000012260606565015134 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/file/0000755000000000000000000000000012260606565016053 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/file/sf_file.dsp0000644000000000000000000001136712232305217020107 00000000000000# Microsoft Developer Studio Project File - Name="sf_file" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_file - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_file.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_file.mak" CFG="sf_file - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_file - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_file - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_file - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "SF_SNORT_PREPROC_DLL" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_file - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "SF_SNORT_PREPROC_DLL" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_file - Win32 Release" # Name "sf_file - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\spp_file.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\spp_file.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/file/file_sha.h0000644000000000000000000000603212260565732017717 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Simple SHA hash table * Author: Hui Cao */ #ifndef SPP_FILE_SHA_H #define SPP_FILE_SHA_H #define SHA256_HASH_STR_SIZE 64 #define SHA256_HASH_SIZE 32 /* * ERROR DEFINES */ #define SHAHASH_NOMEM -2 #define SHAHASH_ERR -1 #define SHAHASH_OK 0 #define SHAHASH_INTABLE 1 /* * HASH NODE */ typedef struct _ShaHashNode { struct _ShaHashNode *next; void *sha; /* Pointer to the sha */ void *data; /* Pointer to the users data, this is never copied! */ } ShaHashNode; typedef struct _ShaHash { ShaHashNode **entries; /* array of node ptr's */ int nrows; /* # rows int the hash table */ unsigned count; /* total # nodes in table */ char sha_size; /* bytes in sha_size */ } ShaHash; /* Create SHA table * * Args: * char sha_bytes: number of bytes in sha * */ ShaHash *sha_table_new( char sha_bytes); /* * Add a key + data pair * --------------------- * * key + data should both be non-zero, although data can be zero * * t - hash table * sha - sha value * data - users data pointer * * returns SHAHASH_NOMEM: alloc error * SHAHASH_INTABLE : key already in table * SHAHASH_OK: added a node for this key + data pair * */ int sha_table_add( ShaHash *t, void *sha, void *data ); /* * Find a Node based on the sha, return users data. */ void * sha_table_find( ShaHash *t, void *sha); /* * Delete the hash Table * * free key's, free node's, and free the users data, if they * supply a free function */ void sha_table_delete( ShaHash *h ); /* * Convert a printable str to sha * * Args: * char *sha256: point to sha to be saved * char *sha_str: point to the string that will be parsed * int max_size: maximum number of bytes to be read from sha_str */ int str_to_sha (char *sha_str, char *sha256, int max_size); /* * Convert a SHA256 to a printable str * * Args: * char *sha256: point to sha in binary * char *sha_str: point to the string that will be saved * int max_size: maximum number of bytes to be saved to sha_str */ int sha_to_str (char *sha256, char *sha_str, int max_size); #endif /* SPP_FILE_SHA_H */ snort-2.9.6.0/src/dynamic-preprocessors/file/file_sha.c0000644000000000000000000001434012260565732017713 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Simple SHA hash table * * We use first two bytes of SHA as index * Author: Hui Cao */ #include "sf_types.h" #include "file_sha.h" #include #include #include typedef uint16_t ShaKeyType; /*16 bits as index, we will have 65536 rows*/ #define SHA_TABLE_ROWS (1<<(sizeof(ShaKeyType)*8)) char conv_to_hex[UINT8_MAX + 1]; /* Create SHA table * * Args: * int sha_bits: number of bytes in sha */ ShaHash *sha_table_new(char sha_bytes) { ShaHash *table = malloc(sizeof(*table)); if (!table) return NULL; table->nrows = SHA_TABLE_ROWS; table->entries = calloc(table->nrows, sizeof(*(table->entries))); if (!table->entries) { free(table); return NULL; } table->sha_size = sha_bytes; table->count = 0; return table; } static int sha_cmp (void *sha1, void *sha2, char sha_bytes) { return memcmp(sha1, sha2, sha_bytes); } static ShaHashNode *sha_table_node_by_sha(ShaHash *table, void *sha) { int index; ShaHashNode *node; index = *(ShaKeyType *)sha; if (!table || !table->entries) return NULL; node = (ShaHashNode *)table->entries[index]; while(node && sha_cmp(node->sha, sha, table->sha_size)) { node = node->next; } if (node) { return node; } else { return NULL; } } /* * Find a Node based on the key, return users data. */ void * sha_table_find(ShaHash *table, void *sha) { ShaHashNode *node; node = sha_table_node_by_sha(table, sha); if (node) { return node->data; } else { return NULL; } } /* * Add a key + data pair * --------------------- * * key + data should both be non-zero, although data can be zero * * t - hash table * sha - sha value * data - users data pointer * * returns SHAHASH_NOMEM: alloc error * SHAHASH_INTABLE : key already in table * SHAHASH_OK: added a node for this key + data pair */ int sha_table_add( ShaHash *table, void *sha, void *data ) { ShaHashNode *oldNode; ShaHashNode *newNode; int index; /*check whether existing*/ oldNode = sha_table_node_by_sha(table, sha); if (oldNode) return SHAHASH_INTABLE; /* Add to the head of entry*/ index = *(ShaKeyType *)sha; oldNode = (ShaHashNode *)table->entries[index]; newNode = calloc(1, sizeof (*newNode)); if (!newNode) return SHAHASH_NOMEM; newNode->next = oldNode; newNode->sha = sha; newNode->data = data; table->entries[index] = newNode; table->count++; return SHAHASH_OK; } /* * Delete the hash Table * * free key's, free node's, and free the users data, if they * supply a free function */ void sha_table_delete( ShaHash *table ) { int i; if (!table || !table->entries) return; for (i = 0; i < table->nrows; i++) { ShaHashNode *node; ShaHashNode *old; node = (ShaHashNode *)table->entries[i]; while(node) { old = node; node = node->next; free(old->sha); free(old); } } free(table->entries); free(table); } static void init_char_to_hex_array(void) { size_t i; char conv1[] = "0123456789ABCDEF"; char conv2[] = "abcdef"; /*initializate to unset*/ for (i = 0; i < sizeof (conv_to_hex); i++) { conv_to_hex[i] = -1; } /* number and upper case letter*/ for (i = 0; i < sizeof (conv1); i++) { conv_to_hex[(int)conv1[i]] = i; } /* lower case number */ for (i = 0; i < sizeof (conv2); i++) { conv_to_hex[(int)conv2[i]] = i + 10; } } /* * Convert a printable str to sha */ int str_to_sha (char *sha_str, char *sha256, int max_size) { char *index = sha_str; char *end = sha_str + max_size; int i; char *dest = sha256; static bool initialized = false; if (!initialized) { init_char_to_hex_array(); initialized = true; } /*trim spaces in the head of signature*/ while ((index < end) && isspace((int)*index)) { index++; } /* make sure length is correct */ if (index + SHA256_HASH_STR_SIZE > end) return -1; /* convert it to hex */ for (i = 0; i < SHA256_HASH_SIZE; i++) { char value; if (conv_to_hex[(int)*index] < 0) return -1; value = conv_to_hex[(int)*(index++)]; if (conv_to_hex[(int)*index] < 0) return -1; *(dest++) = conv_to_hex[(int)*(index++)] + (value << 4); } /*Check end of string*/ while ((index < end) && isspace((int)*index)) { index++; } if (index != end) return -1; return 0; } /* * Create file name based on SHA */ int sha_to_str (char *sha256, char *sha_str, int max_size) { char conv[] = "0123456789ABCDEF"; const char *index; const char *end; char *ridx; int len; if (max_size < 1) return 0; index = sha256; if (max_size < SHA256_HASH_SIZE) len = max_size - 1; else len = SHA256_HASH_SIZE; ridx = sha_str; end = index + len; while(index < end) { *ridx++ = conv[((*index & 0xFF)>>4)]; *ridx++ = conv[((*index & 0xFF)&0x0F)]; index++; } *ridx = '\0'; return len; } snort-2.9.6.0/src/dynamic-preprocessors/file/file_inspect_config.h0000644000000000000000000000423112260565732022135 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Definitions, structs, function prototype(s) for * the file preprocessor. * Author: Hui Cao */ #ifndef SPP_FILE_INSPECT_CONFIG_H #define SPP_FILE_INSPECT_CONFIG_H #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "file_sha.h" #define FILE_CAPTURE_QUEUE_SIZE_DEFAULT 3000 /*files*/ #define FILE_CAPTURE_DISK_SIZE_DEFAULT 300 /*MB*/ typedef struct _FileSigInfo { File_Verdict verdict; } FileSigInfo; /* * Global File preprocessor configuration. * */ typedef struct _fileInspectConfig { bool file_type_enabled; bool file_signature_enabled; bool file_capture_enabled; uint32_t file_capture_queue_size; char *capture_dir; int ref_count; char *hostname; int portno; ShaHash *sig_table; #if defined(DEBUG_MSGS) || defined (REG_TEST) int verdict_delay; /* used for debug, mimic delay to get verdicts */ #endif uint32_t capture_disk_size; /* In megabytes*/ } FileInspectConf; void file_config_parse(FileInspectConf*, const u_char* ); /* Return values * 0: equal * -1: no the same */ int file_config_compare(FileInspectConf* , FileInspectConf* ); /* Release resource of file configruation*/ void file_config_free(FileInspectConf*); #endif /* SPP_FILE_INSPECT_CONFIG_H */ snort-2.9.6.0/src/dynamic-preprocessors/file/file_inspect_config.c0000644000000000000000000003736112260565732022142 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sf_types.h" #include "file_inspect_config.h" #include "file_agent.h" #include "spp_file.h" #include /* * File preprocessor configurations * Author: Hui Cao * */ #define FILE_CONF_SECTION_SEPERATORS ",;" #define FILE_CONF_VALUE_SEPERATORS " " #define FILE_SEPARATORS " \t\r\n" #define FILE_INSPECT_TYPE "type_id" #define FILE_INSPECT_SIG "signature" #define FILE_INSPECT_CAPTURE_MEMORY "capture_memory" #define FILE_INSPECT_CAPTURE_DISK "capture_disk" #define FILE_INSPECT_CAPTURE_NETWORK "capture_network" #define FILE_INSPECT_CAPTURE_QUEUE_SIZE "capture_queue_size" #define FILE_INSPECT_BLACKLIST "blacklist" #define FILE_INSPECT_GREYLIST "greylist" #if defined(DEBUG_MSGS) || defined (REG_TEST) #define FILE_INSPECT_VERDICT_DELAY "verdict_delay" #endif #define MAX_SIG_LINE_LENGTH 8192 static FileSigInfo blackList = {FILE_VERDICT_BLOCK}; static FileSigInfo greyList = {FILE_VERDICT_LOG}; /* * Function: UpdatePathToFile * * Update the path to a file, if using relative path. * The relative path is based on config file directory. * * Arguments: * full_path_filename: file name string * max_size: ? * char *filename: ? * * Returns: * 1 successful * 0 fail * */ static int UpdatePathToFile(char *full_path_filename, unsigned int max_size, char *filename) { char *snort_conf_dir = *(_dpd.snort_conf_dir); if (!snort_conf_dir || !(*snort_conf_dir) || !filename) { DynamicPreprocessorFatalMessage(" %s(%d) => can't create path.\n", *(_dpd.config_file), *(_dpd.config_line)); return 0; } /*filename is too long*/ if ( max_size < strlen(filename) ) { DynamicPreprocessorFatalMessage(" %s(%d) => the file name length %u " "is longer than allowed %u.\n", *(_dpd.config_file), *(_dpd.config_line), strlen(filename), max_size); return 0; } /* If an absolute path is specified, then use that.*/ #ifndef WIN32 if(filename[0] == '/') { snprintf(full_path_filename, max_size, "%s", filename); } else { /* Set up the file name directory.*/ if (snort_conf_dir[strlen(snort_conf_dir) - 1] == '/') { snprintf(full_path_filename,max_size, "%s%s", snort_conf_dir, filename); } else { snprintf(full_path_filename, max_size, "%s/%s", snort_conf_dir, filename); } } #else if(strlen(filename)>3 && filename[1]==':' && filename[2]=='\\') { snprintf(full_path_filename, max_size, "%s", filename); } else { /* Set up the file name directory */ if (snort_conf_dir[strlen(snort_conf_dir) - 1] == '\\' || snort_conf_dir[strlen(snort_conf_dir) - 1] == '/' ) { snprintf(full_path_filename,max_size, "%s%s", snort_conf_dir, filename); } else { snprintf(full_path_filename, max_size, "%s\\%s", snort_conf_dir, filename); } } #endif return 1; } /* * Load file list signature file * * Arguments: * filename: file name string * FileSigInfo *: The file signature information. * FileInspectConf *: The configuration to be update. * * Returns: * None */ static void file_config_signature(char *filename, FileSigInfo *sig_info, FileInspectConf *config) { FILE *fp = NULL; char linebuf[MAX_SIG_LINE_LENGTH]; char full_path_filename[PATH_MAX+1]; int line_number = 0; /* check table first, create one if not exist*/ if (config->sig_table == NULL) { config->sig_table = sha_table_new(SHA256_HASH_SIZE); } if (config->sig_table == NULL) { FILE_FATAL_ERROR("%s(%d) Could not create file signature hash.\n", *(_dpd.config_file), *(_dpd.config_line)); } /* parse the file line by line, each signature one entry*/ _dpd.logMsg("File inspect: processing file %s\n", filename); UpdatePathToFile(full_path_filename, PATH_MAX, filename); if((fp = fopen(full_path_filename, "r")) == NULL) { char errBuf[STD_BUF]; #ifdef WIN32 snprintf(errBuf, STD_BUF, "%s", strerror(errno)); #else strerror_r(errno, errBuf, STD_BUF); #endif errBuf[STD_BUF-1] = '\0'; FILE_FATAL_ERROR("%s(%d) => Unable to open signature file %s, " "Error: %s\n", *(_dpd.config_file), *(_dpd.config_line), filename, errBuf); return; } while( fgets(linebuf, MAX_SIG_LINE_LENGTH, fp) ) { char *cmt = NULL; char *sha256; FileSigInfo *old_info; DEBUG_WRAP(DebugMessage(DEBUG_FILE, "File signatures: %s\n",linebuf );); line_number++; /* Remove comments */ if( (cmt = strchr(linebuf, '#')) ) *cmt = '\0'; /* Remove newline as well, prevent double newline in logging.*/ if( (cmt = strchr(linebuf, '\n')) ) *cmt = '\0'; if (!strlen(linebuf)) continue; sha256 = malloc(SHA256_HASH_SIZE); if (!sha256) { FILE_FATAL_ERROR("%s(%d) => No memory for file: %s (%d), \n" "signature: %s\n", *(_dpd.config_file), *(_dpd.config_line), filename, line_number, linebuf); } if (str_to_sha(linebuf, sha256, strlen(linebuf)) < 0) { FILE_FATAL_ERROR("%s(%d) => signature format at file: %s (%d), \n" "signature: %s\n", *(_dpd.config_file), *(_dpd.config_line), filename, line_number, linebuf); } old_info = (FileSigInfo *)sha_table_find(config->sig_table, sha256); if (old_info) { free(sha256); _dpd.errMsg("%s(%d) => signature redefined at file: %s (%d), \n" "signature: %s\n", *(_dpd.config_file), *(_dpd.config_line), filename, line_number, linebuf); } else { sha_table_add(config->sig_table, sha256, sig_info); } } } /* Display the configuration for the File preprocessor. * * PARAMETERS: * * FileInspectConf *config: pointer to configuration * * RETURNS: Nothing. */ static void DisplayFileConfig(FileInspectConf *config) { if (config == NULL) return; _dpd.logMsg("File config: \n"); _dpd.logMsg(" file type: %s\n", config->file_type_enabled ? "ENABLED":"DISABLED (Default)"); _dpd.logMsg(" file signature: %s\n", config->file_signature_enabled ? "ENABLED":"DISABLED (Default)"); _dpd.logMsg(" file capture: %s\n", config->file_capture_enabled ? "ENABLED":"DISABLED (Default)"); if (config->file_capture_enabled) { _dpd.logMsg(" file capture directory: %s\n", config->capture_dir ? config->capture_dir:"not saved, memory only"); _dpd.logMsg(" file capture disk size: %u %s\n", config->capture_disk_size, config->capture_disk_size == FILE_CAPTURE_DISK_SIZE_DEFAULT? "(Default) megabytes":"megabytes"); } _dpd.logMsg(" file sent to host: %s, port number: %d\n", config->hostname ? config->hostname:"DISABLED (Default)", config->portno); _dpd.logMsg("\n"); } /* Parses and processes the configuration arguments * supplied in the File preprocessor rule. * * PARAMETERS: * FileInspectConf *config: pointer to configuration * argp: Pointer to string containing the config arguments. * * RETURNS: Nothing. */ void file_config_parse(FileInspectConf *config, const u_char* argp) { char* cur_sectionp = NULL; char* next_sectionp = NULL; char* argcpyp = NULL; if (config == NULL) return; config->capture_disk_size = FILE_CAPTURE_DISK_SIZE_DEFAULT; /* Sanity check(s) */ if (!argp) { DisplayFileConfig(config); return; } argcpyp = strdup((char*) argp); if (!argcpyp) { FILE_FATAL_ERROR("Could not allocate memory to " "parse File options.\n"); return; } cur_sectionp = strtok_r(argcpyp, FILE_CONF_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Arguments token: %s\n", cur_sectionp );); while (cur_sectionp) { char* cur_config; unsigned long value; char* cur_tokenp = strtok(cur_sectionp, FILE_CONF_VALUE_SEPERATORS); if (!cur_tokenp) { cur_sectionp = strtok_r(next_sectionp, FILE_CONF_SECTION_SEPERATORS, &next_sectionp); continue; } cur_config = cur_tokenp; if (!strcasecmp(cur_tokenp, FILE_INSPECT_TYPE)) { config->file_type_enabled = true; } else if (!strcasecmp(cur_tokenp, FILE_INSPECT_SIG)) { config->file_signature_enabled = true; } else if (!strcasecmp(cur_tokenp, FILE_INSPECT_BLACKLIST)) { cur_tokenp = strtok(NULL, FILE_CONF_VALUE_SEPERATORS); if(cur_tokenp == NULL) { FILE_FATAL_ERROR("%s(%d) => Please specify list file!\n", *(_dpd.config_file), *(_dpd.config_line)); } file_config_signature(cur_tokenp, &blackList, config); } else if (!strcasecmp(cur_tokenp, FILE_INSPECT_GREYLIST)) { cur_tokenp = strtok(NULL, FILE_CONF_VALUE_SEPERATORS); if(cur_tokenp == NULL) { FILE_FATAL_ERROR("%s(%d) => Please specify list file!\n", *(_dpd.config_file), *(_dpd.config_line)); } file_config_signature(cur_tokenp, &greyList, config); } else if (!strcasecmp(cur_tokenp, FILE_INSPECT_CAPTURE_MEMORY)) { config->file_capture_enabled = true; } else if (!strcasecmp(cur_tokenp, FILE_INSPECT_CAPTURE_DISK)) { config->file_capture_enabled = true; cur_tokenp = strtok(NULL, FILE_CONF_VALUE_SEPERATORS); if(cur_tokenp == NULL) { FILE_FATAL_ERROR("%s(%d) => Please specify directory!\n", *(_dpd.config_file), *(_dpd.config_line)); } if (strlen(cur_tokenp) > FILE_NAME_LEN) { FILE_FATAL_ERROR("%s(%d) => Directory string is too long!\n", *(_dpd.config_file), *(_dpd.config_line)); return; } if (!(config->capture_dir = strdup(cur_tokenp))) { FILE_FATAL_ERROR("Could not allocate memory to parse " "file options.\n"); return; } cur_tokenp = strtok(NULL, FILE_CONF_VALUE_SEPERATORS); if (cur_tokenp) { _dpd.checkValueInRange(cur_tokenp, FILE_INSPECT_CAPTURE_DISK, 0, 65536, &value); config->capture_disk_size = (int)value; } } else if (!strcasecmp(cur_tokenp, FILE_INSPECT_CAPTURE_NETWORK)) { config->file_capture_enabled = true; cur_tokenp = strtok(NULL, FILE_CONF_VALUE_SEPERATORS); if(cur_tokenp == NULL) { FILE_FATAL_ERROR("%s(%d) => Please specify hostname!\n", *(_dpd.config_file), *(_dpd.config_line)); } if (!(config->hostname = strdup(cur_tokenp))) { FILE_FATAL_ERROR("Could not allocate memory to parse " "file options.\n"); return; } cur_tokenp = strtok(NULL, FILE_CONF_VALUE_SEPERATORS); _dpd.checkValueInRange(cur_tokenp, FILE_INSPECT_CAPTURE_NETWORK, 0, 65536, &value); config->portno = (int)value; } else if (!strcasecmp(cur_tokenp, FILE_INSPECT_CAPTURE_QUEUE_SIZE)) { cur_tokenp = strtok(NULL, FILE_CONF_VALUE_SEPERATORS); _dpd.checkValueInRange(cur_tokenp, FILE_INSPECT_CAPTURE_QUEUE_SIZE, 0, UINT32_MAX, &value); config->file_capture_queue_size = (uint32_t) value; } #if defined(DEBUG_MSGS) || defined (REG_TEST) else if (!strcasecmp(cur_tokenp, FILE_INSPECT_VERDICT_DELAY)) { cur_tokenp = strtok(NULL, FILE_CONF_VALUE_SEPERATORS); _dpd.checkValueInRange(cur_tokenp, FILE_INSPECT_VERDICT_DELAY, 0, UINT32_MAX, &value); config->verdict_delay = (uint32_t) value; } #endif else { FILE_FATAL_ERROR(" %s(%d) => Invalid argument: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp); return; } /*Check whether too many parameters*/ if (NULL != strtok(NULL, FILE_CONF_VALUE_SEPERATORS)) { FILE_FATAL_ERROR("%s(%d) => Too many arguments: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_config); } cur_sectionp = strtok_r(next_sectionp, FILE_CONF_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Arguments token: %s\n", cur_sectionp );); } DisplayFileConfig(config); free(argcpyp); } /*Return values * 0: equal * -1: no the same */ static inline int _cmp_config_str(char *str1, char *str2) { if (!str1 && !str2) return 0; if (!str1 || !str2) return -1; return (strcmp(str1, str2)); } /*Return values * 0: equal * -1: no the same */ int file_config_compare(FileInspectConf* conf1 , FileInspectConf* conf2) { if (_cmp_config_str(conf1->capture_dir, conf2->capture_dir) ||(conf1->file_capture_enabled != conf2->file_capture_enabled) ||(conf1->file_capture_queue_size != conf2->file_capture_queue_size) ||(conf1->capture_disk_size != conf2->capture_disk_size) ||(conf1->file_signature_enabled != conf2->file_signature_enabled) ||(conf1->file_type_enabled != conf2->file_type_enabled) || _cmp_config_str(conf1->hostname, conf2->hostname) ||(conf1->portno != conf2->portno)) { return -1; } return 0; } void file_config_free(FileInspectConf* config) { if (config->capture_dir) { free(config->capture_dir); config->capture_dir = NULL; } if (config->hostname) { free(config->hostname); config->hostname = NULL; } if (config->sig_table != NULL) { sha_table_delete(config->sig_table); config->sig_table = NULL; } } snort-2.9.6.0/src/dynamic-preprocessors/file/file_event_log.h0000644000000000000000000000213212260565732021123 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #ifndef _FILE_EVENT_LOG_H_ #define _FILE_EVENT_LOG_H_ #include "file_api.h" #endif snort-2.9.6.0/src/dynamic-preprocessors/file/file_event_log.c0000644000000000000000000002261212260565732021123 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 4.11.2013 - Initial Source Code. ** Log file events */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "event.h" #include "sf_snort_packet.h" #include "snort_debug.h" #include "sf_textlog.h" #include "output_api.h" #include "output_lib.h" #include "sf_dynamic_common.h" #include "file_sha.h" #include "file_event_log.h" #include "sf_dynamic_preprocessor.h" #define OUTPUT_MOD_VERSION 1 #define OUTPUT_NAME "filelog" #define OUTPUT_TYPE (DYNAMIC_OUTPUT_TYPE_FLAG__ALERT) /* full buf was chosen to allow printing max size packets * in hex/ascii mode: * each byte => 2 nibbles + space + ascii + overhead */ #define FULL_BUF (4*65535) #define FAST_BUF (4*K_BYTES) /* * not defined for backwards compatibility * (default is produced by OpenAlertFile() #define DEFAULT_FILE "alert.fast" */ #define DEFAULT_LIMIT (128*M_BYTES) typedef struct { TextLog* log; uint8_t packet_flag; } FileLogData; static void file_log_init(struct _SnortConfig *, char* args); static void file_log_term(int, void* arg); static int file_log_parse (void** config, char* args, const char* default_output_file); static void file_log_exec(void* packet, char* msg, void* arg, void* eventInfo); OUTPUT_SO_PUBLIC Output_Module_t OUTPUT_MODULE_DATA = { .api_major_version = OUTPUT_API_MAJOR_VERSION, .api_minor_version = OUTPUT_API_MINOR_VERSION, .module_version = OUTPUT_MOD_VERSION, .name = OUTPUT_NAME, .type = OUTPUT_TYPE, .default_file = "file", .load = file_log_init, .parse_args = file_log_parse, .postconfig = NULL, .alert_output = file_log_exec, .log_output = NULL, .rotate = NULL, .shutdown = file_log_term, .next = NULL }; /*********************Output plugin for file log*******************************/ static char* getFullName (char* dir, const char* filespec) { char *filename = NULL; char buffer[STD_BUF + 1]; if(filespec == NULL) { _dod.fatalMsg("no argument in this file option, " "remove extra ':' at the end of the alert option\n"); } buffer[STD_BUF] = '\0'; if(filespec[0] == '/') { /* absolute filespecs are saved as is */ filename = strdup(filespec); } else { /* relative filespec is considered relative to the log directory */ /* or /var/log if the log directory has not been set */ /* Make sure this function isn't called before log dir is set */ if (dir != NULL) { strncpy(buffer, dir, sizeof(buffer) - 1); } else { strncpy(buffer, "/var/log/snort", sizeof(buffer) - 1); } strncat(buffer, "/", STD_BUF - strlen(buffer)); strncat(buffer, filespec, STD_BUF - strlen(buffer)); buffer[sizeof(buffer) - 1] = '\0'; filename = strdup(buffer); } return filename; } static void file_log_init (struct _SnortConfig *sc, char* args) { init_output_module(sc, &OUTPUT_MODULE_DATA, args); _dod.logMsg("%s: version %d\n", __FUNCTION__, OUTPUT_MOD_VERSION); } static void file_log_term (int unused, void* arg) { FileLogData *data = (FileLogData *)arg; DEBUG_WRAP(_dod.debugMsg(DEBUG_LOG, "%s\n", "FileLog_Term");); /*free memory from FileLogData */ if ( data->log ) _dod.textLog_Term(data->log); free(data); /*free memory from FileLogData */ } static void file_log_exec(void* packet, char* msg, void* arg, void* eventInfo) { FileLogData *data = (FileLogData *)arg; SFSnortPacket *p = (SFSnortPacket*)packet; Event *event = (Event *)eventInfo; char filename[STD_BUF]; uint8_t *file_name; uint32_t name_size; if ( !event || ((event->sig_generator != GENERATOR_FILE_TYPE) && (event->sig_generator != GENERATOR_FILE_SIGNATURE))) return; _dod.logTimeStamp(data->log, p); /*Get the file name captured*/ if ( _dpd.fileAPI->get_file_name(p->stream_session_ptr, &file_name, &name_size)) { if (name_size > sizeof(filename)) name_size = sizeof(filename) - 1; memcpy(filename, file_name, name_size); filename[name_size] = '\0'; _dod.textLog_Puts(data->log, " [**] "); _dod.textLog_Print(data->log, " [File: %s, size: %d bytes]", filename, _dpd.fileAPI->get_file_size(p->stream_session_ptr)); } if (event->sig_generator == GENERATOR_FILE_SIGNATURE) { char sha256[SHA256_HASH_STR_SIZE + 1]; sha_to_str((char *)_dpd.fileAPI->get_sig_sha256(p->stream_session_ptr), sha256, SHA256_HASH_STR_SIZE + 1); sha256[SHA256_HASH_STR_SIZE] = '\0'; _dod.textLog_Print(data->log, " [signature: %s]", sha256); } if( p != NULL && _dod.active_PacketWasDropped() ) { _dod.textLog_Puts(data->log, " [Drop]"); } else if( p != NULL && _dod.active_PacketWouldBeDropped() ) { _dod.textLog_Puts(data->log, " [WDrop]"); } _dod.textLog_Puts(data->log, " [**] "); _dod.textLog_Print(data->log, "[%lu:%lu:%lu] ", (unsigned long) event->sig_generator, (unsigned long) event->sig_id, (unsigned long) event->sig_rev); if (_dod.ScAlertInterface()) { _dod.textLog_Print(data->log, " <%s> ", _dod.getDAQinterface()); } /*Ignore event message for file signature events*/ if ((msg != NULL) && (event->sig_generator == GENERATOR_FILE_TYPE)) { _dod.textLog_Puts(data->log, msg); } _dod.textLog_Puts(data->log, " [**] "); /* print the packet header to the alert file */ if ((p != NULL) && IPH_IS_VALID(p)) { _dod.textLog_Print(data->log, "{%s} ", _dod.getProtocolName(p)); _dod.logIpAddrs(data->log, p); } _dod.textLog_NewLine(data->log); _dod.textLog_Flush(data->log); } static int file_log_parse (void** config, char* args, const char* default_output_file) { char *tok; FileLogData *data; char* filename = NULL; unsigned long limit = DEFAULT_LIMIT; unsigned int bufSize = FAST_BUF; int i = 0; DEBUG_WRAP(_dod.debugMsg(DEBUG_LOG, "FileLog_Parse: %s\n", args);); data = (FileLogData *)calloc(1, sizeof(*data)); if ( !data ) { _dod.fatalMsg("file_log: unable to allocate memory!\n"); return OUTPUT_ERROR; } if ( !args ) args = ""; tok = strtok( args, " \t"); while ( tok ) { char *end; switch (i) { case 0: if ( !strcasecmp(tok, "stdout") ) { filename = strdup(tok); if (!filename) _dod.fatalMsg("file_log error in %s(%i): %s\n", *(_dod.config_file), *(_dod.config_line), tok); } else { char *dir = _dod.getLogDirectory(); filename = getFullName(dir, tok); } break; case 1: if ( !strcasecmp("packet", tok) ) { data->packet_flag = 1; bufSize = FULL_BUF; break; } /* in this case, only 2 options allowed */ else i++; /* fall thru so "packet" is optional ... */ case 2: limit = strtol(tok, &end, 10); if ( tok == end ) _dod.fatalMsg("file_log error in %s(%i): %s\n", *(_dod.config_file), *(_dod.config_line), tok); if ( end && toupper(*end) == 'G' ) limit <<= 30; /* GB */ else if ( end && toupper(*end) == 'M' ) limit <<= 20; /* MB */ else if ( end && toupper(*end) == 'K' ) limit <<= 10; /* KB */ break; case 3: _dod.fatalMsg("file_log: error in %s(%i): %s\n", *(_dod.config_file), *(_dod.config_line), tok); break; } tok = strtok( NULL, " " ); i++; } #ifdef DEFAULT_FILE if ( !filename ) filename = getFullName(_dod.getLogDirectory(), DEFAULT_FILE); #endif DEBUG_WRAP(_dod.debugMsg( DEBUG_INIT, "file_log: '%s' %d %ld\n", filename ? filename:"alert", data->packet_flag, limit );); if ((filename == NULL) && (_dod.getAlertFile() != NULL)) filename = _dod.SnortStrdup(_dod.getAlertFile()); data->log = _dod.textLog_Init(filename, bufSize, limit); if (filename != NULL) free(filename); *config = data; return OUTPUT_SUCCESS; } snort-2.9.6.0/src/dynamic-preprocessors/file/file_agent.h0000644000000000000000000000304612260565732020244 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 9.25.2012 - Initial Source Code. Hcao */ #ifndef _FILE_AGENT_H_ #define _FILE_AGENT_H_ #include "file_api.h" #include "file_inspect_config.h" #include "file_sha.h" #define FILE_NAME_LEN 200 typedef struct _FileInfo { char sha256[SHA256_HASH_SIZE]; size_t file_size; void *file_mem; } FileInfo; /* Initialize file processing. * This should be called when this preprocessor initialized (snort starts) */ void file_agent_init(FileInspectConf *); /* Close file processing. * This should be called when snort exit */ void file_agent_close(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/file/file_agent.c0000644000000000000000000004366012260565732020245 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** 4.11.2013 - Initial Source Code. Hcao ** ** File agent uses a separate thread to store files and also sends out ** to network. It uses file APIs and provides callbacks. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "sf_types.h" #include "spp_file.h" #include "file_agent.h" #include "mempool.h" #include "sf_dynamic_preprocessor.h" #include "circular_buffer.h" #include "file_sha.h" #include "sfPolicy.h" int sockfd = 0; /*Use circular buffer to synchronize writer/reader threads*/ static CircularBuffer* file_list; static volatile bool stop_file_capturing = false; static volatile bool capture_thread_running = false; static bool file_type_enabled = false; static bool file_signature_enabled = false; static bool file_capture_enabled = false; pthread_t capture_thread_tid; static pid_t capture_thread_pid; uint64_t capture_disk_avaiable; /* bytes available */ static pthread_cond_t file_available_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t file_list_mutex = PTHREAD_MUTEX_INITIALIZER; typedef struct _FILE_MESSAGE_HEADER { /* All values must be in network byte order */ uint16_t version; uint16_t type; uint32_t length; /* Does not include the header */ char filename[FILE_NAME_LEN]; } FileMessageHeader; #define FILE_HEADER_VERSION 0x0001 #define FILE_HEADER_DATA 0x0009 static int file_agent_save_file (FileInfo *, char *); static int file_agent_send_file (FileInfo *); static FileInfo* file_agent_get_file(void); static FileInfo *file_agent_finish_file(void); static File_Verdict file_agent_type_callback(void*, void*, uint32_t, bool); static File_Verdict file_agent_signature_callback(void*, void*, uint8_t*, uint64_t, FileState *, bool); static int file_agent_queue_file(void*, void *); static int file_agent_init_socket(char *hostname, int portno); /* Initialize sockets for file transfer to other host * * Args: * char *hostname: host name or IP address of receiver * int portno: port number of receiver */ int file_agent_init_socket(char *hostname, int portno) { struct sockaddr_in serv_addr; struct hostent *server; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { FILE_FATAL_ERROR("File inspect: ERROR creating socket!\n"); return -1; } /*get the address info by either host name or IP address*/ server = gethostbyname(hostname); if (server == NULL) { _dpd.errMsg("File inspect: ERROR, no such host\n"); close(sockfd); return -1; } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) { _dpd.errMsg("File inspect: ERROR connecting host %s: %d!\n", hostname, portno); close(sockfd); return -1; } _dpd.logMsg("File inspect: Connection established on host: %s, port: %d\n", hostname, portno); return 0; } /*Send file data to other host*/ static void file_agent_send_data(int socket_fd, const uint8_t *resp, uint32_t len) { ssize_t numsent; unsigned total_len = len; unsigned total = 0; do { numsent = write(socket_fd, (*(uint8_t **)&resp) + total, total_len - total); if (!numsent) return; else if (numsent > 0) total += numsent; else if (errno != EINTR && errno != EAGAIN) { file_inspect_stats.file_transfer_failures++; return; } } while (total < total_len); } /* Process all the files in the file queue*/ static inline void file_agent_process_files(CircularBuffer *file_list, FileInspectConf* conf ) { while (!cbuffer_is_empty(file_list)) { FileInfo *file; file = file_agent_get_file(); if (file && file->sha256) { /* Save to disk */ if (conf->capture_dir) file_agent_save_file(file, conf->capture_dir); /* Send to other host */ if (conf->hostname) file_agent_send_file(file); /* Default, memory only */ } file = file_agent_finish_file(); if (file) { _dpd.fileAPI->release_file(file->file_mem); free(file); } } } /* This is the main thread for file capture, * either store to disk or send to network based on setting */ static void* FileCaptureThread(void *arg) { FileInspectConf* conf = (FileInspectConf*) arg; #if defined(LINUX) && defined(SYS_gettid) capture_thread_pid = syscall(SYS_gettid); #else capture_thread_pid = getpid(); #endif capture_thread_running = true; capture_disk_avaiable = conf->capture_disk_size<<20; while(1) { file_agent_process_files(file_list, conf); if (stop_file_capturing) break; pthread_mutex_lock(&file_list_mutex); if (cbuffer_is_empty(file_list)) pthread_cond_wait(&file_available_cond, &file_list_mutex); pthread_mutex_unlock(&file_list_mutex); } capture_thread_running = false; return NULL; } /* Add another thread for file capture to disk or network * When settings are changed, snort must be restarted to get it applied */ void file_agent_init(FileInspectConf* conf) { int rval; const struct timespec thread_sleep = { 0, 100 }; sigset_t mask; /*Need to check configuration to decide whether to enable them*/ if (conf->file_type_enabled) { _dpd.fileAPI->enable_file_type(file_agent_type_callback); file_type_enabled = true; } if (conf->file_signature_enabled) { _dpd.fileAPI->enable_file_signature(file_agent_signature_callback); file_signature_enabled = true; } if (conf->file_capture_enabled) { _dpd.fileAPI->enable_file_capture(file_agent_signature_callback); file_capture_enabled = true; } if (conf->hostname) { file_agent_init_socket(conf->hostname, conf->portno); } /* Spin off the file capture handler thread. */ sigemptyset(&mask); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGQUIT); sigaddset(&mask, SIGPIPE); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGHUP); sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR2); sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGURG); sigaddset(&mask, SIGVTALRM); pthread_sigmask(SIG_SETMASK, &mask, NULL); file_list = cbuffer_init(conf->file_capture_queue_size); if(!file_list) { FILE_FATAL_ERROR("File capture: Unable to create file capture queue!"); } if ((rval = pthread_create(&capture_thread_tid, NULL, &FileCaptureThread, conf)) != 0) { sigemptyset(&mask); pthread_sigmask(SIG_SETMASK, &mask, NULL); FILE_FATAL_ERROR("File capture: Unable to create a " "processing thread: %s", strerror(rval)); } while (!capture_thread_running) nanosleep(&thread_sleep, NULL); sigemptyset(&mask); pthread_sigmask(SIG_SETMASK, &mask, NULL); _dpd.logMsg("File capture thread started tid=%p (pid=%u)\n", (void *) capture_thread_tid, capture_thread_pid); } /* * Files are queued in a list * Add one file to the list */ static int file_agent_queue_file(void* ssnptr, void *file_mem) { FileInfo *finfo; char *sha256; if (cbuffer_is_full(file_list)) { return -1; } finfo = calloc(1, sizeof (*finfo)); if (!finfo) { return -1; } sha256 = (char *) _dpd.fileAPI->get_sig_sha256(ssnptr); if (!sha256) { return -1; } memcpy(finfo->sha256, sha256, SHA256_HASH_SIZE); finfo->file_mem = file_mem; finfo->file_size = _dpd.fileAPI->get_file_capture_size(file_mem); pthread_mutex_lock(&file_list_mutex); if(cbuffer_write(file_list, finfo)) { pthread_mutex_unlock(&file_list_mutex); free(finfo); return -1; } pthread_cond_signal(&file_available_cond); pthread_mutex_unlock(&file_list_mutex); return 0; } /* * Files are queued in a list * Get one file from the list */ static FileInfo* file_agent_get_file(void) { ElemType file; if(cbuffer_peek(file_list, &file)) { return NULL; } return (FileInfo*) file; } /* * Files are queued in a list * Remove one file from the list * The file in head is removed */ static FileInfo* file_agent_finish_file(void) { ElemType file; if(cbuffer_read(file_list, &file)) { return NULL; } return (FileInfo*) file; } /* * writing file to the disk. * * In the case of interrupt errors, the write is retried, but only for a * finite number of times. * * Arguments * uint8_t *: The buffer containing the data to write * size_t: The length of the data to write * FILE *fh: File handler * * Returns: None * */ static void file_agent_write(uint8_t *buf, size_t buf_len, FILE *fh) { int max_retries = 3; size_t bytes_written = 0; int err; /* Nothing to write or nothing to write to */ if ((buf == NULL) || (fh == NULL)) return; /* writing several times */ do { size_t bytes_left = buf_len - bytes_written; bytes_written += fwrite(buf + bytes_written, 1, bytes_left, fh); err = ferror(fh); if (err && (err != EINTR) && (err != EAGAIN)) { break; } max_retries--; } while ((max_retries > 0) && (bytes_written < buf_len)); if (bytes_written < buf_len) { _dpd.errMsg("File inspect: disk writing error - %s!\n", strerror(err)); } } /* Store files on local disk */ static int file_agent_save_file(FileInfo *file, char *capture_dir) { FILE *fh; struct stat buffer; char filename[FILE_NAME_LEN + 1]; int filename_len; char *findex = filename; uint8_t *buff; int size; void *file_mem; filename_len = snprintf(filename, FILE_NAME_LEN, "%s", capture_dir); if (filename_len >= FILE_NAME_LEN ) { free(file); return -1; } file_inspect_stats.files_to_disk_total++; findex += filename_len; filename_len = sha_to_str(file->sha256, findex, FILE_NAME_LEN - filename_len); /*File exists*/ if(stat (filename, &buffer) == 0) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "File exist: %s\n", filename);); file_inspect_stats.file_duplicates_total++; return -1; } if (!capture_disk_avaiable) { return -1; } else if (capture_disk_avaiable < file->file_size) { capture_disk_avaiable = 0; _dpd.errMsg("File inspect: exceeding allocated disk size, " "can't store file!\n"); return -1; } else { capture_disk_avaiable -= file->file_size; } fh = fopen(filename, "w"); if (!fh ) { DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Can't create file: %s\n", filename);); return -1; } file_mem = file->file_mem; /*Check the file buffer*/ while (file_mem) { file_mem = _dpd.fileAPI->read_file(file_mem, &buff, &size); /*Get file from file buffer*/ if (!buff || !size ) { file_inspect_stats.file_read_failures++; _dpd.logMsg("File inspect: can't read file!\n"); return -1; } file_agent_write(buff, size, fh); } fclose(fh); file_inspect_stats.files_saved++; file_inspect_stats.file_data_to_disk += file->file_size; return 0; } /* Send file data to other host*/ static int file_agent_send_file(FileInfo *file) { /*Save the file*/ FileMessageHeader fheader; void *file_mem; uint8_t *buff; int size; if (!sockfd) { return 0; } /*Send the file name*/ fheader.version = htons(FILE_HEADER_VERSION); fheader.type = htons(FILE_HEADER_DATA); fheader.length = htonl(file->file_size); memset(fheader.filename, 0, sizeof(fheader.filename)); sha_to_str(file->sha256, fheader.filename, sizeof (fheader.filename)); file_agent_send_data (sockfd, (uint8_t *)&fheader, sizeof(fheader)); DEBUG_WRAP(DebugMessage(DEBUG_FILE, "sent file: %s, with size: %d\n", fheader.filename, file->file_size);); file_mem = file->file_mem; /*Check the file buffer*/ while (file_mem) { file_mem = _dpd.fileAPI->read_file(file_mem, &buff, &size); /*Get file from file buffer*/ if (!buff || !size ) { file_inspect_stats.file_read_failures++; _dpd.logMsg("File inspect: can't read file!\n"); return -1; } file_agent_send_data(sockfd, buff, size); } file_inspect_stats.files_to_host_total++; file_inspect_stats.file_data_to_host += file->file_size; return 0; } /* Close file agent * 1) stop capture thread: waiting all files queued to be captured * 2) free file queue * 3) close socket */ void file_agent_close(void) { int rval; stop_file_capturing = true; pthread_mutex_lock(&file_list_mutex); pthread_cond_signal(&file_available_cond); pthread_mutex_unlock(&file_list_mutex); if ((rval = pthread_join(capture_thread_tid, NULL)) != 0) { FILE_FATAL_ERROR("Thread termination returned an error: %s\n", strerror(rval)); } while(capture_thread_running) sleep(1); cbuffer_free(file_list); if (sockfd) { close(sockfd); sockfd = 0; } } /* * File type callback when file type is identified * * For file capture or file signature, FILE_VERDICT_PENDING must be returned */ static File_Verdict file_agent_type_callback(void* p, void* ssnptr, uint32_t file_type_id, bool upload) { file_inspect_stats.file_types_total++; if (file_signature_enabled || file_capture_enabled) return FILE_VERDICT_UNKNOWN; else return FILE_VERDICT_LOG; } static inline int file_agent_capture_error(FileCaptureState capture_state) { if (capture_state != FILE_CAPTURE_SUCCESS) { file_inspect_stats.file_reserve_failures++; _dpd.logMsg("File inspect: can't reserve file!\n"); switch(capture_state) { case FILE_CAPTURE_MIN: file_inspect_stats.file_capture_min++; break; case FILE_CAPTURE_MAX: file_inspect_stats.file_capture_max++; break; case FILE_CAPTURE_MEMCAP: file_inspect_stats.file_capture_memcap++; break; default: break; } return 1; } return 0; } /* * File signature callback when file transfer is completed * or capture/singature is aborted */ static File_Verdict file_agent_signature_callback (void* p, void* ssnptr, uint8_t* file_sig, uint64_t file_size, FileState *state, bool upload) { FileCaptureInfo *file_mem = NULL; FileCaptureState capture_state; File_Verdict verdict = FILE_VERDICT_UNKNOWN; FileInspectConf *conf = sfPolicyUserDataGetDefault(file_config); uint64_t capture_file_size; SFSnortPacket *pkt = (SFSnortPacket*)p; file_inspect_stats.file_signatures_total++; if (conf && file_sig) { FileSigInfo *file_verdict; file_verdict = (FileSigInfo *)sha_table_find(conf->sig_table, file_sig); if (file_verdict) { #if defined(DEBUG_MSGS) || defined (REG_TEST) static int verdict_delay = 0; if ((verdict_delay++) < conf->verdict_delay) { verdict = FILE_VERDICT_PENDING; } else #endif verdict = file_verdict->verdict; } } if (!file_capture_enabled) return verdict; /* Check whether there is any error during processing file*/ if (state->capture_state != FILE_CAPTURE_SUCCESS) { if (state->sig_state != FILE_SIG_PROCESSING) file_agent_capture_error(state->capture_state); return verdict; } /* Reserve buffer for file capture */ capture_state = _dpd.fileAPI->reserve_file(ssnptr, &file_mem); /*Check whether there is any error for the last piece of file*/ if (file_agent_capture_error(capture_state)) { return verdict; } /* Check file size */ capture_file_size = _dpd.fileAPI->get_file_capture_size(file_mem); if (file_size != capture_file_size) { _dpd.logMsg("File inspect: file size error %d != %d\n", file_size, capture_file_size); } /*Save the file to our file queue*/ if (file_agent_queue_file(pkt->stream_session_ptr, file_mem) < 0) { file_inspect_stats.file_agent_memcap_failures++; _dpd.logMsg("File inspect: can't queue file!\n"); return verdict; } return verdict; } snort-2.9.6.0/src/dynamic-preprocessors/file/spp_file.h0000644000000000000000000000430012260565732017742 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Definitions, structs, function prototype(s) for * the file preprocessor. * Author: Hui Cao */ #ifndef SPP_FILE_H #define SPP_FILE_H #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "snort_bounds.h" typedef struct _File_Stats { uint64_t file_types_total; /* Total number of file type callbacks */ uint64_t file_signatures_total; /* Total number of file signature callbacks */ uint64_t files_to_disk_total; /* Files needed to be saved on disk */ uint64_t file_duplicates_total; /* Files already on disk */ uint64_t files_saved; /* Files saved on disk */ uint64_t file_reserve_failures; uint64_t file_capture_min; uint64_t file_capture_max; uint64_t file_capture_memcap; uint64_t file_read_failures; uint64_t file_agent_memcap_failures; uint64_t file_data_to_disk; /*file data stored */ uint64_t files_to_host_total; /*files sent */ uint64_t file_data_to_host; /*file data sent */ uint64_t file_transfer_failures; /*file transfer failures */ } File_Stats; /* Prototypes for public interface, initialzie file inspect functions */ extern void SetupFileInspect(void); extern File_Stats file_inspect_stats; extern tSfPolicyUserContextId file_config; #define FILE_FATAL_ERROR DynamicPreprocessorFatalMessage #endif /* SPP_FILE_H */ snort-2.9.6.0/src/dynamic-preprocessors/file/spp_file.c0000644000000000000000000003076112260565732017747 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * File preprocessor * Author: Hui Cao * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_plugin_api.h" #include "snort_debug.h" #include "preprocids.h" #include "spp_file.h" #include "sf_preproc_info.h" #include #include #include #ifndef WIN32 #include #include #endif #include #include #include "file_agent.h" #include "file_inspect_config.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_FILE"; #define FILE_PREPROC_NAME "file_inspect" #define SetupFileInspect DYNAMIC_PREPROC_SETUP /* * Function prototype(s) */ static void FileInit( struct _SnortConfig*, char* ); static void print_file_stats(int exiting); static void FileFreeConfig(tSfPolicyUserContextId config); static int FileCheckConfig(struct _SnortConfig *); static void FileCleanExit(int, void *); static void FileUpdateConfig(FileInspectConf *, tSfPolicyUserContextId); /** File configuration per Policy */ tSfPolicyUserContextId file_config = NULL; #ifdef SNORT_RELOAD static void FileReload(struct _SnortConfig *, char *, void **); static int FileReloadVerify(struct _SnortConfig *, void *); static void * FileReloadSwap(struct _SnortConfig *, void *); static void FileReloadSwapFree(void *); #endif File_Stats file_inspect_stats; /* Called at preprocessor setup time. Links preprocessor keyword * to corresponding preprocessor initialization function. * * PARAMETERS: None. * * RETURNS: Nothing. * */ void SetupFileInspect(void) { /* Link preprocessor keyword to initialization function * in the preprocessor list. */ #ifndef SNORT_RELOAD _dpd.registerPreproc( "file_inspect", FileInit ); #else _dpd.registerPreproc("file_inspect", FileInit, FileReload, FileReloadVerify, FileReloadSwap, FileReloadSwapFree); #endif } /* Initializes the File preprocessor module and registers * it in the preprocessor list. * * PARAMETERS: * * argp: Pointer to argument string to process for config * data. * * RETURNS: Nothing. */ static void FileInit(struct _SnortConfig *sc, char *argp) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); FileInspectConf *pPolicyConfig = NULL; if (file_config == NULL) { /*create a context*/ file_config = sfPolicyConfigCreate(); if (file_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for File config.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupFile(): The Stream preprocessor must be enabled.\n"); } _dpd.addPreprocConfCheck(sc, FileCheckConfig); _dpd.registerPreprocStats(FILE_PREPROC_NAME, print_file_stats); _dpd.addPreprocExit(FileCleanExit, NULL, PRIORITY_LAST, PP_FILE_INSPECT); } sfPolicyUserPolicySet (file_config, policy_id); pPolicyConfig = (FileInspectConf *)sfPolicyUserDataGetCurrent(file_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("File preprocessor can only be " "configured once.\n"); } pPolicyConfig = (FileInspectConf *)calloc(1, sizeof(FileInspectConf)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "File preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(file_config, pPolicyConfig); file_config_parse(pPolicyConfig, (u_char *)argp); FileUpdateConfig(pPolicyConfig, file_config); file_agent_init(pPolicyConfig); } static void FileUpdateConfig(FileInspectConf *pPolicyConfig, tSfPolicyUserContextId context) { FileInspectConf *defaultConfig = (FileInspectConf *)sfPolicyUserDataGetDefault(context); if (pPolicyConfig == defaultConfig) { if (!pPolicyConfig->file_capture_queue_size) pPolicyConfig->file_capture_queue_size = FILE_CAPTURE_QUEUE_SIZE_DEFAULT; if (!pPolicyConfig->capture_disk_size) pPolicyConfig->capture_disk_size = FILE_CAPTURE_DISK_SIZE_DEFAULT; } else if (defaultConfig == NULL) { if (pPolicyConfig->file_capture_queue_size) { DynamicPreprocessorFatalMessage("%s(%d) => File inspect: " "file capture queue size must be configured " "in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } } else { pPolicyConfig->file_capture_queue_size = defaultConfig->file_capture_queue_size; } } static int FileFreeConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { FileInspectConf *pPolicyConfig = (FileInspectConf *)pData; //do any housekeeping before freeing FileInspectConf file_config_free(pPolicyConfig); sfPolicyUserDataClear (config, policyId); free(pPolicyConfig); return 0; } static void FileFreeConfig(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, FileFreeConfigPolicy); sfPolicyConfigDelete(config); } static int FileCheckPolicyConfig(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData) { _dpd.setParserPolicy(sc, policyId); if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { DynamicPreprocessorFatalMessage("FileCheckPolicyConfig(): The Stream preprocessor must be enabled.\n"); } return 0; } static int FileCheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate (sc, file_config, FileCheckPolicyConfig))) return rval; return 0; } static void FileCleanExit(int signal, void *data) { if (file_config != NULL) { file_agent_close(); FileFreeConfig(file_config); file_config = NULL; } } #ifdef SNORT_RELOAD static void FileReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId file_swap_config = (tSfPolicyUserContextId)*new_config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); FileInspectConf * pPolicyConfig = NULL; if (file_swap_config == NULL) { //create a context file_swap_config = sfPolicyConfigCreate(); if (file_swap_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for File config.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupFile(): The Stream preprocessor must be enabled.\n"); } *new_config = (void *)file_swap_config; } sfPolicyUserPolicySet (file_swap_config, policy_id); pPolicyConfig = (FileInspectConf *)sfPolicyUserDataGetCurrent(file_swap_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("File preprocessor can only be " "configured once.\n"); } pPolicyConfig = (FileInspectConf *)calloc(1, sizeof(FileInspectConf)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "File preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(file_swap_config, pPolicyConfig); file_config_parse(pPolicyConfig, (u_char *)args); FileUpdateConfig(pPolicyConfig, file_config); } static int FileReloadVerify(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId file_swap_config = (tSfPolicyUserContextId)swap_config; FileInspectConf * pPolicyConfig = NULL; FileInspectConf * pCurrentConfig = NULL; if (file_swap_config == NULL) return 0; pPolicyConfig = (FileInspectConf *)sfPolicyUserDataGet(file_swap_config, _dpd.getDefaultPolicy()); if (!pPolicyConfig) return 0; if (file_config != NULL) { pCurrentConfig = (FileInspectConf *)sfPolicyUserDataGet(file_config, _dpd.getDefaultPolicy()); } if (!pCurrentConfig) return 0; if (file_config_compare(pCurrentConfig, pPolicyConfig)) { _dpd.errMsg("File inspect reload: Changing file settings requires a restart.\n"); return -1; } if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SetupFile(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } static int FileFreeUnusedConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { FileInspectConf *pPolicyConfig = (FileInspectConf *)pData; //do any housekeeping before freeing FileInspectConf if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); free(pPolicyConfig); } return 0; } static void * FileReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId file_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = file_config; if (file_swap_config == NULL) return NULL; file_config = file_swap_config; file_swap_config = NULL; sfPolicyUserDataFreeIterate (old_config, FileFreeUnusedConfigPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) { /* No more outstanding configs - free the config array */ return (void *)old_config; } return NULL; } static void FileReloadSwapFree(void *data) { if (data == NULL) return; FileFreeConfig((tSfPolicyUserContextId)data); } #endif static void print_file_stats(int exiting) { _dpd.logMsg("File Preprocessor Statistics\n"); _dpd.logMsg(" Total file type callbacks: "FMTu64("-10")" \n", file_inspect_stats.file_types_total); _dpd.logMsg(" Total file signature callbacks: "FMTu64("-10")" \n", file_inspect_stats.file_signatures_total); _dpd.logMsg(" Total files would saved to disk: "FMTu64("-10")" \n", file_inspect_stats.files_to_disk_total); _dpd.logMsg(" Total files saved to disk: "FMTu64("-10")" \n", file_inspect_stats.files_saved); _dpd.logMsg(" Total file data saved to disk: "FMTu64("-10")"bytes\n", file_inspect_stats.file_data_to_disk); _dpd.logMsg(" Total files duplicated: "FMTu64("-10")" \n", file_inspect_stats.file_duplicates_total); _dpd.logMsg(" Total files reserving failed: "FMTu64("-10")" \n", file_inspect_stats.file_reserve_failures); _dpd.logMsg(" Total file capture min: "FMTu64("-10")" \n", file_inspect_stats.file_capture_min); _dpd.logMsg(" Total file capture max: "FMTu64("-10")" \n", file_inspect_stats.file_capture_max); _dpd.logMsg(" Total file capture memcap: "FMTu64("-10")" \n", file_inspect_stats.file_capture_memcap); _dpd.logMsg(" Total files reading failed: "FMTu64("-10")" \n", file_inspect_stats.file_read_failures); _dpd.logMsg(" Total file agent memcap failures: "FMTu64("-10")" \n", file_inspect_stats.file_agent_memcap_failures); _dpd.logMsg(" Total files sent: "FMTu64("-10")" \n", file_inspect_stats.files_to_host_total); _dpd.logMsg(" Total file data sent: "FMTu64("-10")" \n", file_inspect_stats.file_data_to_host); _dpd.logMsg(" Total file transfer failures: "FMTu64("-10")" \n", file_inspect_stats.file_transfer_failures); } snort-2.9.6.0/src/dynamic-preprocessors/file/Makefile.am0000644000000000000000000000431012232305217020012 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs -I./include libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_file_preproc.la libsf_file_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_file_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_file_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sfPolicyUserData.c endif libsf_file_preproc_la_SOURCES = \ spp_file.c \ spp_file.h \ file_agent.c \ file_agent.h \ file_event_log.c \ file_event_log.h \ file_inspect_config.c \ file_inspect_config.h \ file_sha.c \ file_sha.h \ ./include/output_lib.c \ ./include/circular_buffer.c BUILT_SOURCES = \ include/output_lib.c \ include/output_api.h \ include/output_lib.h \ include/output_common.h \ include/sf_textlog.h \ include/circular_buffer.c \ include/circular_buffer.h EXTRA_DIST = \ sf_file.dsp copy_headers = \ mkdir -p include; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi include/output_lib.c: ${top_srcdir}/src/dynamic-output/libs/output_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/output_api.h: ${top_srcdir}/src/dynamic-output/plugins/output_api.h @src_header=$?; dst_header=$@; $(copy_headers) include/output_lib.h: ${top_srcdir}/src/dynamic-output/plugins/output_lib.h @src_header=$?; dst_header=$@; $(copy_headers) include/output_common.h: ${top_srcdir}/src/dynamic-output/plugins/output_common.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_textlog.h: ${top_srcdir}/src/sfutil/sf_textlog.h @src_header=$?; dst_header=$@; $(copy_headers) include/circular_buffer.h: ${top_srcdir}/src/file-process/circular_buffer.h @src_header=$?; dst_header=$@; $(copy_headers) include/circular_buffer.c: ${top_srcdir}/src/file-process/circular_buffer.c @src_header=$?; dst_header=$@; $(copy_headers) clean-local: rm -rf include all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/file/Makefile.in0000644000000000000000000005555012260606521020042 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/file DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_file_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_file_preproc_la_OBJECTS = spp_file.lo file_agent.lo \ file_event_log.lo file_inspect_config.lo file_sha.lo \ output_lib.lo circular_buffer.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_file_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_file_preproc_la_OBJECTS = $(am_libsf_file_preproc_la_OBJECTS) \ $(nodist_libsf_file_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_file_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_file_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_file_preproc_la_SOURCES) \ $(nodist_libsf_file_preproc_la_SOURCES) DIST_SOURCES = $(libsf_file_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs -I./include INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_file_preproc.la libsf_file_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_file_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_file_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_file_preproc_la_SOURCES = \ spp_file.c \ spp_file.h \ file_agent.c \ file_agent.h \ file_event_log.c \ file_event_log.h \ file_inspect_config.c \ file_inspect_config.h \ file_sha.c \ file_sha.h \ ./include/output_lib.c \ ./include/circular_buffer.c BUILT_SOURCES = \ include/output_lib.c \ include/output_api.h \ include/output_lib.h \ include/output_common.h \ include/sf_textlog.h \ include/circular_buffer.c \ include/circular_buffer.h EXTRA_DIST = \ sf_file.dsp copy_headers = \ mkdir -p include; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/file/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/file/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_file_preproc.la: $(libsf_file_preproc_la_OBJECTS) $(libsf_file_preproc_la_DEPENDENCIES) $(EXTRA_libsf_file_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_file_preproc_la_LINK) -rpath $(libdir) $(libsf_file_preproc_la_OBJECTS) $(libsf_file_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< output_lib.lo: ./include/output_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o output_lib.lo `test -f './include/output_lib.c' || echo '$(srcdir)/'`./include/output_lib.c circular_buffer.lo: ./include/circular_buffer.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o circular_buffer.lo `test -f './include/circular_buffer.c' || echo '$(srcdir)/'`./include/circular_buffer.c sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-libLTLIBRARIES include/output_lib.c: ${top_srcdir}/src/dynamic-output/libs/output_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/output_api.h: ${top_srcdir}/src/dynamic-output/plugins/output_api.h @src_header=$?; dst_header=$@; $(copy_headers) include/output_lib.h: ${top_srcdir}/src/dynamic-output/plugins/output_lib.h @src_header=$?; dst_header=$@; $(copy_headers) include/output_common.h: ${top_srcdir}/src/dynamic-output/plugins/output_common.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_textlog.h: ${top_srcdir}/src/sfutil/sf_textlog.h @src_header=$?; dst_header=$@; $(copy_headers) include/circular_buffer.h: ${top_srcdir}/src/file-process/circular_buffer.h @src_header=$?; dst_header=$@; $(copy_headers) include/circular_buffer.c: ${top_srcdir}/src/file-process/circular_buffer.c @src_header=$?; dst_header=$@; $(copy_headers) clean-local: rm -rf include all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/file/include/0000755000000000000000000000000012260606565017476 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/file/include/circular_buffer.c0000644000000000000000000001205512260606565022722 00000000000000/* ** ** ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2013-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Author(s): Hui Cao ** ** NOTES ** ** Circular buffer is thread safe for one writer and one reader thread ** ** This implementaton is inspired by one slot open approach. ** See http://en.wikipedia.org/wiki/Circular_buffer ** ** 5.25.13 - Initial Source Code. Hui Cao */ #include "sf_types.h" #include "circular_buffer.h" #include #include /* Circular buffer object */ struct _CircularBuffer{ uint64_t size; /* maximum number of elements */ uint64_t start; /* index of oldest element, reader update only */ uint64_t end; /* index to write new element, writer update only*/ uint64_t under_run; uint64_t over_run; ElemType *elems; /* vector of elements */ uint64_t total_write; uint64_t total_read; }; /* This approach adds one bit to end and start pointers */ CircularBuffer * cbuffer_init(uint64_t size) { CircularBuffer* cb = calloc(1, sizeof(*cb)); if ( !cb ) return NULL; cb->size = size + 1; cb->elems = (ElemType *)calloc(cb->size, sizeof(ElemType)); if (!cb->elems) { free(cb); return NULL; } return cb; } void cbuffer_free(CircularBuffer *cb) { if(cb && cb->elems) { free(cb->elems); cb->elems = NULL; } free(cb); } /* We use mirror flag to detection full or empty efficiently*/ int cbuffer_is_full(CircularBuffer *cb) { uint64_t next = cb->end + 1; if ( next == cb->size ) next = 0; return (next == cb->start); } /* We use mirror flag to detection full or empty efficiently*/ int cbuffer_is_empty(CircularBuffer *cb) { return (cb->end == cb->start); } /* Returns number of elements in use*/ uint64_t cbuffer_used(CircularBuffer *cb) { /* cb->end < cb->start means passing the end of buffer */ if (cb->end < cb->start) { return (cb->size + cb->end - cb->start); } else { return (cb->end - cb->start); } } /* Returns number of free elements*/ uint64_t cbuffer_available(CircularBuffer *cb) { return (cbuffer_size(cb) - cbuffer_used(cb)); } /* Returns total number of elements*/ uint64_t cbuffer_size(CircularBuffer *cb) { return (cb->size - 1); } /* * Add one element to the buffer, * * Args: * CircularBuffer *: buffer * ElemType elem: the element to be added * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_write(CircularBuffer *cb, const ElemType elem) { uint64_t w = cb->end; if ( cbuffer_is_full (cb)) /* full, return error */ { cb->over_run++; return CB_FAIL; } cb->elems[w++] = elem; if ( w == cb->size ) w = 0; cb->end = w; cb->total_write++; return CB_SUCCESS; } /* * Read one element from the buffer and remove it from buffer, * * Args: * CircularBuffer *: buffer * ElemType *elem: the element pointer to be stored * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_read(CircularBuffer *cb, ElemType *elem) { uint64_t r = cb->start; if (cbuffer_is_empty(cb)) /* Empty, return error */ { cb->under_run++; return CB_FAIL; } *elem = cb->elems[r++]; if ( r == cb->size ) r = 0; cb->start = r; cb->total_read++; return CB_SUCCESS; } /* * Read one element from the buffer and no change on buffer * * Args: * CircularBuffer *: buffer * ElemType *elem: the element pointer to be stored * Return: * CB_FAIL * CB_SUCCESS */ int cbuffer_peek(CircularBuffer *cb, ElemType *elem) { if (cbuffer_is_empty(cb)) /* Empty, return error */ return CB_FAIL; *elem = cb->elems[cb->start]; return CB_SUCCESS; } /* Returns total number of reads*/ uint64_t cbuffer_num_reads(CircularBuffer *cb) { return (cb->total_read); } /* Returns total number of writes*/ uint64_t cbuffer_num_writes(CircularBuffer *cb) { return (cb->total_write); } /* Returns total number of writer overruns*/ uint64_t cbuffer_num_over_runs(CircularBuffer *cb) { return (cb->over_run); } /* Returns total number of reader overruns*/ uint64_t cbuffer_num_under_runs(CircularBuffer *cb) { return (cb->under_run); } snort-2.9.6.0/src/dynamic-preprocessors/file/include/output_lib.c0000644000000000000000000000542312260606565021754 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2012-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ** Date: 01-27-2012 ** Author: Hui Cao */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "output_api.h" #include "output_lib.h" extern char *file_name; extern int file_line; DynamicOutputData _dod; OUTPUT_SO_PUBLIC int initOutputPlugins(void *dod) { DynamicOutputData* outputData = (DynamicOutputData*)dod; /*Check the version*/ if (!dod) return OUTPUT_ERROR; if (outputData->majorVersion != OUTPUT_DATA_MAJOR_VERSION) { printf("ERROR major version %d != %d\n", outputData->majorVersion, OUTPUT_DATA_MAJOR_VERSION); return OUTPUT_ERROR; } if (outputData->minorVersion < OUTPUT_DATA_MINOR_VERSION) { printf("ERROR minor version %d < %d\n", outputData->minorVersion, OUTPUT_DATA_MINOR_VERSION); return OUTPUT_ERROR; } if (outputData->size < sizeof(DynamicOutputData)) { printf("ERROR size %d != %u\n", outputData->size, (unsigned)sizeof(*outputData)); return OUTPUT_ERROR; } _dod = *((DynamicOutputData*)dod); return OUTPUT_SUCCESS; } void init_output_module(struct _SnortConfig *sc, Output_Module_t *om, char *args) { void *config; if (!om) return; printf("Initializing module %s \n", om->name); om->parse_args(&config, args, om->default_file); if (om->alert_output) { _dod.addOutputModule(sc, om->alert_output, DYNAMIC_OUTPUT_TYPE_FLAG__ALERT, config); } if (om->log_output) { _dod.addOutputModule(sc, om->log_output, DYNAMIC_OUTPUT_TYPE_FLAG__LOG, config); } #ifdef SNORT_RELOAD if (om->rotate) { _dod.addReload(om->rotate, config); } #endif if (om->postconfig) { _dod.addPostconfig(sc, om->postconfig, config); } if (om->shutdown) { _dod.addCleanExit(om->shutdown, config); } } snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/0000755000000000000000000000000012260606565016720 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/spp_rzb-saac.c0000644000000000000000000001243512260565732021375 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2005-2013 Sourcefire, Inc. ** Copyright (C) 1998-2005 Martin Roesch ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, ** USA */ /* $Id$ */ /* Snort Preprocessor Plugin Source File RZB */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_STRINGS_H #include #endif #include #include #include #include #include #include "sf_types.h" #include "preprocids.h" #include "sf_snort_packet.h" #include "sf_dynamic_preproc_lib.h" #include "sf_dynamic_preprocessor.h" #include "snort_debug.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "sf_preproc_info.h" #define CONF_SEPARATORS " \t\n\r" #define RZB_CONF "rzb_conf" #define PP_SAAC 6868 #include #include "rzb_smtp-collector.h" #include "rzb_http-server.h" #include "rzb_http-client.h" #define RZB_COLLECT_DISP_GID 3535 #define RZB_COLLECT_DISP_SID 3535 #define RZB_COLLECT_DISP_MESG "Bad file found" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 0; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_RZB_SaaC_Preprocessor"; #define SetupRZB DYNAMIC_PREPROC_SETUP void * dlHandle = NULL; // For the API library static void RZBCleanExit(int, void *); static void RZBProcess(void *, void *); /* list of function prototypes for this preprocessor */ static void RZBInit(char *); #ifdef SNORT_RELOAD static void RZBReload(char *); static void * RZBReloadSwap(void); static void RZBReloadSwapFree(void *); #endif extern char *maxToken; void __attribute__((constructor)) detect_init() { printf("Razorback SaaC Initializing.\n"); init_HTTP_PCREs(); } void __attribute__((destructor)) detect_fini() { printf("Razorback SaaC shutting down\n"); } static void RZBCleanExit(int signal, void *unused) { rzb_collection.finiRZB(10); } #ifdef SNORT_RELOAD static void RZBReload(char *args) { printf("Razorback SaaC RZBReload() not implemented\n"); } static void * RZBReloadSwap(void) { printf("Razorback SaaC RZBReloadSwap() not implemented\n"); return NULL; } static void RZBReloadSwapFree(void *data) { printf("Razorback SaaC RZBReloadSwapFree() not implemented\n"); } #endif void RZBProcess(void *p, void *context) { SFSnortPacket *sp = (SFSnortPacket *)p; // preconditions - what we registered for assert(IsTCP(sp)); // Only rebuilt packets from server if (sp->src_port == 80 && !(sp->flags & FLAG_REBUILT_STREAM) && sp->payload_size != 0) { ProcessFromServer(sp); return; } // No rebuilt packets to server, and only packets with data if(sp->dst_port == 80 && !(sp->flags & FLAG_REBUILT_STREAM) && sp->payload_size != 0) { ProcessFromClient(sp); return; } if(sp->dst_port == 25 && (sp->flags & FLAG_REBUILT_STREAM) && sp->payload_size != 0) { smtpdumpereval(sp); return; } return; } static int functionsRegistered = 0; static void RZBInit(char *args) { if ((args == NULL) || (strlen(args) == 0)) { DynamicPreprocessorFatalMessage("%s(%d) No arguments to RZB SaaC configuration.\n", *_dpd.config_file, *_dpd.config_line); } if (!functionsRegistered) { char *pcToken; pcToken = strtok(args, CONF_SEPARATORS); if (!pcToken) { DynamicPreprocessorFatalMessage("%s(%d)strtok returned NULL when it should not.\n", __FILE__, __LINE__); } if (strcmp(RZB_CONF, pcToken) == 0) { pcToken = strtok(NULL, CONF_SEPARATORS); if (!pcToken) { DynamicPreprocessorFatalMessage("%s(%d)strtok returned NULL when it should not.\n", __FILE__, __LINE__); } rzb_collection.initRZB(pcToken); } else { DynamicPreprocessorFatalMessage("%s(%d) Invalid arguments to RZB SaaC configuration.\n", *_dpd.config_file, *_dpd.config_line); } _dpd.addPreprocExit(RZBCleanExit, NULL, PRIORITY_LAST, PP_SAAC); _dpd.addPreproc(RZBProcess, PRIORITY_TUNNEL, PP_SAAC, PROTO_BIT__TCP); functionsRegistered = 1; } else { DynamicPreprocessorFatalMessage("%s(%d) More than one RZB SaaC configuration.\n", *_dpd.config_file, *_dpd.config_line); } } void SetupRZB(void) { /* link the preprocessor keyword to the init function in the preproc list */ #ifndef SNORT_RELOAD _dpd.registerPreproc("rzb", RZBInit); #else _dpd.registerPreproc("rzb", RZBInit, RZBReload, RZBReloadSwap, RZBReloadSwapFree); #endif } snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_smtp-collector.h0000644000000000000000000000023411524620752022630 00000000000000#ifndef __RZB_SMTP_DUMP_H__ #define __RZB_SMTP_DUMP_H__ #include "sf_snort_packet.h" int smtpdumpereval(SFSnortPacket *); #endif // __RZB_SMTP_DUMP_H__ snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_smtp-collector.c0000644000000000000000000001361511652050544022630 00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_STRINGS_H #include #endif #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sfPolicyUserData.h" #include #include #include #include #include #include "rzb_smtp-collector.h" #include "rzb_debug.h" #define SAAC_SMTP 6825 #ifndef RULE_MATCH #define RULE_MATCH 1 #endif #ifndef RULE_NOMATCH #define RULE_NOMATCH -1 #endif #define SMTPDUMPERID 2525 #define DISPLAY_DEMO_OUTPUT #define SMTPCAP_INITSIZE 30000 #define SMTPCAP_MAXSIZE 15000000 typedef struct { u_int32_t sid; u_int32_t totalsize; u_int32_t storedsize; u_int8_t *clientdata; } smtpcapture; void smtpdumper_freedata(smtpcapture *sessiondata) { //printf("SMTPDUMP smtpdumper_freedata enter\n"); if(!sessiondata) { //printf("SMTPDUMP sessiondata is NULL!\n"); return; } if(sessiondata->clientdata) { free(sessiondata->clientdata); } else { //printf("SMTPDUMP sessiondata->clientdata is NULL!\n"); } free(sessiondata); } void smtpdumper_calldetection(void *dataptr) { BLOCK_META_DATA *mdata = NULL; smtpcapture *smtpcapturedata = (smtpcapture*)dataptr; //printf("SMTPDUMP smtpdumper_calldetection enter\n"); if(!dataptr) { //printf("SMTPDUMP dataptr is NULL!\n"); return; } if(smtpcapturedata->clientdata) { // printf("SMTPDUMP Calling sendData() with the following data (%d bytes):\n\n", ((smtpcapture*)(dataptr))->storedsize); #ifdef DISPLAY_DEMO_OUTPUT prettyprint(smtpcapturedata->clientdata, smtpcapturedata->storedsize); printf("\n\n"); #endif mdata = calloc(1, sizeof(*mdata)); if(mdata == NULL) return; // Fill in the required fields mdata->timestamp = (unsigned int)time(NULL); mdata->data = smtpcapturedata->clientdata; mdata->size = smtpcapturedata->storedsize; // mdata->src_ip = 0x01010101; // mdata->dst_ip = 0x02020202; mdata->ip_proto = 6; mdata->src_port = 25; mdata->dst_port = 8000; uuid_copy(mdata->datatype, MAIL_CAPTURE); rzb_collection.sendData(mdata); } else { //printf("SMTPDUMP dataptr->clientdata is NULL!\n"); } //printf("SMTPDUMP Freeing session data\n"); // Data is freed by sendData; we just need to clear out the rest of the structure. // We can accomplish this by setting clientdata to NULL so we don't do the doublefree smtpcapturedata->clientdata = NULL; smtpdumper_freedata(smtpcapturedata); } /* detection functions */ int smtpdumpereval(SFSnortPacket *sp) { const u_int8_t *cursor_normal, *end_of_payload = 0; // Packet *sp = (Packet *) p; smtpcapture *sessiondata = NULL; u_int8_t *tmpdataptr; // For realloc()s u_int32_t incoming_data_size = 0; //printf("SMTPDUMP smtpdumpereval enter\n"); if(sp == NULL) return RULE_NOMATCH; if(sp->payload == NULL) return RULE_NOMATCH; sessiondata = _dpd.streamAPI->get_application_data(sp->stream_session_ptr, SAAC_SMTP); //printf("SMTPDUMP sessiondata = %p\n", sessiondata); if(sessiondata) { if(sessiondata->sid != SMTPDUMPERID) { printf("SMTPDUMP Someone else's data!\n"); return RULE_NOMATCH; } if(sessiondata->storedsize >= SMTPCAP_MAXSIZE) { printf("SMTPDUMP Already have SMTPCAP_MAXSIZE(%d) bytes of data\n", SMTPCAP_MAXSIZE); return RULE_NOMATCH; } } else { sessiondata = (smtpcapture*)calloc(1, sizeof(smtpcapture)); if(!sessiondata) { printf("SMTPDUMP sessiondata malloc failed!\n"); return RULE_NOMATCH; } sessiondata->sid = SMTPDUMPERID; sessiondata->clientdata = (u_int8_t*)malloc(SMTPCAP_INITSIZE); if(!sessiondata->clientdata) { printf("SMTPDUMP sessiondata->clientdata malloc failed!\n"); smtpdumper_freedata(sessiondata); return RULE_NOMATCH; } sessiondata->totalsize = SMTPCAP_INITSIZE; sessiondata->storedsize = 0; //printf("SMTPDUMP storing rule data\n"); _dpd.streamAPI->set_application_data(sp->stream_session_ptr, SAAC_SMTP, sessiondata, &smtpdumper_calldetection); //printf("SMTPDUMP stored rule data\n"); } cursor_normal = sp->payload; end_of_payload = sp->payload + sp->payload_size; incoming_data_size = sp->payload_size; //end_of_payload - cursor_normal; //printf("SMTPDUMP incoming_data_size = %d\n", incoming_data_size); // Check if we have enough room for the incoming data if(incoming_data_size > (sessiondata->totalsize - sessiondata->storedsize)) { // We've previously ensured we are not already overcapped on data //printf("SMTPDUMP reallocating to %d bytes\n", sessiondata->totalsize * 2); // Double our amount of storage tmpdataptr = realloc(sessiondata->clientdata, sessiondata->totalsize * 2); if(!tmpdataptr) { // If there is not enough available memory, realloc() returns a null pointer and sets errno to [ENOMEM]. if(errno == ENOMEM) { smtpdumper_freedata(sessiondata); return(RULE_NOMATCH); } else { printf("SMTPDUMP realloc() failed but I dunno wtf\n"); smtpdumper_freedata(sessiondata); return(RULE_NOMATCH); } } sessiondata->clientdata = tmpdataptr; sessiondata->totalsize *= 2; //printf("SMTPDUMP totalsize is now %d\n", sessiondata->totalsize); } // We have enough room, so store the data //printf("SMTPDUMP storing %d bytes at %p\n", incoming_data_size, &((sessiondata->clientdata)[sessiondata->storedsize])); memcpy(&((sessiondata->clientdata)[sessiondata->storedsize]), cursor_normal, incoming_data_size); sessiondata->storedsize += incoming_data_size; //printf("SMTPDUMP stored size is now %d\n", sessiondata->storedsize); return RULE_NOMATCH; } snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_http-server.h0000644000000000000000000000101711524620751022143 00000000000000#ifndef NRT_SERVER_H #define NRT_SERVER_H #include #include "rzb_http-fileinfo.h" #include "sf_snort_packet.h" int ProcessFromServer(SFSnortPacket *); enum filereadstatus ProcessServerHeader(const u_int8_t **, const u_int8_t *, FILEINFO *); enum filereadstatus ReadFileData(const u_int8_t **, const u_int8_t *, FILEINFO *); int SkipToEndOfHTTPHeader(const u_int8_t **, const u_int8_t *); int CallDetectionFunction(FILEINFO *); int IsStreamIgnored(RULEDATA *); void IgnoreStream(RULEDATA *); #endif snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_http-server.c0000644000000000000000000003157211652050544022146 00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_STRINGS_H #include #endif #include "sf_types.h" #include #include "rzb_http-client.h" #include "rzb_http-server.h" #include "rzb_debug.h" #include "rzb_http-fileinfo.h" #include "rzb_http.h" #include "sf_snort_plugin_api.h" #include "sfPolicyUserData.h" #include #include #include #include int SkipToEndOfHTTPHeader(const u_int8_t **in_cursor, const u_int8_t *end_of_data) { const u_int8_t *cursor = *in_cursor; while(cursor < end_of_data) { while(cursor < end_of_data && *cursor++ != '\n'); if(cursor[0] == '\r' && cursor[1] == '\n') { cursor += 2; *in_cursor = cursor; return(1); } else if(cursor[0] == '\n') { cursor++; *in_cursor = cursor; return(1); } } return(-1); } enum filereadstatus ReadFileData(const u_int8_t **in_cursor, const u_int8_t *end_of_data, FILEINFO *fileinfo) { const u_int8_t *cursor = *in_cursor; u_int32_t amounttoalloc; u_int32_t bytesavailable; const u_int8_t *end_of_file; u_int8_t *filedataptr; if(cursor >= end_of_data) return(ERROR); // Make sure we have somewhere to store our data if((fileinfo->filedata) == NULL) { // ZDNOTE Need to limit the amount of memory that will be allocated at a time. This may involve some // ZDNOTE changes to the FILEINFO struct. // ZDNOTE amounttoalloc = (fileinfo->filesize < MAXFILEALLOCCHUNK) ? fileinfo->filesize : MAXFILEALLOCCHUNK; if(fileinfo->filesize > 100000000 /*ULONG_MAX*/) { // ZDNOTE this will also trip on files for which we don't have a Content-Length header DEBUGOUT((D_FILE | D_DEBUG), printf("ReadFileData filesize is >100M! Bailing!\n")); return(ERROR); } amounttoalloc = fileinfo->filesize; fileinfo->filedata = calloc(amounttoalloc, 1); if((fileinfo->filedata) == NULL) { printf("ReadFileData unable to allocate file contents buffer!\n"); return(ERROR); } fileinfo->amountstored = 0; fileinfo->bufferindex = 0; } end_of_file = cursor + (fileinfo->filesize - fileinfo->amountstored); if(end_of_file > end_of_data) { end_of_file = end_of_data; } bytesavailable = end_of_file - cursor; // ZDNOTE Need to verify there is enough space left in the buffer before copy filedataptr = &((fileinfo->filedata)[fileinfo->bufferindex]); while(cursor < end_of_file) { *filedataptr++ = *cursor++; } *in_cursor = cursor; fileinfo->amountstored += bytesavailable; fileinfo->bufferindex += bytesavailable; // ZDNOTE again, check buffer size DEBUGOUT((D_FILE | D_DEBUG), printf("Saved %d bytes. (%d/%d total)\n", bytesavailable, fileinfo->amountstored, fileinfo->filesize)); if(fileinfo->amountstored == fileinfo->filesize) return(WAITINGFORRESPONSEHEADER); else if(fileinfo->amountstored < fileinfo->filesize) return(WAITINGFORDATA); else return(ERROR); } int CallDetectionFunction(FILEINFO *fileinfo) { BLOCK_META_DATA *mdata = NULL; const unsigned char *tmp; // Init the metadata structure if((mdata = calloc(1, sizeof(*mdata))) == NULL) { perror("Error allocating mdata\n"); return -1; } // Fill in the required fields mdata->timestamp = (unsigned int)time(NULL); mdata->data = fileinfo->filedata; mdata->size = fileinfo->filesize; mdata->src_ip.ip.ipv4 = fileinfo->saddr; mdata->src_ip.family = AF_INET; mdata->dst_ip.ip.ipv4 = fileinfo->daddr; mdata->dst_ip.family = AF_INET; mdata->ip_proto = 6; mdata->src_port = 25; mdata->dst_port = 8000; tmp = rzb_collection.file_type_lookup(fileinfo->filedata, fileinfo->filesize); uuid_copy(mdata->datatype, tmp); // DEBUGOUT((D_DETECT | D_INFO), printf("CallDetectionFunction enter\n")); // ZDNOTE Dunno what to do, so we're just going to... printf("Calling detection function with following file information:\n"); DumpFileInfo(fileinfo); rzb_collection.sendData(mdata); fileinfo->filedata = NULL; fileinfo->filesize = 0; return(0); } enum filereadstatus ProcessServerHeader(const u_int8_t **in_cursor, const u_int8_t *end_of_data, FILEINFO *fileinfo) { const u_int8_t *cursor = *in_cursor; if(cursor + 15 >= end_of_data) { DEBUGOUT(D_CRITICAL, printf("ProcessServerHeader not enough data!\n")); return(ERROR); } // Check for HTTP/1.[01] header if( (strncasecmp((const char *)cursor, "http/1.", 7) != 0) || (cursor[7] != '0' && cursor[7] != '1')) { DEBUGOUT(D_CRITICAL, printf("ProcessServerHeader not a valid HTTP version\n")); return(ERROR); } cursor += 8; while(cursor < end_of_data && *cursor == ' ') cursor++; if(cursor + 6 >= end_of_data) { DEBUGOUT(D_CRITICAL, printf("ProcessServerHeader not enough data 2!\n")); return(ERROR); } if( memcmp(cursor, "200", 3) != 0) { // DEBUGOUT((D_FILE | D_DEBUG), printf("Unhandled response code: %c%c%c%c%c\n", cursor[-2], cursor[-1], cursor[0], cursor[1], cursor[2])); // DEBUGOUT((D_SERVER | D_WARN), printf("ProcessServerHeader not 200 response (is %c%c%d)\n", *(cursor-3), *(cursor-2), *(cursor-1))); DEBUGOUT((D_SERVER | D_WARN), printf("ProcessServerHeader not 200 response (is %c%c%d)\n", *cursor, *(cursor+1), *(cursor+2))); *in_cursor = cursor; return(SERVERRETURNNOT200); // ZDNOTE We really need to handle other codes to skip over data } cursor += 3; // ZDNOTE Don't know if it matters, but we're not caring about the response message // Now, we're going to see if we can find a Content-Length header. // By definition, it has to be at the start of a line. So, we're just going // To look for newlines and every time we find one, see if we're now looking // at Content-Length: while(cursor < end_of_data) { while(cursor < end_of_data && *cursor++ != '\n'); // Find next newline // No Content-Length: header. if(cursor + 16 >= end_of_data) { DEBUGOUT((D_SERVER | D_EMERG), printf("No content-length header\n")); //SkipToEndOfHTTPHeader(&cursor, end_of_data); fileinfo->filesize = UINT_MAX; break; //return(WAITINGFORDATA); // ZDNOTE bug if header spans packets. INHTTPHEADERS state?? } if( strncasecmp((const char *)cursor, "content-length:", 15) == 0 ) { cursor += 15; if(cursor + 10 <= end_of_data) { fileinfo->filesize = strtoul((char *)cursor, (char**)(&cursor), 10); // ignores preceeding whitespace } DEBUGOUT((D_SERVER | D_DEBUG), printf("Found content-length. Filesize = %d\n", fileinfo->filesize)); SkipToEndOfHTTPHeader(&cursor, end_of_data); break; } else if(cursor[0] == '\r' && cursor[1] == '\n') { cursor += 2; break; } else if(cursor[0] == '\n') { cursor++; break; } } *in_cursor = cursor; return(WAITINGFORDATA); } int ProcessFromServer(SFSnortPacket *sp) { RULEDATA *ruledata; int result; const u_int8_t *cursor = sp->payload; const u_int8_t *end_of_data; FILEINFO *currentfile; // u_int32_t remaining_data = 0; DEBUGOUT((D_SERVER | D_INFO), printf("ProcessFromServer enter\n")); DEBUGOUT((D_PACKET | D_WARN), prettyprint(sp->payload, sp->payload_size)); ruledata = _dpd.streamAPI->get_application_data(sp->stream_session_ptr, SAAC_HTTP); if(!ruledata) { DEBUGOUT((D_SERVER | D_DEBUG), printf("ProcessFromServer: no rule data!\n")); return(-1); } else if(ruledata->sid != NRTSID) { DEBUGOUT((D_SERVER | D_WARN), printf("Not our data! (sid %d/0x%08x)\n", ruledata->sid, ruledata->sid)); return(-1); } else if(IsStreamIgnored(ruledata)) { DEBUGOUT((D_SERVER | D_WARN), printf("ProcessFromServer: stream is ignored\n")); return(-1); } if(fileinfolist[ruledata->streaminfoidx] == NULL) { printf("Craptacular, the fileinfolist is NULL, ruledata->streaminfoidx = %d\n", ruledata->streaminfoidx); DEBUGOUT(D_CRITICAL, printf("ProcessFromServer fileinfolist[ruledata->streaminfoidx] is NULL!\n")); return(-1); } currentfile = (fileinfolist[ruledata->streaminfoidx])->fileinfo; if(currentfile == NULL) { DEBUGOUT(D_CRITICAL, printf("ProcessFromServer head fileinfo is NULL!\n")); return(-1); } cursor = sp->payload; // dataremaining = sp->dsize; end_of_data = sp->payload + sp->payload_size; while(cursor < end_of_data && !IsStreamIgnored(ruledata)) { switch(ruledata->state) { case WAITINGFORRESPONSEHEADER: // We're currently waiting for the server to answer our request // ProcessServerHeader moves the cursor to the beginning of the response body // ...unless the header bridges packets. This will be a bug. ZDNOTE result = ProcessServerHeader(&cursor, end_of_data, currentfile); DEBUGOUT((D_SERVER | D_INFO), printf("return from ProcessServerResponse() was %d\n", result)); DEBUGOUT((D_SERVER | D_WARN), DumpFileInfo(currentfile)); switch(result) { case WAITINGFORDATA: // Successfully processed header, now waiting for data ruledata->state = WAITINGFORDATA; break; case SERVERRETURNNOT200: case IGNORESTREAM: case ERROR: default: DEBUGOUT(D_CRITICAL, printf("ProcessServerHeader() unhandled response code (%d)\n", result)); IgnoreStream(ruledata); //cursor = end_of_data; break; } break; case WAITINGFORDATA: result = ReadFileData(&cursor, end_of_data, currentfile); switch(result) { case WAITINGFORDATA: // Nothing's changed regarding state break; case WAITINGFORRESPONSEHEADER: DEBUGOUT((D_DEBUG | D_SERVER), printf("WE HAVE A COMPLETE FILE! ruledata=%p, streaminfoidx=%d\n", ruledata, ruledata->streaminfoidx)); DEBUGOUT((D_DEBUG | D_SERVER), DumpFileInfoList(ruledata)); // This means we got all of our data. Call the detection function. CallDetectionFunction(currentfile); // Get the current file off of the stack PopFileInfo(ruledata); // And grab the next file on the list if(fileinfolist[ruledata->streaminfoidx]) currentfile = (fileinfolist[ruledata->streaminfoidx])->fileinfo; else currentfile = NULL; // ZDNOTE hm.... IgnoreStream(ruledata); // POC1 for now we're ignoring pipelining //cursor = end_of_data; //ruledata->state = IGNORESTREAM; break; default: DEBUGOUT(D_CRITICAL, printf("ProcessFromServer Unhandled response from ReadFileData (%d)\n", result)); IgnoreStream(ruledata); //cursor = end_of_data; break; } break; case SKIPTONEXTRESPONSE: // Read data, skipping until we find a server response. // We can totally cheat if we know a content length. // break; default: DEBUGOUT(D_CRITICAL, printf("ProcessFromServer Unhandled ruledate state (%d). Bailing.\n", ruledata->state)); IgnoreStream(ruledata); //cursor = end_of_data; break; } } // _dpd.alertAdd(GENERATOR_NRT, DST_PORT_MATCH, // 1, 0, 3, DST_PORT_MATCH_STR, 0); if(IsStreamIgnored(ruledata)) return(-1); else return(0); } // Partially debug / hackery, partially something we'll probably want to keep void IgnoreStream(RULEDATA *ruledata) { if(ruledata == NULL) return; DEBUGOUT((D_DEBUG | D_SERVER), printf("Clearing streaminfoidx %d (%p)\n", ruledata->streaminfoidx, ruledata)); // Set state to ignore and clear out the list ruledata->state = IGNORESTREAM; FreeFileInfoList(ruledata); // if(ruledata->streaminfoidx == INVALIDSTREAMIDX) { // DEBUGOUT((D_DEBUG | D_SERVER), printf(" INVALIDSTREAMIDX, exiting\n")); // return; // } // // while(fileinfolist[ruledata->streaminfoidx]) { // DEBUGOUT((D_DEBUG | D_SERVER), printf(" popping %s\n", (fileinfolist[ruledata->streaminfoidx])->fileinfo->url)); // // DeleteFileInfoListHead(ruledata); //// printf("ZDNOTE MEMORY LEAK! Setting pointer to NULL.\n"); //// fileinfolist[ruledata->streaminfoidx] = NULL; // } // // ruledata->streaminfoidx = INVALIDSTREAMIDX; } int IsStreamIgnored(RULEDATA *ruledata) { if(ruledata == NULL || ruledata->state == IGNORESTREAM || ruledata->streaminfoidx == INVALIDSTREAMIDX) return(1); return(0); } snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_http-fileinfo.h0000644000000000000000000000216011524620751022430 00000000000000#ifndef NRT_FILEINFO_H #define NRT_FILEINFO_H #include #include "rzb_http.h" enum filereadstatus { ERROR = -1, WAITINGFORRESPONSEHEADER = 1, SERVERRETURNNOT200, SKIPTONEXTRESPONSE, WAITINGFORDATA, IGNORESTREAM }; typedef struct _RULEDATA { u_int32_t sid; u_int32_t streaminfoidx; enum filereadstatus state; } RULEDATA; typedef struct _FILEINFO { char url[URLLEN]; char hostname[HOSTNAMELEN]; struct in_addr saddr; struct in_addr daddr; unsigned int filesize; unsigned int amountstored; unsigned int bufferindex; unsigned char *filedata; unsigned char md5[16]; int alert; } FILEINFO; struct FILEINFOLISTELEM { FILEINFO *fileinfo; struct FILEINFOLISTELEM *next; }; int AddFileInfoListElem(RULEDATA *, FILEINFO *); void DumpFileInfo(FILEINFO *); int DumpFileInfoList(RULEDATA *); void FreeFileInfo(FILEINFO *); int DeleteFileInfoListHead(RULEDATA *); FILEINFO *PopFileInfo(RULEDATA *); void FreeFileInfoList(RULEDATA *); void FreeNRTStreamData(void *); extern int numfileinfostructsinuse; extern struct FILEINFOLISTELEM *fileinfolist[NUMSTREAMSTOTRACK]; #endif snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_http-fileinfo.c0000644000000000000000000001503311652050544022425 00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_STRINGS_H #include #endif #include "sf_types.h" #include #include "rzb_http-client.h" #include "rzb_debug.h" #include "rzb_http-fileinfo.h" #include "rzb_http-server.h" #include "sf_ip.h" #include #include int numfileinfostructsinuse = 0; u_int32_t nextfreestreaminfoidx = 0; struct FILEINFOLISTELEM *fileinfolist[NUMSTREAMSTOTRACK]; void DumpFileInfo(FILEINFO *fileinfo) { char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN]; if(fileinfo == NULL) { DEBUGOUT(D_CRITICAL, printf("DumpFileInfo fileinfo is NULL!\n")); return; } // snort typedefs inet_ntoa to sfip_ntoa. We use inetaddrs. wtf. sfip_raw_ntop(AF_INET, &fileinfo->saddr, srcaddr, sizeof(srcaddr)); sfip_raw_ntop(AF_INET, &fileinfo->daddr, dstaddr, sizeof(dstaddr)); printf("/--- fileinfo start ---\n"); printf("| url: %s\n", fileinfo->url); printf("| hostname: %s\n", fileinfo->hostname); printf("| saddr: %s\n", srcaddr); printf("| daddr: %s\n", dstaddr); printf("| filesize: %d\n", fileinfo->filesize); printf("| amountstored: %d\n", fileinfo->amountstored); printf("| bufferindex: %d\n", fileinfo->bufferindex); printf("| filedata = %p\n", fileinfo->filedata); if(fileinfo->filedata != NULL) { DEBUGOUT((D_FILE | D_WARN), prettyprint(fileinfo->filedata, fileinfo->filesize)); #ifndef DEBUG prettyprint(fileinfo->filedata, (fileinfo->filesize > 256) ? 256 : fileinfo->filesize); #endif } printf("\\--- fileinfo end ---\n"); } int DumpFileInfoList(RULEDATA *ruledata) { struct FILEINFOLISTELEM *tmp; printf("DumpFileInfoList, index %d\n", ruledata->streaminfoidx); if(ruledata->streaminfoidx == INVALIDSTREAMIDX) { printf("Invalid stream index!\n"); return(-1); } tmp = fileinfolist[ruledata->streaminfoidx]; if(tmp == NULL) { printf("Head node is NULL!\n"); return(-1); } do { DumpFileInfo(tmp->fileinfo); } while((tmp = tmp->next)); return(1); } void FreeFileInfo(FILEINFO *fileinfo) { if(fileinfo) { if(fileinfo->filedata) { //printf("Freeing file data 0x%08x\n", fileinfo->filedata); free(fileinfo->filedata); //fileinfo->filedata = NULL; } free(fileinfo); numfileinfostructsinuse--; } // printf("FreeFileInfo numfileinfostructsinuse=%d\n", numfileinfostructsinuse); } void FreeNRTStreamData(void *inptr) { RULEDATA *ruledata = (RULEDATA *)inptr; printf("Freeing NRT stream data. Be afraid. Be very afraid.\n"); DEBUGOUT((D_CLIENT|D_SERVER|D_DEBUG), printf("FreeNRTStreamData enter\n")); if(!ruledata) { DEBUGOUT((D_SERVER|D_CLIENT|D_DEBUG), printf(" inptr is NULL, exiting\n")); return; } FreeFileInfoList(ruledata); free(ruledata); } void FreeFileInfoList(RULEDATA *ruledata) { DEBUGOUT((D_CLIENT|D_SERVER|D_DEBUG), printf("FreeFileInfoList enter\n")); if(!ruledata) { DEBUGOUT((D_SERVER|D_CLIENT|D_DEBUG), printf(" inptr is NULL, exiting\n")); return; } if(ruledata->streaminfoidx != INVALIDSTREAMIDX) { while(fileinfolist[ruledata->streaminfoidx]) { DEBUGOUT((D_DEBUG | D_SERVER), printf(" deleting %s\n", (fileinfolist[ruledata->streaminfoidx])->fileinfo->url)); DeleteFileInfoListHead(ruledata); } } ruledata->streaminfoidx = INVALIDSTREAMIDX; } int AddFileInfoListElem(RULEDATA *ruledata, FILEINFO *fileinfo) { struct FILEINFOLISTELEM *tmp, *addme; int i; DEBUGOUT((D_FILE | D_INFO), printf("AddFileInfoListElem enter\n")); if(ruledata->streaminfoidx == INVALIDSTREAMIDX) { if(nextfreestreaminfoidx == OUTOFSTREAMINFOSTORAGE) { DEBUGOUT(D_CRITICAL, printf("out of stream storage!\n")); return(-1); } ruledata->streaminfoidx = nextfreestreaminfoidx; DEBUGOUT((D_FILE | D_DEBUG), printf("Using next open slot, at index %d\n", nextfreestreaminfoidx)); // Now let's find the next open index i = nextfreestreaminfoidx + 1; while(i < NUMSTREAMSTOTRACK) { if(fileinfolist[i] == NULL) break; else i++; } if(i == NUMSTREAMSTOTRACK) { i = 0; while(i < nextfreestreaminfoidx) { if(fileinfolist[i] == NULL) break; else i++; } } // Out of additional storage if(i == ruledata->streaminfoidx) { printf("Out of streaminfo storage\n"); nextfreestreaminfoidx = OUTOFSTREAMINFOSTORAGE; }else nextfreestreaminfoidx = i; DEBUGOUT((D_FILE | D_DEBUG), printf("nextfreestreaminfoidx = %d\n", nextfreestreaminfoidx)); } DEBUGOUT((D_FILE | D_DEBUG), printf("adding fileinfo at index %d\n", ruledata->streaminfoidx)); addme = calloc(1, sizeof(*addme)); if(addme == NULL) { DEBUGOUT(D_CRITICAL, printf("Unable to allocate fileinfolistelem!\n")); return(-1); } addme->fileinfo = fileinfo; addme->next = '\0'; tmp = fileinfolist[ruledata->streaminfoidx]; if(tmp) { while(tmp->next) { tmp = tmp->next; } tmp->next = addme; } else { fileinfolist[ruledata->streaminfoidx] = addme; } numfileinfostructsinuse++; // printf("AddFileInfoListElem numfileinfostructsinuse=%d\n", numfileinfostructsinuse); return(1); } FILEINFO *PopFileInfo(RULEDATA *ruledata) { struct FILEINFOLISTELEM *tmp; FILEINFO *fileinfo; DEBUGOUT((D_FILE | D_INFO), printf("PopFileInfo enter\n")); if(ruledata->streaminfoidx == INVALIDSTREAMIDX) { DEBUGOUT(D_CRITICAL, printf("PopFileInfo streaminfoidx is INVALIDSTREAMIDX!\n")); return(NULL); } tmp = fileinfolist[ruledata->streaminfoidx]; if(tmp == NULL) { DEBUGOUT(D_CRITICAL, printf("PopFileInfo fileinfolist entry is NULL!\n")); return(NULL); } // Change the head fileinfolist[ruledata->streaminfoidx] = tmp->next; // Grab the fileinfo and free the container fileinfo = tmp->fileinfo; free(tmp); DEBUGOUT((D_CLIENT | D_SERVER | D_INFO), printf("PopFileInfo freed fileinfo container at %p\n", tmp)); return(fileinfo); } int DeleteFileInfoListHead(RULEDATA *ruledata) { FILEINFO *fileinfo; DEBUGOUT((D_FILE | D_INFO), printf("DeleteFileInfoListHead enter\n")); fileinfo = PopFileInfo(ruledata); DEBUGOUT((D_CLIENT | D_SERVER | D_INFO), printf("freeing fileinfo at %p\n", fileinfo)); if(fileinfo == NULL) return(-1); FreeFileInfo(fileinfo); return(1); } snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_http.h0000644000000000000000000000044311524620751020641 00000000000000#ifndef RZB_SAAC_H #define RZB_SAAC_H #define SAAC_HTTP 6880 #define URLLEN 1000 #define HOSTNAMELEN 256 #define NUMSTREAMSTOTRACK 5000 #define NRTSID 0xa5a5a5a5 #define INVALIDSTREAMIDX 0xFFFFFFFF #define OUTOFSTREAMINFOSTORAGE 0xFFFFFFFF #endif // RZB_SAAC_H snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_http-client.h0000644000000000000000000000036711524620751022122 00000000000000#ifndef NRT_CLIENT_H #define NRT_CLIENT_H #include #include "sf_snort_packet.h" int ParseClientRequest(const u_int8_t *, u_int32_t, WEB_ENTRY*); int ProcessFromClient(SFSnortPacket *); int init_HTTP_PCREs(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_http-client.c0000644000000000000000000001764011652050544022116 00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_STRINGS_H #include #endif #include "sf_types.h" #include #include "rzb_http-client.h" #include "rzb_debug.h" #include "rzb_http-fileinfo.h" #include "rzb_http-server.h" #include "rzb_http.h" #include "sf_snort_plugin_api.h" #include "sfPolicyUserData.h" #include #include #include #include typedef struct { pcre *re; pcre_extra *pe; } pcrestruct; // Ensure the pcre enum lines up with the pcre strings array enum { PCRE_EOH, PCRE_URL, PCRE_HOST, PCRE_COOKIE, PCRE_UA } http_pcre_enum; #define NUM_HTTP_PCRES PCRE_UA+1 pcrestruct http_pcre_structs[NUM_HTTP_PCRES]; char *http_pcre_strings[] = { "\\n\\r?\\n", "^(GET|POST)\\s+([^\\s]+)\\s+HTTP/1\\.[01]\\s*$", "^Host:\\s*([^\\r\\n]+)", "^Cookie:\\s*([^\\r\\n]+)", "^User-Agent:\\s*([^\\r\\n]+)" }; int init_HTTP_PCREs(void) { const char *error; int erroffset; int i; for(i = 0; i < NUM_HTTP_PCRES; i++) { // /*DEBUGOUT((D_CLIENT | D_INFO),*/printf("Initializing PCRE %d: %s\n", i, http_pcre_strings[i]);//); http_pcre_structs[i].re = pcre_compile(http_pcre_strings[i], PCRE_CASELESS | PCRE_DOTALL | PCRE_MULTILINE, &error, &erroffset, NULL); if(http_pcre_structs[i].re == NULL) { printf("Failed to compile pcre regex %d (%s): %s\n", i, http_pcre_strings[i], error); return(-1); } http_pcre_structs[i].pe = pcre_study(http_pcre_structs[i].re, 0, &error); if(error != NULL) { printf("Failed to study pcre regex %d /%s/: %s\n", i, http_pcre_strings[i], error); return(-1); } } return 1; } // < 0 for error. >= 0 for len of extracted string int extractHTTPClientHeaderVal(const u_int8_t *buf, u_int32_t size, int pcreidx, int substringnum, char *valuebuf, int valuelen) { int result; int ovector[9]; int ovecsize = 9; const char *tmpstring; // printf("Searching for pcre %d (%s)\n", pcreidx, http_pcre_strings[pcreidx]); result = pcre_exec(http_pcre_structs[pcreidx].re, http_pcre_structs[pcreidx].pe, (const char *)buf, size, 0, 0, ovector, ovecsize); if(result < 0 || result == PCRE_ERROR_NOMATCH) { // printf("pcre not found\n"); return(-1); // We need to find the URL or this isn't a valid request } if(valuebuf) { result = pcre_get_substring((const char *)buf, ovector, result, substringnum, &tmpstring); if(result < 0) { // printf("unable to extract substring\n"); return(-2); } strncpy(valuebuf, tmpstring, valuelen); valuebuf[valuelen-1] = '\0'; pcre_free_substring(tmpstring); return(strlen(valuebuf)); } return(0); } int ParseClientRequest(const u_int8_t *payload, u_int32_t payload_size, WEB_ENTRY* webentry) { u_int32_t offset_eoh = 0; int result; DEBUGOUT((D_CLIENT | D_INFO), printf("ParseClientRequest enter\n")); if(payload == NULL) { DEBUGOUT(D_CRITICAL, printf("ParseClientRequest payload is NULL. wtf.\n")); return(-1); } if(payload_size < 15) { return(-1); } // I get the sneaking suspicion that eventually I'm going to realize that I still // need to keep track of HEAD, OPTION, etc because some jackass is going to desynch me by // injecting such requests into the stream so when I receive file data it won't line up // correctly. I really should just rob the code from http_inspect here. // Find the end of the HTTP headers // XXX This code is pretty useless here unless I get an offset for the end of headers result = extractHTTPClientHeaderVal(payload, payload_size, PCRE_EOH, 0, NULL, 0); offset_eoh = /*(result >= 0) ? result :*/ payload_size; // Get the URL result = extractHTTPClientHeaderVal(payload, offset_eoh, PCRE_URL, 2, webentry->url, sizeof(webentry->url)); // We need a URL (also validates this is a valid request) if(result < 0) { printf("Unable to extract URL\n"); return(-1); } // The remaining headers are optional (PCRE_HOST, PCRE_COOKIE, PCRE_UA) result = extractHTTPClientHeaderVal(payload, offset_eoh, PCRE_HOST, 1, webentry->host, sizeof(webentry->host)); if(result < 0) { // printf("Unable to extract Host header\n"); webentry->host[0] = '\0'; } result = extractHTTPClientHeaderVal(payload, offset_eoh, PCRE_COOKIE, 1, webentry->cookie, sizeof(webentry->cookie)); if(result < 0) { // printf("Unable to extract Cookie header\n"); webentry->cookie[0] = '\0'; } result = extractHTTPClientHeaderVal(payload, offset_eoh, PCRE_UA, 1, webentry->user_agent, sizeof(webentry->user_agent)); if(result < 0) { // printf("Unable to extract User-Agent header\n"); webentry->user_agent[0] = '\0'; } return(1); } int ProcessFromClient(SFSnortPacket *sp) { RULEDATA *ruledata; WEB_ENTRY webentry; int result; FILEINFO *fileinfo; DEBUGOUT((D_CLIENT | D_INFO), printf("ProcessFromClient enter\n")); DEBUGOUT((D_PACKET | D_WARN), prettyprint(sp->payload, sp->payload_size)); ruledata = _dpd.streamAPI->get_application_data(sp->stream_session_ptr, SAAC_HTTP); if(!ruledata) { DEBUGOUT((D_CLIENT | D_DEBUG), printf("ProcessFromClient: adding new rule data\n")); ruledata = calloc(1, sizeof(RULEDATA)); if(!ruledata) { DEBUGOUT(D_CRITICAL, printf("ProcessFromClient: ruledata malloc failed\n")); return(-1); } _dpd.streamAPI->set_application_data(sp->stream_session_ptr, SAAC_HTTP, ruledata, &free); ruledata->sid = NRTSID; ruledata->streaminfoidx = INVALIDSTREAMIDX; ruledata->state = WAITINGFORRESPONSEHEADER; } else if(ruledata->sid != NRTSID) { DEBUGOUT(D_CRITICAL, printf("ProcessFromClient: Not our data! (sid %d/0x%08x)\n", ruledata->sid, ruledata->sid)); return(-1); } else if(IsStreamIgnored(ruledata)) { DEBUGOUT((D_SERVER | D_WARN), printf("ProcessFromClient: stream is ignored\n")); return(-1); } fileinfo = calloc(1, sizeof(FILEINFO)); // Set all counts and sizes to 0, all strings to empty, and pointers to NULL // memset(fileinfo, '\0', sizeof(FILEINFO)); result = ParseClientRequest(sp->payload, sp->payload_size, &webentry); DEBUGOUT((D_CLIENT | D_INFO), printf("return from ParseClientRequest() was %d\n", result)); if(result <= 0) { free(fileinfo); return(-1); } // Copy URL and Host header out of webentry into fileinfo snprintf(fileinfo->url, sizeof(fileinfo->url), "%s", webentry.url); fileinfo->url[sizeof(fileinfo->url) - 1] = 0; snprintf(fileinfo->hostname, sizeof(fileinfo->hostname), "%s", webentry.host); fileinfo->hostname[sizeof(fileinfo->hostname) - 1] = 0; // Now store what we know about this request fileinfo->saddr = sp->ip4_header->source; fileinfo->daddr = sp->ip4_header->destination; // Add address info to webentry webentry.src_ip.ip.ipv4 = sp->ip4_header->source; webentry.src_ip.family = AF_INET; webentry.dst_ip.ip.ipv4 = sp->ip4_header->destination; webentry.dst_ip.family = AF_INET; // Now send our webentry as an Intel Nugget! if(rzb_collection.sendWebTrack(&webentry) == R_FAIL) { printf("Failed to send web track info!\n"); // Not making this fatal error } DEBUGOUT((D_CLIENT | D_DEBUG), DumpFileInfo(fileinfo)); result = AddFileInfoListElem(ruledata, fileinfo); DEBUGOUT((D_CLIENT | D_INFO), printf("return from StoreFileData() was %d\n", result)); if(result < 0) { DEBUGOUT(D_CRITICAL, printf("AddFileInfoListElem failed!\n")); free(fileinfo); return(-1); } DEBUGOUT((D_CLIENT | D_WARN), DumpFileInfoList(ruledata)); // _dpd.alertAdd(GENERATOR_NRT, DST_PORT_MATCH, // 1, 0, 3, DST_PORT_MATCH_STR, 0); return(0); } snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_debug.h0000644000000000000000000000145011524620751020747 00000000000000#ifndef NRT_DEBUG_H #define NRT_DEBUG_H #define D_CRITICAL 0xFFFF #define D_EMERG 0x0001 #define D_WARN 0x0002 #define D_DEBUG 0x0004 #define D_INFO 0x0008 #define D_ALLLVL 0x00FF #define D_CRIT 0x0080 #define D_CLIENT 0x0100 #define D_SERVER 0X0200 #define D_DETECT 0x0400 #define D_PACKET 0x0800 #define D_FILE 0x1000 #define D_ALERT 0x2000 #define D_ALLCOMP 0xFF00 #define D_ALLDEBUG 0xFFFF #define DEBUG #ifdef DEBUG #define DEBUGLEVEL D_ALLDEBUG //((D_ALLCOMP & ~D_PACKET) | D_CRIT)// (D_ALLDEBUG & ~D_PACKET) #define DEBUGOUT(flag, code) if((flag & DEBUGLEVEL & 0xFF00) && (flag & DEBUGLEVEL & 0x00FF)) code #else #define DEBUGOUT(flag, code) #endif #define PACKETDUMPSIZE 256 void prettyprint(const unsigned char *, unsigned int); #endif snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/rzb_debug.c0000644000000000000000000000162711652050544020747 00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_STRINGS_H #include #endif #include "sf_types.h" #include "rzb_debug.h" #include #include #include void prettyprint(const unsigned char *data, unsigned int size) { unsigned int i; const unsigned char *dataptr = data; unsigned char asciigraph[17]; memset(asciigraph, '\x00', 17); #ifdef PACKETDUMPSIZE size = (size > PACKETDUMPSIZE) ? PACKETDUMPSIZE : size; #endif for(i=0; i < size; i++, dataptr++) { printf("%02x ", *dataptr); asciigraph[i % 16] = (isgraph(*dataptr) || (*dataptr == ' ')) ? *dataptr : '.'; if(i % 16 == 15) { printf("%s\n", asciigraph); memset(asciigraph, '\x00', 17); } } // Dump any remaining data if(i % 16) { printf("%*s", (16 - (i%16)) * 3, " "); printf("%s\n", asciigraph); } } snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/Makefile.am0000644000000000000000000000165211746560364020704 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs pkglibdir = ${exec_prefix}/lib/snort_dynamicpreprocessor pkglib_LTLIBRARIES = sf_rzb_saac_preproc.la sf_rzb_saac_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB PREPROCLIB=../libsf_dynamic_preproc.la else nodist_sf_rzb_saac_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sf_ip.c \ ../include/sfPolicyUserData.c endif sf_rzb_saac_preproc_la_LIBADD = ${PREPROCLIB} @RAZORBACK_LIBS@ sf_rzb_saac_preproc_la_CFLAGS = @RAZORBACK_CFLAGS@ -Werror sf_rzb_saac_preproc_la_SOURCES = \ rzb_debug.c \ rzb_debug.h \ rzb_http-client.c \ rzb_http-client.h \ rzb_http.h \ rzb_http-fileinfo.c \ rzb_http-fileinfo.h \ rzb_http-server.c \ rzb_http-server.h \ rzb_smtp-collector.c \ rzb_smtp-collector.h \ spp_rzb-saac.c all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-pkglibLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/rzb_saac/Makefile.in0000644000000000000000000005734712260606522020716 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/rzb_saac DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkglibdir)" LTLIBRARIES = $(pkglib_LTLIBRARIES) sf_rzb_saac_preproc_la_DEPENDENCIES = $(PREPROCLIB) am_sf_rzb_saac_preproc_la_OBJECTS = \ sf_rzb_saac_preproc_la-rzb_debug.lo \ sf_rzb_saac_preproc_la-rzb_http-client.lo \ sf_rzb_saac_preproc_la-rzb_http-fileinfo.lo \ sf_rzb_saac_preproc_la-rzb_http-server.lo \ sf_rzb_saac_preproc_la-rzb_smtp-collector.lo \ sf_rzb_saac_preproc_la-spp_rzb-saac.lo @SO_WITH_STATIC_LIB_FALSE@nodist_sf_rzb_saac_preproc_la_OBJECTS = sf_rzb_saac_preproc_la-sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_rzb_saac_preproc_la-sf_ip.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_rzb_saac_preproc_la-sfPolicyUserData.lo sf_rzb_saac_preproc_la_OBJECTS = $(am_sf_rzb_saac_preproc_la_OBJECTS) \ $(nodist_sf_rzb_saac_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = sf_rzb_saac_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) \ $(sf_rzb_saac_preproc_la_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(sf_rzb_saac_preproc_la_SOURCES) \ $(nodist_sf_rzb_saac_preproc_la_SOURCES) DIST_SOURCES = $(sf_rzb_saac_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) pkglibdir = ${exec_prefix}/lib/snort_dynamicpreprocessor ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies pkglib_LTLIBRARIES = sf_rzb_saac_preproc.la sf_rzb_saac_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@PREPROCLIB = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_sf_rzb_saac_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_ip.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c sf_rzb_saac_preproc_la_LIBADD = ${PREPROCLIB} @RAZORBACK_LIBS@ sf_rzb_saac_preproc_la_CFLAGS = @RAZORBACK_CFLAGS@ -Werror sf_rzb_saac_preproc_la_SOURCES = \ rzb_debug.c \ rzb_debug.h \ rzb_http-client.c \ rzb_http-client.h \ rzb_http.h \ rzb_http-fileinfo.c \ rzb_http-fileinfo.h \ rzb_http-server.c \ rzb_http-server.h \ rzb_smtp-collector.c \ rzb_smtp-collector.h \ spp_rzb-saac.c all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/rzb_saac/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/rzb_saac/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ } uninstall-pkglibLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ done clean-pkglibLTLIBRARIES: -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) @list='$(pkglib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } sf_rzb_saac_preproc.la: $(sf_rzb_saac_preproc_la_OBJECTS) $(sf_rzb_saac_preproc_la_DEPENDENCIES) $(EXTRA_sf_rzb_saac_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(sf_rzb_saac_preproc_la_LINK) -rpath $(pkglibdir) $(sf_rzb_saac_preproc_la_OBJECTS) $(sf_rzb_saac_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_rzb_saac_preproc_la-rzb_debug.lo: rzb_debug.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-rzb_debug.lo `test -f 'rzb_debug.c' || echo '$(srcdir)/'`rzb_debug.c sf_rzb_saac_preproc_la-rzb_http-client.lo: rzb_http-client.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-rzb_http-client.lo `test -f 'rzb_http-client.c' || echo '$(srcdir)/'`rzb_http-client.c sf_rzb_saac_preproc_la-rzb_http-fileinfo.lo: rzb_http-fileinfo.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-rzb_http-fileinfo.lo `test -f 'rzb_http-fileinfo.c' || echo '$(srcdir)/'`rzb_http-fileinfo.c sf_rzb_saac_preproc_la-rzb_http-server.lo: rzb_http-server.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-rzb_http-server.lo `test -f 'rzb_http-server.c' || echo '$(srcdir)/'`rzb_http-server.c sf_rzb_saac_preproc_la-rzb_smtp-collector.lo: rzb_smtp-collector.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-rzb_smtp-collector.lo `test -f 'rzb_smtp-collector.c' || echo '$(srcdir)/'`rzb_smtp-collector.c sf_rzb_saac_preproc_la-spp_rzb-saac.lo: spp_rzb-saac.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-spp_rzb-saac.lo `test -f 'spp_rzb-saac.c' || echo '$(srcdir)/'`spp_rzb-saac.c sf_rzb_saac_preproc_la-sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sf_rzb_saac_preproc_la-sf_ip.lo: ../include/sf_ip.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-sf_ip.lo `test -f '../include/sf_ip.c' || echo '$(srcdir)/'`../include/sf_ip.c sf_rzb_saac_preproc_la-sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sf_rzb_saac_preproc_la_CFLAGS) $(CFLAGS) -c -o sf_rzb_saac_preproc_la-sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(pkglibdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-pkglibLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-pkglibLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libtool clean-pkglibLTLIBRARIES \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-pkglibLTLIBRARIES install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-pkglibLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-pkglibLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/dnp3/0000755000000000000000000000000012260606565016000 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/dnp3/sf_dnp3.dsp0000644000000000000000000001347312153454770017774 00000000000000# Microsoft Developer Studio Project File - Name="sf_dnp3" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_dnp3 - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_dnp3.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_dnp3.mak" CFG="sf_dnp3 - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_dnp3 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_dnp3 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_dnp3 - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "SF_SNORT_PREPROC_DLL" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_dnp3 - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "SF_SNORT_PREPROC_DLL" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_dnp3 - Win32 Release" # Name "sf_dnp3 - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\dnp3_map.c # End Source File # Begin Source File SOURCE=.\dnp3_paf.c # End Source File # Begin Source File SOURCE=.\dnp3_reassembly.c # End Source File # Begin Source File SOURCE=.\dnp3_roptions.c # End Source File # Begin Source File SOURCE=..\include\mempool.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_sdlist.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\spp_dnp3.c # End Source File # Begin Source File SOURCE=..\include\strtok_r.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\dnp3_map.h # End Source File # Begin Source File SOURCE=.\dnp3_paf.h # End Source File # Begin Source File SOURCE=.\dnp3_reassembly.h # End Source File # Begin Source File SOURCE=.\dnp3_roptions.h # End Source File # Begin Source File SOURCE=..\include\mempool.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=..\include\sf_sdlist.h # End Source File # Begin Source File SOURCE=..\include\sf_sdlist_types.h # End Source File # Begin Source File SOURCE=.\spp_dnp3.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/dnp3/dnp3_map.h0000644000000000000000000000270312260565732017574 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Tables for DNP3 function & indicator definitions * */ #ifndef DNP3_MAP__H #define DNP3_MAP__H #include /* Check if "code" is in the function map. * * Returns: 1 on success, 0 on failure. */ int DNP3FuncIsDefined(uint16_t code); /* Return the DNP3 function code corresponding to "name". * * Returns: integer * -1 on failure */ int DNP3FuncStrToCode(char *name); /* Return the DNP3 indication code corresponding to "name". * * Returns: integer * -1 on failure */ int DNP3IndStrToCode(char *name); #endif snort-2.9.6.0/src/dynamic-preprocessors/dnp3/dnp3_map.c0000644000000000000000000001001612260565732017563 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Tables for DNP3 function & indicator definitions * */ #include #include #include "dnp3_map.h" /* Name/value pair struct */ typedef struct _dnp3_map_t { char *name; uint16_t value; } dnp3_map_t; /* Mapping of name -> function code for "dnp3_func" option. */ static dnp3_map_t func_map[] = { {"confirm", 0}, {"read", 1}, {"write", 2}, {"select", 3}, {"operate", 4}, {"direct_operate", 5}, {"direct_operate_nr", 6}, {"immed_freeze", 7}, {"immed_freeze_nr", 8}, {"freeze_clear", 9}, {"freeze_clear_nr", 10}, {"freeze_at_time", 11}, {"freeze_at_time_nr", 12}, {"cold_restart", 13}, {"warm_restart", 14}, {"initialize_data", 15}, {"initialize_appl", 16}, {"start_appl", 17}, {"stop_appl", 18}, {"save_config", 19}, {"enable_unsolicited", 20}, {"disable_unsolicited", 21}, {"assign_class", 22}, {"delay_measure", 23}, {"record_current_time", 24}, {"open_file", 25}, {"close_file", 26}, {"delete_file", 27}, {"get_file_info", 28}, {"authenticate_file", 29}, {"abort_file", 30}, {"activate_config", 31}, {"authenticate_req", 32}, {"authenticate_err", 33}, {"response", 129}, {"unsolicited_response", 130}, {"authenticate_resp", 131} }; /* Mapping of name -> indication bit for "dnp3_ind" option. */ static dnp3_map_t indication_map[] = { /* The order is strange, but this is the order in which the spec lists them. */ {"all_stations", 0x0100}, {"class_1_events", 0x0200}, {"class_2_events", 0x0400}, {"class_3_events", 0x0800}, {"need_time", 0x1000}, {"local_control", 0x2000}, {"device_trouble", 0x4000}, {"device_restart", 0x8000}, {"no_func_code_support", 0x0001}, {"object_unknown", 0x0002}, {"parameter_error", 0x0004}, {"event_buffer_overflow", 0x0008}, {"already_executing", 0x0010}, {"config_corrupt", 0x0020}, {"reserved_2", 0x0040}, {"reserved_1", 0x0080}, }; int DNP3FuncIsDefined(uint16_t code) { size_t num_funcs = sizeof(func_map) / sizeof(func_map[0]); size_t i; int func_is_defined = 0; /* Check to see if code is higher than all codes in func map */ if (code > func_map[num_funcs-1].value) return func_is_defined; for (i = 0; i < num_funcs-1; i++) { /* This short-circuit check assumes that the function map remains in-order. */ if (code <= func_map[i].value) break; } if (code == func_map[i].value) func_is_defined = 1; return func_is_defined; } int DNP3FuncStrToCode(char *name) { size_t num_funcs = sizeof(func_map) / sizeof(func_map[0]); size_t i; for (i = 0; i < num_funcs; i++) { if (strcmp(name, func_map[i].name) == 0) return func_map[i].value; } return -1; } int DNP3IndStrToCode(char *name) { size_t num_indications = sizeof(indication_map) / sizeof(indication_map[0]); size_t i; for (i = 0; i < num_indications; i++) { if (strcmp(name, indication_map[i].name) == 0) return indication_map[i].value; } return -1; } snort-2.9.6.0/src/dynamic-preprocessors/dnp3/dnp3_roptions.h0000644000000000000000000000356612260565732020704 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Rule options for the DNP3 preprocessor * */ #ifndef DNP3_ROPTIONS__H #define DNP3_ROPTIONS__H #include /* option names */ #define DNP3_FUNC_NAME "dnp3_func" #define DNP3_OBJ_NAME "dnp3_obj" #define DNP3_IND_NAME "dnp3_ind" #define DNP3_DATA_NAME "dnp3_data" /* Rule registration functions */ int DNP3FuncInit(struct _SnortConfig *sc, char *name, char *params, void **data); int DNP3ObjInit(struct _SnortConfig *sc, char *name, char *params, void **data); int DNP3IndInit(struct _SnortConfig *sc, char *name, char *params, void **data); int DNP3DataInit(struct _SnortConfig *sc, char *name, char *params, void **data); /* Rule evaluation functions */ int DNP3FuncEval(void *raw_packet, const uint8_t **cursor, void *data); int DNP3ObjEval(void *raw_packet, const uint8_t **cursor, void *data); int DNP3IndEval(void *raw_packet, const uint8_t **cursor, void *data); int DNP3DataEval(void *raw_packet, const uint8_t **cursor, void *data); #endif /* DNP3_ROPTIONS__H */ snort-2.9.6.0/src/dynamic-preprocessors/dnp3/dnp3_roptions.c0000644000000000000000000004302012260565732020664 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Rule options for the DNP3 preprocessor * */ #include #include "sf_types.h" #include "sf_snort_plugin_api.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "mempool.h" #include "spp_dnp3.h" #include "dnp3_map.h" #include "dnp3_roptions.h" /* Object decoding constants */ #define DNP3_OBJ_HDR_MIN_LEN 3 /* group, var, qualifier */ #define DNP3_OBJ_QUAL_PREFIX(x) ((x & 0x70) >> 4) #define DNP3_OBJ_QUAL_RANGE(x) (x & 0x0F) /* Object header prefix codes */ #define DNP3_PREFIX_NO_PREFIX 0x00 #define DNP3_PREFIX_1OCT_INDEX 0x01 #define DNP3_PREFIX_2OCT_INDEX 0x02 #define DNP3_PREFIX_4OCT_INDEX 0x03 #define DNP3_PREFIX_1OCT_SIZE 0x04 #define DNP3_PREFIX_2OCT_SIZE 0x05 #define DNP3_PREFIX_4OCT_SIZE 0x06 #define DNP3_PREFIX_RESERVED 0x07 /* Object header range specifiers -- 0x0A & 0x0C-0x0F are reserved */ #define DNP3_RANGE_1OCT_INDICES 0x00 #define DNP3_RANGE_2OCT_INDICES 0x01 #define DNP3_RANGE_4OCT_INDICES 0x02 #define DNP3_RANGE_1OCT_ADDRESSES 0x03 #define DNP3_RANGE_2OCT_ADDRESSES 0x04 #define DNP3_RANGE_4OCT_ADDRESSES 0x05 #define DNP3_RANGE_NO_RANGE 0x06 #define DNP3_RANGE_1OCT_COUNT 0x07 #define DNP3_RANGE_2OCT_COUNT 0x08 #define DNP3_RANGE_4OCT_COUNT 0x09 #define DNP3_RANGE_VARIABLE 0x0B typedef enum _dnp3_option_type_t { DNP3_FUNC = 0, DNP3_OBJ, DNP3_IND, DNP3_DATA } dnp3_option_type_t; typedef struct _dnp3_option_data_t { dnp3_option_type_t type; uint16_t arg; } dnp3_option_data_t; /* Parsing functions */ int DNP3FuncInit(struct _SnortConfig *sc, char *name, char *params, void **data) { char *endptr; dnp3_option_data_t *dnp3_data; long func_code; if (name == NULL || data == NULL) return 0; if (params == NULL) { DynamicPreprocessorFatalMessage("%s(%d): dnp3_func requires a " "number beween 0 and 255, or a valid function name.\n", *_dpd.config_file, *_dpd.config_line); } if (strcmp(name, DNP3_FUNC_NAME) != 0) return 0; dnp3_data = (dnp3_option_data_t *)calloc(1, sizeof(dnp3_option_data_t)); if (dnp3_data == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Failed to allocate memory for " "dnp3_func data structure.\n", __FILE__, __LINE__); } /* Parsing time */ if (isdigit(params[0])) { /* Function code given as integer */ func_code = _dpd.SnortStrtol(params, &endptr, 10); if ((func_code > 255) || (func_code < 0) || (*endptr != '\0')) { DynamicPreprocessorFatalMessage("%s(%d): dnp3_func requires a " "number beween 0 and 255, or a valid function name.\n", *_dpd.config_file, *_dpd.config_line); } } else { func_code = DNP3FuncStrToCode(params); if (func_code == -1) { DynamicPreprocessorFatalMessage("%s(%d): dnp3_func requires a " "number beween 0 and 255, or a valid function name.\n", *_dpd.config_file, *_dpd.config_line); } } dnp3_data->type = DNP3_FUNC; dnp3_data->arg = (uint16_t) func_code; *data = (void *)dnp3_data; return 1; } NORETURN static inline void DNP3ObjError(void) { DynamicPreprocessorFatalMessage("%s(%d) dnp3_obj requires two arguments," "where each argument is a number between 0 and 255.\n", *_dpd.config_file, *_dpd.config_line); } int DNP3ObjInit(struct _SnortConfig *sc, char *name, char *params, void **data) { char *endptr, *token, *saveptr; dnp3_option_data_t *dnp3_data; unsigned int obj_group, obj_var; if (name == NULL || data == NULL) return 0; if (strcmp(name, DNP3_OBJ_NAME) != 0) return 0; if (params == NULL) { DynamicPreprocessorFatalMessage("%s(%d): No argument given for dnp3_obj. " "dnp3_obj requires two arguments, where each argument is a number " "between 0 and 255.\n", *_dpd.config_file, *_dpd.config_line); } dnp3_data = (dnp3_option_data_t *)calloc(1, sizeof(dnp3_option_data_t)); if (dnp3_data == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Failed to allocate memory for " "dnp3_func data structure.\n", __FILE__, __LINE__); } token = strtok_r(params, ",", &saveptr); if (token == NULL) DNP3ObjError(); /* First token: object group */ obj_group = _dpd.SnortStrtoul(token, &endptr, 10); if ((obj_group > 255) || (*endptr != '\0')) DNP3ObjError(); token = strtok_r(NULL, ",", &saveptr); if (token == NULL) DNP3ObjError(); /* Second token: object var */ obj_var = _dpd.SnortStrtoul(token, &endptr, 10); if ((obj_var > 255) || (*endptr != '\0')) DNP3ObjError(); /* pack the two arguments into one uint16_t */ dnp3_data->type = DNP3_OBJ; dnp3_data->arg = ((obj_group << 8) | (obj_var)); *data = dnp3_data; return 1; } int DNP3IndInit(struct _SnortConfig *sc, char *name, char *params, void **data) { dnp3_option_data_t *dnp3_data; char *token, *saveptr; uint16_t flags = 0; if (name == NULL || data == NULL) return 0; if (params == NULL) { DynamicPreprocessorFatalMessage("%s(%d): dnp3_ind requires a " "number beween 0 and 255, or a valid function name.\n", *_dpd.config_file, *_dpd.config_line); } dnp3_data = (dnp3_option_data_t *)calloc(1, sizeof(dnp3_option_data_t)); if (dnp3_data == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Failed to allocate memory for " "dnp3_func data structure.\n", __FILE__, __LINE__); } token = strtok_r(params, ",", &saveptr); while (token != NULL) { int flag = DNP3IndStrToCode(token); if (flag == -1) { DynamicPreprocessorFatalMessage("%s(%d): dnp3_ind requires a " "valid indication flag name. '%s' is invalid.\n", *_dpd.config_file, *_dpd.config_line, token); } flags |= (uint16_t) flag; token = strtok_r(NULL, ",", &saveptr); } if (flags == 0) { DynamicPreprocessorFatalMessage("%s(%d): dnp3_ind requires a " "valid indication flag name. No flags were given.\n", *_dpd.config_file, *_dpd.config_line); } dnp3_data->type = DNP3_IND; dnp3_data->arg = flags; *data = (void *)dnp3_data; return 1; } int DNP3DataInit(struct _SnortConfig *sc, char *name, char *params, void **data) { dnp3_option_data_t *dnp3_data; if (name == NULL || data == NULL) return 0; /* nothing to parse. */ if (params) { DynamicPreprocessorFatalMessage("%s(%d): dnp3_data does not take " "any arguments.\n", *_dpd.config_file, *_dpd.config_line); } dnp3_data = (dnp3_option_data_t *)calloc(1, sizeof(dnp3_option_data_t)); if (dnp3_data == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Failed to allocate memory for " "dnp3_data data structure.\n", __FILE__, __LINE__); } dnp3_data->type = DNP3_DATA; dnp3_data->arg = 0; *data = (void *)dnp3_data; return 1; } /* Evaluation functions */ int DNP3FuncEval(void *raw_packet, const uint8_t **cursor, void *data) { SFSnortPacket *packet = (SFSnortPacket *)raw_packet; MemBucket *tmp_bucket; dnp3_option_data_t *rule_data = (dnp3_option_data_t *)data; dnp3_session_data_t *session_data; dnp3_reassembly_data_t *rdata; /* The preprocessor only evaluates PAF-flushed PDUs. If the rule options don't check for this, they'll fire on stale session data when the original packet goes through before flushing. */ if (packet->tcp_header && !PacketHasFullPDU(packet)) return RULE_NOMATCH; /* For UDP packets, there is no PAF so we use the Alt Decode buffer. */ if (packet->udp_header && !_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE)) return RULE_NOMATCH; tmp_bucket = (MemBucket *) _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_DNP3); if ((packet->payload_size == 0) || (tmp_bucket == NULL)) { return RULE_NOMATCH; } session_data = (dnp3_session_data_t *)tmp_bucket->data; if (session_data->direction == DNP3_CLIENT) rdata = &(session_data->client_rdata); else rdata = &(session_data->server_rdata); /* Only evaluate rules against complete Application-layer fragments */ if (rdata->state != DNP3_REASSEMBLY_STATE__DONE) return RULE_NOMATCH; if (session_data->func == rule_data->arg) return RULE_MATCH; return RULE_NOMATCH; } static int DNP3DecodeObject(uint8_t *buf, uint16_t buflen, uint8_t rule_group, uint8_t rule_var) { uint8_t group, var; /* XXX: uncomment these when fixing the below TODO regarding multiple objects uint8_t qualifier, prefix_size, prefix_code, range_specifier; uint32_t begin, end, num_objects; */ if (buf == NULL || buflen < DNP3_OBJ_HDR_MIN_LEN) return RULE_NOMATCH; /* Decode group */ group = *buf; buf++; buflen--; /* Decode var */ var = *buf; buf++; buflen--; /* Match the rule option here, quit decoding if we found the right header. */ if ((group == rule_group) && (var == rule_var)) return RULE_MATCH; /* TODO: Implement matching with multiple objects in a Request/Response. */ #if 0 /* Decode qualifier */ qualifier = *buf; prefix_code = DNP3_OBJ_QUAL_PREFIX(qualifier); range_specifier = DNP3_OBJ_QUAL_RANGE(qualifier); buf++; buflen--; /* The size of object prefixes depends on the prefix code */ switch (prefix_code) { case DNP3_PREFIX_NO_PREFIX: prefix_size = 0; break; case DNP3_PREFIX_1OCT_INDEX: case DNP3_PREFIX_1OCT_SIZE: prefix_size = 1; break; case DNP3_PREFIX_2OCT_INDEX: case DNP3_PREFIX_2OCT_SIZE: prefix_size = 2; break; case DNP3_PREFIX_4OCT_INDEX: case DNP3_PREFIX_4OCT_SIZE: prefix_size = 4; break; default: /* TODO: Preprocessor alert on reserved value */ return DNP3_FAIL; } /* Decoding of the range field depends on the Range Specifier */ switch (range_specifier) { case DNP3_RANGE_1OCT_INDICES: if (buflen < 2) return DNP3_FAIL; /* Decode 8-bit indices for object prefixes */ begin = *(uint8_t *)buf++; end = *(uint8_t *)buf++; buflen -= 2; /* Check that indices make sense */ if (begin > end) return DNP3_FAIL; /* TODO: Preprocessor alert */ num_objects = end - begin + 1; break; case DNP3_RANGE_2OCT_INDICES: if (buflen < 2) return DNP3_FAIL; /* Decode 8-bit indices for object prefixes */ begin = *(uint16_t *)buf++; end = *(uint16_t *)buf++; buflen -= 2; /* Check that indices make sense */ if (begin > end) return DNP3_FAIL; /* TODO: Preprocessor alert */ num_objects = end - begin + 1; break; case DNP3_RANGE_4OCT_INDICES: case DNP3_RANGE_1OCT_ADDRESSES: case DNP3_RANGE_2OCT_ADDRESSES: case DNP3_RANGE_4OCT_ADDRESSES: case DNP3_RANGE_NO_RANGE: case DNP3_RANGE_1OCT_COUNT: case DNP3_RANGE_2OCT_COUNT: case DNP3_RANGE_4OCT_COUNT: case DNP3_RANGE_VARIABLE: default: } #endif /* 0 */ return RULE_NOMATCH; } int DNP3ObjEval(void *raw_packet, const uint8_t **cursor, void *data) { SFSnortPacket *packet = (SFSnortPacket *)raw_packet; MemBucket *tmp_bucket; dnp3_option_data_t *rule_data = (dnp3_option_data_t *)data; dnp3_session_data_t *session_data; dnp3_reassembly_data_t *rdata; uint8_t group, var; uint8_t *obj_buffer; uint16_t obj_buflen; size_t header_size; int rval = RULE_NOMATCH; /* The preprocessor only evaluates PAF-flushed PDUs. If the rule options don't check for this, they'll fire on stale session data when the original packet goes through before flushing. */ if (packet->tcp_header && !PacketHasFullPDU(packet)) return RULE_NOMATCH; /* For UDP packets, there is no PAF so we use the Alt Decode buffer. */ if (packet->udp_header && !_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE)) return RULE_NOMATCH; tmp_bucket = (MemBucket *) _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_DNP3); if ((packet->payload_size == 0) || (tmp_bucket == NULL)) { return RULE_NOMATCH; } session_data = (dnp3_session_data_t *)tmp_bucket->data; if (session_data->direction == DNP3_CLIENT) { rdata = &(session_data->client_rdata); header_size = sizeof(dnp3_app_request_header_t); } else { rdata = &(session_data->server_rdata); header_size = sizeof(dnp3_app_response_header_t); } /* Only evaluate rules against complete Application-layer fragments */ if (rdata->state != DNP3_REASSEMBLY_STATE__DONE) return RULE_NOMATCH; /* Skip over the App request/response header. They are different sizes, depending on whether it is a request or response! */ if (rdata->buflen < header_size) return RULE_NOMATCH; obj_buffer = (uint8_t *)rdata->buffer + header_size; obj_buflen = rdata->buflen - header_size; /* Rule parsing code combined our two arguments into a single uint16_t */ group = (rule_data->arg >> 8); var = (rule_data->arg & 0x00FF); rval = DNP3DecodeObject(obj_buffer, obj_buflen, group, var); return rval; } int DNP3IndEval(void *raw_packet, const uint8_t **cursor, void *data) { SFSnortPacket *packet = (SFSnortPacket *)raw_packet; MemBucket *tmp_bucket; dnp3_option_data_t *rule_data = (dnp3_option_data_t *)data; dnp3_session_data_t *session_data; dnp3_reassembly_data_t *rdata; /* The preprocessor only evaluates PAF-flushed PDUs. If the rule options don't check for this, they'll fire on stale session data when the original packet goes through before flushing. */ if (packet->tcp_header && !PacketHasFullPDU(packet)) return RULE_NOMATCH; /* For UDP packets, there is no PAF so we use the Alt Decode buffer. */ if (packet->udp_header && !_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE)) return RULE_NOMATCH; tmp_bucket = (MemBucket *) _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_DNP3); if ((packet->payload_size == 0) || (tmp_bucket == NULL)) { return RULE_NOMATCH; } session_data = (dnp3_session_data_t *)tmp_bucket->data; /* Internal Indications only apply to DNP3 responses, not requests. */ if (session_data->direction == DNP3_CLIENT) return RULE_NOMATCH; rdata = &(session_data->server_rdata); /* Only evaluate rules against complete Application-layer fragments */ if (rdata->state != DNP3_REASSEMBLY_STATE__DONE) return RULE_NOMATCH; if (session_data->indications & rule_data->arg) return RULE_MATCH; return RULE_NOMATCH; } int DNP3DataEval(void *raw_packet, const uint8_t **cursor, void *data) { SFSnortPacket *packet = (SFSnortPacket *)raw_packet; MemBucket *tmp_bucket; dnp3_session_data_t *session_data; dnp3_reassembly_data_t *rdata; /* The preprocessor only evaluates PAF-flushed PDUs. If the rule options don't check for this, they'll fire on stale session data when the original packet goes through before flushing. */ if (packet->tcp_header && !PacketHasFullPDU(packet)) return RULE_NOMATCH; /* For UDP packets, there is no PAF so we use the Alt Decode buffer. */ if (packet->udp_header && !_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE)) return RULE_NOMATCH; tmp_bucket = (MemBucket *) _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_DNP3); if ((packet->payload_size == 0) || (tmp_bucket == NULL)) { return RULE_NOMATCH; } session_data = (dnp3_session_data_t *)tmp_bucket->data; if (session_data->direction == DNP3_CLIENT) rdata = &(session_data->client_rdata); else rdata = &(session_data->server_rdata); /* Only evaluate rules against complete Application-layer fragments */ if (rdata->state != DNP3_REASSEMBLY_STATE__DONE) return RULE_NOMATCH; /* Set the cursor to the reassembled Application-layer buffer */ *cursor = (uint8_t *)rdata->buffer; _dpd.SetAltDetect((uint8_t *)rdata->buffer, rdata->buflen); return RULE_MATCH; } snort-2.9.6.0/src/dynamic-preprocessors/dnp3/dnp3_reassembly.h0000644000000000000000000000240012260565732021157 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Dynamic preprocessor for the DNP3 protocol * */ #ifndef DNP3_REASSEMBLY__H #define DNP3_REASSEMBLY__H #include "sf_types.h" #include "sf_snort_packet.h" #include "spp_dnp3.h" int DNP3FullReassembly(dnp3_config_t *config, dnp3_session_data_t *session, SFSnortPacket *packet, uint8_t *pdu_start, uint16_t pdu_length); #endif /* DNP3_REASSEMBLY__H */ snort-2.9.6.0/src/dynamic-preprocessors/dnp3/dnp3_reassembly.c0000644000000000000000000003746512260565732021175 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Dynamic preprocessor for the DNP3 protocol * */ #include #include #include "spp_dnp3.h" #include "sf_types.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_packet.h" #include "snort_bounds.h" #include "dnp3_map.h" #include "dnp3_reassembly.h" #include "dnp3_roptions.h" /* Minimum length of DNP3 "len" field in order to get a transport header. */ #define DNP3_MIN_TRANSPORT_LEN 6 #define DNP3_TPDU_MAX 250 #define DNP3_LPDU_MAX 292 /* CRC look-up table, for computeCRC() below */ static uint16_t crcLookUpTable[256] = { 0x0000, 0x365E, 0x6CBC, 0x5AE2, 0xD978, 0xEF26, 0xB5C4, 0x839A, 0xFF89, 0xC9D7, 0x9335, 0xA56B, 0x26F1, 0x10AF, 0x4A4D, 0x7C13, 0xB26B, 0x8435, 0xDED7, 0xE889, 0x6B13, 0x5D4D, 0x07AF, 0x31F1, 0x4DE2, 0x7BBC, 0x215E, 0x1700, 0x949A, 0xA2C4, 0xF826, 0xCE78, 0x29AF, 0x1FF1, 0x4513, 0x734D, 0xF0D7, 0xC689, 0x9C6B, 0xAA35, 0xD626, 0xE078, 0xBA9A, 0x8CC4, 0x0F5E, 0x3900, 0x63E2, 0x55BC, 0x9BC4, 0xAD9A, 0xF778, 0xC126, 0x42BC, 0x74E2, 0x2E00, 0x185E, 0x644D, 0x5213, 0x08F1, 0x3EAF, 0xBD35, 0x8B6B, 0xD189, 0xE7D7, 0x535E, 0x6500, 0x3FE2, 0x09BC, 0x8A26, 0xBC78, 0xE69A, 0xD0C4, 0xACD7, 0x9A89, 0xC06B, 0xF635, 0x75AF, 0x43F1, 0x1913, 0x2F4D, 0xE135, 0xD76B, 0x8D89, 0xBBD7, 0x384D, 0x0E13, 0x54F1, 0x62AF, 0x1EBC, 0x28E2, 0x7200, 0x445E, 0xC7C4, 0xF19A, 0xAB78, 0x9D26, 0x7AF1, 0x4CAF, 0x164D, 0x2013, 0xA389, 0x95D7, 0xCF35, 0xF96B, 0x8578, 0xB326, 0xE9C4, 0xDF9A, 0x5C00, 0x6A5E, 0x30BC, 0x06E2, 0xC89A, 0xFEC4, 0xA426, 0x9278, 0x11E2, 0x27BC, 0x7D5E, 0x4B00, 0x3713, 0x014D, 0x5BAF, 0x6DF1, 0xEE6B, 0xD835, 0x82D7, 0xB489, 0xA6BC, 0x90E2, 0xCA00, 0xFC5E, 0x7FC4, 0x499A, 0x1378, 0x2526, 0x5935, 0x6F6B, 0x3589, 0x03D7, 0x804D, 0xB613, 0xECF1, 0xDAAF, 0x14D7, 0x2289, 0x786B, 0x4E35, 0xCDAF, 0xFBF1, 0xA113, 0x974D, 0xEB5E, 0xDD00, 0x87E2, 0xB1BC, 0x3226, 0x0478, 0x5E9A, 0x68C4, 0x8F13, 0xB94D, 0xE3AF, 0xD5F1, 0x566B, 0x6035, 0x3AD7, 0x0C89, 0x709A, 0x46C4, 0x1C26, 0x2A78, 0xA9E2, 0x9FBC, 0xC55E, 0xF300, 0x3D78, 0x0B26, 0x51C4, 0x679A, 0xE400, 0xD25E, 0x88BC, 0xBEE2, 0xC2F1, 0xF4AF, 0xAE4D, 0x9813, 0x1B89, 0x2DD7, 0x7735, 0x416B, 0xF5E2, 0xC3BC, 0x995E, 0xAF00, 0x2C9A, 0x1AC4, 0x4026, 0x7678, 0x0A6B, 0x3C35, 0x66D7, 0x5089, 0xD313, 0xE54D, 0xBFAF, 0x89F1, 0x4789, 0x71D7, 0x2B35, 0x1D6B, 0x9EF1, 0xA8AF, 0xF24D, 0xC413, 0xB800, 0x8E5E, 0xD4BC, 0xE2E2, 0x6178, 0x5726, 0x0DC4, 0x3B9A, 0xDC4D, 0xEA13, 0xB0F1, 0x86AF, 0x0535, 0x336B, 0x6989, 0x5FD7, 0x23C4, 0x159A, 0x4F78, 0x7926, 0xFABC, 0xCCE2, 0x9600, 0xA05E, 0x6E26, 0x5878, 0x029A, 0x34C4, 0xB75E, 0x8100, 0xDBE2, 0xEDBC, 0x91AF, 0xA7F1, 0xFD13, 0xCB4D, 0x48D7, 0x7E89, 0x246B, 0x1235 }; /* Append a DNP3 Transport segment to the reassembly buffer. Returns: DNP3_OK: Segment queued successfully. DNP3_FAIL: Data copy failed. Segment did not fit in reassembly buffer. */ static int DNP3QueueSegment(dnp3_reassembly_data_t *rdata, char *buf, uint16_t buflen) { if (rdata == NULL || buf == NULL) return DNP3_FAIL; /* At first I was afraid, but we checked for DNP3_MAX_TRANSPORT_LEN earlier. */ if (buflen + rdata->buflen > DNP3_BUFFER_SIZE) return DNP3_FAIL; memcpy((rdata->buffer + rdata->buflen), buf, (size_t) buflen); rdata->buflen += buflen; return DNP3_OK; } /* Reset a DNP3 reassembly buffer */ static void DNP3ReassemblyReset(dnp3_reassembly_data_t *rdata) { rdata->buflen = 0; rdata->state = DNP3_REASSEMBLY_STATE__IDLE; rdata->last_seq = 0; } /* DNP3 Transport-Layer reassembly state machine. Arguments: rdata: DNP3 reassembly state object. buf: DNP3 Transport Layer segment buflen: Length of Transport Layer segment. Returns: DNP3_FAIL: Segment was discarded. DNP3_OK: Segment was queued. */ static int DNP3ReassembleTransport(dnp3_reassembly_data_t *rdata, char *buf, uint16_t buflen) { dnp3_transport_header_t *trans_header; if (rdata == NULL || buf == NULL || buflen < sizeof(dnp3_transport_header_t) || (buflen > DNP3_MAX_TRANSPORT_LEN)) { return DNP3_FAIL; } /* Take the first byte as a transport header, cut it off of the buffer. */ trans_header = (dnp3_transport_header_t *)buf; buf += sizeof(dnp3_transport_header_t); buflen -= sizeof(dnp3_transport_header_t); /* If the previously-existing state was DONE, we need to reset it back to IDLE. */ if (rdata->state == DNP3_REASSEMBLY_STATE__DONE) DNP3ReassemblyReset(rdata); switch (rdata->state) { case DNP3_REASSEMBLY_STATE__IDLE: /* Discard any non-first segment. */ if ( DNP3_TRANSPORT_FIR(trans_header->control) == 0 ) return DNP3_FAIL; /* Reset the buffer & queue the first segment */ DNP3ReassemblyReset(rdata); DNP3QueueSegment(rdata, buf, buflen); rdata->last_seq = DNP3_TRANSPORT_SEQ(trans_header->control); if ( DNP3_TRANSPORT_FIN(trans_header->control) ) rdata->state = DNP3_REASSEMBLY_STATE__DONE; else rdata->state = DNP3_REASSEMBLY_STATE__ASSEMBLY; break; case DNP3_REASSEMBLY_STATE__ASSEMBLY: /* Reset if the FIR flag is set. */ if ( DNP3_TRANSPORT_FIR(trans_header->control) ) { DNP3ReassemblyReset(rdata); DNP3QueueSegment(rdata, buf, buflen); rdata->last_seq = DNP3_TRANSPORT_SEQ(trans_header->control); if (DNP3_TRANSPORT_FIN(trans_header->control)) rdata->state = DNP3_REASSEMBLY_STATE__DONE; /* Raise an alert so it's clear the buffer was reset. Could signify device trouble. */ _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_REASSEMBLY_BUFFER_CLEARED, 1, 0, 3, DNP3_REASSEMBLY_BUFFER_CLEARED_STR, 0); } else { /* Same seq but FIN is set. Discard segment, BUT finish reassembly. */ if ((DNP3_TRANSPORT_SEQ(trans_header->control) == rdata->last_seq) && (DNP3_TRANSPORT_FIN(trans_header->control))) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_DROPPED_SEGMENT, 1, 0, 3, DNP3_DROPPED_SEGMENT_STR, 0); rdata->state = DNP3_REASSEMBLY_STATE__DONE; return DNP3_FAIL; } /* Discard any other segments without the correct sequence. */ if (DNP3_TRANSPORT_SEQ(trans_header->control) != ((rdata->last_seq + 1) % 0x40 )) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_DROPPED_SEGMENT, 1, 0, 3, DNP3_DROPPED_SEGMENT_STR, 0); return DNP3_FAIL; } /* Otherwise, queue it up! */ DNP3QueueSegment(rdata, buf, buflen); rdata->last_seq = DNP3_TRANSPORT_SEQ(trans_header->control); if (DNP3_TRANSPORT_FIN(trans_header->control)) rdata->state = DNP3_REASSEMBLY_STATE__DONE; else rdata->state = DNP3_REASSEMBLY_STATE__ASSEMBLY; } break; case DNP3_REASSEMBLY_STATE__DONE: break; } /* Set the Alt Decode buffer. This must be done during preprocessing in order to stop the Fast Pattern matcher from using raw packet data to evaluate the longest content in a rule. */ if (rdata->state == DNP3_REASSEMBLY_STATE__DONE) { uint8_t *alt_buf = _dpd.altBuffer->data; uint16_t alt_len = sizeof(_dpd.altBuffer->data); int ret; ret = SafeMemcpy((void *)alt_buf, (const void *)rdata->buffer, (size_t)rdata->buflen, (const void *)alt_buf, (const void *)(alt_buf + alt_len)); if (ret == SAFEMEM_SUCCESS) _dpd.SetAltDecode(alt_len); } return DNP3_OK; } /* Check for reserved application-level function codes. */ static void DNP3CheckReservedFunction(dnp3_session_data_t *session) { if ( !(DNP3FuncIsDefined( (uint16_t)session->func)) ) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_RESERVED_FUNCTION, 1, 0, 3, DNP3_RESERVED_FUNCTION_STR, 0); } } /* Decode a DNP3 Application-layer Fragment, fill out the relevant session data for rule option evaluation. */ static int DNP3ProcessApplication(dnp3_session_data_t *session) { dnp3_reassembly_data_t *rdata = NULL; if (session == NULL) return DNP3_FAIL; /* Master and Outstation use slightly different Application-layer headers. Only the outstation sends Internal Indications. */ if (session->direction == DNP3_CLIENT) { dnp3_app_request_header_t *request = NULL; rdata = &(session->client_rdata); if (rdata->buflen < sizeof(dnp3_app_request_header_t)) return DNP3_FAIL; /* TODO: Preprocessor Alert */ request = (dnp3_app_request_header_t *)(rdata->buffer); session->func = request->function; } else if (session->direction == DNP3_SERVER) { dnp3_app_response_header_t *response = NULL; rdata = &(session->server_rdata); if (rdata->buflen < sizeof(dnp3_app_response_header_t)) return DNP3_FAIL; /* TODO: Preprocessor Alert */ response = (dnp3_app_response_header_t *)(rdata->buffer); session->func = response->function; session->indications = ntohs(response->indications); } DNP3CheckReservedFunction(session); return DNP3_OK; } /* Check a CRC in a single block. */ /* This code is mostly lifted from the example in the DNP3 spec. */ static inline void computeCRC(unsigned char data, uint16_t *crcAccum) { *crcAccum = (*crcAccum >> 8) ^ crcLookUpTable[(*crcAccum ^ data) & 0xFF]; } static int DNP3CheckCRC(unsigned char *buf, uint16_t buflen) { uint16_t idx; uint16_t crc = 0; /* Compute check code for data in received block */ for (idx = 0; idx < buflen-2; idx++) computeCRC(buf[idx], &crc); crc = ~crc; /* Invert */ /* Check CRC at end of block */ if (buf[idx++] == (unsigned char)crc && buf[idx] == (unsigned char)(crc >> 8)) return DNP3_OK; else return DNP3_FAIL; } /* Check CRCs in a Link-Layer Frame, then fill a buffer containing just the user data */ static int DNP3CheckRemoveCRC(dnp3_config_t *config, uint8_t *pdu_start, uint16_t pdu_length, char *buf, uint16_t *buflen) { char *cursor; uint16_t bytes_left; uint16_t curlen = 0; /* Check Header CRC */ if ((config->check_crc) && (DNP3CheckCRC((unsigned char*)pdu_start, sizeof(dnp3_link_header_t)+2) == DNP3_FAIL)) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_BAD_CRC, 1, 0, 3, DNP3_BAD_CRC_STR, 0); return DNP3_FAIL; } cursor = (char *)pdu_start + sizeof(dnp3_link_header_t) + 2; bytes_left = pdu_length - sizeof(dnp3_link_header_t) - 2; /* Process whole 16-byte chunks (plus 2-byte CRC) */ while ( (bytes_left > (DNP3_CHUNK_SIZE + DNP3_CRC_SIZE)) && (curlen + DNP3_CHUNK_SIZE < *buflen) ) { if ((config->check_crc) && (DNP3CheckCRC((unsigned char*)cursor, (DNP3_CHUNK_SIZE+DNP3_CRC_SIZE)) == DNP3_FAIL)) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_BAD_CRC, 1, 0, 3, DNP3_BAD_CRC_STR, 0); return DNP3_FAIL; } memcpy((buf + curlen), cursor, DNP3_CHUNK_SIZE); curlen += DNP3_CHUNK_SIZE; cursor += (DNP3_CHUNK_SIZE+DNP3_CRC_SIZE); bytes_left -= (DNP3_CHUNK_SIZE+DNP3_CRC_SIZE); } /* Process leftover chunk, under 16 bytes */ if ( (bytes_left > DNP3_CRC_SIZE) && (curlen + bytes_left < *buflen) ) { if ((config->check_crc) && (DNP3CheckCRC((unsigned char*)cursor, bytes_left) == DNP3_FAIL)) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_BAD_CRC, 1, 0, 3, DNP3_BAD_CRC_STR, 0); return DNP3_FAIL; } memcpy((buf + curlen), cursor, (bytes_left - DNP3_CRC_SIZE)); curlen += (bytes_left - DNP3_CRC_SIZE); cursor += bytes_left; bytes_left = 0; } *buflen = curlen; return DNP3_OK; } static int DNP3CheckReservedAddrs(dnp3_link_header_t *link) { int bad_addr = 0; if ((link->src >= DNP3_MIN_RESERVED_ADDR) && (link->src <= DNP3_MAX_RESERVED_ADDR)) bad_addr = 1; else if ((link->dest >= DNP3_MIN_RESERVED_ADDR) && (link->dest <= DNP3_MAX_RESERVED_ADDR)) bad_addr = 1; if (bad_addr) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_RESERVED_ADDRESS, 1, 0, 3, DNP3_RESERVED_ADDRESS_STR, 0); return DNP3_FAIL; } return DNP3_OK; } /* Main DNP3 Reassembly function. Moved here to avoid circular dependency between spp_dnp3 and dnp3_reassembly. */ int DNP3FullReassembly(dnp3_config_t *config, dnp3_session_data_t *session, SFSnortPacket *packet, uint8_t *pdu_start, uint16_t pdu_length) { char buf[DNP3_TPDU_MAX]; uint16_t buflen = sizeof(buf); dnp3_link_header_t *link; dnp3_reassembly_data_t *rdata; if (pdu_length < (sizeof(dnp3_link_header_t) + sizeof(dnp3_transport_header_t) + 2)) return DNP3_FAIL; if ( pdu_length > DNP3_LPDU_MAX ) // this means PAF aborted - not DNP3 return DNP3_FAIL; /* Step 1: Decode header and skip to data */ link = (dnp3_link_header_t *) pdu_start; if (link->len < DNP3_MIN_TRANSPORT_LEN) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_DROPPED_FRAME, 1, 0, 3, DNP3_DROPPED_FRAME_STR, 0); return DNP3_FAIL; } /* Check reserved addresses */ if ( DNP3CheckReservedAddrs(link) == DNP3_FAIL ) return DNP3_FAIL; /* XXX: NEED TO TRACK SEPARATE DNP3 SESSIONS OVER SINGLE TCP SESSION */ /* Step 2: Remove CRCs */ if ( DNP3CheckRemoveCRC(config, pdu_start, pdu_length, buf, &buflen) == DNP3_FAIL ) return DNP3_FAIL; /* Step 3: Queue user data in frame for Transport-Layer reassembly */ if (session->direction == DNP3_CLIENT) rdata = &(session->client_rdata); else rdata = &(session->server_rdata); if (DNP3ReassembleTransport(rdata, buf, buflen) == DNP3_FAIL) return DNP3_FAIL; /* Step 4: Decode Application-Layer */ if (rdata->state == DNP3_REASSEMBLY_STATE__DONE) { int ret = DNP3ProcessApplication(session); /* To support multiple PDUs in UDP, we're going to call Detect() on each individual PDU. The AltDecode buffer was set earlier. */ if ((ret == DNP3_OK) && (packet->udp_header)) _dpd.detect(packet); else return ret; } return DNP3_OK; } snort-2.9.6.0/src/dynamic-preprocessors/dnp3/dnp3_paf.h0000644000000000000000000000241212260565732017562 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Protocol Aware Flushing (PAF) code for DNP3 preprocessor. * */ #ifndef DNP3_PAF__H #define DNP3_PAF__H #include "spp_dnp3.h" #include "stream_api.h" int DNP3AddPortsToPaf(struct _SnortConfig *sc, dnp3_config_t *config, tSfPolicyId policy_id); int DNP3AddServiceToPaf(struct _SnortConfig *sc, uint16_t service, tSfPolicyId policy_id); #endif /* DNP3_PAF__H */ snort-2.9.6.0/src/dynamic-preprocessors/dnp3/dnp3_paf.c0000644000000000000000000001366712260565732017573 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Protocol Aware Flushing (PAF) code for DNP3 preprocessor. * */ #include "spp_dnp3.h" #include "dnp3_paf.h" #include "sf_dynamic_preprocessor.h" /* Forward declarations */ static PAF_Status DNP3Paf(void *ssn, void **user, const uint8_t *data, uint32_t len, uint32_t flags, uint32_t *fp); /* State-tracking structs */ typedef enum _dnp3_paf_state { DNP3_PAF_STATE__START_1 = 0, DNP3_PAF_STATE__START_2, DNP3_PAF_STATE__LENGTH, DNP3_PAF_STATE__SET_FLUSH } dnp3_paf_state_t; typedef struct _dnp3_paf_data { dnp3_paf_state_t state; uint8_t dnp3_length; uint16_t real_length; } dnp3_paf_data_t; static int DNP3PafRegisterPort (struct _SnortConfig *sc, uint16_t port, tSfPolicyId policy_id) { if (!_dpd.isPafEnabled()) return 0; _dpd.streamAPI->register_paf_port(sc, policy_id, port, 0, DNP3Paf, true); _dpd.streamAPI->register_paf_port(sc, policy_id, port, 1, DNP3Paf, true); return 0; } #ifdef TARGET_BASED int DNP3AddServiceToPaf (struct _SnortConfig *sc, uint16_t service, tSfPolicyId policy_id) { if (!_dpd.isPafEnabled()) return 0; _dpd.streamAPI->register_paf_service(sc, policy_id, service, 0, DNP3Paf, true); _dpd.streamAPI->register_paf_service(sc, policy_id, service, 1, DNP3Paf, true); return 0; } #endif /* Function: DNP3Paf() Purpose: DNP3 PAF callback. Statefully inspects DNP3 traffic from the start of a session, Reads up until the length octet is found, then sets a flush point. The flushed PDU is a DNP3 Link Layer frame, the preprocessor handles reassembly of frames into Application Layer messages. Arguments: void * - stream5 session pointer void ** - DNP3 state tracking structure const uint8_t * - payload data to inspect uint32_t - length of payload data uint32_t - flags to check whether client or server uint32_t * - pointer to set flush point Returns: PAF_Status - PAF_FLUSH if flush point found, PAF_SEARCH otherwise */ static PAF_Status DNP3Paf(void *ssn, void **user, const uint8_t *data, uint32_t len, uint32_t flags, uint32_t *fp) { dnp3_paf_data_t *pafdata = *(dnp3_paf_data_t **)user; uint32_t bytes_processed = 0; /* Allocate state object if it doesn't exist yet. */ if (pafdata == NULL) { pafdata = calloc(1, sizeof(dnp3_paf_data_t)); if (pafdata == NULL) return PAF_ABORT; *user = pafdata; } /* Process this packet 1 byte at a time */ while (bytes_processed < len) { uint16_t user_data = 0; uint16_t num_crcs = 0; switch (pafdata->state) { /* Check the Start bytes. If they are not \x05\x64, don't advance state. Could be out of sync, junk data between frames, mid-stream pickup, etc. */ case DNP3_PAF_STATE__START_1: if (((uint8_t) *(data + bytes_processed)) == DNP3_START_BYTE_1) pafdata->state++; else return PAF_ABORT; break; case DNP3_PAF_STATE__START_2: if (((uint8_t) *(data + bytes_processed)) == DNP3_START_BYTE_2) pafdata->state++; else return PAF_ABORT; break; /* Read the length. */ case DNP3_PAF_STATE__LENGTH: pafdata->dnp3_length = (uint8_t) *(data + bytes_processed); /* DNP3 length only counts non-CRC octets following the length field itself. Each CRC is two octets. One follows the headers, a CRC is inserted for every 16 octets of user data, plus a CRC for the last bit of user data (< 16 octets) */ if (pafdata->dnp3_length < DNP3_HEADER_REMAINDER_LEN) { /* XXX: Can we go about raising decoder alerts & dropping packets within PAF? */ return PAF_ABORT; } user_data = pafdata->dnp3_length - DNP3_HEADER_REMAINDER_LEN; num_crcs = 1 + (user_data/DNP3_CHUNK_SIZE) + (user_data % DNP3_CHUNK_SIZE? 1 : 0); pafdata->real_length = pafdata->dnp3_length + (DNP3_CRC_SIZE*num_crcs); pafdata->state++; break; /* Set the flush point. */ case DNP3_PAF_STATE__SET_FLUSH: *fp = pafdata->real_length + bytes_processed; pafdata->state = DNP3_PAF_STATE__START_1; return PAF_FLUSH; } bytes_processed++; } return PAF_SEARCH; } /* Take a DNP3 config + Snort policy, iterate through ports, register PAF callback. */ int DNP3AddPortsToPaf(struct _SnortConfig *sc, dnp3_config_t *config, tSfPolicyId policy_id) { unsigned int i; for (i = 0; i < MAX_PORTS; i++) { if (config->ports[PORT_INDEX(i)] & CONV_PORT(i)) { DNP3PafRegisterPort(sc, (uint16_t) i, policy_id); } } return DNP3_OK; } snort-2.9.6.0/src/dynamic-preprocessors/dnp3/spp_dnp3.h0000644000000000000000000001256212260565732017625 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Dynamic preprocessor for the DNP3 protocol * */ #ifndef SPP_DNP3_H #define SPP_DNP3_H #include "config.h" #include "sf_types.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" /* GIDs, SIDs, Messages */ #define GENERATOR_SPP_DNP3 145 #define DNP3_BAD_CRC 1 #define DNP3_DROPPED_FRAME 2 #define DNP3_DROPPED_SEGMENT 3 #define DNP3_REASSEMBLY_BUFFER_CLEARED 4 #define DNP3_RESERVED_ADDRESS 5 #define DNP3_RESERVED_FUNCTION 6 #define DNP3_BAD_CRC_STR "(spp_dnp3): DNP3 Link-Layer Frame contains bad CRC." #define DNP3_DROPPED_FRAME_STR "(spp_dnp3): DNP3 Link-Layer Frame was dropped." #define DNP3_DROPPED_SEGMENT_STR "(spp_dnp3): DNP3 Transport-Layer Segment was dropped during reassembly." #define DNP3_REASSEMBLY_BUFFER_CLEARED_STR "(spp_dnp3): DNP3 Reassembly Buffer was cleared without reassembling a complete message." #define DNP3_RESERVED_ADDRESS_STR "(spp_dnp3): DNP3 Link-Layer Frame uses a reserved address." #define DNP3_RESERVED_FUNCTION_STR "(spp_dnp3): DNP3 Application-Layer Fragment uses a reserved function code." #define MAX_PORTS 65536 /* Default DNP3 port */ #define DNP3_PORT 20000 /* Memcap limits. */ #define MIN_DNP3_MEMCAP 4144 #define MAX_DNP3_MEMCAP (100 * 1024 * 1024) /* Convert port value into an index for the dnp3_config->ports array */ #define PORT_INDEX(port) port/8 /* Convert port value into a value for bitwise operations */ #define CONV_PORT(port) 1<<(port%8) /* Packet directions */ #define DNP3_CLIENT 0 #define DNP3_SERVER 1 /* Session data flags */ #define DNP3_FUNC_RULE_FIRED 0x0001 #define DNP3_OBJ_RULE_FIRED 0x0002 #define DNP3_IND_RULE_FIRED 0x0004 #define DNP3_DATA_RULE_FIRED 0x0008 /* DNP3 minimum length: start (2 octets) + len (1 octet) */ #define DNP3_MIN_LEN 3 #define DNP3_LEN_OFFSET 2 /* Length of the rest of a DNP3 link-layer header: ctrl + src + dest */ #define DNP3_HEADER_REMAINDER_LEN 5 /* Reassembly data types moved here to avoid circular dependency with dnp3_sesion_data_t */ #define DNP3_BUFFER_SIZE 2048 typedef enum _dnp3_reassembly_state_t { DNP3_REASSEMBLY_STATE__IDLE = 0, DNP3_REASSEMBLY_STATE__ASSEMBLY, DNP3_REASSEMBLY_STATE__DONE } dnp3_reassembly_state_t; typedef struct _dnp3_reassembly_data_t { char buffer[DNP3_BUFFER_SIZE]; uint16_t buflen; dnp3_reassembly_state_t state; uint8_t last_seq; } dnp3_reassembly_data_t; /* DNP3 preprocessor configuration */ typedef struct _dnp3_config { uint32_t memcap; char ports[MAX_PORTS/8]; uint8_t check_crc; int disabled; int ref_count; } dnp3_config_t; /* DNP3 session data */ typedef struct _dnp3_session_data { /* Fields for rule option matching. */ uint8_t direction; uint8_t func; uint8_t obj_group; uint8_t obj_var; uint16_t indications; uint16_t flags; /* Reassembly stuff */ dnp3_reassembly_data_t client_rdata; dnp3_reassembly_data_t server_rdata; tSfPolicyId policy_id; tSfPolicyUserContextId context_id; } dnp3_session_data_t; /* DNP3 header structures */ typedef struct _dnp3_link_header_t { uint16_t start; uint8_t len; uint8_t ctrl; uint16_t dest; uint16_t src; } dnp3_link_header_t; #define DNP3_TRANSPORT_FIN(x) (x & 0x80) #define DNP3_TRANSPORT_FIR(x) (x & 0x40) #define DNP3_TRANSPORT_SEQ(x) (x & 0x3F) #define DNP3_MAX_TRANSPORT_LEN 250 typedef struct _dnp3_transport_header_t { uint8_t control; } dnp3_transport_header_t; /* Yep, the locations of FIR and FIN are switched at this layer... */ #define DNP3_APP_FIR(x) (x & 0x80) #define DNP3_APP_FIN(x) (x & 0x40) #define DNP3_APP_SEQ(x) (x & 0x0F) typedef struct _dnp3_app_request_header_t { uint8_t control; uint8_t function; } dnp3_app_request_header_t; typedef struct _dnp3_app_response_header_t { uint8_t control; uint8_t function; uint16_t indications; } dnp3_app_response_header_t; #define DNP3_CHECK_CRC_KEYWORD "check_crc" #define DNP3_PORTS_KEYWORD "ports" #define DNP3_MEMCAP_KEYWORD "memcap" #define DNP3_DISABLED_KEYWORD "disabled" #define DNP3_OK 1 #define DNP3_FAIL (-1) #ifdef WORDS_BIGENDIAN #define DNP3_MIN_RESERVED_ADDR 0xF0FF #define DNP3_MAX_RESERVED_ADDR 0xFBFF #define DNP3_START_BYTES 0x0564 #else #define DNP3_MIN_RESERVED_ADDR 0xFFF0 #define DNP3_MAX_RESERVED_ADDR 0xFFFB #define DNP3_START_BYTES 0x6405 #endif #define DNP3_START_BYTE_1 0x05 #define DNP3_START_BYTE_2 0x64 #define DNP3_CHUNK_SIZE 16 #define DNP3_CRC_SIZE 2 #endif /* SPP_DNP3_H */ snort-2.9.6.0/src/dynamic-preprocessors/dnp3/spp_dnp3.c0000644000000000000000000006703412260565732017624 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Dynamic preprocessor for the DNP3 protocol * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_plugin_api.h" #include "snort_debug.h" #include "mempool.h" #include "preprocids.h" #include "spp_dnp3.h" #include "sf_preproc_info.h" #include "dnp3_paf.h" #include "dnp3_reassembly.h" #include "dnp3_roptions.h" #include "profiler.h" #ifdef PERF_PROFILING PreprocStats dnp3PerfStats; #endif const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_DNP3"; #define SetupDNP3 DYNAMIC_PREPROC_SETUP /* Preprocessor config objects */ static tSfPolicyUserContextId dnp3_context_id = NULL; static dnp3_config_t *dnp3_eval_config = NULL; static MemPool *dnp3_mempool = NULL; /* Target-based app ID */ #ifdef TARGET_BASED int16_t dnp3_app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif /* Prototypes */ static void DNP3Init(struct _SnortConfig *, char *); static inline void DNP3OneTimeInit(struct _SnortConfig *); static inline dnp3_config_t * DNP3PerPolicyInit(struct _SnortConfig *, tSfPolicyUserContextId); static void DNP3RegisterPerPolicyCallbacks(struct _SnortConfig *, dnp3_config_t *); static void ProcessDNP3(void *, void *); #ifdef SNORT_RELOAD static void DNP3Reload(struct _SnortConfig *, char *, void **); static int DNP3ReloadVerify(struct _SnortConfig *, void *); static void * DNP3ReloadSwap(struct _SnortConfig *, void *); static void DNP3ReloadSwapFree(void *); #endif static void _addPortsToStream5Filter(struct _SnortConfig *, dnp3_config_t *, tSfPolicyId); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static void DNP3FreeConfig(tSfPolicyUserContextId context_id); static void FreeDNP3Data(void *); static int DNP3CheckConfig(struct _SnortConfig *); static void DNP3CleanExit(int, void *); static void ParseDNP3Args(struct _SnortConfig *, dnp3_config_t *, char *); static void PrintDNP3Config(dnp3_config_t *config); static int DNP3PortCheck(dnp3_config_t *config, SFSnortPacket *packet); static MemBucket * DNP3CreateSessionData(SFSnortPacket *); /* Default memcap is defined as MAX_TCP_SESSIONS * .05 * 20 bytes */ #define DNP3_DEFAULT_MEMCAP (256 * 1024) /* Register init callback */ void SetupDNP3(void) { #ifndef SNORT_RELOAD _dpd.registerPreproc("dnp3", DNP3Init); #else _dpd.registerPreproc("dnp3", DNP3Init, DNP3Reload, DNP3ReloadVerify, DNP3ReloadSwap, DNP3ReloadSwapFree); #endif } /* Allocate memory for preprocessor config, parse the args, set up callbacks */ static void DNP3Init(struct _SnortConfig *sc, char *argp) { dnp3_config_t *dnp3_policy = NULL; if (dnp3_context_id == NULL) DNP3OneTimeInit(sc); dnp3_policy = DNP3PerPolicyInit(sc, dnp3_context_id); ParseDNP3Args(sc, dnp3_policy, argp); PrintDNP3Config(dnp3_policy); DNP3RegisterPerPolicyCallbacks(sc, dnp3_policy); } static inline void DNP3OneTimeInit(struct _SnortConfig *sc) { /* context creation & error checking */ dnp3_context_id = sfPolicyConfigCreate(); if (dnp3_context_id == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory for " "DNP3 config.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupDNP3(): The Stream preprocessor " "must be enabled.\n"); } /* callback registration */ _dpd.addPreprocConfCheck(sc, DNP3CheckConfig); _dpd.addPreprocExit(DNP3CleanExit, NULL, PRIORITY_LAST, PP_DNP3); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("dnp3", (void *)&dnp3PerfStats, 0, _dpd.totalPerfStats); #endif /* Set up target-based app id */ #ifdef TARGET_BASED dnp3_app_id = _dpd.findProtocolReference("dnp3"); if (dnp3_app_id == SFTARGET_UNKNOWN_PROTOCOL) dnp3_app_id = _dpd.addProtocolReference("dnp3"); #endif } /* Responsible for allocating a DNP3 policy. Never returns NULL. */ static inline dnp3_config_t * DNP3PerPolicyInit(struct _SnortConfig *sc, tSfPolicyUserContextId context_id) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); dnp3_config_t *dnp3_policy = NULL; /* Check for existing policy & bail if found */ sfPolicyUserPolicySet(context_id, policy_id); dnp3_policy = (dnp3_config_t *)sfPolicyUserDataGetCurrent(context_id); if (dnp3_policy != NULL) { DynamicPreprocessorFatalMessage("%s(%d): DNP3 preprocessor can only be " "configured once.\n", *_dpd.config_file, *_dpd.config_line); } /* Allocate new policy */ dnp3_policy = (dnp3_config_t *)calloc(1, sizeof(dnp3_config_t)); if (!dnp3_policy) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "dnp3 preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(context_id, dnp3_policy); return dnp3_policy; } static void DNP3RegisterPerPolicyCallbacks(struct _SnortConfig *sc, dnp3_config_t *dnp3_policy) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); /* Callbacks should be avoided if the preproc is disabled. */ if (dnp3_policy->disabled) return; _dpd.addPreproc(sc, ProcessDNP3, PRIORITY_APPLICATION, PP_DNP3, PROTO_BIT__TCP|PROTO_BIT__UDP); _addPortsToStream5Filter(sc, dnp3_policy, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); DNP3AddServiceToPaf(sc, dnp3_app_id, policy_id); #endif DNP3AddPortsToPaf(sc, dnp3_policy, policy_id); _dpd.preprocOptRegister(sc, DNP3_FUNC_NAME, DNP3FuncInit, DNP3FuncEval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, DNP3_OBJ_NAME, DNP3ObjInit, DNP3ObjEval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, DNP3_IND_NAME, DNP3IndInit, DNP3IndEval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, DNP3_DATA_NAME, DNP3DataInit, DNP3DataEval, free, NULL, NULL, NULL, NULL); } static void ParseSinglePort(dnp3_config_t *config, char *token) { /* single port number */ char *endptr; unsigned long portnum = _dpd.SnortStrtoul(token, &endptr, 10); if ((*endptr != '\0') || (portnum >= MAX_PORTS)) { DynamicPreprocessorFatalMessage("%s(%d): Bad dnp3 port number: %s\n" "Port number must be an integer between 0 and 65535.\n", *_dpd.config_file, *_dpd.config_line, token); } /* Good port number! */ config->ports[PORT_INDEX(portnum)] |= CONV_PORT(portnum); } static void ParseDNP3Args(struct _SnortConfig *sc, dnp3_config_t *config, char *args) { char *saveptr; char *token; /* Set defaults */ config->memcap = DNP3_DEFAULT_MEMCAP; config->ports[PORT_INDEX(DNP3_PORT)] |= CONV_PORT(DNP3_PORT); config->check_crc = 0; /* No arguments? Stick with defaults. */ if (args == NULL) return; token = strtok_r(args, " ,", &saveptr); while (token != NULL) { if (strcmp(token, DNP3_PORTS_KEYWORD) == 0) { unsigned nPorts = 0; /* Un-set the default port */ config->ports[PORT_INDEX(DNP3_PORT)] = 0; /* Parse ports */ token = strtok_r(NULL, " ,", &saveptr); if (token == NULL) { DynamicPreprocessorFatalMessage("%s(%d): Missing argument for " "DNP3 preprocessor 'ports' option.\n", *_dpd.config_file, *_dpd.config_line); } if (isdigit(token[0])) { ParseSinglePort(config, token); nPorts++; } else if (*token == '{') { /* list of ports */ token = strtok_r(NULL, " ,", &saveptr); while (token != NULL && *token != '}') { ParseSinglePort(config, token); nPorts++; token = strtok_r(NULL, " ,", &saveptr); } } else { nPorts = 0; } if ( nPorts == 0 ) { DynamicPreprocessorFatalMessage("%s(%d): Bad DNP3 'ports' argument: '%s'\n" "Argument to DNP3 'ports' must be an integer, or a list " "enclosed in { } braces.\n", *_dpd.config_file, *_dpd.config_line, token); } } else if (strcmp(token, DNP3_MEMCAP_KEYWORD) == 0) { uint32_t memcap; char *endptr; /* Parse memcap */ token = strtok_r(NULL, " ", &saveptr); /* In a multiple policy scenario, the memcap from the default policy overrides the memcap in any targeted policies. */ if (_dpd.getParserPolicy(sc) != _dpd.getDefaultPolicy()) { dnp3_config_t *default_config = (dnp3_config_t *)sfPolicyUserDataGet(dnp3_context_id, _dpd.getDefaultPolicy()); if (!default_config || default_config->memcap == 0) { DynamicPreprocessorFatalMessage("%s(%d): DNP3 'memcap' must be " "configured in the default config.\n", *_dpd.config_file, *_dpd.config_line); } config->memcap = default_config->memcap; } else { if (token == NULL) { DynamicPreprocessorFatalMessage("%s(%d): Missing argument for DNP3 " "preprocessor 'memcap' option.\n", *_dpd.config_file, *_dpd.config_line); } memcap = _dpd.SnortStrtoul(token, &endptr, 10); if ((token[0] == '-') || (*endptr != '\0') || (memcap < MIN_DNP3_MEMCAP) || (memcap > MAX_DNP3_MEMCAP)) { DynamicPreprocessorFatalMessage("%s(%d): Bad DNP3 'memcap' argument: %s\n" "Argument to DNP3 'memcap' must be an integer between " "%d and %d.\n", *_dpd.config_file, *_dpd.config_line, token, MIN_DNP3_MEMCAP, MAX_DNP3_MEMCAP); } config->memcap = memcap; } } else if (strcmp(token, DNP3_CHECK_CRC_KEYWORD) == 0) { /* Parse check_crc */ config->check_crc = 1; } else if (strcmp(token, DNP3_DISABLED_KEYWORD) == 0) { /* TODO: if disabled, check that no other stuff is turned on except memcap */ config->disabled = 1; } else { DynamicPreprocessorFatalMessage("%s(%d): Failed to parse dnp3 argument: " "%s\n", *_dpd.config_file, *_dpd.config_line, token); } token = strtok_r(NULL, " ,", &saveptr); } } /* Print a DNP3 config */ static void PrintDNP3Config(dnp3_config_t *config) { int index, newline = 1; if (config == NULL) return; _dpd.logMsg("DNP3 config: \n"); if (config->disabled) _dpd.logMsg(" DNP3: INACTIVE\n"); _dpd.logMsg(" Memcap: %d\n", config->memcap); _dpd.logMsg(" Check Link-Layer CRCs: %s\n", config->check_crc ? "ENABLED":"DISABLED"); _dpd.logMsg(" Ports:\n"); /* Loop through port array & print, 5 ports per line */ for (index = 0; index < MAX_PORTS; index++) { if (config->ports[PORT_INDEX(index)] & CONV_PORT(index)) { _dpd.logMsg("\t%d", index); if ( !((newline++) % 5) ) { _dpd.logMsg("\n"); } } } _dpd.logMsg("\n"); } static int DNP3ProcessUDP(dnp3_config_t *dnp3_eval_config, dnp3_session_data_t *sessp, SFSnortPacket *packetp) { /* Possibly multiple PDUs in this UDP payload. Split up and process individually. */ uint16_t bytes_processed = 0; int truncated_pdu = 0; while (bytes_processed < packetp->payload_size) { uint8_t *pdu_start; uint16_t user_data, num_crcs, pdu_length; dnp3_link_header_t *link; pdu_start = (uint8_t *)(packetp->payload + bytes_processed); link = (dnp3_link_header_t *)pdu_start; /* Alert and stop if (a) there's not enough data to read a length, or (b) the start bytes are not 0x0564 */ if ((packetp->payload_size - bytes_processed < (int)sizeof(dnp3_link_header_t)) || (link->start != DNP3_START_BYTES) || (link->len < DNP3_HEADER_REMAINDER_LEN)) { truncated_pdu = 1; break; } /* Calculate the actual length of data to inspect */ user_data = link->len - DNP3_HEADER_REMAINDER_LEN; num_crcs = 1 + (user_data/DNP3_CHUNK_SIZE) + (user_data % DNP3_CHUNK_SIZE? 1 : 0); pdu_length = DNP3_MIN_LEN + link->len + (DNP3_CRC_SIZE*num_crcs); if (bytes_processed + pdu_length > packetp->payload_size) { truncated_pdu = 1; break; } DNP3FullReassembly(dnp3_eval_config, sessp, packetp, pdu_start, pdu_length); bytes_processed += pdu_length; } if (truncated_pdu) { _dpd.alertAdd(GENERATOR_SPP_DNP3, DNP3_DROPPED_FRAME, 1, 0, 3, DNP3_DROPPED_FRAME_STR, 0); } /* All detection was done when DNP3FullReassembly() called Detect() on the reassembled PDUs. Clear the flag to avoid double alerts on the last PDU. */ _dpd.DetectReset((uint8_t *)packetp->payload, packetp->payload_size); return DNP3_OK; } /* Main runtime entry point */ static void ProcessDNP3(void *ipacketp, void *contextp) { SFSnortPacket *packetp = (SFSnortPacket *)ipacketp; MemBucket *tmp_bucket = NULL; dnp3_session_data_t *sessp = NULL; PROFILE_VARS; // preconditions - what we registered for assert((IsUDP(packetp) || IsTCP(packetp)) && packetp->payload && packetp->payload_size); /* If TCP, require that PAF flushes full PDUs first. */ if (packetp->tcp_header && !PacketHasFullPDU(packetp)) return; PREPROC_PROFILE_START(dnp3PerfStats); /* When pipelined DNP3 PDUs appear in a single TCP segment or UDP packet, the detection engine caches the results of the rule options after evaluating on the first PDU. Setting this flag stops the caching. */ packetp->flags |= FLAG_ALLOW_MULTIPLE_DETECT; /* Fetch me a preprocessor config to use with this VLAN/subnet/etc.! */ dnp3_eval_config = sfPolicyUserDataGetCurrent(dnp3_context_id); /* Look for a previously-allocated session data. */ tmp_bucket = _dpd.streamAPI->get_application_data(packetp->stream_session_ptr, PP_DNP3); if (tmp_bucket == NULL) { /* No existing session. Check those ports. */ if (DNP3PortCheck(dnp3_eval_config, packetp) != DNP3_OK) { PREPROC_PROFILE_END(dnp3PerfStats); return; } /* Create session data and attach it to the Stream5 session */ tmp_bucket = DNP3CreateSessionData(packetp); if (tmp_bucket == NULL) { PREPROC_PROFILE_END(dnp3PerfStats); return; } } sessp = (dnp3_session_data_t *) tmp_bucket->data; /* Set reassembly direction */ if (packetp->flags & FLAG_FROM_CLIENT) sessp->direction = DNP3_CLIENT; else sessp->direction = DNP3_SERVER; /* Do preprocessor-specific detection stuff here */ if (packetp->tcp_header) { /* Single PDU. PAF already split them up into separate pseudo-packets. */ DNP3FullReassembly(dnp3_eval_config, sessp, packetp, (uint8_t *)packetp->payload, packetp->payload_size); } else if (packetp->udp_header) { DNP3ProcessUDP(dnp3_eval_config, sessp, packetp); } /* That's the end! */ PREPROC_PROFILE_END(dnp3PerfStats); } /* Check ports & services */ static int DNP3PortCheck(dnp3_config_t *config, SFSnortPacket *packet) { #ifdef TARGET_BASED int16_t app_id = _dpd.streamAPI->get_application_protocol_id(packet->stream_session_ptr); /* call to get_application_protocol_id gave an error */ if (app_id == SFTARGET_UNKNOWN_PROTOCOL) return DNP3_FAIL; /* this is positively identified as something non-dnp3 */ if (app_id && (app_id != dnp3_app_id)) return DNP3_FAIL; /* this is identified as dnp3 */ if (app_id == dnp3_app_id) return DNP3_OK; /* fall back to port check */ #endif if (config->ports[PORT_INDEX(packet->src_port)] & CONV_PORT(packet->src_port)) return DNP3_OK; if (config->ports[PORT_INDEX(packet->dst_port)] & CONV_PORT(packet->dst_port)) return DNP3_OK; return DNP3_FAIL; } static MemBucket * DNP3CreateSessionData(SFSnortPacket *packet) { MemBucket *tmp_bucket = NULL; dnp3_session_data_t *data = NULL; /* Sanity Check */ if (!packet || !packet->stream_session_ptr) return NULL; /* data = (dnp3_session_data_t *)calloc(1, sizeof(dnp3_session_data_t)); */ tmp_bucket = mempool_alloc(dnp3_mempool); if (!tmp_bucket) { /* Mempool was full, don't process this session. */ static unsigned int times_mempool_alloc_failed = 0; /* Print a message, but only every 1000 times. Don't want to flood the log if there's a lot of DNP3 traffic. */ if (times_mempool_alloc_failed % 1000 == 0) { _dpd.logMsg("WARNING: DNP3 memcap exceeded.\n"); } times_mempool_alloc_failed++; return NULL; } data = (dnp3_session_data_t *)tmp_bucket->data; if (!data) return NULL; /* Attach to Stream5 session */ _dpd.streamAPI->set_application_data(packet->stream_session_ptr, PP_DNP3, tmp_bucket, FreeDNP3Data); /* Not sure when this reference counting stuff got added to the old preprocs */ data->policy_id = _dpd.getRuntimePolicy(); data->context_id = dnp3_context_id; ((dnp3_config_t *)sfPolicyUserDataGetCurrent(dnp3_context_id))->ref_count++; return tmp_bucket; } /* Reload functions */ #ifdef SNORT_RELOAD /* Almost like DNP3Init, but not quite. */ static void DNP3Reload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId dnp3_swap_context_id = (tSfPolicyUserContextId)*new_config; dnp3_config_t *dnp3_policy = NULL; if (dnp3_swap_context_id == NULL) { dnp3_swap_context_id = sfPolicyConfigCreate(); if (dnp3_swap_context_id == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for DNP3 config.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupDNP3(): The Stream preprocessor " "must be enabled.\n"); } *new_config = (void *)dnp3_swap_context_id; } dnp3_policy = DNP3PerPolicyInit(sc, dnp3_swap_context_id); ParseDNP3Args(sc, dnp3_policy, args); PrintDNP3Config(dnp3_policy); DNP3RegisterPerPolicyCallbacks(sc, dnp3_policy); } /* Check that Stream5 is still running, and that the memcap didn't change. */ static int DNP3ReloadVerify(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId dnp3_swap_context_id = (tSfPolicyUserContextId)swap_config; dnp3_config_t *current_default_config, *new_default_config; if ((dnp3_context_id == NULL) || (dnp3_swap_context_id == NULL)) return 0; current_default_config = (dnp3_config_t *)sfPolicyUserDataGet(dnp3_context_id, _dpd.getDefaultPolicy()); new_default_config = (dnp3_config_t *)sfPolicyUserDataGet(dnp3_swap_context_id, _dpd.getDefaultPolicy()); /* Sanity check. Shouldn't be possible. */ if (current_default_config == NULL) return 0; if (new_default_config == NULL) { _dpd.errMsg("DNP3 reload: Changing the DNP3 configuration " "requires a restart.\n"); return -1; } /* Did memcap change? */ if (current_default_config->memcap != new_default_config->memcap) { _dpd.errMsg("DNP3 reload: Changing the DNP3 memcap " "requires a restart.\n"); return -1; } /* Did stream5 get turned off? */ if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SetupDNP3(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } static int DNP3FreeUnusedConfigPolicy( tSfPolicyUserContextId context_id, tSfPolicyId policy_id, void *data ) { dnp3_config_t *dnp3_config = (dnp3_config_t *)data; /* do any housekeeping before freeing dnp3 config */ if (dnp3_config->ref_count == 0) { sfPolicyUserDataClear(context_id, policy_id); free(dnp3_config); } return 0; } static void * DNP3ReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId dnp3_swap_context_id = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_context_id = dnp3_context_id; if (dnp3_swap_context_id == NULL) return NULL; dnp3_context_id = dnp3_swap_context_id; sfPolicyUserDataFreeIterate(old_context_id, DNP3FreeUnusedConfigPolicy); if (sfPolicyUserPolicyGetActive(old_context_id) == 0) { /* No more outstanding configs - free the config array */ return (void *)old_context_id; } return NULL; } static void DNP3ReloadSwapFree(void *data) { if (data == NULL) return; DNP3FreeConfig( (tSfPolicyUserContextId)data ); } #endif /* Stream5 filter functions */ static void _addPortsToStream5Filter(struct _SnortConfig *sc, dnp3_config_t *config, tSfPolicyId policy_id) { if (config == NULL) return; if (_dpd.streamAPI) { int portNum; for (portNum = 0; portNum < MAX_PORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status( sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); _dpd.streamAPI->set_port_filter_status( sc, IPPROTO_UDP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); } } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status(sc, dnp3_app_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif static int DNP3FreeConfigPolicy( tSfPolicyUserContextId context_id, tSfPolicyId policy_id, void *data ) { dnp3_config_t *dnp3_config = (dnp3_config_t *)data; /* do any housekeeping before freeing dnp3_config */ sfPolicyUserDataClear(context_id, policy_id); free(dnp3_config); return 0; } static void DNP3FreeConfig(tSfPolicyUserContextId context_id) { if (context_id == NULL) return; sfPolicyUserDataFreeIterate(context_id, DNP3FreeConfigPolicy); sfPolicyConfigDelete(context_id); } static int DNP3IsEnabled(struct _SnortConfig *sc, tSfPolicyUserContextId context_id, tSfPolicyId policy_id, void *data) { dnp3_config_t *config = (dnp3_config_t *)data; if ((data == NULL) || config->disabled) return 0; return 1; } /* Check an individual policy */ static int DNP3CheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId context_id, tSfPolicyId policy_id, void *data ) { dnp3_config_t *config = (dnp3_config_t *)data; _dpd.setParserPolicy(sc, policy_id); /* In a multiple-policy setting, the preprocessor can be turned on in a "disabled" state. In this case, we don't require Stream5. */ if (config->disabled) return 0; /* Otherwise, require Stream5. */ if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("ERROR: DNP3CheckPolicyConfig(): " "The Stream preprocessor must be enabled.\n"); return -1; } return 0; } /* Check configs & set up mempool. Mempool stuff is in this function because we want to parse & check *ALL* of the configs before allocating a mempool. */ static int DNP3CheckConfig(struct _SnortConfig *sc) { int rval; unsigned int max_sessions; /* Get default configuration */ dnp3_config_t *default_config = (dnp3_config_t *)sfPolicyUserDataGetDefault(dnp3_context_id); if ( !default_config ) { _dpd.errMsg( "ERROR: preprocessor dnp3 must be configured in the default policy.\n"); return -1; } /* Check all individual configurations */ if ((rval = sfPolicyUserDataIterate(sc, dnp3_context_id, DNP3CheckPolicyConfig))) return rval; /* Set up MemPool, but only if a config exists that's not "disabled". */ if (sfPolicyUserDataIterate(sc, dnp3_context_id, DNP3IsEnabled) == 0) return 0; // FIXTHIS default_config is null when configured in target policy only max_sessions = default_config->memcap / sizeof(dnp3_session_data_t); dnp3_mempool = (MemPool *)calloc(1, sizeof(MemPool)); if (mempool_init(dnp3_mempool, max_sessions, sizeof(dnp3_session_data_t)) != 0) { DynamicPreprocessorFatalMessage("Unable to allocate DNP3 mempool.\n"); } return 0; } static void DNP3CleanExit(int signal, void *data) { if (dnp3_context_id != NULL) { DNP3FreeConfig(dnp3_context_id); dnp3_context_id = NULL; } if ((dnp3_mempool) && (mempool_destroy(dnp3_mempool) == 0)) { free(dnp3_mempool); dnp3_mempool = 0; } } static void FreeDNP3Data(void *bucket) { MemBucket *tmp_bucket = (MemBucket *)bucket; dnp3_session_data_t *session; dnp3_config_t *config = NULL; if ((tmp_bucket == NULL) || (tmp_bucket->data == NULL)) return; session = tmp_bucket->data; if (session->context_id != NULL) { config = (dnp3_config_t *)sfPolicyUserDataGet(session->context_id, session->policy_id); } if (config != NULL) { config->ref_count--; if ((config->ref_count == 0) && (session->context_id != dnp3_context_id)) { sfPolicyUserDataClear(session->context_id, session->policy_id); free(config); if (sfPolicyUserPolicyGetActive(session->context_id) == 0) { /* No more outstanding configs - free the config array */ DNP3FreeConfig(session->context_id); } } } mempool_free(dnp3_mempool, tmp_bucket); } snort-2.9.6.0/src/dynamic-preprocessors/dnp3/Makefile.am0000644000000000000000000000144411746560364017763 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_dnp3_preproc.la libsf_dnp3_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_dnp3_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_dnp3_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sfPolicyUserData.c \ ../include/mempool.c \ ../include/sf_sdlist.c endif libsf_dnp3_preproc_la_SOURCES = \ spp_dnp3.c \ spp_dnp3.h \ dnp3_paf.c \ dnp3_paf.h \ dnp3_reassembly.c \ dnp3_reassembly.h \ dnp3_roptions.c \ dnp3_roptions.h \ dnp3_map.c \ dnp3_map.h EXTRA_DIST = \ sf_dnp3.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/dnp3/Makefile.in0000644000000000000000000005237412260606521017770 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/dnp3 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_dnp3_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_dnp3_preproc_la_OBJECTS = spp_dnp3.lo dnp3_paf.lo \ dnp3_reassembly.lo dnp3_roptions.lo dnp3_map.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_dnp3_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo mempool.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_sdlist.lo libsf_dnp3_preproc_la_OBJECTS = $(am_libsf_dnp3_preproc_la_OBJECTS) \ $(nodist_libsf_dnp3_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_dnp3_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_dnp3_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_dnp3_preproc_la_SOURCES) \ $(nodist_libsf_dnp3_preproc_la_SOURCES) DIST_SOURCES = $(libsf_dnp3_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_dnp3_preproc.la libsf_dnp3_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_dnp3_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_dnp3_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c \ @SO_WITH_STATIC_LIB_FALSE@../include/mempool.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_sdlist.c libsf_dnp3_preproc_la_SOURCES = \ spp_dnp3.c \ spp_dnp3.h \ dnp3_paf.c \ dnp3_paf.h \ dnp3_reassembly.c \ dnp3_reassembly.h \ dnp3_roptions.c \ dnp3_roptions.h \ dnp3_map.c \ dnp3_map.h EXTRA_DIST = \ sf_dnp3.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/dnp3/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/dnp3/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_dnp3_preproc.la: $(libsf_dnp3_preproc_la_OBJECTS) $(libsf_dnp3_preproc_la_DEPENDENCIES) $(EXTRA_libsf_dnp3_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_dnp3_preproc_la_LINK) -rpath $(libdir) $(libsf_dnp3_preproc_la_OBJECTS) $(libsf_dnp3_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mempool.lo: ../include/mempool.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mempool.lo `test -f '../include/mempool.c' || echo '$(srcdir)/'`../include/mempool.c sf_sdlist.lo: ../include/sf_sdlist.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_sdlist.lo `test -f '../include/sf_sdlist.c' || echo '$(srcdir)/'`../include/sf_sdlist.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/modbus/0000755000000000000000000000000012260606565016425 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/modbus/sf_modbus.dsp0000644000000000000000000001255412153454770021045 00000000000000# Microsoft Developer Studio Project File - Name="sf_modbus" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_modbus - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_modbus.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_modbus.mak" CFG="sf_modbus - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_modbus - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_modbus - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_modbus - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "SF_SNORT_PREPROC_DLL" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_modbus - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "SF_SNORT_PREPROC_DLL" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_modbus - Win32 Release" # Name "sf_modbus - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\modbus_decode.c # End Source File # Begin Source File SOURCE=.\modbus_paf.c # End Source File # Begin Source File SOURCE=.\modbus_roptions.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\spp_modbus.c # End Source File # Begin Source File SOURCE=..\include\strtok_r.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\modbus_decode.h # End Source File # Begin Source File SOURCE=.\modbus_paf.h # End Source File # Begin Source File SOURCE=.\modbus_roptions.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\spp_modbus.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/modbus/modbus_paf.h0000644000000000000000000000362312260565732020641 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Protocol-Aware Flushing (PAF) code for the Modbus preprocessor. * */ #ifndef MODBUS_PAF__H #define MODBUS_PAF__H #include "spp_modbus.h" #include "stream_api.h" typedef enum _modbus_paf_state { MODBUS_PAF_STATE__TRANS_ID_1 = 0, MODBUS_PAF_STATE__TRANS_ID_2, MODBUS_PAF_STATE__PROTO_ID_1, MODBUS_PAF_STATE__PROTO_ID_2, MODBUS_PAF_STATE__LENGTH_1, MODBUS_PAF_STATE__LENGTH_2, MODBUS_PAF_STATE__SET_FLUSH } modbus_paf_state_t; typedef struct _modbus_paf_data { modbus_paf_state_t state; uint16_t modbus_length; } modbus_paf_data_t; void ModbusAddPortsToPaf(struct _SnortConfig *sc, modbus_config_t *config, tSfPolicyId policy_id); int ModbusPafRegisterPort(struct _SnortConfig *sc, uint16_t port, tSfPolicyId policy_id); int ModbusAddServiceToPaf(struct _SnortConfig *sc, uint16_t service, tSfPolicyId policy_id); PAF_Status ModbusPaf(void *ssn, void **user, const uint8_t *data, uint32_t len, uint32_t flags, uint32_t *fp); #endif /* MODBUS_PAF__H */ snort-2.9.6.0/src/dynamic-preprocessors/modbus/modbus_paf.c0000644000000000000000000001155612260565732020640 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Protocol-Aware Flushing (PAF) code for the Modbus preprocessor. * */ #include "spp_modbus.h" #include "modbus_decode.h" #include "modbus_paf.h" #include "sf_dynamic_preprocessor.h" /* Defines */ #define MODBUS_MIN_HDR_LEN 2 /* Enough for Unit ID + Function */ #define MODBUS_MAX_HDR_LEN 254 /* Max PDU size is 260, 6 bytes already seen */ int ModbusPafRegisterPort (struct _SnortConfig *sc, uint16_t port, tSfPolicyId policy_id) { if (!_dpd.isPafEnabled()) return 0; _dpd.streamAPI->register_paf_port(sc, policy_id, port, 0, ModbusPaf, true); _dpd.streamAPI->register_paf_port(sc, policy_id, port, 1, ModbusPaf, true); return 0; } #ifdef TARGET_BASED int ModbusAddServiceToPaf (struct _SnortConfig *sc, uint16_t service, tSfPolicyId policy_id) { if (!_dpd.isPafEnabled()) return 0; _dpd.streamAPI->register_paf_service(sc, policy_id, service, 0, ModbusPaf, true); _dpd.streamAPI->register_paf_service(sc, policy_id, service, 1, ModbusPaf, true); return 0; } #endif /* Function: ModbusPaf() Purpose: Modbus/TCP PAF callback. Statefully inspects Modbus traffic from the start of a session, Reads up until the length octet is found, then sets a flush point. Arguments: void * - stream5 session pointer void ** - Modbus state tracking structure const uint8_t * - payload data to inspect uint32_t - length of payload data uint32_t - flags to check whether client or server uint32_t * - pointer to set flush point Returns: PAF_Status - PAF_FLUSH if flush point found, PAF_SEARCH otherwise */ PAF_Status ModbusPaf(void *ssn, void **user, const uint8_t *data, uint32_t len, uint32_t flags, uint32_t *fp) { modbus_paf_data_t *pafdata = *(modbus_paf_data_t **)user; uint32_t bytes_processed = 0; /* Allocate state object if it doesn't exist yet. */ if (pafdata == NULL) { pafdata = calloc(1, sizeof(modbus_paf_data_t)); if (pafdata == NULL) return PAF_ABORT; *user = pafdata; } /* Process this packet 1 byte at a time */ while (bytes_processed < len) { switch (pafdata->state) { /* Skip the Transaction & Protocol IDs */ case MODBUS_PAF_STATE__TRANS_ID_1: case MODBUS_PAF_STATE__TRANS_ID_2: case MODBUS_PAF_STATE__PROTO_ID_1: case MODBUS_PAF_STATE__PROTO_ID_2: pafdata->state++; break; /* Read length 1 byte at a time, in case a TCP segment is sent * with only 5 bytes from the MBAP header */ case MODBUS_PAF_STATE__LENGTH_1: pafdata->modbus_length |= ( *(data + bytes_processed) << 8 ); pafdata->state++; break; case MODBUS_PAF_STATE__LENGTH_2: pafdata->modbus_length |= *(data + bytes_processed); pafdata->state++; break; case MODBUS_PAF_STATE__SET_FLUSH: if ((pafdata->modbus_length < MODBUS_MIN_HDR_LEN) || (pafdata->modbus_length > MODBUS_MAX_HDR_LEN)) { _dpd.alertAdd(GENERATOR_SPP_MODBUS, MODBUS_BAD_LENGTH, 1, 0, 3, MODBUS_BAD_LENGTH_STR, 0); } *fp = pafdata->modbus_length + bytes_processed; pafdata->state = MODBUS_PAF_STATE__TRANS_ID_1; pafdata->modbus_length = 0; return PAF_FLUSH; } bytes_processed++; } return PAF_SEARCH; } /* Take a Modbus config + Snort policy, iterate through ports, register PAF callback */ void ModbusAddPortsToPaf(struct _SnortConfig *sc, modbus_config_t *config, tSfPolicyId policy_id) { unsigned int i; for (i = 0; i < MAX_PORTS; i++) { if (config->ports[PORT_INDEX(i)] & CONV_PORT(i)) { ModbusPafRegisterPort(sc, (uint16_t) i, policy_id); } } } snort-2.9.6.0/src/dynamic-preprocessors/modbus/modbus_roptions.h0000644000000000000000000000350412260565732021746 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Rule options for Modbus preprocessor. * */ #ifndef MODBUS_ROPTIONS_H #define MODBUS_ROPTIONS_H #include #define MODBUS_FUNC_NAME "modbus_func" #define MODBUS_UNIT_NAME "modbus_unit" #define MODBUS_DATA_NAME "modbus_data" /* Data types */ typedef enum _modbus_option_type_t { MODBUS_FUNC = 0, MODBUS_UNIT, MODBUS_DATA } modbus_option_type_t; typedef struct _modbus_option_data_t { modbus_option_type_t type; uint16_t arg; } modbus_option_data_t; typedef struct _modbus_func_map_t { char *name; uint8_t func; } modbus_func_map_t; int ModbusFuncInit(struct _SnortConfig *sc, char *name, char *params, void **data); int ModbusUnitInit(struct _SnortConfig *sc, char *name, char *params, void **data); int ModbusDataInit(struct _SnortConfig *sc, char *name, char *params, void **data); int ModbusRuleEval(void *raw_packet, const uint8_t **cursor, void *data); #endif /* MODBUS_ROPTIONS_H */ snort-2.9.6.0/src/dynamic-preprocessors/modbus/modbus_roptions.c0000644000000000000000000001702712260565732021746 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Rule options for Modbus preprocessor * */ #include #include "sf_types.h" #include "sf_snort_plugin_api.h" #include "sf_dynamic_preprocessor.h" #include "spp_modbus.h" #include "modbus_decode.h" #include "modbus_roptions.h" /* Mapping of name -> function code for 'modbus_func' option. */ static modbus_func_map_t func_map[] = { {"read_coils", 1}, {"read_discrete_inputs", 2}, {"read_holding_registers", 3}, {"read_input_registers", 4}, {"write_single_coil", 5}, {"write_single_register", 6}, {"read_exception_status", 7}, {"diagnostics", 8}, {"get_comm_event_counter", 11}, {"get_comm_event_log", 12}, {"write_multiple_coils", 15}, {"write_multiple_registers", 16}, {"report_slave_id", 17}, {"read_file_record", 20}, {"write_file_record", 21}, {"mask_write_register", 22}, {"read_write_multiple_registers", 23}, {"read_fifo_queue", 24}, {"encapsulated_interface_transport", 43} }; int ModbusFuncInit(struct _SnortConfig *sc, char *name, char *params, void **data) { char *endptr; modbus_option_data_t *modbus_data; unsigned int func_code = 0; if (name == NULL || data == NULL) return 0; if (strcmp(name, MODBUS_FUNC_NAME) != 0) return 0; if (params == NULL) { DynamicPreprocessorFatalMessage("%s(%d): No argument given for modbus_func. " "modbus_func requires a number between 0 and 255, or a valid function " "name.\n", *_dpd.config_file, *_dpd.config_line); } modbus_data = (modbus_option_data_t *)calloc(1, sizeof(modbus_option_data_t)); if (modbus_data == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Failed to allocate memory for " "modbus_func data structure.\n", __FILE__, __LINE__); } /* Parsing time */ if (isdigit(params[0])) { /* Function code given as integer */ func_code = _dpd.SnortStrtoul(params, &endptr, 10); if ((func_code > 255) || (*endptr != '\0')) { DynamicPreprocessorFatalMessage("%s(%d): modbus_func requires a " "number between 0 and 255, or a valid function name.\n", *_dpd.config_file, *_dpd.config_line); } } else { /* Check the argument against the map in modbus_roptions.h */ size_t i; int parse_success = 0; for (i = 0; i < (sizeof(func_map) / sizeof(modbus_func_map_t)); i++) { if (strcmp(params, func_map[i].name) == 0) { parse_success = 1; func_code = func_map[i].func; break; } } if (!parse_success) { DynamicPreprocessorFatalMessage("%s(%d): modbus_func requires a " "number between 0 and 255, or a valid function name.\n", *_dpd.config_file, *_dpd.config_line); } } modbus_data->type = MODBUS_FUNC; modbus_data->arg = (uint8_t) func_code; *data = (void *)modbus_data; return 1; } int ModbusUnitInit(struct _SnortConfig *sc, char *name, char *params, void **data) { char *endptr; modbus_option_data_t *modbus_data; unsigned int unit_code; if (name == NULL || data == NULL) return 0; if (strcmp(name, MODBUS_UNIT_NAME) != 0) return 0; if (params == NULL) { DynamicPreprocessorFatalMessage("%s(%d): No argument given for modbus_unit. " "modbus_unit requires a number between 0 and 255.\n", *_dpd.config_file, *_dpd.config_line); } modbus_data = (modbus_option_data_t *)calloc(1, sizeof(modbus_option_data_t)); if (modbus_data == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Failed to allocate memory for " "modbus_unit data structure.\n", __FILE__, __LINE__); } /* Parsing time */ unit_code = _dpd.SnortStrtoul(params, &endptr, 10); if ((unit_code > 255) || (*endptr != '\0')) { DynamicPreprocessorFatalMessage("%s(%d): modbus_unit requires a " "number between 0 and 255.\n", *_dpd.config_file, *_dpd.config_line); } modbus_data->type = MODBUS_UNIT; modbus_data->arg = (uint8_t) unit_code; *data = (void *)modbus_data; return 1; } int ModbusDataInit(struct _SnortConfig *sc, char *name, char *params, void **data) { modbus_option_data_t *modbus_data; if (strcmp(name, MODBUS_DATA_NAME) != 0) return 0; /* Nothing to parse. */ if (params) { DynamicPreprocessorFatalMessage("%s(%d): modbus_data does not take " "any arguments.\n", *_dpd.config_file, *_dpd.config_line); } modbus_data = (modbus_option_data_t *)calloc(1, sizeof(modbus_option_data_t)); if (modbus_data == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Failed to allocate memory for " "modbus_data data structure.\n", __FILE__, __LINE__); } modbus_data->type = MODBUS_DATA; modbus_data->arg = 0; *data = (void *)modbus_data; return 1; } /* Modbus rule evaluation callback. */ int ModbusRuleEval(void *raw_packet, const uint8_t **cursor, void *data) { SFSnortPacket *packet = (SFSnortPacket *)raw_packet; modbus_option_data_t *rule_data = (modbus_option_data_t *)data; modbus_session_data_t *session_data; /* The preprocessor only evaluates PAF-flushed PDUs. If the rule options don't check for this, they'll fire on stale session data when the original packet goes through before flushing. */ if (!PacketHasFullPDU(packet)) return RULE_NOMATCH; session_data = (modbus_session_data_t *) _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_MODBUS); if ((packet->payload_size == 0 ) || (session_data == NULL)) { return RULE_NOMATCH; } switch (rule_data->type) { case MODBUS_FUNC: if (session_data->func == rule_data->arg) return RULE_MATCH; break; case MODBUS_UNIT: if (session_data->unit == rule_data->arg) return RULE_MATCH; break; case MODBUS_DATA: /* XXX: If a PDU contains only the MBAP + Function, should this option fail or set the cursor to the end of the payload? */ if (packet->payload_size < MODBUS_MIN_LEN) return RULE_NOMATCH; /* Modbus data is always directly after the function code. */ *cursor = (const uint8_t *) (packet->payload + MODBUS_MIN_LEN); _dpd.SetAltDetect((uint8_t *)*cursor, (uint16_t)(packet->payload_size - MODBUS_MIN_LEN)); return RULE_MATCH; } return RULE_NOMATCH; } snort-2.9.6.0/src/dynamic-preprocessors/modbus/modbus_decode.h0000644000000000000000000000332412260565732021314 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Dynamic preprocessor for the Modbus protocol * */ #ifndef MODBUS_DECODE_H #define MODBUS_DECODE_H #include #include "spp_modbus.h" #include "sf_snort_plugin_api.h" /* Need 8 bytes for MBAP Header + Function Code */ #define MODBUS_MIN_LEN 8 /* GIDs, SIDs, and Strings */ #define GENERATOR_SPP_MODBUS 144 #define MODBUS_BAD_LENGTH 1 #define MODBUS_BAD_PROTO_ID 2 #define MODBUS_RESERVED_FUNCTION 3 #define MODBUS_BAD_LENGTH_STR "(spp_modbus): Length in Modbus MBAP header does not match the length needed for the given Modbus function." #define MODBUS_BAD_PROTO_ID_STR "(spp_modbus): Modbus protocol ID is non-zero." #define MODBUS_RESERVED_FUNCTION_STR "(spp_modbus): Reserved Modbus function code in use." int ModbusDecode(modbus_config_t *config, SFSnortPacket *packet); #endif /* MODBUS_DECODE_H */ snort-2.9.6.0/src/dynamic-preprocessors/modbus/modbus_decode.c0000644000000000000000000004133512260565732021313 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Dynamic preprocessor for the Modbus protocol * */ #include "modbus_decode.h" /* Modbus Function Codes */ #define MODBUS_FUNC_READ_COILS 0x01 #define MODBUS_FUNC_READ_DISCRETE_INPUTS 0x02 #define MODBUS_FUNC_READ_HOLDING_REGISTERS 0x03 #define MODBUS_FUNC_READ_INPUT_REGISTERS 0x04 #define MODBUS_FUNC_WRITE_SINGLE_COIL 0x05 #define MODBUS_FUNC_WRITE_SINGLE_REGISTER 0x06 #define MODBUS_FUNC_READ_EXCEPTION_STATUS 0x07 #define MODBUS_FUNC_DIAGNOSTICS 0x08 #define MODBUS_FUNC_GET_COMM_EVENT_COUNTER 0x0B #define MODBUS_FUNC_GET_COMM_EVENT_LOG 0x0C #define MODBUS_FUNC_WRITE_MULTIPLE_COILS 0x0F #define MODBUS_FUNC_WRITE_MULTIPLE_REGISTERS 0x10 #define MODBUS_FUNC_REPORT_SLAVE_ID 0x11 #define MODBUS_FUNC_READ_FILE_RECORD 0x14 #define MODBUS_FUNC_WRITE_FILE_RECORD 0x15 #define MODBUS_FUNC_MASK_WRITE_REGISTER 0x16 #define MODBUS_FUNC_READ_WRITE_MULTIPLE_REGISTERS 0x17 #define MODBUS_FUNC_READ_FIFO_QUEUE 0x18 #define MODBUS_FUNC_ENCAPSULATED_INTERFACE_TRANSPORT 0x2B #define MODBUS_SUB_FUNC_CANOPEN 0x0D #define MODBUS_SUB_FUNC_READ_DEVICE_ID 0x0E /* Various Modbus lengths */ #define MODBUS_BYTE_COUNT_SIZE 1 #define MODBUS_DOUBLE_BYTE_COUNT_SIZE 2 #define MODBUS_FILE_RECORD_SUB_REQUEST_SIZE 7 #define MODBUS_FILE_RECORD_SUB_REQUEST_LEN_OFFSET 5 #define MODBUS_READ_DEVICE_ID_HEADER_LEN 6 #define MODBUS_READ_DEVICE_ID_NUM_OBJ_OFFSET 5 #define MODBUS_EMPTY_DATA_LEN 0 #define MODBUS_FOUR_DATA_BYTES 4 #define MODBUS_BYTE_COUNT_SIZE 1 #define MODBUS_WRITE_MULTIPLE_BYTE_COUNT_OFFSET 4 #define MODBUS_WRITE_MULTIPLE_MIN_SIZE 5 #define MODBUS_MASK_WRITE_REGISTER_SIZE 6 #define MODBUS_READ_WRITE_MULTIPLE_BYTE_COUNT_OFFSET 8 #define MODBUS_READ_WRITE_MULTIPLE_MIN_SIZE 9 #define MODBUS_READ_FIFO_SIZE 2 #define MODBUS_MEI_MIN_SIZE 1 #define MODBUS_FUNC_READ_EXCEPTION_RESP_SIZE 1 #define MODBUS_SUB_FUNC_READ_DEVICE_ID_SIZE 3 #define MODBUS_SUB_FUNC_READ_DEVICE_START_LEN 2 #define MODBUS_SUB_FUNC_READ_DEVICE_LENGTH_OFFSET 1 /* Other defines */ #define MODBUS_PROTOCOL_ID 0 /* Modbus data structures */ typedef struct _modbus_header { /* MBAP Header */ uint16_t transaction_id; uint16_t protocol_id; uint16_t length; uint8_t unit_id; /* PDU Start */ uint8_t function_code; } modbus_header_t; static void ModbusCheckRequestLengths(modbus_session_data_t *session, SFSnortPacket *packet) { uint16_t modbus_payload_len = packet->payload_size - MODBUS_MIN_LEN; uint8_t tmp_count; int check_passed = 0; switch (session->func) { case MODBUS_FUNC_READ_COILS: case MODBUS_FUNC_READ_DISCRETE_INPUTS: case MODBUS_FUNC_READ_HOLDING_REGISTERS: case MODBUS_FUNC_READ_INPUT_REGISTERS: case MODBUS_FUNC_WRITE_SINGLE_COIL: case MODBUS_FUNC_WRITE_SINGLE_REGISTER: case MODBUS_FUNC_DIAGNOSTICS: if (modbus_payload_len == MODBUS_FOUR_DATA_BYTES) check_passed = 1; break; case MODBUS_FUNC_READ_EXCEPTION_STATUS: case MODBUS_FUNC_GET_COMM_EVENT_COUNTER: case MODBUS_FUNC_GET_COMM_EVENT_LOG: case MODBUS_FUNC_REPORT_SLAVE_ID: if (modbus_payload_len == MODBUS_EMPTY_DATA_LEN) check_passed = 1; break; case MODBUS_FUNC_WRITE_MULTIPLE_COILS: case MODBUS_FUNC_WRITE_MULTIPLE_REGISTERS: if (modbus_payload_len >= MODBUS_WRITE_MULTIPLE_MIN_SIZE) { tmp_count = *(packet->payload + MODBUS_MIN_LEN + MODBUS_WRITE_MULTIPLE_BYTE_COUNT_OFFSET); if (modbus_payload_len == tmp_count + MODBUS_WRITE_MULTIPLE_MIN_SIZE) check_passed = 1; } break; case MODBUS_FUNC_MASK_WRITE_REGISTER: if (modbus_payload_len == MODBUS_MASK_WRITE_REGISTER_SIZE) check_passed = 1; break; case MODBUS_FUNC_READ_WRITE_MULTIPLE_REGISTERS: if (modbus_payload_len >= MODBUS_READ_WRITE_MULTIPLE_MIN_SIZE) { tmp_count = *(packet->payload + MODBUS_MIN_LEN + MODBUS_READ_WRITE_MULTIPLE_BYTE_COUNT_OFFSET); if (modbus_payload_len == MODBUS_READ_WRITE_MULTIPLE_MIN_SIZE + tmp_count) check_passed = 1; } break; case MODBUS_FUNC_READ_FIFO_QUEUE: if (modbus_payload_len == MODBUS_READ_FIFO_SIZE) check_passed = 1; break; case MODBUS_FUNC_ENCAPSULATED_INTERFACE_TRANSPORT: if (modbus_payload_len >= MODBUS_MEI_MIN_SIZE) { uint8_t mei_type = *(packet->payload + MODBUS_MIN_LEN); /* MEI Type 0x0E is covered under the Modbus spec as "Read Device Identification". Type 0x0D is defined in the spec as "CANopen General Reference Request and Response PDU" and falls outside the scope of the Modbus preprocessor. Other values are reserved. */ if ((mei_type == MODBUS_SUB_FUNC_READ_DEVICE_ID) && (modbus_payload_len == MODBUS_SUB_FUNC_READ_DEVICE_ID_SIZE)) check_passed = 1; } break; case MODBUS_FUNC_READ_FILE_RECORD: /* Modbus read file record request contains a byte count, followed by a set of 7-byte sub-requests. */ if (modbus_payload_len >= MODBUS_BYTE_COUNT_SIZE) { tmp_count = *(packet->payload + MODBUS_MIN_LEN); if ((tmp_count == modbus_payload_len - MODBUS_BYTE_COUNT_SIZE) && (tmp_count % MODBUS_FILE_RECORD_SUB_REQUEST_SIZE == 0)) { check_passed = 1; } } break; case MODBUS_FUNC_WRITE_FILE_RECORD: /* Modbus write file record request contains a byte count, followed by a set of sub-requests that contain a 7-byte header and a variable amount of data. */ if (modbus_payload_len >= MODBUS_BYTE_COUNT_SIZE) { tmp_count = *(packet->payload + MODBUS_MIN_LEN); if (tmp_count == modbus_payload_len - MODBUS_BYTE_COUNT_SIZE) { uint16_t bytes_processed = 0; while (bytes_processed < (uint16_t)tmp_count) { uint16_t record_length = 0; /* Check space for sub-request header info */ if ((modbus_payload_len - bytes_processed) < MODBUS_FILE_RECORD_SUB_REQUEST_SIZE) break; /* Extract record length. */ record_length = *(packet->payload + MODBUS_MIN_LEN + MODBUS_BYTE_COUNT_SIZE + bytes_processed + MODBUS_FILE_RECORD_SUB_REQUEST_LEN_OFFSET); record_length = record_length << 8; record_length |= *(packet->payload + MODBUS_MIN_LEN + MODBUS_BYTE_COUNT_SIZE + bytes_processed + MODBUS_FILE_RECORD_SUB_REQUEST_LEN_OFFSET + 1); /* Jump over record data. */ bytes_processed += MODBUS_FILE_RECORD_SUB_REQUEST_SIZE + 2*record_length; if (bytes_processed == (uint16_t)tmp_count) check_passed = 1; } } } break; default: /* Don't alert if we couldn't check the length. */ check_passed = 1; break; } if (!check_passed) { _dpd.alertAdd(GENERATOR_SPP_MODBUS, MODBUS_BAD_LENGTH, 1, 0, 3, MODBUS_BAD_LENGTH_STR, 0); } } static void ModbusCheckResponseLengths(modbus_session_data_t *session, SFSnortPacket *packet) { uint16_t modbus_payload_len = packet->payload_size - MODBUS_MIN_LEN; uint8_t tmp_count; int check_passed = 0; switch (session->func) { case MODBUS_FUNC_READ_COILS: case MODBUS_FUNC_READ_DISCRETE_INPUTS: case MODBUS_FUNC_GET_COMM_EVENT_LOG: case MODBUS_FUNC_READ_WRITE_MULTIPLE_REGISTERS: if (modbus_payload_len >= MODBUS_BYTE_COUNT_SIZE) { tmp_count = *(packet->payload + MODBUS_MIN_LEN); /* byte count */ if (modbus_payload_len == MODBUS_BYTE_COUNT_SIZE + tmp_count) check_passed = 1; } break; case MODBUS_FUNC_READ_HOLDING_REGISTERS: case MODBUS_FUNC_READ_INPUT_REGISTERS: if (modbus_payload_len >= MODBUS_BYTE_COUNT_SIZE) { /* count of 2-byte registers*/ tmp_count = *(packet->payload + MODBUS_MIN_LEN); if (modbus_payload_len == MODBUS_BYTE_COUNT_SIZE + 2*tmp_count) check_passed = 1; } break; case MODBUS_FUNC_WRITE_SINGLE_COIL: case MODBUS_FUNC_WRITE_SINGLE_REGISTER: case MODBUS_FUNC_DIAGNOSTICS: case MODBUS_FUNC_GET_COMM_EVENT_COUNTER: case MODBUS_FUNC_WRITE_MULTIPLE_COILS: case MODBUS_FUNC_WRITE_MULTIPLE_REGISTERS: if (modbus_payload_len == MODBUS_FOUR_DATA_BYTES) check_passed = 1; break; case MODBUS_FUNC_READ_EXCEPTION_STATUS: if (modbus_payload_len == MODBUS_FUNC_READ_EXCEPTION_RESP_SIZE) check_passed = 1; break; case MODBUS_FUNC_MASK_WRITE_REGISTER: if (modbus_payload_len == MODBUS_MASK_WRITE_REGISTER_SIZE) check_passed = 1; break; case MODBUS_FUNC_READ_FIFO_QUEUE: if (modbus_payload_len >= MODBUS_DOUBLE_BYTE_COUNT_SIZE) { uint16_t tmp_count_16; /* This function uses a 2-byte byte count!! */ tmp_count_16 = *(uint16_t *)(packet->payload + MODBUS_MIN_LEN); tmp_count_16 = ntohs(tmp_count_16); if (modbus_payload_len == MODBUS_DOUBLE_BYTE_COUNT_SIZE + tmp_count_16) check_passed = 1; } break; case MODBUS_FUNC_ENCAPSULATED_INTERFACE_TRANSPORT: if (modbus_payload_len >= MODBUS_READ_DEVICE_ID_HEADER_LEN) { uint8_t mei_type = *(packet->payload + MODBUS_MIN_LEN); uint8_t num_objects = *(packet->payload + MODBUS_MIN_LEN + MODBUS_READ_DEVICE_ID_NUM_OBJ_OFFSET); uint16_t offset; uint8_t i; /* MEI Type 0x0E is covered under the Modbus spec as "Read Device Identification". Type 0x0D is defined in the spec as "CANopen General Reference Request and Response PDU" and falls outside the scope of the Modbus preprocessor. Other values are reserved. */ if (mei_type == MODBUS_SUB_FUNC_CANOPEN) check_passed = 1; if (mei_type != MODBUS_SUB_FUNC_READ_DEVICE_ID) break; /* Loop through sub-requests, make sure that the lengths inside don't violate our total Modbus PDU size. */ offset = MODBUS_READ_DEVICE_ID_HEADER_LEN; for (i = 0; i < num_objects; i++) { uint8_t sub_request_data_len; /* Sub request starts with 2 bytes, type + len */ if (offset + MODBUS_SUB_FUNC_READ_DEVICE_START_LEN > modbus_payload_len) break; /* Length is second byte in sub-request */ sub_request_data_len = *(packet->payload + MODBUS_MIN_LEN + offset + MODBUS_SUB_FUNC_READ_DEVICE_LENGTH_OFFSET); /* Set offset to byte after sub-request */ offset += (MODBUS_SUB_FUNC_READ_DEVICE_START_LEN + sub_request_data_len); } if ((i == num_objects) && (offset == modbus_payload_len)) check_passed = 1; } break; /* Cannot check this response, as it is device specific. */ case MODBUS_FUNC_REPORT_SLAVE_ID: /* Cannot check these responses, as their sizes depend on the corresponding requests. Can re-visit if we bother with request/response tracking. */ case MODBUS_FUNC_READ_FILE_RECORD: case MODBUS_FUNC_WRITE_FILE_RECORD: default: /* Don't alert if we couldn't check the lengths. */ check_passed = 1; break; } if (!check_passed) { _dpd.alertAdd(GENERATOR_SPP_MODBUS, MODBUS_BAD_LENGTH, 1, 0, 3, MODBUS_BAD_LENGTH_STR, 0); } } static void ModbusCheckReservedFuncs(modbus_header_t *header, SFSnortPacket *packet) { switch (header->function_code) { /* Reserved function codes */ case MODBUS_FUNC_DIAGNOSTICS: /* Only some sub-functions are reserved here. */ { uint16_t sub_func; if (packet->payload_size < MODBUS_MIN_LEN+2) break; sub_func = *((uint16_t *)(packet->payload + MODBUS_MIN_LEN)); sub_func = ntohs(sub_func); if ((sub_func == 19) || (sub_func >= 21)) { _dpd.alertAdd(GENERATOR_SPP_MODBUS, MODBUS_RESERVED_FUNCTION, 1, 0, 3, MODBUS_RESERVED_FUNCTION_STR, 0); } } break; case 0x09: case 0x0A: case 0x0D: case 0x0E: case 0x29: case 0x2A: case 0x5A: case 0x5B: case 0x7D: case 0x7E: case 0x7F: _dpd.alertAdd(GENERATOR_SPP_MODBUS, MODBUS_RESERVED_FUNCTION, 1, 0, 3, MODBUS_RESERVED_FUNCTION_STR, 0); break; } } int ModbusDecode(modbus_config_t *config, SFSnortPacket *packet) { modbus_session_data_t *session; modbus_header_t *header; if (packet->payload_size < MODBUS_MIN_LEN) return MODBUS_FAIL; session = (modbus_session_data_t *) _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_MODBUS); /* Lay the header struct over the payload */ header = (modbus_header_t *) packet->payload; /* The protocol ID field should read 0x0000 for Modbus. It allows for multiplexing with some other protocols over serial line. */ if (header->protocol_id != MODBUS_PROTOCOL_ID) { _dpd.alertAdd(GENERATOR_SPP_MODBUS, MODBUS_BAD_PROTO_ID, 1, 0, 3, MODBUS_BAD_PROTO_ID_STR, 0); return MODBUS_FAIL; } /* Set the session data. Normally we'd need to swap byte order, but these are 8-bit fields. */ session->unit = header->unit_id; session->func = header->function_code; /* Check for reserved function codes */ ModbusCheckReservedFuncs(header, packet); /* Read the Modbus payload and check lengths against the expected length for each function. */ if (packet->flags & FLAG_FROM_CLIENT) ModbusCheckRequestLengths(session, packet); else ModbusCheckResponseLengths(session, packet); return MODBUS_OK; } snort-2.9.6.0/src/dynamic-preprocessors/modbus/spp_modbus.h0000644000000000000000000000376012260565732020677 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Dynamic preprocessor for the Modbus protocol * */ #ifndef SPP_MODBUS_H #define SPP_MODBUS_H #include "sf_types.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #define MAX_PORTS 65536 /* Default MODBUS port */ #define MODBUS_PORT 502 /* Convert port value into an index for the modbus_config->ports array */ #define PORT_INDEX(port) port/8 /* Convert port value into a value for bitwise operations */ #define CONV_PORT(port) 1<<(port%8) /* Session data flags */ #define MODBUS_FUNC_RULE_FIRED 0x0001 #define MODBUS_UNIT_RULE_FIRED 0x0002 #define MODBUS_DATA_RULE_FIRED 0x0004 /* Modbus preprocessor configuration */ typedef struct _modbus_config { char ports[MAX_PORTS/8]; int ref_count; } modbus_config_t; /* Modbus session data */ typedef struct _modbus_session_data { uint8_t func; uint8_t unit; uint16_t flags; tSfPolicyId policy_id; tSfPolicyUserContextId context_id; } modbus_session_data_t; #define MODBUS_PORTS_KEYWORD "ports" #define MODBUS_MEMCAP_KEYWORD "memcap" #define MODBUS_OK 1 #define MODBUS_FAIL (-1) #endif /* SPP_MODBUS_H */ snort-2.9.6.0/src/dynamic-preprocessors/modbus/spp_modbus.c0000644000000000000000000004610212260565732020667 00000000000000/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Ryan Jordan * * Dynamic preprocessor for the Modbus protocol * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_plugin_api.h" #include "snort_debug.h" #include "preprocids.h" #include "spp_modbus.h" #include "sf_preproc_info.h" #include "profiler.h" #ifdef PERF_PROFILING PreprocStats modbusPerfStats; #endif #include "sf_types.h" #include "modbus_decode.h" #include "modbus_roptions.h" #include "modbus_paf.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_MODBUS"; #define SetupModbus DYNAMIC_PREPROC_SETUP /* Preprocessor config objects */ static tSfPolicyUserContextId modbus_context_id = NULL; static modbus_config_t *modbus_eval_config = NULL; /* Target-based app ID */ #ifdef TARGET_BASED int16_t modbus_app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif /* Prototypes */ static void ModbusInit(struct _SnortConfig *, char *); static inline void ModbusOneTimeInit(struct _SnortConfig *); static inline modbus_config_t * ModbusPerPolicyInit(struct _SnortConfig *, tSfPolicyUserContextId); static void ProcessModbus(void *, void *); #ifdef SNORT_RELOAD static void ModbusReload(struct _SnortConfig *, char *, void **); static int ModbusReloadVerify(struct _SnortConfig *, void *); static void * ModbusReloadSwap(struct _SnortConfig *, void *); static void ModbusReloadSwapFree(void *); #endif static void _addPortsToStream5Filter(struct _SnortConfig *, modbus_config_t *, tSfPolicyId); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static void ModbusFreeConfig(tSfPolicyUserContextId context_id); static void FreeModbusData(void *); static int ModbusCheckConfig(struct _SnortConfig *); static void ModbusCleanExit(int, void *); static void ParseModbusArgs(modbus_config_t *config, char *args); static void ModbusPrintConfig(modbus_config_t *config); static int ModbusPortCheck(modbus_config_t *config, SFSnortPacket *packet); static modbus_session_data_t * ModbusCreateSessionData(SFSnortPacket *); /* Register init callback */ void SetupModbus(void) { #ifndef SNORT_RELOAD _dpd.registerPreproc("modbus", ModbusInit); #else _dpd.registerPreproc("modbus", ModbusInit, ModbusReload, ModbusReloadVerify, ModbusReloadSwap, ModbusReloadSwapFree); #endif } /* Allocate memory for preprocessor config, parse the args, set up callbacks */ static void ModbusInit(struct _SnortConfig *sc, char *argp) { modbus_config_t *modbus_policy = NULL; if (modbus_context_id == NULL) { ModbusOneTimeInit(sc); } modbus_policy = ModbusPerPolicyInit(sc, modbus_context_id); ParseModbusArgs(modbus_policy, argp); /* Can't add ports until they've been parsed... */ ModbusAddPortsToPaf(sc, modbus_policy, _dpd.getParserPolicy(sc)); #ifdef TARGET_BASED ModbusAddServiceToPaf(sc, modbus_app_id, _dpd.getParserPolicy(sc)); #endif ModbusPrintConfig(modbus_policy); } static inline void ModbusOneTimeInit(struct _SnortConfig *sc) { /* context creation & error checking */ modbus_context_id = sfPolicyConfigCreate(); if (modbus_context_id == NULL) { _dpd.fatalMsg("%s(%d) Failed to allocate memory for " "Modbus config.\n", *_dpd.config_file, *_dpd.config_line); } if (_dpd.streamAPI == NULL) { _dpd.fatalMsg("%s(%d) SetupModbus(): The Stream preprocessor " "must be enabled.\n", *_dpd.config_file, *_dpd.config_line); } /* callback registration */ _dpd.addPreprocConfCheck(sc, ModbusCheckConfig); _dpd.addPreprocExit(ModbusCleanExit, NULL, PRIORITY_LAST, PP_MODBUS); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("modbus", (void *)&modbusPerfStats, 0, _dpd.totalPerfStats); #endif /* Set up target-based app id */ #ifdef TARGET_BASED modbus_app_id = _dpd.findProtocolReference("modbus"); if (modbus_app_id == SFTARGET_UNKNOWN_PROTOCOL) modbus_app_id = _dpd.addProtocolReference("modbus"); #endif } /* Responsible for allocating a Modbus policy. Never returns NULL. */ static inline modbus_config_t * ModbusPerPolicyInit(struct _SnortConfig *sc, tSfPolicyUserContextId context_id) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); modbus_config_t *modbus_policy = NULL; /* Check for existing policy & bail if found */ sfPolicyUserPolicySet(context_id, policy_id); modbus_policy = (modbus_config_t *)sfPolicyUserDataGetCurrent(context_id); if (modbus_policy != NULL) { _dpd.fatalMsg("%s(%d) Modbus preprocessor can only be " "configured once.\n", *_dpd.config_file, *_dpd.config_line); } /* Allocate new policy */ modbus_policy = (modbus_config_t *)calloc(1, sizeof(modbus_config_t)); if (!modbus_policy) { _dpd.fatalMsg("%s(%d) Could not allocate memory for " "modbus preprocessor configuration.\n" , *_dpd.config_file, *_dpd.config_line); } sfPolicyUserDataSetCurrent(context_id, modbus_policy); /* Register callbacks that are done for each policy */ _dpd.addPreproc(sc, ProcessModbus, PRIORITY_APPLICATION, PP_MODBUS, PROTO_BIT__TCP); _addPortsToStream5Filter(sc, modbus_policy, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif /* Add preprocessor rule options here */ /* _dpd.preprocOptRegister("foo_bar", FOO_init, FOO_rule_eval, free, NULL, NULL, NULL, NULL); */ _dpd.preprocOptRegister(sc, "modbus_func", ModbusFuncInit, ModbusRuleEval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, "modbus_unit", ModbusUnitInit, ModbusRuleEval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, "modbus_data", ModbusDataInit, ModbusRuleEval, free, NULL, NULL, NULL, NULL); return modbus_policy; } static void ParseSinglePort(modbus_config_t *config, char *token) { /* single port number */ char *endptr; unsigned long portnum = _dpd.SnortStrtoul(token, &endptr, 10); if ((*endptr != '\0') || (portnum >= MAX_PORTS)) { _dpd.fatalMsg("%s(%d) Bad modbus port number: %s\n" "Port number must be an integer between 0 and 65535.\n", *_dpd.config_file, *_dpd.config_line, token); } /* Good port number! */ config->ports[PORT_INDEX(portnum)] |= CONV_PORT(portnum); } static void ParseModbusArgs(modbus_config_t *config, char *args) { char *saveptr; char *token; /* Set default port */ config->ports[PORT_INDEX(MODBUS_PORT)] |= CONV_PORT(MODBUS_PORT); /* No args? Stick to the default. */ if (args == NULL) return; token = strtok_r(args, " ", &saveptr); while (token != NULL) { if (strcmp(token, "ports") == 0) { unsigned nPorts = 0; /* Un-set the default port */ config->ports[PORT_INDEX(MODBUS_PORT)] = 0; /* Parse ports */ token = strtok_r(NULL, " ", &saveptr); if (token == NULL) { _dpd.fatalMsg("%s(%d) Missing argument for Modbus preprocessor " "'ports' option.\n", *_dpd.config_file, *_dpd.config_line); } if (isdigit(token[0])) { ParseSinglePort(config, token); nPorts++; } else if (*token == '{') { /* list of ports */ token = strtok_r(NULL, " ", &saveptr); while (token != NULL && *token != '}') { ParseSinglePort(config, token); nPorts++; token = strtok_r(NULL, " ", &saveptr); } } else { nPorts = 0; } if ( nPorts == 0 ) { _dpd.fatalMsg("%s(%d) Bad Modbus 'ports' argument: '%s'\n" "Argument to Modbus 'ports' must be an integer, or a list " "enclosed in { } braces.\n", *_dpd.config_file, *_dpd.config_line, token); } } else { _dpd.fatalMsg("%s(%d) Failed to parse modbus argument: %s\n", *_dpd.config_file, *_dpd.config_line, token); } token = strtok_r(NULL, " ", &saveptr); } } /* Print a Modbus config */ static void ModbusPrintConfig(modbus_config_t *config) { int index; int newline = 1; if (config == NULL) return; _dpd.logMsg("Modbus config: \n"); _dpd.logMsg(" Ports:\n"); /* Loop through port array & print, 5 ports per line */ for (index = 0; index < MAX_PORTS; index++) { if (config->ports[PORT_INDEX(index)] & CONV_PORT(index)) { _dpd.logMsg("\t%d", index); if ( !((newline++) % 5) ) { _dpd.logMsg("\n"); } } } _dpd.logMsg("\n"); } /* Main runtime entry point */ static void ProcessModbus(void *ipacketp, void *contextp) { SFSnortPacket *packetp = (SFSnortPacket *)ipacketp; modbus_session_data_t *sessp; PROFILE_VARS; // preconditions - what we registered for assert(IsTCP(packetp) && packetp->payload && packetp->payload_size); PREPROC_PROFILE_START(modbusPerfStats); /* Fetch me a preprocessor config to use with this VLAN/subnet/etc.! */ modbus_eval_config = sfPolicyUserDataGetCurrent(modbus_context_id); /* Look for a previously-allocated session data. */ sessp = _dpd.streamAPI->get_application_data(packetp->stream_session_ptr, PP_MODBUS); if (sessp == NULL) { /* No existing session. Check those ports. */ if (ModbusPortCheck(modbus_eval_config, packetp) != MODBUS_OK) { PREPROC_PROFILE_END(modbusPerfStats); return; } } if ( !PacketHasFullPDU(packetp) ) { /* If a packet is rebuilt, but not a full PDU, then it's garbage that got flushed at the end of a stream. */ if ( packetp->flags & (FLAG_REBUILT_STREAM|FLAG_PDU_HEAD) ) { _dpd.alertAdd(GENERATOR_SPP_MODBUS, MODBUS_BAD_LENGTH, 1, 0, 3, MODBUS_BAD_LENGTH_STR, 0); } PREPROC_PROFILE_END(modbusPerfStats); return; } if (sessp == NULL) { /* Create session data and attach it to the Stream5 session */ sessp = ModbusCreateSessionData(packetp); if ( !sessp ) { PREPROC_PROFILE_END(modbusPerfStats); return; } } /* When pipelined Modbus PDUs appear in a single TCP segment, the detection engine caches the results of the rule options after evaluating on the first PDU. Setting this flag stops the caching. */ packetp->flags |= FLAG_ALLOW_MULTIPLE_DETECT; /* Do preprocessor-specific detection stuff here */ ModbusDecode(modbus_eval_config, packetp); /* That's the end! */ PREPROC_PROFILE_END(modbusPerfStats); } /* Check ports & services */ static int ModbusPortCheck(modbus_config_t *config, SFSnortPacket *packet) { #ifdef TARGET_BASED int16_t app_id = _dpd.streamAPI->get_application_protocol_id(packet->stream_session_ptr); /* call to get_application_protocol_id gave an error */ if (app_id == SFTARGET_UNKNOWN_PROTOCOL) return MODBUS_FAIL; /* this is positively identified as something non-modbus */ if (app_id && (app_id != modbus_app_id)) return MODBUS_FAIL; /* this is identified as modbus */ if (app_id == modbus_app_id) return MODBUS_OK; /* fall back to port check */ #endif if (config->ports[PORT_INDEX(packet->src_port)] & CONV_PORT(packet->src_port)) return MODBUS_OK; if (config->ports[PORT_INDEX(packet->dst_port)] & CONV_PORT(packet->dst_port)) return MODBUS_OK; return MODBUS_FAIL; } static modbus_session_data_t * ModbusCreateSessionData(SFSnortPacket *packet) { modbus_session_data_t *data = NULL; /* Sanity Check */ if (!packet || !packet->stream_session_ptr) return NULL; data = (modbus_session_data_t *)calloc(1, sizeof(modbus_session_data_t)); if (!data) return NULL; /* Attach to Stream5 session */ _dpd.streamAPI->set_application_data(packet->stream_session_ptr, PP_MODBUS, data, FreeModbusData); /* Not sure when this reference counting stuff got added to the old preprocs */ data->policy_id = _dpd.getRuntimePolicy(); data->context_id = modbus_context_id; ((modbus_config_t *)sfPolicyUserDataGetCurrent(modbus_context_id))->ref_count++; return data; } /* Reload functions */ #ifdef SNORT_RELOAD /* Almost like ModbusInit, but not quite. */ static void ModbusReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId modbus_swap_context_id = (tSfPolicyUserContextId)*new_config; modbus_config_t *modbus_policy = NULL; if (modbus_swap_context_id == NULL) { modbus_swap_context_id = sfPolicyConfigCreate(); if (modbus_swap_context_id == NULL) { _dpd.fatalMsg("Failed to allocate memory " "for Modbus config.\n"); } if (_dpd.streamAPI == NULL) { _dpd.fatalMsg("SetupModbus(): The Stream preprocessor " "must be enabled.\n"); } *new_config = (void *)modbus_swap_context_id; } modbus_policy = ModbusPerPolicyInit(sc, modbus_swap_context_id); ParseModbusArgs(modbus_policy, args); /* Can't add ports until they've been parsed... */ ModbusAddPortsToPaf(sc, modbus_policy, _dpd.getParserPolicy(sc)); ModbusPrintConfig(modbus_policy); } static int ModbusReloadVerify(struct _SnortConfig *sc, void *swap_config) { if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SetupModbus(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } static int ModbusFreeUnusedConfigPolicy( tSfPolicyUserContextId context_id, tSfPolicyId policy_id, void *data ) { modbus_config_t *modbus_config = (modbus_config_t *)data; /* do any housekeeping before freeing modbus config */ if (modbus_config->ref_count == 0) { sfPolicyUserDataClear(context_id, policy_id); free(modbus_config); } return 0; } static void * ModbusReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId modbus_swap_context_id = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_context_id = modbus_context_id; if (modbus_swap_context_id == NULL) return NULL; modbus_context_id = modbus_swap_context_id; sfPolicyUserDataFreeIterate(old_context_id, ModbusFreeUnusedConfigPolicy); if (sfPolicyUserPolicyGetActive(old_context_id) == 0) { /* No more outstanding configs - free the config array */ return (void *)old_context_id; } return NULL; } static void ModbusReloadSwapFree(void *data) { if (data == NULL) return; ModbusFreeConfig( (tSfPolicyUserContextId)data ); } #endif /* Stream5 filter functions */ static void _addPortsToStream5Filter(struct _SnortConfig *sc, modbus_config_t *config, tSfPolicyId policy_id) { if (config == NULL) return; if (_dpd.streamAPI) { int portNum; for (portNum = 0; portNum < MAX_PORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status( sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); } } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status(sc, modbus_app_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif static int ModbusFreeConfigPolicy( tSfPolicyUserContextId context_id, tSfPolicyId policy_id, void *data ) { modbus_config_t *modbus_config = (modbus_config_t *)data; /* do any housekeeping before freeing modbus_config */ sfPolicyUserDataClear(context_id, policy_id); free(modbus_config); return 0; } static void ModbusFreeConfig(tSfPolicyUserContextId context_id) { if (context_id == NULL) return; sfPolicyUserDataFreeIterate(context_id, ModbusFreeConfigPolicy); sfPolicyConfigDelete(context_id); } static int ModbusCheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId context_id, tSfPolicyId policy_id, void *data ) { _dpd.setParserPolicy(sc, policy_id); if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("%s(%d) ModbusCheckPolicyConfig(): The Stream preprocessor " "must be enabled.\n", *_dpd.config_file, *_dpd.config_line); return -1; } return 0; } static int ModbusCheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate(sc, modbus_context_id, ModbusCheckPolicyConfig))) return rval; return 0; } static void ModbusCleanExit(int signal, void *data) { if (modbus_context_id != NULL) { ModbusFreeConfig(modbus_context_id); modbus_context_id = NULL; } } static void FreeModbusData(void *data) { modbus_session_data_t *session = (modbus_session_data_t *)data; modbus_config_t *config = NULL; if (session == NULL) return; if (session->context_id != NULL) { config = (modbus_config_t *)sfPolicyUserDataGet(session->context_id, session->policy_id); } if (config != NULL) { config->ref_count--; if ((config->ref_count == 0) && (session->context_id != modbus_context_id)) { sfPolicyUserDataClear(session->context_id, session->policy_id); free(config); if (sfPolicyUserPolicyGetActive(session->context_id) == 0) { /* No more outstanding configs - free the config array */ ModbusFreeConfig(session->context_id); } } } free(session); } snort-2.9.6.0/src/dynamic-preprocessors/modbus/Makefile.am0000644000000000000000000000135611746560364020412 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_modbus_preproc.la libsf_modbus_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_modbus_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_modbus_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sfPolicyUserData.c endif libsf_modbus_preproc_la_SOURCES = \ spp_modbus.c \ spp_modbus.h \ modbus_decode.c \ modbus_decode.h \ modbus_roptions.c \ modbus_roptions.h \ modbus_paf.c \ modbus_paf.h EXTRA_DIST = \ sf_modbus.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/modbus/Makefile.in0000644000000000000000000005100712260606522020406 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/modbus DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_modbus_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_modbus_preproc_la_OBJECTS = spp_modbus.lo modbus_decode.lo \ modbus_roptions.lo modbus_paf.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_modbus_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_modbus_preproc_la_OBJECTS = \ $(am_libsf_modbus_preproc_la_OBJECTS) \ $(nodist_libsf_modbus_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_modbus_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_modbus_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_modbus_preproc_la_SOURCES) \ $(nodist_libsf_modbus_preproc_la_SOURCES) DIST_SOURCES = $(libsf_modbus_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_modbus_preproc.la libsf_modbus_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_modbus_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_modbus_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_modbus_preproc_la_SOURCES = \ spp_modbus.c \ spp_modbus.h \ modbus_decode.c \ modbus_decode.h \ modbus_roptions.c \ modbus_roptions.h \ modbus_paf.c \ modbus_paf.h EXTRA_DIST = \ sf_modbus.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/modbus/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/modbus/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_modbus_preproc.la: $(libsf_modbus_preproc_la_OBJECTS) $(libsf_modbus_preproc_la_DEPENDENCIES) $(EXTRA_libsf_modbus_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_modbus_preproc_la_LINK) -rpath $(libdir) $(libsf_modbus_preproc_la_OBJECTS) $(libsf_modbus_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/gtp/0000755000000000000000000000000012260606565015726 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/gtp/sf_gtp.dsp0000644000000000000000000001312012153454770017635 00000000000000# Microsoft Developer Studio Project File - Name="sf_gtp" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_gtp - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_gtp.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_gtp.mak" CFG="sf_gtp - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_gtp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_gtp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_gtp - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_gtp - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_gtp - Win32 Release" # Name "sf_gtp - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\gtp_config.c # End Source File # Begin Source File SOURCE=.\gtp_parser.c # End Source File # Begin Source File SOURCE=.\gtp_roptions.c # End Source File # Begin Source File SOURCE=..\include\inet_aton.c # End Source File # Begin Source File SOURCE=..\include\inet_pton.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_ip.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\spp_gtp.c # End Source File # Begin Source File SOURCE=..\include\strtok_r.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\gtp_config.h # End Source File # Begin Source File SOURCE=.\gtp_debug.h # End Source File # Begin Source File SOURCE=.\gtp_parser.h # End Source File # Begin Source File SOURCE=.\gtp_roptions.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\spp_gtp.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/gtp/gtp_debug.h0000644000000000000000000000337412260565732017766 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides macros and functions for debugging the preprocessor. * If Snort is not configured to do debugging, macros are empty. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _GTP_DEBUG_H_ #define _GTP_DEBUG_H_ #include #include "snort_debug.h" /******************************************************************** * Macros ********************************************************************/ #define GTP_DEBUG__START_MSG "GTP Start ********************************************" #define GTP_DEBUG__END_MSG "GTP End **********************************************" #endif /* _GTP_DEBUG_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/gtp/gtp_roptions.h0000644000000000000000000000517412260565732020555 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * This processes the rule options for this preprocessor * * Author: Hui Cao * Date: 07-25-2011 ****************************************************************************/ #ifndef _GTP_ROPTIONS_H_ #define _GTP_ROPTIONS_H_ #include "gtp_config.h" /******************************************************************** * Structures ********************************************************************/ typedef struct _GTP_IEData { uint16_t length; /*length of the data*/ uint16_t shift; /*shift relative to the header*/ uint32_t msg_id; /* used to associate to current msg */ }GTP_IEData; typedef struct _GTP_Roptions { /* gtp_type data*/ uint8_t gtp_type; /* gtp_version data*/ uint8_t gtp_version; uint8_t *gtp_header; uint32_t msg_id; /* used to associate to current msg */ /* gtp ie data */ GTP_IEData *gtp_infoElements; } GTP_Roptions; /*For every value types[i], the bit mask show the version to be applied * bit 1 is for version 0, * bit 2 is for version 1, * bit 3 is for version 2 * */ typedef struct _GTP_TypeRuleOptData { /*Total 256 types*/ uint8_t types[MAX_GTP_TYPE_CODE + 1]; } GTP_TypeRuleOptData; /* * byte 0 is for version 0, * byte 1 is for version 1, * byte 2 is for version 2 * */ typedef struct _GTP_InfoRuleOptData { uint8_t types[MAX_GTP_VERSION_CODE + 1]; } GTP_InfoRuleOptData; /******************************************************************** * Public function prototypes ********************************************************************/ void GTP_RegRuleOptions(struct _SnortConfig *sc); #endif /* _GTP_ROPTIONS_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/gtp/gtp_roptions.c0000644000000000000000000003652612260565732020555 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * This processes the rule options for this preprocessor * * Author: Hui Cao * Date: 07-25-2011 ****************************************************************************/ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "gtp_roptions.h" #include "spp_gtp.h" #include "sf_types.h" #include "sf_dynamic_preprocessor.h" #include "stream_api.h" #include "sf_dynamic_engine.h" #include "sf_snort_plugin_api.h" #include "sfhashfcn.h" #include "profiler.h" #include "gtp_debug.h" #include "gtp_config.h" #include "treenodes.h" #define GTP_ROPT__TYPE "gtp_type" #define GTP_ROPT__IE "gtp_info" #define GTP_ROPT__VERSION "gtp_version" #define GTP_VERSION_0_FLAG (0x01) #define GTP_VERSION_1_FLAG (0x02) #define GTP_VERSION_2_FLAG (0x04) #define GTP_VERSION_ALL_FLAG (GTP_VERSION_0_FLAG|GTP_VERSION_1_FLAG|GTP_VERSION_2_FLAG) /******************************************************************** * Private function prototypes ********************************************************************/ static int GTP_TypeInit(struct _SnortConfig *, char *, char *, void **); static int GTP_TypeEval(void *, const uint8_t **, void *); static int GTP_IEInit(struct _SnortConfig *, char *, char *, void **); static int GTP_IEEval(void *, const uint8_t **, void *); static int GTP_VersionInit(struct _SnortConfig *, char *, char *, void **); static int GTP_VersionEval(void *, const uint8_t **, void *); static inline int GTP_RoptDoEval(SFSnortPacket *p) { if ((p->payload_size == 0) || (p->stream_session_ptr == NULL) || (!IsUDP(p))) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "No payload or no " "session pointer or not TCP or UDP - not evaluating.\n")); return 0; } return 1; } /*gtp type can be numbers*/ static bool GTP_AddTypeByNumer(GTP_TypeRuleOptData *sdata, char *tok) { char *endStr = NULL; unsigned long gtpType; gtpType = _dpd.SnortStrtoul(tok, &endStr, 10); if ( *endStr) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d, OR a correct name.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__TYPE, MIN_GTP_TYPE_CODE, MAX_GTP_TYPE_CODE); } if ((gtpType > MAX_GTP_TYPE_CODE) || (errno == ERANGE)) { DynamicPreprocessorFatalMessage(" %s(%d) => Value specified for %s is out of " "bounds. Please specify an integer between %d and %d, OR a correct name.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__TYPE, MIN_GTP_TYPE_CODE, MAX_GTP_TYPE_CODE); } DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Rule GTP type: %d.\n",gtpType)); sdata->types[gtpType] = GTP_VERSION_ALL_FLAG; return true; } /*gtp type can be names*/ static bool GTP_AddTypeByKeword(GTP_TypeRuleOptData *sdata, char *name) { GTP_MsgType *msgType; int i; bool found = false; for( i = 0; i < MAX_GTP_VERSION_CODE + 1; i++) { if (NULL != (msgType = GetMsgTypeByName((uint8_t)i, name))) { sdata->types[msgType->type] |= 1 << i; found = true; } } return found; } /* Parsing for the rule option */ static int GTP_TypeInit(struct _SnortConfig *sc, char *name, char *params, void **data) { char *nextPara = NULL; char *tok; GTP_TypeRuleOptData *sdata; if (strcasecmp(name, GTP_ROPT__TYPE) != 0) return 0; /* Must have arguments */ if (_dpd.SnortIsStrEmpty(params)) { DynamicPreprocessorFatalMessage("%s(%d) => missing argument to gtp_type keyword\n", *(_dpd.config_file), *(_dpd.config_line)); } tok = strtok_r(params, ",", &nextPara); if(!tok) DynamicPreprocessorFatalMessage("%s(%d) => missing argument to gtp_type keyword\n", *(_dpd.config_file), *(_dpd.config_line)); sdata = (GTP_TypeRuleOptData *)calloc(1, sizeof(*sdata)); if (sdata == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "gtp preprocessor rule option.\n"); } while (NULL != tok) { bool found; if ( isdigit(*tok)) { found = GTP_AddTypeByNumer(sdata, tok); } else /*check keyword*/ { found = GTP_AddTypeByKeword(sdata, tok); } if (! found ) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d, OR a correct name.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__TYPE, MIN_GTP_TYPE_CODE, MAX_GTP_TYPE_CODE); } tok = strtok_r(NULL, ", ", &nextPara); } *data = (void *)sdata; return 1; } /* Rule option evaluation */ static int GTP_TypeEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; GTPData *sd; GTP_Roptions *ropts; GTP_TypeRuleOptData *sdata = (GTP_TypeRuleOptData *)data; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Evaluating \"%s\" rule option.\n", GTP_ROPT__TYPE)); if (!GTP_RoptDoEval(p)) return RULE_NOMATCH; sd = (GTPData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_GTP); if (sd == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "GTP type in packet: %d \n", ropts->gtp_type)); /*Match the GTP type*/ if ((1 << ropts->gtp_version) & sdata->types[ropts->gtp_type]) return RULE_MATCH; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Rule No Match\n")); return RULE_NOMATCH; } /*gtp information element can be number*/ static bool GTP_AddInfoElementByNumer(GTP_InfoRuleOptData *sdata, char *tok) { char *end = NULL; unsigned long gtpIE; int i; gtpIE = _dpd.SnortStrtoul(tok, &end, 10); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Rule GTP information element: %d.\n",gtpIE)); if ( *end) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d, OR a correct name.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__IE, MIN_GTP_IE_CODE, MAX_GTP_IE_CODE); } if ((gtpIE > MAX_GTP_IE_CODE) || (errno == ERANGE)) { DynamicPreprocessorFatalMessage("%s(%d) => Value specified for %s is out of " "bounds. Please specify an integer between %d and %d," "OR a correct name.\n ", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__IE, MIN_GTP_IE_CODE, MAX_GTP_IE_CODE); } for( i = 0; i < MAX_GTP_VERSION_CODE + 1; i++) { sdata->types[i] = (uint8_t)gtpIE; } return true; } /*gtp information element can be name*/ static bool GTP_AddInfoElementByKeyword(GTP_InfoRuleOptData *sdata, char *name) { int i; bool found = false; GTP_InfoElement* infoElement; for( i = 0; i < MAX_GTP_VERSION_CODE + 1; i++) { if (NULL != (infoElement = GetInfoElementByName((uint8_t)i, name))) { sdata->types[i] = infoElement->type; found = true; } } return found; } /* Parsing for the rule option */ static int GTP_IEInit(struct _SnortConfig *sc, char *name, char *params, void **data) { char *nextPara = NULL; char *tok; GTP_InfoRuleOptData *sdata; bool found = false; if (strcasecmp(name, GTP_ROPT__IE) != 0) return 0; /* Must have arguments */ if (_dpd.SnortIsStrEmpty(params)) { DynamicPreprocessorFatalMessage("%s(%d) => missing argument to %s keyword\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__IE); } tok = strtok_r(params, ",", &nextPara); if(!tok) { DynamicPreprocessorFatalMessage("%s(%d) => missing argument to %s keyword\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__IE); } sdata = (GTP_InfoRuleOptData *)calloc(1, sizeof(*sdata)); if (sdata == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "gtp preprocessor rule option.\n"); } if ( isdigit(*tok)) { found = GTP_AddInfoElementByNumer(sdata, tok); } else { found = GTP_AddInfoElementByKeyword(sdata, tok); } if (! found ) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d, OR a correct name.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__IE, MIN_GTP_IE_CODE, MAX_GTP_IE_CODE); } if (!_dpd.SnortIsStrEmpty(nextPara)) { /* Must have only 1 argument*/ DynamicPreprocessorFatalMessage("%s, %s(%d) => rule option: This option has no arguments.\n", GTP_ROPT__IE, *(_dpd.config_file), *(_dpd.config_line)); } *data = (void *)sdata; return 1; } /* Rule option evaluation */ static int GTP_IEEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; GTPData *sd; GTP_Roptions *ropts; GTP_InfoRuleOptData *ie; uint8_t ieType; GTP_IEData *ieData; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Evaluating \"%s\" rule option.\n", GTP_ROPT__IE)); if (!GTP_RoptDoEval(p)) return RULE_NOMATCH; sd = (GTPData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_GTP); if (sd == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; if (NULL == ropts->gtp_infoElements) return RULE_NOMATCH; /*Match the status code*/ ie = (GTP_InfoRuleOptData *)data; ieType = ie->types[ropts->gtp_version]; if (!ieType) { return RULE_NOMATCH; } ieData = &ropts->gtp_infoElements[ieType]; /*if the data is up to date*/ if (ieData->msg_id == ropts->msg_id) { *cursor = ieData->shift + (uint8_t *)ropts->gtp_header; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Setting cursor to IE data: %p.\n", *cursor)); /*Limit the length*/ _dpd.SetAltDetect((uint8_t *)*cursor, ieData->length); return RULE_MATCH; } DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Rule No Match\n")); return RULE_NOMATCH; } /* Parsing for the rule option */ static int GTP_VersionInit(struct _SnortConfig *sc, char *name, char *params, void **data) { char *end = NULL; char *nextPara = NULL; char *tok; uint8_t *sdata; unsigned long gtpVersion; if (strcasecmp(name, GTP_ROPT__VERSION) != 0) return 0; /* Must have arguments */ if (_dpd.SnortIsStrEmpty(params)) { DynamicPreprocessorFatalMessage("%s(%d) => missing argument to %s keyword\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__VERSION); } tok = strtok_r(params, ",", &nextPara); if(!tok) { DynamicPreprocessorFatalMessage("%s(%d) => missing argument to %s keyword\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__VERSION); } sdata = (uint8_t *)calloc(1, sizeof(*sdata)); if (sdata == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "gtp preprocessor rule option.\n"); } gtpVersion = _dpd.SnortStrtoul(tok, &end, 10); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Rule GTP version: %d.\n",gtpVersion)); if ( *end) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__VERSION, MIN_GTP_VERSION_CODE, MAX_GTP_VERSION_CODE); } if ((gtpVersion > MAX_GTP_VERSION_CODE) || (errno == ERANGE)) { DynamicPreprocessorFatalMessage("%s(%d) => Value specified for %s is out of " "bounds. Please specify an integer between %d and %d\n ", *(_dpd.config_file), *(_dpd.config_line), GTP_ROPT__VERSION, MIN_GTP_VERSION_CODE, MAX_GTP_VERSION_CODE); } *sdata = (uint8_t) gtpVersion; if (!_dpd.SnortIsStrEmpty(nextPara)) { /* Must have only 1 argument*/ DynamicPreprocessorFatalMessage("%s, %s(%d) => rule option: This option has only one argument.\n", GTP_ROPT__IE, *(_dpd.config_file), *(_dpd.config_line)); } *data = (void *)sdata; return 1; } /* Rule option evaluation */ static int GTP_VersionEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; GTPData *sd; GTP_Roptions *ropts; uint8_t version = *((uint8_t *)data); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Evaluating \"%s\" rule option.\n", GTP_ROPT__VERSION)); if (!GTP_RoptDoEval(p)) return RULE_NOMATCH; sd = (GTPData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_GTP); if (sd == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; /*Match the status code*/ if (version == ropts->gtp_version) { return RULE_MATCH; } DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Rule No Match\n")); return RULE_NOMATCH; } /******************************************************************** * Function: GTP_RegRuleOptions * * Purpose: Register rule options * * Arguments: void * * Returns: void * ********************************************************************/ void GTP_RegRuleOptions(struct _SnortConfig *sc) { _dpd.preprocOptRegister(sc, GTP_ROPT__TYPE, GTP_TypeInit, GTP_TypeEval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, GTP_ROPT__IE, GTP_IEInit, GTP_IEEval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, GTP_ROPT__VERSION, GTP_VersionInit, GTP_VersionEval, free, NULL, NULL, NULL, NULL); } snort-2.9.6.0/src/dynamic-preprocessors/gtp/gtp_parser.h0000644000000000000000000000276112260565732020173 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 2/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef _GTP_PARSER_H_ #define _GTP_PARSE_H_ #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "gtp_debug.h" #include "spp_gtp.h" int gtp_parse(GTPMsg *, const uint8_t *, uint16_t); void gtp_cleanInfoElements(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/gtp/gtp_parser.c0000644000000000000000000004115212260565732020163 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 7/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_PARSER_H #include #include "sf_types.h" #include "sf_snort_packet.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "gtp_parser.h" #include "spp_gtp.h" #include "gtp_config.h" #ifdef WIN32 #pragma pack(push,gtp_hdrs,1) #else #pragma pack(1) #endif /* GTP basic Header */ typedef struct _GTP_C_Hdr { uint8_t flag; /* flag: version (bit 6-8), PT (5), E (3), S (2), PN (1) */ uint8_t type; /* message type */ uint16_t length; /* length */ } GTP_C_Hdr; typedef struct _GTP_C_Hdr_v0 { GTP_C_Hdr hdr; uint16_t sequence_num; uint16_t flow_lable; uint64_t tid; } GTP_C_Hdr_v0; /* GTP Information element Header */ typedef struct _GTP_IE_Hdr { uint8_t type; uint16_t length; /* length */ } GTP_IE_Hdr; #ifdef WIN32 #pragma pack(pop,gtp_hdrs) #else #pragma pack() #endif /* This table stores all the information elements in a packet * To save memory, only one table for all packets, because we inspect * one packet at a time * The information in the table might from previous packet, * use msg_id to find out whether the information is current. * */ GTP_IEData gtp_ies[MAX_GTP_IE_CODE + 1]; #define GTP_HEADER_LEN_V0 (20) #define GTP_HEADER_LEN_V1 (12) #define GTP_HEADER_LEN_V2 (8) #define GTP_HEADER_LEN_EPC_V2 (12) #define GTP_LENGTH_OFFSET_V0 (GTP_HEADER_LEN_V0) #define GTP_LENGTH_OFFSET_V1 (8) #define GTP_LENGTH_OFFSET_V2 (4) #define GTP_MIN_HEADER_LEN (8) static int gtp_processInfoElements(GTPMsg *msg, const uint8_t *, uint16_t ); /*Because different GTP versions have different format, * they are processed separately*/ static int gtp_parse_v0(GTPMsg *msg, const uint8_t *,uint16_t ); static int gtp_parse_v1(GTPMsg *msg, const uint8_t *, uint16_t ); static int gtp_parse_v2(GTPMsg *msg, const uint8_t *, uint16_t ); #ifdef DEBUG_MSGS /*Display the content*/ static void convertToHex( char *output, int outputSize, const uint8_t *input, int inputSize) { int i = 0; int length; int numBytesInLine = 0; int totalBytes = outputSize; char *buf_ptr = output; while ((i < inputSize)&&(totalBytes > 0)) { length = snprintf(buf_ptr, totalBytes, "%.2x ", (uint8_t)input[i]); buf_ptr += length; totalBytes -= length; if (totalBytes < 0) break; numBytesInLine += length; if (numBytesInLine > 80) { snprintf(buf_ptr++, totalBytes, "\n"); totalBytes--; numBytesInLine = 0; } i++; } return; } /* Display the information elements*/ static void printInfoElements(GTP_IEData *info_elements, GTPMsg *msg) { int i ; for (i=0; i < MAX_GTP_IE_CODE + 1; i++) { char buf[STD_BUF]; if (info_elements[i].msg_id == msg->msg_id) { convertToHex( (char *)buf, sizeof(buf), msg->gtp_header + info_elements[i].shift, info_elements[i].length); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Info type: %.3d, content: %s\n", i, buf);); } } } #endif /******************************************************************** * Function: gtp_processInfoElements() * * Process information elements * * Arguments: * GTPMsg *: the GTP message * * char * * Pointer to the current position in the GTP message. * * uint8_t * * Pointer to the port array mask to set bits for the ports * parsed. * * Returns: * GTP_Ret * GTP_SUCCESS if we were able to successfully parse the * port list. * GTP_FAILURE if an error occured in parsing the port list. * ********************************************************************/ static int gtp_processInfoElements(GTPMsg *msg, const uint8_t *buff, uint16_t len ) { uint8_t *start; uint8_t type; int32_t unprocessed_len; uint8_t previous_type; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Information elements: length: %d\n", len);); start = (uint8_t *)buff; previous_type = (uint8_t) *start; unprocessed_len = len; while ( unprocessed_len > 0) { GTP_InfoElement* ie; uint16_t length; type = *start; if(previous_type > type) { ALERT(GTP_EVENT_OUT_OF_ORDER_IE,GTP_EVENT_OUT_OF_ORDER_IE_STR); } ie = gtp_eval_config->infoElementTable[msg->version][type]; if ( NULL == ie ) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unsupported Information elements!\n");); gtp_stats.unknownIEs++; return GTP_FAILURE; } /*For fixed length, use the table*/ if (ie->length) { length = ie->length; } else /*For variable length, use the length field*/ { GTP_IE_Hdr *ieHdr; /*check the length before reading*/ if (sizeof(*ieHdr) > (unsigned) unprocessed_len) { ALERT(GTP_EVENT_BAD_IE_LEN,GTP_EVENT_BAD_IE_LEN_STR); return GTP_FAILURE; } ieHdr = (GTP_IE_Hdr *)start; length = ntohs(ieHdr->length); /*Check the length */ if (length > UINT16_MAX - GTP_MIN_HEADER_LEN - sizeof(*ieHdr)) { ALERT(GTP_EVENT_BAD_IE_LEN,GTP_EVENT_BAD_IE_LEN_STR); return GTP_FAILURE; } if (msg->version == 2) length += 4; else length += 3; } if (length > unprocessed_len ) { ALERT(GTP_EVENT_BAD_IE_LEN,GTP_EVENT_BAD_IE_LEN_STR); return GTP_FAILURE; } /*Combine the same information element type into one buffer*/ if ((previous_type == type) && (msg->info_elements[type].msg_id == msg->msg_id)) { msg->info_elements[type].length += length; } else { msg->info_elements[type].length = length; msg->info_elements[type].shift = start - msg->gtp_header; msg->info_elements[type].msg_id = msg->msg_id; } DEBUG_WRAP(DebugMessage(DEBUG_GTP, "GTP information element: %s(%d), length: %d\n", ie->name, ie->type, length)); start += length; unprocessed_len -= length; previous_type = type; } DEBUG_WRAP(printInfoElements(msg->info_elements, msg);); return GTP_SUCCESS; } /******************************************************************** * Function: gtp_parse_v0() * * process the GTP v0 message. * * Arguments: * GTPMsg * - gtp message * char* buff - start of the gtp message buffer * uint16_t - length of the message * * Returns: * GTP_FAILURE * GTP_SUCCESS * Bits *Octets 8 7 6 5 4 3 2 1 *1 Version PT 1 1 1 SNN *2 Message Type *3-4 Length *5-6 Sequence Number *7-8 Flow Label *9 SNDCP N-PDULLC Number *10 Spare ‘ 1 1 1 1 1 1 1 1 ‘ *11 Spare ‘ 1 1 1 1 1 1 1 1 ‘ *12 Spare ‘ 1 1 1 1 1 1 1 1 ‘ *13-20 TID * ********************************************************************/ static int gtp_parse_v0(GTPMsg *msg, const uint8_t *buff, uint16_t gtp_len) { GTP_C_Hdr *hdr; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This is a GTP v0 packet.\n");); hdr = (GTP_C_Hdr *) buff; msg->header_len = GTP_HEADER_LEN_V0; /*Check the length field. */ if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V0)) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Calculated length %d != %d in header.\n", gtp_len - GTP_LENGTH_OFFSET_V0, ntohs(hdr->length));); ALERT(GTP_EVENT_BAD_MSG_LEN,GTP_EVENT_BAD_MSG_LEN_STR); return GTP_FAILURE; } return GTP_SUCCESS; } /******************************************************************** * Function: gtp_parse_v1() * * process the GTP v1 message. * * Arguments: * GTPMsg * - gtp message * char* buff - start of the gtp message buffer * uint16_t - length of the message * * Returns: * GTP_FAILURE * GTP_SUCCESS * * Octets 8 7 6 5 4 3 2 1 * 1 Version PT (*) E S PN * 2 Message Type * 3 Length (1st Octet) * 4 Length (2nd Octet) * 5 Tunnel Endpoint Identifier (1st Octet) * 6 Tunnel Endpoint Identifier (2nd Octet) * 7 Tunnel Endpoint Identifier (3rd Octet) * 8 Tunnel Endpoint Identifier (4th Octet) * 9 Sequence Number (1st Octet) * 10 Sequence Number (2nd Octet) * 11 N-PDU Number * 12 Next Extension Header Type ********************************************************************/ static int gtp_parse_v1(GTPMsg *msg, const uint8_t *buff, uint16_t gtp_len) { uint8_t next_hdr_type; GTP_C_Hdr *hdr; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This ia a GTP v1 packet.\n");); hdr = (GTP_C_Hdr *) buff; /*Check the length based on optional fields and extension header*/ if (hdr->flag & 0x07) { msg->header_len = GTP_HEADER_LEN_V1; /*Check optional fields*/ if (gtp_len < msg->header_len) { ALERT(GTP_EVENT_BAD_MSG_LEN,GTP_EVENT_BAD_MSG_LEN_STR); return GTP_FAILURE; } next_hdr_type = *(buff + msg->header_len - 1); /*Check extension headers*/ while (next_hdr_type) { uint16_t ext_header_len; /*check length before reading data, at lease 4 bytes per extension header*/ if (gtp_len < msg->header_len + 4) { ALERT(GTP_EVENT_BAD_MSG_LEN,GTP_EVENT_BAD_MSG_LEN_STR); return GTP_FAILURE; } ext_header_len = *(buff + msg->header_len); if (!ext_header_len) { ALERT(GTP_EVENT_BAD_MSG_LEN,GTP_EVENT_BAD_MSG_LEN_STR); return GTP_FAILURE; } /*Extension header length is a unit of 4 octets*/ msg->header_len += ext_header_len*4; /*check length before reading data*/ if (gtp_len < msg->header_len) { ALERT(GTP_EVENT_BAD_MSG_LEN,GTP_EVENT_BAD_MSG_LEN_STR); return GTP_FAILURE; } next_hdr_type = *(buff + msg->header_len - 1); } } else msg->header_len = GTP_HEADER_LEN_V1; /*Check the length field. */ if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V1)) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Calculated length %d != %d in header.\n", gtp_len - GTP_LENGTH_OFFSET_V1, ntohs(hdr->length));); ALERT(GTP_EVENT_BAD_MSG_LEN,GTP_EVENT_BAD_MSG_LEN_STR); return GTP_FAILURE; } return GTP_SUCCESS; } /******************************************************************** * Function: gtp_parse_v2() * * process the GTP v2 message. * * Arguments: * GTPMsg * - gtp message * char* buff - start of the gtp message buffer * uint16_t - length of the message * * Returns: * GTP_FAILURE * GTP_SUCCESS * *Octets 8 7 6 5 4 3 2 1 *1 Version P T Spare Spare Spare *2 Message Type *3 Message Length (1st Octet) *4 Message Length (2nd Octet) *m to k(m+3) If T flag is set to 1, then TEID shall be placed into octets 5-8. * Otherwise, TEID field is not present at all. *n to (n+2) Sequence Number *(n+3) Spare ********************************************************************/ static int gtp_parse_v2(GTPMsg *msg, const uint8_t *buff, uint16_t gtp_len) { GTP_C_Hdr *hdr; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "This ia a GTP v2 packet.\n");); hdr = (GTP_C_Hdr *) buff; if (hdr->flag & 0x8) msg->header_len = GTP_HEADER_LEN_EPC_V2; else msg->header_len = GTP_HEADER_LEN_V2; /*Check the length field. */ if (gtp_len != ((unsigned int)ntohs(hdr->length) + GTP_LENGTH_OFFSET_V2)) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Calculated length %d != %d in header.\n", gtp_len - GTP_LENGTH_OFFSET_V2, ntohs(hdr->length));); ALERT(GTP_EVENT_BAD_MSG_LEN,GTP_EVENT_BAD_MSG_LEN_STR); return GTP_FAILURE; } return GTP_SUCCESS; } /******************************************************************** * Function: gtp_parse() * * The main entry for parser: process the gtp messages. * * Arguments: * GTPMsg * - gtp message * char* buff - start of the gtp message buffer * uint16_t - length of the message * * Returns: * GTP_FAILURE * GTP_SUCCESS ********************************************************************/ int gtp_parse(GTPMsg *msg, const uint8_t *buff, uint16_t gtp_len) { int status; GTP_C_Hdr *hdr; GTP_MsgType *msgType; /*Initialize key values*/ status = GTP_SUCCESS; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Start parsing...\n")); hdr = (GTP_C_Hdr *) buff; /*Check the length*/ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Basic header length: %d\n", GTP_MIN_HEADER_LEN)); if (gtp_len < GTP_MIN_HEADER_LEN) return GTP_FAILURE; /*The first 3 bits are version number*/ msg->version = (hdr->flag & 0xE0) >> 5; msg->msg_type = hdr->type; msg->gtp_header = (uint8_t *)buff; if (msg->version > MAX_GTP_VERSION_CODE) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unsupported GTP version: %d!\n",msg->version);); return GTP_FAILURE; } /*Check whether this is GTP or GTP', Exit if GTP'*/ if (!(hdr->flag & 0x10)) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unsupported GTP'!\n");); return GTP_FAILURE; } msgType = gtp_eval_config->msgTypeTable[msg->version][msg->msg_type]; if ( NULL == msgType ) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unsupported GTP message type: %d!\n",msg->msg_type);); gtp_stats.unknownTypes++; return GTP_FAILURE; } else { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "GTP version: %d, message type: %s(%d)\n", msg->version, msgType->name, msg->msg_type)); } gtp_stats.messages[msg->version][msg->msg_type]++; /* We only care about control types*/ if ( hdr->type == 255) return GTP_FAILURE; switch (msg->version) { case 0: /*GTP v0*/ status = gtp_parse_v0(msg, buff, gtp_len); break; case 1: /*GTP v1*/ status = gtp_parse_v1(msg, buff, gtp_len); break; case 2:/*GTP v2 */ status = gtp_parse_v2(msg, buff, gtp_len); break; default: DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unknown protocol version.\n");); return GTP_FAILURE; } /*Parse information elements*/ if ((msg->header_len < gtp_len)&& (GTP_SUCCESS == status)) { msg->info_elements = gtp_ies; buff += msg->header_len; status = gtp_processInfoElements(msg, buff, (uint16_t)(gtp_len - msg->header_len)); } return status; } /******************************************************************** * Function: gtp_cleanInfoElements() * * Clean up the shared information elements table * * Arguments: * None * * Returns: * None ********************************************************************/ void gtp_cleanInfoElements(void) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Cleaned total bytes %d, length %d.\n", (MAX_GTP_IE_CODE + 1) * sizeof(GTP_IEData), sizeof(gtp_ies));); memset(gtp_ies, 0, sizeof(gtp_ies)); } #endif snort-2.9.6.0/src/dynamic-preprocessors/gtp/gtp_config.h0000644000000000000000000000610012260565732020133 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 8/1/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef _GTP_CONFIG_H_ #define _GTP_CONFIG_H_ #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "gtp_debug.h" #define GTP_NAME "gtp" #define MAX_GTP_TYPE_CODE (255) #define MIN_GTP_TYPE_CODE (0) #define MAX_GTP_IE_CODE (255) #define MIN_GTP_IE_CODE (0) #define MAX_GTP_VERSION_CODE (2) #define MIN_GTP_VERSION_CODE (0) /* * Message type */ typedef struct _GTP_MsgType { uint8_t type; /* the message type*/ uint8_t isKeyword; /*whether the name can be used as keyword*/ char *name; /*name of the type*/ }GTP_MsgType; /* * Information elements */ typedef struct _GTP_InfoElement { uint8_t type; /* the IE type*/ uint8_t isKeyword; /*whether the name can be used as keyword*/ char *name; /*name of the IE*/ uint16_t length; /* the length of IE; if 0, means variable length*/ }GTP_InfoElement; /* * One of these structures is kept for each configured * server port. */ typedef struct _gtpPortlistNode { uint16_t server_port; struct _gtpPortlistNode* nextp; } GTPPortNode; /* * GTP preprocessor configuration. * * ports: Which ports to check for GTP messages * infoElementTable: information elements table, for quick retrieve * msgTypeTable: message type table, for quick retrieve */ typedef struct _gtpConfig { uint8_t ports[MAXPORTS/8]; GTP_InfoElement* infoElementTable[MAX_GTP_VERSION_CODE + 1 ][MAX_GTP_IE_CODE + 1]; GTP_MsgType *msgTypeTable[MAX_GTP_VERSION_CODE + 1][MAX_GTP_TYPE_CODE + 1]; int ref_count; } GTPConfig; /******************************************************************** * Public function prototypes ********************************************************************/ void ParseGTPArgs(GTPConfig *, u_char*); GTP_MsgType* GetMsgTypeByName(uint8_t, char *); GTP_InfoElement* GetInfoElementByName(uint8_t, char *); #endif snort-2.9.6.0/src/dynamic-preprocessors/gtp/gtp_config.c0000644000000000000000000007317712260565732020150 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 7/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "sf_types.h" #include "sf_snort_packet.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "gtp_config.h" #include "spp_gtp.h" #include "gtp_debug.h" #define METHOD_NOT_FOUND (-1) /* * Default GTP port */ #define GTP_C_PORT (2123) #define GTP_C_PORT_V0 (3386) /* * Keyword strings for parsing configuration options. */ #define GTP_PORTS_KEYWORD "ports" #define GTP_CONFIG_SECTION_SEPERATORS ",;" #define GTP_CONFIG_VALUE_SEPERATORS " " /* * Message type defined */ static GTP_MsgType GTPv0_MsgTypes[] = { {1, 1, "echo_request"}, {2, 1, "echo_response"}, {3, 1, "version_not_supported"}, {4, 1, "node_alive_request"}, {5, 1, "node_alive_response"}, {6, 1, "redirection_request"}, {7, 1, "redirection_response"}, {16, 1,"create_pdp_context_request"}, {17, 1,"create_pdp_context_response"}, {18, 1,"update_pdp_context_request"}, {19, 1,"update_pdp_context_response"}, {20, 1,"delete_pdp_context_request"}, {21, 1,"delete_pdp_context_response"}, {22, 1,"create_aa_pdp_context_request"}, {23, 1,"create_aa_pdp_context_response"}, {24, 1,"delete_aa_pdp_context_request"}, {25, 1,"delete_aa_pdp_context_response"}, {26, 1,"error_indication"}, {27, 1,"pdu_notification_request"}, {28, 1,"pdu_notification_response"}, {29, 1,"pdu_notification_reject_request"}, {30, 1,"pdu_notification_reject_response"}, {32, 1,"send_routing_info_request"}, {33, 1,"send_routing_info_response"}, {34, 1,"failure_report_request"}, {35, 1,"failure_report_response"}, {36, 1,"note_ms_present_request"}, {37, 1,"note_ms_present_response"}, {48, 1,"identification_request"}, {49, 1,"identification_response"}, {50, 1,"sgsn_context_request"}, {51, 1,"sgsn_context_response"}, {52, 1,"sgsn_context_ack"}, {240, 1,"data_record_transfer_request"}, {241, 1,"data_record_transfer_response"}, {255, 1,"pdu"}, {0, 0, NULL} }; static GTP_MsgType GTPv1_MsgTypes[] = { {1, 1, "echo_request"}, {2, 1, "echo_response"}, {3, 1, "version_not_supported"}, {4, 1, "node_alive_request"}, {5, 1, "node_alive_response"}, {6, 1, "redirection_request"}, {7, 1, "redirection_response"}, {16, 1,"create_pdp_context_request"}, {17, 1,"create_pdp_context_response"}, {18, 1,"update_pdp_context_request"}, {19, 1,"update_pdp_context_response"}, {20, 1,"delete_pdp_context_request"}, {21, 1,"delete_pdp_context_response"}, {22, 1,"init_pdp_context_activation_request"}, {23, 1,"init_pdp_context_activation_response"}, {26, 1,"error_indication"}, {27, 1,"pdu_notification_request"}, {28, 1,"pdu_notification_response"}, {29, 1,"pdu_notification_reject_request"}, {30, 1,"pdu_notification_reject_response"}, {31, 1,"supported_ext_header_notification"}, {32, 1,"send_routing_info_request"}, {33, 1,"send_routing_info_response"}, {34, 1,"failure_report_request"}, {35, 1,"failure_report_response"}, {36, 1,"note_ms_present_request"}, {37, 1,"note_ms_present_response"}, {48, 1,"identification_request"}, {49, 1,"identification_response"}, {50, 1,"sgsn_context_request"}, {51, 1,"sgsn_context_response"}, {52, 1,"sgsn_context_ack"}, {53, 1,"forward_relocation_request"}, {54, 1,"forward_relocation_response"}, {55, 1,"forward_relocation_complete"}, {56, 1,"relocation_cancel_request"}, {57, 1,"relocation_cancel_response"}, {58, 1,"forward_srns_contex"}, {59, 1,"forward_relocation_complete_ack"}, {60, 1,"forward_srns_contex_ack"}, {70, 1,"ran_info_relay"}, {96, 1,"mbms_notification_request"}, {97, 1,"mbms_notification_response"}, {98, 1,"mbms_notification_reject_request"}, {99, 1,"mbms_notification_reject_response"}, {100,1,"create_mbms_context_request"}, {101,1,"create_mbms_context_response"}, {102,1,"update_mbms_context_request"}, {103,1,"update_mbms_context_response"}, {104,1,"delete_mbms_context_request"}, {105,1,"delete_mbms_context_response"}, {112,1,"mbms_register_request"}, {113,1,"mbms_register_response"}, {114,1,"mbms_deregister_request"}, {115,1,"mbms_deregister_response"}, {116,1,"mbms_session_start_request"}, {117,1,"mbms_session_start_response"}, {118,1,"mbms_session_stop_request"}, {119,1,"mbms_session_stop_response"}, {120,1,"mbms_session_update_request"}, {121,1,"mbms_session_update_response"}, {128, 1,"ms_info_change_request"}, {129, 1,"ms_info_change_response"}, {240, 1,"data_record_transfer_request"}, {241, 1,"data_record_transfer_response"}, {254, 1,"end_marker"}, {255, 1,"pdu"}, {0, 0, NULL} }; static GTP_MsgType GTPv2_MsgTypes[] = { {1, 1, "echo_request"}, {2, 1, "echo_response"}, {3, 1, "version_not_supported"}, {32, 1,"create_session_request"}, {33, 1,"create_session_response"}, {34, 1,"modify_bearer_request"}, {35, 1,"modify_bearer_response"}, {36, 1,"delete_session_request"}, {37, 1,"delete_session_response"}, {38, 1,"change_notification_request"}, {39, 1,"change_notification_response"}, {64, 1,"modify_bearer_command"}, {65, 1,"modify_bearer_failure_indication"}, {66, 1,"delete_bearer_command"}, {67, 1,"delete_bearer_failure_indication"}, {68, 1,"bearer_resource_command"}, {69, 1,"bearer_resource_failure_indication"}, {70, 1,"downlink_failure_indication"}, {71, 1,"trace_session_activation"}, {72, 1,"trace_session_deactivation"}, {73, 1,"stop_paging_indication"}, {95, 1,"create_bearer_request"}, {96, 1,"create_bearer_response"}, {97, 1,"update_bearer_request"}, {98, 1,"update_bearer_response"}, {99, 1,"delete_bearer_request"}, {100,1,"delete_bearer_response"}, {101,1,"delete_pdn_request"}, {102,1,"delete_pdn_response"}, {128, 1,"identification_request"}, {129, 1,"identification_response"}, {130, 1,"sgsn_context_request"}, {131, 1,"sgsn_context_response"}, {132, 1,"sgsn_context_ack"}, {133, 1,"forward_relocation_request"}, {134, 1,"forward_relocation_response"}, {135, 1,"forward_relocation_complete"}, {136, 1,"forward_relocation_complete_ack"}, {137, 1,"forward_access"}, {138, 1,"forward_access_ack"}, {139, 1,"relocation_cancel_request"}, {140, 1,"relocation_cancel_response"}, {141, 1,"configuration_transfer_tunnel"}, {149, 1,"detach"}, {150, 1,"detach_ack"}, {151, 1,"cs_paging"}, {152, 1,"ran_info_relay"}, {153, 1,"alert_mme"}, {154, 1,"alert_mme_ack"}, {155, 1,"ue_activity"}, {156, 1,"ue_activity_ack"}, {160,1,"create_forward_tunnel_request"}, {161,1,"create_forward_tunnel_response"}, {162, 1,"suspend"}, {163, 1,"suspend_ack"}, {164, 1,"resume"}, {165, 1,"resume_ack"}, {166,1,"create_indirect_forward_tunnel_request"}, {167,1,"create_indirect_forward_tunnel_response"}, {168,1,"delete_indirect_forward_tunnel_request"}, {169,1,"delete_indirect_forward_tunnel_response"}, {170,1,"release_access_bearer_request"}, {171,1,"release_access_bearer_response"}, {176,1,"downlink_data"}, {177,1,"downlink_data_ack"}, {179,1,"pgw_restart"}, {180,1,"pgw_restart_ack"}, {200,1,"update_pdn_request"}, {201,1,"update_pdn_response"}, {211,1,"modify_access_bearer_request"}, {212,1,"modify_access_bearer_response"}, {231,1,"mbms_session_start_request"}, {232,1,"mbms_session_start_response"}, {233,1,"mbms_session_update_request"}, {234,1,"mbms_session_update_response"}, {235,1,"mbms_session_stop_request"}, {236,1,"mbms_session_stop_response"}, {0, 0, NULL} }; /* * Information elements defined */ static GTP_InfoElement GTPv0_InfoElements[] = { {1, 1, "cause", 2}, {2, 1, "imsi", 9}, {3, 1, "rai", 7}, {4, 1, "tlli", 5}, {5, 1, "p_tmsi", 5}, {6, 1, "qos", 4}, {8, 1, "recording_required", 2}, {9, 1, "authentication", 29}, {11, 1, "map_cause", 2}, {12, 1, "p_tmsi_sig", 4}, {13, 1, "ms_validated", 2}, {14, 1, "recovery", 2}, {15, 1, "selection_mode", 2}, {16, 1, "flow_label_data_1", 3}, {17, 1, "flow_label_signalling", 3}, {18, 1, "flow_label_data_2", 4}, {19, 1, "ms_unreachable", 2}, {127, 1, "charge_id", 5}, {128, 1, "end_user_address", 0}, {129, 1, "mm_context", 0}, {130, 1, "pdp_context", 0}, {131, 1, "apn", 0}, {132, 1, "protocol_config", 0}, {133, 1, "gsn", 0}, {134, 1, "msisdn", 0}, {251, 1, "charging_gateway_addr", 0}, {255, 1, "private_extension", 0}, {0, 0, NULL, 0}, }; static GTP_InfoElement GTPv1_InfoElements[] = { {1, 1, "cause", 2}, {2, 1, "imsi", 9}, {3, 1, "rai", 7}, {4, 1, "tlli", 5}, {5, 1, "p_tmsi", 5}, {8, 1, "recording_required", 2}, {9, 1, "authentication", 29}, {11, 1, "map_cause", 2}, {12, 1, "p_tmsi_sig", 4}, {13, 1, "ms_validated", 2}, {14, 1, "recovery", 2}, {15, 1, "selection_mode", 2}, {16, 1, "teid_1", 5}, {17, 1, "teid_control", 5}, {18, 1, "teid_2", 6}, {19, 1, "teardown_ind", 2}, {20, 1, "nsapi", 2}, {21, 1, "ranap", 2}, {22, 1, "rab_context", 10}, {23, 1, "radio_priority_sms", 2}, {24, 1, "radio_priority", 2}, {25, 1, "packet_flow_id", 3}, {26, 1, "charging_char", 3}, {27, 1, "trace_ref", 3}, {28, 1, "trace_type", 3}, {29, 1, "ms_unreachable", 2}, {127, 1, "charge_id", 5}, {128, 1, "end_user_address", 0}, {129, 1, "mm_context", 0}, {130, 1, "pdp_context", 0}, {131, 1, "apn", 0}, {132, 1, "protocol_config", 0}, {133, 1, "gsn", 0}, {134, 1, "msisdn", 0}, {135, 1, "qos", 0}, {136, 1, "authentication_qu", 0}, {137, 1, "tft", 0}, {138, 1, "target_id", 0}, {139, 1, "utran_trans", 0}, {140, 1, "rab_setup", 0}, {141, 1, "ext_header", 0}, {142, 1, "trigger_id", 0}, {143, 1, "omc_id", 0}, {144, 1, "ran_trans", 0}, {145, 1, "pdp_context_pri", 0}, {146, 1, "addi_rab_setup", 0}, {147, 1, "sgsn_number", 0}, {148, 1, "common_flag", 0}, {149, 1, "apn_restriction", 0}, {150, 1, "radio_priority_lcs", 4}, {151, 1, "rat_type", 0}, {152, 1, "user_loc_info", 0}, {153, 1, "ms_time_zone", 0}, {154, 1, "imei_sv", 0}, {155, 1, "camel", 0}, {156, 1, "mbms_ue_context", 0}, {157, 1, "tmp_mobile_group_id", 0}, {158, 1, "rim_routing_addr", 0}, {159, 1, "mbms_config", 0}, {160, 1, "mbms_service_area", 0}, {161, 1, "src_rnc_pdcp", 0}, {162, 1, "addi_trace_info", 0}, {163, 1, "hop_counter", 0}, {164, 1, "plmn_id", 0}, {165, 1, "mbms_session_id", 0}, {166, 1, "mbms_2g3g_indicator", 0}, {167, 1, "enhanced_nsapi", 0}, {168, 1, "mbms_session_duration", 0}, {169, 1, "addi_mbms_trace_info", 0}, {170, 1, "mbms_session_repetition_num", 0}, {171, 1, "mbms_time_to_data", 0}, {173, 1, "bss", 0}, {174, 1, "cell_id", 0}, {175, 1, "pdu_num", 0}, {177, 1, "mbms_bearer_capab", 0}, {178, 1, "rim_routing_disc", 0}, {179, 1, "list_pfc", 0}, {180, 1, "ps_xid", 0}, {181, 1, "ms_info_change_report", 4}, {182, 1, "direct_tunnel_flags", 0}, {183, 1, "correlation_id", 0}, {184, 1, "bearer_control_mode", 0}, {185, 1, "mbms_flow_id", 0}, {186, 1, "mbms_ip_multicast", 0}, {187, 1, "mbms_distribution_ack", 4}, {188, 1, "reliable_inter_rat_handover", 0}, {189, 1, "rfsp_index", 0}, {190, 1, "fqdn", 0}, {191, 1, "evolved_allocation1", 0}, {192, 1, "evolved_allocation2", 0}, {193, 1, "extended_flags", 0}, {194, 1, "uci", 0}, {195, 1, "csg_info", 0}, {196, 1, "csg_id", 0}, {197, 1, "cmi", 4}, {198, 1, "apn_ambr", 0}, {199, 1, "ue_network", 0}, {200, 1, "ue_ambr", 0}, {201, 1, "apn_ambr_nsapi", 0}, {202, 1, "ggsn_backoff_timer", 0}, {203, 1, "signalling_priority_indication", 0}, {204, 1, "signalling_priority_indication_nsapi", 0}, {205, 1, "high_bitrate", 4}, {206, 1, "max_mbr", 0}, {251, 1, "charging_gateway_addr", 0}, {255, 1, "private_extension", 0}, {0, 0, NULL, 0}, }; static GTP_InfoElement GTPv2_InfoElements[] = { {1, 1, "imsi", 0}, {2, 1, "cause", 0}, {3, 1, "recovery", 0}, {71, 1, "apn", 0}, {72, 1, "ambr", 0}, {73, 1, "ebi", 0}, {74, 1, "ip_addr", 0}, {75, 1, "mei", 0}, {76, 1, "msisdn", 0}, {77, 1, "indication", 0}, {78, 1, "pco", 0}, {79, 1, "paa", 0}, {80, 1, "bearer_qos", 0}, {81, 1, "flow_qos", 0}, {82, 1, "rat_type", 0}, {83, 1, "serving_network", 0}, {84, 1, "bearer_tft", 0}, {85, 1, "tad", 0}, {86, 1, "uli", 0}, {87, 1, "f_teid", 0}, {88, 1, "tmsi", 0}, {89, 1, "cn_id", 0}, {90, 1, "s103pdf", 0}, {91, 1, "s1udf", 0}, {92, 1, "delay_value", 0}, {93, 1, "bearer_context", 0}, {94, 1, "charging_id", 0}, {95, 1, "charging_char", 0}, {96, 1, "trace_info", 0}, {97, 1, "bearer_flag", 0}, {99, 1, "pdn_type", 0}, {100, 1, "pti", 0}, {101, 1, "drx_parameter", 0}, {103, 1, "gsm_key_tri", 0}, {104, 1, "umts_key_cipher_quin", 0}, {105, 1, "gsm_key_cipher_quin", 0}, {106, 1, "umts_key_quin", 0}, {107, 1, "eps_quad", 0}, {108, 1, "umts_key_quad_quin", 0}, {109, 1, "pdn_connection", 0}, {110, 1, "pdn_number", 0}, {111, 1, "p_tmsi", 0}, {112, 1, "p_tmsi_sig", 0}, {113, 1, "hop_counter", 0}, {114, 1, "ue_time_zone", 0}, {115, 1, "trace_ref", 0}, {116, 1, "complete_request_msg", 0}, {117, 1, "guti", 0}, {118, 1, "f_container", 0}, {119, 1, "f_cause", 0}, {120, 1, "plmn_id", 0}, {121, 1, "target_id", 0}, {123, 1, "packet_flow_id", 0}, {124, 1, "rab_contex", 0}, {125, 1, "src_rnc_pdcp", 0}, {126, 1, "udp_src_port", 0}, {127, 1, "apn_restriction", 0}, {128, 1, "selection_mode", 0}, {129, 1, "src_id", 0}, {131, 1, "change_report_action", 0}, {132, 1, "fq_csid", 0}, {133, 1, "channel", 0}, {134, 1, "emlpp_pri", 0}, {135, 1, "node_type", 0}, {136, 1, "fqdn", 0}, {137, 1, "ti", 0}, {138, 1, "mbms_session_duration", 0}, {139, 1, "mbms_service_area", 0}, {140, 1, "mbms_session_id", 0}, {141, 1, "mbms_flow_id", 0}, {142, 1, "mbms_ip_multicast", 0}, {143, 1, "mbms_distribution_ack", 0}, {144, 1, "rfsp_index", 0}, {145, 1, "uci", 0}, {146, 1, "csg_info", 0}, {147, 1, "csg_id", 0}, {148, 1, "cmi", 0}, {149, 1, "service_indicator", 0}, {150, 1, "detach_type", 0}, {151, 1, "ldn", 0}, {152, 1, "node_feature", 0}, {153, 1, "mbms_time_to_transfer", 0}, {154, 1, "throttling", 0}, {155, 1, "arp", 0}, {156, 1, "epc_timer", 0}, {157, 1, "signalling_priority_indication", 0}, {158, 1, "tmgi", 0}, {159, 1, "mm_srvcc", 0}, {160, 1, "flags_srvcc", 0}, {161, 1, "mmbr", 0}, {255, 1, "private_extension", 0}, {0, 0, NULL, 0}, }; /* * Function prototype(s) */ static void InitGTPInfoElementTable(GTPConfig *); static void DisplayGTPConfig(GTPConfig *); static void GTP_ParsePortList(char **, uint8_t *); /* Update the information elements table for one GTP version. * * PARAMETERS: * * GTPConfig *config: GTP preprocessor configuration. * GTP_InfoElement *: Information elements * uint8_t: version number for information elements * * RETURNS: Nothing. */ static void UpdateGTPInfoElementTable(GTPConfig *config, GTP_InfoElement *InfoElements, uint8_t version) { int i = 0; while(NULL != InfoElements[i].name) { config->infoElementTable[version][InfoElements[i].type] = &InfoElements[i]; i++; } } /* Update the information elements table for the GTP preprocessor. * * PARAMETERS: * * GTPConfig *config: GTP preprocessor configuration. * * RETURNS: Nothing. */ static void InitGTPInfoElementTable(GTPConfig *config) { GTP_InfoElement *InfoElements; InfoElements = GTPv0_InfoElements; UpdateGTPInfoElementTable(config,InfoElements, 0); InfoElements = GTPv1_InfoElements; UpdateGTPInfoElementTable(config,InfoElements, 1); InfoElements = GTPv2_InfoElements; UpdateGTPInfoElementTable(config,InfoElements, 2); } /* Update the message types table for one GTP version. * * PARAMETERS: * * GTPConfig *config: GTP preprocessor configuration. * GTP_MsgType *: message types * uint8_t: version number for message types * * RETURNS: Nothing. */ static void UpdateGTPMsgTypeTable(GTPConfig *config, GTP_MsgType *MsgTypes, uint8_t version) { int i = 0; while(NULL != MsgTypes[i].name) { config->msgTypeTable[version][MsgTypes[i].type] = &MsgTypes[i]; gtp_stats.msgTypeTable[version][MsgTypes[i].type] = &MsgTypes[i]; i++; } } /* Update the message types table for the GTP preprocessor. * * PARAMETERS: * * GTPConfig *config: GTP preprocessor configuration. * * RETURNS: Nothing. */ static void InitGTPMsgTypeTable(GTPConfig *config) { GTP_MsgType *MsgTypes; MsgTypes = GTPv0_MsgTypes; UpdateGTPMsgTypeTable(config,MsgTypes, 0); MsgTypes = GTPv1_MsgTypes; UpdateGTPMsgTypeTable(config,MsgTypes, 1); MsgTypes = GTPv2_MsgTypes; UpdateGTPMsgTypeTable(config,MsgTypes, 2); } #ifdef DEBUG_MSGS /* Display the message types for the GTP preprocessor. * * PARAMETERS: * * GTPConfig *config: GTP preprocessor configuration. * * RETURNS: Nothing. */ static void DisplayMsgTypes(GTPConfig *config) { int i, j; _dpd.logMsg(" Supported message types:\n"); for(i = 0; i < MAX_GTP_TYPE_CODE + 1; i++) { _dpd.logMsg("\t%3d ", i); for (j = 0; j < MAX_GTP_VERSION_CODE + 1; j++) { if (config->msgTypeTable[j][i]) { _dpd.logMsg("%40s ", config->msgTypeTable[j][i]->name); } else _dpd.logMsg("%40s ", "N/A"); } _dpd.logMsg("\n"); } } /* Display the information element for the GTP preprocessor. * * PARAMETERS: * * GTPConfig *config: GTP preprocessor configuration. * * RETURNS: Nothing. */ static void DisplayInfoElements(GTPConfig *config) { int i, j; _dpd.logMsg(" Supported information elements:\n"); for(i = 0; i < MAX_GTP_IE_CODE + 1; i++) { _dpd.logMsg("\t%3d ", i); for (j = 0; j < MAX_GTP_VERSION_CODE + 1 ; j++) { if (config->infoElementTable[j][i]) _dpd.logMsg(" %40s ", config->infoElementTable[j][i]->name); else _dpd.logMsg(" %40s ", "N/A"); } _dpd.logMsg("\n"); } } #endif /* Display the configuration for the GTP preprocessor. * * PARAMETERS: * * GTPConfig *config: GTP preprocessor configuration. * * RETURNS: Nothing. */ static void DisplayGTPConfig(GTPConfig *config) { int index; int newline; if (config == NULL) return; _dpd.logMsg("GTP config: \n"); /* Traverse list, printing ports, 5 per line */ newline = 1; _dpd.logMsg(" Ports:\n"); for(index = 0; index < MAXPORTS; index++) { if( config->ports[ PORT_INDEX(index) ] & CONV_PORT(index) ) { _dpd.logMsg("\t%d", index); if ( !((newline++)% 5) ) _dpd.logMsg("\n"); } } _dpd.logMsg("\n"); DEBUG_WRAP(DisplayMsgTypes(config)); DEBUG_WRAP(DisplayInfoElements(config)); } /******************************************************************** * Function: GTP_ParsePortList() * * Parses a port list and adds bits associated with the ports * parsed to a bit array. * * Arguments: * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the IP list. * uint8_t * * Pointer to the port array mask to set bits for the ports * parsed. * * Returns: * GTP_Ret * GTP_SUCCESS if we were able to successfully parse the * port list. * GTP_FAILURE if an error occured in parsing the port list. * ********************************************************************/ static void GTP_ParsePortList(char **ptr, uint8_t *port_array) { long int port = -1; char* cur_tokenp = *ptr; /* If the user specified ports, remove GTP_C_PORT for now since * it now needs to be set explicitly. */ port_array[ PORT_INDEX( GTP_C_PORT ) ] = 0; port_array[ PORT_INDEX( GTP_C_PORT_V0 ) ] = 0; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Port configurations: %s\n",*ptr );); /* Eat the open brace. */ cur_tokenp = strtok( NULL, GTP_CONFIG_VALUE_SEPERATORS); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Port token: %s\n",cur_tokenp );); /* Check the space after '{'*/ if (( !cur_tokenp ) || ( 0 != strncmp (cur_tokenp, "{", 2 ))) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s, make sure space before and after '{'.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_PORTS_KEYWORD); } cur_tokenp = strtok( NULL, GTP_CONFIG_VALUE_SEPERATORS); while (( cur_tokenp ) && ( 0 != strncmp (cur_tokenp, "}", 2 ))) { char *endStr = NULL; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Port token: %s\n",cur_tokenp );); if ( !cur_tokenp ) { DynamicPreprocessorFatalMessage(" %s(%d) => No option to '%s'.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_PORTS_KEYWORD); } port = _dpd.SnortStrtol( cur_tokenp, &endStr, 10); if (*endStr) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_PORTS_KEYWORD, 1, MAXPORTS-1); } if ((port < 0 || port > MAXPORTS-1) || (errno == ERANGE)) { DynamicPreprocessorFatalMessage(" %s(%d) => Value specified for %s is out of " "bounds. Please specify an integer between %d and %d.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_PORTS_KEYWORD, 1, MAXPORTS-1); } port_array[ PORT_INDEX( port ) ] |= CONV_PORT(port); cur_tokenp = strtok( NULL, GTP_CONFIG_VALUE_SEPERATORS); } if ( NULL == cur_tokenp ) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s, missing '}'.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_PORTS_KEYWORD); } if ( -1 == port) { DynamicPreprocessorFatalMessage(" %s(%d) => No ports specified.\n", *(_dpd.config_file), *(_dpd.config_line), GTP_PORTS_KEYWORD); } *ptr = cur_tokenp; } /* Parses and processes the configuration arguments * supplied in the GTP preprocessor rule. * * PARAMETERS: * * GTPConfig *config: GTP preprocessor configuration. * argp: Pointer to string containing the config arguments. * * RETURNS: Nothing. */ void ParseGTPArgs(GTPConfig *config, u_char* argp) { char* cur_sectionp = NULL; char* next_sectionp = NULL; char* argcpyp = NULL; if (NULL == config) return; /* Set up default port to listen on */ config->ports[ PORT_INDEX( GTP_C_PORT ) ] |= CONV_PORT(GTP_C_PORT); config->ports[ PORT_INDEX( GTP_C_PORT_V0 ) ] |= CONV_PORT(GTP_C_PORT_V0); InitGTPInfoElementTable(config); InitGTPMsgTypeTable(config); /* Sanity check(s) */ if (NULL == argp) { DisplayGTPConfig(config); return; } argcpyp = strdup( (char*) argp ); if ( !argcpyp ) { DynamicPreprocessorFatalMessage("Could not allocate memory to parse GTP options.\n"); return; } DEBUG_WRAP(DebugMessage(DEBUG_GTP, "GTP configurations: %s\n",argcpyp );); cur_sectionp = strtok_r( argcpyp, GTP_CONFIG_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Arguments token: %s\n",cur_sectionp );); while ( cur_sectionp ) { char* cur_config; char* cur_tokenp = strtok( cur_sectionp, GTP_CONFIG_VALUE_SEPERATORS); if (!cur_tokenp) { cur_sectionp = strtok_r( next_sectionp, GTP_CONFIG_SECTION_SEPERATORS, &next_sectionp); continue; } cur_config = cur_tokenp; if ( !strcmp( cur_tokenp, GTP_PORTS_KEYWORD )) { GTP_ParsePortList(&cur_tokenp, config->ports); } else { DynamicPreprocessorFatalMessage(" %s(%d) => Invalid argument: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp); return; } /*Check whether too many parameters*/ if (NULL != strtok( NULL, GTP_CONFIG_VALUE_SEPERATORS)) { DynamicPreprocessorFatalMessage("%s(%d) => To many arguments: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_config); } cur_sectionp = strtok_r( next_sectionp, GTP_CONFIG_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Arguments token: %s\n",cur_sectionp );); } DisplayGTPConfig(config); free(argcpyp); } /* Search the message type information * * PARAMETERS: * * uint8_t: version number for the message type * char* the message type name * * RETURNS: * * GTP_MsgType*: the message type, NULL if not found */ GTP_MsgType* GetMsgTypeByName(uint8_t version, char *name) { int i = 0; GTP_MsgType *MsgTypes; switch (version) { case 0: MsgTypes = GTPv0_MsgTypes; break; case 1: MsgTypes = GTPv1_MsgTypes; break; case 2: MsgTypes = GTPv2_MsgTypes; break; default: return NULL; } while(NULL != MsgTypes[i].name) { if ( MsgTypes[i].isKeyword &&(strlen(MsgTypes[i].name) == strlen(name)) && (0 == strncmp(MsgTypes[i].name, name, strlen(name)))) return (&(MsgTypes[i])); i++; } return NULL; } /* Search the information element information * * PARAMETERS: * * uint8_t: version number for information elements * char* the information element name * * RETURNS: * * GTP_InfoElement*: the information element, NULL if not found */ GTP_InfoElement* GetInfoElementByName(uint8_t version, char *name) { int i = 0; GTP_InfoElement *InfoElements; switch (version) { case 0: InfoElements = GTPv0_InfoElements; break; case 1: InfoElements = GTPv1_InfoElements; break; case 2: InfoElements = GTPv2_InfoElements; break; default: return NULL; } while(NULL != InfoElements[i].name) { if (InfoElements[i].isKeyword && (strlen(InfoElements[i].name) == strlen(name)) && (0 == strncmp(InfoElements[i].name, name, strlen(name)))) return (&InfoElements[i]); i++; } return NULL; } snort-2.9.6.0/src/dynamic-preprocessors/gtp/spp_gtp.h0000644000000000000000000000665212260565732017504 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2011-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * spp_gtp.h: Definitions, structs, function prototype(s) for * the GTP preprocessor. * Author: Hui Cao */ #ifndef SPP_GTP_H #define SPP_GTP_H #include #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "gtp_roptions.h" /* Convert port value into an index for the gtp_config->ports array */ #define PORT_INDEX(port) port/8 /* Convert port value into a value for bitwise operations */ #define CONV_PORT(port) 1<<(port%8) /* * Boolean values. */ #define GTP_TRUE (1) #define GTP_FALSE (0) /* * Error codes. */ #define GTP_SUCCESS (1) #define GTP_FAILURE (0) /* * Per-session data block containing current state * of the GTP preprocessor for the session. * * state_flags: Bit vector describing the current state of the * session. */ typedef struct _gtpData { uint32_t state_flags; GTP_Roptions ropts; tSfPolicyId policy_id; tSfPolicyUserContextId config; } GTPData; typedef struct _GTPMsg { uint8_t version; uint8_t msg_type; uint16_t msg_length; uint16_t header_len; uint8_t *gtp_header; GTP_IEData *info_elements; /* nothing after this point is zeroed ...*/ uint32_t msg_id; /*internal state, new msg will have a new id*/ } GTPMsg; #define GTPMSG_ZERO_LEN offsetof(GTPMsg, msg_id) /* * Generator id. Define here the same as the official registry * in generators.h */ #define GENERATOR_SPP_GTP 143 /* Ultimately calls SnortEventqAdd */ /* Arguments are: gid, sid, rev, classification, priority, message, rule_info */ #define ALERT(x,y) { _dpd.alertAdd(GENERATOR_SPP_GTP, x, 1, 0, 3, y, 0 ); gtp_stats.events++; } /* * GTP preprocessor alert types. */ #define GTP_EVENT_BAD_MSG_LEN (1) #define GTP_EVENT_BAD_IE_LEN (2) #define GTP_EVENT_OUT_OF_ORDER_IE (3) /* * GTP preprocessor alert strings. */ #define GTP_EVENT_BAD_MSG_LEN_STR "(spp_gtp) Message length is invalid" #define GTP_EVENT_BAD_IE_LEN_STR "(spp_gtp) Information element length is invalid" #define GTP_EVENT_OUT_OF_ORDER_IE_STR "(spp_gtp) Information elements are out of order" typedef struct _GTP_Stats { uint64_t sessions; uint64_t events; uint64_t unknownTypes; uint64_t unknownIEs; uint64_t messages[MAX_GTP_VERSION_CODE + 1][MAX_GTP_TYPE_CODE + 1]; GTP_MsgType *msgTypeTable[MAX_GTP_VERSION_CODE + 1][MAX_GTP_TYPE_CODE + 1]; } GTP_Stats; extern GTP_Stats gtp_stats; extern GTPConfig *gtp_eval_config; extern tSfPolicyUserContextId gtp_config; /* Prototypes for public interface */ void SetupGTP(void); #endif /* SPP_GTP_H */ snort-2.9.6.0/src/dynamic-preprocessors/gtp/spp_gtp.c0000644000000000000000000005216712260565732017501 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2011-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * GTP preprocessor * * This is the main entry point for this preprocessor * * Author: Hui Cao * Date: 07-15-2011 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_plugin_api.h" #include "snort_debug.h" #include "preprocids.h" #include "spp_gtp.h" #include "gtp_config.h" #include "gtp_roptions.h" #include "gtp_parser.h" #include #include #include #include #ifndef WIN32 #include #include #endif #include #include #include "profiler.h" #ifdef PERF_PROFILING PreprocStats gtpPerfStats; #endif #include "sf_types.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_GTP"; #define SetupGTP DYNAMIC_PREPROC_SETUP #ifdef TARGET_BASED int16_t gtp_app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif /* * Session state flags for GTPData::state_flags */ #define GTP_FLG_REASSEMBLY_SET (0x20000) /* * Function prototype(s) */ GTPData * GTPGetNewSession(SFSnortPacket *, tSfPolicyId); static void GTPInit( struct _SnortConfig *, char* ); static int GTPCheckConfig(struct _SnortConfig *); static void FreeGTPData( void* ); static inline int GTP_Process(SFSnortPacket *, GTPData*); static void GTPmain( void*, void* ); static inline int CheckGTPPort( uint16_t ); static void GTPFreeConfig(tSfPolicyUserContextId); static void _addPortsToStream5Filter(struct _SnortConfig *, GTPConfig *, tSfPolicyId); static void GTP_PrintStats(int); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static void GTPCleanExit(int, void *); /******************************************************************** * Global variables ********************************************************************/ uint32_t numSessions = 0; GTP_Stats gtp_stats; GTPConfig *gtp_eval_config; tSfPolicyUserContextId gtp_config; #ifdef SNORT_RELOAD static void GTPReload(struct _SnortConfig *, char *, void **); static int GTPReloadVerify(struct _SnortConfig *, void *); static void * GTPReloadSwap(struct _SnortConfig *, void *); static void GTPReloadSwapFree(void *); #endif /* Called at preprocessor setup time. Links preprocessor keyword * to corresponding preprocessor initialization function. * * PARAMETERS: None. * * RETURNS: Nothing. * */ void SetupGTP(void) { /* Link preprocessor keyword to initialization function * in the preprocessor list. */ #ifndef SNORT_RELOAD _dpd.registerPreproc( "gtp", GTPInit ); #else _dpd.registerPreproc("gtp", GTPInit, GTPReload, GTPReloadVerify, GTPReloadSwap, GTPReloadSwapFree); #endif } /* Initializes the GTP preprocessor module and registers * it in the preprocessor list. * * PARAMETERS: * * argp: Pointer to argument string to process for config data. * * RETURNS: Nothing. */ static void GTPInit(struct _SnortConfig *sc, char *argp) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); GTPConfig *pDefaultPolicyConfig = NULL; GTPConfig *pPolicyConfig = NULL; if (gtp_config == NULL) { /*create a context*/ gtp_config = sfPolicyConfigCreate(); if (gtp_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for GTP config.\n"); } _dpd.addPreprocConfCheck(sc, GTPCheckConfig); _dpd.registerPreprocStats(GTP_NAME, GTP_PrintStats); _dpd.addPreprocExit(GTPCleanExit, NULL, PRIORITY_LAST, PP_GTP); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("gtp", (void *)>pPerfStats, 0, _dpd.totalPerfStats); #endif #ifdef TARGET_BASED gtp_app_id = _dpd.findProtocolReference("gtp"); if (gtp_app_id == SFTARGET_UNKNOWN_PROTOCOL) gtp_app_id = _dpd.addProtocolReference("gtp"); #endif } sfPolicyUserPolicySet (gtp_config, policy_id); pDefaultPolicyConfig = (GTPConfig *)sfPolicyUserDataGetDefault(gtp_config); pPolicyConfig = (GTPConfig *)sfPolicyUserDataGetCurrent(gtp_config); if ((pPolicyConfig != NULL) && (pDefaultPolicyConfig == NULL)) { DynamicPreprocessorFatalMessage("GTP preprocessor can only be " "configured once.\n"); } pPolicyConfig = (GTPConfig *)calloc(1, sizeof(GTPConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "GTP preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(gtp_config, pPolicyConfig); GTP_RegRuleOptions(sc); ParseGTPArgs(pPolicyConfig, (u_char *)argp); if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupGTP(): The Stream preprocessor must be enabled.\n"); } _dpd.addPreproc( sc, GTPmain, PRIORITY_APPLICATION, PP_GTP, PROTO_BIT__UDP ); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } /********************************************************************* * Main entry point for GTP processing. * * Arguments: * SFSnortPacket * - pointer to packet structure * * Returns: * int - GTP_SUCCESS * GTP_FAILURE * *********************************************************************/ static inline int GTP_Process(SFSnortPacket *p, GTPData* sessp) { int status; const uint8_t* gtp_buff = p->payload; static uint32_t msgId = 0; GTP_Roptions *pRopts; GTPMsg gtpMsg; pRopts = &(sessp->ropts); memset(>pMsg, 0, GTPMSG_ZERO_LEN); /* msg_id is used to associate message with information elements * If msg_id matches, the information element in the info_elements * belongs to the message * Using msg_id avoids initializing info_elements for every message * Tabled based info_elements improves information element search performance */ /* To avoid id overlap, clean table when msgId resets*/ if ( msgId == 0) gtp_cleanInfoElements(); gtpMsg.msg_id = ++msgId; status = gtp_parse(>pMsg, gtp_buff, p->payload_size); /*Update the session data*/ pRopts->gtp_type = gtpMsg.msg_type; pRopts->gtp_version = gtpMsg.version; pRopts->gtp_infoElements = gtpMsg.info_elements; pRopts->gtp_header = gtpMsg.gtp_header; pRopts->msg_id = gtpMsg.msg_id; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "GTP message version: %d\n", gtpMsg.version)); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "GTP message type: %d\n", gtpMsg.msg_type)); return status; } /* Main runtime entry point for GTP preprocessor. * Analyzes GTP packets for anomalies/exploits. * * PARAMETERS: * * packetp: Pointer to current packet to process. * contextp: Pointer to context block, not used. * * RETURNS: Nothing. */ static void GTPmain( void* ipacketp, void* contextp ) { GTPData* sessp = NULL; uint8_t source = 0; uint8_t dest = 0; SFSnortPacket* packetp; #ifdef TARGET_BASED int16_t app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "%s\n", GTP_DEBUG__START_MSG)); packetp = (SFSnortPacket*) ipacketp; sfPolicyUserPolicySet (gtp_config, policy_id); // precoditions - what we registered for assert(IsUDP(packetp) && packetp->payload && packetp->payload_size); PREPROC_PROFILE_START(gtpPerfStats); gtp_eval_config = sfPolicyUserDataGetCurrent(gtp_config); /* Attempt to get a previously allocated GTP block. */ sessp = _dpd.streamAPI->get_application_data(packetp->stream_session_ptr, PP_GTP); if (sessp != NULL) { gtp_eval_config = sfPolicyUserDataGet(sessp->config, sessp->policy_id); } if (sessp == NULL) { /* If not doing autodetection, check the ports to make sure this is * running on an GTP port, otherwise no need to examine the traffic. */ #ifdef TARGET_BASED app_id = _dpd.streamAPI->get_application_protocol_id(packetp->stream_session_ptr); if (app_id == SFTARGET_UNKNOWN_PROTOCOL) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Unknown protocol - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "%s\n", GTP_DEBUG__END_MSG)); PREPROC_PROFILE_END(gtpPerfStats); return; } else if (app_id && (app_id != gtp_app_id)) { DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Not GTP - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "%s\n", GTP_DEBUG__END_MSG)); PREPROC_PROFILE_END(gtpPerfStats); return; } else if (!app_id) { #endif source = (uint8_t)CheckGTPPort( packetp->src_port ); dest = (uint8_t)CheckGTPPort( packetp->dst_port ); if ( !source && !dest ) { /* Not one of the ports we care about. */ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Not GTP ports - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "%s\n", GTP_DEBUG__END_MSG)); PREPROC_PROFILE_END(gtpPerfStats); return; } #ifdef TARGET_BASED } #endif /* Check the stream session. If it does not currently * have our GTP data-block attached, create one. */ sessp = GTPGetNewSession(packetp, policy_id); if ( !sessp ) { /* Could not get/create the session data for this packet. */ DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Create session error - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "%s\n", GTP_DEBUG__END_MSG)); PREPROC_PROFILE_END(gtpPerfStats); return; } } /* We're interested in this session. Turn on stream reassembly. */ if ( !(sessp->state_flags & GTP_FLG_REASSEMBLY_SET )) { _dpd.streamAPI->set_reassembly(packetp->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_BOTH, STREAM_FLPOLICY_SET_ABSOLUTE); sessp->state_flags |= GTP_FLG_REASSEMBLY_SET; } /* * Start process PAYLOAD */ GTP_Process(packetp,sessp); DEBUG_WRAP(DebugMessage(DEBUG_GTP, "%s\n", GTP_DEBUG__END_MSG)); PREPROC_PROFILE_END(gtpPerfStats); } /********************************************************************** * Retrieves the GTP data block registered with the stream * session associated w/ the current packet. If none exists, * allocates it and registers it with the stream API. * * Arguments: * * packetp: Pointer to the packet from which/in which to * retrieve/store the GTP data block. * * RETURNS: Pointer to an GTP data block, upon success. * NULL, upon failure. **********************************************************************/ GTPData * GTPGetNewSession(SFSnortPacket *packetp, tSfPolicyId policy_id) { GTPData* datap = NULL; /* Sanity check(s) */ assert( packetp ); if ( !packetp->stream_session_ptr ) { return NULL; } datap = (GTPData *)calloc(1, sizeof(GTPData)); if ( !datap ) return NULL; /*Register the new GTP data block in the stream session. */ _dpd.streamAPI->set_application_data( packetp->stream_session_ptr, PP_GTP, datap, FreeGTPData ); datap->policy_id = policy_id; datap->config = gtp_config; ((GTPConfig *)sfPolicyUserDataGetCurrent(gtp_config))->ref_count++; gtp_stats.sessions++; DEBUG_WRAP(DebugMessage(DEBUG_GTP, "Number of sessions created: %u\n", gtp_stats.sessions)); return datap; } /*********************************************************************** * Registered as a callback with our GTP data blocks when * they are added to the underlying stream session. Called * by the stream preprocessor when a session is about to be * destroyed. * * PARAMETERS: * * idatap: Pointer to the moribund data. * * RETURNS: Nothing. ***********************************************************************/ static void FreeGTPData( void* idatap ) { GTPData *ssn = (GTPData *)idatap; GTPConfig *config = NULL; if (ssn == NULL) return; if (numSessions > 0) numSessions--; /*Clean the configuration data*/ if (ssn->config != NULL) { config = (GTPConfig *)sfPolicyUserDataGet(ssn->config, ssn->policy_id); } if (config == NULL) { free(ssn); return; } config->ref_count--; if ((config->ref_count == 0) && (ssn->config != gtp_config)) { sfPolicyUserDataClear (ssn->config, ssn->policy_id); free(config); if (sfPolicyUserPolicyGetActive(ssn->config) == 0) { /* No more outstanding configs - free the config array */ GTPFreeConfig(ssn->config); } } free(ssn); } /* ********************************************************************** * Validates given port as an GTP server port. * * PARAMETERS: * * port: Port to validate. * * RETURNS: GTP_TRUE, if the port is indeed an GTP server port. * GTP_FALSE, otherwise. ***********************************************************************/ static inline int CheckGTPPort( uint16_t port ) { if ( gtp_eval_config->ports[ PORT_INDEX(port) ] & CONV_PORT( port ) ) { return GTP_TRUE; } return GTP_FALSE; } /* ********************************************************************** * Add ports in the configuration to stream5 filter. * * PARAMETERS: * * GTPConfig: configuration to be used. * tSfPolicyId: policy ID * * RETURNS: None ***********************************************************************/ static void _addPortsToStream5Filter(struct _SnortConfig *sc, GTPConfig *config, tSfPolicyId policy_id) { int portNum; assert(config); assert(_dpd.streamAPI); for (portNum = 0; portNum < MAXPORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_UDP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status(sc, gtp_app_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif static int GTPCheckPolicyConfig(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData) { _dpd.setParserPolicy(sc, policyId); if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("GTPCheckPolicyConfig(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } int GTPCheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate (sc, gtp_config, GTPCheckPolicyConfig))) return rval; return 0; } static void GTPCleanExit(int signal, void *data) { if (gtp_config != NULL) { GTPFreeConfig(gtp_config); gtp_config = NULL; } } static int GTPFreeConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { GTPConfig *pPolicyConfig = (GTPConfig *)pData; //do any housekeeping before freeing GTPConfig sfPolicyUserDataClear (config, policyId); free(pPolicyConfig); return 0; } void GTPFreeConfig(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, GTPFreeConfigPolicy); sfPolicyConfigDelete(config); } /****************************************************************** * Print statistics being kept by the preprocessor. * * Arguments: * int - whether Snort is exiting or not * * Returns: None * ******************************************************************/ static void GTP_PrintStats(int exiting) { int i, j; _dpd.logMsg("GTP Preprocessor Statistics\n"); _dpd.logMsg(" Total sessions: "STDu64"\n", gtp_stats.sessions); if (gtp_stats.sessions < 1) return; if (gtp_stats.events > 0) _dpd.logMsg(" Preprocessor events: "STDu64"\n", gtp_stats.events); _dpd.logMsg(" Total reserved messages: "STDu64"\n", gtp_stats.unknownTypes); _dpd.logMsg(" Packets with reserved information elements: "STDu64"\n", gtp_stats.unknownIEs); for (i = 0; i < MAX_GTP_VERSION_CODE + 1; i++ ) { uint64_t total_msgs = 0; DEBUG_WRAP(_dpd.logMsg(" Messages of version %d:\n", i);); for(j = 0; j < MAX_GTP_TYPE_CODE + 1; j++) { GTP_MsgType *msg = gtp_stats.msgTypeTable[i][j]; if ( msg && msg->name) { DEBUG_WRAP(_dpd.logMsg("%39s: "STDu64"\n", msg->name, gtp_stats.messages[i][j]);); } total_msgs += gtp_stats.messages[i][j]; } if (total_msgs > 0) _dpd.logMsg(" Total messages of version %d: %u\n", i, total_msgs); } } #ifdef SNORT_RELOAD static void GTPReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId gtp_swap_config = (tSfPolicyUserContextId)*new_config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); GTPConfig * pPolicyConfig = NULL; if (gtp_swap_config == NULL) { //create a context gtp_swap_config = sfPolicyConfigCreate(); if (gtp_swap_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for GTP config.\n"); } *new_config = (void *)gtp_swap_config; } sfPolicyUserPolicySet (gtp_swap_config, policy_id); pPolicyConfig = (GTPConfig *)sfPolicyUserDataGetCurrent(gtp_swap_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("GTP preprocessor can only be " "configured once.\n"); } pPolicyConfig = (GTPConfig *)calloc(1, sizeof(GTPConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "GTP preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(gtp_swap_config, pPolicyConfig); GTP_RegRuleOptions(sc); ParseGTPArgs(pPolicyConfig, (u_char *)args); if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupGTP(): The Stream preprocessor must be enabled.\n"); } _dpd.addPreproc( sc, GTPmain, PRIORITY_APPLICATION, PP_GTP, PROTO_BIT__UDP ); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } static int GTPReloadVerify(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId gtp_swap_config = (tSfPolicyUserContextId)swap_config; GTPConfig * pPolicyConfig = NULL; GTPConfig * pCurrentConfig = NULL; if (gtp_swap_config == NULL) return 0; pPolicyConfig = (GTPConfig *)sfPolicyUserDataGet(gtp_swap_config, _dpd.getDefaultPolicy()); if (!pPolicyConfig) return 0; if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SetupGTP(): The Stream preprocessor must be enabled.\n"); return -1; } if (gtp_config != NULL) { pCurrentConfig = (GTPConfig *)sfPolicyUserDataGet(gtp_config, _dpd.getDefaultPolicy()); } if (!pCurrentConfig) return 0; return 0; } static int GTPFreeUnusedConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { GTPConfig *pPolicyConfig = (GTPConfig *)pData; //do any housekeeping before freeing GTPConfig if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); free(pPolicyConfig); } return 0; } static void * GTPReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId gtp_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = gtp_config; if (gtp_swap_config == NULL) return NULL; gtp_config = gtp_swap_config; sfPolicyUserDataFreeIterate (old_config, GTPFreeUnusedConfigPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) { /* No more outstanding configs - free the config array */ return (void *)old_config; } return NULL; } static void GTPReloadSwapFree(void *data) { if (data == NULL) return; GTPFreeConfig((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/gtp/Makefile.am0000644000000000000000000000135511746560364017712 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_gtp_preproc.la libsf_gtp_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_gtp_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_gtp_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sfPolicyUserData.c endif libsf_gtp_preproc_la_SOURCES = \ spp_gtp.c \ spp_gtp.h \ gtp_config.c \ gtp_config.h \ gtp_parser.c \ gtp_parser.h \ gtp_roptions.c \ gtp_roptions.h \ gtp_debug.h EXTRA_DIST = \ sf_gtp.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/gtp/Makefile.in0000644000000000000000000005067212260606522017716 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/gtp DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_gtp_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_gtp_preproc_la_OBJECTS = spp_gtp.lo gtp_config.lo \ gtp_parser.lo gtp_roptions.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_gtp_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_gtp_preproc_la_OBJECTS = $(am_libsf_gtp_preproc_la_OBJECTS) \ $(nodist_libsf_gtp_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_gtp_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_gtp_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_gtp_preproc_la_SOURCES) \ $(nodist_libsf_gtp_preproc_la_SOURCES) DIST_SOURCES = $(libsf_gtp_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_gtp_preproc.la libsf_gtp_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_gtp_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_gtp_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_gtp_preproc_la_SOURCES = \ spp_gtp.c \ spp_gtp.h \ gtp_config.c \ gtp_config.h \ gtp_parser.c \ gtp_parser.h \ gtp_roptions.c \ gtp_roptions.h \ gtp_debug.h EXTRA_DIST = \ sf_gtp.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/gtp/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/gtp/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_gtp_preproc.la: $(libsf_gtp_preproc_la_OBJECTS) $(libsf_gtp_preproc_la_DEPENDENCIES) $(EXTRA_libsf_gtp_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_gtp_preproc_la_LINK) -rpath $(libdir) $(libsf_gtp_preproc_la_OBJECTS) $(libsf_gtp_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/reputation/0000755000000000000000000000000012260606564017325 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/reputation/sf_reputation.dsp0000644000000000000000000001416412153454770022646 00000000000000# Microsoft Developer Studio Project File - Name="sf_reputation" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_reputation - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_reputation.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_reputation.mak" CFG="sf_reputation - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_reputation - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_reputation - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_reputation - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /YX /FD /c # SUBTRACT CPP /X # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_reputation - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "SF_SNORT_PREPROC_DLL" /D "_DEBUG" /D "DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /YX /FD /GZ /c # SUBTRACT CPP /X # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_reputation - Win32 Release" # Name "sf_reputation - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\inet_aton.c # End Source File # Begin Source File SOURCE=..\include\inet_pton.c # End Source File # Begin Source File SOURCE=.\reputation_config.c # End Source File # Begin Source File SOURCE=.\reputation_utils.c # End Source File # Begin Source File SOURCE=..\include\segment_mem.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_ip.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=..\include\sfrt.c # End Source File # Begin Source File SOURCE=..\include\sfrt_dir.c # End Source File # Begin Source File SOURCE=..\include\sfrt_flat.c # End Source File # Begin Source File SOURCE=..\include\sfrt_flat_dir.c # End Source File # Begin Source File SOURCE=.\spp_reputation.c # End Source File # Begin Source File SOURCE=..\include\strtok_r.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\reputation_config.h # End Source File # Begin Source File SOURCE=.\reputation_debug.h # End Source File # Begin Source File SOURCE=.\reputation_utils.h # End Source File # Begin Source File SOURCE=..\include\segment_mem.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=..\include\sfrt_flat.h # End Source File # Begin Source File SOURCE=..\include\sfrt_flat_dir.h # End Source File # Begin Source File SOURCE=.\spp_reputation.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/reputation/reputation_debug.h0000644000000000000000000000355012260565732022762 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides macros and functions for debugging the preprocessor. * If Snort is not configured to do debugging, macros are empty. * * 6/11/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef _REPUTATION_DEBUG_H_ #define _REPUTATION_DEBUG_H_ #include #include "sfPolicyUserData.h" /******************************************************************** * Macros ********************************************************************/ #define DEBUG_REPUTATION 0x00000020 /* 16 */ #define REPUTATION_DEBUG__START_MSG "REPUTATION Start ********************************************" #define REPUTATION_DEBUG__END_MSG "REPUTATION End **********************************************" #endif /* _REPUTATION_DEBUG_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/reputation/reputation_utils.h0000644000000000000000000000267312260565732023041 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions. * * 6/11/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef REPUTATION_UTILS_H_ #define REPUTATION_UTILS_H_ #include "sf_ip.h" #include "sf_snort_packet.h" #include int Reputation_IsEmptyStr(char *); int numLinesInFile(char *fname); #endif /* REPUTATION_UTILS_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/reputation/reputation_utils.c0000644000000000000000000000537412260565732023035 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions. * * 6/11/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "reputation_utils.h" #include #include #define MAX_ADDR_LINE_LENGTH 8192 /******************************************************************** * Function: Reputation_IsEmptyStr() * * Checks if string is NULL, empty or just spaces. * String must be 0 terminated. * * Arguments: * char * - string to check * * Returns: * 1 if string is NULL, empty or just spaces * 0 otherwise * ********************************************************************/ int Reputation_IsEmptyStr(char *str) { char *end; if (str == NULL) return 1; end = str + strlen(str); while ((str < end) && isspace((int)*str)) str++; if (str == end) return 1; return 0; } /******************************************************************** * Function: numLinesInFile() * * Number of lines in the file * * Arguments: * fname: file name * * Returns: * uint32_t number of lines * ********************************************************************/ int numLinesInFile(char *fname) { FILE *fp; uint32_t numlines = 0; char buf[MAX_ADDR_LINE_LENGTH]; fp = fopen(fname, "rb"); if (NULL == fp) return 0; while((fgets(buf, MAX_ADDR_LINE_LENGTH, fp)) != NULL) { if (buf[0] != '#') { numlines++; if (numlines == INT_MAX) { fclose(fp); return INT_MAX; } } } fclose(fp); return numlines; } snort-2.9.6.0/src/dynamic-preprocessors/reputation/reputation_config.h0000644000000000000000000000714512260565732023145 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 6/11/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef _REPUTATION_CONFIG_H_ #define _REPUTATION_CONFIG_H_ #include "sf_types.h" #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "reputation_debug.h" #include "sf_ip.h" #include "sfrt_flat.h" #ifdef SHARED_REP #include "./shmem/shmem_mgmt.h" #endif #define REPUTATION_NAME "reputation" typedef enum _NestedIP { INNER, OUTER, BOTH }NestedIP; typedef enum _WhiteAction { UNBLACK, TRUST }WhiteAction; typedef struct _SharedMem { char *path; uint32_t updateInterval; }SharedMem; typedef enum _IPdecision { DECISION_NULL , MONITORED, BLACKLISTED , WHITELISTED_UNBLACK, WHITELISTED_TRUST, DECISION_MAX }IPdecision; typedef struct _ListInfo{ uint8_t listIndex; uint8_t listType; uint32_t listId; #ifdef SHARED_REP bool zones[MAX_NUM_ZONES]; char padding[2 + MAX_NUM_ZONES - MAX_NUM_ZONES/4*4]; #endif } ListInfo; /* * Reputation preprocessor configuration. * * memcap: the memcap for IP table. * numEntries: number of entries in the table * scanlocal: to scan local network * prioirity: the priority of whitelist, blacklist * nestedIP: which IP address to use when IP encapsulation * iplist: the IP table * ref_count: reference account */ typedef struct _reputationConfig { uint32_t memcap; int numEntries; uint8_t scanlocal; IPdecision priority; NestedIP nestedIP; WhiteAction whiteAction; MEM_OFFSET local_black_ptr; MEM_OFFSET local_white_ptr; void *emptySegment; void *localSegment; SharedMem sharedMem; int segment_version; uint32_t memsize; bool memCapReached; table_flat_t *iplist; ListInfo *listInfo; int ref_count; char *statusBuf; int statusBuf_len; } ReputationConfig; #define NUM_INDEX_PER_ENTRY 4 typedef struct _IPrepInfo{ char listIndexes[NUM_INDEX_PER_ENTRY]; MEM_OFFSET next; } IPrepInfo; /******************************************************************** * Public function prototypes ********************************************************************/ void Reputation_FreeConfig(ReputationConfig *); void ParseReputationArgs(ReputationConfig *, u_char*); void initShareMemory(struct _SnortConfig *sc, void *config); void ReputationRepInfo(IPrepInfo *, uint8_t *, char *, int); DEBUG_WRAP(void ReputationPrintRepInfo(IPrepInfo * repInfo, uint8_t *base);) #endif snort-2.9.6.0/src/dynamic-preprocessors/reputation/reputation_config.c0000644000000000000000000016401012260565732023133 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 6/7/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "sf_snort_packet.h" #include "sf_types.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "reputation_config.h" #include "spp_reputation.h" #include "reputation_debug.h" #include "reputation_utils.h" #ifdef SHARED_REP #include "./shmem/shmem_mgmt.h" #include #endif enum { IP_INSERT_SUCCESS = 0, IP_INVALID, IP_INSERT_FAILURE, IP_INSERT_DUPLICATE, IP_MEM_ALLOC_FAILURE }; /* * Default values for configurable parameters. */ #define REPUTATION_DEFAULT_MEMCAP 500 /*Mega bytes*/ #define REPUTATION_DEFAULT_REFRESH_PERIOD 60 /*60 seconds*/ /* * Min/Max values for each configurable parameter. */ #define MIN_MEMCAP 1 #define MAX_MEMCAP 4095 #define MIN_SHARED_MEM_REFRESH_PERIOD 1 #define MAX_SHARED_MEM_REFRESH_PERIOD UINT32_MAX #define MAX_ADDR_LINE_LENGTH 8192 /* * Keyword strings for parsing configuration options. */ #define REPUTATION_MEMCAP_KEYWORD "memcap" #define REPUTATION_SCANLOCAL_KEYWORD "scan_local" #define REPUTATION_BLACKLIST_KEYWORD "blacklist" #define REPUTATION_WHITELIST_KEYWORD "whitelist" #define REPUTATION_MONITORLIST_KEYWORD "monitorlist" #define REPUTATION_PRIORITY_KEYWORD "priority" #define REPUTATION_NESTEDIP_KEYWORD "nested_ip" #define REPUTATION_SHAREMEM_KEYWORD "shared_mem" #define REPUTATION_SHAREDREFRESH_KEYWORD "shared_refresh" #define REPUTATION_WHITEACTION_KEYWORD "white" #define REPUTATION_CONFIG_SECTION_SEPERATORS ",;" #define REPUTATION_CONFIG_VALUE_SEPERATORS " " #define REPUTATION_SEPARATORS " \t\r\n" static char *black_info = REPUTATION_BLACKLIST_KEYWORD; static char *white_info = REPUTATION_WHITELIST_KEYWORD; static char *monitor_info = REPUTATION_MONITORLIST_KEYWORD; char* NestedIPKeyword[] = { "inner", "outer", "both", NULL }; char* WhiteActionOption[] = { "unblack", "trust", NULL }; #define MAX_MSGS_TO_PRINT 20 static unsigned long total_duplicates; static unsigned long total_invalids; void **IPtables; #ifdef SHARED_REP ReputationConfig *reputation_shmem_config; table_flat_t *emptyIPtables; #endif /* * Function prototype(s) */ static void IpListInit(uint32_t,ReputationConfig *config); static void LoadListFile(char *filename, INFO info, ReputationConfig *config); static void DisplayIPlistStats(ReputationConfig *); static void DisplayReputationConfig(ReputationConfig *); /* ******************************************************************** * Function: estimateSizeFromEntries * * Estimate the memory segment size based on number of entries and memcap. * * Arguments: * * uint32_t num_entries: number of entries. * uint32_t the memcap value set in configuration * * RETURNS: estimated memory size. *********************************************************************/ uint32_t estimateSizeFromEntries(uint32_t num_entries, uint32_t memcap) { uint64_t size; uint64_t sizeFromEntries; /*memcap value is in Megabytes*/ size = (uint64_t)memcap << 20; if (size > UINT32_MAX) size = UINT32_MAX; /*Worst case, 15k ~ 2^14 per entry, plus one Megabytes for empty table*/ if (num_entries > ((UINT32_MAX - (1 << 20))>> 15)) sizeFromEntries = UINT32_MAX; else sizeFromEntries = (num_entries << 15) + (1 << 20); if (size > sizeFromEntries) { size = sizeFromEntries; } return (uint32_t) size; } #ifdef SHARED_REP /**************************************************************************** * * Function: CheckIPlistDir() * * Purpose: We only check if IP list directory exist and * readable * Arguments: None. * * Returns: * 0 : fail * 1 : success * ****************************************************************************/ static int CheckIPlistDir(char *path) { struct stat st; if (path == NULL) return 0; if (stat(path, &st) == -1) return 0; if (!S_ISDIR(st.st_mode) || (access(path, R_OK) == -1)) { return 0; } return 1; } /* ******************************************************************** * Function: LoadFileIntoShmem * * Call back function for shared memory * This is called when new files in the list * Arguments: * * void* ptrSegment: start of shared memory segment. * ShmemDataFileList** file_list: the list of whitelist/blacklist files * int num_files: number of files * * RETURNS: * 0: success * other value fails *********************************************************************/ int LoadFileIntoShmem(void* ptrSegment, ShmemDataFileList** file_list, int num_files) { table_flat_t *table; int i; MEM_OFFSET list_ptr; ListInfo *listInfo; uint8_t *base; if (num_files > MAX_IPLIST_FILES) { _dpd.logMsg("Reputation preprocessor: Too many IP list files. " "The maximum is: %d, current is: %d.\n", MAX_IPLIST_FILES, num_files); num_files = MAX_IPLIST_FILES; } segment_meminit((uint8_t*)ptrSegment, reputation_shmem_config->memsize); /*DIR_16x7_4x4 for performance, but memory usage is high *Use DIR_8x16 worst case IPV4 5K, IPV6 15K (bytes) *Use DIR_16x7_4x4 worst case IPV4 500, IPV6 2.5M */ table = sfrt_flat_new(DIR_8x16, IPv6, reputation_shmem_config->numEntries, reputation_shmem_config->memcap); if (table == NULL) { DynamicPreprocessorFatalMessage("Reputation preprocessor: Failed to create IP list.\n"); } reputation_shmem_config->iplist = table; base = (uint8_t *)ptrSegment; /*Copy the list information table to shared memory block*/ list_ptr = segment_calloc(num_files, sizeof(ListInfo)); if (list_ptr == 0) { DynamicPreprocessorFatalMessage("Reputation preprocessor:: Failed to create IP list table.\n"); } listInfo = (ListInfo *)&base[list_ptr]; table->list_info = list_ptr; reputation_shmem_config->listInfo = listInfo; reputation_shmem_config->memCapReached = false; /*Reset the log message count*/ total_duplicates = 0; for (i = 0; i < num_files; i++) { listInfo[i].listIndex = (uint8_t)i + 1; listInfo[i].listType = (uint8_t)file_list[i]->filetype; listInfo[i].listId = file_list[i]->listid; memcpy(listInfo[i].zones, file_list[i]->zones, MAX_NUM_ZONES); LoadListFile(file_list[i]->filename, list_ptr, reputation_shmem_config); list_ptr += sizeof(ListInfo); } _dpd.logMsg("Reputation Preprocessor shared memory summary:\n"); DisplayIPlistStats(reputation_shmem_config); return 0; } /* ******************************************************************** * Function: GetSegmentSizeFromFileList * * Call back function for shared memory * This is called when new files in the list * * Arguments: * * ShmemDataFileList** file_list: the list of whitelist/blacklist files * int num_files: number of files * * RETURNS: * uint32_t: segment size *********************************************************************/ uint32_t GetSegmentSizeFromFileList(ShmemDataFileList** file_list, int file_count) { int numlines; int totalLines = 0; int i; if (file_count == 0) { return ZEROSEG; } for (i = 0; i < file_count; i++) { errno = 0; numlines = numLinesInFile(file_list[i]->filename); if ((0 == numlines) && (0 != errno)) { char errBuf[STD_BUF]; #ifdef WIN32 snprintf(errBuf, STD_BUF, "%s", strerror(errno)); #else strerror_r(errno, errBuf, STD_BUF); #endif DynamicPreprocessorFatalMessage( "Unable to open address file %s, Error: %s\n", file_list[i]->filename, errBuf); } if (totalLines + numlines < totalLines) { DynamicPreprocessorFatalMessage("Too many entries.\n"); } totalLines += numlines; } if (totalLines == 0) { return ZEROSEG; } reputation_shmem_config->numEntries = totalLines + 1; reputation_shmem_config->memsize = estimateSizeFromEntries(reputation_shmem_config->numEntries, reputation_shmem_config->memcap); return reputation_shmem_config->memsize; } /* ******************************************************************** * Function: InitPerProcessZeroSegment * * Call back function for shared memory * This is called during initialization * * Arguments: * * void*** data_ptr: (output) the address of shared memory address * * RETURNS: * uint32_t: segment size *********************************************************************/ int InitPerProcessZeroSegment(void*** data_ptr) { /*The size of empty segment is 1 Megabytes*/ size_t size = 1; long maxEntries = 1; static bool initiated = false; if (true == initiated) { *data_ptr = (void **)&emptyIPtables; return 0; } reputation_shmem_config->emptySegment = malloc(size*1024*1024); if (reputation_shmem_config->emptySegment == NULL) { DynamicPreprocessorFatalMessage( "Failed to allocate memory for empty segment.\n"); } segment_meminit((uint8_t*) reputation_shmem_config->emptySegment, size*1024*1024); initiated = true; /*DIR_16x7_4x4 for performance, but memory usage is high *Use DIR_8x16 worst case IPV4 5K, IPV6 15K (bytes) *Use DIR_16x7_4x4 worst case IPV4 500, IPV6 2.5M */ emptyIPtables = sfrt_flat_new(DIR_8x16, IPv6, maxEntries, size); if (emptyIPtables == NULL) { DynamicPreprocessorFatalMessage("Reputation preprocessor: Failed to create IP list.\n"); } *data_ptr = (void **)&emptyIPtables; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, " Total memory " "allocated for empty table: %d bytes\n", sfrt_flat_usage(emptyIPtables));); return 0; } /* ******************************************************************** * Function: initShareMemory * * Initialize for shared memory * This is called during initialization * * Arguments: * * ReputationConfig *config: the configure file * * RETURNS: * 1: success *********************************************************************/ void initShareMemory(struct _SnortConfig *sc, void *conf) { uint32_t snortID; ReputationConfig *config = (ReputationConfig *)conf; switch_state = SWITCHING; reputation_shmem_config = config; if (InitShmemDataMgmtFunctions(InitPerProcessZeroSegment, GetSegmentSizeFromFileList,LoadFileIntoShmem)) { DynamicPreprocessorFatalMessage("Unable to initialize DataManagement functions\n"); } /*use snort instance ID to designate server (writer)*/ snortID = _dpd.getSnortInstance(); if (SHMEM_SERVER_ID == snortID) { if ((available_segment = InitShmemWriter(snortID,IPREP,GROUP_0,NUMA_0, config->sharedMem.path, &IPtables,config->sharedMem.updateInterval)) == NO_ZEROSEG) { DynamicPreprocessorFatalMessage("Unable to init share memory writer\n"); } switch_state = SWITCHED; } else { if ((available_segment = InitShmemReader(snortID,IPREP,GROUP_0,NUMA_0, config->sharedMem.path, &IPtables,config->sharedMem.updateInterval)) == NO_ZEROSEG) { DynamicPreprocessorFatalMessage("Unable to init share memory reader\n"); } switch_state = SWITCHED; } SetupReputationUpdate(config->sharedMem.updateInterval); } #endif /* ******************************************************************** * Function: DisplayIPlistStats * * Display the statistics for the Reputation iplist table. * * Arguments: * * ReputationConfig *config: Reputation preprocessor configuration. * * RETURNS: Nothing. *********************************************************************/ static void DisplayIPlistStats(ReputationConfig *config) { /*Print out the summary*/ reputation_stats.memoryAllocated = sfrt_flat_usage(config->iplist); _dpd.logMsg(" Reputation total memory usage: %u bytes\n", reputation_stats.memoryAllocated); config->numEntries = sfrt_flat_num_entries(config->iplist); _dpd.logMsg(" Reputation total entries loaded: %u, invalid: %u, re-defined: %u\n", config->numEntries,total_invalids,total_duplicates); } /* ******************************************************************** * Function: DisplayReputationConfig * * Display the configuration for the Reputation preprocessor. * * Arguments: * * ReputationConfig *config: Reputation preprocessor configuration. * * RETURNS: Nothing. *********************************************************************/ static void DisplayReputationConfig(ReputationConfig *config) { if (config == NULL) return; _dpd.logMsg(" Memcap: %d %s \n", config->memcap, config->memcap == REPUTATION_DEFAULT_MEMCAP ? "(Default) M bytes" : "M bytes" ); _dpd.logMsg(" Scan local network: %s\n", config->scanlocal ? "ENABLED":"DISABLED (Default)"); _dpd.logMsg(" Reputation priority: %s \n", config->priority == WHITELISTED_TRUST? REPUTATION_WHITELIST_KEYWORD "(Default)" : REPUTATION_BLACKLIST_KEYWORD ); _dpd.logMsg(" Nested IP: %s %s \n", NestedIPKeyword[config->nestedIP], config->nestedIP == INNER? "(Default)" : "" ); _dpd.logMsg(" White action: %s %s \n", WhiteActionOption[config->whiteAction], config->whiteAction == UNBLACK? "(Default)" : "" ); if (config->sharedMem.path) { _dpd.logMsg(" Shared memory supported, Update directory: %s\n", config->sharedMem.path ); _dpd.logMsg(" Shared memory refresh period: %d %s \n", config->sharedMem.updateInterval, config->sharedMem.updateInterval == REPUTATION_DEFAULT_REFRESH_PERIOD ? "(Default) seconds" : "seconds" ); } else { _dpd.logMsg(" Shared memory is Not supported.\n"); } _dpd.logMsg("\n"); } /******************************************************************** * Function: IpListInit * * Initiate an iplist table * * Arguments: * Reputation_Config * * The configuration to use. * * Returns: None * ********************************************************************/ static void IpListInit(uint32_t maxEntries, ReputationConfig *config) { uint8_t *base; ListInfo *whiteInfo; ListInfo *blackInfo; MEM_OFFSET list_ptr; if (config->iplist == NULL) { uint32_t mem_size; mem_size = estimateSizeFromEntries(maxEntries, config->memcap); config->localSegment = malloc(mem_size); if (config->localSegment == NULL) { DynamicPreprocessorFatalMessage( "Failed to allocate memory for local segment\n"); } segment_meminit((uint8_t*)config->localSegment,mem_size); base = (uint8_t *)config->localSegment; /*DIR_16x7_4x4 for performance, but memory usage is high *Use DIR_8x16 worst case IPV4 5K, IPV6 15K (bytes) *Use DIR_16x7_4x4 worst case IPV4 500, IPV6 2.5M */ config->iplist = sfrt_flat_new(DIR_8x16, IPv6, maxEntries, config->memcap); if (config->iplist == NULL) { DynamicPreprocessorFatalMessage("%s(%d): Failed to create IP list.\n", *(_dpd.config_file), *(_dpd.config_line)); } list_ptr = segment_calloc((size_t)DECISION_MAX, sizeof(ListInfo)); config->iplist->list_info = list_ptr; config->local_black_ptr = list_ptr + BLACKLISTED * sizeof(ListInfo); blackInfo = (ListInfo *)&base[config->local_black_ptr]; blackInfo->listType = BLACKLISTED; blackInfo->listIndex = BLACKLISTED + 1; #ifdef SHARED_REP memset(blackInfo->zones, true, MAX_NUM_ZONES); #endif if (UNBLACK == config->whiteAction) { config->local_white_ptr = list_ptr + WHITELISTED_UNBLACK * sizeof(ListInfo); whiteInfo = (ListInfo *)&base[config->local_white_ptr]; whiteInfo->listType = WHITELISTED_UNBLACK; whiteInfo->listIndex = WHITELISTED_UNBLACK + 1; #ifdef SHARED_REP memset(whiteInfo->zones, true, MAX_NUM_ZONES); #endif } else { config->local_white_ptr = list_ptr + WHITELISTED_TRUST * sizeof(ListInfo); whiteInfo = (ListInfo *)&base[config->local_white_ptr]; whiteInfo->listType = WHITELISTED_TRUST; whiteInfo->listIndex = WHITELISTED_TRUST + 1; #ifdef SHARED_REP memset(whiteInfo->zones, true, MAX_NUM_ZONES); #endif } } } /********************************************************************* * * Get the last index in the IP repuation information * * Arguments: * * IPrepInfo *repInfo: IP reputation information * uint8_t *base: the base pointer in shared memory * * RETURNS: * int *lastIndex: the last index * IPrepInfo *: the last IP info that stores the last index * NULL if not found *********************************************************************/ static inline IPrepInfo * getLastIndex(IPrepInfo *repInfo, uint8_t *base, int *lastIndex) { int i; assert(repInfo); /* Move to the end of current info*/ while (repInfo->next) { repInfo = (IPrepInfo *)&base[repInfo->next]; } for (i = 0; i < NUM_INDEX_PER_ENTRY; i++) { if (!repInfo->listIndexes[i]) break; } if (i > 0) { *lastIndex = i-1; return repInfo; } else { return NULL; } } /********************************************************************* * * Duplicate IP reputation information * * Arguments: * * IPrepInfo *currentInfo: IP reputation information copy from * IPrepInfo *destInfo: IP reputation information copy to * uint8_t *base: the base pointer in shared memory * * RETURNS: * number of bytes duplicated * -1 if out of memory * *********************************************************************/ static inline int duplicateInfo(IPrepInfo *destInfo,IPrepInfo *currentInfo, uint8_t *base) { int bytesAllocated = 0; while (currentInfo) { INFO nextInfo; *destInfo = *currentInfo; if (!currentInfo->next) break; nextInfo = segment_calloc(1,sizeof(IPrepInfo)); if (!nextInfo) { destInfo->next = 0; return -1; } else { destInfo->next = nextInfo; } bytesAllocated += sizeof(IPrepInfo); currentInfo = (IPrepInfo *)&base[currentInfo->next]; destInfo = (IPrepInfo *)&base[nextInfo]; } return bytesAllocated; } /********************************************************************* * New information for the same IP will be appended to the current * * If current information is empty (0), new information will be created. * * Arguments: * * INFO *current: (address to the location of) current IP reputation information * INFO new: (location of) new IP reputation information * uint8_t *base: the base pointer in shared memory * SaveDest saveDest: whether to update reputation at current location * or update at new location * * Returns: number of bytes allocated, -1 if out of memory * *********************************************************************/ static int64_t updateEntryInfo (INFO *current, INFO new, SaveDest saveDest, uint8_t *base) { IPrepInfo *currentInfo; IPrepInfo *newInfo; IPrepInfo *destInfo; IPrepInfo *lastInfo; int64_t bytesAllocated = 0; int i; char newIndex; if(!(*current)) { /* Copy the data to segment memory*/ *current = segment_calloc(1,sizeof(IPrepInfo)); if (!(*current)) { return -1; } bytesAllocated = sizeof(IPrepInfo); } if (*current == new) return bytesAllocated; currentInfo = (IPrepInfo *)&base[*current]; newInfo = (IPrepInfo *)&base[new]; /*The latest information is always the last entry */ lastInfo = getLastIndex(newInfo, base, &i); if (!lastInfo) { return bytesAllocated; } newIndex = lastInfo->listIndexes[i++]; DEBUG_WRAP( DebugMessage(DEBUG_REPUTATION, "Current IP reputation information: \n");); DEBUG_WRAP(ReputationPrintRepInfo(currentInfo, base);); DEBUG_WRAP( DebugMessage(DEBUG_REPUTATION, "New IP reputation information: \n");); DEBUG_WRAP(ReputationPrintRepInfo(newInfo, base);); if (SAVE_TO_NEW == saveDest) { int bytesDuplicated; /* When updating new entry, current information should be reserved * because current information is inherited from parent */ if ((bytesDuplicated = duplicateInfo(newInfo, currentInfo, base)) < 0) return -1; else bytesAllocated += bytesDuplicated; destInfo = newInfo; } else { destInfo = currentInfo; } /* Add the new list information to the end * This way, the order of list information is preserved. * The first one always has the highest priority, * because it is checked first during lookup. */ while (destInfo->next) { destInfo = (IPrepInfo *)&base[destInfo->next]; } for (i = 0; i < NUM_INDEX_PER_ENTRY; i++) { if (!destInfo->listIndexes[i]) break; else if (destInfo->listIndexes[i] == newIndex) { DEBUG_WRAP( DebugMessage(DEBUG_REPUTATION, "Final IP reputation information: \n");); DEBUG_WRAP(ReputationPrintRepInfo(destInfo, base);); return bytesAllocated; } } if (i < NUM_INDEX_PER_ENTRY) { destInfo->listIndexes[i] = newIndex; } else { IPrepInfo *nextInfo; MEM_OFFSET ipInfo_ptr = segment_calloc(1,sizeof(IPrepInfo)); if (!ipInfo_ptr) return -1; destInfo->next = ipInfo_ptr; nextInfo = (IPrepInfo *)&base[destInfo->next]; nextInfo->listIndexes[0] = newIndex; bytesAllocated += sizeof(IPrepInfo); } DEBUG_WRAP( DebugMessage(DEBUG_REPUTATION, "Final IP reputation information: \n");); DEBUG_WRAP(ReputationPrintRepInfo(destInfo, base);); return bytesAllocated; } /******************************************************************** * Function: AddIPtoList * * Add ip address to config file * * Arguments: * sfip_t *: ip address * void *: information about the file. * ReputationConfig *: The configuration to be update. * * Returns: * IP_INSERT_SUCCESS=0, * IP_INSERT_FAILURE, * IP_INSERT_DUPLICATE * ********************************************************************/ static int AddIPtoList(sfip_t *ipAddr,INFO ipInfo_ptr, ReputationConfig *config) { int iRet; int iFinalRet = IP_INSERT_SUCCESS; /*This variable is used to check whether a more generic address * overrides specific address */ uint32_t usageBeforeAdd; uint32_t usageAfterAdd; if (ipAddr->family == AF_INET) { ipAddr->ip32[0] = ntohl(ipAddr->ip32[0]); } else if (ipAddr->family == AF_INET6) { int i; for(i = 0; i < 4 ; i++) ipAddr->ip32[i] = ntohl(ipAddr->ip32[i]); } #ifdef DEBUG_MSGS if (NULL != sfrt_flat_lookup((void *)ipAddr, config->iplist)) { DebugMessage(DEBUG_REPUTATION, "Find address before insert: %s\n", sfip_to_str(ipAddr) ); } else { DebugMessage(DEBUG_REPUTATION, "Can't find address before insert: %s\n", sfip_to_str(ipAddr) ); } #endif usageBeforeAdd = sfrt_flat_usage(config->iplist); /*Check whether the same or more generic address is already in the table*/ if (NULL != sfrt_flat_lookup((void *)ipAddr, config->iplist)) { iFinalRet = IP_INSERT_DUPLICATE; } iRet = sfrt_flat_insert((void *)ipAddr, (unsigned char)ipAddr->bits, ipInfo_ptr, RT_FAVOR_ALL, config->iplist, &updateEntryInfo); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Unused memory: %d \n",segment_unusedmem());); if (RT_SUCCESS == iRet) { #ifdef DEBUG_MSGS IPrepInfo * result; DebugMessage(DEBUG_REPUTATION, "Number of entries input: %d, in table: %d \n", totalNumEntries,sfrt_flat_num_entries(config->iplist) ); DebugMessage(DEBUG_REPUTATION, "Memory allocated: %d \n",sfrt_flat_usage(config->iplist) ); result = sfrt_flat_lookup((void *)ipAddr, config->iplist); if (NULL != result) { DebugMessage(DEBUG_REPUTATION, "Find address after insert: %s \n",sfip_to_str(ipAddr) ); DEBUG_WRAP(ReputationPrintRepInfo(result, (uint8_t *)config->iplist);); } #endif totalNumEntries++; } else if (MEM_ALLOC_FAILURE == iRet) { iFinalRet = IP_MEM_ALLOC_FAILURE; DEBUG_WRAP( DebugMessage(DEBUG_REPUTATION, "Insert error: %d for address: %s \n",iRet, sfip_to_str(ipAddr) );); } else { iFinalRet = IP_INSERT_FAILURE; DEBUG_WRAP( DebugMessage(DEBUG_REPUTATION, "Insert error: %d for address: %s \n",iRet, sfip_to_str(ipAddr) );); } usageAfterAdd = sfrt_flat_usage(config->iplist); /*Compare in the same scale*/ if (usageAfterAdd > (config->memcap << 20)) { iFinalRet = IP_MEM_ALLOC_FAILURE; } /*Check whether there a more specific address will be overridden*/ if (usageBeforeAdd > usageAfterAdd ) { iFinalRet = IP_INSERT_DUPLICATE; } return iFinalRet; } static int snort_pton__address( char const *src, sfip_t *dest ) { unsigned char _temp[sizeof(struct in6_addr)]; if ( inet_pton(AF_INET, src, _temp) == 1 ) { dest->family = AF_INET; dest->bits = 32; } else if ( inet_pton(AF_INET6, src, _temp) == 1 ) { dest->family = AF_INET6; dest->bits = 128; } else { return 0; } memcpy(&dest->ip, _temp, sizeof(_temp)); return 1; } #define isident(x) (isxdigit((x)) || (x) == ':' || (x) == '.') static int snort_pton( char const * src, sfip_t * dest ) { char ipbuf[INET6_ADDRSTRLEN]; char cidrbuf[sizeof("128")]; char *out; enum { BEGIN, IP, CIDR1, CIDR2, END, INVALID } state; memset(ipbuf, '\0', sizeof(ipbuf)); memset(cidrbuf, '\0', sizeof(cidrbuf)); state = BEGIN; while ( *src ) { char ch = *src; //printf("State:%d; C:%x; P:%p\n", state, ch, src ); src += 1; switch ( state ) { // Scan for beginning of IP address case BEGIN: if ( isident((int)ch) ) { // Set the first ipbuff byte and change state out = ipbuf; *out++ = ch; state = IP; } else if ( !isspace((int)ch) ) { state = INVALID; } break; // Fill in ipbuf with ip identifier characters // Move to CIDR1 if a cidr divider (i.e., '/') is found. case IP: if ( isident((int)ch) && (out - ipbuf + 1) < (int)sizeof(ipbuf) ) { *out++ = ch; } else if ( ch == '/' ) { state = CIDR1; } else if ( isspace((int)ch) ) { state = END; } else { state = INVALID; } break; // First cidr digit case CIDR1: if ( !isdigit((int)ch) ) { state = INVALID; } else { // Set output to the cidrbuf buffer out = cidrbuf; *out++ = ch; state = CIDR2; } break; // Consume any addition digits for cidrbuf case CIDR2: if ( isdigit((int)ch) && (out - cidrbuf + 1) < (int)sizeof(cidrbuf) ) { *out++ = ch; } else if ( isspace((int)ch) ) { state = END; } else { state = INVALID; } break; // Scan for junk at the EOL case END: if ( !isspace((int)ch) ) { state = INVALID; } break; // Can't get here default: break; } if ( state == INVALID ) return -1; } if ( snort_pton__address(ipbuf, dest) < 1 ) return 0; if ( *cidrbuf ) { char *end; int value = strtol(cidrbuf, &end, 10); if ( value > dest->bits || value <= 0 || errno == ERANGE ) return 0; dest->bits = value; } return 1; } /******************************************************************** * Function: * * Load one IP list file * * Arguments: * char *: the line to be processed * void *: information about the file. * ReputationConfig *: The configuration to be update. * * Returns: * IP_INSERT_SUCCESS, * IP_INSERT_FAILURE, * IP_INSERT_DUPLICATE * ********************************************************************/ static int ProcessLine(char *line, INFO info, ReputationConfig *config) { sfip_t address; if ( !line || *line == '\0' ) return IP_INSERT_SUCCESS; if ( snort_pton(line, &address) < 1 ) return IP_INVALID; return AddIPtoList(&address, info, config); } /******************************************************************** * Function: UpdatePathToFile * * Update the path to a file, if using relative path. * The relative path is based on config file directory. * * Arguments: * full_path_filename: file name string * max_size: ? * char *filename: ? * * Returns: * 1 successful * 0 fail * ********************************************************************/ static int UpdatePathToFile(char *full_path_filename, unsigned int max_size, char *filename) { char *snort_conf_dir = *(_dpd.snort_conf_dir); if (!snort_conf_dir || !(*snort_conf_dir) || !full_path_filename || !filename) { DynamicPreprocessorFatalMessage(" %s(%d) => can't create path.\n", *(_dpd.config_file), *(_dpd.config_line)); return 0; } /*filename is too long*/ if ( max_size < strlen(filename) ) { DynamicPreprocessorFatalMessage(" %s(%d) => the file name length %u is longer than allowed %u.\n", *(_dpd.config_file), *(_dpd.config_line), strlen(filename), max_size); return 0; } /* * If an absolute path is specified, then use that. */ #ifndef WIN32 if(filename[0] == '/') { snprintf(full_path_filename, max_size, "%s", filename); } else { /* * Set up the file name directory. */ if (snort_conf_dir[strlen(snort_conf_dir) - 1] == '/') { snprintf(full_path_filename,max_size, "%s%s", snort_conf_dir, filename); } else { snprintf(full_path_filename, max_size, "%s/%s", snort_conf_dir, filename); } } #else if(strlen(filename)>3 && filename[1]==':' && filename[2]=='\\') { snprintf(full_path_filename, max_size, "%s", filename); } else { /* ** Set up the file name directory */ if (snort_conf_dir[strlen(snort_conf_dir) - 1] == '\\' || snort_conf_dir[strlen(snort_conf_dir) - 1] == '/' ) { snprintf(full_path_filename,max_size, "%s%s", snort_conf_dir, filename); } else { snprintf(full_path_filename, max_size, "%s\\%s", snort_conf_dir, filename); } } #endif return 1; } /******************************************************************** * Function: GetListInfo * * Get information about the file * * Arguments: * * info: information about the file. * * Returns: * None * ********************************************************************/ static char* GetListInfo(INFO info) { uint8_t *base; ListInfo *info_value; base = (uint8_t *)segment_basePtr(); info_value = (ListInfo *)(&base[info]); if (!info_value) return NULL; switch(info_value->listType) { case DECISION_NULL: return NULL; break; case BLACKLISTED: return black_info; break; case WHITELISTED_UNBLACK: return white_info; break; case MONITORED: return monitor_info; break; case WHITELISTED_TRUST: return white_info; break; default: return NULL; } return NULL; } /******************************************************************** * Function: LoadListFile * * Load one IP list file * * Arguments: * filename: file name string * info: information about the file. * ReputationConfig *: The configuration to be update. * * Returns: * None * ********************************************************************/ static void LoadListFile(char *filename, INFO info, ReputationConfig *config) { char linebuf[MAX_ADDR_LINE_LENGTH]; char full_path_filename[PATH_MAX+1]; int addrline = 0; FILE *fp = NULL; char *cmt = NULL; char *list_info; ListInfo *listInfo; IPrepInfo *ipInfo; MEM_OFFSET ipInfo_ptr; uint8_t *base; /*entries processing statistics*/ unsigned int duplicate_count = 0; /*number of duplicates in this file*/ unsigned int invalid_count = 0; /*number of invalid entries in this file*/ unsigned int fail_count = 0; /*number of invalid entries in this file*/ unsigned int num_loaded_before = 0; /*number of valid entries loaded */ if ((NULL == filename)||(0 == info)|| (NULL == config)||config->memCapReached) return; UpdatePathToFile(full_path_filename, PATH_MAX, filename); list_info = GetListInfo(info); if (!list_info) return; /*convert list info to ip entry info*/ ipInfo_ptr = segment_calloc(1,sizeof(IPrepInfo)); if (!(ipInfo_ptr)) { return; } base = (uint8_t*)config->iplist; ipInfo = ((IPrepInfo *)&base[ipInfo_ptr]); listInfo = ((ListInfo *)&base[info]); ipInfo->listIndexes[0] = listInfo->listIndex; _dpd.logMsg(" Processing %s file %s\n", list_info, full_path_filename); if((fp = fopen(full_path_filename, "r")) == NULL) { char errBuf[STD_BUF]; #ifdef WIN32 snprintf(errBuf, STD_BUF, "%s", strerror(errno)); #else strerror_r(errno, errBuf, STD_BUF); #endif errBuf[STD_BUF-1] = '\0'; _dpd.errMsg("%s(%d) => Unable to open address file %s, Error: %s\n", *(_dpd.config_file), *(_dpd.config_line), full_path_filename, errBuf); return; } num_loaded_before = sfrt_flat_num_entries(config->iplist); while( fgets(linebuf, MAX_ADDR_LINE_LENGTH, fp) ) { int iRet; addrline++; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Reputation configurations: %s\n",linebuf );); // Remove comments if( (cmt = strchr(linebuf, '#')) ) *cmt = '\0'; // Remove newline as well, prevent double newline in logging. if( (cmt = strchr(linebuf, '\n')) ) *cmt = '\0'; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Reputation configurations: %s\n",linebuf );); /* process the line */ iRet = ProcessLine(linebuf, ipInfo_ptr, config); if (IP_INSERT_SUCCESS == iRet) { continue; } else if (IP_INSERT_FAILURE == iRet && fail_count++ < MAX_MSGS_TO_PRINT) { _dpd.errMsg(" (%d) => Failed to insert address: \'%s\'\n", addrline, linebuf); } else if (IP_INVALID == iRet && invalid_count++ < MAX_MSGS_TO_PRINT) { _dpd.errMsg(" (%d) => Invalid address: \'%s\'\n", addrline, linebuf); } else if (IP_INSERT_DUPLICATE == iRet && duplicate_count++ < MAX_MSGS_TO_PRINT) { _dpd.errMsg(" (%d) => Re-defined address: '%s'\n", addrline, linebuf ); } else if (IP_MEM_ALLOC_FAILURE == iRet) { _dpd.errMsg("WARNING: %s(%d) => Memcap %u Mbytes reached when inserting IP Address: %s\n", full_path_filename, addrline, config->memcap,linebuf); if (config->statusBuf) { snprintf(config->statusBuf, config->statusBuf_len, "WARNING: %s(%d) => Memcap %u Mbytes reached when inserting IP Address: %s\n", full_path_filename, addrline, config->memcap,linebuf); config->statusBuf[config->statusBuf_len] = '\0'; } config->memCapReached = true; break; } } total_duplicates += duplicate_count; total_invalids += invalid_count; /*Print out the summary*/ if (fail_count > MAX_MSGS_TO_PRINT) _dpd.errMsg(" Additional addresses failed insertion but were not listed.\n"); if (invalid_count > MAX_MSGS_TO_PRINT) _dpd.errMsg(" Additional invalid addresses were not listed.\n"); if (duplicate_count > MAX_MSGS_TO_PRINT) _dpd.errMsg(" Additional duplicate addresses were not listed.\n"); _dpd.logMsg(" Reputation entries loaded: %u, invalid: %u, re-defined: %u (from file %s)\n", sfrt_flat_num_entries(config->iplist) - num_loaded_before, invalid_count, duplicate_count, full_path_filename); fclose(fp); } /******************************************************************** * Function: Reputation_FreeConfig * * Frees a reputation configuration * * Arguments: * Reputation_Config * * The configuration to free. * * Returns: None * ********************************************************************/ void Reputation_FreeConfig (ReputationConfig *config) { if (config == NULL) return; if (config->localSegment != NULL) { free(config->localSegment); } if(config->sharedMem.path) free(config->sharedMem.path); free(config); } /********************************************************************* * Function: EstimateNumEntries * * First pass to decide iplist table size. * * Arguments: * * ReputationConfig *config: Reputation preprocessor configuration. * argp: Pointer to string containing the config arguments. * * RETURNS: int. estimated number of Entries based on number of lines *********************************************************************/ int EstimateNumEntries(ReputationConfig *config, u_char* argp) { char* cur_sectionp = NULL; char* next_sectionp = NULL; char* argcpyp = NULL; int totalLines = 0; /*Default values*/ argcpyp = strdup( (char*) argp ); if ( !argcpyp ) { DynamicPreprocessorFatalMessage("Could not allocate memory to parse Reputation options.\n"); return 0; } cur_sectionp = strtok_r( argcpyp, REPUTATION_CONFIG_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Arguments token: %s\n",cur_sectionp );); while ( cur_sectionp ) { char* next_tokenp = NULL; char* cur_tokenp = strtok_r( cur_sectionp, REPUTATION_CONFIG_VALUE_SEPERATORS, &next_tokenp); if (!cur_tokenp) { cur_sectionp = strtok_r( next_sectionp, REPUTATION_CONFIG_SECTION_SEPERATORS, &next_sectionp); continue; } if ( !strcasecmp( cur_tokenp, REPUTATION_MEMCAP_KEYWORD )) { int value; char *endStr = NULL; cur_tokenp = strtok_r(next_tokenp, REPUTATION_CONFIG_VALUE_SEPERATORS, &next_tokenp); if ( !cur_tokenp ) { DynamicPreprocessorFatalMessage(" %s(%d) => No option to '%s'.\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_MEMCAP_KEYWORD); } value = _dpd.SnortStrtol( cur_tokenp, &endStr, 10); if (( *endStr) || (errno == ERANGE)) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d.\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_MEMCAP_KEYWORD, MIN_MEMCAP, MAX_MEMCAP); } if (value < MIN_MEMCAP || value > MAX_MEMCAP) { DynamicPreprocessorFatalMessage(" %s(%d) => Value specified for %s is out of " "bounds. Please specify an integer between %d and %d.\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_MEMCAP_KEYWORD, MIN_MEMCAP, MAX_MEMCAP); } config->memcap = (uint32_t) value; } else if ( !strcasecmp( cur_tokenp, REPUTATION_BLACKLIST_KEYWORD ) ||!strcasecmp( cur_tokenp, REPUTATION_WHITELIST_KEYWORD )) { int numlines; char full_path_filename[PATH_MAX+1]; cur_tokenp = strtok_r( next_tokenp, REPUTATION_CONFIG_VALUE_SEPERATORS, &next_tokenp); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Check list size %s\n",cur_tokenp );); if(cur_tokenp == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Bad list filename in IP List.\n", *(_dpd.config_file), *(_dpd.config_line)); } errno = 0; UpdatePathToFile(full_path_filename,PATH_MAX, cur_tokenp); numlines = numLinesInFile(full_path_filename); if ((0 == numlines) && (0 != errno)) { char errBuf[STD_BUF]; #ifdef WIN32 snprintf(errBuf, STD_BUF, "%s", strerror(errno)); #else strerror_r(errno, errBuf, STD_BUF); #endif DynamicPreprocessorFatalMessage("%s(%d) => Unable to open address file %s, Error: %s\n", *(_dpd.config_file), *(_dpd.config_line), full_path_filename, errBuf); } if (totalLines + numlines < totalLines) { DynamicPreprocessorFatalMessage("%s(%d) => Too many entries in one file.\n", *(_dpd.config_file), *(_dpd.config_line)); } totalLines += numlines; } else if ( !strcasecmp( cur_tokenp, REPUTATION_WHITEACTION_KEYWORD )) { int i = 0; char WhiteActionKeyworBuff[STD_BUF]; WhiteActionKeyworBuff[0] = '\0'; cur_tokenp = strtok_r( next_tokenp, REPUTATION_CONFIG_VALUE_SEPERATORS, &next_tokenp); if (!cur_tokenp) { DynamicPreprocessorFatalMessage(" %s(%d) => Missing argument for %s\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_WHITEACTION_KEYWORD); } while(NULL != WhiteActionOption[i]) { if( !strcasecmp(WhiteActionOption[i],cur_tokenp)) { config->whiteAction = (WhiteAction) i; break; } _dpd.printfappend(WhiteActionKeyworBuff, STD_BUF, "[%s] ", WhiteActionOption[i] ); i++; } if (NULL == WhiteActionOption[i]) { DynamicPreprocessorFatalMessage(" %s(%d) => Invalid argument: %s for %s, use %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp, REPUTATION_WHITEACTION_KEYWORD, WhiteActionKeyworBuff); } } #ifdef SHARED_REP else if ( !strcasecmp( cur_tokenp, REPUTATION_SHAREMEM_KEYWORD )) { if (Reputation_IsEmptyStr(next_tokenp)) { DynamicPreprocessorFatalMessage(" %s(%d) => Missing argument for %s," " please specify a path\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_SHAREMEM_KEYWORD); } if (!CheckIPlistDir(next_tokenp)) { DynamicPreprocessorFatalMessage(" %s(%d) => Can't find or access the path: %s\n", *(_dpd.config_file), *(_dpd.config_line), next_tokenp); } config->sharedMem.path = strdup( (char*) next_tokenp ); if ( !config->sharedMem.path ) { DynamicPreprocessorFatalMessage("Could not allocate memory to parse Reputation options.\n"); } config->sharedMem.updateInterval = REPUTATION_DEFAULT_REFRESH_PERIOD; } #endif cur_sectionp = strtok_r( next_sectionp, REPUTATION_CONFIG_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Arguments token: %s\n",cur_sectionp );); } free(argcpyp); return totalLines; } /********************************************************************* * Function: ParseReputationArgs * * Parses and processes the configuration arguments * supplied in the Reputation preprocessor rule. * * Arguments: * * ReputationConfig *config: Reputation preprocessor configuration. * argp: Pointer to string containing the config arguments. * * RETURNS: Nothing. *********************************************************************/ void ParseReputationArgs(ReputationConfig *config, u_char* argp) { char* cur_sectionp = NULL; char* next_sectionp = NULL; char* argcpyp = NULL; if (config == NULL) return; _dpd.logMsg("Reputation config: \n"); /*Default values*/ config->memcap = REPUTATION_DEFAULT_MEMCAP; config->priority = WHITELISTED_TRUST; config->nestedIP = INNER; config->whiteAction = UNBLACK; config->localSegment = NULL; config->emptySegment = NULL; config->memsize = 0; config->memCapReached = false; /* Sanity check(s) */ if ( !argp ) { _dpd.logMsg("WARNING: Can't find any whitelist/blacklist entries. " "Reputation Preprocessor disabled.\n"); return; } argcpyp = strdup( (char*) argp ); if ( !argcpyp ) { DynamicPreprocessorFatalMessage("Could not allocate memory to parse Reputation options.\n"); return; } DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Reputation configurations: %s\n",argcpyp );); /*We need to parse the memcap, numEntries earlier, then create iplist table*/ config->numEntries = EstimateNumEntries(config, argp ); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Estimated number of entries: %d\n",config->numEntries );); if ((config->numEntries <= 0) && (!config->sharedMem.path)) { _dpd.logMsg("WARNING: Can't find any whitelist/blacklist entries. " "Reputation Preprocessor disabled.\n"); free(argcpyp); return; } if (!config->sharedMem.path) IpListInit(config->numEntries + 1,config); cur_sectionp = strtok_r( argcpyp, REPUTATION_CONFIG_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Arguments token: %s\n",cur_sectionp );); /*Reset the log message count*/ total_duplicates = 0; while ( cur_sectionp ) { char* cur_config; char* cur_tokenp = strtok( cur_sectionp, REPUTATION_CONFIG_VALUE_SEPERATORS); if (!cur_tokenp) { cur_sectionp = strtok_r( next_sectionp, REPUTATION_CONFIG_SECTION_SEPERATORS, &next_sectionp); continue; } cur_config = cur_tokenp; if ( !strcasecmp( cur_tokenp, REPUTATION_SCANLOCAL_KEYWORD )) { config->scanlocal = 1; } else if ( !strcasecmp( cur_tokenp, REPUTATION_MEMCAP_KEYWORD )) { cur_tokenp = strtok( NULL, REPUTATION_CONFIG_VALUE_SEPERATORS); /* processed before */ } else if ( !strcasecmp( cur_tokenp, REPUTATION_BLACKLIST_KEYWORD )) { cur_tokenp = strtok( NULL, REPUTATION_CONFIG_VALUE_SEPERATORS); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Loading blacklist from %s\n",cur_tokenp );); if(cur_tokenp == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Bad list filename in IP List.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (!config->sharedMem.path) LoadListFile(cur_tokenp, config->local_black_ptr, config); else { _dpd.logMsg("WARNING: %s(%d) => List file %s is not loaded " "when using shared memory.\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp); } } else if ( !strcasecmp( cur_tokenp, REPUTATION_WHITELIST_KEYWORD )) { cur_tokenp = strtok( NULL, REPUTATION_CONFIG_VALUE_SEPERATORS); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Loading whitelist from %s\n",cur_tokenp );); if(cur_tokenp == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Bad list filename in IP List.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (!config->sharedMem.path) LoadListFile(cur_tokenp, config->local_white_ptr, config); else { _dpd.logMsg("WARNING: %s(%d) => List file %s is not loaded " "when using shared memory.\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp); } } else if ( !strcasecmp( cur_tokenp, REPUTATION_PRIORITY_KEYWORD )) { cur_tokenp = strtok( NULL, REPUTATION_CONFIG_VALUE_SEPERATORS); if (!cur_tokenp) { DynamicPreprocessorFatalMessage(" %s(%d) => Missing argument for %s\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_PRIORITY_KEYWORD); return; } if((strlen(REPUTATION_BLACKLIST_KEYWORD) == strlen (cur_tokenp)) && !strcasecmp(REPUTATION_BLACKLIST_KEYWORD,cur_tokenp)) { config->priority = BLACKLISTED; } else if((strlen(REPUTATION_WHITELIST_KEYWORD) == strlen (cur_tokenp)) && !strcasecmp(REPUTATION_WHITELIST_KEYWORD,cur_tokenp)) { config->priority = WHITELISTED_TRUST; if (UNBLACK == config->whiteAction) { _dpd.logMsg("WARNING: %s(%d) => Keyword %s for %s is not applied " "when white action is unblack.\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_PRIORITY_KEYWORD, REPUTATION_WHITELIST_KEYWORD); config->priority = WHITELISTED_UNBLACK; } } else { DynamicPreprocessorFatalMessage(" %s(%d) => Invalid argument: %s for %s," " Use [%s] or [%s]\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp, REPUTATION_PRIORITY_KEYWORD, REPUTATION_BLACKLIST_KEYWORD, REPUTATION_WHITELIST_KEYWORD); return; } } else if ( !strcasecmp( cur_tokenp, REPUTATION_NESTEDIP_KEYWORD )) { int i = 0; char NestIPKeyworBuff[STD_BUF]; NestIPKeyworBuff[0] = '\0'; cur_tokenp = strtok( NULL, REPUTATION_CONFIG_VALUE_SEPERATORS); if (!cur_tokenp) { DynamicPreprocessorFatalMessage(" %s(%d) => Missing argument for %s\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_NESTEDIP_KEYWORD); return; } while(NULL != NestedIPKeyword[i]) { if((strlen(NestedIPKeyword[i]) == strlen (cur_tokenp)) && !strcasecmp(NestedIPKeyword[i],cur_tokenp)) { config->nestedIP = (NestedIP) i; break; } _dpd.printfappend(NestIPKeyworBuff, STD_BUF, "[%s] ", NestedIPKeyword[i] ); i++; } if (NULL == NestedIPKeyword[i]) { DynamicPreprocessorFatalMessage(" %s(%d) => Invalid argument: %s for %s, use %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp, REPUTATION_NESTEDIP_KEYWORD, NestIPKeyworBuff); return; } } else if ( !strcasecmp( cur_tokenp, REPUTATION_WHITEACTION_KEYWORD )) { cur_tokenp = strtok( NULL, REPUTATION_CONFIG_VALUE_SEPERATORS); /* processed before */ } #ifdef SHARED_REP else if ( !strcasecmp( cur_tokenp, REPUTATION_SHAREMEM_KEYWORD )) { cur_sectionp = strtok_r( next_sectionp, REPUTATION_CONFIG_SECTION_SEPERATORS, &next_sectionp); continue; /* processed before */ } else if ( !strcasecmp( cur_tokenp, REPUTATION_SHAREDREFRESH_KEYWORD )) { unsigned long value; char *endStr = NULL; if (!config->sharedMem.path) { DynamicPreprocessorFatalMessage(" %s(%d) => Specify option '%s' when using option '%s'.\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_SHAREMEM_KEYWORD, REPUTATION_SHAREDREFRESH_KEYWORD); } cur_tokenp = strtok(NULL, REPUTATION_CONFIG_VALUE_SEPERATORS); if ( !cur_tokenp ) { DynamicPreprocessorFatalMessage(" %s(%d) => No option to '%s'.\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_SHAREDREFRESH_KEYWORD); } value = _dpd.SnortStrtoul( cur_tokenp, &endStr, 10); if ( *endStr) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %u and %u.\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_SHAREDREFRESH_KEYWORD, MIN_SHARED_MEM_REFRESH_PERIOD, MAX_SHARED_MEM_REFRESH_PERIOD); } if (value < MIN_SHARED_MEM_REFRESH_PERIOD || value > MAX_SHARED_MEM_REFRESH_PERIOD || (errno == ERANGE)) { DynamicPreprocessorFatalMessage(" %s(%d) => Value specified for %s is out of " "bounds. Please specify an integer between %u and %u.\n", *(_dpd.config_file), *(_dpd.config_line), REPUTATION_SHAREDREFRESH_KEYWORD, MIN_SHARED_MEM_REFRESH_PERIOD, MAX_SHARED_MEM_REFRESH_PERIOD); } config->sharedMem.updateInterval = (uint32_t) value; } #endif else { DynamicPreprocessorFatalMessage(" %s(%d) => Invalid argument: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp); return; } /*Check whether too many parameters*/ if (NULL != strtok( NULL, REPUTATION_CONFIG_VALUE_SEPERATORS)) { DynamicPreprocessorFatalMessage("%s(%d) => Too many arguments: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_config); } cur_sectionp = strtok_r( next_sectionp, REPUTATION_CONFIG_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Arguments token: %s\n",cur_sectionp );); } DisplayIPlistStats(config); DisplayReputationConfig(config); free(argcpyp); } void ReputationRepInfo(IPrepInfo * repInfo, uint8_t *base, char *repInfoBuff, int bufLen) { char *index = repInfoBuff; int len = bufLen -1 ; int writed; writed = snprintf(index, len, "Reputation Info: "); if (writed >= len || writed < 0) return; index += writed; len -= writed; while(repInfo) { int i; for(i = 0; i < NUM_INDEX_PER_ENTRY; i++) { writed = snprintf(index, len, "%d,",repInfo->listIndexes[i]); if (writed >= len || writed < 0) return; else { index += writed; len -=writed; } } writed = snprintf(index, len, "->"); if (writed >= len || writed < 0) return; else { index += writed; len -=writed; } if (!repInfo->next) break; repInfo = (IPrepInfo *)(&base[repInfo->next]); } } #ifdef DEBUG_MSGS void ReputationPrintRepInfo(IPrepInfo * repInfo, uint8_t *base) { char repInfoBuff[STD_BUF]; int len = STD_BUF -1 ; repInfoBuff[STD_BUF -1] = '\0'; ReputationRepInfo(repInfo, base, repInfoBuff, len); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Reputation Info: %s \n", repInfoBuff);); } #endif snort-2.9.6.0/src/dynamic-preprocessors/reputation/spp_reputation.h0000644000000000000000000000602712260565732022500 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2011-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * spp_reputation.h: Definitions, structs, function prototype(s) for * the Reputation preprocessor. * Author: Hui Cao */ #ifndef SPP_REPUTATION_H #define SPP_REPUTATION_H #include "sf_types.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "sf_ip.h" #include "sfrt_flat.h" #include "reputation_config.h" /* * Generator id. Define here the same as the official registry * in generators.h */ #define GENERATOR_SPP_REPUTATION 136 #define CS_TYPE_REPUTATION_SHAREMEM ((GENERATOR_SPP_REPUTATION *10) + 1) #define CS_TYPE_REPUTATION_SHAREMEM_LOOKUP ((GENERATOR_SPP_REPUTATION *10) + 2) #define CS_TYPE_REPUTATION_SHAREMEM_MGMT_INFO ((GENERATOR_SPP_REPUTATION *10) + 3) /*These IDs are reserved for snort shared memory server (writer)*/ #define SHMEM_SERVER_ID 0 /* Ultimately calls SnortEventqAdd */ /* Arguments are: gid, sid, rev, classification, priority, message, rule_info */ #define ALERT(x,y) { _dpd.alertAdd(GENERATOR_SPP_REPUTATION, x, 1, 0, 3, y, 0 ); } #define REPUTATION_EVENT_BLACKLIST 1 #define REPUTATION_EVENT_BLACKLIST_STR "(spp_reputation) packets blacklisted" #define REPUTATION_EVENT_WHITELIST 2 #define REPUTATION_EVENT_WHITELIST_STR "(spp_reputation) packets whitelisted" #define REPUTATION_EVENT_MONITOR 3 #define REPUTATION_EVENT_MONITOR_STR "(spp_reputation) packets monitored" typedef struct _Reputation_Stats { uint64_t blacklisted; uint64_t whitelisted; uint64_t monitored; uint64_t memoryAllocated; } Reputation_Stats; extern Reputation_Stats reputation_stats; extern int totalNumEntries; extern ReputationConfig *reputation_eval_config; extern tSfPolicyUserContextId reputation_config; extern void **IPtables; #ifdef SHARED_REP typedef enum { NO_SWITCH, SWITCHING, SWITCHED }Swith_State; extern Swith_State switch_state; extern int available_segment; extern table_flat_t *emptyIPtables; extern ReputationConfig *reputation_shmem_config; #endif /* Prototypes for public interface */ void SetupReputation(void); void SetupReputationUpdate(uint32_t interval); #endif /* SPP_REPUTATION_H */ snort-2.9.6.0/src/dynamic-preprocessors/reputation/spp_reputation.c0000644000000000000000000007537212260565732022504 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2011-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Reputation preprocessor * * This is the main entry point for this preprocessor * * Author: Hui Cao * Date: 06-01-2011 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_plugin_api.h" #include "snort_debug.h" #include "preprocids.h" #include "spp_reputation.h" #include "reputation_config.h" #include "reputation_utils.h" #include #include #include #include #ifndef WIN32 #include #include #endif #include #include #ifdef SHARED_REP #include "./shmem/shmem_mgmt.h" #endif #include "profiler.h" #ifdef PERF_PROFILING PreprocStats reputationPerfStats; #endif const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_REPUTATION"; #define SetupReputation DYNAMIC_PREPROC_SETUP /* * Function prototype(s) */ static void ReputationInit( struct _SnortConfig *, char* ); static int ReputationCheckConfig(struct _SnortConfig *); static inline void ReputationProcess(SFSnortPacket *); static void ReputationMain( void*, void* ); static void ReputationFreeConfig(tSfPolicyUserContextId); static void ReputationPrintStats(int); static void ReputationCleanExit(int, void *); static inline IPrepInfo* ReputationLookup(snort_ip_p ip); static inline IPdecision GetReputation(IPrepInfo *, SFSnortPacket *, uint32_t *); #ifdef SHARED_REP Swith_State switch_state = NO_SWITCH; int available_segment = NO_DATASEG; static void ReputationMaintenanceCheck(int, void *); #endif /******************************************************************** * Global variables ********************************************************************/ int totalNumEntries = 0; Reputation_Stats reputation_stats; ReputationConfig *reputation_eval_config; tSfPolicyUserContextId reputation_config; ReputationConfig *pDefaultPolicyConfig = NULL; #ifdef SNORT_RELOAD static void ReputationReload(struct _SnortConfig *, char *, void **); static void * ReputationReloadSwap(struct _SnortConfig *, void *); static void ReputationReloadSwapFree(void *); static int ReputationReloadVerify(struct _SnortConfig *, void *); #endif /* Called at preprocessor setup time. Links preprocessor keyword * to corresponding preprocessor initialization function. * * PARAMETERS: None. * * RETURNS: Nothing. * */ void SetupReputation(void) { /* Link preprocessor keyword to initialization function * in the preprocessor list. */ #ifndef SNORT_RELOAD _dpd.registerPreproc( "reputation", ReputationInit ); #else _dpd.registerPreproc("reputation", ReputationInit, ReputationReload, ReputationReloadVerify, ReputationReloadSwap, ReputationReloadSwapFree); #endif } #ifdef SHARED_REP static int Reputation_MgmtInfo(uint16_t type, const uint8_t *data, uint32_t length, void **new_config, char *statusBuf, int statusBufLen) { ShmemMgmtInfo(statusBuf, statusBufLen); return 0; } static int Reputation_Lookup(uint16_t type, const uint8_t *data, uint32_t length, void **new_config, char *statusBuf, int statusBufLen) { snort_ip addr; IPrepInfo *repInfo = NULL; char *tokstr, *save, *data_copy; CSMessageDataHeader *msg_hdr = (CSMessageDataHeader *)data; statusBuf[0] = 0; if (length <= sizeof(*msg_hdr)) { return -1; } length -= sizeof(*msg_hdr); if (length != (uint32_t)ntohs(msg_hdr->length)) { return -1; } data += sizeof(*msg_hdr); data_copy = malloc(length + 1); if (data_copy == NULL) { return -1; } memcpy(data_copy, data, length); data_copy[length] = 0; tokstr = strtok_r(data_copy, " \t\n", &save); if (tokstr == NULL) { free(data_copy); return -1; } /* Convert tokstr to sfip type */ if (sfip_pton(tokstr, IP_ARG(addr))) { free(data_copy); return -1; } /* Get the reputation info */ repInfo = ReputationLookup(IP_ARG(addr)); if (!repInfo) { snprintf(statusBuf, statusBufLen, "Reputation Info: Error doing lookup"); free(data_copy); return -1; } /* Are we looking to obtain the decision? */ tokstr = strtok_r(NULL, " \t\n", &save); if (tokstr) { uint32_t listid; char *decision; #ifdef DAQ_PKTHDR_UNKNOWN int zone = atoi(tokstr); #endif SFSnortPacket p; #ifdef DAQ_PKTHDR_UNKNOWN DAQ_PktHdr_t hdr; p.pkt_header = &hdr; hdr.ingress_group = zone; #else p.pkt_header = NULL; #endif switch (GetReputation(repInfo, &p, &listid)) { case DECISION_NULL: decision = "DECISION_NULL"; break; case BLACKLISTED: decision = "BLACKLISTED"; break; case WHITELISTED_UNBLACK: decision = "WHITELISTED UNBLACK"; break; case MONITORED: decision = "MONITORED"; break; case WHITELISTED_TRUST: decision = "WHITELISTED TRUST"; break; default: decision = "UNKNOWN"; break; } snprintf(statusBuf, statusBufLen, "Reputation Info: %s in list %d" #ifdef DAQ_PKTHDR_UNKNOWN " from zone %d" #endif ,decision, listid #ifdef DAQ_PKTHDR_UNKNOWN ,zone #endif ); } else { ReputationRepInfo(repInfo, (uint8_t *)reputation_eval_config->iplist, statusBuf, statusBufLen); } free(data_copy); return 0; } static int Reputation_PreControl(uint16_t type, const uint8_t *data, uint32_t length, void **new_config, char *statusBuf, int statusBufLen) { ReputationConfig *pDefaultPolicyConfig = NULL; ReputationConfig *nextConfig = NULL; statusBuf[0] = 0; if (SWITCHING == switch_state ) return -1; pDefaultPolicyConfig = (ReputationConfig *)sfPolicyUserDataGetDefault(reputation_config); if (!pDefaultPolicyConfig) { *new_config = NULL; return -1; } nextConfig = (ReputationConfig *)calloc(1, sizeof(ReputationConfig)); if (!nextConfig) { *new_config = NULL; return -1; } switch_state = SWITCHING; nextConfig->segment_version = NO_DATASEG; nextConfig->memcap = pDefaultPolicyConfig->memcap; nextConfig->statusBuf = statusBuf; nextConfig->statusBuf_len = statusBufLen; reputation_shmem_config = nextConfig; if ((available_segment = LoadSharedMemDataSegmentForWriter(RELOAD)) >= 0) { *new_config = nextConfig; nextConfig->segment_version = available_segment; _dpd.logMsg(" Reputation Preprocessor: Received segment %d\n", available_segment); if (!statusBuf[0]) snprintf(statusBuf,statusBufLen, "Reputation Preprocessor: Received segment %d successful", available_segment); } else { *new_config = NULL; free(nextConfig); switch_state = NO_SWITCH; return -1; } return 0; } static int Reputation_Control(uint16_t type, void *new_config, void **old_config) { ReputationConfig *config = (ReputationConfig *) new_config; if (NULL != config) { SwitchToActiveSegment(config->segment_version, &IPtables); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION,"***Switched to segment %d\n", config->segment_version)); *old_config = config; return 0; } return -1; } static void Reputation_PostControl(uint16_t type, void *old_config, struct _THREAD_ELEMENT *te, ControlDataSendFunc f) { ReputationConfig *config = (ReputationConfig *) old_config; ReputationConfig *pDefaultPolicyConfig = NULL; pDefaultPolicyConfig = (ReputationConfig *)sfPolicyUserDataGetDefault(reputation_config); if (!pDefaultPolicyConfig) { return; } UnmapInactiveSegments(); pDefaultPolicyConfig->memCapReached = config->memCapReached; pDefaultPolicyConfig->segment_version = config->segment_version; pDefaultPolicyConfig->memsize = config->memsize; pDefaultPolicyConfig->numEntries = config->numEntries; pDefaultPolicyConfig->iplist = config->iplist; pDefaultPolicyConfig->statusBuf = NULL; reputation_shmem_config = pDefaultPolicyConfig; switch_state = SWITCHED; free(config); } static void ReputationMaintenanceCheck(int signal, void *data) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Reputation Preprocessor Maintenance!\n");); PrintShmemMgmtInfo(); if (SHMEM_SERVER_ID == _dpd.getSnortInstance()) { ManageUnusedSegments(); /*check whether new shared memory has been applied. If yes, release the old one*/ if ((SWITCHED == switch_state) && reputation_eval_config && (reputation_eval_config->iplist == (table_flat_t *)*IPtables)) { _dpd.logMsg(" Reputation Preprocessor: Instance %d switched to segment_version %d\n", _dpd.getSnortInstance(), available_segment); UnmapInactiveSegments(); switch_state = NO_SWITCH; } } else { if ((NO_SWITCH == switch_state)&&((available_segment = CheckForSharedMemSegment()) >= 0)) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION,"***Switched to segment_version %d ",available_segment);); SwitchToActiveSegment(available_segment, &IPtables); switch_state = SWITCHED; } /*check whether new shared memory has been applied. If yes, release the old one*/ else if ((SWITCHED == switch_state) && reputation_eval_config && (reputation_eval_config->iplist == (table_flat_t *)*IPtables)) { _dpd.logMsg(" Reputation Preprocessor: Instance %d switched to segment_version %d\n", _dpd.getSnortInstance(), available_segment); UnmapInactiveSegments(); switch_state = NO_SWITCH; } } } /*Switch for idle*/ static void ReputationShmemSwitch(void) { if (switch_state == NO_SWITCH) return; reputation_eval_config = sfPolicyUserDataGetDefault(reputation_config); if (reputation_eval_config) reputation_eval_config->iplist = (table_flat_t *)*IPtables; } void SetupReputationUpdate(uint32_t updateInterval) { _dpd.addPeriodicCheck(ReputationMaintenanceCheck,NULL, PRIORITY_FIRST, PP_REPUTATION, updateInterval); _dpd.registerIdleHandler(ReputationShmemSwitch); /*Only writer or server has control channel*/ if (SHMEM_SERVER_ID == _dpd.getSnortInstance()) { _dpd.controlSocketRegisterHandler(CS_TYPE_REPUTATION_SHAREMEM, &Reputation_PreControl, &Reputation_Control, &Reputation_PostControl); _dpd.controlSocketRegisterHandler(CS_TYPE_REPUTATION_SHAREMEM_LOOKUP, &Reputation_Lookup, NULL, NULL); _dpd.controlSocketRegisterHandler(CS_TYPE_REPUTATION_SHAREMEM_MGMT_INFO, &Reputation_MgmtInfo, NULL, NULL); } } #endif /* Initializes the Reputation preprocessor module and registers * it in the preprocessor list. * * PARAMETERS: * * argp: Pointer to argument string to process for configuration data. * * RETURNS: Nothing. */ static void ReputationInit(struct _SnortConfig *sc, char *argp) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); ReputationConfig *pDefaultPolicyConfig = NULL; ReputationConfig *pPolicyConfig = NULL; if (reputation_config == NULL) { /*create a context*/ reputation_config = sfPolicyConfigCreate(); if (reputation_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for Reputation config.\n"); } _dpd.addPreprocConfCheck(sc, ReputationCheckConfig); _dpd.registerPreprocStats(REPUTATION_NAME, ReputationPrintStats); _dpd.addPreprocExit(ReputationCleanExit, NULL, PRIORITY_LAST, PP_REPUTATION); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("reputation", (void *)&reputationPerfStats, 0, _dpd.totalPerfStats); #endif } sfPolicyUserPolicySet (reputation_config, policy_id); pDefaultPolicyConfig = (ReputationConfig *)sfPolicyUserDataGetDefault(reputation_config); pPolicyConfig = (ReputationConfig *)sfPolicyUserDataGetCurrent(reputation_config); if ((policy_id != 0) && (pDefaultPolicyConfig == NULL)) { DynamicPreprocessorFatalMessage("%s(%d) => Reputation configuration may only" " be enabled in default configuration\n", *_dpd.config_file, *_dpd.config_line); } if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Reputation preprocessor can only be " "configured once.\n", *_dpd.config_file, *_dpd.config_line); } pPolicyConfig = (ReputationConfig *)calloc(1, sizeof(ReputationConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "Reputation preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(reputation_config, pPolicyConfig); ParseReputationArgs(pPolicyConfig, (u_char *)argp); if ((0 == pPolicyConfig->numEntries)&&(!pPolicyConfig->sharedMem.path)) { return; } if (policy_id != 0) pPolicyConfig->memcap = pDefaultPolicyConfig->memcap; if (!pPolicyConfig->sharedMem.path && pPolicyConfig->localSegment) IPtables = &pPolicyConfig->localSegment; _dpd.addPreproc( sc, ReputationMain, PRIORITY_FIRST, PP_REPUTATION, PROTO_BIT__IP ); #ifdef SHARED_REP if (pPolicyConfig->sharedMem.path) _dpd.addPostConfigFunc(sc, initShareMemory, pPolicyConfig); #endif } #ifdef REG_TEST /* Generate zones from ports for regression tests*/ static inline void createZones(uint32_t *ingressZone, uint32_t *egressZone, SFSnortPacket *p) { const uint32_t zone_base = 0xF700; *ingressZone = p->src_port - zone_base; *egressZone = p->dst_port - zone_base; } #endif /********************************************************************* * Lookup the IP information stored in the data entry. * * Returns: * IPdecision - * DECISION_NULL * BLACKLISTED * WHITELISTED_UNBLACK * MONITORED * WHITELISTED_TRUST * *********************************************************************/ static inline IPdecision GetReputation( IPrepInfo * repInfo, SFSnortPacket *p, uint32_t *listid) { IPdecision decision = DECISION_NULL; uint8_t *base ; ListInfo *listInfo; #ifdef SHARED_REP uint32_t ingressZone = 0; uint32_t egressZone = 0; #ifdef DAQ_PKTHDR_UNKNOWN if (p->pkt_header) { ingressZone = p->pkt_header->ingress_group; if (p->pkt_header->egress_index < 0) egressZone = ingressZone; else egressZone = p->pkt_header->egress_group; #ifdef REG_TEST createZones(&ingressZone,&egressZone,p); #endif /*Make sure zone ids are in the support range*/ if (ingressZone >= MAX_NUM_ZONES) ingressZone = 0; if (egressZone >= MAX_NUM_ZONES) egressZone = 0; } #endif #endif /*Walk through the IPrepInfo lists*/ base = (uint8_t *) reputation_eval_config->iplist; listInfo = (ListInfo *)(&base[reputation_eval_config->iplist->list_info]); while(repInfo) { int i; for(i = 0; i < NUM_INDEX_PER_ENTRY; i++) { int list_index = repInfo->listIndexes[i]; if (!list_index) break; list_index--; #ifdef SHARED_REP DEBUG_WRAP(PrintListInfo (listInfo[list_index].zones, listInfo[list_index].listId);); /*Check both ingress zone and egress zone*/ if (listInfo[list_index].zones[ingressZone] || listInfo[list_index].zones[egressZone]) #endif { if (WHITELISTED_UNBLACK == (IPdecision)listInfo[list_index].listType) return DECISION_NULL; if (reputation_eval_config->priority == (IPdecision)listInfo[list_index].listType ) { *listid = listInfo[list_index].listId; return ((IPdecision)listInfo[list_index].listType); } else if ( decision < listInfo[list_index].listType) { decision = (IPdecision)listInfo[list_index].listType; *listid = listInfo[list_index].listId; } } } if (!repInfo->next) break; repInfo = (IPrepInfo *)(&base[repInfo->next]); } return decision; } /********************************************************************* * Lookup the iplist table. * * Arguments: * snort_ip_p - ip to be searched * * Returns: * * IPrepInfo * - The reputation information in the table * *********************************************************************/ static inline IPrepInfo* ReputationLookup(snort_ip_p ip) { IPrepInfo * result; DEBUG_WRAP( DebugMessage(DEBUG_REPUTATION, "Lookup address: %s \n",sfip_to_str(ip) );); if (!reputation_eval_config->scanlocal) { if (sfip_is_private(ip) ) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Private address\n");); return NULL; } } result = (IPrepInfo *) sfrt_flat_dir8x_lookup((void *)ip, reputation_eval_config->iplist ); return (result); } /********************************************************************* * Make decision based on ip addresses * * Arguments: * SFSnortPacket * - pointer to packet structure * * Returns: * IPdecision - * DECISION_NULL * BLACKLISTED * WHITELISTED_UNBLACK * MONITORED * WHITELISTED_TRUST * *********************************************************************/ static inline IPdecision ReputationDecision(SFSnortPacket *p) { snort_ip_p ip; IPdecision decision; IPdecision decision_final = DECISION_NULL; IPrepInfo *result; /*Check INNER IP, when configured or only one layer*/ if (( ! p->outer_family ) ||(INNER == reputation_eval_config->nestedIP) ||(BOTH == reputation_eval_config->nestedIP)) { ip = GET_INNER_SRC_IP(((SFSnortPacket *)p)); result = ReputationLookup(ip); if(result) { DEBUG_WRAP(ReputationPrintRepInfo(result,(uint8_t *) reputation_eval_config->iplist);); decision = GetReputation(result,p, &p->iplist_id); p->iprep_layer = IP_INNER_LAYER; p->flags |= FLAG_IPREP_SOURCE_TRIGGERED; if ( reputation_eval_config->priority == decision) return decision; decision_final = decision; } ip = GET_INNER_DST_IP(((SFSnortPacket *)p)); result = ReputationLookup(ip); if(result) { DEBUG_WRAP(ReputationPrintRepInfo(result,(uint8_t *) reputation_eval_config->iplist);); decision = GetReputation(result,p, &p->iplist_id); p->iprep_layer = IP_INNER_LAYER; p->flags &=~FLAG_IPREP_SOURCE_TRIGGERED; if ( reputation_eval_config->priority == decision) return decision; decision_final = decision; } } /*Check OUTER IP*/ if (( p->outer_family) && ((OUTER == reputation_eval_config->nestedIP) ||(BOTH == reputation_eval_config->nestedIP))) { ip = GET_OUTER_SRC_IP(((SFSnortPacket *)p)); result = ReputationLookup(ip); if(result) { decision = GetReputation(result,p, &p->iplist_id); p->iprep_layer = IP_OUTTER_LAYER; p->flags |= FLAG_IPREP_SOURCE_TRIGGERED; if ( reputation_eval_config->priority == decision) return decision; decision_final = decision; } ip = GET_OUTER_DST_IP(((SFSnortPacket *)p)); result = ReputationLookup(ip); if(result) { decision = GetReputation(result,p, &p->iplist_id); p->iprep_layer = IP_OUTTER_LAYER; p->flags &=~FLAG_IPREP_SOURCE_TRIGGERED; if ( reputation_eval_config->priority == decision) return decision; decision_final = decision; } } return (decision_final); } /********************************************************************* * Main entry point for Reputation processing. * * Arguments: * SFSnortPacket * - pointer to packet structure * * Returns: * None * *********************************************************************/ static inline void ReputationProcess(SFSnortPacket *p) { IPdecision decision; reputation_eval_config->iplist = (table_flat_t *)*IPtables; decision = ReputationDecision(p); if (DECISION_NULL == decision) { return; } else if (BLACKLISTED == decision) { ALERT(REPUTATION_EVENT_BLACKLIST,REPUTATION_EVENT_BLACKLIST_STR); #ifdef POLICY_BY_ID_ONLY _dpd.inlineForceDropPacket(p); #endif _dpd.disableAllDetect(p); _dpd.setPreprocBit(p, PP_PERFMONITOR); reputation_stats.blacklisted++; } else if (MONITORED == decision) { ALERT(REPUTATION_EVENT_MONITOR,REPUTATION_EVENT_MONITOR_STR); p->flags |= FLAG_IPREP_DATA_SET; reputation_stats.monitored++; } else if (WHITELISTED_TRUST == decision) { ALERT(REPUTATION_EVENT_WHITELIST,REPUTATION_EVENT_WHITELIST_STR); p->flags |= FLAG_IGNORE_PORT; _dpd.disableAllDetect(p); _dpd.setPreprocBit(p, PP_PERFMONITOR); reputation_stats.whitelisted++; } } /* Main runtime entry point for Reputation preprocessor. * Analyzes Reputation packets for anomalies/exploits. * * PARAMETERS: * * packetp: Pointer to current packet to process. * contextp: Pointer to context block, not used. * * RETURNS: Nothing. */ static void ReputationMain( void* ipacketp, void* contextp ) { PROFILE_VARS; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "%s\n", REPUTATION_DEBUG__START_MSG)); // preconditions - what we registered for assert(IsIP((SFSnortPacket*)ipacketp)); if ( ((SFSnortPacket*)ipacketp)->flags & FLAG_REBUILT_FRAG || ((SFSnortPacket*)ipacketp)->flags & FLAG_REBUILT_STREAM ) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION," -> spp_reputation: Not IP or Is a rebuilt packet\n");); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "%s\n", REPUTATION_DEBUG__END_MSG)); return; } reputation_eval_config = sfPolicyUserDataGetDefault(reputation_config); PREPROC_PROFILE_START(reputationPerfStats); ReputationProcess((SFSnortPacket*) ipacketp); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "%s\n", REPUTATION_DEBUG__END_MSG)); PREPROC_PROFILE_END(reputationPerfStats); } static int ReputationCheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData) { _dpd.setParserPolicy(sc, policyId); return 0; } int ReputationCheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate (sc, reputation_config, ReputationCheckPolicyConfig))) return rval; return 0; } static void ReputationCleanExit(int signal, void *data) { if (reputation_config != NULL) { ReputationFreeConfig(reputation_config); reputation_config = NULL; #ifdef SHARED_REP ShutdownSharedMemory(); if (emptyIPtables != NULL) { free(emptyIPtables); emptyIPtables = NULL; } #endif } } static int ReputationFreeConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { ReputationConfig *pPolicyConfig = (ReputationConfig *)pData; //do any housekeeping before freeing ReputationConfig sfPolicyUserDataClear (config, policyId); Reputation_FreeConfig(pPolicyConfig); return 0; } void ReputationFreeConfig(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, ReputationFreeConfigPolicy); sfPolicyConfigDelete(config); } /****************************************************************** * Print statistics being kept by the preprocessor. * * Arguments: * int - whether Snort is exiting or not * * Returns: None * ******************************************************************/ static void ReputationPrintStats(int exiting) { _dpd.logMsg("Reputation Preprocessor Statistics\n"); _dpd.logMsg(" Total Memory Allocated: "STDu64"\n", reputation_stats.memoryAllocated); if (reputation_stats.blacklisted > 0) _dpd.logMsg(" Number of packets blacklisted: "STDu64"\n", reputation_stats.blacklisted); if (reputation_stats.whitelisted > 0) _dpd.logMsg(" Number of packets whitelisted: "STDu64"\n", reputation_stats.whitelisted); if (reputation_stats.monitored > 0) _dpd.logMsg(" Number of packets monitored: "STDu64"\n", reputation_stats.monitored); } #ifdef SNORT_RELOAD static void ReputationReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId reputation_swap_config = (tSfPolicyUserContextId)*new_config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); ReputationConfig * pPolicyConfig = NULL; ReputationConfig *pDefaultPolicyConfig = NULL; if (reputation_swap_config == NULL) { //create a context reputation_swap_config = sfPolicyConfigCreate(); if (reputation_swap_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for Reputation config.\n"); } *new_config = (void *)reputation_swap_config; } sfPolicyUserPolicySet (reputation_swap_config, policy_id); pPolicyConfig = (ReputationConfig *)sfPolicyUserDataGetCurrent(reputation_swap_config); pDefaultPolicyConfig = (ReputationConfig *)sfPolicyUserDataGetDefault(reputation_config); if ((policy_id != 0) && (pDefaultPolicyConfig == NULL)) { DynamicPreprocessorFatalMessage("%s(%d) => Reputation configuration may only" " be enabled in default configuration\n", *_dpd.config_file, *_dpd.config_line); } if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Reputation preprocessor can only be " "configured once.\n", *_dpd.config_file, *_dpd.config_line); } pPolicyConfig = (ReputationConfig *)calloc(1, sizeof(ReputationConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "Reputation preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(reputation_swap_config, pPolicyConfig); ParseReputationArgs(pPolicyConfig, (u_char *)args); if ((0 == pPolicyConfig->numEntries) &&(!pPolicyConfig->sharedMem.path)) { return; } if ((policy_id != 0) &&(pDefaultPolicyConfig)) pPolicyConfig->memcap = pDefaultPolicyConfig->memcap; _dpd.addPreproc( sc, ReputationMain, PRIORITY_FIRST, PP_REPUTATION, PROTO_BIT__IP ); } static int ReputationReloadVerify(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId reputation_swap_config = (tSfPolicyUserContextId)swap_config; ReputationConfig * pPolicyConfig = NULL; ReputationConfig * pCurrentConfig = NULL; if (reputation_swap_config == NULL) return 0; pPolicyConfig = (ReputationConfig *)sfPolicyUserDataGet(reputation_swap_config, _dpd.getDefaultPolicy()); if (!pPolicyConfig) return 0; if (reputation_config != NULL) { pCurrentConfig = (ReputationConfig *)sfPolicyUserDataGet(reputation_config, _dpd.getDefaultPolicy()); } if (!pCurrentConfig) return 0; if (pPolicyConfig->memcap != pCurrentConfig->memcap) { _dpd.errMsg("Reputation reload: Changing memcap settings requires a restart.\n"); return -1; } #ifdef SHARED_REP /* Shared memory is used*/ if (pPolicyConfig->sharedMem.path || pCurrentConfig->sharedMem.path) { /*Shared memory setting is changed*/ if ( (!pCurrentConfig->sharedMem.path)||(!pPolicyConfig->sharedMem.path) || strcmp(pPolicyConfig->sharedMem.path, pCurrentConfig->sharedMem.path) ||(pPolicyConfig->sharedMem.updateInterval != pCurrentConfig->sharedMem.updateInterval)) { _dpd.errMsg("Reputation reload: Changing memory settings requires a restart.\n"); return -1; } } #endif return 0; } static int ReputationFreeUnusedConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { ReputationConfig *pPolicyConfig = (ReputationConfig *)pData; //do any housekeeping before freeing ReputationConfig if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); Reputation_FreeConfig(pPolicyConfig); } return 0; } static void * ReputationReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId reputation_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = reputation_config; ReputationConfig *pDefaultPolicyConfig = NULL; if (reputation_swap_config == NULL) return NULL; reputation_config = reputation_swap_config; pDefaultPolicyConfig = (ReputationConfig *)sfPolicyUserDataGetDefault(reputation_config); if (pDefaultPolicyConfig->localSegment) IPtables = &pDefaultPolicyConfig->localSegment; sfPolicyUserDataFreeIterate (old_config, ReputationFreeUnusedConfigPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) { /* No more outstanding configs - free the config array */ return (void *)old_config; } return NULL; } static void ReputationReloadSwapFree(void *data) { if (data == NULL) return; ReputationFreeConfig((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/reputation/Makefile.am0000644000000000000000000000264111746560364021311 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_reputation_preproc.la libsf_reputation_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_reputation_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_reputation_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sf_ip.c \ ../include/sfrt.c \ ../include/sfrt_dir.c \ ../include/sfrt_flat.c \ ../include/sfrt_flat_dir.c \ ../include/segment_mem.c \ ../include/sfPolicyUserData.c endif if HAVE_SHARED_REP libsf_reputation_preproc_la_SOURCES = \ spp_reputation.c \ spp_reputation.h \ reputation_config.c \ reputation_config.h \ reputation_utils.c \ reputation_utils.h \ reputation_debug.h \ ./shmem/sflinux_helpers.c \ ./shmem/sflinux_helpers.h \ ./shmem/shmem_common.h \ ./shmem/shmem_config.h \ ./shmem/shmem_config.c \ ./shmem/shmem_datamgmt.h \ ./shmem/shmem_datamgmt.c \ ./shmem/shmem_lib.h \ ./shmem/shmem_lib.c \ ./shmem/shmem_mgmt.h \ ./shmem/shmem_mgmt.c else libsf_reputation_preproc_la_SOURCES = \ spp_reputation.c \ spp_reputation.h \ reputation_config.c \ reputation_config.h \ reputation_utils.c \ reputation_utils.h \ reputation_debug.h endif EXTRA_DIST = \ sf_reputation.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/reputation/Makefile.in0000644000000000000000000006462512260606522021321 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/reputation DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_reputation_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am__libsf_reputation_preproc_la_SOURCES_DIST = spp_reputation.c \ spp_reputation.h reputation_config.c reputation_config.h \ reputation_utils.c reputation_utils.h reputation_debug.h \ ./shmem/sflinux_helpers.c ./shmem/sflinux_helpers.h \ ./shmem/shmem_common.h ./shmem/shmem_config.h \ ./shmem/shmem_config.c ./shmem/shmem_datamgmt.h \ ./shmem/shmem_datamgmt.c ./shmem/shmem_lib.h \ ./shmem/shmem_lib.c ./shmem/shmem_mgmt.h ./shmem/shmem_mgmt.c @HAVE_SHARED_REP_FALSE@am_libsf_reputation_preproc_la_OBJECTS = \ @HAVE_SHARED_REP_FALSE@ spp_reputation.lo reputation_config.lo \ @HAVE_SHARED_REP_FALSE@ reputation_utils.lo @HAVE_SHARED_REP_TRUE@am_libsf_reputation_preproc_la_OBJECTS = \ @HAVE_SHARED_REP_TRUE@ spp_reputation.lo reputation_config.lo \ @HAVE_SHARED_REP_TRUE@ reputation_utils.lo sflinux_helpers.lo \ @HAVE_SHARED_REP_TRUE@ shmem_config.lo shmem_datamgmt.lo \ @HAVE_SHARED_REP_TRUE@ shmem_lib.lo shmem_mgmt.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_reputation_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo sf_ip.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfrt.lo sfrt_dir.lo sfrt_flat.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfrt_flat_dir.lo segment_mem.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_reputation_preproc_la_OBJECTS = \ $(am_libsf_reputation_preproc_la_OBJECTS) \ $(nodist_libsf_reputation_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_reputation_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_reputation_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_reputation_preproc_la_SOURCES) \ $(nodist_libsf_reputation_preproc_la_SOURCES) DIST_SOURCES = $(am__libsf_reputation_preproc_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_reputation_preproc.la libsf_reputation_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_reputation_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_reputation_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_ip.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfrt.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfrt_dir.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfrt_flat.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfrt_flat_dir.c \ @SO_WITH_STATIC_LIB_FALSE@../include/segment_mem.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c @HAVE_SHARED_REP_FALSE@libsf_reputation_preproc_la_SOURCES = \ @HAVE_SHARED_REP_FALSE@spp_reputation.c \ @HAVE_SHARED_REP_FALSE@spp_reputation.h \ @HAVE_SHARED_REP_FALSE@reputation_config.c \ @HAVE_SHARED_REP_FALSE@reputation_config.h \ @HAVE_SHARED_REP_FALSE@reputation_utils.c \ @HAVE_SHARED_REP_FALSE@reputation_utils.h \ @HAVE_SHARED_REP_FALSE@reputation_debug.h @HAVE_SHARED_REP_TRUE@libsf_reputation_preproc_la_SOURCES = \ @HAVE_SHARED_REP_TRUE@spp_reputation.c \ @HAVE_SHARED_REP_TRUE@spp_reputation.h \ @HAVE_SHARED_REP_TRUE@reputation_config.c \ @HAVE_SHARED_REP_TRUE@reputation_config.h \ @HAVE_SHARED_REP_TRUE@reputation_utils.c \ @HAVE_SHARED_REP_TRUE@reputation_utils.h \ @HAVE_SHARED_REP_TRUE@reputation_debug.h \ @HAVE_SHARED_REP_TRUE@./shmem/sflinux_helpers.c \ @HAVE_SHARED_REP_TRUE@./shmem/sflinux_helpers.h \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_common.h \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_config.h \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_config.c \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_datamgmt.h \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_datamgmt.c \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_lib.h \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_lib.c \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_mgmt.h \ @HAVE_SHARED_REP_TRUE@./shmem/shmem_mgmt.c EXTRA_DIST = \ sf_reputation.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/reputation/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/reputation/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_reputation_preproc.la: $(libsf_reputation_preproc_la_OBJECTS) $(libsf_reputation_preproc_la_DEPENDENCIES) $(EXTRA_libsf_reputation_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_reputation_preproc_la_LINK) -rpath $(libdir) $(libsf_reputation_preproc_la_OBJECTS) $(libsf_reputation_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sflinux_helpers.lo: ./shmem/sflinux_helpers.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sflinux_helpers.lo `test -f './shmem/sflinux_helpers.c' || echo '$(srcdir)/'`./shmem/sflinux_helpers.c shmem_config.lo: ./shmem/shmem_config.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shmem_config.lo `test -f './shmem/shmem_config.c' || echo '$(srcdir)/'`./shmem/shmem_config.c shmem_datamgmt.lo: ./shmem/shmem_datamgmt.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shmem_datamgmt.lo `test -f './shmem/shmem_datamgmt.c' || echo '$(srcdir)/'`./shmem/shmem_datamgmt.c shmem_lib.lo: ./shmem/shmem_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shmem_lib.lo `test -f './shmem/shmem_lib.c' || echo '$(srcdir)/'`./shmem/shmem_lib.c shmem_mgmt.lo: ./shmem/shmem_mgmt.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shmem_mgmt.lo `test -f './shmem/shmem_mgmt.c' || echo '$(srcdir)/'`./shmem/shmem_mgmt.c sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sf_ip.lo: ../include/sf_ip.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_ip.lo `test -f '../include/sf_ip.c' || echo '$(srcdir)/'`../include/sf_ip.c sfrt.lo: ../include/sfrt.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfrt.lo `test -f '../include/sfrt.c' || echo '$(srcdir)/'`../include/sfrt.c sfrt_dir.lo: ../include/sfrt_dir.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfrt_dir.lo `test -f '../include/sfrt_dir.c' || echo '$(srcdir)/'`../include/sfrt_dir.c sfrt_flat.lo: ../include/sfrt_flat.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfrt_flat.lo `test -f '../include/sfrt_flat.c' || echo '$(srcdir)/'`../include/sfrt_flat.c sfrt_flat_dir.lo: ../include/sfrt_flat_dir.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfrt_flat_dir.lo `test -f '../include/sfrt_flat_dir.c' || echo '$(srcdir)/'`../include/sfrt_flat_dir.c segment_mem.lo: ../include/segment_mem.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o segment_mem.lo `test -f '../include/segment_mem.c' || echo '$(srcdir)/'`../include/segment_mem.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/0000755000000000000000000000000012260606564020436 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_mgmt.c0000644000000000000000000005275512260565732022676 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_mgmt.c // @author Pramod Chandrashekar #include "shmem_lib.h" #include "shmem_mgmt.h" #include ShmemMgmtData* mgmt_ptr = NULL; void* zeroseg_ptr = NULL; unsigned int usec = SLEEP_TIME; static const char* const MODULE_NAME = "SharedMemMgmt"; static void SetShmemMgmtVariables(int value, uint32_t instance_num) { int i; void* temp_zerosegptr; if (shmusr_ptr->instance_num == instance_num) temp_zerosegptr = zeroseg_ptr; else temp_zerosegptr = mgmt_ptr->instance[instance_num].shmemZeroPtr; if (value == GO_INACTIVE) { mgmt_ptr->instance[instance_num].goInactive = 1; value = mgmt_ptr->instance[instance_num].active; } else { mgmt_ptr->instance[instance_num].goInactive = 0; } mgmt_ptr->instance[instance_num].active = value; mgmt_ptr->instance[instance_num].version = 0; mgmt_ptr->instance[instance_num].activeSegment = NO_DATASEG; mgmt_ptr->instance[instance_num].prevSegment = NO_DATASEG; mgmt_ptr->instance[instance_num].updateTime = time(NULL); mgmt_ptr->instance[instance_num].shmemCurrPtr = temp_zerosegptr; mgmt_ptr->instance[instance_num].shmemZeroPtr = temp_zerosegptr; for (i=0; iinstance[instance_num].shmemSegActiveFlag[i] = 0; for (i=0; iinstance[instance_num].shmemSegmentPtr[i] = temp_zerosegptr; } static void UnsetGoInactive() { int i; for(i=0; iinstance[i].goInactive = 0; } } static void InitShmemDataSegmentMgmtVariables() { int i; mgmt_ptr->activeSegment = NO_DATASEG; for (i=0; isegment[i].version = 0; mgmt_ptr->segment[i].active = 0; mgmt_ptr->segment[i].size = 0; } UnsetGoInactive(); } int MapShmemMgmt() { uint32_t nBytes = sizeof(ShmemMgmtData); int mgmtExists; if (!(mgmtExists = ShmemExists(shmusr_ptr->mgmtSeg))) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "No Shmem mgmt segment present\n");); if (shmusr_ptr->instance_type == READ) return SF_EINVAL; } if ((mgmt_ptr = (ShmemMgmtData *) ShmemMap(shmusr_ptr->mgmtSeg,nBytes,shmusr_ptr->instance_type)) == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Failed to create shmem mgmt segment\n");); return SF_EINVAL; } if (shmusr_ptr->instance_type == WRITE && !mgmtExists) InitShmemDataSegmentMgmtVariables(); return SF_SUCCESS; } static void DoHeartbeat() { uint32_t instance_num = shmusr_ptr->instance_num; if (mgmt_ptr) { mgmt_ptr->instance[instance_num].updateTime = time(NULL); } return; } void ForceShutdown() { int currActiveSegment; _dpd.logMsg(" Reputation Preprocessor: Shared memory is disabled. \n"); if (!mgmt_ptr) return; mgmt_ptr->instance[shmusr_ptr->instance_num].shmemCurrPtr = mgmt_ptr->instance[shmusr_ptr->instance_num].shmemZeroPtr; if ((currActiveSegment = mgmt_ptr->instance[shmusr_ptr->instance_num].activeSegment) >= 0) { mgmt_ptr->instance[shmusr_ptr->instance_num].activeSegment = NO_DATASEG; mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegActiveFlag[currActiveSegment] = 0; } return; } //client side calls for shared memory int CheckForSharedMemSegment() { void *shmem_ptr = NULL; int currActive = NO_DATASEG, newSegment = NO_DATASEG; uint32_t size = 0; if (!mgmt_ptr) { if (MapShmemMgmt()) return newSegment; SetShmemMgmtVariables(ACTIVE,shmusr_ptr->instance_num); } if (mgmt_ptr->instance[shmusr_ptr->instance_num].goInactive) goto exit; if ((currActive = mgmt_ptr->activeSegment) >= 0) { if ( mgmt_ptr->instance[shmusr_ptr->instance_num].activeSegment != currActive && mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegActiveFlag[currActive] != TBMAP ) { //new segment available and not mapped already mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegActiveFlag[currActive] = TBMAP; if ((size = mgmt_ptr->segment[currActive].size) != 0) { if ((shmem_ptr = ShmemMap(shmusr_ptr->dataSeg[currActive],size,READ)) != NULL) { //Store Data segment pointer for instance mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegmentPtr[currActive] = shmem_ptr; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Shmem ptr for segment %d is %p\n",currActive,shmem_ptr);); newSegment = currActive; } else { currActive = NO_DATASEG; } } else { mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegActiveFlag[currActive] = 0; } } } else if (mgmt_ptr->instance[shmusr_ptr->instance_num].activeSegment >= 0) { ForceShutdown(); goto exit; } DoHeartbeat(); exit: DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "new segment being returned is %d\n", newSegment);); return newSegment; } int InitShmemReader ( uint32_t instance_num, int dataset, int group_id, int numa_node, const char* path, void*** data_ptr, uint32_t instance_polltime) { int segment_number = NO_ZEROSEG; if (InitShmemUser(instance_num,READ,dataset,group_id,numa_node,path,instance_polltime)) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Could not initialize config data \n");); return segment_number; } if (dmfunc_ptr->CreatePerProcessZeroSegment(data_ptr)) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Could not initialize zero segment\n");); return segment_number; } zeroseg_ptr = **data_ptr; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Address of zero segment is %p\n",zeroseg_ptr);); if ((segment_number = CheckForSharedMemSegment() ) >=0) { SwitchToActiveSegment(segment_number,data_ptr); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Switched to segment %d\n",segment_number);); } return segment_number; } static int FindFirstUnusedShmemSegment() { int i; for (i=0; isegment[i].active != 1) return i; } return NO_DATASEG; } static int FindActiveSharedMemDataSegmentVersion() { if (mgmt_ptr->activeSegment < 0) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Active segment does not exist\n");); return 0; } DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Active segment is %d and current version is %u\n", mgmt_ptr->activeSegment,mgmt_ptr->segment[mgmt_ptr->activeSegment].version);); return mgmt_ptr->segment[mgmt_ptr->activeSegment].version; } static int MapShmemDataSegmentForWriter(uint32_t size, uint32_t disk_version, int *mode) { int available_segment = NO_DATASEG; uint32_t active_version = 0; void* shmem_ptr = NULL; *mode = WRITE; if ((active_version = FindActiveSharedMemDataSegmentVersion()) == disk_version ) { if ((available_segment = mgmt_ptr->activeSegment) >= 0) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Attaching to segment %d\n", available_segment);); *mode = READ; size = mgmt_ptr->segment[available_segment].size; } else { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "No active segment to attach to\n");); goto exit; } } if (*mode == WRITE) { if ((available_segment = FindFirstUnusedShmemSegment()) < 0) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "No more segments available, all are in use\n");); goto exit; } DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Shared memory segment %d will be initialized\n",available_segment);); } mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegActiveFlag[available_segment] = TBMAP; if ((shmem_ptr = ShmemMap(shmusr_ptr->dataSeg[available_segment],size,*mode)) != NULL) { //store data segment pointer for instance mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegmentPtr[available_segment] = shmem_ptr; } else { mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegActiveFlag[available_segment] = 0; available_segment = NO_DATASEG; } exit: return available_segment; } static void ShutdownSegment(int32_t segment_num) { mgmt_ptr->segment[segment_num].active = 0; mgmt_ptr->segment[segment_num].version = 0; munmap(mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegmentPtr[segment_num], mgmt_ptr->segment[segment_num].size); ShmemDestroy(shmusr_ptr->dataSeg[segment_num]); mgmt_ptr->segment[segment_num].size = 0; mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegmentPtr[segment_num] = mgmt_ptr->instance[shmusr_ptr->instance_num].shmemZeroPtr; } // writer side static int InitSharedMemDataSegmentForWriter(uint32_t size, uint32_t disk_version) { int segment_num = NO_DATASEG, mode = -1; int rval; if ((segment_num = MapShmemDataSegmentForWriter(size,disk_version,&mode)) < 0) goto exit; if (mode == WRITE) { if ((rval = dmfunc_ptr->LoadShmemData((void *)( mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegmentPtr[segment_num]), filelist_ptr, filelist_count)) != SF_SUCCESS) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Loading file into shared memory failed\n");); ShutdownSegment(segment_num); segment_num = NO_DATASEG; goto exit; } mgmt_ptr->segment[segment_num].size = size; if (mgmt_ptr->activeSegment != segment_num) mgmt_ptr->activeSegment = segment_num; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Active segment is %d\n",mgmt_ptr->activeSegment);); mgmt_ptr->segment[segment_num].active = 1; mgmt_ptr->segment[segment_num].version = disk_version; ManageUnusedSegments(); } exit: return segment_num; } int LoadSharedMemDataSegmentForWriter(int startup) { int segment_num = NO_DATASEG; int rval; uint32_t size; uint32_t disk_version, shmem_version; if ( !mgmt_ptr ) return NO_DATASEG; shmem_version = FindActiveSharedMemDataSegmentVersion(); //if version file is not present(open source user), increment version and reload. if (GetLatestShmemDataSetVersionOnDisk(&disk_version) == SF_SUCCESS) { if (disk_version > 0) { if ((shmem_version == disk_version) && !startup) goto exit; } else { goto force_shutdown; } } else { disk_version = shmem_version + 1; if (disk_version == 0) disk_version++; } if ( GetSortedListOfShmemDataFiles( ) != SF_SUCCESS ) goto exit; #ifdef DEBUG_MSGS PrintDataFiles(); #endif if ((size = dmfunc_ptr->GetSegmentSize(filelist_ptr, filelist_count)) != ZEROSEG) { segment_num = InitSharedMemDataSegmentForWriter(size,disk_version); goto exit; } force_shutdown: //got back zero which means its time to shutdown shared memory mgmt_ptr->activeSegment = NO_DATASEG; ForceShutdown(); exit: return segment_num; } int InitShmemWriter( uint32_t instance_num, int dataset, int group_id, int numa_node, const char* path, void*** data_ptr, uint32_t instance_polltime) { int segment_number = NO_ZEROSEG; if (InitShmemUser(instance_num,WRITE,dataset,group_id,numa_node,path,instance_polltime)) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Could not initialize shmem writer config\n");); goto exit; } if (dmfunc_ptr->CreatePerProcessZeroSegment(data_ptr)) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Could not initialize zero segment\n");); goto cleanup_exit; } zeroseg_ptr = **data_ptr; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Address of zero segment is %p\n",zeroseg_ptr);); if (MapShmemMgmt()) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Could not initialize shared memory management segment\n");); FreeShmemDataFileList(); goto cleanup_exit; } ManageUnusedSegments(); SetShmemMgmtVariables(ACTIVE,shmusr_ptr->instance_num); //valid segments are 0 through N if ((segment_number = LoadSharedMemDataSegmentForWriter(STARTUP)) >= 0) SwitchToActiveSegment(segment_number,data_ptr); //pointer switch goto exit; cleanup_exit: FreeShmemUser(); exit: return segment_number; } //switch to active DB void SwitchToActiveSegment(int segment_num, void*** data_ptr) { if ((segment_num < 0)|| (!mgmt_ptr)) return; mgmt_ptr->instance[shmusr_ptr->instance_num].shmemCurrPtr = mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegmentPtr[segment_num]; *data_ptr = (void *)(&mgmt_ptr->instance[shmusr_ptr->instance_num].shmemCurrPtr); mgmt_ptr->instance[shmusr_ptr->instance_num].prevSegment = mgmt_ptr->instance[shmusr_ptr->instance_num].activeSegment; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Prev segment has been set to %d\n", mgmt_ptr->instance[shmusr_ptr->instance_num].prevSegment);); mgmt_ptr->instance[shmusr_ptr->instance_num].activeSegment = segment_num; mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegActiveFlag[segment_num] = 1; } void UnmapInactiveSegments() { int i, segment_num; if (!mgmt_ptr) return; for (i=0; iinstance[shmusr_ptr->instance_num].activeSegment) { if (shmusr_ptr->instance_type != WRITE) { if ((segment_num = mgmt_ptr->instance[shmusr_ptr->instance_num].prevSegment) != NO_DATASEG) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Unmapping segment %d which has address %p and size %u\n", segment_num,mgmt_ptr->instance[shmusr_ptr->instance_num]. shmemSegmentPtr[segment_num],mgmt_ptr->segment[segment_num].size);); munmap(mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegmentPtr[segment_num], mgmt_ptr->segment[segment_num].size); ShmemUnlink(shmusr_ptr->dataSeg[segment_num]); mgmt_ptr->instance[shmusr_ptr->instance_num].prevSegment = NO_DATASEG; mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegmentPtr[i] = mgmt_ptr->instance[shmusr_ptr->instance_num].shmemZeroPtr; } } mgmt_ptr->instance[shmusr_ptr->instance_num].shmemSegActiveFlag[i] = 0; } } DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Active segment for instance %u is %d\n", shmusr_ptr->instance_num,mgmt_ptr->instance[shmusr_ptr->instance_num].activeSegment);); return; } static void ExpireTimedoutInstances() { int i; int64_t max_timeout; time_t current_time = time(NULL); /*timeout will be at least 60 seconds*/ max_timeout = UNUSED_TIMEOUT * (int64_t) shmusr_ptr->instance_polltime + 60; if (max_timeout > UINT32_MAX) max_timeout = UINT32_MAX; for(i=0; iinstance[i].active) { if ((int64_t)current_time > mgmt_ptr->instance[i].updateTime + max_timeout) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Instance %d has expired, last update %jd and current time is %jd\n", i,(intmax_t)mgmt_ptr->instance[i].updateTime,(intmax_t)current_time);); SetShmemMgmtVariables(GO_INACTIVE,i); } } } return; } //WRITER only void ManageUnusedSegments() { uint32_t j,in_use = 0; int i; DoHeartbeat(); //writer heartbeat if (UNUSED_TIMEOUT != -1) ExpireTimedoutInstances(); for (i=0; iinstance[j].active && !mgmt_ptr->instance[j].goInactive) { if (mgmt_ptr->instance[j].shmemSegActiveFlag[i]) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Instance %u is still using segment %d\n",j,i);); in_use++; } } } if (!in_use) { if (mgmt_ptr && mgmt_ptr->segment[i].active && (mgmt_ptr->activeSegment != i)) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Shutting down segment %d\n",i);); ShutdownSegment(i); } } in_use = 0; } if (UNUSED_TIMEOUT != -1) UnsetGoInactive(); } int ShutdownSharedMemory() { if (mgmt_ptr) SetShmemMgmtVariables(INACTIVE,shmusr_ptr->instance_num); FreeShmemUser(); FreeShmemDataMgmtFunctions(); FreeShmemDataFileList(); return SF_SUCCESS; } void ShmemMgmtInfo(char *buf, int bufLen) { uint32_t i; int writed; int len = bufLen -1; char *index = buf; if ( !mgmt_ptr ) return; for (i=0; iinstance[i]); if (shmem_info->shmemCurrPtr) { writed = snprintf(index, len, "instance:%u active:%d goInactive:%d updateTime:%jd\n", i,(int)shmem_info->active, (int)shmem_info->goInactive, (intmax_t)shmem_info->updateTime); if (writed >= len || writed < 0) return; index += writed; len -= writed; writed = snprintf(index, len, "instance:%u activeSegment:%d prevSegment:%d currentPtr:%p zeroPtr:%p\n", i,(int)shmem_info->activeSegment, (int)shmem_info->prevSegment, (void *)shmem_info->shmemCurrPtr, (void *)shmem_info->shmemZeroPtr); if (writed >= len || writed < 0) return; index += writed; len -= writed; } } for (i=0; isegment[i]); writed = snprintf(index, len, "segment:%u active:%d version:%u\n", i,(int)shmem_seg->active,(uint32_t)shmem_seg->version); if (writed >= len || writed < 0) return; index += writed; len -= writed; } writed = snprintf(index, len, "active segment:%d\n\n",mgmt_ptr->activeSegment); /* returning either way */ } void PrintShmemMgmtInfo() { uint32_t i; if ( !mgmt_ptr ) return; for (i=0; iinstance[i]); if (shmem_info->shmemCurrPtr) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "instance:%u active:%d goInactive:%d updateTime:%jd\n", i,(int)shmem_info->active, (int)shmem_info->goInactive, (intmax_t)shmem_info->updateTime);); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "instance:%u activeSegment:%d prevSegment:%d currentPtr:%p zeroPtr:%p\n", i,(int)shmem_info->activeSegment, (int)shmem_info->prevSegment, (void *)shmem_info->shmemCurrPtr, (void *)shmem_info->shmemZeroPtr);); } } for (i=0; isegment[i]); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "segment:%u active:%d version:%u\n", i,(int)shmem_seg->active,(uint32_t)shmem_seg->version);); } DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "active segment:%d\n\n",mgmt_ptr->activeSegment);); } snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_mgmt.h0000644000000000000000000000522712260565732022673 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_mgmt.h // @author Pramod Chandrashekar #ifndef _SHMEMMGMT_H_ #define _SHMEMMGMT_H_ #include #include #include "shmem_config.h" typedef struct _shmemInstance { int active; int goInactive; uint32_t version; time_t updateTime; int activeSegment; int prevSegment; int shmemSegActiveFlag[MAX_SEGMENTS]; void* shmemSegmentPtr[MAX_SEGMENTS]; void* shmemCurrPtr; void* shmemZeroPtr; } shmemInstance; typedef struct _shmemSegment { int active; uint32_t version; uint32_t size; } shmemSegment; typedef struct _shmemMgmtData { shmemInstance instance[MAX_INSTANCES]; shmemSegment segment[MAX_SEGMENTS]; int activeSegment; } ShmemMgmtData; extern void *zeroseg_ptr; //reader int InitShmemReader(uint32_t instance_num, int dataset, int group_id, int numa_node, const char* path, void*** data_ptr, uint32_t instance_polltime); int CheckForSharedMemSegment(void); //writer int InitShmemWriter(uint32_t instance_num, int dataset, int group_id, int numa_node, const char* path, void*** data_ptr, uint32_t instance_polltime); int LoadSharedMemDataSegmentForWriter(int startup); void SwitchToActiveSegment(int segment_num,void*** data_ptr); void UnmapInactiveSegments(void); void ManageUnusedSegments(void); int ShutdownSharedMemory(void); void ShmemMgmtInfo(char *buf, int bufLen); void PrintShmemMgmtInfo(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_lib.c0000644000000000000000000000735012260565732022467 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_lib.c // @author Pramod Chandrashekar #include #include #include #include #include #include "shmem_mgmt.h" #include "shmem_lib.h" static const char* const MODULE_NAME = "ShmemLib"; static int ShmemOpen(const char *shmemName, uint32_t size, int mode) { int fd, flags; mode_t prev_mask; if (mode == WRITE) flags = (O_CREAT | O_RDWR); else if (mode == READ) flags = O_RDWR; else { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Invalid mode specified\n");); return -1; } prev_mask = umask(0); if ( (fd = shm_open(shmemName, flags, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) )) == -1 ) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Unable to open shared memory\n");); umask(prev_mask); return -1; } umask(prev_mask); if (ftruncate(fd, size) == -1) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Unable to open shared memory\n");); return -1; } _dpd.logMsg(" Reputation Preprocessor: Size of shared memory segment %s is %u\n", shmemName, size); return fd; } static void *ShmemMMap (int fd, uint32_t size) { void *shmem_ptr; if ((shmem_ptr = mmap(0, size,(PROT_READ | PROT_WRITE),MAP_SHARED,fd,0)) == MAP_FAILED ) return NULL; return shmem_ptr; } int ShmemExists(const char *shmemName) { int fd; if ((fd = shm_open(shmemName,(O_RDWR),(S_IRUSR))) < 0 ) return 0; close(fd); return SF_EEXIST; } void ShmemUnlink(const char *shmemName) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Unlinking segment %\n",shmemName);); shm_unlink(shmemName); } void ShmemDestroy(const char *shmemName) { ShmemUnlink(shmemName); unlink(shmemName); _dpd.logMsg(" Reputation Preprocessor: %s is freed\n", shmemName); } void* ShmemMap(const char* segment_name, uint32_t size, int mode) { int fd = 0; void *shmem_ptr = NULL; if ((mode == WRITE) && ShmemExists(segment_name)) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Cannot create shared memory segment %s, already exists\n", segment_name);); mode = READ; } if ((fd = ShmemOpen(segment_name,size,mode)) == -1) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Failed to open shm %s\n",segment_name);); return NULL; } if ((shmem_ptr = ShmemMMap(fd,size)) == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Failed to mmmap %s\n",segment_name);); } close(fd); return shmem_ptr; } snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_lib.h0000644000000000000000000000260512260565732022472 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_lib.h // @author Pramod Chandrashekar #ifndef _SHMEMLIB_H_ #define _SHMEMLIB_H_ #include int ShmemExists(const char *shmemName); void* ShmemMap(const char* segment_name, uint32_t size, int mode); void ShmemUnlink(const char *shmemName); void ShmemDestroy(const char *shmemName); #endif snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_datamgmt.c0000644000000000000000000004014512260565732023516 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_datamgmt.c // @author Pramod Chandrashekar #include #include #include #include #include #include #include "shmem_config.h" #include "shmem_common.h" #define MANIFEST_SEPARATORS ",\r\n" #define MIN_MANIFEST_COLUMNS 3 #define WHITE_TYPE_KEYWORD "white" #define BLACK_TYPE_KEYWORD "block" #define MONITOR_TYPE_KEYWORD "monitor" static const char* const MODULE_NAME = "ShmemFileMgmt"; // FIXME eliminate these globals ShmemDataFileList **filelist_ptr = NULL; int filelist_size = 0; // Number of slots in the filelist int filelist_count = 0; // Number of 'used' slots in the file list static inline bool FileListFull( ) { return (filelist_count == filelist_size); } static int StringCompare(const void *elem1, const void *elem2) { ShmemDataFileList * const *a = elem1; ShmemDataFileList * const *b = elem2; return strcmp((*a)->filename,(*b)->filename); } /* (Re)allocate *filelist to the next bucket size. * See `man 3 realloc' for deeper insight. */ static ShmemDataFileList** ShmemDataFileList_Realloc ( ShmemDataFileList *filelist[] ) { ShmemDataFileList **temp; int _size = filelist_size + FILE_LIST_BUCKET_SIZE; // Don't call this function unnecessarily. assert( filelist_size == 0 || filelist_size > filelist_count ); // Use errno to communicate any problems errno = 0; if ( filelist_size >= MAX_IPLIST_FILES ) { errno = ENOSPC; return NULL; } if ( _size > MAX_IPLIST_FILES ) _size = MAX_IPLIST_FILES; // Rely on errno being set by realloc. temp = realloc(filelist, _size * sizeof(*filelist)); if ( temp == NULL ) return NULL; filelist_size = _size; return temp; } static void FreeShmemDataFileListFiles() { int i; if ( !filelist_count || !filelist_ptr ) return; for(i = 0; i < filelist_count; i++) { free(filelist_ptr[i]->filename); free(filelist_ptr[i]); filelist_ptr[i] = NULL; } filelist_count = 0; } void FreeShmemDataFileList() { if ( !filelist_ptr ) return; FreeShmemDataFileListFiles( ); free(filelist_ptr); filelist_ptr = NULL; filelist_size = 0; } static int ReadShmemDataFilesWithoutManifest() { struct dirent *de; DIR *dd; FreeShmemDataFileListFiles(); if ((dd = opendir(shmusr_ptr->path)) == NULL) { _dpd.errMsg("%s: Could not access %s: %s\n", MODULE_NAME, shmusr_ptr->path, strerror(errno)); return SF_EINVAL; } while (( de = readdir(dd) )) { char filename[PATH_MAX]; ShmemDataFileList *listinfo; const char *ext; int type; ext = strrchr(de->d_name , '.'); if ( ext == NULL || *(ext + 1) == '\0' ) continue; if ( strcasecmp(ext, ".blf") == 0 ) type = BLACK_LIST; else if ( strcasecmp(ext, ".wlf") == 0 ) type = WHITE_LIST; else continue; if ( FileListFull() ) { ShmemDataFileList **_temp = ShmemDataFileList_Realloc( filelist_ptr ); if ( !_temp ) { closedir(dd); if ( errno == ENOSPC ) { _dpd.errMsg("%s: Cannot load more than %u ip lists.", MODULE_NAME, MAX_IPLIST_FILES); return SF_ENOSPC; } DynamicPreprocessorFatalMessage("%s: Failed to allocate filelist_ptr: %s\n", MODULE_NAME, strerror(errno)); return SF_ENOMEM; } filelist_ptr = _temp; } listinfo = (ShmemDataFileList *)calloc(1, sizeof(*listinfo)); if ( listinfo == NULL ) { DynamicPreprocessorFatalMessage( "%s: Cannot allocate memory to store file information.\n", MODULE_NAME); } snprintf(filename, sizeof(filename), "%s/%s", shmusr_ptr->path, de->d_name); listinfo->filename = strdup(filename); if ( listinfo->filename == NULL ) { free(listinfo); closedir(dd); DynamicPreprocessorFatalMessage("%s: Error resolving filename: %s\n", MODULE_NAME, strerror(errno)); } listinfo->filetype = type; listinfo->listid = 0; memset(listinfo->zones, true, MAX_NUM_ZONES); filelist_ptr[filelist_count] = listinfo; filelist_count++; } closedir(dd); return SF_SUCCESS; } /*Ignore the space characters from string*/ static char *ignoreStartSpace(char *str) { while((*str) && (isspace((int)*str))) { str++; } return str; } /*Get file type */ static int getFileTypeFromName (char *typeName) { int type = UNKNOWN_LIST; /* Trim the starting spaces */ if (!typeName) return type; typeName = ignoreStartSpace(typeName); if (strncasecmp(typeName, WHITE_TYPE_KEYWORD, strlen(WHITE_TYPE_KEYWORD)) == 0) { type = WHITE_LIST; typeName += strlen(WHITE_TYPE_KEYWORD); } else if (strncasecmp(typeName, BLACK_TYPE_KEYWORD, strlen(BLACK_TYPE_KEYWORD)) == 0) { type = BLACK_LIST; typeName += strlen(BLACK_TYPE_KEYWORD); } else if (strncasecmp(typeName, MONITOR_TYPE_KEYWORD, strlen(MONITOR_TYPE_KEYWORD)) == 0) { type = MONITOR_LIST; typeName += strlen(MONITOR_TYPE_KEYWORD); } if (UNKNOWN_LIST != type ) { /*Ignore spaces in the end*/ typeName = ignoreStartSpace(typeName); if ( *typeName ) { type = UNKNOWN_LIST; } } return type; } /* Parse the line item in manifest file * * The format of manifest is: * file_name, list_id, action (block, white, monitor), zone information * * If no zone information provided, this means all zones are applied. * * */ static ShmemDataFileList* processLineInManifest(char *manifest, char *line, int linenumber) { char* token; int tokenIndex = 0; ShmemDataFileList* listItem = NULL; char* nextPtr = line; char filename[PATH_MAX]; bool hasZone = false; if ((listItem = (ShmemDataFileList*)calloc(1,sizeof(ShmemDataFileList))) == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Cannot allocate memory to " "store reputation manifest file information\n", manifest, linenumber); return NULL; } while((token = strtok_r(nextPtr, MANIFEST_SEPARATORS, &nextPtr)) != NULL) { char *endStr; long zone_id; long list_id; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Process reputation list token: %s\n",token );); switch (tokenIndex) { case 0: /* File name */ DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Reputation list filename: %s\n",token );); snprintf(filename, sizeof(filename), "%s/%s", shmusr_ptr->path,token); listItem->filename = strdup(filename); if (listItem->filename == NULL) { free(listItem); listItem = NULL; DynamicPreprocessorFatalMessage( "%s(%d) => Error resolving filename: %s\n", manifest, linenumber, strerror(errno)); } break; case 1: /* List ID */ list_id = _dpd.SnortStrtol( token, &endStr, 10); /*Ignore spaces in the end*/ endStr = ignoreStartSpace(endStr); if ( *endStr ) { DynamicPreprocessorFatalMessage("%s(%d) => Bad value (%s) specified for listID. " "Please specify an integer between %d and %li.\n", manifest, linenumber, token, 0, MAX_LIST_ID); } if ((list_id < 0) || (list_id > MAX_LIST_ID) || (errno == ERANGE)) { DynamicPreprocessorFatalMessage(" %s(%d) => Value specified (%s) is out of " "bounds. Please specify an integer between %d and %li.\n", manifest, linenumber, token, 0, MAX_LIST_ID); } listItem->listid = (uint32_t) list_id; break; case 2: /* Action */ token = ignoreStartSpace(token); listItem->filetype = getFileTypeFromName(token); if (UNKNOWN_LIST == listItem->filetype) { DynamicPreprocessorFatalMessage(" %s(%d) => Unknown action specified (%s)." " Please specify a value: %s | %s | %s.\n", manifest, linenumber, token, WHITE_TYPE_KEYWORD, BLACK_TYPE_KEYWORD, MONITOR_TYPE_KEYWORD); } break; default: /*Ignore spaces in the beginning*/ token= ignoreStartSpace(token); if (!(*token)) break; zone_id = _dpd.SnortStrtol( token, &endStr, 10); /*Ignore spaces in the end*/ endStr = ignoreStartSpace(endStr); if ( *endStr ) { DynamicPreprocessorFatalMessage("%s(%d) => Bad value (%s) specified for zone. " "Please specify an integer between %d and %li.\n", manifest, linenumber, token, 0, MAX_NUM_ZONES - 1); } if ((zone_id < 0) || (zone_id >= MAX_NUM_ZONES ) || (errno == ERANGE)) { DynamicPreprocessorFatalMessage(" %s(%d) => Value specified (%s) for zone is " "out of bounds. Please specify an integer between %d and %li.\n", manifest, linenumber, token, 0, MAX_NUM_ZONES - 1); } listItem->zones[zone_id] = true; hasZone = true; } tokenIndex++; } if ( tokenIndex < MIN_MANIFEST_COLUMNS ) { free(listItem); if ( tokenIndex > 0 ) { DynamicPreprocessorFatalMessage("%s(%d) => Too few columns in line: %s.\n", manifest, linenumber, line); } return NULL; } if (false == hasZone) { memset(listItem->zones, true, MAX_NUM_ZONES); } return listItem; } /*Parse the manifest file*/ static int ReadShmemDataFilesWithManifest() { FILE *fp; char line[MAX_MANIFEST_LINE_LENGTH]; char manifest_file[PATH_MAX]; int line_number = 0; snprintf(manifest_file, sizeof(manifest_file), "%s/%s",shmusr_ptr->path, MANIFEST_FILENAME); if ((fp = fopen(manifest_file, "r")) == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Error opening file at: %s\n", manifest_file);); return SF_ENOENT; } FreeShmemDataFileListFiles(); while (fgets(line, sizeof(line),fp)) { char* nextPtr = NULL; ShmemDataFileList* listItem; line_number++; DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Reputation manifest: %s\n",line );); /* remove comments */ if( (nextPtr = strchr(line, '#')) ) *nextPtr = '\0'; if ( FileListFull() ) { ShmemDataFileList **_temp = ShmemDataFileList_Realloc( filelist_ptr ); if ( !_temp ) { fclose(fp); if ( errno == ENOSPC ) { _dpd.errMsg("%s: Cannot load more than %u ip lists.", MODULE_NAME, MAX_IPLIST_FILES); return SF_ENOSPC; } DynamicPreprocessorFatalMessage("%s: Failed to allocate filelist_ptr: %s\n", MODULE_NAME, strerror(errno)); return SF_ENOMEM; } filelist_ptr = _temp; } /*Processing the line*/ listItem = processLineInManifest(manifest_file, line, line_number); if ( listItem ) { filelist_ptr[filelist_count] = listItem; filelist_count++; } } fclose(fp); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Successfully processed manifest file: %s\n", MANIFEST_FILENAME);); return SF_SUCCESS; } int GetSortedListOfShmemDataFiles() { int rval; if ((rval = ReadShmemDataFilesWithManifest()) == SF_ENOENT) { if ((rval = ReadShmemDataFilesWithoutManifest()) != SF_SUCCESS) { return rval; } // Only sort when not using a manifest file; manifest ip-lists // need to be used in the order specified used as-is. qsort(filelist_ptr, filelist_count, sizeof(*filelist_ptr), StringCompare); } return SF_SUCCESS; } //valid version values are 1 through UINT_MAX int GetLatestShmemDataSetVersionOnDisk(uint32_t* shmemVersion) { unsigned long tmpVersion; FILE *fp; char line[PATH_MAX]; char version_file[PATH_MAX]; const char *const key = "VERSION"; char* keyend_ptr = NULL; snprintf(version_file, sizeof(version_file), "%s/%s",shmusr_ptr->path,VERSION_FILENAME); if ((fp = fopen(version_file, "r")) == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Error opening file at: %s\n", version_file);); return SF_ENOENT; } while (fgets(line,sizeof(line),fp)) { char *strptr; if ( *line == '#' ) continue; if ( (strptr = strstr(line, key )) && (strptr == line) ) { if ( strlen(line) <= (strlen(key) + 1) ) break; keyend_ptr = line; keyend_ptr += strlen(key) + 1; tmpVersion = strtoul(keyend_ptr,NULL,0); break; } } if (!keyend_ptr) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Invalid file format %s\n", version_file);); fclose(fp); return SF_ENOENT; } if (tmpVersion > UINT_MAX) //someone tampers with the file *shmemVersion = 1; else *shmemVersion = (uint32_t)tmpVersion; fclose(fp); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "version information being returned is %u\n", *shmemVersion);); return SF_SUCCESS; } #ifdef DEBUG_MSGS void PrintListInfo (bool *zones, uint32_t listid) { char zonesInfo[MAX_MANIFEST_LINE_LENGTH]; int zone_id; int buf_len = sizeof(zonesInfo); char *out_buf = zonesInfo; for (zone_id = 0; zone_id < MAX_NUM_ZONES; zone_id++) { int bytesOutput; if (!zones[zone_id]) continue; bytesOutput = snprintf(out_buf, buf_len, "%d,",zone_id); out_buf += bytesOutput; buf_len -= bytesOutput; } DebugMessage(DEBUG_REPUTATION, "List %li has zones defined: %s \n", listid, zonesInfo); } void PrintDataFiles() { int i; for (i=0;i< filelist_count;i++) { DebugMessage(DEBUG_REPUTATION, "File %s of type %d found \n", filelist_ptr[i]->filename, filelist_ptr[i]->filetype); if (filelist_ptr[i]->listid) { PrintListInfo(filelist_ptr[i]->zones, filelist_ptr[i]->listid); } } } #endif /* DEBUG_MSGS */ snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_datamgmt.h0000644000000000000000000000436612260565732023530 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_datamgmt.h // @author Pramod Chandrashekar #ifndef _SHMEM_DMGMT_H_ #define _SHMEM_DMGMT_H_ #include #include #define SF_SUCCESS 0 #define SF_EINVAL 1 // Invalid argument #define SF_ENOMEM 2 // Not enough space #define SF_EEXIST 3 // File exists #define SF_ENOSPC 4 // No space #define SF_ENOENT 5 // No such file or directory #define MAX_NAME 1024 #define FILE_LIST_BUCKET_SIZE 64 #define MAX_NUM_ZONES 1052 #define MAX_MANIFEST_LINE_LENGTH (8*MAX_NUM_ZONES) #define MAX_LIST_ID UINT32_MAX #define MAX_IPLIST_FILES 256 struct _ShmemDataFile { char* filename; int filetype; uint32_t listid; bool zones[MAX_NUM_ZONES]; }; typedef struct _ShmemDataFile ShmemDataFileList; extern ShmemDataFileList** filelist_ptr; extern int filelist_count; /* Functions ****************************************************************/ int GetSortedListOfShmemDataFiles(void); int GetLatestShmemDataSetVersionOnDisk(uint32_t*); void FreeShmemDataFileList(void); #ifdef DEBUG_MSGS void PrintDataFiles(void); void PrintListInfo(bool*, uint32_t); #endif /* DEBUG_MSGS */ #endif /* _SHMEM_DMGMT_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_config.c0000644000000000000000000001102412260565732023157 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_config.c // @author Pramod Chandrashekar #include #include "sf_types.h" #include "sf_dynamic_preprocessor.h" #include "snort_debug.h" #include "sflinux_helpers.h" #include "shmem_config.h" static const char* const MODULE_NAME ="SharedMemConfig"; ShmemUserInfo *shmusr_ptr = NULL; ShmemDataMgmtFunctions *dmfunc_ptr = NULL; static DatasetInfo dataset_names[] = { { "SFIPReputation.rt", IPREP } }; static void ConstructSegmentNames (int dataset, int group_id, int numa_node) { int i; snprintf(shmusr_ptr->mgmtSeg, sizeof(shmusr_ptr->mgmtSeg), "%s.%d.%d",SHMEM_MGMT,group_id,numa_node); for (i=0; idataSeg[i], sizeof(shmusr_ptr->dataSeg[0]), "%s.%d.%d.%d",dataset_names[dataset].name,group_id,numa_node,i); } int InitShmemUser ( uint32_t instance_num, int instance_type, int dataset, int group_id, int numa_node, const char* path, uint32_t instance_polltime) { int rval = SF_EINVAL, num_nodes; if ( (instance_num >= MAX_INSTANCES) || (instance_type != READ && instance_type != WRITE) || (dataset != IPREP) || !path || !instance_polltime ) goto exit; if ((shmusr_ptr = calloc(1, sizeof(*shmusr_ptr))) == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Unable to allocate memory for configuration data");); goto exit; } shmusr_ptr->instance_num = instance_num; shmusr_ptr->instance_type = instance_type; shmusr_ptr->dataset = dataset; shmusr_ptr->group_id = group_id; shmusr_ptr->instance_polltime = instance_polltime; num_nodes = CheckNumaNodes(); if (numa_node > num_nodes) numa_node = NUMA_0; shmusr_ptr->numa_node = numa_node; strncpy(shmusr_ptr->path,path,sizeof(shmusr_ptr->path)); shmusr_ptr->path[sizeof(shmusr_ptr->path)-1] = '\0'; ConstructSegmentNames(dataset,group_id,numa_node); return SF_SUCCESS; exit: DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Error in setting config");); return rval; } int InitShmemDataMgmtFunctions ( CreateMallocZero create_malloc_zero, GetDataSize get_data_size, LoadData load_data) { if ((dmfunc_ptr = (ShmemDataMgmtFunctions*) malloc(sizeof(ShmemDataMgmtFunctions))) == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Could not allocate memory for Shmem Datamanagement function list");); return SF_EINVAL; } dmfunc_ptr->CreatePerProcessZeroSegment = create_malloc_zero; dmfunc_ptr->GetSegmentSize = get_data_size; dmfunc_ptr->LoadShmemData = load_data; return SF_SUCCESS; } void FreeShmemUser() { if (shmusr_ptr) free(shmusr_ptr); shmusr_ptr = NULL; } void FreeShmemDataMgmtFunctions() { if (dmfunc_ptr) free(dmfunc_ptr); dmfunc_ptr = NULL; } void PrintConfig() { int i; _dpd.logMsg("Instance number %u:",shmusr_ptr->instance_num); _dpd.logMsg("Instance type %d:",shmusr_ptr->instance_type); _dpd.logMsg("Instance datatype %d:",shmusr_ptr->dataset); _dpd.logMsg("Instance Group ID %d:",shmusr_ptr->group_id); _dpd.logMsg("Instance Numa node %d:",shmusr_ptr->numa_node); _dpd.logMsg("Instance Poll time %d:",shmusr_ptr->instance_polltime); _dpd.logMsg("Data Path is %s:",shmusr_ptr->path); for (i=0; idataSeg[i]); } snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_config.h0000644000000000000000000000673212260565732023176 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_config.h // @author Pramod Chandrashekar #ifndef _SHMEMCFG_H_ #define _SHMEMCFG_H_ #include #include "shmem_datamgmt.h" //defines shmemdata filelist #include "shmem_common.h" #define SHMEM_MGMT "SFShmemMgmt" #define MAX_SEGMENTS 2 #define MAX_INSTANCES 50 #define WRITE 0 #define READ 1 #define SERVER 0 #define CLIENT1 1 #define CLIENT2 2 #define STARTUP 1 #define RELOAD 0 #define ACTIVE 1 #define INACTIVE 0 #define NO_DATASEG -1 #define NO_ZEROSEG -2 #define UNMAP_OLDSEG -3 #define ZEROSEG 100 #define GO_INACTIVE 10 #define NUMA_0 0 #define NUMA_1 1 #define GROUP_0 0 #define SLEEP_TIME 2 // in micro seconds #define TBMAP 99 #define UNUSED_TIMEOUT -1 //this number is multiplied with outofband check time to determine timeout.If set to -1 it disables expiring timed out instances. #define OUT_OF_BAND_CHEK_TIME 10 typedef struct shmemUserInfo { uint32_t instance_num; //unique ID for each snort instance int instance_type; // READ or WRITE int dataset; // IPRep int group_id; // 0,1... int numa_node; char mgmtSeg[MAX_NAME]; char dataSeg[MAX_SEGMENTS][MAX_NAME]; char path[MAX_NAME]; uint32_t instance_polltime; }ShmemUserInfo; typedef struct { const char *const name; const uint32_t type; } DatasetInfo; typedef struct shmemDataManagmentFunctions { int (*CreatePerProcessZeroSegment)(void*** data_ptr); uint32_t (*GetSegmentSize)(ShmemDataFileList** file_list, int file_count); int (*LoadShmemData)(void* data_ptr, ShmemDataFileList** file_list, int file_count); } ShmemDataMgmtFunctions; typedef int (*CreateMallocZero)(void***); typedef uint32_t (*GetDataSize)(ShmemDataFileList**, int); typedef int (*LoadData)(void*,ShmemDataFileList**,int); extern ShmemDataMgmtFunctions *dmfunc_ptr; extern ShmemUserInfo *shmusr_ptr; void PrintConfig(void); int InitShmemUser( uint32_t instance_num, int instance_type, int dataset, int group_id, int numa_node, const char* path, uint32_t instance_polltime); int InitShmemDataMgmtFunctions( CreateMallocZero create_malloc_zero, GetDataSize get_data_size, LoadData load_data); void FreeShmemUser(void); void FreeShmemDataMgmtFunctions(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/shmem_common.h0000644000000000000000000000273312260565732023216 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file shmem_common.h // @author Pramod Chandrashekar #ifndef _SHMEMCOMMON_H_ #define _SHMEMCOMMON_H_ #include "sf_types.h" #include "snort_debug.h" #include "../reputation_debug.h" #define IPREP 0 #define UNKNOWN_LIST 0 #define MONITOR_LIST 1 #define BLACK_LIST 2 #define WHITE_LIST 3 #define VERSION_FILENAME "IPRVersion.dat" #define MANIFEST_FILENAME "zone.info" #endif snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/sflinux_helpers.h0000644000000000000000000000233412260565732023744 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file sflinux_helpers.h // @author Pramod Chandrashekar #ifndef _SFLINUX_HELPERS_H_ #define _SFLINUX_HELPERS_H_ int CheckNumaNodes(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/reputation/shmem/sflinux_helpers.c0000644000000000000000000000347412260565732023745 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ // @file sflinux_helpers.c // @author Pramod Chandrashekar #include #include #include #include #include #include #include #include #include "shmem_common.h" int CheckNumaNodes() { char filename[1024]; int num_nodes = 0; struct dirent *de; DIR *dir; snprintf(filename, sizeof(filename), "/sys/devices/system/node"); if ((dir = opendir(filename))) { while ((de = readdir(dir))) { if (strncmp(de->d_name, "node", 4) != 0) continue; num_nodes++; } } closedir(dir); DEBUG_WRAP(DebugMessage(DEBUG_REPUTATION, "Number of numa nodes is %d\n",num_nodes);); return num_nodes; } snort-2.9.6.0/src/dynamic-preprocessors/sip/0000755000000000000000000000000012260606564015726 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/sip/sf_sip.dsp0000644000000000000000000001352212153454770017645 00000000000000# Microsoft Developer Studio Project File - Name="sf_sip" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_sip - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_sip.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_sip.mak" CFG="sf_sip - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_sip - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_sip - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_sip - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_sip - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_sip - Win32 Release" # Name "sf_sip - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\inet_aton.c # End Source File # Begin Source File SOURCE=..\include\inet_pton.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_ip.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\sip_config.c # End Source File # Begin Source File SOURCE=.\sip_dialog.c # End Source File # Begin Source File SOURCE=.\sip_parser.c # End Source File # Begin Source File SOURCE=.\sip_roptions.c # End Source File # Begin Source File SOURCE=.\sip_utils.c # End Source File # Begin Source File SOURCE=.\spp_sip.c # End Source File # Begin Source File SOURCE=..\include\strtok_r.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\sip_config.h # End Source File # Begin Source File SOURCE=.\sip_debug.h # End Source File # Begin Source File SOURCE=.\sip_dialog.h # End Source File # Begin Source File SOURCE=.\sip_parser.h # End Source File # Begin Source File SOURCE=.\sip_roptions.h # End Source File # Begin Source File SOURCE=.\sip_utils.h # End Source File # Begin Source File SOURCE=.\spp_sip.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_debug.h0000644000000000000000000000337412260565732017770 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides macros and functions for debugging the preprocessor. * If Snort is not configured to do debugging, macros are empty. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _SIP_DEBUG_H_ #define _SIP_DEBUG_H_ #include #include "snort_debug.h" /******************************************************************** * Macros ********************************************************************/ #define SIP_DEBUG__START_MSG "SIP Start ********************************************" #define SIP_DEBUG__END_MSG "SIP End **********************************************" #endif /* _SIP_DEBUG_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_utils.h0000644000000000000000000000302412260565732020032 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions. * * 2/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef SIP_UTILS_H_ #define SIP_UTILS_H_ #include "sip_config.h" #include "sfhashfcn.h" int SIP_IsEmptyStr(char *); int SIP_TrimSP(const char *, const char *, char **, char** ); SIPMethodNode * SIP_FindMethod(SIPMethodlist, char*, unsigned int); uint32_t strToHash(const char *, int ); #endif /* SIP_UTILS_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_utils.c0000644000000000000000000001050712260565732020031 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions. * * 2/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "sip_utils.h" /******************************************************************** * Function: SIP_IsEmptyStr() * * Checks if string is NULL, empty or just spaces. * String must be 0 terminated. * * Arguments: * char * - string to check * * Returns: * 1 if string is NULL, empty or just spaces * 0 otherwise * ********************************************************************/ int SIP_IsEmptyStr(char *str) { char *end; if (str == NULL) return 1; end = str + strlen(str); while ((str < end) && isspace((int)*str)) str++; if (str == end) return 1; return 0; } /* * Trim spaces non-destructively on both sides of string : '', \t, \n, \r * If string is empty return 0, otherwise 1 * Note: end point to the location start + length, * not necessary the real end of string if not end with \0 */ int SIP_TrimSP(const char *start, const char *end, char **new_start, char** new_end) { char *before; char *after; if (start >= end ) { *new_start = (char *)start; *new_end = *new_start; return 0; } before = (char *) start; // Trim the starting spaces while((before < end) && isspace((int)*before)) { before++; } // This is an empty string if (before == end) { *new_start = (char *)end; *new_end = *new_start; return 0; } // Trim the ending spaces after = (char *) end - 1; while((before < after) && isspace((int)*after)) { after--; } *new_start = before; *new_end = after + 1; return 1; } /******************************************************************** * Function: SIP_FindMethod() * * Find method in the method list by name * * Arguments: * SIPMethodlist - methods list to be searched, * char * - method name, * int - length of the method name * * Returns: * SIPMethodNode*- the founded method node, or NULL if not founded * ********************************************************************/ SIPMethodNode* SIP_FindMethod(SIPMethodlist methods, char* methodName, unsigned int length) { SIPMethodNode* method = NULL; method = methods; while (NULL != method) { if ((length == strlen(method->methodName))&& (strncasecmp(method->methodName, methodName, length) == 0)) { return method; } method = method->nextm; } return method; } /******************************************************************** * Function: strToHash() * * Calculate the hash value of a string * * Arguments: * char * - string to be hashed * int: length of the string * * Returns: * 1 if string is NULL, empty or just spaces * 0 otherwise * ********************************************************************/ uint32_t strToHash(const char *str, int length ) { uint32_t a,b,c,tmp; int i,j,k,l; a = b = c = 0; for (i=0,j=0;i 4) k=4; for (l=0;l #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "sip_roptions.h" #include "spp_sip.h" #include "sf_types.h" #include "sf_dynamic_preprocessor.h" #include "stream_api.h" #include "sf_dynamic_engine.h" #include "sf_snort_plugin_api.h" #include "sfhashfcn.h" #include "profiler.h" #include "sip_utils.h" #include "sip_debug.h" #include "sip_config.h" #include "treenodes.h" #define SIP_ROPT__METHOD "sip_method" #define SIP_ROPT__STATUS_CODE "sip_stat_code" #define SIP_ROPT__HEADER "sip_header" #define SIP_ROPT__BODY "sip_body" /******************************************************************** * Private function prototypes ********************************************************************/ static int SIP_MethodInit(struct _SnortConfig *sc, char *, char *, void **); static int SIP_MethodEval(void *, const uint8_t **, void *); static int SIP_HeaderInit(struct _SnortConfig *sc, char *, char *, void **); static int SIP_HeaderEval(void *, const uint8_t **, void *); static int SIP_StatCodeInit(struct _SnortConfig *sc, char *, char *, void **); static int SIP_StatCodeEval(void *, const uint8_t **, void *); static int SIP_BodyInit(struct _SnortConfig *sc, char *, char *, void **); static int SIP_BodyEval(void *, const uint8_t **, void *); static int SIP_MethodAddFastPatterns(void *, int, int, FPContentInfo **); static inline int SIP_RoptDoEval(SFSnortPacket *p) { if ((p->payload_size == 0) || (p->stream_session_ptr == NULL) || (!IsTCP(p) && !IsUDP(p))) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "No payload or no " "session pointer or not TCP or UDP - not evaluating.\n")); return 0; } return 1; } static inline int IsRequest(SIP_Roptions *ropts) { if (ropts->status_code) return FALSE; else return TRUE; } /* Parsing for the rule option */ static int SIP_MethodInit(struct _SnortConfig *sc, char *name, char *params, void **data) { int flags = 0, mask = 0; char *end = NULL; char *tok; int negated = 0; int numTokens = 0; SipMethodRuleOptData *sdata; SIPMethodNode *method; SIPConfig * sip_parsing_config; if (strcasecmp(name, SIP_ROPT__METHOD) != 0) return 0; /*Evaluate whether all the methods are in the PP configurations */ sip_parsing_config = getParsingSIPConfig(sc); if (NULL == sip_parsing_config) DynamicPreprocessorFatalMessage("%s(%d) => Configuration error!\n", *(_dpd.config_file), *(_dpd.config_line)); /* Must have arguments */ if (SIP_IsEmptyStr(params)) { DynamicPreprocessorFatalMessage("%s(%d) => missing argument to sip_method keyword\n", *(_dpd.config_file), *(_dpd.config_line)); } tok = strtok_r(params, ",", &end); if(!tok) DynamicPreprocessorFatalMessage("%s(%d) => missing argument to sip_method keyword\n", *(_dpd.config_file), *(_dpd.config_line)); while (NULL != tok) { numTokens++; if (tok[0] == '!') { negated = 1; tok++; } /*Only one method is allowed with !*/ if (negated && (numTokens > 1)) { DynamicPreprocessorFatalMessage("%s(%d) => %s, only one method is allowed with ! for %s.\n", *(_dpd.config_file), *(_dpd.config_line), tok, name); } method = SIP_FindMethod (sip_parsing_config->methods, tok, strlen (tok)); /*if method is not found, add it as a user defined method*/ if (NULL == method) { method = SIP_AddUserDefinedMethod(tok, &sip_parsing_config->methodsConfig, &sip_parsing_config->methods ); if (NULL == method) DynamicPreprocessorFatalMessage("%s(%d) => %s can't add new method to %s.\n", *(_dpd.config_file), *(_dpd.config_line), tok, name); _dpd.logMsg("%s(%d) => Add user defined method: %s to SIP preprocessor through rule.\n", *(_dpd.config_file), *(_dpd.config_line), method->methodName); } flags |= 1 << (method->methodFlag - 1); if (negated) mask |= 1 << (method->methodFlag - 1); tok = strtok_r(NULL, ", ", &end); } sdata = (SipMethodRuleOptData *)calloc(1, sizeof(*sdata)); if (sdata == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "sip preprocessor rule option.\n"); } sdata->flags = flags; sdata->mask = mask; *data = (void *)sdata; return 1; } /* Rule option evaluation */ static int SIP_MethodEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; SIPData *sd; SIP_Roptions *ropts; SipMethodRuleOptData *sdata = (SipMethodRuleOptData *)data; uint32_t methodFlag; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Evaluating \"%s\" rule option.\n", SIP_ROPT__METHOD)); if (!SIP_RoptDoEval(p)) return RULE_NOMATCH; sd = (SIPData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_SIP); if (sd == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Rule Flags: %x Data Flags: %x, Mask: %x \n", sdata->flags, ropts->methodFlag, sdata->mask )); // Not response methodFlag = 1 << (ropts->methodFlag - 1); if (IsRequest(ropts) && ((sdata->flags & methodFlag) ^ sdata->mask)) { return RULE_MATCH; } return RULE_NOMATCH; } static int SIP_MethodAddFastPatterns(void *data, int protocol, int direction, FPContentInfo **info) { char *sip = "SIP"; FPContentInfo *method_fp; SipMethodRuleOptData *sdata = (SipMethodRuleOptData *)data; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Evaluating \"%s\" fast pattern rule option.\n", SIP_ROPT__METHOD)); if ((sdata == NULL) || (info == NULL)) return -1; if ((protocol != IPPROTO_TCP) && (protocol != IPPROTO_UDP)) return -1; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "adding info to \"%s\" fast pattern rule option.\n", SIP_ROPT__METHOD)); method_fp = (FPContentInfo *)calloc(1,sizeof(FPContentInfo)); if (NULL == method_fp) return -1; method_fp->content = (char *)malloc(strlen(sip)); if (NULL == method_fp->content) { free(method_fp); return -1; } memcpy(method_fp->content, sip, strlen(sip)); method_fp->length = strlen(sip); *info = method_fp; return 0; } /* Parsing for the rule option */ static int SIP_HeaderInit(struct _SnortConfig *sc, char *name, char *params, void **data) { if (strcasecmp(name, SIP_ROPT__HEADER) != 0) return 0; /* Must not have arguments */ if (!SIP_IsEmptyStr(params)) { DynamicPreprocessorFatalMessage("%s, %s(%d) => rule option: This option has no arguments.\n", SIP_ROPT__HEADER, *(_dpd.config_file), *(_dpd.config_line)); } return 1; } /* Rule option evaluation */ static int SIP_HeaderEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; SIPData *sd; SIP_Roptions *ropts; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Evaluating \"%s\" rule option.\n", SIP_ROPT__HEADER)); if (!SIP_RoptDoEval(p)) return RULE_NOMATCH; sd = (SIPData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_SIP); if (sd == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; if (ropts->header_data != NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Setting cursor to header data: %p.\n", ropts->header_data)); *cursor = ropts->header_data; //Limit the length _dpd.SetAltDetect((uint8_t *)ropts->header_data, ropts->header_len); return RULE_MATCH; } return RULE_NOMATCH; } /* Parsing for the rule option */ static int SIP_StatCodeInit(struct _SnortConfig *sc, char *name, char *params, void **data) { char *end = NULL; char *tok; int i_tok = 0; SipStatCodeRuleOptData *sdata; if (strcasecmp(name, SIP_ROPT__STATUS_CODE) != 0) return 0; /* Must have arguments */ if (SIP_IsEmptyStr(params)) { DynamicPreprocessorFatalMessage("%s(%d) => missing argument to sip_stat_code keyword\n", *(_dpd.config_file), *(_dpd.config_line)); } tok = strtok_r(params, ",", &end); if(!tok) DynamicPreprocessorFatalMessage("%s(%d) => missing argument to sip_stat_code keyword\n", *(_dpd.config_file), *(_dpd.config_line)); sdata = (SipStatCodeRuleOptData *)calloc(1, sizeof(*sdata)); if (sdata == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "sip preprocessor rule option.\n"); } while ((NULL != tok) && (i_tok < SIP_NUM_STAT_CODE_MAX)) { unsigned long statCode = _dpd.SnortStrtoul(tok, NULL, 10); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Rule Status code: %d.\n",sdata->stat_codes[i_tok])); if ((statCode > MAX_STAT_CODE) || ((statCode > NUM_OF_RESPONSE_TYPES - 1) && (statCode < MIN_STAT_CODE))) { DynamicPreprocessorFatalMessage("%s(%d) => Status code %u specified is not a 3 digit number or 1 - %d\n ", *(_dpd.config_file), *(_dpd.config_line), statCode, NUM_OF_RESPONSE_TYPES-1); } sdata->stat_codes[i_tok] = (uint16_t)statCode; tok = strtok_r(NULL, ", ", &end); i_tok++; } if (NULL != tok) DynamicPreprocessorFatalMessage("%s(%d) => More than %d argument to sip_stat_code keyword\n", *(_dpd.config_file), *(_dpd.config_line), SIP_NUM_STAT_CODE_MAX); *data = (void *)sdata; return 1; } /* Rule option evaluation */ static int SIP_StatCodeEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; SIPData *sd; SIP_Roptions *ropts; SipStatCodeRuleOptData *sdata = (SipStatCodeRuleOptData *)data; uint16_t short_code; int i_code; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Evaluating \"%s\" rule option.\n", SIP_ROPT__STATUS_CODE)); if (!SIP_RoptDoEval(p)) return RULE_NOMATCH; sd = (SIPData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_SIP); if (sd == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Status code in packet: %d \n", ropts->status_code)); if (0 == ropts->status_code) return RULE_NOMATCH; /*Match the status code*/ short_code = ropts->status_code / 100; for(i_code = 0; i_code < SIP_NUM_STAT_CODE_MAX; i_code++) { if ((sdata->stat_codes[i_code] == short_code)|| (sdata->stat_codes[i_code] == ropts->status_code)) return RULE_MATCH; } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Rule No Match\n")); return RULE_NOMATCH; } /* Parsing for the rule option */ static int SIP_BodyInit(struct _SnortConfig *sc, char *name, char *params, void **data) { if (strcasecmp(name, SIP_ROPT__BODY) != 0) return 0; /* Must not have arguments */ if (!SIP_IsEmptyStr(params)) { DynamicPreprocessorFatalMessage("%s, %s(%d) => rule option: This option has no arguments.\n", SIP_ROPT__BODY, *(_dpd.config_file), *(_dpd.config_line)); } return 1; } /* Rule option evaluation */ static int SIP_BodyEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; SIPData *sd; SIP_Roptions *ropts; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Evaluating \"%s\" rule option.\n", SIP_ROPT__BODY)); if (!SIP_RoptDoEval(p)) return RULE_NOMATCH; sd = (SIPData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_SIP); if (sd == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; if (ropts->body_data != NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Setting cursor to body data: %p.\n", ropts->body_data)); *cursor = ropts->body_data; //Limit the length _dpd.SetAltDetect((uint8_t *)ropts->body_data, ropts->body_len); return RULE_MATCH; } return RULE_NOMATCH; } /******************************************************************** * Function: SIP_RegRuleOptions * * Purpose: Register rule options * * Arguments: void * * Returns: void * ********************************************************************/ void SIP_RegRuleOptions(struct _SnortConfig *sc) { _dpd.preprocOptRegister(sc, SIP_ROPT__METHOD, SIP_MethodInit, SIP_MethodEval, free, NULL, NULL, NULL, SIP_MethodAddFastPatterns); _dpd.preprocOptRegister(sc, SIP_ROPT__HEADER, SIP_HeaderInit, SIP_HeaderEval, NULL, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, SIP_ROPT__STATUS_CODE, SIP_StatCodeInit, SIP_StatCodeEval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, SIP_ROPT__BODY, SIP_BodyInit, SIP_BodyEval, NULL, NULL, NULL, NULL, NULL); } snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_dialog.h0000644000000000000000000000266512260565732020143 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions. * * 3/15/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef SIP_DIALOG_H_ #define SIP_DIALOG_H_ #include "spp_sip.h" int SIP_updateDialog(SIPMsg *sipMsg, SIP_DialogList *dList, SFSnortPacket *p); void sip_freeDialogs (SIP_DialogList *list); #endif /* SIP_DIALOG_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_dialog.c0000644000000000000000000005517012260565732020135 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for dialog management * Dialog management is the central part of SIP call flow analysis * * 3/15/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "sip_dialog.h" #include "sip_parser.h" #include "sip_debug.h" #include "sf_ip.h" #include "spp_sip.h" #include "stream_api.h" #include static void SIP_updateMedias(SIP_MediaSession *, SIP_MediaList *); static int SIP_compareMedias(SIP_MediaDataList , SIP_MediaDataList ); static int SIP_checkMediaChange(SIPMsg *sipMsg, SIP_DialogData *dialog); static int SIP_processRequest(SIPMsg *, SIP_DialogData *, SIP_DialogList *, SFSnortPacket *); static int SIP_processInvite(SIPMsg *, SIP_DialogData *, SIP_DialogList *); static int SIP_processACK(SIPMsg *, SIP_DialogData *, SIP_DialogList *, SFSnortPacket *); static int SIP_processResponse(SIPMsg *, SIP_DialogData *, SIP_DialogList *, SFSnortPacket *); static int SIP_ignoreChannels( SIP_DialogData *, SFSnortPacket *p); static SIP_DialogData* SIP_addDialog(SIPMsg *, SIP_DialogData *, SIP_DialogList *); static int SIP_deleteDialog(SIP_DialogData *, SIP_DialogList *); #ifdef DEBUG_MSGS void SIP_displayMedias(SIP_MediaList *dList); #endif /******************************************************************** * Function: SIP_processRequest() * * Based on the new received sip request message, update the dialog information. * Note: dialog is created through dialog * Arguments: * SIPMsg * - sip request message * SIP_DialogData* - dialog to be updated, * SFSnortPacket* - the packet * * Returns: * SIP_SUCCESS: request message has been processed correctly * SIP_FAILURE: request message has not been processed correctly ********************************************************************/ static int SIP_processRequest(SIPMsg *sipMsg, SIP_DialogData *dialog, SIP_DialogList *dList, SFSnortPacket *p) { SIPMethodsFlag methodFlag; int ret = SIP_SUCCESS; assert (NULL != sipMsg); /*If dialog not exist, create one */ if((NULL == dialog)&&(SIP_METHOD_CANCEL != sipMsg->methodFlag)) { dialog = SIP_addDialog(sipMsg, dList->head, dList); } methodFlag = sipMsg->methodFlag; sip_stats.requests[TOTAL_REQUESTS]++; if (methodFlag > 0) sip_stats.requests[methodFlag]++; switch (methodFlag) { case SIP_METHOD_INVITE: ret = SIP_processInvite(sipMsg, dialog, dList); break; case SIP_METHOD_CANCEL: if (NULL == dialog) return SIP_FAILURE; /*dialog can be deleted in the early state*/ if((SIP_DLG_EARLY == dialog->state)||(SIP_DLG_INVITING == dialog->state) || (SIP_DLG_CREATE == dialog->state)) SIP_deleteDialog(dialog, dList); break; case SIP_METHOD_ACK: SIP_processACK(sipMsg, dialog, dList, p); break; case SIP_METHOD_BYE: if(SIP_DLG_ESTABLISHED == dialog->state) dialog->state = SIP_DLG_TERMINATING; break; default: break; } return ret; } /******************************************************************** * Function: SIP_processInvite() * * Based on the new received sip invite request message, update the dialog information. * Note: dialog is created through dialog * Arguments: * SIPMsg * - sip request message * SIP_DialogData* - dialog to be updated, * SIP_DialogList*- dialog list * Returns: * SIP_SUCCESS: * SIP_FAILURE: ********************************************************************/ static int SIP_processInvite(SIPMsg *sipMsg, SIP_DialogData *dialog, SIP_DialogList *dList) { int ret = SIP_SUCCESS; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Processing invite, dialog state %d \n", dialog->state );); if (NULL == dialog) return SIP_FAILURE; /*Check for the invite replay attack: authenticated invite without challenge*/ // check whether this invite has authorization information if ((SIP_DLG_AUTHENCATING != dialog->state) && (NULL != sipMsg ->authorization)) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Dialog state code: %u\n", dialog->status_code)); ALERT(SIP_EVENT_AUTH_INVITE_REPLAY_ATTACK,SIP_EVENT_AUTH_INVITE_REPLAY_ATTACK_STR); return SIP_FAILURE; } if (SIP_DLG_ESTABLISHED == dialog->state) { /* this is the case of re-INVITE*/ // create a temporary new dialog before the current dialog dialog = SIP_addDialog(sipMsg, dialog, dList); dialog->state = SIP_DLG_REINVITING; return SIP_SUCCESS; } /*Check for the fake busy attack: change media session before dialog established*/ else if((SIP_DLG_INVITING == dialog->state) || (SIP_DLG_EARLY == dialog->state) || (SIP_DLG_REINVITING == dialog->state)|| (SIP_DLG_AUTHENCATING == dialog->state)) { ret = SIP_checkMediaChange(sipMsg, dialog); if (SIP_FAILURE == ret) ALERT(SIP_EVENT_AUTH_INVITE_DIFF_SESSION,SIP_EVENT_AUTH_INVITE_DIFF_SESSION_STR); SIP_updateMedias(sipMsg->mediaSession, &dialog->mediaSessions); } else if (SIP_DLG_TERMINATED == dialog->state) { SIP_updateMedias(sipMsg->mediaSession, &dialog->mediaSessions); } dialog->state = SIP_DLG_INVITING; return ret; } /******************************************************************** * Function: SIP_processACK() * * Based on the new received sip ACK request message, update the dialog information. * Note: dialog is created through dialog * Arguments: * SIPMsg * - sip request message * SIP_DialogData* - dialog to be updated, * SIP_DialogList* - dialog list * SFSnortPacket* - the packet * Returns: * SIP_SUCCESS: * SIP_FAILURE: ********************************************************************/ static int SIP_processACK(SIPMsg *sipMsg, SIP_DialogData *dialog, SIP_DialogList *dList, SFSnortPacket *p) { if (NULL == dialog) return SIP_FAILURE; if (SIP_DLG_ESTABLISHED == dialog->state) { if ((SIP_METHOD_INVITE == dialog->creator)&&(SIP_checkMediaChange(sipMsg, dialog) == SIP_FAILURE)) { SIP_updateMedias(sipMsg->mediaSession, &dialog->mediaSessions); SIP_ignoreChannels(dialog, p); } } return SIP_SUCCESS; } /******************************************************************** * Function: SIP_processResponse() * * Based on the new received sip response message, update the dialog information. * * Arguments: * SIPMsg * - sip response message * SIP_DialogData* - dialog to be updated, * SFSnortPacket* - the packet * * Returns: * SIP_SUCCESS: * SIP_FAILURE: ********************************************************************/ static int SIP_processResponse(SIPMsg *sipMsg, SIP_DialogData *dialog, SIP_DialogList *dList, SFSnortPacket *p) { int statusType; SIP_DialogData *currDialog = dialog; assert (NULL != sipMsg); statusType = sipMsg->status_code / 100; sip_stats.responses[TOTAL_RESPONSES]++; if (statusType < NUM_OF_RESPONSE_TYPES) sip_stats.responses[statusType]++; if(NULL == dialog) return SIP_FAILURE; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Processing response, dialog state %d \n", dialog->state );); if(sipMsg->status_code > 0) dialog->status_code = sipMsg->status_code; switch (statusType) { case 0: break; case RESPONSE1XX: if (SIP_DLG_CREATE == currDialog->state) currDialog->state = SIP_DLG_EARLY; SIP_updateMedias(sipMsg->mediaSession, &dialog->mediaSessions); break; case RESPONSE2XX: if (SIP_DLG_REINVITING == currDialog->state) { SIP_deleteDialog(currDialog->nextD, dList); if (SIP_checkMediaChange(sipMsg, dialog) == SIP_FAILURE) { SIP_updateMedias(sipMsg->mediaSession, &dialog->mediaSessions); SIP_ignoreChannels(currDialog, p); } currDialog->state = SIP_DLG_ESTABLISHED; } else if (SIP_DLG_TERMINATING == currDialog->state) { SIP_deleteDialog(currDialog, dList); return SIP_SUCCESS; } else { if ((SIP_METHOD_INVITE == currDialog->creator)&& (SIP_checkMediaChange(sipMsg, dialog) == SIP_FAILURE)) { SIP_updateMedias(sipMsg->mediaSession, &dialog->mediaSessions); SIP_ignoreChannels(currDialog, p); } currDialog->state = SIP_DLG_ESTABLISHED; } break; case RESPONSE3XX: case RESPONSE4XX: case RESPONSE5XX: case RESPONSE6XX: // If authentication is required if((401 == sipMsg->status_code) || (407 == sipMsg->status_code)) { currDialog->state = SIP_DLG_AUTHENCATING; } /*Failed re-Invite will resume to the original state*/ else if(SIP_DLG_REINVITING == currDialog->state) { SIP_deleteDialog(currDialog, dList); } else currDialog->state = SIP_DLG_TERMINATED; break; default: break; } return SIP_SUCCESS; } /******************************************************************** * Function: SIP_checkMediaChange() * * Based on the new received sip invite request message, check whether SDP has been changed * * Arguments: * SIPMsg * - sip request message * SIP_DialogData* - dialog to be updated, * * Returns: * SIP_SUCCESS: media not changed * SIP_FAILURE: media changed ********************************************************************/ static int SIP_checkMediaChange(SIPMsg *sipMsg, SIP_DialogData *dialog) { SIP_MediaSession *medias; // Compare the medias (SDP part) if (NULL == sipMsg->mediaSession) return SIP_SUCCESS; medias = dialog->mediaSessions; while(NULL != medias) { if (sipMsg->mediaSession->sessionID == medias->sessionID) break; medias = medias->nextS; } if (NULL == medias) { // Can't find the media session by ID, SDP has been changed. DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Can't find the media data, ID: %u\n", sipMsg->mediaSession->sessionID );); return SIP_FAILURE; } // The media content has been changed if (0 != SIP_compareMedias(medias->medias, sipMsg->mediaSession->medias)) { // Can't find the media session by ID, SDP has been changed. DEBUG_WRAP(DebugMessage(DEBUG_SIP, "The media data is different!\n");); return SIP_FAILURE; } return SIP_SUCCESS; } /******************************************************************** * Function: SIP_ignoreChannels * * Ignore the channels in the current dialog: for a dialog,there will be media * sessions, one from each side of conversation * * Arguments: * SIP_DialogData * - the current dialog * * * Returns: * SIP_SUCCESS: the channel has been ignored * SIP_FAILURE: the channel has not been ignored * ********************************************************************/ static int SIP_ignoreChannels( SIP_DialogData *dialog, SFSnortPacket *p) { SIP_MediaData *mdataA,*mdataB; if (0 == sip_eval_config->ignoreChannel) return SIP_FAILURE; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Ignoring the media data in Dialog: %u\n", dialog->dlgID.callIdHash);); // check the first media session if (NULL == dialog->mediaSessions) return SIP_FAILURE; // check the second media session if (NULL == dialog->mediaSessions->nextS) return SIP_FAILURE; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Ignoring the media sessions ID: %u and %u\n", dialog->mediaSessions->sessionID, dialog->mediaSessions->nextS->sessionID);); mdataA = dialog->mediaSessions->medias; mdataB = dialog->mediaSessions->nextS->medias; sip_stats.ignoreSessions++; while((NULL != mdataA)&&(NULL != mdataB)) { void *ssn; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Ignoring channels Source IP: %s Port: %u\n", sfip_to_str(&mdataA->maddress), mdataA->mport);); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Ignoring channels Destine IP: %s Port: %u\n", sfip_to_str(&mdataB->maddress), mdataB->mport);); /* Call into Streams to mark data channel as something to ignore. */ if ((ssn = _dpd.streamAPI->get_session_ptr_from_ip_port(&mdataA->maddress,mdataA->mport, &mdataB->maddress, mdataB->mport, IPPROTO_UDP, 0, 0, 0))) { _dpd.streamAPI->set_ignore_direction(ssn, SSN_DIR_BOTH); } else { _dpd.streamAPI->ignore_session(&mdataA->maddress, mdataA->mport, &mdataB->maddress, mdataB->mport, IPPROTO_UDP, p->pkt_header->ts.tv_sec, PP_SIP, SSN_DIR_BOTH, 0 /* Not permanent */ ); } sip_stats.ignoreChannels++; mdataA = mdataA->nextM; mdataB = mdataB->nextM; } return SIP_SUCCESS; } /******************************************************************** * Function: SIP_compareMedias * * Compare two media list * * Arguments: * SIPMsg * - the message used to create a dialog * SIP_DialogData * - the current dialog location * SIP_DialogList * - the dialogs to be added. * * * Returns: * 1: not the same * 0: the same * ********************************************************************/ static int SIP_compareMedias(SIP_MediaDataList mlistA, SIP_MediaDataList mlistB ) { SIP_MediaData *mdataA,*mdataB; mdataA = mlistA; mdataB = mlistB; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Compare the media data \n");); while((NULL != mdataA) && (NULL != mdataB)) { if(sfip_compare(&mdataA->maddress, &mdataB->maddress) != SFIP_EQUAL) break; if((mdataA->mport != mdataB->mport)|| (mdataA->numPort != mdataB->numPort)) break; mdataA = mdataA->nextM; mdataB = mdataB->nextM; } if((NULL == mdataA) && (NULL == mdataB)) return 0; else return 1; } /******************************************************************** * Function: SIP_updateMedias() * * Based on the new received media session information, update the media list. * If not in the current list, created one and add it to the head. * * Arguments: * SIP_MediaSession* - media session * SIP_MediaList* - media session list to be updated, * * Returns: * ********************************************************************/ static void SIP_updateMedias(SIP_MediaSession *mSession, SIP_MediaList *dList) { SIP_MediaSession *currSession, *preSession = NULL; if(NULL == mSession) return; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Updating session id: %u\n", mSession->sessionID)); mSession->savedFlag = SIP_SESSION_SAVED; // Find out the media session based on session id currSession = *dList; while(NULL != currSession) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Session id: %u\n", currSession->sessionID)); if(currSession->sessionID == mSession->sessionID) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Found Session id: %u\n", currSession->sessionID)); break; } preSession = currSession; currSession = currSession->nextS; } // if this is a new session data, add to the list head if (NULL == currSession) { mSession->nextS = *dList; *dList = mSession; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Add Session id: %u\n", mSession->sessionID)); // Display the final media session #ifdef DEBUG_MSGS SIP_displayMedias(dList); #endif return; } // if this session needs to be updated DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Insert Session id: %u\n", mSession->sessionID)); mSession->nextS = currSession->nextS; // if this is the header, update the new header if (NULL == preSession) *dList = mSession; else preSession->nextS = mSession; // Clear the old session currSession->nextS = NULL; sip_freeMediaSession(currSession); // Display the final media session #ifdef DEBUG_MSGS SIP_displayMedias(dList); #endif return; } #ifdef DEBUG_MSGS void SIP_displayMedias(SIP_MediaList *dList) { SIP_MediaSession *currSession; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Updated Session information------------\n")); currSession = *dList; while(NULL != currSession) { SIP_MediaData *mdata; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Session id: %u\n", currSession->sessionID)); mdata = currSession->medias; while(NULL != mdata) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Media IP: %s, port: %u, number of ports %u\n", sfip_to_str(&mdata->maddress), mdata->mport, mdata->numPort)); mdata = mdata->nextM; } currSession = currSession->nextS; } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "End of Session information------------\n")); } #endif /******************************************************************** * Function: SIP_addDialog * * Add a sip dialog before the current dialog * * Arguments: * SIPMsg * - the message used to create a dialog * SIP_DialogData * - the current dialog location * SIP_DialogList * - the dialogs to be added. * * * Returns: None * ********************************************************************/ static SIP_DialogData* SIP_addDialog(SIPMsg *sipMsg, SIP_DialogData *currDialog, SIP_DialogList *dList) { SIP_DialogData* dialog; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Add Dialog id: %u, From: %u, To: %u, status code: %u\n", sipMsg->dlgID.callIdHash,sipMsg->dlgID.fromTagHash,sipMsg->dlgID.toTagHash, sipMsg->status_code)); sip_stats.dialogs++; dialog = (SIP_DialogData *) calloc(1, sizeof(SIP_DialogData)); if (NULL == dialog) return NULL; // Add to the head dialog->nextD = currDialog; if(NULL != currDialog) { dialog->prevD = currDialog->prevD; if (NULL != currDialog->prevD) currDialog->prevD->nextD = dialog; else dList->head = dialog; // become the head currDialog->prevD = dialog; } else { // The first dialog dialog->prevD = NULL; dList->head = dialog; } dialog->dlgID = sipMsg->dlgID; dialog->creator = sipMsg->methodFlag; dialog->state = SIP_DLG_CREATE; SIP_updateMedias(sipMsg->mediaSession, &dialog->mediaSessions); dList->num_dialogs++; return dialog; } /******************************************************************** * Function: SIP_deleteDialog * * Delete a sip dialog from the list * * Arguments: * SIP_DialogData * - the current dialog to be deleted * SIP_DialogList * - the dialog list. * * Returns: None * ********************************************************************/ static int SIP_deleteDialog(SIP_DialogData *currDialog, SIP_DialogList *dList) { if ((NULL == currDialog)||(NULL == dList)) return SIP_FAILURE; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Delete Dialog id: %u, From: %u, To: %u \n", currDialog->dlgID.callIdHash,currDialog->dlgID.fromTagHash,currDialog->dlgID.toTagHash)); // If this is the header if(NULL == currDialog->prevD) { if(NULL != currDialog->nextD) currDialog->nextD->prevD = NULL; dList->head = currDialog->nextD; } else { currDialog->prevD->nextD = currDialog->nextD; if(NULL != currDialog->nextD) currDialog->nextD->prevD = currDialog->prevD; } sip_freeMediaList(currDialog->mediaSessions); free(currDialog); if( dList->num_dialogs > 0) dList->num_dialogs--; return SIP_SUCCESS; } /******************************************************************** * Function: SIP_updateDialog() * * Based on the new received sip message, update the dialog information. * If not in the current list, created one and add it to the head. * * Arguments: * SIPMsg * - sip message * SIP_DialogList* - dialog list to be updated, * * Returns: * SIP_SUCCESS: dialog has been updated * SIP_FAILURE: dialog has not been updated ********************************************************************/ int SIP_updateDialog(SIPMsg *sipMsg, SIP_DialogList *dList, SFSnortPacket *p) { SIP_DialogData* dialog; SIP_DialogData* oldDialog = NULL; int ret; if ((NULL == sipMsg)||(0 == sipMsg->dlgID.callIdHash)) return SIP_FAILURE; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Updating Dialog id: %u, From: %u, To: %u\n", sipMsg->dlgID.callIdHash,sipMsg->dlgID.fromTagHash,sipMsg->dlgID.toTagHash)); dialog = dList->head; /*Find out the dialog in the dialog list*/ while(NULL != dialog) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Dialog id: %u, From: %u, To: %u\n", dialog->dlgID.callIdHash,dialog->dlgID.fromTagHash,dialog->dlgID.toTagHash)); if (sipMsg->dlgID.callIdHash == dialog->dlgID.callIdHash) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Found Dialog id: %u, From: %u, To: %u\n", dialog->dlgID.callIdHash,dialog->dlgID.fromTagHash,dialog->dlgID.toTagHash)); break; } oldDialog = dialog; dialog = dialog->nextD; } /*If the number of dialogs exceeded, release the oldest one*/ if((dList->num_dialogs >= sip_eval_config->maxNumDialogsInSession) && (!dialog)) { ALERT(SIP_EVENT_MAX_DIALOGS_IN_A_SESSION, SIP_EVENT_MAX_DIALOGS_IN_A_SESSION_STR); SIP_deleteDialog(oldDialog, dList); } /*Update the dialog information*/ if (sipMsg->status_code == 0) ret = SIP_processRequest(sipMsg, dialog, dList, p); else if (sipMsg->status_code > 0) ret = SIP_processResponse(sipMsg, dialog, dList, p); else ret = SIP_FAILURE; return ret; } /******************************************************************** * Function: sip_freeDialogs * * Frees a sip dialog * * Arguments: * SIP_DialogList * The dialogs to free. * * Returns: None * ********************************************************************/ void sip_freeDialogs (SIP_DialogList *list) { SIP_DialogData *nextNode; SIP_DialogData *curNode = list->head; while (NULL != curNode) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "*Clean Dialog creator: 0x%x, id: %u, From: %u, To: %u, State: %d\n", curNode->creator, curNode->dlgID.callIdHash,curNode->dlgID.fromTagHash,curNode->dlgID.toTagHash,curNode->state)); nextNode = curNode->nextD; sip_freeMediaList(curNode->mediaSessions); free(curNode); curNode = nextNode; } } snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_parser.h0000644000000000000000000000313512260565732020171 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 2/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef _SIP_PARSER_H_ #define _SIP_PARSE_H_ #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "sip_debug.h" #include "spp_sip.h" #include "sf_ip.h" int sip_parse(SIPMsg *, const char *, char *); void sip_freeMsg (SIPMsg *msg); void sip_freeMediaSession (SIP_MediaSession*); void sip_freeMediaList (SIP_MediaList medias); #endif snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_parser.c0000644000000000000000000011301512260565732020163 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 2/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef HAVE_PARSER_H #include #include "sf_types.h" #include "sf_snort_packet.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "sip_parser.h" #include "spp_sip.h" #include "sip_config.h" #include "sip_utils.h" #include "sf_ip.h" #define MAX_NUM_32BIT 2147483647 #define SIP_PARSE_NOFOLDING (-2) #define SIP_PARSE_ERROR (-1) #define SIP_PARSE_SUCCESS (1) /*Should at least have SIP/2.0 */ #define SIP_KEYWORD "SIP/" #define SIP_KEYWORD_LEN 4 #define SIP_VERSION_NUM_LEN 3 /*2.0 or 1.0 or 1.1*/ #define SIP_VERSION_LEN SIP_KEYWORD_LEN + SIP_VERSION_NUM_LEN #define SIP_MIN_MSG_LEN SIP_VERSION_LEN #define SIP_TAG_KEYWORD "tag=" #define SIP_TAG_KEYWORD_LEN 4 static int sip_headers_parse(SIPMsg *, const char *, char *,char **); static int sip_startline_parse(SIPMsg *, const char *, char *,char **); static int sip_body_parse(SIPMsg *, const char *, char *, char **); static int sip_check_headers(SIPMsg *); static int sip_parse_via(SIPMsg *, const char *, const char *); static int sip_parse_from(SIPMsg *, const char *, const char *); static int sip_parse_to(SIPMsg *, const char *, const char *); static int sip_parse_call_id(SIPMsg *, const char *, const char *); static int sip_parse_cseq(SIPMsg *, const char *, const char *); static int sip_parse_contact(SIPMsg *, const char *, const char *); static int sip_parse_authorization(SIPMsg *, const char *, const char *); static int sip_parse_content_type(SIPMsg *, const char *, const char *); static int sip_parse_content_len(SIPMsg *, const char *, const char *); static int sip_parse_content_encode(SIPMsg *, const char *, const char *); static int sip_process_headField(SIPMsg *, const char *, const char *, int *); static int sip_process_bodyField(SIPMsg *, const char *, const char *); static int sip_parse_sdp_o(SIPMsg *, const char *, const char *); static int sip_parse_sdp_c(SIPMsg *, const char *, const char *); static int sip_parse_sdp_m(SIPMsg *, const char *, const char *); static int sip_find_linebreak(const char *, char *, char **); /* * Header fields and processing functions */ typedef struct _SIPheaderField { char *fname; int fnameLen; char *shortName; int (*setfield) (SIPMsg *, const char *,const char *); } SIPheaderField; /* * Body fields and processing functions */ typedef struct _SIPbodyField { char *fname; int fnameLen; int (*setfield) (SIPMsg *, const char *,const char *); } SIPbodyField; /* * header field name, short form field name, and field processing function */ SIPheaderField headerFields[] = { {"Via", 3, "v", &sip_parse_via}, {"From", 4,"f", &sip_parse_from}, {"To", 2, "t", &sip_parse_to}, {"Call-ID", 7, "i", &sip_parse_call_id}, {"CSeq", 4, NULL, &sip_parse_cseq}, {"Contact", 7, "m", &sip_parse_contact}, {"Authorization", 13, NULL, &sip_parse_authorization}, {"Content-Type", 12, "c", &sip_parse_content_type}, {"Content-Length", 14, "l", &sip_parse_content_len}, {"Content-Encoding", 16, "e", &sip_parse_content_encode}, {NULL, 0, NULL, NULL} }; /* * body field name, field processing function */ SIPbodyField bodyFields[] = { {"o=", 2, &sip_parse_sdp_o}, {"c=", 2, &sip_parse_sdp_c}, {"m=", 2, &sip_parse_sdp_m}, {NULL, 0, NULL} }; /******************************************************************** * Function: sip_process_headField() * * Process the header fields (lines). This also deals with folding. * * Arguments: * SIPMsg * - sip message * char* start - start of the header line * char* end - end of the header line * int* - index of last field processed. Used for folding processing * This value will be updated after current field been processed * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_process_headField(SIPMsg *msg, const char *start, const char *end, int *lastFieldIndex) { int findex =0; int length = end -start; char *colonIndex; char *newStart, *newEnd, newLength; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "process line: %.*s\n", length, start)); // If this is folding if((' ' == start[0]) || ('\t' == start[0])) { if(SIP_PARSE_NOFOLDING != *lastFieldIndex) { SIP_TrimSP(start, end, &newStart, &newEnd); return(headerFields[*lastFieldIndex].setfield(msg, newStart, newEnd)); } } // Otherwise, continue normal processing colonIndex = memchr(start, ':', length); if (!colonIndex || (colonIndex < start + 1)) return SIP_PARSE_ERROR; if (!SIP_TrimSP(start, colonIndex, &newStart, &newEnd)) return SIP_PARSE_ERROR; newLength = newEnd - newStart; /*Find out whether the field name needs to process*/ while (NULL != headerFields[findex].fname) { //Use the full name to check if ((headerFields[findex].fnameLen == newLength)&& (0 == strncasecmp(headerFields[findex].fname, newStart, newLength))) { break; } //Use short name to check else if ((NULL != headerFields[findex].shortName) && ( 1 == newLength)&& (0 == strncasecmp(headerFields[findex].shortName, newStart, newLength))) { break; } findex++; } if (NULL != headerFields[findex].fname) { // Found the field name, evaluate the value SIP_TrimSP(colonIndex + 1, end, &newStart, &newEnd); *lastFieldIndex = findex; return (headerFields[findex].setfield(msg, newStart, newEnd)); } *lastFieldIndex = SIP_PARSE_NOFOLDING; return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_process_bodyField() * * Process the body fields. * * Arguments: * SIPMsg * - sip message * char* start - start of the line * char* end - end of the line * * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_process_bodyField(SIPMsg *msg, const char *start, const char *end) { int findex =0; if (start == end) return SIP_PARSE_SUCCESS; /*Find out whether the field name needs to process*/ while (NULL != bodyFields[findex].fname) { int length = bodyFields[findex].fnameLen; if (0 == strncasecmp(bodyFields[findex].fname, start,length)) { return (bodyFields[findex].setfield(msg,start + length, end)); } findex++; } return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_find_linebreak() * * Find the line break \r \n in the current buffer * * Arguments: * char* start - start of the buffer * char* end - end of the buffer * char **lineEnd - output, point to the end of the line defined by line breaks * Returns: * int - number of line breaks found in the line found. ********************************************************************/ static int sip_find_linebreak(const char *start, char *end, char **lineEnd) { int numCRLF; char *s = (char *)start; *lineEnd = NULL; numCRLF = 0; if (start >= end) return 0; while ((s < end) && !('\r' ==*s || '\n' == *s)) { s++; } if (s == end) return 0; s++; numCRLF = 1; if ((s < end) && ('\r' == s[-1]) && ('\n' == s[0])) { s++; numCRLF = 2; } *lineEnd= s; return numCRLF; } /******************************************************************** * Function: sip_is_valid_version() * * Check whether the version is a valid version (2.0, 1.1, 1.0) * * Arguments: * char* start - start of the version * * Returns: * SIP_TRUE * SIP_FALSE ********************************************************************/ static inline int sip_is_valid_version(const char *start) { if (!strncmp(start, "1.", 2)) { if ((*(start+2) == '1') || (*(start+2) == '0')) return SIP_TRUE; } else if (!strncmp(start, "2.0", 3)) return SIP_TRUE; return SIP_FALSE; } /******************************************************************** * Function: sip_startline_parse() * * Parse the start line: request and response are different * * Arguments: * SIPMsg * - sip message * char* buff - start of the sip message buffer * char* end - end of the buffer * char**lineEnd - output, the found end of start line * Returns: * SIP_FAILURE * SIP_SUCCESS ********************************************************************/ static int sip_startline_parse(SIPMsg *msg, const char *buff, char *end, char **lineEnd) { char *next; char *start; int length; int numOfLineBreaks; start = (char *) buff; numOfLineBreaks = sip_find_linebreak(start, end, &next); if (numOfLineBreaks < 1) { /*No CRLF */ DEBUG_WRAP(DebugMessage(DEBUG_SIP, "No CRLF, check failed\n")); return SIP_FAILURE; } /*Exclude CRLF from start line*/ length = next - start - numOfLineBreaks; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Start line: %.*s \n", length, start)); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "End of Start line \n")); /*Should at least have SIP/2.0 */ if (length < SIP_MIN_MSG_LEN) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Message too short, check failed\n")); return SIP_FAILURE; } *lineEnd = next; // This is a response if (0 == strncmp((const char *) buff, (const char *) SIP_KEYWORD, SIP_KEYWORD_LEN)) { char *space; unsigned long statusCode; /*Process response*/ msg->method = NULL; msg->uri = NULL; /*Check SIP version number, end with SP*/ if (!(sip_is_valid_version(buff + SIP_KEYWORD_LEN) && (*(buff + SIP_VERSION_LEN) == ' '))) { ALERT(SIP_EVENT_INVALID_VERSION,SIP_EVENT_INVALID_VERSION_STR); } space = strchr(buff, ' '); if (space == NULL) return SIP_FAILURE; statusCode = _dpd.SnortStrtoul(space + 1, NULL, 10); if (( statusCode > MAX_STAT_CODE) || (statusCode < MIN_STAT_CODE )) { ALERT(SIP_EVENT_BAD_STATUS_CODE,SIP_EVENT_BAD_STATUS_CODE_STR) msg->status_code = MAX_STAT_CODE + 1; } else msg->status_code = (uint16_t)statusCode; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Status code: %d \n", msg->status_code)); } else /* This might be a request*/ { char *space; char *version; int length; SIPMethodNode *method; /*Process request*/ if (NULL ==sip_eval_config) return SIP_FAILURE; msg->status_code = 0; // Parse the method space = memchr(buff, ' ', end - buff); if (space == NULL) return SIP_FAILURE; length = space - buff; msg->method = (char*)buff; msg->methodLen = length; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "method: %.*s\n", msg->methodLen, msg->method)); method = SIP_FindMethod (sip_eval_config->methods, msg->method, msg->methodLen); if (method) { msg->methodFlag = method->methodFlag; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Found the method: %s, Flag: 0x%x\n", method->methodName, method->methodFlag)); } // parse the uri if (space + 1 > end) return SIP_FAILURE; msg->uri = space + 1; space = memchr(space + 1, ' ', end - msg->uri); if (space == NULL) return SIP_FAILURE; msg->uriLen = space - msg->uri; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "uri: %.*s, length: %u\n", msg->uriLen, msg->uri, msg->uriLen)); if(0 == msg->uriLen) ALERT(SIP_EVENT_EMPTY_REQUEST_URI,SIP_EVENT_EMPTY_REQUEST_URI_STR) else if (sip_eval_config->maxUriLen && (msg->uriLen > sip_eval_config->maxUriLen)) ALERT(SIP_EVENT_BAD_URI,SIP_EVENT_BAD_URI_STR); version = space + 1; if (version + SIP_VERSION_LEN > end) return SIP_FAILURE; if (0 != strncmp((const char *) version, (const char *) SIP_KEYWORD, SIP_KEYWORD_LEN)) return SIP_FAILURE; /*Check SIP version number, end with CRLF*/ if (!sip_is_valid_version(*lineEnd - SIP_VERSION_NUM_LEN - numOfLineBreaks)) { ALERT(SIP_EVENT_INVALID_VERSION,SIP_EVENT_INVALID_VERSION_STR); } if (NULL == method) { ALERT(SIP_EVENT_UNKOWN_METHOD, SIP_EVENT_UNKOWN_METHOD_STR); return SIP_FAILURE; } } return SIP_SUCCESS; } /******************************************************************** * Function: sip_headers_parse() * * Parse the SIP header: request and response are the same * * Arguments: * SIPMsg * - sip message * char* buff - start of the header * char* end - end of the buffer * char**lineEnd - output, the found end of header * Returns: * SIP_FAILURE * SIP_SUCCESS ********************************************************************/ static int sip_headers_parse(SIPMsg *msg, const char *buff, char *end, char **headEnd) { char *next; char *start; int length; int numOfLineBreaks; int lastFieldIndex = SIP_PARSE_NOFOLDING ; start = (char *) buff; /* * The end of header is defined by two CRLFs, or CRCR, or LFLF */ numOfLineBreaks = sip_find_linebreak(start, end, &next); while (numOfLineBreaks > 0) { /*Processing this line*/ length = next - start - numOfLineBreaks; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Header line: %.*s\n", length, start)); /*Process headers*/ sip_process_headField(msg, start, start + length, &lastFieldIndex); /*check the end of header*/ if ((1 == numOfLineBreaks) && ( start[0] == start[-1])) { /*Either CRCR or LFLF*/ *headEnd = next ; return SIP_SUCCESS; } else if ( (2 == numOfLineBreaks) && ('\r' == start[0])&&('\n' == start[1])) { *headEnd = next; return SIP_SUCCESS; } start = next; numOfLineBreaks = sip_find_linebreak(start, end, &next); } return SIP_SUCCESS; } /******************************************************************** * Function: sip_body_parse() * * Parse the SIP body: request and response are the same * * Arguments: * SIPMsg * - sip message * char* buff - start of the body * char* end - end of the buffer * char**lineEnd - output, the found end of body * Returns: * SIP_FAILURE * SIP_SUCCESS ********************************************************************/ static int sip_body_parse(SIPMsg *msg, const char *buff, char *end, char **bodyEnd) { int length; char *next; char *start; int numOfLineBreaks; length = end - buff; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Body length: %d\n", length);); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Body line: %.*s\n", length, buff);); // Initialize it *bodyEnd = end; if (buff == end) return SIP_SUCCESS; msg->body_data = (uint8_t *)buff; // Create a media session msg->mediaSession = (SIP_MediaSession *)calloc(1, sizeof(SIP_MediaSession)); if (NULL == msg->mediaSession) return SIP_FAILURE; start = (char *) buff; /* * The end of body is defined by two CRLFs or CRCR or LFLF */ numOfLineBreaks = sip_find_linebreak(start, end, &next); while (numOfLineBreaks > 0) { /*Processing this line*/ length = next - start - numOfLineBreaks; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Body line: %.*s\n", length, start)); /*Process body fields*/ sip_process_bodyField(msg, start, start + length); start = next; numOfLineBreaks = sip_find_linebreak(start, end, &next); } *bodyEnd = start; return SIP_SUCCESS; } /******************************************************************** * Function: sip_check_headers() * * Check whether the headers are mal-formed. * Most checks are here, except some need context information are scattered * in the parsing. * * Arguments: * SIPMsg * - sip message * * Returns: * SIP_FAILURE * SIP_SUCCESS ********************************************************************/ static int sip_check_headers(SIPMsg *msg) { int ret = SIP_SUCCESS; if(0 == msg->fromLen) { ALERT(SIP_EVENT_EMPTY_FROM,SIP_EVENT_EMPTY_FROM_STR) ret = SIP_FAILURE; } else if (sip_eval_config->maxFromLen && (msg->fromLen > sip_eval_config->maxFromLen)) { ALERT(SIP_EVENT_BAD_FROM,SIP_EVENT_BAD_FROM_STR); ret = SIP_FAILURE; } if(0 == msg->toLen) { ALERT(SIP_EVENT_EMPTY_TO,SIP_EVENT_EMPTY_TO_STR) ret = SIP_FAILURE; } else if (sip_eval_config->maxToLen && (msg->toLen > sip_eval_config->maxToLen)) { ALERT(SIP_EVENT_BAD_TO,SIP_EVENT_BAD_TO_STR); ret = SIP_FAILURE; } if(0 == msg->callIdLen) { ALERT(SIP_EVENT_EMPTY_CALL_ID,SIP_EVENT_EMPTY_CALL_ID_STR) ret = SIP_FAILURE; } else if ( sip_eval_config->maxCallIdLen && (msg->callIdLen > sip_eval_config->maxCallIdLen)) { ALERT(SIP_EVENT_BAD_CALL_ID,SIP_EVENT_BAD_CALL_ID_STR); ret = SIP_FAILURE; } if(msg->cseqnum > MAX_NUM_32BIT) { ALERT(SIP_EVENT_BAD_CSEQ_NUM,SIP_EVENT_BAD_CSEQ_NUM_STR); ret = SIP_FAILURE; } if ( sip_eval_config->maxRequestNameLen && (msg->cseqNameLen > sip_eval_config->maxRequestNameLen)) { ALERT(SIP_EVENT_BAD_CSEQ_NAME,SIP_EVENT_BAD_CSEQ_NAME_STR); ret = SIP_FAILURE; } /*Alert here after parsing*/ if(0 == msg->viaLen) { ALERT(SIP_EVENT_EMPTY_VIA,SIP_EVENT_EMPTY_VIA_STR) ret = SIP_FAILURE; } else if (sip_eval_config->maxViaLen && (msg->viaLen > sip_eval_config->maxViaLen)) { ALERT(SIP_EVENT_BAD_VIA,SIP_EVENT_BAD_VIA_STR); ret = SIP_FAILURE; } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Method flag: %d\n", msg->methodFlag)); // Contact is required for invite message if((0 == msg->contactLen)&&(msg->methodFlag == SIP_METHOD_INVITE)&&(0 == msg->status_code)) { ALERT(SIP_EVENT_EMPTY_CONTACT,SIP_EVENT_EMPTY_CONTACT_STR) ret = SIP_FAILURE; } else if (sip_eval_config->maxContactLen && (msg->contactLen > sip_eval_config->maxContactLen)) { ALERT(SIP_EVENT_BAD_CONTACT,SIP_EVENT_BAD_CONTACT_STR); ret = SIP_FAILURE; } if((0 == msg->contentTypeLen) && (msg->content_len > 0)) { ALERT(SIP_EVENT_EMPTY_CONTENT_TYPE,SIP_EVENT_EMPTY_CONTENT_TYPE_STR) ret = SIP_FAILURE; } return ret; } /******************************************************************** * Function: sip_parse_via() * * Parse the via field: Via can have multiple header * * Arguments: * SIPMsg * - sip message * char* start - start of the via filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_via(SIPMsg *msg, const char *start, const char *end) { int length = end -start; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Via value: %.*s\n", length, start);); msg->viaLen = msg->viaLen + length; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Via length: %d\n", msg->viaLen);); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_from() * * Parse the from field and get from tag * Note: From has no multiple header * * Arguments: * SIPMsg * - sip message * char* start - start of the from filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_from(SIPMsg *msg, const char *start, const char *end) { DEBUG_WRAP(int length = end -start;) char *buff; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "From value: %.*s\n", length, start);); msg->from = (char *)start; msg->fromLen = end - start; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "From length: %d , content: %.*s\n", msg->fromLen, msg->fromLen, msg->from);); /*Get the from tag*/ msg->fromTagLen = 0; buff = memchr(start, ';', msg->fromLen); while ((NULL != buff)&& (buff < end)) { if (0 == strncmp(buff + 1, SIP_TAG_KEYWORD, SIP_TAG_KEYWORD_LEN)) { msg->from_tag = buff + SIP_TAG_KEYWORD_LEN + 1; msg->fromTagLen = end - msg->from_tag; msg->dlgID.fromTagHash = strToHash(msg->from_tag,msg->fromTagLen); break; } buff = memchr(buff + 1, ';', msg->fromLen); } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "From tag length: %d , hash: %u, content: %.*s\n", msg->fromTagLen, msg->dlgID.fromTagHash, msg->fromTagLen, msg->from_tag);); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_to() * * Parse the to field and get to tag information * Note: To has no multiple header * * Arguments: * SIPMsg * - sip message * char* start - start of the to filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_to(SIPMsg *msg, const char *start, const char *end) { DEBUG_WRAP(int length = end -start;) char *buff; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "To value: %.*s\n", length, start);); msg->to = (char *)start; msg->toLen = end - start; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "To length: %d , content: %.*s\n", msg->toLen, msg->toLen, msg->to);); /*Processing tag information*/ msg->toTagLen = 0; buff = memchr(start, ';', msg->toLen); while ((NULL != buff)&& (buff < end)) { if (0 == strncmp(buff + 1, SIP_TAG_KEYWORD, SIP_TAG_KEYWORD_LEN)) { msg->to_tag = buff + SIP_TAG_KEYWORD_LEN + 1; msg->toTagLen = end - msg->to_tag; msg->dlgID.toTagHash = strToHash(msg->to_tag,msg->toTagLen); break; } buff = memchr(buff + 1, ';', msg->toLen); } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "To tag length: %d , Hash: %u, content: %.*s\n", msg->toTagLen, msg->dlgID.toTagHash, msg->toTagLen, msg->to_tag);); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_call_id() * * Parse the call-id field * Note: call-id has no multiple header * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_call_id(SIPMsg *msg, const char *start, const char *end) { DEBUG_WRAP(int length = end -start;) DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Call-Id value: %.*s\n", length, start);); msg->call_id = (char *) start; msg->callIdLen = end - start; msg->dlgID.callIdHash = strToHash(msg->call_id, msg->callIdLen); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Call-Id length: %d, Hash: %u\n", msg->callIdLen, msg->dlgID.callIdHash);); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_cseq() * * Parse the cseq field: get sequence number and request name * Note: Cseq has no multiple header * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_cseq(SIPMsg *msg, const char *start, const char *end) { char *next = NULL; DEBUG_WRAP(int length = end -start;) SIPMethodNode* method = NULL; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "CSeq value: %.*s\n", length, start);); msg->cseqnum = _dpd.SnortStrtoul(start, &next, 10); if ((NULL != next )&&(next < end)) { msg->cseqName = next + 1; msg->cseqNameLen = end - msg->cseqName; method = SIP_FindMethod (sip_eval_config->methods, msg->cseqName, msg->cseqNameLen); } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "CSeq number: %d, CSeqName: %.*s\n", msg->cseqnum, msg->cseqNameLen, msg->cseqName);); if (NULL == method) { ALERT(SIP_EVENT_INVALID_CSEQ_NAME,SIP_EVENT_INVALID_CSEQ_NAME_STR) return SIP_PARSE_ERROR; } else { /*Use request name only for response message*/ if ((SIP_METHOD_NULL == msg->methodFlag)&&( msg->status_code > 0)) msg->methodFlag = method->methodFlag; else if ( method->methodFlag != msg->methodFlag) { ALERT(SIP_EVENT_MISMATCH_METHOD,SIP_EVENT_MISMATCH_METHOD_STR) } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Found the method: %s, Flag: 0x%x\n", method->methodName, method->methodFlag)); } return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_contact() * * Parse the to contact field * Note: Contact has multiple header * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_contact(SIPMsg *msg, const char *start, const char *end) { int length = end -start; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Contact value: %.*s\n", length, start);); msg->contact = (char *) start; msg->contactLen = msg->contactLen + length; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Contact length: %d\n", msg->contactLen);); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_authorization() * * Parse the to authorization field * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_authorization(SIPMsg *msg, const char *start, const char *end) { DEBUG_WRAP(int length = end -start;) DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Authorization value: %.*s\n", length, start);); msg->authorization = (char *) start; return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_content_type() * * Parse the to content type field * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_content_type(SIPMsg *msg, const char *start, const char *end) { DEBUG_WRAP(int length = end -start;) DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Content type value: %.*s\n", length, start);); msg->contentTypeLen = end - start; msg->content_type = (char *) start; return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_content_len() * * Parse the to content length field * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_content_len(SIPMsg *msg, const char *start, const char *end) { char *next = NULL; #ifdef DEBUG int length; length = end - start; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Content length value: %.*s\n", length, start);); #endif msg->content_len = _dpd.SnortStrtoul(start, &next, 10); if ( sip_eval_config->maxContentLen && (msg->content_len > sip_eval_config->maxContentLen)) ALERT(SIP_EVENT_BAD_CONTENT_LEN,SIP_EVENT_BAD_CONTENT_LEN_STR); /*Check the length of the value*/ if (next > start + SIP_CONTENT_LEN) // This check is to prevent overflow { if (sip_eval_config->maxContentLen) ALERT(SIP_EVENT_BAD_CONTENT_LEN,SIP_EVENT_BAD_CONTENT_LEN_STR); return SIP_PARSE_ERROR; } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Content length: %u\n", msg->content_len);); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_content_encode() * * Parse the to content encode field * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_content_encode(SIPMsg *msg, const char *start, const char *end) { DEBUG_WRAP(int length = end -start;) DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Content encode value: %.*s\n", length, start);); msg->content_encode = (char *) start; return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_sdp_o() * * Parse SDP origination information * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_sdp_o(SIPMsg *msg, const char *start, const char *end) { int length; char *spaceIndex = NULL; if (NULL == msg->mediaSession) return SIP_PARSE_ERROR; length = end - start; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Origination information: %.*s\n", length, start);); // Get username and session ID information (before second space) spaceIndex = memchr(start, ' ', length); // first space if ((NULL == spaceIndex)||(spaceIndex == end)) return SIP_PARSE_ERROR; spaceIndex = memchr(spaceIndex + 1, ' ', end - spaceIndex -1 ); // second space if (NULL == spaceIndex) return SIP_PARSE_ERROR; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Session information: %.*s\n", spaceIndex - start, start);); msg->mediaSession->sessionID = strToHash(start, spaceIndex - start); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Session ID: %u\n", msg->mediaSession->sessionID);); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_sdp_c() * * Parse SDP connection data * * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_sdp_c(SIPMsg *msg, const char *start, const char *end) { int length; sfip_t *ip; char ipStr[INET6_ADDRSTRLEN + 5]; /* Enough for IPv4 plus netmask or full IPv6 plus prefix */ char *spaceIndex = NULL; if (NULL == msg->mediaSession) return SIP_PARSE_ERROR; length = end - start; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Connection data: %.*s\n", length, start);); /*Get the IP address*/ spaceIndex = memchr(start, ' ', length); // first space if ((NULL == spaceIndex)||(spaceIndex == end)) return SIP_PARSE_ERROR; spaceIndex = memchr(spaceIndex + 1, ' ', end - spaceIndex -1 ); // second space if (NULL == spaceIndex) return SIP_PARSE_ERROR; length = end - spaceIndex; memset(ipStr, 0, sizeof(ipStr)); if(length > INET6_ADDRSTRLEN) { length = INET6_ADDRSTRLEN; } strncpy(ipStr, spaceIndex, length); ipStr[length] = '\0'; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "IP data: %s\n", ipStr);); // If no default session connect information, add it if(NULL == msg->mediaSession->medias) { ip = &(msg->mediaSession->maddress_default); } else // otherwise, update the latest media data (header of media list) { ip = &(msg->mediaSession->medias->maddress); } if( (sfip_pton(ipStr, ip)) != SFIP_SUCCESS) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Parsed error! \n");); return SIP_PARSE_ERROR; } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Parsed Connection data: %s\n", sfip_to_str (ip));); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse_sdp_c() * * Parse media type information * Note: to make it easier update the media address, media data are added to the header of media list * Arguments: * SIPMsg * - sip message * char* start - start of the filed line * char* end - end of the line * Returns: * SIP_PARSE_ERROR * SIP_PARSE_SUCCESS ********************************************************************/ static int sip_parse_sdp_m(SIPMsg *msg, const char *start, const char *end) { int length; char *spaceIndex = NULL; char *next; SIP_MediaData *mdata; if (NULL == msg->mediaSession) return SIP_PARSE_ERROR; length = end - start; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Media information: %.*s\n", length, start);); spaceIndex = memchr(start, ' ', length); // first space if ((NULL == spaceIndex)||(spaceIndex == end)) return SIP_PARSE_ERROR; mdata = (SIP_MediaData *) calloc(1, sizeof(SIP_MediaData)); if (NULL == mdata) return SIP_PARSE_ERROR; mdata->mport = (uint16_t) _dpd.SnortStrtoul(spaceIndex + 1, &next, 10); if ((NULL != next)&&('/'==next[0])) mdata->numPort = (uint8_t)_dpd.SnortStrtoul(spaceIndex + 1, &next, 10); // Put mdata->nextM = msg->mediaSession->medias; mdata->maddress = msg->mediaSession->maddress_default; msg->mediaSession->medias = mdata; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Media IP: %s, Media port %u, number of media: %d\n", sfip_to_str(&mdata->maddress), mdata->mport, mdata->numPort);); return SIP_PARSE_SUCCESS; } /******************************************************************** * Function: sip_parse() * * The main entry for parser: process the sip messages. * * Arguments: * SIPMsg * - sip message * char* buff - start of the sip message buffer * char* end - end of the buffer * * Returns: * SIP_FAILURE * SIP_SUCCESS ********************************************************************/ int sip_parse(SIPMsg *msg, const char *buff, char *end) { char *nextIndex; char *start; int status; /*Initialize key values*/ msg->methodFlag = SIP_METHOD_NULL; msg->status_code = 0; /*Parse the start line*/ start = (char *) buff; nextIndex = NULL; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Start parsing...\n")); msg->header = (uint8_t *) buff; status = sip_startline_parse(msg, start, end, &nextIndex); if(SIP_FAILURE == status ) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Start line parsing failed...\n")); return status; } /*Parse the headers*/ start = nextIndex; status = sip_headers_parse(msg, start, end, &nextIndex); msg->headerLen = nextIndex - buff; if(SIP_FAILURE == status ) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Header parsing failed...\n")); } status = sip_check_headers(msg); if(SIP_FAILURE == status ) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Headers validation failed...\n")); } /*Parse the body*/ start = nextIndex; msg->bodyLen = end - start; /*Disable this check for TCP. Revisit this again when PAF enabled for SIP*/ if((!msg->isTcp)&&(msg->content_len > msg->bodyLen)) ALERT(SIP_EVENT_MISMATCH_CONTENT_LEN,SIP_EVENT_MISMATCH_CONTENT_LEN_STR); if (msg->content_len < msg->bodyLen) status = sip_body_parse(msg, start, start + msg->content_len, &nextIndex); else status = sip_body_parse(msg, start, end, &nextIndex); if(SIP_FAILURE == status ) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Headers validation failed...\n")); } // Find out whether multiple SIP messages in this packet /*Disable this check for TCP. Revisit this again when PAF enabled for SIP*/ if ((!msg->isTcp) && (msg->content_len < msg->bodyLen)) { if (SIP_SUCCESS == sip_startline_parse(msg, start + msg->content_len, end, &nextIndex)) { ALERT(SIP_EVENT_MULTI_MSGS,SIP_EVENT_MULTI_MSGS_STR); } else { ALERT(SIP_EVENT_MISMATCH_CONTENT_LEN,SIP_EVENT_MISMATCH_CONTENT_LEN_STR); } } return status; } /******************************************************************** * Function: sip_freeMsg * * Frees a sip msg. * Media session information will be release if they are not used by dialog. * * Arguments: * SIPMsg * * The sip message to free. * * Returns: None * ********************************************************************/ void sip_freeMsg (SIPMsg *msg) { if (NULL == msg) return; if (NULL != msg->mediaSession) { if (SIP_SESSION_SAVED != msg->mediaSession->savedFlag) sip_freeMediaSession(msg->mediaSession); } } /******************************************************************** * Function: sip_freeMediaSession * * Frees a sip media session * * Arguments: * SIP_MediaSession * * The media session to free. * * Returns: None * ********************************************************************/ void sip_freeMediaSession (SIP_MediaSession *mediaSession) { SIP_MediaData *nextNode; SIP_MediaData *curNode = NULL; if (NULL != mediaSession) { curNode = mediaSession->medias; } while (NULL != curNode) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Clear media ip: %s, port: %d, number of port: %d\n", sfip_to_str(&curNode->maddress), curNode->mport, curNode->numPort )); nextNode = curNode->nextM; free(curNode); curNode = nextNode; } if (NULL != mediaSession) free (mediaSession); } /******************************************************************** * Function: sip_freeMediaList * * Frees a sip media session list * * Arguments: * SIP_MediaList * The media session list to free. * * Returns: None * ********************************************************************/ void sip_freeMediaList (SIP_MediaList medias) { SIP_MediaSession *nextNode; SIP_MediaSession *curNode = medias; while (NULL != curNode) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Clean Media session default IP: %s, session ID: %u\n", sfip_to_str(&curNode->maddress_default), curNode->sessionID)); nextNode = curNode->nextS; sip_freeMediaSession(curNode); curNode = nextNode; } } #endif snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_config.h0000644000000000000000000001011712260565732020140 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 2/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifndef _SIP_CONFIG_H_ #define _SIP_CONFIG_H_ #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "sip_debug.h" #define SIP_NAME "sip" typedef enum _SIP_method { SIP_METHOD_NULL = 0, //0x0000, SIP_METHOD_INVITE = 1, //0x0001, SIP_METHOD_CANCEL = 2, //0x0002, SIP_METHOD_ACK = 3, //0x0004, SIP_METHOD_BYE = 4, //0x0008, SIP_METHOD_REGISTER = 5, //0x0010, SIP_METHOD_OPTIONS = 6, //0x0020, SIP_METHOD_REFER = 7, //0x0040, SIP_METHOD_SUBSCRIBE = 8, //0x0080, SIP_METHOD_UPDATE = 9, //0x0100, SIP_METHOD_JOIN = 10,//0x0200, SIP_METHOD_INFO = 11,//0x0400, SIP_METHOD_MESSAGE = 12,//0x0800, SIP_METHOD_NOTIFY = 13,//0x1000, SIP_METHOD_PRACK = 14,//0x2000, SIP_METHOD_USER_DEFINE = 15,//0x4000, SIP_METHOD_USER_DEFINE_MAX = 32//0x80000000, } SIPMethodsFlag; #define SIP_METHOD_DEFAULT 0x003f #define SIP_METHOD_ALL 0xffffffff /* * Header fields and processing functions */ typedef struct _SIPMethod { char *name; SIPMethodsFlag methodFlag; }SIPMethod; extern SIPMethod StandardMethods[]; typedef struct _sipMethodlistNode { char *methodName; int methodLen; SIPMethodsFlag methodFlag; struct _sipMethodlistNode* nextm; } SIPMethodNode; typedef SIPMethodNode * SIPMethodlist; /* * One of these structures is kept for each configured * server port. */ typedef struct _sipPortlistNode { uint16_t server_port; struct _sipPortlistNode* nextp; } SIPPortNode; /* * SIP preprocessor configuration. * * disabled: Whether or not to disable SIP PP. * maxNumSessions: Maximum amount of run-time memory * ports: Which ports to check for SIP messages * methods: Which methods to check * maxUriLen: Maximum requst_URI size * maxCallIdLen: Maximum call_ID size. * maxRequestNameLen: Maximum length of request name in the CSeqID. * maxFromLen: Maximum From field size * maxToLen: Maximum To field size * maxViaLen: Maximum Via field size * maxContactLen: Maximum Contact field size * maxContentLen: Maximum Content length * ignoreChannel: Whether to ignore media channels found by SIP PP */ typedef struct _sipConfig { uint8_t disabled; uint32_t maxNumSessions; uint32_t maxNumDialogsInSession; uint8_t ports[MAXPORTS/8]; uint32_t methodsConfig; SIPMethodlist methods; uint16_t maxUriLen; uint16_t maxCallIdLen; uint16_t maxRequestNameLen; uint16_t maxFromLen; uint16_t maxToLen; uint16_t maxViaLen; uint16_t maxContactLen; uint16_t maxContentLen; uint8_t ignoreChannel; int ref_count; } SIPConfig; /******************************************************************** * Public function prototypes ********************************************************************/ void SIP_FreeConfig(SIPConfig *); void ParseSIPArgs(SIPConfig *, u_char*); SIPMethodNode* SIP_AddUserDefinedMethod(char *, uint32_t *, SIPMethodlist*); #endif snort-2.9.6.0/src/dynamic-preprocessors/sip/sip_config.c0000644000000000000000000006463412260565732020150 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 2/17/2011 - Initial implementation ... Hui Cao * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "sf_types.h" #include "sf_snort_packet.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "sip_config.h" #include "spp_sip.h" #include "sip_debug.h" #define METHOD_NOT_FOUND -1 /* * Default SIP port */ #define SIP_PORT 5060 #define SIPS_PORT 5061 /* * Default values for configurable parameters. */ #define SIP_DEFAULT_MAX_SESSIONS 10000 #define SIP_DEFAULT_MAX_DIALOGS_IN_SESSION 4 #define SIP_DEFAULT_MAX_URI_LEN 256 #define SIP_DEFAULT_MAX_CALL_ID_LEN 256 #define SIP_DEFAULT_MAX_REQUEST_NAME_LEN 20 #define SIP_DEFAULT_MAX_FROM_LEN 256 #define SIP_DEFAULT_MAX_TO_LEN 256 #define SIP_DEFAULT_MAX_VIA_LEN 1024 #define SIP_DEFAULT_MAX_CONTACT_LEN 256 #define SIP_DEFAULT_MAX_CONTENT_LEN 1024 /* * Min/Max values for each configurable parameter. */ #define MIN_MAX_NUM_SESSION 1024 #define MAX_MAX_NUM_SESSION 4194303 #define MIN_MAX_NUM_DIALOG 1 #define MAX_MAX_NUM_DIALOG 4194303 #define MIN_MAX_URI_LEN 0 #define MAX_MAX_URI_LEN 65535 #define MIN_MAX_CALL_ID_LEN 0 #define MAX_MAX_CALL_ID_LEN 65535 #define MIN_MAX_REQUEST_NAME_LEN 0 #define MAX_MAX_REQUEST_NAME_LEN 65535 #define MIN_MAX_FROM_LEN 0 #define MAX_MAX_FROM_LEN 65535 #define MIN_MAX_TO_LEN 0 #define MAX_MAX_TO_LEN 65535 #define MIN_MAX_VIA_LEN 0 #define MAX_MAX_VIA_LEN 65535 #define MIN_MAX_CONTACT_LEN 0 #define MAX_MAX_CONTACT_LEN 65535 #define MIN_MAX_CONTENT_LEN 0 #define MAX_MAX_CONTENT_LEN 65535 /* * Keyword strings for parsing configuration options. */ #define SIP_DISABLED_KEYWORD "disabled" #define SIP_PORTS_KEYWORD "ports" #define SIP_MAX_SESSION_KEYWORD "max_sessions" #define SIP_MAX_DIALOG_KEYWORD "max_dialogs" #define SIP_METHODS_KEYWORD "methods" #define SIP_MAX_URI_LEN_KEYWORD "max_uri_len" #define SIP_MAX_CALL_ID_LEN_KEYWORD "max_call_id_len" #define SIP_MAX_REQUEST_NAME_LEN_KEYWORD "max_requestName_len" #define SIP_MAX_FROM_LEN_KEYWORD "max_from_len" #define SIP_MAX_TO_LEN_KEYWORD "max_to_len" #define SIP_MAX_VIA_LEN_KEYWORD "max_via_len" #define SIP_MAX_CONTACT_LEN_KEYWORD "max_contact_len" #define SIP_MAX_CONTENT_LEN_KEYWORD "max_content_len" #define SIP_IGNORE_CHANNEL_KEYWORD "ignore_call_channel" #define SIP_SEPERATORS "()<>@,;:\\/[]?={}\" " #define SIP_CONFIG_SECTION_SEPERATORS ",;" #define SIP_CONFIG_VALUE_SEPERATORS " " /* * method names defined by standard, 14 methods defined up to Mar. 2011 * The first 6 methods are standard defined by RFC3261 */ SIPMethod StandardMethods[] = { {"invite", SIP_METHOD_INVITE}, {"cancel",SIP_METHOD_CANCEL}, {"ack", SIP_METHOD_ACK}, {"bye", SIP_METHOD_BYE}, {"register", SIP_METHOD_REGISTER}, {"options",SIP_METHOD_OPTIONS}, {"refer", SIP_METHOD_REFER}, {"subscribe", SIP_METHOD_SUBSCRIBE}, {"update", SIP_METHOD_UPDATE}, {"join", SIP_METHOD_JOIN}, {"info", SIP_METHOD_INFO}, {"message", SIP_METHOD_MESSAGE}, {"notify", SIP_METHOD_NOTIFY}, {"prack", SIP_METHOD_PRACK}, {NULL, SIP_METHOD_NULL} }; static SIPMethodsFlag currentUseDefineMethod = SIP_METHOD_USER_DEFINE; /* * Function prototype(s) */ static void DisplaySIPConfig(SIPConfig *); static void SIP_SetDefaultMethods(SIPConfig *); static void SIP_ParsePortList(char **, uint8_t *); static void SIP_ParseMethods(char **, uint32_t *,SIPMethodlist*); static SIPMethodNode* SIP_AddMethodToList(char *, SIPMethodsFlag, SIPMethodlist*); static int SIP_findMethod(char *, SIPMethod *); static int ParseNumInRange(char *token, char *keyword, int min, int max); /* * Find method from the array methods * * PARAMETERS: * char *token: the method token name to be checked * SIPMethod* methods: methods array. * * RETURNS: * the index of the method in the array, -1 if not found */ static int SIP_findMethod(char *token, SIPMethod* methods) { int i = 0; while(NULL != methods[i].name) { if ((strlen(token) == strlen(methods[i].name))&& (strncasecmp(methods[i].name, token, strlen(token)) == 0)) return i; i++; } return METHOD_NOT_FOUND; } /* Display the configuration for the SIP preprocessor. * * PARAMETERS: * * SIPConfig *config: SIP preprocessor configuration. * * RETURNS: Nothing. */ static void DisplaySIPConfig(SIPConfig *config) { int index; int newline; SIPMethodNode *method; if (config == NULL) return; _dpd.logMsg("SIP config: \n"); _dpd.logMsg(" Max number of sessions: %d %s \n", config->maxNumSessions, config->maxNumSessions == SIP_DEFAULT_MAX_SESSIONS ? "(Default)" : "" ); _dpd.logMsg(" Max number of dialogs in a session: %d %s \n", config->maxNumDialogsInSession, config->maxNumDialogsInSession == SIP_DEFAULT_MAX_DIALOGS_IN_SESSION ? "(Default)" : "" ); _dpd.logMsg(" Status: %s\n", config->disabled ? "DISABLED":"ENABLED"); if (config->disabled) return; _dpd.logMsg(" Ignore media channel: %s\n", config->ignoreChannel ? "ENABLED":"DISABLED"); _dpd.logMsg(" Max URI length: %d %s \n", config->maxUriLen, config->maxUriLen == SIP_DEFAULT_MAX_URI_LEN ? "(Default)" : "" ); _dpd.logMsg(" Max Call ID length: %d %s \n", config->maxCallIdLen, config->maxCallIdLen == SIP_DEFAULT_MAX_CALL_ID_LEN ? "(Default)" : "" ); _dpd.logMsg(" Max Request name length: %d %s \n", config->maxRequestNameLen, config->maxRequestNameLen == SIP_DEFAULT_MAX_REQUEST_NAME_LEN ? "(Default)" : "" ); _dpd.logMsg(" Max From length: %d %s \n", config->maxFromLen, config->maxFromLen == SIP_DEFAULT_MAX_FROM_LEN ? "(Default)" : "" ); _dpd.logMsg(" Max To length: %d %s \n", config->maxToLen, config->maxToLen == SIP_DEFAULT_MAX_TO_LEN ? "(Default)" : "" ); _dpd.logMsg(" Max Via length: %d %s \n", config->maxViaLen, config->maxViaLen == SIP_DEFAULT_MAX_VIA_LEN ? "(Default)" : "" ); _dpd.logMsg(" Max Contact length: %d %s \n", config->maxContactLen, config->maxContactLen == SIP_DEFAULT_MAX_CONTACT_LEN ? "(Default)" : "" ); _dpd.logMsg(" Max Content length: %d %s \n", config->maxContentLen, config->maxContentLen == SIP_DEFAULT_MAX_CONTENT_LEN ? "(Default)" : "" ); /* Traverse list, printing ports, 5 per line */ newline = 1; _dpd.logMsg(" Ports:\n"); for(index = 0; index < MAXPORTS; index++) { if( config->ports[ PORT_INDEX(index) ] & CONV_PORT(index) ) { _dpd.logMsg("\t%d", index); if ( !((newline++)% 5) ) { _dpd.logMsg("\n"); } } } _dpd.logMsg("\n"); _dpd.logMsg(" Methods:\n"); _dpd.logMsg("\t%s ", config->methodsConfig == SIP_METHOD_DEFAULT ? "(Default)" : ""); method = config->methods; while(NULL != method) { _dpd.logMsg(" %s", method->methodName); method = method->nextm; } _dpd.logMsg("\n"); } /* * The first 6 methods are standard defined by RFC3261 * We use those first 6 methods as default * */ static void SIP_SetDefaultMethods(SIPConfig *config) { int i; config->methodsConfig = SIP_METHOD_DEFAULT; for (i = 0; i < 6 ; i++) { if (SIP_AddMethodToList(StandardMethods[i].name, StandardMethods[i].methodFlag, &config->methods) == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to add SIP " "default method: %s.\n", *(_dpd.config_file), *(_dpd.config_line), StandardMethods[i].name); } } } /******************************************************************** * Function: SIP_ParsePortList() * * Parses a port list and adds bits associated with the ports * parsed to a bit array. * * Arguments: * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the IP list. * uint8_t * * Pointer to the port array mask to set bits for the ports * parsed. * * Returns: * SIP_Ret * SIP_SUCCESS if we were able to successfully parse the * port list. * SIP_FAILURE if an error occured in parsing the port list. * ********************************************************************/ static void SIP_ParsePortList(char **ptr, uint8_t *port_array) { int port; char* cur_tokenp = *ptr; /* If the user specified ports, remove SIP_PORT for now since * it now needs to be set explicitly. */ port_array[ PORT_INDEX( SIP_PORT ) ] = 0; port_array[ PORT_INDEX( SIPS_PORT ) ] = 0; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Port configurations: %s\n",*ptr );); /* Eat the open brace. */ cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Port token: %s\n",cur_tokenp );); /* Check the space after '{'*/ if (( !cur_tokenp ) || ( 0 != strncmp (cur_tokenp, "{", 2 ))) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s, make sure space before and after '{'.\n", *(_dpd.config_file), *(_dpd.config_line), SIP_PORTS_KEYWORD); } cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); while (( cur_tokenp ) && ( 0 != strncmp (cur_tokenp, "}", 2 ))) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Port token: %s\n",cur_tokenp );); port = ParseNumInRange(cur_tokenp, SIP_PORTS_KEYWORD, 1, MAXPORTS-1); port_array[ PORT_INDEX( port ) ] |= CONV_PORT(port); cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); } if ( NULL == cur_tokenp ) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s, missing '}'.\n", *(_dpd.config_file), *(_dpd.config_line), SIP_PORTS_KEYWORD); } *ptr = cur_tokenp; } /* Parses a single numerical value. * A fatal error is made if the parsed value is out of bounds. * * PARAMETERS: * * token: String containing argument * keyword: String containing option's name. Used when printing an error. * min: Minimum value of argument * max: Maximum value of argument * * RETURNS: bounds-checked integer value of argument. */ static int ParseNumInRange(char *token, char *keyword, int min, int max) { long int value; char *str; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Num token: %s\n",token );); if (( !token ) || !isdigit((int)token[0]) ) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d.\n", *(_dpd.config_file), *(_dpd.config_line), keyword, min, max); } value = _dpd.SnortStrtol( token, &str, 10); if (0 != strlen(str)) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s. " "Please specify an integer between %d and %d.\n", *(_dpd.config_file), *(_dpd.config_line), keyword, min, max); } if (value < min || value > max) { DynamicPreprocessorFatalMessage(" %s(%d) => Value specified for %s is out of " "bounds. Please specify an integer between %d and %d.\n", *(_dpd.config_file), *(_dpd.config_line), keyword, min, max); } return value; } /******************************************************************** * Function: SIP_ParseMethods() * * Parses the methods to detect * * * Arguments: * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the methods list. * SIPMethods* * Flag for the methods. * NULL flag if not a valid method type * Returns: * ********************************************************************/ static void SIP_ParseMethods(char **ptr, uint32_t *methodsConfig, SIPMethodlist* pmethods) { char* cur_tokenp = *ptr; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Method configurations: %s\n",*ptr );); /* If the user specified methods, remove default methods for now since * it now needs to be set explicitly. */ *methodsConfig = SIP_METHOD_NULL; /* Eat the open brace. */ cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Method token: %s\n",cur_tokenp );); /* Check the space after '{'*/ if (( !cur_tokenp ) || ( 0 != strncmp (cur_tokenp, "{", 2 ))) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s, make sure space before and after '{'.\n", *(_dpd.config_file), *(_dpd.config_line), SIP_METHODS_KEYWORD); } cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); while (( cur_tokenp ) && (0 != strncmp (cur_tokenp, "}", 2 ))) { int i_method; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Method token: %s\n",cur_tokenp );); // Check whether this is a standard method i_method = SIP_findMethod(cur_tokenp, StandardMethods); if (METHOD_NOT_FOUND != i_method ) { *methodsConfig |= 1 << (StandardMethods[i_method].methodFlag - 1); if (SIP_AddMethodToList(cur_tokenp, StandardMethods[i_method].methodFlag, pmethods) == NULL) { DynamicPreprocessorFatalMessage( "%s(%d) => Failed to add SIP method: %s.\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp); } } else { if (SIP_AddUserDefinedMethod(cur_tokenp, methodsConfig, pmethods) == NULL) { DynamicPreprocessorFatalMessage( "%s(%d) => Failed to add user defined SIP method: %s.\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp); } } cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); } if ( NULL == cur_tokenp ) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad value specified for %s, missing '}'.\n", *(_dpd.config_file), *(_dpd.config_line), SIP_METHODS_KEYWORD); } *ptr = cur_tokenp; } static SIPMethodNode* SIP_AddMethodToList(char *methodName, SIPMethodsFlag methodConf, SIPMethodlist* p_methodList) { SIPMethodNode* method; int methodLen; SIPMethodNode* lastMethod; if (NULL == methodName) return NULL; methodLen = strlen(methodName); method =*p_methodList; lastMethod = *p_methodList; while(method) { // Already in the list, return if(strcasecmp(method->methodName, methodName) == 0) return method; lastMethod = method; method = method->nextm; } method = (SIPMethodNode *) malloc(sizeof (SIPMethodNode)); if (NULL == method) return NULL; method->methodName = strdup(methodName); if (NULL == method->methodName) { free(method); return NULL; } method->methodLen = methodLen; method->methodFlag = methodConf; method->nextm = NULL; // The first method, point to the first created one if (NULL == *p_methodList) { *p_methodList = method; } else { lastMethod->nextm = method; } return method; } /******************************************************************** * Function: SIP_FreeConfig * * Frees a sip configuration * * Arguments: * SIP_Config * * The configuration to free. * * Returns: None * ********************************************************************/ void SIP_FreeConfig (SIPConfig *config) { SIPMethodNode *nextNode; SIPMethodNode *curNode; if (config == NULL) return; curNode = config->methods; while (NULL != curNode) { if (NULL != curNode->methodName) free(curNode->methodName); nextNode = curNode->nextm; free(curNode); curNode = nextNode; } free(config); } /* Parses and processes the configuration arguments * supplied in the SIP preprocessor rule. * * PARAMETERS: * * SIPConfig *config: SIP preprocessor configuration. * argp: Pointer to string containing the config arguments. * * RETURNS: Nothing. */ void ParseSIPArgs(SIPConfig *config, u_char* argp) { char* cur_sectionp = NULL; char* next_sectionp = NULL; char* argcpyp = NULL; if (config == NULL) return; config->maxNumSessions = SIP_DEFAULT_MAX_SESSIONS; config->maxNumDialogsInSession = SIP_DEFAULT_MAX_DIALOGS_IN_SESSION; config->maxUriLen = SIP_DEFAULT_MAX_URI_LEN; config->maxCallIdLen = SIP_DEFAULT_MAX_CALL_ID_LEN; config->maxRequestNameLen = SIP_DEFAULT_MAX_REQUEST_NAME_LEN; config->maxFromLen = SIP_DEFAULT_MAX_FROM_LEN; config->maxToLen = SIP_DEFAULT_MAX_TO_LEN; config->maxViaLen = SIP_DEFAULT_MAX_VIA_LEN; config->maxContactLen = SIP_DEFAULT_MAX_CONTACT_LEN; config->maxContentLen = SIP_DEFAULT_MAX_CONTENT_LEN; /* Set up default port to listen on */ config->ports[ PORT_INDEX( SIP_PORT ) ] |= CONV_PORT(SIP_PORT); config->ports[ PORT_INDEX( SIPS_PORT ) ] |= CONV_PORT(SIPS_PORT); config->methodsConfig = SIP_METHOD_NULL; config->methods = NULL; /* Reset user defined method for every policy*/ currentUseDefineMethod = SIP_METHOD_USER_DEFINE; /* Sanity check(s) */ if ( !argp ) { SIP_SetDefaultMethods(config); DisplaySIPConfig(config); return; } argcpyp = strdup( (char*) argp ); if ( !argcpyp ) { DynamicPreprocessorFatalMessage("Could not allocate memory to parse SIP options.\n"); return; } DEBUG_WRAP(DebugMessage(DEBUG_SIP, "SIP configurations: %s\n",argcpyp );); cur_sectionp = strtok_r( argcpyp, SIP_CONFIG_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Arguments token: %s\n",cur_sectionp );); while ( cur_sectionp ) { char* cur_config; char* cur_tokenp = strtok( cur_sectionp, SIP_CONFIG_VALUE_SEPERATORS); if (!cur_tokenp) { cur_sectionp = strtok_r( next_sectionp, SIP_CONFIG_SECTION_SEPERATORS, &next_sectionp); continue; } cur_config = cur_tokenp; if ( !strcmp( cur_tokenp, SIP_PORTS_KEYWORD )) { SIP_ParsePortList(&cur_tokenp, config->ports); } else if ( !strcmp( cur_tokenp, SIP_METHODS_KEYWORD )) { SIP_ParseMethods(&cur_tokenp, &config->methodsConfig, &config->methods ); } else if ( !strcmp( cur_tokenp, SIP_DISABLED_KEYWORD )) { config->disabled = 1; } else if ( !strcmp( cur_tokenp, SIP_MAX_SESSION_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxNumSessions = (uint32_t)ParseNumInRange(cur_tokenp, SIP_MAX_SESSION_KEYWORD, MIN_MAX_NUM_SESSION, MAX_MAX_NUM_SESSION); } else if ( !strcmp( cur_tokenp, SIP_MAX_DIALOG_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxNumDialogsInSession = (uint32_t)ParseNumInRange(cur_tokenp, SIP_MAX_DIALOG_KEYWORD, MIN_MAX_NUM_DIALOG, MAX_MAX_NUM_DIALOG); } else if ( !strcmp( cur_tokenp, SIP_MAX_URI_LEN_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxUriLen = (uint16_t)ParseNumInRange(cur_tokenp, SIP_MAX_URI_LEN_KEYWORD, MIN_MAX_URI_LEN, MAX_MAX_URI_LEN); } else if ( !strcmp( cur_tokenp, SIP_MAX_CALL_ID_LEN_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxCallIdLen = (uint16_t)ParseNumInRange(cur_tokenp, SIP_MAX_CALL_ID_LEN_KEYWORD, MIN_MAX_CALL_ID_LEN, MAX_MAX_CALL_ID_LEN); } else if ( !strcmp( cur_tokenp, SIP_MAX_REQUEST_NAME_LEN_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxRequestNameLen = (uint16_t)ParseNumInRange(cur_tokenp, SIP_MAX_REQUEST_NAME_LEN_KEYWORD, MIN_MAX_REQUEST_NAME_LEN, MAX_MAX_REQUEST_NAME_LEN); } else if ( !strcmp( cur_tokenp, SIP_MAX_FROM_LEN_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxFromLen = (uint16_t)ParseNumInRange(cur_tokenp, SIP_MAX_FROM_LEN_KEYWORD, MIN_MAX_FROM_LEN, MAX_MAX_FROM_LEN); } else if ( !strcmp( cur_tokenp, SIP_MAX_TO_LEN_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxToLen = (uint16_t)ParseNumInRange(cur_tokenp, SIP_MAX_TO_LEN_KEYWORD, MIN_MAX_TO_LEN, MAX_MAX_TO_LEN); } else if ( !strcmp( cur_tokenp, SIP_MAX_VIA_LEN_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxViaLen = (uint16_t)ParseNumInRange(cur_tokenp, SIP_MAX_VIA_LEN_KEYWORD, MIN_MAX_VIA_LEN, MAX_MAX_VIA_LEN); } else if ( !strcmp( cur_tokenp, SIP_MAX_CONTACT_LEN_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxContactLen = (uint16_t)ParseNumInRange(cur_tokenp, SIP_MAX_CONTACT_LEN_KEYWORD, MIN_MAX_CONTACT_LEN, MAX_MAX_CONTACT_LEN); } else if ( !strcmp( cur_tokenp, SIP_MAX_CONTENT_LEN_KEYWORD )) { cur_tokenp = strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS); config->maxContentLen = (uint16_t)ParseNumInRange(cur_tokenp, SIP_MAX_CONTENT_LEN_KEYWORD, MIN_MAX_CONTENT_LEN, MAX_MAX_CONTENT_LEN); } else if ( !strcmp( cur_tokenp, SIP_IGNORE_CHANNEL_KEYWORD )) { config->ignoreChannel = 1; } else { DynamicPreprocessorFatalMessage(" %s(%d) => Invalid argument: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp); return; } /*Check whether too many parameters*/ if (NULL != strtok( NULL, SIP_CONFIG_VALUE_SEPERATORS)) { DynamicPreprocessorFatalMessage("%s(%d) => To many arguments: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_config); } cur_sectionp = strtok_r( next_sectionp, SIP_CONFIG_SECTION_SEPERATORS, &next_sectionp); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Arguments token: %s\n",cur_sectionp );); } /*If no methods defined, use the default*/ if (SIP_METHOD_NULL == config->methodsConfig) { SIP_SetDefaultMethods(config); } DisplaySIPConfig(config); free(argcpyp); } /******************************************************************** * Function: SIP_AddUserDefinedMethod * * Add a user defined method * * Arguments: * char *: the method name * SIPMethodlist *: the list to be added * * Returns: user defined method * ********************************************************************/ SIPMethodNode* SIP_AddUserDefinedMethod(char *methodName, uint32_t *methodsConfig, SIPMethodlist* pmethods) { int i = 0; SIPMethodNode* method; /*Check whether all the chars are defined by RFC2616*/ while(methodName[i]) { if (iscntrl(methodName[i])|(NULL != strchr(SIP_SEPERATORS,methodName[i]))| (methodName[i] < 0) ) { DynamicPreprocessorFatalMessage(" %s(%d) => Bad character included in the User defined method: %s." "Make sure space before and after '}'. \n", *(_dpd.config_file), *(_dpd.config_line), methodName ); return NULL; } i++; } if (currentUseDefineMethod > SIP_METHOD_USER_DEFINE_MAX) { DynamicPreprocessorFatalMessage(" %s(%d) => Exceeded max number of user defined methods (%d), can't add %s.\n", *(_dpd.config_file), *(_dpd.config_line), SIP_METHOD_USER_DEFINE_MAX - SIP_METHOD_USER_DEFINE + 1, methodName ); return NULL; } *methodsConfig |= 1 << (currentUseDefineMethod - 1); method = SIP_AddMethodToList(methodName, currentUseDefineMethod, pmethods); currentUseDefineMethod = (SIPMethodsFlag) (currentUseDefineMethod + 1); return method; } snort-2.9.6.0/src/dynamic-preprocessors/sip/spp_sip.h0000644000000000000000000002160612260565732017502 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2011-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * spp_sip.h: Definitions, structs, function prototype(s) for * the SIP preprocessor. * Author: Hui Cao */ #ifndef SPP_SIP_H #define SPP_SIP_H #include #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "snort_bounds.h" #include "sip_roptions.h" #include "sf_ip.h" /* Convert port value into an index for the sip_config->ports array */ #define PORT_INDEX(port) port/8 /* Convert port value into a value for bitwise operations */ #define CONV_PORT(port) 1<<(port%8) /* * Boolean values. */ #define SIP_TRUE (1) #define SIP_FALSE (0) #define SIP_STATUS_CODE_LEN (3) #define SIP_CONTENT_LEN (5) /* * Error codes. */ #define SIP_SUCCESS (1) #define SIP_FAILURE (0) typedef struct _SIP_MediaData { sfip_t maddress; // media IP uint16_t mport; // media port uint8_t numPort; // number of media ports struct _SIP_MediaData *nextM; } SIP_MediaData; typedef SIP_MediaData* SIP_MediaDataList; #define SIP_SESSION_SAVED (1) #define SIP_SESSION_INIT (0) typedef struct _SIP_MediaSession { uint32_t sessionID; // a hash value of the session int savedFlag; // whether this data has been saved by a dialog, // if savedFlag = 1, this session will be deleted after sip message is processed. sfip_t maddress_default; //Default media IP SIP_MediaDataList medias; //Media list in the session struct _SIP_MediaSession *nextS; // Next media session } SIP_MediaSession; typedef SIP_MediaSession* SIP_MediaList; typedef struct _SIP_DialogID { uint32_t callIdHash; uint32_t fromTagHash; uint32_t toTagHash; } SIP_DialogID; typedef enum _SIP_DialogState { SIP_DLG_CREATE = 1, //1 SIP_DLG_INVITING, //2 SIP_DLG_EARLY, //3 SIP_DLG_AUTHENCATING, //4 SIP_DLG_ESTABLISHED, //5 SIP_DLG_REINVITING, //6 SIP_DLG_TERMINATING, //7 SIP_DLG_TERMINATED //8 } SIP_DialogState; typedef struct _SIP_DialogData { SIP_DialogID dlgID; SIP_DialogState state; SIPMethodsFlag creator; uint16_t status_code; SIP_MediaList mediaSessions; struct _SIP_DialogData *nextD; struct _SIP_DialogData *prevD; } SIP_DialogData; typedef struct _SIP_DialogList { SIP_DialogData* head; uint32_t num_dialogs; }SIP_DialogList; /* * Per-session data block containing current state * of the SIP preprocessor for the session. * * state_flags: Bit vector describing the current state of the * session. */ typedef struct _sipData { uint32_t state_flags; SIP_DialogList dialogs; SIP_Roptions ropts; tSfPolicyId policy_id; tSfPolicyUserContextId config; } SIPData; typedef struct _SIPMsg { uint16_t headerLen; uint16_t methodLen; SIPMethodsFlag methodFlag; uint16_t status_code; uint16_t uriLen; uint16_t callIdLen; uint16_t cseqNameLen; uint16_t fromLen; uint16_t fromTagLen; uint16_t toLen; uint16_t toTagLen; uint16_t viaLen; uint16_t contactLen; uint16_t bodyLen; uint16_t contentTypeLen; uint32_t content_len; SIP_DialogID dlgID; SIP_MediaSession *mediaSession; char *authorization; const uint8_t *header; const uint8_t *body_data; /* Set to NULL if not applicable */ uint64_t cseqnum; /* nothing after this point is zeroed ...*/ /*Input parameters*/ unsigned char isTcp; char *method; char *uri; char *call_id; char *cseqName; char *from; char *from_tag; char *to; char *to_tag; char *via; char *contact; char *content_type; char *content_encode; } SIPMsg; #define SIPMSG_ZERO_LEN offsetof(SIPMsg, isTcp) /* * Generator id. Define here the same as the official registry * in generators.h */ #define GENERATOR_SPP_SIP 140 /* Ultimately calls SnortEventqAdd */ /* Arguments are: gid, sid, rev, classification, priority, message, rule_info */ #define ALERT(x,y) { _dpd.alertAdd(GENERATOR_SPP_SIP, x, 1, 0, 3, y, 0 ); sip_stats.events++; } /* * SIP preprocessor alert types. */ #define SIP_EVENT_MAX_SESSIONS 1 #define SIP_EVENT_EMPTY_REQUEST_URI 2 #define SIP_EVENT_BAD_URI 3 #define SIP_EVENT_EMPTY_CALL_ID 4 #define SIP_EVENT_BAD_CALL_ID 5 #define SIP_EVENT_BAD_CSEQ_NUM 6 #define SIP_EVENT_BAD_CSEQ_NAME 7 #define SIP_EVENT_EMPTY_FROM 8 #define SIP_EVENT_BAD_FROM 9 #define SIP_EVENT_EMPTY_TO 10 #define SIP_EVENT_BAD_TO 11 #define SIP_EVENT_EMPTY_VIA 12 #define SIP_EVENT_BAD_VIA 13 #define SIP_EVENT_EMPTY_CONTACT 14 #define SIP_EVENT_BAD_CONTACT 15 #define SIP_EVENT_BAD_CONTENT_LEN 16 #define SIP_EVENT_MULTI_MSGS 17 #define SIP_EVENT_MISMATCH_CONTENT_LEN 18 #define SIP_EVENT_INVALID_CSEQ_NAME 19 #define SIP_EVENT_AUTH_INVITE_REPLAY_ATTACK 20 #define SIP_EVENT_AUTH_INVITE_DIFF_SESSION 21 #define SIP_EVENT_BAD_STATUS_CODE 22 #define SIP_EVENT_EMPTY_CONTENT_TYPE 23 #define SIP_EVENT_INVALID_VERSION 24 #define SIP_EVENT_MISMATCH_METHOD 25 #define SIP_EVENT_UNKOWN_METHOD 26 #define SIP_EVENT_MAX_DIALOGS_IN_A_SESSION 27 /* * SIP preprocessor alert strings. */ #define SIP_EVENT_MAX_SESSIONS_STR "(spp_sip) Maximum sessions reached" #define SIP_EVENT_EMPTY_REQUEST_URI_STR "(spp_sip) Empty request URI" #define SIP_EVENT_BAD_URI_STR "(spp_sip) URI is too long" #define SIP_EVENT_EMPTY_CALL_ID_STR "(spp_sip) Empty call-Id" #define SIP_EVENT_BAD_CALL_ID_STR "(spp_sip) Call-Id is too long" #define SIP_EVENT_BAD_CSEQ_NUM_STR "(spp_sip) CSeq number is too large or negative" #define SIP_EVENT_BAD_CSEQ_NAME_STR "(spp_sip) Request name in CSeq is too long" #define SIP_EVENT_EMPTY_FROM_STR "(spp_sip) Empty From header" #define SIP_EVENT_BAD_FROM_STR "(spp_sip) From header is too long" #define SIP_EVENT_EMPTY_TO_STR "(spp_sip) Empty To header" #define SIP_EVENT_BAD_TO_STR "(spp_sip) To header is too long" #define SIP_EVENT_EMPTY_VIA_STR "(spp_sip) Empty Via header" #define SIP_EVENT_BAD_VIA_STR "(spp_sip) Via header is too long" #define SIP_EVENT_EMPTY_CONTACT_STR "(spp_sip) Empty Contact" #define SIP_EVENT_BAD_CONTACT_STR "(spp_sip) Contact is too long" #define SIP_EVENT_BAD_CONTENT_LEN_STR "(spp_sip) Content length is too large or negative" #define SIP_EVENT_MULTI_MSGS_STR "(spp_sip) Multiple SIP messages in a packet" #define SIP_EVENT_MISMATCH_CONTENT_LEN_STR "(spp_sip) Content length mismatch" #define SIP_EVENT_INVALID_CSEQ_NAME_STR "(spp_sip) Request name is invalid" #define SIP_EVENT_AUTH_INVITE_REPLAY_ATTACK_STR "(spp_sip) Invite replay attack" #define SIP_EVENT_AUTH_INVITE_DIFF_SESSION_STR "(spp_sip) Illegal session information modification" #define SIP_EVENT_BAD_STATUS_CODE_STR "(spp_sip) Response status code is not a 3 digit number" #define SIP_EVENT_EMPTY_CONTENT_TYPE_STR "(spp_sip) Empty Content-type header" #define SIP_EVENT_INVALID_VERSION_STR "(spp_sip) SIP version is invalid" #define SIP_EVENT_MISMATCH_METHOD_STR "(spp_sip) Mismatch in METHOD of request and the CSEQ header" #define SIP_EVENT_UNKOWN_METHOD_STR "(spp_sip) Method is unknown" #define SIP_EVENT_MAX_DIALOGS_IN_A_SESSION_STR "(spp_sip) Maximum dialogs within a session reached" #define MAX_STAT_CODE 999 #define MIN_STAT_CODE 100 #define TOTAL_RESPONSES 0 #define RESPONSE1XX 1 #define RESPONSE2XX 2 #define RESPONSE3XX 3 #define RESPONSE4XX 4 #define RESPONSE5XX 5 #define RESPONSE6XX 6 #define NUM_OF_RESPONSE_TYPES 10 #define TOTAL_REQUESTS 0 #define NUM_OF_REQUEST_TYPES SIP_METHOD_USER_DEFINE_MAX typedef struct _SIP_Stats { uint64_t sessions; uint64_t events; uint64_t dialogs; uint64_t requests[NUM_OF_REQUEST_TYPES]; uint64_t responses[NUM_OF_RESPONSE_TYPES]; uint64_t ignoreChannels; uint64_t ignoreSessions; } SIP_Stats; extern SIP_Stats sip_stats; extern SIPConfig *sip_eval_config; extern tSfPolicyUserContextId sip_config; /* Prototypes for public interface */ void SetupSIP(void); SIPConfig *getParsingSIPConfig(struct _SnortConfig *); #endif /* SPP_SIP_H */ snort-2.9.6.0/src/dynamic-preprocessors/sip/spp_sip.c0000644000000000000000000006120312260565732017472 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2011-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * SIP preprocessor * * This is the main entry point for this preprocessor * * Author: Hui Cao * Date: 03-15-2011 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_plugin_api.h" #include "snort_debug.h" #include "preprocids.h" #include "spp_sip.h" #include "sip_config.h" #include "sip_roptions.h" #include "sip_parser.h" #include "sip_dialog.h" #include #include #include #include #ifndef WIN32 #include #include #endif #include #include #include "profiler.h" #ifdef PERF_PROFILING PreprocStats sipPerfStats; #endif #include "sf_types.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_SIP"; #define SetupSIP DYNAMIC_PREPROC_SETUP #ifdef TARGET_BASED int16_t sip_app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif /* * Session state flags for SIPData::state_flags */ #define SIP_FLG_MISSED_PACKETS (0x10000) #define SIP_FLG_REASSEMBLY_SET (0x20000) /* * Function prototype(s) */ SIPData * SIPGetNewSession(SFSnortPacket *, tSfPolicyId); static void SIPInit( struct _SnortConfig *, char* ); static int SIPCheckConfig(struct _SnortConfig *); static void FreeSIPData( void* ); static inline int SIP_Process(SFSnortPacket *, SIPData*); static void SIPmain( void*, void* ); static inline int CheckSIPPort( uint16_t ); static void SIPFreeConfig(tSfPolicyUserContextId); static void _addPortsToStream5Filter(struct _SnortConfig *, SIPConfig *, tSfPolicyId); static void SIP_PrintStats(int); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static void SIPCleanExit(int, void *); /******************************************************************** * Global variables ********************************************************************/ uint32_t numSessions = 0; SIP_Stats sip_stats; SIPConfig *sip_eval_config; tSfPolicyUserContextId sip_config; #ifdef SNORT_RELOAD static void SIPReload(struct _SnortConfig *, char *, void **); static int SIPReloadVerify(struct _SnortConfig *, void *); static void * SIPReloadSwap(struct _SnortConfig *, void *); static void SIPReloadSwapFree(void *); #endif /* Called at preprocessor setup time. Links preprocessor keyword * to corresponding preprocessor initialization function. * * PARAMETERS: None. * * RETURNS: Nothing. * */ void SetupSIP(void) { /* Link preprocessor keyword to initialization function * in the preprocessor list. */ #ifndef SNORT_RELOAD _dpd.registerPreproc( "sip", SIPInit ); #else _dpd.registerPreproc("sip", SIPInit, SIPReload, SIPReloadVerify, SIPReloadSwap, SIPReloadSwapFree); #endif } SIPConfig *getParsingSIPConfig(struct _SnortConfig *sc) { SIPConfig * sip_parsing_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId sip_swap_config = (tSfPolicyUserContextId)_dpd.getRelatedReloadData(sc, "sip"); if (sip_swap_config) sip_parsing_config = sfPolicyUserDataGetCurrent(sip_swap_config); else #endif sip_parsing_config = sfPolicyUserDataGetCurrent(sip_config); return sip_parsing_config; } /* Initializes the SIP preprocessor module and registers * it in the preprocessor list. * * PARAMETERS: * * argp: Pointer to argument string to process for config * data. * * RETURNS: Nothing. */ static void SIPInit(struct _SnortConfig *sc, char *argp) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); SIPConfig *pDefaultPolicyConfig = NULL; SIPConfig *pPolicyConfig = NULL; if (sip_config == NULL) { //create a context sip_config = sfPolicyConfigCreate(); if (sip_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for SIP config.\n"); } _dpd.addPreprocConfCheck(sc, SIPCheckConfig); _dpd.registerPreprocStats(SIP_NAME, SIP_PrintStats); _dpd.addPreprocExit(SIPCleanExit, NULL, PRIORITY_LAST, PP_SIP); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("sip", (void *)&sipPerfStats, 0, _dpd.totalPerfStats); #endif #ifdef TARGET_BASED sip_app_id = _dpd.findProtocolReference("sip"); if (sip_app_id == SFTARGET_UNKNOWN_PROTOCOL) sip_app_id = _dpd.addProtocolReference("sip"); #endif } sfPolicyUserPolicySet (sip_config, policy_id); pDefaultPolicyConfig = (SIPConfig *)sfPolicyUserDataGetDefault(sip_config); pPolicyConfig = (SIPConfig *)sfPolicyUserDataGetCurrent(sip_config); if ((pPolicyConfig != NULL) && (pDefaultPolicyConfig == NULL)) { DynamicPreprocessorFatalMessage("SIP preprocessor can only be " "configured once.\n"); } pPolicyConfig = (SIPConfig *)calloc(1, sizeof(SIPConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "SIP preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(sip_config, pPolicyConfig); SIP_RegRuleOptions(sc); ParseSIPArgs(pPolicyConfig, (u_char *)argp); if (policy_id != 0) pPolicyConfig->maxNumSessions = pDefaultPolicyConfig->maxNumSessions; if ( pPolicyConfig->disabled ) return; if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupSIP(): The Stream preprocessor must be enabled.\n"); } _dpd.addPreproc( sc, SIPmain, PRIORITY_APPLICATION, PP_SIP, PROTO_BIT__UDP|PROTO_BIT__TCP ); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } /********************************************************************* * Overload PCRE options: this is to support the "H" * * For SIP messages, uri Buffers will point to SIP instead of HTTP * * Arguments: * SFSnortPacket * - pointer to packet structure * * Returns: * None * *********************************************************************/ static inline void SIP_overloadURI(SFSnortPacket *p, SIPMsg *sipMsg) { if ( sipMsg->header ) _dpd.setHttpBuffer(HTTP_BUFFER_HEADER, sipMsg->header, sipMsg->headerLen); if ( sipMsg->body_data ) _dpd.setHttpBuffer(HTTP_BUFFER_CLIENT_BODY, sipMsg->body_data, sipMsg->bodyLen); } /********************************************************************* * Main entry point for SIP processing. * * Arguments: * SFSnortPacket * - pointer to packet structure * * Returns: * int - SIP_SUCCESS * SIP_FAILURE * *********************************************************************/ static inline int SIP_Process(SFSnortPacket *p, SIPData* sessp) { int status; char* sip_buff = (char*) p->payload; char* end; SIP_Roptions *pRopts; SIPMsg sipMsg; memset(&sipMsg, 0, SIPMSG_ZERO_LEN); /*Input parameters*/ sipMsg.isTcp = IsTCP(p); end = sip_buff + p->payload_size; status = sip_parse(&sipMsg, sip_buff, end); if (SIP_SUCCESS == status) { SIP_overloadURI(p, &sipMsg); /*Update the dialog state*/ SIP_updateDialog(&sipMsg, &(sessp->dialogs), p); } /*Update the session data*/ pRopts = &(sessp->ropts); pRopts->methodFlag = sipMsg.methodFlag; pRopts->header_data = sipMsg.header; pRopts->header_len = sipMsg.headerLen; pRopts->body_len = sipMsg.bodyLen; pRopts->body_data = sipMsg.body_data; pRopts->status_code = sipMsg.status_code; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "SIP message header length: %d\n", sipMsg.headerLen)); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Parsed method: %.*s, Flag: 0x%x\n", sipMsg.methodLen, sipMsg.method, sipMsg.methodFlag)); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Parsed status code: %d\n", sipMsg.status_code)); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Parsed header address: %p.\n", sipMsg.header)); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Parsed body address: %p.\n", sipMsg.body_data)); sip_freeMsg(&sipMsg); return status; } /* Main runtime entry point for SIP preprocessor. * Analyzes SIP packets for anomalies/exploits. * * PARAMETERS: * * packetp: Pointer to current packet to process. * contextp: Pointer to context block, not used. * * RETURNS: Nothing. */ static void SIPmain( void* ipacketp, void* contextp ) { SIPData* sessp = NULL; uint8_t source = 0; uint8_t dest = 0; SFSnortPacket* packetp; #ifdef TARGET_BASED int16_t app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "%s\n", SIP_DEBUG__START_MSG)); packetp = (SFSnortPacket*) ipacketp; sfPolicyUserPolicySet (sip_config, policy_id); // preconditions - what we registered for assert((IsUDP(packetp) || IsTCP(packetp)) && packetp->payload && packetp->payload_size); if ( packetp->flags & FLAG_STREAM_INSERT ) return; PREPROC_PROFILE_START(sipPerfStats); sip_eval_config = sfPolicyUserDataGetCurrent(sip_config); /* Attempt to get a previously allocated SIP block. */ sessp = _dpd.streamAPI->get_application_data(packetp->stream_session_ptr, PP_SIP); if (sessp != NULL) { sip_eval_config = sfPolicyUserDataGet(sessp->config, sessp->policy_id); } if (sessp == NULL) { /* If not doing autodetection, check the ports to make sure this is * running on an SIP port, otherwise no need to examine the traffic. */ #ifdef TARGET_BASED app_id = _dpd.streamAPI->get_application_protocol_id(packetp->stream_session_ptr); if (app_id == SFTARGET_UNKNOWN_PROTOCOL) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Unknown protocol - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "%s\n", SIP_DEBUG__END_MSG)); PREPROC_PROFILE_END(sipPerfStats); return; } else if (app_id && (app_id != sip_app_id)) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Not SIP - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "%s\n", SIP_DEBUG__END_MSG)); PREPROC_PROFILE_END(sipPerfStats); return; } else if (!app_id) { #endif source = (uint8_t)CheckSIPPort( packetp->src_port ); dest = (uint8_t)CheckSIPPort( packetp->dst_port ); if ( !source && !dest ) { /* Not one of the ports we care about. */ DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Not SIP ports - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "%s\n", SIP_DEBUG__END_MSG)); PREPROC_PROFILE_END(sipPerfStats); return; } #ifdef TARGET_BASED } #endif /* Check the stream session. If it does not currently * have our SIP data-block attached, create one. */ sessp = SIPGetNewSession(packetp, policy_id); if ( !sessp ) { /* Could not get/create the session data for this packet. */ DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Create session error - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "%s\n", SIP_DEBUG__END_MSG)); PREPROC_PROFILE_END(sipPerfStats); return; } } /* Don't process if we've missed packets */ if (sessp->state_flags & SIP_FLG_MISSED_PACKETS) { DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Missed packets - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "%s\n", SIP_DEBUG__END_MSG)); PREPROC_PROFILE_END(sipPerfStats); return; } /* If we picked up mid-stream or missed any packets (midstream pick up * means we've already missed packets) set missed packets flag and make * sure we don't do any more reassembly on this session */ if (IsTCP(packetp)) { if ((_dpd.streamAPI->get_session_flags(packetp->stream_session_ptr) & SSNFLAG_MIDSTREAM) || _dpd.streamAPI->missed_packets(packetp->stream_session_ptr, SSN_DIR_BOTH)) { _dpd.streamAPI->set_reassembly(packetp->stream_session_ptr, STREAM_FLPOLICY_IGNORE, SSN_DIR_BOTH, STREAM_FLPOLICY_SET_ABSOLUTE); sessp->state_flags |= SIP_FLG_MISSED_PACKETS; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Missed packets - not inspecting.\n")); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "%s\n", SIP_DEBUG__END_MSG)); PREPROC_PROFILE_END(sipPerfStats); return; } } /* We're interested in this session. Turn on stream reassembly. */ if ( !(sessp->state_flags & SIP_FLG_REASSEMBLY_SET )) { _dpd.streamAPI->set_reassembly(packetp->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_BOTH, STREAM_FLPOLICY_SET_ABSOLUTE); sessp->state_flags |= SIP_FLG_REASSEMBLY_SET; } /* * Start process PAYLOAD */ SIP_Process(packetp,sessp); DEBUG_WRAP(DebugMessage(DEBUG_SIP, "%s\n", SIP_DEBUG__END_MSG)); PREPROC_PROFILE_END(sipPerfStats); } /********************************************************************** * Retrieves the SIP data block registered with the stream * session associated w/ the current packet. If none exists, * allocates it and registers it with the stream API. * * Arguments: * * packetp: Pointer to the packet from which/in which to * retrieve/store the SIP data block. * * RETURNS: Pointer to an SIP data block, upon success. * NULL, upon failure. **********************************************************************/ SIPData * SIPGetNewSession(SFSnortPacket *packetp, tSfPolicyId policy_id) { SIPData* datap = NULL; static int MaxSessionsAlerted = 0; /* Sanity check(s) */ assert( packetp ); if ( !packetp->stream_session_ptr ) { return NULL; } if(numSessions > ((SIPConfig *)sfPolicyUserDataGetCurrent(sip_config))->maxNumSessions) { if (!MaxSessionsAlerted) ALERT(SIP_EVENT_MAX_SESSIONS,SIP_EVENT_MAX_SESSIONS_STR); MaxSessionsAlerted = 1; return NULL; } else { MaxSessionsAlerted = 0; } datap = (SIPData *)calloc(1, sizeof(SIPData)); if ( !datap ) return NULL; /*Register the new SIP data block in the stream session. */ _dpd.streamAPI->set_application_data( packetp->stream_session_ptr, PP_SIP, datap, FreeSIPData ); datap->policy_id = policy_id; datap->config = sip_config; ((SIPConfig *)sfPolicyUserDataGetCurrent(sip_config))->ref_count++; numSessions++; sip_stats.sessions++; DEBUG_WRAP(DebugMessage(DEBUG_SIP, "Number of sessions created: %u\n", numSessions)); return datap; } /*********************************************************************** * Registered as a callback with our SIP data blocks when * they are added to the underlying stream session. Called * by the stream preprocessor when a session is about to be * destroyed. * * PARAMETERS: * * idatap: Pointer to the moribund data. * * RETURNS: Nothing. ***********************************************************************/ static void FreeSIPData( void* idatap ) { SIPData *ssn = (SIPData *)idatap; SIPConfig *config = NULL; if (ssn == NULL) return; if (numSessions > 0) numSessions--; /*Free all the dialog data*/ sip_freeDialogs(&ssn->dialogs); /*Clean the configuration data*/ if (ssn->config != NULL) { config = (SIPConfig *)sfPolicyUserDataGet(ssn->config, ssn->policy_id); } if (config == NULL) { free(ssn); return; } config->ref_count--; if ((config->ref_count == 0) && (ssn->config != sip_config)) { sfPolicyUserDataClear (ssn->config, ssn->policy_id); free(config); if (sfPolicyUserPolicyGetActive(ssn->config) == 0) { /* No more outstanding configs - free the config array */ SIPFreeConfig(ssn->config); } } free(ssn); } /* ********************************************************************** * Validates given port as an SIP server port. * * PARAMETERS: * * port: Port to validate. * * RETURNS: SIP_TRUE, if the port is indeed an SIP server port. * SIP_FALSE, otherwise. ***********************************************************************/ static inline int CheckSIPPort( uint16_t port ) { if ( sip_eval_config->ports[ PORT_INDEX(port) ] & CONV_PORT( port ) ) { return SIP_TRUE; } return SIP_FALSE; } static void _addPortsToStream5Filter(struct _SnortConfig *sc, SIPConfig *config, tSfPolicyId policy_id) { int portNum; assert(config); assert(_dpd.streamAPI); for (portNum = 0; portNum < MAXPORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_UDP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status(sc, sip_app_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif static int SIPCheckPolicyConfig(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData) { SIPConfig *pPolicyConfig = (SIPConfig *)pData; _dpd.setParserPolicy(sc, policyId); if (pPolicyConfig->disabled) return 0; if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SIPCheckPolicyConfig(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } int SIPCheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate (sc, sip_config, SIPCheckPolicyConfig))) return rval; return 0; } static void SIPCleanExit(int signal, void *data) { if (sip_config != NULL) { SIPFreeConfig(sip_config); sip_config = NULL; } } static int SIPFreeConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SIPConfig *pPolicyConfig = (SIPConfig *)pData; //do any housekeeping before freeing SIPConfig sfPolicyUserDataClear (config, policyId); SIP_FreeConfig(pPolicyConfig); return 0; } void SIPFreeConfig(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, SIPFreeConfigPolicy); sfPolicyConfigDelete(config); } /****************************************************************** * Print statistics being kept by the preprocessor. * * Arguments: * int - whether Snort is exiting or not * * Returns: None * ******************************************************************/ static void SIP_PrintStats(int exiting) { int i; _dpd.logMsg("SIP Preprocessor Statistics\n"); _dpd.logMsg(" Total sessions: "STDu64"\n", sip_stats.sessions); if (sip_stats.sessions > 0) { if (sip_stats.events > 0) _dpd.logMsg(" SIP anomalies : "STDu64"\n", sip_stats.events); if (sip_stats.dialogs > 0) _dpd.logMsg(" Total dialogs: "STDu64"\n", sip_stats.dialogs); _dpd.logMsg(" Requests: "STDu64"\n", sip_stats.requests[0]); i = 0; while (NULL != StandardMethods[i].name) { _dpd.logMsg("%16s: "STDu64"\n", StandardMethods[i].name, sip_stats.requests[StandardMethods[i].methodFlag]); i++; } _dpd.logMsg(" Responses: "STDu64"\n", sip_stats.responses[TOTAL_RESPONSES]); for (i = 1; i disabled ) return; if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupSIP(): The Stream preprocessor must be enabled.\n"); } _dpd.addPreproc( sc, SIPmain, PRIORITY_APPLICATION, PP_SIP, PROTO_BIT__UDP|PROTO_BIT__TCP ); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } static int SIPReloadVerify(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId sip_swap_config = (tSfPolicyUserContextId)swap_config; SIPConfig * pPolicyConfig = NULL; SIPConfig * pCurrentConfig = NULL; if (sip_swap_config == NULL) return 0; pPolicyConfig = (SIPConfig *)sfPolicyUserDataGet(sip_swap_config, _dpd.getDefaultPolicy()); if (!pPolicyConfig) return 0; if ( pPolicyConfig->disabled ) return 0; if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SetupSIP(): The Stream preprocessor must be enabled.\n"); return -1; } if (sip_config != NULL) { pCurrentConfig = (SIPConfig *)sfPolicyUserDataGet(sip_config, _dpd.getDefaultPolicy()); } if (!pCurrentConfig) return 0; if (pPolicyConfig->maxNumSessions != pCurrentConfig->maxNumSessions) { _dpd.errMsg("SIP reload: Changing the max_sessions requires a restart.\n"); return -1; } return 0; } static int SIPFreeUnusedConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SIPConfig *pPolicyConfig = (SIPConfig *)pData; //do any housekeeping before freeing SIPConfig if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); SIP_FreeConfig(pPolicyConfig); } return 0; } static void * SIPReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId sip_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = sip_config; if (sip_swap_config == NULL) return NULL; sip_config = sip_swap_config; sfPolicyUserDataFreeIterate (old_config, SIPFreeUnusedConfigPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) { /* No more outstanding configs - free the config array */ return (void *)old_config; } return NULL; } static void SIPReloadSwapFree(void *data) { if (data == NULL) return; SIPFreeConfig((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/sip/Makefile.am0000644000000000000000000000147311746560364017714 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_sip_preproc.la libsf_sip_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_sip_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_sip_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sf_ip.c \ ../include/sfPolicyUserData.c endif libsf_sip_preproc_la_SOURCES = \ spp_sip.c \ spp_sip.h \ sip_config.c \ sip_config.h \ sip_parser.c \ sip_parser.h \ sip_dialog.c \ sip_dialog.h \ sip_roptions.c \ sip_roptions.h \ sip_utils.c \ sip_utils.h \ sip_debug.h EXTRA_DIST = \ sf_sip.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/sip/Makefile.in0000644000000000000000000005156612260606523017723 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/sip DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_sip_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_sip_preproc_la_OBJECTS = spp_sip.lo sip_config.lo \ sip_parser.lo sip_dialog.lo sip_roptions.lo sip_utils.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_sip_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo sf_ip.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_sip_preproc_la_OBJECTS = $(am_libsf_sip_preproc_la_OBJECTS) \ $(nodist_libsf_sip_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_sip_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_sip_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_sip_preproc_la_SOURCES) \ $(nodist_libsf_sip_preproc_la_SOURCES) DIST_SOURCES = $(libsf_sip_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_sip_preproc.la libsf_sip_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_sip_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_sip_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_ip.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_sip_preproc_la_SOURCES = \ spp_sip.c \ spp_sip.h \ sip_config.c \ sip_config.h \ sip_parser.c \ sip_parser.h \ sip_dialog.c \ sip_dialog.h \ sip_roptions.c \ sip_roptions.h \ sip_utils.c \ sip_utils.h \ sip_debug.h EXTRA_DIST = \ sf_sip.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/sip/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/sip/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_sip_preproc.la: $(libsf_sip_preproc_la_OBJECTS) $(libsf_sip_preproc_la_DEPENDENCIES) $(EXTRA_libsf_sip_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_sip_preproc_la_LINK) -rpath $(libdir) $(libsf_sip_preproc_la_OBJECTS) $(libsf_sip_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sf_ip.lo: ../include/sf_ip.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_ip.lo `test -f '../include/sf_ip.c' || echo '$(srcdir)/'`../include/sf_ip.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/sdf/0000755000000000000000000000000012260606564015707 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/sdf/sf_sdf.dsp0000644000000000000000000001274312153454770017613 00000000000000# Microsoft Developer Studio Project File - Name="sf_sdf" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_sdf - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_sdf.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_sdf.mak" CFG="sf_sdf - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_sdf - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_sdf - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_sdf - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_sdf - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_sdf - Win32 Release" # Name "sf_sdf - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\spp_sdf.c # End Source File # Begin Source File SOURCE=..\include\strtok_r.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\sdf_credit_card.c # End Source File # Begin Source File SOURCE=.\sdf_credit_card.h # End Source File # Begin Source File SOURCE=.\sdf_detection_option.c # End Source File # Begin Source File SOURCE=.\sdf_detection_option.h # End Source File # Begin Source File SOURCE=.\sdf_pattern_match.c # End Source File # Begin Source File SOURCE=.\sdf_pattern_match.h # End Source File # Begin Source File SOURCE=.\sdf_us_ssn.c # End Source File # Begin Source File SOURCE=.\sdf_us_ssn.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\spp_sdf.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/sdf/sdf_detection_option.h0000644000000000000000000000316512260565732022210 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SDF_DETECTION_OPTION__H #define SDF_DETECTION_OPTION__H #include #include "treenodes.h" #include "sf_dynamic_engine.h" #include "spp_sdf.h" int SDFOptionInit(struct _SnortConfig *sc, char *name, char *args, void **data); int SDFOptionEval(void *p, const uint8_t **cursor, void *data); int SDFOtnHandler(struct _SnortConfig *sc, void *potn); /* Struct for SDF option data */ typedef struct _SDFOptionData { char *pii; uint32_t counter_index; OptTreeNode *otn; int (*validate_func)(char *buf, uint32_t buflen, struct _SDFConfig *config); uint8_t count; uint8_t match_success; /* These are kept separately in case the OTN reference is freed */ uint32_t sid; uint32_t gid; } SDFOptionData; #endif snort-2.9.6.0/src/dynamic-preprocessors/sdf/sdf_detection_option.c0000644000000000000000000002234212260565732022201 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_sdf.h" #include "sdf_pattern_match.h" #include "sdf_detection_option.h" #include "sf_snort_plugin_api.h" #include "sdf_us_ssn.h" #include "sdf_credit_card.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "treenodes.h" #ifdef SNORT_RELOAD extern sdf_tree_node *swap_head_node; extern uint32_t swap_num_patterns; #endif void AddPortsToConf(struct _SnortConfig *sc, SDFConfig *config, OptTreeNode *otn); void AddProtocolsToConf(struct _SnortConfig *sc, SDFConfig *config, OptTreeNode *otn); /* Function: SDFOptionInit * Purpose: Parses a SDF rule option. * Arguments: * name => Name of rule option * args => Arguments to rule option * data => Variable to save option data * Returns: 1 if successful * 0 if name is incorrect * Fatal Error if invalid arguments */ int SDFOptionInit(struct _SnortConfig *sc, char *name, char *args, void **data) { char *token, *endptr; unsigned long int tmpcount; SDFOptionData *sdf_data; if (name == NULL || args == NULL || data == NULL) return 0; if (strcasecmp(name, SDF_OPTION_NAME) != 0) return 0; sdf_data = (SDFOptionData *)calloc(1, sizeof(SDFOptionData)); if (sdf_data == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Failed to allocate memory for " "SDF pattern data structure.", __FILE__, __LINE__); } /* Parse the count */ if (*args == '-') { free(sdf_data); DynamicPreprocessorFatalMessage("SDF rule cannot have a negative count:" " %s\n", args); } tmpcount = _dpd.SnortStrtoul(args, &endptr, 10); if (*endptr != ',') { free(sdf_data); DynamicPreprocessorFatalMessage("SDF rule configured with invalid " "arguments: %s\n", args); } if (tmpcount == 0 || tmpcount > 255) { free(sdf_data); DynamicPreprocessorFatalMessage("SDF rule needs to have a count between " " 1 - 255: %s\n", args); } sdf_data->count = (uint8_t)tmpcount; /* Take everything after the comma as a pattern. */ token = endptr + 1; if (*token == '\0') { free(sdf_data); DynamicPreprocessorFatalMessage("SDF rule missing pattern: %s ", args); } if (strcasecmp(token, SDF_CREDIT_KEYWORD) == 0) { sdf_data->pii = strdup(SDF_CREDIT_PATTERN_ALL); sdf_data->validate_func = SDFLuhnAlgorithm; } else if (strcasecmp(token, SDF_SOCIAL_KEYWORD) == 0) { sdf_data->pii = strdup(SDF_SOCIAL_PATTERN); sdf_data->validate_func = SDFSocialCheck; } else if (strcasecmp(token, SDF_SOCIAL_NODASHES_KEYWORD) == 0) { sdf_data->pii = strdup(SDF_SOCIAL_NODASHES_PATTERN); sdf_data->validate_func = SDFSocialCheck; } else if (strcasecmp(token, SDF_EMAIL_KEYWORD) == 0) { sdf_data->pii = strdup(SDF_EMAIL_PATTERN); } else { sdf_data->pii = strdup(token); sdf_data->validate_func = NULL; } *data = (void *)sdf_data; return 1; } /* This function receives the OTN of a fully-parsed rule, checks that it is a SDF rule, then adds pattern & OTN to the SDF pattern-matching tree. */ int SDFOtnHandler(struct _SnortConfig *sc, void *potn) { OptTreeNode *otn = (OptTreeNode *)potn; SDFConfig *config; tSfPolicyId policy_id; SDFOptionData *sdf_data; OptFpList *tmp = otn->opt_func; PreprocessorOptionInfo *preproc_info = NULL; tSfPolicyUserContextId context_to_use = sdf_context->context_id; sdf_tree_node *head_node_to_use = sdf_context->head_node; uint32_t *num_patterns_to_use = &sdf_context->num_patterns; int sdf_option_added = 0; #ifdef SNORT_RELOAD /* If we are reloading, use that context instead. This should work since preprocessors get configured before rule parsing */ SDFContext *sdf_swap_context; sdf_swap_context = (SDFContext *)_dpd.getRelatedReloadData(sc, "sensitive_data"); if (sdf_swap_context != NULL) { context_to_use = sdf_swap_context->context_id; head_node_to_use = sdf_swap_context->head_node; num_patterns_to_use = &sdf_swap_context->num_patterns; } #endif /* Retrieve the current policy being parsed */ policy_id = _dpd.getParserPolicy(sc); sfPolicyUserPolicySet(context_to_use, policy_id); config = (SDFConfig *) sfPolicyUserDataGetCurrent(context_to_use); /* Check that this is a SDF rule, then grab the context data. */ while (tmp != NULL && tmp->type != RULE_OPTION_TYPE_LEAF_NODE) { if (tmp->type == RULE_OPTION_TYPE_PREPROCESSOR) preproc_info = tmp->context; if (preproc_info == NULL || preproc_info->optionEval != (PreprocOptionEval) SDFOptionEval) { DynamicPreprocessorFatalMessage("%s(%d) Rules with SDF options cannot " "have other detection options in the same rule.\n", *_dpd.config_file, *_dpd.config_line); } if (sdf_option_added) { DynamicPreprocessorFatalMessage("A rule may contain only one " "\"%s\" option.\n", SDF_OPTION_NAME); } if (otn->sigInfo.generator != GENERATOR_SPP_SDF_RULES) { DynamicPreprocessorFatalMessage("Rules with SDF options must " "use GID %d.\n", GENERATOR_SPP_SDF_RULES); } sdf_data = (SDFOptionData *)preproc_info->data; sdf_data->otn = otn; sdf_data->sid = otn->sigInfo.id; sdf_data->gid = otn->sigInfo.generator; /* Add the pattern to the SDF pattern-matching tree */ AddPii(head_node_to_use, sdf_data); sdf_data->counter_index = (*num_patterns_to_use)++; AddPortsToConf(sc, config, otn); AddProtocolsToConf(sc, config, otn); sdf_option_added = 1; preproc_info = NULL; tmp = tmp->next; } return 1; } /* Take a port object's ports and add them to the preprocessor's port array. */ void AddPortsToConf(struct _SnortConfig *sc, SDFConfig *config, OptTreeNode *otn) { int i, nports; char *src_parray, *dst_parray; RuleTreeNode *rtn; if (config == NULL || otn == NULL) return; /* RTNs vary based on which policy the rule appears in. */ rtn = otn->proto_nodes[_dpd.getParserPolicy(sc)]; /* Take the source port object and add ports to the preproc's array */ src_parray = _dpd.portObjectCharPortArray(NULL, rtn->src_portobject, &nports); if (src_parray == 0) { /* This is an "any" port object! */ for (i = 0; i < MAX_PORTS/8; i++) { config->src_ports[i] = 0xFF; } } else { /* iterate through an array of ports, add each one. */ for (i = 0; i < MAX_PORTS; i++) { if (src_parray[i] == 1) config->src_ports[PORT_INDEX(i)] |= CONV_PORT(i); } } /* Repeat for destination ports. */ dst_parray = _dpd.portObjectCharPortArray(NULL, rtn->dst_portobject, &nports); if (dst_parray == 0) { /* This is an "any" port object! */ for (i = 0; i < MAX_PORTS/8; i++) { config->dst_ports[i] = 0xFF; } } else { /* iterate through an array of ports, add each one. */ for (i = 0; i < MAX_PORTS; i++) { if (dst_parray[i] == 1) config->dst_ports[PORT_INDEX(i)] |= CONV_PORT(i); } } /* Cleanup */ if (src_parray) free(src_parray); if (dst_parray) free(dst_parray); } void AddProtocolsToConf(struct _SnortConfig *sc, SDFConfig *config, OptTreeNode *otn) { #ifdef TARGET_BASED unsigned int i; int16_t ordinal; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); if (config == NULL || otn == NULL) return; for (i = 0; i < otn->sigInfo.num_services; i++) { ordinal = otn->sigInfo.services[i].service_ordinal; if (ordinal > 0 && ordinal < MAX_PROTOCOL_ORDINAL) config->protocol_ordinals[ordinal] = 1; _dpd.streamAPI->set_service_filter_status( sc, ordinal, PORT_MONITOR_SESSION, policy_id, 1); } #endif } /* Stub function -- We're not evaluating SDF during rule-matching */ int SDFOptionEval(void *p, const uint8_t **cursor, void *data) { return RULE_NOMATCH; } snort-2.9.6.0/src/dynamic-preprocessors/sdf/sdf_us_ssn.h0000644000000000000000000000230712260565732020151 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SDF_US_SSN__H #define SDF_US_SSN__H struct _SDFConfig; /* Forward declaration of SDFConfig */ int SDFSocialCheck(char *buf, uint32_t buflen, struct _SDFConfig *config); int ParseSSNGroups(char *filename, struct _SDFConfig *config); int SSNSetDefaultGroups(struct _SDFConfig *config); #endif /* SDF_US_SSN__H */ snort-2.9.6.0/src/dynamic-preprocessors/sdf/sdf_us_ssn.c0000644000000000000000000002350412260565732020146 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_sdf.h" #include "sdf_us_ssn.h" #include "sf_dynamic_preprocessor.h" #include #include #include #include #include #include static int SDFCompareGroupNumbers(int group, int max_group); static int SSNGroupCategory(int group); /* This function takes a string representation of a US Social Security number and checks that it is valid. The string may include or omit hyphens.*/ int SDFSocialCheck(char *buf, uint32_t buflen, struct _SDFConfig *config) { uint32_t i; int digits, area, group, serial; char numbuf[9]; if (buf == NULL || buflen > 13 || buflen < 9) return 0; /* The string will have a non-digit byte on each side. Truncate these. */ buflen -= 2; buf++; /* Check that the string is made of digits, and strip hyphens. */ digits = 0; for (i = 0; i < buflen; i++) { if (isdigit((int)buf[i])) { /* Check for too many digits */ if (digits == 9) return 0; numbuf[digits++] = buf[i]; } else if (buf[i] != '-') break; } if (digits != 9) return 0; /* Convert to ints */ area = (numbuf[0] - '0') * 100 + (numbuf[1] - '0') * 10 + (numbuf[2] - '0'); group = (numbuf[3] - '0') * 10 + (numbuf[4] - '0'); serial = (numbuf[5] - '0') * 1000 + (numbuf[6] - '0') * 100 + (numbuf[7] - '0') * 10 + (numbuf[8] - '0'); /* This range was reserved for advertising */ if (area == 987 && group == 65) { if (serial >= 4320 && serial <= 4329) return 0; } /* Start validating */ if (area > MAX_AREA || area == 666 || area <= 0 || group <= 0 || group > 99 || serial <= 0 || serial > 9999) return 0; return SDFCompareGroupNumbers(group, config->ssn_max_group[area]); } static int SDFCompareGroupNumbers(int group, int max_group) { /* Group numbers are not issued in consecutive order. They go in this order: 1. ODD numbers from 01 through 09 2. EVEN numbers from 10 through 98 3. EVEN numbers from 02 through 08 4. ODD numbers from 11 through 99 For this reason, the group check is not simple. */ int group_category = SSNGroupCategory(group); int max_group_category = SSNGroupCategory(max_group); if (group_category == 0 || max_group_category == 0) return 0; if (group_category < max_group_category) return 1; if ((group_category == max_group_category) && (group <= max_group)) return 1; return 0; } static int SSNGroupCategory(int group) { if ((group % 2 == 1) && (group < 10)) return 1; if ((group % 2 == 0) && (group >= 10) && (group <= 98)) return 2; if ((group % 2 == 0) && (group < 10)) return 3; if ((group % 2 == 1) && (group >= 11) && (group <= 99)) return 4; return 0; } int ParseSSNGroups(char *filename, struct _SDFConfig *config) { FILE *ssn_file; char *contents, *token, *saveptr, *endptr; long length; int i = 1; if (filename == NULL || config == NULL) return -1; ssn_file = fopen(filename, "r"); if (ssn_file == NULL) { _dpd.logMsg("Sensitive Data preprocessor: Failed to open SSN groups " "file \"%s\": %s.\n", filename, strerror(errno)); return -1; } /* Determine size of file */ if (fseek(ssn_file, 0, SEEK_END) == -1) { _dpd.logMsg("Sensitive Data preprocessor: Failed to fseek() to end of " "SSN groups file \"%s\": %s.\n", filename, strerror(errno)); fclose(ssn_file); return -1; } if ((length = ftell(ssn_file)) <= 0) { if (length == -1) { _dpd.logMsg("Sensitive Data preprocessor: Failed to get size of SSN " "groups file \"%s\": %s.\n", filename, strerror(errno)); } else { _dpd.logMsg("Sensitive Data preprocessor: SSN groups file \"%s\" " "is empty.\n", filename); } fclose(ssn_file); return -1; } rewind(ssn_file); contents = (char *)malloc(length + 1); if (contents == NULL) { _dpd.logMsg("Sensitive Data preprocessor: Failed to allocate memory " "for SSN groups.\n"); fclose(ssn_file); return -1; } /* Read file into memory */ if (fread(contents, sizeof(char), length, ssn_file) != (size_t)length) { _dpd.logMsg("Sensitive Data preprocessor: Failed read contents of " "SSN groups file \"%s\".\n", filename); fclose(ssn_file); return -1; } fclose(ssn_file); contents[length] = '\0'; /* Parse! */ token = strtok_r(contents, " ,\n", &saveptr); while (token) { if (i > MAX_AREA) { /* TODO: Print error - too many ints */ free(contents); return -1; } config->ssn_max_group[i++] = strtol(token, &endptr, 10); if (*endptr != '\0') { /* TODO: Print error - not a complete number */ free(contents); return -1; } token = strtok_r(NULL, " ,\n", &saveptr); } free(contents); return 0; } /* Default array of maximum group numbers for each area. These values were last up-to-date as of November 2009. */ int SSNSetDefaultGroups(struct _SDFConfig *config) { int i; int default_max_group[MAX_AREA+1] = { 0, 8, 8, 6, 11, 11, 11, 8, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 90, 90, 90, 90, 90, 90, 74, 74, 72, 72, 72, 15, 13, 13, 13, 13, 13, 13, 13, 13, 13, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 86, 86, 86, 86, 86, 86, 86, 86, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 85, 85, 8, 8, 99, 99, 99, 99, 99, 99, 99, 99, 99, 55, 55, 55, 55, 55, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 35, 35, 35, 35, 35, 35, 35, 35, 33, 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 6, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 71, 71, 71, 71, 71, 71, 69, 69, 99, 99, 99, 99, 99, 99, 99, 99, 65, 65, 65, 65, 65, 65, 65, 63, 63, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 27, 25, 25, 25, 25, 25, 25, 25, 25, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 55, 53, 53, 53, 53, 53, 53, 53, 53, 53, 41, 41, 39, 39, 39, 39, 39, 39, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 35, 35, 43, 43, 55, 55, 55, 55, 31, 31, 31, 29, 29, 29, 29, 47, 47, 83, 83, 59, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 67, 67, 67, 67, 67, 67, 67, 67, 65, 79, 79, 79, 77, 77, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 57, 99, 99, 49, 49, 49, 39, 99, 99, 99, 99, 99, 65, 99, 5, 99, 99, 99, 99, 99, 99, 99, 90, 88, 88, 88, 99, 99, 79, 79, 79, 79, 79, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 23, 23, 23, 23, 23, 23, 23, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 13, 11, 52, 52, 56, 56, 54, 54, 32, 32, 32, 32, 32, 20, 20, 20, 20, 18, 18, 18, 44, 42, 42, 42, 42, 42, 42, 42, 42, 18, 18, 18, 16, 17, 20, 20, 20, 20, 18, 18, 18, 18, 18, 18, 12, 12, 12, 12, 12, 12, 12, 12, 12, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 28, 18, 18, 10, 14, 20, 18, 18, 18, 18, 14, 14, 5, 5, 5, 5, 10, 9, 9, 9, 9, 9, 9, 9, 11, 8, 86, 86, 86, 86, 84, 84, 84 }; if (config == NULL) return -1; for (i = 0; i < MAX_AREA+1; i++) { config->ssn_max_group[i] = default_max_group[i]; } return 1; } snort-2.9.6.0/src/dynamic-preprocessors/sdf/sdf_credit_card.h0000644000000000000000000000236312260565732021104 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SDF_CREDIT_CARD__H #define SDF_CREDIT_CARD__H #include #include "spp_sdf.h" #define ISSUER_SIZE 4 #define CC_COPY_BUF_LEN 20 /* 16 digits + 3 spaces/dashes + null */ #define MIN_CC_BUF_LEN 15 /* 13 digits + 2 surrounding non-digits */ int SDFLuhnAlgorithm(char *buf, uint32_t buflen, struct _SDFConfig *config); #endif /* SDF_CREDIT_CARD__H */ snort-2.9.6.0/src/dynamic-preprocessors/sdf/sdf_credit_card.c0000644000000000000000000000732112260565732021076 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_sdf.h" #include "sdf_credit_card.h" #include #include #include /* Check the Issuer Identification Number of a CC#. */ static inline int CheckIssuers(char *cardnum, uint32_t buflen) { if (cardnum == NULL || buflen < ISSUER_SIZE) return 0; /* Visa */ if (cardnum[0] == '4') return 1; /* Mastercard */ if ((cardnum[0] == '5') && (cardnum[1] > '0') && (cardnum[1] < '6')) return 1; /* Amex */ if ((cardnum[0] == '3') && (cardnum[1] == '4' || cardnum[1] == '7')) return 1; /* Discover */ if (cardnum[0] == '6' && cardnum[1] == '0' && cardnum[2] == '1' && cardnum[3] == '1') return 1; return 0; } /* This function takes a string representation of a credit card number and * checks that it's a valid number. The number may contain spaces or dashes. * * Returns: 1 on match, 0 otherwise. */ int SDFLuhnAlgorithm(char *buf, uint32_t buflen, struct _SDFConfig *config) { int i, digits, alternate, sum, val; char cc_digits[CC_COPY_BUF_LEN]; /* Normalized CC# string */ uint32_t j; if (buf == NULL || buflen < MIN_CC_BUF_LEN) return 0; /* The buffer has two non-digits, one on either side. Strip these out. */ buf++; buflen -= 2; /* If the first digit is greater than 6, this isn't one of the major credit cards. */ if (!isdigit((int)buf[0]) || buf[0] > '6') return 0; /* Check the issuer number for Visa, Mastercard, Amex, or Discover. */ if (CheckIssuers(buf, buflen) == 0) return 0; /* Limit to 16 digits + spaces in between */ if (buflen >= CC_COPY_BUF_LEN) buflen = CC_COPY_BUF_LEN - 1; /* Copy the string into cc_digits, stripping out spaces & dashes. */ digits = 0; for (j = 0; j < buflen; j++) { if (isdigit((int)buf[j]) == 0) { if (buf[j] == ' ' || buf[j] == '-') continue; else break; } cc_digits[digits++] = buf[j]; } cc_digits[digits] = '\0'; /* Check if the string was too short, or we broke at an invalid character */ if (digits < 13 || digits > 16 || j < buflen) return 0; /* The Luhn algorithm: 1) Starting at the right-most digit, double every second digit. 2) Sum all the *individual* digits (i.e. 16 => 1+6) 3) If the Sum mod 10 == 0, the CC# is valid. */ alternate = 0; sum = 0; for (i = digits - 1; i >= 0; i--) { val = cc_digits[i] - '0'; if (alternate) { val *= 2; if (val > 9) val -= 9; } alternate = !alternate; sum += val; } if (sum % 10) return 0; return 1; } snort-2.9.6.0/src/dynamic-preprocessors/sdf/sdf_pattern_match.h0000644000000000000000000000331712260565732021472 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SDF_PATTERN_MATCH__H #define SDF_PATTERN_MATCH__H #include "spp_sdf.h" #include "sdf_detection_option.h" #include "treenodes.h" #include int AddPii(sdf_tree_node *head, SDFOptionData *data); int AddPiiPiece(sdf_tree_node *node, char *new_pattern, SDFOptionData *data); int SplitNode(sdf_tree_node *node, uint16_t split_index); sdf_tree_node * AddChild(sdf_tree_node *node, SDFOptionData *data, char *pattern); int FreePiiTree(sdf_tree_node *head); sdf_tree_node * FindPii(const sdf_tree_node *head, char *buf, uint16_t *buf_index, uint16_t buflen, SDFConfig *config, SDFSessionData *session); sdf_tree_node * FindPiiRecursively(sdf_tree_node *node, char *buf, uint16_t *buf_index, uint16_t buflen, SDFConfig *config, uint16_t *partial_index, sdf_tree_node **partial_node); #endif /* SDF_PATTERN_MATCH__H */ snort-2.9.6.0/src/dynamic-preprocessors/sdf/sdf_pattern_match.c0000644000000000000000000005130012260565732021460 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "sdf_pattern_match.h" #include "treenodes.h" #include "sf_dynamic_preprocessor.h" /* Main pattern-adding function. * Arguments: * head => pointer to top node in PII tree * data => pointer to SDFOptionData struct w/ new pattern * otn => pointer to OptTreeNode struct that this pattern belongs to * Return values: * -1: error * 1: pattern added successfully */ static int AddPiiPattern(sdf_tree_node *head, SDFOptionData *data) { char *pattern = data->pii; int i = 0; int pattern_added = 0; if (head == NULL || pattern == NULL) return -1; /* If the root has some children, try to fit the pattern under them first. */ while(i < head->num_children && !pattern_added) { pattern_added = AddPiiPiece(head->children[i], pattern, data); i++; } /* Otherwise, add a new child to the root node */ if (!pattern_added) { AddChild(head, data, data->pii); pattern_added = 1; } return pattern_added; } /* Check that the brackets in a pattern match up, and only contain numbers. * * Arguments: * pii - string containing pattern. * * Returns: void function. Raises fatal error if there's a problem. */ static void ExpandBrackets(char **pii) { char *bracket_index, *new_pii, *endptr, *pii_position; unsigned long int new_pii_size, repetitions, total_reps = 0; unsigned int num_brackets = 0; if (pii == NULL || *pii == NULL) return; /* Locate first '{' */ bracket_index = strchr(*pii, '{'); /* Brackets at the beginning have nothing to modify. */ if (bracket_index == *pii) { DynamicPreprocessorFatalMessage("SDF Pattern \"%s\" starts with curly " "brackets which have nothing to modify.\n", *pii); } /* Check for various error cases. Total up the # of bytes needed in new pattern */ while (bracket_index) { /* Ignore escaped brackets */ if ((bracket_index > *pii) && (*(bracket_index-1) == '\\')) { bracket_index = strchr(bracket_index+1, '{'); continue; } /* Check for the case of one bracket set modifying another, i.e. "{3}{4}" Note: "\}{4}" is OK */ if ((bracket_index > (*pii)+1) && (*(bracket_index-1) == '}') && (*(bracket_index-2) != '\\') ) { DynamicPreprocessorFatalMessage("SDF Pattern \"%s\" contains curly " "brackets which have nothing to modify.\n", *pii); } /* Get the number from inside the brackets */ repetitions = strtoul(bracket_index+1, &endptr, 10); if (*endptr != '}' && *endptr != '\0') { DynamicPreprocessorFatalMessage("SDF Pattern \"%s\" contains curly " "brackets with non-digits inside.\n", *pii); } else if (*endptr == '\0') { DynamicPreprocessorFatalMessage("SDF Pattern \"%s\" contains " "an unterminated curly bracket.\n", *pii); } /* The brackets look OK. Increase the rep count. */ if ((bracket_index > (*pii)+1) && (*(bracket_index-2) == '\\')) total_reps += (repetitions * 2); else total_reps += repetitions; num_brackets++; /* Next bracket */ bracket_index = strchr(bracket_index+1, '{'); } /* By this point, the brackets all match up. */ if (num_brackets == 0) return; /* Allocate the new pii string. */ new_pii_size = (strlen(*pii) + total_reps - 2*num_brackets + 1); new_pii = (char *) calloc(new_pii_size, sizeof(char)); if (new_pii == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory for " "SDF preprocessor.\n"); } /* Copy the PII string, expanding repeated sections. */ pii_position = *pii; while (*pii_position != '\0') { char repeated_section[3] = {'\0'}; unsigned long int i, reps = 1; repeated_section[0] = pii_position[0]; pii_position++; if (repeated_section[0] == '\\' && pii_position[0] != '\0') { repeated_section[1] = pii_position[0]; pii_position++; } if (pii_position[0] == '{') { reps = strtoul(pii_position+1, &endptr, 10); pii_position = endptr+1; } /* Channeling "Shlemiel the Painter" here. */ for (i = 0; i < reps; i++) { strncat(new_pii, repeated_section, 2); } } /* Switch out the pii strings. */ free(*pii); *pii = new_pii; } /* Perform any modifications needed to a pattern string, then add it to the tree. */ int AddPii(sdf_tree_node *head, SDFOptionData *data) { if (head == NULL || data == NULL) return -1; ExpandBrackets(&(data->pii)); return AddPiiPattern(head, data); } /* Recursive pattern-adding function. * Return values: * -1: error * 0: pattern did not go in this subtree * 1: pattern was added in this subtree */ int AddPiiPiece(sdf_tree_node *node, char *new_pattern, SDFOptionData *data) { /* Potential cases: 1) node->pattern and new_pattern overlap by some number of bytes, but both end differently. Split the current node then add a second child. 2) node->pattern is a substring of new_pattern. Preserve current node, go on to children. If no children exist, add one and stop. 3) new_pattern is a substring of node->pattern. Split the current node, AND add an end-of-pattern marker. 4) Pattern doesn't fit here at all. Return 0 to caller. */ char *node_pattern_copy; uint16_t overlapping_bytes = 0; if (node == NULL || new_pattern == NULL || *new_pattern == '\0') return -1; /* Count the overlapping bytes between a) our current node's pattern b) the piece of the PII pattern being added here Additionally, we advance the pattern ptr to the non-matching part, so that only the non-matching part is added to a child node. */ node_pattern_copy = node->pattern; while(*node_pattern_copy != '\0' && *new_pattern != '\0' && *node_pattern_copy == *new_pattern) { /* Handle escape sequences: either the whole thing matches, or not at all */ if (*new_pattern == '\\') { if (*(new_pattern+1) != *(node_pattern_copy+1)) break; /* Don't increment twice if the strings just ended in '\' */ if (*(new_pattern+1) != '\0') { new_pattern++; node_pattern_copy++; overlapping_bytes++; } } new_pattern++; node_pattern_copy++; overlapping_bytes++; } if (*node_pattern_copy == '\0' && *new_pattern == '\0') { /* Patterns completely match */ uint16_t i; int data_added = 0; /* Replace old option_data if the sid & gid match. The OTN has already been freed out from under us. */ for (i = 0; i < node->num_option_data; i++) { if ((node->option_data_list[i]->sid == data->sid) && (node->option_data_list[i]->gid == data->gid)) { free(node->option_data_list[i]->pii); free(node->option_data_list[i]); node->option_data_list[i] = data; data_added = 1; } } /* Otherwise, append the new option_data to the list. */ if (!data_added) { SDFOptionData **tmp_realloc_ptr = NULL; tmp_realloc_ptr = (SDFOptionData **) realloc((void *)node->option_data_list, (node->num_option_data + 1) * sizeof(SDFOptionData *)); if (tmp_realloc_ptr == NULL) DynamicPreprocessorFatalMessage("%s(%d) Could not reallocate " "option_data_list\n", __FILE__, __LINE__); node->option_data_list = tmp_realloc_ptr; node->option_data_list[node->num_option_data] = data; node->num_option_data++; } return 1; } else if (*node_pattern_copy == '\0') { int i; /* Current node holds a subset of the pattern. Recurse to the children. */ for(i = 0; i < node->num_children; i++) { if (AddPiiPiece(node->children[i], new_pattern, data) == 1) return 1; } /* No children matched, or no children existed. Add the child here. */ AddChild(node, data, new_pattern); return 1; } else if (*new_pattern == '\0') { /* pattern is a subset of the current node's pattern */ SplitNode(node, overlapping_bytes); node->num_option_data = 1; node->option_data_list = (SDFOptionData **) calloc(1, sizeof(SDFOptionData *)); if (node->option_data_list == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate option_data_list\n", __FILE__, __LINE__); } node->option_data_list[0] = data; return 1; } else if (overlapping_bytes > 0) { /* Add the child node */ SplitNode(node, overlapping_bytes); AddChild(node, data, new_pattern); return 1; } /* These patterns don't overlap at all! */ return 0; } int SplitNode(sdf_tree_node *node, uint16_t split_index) { sdf_tree_node *new_node = NULL; if (node == NULL) return -1; if (split_index > strlen(node->pattern)) return -1; /* Create new node for second half of split */ new_node = (sdf_tree_node *) calloc(1,sizeof(sdf_tree_node)); if (new_node == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate new_node\n", __FILE__, __LINE__); } /* Fill in the new node with the child pointers, pattern, pii ptr */ new_node->pattern = strdup(node->pattern + split_index); if (new_node->pattern == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate new_node pattern\n", __FILE__, __LINE__); } new_node->children = node->children; new_node->option_data_list = node->option_data_list; new_node->num_children = node->num_children; new_node->num_option_data = node->num_option_data; /* Truncate the pattern of the current node, set child to new node */ node->children = (sdf_tree_node **) calloc(1,sizeof(sdf_tree_node *)); if (node->children == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate node children\n", __FILE__, __LINE__); } node->children[0] = new_node; node->num_children = 1; node->option_data_list = NULL; node->num_option_data = 0; node->pattern[split_index] = '\0'; return 0; } /* Create a new tree node, and add it as a child to the current node. */ sdf_tree_node * AddChild(sdf_tree_node *node, SDFOptionData *data, char *pattern) { sdf_tree_node *new_node = NULL; /* Take care not to step on the other children */ if (node->num_children) { sdf_tree_node **new_child_ptrs = (sdf_tree_node **) calloc(node->num_children+1, sizeof(sdf_tree_node *)); if (new_child_ptrs == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate new child pointers\n", __FILE__, __LINE__); } memcpy(new_child_ptrs, node->children, (node->num_children * sizeof(sdf_tree_node *))); new_node = (sdf_tree_node *) calloc(1,sizeof(sdf_tree_node)); if (new_node == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate new node\n", __FILE__, __LINE__); } new_child_ptrs[node->num_children] = new_node; free(node->children); node->children = new_child_ptrs; node->num_children++; } else { node->children = (sdf_tree_node **)calloc(1,sizeof(sdf_tree_node *)); if (node->children == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate node children\n", __FILE__, __LINE__); } node->children[0] = (sdf_tree_node *)calloc(1,sizeof(sdf_tree_node)); if (node->children[0] == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate node children[0]\n", __FILE__, __LINE__); } node->num_children = 1; new_node = node->children[0]; } new_node->pattern = strdup(pattern); if (new_node->pattern == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate node pattern\n", __FILE__, __LINE__); } new_node->num_option_data = 1; new_node->option_data_list = (SDFOptionData **) calloc(1, sizeof(SDFOptionData *)); if (new_node->option_data_list == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Could not allocate node list\n", __FILE__, __LINE__); } new_node->option_data_list[0] = data; return new_node; } /* Frees an entire PII tree. */ int FreePiiTree(sdf_tree_node *node) { uint16_t i; if (node == NULL) return -1; for (i = 0; i < node->num_children; i++) { FreePiiTree(node->children[i]); } free(node->pattern); free(node->children); for (i = 0; i < node->num_option_data; i++) { free(node->option_data_list[i]->pii); free(node->option_data_list[i]); } free(node->option_data_list); free(node); return 0; } /* Returns an sdf_tree_node that matches the pattern */ sdf_tree_node * FindPiiRecursively(sdf_tree_node *node, char *buf, uint16_t *buf_index, uint16_t buflen, SDFConfig *config, uint16_t *partial_index, sdf_tree_node **partial_node) { uint16_t old_buf_index; uint16_t pattern_index = *partial_index; int node_match = 1; *partial_index = 0; *partial_node = NULL; if (node == NULL || buf == NULL || buflen == 0 || *buf_index >= buflen) return NULL; /* Save the value of buf_index that was passed in. We revert to this value if a pattern is not matched here. Ultimately, it should hold the number of bytes matched against a pattern. */ old_buf_index = *buf_index; /* Match pattern buf against current node. Evaluate escape sequences. NOTE: node->pattern is a NULL-terminated string, but buf is network data and may legitimately contain NULL bytes. */ while (*buf_index < buflen && *(node->pattern + pattern_index) != '\0' && node_match ) { /* Match a byte at a time. */ if ( *(node->pattern + pattern_index) == '\\' && *(node->pattern + pattern_index + 1) != '\0' ) { /* Escape sequence found */ pattern_index++; switch ( *(node->pattern + pattern_index) ) { /* Escaped special character */ case '\\': case '{': case '}': case '?': node_match = (*(buf + *buf_index) == *(node->pattern + pattern_index)); break; /* \d : match digit */ case 'd': node_match = isdigit( (int)(*(buf + *buf_index)) ); break; /* \D : match non-digit */ case 'D': node_match = !isdigit( (int)(*(buf + *buf_index)) ); break; /* \w : match alphanumeric */ case 'w': node_match = isalnum( (int)(*(buf + *buf_index)) ); break; /* \W : match non-alphanumeric */ case 'W': node_match = !isalnum( (int)(*(buf + *buf_index)) ); break; /* \l : match a letter */ case 'l': node_match = isalpha( (int)(*(buf + *buf_index)) ); break; /* \L : match a non-letter */ case 'L': node_match = !isalpha( (int)(*(buf + *buf_index)) ); break; } } else { /* Normal byte */ node_match = (*(buf + *buf_index) == *(node->pattern + pattern_index)); } /* Handle optional characters */ if (*(node->pattern + pattern_index + 1) == '?') { /* Advance past the '?' in the pattern string. Only advance in the buffer if we matched the optional char. */ pattern_index += 2; if (node_match) (*buf_index)++; else node_match = 1; } else { /* Advance to next byte */ (*buf_index)++; pattern_index++; } } if (node_match) { int i = 0; uint16_t j; bool node_contains_matches = false; sdf_tree_node *matched_node = NULL; if(*buf_index == buflen) { if( (*(node->pattern + pattern_index) != '\0') || ((strlen(node->pattern) == pattern_index) && node->num_children)) { *partial_index = pattern_index; *partial_node = node; return NULL; } } /* Check the children first. Always err on the side of a larger match. */ while (i < node->num_children && matched_node == NULL) { matched_node = FindPiiRecursively(node->children[i], buf, buf_index, buflen, config, partial_index, partial_node); i++; } if (matched_node != NULL) return matched_node; /* An sdf_tree_node holds multiple SDFOptionData. It's possible to get some with validation funs and some without. Evaluate them independently. */ for (j = 0; j < node->num_option_data; j++) { SDFOptionData *option_data = node->option_data_list[j]; /* Run eval func, return NULL if it exists but fails */ if (option_data->validate_func != NULL && option_data->validate_func(buf, *buf_index, config) != 1) { *buf_index = old_buf_index; option_data->match_success = 0; } else { /* No eval func necessary, or an eval func existed and returned 1 */ option_data->match_success = 1; node_contains_matches = true; } } if (node_contains_matches) return node; } /* No match here. */ *buf_index = old_buf_index; return NULL; } /* This function takes a head node, and searches the children for PII. * * head - Pointer to head node of SDF patttern tree. This contains no pattern. * buf - Buffer to search for patterns * buf_index - Pointer to store number of bytes that matched a pattern. * buflen - Length of buffer pointed to by buf * config - SDF preprocessor configuration. * * returns: sdf_tree_node ptr for matched pattern, or NULL if no match. */ sdf_tree_node * FindPii(const sdf_tree_node *head, char *buf, uint16_t *buf_index, uint16_t buflen, SDFConfig *config, SDFSessionData *session) { uint16_t i; uint16_t *partial_index = &(session->part_match_index); sdf_tree_node **partial_node = &(session->part_match_node); if (head == NULL) return NULL; for (i = 0; i < head->num_children; i++) { sdf_tree_node * matched_node; matched_node = FindPiiRecursively(head->children[i], buf, buf_index, buflen, config, partial_index, partial_node); if (matched_node || *partial_index) return matched_node; } return NULL; } snort-2.9.6.0/src/dynamic-preprocessors/sdf/spp_sdf.h0000644000000000000000000000732212260565732017443 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * spp_sdf.h: Definitions, prototypes, etc. for the SDF preprocessor. * Author: Ryan Jordan */ #ifndef SPP_SDF_H #define SPP_SDF_H /*#include "sdf_pattern_match.h"*/ #include #include "sfPolicyUserData.h" #include "sdf_us_ssn.h" #include "sdf_detection_option.h" #define GENERATOR_SPP_SDF_RULES 138 #define GENERATOR_SPP_SDF_PREPROC 139 /* This is the maximum defined area number */ #define MAX_AREA 772 #define MAX_PORTS 65536 #define PORT_INDEX(port) port/8 #define CONV_PORT(port) 1 << (port % 8) #define MAX_PROTOCOL_ORDINAL 8192 typedef struct _sdf_tree_node { char *pattern; uint16_t num_children; uint16_t num_option_data; struct _sdf_tree_node **children; SDFOptionData **option_data_list; } sdf_tree_node; typedef struct _SDFSessionData { sdf_tree_node *part_match_node; uint16_t part_match_index; uint32_t num_patterns, global_counter; uint8_t *counters; int8_t *rtns_matched; uint32_t config_num; } SDFSessionData; typedef struct _SDFContext { tSfPolicyUserContextId context_id; sdf_tree_node *head_node; uint32_t num_patterns; } SDFContext; typedef struct _SDFConfig { SFSnortPacket *pseudo_packet; SDFSessionData *stateless_session; uint32_t threshold; uint8_t mask_output; int ssn_max_group[MAX_AREA+1]; unsigned char src_ports[MAX_PORTS/8]; unsigned char dst_ports[MAX_PORTS/8]; unsigned char protocol_ordinals[MAX_PROTOCOL_ORDINAL]; uint32_t config_num; } SDFConfig; /* Definitions of config options */ #define SDF_THRESHOLD_KEYWORD "alert_threshold" #define SDF_MASK_KEYWORD "mask_output" #define SDF_SSN_FILE_KEYWORD "ssn_file" #define SDF_OPTION_NAME "sd_pattern" #define SDF_OPTION_SEPARATORS "," /* Order of SDF options */ #define SDF_OPTION_COUNT_NUM 1 #define SDF_OPTION_PATTERN_NUM 2 /* Keywords for SDF built-in option */ /* This pattern matches Visa/Mastercard/Amex, with & without spaces or dashes. The pattern alone would match other non-credit patterns, but the function SDFLuhnAlgorithm() does stricter checking. */ #define SDF_CREDIT_KEYWORD "credit_card" #define SDF_CREDIT_PATTERN_ALL "\\D\\d{4} ?-?\\d{4} ?-?\\d{2} ?-?\\d{2} ?-?\\d{3}\\d?\\D" #define SDF_SOCIAL_KEYWORD "us_social" #define SDF_SOCIAL_PATTERN "\\D\\d{3}-\\d{2}-\\d{4}\\D" #define SDF_SOCIAL_NODASHES_KEYWORD "us_social_nodashes" #define SDF_SOCIAL_NODASHES_PATTERN "\\D\\d{9}\\D" #define SDF_EMAIL_KEYWORD "email" #define SDF_EMAIL_PATTERN "\\w@\\w" /* Obfuscation constants */ #define SDF_OBFUSCATION_CHAR 'X' #define SDF_OBFUSCATION_DIGITS_SHOWN 4 /* Length of ": 255\0" */ #define SDF_ALERT_LENGTH 6 /* Combo Alert constants */ #define SDF_COMBO_ALERT_SID 1 #define SDF_COMBO_ALERT_REV 1 #define SDF_COMBO_ALERT_CLASS 1 #define SDF_COMBO_ALERT_PRIORITY 1 #define SDF_COMBO_ALERT_STR "(spp_sdf) SDF Combination Alert" extern SDFContext *sdf_context; #endif snort-2.9.6.0/src/dynamic-preprocessors/sdf/spp_sdf.c0000644000000000000000000007355212260565732017446 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2009-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #include "sf_types.h" /* #include "snort.h" #include "parser.h" #include "util.h" #include "plugbase.h" */ #include "snort_debug.h" #include "stream_api.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "sf_snort_packet.h" /* #ifdef TARGET_BASED #include "sftarget_protocol_reference.h" #endif */ #include "profiler.h" #include "spp_sdf.h" #include "sf_preproc_info.h" #include "sdf_us_ssn.h" #include "sdf_detection_option.h" #include "sdf_pattern_match.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_SDF"; #define SetupSDF DYNAMIC_PREPROC_SETUP /* PROTOTYPES */ static void SDFInit(struct _SnortConfig *, char *args); static void ProcessSDF(void *p, void *context); static SDFConfig * NewSDFConfig(struct _SnortConfig *, tSfPolicyUserContextId); static void ParseSDFArgs(SDFConfig *config, char *args); static void SDFCleanExit(int signal, void *unused); static int SDFFreeConfig(tSfPolicyUserContextId context, tSfPolicyId id, void *pData); static void SDFFillPacket(sdf_tree_node *node, SDFSessionData *session, SFSnortPacket *p, uint16_t *dlen); static void SDFPrintPseudoPacket(SDFConfig *config, SDFSessionData *session, SFSnortPacket *real_packet); #ifdef SNORT_RELOAD static void SDFReload(struct _SnortConfig *, char *, void **); static void * SDFReloadSwap(struct _SnortConfig *, void *); static void SDFReloadSwapFree(void *); #endif /* GLOBALS :( */ SDFContext *sdf_context = NULL; static uint32_t sdf_config_count = 0; #ifdef SNORT_RELOAD sdf_tree_node *swap_head_node = NULL; uint32_t swap_num_patterns = 0; #endif #ifdef PERF_PROFILING PreprocStats sdfPerfStats; #endif #define IPPROTO_SDF 0xFE // TBD - use same for ps? (eg IPPROTO_SNORT?) /* * Function: SetupSDF() * * Purpose: Registers the preprocessor keyword and initialization function * into the preprocessor list. * * Arguments: None. * * Returns: void * */ void SetupSDF(void) { #ifndef SNORT_RELOAD _dpd.registerPreproc("sensitive_data", SDFInit); #else _dpd.registerPreproc("sensitive_data", SDFInit, SDFReload, NULL, SDFReloadSwap, SDFReloadSwapFree); #endif } /* * Function: SDFInit(char *) * * Purpose: Processes the args sent to the preprocessor, sets up the port list, * links the processing function into the preproc function list * * Arguments: args => ptr to argument string * * Returns: void * */ void SDFInit(struct _SnortConfig *sc, char *args) { SDFConfig *config = NULL; /* Check prerequisites */ if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SDFInit(): The Stream preprocessor must be enabled.\n"); } /* Create context id, register callbacks. This is only done once. */ if (sdf_context == NULL) { sdf_context = (SDFContext *)calloc(1, sizeof(*sdf_context)); if (!sdf_context) DynamicPreprocessorFatalMessage("Failed to allocate memory for SDF " "configuration.\n"); sdf_context->context_id = sfPolicyConfigCreate(); if (!sdf_context->context_id) DynamicPreprocessorFatalMessage("Failed to allocate memory for SDF " "configuration.\n"); sdf_context->head_node = (sdf_tree_node *)calloc(1, sizeof(*sdf_context->head_node)); if (!sdf_context->head_node) DynamicPreprocessorFatalMessage("Failed to allocate memory for SDF " "configuration.\n"); _dpd.addPreprocExit(SDFCleanExit, NULL, PRIORITY_LAST, PP_SDF); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("sensitive_data", (void *)&sdfPerfStats, 0, _dpd.totalPerfStats); #endif } /* Handle configuration. This is done once for each policy. */ config = NewSDFConfig(sc, sdf_context->context_id); ParseSDFArgs(config, args); /* Register callbacks */ _dpd.addDetect(sc, ProcessSDF, PRIORITY_FIRST, PP_SDF, PROTO_BIT__TCP | PROTO_BIT__UDP); _dpd.preprocOptRegister(sc, SDF_OPTION_NAME, SDFOptionInit, SDFOptionEval, NULL, NULL, NULL, SDFOtnHandler, NULL); } /* Check the ports and target-based protocol for a given packet. * * Returns: 0 if the port check fails * 1 if the packet should be inspected */ static int SDFCheckPorts(SDFConfig *config, SFSnortPacket *packet) { #ifdef TARGET_BASED int16_t app_ordinal = SFTARGET_UNKNOWN_PROTOCOL; /* Do port checks */ app_ordinal = _dpd.streamAPI->get_application_protocol_id(packet->stream_session_ptr); if (app_ordinal == SFTARGET_UNKNOWN_PROTOCOL) return 0; if (app_ordinal && (config->protocol_ordinals[app_ordinal] == 0)) return 0; if (app_ordinal == 0) { #endif /* No target-based info for this packet. Check ports. */ if (((config->src_ports[PORT_INDEX(packet->src_port)] & CONV_PORT(packet->src_port)) == 0) || ((config->dst_ports[PORT_INDEX(packet->dst_port)] & CONV_PORT(packet->dst_port)) == 0)) { return 0; } #ifdef TARGET_BASED } #endif return 1; } /* A free function that gets registered along with our Stream session data */ static void FreeSDFSession(void *data) { SDFSessionData *session = (SDFSessionData *)data; if (session == NULL) return; free(session->counters); free(session->rtns_matched); free(session); return; } /* Create a new SDF session data struct. Returns: Fatal Error if allocation fails Valid ptr otherwise */ static SDFSessionData * NewSDFSession(SDFConfig *config, SFSnortPacket *packet) { SDFSessionData *session; /* Allocate new session data. */ session = (SDFSessionData *) malloc(sizeof(SDFSessionData)); if (session == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory for " "SDF preprocessor session data.\n"); } if (packet->stream_session_ptr) { _dpd.streamAPI->set_application_data(packet->stream_session_ptr, PP_SDF, session, FreeSDFSession); } session->part_match_node= NULL; session->part_match_index = 0; session->global_counter = 0; session->config_num = config->config_num; /* Allocate counters in the session data */ session->num_patterns = sdf_context->num_patterns; session->counters = calloc(session->num_patterns, sizeof(uint8_t)); session->rtns_matched = calloc(session->num_patterns, sizeof(int8_t)); if (session->counters == NULL || session->rtns_matched == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory for " "SDF preprocessor session data.\n"); } return session; } static void SDFSearchRecursively(SDFConfig *config, SFSnortPacket *packet, SDFSessionData *session, sdf_tree_node *matched_node, char **position, uint16_t *buflen, uint16_t match_length) { /* Iterate through the SDFOptionData that matches this pattern. */ uint16_t i; for (i = 0; i < matched_node->num_option_data; i++) { SDFOptionData *found_pattern = matched_node->option_data_list[i]; if (found_pattern->match_success) { int index; /* Reset the match_success flag for subsequent matches */ found_pattern->match_success = 0; /* Check the RTN for the PII we found. The IPs & ports might not match. We only want to do this once per session */ index = found_pattern->counter_index; if (session->rtns_matched[index] == 0) { bool check_ports = true; OptTreeNode *otn = found_pattern->otn; RuleTreeNode *rtn = NULL; #ifdef TARGET_BASED int16_t app_ordinal; #endif if (_dpd.getRuntimePolicy() < otn->proto_node_num) rtn = otn->proto_nodes[_dpd.getRuntimePolicy()]; #ifdef TARGET_BASED /* Check the service against the matched OTN. */ app_ordinal = _dpd.streamAPI->get_application_protocol_id(packet->stream_session_ptr); if( app_ordinal != SFTARGET_UNKNOWN_PROTOCOL ) { int16_t i; for (i = 0; i < otn->sigInfo.num_services; i++) { if (otn->sigInfo.services[i].service_ordinal == app_ordinal) { check_ports = false; break; } } } #endif if (rtn != NULL && _dpd.fpEvalRTN(rtn, packet, check_ports)) session->rtns_matched[index] = 1; else session->rtns_matched[index] = -1; } if (session->rtns_matched[index] == 1) { /* Increment counters */ session->counters[found_pattern->counter_index]++; /* Obfuscate the data. We do this even if it's not time to alert, to obfuscate each match. */ if (config->mask_output) { /* Only obfuscate built-in patterns */ if (found_pattern->validate_func) { uint16_t offset, ob_length = 0; offset = (uint16_t) ((*position) - (char *)packet->payload); if (match_length > SDF_OBFUSCATION_DIGITS_SHOWN) ob_length = match_length - SDF_OBFUSCATION_DIGITS_SHOWN; /* The CC# and SS# patterns now contain non-digits on either side of the actual number. Adjust the mask to match. */ offset = offset + 1; ob_length = ob_length - 2; _dpd.obApi->addObfuscationEntry(packet, offset, ob_length, SDF_OBFUSCATION_CHAR); } } if (session->counters[found_pattern->counter_index] == found_pattern->count) { /* Raise the alert for this particular pattern */ _dpd.alertAdd(GENERATOR_SPP_SDF_RULES, found_pattern->otn->sigInfo.id, found_pattern->otn->sigInfo.rev, found_pattern->otn->sigInfo.class_id, found_pattern->otn->sigInfo.priority, found_pattern->otn->sigInfo.message, 0); } } } } /* Check the global counter and alert */ session->global_counter++; if (session->global_counter == config->threshold) { /* Do our "combo alert" */ SDFPrintPseudoPacket(config, session, packet); _dpd.genSnortEvent(config->pseudo_packet, GENERATOR_SPP_SDF_PREPROC, SDF_COMBO_ALERT_SID, SDF_COMBO_ALERT_REV, SDF_COMBO_ALERT_CLASS, SDF_COMBO_ALERT_PRIORITY, SDF_COMBO_ALERT_STR); } /* Update position */ (*position) += match_length; (*buflen) -= match_length; } /* Search a buffer for PII. Generates alerts when enough PII is found. Returns: void */ static void SDFSearch(SDFConfig *config, SFSnortPacket *packet, SDFSessionData *session, char *position, char *end, uint16_t buflen) { uint16_t match_length = 0; sdf_tree_node *matched_node = NULL; uint16_t *partial_index = &(session->part_match_index); sdf_tree_node **partial_node = &(session->part_match_node); /* Check to see if there was a partial match */ if(*partial_index > 0) { if( position < end ) { sdf_tree_node *node = *partial_node; if(strlen(node->pattern) == *partial_index) { int i = 0; while ((i < node->num_children) && matched_node == NULL) { *partial_index = 0; matched_node = FindPiiRecursively(node->children[i], position, &match_length, buflen, config, partial_index, partial_node); i++; } } else { matched_node = FindPiiRecursively(node, position, &match_length, buflen, config, partial_index, partial_node); } /* only when matched update the position ptr. FindPiiRecursively only checks one node unlike FindPii */ if (matched_node) SDFSearchRecursively(config, packet, session, matched_node, &position, &buflen, match_length); else if (*partial_index) { position += match_length; buflen -= match_length; } } else { return; } } while (position < end) { match_length = 0; matched_node = NULL; /* Traverse the pattern tree and match PII against our data */ matched_node = FindPii(sdf_context->head_node, position, &match_length, buflen, config, session); if (matched_node) SDFSearchRecursively(config, packet, session, matched_node, &position, &buflen, match_length); else if (*partial_index) { position += match_length; buflen -= match_length; } else { position++; buflen--; } } } /* * Function: ProcessSDF(void *, void *) * * Purpose: Inspects a packet's payload for Personally Identifiable Information * * Arguments: p => poitner to the current packet data struct * context => unused void pointer * * Returns: void * */ static void ProcessSDF(void *p, void *context) { tSfPolicyId policy_id; SDFConfig *config = NULL; SFSnortPacket *packet = (SFSnortPacket *)p; SDFSessionData *session; char *begin, *end; uint16_t buflen; PROFILE_VARS; // preconditions - what we registered for assert((IsUDP(packet) || IsTCP(packet)) && packet->payload && packet->payload_size); /* Check if we should be working on this packet */ if ( packet->flags & FLAG_STREAM_INSERT && !PacketHasFullPDU(p) ) return; // Waiting on stream reassembly /* Retrieve the corresponding config for this packet */ policy_id = _dpd.getRuntimePolicy(); sfPolicyUserPolicySet (sdf_context->context_id, policy_id); config = sfPolicyUserDataGetCurrent(sdf_context->context_id); /* Retrieve stream session data. Create one if it doesn't exist. */ session = _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_SDF); if (session == NULL) { /* Do port checks */ if (SDFCheckPorts(config, packet) == 0) { return; } /* If there's no stream session, we'll just count PII for one packet */ if (packet->stream_session_ptr == NULL) { if (config->stateless_session == NULL) config->stateless_session = NewSDFSession(config, packet); session = config->stateless_session; memset(session->counters, 0, session->num_patterns); memset(session->rtns_matched, 0, session->num_patterns); } else session = NewSDFSession(config, packet); } else if( session->config_num != config->config_num ) { /* Config has changed. Don't use rule tree nodes from previous config */ session->part_match_index = 0; session->part_match_node = NULL; /* Update the session's config num */ session->config_num = config->config_num; } PREPROC_PROFILE_START(sdfPerfStats); /* Inspect HTTP Body or Email attachments. */ if (_dpd.fileDataBuf->len > 0) { begin = (char *) _dpd.fileDataBuf->data; buflen = _dpd.fileDataBuf->len; end = begin + buflen; SDFSearch(config, packet, session, begin, end, buflen); } else if ( PacketHasPAFPayload(packet) ) { /* SDF already requires stream to be enabled, might as well look * at the rebuilt packet */ begin = (char *)packet->payload; buflen = packet->payload_size; end = begin + buflen; SDFSearch(config, packet, session, begin, end, buflen); } /* If this packet is HTTP, inspect the URI and Client Body while ignoring * headers. */ if (packet->flags & FLAG_HTTP_DECODE) { unsigned len; begin = (char*)_dpd.getHttpBuffer(HTTP_BUFFER_URI, &len); if ( begin ) { buflen = (uint16_t)len; end = begin + buflen; SDFSearch(config, packet, session, begin, end, buflen); } begin = (char*)_dpd.getHttpBuffer(HTTP_BUFFER_CLIENT_BODY, &len); if ( begin ) { buflen = (uint16_t)len; end = begin + buflen; SDFSearch(config, packet, session, begin, end, buflen); } } /* End. */ PREPROC_PROFILE_END(sdfPerfStats); return; } static void DisplaySDFConfig(SDFConfig *config) { if (config == NULL) return; _dpd.logMsg("Sensitive Data preprocessor config: \n"); _dpd.logMsg(" Global Alert Threshold: %d\n", config->threshold); _dpd.logMsg(" Masked Output: %s\n", config->mask_output ? "ENABLED" : "DISABLED" ); } /* * Function: ParseSDFArgs(SDFConfig *, char *) * * Purpose: Parse the arguments to the SDF preprocessor and instantiate a * SDFConfig struct. * * Arguments: config => pointer to a newly-allocated SDFConfig struct, which * will be modified. * args => pointer to string containing SDF preproc arguments. * * Returns: void * */ static void ParseSDFArgs(SDFConfig *config, char *args) { char *argcpy = NULL; char *cur_tokenp = NULL; if (config == NULL || args == NULL) return; /* Set default options */ SSNSetDefaultGroups(config); /* Copy args so that we can break them up wtih strtok */ argcpy = strdup(args); if (argcpy == NULL) DynamicPreprocessorFatalMessage("Could not allocate memory to parse " "SDF options.\n"); cur_tokenp = strtok(argcpy, " "); /* Loop through config options */ while (cur_tokenp) { /* Parse the global PII threshold */ if (!strcmp(cur_tokenp, SDF_THRESHOLD_KEYWORD)) { char *endptr; cur_tokenp = strtok(NULL, " "); if (cur_tokenp == NULL) { DynamicPreprocessorFatalMessage("SDF preprocessor config option " "\"%s\" requires an argument.\n", SDF_THRESHOLD_KEYWORD); } if (*cur_tokenp == '-') { DynamicPreprocessorFatalMessage("SDF preprocessor config option " "\"%s\" cannot take a negative argument.\n", SDF_THRESHOLD_KEYWORD); } config->threshold = _dpd.SnortStrtoul(cur_tokenp, &endptr, 10); if (config->threshold == 0 || config->threshold > USHRT_MAX) { DynamicPreprocessorFatalMessage("SDF preprocessor config option " "\"%s\" must have an argument between 1 - %u.\n", SDF_THRESHOLD_KEYWORD, USHRT_MAX); } if (*endptr != '\0') { DynamicPreprocessorFatalMessage("Invalid argument to SDF config " "option \"%s\": %s", SDF_THRESHOLD_KEYWORD, cur_tokenp); } } /* Parse the output masking option */ else if (!strcmp(cur_tokenp, SDF_MASK_KEYWORD)) { config->mask_output = 1; } /* Parse the file containing new SSN group data */ else if (!strcmp(cur_tokenp, SDF_SSN_FILE_KEYWORD)) { int iRet; cur_tokenp = strtok(NULL, " "); if (cur_tokenp == NULL) { DynamicPreprocessorFatalMessage("SDF preprocessor config option " "\"%s\" requires an argument.\n", SDF_SSN_FILE_KEYWORD); } iRet = ParseSSNGroups(cur_tokenp, config); if (iRet < 0) { DynamicPreprocessorFatalMessage("Error parsing Social Security " "group data from file: %s", cur_tokenp); } } cur_tokenp = strtok(NULL, " "); } /* Cleanup */ DisplaySDFConfig(config); free(argcpy); argcpy = NULL; } /* Allocate & Initialize the pseudo-packet used for logging combo alerts. * * Returns: 0 on success, -1 on error. */ static int SDFPacketInit(SDFConfig *config) { config->pseudo_packet = _dpd.encodeNew(); return 0; } /* * Function: NewSDFConfig(void) * * Purpose: Create a new SDFConfig for the current parser policy. * * Arguments: context => context ID to use when creating config * * Returns: Pointer to newly created SDFConfig struct. * */ static SDFConfig * NewSDFConfig(struct _SnortConfig *sc, tSfPolicyUserContextId context) { SDFConfig *config = NULL; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); /* Check for an existing configuration in this policy */ sfPolicyUserPolicySet(context, policy_id); config = (SDFConfig *) sfPolicyUserDataGetCurrent(context); if (config) DynamicPreprocessorFatalMessage("SDF preprocessor can only be " "configured once.\n"); /* Create and store config */ config = (SDFConfig *)calloc(1, sizeof(SDFConfig)); if (!config) DynamicPreprocessorFatalMessage("Failed to allocate memory for SDF " "configuration.\n"); sfPolicyUserDataSetCurrent(context, config); /* Allocate the pseudo-packet used for logging */ SDFPacketInit(config); config->config_num = sdf_config_count++; return config; } /* * Function: SDFCleanExit(int, void *) * * Purpose: Free memory used by the SDF preprocessor before Snort exits. * * Arguments: Signal sent to Snort, unused void pointer * * Returns: void * */ static void SDFCleanExit(int signal, void *unused) { /* Free the individual configs. */ if (sdf_context == NULL) return; sfPolicyUserDataFreeIterate(sdf_context->context_id, SDFFreeConfig); sfPolicyConfigDelete(sdf_context->context_id); FreePiiTree(sdf_context->head_node); free(sdf_context); sdf_context = NULL; } /* * Function: SDFFreeConfig(tSfPolicyUserContextId, tSfPolicyId, void *) * * Purpose: Callback that frees a SDFConfig struct correctly, and clears data * from the policy. * * Arguments: context => context ID for the SDF preprocessor * id => policy ID for the policy being destroyed * pData => pointer to SDFConfig struct that gets freed * * Returns: zero * */ static int SDFFreeConfig(tSfPolicyUserContextId context, tSfPolicyId id, void *pData) { SDFConfig *config = (SDFConfig *)pData; sfPolicyUserDataClear(context, id); _dpd.encodeDelete(config->pseudo_packet); FreeSDFSession(config->stateless_session); free(config); return 0; } #ifdef SNORT_RELOAD static void SDFReload(struct _SnortConfig *sc, char *args, void **new_config) { SDFContext *sdf_swap_context = (SDFContext *)*new_config; SDFConfig *config = NULL; if (sdf_swap_context == NULL) { if (!_dpd.streamAPI) DynamicPreprocessorFatalMessage("SetupSDF(): The Stream preprocessor " "must be enabled.\n"); sdf_swap_context = (SDFContext *)calloc(1, sizeof(*sdf_context)); if (!sdf_swap_context) DynamicPreprocessorFatalMessage("Failed to allocate memory for SDF " "configuration.\n"); sdf_swap_context->context_id = sfPolicyConfigCreate(); if (!sdf_swap_context->context_id) DynamicPreprocessorFatalMessage("Failed to allocate memory for SDF " "configuration.\n"); sdf_swap_context->head_node = (sdf_tree_node *)calloc(1, sizeof(*sdf_swap_context->head_node)); if (!sdf_swap_context->head_node) DynamicPreprocessorFatalMessage("Failed to allocate memory for SDF " "configuration.\n"); *new_config = (void *)sdf_swap_context; } config = NewSDFConfig(sc, sdf_swap_context->context_id); ParseSDFArgs(config, args); _dpd.addDetect(sc, ProcessSDF, PRIORITY_FIRST, PP_SDF, PROTO_BIT__TCP | PROTO_BIT__UDP); _dpd.preprocOptRegister(sc, SDF_OPTION_NAME, SDFOptionInit, SDFOptionEval, NULL, NULL, NULL, SDFOtnHandler, NULL); } static void * SDFReloadSwap(struct _SnortConfig *sc, void *swap_config) { SDFContext *sdf_swap_context = (SDFContext *)swap_config; SDFContext *old_context = sdf_context; if (old_context == NULL || sdf_swap_context == NULL) return NULL; sdf_context = sdf_swap_context; return (void *) old_context; } static void SDFReloadSwapFree(void *data) { SDFContext *context = (SDFContext *) data; if (context == NULL) return; sfPolicyUserDataFreeIterate(context->context_id, SDFFreeConfig); sfPolicyConfigDelete(context->context_id); FreePiiTree(context->head_node); free(context); } #endif /* * checksum IP - header=20+ bytes * * w - short words of data * blen - byte length * */ static inline unsigned short in_chksum_ip( unsigned short * w, int blen ) { unsigned int cksum; /* IP must be >= 20 bytes */ cksum = w[0]; cksum += w[1]; cksum += w[2]; cksum += w[3]; cksum += w[4]; cksum += w[5]; cksum += w[6]; cksum += w[7]; cksum += w[8]; cksum += w[9]; blen -= 20; w += 10; while( blen ) /* IP-hdr must be an integral number of 4 byte words */ { cksum += w[0]; cksum += w[1]; w += 2; blen -= 4; } cksum = (cksum >> 16) + (cksum & 0x0000ffff); cksum += (cksum >> 16); return (unsigned short) (~cksum); } static void SDFPrintPseudoPacket(SDFConfig *config, SDFSessionData *session, SFSnortPacket *real_packet) { SFSnortPacket* p; if (config == NULL || session == NULL || real_packet == NULL) return; p = config->pseudo_packet; _dpd.encodeFormat(ENC_DYN_FWD|ENC_DYN_NET, real_packet, config->pseudo_packet, PSEUDO_PKT_SDF); if ( IS_IP4(real_packet) ) { ((IPV4Header *)p->ip4_header)->proto = IPPROTO_SDF; p->inner_ip4h.ip_proto = IPPROTO_SDF; } else if (IS_IP6(p)) { // FIXTHIS assumes there are no ip6 extension headers p->inner_ip6h.next = IPPROTO_SDF; p->ip6h = &p->inner_ip6h; } /* Fill in the payload with SDF alert info */ SDFFillPacket(sdf_context->head_node, session, p, &p->payload_size); _dpd.encodeUpdate(config->pseudo_packet); if (real_packet->family == AF_INET) { p->ip4h->ip_len = p->ip4_header->data_length; } else { IP6RawHdr* ip6h = (IP6RawHdr*)p->raw_ip6_header; if ( ip6h ) p->ip6h->len = ip6h->ip6_payload_len; } } /* This function traverses the pattern tree and prints out the relevant * info into a provided pseudo-packet. */ static void SDFFillPacket(sdf_tree_node *node, SDFSessionData *session, SFSnortPacket *p, uint16_t *dlen) { uint16_t i; if (node == NULL || session == NULL || p == NULL || dlen == NULL) return; /* Recurse to the leaves of the pattern tree */ for (i = 0; i < node->num_children; i++) { SDFFillPacket(node->children[i], session, p, dlen); } for (i = 0; i < node->num_option_data; i++) { SDFOptionData * option_data = node->option_data_list[i]; /* Print the info from leaves */ if (option_data) { uint32_t index = option_data->counter_index; uint8_t counter = session->counters[index]; if (counter > 0) { /* Print line */ char *sigmessage = option_data->otn->sigInfo.message; uint8_t *dest = (uint8_t*)p->payload + *dlen; size_t siglen = strlen(sigmessage); uint16_t space_left = p->max_payload - *dlen; if (space_left < siglen + SDF_ALERT_LENGTH) return; *dlen += (siglen + SDF_ALERT_LENGTH); snprintf((char *)dest, space_left, "%s: %3d", sigmessage, counter); } } } return; } snort-2.9.6.0/src/dynamic-preprocessors/sdf/Makefile.am0000644000000000000000000000142011746560364017665 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_sdf_preproc.la libsf_sdf_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_sdf_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_sdf_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sfPolicyUserData.c endif libsf_sdf_preproc_la_SOURCES = \ spp_sdf.c \ spp_sdf.h \ sdf_pattern_match.c \ sdf_pattern_match.h \ sdf_credit_card.c \ sdf_credit_card.h \ sdf_us_ssn.c \ sdf_us_ssn.h \ sdf_detection_option.c \ sdf_detection_option.h EXTRA_DIST = \ sf_sdf.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/sdf/Makefile.in0000644000000000000000000005077712260606523017707 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/sdf DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_sdf_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_sdf_preproc_la_OBJECTS = spp_sdf.lo sdf_pattern_match.lo \ sdf_credit_card.lo sdf_us_ssn.lo sdf_detection_option.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_sdf_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_sdf_preproc_la_OBJECTS = $(am_libsf_sdf_preproc_la_OBJECTS) \ $(nodist_libsf_sdf_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_sdf_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_sdf_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_sdf_preproc_la_SOURCES) \ $(nodist_libsf_sdf_preproc_la_SOURCES) DIST_SOURCES = $(libsf_sdf_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_sdf_preproc.la libsf_sdf_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_sdf_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_sdf_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_sdf_preproc_la_SOURCES = \ spp_sdf.c \ spp_sdf.h \ sdf_pattern_match.c \ sdf_pattern_match.h \ sdf_credit_card.c \ sdf_credit_card.h \ sdf_us_ssn.c \ sdf_us_ssn.h \ sdf_detection_option.c \ sdf_detection_option.h EXTRA_DIST = \ sf_sdf.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/sdf/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/sdf/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_sdf_preproc.la: $(libsf_sdf_preproc_la_OBJECTS) $(libsf_sdf_preproc_la_DEPENDENCIES) $(EXTRA_libsf_sdf_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_sdf_preproc_la_LINK) -rpath $(libdir) $(libsf_sdf_preproc_la_OBJECTS) $(libsf_sdf_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/0000755000000000000000000000000012260606564016455 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/sf_dce2.dsp0000644000000000000000000001667612153454770020433 00000000000000# Microsoft Developer Studio Project File - Name="sf_dce2" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_dce2 - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_dce2.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_dce2.mak" CFG="sf_dce2 - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_dce2 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_dce2 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_dce2 - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I ".\includes" /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FR /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_dce2 - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\includes" /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FR /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_dce2 - Win32 Release" # Name "sf_dce2 - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\dce2_cl.c # End Source File # Begin Source File SOURCE=.\dce2_co.c # End Source File # Begin Source File SOURCE=.\dce2_config.c # End Source File # Begin Source File SOURCE=.\dce2_debug.c # End Source File # Begin Source File SOURCE=.\dce2_event.c # End Source File # Begin Source File SOURCE=.\dce2_http.c # End Source File # Begin Source File SOURCE=.\dce2_list.c # End Source File # Begin Source File SOURCE=.\dce2_memory.c # End Source File # Begin Source File SOURCE=.\dce2_paf.c # End Source File # Begin Source File SOURCE=.\dce2_roptions.c # End Source File # Begin Source File SOURCE=.\dce2_smb.c # End Source File # Begin Source File SOURCE=.\dce2_stats.c # End Source File # Begin Source File SOURCE=.\dce2_tcp.c # End Source File # Begin Source File SOURCE=.\dce2_udp.c # End Source File # Begin Source File SOURCE=.\dce2_utils.c # End Source File # Begin Source File SOURCE="..\..\win32\WIN32-Code\inet_aton.c" # End Source File # Begin Source File SOURCE="..\..\win32\WIN32-Code\inet_pton.c" # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_ip.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=..\include\sfrt.c # End Source File # Begin Source File SOURCE=..\include\sfrt_dir.c # End Source File # Begin Source File SOURCE=.\snort_dce2.c # End Source File # Begin Source File SOURCE=.\spp_dce2.c # End Source File # Begin Source File SOURCE="..\..\win32\WIN32-Code\strtok_r.c" # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\dce2_cl.h # End Source File # Begin Source File SOURCE=.\dce2_co.h # End Source File # Begin Source File SOURCE=.\dce2_config.h # End Source File # Begin Source File SOURCE=.\dce2_debug.h # End Source File # Begin Source File SOURCE=.\dce2_event.h # End Source File # Begin Source File SOURCE=.\dce2_http.h # End Source File # Begin Source File SOURCE=.\dce2_list.h # End Source File # Begin Source File SOURCE=.\dce2_memory.h # End Source File # Begin Source File SOURCE=.\dce2_paf.h # End Source File # Begin Source File SOURCE=.\dce2_roptions.h # End Source File # Begin Source File SOURCE=.\dce2_session.h # End Source File # Begin Source File SOURCE=.\dce2_smb.h # End Source File # Begin Source File SOURCE=.\dce2_stats.h # End Source File # Begin Source File SOURCE=.\dce2_tcp.h # End Source File # Begin Source File SOURCE=.\dce2_udp.h # End Source File # Begin Source File SOURCE=.\dce2_utils.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\snort_dce2.h # End Source File # Begin Source File SOURCE=.\spp_dce2.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_paf.h0000644000000000000000000000262612260565732020220 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifndef __DCE2_PAF_H__ #define __DCE2_PAF_H__ #include "sfPolicy.h" #include "sf_types.h" #include "stream_api.h" #include "dce2_utils.h" int DCE2_PafRegisterPort(struct _SnortConfig *, uint16_t, tSfPolicyId, DCE2_TransType); #ifdef TARGET_BASED int DCE2_PafRegisterService(struct _SnortConfig *, uint16_t, tSfPolicyId, DCE2_TransType); #endif #endif /* __DCE2_PAF_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_paf.c0000644000000000000000000005154112260565732020213 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #include "sf_types.h" #include "sfPolicy.h" #include "sf_dynamic_preprocessor.h" #include "stream_api.h" #include "dce2_utils.h" #include "dce2_session.h" #include "dce2_smb.h" #include "dce2_debug.h" #include "snort_dce2.h" #include "includes/dcerpc.h" #include "includes/smb.h" #define DCE2_SMB_PAF_SHIFT(x64, x8) { x64 <<= 8; x64 |= (uint64_t)x8; } // Enumerations for PAF states typedef enum _DCE2_PafSmbStates { DCE2_PAF_SMB_STATES__0 = 0, // NetBIOS type DCE2_PAF_SMB_STATES__1, // Added bit of NetBIOS length DCE2_PAF_SMB_STATES__2, // First byte of NetBIOS length DCE2_PAF_SMB_STATES__3, // Second byte of NetBIOS length // Junk states DCE2_PAF_SMB_STATES__4, // 0xff DCE2_PAF_SMB_STATES__5, // 'S' DCE2_PAF_SMB_STATES__6, // 'M' DCE2_PAF_SMB_STATES__7 // 'B' } DCE2_PafSmbStates; typedef enum _DCE2_PafTcpStates { DCE2_PAF_TCP_STATES__0 = 0, DCE2_PAF_TCP_STATES__1, DCE2_PAF_TCP_STATES__2, DCE2_PAF_TCP_STATES__3, DCE2_PAF_TCP_STATES__4, // Byte order DCE2_PAF_TCP_STATES__5, DCE2_PAF_TCP_STATES__6, DCE2_PAF_TCP_STATES__7, DCE2_PAF_TCP_STATES__8, // First byte of fragment length DCE2_PAF_TCP_STATES__9 // Second byte of fragment length } DCE2_PafTcpStates; // State tracker for DCE/RPC over SMB PAF typedef struct _DCE2_PafSmbState { DCE2_PafSmbStates state; uint64_t nb_hdr; // Enough for NetBIOS header and 4 bytes SMB header } DCE2_PafSmbState; // State tracker for DCE/RPC over TCP PAF typedef struct _DCE2_PafTcpState { DCE2_PafTcpStates state; DceRpcBoFlag byte_order; uint16_t frag_len; } DCE2_PafTcpState; // Local function prototypes static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t, bool); static inline bool DCE2_PafAbort(void *, uint32_t); static PAF_Status DCE2_SmbPaf(void *, void **, const uint8_t *, uint32_t, uint32_t, uint32_t *); static PAF_Status DCE2_TcpPaf(void *, void **, const uint8_t *, uint32_t, uint32_t, uint32_t *); /********************************************************************* * Function: DCE2_PafAbort() * * Purpose: Queries the dcerpc2 session data to see if paf abort * flag is set. * * Arguments: * void * - stream session pointer * uint32_t - flags passed in to callback. * Should have PKT_FROM_CLIENT or PKT_FROM_SERVER set. * * Returns: * bool - true if we should abort PAF, false if not. * *********************************************************************/ static inline bool DCE2_PafAbort(void *ssn, uint32_t flags) { DCE2_SsnData *sd; if (_dpd.streamAPI->get_session_flags(ssn) & SSNFLAG_MIDSTREAM) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Aborting PAF because of midstream pickup.\n")); return true; } else if (!(_dpd.streamAPI->get_session_flags(ssn) & SSNFLAG_ESTABLISHED)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Aborting PAF because of unestablished session.\n")); return true; } sd = (DCE2_SsnData *)_dpd.streamAPI->get_application_data(ssn, PP_DCE2); if ((sd != NULL) && DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Aborting PAF because of session data check.\n")); return true; } return false; } /********************************************************************* * Function: DCE2_PafSmbIsValidNetbiosHdr() * * Purpose: Validates that the NetBIOS header is valid. If in * junk states, header type must be Session Message. * * Arguments: * uint32_t - the 4 bytes of the NetBIOS header * bool - whether we're in a junk data state or not * * Returns: * bool - true if valid, false if not * *********************************************************************/ static inline bool DCE2_PafSmbIsValidNetbiosHdr(uint32_t nb_hdr, bool junk) { uint8_t type = (uint8_t)(nb_hdr >> 24); uint8_t bit = (uint8_t)((nb_hdr & 0x00ff0000) >> 16); if (junk) { if (type != NBSS_SESSION_TYPE__MESSAGE) return false; } else { switch (type) { case NBSS_SESSION_TYPE__MESSAGE: case NBSS_SESSION_TYPE__REQUEST: case NBSS_SESSION_TYPE__POS_RESPONSE: case NBSS_SESSION_TYPE__NEG_RESPONSE: case NBSS_SESSION_TYPE__RETARGET_RESPONSE: case NBSS_SESSION_TYPE__KEEP_ALIVE: break; default: return false; } } if ((bit != 0x00) && (bit != 0x01)) return false; return true; } /********************************************************************* * Function: DCE2_SmbPaf() * * Purpose: The DCE/RPC over SMB PAF callback. * Inspects a byte at a time changing state and shifting * bytes onto the 64bit nb_hdr member. At state 3 * determines if NetBIOS header is valid and if so sets * flush point. If not valid goes to states 4-7 where * there is the possibility that junk data was inserted * before request/response. Needs to validate SMB ID at * this point. At state 7 determines if NetBIOS header * is valid and that the SMB ID is present. Stays in * state 7 until this is the case. * * Arguments: * void * - stream5 session pointer * void ** - SMB state tracking structure * const uint8_t * - payload data to inspect * uint32_t - length of payload data * uint32_t - flags to check whether client or server * uint32_t * - pointer to set flush point * * Returns: * PAF_Status - PAF_FLUSH if flush point found, PAF_SEARCH otherwise * *********************************************************************/ PAF_Status DCE2_SmbPaf(void *ssn, void **user, const uint8_t *data, uint32_t len, uint32_t flags, uint32_t *fp) { DCE2_PafSmbState *ss = *(DCE2_PafSmbState **)user; uint32_t n = 0; PAF_Status ps = PAF_SEARCH; uint32_t nb_hdr; uint32_t nb_len; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_START_MSG)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "SMB: %u bytes of data\n", len)); #ifdef DEBUG_MSGS DCE2_DEBUG_CODE(DCE2_DEBUG__PAF, printf("Session pointer: %p\n", _dpd.streamAPI->get_application_data(ssn, PP_DCE2));) if (flags & FLAG_FROM_CLIENT) DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Packet from Client\n")); else DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Packet from Server\n")); #endif if (DCE2_PafAbort(ssn, flags)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return PAF_ABORT; } if (ss == NULL) { // beware - we allocate here but s5 calls free() directly // so no pointers allowed ss = calloc(1, sizeof(DCE2_PafSmbState)); if (ss == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return PAF_ABORT; } *user = ss; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Start state: %u\n", ss->state)); while (n < len) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, " State %d : 0x%02x", ss->state, data[n])); #ifdef DEBUG_MSGS if (isprint(data[n])) DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, " '%c'\n", data[n])); else DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "\n")); #endif switch (ss->state) { case DCE2_PAF_SMB_STATES__0: ss->nb_hdr = (uint64_t)data[n]; ss->state++; break; case DCE2_PAF_SMB_STATES__3: DCE2_SMB_PAF_SHIFT(ss->nb_hdr, data[n]); if (DCE2_PafSmbIsValidNetbiosHdr((uint32_t)ss->nb_hdr, false)) { nb_hdr = htonl((uint32_t)ss->nb_hdr); nb_len = NbssLen((const NbssHdr *)&nb_hdr); *fp = (nb_len + sizeof(NbssHdr) + n) - ss->state; ss->state = DCE2_PAF_SMB_STATES__0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Setting flush point: %u\n", *fp)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return PAF_FLUSH; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Invalid NetBIOS header - " "entering junk data states.\n")); ss->state++; break; case DCE2_PAF_SMB_STATES__7: DCE2_SMB_PAF_SHIFT(ss->nb_hdr, data[n]); if (!DCE2_PafSmbIsValidNetbiosHdr((uint32_t)(ss->nb_hdr >> 32), true)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Invalid NetBIOS header - " "staying in State 7.\n")); break; } if (((uint32_t)ss->nb_hdr != DCE2_SMB_ID) && ((uint32_t)ss->nb_hdr != DCE2_SMB2_ID)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Invalid SMB ID - " "staying in State 7.\n")); break; } nb_hdr = htonl((uint32_t)(ss->nb_hdr >> 32)); nb_len = NbssLen((const NbssHdr *)&nb_hdr); *fp = (nb_len + sizeof(NbssHdr) + n) - ss->state; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Setting flush point: %u\n", *fp)); ss->state = DCE2_PAF_SMB_STATES__0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return PAF_FLUSH; default: DCE2_SMB_PAF_SHIFT(ss->nb_hdr, data[n]); ss->state++; break; } n++; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return ps; } /********************************************************************* * Function: DCE2_TcpPaf() * * Purpose: The DCE/RPC over TCP PAF callback. * Inspects a byte at a time changing state. At state 4 * gets byte order of PDU. At states 8 and 9 gets * fragment length and sets flush point if no more data. * Otherwise accumulates flush points because there can * be multiple PDUs in a single TCP segment (evasion case). * * Arguments: * void * - stream5 session pointer * void ** - TCP state tracking structure * const uint8_t * - payload data to inspect * uint32_t - length of payload data * uint32_t - flags to check whether client or server * uint32_t * - pointer to set flush point * * Returns: * PAF_Status - PAF_FLUSH if flush point found, PAF_SEARCH otherwise * *********************************************************************/ PAF_Status DCE2_TcpPaf(void *ssn, void **user, const uint8_t *data, uint32_t len, uint32_t flags, uint32_t *fp) { DCE2_PafTcpState *ds = *(DCE2_PafTcpState **)user; uint32_t n = 0; int start_state; PAF_Status ps = PAF_SEARCH; uint32_t tmp_fp = 0; DCE2_SsnData *sd = (DCE2_SsnData *)_dpd.streamAPI->get_application_data(ssn, PP_DCE2); int num_requests = 0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_START_MSG)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "TCP: %u bytes of data\n", len)); DCE2_DEBUG_CODE(DCE2_DEBUG__PAF, printf("Session pointer: %p\n", _dpd.streamAPI->get_application_data(ssn, PP_DCE2));) #ifdef DEBUG_MSGS if (flags & FLAG_FROM_CLIENT) DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Packet from Client\n")); else DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Packet from Server\n")); #endif if (DCE2_PafAbort(ssn, flags)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return PAF_ABORT; } if (sd == NULL) { // Need packet to see if it's an autodetect port then do an autodetect // if autodetect port and not autodetected // return PAF_ABORT bool autodetected = false; #ifdef TARGET_BASED if (_dpd.isAdaptiveConfigured(_dpd.getRuntimePolicy())) { int16_t proto_id = _dpd.streamAPI->get_application_protocol_id(ssn); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "No session data - checking adaptive " "to see if it's DCE/RPC.\n")); if (proto_id == dce2_proto_ids.dcerpc) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Adaptive says it's " "DCE/RPC - no need to autodetect\n")); autodetected = true; } else if (proto_id != 0) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Adaptive says it's " "not DCE/RPC - aborting\n")); return PAF_ABORT; } } if (!autodetected) { #endif DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "No session data - autodetecting\n")); if (len >= sizeof(DceRpcCoHdr)) { DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)data; if ((DceRpcCoVersMaj(co_hdr) == DCERPC_PROTO_MAJOR_VERS__5) && (DceRpcCoVersMin(co_hdr) == DCERPC_PROTO_MINOR_VERS__0) && (((flags & FLAG_FROM_CLIENT) && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND) || ((flags & FLAG_FROM_SERVER) && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK)) && (DceRpcCoFragLen(co_hdr) >= sizeof(DceRpcCoHdr))) { autodetected = true; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Autodetected!\n")); } } else if ((*data == DCERPC_PROTO_MAJOR_VERS__5) && (flags & FLAG_FROM_CLIENT)) { autodetected = true; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Autodetected!\n")); } #ifdef TARGET_BASED } #endif if (!autodetected) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Couldn't autodetect - aborting\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return PAF_ABORT; } } if (ds == NULL) { // beware - we allocate here but s5 calls free() directly // so no pointers allowed ds = calloc(1, sizeof(DCE2_PafTcpState)); if (ds == NULL) return PAF_ABORT; *user = ds; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Start state: %u\n", ds->state)); start_state = (uint8_t)ds->state; // determines how many bytes already looked at while (n < len) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, " State %d : 0x%02x", ds->state, data[n])); #ifdef DEBUG_MSGS if (isprint(data[n])) DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, " '%c'\n", data[n])); else DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "\n")); #endif switch (ds->state) { case DCE2_PAF_TCP_STATES__4: // Get byte order ds->byte_order = DceRpcByteOrder(data[n]); ds->state++; #ifdef DEBUG_MSGS if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Byte order: Little endian\n")); else DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Byte order: Big endian\n")); #endif break; case DCE2_PAF_TCP_STATES__8: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "First byte of fragment length\n")); if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) ds->frag_len = data[n]; else ds->frag_len = data[n] << 8; ds->state++; break; case DCE2_PAF_TCP_STATES__9: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Second byte of fragment length\n")); if (ds->byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) ds->frag_len |= data[n] << 8; else ds->frag_len |= data[n]; /* If we get a bad frag length abort */ if (ds->frag_len < sizeof(DceRpcCoHdr)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return PAF_ABORT; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Fragment length: %u\n", ds->frag_len)); /* Increment n here so we can continue */ n += ds->frag_len - (uint8_t)ds->state; num_requests++; /* Might have multiple PDUs in one segment. If the last PDU is partial, * flush just before it */ if ((num_requests == 1) || (n <= len)) tmp_fp += ds->frag_len; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Requests: %u\n", num_requests)); ds->state = DCE2_PAF_TCP_STATES__0; continue; // we incremented n already default: ds->state++; break; } n++; } if (tmp_fp != 0) { *fp = tmp_fp - start_state; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "Setting flush point: %u\n", *fp)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return PAF_FLUSH; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__PAF, "%s\n", DCE2_DEBUG__PAF_END_MSG)); return ps; } /********************************************************************* * Function: DCE2_PafRegisterPort() * Function: DCE2_PafRegisterService() * * Purpose: Registers callbacks for interested ports and services. * SMB and TCP ports are mutually exclusive so only one or * the other will be registered for any given port. * * Arguments: * uint16_t - port or service to register * tSfPolicyId - the policy to register for * DCE2_TransType - the type of DCE/RPC transport to register for. * * Returns: * int - 0 for success. * *********************************************************************/ int DCE2_PafRegisterPort (struct _SnortConfig *sc, uint16_t port, tSfPolicyId pid, DCE2_TransType trans) { if (!_dpd.isPafEnabled()) return 0; switch (trans) { case DCE2_TRANS_TYPE__SMB: _dpd.streamAPI->register_paf_port(sc, pid, port, 0, DCE2_SmbPaf, true); _dpd.streamAPI->register_paf_port(sc, pid, port, 1, DCE2_SmbPaf, true); break; case DCE2_TRANS_TYPE__TCP: _dpd.streamAPI->register_paf_port(sc, pid, port, 0, DCE2_TcpPaf, true); _dpd.streamAPI->register_paf_port(sc, pid, port, 1, DCE2_TcpPaf, true); break; default: DCE2_Die("Invalid transport type sent to paf registration function"); break; } return 0; } #ifdef TARGET_BASED int DCE2_PafRegisterService (struct _SnortConfig *sc, uint16_t app_id, tSfPolicyId pid, DCE2_TransType trans) { if (!_dpd.isPafEnabled()) return 0; switch (trans) { case DCE2_TRANS_TYPE__SMB: _dpd.streamAPI->register_paf_service(sc, pid, app_id, 0, DCE2_SmbPaf, true); _dpd.streamAPI->register_paf_service(sc, pid, app_id, 1, DCE2_SmbPaf, true); break; case DCE2_TRANS_TYPE__TCP: _dpd.streamAPI->register_paf_service(sc, pid, app_id, 0, DCE2_TcpPaf, true); _dpd.streamAPI->register_paf_service(sc, pid, app_id, 1, DCE2_TcpPaf, true); break; default: DCE2_Die("Invalid transport type sent to paf registration function"); break; } return 0; } #endif snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_http.h0000644000000000000000000001360612260565732020431 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides session handling of an RPC over HTTP transport. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _DCE2_HTTP_H_ #define _DCE2_HTTP_H_ #include "dce2_session.h" #include "dce2_utils.h" #include "dce2_co.h" #include "dce2_tcp.h" #include "sf_types.h" #include "sf_snort_packet.h" /******************************************************************** * Macros ********************************************************************/ #define DCE2_HTTP_PROXY__RPC_CONNECT_STR "RPC_CONNECT" #define DCE2_HTTP_SERVER__RPC_VERS_STR "ncacn_http/1.0" /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_HttpState { DCE2_HTTP_STATE__NONE, DCE2_HTTP_STATE__INIT_CLIENT, DCE2_HTTP_STATE__INIT_SERVER, DCE2_HTTP_STATE__RPC_DATA } DCE2_HttpState; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_HttpSsnData { DCE2_SsnData sd; DCE2_HttpState state; DCE2_CoTracker co_tracker; } DCE2_HttpSsnData; /******************************************************************** * Inline function prototypes ********************************************************************/ static inline DCE2_TransType DCE2_HttpAutodetectProxy(const SFSnortPacket *); static inline DCE2_TransType DCE2_HttpAutodetectServer(const SFSnortPacket *); static inline int DCE2_HttpDecode(const SFSnortPacket *); /******************************************************************** * Public function prototypes ********************************************************************/ DCE2_HttpSsnData * DCE2_HttpProxySsnInit(void); DCE2_HttpSsnData * DCE2_HttpServerSsnInit(void); void DCE2_HttpProcessProxy(DCE2_HttpSsnData *); void DCE2_HttpProcessServer(DCE2_HttpSsnData *); void DCE2_HttpDataFree(DCE2_HttpSsnData *); void DCE2_HttpSsnFree(void *); /******************************************************************** * Function: DCE2_HttpAutodetectProxy() * * Tries to autodetect an RPC over HTTP proxy. Looks for session * setup strings. * * Arguments: * const SFSnortPacket * * Pointer to the packet going through the system. * * Returns: * DCE2_TransType * DCE2_TRANS_TYPE__HTTP_PROXY if a proxy is autodetected. * DCE2_TRANS_TYPE__NONE if a proxy is not autodetected. * ********************************************************************/ static inline DCE2_TransType DCE2_HttpAutodetectProxy(const SFSnortPacket *p) { const char *buf = NULL; unsigned buf_len = 0; if (DCE2_SsnFromServer(p)) return DCE2_TRANS_TYPE__NONE; /* Use the http decode buffer if possible */ if (DCE2_HttpDecode(p)) { buf = (char*)_dpd.getHttpBuffer(HTTP_BUFFER_METHOD, &buf_len); } if (buf == NULL) { buf = (char *)p->payload; buf_len = p->payload_size; } if (buf_len >= strlen(DCE2_HTTP_PROXY__RPC_CONNECT_STR)) { if (strncmp(buf, DCE2_HTTP_PROXY__RPC_CONNECT_STR, strlen(DCE2_HTTP_PROXY__RPC_CONNECT_STR)) == 0) return DCE2_TRANS_TYPE__HTTP_PROXY; } return DCE2_TRANS_TYPE__NONE; } /******************************************************************** * Function: DCE2_HttpAutodetectServer() * * Tries to autodetect an RPC over HTTP server. Looks for session * setup strings. * * Arguments: * const SFSnortPacket * * Pointer to the packet going through the system. * * Returns: * DCE2_TransType * DCE2_TRANS_TYPE__HTTP_SERVER if a server is autodetected. * DCE2_TRANS_TYPE__NONE if a server is not autodetected. * ********************************************************************/ static inline DCE2_TransType DCE2_HttpAutodetectServer(const SFSnortPacket *p) { if (DCE2_SsnFromClient(p)) return DCE2_TRANS_TYPE__NONE; if (p->payload_size >= strlen(DCE2_HTTP_SERVER__RPC_VERS_STR)) { if (strncmp((char *)p->payload, DCE2_HTTP_SERVER__RPC_VERS_STR, strlen(DCE2_HTTP_SERVER__RPC_VERS_STR)) == 0) { return DCE2_TRANS_TYPE__HTTP_SERVER; } } return DCE2_TRANS_TYPE__NONE; } /******************************************************************** * Function: DCE2_HttpDecode() * * Returns whether or not this packet was decoded by http_inspect. * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: * int * Non-zero if the packet was http_inspect decoded * Zero if the packet was not http_inspect decoded * ********************************************************************/ static inline int DCE2_HttpDecode(const SFSnortPacket *p) { return p->flags & FLAG_HTTP_DECODE; } #endif /* _DCE2_HTTP_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_http.c0000644000000000000000000001727012260565732020425 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides session handling of an RPC over HTTP transport. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_http.h" #include "snort_dce2.h" #include "dce2_co.h" #include "dce2_memory.h" #include "dce2_stats.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" /******************************************************************** * Private function prototypes ********************************************************************/ static DCE2_HttpSsnData * DCE2_HttpSsnInit(void); static void DCE2_HttpProcess(DCE2_HttpSsnData *); /******************************************************************** * Function: DCE2_HttpSsnInit() * * Creates and initializes an rpc over http session data structure. * * Arguments: None * * Returns: * DCE2_HttpSsnData * * Valid pointer to an rpc over http session data structure. * NULL if unable to allocate memory. * ********************************************************************/ static DCE2_HttpSsnData * DCE2_HttpSsnInit(void) { DCE2_HttpSsnData *hsd = DCE2_Alloc(sizeof(DCE2_HttpSsnData), DCE2_MEM_TYPE__HTTP_SSN); if (hsd == NULL) return NULL; hsd->state = DCE2_HTTP_STATE__NONE; DCE2_CoInitTracker(&hsd->co_tracker); DCE2_ResetRopts(&hsd->sd.ropts); return hsd; } /******************************************************************** * Function: DCE2_HttpProxySsnInit() * * Wrapper around main session data initialization. Adds * statistical info for a proxy specific rpc over http session. * * Arguments: None * * Returns: * DCE2_HttpSsnData * * Valid pointer to an rpc over http session data structure. * NULL if unable to allocate memory. * ********************************************************************/ DCE2_HttpSsnData * DCE2_HttpProxySsnInit(void) { DCE2_HttpSsnData *hsd = DCE2_HttpSsnInit(); if (hsd == NULL) return NULL; dce2_stats.http_proxy_sessions++; return hsd; } /******************************************************************** * Function: DCE2_HttpServerSsnInit() * * Wrapper around main session data initialization. Adds * statistical info for a server specific rpc over http session. * * Arguments: None * * Returns: * DCE2_HttpSsnData * * Valid pointer to an rpc over http session data structure. * NULL if unable to allocate memory. * ********************************************************************/ DCE2_HttpSsnData * DCE2_HttpServerSsnInit(void) { DCE2_HttpSsnData *hsd = DCE2_HttpSsnInit(); if (hsd == NULL) return NULL; dce2_stats.http_server_sessions++; return hsd; } /******************************************************************** * Function: DCE2_HttpProcessProxy() * * Wrapper arount main processing point for an RPC over HTTP * session. Checks and sets session setup state for a proxy. * * Arguments: * DCE2_HttpSsnData * * Pointer to an RPC over HTTP session data structure. * * Returns: None * ********************************************************************/ void DCE2_HttpProcessProxy(DCE2_HttpSsnData *hsd) { const SFSnortPacket *p = hsd->sd.wire_pkt; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Processing RPC over HTTP proxy packet.\n")); dce2_stats.http_proxy_pkts++; if (hsd->state == DCE2_HTTP_STATE__NONE) { if (DCE2_SsnFromClient(p)) hsd->state = DCE2_HTTP_STATE__INIT_CLIENT; } DCE2_HttpProcess(hsd); } /******************************************************************** * Function: DCE2_HttpProcessServer() * * Wrapper arount main processing point for an RPC over HTTP * session. Checks and sets session setup state for a server. * * Arguments: * DCE2_HttpSsnData * * Pointer to an RPC over HTTP session data structure. * * Returns: None * ********************************************************************/ void DCE2_HttpProcessServer(DCE2_HttpSsnData *hsd) { const SFSnortPacket *p = hsd->sd.wire_pkt; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Processing RPC over HTTP server packet.\n")); dce2_stats.http_server_pkts++; if (hsd->state == DCE2_HTTP_STATE__NONE) { if (DCE2_SsnFromServer(p)) hsd->state = DCE2_HTTP_STATE__INIT_SERVER; } DCE2_HttpProcess(hsd); } /******************************************************************** * Function: DCE2_HttpProcess() * * Main processing point for an RPC over HTTP session. * * Arguments: * DCE2_HttpSsnData * * Pointer to an RPC over HTTP session data structure. * * Returns: None * ********************************************************************/ static void DCE2_HttpProcess(DCE2_HttpSsnData *hsd) { const SFSnortPacket *p = hsd->sd.wire_pkt; const uint8_t *data_ptr = p->payload; uint16_t data_len = p->payload_size; switch (hsd->state) { case DCE2_HTTP_STATE__INIT_CLIENT: hsd->state = DCE2_HTTP_STATE__INIT_SERVER; break; case DCE2_HTTP_STATE__INIT_SERVER: /* Don't really need to look at server response, since if the client * RPC_CONNECT request was bad, the TCP session is terminated by * the server */ hsd->state = DCE2_HTTP_STATE__RPC_DATA; break; case DCE2_HTTP_STATE__RPC_DATA: DCE2_CoProcess(&hsd->sd, &hsd->co_tracker, data_ptr, data_len); break; default: break; } } /******************************************************************** * Function: DCE2_HttpDataFree() * * Frees dynamically allocated data within the RPC over HTTP * session data structure. * * Arguments: * DCE2_HttpSsnData * * Pointer to an RPC over HTTP session data structure. * * Returns: None * ********************************************************************/ void DCE2_HttpDataFree(DCE2_HttpSsnData *hsd) { if (hsd == NULL) return; DCE2_CoCleanTracker(&hsd->co_tracker); } /******************************************************************** * Function: DCE2_HttpSsnFree() * * Frees the session data structure and any dynamically allocated * data within it. * * Arguments: * void * * Pointer to an RPC over HTTP session data structure. * * Returns: None * ********************************************************************/ void DCE2_HttpSsnFree(void *ssn) { DCE2_HttpSsnData *hsd = (DCE2_HttpSsnData *)ssn; if (hsd == NULL) return; DCE2_HttpDataFree(hsd); DCE2_Free((void *)hsd, sizeof(DCE2_HttpSsnData), DCE2_MEM_TYPE__HTTP_SSN); } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_cl.h0000644000000000000000000000412212260565732020041 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _DCE2_CL_H_ #define _DCE2_CL_H_ #include "dce2_list.h" #include "dce2_session.h" #include "sf_types.h" /******************************************************************** * Macros ********************************************************************/ #define DCE2_MOCK_HDR_LEN__CL (sizeof(DceRpcClHdr)) /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_ClTracker { DCE2_List *act_trackers; /* List of activity trackers */ } DCE2_ClTracker; /******************************************************************** * Public function prototypes ********************************************************************/ void DCE2_ClInitRdata(uint8_t *); void DCE2_ClProcess(DCE2_SsnData *, DCE2_ClTracker *); void DCE2_ClCleanTracker(DCE2_ClTracker *); #endif /* _DCE2_CL_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_cl.c0000644000000000000000000010156212260565732020042 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Module for handling connectionless DCE/RPC processing. Provides * functionality for tracking sub-sessions or activities within a * connectionless conversation and for tracking and reassembling fragments * within each activity. Also sets appropriate data for use with * preprocessor rule options. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_dce2.h" #include "dce2_cl.h" #include "snort_dce2.h" #include "dce2_list.h" #include "dce2_memory.h" #include "dce2_utils.h" #include "dce2_stats.h" #include "dce2_session.h" #include "dce2_event.h" #include "dcerpc.h" #include "sf_types.h" #include "snort_debug.h" #include "profiler.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" /******************************************************************** * Global variables ********************************************************************/ static uint8_t dce2_cl_rbuf[IP_MAXPKT]; /******************************************************************** * Macros ********************************************************************/ #define DCE2_CL__MAX_SEQ_NUM UINT32_MAX /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_ClFragNode { uint32_t frag_number; uint16_t frag_len; uint8_t *frag_data; } DCE2_ClFragNode; typedef struct _DCE2_ClFragTracker { Uuid iface; /* only set on first fragment received */ uint32_t iface_vers; /* only set on first fragment received */ int opnum; /* set to that of first fragment, i.e fragment number == 0. * initialize to a sentinel */ int data_byte_order; /* set to that of first fragment, i.e fragment number == 0. * initialize to sentinel */ DCE2_List *frags; /* sorted by fragment number */ int num_expected_frags; /* set when we get last frag */ } DCE2_ClFragTracker; typedef struct _DCE2_ClActTracker { Uuid act; uint32_t seq_num; uint8_t seq_num_invalid; DCE2_ClFragTracker frag_tracker; #if 0 /* Not currently used. These are related to getting a sequence number that * is at the end of the sequence number space */ uint32_t last_pkt_sec; uint8_t no_frags; uint8_t no_requests; #endif } DCE2_ClActTracker; /******************************************************************** * Private function prototypes ********************************************************************/ static DCE2_Ret DCE2_ClHdrChecks(DCE2_SsnData *, const DceRpcClHdr *); static DCE2_ClActTracker * DCE2_ClGetActTracker(DCE2_ClTracker *, DceRpcClHdr *); static DCE2_ClActTracker * DCE2_ClInsertActTracker(DCE2_ClTracker *, DceRpcClHdr *); static void DCE2_ClRequest(DCE2_SsnData *, DCE2_ClActTracker *, DceRpcClHdr *, const uint8_t *, uint16_t); static void DCE2_ClHandleFrag(DCE2_SsnData *, DCE2_ClActTracker *, DceRpcClHdr *, const uint8_t *, uint16_t); static void DCE2_ClFragReassemble(DCE2_SsnData*, DCE2_ClActTracker *, const DceRpcClHdr *); static void DCE2_ClResetFragTracker(DCE2_ClFragTracker *); static inline void DCE2_ClSetRdata(DCE2_ClActTracker *, const DceRpcClHdr *, uint8_t *, uint16_t); /* Callbacks */ static int DCE2_ClFragCompare(const void *, const void *); static void DCE2_ClActDataFree(void *); static void DCE2_ClActKeyFree(void *); static void DCE2_ClFragDataFree(void *); /******************************************************************** * Function: DCE2_ClInitRdata() * * Initializes static values in the global CL data reassembly * buffer. These values should never need to be changed after * this initialization. * * Arguments: * uint8_t * * Pointer to the data reassembly buffer. * * Returns: None * ********************************************************************/ void DCE2_ClInitRdata(uint8_t *buf) { DceRpcClHdr *cl_hdr = (DceRpcClHdr *)buf; /* Set some relevant fields. These should never get reset */ cl_hdr->rpc_vers = DCERPC_PROTO_MAJOR_VERS__4; cl_hdr->ptype = DCERPC_PDU_TYPE__REQUEST; cl_hdr->drep[0] = 0x10; /* Little endian */ } /******************************************************************** * Function: DCE2_ClSetRdata() * * Sets relevant data fields in the reassembly packet. * * Arguments: * DCE2_ClActTracker * * Pointer to the activity tracker associated with the * reassemble packet. * DceRpcClHdr * * Pointer to the connectionless header in the wire packet. * uint8_t * * Pointer to the start of the reassembly buffer. * uint16_t * The length of the stub data. * * Returns: None * ********************************************************************/ static inline void DCE2_ClSetRdata(DCE2_ClActTracker *at, const DceRpcClHdr *pkt_cl_hdr, uint8_t *cl_ptr, uint16_t stub_len) { DCE2_ClFragTracker *ft = &at->frag_tracker; DceRpcClHdr *cl_hdr = (DceRpcClHdr *)cl_ptr; uint16_t opnum = (ft->opnum != DCE2_SENTINEL) ? (uint16_t)ft->opnum : DceRpcClOpnum(pkt_cl_hdr); cl_hdr->len = DceRpcHtons(&stub_len, DCERPC_BO_FLAG__LITTLE_ENDIAN); DCE2_CopyUuid(&cl_hdr->object, &pkt_cl_hdr->object, DceRpcClByteOrder(cl_hdr)); DCE2_CopyUuid(&cl_hdr->if_id, &ft->iface, DCERPC_BO_FLAG__LITTLE_ENDIAN); DCE2_CopyUuid(&cl_hdr->act_id, &at->act, DCERPC_BO_FLAG__LITTLE_ENDIAN); cl_hdr->if_vers = DceRpcHtonl(&ft->iface_vers, DCERPC_BO_FLAG__LITTLE_ENDIAN); cl_hdr->opnum = DceRpcHtons(&opnum, DCERPC_BO_FLAG__LITTLE_ENDIAN); } /******************************************************************** * Function: DCE2_ClProcess() * * Main entry point for connectionless DCE/RPC processing. Gets * the activity tracker associated with this session and passes * along to client or server handling. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_ClTracker * * Pointer to the connectionless tracker structure. * * Returns: None * ********************************************************************/ void DCE2_ClProcess(DCE2_SsnData *sd, DCE2_ClTracker *clt) { DceRpcClHdr *cl_hdr; DCE2_ClActTracker *at; const uint8_t *data_ptr = sd->wire_pkt->payload; uint16_t data_len = sd->wire_pkt->payload_size; PROFILE_VARS; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Cl processing ...\n")); dce2_stats.cl_pkts++; if (data_len < sizeof(DceRpcClHdr)) { if (!DCE2_SsnAutodetected(sd)) DCE2_Alert(sd, DCE2_EVENT__CL_DATA_LT_HDR, data_len, sizeof(DceRpcClHdr)); return; } cl_hdr = (DceRpcClHdr *)data_ptr; DCE2_MOVE(data_ptr, data_len, sizeof(DceRpcClHdr)); if (DCE2_ClHdrChecks(sd, cl_hdr) != DCE2_RET__SUCCESS) return; PREPROC_PROFILE_START(dce2_pstat_cl_acts); at = DCE2_ClGetActTracker(clt, cl_hdr); PREPROC_PROFILE_END(dce2_pstat_cl_acts); if (at == NULL) return; if (DCE2_SsnFromClient(sd->wire_pkt)) { switch (DceRpcClPduType(cl_hdr)) { case DCERPC_PDU_TYPE__REQUEST: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Request\n")); dce2_stats.cl_request++; DCE2_ClRequest(sd, at, cl_hdr, data_ptr, data_len); break; case DCERPC_PDU_TYPE__ACK: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Ack\n")); dce2_stats.cl_ack++; break; case DCERPC_PDU_TYPE__CL_CANCEL: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Cancel\n")); dce2_stats.cl_cancel++; break; case DCERPC_PDU_TYPE__FACK: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Fack\n")); dce2_stats.cl_cli_fack++; break; case DCERPC_PDU_TYPE__PING: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Ping\n")); dce2_stats.cl_ping++; break; case DCERPC_PDU_TYPE__RESPONSE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Response from client. Changing stream direction.")); _dpd.streamAPI->update_direction(sd->wire_pkt->stream_session_ptr, SSN_DIR_FROM_RESPONDER, GET_SRC_IP(((SFSnortPacket *)sd->wire_pkt)), sd->wire_pkt->src_port); break; default: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Other pdu type\n")); dce2_stats.cl_other_req++; break; } } else { switch (DceRpcClPduType(cl_hdr)) { case DCERPC_PDU_TYPE__RESPONSE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Response\n")); dce2_stats.cl_response++; break; case DCERPC_PDU_TYPE__REJECT: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Reject\n")); dce2_stats.cl_reject++; if (DceRpcClSeqNum(cl_hdr) == at->seq_num) { DCE2_ClResetFragTracker(&at->frag_tracker); at->seq_num_invalid = 1; } break; case DCERPC_PDU_TYPE__CANCEL_ACK: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Cancel Ack\n")); dce2_stats.cl_cancel_ack++; break; case DCERPC_PDU_TYPE__FACK: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Fack\n")); dce2_stats.cl_srv_fack++; break; case DCERPC_PDU_TYPE__FAULT: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Fault\n")); dce2_stats.cl_fault++; break; case DCERPC_PDU_TYPE__NOCALL: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "No call\n")); dce2_stats.cl_nocall++; break; case DCERPC_PDU_TYPE__WORKING: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Working\n")); dce2_stats.cl_working++; break; default: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Other pdu type\n")); dce2_stats.cl_other_resp++; break; } } } /******************************************************************** * Function: DCE2_ClHdrChecks() * * Checks to make sure header fields are sane. If they aren't, * alert on the header anomaly. If we've autodetected the session, * however, don't alert, but set a header anomaly flag, so we can * re-autodetect on the next go around. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * * Returns: * DCE2_Ret * DCE2_RET__ERROR * We should not continue to inspect. * DCE2_RET__SUCCESS * Continue inspection. * ********************************************************************/ static DCE2_Ret DCE2_ClHdrChecks(DCE2_SsnData *sd, const DceRpcClHdr *cl_hdr) { if (DceRpcClRpcVers(cl_hdr) != DCERPC_PROTO_MAJOR_VERS__4) { /* If we autodetected the session, we probably guessed wrong */ if (!DCE2_SsnAutodetected(sd)) DCE2_Alert(sd, DCE2_EVENT__CL_BAD_MAJ_VERSION, DceRpcClRpcVers(cl_hdr)); return DCE2_RET__ERROR; } if (DceRpcClPduType(cl_hdr) >= DCERPC_PDU_TYPE__MAX) { if (!DCE2_SsnAutodetected(sd)) DCE2_Alert(sd, DCE2_EVENT__CL_BAD_PDU_TYPE, DceRpcClPduType(cl_hdr)); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ClGetActTracker() * * Searches for activity tracker in list using activity UUID in * packet. If the activity tracker list is NULL, a new one is * created. If the activity tracker is not found, it is inserted * into the list. * * Arguments: * DCE2_ClTracker * * Pointer to the connectionless tracker. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * * Returns: * DCE2_ClActTracker * * A valid pointer to an activity tracker on success. * NULL on error. * ********************************************************************/ static DCE2_ClActTracker * DCE2_ClGetActTracker(DCE2_ClTracker *clt, DceRpcClHdr *cl_hdr) { DCE2_ClActTracker *at = NULL; /* Try to find a currently active activity tracker */ if (clt->act_trackers != NULL) { Uuid uuid; DCE2_CopyUuid(&uuid, &cl_hdr->act_id, DceRpcClByteOrder(cl_hdr)); at = DCE2_ListFind(clt->act_trackers, (void *)&uuid); } else { /* Create a new activity tracker list */ clt->act_trackers = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_UuidCompare, DCE2_ClActDataFree, DCE2_ClActKeyFree, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__CL_ACT); if (clt->act_trackers == NULL) return NULL; } /* Didn't find a currently active activity tracker */ if (at == NULL) { /* Insert a new activity tracker */ at = DCE2_ClInsertActTracker(clt, cl_hdr); if (at == NULL) return NULL; } return at; } /******************************************************************** * Function: DCE2_ClInsertActTracker() * * Creates and inserts a new activity tracker into a list. * * Arguments: * DCE2_ClTracker * * Pointer to connectionless tracker. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * * Returns: * DCE2_ClActTracker * * A valid pointer to an activity tracker on success. * NULL on error. * ********************************************************************/ static DCE2_ClActTracker * DCE2_ClInsertActTracker(DCE2_ClTracker *clt, DceRpcClHdr *cl_hdr) { Uuid *uuid = (Uuid *)DCE2_Alloc(sizeof(Uuid), DCE2_MEM_TYPE__CL_ACT); DCE2_ClActTracker *at; DCE2_Ret status; if (uuid == NULL) return NULL; at = (DCE2_ClActTracker *)DCE2_Alloc(sizeof(DCE2_ClActTracker), DCE2_MEM_TYPE__CL_ACT); if (at == NULL) { DCE2_Free((void *)uuid, sizeof(Uuid), DCE2_MEM_TYPE__CL_ACT); return NULL; } DCE2_CopyUuid(uuid, &cl_hdr->act_id, DceRpcClByteOrder(cl_hdr)); DCE2_CopyUuid(&at->act, &cl_hdr->act_id, DceRpcClByteOrder(cl_hdr)); status = DCE2_ListInsert(clt->act_trackers, (void *)uuid, (void *)at); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)uuid, sizeof(Uuid), DCE2_MEM_TYPE__CL_ACT); DCE2_Free((void *)at, sizeof(DCE2_ClActTracker), DCE2_MEM_TYPE__CL_ACT); return NULL; } return at; } /******************************************************************** * Function: DCE2_ClRequest() * * Handles a client request. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_ClActTracker * * Pointer to the connectionless activity tracker. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * const uint8_t * * Pointer to current position in the packet payload. * uint16_t * Length of packet payload left from current pointer * position. * * Returns: None * ********************************************************************/ static void DCE2_ClRequest(DCE2_SsnData *sd, DCE2_ClActTracker *at, DceRpcClHdr *cl_hdr, const uint8_t *data_ptr, uint16_t data_len) { uint32_t seq_num = DceRpcClSeqNum(cl_hdr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CL, "Processing Request ...\n")); if (seq_num > at->seq_num) { /* This is the normal case where the sequence number is incremented * for each request. Set the new sequence number and mark it valid. */ at->seq_num = seq_num; at->seq_num_invalid = 0; /* If there are any fragments, the new sequence number invalidates * all of the frags that might be currently stored. */ DCE2_ClResetFragTracker(&at->frag_tracker); } else if ((seq_num < at->seq_num) || at->seq_num_invalid) { #if 0 /* If we get a seqence number less than what we're at, the * server won't look at it. If we get the same sequence number, * but we've already processed a previous request, it's bad. * Fragments will have the same sequence number, but we won't * mark the seq number invalid until we've gotten all of them. */ /* Comment for now since we're not able to detect retransmits */ DCE2_Alert(sd, DCE2_EVENT__CL_BAD_SEQ_NUM, dce2_pdu_types[DceRpcClPduType(cl_hdr)]); #endif return; } DCE2_ResetRopts(&sd->ropts); if (DceRpcClFrag(cl_hdr)) /* It's a frag */ { dce2_stats.cl_fragments++; if (DCE2_GcDceDefrag()) { DCE2_ClHandleFrag(sd, at, cl_hdr, data_ptr, data_len); return; } } else /* It's a full request */ { if ((at->frag_tracker.frags != NULL) && !DCE2_ListIsEmpty(at->frag_tracker.frags)) { /* If we get a full request, i.e. not a frag, any frags * we have collected are invalidated */ DCE2_ClResetFragTracker(&at->frag_tracker); } else if (seq_num != DCE2_CL__MAX_SEQ_NUM) { /* This sequence number is now invalid. 0xffffffff is the end of * the sequence number space and can be reused */ at->seq_num_invalid = 1; } else { /* Got the last sequence number in the sequence number space */ dce2_stats.cl_max_seqnum++; } } /* Cache relevant values for rule option processing */ sd->ropts.first_frag = DceRpcClFirstFrag(cl_hdr); DCE2_CopyUuid(&sd->ropts.iface, DceRpcClIface(cl_hdr), DceRpcClByteOrder(cl_hdr)); sd->ropts.iface_vers = DceRpcClIfaceVers(cl_hdr); sd->ropts.hdr_byte_order = DceRpcClByteOrder(cl_hdr); sd->ropts.data_byte_order = DceRpcClByteOrder(cl_hdr); sd->ropts.opnum = DceRpcClOpnum(cl_hdr); sd->ropts.stub_data = (uint8_t *)cl_hdr + sizeof(DceRpcClHdr); DCE2_Detect(sd); } /******************************************************************** * Function: DCE2_ClHandleFrag() * * Handles connectionless fragments. Creates a new fragment list * if necessary and inserts fragment into list. Sets rule option * values based on the fragment. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_ClActTracker * * Pointer to the connectionless activity tracker. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * const uint8_t * * Pointer to current position in the packet payload. * uint16_t * Length of packet payload left from current pointer * position. * * Returns: None * ********************************************************************/ static void DCE2_ClHandleFrag(DCE2_SsnData *sd, DCE2_ClActTracker *at, DceRpcClHdr *cl_hdr, const uint8_t *data_ptr, uint16_t data_len) { DCE2_ClFragTracker *ft = &at->frag_tracker; DCE2_ClFragNode *fn; uint16_t frag_len; int status; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_cl_frag); /* If the frag length is less than data length there might be authentication * data that we don't want to include, otherwise just set to data len */ if (DceRpcClLen(cl_hdr) < data_len) frag_len = DceRpcClLen(cl_hdr); else frag_len = data_len; if (frag_len == 0) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); return; } if (frag_len > dce2_stats.cl_max_frag_size) dce2_stats.cl_max_frag_size = frag_len; if (DCE2_GcMaxFrag() && (frag_len > DCE2_GcMaxFragLen())) frag_len = DCE2_GcMaxFragLen(); if (ft->frags == NULL) { /* Create new list if we don't have one already */ ft->frags = DCE2_ListNew(DCE2_LIST_TYPE__SORTED, DCE2_ClFragCompare, DCE2_ClFragDataFree, NULL, DCE2_LIST_FLAG__NO_DUPS | DCE2_LIST_FLAG__INS_TAIL, DCE2_MEM_TYPE__CL_FRAG); if (ft->frags == NULL) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); return; } } else { /* If we already have a fragment in the list with the same fragment number, * that fragment will take precedence over this fragment and this fragment * will not be used by the server */ fn = (DCE2_ClFragNode *)DCE2_ListFind(ft->frags, (void *)(uintptr_t)DceRpcClFragNum(cl_hdr)); if (fn != NULL) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); return; } } /* Create a new frag node to insert into the list */ fn = (DCE2_ClFragNode *)DCE2_Alloc(sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); if (fn == NULL) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); DCE2_ClFragReassemble(sd, at, cl_hdr); return; } fn->frag_number = DceRpcClFragNum(cl_hdr); fn->frag_len = frag_len; /* Allocate space for the fragment data */ fn->frag_data = (uint8_t *)DCE2_Alloc(frag_len, DCE2_MEM_TYPE__CL_FRAG); if (fn->frag_data == NULL) { DCE2_Free((void *)fn, sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); PREPROC_PROFILE_END(dce2_pstat_cl_frag); DCE2_ClFragReassemble(sd, at, cl_hdr); return; } /* Copy the fragment data in the packet to the space just allocated */ status = DCE2_Memcpy(fn->frag_data, data_ptr, frag_len, fn->frag_data, fn->frag_data + frag_len); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)fn->frag_data, frag_len, DCE2_MEM_TYPE__CL_FRAG); DCE2_Free((void *)fn, sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); PREPROC_PROFILE_END(dce2_pstat_cl_frag); DCE2_ClFragReassemble(sd, at, cl_hdr); return; } if (DCE2_ListIsEmpty(ft->frags)) { /* If this is the first fragment we've received, set interface uuid */ DCE2_CopyUuid(&ft->iface, DceRpcClIface(cl_hdr), DceRpcClByteOrder(cl_hdr)); ft->iface_vers = DceRpcClIfaceVers(cl_hdr); } if (DceRpcClLastFrag(cl_hdr)) { /* Set number of expected frags on last frag */ ft->num_expected_frags = DceRpcClFragNum(cl_hdr) + 1; } else if (DceRpcClFirstFrag(cl_hdr)) { /* Set opum and byte order on first frag */ ft->opnum = DceRpcClOpnum(cl_hdr); ft->data_byte_order = DceRpcClByteOrder(cl_hdr); } /* Insert frag node into the list */ status = DCE2_ListInsert(ft->frags, (void *)(uintptr_t)fn->frag_number, (void *)fn); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)fn->frag_data, frag_len, DCE2_MEM_TYPE__CL_FRAG); DCE2_Free((void *)fn, sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); PREPROC_PROFILE_END(dce2_pstat_cl_frag); DCE2_ClFragReassemble(sd, at, cl_hdr); return; } /* Fragment number field in header is uint16_t */ if ((ft->num_expected_frags != DCE2_SENTINEL) && (uint16_t)ft->frags->num_nodes == (uint16_t)ft->num_expected_frags) { PREPROC_PROFILE_END(dce2_pstat_cl_frag); /* We got all of the frags - reassemble */ DCE2_ClFragReassemble(sd, at, cl_hdr); at->seq_num_invalid = 1; return; } PREPROC_PROFILE_END(dce2_pstat_cl_frag); /* Cache relevant values for rule option processing */ sd->ropts.first_frag = DceRpcClFirstFrag(cl_hdr); DCE2_CopyUuid(&sd->ropts.iface, &ft->iface, DCERPC_BO_FLAG__NONE); sd->ropts.iface_vers = ft->iface_vers; sd->ropts.hdr_byte_order = DceRpcClByteOrder(cl_hdr); if (ft->data_byte_order != DCE2_SENTINEL) sd->ropts.data_byte_order = ft->data_byte_order; else sd->ropts.data_byte_order = DceRpcClByteOrder(cl_hdr); if (ft->opnum != DCE2_SENTINEL) sd->ropts.opnum = ft->opnum; else sd->ropts.opnum = DceRpcClOpnum(cl_hdr); sd->ropts.stub_data = (uint8_t *)cl_hdr + sizeof(DceRpcClHdr); DCE2_Detect(sd); } /******************************************************************** * Function: DCE2_ClFragCompare() * * Callback to fragment list for sorting the nodes in the list * by fragment number. Values passed in are the fragment numbers. * * Arguments: * const void * * First fragment number to compare. * const void * * Second fragment number to compare. * * Returns: * int * 1 if first value is greater than second value * -1 if first value is less than second value * 0 if first value equals second value * ********************************************************************/ static int DCE2_ClFragCompare(const void *a, const void *b) { int x = (int)(uintptr_t)a; int y = (int)(uintptr_t)b; if (x > y) return 1; if (x < y) return -1; return 0; } /******************************************************************** * Function: DCE2_ClFragReassemble() * * Reassembles fragments into reassembly buffer and copies to * reassembly packet. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_ClActTracker * * Pointer to the connectionless activity tracker. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * * Returns: None * ********************************************************************/ static void DCE2_ClFragReassemble(DCE2_SsnData *sd, DCE2_ClActTracker *at, const DceRpcClHdr *cl_hdr) { DCE2_ClFragTracker *ft = &at->frag_tracker; DCE2_ClFragNode *fnode; uint8_t *rdata = dce2_cl_rbuf; uint16_t rlen = sizeof(dce2_cl_rbuf); uint32_t stub_len = 0; const uint8_t *stub_data = NULL; SFSnortPacket *rpkt = NULL; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_cl_reass); for (fnode = (DCE2_ClFragNode *)DCE2_ListFirst(ft->frags); fnode != NULL; fnode = (DCE2_ClFragNode *)DCE2_ListNext(ft->frags)) { if (fnode->frag_len > rlen) { DCE2_Log(DCE2_LOG_TYPE__WARN, "%s(%d) Size of fragments exceeds reassembly buffer size. " "Using as many fragments as will fit.", __FILE__, __LINE__); break; } if (DCE2_Memcpy(rdata, fnode->frag_data, fnode->frag_len, rdata, rdata + rlen) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into fragment " "reassembly buffer.", __FILE__, __LINE__); break; } DCE2_MOVE(rdata, rlen, fnode->frag_len); stub_len += fnode->frag_len; } switch (sd->trans) { case DCE2_TRANS_TYPE__UDP: rpkt = DCE2_GetRpkt(sd->wire_pkt, DCE2_RPKT_TYPE__UDP_CL_FRAG, dce2_cl_rbuf, stub_len); if (rpkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to create reassembly packet.", __FILE__, __LINE__); PREPROC_PROFILE_END(dce2_pstat_cl_reass); return; } DCE2_ClSetRdata(at, cl_hdr, (uint8_t *)rpkt->payload, (uint16_t)(rpkt->payload_size - DCE2_MOCK_HDR_LEN__CL)); stub_data = rpkt->payload + DCE2_MOCK_HDR_LEN__CL; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, sd->trans); return; } PREPROC_PROFILE_END(dce2_pstat_cl_reass); if (DCE2_PushPkt(rpkt) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to push packet onto packet stack.", __FILE__, __LINE__); return; } /* Cache relevant values for rule option processing */ sd->ropts.first_frag = 1; DCE2_CopyUuid(&sd->ropts.iface, &ft->iface, DCERPC_BO_FLAG__NONE); sd->ropts.iface_vers = ft->iface_vers; sd->ropts.hdr_byte_order = DceRpcClByteOrder(cl_hdr); if (ft->data_byte_order != DCE2_SENTINEL) sd->ropts.data_byte_order = ft->data_byte_order; else sd->ropts.data_byte_order = DceRpcClByteOrder(cl_hdr); if (ft->opnum != DCE2_SENTINEL) sd->ropts.opnum = ft->opnum; else sd->ropts.opnum = DceRpcClOpnum(cl_hdr); sd->ropts.stub_data = stub_data; DCE2_Detect(sd); DCE2_PopPkt(); dce2_stats.cl_frag_reassembled++; } /******************************************************************** * Function: DCE2_ClResetFragTracker() * * Destroys the fragment tracker's fragment list and resets opnum, * byte order and number of expected frags to a sentinel. * * Arguments: * DCE2_ClFragTracker * * Pointer to the fragment tracker to reset. * * Returns: None * ********************************************************************/ static void DCE2_ClResetFragTracker(DCE2_ClFragTracker *ft) { if (ft == NULL) return; if (ft->frags != NULL) { DCE2_ListDestroy(ft->frags); ft->frags = NULL; } ft->opnum = DCE2_SENTINEL; ft->data_byte_order = DCE2_SENTINEL; ft->num_expected_frags = DCE2_SENTINEL; } /******************************************************************** * Function: DCE2_ClCleanTracker() * * Destroys all the activity tracker list, which cleans out and * frees all data associated with each activity tracker in the * list. * * Arguments: * DCE2_ClTracker * * Pointer to connectionless tracker. * * Returns: None * ********************************************************************/ void DCE2_ClCleanTracker(DCE2_ClTracker *clt) { if (clt == NULL) return; /* Destroy activity trackers list - this will have the * effect of freeing everything inside of it */ DCE2_ListDestroy(clt->act_trackers); clt->act_trackers = NULL; } /******************************************************************** * Function: DCE2_ClActDataFree() * * Callback to activity tracker list for freeing activity trackers. * * Arguments: * void * * Activity tracker to free. * * Returns: None * ********************************************************************/ static void DCE2_ClActDataFree(void *data) { DCE2_ClActTracker *at = (DCE2_ClActTracker *)data; if (at == NULL) return; DCE2_ListDestroy(at->frag_tracker.frags); at->frag_tracker.frags = NULL; DCE2_Free((void *)at, sizeof(DCE2_ClActTracker), DCE2_MEM_TYPE__CL_ACT); } /******************************************************************** * Function: DCE2_ClActKeyFree() * * Callback to activity tracker list for freeing the key (this is * the activity UUID). Since key is dynamically allocated, we need * to free it. * * Arguments: * void * * The activity UUID to free. * * Returns: None * ********************************************************************/ static void DCE2_ClActKeyFree(void *key) { if (key == NULL) return; DCE2_Free(key, sizeof(Uuid), DCE2_MEM_TYPE__CL_ACT); } /******************************************************************** * Function: DCE2_ClFragDataFree() * * Callback to fragment list for freeing data kept in list. Need * to free the frag node and the data attached to it. * * Arguments: * void * * Pointer to fragment data (a frag node). * * Returns: None * ********************************************************************/ static void DCE2_ClFragDataFree(void *data) { DCE2_ClFragNode *fn = (DCE2_ClFragNode *)data; if (fn == NULL) return; if (fn->frag_data != NULL) DCE2_Free((void *)fn->frag_data, fn->frag_len, DCE2_MEM_TYPE__CL_FRAG); DCE2_Free((void *)fn, sizeof(DCE2_ClFragNode), DCE2_MEM_TYPE__CL_FRAG); } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_udp.h0000644000000000000000000000660312260565732020241 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _DCE2_UDP_H_ #define _DCE2_UDP_H_ #include "dce2_cl.h" #include "dce2_session.h" #include "dce2_list.h" #include "dce2_utils.h" #include "dcerpc.h" #include "sf_snort_packet.h" #include "sf_types.h" #include "snort_debug.h" /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_UdpSsnData { DCE2_SsnData sd; DCE2_ClTracker cl_tracker; } DCE2_UdpSsnData; /******************************************************************** * Inline function prototypes ********************************************************************/ static inline DCE2_TransType DCE2_UdpAutodetect(const SFSnortPacket *); /******************************************************************** * Public function prototypes ********************************************************************/ DCE2_UdpSsnData * DCE2_UdpSsnInit(void); void DCE2_UdpProcess(DCE2_UdpSsnData *); void DCE2_UdpDataFree(DCE2_UdpSsnData *); void DCE2_UdpSsnFree(void *); /********************************************************************* * Function: DCE2_UdpAutodetect() * * Purpose: Tries to determine if a packet is likely to be DCE/RPC * over UDP. * * Arguments: * const uint8_t * - pointer to packet data. * uint16_t - packet data length. * * Returns: * DCE2_TranType * *********************************************************************/ static inline DCE2_TransType DCE2_UdpAutodetect(const SFSnortPacket *p) { if (p->payload_size >= sizeof(DceRpcClHdr)) { DceRpcClHdr *cl_hdr = (DceRpcClHdr *)p->payload; if ((DceRpcClRpcVers(cl_hdr) == DCERPC_PROTO_MAJOR_VERS__4) && ((DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__REQUEST) || (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__RESPONSE) || (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__FAULT) || (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__REJECT) || (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__FACK)) && ((DceRpcClLen(cl_hdr) != 0) && (DceRpcClLen(cl_hdr) + sizeof(DceRpcClHdr)) <= p->payload_size)) { return DCE2_TRANS_TYPE__UDP; } } return DCE2_TRANS_TYPE__NONE; } #endif /* _DCE2_UDP_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_udp.c0000644000000000000000000000621012260565732020226 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_udp.h" #include "snort_dce2.h" #include "dce2_cl.h" #include "dce2_memory.h" #include "dce2_stats.h" #include "sf_types.h" /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_UdpSsnData * DCE2_UdpSsnInit(void) { DCE2_UdpSsnData *usd = DCE2_Alloc(sizeof(DCE2_UdpSsnData), DCE2_MEM_TYPE__UDP_SSN); if (usd == NULL) return NULL; DCE2_ResetRopts(&usd->sd.ropts); dce2_stats.udp_sessions++; return usd; } /******************************************************************** * Function: DCE2_UdpProcess() * * Purpose: Main entry point for DCE/RPC over UDP processing. * * Arguments: * DCE2_UdpSsnData * - a pointer to the data structure associated * with this session. * * Returns: None * ********************************************************************/ void DCE2_UdpProcess(DCE2_UdpSsnData *usd) { dce2_stats.udp_pkts++; DCE2_ClProcess(&usd->sd, &usd->cl_tracker); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_UdpDataFree(DCE2_UdpSsnData *usd) { if (usd == NULL) return; DCE2_ClCleanTracker(&usd->cl_tracker); } /******************************************************************** * Function: DCE2_UdpSsnFree() * * Purpose: Callback to session for freeing sessiond data. * * Arguments: * void * - pointer to the memory to be freed. * * Returns: None * ********************************************************************/ void DCE2_UdpSsnFree(void *data) { DCE2_UdpSsnData *usd = (DCE2_UdpSsnData *)data; if (usd == NULL) return; DCE2_UdpDataFree(usd); DCE2_Free((void *)usd, sizeof(DCE2_UdpSsnData), DCE2_MEM_TYPE__UDP_SSN); } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_co.h0000644000000000000000000001021312260565732020042 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _DCE2_CO_H_ #define _DCE2_CO_H_ #include "dce2_session.h" #include "dce2_list.h" #include "dce2_utils.h" #include "dcerpc.h" #include "sf_types.h" #include "sf_snort_packet.h" /******************************************************************** * Macros ********************************************************************/ #define DCE2_MOCK_HDR_LEN__CO_CLI (sizeof(DceRpcCoHdr) + sizeof(DceRpcCoRequest)) #define DCE2_MOCK_HDR_LEN__CO_SRV (sizeof(DceRpcCoHdr) + sizeof(DceRpcCoResponse)) /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_CoFragTracker { DCE2_Buffer *cli_stub_buf; DCE2_Buffer *srv_stub_buf; int opnum; /* Opnum that is ultimatley used for request */ int ctx_id; /* Context id that is ultimatley used for request */ /* These are set on a first fragment received */ int expected_call_id; /* Expected call id for fragments */ int expected_opnum; /* Expected call id for fragments */ int expected_ctx_id; /* Expected call id for fragments */ } DCE2_CoFragTracker; typedef struct _DCE2_CoSeg { DCE2_Buffer *buf; /* If there is enough data in segmentation buffer for header, * this will be set to the frag length in the header */ uint16_t frag_len; } DCE2_CoSeg; typedef struct _DCE2_CoTracker { DCE2_List *ctx_ids; /* splayed list so most recently used goes to front of list */ int got_bind; /* got an accepted bind */ /* Queue of pending client bind or alter context request context items * Since the actual context id number doesn't have to occur sequentially * in the context list in the client packet, need to keep track to match * up server response since server doesn't reply with actual context id * numbers, but in the order they were in the client packet */ DCE2_Queue *pending_ctx_ids; /* Keeps track of fragmentation buffer and frag specfic data */ DCE2_CoFragTracker frag_tracker; int max_xmit_frag; /* The maximum negotiated size of a client request */ int data_byte_order; /* Depending on policy is from bind or request */ int ctx_id; /* The current context id of the request */ int opnum; /* The current opnum of the request */ int call_id; /* The current call id of the request */ const uint8_t *stub_data; /* Current pointer to stub data in the request */ /* For transport segmentation */ DCE2_CoSeg cli_seg; DCE2_CoSeg srv_seg; } DCE2_CoTracker; /******************************************************************** * Public function prototypes ********************************************************************/ void DCE2_CoInitRdata(uint8_t *, int); void DCE2_CoProcess(DCE2_SsnData *, DCE2_CoTracker *, const uint8_t *, uint16_t); void DCE2_CoInitTracker(DCE2_CoTracker *); void DCE2_CoCleanTracker(DCE2_CoTracker *); #endif /* _DCE2_CO_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_co.c0000644000000000000000000031441312260565732020046 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Module for handling connection-oriented DCE/RPC processing. Provides * context id, interface UUID correlation and tracking for use with the * preprocessor rule options. Provides desegmentation and defragmentation. * Sets appropriate data for use with the preprocessor rule options. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_dce2.h" #include "dce2_co.h" #include "dce2_tcp.h" #include "dce2_smb.h" #include "snort_dce2.h" #include "dce2_memory.h" #include "dce2_utils.h" #include "dce2_stats.h" #include "dce2_event.h" #include "dce2_debug.h" #include "dcerpc.h" #include "profiler.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" /******************************************************************** * Macros ********************************************************************/ #define DCE2_CO__MIN_ALLOC_SIZE 50 #define DCE2_MAX_XMIT_SIZE_FUZZ 500 /******************************************************************** * Global variables ********************************************************************/ static int co_reassembled = 0; /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_CoRpktType { DCE2_CO_RPKT_TYPE__SEG, DCE2_CO_RPKT_TYPE__FRAG, DCE2_CO_RPKT_TYPE__ALL } DCE2_CoRpktType; typedef enum _DCE2_CoCtxState { DCE2_CO_CTX_STATE__ACCEPTED, DCE2_CO_CTX_STATE__REJECTED, DCE2_CO_CTX_STATE__PENDING } DCE2_CoCtxState; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_CoCtxIdNode { uint16_t ctx_id; /* The context id */ Uuid iface; /* The presentation syntax uuid for the interface */ uint16_t iface_vers_maj; /* The major version of the interface */ uint16_t iface_vers_min; /* The minor version of the interface */ /* Whether or not the server accepted or rejected the client bind/alter context * request. Initially set to pending until server response */ DCE2_CoCtxState state; } DCE2_CoCtxIdNode; /******************************************************************** * Private function prototypes ********************************************************************/ static DCE2_Ret DCE2_CoHdrChecks(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *); static void DCE2_CoDecode(DCE2_SsnData *, DCE2_CoTracker *, const uint8_t *, uint16_t); static void DCE2_CoSegDecode(DCE2_SsnData *, DCE2_CoTracker *, DCE2_CoSeg *); static void DCE2_CoBind(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t); static void DCE2_CoAlterCtx(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t); static void DCE2_CoCtxReq(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t, const uint8_t *, uint16_t); static void DCE2_CoBindAck(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t); static void DCE2_CoRequest(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t); static void DCE2_CoResponse(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t); static void DCE2_CoHandleFrag(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t); static inline DCE2_Ret DCE2_CoHandleSegmentation(DCE2_CoSeg *, const uint8_t *, uint16_t, uint16_t, uint16_t *); static void DCE2_CoReassemble(DCE2_SsnData *, DCE2_CoTracker *, DCE2_CoRpktType); static inline void DCE2_CoFragReassemble(DCE2_SsnData *, DCE2_CoTracker *); static inline void DCE2_CoSegReassemble(DCE2_SsnData *, DCE2_CoTracker *); static DCE2_Ret DCE2_CoSetIface(DCE2_SsnData *, DCE2_CoTracker *, uint16_t); static int DCE2_CoCtxCompare(const void *, const void *); static void DCE2_CoCtxFree(void *); static inline void DCE2_CoSetRopts(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *); static inline void DCE2_CoSetRdata(DCE2_SsnData *, DCE2_CoTracker *, uint8_t *, uint16_t); static inline void DCE2_CoResetFragTracker(DCE2_CoFragTracker *); static inline void DCE2_CoResetTracker(DCE2_CoTracker *); static inline DCE2_Ret DCE2_CoInitCtxStorage(DCE2_CoTracker *); static inline void DCE2_CoEraseCtxIds(DCE2_CoTracker *); static inline void DCE2_CoSegAlert(DCE2_SsnData *, DCE2_CoTracker *, DCE2_Event); static inline SFSnortPacket * DCE2_CoGetSegRpkt(DCE2_SsnData *, const uint8_t *, uint32_t); static inline DCE2_RpktType DCE2_CoGetRpktType(DCE2_SsnData *, DCE2_BufType); static SFSnortPacket * DCE2_CoGetRpkt(DCE2_SsnData *, DCE2_CoTracker *, DCE2_CoRpktType, DCE2_RpktType *); static inline DCE2_CoSeg * DCE2_CoGetSegPtr(DCE2_SsnData *, DCE2_CoTracker *); static inline DCE2_Buffer * DCE2_CoGetFragBuf(DCE2_SsnData *, DCE2_CoFragTracker *); static inline int DCE2_CoIsSegBuf(DCE2_SsnData *, DCE2_CoTracker *, const uint8_t *); static void DCE2_CoEarlyReassemble(DCE2_SsnData *, DCE2_CoTracker *); static DCE2_Ret DCE2_CoSegEarlyRequest(DCE2_CoTracker *, const uint8_t *, uint32_t); static int DCE2_CoGetAuthLen(DCE2_SsnData *, const DceRpcCoHdr *, const uint8_t *, uint16_t); /******************************************************************** * Function: DCE2_CoInitRdata() * * Initializes header of defragmentation reassembly packet. * Sets relevant fields in header that will not have to change * from reassembly to reassembly. The reassembly buffer used is * big enough for the header. * * Arguments: * uint8_t * * Pointer to the place in the reassembly packet to set * the header data. * * Returns: None * ********************************************************************/ void DCE2_CoInitRdata(uint8_t *co_ptr, int dir) { DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)co_ptr; /* Set some relevant fields. These should never get reset */ co_hdr->pversion.major = DCERPC_PROTO_MAJOR_VERS__5; co_hdr->pfc_flags = (DCERPC_CO_PFC_FLAGS__FIRST_FRAG | DCERPC_CO_PFC_FLAGS__LAST_FRAG); co_hdr->packed_drep[0] = 0x10; /* Little endian */ if (dir == FLAG_FROM_CLIENT) co_hdr->ptype = DCERPC_PDU_TYPE__REQUEST; else co_hdr->ptype = DCERPC_PDU_TYPE__RESPONSE; } /******************************************************************** * Function: DCE2_CoSetRdata() * * Sets relevant fields in the defragmentation reassembly packet * based on data gathered from the session and reassembly phase. * The reassembly buffer used is big enough for the headers. * * Arguments: * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * uint8_t * * Pointer to the place in the reassembly packet where the * header starts. * uint16_t * The length of the stub data. * * Returns: None * ********************************************************************/ static inline void DCE2_CoSetRdata(DCE2_SsnData *sd, DCE2_CoTracker *cot, uint8_t *co_ptr, uint16_t stub_len) { DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)co_ptr; /* If we've set the fragment tracker context id or opnum, use them. */ uint16_t ctx_id = (cot->frag_tracker.ctx_id != DCE2_SENTINEL) ? (uint16_t)cot->frag_tracker.ctx_id : (uint16_t)cot->ctx_id; uint16_t opnum = (cot->frag_tracker.opnum != DCE2_SENTINEL) ? (uint16_t)cot->frag_tracker.opnum : (uint16_t)cot->opnum; if (DCE2_SsnFromClient(sd->wire_pkt)) { DceRpcCoRequest *co_req = (DceRpcCoRequest *)((uint8_t *)co_hdr + sizeof(DceRpcCoHdr)); /* Doesn't really matter if this wraps ... it is basically just for presentation */ uint16_t flen = sizeof(DceRpcCoHdr) + sizeof(DceRpcCoRequest) + stub_len; co_hdr->frag_length = DceRpcHtons(&flen, DCERPC_BO_FLAG__LITTLE_ENDIAN); co_req->context_id = DceRpcHtons(&ctx_id, DCERPC_BO_FLAG__LITTLE_ENDIAN); co_req->opnum = DceRpcHtons(&opnum, DCERPC_BO_FLAG__LITTLE_ENDIAN); } else { DceRpcCoResponse *co_resp = (DceRpcCoResponse *)((uint8_t *)co_hdr + sizeof(DceRpcCoHdr)); uint16_t flen = sizeof(DceRpcCoHdr) + sizeof(DceRpcCoResponse) + stub_len; co_hdr->frag_length = DceRpcHtons(&flen, DCERPC_BO_FLAG__LITTLE_ENDIAN); co_resp->context_id = DceRpcHtons(&ctx_id, DCERPC_BO_FLAG__LITTLE_ENDIAN); } } /******************************************************************** * Function: DCE2_CoProcess() * * Main entry point for connection-oriented DCE/RPC processing. * Since there can be more than one DCE/RPC pdu in the packet, it * loops through the packet data until none is left. It handles * transport layer segmentation and buffers data until it gets the * full pdu, then hands off to pdu processing. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * const uint8_t * * Pointer to packet data * uint16_t * Packet data length * * Returns: None * ********************************************************************/ void DCE2_CoProcess(DCE2_SsnData *sd, DCE2_CoTracker *cot, const uint8_t *data_ptr, uint16_t data_len) { DCE2_CoSeg *seg = DCE2_CoGetSegPtr(sd, cot); DCE2_Ret status; uint32_t num_frags = 0; dce2_stats.co_pdus++; co_reassembled = 0; while (data_len > 0) { num_frags++; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "DCE/RPC message number: %u\n", num_frags)); /* Fast track full fragments */ if (DCE2_BufferIsEmpty(seg->buf)) { const uint8_t *frag_ptr = data_ptr; uint16_t frag_len; uint16_t data_used; /* Not enough data left for a header. Buffer it and return */ if (data_len < sizeof(DceRpcCoHdr)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Not enough data in packet for DCE/RPC Connection-oriented header.\n")); DCE2_CoHandleSegmentation(seg, data_ptr, data_len, sizeof(DceRpcCoHdr), &data_used); /* Just break out of loop in case early detect is enabled */ break; } if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr *)data_ptr) != DCE2_RET__SUCCESS) return; frag_len = DceRpcCoFragLen((DceRpcCoHdr *)data_ptr); /* Not enough data left for the pdu. */ if (data_len < frag_len) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Not enough data in packet for fragment length: %u\n", frag_len)); /* Set frag length so we don't have to check it again in seg code */ seg->frag_len = frag_len; DCE2_CoHandleSegmentation(seg, data_ptr, data_len, frag_len, &data_used); break; } DCE2_MOVE(data_ptr, data_len, frag_len); /* Got a full DCE/RPC pdu */ DCE2_CoDecode(sd, cot, frag_ptr, frag_len); /* If we're configured to do defragmentation only detect on first frag * since we'll detect on reassembled */ if (!DCE2_GcDceDefrag() || ((num_frags == 1) && !co_reassembled)) DCE2_Detect(sd); /* Reset if this is a last frag */ if (DceRpcCoLastFrag((DceRpcCoHdr *)frag_ptr)) num_frags = 0; } else /* We've already buffered data */ { uint16_t data_used = 0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Segmentation buffer has %u bytes\n", DCE2_BufferLength(seg->buf))); /* Need more data to get header */ if (DCE2_BufferLength(seg->buf) < sizeof(DceRpcCoHdr)) { status = DCE2_CoHandleSegmentation(seg, data_ptr, data_len, sizeof(DceRpcCoHdr), &data_used); /* Still not enough for header */ if (status != DCE2_RET__SUCCESS) break; /* Move the length of the amount of data we used to get header */ DCE2_MOVE(data_ptr, data_len, data_used); if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr *)DCE2_BufferData(seg->buf)) != DCE2_RET__SUCCESS) { int data_back; DCE2_BufferEmpty(seg->buf); /* Move back to original packet header */ data_back = -data_used; DCE2_MOVE(data_ptr, data_len, data_back); /*Check the original packet*/ if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr *)data_ptr) != DCE2_RET__SUCCESS) return; else { /*Only use the original packet, ignore the data in seg_buffer*/ num_frags = 0; continue; } } seg->frag_len = DceRpcCoFragLen((DceRpcCoHdr *)DCE2_BufferData(seg->buf)); } /* Need more data for full pdu */ if (DCE2_BufferLength(seg->buf) < seg->frag_len) { status = DCE2_CoHandleSegmentation(seg, data_ptr, data_len, seg->frag_len, &data_used); /* Still not enough */ if (status != DCE2_RET__SUCCESS) break; DCE2_MOVE(data_ptr, data_len, data_used); } /* Do this before calling DCE2_CoSegDecode since it will empty * seg buffer */ if (DceRpcCoLastFrag((DceRpcCoHdr *)seg->buf->data)) num_frags = 0; /* Got the full DCE/RPC pdu. Need to create new packet before decoding */ DCE2_CoSegDecode(sd, cot, seg); if ( !data_used ) break; } } if (DCE2_GcReassembleEarly() && !co_reassembled) DCE2_CoEarlyReassemble(sd, cot); } /******************************************************************** * Function: DCE2_CoHandleSegmentation() * * Wrapper around DCE2_HandleSegmentation() to allocate a new * buffer object if necessary. * * Arguments: * DCE2_CoSeg * * Pointer to a connection-oriented segmentation structure. * uint8_t * * Pointer to the current data cursor in packet. * uint16_t * Length of data from current data cursor. * uint16_t * Length of data that we need in order to consider * desegmentation complete. * uint16_t * * Pointer to basically a return value for the amount of * data in the packet that was actually used for * desegmentation. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if an error occured. Nothing can * be trusted. * DCE2_RET__SEG if there is still more desegmentation * to go, i.e. the need length has not been met by * the data length. * DCE2_RET__SUCCESS if desegmentation is complete, * i.e. the need length was met. * ********************************************************************/ static inline DCE2_Ret DCE2_CoHandleSegmentation(DCE2_CoSeg *seg, const uint8_t *data_ptr, uint16_t data_len, uint16_t need_len, uint16_t *data_used) { DCE2_Ret status; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_co_seg); if (seg == NULL) { PREPROC_PROFILE_END(dce2_pstat_co_seg); return DCE2_RET__ERROR; } if (seg->buf == NULL) { seg->buf = DCE2_BufferNew(need_len, DCE2_CO__MIN_ALLOC_SIZE, DCE2_MEM_TYPE__CO_SEG); if (seg->buf == NULL) { PREPROC_PROFILE_END(dce2_pstat_co_seg); return DCE2_RET__ERROR; } } status = DCE2_HandleSegmentation(seg->buf, data_ptr, data_len, need_len, data_used); PREPROC_PROFILE_END(dce2_pstat_co_seg); return status; } /******************************************************************** * Function: DCE2_CoHdrChecks() * * Checks some relevant fields in the header to make sure they're * sane. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to the header struct layed over the packet data. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if we should not continue processing. * DCE2_RET__SUCCESS if we should continue processing. * ********************************************************************/ static DCE2_Ret DCE2_CoHdrChecks(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr) { uint16_t frag_len = DceRpcCoFragLen(co_hdr); DceRpcPduType pdu_type = DceRpcCoPduType(co_hdr); int is_seg_buf = DCE2_CoIsSegBuf(sd, cot, (uint8_t *)co_hdr); if (frag_len < sizeof(DceRpcCoHdr)) { /* Assume we autodetected incorrectly or that DCE/RPC is not running * over the SMB named pipe */ if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB)) { if (is_seg_buf) DCE2_CoSegAlert(sd, cot, DCE2_EVENT__CO_FLEN_LT_HDR); else DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_HDR, frag_len, sizeof(DceRpcCoHdr)); } return DCE2_RET__ERROR; } if (DceRpcCoVersMaj(co_hdr) != DCERPC_PROTO_MAJOR_VERS__5) { if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB)) { if (is_seg_buf) DCE2_CoSegAlert(sd, cot, DCE2_EVENT__CO_BAD_MAJ_VERSION); else DCE2_Alert(sd, DCE2_EVENT__CO_BAD_MAJ_VERSION, DceRpcCoVersMaj(co_hdr)); } return DCE2_RET__ERROR; } if (DceRpcCoVersMin(co_hdr) != DCERPC_PROTO_MINOR_VERS__0) { if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB)) { if (is_seg_buf) DCE2_CoSegAlert(sd, cot, DCE2_EVENT__CO_BAD_MIN_VERSION); else DCE2_Alert(sd, DCE2_EVENT__CO_BAD_MIN_VERSION, DceRpcCoVersMin(co_hdr)); } return DCE2_RET__ERROR; } if (pdu_type >= DCERPC_PDU_TYPE__MAX) { if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB)) { if (is_seg_buf) DCE2_CoSegAlert(sd, cot, DCE2_EVENT__CO_BAD_PDU_TYPE); else DCE2_Alert(sd, DCE2_EVENT__CO_BAD_PDU_TYPE, DceRpcCoPduType(co_hdr)); } return DCE2_RET__ERROR; } if (DCE2_SsnFromClient(sd->wire_pkt) && (cot->max_xmit_frag != DCE2_SENTINEL)) { if (frag_len > cot->max_xmit_frag) { if (is_seg_buf) DCE2_CoSegAlert(sd, cot, DCE2_EVENT__CO_FRAG_GT_MAX_XMIT_FRAG); else DCE2_Alert(sd, DCE2_EVENT__CO_FRAG_GT_MAX_XMIT_FRAG, dce2_pdu_types[pdu_type], frag_len, cot->max_xmit_frag); } else if (!DceRpcCoLastFrag(co_hdr) && (pdu_type == DCERPC_PDU_TYPE__REQUEST) && ((((int)cot->max_xmit_frag - DCE2_MAX_XMIT_SIZE_FUZZ) < 0) || ((int)frag_len < ((int)cot->max_xmit_frag - DCE2_MAX_XMIT_SIZE_FUZZ)))) { /* If client needs to fragment the DCE/RPC request, it shouldn't be less than the * maximum xmit size negotiated. Only if it's not a last fragment. Make this alert * only if it is considerably less - have seen legitimate fragments that are just * slightly less the negotiated fragment size. */ if (is_seg_buf) DCE2_CoSegAlert(sd, cot, DCE2_EVENT__CO_FRAG_LT_MAX_XMIT_FRAG); else DCE2_Alert(sd, DCE2_EVENT__CO_FRAG_LT_MAX_XMIT_FRAG, dce2_pdu_types[pdu_type], frag_len, cot->max_xmit_frag); } /* Continue processing */ } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_CoDecode() * * Main processing for the DCE/RPC pdu types. Most are not * implemented as, currently, they are not necessary and only * stats are kept for them. Important are the bind, alter context * and request. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * const uint8_t * * Pointer to the start of the DCE/RPC pdu in the packet data. * uint16_t * Fragment length of the pdu. * * Returns: None * ********************************************************************/ static void DCE2_CoDecode(DCE2_SsnData *sd, DCE2_CoTracker *cot, const uint8_t *frag_ptr, uint16_t frag_len) { /* Already checked that we have enough data for header */ const DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)frag_ptr; int pdu_type = DceRpcCoPduType(co_hdr); /* We've got the main header. Move past it to the * start of the pdu */ DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoHdr)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "PDU type: ")); /* Client specific pdu types - some overlap with server */ if (DCE2_SsnFromClient(sd->wire_pkt)) { switch (pdu_type) { case DCERPC_PDU_TYPE__BIND: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Bind\n")); dce2_stats.co_bind++; /* Make sure context id list and queue are initialized */ if (DCE2_CoInitCtxStorage(cot) != DCE2_RET__SUCCESS) return; DCE2_CoBind(sd, cot, co_hdr, frag_ptr, frag_len); break; case DCERPC_PDU_TYPE__ALTER_CONTEXT: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Alter Context\n")); dce2_stats.co_alter_ctx++; if (DCE2_CoInitCtxStorage(cot) != DCE2_RET__SUCCESS) return; DCE2_CoAlterCtx(sd, cot, co_hdr, frag_ptr, frag_len); break; case DCERPC_PDU_TYPE__REQUEST: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Request\n")); dce2_stats.co_request++; if (DCE2_ListIsEmpty(cot->ctx_ids) && DCE2_QueueIsEmpty(cot->pending_ctx_ids)) { return; } DCE2_CoRequest(sd, cot, co_hdr, frag_ptr, frag_len); break; case DCERPC_PDU_TYPE__AUTH3: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Auth3\n")); dce2_stats.co_auth3++; break; case DCERPC_PDU_TYPE__CO_CANCEL: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Cancel\n")); dce2_stats.co_cancel++; break; case DCERPC_PDU_TYPE__ORPHANED: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Orphaned\n")); dce2_stats.co_orphaned++; break; case DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Microsoft Request To Send RPC over HTTP\n")); dce2_stats.co_ms_pdu++; break; default: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Unknown (0x%02x)\n", pdu_type)); dce2_stats.co_other_req++; break; } } else { switch (pdu_type) { case DCERPC_PDU_TYPE__BIND_ACK: case DCERPC_PDU_TYPE__ALTER_CONTEXT_RESP: if (pdu_type == DCERPC_PDU_TYPE__BIND_ACK) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Bind Ack\n")); dce2_stats.co_bind_ack++; } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Alter Context Response\n")); dce2_stats.co_alter_ctx_resp++; } if (DCE2_QueueIsEmpty(cot->pending_ctx_ids)) return; /* Bind ack and alter context response have the same * header structure, just different pdu type */ DCE2_CoBindAck(sd, cot, co_hdr, frag_ptr, frag_len); /* Got the bind/alter response - clear out the pending queue */ DCE2_QueueEmpty(cot->pending_ctx_ids); break; case DCERPC_PDU_TYPE__BIND_NACK: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Bind Nack\n")); dce2_stats.co_bind_nack++; /* Bind nack in Windows seems to blow any previous context away */ switch (DCE2_SsnGetServerPolicy(sd)) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: DCE2_CoEraseCtxIds(cot); break; default: break; } cot->got_bind = 0; break; case DCERPC_PDU_TYPE__RESPONSE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Response\n")); dce2_stats.co_response++; DCE2_CoResponse(sd, cot, co_hdr, frag_ptr, frag_len); break; case DCERPC_PDU_TYPE__FAULT: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Fault\n")); dce2_stats.co_fault++; /* Clear out the client side */ DCE2_QueueEmpty(cot->pending_ctx_ids); DCE2_BufferEmpty(cot->cli_seg.buf); DCE2_BufferEmpty(cot->frag_tracker.cli_stub_buf); DCE2_CoResetTracker(cot); break; case DCERPC_PDU_TYPE__SHUTDOWN: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Shutdown\n")); dce2_stats.co_shutdown++; break; case DCERPC_PDU_TYPE__REJECT: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Reject\n")); dce2_stats.co_reject++; DCE2_QueueEmpty(cot->pending_ctx_ids); break; case DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Microsoft Request To Send RPC over HTTP\n")); dce2_stats.co_ms_pdu++; break; default: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Unknown (0x%02x)\n", pdu_type)); dce2_stats.co_other_resp++; break; } } } /******************************************************************** * Function: DCE2_CoBind() * * Handles the processing of a client bind request. There are * differences between Windows and Samba and even early Samba in * how multiple binds on the session are handled. Processing of * the context id bindings is handed off. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to the main header in the packet data. * const uint8_t * * Pointer to the current processing point of the DCE/RPC * pdu in the packet data. * uint16_t * Fragment length left in the pdu. * * Returns: None * ********************************************************************/ static void DCE2_CoBind(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr, const uint8_t *frag_ptr, uint16_t frag_len) { DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd); DceRpcCoBind *bind = (DceRpcCoBind *)frag_ptr; if (frag_len < sizeof(DceRpcCoBind)) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, sizeof(DceRpcCoBind)); return; } DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoBind)); switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: /* Windows will not accept more than one bind */ if (!DCE2_ListIsEmpty(cot->ctx_ids)) { /* Delete context id list if anything there */ DCE2_CoEraseCtxIds(cot); return; } /* Byte order of stub data will be that of the bind */ cot->data_byte_order = DceRpcCoByteOrder(co_hdr); break; case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: if (cot->got_bind) return; break; case DCE2_POLICY__SAMBA_3_0_20: /* Accepts multiple binds */ break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); return; } cot->max_xmit_frag = (int)DceRpcCoBindMaxXmitFrag(co_hdr, bind); DCE2_CoCtxReq(sd, cot, co_hdr, DceRpcCoNumCtxItems(bind), frag_ptr, frag_len); } /******************************************************************** * Function: DCE2_CoAlterCtx() * * Handles the processing of a client alter context request. * Again, differences in how this is handled - whether we've seen * a bind yet or not, altering the data byte order. Processing * of the context id bindings is handed off. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to the main header in the packet data. * const uint8_t * * Pointer to the current processing point of the DCE/RPC * pdu in the packet data. * uint16_t * Fragment length left in the pdu. * * Returns: None * ********************************************************************/ static void DCE2_CoAlterCtx(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr, const uint8_t *frag_ptr, uint16_t frag_len) { DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd); DceRpcCoAltCtx *alt_ctx = (DceRpcCoAltCtx *)frag_ptr; if (frag_len < sizeof(DceRpcCoAltCtx)) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, sizeof(DceRpcCoAltCtx)); return; } DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoAltCtx)); switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: /* Windows will not accept an alter context before * bind and will bind_nak it */ if (DCE2_ListIsEmpty(cot->ctx_ids)) return; if (cot->data_byte_order != (int)DceRpcCoByteOrder(co_hdr)) { /* This is anomalous behavior. Alert, but continue processing */ if (cot->data_byte_order != DCE2_SENTINEL) DCE2_Alert(sd, DCE2_EVENT__CO_ALTER_CHANGE_BYTE_ORDER); } break; case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: /* Nothing for Samba */ break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); break; } /* Alter context is typedef'ed as a bind */ DCE2_CoCtxReq(sd, cot, co_hdr, DceRpcCoNumCtxItems((DceRpcCoBind *)alt_ctx), frag_ptr, frag_len); } /******************************************************************** * Function: DCE2_CoCtxReq() * * Handles parsing the context id list out of the packet. * Context ids and associated uuids are stored in a queue and * dequeued upon server response. Server response doesn't * indicate by context id which bindings were accepted or * rejected, but the index or order they were in in the client * bind or alter context, hence the queue. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to the main header in the packet data. * const uint8_t * The number of context items in the bind or alter context. * const uint8_t * * Pointer to the current processing point of the DCE/RPC * pdu in the packet data. * uint16_t * Fragment length left in the pdu. * * Returns: None * ********************************************************************/ static void DCE2_CoCtxReq(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr, const uint8_t num_ctx_items, const uint8_t *frag_ptr, uint16_t frag_len) { DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd); unsigned int i; DCE2_Ret status; if (num_ctx_items == 0) { DCE2_Alert(sd, DCE2_EVENT__CO_ZERO_CTX_ITEMS, dce2_pdu_types[DceRpcCoPduType(co_hdr)]); return; } for (i = 0; i < num_ctx_items; i++) { DceRpcCoContElem *ctx_elem = (DceRpcCoContElem *)frag_ptr; uint16_t ctx_id; uint8_t num_tsyns; const Uuid *iface; uint16_t if_vers_maj; uint16_t if_vers_min; DCE2_CoCtxIdNode *ctx_node; int j; PROFILE_VARS; if (frag_len < sizeof(DceRpcCoContElem)) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, sizeof(DceRpcCoContElem)); return; } ctx_id = DceRpcCoContElemCtxId(co_hdr, ctx_elem); num_tsyns = DceRpcCoContElemNumTransSyntaxes(ctx_elem); iface = DceRpcCoContElemIface(ctx_elem); if_vers_maj = DceRpcCoContElemIfaceVersMaj(co_hdr, ctx_elem); if_vers_min = DceRpcCoContElemIfaceVersMin(co_hdr, ctx_elem); /* No transfer syntaxes */ if (num_tsyns == 0) { DCE2_Alert(sd, DCE2_EVENT__CO_ZERO_TSYNS, dce2_pdu_types[DceRpcCoPduType(co_hdr)]); return; } DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoContElem)); /* Don't really care about the transfer syntaxes */ for (j = 0; j < num_tsyns; j++) { if (frag_len < sizeof(DceRpcCoSynId)) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, sizeof(DceRpcCoSynId)); return; } DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoSynId)); } PREPROC_PROFILE_START(dce2_pstat_co_ctx); /* If there is already an accepted node with in the list * with this ctx, just return */ if (policy == DCE2_POLICY__SAMBA_3_0_20) { ctx_node = DCE2_ListFind(cot->ctx_ids, (void *)(uintptr_t)ctx_id); if ((ctx_node != NULL) && (ctx_node->state != DCE2_CO_CTX_STATE__REJECTED)) { PREPROC_PROFILE_END(dce2_pstat_co_ctx); return; } } ctx_node = (DCE2_CoCtxIdNode *)DCE2_Alloc(sizeof(DCE2_CoCtxIdNode), DCE2_MEM_TYPE__CO_CTX); if (ctx_node == NULL) { PREPROC_PROFILE_END(dce2_pstat_co_ctx); return; } /* Add context id to pending queue */ status = DCE2_QueueEnqueue(cot->pending_ctx_ids, ctx_node); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)ctx_node, sizeof(DCE2_CoCtxIdNode), DCE2_MEM_TYPE__CO_CTX); PREPROC_PROFILE_END(dce2_pstat_co_ctx); return; } /* This node will get moved to the context id list upon server response */ ctx_node->ctx_id = ctx_id; DCE2_CopyUuid(&ctx_node->iface, iface, DceRpcCoByteOrder(co_hdr)); ctx_node->iface_vers_maj = if_vers_maj; ctx_node->iface_vers_min = if_vers_min; ctx_node->state = DCE2_CO_CTX_STATE__PENDING; PREPROC_PROFILE_END(dce2_pstat_co_ctx); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Added Context item to queue.\n" " Context id: %u\n" " Interface: %s\n" " Interface major version: %u\n" " Interface minor version: %u\n", ctx_node->ctx_id, DCE2_UuidToStr(&ctx_node->iface, DCERPC_BO_FLAG__NONE), ctx_node->iface_vers_maj, ctx_node->iface_vers_min)); switch (policy) { case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: /* Samba only ever looks at one context item. Not sure * if this is an alertable offense */ return; default: break; } } } /******************************************************************** * Function: DCE2_CoBindAck() * * Handles the processing of a server bind ack or a server alter * context response since they share the same header. * Moves context id items from the pending queue into a list * ultimately used by the rule options and sets each context item * as accepted or rejected based on the server response. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to the main header in the packet data. * const uint8_t * * Pointer to the current processing point of the DCE/RPC * pdu in the packet data. * uint16_t * Fragment length left in the pdu. * * Returns: None * ********************************************************************/ static void DCE2_CoBindAck(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr, const uint8_t *frag_ptr, uint16_t frag_len) { DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd); DceRpcCoBindAck *bind_ack = (DceRpcCoBindAck *)frag_ptr; uint16_t sec_addr_len; const uint8_t *ctx_data; uint16_t ctx_len; uint16_t pad = 0; DceRpcCoContResultList *ctx_list; uint8_t num_ctx_results; unsigned int i; uint16_t max_recv_frag; DCE2_Ret status; if (frag_len < sizeof(DceRpcCoBindAck)) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, sizeof(DceRpcCoBindAck)); return; } DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoBindAck)); /* Set what should be the maximum amount of data a client can send in a fragment */ max_recv_frag = DceRpcCoBindAckMaxRecvFrag(co_hdr, bind_ack); if ((cot->max_xmit_frag == DCE2_SENTINEL) || (max_recv_frag < cot->max_xmit_frag)) cot->max_xmit_frag = (int)max_recv_frag; sec_addr_len = DceRpcCoSecAddrLen(co_hdr, bind_ack); ctx_data = frag_ptr; ctx_len = frag_len; /* First move past secondary address */ if (ctx_len < sec_addr_len) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], ctx_len, sec_addr_len); return; } DCE2_MOVE(ctx_data, ctx_len, sec_addr_len); /* padded to 4 octet */ if ((sizeof(DceRpcCoBindAck) + sec_addr_len) & 3) pad = (4 - ((sizeof(DceRpcCoBindAck) + sec_addr_len) & 3)); if (ctx_len < pad) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], ctx_len, pad); return; } DCE2_MOVE(ctx_data, ctx_len, pad); /* Now we're at the start of the context item results */ if (ctx_len < sizeof(DceRpcCoContResultList)) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], ctx_len, sizeof(DceRpcCoContResultList)); return; } ctx_list = (DceRpcCoContResultList *)ctx_data; num_ctx_results = DceRpcCoContNumResults(ctx_list); DCE2_MOVE(ctx_data, ctx_len, sizeof(DceRpcCoContResultList)); for (i = 0; i < num_ctx_results; i++) { DceRpcCoContResult *ctx_result; uint16_t result; DCE2_CoCtxIdNode *ctx_node, *existing_ctx_node; PROFILE_VARS; if (ctx_len < sizeof(DceRpcCoContResult)) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], ctx_len, sizeof(DceRpcCoContResult)); return; } ctx_result = (DceRpcCoContResult *)ctx_data; result = DceRpcCoContRes(co_hdr, ctx_result); DCE2_MOVE(ctx_data, ctx_len, sizeof(DceRpcCoContResult)); if (DCE2_QueueIsEmpty(cot->pending_ctx_ids)) return; PREPROC_PROFILE_START(dce2_pstat_co_ctx); /* Dequeue context item in pending queue - this will get put in the permanent * context id list or free'd */ ctx_node = (DCE2_CoCtxIdNode *)DCE2_QueueDequeue(cot->pending_ctx_ids); if (ctx_node == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to dequeue a context id node.", __FILE__, __LINE__); PREPROC_PROFILE_END(dce2_pstat_co_ctx); return; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Adding Context item to context item list.\n" " Context id: %u\n" " Interface: %s\n" " Interface major version: %u\n" " Interface minor version: %u\n", ctx_node->ctx_id, DCE2_UuidToStr(&ctx_node->iface, DCERPC_BO_FLAG__NONE), ctx_node->iface_vers_maj, ctx_node->iface_vers_min)); if (result == DCERPC_CO_CONT_DEF_RESULT__ACCEPTANCE) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Server accepted context item.\n")); ctx_node->state = DCE2_CO_CTX_STATE__ACCEPTED; if (DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK) cot->got_bind = 1; } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Server rejected context item.\n")); ctx_node->state = DCE2_CO_CTX_STATE__REJECTED; cot->got_bind = 0; } existing_ctx_node = (DCE2_CoCtxIdNode *)DCE2_ListFind(cot->ctx_ids, (void *)(uintptr_t)ctx_node->ctx_id); if (existing_ctx_node != NULL) { switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: if (ctx_node->state == DCE2_CO_CTX_STATE__REJECTED) break; if (existing_ctx_node->state == DCE2_CO_CTX_STATE__REJECTED) { existing_ctx_node->ctx_id = ctx_node->ctx_id; DCE2_CopyUuid(&existing_ctx_node->iface, &ctx_node->iface, DCERPC_BO_FLAG__NONE); existing_ctx_node->iface_vers_maj = ctx_node->iface_vers_maj; existing_ctx_node->iface_vers_min = ctx_node->iface_vers_min; existing_ctx_node->state = ctx_node->state; } break; case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: /* Samba actually alters the context. Windows keeps the old */ if (ctx_node->state != DCE2_CO_CTX_STATE__REJECTED) { existing_ctx_node->ctx_id = ctx_node->ctx_id; DCE2_CopyUuid(&existing_ctx_node->iface, &ctx_node->iface, DCERPC_BO_FLAG__NONE); existing_ctx_node->iface_vers_maj = ctx_node->iface_vers_maj; existing_ctx_node->iface_vers_min = ctx_node->iface_vers_min; existing_ctx_node->state = ctx_node->state; } break; default: break; } DCE2_Free((void *)ctx_node, sizeof(DCE2_CoCtxIdNode), DCE2_MEM_TYPE__CO_CTX); } else { status = DCE2_ListInsert(cot->ctx_ids, (void *)(uintptr_t)ctx_node->ctx_id, (void *)ctx_node); if (status != DCE2_RET__SUCCESS) { /* Hit memcap */ DCE2_Free((void *)ctx_node, sizeof(DCE2_CoCtxIdNode), DCE2_MEM_TYPE__CO_CTX); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Failed to add context id node to list.\n")); PREPROC_PROFILE_END(dce2_pstat_co_ctx); return; } } PREPROC_PROFILE_END(dce2_pstat_co_ctx); } } /******************************************************************** * Function: DCE2_CoRequest() * * Handles a DCE/RPC request from the client. This is were the * client actually asks the server to do stuff on it's behalf. * If it's a first/last fragment, set relevant rule option * data and return. If it's a true fragment, do some target * based futzing to set the right opnum and context id for * the to be reassembled packet. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to the main header in the packet data. * const uint8_t * * Pointer to the current processing point of the DCE/RPC * pdu in the packet data. * uint16_t * Fragment length left in the pdu. * * Returns: None * ********************************************************************/ static void DCE2_CoRequest(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr, const uint8_t *frag_ptr, uint16_t frag_len) { DceRpcCoRequest *rhdr = (DceRpcCoRequest *)frag_ptr; uint16_t req_size = sizeof(DceRpcCoRequest); DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd); /* Account for possible object uuid */ if (DceRpcCoObjectFlag(co_hdr)) req_size += sizeof(Uuid); if (frag_len < req_size) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, req_size); return; } switch (policy) { /* After 3.0.37 up to 3.5.2 byte order of stub data is always * interpreted as little endian */ case DCE2_POLICY__SAMBA: cot->data_byte_order = DCERPC_BO_FLAG__LITTLE_ENDIAN; break; case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: cot->data_byte_order = DceRpcCoByteOrder(co_hdr); break; default: break; } /* Move past header */ DCE2_MOVE(frag_ptr, frag_len, req_size); /* If for some reason we had some fragments queued */ if (DceRpcCoFirstFrag(co_hdr) && !DceRpcCoLastFrag(co_hdr) && !DCE2_BufferIsEmpty(cot->frag_tracker.cli_stub_buf)) { DCE2_CoFragReassemble(sd, cot); DCE2_BufferEmpty(cot->frag_tracker.cli_stub_buf); DCE2_CoResetFragTracker(&cot->frag_tracker); } cot->stub_data = frag_ptr; cot->opnum = DceRpcCoOpnum(co_hdr, rhdr); cot->ctx_id = DceRpcCoCtxId(co_hdr, rhdr); cot->call_id = DceRpcCoCallId(co_hdr); if (DceRpcCoFirstFrag(co_hdr) && DceRpcCoLastFrag(co_hdr)) { int auth_len = DCE2_CoGetAuthLen(sd, co_hdr, frag_ptr, frag_len); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "First and last fragment.\n")); if (auth_len == -1) return; DCE2_CoSetRopts(sd, cot, co_hdr); } else { DCE2_CoFragTracker *ft = &cot->frag_tracker; int auth_len = DCE2_CoGetAuthLen(sd, co_hdr, frag_ptr, frag_len); dce2_stats.co_req_fragments++; #ifdef DEBUG_MSGS DCE2_DEBUG_CODE(DCE2_DEBUG__CO, if (DceRpcCoFirstFrag(co_hdr)) DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "First fragment.\n")); else if (DceRpcCoLastFrag(co_hdr)) DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Last fragment.\n")); else DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Middle fragment.\n")); DCE2_PrintPktData(frag_ptr, frag_len);); #endif if (auth_len == -1) return; if (DCE2_BufferIsEmpty(ft->cli_stub_buf)) { ft->expected_opnum = cot->opnum; ft->expected_ctx_id = cot->ctx_id; ft->expected_call_id = cot->call_id; } else { /* Don't return for these, because we can still process and servers * will still accept and deal with the anomalies in their own way */ if ((ft->expected_opnum != DCE2_SENTINEL) && (ft->expected_opnum != cot->opnum)) { DCE2_Alert(sd, DCE2_EVENT__CO_FRAG_DIFF_OPNUM, cot->opnum, ft->expected_opnum); } if ((ft->expected_ctx_id != DCE2_SENTINEL) && (ft->expected_ctx_id != cot->ctx_id)) { DCE2_Alert(sd, DCE2_EVENT__CO_FRAG_DIFF_CTX_ID, cot->ctx_id, ft->expected_ctx_id); } if ((ft->expected_call_id != DCE2_SENTINEL) && (ft->expected_call_id != cot->call_id)) { DCE2_Alert(sd, DCE2_EVENT__CO_FRAG_DIFF_CALL_ID, cot->call_id, ft->expected_call_id); } } /* Possibly set opnum in frag tracker */ switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: if (DceRpcCoLastFrag(co_hdr)) ft->opnum = cot->opnum; break; case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: if (DceRpcCoFirstFrag(co_hdr)) ft->opnum = cot->opnum; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); break; } /* Possibly set context id in frag tracker */ switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: if (DceRpcCoFirstFrag(co_hdr)) { ft->ctx_id = cot->ctx_id; } else if ((ft->expected_call_id != DCE2_SENTINEL) && (ft->expected_call_id != cot->call_id)) { /* Server won't accept frag */ return; } break; case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: if (DceRpcCoLastFrag(co_hdr)) { ft->ctx_id = cot->ctx_id; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); break; } DCE2_CoSetRopts(sd, cot, co_hdr); /* If we're configured to do defragmentation */ if (DCE2_GcDceDefrag()) { /* Don't want to include authentication data in fragment */ DCE2_CoHandleFrag(sd, cot, co_hdr, frag_ptr, (uint16_t)(frag_len - (uint16_t)auth_len)); } } } /******************************************************************** * Function: DCE2_CoResponse() * * Handles a DCE/RPC response from the server. * Samba responds to SMB bind write, request write before read with * a response to the request and doesn't send a bind ack. Get the * context id from the pending context id list and put in stable * list. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to the main header in the packet data. * const uint8_t * * Pointer to the current processing point of the DCE/RPC * pdu in the packet data. * uint16_t * Fragment length left in the pdu. * * Returns: None * ********************************************************************/ static void DCE2_CoResponse(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr, const uint8_t *frag_ptr, uint16_t frag_len) { DceRpcCoResponse *rhdr = (DceRpcCoResponse *)frag_ptr; uint16_t ctx_id; DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd); if (frag_len < sizeof(DceRpcCoResponse)) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, sizeof(DceRpcCoResponse)); return; } switch (policy) { case DCE2_POLICY__SAMBA: cot->data_byte_order = DCERPC_BO_FLAG__LITTLE_ENDIAN; break; case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: cot->data_byte_order = DceRpcCoByteOrder(co_hdr); break; default: break; } ctx_id = DceRpcCoCtxIdResp(co_hdr, rhdr); /* If pending queue is not empty, add this context id as accepted and all * others as pending */ while (!DCE2_QueueIsEmpty(cot->pending_ctx_ids)) { DCE2_Ret status; DCE2_CoCtxIdNode *ctx_node = (DCE2_CoCtxIdNode *)DCE2_QueueDequeue(cot->pending_ctx_ids); if (ctx_node == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to dequeue a context id node.", __FILE__, __LINE__); return; } if (ctx_node->ctx_id == ctx_id) ctx_node->state = DCE2_CO_CTX_STATE__ACCEPTED; status = DCE2_ListInsert(cot->ctx_ids, (void *)(uintptr_t)ctx_node->ctx_id, (void *)ctx_node); if (status != DCE2_RET__SUCCESS) { /* Might be a duplicate in there already. If there is we would have used it * anyway before looking at the pending queue. Just get rid of it */ DCE2_Free((void *)ctx_node, sizeof(DCE2_CoCtxIdNode), DCE2_MEM_TYPE__CO_CTX); return; } } /* Move past header */ DCE2_MOVE(frag_ptr, frag_len, sizeof(DceRpcCoResponse)); /* If for some reason we had some fragments queued */ if (DceRpcCoFirstFrag(co_hdr) && !DCE2_BufferIsEmpty(cot->frag_tracker.srv_stub_buf)) { DCE2_CoFragReassemble(sd, cot); DCE2_BufferEmpty(cot->frag_tracker.srv_stub_buf); DCE2_CoResetFragTracker(&cot->frag_tracker); } cot->stub_data = frag_ptr; /* Opnum not in response header - have to use previous client's */ cot->ctx_id = ctx_id; cot->call_id = DceRpcCoCallId(co_hdr); if (DceRpcCoFirstFrag(co_hdr) && DceRpcCoLastFrag(co_hdr)) { int auth_len = DCE2_CoGetAuthLen(sd, co_hdr, frag_ptr, frag_len); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "First and last fragment.\n")); if (auth_len == -1) return; DCE2_CoSetRopts(sd, cot, co_hdr); } else { //DCE2_CoFragTracker *ft = &cot->frag_tracker; int auth_len = DCE2_CoGetAuthLen(sd, co_hdr, frag_ptr, frag_len); dce2_stats.co_resp_fragments++; if (auth_len == -1) return; #if 0 /* TBD - Target based foo */ /* Don't return for these, because we can still process */ if ((ft->expected_opnum != DCE2_SENTINEL) && (ft->expected_opnum != cot->opnum)) { DCE2_Alert(sd, DCE2_EVENT__CO_FRAG_DIFF_OPNUM, cot->opnum, ft->expected_opnum); } if ((ft->expected_ctx_id != DCE2_SENTINEL) && (ft->expected_ctx_id != cot->ctx_id)) { DCE2_Alert(sd, DCE2_EVENT__CO_FRAG_DIFF_CTX_ID, cot->ctx_id, ft->expected_ctx_id); } if ((ft->expected_call_id != DCE2_SENTINEL) && (ft->expected_call_id != cot->call_id)) { DCE2_Alert(sd, DCE2_EVENT__CO_FRAG_DIFF_CALL_ID, cot->call_id, ft->expected_call_id); } #endif DCE2_CoSetRopts(sd, cot, co_hdr); /* If we're configured to do defragmentation */ if (DCE2_GcDceDefrag()) { DCE2_CoHandleFrag(sd, cot, co_hdr, frag_ptr, (uint16_t)(frag_len - (uint16_t)auth_len)); } } } /******************************************************************** * Function: DCE2_CoHandleFrag() * * Handles adding a fragment to the defragmentation buffer. * Does overflow checking. Maximum length of fragmentation buffer * is based on the maximum packet length Snort can handle. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to the main header in the packet data. * const uint8_t * * Pointer to the current processing point of the DCE/RPC * pdu in the packet data. * uint16_t * Fragment length left in the pdu. * * Returns: None * ********************************************************************/ static void DCE2_CoHandleFrag(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr, const uint8_t *frag_ptr, uint16_t frag_len) { DCE2_Buffer *frag_buf = DCE2_CoGetFragBuf(sd, &cot->frag_tracker); uint32_t size = (frag_len < DCE2_CO__MIN_ALLOC_SIZE) ? DCE2_CO__MIN_ALLOC_SIZE : frag_len; uint16_t max_frag_data; DCE2_BufferMinAddFlag mflag = DCE2_BUFFER_MIN_ADD_FLAG__USE; DCE2_Ret status; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_co_frag); if (DCE2_SsnFromClient(sd->wire_pkt)) { if (frag_len > dce2_stats.co_cli_max_frag_size) dce2_stats.co_cli_max_frag_size = frag_len; if (dce2_stats.co_cli_min_frag_size == 0 || frag_len < dce2_stats.co_cli_min_frag_size) dce2_stats.co_cli_min_frag_size = frag_len; } else { if (frag_len > dce2_stats.co_srv_max_frag_size) dce2_stats.co_srv_max_frag_size = frag_len; if (dce2_stats.co_srv_min_frag_size == 0 || frag_len < dce2_stats.co_srv_min_frag_size) dce2_stats.co_srv_min_frag_size = frag_len; } if (frag_buf == NULL) { if (DCE2_SsnFromServer(sd->wire_pkt)) { cot->frag_tracker.srv_stub_buf = DCE2_BufferNew(size, DCE2_CO__MIN_ALLOC_SIZE, DCE2_MEM_TYPE__CO_FRAG); frag_buf = cot->frag_tracker.srv_stub_buf; } else { cot->frag_tracker.cli_stub_buf = DCE2_BufferNew(size, DCE2_CO__MIN_ALLOC_SIZE, DCE2_MEM_TYPE__CO_FRAG); frag_buf = cot->frag_tracker.cli_stub_buf; } if (frag_buf == NULL) { PREPROC_PROFILE_START(dce2_pstat_co_frag); return; } } /* If there's already data in the buffer and this is a first frag * we probably missed packets */ if (DceRpcCoFirstFrag(co_hdr) && !DCE2_BufferIsEmpty(frag_buf)) { DCE2_CoResetFragTracker(&cot->frag_tracker); DCE2_BufferEmpty(frag_buf); } /* Check for potential overflow */ if (sd->trans == DCE2_TRANS_TYPE__SMB) max_frag_data = DCE2_GetRpktMaxData(sd, DCE2_RPKT_TYPE__SMB_CO_FRAG); else max_frag_data = DCE2_GetRpktMaxData(sd, DCE2_RPKT_TYPE__TCP_CO_FRAG); if (DCE2_GcMaxFrag() && (frag_len > DCE2_GcMaxFragLen())) frag_len = DCE2_GcMaxFragLen(); if ((DCE2_BufferLength(frag_buf) + frag_len) > max_frag_data) frag_len = max_frag_data - (uint16_t)DCE2_BufferLength(frag_buf); if (frag_len != 0) { /* If it's the last fragment we're going to flush so just alloc * exactly what we need ... or if there is more data than can fit * in the reassembly buffer */ if (DceRpcCoLastFrag(co_hdr) || (DCE2_BufferLength(frag_buf) == max_frag_data)) mflag = DCE2_BUFFER_MIN_ADD_FLAG__IGNORE; status = DCE2_BufferAddData(frag_buf, frag_ptr, frag_len, DCE2_BufferLength(frag_buf), mflag); if (status != DCE2_RET__SUCCESS) { PREPROC_PROFILE_END(dce2_pstat_co_frag); /* Either hit memcap or a memcpy failed - reassemble */ DCE2_CoFragReassemble(sd, cot); DCE2_BufferEmpty(frag_buf); return; } } PREPROC_PROFILE_END(dce2_pstat_co_frag); /* Reassemble if we got a last frag ... */ if (DceRpcCoLastFrag(co_hdr)) { DCE2_CoFragReassemble(sd, cot); DCE2_BufferEmpty(frag_buf); /* Set this for the server response since response doesn't * contain client opnum used */ cot->opnum = cot->frag_tracker.opnum; DCE2_CoResetFragTracker(&cot->frag_tracker); /* Return early - rule opts will be set in reassembly handler */ return; } else if (DCE2_BufferLength(frag_buf) == max_frag_data) { /* ... or can't fit any more data in the buffer * Don't reset frag tracker */ DCE2_CoFragReassemble(sd, cot); DCE2_BufferEmpty(frag_buf); return; } } /******************************************************************** * Function: DCE2_CoFragReassemble() * * Wrapper for the generic reassembly function. Calls generic * reassembly function specifying that we want to do fragmentation * reassembly. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * * Returns: None * ********************************************************************/ static inline void DCE2_CoFragReassemble(DCE2_SsnData *sd, DCE2_CoTracker *cot) { DCE2_CoReassemble(sd, cot, DCE2_CO_RPKT_TYPE__FRAG); } /******************************************************************** * Function: DCE2_CoSegReassemble() * * Wrapper for the generic reassembly function. Calls generic * reassembly function specifying that we want to do segmentation * reassembly. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * * Returns: None * ********************************************************************/ static inline void DCE2_CoSegReassemble(DCE2_SsnData *sd, DCE2_CoTracker *cot) { DCE2_CoReassemble(sd, cot, DCE2_CO_RPKT_TYPE__SEG); } /******************************************************************** * Function: DCE2_CoReassemble() * * Gets a reassemly packet based on the transport and the type of * reassembly we want to do. Sets rule options and calls detect * on the reassembled packet. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DCE2_CoRpktType * Specifies whether we want to do segmenation, fragmentation * or fragmentation and segmentation reassembly. * * Returns: None * ********************************************************************/ static void DCE2_CoReassemble(DCE2_SsnData *sd, DCE2_CoTracker *cot, DCE2_CoRpktType co_rtype) { DCE2_RpktType rpkt_type; DceRpcCoHdr *co_hdr; SFSnortPacket *rpkt; int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI : DCE2_MOCK_HDR_LEN__SMB_SRV; int co_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__CO_CLI : DCE2_MOCK_HDR_LEN__CO_SRV; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_co_reass); rpkt = DCE2_CoGetRpkt(sd, cot, co_rtype, &rpkt_type); if (rpkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Could not create DCE/RPC frag reassembled packet.\n", __FILE__, __LINE__); PREPROC_PROFILE_END(dce2_pstat_co_reass); return; } switch (rpkt_type) { case DCE2_RPKT_TYPE__SMB_CO_FRAG: case DCE2_RPKT_TYPE__SMB_CO_SEG: DCE2_SmbSetRdata((DCE2_SmbSsnData *)sd, (uint8_t *)rpkt->payload, (uint16_t)(rpkt->payload_size - smb_hdr_len)); if (rpkt_type == DCE2_RPKT_TYPE__SMB_CO_FRAG) { DCE2_CoSetRdata(sd, cot, (uint8_t *)rpkt->payload + smb_hdr_len, (uint16_t)(rpkt->payload_size - (smb_hdr_len + co_hdr_len))); if (DCE2_SsnFromClient(sd->wire_pkt)) dce2_stats.co_cli_frag_reassembled++; else dce2_stats.co_srv_frag_reassembled++; } else { if (DCE2_SsnFromClient(sd->wire_pkt)) dce2_stats.co_cli_seg_reassembled++; else dce2_stats.co_srv_seg_reassembled++; } co_hdr = (DceRpcCoHdr *)(rpkt->payload + smb_hdr_len); cot->stub_data = rpkt->payload + smb_hdr_len + co_hdr_len; break; case DCE2_RPKT_TYPE__TCP_CO_FRAG: case DCE2_RPKT_TYPE__TCP_CO_SEG: if (rpkt_type == DCE2_RPKT_TYPE__TCP_CO_FRAG) { DCE2_CoSetRdata(sd, cot, (uint8_t *)rpkt->payload, (uint16_t)(rpkt->payload_size - co_hdr_len)); if (DCE2_SsnFromClient(sd->wire_pkt)) dce2_stats.co_cli_frag_reassembled++; else dce2_stats.co_srv_frag_reassembled++; } else { if (DCE2_SsnFromClient(sd->wire_pkt)) dce2_stats.co_cli_seg_reassembled++; else dce2_stats.co_srv_seg_reassembled++; } co_hdr = (DceRpcCoHdr *)rpkt->payload; cot->stub_data = rpkt->payload + co_hdr_len; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid rpkt type: %d", __FILE__, __LINE__, rpkt_type); PREPROC_PROFILE_END(dce2_pstat_co_reass); return; } PREPROC_PROFILE_END(dce2_pstat_co_reass); /* Push packet onto stack */ if (DCE2_PushPkt(rpkt) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to push packet onto packet stack.", __FILE__, __LINE__); return; } DCE2_CoSetRopts(sd, cot, co_hdr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Reassembled CO fragmented packet:\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__CO, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size);); DCE2_Detect(sd); DCE2_PopPkt(); co_reassembled = 1; } /******************************************************************** * Function: DCE2_CoSetIface() * * Sets the interface UUID for the rules options. Looks in the * context id list. If nothing found there, it looks in the pending * list (in case we never saw the server response because of * missed packets) to see if something is there. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * uint16_t * The context id to use for the lookup. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if the interface UUID could not be found * based on the context id passed in. * DCE2_RET__SUCESS if the interface UUID could be found and * the appropriate rule options could be set. * ********************************************************************/ static DCE2_Ret DCE2_CoSetIface(DCE2_SsnData *sd, DCE2_CoTracker *cot, uint16_t ctx_id) { DCE2_CoCtxIdNode *ctx_id_node; PROFILE_VARS; /* This should be set if we've gotten a Bind */ if (cot->ctx_ids == NULL) return DCE2_RET__ERROR; PREPROC_PROFILE_START(dce2_pstat_co_ctx); ctx_id_node = (DCE2_CoCtxIdNode *)DCE2_ListFind(cot->ctx_ids, (void *)(uintptr_t)ctx_id); if (ctx_id_node == NULL) /* context id not found in list */ { /* See if it's in the queue. An easy evasion would be to stagger the writes * and reads such that we see a request before seeing the server bind ack */ if (cot->pending_ctx_ids != NULL) { for (ctx_id_node = (DCE2_CoCtxIdNode *)DCE2_QueueFirst(cot->pending_ctx_ids); ctx_id_node != NULL; ctx_id_node = (DCE2_CoCtxIdNode *)DCE2_QueueNext(cot->pending_ctx_ids)) { if (ctx_id_node->ctx_id == ctx_id) break; } } if (ctx_id_node == NULL) { PREPROC_PROFILE_END(dce2_pstat_co_ctx); return DCE2_RET__ERROR; } } if (ctx_id_node->state == DCE2_CO_CTX_STATE__REJECTED) { PREPROC_PROFILE_END(dce2_pstat_co_ctx); return DCE2_RET__ERROR; } DCE2_CopyUuid(&sd->ropts.iface, &ctx_id_node->iface, DCERPC_BO_FLAG__NONE); sd->ropts.iface_vers_maj = ctx_id_node->iface_vers_maj; sd->ropts.iface_vers_min = ctx_id_node->iface_vers_min; PREPROC_PROFILE_END(dce2_pstat_co_ctx); return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_CoCtxCompare() * * Callback to context id list for finding the right interface * UUID node. Values passed in are context ids which are used as * the keys for the list. * * Arguments: * const void * * First context id to compare. * const void * * Second context id to compare. * * Returns: * int * 0 if first value equals second value * -1 if first value does not equal the second value * ********************************************************************/ static int DCE2_CoCtxCompare(const void *a, const void *b) { int x = (int)(uintptr_t)a; int y = (int)(uintptr_t)b; if (x == y) return 0; /* Only care about equality for finding */ return -1; } /******************************************************************** * Function: DCE2_CoCtxFree() * * Callback to context id list for freeing context id nodes in * the list. * * Arguments: * void * * Context id node to free. * * Returns: None * ********************************************************************/ static void DCE2_CoCtxFree(void *data) { if (data == NULL) return; DCE2_Free(data, sizeof(DCE2_CoCtxIdNode), DCE2_MEM_TYPE__CO_CTX); } /******************************************************************** * Function: DCE2_CoInitTracker() * * Initializes fields in the connection-oriented tracker to * sentinels. Many decisions are made based on whether or not * these fields have been set. * * Arguments: * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * * Returns: None * ********************************************************************/ void DCE2_CoInitTracker(DCE2_CoTracker *cot) { if (cot == NULL) return; cot->max_xmit_frag = DCE2_SENTINEL; cot->data_byte_order = DCE2_SENTINEL; cot->ctx_id = DCE2_SENTINEL; cot->opnum = DCE2_SENTINEL; cot->call_id = DCE2_SENTINEL; cot->stub_data = NULL; cot->got_bind = 0; cot->frag_tracker.opnum = DCE2_SENTINEL; cot->frag_tracker.ctx_id = DCE2_SENTINEL; cot->frag_tracker.expected_call_id = DCE2_SENTINEL; cot->frag_tracker.expected_opnum = DCE2_SENTINEL; cot->frag_tracker.expected_ctx_id = DCE2_SENTINEL; } /******************************************************************** * Function: DCE2_CoResetTracker() * * Resets frag tracker fields after having reassembled. * * Arguments: * DCE2_CoFragTracker * * Pointer to the relevant connection-oriented frag tracker. * * Returns: None * ********************************************************************/ static inline void DCE2_CoResetFragTracker(DCE2_CoFragTracker *ft) { if (ft == NULL) return; ft->opnum = DCE2_SENTINEL; ft->ctx_id = DCE2_SENTINEL; ft->expected_call_id = DCE2_SENTINEL; ft->expected_ctx_id = DCE2_SENTINEL; ft->expected_opnum = DCE2_SENTINEL; } /******************************************************************** * Function: DCE2_CoResetTracker() * * Resets fields that are transient for requests after the bind or * alter context. The context id and opnum are dependent on the * request and in the case of fragmented requests are set until all * fragments are received. If we got a full request or all of the * fragments, these should be reset. * * Arguments: * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * * Returns: None * ********************************************************************/ static inline void DCE2_CoResetTracker(DCE2_CoTracker *cot) { if (cot == NULL) return; cot->ctx_id = DCE2_SENTINEL; cot->opnum = DCE2_SENTINEL; cot->call_id = DCE2_SENTINEL; cot->stub_data = NULL; DCE2_CoResetFragTracker(&cot->frag_tracker); } /******************************************************************** * Function: DCE2_CoCleanTracker() * * Destroys all dynamically allocated data associated with * connection-oriented tracker. * * Arguments: * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * * Returns: None * ********************************************************************/ void DCE2_CoCleanTracker(DCE2_CoTracker *cot) { if (cot == NULL) return; DCE2_BufferDestroy(cot->frag_tracker.cli_stub_buf); cot->frag_tracker.cli_stub_buf = NULL; DCE2_BufferDestroy(cot->frag_tracker.srv_stub_buf); cot->frag_tracker.srv_stub_buf = NULL; DCE2_BufferDestroy(cot->cli_seg.buf); cot->cli_seg.buf = NULL; DCE2_BufferDestroy(cot->srv_seg.buf); cot->srv_seg.buf = NULL; DCE2_ListDestroy(cot->ctx_ids); cot->ctx_ids = NULL; DCE2_QueueDestroy(cot->pending_ctx_ids); cot->pending_ctx_ids = NULL; DCE2_CoInitTracker(cot); } /******************************************************************** * Function: DCE2_CoEraseCtxIds() * * Empties out the context id list and the pending context id * queue. Does not free the list and queue - might need to still * use them. * * Arguments: * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * * Returns: None * ********************************************************************/ static inline void DCE2_CoEraseCtxIds(DCE2_CoTracker *cot) { if (cot == NULL) return; DCE2_QueueEmpty(cot->pending_ctx_ids); DCE2_ListEmpty(cot->ctx_ids); } /******************************************************************** * Function: DCE2_CoSegAlert() * * We have to alert with the appropriate data so the alert actually * makes sense. In this case, the alert was generated based on * data in a segmentation buffer. We have to create a packet * using the segmentation buffer before actually alerting. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DCE2_Event * The event that was generated. * * Returns: None * ********************************************************************/ static inline void DCE2_CoSegAlert(DCE2_SsnData *sd, DCE2_CoTracker *cot, DCE2_Event event) { SFSnortPacket *rpkt; DCE2_Buffer *buf; DceRpcCoHdr *co_hdr; uint16_t frag_len; DceRpcPduType pdu_type; if (DCE2_SsnFromClient(sd->wire_pkt)) buf = cot->cli_seg.buf; else buf = cot->srv_seg.buf; /* This should be called from the desegmentation code after there is * enough data for a connection oriented header. All of the alerts * here require a header. */ if (DCE2_BufferIsEmpty(buf) || (DCE2_BufferLength(buf) < sizeof(DceRpcCoHdr))) { return; } rpkt = DCE2_CoGetSegRpkt(sd, DCE2_BufferData(buf), DCE2_BufferLength(buf)); if (rpkt == NULL) return; co_hdr = (DceRpcCoHdr *)DCE2_BufferData(buf); frag_len = DceRpcCoFragLen(co_hdr); pdu_type = DceRpcCoPduType(co_hdr); if (DCE2_PushPkt(rpkt) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to push packet onto packet stack.", __FILE__, __LINE__); return; } switch (event) { case DCE2_EVENT__CO_FLEN_LT_HDR: DCE2_Alert(sd, event, frag_len, sizeof(DceRpcCoHdr)); break; case DCE2_EVENT__CO_BAD_MAJ_VERSION: DCE2_Alert(sd, event, DceRpcCoVersMaj(co_hdr)); break; case DCE2_EVENT__CO_BAD_MIN_VERSION: DCE2_Alert(sd, event, DceRpcCoVersMin(co_hdr)); break; case DCE2_EVENT__CO_BAD_PDU_TYPE: DCE2_Alert(sd, event, DceRpcCoPduType(co_hdr)); break; case DCE2_EVENT__CO_FRAG_GT_MAX_XMIT_FRAG: DCE2_Alert(sd, event, dce2_pdu_types[pdu_type], frag_len, cot->max_xmit_frag); break; case DCE2_EVENT__CO_FRAG_LT_MAX_XMIT_FRAG: DCE2_Alert(sd, event, dce2_pdu_types[pdu_type], frag_len, cot->max_xmit_frag); break; default: break; } DCE2_PopPkt(); } /******************************************************************** * Function: DCE2_CoGetSegRpkt() * * Gets and returns a reassembly packet based on a segmentation * buffer. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * const uint8_t * * Pointer to the start of data in the segmentation buffer. * uint32_t * The length of the data in the segmentation buffer. * * Returns: * SFSnortPacket * * A valid pointer to a reassembled packet on success. * NULL on error. * ********************************************************************/ static inline SFSnortPacket * DCE2_CoGetSegRpkt(DCE2_SsnData *sd, const uint8_t *data_ptr, uint32_t data_len) { SFSnortPacket *rpkt = NULL; int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI : DCE2_MOCK_HDR_LEN__SMB_SRV; switch (sd->trans) { case DCE2_TRANS_TYPE__SMB: rpkt = DCE2_GetRpkt(sd->wire_pkt, DCE2_RPKT_TYPE__SMB_CO_SEG, data_ptr, data_len); if (rpkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to create reassembly packet.", __FILE__, __LINE__); return NULL; } DCE2_SmbSetRdata((DCE2_SmbSsnData *)sd, (uint8_t *)rpkt->payload, (uint16_t)(rpkt->payload_size - smb_hdr_len)); break; case DCE2_TRANS_TYPE__TCP: case DCE2_TRANS_TYPE__HTTP_PROXY: case DCE2_TRANS_TYPE__HTTP_SERVER: rpkt = DCE2_GetRpkt(sd->wire_pkt, DCE2_RPKT_TYPE__TCP_CO_SEG, data_ptr, data_len); if (rpkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to create reassembly packet.", __FILE__, __LINE__); return NULL; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, sd->trans); break; } return rpkt; } /******************************************************************** * Function: DCE2_CoInitCtxStorage() * * Allocates, if necessary, and initializes the context id list * and the context id pending queue. * * Arguments: * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * * Returns: * DCE2_Ret * DCE2_RET__ERROR * We were not able to allocate data for new lists. * DCE2_RET__SUCCESS * We were able to allocate and initialize new lists. * ********************************************************************/ static inline DCE2_Ret DCE2_CoInitCtxStorage(DCE2_CoTracker *cot) { if (cot == NULL) return DCE2_RET__ERROR; if (cot->ctx_ids == NULL) { cot->ctx_ids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_CoCtxCompare, DCE2_CoCtxFree, NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__CO_CTX); if (cot->ctx_ids == NULL) return DCE2_RET__ERROR; } if (cot->pending_ctx_ids == NULL) { cot->pending_ctx_ids = DCE2_QueueNew(DCE2_CoCtxFree, DCE2_MEM_TYPE__CO_CTX); if (cot->pending_ctx_ids == NULL) { DCE2_ListDestroy(cot->ctx_ids); cot->ctx_ids = NULL; return DCE2_RET__ERROR; } } else if (!DCE2_QueueIsEmpty(cot->pending_ctx_ids)) { DCE2_QueueEmpty(cot->pending_ctx_ids); } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_CoEarlyReassemble() * * Checks to see if we should send a reassembly packet based on * the current data in fragmentation and segmentation buffers * to the detection engine. Whether we do or not is based on * whether or not we are configured to do so. The number of bytes * in the fragmentation and segmentation buffers are calulated * and if they exceed the amount we are configured for, we * reassemble. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * * Returns: None * ********************************************************************/ static void DCE2_CoEarlyReassemble(DCE2_SsnData *sd, DCE2_CoTracker *cot) { DCE2_Buffer *frag_buf = DCE2_CoGetFragBuf(sd, &cot->frag_tracker); if (DCE2_SsnFromServer(sd->wire_pkt)) return; if (!DCE2_BufferIsEmpty(frag_buf)) { uint32_t bytes = DCE2_BufferLength(frag_buf); uint32_t seg_bytes = 0; if (!DCE2_BufferIsEmpty(cot->cli_seg.buf)) { uint16_t hdr_size = sizeof(DceRpcCoHdr) + sizeof(DceRpcCoRequest); if (DCE2_BufferLength(cot->cli_seg.buf) > hdr_size) { DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)DCE2_BufferData(cot->cli_seg.buf); if (DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__REQUEST) { seg_bytes = DCE2_BufferLength(cot->cli_seg.buf) - hdr_size; if ((UINT32_MAX - bytes) < seg_bytes) seg_bytes = UINT32_MAX - bytes; bytes += seg_bytes; } } } if (bytes >= DCE2_GcReassembleThreshold()) { if (seg_bytes == 0) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Early reassemble - DCE/RPC fragments\n")); DCE2_CoReassemble(sd, cot, DCE2_CO_RPKT_TYPE__FRAG); } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Early reassemble - DCE/RPC fragments and segments\n")); DCE2_CoReassemble(sd, cot, DCE2_CO_RPKT_TYPE__ALL); } } } else if (!DCE2_BufferIsEmpty(cot->cli_seg.buf)) { uint16_t hdr_size = sizeof(DceRpcCoHdr) + sizeof(DceRpcCoRequest); uint32_t bytes = DCE2_BufferLength(cot->cli_seg.buf); if (bytes < hdr_size) return; if (bytes >= DCE2_GcReassembleThreshold()) { DCE2_Ret status; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Early reassemble - DCE/RPC segments\n")); status = DCE2_CoSegEarlyRequest(cot, DCE2_BufferData(cot->cli_seg.buf), bytes); if (status != DCE2_RET__SUCCESS) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Not enough data in seg buffer to set rule option data.\n")); return; } DCE2_CoReassemble(sd, cot, DCE2_CO_RPKT_TYPE__SEG); } } } /******************************************************************** * Function: DCE2_CoGetRpkt() * * Creates a reassembled packet based on the kind of data * (fragment, segment or both) we want to put in the reassembled * packet. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DCE2_CoRpktType * Whether we want a defrag, deseg or defrag + deseg * reassembled packet. * DCE2_RpktType * * This is set based on the transport for the session, and * potentially used by the caller to set fields in the * reassembled packet. * * Returns: * SFSnortPacket * * Pointer to the reassembled packet. * ********************************************************************/ static SFSnortPacket * DCE2_CoGetRpkt(DCE2_SsnData *sd, DCE2_CoTracker *cot, DCE2_CoRpktType co_rtype, DCE2_RpktType *rtype) { DCE2_CoSeg *seg_buf = DCE2_CoGetSegPtr(sd, cot); DCE2_Buffer *frag_buf = DCE2_CoGetFragBuf(sd, &cot->frag_tracker); const uint8_t *frag_data = NULL, *seg_data = NULL; uint32_t frag_len = 0, seg_len = 0; SFSnortPacket *rpkt = NULL; *rtype = DCE2_RPKT_TYPE__NULL; switch (co_rtype) { case DCE2_CO_RPKT_TYPE__ALL: if (!DCE2_BufferIsEmpty(frag_buf)) { frag_data = DCE2_BufferData(frag_buf); frag_len = DCE2_BufferLength(frag_buf); } if (!DCE2_BufferIsEmpty(seg_buf->buf)) { seg_data = DCE2_BufferData(seg_buf->buf); seg_len = DCE2_BufferLength(seg_buf->buf); } break; case DCE2_CO_RPKT_TYPE__FRAG: if (!DCE2_BufferIsEmpty(frag_buf)) { frag_data = DCE2_BufferData(frag_buf); frag_len = DCE2_BufferLength(frag_buf); } break; case DCE2_CO_RPKT_TYPE__SEG: if (!DCE2_BufferIsEmpty(seg_buf->buf)) { seg_data = DCE2_BufferData(seg_buf->buf); seg_len = DCE2_BufferLength(seg_buf->buf); } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid CO rpkt type: %d", __FILE__, __LINE__, co_rtype); return NULL; } /* Seg stub data will be added to end of frag data */ if ((frag_data != NULL) && (seg_data != NULL)) { uint16_t hdr_size = sizeof(DceRpcCoHdr) + sizeof(DceRpcCoRequest); /* Need to just extract the stub data from the seg buffer * if there is enough data there */ if (seg_len > hdr_size) { DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)seg_data; /* Don't use it if it's not a request and therefore doesn't * belong with the frag data. This is an insanity check - * shouldn't have seg data that's not a request if there are * frags queued up */ if (DceRpcCoPduType(co_hdr) != DCERPC_PDU_TYPE__REQUEST) { seg_data = NULL; seg_len = 0; } else { DCE2_MOVE(seg_data, seg_len, hdr_size); } } else /* Not enough stub data in seg buffer */ { seg_data = NULL; seg_len = 0; } } if (frag_data != NULL) *rtype = DCE2_CoGetRpktType(sd, DCE2_BUF_TYPE__FRAG); else if (seg_data != NULL) *rtype = DCE2_CoGetRpktType(sd, DCE2_BUF_TYPE__SEG); if (*rtype == DCE2_RPKT_TYPE__NULL) return NULL; if (frag_data != NULL) { rpkt = DCE2_GetRpkt(sd->wire_pkt, *rtype, frag_data, frag_len); if (rpkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to create reassembly packet.", __FILE__, __LINE__); return NULL; } if (seg_data != NULL) { /* If this fails, we'll still have the frag data */ DCE2_AddDataToRpkt(rpkt, *rtype, seg_data, seg_len); } } else if (seg_data != NULL) { rpkt = DCE2_GetRpkt(sd->wire_pkt, *rtype, seg_data, seg_len); if (rpkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to create reassembly packet.", __FILE__, __LINE__); return NULL; } } return rpkt; } /******************************************************************** * Function: DCE2_CoSegDecode() * * Creates a reassembled packet from the segmentation buffer and * sends off to be decoded. It's also detected on since the * detection engine has yet to see this data. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DCE2_CoSeg * * Pointer to the client or server segmentation buffer struct. * * Returns: None * ********************************************************************/ static void DCE2_CoSegDecode(DCE2_SsnData *sd, DCE2_CoTracker *cot, DCE2_CoSeg *seg) { const uint8_t *frag_ptr; uint16_t frag_len; SFSnortPacket *rpkt; int smb_hdr_len = DCE2_SsnFromClient(sd->wire_pkt) ? DCE2_MOCK_HDR_LEN__SMB_CLI : DCE2_MOCK_HDR_LEN__SMB_SRV; PROFILE_VARS; if (DCE2_SsnFromClient(sd->wire_pkt)) dce2_stats.co_cli_seg_reassembled++; else dce2_stats.co_srv_seg_reassembled++; PREPROC_PROFILE_START(dce2_pstat_co_reass); rpkt = DCE2_CoGetSegRpkt(sd, DCE2_BufferData(seg->buf), DCE2_BufferLength(seg->buf)); PREPROC_PROFILE_END(dce2_pstat_co_reass); // FIXTHIS - don't toss data until success response to // allow for retransmission of last segment of pdu. if // we don't do it here 2 things break: // (a) we can't alert on this packet; and // (b) subsequent pdus aren't desegmented correctly. DCE2_BufferEmpty(seg->buf); if (rpkt == NULL) return; /* Set the start of the connection oriented pdu to where it * is in the reassembled packet */ switch (sd->trans) { case DCE2_TRANS_TYPE__SMB: frag_ptr = rpkt->payload + smb_hdr_len; frag_len = rpkt->payload_size - smb_hdr_len; break; case DCE2_TRANS_TYPE__TCP: case DCE2_TRANS_TYPE__HTTP_PROXY: case DCE2_TRANS_TYPE__HTTP_SERVER: frag_ptr = rpkt->payload; frag_len = rpkt->payload_size; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, sd->trans); return; } if (DCE2_PushPkt(rpkt) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to push packet onto packet stack.", __FILE__, __LINE__); return; } /* All is good. Decode the pdu */ DCE2_CoDecode(sd, cot, frag_ptr, frag_len); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__CO, "Reassembled CO segmented packet\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__CO, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size);); /* Call detect since this is a reassembled packet that the * detection engine hasn't seen yet */ if (!co_reassembled) DCE2_Detect(sd); DCE2_PopPkt(); } /******************************************************************** * Function: DCE2_CoSetRopts() * * Sets values necessary for the rule options. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * DceRpcCoHdr * * Pointer to connection-oriented header in packet. * * Returns: None * ********************************************************************/ static inline void DCE2_CoSetRopts(DCE2_SsnData *sd, DCE2_CoTracker *cot, const DceRpcCoHdr *co_hdr) { DCE2_CoFragTracker *ft = &cot->frag_tracker; int opnum = (ft->opnum != DCE2_SENTINEL) ? ft->opnum : cot->opnum; int ctx_id = (ft->ctx_id != DCE2_SENTINEL) ? ft->ctx_id : cot->ctx_id; int data_byte_order = (cot->data_byte_order != DCE2_SENTINEL) ? cot->data_byte_order : (int)DceRpcCoByteOrder(co_hdr); if (DCE2_CoSetIface(sd, cot, (uint16_t)ctx_id) != DCE2_RET__SUCCESS) sd->ropts.first_frag = DCE2_SENTINEL; else sd->ropts.first_frag = DceRpcCoFirstFrag(co_hdr); sd->ropts.hdr_byte_order = DceRpcCoByteOrder(co_hdr); sd->ropts.data_byte_order = data_byte_order; sd->ropts.opnum = opnum; sd->ropts.stub_data = cot->stub_data; } /******************************************************************** * Function: DCE2_CoGetRpktType() * * Determines the type of reassembly packet we need to use * based on the transport and buffer type. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_BufType * The type of buffer we're using - fragmentation or * segmentation. * * Returns: * DCE2_RpktType * The type of reassembly packet type we should be using * given the transport and buffer type. * ********************************************************************/ static inline DCE2_RpktType DCE2_CoGetRpktType(DCE2_SsnData *sd, DCE2_BufType btype) { DCE2_RpktType rtype = DCE2_RPKT_TYPE__NULL; switch (sd->trans) { case DCE2_TRANS_TYPE__SMB: switch (btype) { case DCE2_BUF_TYPE__SEG: rtype = DCE2_RPKT_TYPE__SMB_CO_SEG; break; case DCE2_BUF_TYPE__FRAG: rtype = DCE2_RPKT_TYPE__SMB_CO_FRAG; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid buffer type: %d", __FILE__, __LINE__, btype); break; } break; case DCE2_TRANS_TYPE__TCP: case DCE2_TRANS_TYPE__HTTP_PROXY: case DCE2_TRANS_TYPE__HTTP_SERVER: switch (btype) { case DCE2_BUF_TYPE__SEG: rtype = DCE2_RPKT_TYPE__TCP_CO_SEG; break; case DCE2_BUF_TYPE__FRAG: rtype = DCE2_RPKT_TYPE__TCP_CO_FRAG; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid buffer type: %d", __FILE__, __LINE__, btype); break; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, sd->trans); break; } return rtype; } /******************************************************************** * Function: DCE2_CoIsSegBuf() * * Determines if the pointer passed in is within a segmentation * buffer. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * const uint8_t * * The pointer to test. * * Returns: * int * 1 if the pointer is in a segmentation buffer. * 0 if the pointer is not within a segmentation buffer. * ********************************************************************/ static inline int DCE2_CoIsSegBuf(DCE2_SsnData *sd, DCE2_CoTracker *cot, const uint8_t *ptr) { DCE2_Buffer *seg_buf; if (DCE2_SsnFromServer(sd->wire_pkt)) seg_buf = cot->srv_seg.buf; else seg_buf = cot->cli_seg.buf; if (DCE2_BufferIsEmpty(seg_buf)) return 0; /* See if we're looking at a segmentation buffer */ if ((ptr < DCE2_BufferData(seg_buf)) || (ptr > (DCE2_BufferData(seg_buf) + DCE2_BufferLength(seg_buf)))) { return 0; } return 1; } /******************************************************************** * Function: DCE2_CoSegEarlyRequest() * * Used to set rule option data if we are doing an early * reassembly on data in the segmentation buffer. If we are * taking directly from the segmentation buffer, none of the * rule option data will be set since processing doesn't get to * that point. Only do if this is a Request PDU. * * Arguments: * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * const uint8_t * * Pointer to the segmentation buffer data. * uint16_t * Length of the segmentation buffer data. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if there is enough data in buffer to * set rule option data and we should continue processing. * DCE2_RET__ERROR if there is not enough data in segmentation * buffer to set rule option data and we should not * continue processing. * ********************************************************************/ static DCE2_Ret DCE2_CoSegEarlyRequest(DCE2_CoTracker *cot, const uint8_t *seg_ptr, uint32_t seg_len) { const DceRpcCoHdr *co_hdr; const DceRpcCoRequest *rhdr; uint16_t req_size = sizeof(DceRpcCoRequest); if (seg_len < sizeof(DceRpcCoHdr)) return DCE2_RET__ERROR; co_hdr = (DceRpcCoHdr *)seg_ptr; DCE2_MOVE(seg_ptr, seg_len, sizeof(DceRpcCoHdr)); if (DceRpcCoPduType(co_hdr) != DCERPC_PDU_TYPE__REQUEST) return DCE2_RET__ERROR; rhdr = (DceRpcCoRequest *)seg_ptr; /* Account for possible object uuid */ if (DceRpcCoObjectFlag(co_hdr)) req_size += sizeof(Uuid); if (seg_len < req_size) return DCE2_RET__ERROR; cot->opnum = DceRpcCoOpnum(co_hdr, rhdr); cot->ctx_id = DceRpcCoCtxId(co_hdr, rhdr); cot->call_id = DceRpcCoCallId(co_hdr); return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_CoGetSegPtr() * * Returns the appropriate segmentation buffer. * * Arguments: * DCE2_SsnData * * Pointer to session data. * DCE2_CoTracker * * Pointer to connection-oriented tracker. * * Returns: * DCE2_CoSeg * * Pointer to client or server segmenation buffer. * ********************************************************************/ static inline DCE2_CoSeg * DCE2_CoGetSegPtr(DCE2_SsnData *sd, DCE2_CoTracker *cot) { if (DCE2_SsnFromServer(sd->wire_pkt)) return &cot->srv_seg; return &cot->cli_seg; } /******************************************************************** * Function: DCE2_CoGetFragBuf() * * Returns the appropriate fragmentation buffer. * * Arguments: * DCE2_SsnData * * Pointer to session data. * DCE2_CoFragTracker * * Pointer to connection-oriented fragmentation tracker. * * Returns: * DCE2_Buffer * * Pointer to client or server fragmentation buffer. * ********************************************************************/ static inline DCE2_Buffer * DCE2_CoGetFragBuf(DCE2_SsnData *sd, DCE2_CoFragTracker *ft) { if (DCE2_SsnFromServer(sd->wire_pkt)) return ft->srv_stub_buf; return ft->cli_stub_buf; } static int DCE2_CoGetAuthLen(DCE2_SsnData *sd, const DceRpcCoHdr *co_hdr, const uint8_t *frag_ptr, uint16_t frag_len) { DceRpcCoAuthVerifier *auth_hdr; uint16_t auth_len = DceRpcCoAuthLen(co_hdr); if (auth_len == 0) return 0; auth_len += sizeof(DceRpcCoAuthVerifier); /* This means the auth len was bogus */ if (auth_len > frag_len) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, auth_len); return -1; } auth_hdr = (DceRpcCoAuthVerifier *)(frag_ptr + (frag_len - auth_len)); if (DceRpcCoAuthLevel(auth_hdr) == DCERPC_CO_AUTH_LEVEL__PKT_PRIVACY) { /* Data is encrypted - don't inspect */ return -1; } auth_len += DceRpcCoAuthPad(auth_hdr); /* This means the auth pad len was bogus */ if (auth_len > frag_len) { DCE2_Alert(sd, DCE2_EVENT__CO_FLEN_LT_SIZE, dce2_pdu_types[DceRpcCoPduType(co_hdr)], frag_len, auth_len); return -1; } return (int)auth_len; } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_tcp.h0000644000000000000000000000664112260565732020241 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _DCE2_TCP_H_ #define _DCE2_TCP_H_ #include "dce2_session.h" #include "dce2_co.h" #include "dce2_utils.h" #include "dcerpc.h" #include "sf_snort_packet.h" #include "sf_types.h" #include "snort_debug.h" /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_TcpSsnData { DCE2_SsnData sd; DCE2_CoTracker co_tracker; } DCE2_TcpSsnData; /******************************************************************** * Inline function prototypes ********************************************************************/ static inline DCE2_TransType DCE2_TcpAutodetect(const SFSnortPacket *); /******************************************************************** * Public function prototypes ********************************************************************/ DCE2_TcpSsnData * DCE2_TcpSsnInit(void); void DCE2_TcpProcess(DCE2_TcpSsnData *); void DCE2_TcpDataFree(DCE2_TcpSsnData *); void DCE2_TcpSsnFree(void *); /********************************************************************* * Function: DCE2_TcpAutodetect() * * Purpose: Tries to determine if a packet is likely to be DCE/RPC * over TCP. * * Arguments: * const uint8_t * - pointer to packet data. * uint16_t - packet data length. * * Returns: * DCE2_TranType * *********************************************************************/ static inline DCE2_TransType DCE2_TcpAutodetect(const SFSnortPacket *p) { if (p->payload_size >= sizeof(DceRpcCoHdr)) { DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)p->payload; if ((DceRpcCoVersMaj(co_hdr) == DCERPC_PROTO_MAJOR_VERS__5) && (DceRpcCoVersMin(co_hdr) == DCERPC_PROTO_MINOR_VERS__0) && ((DCE2_SsnFromClient(p) && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND) || (DCE2_SsnFromServer(p) && DceRpcCoPduType(co_hdr) == DCERPC_PDU_TYPE__BIND_ACK)) && (DceRpcCoFragLen(co_hdr) >= sizeof(DceRpcCoHdr))) { return DCE2_TRANS_TYPE__TCP; } } else if ((*p->payload == DCERPC_PROTO_MAJOR_VERS__5) && DCE2_SsnFromClient(p)) { return DCE2_TRANS_TYPE__TCP; } return DCE2_TRANS_TYPE__NONE; } #endif /* _DCE2_TCP_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_tcp.c0000644000000000000000000000622412260565732020231 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_tcp.h" #include "snort_dce2.h" #include "dce2_co.h" #include "dce2_memory.h" #include "dce2_stats.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_TcpSsnData * DCE2_TcpSsnInit(void) { DCE2_TcpSsnData *tsd = DCE2_Alloc(sizeof(DCE2_TcpSsnData), DCE2_MEM_TYPE__TCP_SSN); if (tsd == NULL) return NULL; DCE2_CoInitTracker(&tsd->co_tracker); DCE2_ResetRopts(&tsd->sd.ropts); dce2_stats.tcp_sessions++; return tsd; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_TcpProcess(DCE2_TcpSsnData *tsd) { const SFSnortPacket *p = tsd->sd.wire_pkt; const uint8_t *data_ptr = p->payload; uint16_t data_len = p->payload_size; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Processing TCP packet.\n")); dce2_stats.tcp_pkts++; DCE2_CoProcess(&tsd->sd, &tsd->co_tracker, data_ptr, data_len); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_TcpDataFree(DCE2_TcpSsnData *tsd) { if (tsd == NULL) return; DCE2_CoCleanTracker(&tsd->co_tracker); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_TcpSsnFree(void *ssn) { DCE2_TcpSsnData *tsd = (DCE2_TcpSsnData *)ssn; if (tsd == NULL) return; DCE2_TcpDataFree(tsd); DCE2_Free((void *)tsd, sizeof(DCE2_TcpSsnData), DCE2_MEM_TYPE__TCP_SSN); } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_smb.h0000644000000000000000000002632612260565732020236 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _DCE2_SMB_H_ #define _DCE2_SMB_H_ #include "dce2_session.h" #include "dce2_tcp.h" #include "dce2_list.h" #include "dce2_utils.h" #include "smb.h" #include "sf_snort_packet.h" #include "sf_types.h" #include "snort_debug.h" /******************************************************************** * Macros ********************************************************************/ // Used for reassembled packets #define DCE2_MOCK_HDR_LEN__SMB_CLI \ (sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq)) #define DCE2_MOCK_HDR_LEN__SMB_SRV \ (sizeof(NbssHdr) + sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp)) // This is for ease of comparison so a 32 bit numeric compare can be done // instead of a string compare. #define DCE2_SMB_ID 0xff534d42 /* \xffSMB */ #define DCE2_SMB2_ID 0xfe534d42 /* \xfeSMB */ // MS-FSCC Section 2.1.5 - Pathname #define DCE2_SMB_MAX_PATH_LEN 32760 #define DCE2_SMB_MAX_COMP_LEN 255 /******************************************************************** * Externs ********************************************************************/ extern SmbAndXCom smb_chain_map[SMB_MAX_NUM_COMS]; extern const char *smb_com_strings[SMB_MAX_NUM_COMS]; extern const char *smb_transaction_sub_command_strings[TRANS_SUBCOM_MAX]; extern const char *smb_transaction2_sub_command_strings[TRANS2_SUBCOM_MAX]; extern const char *smb_nt_transact_sub_command_strings[NT_TRANSACT_SUBCOM_MAX]; extern char smb_file_name[DCE2_SMB_MAX_PATH_LEN+1]; /******************************************************************** * Enums ********************************************************************/ typedef enum _DCE2_SmbSsnState { DCE2_SMB_SSN_STATE__START = 0x00, DCE2_SMB_SSN_STATE__NEGOTIATED = 0x01, DCE2_SMB_SSN_STATE__FP_CLIENT = 0x02, // Fingerprinted client DCE2_SMB_SSN_STATE__FP_SERVER = 0x04 // Fingerprinted server } DCE2_SmbSsnState; typedef enum _DCE2_SmbDataState { DCE2_SMB_DATA_STATE__NETBIOS_HEADER, DCE2_SMB_DATA_STATE__SMB_HEADER, DCE2_SMB_DATA_STATE__NETBIOS_PDU } DCE2_SmbDataState; typedef enum _DCE2_SmbPduState { DCE2_SMB_PDU_STATE__COMMAND, DCE2_SMB_PDU_STATE__RAW_DATA } DCE2_SmbPduState; typedef enum _DCE2_SmbFileDirection { DCE2_SMB_FILE_DIRECTION__UNKNOWN = 0, DCE2_SMB_FILE_DIRECTION__UPLOAD, DCE2_SMB_FILE_DIRECTION__DOWNLOAD } DCE2_SmbFileDirection; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_SmbWriteAndXRaw { int remaining; // A signed integer so it can be negative DCE2_Buffer *buf; } DCE2_SmbWriteAndXRaw; typedef struct _DCE2_SmbFileChunk { uint64_t offset; uint32_t length; uint8_t *data; } DCE2_SmbFileChunk; typedef struct _DCE2_SmbFileTracker { int fid; // A signed integer so it can be set to sentinel uint16_t uid; uint16_t tid; bool is_ipc; char *file_name; union { struct { // If pipe has been set to byte mode via TRANS_SET_NMPIPE_STATE bool byte_mode; // For Windows 2000 bool used; // For WriteAndX requests that use raw mode flag // Windows only DCE2_SmbWriteAndXRaw *writex_raw; // Connection-oriented DCE/RPC tracker DCE2_CoTracker *co_tracker; } nmpipe; struct { uint64_t file_size; uint64_t file_offset; uint64_t bytes_processed; DCE2_List *file_chunks; uint32_t bytes_queued; DCE2_SmbFileDirection file_direction; bool sequential_only; } file; } tracker; #define fp_byte_mode tracker.nmpipe.byte_mode #define fp_used tracker.nmpipe.used #define fp_writex_raw tracker.nmpipe.writex_raw #define fp_co_tracker tracker.nmpipe.co_tracker #define ff_file_size tracker.file.file_size #define ff_file_offset tracker.file.file_offset #define ff_bytes_processed tracker.file.bytes_processed #define ff_file_direction tracker.file.file_direction #define ff_file_chunks tracker.file.file_chunks #define ff_bytes_queued tracker.file.bytes_queued #define ff_sequential_only tracker.file.sequential_only } DCE2_SmbFileTracker; typedef struct _DCE2_SmbTransactionTracker { int smb_type; uint8_t subcom; bool one_way; bool disconnect_tid; bool pipe_byte_mode; uint32_t tdcnt; uint32_t dsent; DCE2_Buffer *dbuf; uint32_t tpcnt; uint32_t psent; DCE2_Buffer *pbuf; // For Transaction2/Query File Information uint16_t info_level; } DCE2_SmbTransactionTracker; typedef struct _DCE2_SmbRequestTracker { int smb_com; int mid; // A signed integer so it can be set to sentinel uint16_t uid; uint16_t tid; uint16_t pid; // For WriteRaw bool writeraw_writethrough; uint32_t writeraw_remaining; // For Transaction/Transaction2/NtTransact DCE2_SmbTransactionTracker ttracker; // Client can chain a write to an open. Need to write data, but also // need to associate tracker with fid returned from server DCE2_Queue *ft_queue; // This is a reference to an existing file tracker DCE2_SmbFileTracker *ftracker; // Used for requests to cache data that will ultimately end up in // the file tracker upon response. char *file_name; uint64_t file_size; uint64_t file_offset; bool sequential_only; // For TreeConnect to know whether it's to IPC bool is_ipc; } DCE2_SmbRequestTracker; typedef struct _DCE2_SmbSsnData { DCE2_SsnData sd; // This member must be first DCE2_Policy policy; int dialect_index; int ssn_state_flags; DCE2_SmbDataState cli_data_state; DCE2_SmbDataState srv_data_state; DCE2_SmbPduState pdu_state; int uid; // A signed integer so it can be set to sentinel int tid; // A signed integer so it can be set to sentinel DCE2_List *uids; DCE2_List *tids; // For tracking files and named pipes DCE2_SmbFileTracker ftracker; DCE2_List *ftrackers; // List of DCE2_SmbFileTracker // For tracking requests / responses DCE2_SmbRequestTracker rtracker; DCE2_Queue *rtrackers; uint16_t max_outstanding_requests; uint16_t outstanding_requests; // The current pid/mid node for this request/response DCE2_SmbRequestTracker *cur_rtracker; // Used for TCP segmentation to get full PDU DCE2_Buffer *cli_seg; DCE2_Buffer *srv_seg; // These are used for commands we don't need to process uint32_t cli_ignore_bytes; uint32_t srv_ignore_bytes; // The file API supports one concurrent upload/download per session. // This is a reference to a file tracker so shouldn't be freed. DCE2_SmbFileTracker *fapi_ftracker; #ifdef ACTIVE_RESPONSE DCE2_SmbFileTracker *fb_ftracker; bool block_pdus; #endif // Maximum file depth as returned from file API int64_t max_file_depth; } DCE2_SmbSsnData; typedef struct _DCE2SmbFsm { char input; int next_state; int fail_state; } DCE2_SmbFsm; /******************************************************************** * Inline function prototypes ********************************************************************/ static inline DCE2_TransType DCE2_SmbAutodetect(const SFSnortPacket *); static inline void DCE2_SmbSetFingerprintedClient(DCE2_SmbSsnData *); static inline bool DCE2_SmbFingerprintedClient(DCE2_SmbSsnData *); static inline void DCE2_SmbSetFingerprintedServer(DCE2_SmbSsnData *); static inline bool DCE2_SmbFingerprintedServer(DCE2_SmbSsnData *); /******************************************************************** * Public function prototypes ********************************************************************/ void DCE2_SmbInitGlobals(void); void DCE2_SmbInitRdata(uint8_t *, int); void DCE2_SmbSetRdata(DCE2_SmbSsnData *, uint8_t *, uint16_t); DCE2_SmbSsnData * DCE2_SmbSsnInit(SFSnortPacket *); void DCE2_SmbProcess(DCE2_SmbSsnData *); void DCE2_SmbDataFree(DCE2_SmbSsnData *); void DCE2_SmbSsnFree(void *); #ifdef ACTIVE_RESPONSE void DCE2_SmbInitDeletePdu(void); #endif /********************************************************************* * Function: DCE2_SmbAutodetect() * * Purpose: Tries to determine if a packet is likely to be SMB. * * Arguments: * const uint8_t * - pointer to packet data. * uint16_t - packet data length. * * Returns: * DCE2_TranType * *********************************************************************/ static inline DCE2_TransType DCE2_SmbAutodetect(const SFSnortPacket *p) { if (p->payload_size > (sizeof(NbssHdr) + sizeof(SmbNtHdr))) { NbssHdr *nb_hdr = (NbssHdr *)p->payload; switch (NbssType(nb_hdr)) { case NBSS_SESSION_TYPE__MESSAGE: { SmbNtHdr *smb_hdr = (SmbNtHdr *)(p->payload + sizeof(NbssHdr)); if ((SmbId(smb_hdr) == DCE2_SMB_ID) || (SmbId(smb_hdr) == DCE2_SMB2_ID)) { return DCE2_TRANS_TYPE__SMB; } } break; default: break; } } return DCE2_TRANS_TYPE__NONE; } static inline void DCE2_SmbSetFingerprintedClient(DCE2_SmbSsnData *ssd) { ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__FP_CLIENT; } static inline bool DCE2_SmbFingerprintedClient(DCE2_SmbSsnData *ssd) { return ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__FP_CLIENT; } static inline void DCE2_SmbSetFingerprintedServer(DCE2_SmbSsnData *ssd) { ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__FP_SERVER; } static inline bool DCE2_SmbFingerprintedServer(DCE2_SmbSsnData *ssd) { return ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__FP_SERVER; } static inline bool DCE2_SmbFileDirUnknown(DCE2_SmbFileDirection dir) { return dir == DCE2_SMB_FILE_DIRECTION__UNKNOWN; } static inline bool DCE2_SmbFileUpload(DCE2_SmbFileDirection dir) { return dir == DCE2_SMB_FILE_DIRECTION__UPLOAD; } static inline bool DCE2_SmbFileDownload(DCE2_SmbFileDirection dir) { return dir == DCE2_SMB_FILE_DIRECTION__DOWNLOAD; } #endif /* _DCE2_SMB_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_smb.c0000644000000000000000000132313512260565732020230 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_dce2.h" #include "dce2_smb.h" #include "dce2_tcp.h" #include "dce2_co.h" #include "snort_dce2.h" #include "dce2_config.h" #include "dce2_memory.h" #include "dce2_utils.h" #include "dce2_debug.h" #include "dce2_stats.h" #include "dce2_event.h" #include "smb.h" #include "sf_snort_packet.h" #include "sf_types.h" #include "profiler.h" #include "snort_debug.h" #include "sf_dynamic_preprocessor.h" #include "file_api.h" #ifndef WIN32 #include /* for ntohl */ #endif /* WIN32 */ /******************************************************************** * Enums ********************************************************************/ typedef enum _DCE2_SmbComError { // No errors associated with the command DCE2_SMB_COM_ERROR__COMMAND_OK = 0x0000, // An error was reported in the SMB response header DCE2_SMB_COM_ERROR__STATUS_ERROR = 0x0001, // An invalid word count makes it unlikely any data accessed will be correct // and if accessed the possibility of accessing out of bounds data DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT = 0x0002, // An invalid byte count just means the byte count is not right for // the command processed. The command can still be processed but // the byte count should not be used. In general, the byte count // should not be used since Windows and Samba often times ignore it DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT = 0x0004, // Not enough data to process command so don't try to access any // of the command's header or data. DCE2_SMB_COM_ERROR__BAD_LENGTH = 0x0008 } DCE2_SmbComError; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_SmbComInfo { int smb_type; // SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE int cmd_error; // mask of DCE2_SmbComError uint8_t smb_com; uint8_t word_count; uint16_t byte_count; uint16_t cmd_size; } DCE2_SmbComInfo; // Inline accessor functions for DCE2_SmbComInfo static inline bool DCE2_ComInfoIsResponse(const DCE2_SmbComInfo *com_info) { return (com_info->smb_type == SMB_TYPE__RESPONSE) ? true : false; } static inline bool DCE2_ComInfoIsRequest(const DCE2_SmbComInfo *com_info) { return (com_info->smb_type == SMB_TYPE__REQUEST) ? true : false; } static inline uint8_t DCE2_ComInfoWordCount(const DCE2_SmbComInfo *com_info) { return com_info->word_count; } static inline uint8_t DCE2_ComInfoSmbCom(const DCE2_SmbComInfo *com_info) { return com_info->smb_com; } static inline uint16_t DCE2_ComInfoByteCount(const DCE2_SmbComInfo *com_info) { return com_info->byte_count; } static inline uint16_t DCE2_ComInfoCommandSize(const DCE2_SmbComInfo *com_info) { return com_info->cmd_size; } static inline bool DCE2_ComInfoIsCommandOK(const DCE2_SmbComInfo *com_info) { return (com_info->cmd_error == DCE2_SMB_COM_ERROR__COMMAND_OK) ? true : false; } static inline bool DCE2_ComInfoIsStatusError(const DCE2_SmbComInfo *com_info) { return (com_info->cmd_error & DCE2_SMB_COM_ERROR__STATUS_ERROR) ? true : false; } static inline bool DCE2_ComInfoIsInvalidWordCount(const DCE2_SmbComInfo *com_info) { return (com_info->cmd_error & DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT) ? true : false; } static inline bool DCE2_ComInfoIsInvalidByteCount(const DCE2_SmbComInfo *com_info) { return (com_info->cmd_error & DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT) ? true : false; } static inline bool DCE2_ComInfoIsBadLength(const DCE2_SmbComInfo *com_info) { return (com_info->cmd_error & DCE2_SMB_COM_ERROR__BAD_LENGTH) ? true : false; } // If this returns false, the command should not be processed static inline bool DCE2_ComInfoCanProcessCommand(const DCE2_SmbComInfo *com_info) { if (DCE2_ComInfoIsBadLength(com_info) || DCE2_ComInfoIsStatusError(com_info) || DCE2_ComInfoIsInvalidWordCount(com_info)) return false; return true; } /******************************************************************** * Global variables ********************************************************************/ typedef DCE2_Ret (*DCE2_SmbComFunc)(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_SmbComFunc smb_com_funcs[SMB_MAX_NUM_COMS]; static uint8_t smb_wcts[SMB_MAX_NUM_COMS][2][32]; static uint16_t smb_bccs[SMB_MAX_NUM_COMS][2][2]; static DCE2_SmbComFunc smb_chain_funcs[DCE2_POLICY__MAX][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS]; static bool smb_deprecated_coms[SMB_MAX_NUM_COMS]; static bool smb_unusual_coms[SMB_MAX_NUM_COMS]; // File name of the current file we are tracking for logging since the // file tracker may be gone before logging occurs. char smb_file_name[DCE2_SMB_MAX_PATH_LEN+1]; // Exported SmbAndXCom smb_chain_map[SMB_MAX_NUM_COMS]; const char *smb_com_strings[SMB_MAX_NUM_COMS] = { "Create Directory", // 0x00 "Delete Directory", // 0x01 "Open", // 0x02 "Create", // 0x03 "Close", // 0x04 "Flush", // 0x05 "Delete", // 0x06 "Rename", // 0x07 "Query Information", // 0x08 "Set Information", // 0x09 "Read", // 0x0A "Write", // 0x0B "Lock Byte Range", // 0x0C "Unlock Byte Range", // 0x0D "Create Temporary", // 0x0E "Create New", // 0x0F "Check Directory", // 0x10 "Process Exit", // 0x11 "Seek", // 0x12 "Lock And Read", // 0x13 "Write And Unlock", // 0x14 "Unknown", // 0X15 "Unknown", // 0X16 "Unknown", // 0X17 "Unknown", // 0X18 "Unknown", // 0X19 "Read Raw", // 0x1A "Read Mpx", // 0x1B "Read Mpx Secondary", // 0x1C "Write Raw", // 0x1D "Write Mpx", // 0x1E "Write Mpx Secondary", // 0x1F "Write Complete", // 0x20 "Query Server", // 0x21 "Set Information2", // 0x22 "Query Information2", // 0x23 "Locking AndX", // 0x24 "Transaction", // 0x25 "Transaction Secondary", // 0x26 "Ioctl", // 0x27 "Ioctl Secondary", // 0x28 "Copy", // 0x29 "Move", // 0x2A "Echo", // 0x2B "Write And Close", // 0x2C "Open AndX", // 0x2D "Read AndX", // 0x2E "Write AndX", // 0x2F "New File Size", // 0x30 "Close And Tree Disc", // 0x31 "Transaction2", // 0x32 "Transaction2 Secondary", // 0x33 "Find Close2", // 0x34 "Find Notify Close", // 0x35 "Unknown", // 0X36 "Unknown", // 0X37 "Unknown", // 0X38 "Unknown", // 0X39 "Unknown", // 0X3A "Unknown", // 0X3B "Unknown", // 0X3C "Unknown", // 0X3D "Unknown", // 0X3E "Unknown", // 0X3F "Unknown", // 0X40 "Unknown", // 0X41 "Unknown", // 0X42 "Unknown", // 0X43 "Unknown", // 0X44 "Unknown", // 0X45 "Unknown", // 0X46 "Unknown", // 0X47 "Unknown", // 0X48 "Unknown", // 0X49 "Unknown", // 0X4A "Unknown", // 0X4B "Unknown", // 0X4C "Unknown", // 0X4D "Unknown", // 0X4E "Unknown", // 0X4F "Unknown", // 0X50 "Unknown", // 0X51 "Unknown", // 0X52 "Unknown", // 0X53 "Unknown", // 0X54 "Unknown", // 0X55 "Unknown", // 0X56 "Unknown", // 0X57 "Unknown", // 0X58 "Unknown", // 0X59 "Unknown", // 0X5A "Unknown", // 0X5B "Unknown", // 0X5C "Unknown", // 0X5D "Unknown", // 0X5E "Unknown", // 0X5F "Unknown", // 0X60 "Unknown", // 0X61 "Unknown", // 0X62 "Unknown", // 0X63 "Unknown", // 0X64 "Unknown", // 0X65 "Unknown", // 0X66 "Unknown", // 0X67 "Unknown", // 0X68 "Unknown", // 0X69 "Unknown", // 0X6A "Unknown", // 0X6B "Unknown", // 0X6C "Unknown", // 0X6D "Unknown", // 0X6E "Unknown", // 0X6F "Tree Connect", // 0x70 "Tree Disconnect", // 0x71 "Negotiate", // 0x72 "Session Setup AndX", // 0x73 "Logoff AndX", // 0x74 "Tree Connect AndX", // 0x75 "Unknown", // 0X76 "Unknown", // 0X77 "Unknown", // 0X78 "Unknown", // 0X79 "Unknown", // 0X7A "Unknown", // 0X7B "Unknown", // 0X7C "Unknown", // 0X7D "Security Package AndX", // 0x7E "Unknown", // 0X7F "Query Information Disk", // 0x80 "Search", // 0x81 "Find", // 0x82 "Find Unique", // 0x83 "Find Close", // 0x84 "Unknown", // 0X85 "Unknown", // 0X86 "Unknown", // 0X87 "Unknown", // 0X88 "Unknown", // 0X89 "Unknown", // 0X8A "Unknown", // 0X8B "Unknown", // 0X8C "Unknown", // 0X8D "Unknown", // 0X8E "Unknown", // 0X8F "Unknown", // 0X90 "Unknown", // 0X91 "Unknown", // 0X92 "Unknown", // 0X93 "Unknown", // 0X94 "Unknown", // 0X95 "Unknown", // 0X96 "Unknown", // 0X97 "Unknown", // 0X98 "Unknown", // 0X99 "Unknown", // 0X9A "Unknown", // 0X9B "Unknown", // 0X9C "Unknown", // 0X9D "Unknown", // 0X9E "Unknown", // 0X9F "Nt Transact", // 0xA0 "Nt Transact Secondary", // 0xA1 "Nt Create AndX", // 0xA2 "Unknown", // 0XA3 "Nt Cancel", // 0xA4 "Nt Rename", // 0xA5 "Unknown", // 0XA6 "Unknown", // 0XA7 "Unknown", // 0XA8 "Unknown", // 0XA9 "Unknown", // 0XAA "Unknown", // 0XAB "Unknown", // 0XAC "Unknown", // 0XAD "Unknown", // 0XAE "Unknown", // 0XAF "Unknown", // 0XB0 "Unknown", // 0XB1 "Unknown", // 0XB2 "Unknown", // 0XB3 "Unknown", // 0XB4 "Unknown", // 0XB5 "Unknown", // 0XB6 "Unknown", // 0XB7 "Unknown", // 0XB8 "Unknown", // 0XB9 "Unknown", // 0XBA "Unknown", // 0XBB "Unknown", // 0XBC "Unknown", // 0XBD "Unknown", // 0XBE "Unknown", // 0XBF "Open Print File", // 0xC0 "Write Print File", // 0xC1 "Close Print File", // 0xC2 "Get Print Queue", // 0xC3 "Unknown", // 0XC4 "Unknown", // 0XC5 "Unknown", // 0XC6 "Unknown", // 0XC7 "Unknown", // 0XC8 "Unknown", // 0XC9 "Unknown", // 0XCA "Unknown", // 0XCB "Unknown", // 0XCC "Unknown", // 0XCD "Unknown", // 0XCE "Unknown", // 0XCF "Unknown", // 0XD0 "Unknown", // 0XD1 "Unknown", // 0XD2 "Unknown", // 0XD3 "Unknown", // 0XD4 "Unknown", // 0XD5 "Unknown", // 0XD6 "Unknown", // 0XD7 "Read Bulk", // 0xD8 "Write Bulk", // 0xD9 "Write Bulk Data", // 0xDA "Unknown", // 0XDB "Unknown", // 0XDC "Unknown", // 0XDD "Unknown", // 0XDE "Unknown", // 0XDF "Unknown", // 0XE0 "Unknown", // 0XE1 "Unknown", // 0XE2 "Unknown", // 0XE3 "Unknown", // 0XE4 "Unknown", // 0XE5 "Unknown", // 0XE6 "Unknown", // 0XE7 "Unknown", // 0XE8 "Unknown", // 0XE9 "Unknown", // 0XEA "Unknown", // 0XEB "Unknown", // 0XEC "Unknown", // 0XED "Unknown", // 0XEE "Unknown", // 0XEF "Unknown", // 0XF0 "Unknown", // 0XF1 "Unknown", // 0XF2 "Unknown", // 0XF3 "Unknown", // 0XF4 "Unknown", // 0XF5 "Unknown", // 0XF6 "Unknown", // 0XF7 "Unknown", // 0XF8 "Unknown", // 0XF9 "Unknown", // 0XFA "Unknown", // 0XFB "Unknown", // 0XFC "Unknown", // 0XFD "Invalid", // 0xFE "No AndX Command" // 0xFF }; const char *smb_transaction_sub_command_strings[TRANS_SUBCOM_MAX] = { "Unknown", // 0x0000 "TRANS_SET_NMPIPE_STATE", // 0x0001 "Unknown", // 0x0002 "Unknown", // 0x0003 "Unknown", // 0x0004 "Unknown", // 0x0005 "Unknown", // 0x0006 "Unknown", // 0x0007 "Unknown", // 0x0008 "Unknown", // 0x0009 "Unknown", // 0x000A "Unknown", // 0x000B "Unknown", // 0x000C "Unknown", // 0x000D "Unknown", // 0x000E "Unknown", // 0x000F "Unknown", // 0x0010 "TRANS_RAW_READ_NMPIPE", // 0x0011 "Unknown", // 0x0012 "Unknown", // 0x0013 "Unknown", // 0x0014 "Unknown", // 0x0015 "Unknown", // 0x0016 "Unknown", // 0x0017 "Unknown", // 0x0018 "Unknown", // 0x0019 "Unknown", // 0x001A "Unknown", // 0x001B "Unknown", // 0x001C "Unknown", // 0x001D "Unknown", // 0x001E "Unknown", // 0x001F "Unknown", // 0x0020 "TRANS_QUERY_NMPIPE_STATE", // 0x0021 "TRANS_QUERY_NMPIPE_INFO", // 0x0022 "TRANS_PEEK_NMPIPE", // 0x0023 "Unknown", // 0x0024 "Unknown", // 0x0025 "TRANS_TRANSACT_NMPIPE", // 0x0026 "Unknown", // 0x0027 "Unknown", // 0x0028 "Unknown", // 0x0029 "Unknown", // 0x002A "Unknown", // 0x002B "Unknown", // 0x002C "Unknown", // 0x002D "Unknown", // 0x002E "Unknown", // 0x002F "Unknown", // 0x0030 "TRANS_RAW_WRITE_NMPIPE", // 0x0031 "Unknown", // 0x0032 "Unknown", // 0x0033 "Unknown", // 0x0034 "Unknown", // 0x0035 "TRANS_READ_NMPIPE", // 0x0036 "TRANS_WRITE_NMPIPE", // 0x0037 "Unknown", // 0x0038 "Unknown", // 0x0039 "Unknown", // 0x003A "Unknown", // 0x003B "Unknown", // 0x003C "Unknown", // 0x003D "Unknown", // 0x003E "Unknown", // 0x003F "Unknown", // 0x0040 "Unknown", // 0x0041 "Unknown", // 0x0042 "Unknown", // 0x0043 "Unknown", // 0x0044 "Unknown", // 0x0045 "Unknown", // 0x0046 "Unknown", // 0x0047 "Unknown", // 0x0048 "Unknown", // 0x0049 "Unknown", // 0x004A "Unknown", // 0x004B "Unknown", // 0x004C "Unknown", // 0x004D "Unknown", // 0x004E "Unknown", // 0x004F "Unknown", // 0x0050 "Unknown", // 0x0051 "Unknown", // 0x0052 "TRANS_WAIT_NMPIPE", // 0x0053 "TRANS_CALL_NMPIPE" // 0x0054 }; const char *smb_transaction2_sub_command_strings[TRANS2_SUBCOM_MAX] = { "TRANS2_OPEN2", // 0x0000 "TRANS2_FIND_FIRST2", // 0x0001 "TRANS2_FIND_NEXT2", // 0x0002 "TRANS2_QUERY_FS_INFORMATION", // 0x0003 "TRANS2_SET_FS_INFORMATION", // 0x0004 "TRANS2_QUERY_PATH_INFORMATION", // 0x0005 "TRANS2_SET_PATH_INFORMATION", // 0x0006 "TRANS2_QUERY_FILE_INFORMATION", // 0x0007 "TRANS2_SET_FILE_INFORMATION", // 0x0008 "TRANS2_FSCTL", // 0x0009 "TRANS2_IOCTL2", // 0x000A "TRANS2_FIND_NOTIFY_FIRST", // 0x000B "TRANS2_FIND_NOTIFY_NEXT", // 0x000C "TRANS2_CREATE_DIRECTORY", // 0x000D "TRANS2_SESSION_SETUP", // 0x000E "Unknown", // 0x000F "TRANS2_GET_DFS_REFERRAL", // 0x0010 "TRANS2_REPORT_DFS_INCONSISTENCY" // 0x0011 }; const char *smb_nt_transact_sub_command_strings[NT_TRANSACT_SUBCOM_MAX] = { "Unknown", // 0x0000 "NT_TRANSACT_CREATE", // 0x0001 "NT_TRANSACT_IOCTL", // 0x0002 "NT_TRANSACT_SET_SECURITY_DESC", // 0x0003 "NT_TRANSACT_NOTIFY_CHANGE", // 0x0004 "NT_TRANSACT_RENAME", // 0x0005 "NT_TRANSACT_QUERY_SECURITY_DESC" // 0x0006 }; /******************************************************************** * Private function prototypes ********************************************************************/ static inline int DCE2_SmbType(DCE2_SmbSsnData *); static inline void DCE2_SmbSetValidWordCount(uint8_t, uint8_t, uint8_t); static inline bool DCE2_SmbIsValidWordCount(uint8_t, uint8_t, uint8_t); static inline void DCE2_SmbSetValidByteCount(uint8_t, uint8_t, uint16_t, uint16_t); static inline bool DCE2_SmbIsValidByteCount(uint8_t, uint8_t, uint16_t); static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData *, const NbssHdr *); static DCE2_SmbRequestTracker * DCE2_SmbInspect(DCE2_SmbSsnData *, const SmbNtHdr *); static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData *, const SmbNtHdr *); static uint32_t DCE2_IgnoreJunkData(const uint8_t *, uint16_t, uint32_t); static inline DCE2_Ret DCE2_SmbHandleSegmentation(DCE2_Buffer **, const uint8_t *, uint32_t, uint32_t); static inline DCE2_Buffer ** DCE2_SmbGetSegBuffer(DCE2_SmbSsnData *); static inline uint32_t * DCE2_SmbGetIgnorePtr(DCE2_SmbSsnData *); static inline DCE2_SmbDataState * DCE2_SmbGetDataState(DCE2_SmbSsnData *); static inline bool DCE2_SmbIsSegBuffer(DCE2_SmbSsnData *, const uint8_t *); static inline void DCE2_SmbSegAlert(DCE2_SmbSsnData *, DCE2_Event); static inline bool DCE2_SmbIsRawData(DCE2_SmbSsnData *); static void DCE2_SmbProcessRawData(DCE2_SmbSsnData *, const uint8_t *, uint32_t); static DCE2_SmbComInfo * DCE2_SmbCheckCommand(DCE2_SmbSsnData *, const SmbNtHdr *, const uint8_t, const uint8_t *, uint32_t); static void DCE2_SmbProcessCommand(DCE2_SmbSsnData *, const SmbNtHdr *, const uint8_t *, uint32_t); static inline DCE2_Ret DCE2_SmbCheckData(DCE2_SmbSsnData *, const uint8_t *, const uint8_t *, const uint32_t, const uint16_t, const uint32_t, uint16_t); static inline DCE2_Ret DCE2_SmbValidateTransactionFields(DCE2_SmbSsnData *, const uint8_t *, const uint8_t *, const uint32_t, const uint16_t, const uint32_t, const uint32_t, const uint32_t, const uint32_t, const uint32_t, const uint32_t, const uint32_t, const uint32_t); static inline DCE2_Ret DCE2_SmbValidateTransactionSent(DCE2_SmbSsnData *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); static inline DCE2_Ret DCE2_SmbCheckTransDataParams(DCE2_SmbSsnData *, const uint8_t *, const uint8_t *, const uint32_t, const uint16_t, const uint32_t, const uint32_t, const uint32_t, const uint32_t); static inline DCE2_Ret DCE2_SmbCheckTotalCount(DCE2_SmbSsnData *, const uint32_t, const uint32_t, const uint32_t); static inline void DCE2_SmbCheckFmtData(DCE2_SmbSsnData *, const uint32_t, const uint16_t, const uint8_t, const uint16_t, const uint16_t); static inline DCE2_Ret DCE2_SmbCheckAndXOffset(DCE2_SmbSsnData *, const uint8_t *, const uint8_t *, const uint32_t); static inline void DCE2_SmbInvalidShareCheck(DCE2_SmbSsnData *, const SmbNtHdr *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbTransactionGetName(const uint8_t *, uint32_t, uint16_t, bool); static inline bool DCE2_SmbIsTransactionComplete(DCE2_SmbTransactionTracker *); static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbUpdateTransSecondary(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbUpdateTransResponse(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbClose(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbRename(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbRead(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbWrite(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbLockAndRead(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbWriteAndUnlock(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbReadRaw(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbWriteRaw(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbWriteComplete(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static inline DCE2_Ret DCE2_SmbTransactionReq(DCE2_SmbSsnData *, DCE2_SmbTransactionTracker *, const uint8_t *, uint32_t, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbTransactionSecondary(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbWriteAndClose(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbReadAndX(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbWriteAndX(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static inline DCE2_Ret DCE2_SmbTrans2Open2Req(DCE2_SmbSsnData *, const uint8_t *, uint32_t, bool); static inline DCE2_Ret DCE2_SmbTrans2QueryFileInfoReq(DCE2_SmbSsnData *, const uint8_t *, uint32_t); static inline DCE2_Ret DCE2_SmbTrans2SetFileInfoReq(DCE2_SmbSsnData *, const uint8_t *, uint32_t, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbTransaction2(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbTransaction2Secondary(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbTreeConnect(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbTreeDisconnect(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbNegotiate(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbLogoffAndX(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbTreeConnectAndX(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static inline DCE2_Ret DCE2_SmbNtTransactCreateReq(DCE2_SmbSsnData *, const uint8_t *, uint32_t, bool); static DCE2_Ret DCE2_SmbNtTransact(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbNtTransactSecondary(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData *, const SmbNtHdr *, const DCE2_SmbComInfo *, const uint8_t *, uint32_t); static inline DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData *, const uint16_t, const uint8_t *, uint32_t, uint64_t); static inline DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData *, const uint8_t *, uint32_t); static void DCE2_SmbProcessFileData(DCE2_SmbSsnData *, DCE2_SmbFileTracker *, const uint8_t *, uint32_t, bool); static inline DCE2_SmbRequestTracker * DCE2_SmbNewRequestTracker(DCE2_SmbSsnData *, const SmbNtHdr *); static inline DCE2_Ret DCE2_SmbBufferTransactionData(DCE2_SmbTransactionTracker *, const uint8_t *, uint16_t, uint16_t); static inline DCE2_Ret DCE2_SmbBufferTransactionParameters(DCE2_SmbTransactionTracker *, const uint8_t *, uint16_t, uint16_t); static inline DCE2_SmbRequestTracker * DCE2_SmbFindRequestTracker(DCE2_SmbSsnData *, const SmbNtHdr *); static inline void DCE2_SmbRemoveRequestTracker(DCE2_SmbSsnData *, DCE2_SmbRequestTracker *); static void DCE2_SmbInsertUid(DCE2_SmbSsnData *, const uint16_t); static DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData *, const uint16_t); static void DCE2_SmbRemoveUid(DCE2_SmbSsnData *ssd, const uint16_t); static void DCE2_SmbInsertTid(DCE2_SmbSsnData *, const uint16_t, const bool); static DCE2_Ret DCE2_SmbFindTid(DCE2_SmbSsnData *, const uint16_t); static bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData *, const uint16_t); static void DCE2_SmbRemoveTid(DCE2_SmbSsnData *, const uint16_t); static DCE2_SmbFileTracker * DCE2_SmbNewFileTracker(DCE2_SmbSsnData *, const uint16_t, const uint16_t, const uint16_t); static void DCE2_SmbQueueTmpFileTracker(DCE2_SmbSsnData *, DCE2_SmbRequestTracker *, const uint16_t, const uint16_t); static inline DCE2_SmbFileTracker * DCE2_SmbGetTmpFileTracker(DCE2_SmbRequestTracker *); static inline void DCE2_SmbEmptyTmpFileTrackerQueue(DCE2_SmbRequestTracker *); static DCE2_SmbFileTracker * DCE2_SmbDequeueTmpFileTracker(DCE2_SmbSsnData *, DCE2_SmbRequestTracker *, const uint16_t); static inline DCE2_SmbFileTracker * DCE2_SmbGetFileTracker(DCE2_SmbSsnData *, const uint16_t); static DCE2_SmbFileTracker * DCE2_SmbFindFileTracker(DCE2_SmbSsnData *, const uint16_t, const uint16_t, const uint16_t); static void DCE2_SmbRemoveFileTracker(DCE2_SmbSsnData *, DCE2_SmbFileTracker *); static inline void DCE2_SmbCleanFileTracker(DCE2_SmbFileTracker *); static inline void DCE2_SmbCleanTransactionTracker(DCE2_SmbTransactionTracker *); static inline void DCE2_SmbCleanRequestTracker(DCE2_SmbRequestTracker *); static int DCE2_SmbUidTidFidCompare(const void *, const void *); static void DCE2_SmbFileTrackerDataFree(void *); static void DCE2_SmbRequestTrackerDataFree(void *); static inline SFSnortPacket * DCE2_SmbGetRpkt(DCE2_SmbSsnData *, const uint8_t **, uint32_t *, DCE2_RpktType); static inline void DCE2_SmbReturnRpkt(void); static inline void DCE2_SmbSetFileName(char *); static char * DCE2_SmbGetString(const uint8_t *, uint32_t, bool, bool); static inline void DCE2_SmbResetFileChunks(DCE2_SmbFileTracker *); static inline void DCE2_SmbAbortFileAPI(DCE2_SmbSsnData *); static inline void DCE2_SmbFinishFileAPI(DCE2_SmbSsnData *); static inline void DCE2_SmbSetNewFileAPIFileTracker(DCE2_SmbSsnData *); static int DCE2_SmbFileOffsetCompare(const void *, const void *); static void DCE2_SmbFileChunkFree(void *); static DCE2_Ret DCE2_SmbHandleOutOfOrderFileData(DCE2_SmbSsnData *, DCE2_SmbFileTracker *, const uint8_t *, uint32_t, bool); static DCE2_Ret DCE2_SmbFileAPIProcess(DCE2_SmbSsnData *, DCE2_SmbFileTracker *, const uint8_t *, uint32_t, bool); static inline void DCE2_SmbRemoveFileTrackerFromRequestTrackers(DCE2_SmbSsnData *, DCE2_SmbFileTracker *); #ifdef ACTIVE_RESPONSE static void DCE2_SmbInjectDeletePdu(DCE2_SmbSsnData *, DCE2_SmbFileTracker *); static void DCE2_SmbFinishFileBlockVerdict(DCE2_SmbSsnData *); static File_Verdict DCE2_SmbGetFileVerdict(void *, void *); #endif /******************************************************************** * Function: DCE2_SmbType() * * Purpose: * Since Windows and Samba don't seem to care or even look at the * actual flag in the SMB header, make the determination based on * whether from client or server. * * Arguments: * DCE2_SmbSsnData * - session data structure that has the raw * packet and packet flags to make determination * * Returns: * SMB_TYPE__REQUEST if packet is from client * SMB_TYPE__RESPONSE if packet is from server * ********************************************************************/ static inline int DCE2_SmbType(DCE2_SmbSsnData *ssd) { if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) return SMB_TYPE__REQUEST; else return SMB_TYPE__RESPONSE; } /******************************************************************** * Function: DCE2_SmbSetValidWordCount() * * Purpose: * Initializes global data for valid word counts for supported * SMB command requests and responses. * * Arguments: * uint8_t - the SMB command code * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE * uint8_t - the valid word count * * Returns: None * ********************************************************************/ static inline void DCE2_SmbSetValidWordCount(uint8_t com, uint8_t resp, uint8_t wct) { smb_wcts[com][resp][wct/8] |= (1 << (wct % 8)); } /******************************************************************** * Function: DCE2_SmbIsValidWordCount() * * Purpose: * Checks if a word count is valid for a given command request * or response. * * Arguments: * uint8_t - the SMB command code * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE * uint8_t - the word count to validate * * Returns: * bool - true if valid, false if not valid. * ********************************************************************/ static inline bool DCE2_SmbIsValidWordCount(uint8_t com, uint8_t resp, uint8_t wct) { return (smb_wcts[com][resp][wct/8] & (1 << (wct % 8))) ? true : false; } /******************************************************************** * Function: DCE2_SmbSetValidByteCount() * * Purpose: * Initializes global data for valid byte counts as a range for * supported SMB command requests and responses. * Since a byte count is 2 bytes, a 4 byte type is used to store * the range. The maximum is in the most significant 2 bytes and * the minimum in the least significant 2 bytes. * * Arguments: * uint8_t - the SMB command code * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE * uint8_t - the minimum word count that is valid * uint8_t - the maximum word count that is valid * * Returns: None * ********************************************************************/ static inline void DCE2_SmbSetValidByteCount(uint8_t com, uint8_t resp, uint16_t min, uint16_t max) { smb_bccs[com][resp][0] = min; smb_bccs[com][resp][1] = max; } /******************************************************************** * Function: DCE2_SmbIsValidByteCount() * * Purpose: * Checks if a byte count is valid for a given command request * or response. * * Arguments: * uint8_t - the SMB command code * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE * uint8_t - the byte count to validate * * Returns: * bool - true if valid, false if not valid. * ********************************************************************/ static inline bool DCE2_SmbIsValidByteCount(uint8_t com, uint8_t resp, uint16_t bcc) { return ((bcc < smb_bccs[com][resp][0]) || (bcc > smb_bccs[com][resp][1])) ? false : true; } /******************************************************************** * Function: DCE2_SmbGetMinByteCount() * * Purpose: * Returns the minimum byte count for the given command request * or response. * * Arguments: * uint8_t - the SMB command code * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE * * Returns: * uint16_t - the minimum byte count * ********************************************************************/ static inline uint16_t DCE2_SmbGetMinByteCount(uint8_t com, uint8_t resp) { return smb_bccs[com][resp][0]; } /******************************************************************** * Function: DCE2_SmbInitGlobals() * * Purpose: * Initializes global variables for SMB processing. * Sets up the functions and valid word and byte counts for SMB * commands. * Sets up AndX chain mappings and valid command chaining for * supported policies. * * Arguments: None * * Returns: None * ********************************************************************/ void DCE2_SmbInitGlobals(void) { int com; DCE2_Policy policy; SmbAndXCom andx; int i; memset(&smb_wcts, 0, sizeof(smb_wcts)); memset(&smb_bccs, 0, sizeof(smb_bccs)); // Sets up the function to call for the command and valid word and byte // counts for the command. Ensuring valid word and byte counts is very // important to processing the command as it will assume the command is // legitimate and can access data that is acutally there. Note that // commands with multiple word counts indicate a different command // structure, however most, if not all just have an extended version // of the structure for which the extended part isn't used. If the // extended part of a command structure needs to be used, be sure to // check the word count in the command function before accessing data // in the extended version of the command structure. for (com = 0; com < SMB_MAX_NUM_COMS; com++) { switch (com) { case SMB_COM_OPEN: smb_com_funcs[com] = DCE2_SmbOpen; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_CREATE: smb_com_funcs[com] = DCE2_SmbCreate; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_CLOSE: smb_com_funcs[com] = DCE2_SmbClose; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_RENAME: smb_com_funcs[com] = DCE2_SmbRename; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 1); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 4, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_READ: smb_com_funcs[com] = DCE2_SmbRead; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX); break; case SMB_COM_WRITE: smb_com_funcs[com] = DCE2_SmbWrite; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_CREATE_NEW: smb_com_funcs[com] = DCE2_SmbCreateNew; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_LOCK_AND_READ: smb_com_funcs[com] = DCE2_SmbLockAndRead; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX); break; case SMB_COM_WRITE_AND_UNLOCK: smb_com_funcs[com] = DCE2_SmbWriteAndUnlock; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_READ_RAW: smb_com_funcs[com] = DCE2_SmbReadRaw; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8); // With optional OffsetHigh DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); // Response is raw data, i.e. without SMB break; case SMB_COM_WRITE_RAW: smb_com_funcs[com] = DCE2_SmbWriteRaw; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); // With optional OffsetHigh DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); // Interim server response DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_WRITE_COMPLETE: // Final server response to SMB_COM_WRITE_RAW smb_com_funcs[com] = DCE2_SmbWriteComplete; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_TRANSACTION: smb_com_funcs[com] = DCE2_SmbTransaction; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; // Word count depends on setup count //for (i = 14; i < 256; i++) // DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i); // In reality, all subcommands of SMB_COM_TRANSACTION requests // have a setup count of 2 words. DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 16); // \PIPE\LANMAN // Not something the preprocessor is looking at as it // doesn't carry DCE/RPC but don't want to false positive // on the preprocessor event. DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); // Word count depends on setup count //for (i = 10; i < 256; i++) // DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i); // In reality, all subcommands of SMB_COM_TRANSACTION responses // have a setup count of 0 words. DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10); // Interim server response // When client sends an incomplete transaction and needs to // send TransactionSecondary requests to complete request. DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); // Exception will be made for Interim responses when // byte count is checked. DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; case SMB_COM_TRANSACTION_SECONDARY: smb_com_funcs[com] = DCE2_SmbTransactionSecondary; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8); // Response is an SMB_COM_TRANSACTION DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); break; case SMB_COM_WRITE_AND_CLOSE: smb_com_funcs[com] = DCE2_SmbWriteAndClose; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 6); // For some reason MS-CIFS specifies a version of this command // with 6 extra words (12 bytes) of reserved, i.e. useless data. // Maybe had intentions of extending and defining the data at // some point, but there is no documentation that I could find // that does. DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_OPEN_ANDX: smb_com_funcs[com] = DCE2_SmbOpenAndX; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 15); // Extended response DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); // MS-SMB says that Windows 2000, XP and Vista set this to // some arbitrary value that is ignored on receipt. //DCE2_SmbSetValidByteCount(com, SMB_TYPE__RESPONSE, 0, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; case SMB_COM_READ_ANDX: smb_com_funcs[com] = DCE2_SmbReadAndX; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); // With optional OffsetHigh DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 12); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; case SMB_COM_WRITE_ANDX: smb_com_funcs[com] = DCE2_SmbWriteAndX; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); // With optional OffsetHigh DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 6); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_TRANSACTION2: smb_com_funcs[com] = DCE2_SmbTransaction2; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; // Word count depends on setup count //for (i = 14; i < 256; i++) // DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i); // In reality, all subcommands of SMB_COM_TRANSACTION2 // requests have a setup count of 1 word. DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15); // Word count depends on setup count //for (i = 10; i < 256; i++) // DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i); // In reality, all subcommands of SMB_COM_TRANSACTION2 // responses have a setup count of 0 or 1 word. DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 11); // Interim server response DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); // Exception will be made for Interim responses when // byte count is checked. DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; case SMB_COM_TRANSACTION2_SECONDARY: smb_com_funcs[com] = DCE2_SmbTransaction2Secondary; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 9); // Response is an SMB_COM_TRANSACTION2 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); break; case SMB_COM_TREE_CONNECT: smb_com_funcs[com] = DCE2_SmbTreeConnect; smb_deprecated_coms[com] = true; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 6, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_TREE_DISCONNECT: smb_com_funcs[com] = DCE2_SmbTreeDisconnect; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_NEGOTIATE: // Not doing anything with this command right now. smb_com_funcs[com] = DCE2_SmbNegotiate; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 13); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 17); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); // This can vary depending on dialect so just set wide. DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; case SMB_COM_SESSION_SETUP_ANDX: smb_com_funcs[com] = DCE2_SmbSessionSetupAndX; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 13); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 4); // These can vary so just set wide. DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; case SMB_COM_LOGOFF_ANDX: smb_com_funcs[com] = DCE2_SmbLogoffAndX; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); // Windows responds to a LogoffAndX => SessionSetupAndX with just a // LogoffAndX and with the word count field containing 3, but only // has 2 words DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); break; case SMB_COM_TREE_CONNECT_ANDX: smb_com_funcs[com] = DCE2_SmbTreeConnectAndX; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 4); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); // Extended response DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 2, UINT16_MAX); break; case SMB_COM_NT_TRANSACT: smb_com_funcs[com] = DCE2_SmbNtTransact; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; // Word count depends on setup count // In reality, all subcommands of SMB_COM_NT_TRANSACT // requests have a setup count of 0 or 4 words. //for (i = 19; i < 256; i++) // DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, i); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 19); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 23); // Word count depends on setup count // In reality, all subcommands of SMB_COM_NT_TRANSACT // responses have a setup count of 0 or 1 word. //for (i = 18; i < 256; i++) // DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, i); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 18); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19); // Interim server response DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); // Exception will be made for Interim responses when // byte count is checked. DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; case SMB_COM_NT_TRANSACT_SECONDARY: smb_com_funcs[com] = DCE2_SmbNtTransactSecondary; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 18); // Response is an SMB_COM_NT_TRANSACT DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); break; case SMB_COM_NT_CREATE_ANDX: smb_com_funcs[com] = DCE2_SmbNtCreateAndX; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 24); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 34); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 26); // Extended response - though there are actually 50 words DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 42); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); // MS-SMB indicates that this field should be 0 but may be // sent uninitialized so basically ignore it. //DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; default: smb_com_funcs[com] = NULL; smb_deprecated_coms[com] = false; smb_unusual_coms[com] = false; // Just set to all valid since the specific command won't // be processed. Don't want to false positive on these. for (i = 0; i < 256; i++) { DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, (uint8_t)i); DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, (uint8_t)i); } DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); break; } } // Maps commands for use in quickly determining if a command // is chainable and what command it is. for (com = 0; com < SMB_MAX_NUM_COMS; com++) { switch (com) { case SMB_COM_SESSION_SETUP_ANDX: smb_chain_map[com] = SMB_ANDX_COM__SESSION_SETUP_ANDX; break; case SMB_COM_LOGOFF_ANDX: smb_chain_map[com] = SMB_ANDX_COM__LOGOFF_ANDX; break; case SMB_COM_TREE_CONNECT_ANDX: smb_chain_map[com] = SMB_ANDX_COM__TREE_CONNECT_ANDX; break; case SMB_COM_OPEN_ANDX: smb_chain_map[com] = SMB_ANDX_COM__OPEN_ANDX; break; case SMB_COM_NT_CREATE_ANDX: smb_chain_map[com] = SMB_ANDX_COM__NT_CREATE_ANDX; break; case SMB_COM_WRITE_ANDX: smb_chain_map[com] = SMB_ANDX_COM__WRITE_ANDX; break; case SMB_COM_READ_ANDX: smb_chain_map[com] = SMB_ANDX_COM__READ_ANDX; break; default: smb_chain_map[com] = SMB_ANDX_COM__NONE; break; } } // Sets up the valid command chaining combinations per policy for (policy = DCE2_POLICY__NONE; policy < DCE2_POLICY__MAX; policy++) { for (andx = SMB_ANDX_COM__NONE; andx < SMB_ANDX_COM__MAX; andx++) { /* com is the chained command or com2 */ for (com = 0; com < SMB_MAX_NUM_COMS; com++) { DCE2_SmbComFunc com_func = NULL; switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: switch (andx) { case SMB_ANDX_COM__SESSION_SETUP_ANDX: switch (com) { case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_OPEN: case SMB_COM_OPEN_ANDX: case SMB_COM_CREATE: case SMB_COM_CREATE_NEW: com_func = smb_com_funcs[com]; break; case SMB_COM_TRANSACTION: if (policy == DCE2_POLICY__WIN2000) com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__LOGOFF_ANDX: switch (com) { case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_TREE_CONNECT_ANDX: // Only for responses com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__TREE_CONNECT_ANDX: switch (com) { case SMB_COM_OPEN: case SMB_COM_CREATE: case SMB_COM_CREATE_NEW: com_func = smb_com_funcs[com]; break; case SMB_COM_TRANSACTION: if (policy == DCE2_POLICY__WIN2000) com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__OPEN_ANDX: break; case SMB_ANDX_COM__NT_CREATE_ANDX: switch (com) { case SMB_COM_READ_ANDX: // Only for normal files com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__WRITE_ANDX: switch (com) { case SMB_COM_CLOSE: case SMB_COM_WRITE_ANDX: case SMB_COM_READ: case SMB_COM_READ_ANDX: com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__READ_ANDX: break; default: break; } break; case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: switch (andx) { case SMB_ANDX_COM__SESSION_SETUP_ANDX: switch (com) { case SMB_COM_LOGOFF_ANDX: case SMB_COM_TREE_CONNECT: case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_TREE_DISCONNECT: case SMB_COM_OPEN_ANDX: case SMB_COM_NT_CREATE_ANDX: case SMB_COM_CLOSE: case SMB_COM_READ_ANDX: com_func = smb_com_funcs[com]; break; case SMB_COM_WRITE: if ((policy == DCE2_POLICY__SAMBA_3_0_22) || (policy == DCE2_POLICY__SAMBA_3_0_20)) com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__LOGOFF_ANDX: switch (com) { case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_TREE_DISCONNECT: com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__TREE_CONNECT_ANDX: switch (com) { case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_LOGOFF_ANDX: case SMB_COM_TREE_DISCONNECT: case SMB_COM_OPEN_ANDX: case SMB_COM_NT_CREATE_ANDX: case SMB_COM_CLOSE: case SMB_COM_WRITE: case SMB_COM_READ_ANDX: com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__OPEN_ANDX: switch (com) { case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_LOGOFF_ANDX: case SMB_COM_TREE_CONNECT: case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_TREE_DISCONNECT: case SMB_COM_OPEN_ANDX: case SMB_COM_NT_CREATE_ANDX: case SMB_COM_CLOSE: case SMB_COM_WRITE: case SMB_COM_READ_ANDX: com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__NT_CREATE_ANDX: switch (com) { case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_TREE_CONNECT: case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_OPEN_ANDX: case SMB_COM_NT_CREATE_ANDX: case SMB_COM_WRITE: case SMB_COM_READ_ANDX: com_func = smb_com_funcs[com]; break; case SMB_COM_LOGOFF_ANDX: case SMB_COM_TREE_DISCONNECT: case SMB_COM_CLOSE: if ((policy == DCE2_POLICY__SAMBA) || (policy == DCE2_POLICY__SAMBA_3_0_37)) com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__WRITE_ANDX: switch (com) { case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_LOGOFF_ANDX: case SMB_COM_TREE_CONNECT: case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_OPEN_ANDX: case SMB_COM_NT_CREATE_ANDX: case SMB_COM_CLOSE: case SMB_COM_WRITE: case SMB_COM_READ_ANDX: case SMB_COM_WRITE_ANDX: com_func = smb_com_funcs[com]; break; default: break; } break; case SMB_ANDX_COM__READ_ANDX: switch (com) { case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_WRITE: com_func = smb_com_funcs[com]; break; case SMB_COM_LOGOFF_ANDX: case SMB_COM_TREE_CONNECT: case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_TREE_DISCONNECT: case SMB_COM_OPEN_ANDX: case SMB_COM_NT_CREATE_ANDX: case SMB_COM_CLOSE: case SMB_COM_READ_ANDX: if ((policy == DCE2_POLICY__SAMBA) || (policy == DCE2_POLICY__SAMBA_3_0_37)) com_func = smb_com_funcs[com]; break; default: break; } break; default: break; } break; default: break; } smb_chain_funcs[policy][andx][com] = com_func; } } } } /******************************************************************** * Function: DCE2_SmbInitRdata() * * Purpose: * Initializes the reassembled packet structure for an SMB * reassembled packet. Uses WriteAndX and ReadAndX. * TODO Use command that was used when reassembly occurred. * One issue with this is that multiple different write/read * commands can be used to write/read the full DCE/RPC * request/response. * * Arguments: * uint8_t * - pointer to the start of the NetBIOS header where * data initialization should start. * int dir - FLAG_FROM_CLIENT or FLAG_FROM_SERVER * * Returns: None * ********************************************************************/ void DCE2_SmbInitRdata(uint8_t *nb_ptr, int dir) { NbssHdr *nb_hdr = (NbssHdr *)nb_ptr; SmbNtHdr *smb_hdr = (SmbNtHdr *)((uint8_t *)nb_hdr + sizeof(NbssHdr)); nb_hdr->type = NBSS_SESSION_TYPE__MESSAGE; memcpy((void *)smb_hdr->smb_idf, (void *)"\xffSMB", sizeof(smb_hdr->smb_idf)); if (dir == FLAG_FROM_CLIENT) { SmbWriteAndXReq *writex = (SmbWriteAndXReq *)((uint8_t *)smb_hdr + sizeof(SmbNtHdr)); uint16_t offset = sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq); smb_hdr->smb_com = SMB_COM_WRITE_ANDX; smb_hdr->smb_flg = 0x00; writex->smb_wct = 12; writex->smb_com2 = SMB_COM_NO_ANDX_COMMAND; writex->smb_doff = SmbHtons(&offset); } else { SmbReadAndXResp *readx = (SmbReadAndXResp *)((uint8_t *)smb_hdr + sizeof(SmbNtHdr)); uint16_t offset = sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp); smb_hdr->smb_com = SMB_COM_READ_ANDX; smb_hdr->smb_flg = 0x80; readx->smb_wct = 12; readx->smb_com2 = SMB_COM_NO_ANDX_COMMAND; readx->smb_doff = SmbHtons(&offset); } } /******************************************************************** * Function: DCE2_SmbSetRdata() * * Purpose: * When a reassembled packet is needed this function is called to * fill in appropriate fields to make the reassembled packet look * correct from an SMB standpoint. * * Arguments: * DCE2_SmbSsnData * - the session data structure. * uint8_t * - pointer to the start of the NetBIOS header where * data initialization should start. * uint16_t - the length of the connection-oriented DCE/RPC data. * * Returns: None * ********************************************************************/ void DCE2_SmbSetRdata(DCE2_SmbSsnData *ssd, uint8_t *nb_ptr, uint16_t co_len) { NbssHdr *nb_hdr = (NbssHdr *)nb_ptr; SmbNtHdr *smb_hdr = (SmbNtHdr *)((uint8_t *)nb_hdr + sizeof(NbssHdr)); uint16_t uid = (ssd->cur_rtracker == NULL) ? 0 : ssd->cur_rtracker->uid; uint16_t tid = (ssd->cur_rtracker == NULL) ? 0 : ssd->cur_rtracker->tid; DCE2_SmbFileTracker *ftracker = (ssd->cur_rtracker == NULL) ? NULL : ssd->cur_rtracker->ftracker; smb_hdr->smb_uid = SmbHtons((const uint16_t *)&uid); smb_hdr->smb_tid = SmbHtons((const uint16_t *)&tid); if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) { SmbWriteAndXReq *writex = (SmbWriteAndXReq *)((uint8_t *)smb_hdr + sizeof(SmbNtHdr)); uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq) + co_len; /* The data will get truncated anyway since we can only fit * 64K in the reassembly buffer */ if (nb_len > UINT16_MAX) nb_len = UINT16_MAX; nb_hdr->length = htons((uint16_t)nb_len); if ((ftracker != NULL) && (ftracker->fid > 0)) { uint16_t fid = (uint16_t)ftracker->fid; writex->smb_fid = SmbHtons(&fid); } else { writex->smb_fid = 0; } writex->smb_countleft = SmbHtons(&co_len); writex->smb_dsize = SmbHtons(&co_len); writex->smb_bcc = SmbHtons(&co_len); } else { SmbReadAndXResp *readx = (SmbReadAndXResp *)((uint8_t *)smb_hdr + sizeof(SmbNtHdr)); uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp) + co_len; /* The data will get truncated anyway since we can only fit * 64K in the reassembly buffer */ if (nb_len > UINT16_MAX) nb_len = UINT16_MAX; nb_hdr->length = htons((uint16_t)nb_len); readx->smb_remaining = SmbHtons(&co_len); readx->smb_dsize = SmbHtons(&co_len); readx->smb_bcc = SmbHtons(&co_len); } } /******************************************************************** * Function: DCE2_SmbSsnInit() * * Purpose: * Allocates and initializes a new session data structure. * * Arguments: None * * Returns: * DCE2_SmbSsnData * - a new initialized session data structure. * ********************************************************************/ DCE2_SmbSsnData * DCE2_SmbSsnInit(SFSnortPacket *p) { DCE2_SmbSsnData *ssd = (DCE2_SmbSsnData *)DCE2_Alloc(sizeof(DCE2_SmbSsnData), DCE2_MEM_TYPE__SMB_SSN); if (ssd == NULL) return NULL; ssd->dialect_index = DCE2_SENTINEL; ssd->max_outstanding_requests = 10; // Until Negotiate/SessionSetupAndX ssd->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; ssd->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; ssd->uid = DCE2_SENTINEL; ssd->tid = DCE2_SENTINEL; ssd->ftracker.fid = DCE2_SENTINEL; ssd->rtracker.mid = DCE2_SENTINEL; ssd->max_file_depth = _dpd.fileAPI->get_max_file_depth(); DCE2_ResetRopts(&ssd->sd.ropts); dce2_stats.smb_sessions++; return ssd; } /******************************************************************** * Function: DCE2_NbssHdrChecks() * * Purpose: * Does validation of the NetBIOS header. SMB will only run over * the Session Message type. On port 139, there is always an * initial Session Request / Session Positive/Negative response * followed by the normal SMB conversation, i.e. Negotiate, * SessionSetupAndX, etc. * Side effects are potential alerts for anomolous behavior. * * Arguments: * DCE2_SmbSsnData * - the session data structure. * const NbssHdr * - pointer to the NetBIOS Session Service * header structure. Size is already validated. * * Returns: * DCE2_Ret - DCE2_RET__SUCCESS if all goes well and processing * should continue. * DCE2_RET__IGNORE if it's not something we need to * look at. * DCE2_RET__ERROR if an invalid NetBIOS Session * Service type is found. * ********************************************************************/ static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData *ssd, const NbssHdr *nb_hdr) { const SFSnortPacket *p = ssd->sd.wire_pkt; bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t *)nb_hdr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "NetBIOS Session Service type: ")); switch (NbssType(nb_hdr)) { case NBSS_SESSION_TYPE__MESSAGE: /* Only want to look at session messages */ DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Session Message\n")); if (!DCE2_SmbIsRawData(ssd)) { uint32_t nb_len = NbssLen(nb_hdr); if (nb_len == 0) return DCE2_RET__IGNORE; if (nb_len < sizeof(SmbNtHdr)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "NetBIOS SS len(%u) < SMB header len(%u).\n", sizeof(SmbNtHdr), sizeof(NbssHdr) + nb_len)); if (is_seg_buf) DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_NB_LT_SMBHDR); else DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_SMBHDR, nb_len, sizeof(SmbNtHdr)); return DCE2_RET__IGNORE; } } return DCE2_RET__SUCCESS; case NBSS_SESSION_TYPE__REQUEST: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Session Request\n")); if (DCE2_SsnFromServer(p)) { if (is_seg_buf) DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_NBSS_TYPE); else DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_NBSS_TYPE); } break; case NBSS_SESSION_TYPE__POS_RESPONSE: case NBSS_SESSION_TYPE__NEG_RESPONSE: case NBSS_SESSION_TYPE__RETARGET_RESPONSE: DCE2_DEBUG_CODE(DCE2_DEBUG__SMB, if (NbssType(nb_hdr) == NBSS_SESSION_TYPE__POS_RESPONSE) printf("Positive Session Response\n"); else if (NbssType(nb_hdr) == NBSS_SESSION_TYPE__NEG_RESPONSE) printf("Negative Session Response\n"); else printf("Session Retarget Response\n");); if (DCE2_SsnFromClient(p)) { if (is_seg_buf) DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_NBSS_TYPE); else DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_NBSS_TYPE); } break; case NBSS_SESSION_TYPE__KEEP_ALIVE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Session Keep Alive\n")); break; default: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Invalid Session Service type: 0x%02X\n", NbssType(nb_hdr))); if (is_seg_buf) DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_NBSS_TYPE); else DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_NBSS_TYPE); return DCE2_RET__ERROR; } return DCE2_RET__IGNORE; } /******************************************************************** * Function: DCE2_SmbInspect() * * Purpose: * Determines whether the SMB command is something the preprocessor * needs to inspect. * This function returns a DCE2_SmbRequestTracker which tracks command * requests / responses. * * Arguments: * DCE2_SmbSsnData * - the session data structure. * const SmbNtHdr * - pointer to the SMB header. * * Returns: * DCE2_SmbRequestTracker * - NULL if it's not something we want to or can * inspect. * Otherwise an initialized structure if request * and the found structure if response. * ********************************************************************/ static DCE2_SmbRequestTracker * DCE2_SmbInspect(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr) { DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); DCE2_SmbRequestTracker *rtracker = NULL; int smb_com = SmbCom(smb_hdr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "SMB command: %s (0x%02X)\n", smb_com_strings[smb_com], smb_com)); if (smb_com_funcs[smb_com] == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Command isn't processed " "by preprocessor.\n")); return NULL; } // See if this is something we need to inspect if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST) { switch (smb_com) { case SMB_COM_NEGOTIATE: if (ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_MULTIPLE_NEGOTIATIONS); return NULL; } break; case SMB_COM_SESSION_SETUP_ANDX: break; case SMB_COM_TREE_CONNECT: case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_RENAME: case SMB_COM_LOGOFF_ANDX: if (DCE2_SmbFindUid(ssd, SmbUid(smb_hdr)) != DCE2_RET__SUCCESS) return NULL; break; default: if (DCE2_SmbFindTid(ssd, SmbTid(smb_hdr)) != DCE2_RET__SUCCESS) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Couldn't find Tid (%u)\n", SmbTid(smb_hdr))); return NULL; } if (DCE2_SmbIsTidIPC(ssd, SmbTid(smb_hdr))) { switch (smb_com) { case SMB_COM_OPEN: case SMB_COM_CREATE: case SMB_COM_CREATE_NEW: case SMB_COM_WRITE_AND_CLOSE: case SMB_COM_WRITE_AND_UNLOCK: case SMB_COM_READ: // Samba doesn't allow these commands under an IPC tree switch (policy) { case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Samba doesn't " "process this command under an IPC tree.\n")); return NULL; default: break; } break; case SMB_COM_READ_RAW: case SMB_COM_WRITE_RAW: // Samba and Windows Vista on don't allow these commands // under an IPC tree, whether or not the raw read/write // flag is set in the Negotiate capabilities. // Windows RSTs the connection and Samba FINs it. switch (policy) { case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Samba and " "Windows Vista on don't process this " "command under an IPC tree.\n")); return NULL; default: break; } break; case SMB_COM_LOCK_AND_READ: // The lock will fail so the read won't happen return NULL; default: break; } } else // Not IPC { switch (smb_com) { // These commands are only used for IPC case SMB_COM_TRANSACTION: case SMB_COM_TRANSACTION_SECONDARY: return NULL; case SMB_COM_READ_RAW: case SMB_COM_WRITE_RAW: // Windows Vista on don't seem to support these // commands, whether or not the raw read/write // flag is set in the Negotiate capabilities. // Windows RSTs the connection. switch (policy) { case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Windows Vista on don't process " "this command.\n")); return NULL; default: break; } break; default: break; } } break; } switch (smb_com) { case SMB_COM_TRANSACTION_SECONDARY: case SMB_COM_TRANSACTION2_SECONDARY: case SMB_COM_NT_TRANSACT_SECONDARY: rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); break; case SMB_COM_TRANSACTION: case SMB_COM_TRANSACTION2: case SMB_COM_NT_TRANSACT: // If there is already and existing request tracker // and the transaction is not complete, server will // return an error. rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); if (rtracker != NULL) break; // Fall through default: rtracker = DCE2_SmbNewRequestTracker(ssd, smb_hdr); break; } } else { rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); } DCE2_DEBUG_CODE(DCE2_DEBUG__SMB, if (rtracker == NULL) printf("Failed to get request tracker.\n");); return rtracker; } /******************************************************************** * Function: DCE2_SmbHdrChecks() * * Checks some relevant fields in the header to make sure they're * sane. * Side effects are potential alerts for anomolous behavior. * * Arguments: * DCE2_SmbSsnData * * Pointer to the session data structure. * SmbNtHdr * * Pointer to the header struct layed over the packet data. * * Returns: * DCE2_Ret * DCE2_RET__IGNORE if we should continue processing, but * ignore data because of the error. * DCE2_RET__SUCCESS if we should continue processing. * ********************************************************************/ static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr) { const SFSnortPacket *p = ssd->sd.wire_pkt; bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t *)smb_hdr); if ((DCE2_SsnFromServer(p) && (SmbType(smb_hdr) == SMB_TYPE__REQUEST)) || (DCE2_SsnFromClient(p) && (SmbType(smb_hdr) == SMB_TYPE__RESPONSE))) { if (is_seg_buf) DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_TYPE); else DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_TYPE); // Continue looking at traffic. Neither Windows nor Samba seem // to care, or even look at this flag } if ((SmbId(smb_hdr) != DCE2_SMB_ID) && (SmbId(smb_hdr) != DCE2_SMB2_ID)) { if (is_seg_buf) DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_ID); else DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_ID); return DCE2_RET__IGNORE; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_IgnoreJunkData() * * Purpose: * An evasion technique can be to put a bunch of junk data before * the actual SMB request and it seems the MS implementation has * no problem with it and seems to just ignore the data. This * function attempts to move past all the junk to get to the * actual NetBIOS message request. * * Arguments: * const uint8_t * - pointer to the current position in the data * being inspected * uint16_t - the amount of data left to look at * uint32_t - the amount of data to ignore if there doesn't seem * to be any junk data. Just use the length as if the bad * NetBIOS header was good. * * Returns: * uint32_t - the amount of bytes to ignore as junk. * ********************************************************************/ static uint32_t DCE2_IgnoreJunkData(const uint8_t *data_ptr, uint16_t data_len, uint32_t assumed_nb_len) { const uint8_t *tmp_ptr = data_ptr; uint32_t ignore_bytes = 0; /* Try to find \xffSMB and go back 8 bytes to beginning * of what should be a Netbios header with type Session * Message (\x00) - do appropriate buffer checks to make * sure the index is in bounds. Ignore all intervening * bytes */ while ((tmp_ptr + sizeof(uint32_t)) <= (data_ptr + data_len)) { if ((SmbId((SmbNtHdr *)tmp_ptr) == DCE2_SMB_ID) || (SmbId((SmbNtHdr *)tmp_ptr) == DCE2_SMB2_ID)) { break; } tmp_ptr++; } if ((tmp_ptr + sizeof(uint32_t)) > (data_ptr + data_len)) { ignore_bytes = data_len; } else { if ((tmp_ptr - sizeof(NbssHdr)) > data_ptr) ignore_bytes = (tmp_ptr - data_ptr) - sizeof(NbssHdr); else /* Just ignore whatever the bad NB header had as a length */ ignore_bytes = assumed_nb_len; } return ignore_bytes; } /******************************************************************** * Function: DCE2_SmbProcess() * * Purpose: * This is the main entry point for SMB processing. * * Arguments: * DCE2_SmbSsnData * - the session data structure. * * Returns: None * ********************************************************************/ void DCE2_SmbProcess(DCE2_SmbSsnData *ssd) { const SFSnortPacket *p = ssd->sd.wire_pkt; const uint8_t *data_ptr = p->payload; uint16_t data_len = p->payload_size; uint32_t *ignore_bytes = DCE2_SmbGetIgnorePtr(ssd); DCE2_Buffer **seg_buf = DCE2_SmbGetSegBuffer(ssd); DCE2_SmbDataState *data_state = DCE2_SmbGetDataState(ssd); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Processing SMB packet.\n")); dce2_stats.smb_pkts++; /* Have to account for segmentation. Even though stream will give * us larger chunks, we might end up in the middle of something */ while (data_len > 0) { // The amount of data needed in a given state to continue processing uint32_t data_need; NbssHdr *nb_hdr = NULL; SmbNtHdr *smb_hdr = NULL; uint32_t nb_len; const uint8_t *nb_ptr; DCE2_SmbRequestTracker *rtracker = NULL; DCE2_Ret status; // We are ignoring an entire PDU or junk data so state should be NETBIOS_HEADER // Note that it could be TCP segmented so ignore_bytes could be greater than // the amount of data we have if (*ignore_bytes) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Ignoring %u bytes\n", *ignore_bytes)); if (data_len <= *ignore_bytes) { *ignore_bytes -= data_len; return; } else { /* ignore bytes is less than UINT16_MAX */ DCE2_MOVE(data_ptr, data_len, (uint16_t)*ignore_bytes); *ignore_bytes = 0; } } switch (*data_state) { // This state is to verify it's a NetBIOS Session Message packet // and to get the length of the SMB PDU. Also does the SMB junk // data check. If it's not a Session Message the data isn't // processed since it won't be carrying SMB. case DCE2_SMB_DATA_STATE__NETBIOS_HEADER: data_need = sizeof(NbssHdr) - DCE2_BufferLength(*seg_buf); // See if there is enough data to process the NetBIOS header if (data_len < data_need) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data len(%u) < NetBIOS SS header(%u). " "Queueing data.\n", data_len, data_need)); if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, sizeof(NbssHdr)) != DCE2_RET__SUCCESS) { DCE2_BufferEmpty(*seg_buf); } return; } // Set the NetBIOS header structure if (DCE2_BufferIsEmpty(*seg_buf)) { nb_hdr = (NbssHdr *)data_ptr; } else { // If data already buffered add the remainder for the // size of the NetBIOS header if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, sizeof(NbssHdr)) != DCE2_RET__SUCCESS) { DCE2_BufferEmpty(*seg_buf); return; } nb_hdr = (NbssHdr *)DCE2_BufferData(*seg_buf); } nb_len = NbssLen(nb_hdr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "NetBIOS PDU length: %u\n", nb_len)); status = DCE2_NbssHdrChecks(ssd, nb_hdr); if (status != DCE2_RET__SUCCESS) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not a NetBIOS Session Message.\n")); if (status == DCE2_RET__IGNORE) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Valid NetBIOS header " "type so ignoring NetBIOS length bytes.\n")); *ignore_bytes = data_need + nb_len; } else // nb_ret == DCE2_RET__ERROR, i.e. invalid NetBIOS type { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not a valid NetBIOS " "header type so trying to find \\xffSMB to " "determine how many bytes to ignore.\n")); *ignore_bytes = DCE2_IgnoreJunkData(data_ptr, data_len, data_need + nb_len); } DCE2_BufferEmpty(*seg_buf); dce2_stats.smb_ignored_bytes += *ignore_bytes; continue; } if (!DCE2_BufferIsEmpty(*seg_buf)) DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); switch (ssd->pdu_state) { case DCE2_SMB_PDU_STATE__COMMAND: *data_state = DCE2_SMB_DATA_STATE__SMB_HEADER; break; case DCE2_SMB_PDU_STATE__RAW_DATA: *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU; // Continue here because of fall through below continue; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid SMB PDU " "state: %d\n", __FILE__, __LINE__, ssd->pdu_state); return; } // Fall through for DCE2_SMB_DATA_STATE__SMB_HEADER // This is the normal progression without segmentation. // This state is to do validation checks on the SMB header and // more importantly verify it's data that needs to be inspected. // If the TID in the SMB header is not referring to the IPC share // there won't be any DCE/RPC traffic associated with it. case DCE2_SMB_DATA_STATE__SMB_HEADER: data_need = (sizeof(NbssHdr) + sizeof(SmbNtHdr)) - DCE2_BufferLength(*seg_buf); // See if there is enough data to process the SMB header if (data_len < data_need) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data len (%u) < " "NetBIOS SS header + SMB header (%u). Queueing data.\n", data_len, data_need)); if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS) { DCE2_BufferEmpty(*seg_buf); *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; } return; } // Set the SMB header structure if (DCE2_BufferIsEmpty(*seg_buf)) { smb_hdr = (SmbNtHdr *)(data_ptr + sizeof(NbssHdr)); } else { if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS) { DCE2_BufferEmpty(*seg_buf); *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; return; } smb_hdr = (SmbNtHdr *)(DCE2_BufferData(*seg_buf) + sizeof(NbssHdr)); } // XXX Don't support SMB2 yet if (SmbId(smb_hdr) == DCE2_SMB2_ID) { ssd->sd.flags |= DCE2_SSN_FLAG__NO_INSPECT; return; } // See if this is something we need to inspect rtracker = DCE2_SmbInspect(ssd, smb_hdr); if (rtracker == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not inspecting SMB packet.\n")); if (DCE2_BufferIsEmpty(*seg_buf)) { *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr *)data_ptr); } else { *ignore_bytes = (NbssLen((NbssHdr *)DCE2_BufferData(*seg_buf)) - sizeof(SmbNtHdr)) + data_need; DCE2_BufferEmpty(*seg_buf); } *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; dce2_stats.smb_ignored_bytes += *ignore_bytes; continue; } // Check the SMB header for anomolies if (DCE2_SmbHdrChecks(ssd, smb_hdr) != DCE2_RET__SUCCESS) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Bad SMB header.\n")); if (DCE2_BufferIsEmpty(*seg_buf)) { *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr *)data_ptr); } else { *ignore_bytes = (NbssLen((NbssHdr *)DCE2_BufferData(*seg_buf)) - sizeof(SmbNtHdr)) + data_need; DCE2_BufferEmpty(*seg_buf); } *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; dce2_stats.smb_ignored_bytes += *ignore_bytes; continue; } if (!DCE2_BufferIsEmpty(*seg_buf)) DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU; // Fall through // This state ensures that we have the entire PDU before continuing // to process. case DCE2_SMB_DATA_STATE__NETBIOS_PDU: if (DCE2_BufferIsEmpty(*seg_buf)) { nb_len = NbssLen((NbssHdr *)data_ptr); data_need = sizeof(NbssHdr) + nb_len; } else { nb_len = NbssLen((NbssHdr *)DCE2_BufferData(*seg_buf)); data_need = (sizeof(NbssHdr) + nb_len) - DCE2_BufferLength(*seg_buf); } /* It's something we want to inspect so make sure we have the full NBSS packet */ if (data_len < data_need) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data len(%u) < " "NetBIOS SS header + NetBIOS len(%u). " "Queueing data.\n", data_len, sizeof(NbssHdr) + nb_len)); if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS) { DCE2_BufferEmpty(*seg_buf); *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; } return; } // data_len >= data_need which means data_need <= UINT16_MAX // So casts below of data_need to uint16_t are okay. *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; if (DCE2_BufferIsEmpty(*seg_buf)) { nb_ptr = data_ptr; nb_len = data_need; DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); } else { SFSnortPacket *rpkt; if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS) { DCE2_BufferEmpty(*seg_buf); DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); continue; } DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); nb_ptr = DCE2_BufferData(*seg_buf); nb_len = DCE2_BufferLength(*seg_buf); // Get reassembled packet rpkt = DCE2_SmbGetRpkt(ssd, &nb_ptr, &nb_len, DCE2_RPKT_TYPE__SMB_SEG); if (rpkt == NULL) { DCE2_BufferEmpty(*seg_buf); continue; } nb_ptr = DCE2_BufferData(*seg_buf); nb_len = DCE2_BufferLength(*seg_buf); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Segmentation buffer: len: %u, size: %u\n", DCE2_BufferLength(*seg_buf), DCE2_BufferSize(*seg_buf));); if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) dce2_stats.smb_cli_seg_reassembled++; else dce2_stats.smb_srv_seg_reassembled++; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "TCP reassembled SMB PDU\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size);); } switch (ssd->pdu_state) { case DCE2_SMB_PDU_STATE__COMMAND: smb_hdr = (SmbNtHdr *)(nb_ptr + sizeof(NbssHdr)); DCE2_MOVE(nb_ptr, nb_len, (sizeof(NbssHdr) + sizeof(SmbNtHdr))); ssd->cur_rtracker = (rtracker != NULL) ? rtracker : DCE2_SmbFindRequestTracker(ssd, smb_hdr); if (ssd->cur_rtracker != NULL) DCE2_SmbProcessCommand(ssd, smb_hdr, nb_ptr, nb_len); break; case DCE2_SMB_PDU_STATE__RAW_DATA: DCE2_MOVE(nb_ptr, nb_len, sizeof(NbssHdr)); if (ssd->cur_rtracker != NULL) DCE2_SmbProcessRawData(ssd, nb_ptr, nb_len); // Only one raw read or write ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid SMB PDU " "state: %d\n", __FILE__, __LINE__, ssd->pdu_state); return; } if (!DCE2_BufferIsEmpty(*seg_buf)) { DCE2_SmbReturnRpkt(); DCE2_BufferDestroy(*seg_buf); *seg_buf = NULL; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid SMB Data " "state: %d\n", __FILE__, __LINE__, *data_state); return; } } } /******************************************************************** * Function: DCE2_SmbHandleSegmentation() * * Wrapper around DCE2_HandleSegmentation() to allocate a new * buffer object if necessary. * * Arguments: * DCE2_SmbBuffer ** * Pointer to pointer of buffer to add data to. If NULL * a new buffer will be allocated. * uint8_t * * Pointer to the current data cursor in packet. * uint32_t * Length of data to add to buffer. * uint32_t * The minimum allocation size so that small allocations * aren't consistently done. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if an error occured. Nothing can * be trusted. * DCE2_RET__SUCCESS if data was successfully added. * ********************************************************************/ static inline DCE2_Ret DCE2_SmbHandleSegmentation(DCE2_Buffer **buf, const uint8_t *data_ptr, uint32_t add_len, uint32_t alloc_size) { DCE2_Ret status; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_seg); if (buf == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_seg); return DCE2_RET__ERROR; } if (*buf == NULL) { /* No initial size or min alloc size */ *buf = DCE2_BufferNew(alloc_size, alloc_size, DCE2_MEM_TYPE__SMB_SEG); if (*buf == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_seg); return DCE2_RET__ERROR; } } status = DCE2_BufferAddData(*buf, data_ptr, add_len, DCE2_BufferLength(*buf), DCE2_BUFFER_MIN_ADD_FLAG__IGNORE); DCE2_DEBUG_CODE(DCE2_DEBUG__SMB, if (status != DCE2_RET__SUCCESS) printf("Failed to add data to SMB segmentation buffer.\n");); PREPROC_PROFILE_END(dce2_pstat_smb_seg); return status; } /******************************************************************** * Function: DCE2_SmbGetSegBuffer() * * Returns the appropriate segmentation buffer. * * Arguments: * DCE2_SmbSsnData * * Pointer to SMB session data. * * Returns: * DCE2_SmbSeg * * Pointer to client or server segmenation buffer. * ********************************************************************/ static inline DCE2_Buffer ** DCE2_SmbGetSegBuffer(DCE2_SmbSsnData *ssd) { if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) return &ssd->srv_seg; return &ssd->cli_seg; } /******************************************************************** * Function: DCE2_SmbGetIgnorePtr() * * Returns a pointer to the bytes we are ignoring on client or * server side. Bytes are ignored if they are associated with * data we are not interested in. * * Arguments: * DCE2_SmbSsnData * - Pointer to SMB session data. * * Returns: * uint32_t * * Pointer to the client or server ignore bytes. * ********************************************************************/ static inline uint32_t * DCE2_SmbGetIgnorePtr(DCE2_SmbSsnData *ssd) { if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) return &ssd->srv_ignore_bytes; return &ssd->cli_ignore_bytes; } /******************************************************************** * Function: DCE2_SmbGetDataState() * * Returns a pointer to the data state of client or server * * Arguments: * DCE2_SmbSsnData * - Pointer to SMB session data. * * Returns: * DCE2_SmbDataState * * Pointer to the client or server data state. * ********************************************************************/ static inline DCE2_SmbDataState * DCE2_SmbGetDataState(DCE2_SmbSsnData *ssd) { if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) return &ssd->srv_data_state; return &ssd->cli_data_state; } /******************************************************************** * Function: DCE2_SmbIsSegBuffer() * * Purpose: * Determines whether the pointer passed in lies within one of the * segmentation buffers or not. * * Arguments: * DCE2_SmbSsnData * * Pointer to SMB session data. * * Returns: * bool - True is the pointer lies within one of the segmentation * buffers. * False if it doesn't. * ********************************************************************/ static inline bool DCE2_SmbIsSegBuffer(DCE2_SmbSsnData *ssd, const uint8_t *ptr) { DCE2_Buffer *seg_buf; if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) seg_buf = ssd->srv_seg; else seg_buf = ssd->cli_seg; if (DCE2_BufferIsEmpty(seg_buf)) return false; /* See if we're looking at a segmentation buffer */ if ((ptr < DCE2_BufferData(seg_buf)) || (ptr > (DCE2_BufferData(seg_buf) + DCE2_BufferLength(seg_buf)))) { return false; } return true; } /******************************************************************** * Function: DCE2_SmbSegAlert() * * Purpose: * To create a reassembled packet using the data in one of the * segmentation buffers in order to generate an alert with the * correct, or more complete data. * * Arguments: * DCE2_SmbSsnData * - Pointer to SMB session data. * DCE2_Event - the event code to generate and event for. * * Returns: None * ********************************************************************/ static inline void DCE2_SmbSegAlert(DCE2_SmbSsnData *ssd, DCE2_Event event) { SFSnortPacket *rpkt; DCE2_Buffer *buf; uint32_t nb_len = 0; const uint8_t *data_ptr; uint32_t data_len; if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) buf = ssd->cli_seg; else buf = ssd->srv_seg; /* This should be called from the desegmentation code. */ if (DCE2_BufferIsEmpty(buf)) return; data_ptr = DCE2_BufferData(buf); data_len = DCE2_BufferLength(buf); rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_SEG); if (rpkt == NULL) return; if (DCE2_BufferLength(buf) >= sizeof(NbssHdr)) nb_len = NbssLen((NbssHdr *)DCE2_BufferData(buf)); switch (event) { case DCE2_EVENT__SMB_BAD_NBSS_TYPE: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_NBSS_TYPE); break; case DCE2_EVENT__SMB_BAD_TYPE: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_TYPE); break; case DCE2_EVENT__SMB_BAD_ID: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_ID); break; case DCE2_EVENT__SMB_NB_LT_SMBHDR: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_SMBHDR, nb_len, sizeof(SmbNtHdr)); break; default: break; } DCE2_SmbReturnRpkt(); } /******************************************************************** * Function: DCE2_SmbIsRawData() * * Purpose: * To determine if the current state is such that a raw read or * write is expected. * * Arguments: * DCE2_SmbSsnData * - Pointer to SMB session data. * * Returns: * bool - True if expecting raw data. * False if not. * ********************************************************************/ static inline bool DCE2_SmbIsRawData(DCE2_SmbSsnData *ssd) { return (ssd->pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbProcessRawData(DCE2_SmbSsnData *ssd, const uint8_t *nb_ptr, uint32_t nb_len) { DCE2_SmbFileTracker *ftracker = ssd->cur_rtracker->ftracker; bool remove_rtracker = false; if (ftracker == NULL) { DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); ssd->cur_rtracker = NULL; return; } if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Raw data: Write Raw\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Request Fid: 0x%04X\n", ftracker->fid)); dce2_stats.smb_com_stats[SMB_TYPE__REQUEST][SMB_COM_WRITE_RAW]++; if (nb_len > ssd->cur_rtracker->writeraw_remaining) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_TDCNT_LT_DSIZE, ssd->cur_rtracker->writeraw_remaining, nb_len); // If this happens, Windows never responds regardless of // WriteThrough flag, so get rid of request tracker remove_rtracker = true; } else if (!ssd->cur_rtracker->writeraw_writethrough) { // If WriteThrough flag was not set on initial request, a // SMB_COM_WRITE_COMPLETE will not be sent so need to get // rid of request tracker. remove_rtracker = true; } else { ssd->cur_rtracker->writeraw_writethrough = false; ssd->cur_rtracker->writeraw_remaining = 0; } } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Raw data: Read Raw\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Response Fid: 0x%04X\n", ftracker->fid)); dce2_stats.smb_com_stats[SMB_TYPE__RESPONSE][SMB_COM_READ_RAW]++; remove_rtracker = true; } // Only one raw read/write allowed ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; DCE2_SmbSetFileName(ftracker->file_name); if (ftracker->is_ipc) { // Maximum possible fragment length is 16 bit if (nb_len > UINT16_MAX) nb_len = UINT16_MAX; DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, nb_ptr, (uint16_t)nb_len); } else { bool upload = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? true : false; DCE2_SmbProcessFileData(ssd, ftracker, nb_ptr, nb_len, upload); } if (remove_rtracker) { DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); ssd->cur_rtracker = NULL; } } /******************************************************************** * Function: DCE2_SmbCheckCommand() * * Purpose: * Checks basic validity of an SMB command. * * Arguments: * DCE2_SmbSsnData * - pointer to session data structure * SmbNtHdr * - pointer to the SMB header structure * int - the SMB command code, i.e. SMB_COM_* * uint8_t * - current pointer to data, i.e. the command * uint32_t - the remaining length * * Returns: * DCE2_SmbComInfo * * Populated structure for command processing * ********************************************************************/ static DCE2_SmbComInfo * DCE2_SmbCheckCommand(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const uint8_t smb_com, const uint8_t *nb_ptr, uint32_t nb_len) { SmbAndXCom andx_com = smb_chain_map[smb_com]; const SmbCommon *sc = (SmbCommon *)nb_ptr; int chk_com_size; uint16_t smb_bcc; static DCE2_SmbComInfo com_info; com_info.smb_type = DCE2_SmbType(ssd); com_info.cmd_error = DCE2_SMB_COM_ERROR__COMMAND_OK; com_info.word_count = 0; com_info.smb_com = smb_com; com_info.cmd_size = 0; com_info.byte_count = 0; // Check for server error response if (com_info.smb_type == SMB_TYPE__RESPONSE) { const SmbEmptyCom *ec = (SmbEmptyCom *)nb_ptr; // Verify there is enough data to do checks if (nb_len < sizeof(SmbEmptyCom)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_COM, nb_len, sizeof(SmbEmptyCom)); com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; return &com_info; } // If word and byte counts are zero and there is an error // the server didn't accept client request if ((SmbEmptyComWct(ec) == 0) && (SmbEmptyComBcc(ec) == 0) && SmbError(smb_hdr)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Response error: 0x%08X\n", SmbNtStatus(smb_hdr))); // If broken pipe, clean up data associated with open named pipe if (SmbBrokenPipe(smb_hdr)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, " Broken or disconnected pipe.\n")); DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker); } com_info.cmd_error |= DCE2_SMB_COM_ERROR__STATUS_ERROR; return &com_info; } } // Set the header size to the minimum size the command can be // without the byte count to make sure there is enough data to // get the word count. if (andx_com == SMB_ANDX_COM__NONE) chk_com_size = sizeof(SmbCommon); else chk_com_size = sizeof(SmbAndXCommon); // Verify there is enough data to do checks if (nb_len < (uint32_t)chk_com_size) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_COM, nb_len, chk_com_size); com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; return &com_info; } com_info.word_count = SmbWct(sc); // Make sure the word count is a valid one for the command. If not // testing shows an error will be returned. And command structures // won't lie on data correctly and out of bounds data accesses are possible. if (!DCE2_SmbIsValidWordCount(smb_com, (uint8_t)com_info.smb_type, com_info.word_count)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_WCT, com_info.word_count); com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT; return &com_info; } // This gets the size of the SMB command from word count through byte count // using the advertised value in the word count field. com_info.cmd_size = (uint16_t)SMB_COM_SIZE(com_info.word_count); if (nb_len < com_info.cmd_size) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_COM, nb_len, com_info.cmd_size); com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; return &com_info; } smb_bcc = SmbBcc(nb_ptr, com_info.cmd_size); // SMB_COM_NT_CREATE_ANDX is a special case. Who know what's going // on with the word count (see MS-CIFS and MS-SMB). A 42 word count // command seems to actually have 50 words, so who knows where the // byte count is. Just set to zero since it's not needed. if ((smb_com == SMB_COM_NT_CREATE_ANDX) && (com_info.smb_type == SMB_TYPE__RESPONSE)) smb_bcc = 0; // If byte count is deemed invalid, alert but continue processing switch (smb_com) { // Interim responses case SMB_COM_TRANSACTION: case SMB_COM_TRANSACTION2: case SMB_COM_NT_TRANSACT: // If word count is 0, byte count must be 0 if ((com_info.word_count == 0) && (com_info.smb_type == SMB_TYPE__RESPONSE)) { if (smb_bcc != 0) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_BCC, smb_bcc); com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT; } break; } // Fall through default: if (!DCE2_SmbIsValidByteCount(smb_com, (uint8_t)com_info.smb_type, smb_bcc)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_BCC, smb_bcc); com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT; } break; } // Move just past byte count field which is the end of the command DCE2_MOVE(nb_ptr, nb_len, com_info.cmd_size); // Validate that there is enough data to be able to process the command if (nb_len < DCE2_SmbGetMinByteCount(smb_com, (uint8_t)com_info.smb_type)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_BCC, nb_len, DCE2_SmbGetMinByteCount(smb_com, (uint8_t)com_info.smb_type)); com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; } // The byte count seems to be ignored by Windows and current Samba (3.5.4) // as long as it is less than the amount of data left. If more, an error // is returned. // !!!WARNING!!! the byte count should probably never be used. if (smb_bcc > nb_len) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_BCC, nb_len, smb_bcc); // Large byte count doesn't seem to matter for early Samba switch (DCE2_SsnGetPolicy(&ssd->sd)) { case DCE2_POLICY__SAMBA_3_0_20: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_37: break; default: com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; break; } } else if ((smb_bcc == 0) && (SmbCom(smb_hdr) == SMB_COM_TRANSACTION) && (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST) && (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA)) { // Current Samba errors on a zero byte count Transaction because it // uses it to get the Name string and if zero Name will be NULL and // it won't process it. com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; } com_info.byte_count = smb_bcc; return &com_info; } /******************************************************************** * Function: DCE2_SmbProcessCommand() * * Purpose: * This is the main function for handling SMB commands and command * chaining. * It does an initial check of the command to determine validity * and gets basic information about the command. Then it calls the * specific command function (setup in DCE2_SmbInitGlobals). * If there is command chaining, it will do the chaining foo to * get to the next command. * * Arguments: * DCE2_SmbSsnData * - pointer to session data structure * SmbNtHdr * - pointer to the SMB header structure * uint8_t * - current pointer to data, i.e. the command * uint32_t - the remaining length * * Returns: None * ********************************************************************/ static void DCE2_SmbProcessCommand(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const uint8_t *nb_ptr, uint32_t nb_len) { DCE2_Ret status = DCE2_RET__ERROR; DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); uint8_t smb_com = SmbCom(smb_hdr); int smb_type = DCE2_SmbType(ssd); int num_chained = 0; bool sess_chain = false; bool tree_chain = false; bool open_chain = false; dce2_stats.smb_com_stats[smb_type][smb_com]++; while (nb_len > 0) { SmbAndXCom andx_com = smb_chain_map[smb_com]; const SmbAndXCommon *andx_ptr = (SmbAndXCommon *)nb_ptr; uint8_t smb_com2; const uint8_t *off2_ptr; DCE2_SmbComInfo *com_info; #ifdef ACTIVE_RESPONSE if (ssd->block_pdus && (smb_type == SMB_TYPE__REQUEST)) { _dpd.inlineDropPacket((void *)ssd->sd.wire_pkt); status = DCE2_RET__IGNORE; break; } #endif // Break out if command not supported if (smb_com_funcs[smb_com] == NULL) break; if (smb_deprecated_coms[smb_com]) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DEPR_COMMAND_USED, smb_com_strings[smb_com]); } if (smb_unusual_coms[smb_com]) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED, smb_com_strings[smb_com]); } com_info = DCE2_SmbCheckCommand(ssd, smb_hdr, smb_com, nb_ptr, nb_len); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Processing command: %s (0x%02X)\n", smb_com_strings[smb_com], smb_com)); // Note that even if the command shouldn't be processed, some of // the command functions need to know and do cleanup or some other // processing. status = smb_com_funcs[smb_com](ssd, smb_hdr, (const DCE2_SmbComInfo *)com_info, nb_ptr, nb_len); if (status != DCE2_RET__SUCCESS) break; // This command is not chainable if (andx_com == SMB_ANDX_COM__NONE) break; /********************************************************** * AndX Chaining **********************************************************/ smb_com2 = SmbAndXCom2(andx_ptr); if (smb_com2 == SMB_COM_NO_ANDX_COMMAND) break; dce2_stats.smb_chained_stats[smb_type][andx_com][smb_com2]++; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Chained SMB command: %s\n", smb_com_strings[smb_com2])); num_chained++; if (DCE2_ScSmbMaxChain(ssd->sd.sconfig) && (num_chained >= DCE2_ScSmbMaxChain(ssd->sd.sconfig))) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EXCESSIVE_CHAINING, DCE2_ScSmbMaxChain(ssd->sd.sconfig)); } // Multiple SessionSetupAndX, TreeConnectAndX, OpenAndX and NtCreateAndX // are only allowed by Samba. if (smb_com == SMB_COM_SESSION_SETUP_ANDX) sess_chain = true; // Check for multiple chained SessionSetupAndX if ((smb_com2 == SMB_COM_SESSION_SETUP_ANDX) && sess_chain) { // There is only one place to return a uid. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_MULT_CHAIN_SS); // XXX Should we continue processing? break; } // Check for chained SessionSetupAndX => .? => LogoffAndX if ((smb_com2 == SMB_COM_LOGOFF_ANDX) && sess_chain) { // This essentially deletes the uid created by the login // and doesn't make any sense. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_CHAIN_SS_LOGOFF); } if (smb_com == SMB_COM_TREE_CONNECT_ANDX) tree_chain = true; // Check for multiple chained TreeConnects if (((smb_com2 == SMB_COM_TREE_CONNECT_ANDX) || (smb_com2 == SMB_COM_TREE_CONNECT)) && tree_chain) { // There is only one place to return a tid. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_MULT_CHAIN_TC); // XXX Should we continue processing? break; } // Check for chained TreeConnectAndX => .? => TreeDisconnect if ((smb_com2 == SMB_COM_TREE_DISCONNECT) && tree_chain) { // This essentially deletes the tid created by the tree connect // and doesn't make any sense. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_CHAIN_TC_TDIS); } if ((smb_com == SMB_COM_OPEN_ANDX) || (smb_com == SMB_COM_NT_CREATE_ANDX)) open_chain = true; // Check for chained OpenAndX/NtCreateAndX => .? => Close if ((smb_com2 == SMB_COM_CLOSE) && open_chain) { // This essentially deletes the fid created by the open command // and doesn't make any sense. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_CHAIN_OPEN_CLOSE); } // Check that policy allows for such chaining if (smb_chain_funcs[policy][andx_com][smb_com2] == NULL) break; DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); // XXX Need to test out of order chaining off2_ptr = (uint8_t *)smb_hdr + SmbAndXOff2(andx_ptr); if (DCE2_SmbCheckAndXOffset(ssd, off2_ptr, nb_ptr, nb_len) != DCE2_RET__SUCCESS) break; DCE2_MOVE(nb_ptr, nb_len, (off2_ptr - nb_ptr)); // XXX Need to test more. switch (smb_com) { case SMB_COM_SESSION_SETUP_ANDX: case SMB_COM_TREE_CONNECT_ANDX: case SMB_COM_OPEN_ANDX: case SMB_COM_NT_CREATE_ANDX: switch (smb_com2) { case SMB_COM_WRITE: case SMB_COM_WRITE_ANDX: case SMB_COM_TRANSACTION: case SMB_COM_READ_ANDX: if (DCE2_SsnFromClient(ssd->sd.wire_pkt) && open_chain) { DCE2_SmbQueueTmpFileTracker(ssd, ssd->cur_rtracker, SmbUid(smb_hdr), SmbTid(smb_hdr)); } break; default: break; } break; default: break; } smb_com = smb_com2; } if (smb_type == SMB_TYPE__RESPONSE) { switch (smb_com) { case SMB_COM_TRANSACTION: case SMB_COM_TRANSACTION2: case SMB_COM_NT_TRANSACT: case SMB_COM_TRANSACTION_SECONDARY: case SMB_COM_TRANSACTION2_SECONDARY: case SMB_COM_NT_TRANSACT_SECONDARY: // This case means there was an error with the initial response // so the tracker isn't yet officially in response mode if (ssd->cur_rtracker->ttracker.smb_type == SMB_TYPE__REQUEST) { // Samba throws out entire transaction and Windows just this request if (DCE2_SsnIsServerSambaPolicy(&ssd->sd) && (status != DCE2_RET__SUCCESS)) break; if (!DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) return; } else { if ((status == DCE2_RET__SUCCESS) && !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) return; } break; case SMB_COM_WRITE_RAW: if ((status == DCE2_RET__SUCCESS) && (ssd->cur_rtracker->writeraw_remaining != 0)) return; break; default: break; } } else if (status != DCE2_RET__IGNORE) { switch (smb_com) { case SMB_COM_TRANSACTION: case SMB_COM_TRANSACTION_SECONDARY: if (DCE2_SsnIsWindowsPolicy(&ssd->sd)) { if (!ssd->cur_rtracker->ttracker.one_way || !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) return; // Remove the request tracker if transaction is one-way and // all data and parameters have been sent break; } default: // Anything else, keep the request tracker return; } } DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); ssd->cur_rtracker = NULL; } /******************************************************************** * Function: DCE2_SmbCheckData() * * Purpose: * Ensures that the data size reported in an SMB command is kosher. * * Arguments: * DCE2_SmbSsnData * - SMB session data structure * const uint8_t * - pointer to start of SMB header where offset is * taken from. * const uint8_t * - current pointer - should be right after command * structure. * const uint32_t - remaining data left in PDU from current pointer. * const uint16_t - the byte count from the SMB command * const uint16_t - reported data count in SMB command * const uint16_t - reported data offset in SMB command * * Returns: * DCE2_Ret - DCE2_RET__ERROR if data should not be processed * DCE2_RET__SUCCESS if data can be processed * ********************************************************************/ static inline DCE2_Ret DCE2_SmbCheckData(DCE2_SmbSsnData *ssd, const uint8_t *smb_hdr_ptr, const uint8_t *nb_ptr, const uint32_t nb_len, const uint16_t bcc, const uint32_t dcnt, uint16_t doff) { const uint8_t *offset = smb_hdr_ptr + doff; const uint8_t *nb_end = nb_ptr + nb_len; // Byte counts don't usually matter, so no error but still alert // Don't alert in the case where the data count is larger than what the // byte count can handle. This can happen if CAP_LARGE_READX or // CAP_LARGE_WRITEX were negotiated. if ((dcnt <= UINT16_MAX) && (bcc < dcnt)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BCC_LT_DSIZE, bcc, (uint64_t)dcnt); if (offset > nb_end) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, offset, nb_ptr, nb_end); // Error if offset is beyond data left return DCE2_RET__ERROR; } // Only check if the data count is non-zero if ((dcnt != 0) && (offset < nb_ptr)) { // Not necessarily and error if the offset puts the data // before or in the command structure. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, offset, nb_ptr, nb_end); } // Not necessarily an error if the addition of the data count goes // beyond the data left if (((offset + dcnt) > nb_end) // beyond data left || ((offset + dcnt) < offset)) // wrap { int pad = offset - nb_ptr; if (pad > 0) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len - pad, dcnt); else DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, dcnt); } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_SmbValidateTransactionFields() * * Purpose: * Wrapper that calls DCE2_SmbCheckTotalCount() for total parameter * count and total data count and DCE2_SmbCheckTransDataParams() * * Arguments: * DCE2_SmbSsnData * - SMB session data structure * const uint8_t * - pointer to start of SMB header where offset is * taken from. * const uint8_t * - current pointer - should be right after command * structure. * const uint32_t - remaining data left in PDU from current pointer. * const uint16_t - the byte count * const uint32_t - reported total data count * const uint32_t - reported total parameter count * const uint32_t - reported data count * const uint32_t - reported data offset * const uint32_t - reported data displacement * const uint32_t - reported parameter count * const uint32_t - reported parameter offset * const uint32_t - reported parameter displacement * * Returns: * DCE2_Ret - DCE2_RET__ERROR if data should not be processed * DCE2_RET__SUCCESS if data can be processed * ********************************************************************/ static inline DCE2_Ret DCE2_SmbValidateTransactionFields(DCE2_SmbSsnData *ssd, const uint8_t *smb_hdr_ptr, const uint8_t *nb_ptr, const uint32_t nb_len, const uint16_t bcc, const uint32_t tdcnt, const uint32_t tpcnt, const uint32_t dcnt, const uint32_t doff, const uint32_t ddisp, const uint32_t pcnt, const uint32_t poff, const uint32_t pdisp) { if (DCE2_SmbCheckTotalCount(ssd, tdcnt, dcnt, ddisp) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_SmbCheckTotalCount(ssd, tpcnt, pcnt, pdisp) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_SmbCheckTransDataParams(ssd, smb_hdr_ptr, nb_ptr, nb_len, bcc, dcnt, doff, pcnt, poff) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_SmbValidateTransactionSent() * * Purpose: * Checks that amount sent plus current amount is not greater than * the total count expected. * * Arguments: * DCE2_SmbSsnData * - SMB session data structure * const uint32_t - amount of data sent so far * const uint32_t - reported total data count * const uint32_t - reported data count * const uint32_t - amount of parameters sent so far * const uint32_t - reported total parameter count * const uint32_t - reported parameter count * * Returns: * DCE2_Ret - DCE2_RET__ERROR if data should not be processed * DCE2_RET__SUCCESS if data can be processed * ********************************************************************/ static inline DCE2_Ret DCE2_SmbValidateTransactionSent(DCE2_SmbSsnData *ssd, uint32_t dsent, uint32_t dcnt, uint32_t tdcnt, uint32_t psent, uint32_t pcnt, uint32_t tpcnt) { if (((dsent + dcnt) > tdcnt) || ((psent + pcnt) > tpcnt)) { if ((dsent + dcnt) > tdcnt) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DSENT_GT_TDCNT, ((uint64_t)dsent + dcnt), tdcnt); } if ((psent + pcnt) > tpcnt) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DSENT_GT_TDCNT, ((uint64_t)psent + pcnt), tpcnt); } // Samba throws out entire transaction and Windows seems to hang in // limbo forever and never responds, so stop looking return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_SmbCheckTransDataParams() * * Purpose: * Ensures that the data size reported in an SMB command is kosher. * Note the 32 bit values are because of the NtTransact command * though it's currently not checked. * * Arguments: * DCE2_SmbSsnData * - SMB session data structure * const uint8_t * - pointer to start of SMB header where offset is * taken from. * const uint8_t * - current pointer - should be right after command * structure. * const uint32_t - remaining data left in PDU from current pointer. * const uint16_t - the byte count * const uint32_t - reported data count * const uint32_t - reported data offset * const uint32_t - reported parameter count * const uint32_t - reported parameter offset * * Returns: * DCE2_Ret - DCE2_RET__ERROR if data should not be processed * DCE2_RET__SUCCESS if data can be processed * ********************************************************************/ static inline DCE2_Ret DCE2_SmbCheckTransDataParams(DCE2_SmbSsnData *ssd, const uint8_t *smb_hdr_ptr, const uint8_t *nb_ptr, const uint32_t nb_len, const uint16_t bcc, const uint32_t dcnt, const uint32_t doff, const uint32_t pcnt, const uint32_t poff) { const uint8_t *doffset = smb_hdr_ptr + doff; const uint8_t *poffset = smb_hdr_ptr + poff; const uint8_t *nb_end = nb_ptr + nb_len; if (bcc < ((uint64_t)dcnt + pcnt)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BCC_LT_DSIZE, bcc, ((uint64_t)dcnt + pcnt)); // Check data offset out of bounds if ((doffset > nb_end) || (doffset < smb_hdr_ptr)) { // Beyond data left or wrap DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, doffset, nb_ptr, nb_end); return DCE2_RET__ERROR; } // Check data offset in bounds but backwards // Only check if the data count is non-zero if ((dcnt != 0) && (doffset < nb_ptr)) { // Not necessarily and error if the offset puts the data // before or in the command structure. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, doffset, nb_ptr, nb_end); } // Check the data offset + data count if (((doffset + dcnt) > nb_end) // beyond data left || ((doffset + dcnt) < doffset)) // wrap { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, dcnt); return DCE2_RET__ERROR; } // Check parameter offset out of bounds if ((poffset > nb_end) || (poffset < smb_hdr_ptr)) { // Beyond data left or wrap DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, poffset, nb_ptr, nb_end); return DCE2_RET__ERROR; } // Check parameter offset in bounds but backwards // Only check if the parameter count is non-zero if ((pcnt != 0) && (poffset < nb_ptr)) { // Not necessarily and error if the offset puts the data // before or in the command structure. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, poffset, nb_ptr, nb_end); } // Check the parameter offset + parameter count if (((poffset + pcnt) > nb_end) // beyond data left || ((poffset + pcnt) < poffset)) // wrap { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, pcnt); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_SmbCheckFmtData() * * Purpose: * Checks the data count in commands with formats, e.g. * SMB_COM_WRITE, SMB_COM_WRITE_AND_CLOSE, SMB_COM_WRITE_AND_UNLOCK. * * Arguments: * DCE2_SmbSsnData * - SMB session data structure * const uint32_t - remaining NetBIOS PDU length * const uint16_t - advertised byte count * const uint8_t - data format specifier * const uint16_t - data count reported in command * const uint16_t - data count reported in format field * * Returns: None * ********************************************************************/ static inline void DCE2_SmbCheckFmtData(DCE2_SmbSsnData *ssd, const uint32_t nb_len, const uint16_t bcc, const uint8_t fmt, const uint16_t com_dcnt, const uint16_t fmt_dcnt) { if (fmt != SMB_FMT__DATA_BLOCK) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, fmt); if (com_dcnt != fmt_dcnt) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_MISMATCH, com_dcnt, fmt_dcnt); if (com_dcnt != (bcc - 3)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_DSIZE, com_dcnt, bcc); if (nb_len < com_dcnt) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, com_dcnt); } /******************************************************************** * Function: DCE2_SmbCheckTotalCount() * * Purpose: * Validates the advertised total data/param count. Makes sure the * current count isn't greater than total count, that the * displacement + count isn't greater than the total data count and * that the total data count isn't zero. Mainly relevant to Write Raw, * Transaction and Transaction Secondary commands. * * Arguments: * DCE2_SmbSsnData * - SMB session data structure * const uint32_t - total data count * const uint32_t - data count/size * const uint32_t - data displacement * * Returns: * DCE2_Ret - DCE2_RET__SUCCESS if all is ok * DCE2_RET__ERROR if any of the checks fail. * ********************************************************************/ static inline DCE2_Ret DCE2_SmbCheckTotalCount(DCE2_SmbSsnData *ssd, const uint32_t tcnt, const uint32_t cnt, const uint32_t disp) { DCE2_Ret ret = DCE2_RET__SUCCESS; if (cnt > tcnt) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_TDCNT_LT_DSIZE, tcnt, cnt); ret = DCE2_RET__ERROR; } if (((uint64_t)disp + cnt) > tcnt) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DSENT_GT_TDCNT, ((uint64_t)disp + cnt), tcnt); ret = DCE2_RET__ERROR; } return ret; } /******************************************************************** * Function: DCE2_SmbCheckAndXOffset() * * Purpose: * Validates that the AndXOffset is within bounds of the remaining * data we have to work with. * * Arguments: * uint8_t * - pointer to where the offset would take us. * uint8_t * - pointer to bound offset * uint8_t * - length of data where offset should be within * * Returns: * DCE2_RET__SUCCESS - Offset is okay. * DCE2_RET__ERROR - Offset is bad. * ********************************************************************/ static inline DCE2_Ret DCE2_SmbCheckAndXOffset(DCE2_SmbSsnData *ssd, const uint8_t *off_ptr, const uint8_t *start_bound, const uint32_t length) { /* Offset should not point within data we just looked at or be equal to * or beyond the length of the NBSS length left */ if ((off_ptr < start_bound) || (off_ptr > (start_bound + length))) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, off_ptr, start_bound, start_bound + length); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_SmbInvalidShareCheck() * * Purpose: * Checks the share reported in a TreeConnect or TreeConnectAndX * against the invalid share list configured in the dcerpc2 * configuration in snort.conf. * * Arguments: * DCE2_SmbSsnData * - SMB session data structure * SmbNtHdr * - pointer to the SMB header structure * uint8_t * - current pointer to the share to check * uint32_t - the remaining length * * Returns: None * Alerts if there is an invalid share match. * ********************************************************************/ static inline void DCE2_SmbInvalidShareCheck(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const uint8_t *nb_ptr, uint32_t nb_len) { DCE2_List *share_list = DCE2_ScSmbInvalidShares(ssd->sd.sconfig); DCE2_SmbShare *smb_share; if (share_list == NULL) return; for (smb_share = (DCE2_SmbShare *)DCE2_ListFirst(share_list); smb_share != NULL; smb_share = (DCE2_SmbShare *)DCE2_ListNext(share_list)) { unsigned int i; const char *share_str; unsigned int share_str_len; if (SmbUnicode(smb_hdr)) { share_str = smb_share->unicode_str; share_str_len = smb_share->unicode_str_len; } else { share_str = smb_share->ascii_str; share_str_len = smb_share->ascii_str_len; } /* Make sure we have enough data */ if (nb_len < share_str_len) continue; /* Test for share match */ for (i = 0; i < share_str_len; i++) { /* All share strings should have been converted to upper case and * should include null terminating bytes */ if ((nb_ptr[i] != share_str[i]) && (nb_ptr[i] != tolower((int)share_str[i]))) break; } if (i == share_str_len) { /* Should only match one share since no duplicate shares in list */ DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_SHARE, smb_share->ascii_str); break; } } } /******************************************************************** * Functions: * DCE2_SmbOpen() * DCE2_SmbCreate() * DCE2_SmbClose() * DCE2_SmbRename() * DCE2_SmbRead() * DCE2_SmbWrite() * DCE2_SmbCreateNew() * DCE2_SmbLockAndRead() * DCE2_SmbWriteAndUnlock() * DCE2_SmbReadRaw() * DCE2_SmbWriteRaw() * DCE2_SmbWriteComplete() * DCE2_SmbTransaction() * DCE2_SmbTransactionSecondary() * DCE2_SmbWriteAndClose() * DCE2_SmbOpenAndX() * DCE2_SmbReadAndX() * DCE2_SmbWriteAndX() * DCE2_SmbTransaction2() * DCE2_SmbTransaction2Secondary() * DCE2_SmbTreeConnect() * DCE2_SmbTreeDisconnect() * DCE2_SmbNegotiate() * DCE2_SmbSessionSetupAndX() * DCE2_SmbLogoffAndX() * DCE2_SmbTreeConnectAndX() * DCE2_SmbNtTransact() * DCE2_SmbNtTransactSecondary() * DCE2_SmbNtCreateAndX() * * Purpose: Process SMB command * * Arguments: * DCE2_SmbSsnData * - SMB session data structure * const SmbNtHdr * - SMB header structure (packet pointer) * const DCE2_SmbComInfo * - Basic command information structure * uint8_t * - pointer to start of command (packet pointer) * uint32_t - remaining NetBIOS length * * Returns: * DCE2_Ret - DCE2_RET__ERROR if something went wrong and/or processing * should stop * DCE2_RET__SUCCESS if processing should continue * ********************************************************************/ // SMB_COM_OPEN static DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsResponse(com_info)) { DCE2_SmbFileTracker *ftracker; if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid) && (SmbFileAttrsDirectory(SmbOpenRespFileAttrs((SmbOpenResp *)nb_ptr)) || SmbOpenForWriting(SmbOpenRespAccessMode((SmbOpenResp *)nb_ptr)))) return DCE2_RET__SUCCESS; ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbOpenRespFid((SmbOpenResp *)nb_ptr)); if (ftracker == NULL) return DCE2_RET__ERROR; ftracker->file_name = ssd->cur_rtracker->file_name; ssd->cur_rtracker->file_name = NULL; if (!ftracker->is_ipc) { // This command can only be used to open an existing file ftracker->ff_file_size = SmbOpenRespFileSize((SmbOpenResp *)nb_ptr); } } else { // Have at least 2 bytes of data based on byte count check done earlier DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); if (!SmbFmtAscii(*nb_ptr)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, 1); ssd->cur_rtracker->file_name = DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), false); } return DCE2_RET__SUCCESS; } // SMB_COM_CREATE static DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsResponse(com_info)) { DCE2_SmbFileTracker *ftracker = DCE2_SmbNewFileTracker( ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbCreateRespFid((SmbCreateResp *)nb_ptr)); if (ftracker == NULL) return DCE2_RET__ERROR; ftracker->file_name = ssd->cur_rtracker->file_name; ssd->cur_rtracker->file_name = NULL; // Command creates or opens and truncates file to 0 so assume // upload. if (!ftracker->is_ipc) ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD; } else { if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)) { uint16_t file_attrs = SmbCreateReqFileAttrs((SmbCreateReq *)nb_ptr); if (SmbAttrDirectory(file_attrs)) return DCE2_RET__IGNORE; if (SmbEvasiveFileAttrs(file_attrs)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS); } // Have at least 2 bytes of data based on byte count check done earlier DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); if (!SmbFmtAscii(*nb_ptr)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, 1); ssd->cur_rtracker->file_name = DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), false); } return DCE2_RET__SUCCESS; } // SMB_COM_CLOSE static DCE2_Ret DCE2_SmbClose(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { uint16_t fid = SmbCloseReqFid((SmbCloseReq *)nb_ptr); // Set this for response ssd->cur_rtracker->ftracker = DCE2_SmbGetFileTracker(ssd, fid); #ifdef ACTIVE_RESPONSE if ((ssd->fb_ftracker != NULL) && (ssd->fb_ftracker == ssd->cur_rtracker->ftracker)) { void *ssnptr = ssd->sd.wire_pkt->stream_session_ptr; void *p = (void *)ssd->sd.wire_pkt; File_Verdict verdict = DCE2_SmbGetFileVerdict(p, ssnptr); if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT)) ssd->block_pdus = true; } #endif } else { DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker); } return DCE2_RET__SUCCESS; } // SMB_COM_RENAME static DCE2_Ret DCE2_SmbRename(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { // NOTE: This command is only processed for CVE-2006-4696 where the buffer // formats are invalid and has no bearing on DCE/RPC processing. if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { // Have at least 4 bytes of data based on byte count check done earlier uint32_t i; DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); if (!SmbFmtAscii(*nb_ptr)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, 1); if (SmbUnicode(smb_hdr)) { for (i = 0; i < (nb_len - 1); i += 2) { if (*((uint16_t *)(nb_ptr + i)) == 0) { i += 2; // move past null terminating bytes break; } } } else { for (i = 0; i < nb_len; i++) { if (nb_ptr[i] == 0) { i++; // move past null terminating byte break; } } } // i <= nb_len DCE2_MOVE(nb_ptr, nb_len, i); if ((nb_len > 0) && !SmbFmtAscii(*nb_ptr)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr); return DCE2_RET__ERROR; } } // Don't care about tracking response return DCE2_RET__ERROR; } // SMB_COM_READ static DCE2_Ret DCE2_SmbRead(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { DCE2_SmbFileTracker *ftracker = DCE2_SmbGetFileTracker(ssd, SmbReadReqFid((SmbReadReq *)nb_ptr)); // Set this for response since response doesn't have the Fid ssd->cur_rtracker->ftracker = ftracker; if ((ftracker != NULL) && !ftracker->is_ipc) ssd->cur_rtracker->file_offset = SmbReadReqOffset((SmbReadReq *)nb_ptr); } else { // Have at least 3 bytes of data based on byte count check done earlier uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint16_t com_dcnt = SmbReadRespCount((SmbReadResp *)nb_ptr); uint8_t fmt = *(nb_ptr + com_size); uint16_t fmt_dcnt = SmbNtohs((uint16_t *)(nb_ptr + com_size + 1)); DCE2_MOVE(nb_ptr, nb_len, (com_size + 3)); DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt); if (com_dcnt > nb_len) return DCE2_RET__ERROR; return DCE2_SmbProcessResponseData(ssd, nb_ptr, com_dcnt); } return DCE2_RET__SUCCESS; } // SMB_COM_WRITE static DCE2_Ret DCE2_SmbWrite(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { // Have at least 3 bytes of data based on byte count check done earlier uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint8_t fmt = *(nb_ptr + com_size); uint16_t com_dcnt = SmbWriteReqCount((SmbWriteReq *)nb_ptr); uint16_t fmt_dcnt = SmbNtohs((uint16_t *)(nb_ptr + com_size + 1)); uint16_t fid = SmbWriteReqFid((SmbWriteReq *)nb_ptr); uint32_t offset = SmbWriteReqOffset((SmbWriteReq *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, (com_size + 3)); DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt); if (com_dcnt == 0) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_ZERO); return DCE2_RET__ERROR; } if (com_dcnt > nb_len) com_dcnt = (uint16_t)nb_len; return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, com_dcnt, offset); } return DCE2_RET__SUCCESS; } // SMB_COM_CREATE_NEW static DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsResponse(com_info)) { DCE2_SmbFileTracker *ftracker = DCE2_SmbNewFileTracker( ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbCreateNewRespFid((SmbCreateNewResp *)nb_ptr)); if (ftracker == NULL) return DCE2_RET__ERROR; ftracker->file_name = ssd->cur_rtracker->file_name; ssd->cur_rtracker->file_name = NULL; // Command creates a new file so assume upload. if (!ftracker->is_ipc) ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD; } else { if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)) { uint16_t file_attrs = SmbCreateNewReqFileAttrs((SmbCreateNewReq *)nb_ptr); if (SmbAttrDirectory(file_attrs)) return DCE2_RET__IGNORE; if (SmbEvasiveFileAttrs(file_attrs)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS); } // Have at least 2 bytes of data based on byte count check done earlier DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); if (!SmbFmtAscii(*nb_ptr)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, 1); ssd->cur_rtracker->file_name = DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), false); } return DCE2_RET__SUCCESS; } // SMB_COM_LOCK_AND_READ static DCE2_Ret DCE2_SmbLockAndRead(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { DCE2_SmbFileTracker *ftracker = DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbLockAndReadReqFid((SmbLockAndReadReq *)nb_ptr)); // No sense in tracking response if (ftracker == NULL) return DCE2_RET__ERROR; if (!ftracker->is_ipc) ssd->cur_rtracker->file_offset = SmbLockAndReadReqOffset((SmbLockAndReadReq *)nb_ptr); // Set this for response ssd->cur_rtracker->ftracker = ftracker; } else { // Have at least 3 bytes of data based on byte count check done earlier uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint8_t fmt = *(nb_ptr + com_size); uint16_t com_dcnt = SmbLockAndReadRespCount((SmbLockAndReadResp *)nb_ptr); uint16_t fmt_dcnt = SmbNtohs((uint16_t *)(nb_ptr + com_size + 1)); DCE2_MOVE(nb_ptr, nb_len, (com_size + 3)); DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt); if (com_dcnt == 0) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_ZERO); return DCE2_RET__ERROR; } if (com_dcnt > nb_len) com_dcnt = (uint16_t)nb_len; return DCE2_SmbProcessResponseData(ssd, nb_ptr, com_dcnt); } return DCE2_RET__SUCCESS; } // SMB_COM_WRITE_AND_UNLOCK static DCE2_Ret DCE2_SmbWriteAndUnlock(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) { if (DCE2_ComInfoIsBadLength(com_info) || DCE2_ComInfoIsInvalidWordCount(com_info)) return DCE2_RET__ERROR; // These are special cases. The write succeeds but the unlock fails // so an error reponse is returned but the data was actually written. if (DCE2_ComInfoIsResponse(com_info) && DCE2_ComInfoIsStatusError(com_info)) { if (DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)) { if (!SmbErrorInvalidDeviceRequest(smb_hdr)) return DCE2_RET__ERROR; } else if (!SmbErrorRangeNotLocked(smb_hdr)) { return DCE2_RET__ERROR; } } } if (DCE2_ComInfoIsRequest(com_info)) { // Have at least 3 bytes of data based on byte count check done earlier uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint8_t fmt = *(nb_ptr + com_size); uint16_t com_dcnt = SmbWriteAndUnlockReqCount((SmbWriteAndUnlockReq *)nb_ptr); uint16_t fmt_dcnt = SmbNtohs((uint16_t *)(nb_ptr + com_size + 1)); uint16_t fid = SmbWriteAndUnlockReqFid((SmbWriteAndUnlockReq *)nb_ptr); uint32_t offset = SmbWriteAndUnlockReqOffset((SmbWriteAndUnlockReq *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, (com_size + 3)); DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt); if (com_dcnt == 0) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_ZERO); return DCE2_RET__ERROR; } if (com_dcnt > nb_len) com_dcnt = (uint16_t)nb_len; return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, com_dcnt, offset); } return DCE2_RET__SUCCESS; } // SMB_COM_READ_RAW static DCE2_Ret DCE2_SmbReadRaw(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { DCE2_SmbFileTracker *ftracker = DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbReadRawReqFid((SmbReadRawReq *)nb_ptr)); ssd->cur_rtracker->ftracker = ftracker; ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA; if ((ftracker != NULL) && !ftracker->is_ipc) ssd->cur_rtracker->file_offset = SmbReadRawReqOffset((SmbReadRawExtReq *)nb_ptr); } else { // The server response is the raw data. Supposedly if an error occurs, // the server will send a 0 byte read. Just the NetBIOS header with // zero byte length. Client upon getting the zero read is supposed to issue // another read using ReadAndX or Read to get the error. return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } // SMB_COM_WRITE_RAW static DCE2_Ret DCE2_SmbWriteRaw(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint16_t fid = SmbWriteRawReqFid((SmbWriteRawReq *)nb_ptr); uint16_t tdcnt = SmbWriteRawReqTotalCount((SmbWriteRawReq *)nb_ptr); bool writethrough = SmbWriteRawReqWriteThrough((SmbWriteRawReq *)nb_ptr); uint16_t doff = SmbWriteRawReqDataOff((SmbWriteRawReq *)nb_ptr); uint16_t dcnt = SmbWriteRawReqDataCnt((SmbWriteRawReq *)nb_ptr); uint64_t offset = SmbWriteRawReqOffset((SmbWriteRawExtReq *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, com_size); if (DCE2_SmbCheckTotalCount(ssd, tdcnt, dcnt, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len, byte_count, dcnt, doff) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; // This may move backwards DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); if (dcnt > nb_len) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, dcnt); return DCE2_RET__ERROR; } // If all of the data wasn't written in this request, the server will // send an interim SMB_COM_WRITE_RAW response and the client will send // the rest of the data raw. In this case if the WriteThrough flag is // not set, the server will not send a final SMB_COM_WRITE_COMPLETE // response. If all of the data is in this request the server will // send an SMB_COM_WRITE_COMPLETE response regardless of whether or // not the WriteThrough flag is set. if (dcnt != tdcnt) { ssd->cur_rtracker->writeraw_writethrough = writethrough; ssd->cur_rtracker->writeraw_remaining = tdcnt - dcnt; } return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset); } else { DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); // Samba messes this up and sends a request instead of an interim // response and a response instead of a Write Complete response. switch (policy) { case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: if (SmbType(smb_hdr) != SMB_TYPE__REQUEST) return DCE2_RET__SUCCESS; break; default: break; } // If all the data wasn't written initially this interim response will // be sent by the server and the raw data will ensue from the client. ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA; } return DCE2_RET__SUCCESS; } // SMB_COM_WRITE_COMPLETE static DCE2_Ret DCE2_SmbWriteComplete(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; return DCE2_RET__SUCCESS; } #define TRANS_NM_PIPE_0 (0) #define TRANS_NM_PIPE_1 (TRANS_NM_PIPE_0+7) #define TRANS_NM_PIPE_2 (TRANS_NM_PIPE_1+1) #define TRANS_NM_PIPE_3 (TRANS_NM_PIPE_2+1) #define TRANS_NM_PIPE_4 (TRANS_NM_PIPE_3+5) #define TRANS_NM_PIPE_5 (TRANS_NM_PIPE_4+5) #define TRANS_NM_PIPE_6 (TRANS_NM_PIPE_5+1) #define TRANS_NM_PIPE_7 (TRANS_NM_PIPE_6+5) #define TRANS_NM_PIPE_8 (TRANS_NM_PIPE_7+3) #define TRANS_NM_PIPE_9 (TRANS_NM_PIPE_8+6) #define TRANS_NM_PIPE_FS (TRANS_NM_PIPE_9+1) #define TRANS_NM_PIPE_DONE (TRANS_NM_PIPE_FS+1) static DCE2_SmbFsm dce2_samba_pipe_fsm[] = { // Normal sequence {'\\', TRANS_NM_PIPE_0+1, TRANS_NM_PIPE_FS }, {'P' , TRANS_NM_PIPE_0+2, TRANS_NM_PIPE_FS }, {'I' , TRANS_NM_PIPE_0+3, TRANS_NM_PIPE_FS }, {'P' , TRANS_NM_PIPE_0+4, TRANS_NM_PIPE_FS }, {'E' , TRANS_NM_PIPE_0+5, TRANS_NM_PIPE_FS }, {'\\', TRANS_NM_PIPE_0+6, TRANS_NM_PIPE_1 }, {'\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_2 }, // Win98 {'\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_FS }, {'W' , TRANS_NM_PIPE_2+1, TRANS_NM_PIPE_5 }, {'K' , TRANS_NM_PIPE_3+1, TRANS_NM_PIPE_4 }, {'S' , TRANS_NM_PIPE_3+2, TRANS_NM_PIPE_FS }, {'S' , TRANS_NM_PIPE_3+3, TRANS_NM_PIPE_FS }, {'V' , TRANS_NM_PIPE_3+4, TRANS_NM_PIPE_FS }, {'C' , TRANS_NM_PIPE_9 , TRANS_NM_PIPE_FS }, {'I' , TRANS_NM_PIPE_4+1, TRANS_NM_PIPE_FS }, {'N' , TRANS_NM_PIPE_4+2, TRANS_NM_PIPE_FS }, {'R' , TRANS_NM_PIPE_4+3, TRANS_NM_PIPE_FS }, {'E' , TRANS_NM_PIPE_4+4, TRANS_NM_PIPE_FS }, {'G' , TRANS_NM_PIPE_9 , TRANS_NM_PIPE_FS }, {'S' , TRANS_NM_PIPE_5+1, TRANS_NM_PIPE_8 }, {'R' , TRANS_NM_PIPE_6+1, TRANS_NM_PIPE_5 }, {'V' , TRANS_NM_PIPE_6+2, TRANS_NM_PIPE_FS }, {'S' , TRANS_NM_PIPE_6+3, TRANS_NM_PIPE_FS }, {'V' , TRANS_NM_PIPE_6+4, TRANS_NM_PIPE_FS }, {'C' , TRANS_NM_PIPE_9 , TRANS_NM_PIPE_FS }, {'A' , TRANS_NM_PIPE_7+1, TRANS_NM_PIPE_FS }, {'M' , TRANS_NM_PIPE_7+2, TRANS_NM_PIPE_FS }, {'R' , TRANS_NM_PIPE_9 , TRANS_NM_PIPE_FS }, {'L' , TRANS_NM_PIPE_8+1, TRANS_NM_PIPE_FS }, {'S' , TRANS_NM_PIPE_8+2, TRANS_NM_PIPE_FS }, {'A' , TRANS_NM_PIPE_8+3, TRANS_NM_PIPE_FS }, {'R' , TRANS_NM_PIPE_8+4, TRANS_NM_PIPE_FS }, {'P' , TRANS_NM_PIPE_8+5, TRANS_NM_PIPE_FS }, {'C' , TRANS_NM_PIPE_9 , TRANS_NM_PIPE_FS }, {'\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_FS }, {0, TRANS_NM_PIPE_FS, TRANS_NM_PIPE_FS } }; // Validates Name for Samba Transaction requests static DCE2_Ret DCE2_SmbTransactionGetName(const uint8_t *nb_ptr, uint32_t nb_len, uint16_t bcc, bool unicode) { uint8_t increment = unicode ? 2 : 1; int state = TRANS_NM_PIPE_0; if ((nb_len == 0) || (bcc == 0)) return DCE2_RET__ERROR; if (bcc < nb_len) nb_len = bcc; if (unicode) DCE2_MOVE(nb_ptr, nb_len, 1); // One byte pad for unicode while ((nb_len >= increment) && (state < TRANS_NM_PIPE_FS)) { if (dce2_samba_pipe_fsm[state].input == toupper((int)nb_ptr[0])) { if (unicode && (nb_ptr[1] != 0)) break; state = dce2_samba_pipe_fsm[state].next_state; DCE2_MOVE(nb_ptr, nb_len, increment); } else { state = dce2_samba_pipe_fsm[state].fail_state; } } switch (state) { case TRANS_NM_PIPE_DONE: break; case TRANS_NM_PIPE_FS: default: return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } // Convenience function to determine whether or not the transaction is complete // for one side, i.e. all data and parameters sent. static inline bool DCE2_SmbIsTransactionComplete(DCE2_SmbTransactionTracker *ttracker) { if ((ttracker->tdcnt == ttracker->dsent) && (ttracker->tpcnt == ttracker->psent)) return true; return false; } // SMB_COM_TRANSACTION Request static inline DCE2_Ret DCE2_SmbTransactionReq(DCE2_SmbSsnData *ssd, DCE2_SmbTransactionTracker *ttracker, const uint8_t *data_ptr, uint32_t data_len, const uint8_t *param_ptr, uint32_t param_len) { switch (ttracker->subcom) { case TRANS_TRANSACT_NMPIPE: case TRANS_WRITE_NMPIPE: if (DCE2_SmbProcessRequestData(ssd, 0, data_ptr, data_len, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case TRANS_SET_NMPIPE_STATE: // Only two parameters but more seems okay if (param_len >= 2) { if ((SmbNtohs((uint16_t *)param_ptr) & PIPE_STATE_MESSAGE_MODE)) ttracker->pipe_byte_mode = false; else ttracker->pipe_byte_mode = true; // Won't get a response if (DCE2_SsnIsWindowsPolicy(&ssd->sd) && ttracker->one_way) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting pipe to %s mode\n", ttracker->pipe_byte_mode ? "byte" : "message")); ssd->cur_rtracker->ftracker->fp_byte_mode = ttracker->pipe_byte_mode; } } break; case TRANS_READ_NMPIPE: break; default: return DCE2_RET__IGNORE; } if (DCE2_SsnIsWindowsPolicy(&ssd->sd) && ttracker->one_way && ttracker->disconnect_tid) DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid); return DCE2_RET__SUCCESS; } // SMB_COM_TRANSACTION static DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; // Got a matching request for an in progress transaction - don't process it, // but don't want to remove tracker. if (DCE2_ComInfoIsRequest(com_info) && !DCE2_SmbIsTransactionComplete(ttracker)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Got new transaction request " "that matches an in progress transaction - not inspecting.\n")); return DCE2_RET__ERROR; } // Avoid decoding/tracking \PIPE\LANMAN requests if (DCE2_ComInfoIsRequest(com_info) && (DCE2_ComInfoWordCount(com_info) != 16)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "\\PIPE\\LANMAN request - not inspecting\n")); return DCE2_RET__IGNORE; } if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; // Interim response is sent if client didn't send all data / parameters // in initial Transaction request and will have to complete the request // with TransactionSecondary commands. if (DCE2_ComInfoIsResponse(com_info) && (com_size == sizeof(SmbTransactionInterimResp))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, " Server Transaction interim response.\n")); return DCE2_RET__SUCCESS; } if (DCE2_ComInfoIsRequest(com_info)) { uint16_t doff, dcnt, pcnt, poff; const uint8_t *data_ptr, *param_ptr; DCE2_Ret status = DCE2_SmbUpdateTransRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; ttracker->disconnect_tid = SmbTransactionReqDisconnectTid((SmbTransactionReq *)nb_ptr); ttracker->one_way = SmbTransactionReqOneWay((SmbTransactionReq *)nb_ptr); doff = SmbTransactionReqDataOff((SmbTransactionReq *)nb_ptr); dcnt = SmbTransactionReqDataCnt((SmbTransactionReq *)nb_ptr); pcnt = SmbTransactionReqParamCnt((SmbTransactionReq *)nb_ptr); poff = SmbTransactionReqParamOff((SmbTransactionReq *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); data_ptr = nb_ptr; DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); param_ptr = nb_ptr; status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, dcnt, param_ptr, pcnt); if (status != DCE2_RET__SUCCESS) return status; } else { DCE2_Ret status = DCE2_SmbUpdateTransResponse(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; switch (ttracker->subcom) { case TRANS_TRANSACT_NMPIPE: case TRANS_READ_NMPIPE: if (!DCE2_BufferIsEmpty(ttracker->dbuf)) { const uint8_t *data_ptr = DCE2_BufferData(ttracker->dbuf); uint32_t data_len = DCE2_BufferLength(ttracker->dbuf); SFSnortPacket *rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS); if (rpkt == NULL) return DCE2_RET__ERROR; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Reassembled Transaction response\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size);); status = DCE2_SmbProcessResponseData(ssd, data_ptr, data_len); DCE2_SmbReturnRpkt(); if (status != DCE2_RET__SUCCESS) return status; } else { uint16_t dcnt = SmbTransactionRespDataCnt((SmbTransactionResp *)nb_ptr); uint16_t doff = SmbTransactionRespDataOff((SmbTransactionResp *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); if (DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; } break; case TRANS_SET_NMPIPE_STATE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting pipe " "to %s mode\n", ttracker->pipe_byte_mode ? "byte" : "message")); ssd->cur_rtracker->ftracker->fp_byte_mode = ttracker->pipe_byte_mode; break; case TRANS_WRITE_NMPIPE: break; default: return DCE2_RET__ERROR; } if (ttracker->disconnect_tid) DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid); } return DCE2_RET__SUCCESS; } // SMB_COM_TRANSACTION_SECONDARY static DCE2_Ret DCE2_SmbTransactionSecondary(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; DCE2_Ret status; SFSnortPacket *rpkt = NULL; if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; status = DCE2_SmbUpdateTransSecondary(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; switch (ttracker->subcom) { case TRANS_TRANSACT_NMPIPE: case TRANS_WRITE_NMPIPE: { const uint8_t *data_ptr = DCE2_BufferData(ttracker->dbuf); uint32_t data_len = DCE2_BufferLength(ttracker->dbuf); rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS); if (rpkt == NULL) return DCE2_RET__ERROR; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Reassembled Transaction request\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size);); status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, data_len, DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf)); DCE2_SmbReturnRpkt(); } break; default: status = DCE2_SmbTransactionReq(ssd, ttracker, DCE2_BufferData(ttracker->dbuf), DCE2_BufferLength(ttracker->dbuf), DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf)); break; } return status; } // SMB_COM_WRITE_AND_CLOSE static DCE2_Ret DCE2_SmbWriteAndClose(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { // Have at least one byte based on byte count check done earlier uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint16_t dcnt = SmbWriteAndCloseReqCount((SmbWriteAndCloseReq *)nb_ptr); uint16_t fid = SmbWriteAndCloseReqFid((SmbWriteAndCloseReq *)nb_ptr); uint32_t offset = SmbWriteAndCloseReqOffset((SmbWriteAndCloseReq *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, (com_size + 1)); if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len, byte_count, dcnt, (uint16_t)(sizeof(SmbNtHdr) + com_size + 1)) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (dcnt == 0) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_ZERO); return DCE2_RET__ERROR; } // WriteAndClose has a 1 byte pad after the byte count if ((uint32_t)(dcnt + 1) != (uint32_t)byte_count) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_DSIZE, (dcnt + 1), byte_count); if (dcnt > nb_len) dcnt = (uint16_t)nb_len; return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset); } else { DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker); } return DCE2_RET__SUCCESS; } // SMB_COM_OPEN_ANDX static DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsResponse(com_info)) { const uint16_t fid = SmbOpenAndXRespFid((SmbOpenAndXResp *)nb_ptr); const uint16_t file_attrs = SmbOpenAndXRespFileAttrs((SmbOpenAndXResp *)nb_ptr); const uint16_t resource_type = SmbOpenAndXRespResourceType((SmbOpenAndXResp *)nb_ptr); DCE2_SmbFileTracker *ftracker = NULL; // Set request tracker's current file tracker in case of chained commands switch (SmbAndXCom2((SmbAndXCommon *)nb_ptr)) { // This is in case in the request a write was chained to an open // in which case the write will be to the newly opened file case SMB_COM_WRITE: case SMB_COM_WRITE_ANDX: case SMB_COM_TRANSACTION: case SMB_COM_READ_ANDX: ftracker = DCE2_SmbDequeueTmpFileTracker(ssd, ssd->cur_rtracker, fid); break; default: break; } if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid) && (SmbFileAttrsDirectory(file_attrs) || !SmbResourceTypeDisk(resource_type))) { if (ftracker != NULL) DCE2_SmbRemoveFileTracker(ssd, ftracker); return DCE2_RET__SUCCESS; } if (ftracker == NULL) { ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid); if (ftracker == NULL) return DCE2_RET__ERROR; } ftracker->file_name = ssd->cur_rtracker->file_name; ssd->cur_rtracker->file_name = NULL; if (!ftracker->is_ipc) { const uint16_t open_results = SmbOpenAndXRespOpenResults((SmbOpenAndXResp *)nb_ptr); if (SmbOpenResultRead(open_results)) { ftracker->ff_file_size = SmbOpenAndXRespFileSize((SmbOpenAndXResp *)nb_ptr); } else { ftracker->ff_file_size = ssd->cur_rtracker->file_size; ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD; } } ssd->cur_rtracker->ftracker = ftracker; } else { uint32_t pad = 0; const bool unicode = SmbUnicode(smb_hdr); uint8_t null_bytes = unicode ? 2 : 1; if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)) { uint16_t file_attrs = SmbOpenAndXReqFileAttrs((SmbOpenAndXReq *)nb_ptr); if (SmbEvasiveFileAttrs(file_attrs)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS); ssd->cur_rtracker->file_size = SmbOpenAndXReqAllocSize((SmbOpenAndXReq *)nb_ptr); } DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); if (unicode) pad = (nb_ptr - (const uint8_t *)smb_hdr) & 1; if (nb_len < (pad + null_bytes)) return DCE2_RET__ERROR; DCE2_MOVE(nb_ptr, nb_len, pad); // Samba allows chaining OpenAndX/NtCreateAndX so might have // already been set. if (ssd->cur_rtracker->file_name == NULL) { ssd->cur_rtracker->file_name = DCE2_SmbGetString(nb_ptr, nb_len, unicode, false); } } return DCE2_RET__SUCCESS; } // SMB_COM_READ_ANDX static DCE2_Ret DCE2_SmbReadAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { DCE2_SmbFileTracker *ftracker = DCE2_SmbGetFileTracker(ssd, SmbReadAndXReqFid((SmbReadAndXReq *)nb_ptr)); // No sense in tracking response if (ftracker == NULL) return DCE2_RET__ERROR; if (!ftracker->is_ipc) ssd->cur_rtracker->file_offset = SmbReadAndXReqOffset((SmbReadAndXExtReq *)nb_ptr); // Set this for response ssd->cur_rtracker->ftracker = ftracker; } else { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint16_t doff = SmbReadAndXRespDataOff((SmbReadAndXResp *)nb_ptr); uint32_t dcnt = SmbReadAndXRespDataCnt((SmbReadAndXResp *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, com_size); if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len, byte_count, dcnt, doff) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; // This may move backwards DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); if (dcnt > nb_len) dcnt = nb_len; return DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt); } return DCE2_RET__SUCCESS; } // SMB_COM_WRITE_ANDX static DCE2_Ret DCE2_SmbWriteAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) { DCE2_SmbFileTracker *ftracker = ssd->cur_rtracker->ftracker; if ((ftracker != NULL) && ftracker->is_ipc && (ftracker->fp_writex_raw != NULL)) { ftracker->fp_writex_raw->remaining = 0; DCE2_BufferEmpty(ftracker->fp_writex_raw->buf); } return DCE2_RET__ERROR; } if (DCE2_ComInfoIsRequest(com_info) && (SmbWriteAndXReqStartRaw((SmbWriteAndXReq *)nb_ptr) || SmbWriteAndXReqRaw((SmbWriteAndXReq *)nb_ptr))) { DCE2_SmbFileTracker *ftracker = DCE2_SmbGetFileTracker(ssd, SmbWriteAndXReqFid((SmbWriteAndXReq *)nb_ptr)); // Raw mode is only applicable to named pipes. if ((ftracker != NULL) && ftracker->is_ipc) return DCE2_SmbWriteAndXRawRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len); } if (DCE2_ComInfoIsRequest(com_info)) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint16_t fid = SmbWriteAndXReqFid((SmbWriteAndXReq *)nb_ptr); uint16_t doff = SmbWriteAndXReqDataOff((SmbWriteAndXReq *)nb_ptr); uint32_t dcnt = SmbWriteAndXReqDataCnt((SmbWriteAndXReq *)nb_ptr); uint64_t offset = SmbWriteAndXReqOffset((SmbWriteAndXExtReq *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, com_size); if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len, byte_count, dcnt, doff) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; // This may move backwards DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); if (dcnt > nb_len) { // Current Samba errors if data count is greater than data left if (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA) return DCE2_RET__ERROR; // Windows and early Samba just use what's left dcnt = nb_len; } return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset); } return DCE2_RET__SUCCESS; } // SMB_COM_WRITE_ANDX - raw mode static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint16_t fid = SmbWriteAndXReqFid((SmbWriteAndXReq *)nb_ptr); uint16_t doff = SmbWriteAndXReqDataOff((SmbWriteAndXReq *)nb_ptr); uint32_t dcnt = SmbWriteAndXReqDataCnt((SmbWriteAndXReq *)nb_ptr); bool start_write_raw = SmbWriteAndXReqStartRaw((SmbWriteAndXReq *)nb_ptr); bool continue_write_raw = SmbWriteAndXReqRaw((SmbWriteAndXReq *)nb_ptr); uint16_t remaining = SmbWriteAndXReqRemaining((SmbWriteAndXReq *)nb_ptr); DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); DCE2_SmbFileTracker *ftracker = DCE2_SmbGetFileTracker(ssd, fid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Processing WriteAndX with raw mode flags\n")); // Set this now for possible reassembled packet ssd->cur_rtracker->ftracker = ftracker; if (ftracker == NULL) return DCE2_RET__ERROR; // Got request to write in raw mode without having gotten the initial // raw mode request or got initial raw mode request and then another // without having finished the first. if ((start_write_raw && (ftracker->fp_writex_raw != NULL) && (ftracker->fp_writex_raw->remaining != 0)) || (continue_write_raw && ((ftracker->fp_writex_raw == NULL) || (ftracker->fp_writex_raw->remaining == 0)))) { switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: if (ftracker->fp_writex_raw != NULL) { ftracker->fp_writex_raw->remaining = 0; DCE2_BufferEmpty(ftracker->fp_writex_raw->buf); } return DCE2_RET__ERROR; case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: // Samba doesn't do anything special here except if the two // flags are set it walks past the two "length" bytes. // See below. break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); break; } } DCE2_MOVE(nb_ptr, nb_len, com_size); if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len, byte_count, dcnt, doff) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; // This may move backwards DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); // If a "raw" write is requested there will be two bytes after the // header/pad and before the data which is supposed to represent a // length but everyone ignores it. However we need to move past it. // This is the one situation where the remaining field matters and // should be equal to the total amount of data to be written. if (start_write_raw) { if (dcnt < 2) return DCE2_RET__ERROR; // From data size check above, nb_len >= dsize dcnt -= 2; DCE2_MOVE(nb_ptr, nb_len, 2); } if (dcnt > nb_len) dcnt = nb_len; // File tracker already validated switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: if (start_write_raw) { if (ftracker->fp_writex_raw == NULL) { ftracker->fp_writex_raw = (DCE2_SmbWriteAndXRaw *) DCE2_Alloc(sizeof(DCE2_SmbWriteAndXRaw), DCE2_MEM_TYPE__SMB_FID); if (ftracker->fp_writex_raw == NULL) return DCE2_RET__ERROR; ftracker->fp_writex_raw->remaining = (int)remaining; } } ftracker->fp_writex_raw->remaining -= (int)dcnt; if (ftracker->fp_writex_raw->remaining < 0) { ftracker->fp_writex_raw->remaining = 0; DCE2_BufferEmpty(ftracker->fp_writex_raw->buf); return DCE2_RET__ERROR; } // If the "raw" write isn't finished in the first request // and haven't allocated a buffer yet. if (start_write_raw && (ftracker->fp_writex_raw->remaining != 0) && (ftracker->fp_writex_raw->buf == NULL)) { ftracker->fp_writex_raw->buf = DCE2_BufferNew(remaining, 0, DCE2_MEM_TYPE__SMB_FID); if (ftracker->fp_writex_raw->buf == NULL) { ftracker->fp_writex_raw->remaining = 0; return DCE2_RET__ERROR; } } // If data has to be added to buffer, i.e. not a start raw // or a start raw and more raw requests to come. if (!start_write_raw || (ftracker->fp_writex_raw->remaining != 0)) { if (DCE2_BufferAddData(ftracker->fp_writex_raw->buf, nb_ptr, dcnt, DCE2_BufferLength(ftracker->fp_writex_raw->buf), DCE2_BUFFER_MIN_ADD_FLAG__IGNORE) != DCE2_RET__SUCCESS) { ftracker->fp_writex_raw->remaining = 0; DCE2_BufferEmpty(ftracker->fp_writex_raw->buf); return DCE2_RET__ERROR; } if (ftracker->fp_writex_raw->remaining == 0) { // Create reassembled packet const uint8_t *data_ptr = DCE2_BufferData(ftracker->fp_writex_raw->buf); uint32_t data_len = DCE2_BufferLength(ftracker->fp_writex_raw->buf); SFSnortPacket *rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS); if (rpkt == NULL) { DCE2_BufferEmpty(ftracker->fp_writex_raw->buf); return DCE2_RET__ERROR; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Reassembled WriteAndX raw mode request\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size);); (void)DCE2_SmbProcessRequestData(ssd, fid, data_ptr, data_len, 0); DCE2_SmbReturnRpkt(); DCE2_BufferEmpty(ftracker->fp_writex_raw->buf); } } else { (void)DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, 0); } // Windows doesn't process chained commands to raw WriteAndXs // so return error so it exits the loop. return DCE2_RET__ERROR; case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: // All Samba cares about is skipping the 2 byte "length" // if both flags are set. break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); break; } return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, 0); } // TRANS2_OPEN2 static inline DCE2_Ret DCE2_SmbTrans2Open2Req(DCE2_SmbSsnData *ssd, const uint8_t *param_ptr, uint32_t param_len, bool unicode) { if (param_len < sizeof(SmbTrans2Open2ReqParams)) return DCE2_RET__ERROR; if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)) { uint16_t file_attrs = SmbTrans2Open2ReqFileAttrs((SmbTrans2Open2ReqParams *)param_ptr); if (SmbEvasiveFileAttrs(file_attrs)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS); ssd->cur_rtracker->file_size = SmbTrans2Open2ReqAllocSize((SmbTrans2Open2ReqParams *)param_ptr); } DCE2_MOVE(param_ptr, param_len, sizeof(SmbTrans2Open2ReqParams)); ssd->cur_rtracker->file_name = DCE2_SmbGetString(param_ptr, param_len, unicode, false); return DCE2_RET__SUCCESS; } // TRANS2_QUERY_FILE_INFORMATION static inline DCE2_Ret DCE2_SmbTrans2QueryFileInfoReq(DCE2_SmbSsnData *ssd, const uint8_t *param_ptr, uint32_t param_len) { DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; DCE2_SmbFileTracker *ftracker; if (param_len < sizeof(SmbTrans2QueryFileInfoReqParams)) return DCE2_RET__ERROR; ftracker = DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbTrans2QueryFileInfoReqFid((SmbTrans2QueryFileInfoReqParams *)param_ptr)); if ((ftracker == NULL) || ftracker->is_ipc || DCE2_SmbFileUpload(ftracker->ff_file_direction)) return DCE2_RET__IGNORE; ttracker->info_level = SmbTrans2QueryFileInfoReqInfoLevel((SmbTrans2QueryFileInfoReqParams *)param_ptr); ssd->cur_rtracker->ftracker = ftracker; return DCE2_RET__SUCCESS; } // TRANS2_SET_FILE_INFORMATION static inline DCE2_Ret DCE2_SmbTrans2SetFileInfoReq(DCE2_SmbSsnData *ssd, const uint8_t *param_ptr, uint32_t param_len, const uint8_t *data_ptr, uint32_t data_len) { DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; DCE2_SmbFileTracker *ftracker; if ((param_len < sizeof(SmbTrans2SetFileInfoReqParams)) || (data_len < sizeof(uint64_t))) return DCE2_RET__ERROR; ttracker->info_level = SmbTrans2SetFileInfoReqInfoLevel((SmbTrans2SetFileInfoReqParams *)param_ptr); // Check to see if there is an attempt to set READONLY/HIDDEN/SYSTEM // attributes on a file if (SmbSetFileInfoSetFileBasicInfo(ttracker->info_level) && (data_len >= sizeof(SmbSetFileBasicInfo))) { uint32_t ext_file_attrs = SmbSetFileInfoExtFileAttrs((SmbSetFileBasicInfo *)data_ptr); if (SmbEvasiveFileAttrs(ext_file_attrs)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS); // Don't need to see the response return DCE2_RET__IGNORE; } // Only looking for end of file information for this subcommand if (!SmbSetFileInfoEndOfFile(ttracker->info_level)) return DCE2_RET__IGNORE; ftracker = DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbTrans2SetFileInfoReqFid((SmbTrans2SetFileInfoReqParams *)param_ptr)); if ((ftracker == NULL) || ftracker->is_ipc || DCE2_SmbFileDownload(ftracker->ff_file_direction) || (ftracker->ff_bytes_processed != 0)) return DCE2_RET__IGNORE; ssd->cur_rtracker->file_size = SmbNtohq((uint64_t *)data_ptr); ssd->cur_rtracker->ftracker = ftracker; return DCE2_RET__SUCCESS; } // SMB_COM_TRANSACTION2 static DCE2_Ret DCE2_SmbTransaction2(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; // Got a matching request for an in progress transaction - don't process it, // but don't want to remove tracker. if (DCE2_ComInfoIsRequest(com_info) && !DCE2_SmbIsTransactionComplete(ttracker)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Got new transaction request " "that matches an in progress transaction - not inspecting.\n")); return DCE2_RET__ERROR; } if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; // Interim response is sent if client didn't send all data / parameters // in initial Transaction2 request and will have to complete the request // with Transaction2Secondary commands. if (DCE2_ComInfoIsResponse(com_info) && (com_size == sizeof(SmbTransaction2InterimResp))) { return DCE2_RET__SUCCESS; } if (DCE2_ComInfoIsRequest(com_info)) { uint16_t pcnt = SmbTransaction2ReqParamCnt((SmbTransaction2Req *)nb_ptr); uint16_t poff = SmbTransaction2ReqParamOff((SmbTransaction2Req *)nb_ptr); uint16_t dcnt = SmbTransaction2ReqDataCnt((SmbTransaction2Req *)nb_ptr); uint16_t doff = SmbTransaction2ReqDataOff((SmbTransaction2Req *)nb_ptr); const uint8_t *data_ptr; DCE2_Ret status = DCE2_SmbUpdateTransRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); switch (ttracker->subcom) { case TRANS2_OPEN2: if (DCE2_SmbTrans2Open2Req(ssd, nb_ptr, pcnt, SmbUnicode(smb_hdr)) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case TRANS2_QUERY_FILE_INFORMATION: status = DCE2_SmbTrans2QueryFileInfoReq(ssd, nb_ptr, pcnt); if (status != DCE2_RET__SUCCESS) return status; break; case TRANS2_SET_FILE_INFORMATION: data_ptr = nb_ptr; DCE2_MOVE(data_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - data_ptr); status = DCE2_SmbTrans2SetFileInfoReq(ssd, nb_ptr, pcnt, data_ptr, dcnt); if (status != DCE2_RET__SUCCESS) return status; break; default: return DCE2_RET__IGNORE; } } else { const uint8_t *ptr; uint32_t len; DCE2_SmbFileTracker *ftracker = NULL; DCE2_Ret status = DCE2_SmbUpdateTransResponse(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; switch (ttracker->subcom) { case TRANS2_OPEN2: if (!DCE2_BufferIsEmpty(ttracker->pbuf)) { ptr = DCE2_BufferData(ttracker->pbuf); len = DCE2_BufferLength(ttracker->pbuf); } else { uint16_t poff = SmbTransaction2RespParamOff((SmbTransaction2Resp *)nb_ptr); uint16_t pcnt = SmbTransaction2RespParamCnt((SmbTransaction2Resp *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); ptr = nb_ptr; len = pcnt; } if (len < sizeof(SmbTrans2Open2RespParams)) return DCE2_RET__ERROR; if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid) && (SmbFileAttrsDirectory(SmbTrans2Open2RespFileAttrs( (SmbTrans2Open2RespParams *)ptr)) || !SmbResourceTypeDisk(SmbTrans2Open2RespResourceType( (SmbTrans2Open2RespParams *)ptr)))) { return DCE2_RET__SUCCESS; } ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbTrans2Open2RespFid((SmbTrans2Open2RespParams *)ptr)); if (ftracker == NULL) return DCE2_RET__ERROR; ftracker->file_name = ssd->cur_rtracker->file_name; ssd->cur_rtracker->file_name = NULL; if (!ftracker->is_ipc) { uint16_t open_results = SmbTrans2Open2RespActionTaken((SmbTrans2Open2RespParams *)ptr); if (SmbOpenResultRead(open_results)) { ftracker->ff_file_size = SmbTrans2Open2RespFileDataSize((SmbTrans2Open2RespParams *)ptr); } else { ftracker->ff_file_size = ssd->cur_rtracker->file_size; ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD; } } break; case TRANS2_QUERY_FILE_INFORMATION: ftracker = ssd->cur_rtracker->ftracker; if (ftracker == NULL) return DCE2_RET__ERROR; if (!DCE2_BufferIsEmpty(ttracker->dbuf)) { ptr = DCE2_BufferData(ttracker->dbuf); len = DCE2_BufferLength(ttracker->dbuf); } else { uint16_t doff = SmbTransaction2RespDataOff((SmbTransaction2Resp *)nb_ptr); uint16_t dcnt = SmbTransaction2RespDataCnt((SmbTransaction2Resp *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); ptr = nb_ptr; len = dcnt; } switch (ttracker->info_level) { case SMB_INFO_STANDARD: if (len >= sizeof(SmbQueryInfoStandard)) { ftracker->ff_file_size = SmbQueryInfoStandardFileDataSize((SmbQueryInfoStandard *)ptr); } break; case SMB_INFO_QUERY_EA_SIZE: if (len >= sizeof(SmbQueryInfoQueryEaSize)) { ftracker->ff_file_size = SmbQueryInfoQueryEaSizeFileDataSize((SmbQueryInfoQueryEaSize *)ptr); } break; case SMB_QUERY_FILE_STANDARD_INFO: if (len >= sizeof(SmbQueryFileStandardInfo)) { ftracker->ff_file_size = SmbQueryFileStandardInfoEndOfFile((SmbQueryFileStandardInfo *)ptr); } break; case SMB_QUERY_FILE_ALL_INFO: if (len >= sizeof(SmbQueryFileAllInfo)) { ftracker->ff_file_size = SmbQueryFileAllInfoEndOfFile((SmbQueryFileAllInfo *)ptr); } break; case SMB_INFO_PT_FILE_STANDARD_INFO: if (len >= sizeof(SmbQueryPTFileStreamInfo)) { ftracker->ff_file_size = SmbQueryPTFileStreamInfoStreamSize((SmbQueryPTFileStreamInfo *)ptr); } break; case SMB_INFO_PT_FILE_STREAM_INFO: if (len >= sizeof(SmbQueryFileStandardInfo)) { ftracker->ff_file_size = SmbQueryFileStandardInfoEndOfFile((SmbQueryFileStandardInfo *)ptr); } break; case SMB_INFO_PT_FILE_ALL_INFO: if (len >= sizeof(SmbQueryPTFileAllInfo)) { ftracker->ff_file_size = SmbQueryPTFileAllInfoEndOfFile((SmbQueryPTFileAllInfo *)ptr); } break; case SMB_INFO_PT_NETWORK_OPEN_INFO: if (len >= sizeof(SmbQueryPTNetworkOpenInfo)) { ftracker->ff_file_size = SmbQueryPTNetworkOpenInfoEndOfFile((SmbQueryPTNetworkOpenInfo *)ptr); } break; default: break; } break; case TRANS2_SET_FILE_INFORMATION: ftracker = ssd->cur_rtracker->ftracker; if (ftracker == NULL) return DCE2_RET__ERROR; if (!DCE2_BufferIsEmpty(ttracker->pbuf)) { ptr = DCE2_BufferData(ttracker->pbuf); len = DCE2_BufferLength(ttracker->pbuf); } else { uint16_t poff = SmbTransaction2RespParamOff((SmbTransaction2Resp *)nb_ptr); uint16_t pcnt = SmbTransaction2RespParamCnt((SmbTransaction2Resp *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); ptr = nb_ptr; len = pcnt; } // *ptr will be non-zero if there was an error. if ((len >= 2) && (*ptr == 0)) ftracker->ff_file_size = ssd->cur_rtracker->file_size; break; default: break; } } return DCE2_RET__SUCCESS; } // SMB_COM_TRANSACTION2_SECONDARY static DCE2_Ret DCE2_SmbTransaction2Secondary(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { DCE2_Ret status; DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; status = DCE2_SmbUpdateTransSecondary(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; switch (ttracker->subcom) { case TRANS2_OPEN2: status = DCE2_SmbTrans2Open2Req(ssd, DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf), SmbUnicode(smb_hdr)); if (status != DCE2_RET__SUCCESS) return status; break; case TRANS2_QUERY_FILE_INFORMATION: status = DCE2_SmbTrans2QueryFileInfoReq(ssd, DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf)); if (status != DCE2_RET__SUCCESS) return status; break; case TRANS2_SET_FILE_INFORMATION: status = DCE2_SmbTrans2SetFileInfoReq(ssd, DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf), DCE2_BufferData(ttracker->dbuf), DCE2_BufferLength(ttracker->dbuf)); if (status != DCE2_RET__SUCCESS) return status; break; default: break; } return DCE2_RET__SUCCESS; } #define SHARE_0 (0) #define SHARE_FS (SHARE_0+5) #define SHARE_IPC (SHARE_FS+1) static DCE2_SmbFsm dce2_ipc_share_fsm[] = { {'I' , SHARE_0+1, SHARE_FS }, {'P' , SHARE_0+2, SHARE_FS }, {'C' , SHARE_0+3, SHARE_FS }, {'$' , SHARE_0+4, SHARE_FS }, {'\0', SHARE_IPC, SHARE_FS }, {0, SHARE_FS, SHARE_FS } }; // SMB_COM_TREE_CONNECT static DCE2_Ret DCE2_SmbTreeConnect(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); const uint8_t *bs = NULL; bool unicode = SmbUnicode(smb_hdr); uint8_t increment = unicode ? 2 : 1; int state = SHARE_0; bool is_ipc = false; // Have at least 4 bytes of data based on byte count check done earlier DCE2_MOVE(nb_ptr, nb_len, com_size); // If unicode flag is set, strings, except possibly the service string // are going to be unicode. The NT spec specifies that unicode strings // must be word aligned with respect to the beginning of the SMB and that for // type-prefixed strings (this case), the padding byte is found after the // type format byte. // This byte will realign things. if (*nb_ptr != SMB_FMT__ASCII) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, 1); // IPC$ does not need to be case sensitive. And the case sensitivity flag in // the SMB header doesn't seem to have any effect on this. while ((bs = memchr(nb_ptr, '\\', nb_len)) != NULL) DCE2_MOVE(nb_ptr, nb_len, (bs - nb_ptr) + 1); if (unicode && (nb_len > 0)) DCE2_MOVE(nb_ptr, nb_len, 1); // Check for invalid shares first if ((DCE2_ScSmbInvalidShares(ssd->sd.sconfig) != NULL) && (nb_len > 0)) DCE2_SmbInvalidShareCheck(ssd, smb_hdr, nb_ptr, nb_len); while ((nb_len >= increment) && (state < SHARE_FS)) { if (dce2_ipc_share_fsm[state].input == toupper((int)nb_ptr[0])) { if (unicode && (nb_ptr[1] != 0)) break; state = dce2_ipc_share_fsm[state].next_state; DCE2_MOVE(nb_ptr, nb_len, increment); } else { state = dce2_ipc_share_fsm[state].fail_state; } } switch (state) { case SHARE_IPC: is_ipc = true; break; case SHARE_FS: default: break; } ssd->cur_rtracker->is_ipc = is_ipc; } else { // XXX What if the TID in the SMB header differs from that returned // in the TreeConnect command response? uint16_t tid = SmbTid(smb_hdr); DCE2_SmbInsertTid(ssd, tid, ssd->cur_rtracker->is_ipc); DCE2_DEBUG_CODE(DCE2_DEBUG__SMB, if (ssd->cur_rtracker->is_ipc) printf("Tid (%u) is an IPC tree\n", tid); else printf("Tid (%u) not an IPC tree\n", tid);); } return DCE2_RET__SUCCESS; } // SMB_COM_TREE_DISCONNECT static DCE2_Ret DCE2_SmbTreeDisconnect(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsResponse(com_info)) DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid); return DCE2_RET__SUCCESS; } // SMB_COM_NEGOTIATE static DCE2_Ret DCE2_SmbNegotiate(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); PROFILE_VARS; if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; PREPROC_PROFILE_START(dce2_pstat_smb_negotiate); if (DCE2_ComInfoIsRequest(com_info)) { // Have at least 2 bytes based on byte count check done earlier uint8_t *term_ptr; int ntlm_index = 0; DCE2_MOVE(nb_ptr, nb_len, com_size); while ((term_ptr = memchr(nb_ptr, '\0', nb_len)) != NULL) { if (!SmbFmtDialect(*nb_ptr)) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr); // Windows errors if bad format if (DCE2_SsnIsWindowsPolicy(&ssd->sd)) { PREPROC_PROFILE_END(dce2_pstat_smb_negotiate); return DCE2_RET__ERROR; } } // Move past format DCE2_MOVE(nb_ptr, nb_len, 1); if (nb_len == 0) break; // Just a NULL byte - acceptable by Samba and Windows if (term_ptr == nb_ptr) continue; if ((*nb_ptr == 'N') && (strncmp((const char *)nb_ptr, SMB_DIALECT_NT_LM_012, term_ptr - nb_ptr) == 0)) break; // Move past string and NULL byte DCE2_MOVE(nb_ptr, nb_len, (term_ptr - nb_ptr) + 1); ntlm_index++; } if (term_ptr != NULL) { ssd->dialect_index = ntlm_index; } else { ssd->dialect_index = DCE2_SENTINEL; DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED); } } else { uint16_t dialect_index = SmbNegotiateRespDialectIndex((SmbCore_NegotiateProtocolResp *)nb_ptr); if ((ssd->dialect_index != DCE2_SENTINEL) && (dialect_index != ssd->dialect_index)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED); ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__NEGOTIATED; if (DCE2_ComInfoWordCount(com_info) == 17) { ssd->max_outstanding_requests = SmbNt_NegotiateRespMaxMultiplex((SmbNt_NegotiateProtocolResp *)nb_ptr); } else if (DCE2_ComInfoWordCount(com_info) == 13) { ssd->max_outstanding_requests = SmbLm_NegotiateRespMaxMultiplex((SmbLm10_NegotiateProtocolResp *)nb_ptr); } else { ssd->max_outstanding_requests = 1; } } PREPROC_PROFILE_END(dce2_pstat_smb_negotiate); return DCE2_RET__SUCCESS; } #define OS_0 (0) // "Windows" start #define OS_1 (OS_0+ 8) // Windows 2000 and XP server #define OS_2 (OS_1+ 4) // Windows 2000 and XP client #define OS_3 (OS_2+ 5) // "Server", 2003, 2008R2, 2008 #define OS_4 (OS_3+20) // Windows Vista #define OS_5 (OS_4 +5) // Windows 7 #define OS_6 (OS_5 +1) // Windows NT #define OS_7 (OS_6 +2) // Windows 98 #define OS_FS (OS_7+ 3) // Failure state #define OS_WIN2000 (OS_FS+1) #define OS_WINXP (OS_FS+2) #define OS_WIN2003 (OS_FS+3) #define OS_WINVISTA (OS_FS+4) #define OS_WIN2008 (OS_FS+5) #define OS_WIN7 (OS_FS+6) static DCE2_SmbFsm dce2_smb_os_fsm[] = { // Windows start states { 'W', OS_0+1, OS_FS }, { 'i', OS_0+2, OS_FS }, { 'n', OS_0+3, OS_FS }, { 'd', OS_0+4, OS_FS }, { 'o', OS_0+5, OS_FS }, { 'w', OS_0+6, OS_FS }, { 's', OS_0+7, OS_FS }, { ' ', OS_0+8, OS_FS }, // Windows 2000 and XP server states { '5', OS_1+1, OS_2 }, { '.', OS_1+2, OS_FS }, { '1', OS_WINXP, OS_1+3 }, // Windows XP { '0', OS_WIN2000, OS_FS }, // Windows 2000 // Windows 2000 or XP client states { '2', OS_2+1, OS_3 }, { '0', OS_2+2, OS_FS }, { '0', OS_2+3, OS_FS }, { '2', OS_WINXP, OS_2+4 }, // Windows XP { '0', OS_WIN2000, OS_FS }, // Windows 2000 // "Server" string states { 'S', OS_3+ 1, OS_4 }, { 'e', OS_3+ 2, OS_FS }, { 'r', OS_3+ 3, OS_FS }, { 'v', OS_3+ 4, OS_FS }, { 'e', OS_3+ 5, OS_FS }, { 'r', OS_3+ 6, OS_FS }, { ' ', OS_3+ 7, OS_FS }, { '2', OS_3+ 8, OS_3+12 }, { '0', OS_3+ 9, OS_FS }, { '0', OS_3+10, OS_FS }, { '3', OS_WIN2003, OS_3+11 }, // Windows Server 2003 { '8', OS_WIN2008, OS_FS }, // Windows Server 2008R2 // Windows 2008 has this, 2008 R2 does not { '(', OS_3+13, OS_FS }, { 'R', OS_3+14, OS_FS }, { ')', OS_3+15, OS_FS }, { ' ', OS_3+16, OS_FS }, { '2', OS_3+17, OS_FS }, { '0', OS_3+18, OS_FS }, { '0', OS_3+19, OS_FS }, { '8', OS_WIN2008, OS_FS }, // Windows Vista states { 'V', OS_4+1, OS_5 }, { 'i', OS_4+2, OS_FS }, { 's', OS_4+3, OS_FS }, { 't', OS_4+4, OS_FS }, { 'a', OS_WINVISTA, OS_FS }, // Windows 7 state { '7', OS_WIN7, OS_6 }, // Windows NT { 'N', OS_6+1, OS_7 }, { 'T', OS_WIN2000, OS_FS }, // Windows NT, set policy to Windows 2000 // Windows 98 { '4', OS_7+1, OS_FS }, { '.', OS_7+2, OS_FS }, { '0', OS_WIN2000, OS_FS }, // Windows 98, set policy to Windows 2000 // Failure state { 0, OS_FS, OS_FS } // Match states shouldn't be accessed }; // SMB_COM_SESSION_SETUP_ANDX static DCE2_Ret DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { uint16_t max_multiplex = SmbSessionSetupAndXReqMaxMultiplex((SmbLm10_SessionSetupAndXReq *)nb_ptr); if (max_multiplex < ssd->max_outstanding_requests) ssd->max_outstanding_requests = max_multiplex; if (!DCE2_SmbFingerprintedClient(ssd) && DCE2_GcSmbFingerprintClient()) { uint8_t increment = SmbUnicode(smb_hdr) ? 2 : 1; uint16_t word_count = DCE2_ComInfoWordCount(com_info); uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint32_t i; PROFILE_VARS; DCE2_SmbSetFingerprintedClient(ssd); // OS and Lanman strings won't be in request if ((word_count != 13) && (word_count != 12)) return DCE2_RET__SUCCESS; PREPROC_PROFILE_START(dce2_pstat_smb_fingerprint); if (word_count == 13) { uint16_t oem_pass_len = SmbNt10SessionSetupAndXReqOemPassLen((SmbNt10_SessionSetupAndXReq *)nb_ptr); uint16_t uni_pass_len = SmbNt10SessionSetupAndXReqUnicodePassLen((SmbNt10_SessionSetupAndXReq *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, com_size); if (((uint32_t)oem_pass_len + uni_pass_len) > nb_len) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, (oem_pass_len + uni_pass_len)); // If unicode there should be a padding byte if the password // lengths are even since the command length is odd if ((increment == 2) && (nb_len != 0) && !((oem_pass_len + uni_pass_len) & 1)) DCE2_MOVE(nb_ptr, nb_len, 1); } else // Extended security blob version, word count of 12 { uint16_t blob_len = SmbSessionSetupAndXReqBlobLen((SmbNt10_SessionSetupAndXExtReq *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, com_size); if (blob_len > nb_len) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, blob_len); // If unicode there should be a padding byte if the blob // length is even since the command length is odd if ((increment == 2) && (nb_len != 0) && !(blob_len & 1)) DCE2_MOVE(nb_ptr, nb_len, 1); } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Attempting to fingerprint " "Client Windows/Samba version ... \n")); // Move past Account and Domain strings // Blob version doesn't have these as they're in the blob if (DCE2_ComInfoWordCount(com_info) == 13) { int j; for (j = 0; j < 2; j++) { while ((nb_len >= increment) && (*nb_ptr != '\0')) DCE2_MOVE(nb_ptr, nb_len, increment); // Just return success if we run out of data if (nb_len < increment) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Move past NULL string terminator DCE2_MOVE(nb_ptr, nb_len, increment); } } if (nb_len < increment) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Note the below is quick and dirty. We're assuming the client // is kosher. It's policy will be used when the server is // sending data to it. #ifdef DEBUG { uint32_t k, l = 0; char buf[65535]; for (k = 0; (k < nb_len) && (nb_ptr[k] != 0); k += increment, l++) buf[l] = nb_ptr[k]; buf[l] = 0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, " Client OS: %s\n", buf)); k += increment; l = 0; for (; k < nb_len && nb_ptr[k] != 0; k += increment, l++) buf[l] = nb_ptr[k]; buf[l] = 0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, " Client Lanman: %s\n", buf)); } #endif // Windows Vista and above don't put anything here if (*nb_ptr == '\0') { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting client policy to Windows Vista\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINVISTA); PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Windows if (*nb_ptr == 'W') { int state = OS_0; int64_t rlen = (int64_t)nb_len; while ((rlen > 0) && (state < OS_FS)) { if (dce2_smb_os_fsm[state].input == (char)*nb_ptr) { state = dce2_smb_os_fsm[state].next_state; DCE2_MOVE(nb_ptr, rlen, increment); } else { state = dce2_smb_os_fsm[state].fail_state; } } switch (state) { case OS_WIN2000: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting client policy to Windows 2000\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2000); break; case OS_WINXP: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting client policy to Windows XP\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINXP); break; case OS_WIN2003: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting client policy to Windows 2003\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2003); break; default: break; } PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Samba puts "Unix" in the OS field if (*nb_ptr != 'U') { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Move past OS string for (i = 0; (i < nb_len) && (nb_ptr[i] != '\0'); i += increment); if ((i + increment) >= nb_len) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Move to LanMan string DCE2_MOVE(nb_ptr, nb_len, i + increment); // Samba if (*nb_ptr == 'S') { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting client policy to Samba\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA); } PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); } } else { uint16_t uid = SmbUid(smb_hdr); DCE2_SmbInsertUid(ssd, uid); ssd->cur_rtracker->uid = uid; // Set this in case there are chained commands if (!(ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED)) ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__NEGOTIATED; if (!DCE2_SmbFingerprintedServer(ssd) && DCE2_GcSmbFingerprintServer()) { uint8_t increment = SmbUnicode(smb_hdr) ? 2 : 1; uint32_t i; PROFILE_VARS; DCE2_SmbSetFingerprintedServer(ssd); // Set the policy based on what the server reports in the OS field // for Windows and the LanManager field for Samba if (DCE2_ComInfoByteCount(com_info) == 0) return DCE2_RET__SUCCESS; PREPROC_PROFILE_START(dce2_pstat_smb_fingerprint); if (DCE2_ComInfoWordCount(com_info) == 3) { DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); // Word count 3 and Unicode has a one byte pad if ((increment == 2) && (nb_len != 0)) DCE2_MOVE(nb_ptr, nb_len, 1); } else // Only valid word counts are 3 and 4 { uint16_t blob_len = SmbSessionSetupAndXRespBlobLen((SmbNt10_SessionSetupAndXExtResp *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); if (blob_len > nb_len) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, blob_len); if ((increment == 2) && (nb_len != 0) && !(blob_len & 1)) DCE2_MOVE(nb_ptr, nb_len, 1); } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Attempting to fingerprint " "Server Windows/Samba version ... \n")); // Note the below is quick and dirty. We're assuming the server // is kosher. It's policy will be used when the client is // sending data to it. #ifdef DEBUG { uint32_t k, l = 0; char buf[65535]; for (k = 0; (k < nb_len) && (nb_ptr[k] != 0); k += increment, l++) buf[l] = nb_ptr[k]; buf[l] = 0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, " Server OS: %s\n", buf)); k += increment; l = 0; for (; k < nb_len && nb_ptr[k] != 0; k += increment, l++) buf[l] = nb_ptr[k]; buf[l] = 0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, " Server Lanman: %s\n", buf)); } #endif if ((nb_len < increment) || (*nb_ptr == '\0')) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Next field should be OS string for (i = 0; (i < nb_len) && (nb_ptr[i] != '\0'); i += increment); i -= increment; // Windows if (*nb_ptr == 'W') { int state = OS_0; int64_t rlen = (int64_t)nb_len; while ((rlen > 0) && (state < OS_FS)) { if (dce2_smb_os_fsm[state].input == (char)*nb_ptr) { state = dce2_smb_os_fsm[state].next_state; DCE2_MOVE(nb_ptr, rlen, increment); } else { state = dce2_smb_os_fsm[state].fail_state; } } switch (state) { case OS_WIN2000: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Windows 2000\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2000); break; case OS_WINXP: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Windows XP\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINXP); break; case OS_WIN2003: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Windows 2003\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2003); break; case OS_WIN2008: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Windows 2008\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2008); break; case OS_WINVISTA: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Windows Vista\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINVISTA); break; case OS_WIN7: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Windows 7\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN7); break; default: break; } PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Samba puts "Unix" in the OS field if (*nb_ptr != 'U') { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Move past OS string for (i = 0; (i < nb_len) && (nb_ptr[i] != '\0'); i += increment); if ((i + increment) >= nb_len) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Move to LanMan string DCE2_MOVE(nb_ptr, nb_len, i + increment); // Samba if (*nb_ptr == 'S') { uint8_t r1 = 0; // Release version first digit uint8_t r2 = 0; // Release version second digit // Get Major version for (i = 0; (i < nb_len) && (*nb_ptr != '\0'); i += increment) { if (isdigit((int)nb_ptr[i])) break; } if ((i == nb_len) || (*nb_ptr == '\0')) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // If less than 3 set policy to earliest Samba policy we use if ((nb_ptr[i] == '0') || (nb_ptr[i] == '1') || (nb_ptr[i] == '2')) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Samba 3.0.20\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_20); PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // Need ".\d.\d\d" or ".\d.\d\x00" if (i + increment*5 > nb_len) { PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } i += increment*2; // If it's not 0, then set to latest Samba policy we use if (nb_ptr[i] != '0') { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to current Samba\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA); PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } r1 = nb_ptr[i + increment*2]; r2 = nb_ptr[i + increment*3]; // First digit is 1 or no second digit or 20, Samba 3.0.20 if ((r1 == '1') || (r2 == '\0') || ((r1 == '2') && (r2 == '0'))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Samba 3.0.20\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_20); PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // 21 or 22, Samba 3.0.22 if ((r1 == '2') && (r2 <= '2')) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Samba 3.0.22\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_22); PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } // 23, 24 ... 30 ... 37, Samba 3.0.37 if ((r1 == '2') || ((r1 == '3') && (r2 <= '7'))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to Samba 3.0.37\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_37); PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); return DCE2_RET__SUCCESS; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting server policy to current Samba\n")); DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA); } PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint); } } return DCE2_RET__SUCCESS; } // SMB_COM_LOGOFF_ANDX static DCE2_Ret DCE2_SmbLogoffAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsResponse(com_info)) { DCE2_SmbRemoveUid(ssd, ssd->cur_rtracker->uid); switch (DCE2_SsnGetServerPolicy(&ssd->sd)) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: /* Windows responds to a chained LogoffAndX => SessionSetupAndX with a * word count 3 LogoffAndX without the chained SessionSetupAndX */ if (DCE2_ComInfoWordCount(com_info) == 3) { uint16_t uid = SmbUid(smb_hdr); DCE2_SmbInsertUid(ssd, uid); ssd->cur_rtracker->uid = uid; // Set this in case there are chained commands } break; default: break; } } return DCE2_RET__SUCCESS; } #define SERVICE_0 (0) // IPC start #define SERVICE_1 (SERVICE_0+4) // DISK start #define SERVICE_FS (SERVICE_1+3) // Failure #define SERVICE_IPC (SERVICE_FS+1) // IPC service #define SERVICE_DISK (SERVICE_FS+2) // DISK service static DCE2_SmbFsm dce2_smb_service_fsm[] = { // IPC { 'I', SERVICE_0+1, SERVICE_1 }, { 'P', SERVICE_0+2, SERVICE_FS }, { 'C', SERVICE_0+3, SERVICE_FS }, { '\0', SERVICE_IPC, SERVICE_FS }, // DISK { 'A', SERVICE_1+1, SERVICE_FS }, { ':', SERVICE_1+2, SERVICE_FS }, { '\0', SERVICE_DISK, SERVICE_FS }, { 0, SERVICE_FS, SERVICE_FS } }; // SMB_COM_TREE_CONNECT_ANDX static DCE2_Ret DCE2_SmbTreeConnectAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsRequest(com_info)) { if (DCE2_ScSmbInvalidShares(ssd->sd.sconfig) != NULL) { uint16_t pass_len = SmbTreeConnectAndXReqPassLen((SmbTreeConnectAndXReq *)nb_ptr); const uint8_t *bs = NULL; DCE2_MOVE(nb_ptr, nb_len, com_size); if (pass_len >= nb_len) return DCE2_RET__ERROR; // Move past password length DCE2_MOVE(nb_ptr, nb_len, pass_len); // Move past path components while ((bs = memchr(nb_ptr, '\\', nb_len)) != NULL) DCE2_MOVE(nb_ptr, nb_len, (bs - nb_ptr) + 1); // Move past NULL byte if unicode if (SmbUnicode(smb_hdr) && (nb_len != 0)) DCE2_MOVE(nb_ptr, nb_len, 1); if (nb_len != 0) DCE2_SmbInvalidShareCheck(ssd, smb_hdr, nb_ptr, nb_len); } } else { uint16_t tid = SmbTid(smb_hdr); bool is_ipc = true; int state = SERVICE_0; DCE2_MOVE(nb_ptr, nb_len, com_size); while ((nb_len > 0) && (state < SERVICE_FS)) { if (dce2_smb_service_fsm[state].input == (char)*nb_ptr) { state = dce2_smb_service_fsm[state].next_state; DCE2_MOVE(nb_ptr, nb_len, 1); } else { state = dce2_smb_service_fsm[state].fail_state; } } switch (state) { case SERVICE_IPC: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Tid (%u) is an IPC tree.\n", tid);); break; case SERVICE_DISK: is_ipc = false; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Tid (%u) is a DISK tree.\n", tid);); break; default: return DCE2_RET__IGNORE; } // Insert tid into list DCE2_SmbInsertTid(ssd, tid, is_ipc); ssd->cur_rtracker->tid = tid; // Set this in case there are chained commands } return DCE2_RET__SUCCESS; } // NT_TRANSACT_CREATE static inline DCE2_Ret DCE2_SmbNtTransactCreateReq(DCE2_SmbSsnData *ssd, const uint8_t *param_ptr, uint32_t param_len, bool unicode) { uint32_t pad = 0; uint32_t file_name_length; const uint8_t *param_start = param_ptr; if (param_len < sizeof(SmbNtTransactCreateReqParams)) return DCE2_RET__ERROR; if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)) { uint32_t ext_file_attrs = SmbNtTransactCreateReqFileAttrs((SmbNtTransactCreateReqParams *)param_ptr); if (SmbEvasiveFileAttrs(ext_file_attrs)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS); // If the file is going to be accessed sequentially, track it. if (SmbNtTransactCreateReqSequentialOnly((SmbNtTransactCreateReqParams *)param_ptr)) ssd->cur_rtracker->sequential_only = true; ssd->cur_rtracker->file_size = SmbNtTransactCreateReqAllocSize((SmbNtTransactCreateReqParams *)param_ptr); } file_name_length = SmbNtTransactCreateReqFileNameLength((SmbNtTransactCreateReqParams *)param_ptr); if (file_name_length > DCE2_SMB_MAX_PATH_LEN) return DCE2_RET__ERROR; DCE2_MOVE(param_ptr, param_len, sizeof(SmbNtTransactCreateReqParams)); if (unicode) pad = (param_ptr - param_start) & 1; if (param_len < (pad + file_name_length)) return DCE2_RET__ERROR; DCE2_MOVE(param_ptr, param_len, pad); ssd->cur_rtracker->file_name = DCE2_SmbGetString(param_ptr, file_name_length, unicode, false); return DCE2_RET__SUCCESS; } // SMB_COM_NT_TRANSACT static DCE2_Ret DCE2_SmbNtTransact(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; // NOTE: Only looking at NT_TRANSACT_CREATE as another way to open a named pipe // Got a matching request for an in progress transaction - don't process it, // but don't want to remove tracker. if (DCE2_ComInfoIsRequest(com_info) && !DCE2_SmbIsTransactionComplete(ttracker)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Got new transaction request " "that matches an in progress transaction - not inspecting.\n")); return DCE2_RET__ERROR; } if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; // Interim response is sent if client didn't send all data / parameters // in initial NtTransact request and will have to complete the request // with NtTransactSecondary commands. if (DCE2_ComInfoIsResponse(com_info) && (com_size == sizeof(SmbNtTransactInterimResp))) { return DCE2_RET__SUCCESS; } if (DCE2_ComInfoIsRequest(com_info)) { uint32_t pcnt = SmbNtTransactReqParamCnt((SmbNtTransactReq *)nb_ptr); uint32_t poff = SmbNtTransactReqParamOff((SmbNtTransactReq *)nb_ptr); DCE2_Ret status = DCE2_SmbUpdateTransRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); switch (ttracker->subcom) { case NT_TRANSACT_CREATE: status = DCE2_SmbNtTransactCreateReq(ssd, nb_ptr, pcnt, SmbUnicode(smb_hdr)); if (status != DCE2_RET__SUCCESS) return status; break; default: return DCE2_RET__IGNORE; } } else { const uint8_t *ptr; uint32_t len; DCE2_SmbFileTracker *ftracker = NULL; DCE2_Ret status = DCE2_SmbUpdateTransResponse(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; if (!DCE2_BufferIsEmpty(ttracker->pbuf)) { ptr = DCE2_BufferData(ttracker->pbuf); len = DCE2_BufferLength(ttracker->pbuf); } else { uint32_t poff = SmbNtTransactRespParamOff((SmbNtTransactResp *)nb_ptr); uint32_t pcnt = SmbNtTransactRespParamCnt((SmbNtTransactResp *)nb_ptr); DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); ptr = nb_ptr; len = pcnt; } if (len < sizeof(SmbNtTransactCreateRespParams)) return DCE2_RET__ERROR; if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)) { const bool is_directory = SmbNtTransactCreateRespDirectory((SmbNtTransactCreateRespParams *)ptr); const uint16_t resource_type = SmbNtTransactCreateRespResourceType((SmbNtTransactCreateRespParams *)ptr); if (is_directory || !SmbResourceTypeDisk(resource_type)) return DCE2_RET__SUCCESS; // Give preference to files opened with the sequential only flag set if (((ssd->fapi_ftracker == NULL) || !ssd->fapi_ftracker->ff_sequential_only) && ssd->cur_rtracker->sequential_only) { DCE2_SmbAbortFileAPI(ssd); } } ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, SmbNtTransactCreateRespFid((SmbNtTransactCreateRespParams *)ptr)); if (ftracker == NULL) return DCE2_RET__ERROR; ftracker->file_name = ssd->cur_rtracker->file_name; ssd->cur_rtracker->file_name = NULL; if (!ftracker->is_ipc) { uint32_t create_disposition = SmbNtTransactCreateRespCreateAction((SmbNtTransactCreateRespParams *)ptr); if (SmbCreateDispositionRead(create_disposition)) { ftracker->ff_file_size = SmbNtTransactCreateRespEndOfFile((SmbNtTransactCreateRespParams *)ptr); } else { ftracker->ff_file_size = ssd->cur_rtracker->file_size; ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD; } ftracker->ff_sequential_only = ssd->cur_rtracker->sequential_only; DCE2_DEBUG_CODE(DCE2_DEBUG__SMB, if (ftracker->ff_sequential_only) printf("File opened for sequential only access.\n");); } } return DCE2_RET__SUCCESS; } // SMB_COM_NT_TRANSACT_SECONDARY static DCE2_Ret DCE2_SmbNtTransactSecondary(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { DCE2_Ret status; DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; status = DCE2_SmbUpdateTransSecondary(ssd, smb_hdr, com_info, nb_ptr, nb_len); if (status != DCE2_RET__FULL) return status; switch (ttracker->subcom) { case NT_TRANSACT_CREATE: status = DCE2_SmbNtTransactCreateReq(ssd, DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf), SmbUnicode(smb_hdr)); if (status != DCE2_RET__SUCCESS) return status; break; default: break; } return DCE2_RET__SUCCESS; } // SMB_COM_NT_CREATE_ANDX static DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { if (!DCE2_ComInfoCanProcessCommand(com_info)) return DCE2_RET__ERROR; if (DCE2_ComInfoIsResponse(com_info)) { const uint16_t fid = SmbNtCreateAndXRespFid((SmbNtCreateAndXResp *)nb_ptr); DCE2_SmbFileTracker *ftracker = NULL; // Set request tracker's current file tracker in case of chained commands switch (SmbAndXCom2((SmbAndXCommon *)nb_ptr)) { // This is in case in the request a write was chained to an open // in which case the write will be to the newly opened file case SMB_COM_WRITE: case SMB_COM_WRITE_ANDX: case SMB_COM_TRANSACTION: case SMB_COM_READ_ANDX: ftracker = DCE2_SmbDequeueTmpFileTracker(ssd, ssd->cur_rtracker, fid); break; default: break; } if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)) { const bool is_directory = SmbNtCreateAndXRespDirectory((SmbNtCreateAndXResp *)nb_ptr); const uint16_t resource_type = SmbNtCreateAndXRespResourceType((SmbNtCreateAndXResp *)nb_ptr); if (is_directory || !SmbResourceTypeDisk(resource_type)) { if (ftracker != NULL) DCE2_SmbRemoveFileTracker(ssd, ftracker); return DCE2_RET__SUCCESS; } // Give preference to files opened with the sequential only flag set if (((ssd->fapi_ftracker == NULL) || !ssd->fapi_ftracker->ff_sequential_only) && (ftracker == NULL) && ssd->cur_rtracker->sequential_only) { DCE2_SmbAbortFileAPI(ssd); } } if (ftracker == NULL) { ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid); if (ftracker == NULL) return DCE2_RET__ERROR; } ftracker->file_name = ssd->cur_rtracker->file_name; ssd->cur_rtracker->file_name = NULL; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File name: %s\n", (ftracker->file_name == NULL) ? "NULL" : ftracker->file_name)); if (!ftracker->is_ipc) { const uint32_t create_disposition = SmbNtCreateAndXRespCreateDisposition((SmbNtCreateAndXResp *)nb_ptr); if (SmbCreateDispositionRead(create_disposition)) { ftracker->ff_file_size = SmbNtCreateAndXRespEndOfFile((SmbNtCreateAndXResp *)nb_ptr); } else { ftracker->ff_file_size = ssd->cur_rtracker->file_size; ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD; } ftracker->ff_sequential_only = ssd->cur_rtracker->sequential_only; DCE2_DEBUG_CODE(DCE2_DEBUG__SMB, if (ftracker->ff_sequential_only) printf("File opened for sequential only access.\n");); } ssd->cur_rtracker->ftracker = ftracker; } else { uint32_t pad = 0; uint16_t file_name_length = SmbNtCreateAndXReqFileNameLen((SmbNtCreateAndXReq *)nb_ptr); const bool unicode = SmbUnicode(smb_hdr); bool is_ipc = DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid); uint8_t smb_com2 = SmbAndXCom2((SmbAndXCommon *)nb_ptr); if (!is_ipc) { uint32_t ext_file_attrs = SmbNtCreateAndXReqFileAttrs((SmbNtCreateAndXReq *)nb_ptr); if (SmbEvasiveFileAttrs(ext_file_attrs)) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS); // If the file is going to be accessed sequentially, track it. if (SmbNtCreateAndXReqSequentialOnly((SmbNtCreateAndXReq *)nb_ptr)) ssd->cur_rtracker->sequential_only = true; ssd->cur_rtracker->file_size = SmbNtCreateAndXReqAllocSize((SmbNtCreateAndXReq *)nb_ptr); } DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); if (file_name_length > DCE2_SMB_MAX_PATH_LEN) return DCE2_RET__ERROR; if (unicode) pad = (nb_ptr - (const uint8_t *)smb_hdr) & 1; if (nb_len < (pad + file_name_length)) return DCE2_RET__ERROR; DCE2_MOVE(nb_ptr, nb_len, pad); // Samba allows chaining OpenAndX/NtCreateAndX so might have // already been set. if (ssd->cur_rtracker->file_name == NULL) { ssd->cur_rtracker->file_name = DCE2_SmbGetString(nb_ptr, file_name_length, unicode, false); } if (is_ipc) { switch (smb_com2) { case SMB_COM_READ_ANDX: if (DCE2_SsnIsWindowsPolicy(&ssd->sd)) return DCE2_RET__ERROR; break; default: break; } } } return DCE2_RET__SUCCESS; } static inline DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData *ssd, const uint16_t fid, const uint8_t *data_ptr, uint32_t data_len, uint64_t offset) { DCE2_SmbFileTracker *ftracker = DCE2_SmbGetFileTracker(ssd, fid); if (ftracker == NULL) return DCE2_RET__ERROR; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Processing request data with Fid: 0x%04X ~~~~~~~~~~~~~~~~~\n", ftracker->fid)); // Set this in case of chained commands or reassembled packet ssd->cur_rtracker->ftracker = ftracker; DCE2_SmbSetFileName(ftracker->file_name); if (ftracker->is_ipc) { // Maximum possible fragment length is 16 bit if (data_len > UINT16_MAX) data_len = UINT16_MAX; DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len); if (!ftracker->fp_used) ftracker->fp_used = true; } else { ftracker->ff_file_offset = offset; DCE2_SmbProcessFileData(ssd, ftracker, data_ptr, data_len, true); } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")); return DCE2_RET__SUCCESS; } static inline DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData *ssd, const uint8_t *data_ptr, uint32_t data_len) { DCE2_SmbFileTracker *ftracker = ssd->cur_rtracker->ftracker; if (ftracker == NULL) return DCE2_RET__ERROR; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Processing response data with Fid: 0x%04X ~~~~~~~~~~~~~~~~\n", ftracker->fid)); DCE2_SmbSetFileName(ftracker->file_name); if (ftracker->is_ipc) { // Maximum possible fragment length is 16 bit if (data_len > UINT16_MAX) data_len = UINT16_MAX; DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len); } else { ftracker->ff_file_offset = ssd->cur_rtracker->file_offset; DCE2_SmbProcessFileData(ssd, ftracker, data_ptr, data_len, false); } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")); return DCE2_RET__SUCCESS; } static inline DCE2_SmbRequestTracker * DCE2_SmbNewRequestTracker(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr) { DCE2_SmbRequestTracker *rtracker = NULL; DCE2_SmbRequestTracker *tmp_rtracker = NULL; uint16_t pid = SmbPid(smb_hdr); uint16_t mid = SmbMid(smb_hdr); uint16_t uid = SmbUid(smb_hdr); uint16_t tid = SmbTid(smb_hdr); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_req); if (ssd == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_req); return NULL; } if (ssd->outstanding_requests >= ssd->max_outstanding_requests) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_MAX_REQS_EXCEEDED, ssd->max_outstanding_requests); } // Check for outstanding requests with the same MID tmp_rtracker = &ssd->rtracker; while ((tmp_rtracker != NULL) && (tmp_rtracker->mid != DCE2_SENTINEL)) { if (tmp_rtracker->mid == (int)mid) { // Have yet to see an MID repeatedly used so shouldn't // be any outstanding requests with the same MID. DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_REQS_SAME_MID); break; } // Look at the next request in the queue if (tmp_rtracker == &ssd->rtracker) tmp_rtracker = DCE2_QueueFirst(ssd->rtrackers); else tmp_rtracker = DCE2_QueueNext(ssd->rtrackers); } if (ssd->rtracker.mid == DCE2_SENTINEL) { rtracker = &ssd->rtracker; } else { if (ssd->rtrackers == NULL) { ssd->rtrackers = DCE2_QueueNew(DCE2_SmbRequestTrackerDataFree, DCE2_MEM_TYPE__SMB_REQ); if (ssd->rtrackers == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_req); return NULL; } } rtracker = (DCE2_SmbRequestTracker *)DCE2_Alloc(sizeof(DCE2_SmbRequestTracker), DCE2_MEM_TYPE__SMB_REQ); if (rtracker == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_req); return NULL; } if (DCE2_QueueEnqueue(ssd->rtrackers, (void *)rtracker) != DCE2_RET__SUCCESS) { DCE2_Free((void *)rtracker, sizeof(DCE2_SmbRequestTracker), DCE2_MEM_TYPE__SMB_REQ); PREPROC_PROFILE_END(dce2_pstat_smb_req); return NULL; } } rtracker->smb_com = SmbCom(smb_hdr); rtracker->uid = uid; rtracker->tid = tid; rtracker->pid = pid; rtracker->mid = (int)mid; memset(&rtracker->ttracker, 0, sizeof(rtracker->ttracker)); rtracker->ftracker = NULL; rtracker->sequential_only = false; ssd->outstanding_requests++; if (ssd->outstanding_requests > dce2_stats.smb_max_outstanding_requests) dce2_stats.smb_max_outstanding_requests = ssd->outstanding_requests; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Added new request tracker => " "Uid: %u, Tid: %u, Pid: %u, Mid: %u\n", rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Current outstanding requests: %u\n", ssd->outstanding_requests)); PREPROC_PROFILE_END(dce2_pstat_smb_req); return rtracker; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline DCE2_Ret DCE2_SmbBufferTransactionData(DCE2_SmbTransactionTracker *ttracker, const uint8_t *data_ptr, uint16_t dcnt, uint16_t ddisp) { PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_req); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Buffering transaction data.\n")); if (ttracker->dbuf == NULL) { /* Buf size should be the total data count we need */ ttracker->dbuf = DCE2_BufferNew(ttracker->tdcnt, 0, DCE2_MEM_TYPE__SMB_REQ); if (ttracker->dbuf == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Failed to allocate new " "buffer to for transaction data.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_req); return DCE2_RET__ERROR; } } if (DCE2_BufferAddData(ttracker->dbuf, data_ptr, dcnt, ddisp, DCE2_BUFFER_MIN_ADD_FLAG__IGNORE) != DCE2_RET__SUCCESS) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Failed to buffer transaction data.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_req); return DCE2_RET__ERROR; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Successfully buffered transaction data.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_req); return DCE2_RET__SUCCESS; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline DCE2_Ret DCE2_SmbBufferTransactionParameters(DCE2_SmbTransactionTracker *ttracker, const uint8_t *param_ptr, uint16_t pcnt, uint16_t pdisp) { PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_req); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Buffering transaction parameters.\n")); if (ttracker->pbuf == NULL) { /* Buf size should be the total data count we need */ ttracker->pbuf = DCE2_BufferNew(ttracker->tpcnt, 0, DCE2_MEM_TYPE__SMB_REQ); if (ttracker->pbuf == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Failed to allocate new " "buffer to for transaction parameter.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_req); return DCE2_RET__ERROR; } } if (DCE2_BufferAddData(ttracker->pbuf, param_ptr, pcnt, pdisp, DCE2_BUFFER_MIN_ADD_FLAG__IGNORE) != DCE2_RET__SUCCESS) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Failed to buffer transaction parameter data.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_req); return DCE2_RET__ERROR; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Successfully buffered transaction parameter data.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_req); return DCE2_RET__SUCCESS; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline DCE2_SmbRequestTracker * DCE2_SmbFindRequestTracker(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr) { DCE2_Policy policy = DCE2_SsnGetPolicy(&ssd->sd); DCE2_SmbRequestTracker *first_rtracker = NULL; DCE2_SmbRequestTracker *win_rtracker = NULL; DCE2_SmbRequestTracker *first_mid_rtracker = NULL; DCE2_SmbRequestTracker *tmp_rtracker = NULL; DCE2_SmbRequestTracker *ret_rtracker = NULL; int smb_com = SmbCom(smb_hdr); uint16_t uid = SmbUid(smb_hdr); uint16_t tid = SmbTid(smb_hdr); uint16_t pid = SmbPid(smb_hdr); uint16_t mid = SmbMid(smb_hdr); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_req); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Find request tracker => " "Uid: %u, Tid: %u, Pid: %u, Mid: %u ... ", uid, tid, pid, mid)); tmp_rtracker = &ssd->rtracker; switch (smb_com) { case SMB_COM_TRANSACTION_SECONDARY: smb_com = SMB_COM_TRANSACTION; break; case SMB_COM_TRANSACTION2_SECONDARY: smb_com = SMB_COM_TRANSACTION2; break; case SMB_COM_NT_TRANSACT_SECONDARY: smb_com = SMB_COM_NT_TRANSACT; break; case SMB_COM_WRITE_COMPLETE: smb_com = SMB_COM_WRITE_RAW; break; default: break; } while (tmp_rtracker != NULL) { if ((tmp_rtracker->mid == (int)mid) && (tmp_rtracker->smb_com == smb_com)) { // This is the normal case except for SessionSetupAndX and // TreeConnect/TreeConnectAndX which will fall into the // default case below. if ((tmp_rtracker->pid == pid) && (tmp_rtracker->uid == uid) && (tmp_rtracker->tid == tid)) { ret_rtracker = tmp_rtracker; } else { switch (smb_com) { case SMB_COM_TRANSACTION: case SMB_COM_TRANSACTION2: case SMB_COM_NT_TRANSACT: case SMB_COM_TRANSACTION_SECONDARY: case SMB_COM_TRANSACTION2_SECONDARY: case SMB_COM_NT_TRANSACT_SECONDARY: // These should conform to above break; default: if (tmp_rtracker->pid == pid) ret_rtracker = tmp_rtracker; break; } } if (ret_rtracker != NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Found.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_req); return ret_rtracker; } // Take the first one where the PIDs also match // in the case of the Transacts above if ((tmp_rtracker->pid == pid) && (win_rtracker == NULL)) win_rtracker = tmp_rtracker; // Set this to the first matching request in the queue // where the Mid matches. Don't set for Windows if from // client since PID/MID are necessary if (((DCE2_SmbType(ssd) == SMB_TYPE__RESPONSE) || !DCE2_SsnIsWindowsPolicy(&ssd->sd)) && first_mid_rtracker == NULL) { first_mid_rtracker = tmp_rtracker; } } // Set the first one we see for early Samba versions if ((first_rtracker == NULL) && (tmp_rtracker->mid != DCE2_SENTINEL) && (tmp_rtracker->smb_com == smb_com)) first_rtracker = tmp_rtracker; // Look at the next request in the queue if (tmp_rtracker == &ssd->rtracker) tmp_rtracker = DCE2_QueueFirst(ssd->rtrackers); else tmp_rtracker = DCE2_QueueNext(ssd->rtrackers); } switch (policy) { case DCE2_POLICY__SAMBA_3_0_20: case DCE2_POLICY__SAMBA_3_0_22: ret_rtracker = first_rtracker; break; case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: ret_rtracker = first_mid_rtracker; break; case DCE2_POLICY__WIN2000: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: if (win_rtracker != NULL) ret_rtracker = win_rtracker; else ret_rtracker = first_mid_rtracker; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); break; } DCE2_DEBUG_CODE(DCE2_DEBUG__SMB, if (ret_rtracker != NULL) printf("Found.\n"); else printf("Not found\n");); PREPROC_PROFILE_END(dce2_pstat_smb_req); return ret_rtracker; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_SmbRemoveRequestTracker(DCE2_SmbSsnData *ssd, DCE2_SmbRequestTracker *rtracker) { DCE2_SmbRequestTracker *tmp_node; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_req); if ((ssd == NULL) || (rtracker == NULL)) { PREPROC_PROFILE_END(dce2_pstat_smb_req); return; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing request tracker => " "Uid: %u, Tid: %u, Pid: %u, Mid: %u ... ", rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid)); if (rtracker == &ssd->rtracker) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removed\n")); DCE2_SmbCleanRequestTracker(&ssd->rtracker); ssd->outstanding_requests--; PREPROC_PROFILE_END(dce2_pstat_smb_req); return; } for (tmp_node = DCE2_QueueFirst(ssd->rtrackers); tmp_node != NULL; tmp_node = DCE2_QueueNext(ssd->rtrackers)) { if (tmp_node == (void *)rtracker) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removed.\n")); DCE2_QueueRemoveCurrent(ssd->rtrackers); ssd->outstanding_requests--; PREPROC_PROFILE_END(dce2_pstat_smb_req); return; } } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not removed.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_req); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbInsertUid(DCE2_SmbSsnData *ssd, const uint16_t uid) { PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_uid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Inserting Uid: %u\n", uid);); if (ssd->uid == DCE2_SENTINEL) { ssd->uid = (int)uid; } else { if (ssd->uids == NULL) { ssd->uids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_SmbUidTidFidCompare, NULL, NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_UID); if (ssd->uids == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_uid); return; } } DCE2_ListInsert(ssd->uids, (void *)(uintptr_t)uid, (void *)(uintptr_t)uid); } PREPROC_PROFILE_END(dce2_pstat_smb_uid); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData *ssd, const uint16_t uid) { DCE2_Ret status; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_uid); if ((ssd->uid != DCE2_SENTINEL) && (ssd->uid == (int)uid)) status = DCE2_RET__SUCCESS; else status = DCE2_ListFindKey(ssd->uids, (void *)(uintptr_t)uid); PREPROC_PROFILE_END(dce2_pstat_smb_uid); return status; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbRemoveUid(DCE2_SmbSsnData *ssd, const uint16_t uid) { const DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_uid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing Uid: %u\n", uid);); if ((ssd->uid != DCE2_SENTINEL) && (ssd->uid == (int)uid)) ssd->uid = DCE2_SENTINEL; else DCE2_ListRemove(ssd->uids, (void *)(uintptr_t)uid); switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: // Removing uid invalidates any fid that was created with it */ if ((ssd->ftracker.fid != DCE2_SENTINEL) && (ssd->ftracker.uid == uid)) { DCE2_SmbRemoveFileTracker(ssd, &ssd->ftracker); } if (ssd->ftrackers != NULL) { DCE2_SmbFileTracker *ftracker; for (ftracker = DCE2_ListFirst(ssd->ftrackers); ftracker != NULL; ftracker = DCE2_ListNext(ssd->ftrackers)) { if (ftracker->uid == uid) { if (ssd->fapi_ftracker == ftracker) DCE2_SmbFinishFileAPI(ssd); #ifdef ACTIVE_RESPONSE if (ssd->fb_ftracker == ftracker) DCE2_SmbFinishFileBlockVerdict(ssd); #endif DCE2_ListRemoveCurrent(ssd->ftrackers); DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker); } } } break; case DCE2_POLICY__SAMBA_3_0_20: case DCE2_POLICY__SAMBA_3_0_22: // Removing Uid used to create file doesn't invalidate it. break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); break; } PREPROC_PROFILE_END(dce2_pstat_smb_uid); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbInsertTid(DCE2_SmbSsnData *ssd, const uint16_t tid, const bool is_ipc) { int insert_tid = (int)tid; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_tid); if (!is_ipc && (!DCE2_ScSmbFileInspection(ssd->sd.sconfig) || ((ssd->max_file_depth == -1) && DCE2_ScSmbFileDepth(ssd->sd.sconfig) == -1))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not inserting TID (%u) " "because it's not IPC and not inspecting normal file " "data.", tid)); PREPROC_PROFILE_END(dce2_pstat_smb_tid); return; } if (is_ipc && DCE2_ScSmbFileInspectionOnly(ssd->sd.sconfig)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not inserting TID (%u) " "because it's IPC and only inspecting normal file " "data.", tid)); PREPROC_PROFILE_END(dce2_pstat_smb_tid); return; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Inserting Tid: %u\n", tid)); // Set a bit so as to distinguish between IPC and non-IPC TIDs if (!is_ipc) insert_tid |= (1 << 16); if (ssd->tid == DCE2_SENTINEL) { ssd->tid = insert_tid; } else { if (ssd->tids == NULL) { ssd->tids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_SmbUidTidFidCompare, NULL, NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_TID); if (ssd->tids == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_tid); return; } } DCE2_ListInsert(ssd->tids, (void *)(uintptr_t)tid, (void *)(uintptr_t)insert_tid); } PREPROC_PROFILE_END(dce2_pstat_smb_tid); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static DCE2_Ret DCE2_SmbFindTid(DCE2_SmbSsnData *ssd, const uint16_t tid) { DCE2_Ret status; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_tid); if ((ssd->tid != DCE2_SENTINEL) && ((ssd->tid & 0x0000ffff) == (int)tid)) status = DCE2_RET__SUCCESS; else status = DCE2_ListFindKey(ssd->tids, (void *)(uintptr_t)tid); PREPROC_PROFILE_END(dce2_pstat_smb_tid); return status; } /******************************************************************** * Function: DCE2_SmbIsTidIPC() * * Purpose: Checks to see if the TID passed in was to IPC or not. * * Arguments: * DCE2_SmbSsnData * - pointer to session data * const uint16_t - the TID to check * * Returns: * bool - True if TID is IPC, false if not or if TID not found. * ********************************************************************/ static bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData *ssd, const uint16_t tid) { if ((ssd->tid != DCE2_SENTINEL) && ((ssd->tid & 0x0000ffff) == (int)tid)) { if ((ssd->tid >> 16) == 0) return true; } else { int check_tid = (int)(uintptr_t)DCE2_ListFind(ssd->tids, (void *)(uintptr_t)tid); if (((check_tid & 0x0000ffff) == (int)tid) && ((check_tid >> 16) == 0)) return true; } return false; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbRemoveTid(DCE2_SmbSsnData *ssd, const uint16_t tid) { PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_tid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing Tid: %u\n", tid)); if ((ssd->tid != DCE2_SENTINEL) && ((ssd->tid & 0x0000ffff) == (int)tid)) ssd->tid = DCE2_SENTINEL; else DCE2_ListRemove(ssd->tids, (void *)(uintptr_t)tid); // Removing Tid invalidates files created with it if ((ssd->ftracker.fid != DCE2_SENTINEL) && (ssd->ftracker.tid == tid)) { DCE2_SmbRemoveFileTracker(ssd, &ssd->ftracker); } if (ssd->ftrackers != NULL) { DCE2_SmbFileTracker *ftracker; for (ftracker = DCE2_ListFirst(ssd->ftrackers); ftracker != NULL; ftracker = DCE2_ListNext(ssd->ftrackers)) { if (ftracker->tid == (int)tid) { if (ssd->fapi_ftracker == ftracker) DCE2_SmbFinishFileAPI(ssd); #ifdef ACTIVE_RESPONSE if (ssd->fb_ftracker == ftracker) DCE2_SmbFinishFileBlockVerdict(ssd); #endif DCE2_ListRemoveCurrent(ssd->ftrackers); DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker); } } } PREPROC_PROFILE_END(dce2_pstat_smb_tid); } static inline DCE2_Ret DCE2_SmbInitFileTracker(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker, const bool is_ipc, const uint16_t uid, const uint16_t tid, const int fid) { if (ftracker == NULL) return DCE2_RET__ERROR; ftracker->uid = uid; ftracker->tid = tid; ftracker->fid = fid; ftracker->is_ipc = is_ipc; ftracker->file_name = NULL; if (is_ipc) { DCE2_CoTracker *co_tracker = DCE2_Alloc(sizeof(DCE2_CoTracker), DCE2_MEM_TYPE__SMB_FID); if (co_tracker == NULL) return DCE2_RET__ERROR; DCE2_CoInitTracker(co_tracker); ftracker->fp_co_tracker = co_tracker; ftracker->fp_byte_mode = false; ftracker->fp_used = false; ftracker->fp_writex_raw = NULL; } else { ftracker->ff_file_size = 0; ftracker->ff_file_offset = 0; ftracker->ff_bytes_processed = 0; ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UNKNOWN; ftracker->ff_file_chunks = NULL; ftracker->ff_bytes_queued = 0; if ((ssd->fapi_ftracker == NULL) && (ssd->max_file_depth != -1)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Designating file tracker " "for file API processing: 0x%04X\n", (uint16_t)fid);); ssd->fapi_ftracker = ftracker; } } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static DCE2_SmbFileTracker * DCE2_SmbNewFileTracker(DCE2_SmbSsnData *ssd, const uint16_t uid, const uint16_t tid, const uint16_t fid) { DCE2_SmbFileTracker *ftracker = NULL; bool is_ipc = DCE2_SmbIsTidIPC(ssd, tid); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_fid); // Already have tracker for file API and not setting file data pointer // so don't create new file tracker. if (!is_ipc && (ssd->fapi_ftracker != NULL) && (DCE2_ScSmbFileDepth(ssd->sd.sconfig) == -1)) return NULL; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Creating new file tracker " "with Uid: %u, Tid: %u, Fid: 0x%04X\n", uid, tid, fid)); if (ssd->ftracker.fid == DCE2_SENTINEL) { ftracker = &ssd->ftracker; if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, (int)fid) != DCE2_RET__SUCCESS) { DCE2_SmbCleanFileTracker(ftracker); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } } else { ftracker = (DCE2_SmbFileTracker *) DCE2_Alloc(sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); if (ftracker == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, (int)fid) != DCE2_RET__SUCCESS) { DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } if (ssd->ftrackers == NULL) { ssd->ftrackers = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_SmbUidTidFidCompare, DCE2_SmbFileTrackerDataFree, NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_FID); if (ssd->ftrackers == NULL) { DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } } if (DCE2_ListInsert(ssd->ftrackers, (void *)(uintptr_t)fid, (void *)ftracker) != DCE2_RET__SUCCESS) { DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } } PREPROC_PROFILE_END(dce2_pstat_smb_fid); return ftracker; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbQueueTmpFileTracker(DCE2_SmbSsnData *ssd, DCE2_SmbRequestTracker *rtracker, const uint16_t uid, const uint16_t tid) { DCE2_SmbFileTracker *ftracker; bool is_ipc = DCE2_SmbIsTidIPC(ssd, tid); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_fid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Queueing file tracker " "with Uid: %u, Tid: %u\n", uid, tid)); ftracker = (DCE2_SmbFileTracker *) DCE2_Alloc(sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); if (ftracker == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_fid); return; } if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, DCE2_SENTINEL) != DCE2_RET__SUCCESS) { DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return; } if (!is_ipc && (ssd->fapi_ftracker == ftracker)) ssd->fapi_ftracker = NULL; if (rtracker->ft_queue == NULL) { rtracker->ft_queue = DCE2_QueueNew(DCE2_SmbFileTrackerDataFree, DCE2_MEM_TYPE__SMB_FID); if (rtracker->ft_queue == NULL) { DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return; } } if (DCE2_QueueEnqueue(rtracker->ft_queue, (void *)ftracker) != DCE2_RET__SUCCESS) { DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return; } PREPROC_PROFILE_END(dce2_pstat_smb_fid); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: None * ********************************************************************/ static inline DCE2_SmbFileTracker * DCE2_SmbGetTmpFileTracker(DCE2_SmbRequestTracker *rtracker) { if (!DCE2_QueueIsEmpty(rtracker->ft_queue)) return (DCE2_SmbFileTracker *)DCE2_QueueLast(rtracker->ft_queue); return NULL; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: None * ********************************************************************/ static inline void DCE2_SmbEmptyTmpFileTrackerQueue(DCE2_SmbRequestTracker *rtracker) { if (!DCE2_QueueIsEmpty(rtracker->ft_queue)) DCE2_QueueEmpty(rtracker->ft_queue); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: None * ********************************************************************/ static DCE2_SmbFileTracker * DCE2_SmbDequeueTmpFileTracker(DCE2_SmbSsnData *ssd, DCE2_SmbRequestTracker *rtracker, const uint16_t fid) { DCE2_SmbFileTracker *ftracker; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_fid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Dequeueing file tracker " "and binding to fid: 0x%04X\n", fid)); ftracker = (DCE2_SmbFileTracker *)DCE2_QueueDequeue(rtracker->ft_queue); if (ftracker == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } if (ssd->ftracker.fid == DCE2_SENTINEL) { memcpy(&ssd->ftracker, ftracker, sizeof(DCE2_SmbFileTracker)); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); if (ssd->fapi_ftracker == ftracker) ssd->fapi_ftracker = &ssd->ftracker; ftracker = &ssd->ftracker; } else { if (ssd->ftrackers == NULL) { ssd->ftrackers = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_SmbUidTidFidCompare, DCE2_SmbFileTrackerDataFree, NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_FID); if (ssd->ftrackers == NULL) { DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } } if (DCE2_ListInsert(ssd->ftrackers, (void *)(uintptr_t)fid, (void *)ftracker) != DCE2_RET__SUCCESS) { DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } } // Other values were intialized when queueing. ftracker->fid = (int)fid; PREPROC_PROFILE_END(dce2_pstat_smb_fid); return ftracker; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline DCE2_SmbFileTracker * DCE2_SmbGetFileTracker(DCE2_SmbSsnData *ssd, const uint16_t fid) { DCE2_SmbFileTracker *ftracker = ssd->cur_rtracker->ftracker; if (ftracker == NULL) { // Write could've been chained to an OpenAndX or NtCreateAndX so a // temporary file tracker would've been created until we get the // response with the Fid returned from the OpenAndX / NtCreateAndX ftracker = DCE2_SmbGetTmpFileTracker(ssd->cur_rtracker); if (ftracker == NULL) { // Otherwise find it with the passed in Fid ftracker = DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid); } } return ftracker; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static DCE2_SmbFileTracker * DCE2_SmbFindFileTracker(DCE2_SmbSsnData *ssd, const uint16_t uid, const uint16_t tid, const uint16_t fid) { const DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); DCE2_SmbFileTracker *ftracker; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_fid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Finding file tracker with " "Uid: %u, Tid: %u, Fid: 0x%04X ... ", uid, tid, fid)); if ((ssd->ftracker.fid != DCE2_SENTINEL) && (ssd->ftracker.fid == (int)fid)) { ftracker = &ssd->ftracker; } else { ftracker = (DCE2_SmbFileTracker *) DCE2_ListFind(ssd->ftrackers, (void *)(uintptr_t)fid); } if (ftracker == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not found.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } // Note IPC Tid has already been validated in initial processing switch (policy) { case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: // Only Uid used to open file can be used to make a request if (ftracker->uid != uid) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not found.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } break; case DCE2_POLICY__WIN2000: case DCE2_POLICY__SAMBA_3_0_20: case DCE2_POLICY__SAMBA_3_0_22: // Any valid Uid can be used to make a request to a file ... // except for Windows 2000 on the first use. if ((policy != DCE2_POLICY__WIN2000) || (ftracker->is_ipc && ftracker->fp_used)) { // Check that the Uid exists if (DCE2_SmbFindUid(ssd, uid) != DCE2_RET__SUCCESS) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not found.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } break; } // Fall through for Windows 2000 for first request to file case DCE2_POLICY__WIN2003: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: // Both Uid and Tid used to create file must be used to make a request if ((ftracker->uid != uid) || (ftracker->tid != tid)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not found.\n")); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return NULL; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d", __FILE__, __LINE__, policy); break; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Found with " "Uid: %u, Tid: %u, Fid: 0x%04X\n", ftracker->uid, ftracker->tid, ftracker->fid)); PREPROC_PROFILE_END(dce2_pstat_smb_fid); return ftracker; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbRemoveFileTracker(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker) { PROFILE_VARS; if (ftracker == NULL) return; PREPROC_PROFILE_START(dce2_pstat_smb_fid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing file tracker with Fid: 0x%04X\n", ftracker->fid)); if (ssd->fapi_ftracker == ftracker) DCE2_SmbFinishFileAPI(ssd); #ifdef ACTIVE_RESPONSE if (ssd->fb_ftracker == ftracker) DCE2_SmbFinishFileBlockVerdict(ssd); #endif if (ftracker == &ssd->ftracker) DCE2_SmbCleanFileTracker(&ssd->ftracker); else if (ssd->ftrackers != NULL) DCE2_ListRemove(ssd->ftrackers, (void *)(uintptr_t)ftracker->fid); DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker); PREPROC_PROFILE_END(dce2_pstat_smb_fid); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_SmbCleanFileTracker(DCE2_SmbFileTracker *ftracker) { PROFILE_VARS; if (ftracker == NULL) return; PREPROC_PROFILE_START(dce2_pstat_smb_fid); ftracker->fid = DCE2_SENTINEL; if (ftracker->file_name != NULL) { DCE2_Free((void *)ftracker->file_name, strlen(ftracker->file_name)+1, DCE2_MEM_TYPE__SMB_SSN); ftracker->file_name = NULL; } if (ftracker->is_ipc) { ftracker->fp_used = 0; ftracker->fp_byte_mode = 0; if (ftracker->fp_writex_raw != NULL) { DCE2_BufferDestroy(ftracker->fp_writex_raw->buf); DCE2_Free((void *)ftracker->fp_writex_raw, sizeof(DCE2_SmbWriteAndXRaw), DCE2_MEM_TYPE__SMB_FID); ftracker->fp_writex_raw = NULL; } if (ftracker->fp_co_tracker != NULL) { DCE2_CoCleanTracker(ftracker->fp_co_tracker); DCE2_Free((void *)ftracker->fp_co_tracker, sizeof(DCE2_CoTracker), DCE2_MEM_TYPE__SMB_FID); ftracker->fp_co_tracker = NULL; } } else { ftracker->ff_file_size = 0; ftracker->ff_file_offset = 0; ftracker->ff_bytes_processed = 0; ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UNKNOWN; ftracker->ff_bytes_queued = 0; ftracker->ff_sequential_only = false; if (ftracker->ff_file_chunks != NULL) { DCE2_ListDestroy(ftracker->ff_file_chunks); ftracker->ff_file_chunks = NULL; } } PREPROC_PROFILE_END(dce2_pstat_smb_fid); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_SmbCleanTransactionTracker(DCE2_SmbTransactionTracker *ttracker) { PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_req); if (ttracker == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_req); return; } if (ttracker->dbuf != NULL) DCE2_BufferDestroy(ttracker->dbuf); if (ttracker->pbuf != NULL) DCE2_BufferDestroy(ttracker->pbuf); memset(ttracker, 0, sizeof(*ttracker)); PREPROC_PROFILE_END(dce2_pstat_smb_req); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_SmbCleanRequestTracker(DCE2_SmbRequestTracker *rtracker) { PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_req); if (rtracker == NULL) { PREPROC_PROFILE_END(dce2_pstat_smb_req); return; } if (rtracker->mid == DCE2_SENTINEL) { PREPROC_PROFILE_END(dce2_pstat_smb_req); return; } rtracker->mid = DCE2_SENTINEL; rtracker->ftracker = NULL; rtracker->sequential_only = false; DCE2_SmbCleanTransactionTracker(&rtracker->ttracker); DCE2_QueueDestroy(rtracker->ft_queue); rtracker->ft_queue = NULL; if (rtracker->file_name != NULL) { DCE2_Free((void *)rtracker->file_name, strlen(rtracker->file_name)+1, DCE2_MEM_TYPE__SMB_SSN); rtracker->file_name = NULL; } PREPROC_PROFILE_END(dce2_pstat_smb_req); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_SmbUidTidFidCompare(const void *a, const void *b) { int x = (int)(uintptr_t)a; int y = (int)(uintptr_t)b; if (x == y) return 0; /* Only care about equality for finding */ return -1; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_SmbDataFree(DCE2_SmbSsnData *ssd) { if (ssd == NULL) return; // XXX This tries to account for the situation where we never knew the file // size and the TCP session was shutdown before an SMB_COM_CLOSE on the file. // Possibly need to add callback to fileAPI since it may have already // released it's resources. //DCE2_SmbFinishFileAPI(ssd); if (ssd->uids != NULL) { DCE2_ListDestroy(ssd->uids); ssd->uids = NULL; } if (ssd->tids != NULL) { DCE2_ListDestroy(ssd->tids); ssd->tids = NULL; } DCE2_SmbCleanFileTracker(&ssd->ftracker); if (ssd->ftrackers != NULL) { DCE2_ListDestroy(ssd->ftrackers); ssd->ftrackers = NULL; } DCE2_SmbCleanRequestTracker(&ssd->rtracker); if (ssd->rtrackers != NULL) { DCE2_QueueDestroy(ssd->rtrackers); ssd->rtrackers = NULL; } if (ssd->cli_seg != NULL) { DCE2_BufferDestroy(ssd->cli_seg); ssd->cli_seg = NULL; } if (ssd->srv_seg != NULL) { DCE2_BufferDestroy(ssd->srv_seg); ssd->srv_seg = NULL; } } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_SmbSsnFree(void *ssn) { DCE2_SmbSsnData *ssd = (DCE2_SmbSsnData *)ssn; if (ssd == NULL) return; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing Session: %p\n", ssd)); DCE2_SmbDataFree(ssd); DCE2_Free((void *)ssn, sizeof(DCE2_SmbSsnData), DCE2_MEM_TYPE__SMB_SSN); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbFileTrackerDataFree(void *data) { DCE2_SmbFileTracker *ftracker = (DCE2_SmbFileTracker *)data; if (ftracker == NULL) return; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Freeing file tracker: " "Uid: %u, Tid: %u, Fid: 0x%04X\n", ftracker->uid, ftracker->tid, ftracker->fid)); DCE2_SmbCleanFileTracker(ftracker); DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_SmbRequestTrackerDataFree(void *data) { DCE2_SmbRequestTracker *rtracker = (DCE2_SmbRequestTracker *)data; if (rtracker == NULL) return; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Freeing request tracker: " "Uid: %u, Tid: %u, Pid: %u, Mid: %u\n", rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid)); DCE2_SmbCleanRequestTracker(rtracker); DCE2_Free((void *)rtracker, sizeof(DCE2_SmbRequestTracker), DCE2_MEM_TYPE__SMB_REQ); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline SFSnortPacket * DCE2_SmbGetRpkt(DCE2_SmbSsnData *ssd, const uint8_t **data, uint32_t *data_len, DCE2_RpktType rtype) { SFSnortPacket *rpkt; uint16_t header_len; if ((ssd == NULL) || (data == NULL) || (*data == NULL) || (data_len == NULL) || (*data_len == 0)) return NULL; rpkt = DCE2_GetRpkt(ssd->sd.wire_pkt, rtype, *data, *data_len); if (rpkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to create reassembly packet.", __FILE__, __LINE__); return NULL; } if (DCE2_PushPkt(rpkt) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to push packet onto packet stack.", __FILE__, __LINE__); return NULL; } *data = rpkt->payload; *data_len = rpkt->payload_size; switch (rtype) { case DCE2_RPKT_TYPE__SMB_TRANS: if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST) header_len = DCE2_MOCK_HDR_LEN__SMB_CLI; else header_len = DCE2_MOCK_HDR_LEN__SMB_SRV; DCE2_SmbSetRdata(ssd, (uint8_t *)rpkt->payload, (uint16_t)(rpkt->payload_size - header_len)); DCE2_MOVE(*data, *data_len, header_len); break; case DCE2_RPKT_TYPE__SMB_SEG: default: break; } return rpkt; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_SmbReturnRpkt(void) { DCE2_PopPkt(); } #define DCE2_SMB_TRANS__NONE 0x00 #define DCE2_SMB_TRANS__DATA 0x01 #define DCE2_SMB_TRANS__PARAMS 0x02 #define DCE2_SMB_TRANS__BOTH (DCE2_SMB_TRANS__DATA|DCE2_SMB_TRANS__PARAMS) /******************************************************************** * Function: DCE2_SmbUpdateTransRequest() * * Purpose: * Handles common checks and updates of transaction requests - * SMB_COM_TRANSACTION, SMB_COM_TRANSACTION2 and SMB_COM_NT_TRANSACT * * Arguments: * DCE2_SmbSsnData * - pointer to SMB session data * const SmbNtHdr * - pointer to SMB header * const DCE2_SmbComInfo * - pointer to com info structure * const uint8_t * - pointer to data * uint32_t - data length * * Returns: * DCE2_Ret * DCE2_RET__IGNORE if we don't process the subcommand * DCE2_RET__FULL if the transaction is complete * DCE2_RET__ERROR if an error occurred. * DCE2_RET__SUCCESS if ok (but not complete). * ********************************************************************/ static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint32_t tpcnt, pcnt, poff; uint32_t tdcnt, dcnt, doff; uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint16_t fid; uint8_t setup_count; DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; uint16_t sub_com; int data_params = DCE2_SMB_TRANS__NONE; uint8_t smb_com = DCE2_ComInfoSmbCom(com_info); switch (smb_com) { case SMB_COM_TRANSACTION: sub_com = SmbTransactionReqSubCom((SmbTransactionReq *)nb_ptr); fid = SmbTransactionReqFid((SmbTransactionReq *)nb_ptr); setup_count = SmbTransactionReqSetupCnt((SmbTransactionReq *)nb_ptr); tdcnt = SmbTransactionReqTotalDataCnt((SmbTransactionReq *)nb_ptr); doff = SmbTransactionReqDataOff((SmbTransactionReq *)nb_ptr); dcnt = SmbTransactionReqDataCnt((SmbTransactionReq *)nb_ptr); tpcnt = SmbTransactionReqTotalParamCnt((SmbTransactionReq *)nb_ptr); pcnt = SmbTransactionReqParamCnt((SmbTransactionReq *)nb_ptr); poff = SmbTransactionReqParamOff((SmbTransactionReq *)nb_ptr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Transaction subcommand: %s (0x%04X)\n", (sub_com < TRANS_SUBCOM_MAX) ? smb_transaction_sub_command_strings[sub_com] : "Unknown", sub_com)); if (sub_com < TRANS_SUBCOM_MAX) dce2_stats.smb_trans_subcom_stats[SMB_TYPE__REQUEST][sub_com]++; else dce2_stats.smb_trans_subcom_stats[SMB_TYPE__REQUEST][TRANS_SUBCOM_MAX]++; ssd->cur_rtracker->ftracker = DCE2_SmbGetFileTracker(ssd, fid); if (ssd->cur_rtracker->ftracker == NULL) return DCE2_RET__IGNORE; switch (sub_com) { case TRANS_TRANSACT_NMPIPE: if (DCE2_SsnIsWindowsPolicy(&ssd->sd) && ssd->cur_rtracker->ftracker->fp_byte_mode) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Pipe is in byte " "mode - TRANS_TRANSACT_NMPIPE won't work\n")); return DCE2_RET__ERROR; } data_params = DCE2_SMB_TRANS__DATA; break; case TRANS_READ_NMPIPE: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED, smb_transaction_sub_command_strings[sub_com]); break; case TRANS_SET_NMPIPE_STATE: data_params = DCE2_SMB_TRANS__PARAMS; break; case TRANS_WRITE_NMPIPE: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED, smb_transaction_sub_command_strings[sub_com]); data_params = DCE2_SMB_TRANS__DATA; break; // Not implemented according to MS-CIFS case TRANS_RAW_READ_NMPIPE: // Can only write 2 NULL bytes and subsequent writes return pipe disconnected case TRANS_RAW_WRITE_NMPIPE: // Can at most do a DCE/RPC bind case TRANS_CALL_NMPIPE: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DEPR_COMMAND_USED, smb_transaction_sub_command_strings[sub_com]); // Aren't looking at these or the three above case TRANS_QUERY_NMPIPE_STATE: case TRANS_QUERY_NMPIPE_INFO: case TRANS_PEEK_NMPIPE: case TRANS_WAIT_NMPIPE: default: // Don't want to track the response return DCE2_RET__IGNORE; } // Servers return error if incorrect setup count if (setup_count != 2) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_SETUP_COUNT, smb_com_strings[SMB_COM_TRANSACTION], smb_transaction_sub_command_strings[sub_com], setup_count); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, com_size); // Samba validates the Name which should be \PIPE\ and errors // if not. Windows doesn't care. // And Samba uses the ByteCount to validate if (DCE2_SsnIsSambaPolicy(&ssd->sd) && (DCE2_SmbTransactionGetName(nb_ptr, nb_len, byte_count, SmbUnicode(smb_hdr)) != DCE2_RET__SUCCESS)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Failed to validate " "pipe name for Samba.\n")); return DCE2_RET__ERROR; } break; case SMB_COM_TRANSACTION2: sub_com = SmbTransaction2ReqSubCom((SmbTransaction2Req *)nb_ptr); setup_count = SmbTransaction2ReqSetupCnt((SmbTransaction2Req *)nb_ptr); tdcnt = SmbTransaction2ReqTotalDataCnt((SmbTransaction2Req *)nb_ptr); doff = SmbTransaction2ReqDataOff((SmbTransaction2Req *)nb_ptr); dcnt = SmbTransaction2ReqDataCnt((SmbTransaction2Req *)nb_ptr); tpcnt = SmbTransaction2ReqTotalParamCnt((SmbTransaction2Req *)nb_ptr); pcnt = SmbTransaction2ReqParamCnt((SmbTransaction2Req *)nb_ptr); poff = SmbTransaction2ReqParamOff((SmbTransaction2Req *)nb_ptr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Transaction2 subcommand: %s (0x%04X)\n", (sub_com < TRANS2_SUBCOM_MAX) ? smb_transaction2_sub_command_strings[sub_com] : "Unknown", sub_com)); if (sub_com < TRANS2_SUBCOM_MAX) dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__REQUEST][sub_com]++; else dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__REQUEST][TRANS2_SUBCOM_MAX]++; switch (sub_com) { case TRANS2_OPEN2: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED, smb_transaction2_sub_command_strings[sub_com]); data_params = DCE2_SMB_TRANS__PARAMS; break; case TRANS2_QUERY_FILE_INFORMATION: data_params = DCE2_SMB_TRANS__PARAMS; break; case TRANS2_SET_FILE_INFORMATION: data_params = DCE2_SMB_TRANS__BOTH; break; case TRANS2_FIND_FIRST2: case TRANS2_FIND_NEXT2: case TRANS2_QUERY_FS_INFORMATION: case TRANS2_SET_FS_INFORMATION: case TRANS2_QUERY_PATH_INFORMATION: case TRANS2_SET_PATH_INFORMATION: case TRANS2_FSCTL: case TRANS2_IOCTL2: case TRANS2_FIND_NOTIFY_FIRST: case TRANS2_FIND_NOTIFY_NEXT: case TRANS2_CREATE_DIRECTORY: case TRANS2_SESSION_SETUP: case TRANS2_GET_DFS_REFERRAL: case TRANS2_REPORT_DFS_INCONSISTENCY: default: // Don't want to process this transaction any more return DCE2_RET__IGNORE; } if (setup_count != 1) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_SETUP_COUNT, smb_com_strings[SMB_COM_TRANSACTION2], smb_transaction2_sub_command_strings[sub_com], setup_count); return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, com_size); break; case SMB_COM_NT_TRANSACT: sub_com = SmbNtTransactReqSubCom((SmbNtTransactReq *)nb_ptr); setup_count = SmbNtTransactReqSetupCnt((SmbNtTransactReq *)nb_ptr); tdcnt = SmbNtTransactReqTotalDataCnt((SmbNtTransactReq *)nb_ptr); doff = SmbNtTransactReqDataOff((SmbNtTransactReq *)nb_ptr); dcnt = SmbNtTransactReqDataCnt((SmbNtTransactReq *)nb_ptr); tpcnt = SmbNtTransactReqTotalParamCnt((SmbNtTransactReq *)nb_ptr); pcnt = SmbNtTransactReqParamCnt((SmbNtTransactReq *)nb_ptr); poff = SmbNtTransactReqParamOff((SmbNtTransactReq *)nb_ptr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Nt Transact subcommand: %s (0x%04X)\n", (sub_com < NT_TRANSACT_SUBCOM_MAX) ? smb_nt_transact_sub_command_strings[sub_com] : "Unknown", sub_com)); if (sub_com < NT_TRANSACT_SUBCOM_MAX) dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__REQUEST][sub_com]++; else dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__REQUEST][NT_TRANSACT_SUBCOM_MAX]++; switch (sub_com) { case NT_TRANSACT_CREATE: DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED, smb_nt_transact_sub_command_strings[sub_com]); if (setup_count != 0) { DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_SETUP_COUNT, smb_com_strings[SMB_COM_NT_TRANSACT], smb_nt_transact_sub_command_strings[sub_com], setup_count); return DCE2_RET__ERROR; } data_params = DCE2_SMB_TRANS__PARAMS; break; case NT_TRANSACT_IOCTL: case NT_TRANSACT_SET_SECURITY_DESC: case NT_TRANSACT_NOTIFY_CHANGE: case NT_TRANSACT_RENAME: case NT_TRANSACT_QUERY_SECURITY_DESC: default: // Don't want to process this transaction any more return DCE2_RET__IGNORE; } DCE2_MOVE(nb_ptr, nb_len, com_size); break; default: return DCE2_RET__ERROR; } if (DCE2_SmbValidateTransactionFields(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len, byte_count, tdcnt, tpcnt, dcnt, doff, 0, pcnt, poff, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; ttracker->smb_type = SMB_TYPE__REQUEST; ttracker->subcom = (uint8_t)sub_com; ttracker->tdcnt = tdcnt; ttracker->dsent = dcnt; ttracker->tpcnt = tpcnt; ttracker->psent = pcnt; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data count: %u, " "Total data count: %u, Param count: %u, " "Total param count: %u\n", dcnt, tdcnt, pcnt, tpcnt)); // Testing shows that Transacts aren't processed until // all of the data and parameters are received, so overlapping // writes to the same FID can occur as long as the pid/mid are // distinct (and that depends on policy). So we need to buffer // data up for each incomplete Transact so data doesn't get mangled // together with multiple ones intermixing at the same time. if (data_params & DCE2_SMB_TRANS__DATA) { if (tdcnt == 0) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_TDCNT_ZERO); DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); // If all of the data and parameters weren't sent, buffer what was sent if (((dcnt != tdcnt) || (pcnt != tpcnt)) && (dcnt != 0) && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, 0) != DCE2_RET__SUCCESS)) { return DCE2_RET__ERROR; } } if (data_params & DCE2_SMB_TRANS__PARAMS) { if (tpcnt == 0) DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_TDCNT_ZERO); DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); // If all of the data and parameters weren't sent, buffer what was sent if (((pcnt != tpcnt) || (dcnt != tdcnt)) && (pcnt != 0) && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, 0) != DCE2_RET__SUCCESS)) { return DCE2_RET__ERROR; } } if ((dcnt == tdcnt) && (pcnt == tpcnt)) return DCE2_RET__FULL; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_SmbUpdateTransSecondary() * * Purpose: * Handles common checks and updates of transaction secondary * requests - SMB_COM_TRANSACTION_SECONDARY, * SMB_COM_TRANSACTION2_SECONDARY and * SMB_COM_NT_TRANSACT_SECONDARY * * Arguments: * DCE2_SmbSsnData * - pointer to SMB session data * const SmbNtHdr * - pointer to SMB header * const DCE2_SmbComInfo * - pointer to com info structure * const uint8_t * - pointer to data * uint32_t - data length * * Returns: * DCE2_Ret * DCE2_RET__IGNORE if we don't process the subcommand * DCE2_RET__FULL if the transaction is complete * DCE2_RET__ERROR if an error occurred. * DCE2_RET__SUCCESS if ok (but not complete). * ********************************************************************/ static DCE2_Ret DCE2_SmbUpdateTransSecondary(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint16_t com_size = DCE2_ComInfoCommandSize(com_info); uint16_t byte_count = DCE2_ComInfoByteCount(com_info); uint32_t tdcnt, doff, dcnt, ddisp; uint32_t tpcnt, poff, pcnt, pdisp; DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; uint16_t sub_com = ttracker->subcom; int data_params = DCE2_SMB_TRANS__NONE; uint8_t smb_com = DCE2_ComInfoSmbCom(com_info); switch (smb_com) { case SMB_COM_TRANSACTION_SECONDARY: tdcnt = SmbTransactionSecondaryReqTotalDataCnt((SmbTransactionSecondaryReq *)nb_ptr); doff = SmbTransactionSecondaryReqDataOff((SmbTransactionSecondaryReq *)nb_ptr); dcnt = SmbTransactionSecondaryReqDataCnt((SmbTransactionSecondaryReq *)nb_ptr); ddisp = SmbTransactionSecondaryReqDataDisp((SmbTransactionSecondaryReq *)nb_ptr); tpcnt = SmbTransactionSecondaryReqTotalParamCnt((SmbTransactionSecondaryReq *)nb_ptr); poff = SmbTransactionSecondaryReqParamOff((SmbTransactionSecondaryReq *)nb_ptr); pcnt = SmbTransactionSecondaryReqParamCnt((SmbTransactionSecondaryReq *)nb_ptr); pdisp = SmbTransactionSecondaryReqParamDisp((SmbTransactionSecondaryReq *)nb_ptr); switch (sub_com) { case TRANS_TRANSACT_NMPIPE: case TRANS_WRITE_NMPIPE: data_params = DCE2_SMB_TRANS__DATA; break; case TRANS_SET_NMPIPE_STATE: data_params = DCE2_SMB_TRANS__PARAMS; break; default: return DCE2_RET__IGNORE; } break; case SMB_COM_TRANSACTION2_SECONDARY: tdcnt = SmbTransaction2SecondaryReqTotalDataCnt((SmbTransaction2SecondaryReq *)nb_ptr); doff = SmbTransaction2SecondaryReqDataOff((SmbTransaction2SecondaryReq *)nb_ptr); dcnt = SmbTransaction2SecondaryReqDataCnt((SmbTransaction2SecondaryReq *)nb_ptr); ddisp = SmbTransaction2SecondaryReqDataDisp((SmbTransaction2SecondaryReq *)nb_ptr); tpcnt = SmbTransaction2SecondaryReqTotalParamCnt((SmbTransaction2SecondaryReq *)nb_ptr); poff = SmbTransaction2SecondaryReqParamOff((SmbTransaction2SecondaryReq *)nb_ptr); pcnt = SmbTransaction2SecondaryReqParamCnt((SmbTransaction2SecondaryReq *)nb_ptr); pdisp = SmbTransaction2SecondaryReqParamDisp((SmbTransaction2SecondaryReq *)nb_ptr); switch (sub_com) { case TRANS2_OPEN2: case TRANS2_QUERY_FILE_INFORMATION: data_params = DCE2_SMB_TRANS__PARAMS; break; case TRANS2_SET_FILE_INFORMATION: data_params = DCE2_SMB_TRANS__BOTH; break; default: return DCE2_RET__IGNORE; } break; case SMB_COM_NT_TRANSACT_SECONDARY: tdcnt = SmbNtTransactSecondaryReqTotalDataCnt((SmbNtTransactSecondaryReq *)nb_ptr); doff = SmbNtTransactSecondaryReqDataOff((SmbNtTransactSecondaryReq *)nb_ptr); dcnt = SmbNtTransactSecondaryReqDataCnt((SmbNtTransactSecondaryReq *)nb_ptr); ddisp = SmbNtTransactSecondaryReqDataDisp((SmbNtTransactSecondaryReq *)nb_ptr); tpcnt = SmbNtTransactSecondaryReqTotalParamCnt((SmbNtTransactSecondaryReq *)nb_ptr); poff = SmbNtTransactSecondaryReqParamOff((SmbNtTransactSecondaryReq *)nb_ptr); pcnt = SmbNtTransactSecondaryReqParamCnt((SmbNtTransactSecondaryReq *)nb_ptr); pdisp = SmbNtTransactSecondaryReqParamDisp((SmbNtTransactSecondaryReq *)nb_ptr); switch (sub_com) { case NT_TRANSACT_CREATE: data_params = DCE2_SMB_TRANS__PARAMS; break; default: return DCE2_RET__IGNORE; } break; default: return DCE2_RET__ERROR; } if (DCE2_SsnIsSambaPolicy(&ssd->sd)) { // If the total count decreases, Samba will reset this to the new // total count. if (tdcnt < ttracker->tdcnt) ttracker->tdcnt = tdcnt; if (tpcnt < ttracker->tpcnt) ttracker->tpcnt = tpcnt; } else { // Windows always uses the total data count from the first transaction. tdcnt = (uint16_t)ttracker->tdcnt; tpcnt = (uint16_t)ttracker->tpcnt; } DCE2_MOVE(nb_ptr, nb_len, com_size); if (DCE2_SmbValidateTransactionFields(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len, byte_count, tdcnt, tpcnt, dcnt, doff, ddisp, pcnt, poff, pdisp) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_SmbValidateTransactionSent(ssd, ttracker->dsent, dcnt, ttracker->tdcnt, ttracker->psent, pcnt, ttracker->tpcnt) != DCE2_RET__SUCCESS) return DCE2_RET__IGNORE; ttracker->dsent += dcnt; ttracker->psent += pcnt; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data displacement: %u, " "Data count: %u, Total data count: %u\n" "Parameter displacement: %u, " "Parameter count: %u, Total parameter count: %u\n", ddisp, dcnt, tdcnt, pdisp, pcnt, tpcnt)); if (data_params & DCE2_SMB_TRANS__DATA) { DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); if ((dcnt != 0) && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, ddisp) != DCE2_RET__SUCCESS)) { return DCE2_RET__ERROR; } } if (data_params & DCE2_SMB_TRANS__PARAMS) { DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); if ((pcnt != 0) && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, pdisp) != DCE2_RET__SUCCESS)) { return DCE2_RET__ERROR; } } if ((ttracker->dsent == ttracker->tdcnt) && (ttracker->psent == ttracker->tpcnt)) { return DCE2_RET__FULL; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_SmbUpdateTransResponse() * * Purpose: * Handles common checks and updates of transaction responses - * SMB_COM_TRANSACTION, SMB_COM_TRANSACTION2 and SMB_COM_NT_TRANSACT * * Arguments: * DCE2_SmbSsnData * - pointer to SMB session data * const SmbNtHdr * - pointer to SMB header * const DCE2_SmbComInfo * - pointer to com info structure * const uint8_t * - pointer to data * uint32_t - data length * * Returns: * DCE2_Ret * DCE2_RET__FULL if the transaction is complete * DCE2_RET__ERROR if an error occurred. * DCE2_RET__SUCCESS if ok (but not complete). * ********************************************************************/ static DCE2_Ret DCE2_SmbUpdateTransResponse(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len) { uint32_t tpcnt, pcnt, poff, pdisp; uint32_t tdcnt, dcnt, doff, ddisp; DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker; uint16_t sub_com = ttracker->subcom; int data_params = DCE2_SMB_TRANS__NONE; uint8_t smb_com = DCE2_ComInfoSmbCom(com_info); switch (smb_com) { case SMB_COM_TRANSACTION: tdcnt = SmbTransactionRespTotalDataCnt((SmbTransactionResp *)nb_ptr); doff = SmbTransactionRespDataOff((SmbTransactionResp *)nb_ptr); dcnt = SmbTransactionRespDataCnt((SmbTransactionResp *)nb_ptr); ddisp = SmbTransactionRespDataDisp((SmbTransactionResp *)nb_ptr); tpcnt = SmbTransactionRespTotalParamCnt((SmbTransactionResp *)nb_ptr); pcnt = SmbTransactionRespParamCnt((SmbTransactionResp *)nb_ptr); poff = SmbTransactionRespParamOff((SmbTransactionResp *)nb_ptr); pdisp = SmbTransactionRespParamDisp((SmbTransactionResp *)nb_ptr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Transaction subcommand: %s (0x%04X)\n", (sub_com < TRANS_SUBCOM_MAX) ? smb_transaction_sub_command_strings[sub_com] : "Unknown", sub_com)); if (sub_com < TRANS_SUBCOM_MAX) dce2_stats.smb_trans_subcom_stats[SMB_TYPE__RESPONSE][sub_com]++; else dce2_stats.smb_trans_subcom_stats[SMB_TYPE__RESPONSE][TRANS_SUBCOM_MAX]++; switch (sub_com) { case TRANS_TRANSACT_NMPIPE: case TRANS_READ_NMPIPE: data_params = DCE2_SMB_TRANS__DATA; break; case TRANS_SET_NMPIPE_STATE: case TRANS_WRITE_NMPIPE: data_params = DCE2_SMB_TRANS__PARAMS; break; default: return DCE2_RET__ERROR; } break; case SMB_COM_TRANSACTION2: tpcnt = SmbTransaction2RespTotalParamCnt((SmbTransaction2Resp *)nb_ptr); pcnt = SmbTransaction2RespParamCnt((SmbTransaction2Resp *)nb_ptr); poff = SmbTransaction2RespParamOff((SmbTransaction2Resp *)nb_ptr); pdisp = SmbTransaction2RespParamDisp((SmbTransaction2Resp *)nb_ptr); tdcnt = SmbTransaction2RespTotalDataCnt((SmbTransaction2Resp *)nb_ptr); dcnt = SmbTransaction2RespDataCnt((SmbTransaction2Resp *)nb_ptr); doff = SmbTransaction2RespDataOff((SmbTransaction2Resp *)nb_ptr); ddisp = SmbTransaction2RespDataDisp((SmbTransaction2Resp *)nb_ptr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Transaction2 subcommand: %s (0x%04X)\n", (sub_com < TRANS2_SUBCOM_MAX) ? smb_transaction2_sub_command_strings[sub_com] : "Unknown", sub_com)); if (sub_com < TRANS2_SUBCOM_MAX) dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__RESPONSE][sub_com]++; else dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__RESPONSE][TRANS2_SUBCOM_MAX]++; switch (sub_com) { case TRANS2_OPEN2: case TRANS2_SET_FILE_INFORMATION: data_params = DCE2_SMB_TRANS__PARAMS; break; case TRANS2_QUERY_FILE_INFORMATION: data_params = DCE2_SMB_TRANS__DATA; break; default: return DCE2_RET__ERROR; } break; case SMB_COM_NT_TRANSACT: tpcnt = SmbNtTransactRespTotalParamCnt((SmbNtTransactResp *)nb_ptr); pcnt = SmbNtTransactRespParamCnt((SmbNtTransactResp *)nb_ptr); poff = SmbNtTransactRespParamOff((SmbNtTransactResp *)nb_ptr); pdisp = SmbNtTransactRespParamDisp((SmbNtTransactResp *)nb_ptr); tdcnt = SmbNtTransactRespTotalDataCnt((SmbNtTransactResp *)nb_ptr); dcnt = SmbNtTransactRespDataCnt((SmbNtTransactResp *)nb_ptr); doff = SmbNtTransactRespDataOff((SmbNtTransactResp *)nb_ptr); ddisp = SmbNtTransactRespDataDisp((SmbNtTransactResp *)nb_ptr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Nt Transact subcommand: %s (0x%04X)\n", (sub_com < NT_TRANSACT_SUBCOM_MAX) ? smb_nt_transact_sub_command_strings[sub_com] : "Unknown", sub_com)); if (sub_com < NT_TRANSACT_SUBCOM_MAX) dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__RESPONSE][sub_com]++; else dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__RESPONSE][NT_TRANSACT_SUBCOM_MAX]++; switch (sub_com) { case NT_TRANSACT_CREATE: data_params = DCE2_SMB_TRANS__PARAMS; break; default: return DCE2_RET__ERROR; } break; default: return DCE2_RET__ERROR; } DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info)); // From client request if (ttracker->smb_type == SMB_TYPE__REQUEST) { ttracker->smb_type = SMB_TYPE__RESPONSE; ttracker->tdcnt = tdcnt; ttracker->tpcnt = tpcnt; ttracker->dsent = 0; ttracker->psent = 0; DCE2_BufferDestroy(ttracker->dbuf); ttracker->dbuf = NULL; DCE2_BufferDestroy(ttracker->pbuf); ttracker->pbuf = NULL; } else { if (tdcnt < ttracker->tdcnt) ttracker->tdcnt = tdcnt; if (tpcnt < ttracker->tpcnt) ttracker->tpcnt = pcnt; } if (DCE2_SmbValidateTransactionFields(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len, DCE2_ComInfoByteCount(com_info), tdcnt, tpcnt, dcnt, doff, ddisp, pcnt, poff, pdisp) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_SmbValidateTransactionSent(ssd, ttracker->dsent, dcnt, ttracker->tdcnt, ttracker->psent, pcnt, ttracker->tpcnt) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; ttracker->dsent += dcnt; ttracker->psent += pcnt; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data displacement: %u, " "Data count: %u, Total data count: %u\n" "Parameter displacement: %u, " "Parameter count: %u, Total parameter count: %u\n", ddisp, dcnt, tdcnt, pdisp, pcnt, tpcnt)); if (data_params & DCE2_SMB_TRANS__DATA) { DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr); if ((ttracker->dsent < ttracker->tdcnt) || (ttracker->psent < ttracker->tpcnt) || !DCE2_BufferIsEmpty(ttracker->dbuf)) { if ((dcnt != 0) && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, ddisp) != DCE2_RET__SUCCESS)) { return DCE2_RET__ERROR; } } } if (data_params & DCE2_SMB_TRANS__PARAMS) { DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr); if ((ttracker->dsent < ttracker->tdcnt) || (ttracker->psent < ttracker->tpcnt) || !DCE2_BufferIsEmpty(ttracker->dbuf)) { if ((pcnt != 0) && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, pdisp) != DCE2_RET__SUCCESS)) { return DCE2_RET__ERROR; } } } if ((ttracker->dsent == ttracker->tdcnt) && (ttracker->psent == ttracker->tpcnt)) { return DCE2_RET__FULL; } return DCE2_RET__SUCCESS; } static inline void DCE2_SmbRemoveFileTrackerFromRequestTrackers(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker) { DCE2_SmbRequestTracker *rtracker; if (ftracker == NULL) return; // NULL out file trackers of any outstanding requests // that reference this file tracker if (ssd->rtracker.ftracker == ftracker) ssd->rtracker.ftracker = NULL; if ((ssd->cur_rtracker != NULL) && (ssd->cur_rtracker->ftracker == ftracker)) ssd->cur_rtracker->ftracker = NULL; for (rtracker = DCE2_QueueFirst(ssd->rtrackers); rtracker != NULL; rtracker = DCE2_QueueNext(ssd->rtrackers)) { if (rtracker->ftracker == ftracker) rtracker->ftracker = NULL; } } static inline void DCE2_SmbSetNewFileAPIFileTracker(DCE2_SmbSsnData *ssd) { DCE2_SmbFileTracker *ftracker = &ssd->ftracker; while (ftracker != NULL) { if ((ftracker != ssd->fapi_ftracker) && (ftracker->fid != DCE2_SENTINEL) && !ftracker->is_ipc && ftracker->ff_sequential_only && (ftracker->ff_bytes_processed == 0)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Designating file tracker " "for file API processing: \"%s\" (0x%04X)\n", ftracker->file_name, (uint16_t)ftracker->fid);); break; } if (ftracker == &ssd->ftracker) ftracker = DCE2_ListFirst(ssd->ftrackers); else ftracker = DCE2_ListNext(ssd->ftrackers); } ssd->fapi_ftracker = ftracker; } static inline void DCE2_SmbResetFileChunks(DCE2_SmbFileTracker *ftracker) { if (ftracker == NULL) return; DCE2_ListDestroy(ftracker->ff_file_chunks); ftracker->ff_file_chunks = NULL; ftracker->ff_bytes_queued = 0; } static inline void DCE2_SmbAbortFileAPI(DCE2_SmbSsnData *ssd) { DCE2_SmbResetFileChunks(ssd->fapi_ftracker); ssd->fapi_ftracker = NULL; } #ifdef ACTIVE_RESPONSE static uint8_t dce2_smb_delete_pdu[65535]; void DCE2_SmbInitDeletePdu(void) { NbssHdr *nb_hdr = (NbssHdr *)dce2_smb_delete_pdu; SmbNtHdr *smb_hdr = (SmbNtHdr *)((uint8_t *)nb_hdr + sizeof(*nb_hdr)); SmbDeleteReq *del_req = (SmbDeleteReq *)((uint8_t *)smb_hdr + sizeof(*smb_hdr)); uint8_t *del_req_fmt = (uint8_t *)del_req + sizeof(*del_req); uint16_t smb_flg2 = 0x4001; uint16_t search_attrs = 0x0006; memset(dce2_smb_delete_pdu, 0, sizeof(dce2_smb_delete_pdu)); nb_hdr->type = 0; nb_hdr->flags = 0; memcpy((void *)smb_hdr->smb_idf, (void *)"\xffSMB", sizeof(smb_hdr->smb_idf)); smb_hdr->smb_com = SMB_COM_DELETE; smb_hdr->smb_status.nt_status = 0; //smb_hdr->smb_flg = 0x18; smb_hdr->smb_flg = 0; smb_hdr->smb_flg2 = SmbHtons(&smb_flg2); smb_hdr->smb_tid = 0; // needs to be set before injected smb_hdr->smb_pid = 777; smb_hdr->smb_uid = 0; // needs to be set before injected smb_hdr->smb_mid = 777; del_req->smb_wct = 1; del_req->smb_search_attrs = SmbHtons(&search_attrs); *del_req_fmt = SMB_FMT__ASCII; } static void DCE2_SmbInjectDeletePdu(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker) { NbssHdr *nb_hdr = (NbssHdr *)dce2_smb_delete_pdu; SmbNtHdr *smb_hdr = (SmbNtHdr *)((uint8_t *)nb_hdr + sizeof(*nb_hdr)); SmbDeleteReq *del_req = (SmbDeleteReq *)((uint8_t *)smb_hdr + sizeof(*smb_hdr)); char *del_filename = (char *)((uint8_t *)del_req + sizeof(*del_req) + 1); uint32_t len; uint16_t file_name_len = strlen(ftracker->file_name) + 1; nb_hdr->length = htons(sizeof(*smb_hdr) + sizeof(*del_req) + 1 + file_name_len); len = ntohs(nb_hdr->length) + sizeof(*nb_hdr); smb_hdr->smb_tid = SmbHtons(&ftracker->tid); smb_hdr->smb_uid = SmbHtons(&ftracker->uid); del_req->smb_bcc = 1 + file_name_len; memcpy(del_filename, ftracker->file_name, file_name_len); _dpd.activeInjectData((void *)ssd->sd.wire_pkt, 0, (uint8_t *)nb_hdr, len); } static void DCE2_SmbFinishFileBlockVerdict(DCE2_SmbSsnData *ssd) { void *ssnptr = ssd->sd.wire_pkt->stream_session_ptr; void *p = (void *)ssd->sd.wire_pkt; File_Verdict verdict; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_file); verdict = DCE2_SmbGetFileVerdict(p, ssnptr); if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT)) { DCE2_SmbInjectDeletePdu(ssd, ssd->fb_ftracker); PREPROC_PROFILE_START(dce2_pstat_smb_file_api); _dpd.fileAPI->render_block_verdict(NULL, p); PREPROC_PROFILE_END(dce2_pstat_smb_file_api); } ssd->fb_ftracker = NULL; ssd->block_pdus = false; PREPROC_PROFILE_END(dce2_pstat_smb_file); } static File_Verdict DCE2_SmbGetFileVerdict(void *p, void *ssnptr) { File_Verdict verdict; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_smb_file_api); verdict = _dpd.fileAPI->get_file_verdict(ssnptr); if (verdict == FILE_VERDICT_PENDING) { _dpd.fileAPI->file_signature_lookup(p, true); verdict = _dpd.fileAPI->get_file_verdict(ssnptr); } PREPROC_PROFILE_END(dce2_pstat_smb_file_api); return verdict; } #endif static inline void DCE2_SmbFinishFileAPI(DCE2_SmbSsnData *ssd) { void *ssnptr = ssd->sd.wire_pkt->stream_session_ptr; void *p = (void *)ssd->sd.wire_pkt; DCE2_SmbFileTracker *ftracker = ssd->fapi_ftracker; bool upload; PROFILE_VARS; if (ftracker == NULL) return; PREPROC_PROFILE_START(dce2_pstat_smb_file); upload = _dpd.fileAPI->get_file_direction(ssnptr); if (_dpd.fileAPI->get_file_processed_size(ssnptr) != 0) { // Never knew the size of the file so never knew when to tell the // fileAPI the upload/download was finished. if ((ftracker->ff_file_size == 0) && (ftracker->ff_bytes_processed != 0)) { DCE2_SmbSetFileName(ftracker->file_name); PREPROC_PROFILE_START(dce2_pstat_smb_file_api); #ifdef ACTIVE_RESPONSE if (_dpd.fileAPI->file_process(p, NULL, 0, SNORT_FILE_END, upload, upload)) { if (upload) { File_Verdict verdict = _dpd.fileAPI->get_file_verdict(ssd->sd.wire_pkt->stream_session_ptr); if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT)) ssd->fb_ftracker = ftracker; } } #else (void)_dpd.fileAPI->file_process(p, NULL, 0, SNORT_FILE_END, upload, false); #endif PREPROC_PROFILE_END(dce2_pstat_smb_file_api); dce2_stats.smb_files_processed++; } } ssd->fapi_ftracker = NULL; PREPROC_PROFILE_END(dce2_pstat_smb_file); } static inline bool DCE2_SmbIsVerdictSuspend(bool upload, FilePosition position) { #ifdef ACTIVE_RESPONSE if (upload && ((position == SNORT_FILE_FULL) || (position == SNORT_FILE_END))) return true; #endif return false; } static DCE2_Ret DCE2_SmbFileAPIProcess(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker, const uint8_t *data_ptr, uint32_t data_len, bool upload) { FilePosition position; PROFILE_VARS; if (ssd->fb_ftracker && (ssd->fb_ftracker != ftracker)) return DCE2_RET__SUCCESS; // Trim data length if it exceeds the maximum file depth if ((ssd->max_file_depth != 0) && (ftracker->ff_bytes_processed + data_len) > (uint64_t)ssd->max_file_depth) data_len = ssd->max_file_depth - ftracker->ff_bytes_processed; if (ftracker->ff_file_size == 0) { // Don't know the file size. if ((ftracker->ff_bytes_processed == 0) && (ssd->max_file_depth != 0) && (data_len == (uint64_t)ssd->max_file_depth)) position = SNORT_FILE_FULL; else if (ftracker->ff_bytes_processed == 0) position = SNORT_FILE_START; else if ((ssd->max_file_depth != 0) && ((ftracker->ff_bytes_processed + data_len) == (uint64_t)ssd->max_file_depth)) position = SNORT_FILE_END; else position = SNORT_FILE_MIDDLE; } else { if ((ftracker->ff_bytes_processed == 0) && ((data_len == ftracker->ff_file_size) || ((ssd->max_file_depth != 0) && (data_len == (uint64_t)ssd->max_file_depth)))) position = SNORT_FILE_FULL; else if (ftracker->ff_bytes_processed == 0) position = SNORT_FILE_START; else if (((ftracker->ff_bytes_processed + data_len) >= ftracker->ff_file_size) || ((ssd->max_file_depth != 0) && ((ftracker->ff_bytes_processed + data_len) == (uint64_t)ssd->max_file_depth))) position = SNORT_FILE_END; else position = SNORT_FILE_MIDDLE; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Sending SMB file data to file API ........\n")); PREPROC_PROFILE_START(dce2_pstat_smb_file_api); if (!_dpd.fileAPI->file_process((void *)ssd->sd.wire_pkt, (uint8_t *)data_ptr, (int)data_len, position, upload, DCE2_SmbIsVerdictSuspend(upload, position))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File API returned FAILURE " "for \"%s\" (0x%02X) %s\n", smb_file_name, ftracker->fid, upload ? "UPLOAD" : "DOWNLOAD")); PREPROC_PROFILE_END(dce2_pstat_smb_file_api); // Failure. Abort tracking this file under file API return DCE2_RET__ERROR; } else { PREPROC_PROFILE_END(dce2_pstat_smb_file_api); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File API returned SUCCESS " "for \"%s\" (0x%02X) %s\n", smb_file_name, ftracker->fid, upload ? "UPLOAD" : "DOWNLOAD")); if (((position == SNORT_FILE_START) || (position == SNORT_FILE_FULL)) && (strlen(smb_file_name) != 0)) { _dpd.fileAPI->set_file_name((void *)ssd->sd.wire_pkt->stream_session_ptr, (uint8_t *)smb_file_name, strlen(smb_file_name)); } if ((position == SNORT_FILE_FULL) || (position == SNORT_FILE_END)) { #ifdef ACTIVE_RESPONSE if (upload) { File_Verdict verdict = _dpd.fileAPI->get_file_verdict(ssd->sd.wire_pkt->stream_session_ptr); if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT) || (verdict == FILE_VERDICT_PENDING)) { ssd->fb_ftracker = ftracker; } } #endif ftracker->ff_sequential_only = false; dce2_stats.smb_files_processed++; return DCE2_RET__FULL; } } return DCE2_RET__SUCCESS; } static int DCE2_SmbFileOffsetCompare(const void *a, const void *b) { const DCE2_SmbFileChunk *x = (DCE2_SmbFileChunk *)a; const DCE2_SmbFileChunk *y = (DCE2_SmbFileChunk *)b; if (x->offset > y->offset) return 1; if (x->offset < y->offset) return -1; return 0; } static void DCE2_SmbFileChunkFree(void *data) { DCE2_SmbFileChunk *fc = (DCE2_SmbFileChunk *)data; if (fc == NULL) return; if (fc->data != NULL) DCE2_Free((void *)fc->data, fc->length, DCE2_MEM_TYPE__SMB_FILE); DCE2_Free((void *)fc, sizeof(DCE2_SmbFileChunk), DCE2_MEM_TYPE__SMB_FILE); } static DCE2_Ret DCE2_SmbHandleOutOfOrderFileData(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker, const uint8_t *data_ptr, uint32_t data_len, bool upload) { if (ftracker->ff_file_offset == ftracker->ff_bytes_processed) { uint64_t initial_offset = ftracker->ff_file_offset; uint64_t next_offset = initial_offset + data_len; DCE2_SmbFileChunk *file_chunk = DCE2_ListFirst(ftracker->ff_file_chunks); DCE2_Ret ret = DCE2_SmbFileAPIProcess(ssd, ftracker, data_ptr, data_len, upload); ftracker->ff_bytes_processed += data_len; ftracker->ff_file_offset = ftracker->ff_bytes_processed; if (ret != DCE2_RET__SUCCESS) return ret; // Should already be chunks in here if we came into this function // with an in order chunk, but check just in case. if (file_chunk == NULL) return DCE2_RET__ERROR; while (file_chunk != NULL) { if (file_chunk->offset > next_offset) break; if (file_chunk->offset == next_offset) { ret = DCE2_SmbFileAPIProcess(ssd, ftracker, file_chunk->data, file_chunk->length, upload); ftracker->ff_bytes_processed += file_chunk->length; ftracker->ff_file_offset = ftracker->ff_bytes_processed; if (ret != DCE2_RET__SUCCESS) return ret; next_offset = file_chunk->offset + file_chunk->length; } ftracker->ff_bytes_queued -= file_chunk->length; DCE2_ListRemoveCurrent(ftracker->ff_file_chunks); file_chunk = DCE2_ListNext(ftracker->ff_file_chunks); } if (initial_offset == 0) DCE2_SmbResetFileChunks(ftracker); } else { DCE2_SmbFileChunk *file_chunk; DCE2_Ret ret; if (ftracker->ff_file_chunks == NULL) { ftracker->ff_file_chunks = DCE2_ListNew(DCE2_LIST_TYPE__SORTED, DCE2_SmbFileOffsetCompare, DCE2_SmbFileChunkFree, NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_FILE); if (ftracker->ff_file_chunks == NULL) return DCE2_RET__ERROR; } if ((ftracker->ff_bytes_queued + data_len) > (DCE2_GcMemcap() >> 4)) return DCE2_RET__ERROR; file_chunk = DCE2_Alloc(sizeof(DCE2_SmbFileChunk), DCE2_MEM_TYPE__SMB_FILE); if (file_chunk == NULL) return DCE2_RET__ERROR; file_chunk->data = DCE2_Alloc(data_len, DCE2_MEM_TYPE__SMB_FILE); if (file_chunk->data == NULL) { DCE2_Free(file_chunk, sizeof(DCE2_SmbFileChunk), DCE2_MEM_TYPE__SMB_FILE); return DCE2_RET__ERROR; } file_chunk->offset = ftracker->ff_file_offset; file_chunk->length = data_len; memcpy(file_chunk->data, data_ptr, data_len); ftracker->ff_bytes_queued += data_len; if ((ret = DCE2_ListInsert(ftracker->ff_file_chunks, (void *)file_chunk, (void *)file_chunk)) != DCE2_RET__SUCCESS) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Insert file chunk failed: " "0x%02X.\n", ftracker->fid);); DCE2_Free(file_chunk->data, data_len, DCE2_MEM_TYPE__SMB_FILE); DCE2_Free(file_chunk, sizeof(DCE2_SmbFileChunk), DCE2_MEM_TYPE__SMB_FILE); if (ret != DCE2_RET__DUPLICATE) return DCE2_RET__ERROR; } } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Currently buffering %u bytes " "of out of order file data.\n", ftracker->ff_bytes_queued);); return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_SmbProcessFileData() * * Purpose: * Processes regular file data send via reads/writes. Sends * data to the file API for type id and signature and sets the * file data ptr for rule inspection. * * Arguments: * DCE2_SmbSsnData * - pointer to SMB session data * DCE2_SmbFileTracker * - pointer to file tracker * const uint8_t * - pointer to file data * uint32_t - length of file data * bool - whether it's an upload (true) or * download (false) * * Returns: None * ********************************************************************/ static void DCE2_SmbProcessFileData(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker, const uint8_t *data_ptr, uint32_t data_len, bool upload) { bool cur_upload = DCE2_SmbFileUpload(ftracker->ff_file_direction) ? true : false; int64_t file_data_depth = DCE2_ScSmbFileDepth(ssd->sd.sconfig); PROFILE_VARS; if (data_len == 0) return; PREPROC_PROFILE_START(dce2_pstat_smb_file); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File size: "STDu64", File offset: "STDu64", Bytes processed: "STDu64", " "Data len: %u\n", ftracker->ff_file_size, ftracker->ff_file_offset, ftracker->ff_bytes_processed, data_len);); // Account for wrapping. Not likely but just in case. if ((ftracker->ff_bytes_processed + data_len) < ftracker->ff_bytes_processed) { DCE2_SmbRemoveFileTracker(ssd, ftracker); PREPROC_PROFILE_END(dce2_pstat_smb_file); return; } if ((ftracker->ff_bytes_processed == 0) && DCE2_SmbFileDirUnknown(ftracker->ff_file_direction)) { ftracker->ff_file_direction = upload ? DCE2_SMB_FILE_DIRECTION__UPLOAD : DCE2_SMB_FILE_DIRECTION__DOWNLOAD; } else if (cur_upload != upload) { if (cur_upload) { // Went from writing to reading. Ignore the read. DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Went from writing to " "reading - ignoring read.\n");); PREPROC_PROFILE_END(dce2_pstat_smb_file); return; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Went from reading to " "writing - consider transfer done.\n");); // Went from reading to writing. Consider the transfer done // and remove the file tracker. DCE2_SmbRemoveFileTracker(ssd, ftracker); PREPROC_PROFILE_END(dce2_pstat_smb_file); return; } if ((file_data_depth != -1) && ((ftracker->ff_file_offset == ftracker->ff_bytes_processed) && ((file_data_depth == 0) || (ftracker->ff_bytes_processed < (uint64_t)file_data_depth)))) { _dpd.setFileDataPtr((uint8_t *)data_ptr, (data_len > UINT16_MAX) ? UINT16_MAX : (uint16_t)data_len); DCE2_FileDetect(&ssd->sd); } if (ftracker == ssd->fapi_ftracker) { DCE2_Ret ret; if ((ftracker->ff_file_offset != ftracker->ff_bytes_processed) || !DCE2_ListIsEmpty(ftracker->ff_file_chunks)) { if ((ssd->max_file_depth != 0) && (ftracker->ff_file_offset >= (uint64_t)ssd->max_file_depth)) { // If the offset is beyond the max file depth, ignore it. PREPROC_PROFILE_END(dce2_pstat_smb_file); return; } else if (upload && (data_len == 1) && (ftracker->ff_file_offset > ftracker->ff_bytes_processed)) { // Sometimes a write one byte is done at a high offset, I'm // guessing to make sure the system has sufficient disk // space to complete the full write. Ignore it because it // will likely be overwritten. PREPROC_PROFILE_END(dce2_pstat_smb_file); return; } if ((ftracker->ff_file_offset == 0) && (ftracker->ff_bytes_processed != 0)) { // Sometimes initial reads/writes are out of order to get file info // such as an icon, then proceed to write in order. Usually the // first read/write is at offset 0, then the next ones are somewhere // off in the distance. Reset and continue on below. DCE2_SmbResetFileChunks(ftracker); ftracker->ff_bytes_processed = 0; } else if (ftracker->ff_file_offset < ftracker->ff_bytes_processed) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File offset ("STDu64") is " "less than bytes processed ("STDu64") - aborting.\n", ftracker->ff_file_offset, ftracker->ff_bytes_processed);); DCE2_SmbAbortFileAPI(ssd); DCE2_SmbSetNewFileAPIFileTracker(ssd); PREPROC_PROFILE_END(dce2_pstat_smb_file); return; } else { ret = DCE2_SmbHandleOutOfOrderFileData(ssd, ftracker, data_ptr, data_len, upload); if (ret != DCE2_RET__SUCCESS) { DCE2_SmbAbortFileAPI(ssd); DCE2_SmbSetNewFileAPIFileTracker(ssd); } PREPROC_PROFILE_END(dce2_pstat_smb_file); return; } } ret = DCE2_SmbFileAPIProcess(ssd, ftracker, data_ptr, data_len, upload); ftracker->ff_bytes_processed += data_len; ftracker->ff_file_offset = ftracker->ff_bytes_processed; if (ret != DCE2_RET__SUCCESS) { DCE2_SmbAbortFileAPI(ssd); DCE2_SmbSetNewFileAPIFileTracker(ssd); } } else { if (ftracker->ff_file_offset == ftracker->ff_bytes_processed) { ftracker->ff_bytes_processed += data_len; ftracker->ff_file_offset = ftracker->ff_bytes_processed; } if ((file_data_depth == -1) || ((file_data_depth != 0) && (ftracker->ff_bytes_processed >= (uint64_t)file_data_depth))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Bytes processed ("STDu64") " "is at or beyond file data depth ("STDu64") - finished.\n", ftracker->ff_bytes_processed, file_data_depth);); DCE2_SmbRemoveFileTracker(ssd, ftracker); PREPROC_PROFILE_END(dce2_pstat_smb_file); return; } } PREPROC_PROFILE_END(dce2_pstat_smb_file); } /******************************************************************** * Function: DCE2_SmbSetFileName() * * Purpose: * Copies the NULL terminated file name passed in to the global * array for logging the file name for events. * * Arguments: * char * - NULL terminated file name * * Returns: None * ********************************************************************/ static inline void DCE2_SmbSetFileName(char *file_name) { uint16_t size; size_t file_name_len; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File name: %s\n", (file_name == NULL) ? "NULL" : file_name)); if (file_name == NULL) return; file_name_len = strlen(file_name); if (file_name_len+1 > sizeof(smb_file_name)) size = sizeof(smb_file_name)-1; else size = file_name_len; memcpy(smb_file_name, file_name, size); smb_file_name[size] = '\0'; } /******************************************************************** * Function: DCE2_SmbGetString() * * Purpose: * Parses data passed in and returns an ASCII string. True * unicode characters are replaced with a '.' * * Arguments: * const uint8_t * - pointer to data * uint32_t - data length * bool - true if the data is unicode (UTF-16LE) * bool - true if the function should only return the * file name instead of the entire path * * Returns: * char * - NULL terminated ASCII string * ********************************************************************/ static char * DCE2_SmbGetString(const uint8_t *data, uint32_t data_len, bool unicode, bool get_file) { char *str; uint32_t i, j, k = unicode ? data_len - 1 : data_len; uint8_t inc = unicode ? 2 : 1; if (data_len < inc) return NULL; // Move forward. Don't know if the end of data is actually // the end of the string. for (i = 0, j = 0; i < k; i += inc) { uint16_t uchar = unicode ? SmbNtohs((uint16_t *)(data + i)) : data[i]; if (uchar == 0) break; else if (get_file && ((uchar == 0x002F) || (uchar == 0x005C))) // slash and back-slash j = i + inc; } // Only got a NULL byte or nothing after slash/back-slash or too big. if ((i == 0) || (j == i) || (get_file && (i > DCE2_SMB_MAX_COMP_LEN)) || (i > DCE2_SMB_MAX_PATH_LEN)) return NULL; str = (char *)DCE2_Alloc(((i-j)>>(inc-1))+1, DCE2_MEM_TYPE__SMB_SSN); if (str == NULL) return NULL; for (k = 0; j < i; j += inc, k++) { if (isprint((int)data[j])) str[k] = (char)data[j]; else str[k] = '.'; } str[k] = 0; return str; } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/snort_dce2.h0000644000000000000000000001047712260565732020622 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _SNORT_DCE2_H_ #define _SNORT_DCE2_H_ #include "dce2_utils.h" #include "dce2_session.h" #include "sf_snort_packet.h" #include "sf_types.h" #include "snort_debug.h" /******************************************************************** * Macros ********************************************************************/ #define DCE2_PROTO_REF_STR__NBSS "netbios-ssn" /* Essentially SMB */ #define DCE2_PROTO_REF_STR__DCERPC "dcerpc" /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_RpktType { DCE2_RPKT_TYPE__NULL = 0, DCE2_RPKT_TYPE__SMB_SEG, DCE2_RPKT_TYPE__SMB_TRANS, DCE2_RPKT_TYPE__SMB_CO_SEG, DCE2_RPKT_TYPE__SMB_CO_FRAG, DCE2_RPKT_TYPE__TCP_CO_SEG, DCE2_RPKT_TYPE__TCP_CO_FRAG, DCE2_RPKT_TYPE__UDP_CL_FRAG, DCE2_RPKT_TYPE__MAX } DCE2_RpktType; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_ProtoIds { int16_t dcerpc; int16_t nbss; } DCE2_ProtoIds; /******************************************************************** * Extern variables ********************************************************************/ extern DCE2_ProtoIds dce2_proto_ids; extern DCE2_CStack *dce2_pkt_stack; /******************************************************************** * Public function prototypes ********************************************************************/ DCE2_Ret DCE2_Process(SFSnortPacket *); void DCE2_InitRpkts(void); SFSnortPacket * DCE2_GetRpkt(const SFSnortPacket *, DCE2_RpktType, const uint8_t *, uint32_t); DCE2_Ret DCE2_AddDataToRpkt(SFSnortPacket *, DCE2_RpktType, const uint8_t *, uint32_t); DCE2_Ret DCE2_PushPkt(SFSnortPacket *); void DCE2_PopPkt(void); void DCE2_Detect(DCE2_SsnData *); void DCE2_FileDetect(DCE2_SsnData *); uint16_t DCE2_GetRpktMaxData(DCE2_SsnData *, DCE2_RpktType); void DCE2_FreeGlobals(void); void DCE2_SetNoInspect(DCE2_SsnData *); /******************************************************************** * Inline function prototypes ********************************************************************/ static inline void DCE2_ResetRopts(DCE2_Roptions *); static inline void DCE2_DisableDetect(SFSnortPacket *); /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: None * ********************************************************************/ static inline void DCE2_ResetRopts(DCE2_Roptions *ropts) { ropts->first_frag = DCE2_SENTINEL; ropts->opnum = DCE2_SENTINEL; ropts->hdr_byte_order = DCE2_SENTINEL; ropts->data_byte_order = DCE2_SENTINEL; ropts->stub_data = NULL; } /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ static inline void DCE2_DisableDetect(SFSnortPacket *p) { _dpd.disableAllDetect(p); _dpd.setPreprocBit(p, PP_SFPORTSCAN); _dpd.setPreprocBit(p, PP_PERFMONITOR); _dpd.setPreprocBit(p, PP_SDF); } #endif /* _SNORT_DCE2_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/snort_dce2.c0000644000000000000000000012257212260565732020615 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_dce2.h" #include "spp_dce2.h" #include "dce2_config.h" #include "dce2_utils.h" #include "dce2_list.h" #include "dce2_stats.h" #include "dce2_session.h" #include "dce2_event.h" #include "dce2_smb.h" #include "dce2_udp.h" #include "dce2_tcp.h" #include "dce2_http.h" #include "dce2_co.h" #include "dce2_cl.h" #include "dce2_memory.h" #include "sf_dynamic_preprocessor.h" #include "stream_api.h" #include "sfrt.h" #include "profiler.h" #include "sfPolicy.h" #include "sf_seqnums.h" /******************************************************************** * Global variables ********************************************************************/ DCE2_CStack *dce2_pkt_stack = NULL; DCE2_ProtoIds dce2_proto_ids; static SFSnortPacket* dce2_rpkt[DCE2_RPKT_TYPE__MAX] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static int dce2_detected = 0; // Used to indicate that a session is no longer being looked at // It will be the session data that is returned so a pointer check // is sufficient to tell if the preprocessor shouldn't look at the session. uint8_t dce2_no_inspect; /******************************************************************** * Macros ********************************************************************/ #define DCE2_PKT_STACK__SIZE 10 /******************************************************************** * Private function prototypes ********************************************************************/ static DCE2_SsnData * DCE2_NewSession(SFSnortPacket *, tSfPolicyId); static DCE2_TransType DCE2_GetTransport(SFSnortPacket *, const DCE2_ServerConfig *, int *); static DCE2_TransType DCE2_GetDetectTransport(SFSnortPacket *, const DCE2_ServerConfig *); static DCE2_TransType DCE2_GetAutodetectTransport(SFSnortPacket *, const DCE2_ServerConfig *); static DCE2_Ret DCE2_SetSsnState(DCE2_SsnData *, SFSnortPacket *); static void DCE2_SsnFree(void *); /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ static DCE2_SsnData * DCE2_NewSession(SFSnortPacket *p, tSfPolicyId policy_id) { DCE2_SsnData *sd = NULL; DCE2_TransType trans; const DCE2_ServerConfig *sc = DCE2_ScGetConfig(p); int autodetected = 0; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_new_session); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Creating new session: ")); trans = DCE2_GetTransport(p, sc, &autodetected); switch (trans) { case DCE2_TRANS_TYPE__SMB: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "SMB transport ... ")); sd = (DCE2_SsnData *)DCE2_SmbSsnInit(p); break; case DCE2_TRANS_TYPE__TCP: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "TCP transport ... ")); sd = (DCE2_SsnData *)DCE2_TcpSsnInit(); break; case DCE2_TRANS_TYPE__UDP: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "UDP transport ... ")); sd = (DCE2_SsnData *)DCE2_UdpSsnInit(); break; case DCE2_TRANS_TYPE__HTTP_PROXY: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "RPC over HTTP proxy transport ... ")); sd = (DCE2_SsnData *)DCE2_HttpProxySsnInit(); break; case DCE2_TRANS_TYPE__HTTP_SERVER: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "RPC over HTTP server transport ... ")); sd = (DCE2_SsnData *)DCE2_HttpServerSsnInit(); break; case DCE2_TRANS_TYPE__NONE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Not configured to " "look at this traffic or unable to autodetect - not inspecting.\n")); PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, trans); PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; } if (sd == NULL) { PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; } DCE2_SsnSetAppData(p, (void *)sd, DCE2_SsnFree); dce2_stats.sessions++; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Created (%p)\n", (void *)sd)); sd->trans = trans; sd->server_policy = DCE2_ScPolicy(sc); sd->client_policy = DCE2_POLICY__WINXP; // Default to Windows XP sd->sconfig = sc; sd->wire_pkt = p; sd->policy_id = policy_id; sd->config = dce2_config; ((DCE2_Config *)sfPolicyUserDataGet(sd->config, policy_id))->ref_count++; if (autodetected) { dce2_stats.sessions_autodetected++; #ifdef DEBUG if (DCE2_SsnFromServer(p)) dce2_stats.autoports[p->src_port][trans]++; else dce2_stats.autoports[p->dst_port][trans]++; #endif DCE2_SsnSetAutodetected(sd, p); } /* If we've determined a transport, make sure we're doing * reassembly on the session */ if (IsTCP(p)) { int rs_dir = DCE2_SsnGetReassembly(p); if (!_dpd.isPafEnabled() && (rs_dir != SSN_DIR_BOTH)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Setting client/server reassembly to FOOTPRINT for this session.\n")); DCE2_SsnSetReassembly(p); } if (!DCE2_SsnIsRebuilt(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Got non-rebuilt packet\n")); if (DCE2_SsnIsStreamInsert(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Stream inserted - not inspecting.\n")); PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; } else if ((DCE2_SsnFromClient(p) && (rs_dir == SSN_DIR_FROM_SERVER)) || (DCE2_SsnFromServer(p) && (rs_dir == SSN_DIR_FROM_CLIENT)) || (rs_dir == SSN_DIR_BOTH)) { /* Reassembly was already set for this session, but stream * decided not to use the packet so it's probably not good */ DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Got non-stream inserted packet - not inspecting\n")); PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; } } } PREPROC_PROFILE_END(dce2_pstat_new_session); return sd; } /********************************************************************* * Function: DCE2_Process() * * Purpose: Main entry point for DCE/RPC processing. * * Arguments: * SFSnortPacket * - pointer to packet structure * * Returns: * DCE2_Ret - status * *********************************************************************/ DCE2_Ret DCE2_Process(SFSnortPacket *p) { tSfPolicyId policy_id = _dpd.getRuntimePolicy(); DCE2_SsnData *sd = (DCE2_SsnData *)DCE2_SsnGetAppData(p); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_session); if ((sd != NULL) && DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Session set to " "not inspect. Returning\n")); PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } dce2_eval_config = (DCE2_Config *)sfPolicyUserDataGet(dce2_config, policy_id); if (sd != NULL) dce2_eval_config = (DCE2_Config *)sfPolicyUserDataGet(sd->config, sd->policy_id); if (dce2_eval_config == NULL) { PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } if (sd == NULL) { sd = DCE2_NewSession(p, policy_id); if (sd == NULL) { PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } } else { sd->wire_pkt = p; if (_dpd.isPafEnabled() && !DCE2_SsnIsPafActive(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "PAF was aborted on " "one or both sides - aborting session inspection\n")); DCE2_SetNoInspect(sd); PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } if (IsTCP(p) && !DCE2_SsnIsRebuilt(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Got non-rebuilt packet " "on session (%p)\n", (void *)sd)); if (DCE2_SsnIsStreamInsert(p)) { if (!_dpd.isPafEnabled()) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Flushing opposite direction.\n")); DCE2_SsnFlush(p); } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Stream inserted - not inspecting.\n")); } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Got non-stream inserted packet " "- not inspecting\n")); } PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } else if (DCE2_SsnAutodetected(sd) && !(p->flags & sd->autodetect_dir)) { /* Try to autodetect in opposite direction */ if ((sd->trans != DCE2_TRANS_TYPE__HTTP_PROXY) && (sd->trans != DCE2_TRANS_TYPE__HTTP_SERVER) && (DCE2_GetAutodetectTransport(p, sd->sconfig) != sd->trans)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Bad autodetect.\n")); DCE2_SetNoInspect(sd); dce2_stats.bad_autodetects++; PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } DCE2_SsnClearAutodetected(sd); } } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Session pointer: %p\n", (void *)sd)); if (IsTCP(p) && (DCE2_SetSsnState(sd, p) != DCE2_RET__SUCCESS)) { PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } if (DCE2_PushPkt((void *)p) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to push packet onto packet stack.", __FILE__, __LINE__); PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } p->flags |= FLAG_ALLOW_MULTIPLE_DETECT; dce2_detected = 0; PREPROC_PROFILE_END(dce2_pstat_session); switch (sd->trans) { case DCE2_TRANS_TYPE__SMB: DCE2_SmbProcess((DCE2_SmbSsnData *)sd); break; case DCE2_TRANS_TYPE__TCP: DCE2_TcpProcess((DCE2_TcpSsnData *)sd); break; case DCE2_TRANS_TYPE__UDP: DCE2_UdpProcess((DCE2_UdpSsnData *)sd); break; case DCE2_TRANS_TYPE__HTTP_PROXY: DCE2_HttpProcessProxy((DCE2_HttpSsnData *)sd); break; case DCE2_TRANS_TYPE__HTTP_SERVER: DCE2_HttpProcessServer((DCE2_HttpSsnData *)sd); break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, sd->trans); return DCE2_RET__NOT_INSPECTED; } if (sd->flags & DCE2_SSN_FLAG__NO_INSPECT) { DCE2_SetNoInspect(sd); DCE2_PopPkt(); PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } if (!dce2_detected) DCE2_Detect(sd); DCE2_ResetRopts(&sd->ropts); DCE2_PopPkt(); if (dce2_mem_state == DCE2_MEM_STATE__MEMCAP) { DCE2_SetNoInspect(sd); dce2_mem_state = DCE2_MEM_STATE__OKAY; return DCE2_RET__NOT_INSPECTED; } if (DCE2_SsnAutodetected(sd)) return DCE2_RET__NOT_INSPECTED; return DCE2_RET__INSPECTED; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_SetNoInspect(DCE2_SsnData *sd) { if (sd == NULL) return; dce2_stats.sessions_aborted++; DCE2_SsnSetNoInspect(sd->wire_pkt); } /******************************************************************** * Function: DCE2_SetSsnState() * * Purpose: * Checks for missing packets and overlapping data on session * * Arguments: * DCE2_SsnData * - session data pointer * SFSnortPacket * - packet structure * * Returns: * DCE2_RET__SUCCESS * DCE2_RET__ERROR * ********************************************************************/ static DCE2_Ret DCE2_SetSsnState(DCE2_SsnData *sd, SFSnortPacket *p) { uint32_t pkt_seq = ntohl(p->tcp_header->sequence); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_session_state); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Payload size: %u\n", p->payload_size)); if (DCE2_SsnFromClient(p) && !DCE2_SsnSeenClient(sd)) { uint32_t pkt_ack = ntohl(p->tcp_header->acknowledgement); if (DCE2_SsnSeenServer(sd) && SEQ_LT(sd->cli_seq, pkt_seq) && (sd->trans != DCE2_TRANS_TYPE__HTTP_SERVER)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Missing packets on session - aborting session inspection\n")); DCE2_SetNoInspect(sd); PREPROC_PROFILE_END(dce2_pstat_session_state); return DCE2_RET__ERROR; } DCE2_SsnSetSeenClient(sd); sd->cli_seq = pkt_seq; sd->cli_nseq = pkt_seq + p->payload_size; if (!DCE2_SsnSeenServer(sd)) sd->srv_seq = sd->srv_nseq = pkt_ack; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Initial client => seq: %u, " "next seq: %u\n", sd->cli_seq, sd->cli_nseq)); } else if (DCE2_SsnFromServer(p) && !DCE2_SsnSeenServer(sd)) { uint32_t pkt_ack = ntohl(p->tcp_header->acknowledgement); if ((DCE2_SsnSeenClient(sd) && SEQ_LT(sd->srv_seq, pkt_seq)) || (!DCE2_SsnSeenClient(sd) && (sd->trans != DCE2_TRANS_TYPE__HTTP_SERVER))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Missing packets on session - aborting session inspection\n")); PREPROC_PROFILE_END(dce2_pstat_session_state); DCE2_SetNoInspect(sd); return DCE2_RET__ERROR; } DCE2_SsnSetSeenServer(sd); sd->srv_seq = pkt_seq; sd->srv_nseq = pkt_seq + p->payload_size; if (!DCE2_SsnSeenClient(sd)) sd->cli_seq = sd->cli_nseq = pkt_ack; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Initial server => seq: %u, " "next seq: %u\n", sd->srv_seq, sd->srv_nseq)); } else { uint32_t *ssn_seq; uint32_t *ssn_nseq; if (DCE2_SsnFromClient(p)) { ssn_seq = &sd->cli_seq; ssn_nseq = &sd->cli_nseq; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Client last => seq: %u, " "next seq: %u\n", sd->cli_seq, sd->cli_nseq)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "This packet => seq: %u, " "next seq: %u\n", pkt_seq, pkt_seq + p->payload_size)); } else { ssn_seq = &sd->srv_seq; ssn_nseq = &sd->srv_nseq; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Server last => seq: %u, " "next seq: %u\n", sd->srv_seq, sd->srv_nseq)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "This packet => seq: %u, " "next seq: %u\n", pkt_seq, pkt_seq + p->payload_size)); } if (*ssn_nseq != pkt_seq) { if (SEQ_LT(*ssn_nseq, pkt_seq)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Next expected sequence number (%u) is less than " "this sequence number (%u).\n", *ssn_nseq, pkt_seq)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Missing packets on session - aborting session inspection\n")); DCE2_SetNoInspect(sd); PREPROC_PROFILE_END(dce2_pstat_session_state); return DCE2_RET__ERROR; } else { /* Got some kind of overlap. This shouldn't happen since we're doing * reassembly on both sides and not looking at non-reassembled packets * Actually this can happen if the stream seg list is empty */ DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Overlap => seq: %u, " "next seq: %u - aborting session inspection\n", pkt_seq, pkt_seq + p->payload_size)); DCE2_SetNoInspect(sd); PREPROC_PROFILE_END(dce2_pstat_session_state); return DCE2_RET__ERROR; } } *ssn_seq = pkt_seq; *ssn_nseq = pkt_seq + p->payload_size; } PREPROC_PROFILE_END(dce2_pstat_session_state); return DCE2_RET__SUCCESS; } /********************************************************************* * Function: DCE2_GetTransport() * * Determines whether or not we should look at this traffic and if * so, what transport it should be classified as. * * Arguments: * SFSnortPacket * * Pointer to packet structure. * const DCE2_ServerConfig * * The server configuration associated with the packet's IP. * int * * Pointer to a value that will be filled in with whether * or not the packet was autodetected. * Non-zero if autodetected * Zero if not autodetected * * Returns: * DCE2_TransType * DCE2_TRANS_TYPE__NONE if a transport could not be * determined or target based labeled the session as * traffic we are not interested in. * DCE2_TRANS_TYPE__SMB if the traffic is determined to be * DCE/RPC over SMB. * DCE2_TRANS_TYPE__TCP if the traffic is determined to be * DCE/RPC over TCP. * DCE2_TRANS_TYPE__UDP if the traffic is determined to be * DCE/RPC over UDP. * DCE2_TRANS_TYPE__HTTP_PROXY if the traffic is determined * to be DCE/RPC over HTTP proxy. * DCE2_TRANS_TYPE__HTTP_SERVER if the traffic is determined * to be DCE/RPC over HTTP server. * *********************************************************************/ static DCE2_TransType DCE2_GetTransport(SFSnortPacket *p, const DCE2_ServerConfig *sc, int *autodetected) { DCE2_TransType trans = DCE2_TRANS_TYPE__NONE; #ifdef TARGET_BASED int16_t proto_id = 0; #endif *autodetected = 0; #ifdef TARGET_BASED if (_dpd.isAdaptiveConfigured(_dpd.getRuntimePolicy())) { proto_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if (proto_id == SFTARGET_UNKNOWN_PROTOCOL) return DCE2_TRANS_TYPE__NONE; } if (proto_id != 0) { if (proto_id == dce2_proto_ids.dcerpc) { if (IsTCP(p)) { return DCE2_TRANS_TYPE__TCP; } else { return DCE2_TRANS_TYPE__UDP; } } else if (proto_id == dce2_proto_ids.nbss) { return DCE2_TRANS_TYPE__SMB; } } else #endif { trans = DCE2_GetDetectTransport(p, sc); if (trans == DCE2_TRANS_TYPE__NONE) { trans = DCE2_GetAutodetectTransport(p, sc); *autodetected = 1; } else if ((trans == DCE2_TRANS_TYPE__HTTP_PROXY) && (DCE2_ScAutodetectHttpProxyPorts(sc) == DCE2_CS__ENABLED)) { trans = DCE2_HttpAutodetectProxy(p); *autodetected = 1; } } return trans; } /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ static DCE2_TransType DCE2_GetDetectTransport(SFSnortPacket *p, const DCE2_ServerConfig *sc) { DCE2_TransType trans = DCE2_TRANS_TYPE__NONE; uint16_t port; if (DCE2_SsnFromServer(p)) port = p->src_port; else port = p->dst_port; /* Check our configured ports to see if we should continue processing */ if (IsTCP(p)) { if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__SMB)) trans = DCE2_TRANS_TYPE__SMB; else if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__TCP)) trans = DCE2_TRANS_TYPE__TCP; else if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__HTTP_PROXY)) trans = DCE2_TRANS_TYPE__HTTP_PROXY; else if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__HTTP_SERVER)) trans = DCE2_TRANS_TYPE__HTTP_SERVER; } else /* it's UDP */ { if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__UDP)) trans = DCE2_TRANS_TYPE__UDP; } return trans; } /********************************************************************* * Function: DCE2_GetAutodetectTransport() * * * Arguments: * * Returns: * *********************************************************************/ static DCE2_TransType DCE2_GetAutodetectTransport(SFSnortPacket *p, const DCE2_ServerConfig *sc) { DCE2_TransType trans = DCE2_TRANS_TYPE__NONE; uint16_t port; if (DCE2_SsnFromServer(p)) port = p->src_port; else port = p->dst_port; if (IsTCP(p)) { /* Look for raw DCE/RCP over TCP first, since it's * more likely not to have configured a port for this. */ if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__TCP)) { trans = DCE2_TcpAutodetect(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__HTTP_SERVER)) { trans = DCE2_HttpAutodetectServer(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__HTTP_PROXY)) { trans = DCE2_HttpAutodetectProxy(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__SMB)) { trans = DCE2_SmbAutodetect(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } } else /* it's UDP */ { if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__UDP)) { trans = DCE2_UdpAutodetect(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } } return DCE2_TRANS_TYPE__NONE; } /********************************************************************* * Function: DCE2_InitRpkts() * * Purpose: Allocate and initialize reassembly packets. * * Arguments: None * * Returns: None * *********************************************************************/ void DCE2_InitRpkts(void) { int i; dce2_pkt_stack = DCE2_CStackNew(DCE2_PKT_STACK__SIZE, NULL, DCE2_MEM_TYPE__INIT); if (dce2_pkt_stack == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for packet stack.", __FILE__, __LINE__); } for ( i = 0; i < DCE2_RPKT_TYPE__MAX; i++ ) dce2_rpkt[i] = _dpd.encodeNew(); } /********************************************************************* * Function: DCE2_GetRpkt() * * Purpose: * * Arguments: * SFSnortPacket * - pointer to packet off wire * const uint8_t * - pointer to data to attach to reassembly packet * uint16_t - length of data * * Returns: * SFSnortPacket * - pointer to reassembly packet * *********************************************************************/ SFSnortPacket * DCE2_GetRpkt(const SFSnortPacket *wire_pkt, DCE2_RpktType rpkt_type, const uint8_t *data, uint32_t data_len) { DCE2_Ret status; SFSnortPacket *rpkt; uint16_t payload_len = 0; uint16_t data_overhead = 0; rpkt = dce2_rpkt[rpkt_type]; switch (rpkt_type) { case DCE2_RPKT_TYPE__SMB_SEG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_SMB_SEG); break; case DCE2_RPKT_TYPE__SMB_TRANS: // TBD these memset()s could be encapsulated by the various // init functions which should also return the data_overhead. // Better still pass in rpkt and let the init function update // payload, etc. Also, some memsets could probably be avoided // by explicitly setting the unitialized header fields. _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_SMB_TRANS); if (DCE2_SsnFromClient(wire_pkt)) { data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_CLIENT); } else { data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_SERVER); } break; case DCE2_RPKT_TYPE__SMB_CO_SEG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_SEG); if (DCE2_SsnFromClient(wire_pkt)) { data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_CLIENT); } else { data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_SERVER); } break; case DCE2_RPKT_TYPE__SMB_CO_FRAG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_FRAG); if (DCE2_SsnFromClient(wire_pkt)) { data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_CLIENT); DCE2_CoInitRdata((uint8_t *)rpkt->payload + DCE2_MOCK_HDR_LEN__SMB_CLI, FLAG_FROM_CLIENT); } else { data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_SERVER); DCE2_CoInitRdata((uint8_t *)rpkt->payload + DCE2_MOCK_HDR_LEN__SMB_SRV, FLAG_FROM_SERVER); } break; case DCE2_RPKT_TYPE__TCP_CO_SEG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_SEG); break; case DCE2_RPKT_TYPE__TCP_CO_FRAG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_FRAG); if (DCE2_SsnFromClient(wire_pkt)) { data_overhead = DCE2_MOCK_HDR_LEN__CO_CLI; memset((void*)rpkt->payload, 0, data_overhead); DCE2_CoInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_CLIENT); } else { data_overhead = DCE2_MOCK_HDR_LEN__CO_SRV; memset((void*)rpkt->payload, 0, data_overhead); DCE2_CoInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_SERVER); } break; case DCE2_RPKT_TYPE__UDP_CL_FRAG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_FRAG); data_overhead = DCE2_MOCK_HDR_LEN__CL; memset((void*)rpkt->payload, 0, data_overhead); DCE2_ClInitRdata((uint8_t *)rpkt->payload); break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid reassembly packet type: %d", __FILE__, __LINE__, rpkt_type); return NULL; } payload_len = rpkt->max_payload; if ((data_overhead + data_len) > payload_len) data_len -= (data_overhead + data_len) - payload_len; status = DCE2_Memcpy( (void *)(rpkt->payload + data_overhead), (void *)data, (size_t)data_len, (void *)rpkt->payload, (void *)((uint8_t *)rpkt->payload + payload_len)); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into reassembly packet.", __FILE__, __LINE__); return NULL; } rpkt->payload_size = (uint16_t)(data_overhead + data_len); _dpd.encodeUpdate(rpkt); if (wire_pkt->family == AF_INET) { rpkt->ip4h->ip_len = rpkt->ip4_header->data_length; } else { IP6RawHdr* ip6h = (IP6RawHdr*)rpkt->raw_ip6_header; if ( ip6h ) rpkt->ip6h->len = ip6h->ip6_payload_len; } rpkt->flags |= FLAG_STREAM_EST; if (DCE2_SsnFromClient(wire_pkt)) rpkt->flags |= FLAG_FROM_CLIENT; else rpkt->flags |= FLAG_FROM_SERVER; rpkt->stream_session_ptr = wire_pkt->stream_session_ptr; return rpkt; } /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ DCE2_Ret DCE2_AddDataToRpkt(SFSnortPacket *rpkt, DCE2_RpktType rtype, const uint8_t *data, uint32_t data_len) { int hdr_overhead = 0; const uint8_t *pkt_data_end; const uint8_t *payload_end; DCE2_Ret status; if ((rpkt == NULL) || (data == NULL) || (data_len == 0)) return DCE2_RET__ERROR; if (rpkt->payload == NULL) return DCE2_RET__ERROR; /* This is a check to make sure we don't overwrite header data */ switch (rtype) { case DCE2_RPKT_TYPE__SMB_CO_SEG: if (DCE2_SsnFromClient(rpkt)) hdr_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI; else hdr_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV; break; case DCE2_RPKT_TYPE__SMB_CO_FRAG: if (DCE2_SsnFromClient(rpkt)) hdr_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI; else hdr_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV; break; case DCE2_RPKT_TYPE__TCP_CO_FRAG: if (DCE2_SsnFromClient(rpkt)) hdr_overhead = DCE2_MOCK_HDR_LEN__CO_CLI; else hdr_overhead = DCE2_MOCK_HDR_LEN__CO_SRV; break; case DCE2_RPKT_TYPE__UDP_CL_FRAG: hdr_overhead = DCE2_MOCK_HDR_LEN__CL; break; default: break; } if (rpkt->payload_size < hdr_overhead) return DCE2_RET__ERROR; pkt_data_end = rpkt->pkt_data + rpkt->max_payload; payload_end = rpkt->payload + rpkt->payload_size; if ((payload_end + data_len) > pkt_data_end) data_len = pkt_data_end - payload_end; status = DCE2_Memcpy((void *)payload_end, (void *)data, (size_t)data_len, (void *)payload_end, (void *)pkt_data_end); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into reassembly packet.", __FILE__, __LINE__); return DCE2_RET__ERROR; } rpkt->payload_size += (uint16_t)data_len; // there is room for optimization here since the update was done // earlier - that my be eliminated, but only in this case one // approach is to move the updates to push pkt - but don't want // to update non-dce2 pseudo pkts; perhaps a flag check there // will suffice. _dpd.encodeUpdate(rpkt); if (rpkt->family == AF_INET) { rpkt->ip4h->ip_len = rpkt->ip4_header->data_length; } else { IP6RawHdr* ip6h = (IP6RawHdr*)rpkt->raw_ip6_header; if ( ip6h ) rpkt->ip6h->len = ip6h->ip6_payload_len; } return DCE2_RET__SUCCESS; } /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ DCE2_Ret DCE2_PushPkt(SFSnortPacket *p) { SFSnortPacket *top_pkt = (SFSnortPacket *)DCE2_CStackTop(dce2_pkt_stack); if (top_pkt != NULL) { PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_log); _dpd.pushAlerts(); _dpd.logAlerts((void *)top_pkt); _dpd.resetAlerts(); _dpd.popAlerts(); PREPROC_PROFILE_END(dce2_pstat_log); } if (DCE2_CStackPush(dce2_pkt_stack, (void *)p) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; return DCE2_RET__SUCCESS; } /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ void DCE2_PopPkt(void) { SFSnortPacket *pop_pkt = (SFSnortPacket *)DCE2_CStackPop(dce2_pkt_stack); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_log); if (pop_pkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) No packet to pop off stack.", __FILE__, __LINE__); PREPROC_PROFILE_END(dce2_pstat_log); return; } _dpd.pushAlerts(); _dpd.logAlerts((void *)pop_pkt); _dpd.resetAlerts(); _dpd.popAlerts(); PREPROC_PROFILE_END(dce2_pstat_log); } /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ void DCE2_Detect(DCE2_SsnData *sd) { SFSnortPacket *top_pkt = (SFSnortPacket *)DCE2_CStackTop(dce2_pkt_stack); PROFILE_VARS; if (top_pkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) No packet on top of stack.", __FILE__, __LINE__); return; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Detecting ------------------------------------------------\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, " Rule options:\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__ROPTIONS, DCE2_PrintRoptions(&sd->ropts);); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Payload:\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(top_pkt->payload, top_pkt->payload_size);); DCE2_DEBUG_CODE(DCE2_DEBUG__ROPTIONS, if (sd->ropts.stub_data != NULL) { printf("\nStub data:\n"); DCE2_PrintPktData(sd->ropts.stub_data, top_pkt->payload_size - (sd->ropts.stub_data - top_pkt->payload)); }); PREPROC_PROFILE_START(dce2_pstat_detect); _dpd.pushAlerts(); _dpd.detect(top_pkt); _dpd.popAlerts(); PREPROC_PROFILE_END(dce2_pstat_detect); /* Always reset rule option data after detecting */ DCE2_ResetRopts(&sd->ropts); dce2_detected = 1; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "----------------------------------------------------------\n")); } void DCE2_FileDetect(DCE2_SsnData *sd) { SFSnortPacket *top_pkt = (SFSnortPacket *)DCE2_CStackTop(dce2_pkt_stack); PROFILE_VARS; if (top_pkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) No packet on top of stack.", __FILE__, __LINE__); return; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Detecting ------------------------------------------------\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Payload:\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(top_pkt->payload, top_pkt->payload_size);); PREPROC_PROFILE_START(dce2_pstat_smb_file_detect); _dpd.pushAlerts(); _dpd.detect(top_pkt); _dpd.popAlerts(); PREPROC_PROFILE_END(dce2_pstat_smb_file_detect); // Reset file data pointer after detecting _dpd.setFileDataPtr(NULL, 0); dce2_detected = 1; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "----------------------------------------------------------\n")); } /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ // TBD this function could be called on the actual rpkt // to very easily get the exact available payload space and // then truncate the data as needed. That avoids the calculations // here which inevitably include tacit assumptions about the // rpkt which may not be true (nor future proof). uint16_t DCE2_GetRpktMaxData(DCE2_SsnData *sd, DCE2_RpktType rtype) { const SFSnortPacket *p = sd->wire_pkt; uint16_t overhead; uint8_t* base, *last; int n = p->next_layer_index - 1; if ( n < 2 ) return 0; base = p->proto_layers[1].proto_start; last = p->proto_layers[n].proto_start + p->proto_layers[n].proto_length; overhead = last - base; switch (rtype) { case DCE2_RPKT_TYPE__SMB_SEG: case DCE2_RPKT_TYPE__SMB_TRANS: break; case DCE2_RPKT_TYPE__SMB_CO_SEG: if (DCE2_SsnFromClient(p)) overhead += DCE2_MOCK_HDR_LEN__SMB_CLI; else overhead += DCE2_MOCK_HDR_LEN__SMB_SRV; break; case DCE2_RPKT_TYPE__SMB_CO_FRAG: if (DCE2_SsnFromClient(p)) overhead += DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI; else overhead += DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV; break; case DCE2_RPKT_TYPE__TCP_CO_SEG: break; case DCE2_RPKT_TYPE__TCP_CO_FRAG: if (DCE2_SsnFromClient(p)) overhead += DCE2_MOCK_HDR_LEN__CO_CLI; else overhead += DCE2_MOCK_HDR_LEN__CO_SRV; break; case DCE2_RPKT_TYPE__UDP_CL_FRAG: overhead += DCE2_MOCK_HDR_LEN__CL; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid reassembly packet type: %d", __FILE__, __LINE__, rtype); return 0; } return (IP_MAXPKT - overhead); } /****************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ******************************************************************/ void DCE2_FreeGlobals(void) { int i; if (dce2_pkt_stack != NULL) { DCE2_CStackDestroy(dce2_pkt_stack); dce2_pkt_stack = NULL; } for ( i = 0; i < DCE2_RPKT_TYPE__MAX; i++ ) { if ( dce2_rpkt[i] != NULL ) { _dpd.encodeDelete(dce2_rpkt[i]); dce2_rpkt[i] = NULL; } } DCE2_EventsFree(); } static void DCE2_SsnFree(void *data) { DCE2_SsnData *sd = (DCE2_SsnData *)data; #ifdef SNORT_RELOAD DCE2_Config *pPolicyConfig; tSfPolicyUserContextId config; tSfPolicyId policy_id; #endif if (sd == NULL) return; #ifdef SNORT_RELOAD config = sd->config; policy_id = sd->policy_id; #endif switch (sd->trans) { case DCE2_TRANS_TYPE__SMB: DCE2_SmbSsnFree((DCE2_SmbSsnData *)sd); break; case DCE2_TRANS_TYPE__TCP: DCE2_TcpSsnFree((DCE2_TcpSsnData *)sd); break; case DCE2_TRANS_TYPE__UDP: DCE2_UdpSsnFree((DCE2_UdpSsnData *)sd); break; case DCE2_TRANS_TYPE__HTTP_SERVER: case DCE2_TRANS_TYPE__HTTP_PROXY: DCE2_HttpSsnFree((DCE2_HttpSsnData *)sd); break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, sd->trans); return; } #ifdef SNORT_RELOAD pPolicyConfig = (DCE2_Config *)sfPolicyUserDataGet(config, policy_id); if (pPolicyConfig != NULL) { pPolicyConfig->ref_count--; if ((pPolicyConfig->ref_count == 0) && (config != dce2_config)) { sfPolicyUserDataClear (config, policy_id); DCE2_FreeConfig(pPolicyConfig); /* No more outstanding policies for this config */ if (sfPolicyUserPolicyGetActive(config) == 0) DCE2_FreeConfigs(config); } } #endif } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/spp_dce2.h0000644000000000000000000000446012260565732020252 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef SPP_DCE2_H #define SPP_DCE2_H /******************************************************************** * Externs ********************************************************************/ #ifdef PERF_PROFILING #include "profiler.h" extern PreprocStats dce2_pstat_main; extern PreprocStats dce2_pstat_session; extern PreprocStats dce2_pstat_new_session; extern PreprocStats dce2_pstat_session_state; extern PreprocStats dce2_pstat_detect; extern PreprocStats dce2_pstat_log; extern PreprocStats dce2_pstat_smb_seg; extern PreprocStats dce2_pstat_smb_req; extern PreprocStats dce2_pstat_smb_uid; extern PreprocStats dce2_pstat_smb_tid; extern PreprocStats dce2_pstat_smb_fid; extern PreprocStats dce2_pstat_smb_file; extern PreprocStats dce2_pstat_smb_file_detect; extern PreprocStats dce2_pstat_smb_file_api; extern PreprocStats dce2_pstat_smb_fingerprint; extern PreprocStats dce2_pstat_smb_negotiate; extern PreprocStats dce2_pstat_co_seg; extern PreprocStats dce2_pstat_co_frag; extern PreprocStats dce2_pstat_co_reass; extern PreprocStats dce2_pstat_co_ctx; extern PreprocStats dce2_pstat_cl_acts; extern PreprocStats dce2_pstat_cl_frag; extern PreprocStats dce2_pstat_cl_reass; #endif #endif /* SPP_DCE2_H */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/spp_dce2.c0000644000000000000000000014605012260565732020247 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "sf_types.h" #include "spp_dce2.h" #include "sf_preproc_info.h" #include "dce2_memory.h" #include "dce2_list.h" #include "dce2_utils.h" #include "dce2_config.h" #include "dce2_roptions.h" #include "dce2_stats.h" #include "dce2_event.h" #include "dce2_paf.h" #include "dce2_smb.h" #include "snort_dce2.h" #include "preprocids.h" #include "profiler.h" #include "sfrt.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "stream_api.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #ifdef DCE2_LOG_EXTRA_DATA #include "Unified2_common.h" #endif /******************************************************************** * Global variables ********************************************************************/ #ifdef PERF_PROFILING PreprocStats dce2_pstat_main; PreprocStats dce2_pstat_session; PreprocStats dce2_pstat_new_session; PreprocStats dce2_pstat_session_state; PreprocStats dce2_pstat_detect; PreprocStats dce2_pstat_log; PreprocStats dce2_pstat_smb_seg; PreprocStats dce2_pstat_smb_req; PreprocStats dce2_pstat_smb_uid; PreprocStats dce2_pstat_smb_tid; PreprocStats dce2_pstat_smb_fid; PreprocStats dce2_pstat_smb_file; PreprocStats dce2_pstat_smb_file_detect; PreprocStats dce2_pstat_smb_file_api; PreprocStats dce2_pstat_smb_fingerprint; PreprocStats dce2_pstat_smb_negotiate; PreprocStats dce2_pstat_co_seg; PreprocStats dce2_pstat_co_frag; PreprocStats dce2_pstat_co_reass; PreprocStats dce2_pstat_co_ctx; PreprocStats dce2_pstat_cl_acts; PreprocStats dce2_pstat_cl_frag; PreprocStats dce2_pstat_cl_reass; #endif const int MAJOR_VERSION = 1; const int MINOR_VERSION = 0; const int BUILD_VERSION = 3; const char *PREPROC_NAME = "SF_DCERPC2"; #define DCE2_RegisterPreprocessor DYNAMIC_PREPROC_SETUP /******************************************************************** * Macros ********************************************************************/ #ifdef PERF_PROFILING #define DCE2_PSTAT__MAIN "DceRpcMain" #define DCE2_PSTAT__SESSION "DceRpcSession" #define DCE2_PSTAT__NEW_SESSION "DceRpcNewSession" #define DCE2_PSTAT__SSN_STATE "DceRpcSessionState" #define DCE2_PSTAT__DETECT "DceRpcDetect" #define DCE2_PSTAT__LOG "DceRpcLog" #define DCE2_PSTAT__SMB_SEG "DceRpcSmbSeg" #define DCE2_PSTAT__SMB_REQ "DceRpcSmbReq" #define DCE2_PSTAT__SMB_UID "DceRpcSmbUid" #define DCE2_PSTAT__SMB_TID "DceRpcSmbTid" #define DCE2_PSTAT__SMB_FID "DceRpcSmbFid" #define DCE2_PSTAT__SMB_FILE "DceRpcSmbFile" #define DCE2_PSTAT__SMB_FILE_DETECT "DceRpcSmbFileDetect" #define DCE2_PSTAT__SMB_FILE_API "DceRpcSmbFileAPI" #define DCE2_PSTAT__SMB_FP "DceRpcSmbFingerprint" #define DCE2_PSTAT__SMB_NEG "DceRpcSmbNegotiate" #define DCE2_PSTAT__CO_SEG "DceRpcCoSeg" #define DCE2_PSTAT__CO_FRAG "DceRpcCoFrag" #define DCE2_PSTAT__CO_REASS "DceRpcCoReass" #define DCE2_PSTAT__CO_CTX "DceRpcCoCtx" #define DCE2_PSTAT__CL_ACTS "DceRpcClActs" #define DCE2_PSTAT__CL_FRAG "DceRpcClFrag" #define DCE2_PSTAT__CL_REASS "DceRpcClReass" #endif /* PERF_PROFILING */ /******************************************************************** * Private function prototypes ********************************************************************/ static void DCE2_InitGlobal(struct _SnortConfig *, char *); static void DCE2_InitServer(struct _SnortConfig *, char *); static int DCE2_CheckConfig(struct _SnortConfig *); static void DCE2_Main(void *, void *); static void DCE2_PrintStats(int); static void DCE2_Reset(int, void *); static void DCE2_ResetStats(int, void *); static void DCE2_CleanExit(int, void *); #ifdef DCE2_LOG_EXTRA_DATA static int DCE2_LogSmbFileName(void *, uint8_t **, uint32_t *, uint32_t *); #endif #ifdef SNORT_RELOAD static void DCE2_ReloadGlobal(struct _SnortConfig *, char *, void **); static void DCE2_ReloadServer(struct _SnortConfig *, char *, void **); static int DCE2_ReloadVerify(struct _SnortConfig *, void *); static void * DCE2_ReloadSwap(struct _SnortConfig *, void *); static void DCE2_ReloadSwapFree(void *); #endif static void DCE2_AddPortsToPaf(struct _SnortConfig *, DCE2_Config *, tSfPolicyId); static void DCE2_ScAddPortsToPaf(struct _SnortConfig *, void *); /******************************************************************** * Function: DCE2_RegisterPreprocessor() * * Purpose: Registers the DCE/RPC preprocessor with Snort * * Arguments: None * * Returns: None * ********************************************************************/ void DCE2_RegisterPreprocessor(void) { #ifndef SNORT_RELOAD _dpd.registerPreproc(DCE2_GNAME, DCE2_InitGlobal); _dpd.registerPreproc(DCE2_SNAME, DCE2_InitServer); #else _dpd.registerPreproc(DCE2_GNAME, DCE2_InitGlobal, DCE2_ReloadGlobal, DCE2_ReloadVerify, DCE2_ReloadSwap, DCE2_ReloadSwapFree); _dpd.registerPreproc(DCE2_SNAME, DCE2_InitServer, DCE2_ReloadServer, NULL, NULL, NULL); #endif } /********************************************************************* * Function: DCE2_InitGlobal() * * Purpose: Initializes the global DCE/RPC preprocessor config. * * Arguments: snort.conf argument line for the DCE/RPC preprocessor. * * Returns: None * *********************************************************************/ static void DCE2_InitGlobal(struct _SnortConfig *sc, char *args) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); DCE2_Config *pDefaultPolicyConfig = NULL; DCE2_Config *pCurrentPolicyConfig = NULL; if ((_dpd.streamAPI == NULL) || (_dpd.streamAPI->version != STREAM_API_VERSION5)) { DCE2_Die("%s(%d) \"%s\" configuration: " "Stream5 must be enabled with TCP and UDP tracking.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } if (dce2_config == NULL) { dce2_config = sfPolicyConfigCreate(); if (dce2_config == NULL) { DCE2_Die("%s(%d) \"%s\" configuration: Could not allocate memory " "configuration.\n", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } DCE2_MemInit(); DCE2_StatsInit(); DCE2_EventsInit(); smb_file_name[0] = '\0'; /* Initialize reassembly packet */ DCE2_InitRpkts(); #ifdef ACTIVE_RESPONSE DCE2_SmbInitDeletePdu(); #endif DCE2_SmbInitGlobals(); _dpd.addPreprocConfCheck(sc, DCE2_CheckConfig); _dpd.registerPreprocStats(DCE2_GNAME, DCE2_PrintStats); _dpd.addPreprocReset(DCE2_Reset, NULL, PRIORITY_LAST, PP_DCE2); _dpd.addPreprocResetStats(DCE2_ResetStats, NULL, PRIORITY_LAST, PP_DCE2); _dpd.addPreprocExit(DCE2_CleanExit, NULL, PRIORITY_LAST, PP_DCE2); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc(DCE2_PSTAT__MAIN, &dce2_pstat_main, 0, _dpd.totalPerfStats); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SESSION, &dce2_pstat_session, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__NEW_SESSION, &dce2_pstat_new_session, 2, &dce2_pstat_session); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SSN_STATE, &dce2_pstat_session_state, 2, &dce2_pstat_session); _dpd.addPreprocProfileFunc(DCE2_PSTAT__LOG, &dce2_pstat_log, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__DETECT, &dce2_pstat_detect, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_SEG, &dce2_pstat_smb_seg, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_REQ, &dce2_pstat_smb_req, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_UID, &dce2_pstat_smb_uid, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_TID, &dce2_pstat_smb_tid, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_FID, &dce2_pstat_smb_fid, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_FILE, &dce2_pstat_smb_file, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_FILE_DETECT, &dce2_pstat_smb_file_detect, 2, &dce2_pstat_smb_file); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_FILE_API, &dce2_pstat_smb_file_api, 2, &dce2_pstat_smb_file); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_FP, &dce2_pstat_smb_fingerprint, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__SMB_NEG, &dce2_pstat_smb_negotiate, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CO_SEG, &dce2_pstat_co_seg, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CO_FRAG, &dce2_pstat_co_frag, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CO_REASS, &dce2_pstat_co_reass, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CO_CTX, &dce2_pstat_co_ctx, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CL_ACTS, &dce2_pstat_cl_acts, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CL_FRAG, &dce2_pstat_cl_frag, 1, &dce2_pstat_main); _dpd.addPreprocProfileFunc(DCE2_PSTAT__CL_REASS, &dce2_pstat_cl_reass, 1, &dce2_pstat_main); #endif #ifdef TARGET_BASED dce2_proto_ids.dcerpc = _dpd.findProtocolReference(DCE2_PROTO_REF_STR__DCERPC); if (dce2_proto_ids.dcerpc == SFTARGET_UNKNOWN_PROTOCOL) dce2_proto_ids.dcerpc = _dpd.addProtocolReference(DCE2_PROTO_REF_STR__DCERPC); /* smb and netbios-ssn refer to the same thing */ dce2_proto_ids.nbss = _dpd.findProtocolReference(DCE2_PROTO_REF_STR__NBSS); if (dce2_proto_ids.nbss == SFTARGET_UNKNOWN_PROTOCOL) dce2_proto_ids.nbss = _dpd.addProtocolReference(DCE2_PROTO_REF_STR__NBSS); #endif } sfPolicyUserPolicySet(dce2_config, policy_id); pDefaultPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetDefault(dce2_config); pCurrentPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetCurrent(dce2_config); if ((policy_id != 0) && (pDefaultPolicyConfig == NULL)) { DCE2_Die("%s(%d) \"%s\" configuration: Must configure default policy " "if other policies are to be configured.\n", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } /* Can only do one global configuration */ if (pCurrentPolicyConfig != NULL) { DCE2_Die("%s(%d) \"%s\" configuration: Only one global configuration can be specified.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } DCE2_RegRuleOptions(sc); pCurrentPolicyConfig = (DCE2_Config *)DCE2_Alloc(sizeof(DCE2_Config), DCE2_MEM_TYPE__CONFIG); sfPolicyUserDataSetCurrent(dce2_config, pCurrentPolicyConfig); /* Parse configuration args */ DCE2_GlobalConfigure(pCurrentPolicyConfig, args); if (policy_id != 0) pCurrentPolicyConfig->gconfig->memcap = pDefaultPolicyConfig->gconfig->memcap; if ( pCurrentPolicyConfig->gconfig->disabled ) return; /* Register callbacks */ _dpd.addPreproc(sc, DCE2_Main, PRIORITY_APPLICATION, PP_DCE2, PROTO_BIT__TCP | PROTO_BIT__UDP); #ifdef TARGET_BASED _dpd.streamAPI->set_service_filter_status (sc, dce2_proto_ids.dcerpc, PORT_MONITOR_SESSION, policy_id, 1); _dpd.streamAPI->set_service_filter_status (sc, dce2_proto_ids.nbss, PORT_MONITOR_SESSION, policy_id, 1); #endif } /********************************************************************* * Function: DCE2_InitServer() * * Purpose: Initializes a DCE/RPC server configuration * * Arguments: snort.conf argument line for the DCE/RPC preprocessor. * * Returns: None * *********************************************************************/ static void DCE2_InitServer(struct _SnortConfig *sc, char *args) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); DCE2_Config *pPolicyConfig = NULL; if (dce2_config != NULL) { sfPolicyUserPolicySet (dce2_config, policy_id); pPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetCurrent(dce2_config); } if ((dce2_config == NULL) || (pPolicyConfig == NULL) || (pPolicyConfig->gconfig == NULL)) { DCE2_Die("%s(%d) \"%s\" configuration: \"%s\" must be configured " "before \"%s\".", *_dpd.config_file, *_dpd.config_line, DCE2_SNAME, DCE2_GNAME, DCE2_SNAME); } /* Parse configuration args */ DCE2_ServerConfigure(sc, pPolicyConfig, args); } static int DCE2_CheckConfigPolicy( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { int rval; DCE2_Config *pPolicyConfig = (DCE2_Config *)pData; DCE2_ServerConfig *dconfig; if ( pPolicyConfig->gconfig->disabled ) return 0; _dpd.setParserPolicy(sc, policyId); // config_file/config_line are not set here if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { DCE2_Log(DCE2_LOG_TYPE__WARN, "Stream5 must be enabled with TCP and UDP tracking."); return -1; } dconfig = pPolicyConfig->dconfig; if (dconfig == NULL) { if ((rval = DCE2_CreateDefaultServerConfig(sc, pPolicyConfig, policyId))) return rval; } #ifdef TARGET_BASED if (!_dpd.isAdaptiveConfiguredForSnortConfig(sc, policyId)) #endif { if ((rval = DCE2_ScCheckTransports(pPolicyConfig))) return rval; } DCE2_AddPortsToPaf(sc, pPolicyConfig, policyId); #ifdef TARGET_BASED DCE2_PafRegisterService(sc, dce2_proto_ids.nbss, policyId, DCE2_TRANS_TYPE__SMB); DCE2_PafRegisterService(sc, dce2_proto_ids.dcerpc, policyId, DCE2_TRANS_TYPE__TCP); #endif #ifdef DCE2_LOG_EXTRA_DATA pPolicyConfig->xtra_logging_smb_file_name_id = _dpd.streamAPI->reg_xtra_data_cb(DCE2_LogSmbFileName); #endif /* Register routing table memory */ if (pPolicyConfig->sconfigs != NULL) DCE2_RegMem(sfrt_usage(pPolicyConfig->sconfigs), DCE2_MEM_TYPE__RT); return 0; } /********************************************************************* * Function: DCE2_CheckConfig() * * Purpose: Verifies the DCE/RPC preprocessor configuration * * Arguments: None * * Returns: None * *********************************************************************/ static int DCE2_CheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate (sc, dce2_config, DCE2_CheckConfigPolicy))) { return rval; } return 0; } /********************************************************************* * Function: DCE2_Main() * * Purpose: Main entry point for DCE/RPC processing. * * Arguments: * void * - pointer to packet structure * void * - pointer to context * * Returns: None * *********************************************************************/ static void DCE2_Main(void *pkt, void *context) { SFSnortPacket *p = (SFSnortPacket *)pkt; PROFILE_VARS; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__START_MSG)); sfPolicyUserPolicySet (dce2_config, _dpd.getRuntimePolicy()); #ifdef DEBUG_MSGS if (DCE2_SsnFromServer(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Packet from Server.\n")); } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Packet from Client.\n")); } #endif // preconditions - what we registered for assert((IsUDP(p) || IsTCP(p)) && p->payload && p->payload_size); /* No inspection to do */ if (p->stream_session_ptr == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "No session pointer - not inspecting.\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); return; } if (IsTCP(p)) { if (DCE2_SsnIsMidstream(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Midstream - not inspecting.\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); return; } else if (!DCE2_SsnIsEstablished(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Not established - not inspecting.\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); return; } } PREPROC_PROFILE_START(dce2_pstat_main); if (DCE2_Process(p) == DCE2_RET__INSPECTED) DCE2_DisableDetect(p); PREPROC_PROFILE_END(dce2_pstat_main); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); } #ifdef DCE2_LOG_EXTRA_DATA /****************************************************************** * Function: DCE2_LogSmbFileName * * Purpose: Callback for unified2 logging of extra data, in this * case the SMB file name. * * Arguments: * void * - stream session pointer * uint8_t ** - pointer to buffer for extra data * uint32_t * - pointer to length of extra data * uint32_t * - pointer to type of extra data * * Returns: * int - 1 for success * 0 for failure * ******************************************************************/ static int DCE2_LogSmbFileName(void *ssn_ptr, uint8_t **buf, uint32_t *len, uint32_t *type) { if ((_dpd.streamAPI->get_application_data(ssn_ptr, PP_DCE2) == NULL) || (strlen(smb_file_name) == 0)) return 0; *buf = (uint8_t *)smb_file_name; *len = strlen(smb_file_name); *type = EVENT_INFO_SMB_FILENAME; return 1; } #endif /****************************************************************** * Function: DCE2_PrintStats() * * Purpose: Print statistics being kept by the preprocessor. * * Arguments: * int - whether Snort is exiting or not * * Returns: None * ******************************************************************/ static void DCE2_PrintStats(int exiting) { int smb_com; int sub_com; _dpd.logMsg("dcerpc2 Preprocessor Statistics\n"); _dpd.logMsg(" Total sessions: "STDu64"\n", dce2_stats.sessions); if (dce2_stats.sessions > 0) { if (dce2_stats.sessions_autodetected > 0) _dpd.logMsg(" Total sessions autodetected: "STDu64"\n", dce2_stats.sessions_autodetected); if (dce2_stats.sessions_aborted > 0) _dpd.logMsg(" Total sessions aborted: "STDu64"\n", dce2_stats.sessions_aborted); if (dce2_stats.bad_autodetects > 0) _dpd.logMsg(" Bad autodetects: "STDu64"\n", dce2_stats.bad_autodetects); if (dce2_stats.events > 0) _dpd.logMsg(" Preprocessor events: "STDu64"\n", dce2_stats.events); #ifdef DEBUG { unsigned int port; int first = 1; for (port = 0; port < (sizeof(dce2_stats.autoports) / sizeof(dce2_stats.autoports[0])); port++) { DCE2_TransType ttype; for (ttype = DCE2_TRANS_TYPE__NONE; ttype < DCE2_TRANS_TYPE__MAX; ttype++) { if ((dce2_stats.autoports[port][ttype] > 0) && (dce2_trans_strs[ttype] != NULL)) { if (first) { _dpd.logMsg("\n"); _dpd.logMsg(" Autodetected ports:\n"); _dpd.logMsg(" %7s%15s%15s\n", "Port", "Transport", "Total"); first = 0; } _dpd.logMsg(" %7u%15s"FMTu64("15")"\n", port, dce2_trans_strs[ttype], dce2_stats.autoports[port][ttype]); } } } } #endif _dpd.logMsg("\n"); _dpd.logMsg(" Transports\n"); if (dce2_stats.smb_sessions > 0) { _dpd.logMsg(" SMB\n"); _dpd.logMsg(" Total sessions: "STDu64"\n", dce2_stats.smb_sessions); _dpd.logMsg(" Packet stats\n"); _dpd.logMsg(" Packets: "STDu64"\n", dce2_stats.smb_pkts); if (dce2_stats.smb_ignored_bytes > 0) _dpd.logMsg(" Ignored bytes: "STDu64"\n", dce2_stats.smb_ignored_bytes); if (dce2_stats.smb_files_processed > 0) _dpd.logMsg(" Files processed: "STDu64"\n", dce2_stats.smb_files_processed); if (dce2_stats.smb_cli_seg_reassembled > 0) _dpd.logMsg(" Client TCP reassembled: "STDu64"\n", dce2_stats.smb_cli_seg_reassembled); if (dce2_stats.smb_srv_seg_reassembled > 0) _dpd.logMsg(" Server TCP reassembled: "STDu64"\n", dce2_stats.smb_srv_seg_reassembled); _dpd.logMsg(" Maximum outstanding requests: "STDu64"\n", dce2_stats.smb_max_outstanding_requests); // SMB command stats _dpd.logMsg(" SMB command requests/responses processed\n"); for (smb_com = 0; smb_com < SMB_MAX_NUM_COMS; smb_com++) { SmbAndXCom andx = smb_chain_map[smb_com]; // Print out the stats for command requests if ((dce2_stats.smb_com_stats[SMB_TYPE__REQUEST][smb_com] != 0) || (dce2_stats.smb_com_stats[SMB_TYPE__RESPONSE][smb_com] != 0)) { _dpd.logMsg(" %s (0x%02X) : "STDu64"/"STDu64"\n", smb_com_strings[smb_com], smb_com, dce2_stats.smb_com_stats[SMB_TYPE__REQUEST][smb_com], dce2_stats.smb_com_stats[SMB_TYPE__RESPONSE][smb_com]); switch (smb_com) { case SMB_COM_TRANSACTION: for (sub_com = 0; sub_com < TRANS_SUBCOM_MAX+1; sub_com++) { if ((dce2_stats.smb_trans_subcom_stats[SMB_TYPE__REQUEST][sub_com] != 0) || (dce2_stats.smb_trans_subcom_stats[SMB_TYPE__RESPONSE][sub_com] != 0)) { _dpd.logMsg(" %s (0x%04X) : "STDu64"/"STDu64"\n", (sub_com < TRANS_SUBCOM_MAX) ? smb_transaction_sub_command_strings[sub_com] : "Unknown", sub_com, dce2_stats.smb_trans_subcom_stats[SMB_TYPE__REQUEST][sub_com], dce2_stats.smb_trans_subcom_stats[SMB_TYPE__RESPONSE][sub_com]); } } break; case SMB_COM_TRANSACTION2: for (sub_com = 0; sub_com < TRANS2_SUBCOM_MAX+1; sub_com++) { if ((dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__REQUEST][sub_com] != 0) || (dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__RESPONSE][sub_com] != 0)) { _dpd.logMsg(" %s (0x%04X) : "STDu64"/"STDu64"\n", (sub_com < TRANS2_SUBCOM_MAX) ? smb_transaction2_sub_command_strings[sub_com] : "Unknown", sub_com, dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__REQUEST][sub_com], dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__RESPONSE][sub_com]); } } break; case SMB_COM_NT_TRANSACT: for (sub_com = 0; sub_com < NT_TRANSACT_SUBCOM_MAX+1; sub_com++) { if ((dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__REQUEST][sub_com] != 0) || (dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__RESPONSE][sub_com] != 0)) { _dpd.logMsg(" %s (0x%04X) : "STDu64"/"STDu64"\n", (sub_com < NT_TRANSACT_SUBCOM_MAX) ? smb_nt_transact_sub_command_strings[sub_com] : "Unknown", sub_com, dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__REQUEST][sub_com], dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__RESPONSE][sub_com]); } } break; default: break; } } // Print out chaining stats for AndX command requests if (andx != SMB_ANDX_COM__NONE) { int chained_com; for (chained_com = 0; chained_com < SMB_MAX_NUM_COMS; chained_com++) { if ((dce2_stats.smb_chained_stats[SMB_TYPE__REQUEST][andx][chained_com] != 0) || (dce2_stats.smb_chained_stats[SMB_TYPE__RESPONSE][andx][chained_com] != 0)) { _dpd.logMsg(" => %s (0x%02X) : "STDu64"/"STDu64"\n", smb_com_strings[chained_com], chained_com, dce2_stats.smb_chained_stats[SMB_TYPE__REQUEST][andx][chained_com], dce2_stats.smb_chained_stats[SMB_TYPE__RESPONSE][andx][chained_com]); } } } } #ifdef DEBUG_MSGS _dpd.logMsg(" Memory stats (bytes)\n"); _dpd.logMsg(" Current total: %u\n", dce2_memory.smb_total); _dpd.logMsg(" Maximum total: %u\n", dce2_memory.smb_total_max); _dpd.logMsg(" Current session data: %u\n", dce2_memory.smb_ssn); _dpd.logMsg(" Maximum session data: %u\n", dce2_memory.smb_ssn_max); _dpd.logMsg(" Current segmentation buffering: %u\n", dce2_memory.smb_seg); _dpd.logMsg(" Maximum segmentation buffering: %u\n", dce2_memory.smb_seg_max); _dpd.logMsg(" Current uid tracking: %u\n", dce2_memory.smb_uid); _dpd.logMsg(" Maximum uid tracking: %u\n", dce2_memory.smb_uid_max); _dpd.logMsg(" Current tid tracking: %u\n", dce2_memory.smb_tid); _dpd.logMsg(" Maximum tid tracking: %u\n", dce2_memory.smb_tid_max); _dpd.logMsg(" Current fid tracking: %u\n", dce2_memory.smb_fid); _dpd.logMsg(" Maximum fid tracking: %u\n", dce2_memory.smb_fid_max); _dpd.logMsg(" Current file tracking: %u\n", dce2_memory.smb_file); _dpd.logMsg(" Maximum file tracking: %u\n", dce2_memory.smb_file_max); _dpd.logMsg(" Current request tracking: %u\n", dce2_memory.smb_req); _dpd.logMsg(" Maximum request tracking: %u\n", dce2_memory.smb_req_max); #endif } if (dce2_stats.tcp_sessions > 0) { _dpd.logMsg(" TCP\n"); _dpd.logMsg(" Total sessions: "STDu64"\n", dce2_stats.tcp_sessions); _dpd.logMsg(" Packet stats\n"); _dpd.logMsg(" Packets: "STDu64"\n", dce2_stats.tcp_pkts); #ifdef DEBUG_MSGS _dpd.logMsg(" Memory stats (bytes)\n"); _dpd.logMsg(" Current total: %u\n", dce2_memory.tcp_total); _dpd.logMsg(" Maximum total: %u\n", dce2_memory.tcp_total_max); _dpd.logMsg(" Current session data: %u\n", dce2_memory.tcp_ssn); _dpd.logMsg(" Maximum session data: %u\n", dce2_memory.tcp_ssn_max); #endif } if (dce2_stats.udp_sessions > 0) { _dpd.logMsg(" UDP\n"); _dpd.logMsg(" Total sessions: "STDu64"\n", dce2_stats.udp_sessions); _dpd.logMsg(" Packet stats\n"); _dpd.logMsg(" Packets: "STDu64"\n", dce2_stats.udp_pkts); #ifdef DEBUG_MSGS _dpd.logMsg(" Memory stats (bytes)\n"); _dpd.logMsg(" Current total: %u\n", dce2_memory.udp_total); _dpd.logMsg(" Maximum total: %u\n", dce2_memory.udp_total_max); _dpd.logMsg(" Current session data: %u\n", dce2_memory.udp_ssn); _dpd.logMsg(" Maximum session data: %u\n", dce2_memory.udp_ssn_max); #endif } if ((dce2_stats.http_server_sessions > 0) || (dce2_stats.http_proxy_sessions > 0)) { _dpd.logMsg(" RPC over HTTP\n"); if (dce2_stats.http_server_sessions > 0) _dpd.logMsg(" Total server sessions: "STDu64"\n", dce2_stats.http_server_sessions); if (dce2_stats.http_proxy_sessions > 0) _dpd.logMsg(" Total proxy sessions: "STDu64"\n", dce2_stats.http_proxy_sessions); _dpd.logMsg(" Packet stats\n"); if (dce2_stats.http_server_sessions > 0) _dpd.logMsg(" Server packets: "STDu64"\n", dce2_stats.http_server_pkts); if (dce2_stats.http_proxy_sessions > 0) _dpd.logMsg(" Proxy packets: "STDu64"\n", dce2_stats.http_proxy_pkts); #ifdef DEBUG_MSGS _dpd.logMsg(" Memory stats (bytes)\n"); _dpd.logMsg(" Current total: %u\n", dce2_memory.http_total); _dpd.logMsg(" Maximum total: %u\n", dce2_memory.http_total_max); _dpd.logMsg(" Current session data: %u\n", dce2_memory.http_ssn); _dpd.logMsg(" Maximum session data: %u\n", dce2_memory.http_ssn_max); #endif } if ((dce2_stats.co_pdus > 0) || (dce2_stats.cl_pkts > 0)) { _dpd.logMsg("\n"); _dpd.logMsg(" DCE/RPC\n"); if (dce2_stats.co_pdus > 0) { _dpd.logMsg(" Connection oriented\n"); _dpd.logMsg(" Packet stats\n"); _dpd.logMsg(" PDUs: "STDu64"\n", dce2_stats.co_pdus); if ((dce2_stats.co_bind > 0) || (dce2_stats.co_bind_ack > 0)) { _dpd.logMsg(" Bind: "STDu64"\n", dce2_stats.co_bind); _dpd.logMsg(" Bind Ack: "STDu64"\n", dce2_stats.co_bind_ack); } if ((dce2_stats.co_alter_ctx > 0) || (dce2_stats.co_alter_ctx_resp > 0)) { _dpd.logMsg(" Alter context: "STDu64"\n", dce2_stats.co_alter_ctx); _dpd.logMsg(" Alter context response: "STDu64"\n", dce2_stats.co_alter_ctx_resp); } if (dce2_stats.co_bind_nack > 0) _dpd.logMsg(" Bind Nack: "STDu64"\n", dce2_stats.co_bind_nack); if ((dce2_stats.co_request > 0) || (dce2_stats.co_response > 0)) { _dpd.logMsg(" Request: "STDu64"\n", dce2_stats.co_request); _dpd.logMsg(" Response: "STDu64"\n", dce2_stats.co_response); } if (dce2_stats.co_fault > 0) _dpd.logMsg(" Fault: "STDu64"\n", dce2_stats.co_fault); if (dce2_stats.co_reject > 0) _dpd.logMsg(" Reject: "STDu64"\n", dce2_stats.co_reject); if (dce2_stats.co_auth3 > 0) _dpd.logMsg(" Auth3: "STDu64"\n", dce2_stats.co_auth3); if (dce2_stats.co_shutdown > 0) _dpd.logMsg(" Shutdown: "STDu64"\n", dce2_stats.co_shutdown); if (dce2_stats.co_cancel > 0) _dpd.logMsg(" Cancel: "STDu64"\n", dce2_stats.co_cancel); if (dce2_stats.co_orphaned > 0) _dpd.logMsg(" Orphaned: "STDu64"\n", dce2_stats.co_orphaned); if (dce2_stats.co_ms_pdu > 0) _dpd.logMsg(" Microsoft Request To Send RPC over HTTP: "STDu64"\n", dce2_stats.co_ms_pdu); if (dce2_stats.co_other_req > 0) _dpd.logMsg(" Other request type: "STDu64"\n", dce2_stats.co_other_req); if (dce2_stats.co_other_resp > 0) _dpd.logMsg(" Other response type: "STDu64"\n", dce2_stats.co_other_resp); _dpd.logMsg(" Request fragments: "STDu64"\n", dce2_stats.co_req_fragments); if (dce2_stats.co_req_fragments > 0) { _dpd.logMsg(" Min fragment size: "STDu64"\n", dce2_stats.co_cli_min_frag_size); _dpd.logMsg(" Max fragment size: "STDu64"\n", dce2_stats.co_cli_max_frag_size); _dpd.logMsg(" Frag reassembled: "STDu64"\n", dce2_stats.co_cli_frag_reassembled); } _dpd.logMsg(" Response fragments: "STDu64"\n", dce2_stats.co_resp_fragments); if (dce2_stats.co_resp_fragments > 0) { _dpd.logMsg(" Min fragment size: "STDu64"\n", dce2_stats.co_srv_min_frag_size); _dpd.logMsg(" Max fragment size: "STDu64"\n", dce2_stats.co_srv_max_frag_size); _dpd.logMsg(" Frag reassembled: "STDu64"\n", dce2_stats.co_srv_frag_reassembled); } _dpd.logMsg(" Client PDU segmented reassembled: "STDu64"\n", dce2_stats.co_cli_seg_reassembled); _dpd.logMsg(" Server PDU segmented reassembled: "STDu64"\n", dce2_stats.co_srv_seg_reassembled); #ifdef DEBUG_MSGS _dpd.logMsg(" Memory stats (bytes)\n"); _dpd.logMsg(" Current segmentation buffering: %u\n", dce2_memory.co_seg); _dpd.logMsg(" Maximum segmentation buffering: %u\n", dce2_memory.co_seg_max); _dpd.logMsg(" Current fragment tracker: %u\n", dce2_memory.co_frag); _dpd.logMsg(" Maximum fragment tracker: %u\n", dce2_memory.co_frag_max); _dpd.logMsg(" Current context tracking: %u\n", dce2_memory.co_ctx); _dpd.logMsg(" Maximum context tracking: %u\n", dce2_memory.co_ctx_max); #endif } if (dce2_stats.cl_pkts > 0) { _dpd.logMsg(" Connectionless\n"); _dpd.logMsg(" Packet stats\n"); _dpd.logMsg(" Packets: "STDu64"\n", dce2_stats.cl_pkts); if ((dce2_stats.cl_request > 0) || (dce2_stats.cl_response > 0)) { _dpd.logMsg(" Request: "STDu64"\n", dce2_stats.cl_request); _dpd.logMsg(" Response: "STDu64"\n", dce2_stats.cl_response); } if (dce2_stats.cl_ack > 0) _dpd.logMsg(" Ack: "STDu64"\n", dce2_stats.cl_ack); if (dce2_stats.cl_cancel > 0) _dpd.logMsg(" Cancel: "STDu64"\n", dce2_stats.cl_cancel); if (dce2_stats.cl_cli_fack > 0) _dpd.logMsg(" Client Fack: "STDu64"\n", dce2_stats.cl_cli_fack); if (dce2_stats.cl_ping > 0) _dpd.logMsg(" Ping: "STDu64"\n", dce2_stats.cl_ping); if (dce2_stats.cl_reject > 0) _dpd.logMsg(" Reject: "STDu64"\n", dce2_stats.cl_reject); if (dce2_stats.cl_cancel_ack > 0) _dpd.logMsg(" Cancel Ack: "STDu64"\n", dce2_stats.cl_cancel_ack); if (dce2_stats.cl_srv_fack > 0) _dpd.logMsg(" Server Fack: "STDu64"\n", dce2_stats.cl_srv_fack); if (dce2_stats.cl_fault > 0) _dpd.logMsg(" Fault: "STDu64"\n", dce2_stats.cl_fault); if (dce2_stats.cl_nocall > 0) _dpd.logMsg(" NoCall: "STDu64"\n", dce2_stats.cl_nocall); if (dce2_stats.cl_working > 0) _dpd.logMsg(" Working: "STDu64"\n", dce2_stats.cl_working); if (dce2_stats.cl_other_req > 0) _dpd.logMsg(" Other request type: "STDu64"\n", dce2_stats.cl_other_req); if (dce2_stats.cl_other_resp > 0) _dpd.logMsg(" Other response type: "STDu64"\n", dce2_stats.cl_other_resp); _dpd.logMsg(" Fragments: "STDu64"\n", dce2_stats.cl_fragments); _dpd.logMsg(" Max fragment size: "STDu64"\n", dce2_stats.cl_max_frag_size); _dpd.logMsg(" Reassembled: "STDu64"\n", dce2_stats.cl_frag_reassembled); if (dce2_stats.cl_max_seqnum > 0) _dpd.logMsg(" Max seq num: "STDu64"\n", dce2_stats.cl_max_seqnum); #ifdef DEBUG_MSGS _dpd.logMsg(" Memory stats (bytes)\n"); _dpd.logMsg(" Current activity tracker: %u\n", dce2_memory.cl_act); _dpd.logMsg(" Maximum activity tracker: %u\n", dce2_memory.cl_act_max); _dpd.logMsg(" Current fragment tracker: %u\n", dce2_memory.cl_frag); _dpd.logMsg(" Maximum fragment tracker: %u\n", dce2_memory.cl_frag_max); #endif } } } /* Have to free it here because CleanExit is called before stats functions * (so anything flushed by stream can go through and count towards stats) */ if (exiting) DCE2_StatsFree(); #ifdef DEBUG_MSGS _dpd.logMsg("\n"); _dpd.logMsg(" Memory stats (bytes)\n"); _dpd.logMsg(" Current total: %u\n", dce2_memory.total); _dpd.logMsg(" Maximum total: %u\n", dce2_memory.total_max); _dpd.logMsg(" Current runtime total: %u\n", dce2_memory.rtotal); _dpd.logMsg(" Maximum runtime total: %u\n", dce2_memory.rtotal_max); _dpd.logMsg(" Current config total: %u\n", dce2_memory.config); _dpd.logMsg(" Maximum config total: %u\n", dce2_memory.config_max); _dpd.logMsg(" Current rule options total: %u\n", dce2_memory.roptions); _dpd.logMsg(" Maximum rule options total: %u\n", dce2_memory.roptions_max); _dpd.logMsg(" Current routing table total: %u\n", dce2_memory.rt); _dpd.logMsg(" Maximum routing table total: %u\n", dce2_memory.rt_max); _dpd.logMsg(" Current initialization total: %u\n", dce2_memory.init); _dpd.logMsg(" Maximum initialization total: %u\n", dce2_memory.init_max); #endif } /****************************************************************** * Function: DCE2_Reset() * * Purpose: Reset the preprocessor to a post configuration state. * * Arguments: * int - signal that caused the reset * void * - pointer to data * * Returns: None * ******************************************************************/ static void DCE2_Reset(int signal, void *data) { if (!DCE2_CStackIsEmpty(dce2_pkt_stack)) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Packet stack is not empty when it should be.", __FILE__, __LINE__); DCE2_CStackEmpty(dce2_pkt_stack); } } /****************************************************************** * Function: DCE2_ResetStats() * * Purpose: Reset any statistics being kept by the preprocessor. * * Arguments: * int - signal that caused function to be called * void * - pointer to data * * Returns: None * ******************************************************************/ static void DCE2_ResetStats(int signal, void *data) { DCE2_StatsInit(); } /****************************************************************** * Function: DCE2_CleanExit() * * Purpose: Do any cleanup necessary when Snort exits. * * Arguments: * int - signal that caused Snort to exit * void * - pointer to data * * Returns: None * ******************************************************************/ static void DCE2_CleanExit(int signal, void *data) { DCE2_FreeConfigs(dce2_config); dce2_config = NULL; DCE2_FreeGlobals(); } #ifdef SNORT_RELOAD /********************************************************************* * Function: DCE2_ReloadGlobal() * * Purpose: Creates a new global DCE/RPC preprocessor config. * * Arguments: snort.conf argument line for the DCE/RPC preprocessor. * * Returns: None * *********************************************************************/ static void DCE2_ReloadGlobal(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId dce2_swap_config = (tSfPolicyUserContextId)*new_config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); DCE2_Config *pDefaultPolicyConfig = NULL; DCE2_Config *pCurrentPolicyConfig = NULL; if ((_dpd.streamAPI == NULL) || (_dpd.streamAPI->version != STREAM_API_VERSION5)) { DCE2_Die("%s(%d) \"%s\" configuration: " "Stream5 must be enabled with TCP and UDP tracking.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } if (dce2_swap_config == NULL) { //create a context dce2_swap_config = sfPolicyConfigCreate(); if (dce2_swap_config == NULL) { DCE2_Die("%s(%d) \"%s\" configuration: Could not allocate memory " "configuration.\n", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } *new_config = (void *)dce2_swap_config; } sfPolicyUserPolicySet(dce2_swap_config, policy_id); pDefaultPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetDefault(dce2_swap_config); pCurrentPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetCurrent(dce2_swap_config); if ((policy_id != 0) && (pDefaultPolicyConfig == NULL)) { DCE2_Die("%s(%d) \"%s\" configuration: Must configure default policy " "if other policies are to be configured.\n", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } /* Can only do one global configuration */ if (pCurrentPolicyConfig != NULL) { DCE2_Die("%s(%d) \"%s\" configuration: Only one global configuration can be specified.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); } DCE2_RegRuleOptions(sc); pCurrentPolicyConfig = (DCE2_Config *)DCE2_Alloc(sizeof(DCE2_Config), DCE2_MEM_TYPE__CONFIG); sfPolicyUserDataSetCurrent(dce2_swap_config, pCurrentPolicyConfig); /* Parse configuration args */ DCE2_GlobalConfigure(pCurrentPolicyConfig, args); if ( pCurrentPolicyConfig->gconfig->disabled ) return; _dpd.addPreproc(sc, DCE2_Main, PRIORITY_APPLICATION, PP_DCE2, PROTO_BIT__TCP | PROTO_BIT__UDP); #ifdef TARGET_BASED _dpd.streamAPI->set_service_filter_status (sc, dce2_proto_ids.dcerpc, PORT_MONITOR_SESSION, policy_id, 1); _dpd.streamAPI->set_service_filter_status (sc, dce2_proto_ids.nbss, PORT_MONITOR_SESSION, policy_id, 1); #endif if (policy_id != 0) pCurrentPolicyConfig->gconfig->memcap = pDefaultPolicyConfig->gconfig->memcap; } /********************************************************************* * Function: DCE2_ReloadServer() * * Purpose: Creates a new DCE/RPC server configuration * * Arguments: snort.conf argument line for the DCE/RPC preprocessor. * * Returns: None * *********************************************************************/ static void DCE2_ReloadServer(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId dce2_swap_config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); DCE2_Config *pPolicyConfig = NULL; dce2_swap_config = (tSfPolicyUserContextId)_dpd.getRelatedReloadData(sc, DCE2_GNAME); if (dce2_swap_config != NULL) { sfPolicyUserPolicySet (dce2_swap_config, policy_id); pPolicyConfig = (DCE2_Config *)sfPolicyUserDataGetCurrent(dce2_swap_config); } if ((dce2_swap_config == NULL) || (pPolicyConfig == NULL) || (pPolicyConfig->gconfig == NULL)) { DCE2_Die("%s(%d) \"%s\" configuration: \"%s\" must be configured " "before \"%s\".", *_dpd.config_file, *_dpd.config_line, DCE2_SNAME, DCE2_GNAME, DCE2_SNAME); } /* Parse configuration args */ DCE2_ServerConfigure(sc, pPolicyConfig, args); } static int DCE2_ReloadVerifyPolicy( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { int rval; DCE2_Config *swap_config = (DCE2_Config *)pData; DCE2_Config *current_config = (DCE2_Config *)sfPolicyUserDataGet(dce2_config, policyId); DCE2_ServerConfig *dconfig; //do any housekeeping before freeing DCE2_Config if ( swap_config == NULL || swap_config->gconfig->disabled ) return 0; if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { DCE2_Log(DCE2_LOG_TYPE__WARN, "%s(%d) \"%s\" configuration: " "Stream5 must be enabled with TCP and UDP tracking.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME); return -1; } dconfig = swap_config->dconfig; if (dconfig == NULL) { if ((rval = DCE2_CreateDefaultServerConfig(sc, swap_config, policyId))) return rval; } #ifdef TARGET_BASED if (!_dpd.isAdaptiveConfiguredForSnortConfig(sc, policyId)) #endif { if ((rval = DCE2_ScCheckTransports(swap_config))) return rval; } DCE2_AddPortsToPaf(sc, swap_config, policyId); #ifdef TARGET_BASED DCE2_PafRegisterService(sc, dce2_proto_ids.nbss, policyId, DCE2_TRANS_TYPE__SMB); DCE2_PafRegisterService(sc, dce2_proto_ids.dcerpc, policyId, DCE2_TRANS_TYPE__TCP); #endif #ifdef DCE2_LOG_EXTRA_DATA swap_config->xtra_logging_smb_file_name_id = _dpd.streamAPI->reg_xtra_data_cb(DCE2_LogSmbFileName); #endif /* Register routing table memory */ if (swap_config->sconfigs != NULL) DCE2_RegMem(sfrt_usage(swap_config->sconfigs), DCE2_MEM_TYPE__RT); if (current_config == NULL) return 0; if (swap_config->gconfig->memcap != current_config->gconfig->memcap) { _dpd.errMsg("dcerpc2 reload: Changing the memcap requires a restart.\n"); return -1; } return 0; } /********************************************************************* * Function: DCE2_ReloadVerify() * * Purpose: Verifies a reloaded DCE/RPC preprocessor configuration * * Arguments: None * * Returns: * int * -1 if changed configuration value requires a restart * 0 if configuration is ok * *********************************************************************/ static int DCE2_ReloadVerify(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId dce2_swap_config = (tSfPolicyUserContextId)swap_config; if ((dce2_swap_config == NULL) || (dce2_config == NULL)) return 0; if (sfPolicyUserDataIterate(sc, dce2_swap_config, DCE2_ReloadVerifyPolicy) != 0) { return -1; } return 0; } static int DCE2_ReloadSwapPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { DCE2_Config *pPolicyConfig = (DCE2_Config *)pData; //do any housekeeping before freeing config if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); DCE2_FreeConfig(pPolicyConfig); } return 0; } /********************************************************************* * Function: DCE2_ReloadSwap() * * Purpose: Swaps a new config for the old one. * * Arguments: None * * Returns: None * *********************************************************************/ static void * DCE2_ReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId dce2_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = dce2_config; if (dce2_swap_config == NULL) return NULL; dce2_config = dce2_swap_config; sfPolicyUserDataFreeIterate (old_config, DCE2_ReloadSwapPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) return (void *)old_config; return NULL; } static void DCE2_ReloadSwapFree(void *data) { if (data == NULL) return; DCE2_FreeConfigs((tSfPolicyUserContextId)data); } #endif // Used for iterate function below since we can't pass it static tSfPolicyId dce2_paf_tmp_policy_id = 0; /********************************************************************* * Function: DCE2_AddPortsToPaf() * * Add detect and autodetect ports to stream5 paf * * Arguments: * DCE2_Config * * Pointer to configuration structure. * * Returns: None * *********************************************************************/ static void DCE2_AddPortsToPaf(struct _SnortConfig *sc, DCE2_Config *config, tSfPolicyId policy_id) { if (config == NULL) return; dce2_paf_tmp_policy_id = policy_id; DCE2_ScAddPortsToPaf(sc, config->dconfig); if (config->sconfigs != NULL) sfrt_iterate_with_snort_config(sc, config->sconfigs, DCE2_ScAddPortsToPaf); dce2_paf_tmp_policy_id = 0; } static void DCE2_ScAddPortsToPaf(struct _SnortConfig *snortConf, void *data) { DCE2_ServerConfig *sc = (DCE2_ServerConfig *)data; unsigned int port; tSfPolicyId policy_id = dce2_paf_tmp_policy_id; if (data == NULL) return; for (port = 0; port < DCE2_PORTS__MAX; port++) { if (DCE2_IsPortSet(sc->smb_ports, (uint16_t)port)) { DCE2_PafRegisterPort(snortConf, (uint16_t)port, policy_id, DCE2_TRANS_TYPE__SMB); } if (DCE2_IsPortSet(sc->auto_smb_ports, (uint16_t)port)) { DCE2_PafRegisterPort(snortConf, (uint16_t)port, policy_id, DCE2_TRANS_TYPE__SMB); } if (DCE2_IsPortSet(sc->tcp_ports, (uint16_t)port)) { DCE2_PafRegisterPort(snortConf, (uint16_t)port, policy_id, DCE2_TRANS_TYPE__TCP); } if (DCE2_IsPortSet(sc->auto_tcp_ports, (uint16_t)port)) { DCE2_PafRegisterPort(snortConf, (uint16_t)port, policy_id, DCE2_TRANS_TYPE__TCP); } #if 0 if (DCE2_IsPortSet(sc->http_proxy_ports, (uint16_t)port)) { /* TODO Implement PAF registration and callback. */ } if (DCE2_IsPortSet(sc->http_server_ports, (uint16_t)port)) { /* TODO Implement PAF registration and callback. */ } #endif } } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_session.h0000644000000000000000000005361012260565732021134 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _DCE2_SESSION_H_ #define _DCE2_SESSION_H_ #include "dce2_utils.h" #include "dce2_config.h" #include "dce2_memory.h" #include "dce2_roptions.h" #include "dcerpc.h" #include "sf_snort_packet.h" #include "stream_api.h" #include "sf_dynamic_preprocessor.h" /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_SsnFlag { DCE2_SSN_FLAG__NONE = 0x0000, DCE2_SSN_FLAG__SEEN_CLIENT = 0x0001, DCE2_SSN_FLAG__SEEN_SERVER = 0x0002, DCE2_SSN_FLAG__AUTODETECTED = 0x0010, DCE2_SSN_FLAG__PAF_ABORT = 0x0020, DCE2_SSN_FLAG__NO_INSPECT = 0x0040, DCE2_SSN_FLAG__ALL = 0xffff } DCE2_SsnFlag; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_SsnData { DCE2_TransType trans; DCE2_Policy server_policy; DCE2_Policy client_policy; int flags; const DCE2_ServerConfig *sconfig; const SFSnortPacket *wire_pkt; uint64_t alert_mask; DCE2_Roptions ropts; int autodetect_dir; uint32_t cli_seq; uint32_t cli_nseq; uint32_t srv_seq; uint32_t srv_nseq; tSfPolicyId policy_id; tSfPolicyUserContextId config; } DCE2_SsnData; /******************************************************************** * Extern variables ********************************************************************/ extern uint8_t dce2_no_inspect; /******************************************************************** * Inline function prototypes ********************************************************************/ static inline int DCE2_SsnIsEstablished(const SFSnortPacket *); static inline int DCE2_SsnIsMidstream(const SFSnortPacket *); static inline void DCE2_SsnSetAppData(const SFSnortPacket *, void *, StreamAppDataFree); static inline void * DCE2_SsnGetAppData(const SFSnortPacket *); static inline int DCE2_SsnGetReassembly(const SFSnortPacket *); static inline void DCE2_SsnSetReassembly(const SFSnortPacket *); static inline int DCE2_SsnIsRebuilt(const SFSnortPacket *); static inline int DCE2_SsnIsStreamInsert(const SFSnortPacket *); static inline void DCE2_SsnFlush(SFSnortPacket *); static inline int DCE2_SsnFromServer(const SFSnortPacket *); static inline int DCE2_SsnFromClient(const SFSnortPacket *); static inline bool DCE2_SsnIsPafActive(const SFSnortPacket *); static inline void DCE2_SsnSetSeenClient(DCE2_SsnData *); static inline int DCE2_SsnSeenClient(DCE2_SsnData *); static inline void DCE2_SsnSetSeenServer(DCE2_SsnData *); static inline int DCE2_SsnSeenServer(DCE2_SsnData *); static inline void DCE2_SsnSetAutodetected(DCE2_SsnData *, const SFSnortPacket *); static inline int DCE2_SsnAutodetected(DCE2_SsnData *); static inline int DCE2_SsnAutodetectDir(DCE2_SsnData *); static inline void DCE2_SsnSetNoInspect(const SFSnortPacket *); static inline int DCE2_SsnNoInspect(DCE2_SsnData *sd); static inline void DCE2_SsnSetPolicy(DCE2_SsnData *, DCE2_Policy); static inline DCE2_Policy DCE2_SsnGetPolicy(DCE2_SsnData *); static inline DCE2_Policy DCE2_SsnGetServerPolicy(DCE2_SsnData *); static inline DCE2_Policy DCE2_SsnGetClientPolicy(DCE2_SsnData *); static inline bool DCE2_SsnIsWindowsPolicy(DCE2_SsnData *); static inline bool DCE2_SsnIsSambaPolicy(DCE2_SsnData *); static inline bool DCE2_SsnIsServerWindowsPolicy(DCE2_SsnData *); static inline bool DCE2_SsnIsServerSambaPolicy(DCE2_SsnData *); /******************************************************************** * Function: DCE2_SsnIsEstablished() * * Purpose: Returns whether or not the session is established * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: * int - non-zero if the session is established. * zero if the session is not established. * ********************************************************************/ static inline int DCE2_SsnIsEstablished(const SFSnortPacket *p) { return _dpd.streamAPI->get_session_flags (p->stream_session_ptr) & SSNFLAG_ESTABLISHED; } /******************************************************************** * Function: DCE2_SsnIsEstablished() * * Purpose: Returns whether or not the session was picked * up midstream. * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: * int - non-zero if the session was picked up midstream. * zero if the session was not picked up midstream. * ********************************************************************/ static inline int DCE2_SsnIsMidstream(const SFSnortPacket *p) { return _dpd.streamAPI->get_session_flags (p->stream_session_ptr) & SSNFLAG_MIDSTREAM; } /******************************************************************** * Function: DCE2_SsnSetAppData() * * Purpose: Sets application data associated with session. * * Arguments: * SFSnortPacket * - pointer to packet * void * - pointer to data to store on session. * StreamAppDataFree - free function for freeing data stored * on session * * Note: Both data and free function can be NULL and have the * effect of removing the session data. * * Returns: None * ********************************************************************/ static inline void DCE2_SsnSetAppData(const SFSnortPacket *p, void *data, StreamAppDataFree sdfree) { _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_DCE2, data, sdfree); } /******************************************************************** * Function: DCE2_SsnGetAppData() * * Purpose: Gets application data stored with session. * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: * void * - the data stored on the session. * ********************************************************************/ static inline void * DCE2_SsnGetAppData(const SFSnortPacket *p) { return _dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_DCE2); } /******************************************************************** * Function: DCE2_SsnGetReassembly() * * Purpose: Gets reassembly direction for the session. * * Arguments: * DCE2_SsnData * - session data pointer * * Returns: * int - the reassembly direction * SSN_DIR_NONE, SSN_DIR_FROM_CLIENT, SSN_DIR_FROM_SERVER or SSN_DIR_BOTH * ********************************************************************/ static inline int DCE2_SsnGetReassembly(const SFSnortPacket *p) { return (int)_dpd.streamAPI->get_reassembly_direction(p->stream_session_ptr); } /******************************************************************** * Function: DCE2_SsnSetReassembly() * * Purpose: Sets reassembly direction for the session to * SSN_DIR_BOTH since the preprocessor looks at both * client and server packets. * * Arguments: * DCE2_SsnData * - session data pointer * * Returns: None * ********************************************************************/ static inline void DCE2_SsnSetReassembly(const SFSnortPacket *p) { _dpd.streamAPI->set_reassembly(p->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_BOTH, STREAM_FLPOLICY_SET_ABSOLUTE); } /******************************************************************** * Function: DCE2_SsnIsRebuilt() * * Purpose: Returns whether or not the packet is a stream * reassembled packet. * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: * int - non-zero if the packet is stream reassembled. * zero if the packet is not stream reassembled. * ********************************************************************/ static inline int DCE2_SsnIsRebuilt(const SFSnortPacket *p) { return PacketHasFullPDU(p) || (p->flags & FLAG_REBUILT_STREAM); } /******************************************************************** * Function: DCE2_SsnIsStreamInsert() * * Purpose: Returns whether or not the packet is a stream * inserted packet. * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: * int - non-zero if the packet is stream inserted. * zero if the packet is not stream inserted. * ********************************************************************/ static inline int DCE2_SsnIsStreamInsert(const SFSnortPacket *p) { return p->flags & FLAG_STREAM_INSERT; } /******************************************************************** * Function: DCE2_SsnFlush() * * Purpose: Flushes the stream inserted packets on the opposite * side of the conversation. * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: None * ********************************************************************/ static inline void DCE2_SsnFlush(SFSnortPacket *p) { _dpd.streamAPI->response_flush_stream(p); } /******************************************************************** * Function: DCE2_SsnFromServer() * * Purpose: Returns whether or not this packet is from * the server. * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: * int - non-zero if the packet is from the server. * zero if the packet is not from the server. * ********************************************************************/ static inline int DCE2_SsnFromServer(const SFSnortPacket *p) { return p->flags & FLAG_FROM_SERVER; } /******************************************************************** * Function: DCE2_SsnFromClient() * * Purpose: Returns whether or not this packet is from * the client. * * Arguments: * SFSnortPacket * - pointer to packet * * Returns: * int - non-zero if the packet is from the client. * zero if the packet is not from the client. * ********************************************************************/ static inline int DCE2_SsnFromClient(const SFSnortPacket *p) { return p->flags & FLAG_FROM_CLIENT; } /******************************************************************** * Function: DCE2_SsnIsPafActive() * * Purpose: Checks stream api to see if PAF is active for both sides * of the session. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * bool - true if paf is active * false if not * ********************************************************************/ static inline bool DCE2_SsnIsPafActive(const SFSnortPacket *p) { if ((p->stream_session_ptr == NULL) || (_dpd.streamAPI->is_paf_active(p->stream_session_ptr, true) && _dpd.streamAPI->is_paf_active(p->stream_session_ptr, false))) return true; return false; } /******************************************************************** * Function: DCE2_SsnSetSeenClient() * * Purpose: Sets a flag that indicates that we have seen the * client side of the conversation. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: None * ********************************************************************/ static inline void DCE2_SsnSetSeenClient(DCE2_SsnData *sd) { sd->flags |= DCE2_SSN_FLAG__SEEN_CLIENT; } /******************************************************************** * Function: DCE2_SsnSeenClient() * * Purpose: Returns whether or not we've seen the client side * of the conversation on this session. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * int - non-zero if we've seen the client * zero if we haven't seen the client * ********************************************************************/ static inline int DCE2_SsnSeenClient(DCE2_SsnData *sd) { return sd->flags & DCE2_SSN_FLAG__SEEN_CLIENT; } /******************************************************************** * Function: DCE2_SsnSetSeenServer() * * Purpose: Sets a flag that indicates that we have seen the * server side of the conversation. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: None * ********************************************************************/ static inline void DCE2_SsnSetSeenServer(DCE2_SsnData *sd) { sd->flags |= DCE2_SSN_FLAG__SEEN_SERVER; } /******************************************************************** * Function: DCE2_SsnSeenServer() * * Purpose: Returns whether or not we've seen the server side * of the conversation on this session. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * int - non-zero if we've seen the server * zero if we haven't seen the server * ********************************************************************/ static inline int DCE2_SsnSeenServer(DCE2_SsnData *sd) { return sd->flags & DCE2_SSN_FLAG__SEEN_SERVER; } /******************************************************************** * Function: DCE2_SsnSetAutodetected() * * Purpose: Sets flag that indicates that this session * was autodetected. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: None * ********************************************************************/ static inline void DCE2_SsnSetAutodetected(DCE2_SsnData *sd, const SFSnortPacket *p) { sd->flags |= DCE2_SSN_FLAG__AUTODETECTED; sd->autodetect_dir = p->flags & (FLAG_FROM_CLIENT | FLAG_FROM_SERVER); } /******************************************************************** * Function: DCE2_SsnAutodetected() * * Purpose: Returns whether or not this session was autodetected. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * int - non-zero if session was autodetected * zero if session was not autodetected * ********************************************************************/ static inline int DCE2_SsnAutodetected(DCE2_SsnData *sd) { return sd->flags & DCE2_SSN_FLAG__AUTODETECTED; } /******************************************************************** * Function: DCE2_SsnAutodetectDir() * * Purpose: Returns what direction the session was autodetected on. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * int - FLAG_FROM_CLIENT if autodetected on client packet * FLAG_FROM_SERVER if autodetected on server packet * zero if session was not autodetected * ********************************************************************/ static inline int DCE2_SsnAutodetectDir(DCE2_SsnData *sd) { return sd->autodetect_dir; } /******************************************************************** * Function: DCE2_SsnClearAutodetected() * * Clears the autodetect flag. To be used after it has been * determined this is definitely DCE/RPC traffic. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: None * ********************************************************************/ static inline void DCE2_SsnClearAutodetected(DCE2_SsnData *sd) { sd->flags &= ~DCE2_SSN_FLAG__AUTODETECTED; sd->autodetect_dir = 0; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_SsnSetNoInspect(const SFSnortPacket *p) { _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_DCE2, (void *)&dce2_no_inspect, NULL); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DCE2_SsnNoInspect(DCE2_SsnData *sd) { return (void *)sd == (void *)&dce2_no_inspect; } /******************************************************************** * Function: DCE2_SsnSetPolicy() * * Purpose: * Convenience function to set policy for session, client or server. * Sets policy for the current direction packet is from. * * Arguments: * DCE2_SsnData * - pointer to session data * DCE2_Policy - the policy to set client/server to * * Returns: None * ********************************************************************/ static inline void DCE2_SsnSetPolicy(DCE2_SsnData *sd, DCE2_Policy policy) { if (DCE2_SsnFromClient(sd->wire_pkt)) sd->client_policy = policy; else sd->server_policy = policy; } /******************************************************************** * Function: DCE2_SsnGetPolicy() * * Purpose: * Convenience function to get policy for session, client or server * determined by the direction the traffic is flowing to. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: None * DCE2_Policy - If from the client returns server policy. * If from server returns client policy. * ********************************************************************/ static inline DCE2_Policy DCE2_SsnGetPolicy(DCE2_SsnData *sd) { if (DCE2_SsnFromClient(sd->wire_pkt)) return sd->server_policy; else return sd->client_policy; } /******************************************************************** * Function: DCE2_SsnGetServerPolicy() * * Purpose: * Returns server policy for session * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: None * DCE2_Policy - The server policy * ********************************************************************/ static inline DCE2_Policy DCE2_SsnGetServerPolicy(DCE2_SsnData *sd) { return sd->server_policy; } /******************************************************************** * Function: DCE2_SsnGetClientPolicy() * * Purpose: * Returns client policy for session * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: None * DCE2_Policy - The client policy * ********************************************************************/ static inline DCE2_Policy DCE2_SsnGetClientPolicy(DCE2_SsnData *sd) { return sd->client_policy; } /******************************************************************** * Function: DCE2_SsnIsWindowsPolicy() * * Purpose: * Convenience function to determine if policy traffic is going to * is a Windows one. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * bool - true if Samba, false if not * ********************************************************************/ static inline bool DCE2_SsnIsWindowsPolicy(DCE2_SsnData *sd) { DCE2_Policy policy = DCE2_SsnGetPolicy(sd); switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: return true; default: break; } return false; } /******************************************************************** * Function: DCE2_SsnIsSambaPolicy() * * Purpose: * Convenience function to determine if policy traffic is going to * is a Samba one. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * bool - true if Samba, false if not * ********************************************************************/ static inline bool DCE2_SsnIsSambaPolicy(DCE2_SsnData *sd) { DCE2_Policy policy = DCE2_SsnGetPolicy(sd); switch (policy) { case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: return true; default: break; } return false; } /******************************************************************** * Function: DCE2_SsnIsServerWindowsPolicy() * * Purpose: * Convenience function to determine if server policy is a * Windows one. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * bool - true if Samba, false if not * ********************************************************************/ static inline bool DCE2_SsnIsServerWindowsPolicy(DCE2_SsnData *sd) { DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd); switch (policy) { case DCE2_POLICY__WIN2000: case DCE2_POLICY__WINXP: case DCE2_POLICY__WINVISTA: case DCE2_POLICY__WIN2003: case DCE2_POLICY__WIN2008: case DCE2_POLICY__WIN7: return true; default: break; } return false; } /******************************************************************** * Function: DCE2_SsnIsServerSambaPolicy() * * Purpose: * Convenience function to determine if server policy is a * Samba one. * * Arguments: * DCE2_SsnData * - pointer to session data * * Returns: * bool - true if Samba, false if not * ********************************************************************/ static inline bool DCE2_SsnIsServerSambaPolicy(DCE2_SsnData *sd) { DCE2_Policy policy = DCE2_SsnGetServerPolicy(sd); switch (policy) { case DCE2_POLICY__SAMBA: case DCE2_POLICY__SAMBA_3_0_37: case DCE2_POLICY__SAMBA_3_0_22: case DCE2_POLICY__SAMBA_3_0_20: return true; default: break; } return false; } #endif /* _DCE2_SESSION_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_roptions.h0000644000000000000000000000450712260565732021327 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _DCE2_ROPTIONS_H_ #define _DCE2_ROPTIONS_H_ #include "dcerpc.h" /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_Roptions { /* dce_iface */ int first_frag; /* Set to sentinel if not applicable */ Uuid iface; /* For connectionless */ uint32_t iface_vers; /* For connectionless */ /* For connection-oriented */ uint16_t iface_vers_maj; uint16_t iface_vers_min; /* dce_opnum */ int opnum; /* Set to sentinel if not applicable */ /* dce_byte_test */ int hdr_byte_order; /* Set to sentinel if not applicable */ int data_byte_order; /* Set to sentinel if not applicable */ /* dce_stub_data */ const uint8_t *stub_data; /* Set to NULL if not applicable */ } DCE2_Roptions; /******************************************************************** * Public function prototypes ********************************************************************/ struct _SnortConfig; void DCE2_RegRuleOptions(struct _SnortConfig *); void DCE2_PrintRoptions(DCE2_Roptions *); int DCE2_GetByteOrder(void *, int32_t); #endif /* _DCE2_ROPTIONS_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_roptions.c0000644000000000000000000026414712260565732021332 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_roptions.h" #include "dce2_memory.h" #include "dcerpc.h" #include "dce2_utils.h" #include "dce2_session.h" #include "sf_types.h" #include "sf_dynamic_preprocessor.h" #include "stream_api.h" #include "sf_dynamic_engine.h" #include "sf_snort_plugin_api.h" #include "sfhashfcn.h" #include "profiler.h" /******************************************************************** * Macros ********************************************************************/ #define DCE2_RTOKEN__OPT_SEP "," /* Rule option option separator */ #define DCE2_RTOKEN__ARG_SEP " \t" /* Rule option argument separator */ #define DCE2_RTOKEN__IFACE_SEP "-" /* Rule option interface separator */ #define DCE2_ROPT__IFACE "dce_iface" #define DCE2_ROPT__OPNUM "dce_opnum" #define DCE2_ROPT__STUB_DATA "dce_stub_data" #define DCE2_ROPT__BYTE_TEST "byte_test" /* Override keyword */ #define DCE2_ROPT__BYTE_JUMP "byte_jump" /* Override keyword */ #define DCE2_ROPT__BYTE_EXTRACT "byte_extract" /* Override keyword */ #define DCE2_RARG__LT '<' #define DCE2_RARG__EQ '=' #define DCE2_RARG__GT '>' #define DCE2_RARG__NE '!' #define DCE2_RARG__AND '&' #define DCE2_RARG__XOR '^' #define DCE2_RARG__ANY_FRAG "any_frag" #define DCE2_RARG__RELATIVE "relative" #define DCE2_RARG__MULTIPLIER "multiplier" #define DCE2_RARG__ALIGN "align" #define DCE2_RARG__POST_OFFSET "post_offset" #define DCE2_RARG__DCE_OVERRIDE "dce" #define DCE2_RARG__DCE_BYTEORDER "dce" #define DCE2_IFACE__MIN_ARGS 1 #define DCE2_IFACE__MAX_ARGS 3 #define DCE2_IFACE__LEN 36 /* counting the dashes */ #define DCE2_IFACE__TIME_LOW_LEN 8 #define DCE2_IFACE__TIME_MID_LEN 4 #define DCE2_IFACE__TIME_HIGH_LEN 4 #define DCE2_IFACE__CLOCK_SEQ_LEN 4 #define DCE2_IFACE__NODE_LEN 12 #define DCE2_BTEST__MIN_ARGS 4 #define DCE2_BTEST__MAX_ARGS 6 #define DCE2_BJUMP__MIN_ARGS 2 #define DCE2_BJUMP__MAX_ARGS 7 #define DCE2_OPNUM__MAX (UINT16_MAX + 1) #define DCE2_OPNUM__MAX_INDEX (DCE2_OPNUM__MAX / 8) /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_IfOp { DCE2_IF_OP__NONE = 0, DCE2_IF_OP__LT, DCE2_IF_OP__EQ, DCE2_IF_OP__GT, DCE2_IF_OP__NE } DCE2_IfOp; typedef enum _DCE2_BtOp { DCE2_BT_OP__NONE = 0, DCE2_BT_OP__LT, DCE2_BT_OP__EQ, DCE2_BT_OP__GT, DCE2_BT_OP__AND, DCE2_BT_OP__XOR } DCE2_BtOp; typedef enum _DCE2_OpnumType { DCE2_OPNUM_TYPE__SINGLE, DCE2_OPNUM_TYPE__MULTIPLE } DCE2_OpnumType; typedef enum _DCE2_OpnumListState { DCE2_OPNUM_LIST_STATE__START, DCE2_OPNUM_LIST_STATE__OPNUM_START, DCE2_OPNUM_LIST_STATE__OPNUM_LO, DCE2_OPNUM_LIST_STATE__OPNUM_RANGE, DCE2_OPNUM_LIST_STATE__OPNUM_HI, DCE2_OPNUM_LIST_STATE__OPNUM_END, DCE2_OPNUM_LIST_STATE__END } DCE2_OpnumListState; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_IfaceData { Uuid iface; uint32_t iface_vers; int iface_vers_maj; int iface_vers_min; DCE2_IfOp operator; int any_frag; } DCE2_IfaceData; typedef struct _DCE_OpnumData { DCE2_OpnumType type; } DCE2_OpnumData; typedef struct _DCE_OpnumSingle { DCE2_OpnumData odata; uint16_t opnum; } DCE2_OpnumSingle; typedef struct _DCE2_OpnumMultiple { DCE2_OpnumData odata; uint8_t *mask; uint16_t mask_size; uint16_t opnum_lo; uint16_t opnum_hi; } DCE2_OpnumMultiple; typedef struct _DCE2_ByteTestData { int num_bytes; uint32_t value; int invert; DCE2_BtOp operator; int32_t offset; /* can be negative */ int relative; } DCE2_ByteTestData; typedef struct _DCE2_ByteJumpData { int num_bytes; int32_t offset; /* can be negative */ int relative; int multiplier; int align; int32_t post_offset; /* can be negative */ } DCE2_ByteJumpData; /******************************************************************** * Private function prototypes ********************************************************************/ static int DCE2_IfaceInit(struct _SnortConfig *, char *, char *, void **); static int DCE2_OpnumInit(struct _SnortConfig *, char *, char *, void **); static void DCE2_ParseOpnumList(char **, char *, uint8_t *); static inline void DCE2_OpnumSet(uint8_t *, const uint16_t); static inline void DCE2_OpnumSetRange(uint8_t *, uint16_t, uint16_t); static inline int DCE2_OpnumIsSet(const uint8_t *, const uint16_t, const uint16_t, const uint16_t); static int DCE2_StubDataInit(struct _SnortConfig *, char *, char *, void **); static int DCE2_ByteTestInit(struct _SnortConfig *, char *, char *, void **); static int DCE2_ByteJumpInit(struct _SnortConfig *, char *, char *, void **); static void DCE2_ParseIface(char *, DCE2_IfaceData *); static int DCE2_IfaceEval(void *, const uint8_t **, void *); static int DCE2_OpnumEval(void *, const uint8_t **, void *); static int DCE2_StubDataEval(void *, const uint8_t **, void *); static int DCE2_ByteTestEval(void *, const uint8_t **, void *); static int DCE2_ByteJumpEval(void *, const uint8_t **, void *); static void DCE2_IfaceCleanup(void *); static void DCE2_OpnumCleanup(void *); static void DCE2_ByteTestCleanup(void *); static void DCE2_ByteJumpCleanup(void *); static uint32_t DCE2_IfaceHash(void *); static uint32_t DCE2_OpnumHash(void *); static uint32_t DCE2_ByteTestHash(void *); static uint32_t DCE2_ByteJumpHash(void *); static int DCE2_IfaceKeyCompare(void *, void *); static int DCE2_OpnumKeyCompare(void *, void *); static int DCE2_ByteTestKeyCompare(void *, void *); static int DCE2_ByteJumpKeyCompare(void *, void *); static inline int DCE2_RoptDoEval(SFSnortPacket *); static NORETURN void DCE2_RoptError(const char *, ...); static inline void * DCE2_AllocFp(uint32_t); static int DCE2_IfaceAddFastPatterns(void *, int, int, FPContentInfo **); /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_RegRuleOptions(struct _SnortConfig *sc) { _dpd.preprocOptRegister(sc, DCE2_ROPT__IFACE, DCE2_IfaceInit, DCE2_IfaceEval, DCE2_IfaceCleanup, DCE2_IfaceHash, DCE2_IfaceKeyCompare, NULL, DCE2_IfaceAddFastPatterns); _dpd.preprocOptRegister(sc, DCE2_ROPT__OPNUM, DCE2_OpnumInit, DCE2_OpnumEval, DCE2_OpnumCleanup, DCE2_OpnumHash, DCE2_OpnumKeyCompare, NULL, NULL); _dpd.preprocOptRegister(sc, DCE2_ROPT__STUB_DATA, DCE2_StubDataInit, DCE2_StubDataEval, NULL, NULL, NULL, NULL, NULL); _dpd.preprocOptOverrideKeyword(sc, DCE2_ROPT__BYTE_TEST, DCE2_RARG__DCE_OVERRIDE, DCE2_ByteTestInit, DCE2_ByteTestEval, DCE2_ByteTestCleanup, DCE2_ByteTestHash, DCE2_ByteTestKeyCompare, NULL, NULL); _dpd.preprocOptOverrideKeyword(sc, DCE2_ROPT__BYTE_JUMP, DCE2_RARG__DCE_OVERRIDE, DCE2_ByteJumpInit, DCE2_ByteJumpEval, DCE2_ByteJumpCleanup, DCE2_ByteJumpHash, DCE2_ByteJumpKeyCompare, NULL, NULL); _dpd.preprocOptByteOrderKeyword(DCE2_RARG__DCE_BYTEORDER, DCE2_GetByteOrder); } /******************************************************************** * Function: DCE2_IfaceInit() * * Parses dce_iface rule option. * * XXX Connectionless uses a 32bit version, connection-oriented * a 16bit major version and 16bit minor version. Not likely to * need to support versions greater than 65535, but may need to * support minor version. * * Arguments: * char * * Name of rule option. * char * * Arguments for rule option. * data ** * Variable for saving rule option structure. * * Returns: * 1 if successful * 0 if name is not dce_iface * Fatal errors if invalid arguments. * ********************************************************************/ static int DCE2_IfaceInit(struct _SnortConfig *sc, char *name, char *args, void **data) { char *token, *saveptr = NULL; int iface_vers = 0, any_frag = 0; int tok_num = 0; DCE2_IfaceData *iface_data; if (strcasecmp(name, DCE2_ROPT__IFACE) != 0) return 0; iface_data = (DCE2_IfaceData *)DCE2_Alloc(sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); if (iface_data == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for iface data structure.", __FILE__, __LINE__); } iface_data->operator = DCE2_IF_OP__NONE; /* Must have arguments */ if (DCE2_IsEmptyStr(args)) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option requires arguments.", DCE2_ROPT__IFACE); } /* Get argument */ token = strtok_r(args, DCE2_RTOKEN__OPT_SEP, &saveptr); if (token == NULL) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_Die("%s(%d) strtok_r() returned NULL when string argument " "was not NULL.", __FILE__, __LINE__); } do { tok_num++; token = DCE2_PruneWhiteSpace(token); if (tok_num == 1) /* Iface uuid */ { DCE2_ParseIface(token, iface_data); } else if ((tok_num > DCE2_IFACE__MIN_ARGS) && (tok_num <= DCE2_IFACE__MAX_ARGS)) { int try_any_frag = 0; /* Need at least two bytes */ if (strlen(token) < 2) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid argument: %s.", DCE2_ROPT__IFACE, token); } switch (*token) { case DCE2_RARG__LT: iface_data->operator = DCE2_IF_OP__LT; break; case DCE2_RARG__EQ: iface_data->operator = DCE2_IF_OP__EQ; break; case DCE2_RARG__GT: iface_data->operator = DCE2_IF_OP__GT; break; case DCE2_RARG__NE: iface_data->operator = DCE2_IF_OP__NE; break; default: try_any_frag = 1; } if (!try_any_frag) { char *endptr; if (iface_vers) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Cannot configure interface " "version more than once.", DCE2_ROPT__IFACE); } token++; iface_data->iface_vers = _dpd.SnortStrtoul(token, &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid argument: %s.", DCE2_ROPT__IFACE, token); } switch (iface_data->operator) { case DCE2_IF_OP__LT: if (iface_data->iface_vers == 0) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Interface version " "cannot be less than zero.", DCE2_ROPT__IFACE); } else if (iface_data->iface_vers > (UINT16_MAX + 1)) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Interface version " "cannot be greater than %u.", DCE2_ROPT__IFACE, UINT16_MAX); } break; case DCE2_IF_OP__EQ: case DCE2_IF_OP__NE: if (iface_data->iface_vers > UINT16_MAX) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Interface version " "cannot be greater than %u.", DCE2_ROPT__IFACE, UINT16_MAX); } break; case DCE2_IF_OP__GT: if (iface_data->iface_vers >= UINT16_MAX) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Interface version " "cannot be greater than %u.", DCE2_ROPT__IFACE, UINT16_MAX); } break; default: /* Shouldn't get here */ DCE2_Die("%s(%d) Invalid operator: %d", __FILE__, __LINE__, iface_data->operator); break; } if (iface_data->iface_vers <= UINT16_MAX) iface_data->iface_vers_maj = (int)iface_data->iface_vers; else iface_data->iface_vers_maj = DCE2_SENTINEL; iface_vers = 1; } else { if (any_frag) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Cannot configure " "\"%s\" more than once.", DCE2_ROPT__IFACE, DCE2_RARG__ANY_FRAG); } if (strcasecmp(token, DCE2_RARG__ANY_FRAG) == 0) { iface_data->any_frag = 1; } else { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid argument: %s.", DCE2_ROPT__IFACE, token); } any_frag = 1; } } else { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Too many arguments.", DCE2_ROPT__IFACE); } } while ((token = strtok_r(NULL, DCE2_RTOKEN__OPT_SEP, &saveptr)) != NULL); *data = (void *)iface_data; return 1; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_ParseIface(char *token, DCE2_IfaceData *iface_data) { char *iface, *ifaceptr = NULL; char *if_hex, *if_hexptr = NULL; int num_pieces = 0; /* Has to be a uuid in string format, e.g 4b324fc8-1670-01d3-1278-5a47bf6ee188 * Check the length */ if (strlen(token) != DCE2_IFACE__LEN) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } /* Detach token */ iface = strtok_r(token, DCE2_RTOKEN__ARG_SEP, &ifaceptr); if (iface == NULL) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_Die("%s(%d) strtok_r() returned NULL when string argument " "was not NULL.", __FILE__, __LINE__); } /* Cut into pieces separated by '-' */ if_hex = strtok_r(iface, DCE2_RTOKEN__IFACE_SEP, &if_hexptr); if (if_hex == NULL) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_Die("%s(%d) strtok_r() returned NULL when string argument " "was not NULL.", __FILE__, __LINE__); } do { char *endptr; switch (num_pieces) { case 0: { unsigned long int time_low; if (strlen(if_hex) != DCE2_IFACE__TIME_LOW_LEN) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } time_low = _dpd.SnortStrtoul(if_hex, &endptr, 16); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } iface_data->iface.time_low = (uint32_t)time_low; } break; case 1: { unsigned long int time_mid; if (strlen(if_hex) != DCE2_IFACE__TIME_MID_LEN) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } time_mid = _dpd.SnortStrtoul(if_hex, &endptr, 16); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } /* Length check ensures 16 bit value */ iface_data->iface.time_mid = (uint16_t)time_mid; } break; case 2: { unsigned long int time_high; if (strlen(if_hex) != DCE2_IFACE__TIME_HIGH_LEN) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } time_high = _dpd.SnortStrtoul(if_hex, &endptr, 16); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } /* Length check ensures 16 bit value */ iface_data->iface.time_high_and_version = (uint16_t)time_high; } break; case 3: { unsigned long int clock_seq_and_reserved, clock_seq_low; if (strlen(if_hex) != DCE2_IFACE__CLOCK_SEQ_LEN) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } /* Work backwards */ clock_seq_low = _dpd.SnortStrtoul(&if_hex[2], &endptr, 16); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } iface_data->iface.clock_seq_low = (uint8_t)clock_seq_low; /* Set third byte to null so we can _dpd.SnortStrtoul the first part */ if_hex[2] = '\x00'; clock_seq_and_reserved = _dpd.SnortStrtoul(if_hex, &endptr, 16); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } iface_data->iface.clock_seq_and_reserved = (uint8_t)clock_seq_and_reserved; } break; case 4: { int i, j; if (strlen(if_hex) != DCE2_IFACE__NODE_LEN) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } /* Walk back a byte at a time - 2 hex digits */ for (i = DCE2_IFACE__NODE_LEN - 2, j = sizeof(iface_data->iface.node) - 1; (i >= 0) && (j >= 0); i -= 2, j--) { /* Only giving _dpd.SnortStrtoul 1 byte */ iface_data->iface.node[j] = (uint8_t)_dpd.SnortStrtoul(&if_hex[i], &endptr, 16); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } if_hex[i] = '\0'; } } break; default: break; } num_pieces++; } while ((if_hex = strtok_r(NULL, DCE2_RTOKEN__IFACE_SEP, &if_hexptr)) != NULL); if (num_pieces != 5) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } /* Check for more arguments */ iface = strtok_r(NULL, DCE2_RTOKEN__ARG_SEP, &ifaceptr); if (iface != NULL) { DCE2_Free((void *)iface_data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid uuid.", DCE2_ROPT__IFACE); } } static inline void * DCE2_AllocFp(uint32_t size) { void *mem = calloc(1, (size_t)size); if (mem == NULL) { DCE2_Die("%s(%d) Out of memory!", __FILE__, __LINE__); } return mem; } static int DCE2_IfaceAddFastPatterns(void *rule_opt_data, int protocol, int direction, FPContentInfo **info) { DCE2_IfaceData *iface_data = (DCE2_IfaceData *)rule_opt_data; if ((rule_opt_data == NULL) || (info == NULL)) return -1; if ((protocol != IPPROTO_TCP) && (protocol != IPPROTO_UDP)) return -1; if (protocol == IPPROTO_TCP) { FPContentInfo *tcp_fp = (FPContentInfo *)DCE2_AllocFp(sizeof(FPContentInfo)); char *client_fp = "\x05\x00\x00"; char *server_fp = "\x05\x00\x02"; char *no_dir_fp = "\x05\x00"; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Adding fast pattern " "content for TCP rule option.\n")); switch (direction) { case FLAG_FROM_CLIENT: tcp_fp->content = (char *)DCE2_AllocFp(3); memcpy(tcp_fp->content, client_fp, 3); tcp_fp->length = 3; break; case FLAG_FROM_SERVER: tcp_fp->content = (char *)DCE2_AllocFp(3); memcpy(tcp_fp->content, server_fp, 3); tcp_fp->length = 3; break; default: tcp_fp->content = (char *)DCE2_AllocFp(2); memcpy(tcp_fp->content, no_dir_fp, 2); tcp_fp->length = 2; break; } *info = tcp_fp; } else { //DCE2_IfaceData *iface_data = (DCE2_IfaceData *)rule_opt_data; FPContentInfo *big_fp = (FPContentInfo *)DCE2_AllocFp(sizeof(FPContentInfo)); FPContentInfo *little_fp = (FPContentInfo *)DCE2_AllocFp(sizeof(FPContentInfo)); char *big_content = (char *)DCE2_AllocFp(sizeof(Uuid)); char *little_content = (char *)DCE2_AllocFp(sizeof(Uuid)); uint32_t time32; uint16_t time16; int index = 0; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Adding fast pattern " "content for UDP rule option.\n")); time32 = DceRpcNtohl(&iface_data->iface.time_low, DCERPC_BO_FLAG__BIG_ENDIAN); memcpy(&big_content[index], &time32, sizeof(uint32_t)); time32 = DceRpcNtohl(&iface_data->iface.time_low, DCERPC_BO_FLAG__LITTLE_ENDIAN); memcpy(&little_content[index], &time32, sizeof(uint32_t)); index += sizeof(uint32_t); time16 = DceRpcNtohs(&iface_data->iface.time_mid, DCERPC_BO_FLAG__BIG_ENDIAN); memcpy(&big_content[index], &time16, sizeof(uint16_t)); time16 = DceRpcNtohs(&iface_data->iface.time_mid, DCERPC_BO_FLAG__LITTLE_ENDIAN); memcpy(&little_content[index], &time16, sizeof(uint16_t)); index += sizeof(uint16_t); time16 = DceRpcNtohs(&iface_data->iface.time_high_and_version, DCERPC_BO_FLAG__BIG_ENDIAN); memcpy(&big_content[index], &time16, sizeof(uint16_t)); time16 = DceRpcNtohs(&iface_data->iface.time_high_and_version, DCERPC_BO_FLAG__LITTLE_ENDIAN); memcpy(&little_content[index], &time16, sizeof(uint16_t)); index += sizeof(uint16_t); big_content[index] = iface_data->iface.clock_seq_and_reserved; little_content[index] = iface_data->iface.clock_seq_and_reserved; index += sizeof(uint8_t); big_content[index] = iface_data->iface.clock_seq_low; little_content[index] = iface_data->iface.clock_seq_low; index += sizeof(uint8_t); memcpy(&big_content[index], iface_data->iface.node, 6); memcpy(&little_content[index], iface_data->iface.node, 6); big_fp->content = big_content; big_fp->length = sizeof(Uuid); little_fp->content = little_content; little_fp->length = sizeof(Uuid); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, " Iface: %s\n Big endian: %s\n Little endian: %s\n", DCE2_UuidToStr(&iface_data->iface, DCERPC_BO_FLAG__NONE), DCE2_UuidToStr((Uuid *)big_fp->content, DCERPC_BO_FLAG__NONE), DCE2_UuidToStr((Uuid *)little_fp->content, DCERPC_BO_FLAG__NONE));); big_fp->next = little_fp; *info = big_fp; } return 0; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_OpnumInit(struct _SnortConfig *sc, char *name, char *args, void **data) { uint8_t opnum_mask[DCE2_OPNUM__MAX_INDEX]; /* 65536 bits */ char *args_end; uint16_t num_opnums = 0; unsigned int i; int opnum_lo = DCE2_SENTINEL; int opnum_hi = 0; if (strcasecmp(name, DCE2_ROPT__OPNUM) != 0) return 0; /* Must have arguments */ if (DCE2_IsEmptyStr(args)) { DCE2_RoptError("\"%s\" rule option: No arguments. Must supply " "the value of the opnum.", DCE2_ROPT__OPNUM); } /* Include NULL byte for parsing */ args_end = args + (strlen(args) + 1); memset(opnum_mask, 0, sizeof(opnum_mask)); DCE2_ParseOpnumList(&args, args_end, opnum_mask); /* Must have at least one bit set or the parsing would have errored */ for (i = 0; i < DCE2_OPNUM__MAX; i++) { if (DCE2_OpnumIsSet(opnum_mask, 0, DCE2_OPNUM__MAX - 1, (uint16_t)i)) { num_opnums++; if (opnum_lo == DCE2_SENTINEL) opnum_lo = (uint16_t)i; opnum_hi = (uint16_t)i; } } if (num_opnums == 1) { DCE2_OpnumSingle *odata = (DCE2_OpnumSingle *)DCE2_Alloc(sizeof(DCE2_OpnumSingle), DCE2_MEM_TYPE__ROPTION); if (odata == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for opnum data.", __FILE__, __LINE__); } odata->odata.type = DCE2_OPNUM_TYPE__SINGLE; odata->opnum = (uint16_t)opnum_lo; *data = (void *)odata; } else { int opnum_range = opnum_hi - opnum_lo; int mask_size = (opnum_range / 8) + 1; DCE2_OpnumMultiple *odata = (DCE2_OpnumMultiple *)DCE2_Alloc(sizeof(DCE2_OpnumMultiple), DCE2_MEM_TYPE__ROPTION); if (odata == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for opnum data.", __FILE__, __LINE__); } odata->mask = (uint8_t *)DCE2_Alloc(mask_size, DCE2_MEM_TYPE__ROPTION); if (odata->mask == NULL) { DCE2_Free((void *)odata, sizeof(DCE2_OpnumMultiple), DCE2_MEM_TYPE__ROPTION); DCE2_Die("%s(%d) Failed to allocate memory for opnum data.", __FILE__, __LINE__); } odata->odata.type = DCE2_OPNUM_TYPE__MULTIPLE; odata->mask_size = (uint16_t)mask_size; odata->opnum_lo = (uint16_t)opnum_lo; odata->opnum_hi = (uint16_t)opnum_hi; /* Set the opnum bits in our reduced size opnum mask */ for (i = (unsigned int)opnum_lo; i <= (unsigned int)opnum_hi; i++) { if (DCE2_OpnumIsSet(opnum_mask, 0, DCE2_OPNUM__MAX - 1, (uint16_t)i)) DCE2_OpnumSet(odata->mask, (uint16_t)(i - opnum_lo)); } *data = (void *)odata; } return 1; } /******************************************************************** * Function: * * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_ParseOpnumList(char **ptr, char *end, uint8_t *opnum_mask) { char *lo_start = NULL; char *hi_start = NULL; DCE2_OpnumListState state = DCE2_OPNUM_LIST_STATE__START; uint16_t lo_opnum = 0, hi_opnum = 0; while (*ptr < end) { char c = **ptr; if (state == DCE2_OPNUM_LIST_STATE__END) break; switch (state) { case DCE2_OPNUM_LIST_STATE__START: if (DCE2_IsOpnumChar(c)) { lo_start = *ptr; state = DCE2_OPNUM_LIST_STATE__OPNUM_LO; } else if (!DCE2_IsSpaceChar(c)) { DCE2_RoptError("\"%s\" rule option: Invalid opnum list: %s.", DCE2_ROPT__OPNUM, *ptr); } break; case DCE2_OPNUM_LIST_STATE__OPNUM_LO: if (!DCE2_IsOpnumChar(c)) { DCE2_Ret status = DCE2_GetValue(lo_start, *ptr, &lo_opnum, 0, DCE2_INT_TYPE__UINT16, 10); if (status != DCE2_RET__SUCCESS) { DCE2_RoptError("\"%s\" rule option: Invalid opnum: %.*s", DCE2_ROPT__OPNUM, *ptr - lo_start, lo_start); } if (DCE2_IsOpnumRangeChar(c)) { state = DCE2_OPNUM_LIST_STATE__OPNUM_RANGE; } else { DCE2_OpnumSet(opnum_mask, lo_opnum); state = DCE2_OPNUM_LIST_STATE__OPNUM_END; continue; } } break; case DCE2_OPNUM_LIST_STATE__OPNUM_RANGE: if (DCE2_IsOpnumChar(c)) { hi_start = *ptr; state = DCE2_OPNUM_LIST_STATE__OPNUM_HI; } else { DCE2_OpnumSetRange(opnum_mask, lo_opnum, UINT16_MAX); state = DCE2_OPNUM_LIST_STATE__OPNUM_END; continue; } break; case DCE2_OPNUM_LIST_STATE__OPNUM_HI: if (!DCE2_IsOpnumChar(c)) { DCE2_Ret status = DCE2_GetValue(hi_start, *ptr, &hi_opnum, 0, DCE2_INT_TYPE__UINT16, 10); if (status != DCE2_RET__SUCCESS) { DCE2_RoptError("\"%s\" rule option: Invalid opnum: %.*s", DCE2_ROPT__OPNUM, *ptr - hi_start, hi_start); } DCE2_OpnumSetRange(opnum_mask, lo_opnum, hi_opnum); state = DCE2_OPNUM_LIST_STATE__OPNUM_END; continue; } break; case DCE2_OPNUM_LIST_STATE__OPNUM_END: if (DCE2_IsListSepChar(c)) { state = DCE2_OPNUM_LIST_STATE__START; } else if (DCE2_IsConfigEndChar(c)) { state = DCE2_OPNUM_LIST_STATE__END; continue; } else if (!DCE2_IsSpaceChar(c)) { DCE2_RoptError("\"%s\" rule option: Invalid opnum list: %s.", DCE2_ROPT__OPNUM, *ptr); } break; default: DCE2_Die("%s(%d) Invalid opnum list state: %d", __FILE__, __LINE__, state); break; } (*ptr)++; } if (state != DCE2_OPNUM_LIST_STATE__END) { DCE2_RoptError("\"%s\" rule option: Invalid opnum list: %s", DCE2_ROPT__OPNUM, *ptr); } } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DCE2_OpnumIsSet(const uint8_t *opnum_mask, const uint16_t opnum_lo, const uint16_t opnum_hi, const uint16_t opnum) { uint16_t otmp = opnum - opnum_lo; if ((opnum < opnum_lo) || (opnum > opnum_hi)) return 0; return opnum_mask[(otmp / 8)] & (1 << (otmp % 8)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_OpnumSet(uint8_t *opnum_mask, const uint16_t opnum) { opnum_mask[(opnum / 8)] |= (1 << (opnum % 8)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_OpnumSetRange(uint8_t *opnum_mask, uint16_t lo_opnum, uint16_t hi_opnum) { uint16_t i; if (lo_opnum > hi_opnum) { uint16_t tmp = lo_opnum; lo_opnum = hi_opnum; hi_opnum = tmp; } for (i = lo_opnum; i <= hi_opnum; i++) DCE2_OpnumSet(opnum_mask, i); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_StubDataInit(struct _SnortConfig *sc, char *name, char *args, void **data) { if (strcasecmp(name, DCE2_ROPT__STUB_DATA) != 0) return 0; /* Must not have arguments */ if (!DCE2_IsEmptyStr(args)) { DCE2_RoptError("\"%s\" rule option: This option has no arguments.", DCE2_ROPT__STUB_DATA); } /* Set it to something even though we don't need it */ *data = (void *)1; return 1; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_ByteTestInit(struct _SnortConfig *sc, char *name, char *args, void **data) { char *token, *saveptr = NULL; int tok_num = 0; DCE2_ByteTestData *bt_data; if (strcasecmp(name, DCE2_ROPT__BYTE_TEST) != 0) return 0; bt_data = (DCE2_ByteTestData *)DCE2_Alloc(sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); if (bt_data == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for byte test data structure.", __FILE__, __LINE__); } bt_data->operator = DCE2_BT_OP__NONE; /* Must have arguments */ if (DCE2_IsEmptyStr(args)) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: No arguments.", DCE2_ROPT__BYTE_TEST); } /* Get argument */ token = strtok_r(args, DCE2_RTOKEN__OPT_SEP, &saveptr); if (token == NULL) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_Die("%s(%d) strtok_r() returned NULL when string argument " "was not NULL.", __FILE__, __LINE__); } do { tok_num++; token = DCE2_PruneWhiteSpace(token); if (tok_num == 1) /* Number of bytes to convert */ { char *endptr; unsigned long int num_bytes = _dpd.SnortStrtoul(token, &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid number of bytes to " "convert: %s. Should be one of 1, 2 or 4.", DCE2_ROPT__BYTE_TEST, token); } if ((num_bytes != 1) && (num_bytes != 2) && (num_bytes != 4)) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid number of bytes to " "convert: %s. Should be one of 1, 2 or 4.", DCE2_ROPT__BYTE_TEST, token); } bt_data->num_bytes = num_bytes; } else if (tok_num == 2) /* Operator */ { /* Should only be one byte */ if (strlen(token) > 2) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid argument: %s", DCE2_ROPT__BYTE_TEST, token); } /* If two bytes first must be '!' */ if (strlen(token) == 2) { if (*token != DCE2_RARG__NE) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid argument: %s", DCE2_ROPT__BYTE_TEST, token); } else { bt_data->invert = 1; } token++; } switch (*token) { case DCE2_RARG__LT: bt_data->operator = DCE2_BT_OP__LT; break; case DCE2_RARG__EQ: bt_data->operator = DCE2_BT_OP__EQ; break; case DCE2_RARG__GT: bt_data->operator = DCE2_BT_OP__GT; break; case DCE2_RARG__AND: bt_data->operator = DCE2_BT_OP__AND; break; case DCE2_RARG__XOR: bt_data->operator = DCE2_BT_OP__XOR; break; default: DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid argument: %s", DCE2_ROPT__BYTE_TEST, token); break; } } else if (tok_num == 3) /* Value to compare to */ { char *endptr; unsigned long int value = _dpd.SnortStrtoul(token, &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0') || (value > UINT32_MAX)) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid compare value: %s. Must be " "between 0 and %u inclusive.", DCE2_ROPT__BYTE_TEST, token, UINT32_MAX); } bt_data->value = value; } else if (tok_num == 4) /* Offset in packet data */ { char *endptr; long int offset = _dpd.SnortStrtol(token, &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0') || (offset > (long int)UINT16_MAX) || (offset < (-1 * (long int)UINT16_MAX))) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid offset: %s. Must be " "between -%u and %u inclusive.", DCE2_ROPT__BYTE_TEST, token, UINT16_MAX, UINT16_MAX); } bt_data->offset = offset; } else if ((tok_num == 5) || (tok_num == 6)) { if (strcasecmp(token, DCE2_RARG__RELATIVE) == 0) { /* Can't configure it twice */ if (bt_data->relative) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Can't configure \"%s\" " "more than once.", DCE2_ROPT__BYTE_TEST, DCE2_RARG__RELATIVE); } bt_data->relative = 1; } else if (strcasecmp(token, DCE2_RARG__DCE_OVERRIDE) != 0) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid argument: %s.", DCE2_ROPT__BYTE_TEST, token); } } else { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Too many arguments.", DCE2_ROPT__BYTE_TEST); } } while ((token = strtok_r(NULL, DCE2_RTOKEN__OPT_SEP, &saveptr)) != NULL); if (tok_num < DCE2_BTEST__MIN_ARGS) { DCE2_Free((void *)bt_data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Not enough arguments.", DCE2_ROPT__BYTE_TEST); } *data = (void *)bt_data; return 1; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_ByteJumpInit(struct _SnortConfig *sc, char *name, char *args, void **data) { char *token, *saveptr = NULL; int tok_num = 0; DCE2_ByteJumpData *bj_data; int post_offset_configured = 0; if (strcasecmp(name, DCE2_ROPT__BYTE_JUMP) != 0) return 0; bj_data = (DCE2_ByteJumpData *)DCE2_Alloc(sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); if (bj_data == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for byte jump data structure.", __FILE__, __LINE__); } bj_data->multiplier = DCE2_SENTINEL; /* Must have arguments */ if (DCE2_IsEmptyStr(args)) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: No arguments.", DCE2_ROPT__BYTE_JUMP); } /* Get argument */ token = strtok_r(args, DCE2_RTOKEN__OPT_SEP, &saveptr); if (token == NULL) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_Die("%s(%d) strtok_r() returned NULL when string argument " "was not NULL.", __FILE__, __LINE__); } do { tok_num++; token = DCE2_PruneWhiteSpace(token); if (tok_num == 1) /* Number of bytes to convert */ { char *endptr; unsigned long int num_bytes = _dpd.SnortStrtoul(token, &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid number of bytes to " "convert: %s. Should be one of 1, 2 or 4.", DCE2_ROPT__BYTE_JUMP, token); } if ((num_bytes != 4) && (num_bytes != 2) && (num_bytes != 1)) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid number of bytes to " "convert: %s. Should be one of 1, 2 or 4.", DCE2_ROPT__BYTE_JUMP, token); } bj_data->num_bytes = num_bytes; } else if (tok_num == 2) /* Offset in packet data */ { char *endptr; long int offset = _dpd.SnortStrtol(token, &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0') || (offset > (long int)UINT16_MAX) || (offset < (-1 * (long int)UINT16_MAX))) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid offset: %s. Must be " "between -%u and %u inclusive.", DCE2_ROPT__BYTE_JUMP, token, UINT16_MAX, UINT16_MAX); } bj_data->offset = offset; } else if ((tok_num > DCE2_BJUMP__MIN_ARGS) && (tok_num <= DCE2_BJUMP__MAX_ARGS)) { char *arg, *argptr; /* Detach arg to get potenial sub-arg */ arg = strtok_r(token, DCE2_RTOKEN__ARG_SEP, &argptr); if (arg == NULL) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_Die("%s(%d) strtok_r() returned NULL when string argument " "was not NULL.", __FILE__, __LINE__); } if (strcasecmp(arg, DCE2_RARG__RELATIVE) == 0) { /* Can't configure it twice */ if (bj_data->relative) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Can't configure \"%s\" " "more than once.", DCE2_ROPT__BYTE_TEST, DCE2_RARG__RELATIVE); } bj_data->relative = 1; } else if (strcasecmp(arg, DCE2_RARG__ALIGN) == 0) { if (bj_data->align) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Can't configure \"%s\" " "more than once.", DCE2_ROPT__BYTE_TEST, DCE2_RARG__ALIGN); } bj_data->align = 1; } else if (strcasecmp(arg, DCE2_RARG__MULTIPLIER) == 0) { char *endptr; unsigned long int multiplier; if (bj_data->multiplier != DCE2_SENTINEL) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Can't configure \"%s\" " "more than once.", DCE2_ROPT__BYTE_TEST, DCE2_RARG__MULTIPLIER); } arg = strtok_r(NULL, DCE2_RTOKEN__ARG_SEP, &argptr); if (arg == NULL) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: \"%s\" requires an argument.", DCE2_ROPT__BYTE_JUMP, DCE2_RARG__MULTIPLIER); } multiplier = _dpd.SnortStrtoul(arg, &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0') || (multiplier <= 1) || (multiplier > UINT16_MAX)) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid multiplier: %s. " "Must be between 2 and %u inclusive.", DCE2_ROPT__BYTE_JUMP, arg, UINT16_MAX); } bj_data->multiplier = multiplier; } else if (strcasecmp(arg, DCE2_RARG__POST_OFFSET) == 0) { char *endptr; long int post_offset; if (post_offset_configured) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Can't configure \"%s\" " "more than once.", DCE2_ROPT__BYTE_TEST, DCE2_RARG__POST_OFFSET); } arg = strtok_r(NULL, DCE2_RTOKEN__ARG_SEP, &argptr); if (arg == NULL) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: \"%s\" requires an argument.", DCE2_ROPT__BYTE_JUMP, DCE2_RARG__POST_OFFSET); } post_offset = _dpd.SnortStrtol(arg, &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0') || (post_offset > (long int)UINT16_MAX) || (post_offset < (-1 * (long int)UINT16_MAX))) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid post offset " "value: %s. Must be between -%u to %u inclusive", DCE2_ROPT__BYTE_JUMP, arg, UINT16_MAX, UINT16_MAX); } bj_data->post_offset = post_offset; post_offset_configured = 1; } else if (strcasecmp(arg, DCE2_RARG__DCE_OVERRIDE) != 0) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Invalid argument: %s.", DCE2_ROPT__BYTE_JUMP, arg); } } else { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Too many arguments.", DCE2_ROPT__BYTE_JUMP); } } while ((token = strtok_r(NULL, DCE2_RTOKEN__OPT_SEP, &saveptr)) != NULL); if (tok_num < DCE2_BJUMP__MIN_ARGS) { DCE2_Free((void *)bj_data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); DCE2_RoptError("\"%s\" rule option: Not enough arguments.", DCE2_ROPT__BYTE_JUMP); } *data = (void *)bj_data; return 1; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_IfaceEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; DCE2_SsnData *sd; DCE2_Roptions *ropts; DCE2_IfaceData *iface_data; int ret = RULE_NOMATCH; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Evaluating \"%s\" rule option.\n", DCE2_ROPT__IFACE)); if (!DCE2_RoptDoEval(p)) return RULE_NOMATCH; sd = (DCE2_SsnData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_DCE2); if ((sd == NULL) || DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; if (ropts->first_frag == DCE2_SENTINEL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "First frag not set - not evaluating.\n")); return RULE_NOMATCH; } iface_data = (DCE2_IfaceData *)data; if (iface_data == NULL) return RULE_NOMATCH; if (!iface_data->any_frag && !ropts->first_frag) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Not a first fragment and rule set to only look at " "first fragment.\n")); return RULE_NOMATCH; } /* Compare the uuid */ DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Comparing \"%s\" to \"%s\"\n", DCE2_UuidToStr(&ropts->iface, DCERPC_BO_FLAG__NONE), DCE2_UuidToStr(&iface_data->iface, DCERPC_BO_FLAG__NONE))); if (DCE2_UuidCompare((void *)&ropts->iface, (void *)&iface_data->iface) != 0) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Uuids don't match\n")); return RULE_NOMATCH; } if (iface_data->operator == DCE2_IF_OP__NONE) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "\"%s\" Match\n", DCE2_ROPT__IFACE)); return RULE_MATCH; } switch (iface_data->operator) { case DCE2_IF_OP__LT: if (IsTCP(p) && (iface_data->iface_vers_maj != DCE2_SENTINEL)) { if ((int)ropts->iface_vers_maj < iface_data->iface_vers_maj) ret = RULE_MATCH; } else { if (ropts->iface_vers < iface_data->iface_vers) ret = RULE_MATCH; } break; case DCE2_IF_OP__EQ: if (IsTCP(p) && (iface_data->iface_vers_maj != DCE2_SENTINEL)) { if ((int)ropts->iface_vers_maj == iface_data->iface_vers_maj) ret = RULE_MATCH; } else { if (ropts->iface_vers == iface_data->iface_vers) ret = RULE_MATCH; } break; case DCE2_IF_OP__GT: if (IsTCP(p) && (iface_data->iface_vers_maj != DCE2_SENTINEL)) { if ((int)ropts->iface_vers_maj > iface_data->iface_vers_maj) ret = RULE_MATCH; } else { if (ropts->iface_vers > iface_data->iface_vers) ret = RULE_MATCH; } break; case DCE2_IF_OP__NE: if (IsTCP(p) && (iface_data->iface_vers_maj != DCE2_SENTINEL)) { if ((int)ropts->iface_vers_maj != iface_data->iface_vers_maj) ret = RULE_MATCH; } else { if (ropts->iface_vers != iface_data->iface_vers) ret = RULE_MATCH; } break; default: break; } return ret; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_OpnumEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; DCE2_OpnumData *opnum_data = (DCE2_OpnumData *)data; DCE2_SsnData *sd; DCE2_Roptions *ropts; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Evaluating \"%s\" rule option.\n", DCE2_ROPT__OPNUM)); if (!DCE2_RoptDoEval(p)) return RULE_NOMATCH; sd = (DCE2_SsnData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_DCE2); if ((sd == NULL) || DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; if (ropts->opnum == DCE2_SENTINEL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Opnum not set - not evaluating.\n")); return RULE_NOMATCH; } switch (opnum_data->type) { case DCE2_OPNUM_TYPE__SINGLE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Rule opnum: %u, ropts opnum: %u\n", ((DCE2_OpnumSingle *)opnum_data)->opnum, ropts->opnum)); if (ropts->opnum == ((DCE2_OpnumSingle *)opnum_data)->opnum) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "\"%s\" Match\n", DCE2_ROPT__OPNUM)); return RULE_MATCH; } break; case DCE2_OPNUM_TYPE__MULTIPLE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Multiple opnums: ropts opnum: %u\n", ropts->opnum)); { DCE2_OpnumMultiple *omult = (DCE2_OpnumMultiple *)opnum_data; if (DCE2_OpnumIsSet(omult->mask, omult->opnum_lo, omult->opnum_hi, (uint16_t)ropts->opnum)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "\"%s\" Match\n", DCE2_ROPT__OPNUM)); return RULE_MATCH; } } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid opnum type: %d", __FILE__, __LINE__, opnum_data->type); break; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "\"%s\" Fail\n", DCE2_ROPT__OPNUM)); return RULE_NOMATCH; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_StubDataEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; DCE2_SsnData *sd; DCE2_Roptions *ropts; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Evaluating \"%s\" rule option.\n", DCE2_ROPT__STUB_DATA)); if (!DCE2_RoptDoEval(p)) return RULE_NOMATCH; sd = (DCE2_SsnData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_DCE2); if ((sd == NULL) || DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; if (ropts->stub_data != NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Setting cursor to stub data: %p.\n", ropts->stub_data)); *cursor = ropts->stub_data; _dpd.SetAltDetect((uint8_t *)ropts->stub_data, (uint16_t)(p->payload_size - (ropts->stub_data - p->payload))); return RULE_MATCH; } return RULE_NOMATCH; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_ByteTestEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; DCE2_SsnData *sd; DCE2_Roptions *ropts; DCE2_ByteTestData *bt_data; const uint8_t *start_ptr; uint16_t dsize; const uint8_t *bt_ptr; uint32_t pkt_value; DceRpcBoFlag byte_order; int ret = RULE_NOMATCH; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Evaluating \"%s\" rule option.\n", DCE2_ROPT__BYTE_TEST)); if (*cursor == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Cursor is NULL - not evaluating.\n")); return RULE_NOMATCH; } if (!DCE2_RoptDoEval(p)) return RULE_NOMATCH; sd = (DCE2_SsnData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_DCE2); if ((sd == NULL) || DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; if ((ropts->data_byte_order == DCE2_SENTINEL) || (ropts->hdr_byte_order == DCE2_SENTINEL)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Data byte order or header byte order not set " "in rule options - not evaluating.\n")); return RULE_NOMATCH; } bt_data = (DCE2_ByteTestData *)data; if (bt_data == NULL) return RULE_NOMATCH; if (_dpd.Is_DetectFlag(SF_FLAG_ALT_DETECT)) { _dpd.GetAltDetect((uint8_t **)&start_ptr, &dsize); DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Using Alternative Detect buffer!\n");); } else { start_ptr = p->payload; dsize = p->payload_size; } /* Make sure we don't read past the end of the payload or before * beginning of payload */ if (bt_data->relative) { if ((bt_data->offset < 0) && (*cursor + bt_data->offset) < start_ptr) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Offset is negative and puts cursor before beginning " "of payload - not evaluating.\n")); return RULE_NOMATCH; } if ((*cursor + bt_data->offset + bt_data->num_bytes) > (start_ptr + dsize)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Offset plus number of bytes to read puts cursor past " "end of payload - not evaluating.\n")); return RULE_NOMATCH; } bt_ptr = *cursor + bt_data->offset; } else { if (bt_data->offset < 0) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Offset is negative but is not relative - " "not evaluating.\n")); return RULE_NOMATCH; } else if ((start_ptr + bt_data->offset + bt_data->num_bytes) > (start_ptr + dsize)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Offset plus number of bytes to read puts cursor past " "end of payload - not evaluating.\n")); return RULE_NOMATCH; } bt_ptr = start_ptr + bt_data->offset; } /* Determine which byte order to use */ if (ropts->stub_data == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Stub data is NULL. Setting byte order to that " "of the header.\n")); byte_order = (DceRpcBoFlag)ropts->hdr_byte_order; } else if (bt_ptr < ropts->stub_data) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Reading data in the header. Setting byte order " "to that of the header.\n")); byte_order = (DceRpcBoFlag)ropts->hdr_byte_order; } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Reading data in the stub. Setting byte order " "to that of the stub data.\n")); byte_order = (DceRpcBoFlag)ropts->data_byte_order; } /* Get the value */ switch (bt_data->num_bytes) { case 1: pkt_value = *((uint8_t *)bt_ptr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Got 1 byte: %u.\n", pkt_value)); break; case 2: pkt_value = DceRpcNtohs((uint16_t *)bt_ptr, byte_order); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Got 2 bytes: %u.\n", pkt_value)); break; case 4: pkt_value = DceRpcNtohl((uint32_t *)bt_ptr, byte_order); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Got 4 bytes: %u.\n", pkt_value)); break; default: return RULE_NOMATCH; } /* Invert the return value. */ if (bt_data->invert) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Applying not flag.\n")); ret = RULE_MATCH; } switch (bt_data->operator) { case DCE2_BT_OP__LT: if (pkt_value < bt_data->value) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Packet value (%u) < Option value (%u).\n", pkt_value, bt_data->value)); if (ret == RULE_MATCH) ret = RULE_NOMATCH; else ret = RULE_MATCH; } break; case DCE2_BT_OP__EQ: if (pkt_value == bt_data->value) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Packet value (%u) == Option value (%u).\n", pkt_value, bt_data->value)); if (ret == RULE_MATCH) ret = RULE_NOMATCH; else ret = RULE_MATCH; } break; case DCE2_BT_OP__GT: if (pkt_value > bt_data->value) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Packet value (%u) > Option value (%u).\n", pkt_value, bt_data->value)); if (ret == RULE_MATCH) ret = RULE_NOMATCH; else ret = RULE_MATCH; } break; case DCE2_BT_OP__AND: if (pkt_value & bt_data->value) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Packet value (%08x) & Option value (%08x).\n", pkt_value, bt_data->value)); if (ret == RULE_MATCH) ret = RULE_NOMATCH; else ret = RULE_MATCH; } break; case DCE2_BT_OP__XOR: if (pkt_value ^ bt_data->value) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Packet value (%08x) ^ Option value (%08x).\n", pkt_value, bt_data->value)); if (ret == RULE_MATCH) ret = RULE_NOMATCH; else ret = RULE_MATCH; } break; default: return RULE_NOMATCH; } #ifdef DEBUG_MSGS if (ret == RULE_MATCH) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "\"%s\" Match.\n", DCE2_ROPT__BYTE_TEST)); } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "\"%s\" Fail.\n", DCE2_ROPT__BYTE_TEST)); } #endif return ret; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_ByteJumpEval(void *pkt, const uint8_t **cursor, void *data) { SFSnortPacket *p = (SFSnortPacket *)pkt; DCE2_SsnData *sd; DCE2_Roptions *ropts; DCE2_ByteJumpData *bj_data; const uint8_t *start_ptr; uint16_t dsize; const uint8_t *bj_ptr; uint32_t jmp_value; DceRpcBoFlag byte_order; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Evaluating \"%s\" rule option.\n", DCE2_ROPT__BYTE_JUMP)); if (*cursor == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Cursor is NULL - not evaluating.\n")); return RULE_NOMATCH; } if (!DCE2_RoptDoEval(p)) return RULE_NOMATCH; sd = (DCE2_SsnData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_DCE2); if ((sd == NULL) || DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "No session data - not evaluating.\n")); return RULE_NOMATCH; } ropts = &sd->ropts; if ((ropts->data_byte_order == DCE2_SENTINEL) || (ropts->hdr_byte_order == DCE2_SENTINEL)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Data byte order or header byte order not set " "in rule options - not evaluating.\n")); return RULE_NOMATCH; } bj_data = (DCE2_ByteJumpData *)data; if (bj_data == NULL) return RULE_NOMATCH; if (_dpd.Is_DetectFlag(SF_FLAG_ALT_DETECT)) { _dpd.GetAltDetect((uint8_t **)&start_ptr, &dsize); DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Using Alternative Detect buffer!\n");); } else { start_ptr = p->payload; dsize = p->payload_size; } /* Make sure we don't read past the end of the payload or before * beginning of payload */ if (bj_data->relative) { if ((bj_data->offset < 0) && (*cursor + bj_data->offset) < start_ptr) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Offset is negative and puts cursor before beginning " "of payload - not evaluating.\n")); return RULE_NOMATCH; } if ((*cursor + bj_data->offset + bj_data->num_bytes) > (start_ptr + dsize)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Offset plus number of bytes to read puts cursor past " "end of payload - not evaluating.\n")); return RULE_NOMATCH; } bj_ptr = *cursor + bj_data->offset; } else { if (bj_data->offset < 0) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Offset is negative but is not relative - " "not evaluating.\n")); return RULE_NOMATCH; } else if ((start_ptr + bj_data->offset + bj_data->num_bytes) > (start_ptr + dsize)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Offset plus number of bytes to read puts cursor past " "end of payload - not evaluating.\n")); return RULE_NOMATCH; } bj_ptr = start_ptr + bj_data->offset; } /* Determine which byte order to use */ if (ropts->stub_data == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Stub data is NULL. " "Setting byte order to that of the header.\n")); byte_order = (DceRpcBoFlag)ropts->hdr_byte_order; } else if (bj_ptr < ropts->stub_data) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Reading data in the header. Setting byte order " "to that of the header.\n")); byte_order = (DceRpcBoFlag)ropts->hdr_byte_order; } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Reading data in the stub. Setting byte order " "to that of the stub data.\n")); byte_order = (DceRpcBoFlag)ropts->data_byte_order; } /* Get the value */ switch (bj_data->num_bytes) { case 1: jmp_value = *((uint8_t *)bj_ptr); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Got 1 byte: %u.\n", jmp_value)); break; case 2: jmp_value = DceRpcNtohs((uint16_t *)bj_ptr, byte_order); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Got 2 bytes: %u.\n", jmp_value)); break; case 4: jmp_value = DceRpcNtohl((uint32_t *)bj_ptr, byte_order); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Got 4 bytes: %u.\n", jmp_value)); break; default: return 0; } if (bj_data->multiplier != DCE2_SENTINEL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Applying multiplier: %u * %u = %u.\n", jmp_value, bj_data->multiplier, jmp_value * bj_data->multiplier)); jmp_value *= bj_data->multiplier; } if (bj_data->align && (jmp_value & 3)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Aligning to 4 byte boundary: %u => %u.\n", jmp_value, jmp_value + (4 - (jmp_value & 3)))); jmp_value += (4 - (jmp_value & 3)); } bj_ptr += bj_data->num_bytes + jmp_value + bj_data->post_offset; if ((bj_ptr < start_ptr) || (bj_ptr >= (start_ptr + dsize))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "\"%s\" Fail. Jump puts us past end of payload.\n", DCE2_ROPT__BYTE_JUMP)); return RULE_NOMATCH; } *cursor = bj_ptr; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "\"%s\" Match.\n", DCE2_ROPT__BYTE_JUMP)); return RULE_MATCH; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DCE2_RoptDoEval(SFSnortPacket *p) { if ((p->payload_size == 0) || (p->stream_session_ptr == NULL) || (!IsTCP(p) && !IsUDP(p))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "No payload or no " "session pointer or not TCP or UDP - not evaluating.\n")); return 0; } return 1; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_IfaceCleanup(void *data) { if (data == NULL) return; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MEMORY, "Cleaning Iface data: %u bytes.\n", sizeof(DCE2_IfaceData))); DCE2_Free(data, sizeof(DCE2_IfaceData), DCE2_MEM_TYPE__ROPTION); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_OpnumCleanup(void *data) { DCE2_OpnumData *odata = (DCE2_OpnumData *)data; if (data == NULL) return; switch (odata->type) { case DCE2_OPNUM_TYPE__SINGLE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MEMORY, "Cleaning Single opnum data: %u bytes.\n", sizeof(DCE2_OpnumSingle))); DCE2_Free((void *)odata, sizeof(DCE2_OpnumSingle), DCE2_MEM_TYPE__ROPTION); break; case DCE2_OPNUM_TYPE__MULTIPLE: { DCE2_OpnumMultiple *omult = (DCE2_OpnumMultiple *)odata; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MEMORY, "Cleaning Multiple opnum data: %u bytes.\n", sizeof(DCE2_OpnumMultiple) + omult->mask_size)); if (omult->mask != NULL) DCE2_Free((void *)omult->mask, omult->mask_size, DCE2_MEM_TYPE__ROPTION); DCE2_Free((void *)omult, sizeof(DCE2_OpnumMultiple), DCE2_MEM_TYPE__ROPTION); } break; default: break; } } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_ByteTestCleanup(void *data) { if (data == NULL) return; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MEMORY, "Cleaning ByteTest data: %u bytes.\n", sizeof(DCE2_ByteTestData))); DCE2_Free(data, sizeof(DCE2_ByteTestData), DCE2_MEM_TYPE__ROPTION); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_ByteJumpCleanup(void *data) { if (data == NULL) return; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MEMORY, "Cleaning ByteJump data: %u bytes.\n", sizeof(DCE2_ByteJumpData))); DCE2_Free(data, sizeof(DCE2_ByteJumpData), DCE2_MEM_TYPE__ROPTION); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static uint32_t DCE2_IfaceHash(void *data) { uint32_t a, b, c; DCE2_IfaceData *iface_data = (DCE2_IfaceData *)data; if (iface_data == NULL) return 0; a = iface_data->iface.time_low; b = (iface_data->iface.time_mid << 16) | (iface_data->iface.time_high_and_version); c = (iface_data->iface.clock_seq_and_reserved << 24) | (iface_data->iface.clock_seq_low << 16) | (iface_data->iface.node[0] << 8) | (iface_data->iface.node[1]); mix(a, b, c); a += (iface_data->iface.node[2] << 24) | (iface_data->iface.node[3] << 16) | (iface_data->iface.node[4] << 8) | (iface_data->iface.node[5]); b += iface_data->iface_vers; c += iface_data->iface_vers_maj; mix(a, b, c); a += iface_data->iface_vers_min; b += iface_data->operator; c += iface_data->any_frag; final(a, b, c); return c; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static uint32_t DCE2_OpnumHash(void *data) { uint32_t a = 0, b = 0, c = 0; DCE2_OpnumData *odata = (DCE2_OpnumData *)data; if (odata == NULL) return 0; switch (odata->type) { case DCE2_OPNUM_TYPE__SINGLE: { DCE2_OpnumSingle *osingle = (DCE2_OpnumSingle *)odata; a = odata->type; b = osingle->opnum; c = 10; final(a, b, c); } break; case DCE2_OPNUM_TYPE__MULTIPLE: { DCE2_OpnumMultiple *omult = (DCE2_OpnumMultiple *)odata; unsigned int i; a = odata->type; b = omult->mask_size; c = 0; /* Don't care about potential wrapping if it exists */ for (i = 0; i < omult->mask_size; i++) c += omult->mask[i]; mix(a, b, c); a = omult->opnum_lo; b = omult->opnum_hi; c = 10; final(a, b, c); } break; default: DCE2_Die("%s(%d) Invalid opnum type: %d", __FILE__, __LINE__, odata->type); break; } return c; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static uint32_t DCE2_ByteTestHash(void *data) { uint32_t a, b, c; DCE2_ByteTestData *bt_data = (DCE2_ByteTestData *)data; if (bt_data == NULL) return 0; a = bt_data->num_bytes; b = bt_data->value; c = bt_data->invert; mix(a, b, c); a += bt_data->operator; b += bt_data->offset; c += bt_data->relative; final(a, b, c); return c; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static uint32_t DCE2_ByteJumpHash(void *data) { uint32_t a, b, c; DCE2_ByteJumpData *bj_data = (DCE2_ByteJumpData *)data; if (bj_data == NULL) return 0; a = bj_data->num_bytes; b = bj_data->offset; c = bj_data->relative; mix(a, b, c); a += bj_data->multiplier; b += bj_data->align; final(a, b, c); return c; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_IfaceKeyCompare(void *l, void *r) { DCE2_IfaceData *left = (DCE2_IfaceData *)l; DCE2_IfaceData *right = (DCE2_IfaceData *)r; if ((left == NULL) || (right == NULL)) return PREPROC_OPT_NOT_EQUAL; if ((DCE2_UuidCompare(&left->iface, &right->iface) == 0) && (left->iface_vers == right->iface_vers) && (left->iface_vers_maj == right->iface_vers_maj) && (left->iface_vers_min == right->iface_vers_min) && (left->operator == right->operator) && (left->any_frag == right->any_frag)) { return PREPROC_OPT_EQUAL; } return PREPROC_OPT_NOT_EQUAL; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_OpnumKeyCompare(void *l, void *r) { DCE2_OpnumData *left = (DCE2_OpnumData *)l; DCE2_OpnumData *right = (DCE2_OpnumData *)r; if ((left == NULL) || (right == NULL)) return PREPROC_OPT_NOT_EQUAL; if (left->type != right->type) return PREPROC_OPT_NOT_EQUAL; switch (left->type) { case DCE2_OPNUM_TYPE__SINGLE: { DCE2_OpnumSingle *lsingle = (DCE2_OpnumSingle *)left; DCE2_OpnumSingle *rsingle = (DCE2_OpnumSingle *)right; if (lsingle->opnum != rsingle->opnum) return PREPROC_OPT_NOT_EQUAL; } break; case DCE2_OPNUM_TYPE__MULTIPLE: { unsigned int i; DCE2_OpnumMultiple *lmult = (DCE2_OpnumMultiple *)left; DCE2_OpnumMultiple *rmult = (DCE2_OpnumMultiple *)right; if ((lmult->mask_size != rmult->mask_size) || (lmult->opnum_lo != rmult->opnum_lo) || (lmult->opnum_hi != rmult->opnum_hi)) { return PREPROC_OPT_NOT_EQUAL; } for (i = 0; i < lmult->mask_size; i++) { if (lmult->mask[i] != rmult->mask[i]) return PREPROC_OPT_NOT_EQUAL; } } break; default: DCE2_Die("%s(%d) Invalid opnum type: %d", __FILE__, __LINE__, left->type); break; } return PREPROC_OPT_EQUAL; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_ByteTestKeyCompare(void *l, void *r) { DCE2_ByteTestData *left = (DCE2_ByteTestData *)l; DCE2_ByteTestData *right = (DCE2_ByteTestData *)r; if ((left == NULL) || (right == NULL)) return PREPROC_OPT_NOT_EQUAL; if ((left->num_bytes == right->num_bytes) && (left->value == right->value) && (left->invert == right->invert) && (left->operator == right->operator) && (left->offset == right->offset) && (left->relative == right->relative)) { return PREPROC_OPT_EQUAL; } return PREPROC_OPT_NOT_EQUAL; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_ByteJumpKeyCompare(void *l, void *r) { DCE2_ByteJumpData *left = (DCE2_ByteJumpData *)l; DCE2_ByteJumpData *right = (DCE2_ByteJumpData *)r; if ((left == NULL) || (right == NULL)) return PREPROC_OPT_NOT_EQUAL; if ((left->num_bytes == right->num_bytes) && (left->offset == right->offset) && (left->relative == right->relative) && (left->multiplier == right->multiplier) && (left->align == right->align)) { return PREPROC_OPT_EQUAL; } return PREPROC_OPT_NOT_EQUAL; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_PrintRoptions(DCE2_Roptions *ropts) { printf(" First frag: %s\n", ropts->first_frag == 1 ? "yes" : (ropts->first_frag == 0 ? "no" : "unset")); if (ropts->first_frag == DCE2_SENTINEL) { printf(" Iface: unset\n"); printf(" Iface version: unset\n"); } else { printf(" Iface: %s\n", DCE2_UuidToStr(&ropts->iface, DCERPC_BO_FLAG__NONE)); printf(" Iface version: %u\n", ropts->iface_vers_maj); } if (ropts->opnum == DCE2_SENTINEL) printf(" Opnum: unset\n"); else printf(" Opnum: %u\n", ropts->opnum); printf(" Header byte order: %s\n", ropts->hdr_byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN ? "little endian" : (ropts->hdr_byte_order == DCERPC_BO_FLAG__BIG_ENDIAN ? "big endian" : "unset")); printf(" Data byte order: %s\n", ropts->data_byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN ? "little endian" : (ropts->data_byte_order == DCERPC_BO_FLAG__BIG_ENDIAN ? "big endian" : "unset")); if (ropts->stub_data != NULL) printf(" Stub data: %p\n", ropts->stub_data); else printf(" Stub data: NULL\n"); } /******************************************************************** * Function: DCE2_RoptError() * * Prints rule option error and dies. * * Arguments: * const char * * Format string * ... * Arguments to format string * * Returns: None * ********************************************************************/ static NORETURN void DCE2_RoptError(const char *format, ...) { char buf[1024]; va_list ap; va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); buf[sizeof(buf) - 1] = '\0'; DCE2_Die("%s(%d): %s Please consult documentation.", *_dpd.config_file, *_dpd.config_line, buf); } /********************************** * Function: DCE2_GetByteOrder() * * Gets the byte order needed for a byte_test, byte_jump, or byte_extract. * * Arguments: * Packet * * packet being evaluated * int32_t * offset into the packet payload where the rule will be evaluated. * calling function is responsible for checking that the offset is in-bounds. * * Returns: * DCE2_SENTINEL (-1) if byte order not set, or otherwise not evaluating * BIG (0) if byte order is big-endian * LITTLE (1) if byte order is little-endian * **********************************/ #define BIG 0 #define LITTLE 1 int DCE2_GetByteOrder(void *data, int32_t offset) { DCE2_SsnData *sd; DCE2_Roptions *ropts; DceRpcBoFlag byte_order; const uint8_t *data_ptr; SFSnortPacket *p = (SFSnortPacket *)data; if (p == NULL) return -1; sd = (DCE2_SsnData *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_DCE2); if ((sd == NULL) || DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "No session data - not evaluating.\n")); return -1; } ropts = &sd->ropts; if ((ropts->data_byte_order == DCE2_SENTINEL) || (ropts->hdr_byte_order == DCE2_SENTINEL)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Data byte order or header byte order not set " "in rule options - not evaluating.\n")); return -1; } /* Determine which byte order to use */ data_ptr = p->payload + offset; if (ropts->stub_data == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Stub data is NULL. " "Setting byte order to that of the header.\n")); byte_order = (DceRpcBoFlag)ropts->hdr_byte_order; } else if (data_ptr < ropts->stub_data) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Reading data in the header. Setting byte order " "to that of the header.\n")); byte_order = (DceRpcBoFlag)ropts->hdr_byte_order; } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, "Reading data in the stub. Setting byte order " "to that of the stub data.\n")); byte_order = (DceRpcBoFlag)ropts->data_byte_order; } /* Return ints, since this enum doesn't exist back in Snort-land. */ if (byte_order == DCERPC_BO_FLAG__BIG_ENDIAN) return BIG; if (byte_order == DCERPC_BO_FLAG__LITTLE_ENDIAN) return LITTLE; return -1; } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_config.h0000644000000000000000000011307312260565732020716 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides convenience functions for parsing and querying configuration. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _DCE2_CONFIG_H_ #define _DCE2_CONFIG_H_ #include "dce2_debug.h" #include "dce2_utils.h" #include "dce2_list.h" #include "sf_types.h" #include "sf_ip.h" #include "sfrt.h" #include "sf_snort_packet.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" /******************************************************************** * Macros ********************************************************************/ #define DCE2_GNAME "dcerpc2" #define DCE2_SNAME "dcerpc2_server" #define DCE2_CFG_TOK__DASH '-' #define DCE2_CFG_TOK__UNDERSCORE '_' #define DCE2_CFG_TOK__QUOTE '"' #define DCE2_CFG_TOK__LIST_START '[' #define DCE2_CFG_TOK__LIST_END ']' #define DCE2_CFG_TOK__OPT_SEP ',' #define DCE2_CFG_TOK__LIST_SEP ',' #define DCE2_CFG_TOK__PORT_RANGE ':' #define DCE2_CFG_TOK__OPNUM_RANGE '-' #define DCE2_CFG_TOK__DOT '.' #define DCE2_CFG_TOK__IP6_TET_SEP ':' #define DCE2_CFG_TOK__IP4_TET_SEP '.' #define DCE2_CFG_TOK__IP_PREFIX_SEP '/' #define DCE2_CFG_TOK__MINUS '-' #define DCE2_CFG_TOK__PLUS '+' #define DCE2_CFG_TOK__HEX_SEP 'x' #define DCE2_CFG_TOK__HEX_OCT_START '0' #define DCE2_CFG_TOK__END '\0' #define DCE2_PORTS__MAX (UINT16_MAX + 1) #define DCE2_PORTS__MAX_INDEX (DCE2_PORTS__MAX / 8) #define DCE2_MEMCAP__DEFAULT (100 * 1024) /* 100 MB */ /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_Policy { DCE2_POLICY__NONE, DCE2_POLICY__WIN2000, DCE2_POLICY__WINXP, DCE2_POLICY__WINVISTA, DCE2_POLICY__WIN2003, DCE2_POLICY__WIN2008, DCE2_POLICY__WIN7, DCE2_POLICY__SAMBA, DCE2_POLICY__SAMBA_3_0_37, DCE2_POLICY__SAMBA_3_0_22, DCE2_POLICY__SAMBA_3_0_20, DCE2_POLICY__MAX } DCE2_Policy; typedef enum _DCE2_DetectFlag { DCE2_DETECT_FLAG__NULL = 0x0000, DCE2_DETECT_FLAG__NONE = 0x0001, DCE2_DETECT_FLAG__SMB = 0x0002, DCE2_DETECT_FLAG__TCP = 0x0004, DCE2_DETECT_FLAG__UDP = 0x0008, DCE2_DETECT_FLAG__HTTP_PROXY = 0x0010, DCE2_DETECT_FLAG__HTTP_SERVER = 0x0020, DCE2_DETECT_FLAG__ALL = 0xffff } DCE2_DetectFlag; typedef enum _DCE2_EventFlag { DCE2_EVENT_FLAG__NULL = 0x0000, DCE2_EVENT_FLAG__NONE = 0x0001, DCE2_EVENT_FLAG__MEMCAP = 0x0002, DCE2_EVENT_FLAG__SMB = 0x0004, DCE2_EVENT_FLAG__CO = 0x0008, DCE2_EVENT_FLAG__CL = 0x0010, DCE2_EVENT_FLAG__ALL = 0xffff } DCE2_EventFlag; typedef enum _DCE2_ValidSmbVersionFlag { DCE2_VALID_SMB_VERSION_FLAG__NULL = 0x0000, DCE2_VALID_SMB_VERSION_FLAG__V1 = 0x0001, DCE2_VALID_SMB_VERSION_FLAG__V2 = 0x0002, DCE2_VALID_SMB_VERSION_FLAG__ALL = 0xffff } DCE2_ValidSmbVersionFlag; typedef enum _DCE2_SmbFingerprintFlag { DCE2_SMB_FINGERPRINT__NONE = 0x0000, DCE2_SMB_FINGERPRINT__CLIENT = 0x0001, DCE2_SMB_FINGERPRINT__SERVER = 0x0002 } DCE2_SmbFingerprintFlag; /* Whether an option is on or off: CS - configuration switch */ typedef enum _DCE2_CS { DCE2_CS__DISABLED = 0, DCE2_CS__ENABLED } DCE2_CS; typedef enum _DCE2_SmbFileInspection { DCE2_SMB_FILE_INSPECTION__OFF = 0, DCE2_SMB_FILE_INSPECTION__ON, DCE2_SMB_FILE_INSPECTION__ONLY } DCE2_SmbFileInspection; typedef enum _DCE2_WordCharPosition { DCE2_WORD_CHAR_POSITION__START, DCE2_WORD_CHAR_POSITION__MIDDLE, DCE2_WORD_CHAR_POSITION__END } DCE2_WordCharPosition; typedef enum _DCE2_WordListState { DCE2_WORD_LIST_STATE__START, DCE2_WORD_LIST_STATE__WORD_START, DCE2_WORD_LIST_STATE__QUOTE, DCE2_WORD_LIST_STATE__WORD, DCE2_WORD_LIST_STATE__WORD_END, DCE2_WORD_LIST_STATE__END } DCE2_WordListState; typedef enum _DCE2_ValueState { DCE2_VALUE_STATE__START, DCE2_VALUE_STATE__MODIFIER, DCE2_VALUE_STATE__HEX_OR_OCT, DCE2_VALUE_STATE__DECIMAL, DCE2_VALUE_STATE__HEX_START, DCE2_VALUE_STATE__HEX, DCE2_VALUE_STATE__OCTAL } DCE2_ValueState; typedef enum _DCE2_PortListState { DCE2_PORT_LIST_STATE__START, DCE2_PORT_LIST_STATE__PORT_START, DCE2_PORT_LIST_STATE__PORT_LO, DCE2_PORT_LIST_STATE__PORT_RANGE, DCE2_PORT_LIST_STATE__PORT_HI, DCE2_PORT_LIST_STATE__PORT_END, DCE2_PORT_LIST_STATE__END } DCE2_PortListState; typedef enum _DCE2_IpListState { DCE2_IP_LIST_STATE__START, DCE2_IP_LIST_STATE__IP_START, DCE2_IP_LIST_STATE__IP_END, DCE2_IP_LIST_STATE__END } DCE2_IpListState; typedef enum _DCE2_IpState { DCE2_IP_STATE__START, DCE2_IP_STATE__IP } DCE2_IpState; typedef enum _DCE2_IntType { DCE2_INT_TYPE__INT8, DCE2_INT_TYPE__UINT8, DCE2_INT_TYPE__INT16, DCE2_INT_TYPE__UINT16, DCE2_INT_TYPE__INT32, DCE2_INT_TYPE__UINT32, DCE2_INT_TYPE__INT64, DCE2_INT_TYPE__UINT64 } DCE2_IntType; /******************************************************************** * Structures ********************************************************************/ /* Global configuration struct */ typedef struct _DCE2_GlobalConfig { int disabled; uint32_t memcap; int event_mask; DCE2_CS dce_defrag; int max_frag_len; uint16_t reassemble_threshold; int smb_fingerprint_policy; } DCE2_GlobalConfig; typedef struct _DCE2_SmbShare { char *unicode_str; unsigned int unicode_str_len; char *ascii_str; unsigned int ascii_str_len; } DCE2_SmbShare; /* Server configuration struct */ typedef struct _DCE2_ServerConfig { DCE2_Policy policy; uint8_t smb_ports[DCE2_PORTS__MAX_INDEX]; uint8_t tcp_ports[DCE2_PORTS__MAX_INDEX]; uint8_t udp_ports[DCE2_PORTS__MAX_INDEX]; uint8_t http_proxy_ports[DCE2_PORTS__MAX_INDEX]; uint8_t http_server_ports[DCE2_PORTS__MAX_INDEX]; uint8_t auto_smb_ports[DCE2_PORTS__MAX_INDEX]; uint8_t auto_tcp_ports[DCE2_PORTS__MAX_INDEX]; uint8_t auto_udp_ports[DCE2_PORTS__MAX_INDEX]; uint8_t auto_http_proxy_ports[DCE2_PORTS__MAX_INDEX]; uint8_t auto_http_server_ports[DCE2_PORTS__MAX_INDEX]; uint8_t smb_max_chain; uint8_t smb2_max_compound; DCE2_CS autodetect_http_proxy_ports; DCE2_SmbFileInspection smb_file_inspection; int64_t smb_file_depth; DCE2_List *smb_invalid_shares; int valid_smb_versions_mask; /* Used when freeing from routing table */ uint32_t ref_count; } DCE2_ServerConfig; typedef struct _DCE2_Config { DCE2_GlobalConfig *gconfig; DCE2_ServerConfig *dconfig; table_t *sconfigs; uint32_t ref_count; #ifdef DCE2_LOG_EXTRA_DATA uint32_t xtra_logging_smb_file_name_id; #endif } DCE2_Config; /******************************************************************** * Extern variables ********************************************************************/ extern DCE2_Config *dce2_eval_config; extern tSfPolicyUserContextId dce2_config; extern DCE2_Config *dce2_eval_config; /******************************************************************** * Inline function prototypes ********************************************************************/ static inline uint32_t DCE2_GcMemcap(void); static inline int DCE2_GcMaxFrag(void); static inline uint16_t DCE2_GcMaxFragLen(void); static inline int DCE2_GcAlertOnEvent(DCE2_EventFlag); static inline int DCE2_GcReassembleEarly(void); static inline uint16_t DCE2_GcReassembleThreshold(void); static inline DCE2_CS DCE2_GcDceDefrag(void); static inline bool DCE2_GcSmbFingerprintClient(void); static inline bool DCE2_GcSmbFingerprintServer(void); static inline DCE2_Policy DCE2_ScPolicy(const DCE2_ServerConfig *); static inline int DCE2_ScIsDetectPortSet(const DCE2_ServerConfig *, const uint16_t, const DCE2_TransType); static inline int DCE2_ScIsAutodetectPortSet(const DCE2_ServerConfig *, const uint16_t, const DCE2_TransType); static inline DCE2_CS DCE2_ScAutodetectHttpProxyPorts(const DCE2_ServerConfig *); static inline uint8_t DCE2_ScSmbMaxChain(const DCE2_ServerConfig *); static inline DCE2_List * DCE2_ScSmbInvalidShares(const DCE2_ServerConfig *); static inline bool DCE2_ScSmbFileInspection(const DCE2_ServerConfig *); static inline bool DCE2_ScSmbFileInspectionOnly(const DCE2_ServerConfig *); static inline int64_t DCE2_ScSmbFileDepth(const DCE2_ServerConfig *); static inline uint8_t DCE2_ScSmb2MaxCompound(const DCE2_ServerConfig *); static inline uint8_t DCE2_ScIsValidSmbVersion(const DCE2_ServerConfig *, DCE2_ValidSmbVersionFlag); static inline int DCE2_IsPortSet(const uint8_t *, const uint16_t); static inline void DCE2_SetPort(uint8_t *, const uint16_t); static inline void DCE2_SetPortRange(uint8_t *, uint16_t, uint16_t); static inline void DCE2_ClearPorts(uint8_t *); static inline int DCE2_IsWordChar(const char, const DCE2_WordCharPosition); static inline int DCE2_IsGraphChar(const char); static inline int DCE2_IsQuoteChar(const char); static inline int DCE2_IsListSepChar(const char); static inline int DCE2_IsOptEndChar(const char); static inline int DCE2_IsSpaceChar(const char); static inline int DCE2_IsConfigEndChar(const char); static inline int DCE2_IsPortChar(const char); static inline int DCE2_IsPortRangeChar(const char); static inline int DCE2_IsListStartChar(const char); static inline int DCE2_IsListEndChar(const char); static inline int DCE2_IsIpChar(const char); static inline DCE2_Ret DCE2_CheckAndSetMask(int, int *); /******************************************************************** * Public function prototypes ********************************************************************/ void DCE2_GlobalConfigure(DCE2_Config *, char *); void DCE2_ServerConfigure(struct _SnortConfig *, DCE2_Config *, char *); int DCE2_CreateDefaultServerConfig(struct _SnortConfig *, DCE2_Config *, tSfPolicyId); int DCE2_ScCheckTransports(DCE2_Config *); const DCE2_ServerConfig * DCE2_ScGetConfig(const SFSnortPacket *); int DCE2_ScIsPortSet(const DCE2_ServerConfig *, const uint16_t, const DCE2_TransType); int DCE2_ScIsDetectPortSet(const DCE2_ServerConfig *, const uint16_t, const DCE2_TransType); int DCE2_ScIsAutodetectPortSet(const DCE2_ServerConfig *, const uint16_t, const DCE2_TransType); int DCE2_ScIsNoAutoPortSet(const DCE2_ServerConfig *, const uint16_t); DCE2_Ret DCE2_ParseValue(char **, char *, void *, DCE2_IntType); DCE2_Ret DCE2_GetValue(char *, char *, void *, int, DCE2_IntType, uint8_t); DCE2_Ret DCE2_ParseIpList(char **, char *, DCE2_Queue *); DCE2_Ret DCE2_ParseIp(char **, char *, sfip_t *); DCE2_Ret DCE2_ParsePortList(char **, char *, uint8_t *); void DCE2_FreeConfigs(tSfPolicyUserContextId config); void DCE2_FreeConfig(DCE2_Config *); /******************************************************************** * Function: DCE2_GcMemcap() * * Convenience function for getting the memcap configured for * the preprocessor. * * Arguments: None * * Returns: * uint32_t * The memcap configured for the preprocessor. * ********************************************************************/ static inline uint32_t DCE2_GcMemcap(void) { return dce2_eval_config->gconfig->memcap; } /******************************************************************** * Function: DCE2_GcMaxFrag() * * Convenience function for checking if the maximum fragment length * was configured for the preprocessor. * * Arguments: None * * Returns: * int * 1 if it was configured. * 0 if it was not configured. * ********************************************************************/ static inline int DCE2_GcMaxFrag(void) { if (dce2_eval_config->gconfig->max_frag_len != DCE2_SENTINEL) return 1; return 0; } /******************************************************************** * Function: DCE2_GcMaxFragLen() * * Convenience function for getting the maximum fragment length * that is configured for the preprocessor. If not configured, * just return the maximum the return value can hold. One should * check if configured first. * * Arguments: None * * Returns: * uint16_t * The maximum fragment length configured. * UINT16_MAX if not configured. * ********************************************************************/ static inline uint16_t DCE2_GcMaxFragLen(void) { if (DCE2_GcMaxFrag()) return (uint16_t)dce2_eval_config->gconfig->max_frag_len; return UINT16_MAX; } /******************************************************************** * Function: DCE2_GcAlertOnEvent() * * Convenience function for determining if we are configured * to alert on a certain event type. * * Arguments: * DCE2_EventFlag * The event type to check to see if we are configured * to alert on. * * Returns: * int * Non-zero if we are configured to alert on this event type. * Zero if we are not configured to alert on this event type. * ********************************************************************/ static inline int DCE2_GcAlertOnEvent(DCE2_EventFlag eflag) { return dce2_eval_config->gconfig->event_mask & eflag; } /******************************************************************** * Function: DCE2_GcDceDefrag() * * Convenience function for determining if we are configured * to do DCE/RPC defragmentation. * * Arguments: None * * Returns: * DCE2_CS * DCE2_CS__ENABLED if we are configured to do DCE/RPC * defragmentation. * DCE2_CS__DISABLED if we are not configured to do DCE/RPC * defragmentation. * ********************************************************************/ static inline DCE2_CS DCE2_GcDceDefrag(void) { return dce2_eval_config->gconfig->dce_defrag; } /******************************************************************** * Function: DCE2_GcReassembleEarly() * * Convenience function for checking if the reassemble threshold * was configured for the preprocessor. * * Arguments: None * * Returns: * int * 1 if it was configured. * 0 if it was not configured. * ********************************************************************/ static inline int DCE2_GcReassembleEarly(void) { if (dce2_eval_config->gconfig->reassemble_threshold > 0) return 1; return 0; } /******************************************************************** * Function: DCE2_GcReassembleThreshold() * * Convenience function for getting the reassemble threshold * that is configured for the preprocessor. If not configured, * just return the maximum the return value can hold. One should * check if configured first. * * Arguments: None * * Returns: * uint16_t * The reassemble threshold configured. * UINT16_MAX if not configured. * ********************************************************************/ static inline uint16_t DCE2_GcReassembleThreshold(void) { if (DCE2_GcReassembleEarly()) return dce2_eval_config->gconfig->reassemble_threshold; return UINT16_MAX; } /******************************************************************** * Function: DCE2_GcSmbFingerprintClient() * * Convenience function for finding out if the preprocessor is * configured to fingerprint the client policy base off SMB * traffic. * * Arguments: None * * Returns: * bool - true if configure to fingerprint client, false if not * ********************************************************************/ static inline bool DCE2_GcSmbFingerprintClient(void) { return dce2_eval_config->gconfig->smb_fingerprint_policy & DCE2_SMB_FINGERPRINT__CLIENT ? true : false; } /******************************************************************** * Function: DCE2_GcSmbFingerprintServer() * * Convenience function for finding out if the preprocessor is * configured to fingerprint the server policy base off SMB * traffic. * * Arguments: None * * Returns: * bool - true if configure to fingerprint server, false if not * ********************************************************************/ static inline bool DCE2_GcSmbFingerprintServer(void) { return dce2_eval_config->gconfig->smb_fingerprint_policy & DCE2_SMB_FINGERPRINT__SERVER ? true : false; } /******************************************************************** * Function: DCE2_ScPolicy() * * Convenience function for getting the policy the server * configuration is configured for. * * Arguments: * const DCE2_ServerConfig * * Pointer to the server configuration to check. * * Returns: * DCE2_Policy * The policy the server configuration is configured for. * DCE2_POLICY__NONE if a NULL pointer is passed in. * ********************************************************************/ static inline DCE2_Policy DCE2_ScPolicy(const DCE2_ServerConfig *sc) { if (sc == NULL) return DCE2_POLICY__NONE; return sc->policy; } /********************************************************************* * Function: DCE2_ScIsDetectPortSet() * * Determines if the server configuration is configured to detect * on the port and transport passed in. * * Arguments: * const DCE2_ServerConfig * * Pointer to the server configuration to check. * const uint16_t * The port to check. * const DCE2_TransType * The transport to check for the port. * * Returns: * int * 1 if configured to detect on this port for the given * transport. * 0 if not configured to detect on this port for the given * transport, or if the server configuration passed in * is NULL. * *********************************************************************/ static inline int DCE2_ScIsDetectPortSet(const DCE2_ServerConfig *sc, const uint16_t port, const DCE2_TransType ttype) { const uint8_t *port_array; if (sc == NULL) return 0; switch (ttype) { case DCE2_TRANS_TYPE__SMB: port_array = sc->smb_ports; break; case DCE2_TRANS_TYPE__TCP: port_array = sc->tcp_ports; break; case DCE2_TRANS_TYPE__UDP: port_array = sc->udp_ports; break; case DCE2_TRANS_TYPE__HTTP_PROXY: port_array = sc->http_proxy_ports; break; case DCE2_TRANS_TYPE__HTTP_SERVER: port_array = sc->http_server_ports; break; default: return 0; } return DCE2_IsPortSet(port_array, port); } /********************************************************************* * Function: DCE2_ScIsAutodetectPortSet() * * Determines if the server configuration is configured to autodetect * on the port and transport passed in. * * Arguments: * const DCE2_ServerConfig * * Pointer to the server configuration to check. * const uint16_t * The port to check. * const DCE2_TransType * The transport to check for the port. * * Returns: * int * 1 if configured to autodetect on this port for the given * transport. * 0 if not configured to autodetect on this port for the given * transport, or if the server configuration passed in * is NULL. * *********************************************************************/ static inline int DCE2_ScIsAutodetectPortSet(const DCE2_ServerConfig *sc, const uint16_t port, const DCE2_TransType ttype) { const uint8_t *port_array; if (sc == NULL) return 0; switch (ttype) { case DCE2_TRANS_TYPE__SMB: port_array = sc->auto_smb_ports; break; case DCE2_TRANS_TYPE__TCP: port_array = sc->auto_tcp_ports; break; case DCE2_TRANS_TYPE__UDP: port_array = sc->auto_udp_ports; break; case DCE2_TRANS_TYPE__HTTP_PROXY: port_array = sc->auto_http_proxy_ports; break; case DCE2_TRANS_TYPE__HTTP_SERVER: port_array = sc->auto_http_server_ports; break; default: return 0; } return DCE2_IsPortSet(port_array, port); } /******************************************************************** * Function: DCE2_ScAutodetectHttpProxyPorts() * * Convenience function to determine if the server configuration * is configured to autodetect on all rpc over http proxy detect * ports. * * Arguments: * const DCE2_ServerConfig * * Pointer to the server configuration to check. * * Returns: * DCE2_CS * DCE2_CS__ENABLED if configured to autodetect on all rpc * over http proxy ports. This is also returned it the * server configuration passed in is NULL. * DCE2_CS__DISABLED if not configured to autodetect on all * rpc over http proxy ports. * ********************************************************************/ static inline DCE2_CS DCE2_ScAutodetectHttpProxyPorts(const DCE2_ServerConfig *sc) { if (sc == NULL) return DCE2_CS__ENABLED; return sc->autodetect_http_proxy_ports; } /******************************************************************** * Function: DCE2_ScSmbMaxChain() * * Convenience function to get the SMB maximum amount of command * chaining allowed. A value of 0 means unlimited. * * Arguments: * const DCE2_ServerConfig * * Pointer to the server configuration to check. * * Returns: * uint8_t * The value for the maximum amount of command chaining. * 0 is returned if the server configuration passed in is NULL. * ********************************************************************/ static inline uint8_t DCE2_ScSmbMaxChain(const DCE2_ServerConfig *sc) { if (sc == NULL) return 0; return sc->smb_max_chain; } /******************************************************************** * Function: DCE2_ScSmbInvalidShares() * * Returns the list of SMB invalid shares configured. If no * shares were configured, this will return a NULL list. * * Arguments: * const DCE2_ServerConfig * * Pointer to the server configuration to check. * * Returns: * DCE2_List * * Pointer to the list containing the SMB invalid share * strings. * NULL if no shares were configured or the server * configuration passed in is NULL. * ********************************************************************/ static inline DCE2_List * DCE2_ScSmbInvalidShares(const DCE2_ServerConfig *sc) { if (sc == NULL) return NULL; return sc->smb_invalid_shares; } static inline bool DCE2_ScSmbFileInspection(const DCE2_ServerConfig *sc) { if (sc == NULL) return false; return ((sc->smb_file_inspection == DCE2_SMB_FILE_INSPECTION__ON) || (sc->smb_file_inspection == DCE2_SMB_FILE_INSPECTION__ONLY)); } static inline bool DCE2_ScSmbFileInspectionOnly(const DCE2_ServerConfig *sc) { if (sc == NULL) return false; return sc->smb_file_inspection == DCE2_SMB_FILE_INSPECTION__ONLY; } static inline int64_t DCE2_ScSmbFileDepth(const DCE2_ServerConfig *sc) { if (!DCE2_ScSmbFileInspection(sc)) return -1; return sc->smb_file_depth; } /******************************************************************** * Function: DCE2_ScSmb2MaxChain() * * Convenience function to get the SMB maximum amount of command * compounding allowed. A value of 0 means unlimited. * * Arguments: * const DCE2_ServerConfig * * Pointer to the server configuration to check. * * Returns: * uint8_t * The value for the maximum amount of command compounding. * 0 is returned if the server configuration passed in is NULL. * ********************************************************************/ static inline uint8_t DCE2_ScSmb2MaxCompound(const DCE2_ServerConfig *sc) { if (sc == NULL) return 0; return sc->smb2_max_compound; } /******************************************************************** * Function: DCE2_ScIsValidSmbVersion() * * Convenience function to check if an smb version flag is set. * * Arguments: * const DCE2_ServerConfig * * Pointer to the server configuration to check. * const DCE2_ValidSmbVersionFlag * The version flag to test * * Returns: * int * non-zero if the flag is set * 0 if the flag is not set * ********************************************************************/ static inline uint8_t DCE2_ScIsValidSmbVersion( const DCE2_ServerConfig *sc, DCE2_ValidSmbVersionFlag vflag) { if (sc == NULL) return 0; return sc->valid_smb_versions_mask & vflag; } /********************************************************************* * Function: DCE2_IsPortSet() * * Checks to see if a port is set in one in the port array mask * passed in. * * Arguments: * uint8_t * * Pointer to a port array mask. * const uint16_t * The port to check for in the mask. * * Returns: * int * Non-zero if the port is set. * Zero if the port is not set. * *********************************************************************/ static inline int DCE2_IsPortSet(const uint8_t *port_array, const uint16_t port) { return port_array[(port / 8)] & (1 << (port % 8)); } /********************************************************************* * Function: DCE2_SetPort() * * Sets a port in the port array mask passed in. * * Arguments: * uint8_t * * Pointer to a port array mask. * const uint16_t * The port to set in the port array mask. * * Returns: None * *********************************************************************/ static inline void DCE2_SetPort(uint8_t *port_array, const uint16_t port) { port_array[(port / 8)] |= (1 << (port % 8)); } /********************************************************************* * Function: DCE2_SetPortRange() * * Sets ports from lo to hi in one of the transport port * configurations. * * Arguments: * uint8_t * * Pointer to a port array mask. * uint16_t * The lo port to start setting ports in the port array mask. * uint16_t * The hi port to end setting ports in the port array mask. * * Returns: None * *********************************************************************/ static inline void DCE2_SetPortRange(uint8_t *port_array, uint16_t lo_port, uint16_t hi_port) { unsigned int i; if (lo_port > hi_port) { uint16_t tmp = lo_port; lo_port = hi_port; hi_port = tmp; } for (i = lo_port; i <= hi_port; i++) DCE2_SetPort(port_array, (uint16_t)i); } /******************************************************************** * Function: DCE2_ClearPorts() * * Clears all of the port bits set in the port array mask. * * Arguments: * uint8_t * * Pointer to a port array mask. * * Returns: None * ********************************************************************/ static inline void DCE2_ClearPorts(uint8_t *port_array) { memset(port_array, 0, DCE2_PORTS__MAX_INDEX); } /******************************************************************** * Function: DCE2_IsWordChar() * * Determines if a character is a valid word character based on * position in the word. Of course, this is the preprocessor's * definition. Mainly used for restricting preprocessor option * names and set argument names. * * Arguments: * const char * The character to make the determination on. * DCE2_WordCharPosition * The position in the word the character is. * * Returns: * int * 1 if a valid word character. * 0 if not a valid word character. * ********************************************************************/ static inline int DCE2_IsWordChar(const char c, const DCE2_WordCharPosition pos) { if (pos == DCE2_WORD_CHAR_POSITION__START) { if (isalpha((int)c)) return 1; } else if (pos == DCE2_WORD_CHAR_POSITION__MIDDLE) { if (isalpha((int)c) || isdigit((int)c) || (c == DCE2_CFG_TOK__DASH) || (c == DCE2_CFG_TOK__UNDERSCORE) || (c == DCE2_CFG_TOK__DOT)) { return 1; } } else if (pos == DCE2_WORD_CHAR_POSITION__END) { if (isalpha((int)c) || isdigit((int)c)) return 1; } return 0; } /******************************************************************** * Function: DCE2_IsListSepChar() * * Determines if the character passed in is a character that * separates values in lists. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid list separator character. * 0 if not a valid list separator character. * ********************************************************************/ static inline int DCE2_IsListSepChar(const char c) { if (c == DCE2_CFG_TOK__LIST_SEP) return 1; return 0; } /******************************************************************** * Function: DCE2_IsOptEndChar() * * Determines if the character passed in is a character that * marks the end of an option and start of a new option. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid option end character. * 0 if not a valid option end character. * ********************************************************************/ static inline int DCE2_IsOptEndChar(const char c) { if (c == DCE2_CFG_TOK__OPT_SEP) return 1; return 0; } /******************************************************************** * Function: DCE2_IsSpaceChar() * * Determines if the character passed in is a character that * the preprocessor considers a to be a space character. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid space character. * 0 if not a valid space character. * ********************************************************************/ static inline int DCE2_IsSpaceChar(const char c) { if (isspace((int)c)) return 1; return 0; } /******************************************************************** * Function: DCE2_IsConfigEndChar() * * Determines if the character passed in is a character that * the preprocessor considers a to be an end of configuration * character. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid end of configuration character. * 0 if not a valid end of configuration character. * ********************************************************************/ static inline int DCE2_IsConfigEndChar(const char c) { if (c == DCE2_CFG_TOK__END) return 1; return 0; } /******************************************************************** * Function: DCE2_IsPortChar() * * Determines if the character passed in is a character that * the preprocessor considers a to be a valid character for a port. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid port character. * 0 if not a valid port character. * ********************************************************************/ static inline int DCE2_IsPortChar(const char c) { if (isdigit((int)c)) return 1; return 0; } /******************************************************************** * Function: DCE2_IsPortRangeChar() * * Determines if the character passed in is a character that can be * placed before, between or after a port to specify a port range. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid port range character. * 0 if not a valid port range character. * ********************************************************************/ static inline int DCE2_IsPortRangeChar(const char c) { if (c == DCE2_CFG_TOK__PORT_RANGE) return 1; return 0; } /******************************************************************** * Function: DCE2_IsOpnumChar() * * Determines if the character passed in is a character that * the preprocessor considers a to be a valid character for a * DCE/RPC opnum. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid DCE/RPC opnum character. * 0 if not a valid DCE/RPC opnum character. * ********************************************************************/ static inline int DCE2_IsOpnumChar(const char c) { if (isdigit((int)c)) return 1; return 0; } /******************************************************************** * Function: DCE2_IsOpnumRangeChar() * * Determines if the character passed in is a character that is * used to indicate a range of DCE/RPC opnums. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid DCE/RPC opnum range character. * 0 if not a valid DCE/RPC opnum range character. * ********************************************************************/ static inline int DCE2_IsOpnumRangeChar(const char c) { if (c == DCE2_CFG_TOK__OPNUM_RANGE) return 1; return 0; } /******************************************************************** * Function: DCE2_IsListStartChar() * * Determines if the character passed in is a character that is * used to indicate the start of a list. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid start of list character. * 0 if not a valid start of list character. * ********************************************************************/ static inline int DCE2_IsListStartChar(const char c) { if (c == DCE2_CFG_TOK__LIST_START) return 1; return 0; } /******************************************************************** * Function: DCE2_IsListEndChar() * * Determines if the character passed in is a character that is * used to indicate the end of a list. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid end of list character. * 0 if not a valid end of list character. * ********************************************************************/ static inline int DCE2_IsListEndChar(const char c) { if (c == DCE2_CFG_TOK__LIST_END) return 1; return 0; } /******************************************************************** * Function: DCE2_IsQuoteChar() * * Determines if the character passed in is a what the preprocessor * considers to be a quote character. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid quote character. * 0 if not a valid quote character. * ********************************************************************/ static inline int DCE2_IsQuoteChar(const char c) { if (c == DCE2_CFG_TOK__QUOTE) return 1; return 0; } /******************************************************************** * Function: DCE2_IsIpChar() * * Determines if the character passed in is a character that can * be used in an IP address - IPv4 or IPv6. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid IP character. * 0 if not a valid IP character. * ********************************************************************/ static inline int DCE2_IsIpChar(const char c) { if (isxdigit((int)c) || (c == DCE2_CFG_TOK__IP6_TET_SEP) || (c == DCE2_CFG_TOK__IP4_TET_SEP) || (c == DCE2_CFG_TOK__IP_PREFIX_SEP)) { return 1; } return 0; } /******************************************************************** * Function: DCE2_IsGraphChar() * * Determines is the character passed in is a graphical character. * Characters excluded are what the preprocessor considers as * meta characters or space characters. * * Arguments: * const char * The character to make the determination on. * * Returns: * int * 1 if a valid graphical character. * 0 if not a valid graphical character. * ********************************************************************/ static inline int DCE2_IsGraphChar(const char c) { if (!DCE2_IsListStartChar(c) && !DCE2_IsListEndChar(c) && !DCE2_IsQuoteChar(c) && !DCE2_IsListSepChar(c) && !DCE2_IsSpaceChar(c)) return 1; return 0; } /********************************************************************* * Function: DCE2_CheckAndSetMask() * * Checks to see if a flag passed in is already set in the mask * passed in. If it is, error is returned. If it is not, the * flag is set in the mask. * * Arguments: * int * The flag to check and set. * int * * The mask to check and set the flag against. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if the flag is already set in the mask. * DCE2_RET__SUCCESS if the flag is not already set in the mask. * *********************************************************************/ static inline DCE2_Ret DCE2_CheckAndSetMask(int flag, int *mask) { if (*mask & flag) return DCE2_RET__ERROR; *mask |= flag; return DCE2_RET__SUCCESS; } #endif /* _DCE2_CONFIG_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_config.c0000644000000000000000000052145012260565732020713 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Parses and processes configuration set in snort.conf. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_config.h" #include "dce2_utils.h" #include "dce2_list.h" #include "dce2_memory.h" #include "dce2_event.h" #include "dce2_session.h" #include "sf_dynamic_preprocessor.h" #include "sf_types.h" #include "sfrt.h" #include "sf_ip.h" #include #include #include #include #include #ifndef WIN32 #include #include #endif /* WIN32 */ #include #include /******************************************************************** * Global variables ********************************************************************/ tSfPolicyUserContextId dce2_config = NULL; DCE2_Config *dce2_eval_config = NULL; /* Default ports */ static const uint16_t DCE2_PORTS_SMB__DEFAULT[] = {139, 445}; static const uint16_t DCE2_PORTS_TCP__DEFAULT[] = {135}; static const uint16_t DCE2_PORTS_UDP__DEFAULT[] = {135}; //static const uint16_t DCE2_PORTS_HTTP_PROXY__DEFAULT[] = {80}; static const uint16_t DCE2_PORTS_HTTP_SERVER__DEFAULT[] = {593}; static char dce2_config_error[1024]; /******************************************************************** * Macros ********************************************************************/ #define DCE2_GOPT__MEMCAP "memcap" #define DCE2_GOPT__DISABLE_DEFRAG "disable_defrag" #define DCE2_GOPT__MAX_FRAG_LEN "max_frag_len" #define DCE2_GOPT__REASSEMBLE_THRESHOLD "reassemble_threshold" #define DCE2_GOPT__DISABLED "disabled" #define DCE2_GOPT__EVENTS "events" #define DCE2_GARG__EVENTS_NONE "none" #define DCE2_GARG__EVENTS_MEMCAP "memcap" #define DCE2_GARG__EVENTS_SMB "smb" #define DCE2_GARG__EVENTS_CO "co" /* Connection-oriented DCE/RPC */ #define DCE2_GARG__EVENTS_CL "cl" /* Connectionless DCE/RPC */ #define DCE2_GARG__EVENTS_ALL "all" #define DCE2_GOPT__SMB_FINGERPRINT "smb_fingerprint_policy" #define DCE2_GARG__SMBFP_CLIENT "client" #define DCE2_GARG__SMBFP_SERVER "server" #define DCE2_GARG__SMBFP_BOTH "both" #define DCE2_GARG__SMBFP_NONE "none" #define DCE2_SOPT__DEFAULT "default" #define DCE2_SOPT__NET "net" #define DCE2_SOPT__POLICY "policy" #define DCE2_SARG__POLICY_WIN2000 "Win2000" #define DCE2_SARG__POLICY_WINXP "WinXP" #define DCE2_SARG__POLICY_WINVISTA "WinVista" #define DCE2_SARG__POLICY_WIN2003 "Win2003" #define DCE2_SARG__POLICY_WIN2008 "Win2008" #define DCE2_SARG__POLICY_WIN7 "Win7" #define DCE2_SARG__POLICY_SAMBA "Samba" #define DCE2_SARG__POLICY_SAMBA_3_0_37 "Samba-3.0.37" /* Samba version 3.0.37 and previous */ #define DCE2_SARG__POLICY_SAMBA_3_0_22 "Samba-3.0.22" /* Samba version 3.0.22 and previous */ #define DCE2_SARG__POLICY_SAMBA_3_0_20 "Samba-3.0.20" /* Samba version 3.0.20 and previous */ #define DCE2_SOPT__DETECT "detect" #define DCE2_SOPT__AUTODETECT "autodetect" #define DCE2_SARG__DETECT_NONE "none" #define DCE2_SARG__DETECT_SMB "smb" #define DCE2_SARG__DETECT_TCP "tcp" #define DCE2_SARG__DETECT_UDP "udp" #define DCE2_SARG__DETECT_HTTP_PROXY "rpc-over-http-proxy" #define DCE2_SARG__DETECT_HTTP_SERVER "rpc-over-http-server" #define DCE2_SOPT__NO_AUTODETECT_HTTP_PROXY_PORTS "no_autodetect_http_proxy_ports" #define DCE2_SOPT__SMB_INVALID_SHARES "smb_invalid_shares" #define DCE2_SOPT__SMB_MAX_CHAIN "smb_max_chain" #define DCE2_SMB_MAX_CHAIN__DEFAULT 3 #define DCE2_SMB_MAX_CHAIN__MAX 255 /* uint8_t is used to store value */ #define DCE2_SOPT__SMB_FILE_INSPECTION "smb_file_inspection" #define DCE2_SARG__SMB_FILE_INSPECTION_ON "on" #define DCE2_SARG__SMB_FILE_INSPECTION_OFF "off" #define DCE2_SARG__SMB_FILE_INSPECTION_ONLY "only" #define DCE2_SARG__SMB_FILE_INSPECTION_DEPTH "file-depth" #define DCE2_SMB_FILE_DEPTH_DEFAULT 16384 #define DCE2_SOPT__VALID_SMB_VERSIONS "valid_smb_versions" #define DCE2_SARG__VALID_SMB_VERSIONS_V1 "v1" #define DCE2_SARG__VALID_SMB_VERSIONS_V2 "v2" #define DCE2_SARG__VALID_SMB_VERSIONS_ALL "all" #define DCE2_SOPT__SMB2_MAX_COMPOUND "smb2_max_compound" #define DCE2_SMB2_MAX_COMPOUND__DEFAULT 3 #define DCE2_SMB2_MAX_COMPOUND__MAX 255 /* uint8_t is used to store value */ /*** Don't increase max memcap number or it will overflow ***/ #define DCE2_MEMCAP__MIN 1024 /* 1 MB min */ #define DCE2_MEMCAP__MAX ((4 * 1024 * 1024) - 1) /* ~ 4 GB max */ #define DCE2_MAX_FRAG__MAX 65535 #define DCE2_MAX_FRAG__MIN 1514 #define DCE2_AUTO_PORTS__START 1025 /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_GcState { DCE2_GC_STATE__OPT_START, DCE2_GC_STATE__OPT, DCE2_GC_STATE__OPT_END, DCE2_GC_STATE__END } DCE2_GcState; typedef enum _DCE2_GcOptFlag { DCE2_GC_OPT_FLAG__NULL = 0x0000, DCE2_GC_OPT_FLAG__MEMCAP = 0x0001, DCE2_GC_OPT_FLAG__DISABLE_SMB_DESEG = 0x0002, DCE2_GC_OPT_FLAG__DISABLE_DEFRAG = 0x0004, DCE2_GC_OPT_FLAG__MAX_FRAG_LEN = 0x0008, DCE2_GC_OPT_FLAG__EVENTS = 0x0010, DCE2_GC_OPT_FLAG__REASSEMBLE_THRESHOLD = 0x0020, DCE2_GC_OPT_FLAG__DISABLED = 0x0040, DCE2_GC_OPT_FLAG__SMB_FINGERPRINT = 0x0080 } DCE2_GcOptFlag; typedef enum _DCE2_ScState { DCE2_SC_STATE__ROPT_START, /* Required option */ DCE2_SC_STATE__ROPT, DCE2_SC_STATE__OPT_START, DCE2_SC_STATE__OPT, DCE2_SC_STATE__OPT_END, DCE2_SC_STATE__END } DCE2_ScState; typedef enum _DCE2_ScOptFlag { DCE2_SC_OPT_FLAG__NULL = 0x0000, DCE2_SC_OPT_FLAG__DEFAULT = 0x0001, DCE2_SC_OPT_FLAG__NET = 0x0002, DCE2_SC_OPT_FLAG__POLICY = 0x0004, DCE2_SC_OPT_FLAG__DETECT = 0x0008, DCE2_SC_OPT_FLAG__AUTODETECT = 0x0010, DCE2_SC_OPT_FLAG__NO_AUTODETECT_HTTP_PROXY_PORTS = 0x0020, DCE2_SC_OPT_FLAG__SMB_INVALID_SHARES = 0x0040, DCE2_SC_OPT_FLAG__SMB_MAX_CHAIN = 0x0080, DCE2_SC_OPT_FLAG__VALID_SMB_VERSIONS = 0x0100, DCE2_SC_OPT_FLAG__SMB2_MAX_COMPOUND = 0x0200, DCE2_SC_OPT_FLAG__SMB_FILE_INSPECTION = 0x0400 } DCE2_ScOptFlag; typedef enum _DCE2_DetectListState { DCE2_DETECT_LIST_STATE__START, DCE2_DETECT_LIST_STATE__TYPE_START, DCE2_DETECT_LIST_STATE__TYPE, DCE2_DETECT_LIST_STATE__TYPE_END, DCE2_DETECT_LIST_STATE__PORTS_START, DCE2_DETECT_LIST_STATE__PORTS, DCE2_DETECT_LIST_STATE__PORTS_END, DCE2_DETECT_LIST_STATE__END } DCE2_DetectListState; typedef enum _DCE2_SmbFileListState { DCE2_SMB_FILE_LIST_STATE__START, DCE2_SMB_FILE_LIST_STATE__ENABLEMENT_START, DCE2_SMB_FILE_LIST_STATE__ENABLEMENT, DCE2_SMB_FILE_LIST_STATE__ENABLEMENT_END, DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_START, DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH, DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE_START, DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE, DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE_END, DCE2_SMB_FILE_LIST_STATE__END } DCE2_SmbFileListState; /******************************************************************** * Structures ********************************************************************/ /* Just used for printing detect and autodetect configurations */ typedef struct _DCE2_PrintPortsStruct { const uint8_t *port_array; const char *trans_str; } DCE2_PrintPortsStruct; /******************************************************************** * Private function prototypes ********************************************************************/ static void DCE2_GcInitConfig(DCE2_GlobalConfig *gc); static DCE2_Ret DCE2_GcParseConfig(DCE2_GlobalConfig *, char *); static inline DCE2_GcOptFlag DCE2_GcParseOption(char *, char *, int *); static DCE2_Ret DCE2_GcParseMemcap(DCE2_GlobalConfig *, char **, char *); static DCE2_Ret DCE2_GcParseMaxFrag(DCE2_GlobalConfig *, char **, char *); static DCE2_Ret DCE2_GcParseEvents(DCE2_GlobalConfig *, char **, char *); static inline void DCE2_GcSetEvent(DCE2_GlobalConfig *, DCE2_EventFlag); static inline void DCE2_GcClearEvent(DCE2_GlobalConfig *, DCE2_EventFlag); static inline void DCE2_GcClearAllEvents(DCE2_GlobalConfig *); static inline DCE2_EventFlag DCE2_GcParseEvent(char *, char *, int *); static DCE2_Ret DCE2_GcParseReassembleThreshold(DCE2_GlobalConfig *, char **, char *); static DCE2_Ret DCE2_GcParseSmbFingerprintPolicy(DCE2_GlobalConfig *, char **, char *); static void DCE2_GcPrintConfig(const DCE2_GlobalConfig *); static void DCE2_GcError(const char *, ...); static DCE2_Ret DCE2_ScInitConfig(DCE2_ServerConfig *); static DCE2_Ret DCE2_ScInitPortArray(DCE2_ServerConfig *, DCE2_DetectFlag, int); static DCE2_Ret DCE2_ScParseConfig(DCE2_Config *, DCE2_ServerConfig *, char *, DCE2_Queue *); static inline DCE2_ScOptFlag DCE2_ScParseOption(char *, char *, int *); static DCE2_Ret DCE2_ScParsePolicy(DCE2_ServerConfig *, char **, char *); static DCE2_Ret DCE2_ScParseDetect(DCE2_ServerConfig *, char **, char *, int); static inline DCE2_DetectFlag DCE2_ScParseDetectType(char *, char *, int *); static inline void DCE2_ScResetPortsArrays(DCE2_ServerConfig *, int); static DCE2_Ret DCE2_ScParseSmbShares(DCE2_ServerConfig *, char **, char *); static DCE2_Ret DCE2_ScParseSmbMaxChain(DCE2_ServerConfig *, char **, char *); static DCE2_Ret DCE2_ScParseSmb2MaxCompound(DCE2_ServerConfig *, char **, char *); static DCE2_Ret DCE2_ScParseValidSmbVersions(DCE2_ServerConfig *, char **, char *); static DCE2_Ret DCE2_ScParseSmbFileInspection(DCE2_ServerConfig *, char **, char *); static inline DCE2_ValidSmbVersionFlag DCE2_ScParseValidSmbVersion(char *, char *, int *); static inline void DCE2_ScSetValidSmbVersion(DCE2_ServerConfig *, DCE2_ValidSmbVersionFlag); static inline void DCE2_ScClearValidSmbVersion(DCE2_ServerConfig *, DCE2_ValidSmbVersionFlag); static inline void DCE2_ScClearAllValidSmbVersionFlags(DCE2_ServerConfig *); static DCE2_Ret DCE2_ScAddToRoutingTable(DCE2_Config *, DCE2_ServerConfig *, DCE2_Queue *); static int DCE2_ScSmbShareCompare(const void *, const void *); static void DCE2_ScSmbShareFree(void *); static void DCE2_ScPrintConfig(const DCE2_ServerConfig *, DCE2_Queue *); static void DCE2_ScPrintPorts(const DCE2_ServerConfig *, int); static void DCE2_ScIpListDataFree(void *); static int DCE2_ScCheckTransport(void *); static DCE2_Ret DCE2_ScCheckPortOverlap(const DCE2_ServerConfig *); static void DCE2_AddPortsToStream5Filter(struct _SnortConfig *, DCE2_ServerConfig *, tSfPolicyId); static void DCE2_ScError(const char *, ...); static void DCE2_ServerConfigCleanup(void *); /******************************************************************** * Function: DCE2_GlobalConfigure() * * Parses the DCE/RPC global configuration and stores values in a * global configuration structure. * * Arguments: * char * * snort.conf argument line for the dcerpc2 preprocessor. * * Returns: None * ********************************************************************/ void DCE2_GlobalConfigure(DCE2_Config *config, char *args) { if (config == NULL) return; dce2_config_error[0] = '\0'; config->gconfig = (DCE2_GlobalConfig *) DCE2_Alloc(sizeof(DCE2_GlobalConfig), DCE2_MEM_TYPE__CONFIG); /* Allocate memory for global config structure */ if (config->gconfig == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for global configuration.", __FILE__, __LINE__); } /* Initialize the global config structure */ DCE2_GcInitConfig(config->gconfig); /* If no arguments, just use default configuration */ if (DCE2_IsEmptyStr(args)) { DCE2_GcPrintConfig(config->gconfig); return; } if (DCE2_GcParseConfig(config->gconfig, args) != DCE2_RET__SUCCESS) DCE2_Die("%s", dce2_config_error); DCE2_GcPrintConfig(config->gconfig); } /******************************************************************** * Function: DCE2_GcInitConfig * * Initializes global configuration to defaults. * * Arguments: * DCE2_GlobalConfig * * Pointer to global config structure. * * Returns: None * ********************************************************************/ static void DCE2_GcInitConfig(DCE2_GlobalConfig *gc) { if (gc == NULL) return; /* Convert default memcap to 100MB */ gc->memcap = DCE2_MEMCAP__DEFAULT * 1024; /* Enable fragmentation reassembly */ gc->dce_defrag = DCE2_CS__ENABLED; /* Set default max fragment size */ gc->max_frag_len = DCE2_SENTINEL; } /******************************************************************** * Function: DCE2_GcParseConfig() * * Main parsing of global configuration. Parses options and * passes off to individual option handling. * * Arguments: * DCE2_GlobalConfig * * Pointer to the global configuration structure. * char * * Pointer to the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if parsing completed without error. * DCE2_RET__ERROR if an error occurred during parsing. * ********************************************************************/ static DCE2_Ret DCE2_GcParseConfig(DCE2_GlobalConfig *gc, char *args) { DCE2_GcState state = DCE2_GC_STATE__OPT_START; char *ptr, *end; char *opt_start = args; char last_char = 0; int option_mask = 0; ptr = args; end = ptr + strlen(args) + 1; /* Include NULL byte for state */ while (ptr < end) { char c = *ptr; switch (state) { case DCE2_GC_STATE__OPT_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { opt_start = ptr; /* Save pointer to first char of option */ state = DCE2_GC_STATE__OPT; } else if (!DCE2_IsSpaceChar(c)) { DCE2_GcError("Invalid syntax: \"%s\"", ptr); return DCE2_RET__ERROR; } break; case DCE2_GC_STATE__OPT: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { DCE2_GcOptFlag opt_flag; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_GcError("Invalid option: \"%.*s\"", ptr - opt_start, opt_start); return DCE2_RET__ERROR; } opt_flag = DCE2_GcParseOption(opt_start, ptr, &option_mask); switch (opt_flag) { case DCE2_GC_OPT_FLAG__MEMCAP: if (DCE2_GcParseMemcap(gc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_GC_OPT_FLAG__DISABLE_DEFRAG: gc->dce_defrag = DCE2_CS__DISABLED; break; case DCE2_GC_OPT_FLAG__MAX_FRAG_LEN: if (DCE2_GcParseMaxFrag(gc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_GC_OPT_FLAG__EVENTS: if (DCE2_GcParseEvents(gc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_GC_OPT_FLAG__REASSEMBLE_THRESHOLD: if (DCE2_GcParseReassembleThreshold(gc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_GC_OPT_FLAG__DISABLED: gc->disabled = 1; break; case DCE2_GC_OPT_FLAG__SMB_FINGERPRINT: if (DCE2_GcParseSmbFingerprintPolicy(gc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; default: return DCE2_RET__ERROR; } state = DCE2_GC_STATE__OPT_END; continue; } break; case DCE2_GC_STATE__OPT_END: if (DCE2_IsConfigEndChar(c)) { return DCE2_RET__SUCCESS; } else if (DCE2_IsOptEndChar(c)) { state = DCE2_GC_STATE__OPT_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_GcError("Invalid syntax: \"%s\"", ptr); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid option state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } last_char = c; ptr++; } return DCE2_RET__ERROR; } /******************************************************************** * Function: DCE2_GcParseOption() * * Parses the option and returns an option flag. Checks to make * sure option is only configured once. * * Arguments: * char * * Pointer to the first character of the option name. * char * * Pointer to the byte after the last character of * the option name. * int * Pointer to the current option mask. Contains bits set * for each option that has already been configured. Mask * is checked and updated for new option. * * Returns: * DCE2_GcOptFlag * Flag for the global option that is being configured. * NULL flag if not a valid option or option has already * been configured. * ********************************************************************/ static inline DCE2_GcOptFlag DCE2_GcParseOption(char *opt_start, char *opt_end, int *opt_mask) { DCE2_GcOptFlag opt_flag = DCE2_GC_OPT_FLAG__NULL; size_t opt_len = opt_end - opt_start; if (opt_len == strlen(DCE2_GOPT__MEMCAP) && strncasecmp(DCE2_GOPT__MEMCAP, opt_start, opt_len) == 0) { opt_flag = DCE2_GC_OPT_FLAG__MEMCAP; } else if (opt_len == strlen(DCE2_GOPT__DISABLE_DEFRAG) && strncasecmp(DCE2_GOPT__DISABLE_DEFRAG, opt_start, opt_len) == 0) { opt_flag = DCE2_GC_OPT_FLAG__DISABLE_DEFRAG; } else if (opt_len == strlen(DCE2_GOPT__MAX_FRAG_LEN) && strncasecmp(DCE2_GOPT__MAX_FRAG_LEN, opt_start, opt_len) == 0) { opt_flag = DCE2_GC_OPT_FLAG__MAX_FRAG_LEN; } else if (opt_len == strlen(DCE2_GOPT__EVENTS) && strncasecmp(DCE2_GOPT__EVENTS, opt_start, opt_len) == 0) { opt_flag = DCE2_GC_OPT_FLAG__EVENTS; } else if (opt_len == strlen(DCE2_GOPT__REASSEMBLE_THRESHOLD) && strncasecmp(DCE2_GOPT__REASSEMBLE_THRESHOLD, opt_start, opt_len) == 0) { opt_flag = DCE2_GC_OPT_FLAG__REASSEMBLE_THRESHOLD; } else if (opt_len == strlen(DCE2_GOPT__DISABLED) && strncasecmp(DCE2_GOPT__DISABLED, opt_start, opt_len) == 0) { opt_flag = DCE2_GC_OPT_FLAG__DISABLED; } else if (opt_len == strlen(DCE2_GOPT__SMB_FINGERPRINT) && strncasecmp(DCE2_GOPT__SMB_FINGERPRINT, opt_start, opt_len) == 0) { opt_flag = DCE2_GC_OPT_FLAG__SMB_FINGERPRINT; } else { DCE2_GcError("Invalid option: \"%.*s\"", opt_len, opt_start); return DCE2_GC_OPT_FLAG__NULL; } if (DCE2_CheckAndSetMask(opt_flag, opt_mask) != DCE2_RET__SUCCESS) { DCE2_GcError("Can only configure option once: \"%.*s\"", opt_len, opt_start); return DCE2_GC_OPT_FLAG__NULL; } return opt_flag; } /******************************************************************** * Function: DCE2_GcParseMemcap() * * Parses the argument to the memcap option and adds to global * configuration if successfully parsed. * * Arguments: * DCE2_GlobalConfig * * Pointer to the global configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing memcap. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * value for the memcap. * DCE2_RET__ERROR if an error occured in parsing the memcap. * ********************************************************************/ static DCE2_Ret DCE2_GcParseMemcap(DCE2_GlobalConfig *gc, char **ptr, char *end) { uint32_t memcap; if (DCE2_ParseValue(ptr, end, &memcap, DCE2_INT_TYPE__UINT32) != DCE2_RET__SUCCESS) { DCE2_GcError("Error parsing \"%s\". Value must be between %d and %d KB.", DCE2_GOPT__MEMCAP, DCE2_MEMCAP__MIN, DCE2_MEMCAP__MAX); return DCE2_RET__ERROR; } if ((memcap < DCE2_MEMCAP__MIN) || (memcap > DCE2_MEMCAP__MAX)) { DCE2_GcError("Invalid \"%s\". Value must be between %d and %d KB", DCE2_GOPT__MEMCAP, DCE2_MEMCAP__MIN, DCE2_MEMCAP__MAX); return DCE2_RET__ERROR; } /* Memcap is configured as kilobytes - convert to bytes */ gc->memcap = memcap * 1024; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_GcParseMaxFrag() * * Parses the argument to the max frag option and adds to global * configuration if successfully parsed. * * Arguments: * DCE2_GlobalConfig * * Pointer to the global configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing max frag. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * value for the max frag option. * DCE2_RET__ERROR if an error occured in parsing the max frag * option. * ********************************************************************/ static DCE2_Ret DCE2_GcParseMaxFrag(DCE2_GlobalConfig *gc, char **ptr, char *end) { uint16_t max_frag_len; if (DCE2_ParseValue(ptr, end, &max_frag_len, DCE2_INT_TYPE__UINT16) != DCE2_RET__SUCCESS) { DCE2_GcError("Error parsing \"%s\". Value must be between %d and %d", DCE2_GOPT__MAX_FRAG_LEN, DCE2_MAX_FRAG__MIN, DCE2_MAX_FRAG__MAX); return DCE2_RET__ERROR; } if (max_frag_len < DCE2_MAX_FRAG__MIN) { DCE2_GcError("Invalid \"%s\". Value must be between %d and %d", DCE2_GOPT__MAX_FRAG_LEN, DCE2_MAX_FRAG__MIN, DCE2_MAX_FRAG__MAX); return DCE2_RET__ERROR; } /* Cast since we initialize max frag len in global structure to a sentinel */ gc->max_frag_len = (int)max_frag_len; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_GcParseEvents() * * Parses the event types for the events option and adds to * global configuration. * * Arguments: * DCE2_GlobalConfig * * Pointer to the global configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing memcap. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * events. * DCE2_RET__ERROR if an error occured in parsing the events. * ********************************************************************/ static DCE2_Ret DCE2_GcParseEvents(DCE2_GlobalConfig *gc, char **ptr, char *end) { DCE2_WordListState state = DCE2_WORD_LIST_STATE__START; char *event_start = *ptr; char last_char = 0; int one_event = 0; int event_mask = 0; DCE2_GcClearAllEvents(gc); while (*ptr < end) { char c = **ptr; if (state == DCE2_WORD_LIST_STATE__END) break; switch (state) { case DCE2_WORD_LIST_STATE__START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { /* Only one event */ event_start = *ptr; one_event = 1; state = DCE2_WORD_LIST_STATE__WORD; } else if (DCE2_IsListStartChar(c)) { state = DCE2_WORD_LIST_STATE__WORD_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_GcError("Invalid \"%s\" syntax: \"%s\"", DCE2_GOPT__EVENTS, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__WORD_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { event_start = *ptr; state = DCE2_WORD_LIST_STATE__WORD; } else if (!DCE2_IsSpaceChar(c)) { DCE2_GcError("Invalid \"%s\" syntax: \"%s\"", DCE2_GOPT__EVENTS, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__WORD: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { DCE2_EventFlag eflag; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_GcError("Invalid \"%s\" argument: \"%.*s\"", DCE2_GOPT__EVENTS, *ptr - event_start, event_start); return DCE2_RET__ERROR; } eflag = DCE2_GcParseEvent(event_start, *ptr, &event_mask); switch (eflag) { case DCE2_EVENT_FLAG__NULL: return DCE2_RET__ERROR; case DCE2_EVENT_FLAG__NONE: if (!one_event) { DCE2_GcError("Event type \"%s\" cannot be " "configured in a list", DCE2_GARG__EVENTS_NONE); return DCE2_RET__ERROR; } /* Not really necessary since we're returning early, * but leave it here since this would be the action */ DCE2_GcClearAllEvents(gc); break; case DCE2_EVENT_FLAG__ALL: if (!one_event) { DCE2_GcError("Event type \"%s\" cannot be " "configured in a list", DCE2_GARG__EVENTS_ALL); return DCE2_RET__ERROR; } DCE2_GcSetEvent(gc, eflag); break; default: DCE2_GcSetEvent(gc, eflag); break; } if (one_event) return DCE2_RET__SUCCESS; state = DCE2_WORD_LIST_STATE__WORD_END; continue; } break; case DCE2_WORD_LIST_STATE__WORD_END: if (DCE2_IsListEndChar(c)) { state = DCE2_WORD_LIST_STATE__END; } else if (DCE2_IsListSepChar(c)) { state = DCE2_WORD_LIST_STATE__WORD_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_GcError("Invalid \"%s\" syntax: \"%s\"", DCE2_GOPT__EVENTS, *ptr); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid events state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } last_char = c; (*ptr)++; } if (state != DCE2_WORD_LIST_STATE__END) { DCE2_GcError("Invalid \"%s\" syntax: \"%s\"", DCE2_GOPT__EVENTS, *ptr); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_GcParseEvent() * * Parses event type and returns flag indication the type of event. * Checks and sets a bit in a mask to prevent multiple * configurations of the same event type. * * Arguments: * char * * Pointer to the first character of the event type name. * char * * Pointer to the byte after the last character of * the event type name. * int * Pointer to the current event type mask. Contains bits set * for each event type that has already been configured. Mask * is checked and updated for new event type. * * Returns: * DCE2_EventFlag * Flag indicating the type of event. * DCE2_EVENT_FLAG__NULL if no event type or multiple * configuration of event type. * ********************************************************************/ static inline DCE2_EventFlag DCE2_GcParseEvent(char *start, char *end, int *emask) { DCE2_EventFlag eflag = DCE2_EVENT_FLAG__NULL; size_t event_len = end - start; if (event_len == strlen(DCE2_GARG__EVENTS_NONE) && strncasecmp(DCE2_GARG__EVENTS_NONE, start, event_len) == 0) { eflag = DCE2_EVENT_FLAG__NONE; } else if (event_len == strlen(DCE2_GARG__EVENTS_MEMCAP) && strncasecmp(DCE2_GARG__EVENTS_MEMCAP, start, event_len) == 0) { eflag = DCE2_EVENT_FLAG__MEMCAP; } else if (event_len == strlen(DCE2_GARG__EVENTS_SMB) && strncasecmp(DCE2_GARG__EVENTS_SMB, start, event_len) == 0) { eflag = DCE2_EVENT_FLAG__SMB; } else if (event_len == strlen(DCE2_GARG__EVENTS_CO) && strncasecmp(DCE2_GARG__EVENTS_CO, start, event_len) == 0) { eflag = DCE2_EVENT_FLAG__CO; } else if (event_len == strlen(DCE2_GARG__EVENTS_CL) && strncasecmp(DCE2_GARG__EVENTS_CL, start, event_len) == 0) { eflag = DCE2_EVENT_FLAG__CL; } else if (event_len == strlen(DCE2_GARG__EVENTS_ALL) && strncasecmp(DCE2_GARG__EVENTS_ALL, start, event_len) == 0) { eflag = DCE2_EVENT_FLAG__ALL; } else { DCE2_GcError("Invalid \"%s\" argument: \"%.*s\"", DCE2_GOPT__EVENTS, event_len, start); return DCE2_EVENT_FLAG__NULL; } if (DCE2_CheckAndSetMask((int)eflag, emask) != DCE2_RET__SUCCESS) { DCE2_GcError("Event type \"%.*s\" cannot be specified more than once", event_len, start); return DCE2_EVENT_FLAG__NULL; } return eflag; } /********************************************************************* * Function: DCE2_GcSetEvent() * * Sets the event types the user wants to see during processing in * the global configuration event mask. * * Arguments: * DCE2_GlobalConfig * * Pointer to global config structure. * DCE2_EventFlag * The event type flag to set. * * Returns: None * *********************************************************************/ static inline void DCE2_GcSetEvent(DCE2_GlobalConfig *gc, DCE2_EventFlag eflag) { gc->event_mask |= eflag; } /********************************************************************* * Function: DCE2_GcClearEvent() * * Clears the bit associated with the event type flag passed in for * the global configuration event mask. * * Arguments: * DCE2_GlobalConfig * * Pointer to global config structure. * DCE2_EventFlag * The event type flag to clear. * * Returns: None * *********************************************************************/ static inline void DCE2_GcClearEvent(DCE2_GlobalConfig *gc, DCE2_EventFlag eflag) { gc->event_mask &= ~eflag; } /********************************************************************* * Function: DCE2_GcClearAllEvents() * * Clears all of the bits in the global configuration event mask. * * Arguments: * DCE2_GlobalConfig * * Pointer to global config structure. * * Returns: None * *********************************************************************/ static inline void DCE2_GcClearAllEvents(DCE2_GlobalConfig *gc) { gc->event_mask = DCE2_EVENT_FLAG__NULL; } /******************************************************************** * Function: DCE2_GcParseReassembleThreshold() * * Parses the argument to the reassemble threshold option and adds * to global configuration if successfully parsed. * * Arguments: * DCE2_GlobalConfig * * Pointer to the global configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the reassemble threshold. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * value for the reassemble threshold. * DCE2_RET__ERROR if an error occured in parsing the * reassemble threshold. * ********************************************************************/ static DCE2_Ret DCE2_GcParseReassembleThreshold(DCE2_GlobalConfig *gc, char **ptr, char *end) { uint16_t reassemble_threshold; if (DCE2_ParseValue(ptr, end, &reassemble_threshold, DCE2_INT_TYPE__UINT16) != DCE2_RET__SUCCESS) { DCE2_GcError("Error parsing \"%s\". Value must be between 0 and %u inclusive", DCE2_GOPT__REASSEMBLE_THRESHOLD, UINT16_MAX); return DCE2_RET__ERROR; } gc->reassemble_threshold = reassemble_threshold; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_GcParseSmbFingerPrintPolicy() * * Parses the smb_fingerprint_policy option * * Arguments: * DCE2_GlobalConfig * * Pointer to the global configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the reassemble threshold. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse. * DCE2_RET__ERROR if an error occured in parsing. * ********************************************************************/ static DCE2_Ret DCE2_GcParseSmbFingerprintPolicy(DCE2_GlobalConfig *gc, char **ptr, char *end) { DCE2_WordListState state = DCE2_WORD_LIST_STATE__START; char *fp_start = *ptr; char last_char = 0; while (*ptr < end) { char c = **ptr; if (state == DCE2_WORD_LIST_STATE__END) break; switch (state) { case DCE2_WORD_LIST_STATE__START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { fp_start = *ptr; state = DCE2_WORD_LIST_STATE__WORD; } else if (!DCE2_IsSpaceChar(c)) { DCE2_GcError("Invalid \"%s\" syntax: \"%s\"", DCE2_GOPT__SMB_FINGERPRINT, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__WORD: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { size_t len = *ptr - fp_start; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_GcError("Invalid \"%s\" argument: \"%*.s\"", DCE2_GOPT__SMB_FINGERPRINT, *ptr - fp_start, fp_start); return DCE2_RET__ERROR; } if (len == strlen(DCE2_GARG__SMBFP_CLIENT) && strncasecmp(DCE2_GARG__SMBFP_CLIENT, fp_start, len) == 0) { gc->smb_fingerprint_policy = DCE2_SMB_FINGERPRINT__CLIENT; } else if (len == strlen(DCE2_GARG__SMBFP_SERVER) && strncasecmp(DCE2_GARG__SMBFP_SERVER, fp_start, len) == 0) { gc->smb_fingerprint_policy = DCE2_SMB_FINGERPRINT__SERVER; } else if (len == strlen(DCE2_GARG__SMBFP_BOTH) && strncasecmp(DCE2_GARG__SMBFP_BOTH, fp_start, len) == 0) { gc->smb_fingerprint_policy = DCE2_SMB_FINGERPRINT__SERVER; gc->smb_fingerprint_policy |= DCE2_SMB_FINGERPRINT__CLIENT; } else if (len == strlen(DCE2_GARG__SMBFP_NONE) && strncasecmp(DCE2_GARG__SMBFP_NONE, fp_start, len) == 0) { gc->smb_fingerprint_policy = DCE2_SMB_FINGERPRINT__NONE; } else { DCE2_GcError("Invalid \"%s\" argument: \"%.*s\"", DCE2_GOPT__SMB_FINGERPRINT, *ptr - fp_start, fp_start); return DCE2_RET__ERROR; } state = DCE2_WORD_LIST_STATE__END; continue; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid smb fingerprint state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } last_char = c; (*ptr)++; } if (state != DCE2_WORD_LIST_STATE__END) { DCE2_GcError("Invalid \"%s\" syntax: \"%s\"", DCE2_GOPT__SMB_FINGERPRINT, *ptr); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScInitConfig * * Initializes a server configuration to defaults. * * Arguments: * DCE2_ServerConfig * * Pointer to server configuration structure to initialize. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if initialization fails * DCE2_RET__SUCCESS if initialization succeeds * ********************************************************************/ static DCE2_Ret DCE2_ScInitConfig(DCE2_ServerConfig *sc) { if (sc == NULL) return DCE2_RET__ERROR; /* Set defaults */ sc->policy = DCE2_POLICY__WINXP; sc->smb_max_chain = DCE2_SMB_MAX_CHAIN__DEFAULT; sc->smb2_max_compound = DCE2_SMB2_MAX_COMPOUND__DEFAULT; sc->valid_smb_versions_mask = DCE2_VALID_SMB_VERSION_FLAG__ALL; sc->autodetect_http_proxy_ports = DCE2_CS__ENABLED; sc->smb_file_inspection = DCE2_SMB_FILE_INSPECTION__OFF; sc->smb_file_depth = DCE2_SMB_FILE_DEPTH_DEFAULT; /* Add default detect ports */ if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__SMB, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__TCP, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__UDP, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__HTTP_PROXY, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__HTTP_SERVER, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; /* Add default autodetect ports */ if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__SMB, 1) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__TCP, 1) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__UDP, 1) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__HTTP_PROXY, 1) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; if (DCE2_ScInitPortArray(sc, DCE2_DETECT_FLAG__HTTP_SERVER, 1) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScInitPortArray * * Initializes a detect or autodetect port array to default * values. * * Arguments: * DCE2_ServerConfig * * Pointer to server configuration structure to initialize. * DCE2_DetectFlag * The transport for which to set defaults * int * Non-zero to set autodetect ports * Zero to set detect ports * * Returns: * DCE2_Ret * DCE2_RET__ERROR if and invalid DetectFlag is passed in * DCE2_RET__SUCCESS if ports arrays are successfully * initialized * ********************************************************************/ static DCE2_Ret DCE2_ScInitPortArray(DCE2_ServerConfig *sc, DCE2_DetectFlag dflag, int autodetect) { if (!autodetect) { unsigned int array_len; unsigned int i; switch (dflag) { case DCE2_DETECT_FLAG__SMB: DCE2_ClearPorts(sc->smb_ports); array_len = sizeof(DCE2_PORTS_SMB__DEFAULT) / sizeof(DCE2_PORTS_SMB__DEFAULT[0]); for (i = 0; i < array_len; i++) DCE2_SetPort(sc->smb_ports, DCE2_PORTS_SMB__DEFAULT[i]); break; case DCE2_DETECT_FLAG__TCP: DCE2_ClearPorts(sc->tcp_ports); array_len = sizeof(DCE2_PORTS_TCP__DEFAULT) / sizeof(DCE2_PORTS_TCP__DEFAULT[0]); for (i = 0; i < array_len; i++) DCE2_SetPort(sc->tcp_ports, DCE2_PORTS_TCP__DEFAULT[i]); break; case DCE2_DETECT_FLAG__UDP: DCE2_ClearPorts(sc->udp_ports); array_len = sizeof(DCE2_PORTS_UDP__DEFAULT) / sizeof(DCE2_PORTS_UDP__DEFAULT[0]); for (i = 0; i < array_len; i++) DCE2_SetPort(sc->udp_ports, DCE2_PORTS_UDP__DEFAULT[i]); break; case DCE2_DETECT_FLAG__HTTP_PROXY: DCE2_ClearPorts(sc->http_proxy_ports); /* Since there currently aren't any VRT dcerpc rules using * port 80, don't include it by default */ #if 0 array_len = sizeof(DCE2_PORTS_HTTP_PROXY__DEFAULT) / sizeof(DCE2_PORTS_HTTP_PROXY__DEFAULT[0]); for (i = 0; i < array_len; i++) DCE2_SetPort(sc->http_proxy_ports, DCE2_PORTS_HTTP_PROXY__DEFAULT[i]); #endif break; case DCE2_DETECT_FLAG__HTTP_SERVER: DCE2_ClearPorts(sc->http_server_ports); array_len = sizeof(DCE2_PORTS_HTTP_SERVER__DEFAULT) / sizeof(DCE2_PORTS_HTTP_SERVER__DEFAULT[0]); for (i = 0; i < array_len; i++) DCE2_SetPort(sc->http_server_ports, DCE2_PORTS_HTTP_SERVER__DEFAULT[i]); break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, dflag); return DCE2_RET__ERROR; } } else { uint8_t *port_array = NULL; unsigned int port; switch (dflag) { case DCE2_DETECT_FLAG__SMB: DCE2_ClearPorts(sc->auto_smb_ports); return DCE2_RET__SUCCESS; case DCE2_DETECT_FLAG__TCP: DCE2_ClearPorts(sc->auto_tcp_ports); port_array = sc->auto_tcp_ports; break; case DCE2_DETECT_FLAG__UDP: DCE2_ClearPorts(sc->auto_udp_ports); port_array = sc->auto_udp_ports; break; case DCE2_DETECT_FLAG__HTTP_PROXY: DCE2_ClearPorts(sc->auto_http_proxy_ports); return DCE2_RET__SUCCESS; case DCE2_DETECT_FLAG__HTTP_SERVER: DCE2_ClearPorts(sc->auto_http_server_ports); port_array = sc->auto_http_server_ports; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, dflag); return DCE2_RET__ERROR; } /* By default, only autodetect on ports 1025 and above, * and not on SMB or RPC over HTTP proxy */ for (port = DCE2_AUTO_PORTS__START; port < DCE2_PORTS__MAX; port++) DCE2_SetPort(port_array, (uint16_t)port); } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_CreateDefaultServerConfig() * * Creates a default server configuration for non-matching specific * server configurations. * * Arguments: None * * Returns: -1 on error * ********************************************************************/ int DCE2_CreateDefaultServerConfig(struct _SnortConfig *sc, DCE2_Config *config, tSfPolicyId policy_id) { if (config == NULL) return 0; config->dconfig = (DCE2_ServerConfig *) DCE2_Alloc(sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); if (config->dconfig == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for default server " "configuration.", __FILE__, __LINE__); } if (DCE2_ScInitConfig(config->dconfig) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__WARN, "%s(%d) Failed to initialize default server " "configuration.", __FILE__, __LINE__); return -1; } DCE2_AddPortsToStream5Filter(sc, config->dconfig, policy_id); return 0; } /******************************************************************** * Function: DCE2_ServerConfigure() * * Parses the DCE/RPC server configuration and stores values in * server configuration. * * Arguments: * char * * snort.conf argument line for the dcerpc2 preprocessor. * * Returns: None * ********************************************************************/ void DCE2_ServerConfigure(struct _SnortConfig *snortConf, DCE2_Config *config, char *args) { DCE2_ServerConfig *sc; DCE2_Queue *ip_queue; DCE2_Ret status; tSfPolicyId policy_id = _dpd.getParserPolicy(snortConf); if (config == NULL) return; dce2_config_error[0] = '\0'; /* Must have arguments */ if (DCE2_IsEmptyStr(args)) { DCE2_Die("%s(%d) \"%s\" configuration: No arguments to server " "configuration. Must have a \"%s\" or \"%s\" argument.", *_dpd.config_file, *_dpd.config_line, DCE2_SNAME, DCE2_SOPT__DEFAULT, DCE2_SOPT__NET); } /* Alloc server config */ sc = (DCE2_ServerConfig *)DCE2_Alloc(sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); if (sc == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for server " "configuration.", __FILE__, __LINE__); } if (DCE2_ScInitConfig(sc) != DCE2_RET__SUCCESS) { DCE2_ListDestroy(sc->smb_invalid_shares); DCE2_Free((void *)sc, sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); DCE2_Die("%s(%d) \"%s\" configuration: Failed to initialize server configuration.", __FILE__, __LINE__, DCE2_SNAME); } /* The ip queue stores the IPs from a specific server configuration * for adding to the routing tables */ ip_queue = DCE2_QueueNew(DCE2_ScIpListDataFree, DCE2_MEM_TYPE__CONFIG); if (ip_queue == NULL) { DCE2_ListDestroy(sc->smb_invalid_shares); DCE2_Free((void *)sc, sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); DCE2_Die("%s(%d) Failed to allocate memory for IP queue.", __FILE__, __LINE__); } status = DCE2_ScParseConfig(config, sc, args, ip_queue); if (status != DCE2_RET__SUCCESS) { if (sc != config->dconfig) { DCE2_ListDestroy(sc->smb_invalid_shares); DCE2_Free((void *)sc, sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); } DCE2_QueueDestroy(ip_queue); DCE2_Die("%s", dce2_config_error); } /* Check for overlapping detect ports */ if (DCE2_ScCheckPortOverlap(sc) != DCE2_RET__SUCCESS) { if (sc != config->dconfig) { DCE2_ListDestroy(sc->smb_invalid_shares); DCE2_Free((void *)sc, sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); } DCE2_QueueDestroy(ip_queue); DCE2_Die("%s", dce2_config_error); } DCE2_AddPortsToStream5Filter(snortConf, sc, policy_id); if ((sc != config->dconfig) && (DCE2_ScAddToRoutingTable(config, sc, ip_queue) != DCE2_RET__SUCCESS)) { DCE2_ListDestroy(sc->smb_invalid_shares); DCE2_Free((void *)sc, sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); DCE2_QueueDestroy(ip_queue); DCE2_Die("%s", dce2_config_error); } DCE2_ScPrintConfig(sc, ip_queue); DCE2_QueueDestroy(ip_queue); } /******************************************************************** * Function: DCE2_ScParseConfig() * * Main parsing of a server configuration. Parses options and * passes off to individual option handling. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * char * * Pointer to the configuration line. * DCE2_Queue * * Pointer to a queue for storing IPs. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if parsing completed without error. * DCE2_RET__ERROR if an error occurred during parsing. * ********************************************************************/ static DCE2_Ret DCE2_ScParseConfig(DCE2_Config *config, DCE2_ServerConfig *sc, char *args, DCE2_Queue *ip_queue) { DCE2_ScState state = DCE2_SC_STATE__ROPT_START; char *ptr, *end; char *opt_start = args; char last_char = 0; int option_mask = 0; ptr = args; end = ptr + strlen(args) + 1; /* Include NULL byte for state */ while (ptr < end) { char c = *ptr; switch (state) { case DCE2_SC_STATE__ROPT_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { opt_start = ptr; state = DCE2_SC_STATE__ROPT; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid syntax: \"%s\"", ptr); return DCE2_RET__ERROR; } break; case DCE2_SC_STATE__ROPT: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { DCE2_ScOptFlag opt_flag; DCE2_Ret status; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_ScError("Invalid option: \"%.*s\"", ptr - opt_start, opt_start); return DCE2_RET__ERROR; } opt_flag = DCE2_ScParseOption(opt_start, ptr, &option_mask); switch (opt_flag) { case DCE2_SC_OPT_FLAG__DEFAULT: if (config->dconfig != NULL) { DCE2_ScError("Can only configure \"%s\" " "configuration once", DCE2_SOPT__DEFAULT); return DCE2_RET__ERROR; } config->dconfig = sc; break; case DCE2_SC_OPT_FLAG__NET: if (config->dconfig == NULL) { DCE2_ScError("Must configure \"%s\" before any " "\"%s\" configurations", DCE2_SOPT__DEFAULT, DCE2_SOPT__NET); return DCE2_RET__ERROR; } status = DCE2_ParseIpList(&ptr, end, ip_queue); if (status != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; default: DCE2_ScError("Invalid first option to server configuration. " "First option must be \"%s\" or \"%s\"", DCE2_SOPT__DEFAULT, DCE2_SOPT__NET); return DCE2_RET__ERROR; } state = DCE2_SC_STATE__OPT_END; continue; } break; case DCE2_SC_STATE__OPT_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { opt_start = ptr; state = DCE2_SC_STATE__OPT; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid syntax: \"%s\"", ptr); return DCE2_RET__ERROR; } break; case DCE2_SC_STATE__OPT: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { DCE2_ScOptFlag opt_flag; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_ScError("Invalid option: \"%.*s\"", ptr - opt_start, opt_start); return DCE2_RET__ERROR; } opt_flag = DCE2_ScParseOption(opt_start, ptr, &option_mask); switch (opt_flag) { case DCE2_SC_OPT_FLAG__POLICY: if (DCE2_ScParsePolicy(sc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_SC_OPT_FLAG__DETECT: if (DCE2_ScParseDetect(sc, &ptr, end, 0) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_SC_OPT_FLAG__AUTODETECT: if (DCE2_ScParseDetect(sc, &ptr, end, 1) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_SC_OPT_FLAG__NO_AUTODETECT_HTTP_PROXY_PORTS: sc->autodetect_http_proxy_ports = DCE2_CS__DISABLED; break; case DCE2_SC_OPT_FLAG__SMB_INVALID_SHARES: sc->smb_invalid_shares = DCE2_ListNew(DCE2_LIST_TYPE__NORMAL, DCE2_ScSmbShareCompare, DCE2_ScSmbShareFree, DCE2_ScSmbShareFree, DCE2_LIST_FLAG__NO_DUPS | DCE2_LIST_FLAG__INS_TAIL, DCE2_MEM_TYPE__CONFIG); if (sc->smb_invalid_shares == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to allocate memory " "for invalid share list.", __FILE__, __LINE__); return DCE2_RET__ERROR; } if (DCE2_ScParseSmbShares(sc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_SC_OPT_FLAG__SMB_MAX_CHAIN: if (DCE2_ScParseSmbMaxChain(sc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_SC_OPT_FLAG__SMB2_MAX_COMPOUND: if (DCE2_ScParseSmb2MaxCompound(sc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_SC_OPT_FLAG__VALID_SMB_VERSIONS: if (DCE2_ScParseValidSmbVersions(sc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; break; case DCE2_SC_OPT_FLAG__SMB_FILE_INSPECTION: if (DCE2_ScParseSmbFileInspection(sc, &ptr, end) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; #ifdef ACTIVE_RESPONSE if ((sc->smb_file_inspection == DCE2_SMB_FILE_INSPECTION__ONLY) || (sc->smb_file_inspection == DCE2_SMB_FILE_INSPECTION__ON)) _dpd.activeSetEnabled(1); #endif break; case DCE2_SC_OPT_FLAG__DEFAULT: case DCE2_SC_OPT_FLAG__NET: DCE2_ScError("\"%s\" or \"%s\" must be the first " "option to configuration", DCE2_SOPT__DEFAULT, DCE2_SOPT__NET); return DCE2_RET__ERROR; default: return DCE2_RET__ERROR; } state = DCE2_SC_STATE__OPT_END; continue; } break; case DCE2_SC_STATE__OPT_END: if (DCE2_IsConfigEndChar(c)) { return DCE2_RET__SUCCESS; } else if (DCE2_IsOptEndChar(c)) { state = DCE2_SC_STATE__OPT_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid syntax: \"%s\"", ptr); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid option state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } last_char = c; ptr++; } return DCE2_RET__ERROR; } /******************************************************************** * Function: DCE2_ScParseOption() * * Parses the option and returns an option flag. Checks to make * sure option is only configured once. * * Arguments: * char * * Pointer to the first character of the option name. * char * * Pointer to the byte after the last character of * the option name. * int * Pointer to the current option mask. Contains bits set * for each option that has already been configured. Mask * is checked and updated for new option. * * Returns: * DCE2_ScOptFlag * Flag for the server option that is being configured. * NULL flag if not a valid option or option has already * been configured. * ********************************************************************/ static inline DCE2_ScOptFlag DCE2_ScParseOption(char *opt_start, char *opt_end, int *opt_mask) { DCE2_ScOptFlag opt_flag = DCE2_SC_OPT_FLAG__NULL; size_t opt_len = opt_end - opt_start; if (opt_len == strlen(DCE2_SOPT__DEFAULT) && strncasecmp(DCE2_SOPT__DEFAULT, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__DEFAULT; } else if (opt_len == strlen(DCE2_SOPT__NET) && strncasecmp(DCE2_SOPT__NET, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__NET; } else if (opt_len == strlen(DCE2_SOPT__POLICY) && strncasecmp(DCE2_SOPT__POLICY, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__POLICY; } else if (opt_len == strlen(DCE2_SOPT__DETECT) && strncasecmp(DCE2_SOPT__DETECT, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__DETECT; } else if (opt_len == strlen(DCE2_SOPT__AUTODETECT) && strncasecmp(DCE2_SOPT__AUTODETECT, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__AUTODETECT; } else if (opt_len == strlen(DCE2_SOPT__NO_AUTODETECT_HTTP_PROXY_PORTS) && strncasecmp(DCE2_SOPT__NO_AUTODETECT_HTTP_PROXY_PORTS, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__NO_AUTODETECT_HTTP_PROXY_PORTS; } else if (opt_len == strlen(DCE2_SOPT__SMB_INVALID_SHARES) && strncasecmp(DCE2_SOPT__SMB_INVALID_SHARES, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__SMB_INVALID_SHARES; } else if (opt_len == strlen(DCE2_SOPT__SMB_MAX_CHAIN) && strncasecmp(DCE2_SOPT__SMB_MAX_CHAIN, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__SMB_MAX_CHAIN; } else if (opt_len == strlen(DCE2_SOPT__SMB2_MAX_COMPOUND) && strncasecmp(DCE2_SOPT__SMB2_MAX_COMPOUND, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__SMB2_MAX_COMPOUND; } else if (opt_len == strlen(DCE2_SOPT__SMB_FILE_INSPECTION) && strncasecmp(DCE2_SOPT__SMB_FILE_INSPECTION, opt_start, opt_len) == 0) { opt_flag = DCE2_SC_OPT_FLAG__SMB_FILE_INSPECTION; } else { DCE2_ScError("Invalid option: \"%.*s\"", opt_len, opt_start); return DCE2_SC_OPT_FLAG__NULL; } if (DCE2_CheckAndSetMask(opt_flag, opt_mask) != DCE2_RET__SUCCESS) { DCE2_ScError("Can only configure option once: \"%.*s\"", opt_len, opt_start); return DCE2_SC_OPT_FLAG__NULL; } return opt_flag; } /******************************************************************** * Function: DCE2_ScParsePolicy() * * Parses the argument given to the policy option. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the policy argument. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * value for the policy. * DCE2_RET__ERROR if an error occured in parsing the policy. * ********************************************************************/ static DCE2_Ret DCE2_ScParsePolicy(DCE2_ServerConfig *sc, char **ptr, char *end) { DCE2_WordListState state = DCE2_WORD_LIST_STATE__START; char *policy_start = *ptr; char last_char = 0; while (*ptr < end) { char c = **ptr; if (state == DCE2_WORD_LIST_STATE__END) break; switch (state) { case DCE2_WORD_LIST_STATE__START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { policy_start = *ptr; state = DCE2_WORD_LIST_STATE__WORD; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__POLICY, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__WORD: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { size_t policy_len = *ptr - policy_start; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", DCE2_SOPT__POLICY, *ptr - policy_start, policy_start); return DCE2_RET__ERROR; } if (policy_len == strlen(DCE2_SARG__POLICY_WIN2000) && strncasecmp(DCE2_SARG__POLICY_WIN2000, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__WIN2000; } else if (policy_len == strlen(DCE2_SARG__POLICY_WINXP) && strncasecmp(DCE2_SARG__POLICY_WINXP, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__WINXP; } else if (policy_len == strlen(DCE2_SARG__POLICY_WINVISTA) && strncasecmp(DCE2_SARG__POLICY_WINVISTA, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__WINVISTA; } else if (policy_len == strlen(DCE2_SARG__POLICY_WIN2003) && strncasecmp(DCE2_SARG__POLICY_WIN2003, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__WIN2003; } else if (policy_len == strlen(DCE2_SARG__POLICY_WIN2008) && strncasecmp(DCE2_SARG__POLICY_WIN2008, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__WIN2008; } else if (policy_len == strlen(DCE2_SARG__POLICY_WIN7) && strncasecmp(DCE2_SARG__POLICY_WIN7, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__WIN7; } else if (policy_len == strlen(DCE2_SARG__POLICY_SAMBA) && strncasecmp(DCE2_SARG__POLICY_SAMBA, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__SAMBA; } else if (policy_len == strlen(DCE2_SARG__POLICY_SAMBA_3_0_37) && strncasecmp(DCE2_SARG__POLICY_SAMBA_3_0_37, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__SAMBA_3_0_37; } else if (policy_len == strlen(DCE2_SARG__POLICY_SAMBA_3_0_22) && strncasecmp(DCE2_SARG__POLICY_SAMBA_3_0_22, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__SAMBA_3_0_22; } else if (policy_len == strlen(DCE2_SARG__POLICY_SAMBA_3_0_20) && strncasecmp(DCE2_SARG__POLICY_SAMBA_3_0_20, policy_start, policy_len) == 0) { sc->policy = DCE2_POLICY__SAMBA_3_0_20; } else { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", DCE2_SOPT__POLICY, policy_len, policy_start); return DCE2_RET__ERROR; } state = DCE2_WORD_LIST_STATE__END; continue; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } last_char = c; (*ptr)++; } if (state != DCE2_WORD_LIST_STATE__END) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__POLICY, *ptr); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScParseDetect() * * Parses the arguments to the detect or autodetect options. These * options take the same arguments. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the policy argument. * char * * Pointer to the end of the configuration line. * int * Non-zero if we're configuring for the autodetect option. * Zero if we're configuring for the detect option. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * arguments for the detect or autodetect options. * DCE2_RET__ERROR if an error occured in parsing the detect * or autodetect arguments. * ********************************************************************/ static DCE2_Ret DCE2_ScParseDetect(DCE2_ServerConfig *sc, char **ptr, char *end, int autodetect) { DCE2_DetectListState state = DCE2_DETECT_LIST_STATE__START; char *type_start = *ptr; uint8_t *port_array = NULL; int dmask = DCE2_DETECT_FLAG__NULL; int one_type = 0; char last_char = 0; DCE2_DetectFlag dflag = DCE2_DETECT_FLAG__NULL; char *option_str = autodetect ? DCE2_SOPT__AUTODETECT : DCE2_SOPT__DETECT; DCE2_ScResetPortsArrays(sc, autodetect); while (*ptr < end) { char c = **ptr; if (state == DCE2_DETECT_LIST_STATE__END) break; switch (state) { case DCE2_DETECT_LIST_STATE__START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { type_start = *ptr; one_type = 1; state = DCE2_DETECT_LIST_STATE__TYPE; } else if (DCE2_IsListStartChar(c)) { state = DCE2_DETECT_LIST_STATE__TYPE_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", option_str, *ptr); return DCE2_RET__ERROR; } break; case DCE2_DETECT_LIST_STATE__TYPE_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { type_start = *ptr; state = DCE2_DETECT_LIST_STATE__TYPE; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", option_str, *ptr); return DCE2_RET__ERROR; } break; case DCE2_DETECT_LIST_STATE__TYPE: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", option_str, *ptr - type_start, type_start); return DCE2_RET__ERROR; } dflag = DCE2_ScParseDetectType(type_start, *ptr, &dmask); switch (dflag) { case DCE2_DETECT_FLAG__NONE: /* This can only be used by itself */ if (dmask != DCE2_DETECT_FLAG__NONE) { DCE2_ScError("Can only use \"%s\" type \"%s\" " "by itself", option_str, DCE2_SARG__DETECT_NONE); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; case DCE2_DETECT_FLAG__SMB: if (autodetect) port_array = sc->auto_smb_ports; else port_array = sc->smb_ports; break; case DCE2_DETECT_FLAG__TCP: if (autodetect) port_array = sc->auto_tcp_ports; else port_array = sc->tcp_ports; break; case DCE2_DETECT_FLAG__UDP: if (autodetect) port_array = sc->auto_udp_ports; else port_array = sc->udp_ports; break; case DCE2_DETECT_FLAG__HTTP_PROXY: if (autodetect) port_array = sc->auto_http_proxy_ports; else port_array = sc->http_proxy_ports; break; case DCE2_DETECT_FLAG__HTTP_SERVER: if (autodetect) port_array = sc->auto_http_server_ports; else port_array = sc->http_server_ports; break; default: return DCE2_RET__ERROR; } state = DCE2_DETECT_LIST_STATE__TYPE_END; continue; } break; case DCE2_DETECT_LIST_STATE__TYPE_END: if (DCE2_IsSpaceChar(c)) { /* Guess that a port list will be next */ state = DCE2_DETECT_LIST_STATE__PORTS_START; } else if (one_type) { return DCE2_ScInitPortArray(sc, dflag, autodetect); } else if (DCE2_IsListSepChar(c)) { if (DCE2_ScInitPortArray(sc, dflag, autodetect) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; state = DCE2_DETECT_LIST_STATE__TYPE_START; } else if (DCE2_IsListEndChar(c)) { if (DCE2_ScInitPortArray(sc, dflag, autodetect) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; state = DCE2_DETECT_LIST_STATE__END; } else { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", option_str, *ptr); return DCE2_RET__ERROR; } break; case DCE2_DETECT_LIST_STATE__PORTS_START: if (DCE2_IsPortChar(c) || DCE2_IsPortRangeChar(c) || DCE2_IsListStartChar(c)) { state = DCE2_DETECT_LIST_STATE__PORTS; continue; } else if (one_type) { if (!DCE2_IsSpaceChar(c)) { return DCE2_ScInitPortArray(sc, dflag, autodetect); } } else if (DCE2_IsListSepChar(c)) { if (DCE2_ScInitPortArray(sc, dflag, autodetect) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; state = DCE2_DETECT_LIST_STATE__TYPE_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", option_str, *ptr); return DCE2_RET__ERROR; } break; case DCE2_DETECT_LIST_STATE__PORTS: if (DCE2_ParsePortList(ptr, end, port_array) != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; state = DCE2_DETECT_LIST_STATE__PORTS_END; continue; case DCE2_DETECT_LIST_STATE__PORTS_END: if (one_type) { return DCE2_RET__SUCCESS; } else if (DCE2_IsListEndChar(c)) { state = DCE2_DETECT_LIST_STATE__END; } else if (DCE2_IsListSepChar(c)) { state = DCE2_DETECT_LIST_STATE__TYPE_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", option_str, *ptr); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid %s state: %d", __FILE__, __LINE__, option_str, state); return DCE2_RET__ERROR; } last_char = c; (*ptr)++; } if (state != DCE2_DETECT_LIST_STATE__END) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", option_str, *ptr); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScResetPortArrays() * * Clears all of the port bits in the specified port array masks * for the passed in server configuration. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * int * Non-zero if we should clear the autodetect port bits. * Zero if we should clear the detect port bits. * * Returns: None * ********************************************************************/ static inline void DCE2_ScResetPortsArrays(DCE2_ServerConfig *sc, int autodetect) { if (!autodetect) { DCE2_ClearPorts(sc->smb_ports); DCE2_ClearPorts(sc->tcp_ports); DCE2_ClearPorts(sc->udp_ports); DCE2_ClearPorts(sc->http_proxy_ports); DCE2_ClearPorts(sc->http_server_ports); } else { DCE2_ClearPorts(sc->auto_smb_ports); DCE2_ClearPorts(sc->auto_tcp_ports); DCE2_ClearPorts(sc->auto_udp_ports); DCE2_ClearPorts(sc->auto_http_proxy_ports); DCE2_ClearPorts(sc->auto_http_server_ports); } } /******************************************************************** * Function: DCE2_ScParseDetectType() * * Parses the detect type or transport argument to the detect or * autodetect options. * * Arguments: * char * * Pointer to the first character of the detect type name. * char * * Pointer to the byte after the last character of * the detect type name. * int * Pointer to the current detect type mask. Contains bits * set for each detect type that has already been configured. * Mask is checked and updated for new option. * * Returns: * DCE2_DetectFlag * Flag for the detect type or transport. * NULL flag if not a valid detect type or detect type has * already been configured. * ********************************************************************/ static inline DCE2_DetectFlag DCE2_ScParseDetectType(char *start, char *end, int *dmask) { DCE2_DetectFlag dflag = DCE2_DETECT_FLAG__NULL; size_t dtype_len = end - start; if (dtype_len == strlen(DCE2_SARG__DETECT_SMB) && strncasecmp(DCE2_SARG__DETECT_SMB, start, dtype_len) == 0) { dflag = DCE2_DETECT_FLAG__SMB; } else if (dtype_len == strlen(DCE2_SARG__DETECT_TCP) && strncasecmp(DCE2_SARG__DETECT_TCP, start, dtype_len) == 0) { dflag = DCE2_DETECT_FLAG__TCP; } else if (dtype_len == strlen(DCE2_SARG__DETECT_UDP) && strncasecmp(DCE2_SARG__DETECT_UDP, start, dtype_len) == 0) { dflag = DCE2_DETECT_FLAG__UDP; } else if (dtype_len == strlen(DCE2_SARG__DETECT_HTTP_PROXY) && strncasecmp(DCE2_SARG__DETECT_HTTP_PROXY, start, dtype_len) == 0) { dflag = DCE2_DETECT_FLAG__HTTP_PROXY; } else if (dtype_len == strlen(DCE2_SARG__DETECT_HTTP_SERVER) && strncasecmp(DCE2_SARG__DETECT_HTTP_SERVER, start, dtype_len) == 0) { dflag = DCE2_DETECT_FLAG__HTTP_SERVER; } else if (dtype_len == strlen(DCE2_SARG__DETECT_NONE) && strncasecmp(DCE2_SARG__DETECT_NONE, start, dtype_len) == 0) { dflag = DCE2_DETECT_FLAG__NONE; } else { DCE2_ScError("Invalid detect/autodetect type: \"%.*s\"", dtype_len, start); return DCE2_DETECT_FLAG__NULL; } if (DCE2_CheckAndSetMask(dflag, dmask) != DCE2_RET__SUCCESS) { DCE2_ScError("Can only configure option once: \"%.*s\"", dtype_len, start); return DCE2_DETECT_FLAG__NULL; } return dflag; } /******************************************************************** * Function: DCE2_ScParseSmbShares() * * Parses shares given to the smb shares option. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the smb shares arguments. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * arguments to the smb shares option * DCE2_RET__ERROR if an error occured in parsing the smb * shares option. * ********************************************************************/ static DCE2_Ret DCE2_ScParseSmbShares(DCE2_ServerConfig *sc, char **ptr, char *end) { DCE2_WordListState state = DCE2_WORD_LIST_STATE__START; char *share_start = *ptr; int one_share = 0; int quote = 0; while (*ptr < end) { char c = **ptr; if (state == DCE2_WORD_LIST_STATE__END) break; switch (state) { case DCE2_WORD_LIST_STATE__START: if (DCE2_IsQuoteChar(c)) { quote ^= 1; one_share = 1; state = DCE2_WORD_LIST_STATE__QUOTE; } else if (DCE2_IsListStartChar(c)) { state = DCE2_WORD_LIST_STATE__WORD_START; } else if (DCE2_IsGraphChar(c)) { /* Only one share */ share_start = *ptr; one_share = 1; state = DCE2_WORD_LIST_STATE__WORD; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__SMB_INVALID_SHARES, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__QUOTE: if (DCE2_IsGraphChar(c)) { share_start = *ptr; state = DCE2_WORD_LIST_STATE__WORD; } else { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__SMB_INVALID_SHARES, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__WORD_START: if (DCE2_IsQuoteChar(c)) { quote ^= 1; state = DCE2_WORD_LIST_STATE__QUOTE; } else if (DCE2_IsGraphChar(c)) { share_start = *ptr; state = DCE2_WORD_LIST_STATE__WORD; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__SMB_INVALID_SHARES, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__WORD: if (!DCE2_IsGraphChar(c)) { DCE2_SmbShare *smb_share; DCE2_SmbShare *smb_share_key; int share_len = *ptr - share_start; int i, j; DCE2_Ret status; smb_share = (DCE2_SmbShare *)DCE2_Alloc(sizeof(DCE2_SmbShare), DCE2_MEM_TYPE__CONFIG); smb_share_key = (DCE2_SmbShare *)DCE2_Alloc(sizeof(DCE2_SmbShare), DCE2_MEM_TYPE__CONFIG); if ((smb_share == NULL) || (smb_share_key == NULL)) { DCE2_ScSmbShareFree((void *)smb_share); DCE2_ScSmbShareFree((void *)smb_share_key); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to allocate memory for smb share.", __FILE__, __LINE__); return DCE2_RET__ERROR; } smb_share->unicode_str_len = (share_len * 2) + 2; smb_share->unicode_str = (char *)DCE2_Alloc(smb_share->unicode_str_len, DCE2_MEM_TYPE__CONFIG); smb_share->ascii_str_len = share_len + 1; smb_share->ascii_str = (char *)DCE2_Alloc(smb_share->ascii_str_len, DCE2_MEM_TYPE__CONFIG); if ((smb_share->unicode_str == NULL) || (smb_share->ascii_str == NULL)) { DCE2_ScSmbShareFree((void *)smb_share); DCE2_ScSmbShareFree((void *)smb_share_key); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to allocate memory for smb share.", __FILE__, __LINE__); return DCE2_RET__ERROR; } for (i = 0, j = 0; i < share_len; i++, j += 2) { smb_share->unicode_str[j] = (char)toupper((int)share_start[i]); smb_share->ascii_str[i] = (char)toupper((int)share_start[i]); } /* Just use ascii share as the key */ smb_share_key->ascii_str_len = smb_share->ascii_str_len; smb_share_key->ascii_str = (char *)DCE2_Alloc(smb_share_key->ascii_str_len, DCE2_MEM_TYPE__CONFIG); if (smb_share_key->ascii_str == NULL) { DCE2_ScSmbShareFree((void *)smb_share); DCE2_ScSmbShareFree((void *)smb_share_key); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to allocate memory for smb share.", __FILE__, __LINE__); return DCE2_RET__ERROR; } memcpy(smb_share_key->ascii_str, smb_share->ascii_str, smb_share_key->ascii_str_len); status = DCE2_ListInsert(sc->smb_invalid_shares, (void *)smb_share_key, (void *)smb_share); if (status == DCE2_RET__DUPLICATE) { /* Just free this share and move on */ DCE2_ScSmbShareFree((void *)smb_share); DCE2_ScSmbShareFree((void *)smb_share_key); } else if (status != DCE2_RET__SUCCESS) { DCE2_ScSmbShareFree((void *)smb_share); DCE2_ScSmbShareFree((void *)smb_share_key); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to insert invalid share into list.", __FILE__, __LINE__); return DCE2_RET__ERROR; } if (one_share) { if (quote && !DCE2_IsQuoteChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: Unterminated quoted string", DCE2_SOPT__SMB_INVALID_SHARES); return DCE2_RET__ERROR; } state = DCE2_WORD_LIST_STATE__END; break; } state = DCE2_WORD_LIST_STATE__WORD_END; continue; } break; case DCE2_WORD_LIST_STATE__WORD_END: if (quote) { if (!DCE2_IsQuoteChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: Unterminated quoted string", DCE2_SOPT__SMB_INVALID_SHARES); return DCE2_RET__ERROR; } quote ^= 1; } else if (DCE2_IsListEndChar(c)) { state = DCE2_WORD_LIST_STATE__END; } else if (DCE2_IsListSepChar(c)) { state = DCE2_WORD_LIST_STATE__WORD_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__SMB_INVALID_SHARES, *ptr); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid smb shares state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } (*ptr)++; } if (state != DCE2_WORD_LIST_STATE__END) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__SMB_INVALID_SHARES, *ptr); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScParseSmbMaxChain() * * Parses the argument to the smb max chain option. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the smb max chain argument. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * argument to the smb max chain option. * DCE2_RET__ERROR if an error occured in parsing the smb max * chain argument. * ********************************************************************/ static DCE2_Ret DCE2_ScParseSmbMaxChain(DCE2_ServerConfig *sc, char **ptr, char *end) { DCE2_Ret status; uint8_t chain_len; status = DCE2_ParseValue(ptr, end, &chain_len, DCE2_INT_TYPE__UINT8); if (status != DCE2_RET__SUCCESS) { DCE2_ScError("Error parsing \"%s\". Value must be between 0 and %u inclusive", DCE2_SOPT__SMB_MAX_CHAIN, UINT8_MAX); return DCE2_RET__ERROR; } sc->smb_max_chain = chain_len; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScParseSmb2MaxCompound() * * Parses the argument to the smb2 max compound option. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the smb max chain argument. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * argument to the smb2 max compound option. * DCE2_RET__ERROR if an error occured in parsing the smb2 max * compound argument. * ********************************************************************/ static DCE2_Ret DCE2_ScParseSmb2MaxCompound(DCE2_ServerConfig *sc, char **ptr, char *end) { DCE2_Ret status; uint8_t compound_len; status = DCE2_ParseValue(ptr, end, &compound_len, DCE2_INT_TYPE__UINT8); if (status != DCE2_RET__SUCCESS) { DCE2_ScError("Error parsing \"%s\". Value must be between 0 and %u inclusive", DCE2_SOPT__SMB2_MAX_COMPOUND, UINT8_MAX); return DCE2_RET__ERROR; } sc->smb2_max_compound = compound_len; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScParseValidSmbVersions() * * Parses the version types for the valid smb versions option and * adds to server configuration. * * Arguments: * DCE2_GlobalConfig * * Pointer to the global configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * valid smb versions * DCE2_RET__ERROR if an error occured in parsing. * ********************************************************************/ static DCE2_Ret DCE2_ScParseValidSmbVersions(DCE2_ServerConfig *sc, char **ptr, char *end) { DCE2_WordListState state = DCE2_WORD_LIST_STATE__START; char *version_start = *ptr; char last_char = 0; int one_version = 0; int version_mask = 0; DCE2_ScClearAllValidSmbVersionFlags(sc); while (*ptr < end) { char c = **ptr; if (state == DCE2_WORD_LIST_STATE__END) break; switch (state) { case DCE2_WORD_LIST_STATE__START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { /* Only one valid smb version */ version_start = *ptr; one_version = 1; state = DCE2_WORD_LIST_STATE__WORD; } else if (DCE2_IsListStartChar(c)) { state = DCE2_WORD_LIST_STATE__WORD_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__VALID_SMB_VERSIONS, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__WORD_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { version_start = *ptr; state = DCE2_WORD_LIST_STATE__WORD; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__VALID_SMB_VERSIONS, *ptr); return DCE2_RET__ERROR; } break; case DCE2_WORD_LIST_STATE__WORD: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { DCE2_ValidSmbVersionFlag vflag; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", DCE2_SOPT__VALID_SMB_VERSIONS, *ptr - version_start, version_start); return DCE2_RET__ERROR; } vflag = DCE2_ScParseValidSmbVersion(version_start, *ptr, &version_mask); switch (vflag) { case DCE2_VALID_SMB_VERSION_FLAG__NULL: return DCE2_RET__ERROR; case DCE2_VALID_SMB_VERSION_FLAG__ALL: if (!one_version) { DCE2_ScError("Valid smb version \"%s\" cannot be " "configured in a list", DCE2_SARG__VALID_SMB_VERSIONS_ALL); return DCE2_RET__ERROR; } DCE2_ScSetValidSmbVersion(sc, vflag); break; default: DCE2_ScSetValidSmbVersion(sc, vflag); break; } if (one_version) return DCE2_RET__SUCCESS; state = DCE2_WORD_LIST_STATE__WORD_END; continue; } break; case DCE2_WORD_LIST_STATE__WORD_END: if (DCE2_IsListEndChar(c)) { state = DCE2_WORD_LIST_STATE__END; } else if (DCE2_IsListSepChar(c)) { state = DCE2_WORD_LIST_STATE__WORD_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__VALID_SMB_VERSIONS, *ptr); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid valid " "smb versions state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } last_char = c; (*ptr)++; } if (state != DCE2_WORD_LIST_STATE__END) { DCE2_ScError("Invalid \"%s\" syntax: \"%s\"", DCE2_SOPT__VALID_SMB_VERSIONS, *ptr); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScParseValidSmbVersion() * * Parses smb version and returns flag indication the smb version. * Checks and sets a bit in a mask to prevent multiple * configurations of the same event type. * * Arguments: * char * * Pointer to the first character of the smb version name. * char * * Pointer to the byte after the last character of * the smb version name. * int * Pointer to the current valid smb versions mask. Contains * bits set for each smb version that has already been * configured. Mask is checked and updated for new version. * * Returns: * DCE2_ValidSmbVersionFlag * Flag indicating the smb version. * DCE2_VALID_SMB_VERSION_FLAG__NULL if no version or multiple * configuration of smb version. * ********************************************************************/ static inline DCE2_ValidSmbVersionFlag DCE2_ScParseValidSmbVersion( char *start, char *end, int *vmask) { DCE2_ValidSmbVersionFlag vflag = DCE2_VALID_SMB_VERSION_FLAG__NULL; size_t version_len = end - start; if (version_len == strlen(DCE2_SARG__VALID_SMB_VERSIONS_V1) && strncasecmp(DCE2_SARG__VALID_SMB_VERSIONS_V1, start, version_len) == 0) { vflag = DCE2_VALID_SMB_VERSION_FLAG__V1; } else if (version_len == strlen(DCE2_SARG__VALID_SMB_VERSIONS_V2) && strncasecmp(DCE2_SARG__VALID_SMB_VERSIONS_V2, start, version_len) == 0) { vflag = DCE2_VALID_SMB_VERSION_FLAG__V2; } else if (version_len == strlen(DCE2_SARG__VALID_SMB_VERSIONS_ALL) && strncasecmp(DCE2_SARG__VALID_SMB_VERSIONS_ALL, start, version_len) == 0) { vflag = DCE2_VALID_SMB_VERSION_FLAG__ALL; } else { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", DCE2_SOPT__VALID_SMB_VERSIONS, version_len, start); return DCE2_VALID_SMB_VERSION_FLAG__NULL; } if (DCE2_CheckAndSetMask((int)vflag, vmask) != DCE2_RET__SUCCESS) { DCE2_ScError("Valid smb version \"%.*s\" cannot be specified more than once", version_len, start); return DCE2_VALID_SMB_VERSION_FLAG__NULL; } return vflag; } /********************************************************************* * Function: DCE2_ScSetValidSmbVersion() * * Sets the valid smb version the user will allow during processing * in the server configuration valid smb versions mask. * * Arguments: * DCE2_ServerConfig * * Pointer to server config structure. * DCE2_ValidSmbVersionFlag * The smb version flag to set. * * Returns: None * *********************************************************************/ static inline void DCE2_ScSetValidSmbVersion(DCE2_ServerConfig *sc, DCE2_ValidSmbVersionFlag vflag) { sc->valid_smb_versions_mask |= vflag; } /********************************************************************* * Function: DCE2_ScClearValidSmbVersion() * * Sets the bit associated with the smb version flag passed in for * the server configuration valid smb versions mask. * * Arguments: * DCE2_ServerConfig * * Pointer to server config structure. * DCE2_ValidSmbVersionFlag * The smb version flag to clear. * * Returns: None * *********************************************************************/ static inline void DCE2_ScClearValidSmbVersion(DCE2_ServerConfig *sc, DCE2_ValidSmbVersionFlag vflag) { sc->valid_smb_versions_mask &= ~vflag; } /********************************************************************* * Function: DCE2_ScClearAllValidSmbVersionFlags() * * Clears all of the bits in the server configuration smb * valid versions mask. * * Arguments: * DCE2_ServerConfig * * Pointer to server config structure. * * Returns: None * *********************************************************************/ static inline void DCE2_ScClearAllValidSmbVersionFlags(DCE2_ServerConfig *sc) { sc->valid_smb_versions_mask = DCE2_VALID_SMB_VERSION_FLAG__NULL; } /******************************************************************** * Function: DCE2_ScParseSmbFileInspection() * * Parses the arguments to the smb_file_inspection option. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the policy argument. * char * * Pointer to the end of the configuration line. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse. * DCE2_RET__ERROR if an error occured in parsing. * ********************************************************************/ static DCE2_Ret DCE2_ScParseSmbFileInspection(DCE2_ServerConfig *sc, char **ptr, char *end) { DCE2_SmbFileListState state = DCE2_SMB_FILE_LIST_STATE__START; const char *option = DCE2_SOPT__SMB_FILE_INSPECTION; char *option_start = *ptr; char *optr; int no_list = 0; char last_char = 0; while (*ptr < end) { char c = **ptr; if (state == DCE2_SMB_FILE_LIST_STATE__END) break; switch (state) { case DCE2_SMB_FILE_LIST_STATE__START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { optr = *ptr; no_list = 1; state = DCE2_SMB_FILE_LIST_STATE__ENABLEMENT; } else if (DCE2_IsListStartChar(c)) { state = DCE2_SMB_FILE_LIST_STATE__ENABLEMENT_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%.*s\"", option, *ptr - option_start, option_start); return DCE2_RET__ERROR; } break; case DCE2_SMB_FILE_LIST_STATE__ENABLEMENT_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { optr = *ptr; state = DCE2_SMB_FILE_LIST_STATE__ENABLEMENT; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%.*s\"", option, *ptr - option_start, option_start); return DCE2_RET__ERROR; } break; case DCE2_SMB_FILE_LIST_STATE__ENABLEMENT: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { int olen = *ptr - optr; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", option, *ptr - optr, optr); return DCE2_RET__ERROR; } if ((olen == strlen(DCE2_SARG__SMB_FILE_INSPECTION_ON)) && (strncasecmp(DCE2_SARG__SMB_FILE_INSPECTION_ON, optr, olen) == 0)) { sc->smb_file_inspection = DCE2_SMB_FILE_INSPECTION__ON; } else if ((olen == strlen(DCE2_SARG__SMB_FILE_INSPECTION_OFF)) && (strncasecmp(DCE2_SARG__SMB_FILE_INSPECTION_OFF, optr, olen) == 0)) { sc->smb_file_inspection = DCE2_SMB_FILE_INSPECTION__OFF; } else if ((olen == strlen(DCE2_SARG__SMB_FILE_INSPECTION_ONLY)) && (strncasecmp(DCE2_SARG__SMB_FILE_INSPECTION_ONLY, optr, olen) == 0)) { sc->smb_file_inspection = DCE2_SMB_FILE_INSPECTION__ONLY; } else { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", option, *ptr - optr, optr); return DCE2_RET__ERROR; } state = DCE2_SMB_FILE_LIST_STATE__ENABLEMENT_END; continue; } break; case DCE2_SMB_FILE_LIST_STATE__ENABLEMENT_END: if (no_list) { return DCE2_RET__SUCCESS; } else if (DCE2_IsListSepChar(c)) { state = DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_START; } else if (DCE2_IsListEndChar(c)) { state = DCE2_SMB_FILE_LIST_STATE__END; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%.*s\"", option, *ptr - option_start, option_start); return DCE2_RET__ERROR; } break; case DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__START)) { optr = *ptr; state = DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%.*s\"", option, *ptr - option_start, option_start); return DCE2_RET__ERROR; } break; case DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { int olen = *ptr - optr; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", option, *ptr - optr, optr); return DCE2_RET__ERROR; } if ((olen == strlen(DCE2_SARG__SMB_FILE_INSPECTION_DEPTH)) && (strncasecmp(DCE2_SARG__SMB_FILE_INSPECTION_DEPTH, optr, olen) == 0)) { state = DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE_START; } else { DCE2_ScError("Invalid \"%s\" argument: \"%.*s\"", option, *ptr - optr, optr); return DCE2_RET__ERROR; } continue; } break; case DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE_START: if (DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { optr = *ptr; state = DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%.*s\"", option, *ptr - option_start, option_start); return DCE2_RET__ERROR; } break; case DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE: if (!DCE2_IsWordChar(c, DCE2_WORD_CHAR_POSITION__MIDDLE)) { char *start_value = optr; if (!DCE2_IsWordChar(last_char, DCE2_WORD_CHAR_POSITION__END)) { DCE2_ScError("Invalid argument to \"%s\": \"%.*s\". Value " "must be between -1 and "STDi64".\n", DCE2_SARG__SMB_FILE_INSPECTION_DEPTH, optr - start_value, start_value, INT64_MAX); return DCE2_RET__ERROR; } if (DCE2_ParseValue(&optr, *ptr, &sc->smb_file_depth, DCE2_INT_TYPE__INT64) != DCE2_RET__SUCCESS) { DCE2_ScError("Invalid argument to \"%s\": \"%.*s\". Value " "must be between -1 and "STDi64".\n", DCE2_SARG__SMB_FILE_INSPECTION_DEPTH, optr - start_value, start_value, INT64_MAX); return DCE2_RET__ERROR; } if ((sc->smb_file_depth < 0) && (sc->smb_file_depth != -1)) { DCE2_ScError("Invalid argument to \"%s\": "STDi64". Value " "must be between -1 and "STDi64".\n", DCE2_SARG__SMB_FILE_INSPECTION_DEPTH, sc->smb_file_depth, INT64_MAX); return DCE2_RET__ERROR; } state = DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE_END; continue; } break; case DCE2_SMB_FILE_LIST_STATE__FILE_DEPTH_VALUE_END: if (DCE2_IsListEndChar(c)) { state = DCE2_SMB_FILE_LIST_STATE__END; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid \"%s\" syntax: \"%.*s\"", option, *ptr - option_start, option_start); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid %s state: %d", __FILE__, __LINE__, option, state); return DCE2_RET__ERROR; } last_char = c; (*ptr)++; } if (state != DCE2_SMB_FILE_LIST_STATE__END) { DCE2_ScError("Invalid \"%s\" syntax: \"%.*s\"", option, *ptr - option_start, option_start); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ScAddToRoutingTable() * * Adds the server configuration to the appropriate routing table * (IPv4 or IPv6) based on the ip addresses and nets (as sfip_t) * from the passed in queue. A pointer to the server configuration * is saved in the routing table for each ip set. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * DCE2_Queue * * Queue containing the IPs and nets to add to the routing * tables for this server configuration. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully add all * of the IPs and nets to the routing tables for this * server configuration. * DCE2_RET__ERROR if an error occured in trying to add all * of the IPs and nets to the routing tables for this * server configuration. * ********************************************************************/ static DCE2_Ret DCE2_ScAddToRoutingTable(DCE2_Config *config, DCE2_ServerConfig *sc, DCE2_Queue *ip_queue) { sfip_t *ip; sfip_t tmp_ip; if ((config == NULL) || (sc == NULL) || (ip_queue == NULL)) return DCE2_RET__ERROR; for (ip = (sfip_t *)DCE2_QueueFirst(ip_queue); ip != NULL; ip = (sfip_t *)DCE2_QueueNext(ip_queue)) { int rt_status; /* For IPv4, need to pass the address in host order */ if (ip->family == AF_INET) { if (sfip_set_ip(&tmp_ip, ip) != SFIP_SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy IPv4 address.", __FILE__, __LINE__); return DCE2_RET__ERROR; } tmp_ip.ip32[0] = ntohl(tmp_ip.ip32[0]); /* Just set ip to tmp_ip since we don't need to modify ip */ ip = &tmp_ip; } if (config->sconfigs == NULL) { config->sconfigs = sfrt_new(DIR_16_4x4_16x5_4x4, IPv6, 100, 20); if (config->sconfigs == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d): Failed to create server configuration " "routing table.", __FILE__, __LINE__); return DCE2_RET__ERROR; } } else { DCE2_ServerConfig *conf; conf = (DCE2_ServerConfig *)sfrt_search((void *)ip, (unsigned char)ip->bits, config->sconfigs); if (conf != NULL) { DCE2_ScError("\"%s\": Cannot have the same net in different " "server configurations", DCE2_SOPT__NET); return DCE2_RET__ERROR; } } rt_status = sfrt_insert((void *)ip, (unsigned char)ip->bits, (void *)sc, RT_FAVOR_SPECIFIC, config->sconfigs); if (rt_status != RT_SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to insert net into routing table.", __FILE__, __LINE__); return DCE2_RET__ERROR; } /* This is a count of the number of pointers or references to this * server configuration in the routing tables. */ sc->ref_count++; } return DCE2_RET__SUCCESS; } /********************************************************************* * Function: DCE2_ScIpListDataFree() * * Callback given to the queue for storing sfip_t structures. * * Arguments: * void * * The sfip_t structure to free. * * Returns: None * *********************************************************************/ static void DCE2_ScIpListDataFree(void *data) { if (data == NULL) return; DCE2_Free(data, sizeof(sfip_t), DCE2_MEM_TYPE__CONFIG); } /******************************************************************** * Function: DCE2_ScGetConfig() * * Convenience function for run-time retrieving of a server * configuration. Does a lookup in the appropriate routing table * based on the IPs in the packet structure. * * Arguments: * const SFSnortPacket * * Pointer to the packet structure flowing through the system. * * Returns: * DCE2_ServerConfig * * A pointer to a valid server configuration if a routing * table lookup succeeded. * A pointer to the default server configuration if an entry * in the routing table could not be found. * ********************************************************************/ const DCE2_ServerConfig * DCE2_ScGetConfig(const SFSnortPacket *p) { const DCE2_ServerConfig *sc = NULL; snort_ip_p ip; sfip_t tmp_ip; if (dce2_eval_config == NULL) return NULL; if (DCE2_SsnFromClient(p)) ip = GET_DST_IP(((SFSnortPacket *)p)); else ip = GET_SRC_IP(((SFSnortPacket *)p)); if (dce2_eval_config->sconfigs != NULL) { if (ip->family == AF_INET) { if (sfip_set_ip(&tmp_ip, ip) != SFIP_SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to set IPv4 address for lookup in " "routing table", __FILE__, __LINE__); /* Just return default configuration */ return dce2_eval_config->dconfig; } tmp_ip.ip32[0] = ntohl(tmp_ip.ip32[0]); /* Just set ip to tmp_ip since we don't need to modify ip */ ip = &tmp_ip; } sc = sfrt_lookup((void *)ip, dce2_eval_config->sconfigs); } if (sc == NULL) return dce2_eval_config->dconfig; return sc; } /********************************************************************* * Function: DCE2_ScSmbShareCompare() * * Callback for the list used to hold the invalid smb shares for * doing a comparison. Don't want any duplicates. * * Arguments: * const void * * The first share name to compare. * const void * * The second share name to compare. * * Returns: * int * 0 if the shares are equal. * -1 if the shares are not equal. * *********************************************************************/ static int DCE2_ScSmbShareCompare(const void *a, const void *b) { DCE2_SmbShare *ashare = (DCE2_SmbShare *)a; DCE2_SmbShare *bshare = (DCE2_SmbShare *)b; if ((ashare == NULL) || (bshare == NULL)) return -1; /* Just check the ascii string */ if (ashare->ascii_str_len != bshare->ascii_str_len) return -1; if (memcmp(ashare->ascii_str, bshare->ascii_str, ashare->ascii_str_len) == 0) return 0; /* Only care about equality for dups */ return -1; } /********************************************************************* * Function: DCE2_ScSmbShareFree() * * Callback to the list used to hold the invalid smb shares for * freeing the shares. * * Arguments: * void * * Pointer to the share structure. * * Returns: None * *********************************************************************/ static void DCE2_ScSmbShareFree(void *data) { DCE2_SmbShare *smb_share = (DCE2_SmbShare *)data; if (smb_share == NULL) return; DCE2_Free((void *)smb_share->unicode_str, smb_share->unicode_str_len, DCE2_MEM_TYPE__CONFIG); DCE2_Free((void *)smb_share->ascii_str, smb_share->ascii_str_len, DCE2_MEM_TYPE__CONFIG); DCE2_Free((void *)smb_share, sizeof(DCE2_SmbShare), DCE2_MEM_TYPE__CONFIG); } /******************************************************************** * Function: DCE2_GcPrintConfig() * * Prints the DCE/RPC global configuration. * * Arguments: * DCE2_GlobalConfig * * Pointer to the global configuration structure. * * Returns: None * ********************************************************************/ static void DCE2_GcPrintConfig(const DCE2_GlobalConfig *gc) { char events[1000]; if (gc == NULL) return; _dpd.logMsg("DCE/RPC 2 Preprocessor Configuration\n"); _dpd.logMsg(" Global Configuration\n"); if(gc->disabled) { _dpd.logMsg(" DCE/RPC 2 Preprocessor: INACTIVE\n"); } _dpd.logMsg(" DCE/RPC Defragmentation: %s\n", gc->dce_defrag == DCE2_CS__ENABLED ? "Enabled" : "Disabled"); if ((gc->dce_defrag == DCE2_CS__ENABLED) && (gc->max_frag_len != DCE2_SENTINEL)) _dpd.logMsg(" Max DCE/RPC Frag Size: %u bytes\n", gc->max_frag_len); _dpd.logMsg(" Memcap: %u KB\n", gc->memcap / 1024); if (gc->reassemble_threshold != 0) _dpd.logMsg(" Reassemble threshold: %u bytes\n", gc->reassemble_threshold); snprintf(events, sizeof(events), " Events: "); events[sizeof(events) - 1] = '\0'; if (gc->event_mask == DCE2_EVENT_FLAG__NULL) { strncat(events, DCE2_GARG__EVENTS_NONE, (sizeof(events) - 1) - strlen(events)); } else { if (gc->event_mask & DCE2_EVENT_FLAG__MEMCAP) { strncat(events, DCE2_GARG__EVENTS_MEMCAP, (sizeof(events) - 1) - strlen(events)); strncat(events, " ", (sizeof(events) - 1) - strlen(events)); } if (gc->event_mask & DCE2_EVENT_FLAG__SMB) { strncat(events, DCE2_GARG__EVENTS_SMB, (sizeof(events) - 1) - strlen(events)); strncat(events, " ", (sizeof(events) - 1) - strlen(events)); } if (gc->event_mask & DCE2_EVENT_FLAG__CO) { strncat(events, DCE2_GARG__EVENTS_CO, (sizeof(events) - 1) - strlen(events)); strncat(events, " ", (sizeof(events) - 1) - strlen(events)); } if (gc->event_mask & DCE2_EVENT_FLAG__CL) { strncat(events, DCE2_GARG__EVENTS_CL, (sizeof(events) - 1) - strlen(events)); strncat(events, " ", (sizeof(events) - 1) - strlen(events)); } } strncat(events, "\n", (sizeof(events) - 1) - strlen(events)); _dpd.logMsg(events); // Just use the events buffer snprintf(events, sizeof(events), " SMB Fingerprint policy: "); if (gc->smb_fingerprint_policy == DCE2_SMB_FINGERPRINT__NONE) strncat(events, "Disabled\n", (sizeof(events) - 1) - strlen(events)); else if (gc->smb_fingerprint_policy == (DCE2_SMB_FINGERPRINT__CLIENT|DCE2_SMB_FINGERPRINT__SERVER)) strncat(events, "Client and Server\n", (sizeof(events) - 1) - strlen(events)); else if (gc->smb_fingerprint_policy & DCE2_SMB_FINGERPRINT__CLIENT) strncat(events, "Client\n", (sizeof(events) - 1) - strlen(events)); else if (gc->smb_fingerprint_policy & DCE2_SMB_FINGERPRINT__SERVER) strncat(events, "Server\n", (sizeof(events) - 1) - strlen(events)); _dpd.logMsg(events); } /******************************************************************** * Function: DCE2_ScPrintConfig() * * Prints a DCE/RPC server configuration. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * DCE2_Queue * * Queue that holds the nets for printing. * * Returns: None * ********************************************************************/ static void DCE2_ScPrintConfig(const DCE2_ServerConfig *sc, DCE2_Queue *net_queue) { char *policy = NULL; unsigned int i; if (sc == NULL) return; if (!DCE2_QueueIsEmpty(net_queue)) { char nets[80]; _dpd.logMsg(" Server Configuration\n"); snprintf(nets, sizeof(nets), " Net: "); nets[sizeof(nets) - 1] = '\0'; while (!DCE2_QueueIsEmpty(net_queue)) { char *ip_addr; uint8_t prefix; sfip_t *ip; char tmp_net[INET6_ADDRSTRLEN + 5]; /* Enough for IPv4 plus netmask or full IPv6 plus prefix */ ip = (sfip_t *)DCE2_QueueDequeue(net_queue); ip_addr = sfip_to_str(ip); prefix = (uint8_t)ip->bits; DCE2_Free((void *)ip, sizeof(sfip_t), DCE2_MEM_TYPE__CONFIG); snprintf(tmp_net, sizeof(tmp_net), "%s/%u ", ip_addr, prefix); tmp_net[sizeof(tmp_net) - 1] = '\0'; if ((strlen(nets) + strlen(tmp_net)) >= sizeof(nets)) { _dpd.logMsg("%s\n", nets); snprintf(nets, sizeof(nets), " %s", tmp_net); nets[sizeof(nets) - 1] = '\0'; } else { strncat(nets, tmp_net, (sizeof(nets) - 1) - strlen(nets)); } } _dpd.logMsg("%s\n", nets); } else { _dpd.logMsg(" Server Default Configuration\n"); } switch (sc->policy) { case DCE2_POLICY__WIN2000: policy = DCE2_SARG__POLICY_WIN2000; break; case DCE2_POLICY__WINXP: policy = DCE2_SARG__POLICY_WINXP; break; case DCE2_POLICY__WINVISTA: policy = DCE2_SARG__POLICY_WINVISTA; break; case DCE2_POLICY__WIN2003: policy = DCE2_SARG__POLICY_WIN2003; break; case DCE2_POLICY__WIN2008: policy = DCE2_SARG__POLICY_WIN2008; break; case DCE2_POLICY__WIN7: policy = DCE2_SARG__POLICY_WIN7; break; case DCE2_POLICY__SAMBA: policy = DCE2_SARG__POLICY_SAMBA; break; case DCE2_POLICY__SAMBA_3_0_37: policy = DCE2_SARG__POLICY_SAMBA_3_0_37; break; case DCE2_POLICY__SAMBA_3_0_22: policy = DCE2_SARG__POLICY_SAMBA_3_0_22; break; case DCE2_POLICY__SAMBA_3_0_20: policy = DCE2_SARG__POLICY_SAMBA_3_0_20; break; default: DCE2_QueueDestroy(net_queue); DCE2_Die("%s(%d) Invalid policy: %d", __FILE__, __LINE__, sc->policy); } _dpd.logMsg(" Policy: %s\n", policy); DCE2_ScPrintPorts(sc, 0); for (i = 0; i < DCE2_PORTS__MAX; i++) { if (DCE2_IsPortSet(sc->http_proxy_ports, (uint16_t)i)) { _dpd.logMsg(" Autodetect on RPC over HTTP proxy detect ports: %s\n", sc->autodetect_http_proxy_ports == DCE2_CS__ENABLED ? "Yes" : "No"); break; } } DCE2_ScPrintPorts(sc, 1); for (i = 0; i < DCE2_PORTS__MAX; i++) { if (DCE2_IsPortSet(sc->smb_ports, (uint16_t)i) || DCE2_IsPortSet(sc->auto_smb_ports, (uint16_t)i)) { break; } } if ((i != DCE2_PORTS__MAX) && (sc->smb_invalid_shares != NULL)) { char share_str[80]; DCE2_SmbShare *share; snprintf(share_str, sizeof(share_str), " Invalid SMB shares: "); share_str[sizeof(share_str) - 1] = '\0'; for (share = DCE2_ListFirst(sc->smb_invalid_shares); share != NULL; share = DCE2_ListNext(sc->smb_invalid_shares)) { char *tmp_share; unsigned int tmp_share_len; /* Ascii string will be NULL terminated. Also alloc enough for space. * Note that if share is longer than the size of the buffer it will be * put into, it will be truncated */ tmp_share_len = strlen(share->ascii_str) + 2; tmp_share = (char *)DCE2_Alloc(tmp_share_len, DCE2_MEM_TYPE__CONFIG); if (tmp_share == NULL) { DCE2_QueueDestroy(net_queue); DCE2_Die("%s(%d) Failed to allocate memory for printing " "configuration.", __FILE__, __LINE__); } snprintf(tmp_share, tmp_share_len, "%s ", share->ascii_str); tmp_share[tmp_share_len - 1] = '\0'; if ((strlen(share_str) + strlen(tmp_share)) >= sizeof(share_str)) { _dpd.logMsg("%s\n", share_str); snprintf(share_str, sizeof(share_str), " %s", tmp_share); share_str[sizeof(share_str) - 1] = '\0'; } else { strncat(share_str, tmp_share, (sizeof(share_str) - 1) - strlen(share_str)); } DCE2_Free((void *)tmp_share, tmp_share_len, DCE2_MEM_TYPE__CONFIG); } _dpd.logMsg("%s\n", share_str); } if (i != DCE2_PORTS__MAX) { if (sc->smb_max_chain == 0) _dpd.logMsg(" Maximum SMB command chaining: Unlimitied\n"); else if (sc->smb_max_chain == 1) _dpd.logMsg(" Maximum SMB command chaining: No chaining allowed\n"); else _dpd.logMsg(" Maximum SMB command chaining: %u commands\n", sc->smb_max_chain); if (!DCE2_ScSmbFileInspection(sc)) { _dpd.logMsg(" SMB file inspection: Disabled\n"); } else { int64_t file_depth = DCE2_ScSmbFileDepth(sc); if (DCE2_ScSmbFileInspectionOnly(sc)) _dpd.logMsg(" SMB file inspection: Only\n"); else _dpd.logMsg(" SMB file inspection: Enabled\n"); if (file_depth == -1) _dpd.logMsg(" File depth: Disabled\n"); else if (file_depth == 0) _dpd.logMsg(" File depth: Unlimited\n"); else _dpd.logMsg(" File depth: "STDi64"\n", file_depth); } } } /********************************************************************* * Function: DCE2_ScPrintPorts() * * Used for gathering the bits set in a detect or autodetect port * array mask and displaying in a readable form. * * Arguments: * const uint8_t * * The port array mask to get the set bits from. * char * * An array to print the readable string to. * int * The size of the array to print the readable string to. * * Returns: None * *********************************************************************/ static void DCE2_ScPrintPorts(const DCE2_ServerConfig *sc, int autodetect) { unsigned int pps_idx; DCE2_PrintPortsStruct pps[5]; pps[0].trans_str = "SMB"; pps[1].trans_str = "TCP"; pps[2].trans_str = "UDP"; pps[3].trans_str = "RPC over HTTP server"; pps[4].trans_str = "RPC over HTTP proxy"; if (!autodetect) { pps[0].port_array = sc->smb_ports; pps[1].port_array = sc->tcp_ports; pps[2].port_array = sc->udp_ports; pps[3].port_array = sc->http_server_ports; pps[4].port_array = sc->http_proxy_ports; if (_dpd.isPafEnabled()) _dpd.logMsg(" Detect ports (PAF)\n"); else _dpd.logMsg(" Detect ports\n"); } else { pps[0].port_array = sc->auto_smb_ports; pps[1].port_array = sc->auto_tcp_ports; pps[2].port_array = sc->auto_udp_ports; pps[3].port_array = sc->auto_http_server_ports; pps[4].port_array = sc->auto_http_proxy_ports; if (_dpd.isPafEnabled()) _dpd.logMsg(" Autodetect ports (PAF)\n"); else _dpd.logMsg(" Autodetect ports\n"); } for (pps_idx = 0; pps_idx < sizeof(pps) / sizeof(DCE2_PrintPortsStruct); pps_idx++) { int port_start = 1; unsigned int start_port = 0, end_port = 0; unsigned int i; char ports[80]; int got_port = 0; const uint8_t *port_mask_array; snprintf(ports, sizeof(ports), " %s: ", pps[pps_idx].trans_str); ports[sizeof(ports) - 1] = '\0'; port_mask_array = pps[pps_idx].port_array; for (i = 0; i < DCE2_PORTS__MAX; i++) { if (port_start) { if (DCE2_IsPortSet(port_mask_array, (uint16_t)i)) { start_port = i; end_port = i; port_start = 0; got_port = 1; } } if (!port_start) { if (!DCE2_IsPortSet(port_mask_array, (uint16_t)i) || (i == (DCE2_PORTS__MAX - 1))) { char tmp_port[15]; /* big enough to hold a full port range */ if (i == (DCE2_PORTS__MAX - 1) && DCE2_IsPortSet(port_mask_array, (uint16_t)i)) end_port = i; /* Only print range if more than 2 ports */ if ((start_port + 1) < end_port) { snprintf(tmp_port, sizeof(tmp_port), "%u-%u ", start_port, end_port); tmp_port[sizeof(tmp_port) - 1] = '\0'; } else if (start_port < end_port) { snprintf(tmp_port, sizeof(tmp_port), "%u %u ", start_port, end_port); tmp_port[sizeof(tmp_port) - 1] = '\0'; } else { snprintf(tmp_port, sizeof(tmp_port), "%u ", start_port); tmp_port[sizeof(tmp_port) - 1] = '\0'; } if ((strlen(ports) + strlen(tmp_port)) >= sizeof(ports)) { _dpd.logMsg("%s\n", ports); snprintf(ports, sizeof(ports), " %s", tmp_port); ports[sizeof(ports) - 1] = '\0'; } else { strncat(ports, tmp_port, (sizeof(ports) - 1) - strlen(ports)); } port_start = 1; } else { end_port = i; } } } if (got_port) { _dpd.logMsg("%s\n", ports); } else { strncat(ports, "None", (sizeof(ports) - 1) - strlen(ports)); _dpd.logMsg("%s\n", ports); } } } /********************************************************************* * Function: DCE2_ScCheckTransport() * * Makes sure at least one transport for detect or autodetect. If * not there is no sense in running this policy since no detection * will ever be done. * * Arguments: * void * * Pointer to a server configuration structure. * * Returns: -1 on error * *********************************************************************/ static int DCE2_ScCheckTransport(void *data) { unsigned int i; DCE2_ServerConfig *sc = (DCE2_ServerConfig *)data; if (data == NULL) return 0; for (i = 0; i < DCE2_PORTS__MAX_INDEX - 3; i += 4) { if (*((uint32_t *)&sc->smb_ports[i]) || *((uint32_t *)&sc->tcp_ports[i]) || *((uint32_t *)&sc->udp_ports[i]) || *((uint32_t *)&sc->http_proxy_ports[i]) || *((uint32_t *)&sc->http_server_ports[i]) || *((uint32_t *)&sc->auto_smb_ports[i]) || *((uint32_t *)&sc->auto_tcp_ports[i]) || *((uint32_t *)&sc->auto_udp_ports[i]) || *((uint32_t *)&sc->auto_http_proxy_ports[i]) || *((uint32_t *)&sc->auto_http_server_ports[i])) { return 0; } } DCE2_Log(DCE2_LOG_TYPE__WARN, "%s: Must have at least one detect or autodetect transport " "enabled for a server configuration if target-based/attribute-" "table/adaptive-profiles is not enabled. However, if specific " "server configurations are configured, the default server " "configuration does not need to have any detect/autodetect " "transports configured.", DCE2_SNAME); return -1; } /********************************************************************* * Function: DCE2_ScCheckTransports() * * Makes sure at least one transport for detect or autodetect. If * not there is no sense in running this policy since no detection * will ever be done. * * Arguments: None * * Returns: -1 on error * *********************************************************************/ int DCE2_ScCheckTransports(DCE2_Config *config) { if (config == NULL) return 0; if (config->sconfigs == NULL) return DCE2_ScCheckTransport(config->dconfig); return sfrt_iterate2(config->sconfigs, DCE2_ScCheckTransport); } /********************************************************************* * Function: DCE2_ScCheckPortOverlap() * * Makes sure there are no overlapping detect ports configured. * It's okay for overlap between TCP and UDP. * Transports SMB, TCP, RPC over HTTP proxy and RPC over HTTP server * cannot define ports that overlap. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if no overlapping ports. * DCE2_RET__ERROR if overlapping ports. * *********************************************************************/ static DCE2_Ret DCE2_ScCheckPortOverlap(const DCE2_ServerConfig *sc) { unsigned int i; /* All port array masks should be the same size */ for (i = 0; i < sizeof(sc->smb_ports) - 3; i += 4) { /* Take 4 bytes at a time and bitwise and them. Should * be 0 if there are no overlapping ports. */ uint32_t overlap = *((uint32_t *)&sc->smb_ports[i]) & *((uint32_t *)&sc->tcp_ports[i]); uint32_t cached; if (overlap) { DCE2_ScError("Cannot have overlapping detect ports in " "smb, tcp, rpc-over-http-proxy or rpc-over-http-server. " "Overlapping port detected in tcp ports"); return DCE2_RET__ERROR; } cached = *((uint32_t *)&sc->smb_ports[i]) | *((uint32_t *)&sc->tcp_ports[i]); overlap = *((uint32_t *)&sc->http_proxy_ports[i]) & cached; if (overlap) { DCE2_ScError("Cannot have overlapping detect ports in " "smb, tcp, rpc-over-http-proxy or rpc-over-http-server. " "Overlapping port detected in rpc-over-http-proxy ports"); return DCE2_RET__ERROR; } cached |= *((uint32_t *)&sc->http_proxy_ports[i]); overlap = *((uint32_t *)&sc->http_server_ports[i]) & cached; if (overlap) { DCE2_ScError("Cannot have overlapping detect ports in " "smb, tcp, rpc-over-http-proxy or rpc-over-http-server. " "Overlapping port detected in rpc-over-http-server ports"); return DCE2_RET__ERROR; } } return DCE2_RET__SUCCESS; } /********************************************************************* * Function: DCE2_AddPortsToStream5Filter() * * Add all detect ports to stream5 filter so stream sessions are * created. Don't do autodetect ports and rely on rules to set * any off ports. This is mainly necessary for SMB ports where * we are looking for SMB vulnerabilities in the preprocessor. * * Arguments: * DCE2_ServerConfig * * Pointer to a server configuration structure. * * Returns: None * *********************************************************************/ static void DCE2_AddPortsToStream5Filter(struct _SnortConfig *snortConf, DCE2_ServerConfig *sc, tSfPolicyId policy_id) { unsigned int port; for (port = 0; port < DCE2_PORTS__MAX; port++) { if (DCE2_IsPortSet(sc->smb_ports, (uint16_t)port)) { _dpd.streamAPI->set_port_filter_status (snortConf, IPPROTO_TCP, (uint16_t)port, PORT_MONITOR_SESSION, policy_id, 1); } if (DCE2_IsPortSet(sc->tcp_ports, (uint16_t)port)) { _dpd.streamAPI->set_port_filter_status (snortConf, IPPROTO_TCP, (uint16_t)port, PORT_MONITOR_SESSION, policy_id, 1); } if (DCE2_IsPortSet(sc->udp_ports, (uint16_t)port)) { _dpd.streamAPI->set_port_filter_status (snortConf, IPPROTO_UDP, (uint16_t)port, PORT_MONITOR_SESSION, policy_id, 1); } if (DCE2_IsPortSet(sc->http_proxy_ports, (uint16_t)port)) { _dpd.streamAPI->set_port_filter_status (snortConf, IPPROTO_TCP, (uint16_t)port, PORT_MONITOR_SESSION, policy_id, 1); } if (DCE2_IsPortSet(sc->http_server_ports, (uint16_t)port)) { _dpd.streamAPI->set_port_filter_status (snortConf, IPPROTO_TCP, (uint16_t)port, PORT_MONITOR_SESSION, policy_id, 1); } } } /******************************************************************** * Function: DCE2_ParseIpList() * * Parses an IP list, creates sfip_t for each IP address/net and * adds to a queue. * * Arguments: * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the IP list. * char * * Pointer to the end of the string. * DCE2_Queue * * Queue to store the sfip_t structures. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * IP list. * DCE2_RET__ERROR if an error occured in parsing the IP list. * ********************************************************************/ DCE2_Ret DCE2_ParseIpList(char **ptr, char *end, DCE2_Queue *ip_queue) { DCE2_IpListState state = DCE2_IP_LIST_STATE__START; sfip_t ip; while (*ptr < end) { char c = **ptr; if (state == DCE2_IP_LIST_STATE__END) break; switch (state) { case DCE2_IP_LIST_STATE__START: if (DCE2_IsIpChar(c)) { DCE2_Ret status = DCE2_ParseIp(ptr, end, &ip); sfip_t *ip_copy; if (status != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; ip_copy = (sfip_t *)DCE2_Alloc(sizeof(sfip_t), DCE2_MEM_TYPE__CONFIG); if (ip_copy == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to allocate memory for IP structure.", __FILE__, __LINE__); return DCE2_RET__ERROR; } memcpy((void *)ip_copy, (void *)&ip, sizeof(sfip_t)); status = DCE2_QueueEnqueue(ip_queue, ip_copy); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)ip_copy, sizeof(sfip_t), DCE2_MEM_TYPE__CONFIG); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to queue an IP structure.", __FILE__, __LINE__); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } else if (DCE2_IsListStartChar(c)) { state = DCE2_IP_LIST_STATE__IP_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid IP list: \"%s\"", *ptr); return DCE2_RET__ERROR; } break; case DCE2_IP_LIST_STATE__IP_START: if (DCE2_IsIpChar(c)) { DCE2_Ret status = DCE2_ParseIp(ptr, end, &ip); sfip_t *ip_copy; if (status != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; ip_copy = (sfip_t *)DCE2_Alloc(sizeof(sfip_t), DCE2_MEM_TYPE__CONFIG); if (ip_copy == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to allocate memory for IP structure.", __FILE__, __LINE__); return DCE2_RET__ERROR; } memcpy((void *)ip_copy, (void *)&ip, sizeof(sfip_t)); status = DCE2_QueueEnqueue(ip_queue, ip_copy); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)ip_copy, sizeof(sfip_t), DCE2_MEM_TYPE__CONFIG); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to queue an IP structure.", __FILE__, __LINE__); return DCE2_RET__ERROR; } state = DCE2_IP_LIST_STATE__IP_END; continue; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid IP list: \"%s\"", *ptr); return DCE2_RET__ERROR; } break; case DCE2_IP_LIST_STATE__IP_END: if (DCE2_IsListEndChar(c)) { state = DCE2_IP_LIST_STATE__END; } else if (DCE2_IsListSepChar(c)) { state = DCE2_IP_LIST_STATE__IP_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid IP list: \"%s\"", *ptr); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid IP list state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } (*ptr)++; } if (state != DCE2_IP_LIST_STATE__END) { DCE2_ScError("Invalid IP list: \"%s\"", *ptr); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ParseIP() * * Parses an IP address or net. Gobbles up ':', '.', '/' and hex * digits. Not very smart, but we'll let sfip_pton take care of it. * * Arguments: * char ** * Pointer to the pointer to the current position in the string * being parsed. This is updated to the current position * after parsing the IP. * char * * Pointer to the end of the string. * sfip_t * * Pointer to an sfip_t structure that should be filled in * based on the IP or net parsed. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * IP address or net. * DCE2_RET__ERROR if an error occured in parsing the IP * address or net. * ********************************************************************/ DCE2_Ret DCE2_ParseIp(char **ptr, char *end, sfip_t *ip) { DCE2_IpState state = DCE2_IP_STATE__START; char *ip_start = NULL; char ip_addr[INET6_ADDRSTRLEN + 5]; /* Enough for IPv4 plus netmask or full IPv6 plus prefix */ memset(ip_addr, 0, sizeof(ip_addr)); while (*ptr < end) { char c = **ptr; switch (state) { case DCE2_IP_STATE__START: if (DCE2_IsIpChar(c)) { ip_start = *ptr; state = DCE2_IP_STATE__IP; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid IP address: \"%s\"", *ptr); return DCE2_RET__ERROR; } break; case DCE2_IP_STATE__IP: if (!DCE2_IsIpChar(c)) { int copy_len = *ptr - ip_start; DCE2_Ret status = DCE2_Memcpy(ip_addr, ip_start, copy_len, ip_addr, ip_addr + sizeof(ip_addr) - 1); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy IP address.", __FILE__, __LINE__); return DCE2_RET__ERROR; } /* No prefix - done with ip */ if (sfip_pton(ip_addr, ip) != SFIP_SUCCESS) { DCE2_ScError("Invalid IP address: \"%.*s\"", copy_len, ip_start); return DCE2_RET__ERROR; } /* Don't allow a zero bit mask */ if (ip->bits == 0) { DCE2_ScError("Invalid IP address with zero bit " "prefix: \"%.*s\"", copy_len, ip_start); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } break; } (*ptr)++; } return DCE2_RET__ERROR; } /******************************************************************** * Function: DCE2_ParsePortList() * * Parses a port list and adds bits associated with the ports * parsed to a bit array. * * Arguments: * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the IP list. * char * * Pointer to the end of the string. * uint8_t * * Pointer to the port array mask to set bits for the ports * parsed. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * port list. * DCE2_RET__ERROR if an error occured in parsing the port list. * ********************************************************************/ DCE2_Ret DCE2_ParsePortList(char **ptr, char *end, uint8_t *port_array) { char *lo_start = NULL; char *hi_start = NULL; DCE2_PortListState state = DCE2_PORT_LIST_STATE__START; uint16_t lo_port = 0, hi_port = 0; int one_port = 0; while (*ptr < end) { char c = **ptr; if (state == DCE2_PORT_LIST_STATE__END) break; switch (state) { case DCE2_PORT_LIST_STATE__START: if (DCE2_IsListStartChar(c)) { state = DCE2_PORT_LIST_STATE__PORT_START; } else if (DCE2_IsPortChar(c)) { one_port = 1; lo_start = *ptr; state = DCE2_PORT_LIST_STATE__PORT_LO; } else if (DCE2_IsPortRangeChar(c)) { one_port = 1; lo_port = 0; state = DCE2_PORT_LIST_STATE__PORT_RANGE; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid port list: \"%s\"", *ptr); return DCE2_RET__ERROR; } break; case DCE2_PORT_LIST_STATE__PORT_START: lo_start = hi_start = NULL; if (DCE2_IsPortChar(c)) { lo_start = *ptr; state = DCE2_PORT_LIST_STATE__PORT_LO; } else if (DCE2_IsPortRangeChar(c)) { lo_port = 0; state = DCE2_PORT_LIST_STATE__PORT_RANGE; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid port list: \"%s\"", *ptr); return DCE2_RET__ERROR; } break; case DCE2_PORT_LIST_STATE__PORT_LO: if (!DCE2_IsPortChar(c)) { DCE2_Ret status = DCE2_GetValue(lo_start, *ptr, &lo_port, 0, DCE2_INT_TYPE__UINT16, 10); if (status != DCE2_RET__SUCCESS) { DCE2_ScError("Invalid port: \"%.*s\"", *ptr - lo_start, lo_start); return DCE2_RET__ERROR; } if (DCE2_IsPortRangeChar(c)) { state = DCE2_PORT_LIST_STATE__PORT_RANGE; } else { DCE2_SetPort(port_array, lo_port); if (one_port) return DCE2_RET__SUCCESS; state = DCE2_PORT_LIST_STATE__PORT_END; continue; } } break; case DCE2_PORT_LIST_STATE__PORT_RANGE: if (DCE2_IsPortChar(c)) { hi_start = *ptr; state = DCE2_PORT_LIST_STATE__PORT_HI; } else { DCE2_SetPortRange(port_array, lo_port, UINT16_MAX); if (one_port) return DCE2_RET__SUCCESS; state = DCE2_PORT_LIST_STATE__PORT_END; continue; } break; case DCE2_PORT_LIST_STATE__PORT_HI: if (!DCE2_IsPortChar(c)) { DCE2_Ret status = DCE2_GetValue(hi_start, *ptr, &hi_port, 0, DCE2_INT_TYPE__UINT16, 10); if (status != DCE2_RET__SUCCESS) { DCE2_ScError("Invalid port: \"%.*s\"", *ptr - hi_start, hi_start); return DCE2_RET__ERROR; } DCE2_SetPortRange(port_array, lo_port, hi_port); if (one_port) return DCE2_RET__SUCCESS; state = DCE2_PORT_LIST_STATE__PORT_END; continue; } break; case DCE2_PORT_LIST_STATE__PORT_END: if (DCE2_IsListEndChar(c)) { state = DCE2_PORT_LIST_STATE__END; } else if (DCE2_IsListSepChar(c)) { state = DCE2_PORT_LIST_STATE__PORT_START; } else if (!DCE2_IsSpaceChar(c)) { DCE2_ScError("Invalid port list: \"%s\"", *ptr); return DCE2_RET__ERROR; } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid port list state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } (*ptr)++; } if (state != DCE2_PORT_LIST_STATE__END) { DCE2_ScError("Invalid port list: \"%s\"", *ptr); return DCE2_RET__ERROR; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ParseValue() * * Parses what should be an integer value and stores in memory * passed in as an argument. This function will parse positive * and negative values and decimal, octal or hexidecimal. The * positive and negative modifiers can only be used with * decimal values. * * Arguments: * char ** * Pointer to the pointer to the current position in the * configuration line. This is updated to the current position * after parsing the IP list. * char * * Pointer to the end of the string. * void * * Pointer to the place where the value should be stored if * parsed successfully. * DCE2_IntType * The type of integer that the value pointer points to and * that should be parsed. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * integer value. * DCE2_RET__ERROR if an error occured in parsing the integer * value. * ********************************************************************/ DCE2_Ret DCE2_ParseValue(char **ptr, char *end, void *value, DCE2_IntType int_type) { char *value_start = *ptr; DCE2_ValueState state = DCE2_VALUE_STATE__START; int negate = 0; while (*ptr < end) { char c = **ptr; switch (state) { case DCE2_VALUE_STATE__START: if (c == DCE2_CFG_TOK__HEX_OCT_START) { /* Just in case it's just a 0 */ value_start = *ptr; state = DCE2_VALUE_STATE__HEX_OR_OCT; } else if (isdigit((int)c)) { value_start = *ptr; state = DCE2_VALUE_STATE__DECIMAL; } else if (c == DCE2_CFG_TOK__MINUS) { if ((int_type == DCE2_INT_TYPE__UINT8) || (int_type == DCE2_INT_TYPE__UINT16) || (int_type == DCE2_INT_TYPE__UINT32) || (int_type == DCE2_INT_TYPE__UINT64)) { return DCE2_RET__ERROR; } negate = 1; state = DCE2_VALUE_STATE__MODIFIER; } else if (c == DCE2_CFG_TOK__PLUS) { negate = 0; state = DCE2_VALUE_STATE__MODIFIER; } else if (!isspace((int)c)) /* Allow for leading space */ { return DCE2_RET__ERROR; } break; case DCE2_VALUE_STATE__MODIFIER: if (isdigit((int)c)) { value_start = *ptr; state = DCE2_VALUE_STATE__DECIMAL; } else { return DCE2_RET__ERROR; } break; case DCE2_VALUE_STATE__HEX_OR_OCT: if (tolower((int)c) == tolower((int)DCE2_CFG_TOK__HEX_SEP)) { state = DCE2_VALUE_STATE__HEX_START; } else if (isdigit((int)c)) { value_start = *ptr; state = DCE2_VALUE_STATE__OCTAL; } else { /* It's just a zero */ return DCE2_GetValue(value_start, *ptr, value, negate, int_type, 10); } break; case DCE2_VALUE_STATE__DECIMAL: if (!isdigit((int)c)) { return DCE2_GetValue(value_start, *ptr, value, negate, int_type, 10); } break; case DCE2_VALUE_STATE__HEX_START: if (isxdigit((int)c)) { value_start = *ptr; state = DCE2_VALUE_STATE__HEX; } else { return DCE2_RET__ERROR; } break; case DCE2_VALUE_STATE__HEX: if (!isxdigit((int)c)) { return DCE2_GetValue(value_start, *ptr, value, negate, int_type, 16); } break; case DCE2_VALUE_STATE__OCTAL: if (!isdigit((int)c)) { return DCE2_GetValue(value_start, *ptr, value, negate, int_type, 8); } break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid value state: %d", __FILE__, __LINE__, state); return DCE2_RET__ERROR; } (*ptr)++; } // In case we hit the end before getting a non-type character. switch (state) { case DCE2_VALUE_STATE__HEX_OR_OCT: return DCE2_GetValue(value_start, end, value, negate, int_type, 8); case DCE2_VALUE_STATE__DECIMAL: return DCE2_GetValue(value_start, end, value, negate, int_type, 10); case DCE2_VALUE_STATE__HEX: return DCE2_GetValue(value_start, end, value, negate, int_type, 16); case DCE2_VALUE_STATE__OCTAL: return DCE2_GetValue(value_start, end, value, negate, int_type, 8); default: break; } /* If we break out of the loop before finishing, didn't * get a valid value */ return DCE2_RET__ERROR; } /******************************************************************** * Function: DCE2_GetValue() * * Parses integer values up to 64 bit unsigned. Stores the value * parsed in memory passed in as an argument. * * Arguments: * char * * Pointer to the first character in the string to parse. * char * * Pointer to the byte after the last character of * the string to parse. * void * * Pointer to the memory where the parsed integer should * be stored on successful parsing. * int * Non-zero if the parsed value should be negated. * Zero if the parsed value should not be negated. * DCE2_IntType * The type of integer we want to parse and the integer type * that the pointer that the parsed value will be put in is. * uint8_t * The base that the parsed value should be converted to. * Only 8, 10 and 16 are supported. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if we were able to successfully parse the * integer to the type specified. * DCE2_RET__ERROR if an error occured in parsing. * ********************************************************************/ DCE2_Ret DCE2_GetValue(char *start, char *end, void *int_value, int negate, DCE2_IntType int_type, uint8_t base) { uint64_t value = 0; uint64_t place = 1; uint64_t max_value = 0; if ((end == NULL) || (start == NULL) || (int_value == NULL)) return DCE2_RET__ERROR; if (start >= end) return DCE2_RET__ERROR; for (end = end - 1; end >= start; end--) { uint64_t add_value; char c = *end; if ((base == 16) && !isxdigit((int)c)) return DCE2_RET__ERROR; else if ((base != 16) && !isdigit((int)c)) return DCE2_RET__ERROR; if (isdigit((int)c)) add_value = (uint64_t)(c - '0') * place; else add_value = (uint64_t)((toupper((int)c) - 'A') + 10) * place; if ((UINT64_MAX - value) < add_value) return DCE2_RET__ERROR; value += add_value; place *= base; } switch (int_type) { case DCE2_INT_TYPE__INT8: max_value = ((UINT8_MAX - 1) / 2); if (negate) max_value++; break; case DCE2_INT_TYPE__UINT8: max_value = UINT8_MAX; break; case DCE2_INT_TYPE__INT16: max_value = ((UINT16_MAX - 1) / 2); if (negate) max_value++; break; case DCE2_INT_TYPE__UINT16: max_value = UINT16_MAX; break; case DCE2_INT_TYPE__INT32: max_value = ((UINT32_MAX - 1) / 2); if (negate) max_value++; break; case DCE2_INT_TYPE__UINT32: max_value = UINT32_MAX; break; case DCE2_INT_TYPE__INT64: max_value = ((UINT64_MAX - 1) / 2); if (negate) max_value++; break; case DCE2_INT_TYPE__UINT64: max_value = UINT64_MAX; break; } if (value > max_value) return DCE2_RET__ERROR; if (negate) value *= -1; switch (int_type) { case DCE2_INT_TYPE__INT8: *(int8_t *)int_value = (int8_t)value; break; case DCE2_INT_TYPE__UINT8: *(uint8_t *)int_value = (uint8_t)value; break; case DCE2_INT_TYPE__INT16: *(int16_t *)int_value = (int16_t)value; break; case DCE2_INT_TYPE__UINT16: *(uint16_t *)int_value = (uint16_t)value; break; case DCE2_INT_TYPE__INT32: *(int32_t *)int_value = (int32_t)value; break; case DCE2_INT_TYPE__UINT32: *(uint32_t *)int_value = (uint32_t)value; break; case DCE2_INT_TYPE__INT64: *(int64_t *)int_value = (int64_t)value; break; case DCE2_INT_TYPE__UINT64: *(uint64_t *)int_value = (uint64_t)value; break; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_GcError() * * Formats errors related to global configuration and puts in * global error buffer. * * Arguments: * const char * * The format string * ... * The arguments to format string * * Returns: None * ********************************************************************/ static void DCE2_GcError(const char *format, ...) { char buf[1024]; va_list ap; va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); buf[sizeof(buf) - 1] = '\0'; snprintf(dce2_config_error, sizeof(dce2_config_error), "%s(%d): \"%s\" configuration: %s. Please consult documentation.", *_dpd.config_file, *_dpd.config_line, DCE2_GNAME, buf); dce2_config_error[sizeof(dce2_config_error) - 1] = '\0'; } /******************************************************************** * Function: DCE2_ScError() * * Formats errors related to server configuration and puts in * global error buffer. * * Arguments: * const char * * The format string * ... * The arguments to format string * * Returns: None * ********************************************************************/ static void DCE2_ScError(const char *format, ...) { char buf[1024]; va_list ap; va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); buf[sizeof(buf) - 1] = '\0'; snprintf(dce2_config_error, sizeof(dce2_config_error), "%s(%d): \"%s\" configuration: %s. Please consult documentation.", *_dpd.config_file, *_dpd.config_line, DCE2_SNAME, buf); dce2_config_error[sizeof(dce2_config_error) - 1] = '\0'; } /******************************************************************** * Function: DCE2_FreeConfig * * Frees a dcerpc configuration * * Arguments: * DCE2_Config * * The configuration to free. * * Returns: None * ********************************************************************/ void DCE2_FreeConfig(DCE2_Config *config) { if (config == NULL) return; if (config->gconfig != NULL) DCE2_Free((void *)config->gconfig, sizeof(DCE2_GlobalConfig), DCE2_MEM_TYPE__CONFIG); if (config->dconfig != NULL) { if (config->dconfig->smb_invalid_shares != NULL) DCE2_ListDestroy(config->dconfig->smb_invalid_shares); DCE2_Free((void *)config->dconfig, sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); } /* Free routing tables and server configurations */ if (config->sconfigs != NULL) { /* UnRegister routing table memory */ DCE2_UnRegMem(sfrt_usage(config->sconfigs), DCE2_MEM_TYPE__RT); sfrt_cleanup(config->sconfigs, DCE2_ServerConfigCleanup); sfrt_free(config->sconfigs); } DCE2_Free((void *)config, sizeof(DCE2_Config), DCE2_MEM_TYPE__CONFIG); } /******************************************************************** * Function: DCE2_FreeConfigs * * Frees a dcerpc configuration * * Arguments: * DCE2_Config * * The configuration to free. * * Returns: None * ********************************************************************/ static int DCE2_FreeConfigsPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { DCE2_Config *pPolicyConfig = (DCE2_Config *)pData; //do any housekeeping before freeing DCE22_Config sfPolicyUserDataClear (config, policyId); DCE2_FreeConfig(pPolicyConfig); return 0; } void DCE2_FreeConfigs(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, DCE2_FreeConfigsPolicy); sfPolicyConfigDelete(config); } /****************************************************************** * Function: DCE2_ServerConfigCleanup() * * Free server configurations in routing table. Each server * configuration keeps a reference count of the number of pointers * in the routing table that are pointed to it. The server * configuration is only freed when this count reaches zero. * * Arguments: * void * * Pointer to server configuration. * * Returns: None * ******************************************************************/ static void DCE2_ServerConfigCleanup(void *data) { DCE2_ServerConfig *sc = (DCE2_ServerConfig *)data; if (sc != NULL) { sc->ref_count--; if (sc->ref_count == 0) { DCE2_ListDestroy(sc->smb_invalid_shares); DCE2_Free((void *)sc, sizeof(DCE2_ServerConfig), DCE2_MEM_TYPE__CONFIG); } } } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_event.h0000644000000000000000000001332612260565732020572 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Handles processing of events generated by the preprocessor. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _DCE2_EVENT_H_ #define _DCE2_EVENT_H_ #include "dce2_session.h" #include "dce2_config.h" #include "snort_debug.h" #include "dcerpc.h" #include "sf_types.h" /******************************************************************** * Macros ********************************************************************/ #define GENERATOR_DCE2 133 /******************************************************************** * Externs ********************************************************************/ extern char *dce2_pdu_types[DCERPC_PDU_TYPE__MAX]; /******************************************************************** * Enumerations ********************************************************************/ /* Since this is mirrored in generators.h via #defines, any * additions to this should go at the end, just before * DCE2_EVENT__MAX. It is important the the sids stay the * same in generators.h as these are also in gen-msg.map */ typedef enum _DCE2_Event { DCE2_EVENT__NO_EVENT = 0, DCE2_EVENT__MEMCAP, DCE2_EVENT__SMB_BAD_NBSS_TYPE, DCE2_EVENT__SMB_BAD_TYPE, DCE2_EVENT__SMB_BAD_ID, DCE2_EVENT__SMB_BAD_WCT, DCE2_EVENT__SMB_BAD_BCC, DCE2_EVENT__SMB_BAD_FORMAT, DCE2_EVENT__SMB_BAD_OFF, DCE2_EVENT__SMB_TDCNT_ZERO, DCE2_EVENT__SMB_NB_LT_SMBHDR, DCE2_EVENT__SMB_NB_LT_COM, DCE2_EVENT__SMB_NB_LT_BCC, DCE2_EVENT__SMB_NB_LT_DSIZE, DCE2_EVENT__SMB_TDCNT_LT_DSIZE, DCE2_EVENT__SMB_DSENT_GT_TDCNT, DCE2_EVENT__SMB_BCC_LT_DSIZE, DCE2_EVENT__SMB_INVALID_DSIZE, DCE2_EVENT__SMB_EXCESSIVE_TREE_CONNECTS, DCE2_EVENT__SMB_EXCESSIVE_READS, DCE2_EVENT__SMB_EXCESSIVE_CHAINING, DCE2_EVENT__SMB_MULT_CHAIN_SS, DCE2_EVENT__SMB_MULT_CHAIN_TC, DCE2_EVENT__SMB_CHAIN_SS_LOGOFF, DCE2_EVENT__SMB_CHAIN_TC_TDIS, DCE2_EVENT__SMB_CHAIN_OPEN_CLOSE, DCE2_EVENT__SMB_INVALID_SHARE, DCE2_EVENT__CO_BAD_MAJ_VERSION, DCE2_EVENT__CO_BAD_MIN_VERSION, DCE2_EVENT__CO_BAD_PDU_TYPE, DCE2_EVENT__CO_FLEN_LT_HDR, DCE2_EVENT__CO_FLEN_LT_SIZE, DCE2_EVENT__CO_ZERO_CTX_ITEMS, DCE2_EVENT__CO_ZERO_TSYNS, DCE2_EVENT__CO_FRAG_LT_MAX_XMIT_FRAG, DCE2_EVENT__CO_FRAG_GT_MAX_XMIT_FRAG, DCE2_EVENT__CO_ALTER_CHANGE_BYTE_ORDER, DCE2_EVENT__CO_FRAG_DIFF_CALL_ID, DCE2_EVENT__CO_FRAG_DIFF_OPNUM, DCE2_EVENT__CO_FRAG_DIFF_CTX_ID, DCE2_EVENT__CL_BAD_MAJ_VERSION, DCE2_EVENT__CL_BAD_PDU_TYPE, DCE2_EVENT__CL_DATA_LT_HDR, DCE2_EVENT__CL_BAD_SEQ_NUM, DCE2_EVENT__SMB_V1, DCE2_EVENT__SMB_V2, DCE2_EVENT__SMB_INVALID_BINDING, DCE2_EVENT__SMB2_EXCESSIVE_COMPOUNDING, DCE2_EVENT__SMB_DCNT_ZERO, DCE2_EVENT__SMB_DCNT_MISMATCH, DCE2_EVENT__SMB_MAX_REQS_EXCEEDED, DCE2_EVENT__SMB_REQS_SAME_MID, DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED, DCE2_EVENT__SMB_DEPR_COMMAND_USED, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED, DCE2_EVENT__SMB_INVALID_SETUP_COUNT, DCE2_EVENT__SMB_MULTIPLE_NEGOTIATIONS, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS, DCE2_EVENT__MAX } DCE2_Event; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_EventNode { DCE2_EventFlag eflag; DCE2_Event event; char *format; } DCE2_EventNode; /******************************************************************** * Public Function Prototypes ********************************************************************/ void DCE2_EventsInit(void); void DCE2_Alert(DCE2_SsnData *, DCE2_Event, ...); void DCE2_EventsFree(void); /******************************************************************** * Inline Function Prototypes ********************************************************************/ static inline int DCE2_SsnAlerted(DCE2_SsnData *, DCE2_Event); /****************************************************************** * Function: DCE2_SsnAlerted() * * Checks to see if we have already generated an alert on this * session for the event type passed in. * * Arguments: * DCE2_SsnData * * The session data structure. * DCE2_Event * The event to check for. * * Returns: * int * 1 if we have already alerted for this event type on this * session. * 0 if we have not alerted for this event type on this * session. * ******************************************************************/ static inline int DCE2_SsnAlerted(DCE2_SsnData *sd, DCE2_Event e) { if (sd->alert_mask & (1 << e)) return 1; return 0; } #endif /* _DCE2_EVENT_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_event.c0000644000000000000000000004617712260565732020577 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Handles processing of events generated by the preprocessor. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_event.h" #include "dce2_memory.h" #include "dce2_config.h" #include "dce2_stats.h" #include "smb.h" #include "dcerpc.h" #include "sf_dynamic_preprocessor.h" #include #include /******************************************************************** * Global variables ********************************************************************/ /* Used to print events and their arguments to. Each event gets * a buffer and 255 chars to print to. The reason for the multiple * buffers is that if multiple events fire, we don't want to overwrite * one before it's been written via an output plugin. Only one event * type per session is ever logged. */ static char dce2_event_bufs[DCE2_EVENT__MAX][256]; /* Used to hold event information */ static DCE2_EventNode dce2_events[DCE2_EVENT__MAX]; /* Used for matching a pdu string to a pdu type */ char *dce2_pdu_types[DCERPC_PDU_TYPE__MAX]; /****************************************************************** * Function: DCE2_EventsInit() * * Initializes global data. * * Arguments: None * * Returns: None * ******************************************************************/ void DCE2_EventsInit(void) { DCE2_Event event; char gname[100]; unsigned int i; static const DCE2_EventNode events[DCE2_EVENT__MAX] = { { DCE2_EVENT_FLAG__NONE, DCE2_EVENT__NO_EVENT, "Have to use this because can't have an event sid of zero" }, { DCE2_EVENT_FLAG__MEMCAP, DCE2_EVENT__MEMCAP, "Memory cap exceeded" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_NBSS_TYPE, "SMB - Bad NetBIOS Session Service session type" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_TYPE, "SMB - Bad SMB message type" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_ID, "SMB - Bad SMB Id (not \\xffSMB for SMB1 or not \\xfeSMB for SMB2)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_WCT, "SMB - Bad word count or structure size: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_BCC, "SMB - Bad byte count: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_FORMAT, "SMB - Bad format type: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BAD_OFF, "SMB - Bad offset: %p not between %p and %p" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_TDCNT_ZERO, "SMB - Zero total data count" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_NB_LT_SMBHDR, "SMB - NetBIOS data length (%u) less than SMB header length (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_NB_LT_COM, "SMB - Remaining NetBIOS data length (%u) less than command length (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_NB_LT_BCC, "SMB - Remaining NetBIOS data length (%u) less than command byte count (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_NB_LT_DSIZE, "SMB - Remaining NetBIOS data length (%u) less than command data size (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_TDCNT_LT_DSIZE, "SMB - Remaining total data count (%u) less than this command data size (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DSENT_GT_TDCNT, "SMB - Total data sent ("STDu64") greater than command total data expected (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_BCC_LT_DSIZE, "SMB - Byte count (%u) less than command data size ("STDu64")" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_INVALID_DSIZE, "SMB - Invalid command data size (%u) for byte count (%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_EXCESSIVE_TREE_CONNECTS, "SMB - Excessive Tree Connect requests (>%u) with pending Tree Connect responses" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_EXCESSIVE_READS, "SMB - Excessive Read requests (>%u) with pending Read responses" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_EXCESSIVE_CHAINING, "SMB - Excessive command chaining (>%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_MULT_CHAIN_SS, "SMB - Multiple chained login requests" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_MULT_CHAIN_TC, "SMB - Multiple chained tree connect requests" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_CHAIN_SS_LOGOFF, "SMB - Chained/Compounded login followed by logoff" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_CHAIN_TC_TDIS, "SMB - Chained/Compounded tree connect followed by tree disconnect" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_CHAIN_OPEN_CLOSE, "SMB - Chained/Compounded open pipe followed by close pipe" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_INVALID_SHARE, "SMB - Invalid share access: %s" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_BAD_MAJ_VERSION, "Connection-oriented DCE/RPC - Invalid major version: %u" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_BAD_MIN_VERSION, "Connection-oriented DCE/RPC - Invalid minor version: %u" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_BAD_PDU_TYPE, "Connection-oriented DCE/RPC - Invalid pdu type: 0x%02x" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FLEN_LT_HDR, "Connection-oriented DCE/RPC - Fragment length (%u) less than header size (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FLEN_LT_SIZE, "Connection-oriented DCE/RPC - %s: Remaining fragment length (%u) less than size needed (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_ZERO_CTX_ITEMS, "Connection-oriented DCE/RPC - %s: No context items specified" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_ZERO_TSYNS, "Connection-oriented DCE/RPC - %s: No transfer syntaxes specified" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_LT_MAX_XMIT_FRAG, "Connection-oriented DCE/RPC - %s: Fragment length on non-last fragment (%u) less than " "maximum negotiated fragment transmit size for client (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_GT_MAX_XMIT_FRAG, "Connection-oriented DCE/RPC - %s: Fragment length (%u) greater than " "maximum negotiated fragment transmit size (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_ALTER_CHANGE_BYTE_ORDER, "Connection-oriented DCE/RPC - Alter Context byte order different from Bind" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_DIFF_CALL_ID, "Connection-oriented DCE/RPC - Call id (%u) of non first/last fragment different " "from call id established for fragmented request (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_DIFF_OPNUM, "Connection-oriented DCE/RPC - Opnum (%u) of non first/last fragment different " "from opnum established for fragmented request (%u)" }, { DCE2_EVENT_FLAG__CO, DCE2_EVENT__CO_FRAG_DIFF_CTX_ID, "Connection-oriented DCE/RPC - Context id (%u) of non first/last fragment different " "from context id established for fragmented request (%u)" }, { DCE2_EVENT_FLAG__CL, DCE2_EVENT__CL_BAD_MAJ_VERSION, "Connection-less DCE/RPC - Invalid major version: %u" }, { DCE2_EVENT_FLAG__CL, DCE2_EVENT__CL_BAD_PDU_TYPE, "Connection-less DCE/RPC - Invalid pdu type: 0x%02x" }, { DCE2_EVENT_FLAG__CL, DCE2_EVENT__CL_DATA_LT_HDR, "Connection-less DCE/RPC - Data length (%u) less than header size (%u)" }, { DCE2_EVENT_FLAG__CL, DCE2_EVENT__CL_BAD_SEQ_NUM, "Connection-less DCE/RPC - %s: Bad sequence number" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_V1, "SMB - Invalid SMB version 1 seen" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_V2, "SMB - Invalid SMB version 2 seen" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_INVALID_BINDING, "SMB - Invalid user, tree connect, file binding" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB2_EXCESSIVE_COMPOUNDING, "SMB - Excessive command compounding (>%u)" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DCNT_ZERO, "SMB - Zero data count" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DCNT_MISMATCH, "SMB - Data count mismatch %u in command / %u in format" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_MAX_REQS_EXCEEDED, "SMB - Maximum number of outstanding requests exceeded: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_REQS_SAME_MID, "SMB - Outstanding requests with same MID", }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED, "SMB - Deprecated dialect negotiated" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_DEPR_COMMAND_USED, "SMB - Deprecated command used: %s" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED, "SMB - Unusual command used: %s" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_INVALID_SETUP_COUNT, "SMB - Invalid setup count for %s/%s command: %u" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_MULTIPLE_NEGOTIATIONS, "SMB - Client attempted multiple dialect negotiations on session" }, { DCE2_EVENT_FLAG__SMB, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS, "SMB - Client attempted to create or set a file's attributes to readonly/hidden/system" } }; snprintf(gname, sizeof(gname) - 1, "(%s) ", DCE2_GNAME); gname[sizeof(gname) - 1] = '\0'; for (event = DCE2_EVENT__NO_EVENT; event < DCE2_EVENT__MAX; event++) { int size = strlen(gname) + strlen(events[event].format) + 1; /* This is a check to make sure all of the events in the array are * in the same order as the enum, so we index the right thing when * alerting - DO NOT REMOVE THIS CHECK */ if (events[event].event != event) { DCE2_Die("%s(%d) Events are not in the right order.", __FILE__, __LINE__); } dce2_events[event].format = (char *)DCE2_Alloc(size, DCE2_MEM_TYPE__INIT); if (dce2_events[event].format == NULL) { DCE2_Die("%s(%d) Could not allocate memory for events array.", __FILE__, __LINE__); } dce2_events[event].format[size - 1] = '\0'; snprintf(dce2_events[event].format, size, "%s%s", gname, events[event].format); if (dce2_events[event].format[size - 1] != '\0') { DCE2_Die("%s(%d) Event string truncated.", __FILE__, __LINE__); } dce2_events[event].eflag = events[event].eflag; dce2_events[event].event = events[event].event; } for (i = 0; i < (sizeof(dce2_pdu_types) / sizeof(char *)); i++) { char *type; switch (i) { case DCERPC_PDU_TYPE__REQUEST: type = "Request"; break; case DCERPC_PDU_TYPE__PING: type = "Ping"; break; case DCERPC_PDU_TYPE__RESPONSE: type = "Response"; break; case DCERPC_PDU_TYPE__FAULT: type = "Fault"; break; case DCERPC_PDU_TYPE__WORKING: type = "Working"; break; case DCERPC_PDU_TYPE__NOCALL: type = "NoCall"; break; case DCERPC_PDU_TYPE__REJECT: type = "Reject"; break; case DCERPC_PDU_TYPE__ACK: type = "Ack"; break; case DCERPC_PDU_TYPE__CL_CANCEL: type = "Cancel"; break; case DCERPC_PDU_TYPE__FACK: type = "Fack"; break; case DCERPC_PDU_TYPE__CANCEL_ACK: type = "Cancel Ack"; break; case DCERPC_PDU_TYPE__BIND: type = "Bind"; break; case DCERPC_PDU_TYPE__BIND_ACK: type = "Bind Ack"; break; case DCERPC_PDU_TYPE__BIND_NACK: type = "Bind Nack"; break; case DCERPC_PDU_TYPE__ALTER_CONTEXT: type = "Alter Context"; break; case DCERPC_PDU_TYPE__ALTER_CONTEXT_RESP: type = "Alter Context Response"; break; case DCERPC_PDU_TYPE__AUTH3: type = "Auth3"; break; case DCERPC_PDU_TYPE__SHUTDOWN: type = "Shutdown"; break; case DCERPC_PDU_TYPE__CO_CANCEL: type = "Cancel"; break; case DCERPC_PDU_TYPE__ORPHANED: type = "Orphaned"; break; case DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP: type = "Microsoft Exchange/Outlook 2003"; break; default: type = "Unknown DCE/RPC type"; break; } dce2_pdu_types[i] = (char *)DCE2_Alloc(strlen(type) + 1, DCE2_MEM_TYPE__INIT); strncpy(dce2_pdu_types[i], type, strlen(type)); dce2_pdu_types[i][strlen(type)] = '\0'; #ifdef DCE2_EVENT_PRINT_DEBUG printf("%s\n", dce2_pdu_types[i]); #endif } } /****************************************************************** * Function: DCE2_Alert() * * Potentially generates an alert if an event is triggered. * * Arguments: * DCE2_SsnData * * This is the current session data structure being used * when the event was triggered. It is not a necessary * argument if no session data is currently available, for * example if the event is a memcap event - pass in NULL in * this case. * DCE2_Event * The event type that was triggered. * ... * The arguments to the format for the event. * * Returns: None * ******************************************************************/ void DCE2_Alert(DCE2_SsnData *sd, DCE2_Event e, ...) { va_list ap; #ifdef DEBUG_MSGS // When debugging want to see all of the alerts generated va_start(ap, e); vsnprintf(dce2_event_bufs[e], sizeof(dce2_event_bufs[e]) - 1, dce2_events[e].format, ap); va_end(ap); dce2_event_bufs[e][sizeof(dce2_event_bufs[e]) - 1] = '\0'; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "DCE2 Alert => %s\n", dce2_event_bufs[e])); #endif if (sd != NULL) { // NOTE This check needs to change if the number of preprocessor events // should exceed 63 /* Only log a specific alert once per session */ if (sd->alert_mask & ((uint64_t)1 << e)) return; /* set bit for this alert so we don't alert on again * in this session */ sd->alert_mask |= ((uint64_t)1 << e); } if (!DCE2_GcAlertOnEvent(dce2_events[e].eflag)) return; dce2_stats.events++; #ifndef DEBUG_MSGS va_start(ap, e); vsnprintf(dce2_event_bufs[e], sizeof(dce2_event_bufs[e]) - 1, dce2_events[e].format, ap); va_end(ap); dce2_event_bufs[e][sizeof(dce2_event_bufs[e]) - 1] = '\0'; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "DCE2 Alert => %s\n", dce2_event_bufs[e])); #endif _dpd.alertAdd(GENERATOR_DCE2, e, 1, 0, 3, dce2_event_bufs[e], 0); } /****************************************************************** * Function: DCE2_EventsFree() * * Frees any global data that was dynamically allocated. * * Arguments: None * * Returns: None * ******************************************************************/ void DCE2_EventsFree(void) { unsigned int i; for (i = 0; i < DCE2_EVENT__MAX; i++) { if (dce2_events[i].format != NULL) { DCE2_Free((void *)dce2_events[i].format, strlen(dce2_events[i].format) + 1, DCE2_MEM_TYPE__INIT); dce2_events[i].format = NULL; } } for (i = 0; i < (sizeof(dce2_pdu_types) / sizeof(char *)); i++) { if (dce2_pdu_types[i] != NULL) { DCE2_Free((void *)dce2_pdu_types[i], strlen(dce2_pdu_types[i]) + 1, DCE2_MEM_TYPE__INIT); dce2_pdu_types[i] = NULL; } } } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_stats.h0000644000000000000000000001034112260565732020601 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _DCE2_STATS_H_ #define _DCE2_STATS_H_ #include "dce2_utils.h" #include "smb.h" #include "sf_types.h" /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_Stats { uint64_t sessions; uint64_t sessions_autodetected; uint64_t sessions_aborted; uint64_t bad_autodetects; uint64_t events; #ifdef DEBUG uint64_t autoports[65535][DCE2_TRANS_TYPE__MAX]; #endif uint64_t smb_sessions; uint64_t smb_pkts; uint64_t smb_ignored_bytes; uint64_t smb_cli_seg_reassembled; uint64_t smb_srv_seg_reassembled; uint64_t smb_max_outstanding_requests; uint64_t smb_com_stats[2][SMB_MAX_NUM_COMS]; uint64_t smb_chained_stats[2][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS]; // The +1 is for codes beyond the range of the highest valid subcommand code // Indicates a bogus subcommand uint64_t smb_trans_subcom_stats[2][TRANS_SUBCOM_MAX+1]; uint64_t smb_trans2_subcom_stats[2][TRANS2_SUBCOM_MAX+1]; uint64_t smb_nt_transact_subcom_stats[2][NT_TRANSACT_SUBCOM_MAX+1]; uint64_t smb_files_processed; uint64_t tcp_sessions; uint64_t tcp_pkts; uint64_t udp_sessions; uint64_t udp_pkts; uint64_t http_proxy_sessions; uint64_t http_proxy_pkts; uint64_t http_server_sessions; uint64_t http_server_pkts; uint64_t co_pdus; uint64_t co_bind; uint64_t co_bind_ack; uint64_t co_alter_ctx; uint64_t co_alter_ctx_resp; uint64_t co_bind_nack; uint64_t co_request; uint64_t co_response; uint64_t co_cancel; uint64_t co_orphaned; uint64_t co_fault; uint64_t co_auth3; uint64_t co_shutdown; uint64_t co_reject; uint64_t co_ms_pdu; uint64_t co_other_req; uint64_t co_other_resp; uint64_t co_req_fragments; uint64_t co_resp_fragments; uint64_t co_cli_max_frag_size; uint64_t co_cli_min_frag_size; uint64_t co_cli_seg_reassembled; uint64_t co_cli_frag_reassembled; uint64_t co_srv_max_frag_size; uint64_t co_srv_min_frag_size; uint64_t co_srv_seg_reassembled; uint64_t co_srv_frag_reassembled; uint64_t cl_pkts; uint64_t cl_request; uint64_t cl_ack; uint64_t cl_cancel; uint64_t cl_cli_fack; uint64_t cl_ping; uint64_t cl_response; uint64_t cl_reject; uint64_t cl_cancel_ack; uint64_t cl_srv_fack; uint64_t cl_fault; uint64_t cl_nocall; uint64_t cl_working; uint64_t cl_other_req; uint64_t cl_other_resp; uint64_t cl_fragments; uint64_t cl_max_frag_size; uint64_t cl_frag_reassembled; uint64_t cl_max_seqnum; } DCE2_Stats; /******************************************************************** * Extern variables ********************************************************************/ extern DCE2_Stats dce2_stats; extern char **dce2_trans_strs; /******************************************************************** * Public function prototypes ********************************************************************/ void DCE2_StatsInit(void); void DCE2_StatsFree(void); #endif /* _DCE2_STATS_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_stats.c0000644000000000000000000001260412260565732020600 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_stats.h" #include "dce2_utils.h" #include "dce2_memory.h" #include "dce2_config.h" #include /******************************************************************** * Global variables ********************************************************************/ DCE2_Stats dce2_stats; char **dce2_trans_strs = NULL; /******************************************************************** * Private function prototypes ********************************************************************/ static inline void DCE2_CreateTransStr(char **, DCE2_TransType, char *); /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_StatsInit(void) { memset(&dce2_stats, 0, sizeof(dce2_stats)); if (dce2_trans_strs == NULL) { DCE2_TransType ttype; dce2_trans_strs = (char **)DCE2_Alloc((DCE2_TRANS_TYPE__MAX * sizeof(char *)), DCE2_MEM_TYPE__INIT); if (dce2_trans_strs == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for transport string " "array", __FILE__, __LINE__); } for (ttype = DCE2_TRANS_TYPE__NONE; ttype < DCE2_TRANS_TYPE__MAX; ttype++) { switch (ttype) { case DCE2_TRANS_TYPE__NONE: break; case DCE2_TRANS_TYPE__SMB: { char *str = "SMB"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; case DCE2_TRANS_TYPE__TCP: { char *str = "TCP"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; case DCE2_TRANS_TYPE__UDP: { char *str = "UDP"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; case DCE2_TRANS_TYPE__HTTP_PROXY: { char *str = "HTTP Proxy"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; case DCE2_TRANS_TYPE__HTTP_SERVER: { char *str = "HTTP Server"; DCE2_CreateTransStr(dce2_trans_strs, ttype, str); } break; default: DCE2_Die("%s(%d) Invalid transport type for allocing " "transport strings: %d", __FILE__, __LINE__, ttype); break; } } } } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline void DCE2_CreateTransStr(char **trans_buf, DCE2_TransType ttype, char *trans_str) { if ((trans_buf == NULL) || (trans_str == NULL)) return; trans_buf[ttype] = (char *)DCE2_Alloc(strlen(trans_str) + 1, DCE2_MEM_TYPE__INIT); if (trans_buf[ttype] == NULL) { DCE2_Die("%s(%d) Failed to allocate memory for transport string", __FILE__, __LINE__); } snprintf(trans_buf[ttype], strlen(trans_str) + 1, "%s", trans_str); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_StatsFree(void) { if (dce2_trans_strs != NULL) { unsigned int i; for (i = DCE2_TRANS_TYPE__NONE; i < DCE2_TRANS_TYPE__MAX; i++) { if (dce2_trans_strs[i] != NULL) { DCE2_Free((void *)dce2_trans_strs[i], strlen(dce2_trans_strs[i]) + 1, DCE2_MEM_TYPE__INIT); } } DCE2_Free((void *)dce2_trans_strs, (DCE2_TRANS_TYPE__MAX * sizeof(char *)), DCE2_MEM_TYPE__INIT); dce2_trans_strs = NULL; } } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_memory.h0000644000000000000000000001506212260565732020760 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _DCE2_MEMORY_H_ #define _DCE2_MEMORY_H_ /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_MemType { DCE2_MEM_TYPE__CONFIG, /* Configuration */ DCE2_MEM_TYPE__ROPTION, /* Rule options */ DCE2_MEM_TYPE__RT, /* Routing tables */ DCE2_MEM_TYPE__INIT, /* Other initialization */ DCE2_MEM_TYPE__SMB_SSN, /* SMB session data */ DCE2_MEM_TYPE__SMB_SEG, /* SMB segmentation buffer */ DCE2_MEM_TYPE__SMB_UID, /* SMB uid tracking */ DCE2_MEM_TYPE__SMB_TID, /* SMB tid tracking */ DCE2_MEM_TYPE__SMB_FID, /* SMB fid tracking */ DCE2_MEM_TYPE__SMB_FILE, /* SMB file tracking */ DCE2_MEM_TYPE__SMB_REQ, /* SMB request/response tracking */ DCE2_MEM_TYPE__TCP_SSN, /* TCP session data */ DCE2_MEM_TYPE__CO_SEG, /* TCP segmentation buffer */ DCE2_MEM_TYPE__CO_FRAG, /* TCP fragmentation data */ DCE2_MEM_TYPE__CO_CTX, /* TCP context tracking */ DCE2_MEM_TYPE__UDP_SSN, /* UDP session data */ DCE2_MEM_TYPE__CL_ACT, /* UDP activity tracking */ DCE2_MEM_TYPE__CL_FRAG, /* UDP fragment tracking */ DCE2_MEM_TYPE__HTTP_SSN /* HTTP session data */ } DCE2_MemType; typedef enum _DCE2_MemState { DCE2_MEM_STATE__OKAY, DCE2_MEM_STATE__MEMCAP } DCE2_MemState; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_Memory { uint32_t total; uint32_t total_max; uint32_t rtotal; /* Run time total */ uint32_t rtotal_max; uint32_t config; uint32_t config_max; uint32_t roptions; uint32_t roptions_max; uint32_t rt; uint32_t rt_max; uint32_t init; uint32_t init_max; uint32_t smb_total; /* total memory allocated for SMB */ uint32_t smb_total_max; /* max total memory allocated for SMB */ uint32_t smb_ssn; /* amount allocated for session structures */ uint32_t smb_ssn_max; /* max amount allocated for session structures */ uint32_t smb_seg; /* amount allocated for segmentation buffers */ uint32_t smb_seg_max; /* max amount allocated for segmentation buffers */ uint32_t smb_uid; /* amount allocated for uid tracking */ uint32_t smb_uid_max; /* max amount allocated for uid tracking */ uint32_t smb_tid; /* amount allocated for tid tracking */ uint32_t smb_tid_max; /* max amount allocated for tid tracking */ uint32_t smb_fid; /* amount allocated for fid tracking */ uint32_t smb_fid_max; /* max amount allocated for fid tracking */ uint32_t smb_file; /* amount allocated for file tracking */ uint32_t smb_file_max; /* max amount allocated for file tracking */ uint32_t smb_req; /* amount allocated for request tracking */ uint32_t smb_req_max; /* max amount allocated for request tracking */ uint32_t tcp_total; /* total memory allocated for TCP */ uint32_t tcp_total_max; /* max total memory allocated for TCP */ uint32_t tcp_ssn; /* amount allocated for session structures */ uint32_t tcp_ssn_max; /* max amount allocated for session structures */ uint32_t udp_total; /* total memory allocated for UDP */ uint32_t udp_total_max; /* max total memory allocated for UDP */ uint32_t udp_ssn; /* amount allocated for session structures */ uint32_t udp_ssn_max; /* max amount allocated for session structures */ uint32_t http_total; /* total memory allocated for UDP */ uint32_t http_total_max; /* max total memory allocated for UDP */ uint32_t http_ssn; /* amount allocated for session structures */ uint32_t http_ssn_max; /* max amount allocated for session structures */ uint32_t co_total; /* total memory allocated for CO */ uint32_t co_total_max; /* max total memory allocated for CO */ uint32_t co_seg; /* amount allocated for segmentation */ uint32_t co_seg_max; /* max amount allocated for segmentation */ uint32_t co_frag; /* amount allocated for frag tracking */ uint32_t co_frag_max; /* max amount allocated for frag tracking */ uint32_t co_ctx; /* amount allocated for contexts */ uint32_t co_ctx_max; /* max amount allocated for contexts */ uint32_t cl_total; /* total memory allocated for CL */ uint32_t cl_total_max; /* max total memory allocated for CL */ uint32_t cl_act; /* amount allocated for activity trackers */ uint32_t cl_act_max; /* max amount allocated for activity trackers */ uint32_t cl_frag; /* amount allocated for frag tracking */ uint32_t cl_frag_max; /* max amount allocated for frag tracking */ } DCE2_Memory; /******************************************************************** * Extern variables ********************************************************************/ extern DCE2_Memory dce2_memory; extern DCE2_MemState dce2_mem_state; /******************************************************************** * Public functions ********************************************************************/ void DCE2_RegMem(uint32_t, DCE2_MemType); void DCE2_UnRegMem(uint32_t, DCE2_MemType); void * DCE2_Alloc(uint32_t, DCE2_MemType); void DCE2_Free(void *, uint32_t, DCE2_MemType); void * DCE2_ReAlloc(void *, uint32_t, uint32_t, DCE2_MemType); void DCE2_FreeAll(void); void DCE2_MemInit(void); #endif /* _DCE2_MEMORY_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_memory.c0000644000000000000000000004056312260565732020757 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_memory.h" #include "dce2_utils.h" #include "dce2_config.h" #include "dce2_event.h" #include #include #include /******************************************************************** * Macros ********************************************************************/ #define DCE2_MEMCAP_OK 0 #define DCE2_MEMCAP_EXCEEDED 1 /******************************************************************** * Global variables ********************************************************************/ DCE2_Memory dce2_memory; DCE2_MemState dce2_mem_state = DCE2_MEM_STATE__OKAY; /******************************************************************** * Private function prototypes ********************************************************************/ static void DCE2_RegMemSmb(uint32_t, DCE2_MemType); static void DCE2_RegMemCo(uint32_t, DCE2_MemType); static void DCE2_RegMemCl(uint32_t, DCE2_MemType); static int DCE2_CheckMemcap(uint32_t, DCE2_MemType); /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_RegMem(uint32_t size, DCE2_MemType mtype) { switch (mtype) { case DCE2_MEM_TYPE__CONFIG: dce2_memory.config += size; if (dce2_memory.config > dce2_memory.config_max) dce2_memory.config_max = dce2_memory.config; break; case DCE2_MEM_TYPE__ROPTION: dce2_memory.roptions += size; if (dce2_memory.roptions > dce2_memory.roptions_max) dce2_memory.roptions_max = dce2_memory.roptions; break; case DCE2_MEM_TYPE__RT: dce2_memory.rt += size; if (dce2_memory.rt > dce2_memory.rt_max) dce2_memory.rt_max = dce2_memory.rt; break; case DCE2_MEM_TYPE__INIT: dce2_memory.init += size; if (dce2_memory.init > dce2_memory.init_max) dce2_memory.init_max = dce2_memory.init; break; case DCE2_MEM_TYPE__SMB_SSN: case DCE2_MEM_TYPE__SMB_SEG: case DCE2_MEM_TYPE__SMB_UID: case DCE2_MEM_TYPE__SMB_TID: case DCE2_MEM_TYPE__SMB_FID: case DCE2_MEM_TYPE__SMB_FILE: case DCE2_MEM_TYPE__SMB_REQ: DCE2_RegMemSmb(size, mtype); break; case DCE2_MEM_TYPE__TCP_SSN: dce2_memory.tcp_ssn += size; if (dce2_memory.tcp_ssn > dce2_memory.tcp_ssn_max) dce2_memory.tcp_ssn_max = dce2_memory.tcp_ssn; dce2_memory.tcp_total += size; if (dce2_memory.tcp_total > dce2_memory.tcp_total_max) dce2_memory.tcp_total_max = dce2_memory.tcp_total; break; case DCE2_MEM_TYPE__CO_SEG: case DCE2_MEM_TYPE__CO_FRAG: case DCE2_MEM_TYPE__CO_CTX: DCE2_RegMemCo(size, mtype); break; case DCE2_MEM_TYPE__UDP_SSN: dce2_memory.udp_ssn += size; if (dce2_memory.udp_ssn > dce2_memory.udp_ssn_max) dce2_memory.udp_ssn_max = dce2_memory.udp_ssn; dce2_memory.udp_total += size; if (dce2_memory.udp_total > dce2_memory.udp_total_max) dce2_memory.udp_total_max = dce2_memory.udp_total; break; case DCE2_MEM_TYPE__HTTP_SSN: dce2_memory.http_ssn += size; if (dce2_memory.http_ssn > dce2_memory.http_ssn_max) dce2_memory.http_ssn_max = dce2_memory.http_ssn; dce2_memory.http_total += size; if (dce2_memory.http_total > dce2_memory.http_total_max) dce2_memory.http_total_max = dce2_memory.http_total; break; case DCE2_MEM_TYPE__CL_ACT: case DCE2_MEM_TYPE__CL_FRAG: DCE2_RegMemCl(size, mtype); break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid memory type: %d", __FILE__, __LINE__, mtype); break; } switch (mtype) { case DCE2_MEM_TYPE__CONFIG: case DCE2_MEM_TYPE__ROPTION: case DCE2_MEM_TYPE__RT: case DCE2_MEM_TYPE__INIT: break; default: dce2_memory.rtotal += size; if (dce2_memory.rtotal > dce2_memory.rtotal_max) dce2_memory.rtotal_max = dce2_memory.rtotal; } dce2_memory.total += size; if (dce2_memory.total > dce2_memory.total_max) dce2_memory.total_max = dce2_memory.total; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_RegMemSmb(uint32_t size, DCE2_MemType mtype) { switch (mtype) { case DCE2_MEM_TYPE__SMB_SSN: dce2_memory.smb_ssn += size; if (dce2_memory.smb_ssn > dce2_memory.smb_ssn_max) dce2_memory.smb_ssn_max = dce2_memory.smb_ssn; break; case DCE2_MEM_TYPE__SMB_SEG: dce2_memory.smb_seg += size; if (dce2_memory.smb_seg > dce2_memory.smb_seg_max) dce2_memory.smb_seg_max = dce2_memory.smb_seg; break; case DCE2_MEM_TYPE__SMB_UID: dce2_memory.smb_uid += size; if (dce2_memory.smb_uid > dce2_memory.smb_uid_max) dce2_memory.smb_uid_max = dce2_memory.smb_uid; break; case DCE2_MEM_TYPE__SMB_TID: dce2_memory.smb_tid += size; if (dce2_memory.smb_tid > dce2_memory.smb_tid_max) dce2_memory.smb_tid_max = dce2_memory.smb_tid; break; case DCE2_MEM_TYPE__SMB_FID: dce2_memory.smb_fid += size; if (dce2_memory.smb_fid > dce2_memory.smb_fid_max) dce2_memory.smb_fid_max = dce2_memory.smb_fid; break; case DCE2_MEM_TYPE__SMB_FILE: dce2_memory.smb_file += size; if (dce2_memory.smb_file > dce2_memory.smb_file_max) dce2_memory.smb_file_max = dce2_memory.smb_file; break; case DCE2_MEM_TYPE__SMB_REQ: dce2_memory.smb_req += size; if (dce2_memory.smb_req > dce2_memory.smb_req_max) dce2_memory.smb_req_max = dce2_memory.smb_req; break; default: return; } dce2_memory.smb_total += size; if (dce2_memory.smb_total > dce2_memory.smb_total_max) dce2_memory.smb_total_max = dce2_memory.smb_total; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_RegMemCo(uint32_t size, DCE2_MemType mtype) { switch (mtype) { case DCE2_MEM_TYPE__CO_SEG: dce2_memory.co_seg += size; if (dce2_memory.co_seg > dce2_memory.co_seg_max) dce2_memory.co_seg_max = dce2_memory.co_seg; break; case DCE2_MEM_TYPE__CO_FRAG: dce2_memory.co_frag += size; if (dce2_memory.co_frag > dce2_memory.co_frag_max) dce2_memory.co_frag_max = dce2_memory.co_frag; break; case DCE2_MEM_TYPE__CO_CTX: dce2_memory.co_ctx += size; if (dce2_memory.co_ctx > dce2_memory.co_ctx_max) dce2_memory.co_ctx_max = dce2_memory.co_ctx; break; default: return; } dce2_memory.co_total += size; if (dce2_memory.co_total > dce2_memory.co_total_max) dce2_memory.co_total_max = dce2_memory.co_total; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static void DCE2_RegMemCl(uint32_t size, DCE2_MemType mtype) { switch (mtype) { case DCE2_MEM_TYPE__CL_ACT: dce2_memory.cl_act += size; if (dce2_memory.cl_act > dce2_memory.cl_act_max) dce2_memory.cl_act_max = dce2_memory.cl_act; break; case DCE2_MEM_TYPE__CL_FRAG: dce2_memory.cl_frag += size; if (dce2_memory.cl_frag > dce2_memory.cl_frag_max) dce2_memory.cl_frag_max = dce2_memory.cl_frag; break; default: return; } dce2_memory.cl_total += size; if (dce2_memory.cl_total > dce2_memory.cl_total_max) dce2_memory.cl_total_max = dce2_memory.cl_total; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_UnRegMem(uint32_t size, DCE2_MemType mtype) { switch (mtype) { case DCE2_MEM_TYPE__CONFIG: dce2_memory.config -= size; break; case DCE2_MEM_TYPE__ROPTION: dce2_memory.roptions -= size; break; case DCE2_MEM_TYPE__RT: dce2_memory.rt -= size; break; case DCE2_MEM_TYPE__INIT: dce2_memory.init -= size; break; case DCE2_MEM_TYPE__SMB_SSN: dce2_memory.smb_total -= size; dce2_memory.smb_ssn -= size; break; case DCE2_MEM_TYPE__SMB_SEG: dce2_memory.smb_total -= size; dce2_memory.smb_seg -= size; break; case DCE2_MEM_TYPE__SMB_UID: dce2_memory.smb_total -= size; dce2_memory.smb_uid -= size; break; case DCE2_MEM_TYPE__SMB_TID: dce2_memory.smb_total -= size; dce2_memory.smb_tid -= size; break; case DCE2_MEM_TYPE__SMB_FID: dce2_memory.smb_total -= size; dce2_memory.smb_fid -= size; break; case DCE2_MEM_TYPE__SMB_FILE: dce2_memory.smb_total -= size; dce2_memory.smb_file -= size; break; case DCE2_MEM_TYPE__SMB_REQ: dce2_memory.smb_total -= size; dce2_memory.smb_req -= size; break; case DCE2_MEM_TYPE__TCP_SSN: dce2_memory.tcp_total -= size; dce2_memory.tcp_ssn -= size; break; case DCE2_MEM_TYPE__CO_SEG: dce2_memory.co_total -= size; dce2_memory.co_seg -= size; break; case DCE2_MEM_TYPE__CO_FRAG: dce2_memory.co_total -= size; dce2_memory.co_frag -= size; break; case DCE2_MEM_TYPE__CO_CTX: dce2_memory.co_total -= size; dce2_memory.co_ctx -= size; break; case DCE2_MEM_TYPE__UDP_SSN: dce2_memory.udp_total -= size; dce2_memory.udp_ssn -= size; break; case DCE2_MEM_TYPE__CL_ACT: dce2_memory.cl_total -= size; dce2_memory.cl_act -= size; break; case DCE2_MEM_TYPE__HTTP_SSN: dce2_memory.http_total -= size; dce2_memory.http_ssn -= size; break; case DCE2_MEM_TYPE__CL_FRAG: dce2_memory.cl_total -= size; dce2_memory.cl_frag -= size; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid memory type: %d", __FILE__, __LINE__, mtype); break; } switch (mtype) { case DCE2_MEM_TYPE__CONFIG: case DCE2_MEM_TYPE__ROPTION: case DCE2_MEM_TYPE__RT: case DCE2_MEM_TYPE__INIT: break; default: dce2_memory.rtotal -= size; } dce2_memory.total -= size; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static int DCE2_CheckMemcap(uint32_t size, DCE2_MemType mtype) { switch (mtype) { /*Avoid checking memcap for configurations*/ case DCE2_MEM_TYPE__CONFIG: case DCE2_MEM_TYPE__ROPTION: case DCE2_MEM_TYPE__RT: case DCE2_MEM_TYPE__INIT: break; default: if (dce2_mem_state == DCE2_MEM_STATE__MEMCAP) break; if ((dce2_memory.rtotal + size) > DCE2_GcMemcap()) { DCE2_Alert(NULL, DCE2_EVENT__MEMCAP); dce2_mem_state = DCE2_MEM_STATE__MEMCAP; return DCE2_MEMCAP_EXCEEDED; } break; } return DCE2_MEMCAP_OK; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void * DCE2_Alloc(uint32_t size, DCE2_MemType mtype) { void *mem; if (DCE2_CheckMemcap(size, mtype) != DCE2_MEMCAP_OK) return NULL; mem = calloc(1, (size_t)size); if (mem == NULL) { DCE2_Die("%s(%d) Out of memory!", __FILE__, __LINE__); } DCE2_RegMem(size, mtype); return mem; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_Free(void *mem, uint32_t size, DCE2_MemType mtype) { if (mem == NULL) return; DCE2_UnRegMem(size, mtype); free(mem); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void * DCE2_ReAlloc(void *old_mem, uint32_t old_size, uint32_t new_size, DCE2_MemType mtype) { void *new_mem; DCE2_Ret status; if (old_mem == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Old memory passed in was NULL.", __FILE__, __LINE__); return NULL; } else if (new_size < old_size) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) New size is less than old size.", __FILE__, __LINE__); return NULL; } else if (new_size == old_size) { return old_mem; } if (DCE2_CheckMemcap(new_size - old_size, mtype) == DCE2_MEMCAP_EXCEEDED) return NULL; new_mem = DCE2_Alloc(new_size, mtype); if (new_mem == NULL) return NULL; status = DCE2_Memcpy(new_mem, old_mem, old_size, new_mem, (void *)((uint8_t *)new_mem + new_size)); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy old memory into new memory.", __FILE__, __LINE__); DCE2_Free(new_mem, new_size, mtype); return NULL; } DCE2_Free(old_mem, old_size, mtype); return new_mem; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_MemInit(void) { memset(&dce2_memory, 0, sizeof(dce2_memory)); } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_list.h0000644000000000000000000002406112260565732020422 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides list, queue and stack data structures and methods for use * with the preprocessor. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _DCE2_LIST_H_ #define _DCE2_LIST_H_ #include "dce2_memory.h" #include "dce2_utils.h" #include "sf_types.h" #include "snort_debug.h" /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_ListType { DCE2_LIST_TYPE__NORMAL = 0, /* Don't do anything special */ DCE2_LIST_TYPE__SORTED, /* Sort list by key */ DCE2_LIST_TYPE__SPLAYED /* Move most recently accessed node to head */ } DCE2_ListType; typedef enum _DCE2_ListFlags { DCE2_LIST_FLAG__NO_FLAG = 0x00, /* No flags */ DCE2_LIST_FLAG__NO_DUPS = 0x01, /* No duplicate keys in list */ DCE2_LIST_FLAG__INS_TAIL = 0x02 /* Insert at tail - default is to insert at head */ } DCE2_ListFlags; /******************************************************************** * Callbacks ********************************************************************/ typedef void (*DCE2_ListDataFree)(void *); typedef void (*DCE2_ListKeyFree)(void *); typedef int (*DCE2_ListKeyCompare)(const void *, const void *); /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_ListNode { void *key; void *data; struct _DCE2_ListNode *prev; struct _DCE2_ListNode *next; } DCE2_ListNode; typedef struct _DCE2_List { DCE2_ListType type; DCE2_MemType mtype; uint32_t num_nodes; DCE2_ListKeyCompare compare; DCE2_ListDataFree data_free; DCE2_ListKeyFree key_free; int flags; struct _DCE2_ListNode *head; struct _DCE2_ListNode *tail; struct _DCE2_ListNode *current; struct _DCE2_ListNode *next; struct _DCE2_ListNode *prev; } DCE2_List; typedef struct _DCE2_QueueNode { void *data; struct _DCE2_QueueNode *prev; struct _DCE2_QueueNode *next; } DCE2_QueueNode; typedef DCE2_ListDataFree DCE2_QueueDataFree; typedef struct _DCE2_Queue { uint32_t num_nodes; DCE2_MemType mtype; DCE2_QueueDataFree data_free; struct _DCE2_QueueNode *current; struct _DCE2_QueueNode *head; struct _DCE2_QueueNode *tail; struct _DCE2_QueueNode *next; struct _DCE2_QueueNode *prev; } DCE2_Queue; typedef struct _DCE2_StackNode { void *data; struct _DCE2_StackNode *prev; struct _DCE2_StackNode *next; } DCE2_StackNode; typedef DCE2_ListDataFree DCE2_StackDataFree; typedef struct _DCE2_Stack { uint32_t num_nodes; DCE2_MemType mtype; DCE2_StackDataFree data_free; struct _DCE2_StackNode *current; struct _DCE2_StackNode *head; struct _DCE2_StackNode *tail; } DCE2_Stack; /* Circular queue */ typedef DCE2_ListDataFree DCE2_CQueueDataFree; typedef struct _DCE2_CQueue { uint32_t num_nodes; DCE2_MemType mtype; DCE2_CQueueDataFree data_free; int size; void **queue; int head_idx; int tail_idx; int cur_idx; } DCE2_CQueue; typedef DCE2_ListDataFree DCE2_CStackDataFree; typedef struct _DCE2_CStack { uint32_t num_nodes; DCE2_MemType mtype; DCE2_CStackDataFree data_free; int size; void **stack; int tail_idx; int cur_idx; } DCE2_CStack; /******************************************************************** * Public function prototypes ********************************************************************/ DCE2_List * DCE2_ListNew(DCE2_ListType, DCE2_ListKeyCompare, DCE2_ListDataFree, DCE2_ListKeyFree, int, DCE2_MemType); void * DCE2_ListFind(DCE2_List *, void *); DCE2_Ret DCE2_ListFindKey(DCE2_List *, void *); DCE2_Ret DCE2_ListInsert(DCE2_List *, void *, void *); DCE2_Ret DCE2_ListRemove(DCE2_List *, void *); void * DCE2_ListFirst(DCE2_List *); void * DCE2_ListNext(DCE2_List *); void * DCE2_ListLast(DCE2_List *); void * DCE2_ListPrev(DCE2_List *); void DCE2_ListRemoveCurrent(DCE2_List *); static inline int DCE2_ListIsEmpty(DCE2_List *); void DCE2_ListEmpty(DCE2_List *); void DCE2_ListDestroy(DCE2_List *); DCE2_Queue * DCE2_QueueNew(DCE2_QueueDataFree, DCE2_MemType); DCE2_Ret DCE2_QueueEnqueue(DCE2_Queue *, void *); void * DCE2_QueueDequeue(DCE2_Queue *); void * DCE2_QueueFirst(DCE2_Queue *); void * DCE2_QueueNext(DCE2_Queue *); void * DCE2_QueueLast(DCE2_Queue *); void * DCE2_QueuePrev(DCE2_Queue *); void DCE2_QueueRemoveCurrent(DCE2_Queue *); static inline int DCE2_QueueIsEmpty(DCE2_Queue *); void DCE2_QueueEmpty(DCE2_Queue *); void DCE2_QueueDestroy(DCE2_Queue *); DCE2_Stack * DCE2_StackNew(DCE2_StackDataFree, DCE2_MemType); DCE2_Ret DCE2_StackPush(DCE2_Stack *, void *); void * DCE2_StackPop(DCE2_Stack *); void * DCE2_StackFirst(DCE2_Stack *); void * DCE2_StackNext(DCE2_Stack *); void * DCE2_StackLast(DCE2_Stack *); void * DCE2_StackPrev(DCE2_Stack *); static inline int DCE2_StackIsEmpty(DCE2_Stack *); void DCE2_StackEmpty(DCE2_Stack *); void DCE2_StackDestroy(DCE2_Stack *); DCE2_CQueue * DCE2_CQueueNew(int, DCE2_CQueueDataFree, DCE2_MemType); DCE2_Ret DCE2_CQueueEnqueue(DCE2_CQueue *, void *); void * DCE2_CQueueDequeue(DCE2_CQueue *); void * DCE2_CQueueFirst(DCE2_CQueue *); void * DCE2_CQueueNext(DCE2_CQueue *); static inline int DCE2_CQueueIsEmpty(DCE2_CQueue *); void DCE2_CQueueEmpty(DCE2_CQueue *); void DCE2_CQueueDestroy(DCE2_CQueue *); DCE2_CStack * DCE2_CStackNew(int, DCE2_CStackDataFree, DCE2_MemType); DCE2_Ret DCE2_CStackPush(DCE2_CStack *, void *); void * DCE2_CStackPop(DCE2_CStack *); void * DCE2_CStackTop(DCE2_CStack *); void * DCE2_CStackFirst(DCE2_CStack *); void * DCE2_CStackNext(DCE2_CStack *); static inline int DCE2_CStackIsEmpty(DCE2_CStack *); void DCE2_CStackEmpty(DCE2_CStack *); void DCE2_CStackDestroy(DCE2_CStack *); /******************************************************************** * Function: DCE2_ListIsEmpty() * * Determines whether or not the list has any items in it * currently. * * Arguments: * DCE2_List * * A pointer to the list object. * * Returns: * int * 1 if the list has zero nodes in it or the list object * passed in is NULL. * 0 if the list has one or more nodes in it. * ********************************************************************/ static inline int DCE2_ListIsEmpty(DCE2_List *list) { if (list == NULL) return 1; if (list->num_nodes == 0) return 1; return 0; } /******************************************************************** * Function: DCE2_QueueIsEmpty() * * Determines whether or not the queue has any items in it * currently. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * * Returns: * int * 1 if the queue has zero nodes in it or the queue object * passed in is NULL. * 0 if the queue has one or more nodes in it. * ********************************************************************/ static inline int DCE2_QueueIsEmpty(DCE2_Queue *queue) { if (queue == NULL) return 1; if (queue->num_nodes == 0) return 1; return 0; } /******************************************************************** * Function: DCE2_StackIsEmpty() * * Determines whether or not the stack has any items in it * currently. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * * Returns: * int * 1 if the stack has zero nodes in it or the stack object * passed in is NULL. * 0 if the stack has one or more nodes in it. * ********************************************************************/ static inline int DCE2_StackIsEmpty(DCE2_Stack *stack) { if (stack == NULL) return 1; if (stack->num_nodes == 0) return 1; return 0; } /******************************************************************** * Function: DCE2_CQueueIsEmpty() * * Determines whether or not the queue has any items in it * currently. * * Arguments: * DCE2_CQueue * * A pointer to the queue object. * * Returns: * int * 1 if the queue has zero nodes in it or the queue object * passed in is NULL. * 0 if the queue has one or more nodes in it. * ********************************************************************/ static inline int DCE2_CQueueIsEmpty(DCE2_CQueue *cqueue) { if (cqueue == NULL) return 1; if (cqueue->num_nodes == 0) return 1; return 0; } /******************************************************************** * Function: DCE2_CStackIsEmpty() * * Determines whether or not the stack has any items in it * currently. * * Arguments: * DCE2_CStack * * A pointer to the stack object. * * Returns: * int * 1 if the stack has zero nodes in it or the stack object * passed in is NULL. * 0 if the stack has one or more nodes in it. * ********************************************************************/ static inline int DCE2_CStackIsEmpty(DCE2_CStack *cstack) { if (cstack == NULL) return 1; if (cstack->num_nodes == 0) return 1; return 0; } #endif /* _DCE2_LIST_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_list.c0000644000000000000000000015261212260565732020421 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides list, queue and stack data structures and methods for use * with the preprocessor. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "dce2_list.h" #include "dce2_memory.h" #include "dce2_debug.h" #include "dce2_utils.h" #include "sf_types.h" /******************************************************************** * Private function prototyes ********************************************************************/ static void DCE2_ListInsertTail(DCE2_List *, DCE2_ListNode *); static void DCE2_ListInsertHead(DCE2_List *, DCE2_ListNode *); static void DCE2_ListInsertBefore(DCE2_List *, DCE2_ListNode *, DCE2_ListNode *); /******************************************************************** * Function: DCE2_ListNew() * * Creates and returns a new list object. * * Arguments: * DCE2_ListType * The type of list this should be - sorted, splayed, etc. * DCE2_ListKeyCompare * The comparison function to call when comparing two keys * for inserting, finding, etc. * DCE2_ListDataFree * An optional function to call to free data in the list. * If NULL is passed in, the user will have to manually free * the data. * DCE2_ListKeyFree * An optional function to call to free keys used in the list. * If NULL is passed in, the user will have to manually free * the keys. * int * Flags that affect processing of the list. * See DCE2_ListFlags for possible combinations. * DCE2_MemType * The memory type that dynamically allocated data should be * associated with. * * Returns: * DCE2_List * * Pointer to a valid list object. * NULL if an error occurs. * ********************************************************************/ DCE2_List * DCE2_ListNew(DCE2_ListType type, DCE2_ListKeyCompare kc, DCE2_ListDataFree df, DCE2_ListKeyFree kf, int flags, DCE2_MemType mtype) { DCE2_List *list; /* Must have a key compare function */ if (kc == NULL) return NULL; list = (DCE2_List *)DCE2_Alloc(sizeof(DCE2_List), mtype); if (list == NULL) return NULL; list->type = type; list->compare = kc; list->data_free = df; list->key_free = kf; list->flags = flags; list->mtype = mtype; return list; } /******************************************************************** * Function: DCE2_ListFind() * * Trys to find a node in the list using key passed in. If list * is splayed, found node is moved to front of list. The data * associated with the node is returned. * * Arguments: * DCE2_List * * A pointer to the list object. * void * * Pointer to a key. * * Returns: * void * * If the key is found, the data associated with the node * is returned. * NULL is returned if the item cannot be found given the key. * ********************************************************************/ void * DCE2_ListFind(DCE2_List *list, void *key) { DCE2_ListNode *n; if (list == NULL) return NULL; for (n = list->head; n != NULL; n = n->next) { int comp = list->compare(key, n->key); if (comp == 0) { /* Found it, break out */ break; } else if ((comp < 0) && (list->type == DCE2_LIST_TYPE__SORTED)) { /* Don't look any more if the list is sorted */ return NULL; } } if (n != NULL) { /* If list is splayed, move found node to front of list */ if ((list->type == DCE2_LIST_TYPE__SPLAYED) && (n != list->head)) { n->prev->next = n->next; if (n->next != NULL) n->next->prev = n->prev; else /* it's the tail */ list->tail = n->prev; n->prev = NULL; n->next = list->head; list->head->prev = n; list->head = n; } return n->data; } return NULL; } /******************************************************************** * Function: DCE2_ListFindKey() * * Trys to find a node in the list using key passed in. If list * is splayed, found node is moved to front of list. Returns * whether or not the key is associated with a node in the list. * * Arguments: * DCE2_List * * A pointer to the list object. * void * * Pointer to a key. * * Returns: * DCE2_Ret * DCE2_RET__SUCCESS if the key is found. * DCE2_RET__ERROR if the key is not found. * ********************************************************************/ DCE2_Ret DCE2_ListFindKey(DCE2_List *list, void *key) { DCE2_ListNode *n; if (list == NULL) return DCE2_RET__ERROR; for (n = list->head; n != NULL; n = n->next) { int comp = list->compare(key, n->key); if (comp == 0) { /* Found it, break out */ break; } else if ((comp < 0) && (list->type == DCE2_LIST_TYPE__SORTED)) { /* Don't look any more if the list is sorted */ return DCE2_RET__ERROR; } } if (n != NULL) { /* If list is splayed, move found node to front of list */ if ((list->type == DCE2_LIST_TYPE__SPLAYED) && (n != list->head)) { n->prev->next = n->next; if (n->next != NULL) n->next->prev = n->prev; else /* it's the tail */ list->tail = n->prev; n->prev = NULL; n->next = list->head; list->head->prev = n; list->head = n; } return DCE2_RET__SUCCESS; } return DCE2_RET__ERROR; } /******************************************************************** * Function: DCE2_ListInsert() * * Adds a new node to the list with the key and data supplied. * If no duplicates are allowed in the key is searched for first * to see if a node is already present in the list. If sorted, * the node is inserted into the list based on the key compare * function associated with the list object. * * Arguments: * DCE2_List * * A pointer to the list object. * void * * Pointer to a key to associate with data. * void * * Pointer to the data to insert into the list. * * Returns: * DCE2_Ret * DCE2_RET__DUPLICATE if an entry with the key is already * in the list and no duplicates are allowed. * DCE2_RET__SUCCESS if a new node with key and data is * successfully inserted into the list. * DCE2_RET__ERROR if memory cannot be allocated for the * new node or a NULL list object was passed in. * ********************************************************************/ DCE2_Ret DCE2_ListInsert(DCE2_List *list, void *key, void *data) { DCE2_ListNode *n; DCE2_ListNode *last = NULL; int dup_check = 0; if (list == NULL) return DCE2_RET__ERROR; if (list->flags & DCE2_LIST_FLAG__NO_DUPS) { for (last = list->head; last != NULL; last = last->next) { int comp = list->compare(key, last->key); if (comp == 0) { /* It's already in the list */ return DCE2_RET__DUPLICATE; } else if ((comp < 0) && (list->type == DCE2_LIST_TYPE__SORTED)) { /* Break out here so as to insert after this node since * the list is sorted */ break; } } dup_check = 1; } n = (DCE2_ListNode *)DCE2_Alloc(sizeof(DCE2_ListNode), list->mtype); if (n == NULL) return DCE2_RET__ERROR; n->key = key; n->data = data; if ((list->type != DCE2_LIST_TYPE__SORTED) || (list->head == NULL)) { if (list->flags & DCE2_LIST_FLAG__INS_TAIL) DCE2_ListInsertTail(list, n); else DCE2_ListInsertHead(list, n); } else if (dup_check) /* and the list is sorted */ { if (last == NULL) DCE2_ListInsertTail(list, n); else DCE2_ListInsertBefore(list, n, last); } else { DCE2_ListNode *tmp; for (tmp = list->head; tmp != NULL; tmp = tmp->next) { if (list->compare(key, tmp->key) <= 0) break; } if (tmp == NULL) DCE2_ListInsertTail(list, n); else if (tmp == list->head) DCE2_ListInsertHead(list, n); else DCE2_ListInsertBefore(list, n, tmp); } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ListRemove() * * Removes the node in the list with the specified key. If * data free and key free functions were given with the creation * of the list object, they are called with the data and key * respectively. * * Arguments: * DCE2_List * * A pointer to the list object. * void * * Pointer to a key. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if a node in the list with the specified * key cannot be found or the list object passed in is NULL. * DCE2_RET__SUCCESS if the node is successfully removed from * the list. * ********************************************************************/ DCE2_Ret DCE2_ListRemove(DCE2_List *list, void *key) { DCE2_ListNode *n; if (list == NULL) return DCE2_RET__ERROR; for (n = list->head; n != NULL; n = n->next) { int comp = list->compare(key, n->key); if (comp == 0) { /* Found it */ break; } else if ((comp < 0) && (list->type == DCE2_LIST_TYPE__SORTED)) { /* Won't find it after this since the list is sorted */ return DCE2_RET__ERROR; } } if (n == NULL) return DCE2_RET__ERROR; if (n == list->head) list->head = n->next; if (n == list->tail) list->tail = n->prev; if (n->prev != NULL) n->prev->next = n->next; if (n->next != NULL) n->next->prev = n->prev; if (list->key_free != NULL) list->key_free(n->key); if (list->data_free != NULL) list->data_free(n->data); DCE2_Free((void *)n, sizeof(DCE2_ListNode), list->mtype); list->num_nodes--; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_ListFirst() * * Returns a pointer to the data of the first node in the list. * Sets a current pointer to the first node in the list for * iterating over the list. * * Arguments: * DCE2_List * * A pointer to the list object. * * Returns: * void * * The data in the first node in the list. * NULL if the list object passed in is NULL, or there are * no items in the list. * ********************************************************************/ void * DCE2_ListFirst(DCE2_List *list) { if (list == NULL) return NULL; list->current = list->head; list->next = NULL; if (list->current != NULL) return list->current->data; return NULL; } /******************************************************************** * Function: DCE2_ListNext() * * Increments the current pointer in the list to the next node in * the list and returns the data associated with it. This in * combination with DCE2_ListFirst is useful in a for loop to * iterate over the items in a list. * * Arguments: * DCE2_List * * A pointer to the list object. * * Returns: * void * * The data in the next node in the list. * NULL if the list object passed in is NULL, or we are at * the end of the list and there are no next nodes. * ********************************************************************/ void * DCE2_ListNext(DCE2_List *list) { if (list == NULL) return NULL; if (list->next != NULL) { list->current = list->next; list->next = NULL; return list->current->data; } else if (list->current != NULL) { list->current = list->current->next; if (list->current != NULL) return list->current->data; } return NULL; } /******************************************************************** * Function: DCE2_ListLast() * * Returns a pointer to the data of the last node in the list. * Sets a current pointer to the last node in the list for * iterating over the list backwards. * * Arguments: * DCE2_List * * A pointer to the list object. * * Returns: * void * * The data in the last node in the list. * NULL if the list object passed in is NULL, or there are * no items in the list. * ********************************************************************/ void * DCE2_ListLast(DCE2_List *list) { if (list == NULL) return NULL; list->current = list->tail; list->prev = NULL; if (list->current != NULL) return list->current->data; return NULL; } /******************************************************************** * Function: DCE2_ListPrev() * * Puts the current pointer in the list to the previous node in * the list and returns the data associated with it. This in * combination with DCE2_ListLast is useful in a for loop to * iterate over the items in a list in backwards order. * * Arguments: * DCE2_List * * A pointer to the list object. * * Returns: * void * * The data in the previous node in the list. * NULL if the list object passed in is NULL, or we are at * the beginning of the list and there are no previous nodes. * ********************************************************************/ void * DCE2_ListPrev(DCE2_List *list) { if (list == NULL) return NULL; if (list->prev != NULL) { list->current = list->prev; list->prev = NULL; return list->current->data; } else if (list->current != NULL) { list->current = list->current->prev; if (list->current != NULL) return list->current->data; } return NULL; } /******************************************************************** * Function: DCE2_ListRemoveCurrent() * * Removes the current node pointed to in the list. This is set * when a call to DCE2_ListFirst or DCE2_ListNext is called. For * either of these if data is returned and the user want to remove * that data from the list, this function should be called. * Sets a next pointer, so a next call to DCE2_ListNext will point * to the node after the deleted one. * * Arguments: * DCE2_List * * A pointer to the list object. * * Returns: None * ********************************************************************/ void DCE2_ListRemoveCurrent(DCE2_List *list) { if (list == NULL) return; if (list->current == NULL) return; list->next = list->current->next; list->prev = list->current->prev; if (list->current == list->head) list->head = list->current->next; if (list->current == list->tail) list->tail = list->current->prev; if (list->current->prev != NULL) list->current->prev->next = list->current->next; if (list->current->next != NULL) list->current->next->prev = list->current->prev; if (list->key_free != NULL) list->key_free(list->current->key); if (list->data_free != NULL) list->data_free(list->current->data); DCE2_Free((void *)list->current, sizeof(DCE2_ListNode), list->mtype); list->current = NULL; list->num_nodes--; } /******************************************************************** * Function: DCE2_ListEmpty() * * Removes all of the nodes in a list. Does not delete the list * object itself. Calls data free and key free functions for * data and key if they are not NULL. * * Arguments: * DCE2_List * * A pointer to the list object. * * Returns: None * ********************************************************************/ void DCE2_ListEmpty(DCE2_List *list) { DCE2_ListNode *n; if (list == NULL) return; n = list->head; while (n != NULL) { DCE2_ListNode *tmp = n->next; if (list->data_free != NULL) list->data_free(n->data); if (list->key_free != NULL) list->key_free(n->key); DCE2_Free((void *)n, sizeof(DCE2_ListNode), list->mtype); n = tmp; } list->head = list->tail = list->current = NULL; list->num_nodes = 0; } /******************************************************************** * Function: DCE2_ListDestroy() * * Destroys the list object and all of the data associated with it. * * Arguments: * DCE2_List * * A pointer to the list object. * * Returns: None * ********************************************************************/ void DCE2_ListDestroy(DCE2_List *list) { if (list == NULL) return; DCE2_ListEmpty(list); DCE2_Free(list, sizeof(DCE2_List), list->mtype); } /******************************************************************** * Function: DCE2_ListInsertTail() * * Private function for inserting a node at the end of the list. * * Arguments: * DCE2_List * * A pointer to the list object. * DCE2_ListNode * * A pointer to the list node to insert. * * Returns: None * ********************************************************************/ static void DCE2_ListInsertTail(DCE2_List *list, DCE2_ListNode *n) { if ((list == NULL) || (n == NULL)) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) List and/or list node passed in was NULL", __FILE__, __LINE__); return; } if (list->tail == NULL) { list->tail = list->head = n; n->prev = n->next = NULL; } else { n->prev = list->tail; n->next = NULL; list->tail->next = n; list->tail = n; } list->num_nodes++; } /******************************************************************** * Function: DCE2_ListInsertHead() * * Private function for inserting a node at the front of the list. * * Arguments: * DCE2_List * * A pointer to the list object. * DCE2_ListNode * * A pointer to the list node to insert. * * Returns: None * ********************************************************************/ static void DCE2_ListInsertHead(DCE2_List *list, DCE2_ListNode *n) { if ((list == NULL) || (n == NULL)) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) List and/or list node passed in was NULL", __FILE__, __LINE__); return; } if (list->head == NULL) { list->head = list->tail = n; n->prev = n->next = NULL; } else { n->prev = NULL; n->next = list->head; list->head->prev = n; list->head = n; } list->num_nodes++; } /******************************************************************** * Function: DCE2_ListInsertBefore() * * Private function for inserting a node before a given node in * the list. * * Arguments: * DCE2_List * * A pointer to the list object. * DCE2_ListNode * * A pointer to the list node to insert. * DCE2_ListNode * * A pointer to the list node to insert this node before. * * Returns: None * ********************************************************************/ static void DCE2_ListInsertBefore(DCE2_List *list, DCE2_ListNode *insert, DCE2_ListNode *front) { if ((list == NULL) || (insert == NULL) || (front == NULL)) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) List, insert node and/or front node passed in " "was NULL", __FILE__, __LINE__); return; } if (front == list->head) { DCE2_ListInsertHead(list, insert); } else { insert->prev = front->prev; insert->next = front; front->prev->next = insert; front->prev = insert; list->num_nodes++; } } /******************************************************************** * Function: DCE2_QueueNew() * * Creates and initializes a new queue object. * * Arguments: * DCE2_QueueDataFree * An optional free function for the data inserted into * the queue. If NULL is passed in, the user will be * responsible for freeing data left in the queue. * DCE2_MemType * The type of memory to associate dynamically allocated * memory with. * * Returns: * DCE2_Queue * * Pointer to a new queue object. * NULL if unable to allocate memory for the object. * ********************************************************************/ DCE2_Queue * DCE2_QueueNew(DCE2_QueueDataFree df, DCE2_MemType mtype) { DCE2_Queue *queue; queue = (DCE2_Queue *)DCE2_Alloc(sizeof(DCE2_Queue), mtype); if (queue == NULL) return NULL; queue->data_free = df; queue->mtype = mtype; return queue; } /******************************************************************** * Function: DCE2_QueueEnqueue() * * Inserts data into the queue. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * void * * Pointer to the data to insert into the queue. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if memory cannot be allocated for a new * queue node or the queue object passed in is NULL. * DCE2_RET__SUCCESS if the data is successfully added to * the queue. * ********************************************************************/ DCE2_Ret DCE2_QueueEnqueue(DCE2_Queue *queue, void *data) { DCE2_QueueNode *n; if (queue == NULL) return DCE2_RET__ERROR; n = (DCE2_QueueNode *)DCE2_Alloc(sizeof(DCE2_QueueNode), queue->mtype); if (n == NULL) return DCE2_RET__ERROR; n->data = data; if (queue->tail == NULL) { queue->head = queue->tail = n; n->next = NULL; } else { queue->tail->next = n; n->prev = queue->tail; queue->tail = n; } queue->num_nodes++; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_QueueDequeue() * * Removes and returns the data in the first node in the queue. * Note that the user will have to free the data returned. The * data free function only applies to data that is in the queue * when it is emptied or destroyed. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * * Returns: * void * * The data in the first node in the queue. * NULL if there are no items in the queue or the queue object * passed in is NULL. * ********************************************************************/ void * DCE2_QueueDequeue(DCE2_Queue *queue) { DCE2_QueueNode *n; if (queue == NULL) return NULL; n = queue->head; if (n != NULL) { void *data = n->data; if (queue->head == queue->tail) { queue->head = queue->tail = NULL; } else { queue->head->next->prev = NULL; queue->head = queue->head->next; } DCE2_Free((void *)n, sizeof(DCE2_QueueNode), queue->mtype); queue->num_nodes--; return data; } return NULL; } /******************************************************************** * Function: DCE2_QueueFirst() * * Returns a pointer to the data of the first node in the queue. * Sets a current pointer to the first node in the queue for * iterating over the queue. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * * Returns: * void * * The data in the first node in the queue. * NULL if the queue object passed in is NULL, or there are * no items in the queue. * ********************************************************************/ void * DCE2_QueueFirst(DCE2_Queue *queue) { if (queue == NULL) return NULL; queue->current = queue->head; queue->next = NULL; if (queue->current != NULL) return queue->current->data; return NULL; } /******************************************************************** * Function: DCE2_QueueNext() * * Increments the current pointer in the queue to the next node in * the queue and returns the data associated with it. This in * combination with DCE2_QueueFirst is useful in a for loop to * iterate over the items in a queue. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * * Returns: * void * * The data in the next node in the queue. * NULL if the queue object passed in is NULL, or we are at * the end of the queue and there are no next nodes. * ********************************************************************/ void * DCE2_QueueNext(DCE2_Queue *queue) { if (queue == NULL) return NULL; if (queue->next != NULL) { queue->current = queue->next; queue->next = NULL; return queue->current->data; } else if (queue->current != NULL) { queue->current = queue->current->next; if (queue->current != NULL) return queue->current->data; } return NULL; } /******************************************************************** * Function: DCE2_QueueLast() * * Returns a pointer to the data of the last node in the queue. * Sets a current pointer to the last node in the queue for * iterating over the queue backwards. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * * Returns: * void * * The data in the last node in the queue. * NULL if the queue object passed in is NULL, or there are * no items in the queue. * ********************************************************************/ void * DCE2_QueueLast(DCE2_Queue *queue) { if (queue == NULL) return NULL; queue->current = queue->tail; queue->prev = NULL; if (queue->current != NULL) return queue->current->data; return NULL; } /******************************************************************** * Function: DCE2_QueuePrev() * * Puts the current pointer in the queue to the previous node in * the queue and returns the data associated with it. This in * combination with DCE2_QueueLast is useful in a for loop to * iterate over the items in a queue in backwards order. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * * Returns: * void * * The data in the previous node in the queue. * NULL if the queue object passed in is NULL, or we are at * the beginning of the queue and there are no previous nodes. * ********************************************************************/ void * DCE2_QueuePrev(DCE2_Queue *queue) { if (queue == NULL) return NULL; if (queue->prev != NULL) { queue->current = queue->prev; queue->prev = NULL; return queue->current->data; } else if (queue->current != NULL) { queue->current = queue->current->prev; if (queue->current != NULL) return queue->current->data; } return NULL; } /******************************************************************** * Function: DCE2_QueueRemoveCurrent() * * Removes the current node pointed to in the queue. This is set * when a call to DCE2_QueueFirst or DCE2_QueueNext is called. For * either of these if data is returned and the user want to remove * that data from the queue, this function should be called. * Sets a next pointer, so a next call to DCE2_QueueNext will point * to the node after the deleted one. * * Arguments: * DCE2_Queue * * A pointer to the list object. * * Returns: None * ********************************************************************/ void DCE2_QueueRemoveCurrent(DCE2_Queue *queue) { if (queue == NULL) return; if (queue->current == NULL) return; queue->next = queue->current->next; queue->prev = queue->current->prev; if (queue->current == queue->head) queue->head = queue->current->next; if (queue->current == queue->tail) queue->tail = queue->current->prev; if (queue->current->prev != NULL) queue->current->prev->next = queue->current->next; if (queue->current->next != NULL) queue->current->next->prev = queue->current->prev; if (queue->data_free != NULL) queue->data_free(queue->current->data); DCE2_Free((void *)queue->current, sizeof(DCE2_QueueNode), queue->mtype); queue->current = NULL; queue->num_nodes--; } /******************************************************************** * Function: DCE2_QueueEmpty() * * Removes all of the nodes in a queue. Does not delete the queue * object itself. Calls data free function for data if it is * not NULL. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * * Returns: None * ********************************************************************/ void DCE2_QueueEmpty(DCE2_Queue *queue) { DCE2_QueueNode *n; if (queue == NULL) return; n = queue->head; while (n != NULL) { DCE2_QueueNode *tmp = n->next; if (queue->data_free != NULL) queue->data_free(n->data); DCE2_Free((void *)n, sizeof(DCE2_QueueNode), queue->mtype); n = tmp; } queue->head = queue->tail = queue->current = NULL; queue->num_nodes = 0; } /******************************************************************** * Function: DCE2_QueueDestroy() * * Destroys the queue object and all of the data associated with it. * * Arguments: * DCE2_Queue * * A pointer to the queue object. * * Returns: None * ********************************************************************/ void DCE2_QueueDestroy(DCE2_Queue *queue) { if (queue == NULL) return; DCE2_QueueEmpty(queue); DCE2_Free((void *)queue, sizeof(DCE2_Queue), queue->mtype); } /******************************************************************** * Function: DCE2_StackNew() * * Creates and initializes a new stack object. * * Arguments: * DCE2_StackDataFree * An optional free function for the data inserted into * the stack. If NULL is passed in, the user will be * responsible for freeing data left in the stack. * DCE2_MemType * The type of memory to associate dynamically allocated * memory with. * * Returns: * DCE2_Stack * * Pointer to a new stack object. * NULL if unable to allocate memory for the object. * ********************************************************************/ DCE2_Stack * DCE2_StackNew(DCE2_StackDataFree df, DCE2_MemType mtype) { DCE2_Stack *stack; stack = (DCE2_Stack *)DCE2_Alloc(sizeof(DCE2_Stack), mtype); if (stack == NULL) return NULL; stack->data_free = df; stack->mtype = mtype; return stack; } /******************************************************************** * Function: DCE2_StackPush() * * Inserts data onto the stack. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * void * * Pointer to the data to insert onto the stack. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if memory cannot be allocated for a new * stack node or the stack object passed in is NULL. * DCE2_RET__SUCCESS if the data is successfully added to * the stack. * ********************************************************************/ DCE2_Ret DCE2_StackPush(DCE2_Stack *stack, void *data) { DCE2_StackNode *n; if (stack == NULL) return DCE2_RET__ERROR; n = (DCE2_StackNode *)DCE2_Alloc(sizeof(DCE2_StackNode), stack->mtype); if (n == NULL) return DCE2_RET__ERROR; n->data = data; if (stack->tail == NULL) { stack->tail = stack->head = n; n->prev = NULL; n->next = NULL; } else { stack->tail->next = n; n->prev = stack->tail; stack->tail = n; } stack->num_nodes++; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_StackPop() * * Removes and returns the data in the last node in the stack. * Note that the user will have to free the data returned. The * data free function only applies to data that is in the stack * when it is emptied or destroyed. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * * Returns: * void * * The data in the last node in the stack. * NULL if there are no items in the stack or the stack object * passed in is NULL. * ********************************************************************/ void * DCE2_StackPop(DCE2_Stack *stack) { DCE2_StackNode *n; if (stack == NULL) return NULL; n = stack->tail; if (n != NULL) { void *data = n->data; stack->tail = stack->tail->prev; if (stack->tail == NULL) stack->head = NULL; DCE2_Free((void *)n, sizeof(DCE2_StackNode), stack->mtype); stack->num_nodes--; return data; } return NULL; } /******************************************************************** * Function: DCE2_StackFirst() * * Returns a pointer to the data of the first node in the stack. * Sets a current pointer to the first node in the stack for * iterating over the stack. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * * Returns: * void * * The data in the first node in the stack. * NULL if the stack object passed in is NULL, or there are * no items in the stack. * ********************************************************************/ void * DCE2_StackFirst(DCE2_Stack *stack) { if (stack == NULL) return NULL; stack->current = stack->head; if (stack->current != NULL) return stack->current->data; return NULL; } /******************************************************************** * Function: DCE2_StackNext() * * Increments the current pointer in the stack to the next node in * the stack and returns the data associated with it. This in * combination with DCE2_StackFirst is useful in a for loop to * iterate over the items in a stack. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * * Returns: * void * * The data in the next node in the stack. * NULL if the stack object passed in is NULL, or we are at * the end of the stack and there are no next nodes. * ********************************************************************/ void * DCE2_StackNext(DCE2_Stack *stack) { if (stack == NULL) return NULL; if (stack->current != NULL) { stack->current = stack->current->next; if (stack->current != NULL) return stack->current->data; } return NULL; } /******************************************************************** * Function: DCE2_StackLast() * * Returns a pointer to the data of the last node in the stack. * Sets a current pointer to the last node in the stack for * iterating over the stack backwards. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * * Returns: * void * * The data in the last node in the stack. * NULL if the stack object passed in is NULL, or there are * no items in the stack. * ********************************************************************/ void * DCE2_StackLast(DCE2_Stack *stack) { if (stack == NULL) return NULL; stack->current = stack->tail; if (stack->current != NULL) return stack->current->data; return NULL; } /******************************************************************** * Function: DCE2_StackPrev() * * Puts the current pointer in the stack to the previous node in * the stack and returns the data associated with it. This in * combination with DCE2_StackLast is useful in a for loop to * iterate over the items in a stack in backwards order. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * * Returns: * void * * The data in the previous node in the stack. * NULL if the stack object passed in is NULL, or we are at * the beginning of the stack and there are no previous nodes. * ********************************************************************/ void * DCE2_StackPrev(DCE2_Stack *stack) { if (stack == NULL) return NULL; if (stack->current != NULL) { stack->current = stack->current->prev; if (stack->current != NULL) return stack->current->data; } return NULL; } /******************************************************************** * Function: DCE2_StackEmpty() * * Removes all of the nodes in a stack. Does not delete the stack * object itself. Calls data free function for data if it is * not NULL. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * * Returns: None * ********************************************************************/ void DCE2_StackEmpty(DCE2_Stack *stack) { DCE2_StackNode *n; if (stack == NULL) return; n = stack->head; while (n != NULL) { DCE2_StackNode *tmp = n->next; if (stack->data_free != NULL) stack->data_free(n->data); DCE2_Free((void *)n, sizeof(DCE2_StackNode), stack->mtype); n = tmp; } stack->head = stack->tail = stack->current = NULL; stack->num_nodes = 0; } /******************************************************************** * Function: DCE2_StackDestroy() * * Destroys the stack object and all of the data associated with it. * * Arguments: * DCE2_Stack * * A pointer to the stack object. * * Returns: None * ********************************************************************/ void DCE2_StackDestroy(DCE2_Stack *stack) { if (stack == NULL) return; DCE2_StackEmpty(stack); DCE2_Free((void *)stack, sizeof(DCE2_Stack), stack->mtype); } /******************************************************************** * Function: DCE2_CQueueNew() * * Creates and initializes a new circular queue object. The * circular queue uses a fixed size array and uses indexes to * indicate the start and end of the queue. This type of * queue can become full since it is a fixed size. Used for * performance reasons since new nodes do not need to be * allocated on the fly. * * Arguments: * int * The size that should be allocated for the circular * queue storage. * DCE2_CQueueDataFree * An optional free function for the data inserted into * the queue. If NULL is passed in, the user will be * responsible for freeing data left in the queue. * DCE2_MemType * The type of memory to associate dynamically allocated * memory with. * * Returns: * DCE2_CQueue * * Pointer to a new queue object. * NULL if unable to allocate memory for the object or the * array for storage. * ********************************************************************/ DCE2_CQueue * DCE2_CQueueNew(int size, DCE2_CQueueDataFree df, DCE2_MemType mtype) { DCE2_CQueue *cqueue; if (size <= 0) return NULL; cqueue = (DCE2_CQueue *)DCE2_Alloc(sizeof(DCE2_CQueue), mtype); if (cqueue == NULL) return NULL; cqueue->data_free = df; cqueue->mtype = mtype; cqueue->queue = DCE2_Alloc(size * sizeof(void *), mtype); if (cqueue->queue == NULL) { DCE2_Free(cqueue, sizeof(DCE2_CQueue), mtype); return NULL; } cqueue->size = size; cqueue->head_idx = 0; cqueue->tail_idx = DCE2_SENTINEL; cqueue->cur_idx = DCE2_SENTINEL; return cqueue; } /******************************************************************** * Function: DCE2_CQueueEnqueue() * * Inserts data into the circular queue. * * Arguments: * DCE2_CQueue * * A pointer to the queue object. * void * * Pointer to the data to insert into the queue. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if the queue is full or the queue object * passed in is NULL. * DCE2_RET__SUCCESS if the data is successfully added to * the queue. * ********************************************************************/ DCE2_Ret DCE2_CQueueEnqueue(DCE2_CQueue *cqueue, void *data) { if (cqueue == NULL) return DCE2_RET__ERROR; if (cqueue->num_nodes == (uint32_t)cqueue->size) return DCE2_RET__ERROR; if (cqueue->tail_idx == DCE2_SENTINEL) cqueue->tail_idx = cqueue->head_idx; cqueue->queue[cqueue->tail_idx] = data; if ((cqueue->tail_idx + 1) == cqueue->size) cqueue->tail_idx = 0; else cqueue->tail_idx++; cqueue->num_nodes++; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_CQueueDequeue() * * Removes and returns the data in the first node in the queue. * Note that the user will have to free the data returned. The * data free function only applies to data that is in the queue * when it is emptied or destroyed. * * Arguments: * DCE2_CQueue * * A pointer to the queue object. * * Returns: * void * * The data in the first node in the queue. * NULL if there are no items in the queue or the queue object * passed in is NULL. * ********************************************************************/ void * DCE2_CQueueDequeue(DCE2_CQueue *cqueue) { void *data; if (cqueue == NULL) return NULL; if (cqueue->num_nodes == 0) return NULL; data = cqueue->queue[cqueue->head_idx]; cqueue->queue[cqueue->head_idx] = NULL; if ((cqueue->head_idx + 1) == cqueue->size) cqueue->head_idx = 0; else cqueue->head_idx++; if (cqueue->head_idx == cqueue->tail_idx) cqueue->tail_idx = DCE2_SENTINEL; cqueue->num_nodes--; return data; } /******************************************************************** * Function: DCE2_CQueueFirst() * * Returns a pointer to the data of the first node in the queue. * Sets a current index to the first node in the queue for * iterating over the queue. * * Arguments: * DCE2_CQueue * * A pointer to the queue object. * * Returns: * void * * The data in the first node in the queue. * NULL if the queue object passed in is NULL, or there are * no items in the queue. * ********************************************************************/ void * DCE2_CQueueFirst(DCE2_CQueue *cqueue) { if (cqueue == NULL) return NULL; if (cqueue->tail_idx == DCE2_SENTINEL) return NULL; cqueue->cur_idx = cqueue->head_idx; return cqueue->queue[cqueue->cur_idx]; } /******************************************************************** * Function: DCE2_CQueueNext() * * Increments the current index in the queue to the next node in * the queue and returns the data associated with it. This in * combination with DCE2_CQueueFirst is useful in a for loop to * iterate over the items in a queue. * * Arguments: * DCE2_CQueue * * A pointer to the queue object. * * Returns: * void * * The data in the next node in the queue. * NULL if the queue object passed in is NULL, or we are at * the end of the queue and there are no next nodes. * ********************************************************************/ void * DCE2_CQueueNext(DCE2_CQueue *cqueue) { if (cqueue == NULL) return NULL; if ((cqueue->tail_idx == DCE2_SENTINEL) || (cqueue->cur_idx == DCE2_SENTINEL)) return NULL; if ((cqueue->cur_idx + 1) == cqueue->size) cqueue->cur_idx = 0; else cqueue->cur_idx++; if (cqueue->cur_idx == cqueue->tail_idx) { cqueue->cur_idx = DCE2_SENTINEL; return NULL; } return cqueue->queue[cqueue->cur_idx]; } /******************************************************************** * Function: DCE2_CQueueEmpty() * * Removes all of the nodes in a queue. Does not delete the queue * object itself or the storage array. Calls data free function * for data if it is not NULL. * * Arguments: * DCE2_CQueue * * A pointer to the queue object. * * Returns: None * ********************************************************************/ void DCE2_CQueueEmpty(DCE2_CQueue *cqueue) { if (cqueue == NULL) return; while (!DCE2_CQueueIsEmpty(cqueue)) { void *data = DCE2_CQueueDequeue(cqueue); if ((data != NULL) && (cqueue->data_free != NULL)) cqueue->data_free(data); } cqueue->num_nodes = 0; cqueue->head_idx = 0; cqueue->tail_idx = DCE2_SENTINEL; cqueue->cur_idx = DCE2_SENTINEL; } /******************************************************************** * Function: DCE2_CQueueDestroy() * * Destroys the queue object and all of the data associated with it. * * Arguments: * DCE2_CQueue * * A pointer to the queue object. * * Returns: None * ********************************************************************/ void DCE2_CQueueDestroy(DCE2_CQueue *cqueue) { if (cqueue == NULL) return; DCE2_CQueueEmpty(cqueue); DCE2_Free((void *)cqueue->queue, (cqueue->size * sizeof(void *)), cqueue->mtype); DCE2_Free((void *)cqueue, sizeof(DCE2_CQueue), cqueue->mtype); } /******************************************************************** * Function: DCE2_CStackNew() * * Creates and initializes a new static sized stack object. The * static stack uses a fixed size array and uses indexes to * indicate the start and end of the stack. This type of * stack can become full since it is a fixed size. Used for * performance reasons since new nodes do not need to be * allocated on the fly. * * Arguments: * int * The size that should be allocated for the static * stack storage. * DCE2_CStackDataFree * An optional free function for the data inserted into * the stack. If NULL is passed in, the user will be * responsible for freeing data left in the stack. * DCE2_MemType * The type of memory to associate dynamically allocated * memory with. * * Returns: * DCE2_CStack * * Pointer to a new stack object. * NULL if unable to allocate memory for the object or the * array for storage. * ********************************************************************/ DCE2_CStack * DCE2_CStackNew(int size, DCE2_CStackDataFree df, DCE2_MemType mtype) { DCE2_CStack *cstack; if (size <= 0) return NULL; cstack = (DCE2_CStack *)DCE2_Alloc(sizeof(DCE2_CStack), mtype); if (cstack == NULL) return NULL; cstack->data_free = df; cstack->mtype = mtype; cstack->stack = DCE2_Alloc(size * sizeof(void *), mtype); if (cstack->stack == NULL) { DCE2_Free(cstack, sizeof(DCE2_CStack), mtype); return NULL; } cstack->size = size; cstack->tail_idx = DCE2_SENTINEL; cstack->cur_idx = DCE2_SENTINEL; return cstack; } /******************************************************************** * Function: DCE2_CStackPush() * * Inserts data into the static stack. * * Arguments: * DCE2_CStack * * A pointer to the stack object. * void * * Pointer to the data to insert into the stack. * * Returns: * DCE2_Ret * DCE2_RET__ERROR if the stack is full or the stack object * passed in is NULL. * DCE2_RET__SUCCESS if the data is successfully added to * the stack. * ********************************************************************/ DCE2_Ret DCE2_CStackPush(DCE2_CStack *cstack, void *data) { if (cstack == NULL) return DCE2_RET__ERROR; if (cstack->num_nodes == (uint32_t)cstack->size) return DCE2_RET__ERROR; if (cstack->tail_idx == DCE2_SENTINEL) cstack->tail_idx = 0; else cstack->tail_idx++; cstack->stack[cstack->tail_idx] = data; cstack->num_nodes++; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: DCE2_CStackPop() * * Removes and returns the data in the last node in the stack. * Note that the user will have to free the data returned. The * data free function only applies to data that is in the stack * when it is emptied or destroyed. * * Arguments: * DCE2_CStack * * A pointer to the stack object. * * Returns: * void * * The data in the last node in the stack. * NULL if there are no items in the stack or the stack object * passed in is NULL. * ********************************************************************/ void * DCE2_CStackPop(DCE2_CStack *cstack) { void *data; if (cstack == NULL) return NULL; if (cstack->num_nodes == 0) return NULL; data = cstack->stack[cstack->tail_idx]; cstack->stack[cstack->tail_idx] = NULL; if (cstack->tail_idx == 0) cstack->tail_idx = DCE2_SENTINEL; else cstack->tail_idx--; cstack->num_nodes--; return data; } /******************************************************************** * Function: DCE2_CStackTop() * * Returns the data on top of the stack. Does not remove the data * from the stack. * * Arguments: * DCE2_CStack * * A pointer to the stack object. * * Returns: * void * * The data on top of the stack. * NULL if there are no items in the stack or the stack object * passed in is NULL. * ********************************************************************/ void * DCE2_CStackTop(DCE2_CStack *cstack) { if (cstack == NULL) return NULL; if (cstack->num_nodes == 0) return NULL; return cstack->stack[cstack->tail_idx]; } /******************************************************************** * Function: DCE2_CStackFirst() * * Returns a pointer to the data of the first node in the stack * array. Sets a current index to the first node in the stack for * iterating over the stack. * * Arguments: * DCE2_CStack * * A pointer to the stack object. * * Returns: * void * * The data in the first node in the stack. * NULL if the stack object passed in is NULL, or there are * no items in the stack. * ********************************************************************/ void * DCE2_CStackFirst(DCE2_CStack *cstack) { if (cstack == NULL) return NULL; if (cstack->num_nodes == 0) return NULL; cstack->cur_idx = 0; return cstack->stack[cstack->cur_idx]; } /******************************************************************** * Function: DCE2_CStackNext() * * Increments the current index in the stack to the next node in * the stack and returns the data associated with it. This in * combination with DCE2_CStackFirst is useful in a for loop to * iterate over the items in a stack. * * Arguments: * DCE2_CStack * * A pointer to the stack object. * * Returns: * void * * The data in the next node in the stack. * NULL if the stack object passed in is NULL, or we are at * the end of the stack and there are no next nodes. * ********************************************************************/ void * DCE2_CStackNext(DCE2_CStack *cstack) { if (cstack == NULL) return NULL; if ((uint32_t)(cstack->cur_idx + 1) == cstack->num_nodes) return NULL; cstack->cur_idx++; return cstack->stack[cstack->cur_idx]; } /******************************************************************** * Function: DCE2_CStackEmpty() * * Removes all of the nodes in a stack. Does not delete the stack * object itself or the storage array. Calls data free function * for data if it is not NULL. * * Arguments: * DCE2_CStack * * A pointer to the stack object. * * Returns: None * ********************************************************************/ void DCE2_CStackEmpty(DCE2_CStack *cstack) { if (cstack == NULL) return; while (!DCE2_CStackIsEmpty(cstack)) { void *data = DCE2_CStackPop(cstack); if ((data != NULL) && (cstack->data_free != NULL)) cstack->data_free(data); } cstack->num_nodes = 0; cstack->tail_idx = DCE2_SENTINEL; cstack->cur_idx = DCE2_SENTINEL; } /******************************************************************** * Function: DCE2_CStackDestroy() * * Destroys the stack object and all of the data associated with it. * * Arguments: * DCE2_CStack * * A pointer to the stack object. * * Returns: None * ********************************************************************/ void DCE2_CStackDestroy(DCE2_CStack *cstack) { if (cstack == NULL) return; DCE2_CStackEmpty(cstack); DCE2_Free((void *)cstack->stack, (cstack->size * sizeof(void *)), cstack->mtype); DCE2_Free((void *)cstack, sizeof(DCE2_CStack), cstack->mtype); } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_utils.h0000644000000000000000000003465212260565732020616 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _DCE2_UTILS_H_ #define _DCE2_UTILS_H_ #include "dce2_debug.h" #include "dce2_memory.h" #include "dcerpc.h" #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "snort_debug.h" #include "snort_bounds.h" /******************************************************************** * Macros ********************************************************************/ #define DCE2_SENTINEL -1 /******************************************************************** * Enumerations ********************************************************************/ typedef enum _DCE2_Ret { DCE2_RET__SUCCESS = 0, DCE2_RET__ERROR, DCE2_RET__MEMCAP, DCE2_RET__NOT_INSPECTED, DCE2_RET__INSPECTED, DCE2_RET__REASSEMBLE, DCE2_RET__SEG, DCE2_RET__FULL, DCE2_RET__FRAG, DCE2_RET__ALERTED, DCE2_RET__IGNORE, DCE2_RET__DUPLICATE } DCE2_Ret; typedef enum _DCE2_TransType { DCE2_TRANS_TYPE__NONE = 0, DCE2_TRANS_TYPE__SMB, DCE2_TRANS_TYPE__TCP, DCE2_TRANS_TYPE__UDP, DCE2_TRANS_TYPE__HTTP_PROXY, DCE2_TRANS_TYPE__HTTP_SERVER, DCE2_TRANS_TYPE__MAX } DCE2_TransType; typedef enum _DCE2_BufferMinAddFlag { DCE2_BUFFER_MIN_ADD_FLAG__USE, DCE2_BUFFER_MIN_ADD_FLAG__IGNORE } DCE2_BufferMinAddFlag; typedef enum _DCE2_BufType { DCE2_BUF_TYPE__NULL, DCE2_BUF_TYPE__SEG, DCE2_BUF_TYPE__FRAG } DCE2_BufType; typedef enum _DCE2_LogType { DCE2_LOG_TYPE__LOG, DCE2_LOG_TYPE__WARN, DCE2_LOG_TYPE__ERROR } DCE2_LogType; /******************************************************************** * Structures ********************************************************************/ typedef struct _DCE2_Buffer { uint8_t *data; uint32_t len; uint32_t size; DCE2_MemType mtype; uint32_t min_add_size; uint32_t offset; } DCE2_Buffer; /******************************************************************** * Inline function prototypes ********************************************************************/ #define DCE2_MOVE(data_ptr, data_len, amount) \ { data_len -= (amount); data_ptr = (uint8_t *)data_ptr + (amount); } static inline int DCE2_BufferIsEmpty(DCE2_Buffer *); static inline void DCE2_BufferEmpty(DCE2_Buffer *); static inline uint32_t DCE2_BufferSize(DCE2_Buffer *); static inline uint32_t DCE2_BufferLength(DCE2_Buffer *); static inline void DCE2_BufferSetLength(DCE2_Buffer *, uint32_t); static inline uint8_t * DCE2_BufferData(DCE2_Buffer *); static inline uint32_t DCE2_BufferMinAllocSize(DCE2_Buffer *); static inline void DCE2_BufferSetMinAllocSize(DCE2_Buffer *, uint32_t); static inline char * DCE2_PruneWhiteSpace(char *); static inline int DCE2_IsEmptyStr(char *); static inline DCE2_Ret DCE2_Memcpy(void *, const void *, uint32_t, const void *, const void *); static inline DCE2_Ret DCE2_Memmove(void *, const void *, uint32_t, const void *, const void *); static inline int DCE2_UuidCompare(const void *, const void *); static inline void DCE2_CopyUuid(Uuid *, const Uuid *, const DceRpcBoFlag); /******************************************************************** * Public function prototypes ********************************************************************/ DCE2_Buffer * DCE2_BufferNew(uint32_t, uint32_t, DCE2_MemType); DCE2_Ret DCE2_BufferAddData(DCE2_Buffer *, const uint8_t *, uint32_t, uint32_t, DCE2_BufferMinAddFlag); DCE2_Ret DCE2_BufferMoveData(DCE2_Buffer *, uint32_t, const uint8_t *, uint32_t); void DCE2_BufferDestroy(DCE2_Buffer *); DCE2_Ret DCE2_HandleSegmentation(DCE2_Buffer *, const uint8_t *, uint16_t, uint32_t, uint16_t *); NORETURN void DCE2_Die(const char *, ...); void DCE2_Log(DCE2_LogType, const char *, ...); const char * DCE2_UuidToStr(const Uuid *, DceRpcBoFlag); void DCE2_PrintPktData(const uint8_t *, const uint16_t); /********************************************************************* * Function: DCE2_BufferIsEmpty() * * Determines whether or not a buffer should be considered empty. * Buffer is considered empty if it is NULL, it's data is NULL * or the length of the data is zero. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * * Returns: * 1 if considered empty * 0 if not considered empty * *********************************************************************/ static inline int DCE2_BufferIsEmpty(DCE2_Buffer *buf) { if (buf == NULL) return 1; if ((buf->data == NULL) || (buf->len == 0)) return 1; return 0; } /********************************************************************* * Function: DCE2_BufferEmpty() * * Sets the buffer's data length to zero. Essentially says that * any copied data is not important anymore. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * * Returns: None * *********************************************************************/ static inline void DCE2_BufferEmpty(DCE2_Buffer *buf) { if (buf == NULL) return; buf->len = 0; } /********************************************************************* * Function: DCE2_BufferSize() * * Returns the size of the data currently allocated for storing data. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * * Returns: * uint32_t * The size of the allocated data or zero if buffer * object is NULL. * *********************************************************************/ static inline uint32_t DCE2_BufferSize(DCE2_Buffer *buf) { if (buf == NULL) return 0; return buf->size; } /********************************************************************* * Function: DCE2_BufferLength() * * Returns the length of the data copied into the buffer. This will * always be less than or equal to the size of the data allocated. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * * Returns: * uint32_t * The length of the data copied into the buffer or zero * if buffer object is NULL. * *********************************************************************/ static inline uint32_t DCE2_BufferLength(DCE2_Buffer *buf) { if (buf == NULL) return 0; return buf->len; } /********************************************************************* * Function: DCE2_BufferOffset() * * Returns the offset of the data copied into the buffer. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * * Returns: * uint32_t * The length of the data copied into the buffer or zero * if buffer object is NULL. * *********************************************************************/ static inline uint32_t DCE2_BufferOffset(DCE2_Buffer *buf) { if (buf == NULL) return 0; return buf->offset; } /********************************************************************* * Function: DCE2_BufferSetLength() * * Sets the length of the buffer up to the buffer size. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * uint32_t len * The length to set the amount of data in the buffer to * * Returns: None * *********************************************************************/ static inline void DCE2_BufferSetLength(DCE2_Buffer *buf, uint32_t len) { if (buf == NULL) return; if (len > buf->size) buf->len = buf->size; else buf->len = len; } /********************************************************************* * Function: DCE2_BufferData() * * Returns a pointer to the allocated data. Note that this could * be NULL if not data has been allocated yet. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * * Returns: * uint8_t * * Pointer to the buffer data or NULL if none allocated or * buffer object is NULL. * *********************************************************************/ static inline uint8_t * DCE2_BufferData(DCE2_Buffer *buf) { if (buf == NULL) return NULL; return buf->data; } /********************************************************************* * Function: DCE2_BufferMinAllocSize() * * Returns the minimum allocation size for the buffer. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * * Returns: * uint32_t * The minimum allocation size. * *********************************************************************/ static inline uint32_t DCE2_BufferMinAllocSize(DCE2_Buffer *buf) { if (buf == NULL) return 0; return buf->min_add_size; } /********************************************************************* * Function: DCE2_BufferSetMinAllocSize() * * Sets the minimum allocation size for the buffer. * * Arguments: * DCE2_Buffer * * Pointer to buffer object. * uint32_t * Size to set the minimum allocation size to. * * Returns: None * *********************************************************************/ static inline void DCE2_BufferSetMinAllocSize(DCE2_Buffer *buf, uint32_t size) { if (buf == NULL) return; buf->min_add_size = size; } /******************************************************************** * Function: DCE2_PruneWhiteSpace() * * Prunes whitespace surrounding string. * String must be 0 terminated. * * Arguments: * char * * NULL terminated string to prune. * int * length of string * * Returns: * char * - Pointer to the pruned string. Note that the pointer * still points within the original string. * * Side effects: Spaces at the end of the string passed in as an * argument are replaced by NULL bytes. * ********************************************************************/ static inline char * DCE2_PruneWhiteSpace(char *str) { char *end; if (str == NULL) return NULL; /* Put end a char before NULL byte */ end = str + (strlen(str) - 1); while (isspace((int)*str)) str++; while ((end > str) && isspace((int)*end)) { *end = '\0'; end--; } return str; } /******************************************************************** * Function: DCE2_IsEmptyStr() * * Checks if string is NULL, empty or just spaces. * String must be 0 terminated. * * Arguments: None * char * - string to check * * Returns: * 1 if string is NULL, empty or just spaces * 0 otherwise * ********************************************************************/ static inline int DCE2_IsEmptyStr(char *str) { char *end; if (str == NULL) return 1; end = str + strlen(str); while ((str < end) && isspace((int)*str)) str++; if (str == end) return 1; return 0; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * DCE2_RET__ERROR - memcpy failed * DCE2_RET__SUCCESS - memcpy succeeded * ********************************************************************/ static inline DCE2_Ret DCE2_Memcpy(void *dst, const void *src, uint32_t len, const void *dst_start, const void *dst_end) { if (SafeMemcpy(dst, src, (size_t)len, dst_start, dst_end) != SAFEMEM_SUCCESS) return DCE2_RET__ERROR; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * DCE2_RET__ERROR - memmove failed * DCE2_RET__SUCCESS - memmove succeeded * ********************************************************************/ static inline DCE2_Ret DCE2_Memmove(void *dst, const void *src, uint32_t len, const void *dst_start, const void *dst_end) { if (SafeMemmove(dst, src, (size_t)len, dst_start, dst_end) != SAFEMEM_SUCCESS) return DCE2_RET__ERROR; return DCE2_RET__SUCCESS; } /********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ static inline int DCE2_UuidCompare(const void *data1, const void *data2) { const Uuid *uuid1 = (Uuid *)data1; const Uuid *uuid2 = (Uuid *)data2; if ((uuid1 == NULL) || (uuid2 == NULL)) return -1; if ((uuid1->time_low == uuid2->time_low) && (uuid1->time_mid == uuid2->time_mid) && (uuid1->time_high_and_version == uuid2->time_high_and_version) && (uuid1->clock_seq_and_reserved == uuid2->clock_seq_and_reserved) && (uuid1->clock_seq_low == uuid2->clock_seq_low) && (memcmp(uuid1->node, uuid2->node, sizeof(uuid1->node)) == 0)) { return 0; } /* Just return something other than 0 */ return -1; } /********************************************************************* * Function: DCE2_CopyUuid() * * Copies a src uuid to a dst uuid based on the byte * order specified. * * Arguments: * Uuid * * Pointer to uuid to copy to. * Uuid * * Pointer to uuid to copy from. * const int * The byte order to use. * * Returns: None * *********************************************************************/ static inline void DCE2_CopyUuid(Uuid *dst_uuid, const Uuid *pkt_uuid, const DceRpcBoFlag byte_order) { dst_uuid->time_low = DceRpcNtohl(&pkt_uuid->time_low, byte_order); dst_uuid->time_mid = DceRpcNtohs(&pkt_uuid->time_mid, byte_order); dst_uuid->time_high_and_version = DceRpcNtohs(&pkt_uuid->time_high_and_version, byte_order); dst_uuid->clock_seq_and_reserved = pkt_uuid->clock_seq_and_reserved; dst_uuid->clock_seq_low = pkt_uuid->clock_seq_low; memcpy(dst_uuid->node, pkt_uuid->node, sizeof(dst_uuid->node)); } #endif /* _DCE2_UTILS_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_utils.c0000644000000000000000000003574612260565732020616 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "dce2_utils.h" #include "dce2_debug.h" #include "dce2_config.h" #include "snort_dce2.h" #include "sf_types.h" #include "snort_bounds.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_Buffer * DCE2_BufferNew(uint32_t initial_size, uint32_t min_add_size, DCE2_MemType mem_type) { DCE2_Buffer *buf = (DCE2_Buffer *)DCE2_Alloc(sizeof(DCE2_Buffer), mem_type); if (buf == NULL) return NULL; if (initial_size != 0) { buf->data = (uint8_t *)DCE2_Alloc(initial_size, mem_type); if (buf->data == NULL) { DCE2_Free((void *)buf, sizeof(DCE2_Buffer), mem_type); return NULL; } } buf->size = initial_size; buf->len = 0; buf->mtype = mem_type; buf->min_add_size = min_add_size; buf->offset = 0; return buf; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_Ret DCE2_BufferAddData(DCE2_Buffer *buf, const uint8_t *data, uint32_t data_len, uint32_t data_offset, DCE2_BufferMinAddFlag mflag) { DCE2_Ret status; if ((buf == NULL) || (data == NULL)) return DCE2_RET__ERROR; /* Return success for this since ultimately nothing _was_ added */ if (data_len == 0) return DCE2_RET__SUCCESS; if (buf->data == NULL) { uint32_t size = data_offset + data_len; if ((size < buf->min_add_size) && (mflag == DCE2_BUFFER_MIN_ADD_FLAG__USE)) size = buf->min_add_size; buf->data = (uint8_t *)DCE2_Alloc(size, buf->mtype); if (buf->data == NULL) return DCE2_RET__ERROR; buf->size = size; } else if ((data_offset + data_len) > buf->size) { uint8_t *tmp; uint32_t new_size = data_offset + data_len; if (((new_size - buf->size) < buf->min_add_size) && (mflag == DCE2_BUFFER_MIN_ADD_FLAG__USE)) new_size = buf->size + buf->min_add_size; tmp = (uint8_t *)DCE2_ReAlloc(buf->data, buf->size, new_size, buf->mtype); if (tmp == NULL) return DCE2_RET__ERROR; buf->data = tmp; buf->size = new_size; } status = DCE2_Memcpy(buf->data + data_offset, data, data_len, buf->data, buf->data + buf->size); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } if ((data_offset + data_len) > buf->len) buf->len = data_offset + data_len; return DCE2_RET__SUCCESS; } /******************************************************************** * Function: * * Must have allocated data in buffer and data_len must fit in * buffer. * * Arguments: * * Returns: * ********************************************************************/ DCE2_Ret DCE2_BufferMoveData(DCE2_Buffer *buf, uint32_t data_offset, const uint8_t *move, uint32_t move_len) { DCE2_Ret status; uint8_t *offset, *end; if ((buf == NULL) || (buf->data == NULL) || (move == NULL)) return DCE2_RET__ERROR; /* Return success for this since ultimately nothing _was_ moved */ if (move_len == 0) return DCE2_RET__SUCCESS; offset = buf->data + data_offset; end = buf->data + buf->len; /* Moved data must be within current data */ if ((move < buf->data) || ((move + move_len) > end)) return DCE2_RET__ERROR; /* No move required */ if (move == offset) return DCE2_RET__SUCCESS; /* Would have to do two moves. One for the data and one to realign data * with start of moved data. Don't want to succeed on the first and fail * on the second and leave the buffer in a bad state. Don't want to use * an offset in data buffer because want to keep the size the same. */ if (move == buf->data) { uint32_t tmp_size = buf->len; uint8_t *tmp = (uint8_t *)DCE2_Alloc(tmp_size, buf->mtype); uint8_t *tmp_offset, *tmp_end; uint32_t new_len; if (tmp == NULL) return DCE2_RET__ERROR; tmp_offset = tmp + data_offset; tmp_end = tmp + tmp_size; status = DCE2_Memcpy(tmp, buf->data, buf->len, tmp, tmp_end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } status = DCE2_Memmove(tmp_offset, tmp, move_len, tmp_offset, tmp_end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } if (tmp_offset > (tmp + move_len)) tmp_offset = tmp + move_len; new_len = tmp_end - tmp_offset; status = DCE2_Memcpy(buf->data, tmp_offset, new_len, buf->data, end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } buf->len = new_len; DCE2_Free((void *)tmp, tmp_size, buf->mtype); } else { status = DCE2_Memmove(offset, move, move_len, offset, end); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer", __FILE__, __LINE__); return DCE2_RET__ERROR; } /* If we have a new end of data, adjust length */ if ((move + move_len) == end) buf->len = data_offset + move_len; } return DCE2_RET__SUCCESS; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_BufferDestroy(DCE2_Buffer *buf) { if (buf == NULL) return; if (buf->data != NULL) DCE2_Free((void *)buf->data, buf->size, buf->mtype); DCE2_Free((void *)buf, sizeof(DCE2_Buffer), buf->mtype); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_Ret DCE2_HandleSegmentation(DCE2_Buffer *seg_buf, const uint8_t *data_ptr, uint16_t data_len, uint32_t need_len, uint16_t *data_used) { uint32_t copy_len; DCE2_Ret status; /* Initialize in case we return early without adding * any data to the buffer */ *data_used = 0; if (seg_buf == NULL) return DCE2_RET__ERROR; /* Don't need anything - call it desegmented. Really return * an error - this shouldn't happen */ if (need_len == 0) return DCE2_RET__ERROR; /* Already have enough data for need */ if (DCE2_BufferLength(seg_buf) >= need_len) return DCE2_RET__SUCCESS; /* No data and need length > 0 - must still be segmented */ if (data_len == 0) return DCE2_RET__SEG; /* Already know that need length is greater than buffer length */ copy_len = need_len - DCE2_BufferLength(seg_buf); if (copy_len > data_len) copy_len = data_len; status = DCE2_BufferAddData(seg_buf, data_ptr, copy_len, DCE2_BufferLength(seg_buf), DCE2_BUFFER_MIN_ADD_FLAG__USE); if (status != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; /* copy_len <= data_len <= UINT16_MAX */ *data_used = (uint16_t)copy_len; if (DCE2_BufferLength(seg_buf) == need_len) return DCE2_RET__SUCCESS; return DCE2_RET__SEG; } /******************************************************************** * Function: DCE2_Die() * * Purpose: Fatal errors. Calls DynamicPreprocessorFatalMessage. * It's just quicker to type. * * Arguments: None * const char * - format string * ... - format arguments * * Returns: None * ********************************************************************/ NORETURN void DCE2_Die(const char *format, ...) { char buf[1024]; va_list ap; DCE2_FreeGlobals(); if (format == NULL) { _dpd.errMsg("ERROR: %s(%d) => %s: format is NULL.\n", __FILE__, __LINE__, DCE2_GNAME); DynamicPreprocessorFatalMessage("%s: Dieing.\n", DCE2_GNAME, buf); } va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); buf[sizeof(buf) - 1] = '\0'; DynamicPreprocessorFatalMessage("%s: %s\n", DCE2_GNAME, buf); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_Log(DCE2_LogType ltype, const char *format, ...) { char buf[1024]; va_list ap; if (format == NULL) { _dpd.errMsg("ERROR: %s(%d) => %s: format is NULL.\n", __FILE__, __LINE__, DCE2_GNAME); return; } va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); buf[sizeof(buf) - 1] = '\0'; switch (ltype) { case DCE2_LOG_TYPE__LOG: _dpd.logMsg("LOG: %s: %s\n", DCE2_GNAME, buf); break; case DCE2_LOG_TYPE__WARN: _dpd.errMsg("WARN: %s: %s\n", DCE2_GNAME, buf); break; case DCE2_LOG_TYPE__ERROR: _dpd.errMsg("ERROR: %s: %s\n", DCE2_GNAME, buf); break; default: _dpd.errMsg("ERROR: %s(%d) => %s: Invalid log type: %d.\n", __FILE__, __LINE__, DCE2_GNAME, ltype); break; } } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ const char * DCE2_UuidToStr(const Uuid *uuid, DceRpcBoFlag byte_order) { #define UUID_BUF_SIZE 50 static char uuid_buf1[UUID_BUF_SIZE]; static char uuid_buf2[UUID_BUF_SIZE]; static int buf_num = 0; char *uuid_buf; if (buf_num == 0) { uuid_buf = uuid_buf1; buf_num = 1; } else { uuid_buf = uuid_buf2; buf_num = 0; } snprintf(uuid_buf, UUID_BUF_SIZE, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", DceRpcHtonl(&uuid->time_low, byte_order), DceRpcHtons(&uuid->time_mid, byte_order), DceRpcHtons(&uuid->time_high_and_version, byte_order), uuid->clock_seq_and_reserved, uuid->clock_seq_low, uuid->node[0], uuid->node[1], uuid->node[2], uuid->node[3], uuid->node[4], uuid->node[5]); uuid_buf[UUID_BUF_SIZE - 1] = '\0'; return uuid_buf; } #ifdef DEBUG_MSGS /******************************************************************** * Function: DCE2_PrintPktData() * * Purpose: Prints packet data in hex and ascii. * * Arguments: None * const uint8_t * - pointer to data to print * const uint16_t - size of data * * Returns: None * ********************************************************************/ void DCE2_PrintPktData(const uint8_t *data, const uint16_t len) { unsigned int i, j = 0, line_len = 0; uint8_t hex_buf[16]; uint8_t char_buf[16]; for (i = 0; i < len; i++) { hex_buf[j] = data[i]; if (isascii((int)data[i]) && isprint((int)data[i])) char_buf[j] = data[i]; else char_buf[j] = '.'; if (line_len == 15) { unsigned int k, sub_line_len = 0; for (k = 0; k <= j; k++) { printf("%02x ", hex_buf[k]); if (sub_line_len >= 7) { printf(" "); sub_line_len = 0; } else { sub_line_len++; } } printf(" "); sub_line_len = 0; for (k = 0; k <= j; k++) { printf("%c", char_buf[k]); if (sub_line_len >= 7) { printf(" "); sub_line_len = 0; } else { sub_line_len++; } } printf("\n"); j = line_len = 0; } else { j++; line_len++; } } if (line_len > 0) { unsigned int k, sub_line_len = 0; for (k = 0; k < j; k++) { printf("%02x ", hex_buf[k]); if (sub_line_len >= 7) { printf(" "); sub_line_len = 0; } else { sub_line_len++; } } if (k < 8) printf(" "); else printf(" "); while (k < 16) { printf(" "); k++; } sub_line_len = 0; for (k = 0; k < j; k++) { printf("%c", char_buf[k]); if (sub_line_len >= 7) { printf(" "); sub_line_len = 0; } else { sub_line_len++; } } } printf("\n"); } #endif snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_debug.h0000644000000000000000000000613612260565732020540 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides macros and functions for debugging the preprocessor. * If Snort is not configured to do debugging, macros are empty. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifndef _DCE2_DEBUG_H_ #define _DCE2_DEBUG_H_ #include /******************************************************************** * Public function prototypes ********************************************************************/ // Use like this: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "msg\n");) void DCE2_DebugMsg(int, const char *, ...); int DCE2_DebugThis(int level); /******************************************************************** * Macros ********************************************************************/ #define DCE2_DEBUG_VARIABLE "DCE2_DEBUG" #define DCE2_DEBUG__NONE 0x00000000 #define DCE2_DEBUG__ROPTIONS 0x00000001 #define DCE2_DEBUG__CONFIG 0x00000002 #define DCE2_DEBUG__MAIN 0x00000004 #define DCE2_DEBUG__SMB 0x00000008 #define DCE2_DEBUG__CO 0x00000010 #define DCE2_DEBUG__EVENT 0x00000020 #define DCE2_DEBUG__MEMORY 0x00000040 #define DCE2_DEBUG__HTTP 0x00000080 #define DCE2_DEBUG__CL 0x00000100 #define DCE2_DEBUG__PAF 0x00000200 #define DCE2_DEBUG__ALL 0xffffffff #define DCE2_DEBUG__START_MSG "DCE/RPC Preprocessor *************************************" #define DCE2_DEBUG__END_MSG "**********************************************************" #define DCE2_DEBUG__PAF_START_MSG "DCE/RPC PAF ==============================================" #define DCE2_DEBUG__PAF_END_MSG "==========================================================" #ifdef DEBUG #include #define DCE2_ASSERT(code) assert(code) #else #define DCE2_ASSERT(code) #endif #ifdef DEBUG_MSGS #define DCE2_DEBUG_VAR(code) code #define DCE2_DEBUG_CODE(level, code) { if (DCE2_DebugThis(level)) { code } } #else #define DCE2_DEBUG_VAR(code) #define DCE2_DEBUG_CODE(level, code) #endif #endif /* _DCE2_DEBUG_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/dce2_debug.c0000644000000000000000000000736412260565732020537 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * Provides functions for debugging the preprocessor. * * 8/17/2008 - Initial implementation ... Todd Wease * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_STDINT_H #include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include "sf_types.h" #include "dce2_debug.h" #include "dce2_utils.h" /******************************************************************** * Function: DCE2_GetDebugLevel() * * Gets the debugging level set by the DCE2 debugging environment * variable on the first call. Subsequent calls will used the * cached value. * * Arguments: None * * Returns: * uint32_t * The debugging level set by the environment variable. * ********************************************************************/ static uint32_t DCE2_GetDebugLevel(void) { static int debug_init = 0; static uint32_t debug_level = 0; const char* value; if (debug_init) return debug_level; value = getenv(DCE2_DEBUG_VARIABLE); if (value != NULL) { char *endptr; debug_level = _dpd.SnortStrtoul(value, &endptr, 0); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Log(DCE2_LOG_TYPE__WARN, "\"%s\" value out of range or not a number: %s. " "Debugging will not be turned on.", DCE2_DEBUG_VARIABLE, value); debug_level = 0; } } debug_init = 1; return debug_level; } /******************************************************************** * Function: DCE2_DebugThis() * * Determines based on the level if debugging is turned on. * * Arguments: * int * The level to check for. * * Returns: * int * 1 if debugging is turned on. * 0 if debugging is not turned on. * ********************************************************************/ int DCE2_DebugThis(int level) { if (level & DCE2_GetDebugLevel()) return 1; return 0; } /******************************************************************** * Function: DCE2_DebugMsg() * * Prints message to stdout if debugging is on for specified level. * * Arguments: * int * The level the message refers to. * const char * * The format string. * ... * The arguments to the format string. * * Returns: None * ********************************************************************/ void DCE2_DebugMsg(int level, const char *format, ...) { va_list ap; if (!DCE2_DebugThis(level)) return; va_start(ap, format); vfprintf(stdout, format, ap); va_end(ap); } snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/Makefile.am0000644000000000000000000000231211746560363020433 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_dce2_preproc.la libsf_dce2_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_dce2_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_dce2_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sf_ip.c \ ../include/sfrt.c \ ../include/sfrt_dir.c \ ../include/sfPolicyUserData.c endif libsf_dce2_preproc_la_SOURCES = \ includes/dcerpc.h \ includes/smb.h \ dce2_debug.c \ dce2_debug.h \ dce2_utils.c \ dce2_utils.h \ dce2_list.c \ dce2_list.h \ dce2_memory.c \ dce2_memory.h \ dce2_stats.c \ dce2_stats.h \ dce2_event.c \ dce2_event.h \ dce2_config.c \ dce2_config.h \ dce2_roptions.c \ dce2_roptions.h \ dce2_session.h \ spp_dce2.c \ spp_dce2.h \ snort_dce2.c \ snort_dce2.h \ dce2_smb.c \ dce2_smb.h \ dce2_tcp.c \ dce2_tcp.h \ dce2_co.c \ dce2_co.h \ dce2_udp.c \ dce2_udp.h \ dce2_cl.c \ dce2_cl.h \ dce2_http.c \ dce2_http.h \ dce2_paf.c \ dce2_paf.h EXTRA_DIST = \ sf_dce2.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/Makefile.in0000644000000000000000000005420712260606521020443 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/dcerpc2 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_dce2_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_dce2_preproc_la_OBJECTS = dce2_debug.lo dce2_utils.lo \ dce2_list.lo dce2_memory.lo dce2_stats.lo dce2_event.lo \ dce2_config.lo dce2_roptions.lo spp_dce2.lo snort_dce2.lo \ dce2_smb.lo dce2_tcp.lo dce2_co.lo dce2_udp.lo dce2_cl.lo \ dce2_http.lo dce2_paf.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_dce2_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo sf_ip.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfrt.lo sfrt_dir.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_dce2_preproc_la_OBJECTS = $(am_libsf_dce2_preproc_la_OBJECTS) \ $(nodist_libsf_dce2_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_dce2_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_dce2_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_dce2_preproc_la_SOURCES) \ $(nodist_libsf_dce2_preproc_la_SOURCES) DIST_SOURCES = $(libsf_dce2_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_dce2_preproc.la libsf_dce2_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_dce2_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_dce2_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_ip.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfrt.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfrt_dir.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_dce2_preproc_la_SOURCES = \ includes/dcerpc.h \ includes/smb.h \ dce2_debug.c \ dce2_debug.h \ dce2_utils.c \ dce2_utils.h \ dce2_list.c \ dce2_list.h \ dce2_memory.c \ dce2_memory.h \ dce2_stats.c \ dce2_stats.h \ dce2_event.c \ dce2_event.h \ dce2_config.c \ dce2_config.h \ dce2_roptions.c \ dce2_roptions.h \ dce2_session.h \ spp_dce2.c \ spp_dce2.h \ snort_dce2.c \ snort_dce2.h \ dce2_smb.c \ dce2_smb.h \ dce2_tcp.c \ dce2_tcp.h \ dce2_co.c \ dce2_co.h \ dce2_udp.c \ dce2_udp.h \ dce2_cl.c \ dce2_cl.h \ dce2_http.c \ dce2_http.h \ dce2_paf.c \ dce2_paf.h EXTRA_DIST = \ sf_dce2.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/dcerpc2/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/dcerpc2/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_dce2_preproc.la: $(libsf_dce2_preproc_la_OBJECTS) $(libsf_dce2_preproc_la_DEPENDENCIES) $(EXTRA_libsf_dce2_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_dce2_preproc_la_LINK) -rpath $(libdir) $(libsf_dce2_preproc_la_OBJECTS) $(libsf_dce2_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sf_ip.lo: ../include/sf_ip.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_ip.lo `test -f '../include/sf_ip.c' || echo '$(srcdir)/'`../include/sf_ip.c sfrt.lo: ../include/sfrt.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfrt.lo `test -f '../include/sfrt.c' || echo '$(srcdir)/'`../include/sfrt.c sfrt_dir.lo: ../include/sfrt_dir.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfrt_dir.lo `test -f '../include/sfrt_dir.c' || echo '$(srcdir)/'`../include/sfrt_dir.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/includes/0000755000000000000000000000000012260606564020263 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/includes/smb.h0000644000000000000000000036324512260565732021153 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef _SMB_H_ #define _SMB_H_ #ifdef HAVE_CONFIG_H #include "config.h" /* For WORDS_BIGENDIAN */ #endif #include "snort_debug.h" /* For inline */ #include "sf_types.h" /******************************************************************** * Macros ********************************************************************/ #define NBSS_SESSION_TYPE__MESSAGE 0x00 #define NBSS_SESSION_TYPE__REQUEST 0x81 #define NBSS_SESSION_TYPE__POS_RESPONSE 0x82 #define NBSS_SESSION_TYPE__NEG_RESPONSE 0x83 #define NBSS_SESSION_TYPE__RETARGET_RESPONSE 0x84 #define NBSS_SESSION_TYPE__KEEP_ALIVE 0x85 // SMB dialects #define SMB_DIALECT_PCLAN10 "PCLAN1.0" // Core Protocol #define SMB_DIALECT_PC_NET_PROG10 "PC NETWORK PROGRAM 1.0" // Core Protocol #define SMB_DIALECT_XENIX11 "xenix1.1" // Xenix Extensions #define SMB_DIALECT_XENIX_CORE "XENIX CORE" // Xenix Extensions #define SMB_DIALECT_MS_NET103 "MICROSOFT NETWORKS 1.03" // CorePlus #define SMB_DIALECT_LANMAN10 "LANMAN1.0" // LAN Manager 1.0 #define SMB_DIALECT_MS_NET30 "MICROSOFT NETWORKS 3.0" // DOS LAN Manager 1.0 #define SMB_DIALECT_WIN_FOR_WKGS31a "Windows for Workgroups 3.1a" // Not documented in MS-CIFS but always used #define SMB_DIALECT_LANMAN12 "LANMAN1.2" // LAN Manager 1.2 #define SMB_DIALECT_DOS_LM12X002 "DOS LM1.2X002" // DOS LAN Manager 2.0 #define SMB_DIALECT_LM12X002 "LM1.2X002" // LAN Manager 2.0 #define SMB_DIALECT_DOS_LANMAN21 "DOS LANMAN2.1" // DOS LAN Manager 2.1 #define SMB_DIALECT_LANMAN21 "LANMAN2.1" // LAN Manager 2.1 #define SMB_DIALECT_SAMBA "Samba" // Some Samba specific thing #define SMB_DIALECT_NT_LANMAN10 "NT LANMAN 1.0" // Only seen with Samba #define SMB_DIALECT_NT_LM_012 "NT LM 0.12" // NT LAN Manager #define SMB_DIALECT_SMB_2002 "SMB 2.002" // SMB 2.002 #define SMB_DIALECT_SMB_212 "SMB 2.???" // SMB 2.1 or 2.2 #define SMB_FLG__TYPE 0x80 #define SMB_TYPE__REQUEST 0 #define SMB_TYPE__RESPONSE 1 #define SMB_FLG2__UNICODE 0x8000 #define SMB_FLG2__NT_CODES 0x4000 #define SMB_NT_STATUS_SEVERITY__SUCCESS 0 #define SMB_NT_STATUS_SEVERITY__INFORMATIONAL 1 #define SMB_NT_STATUS_SEVERITY__WARNING 2 #define SMB_NT_STATUS_SEVERITY__ERROR 3 #define SMB_NT_STATUS__SUCCESS 0x00000000 #define SMB_NT_STATUS__INVALID_DEVICE_REQUEST 0xc0000010 #define SMB_NT_STATUS__RANGE_NOT_LOCKED 0xc000007e #define SMB_NT_STATUS__PIPE_BROKEN 0xc000014b #define SMB_NT_STATUS__PIPE_DISCONNECTED 0xc00000b0 #define SMB_ERROR_CLASS__SUCCESS 0x00 #define SMB_ERROR_CLASS__ERRDOS 0x01 #define SMB_ERROR_CLASS__ERRSRV 0x02 #define SMB_ERROR_CLASS__ERRHRD 0x03 #define SMB_ERROR_CLASS__ERRXOS 0x04 #define SMB_ERROR_CLASS__ERRMX1 0xe1 #define SMB_ERROR_CLASS__ERRMX2 0xe2 #define SMB_ERROR_CLASS__ERRMX3 0xe3 #define SMB_ERROR_CLASS__ERRCMD 0xff #define SMB_ERRSRV__INVALID_DEVICE 0x0007 #define SMB_ERRDOS__NOT_LOCKED 0x009e #define SMB_ERRDOS__BAD_PIPE 0x00e6 #define SMB_ERRDOS__PIPE_NOT_CONNECTED 0x00e9 #define SMB_ERRDOS__MORE_DATA 0x00ea /* SMB formats (smb_fmt) Dialect, Pathname and ASCII are all * NULL terminated ASCII strings unless Unicode is specified * in the NT LM 1.0 SMB header in which case they are NULL * terminated unicode strings */ #define SMB_FMT__DATA_BLOCK 1 #define SMB_FMT__DIALECT 2 #define SMB_FMT__ASCII 4 static inline bool SmbFmtDataBlock(const uint8_t fmt) { return fmt == SMB_FMT__DATA_BLOCK ? true : false; } static inline bool SmbFmtDialect(const uint8_t fmt) { return fmt == SMB_FMT__DIALECT ? true : false; } static inline bool SmbFmtAscii(const uint8_t fmt) { return fmt == SMB_FMT__ASCII ? true : false; } /* SMB command codes */ #define SMB_COM_CREATE_DIRECTORY 0x00 #define SMB_COM_DELETE_DIRECTORY 0x01 #define SMB_COM_OPEN 0x02 #define SMB_COM_CREATE 0x03 #define SMB_COM_CLOSE 0x04 #define SMB_COM_FLUSH 0x05 #define SMB_COM_DELETE 0x06 #define SMB_COM_RENAME 0x07 #define SMB_COM_QUERY_INFORMATION 0x08 #define SMB_COM_SET_INFORMATION 0x09 #define SMB_COM_READ 0x0A #define SMB_COM_WRITE 0x0B #define SMB_COM_LOCK_BYTE_RANGE 0x0C #define SMB_COM_UNLOCK_BYTE_RANGE 0x0D #define SMB_COM_CREATE_TEMPORARY 0x0E #define SMB_COM_CREATE_NEW 0x0F #define SMB_COM_CHECK_DIRECTORY 0x10 #define SMB_COM_PROCESS_EXIT 0x11 #define SMB_COM_SEEK 0x12 #define SMB_COM_LOCK_AND_READ 0x13 #define SMB_COM_WRITE_AND_UNLOCK 0x14 #define SMB_COM_READ_RAW 0x1A #define SMB_COM_READ_MPX 0x1B #define SMB_COM_READ_MPX_SECONDARY 0x1C #define SMB_COM_WRITE_RAW 0x1D #define SMB_COM_WRITE_MPX 0x1E #define SMB_COM_WRITE_MPX_SECONDARY 0x1F #define SMB_COM_WRITE_COMPLETE 0x20 #define SMB_COM_QUERY_SERVER 0x21 #define SMB_COM_SET_INFORMATION2 0x22 #define SMB_COM_QUERY_INFORMATION2 0x23 #define SMB_COM_LOCKING_ANDX 0x24 #define SMB_COM_TRANSACTION 0x25 #define SMB_COM_TRANSACTION_SECONDARY 0x26 #define SMB_COM_IOCTL 0x27 #define SMB_COM_IOCTL_SECONDARY 0x28 #define SMB_COM_COPY 0x29 #define SMB_COM_MOVE 0x2A #define SMB_COM_ECHO 0x2B #define SMB_COM_WRITE_AND_CLOSE 0x2C #define SMB_COM_OPEN_ANDX 0x2D #define SMB_COM_READ_ANDX 0x2E #define SMB_COM_WRITE_ANDX 0x2F #define SMB_COM_NEW_FILE_SIZE 0x30 #define SMB_COM_CLOSE_AND_TREE_DISC 0x31 #define SMB_COM_TRANSACTION2 0x32 #define SMB_COM_TRANSACTION2_SECONDARY 0x33 #define SMB_COM_FIND_CLOSE2 0x34 #define SMB_COM_FIND_NOTIFY_CLOSE 0x35 #define SMB_COM_TREE_CONNECT 0x70 #define SMB_COM_TREE_DISCONNECT 0x71 #define SMB_COM_NEGOTIATE 0x72 #define SMB_COM_SESSION_SETUP_ANDX 0x73 #define SMB_COM_LOGOFF_ANDX 0x74 #define SMB_COM_TREE_CONNECT_ANDX 0x75 #define SMB_COM_SECURITY_PACKAGE_ANDX 0x7E #define SMB_COM_QUERY_INFORMATION_DISK 0x80 #define SMB_COM_SEARCH 0x81 #define SMB_COM_FIND 0x82 #define SMB_COM_FIND_UNIQUE 0x83 #define SMB_COM_FIND_CLOSE 0x84 #define SMB_COM_NT_TRANSACT 0xA0 #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 #define SMB_COM_NT_CREATE_ANDX 0xA2 #define SMB_COM_NT_CANCEL 0xA4 #define SMB_COM_NT_RENAME 0xA5 #define SMB_COM_OPEN_PRINT_FILE 0xC0 #define SMB_COM_WRITE_PRINT_FILE 0xC1 #define SMB_COM_CLOSE_PRINT_FILE 0xC2 #define SMB_COM_GET_PRINT_QUEUE 0xC3 #define SMB_COM_READ_BULK 0xD8 #define SMB_COM_WRITE_BULK 0xD9 #define SMB_COM_WRITE_BULK_DATA 0xDA #define SMB_COM_INVALID 0xFE #define SMB_COM_NO_ANDX_COMMAND 0xFF #define SMB_MAX_NUM_COMS 256 /* Size of word count field + Word count * 2 bytes + Size of byte count field */ #define SMB_COM_SIZE(wct) (sizeof(uint8_t) + ((wct) * sizeof(uint16_t)) + sizeof(uint16_t)) #define SMB_FILE_TYPE_DISK 0x0000 #define SMB_FILE_TYPE_BYTE_MODE_PIPE 0x0001 #define SMB_FILE_TYPE_MESSAGE_MODE_PIPE 0x0002 #define SMB_FILE_TYPE_PRINTER 0x0003 #define SMB_FILE_TYPE_COMMON_DEVICE 0x0004 #define SMB_FILE_ATTRIBUTE_NORMAL 0x0000 #define SMB_FILE_ATTRIBUTE_READONLY 0x0001 #define SMB_FILE_ATTRIBUTE_HIDDEN 0x0002 #define SMB_FILE_ATTRIBUTE_SYSTEM 0x0004 #define SMB_FILE_ATTRIBUTE_VOLUME 0x0008 #define SMB_FILE_ATTRIBUTE_DIRECTORY 0x0010 #define SMB_FILE_ATTRIBUTE_ARCHIVE 0x0020 #define SMB_SEARCH_ATTRIBUTE_READONLY 0x0100 #define SMB_SEARCH_ATTRIBUTE_HIDDEN 0x0200 #define SMB_SEARCH_ATTRIBUTE_SYSTEM 0x0400 #define SMB_SEARCH_ATTRIBUTE_DIRECTORY 0x1000 #define SMB_SEARCH_ATTRIBUTE_ARCHIVE 0x2000 #define SMB_FILE_ATTRIBUTE_OTHER 0xC8C0 // Reserved #define SMB_EXT_FILE_ATTR_READONLY 0x00000001 #define SMB_EXT_FILE_ATTR_HIDDEN 0x00000002 #define SMB_EXT_FILE_ATTR_SYSTEM 0x00000004 #define SMB_EXT_FILE_ATTR_DIRECTORY 0x00000010 #define SMB_EXT_FILE_ATTR_ARCHIVE 0x00000020 #define SMB_EXT_FILE_ATTR_NORMAL 0x00000080 #define SMB_EXT_FILE_ATTR_TEMPORARY 0x00000100 #define SMB_EXT_FILE_ATTR_COMPRESSED 0x00000800 #define SMB_EXT_FILE_POSIX_SEMANTICS 0x01000000 #define SMB_EXT_FILE_BACKUP_SEMANTICS 0x02000000 #define SMB_EXT_FILE_DELETE_ON_CLOSE 0x04000000 #define SMB_EXT_FILE_SEQUENTIAL_SCAN 0x08000000 #define SMB_EXT_FILE_RANDOM_ACCESS 0x10000000 #define SMB_EXT_FILE_NO_BUFFERING 0x20000000 #define SMB_EXT_FILE_WRITE_THROUGH 0x80000000 /******************************************************************** * Enums ********************************************************************/ typedef enum _SmbAndXCom { SMB_ANDX_COM__NONE, SMB_ANDX_COM__OPEN_ANDX, SMB_ANDX_COM__READ_ANDX, SMB_ANDX_COM__WRITE_ANDX, SMB_ANDX_COM__TREE_CONNECT_ANDX, SMB_ANDX_COM__SESSION_SETUP_ANDX, SMB_ANDX_COM__LOGOFF_ANDX, SMB_ANDX_COM__NT_CREATE_ANDX, SMB_ANDX_COM__MAX } SmbAndXCom; typedef enum _SmbTransactionSubcommand { TRANS_UNKNOWN_0000 = 0x0000, TRANS_SET_NMPIPE_STATE = 0x0001, TRANS_UNKNOWN_0002 = 0x0002, TRANS_UNKNOWN_0003 = 0x0003, TRANS_UNKNOWN_0004 = 0x0004, TRANS_UNKNOWN_0005 = 0x0005, TRANS_UNKNOWN_0006 = 0x0006, TRANS_UNKNOWN_0007 = 0x0007, TRANS_UNKNOWN_0008 = 0x0008, TRANS_UNKNOWN_0009 = 0x0009, TRANS_UNKNOWN_000A = 0x000A, TRANS_UNKNOWN_000B = 0x000B, TRANS_UNKNOWN_000C = 0x000C, TRANS_UNKNOWN_000D = 0x000D, TRANS_UNKNOWN_000E = 0x000E, TRANS_UNKNOWN_000F = 0x000F, TRANS_UNKNOWN_0010 = 0x0010, TRANS_RAW_READ_NMPIPE = 0x0011, TRANS_UNKNOWN_0012 = 0x0012, TRANS_UNKNOWN_0013 = 0x0013, TRANS_UNKNOWN_0014 = 0x0014, TRANS_UNKNOWN_0015 = 0x0015, TRANS_UNKNOWN_0016 = 0x0016, TRANS_UNKNOWN_0017 = 0x0017, TRANS_UNKNOWN_0018 = 0x0018, TRANS_UNKNOWN_0019 = 0x0019, TRANS_UNKNOWN_001A = 0x001A, TRANS_UNKNOWN_001B = 0x001B, TRANS_UNKNOWN_001C = 0x001C, TRANS_UNKNOWN_001D = 0x001D, TRANS_UNKNOWN_001E = 0x001E, TRANS_UNKNOWN_001F = 0x001F, TRANS_UNKNOWN_0020 = 0x0020, TRANS_QUERY_NMPIPE_STATE = 0x0021, TRANS_QUERY_NMPIPE_INFO = 0x0022, TRANS_PEEK_NMPIPE = 0x0023, TRANS_UNKNOWN_0024 = 0x0024, TRANS_UNKNOWN_0025 = 0x0025, TRANS_TRANSACT_NMPIPE = 0x0026, TRANS_UNKNOWN_0027 = 0x0027, TRANS_UNKNOWN_0028 = 0x0028, TRANS_UNKNOWN_0029 = 0x0029, TRANS_UNKNOWN_002A = 0x002A, TRANS_UNKNOWN_002B = 0x002B, TRANS_UNKNOWN_002C = 0x002C, TRANS_UNKNOWN_002D = 0x002D, TRANS_UNKNOWN_002E = 0x002E, TRANS_UNKNOWN_002F = 0x002F, TRANS_UNKNOWN_0030 = 0x0030, TRANS_RAW_WRITE_NMPIPE = 0x0031, TRANS_UNKNOWN_0032 = 0x0032, TRANS_UNKNOWN_0033 = 0x0033, TRANS_UNKNOWN_0034 = 0x0034, TRANS_UNKNOWN_0035 = 0x0035, TRANS_READ_NMPIPE = 0x0036, TRANS_WRITE_NMPIPE = 0x0037, TRANS_UNKNOWN_0038 = 0x0038, TRANS_UNKNOWN_0039 = 0x0039, TRANS_UNKNOWN_003A = 0x003A, TRANS_UNKNOWN_003B = 0x003B, TRANS_UNKNOWN_003C = 0x003C, TRANS_UNKNOWN_003D = 0x003D, TRANS_UNKNOWN_003E = 0x003E, TRANS_UNKNOWN_003F = 0x003F, TRANS_UNKNOWN_0040 = 0x0040, TRANS_UNKNOWN_0041 = 0x0041, TRANS_UNKNOWN_0042 = 0x0042, TRANS_UNKNOWN_0043 = 0x0043, TRANS_UNKNOWN_0044 = 0x0044, TRANS_UNKNOWN_0045 = 0x0045, TRANS_UNKNOWN_0046 = 0x0046, TRANS_UNKNOWN_0047 = 0x0047, TRANS_UNKNOWN_0048 = 0x0048, TRANS_UNKNOWN_0049 = 0x0049, TRANS_UNKNOWN_004A = 0x004A, TRANS_UNKNOWN_004B = 0x004B, TRANS_UNKNOWN_004C = 0x004C, TRANS_UNKNOWN_004D = 0x004D, TRANS_UNKNOWN_004E = 0x004E, TRANS_UNKNOWN_004F = 0x004F, TRANS_UNKNOWN_0050 = 0x0050, TRANS_UNKNOWN_0051 = 0x0051, TRANS_UNKNOWN_0052 = 0x0052, TRANS_WAIT_NMPIPE = 0x0053, TRANS_CALL_NMPIPE = 0x0054, TRANS_SUBCOM_MAX = 0x0055 } SmbTransactionSubcommand; typedef enum _SmbTransaction2Subcommand { TRANS2_OPEN2 = 0x0000, TRANS2_FIND_FIRST2 = 0x0001, TRANS2_FIND_NEXT2 = 0x0002, TRANS2_QUERY_FS_INFORMATION = 0x0003, TRANS2_SET_FS_INFORMATION = 0x0004, TRANS2_QUERY_PATH_INFORMATION = 0x0005, TRANS2_SET_PATH_INFORMATION = 0x0006, TRANS2_QUERY_FILE_INFORMATION = 0x0007, TRANS2_SET_FILE_INFORMATION = 0x0008, TRANS2_FSCTL = 0x0009, TRANS2_IOCTL2 = 0x000A, TRANS2_FIND_NOTIFY_FIRST = 0x000B, TRANS2_FIND_NOTIFY_NEXT = 0x000C, TRANS2_CREATE_DIRECTORY = 0x000D, TRANS2_SESSION_SETUP = 0x000E, TRANS2_UNKNOWN_000F = 0x000F, TRANS2_GET_DFS_REFERRAL = 0x0010, TRANS2_REPORT_DFS_INCONSISTENCY = 0x0011, TRANS2_SUBCOM_MAX = 0x0012 } SmbTransaction2Subcommand; typedef enum _SmbNtTransactSubcommand { NT_TRANSACT_UNKNOWN_0000 = 0x0000, NT_TRANSACT_CREATE = 0x0001, NT_TRANSACT_IOCTL = 0x0002, NT_TRANSACT_SET_SECURITY_DESC = 0x0003, NT_TRANSACT_NOTIFY_CHANGE = 0x0004, NT_TRANSACT_RENAME = 0x0005, NT_TRANSACT_QUERY_SECURITY_DESC = 0x0006, NT_TRANSACT_SUBCOM_MAX = 0x0007 } SmbNtTransactSubcommand; /******************************************************************** * Structures and inline accessor functions ********************************************************************/ /* Pack the structs since we'll be laying them on top of packet data */ #ifdef WIN32 #pragma pack(push,smb_hdrs,1) #else #pragma pack(1) #endif /******************************************************************** * NetBIOS Session Service header ********************************************************************/ typedef struct _NbssHdr { uint8_t type; uint8_t flags; /* Treat flags as the upper byte to length */ uint16_t length; } NbssHdr; static inline uint32_t NbssLen(const NbssHdr *nb) { /* Treat first bit of flags as the upper byte to length */ return ((nb->flags & 0x01) << 16) | ntohs(nb->length); } static inline uint8_t NbssType(const NbssHdr *nb) { return nb->type; } /******************************************************************** * SMB headers * * Length of header is always 32 but meaning of fields differs * according to dialect ********************************************************************/ typedef struct _SmbCoreHdr { uint8_t smb_idf[4]; /* contains 0xFF, 'SMB' */ uint8_t smb_com; /* command code */ uint8_t smb_rcls; /* error code class */ uint8_t smb_reh; /* reserved (contains AH if DOS INT-24 ERR) */ uint16_t smb_err; /* error code */ uint8_t smb_reb; /* reserved */ uint16_t smb_res[7]; /* reserved */ uint16_t smb_tid; /* tree id # */ uint16_t smb_pid; /* caller's process id # */ uint16_t smb_uid; /* user id # */ uint16_t smb_mid; /* multiplex id # */ #if 0 uint8_t smb_wct; /* count of parameter words */ uint16_t smb_vwv[]; /* variable # words of params */ uint16_t smb_bcc; /* # bytes of data following */ uint8_t smb_data[]; /* data bytes */ #endif } SmbCoreHdr; typedef struct _SmbLm10Hdr { uint8_t smb_idf[4]; /* contains 0xFF, 'SMB' */ uint8_t smb_com; /* command code */ uint8_t smb_rcls; /* error class */ uint8_t smb_reh; /* reserved for future */ uint16_t smb_err; /* error code */ uint8_t smb_flg; /* flags */ uint16_t smb_res[7]; /* reserved for future */ uint16_t smb_tid; /* authenticated resource identifier */ uint16_t smb_pid; /* caller's process id */ uint16_t smb_uid; /* unauthenticated user id */ uint16_t smb_mid; /* multiplex id */ #if 0 uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_vwv[]; /* variable number of 16-bit words */ uint16_t smb_bcc; /* count of bytes that follow */ uint8_t smb_buf[]; /* variable number of bytes */ #endif } SmbLm10Hdr; typedef struct _SmbLm20Hdr { uint8_t smb_idf[4]; /* contains 0xFF,’SMB’ */ uint8_t smb_com; /* command code */ uint8_t smb_rcls; /* error class */ uint8_t smb_reh; /* reserved for future */ uint16_t smb_err; /* error code */ uint8_t smb_flg; /* flags */ uint16_t smb_flg2; /* flags */ uint16_t smb_res[6]; /* reserved for future */ uint16_t smb_tid; /* authenticated resource identifier */ uint16_t smb_pid; /* caller’s process id */ uint16_t smb_uid; /* authenticated user id */ uint16_t smb_mid; /* multiplex id */ #if 0 uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_vwv[]; /* variable number of 16-bit words */ uint16_t smb_bcc; /* count of bytes that follow */ uint8_t smb_buf[]; /* variable number of bytes */ #endif } SmbLm20Hdr; typedef struct _SmbNtHdr { uint8_t smb_idf[4]; /* contains 0xFF, 'SMB' */ uint8_t smb_com; /* command code */ union { struct { uint8_t smb_class; /* dos error class */ uint8_t smb_res; /* reserved for future */ uint16_t smb_code; /* dos error code */ } smb_status; uint32_t nt_status; /* nt status */ } smb_status; uint8_t smb_flg; /* flags */ uint16_t smb_flg2; /* flags */ uint16_t smb_pid_high; uint64_t smb_signature; uint16_t smb_res; /* reserved for future */ uint16_t smb_tid; /* tree id */ uint16_t smb_pid; /* caller's process id */ uint16_t smb_uid; /* authenticated user id */ uint16_t smb_mid; /* multiplex id */ #if 0 uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_vwv[]; /* variable number of 16-bit words */ uint16_t smb_bcc; /* count of bytes that follow */ uint8_t smb_buf[]; /* variable number of bytes */ #endif } SmbNtHdr; static inline uint16_t SmbNtohs(const uint16_t *ptr) { uint16_t value; if (ptr == NULL) return 0; #ifdef WORDS_MUSTALIGN value = *((uint8_t *)ptr) << 8 | *((uint8_t *)ptr + 1); #else value = *ptr; #endif /* WORDS_MUSTALIGN */ #ifdef WORDS_BIGENDIAN return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8); #else return value; #endif /* WORDS_BIGENDIAN */ } static inline uint16_t SmbHtons(const uint16_t *ptr) { return SmbNtohs(ptr); } static inline uint32_t SmbNtohl(const uint32_t *ptr) { uint32_t value; if (ptr == NULL) return 0; #ifdef WORDS_MUSTALIGN value = *((uint8_t *)ptr) << 24 | *((uint8_t *)ptr + 1) << 16 | *((uint8_t *)ptr + 2) << 8 | *((uint8_t *)ptr + 3); #else value = *ptr; #endif /* WORDS_MUSTALIGN */ #ifdef WORDS_BIGENDIAN return ((value & 0xff000000) >> 24) | ((value & 0x00ff0000) >> 8) | ((value & 0x0000ff00) << 8) | ((value & 0x000000ff) << 24); #else return value; #endif /* WORDS_BIGENDIAN */ } static inline uint32_t SmbHtonl(const uint32_t *ptr) { return SmbNtohl(ptr); } static inline uint64_t SmbNtohq(const uint64_t *ptr) { uint64_t value; if (ptr == NULL) return 0; #ifdef WORDS_MUSTALIGN value = *((uint8_t *)ptr) << 56 | *((uint8_t *)ptr + 1) << 48 | *((uint8_t *)ptr + 2) << 40 | *((uint8_t *)ptr + 3) << 32 | *((uint8_t *)ptr + 4) << 24 | *((uint8_t *)ptr + 5) << 16 | *((uint8_t *)ptr + 6) << 8 | *((uint8_t *)ptr + 7); #else value = *ptr; #endif /* WORDS_MUSTALIGN */ #ifdef WORDS_BIGENDIAN return ((value & 0xff00000000000000) >> 56) | ((value & 0x00ff000000000000) >> 40) | ((value & 0x0000ff0000000000) >> 24) | ((value & 0x000000ff00000000) >> 8) | ((value & 0x00000000ff000000) << 8) | ((value & 0x0000000000ff0000) << 24) | ((value & 0x000000000000ff00) << 40) | ((value & 0x00000000000000ff) << 56); #else return value; #endif /* WORDS_BIGENDIAN */ } static inline uint64_t SmbHtonq(const uint64_t *ptr) { return SmbNtohq(ptr); } static inline uint32_t SmbId(const SmbNtHdr *hdr) { #ifdef WORDS_MUSTALIGN uint8_t *idf = (uint8_t *)hdr->smb_idf; return *idf << 24 | *(idf + 1) << 16 | *(idf + 2) << 8 | *(idf + 3); #else return ntohl(*((uint32_t *)hdr->smb_idf)); #endif /* WORDS_MUSTALIGN */ } static inline uint8_t SmbCom(const SmbNtHdr *hdr) { return hdr->smb_com; } #if 0 // So no compiler warning for being unused // Refers to older pre-NT status codes static bool SmbStatusSmbCodes(const SmbNtHdr *hdr) { if (SmbNtohs(&hdr->smb_flg2) & SMB_FLG2__NT_CODES) return false; return true; } #endif static bool SmbStatusNtCodes(const SmbNtHdr *hdr) { if (SmbNtohs(&hdr->smb_flg2) & SMB_FLG2__NT_CODES) return true; return false; } static inline uint32_t SmbNtStatus(const SmbNtHdr *hdr) { return SmbNtohl(&hdr->smb_status.nt_status); } static inline uint8_t SmbNtStatusSeverity(const SmbNtHdr *hdr) { return (uint8_t)(SmbNtStatus(hdr) >> 30); } static inline uint8_t SmbStatusClass(const SmbNtHdr *hdr) { return hdr->smb_status.smb_status.smb_class; } static inline uint16_t SmbStatusCode(const SmbNtHdr *hdr) { return SmbNtohs(&hdr->smb_status.smb_status.smb_code); } // This function is obviously deficient. Need to do a lot more // testing, research and reading MS-CIFS, MS-SMB and MS-ERREF. static inline bool SmbError(const SmbNtHdr *hdr) { if (SmbStatusNtCodes(hdr)) { /* Nt status codes are being used. First 2 bits indicate * severity. */ switch (SmbNtStatusSeverity(hdr)) { case SMB_NT_STATUS_SEVERITY__SUCCESS: case SMB_NT_STATUS_SEVERITY__INFORMATIONAL: case SMB_NT_STATUS_SEVERITY__WARNING: return false; case SMB_NT_STATUS_SEVERITY__ERROR: default: break; } } else { switch (SmbStatusClass(hdr)) { case SMB_ERROR_CLASS__SUCCESS: return false; case SMB_ERROR_CLASS__ERRDOS: if (SmbStatusCode(hdr) == SMB_ERRDOS__MORE_DATA) return false; break; case SMB_ERROR_CLASS__ERRSRV: case SMB_ERROR_CLASS__ERRHRD: case SMB_ERROR_CLASS__ERRCMD: default: break; } } return true; } static inline bool SmbBrokenPipe(const SmbNtHdr *hdr) { if (SmbStatusNtCodes(hdr)) { uint32_t nt_status = SmbNtStatus(hdr); if ((nt_status == SMB_NT_STATUS__PIPE_BROKEN) || (nt_status == SMB_NT_STATUS__PIPE_DISCONNECTED)) return true; } else { if (SmbStatusClass(hdr) == SMB_ERROR_CLASS__ERRDOS) { uint16_t smb_status = SmbStatusCode(hdr); if ((smb_status == SMB_ERRDOS__BAD_PIPE) || (smb_status == SMB_ERRDOS__PIPE_NOT_CONNECTED)) return true; } } return false; } static inline bool SmbErrorInvalidDeviceRequest(const SmbNtHdr *hdr) { if (SmbStatusNtCodes(hdr)) { if (SmbNtStatus(hdr) == SMB_NT_STATUS__INVALID_DEVICE_REQUEST) return true; } else { if ((SmbStatusClass(hdr) == SMB_ERROR_CLASS__ERRSRV) && (SmbStatusCode(hdr) == SMB_ERRSRV__INVALID_DEVICE)) return true; } return false; } static inline bool SmbErrorRangeNotLocked(const SmbNtHdr *hdr) { if (SmbStatusNtCodes(hdr)) { if (SmbNtStatus(hdr) == SMB_NT_STATUS__RANGE_NOT_LOCKED) return true; } else { if ((SmbStatusClass(hdr) == SMB_ERROR_CLASS__ERRDOS) && (SmbStatusCode(hdr) == SMB_ERRDOS__NOT_LOCKED)) return true; } return false; } static inline int SmbType(const SmbNtHdr *hdr) { if (hdr->smb_flg & SMB_FLG__TYPE) return SMB_TYPE__RESPONSE; return SMB_TYPE__REQUEST; } static inline bool SmbUnicode(const SmbNtHdr *hdr) { return (SmbNtohs(&hdr->smb_flg2) & SMB_FLG2__UNICODE) ? true : false; } static inline uint16_t SmbUid(const SmbNtHdr *hdr) { return SmbNtohs(&hdr->smb_uid); } static inline uint16_t SmbTid(const SmbNtHdr *hdr) { return SmbNtohs(&hdr->smb_tid); } // PidHigh doesn't seem to matter ever static inline uint16_t SmbPid(const SmbNtHdr *hdr) { return SmbNtohs(&hdr->smb_pid); } static inline uint16_t SmbMid(const SmbNtHdr *hdr) { return SmbNtohs(&hdr->smb_mid); } /******************************************************************** * Common fields to all commands ********************************************************************/ typedef struct _SmbCommon { uint8_t smb_wct; } SmbCommon; static inline uint8_t SmbWct(const SmbCommon *hdr) { return hdr->smb_wct; } /* Common fields to all AndX commands */ typedef struct _SmbAndXCommon { uint8_t smb_wct; uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ } SmbAndXCommon; static inline uint8_t SmbAndXCom2(const SmbAndXCommon *andx) { return andx->smb_com2; } static inline uint16_t SmbAndXOff2(const SmbAndXCommon *andx) { return SmbNtohs(&andx->smb_off2); } /* For server empty respones indicating client error or interim response */ typedef struct _SmbEmptyCom { uint8_t smb_wct; /* value = 0 */ uint16_t smb_bcc; /* value = 0 */ } SmbEmptyCom; static inline uint8_t SmbEmptyComWct(const SmbEmptyCom *ec) { return ec->smb_wct; } static inline uint16_t SmbEmptyComBcc(const SmbEmptyCom *ec) { return SmbNtohs(&ec->smb_bcc); } static inline uint16_t SmbBcc(const uint8_t *ptr, uint16_t com_size) { /* com_size must be at least the size of the command encasing */ if (com_size < sizeof(SmbEmptyCom)) return 0; return SmbNtohs((uint16_t *)(ptr + com_size - sizeof(uint16_t))); } /******************************************************************** * SMB_COM_OPEN ********************************************************************/ typedef struct _SmbOpenReq /* smb_wct = 2 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_mode; /* r/w/share */ uint16_t smb_attr; /* attribute */ uint16_t smb_bcc; /* min = 2 */ #if 0 uint8_t smb_fmt; /* ASCII -- 04 */ uint8_t smb_buf[]; /* file pathname */ #endif } SmbOpenReq; typedef struct _SmbOpenResp /* smb_wct = 7 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; /* file handle */ uint16_t smb_attr; /* attribute */ uint32_t smb_time; /* time1 low */ uint32_t smb_file_size; /* file size low */ uint16_t smb_access; /* access allowed */ uint16_t smb_bcc; /* must be 0 */ } SmbOpenResp; #define SMB_OPEN_ACCESS_MODE__READ 0x0000 #define SMB_OPEN_ACCESS_MODE__WRITE 0x0001 #define SMB_OPEN_ACCESS_MODE__READ_WRITE 0x0002 #define SMB_OPEN_ACCESS_MODE__EXECUTE 0x0003 static inline uint16_t SmbOpenRespFid(const SmbOpenResp *resp) { return SmbNtohs(&resp->smb_fid); } static inline uint32_t SmbOpenRespFileSize(const SmbOpenResp *resp) { return SmbNtohl(&resp->smb_file_size); } static inline uint16_t SmbOpenRespFileAttrs(const SmbOpenResp *resp) { return SmbNtohs(&resp->smb_attr); } static inline bool SmbFileAttrsDirectory(const uint16_t file_attrs) { if (file_attrs & SMB_FILE_ATTRIBUTE_DIRECTORY) return true; return false; } static inline uint16_t SmbOpenRespAccessMode(const SmbOpenResp *resp) { return SmbNtohs(&resp->smb_access); } static inline bool SmbOpenForWriting(const uint16_t access_mode) { return access_mode == SMB_OPEN_ACCESS_MODE__WRITE; } /******************************************************************** * SMB_COM_CREATE ********************************************************************/ typedef struct _SmbCreateReq /* smb_wct = 3 */ { uint8_t smb_wct; uint16_t smb_file_attrs; uint32_t smb_creation_time; uint16_t smb_bcc; #if 0 uint8_t smb_fmt; /* ASCII -- 04 */ uint8_t smb_buf[]; /* file pathname */ #endif } SmbCreateReq; typedef struct _SmbCreateResp /* smb_wct = 1 */ { uint8_t smb_wct; uint16_t smb_fid; uint16_t smb_bcc; } SmbCreateResp; static inline uint16_t SmbCreateReqFileAttrs(const SmbCreateReq *req) { return SmbNtohs(&req->smb_file_attrs); } static inline bool SmbAttrDirectory(const uint16_t file_attrs) { if (file_attrs & SMB_FILE_ATTRIBUTE_DIRECTORY) return true; return false; } static inline bool SmbAttrHidden(const uint16_t file_attrs) { if (file_attrs & SMB_FILE_ATTRIBUTE_HIDDEN) return true; return false; } static inline bool SmbAttrSystem(const uint16_t file_attrs) { if (file_attrs & SMB_FILE_ATTRIBUTE_SYSTEM) return true; return false; } static inline uint16_t SmbCreateRespFid(const SmbCreateResp *resp) { return SmbNtohs(&resp->smb_fid); } /******************************************************************** * SMB_COM_CLOSE ********************************************************************/ typedef struct _SmbCloseReq /* smb_wct = 3 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; /* file handle */ uint16_t smb_tlow; /* time low */ uint16_t smb_thigh; /* time high */ uint16_t smb_bcc; /* must be 0 */ } SmbCloseReq; typedef struct _SmbCloseResp /* smb_wct = 0 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_bcc; /* must be 0 */ } SmbCloseResp; static inline uint16_t SmbCloseReqFid(const SmbCloseReq *req) { return SmbNtohs(&req->smb_fid); } /******************************************************************** * SMB_COM_DELETE ********************************************************************/ typedef struct _SmbDeleteReq /* smb_wct = 1 */ { uint8_t smb_wct; uint16_t smb_search_attrs; uint16_t smb_bcc; #if 0 uint8_t smb_fmt; /* ASCII -- 04 */ uint8_t smb_buf[]; /* filename */ #endif } SmbDeleteReq; typedef struct _SmbDeleteResp /* smb_wct = 0 */ { uint8_t smb_wct; uint16_t smb_bcc; } SmbDeleteResp; /******************************************************************** * SMB_COM_RENAME ********************************************************************/ typedef struct _SmbRenameReq /* smb_wct = 1 */ { uint8_t smb_wct; uint16_t smb_attrs; uint16_t smb_bcc; #if 0 uint8_t smb_fmt; /* ASCII -- 04 */ uint8_t smb_buf[]; /* old filename */ uint8_t smb_fmt2; /* ASCII -- 04 */ uint8_t smb_buf2[]; /* new filename */ #endif } SmbRenameReq; typedef struct _SmbRenameResp /* smb_wct = 0 */ { uint8_t smb_wct; uint16_t smb_bcc; } SmbRenameResp; /******************************************************************** * SMB_COM_READ ********************************************************************/ typedef struct _SmbReadReq /* smb_wct = 5 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; /* file handle */ uint16_t smb_cnt; /* count of bytes */ uint32_t smb_off; /* offset */ uint16_t smb_left; /* count left */ uint16_t smb_bcc; /* must be 0 */ } SmbReadReq; typedef struct _SmbReadResp /* smb_wct = 5 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_cnt; /* count */ uint16_t smb_res[4]; /* reserved (MBZ) */ uint16_t smb_bcc; /* length of data + 3 */ #if 0 uint8_t smb_fmt; /* Data Block -- 01 */ uint16_t smb_dlen; /* length of data */ uint8_t smb_buf[]; /* data */ #endif } SmbReadResp; static inline uint16_t SmbReadReqFid(const SmbReadReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint32_t SmbReadReqOffset(const SmbReadReq *req) { return SmbNtohl(&req->smb_off); } static inline uint16_t SmbReadRespCount(const SmbReadResp *resp) { return SmbNtohs(&resp->smb_cnt); } /******************************************************************** * SMB_COM_WRITE ********************************************************************/ typedef struct _SmbWriteReq /* smb_wct = 5 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; /* file handle */ uint16_t smb_cnt; /* count of bytes */ uint32_t smb_offset; /* file offset in bytes */ uint16_t smb_left; /* count left */ uint16_t smb_bcc; /* length of data + 3 */ #if 0 uint16_t smb_fmt; /* Data Block -- 01 */ uint16_t smb_dlen; /* length of data */ uint8_t smb_buf[]; /* data */ #endif } SmbWriteReq; typedef struct _SmbWriteResp /* smb_wct = 1 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_cnt; /* count */ uint16_t smb_bcc; /* must be 0 */ } SmbWriteResp; static inline uint16_t SmbWriteReqFid(const SmbWriteReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint16_t SmbWriteReqCount(const SmbWriteReq *req) { return SmbNtohs(&req->smb_cnt); } static inline uint32_t SmbWriteReqOffset(const SmbWriteReq *req) { return SmbNtohl(&req->smb_offset); } static inline uint16_t SmbWriteRespCount(const SmbWriteResp *resp) { return SmbNtohs(&resp->smb_cnt); } /******************************************************************** * SMB_COM_CREATE_NEW ********************************************************************/ typedef struct _SmbCreateNewReq /* smb_wct = 3 */ { uint8_t smb_wct; uint16_t smb_file_attrs; uint32_t smb_creation_time; uint16_t smb_bcc; #if 0 uint8_t smb_fmt; /* ASCII -- 04 */ uint8_t smb_buf[]; /* file pathname */ #endif } SmbCreateNewReq; typedef struct _SmbCreateNewResp /* smb_wct = 1 */ { uint8_t smb_wct; uint16_t smb_fid; uint16_t smb_bcc; } SmbCreateNewResp; static inline uint16_t SmbCreateNewReqFileAttrs(const SmbCreateNewReq *req) { return SmbNtohs(&req->smb_file_attrs); } static inline uint16_t SmbCreateNewRespFid(const SmbCreateNewResp *resp) { return SmbNtohs(&resp->smb_fid); } /******************************************************************** * SMB_COM_LOCK_AND_READ ********************************************************************/ typedef struct _SmbLockAndReadReq /* smb_wct = 5 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; uint16_t smb_cnt; uint32_t smb_read_offset; uint16_t smb_remaining; uint16_t smb_bcc; /* must be 0 */ } SmbLockAndReadReq; typedef struct _SmbLockAndReadResp /* smb_wct = 5 */ { uint8_t smb_wct; uint16_t smb_cnt; uint16_t reserved[4]; uint16_t smb_bcc; #if 0 uint16_t smb_fmt; /* Data Block -- 01 */ uint16_t smb_dlen; /* length of data */ uint8_t smb_buf[]; /* data */ #endif } SmbLockAndReadResp; static inline uint16_t SmbLockAndReadReqFid(const SmbLockAndReadReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint32_t SmbLockAndReadReqOffset(const SmbLockAndReadReq *req) { return SmbNtohl(&req->smb_read_offset); } static inline uint16_t SmbLockAndReadRespCount(const SmbLockAndReadResp *resp) { return SmbNtohs(&resp->smb_cnt); } /******************************************************************** * SMB_COM_WRITE_AND_UNLOCK ********************************************************************/ typedef struct _SmbWriteAndUnlockReq { uint8_t smb_wct; uint16_t smb_fid; uint16_t smb_cnt; uint32_t smb_write_offset; uint16_t smb_estimate_of_remaining; uint16_t smb_bcc; #if 0 uint16_t smb_fmt; /* Data Block -- 01 */ uint16_t smb_dlen; /* length of data */ uint8_t smb_buf[]; /* data */ #endif } SmbWriteAndUnlockReq; typedef struct _SmbWriteAndUnlockResp /* smb_wct = 1 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_cnt; /* count */ uint16_t smb_bcc; /* must be 0 */ } SmbWriteAndUnlockResp; static inline uint16_t SmbWriteAndUnlockReqFid(const SmbWriteAndUnlockReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint16_t SmbWriteAndUnlockReqCount(const SmbWriteAndUnlockReq *req) { return SmbNtohs(&req->smb_cnt); } static inline uint32_t SmbWriteAndUnlockReqOffset(const SmbWriteAndUnlockReq *req) { return SmbNtohl(&req->smb_write_offset); } /******************************************************************** * SMB_COM_READ_RAW ********************************************************************/ typedef struct _SmbReadRawReq /* smb_wct = 8 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; /* file handle */ uint32_t smb_offset; /* offset in file to begin read */ uint16_t smb_maxcnt; /* max number of bytes to return (max 65,535) */ uint16_t smb_mincnt; /* min number of bytes to return (normally 0) */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_rsvd; /* reserved */ uint16_t smb_bcc; /* value = 0 */ } SmbReadRawReq; typedef struct _SmbReadRawExtReq /* smb_wct = 10 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; /* file handle */ uint32_t smb_offset; /* offset in file to begin read */ uint16_t smb_maxcnt; /* max number of bytes to return (max 65,535) */ uint16_t smb_mincnt; /* min number of bytes to return (normally 0) */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_rsvd; /* reserved */ uint32_t smb_off_high; /* high offset in file to begin write */ uint16_t smb_bcc; /* value = 0 */ } SmbReadRawExtReq; /* Read Raw response is raw data wrapped in NetBIOS header */ static inline uint16_t SmbReadRawReqFid(const SmbReadRawReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint64_t SmbReadRawReqOffset(const SmbReadRawExtReq *req) { if (req->smb_wct == 8) return (uint64_t)SmbNtohl(&req->smb_offset); return (uint64_t)SmbNtohl(&req->smb_off_high) << 32 | (uint64_t)SmbNtohl(&req->smb_offset); } /******************************************************************** * SMB_COM_WRITE_RAW ********************************************************************/ typedef struct _SmbWriteRawReq { uint8_t smb_wct; /* value = 12 */ uint16_t smb_fid; /* file handle */ uint16_t smb_tcount; /* total bytes (including this buf, 65,535 max ) */ uint16_t smb_rsvd; /* reserved */ uint32_t smb_offset; /* offset in file to begin write */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_wmode; /* write mode: bit0 - complete write to disk and send final result response bit1 - return smb_remaining (pipes/devices only) */ uint32_t smb_rsvd2; /* reserved */ uint16_t smb_dsize; /* number of data bytes this buffer (min value = 0) */ uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ uint16_t smb_bcc; /* total bytes (including pad bytes) following */ #if 0 uint8_t smb_pad[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_data[*]; /* data bytes (* = value of smb_dsize) */ #endif } SmbWriteRawReq; typedef struct _SmbWriteRawExtReq { uint8_t smb_wct; /* value = 14 */ uint16_t smb_fid; /* file handle */ uint16_t smb_tcount; /* total bytes (including this buf, 65,535 max ) */ uint16_t smb_rsvd; /* reserved */ uint32_t smb_offset; /* offset in file to begin write */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_wmode; /* write mode: bit0 - complete write to disk and send final result response bit1 - return smb_remaining (pipes/devices only) */ uint32_t smb_rsvd2; /* reserved */ uint16_t smb_dsize; /* number of data bytes this buffer (min value = 0) */ uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ uint32_t smb_off_high; /* high offset in file to begin write */ uint16_t smb_bcc; /* total bytes (including pad bytes) following */ #if 0 uint8_t smb_pad[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_data[*]; /* data bytes (* = value of smb_dsize) */ #endif } SmbWriteRawExtReq; typedef struct _SmbWriteRawInterimResp { uint8_t smb_wct; /* value = 1 */ uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ uint16_t smb_bcc; /* value = 0 */ } SmbWriteRawInterimResp; static inline uint16_t SmbWriteRawReqTotalCount(const SmbWriteRawReq *req) { return SmbNtohs(&req->smb_tcount); } static inline bool SmbWriteRawReqWriteThrough(const SmbWriteRawReq *req) { return SmbNtohs(&req->smb_wmode) & 0x0001; } static inline uint16_t SmbWriteRawReqFid(const SmbWriteRawReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint16_t SmbWriteRawReqDataOff(const SmbWriteRawReq *req) { return SmbNtohs(&req->smb_doff); } static inline uint16_t SmbWriteRawReqDataCnt(const SmbWriteRawReq *req) { return SmbNtohs(&req->smb_dsize); } static inline uint64_t SmbWriteRawReqOffset(const SmbWriteRawExtReq *req) { if (req->smb_wct == 12) return (uint64_t)SmbNtohl(&req->smb_offset); return (uint64_t)SmbNtohl(&req->smb_off_high) << 32 | (uint64_t)SmbNtohl(&req->smb_offset); } static inline uint16_t SmbWriteRawInterimRespRemaining(const SmbWriteRawInterimResp *resp) { return SmbNtohs(&resp->smb_remaining); } /******************************************************************** * SMB_COM_WRITE_COMPLETE - final response to an SMB_COM_WRITE_RAW ********************************************************************/ typedef struct _SmbWriteCompleteResp { uint8_t smb_wct; /* value = 1 */ uint16_t smb_count; /* total number of bytes written */ uint16_t smb_bcc; /* value = 0 */ } SmbWriteCompleteResp; static inline uint16_t SmbWriteCompleteRespCount(const SmbWriteCompleteResp *resp) { return SmbNtohs(&resp->smb_count); } /******************************************************************** * SMB_COM_TRANSACTION ********************************************************************/ typedef struct _SmbTransactionReq /* smb_wct = 14 + value of smb_suwcnt */ { /* Note all subcommands use a setup count of 2 */ uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_tpscnt; /* total number of parameter bytes being sent */ uint16_t smb_tdscnt; /* total number of data bytes being sent */ uint16_t smb_mprcnt; /* max number of parameter bytes to return */ uint16_t smb_mdrcnt; /* max number of data bytes to return */ uint8_t smb_msrcnt; /* max number of setup words to return */ uint8_t smb_rsvd; /* reserved (pad above to word) */ uint16_t smb_flags; /* additional information: bit 0 - if set, also disconnect TID in smb_tid bit 1 - if set, transaction is one way (no final response) */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_rsvd1; /* reserved */ uint16_t smb_pscnt; /* number of parameter bytes being sent this buffer */ uint16_t smb_psoff; /* offset (from start of SMB hdr) to parameter bytes */ uint16_t smb_dscnt; /* number of data bytes being sent this buffer */ uint16_t smb_dsoff; /* offset (from start of SMB hdr) to data bytes */ uint8_t smb_suwcnt; /* set up word count */ uint8_t smb_rsvd2; /* reserved (pad above to word) */ uint16_t smb_setup1; /* function (see below) TRANS_SET_NM_PIPE_STATE = 0x0001 TRANS_RAW_READ_NMPIPE = 0x0011 TRANS_QUERY_NMPIPE_STATE = 0x0021 TRANS_QUERY_NMPIPE_INFO = 0x0022 TRANS_PEEK_NMPIPE = 0x0023 TRANS_TRANSACT_NMPIPE = 0x0026 TRANS_RAW_WRITE_NMPIPE = 0x0031 TRANS_READ_NMPIPE = 0x0036 TRANS_WRITE_NMPIPE = 0x0037 TRANS_WAIT_NMPIPE = 0x0053 TRANS_CALL_NMPIPE = 0x0054 */ uint16_t smb_setup2; /* FID (handle) of pipe (if needed), or priority */ uint16_t smb_bcc; /* total bytes (including pad bytes) following */ #if 0 uint8_t smb_name[]; /* name of transaction */ uint8_t smb_pad[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_param[*]; /* param bytes (* = value of smb_pscnt) */ uint8_t smb_pad1[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_data[*]; /* data bytes (* = value of smb_dscnt) */ #endif } SmbTransactionReq; typedef struct _SmbTransactionInterimResp /* smb_wct = 0 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_bcc; /* must be 0 */ } SmbTransactionInterimResp; typedef struct _SmbTransactionResp /* smb_wct = 10 + value of smb_suwcnt */ { /* Note all subcommands use a setup count of 0 */ uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_tprcnt; /* total number of parameter bytes being returned */ uint16_t smb_tdrcnt; /* total number of data bytes being returned */ uint16_t smb_rsvd; /* reserved */ uint16_t smb_prcnt; /* number of parameter bytes being returned this buf */ uint16_t smb_proff; /* offset (from start of SMB hdr) to parameter bytes */ uint16_t smb_prdisp; /* byte displacement for these parameter bytes */ uint16_t smb_drcnt; /* number of data bytes being returned this buffer */ uint16_t smb_droff; /* offset (from start of SMB hdr) to data bytes */ uint16_t smb_drdisp; /* byte displacement for these data bytes */ uint8_t smb_suwcnt; /* set up return word count */ uint8_t smb_rsvd1; /* reserved (pad above to word) */ uint16_t smb_bcc; /* total bytes (including pad bytes) following */ #if 0 uint8_t smb_pad[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_param[*]; /* param bytes (* = value of smb_prcnt) */ uint8_t smb_pad1[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_data[*]; /* data bytes (* = value of smb_drcnt) */ #endif } SmbTransactionResp; static inline uint16_t SmbTransactionReqSubCom(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_setup1); } static inline uint16_t SmbTransactionReqFid(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_setup2); } static inline bool SmbTransactionReqDisconnectTid(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_flags) & 0x0001 ? true : false; } static inline bool SmbTransactionReqOneWay(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_flags) & 0x0002 ? true : false; } static inline uint8_t SmbTransactionReqSetupCnt(const SmbTransactionReq *req) { return req->smb_suwcnt; } static inline uint16_t SmbTransactionReqTotalDataCnt(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_tdscnt); } static inline uint16_t SmbTransactionReqDataCnt(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_dscnt); } static inline uint16_t SmbTransactionReqDataOff(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_dsoff); } static inline uint16_t SmbTransactionReqTotalParamCnt(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_tpscnt); } static inline uint16_t SmbTransactionReqParamCnt(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_pscnt); } static inline uint16_t SmbTransactionReqParamOff(const SmbTransactionReq *req) { return SmbNtohs(&req->smb_psoff); } static inline uint16_t SmbTransactionRespTotalDataCnt(const SmbTransactionResp *resp) { return SmbNtohs(&resp->smb_tdrcnt); } static inline uint16_t SmbTransactionRespDataCnt(const SmbTransactionResp *resp) { return SmbNtohs(&resp->smb_drcnt); } static inline uint16_t SmbTransactionRespDataOff(const SmbTransactionResp *resp) { return SmbNtohs(&resp->smb_droff); } static inline uint16_t SmbTransactionRespDataDisp(const SmbTransactionResp *resp) { return SmbNtohs(&resp->smb_drdisp); } static inline uint16_t SmbTransactionRespTotalParamCnt(const SmbTransactionResp *resp) { return SmbNtohs(&resp->smb_tprcnt); } static inline uint16_t SmbTransactionRespParamCnt(const SmbTransactionResp *resp) { return SmbNtohs(&resp->smb_prcnt); } static inline uint16_t SmbTransactionRespParamOff(const SmbTransactionResp *resp) { return SmbNtohs(&resp->smb_proff); } static inline uint16_t SmbTransactionRespParamDisp(const SmbTransactionResp *resp) { return SmbNtohs(&resp->smb_prdisp); } // Flags for TRANS_SET_NMPIPE_STATE parameters #define PIPE_STATE_NON_BLOCKING 0x8000 #define PIPE_STATE_MESSAGE_MODE 0x0100 /******************************************************************** * SMB_COM_TRANSACTION_SECONDARY * Continuation command for SMB_COM_TRANSACTION requests if all * data wasn't sent. ********************************************************************/ typedef struct _SmbTransactionSecondaryReq /* smb_wct = 8 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_tpscnt; /* total number of parameter bytes being sent */ uint16_t smb_tdscnt; /* total number of data bytes being sent */ uint16_t smb_pscnt; /* number of parameter bytes being sent this buffer */ uint16_t smb_psoff; /* offset (from start of SMB hdr) to parameter bytes */ uint16_t smb_psdisp; /* byte displacement for these parameter bytes */ uint16_t smb_dscnt; /* number of data bytes being sent this buffer */ uint16_t smb_dsoff; /* offset (from start of SMB hdr) to data bytes */ uint16_t smb_dsdisp; /* byte displacement for these data bytes */ uint16_t smb_bcc; /* total bytes (including pad bytes) following */ #if 0 uint8_t smb_pad[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_param[*]; /* param bytes (* = value of smb_pscnt) */ uint8_t smb_pad1[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_data[*]; /* data bytes (* = value of smb_dscnt) */ #endif } SmbTransactionSecondaryReq; static inline uint16_t SmbTransactionSecondaryReqTotalDataCnt(const SmbTransactionSecondaryReq *req) { return SmbNtohs(&req->smb_tdscnt); } static inline uint16_t SmbTransactionSecondaryReqDataCnt(const SmbTransactionSecondaryReq *req) { return SmbNtohs(&req->smb_dscnt); } static inline uint16_t SmbTransactionSecondaryReqDataOff(const SmbTransactionSecondaryReq *req) { return SmbNtohs(&req->smb_dsoff); } static inline uint16_t SmbTransactionSecondaryReqDataDisp(const SmbTransactionSecondaryReq *req) { return SmbNtohs(&req->smb_dsdisp); } static inline uint16_t SmbTransactionSecondaryReqTotalParamCnt(const SmbTransactionSecondaryReq *req) { return SmbNtohs(&req->smb_tpscnt); } static inline uint16_t SmbTransactionSecondaryReqParamCnt(const SmbTransactionSecondaryReq *req) { return SmbNtohs(&req->smb_pscnt); } static inline uint16_t SmbTransactionSecondaryReqParamOff(const SmbTransactionSecondaryReq *req) { return SmbNtohs(&req->smb_psoff); } static inline uint16_t SmbTransactionSecondaryReqParamDisp(const SmbTransactionSecondaryReq *req) { return SmbNtohs(&req->smb_psdisp); } /******************************************************************** * SMB_COM_WRITE_AND_CLOSE ********************************************************************/ typedef struct _SmbWriteAndCloseReq /* smb_wct = 6 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; /* file handle (close after write) */ uint16_t smb_count; /* number of bytes to write */ uint32_t smb_offset; /* offset in file to begin write */ uint32_t smb_mtime; /* modification time */ uint16_t smb_bcc; /* 1 (for pad) + value of smb_count */ #if 0 uint8_t smb_pad; /* force data to dword boundary */ uint8_t smb_data[]; /* data */ #endif } SmbWriteAndCloseReq; typedef struct _SmbWriteAndCloseExtReq /* smb_wct = 12 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_fid; /* file handle (close after write) */ uint16_t smb_count; /* number of bytes to write */ uint32_t smb_offset; /* offset in file to begin write */ uint32_t smb_mtime; /* modification time */ uint32_t smb_rsvd1; /* Optional */ uint32_t smb_rsvd2; /* Optional */ uint32_t smb_rsvd3; /* Optional */ uint16_t smb_bcc; /* 1 (for pad) + value of smb_count */ #if 0 uint8_t smb_pad; /* force data to dword boundary */ uint8_t smb_data[]; /* data */ #endif } SmbWriteAndCloseExtReq; typedef struct _SmbWriteAndCloseResp /* smb_wct = 1 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_count; /* number of bytes written */ uint16_t smb_bcc; /* must be 0 */ } SmbWriteAndCloseResp; static inline uint16_t SmbWriteAndCloseReqFid(const SmbWriteAndCloseReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint16_t SmbWriteAndCloseReqCount(const SmbWriteAndCloseReq *req) { return SmbNtohs(&req->smb_count); } static inline uint32_t SmbWriteAndCloseReqOffset(const SmbWriteAndCloseReq *req) { return SmbNtohl(&req->smb_offset); } static inline uint16_t SmbWriteAndCloseRespCount(const SmbWriteAndCloseResp *resp) { return SmbNtohs(&resp->smb_count); } /******************************************************************** * SMB_COM_OPEN_ANDX ********************************************************************/ typedef struct _SmbOpenAndXReq /* smb_wct = 15 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_flags; /* additional information: bit 0 - if set, return additional information bit 1 - if set, set single user total file lock (if only access) bit 2 - if set, the server should notify the consumer on any action which can modify the file (delete, setattrib, rename, etc.). if not set, the server need only notify the consumer on another open request. This bit only has meaning if bit 1 is set. */ uint16_t smb_mode; /* file open mode */ uint16_t smb_sattr; /* search attributes */ uint16_t smb_attr; /* file attributes (for create) */ uint32_t smb_time; /* create time */ uint16_t smb_ofun; /* open function */ uint32_t smb_size; /* bytes to reserve on "create" or "truncate" */ uint32_t smb_timeout; /* max milliseconds to wait for resource to open */ uint32_t smb_rsvd; /* reserved (must be zero) */ uint16_t smb_bcc; /* minimum value = 1 */ #if 0 uint8_t smb_pathname[]; /* file pathname */ #endif } SmbOpenAndXReq; typedef struct _SmbOpenAndXResp /* smb_wct = 15 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_fid; /* file handle */ uint16_t smb_attribute; /* attributes of file or device */ uint32_t smb_time; /* last modification time */ uint32_t smb_size; /* current file size */ uint16_t smb_access; /* access permissions actually allowed */ uint16_t smb_type; /* file type */ uint16_t smb_state; /* state of IPC device (e.g. pipe) */ uint16_t smb_action; /* action taken */ uint32_t smb_fileid; /* server unique file id */ uint16_t smb_rsvd; /* reserved */ uint16_t smb_bcc; /* value = 0 */ } SmbOpenAndXResp; static inline uint32_t SmbOpenAndXReqAllocSize(const SmbOpenAndXReq *req) { return SmbNtohl(&req->smb_size); } static inline uint16_t SmbOpenAndXReqFileAttrs(const SmbOpenAndXReq *req) { return SmbNtohs(&req->smb_attr); } static inline uint16_t SmbOpenAndXRespFid(const SmbOpenAndXResp *resp) { return SmbNtohs(&resp->smb_fid); } static inline uint16_t SmbOpenAndXRespFileAttrs(const SmbOpenAndXResp *resp) { return SmbNtohs(&resp->smb_attribute); } static inline uint32_t SmbOpenAndXRespFileSize(const SmbOpenAndXResp *resp) { return SmbNtohl(&resp->smb_size); } static inline uint16_t SmbOpenAndXRespResourceType(const SmbOpenAndXResp *resp) { return SmbNtohs(&resp->smb_type); } #define SMB_OPEN_RESULT__EXISTED 0x0001 #define SMB_OPEN_RESULT__CREATED 0x0002 #define SMB_OPEN_RESULT__TRUNCATED 0x0003 static inline uint16_t SmbOpenAndXRespOpenResults(const SmbOpenAndXResp *resp) { return SmbNtohs(&resp->smb_action); } static inline bool SmbOpenResultRead(const uint16_t open_results) { return ((open_results & 0x00FF) == SMB_OPEN_RESULT__EXISTED); } static inline bool SmbResourceTypeDisk(const uint16_t resource_type) { return resource_type == SMB_FILE_TYPE_DISK; } /******************************************************************** * SMB_COM_READ_ANDX ********************************************************************/ typedef struct _SmbReadAndXReq /* smb_wct = 10 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_fid; /* file handle */ uint32_t smb_offset; /* offset in file to begin read */ uint16_t smb_maxcnt; /* max number of bytes to return */ uint16_t smb_mincnt; /* min number of bytes to return */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_countleft; /* bytes remaining to satisfy user’s request */ uint16_t smb_bcc; /* value = 0 */ } SmbReadAndXReq; typedef struct _SmbReadAndXExtReq /* smb_wct = 12 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_fid; /* file handle */ uint32_t smb_offset; /* low offset in file to begin read */ uint16_t smb_maxcnt; /* max number of bytes to return */ uint16_t smb_mincnt; /* min number of bytes to return */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_countleft; /* bytes remaining to satisfy user’s request */ uint32_t smb_off_high; /* high offset in file to begin read */ uint16_t smb_bcc; /* value = 0 */ } SmbReadAndXExtReq; typedef struct _SmbReadAndXResp /* smb_wct = 12 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ uint32_t smb_rsvd; /* reserved */ uint16_t smb_dsize; /* number of data bytes (minimum value = 0) */ uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ uint16_t smb_dsize_high; /* high bytes of data size */ uint32_t smb_rsvd1; /* reserved */ uint32_t smb_rsvd2; /* reserved */ uint16_t smb_bcc; /* total bytes (including pad bytes) following */ #if 0 uint8_t smb_pad[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_data[*]; /* data bytes (* = value of smb_dsize) */ #endif } SmbReadAndXResp; static inline uint16_t SmbReadAndXReqFid(const SmbReadAndXReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint64_t SmbReadAndXReqOffset(const SmbReadAndXExtReq *req) { if (req->smb_wct == 10) return (uint64_t)SmbNtohl(&req->smb_offset); return (uint64_t)SmbNtohl(&req->smb_off_high) << 32 | (uint64_t)SmbNtohl(&req->smb_offset); } static inline uint16_t SmbReadAndXRespDataOff(const SmbReadAndXResp *req) { return SmbNtohs(&req->smb_doff); } static inline uint32_t SmbReadAndXRespDataCnt(const SmbReadAndXResp *resp) { return (uint32_t)SmbNtohs(&resp->smb_dsize_high) << 16 | (uint32_t)SmbNtohs(&resp->smb_dsize); } /******************************************************************** * SMB_COM_WRITE_ANDX ********************************************************************/ typedef struct _SmbWriteAndXReq /* smb_wct = 12 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_fid; /* file handle */ uint32_t smb_offset; /* offset in file to begin write */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_wmode; /* write mode: bit0 - complete write before return (write through) bit1 - return smb_remaining (pipes/devices only) bit2 - use WriteRawNamedPipe (pipes only) bit3 - this is the start of a message (pipes only) */ uint16_t smb_countleft; /* bytes remaining to write to satisfy user’s request */ uint16_t smb_dsize_high; /* high bytes of data size */ uint16_t smb_dsize; /* number of data bytes in buffer (min value = 0) */ uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ uint16_t smb_bcc; /* total bytes (including pad bytes) following */ #if 0 uint8_t smb_pad[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_data[*]; /* data bytes (* = value of smb_dsize) */ #endif } SmbWriteAndXReq; typedef struct _SmbWriteAndXExtReq /* smb_wct = 14 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_fid; /* file handle */ uint32_t smb_offset; /* low offset in file to begin write */ uint32_t smb_timeout; /* number of milliseconds to wait for completion */ uint16_t smb_wmode; /* write mode: bit0 - complete write before return (write through) bit1 - return smb_remaining (pipes/devices only) bit2 - use WriteRawNamedPipe (pipes only) bit3 - this is the start of a message (pipes only) */ uint16_t smb_countleft; /* bytes remaining to write to satisfy user’s request */ uint16_t smb_dsize_high; /* high bytes of data size */ uint16_t smb_dsize; /* number of data bytes in buffer (min value = 0) */ uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ uint32_t smb_off_high; /* high offset in file to begin write */ uint16_t smb_bcc; /* total bytes (including pad bytes) following */ #if 0 uint8_t smb_pad[]; /* (optional) to pad to word or dword boundary */ uint8_t smb_data[*]; /* data bytes (* = value of smb_dsize) */ #endif } SmbWriteAndXExtReq; typedef struct _SmbWriteAndXResp /* smb_wct = 6 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_count; /* number of bytes written */ uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ uint16_t smb_count_high; /* high order bytes of data count */ uint16_t smb_rsvd; /* reserved */ uint16_t smb_bcc; /* value = 0 */ } SmbWriteAndXResp; static inline uint16_t SmbWriteAndXReqFid(const SmbWriteAndXReq *req) { return SmbNtohs(&req->smb_fid); } static inline uint16_t SmbWriteAndXReqDataOff(const SmbWriteAndXReq *req) { return SmbNtohs(&req->smb_doff); } static inline uint16_t SmbWriteAndXReqRemaining(const SmbWriteAndXReq *req) { return SmbNtohs(&req->smb_countleft); } static inline uint64_t SmbWriteAndXReqOffset(const SmbWriteAndXExtReq *req) { if (req->smb_wct == 12) return (uint64_t)SmbNtohl(&req->smb_offset); return (uint64_t)SmbNtohl(&req->smb_off_high) << 32 | (uint64_t)SmbNtohl(&req->smb_offset); } static inline uint32_t SmbWriteAndXReqDataCnt(const SmbWriteAndXReq *req) { return (uint32_t)SmbNtohs(&req->smb_dsize_high) << 16 | (uint32_t)SmbNtohs(&req->smb_dsize); } static inline uint16_t SmbWriteAndXReqWriteMode(const SmbWriteAndXReq *req) { return SmbNtohs(&req->smb_wmode); } static inline bool SmbWriteAndXReqStartRaw(const SmbWriteAndXReq *req) { return ((SmbNtohs(&req->smb_wmode) & 0x000c) == 0x000c) ? true : false; } static inline bool SmbWriteAndXReqRaw(const SmbWriteAndXReq *req) { return ((SmbNtohs(&req->smb_wmode) & 0x000c) == 0x0004) ? true : false; } static inline uint16_t SmbWriteAndXRespCnt(const SmbWriteAndXResp *resp) { return SmbNtohs(&resp->smb_count); } /******************************************************************** * SMB_COM_TRANSACTION2 ********************************************************************/ typedef struct _SmbTransaction2Req { uint8_t smb_wct; uint16_t smb_total_param_count; uint16_t smb_total_data_count; uint16_t smb_max_param_count; uint16_t smb_max_data_count; uint8_t smb_max_setup_count; uint8_t smb_res; uint16_t smb_flags; uint32_t smb_timeout; uint16_t smb_res2; uint16_t smb_param_count; uint16_t smb_param_offset; uint16_t smb_data_count; uint16_t smb_data_offset; uint8_t smb_setup_count; /* Should be 1 for all subcommands */ uint8_t smb_res3; uint16_t smb_setup; /* This is the subcommand */ uint16_t smb_bcc; #if 0 uint8_t smb_name[]; /* ASCII or Unicode depending on smb header flags */ uint8_t pad1[]; uint8_t smb_trans2_params[smb_param_count]; uint8_t pad2[]; uint8_t smb_trans2_data[smb_data_count]; #endif } SmbTransaction2Req; typedef struct _SmbTransaction2InterimResp { uint8_t smb_wct; uint16_t smb_bcc; } SmbTransaction2InterimResp; typedef struct _SmbTransaction2Resp { uint8_t smb_wct; uint16_t smb_total_param_count; uint16_t smb_total_data_count; uint16_t smb_res; uint16_t smb_param_count; uint16_t smb_param_offset; uint16_t smb_param_disp; uint16_t smb_data_count; uint16_t smb_data_offset; uint16_t smb_data_disp; uint16_t smb_setup_count; /* 0 or 1 word */ uint8_t smb_res2; #if 0 uint16_t smb_setup[smb_setup_count]; uint16_t smb_bcc; uint8_t pad1[]; uint8_t smb_trans2_params[smb_param_count]; uint8_t pad2[]; uint8_t smb_trans2_data[smb_data_count]; #endif } SmbTransaction2Resp; static inline uint16_t SmbTransaction2ReqSubCom(const SmbTransaction2Req *req) { return SmbNtohs(&req->smb_setup); } static inline uint16_t SmbTransaction2ReqTotalParamCnt(const SmbTransaction2Req *req) { return SmbNtohs(&req->smb_total_param_count); } static inline uint16_t SmbTransaction2ReqParamCnt(const SmbTransaction2Req *req) { return SmbNtohs(&req->smb_param_count); } static inline uint16_t SmbTransaction2ReqParamOff(const SmbTransaction2Req *req) { return SmbNtohs(&req->smb_param_offset); } static inline uint16_t SmbTransaction2ReqTotalDataCnt(const SmbTransaction2Req *req) { return SmbNtohs(&req->smb_total_data_count); } static inline uint16_t SmbTransaction2ReqDataCnt(const SmbTransaction2Req *req) { return SmbNtohs(&req->smb_data_count); } static inline uint16_t SmbTransaction2ReqDataOff(const SmbTransaction2Req *req) { return SmbNtohs(&req->smb_data_offset); } static inline uint8_t SmbTransaction2ReqSetupCnt(const SmbTransaction2Req *req) { return req->smb_setup_count; } static inline uint16_t SmbTransaction2RespTotalParamCnt(const SmbTransaction2Resp *resp) { return SmbNtohs(&resp->smb_total_param_count); } static inline uint16_t SmbTransaction2RespParamCnt(const SmbTransaction2Resp *resp) { return SmbNtohs(&resp->smb_param_count); } static inline uint16_t SmbTransaction2RespParamOff(const SmbTransaction2Resp *resp) { return SmbNtohs(&resp->smb_param_offset); } static inline uint16_t SmbTransaction2RespParamDisp(const SmbTransaction2Resp *resp) { return SmbNtohs(&resp->smb_param_disp); } static inline uint16_t SmbTransaction2RespTotalDataCnt(const SmbTransaction2Resp *resp) { return SmbNtohs(&resp->smb_total_data_count); } static inline uint16_t SmbTransaction2RespDataCnt(const SmbTransaction2Resp *resp) { return SmbNtohs(&resp->smb_data_count); } static inline uint16_t SmbTransaction2RespDataOff(const SmbTransaction2Resp *resp) { return SmbNtohs(&resp->smb_data_offset); } static inline uint16_t SmbTransaction2RespDataDisp(const SmbTransaction2Resp *resp) { return SmbNtohs(&resp->smb_data_disp); } typedef struct _SmbTrans2Open2ReqParams { uint16_t Flags; uint16_t AccessMode; uint16_t Reserved1; uint16_t FileAttributes; uint32_t CreationTime; uint16_t OpenMode; uint32_t AllocationSize; uint16_t Reserved[5]; #if 0 SMB_STRING FileName; #endif } SmbTrans2Open2ReqParams; typedef SmbTransaction2Req SmbTrans2Open2Req; static inline uint16_t SmbTrans2Open2ReqAccessMode(const SmbTrans2Open2ReqParams *req) { return SmbNtohs(&req->AccessMode); } static inline uint16_t SmbTrans2Open2ReqFileAttrs(const SmbTrans2Open2ReqParams *req) { return SmbNtohs(&req->FileAttributes); } static inline uint16_t SmbTrans2Open2ReqOpenMode(const SmbTrans2Open2ReqParams *req) { return SmbNtohs(&req->OpenMode); } static inline uint32_t SmbTrans2Open2ReqAllocSize(const SmbTrans2Open2ReqParams *req) { return SmbNtohl(&req->AllocationSize); } typedef struct _SmbTrans2Open2RespParams { uint16_t smb_fid; uint16_t file_attributes; uint32_t creation_time; uint32_t file_data_size; uint16_t access_mode; uint16_t resource_type; uint16_t nm_pipe_status; uint16_t action_taken; uint32_t reserved; uint16_t extended_attribute_error_offset; uint32_t extended_attribute_length; } SmbTrans2Open2RespParams; static inline uint16_t SmbTrans2Open2RespFid(const SmbTrans2Open2RespParams *resp) { return SmbNtohs(&resp->smb_fid); } static inline uint16_t SmbTrans2Open2RespFileAttrs(const SmbTrans2Open2RespParams *resp) { return SmbNtohs(&resp->file_attributes); } static inline uint32_t SmbTrans2Open2RespFileDataSize(const SmbTrans2Open2RespParams *resp) { return SmbNtohl(&resp->file_data_size); } static inline uint16_t SmbTrans2Open2RespResourceType(const SmbTrans2Open2RespParams *resp) { return SmbNtohs(&resp->resource_type); } static inline uint16_t SmbTrans2Open2RespActionTaken(const SmbTrans2Open2RespParams *resp) { return SmbNtohs(&resp->action_taken); } typedef struct _SmbTrans2Open2Resp { uint8_t smb_wct; uint16_t smb_total_param_count; uint16_t smb_total_data_count; uint16_t smb_res; uint16_t smb_param_count; uint16_t smb_param_offset; uint16_t smb_param_disp; uint16_t smb_data_count; uint16_t smb_data_offset; uint16_t smb_data_disp; uint16_t smb_setup_count; /* 0 */ uint8_t smb_res2; uint16_t smb_bcc; #if 0 uint8_t pad1[]; uint8_t smb_trans2_params[smb_param_count]; uint8_t pad2[]; uint8_t smb_trans2_data[smb_data_count]; #endif } SmbTrans2Open2Resp; // See MS-CIFS Section 2.2.2.3.3 #define SMB_INFO_STANDARD 0x0001 #define SMB_INFO_QUERY_EA_SIZE 0x0002 #define SMB_INFO_QUERY_EAS_FROM_LIST 0x0003 #define SMB_INFO_QUERY_ALL_EAS 0x0004 #define SMB_INFO_IS_NAME_VALID 0x0006 #define SMB_QUERY_FILE_BASIC_INFO 0x0101 #define SMB_QUERY_FILE_STANDARD_INFO 0x0102 #define SMB_QUERY_FILE_EA_INFO 0x0103 #define SMB_QUERY_FILE_NAME_INFO 0x0104 #define SMB_QUERY_FILE_ALL_INFO 0x0107 #define SMB_QUERY_FILE_ALT_NAME_INFO 0x0108 #define SMB_QUERY_FILE_STREAM_INFO 0x0109 #define SMB_QUERY_FILE_COMPRESSION_INFO 0x010b // See MS-SMB Section 2.2.2.3.5 // For added value, see below from MS-FSCC #define SMB_INFO_PASSTHROUGH 0x03e8 #define SMB_INFO_PT_FILE_STANDARD_INFO SMB_INFO_PASSTHROUGH+5 #define SMB_INFO_PT_FILE_ALL_INFO SMB_INFO_PASSTHROUGH+18 #define SMB_INFO_PT_FILE_STREAM_INFO SMB_INFO_PASSTHROUGH+22 #define SMB_INFO_PT_NETWORK_OPEN_INFO SMB_INFO_PASSTHROUGH+34 #if 0 See MS-FSCC Section 2.4 File Information Classes FileDirectoryInformation 1 //Query FileFullDirectoryInformation 2 //Query FileBothDirectoryInformation 3 //Query FileBasicInformation 4 //Query, Set FileStandardInformation 5 //Query FileInternalInformation 6 //Query FileEaInformation 7 //Query FileAccessInformation 8 //Query FileNameInformation 9 //LOCAL<71> FileRenameInformation 10 //Set FileLinkInformation 11 //Set FileNamesInformation 12 //Query FileDispositionInformation 13 //Set FilePositionInformation 14 //Query, Set FileFullEaInformation 15 //Query, Set FileModeInformation 16 //Query, Set<69> FileAlignmentInformation 17 //Query FileAllInformation 18 //Query FileAllocationInformation 19 //Set FileEndOfFileInformation 20 //Set FileAlternateNameInformation 21 //Query FileStreamInformation 22 //Query FilePipeInformation 23 //Query, Set FilePipeLocalInformation 24 //Query FilePipeRemoteInformation 25 //Query FileMailslotQueryInformation 26 //LOCAL<67> FileMailslotSetInformation 27 //LOCAL<68> FileCompressionInformation 28 //Query FileObjectIdInformation 29 //LOCAL<73> FileMoveClusterInformation 31 //<70> FileQuotaInformation 32 //Query, Set<74> FileReparsePointInformation 33 //LOCAL<75> FileNetworkOpenInformation 34 //Query FileAttributeTagInformation 35 //Query FileTrackingInformation 36 //LOCAL<79> FileIdBothDirectoryInformation 37 //Query FileIdFullDirectoryInformation 38 //Query FileValidDataLengthInformation 39 //Set FileShortNameInformation 40 //Set FileSfioReserveInformation 44 //LOCAL<76> FileSfioVolumeInformation 45 //<77> FileHardLinkInformation 46 //LOCAL<65> FileNormalizedNameInformation 48 //<72> FileIdGlobalTxDirectoryInformation 50 //LOCAL<66> FileStandardLinkInformation 54 //LOCAL<78> #endif typedef struct _SmbTrans2QueryFileInfoReqParams { uint16_t fid; uint16_t information_level; } SmbTrans2QueryFileInfoReqParams; static inline uint16_t SmbTrans2QueryFileInfoReqFid(const SmbTrans2QueryFileInfoReqParams *req) { return SmbNtohs(&req->fid); } static inline uint16_t SmbTrans2QueryFileInfoReqInfoLevel(const SmbTrans2QueryFileInfoReqParams *req) { return SmbNtohs(&req->information_level); } typedef struct _SmbQueryInfoStandard { uint16_t CreationDate; uint16_t CreationTime; uint16_t LastAccessDate; uint16_t LastAccessTime; uint16_t LastWriteDate; uint16_t LastWriteTime; uint32_t FileDataSize; uint32_t AllocationSize; uint16_t Attributes; } SmbQueryInfoStandard; static inline uint32_t SmbQueryInfoStandardFileDataSize(const SmbQueryInfoStandard *q) { return SmbNtohl(&q->FileDataSize); } typedef struct _SmbQueryInfoQueryEaSize { uint16_t CreationDate; uint16_t CreationTime; uint16_t LastAccessDate; uint16_t LastAccessTime; uint16_t LastWriteDate; uint16_t LastWriteTime; uint32_t FileDataSize; uint32_t AllocationSize; uint16_t Attributes; uint32_t EaSize; } SmbQueryInfoQueryEaSize; static inline uint32_t SmbQueryInfoQueryEaSizeFileDataSize(const SmbQueryInfoQueryEaSize *q) { return SmbNtohl(&q->FileDataSize); } typedef struct _SmbQueryFileStandardInfo { uint64_t AllocationSize; uint64_t EndOfFile; uint32_t NumberOfLinks; uint8_t DeletePending; uint8_t Directory; uint16_t Reserved; } SmbQueryFileStandardInfo; static inline uint64_t SmbQueryFileStandardInfoEndOfFile(const SmbQueryFileStandardInfo *q) { return SmbNtohq(&q->EndOfFile); } typedef struct _SmbQueryFileAllInfo { // Basic Info uint64_t CreationTime; uint64_t LastAccessTime; uint64_t LastWriteTime; uint64_t LastChangeTime; uint32_t ExtFileAttributes; uint32_t Reserved1; uint64_t AllocationSize; uint64_t EndOfFile; uint32_t NumberOfLinks; uint8_t DeletePending; uint8_t Directory; uint16_t Reserved2; uint32_t EaSize; uint32_t FileNameLength; #if 0 uint16_t FileName[FileNameLength/2]; #endif } SmbQueryFileAllInfo; static inline uint64_t SmbQueryFileAllInfoEndOfFile(const SmbQueryFileAllInfo *q) { return SmbNtohq(&q->EndOfFile); } typedef struct _SmbQueryPTFileAllInfo { // Basic Info uint64_t CreationTime; uint64_t LastAccessTime; uint64_t LastWriteTime; uint64_t LastChangeTime; uint32_t ExtFileAttributes; uint32_t Reserved1; // Standard Info uint64_t AllocationSize; uint64_t EndOfFile; uint32_t NumberOfLinks; uint8_t DeletePending; uint8_t Directory; uint16_t Reserved2; // Internal Info uint64_t IndexNumber; // EA Info uint32_t EaSize; // Access Info uint32_t AccessFlags; // Position Info uint64_t CurrentByteOffset; // Mode Info uint32_t Mode; // Alignment Info uint32_t AlignmentRequirement; // Name Info uint32_t FileNameLength; #if 0 uint16_t FileName[FileNameLength/2]; #endif } SmbQueryPTFileAllInfo; static inline uint64_t SmbQueryPTFileAllInfoEndOfFile(const SmbQueryPTFileAllInfo *q) { return SmbNtohq(&q->EndOfFile); } typedef struct _SmbQueryPTNetworkOpenInfo { uint64_t CreationTime; uint64_t LastAccessTime; uint64_t LastWriteTime; uint64_t LastChangeTime; uint64_t AllocationSize; uint64_t EndOfFile; uint32_t FileAttributes; uint32_t Reserved; } SmbQueryPTNetworkOpenInfo; static inline uint64_t SmbQueryPTNetworkOpenInfoEndOfFile(const SmbQueryPTNetworkOpenInfo *q) { return SmbNtohq(&q->EndOfFile); } typedef struct _SmbQueryPTFileStreamInfo { uint32_t NextEntryOffset; uint32_t StreamNameLength; uint64_t StreamSize; uint64_t StreamAllocationSize; #if 0 StreamName (variable) #endif } SmbQueryPTFileStreamInfo; static inline uint64_t SmbQueryPTFileStreamInfoStreamSize(const SmbQueryPTFileStreamInfo *q) { return SmbNtohq(&q->StreamSize); } typedef struct _SmbTrans2QueryFileInformationResp { uint8_t smb_wct; uint16_t smb_total_param_count; uint16_t smb_total_data_count; uint16_t smb_res; uint16_t smb_param_count; uint16_t smb_param_offset; uint16_t smb_param_disp; uint16_t smb_data_count; uint16_t smb_data_offset; uint16_t smb_data_disp; uint16_t smb_setup_count; /* 0 */ uint8_t smb_res2; uint16_t smb_bcc; #if 0 uint8_t pad1[]; uint8_t smb_trans2_params[smb_param_count]; uint8_t pad2[]; // Will be one of the SmbQuery* structures above uint8_t smb_trans2_data[smb_data_count]; #endif } SmbTrans2QueryFileInformationResp; #define SMB_INFO_SET_EAS 0x0002 #define SMB_SET_FILE_BASIC_INFO 0x0101 #define SMB_SET_FILE_DISPOSITION_INFO 0x0102 #define SMB_SET_FILE_ALLOCATION_INFO 0x0103 #define SMB_SET_FILE_END_OF_FILE_INFO 0x0104 // For added value, see above File Information Classes #define SMB_INFO_PT_SET_FILE_BASIC_FILE_INFO SMB_INFO_PASSTHROUGH+4 #define SMB_INFO_PT_SET_FILE_END_OF_FILE_INFO SMB_INFO_PASSTHROUGH+20 typedef struct _SmbTrans2SetFileInfoReqParams { uint16_t fid; uint16_t information_level; uint16_t reserved; } SmbTrans2SetFileInfoReqParams; static inline uint16_t SmbTrans2SetFileInfoReqFid(const SmbTrans2SetFileInfoReqParams *req) { return SmbNtohs(&req->fid); } static inline uint16_t SmbTrans2SetFileInfoReqInfoLevel(const SmbTrans2SetFileInfoReqParams *req) { return SmbNtohs(&req->information_level); } static inline bool SmbSetFileInfoEndOfFile(const uint16_t info_level) { return ((info_level == SMB_SET_FILE_END_OF_FILE_INFO) || (info_level == SMB_INFO_PT_SET_FILE_END_OF_FILE_INFO)); } typedef struct _SmbSetFileBasicInfo { uint64_t CreationTime; uint64_t LastAccessTime; uint64_t LastWriteTime; uint64_t ChangeTime; uint32_t ExtFileAttributes; uint32_t Reserved; } SmbSetFileBasicInfo; static inline uint32_t SmbSetFileInfoExtFileAttrs(const SmbSetFileBasicInfo *info) { return SmbNtohl(&info->ExtFileAttributes); } static inline bool SmbSetFileInfoSetFileBasicInfo(const uint16_t info_level) { return ((info_level == SMB_SET_FILE_BASIC_INFO) || (info_level == SMB_INFO_PT_SET_FILE_BASIC_FILE_INFO)); } static inline bool SmbExtAttrReadOnly(const uint32_t ext_file_attrs) { if (ext_file_attrs & SMB_EXT_FILE_ATTR_SYSTEM) return true; return false; } static inline bool SmbExtAttrHidden(const uint32_t ext_file_attrs) { if (ext_file_attrs & SMB_EXT_FILE_ATTR_HIDDEN) return true; return false; } static inline bool SmbExtAttrSystem(const uint32_t ext_file_attrs) { if (ext_file_attrs & SMB_EXT_FILE_ATTR_SYSTEM) return true; return false; } static inline bool SmbEvasiveFileAttrs(const uint32_t ext_file_attrs) { return (SmbExtAttrReadOnly(ext_file_attrs) && SmbExtAttrHidden(ext_file_attrs) && SmbExtAttrSystem(ext_file_attrs)); } /******************************************************************** * SMB_COM_TRANSACTION2_SECONDARY * Continuation command for SMB_COM_TRANSACTION2 requests if all * data wasn't sent. ********************************************************************/ typedef struct _SmbTransaction2SecondaryReq { uint8_t smb_wct; uint16_t smb_total_param_count; uint16_t smb_total_data_count; uint16_t smb_param_count; uint16_t smb_param_offset; uint16_t smb_param_disp; uint16_t smb_data_count; uint16_t smb_data_offset; uint16_t smb_data_disp; uint16_t smb_fid; uint16_t smb_bcc; #if 0 uint8_t pad1[]; uint8_t smb_trans2_params[smb_param_count]; uint8_t pad2[]; uint8_t smb_trans2_data[smb_data_count]; #endif } SmbTransaction2SecondaryReq; static inline uint16_t SmbTransaction2SecondaryReqTotalParamCnt(const SmbTransaction2SecondaryReq *req) { return SmbNtohs(&req->smb_total_param_count); } static inline uint16_t SmbTransaction2SecondaryReqParamCnt(const SmbTransaction2SecondaryReq *req) { return SmbNtohs(&req->smb_param_count); } static inline uint16_t SmbTransaction2SecondaryReqParamOff(const SmbTransaction2SecondaryReq *req) { return SmbNtohs(&req->smb_param_offset); } static inline uint16_t SmbTransaction2SecondaryReqParamDisp(const SmbTransaction2SecondaryReq *req) { return SmbNtohs(&req->smb_param_disp); } static inline uint16_t SmbTransaction2SecondaryReqTotalDataCnt(const SmbTransaction2SecondaryReq *req) { return SmbNtohs(&req->smb_total_data_count); } static inline uint16_t SmbTransaction2SecondaryReqDataCnt(const SmbTransaction2SecondaryReq *req) { return SmbNtohs(&req->smb_data_count); } static inline uint16_t SmbTransaction2SecondaryReqDataOff(const SmbTransaction2SecondaryReq *req) { return SmbNtohs(&req->smb_data_offset); } static inline uint16_t SmbTransaction2SecondaryReqDataDisp(const SmbTransaction2SecondaryReq *req) { return SmbNtohs(&req->smb_data_disp); } /********************************************************************* * SMB_COM_TREE_CONNECT *********************************************************************/ typedef struct _SmbTreeConnectReq /* smb_wct = 0 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_bcc; /* min = 4 */ #if 0 uint8_t smb_fmt; /* ASCII -- 04 */ uint8_t smb_buf[]; /* path/username */ uint8_t smb_fmt2; /* ASCII -- 04 */ uint8_t smb_buf2[]; /* password */ uint8_t smb_fmt3; /* ASCII -- 04 */ uint8_t smb_buf3[]; /* dev name ( or LPT1) */ #endif } SmbTreeConnectReq; typedef struct _SmbTreeConnectResp /* smb_wct = 2 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_xmit; /* max xmit size */ uint16_t smb_tid; /* tree id */ uint16_t smb_bcc; } SmbTreeConnectResp; /******************************************************************** * SMB_COM_TREE_DISCONNECT ********************************************************************/ typedef struct _SmbTreeDisconnectReq /* smb_wct = 0 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_bcc; /* must be 0 */ } SmbTreeDisconnectReq; typedef struct _SmbTreeDisconnectResp /* smb_wct = 0 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_bcc; /* must be 0 */ } SmbTreeDisconnectResp; /******************************************************************** * SMB_COM_NEGOTIATE ********************************************************************/ typedef struct _SmbNegotiateReq /* smb_wct = 0 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_bcc; /* min = 2 */ #if 0 uint8_t smb_fmt; /* Dialect -- 02 */ uint8_t smb_buf[]; /* dialect0 */ . . . uint8_t smb_fmt; /* Dialect -- 02 */ uint8_t smb_bufn[]; /* dialectn*/ #endif } SmbCore_NegotiateProtocolReq; /* This is the Core Protocol response */ typedef struct _SmbCore_NegotiateProtocolResp /* smb_wct = 1 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_index; /* index */ uint16_t smb_bcc; /* must be 0 */ } SmbCore_NegotiateProtocolResp; /* This is the Lanman response */ typedef struct _SmbLm10_NegotiateProtocolResp /* smb_wct = 13 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_index; /* index identifying dialect selected */ uint16_t smb_secmode; /* security mode: bit 0, 1 = User level, 0 = Share level bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */ uint16_t smb_maxxmt; /* max transmit buffer size server supports, 1K min */ uint16_t smb_maxmux; /* max pending multiplexed requests server supports */ uint16_t smb_maxvcs; /* max VCs per server/consumer session supported */ uint16_t smb_blkmode; /* block read/write mode support: bit 0, Read Block Raw supported (65535 bytes max) bit 1, Write Block Raw supported (65535 bytes max) */ uint32_t smb_sesskey; /* Session Key (unique token identifying session) */ uint16_t smb_srv_time; /* server's current time (hhhhh mmmmmm xxxxx) */ uint16_t smb_srv_tzone; /* server's current data (yyyyyyy mmmm ddddd) */ uint32_t smb_rsvd; /* reserved */ uint16_t smb_bcc; /* value = (size of smb_cryptkey) */ #if 0 uint8_t smb_cryptkey[]; /* Key used for password encryption */ #endif } SmbLm10_NegotiateProtocolResp; /* This is the Lanman 2.1 response */ typedef struct _SmbLm21_NegotiateProtocolResp /* smb_wct = 13 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_index; /* index identifying dialect selected */ uint16_t smb_secmode; /* security mode: bit 0, 1 = User level, 0 = Share level bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */ uint16_t smb_maxxmt; /* max transmit buffer size server supports, 1K min */ uint16_t smb_maxmux; /* max pending multiplexed requests server supports */ uint16_t smb_maxvcs; /* max VCs per server/consumer session supported */ uint16_t smb_blkmode; /* block read/write mode support: bit 0, Read Block Raw supported (65535 bytes max) bit 1, Write Block Raw supported (65535 bytes max) */ uint32_t smb_sesskey; /* Session Key (unique token identifying session) */ uint16_t smb_srv_time; /* server's current time (hhhhh mmmmmm xxxxx) */ uint16_t smb_srv_tzone; /* server's current data (yyyyyyy mmmm ddddd) */ uint16_t smb_cryptkeylen; /* length of smb_cryptkey */ uint16_t smb_rsvd; /* reserved */ uint16_t smb_bcc; /* value = (size of smb_cryptkey) */ #if 0 uint8_t smb_cryptkey[]; /* Key used for password encryption */ uint8_t smb_domain[] /* Null terminated server domain */ #endif } SmbLm21_NegotiateProtocolResp; /* This is the NT response */ typedef struct _SmbNt_NegotiateProtocolResp /* smb_wct = 17 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint16_t smb_index; /* index identifying dialect selected */ uint8_t smb_secmode; /* security mode: bit 0, 1 = User level, 0 = Share level bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */ uint16_t smb_maxmux; /* max pending multiplexed requests server supports */ uint16_t smb_maxvcs; /* max VCs per server/consumer session supported */ uint32_t smb_maxbuf; /* maximum buffer size supported */ uint32_t smb_maxraw; /* maximum raw buffer size supported */ uint32_t smb_sesskey; /* Session Key (unique token identifying session) */ uint32_t smb_cap; /* capabilities */ struct { uint32_t low_time; int32_t high_time; } smb_srv_time; /* server time */ uint16_t smb_srv_tzone; /* server's current data (yyyyyyy mmmm ddddd) */ uint8_t smb_challenge_len; /* Challenge length */ uint16_t smb_bcc; /* value = (size of smb_cryptkey) */ #if 0 uint8_t smb_challenge[]; /* challenge used for password encryption */ uint8_t smb_domain[]; /* domain name */ uint8_t smb_server[]; /* server name */ // or uint8_t smb_server_guid[16]; uint8_t smb_security_blob[]; #endif } SmbNt_NegotiateProtocolResp; static inline uint16_t SmbNegotiateRespDialectIndex(const SmbCore_NegotiateProtocolResp *resp) { return SmbNtohs(&resp->smb_index); } static inline uint16_t SmbLm_NegotiateRespMaxMultiplex(const SmbLm10_NegotiateProtocolResp *resp) { return SmbNtohs(&resp->smb_maxmux); } static inline uint16_t SmbNt_NegotiateRespMaxMultiplex(const SmbNt_NegotiateProtocolResp *resp) { return SmbNtohs(&resp->smb_maxmux); } /******************************************************************** * SMB_COM_SESSION_SETUP_ANDX ********************************************************************/ typedef struct _SmbLm10_SessionSetupAndXReq /* smb_wct = 10 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_bufsize; /* the consumers max buffer size */ uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ uint16_t smb_apasslen; /* size of account password (smb_apasswd) */ uint32_t smb_rsvd; /* reserved */ uint16_t smb_bcc; /* minimum value = 0 */ #if 0 uint8_t smb_apasswd[*]; /* account password (* = smb_apasslen value) */ uint8_t smb_aname[]; /* account name string */ #endif } SmbLm10_SessionSetupAndXReq; typedef struct _SmbLm10_SessionSetupAndXResp /* smb_wct = 3 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_action; /* request mode: bit0 = Logged in successfully - BUT as GUEST */ uint16_t smb_bcc; /* value = 0 */ } SmbLm10_SessionSetupAndXResp; /* Extended request as defined in LM 2.0 document */ typedef struct _SmbLm20_SessionSetupAndXReq /* smb_wct = 10 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_bufsize; /* the consumers max buffer size */ uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ uint16_t smb_apasslen; /* size of account password (smb_apasswd) */ uint16_t smb_encryptlen; /* size of encryption key (smb_encrypt) */ uint16_t smb_encryptoff; /* offet (from SMB hdr start) to smb_encrypt */ uint16_t smb_bcc; /* minimum value = 0 */ #if 0 uint8_t smb_apasswd[*]; /* account password (* = smb_apasslen value) */ uint8_t smb_aname[]; /* account name string */ uint8_t smb_encrypt[*]; /* encryption key. (* = smb_encryptlen value) */ #endif } SmbLm20_SessionSetupAndXReq; /* Extended response as defined in LM 2.0 document */ typedef struct _SmbLm20_SessionSetupAndXResp /* smb_wct = 3 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_action; /* request mode: bit0 = Logged in successfully - BUT as GUEST */ uint16_t smb_bcc; /* min value = 0 */ #if 0 smb_encresp[]; /* server response to request encryption key */ #endif } SmbLm20_SessionSetupAndXResp; /* Extended request as defined in LM 2.1 document */ typedef struct _SmbLm21_SessionSetupAndXReq /* smb_wct = 10 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_bufsize; /* the consumers max buffer size */ uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ uint16_t smb_apasslen; /* size of account password (smb_apasswd) */ uint32_t smb_rsvd; /* reserved */ uint16_t smb_bcc; /* minimum value = 0 */ #if 0 uint8_t smb_apasswd[*]; /* account password (* = smb_apasslen value) */ uint8_t smb_aname[]; /* account name string */ uint8_t smb_domain[]; /* name of domain that client was authenticated on */ uint8_t smb_mativeos[]; /* native operation system of client */ uint8_t smb_nativelm[]; /* native LAN Manager type */ #endif } SmbLm21_SessionSetupAndXReq; /* Extended response as defined in LM 2.1 document */ typedef struct _SmbLm21_SessionSetupAndXResp /* smb_wct = 3 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_action; /* request mode: bit0 = Logged in successfully - BUT as GUEST */ uint16_t smb_bcc; /* min value = 0 */ #if 0 uint8_t smb_nativeos[]; /* server's native operating system */ uint8_t smb_nativelm[]; /* server's native LM type */ #endif } SmbLm21_SessionSetupAndXResp; /* Extended request as defined in NT LM 1.0 document */ typedef struct _SmbNt10_SessionSetupAndXReq /* smb_wct = 13 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_bufsize; /* the consumers max buffer size */ uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ uint16_t smb_oem_passlen; /* case insensitive password length */ uint16_t smb_unicode_passlen; /* case sensitive password length */ uint32_t smb_rsvd; /* reserved */ uint32_t smb_cap; /* capabilities */ uint16_t smb_bcc; /* minimum value = 0 */ #if 0 uint8_t smb_oem_passwd[*]; /* case insensitive password (* = smb_ci_passlen) */ uint8_t smb_unicode_passwd[*]; /* case sensitive password (* = smb_cs_passlen) */ uint8_t pad[]; /* if unicode to align */ uint8_t smb_aname[]; /* ascii or unicode account name string */ uint8_t smb_domain[]; /* ascii or unicode name of domain that client was authenticated on */ uint8_t smb_nativeos[]; /* ascii or unicode native operation system of client */ uint8_t smb_nativelm[]; /* ascii or unicode native LAN Manager type */ #endif } SmbNt10_SessionSetupAndXReq; static inline uint16_t SmbSessionSetupAndXReqMaxMultiplex(const SmbLm10_SessionSetupAndXReq *req) { return SmbNtohs(&req->smb_mpxmax); } static inline uint16_t SmbNt10SessionSetupAndXReqOemPassLen(const SmbNt10_SessionSetupAndXReq *req) { return SmbNtohs(&req->smb_oem_passlen); } static inline uint16_t SmbNt10SessionSetupAndXReqUnicodePassLen(const SmbNt10_SessionSetupAndXReq *req) { return SmbNtohs(&req->smb_unicode_passlen); } /* Extended request for security blob */ typedef struct _SmbNt10_SessionSetupAndXExtReq /* smb_wct = 12 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_bufsize; /* the consumers max buffer size */ uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ uint16_t smb_blob_len; /* length of security blob */ uint32_t smb_rsvd; /* reserved */ uint32_t smb_cap; /* capabilities */ uint16_t smb_bcc; /* minimum value = 0 */ #if 0 uint8_t smb_blob[]; /* security blob */ uint8_t smb_nativeos[]; /* ascii or unicode native operation system of client */ uint8_t smb_nativelm[]; /* ascii or unicode native LAN Manager type */ #endif } SmbNt10_SessionSetupAndXExtReq; static inline uint16_t SmbSessionSetupAndXReqBlobLen(const SmbNt10_SessionSetupAndXExtReq *req) { return SmbNtohs(&req->smb_blob_len); } /* Response as defined in NT LM 1.0 document */ typedef struct _SmbNt10_SessionSetupAndXResp /* smb_wct = 3 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_action; /* request mode: bit0 = Logged in successfully - BUT as GUEST */ uint16_t smb_bcc; /* min value = 0 */ #if 0 uint8_t pad[]; /* if unicode is used to align */ uint8_t smb_nativeos[]; /* ascii or unicode server's native operating system */ uint8_t smb_nativelm[]; /* ascii or unicode server's native LM type */ uint8_t smb_domain[]; /* ascii or unicode logon domain of the user */ #endif } SmbNt10_SessionSetupAndXResp; /* Extended response for security blob */ typedef struct _SmbNt10_SessionSetupAndXExtResp /* smb_wct = 4 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_action; /* request mode: bit0 = Logged in successfully - BUT as GUEST */ uint16_t smb_blob_len; /* length of security blob */ uint16_t smb_bcc; /* min value = 0 */ #if 0 uint8_t smb_blob[]; /* security blob */ uint8_t smb_nativeos[]; /* ascii or unicode server's native operating system */ uint8_t smb_nativelm[]; /* ascii or unicode server's native LM type */ #endif } SmbNt10_SessionSetupAndXExtResp; static inline uint16_t SmbSessionSetupAndXRespBlobLen(const SmbNt10_SessionSetupAndXExtResp *resp) { return SmbNtohs(&resp->smb_blob_len); } /******************************************************************** * SMB_COM_LOGOFF_ANDX ********************************************************************/ typedef struct _SmbLogoffAndXReq /* smb_wct = 2 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_bcc; /* value = 0 */ } SmbLogoffAndXReq; typedef struct _SmbLogoffAndXResp /* smb_wct = 2 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_bcc; /* value = 0 */ } SmbLogoffAndXResp; /********************************************************************* * SMB_COM_TREE_CONNECT_ANDX *********************************************************************/ typedef struct _SmbTreeConnectAndXReq /* smb_wct = 4 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_reh2; /* reserved (must be zero) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_flags; /* additional information: bit 0 - if set, disconnect TID in current smb_tid */ uint16_t smb_spasslen; /* length of smb_spasswd */ uint16_t smb_bcc; /* minimum value = 3 */ #if 0 uint8_t smb_spasswd[*]; /* net-name password (* = smb_spasslen value) */ uint8_t pad[]; /* if unicode to align */ uint8_t smb_path[]; /* server name and net-name */ uint8_t smb_service[]; /* service name string */ #endif } SmbTreeConnectAndXReq; typedef struct _SmbLm10_TreeConnectAndXResp /* smb_wct = 2 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_bcc; /* min value = 3 */ #if 0 uint8_t smb_service[]; /* service type connected to (string) */ #endif } SmbLm10_TreeConnectAndXResp; typedef struct _SmbTreeConnectAndXResp /* smb_wct = 3 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_optsupp; /* bit mask indicating advanced OS features available bit0 = 1, exclusive search bits supported */ uint16_t smb_bcc; /* min value = 3 */ #if 0 uint8_t smb_service[]; /* service type connected to - ASCII */ uint8_t pad[]; /* if unicode to align */ uint8_t smb_nativefs[]; /* native file system for this connection */ #endif } SmbTreeConnectAndXResp; typedef struct _SmbTreeConnectAndXExtResp /* smb_wct = 7 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint16_t smb_optsupp; /* bit mask indicating advanced OS features available */ uint32_t smb_share_access; /* maximal share access rights */ uint32_t smb_guest_access; /* guest maximal share access rights */ uint16_t smb_bcc; /* min value = 3 */ #if 0 uint8_t smb_service[]; /* service type connected to - ASCII */ uint8_t pad[]; /* if unicode to align */ uint8_t smb_nativefs[]; /* native file system for this connection */ #endif } SmbTreeConnectAndXExtResp; static inline uint16_t SmbTreeConnectAndXReqPassLen(const SmbTreeConnectAndXReq *req) { return SmbNtohs(&req->smb_spasslen); } /******************************************************************** * SMB_COM_NT_TRANSACT ********************************************************************/ #define SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY 0x00000004 typedef struct _SmbNtTransactReq { uint8_t smb_wct; uint8_t smb_max_setup_count; uint16_t smb_res; uint32_t smb_total_param_count; uint32_t smb_total_data_count; uint32_t smb_max_param_count; uint32_t smb_max_data_count; uint32_t smb_param_count; uint32_t smb_param_offset; uint32_t smb_data_count; uint32_t smb_data_offset; uint8_t smb_setup_count; uint16_t smb_function; #if 0 uint16_t smb_setup[smb_setup_count]; uint16_t smb_bcc; uint8_t pad1[]; uint8_t smb_nt_trans_params[smb_param_count]; uint8_t pad2[]; uint8_t smb_nt_trans_data[smb_data_count]; #endif } SmbNtTransactReq; typedef struct _SmbNtTransactInterimResp { uint8_t smb_wct; uint16_t smb_bcc; } SmbNtTransactInterimResp; typedef struct _SmbNtTransactResp { uint8_t smb_wct; uint8_t smb_res[3]; uint32_t smb_total_param_count; uint32_t smb_total_data_count; uint32_t smb_param_count; uint32_t smb_param_offset; uint32_t smb_param_disp; uint32_t smb_data_count; uint32_t smb_data_offset; uint32_t smb_data_disp; uint8_t smb_setup_count; #if 0 uint16_t smb_setup[smb_setup_count]; uint16_t smb_bcc; uint8_t pad1[]; uint8_t smb_nt_trans_params[smb_param_count]; uint8_t pad2[]; uint8_t smb_nt_trans_data[smb_data_count]; #endif } SmbNtTransactResp; static inline uint16_t SmbNtTransactReqSubCom(const SmbNtTransactReq *req) { return SmbNtohs(&req->smb_function); } static inline uint8_t SmbNtTransactReqSetupCnt(const SmbNtTransactReq *req) { return req->smb_setup_count; } static inline uint32_t SmbNtTransactReqTotalParamCnt(const SmbNtTransactReq *req) { return SmbNtohl(&req->smb_total_param_count); } static inline uint32_t SmbNtTransactReqParamCnt(const SmbNtTransactReq *req) { return SmbNtohl(&req->smb_param_count); } static inline uint32_t SmbNtTransactReqParamOff(const SmbNtTransactReq *req) { return SmbNtohl(&req->smb_param_offset); } static inline uint32_t SmbNtTransactReqTotalDataCnt(const SmbNtTransactReq *req) { return SmbNtohl(&req->smb_total_data_count); } static inline uint32_t SmbNtTransactReqDataCnt(const SmbNtTransactReq *req) { return SmbNtohl(&req->smb_data_count); } static inline uint32_t SmbNtTransactReqDataOff(const SmbNtTransactReq *req) { return SmbNtohl(&req->smb_data_offset); } static inline uint32_t SmbNtTransactRespTotalParamCnt(const SmbNtTransactResp *resp) { return SmbNtohl(&resp->smb_total_param_count); } static inline uint32_t SmbNtTransactRespParamCnt(const SmbNtTransactResp *resp) { return SmbNtohl(&resp->smb_param_count); } static inline uint32_t SmbNtTransactRespParamOff(const SmbNtTransactResp *resp) { return SmbNtohl(&resp->smb_param_offset); } static inline uint32_t SmbNtTransactRespParamDisp(const SmbNtTransactResp *resp) { return SmbNtohl(&resp->smb_param_disp); } static inline uint32_t SmbNtTransactRespTotalDataCnt(const SmbNtTransactResp *resp) { return SmbNtohl(&resp->smb_total_data_count); } static inline uint32_t SmbNtTransactRespDataCnt(const SmbNtTransactResp *resp) { return SmbNtohl(&resp->smb_data_count); } static inline uint32_t SmbNtTransactRespDataOff(const SmbNtTransactResp *resp) { return SmbNtohl(&resp->smb_data_offset); } static inline uint32_t SmbNtTransactRespDataDisp(const SmbNtTransactResp *resp) { return SmbNtohl(&resp->smb_data_disp); } typedef struct _SmbNtTransactCreateReqParams { uint32_t flags; uint32_t root_dir_fid; uint32_t desired_access; uint64_t allocation_size; uint32_t ext_file_attributes; uint32_t share_access; uint32_t create_disposition; uint32_t create_options; uint32_t security_descriptor_length; uint32_t ea_length; uint32_t name_length; uint32_t impersonation_level; uint8_t security_flags; #if 0 uint8_t name[name_length]; #endif } SmbNtTransactCreateReqParams; #if 0 // Not used now typedef struct _SmbNtTransactCreateReqData { uint8_t security_descriptor[security_descriptor_length]; uint8_t extended_attributes[ea_length]; } SmbNtTransactCreateReqData; #endif static inline uint64_t SmbNtTransactCreateReqAllocSize(const SmbNtTransactCreateReqParams *req) { return SmbNtohq(&req->allocation_size); } static inline uint32_t SmbNtTransactCreateReqFileNameLength(const SmbNtTransactCreateReqParams *req) { return SmbNtohl(&req->name_length); } static inline uint32_t SmbNtTransactCreateReqFileAttrs(const SmbNtTransactCreateReqParams *req) { return SmbNtohl(&req->ext_file_attributes); } static inline bool SmbNtTransactCreateReqSequentialOnly(const SmbNtTransactCreateReqParams *req) { return (SmbNtohl(&req->create_options) & SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY); } typedef struct _SmbNtTransactCreateReq { uint8_t smb_wct; uint8_t smb_max_setup_count; uint16_t smb_res; uint32_t smb_total_param_count; uint32_t smb_total_data_count; uint32_t smb_max_param_count; uint32_t smb_max_data_count; uint32_t smb_param_count; uint32_t smb_param_offset; uint32_t smb_data_count; uint32_t smb_data_offset; uint8_t smb_setup_count; /* Must be 0x00 */ uint16_t smb_function; /* NT_TRANSACT_CREATE */ uint16_t smb_bcc; #if 0 uint8_t pad1[]; uint8_t smb_nt_trans_params[smb_param_count]; /* SmbNtTransCreateParams */ uint8_t pad2[]; uint8_t smb_nt_trans_data[smb_data_count]; #endif } SmbNtTransactCreateReq; typedef struct _SmbNtTransactCreateRespParams { uint8_t op_lock_level; uint8_t reserved; uint16_t smb_fid; uint32_t create_action; uint32_t ea_error_offset; uint64_t creation_time; uint64_t last_access_time; uint64_t last_write_time; uint64_t last_change_time; uint32_t ext_file_attributes; uint64_t allocation_size; uint64_t end_of_file; uint16_t resource_type; uint16_t nm_pipe_status; uint8_t directory; } SmbNtTransactCreateRespParams; static inline uint16_t SmbNtTransactCreateRespFid(const SmbNtTransactCreateRespParams *resp) { return SmbNtohs(&resp->smb_fid); } static inline uint32_t SmbNtTransactCreateRespCreateAction(const SmbNtTransactCreateRespParams *resp) { return SmbNtohl(&resp->create_action); } static inline uint64_t SmbNtTransactCreateRespEndOfFile(const SmbNtTransactCreateRespParams *resp) { return SmbNtohq(&resp->end_of_file); } static inline uint16_t SmbNtTransactCreateRespResourceType(const SmbNtTransactCreateRespParams *resp) { return SmbNtohs(&resp->resource_type); } static inline bool SmbNtTransactCreateRespDirectory(const SmbNtTransactCreateRespParams *resp) { return (resp->directory ? true : false); } typedef struct _SmbNtTransactCreateResp { uint8_t smb_wct; uint8_t smb_res[3]; uint32_t smb_total_param_count; uint32_t smb_total_data_count; uint32_t smb_param_count; uint32_t smb_param_offset; uint32_t smb_param_disp; uint32_t smb_data_count; uint32_t smb_data_offset; uint32_t smb_data_disp; uint8_t smb_setup_count; /* 0x00 */ uint16_t smb_bcc; #if 0 uint8_t pad1[]; uint8_t smb_nt_trans_params[smb_param_count]; uint8_t pad2[]; uint8_t smb_nt_trans_data[smb_data_count]; #endif } SmbNtTransactCreateResp; /******************************************************************** * SMB_COM_NT_TRANSACT_SECONDARY ********************************************************************/ typedef struct _SmbNtTransactSecondaryReq { uint8_t smb_wct; uint8_t smb_res[3]; uint32_t smb_total_param_count; uint32_t smb_total_data_count; uint32_t smb_param_count; uint32_t smb_param_offset; uint32_t smb_param_disp; uint32_t smb_data_count; uint32_t smb_data_offset; uint32_t smb_data_disp; uint8_t smb_res2; #if 0 uint8_t pad1[]; uint8_t smb_nt_trans_params[smb_param_count]; uint8_t pad2[]; uint8_t smb_nt_trans_data[smb_data_count]; #endif } SmbNtTransactSecondaryReq; static inline uint32_t SmbNtTransactSecondaryReqTotalParamCnt(const SmbNtTransactSecondaryReq *req) { return SmbNtohl(&req->smb_total_param_count); } static inline uint32_t SmbNtTransactSecondaryReqParamCnt(const SmbNtTransactSecondaryReq *req) { return SmbNtohl(&req->smb_param_count); } static inline uint32_t SmbNtTransactSecondaryReqParamOff(const SmbNtTransactSecondaryReq *req) { return SmbNtohl(&req->smb_param_offset); } static inline uint32_t SmbNtTransactSecondaryReqParamDisp(const SmbNtTransactSecondaryReq *req) { return SmbNtohl(&req->smb_param_disp); } static inline uint32_t SmbNtTransactSecondaryReqTotalDataCnt(const SmbNtTransactSecondaryReq *req) { return SmbNtohl(&req->smb_total_data_count); } static inline uint32_t SmbNtTransactSecondaryReqDataCnt(const SmbNtTransactSecondaryReq *req) { return SmbNtohl(&req->smb_data_count); } static inline uint32_t SmbNtTransactSecondaryReqDataOff(const SmbNtTransactSecondaryReq *req) { return SmbNtohl(&req->smb_data_offset); } static inline uint32_t SmbNtTransactSecondaryReqDataDisp(const SmbNtTransactSecondaryReq *req) { return SmbNtohl(&req->smb_data_disp); } /******************************************************************** * SMB_COM_NT_CREATE_ANDX ********************************************************************/ #define SMB_CREATE_DISPOSITSION__FILE_SUPERCEDE 0x00000000 #define SMB_CREATE_DISPOSITSION__FILE_OPEN 0x00000001 #define SMB_CREATE_DISPOSITSION__FILE_CREATE 0x00000002 #define SMB_CREATE_DISPOSITSION__FILE_OPEN_IF 0x00000003 #define SMB_CREATE_DISPOSITSION__FILE_OVERWRITE 0x00000004 #define SMB_CREATE_DISPOSITSION__FILE_OVERWRITE_IF 0x00000005 typedef struct _SmbNtCreateAndXReq /* smb_wct = 24 */ { uint8_t smb_wct; /* count of 16-bit words that follow */ uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ uint8_t smb_res2; /* reserved (pad to word) */ uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ uint8_t smb_res; /* reserved */ uint16_t smb_name_len; /* length of name of file */ uint32_t smb_flags; /* flags */ uint32_t smb_root_fid; /* fid for previously opened directory */ uint32_t smb_access; /* specifies the type of file access */ uint64_t smb_alloc_size; /* initial allocation size of the file */ uint32_t smb_file_attrs; /* specifies the file attributes for the file */ uint32_t smb_share_access; /* the type of share access */ uint32_t smb_create_disp; /* actions to take if file does or does not exist */ uint32_t smb_create_opts; /* options used when creating or opening file */ uint32_t smb_impersonation_level; /* security impersonation level */ uint8_t smb_security_flags; /* security flags */ uint16_t smb_bcc; /* byte count */ #if 0 uint8_t * file_name[]; /* name of file to open - ascii or unicode */ #endif } SmbNtCreateAndXReq; typedef struct _SmbNtCreateAndXResp /* smb_wct = 34 */ { uint8_t smb_wct; uint8_t smb_com2; uint8_t smb_res2; uint16_t smb_off2; uint8_t smb_oplock_level; uint16_t smb_fid; uint32_t smb_create_disposition; uint64_t smb_creation_time; uint64_t smb_last_access_time; uint64_t smb_last_write_time; uint64_t smb_change_time; uint32_t smb_file_attrs; uint64_t smb_alloc_size; uint64_t smb_eof; uint16_t smb_resource_type; uint16_t smb_nm_pipe_state; uint8_t smb_directory; uint16_t smb_bcc; } SmbNtCreateAndXResp; // Word count is always set to 42 though there are actually 50 words typedef struct _SmbNtCreateAndXExtResp /* smb_wct = 42 */ { uint8_t smb_wct; uint8_t smb_com2; uint8_t smb_res2; uint16_t smb_off2; uint8_t smb_oplock_level; uint16_t smb_fid; uint32_t smb_create_disposition; uint64_t smb_creation_time; uint64_t smb_last_access_time; uint64_t smb_last_write_time; uint64_t smb_change_time; uint32_t smb_file_attrs; uint64_t smb_alloc_size; uint64_t smb_eof; uint16_t smb_resource_type; uint16_t smb_nm_pipe_state; uint8_t smb_directory; uint8_t smb_volume_guid[16]; uint64_t smb_fileid; uint32_t smb_max_access_rights; uint32_t smb_guest_access_rights; uint16_t smb_bcc; } SmbNtCreateAndXExtResp; static inline uint16_t SmbNtCreateAndXReqFileNameLen(const SmbNtCreateAndXReq *req) { return SmbNtohs(&req->smb_name_len); } static inline uint32_t SmbNtCreateAndXReqCreateDisposition(const SmbNtCreateAndXReq *req) { return SmbNtohl(&req->smb_create_disp); } static inline bool SmbCreateDispositionRead(const uint32_t create_disposition) { return (create_disposition == SMB_CREATE_DISPOSITSION__FILE_OPEN) || (create_disposition > SMB_CREATE_DISPOSITSION__FILE_OVERWRITE_IF); } static inline uint64_t SmbNtCreateAndXReqAllocSize(const SmbNtCreateAndXReq *req) { return SmbNtohq(&req->smb_alloc_size); } static inline bool SmbNtCreateAndXReqSequentialOnly(const SmbNtCreateAndXReq *req) { return (SmbNtohl(&req->smb_create_opts) & SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY); } static inline uint32_t SmbNtCreateAndXReqFileAttrs(const SmbNtCreateAndXReq *req) { return SmbNtohl(&req->smb_file_attrs); } static inline uint16_t SmbNtCreateAndXRespFid(const SmbNtCreateAndXResp *resp) { return SmbNtohs(&resp->smb_fid); } static inline uint32_t SmbNtCreateAndXRespCreateDisposition(const SmbNtCreateAndXResp *resp) { return SmbNtohl(&resp->smb_create_disposition); } static inline bool SmbNtCreateAndXRespDirectory(const SmbNtCreateAndXResp *resp) { return (resp->smb_directory ? true : false); } static inline uint16_t SmbNtCreateAndXRespResourceType(const SmbNtCreateAndXResp *resp) { return SmbNtohs(&resp->smb_resource_type); } static inline uint64_t SmbNtCreateAndXRespEndOfFile(const SmbNtCreateAndXResp *resp) { return SmbNtohq(&resp->smb_eof); } #ifdef WIN32 #pragma pack(pop,smb_hdrs) #else #pragma pack() #endif #endif /* _SMB_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/dcerpc2/includes/dcerpc.h0000644000000000000000000007640112260565732021625 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2008-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************************** * ****************************************************************************/ #ifndef DCERPC_H #define DCERPC_H #ifdef HAVE_CONFIG_H #include "config.h" /* For WORDS_BIGENDIAN */ #endif /******************************************************************** * Enumerations ********************************************************************/ /* DCE/RPC byte order flag */ typedef enum _DceRpcBoFlag { DCERPC_BO_FLAG__NONE, DCERPC_BO_FLAG__BIG_ENDIAN, DCERPC_BO_FLAG__LITTLE_ENDIAN } DceRpcBoFlag; /* * Common to Connectionless and Connection Oriented */ typedef enum _DceRpcPduType { DCERPC_PDU_TYPE__REQUEST = 0, DCERPC_PDU_TYPE__PING, DCERPC_PDU_TYPE__RESPONSE, DCERPC_PDU_TYPE__FAULT, DCERPC_PDU_TYPE__WORKING, DCERPC_PDU_TYPE__NOCALL, DCERPC_PDU_TYPE__REJECT, DCERPC_PDU_TYPE__ACK, DCERPC_PDU_TYPE__CL_CANCEL, DCERPC_PDU_TYPE__FACK, DCERPC_PDU_TYPE__CANCEL_ACK, DCERPC_PDU_TYPE__BIND, DCERPC_PDU_TYPE__BIND_ACK, DCERPC_PDU_TYPE__BIND_NACK, DCERPC_PDU_TYPE__ALTER_CONTEXT, DCERPC_PDU_TYPE__ALTER_CONTEXT_RESP, DCERPC_PDU_TYPE__AUTH3, DCERPC_PDU_TYPE__SHUTDOWN, DCERPC_PDU_TYPE__CO_CANCEL, DCERPC_PDU_TYPE__ORPHANED, DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP, DCERPC_PDU_TYPE__MAX } DceRpcPduType; /* Version 4 is for Connectionless * Version 5 is for Connection oriented */ typedef enum _DceRpcProtoMajorVers { DCERPC_PROTO_MAJOR_VERS__4 = 4, DCERPC_PROTO_MAJOR_VERS__5 = 5 } DceRpcProtoMajorVers; typedef enum _DceRpcProtoMinorVers { DCERPC_PROTO_MINOR_VERS__0 = 0, DCERPC_PROTO_MINOR_VERS__1 = 1 } DceRpcProtoMinorVers; /* * Connectionless */ typedef enum _DceRpcClFlags1 { DCERPC_CL_FLAGS1__RESERVED_01 = 0x01, DCERPC_CL_FLAGS1__LASTFRAG = 0x02, DCERPC_CL_FLAGS1__FRAG = 0x04, DCERPC_CL_FLAGS1__NOFACK = 0x08, DCERPC_CL_FLAGS1__MAYBE = 0x10, DCERPC_CL_FLAGS1__IDEMPOTENT = 0x20, DCERPC_CL_FLAGS1__BROADCAST = 0x40, DCERPC_CL_FLAGS1__RESERVED_80 = 0x80 } DceRpcClFlags1; typedef enum _DceRpcClFlags2 { DCERPC_CL_FLAGS2__RESERVED_01 = 0x01, DCERPC_CL_FLAGS2__CANCEL_PENDING = 0x02, DCERPC_CL_FLAGS2__RESERVED_04 = 0x04, DCERPC_CL_FLAGS2__RESERVED_08 = 0x08, DCERPC_CL_FLAGS2__RESERVED_10 = 0x10, DCERPC_CL_FLAGS2__RESERVED_20 = 0x20, DCERPC_CL_FLAGS2__RESERVED_40 = 0x40, DCERPC_CL_FLAGS2__RESERVED_80 = 0x80 } DceRpcClFlags2; typedef enum _DCERPC_AuthProto { DCERPC_AUTH_PROTO__NONE = 0, DCERPC_AUTH_PROTO__OSF_DCERPC_PK_AUTH = 1 } DCERPC_AuthProto; /* * Connection oriented */ typedef enum _DceRpcCoPfcFlags { DCERPC_CO_PFC_FLAGS__FIRST_FRAG = 0x01, DCERPC_CO_PFC_FLAGS__LAST_FRAG = 0x02, DCERPC_CO_PFC_FLAGS__PENDING_CANCEL = 0x04, DCERPC_CO_PFC_FLAGS__RESERVED_1 = 0x08, DCERPC_CO_PFC_FLAGS__CONC_MPX = 0x10, DCERPC_CO_PFC_FLAGS__DID_NOT_EXECUTE = 0x20, DCERPC_CO_PFC_FLAGS__MAYBE = 0x40, DCERPC_CO_PFC_FLAGS__OBJECT_UUID = 0x80 } DceRpcCoPfcFlags; /* Presentation context definition result */ typedef enum _DceRpcCoContDefResult { DCERPC_CO_CONT_DEF_RESULT__ACCEPTANCE = 0, DCERPC_CO_CONT_DEF_RESULT__USER_REJECTION, DCERPC_CO_CONT_DEF_RESULT__PROVIDER_REJECTION } DceRpcCoContDefResult; /* Presentation provider rejection reason */ typedef enum _DceRpcCoProvRejReason { DCERPC_CO_PROV_REJ_REASON__REASON_NOT_SPECIFIED = 0, DCERPC_CO_PROV_REJ_REASON__ABSTRACT_SYNTAX_NOT_SUPPORTED, DCERPC_CO_PROV_REJ_REASON__PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED, DCERPC_CO_PROV_REJ_REASON__LOCAL_LIMIT_EXCEEDED } DceRpcCoProvRejReason; typedef enum _DceRpcCoBindNakReason { DCERPC_CO_BIND_NAK_REASON__REASON_NOT_SPECIFIED = 0, DCERPC_CO_BIND_NAK_REASON__TEMPORARY_CONGESTION, DCERPC_CO_BIND_NAK_REASON__LOCAL_LIMIT_EXECEEDED, DCERPC_CO_BIND_NAK_REASON__CALLED_PADDR_UNKNOWN, DCERPC_CO_BIND_NAK_REASON__PROTOCOL_VERSION_NOT_SUPPORTED, DCERPC_CO_BIND_NAK_REASON__DEFAULT_CONTEXT_NOT_SUPPORTED, DCERPC_CO_BIND_NAK_REASON__USER_DATA_NOT_READABLE, DCERPC_CO_BIND_NAK_REASON__NO_PSAP_AVAILABLE } DceRpcCoBindNakReason; typedef enum _DceRpcCoAuthLevelType { DCERPC_CO_AUTH_LEVEL__NONE = 1, DCERPC_CO_AUTH_LEVEL__CONNECT, DCERPC_CO_AUTH_LEVEL__CALL, DCERPC_CO_AUTH_LEVEL__PKT, DCERPC_CO_AUTH_LEVEL__PKT_INTEGRITY, DCERPC_CO_AUTH_LEVEL__PKT_PRIVACY } DceRpcCoAuthLevelType; /******************************************************************** * Structures ********************************************************************/ #ifdef WIN32 #pragma pack(push, dcerpc_hdrs, 1) #else #pragma pack(1) #endif typedef struct _Uuid { uint32_t time_low; uint16_t time_mid; uint16_t time_high_and_version; uint8_t clock_seq_and_reserved; uint8_t clock_seq_low; uint8_t node[6]; } Uuid; /* * Connectionless */ typedef struct _DceRpcClHdr /* Connectionless header */ { uint8_t rpc_vers; uint8_t ptype; uint8_t flags1; uint8_t flags2; uint8_t drep[3]; uint8_t serial_hi; Uuid object; Uuid if_id; Uuid act_id; uint32_t server_boot; uint32_t if_vers; uint32_t seqnum; uint16_t opnum; uint16_t ihint; uint16_t ahint; uint16_t len; uint16_t fragnum; uint8_t auth_proto; uint8_t serial_lo; } DceRpcClHdr; /* ack PDU contains no body */ /* cancel PDU */ typedef struct _DceRpcClCancel { uint32_t vers; uint32_t cancel_id; } DceRpcClCancel; /* cancel_ack PDU */ typedef struct _DceRpcClCancelAck { uint32_t vers; uint32_t cancel_id; int server_is_accepting; } DceRpcClCancelAck; /* fack PDU */ typedef struct _DceRpcClFack { uint8_t vers; uint8_t pad1; uint16_t window_size; uint32_t max_tpdu; uint32_t max_frag_size; uint16_t serial_num; uint16_t selack_len; uint32_t selack[1]; /* variable length */ } DceRpcClFack; /* fault PDU */ typedef struct _DceRpcClFault { uint32_t status; /* status code */ } DceRpcClFault; /* nocall PDU (negative reply to ping) contains no body */ /* ping PDU contains no body */ /* reject PDU is the same as fack */ typedef DceRpcClFault DceRpcClReject; /* request PDU contains stub data as body */ /* response PDU contains stub data as body */ /* working PDU (positive reply to ping) contains no body */ /* * Connection oriented */ typedef struct _DceRpcCoVersion { uint8_t major; uint8_t minor; } DceRpcCoVersion; /* Connection oriented common header */ typedef struct _DceRpcCoHdr { DceRpcCoVersion pversion; uint8_t ptype; uint8_t pfc_flags; uint8_t packed_drep[4]; uint16_t frag_length; uint16_t auth_length; uint32_t call_id; } DceRpcCoHdr; /* Presentation syntax id */ typedef struct _DceRpcCoSynId { Uuid if_uuid; uint32_t if_version; } DceRpcCoSynId; /* Presentation context element */ typedef struct _DceRpcCoContElem { uint16_t p_cont_id; uint8_t n_transfer_syn; /* number of transfer syntaxes */ uint8_t reserved; DceRpcCoSynId abstract_syntax; #if 0 DceRpcCoSynId transfer_syntaxes[]; /* variable length */ #endif } DceRpcCoContElem; #if 0 /* Put this in the Bind header */ /* Presentation context list */ typedef struct _DceRpcCoContList { uint8_t n_context_elem; /* number of context elements */ uint8_t reserved; uint16_t reserved2; #if 0 DceRpcCoContElem p_cont_elem[]; /* variable length */ #endif } DceRpcCoContList; #endif /* Presentation result */ typedef struct _DceRpcCoContResult { uint16_t result; uint16_t reason; DceRpcCoSynId transfer_syntax; } DceRpcCoContResult; typedef struct _DceRpcCoContResultList { uint8_t n_results; uint8_t reserved; uint16_t reserved2; #if 0 DceRpcCoContResult p_results[]; /* variable length */ #endif } DceRpcCoContResultList; /* DCE version supported */ typedef struct _DceRpcCoVerSup { uint8_t n_protocols; /* number of protocols */ #if 0 DceRpcCoVersion protocols[]; /* variable length */ #endif } DceRpcCoVerSup; /* Bind */ typedef struct _DceRpcCoBind { uint16_t max_xmit_frag; uint16_t max_recv_frag; uint32_t assoc_group_id; uint8_t n_context_elem; /* number of context elements */ uint8_t reserved; uint16_t reserved2; #if 0 uint16_t p_cont_id; uint8_t n_tranfer_syn; /* number of transfer syntaxes */ uint8_t reserved; DceRpcCoSynId abstract_syntax; #endif #if 0 DceRpcCoContList p_context_elem_list; /* variable length */ auth_verifier_co_t auth_verifier; #endif } DceRpcCoBind; /* Bind response */ typedef struct _DceRpcCoBindAck { uint16_t max_xmit_frag; uint16_t max_recv_frag; uint32_t assoc_group_id; uint16_t sec_addr_len; #if 0 char sec_addr[]; /* variable length */ uint8_t pad2[align(4)]; /* this is really to align the above field whose last member is a variable len str. It will be 0-3 bytes long. */ DceRpcCoContResultList p_context_elem; aut_verifier_co_t auth_verifier; #endif } DceRpcCoBindAck; typedef DceRpcCoBind DceRpcCoAltCtx; typedef DceRpcCoBindAck DceRpcCoAltCtxResp; typedef struct _DceRpcCoBindNak { DceRpcCoBindNakReason provider_reject_reason; #if 0 DceRpcCoVerSup versions; /* variable length */ #endif } DceRpcCoBindNak; #if 0 typedef struct _DceRpcCoCancel { auth_verifier_co_t auth_verifier; } DceRpcCoCancel; #endif typedef struct _DceRpcCoFault { uint32_t alloc_hint; uint16_t context_id; uint8_t cancel_count; uint8_t reserved; uint32_t status; uint8_t reserved2[4]; #if 0 uint8_t stub data[] /* 8 octet aligned if auth_verifier, which will take care of the pad. */ auth_verifier_co_t auth_verifier; #endif } DceRpcCoFault; #if 0 typedef struct _DceRpcCoOrphaned { auth_verifier_co_t auth_verifier; } DceRpcCoOrphaned; #endif typedef struct _DceRpcCoRequest { uint32_t alloc_hint; uint16_t context_id; uint16_t opnum; #if 0 Uuid object; /* only if object flag is set */ uint8_t stub data[]; /* 8 octet aligned if auth_verifier, which will take care of the pad. */ auth_verifier_co_t auth_verifier; #endif } DceRpcCoRequest; typedef struct _DceRpcCoResponse { uint32_t alloc_hint; uint16_t context_id; uint8_t cancel_count; uint8_t reserved; #if 0 uint8_t stub data[] /* 8 octet aligned if auth_verifier, which will take care of the pad. */ auth_verifier_co_t auth_verifier; #endif } DceRpcCoResponse; #if 0 typedef struct _DceRpcCoShutdown { // nothing } DceRpcCoShutdown; #endif typedef struct _DceRpcCoAuthVerifier { #if 0 uint8_t auth_pad[]; /* variable length to restore 4 byte alignment */ #endif uint8_t auth_type; uint8_t auth_level; uint8_t auth_pad_length; uint8_t auth_reserved; uint32_t auth_context_id; #if 0 uint8_t auth_value[]; /* variable auth_length */ #endif } DceRpcCoAuthVerifier; /* Optional Data used with Reject/Disconnect header * These do not share the common header, but are special * cases (pretty much the same as the common header) */ typedef uint16_t DceRpcReasonCode; typedef struct _DceRpcCoOptData { DceRpcCoVersion pversion; uint8_t reserved[2]; uint8_t packed_drep[4]; uint32_t reject_status; uint8_t reserved2[4]; } DceRpcCoOptData; typedef struct _DceRpcCoRejHdr { DceRpcReasonCode reason_code; DceRpcCoOptData rpc_info; } DceRpcCoRejHdr; /* Disconnect header same as Reject header */ typedef DceRpcCoRejHdr DceRpcCoDiscHdr; #ifdef WIN32 #pragma pack(pop, dcerpc_hdrs) #else #pragma pack() #endif /******************************************************************** * Inline functions prototypes ********************************************************************/ static inline DceRpcBoFlag DceRpcByteOrder(const uint8_t); static inline uint16_t DceRpcNtohs(const uint16_t *, const DceRpcBoFlag); static inline uint16_t DceRpcHtons(const uint16_t *, const DceRpcBoFlag); static inline uint32_t DceRpcNtohl(const uint32_t *, const DceRpcBoFlag); static inline uint32_t DceRpcHtonl(const uint32_t *, const DceRpcBoFlag); /* Connectionless */ static inline uint8_t DceRpcClRpcVers(const DceRpcClHdr *); static inline DceRpcBoFlag DceRpcClByteOrder(const DceRpcClHdr *); static inline uint32_t DceRpcClIfaceVers(const DceRpcClHdr *); static inline uint16_t DceRpcClOpnum(const DceRpcClHdr *); static inline uint32_t DceRpcClSeqNum(const DceRpcClHdr *); static inline uint16_t DceRpcClFragNum(const DceRpcClHdr *); static inline int DceRpcClFragFlag(const DceRpcClHdr *); static inline int DceRpcClLastFrag(const DceRpcClHdr *); static inline int DceRpcClFirstFrag(const DceRpcClHdr *); static inline uint16_t DceRpcClLen(const DceRpcClHdr *); static inline int DceRpcClFrag(const DceRpcClHdr *); /* Connection oriented */ static inline uint8_t DceRpcCoVersMaj(const DceRpcCoHdr *); static inline uint8_t DceRpcCoVersMin(const DceRpcCoHdr *); static inline DceRpcPduType DceRpcCoPduType(const DceRpcCoHdr *); static inline int DceRpcCoFirstFrag(const DceRpcCoHdr *); static inline int DceRpcCoLastFrag(const DceRpcCoHdr *); static inline int DceRpcCoObjectFlag(const DceRpcCoHdr *); static inline DceRpcBoFlag DceRpcCoByteOrder(const DceRpcCoHdr *); static inline uint16_t DceRpcCoFragLen(const DceRpcCoHdr *); static inline uint16_t DceRpcCoAuthLen(const DceRpcCoHdr *); static inline uint32_t DceRpcCoCallId(const DceRpcCoHdr *); static inline uint16_t DceRpcCoCtxId(const DceRpcCoHdr *, const DceRpcCoRequest *); static inline uint16_t DceRpcCoCtxIdResp(const DceRpcCoHdr *, const DceRpcCoResponse *); static inline uint16_t DceRpcCoOpnum(const DceRpcCoHdr *, const DceRpcCoRequest *); static inline uint16_t DceRpcCoBindMaxXmitFrag(const DceRpcCoHdr *, const DceRpcCoBind *); static inline uint16_t DceRpcCoBindAckMaxRecvFrag(const DceRpcCoHdr *, const DceRpcCoBindAck *); static inline uint8_t DceRpcCoNumCtxItems(const DceRpcCoBind *); static inline uint16_t DceRpcCoContElemCtxId(const DceRpcCoHdr *, const DceRpcCoContElem *); static inline uint8_t DceRpcCoContElemNumTransSyntaxes(const DceRpcCoContElem *); static inline const Uuid * DceRpcCoContElemIface(const DceRpcCoContElem *); static inline uint16_t DceRpcCoContElemIfaceVersMaj(const DceRpcCoHdr *, const DceRpcCoContElem *); static inline uint16_t DceRpcCoContElemIfaceVersMin(const DceRpcCoHdr *, const DceRpcCoContElem *); static inline uint16_t DceRpcCoSecAddrLen(const DceRpcCoHdr *, const DceRpcCoBindAck *); static inline uint8_t DceRpcCoContNumResults(const DceRpcCoContResultList *); static inline uint16_t DceRpcCoContRes(const DceRpcCoHdr *, const DceRpcCoContResult *); static inline uint16_t DceRpcCoAuthPad(const DceRpcCoAuthVerifier *); static inline uint8_t DceRpcCoAuthLevel(const DceRpcCoAuthVerifier *); /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline DceRpcBoFlag DceRpcByteOrder(const uint8_t value) { if ((value & 0x10) >> 4) return DCERPC_BO_FLAG__LITTLE_ENDIAN; return DCERPC_BO_FLAG__BIG_ENDIAN; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcNtohs(const uint16_t *ptr, const DceRpcBoFlag bo_flag) { uint16_t value; if (ptr == NULL) return 0; #ifdef WORDS_MUSTALIGN value = *((uint8_t *)ptr) << 8 | *((uint8_t *)ptr + 1); #else value = *ptr; #endif /* WORDS_MUSTALIGN */ if (bo_flag == DCERPC_BO_FLAG__NONE) return value; #ifdef WORDS_BIGENDIAN if (bo_flag == DCERPC_BO_FLAG__BIG_ENDIAN) #else if (bo_flag == DCERPC_BO_FLAG__LITTLE_ENDIAN) #endif /* WORDS_BIGENDIAN */ return value; return ((value & 0xff00) >> 8) | ((value & 0x00ff) << 8); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcHtons(const uint16_t *ptr, const DceRpcBoFlag bo_flag) { return DceRpcNtohs(ptr, bo_flag); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint32_t DceRpcNtohl(const uint32_t *ptr, const DceRpcBoFlag bo_flag) { uint32_t value; if (ptr == NULL) return 0; #ifdef WORDS_MUSTALIGN value = *((uint8_t *)ptr) << 24 | *((uint8_t *)ptr + 1) << 16 | *((uint8_t *)ptr + 2) << 8 | *((uint8_t *)ptr + 3); #else value = *ptr; #endif /* WORDS_MUSTALIGN */ if (bo_flag == DCERPC_BO_FLAG__NONE) return value; #ifdef WORDS_BIGENDIAN if (bo_flag == DCERPC_BO_FLAG__BIG_ENDIAN) #else if (bo_flag == DCERPC_BO_FLAG__LITTLE_ENDIAN) #endif /* WORDS_BIGENDIAN */ return value; return ((value & 0xff000000) >> 24) | ((value & 0x00ff0000) >> 8) | ((value & 0x0000ff00) << 8) | ((value & 0x000000ff) << 24); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint32_t DceRpcHtonl(const uint32_t *ptr, const DceRpcBoFlag bo_flag) { return DceRpcNtohl(ptr, bo_flag); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint8_t DceRpcClRpcVers(const DceRpcClHdr *cl) { return cl->rpc_vers; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint8_t DceRpcClPduType(const DceRpcClHdr *cl) { return cl->ptype; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline DceRpcBoFlag DceRpcClByteOrder(const DceRpcClHdr *cl) { return DceRpcByteOrder(cl->drep[0]); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline const Uuid * DceRpcClIface(const DceRpcClHdr *cl) { return &cl->if_id; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint32_t DceRpcClIfaceVers(const DceRpcClHdr *cl) { return DceRpcNtohl(&cl->if_vers, DceRpcClByteOrder(cl)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcClOpnum(const DceRpcClHdr *cl) { return DceRpcNtohs(&cl->opnum, DceRpcClByteOrder(cl)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint32_t DceRpcClSeqNum(const DceRpcClHdr *cl) { return DceRpcNtohl(&cl->seqnum, DceRpcClByteOrder(cl)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcClFragNum(const DceRpcClHdr *cl) { return DceRpcNtohs(&cl->fragnum, DceRpcClByteOrder(cl)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DceRpcClFragFlag(const DceRpcClHdr *cl) { return cl->flags1 & DCERPC_CL_FLAGS1__FRAG; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DceRpcClLastFrag(const DceRpcClHdr *cl) { return cl->flags1 & DCERPC_CL_FLAGS1__LASTFRAG; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DceRpcClFirstFrag(const DceRpcClHdr *cl) { return (DceRpcClFragFlag(cl) && (DceRpcClFragNum(cl) == 0)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcClLen(const DceRpcClHdr *cl) { return DceRpcNtohs(&cl->len, DceRpcClByteOrder(cl)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DceRpcClFrag(const DceRpcClHdr *cl) { if (DceRpcClFragFlag(cl)) { if (DceRpcClLastFrag(cl) && (DceRpcClFragNum(cl) == 0)) return 0; return 1; } return 0; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint8_t DceRpcCoVersMaj(const DceRpcCoHdr *co) { return co->pversion.major; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint8_t DceRpcCoVersMin(const DceRpcCoHdr *co) { return co->pversion.minor; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline DceRpcPduType DceRpcCoPduType(const DceRpcCoHdr *co) { return (DceRpcPduType)co->ptype; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DceRpcCoFirstFrag(const DceRpcCoHdr *co) { return co->pfc_flags & DCERPC_CO_PFC_FLAGS__FIRST_FRAG; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DceRpcCoLastFrag(const DceRpcCoHdr *co) { return co->pfc_flags & DCERPC_CO_PFC_FLAGS__LAST_FRAG; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline int DceRpcCoObjectFlag(const DceRpcCoHdr *co) { return co->pfc_flags & DCERPC_CO_PFC_FLAGS__OBJECT_UUID; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline DceRpcBoFlag DceRpcCoByteOrder(const DceRpcCoHdr *co) { return DceRpcByteOrder(co->packed_drep[0]); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoFragLen(const DceRpcCoHdr *co) { return DceRpcNtohs(&co->frag_length, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoAuthLen(const DceRpcCoHdr *co) { return DceRpcNtohs(&co->auth_length, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint32_t DceRpcCoCallId(const DceRpcCoHdr *co) { return DceRpcNtohl(&co->call_id, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoOpnum(const DceRpcCoHdr *co, const DceRpcCoRequest *cor) { return DceRpcNtohs(&cor->opnum, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoCtxId(const DceRpcCoHdr *co, const DceRpcCoRequest *cor) { return DceRpcNtohs(&cor->context_id, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoCtxIdResp(const DceRpcCoHdr *co, const DceRpcCoResponse *cor) { return DceRpcNtohs(&cor->context_id, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoBindMaxXmitFrag(const DceRpcCoHdr *co, const DceRpcCoBind *cob) { return DceRpcNtohs(&cob->max_xmit_frag, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoBindAckMaxRecvFrag(const DceRpcCoHdr *co, const DceRpcCoBindAck *coba) { return DceRpcNtohs(&coba->max_recv_frag, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint8_t DceRpcCoNumCtxItems(const DceRpcCoBind *cob) { return cob->n_context_elem; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoContElemCtxId(const DceRpcCoHdr *co, const DceRpcCoContElem *coce) { return DceRpcNtohs(&coce->p_cont_id, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint8_t DceRpcCoContElemNumTransSyntaxes(const DceRpcCoContElem *coce) { return coce->n_transfer_syn; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline const Uuid * DceRpcCoContElemIface(const DceRpcCoContElem *coce) { return &coce->abstract_syntax.if_uuid; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoContElemIfaceVersMaj(const DceRpcCoHdr *co, const DceRpcCoContElem *coce) { return (uint16_t)(DceRpcNtohl(&coce->abstract_syntax.if_version, DceRpcCoByteOrder(co)) & 0x0000ffff); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoContElemIfaceVersMin(const DceRpcCoHdr *co, const DceRpcCoContElem *coce) { return (uint16_t)(DceRpcNtohl(&coce->abstract_syntax.if_version, DceRpcCoByteOrder(co)) >> 16); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoSecAddrLen(const DceRpcCoHdr *co, const DceRpcCoBindAck *coba) { return DceRpcNtohs(&coba->sec_addr_len, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint8_t DceRpcCoContNumResults(const DceRpcCoContResultList *cocrl) { return cocrl->n_results; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoContRes(const DceRpcCoHdr *co, const DceRpcCoContResult *cocr) { return DceRpcNtohs(&cocr->result, DceRpcCoByteOrder(co)); } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint16_t DceRpcCoAuthPad(const DceRpcCoAuthVerifier *coav) { return coav->auth_pad_length; } /******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ static inline uint8_t DceRpcCoAuthLevel(const DceRpcCoAuthVerifier *coav) { return coav->auth_level; } #endif /* DCERPC_H */ snort-2.9.6.0/src/dynamic-preprocessors/ssl/0000755000000000000000000000000012260606564015734 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/ssl/sf_ssl.dsp0000644000000000000000000001172512153454771017665 00000000000000# Microsoft Developer Studio Project File - Name="sf_ssl" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_ssl - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_ssl.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_ssl.mak" CFG="sf_ssl - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_ssl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_ssl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_ssl - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\\" /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "SF_SNORT_PREPROC_DLL" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib ../libs/Release/sfdynamic_preproc_libs.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_ssl - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\\" /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "SF_SNORT_PREPROC_DLL" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib ../libs/Debug/sfdynamic_preproc_libs.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_ssl - Win32 Release" # Name "sf_ssl - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\spp_ssl.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\spp_ssl.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/ssl/spp_ssl.h0000644000000000000000000000512512260565732017514 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2007-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Adam Keeton * spp_ssl.h * 10/10/07 */ #ifndef SPP_SSLPP_H #define SPP_SSLPP_H #include "sf_types.h" #include "sfcommon.h" #include "ssl.h" /* Prototypes for public interface */ extern void SetupSSLPP(void); /* Configuration flags */ #define SSLPP_DISABLE_FLAG 0x0001 #define SSLPP_TRUSTSERVER_FLAG 0x0002 typedef struct _SSLPP_config { ports_tbl_t ports; uint16_t flags; } SSLPP_config_t; typedef struct { /* * SSL preprocessor global configuration structure. */ SSLPP_config_t config; } tSslPolicyConfig; extern tSslPolicyConfig sslPolicyConfig[]; typedef struct _SSLPP_counters { uint64_t stopped; uint64_t disabled; uint64_t decoded; uint64_t alerts; uint64_t cipher_change; uint64_t unrecognized; uint64_t completed_hs; uint64_t bad_handshakes; uint64_t hs_chello; uint64_t hs_shello; uint64_t hs_cert; uint64_t hs_skey; uint64_t hs_ckey; uint64_t hs_finished; uint64_t hs_sdone; uint64_t capp; uint64_t sapp; } SSLPP_counters_t; #define SSLPP_TRUE 1 #define SSLPP_FALSE 0 #define SSLPP_ENCRYPTED_FLAGS (SSL_HS_SDONE_FLAG | SSL_CLIENT_KEYX_FLAG | \ SSL_CAPP_FLAG | SSL_SAPP_FLAG) #define SSLPP_ENCRYPTED_FLAGS2 (SSL_HS_SDONE_FLAG | SSL_CHANGE_CIPHER_FLAG | \ SSL_CAPP_FLAG | SSL_SAPP_FLAG) #define GENERATOR_SPP_SSLPP 137 #define SSL_INVALID_CLIENT_HELLO 1 #define SSL_INVALID_SERVER_HELLO 2 #define SSL_INVALID_CLIENT_HELLO_STR "(ssp_ssl) Invalid Client HELLO after Server HELLO Detected" #define SSL_INVALID_SERVER_HELLO_STR "(ssp_ssl) Invalid Server HELLO without Client HELLO Detected" #endif /* SPP_SSLPP_H */ snort-2.9.6.0/src/dynamic-preprocessors/ssl/spp_ssl.c0000644000000000000000000011605012260565732017507 00000000000000/* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2007-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * Adam Keeton * SSLPP Preprocessor * 10/10/07 * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_plugin_api.h" #include "snort_debug.h" #include "preprocids.h" #include "spp_ssl.h" #include "sf_preproc_info.h" #include #include #include #include #ifndef WIN32 #include #include #endif #include #include #include "profiler.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 4; const char *PREPROC_NAME = "SF_SSLPP"; #define SetupSSLPP DYNAMIC_PREPROC_SETUP #ifdef PERF_PROFILING PreprocStats sslpp_perf_stats; #endif #ifdef TARGET_BASED int16_t ssl_app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif /* Ultimately calls SnortEventqAdd */ /* Arguments are: gid, sid, rev, classification, priority, message, rule_info */ #define ALERT(x,y) { _dpd.alertAdd(GENERATOR_SPP_SSLPP, x, 1, 0, 3, y, 0 ); } /* Wraps disabling detect with incrementing the counter */ #define DISABLE_DETECT() { _dpd.disableDetect(packet); counts.disabled++; } static tSfPolicyUserContextId ssl_config = NULL; static SSLPP_counters_t counts; #ifdef SNORT_RELOAD static void SSLReload(struct _SnortConfig *, char *, void **); static int SSLReloadVerify(struct _SnortConfig *, void *); static void * SSLReloadSwap(struct _SnortConfig *, void *); static void SSLReloadSwapFree(void *); #endif static inline void SSLSetPort(SSLPP_config_t *, int); static void SSL_UpdateCounts(const uint32_t); #ifdef DEBUG_MSGS static void SSL_PrintFlags(uint32_t); #endif static void SSLFreeConfig(tSfPolicyUserContextId config); static void SSLCleanExit(int, void *); static void SSLResetStats(int, void *); static int SSLPP_CheckConfig(struct _SnortConfig *); static void _addPortsToStream5Filter(struct _SnortConfig *, SSLPP_config_t *, tSfPolicyId); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif typedef struct _SslRuleOptData { int flags; int mask; } SslRuleOptData; static inline int SSLPP_is_encrypted(uint32_t ssl_flags, SFSnortPacket *packet) { SSLPP_config_t *config = NULL; config = (SSLPP_config_t *)sfPolicyUserDataGetCurrent(ssl_config); if (config->flags & SSLPP_TRUSTSERVER_FLAG) { if(ssl_flags & SSL_SAPP_FLAG) return SSLPP_TRUE; } if (SSL_IS_CLEAN(ssl_flags)) { if (((ssl_flags & SSLPP_ENCRYPTED_FLAGS) == SSLPP_ENCRYPTED_FLAGS) || ((ssl_flags & SSLPP_ENCRYPTED_FLAGS2) == SSLPP_ENCRYPTED_FLAGS2)) { counts.completed_hs++; return SSLPP_TRUE; } /* Check if we're either midstream or if packets were missed after the * connection was established */ else if ((_dpd.streamAPI->get_session_flags (packet->stream_session_ptr) & SSNFLAG_MIDSTREAM) || (_dpd.streamAPI->missed_packets(packet->stream_session_ptr, SSN_DIR_BOTH))) { if ((ssl_flags & (SSL_CAPP_FLAG | SSL_SAPP_FLAG)) == (SSL_CAPP_FLAG | SSL_SAPP_FLAG)) { return SSLPP_TRUE; } } } return SSLPP_FALSE; } static inline uint32_t SSLPP_process_alert( uint32_t ssn_flags, uint32_t new_flags, SFSnortPacket *packet) { SSLPP_config_t *config = NULL; config = (SSLPP_config_t *)sfPolicyUserDataGetCurrent(ssl_config); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Alert\n");); ssn_flags |= new_flags; /* Check if we've seen a handshake, that this isn't it, * that the cipher flags is not set, and that we are disabling detection */ if(SSL_IS_HANDSHAKE(ssn_flags) && !SSL_IS_HANDSHAKE(new_flags) && !(new_flags & SSL_CHANGE_CIPHER_FLAG) && (config->flags & SSLPP_DISABLE_FLAG)) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Disabling detect\n");); DISABLE_DETECT(); } /* Need to negate the application flags from the opposing side. */ if(packet->flags & FLAG_FROM_CLIENT) return ssn_flags & ~SSL_SAPP_FLAG; else if(packet->flags & FLAG_FROM_SERVER) return ssn_flags & ~SSL_CAPP_FLAG; return ssn_flags; } static inline uint32_t SSLPP_process_hs(uint32_t ssl_flags, uint32_t new_flags) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Handshake\n");); if(!SSL_BAD_HS(new_flags)) { ssl_flags |= new_flags & (SSL_CLIENT_HELLO_FLAG | SSL_SERVER_HELLO_FLAG | SSL_CLIENT_KEYX_FLAG | SSL_SFINISHED_FLAG); } else { counts.bad_handshakes++; } return ssl_flags; } static inline uint32_t SSLPP_process_app( uint32_t ssn_flags, uint32_t new_flags, SFSnortPacket *packet) { SSLPP_config_t *config = NULL; config = (SSLPP_config_t *)sfPolicyUserDataGetCurrent(ssl_config); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Process Application\n");); if(!(config->flags & SSLPP_DISABLE_FLAG)) return ssn_flags | new_flags; if(SSLPP_is_encrypted(ssn_flags | new_flags, packet) ) { ssn_flags |= SSL_ENCRYPTED_FLAG; DEBUG_WRAP(DebugMessage(DEBUG_SSL, "STOPPING INSPECTION (process_app)\n");); _dpd.streamAPI->stop_inspection(packet->stream_session_ptr, packet, SSN_DIR_BOTH, -1, 0); counts.stopped++; } return ssn_flags | new_flags; } static inline void SSLPP_process_other( uint32_t ssn_flags, uint32_t new_flags, SFSnortPacket *packet) { SSLPP_config_t *config = NULL; config = (SSLPP_config_t *)sfPolicyUserDataGetCurrent(ssl_config); /* Encrypted SSLv2 will appear unrecognizable. Check if the handshake was * seen and stop inspecting if so. */ /* Check for an existing handshake from both sides */ if((ssn_flags & SSL_VER_SSLV2_FLAG) && SSL_IS_CHELLO(ssn_flags) && SSL_IS_SHELLO(ssn_flags) && (config->flags & SSLPP_DISABLE_FLAG) && !(new_flags & SSL_CHANGE_CIPHER_FLAG)) { ssn_flags |= SSL_ENCRYPTED_FLAG | new_flags; DEBUG_WRAP(DebugMessage(DEBUG_SSL, "STOPPING INSPECTION (process_other)\n");); _dpd.streamAPI->stop_inspection(packet->stream_session_ptr, packet, SSN_DIR_BOTH, -1, 0); } else { counts.unrecognized++; /* Special handling for SSLv2 */ if(new_flags & SSL_VER_SSLV2_FLAG) ssn_flags |= new_flags; if(new_flags & SSL_UNKNOWN_FLAG) ssn_flags |= new_flags; /* The following block is intentionally disabled. */ /* If we were unable to decode the packet, and previous packets had been * missed, we will not assume it is encrypted SSLv2. */ #if 0 /* More special handling for SSLv2. * If both server-side and client-side data was missed, and it has not * been identified it as TLS, it is possibly encrypted SSLv2. */ if( !(ssn_flags & ( SSL_VER_SSLV3_FLAG | SSL_VER_TLS10_FLAG | SSL_VER_TLS11_FLAG | SSL_VER_TLS12_FLAG)) ) { if(packet->stream_session_ptr && _dpd.streamAPI->missed_packets( packet->stream_session_ptr, SSN_DIR_FROM_SERVER) && _dpd.streamAPI->missed_packets( packet->stream_session_ptr, SSN_DIR_FROM_CLIENT) ) ssn_flags |= SSL_VER_SSLV2_FLAG; } #endif } /* Still need to set application data here because some of the ssn_flags * flags were cleared in SSL_CLEAR_TEMPORARY_FLAGS */ _dpd.streamAPI->set_application_data(packet->stream_session_ptr, PP_SSL, (void *)(uintptr_t)ssn_flags, NULL); } /* SSL Preprocessor process callback. */ static void SSLPP_process(void *raw_packet, void *context) { SFSnortPacket *packet; uint32_t ssn_flags; uint32_t new_flags; #ifdef TARGET_BASED int16_t app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif SSLPP_config_t *config = NULL; PROFILE_VARS; sfPolicyUserPolicySet (ssl_config, _dpd.getRuntimePolicy()); config = (SSLPP_config_t *)sfPolicyUserDataGetCurrent(ssl_config); if (config == NULL) return; DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL Start ================================\n");); packet = (SFSnortPacket*)raw_packet; // preconditions - what we registered for assert(IsTCP(packet)); // FIXTHIS need a new class to only run when data ahead of applications? if (!packet->payload || !packet->payload_size || !packet->stream_session_ptr) { #ifdef DEBUG_MSGS if (packet->payload == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Packet payload is NULL\n");); } if (packet->payload_size == 0) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Packet payload size is 0\n");); } if (packet->stream_session_ptr == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - No stream session pointer\n");); } DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Not inspecting packet\n");); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n");); #endif return; } #ifdef TARGET_BASED /* Check packet based on protocol number */ app_id = _dpd.streamAPI->get_application_protocol_id(packet->stream_session_ptr); if (app_id == SFTARGET_UNKNOWN_PROTOCOL) { return; } if (app_id && (app_id != ssl_app_id)) { return; } /* Fall back to port checking */ if (!app_id) { #endif /* Make sure the packet is on the right port */ if(!(config->ports[PORT_INDEX(packet->src_port)] & CONV_PORT(packet->src_port)) && !(config->ports[PORT_INDEX(packet->dst_port)] & CONV_PORT(packet->dst_port))) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL - Not configured for these ports\n");); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n");); return; } #ifdef TARGET_BASED } #endif #ifdef DEBUG_MSGS if (packet->flags & FLAG_FROM_SERVER) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Server packet\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Client packet\n");); } if (packet->flags & FLAG_REBUILT_STREAM) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Packet is rebuilt\n");); } #endif PREPROC_PROFILE_START(sslpp_perf_stats); ssn_flags = (uint32_t)(uintptr_t) _dpd.streamAPI->get_application_data(packet->stream_session_ptr, PP_SSL); /* Flush opposite direction to keep conversation in sync */ if (!(packet->flags & FLAG_REBUILT_STREAM)) { switch (_dpd.streamAPI->get_reassembly_direction(packet->stream_session_ptr)) { case SSN_DIR_FROM_SERVER: if (packet->flags & FLAG_FROM_SERVER) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Flushing server side\n");); _dpd.streamAPI->response_flush_stream(packet); } break; case SSN_DIR_FROM_CLIENT: if (packet->flags & FLAG_FROM_CLIENT) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Flushing client side\n");); _dpd.streamAPI->response_flush_stream(packet); } break; case SSN_DIR_BOTH: DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Flushing opposite side\n");); _dpd.streamAPI->response_flush_stream(packet); break; case SSN_DIR_NONE: default: break; } } #if 0 /* XXX If the preprocessor should in the future need to do any data * reassembly, one or the other of raw or reassembled needs to be used */ if (packet->flags & FLAG_STREAM_INSERT) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Packet is stream inserted - not inspecting\n");); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n");); return; } #endif #ifdef DEBUG_MSGS DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Ssn flags before ----------------------\n");); SSL_PrintFlags(ssn_flags); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "---------------------------------------\n");); #endif SSL_CLEAR_TEMPORARY_FLAGS(ssn_flags); #ifdef DEBUG_MSGS if (packet->payload_size >= 5) { const uint8_t *pkt = packet->payload; DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Five bytes of data: %02x %02x %02x %02x %02x\n", pkt[0], pkt[1], pkt[2], pkt[3], pkt[4]);); } else { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Payload size < 5 bytes");); } #endif new_flags = SSL_decode(packet->payload, (int)packet->payload_size, packet->flags, ssn_flags); // If the client used an SSLv2 ClientHello with an SSLv3/TLS version and // the server replied with an SSLv3/TLS ServerHello, remove the backward // compatibility flag and the SSLv2 flag since this session will continue // as SSLv3/TLS. if ((ssn_flags & SSL_V3_BACK_COMPAT_V2) && SSL_V3_SERVER_HELLO(new_flags)) ssn_flags &= ~(SSL_VER_SSLV2_FLAG|SSL_V3_BACK_COMPAT_V2); if( SSL_IS_CHELLO(new_flags) && SSL_IS_CHELLO(ssn_flags) && SSL_IS_SHELLO(ssn_flags) ) { ALERT(SSL_INVALID_CLIENT_HELLO, SSL_INVALID_CLIENT_HELLO_STR); } else if(!(config->flags & SSLPP_TRUSTSERVER_FLAG)) { if( (SSL_IS_SHELLO(new_flags) && !SSL_IS_CHELLO(ssn_flags) )) { if(!(_dpd.streamAPI->missed_packets( packet->stream_session_ptr, SSN_DIR_FROM_CLIENT))) ALERT(SSL_INVALID_SERVER_HELLO, SSL_INVALID_SERVER_HELLO_STR); } } counts.decoded++; #ifdef DEBUG_MSGS DEBUG_WRAP(DebugMessage(DEBUG_SSL, "New flags -----------------------------\n");); SSL_PrintFlags(new_flags); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "---------------------------------------\n");); #endif SSL_UpdateCounts(new_flags); /* Note, there can be multiple record types in each SSL packet. * Processing them in this order is intentional. If there is an * Alert, we don't care about the other records */ if(SSL_IS_ALERT(new_flags)) { ssn_flags = SSLPP_process_alert(ssn_flags, new_flags, packet); } else if(SSL_IS_HANDSHAKE(new_flags)) { ssn_flags = SSLPP_process_hs(ssn_flags, new_flags); } else if(SSL_IS_APP(new_flags)) { ssn_flags = SSLPP_process_app(ssn_flags, new_flags, packet); } else { /* Different record type that we don't care about. * Either it's a 'change cipher spec' or we failed to recognize the * record type. Do not update session data */ SSLPP_process_other(ssn_flags, new_flags, packet); /* Application data is updated inside of SSLPP_process_other */ PREPROC_PROFILE_END(sslpp_perf_stats); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n");); return; } ssn_flags |= new_flags; #ifdef DEBUG_MSGS DEBUG_WRAP(DebugMessage(DEBUG_SSL, "Ssn flags after -----------------------\n");); SSL_PrintFlags(ssn_flags); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "---------------------------------------\n");); #endif _dpd.streamAPI->set_application_data( packet->stream_session_ptr, PP_SSL, (void*)(uintptr_t)ssn_flags, NULL); PREPROC_PROFILE_END(sslpp_perf_stats); DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL End ================================\n");); } static void SSL_UpdateCounts(const uint32_t new_flags) { if(new_flags & SSL_CHANGE_CIPHER_FLAG) counts.cipher_change++; if (new_flags & SSL_ALERT_FLAG) counts.alerts++; if (new_flags & SSL_CLIENT_HELLO_FLAG) counts.hs_chello++; if (new_flags & SSL_SERVER_HELLO_FLAG) counts.hs_shello++; if (new_flags & SSL_CERTIFICATE_FLAG) counts.hs_cert++; if (new_flags & SSL_SERVER_KEYX_FLAG) counts.hs_skey++; if (new_flags & SSL_CLIENT_KEYX_FLAG) counts.hs_ckey++; if (new_flags & SSL_SFINISHED_FLAG) counts.hs_finished++; if (new_flags & SSL_HS_SDONE_FLAG) counts.hs_sdone++; if (new_flags & SSL_SAPP_FLAG) counts.sapp++; if (new_flags & SSL_CAPP_FLAG) counts.capp++; } /* Parsing for the ssl_state rule option */ static int SSLPP_state_init(struct _SnortConfig *sc, char *name, char *params, void **data) { int flags = 0, mask = 0; char *end = NULL; char *tok; SslRuleOptData *sdata; tok = strtok_r(params, ",", &end); if(!tok) DynamicPreprocessorFatalMessage("%s(%d) => missing argument to" "ssl_state keyword\n", *(_dpd.config_file), *(_dpd.config_line)); do { int negated = 0; if (tok[0] == '!') { negated = 1; tok++; } if(!strcasecmp("client_hello", tok)) { flags |= SSL_CUR_CLIENT_HELLO_FLAG; if (negated) mask |= SSL_CUR_CLIENT_HELLO_FLAG; } else if(!strcasecmp("server_hello", tok)) { flags |= SSL_CUR_SERVER_HELLO_FLAG; if (negated) mask |= SSL_CUR_SERVER_HELLO_FLAG; } else if(!strcasecmp("client_keyx", tok)) { flags |= SSL_CUR_CLIENT_KEYX_FLAG; if (negated) mask |= SSL_CUR_CLIENT_KEYX_FLAG; } else if(!strcasecmp("server_keyx", tok)) { flags |= SSL_CUR_SERVER_KEYX_FLAG; if (negated) mask |= SSL_CUR_SERVER_KEYX_FLAG; } else if(!strcasecmp("unknown", tok)) { flags |= SSL_UNKNOWN_FLAG; if (negated) mask |= SSL_UNKNOWN_FLAG; } else { DynamicPreprocessorFatalMessage( "%s(%d) => %s is not a recognized argument to %s.\n", *(_dpd.config_file), _dpd.config_file, tok, name); } } while( (tok = strtok_r(NULL, ",", &end)) != NULL ); sdata = (SslRuleOptData *)calloc(1, sizeof(*sdata)); if (sdata == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "ssl_state preprocessor rule option.\n"); } sdata->flags = flags; sdata->mask = mask; *data = (void *)sdata; return 1; } /* Parsing for the ssl_version rule option */ static int SSLPP_ver_init(struct _SnortConfig *sc, char *name, char *params, void **data) { int flags = 0, mask = 0; char *end = NULL; char *tok; SslRuleOptData *sdata; tok = strtok_r(params, ",", &end); if(!tok) DynamicPreprocessorFatalMessage("%s(%d) => missing argument to" "ssl_state keyword\n", *(_dpd.config_file), *(_dpd.config_line)); do { int negated = 0; if (tok[0] == '!') { negated = 1; tok++; } if(!strcasecmp("sslv2", tok)) { flags |= SSL_VER_SSLV2_FLAG; if (negated) mask |= SSL_VER_SSLV2_FLAG; } else if(!strcasecmp("sslv3", tok)) { flags |= SSL_VER_SSLV3_FLAG; if (negated) mask |= SSL_VER_SSLV3_FLAG; } else if(!strcasecmp("tls1.0", tok)) { flags |= SSL_VER_TLS10_FLAG; if (negated) mask |= SSL_VER_TLS10_FLAG; } else if(!strcasecmp("tls1.1", tok)) { flags |= SSL_VER_TLS11_FLAG; if (negated) mask |= SSL_VER_TLS11_FLAG; } else if(!strcasecmp("tls1.2", tok)) { flags |= SSL_VER_TLS12_FLAG; if (negated) mask |= SSL_VER_TLS12_FLAG; } else { DynamicPreprocessorFatalMessage( "%s(%d) => %s is not a recognized argument to %s.\n", *(_dpd.config_file), _dpd.config_file, tok, name); } } while( (tok = strtok_r(NULL, ",", &end)) != NULL ); sdata = (SslRuleOptData *)calloc(1, sizeof(*sdata)); if (sdata == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "ssl_version preprocessor rule option.\n"); } sdata->flags = flags; sdata->mask = mask; *data = (void *)sdata; return 1; } /* Rule option evaluation (for both rule options) */ static int SSLPP_rule_eval(void *raw_packet, const uint8_t **cursor, void *data) { int ssn_data; SFSnortPacket *p = (SFSnortPacket*)raw_packet; SslRuleOptData *sdata = (SslRuleOptData *)data; if (!p || !p->tcp_header || !p->stream_session_ptr || !data) return RULE_NOMATCH; ssn_data = (int)(uintptr_t)_dpd.streamAPI->get_application_data( p->stream_session_ptr, PP_SSL); if ((sdata->flags & ssn_data) ^ sdata->mask) return RULE_MATCH; return RULE_NOMATCH; } /* SSL Preprocessor configuration parsing */ static void SSLPP_config(SSLPP_config_t *config, char *conf) { char *saveptr; char *space_tok; char *comma_tok; char *portptr; char *search; SFP_errstr_t err; if(!conf) return; if (config == NULL) return; search = conf; while( (comma_tok = strtok_r(search, ",", &saveptr)) != NULL ) { search = NULL; space_tok = strtok_r(comma_tok, " ", &portptr); if(!space_tok) return; if(!strcasecmp(space_tok, "ports")) { memset(config->ports, 0, sizeof(config->ports)); if(SFP_ports(config->ports, portptr, err) != SFP_SUCCESS) DynamicPreprocessorFatalMessage( "%s(%d) => Failed to parse: %s\n", *(_dpd.config_file), *(_dpd.config_line), SFP_GET_ERR(err)); } else if(!strcasecmp(space_tok, "noinspect_encrypted")) { char *tmpChar; tmpChar = strtok_r(NULL, " \t\n", &portptr); if(tmpChar) { DynamicPreprocessorFatalMessage("%s(%d) => Invalid argument to the" " SSL preprocessor: '%s' in %s\n", *(_dpd.config_file), *(_dpd.config_line), space_tok, tmpChar); } config->flags |= SSLPP_DISABLE_FLAG; } else if(!strcasecmp(space_tok, "trustservers")) { char *tmpChar; tmpChar = strtok_r(NULL, " \t\n", &portptr); if(tmpChar) { DynamicPreprocessorFatalMessage("%s(%d) => Invalid argument to the" " SSL preprocessor: '%s' in %s\n", *(_dpd.config_file), *(_dpd.config_line), space_tok, tmpChar); } config->flags |= SSLPP_TRUSTSERVER_FLAG; } else { DynamicPreprocessorFatalMessage("%s(%d) => Invalid argument to the" " SSL preprocessor: '%s' in %s\n", *(_dpd.config_file), *(_dpd.config_line), comma_tok, conf); } } /* Verify configured options make sense */ if ((config->flags & SSLPP_TRUSTSERVER_FLAG) && !(config->flags & SSLPP_DISABLE_FLAG)) { DynamicPreprocessorFatalMessage("%s(%d) => SSL preprocessor: 'trustservers' " "requires 'noinspect_encrypted' to be useful.\n", *(_dpd.config_file), *(_dpd.config_line)); } } static void SSLPP_print_config(SSLPP_config_t *config) { char buf[1024]; /* For syslog printing */ int i; int newline; if (config == NULL) return; memset(buf, 0, sizeof(buf)); _dpd.logMsg("SSLPP config:\n"); _dpd.logMsg(" Encrypted packets: %s\n", config->flags & SSLPP_DISABLE_FLAG ? "not inspected" : "inspected"); _dpd.logMsg(" Ports:\n"); for(newline = 0, i = 0; i < MAXPORTS; i++) { if( config->ports[ PORT_INDEX(i) ] & CONV_PORT(i) ) { SFP_snprintfa(buf, sizeof(buf), " %5d", i); if( !((++newline) % 5) ) { SFP_snprintfa(buf, sizeof(buf), "\n"); _dpd.logMsg(buf); memset(buf, 0, sizeof(buf)); } } } if(newline % 5) SFP_snprintfa(buf, sizeof(buf), "\n"); _dpd.logMsg(buf); if ( config->flags & SSLPP_TRUSTSERVER_FLAG ) { _dpd.logMsg(" Server side data is trusted\n"); } } static void SSLPP_init_config(SSLPP_config_t *config) { if (config == NULL) return; /* Setup default ports */ SSLSetPort(config, 443); /* HTTPS */ SSLSetPort(config, 465); /* SMTPS */ SSLSetPort(config, 563); /* NNTPS */ SSLSetPort(config, 636); /* LDAPS */ SSLSetPort(config, 989); /* FTPS */ SSLSetPort(config, 992); /* TelnetS */ SSLSetPort(config, 993); /* IMAPS */ SSLSetPort(config, 994); /* IRCS */ SSLSetPort(config, 995); /* POPS */ } static inline void SSLSetPort(SSLPP_config_t *config, int port) { if (config == NULL) return; config->ports[ PORT_INDEX(port) ] |= CONV_PORT(port); } static void SSLPP_drop_stats(int exiting) { if(!counts.decoded) return; _dpd.logMsg("SSL Preprocessor:\n"); _dpd.logMsg(" SSL packets decoded: " FMTu64("-10") "\n", counts.decoded); _dpd.logMsg(" Client Hello: " FMTu64("-10") "\n", counts.hs_chello); _dpd.logMsg(" Server Hello: " FMTu64("-10") "\n", counts.hs_shello); _dpd.logMsg(" Certificate: " FMTu64("-10") "\n", counts.hs_cert); _dpd.logMsg(" Server Done: " FMTu64("-10") "\n", counts.hs_sdone); _dpd.logMsg(" Client Key Exchange: " FMTu64("-10") "\n", counts.hs_ckey); _dpd.logMsg(" Server Key Exchange: " FMTu64("-10") "\n", counts.hs_skey); _dpd.logMsg(" Change Cipher: " FMTu64("-10") "\n", counts.cipher_change); _dpd.logMsg(" Finished: " FMTu64("-10") "\n", counts.hs_finished); _dpd.logMsg(" Client Application: " FMTu64("-10") "\n", counts.capp); _dpd.logMsg(" Server Application: " FMTu64("-10") "\n", counts.sapp); _dpd.logMsg(" Alert: " FMTu64("-10") "\n", counts.alerts); _dpd.logMsg(" Unrecognized records: " FMTu64("-10") "\n", counts.unrecognized); _dpd.logMsg(" Completed handshakes: " FMTu64("-10") "\n", counts.completed_hs); _dpd.logMsg(" Bad handshakes: " FMTu64("-10") "\n", counts.bad_handshakes); _dpd.logMsg(" Sessions ignored: " FMTu64("-10") "\n", counts.stopped); _dpd.logMsg(" Detection disabled: " FMTu64("-10") "\n", counts.disabled); } static void SSLPP_init(struct _SnortConfig *sc, char *args) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); SSLPP_config_t *pPolicyConfig = NULL; if (ssl_config == NULL) { //create a context ssl_config = sfPolicyConfigCreate(); if (ssl_config == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "SSL preprocessor configuration.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage( "SSLPP_init(): The Stream preprocessor must be enabled.\n"); } memset(&counts, 0, sizeof(counts)); _dpd.registerPreprocStats("ssl", SSLPP_drop_stats); _dpd.addPreprocConfCheck(sc, SSLPP_CheckConfig); _dpd.addPreprocExit(SSLCleanExit, NULL, PRIORITY_LAST, PP_SSL); _dpd.addPreprocResetStats(SSLResetStats, NULL, PRIORITY_LAST, PP_SSL); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("ssl", (void *)&sslpp_perf_stats, 0, _dpd.totalPerfStats); #endif #ifdef TARGET_BASED ssl_app_id = _dpd.findProtocolReference("ssl"); if (ssl_app_id == SFTARGET_UNKNOWN_PROTOCOL) { ssl_app_id = _dpd.addProtocolReference("ssl"); } #endif } sfPolicyUserPolicySet (ssl_config, policy_id); pPolicyConfig = (SSLPP_config_t *)sfPolicyUserDataGetCurrent(ssl_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("SSL preprocessor can only be " "configured once.\n"); } pPolicyConfig = (SSLPP_config_t *)calloc(1, sizeof(SSLPP_config_t)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "SSL preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(ssl_config, pPolicyConfig); SSLPP_init_config(pPolicyConfig); SSLPP_config(pPolicyConfig, args); SSLPP_print_config(pPolicyConfig); _dpd.preprocOptRegister(sc, "ssl_state", SSLPP_state_init, SSLPP_rule_eval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, "ssl_version", SSLPP_ver_init, SSLPP_rule_eval, free, NULL, NULL, NULL, NULL); _dpd.addPreproc( sc, SSLPP_process, PRIORITY_TUNNEL, PP_SSL, PROTO_BIT__TCP ); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } void SetupSSLPP(void) { #ifndef SNORT_RELOAD _dpd.registerPreproc( "ssl", SSLPP_init); #else _dpd.registerPreproc("ssl", SSLPP_init, SSLReload, SSLReloadVerify, SSLReloadSwap, SSLReloadSwapFree); #endif } #ifdef DEBUG_MSGS static void SSL_PrintFlags(uint32_t flags) { if (flags & SSL_CHANGE_CIPHER_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CHANGE_CIPHER_FLAG\n");); } if (flags & SSL_ALERT_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_ALERT_FLAG\n");); } if (flags & SSL_POSSIBLE_HS_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_POSSIBLE_HS_FLAG\n");); } if (flags & SSL_CLIENT_HELLO_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CLIENT_HELLO_FLAG\n");); } if (flags & SSL_SERVER_HELLO_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_SERVER_HELLO_FLAG\n");); } if (flags & SSL_CERTIFICATE_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CERTIFICATE_FLAG\n");); } if (flags & SSL_SERVER_KEYX_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_SERVER_KEYX_FLAG\n");); } if (flags & SSL_CLIENT_KEYX_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CLIENT_KEYX_FLAG\n");); } if (flags & SSL_CIPHER_SPEC_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CIPHER_SPEC_FLAG\n");); } if (flags & SSL_SFINISHED_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_SFINISHED_FLAG\n");); } if (flags & SSL_SAPP_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_SAPP_FLAG\n");); } if (flags & SSL_CAPP_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CAPP_FLAG\n");); } if (flags & SSL_HS_SDONE_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_HS_SDONE_FLAG\n");); } if (flags & SSL_POSSIBLY_ENC_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_POSSIBLY_ENC_FLAG\n");); } if (flags & SSL_VER_SSLV2_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_VER_SSLV2_FLAG\n");); } if (flags & SSL_VER_SSLV3_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_VER_SSLV3_FLAG\n");); } if (flags & SSL_VER_TLS10_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_VER_TLS10_FLAG\n");); } if (flags & SSL_VER_TLS11_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_VER_TLS11_FLAG\n");); } if (flags & SSL_VER_TLS12_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_VER_TLS12_FLAG\n");); } #if 0 SSL_VERFLAGS (SSL_VER_SSLV2_FLAG | SSL_VER_SSLV3_FLAG | \ SSL_VER_TLS10_FLAG | SSL_VER_TLS11_FLAG | \ SSL_VER_TLS12_FLAG) #endif if (flags & SSL_CUR_CLIENT_HELLO_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CUR_CLIENT_HELLO_FLAG\n");); } if (flags & SSL_CUR_SERVER_HELLO_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CUR_SERVER_HELLO_FLAG\n");); } if (flags & SSL_CUR_SERVER_KEYX_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CUR_SERVER_KEYX_FLAG\n");); } if (flags & SSL_CUR_CLIENT_KEYX_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_CUR_CLIENT_KEYX_FLAG\n");); } if (flags & SSL_ENCRYPTED_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_ENCRYPTED_FLAG\n");); } if (flags & SSL_UNKNOWN_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_UNKNOWN_FLAG\n");); } #if 0 SSL_STATEFLAGS (SSL_CUR_CLIENT_HELLO_FLAG | SSL_CUR_SERVER_HELLO_FLAG | \ SSL_CUR_SERVER_KEYX_FLAG | SSL_CUR_CLIENT_KEYX_FLAG | \ SSL_UNKNOWN_FLAG) #endif if (flags & SSL_BOGUS_HS_DIR_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_BOGUS_HS_DIR_FLAG\n");); } if (flags & SSL_TRAILING_GARB_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_TRAILING_GARB_FLAG\n");); } if (flags & SSL_BAD_TYPE_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_BAD_TYPE_FLAG\n");); } if (flags & SSL_BAD_VER_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_BAD_VER_FLAG\n");); } if (flags & SSL_TRUNCATED_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_TRUNCATED_FLAG\n");); } if (flags == SSL_ARG_ERROR_FLAG) { DEBUG_WRAP(DebugMessage(DEBUG_SSL, "SSL_ARG_ERROR_FLAG\n");); } } #endif static void _addPortsToStream5Filter(struct _SnortConfig *sc, SSLPP_config_t *config, tSfPolicyId policy_id) { unsigned int portNum; if (config == NULL) return; for (portNum = 0; portNum < MAXPORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status (sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status (sc, ssl_app_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif static int SSLFreeConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SSLPP_config_t *pPolicyConfig = (SSLPP_config_t *)pData; //do any housekeeping before freeing SSLPP_config_t sfPolicyUserDataClear (config, policyId); free(pPolicyConfig); return 0; } static void SSLFreeConfig(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, SSLFreeConfigPolicy); sfPolicyConfigDelete(config); } static void SSLCleanExit(int signal, void *data) { if (ssl_config != NULL) { SSLFreeConfig(ssl_config); ssl_config = NULL; } } static void SSLResetStats(int signal, void *data) { memset(&counts, 0, sizeof(counts)); } static int SSLPP_CheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { _dpd.setParserPolicy(sc, policyId); if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg( "SSLPP_CheckPolicyConfig(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } static int SSLPP_CheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate (sc, ssl_config, SSLPP_CheckPolicyConfig))) return rval; return 0; } #ifdef SNORT_RELOAD static void SSLReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId ssl_swap_config = (tSfPolicyUserContextId)*new_config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); SSLPP_config_t * pPolicyConfig = NULL; if (ssl_swap_config == NULL) { //create a context ssl_swap_config = sfPolicyConfigCreate(); if (ssl_swap_config == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "SSL preprocessor configuration.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage( "SSLPP_init(): The Stream preprocessor must be enabled.\n"); } *new_config = (void *)ssl_swap_config; } sfPolicyUserPolicySet (ssl_swap_config, policy_id); pPolicyConfig = (SSLPP_config_t *)sfPolicyUserDataGetCurrent(ssl_swap_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("SSL preprocessor can only be " "configured once.\n"); } pPolicyConfig = (SSLPP_config_t *)calloc(1, sizeof(SSLPP_config_t)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for the " "SSL preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(ssl_swap_config, pPolicyConfig); SSLPP_init_config(pPolicyConfig); SSLPP_config(pPolicyConfig, args); SSLPP_print_config(pPolicyConfig); _dpd.preprocOptRegister(sc, "ssl_state", SSLPP_state_init, SSLPP_rule_eval, free, NULL, NULL, NULL, NULL); _dpd.preprocOptRegister(sc, "ssl_version", SSLPP_ver_init, SSLPP_rule_eval, free, NULL, NULL, NULL, NULL); _dpd.addPreproc(sc, SSLPP_process, PRIORITY_TUNNEL, PP_SSL, PROTO_BIT__TCP); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } static int SSLReloadVerify(struct _SnortConfig *sc, void *swap_config) { if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SSLPP_init(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } static void * SSLReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId ssl_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = ssl_config; if (ssl_swap_config == NULL) return NULL; ssl_config = ssl_swap_config; return (void *)old_config; } static void SSLReloadSwapFree(void *data) { if (data == NULL) return; SSLFreeConfig((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/ssl/Makefile.am0000644000000000000000000000151211746560364017714 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_ssl_preproc.la libsf_ssl_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_ssl_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_ssl_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sfPolicyUserData.c endif libsf_ssl_preproc_la_SOURCES = \ spp_ssl.c \ spp_ssl.h \ ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c \ ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.h \ ${top_srcdir}/src/dynamic-preprocessors/libs/sfparser.c \ ${top_srcdir}/src/dynamic-preprocessors/libs/sfcommon.h EXTRA_DIST = \ sf_ssl.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/ssl/Makefile.in0000644000000000000000000005245212260606523017724 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/ssl DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_ssl_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_ssl_preproc_la_OBJECTS = spp_ssl.lo ssl.lo sfparser.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_ssl_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_ssl_preproc_la_OBJECTS = $(am_libsf_ssl_preproc_la_OBJECTS) \ $(nodist_libsf_ssl_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_ssl_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_ssl_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_ssl_preproc_la_SOURCES) \ $(nodist_libsf_ssl_preproc_la_SOURCES) DIST_SOURCES = $(libsf_ssl_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_ssl_preproc.la libsf_ssl_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_ssl_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_ssl_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_ssl_preproc_la_SOURCES = \ spp_ssl.c \ spp_ssl.h \ ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c \ ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.h \ ${top_srcdir}/src/dynamic-preprocessors/libs/sfparser.c \ ${top_srcdir}/src/dynamic-preprocessors/libs/sfcommon.h EXTRA_DIST = \ sf_ssl.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/ssl/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/ssl/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_ssl_preproc.la: $(libsf_ssl_preproc_la_OBJECTS) $(libsf_ssl_preproc_la_DEPENDENCIES) $(EXTRA_libsf_ssl_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_ssl_preproc_la_LINK) -rpath $(libdir) $(libsf_ssl_preproc_la_OBJECTS) $(libsf_ssl_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< ssl.lo: ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ssl.lo `test -f '${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c' || echo '$(srcdir)/'`${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c sfparser.lo: ${top_srcdir}/src/dynamic-preprocessors/libs/sfparser.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfparser.lo `test -f '${top_srcdir}/src/dynamic-preprocessors/libs/sfparser.c' || echo '$(srcdir)/'`${top_srcdir}/src/dynamic-preprocessors/libs/sfparser.c sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/dns/0000755000000000000000000000000012260606564015717 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/dns/sf_dns.dsp0000755000000000000000000001154712153454770017637 00000000000000# Microsoft Developer Studio Project File - Name="sf_dns" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_dns - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_dns.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_dns.mak" CFG="sf_dns - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_dns - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_dns - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_dns - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_dns - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_dns - Win32 Release" # Name "sf_dns - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\spp_dns.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\spp_dns.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/dns/spp_dns.h0000644000000000000000000002060412260565732017461 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * spp_dns.h: Definitions, structs, function prototype(s) for * the DNS preprocessor. * Author: Steven Sturges */ #ifndef SPP_DNS_H #define SPP_DNS_H #define MAX_PORTS 65536 /* * Default DNS port */ #define DNS_PORT 53 /* * Error codes. */ #define DNS_SUCCESS 1 #define DNS_FAILURE 0 /* * Directional defines */ #define DNS_DIR_FROM_SERVER 1 #define DNS_DIR_FROM_CLIENT 2 /* * Global DNS preprocessor configuration. * * autodetect: Whether or not to apply auto-detection of DNS * to ports other than those configured. * enabled_alerts: Bit vector describing which alerts are enabled. */ typedef struct _DNSConfig { #if 0 uint8_t autodetect; #endif uint16_t enabled_alerts; char ports[MAX_PORTS/8]; } DNSConfig; /****** A few data structures ******/ typedef struct _DNSHdr { uint16_t id; uint16_t flags; uint16_t questions; uint16_t answers; uint16_t authorities; uint16_t additionals; } DNSHdr; #define DNS_HDR_FLAG_REPLY_CODE_MASK 0x000F #define DNS_HDR_FLAG_NON_AUTHENTICATED_OK 0x0010 #define DNS_HDR_FLAG_ANS_AUTHENTICATED 0x0020 #define DNS_HDR_FLAG_RESERVED 0x0040 #define DNS_HDR_FLAG_RECURSION_AVAIL 0x0080 #define DNS_HDR_FLAG_RECURSION_DESIRED 0x0100 #define DNS_HDR_FLAG_TRUNCATED 0x0200 #define DNS_HDR_FLAG_AUTHORITATIVE 0x0400 #define DNS_HDR_FLAG_OPCODE_MASK 0x7800 #define DNS_HDR_FLAG_RESPONSE 0x8000 typedef struct _DNSQuestion { uint16_t type; uint16_t dns_class; } DNSQuestion; typedef struct _DNSRR { uint16_t type; uint16_t dns_class; uint32_t ttl; uint16_t length; } DNSRR; typedef struct _DNSNameState { uint32_t txt_count; uint32_t total_txt_len; uint8_t txt_len; uint8_t txt_bytes_seen; uint8_t name_state; uint8_t alerted; uint16_t offset; uint8_t relative; } DNSNameState; #define DNS_RR_TYPE_A 0x0001 #define DNS_RR_TYPE_NS 0x0002 #define DNS_RR_TYPE_MD 0x0003 /* obsolete */ #define DNS_RR_TYPE_MF 0x0004 /* obsolete */ #define DNS_RR_TYPE_CNAME 0x0005 #define DNS_RR_TYPE_SOA 0x0006 #define DNS_RR_TYPE_MB 0x0007 /* experimental */ #define DNS_RR_TYPE_MG 0x0008 /* experimental */ #define DNS_RR_TYPE_MR 0x0009 /* experimental */ #define DNS_RR_TYPE_NULL 0x000a /* experimental */ #define DNS_RR_TYPE_WKS 0x000b #define DNS_RR_TYPE_PTR 0x000c #define DNS_RR_TYPE_HINFO 0x000d #define DNS_RR_TYPE_MINFO 0x000e /* experimental */ #define DNS_RR_TYPE_MX 0x000f #define DNS_RR_TYPE_TXT 0x0010 /* * Per-session data block containing current state * of the DNS preprocessor for the session. * * state: The current state of the session. * num_records: Number of records in the session. * curr_record: Record number for the current record * curr_record_length: Current record length. * total_record_length: Total data length of records. * length: Total length of DNS response (TCP only) * hdr: Copy of the data from the DNS Header */ typedef struct _DNSSessionData { uint32_t state; uint16_t curr_rec; uint16_t curr_rec_length; uint16_t bytes_seen_curr_rec; uint16_t length; uint8_t curr_rec_state; DNSHdr hdr; DNSQuestion curr_q; DNSRR curr_rr; DNSNameState curr_txt; uint8_t flags; } DNSSessionData; #define DNS_FLAG_NOT_DNS 0x01 /* DNSSessionData States */ #define DNS_RESP_STATE_LENGTH 0x00 /* 2 bytes - TCP only*/ #define DNS_RESP_STATE_LENGTH_PART 0x01 /* Partial length */ #define DNS_RESP_STATE_HDR 0x10 /* 12 bytes */ #define DNS_RESP_STATE_HDR_ID 0x11 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_ID_PART 0x12 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_FLAGS 0x13 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_FLAGS_PART 0x14 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_QS 0x15 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_QS_PART 0x16 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_ANSS 0x17 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_ANSS_PART 0x18 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_AUTHS 0x19 /* (2 bytes) */ #define DNS_RESP_STATE_HDR_AUTHS_PART 0x1a /* (2 bytes) */ #define DNS_RESP_STATE_HDR_ADDS 0x1b /* (2 bytes) */ #define DNS_RESP_STATE_HDR_ADDS_PART 0x1c /* (2 bytes) */ #define DNS_RESP_STATE_QUESTION 0x20 /* 4 bytes */ #define DNS_RESP_STATE_Q_NAME 0x21 /* (size depends on data) */ #define DNS_RESP_STATE_Q_NAME_COMPLETE 0x22 /* (size depends on data) */ #define DNS_RESP_STATE_Q_TYPE 0x23 /* (2 bytes) */ #define DNS_RESP_STATE_Q_TYPE_PART 0x24 /* (2 bytes) */ #define DNS_RESP_STATE_Q_CLASS 0x25 /* (2 bytes) */ #define DNS_RESP_STATE_Q_CLASS_PART 0x26 /* (2 bytes) */ #define DNS_RESP_STATE_Q_COMPLETE 0x27 #define DNS_RESP_STATE_NAME_SIZE 0x31 /* (1 byte) */ #define DNS_RESP_STATE_NAME 0x32 /* (size depends on field) */ #define DNS_RESP_STATE_NAME_COMPLETE 0x33 #define DNS_RESP_STATE_ANS_RR 0x40 /* (size depends on field) */ #define DNS_RESP_STATE_RR_NAME_SIZE 0x41 /* (1 byte) */ #define DNS_RESP_STATE_RR_NAME 0x42 /* (size depends on field) */ #define DNS_RESP_STATE_RR_NAME_COMPLETE 0x43 #define DNS_RESP_STATE_RR_TYPE 0x44 /* (2 bytes) */ #define DNS_RESP_STATE_RR_TYPE_PART 0x45 /* (2 bytes) */ #define DNS_RESP_STATE_RR_CLASS 0x46 /* (2 bytes) */ #define DNS_RESP_STATE_RR_CLASS_PART 0x47 /* (2 bytes) */ #define DNS_RESP_STATE_RR_TTL 0x48 /* (4 bytes) */ #define DNS_RESP_STATE_RR_TTL_PART 0x49 /* (4 bytes) */ #define DNS_RESP_STATE_RR_RDLENGTH 0x4a /* (2 bytes) */ #define DNS_RESP_STATE_RR_RDLENGTH_PART 0x4b /* (2 bytes) */ #define DNS_RESP_STATE_RR_RDATA_START 0x4c /* (size depends on RDLENGTH) */ #define DNS_RESP_STATE_RR_RDATA_MID 0x4d /* (size depends on RDLENGTH) */ #define DNS_RESP_STATE_RR_COMPLETE 0x4e #define DNS_RESP_STATE_AUTH_RR 0x50 #define DNS_RESP_STATE_ADD_RR 0x60 /* * Keyword strings for parsing configuration options. */ #define DNS_PORTS_KEYWORD "ports" #if 0 #define DNS_AUTODETECT_KEYWORD "autodetect" #endif #define DNS_ENABLE_OBSOLETE_TYPES_KEYWORD "enable_obsolete_types" #define DNS_ENABLE_EXPERIMENTAL_TYPES_KEYWORD "enable_experimental_types" #define DNS_ENABLE_RDATA_OVERFLOW_KEYWORD "enable_rdata_overflow" /* * DNS preprocessor alert types. */ #define DNS_EVENT_OBSOLETE_TYPES 1 #define DNS_EVENT_EXPERIMENTAL_TYPES 2 #define DNS_EVENT_RDATA_OVERFLOW 3 /* * DNS alert flags */ #define DNS_ALERT_NONE 0x0 #define DNS_ALERT_OBSOLETE_TYPES 0x1 #define DNS_ALERT_EXPERIMENTAL_TYPES 0x2 #define DNS_ALERT_RDATA_OVERFLOW 0x4 #define DNS_ALERT_ALL 0xFFFF /* * DNS preprocessor alert strings. */ #define DNS_EVENT_OBSOLETE_TYPES_STR "(spp_dns) Obsolete DNS RR Types" #define DNS_EVENT_EXPERIMENTAL_TYPES_STR "(spp_dns) Experimental DNS RR Types" #define DNS_EVENT_RDATA_OVERFLOW_STR "(spp_dns) DNS Client rdata txt Overflow" /* Prototypes for public interface */ extern void SetupDNS(void); #endif /* SPP_DNS_H */ snort-2.9.6.0/src/dynamic-preprocessors/dns/spp_dns.c0000644000000000000000000015515412260565732017465 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2006-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * DNS preprocessor * Author: Steven Sturges * * * Alert for DNS client rdata buffer overflow. * Alert for Obsolete or Experimental RData types (per RFC 1035) * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_STRINGS_H #include #endif #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "preprocids.h" #include "snort_debug.h" #include "spp_dns.h" #include "sf_preproc_info.h" #include #include #include #include #ifndef WIN32 #include #endif #include #include #include "profiler.h" #ifdef PERF_PROFILING PreprocStats dnsPerfStats; #endif #include "sf_types.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "snort_bounds.h" #ifdef TARGET_BASED int16_t dns_app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 4; const char *PREPROC_NAME = "SF_DNS"; #define SetupDNS DYNAMIC_PREPROC_SETUP /* * Generator id. Define here the same as the official registry * in generators.h */ #define GENERATOR_SPP_DNS 131 /* * Function prototype(s) */ DNSSessionData * GetDNSSessionData(SFSnortPacket *, DNSConfig *); static void DNSInit( struct _SnortConfig *, char* ); static void PrintDNSConfig(DNSConfig *); static void FreeDNSSessionData( void* ); static void ParseDNSArgs(DNSConfig *, u_char*); static void ProcessDNS( void*, void* ); static inline int CheckDNSPort(DNSConfig *, uint16_t); static void DNSReset(int, void *); static void DNSResetStats(int, void *); static void _addPortsToStream5Filter(struct _SnortConfig *, DNSConfig *, tSfPolicyId); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static void DNSFreeConfig(tSfPolicyUserContextId config); static int DNSCheckConfig(struct _SnortConfig *); static void DNSCleanExit(int, void *); /* Ultimately calls SnortEventqAdd */ /* Arguments are: gid, sid, rev, classification, priority, message, rule_info */ #define DNS_ALERT(x,y) { _dpd.alertAdd(GENERATOR_SPP_DNS, x, 1, 0, 3, y, 0 ); } /* Convert port value into an index for the dns_config ports array */ #define PORT_INDEX(port) port/8 /* Convert port value into a value for bitwise operations */ #define CONV_PORT(port) 1<<(port%8) #define DNS_RR_PTR 0xC0 static tSfPolicyUserContextId dns_config = NULL; DNSConfig *dns_eval_config = NULL; #ifdef SNORT_RELOAD static void DNSReload(struct _SnortConfig *, char *, void **); static int DNSReloadVerify(struct _SnortConfig *, void *); static void * DNSReloadSwap(struct _SnortConfig *, void *); static void DNSReloadSwapFree(void *); #endif /* Called at preprocessor setup time. Links preprocessor keyword * to corresponding preprocessor initialization function. * * PARAMETERS: None. * * RETURNS: Nothing. * */ void SetupDNS(void) { /* Link preprocessor keyword to initialization function * in the preprocessor list. */ #ifndef SNORT_RELOAD _dpd.registerPreproc( "dns", DNSInit ); #else _dpd.registerPreproc("dns", DNSInit, DNSReload, DNSReloadVerify, DNSReloadSwap, DNSReloadSwapFree); #endif } /* Initializes the DNS preprocessor module and registers * it in the preprocessor list. * * PARAMETERS: * * argp: Pointer to argument string to process for config * data. * * RETURNS: Nothing. */ static void DNSInit( struct _SnortConfig *sc, char* argp ) { int policy_id = _dpd.getParserPolicy(sc); DNSConfig *pPolicyConfig = NULL; if (dns_config == NULL) { //create a context dns_config = sfPolicyConfigCreate(); if (dns_config == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "DNS configuration.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Dns preprocessor requires the " "stream5 preprocessor to be enabled.\n", *(_dpd.config_file), *(_dpd.config_line)); } _dpd.addPreprocReset(DNSReset, NULL, PRIORITY_LAST, PP_DNS); _dpd.addPreprocResetStats(DNSResetStats, NULL, PRIORITY_LAST, PP_DNS); _dpd.addPreprocConfCheck(sc, DNSCheckConfig); _dpd.addPreprocExit(DNSCleanExit, NULL, PRIORITY_LAST, PP_DNS); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("dns", (void *)&dnsPerfStats, 0, _dpd.totalPerfStats); #endif #ifdef TARGET_BASED dns_app_id = _dpd.findProtocolReference("dns"); if (dns_app_id == SFTARGET_UNKNOWN_PROTOCOL) { dns_app_id = _dpd.addProtocolReference("dns"); } #endif } sfPolicyUserPolicySet (dns_config, policy_id); pPolicyConfig = (DNSConfig *)sfPolicyUserDataGetCurrent(dns_config); if (pPolicyConfig) { DynamicPreprocessorFatalMessage("%s(%d) Dns preprocessor can only " "be configured once.\n", *(_dpd.config_file), *(_dpd.config_line)); } pPolicyConfig = (DNSConfig *)calloc(1, sizeof(DNSConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "DNS configuration.\n"); } sfPolicyUserDataSetCurrent(dns_config, pPolicyConfig); ParseDNSArgs(pPolicyConfig, (u_char *)argp); _dpd.addPreproc(sc, ProcessDNS, PRIORITY_APPLICATION, PP_DNS, PROTO_BIT__TCP | PROTO_BIT__UDP); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } /* Parses and processes the configuration arguments * supplied in the DNS preprocessor rule. * * PARAMETERS: * * argp: Pointer to string containing the config arguments. * * RETURNS: Nothing. */ static void ParseDNSArgs(DNSConfig *config, u_char* argp) { char* cur_tokenp = NULL; char* argcpyp = NULL; int port; if (config == NULL) return; /* Set up default port to listen on */ config->ports[ PORT_INDEX( DNS_PORT ) ] |= CONV_PORT(DNS_PORT); /* Sanity check(s) */ if ( !argp ) { PrintDNSConfig(config); return; } argcpyp = strdup( (char*) argp ); if ( !argcpyp ) { DynamicPreprocessorFatalMessage("Could not allocate memory to parse DNS options.\n"); return; } cur_tokenp = strtok( argcpyp, " "); while ( cur_tokenp ) { if ( !strcmp( cur_tokenp, DNS_PORTS_KEYWORD )) { /* If the user specified ports, remove 'DNS_PORT' for now since * it now needs to be set explicitely. */ config->ports[ PORT_INDEX( DNS_PORT ) ] = 0; /* Eat the open brace. */ cur_tokenp = strtok( NULL, " "); if (( !cur_tokenp ) || ( strcmp(cur_tokenp, "{" ))) { DynamicPreprocessorFatalMessage("%s(%d) Bad value specified for %s. Must start " "with '{' and be space seperated.\n", *(_dpd.config_file), *(_dpd.config_line), DNS_PORTS_KEYWORD); //free(argcpyp); //return; } cur_tokenp = strtok( NULL, " "); while (( cur_tokenp ) && strcmp(cur_tokenp, "}" )) { if ( !isdigit( (int)cur_tokenp[0] )) { DynamicPreprocessorFatalMessage("%s(%d) Bad port %s.\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp ); //free(argcpyp); //return; } else { port = atoi( cur_tokenp ); if( port < 0 || port > MAX_PORTS ) { DynamicPreprocessorFatalMessage("%s(%d) Port value illegitimate: %s\n", *(_dpd.config_file), *(_dpd.config_line), cur_tokenp ); //free(argcpyp); //return; } config->ports[ PORT_INDEX( port ) ] |= CONV_PORT(port); } cur_tokenp = strtok( NULL, " "); } } else if ( !strcmp( cur_tokenp, DNS_ENABLE_RDATA_OVERFLOW_KEYWORD )) { config->enabled_alerts |= DNS_ALERT_RDATA_OVERFLOW; } else if ( !strcmp( cur_tokenp, DNS_ENABLE_OBSOLETE_TYPES_KEYWORD )) { config->enabled_alerts |= DNS_ALERT_OBSOLETE_TYPES; } else if ( !strcmp( cur_tokenp, DNS_ENABLE_EXPERIMENTAL_TYPES_KEYWORD )) { config->enabled_alerts |= DNS_ALERT_EXPERIMENTAL_TYPES; } #if 0 else if ( !strcmp( cur_tokenp, DNS_AUTODETECT_KEYWORD )) { config->autodetect++; } #endif else { DynamicPreprocessorFatalMessage("Invalid argument: %s\n", cur_tokenp); return; } cur_tokenp = strtok( NULL, " " ); } PrintDNSConfig(config); free(argcpyp); } /* Display the configuration for the DNS preprocessor. * * PARAMETERS: None. * * RETURNS: Nothing. */ static void PrintDNSConfig(DNSConfig *config) { int index; if (config == NULL) return; _dpd.logMsg("DNS config: \n"); #if 0 _dpd.logMsg(" Autodetection: %s\n", config->autodetect ? "ENABLED":"DISABLED"); #endif _dpd.logMsg(" DNS Client rdata txt Overflow Alert: %s\n", config->enabled_alerts & DNS_ALERT_RDATA_OVERFLOW ? "ACTIVE" : "INACTIVE" ); _dpd.logMsg(" Obsolete DNS RR Types Alert: %s\n", config->enabled_alerts & DNS_ALERT_OBSOLETE_TYPES ? "ACTIVE" : "INACTIVE" ); _dpd.logMsg(" Experimental DNS RR Types Alert: %s\n", config->enabled_alerts & DNS_ALERT_EXPERIMENTAL_TYPES ? "ACTIVE" : "INACTIVE" ); /* Printing ports */ _dpd.logMsg(" Ports:"); for(index = 0; index < MAX_PORTS; index++) { if( config->ports[ PORT_INDEX(index) ] & CONV_PORT(index) ) { _dpd.logMsg(" %d", index); } } _dpd.logMsg("\n"); } /* Retrieves the DNS data block registered with the stream * session associated w/ the current packet. If none exists, * allocates it and registers it with the stream API. * * PARAMETERS: * * p: Pointer to the packet from which/in which to * retrieve/store the DNS data block. * * RETURNS: Pointer to an DNS data block, upon success. * NULL, upon failure. */ static DNSSessionData udpSessionData; #define MIN_UDP_PAYLOAD 0x1FFF DNSSessionData * GetDNSSessionData(SFSnortPacket *p, DNSConfig *config) { DNSSessionData* dnsSessionData = NULL; if (config == NULL) return NULL; if (p->udp_header) { if (!(config->enabled_alerts & DNS_ALERT_OBSOLETE_TYPES) && !(config->enabled_alerts & DNS_ALERT_EXPERIMENTAL_TYPES)) { if (config->enabled_alerts & DNS_ALERT_RDATA_OVERFLOW) { /* Checking RData Overflow... */ if (p->payload_size < (sizeof(DNSHdr) + sizeof(DNSRR) + MIN_UDP_PAYLOAD)) { /* But we don't have sufficient data. Go away. */ return NULL; } } else { /* Not checking for experimental or obsolete types. Go away. */ return NULL; } } /* Its a UDP packet, use the "stateless" one */ dnsSessionData = &udpSessionData; memset(dnsSessionData, 0, sizeof(DNSSessionData)); return dnsSessionData; } /* More Sanity check(s) */ if ( !p->stream_session_ptr ) { return NULL; } dnsSessionData = calloc( 1, sizeof( DNSSessionData )); if ( !dnsSessionData ) return NULL; /*Register the new DNS data block in the stream session. */ _dpd.streamAPI->set_application_data( p->stream_session_ptr, PP_DNS, dnsSessionData, FreeDNSSessionData ); return dnsSessionData; } /* Registered as a callback with the DNS data when they are * added to the stream session. Called by stream when a * session is about to be destroyed to free that data. * * PARAMETERS: * * application_data: Pointer to the DNS data * * RETURNS: Nothing. */ static void FreeDNSSessionData( void* application_data ) { DNSSessionData* dnsSessionData = (DNSSessionData*)application_data; if ( dnsSessionData ) { free( dnsSessionData ); } } /* Validates given port as an DNS server port. * * PARAMETERS: * * port: Port to validate. * * RETURNS: DNS_TRUE, if the port is indeed an DNS server port. * DNS_FALSE, otherwise. */ static inline int CheckDNSPort(DNSConfig *config, uint16_t port) { return config->ports[PORT_INDEX(port)] & CONV_PORT(port); } static uint16_t ParseDNSHeader(const unsigned char *data, uint16_t bytes_unused, DNSSessionData *dnsSessionData) { if (bytes_unused == 0) { return bytes_unused; } switch (dnsSessionData->state) { case DNS_RESP_STATE_LENGTH: /* First two bytes are length in TCP */ dnsSessionData->length = ((uint8_t)*data) << 8; dnsSessionData->state = DNS_RESP_STATE_LENGTH_PART; data++; bytes_unused--; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_LENGTH_PART: dnsSessionData->length |= ((uint8_t)*data); dnsSessionData->state = DNS_RESP_STATE_HDR_ID; data++; bytes_unused--; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_ID: dnsSessionData->hdr.id = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_ID_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_ID_PART: dnsSessionData->hdr.id |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_FLAGS; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_FLAGS: dnsSessionData->hdr.flags = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_FLAGS_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_FLAGS_PART: dnsSessionData->hdr.flags |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_QS; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_QS: dnsSessionData->hdr.questions = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_QS_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_QS_PART: dnsSessionData->hdr.questions |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_ANSS; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_ANSS: dnsSessionData->hdr.answers = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_ANSS_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_ANSS_PART: dnsSessionData->hdr.answers |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_AUTHS; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_AUTHS: dnsSessionData->hdr.authorities = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_AUTHS_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_AUTHS_PART: dnsSessionData->hdr.authorities |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_ADDS; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_ADDS: dnsSessionData->hdr.additionals = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_HDR_ADDS_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_HDR_ADDS_PART: dnsSessionData->hdr.additionals |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->state = DNS_RESP_STATE_QUESTION; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ default: /* Continue -- we're beyond the header */ break; } return bytes_unused; } uint16_t ParseDNSName(const unsigned char *data, uint16_t bytes_unused, DNSSessionData *dnsSessionData) { uint16_t bytes_required = dnsSessionData->curr_txt.txt_len - dnsSessionData->curr_txt.txt_bytes_seen; while (dnsSessionData->curr_txt.name_state != DNS_RESP_STATE_NAME_COMPLETE) { if (bytes_unused == 0) { return bytes_unused; } switch (dnsSessionData->curr_txt.name_state) { case DNS_RESP_STATE_NAME_SIZE: dnsSessionData->curr_txt.txt_len = (uint8_t)*data; data++; bytes_unused--; dnsSessionData->bytes_seen_curr_rec++; if (dnsSessionData->curr_txt.txt_len == 0) { dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_COMPLETE; return bytes_unused; } dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME; dnsSessionData->curr_txt.txt_bytes_seen = 0; if ((dnsSessionData->curr_txt.txt_len & DNS_RR_PTR) == DNS_RR_PTR) { /* A reference to another location... */ /* This is an offset */ dnsSessionData->curr_txt.offset = (dnsSessionData->curr_txt.txt_len & ~0xC0) << 8; bytes_required = dnsSessionData->curr_txt.txt_len = 1; dnsSessionData->curr_txt.relative = 1; /* Setup to read 2nd Byte of Location */ } else { bytes_required = dnsSessionData->curr_txt.txt_len; dnsSessionData->curr_txt.offset = 0; dnsSessionData->curr_txt.relative = 0; } if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_NAME: if (bytes_required <= bytes_unused) { bytes_unused -= bytes_required; if (dnsSessionData->curr_txt.relative) { /* If this one is a relative offset, read that extra byte */ dnsSessionData->curr_txt.offset |= *data; } data += bytes_required; dnsSessionData->bytes_seen_curr_rec += bytes_required; dnsSessionData->curr_txt.txt_bytes_seen += bytes_required; if (bytes_unused == 0) { return bytes_unused; } } else { dnsSessionData->bytes_seen_curr_rec+= bytes_unused; dnsSessionData->curr_txt.txt_bytes_seen += bytes_unused; return 0; } if (dnsSessionData->curr_txt.relative) { /* And since its relative, we're done */ dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_COMPLETE; return bytes_unused; } break; } /* Go to the next portion of the name */ dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_SIZE; } return bytes_unused; } static uint16_t ParseDNSQuestion(const unsigned char *data, uint16_t data_size, uint16_t bytes_unused, DNSSessionData *dnsSessionData) { uint16_t bytes_used = 0; uint16_t new_bytes_unused = 0; if (bytes_unused == 0) { return bytes_unused; } if (dnsSessionData->curr_rec_state < DNS_RESP_STATE_Q_NAME_COMPLETE) { new_bytes_unused = ParseDNSName(data, bytes_unused, dnsSessionData); bytes_used = bytes_unused - new_bytes_unused; if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE) { dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_TYPE; memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); data = data + bytes_used; bytes_unused = new_bytes_unused; if (bytes_unused == 0) { /* ran out of data */ return bytes_unused; } } else { /* Should be 0 -- ran out of data */ return new_bytes_unused; } } switch (dnsSessionData->curr_rec_state) { case DNS_RESP_STATE_Q_TYPE: dnsSessionData->curr_q.type = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_TYPE_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_Q_TYPE_PART: dnsSessionData->curr_q.type |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_CLASS; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_Q_CLASS: dnsSessionData->curr_q.dns_class = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_CLASS_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_Q_CLASS_PART: dnsSessionData->curr_q.dns_class |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_COMPLETE; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ default: /* Continue -- we're beyond this question */ break; } return bytes_unused; } uint16_t ParseDNSAnswer(const unsigned char *data, uint16_t data_size, uint16_t bytes_unused, DNSSessionData *dnsSessionData) { uint16_t bytes_used = 0; uint16_t new_bytes_unused = 0; if (bytes_unused == 0) { return bytes_unused; } if (dnsSessionData->curr_rec_state < DNS_RESP_STATE_RR_NAME_COMPLETE) { new_bytes_unused = ParseDNSName(data, bytes_unused, dnsSessionData); bytes_used = bytes_unused - new_bytes_unused; if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE) { dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TYPE; memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); data = data + bytes_used; } bytes_unused = new_bytes_unused; if (bytes_unused == 0) { /* ran out of data */ return bytes_unused; } } switch (dnsSessionData->curr_rec_state) { case DNS_RESP_STATE_RR_TYPE: dnsSessionData->curr_rr.type = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TYPE_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_RR_TYPE_PART: dnsSessionData->curr_rr.type |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_CLASS; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_RR_CLASS: dnsSessionData->curr_rr.dns_class = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_CLASS_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_RR_CLASS_PART: dnsSessionData->curr_rr.dns_class |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TTL; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_RR_TTL: dnsSessionData->curr_rr.ttl = (uint8_t)*data << 24; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TTL_PART; dnsSessionData->bytes_seen_curr_rec = 1; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_RR_TTL_PART: while (dnsSessionData->bytes_seen_curr_rec < 4) { dnsSessionData->bytes_seen_curr_rec++; dnsSessionData->curr_rr.ttl |= (uint8_t)*data << (4-dnsSessionData->bytes_seen_curr_rec)*8; data++; bytes_unused--; if (bytes_unused == 0) { return bytes_unused; } } dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDLENGTH; /* Fall through */ case DNS_RESP_STATE_RR_RDLENGTH: dnsSessionData->curr_rr.length = (uint8_t)*data << 8; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDLENGTH_PART; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_RR_RDLENGTH_PART: dnsSessionData->curr_rr.length |= (uint8_t)*data; data++; bytes_unused--; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_START; if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ default: /* Continue -- we're beyond this answer */ break; } return bytes_unused; } /* The following check is to look for an attempt to exploit * a vulnerability in the DNS client, per MS 06-041. * * For details, see: * http://www.microsoft.com/technet/security/bulletin/ms06-007.mspx * http://cve.mitre.org/cgi-bin/cvename.cgi?name=2006-3441 * * Vulnerability Research by Lurene Grenier, Judy Novak, * and Brian Caswell. */ uint16_t CheckRRTypeTXTVuln(const unsigned char *data, uint16_t bytes_unused, DNSSessionData *dnsSessionData) { uint16_t bytes_required = dnsSessionData->curr_txt.txt_len - dnsSessionData->curr_txt.txt_bytes_seen; while (dnsSessionData->curr_txt.name_state != DNS_RESP_STATE_RR_NAME_COMPLETE) { if (dnsSessionData->bytes_seen_curr_rec == dnsSessionData->curr_rr.length) { /* Done with the name */ dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME_COMPLETE; /* Got to the end of the rdata in this packet! */ dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_COMPLETE; return bytes_unused; } if (bytes_unused == 0) { return bytes_unused; } switch (dnsSessionData->curr_txt.name_state) { case DNS_RESP_STATE_RR_NAME_SIZE: dnsSessionData->curr_txt.txt_len = (uint8_t)*data; dnsSessionData->curr_txt.txt_count++; dnsSessionData->curr_txt.total_txt_len += dnsSessionData->curr_txt.txt_len + 1; /* include the NULL */ if (!dnsSessionData->curr_txt.alerted) { uint32_t overflow_check = (dnsSessionData->curr_txt.txt_count * 4) + (dnsSessionData->curr_txt.total_txt_len * 2) + 4; /* if txt_count * 4 + total_txt_len * 2 + 4 > FFFF, vulnerability! */ if (overflow_check > 0xFFFF) { if (dns_eval_config->enabled_alerts & DNS_ALERT_RDATA_OVERFLOW) { /* Alert on obsolete DNS RR types */ DNS_ALERT(DNS_EVENT_RDATA_OVERFLOW, DNS_EVENT_RDATA_OVERFLOW_STR); } dnsSessionData->curr_txt.alerted = 1; } } data++; bytes_unused--; dnsSessionData->bytes_seen_curr_rec++; if (dnsSessionData->curr_txt.txt_len > 0) { dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME; dnsSessionData->curr_txt.txt_bytes_seen = 0; bytes_required = dnsSessionData->curr_txt.txt_len; } else { continue; } if (bytes_unused == 0) { return bytes_unused; } /* Fall through */ case DNS_RESP_STATE_RR_NAME: if (bytes_required <= bytes_unused) { bytes_unused -= bytes_required; dnsSessionData->bytes_seen_curr_rec += bytes_required; data += bytes_required; dnsSessionData->curr_txt.txt_bytes_seen += bytes_required; if (bytes_unused == 0) { return bytes_unused; } } else { dnsSessionData->curr_txt.txt_bytes_seen += bytes_unused; dnsSessionData->bytes_seen_curr_rec += bytes_unused; return 0; } break; } /* Go to the next portion of the name */ dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME_SIZE; } return bytes_unused; } uint16_t SkipDNSRData(const unsigned char *data, uint16_t bytes_unused, DNSSessionData *dnsSessionData) { uint16_t bytes_required = dnsSessionData->curr_rr.length - dnsSessionData->bytes_seen_curr_rec; if (bytes_required <= bytes_unused) { bytes_unused -= bytes_required; data += bytes_required; dnsSessionData->bytes_seen_curr_rec += bytes_required; } else { dnsSessionData->bytes_seen_curr_rec += bytes_unused; return 0; } /* Got to the end of the rdata in this packet! */ dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_COMPLETE; return bytes_unused; } uint16_t ParseDNSRData(SFSnortPacket *p, const unsigned char *data, uint16_t bytes_unused, DNSSessionData *dnsSessionData) { if (bytes_unused == 0) { return bytes_unused; } switch (dnsSessionData->curr_rr.type) { case DNS_RR_TYPE_TXT: /* Check for RData Overflow */ bytes_unused = CheckRRTypeTXTVuln(data, bytes_unused, dnsSessionData); break; case DNS_RR_TYPE_MD: case DNS_RR_TYPE_MF: if (dns_eval_config->enabled_alerts & DNS_ALERT_OBSOLETE_TYPES) { /* Alert on obsolete DNS RR types */ DNS_ALERT(DNS_EVENT_OBSOLETE_TYPES, DNS_EVENT_OBSOLETE_TYPES_STR); } bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData); break; case DNS_RR_TYPE_MB: case DNS_RR_TYPE_MG: case DNS_RR_TYPE_MR: case DNS_RR_TYPE_NULL: case DNS_RR_TYPE_MINFO: if (dns_eval_config->enabled_alerts & DNS_ALERT_EXPERIMENTAL_TYPES) { /* Alert on experimental DNS RR types */ DNS_ALERT(DNS_EVENT_EXPERIMENTAL_TYPES, DNS_EVENT_EXPERIMENTAL_TYPES_STR); } bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData); break; case DNS_RR_TYPE_A: case DNS_RR_TYPE_NS: case DNS_RR_TYPE_CNAME: case DNS_RR_TYPE_SOA: case DNS_RR_TYPE_WKS: case DNS_RR_TYPE_PTR: case DNS_RR_TYPE_HINFO: case DNS_RR_TYPE_MX: bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData); break; default: /* Not one of the known types. Stop looking at this session * as DNS. */ dnsSessionData->flags |= DNS_FLAG_NOT_DNS; break; } return bytes_unused; } void ParseDNSResponseMessage(SFSnortPacket *p, DNSSessionData *dnsSessionData) { uint16_t bytes_unused = p->payload_size; int i; const unsigned char *data = p->payload; while (bytes_unused) { /* Parse through the DNS Header */ if (dnsSessionData->state < DNS_RESP_STATE_QUESTION) { /* Length only applies on a TCP packet, skip to header ID * if at beginning of a UDP Response. */ if ((dnsSessionData->state == DNS_RESP_STATE_LENGTH) && (p->udp_header)) { dnsSessionData->state = DNS_RESP_STATE_HDR_ID; } bytes_unused = ParseDNSHeader(data, bytes_unused, dnsSessionData); if (bytes_unused > 0) { data = p->payload + (p->payload_size - bytes_unused); } else { /* No more data */ return; } dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_NAME; dnsSessionData->curr_rec = 0; } /* Print out the header (but only once -- when we're ready to parse the Questions */ #ifdef DEBUG_MSGS if ((dnsSessionData->curr_rec_state == DNS_RESP_STATE_Q_NAME) && (dnsSessionData->curr_rec == 0)) { DebugMessage(DEBUG_DNS, "DNS Header: length %d, id 0x%x, flags 0x%x, " "questions %d, answers %d, authorities %d, additionals %d\n", dnsSessionData->length, dnsSessionData->hdr.id, dnsSessionData->hdr.flags, dnsSessionData->hdr.questions, dnsSessionData->hdr.answers, dnsSessionData->hdr.authorities, dnsSessionData->hdr.additionals); } #endif if (!(dnsSessionData->hdr.flags & DNS_HDR_FLAG_RESPONSE)) { /* Not a response */ return; } /* Handle the DNS Queries */ if (dnsSessionData->state == DNS_RESP_STATE_QUESTION) { /* Skip over the 4 byte question records... */ for (i=dnsSessionData->curr_rec; i< dnsSessionData->hdr.questions; i++) { bytes_unused = ParseDNSQuestion(data, p->payload_size, bytes_unused, dnsSessionData); if (dnsSessionData->curr_rec_state == DNS_RESP_STATE_Q_COMPLETE) { DEBUG_WRAP( DebugMessage(DEBUG_DNS, "DNS Question %d: type %d, class %d\n", i, dnsSessionData->curr_q.type, dnsSessionData->curr_q.dns_class); ); dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_NAME; dnsSessionData->curr_rec++; } if (bytes_unused > 0) { data = p->payload + (p->payload_size - bytes_unused); } else { /* No more data */ return; } } dnsSessionData->state = DNS_RESP_STATE_ANS_RR; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE; dnsSessionData->curr_rec = 0; } /* Handle the RRs */ switch (dnsSessionData->state) { case DNS_RESP_STATE_ANS_RR: /* ANSWERS section */ for (i=dnsSessionData->curr_rec; ihdr.answers; i++) { bytes_unused = ParseDNSAnswer(data, p->payload_size, bytes_unused, dnsSessionData); if (bytes_unused == 0) { /* No more data */ return; } switch (dnsSessionData->curr_rec_state) { case DNS_RESP_STATE_RR_RDATA_START: DEBUG_WRAP( DebugMessage(DEBUG_DNS, "DNS ANSWER RR %d: type %d, class %d, " "ttl %d rdlength %d\n", i, dnsSessionData->curr_rr.type, dnsSessionData->curr_rr.dns_class, dnsSessionData->curr_rr.ttl, dnsSessionData->curr_rr.length); ); dnsSessionData->bytes_seen_curr_rec = 0; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID; /* Fall through */ case DNS_RESP_STATE_RR_RDATA_MID: /* Data now points to the beginning of the RDATA */ data = p->payload + (p->payload_size - bytes_unused); bytes_unused = ParseDNSRData(p, data, bytes_unused, dnsSessionData); if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE) { /* Out of data, pick up on the next packet */ return; } else { /* Go to the next record */ dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE; dnsSessionData->curr_rec++; if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT) { /* Reset the state tracking for this record */ memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); } data = p->payload + (p->payload_size - bytes_unused); } } } dnsSessionData->state = DNS_RESP_STATE_AUTH_RR; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE; dnsSessionData->curr_rec = 0; /* Fall through */ case DNS_RESP_STATE_AUTH_RR: /* AUTHORITIES section */ for (i=dnsSessionData->curr_rec; ihdr.authorities; i++) { bytes_unused = ParseDNSAnswer(data, p->payload_size, bytes_unused, dnsSessionData); if (bytes_unused == 0) { /* No more data */ return; } switch (dnsSessionData->curr_rec_state) { case DNS_RESP_STATE_RR_RDATA_START: DEBUG_WRAP( DebugMessage(DEBUG_DNS, "DNS AUTH RR %d: type %d, class %d, " "ttl %d rdlength %d\n", i, dnsSessionData->curr_rr.type, dnsSessionData->curr_rr.dns_class, dnsSessionData->curr_rr.ttl, dnsSessionData->curr_rr.length); ); dnsSessionData->bytes_seen_curr_rec = 0; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID; /* Fall through */ case DNS_RESP_STATE_RR_RDATA_MID: /* Data now points to the beginning of the RDATA */ data = p->payload + (p->payload_size - bytes_unused); bytes_unused = ParseDNSRData(p, data, bytes_unused, dnsSessionData); if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE) { /* Out of data, pick up on the next packet */ return; } else { /* Go to the next record */ dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE; dnsSessionData->curr_rec++; if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT) { /* Reset the state tracking for this record */ memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); } data = p->payload + (p->payload_size - bytes_unused); } } } dnsSessionData->state = DNS_RESP_STATE_ADD_RR; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE; dnsSessionData->curr_rec = 0; /* Fall through */ case DNS_RESP_STATE_ADD_RR: /* ADDITIONALS section */ for (i=dnsSessionData->curr_rec; ihdr.authorities; i++) { bytes_unused = ParseDNSAnswer(data, p->payload_size, bytes_unused, dnsSessionData); if (bytes_unused == 0) { /* No more data */ return; } switch (dnsSessionData->curr_rec_state) { case DNS_RESP_STATE_RR_RDATA_START: DEBUG_WRAP( DebugMessage(DEBUG_DNS, "DNS ADDITONAL RR %d: type %d, class %d, " "ttl %d rdlength %d\n", i, dnsSessionData->curr_rr.type, dnsSessionData->curr_rr.dns_class, dnsSessionData->curr_rr.ttl, dnsSessionData->curr_rr.length); ); dnsSessionData->bytes_seen_curr_rec = 0; dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID; /* Fall through */ case DNS_RESP_STATE_RR_RDATA_MID: /* Data now points to the beginning of the RDATA */ data = p->payload + (p->payload_size - bytes_unused); bytes_unused = ParseDNSRData(p, data, bytes_unused, dnsSessionData); if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE) { /* Out of data, pick up on the next packet */ return; } else { /* Go to the next record */ dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE; dnsSessionData->curr_rec++; if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT) { /* Reset the state tracking for this record */ memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState)); } data = p->payload + (p->payload_size - bytes_unused); } } } /* Done with this one, onto the next -- may also be in this packet */ dnsSessionData->state = DNS_RESP_STATE_LENGTH; dnsSessionData->curr_rec_state = 0; dnsSessionData->curr_rec = 0; } } return; } /* Main runtime entry point for DNS preprocessor. * Analyzes DNS packets for anomalies/exploits. * * PARAMETERS: * * p: Pointer to current packet to process. * context: Pointer to context block, not used. * * RETURNS: Nothing. */ static void ProcessDNS( void* packetPtr, void* context ) { DNSSessionData* dnsSessionData = NULL; uint8_t src = 0; uint8_t dst = 0; uint8_t known_port = 0; uint8_t direction = 0; SFSnortPacket* p; #ifdef TARGET_BASED int16_t app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif DNSConfig *config = NULL; PROFILE_VARS; sfPolicyUserPolicySet (dns_config, _dpd.getRuntimePolicy()); config = (DNSConfig *)sfPolicyUserDataGetCurrent(dns_config); if (config == NULL) return; dns_eval_config = config; p = (SFSnortPacket*) packetPtr; // preconditions - what we registered for assert((IsUDP(p) || IsTCP(p)) && p->payload_size && p->payload); /* Attempt to get a previously allocated DNS block. If none exists, * allocate and register one with the stream layer. */ dnsSessionData = _dpd.streamAPI->get_application_data( p->stream_session_ptr, PP_DNS ); if (dnsSessionData == NULL) { /* Check the ports to make sure this is a DNS port. * Otherwise no need to examine the traffic. */ #ifdef TARGET_BASED app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if (app_id == SFTARGET_UNKNOWN_PROTOCOL) return; if (app_id && (app_id != dns_app_id)) return; if (!app_id) { #endif src = CheckDNSPort(config, p->src_port); dst = CheckDNSPort(config, p->dst_port); #ifdef TARGET_BASED } #endif /* See if a known server port is involved. */ known_port = ( src || dst ? 1 : 0 ); #if 0 if ( !dns_config->autodetect && !src && !dst ) { /* Not one of the ports we care about. */ return; } #endif #ifdef TARGET_BASED if (!app_id && !known_port) #else if (!known_port) #endif { /* Not one of the ports we care about. */ return; } } /* For TCP, do a few extra checks... */ if (p->tcp_header) { /* If session picked up mid-stream, do not process further. * Would be almost impossible to tell where we are in the * data stream. */ if ( _dpd.streamAPI->get_session_flags( p->stream_session_ptr) & SSNFLAG_MIDSTREAM ) { return; } if ( !_dpd.streamAPI->is_stream_sequenced(p->stream_session_ptr, SSN_DIR_FROM_SERVER)) { return; } if (!(_dpd.streamAPI->get_reassembly_direction(p->stream_session_ptr) & SSN_DIR_FROM_SERVER)) { /* This should only happen for the first packet (SYN or SYN-ACK) * in the TCP session */ _dpd.streamAPI->set_reassembly(p->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_FROM_SERVER, STREAM_FLPOLICY_SET_ABSOLUTE); return; } /* If we're waiting on stream reassembly, don't process this packet. */ if ( p->flags & FLAG_STREAM_INSERT) { return; } /* Get the direction of the packet. */ direction = ( (p->flags & FLAG_FROM_SERVER ) ? DNS_DIR_FROM_SERVER : DNS_DIR_FROM_CLIENT ); } else if (p->udp_header) { #ifdef TARGET_BASED if (app_id == dns_app_id) { direction = ( (p->flags & FLAG_FROM_SERVER ) ? DNS_DIR_FROM_SERVER : DNS_DIR_FROM_CLIENT ); } else { #endif if (src) direction = DNS_DIR_FROM_SERVER; else if (dst) direction = DNS_DIR_FROM_CLIENT; #ifdef TARGET_BASED } #endif } PREPROC_PROFILE_START(dnsPerfStats); /* Check the stream session. If it does not currently * have our DNS data-block attached, create one. */ if (dnsSessionData == NULL) dnsSessionData = GetDNSSessionData(p, config); if ( !dnsSessionData ) { /* Could not get/create the session data for this packet. */ PREPROC_PROFILE_END(dnsPerfStats); return; } if (dnsSessionData->flags & DNS_FLAG_NOT_DNS) { /* determined that this session wasn't DNS, we're done */ PREPROC_PROFILE_END(dnsPerfStats); return; } if (direction == DNS_DIR_FROM_SERVER) { ParseDNSResponseMessage(p, dnsSessionData); } PREPROC_PROFILE_END(dnsPerfStats); } static void DNSReset(int signal, void *data) { return; } static void DNSResetStats(int signal, void *data) { return; } static void _addPortsToStream5Filter(struct _SnortConfig *sc, DNSConfig *config, tSfPolicyId policy_id) { unsigned int portNum; if (config == NULL) return; for (portNum = 0; portNum < MAXPORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status (sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); _dpd.streamAPI->set_port_filter_status (sc, IPPROTO_UDP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status (sc, dns_app_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif static int DnsFreeConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { DNSConfig *pPolicyConfig = (DNSConfig *)pData; //do any housekeeping before freeing DnsConfig sfPolicyUserDataClear (config, policyId); free(pPolicyConfig); return 0; } static void DNSFreeConfig(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, DnsFreeConfigPolicy); sfPolicyConfigDelete(config); } static int DNSCheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { _dpd.setParserPolicy(sc, policyId); if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("Streaming & reassembly must be enabled for DNS preprocessor\n"); return -1; } return 0; } static int DNSCheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate (sc, dns_config, DNSCheckPolicyConfig))) return rval; return 0; } static void DNSCleanExit(int signal, void *data) { DNSFreeConfig(dns_config); dns_config = NULL; } #ifdef SNORT_RELOAD static void DNSReload(struct _SnortConfig *sc, char *argp, void **new_config) { tSfPolicyUserContextId dns_swap_config = (tSfPolicyUserContextId)*new_config; int policy_id = _dpd.getParserPolicy(sc); DNSConfig *pPolicyConfig = NULL; if (dns_swap_config == NULL) { //create a context dns_swap_config = sfPolicyConfigCreate(); if (dns_swap_config == NULL) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "DNS configuration.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("%s(%d) Dns preprocessor requires the " "stream5 preprocessor to be enabled.\n", *(_dpd.config_file), *(_dpd.config_line)); } *new_config = (void *)dns_swap_config; } sfPolicyUserPolicySet (dns_swap_config, policy_id); pPolicyConfig = (DNSConfig *)sfPolicyUserDataGetCurrent(dns_swap_config); if (pPolicyConfig) { DynamicPreprocessorFatalMessage("%s(%d) Dns preprocessor can only " "be configured once.\n", *(_dpd.config_file), *(_dpd.config_line)); } pPolicyConfig = (DNSConfig *)calloc(1,sizeof(DNSConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "DNS configuration.\n"); } sfPolicyUserDataSetCurrent(dns_swap_config, pPolicyConfig); ParseDNSArgs(pPolicyConfig, (u_char *)argp); _dpd.addPreproc(sc, ProcessDNS, PRIORITY_APPLICATION, PP_DNS, PROTO_BIT__TCP | PROTO_BIT__UDP); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } static int DNSReloadVerify(struct _SnortConfig *sc, void *swap_config) { if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("Streaming & reassembly must be enabled for DNS preprocessor\n"); return -1; } return 0; } static void * DNSReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId dns_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = dns_config; if (dns_swap_config == NULL) return NULL; dns_config = dns_swap_config; return (void *)old_config; } static void DNSReloadSwapFree(void *data) { if (data == NULL) return; DNSFreeConfig((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/dns/Makefile.am0000644000000000000000000000115411746560364017701 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_dns_preproc.la libsf_dns_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_dns_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_dns_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sfPolicyUserData.c endif libsf_dns_preproc_la_SOURCES = \ spp_dns.c \ spp_dns.h EXTRA_DIST = \ sf_dns.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/dns/Makefile.in0000644000000000000000000005041212260606521017677 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/dns DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_dns_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_dns_preproc_la_OBJECTS = spp_dns.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_dns_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_dns_preproc_la_OBJECTS = $(am_libsf_dns_preproc_la_OBJECTS) \ $(nodist_libsf_dns_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_dns_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_dns_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_dns_preproc_la_SOURCES) \ $(nodist_libsf_dns_preproc_la_SOURCES) DIST_SOURCES = $(libsf_dns_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_dns_preproc.la libsf_dns_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_dns_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_dns_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_dns_preproc_la_SOURCES = \ spp_dns.c \ spp_dns.h EXTRA_DIST = \ sf_dns.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/dns/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/dns/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_dns_preproc.la: $(libsf_dns_preproc_la_OBJECTS) $(libsf_dns_preproc_la_DEPENDENCIES) $(EXTRA_libsf_dns_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_dns_preproc_la_LINK) -rpath $(libdir) $(libsf_dns_preproc_la_OBJECTS) $(libsf_dns_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/ssh/0000755000000000000000000000000012260606563015727 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/ssh/sf_ssh.dsp0000644000000000000000000001154712153454771017657 00000000000000# Microsoft Developer Studio Project File - Name="sf_ssh" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_ssh - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_ssh.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_ssh.mak" CFG="sf_ssh - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_ssh - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_ssh - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_ssh - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "SF_SNORT_PREPROC_DLL" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_ssh - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "SF_SNORT_PREPROC_DLL" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_ssh - Win32 Release" # Name "sf_ssh - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\spp_ssh.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\spp_ssh.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/ssh/spp_ssh.h0000644000000000000000000002016112260565732017501 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2005-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * spp_ssh.h: Definitions, structs, function prototype(s) for * the SSH preprocessor. * Author: Chris Sherwin */ #ifndef SPP_SSH_H #define SPP_SSH_H #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "snort_bounds.h" #define MAX_PORTS 65536 /* * Default SSH port */ #define SSH_PORT 22 /* * Boolean values. */ #define SSH_TRUE (1) #define SSH_FALSE (0) /* * Error codes. */ #define SSH_SUCCESS (1) #define SSH_FAILURE (0) /* * Default values for configurable parameters. */ #define SSH_DEFAULT_MAX_ENC_PKTS 25 #define SSH_DEFAULT_MAX_CLIENT_BYTES 19600 #define SSH_DEFAULT_MAX_SERVER_VERSION_LEN 80 /* * Min/Max values for each configurable parameter. */ #define MIN_MAX_ENC_PKTS 0 #define MAX_MAX_ENC_PKTS 65535 #define MIN_MAX_CLIENT_BYTES 0 #define MAX_MAX_CLIENT_BYTES 65535 #define MIN_MAX_SERVER_VERSION_LEN 0 #define MAX_MAX_SERVER_VERSION_LEN 255 /* * One of these structures is kept for each configured * server port. */ typedef struct _sshPortlistNode { uint16_t server_port; struct _sshPortlistNode* nextp; } SSHPortNode; /* * Global SSH preprocessor configuration. * * AutodetectEnabled: Whether or not to apply auto-detection of SSH * to ports other than those configured. * MaxEncryptedPackets: Maximum number of encrypted packets examined per * session. * MaxClientBytes: Maximum bytes of encrypted data that can be * sent by client without a server response. * MaxServerVersionLen: Maximum length of a server's version string. * Configurable threshold for Secure CRT-style overflow. * DisableRules: Disable rule processing for SSH traffic. * EnabledAlerts: Bit vector describing which alerts are enabled. */ typedef struct _sshConfig { uint8_t AutodetectEnabled; uint16_t MaxEncryptedPackets; uint16_t MaxClientBytes; uint16_t MaxServerVersionLen; // uint16_t DisableRules; uint16_t EnabledAlerts; // SSHPortNode* PortList; char ports[MAX_PORTS/8]; int ref_count; } SSHConfig; /* * Per-session data block containing current state * of the SSH preprocessor for the session. * * version: Version of SSH detected for this session. * num_enc_pkts: Number of encrypted packets seen on this session. * num_client_bytes: Number of bytes of encrypted data sent by client, * without a server response. * state_flags: Bit vector describing the current state of the * session. */ typedef struct _sshData { uint8_t version; uint16_t num_enc_pkts; uint16_t num_client_bytes; uint32_t state_flags; tSfPolicyId policy_id; tSfPolicyUserContextId config; } SSHData; /* * Session state flags for SSHData::state_flags */ #define SSH_FLG_CLEAR (0x0) #define SSH_FLG_CLIENT_IDSTRING_SEEN (0x1) #define SSH_FLG_SERV_IDSTRING_SEEN (0x2) #define SSH_FLG_SERV_PKEY_SEEN (0x4) #define SSH_FLG_CLIENT_SKEY_SEEN (0x8) #define SSH_FLG_CLIENT_KEXINIT_SEEN (0x10) #define SSH_FLG_SERV_KEXINIT_SEEN (0x20) #define SSH_FLG_KEXDH_INIT_SEEN (0x40) #define SSH_FLG_KEXDH_REPLY_SEEN (0x80) #define SSH_FLG_GEX_REQ_SEEN (0x100) #define SSH_FLG_GEX_GRP_SEEN (0x200) #define SSH_FLG_GEX_INIT_SEEN (0x400) #define SSH_FLG_GEX_REPLY_SEEN (0x800) #define SSH_FLG_NEWKEYS_SEEN (0x1000) #define SSH_FLG_SESS_ENCRYPTED (0x2000) #define SSH_FLG_RESPOVERFLOW_ALERTED (0x4000) #define SSH_FLG_CRC32_ALERTED (0x8000) #define SSH_FLG_MISSED_PACKETS (0x10000) #define SSH_FLG_REASSEMBLY_SET (0x20000) #define SSH_FLG_AUTODETECTED (0x40000) /* * Some convenient combinations of state flags. */ #define SSH_FLG_BOTH_IDSTRING_SEEN (SSH_FLG_CLIENT_IDSTRING_SEEN | \ SSH_FLG_SERV_IDSTRING_SEEN ) #define SSH_FLG_V1_KEYEXCH_DONE (SSH_FLG_SERV_PKEY_SEEN | \ SSH_FLG_CLIENT_SKEY_SEEN ) #define SSH_FLG_V2_KEXINIT_DONE (SSH_FLG_CLIENT_KEXINIT_SEEN | \ SSH_FLG_SERV_KEXINIT_SEEN ) #define SSH_FLG_V2_DHOLD_DONE (SSH_FLG_KEXDH_INIT_SEEN | \ SSH_FLG_KEXDH_REPLY_SEEN | \ SSH_FLG_NEWKEYS_SEEN ) #define SSH_FLG_V2_DHNEW_DONE (SSH_FLG_GEX_REQ_SEEN | \ SSH_FLG_GEX_GRP_SEEN | \ SSH_FLG_GEX_INIT_SEEN | \ SSH_FLG_GEX_REPLY_SEEN | \ SSH_FLG_NEWKEYS_SEEN ) /* * SSH version values for SSHData::version */ #define SSH_VERSION_UNKNOWN (0x0) #define SSH_VERSION_1 (0x1) #define SSH_VERSION_2 (0x2) /* * Length of SSH2 header, in bytes. */ #define SSH2_HEADERLEN (5) #define SSH2_PACKET_MAX_SIZE (256 * 1024) /* * SSH2 binary packet struct. * * packet_length: Length of packet in bytes not including * this field or the mesg auth code (mac) * padding_length: Length of padding section. * packet_data: Variable length packet payload + padding + MAC. */ typedef struct _ssh2Packet { uint32_t packet_length; uint8_t padding_length; char packet_data[1]; } SSH2Packet; /* * SSH v1 message types (of interest) */ #define SSH_MSG_V1_SMSG_PUBLIC_KEY 2 #define SSH_MSG_V1_CMSG_SESSION_KEY 3 /* * SSH v2 message types (of interest) */ #define SSH_MSG_KEXINIT 20 #define SSH_MSG_NEWKEYS 21 #define SSH_MSG_KEXDH_INIT 30 #define SSH_MSG_KEXDH_REPLY 31 #define SSH_MSG_KEXDH_GEX_REQ 34 #define SSH_MSG_KEXDH_GEX_GRP 33 #define SSH_MSG_KEXDH_GEX_INIT 32 #define SSH_MSG_KEXDH_GEX_REPLY 31 /* Direction of sent message. */ #define SSH_DIR_FROM_SERVER (0x1) #define SSH_DIR_FROM_CLIENT (0x2) /* * Keyword strings for parsing configuration options. */ #define SSH_SERVERPORTS_KEYWORD "server_ports" #define SSH_MAX_ENC_PKTS_KEYWORD "max_encrypted_packets" #define SSH_MAX_CLIENT_BYTES_KEYWORD "max_client_bytes" #define SSH_MAX_SERVER_VERSION_KEYWORD "max_server_version_len" #define SSH_AUTODETECT_KEYWORD "autodetect" #define SSH_ENABLE_RESPOVERFLOW_KEYWORD "enable_respoverflow" #define SSH_ENABLE_CRC32_KEYWORD "enable_ssh1crc32" #define SSH_ENABLE_SECURECRT_KEYWORD "enable_srvoverflow" #define SSH_ENABLE_PROTOMISMATCH_KEYWORD "enable_protomismatch" #define SSH_ENABLE_WRONGDIR_KEYWORD "enable_badmsgdir" #define SSH_DISABLE_RULES_KEYWORD "disable_rules" #define SSH_ENABLE_PAYLOAD_SIZE "enable_paysize" #define SSH_ENABLE_UNRECOGNIZED_VER "enable_recognition" /* * SSH preprocessor alert types. */ #define SSH_EVENT_RESPOVERFLOW 1 #define SSH_EVENT_CRC32 2 #define SSH_EVENT_SECURECRT 3 #define SSH_EVENT_PROTOMISMATCH 4 #define SSH_EVENT_WRONGDIR 5 #define SSH_EVENT_PAYLOAD_SIZE 6 #define SSH_EVENT_VERSION 7 /* * SSH alert flags */ #define SSH_ALERT_NONE (0x0) #define SSH_ALERT_RESPOVERFLOW (0x1) #define SSH_ALERT_CRC32 (0x2) #define SSH_ALERT_SECURECRT (0x4) #define SSH_ALERT_PROTOMISMATCH (0x8) #define SSH_ALERT_WRONGDIR (0x10) #define SSH_ALERT_PAYSIZE (0x20) #define SSH_ALERT_UNRECOGNIZED (0x40) #define SSH_ALERT_ALL (0xFFFF) /* * SSH preprocessor alert strings. */ #define SSH_EVENT_RESPOVERFLOW_STR "(spp_ssh) Challenge-Response Overflow exploit" #define SSH_EVENT_CRC32_STR "(spp_ssh) SSH1 CRC32 exploit" #define SSH_EVENT_SECURECRT_STR "(spp_ssh) Server version string overflow" #define SSH_EVENT_PROTOMISMATCH_STR "(spp_ssh) Protocol mismatch" #define SSH_EVENT_WRONGDIR_STR "(spp_ssh) Bad message direction" #define SSH_PAYLOAD_SIZE_STR "(spp_ssh) Payload size incorrect for the given payload" #define SSH_VERSION_STR "(spp_ssh) Failed to detect SSH version string" /* Prototypes for public interface */ extern void SetupSSH(void); #endif /* SPP_SSH_H */ snort-2.9.6.0/src/dynamic-preprocessors/ssh/spp_ssh.c0000644000000000000000000014207112260565732017501 00000000000000/* $Id */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2005-2013 Sourcefire, Inc. ** ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * SSH preprocessor * Author: Chris Sherwin * Contributors: Adam Keeton, Ryan Jordan * * * Alert for Gobbles, CRC32, protocol mismatch (Cisco catalyst vulnerability), * and a SecureCRT vulnerability. Will also alert if the client or server * traffic appears to flow the wrong direction, or if packets appear * malformed/spoofed. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include "sf_types.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_plugin_api.h" #include "snort_debug.h" #include "preprocids.h" #include "spp_ssh.h" #include "sf_preproc_info.h" #include #include #include #include #ifndef WIN32 #include #include #endif #include #include #include "profiler.h" #ifdef PERF_PROFILING PreprocStats sshPerfStats; #endif #include "sf_types.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 3; const char *PREPROC_NAME = "SF_SSH"; #define SetupSSH DYNAMIC_PREPROC_SETUP #ifdef TARGET_BASED int16_t ssh_app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif /* * Generator id. Define here the same as the official registry * in generators.h */ #define GENERATOR_SPP_SSH 128 /* * Function prototype(s) */ SSHData * SSHGetNewSession(SFSnortPacket *, tSfPolicyId); static void SSHInit( struct _SnortConfig *, char* ); static void DisplaySSHConfig(SSHConfig *); static void FreeSSHData( void* ); static void ParseSSHArgs(SSHConfig *, u_char*); static void ProcessSSH( void*, void* ); static inline int CheckSSHPort( uint16_t ); static unsigned int ProcessSSHProtocolVersionExchange( SSHData*, SFSnortPacket*, uint8_t, uint8_t ); static unsigned int ProcessSSHKeyExchange( SSHData*, SFSnortPacket*, uint8_t, unsigned int ); static unsigned int ProcessSSHKeyInitExchange( SSHData*, SFSnortPacket*, uint8_t, unsigned int); static void _addPortsToStream5Filter(struct _SnortConfig *, SSHConfig *, tSfPolicyId); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static void SSHFreeConfig(tSfPolicyUserContextId config); static int SSHCheckConfig(struct _SnortConfig *); static void SSHCleanExit(int, void *); /* Ultimately calls SnortEventqAdd */ /* Arguments are: gid, sid, rev, classification, priority, message, rule_info */ #define ALERT(x,y) { _dpd.alertAdd(GENERATOR_SPP_SSH, x, 1, 0, 3, y, 0 ); } /* Convert port value into an index for the ssh_config->ports array */ #define PORT_INDEX(port) port/8 /* Convert port value into a value for bitwise operations */ #define CONV_PORT(port) 1<<(port%8) /** SSH configuration per Policy */ static tSfPolicyUserContextId ssh_config = NULL; static SSHConfig *ssh_eval_config = NULL; #ifdef SNORT_RELOAD static void SSHReload(struct _SnortConfig *, char *, void **); static int SSHReloadVerify(struct _SnortConfig *, void *); static void * SSHReloadSwap(struct _SnortConfig *, void *); static void SSHReloadSwapFree(void *); #endif /* Called at preprocessor setup time. Links preprocessor keyword * to corresponding preprocessor initialization function. * * PARAMETERS: None. * * RETURNS: Nothing. * */ void SetupSSH(void) { /* Link preprocessor keyword to initialization function * in the preprocessor list. */ #ifndef SNORT_RELOAD _dpd.registerPreproc( "ssh", SSHInit ); #else _dpd.registerPreproc("ssh", SSHInit, SSHReload, SSHReloadVerify, SSHReloadSwap, SSHReloadSwapFree); #endif } /* Initializes the SSH preprocessor module and registers * it in the preprocessor list. * * PARAMETERS: * * argp: Pointer to argument string to process for config * data. * * RETURNS: Nothing. */ static void SSHInit(struct _SnortConfig *sc, char *argp) { tSfPolicyId policy_id = _dpd.getParserPolicy(sc); SSHConfig *pPolicyConfig = NULL; if (ssh_config == NULL) { //create a context ssh_config = sfPolicyConfigCreate(); if (ssh_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for SSH config.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupSSH(): The Stream preprocessor must be enabled.\n"); } _dpd.addPreprocConfCheck(sc, SSHCheckConfig); _dpd.addPreprocExit(SSHCleanExit, NULL, PRIORITY_LAST, PP_SSH); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("ssh", (void *)&sshPerfStats, 0, _dpd.totalPerfStats); #endif #ifdef TARGET_BASED ssh_app_id = _dpd.findProtocolReference("ssh"); if (ssh_app_id == SFTARGET_UNKNOWN_PROTOCOL) ssh_app_id = _dpd.addProtocolReference("ssh"); #endif } sfPolicyUserPolicySet (ssh_config, policy_id); pPolicyConfig = (SSHConfig *)sfPolicyUserDataGetCurrent(ssh_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("SSH preprocessor can only be " "configured once.\n"); } pPolicyConfig = (SSHConfig *)calloc(1, sizeof(SSHConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "SSH preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(ssh_config, pPolicyConfig); ParseSSHArgs(pPolicyConfig, (u_char *)argp); _dpd.addPreproc( sc, ProcessSSH, PRIORITY_APPLICATION, PP_SSH, PROTO_BIT__TCP ); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } /* Parses a single numerical value. * A fatal error is made if the parsed value is out of bounds. * * PARAMETERS: * * token: String containing argument * keyword: String containing option's name. Used when printing an error. * min: Minimum value of argument * max: Maximum value of argument * * RETURNS: bounds-checked integer value of argument. */ static int ParseNumInRange(char *token, char *keyword, int min, int max) { int value; if (( !token ) || !isdigit((int)token[0]) ) { DynamicPreprocessorFatalMessage("Bad value specified for %s. " "Please specify a number between %d and %d.\n", keyword, min, max); } value = atoi( token ); if (value < min || value > max) { DynamicPreprocessorFatalMessage("Value specified for %s is out of " "bounds. Please specify a number between %d and %d.\n", keyword, min, max); } return value; } /* Parses and processes the configuration arguments * supplied in the SSH preprocessor rule. * * PARAMETERS: * * argp: Pointer to string containing the config arguments. * * RETURNS: Nothing. */ static void ParseSSHArgs(SSHConfig *config, u_char* argp) { char* cur_tokenp = NULL; char* argcpyp = NULL; int port; if (config == NULL) return; config->MaxEncryptedPackets = SSH_DEFAULT_MAX_ENC_PKTS; config->MaxClientBytes = SSH_DEFAULT_MAX_CLIENT_BYTES; config->MaxServerVersionLen = SSH_DEFAULT_MAX_SERVER_VERSION_LEN; /* Set up default port to listen on */ config->ports[ PORT_INDEX( 22 ) ] |= CONV_PORT(22); /* Sanity check(s) */ if ( !argp ) { DisplaySSHConfig(config); return; } argcpyp = strdup( (char*) argp ); if ( !argcpyp ) { DynamicPreprocessorFatalMessage("Could not allocate memory to parse SSH options.\n"); return; } cur_tokenp = strtok( argcpyp, " "); while ( cur_tokenp ) { if ( !strcmp( cur_tokenp, SSH_SERVERPORTS_KEYWORD )) { /* If the user specified ports, remove '22' for now since * it now needs to be set explicitely. */ config->ports[ PORT_INDEX( 22 ) ] = 0; /* Eat the open brace. */ cur_tokenp = strtok( NULL, " "); if (( !cur_tokenp ) || ( cur_tokenp[0] != '{' )) { DynamicPreprocessorFatalMessage("Bad value specified for %s.\n", SSH_SERVERPORTS_KEYWORD); //free(argcpyp); //return; } cur_tokenp = strtok( NULL, " "); while (( cur_tokenp ) && ( cur_tokenp[0] != '}' )) { if ( !isdigit( (int)cur_tokenp[0] )) { DynamicPreprocessorFatalMessage("Bad port %s.\n", cur_tokenp ); //free(argcpyp); //return; } else { port = atoi( cur_tokenp ); if( port < 0 || port > MAX_PORTS ) { DynamicPreprocessorFatalMessage("Port value illegitimate: %s\n", cur_tokenp); //free(argcpyp); //return; } config->ports[ PORT_INDEX( port ) ] |= CONV_PORT(port); } cur_tokenp = strtok( NULL, " "); } } else if ( !strcmp( cur_tokenp, SSH_AUTODETECT_KEYWORD )) { config->AutodetectEnabled = 1; } else if ( !strcmp( cur_tokenp, SSH_MAX_ENC_PKTS_KEYWORD )) { cur_tokenp = strtok( NULL, " "); config->MaxEncryptedPackets = (uint16_t)ParseNumInRange(cur_tokenp, SSH_MAX_ENC_PKTS_KEYWORD, MIN_MAX_ENC_PKTS, MAX_MAX_ENC_PKTS); } else if (!strcmp( cur_tokenp, SSH_MAX_CLIENT_BYTES_KEYWORD )) { cur_tokenp = strtok( NULL, " "); config->MaxClientBytes = (uint16_t)ParseNumInRange(cur_tokenp, SSH_MAX_CLIENT_BYTES_KEYWORD, MIN_MAX_CLIENT_BYTES, MAX_MAX_CLIENT_BYTES); } else if ( !strcmp( cur_tokenp, SSH_MAX_SERVER_VERSION_KEYWORD )) { cur_tokenp = strtok( NULL, " "); config->MaxServerVersionLen = (uint16_t)ParseNumInRange(cur_tokenp, SSH_MAX_SERVER_VERSION_KEYWORD, MIN_MAX_SERVER_VERSION_LEN, MAX_MAX_SERVER_VERSION_LEN); } else if ( !strcmp( cur_tokenp, SSH_ENABLE_RESPOVERFLOW_KEYWORD )) { config->EnabledAlerts |= SSH_ALERT_RESPOVERFLOW; } else if ( !strcmp( cur_tokenp, SSH_ENABLE_CRC32_KEYWORD )) { config->EnabledAlerts |= SSH_ALERT_CRC32; } else if ( !strcmp( cur_tokenp, SSH_ENABLE_SECURECRT_KEYWORD )) { config->EnabledAlerts |= SSH_ALERT_SECURECRT; } else if ( !strcmp( cur_tokenp, SSH_ENABLE_PROTOMISMATCH_KEYWORD )) { config->EnabledAlerts |= SSH_ALERT_PROTOMISMATCH; } else if ( !strcmp( cur_tokenp, SSH_ENABLE_WRONGDIR_KEYWORD )) { config->EnabledAlerts |= SSH_ALERT_WRONGDIR; } #if 0 else if ( !strcmp( cur_tokenp, SSH_DISABLE_RULES_KEYWORD )) { config->DisableRules++; } #endif else if( !strcmp( cur_tokenp, SSH_ENABLE_PAYLOAD_SIZE )) { config->EnabledAlerts |= SSH_ALERT_PAYSIZE; } else if( !strcmp( cur_tokenp, SSH_ENABLE_UNRECOGNIZED_VER )) { config->EnabledAlerts |= SSH_ALERT_UNRECOGNIZED; } else { DynamicPreprocessorFatalMessage("Invalid argument: %s\n", cur_tokenp); return; } cur_tokenp = strtok( NULL, " " ); } DisplaySSHConfig(config); free(argcpyp); } /* Display the configuration for the SSH preprocessor. * * PARAMETERS: None. * * RETURNS: Nothing. */ static void DisplaySSHConfig(SSHConfig *config) { int index; int newline; if (config == NULL) return; _dpd.logMsg("SSH config: \n"); _dpd.logMsg(" Autodetection: %s\n", config->AutodetectEnabled ? "ENABLED":"DISABLED"); _dpd.logMsg(" Challenge-Response Overflow Alert: %s\n", config->EnabledAlerts & SSH_ALERT_RESPOVERFLOW ? "ENABLED" : "DISABLED" ); _dpd.logMsg(" SSH1 CRC32 Alert: %s\n", config->EnabledAlerts & SSH_ALERT_CRC32 ? "ENABLED" : "DISABLED" ); _dpd.logMsg(" Server Version String Overflow Alert: %s\n", config->EnabledAlerts & SSH_ALERT_SECURECRT ? "ENABLED" : "DISABLED" ); _dpd.logMsg(" Protocol Mismatch Alert: %s\n", config->EnabledAlerts & SSH_ALERT_PROTOMISMATCH? "ENABLED" : "DISABLED" ); _dpd.logMsg(" Bad Message Direction Alert: %s\n", config->EnabledAlerts & SSH_ALERT_WRONGDIR ? "ENABLED" : "DISABLED" ); _dpd.logMsg(" Bad Payload Size Alert: %s\n", config->EnabledAlerts & SSH_ALERT_PAYSIZE ? "ENABLED" : "DISABLED" ); _dpd.logMsg(" Unrecognized Version Alert: %s\n", config->EnabledAlerts & SSH_ALERT_UNRECOGNIZED ? "ENABLED" : "DISABLED" ); _dpd.logMsg(" Max Encrypted Packets: %d %s \n", config->MaxEncryptedPackets, config->MaxEncryptedPackets == SSH_DEFAULT_MAX_ENC_PKTS ? "(Default)" : "" ); _dpd.logMsg(" Max Server Version String Length: %d %s \n", config->MaxServerVersionLen, config->MaxServerVersionLen == SSH_DEFAULT_MAX_SERVER_VERSION_LEN ? "(Default)" : "" ); if ( config->EnabledAlerts & (SSH_ALERT_RESPOVERFLOW | SSH_ALERT_CRC32)) { _dpd.logMsg(" MaxClientBytes: %d %s \n", config->MaxClientBytes, config->MaxClientBytes == SSH_DEFAULT_MAX_CLIENT_BYTES ? "(Default)" : "" ); } /* Traverse list, printing ports, 5 per line */ newline = 1; _dpd.logMsg(" Ports:\n"); for(index = 0; index < MAX_PORTS; index++) { if( config->ports[ PORT_INDEX(index) ] & CONV_PORT(index) ) { _dpd.logMsg("\t%d", index); if ( !((newline++)% 5) ) { _dpd.logMsg("\n"); } } } _dpd.logMsg("\n"); } /* Returns the true length of the ssh packet, including * the ssh packet header and all padding. * * If the packet length is invalid, 0 is returned. * The return value is never larger than buflen. * * PARAMETERS: * p: Pointer to the SSH packet. * buflen: the size of packet buffer. */ static unsigned int SSHPacket_GetLength(SSH2Packet *p, size_t buflen) { unsigned int ssh_length; if (buflen < sizeof(SSH2Packet)) return 0; ssh_length = ntohl(p->packet_length); if ((ssh_length < sizeof(SSH2Packet) + 1) || ssh_length > SSH2_PACKET_MAX_SIZE) return 0; /* Everything after packet length field (including padding) is included in the packet_length */ ssh_length += sizeof(p->packet_length); if (buflen < ssh_length) return buflen; /* truncated */ return ssh_length; } /* Main runtime entry point for SSH preprocessor. * Analyzes SSH packets for anomalies/exploits. * * PARAMETERS: * * packetp: Pointer to current packet to process. * contextp: Pointer to context block, not used. * * RETURNS: Nothing. */ static void ProcessSSH( void* ipacketp, void* contextp ) { SSHData* sessp = NULL; uint8_t source = 0; uint8_t dest = 0; uint8_t known_port = 0; uint8_t direction; unsigned int offset = 0; SFSnortPacket* packetp; #ifdef TARGET_BASED int16_t app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif uint32_t search_dir_ver, search_dir_keyinit; char flags = STREAM_FLPOLICY_SET_ABSOLUTE; tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; packetp = (SFSnortPacket*) ipacketp; sfPolicyUserPolicySet (ssh_config, policy_id); // preconditions - what we registered for assert(packetp->payload && packetp->payload_size && IPH_IS_VALID(packetp) && packetp->tcp_header); PREPROC_PROFILE_START(sshPerfStats); ssh_eval_config = sfPolicyUserDataGetCurrent(ssh_config); /* Attempt to get a previously allocated SSH block. */ sessp = _dpd.streamAPI->get_application_data(packetp->stream_session_ptr, PP_SSH); if (sessp != NULL) { ssh_eval_config = sfPolicyUserDataGet(sessp->config, sessp->policy_id); known_port = 1; } else { /* If not doing autodetection, check the ports to make sure this is * running on an SSH port, otherwise no need to examine the traffic. */ #ifdef TARGET_BASED app_id = _dpd.streamAPI->get_application_protocol_id(packetp->stream_session_ptr); if (app_id == SFTARGET_UNKNOWN_PROTOCOL) { PREPROC_PROFILE_END(sshPerfStats); return; } if (app_id && (app_id != ssh_app_id)) { PREPROC_PROFILE_END(sshPerfStats); return; } if (app_id == ssh_app_id) { known_port = 1; } if (!app_id) { #endif source = (uint8_t)CheckSSHPort( packetp->src_port ); dest = (uint8_t)CheckSSHPort( packetp->dst_port ); if ( !ssh_eval_config->AutodetectEnabled && !source && !dest ) { /* Not one of the ports we care about. */ PREPROC_PROFILE_END(sshPerfStats); return; } #ifdef TARGET_BASED } #endif /* Check the stream session. If it does not currently * have our SSH data-block attached, create one. */ sessp = SSHGetNewSession(packetp, policy_id); if ( !sessp ) { /* Could not get/create the session data for this packet. */ PREPROC_PROFILE_END(sshPerfStats); return; } /* See if a known server port is involved. */ if (!known_port) { known_port = ( source || dest ? 1 : 0 ); /* If this is a non-SSH port, but autodetect is on, we flag this session to reduce false positives later on. */ if (!known_port && ssh_eval_config->AutodetectEnabled) { sessp->state_flags |= SSH_FLG_AUTODETECTED; flags = STREAM_FLPOLICY_SET_APPEND; } } } /* Don't process if we've missed packets */ if (sessp->state_flags & SSH_FLG_MISSED_PACKETS) { PREPROC_PROFILE_END(sshPerfStats); return; } /* We're interested in this session. Turn on stream reassembly. */ if ( !(sessp->state_flags & SSH_FLG_REASSEMBLY_SET )) { _dpd.streamAPI->set_reassembly(packetp->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_BOTH, flags); sessp->state_flags |= SSH_FLG_REASSEMBLY_SET; } /* Make sure this preprocessor should run. */ /* check if we're waiting on stream reassembly */ if ( packetp->flags & FLAG_STREAM_INSERT ) { PREPROC_PROFILE_END(sshPerfStats); return; } /* If we picked up mid-stream or missed any packets (midstream pick up * means we've already missed packets) set missed packets flag and make * sure we don't do any more reassembly on this session */ if ((_dpd.streamAPI->get_session_flags(packetp->stream_session_ptr) & SSNFLAG_MIDSTREAM) || _dpd.streamAPI->missed_packets(packetp->stream_session_ptr, SSN_DIR_BOTH)) { /* Order only matters if the packets are not encrypted */ if ( !(sessp->state_flags & SSH_FLG_SESS_ENCRYPTED )) { /* Don't turn off reassembly if autodetected since another preprocessor * may actually be looking at this session as well and the SSH * autodetect of this session may be wrong. */ if (!(sessp->state_flags & SSH_FLG_AUTODETECTED)) { _dpd.streamAPI->set_reassembly(packetp->stream_session_ptr, STREAM_FLPOLICY_IGNORE, SSN_DIR_BOTH, STREAM_FLPOLICY_SET_APPEND); } sessp->state_flags |= SSH_FLG_MISSED_PACKETS; PREPROC_PROFILE_END(sshPerfStats); return; } } /* Get the direction of the packet. */ if( packetp->flags & FLAG_FROM_SERVER ) { direction = SSH_DIR_FROM_SERVER; search_dir_ver = SSH_FLG_SERV_IDSTRING_SEEN; search_dir_keyinit = SSH_FLG_SERV_PKEY_SEEN | SSH_FLG_SERV_KEXINIT_SEEN; } else { direction = SSH_DIR_FROM_CLIENT; search_dir_ver = SSH_FLG_CLIENT_IDSTRING_SEEN; search_dir_keyinit = SSH_FLG_CLIENT_SKEY_SEEN | SSH_FLG_CLIENT_KEXINIT_SEEN; } if ( !(sessp->state_flags & SSH_FLG_SESS_ENCRYPTED )) { /* If server and client have not performed the protocol * version exchange yet, must look for version strings. */ if ( !(sessp->state_flags & search_dir_ver) ) { offset = ProcessSSHProtocolVersionExchange( sessp, packetp, direction, known_port); if (!offset) { /*Error processing protovers exchange msg */ PREPROC_PROFILE_END(sshPerfStats); return; } /* found protocol version. Stream reassembly might have appended an ssh packet, * such as the key exchange init. Thus call ProcessSSHKeyInitExchange() too. */ } /* Expecting to see the key init exchange at this point * (in SSH2) or the actual key exchange if SSH1 */ if ( !(sessp->state_flags & search_dir_keyinit) ) { offset = ProcessSSHKeyInitExchange( sessp, packetp, direction, offset); if (!offset) { if ( !(sessp->state_flags & SSH_FLG_SESS_ENCRYPTED )) { PREPROC_PROFILE_END(sshPerfStats); return; } } } /* If SSH2, need to process the actual key exchange msgs. * The actual key exchange type was negotiated in the * key exchange init msgs. SSH1 won't arrive here. */ offset = ProcessSSHKeyExchange( sessp, packetp, direction, offset); if (!offset) { PREPROC_PROFILE_END(sshPerfStats); return; } } { /* Traffic on this session is currently encrypted. * Two of the major SSH exploits, SSH1 CRC-32 and * the Challenge-Response Overflow attack occur within * the encrypted portion of the SSH session. Therefore, * the only way to detect these attacks is by examining * amounts of data exchanged for anomalies. */ sessp->num_enc_pkts++; if ( sessp->num_enc_pkts <= ssh_eval_config->MaxEncryptedPackets ) { if ( direction == SSH_DIR_FROM_CLIENT ) { if(!offset) { sessp->num_client_bytes += packetp->payload_size; } else { sessp->num_client_bytes += (packetp->payload_size - offset); } if ( sessp->num_client_bytes >= ssh_eval_config->MaxClientBytes ) { /* Probable exploit in progress.*/ if (sessp->version == SSH_VERSION_1) { if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_CRC32 ) { ALERT(SSH_EVENT_CRC32, SSH_EVENT_CRC32_STR); _dpd.streamAPI->stop_inspection( packetp->stream_session_ptr, packetp, SSN_DIR_BOTH, -1, 0 ); } } else { if (ssh_eval_config->EnabledAlerts & SSH_ALERT_RESPOVERFLOW ) { ALERT(SSH_EVENT_RESPOVERFLOW, SSH_EVENT_RESPOVERFLOW_STR); _dpd.streamAPI->stop_inspection( packetp->stream_session_ptr, packetp, SSN_DIR_BOTH, -1, 0 ); } } } } else { /* * Have seen a server response, so * this appears to be a valid exchange. * Reset suspicious byte count to zero. */ sessp->num_client_bytes = 0; } } else { /* Have already examined more than the limit * of encrypted packets. Both the Gobbles and * the CRC32 attacks occur during authentication * and therefore cannot be used late in an * encrypted session. For performance purposes, * stop examining this session. */ _dpd.streamAPI->stop_inspection( packetp->stream_session_ptr, packetp, SSN_DIR_BOTH, -1, 0 ); } } PREPROC_PROFILE_END(sshPerfStats); } /* Retrieves the SSH data block registered with the stream * session associated w/ the current packet. If none exists, * allocates it and registers it with the stream API. * * PARAMETERS: * * packetp: Pointer to the packet from which/in which to * retrieve/store the SSH data block. * * RETURNS: Pointer to an SSH data block, upon success. * NULL, upon failure. */ SSHData * SSHGetNewSession(SFSnortPacket *packetp, tSfPolicyId policy_id) { SSHData* datap = NULL; /* Sanity check(s) */ if (( !packetp ) || ( !packetp->stream_session_ptr )) { return NULL; } datap = (SSHData *)calloc(1, sizeof(SSHData)); if ( !datap ) return NULL; /*Register the new SSH data block in the stream session. */ _dpd.streamAPI->set_application_data( packetp->stream_session_ptr, PP_SSH, datap, FreeSSHData ); datap->policy_id = policy_id; datap->config = ssh_config; ((SSHConfig *)sfPolicyUserDataGetCurrent(ssh_config))->ref_count++; return datap; } static int SshFreeConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SSHConfig *pPolicyConfig = (SSHConfig *)pData; //do any housekeeping before freeing SSHConfig sfPolicyUserDataClear (config, policyId); free(pPolicyConfig); return 0; } static void SSHFreeConfig(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, SshFreeConfigPolicy); sfPolicyConfigDelete(config); } /* Registered as a callback with our SSH data blocks when * they are added to the underlying stream session. Called * by the stream preprocessor when a session is about to be * destroyed. * * PARAMETERS: * * idatap: Pointer to the moribund data. * * RETURNS: Nothing. */ static void FreeSSHData( void* idatap ) { SSHData *ssn = (SSHData *)idatap; SSHConfig *config = NULL; if (ssn == NULL) return; if (ssn->config != NULL) { config = (SSHConfig *)sfPolicyUserDataGet(ssn->config, ssn->policy_id); } if (config != NULL) { config->ref_count--; if ((config->ref_count == 0) && (ssn->config != ssh_config)) { sfPolicyUserDataClear (ssn->config, ssn->policy_id); free(config); if (sfPolicyUserPolicyGetActive(ssn->config) == 0) { /* No more outstanding configs - free the config array */ SSHFreeConfig(ssn->config); } } } free(ssn); } /* Validates given port as an SSH server port. * * PARAMETERS: * * port: Port to validate. * * RETURNS: SSH_TRUE, if the port is indeed an SSH server port. * SSH_FALSE, otherwise. */ static inline int CheckSSHPort( uint16_t port ) { if ( ssh_eval_config->ports[ PORT_INDEX(port) ] & CONV_PORT( port ) ) { return SSH_TRUE; } return SSH_FALSE; } /* Checks if the string 'str' is 'max' bytes long or longer. * Returns 0 if 'str' is less than or equal to 'max' bytes; * returns 1 otherwise. */ static inline int SSHCheckStrlen(char *str, int max) { while(*(str++) && max--) ; if(max > 0) return 0; /* str size is <= max bytes */ return 1; } /* Attempts to process current packet as a protocol version exchange * packet. This function will be called if either the client or server * protocol version message (or both) has not been sent. * * PARAMETERS: * * sessionp: Pointer to SSH data for packet's session. * packetp: Pointer to the packet to inspect. * direction: Which direction the packet is going. * known_port: A pre-configured or default server port is involved. * * RETURNS: SSH_SUCCESS, if successfully processed a proto exch msg * SSH_FAILURE, otherwise. */ static unsigned int ProcessSSHProtocolVersionExchange( SSHData* sessionp, SFSnortPacket* packetp, uint8_t direction, uint8_t known_port ) { char* version_stringp = (char*) packetp->payload; uint8_t version; char *version_end; /* Get the version. */ if ( packetp->payload_size >= 6 && !strncasecmp( version_stringp, "SSH-1.", 6)) { if (( packetp->payload_size > 7 ) && ( version_stringp[6] == '9') && (version_stringp[7] == '9')) { /* SSH 1.99 which is the same as SSH2.0 */ version = SSH_VERSION_2; } else { version = SSH_VERSION_1; } /* CAN-2002-0159 */ /* Verify the version string is not greater than * the configured maximum. * We've already verified the first 6 bytes, so we'll start * check from &version_string[6] */ if( (ssh_eval_config->EnabledAlerts & SSH_ALERT_SECURECRT ) && /* First make sure the payload itself is sufficiently large */ (packetp->payload_size > ssh_eval_config->MaxServerVersionLen) && /* CheckStrlen will check if the version string up to * MaxServerVersionLen+1 since there's no reason to * continue checking after that point*/ (SSHCheckStrlen(&version_stringp[6], ssh_eval_config->MaxServerVersionLen-6))) { ALERT(SSH_EVENT_SECURECRT, SSH_EVENT_SECURECRT_STR); } } else if ( packetp->payload_size >= 6 && !strncasecmp( version_stringp, "SSH-2.", 6)) { version = SSH_VERSION_2; } else { /* Not SSH on SSH port, CISCO vulnerability */ if ((direction == SSH_DIR_FROM_CLIENT) && ( known_port != 0 ) && ( !(sessionp->state_flags & SSH_FLG_AUTODETECTED) ) && ( ssh_eval_config->EnabledAlerts & SSH_ALERT_PROTOMISMATCH )) { ALERT(SSH_EVENT_PROTOMISMATCH, SSH_EVENT_PROTOMISMATCH_STR); } return 0; } /* Saw a valid protocol exchange message. Mark the session * according to the direction. */ switch( direction ) { case SSH_DIR_FROM_SERVER: sessionp->state_flags |= SSH_FLG_SERV_IDSTRING_SEEN; break; case SSH_DIR_FROM_CLIENT: sessionp->state_flags |= SSH_FLG_CLIENT_IDSTRING_SEEN; break; } sessionp->version = version; version_end = memchr(version_stringp, '\n', packetp->payload_size); if (version_end) return ((version_end - version_stringp) + 1); /* incomplete version string, should end with \n or \r\n for sshv2 */ return packetp->payload_size; } /* Called to process SSH1 key exchange or SSH2 key exchange init * messages. On failure, inspection will be continued, but the packet * will be alerted on, and ignored. * * PARAMETERS: * * sessionp: Pointer to SSH data for packet's session. * packetp: Pointer to the packet to inspect. * direction: Which direction the packet is going. * * RETURN: SSH_SUCCESS, if a valid key exchange message is processed * SSH_FAILURE, otherwise. */ static unsigned int ProcessSSHKeyInitExchange( SSHData* sessionp, SFSnortPacket* packetp, uint8_t direction, unsigned int offset ) { SSH2Packet* ssh2packetp = NULL; unsigned int payload_size = packetp->payload_size; const char *payload = packetp->payload; unsigned int ssh_length = 0; if (payload_size < sizeof(SSH2Packet) || (payload_size < (offset + sizeof(SSH2Packet))) || (payload_size <= offset)) return 0; payload_size -= offset; payload += offset; if ( sessionp->version == SSH_VERSION_1 ) { uint32_t length; uint8_t padding_length; uint8_t message_type; /* * Validate packet payload. * First 4 bytes should have the SSH packet length, * minus any padding. */ if ( payload_size < 4 ) { if(ssh_eval_config->EnabledAlerts & SSH_ALERT_PAYSIZE) { ALERT(SSH_EVENT_PAYLOAD_SIZE, SSH_PAYLOAD_SIZE_STR); } return 0; } /* * SSH1 key exchange is very simple and * consists of only two messages, a server * key and a client key message.` */ memcpy(&length, payload, sizeof(length)); length = ntohl(length); /* Packet payload should be larger than length, due to padding. */ if ( payload_size < length ) { if(ssh_eval_config->EnabledAlerts & SSH_ALERT_PAYSIZE) { ALERT(SSH_EVENT_PAYLOAD_SIZE, SSH_PAYLOAD_SIZE_STR); } return 0; } padding_length = (uint8_t)(8 - (length % 8)); /* * With the padding calculated, verify payload is sufficiently large * to include the message type. */ if ( payload_size < (padding_length + 4 + 1 + offset)) { if((offset == 0) && (ssh_eval_config->EnabledAlerts & SSH_ALERT_PAYSIZE)) { ALERT(SSH_EVENT_PAYLOAD_SIZE, SSH_PAYLOAD_SIZE_STR); } return 0; } message_type = *( (uint8_t*) (payload + padding_length + 4)); switch( message_type ) { case SSH_MSG_V1_SMSG_PUBLIC_KEY: if ( direction == SSH_DIR_FROM_SERVER ) { sessionp->state_flags |= SSH_FLG_SERV_PKEY_SEEN; } else if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_WRONGDIR ) { /* Server msg not from server. */ ALERT(SSH_EVENT_WRONGDIR, SSH_EVENT_WRONGDIR_STR); } break; case SSH_MSG_V1_CMSG_SESSION_KEY: if ( direction == SSH_DIR_FROM_CLIENT ) { sessionp->state_flags |= SSH_FLG_CLIENT_SKEY_SEEN; } else if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_WRONGDIR ) { /* Client msg not from client. */ ALERT(SSH_EVENT_WRONGDIR, SSH_EVENT_WRONGDIR_STR); } break; default: /* Invalid msg type*/ break; } /* Once the V1 key exchange is done, remainder of * communications are encrypted. */ ssh_length = length + padding_length + sizeof(length) + offset; if ( (sessionp->state_flags & SSH_FLG_V1_KEYEXCH_DONE) == SSH_FLG_V1_KEYEXCH_DONE ) { sessionp->state_flags |= SSH_FLG_SESS_ENCRYPTED; } } else if ( sessionp->version == SSH_VERSION_2 ) { /* We want to overlay the payload on our data packet struct, * so first verify that the payload size is big enough. * This may legitimately occur such as in the case of a * retransmission. */ if ( payload_size < sizeof(SSH2Packet) ) { return 0; } /* Overlay the SSH2 binary data packet struct on the packet */ ssh2packetp = (SSH2Packet*) payload; if ( payload_size < SSH2_HEADERLEN + 1) { /* Invalid packet length. */ return 0; } ssh_length = offset + ntohl(ssh2packetp->packet_length) + sizeof(ssh2packetp->packet_length); switch ( payload[SSH2_HEADERLEN] ) { case SSH_MSG_KEXINIT: sessionp->state_flags |= (direction == SSH_DIR_FROM_SERVER ? SSH_FLG_SERV_KEXINIT_SEEN : SSH_FLG_CLIENT_KEXINIT_SEEN ); break; default: /* Unrecognized message type. */ break; } } else { if(ssh_eval_config->EnabledAlerts & SSH_ALERT_UNRECOGNIZED) { /* Unrecognized version. */ ALERT(SSH_EVENT_VERSION, SSH_VERSION_STR); } return 0; } if(ssh_length < packetp->payload_size) return ssh_length; else return 0; } /* Called to process SSH2 key exchange msgs (key exch init msgs already * processed earlier). On failure, inspection will be continued, but the * packet will be alerted on, and ignored. * * PARAMETERS: * * sessionp: Pointer to SSH data for packet's session. * packetp: Pointer to the packet to inspect. * direction: Which direction the packet is going. * * RETURN: SSH_SUCCESS, if a valid key exchange message is processed * SSH_FAILURE, otherwise. */ static unsigned int ProcessSSHKeyExchange( SSHData* sessionp, SFSnortPacket* packetp, uint8_t direction, unsigned int offset) { SSH2Packet* ssh2packetp = NULL; unsigned int payload_size = packetp->payload_size; const char *payload = packetp->payload; unsigned int ssh_length; bool next_packet = true; unsigned int npacket_offset = 0; if (payload_size < sizeof(SSH2Packet) || (payload_size < (offset + sizeof(SSH2Packet))) || (payload_size <= offset)) { return 0; } payload_size -= offset; payload += offset; while(next_packet) { ssh2packetp = (SSH2Packet*) (payload + npacket_offset); ssh_length = SSHPacket_GetLength(ssh2packetp, payload_size); if (ssh_length == 0) { if(ssh_eval_config->EnabledAlerts & SSH_ALERT_PAYSIZE) { /* Invalid packet length. */ ALERT(SSH_EVENT_PAYLOAD_SIZE, SSH_PAYLOAD_SIZE_STR); } return 0; } switch(payload[npacket_offset + SSH2_HEADERLEN] ) { case SSH_MSG_KEXDH_INIT: if ( direction == SSH_DIR_FROM_CLIENT ) { sessionp->state_flags |= SSH_FLG_KEXDH_INIT_SEEN; } else if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_WRONGDIR ) { /* Client msg from server. */ ALERT(SSH_EVENT_WRONGDIR, SSH_EVENT_WRONGDIR_STR); } break; case SSH_MSG_KEXDH_REPLY: if ( direction == SSH_DIR_FROM_SERVER ) { /* KEXDH_REPLY has the same msg * type as the new style GEX_REPLY */ sessionp->state_flags |= SSH_FLG_KEXDH_REPLY_SEEN | SSH_FLG_GEX_REPLY_SEEN; } else if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_WRONGDIR ) { /* Server msg from client. */ ALERT(SSH_EVENT_WRONGDIR, SSH_EVENT_WRONGDIR_STR); } break; case SSH_MSG_KEXDH_GEX_REQ: if ( direction == SSH_DIR_FROM_CLIENT ) { sessionp->state_flags |= SSH_FLG_GEX_REQ_SEEN; } else if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_WRONGDIR ) { /* Server msg from client. */ ALERT(SSH_EVENT_WRONGDIR, SSH_EVENT_WRONGDIR_STR); } break; case SSH_MSG_KEXDH_GEX_GRP: if ( direction == SSH_DIR_FROM_SERVER ) { sessionp->state_flags |= SSH_FLG_GEX_GRP_SEEN; } else if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_WRONGDIR ) { /* Client msg from server. */ ALERT(SSH_EVENT_WRONGDIR, SSH_EVENT_WRONGDIR_STR); } break; case SSH_MSG_KEXDH_GEX_INIT: if ( direction == SSH_DIR_FROM_CLIENT ) { sessionp->state_flags |= SSH_FLG_GEX_INIT_SEEN; } else if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_WRONGDIR ) { /* Server msg from client. */ ALERT(SSH_EVENT_WRONGDIR, SSH_EVENT_WRONGDIR_STR); } break; case SSH_MSG_NEWKEYS: /* This message is required to complete the * key exchange. Both server and client should * send one, but as per Alex Kirk's note on this, * in some implementations the server does not * actually send this message. So receving a new * keys msg from the client is sufficient. */ if ( direction == SSH_DIR_FROM_CLIENT ) { sessionp->state_flags |= SSH_FLG_NEWKEYS_SEEN; } break; default: /* Unrecognized message type. Possibly encrypted */ sessionp->state_flags |= SSH_FLG_SESS_ENCRYPTED; return offset; } /* If either an old-style or new-style Diffie Helman exchange * has completed, the session will enter encrypted mode. */ if (( (sessionp->state_flags & SSH_FLG_V2_DHOLD_DONE) == SSH_FLG_V2_DHOLD_DONE ) || ( (sessionp->state_flags & SSH_FLG_V2_DHNEW_DONE) == SSH_FLG_V2_DHNEW_DONE )) { sessionp->state_flags |= SSH_FLG_SESS_ENCRYPTED; if(ssh_length < payload_size) return (npacket_offset+ ssh_length); else return 0; } if ((ssh_length < payload_size) && (ssh_length >= 4)) { npacket_offset += ssh_length; payload_size -= ssh_length; } else { next_packet = false; npacket_offset = 0; if(ssh_eval_config->EnabledAlerts & SSH_ALERT_PAYSIZE) { /* Invalid packet length. */ ALERT(SSH_EVENT_PAYLOAD_SIZE, SSH_PAYLOAD_SIZE_STR); } } } return npacket_offset; } static void _addPortsToStream5Filter(struct _SnortConfig *sc, SSHConfig *config, tSfPolicyId policy_id) { if (config == NULL) return; if (_dpd.streamAPI) { int portNum; for (portNum = 0; portNum < MAXPORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status( sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); } } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status(sc, ssh_app_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif static int SSHCheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { _dpd.setParserPolicy(sc, policyId); if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SSHCheckPolicyConfig(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } static int SSHCheckConfig(struct _SnortConfig *sc) { int rval; if ((rval = sfPolicyUserDataIterate (sc, ssh_config, SSHCheckPolicyConfig))) return rval; return 0; } static void SSHCleanExit(int signal, void *data) { if (ssh_config != NULL) { SSHFreeConfig(ssh_config); ssh_config = NULL; } } #ifdef SNORT_RELOAD static void SSHReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId ssh_swap_config = (tSfPolicyUserContextId)*new_config; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); SSHConfig * pPolicyConfig = NULL; if (ssh_swap_config == NULL) { //create a context ssh_swap_config = sfPolicyConfigCreate(); if (ssh_swap_config == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory " "for SSH config.\n"); } if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("SetupSSH(): The Stream preprocessor must be enabled.\n"); } *new_config = (void *)ssh_swap_config; } sfPolicyUserPolicySet (ssh_swap_config, policy_id); pPolicyConfig = (SSHConfig *)sfPolicyUserDataGetCurrent(ssh_swap_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("SSH preprocessor can only be " "configured once.\n"); } pPolicyConfig = (SSHConfig *)calloc(1, sizeof(SSHConfig)); if (!pPolicyConfig) { DynamicPreprocessorFatalMessage("Could not allocate memory for " "SSH preprocessor configuration.\n"); } sfPolicyUserDataSetCurrent(ssh_swap_config, pPolicyConfig); ParseSSHArgs(pPolicyConfig, (u_char *)args); _dpd.addPreproc( sc, ProcessSSH, PRIORITY_APPLICATION, PP_SSH, PROTO_BIT__TCP ); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } static int SSHReloadVerify(struct _SnortConfig *sc, void *swap_config) { if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("SetupSSH(): The Stream preprocessor must be enabled.\n"); return -1; } return 0; } static int SshFreeUnusedConfigPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SSHConfig *pPolicyConfig = (SSHConfig *)pData; //do any housekeeping before freeing SSHConfig if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); free(pPolicyConfig); } return 0; } static void * SSHReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId ssh_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = ssh_config; if (ssh_swap_config == NULL) return NULL; ssh_config = ssh_swap_config; sfPolicyUserDataFreeIterate (old_config, SshFreeUnusedConfigPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) { /* No more outstanding configs - free the config array */ return (void *)old_config; } return NULL; } static void SSHReloadSwapFree(void *data) { if (data == NULL) return; SSHFreeConfig((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/ssh/Makefile.am0000644000000000000000000000115411746560364017712 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_ssh_preproc.la libsf_ssh_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_ssh_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_ssh_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sfPolicyUserData.c endif libsf_ssh_preproc_la_SOURCES = \ spp_ssh.c \ spp_ssh.h EXTRA_DIST = \ sf_ssh.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/ssh/Makefile.in0000644000000000000000000005041212260606523017712 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/ssh DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_ssh_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_ssh_preproc_la_OBJECTS = spp_ssh.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_ssh_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_ssh_preproc_la_OBJECTS = $(am_libsf_ssh_preproc_la_OBJECTS) \ $(nodist_libsf_ssh_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_ssh_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_ssh_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_ssh_preproc_la_SOURCES) \ $(nodist_libsf_ssh_preproc_la_SOURCES) DIST_SOURCES = $(libsf_ssh_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_ssh_preproc.la libsf_ssh_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_ssh_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_ssh_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_ssh_preproc_la_SOURCES = \ spp_ssh.c \ spp_ssh.h EXTRA_DIST = \ sf_ssh.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/ssh/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/ssh/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_ssh_preproc.la: $(libsf_ssh_preproc_la_OBJECTS) $(libsf_ssh_preproc_la_DEPENDENCIES) $(EXTRA_libsf_ssh_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_ssh_preproc_la_LINK) -rpath $(libdir) $(libsf_ssh_preproc_la_OBJECTS) $(libsf_ssh_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/smtp/0000755000000000000000000000000012260606563016115 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/smtp/sf_smtp.dsp0000644000000000000000000001512212153454770020223 00000000000000# Microsoft Developer Studio Project File - Name="sf_smtp" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_smtp - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_smtp.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_smtp.mak" CFG="sf_smtp - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_smtp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_smtp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_smtp - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "SF_SNORT_PREPROC_DLL" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 pcre.lib ws2_32.lib ../libs/Release/sfdynamic_preproc_libs.lib /nologo /dll /machine:I386 /libpath:"../../../src/win32/WIN32-Libraries" !ELSEIF "$(CFG)" == "sf_smtp - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "SF_SNORT_PREPROC_DLL" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 pcre.lib ws2_32.lib ../libs/Debug/sfdynamic_preproc_libs.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../src/win32/WIN32-Libraries" !ENDIF # Begin Target # Name "sf_smtp - Win32 Release" # Name "sf_smtp - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\mempool.c # End Source File # Begin Source File SOURCE=..\include\sf_base64decode.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_email_attach_decode.c # End Source File # Begin Source File SOURCE=..\include\sf_sdlist.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\smtp_config.c # End Source File # Begin Source File SOURCE=.\smtp_log.c # End Source File # Begin Source File SOURCE=.\smtp_normalize.c # End Source File # Begin Source File SOURCE=.\smtp_util.c # End Source File # Begin Source File SOURCE=.\smtp_xlink2state.c # End Source File # Begin Source File SOURCE=.\snort_smtp.c # End Source File # Begin Source File SOURCE=.\spp_smtp.c # End Source File # Begin Source File SOURCE=..\include\util_unfold.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\mempool.h # End Source File # Begin Source File SOURCE=..\include\sf_base64decode.h # End Source File # Begin Source File SOURCE=..\include\sf_email_attach_decode.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=..\include\sf_sdlist.h # End Source File # Begin Source File SOURCE=.\smtp_config.h # End Source File # Begin Source File SOURCE=.\smtp_log.h # End Source File # Begin Source File SOURCE=.\smtp_normalize.h # End Source File # Begin Source File SOURCE=.\smtp_util.h # End Source File # Begin Source File SOURCE=.\smtp_xlink2state.h # End Source File # Begin Source File SOURCE=.\snort_smtp.h # End Source File # Begin Source File SOURCE=.\spp_smtp.h # End Source File # Begin Source File SOURCE=..\include\util_unfold.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/smtp/spp_smtp.h0000644000000000000000000000216712260565732020063 00000000000000 /* * spp_smtp.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * Author: Andy Mullican * * Description: * * This file defines the publicly available functions for the SMTP * functionality for Snort. * */ #ifndef __SPP_SMTP_H__ #define __SPP_SMTP_H__ void SetupSMTP(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/smtp/spp_smtp.c0000644000000000000000000005635512260565732020066 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * spp_smtp.c * * Author: Andy Mullican * * Description: * * This file initializes SMTP as a Snort preprocessor. * * This file registers the SMTP initialization function, * adds the SMTP function into the preprocessor list. * * In general, this file is a wrapper to SMTP functionality, * by interfacing with the Snort preprocessor functions. The rest * of SMTP should be separate from the preprocessor hooks. * **************************************************************************/ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_smtp.h" #include "sf_preproc_info.h" #include "snort_smtp.h" #include "smtp_config.h" #include "smtp_log.h" #include "preprocids.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "snort_debug.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "profiler.h" #ifdef PERF_PROFILING PreprocStats smtpPerfStats; PreprocStats smtpDetectPerfStats; int smtpDetectCalled = 0; #endif #include "sf_types.h" #include "mempool.h" #include "snort_bounds.h" #include "file_api.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 1; const int BUILD_VERSION = 9; const char *PREPROC_NAME = "SF_SMTP"; const char *PROTOCOL_NAME = "SMTP"; #define SetupSMTP DYNAMIC_PREPROC_SETUP MemPool *smtp_mime_mempool = NULL; SMTP_Stats smtp_stats; MemPool *smtp_mempool = NULL; tSfPolicyUserContextId smtp_config = NULL; SMTPConfig *smtp_eval_config = NULL; extern SMTP smtp_no_session; extern int16_t smtp_proto_id; static void SMTPInit(struct _SnortConfig *, char *); static void SMTPDetect(void *, void *context); static void SMTPCleanExitFunction(int, void *); static void SMTPResetFunction(int, void *); static void SMTPResetStatsFunction(int, void *); static void _addPortsToStream5Filter(struct _SnortConfig *, SMTPConfig *, tSfPolicyId); static void SMTP_RegXtraDataFuncs(SMTPConfig *config); static void SMTP_PrintStats(int); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static int SMTPCheckConfig(struct _SnortConfig *); #ifdef SNORT_RELOAD static void SMTPReload(struct _SnortConfig *, char *, void **); static int SMTPReloadVerify(struct _SnortConfig *, void *); static void * SMTPReloadSwap(struct _SnortConfig *, void *); static void SMTPReloadSwapFree(void *); #endif /* * Function: SetupSMTP() * * Purpose: Registers the preprocessor keyword and initialization * function into the preprocessor list. This is the function that * gets called from InitPreprocessors() in plugbase.c. * * Arguments: None. * * Returns: void function * */ void SetupSMTP(void) { /* link the preprocessor keyword to the init function in the preproc list */ #ifndef SNORT_RELOAD _dpd.registerPreproc("smtp", SMTPInit); #else _dpd.registerPreproc("smtp", SMTPInit, SMTPReload, SMTPReloadVerify, SMTPReloadSwap, SMTPReloadSwapFree); #endif } /* * Function: SMTPInit(char *) * * Purpose: Calls the argument parsing function, performs final setup on data * structs, links the preproc function into the function list. * * Arguments: args => ptr to argument string * * Returns: void function * */ static void SMTPInit(struct _SnortConfig *sc, char *args) { SMTPToken *tmp; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); SMTPConfig * pPolicyConfig = NULL; if (smtp_config == NULL) { //create a context smtp_config = sfPolicyConfigCreate(); if (smtp_config == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create SMTP " "configuration.\n"); } /* Initialize the searches not dependent on configuration. * headers, reponsed, data, mime boundary regular expression */ SMTP_SearchInit(); /* zero out static SMTP global used for stateless SMTP or if there * is no session pointer */ memset(&smtp_no_session, 0, sizeof(SMTP)); /* Put the preprocessor function into the function list */ /* _dpd.addPreproc(SMTPDetect, PRIORITY_APPLICATION, PP_SMTP, PROTO_BIT__TCP);*/ _dpd.addPreprocExit(SMTPCleanExitFunction, NULL, PRIORITY_LAST, PP_SMTP); _dpd.addPreprocReset(SMTPResetFunction, NULL, PRIORITY_LAST, PP_SMTP); _dpd.registerPreprocStats(SMTP_PROTO_REF_STR, SMTP_PrintStats); _dpd.addPreprocResetStats(SMTPResetStatsFunction, NULL, PRIORITY_LAST, PP_SMTP); _dpd.addPreprocConfCheck(sc, SMTPCheckConfig); #ifdef TARGET_BASED smtp_proto_id = _dpd.findProtocolReference(SMTP_PROTO_REF_STR); if (smtp_proto_id == SFTARGET_UNKNOWN_PROTOCOL) smtp_proto_id = _dpd.addProtocolReference(SMTP_PROTO_REF_STR); DEBUG_WRAP(DebugMessage(DEBUG_SMTP,"SMTP: Target-based: Proto id for %s: %u.\n", SMTP_PROTO_REF_STR, smtp_proto_id);); #endif #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("smtp", (void*)&smtpPerfStats, 0, _dpd.totalPerfStats); #endif } sfPolicyUserPolicySet (smtp_config, policy_id); pPolicyConfig = (SMTPConfig *)sfPolicyUserDataGetCurrent(smtp_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("Can only configure SMTP preprocessor once.\n"); } pPolicyConfig = (SMTPConfig *)calloc(1, sizeof(SMTPConfig)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create SMTP " "configuration.\n"); } sfPolicyUserDataSetCurrent(smtp_config, pPolicyConfig); SMTP_RegXtraDataFuncs(pPolicyConfig); SMTP_InitCmds(pPolicyConfig); SMTP_ParseArgs(pPolicyConfig, args); SMTP_CheckConfig(pPolicyConfig, smtp_config); SMTP_PrintConfig(pPolicyConfig); if(pPolicyConfig->disabled) return; _dpd.addPreproc(sc, SMTPDetect, PRIORITY_APPLICATION, PP_SMTP, PROTO_BIT__TCP); if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled " "for SMTP preprocessor\n"); } /* Command search - do this here because it's based on configuration */ pPolicyConfig->cmd_search_mpse = _dpd.searchAPI->search_instance_new(); if (pPolicyConfig->cmd_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate SMTP " "command search.\n"); } for (tmp = pPolicyConfig->cmds; tmp->name != NULL; tmp++) { pPolicyConfig->cmd_search[tmp->search_id].name = tmp->name; pPolicyConfig->cmd_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pPolicyConfig->cmd_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pPolicyConfig->cmd_search_mpse); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } /* * Function: SMTPDetect(void *, void *) * * Purpose: Perform the preprocessor's intended function. This can be * simple (statistics collection) or complex (IP defragmentation) * as you like. Try not to destroy the performance of the whole * system by trying to do too much.... * * Arguments: p => pointer to the current packet data struct * * Returns: void function * */ static void SMTPDetect(void *pkt, void *context) { SFSnortPacket *p = (SFSnortPacket *)pkt; tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; // preconditions - what we registered for assert(IsTCP(p) && p->payload && p->payload_size); PREPROC_PROFILE_START(smtpPerfStats); DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP Start (((((((((((((((((((((((((((((((((((((((\n");); sfPolicyUserPolicySet (smtp_config, policy_id); SnortSMTP(p); DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP End )))))))))))))))))))))))))))))))))))))))))\n\n");); PREPROC_PROFILE_END(smtpPerfStats); #ifdef PERF_PROFILING if (PROFILING_PREPROCS && smtpDetectCalled) { smtpPerfStats.ticks -= smtpDetectPerfStats.ticks; /* And Reset ticks to 0 */ smtpDetectPerfStats.ticks = 0; smtpDetectCalled = 0; } #endif } /* * Function: SMTPCleanExitFunction(int, void *) * * Purpose: This function gets called when Snort is exiting, if there's * any cleanup that needs to be performed (e.g. closing files) * it should be done here. * * Arguments: signal => the code of the signal that was issued to Snort * data => any arguments or data structs linked to this * function when it was registered, may be * needed to properly exit * * Returns: void function */ static void SMTPCleanExitFunction(int signal, void *data) { SMTP_Free(); if (mempool_destroy(smtp_mime_mempool) == 0) { free(smtp_mime_mempool); smtp_mime_mempool = NULL; } if (mempool_destroy(smtp_mempool) == 0) { free(smtp_mempool); smtp_mempool = NULL; } } static void SMTPResetFunction(int signal, void *data) { return; } static void SMTPResetStatsFunction(int signal, void *data) { return; } static void _addPortsToStream5Filter(struct _SnortConfig *sc, SMTPConfig *config, tSfPolicyId policy_id) { unsigned int portNum; if (config == NULL) return; for (portNum = 0; portNum < MAXPORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status(sc, smtp_proto_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif static int SMTPEnableDecoding(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void *pData) { SMTPConfig *context = (SMTPConfig *)pData; if (pData == NULL) return 0; if(context->disabled) return 0; if(!SMTP_IsDecodingEnabled(context)) return 1; return 0; } static int SMTPLogExtraData(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void *pData) { SMTPConfig *context = (SMTPConfig *)pData; if (pData == NULL) return 0; if(context->disabled) return 0; if(context->log_config.log_email_hdrs || context->log_config.log_filename || context->log_config.log_mailfrom || context->log_config.log_rcptto) return 1; return 0; } static int CheckFilePolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SMTPConfig *context = (SMTPConfig *)pData; context->file_depth = _dpd.fileAPI->get_max_file_depth(); if (context->file_depth > -1) context->log_config.log_filename = 1; updateMaxDepth(context->file_depth, &context->max_depth); return 0; } static int SMTPCheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SMTPConfig *context = (SMTPConfig *)pData; _dpd.setParserPolicy(sc, policyId); /* In a multiple-policy setting, the SMTP preproc can be turned on in a "disabled" state. In this case, we don't require Stream5. */ if (context->disabled) return 0; if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled " "for SMTP preprocessor\n"); } return 0; } static void SMTP_RegXtraDataFuncs(SMTPConfig *config) { if ((_dpd.streamAPI == NULL) || !config) return; config->xtra_filename_id = _dpd.streamAPI->reg_xtra_data_cb(SMTP_GetFilename); config->xtra_mfrom_id = _dpd.streamAPI->reg_xtra_data_cb(SMTP_GetMailFrom); config->xtra_rcptto_id = _dpd.streamAPI->reg_xtra_data_cb(SMTP_GetRcptTo); config->xtra_ehdrs_id = _dpd.streamAPI->reg_xtra_data_cb(SMTP_GetEmailHdrs); } static int SMTPCheckConfig(struct _SnortConfig *sc) { sfPolicyUserDataIterate (sc, smtp_config, SMTPCheckPolicyConfig); sfPolicyUserDataIterate (sc, smtp_config, CheckFilePolicyConfig); { SMTPConfig *defaultConfig = (SMTPConfig *)sfPolicyUserDataGetDefault(smtp_config); if (defaultConfig == NULL) { _dpd.errMsg( "SMTP: Must configure a default configuration if you " "want to enable smtp decoding.\n"); return -1; } if (sfPolicyUserDataIterate(sc, smtp_config, SMTPEnableDecoding) != 0) { smtp_mime_mempool = (MemPool *) _dpd.fileAPI->init_mime_mempool(defaultConfig->max_mime_mem, defaultConfig->max_depth, smtp_mime_mempool, PROTOCOL_NAME); } if (sfPolicyUserDataIterate(sc, smtp_config, SMTPLogExtraData) != 0) { smtp_mempool = (MemPool *)_dpd.fileAPI->init_log_mempool(defaultConfig->log_config.email_hdrs_log_depth, defaultConfig->memcap, smtp_mempool, PROTOCOL_NAME); } } return 0; } static void SMTP_PrintStats(int exiting) { _dpd.logMsg("SMTP Preprocessor Statistics\n"); _dpd.logMsg(" Total sessions : "STDu64"\n", smtp_stats.sessions); _dpd.logMsg(" Max concurrent sessions : "STDu64"\n", smtp_stats.max_conc_sessions); if (smtp_stats.sessions > 0) { _dpd.logMsg(" Base64 attachments decoded : "STDu64"\n", smtp_stats.attachments[DECODE_B64]); _dpd.logMsg(" Total Base64 decoded bytes : "STDu64"\n", smtp_stats.decoded_bytes[DECODE_B64]); _dpd.logMsg(" Quoted-Printable attachments decoded : "STDu64"\n", smtp_stats.attachments[DECODE_QP]); _dpd.logMsg(" Total Quoted decoded bytes : "STDu64"\n", smtp_stats.decoded_bytes[DECODE_QP]); _dpd.logMsg(" UU attachments decoded : "STDu64"\n", smtp_stats.attachments[DECODE_UU]); _dpd.logMsg(" Total UU decoded bytes : "STDu64"\n", smtp_stats.decoded_bytes[DECODE_UU]); _dpd.logMsg(" Non-Encoded MIME attachments extracted : "STDu64"\n", smtp_stats.attachments[DECODE_BITENC]); _dpd.logMsg(" Total Non-Encoded MIME bytes extracted : "STDu64"\n", smtp_stats.decoded_bytes[DECODE_BITENC]); if ( smtp_stats.memcap_exceeded ) _dpd.logMsg(" Sessions not decoded due to memory unavailability : "STDu64"\n", smtp_stats.memcap_exceeded); } } #ifdef SNORT_RELOAD static void SMTPReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId smtp_swap_config = (tSfPolicyUserContextId)*new_config; SMTPToken *tmp; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); SMTPConfig *pPolicyConfig = NULL; if (smtp_swap_config == NULL) { //create a context smtp_swap_config = sfPolicyConfigCreate(); if (smtp_swap_config == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create SMTP " "configuration.\n"); } *new_config = (void *)smtp_swap_config; } sfPolicyUserPolicySet (smtp_swap_config, policy_id); pPolicyConfig = (SMTPConfig *)sfPolicyUserDataGetCurrent(smtp_swap_config); if (pPolicyConfig != NULL) DynamicPreprocessorFatalMessage("Can only configure SMTP preprocessor once.\n"); pPolicyConfig = (SMTPConfig *)calloc(1, sizeof(SMTPConfig)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create SMTP " "configuration.\n"); } sfPolicyUserDataSetCurrent(smtp_swap_config, pPolicyConfig); SMTP_RegXtraDataFuncs(pPolicyConfig); SMTP_InitCmds(pPolicyConfig); SMTP_ParseArgs(pPolicyConfig, args); SMTP_CheckConfig(pPolicyConfig, smtp_swap_config); SMTP_PrintConfig(pPolicyConfig); if( pPolicyConfig->disabled ) return; if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled " "for SMTP preprocessor\n"); } /* Command search - do this here because it's based on configuration */ pPolicyConfig->cmd_search_mpse = _dpd.searchAPI->search_instance_new(); if (pPolicyConfig->cmd_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate SMTP " "command search.\n"); } for (tmp = pPolicyConfig->cmds; tmp->name != NULL; tmp++) { pPolicyConfig->cmd_search[tmp->search_id].name = tmp->name; pPolicyConfig->cmd_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pPolicyConfig->cmd_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pPolicyConfig->cmd_search_mpse); _dpd.addPreproc(sc, SMTPDetect, PRIORITY_APPLICATION, PP_SMTP, PROTO_BIT__TCP); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } static int SMTPReloadVerify(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId smtp_swap_config = (tSfPolicyUserContextId)swap_config; SMTPConfig *config = NULL; SMTPConfig *configNext = NULL; if (smtp_swap_config == NULL) return 0; if (smtp_config != NULL) { config = (SMTPConfig *)sfPolicyUserDataGet(smtp_config, _dpd.getDefaultPolicy()); } configNext = (SMTPConfig *)sfPolicyUserDataGet(smtp_swap_config, _dpd.getDefaultPolicy()); if (config == NULL) { return 0; } sfPolicyUserDataIterate (sc, smtp_swap_config, CheckFilePolicyConfig); if (smtp_mime_mempool != NULL) { if (configNext == NULL) { _dpd.errMsg("SMTP reload: Changing the SMTP configuration requires a restart.\n"); return -1; } if (configNext->max_mime_mem != config->max_mime_mem) { _dpd.errMsg("SMTP reload: Changing the max_mime_mem requires a restart.\n"); return -1; } if(configNext->b64_depth != config->b64_depth) { _dpd.errMsg("SMTP reload: Changing the b64_decode_depth requires a restart.\n"); return -1; } if(configNext->qp_depth != config->qp_depth) { _dpd.errMsg("SMTP reload: Changing the qp_decode_depth requires a restart.\n"); return -1; } if(configNext->bitenc_depth != config->bitenc_depth) { _dpd.errMsg("SMTP reload: Changing the bitenc_decode_depth requires a restart.\n"); return -1; } if(configNext->uu_depth != config->uu_depth) { _dpd.errMsg("SMTP reload: Changing the uu_decode_depth requires a restart.\n"); return -1; } if(configNext->file_depth != config->file_depth) { _dpd.errMsg("SMTP reload: Changing the file_depth requires a restart.\n"); return -1; } } if (smtp_mempool != NULL) { if (configNext == NULL) { _dpd.errMsg("SMTP reload: Changing the memcap or email_hdrs_log_depth requires a restart.\n"); return -1; } if (configNext->memcap != config->memcap) { _dpd.errMsg("SMTP reload: Changing the memcap requires a restart.\n"); return -1; } if (configNext->log_config.email_hdrs_log_depth & 7) configNext->log_config.email_hdrs_log_depth += (8 - (configNext->log_config.email_hdrs_log_depth & 7)); if(configNext->log_config.email_hdrs_log_depth != config->log_config.email_hdrs_log_depth) { _dpd.errMsg("SMTP reload: Changing the email_hdrs_log_depth requires a restart.\n"); return -1; } } else if(configNext != NULL) { if (sfPolicyUserDataIterate(sc, smtp_swap_config, SMTPEnableDecoding) != 0) smtp_mime_mempool = (MemPool *)_dpd.fileAPI->init_mime_mempool(configNext->max_mime_mem, configNext->max_depth, smtp_mime_mempool, PROTOCOL_NAME); if (sfPolicyUserDataIterate(sc, smtp_swap_config, SMTPLogExtraData) != 0) smtp_mempool = (MemPool *)_dpd.fileAPI->init_log_mempool(configNext->log_config.email_hdrs_log_depth, configNext->memcap, smtp_mempool, PROTOCOL_NAME); if ( configNext->disabled ) return 0; } if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("Streaming & reassembly must be enabled " "for SMTP preprocessor\n"); return -2; } return 0; } static int SMTPReloadSwapPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SMTPConfig *pPolicyConfig = (SMTPConfig *)pData; if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); SMTP_FreeConfig(pPolicyConfig); } return 0; } static void * SMTPReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId smtp_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = smtp_config; if (smtp_swap_config == NULL) return NULL; smtp_config = smtp_swap_config; sfPolicyUserDataFreeIterate (old_config, SMTPReloadSwapPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) SMTP_FreeConfigs(old_config); return NULL; } static void SMTPReloadSwapFree(void *data) { if (data == NULL) return; SMTP_FreeConfigs((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/smtp/snort_smtp.h0000644000000000000000000002103312260565732020417 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * **************************************************************************/ /************************************************************************** * * snort_smtp.h * * Author: Andy Mullican * Author: Todd Wease * * Description: * * This file defines everything specific to the SMTP preprocessor. * **************************************************************************/ #ifndef __SMTP_H__ #define __SMTP_H__ /* Includes ***************************************************************/ #include #include "sf_snort_packet.h" #include "ssl.h" #include "smtp_config.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "mempool.h" #include "sf_email_attach_decode.h" #include "file_api.h" #ifdef DEBUG #include "sf_types.h" #endif /**************************************************************************/ /* Defines ****************************************************************/ /* Direction packet is coming from, if we can figure it out */ #define SMTP_PKT_FROM_UNKNOWN 0 #define SMTP_PKT_FROM_CLIENT 1 #define SMTP_PKT_FROM_SERVER 2 /* Inspection type */ #define SMTP_STATELESS 0 #define SMTP_STATEFUL 1 #define SEARCH_CMD 0 #define SEARCH_RESP 1 #define SEARCH_HDR 2 #define SEARCH_DATA_END 3 #define NUM_SEARCHES 4 #define BOUNDARY 0 #define MAX_BOUNDARY_LEN 70 /* Max length of boundary string, defined in RFC 2046 */ #define STATE_CONNECT 0 #define STATE_COMMAND 1 /* Command state of SMTP transaction */ #define STATE_DATA 2 /* Data state */ #define STATE_BDATA 3 /* Binary data state */ #define STATE_TLS_CLIENT_PEND 4 /* Got STARTTLS */ #define STATE_TLS_SERVER_PEND 5 /* Got STARTTLS */ #define STATE_TLS_DATA 6 /* Successful handshake, TLS encrypted data */ #define STATE_AUTH 7 #define STATE_XEXCH50 8 #define STATE_UNKNOWN 9 #define STATE_DATA_INIT 0 #define STATE_DATA_HEADER 1 /* Data header section of data state */ #define STATE_DATA_BODY 2 /* Data body section of data state */ #define STATE_MIME_HEADER 3 /* MIME header section within data section */ #define STATE_DATA_UNKNOWN 4 /* state flags */ #define SMTP_FLAG_GOT_MAIL_CMD 0x00000001 #define SMTP_FLAG_GOT_RCPT_CMD 0x00000002 #define SMTP_FLAG_FOLDING 0x00000004 #define SMTP_FLAG_IN_CONTENT_TYPE 0x00000008 #define SMTP_FLAG_GOT_BOUNDARY 0x00000010 #define SMTP_FLAG_DATA_HEADER_CONT 0x00000020 #define SMTP_FLAG_IN_CONT_TRANS_ENC 0x00000040 #define SMTP_FLAG_EMAIL_ATTACH 0x00000080 #define SMTP_FLAG_MULTIPLE_EMAIL_ATTACH 0x00000100 #define SMTP_FLAG_IN_CONT_DISP 0x00000200 #define SMTP_FLAG_IN_CONT_DISP_CONT 0x00000400 #define SMTP_FLAG_MIME_END 0x00000800 #define SMTP_FLAG_BDAT 0x00001000 #define SMTP_FLAG_ABORT 0x00002000 /* log flags */ #define SMTP_FLAG_MAIL_FROM_PRESENT 0x00000001 #define SMTP_FLAG_RCPT_TO_PRESENT 0x00000002 #define SMTP_FLAG_FILENAME_PRESENT 0x00000004 #define SMTP_FLAG_EMAIL_HDRS_PRESENT 0x00000008 /* session flags */ #define SMTP_FLAG_XLINK2STATE_GOTFIRSTCHUNK 0x00000001 #define SMTP_FLAG_XLINK2STATE_ALERTED 0x00000002 #define SMTP_FLAG_NEXT_STATE_UNKNOWN 0x00000004 #define SMTP_FLAG_GOT_NON_REBUILT 0x00000008 #define SMTP_FLAG_CHECK_SSL 0x00000010 #define SMTP_SSL_ERROR_FLAGS (SSL_BOGUS_HS_DIR_FLAG | \ SSL_BAD_VER_FLAG | \ SSL_BAD_TYPE_FLAG | \ SSL_UNKNOWN_FLAG) /* Maximum length of header chars before colon, based on Exim 4.32 exploit */ #define MAX_HEADER_NAME_LEN 64 #define SMTP_PROTO_REF_STR "smtp" #define MAX_AUTH_NAME_LEN 20 /* Max length of SASL mechanisms, defined in RFC 4422 */ /**************************************************************************/ /* Data structures ********************************************************/ typedef enum _SMTPCmdEnum { CMD_ATRN = 0, CMD_AUTH, CMD_BDAT, CMD_DATA, CMD_DEBUG, CMD_EHLO, CMD_EMAL, CMD_ESAM, CMD_ESND, CMD_ESOM, CMD_ETRN, CMD_EVFY, CMD_EXPN, CMD_HELO, CMD_HELP, CMD_IDENT, CMD_MAIL, CMD_NOOP, CMD_ONEX, CMD_QUEU, CMD_QUIT, CMD_RCPT, CMD_RSET, CMD_SAML, CMD_SEND, CMD_SIZE, CMD_STARTTLS, CMD_SOML, CMD_TICK, CMD_TIME, CMD_TURN, CMD_TURNME, CMD_VERB, CMD_VRFY, CMD_X_EXPS, CMD_XADR, CMD_XAUTH, CMD_XCIR, CMD_XEXCH50, CMD_XGEN, CMD_XLICENSE, CMD_X_LINK2STATE, CMD_XQUE, CMD_XSTA, CMD_XTRN, CMD_XUSR, CMD_ABORT, CMD_LAST } SMTPCmdEnum; typedef enum _SMTPRespEnum { RESP_220 = 0, RESP_221, RESP_235, RESP_250, RESP_334, RESP_354, RESP_421, RESP_450, RESP_451, RESP_452, RESP_500, RESP_501, RESP_502, RESP_503, RESP_504, RESP_535, RESP_550, RESP_551, RESP_552, RESP_553, RESP_554, RESP_LAST } SMTPRespEnum; typedef enum _SMTPHdrEnum { HDR_CONTENT_TYPE = 0, HDR_CONT_TRANS_ENC, HDR_CONT_DISP, HDR_LAST } SMTPHdrEnum; typedef enum _SMTPDataEndEnum { DATA_END_1 = 0, DATA_END_2, DATA_END_3, DATA_END_4, DATA_END_LAST } SMTPDataEndEnum; typedef struct _SMTPSearchInfo { int id; int index; int length; } SMTPSearchInfo; typedef struct _SMTPMimeBoundary { int state; char boundary[2 + MAX_BOUNDARY_LEN + 1]; /* '--' + MIME boundary string + '\0' */ int boundary_len; void *boundary_search; } SMTPMimeBoundary; typedef struct _SMTPPcre { pcre *re; pcre_extra *pe; } SMTPPcre; typedef struct _SMTPAuthName { int length; char name[MAX_AUTH_NAME_LEN]; } SMTPAuthName; typedef struct _SMTP { int state; int data_state; int state_flags; int log_flags; int session_flags; int alert_mask; int reassembling; uint32_t dat_chunk; #ifdef DEBUG_MSGS uint64_t session_number; #endif /* may want to keep track where packet didn't end with end of line marker int cur_client_line_len; int cur_server_line_len; */ MemBucket *decode_bkt; SMTPMimeBoundary mime_boundary; Email_DecodeState *decode_state; MAIL_LogState *log_state; SMTPAuthName *auth_name; /* In future if we look at forwarded mail (message/rfc822) we may * need to keep track of additional mime boundaries * SMTPMimeBoundary mime_boundary[8]; * int current_mime_boundary; */ tSfPolicyId policy_id; tSfPolicyUserContextId config; } SMTP; /**************************************************************************/ /* Function prototypes ****************************************************/ void SMTP_InitCmds(SMTPConfig *config); void SMTP_SearchInit(void); void SMTP_Free(void); void SnortSMTP(SFSnortPacket *); int SMTP_IsServer(uint16_t); void SMTP_FreeConfig(SMTPConfig *); void SMTP_FreeConfigs(tSfPolicyUserContextId); int SMTP_GetFilename(void *data, uint8_t **buf, uint32_t *len, uint32_t *type); int SMTP_GetMailFrom(void *data, uint8_t **buf, uint32_t *len, uint32_t *type); int SMTP_GetRcptTo(void *data, uint8_t **buf, uint32_t *len, uint32_t *type); int SMTP_GetEmailHdrs(void *data, uint8_t **buf, uint32_t *len, uint32_t *type); void SMTP_MempoolInit(uint32_t, uint32_t); /**************************************************************************/ #endif /* __SMTP_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/smtp/snort_smtp.c0000644000000000000000000025563712260565732020435 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * snort_smtp.c * * Author: Andy Mullican * Author: Todd Wease * * Description: * * This file handles SMTP protocol checking and normalization. * * Entry point functions: * * SnortSMTP() * SMTP_Init() * SMTP_Free() * **************************************************************************/ /* Includes ***************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "sf_types.h" #include "snort_smtp.h" #include "smtp_config.h" #include "smtp_normalize.h" #include "smtp_util.h" #include "smtp_log.h" #include "smtp_xlink2state.h" #include "sf_snort_packet.h" #include "stream_api.h" #include "snort_debug.h" #include "profiler.h" #include "snort_bounds.h" #include "sf_dynamic_preprocessor.h" #include "ssl.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "Unified2_common.h" #include "file_api.h" #ifdef DEBUG_MSGS #include "sf_types.h" #endif /**************************************************************************/ /* Externs ****************************************************************/ #ifdef PERF_PROFILING extern PreprocStats smtpDetectPerfStats; extern int smtpDetectCalled; #endif extern tSfPolicyUserContextId smtp_config; extern SMTPConfig *smtp_eval_config; extern MemPool *smtp_mime_mempool; extern MemPool *smtp_mempool; #ifdef DEBUG_MSGS extern char smtp_print_buffer[]; #endif /**************************************************************************/ /* Globals ****************************************************************/ const SMTPToken smtp_known_cmds[] = { {"ATRN", 4, CMD_ATRN, SMTP_CMD_TYPE_NORMAL}, {"AUTH", 4, CMD_AUTH, SMTP_CMD_TYPE_AUTH}, {"BDAT", 4, CMD_BDAT, SMTP_CMD_TYPE_BDATA}, {"DATA", 4, CMD_DATA, SMTP_CMD_TYPE_DATA}, {"DEBUG", 5, CMD_DEBUG, SMTP_CMD_TYPE_NORMAL}, {"EHLO", 4, CMD_EHLO, SMTP_CMD_TYPE_NORMAL}, {"EMAL", 4, CMD_EMAL, SMTP_CMD_TYPE_NORMAL}, {"ESAM", 4, CMD_ESAM, SMTP_CMD_TYPE_NORMAL}, {"ESND", 4, CMD_ESND, SMTP_CMD_TYPE_NORMAL}, {"ESOM", 4, CMD_ESOM, SMTP_CMD_TYPE_NORMAL}, {"ETRN", 4, CMD_ETRN, SMTP_CMD_TYPE_NORMAL}, {"EVFY", 4, CMD_EVFY, SMTP_CMD_TYPE_NORMAL}, {"EXPN", 4, CMD_EXPN, SMTP_CMD_TYPE_NORMAL}, {"HELO", 4, CMD_HELO, SMTP_CMD_TYPE_NORMAL}, {"HELP", 4, CMD_HELP, SMTP_CMD_TYPE_NORMAL}, {"IDENT", 5, CMD_IDENT, SMTP_CMD_TYPE_NORMAL}, {"MAIL", 4, CMD_MAIL, SMTP_CMD_TYPE_NORMAL}, {"NOOP", 4, CMD_NOOP, SMTP_CMD_TYPE_NORMAL}, {"ONEX", 4, CMD_ONEX, SMTP_CMD_TYPE_NORMAL}, {"QUEU", 4, CMD_QUEU, SMTP_CMD_TYPE_NORMAL}, {"QUIT", 4, CMD_QUIT, SMTP_CMD_TYPE_NORMAL}, {"RCPT", 4, CMD_RCPT, SMTP_CMD_TYPE_NORMAL}, {"RSET", 4, CMD_RSET, SMTP_CMD_TYPE_NORMAL}, {"SAML", 4, CMD_SAML, SMTP_CMD_TYPE_NORMAL}, {"SEND", 4, CMD_SEND, SMTP_CMD_TYPE_NORMAL}, {"SIZE", 4, CMD_SIZE, SMTP_CMD_TYPE_NORMAL}, {"STARTTLS", 8, CMD_STARTTLS, SMTP_CMD_TYPE_NORMAL}, {"SOML", 4, CMD_SOML, SMTP_CMD_TYPE_NORMAL}, {"TICK", 4, CMD_TICK, SMTP_CMD_TYPE_NORMAL}, {"TIME", 4, CMD_TIME, SMTP_CMD_TYPE_NORMAL}, {"TURN", 4, CMD_TURN, SMTP_CMD_TYPE_NORMAL}, {"TURNME", 6, CMD_TURNME, SMTP_CMD_TYPE_NORMAL}, {"VERB", 4, CMD_VERB, SMTP_CMD_TYPE_NORMAL}, {"VRFY", 4, CMD_VRFY, SMTP_CMD_TYPE_NORMAL}, {"X-EXPS", 6, CMD_X_EXPS, SMTP_CMD_TYPE_AUTH}, {"XADR", 4, CMD_XADR, SMTP_CMD_TYPE_NORMAL}, {"XAUTH", 5, CMD_XAUTH, SMTP_CMD_TYPE_AUTH}, {"XCIR", 4, CMD_XCIR, SMTP_CMD_TYPE_NORMAL}, {"XEXCH50", 7, CMD_XEXCH50, SMTP_CMD_TYPE_BDATA}, {"XGEN", 4, CMD_XGEN, SMTP_CMD_TYPE_NORMAL}, {"XLICENSE", 8, CMD_XLICENSE, SMTP_CMD_TYPE_NORMAL}, {"X-LINK2STATE", 12, CMD_X_LINK2STATE, SMTP_CMD_TYPE_NORMAL}, {"XQUE", 4, CMD_XQUE, SMTP_CMD_TYPE_NORMAL}, {"XSTA", 4, CMD_XSTA, SMTP_CMD_TYPE_NORMAL}, {"XTRN", 4, CMD_XTRN, SMTP_CMD_TYPE_NORMAL}, {"XUSR", 4, CMD_XUSR, SMTP_CMD_TYPE_NORMAL}, {"*", 1, CMD_ABORT, SMTP_CMD_TYPE_NORMAL}, {NULL, 0, 0, SMTP_CMD_TYPE_NORMAL} }; const SMTPToken smtp_resps[] = { {"220", 3, RESP_220, SMTP_CMD_TYPE_NORMAL}, /* Service ready - initial response and STARTTLS response */ {"221", 3, RESP_221, SMTP_CMD_TYPE_NORMAL}, /* Goodbye - response to QUIT */ {"235", 3, RESP_235, SMTP_CMD_TYPE_NORMAL}, /* Auth done response */ {"250", 3, RESP_250, SMTP_CMD_TYPE_NORMAL}, /* Requested mail action okay, completed */ {"334", 3, RESP_334, SMTP_CMD_TYPE_NORMAL}, /* Auth intermediate response */ {"354", 3, RESP_354, SMTP_CMD_TYPE_NORMAL}, /* Start mail input - data response */ {"421", 3, RESP_421, SMTP_CMD_TYPE_NORMAL}, /* Service not availiable - closes connection */ {"450", 3, RESP_450, SMTP_CMD_TYPE_NORMAL}, /* Mailbox unavailable */ {"451", 3, RESP_451, SMTP_CMD_TYPE_NORMAL}, /* Local error in processing */ {"452", 3, RESP_452, SMTP_CMD_TYPE_NORMAL}, /* Insufficient system storage */ {"500", 3, RESP_500, SMTP_CMD_TYPE_NORMAL}, /* Command unrecognized */ {"501", 3, RESP_501, SMTP_CMD_TYPE_NORMAL}, /* Syntax error in parameters or arguments */ {"502", 3, RESP_502, SMTP_CMD_TYPE_NORMAL}, /* Command not implemented */ {"503", 3, RESP_503, SMTP_CMD_TYPE_NORMAL}, /* Bad sequence of commands */ {"504", 3, RESP_504, SMTP_CMD_TYPE_NORMAL}, /* Command parameter not implemented */ {"535", 3, RESP_535, SMTP_CMD_TYPE_NORMAL}, /* Authentication failed */ {"550", 3, RESP_550, SMTP_CMD_TYPE_NORMAL}, /* Action not taken - mailbox unavailable */ {"551", 3, RESP_551, SMTP_CMD_TYPE_NORMAL}, /* User not local; please try */ {"552", 3, RESP_552, SMTP_CMD_TYPE_NORMAL}, /* Mail action aborted: exceeded storage allocation */ {"553", 3, RESP_553, SMTP_CMD_TYPE_NORMAL}, /* Action not taken: mailbox name not allowed */ {"554", 3, RESP_554, SMTP_CMD_TYPE_NORMAL}, /* Transaction failed */ {NULL, 0, 0, SMTP_CMD_TYPE_NORMAL} }; const SMTPToken smtp_hdrs[] = { {"Content-type:", 13, HDR_CONTENT_TYPE, SMTP_CMD_TYPE_NORMAL}, {"Content-Transfer-Encoding:", 26, HDR_CONT_TRANS_ENC, SMTP_CMD_TYPE_NORMAL}, {"Content-Disposition:", 20, HDR_CONT_DISP, SMTP_CMD_TYPE_NORMAL}, {NULL, 0, 0, SMTP_CMD_TYPE_NORMAL} }; const SMTPToken smtp_data_end[] = { {"\r\n.\r\n", 5, DATA_END_1, SMTP_CMD_TYPE_NORMAL}, {"\n.\r\n", 4, DATA_END_2, SMTP_CMD_TYPE_NORMAL}, {"\r\n.\n", 4, DATA_END_3, SMTP_CMD_TYPE_NORMAL}, {"\n.\n", 3, DATA_END_4, SMTP_CMD_TYPE_NORMAL}, {NULL, 0, 0, SMTP_CMD_TYPE_NORMAL} }; typedef struct _SMTPAuth { char *name; int name_len; } SMTPAuth; /* Cyrus SASL authentication mechanisms ANONYMOUS, PLAIN and LOGIN * does not have context */ const SMTPAuth smtp_auth_no_ctx[] = { { "ANONYMOUS", 9 }, { "PLAIN", 5 }, { "LOGIN", 5 }, {NULL, 0} }; SMTP *smtp_ssn = NULL; SMTP smtp_no_session; SMTPPcre mime_boundary_pcre; char smtp_normalizing; SMTPSearchInfo smtp_search_info; #ifdef DEBUG_MSGS uint64_t smtp_session_counter = 0; #endif #ifdef TARGET_BASED int16_t smtp_proto_id; #endif void *smtp_resp_search_mpse = NULL; SMTPSearch smtp_resp_search[RESP_LAST]; void *smtp_hdr_search_mpse = NULL; SMTPSearch smtp_hdr_search[HDR_LAST]; void *smtp_data_search_mpse = NULL; SMTPSearch smtp_data_end_search[DATA_END_LAST]; SMTPSearch *smtp_current_search = NULL; /**************************************************************************/ /* Private functions ******************************************************/ static int SMTP_Setup(SFSnortPacket *p, SMTP *ssn); static void SMTP_ResetState(void); static void SMTP_SessionFree(void *); static void SMTP_NoSessionFree(void); static int SMTP_GetPacketDirection(SFSnortPacket *, int); static void SMTP_ProcessClientPacket(SFSnortPacket *); static int SMTP_ProcessServerPacket(SFSnortPacket *, int *); static void SMTP_DisableDetect(SFSnortPacket *); static const uint8_t * SMTP_HandleCommand(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * SMTP_HandleData(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * SMTP_HandleHeader(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * SMTP_HandleDataBody(SFSnortPacket *, const uint8_t *, const uint8_t *); static int SMTP_SearchStrFound(void *, void *, int, void *, void *); static int SMTP_BoundaryStrFound(void *, void *, int , void *, void *); static int SMTP_GetBoundary(const char *, int); static int SMTP_IsTlsClientHello(const uint8_t *, const uint8_t *); static int SMTP_IsTlsServerHello(const uint8_t *, const uint8_t *); static int SMTP_IsSSL(const uint8_t *, int, int); static int SMTP_Inspect(SFSnortPacket *); /**************************************************************************/ static inline void SetSmtpBuffers(SMTP *ssn) { if ((ssn != NULL) && (ssn->decode_state == NULL)) { MemBucket *bkt = mempool_alloc(smtp_mime_mempool); if (bkt != NULL) { ssn->decode_state = (Email_DecodeState *)calloc(1, sizeof(Email_DecodeState)); if( ssn->decode_state != NULL ) { ssn->decode_bkt = bkt; SetEmailDecodeState(ssn->decode_state, bkt->data, smtp_eval_config->max_depth, smtp_eval_config->b64_depth, smtp_eval_config->qp_depth, smtp_eval_config->uu_depth, smtp_eval_config->bitenc_depth, smtp_eval_config->file_depth); } else { /*free mempool if calloc fails*/ mempool_free(smtp_mime_mempool, bkt); } } else { smtp_stats.memcap_exceeded++; } } } static inline void SMTP_UpdateDecodeStats(Email_DecodeState *ds) { smtp_stats.decoded_bytes[ds->decode_type] += ds->decoded_bytes; } void SMTP_InitCmds(SMTPConfig *config) { const SMTPToken *tmp; if (config == NULL) return; /* add one to CMD_LAST for NULL entry */ config->cmds = (SMTPToken *)calloc(CMD_LAST + 1, sizeof(SMTPToken)); if (config->cmds == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for smtp " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } for (tmp = &smtp_known_cmds[0]; tmp->name != NULL; tmp++) { config->cmds[tmp->search_id].name_len = tmp->name_len; config->cmds[tmp->search_id].search_id = tmp->search_id; config->cmds[tmp->search_id].name = strdup(tmp->name); config->cmds[tmp->search_id].type = tmp->type; if (config->cmds[tmp->search_id].name == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for smtp " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } } /* initialize memory for command searches */ config->cmd_search = (SMTPSearch *)calloc(CMD_LAST, sizeof(SMTPSearch)); if (config->cmd_search == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for smtp " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } config->num_cmds = CMD_LAST; } /* * Initialize SMTP searches * * @param none * * @return none */ void SMTP_SearchInit(void) { const char *error; int erroffset; const SMTPToken *tmp; /* Response search */ smtp_resp_search_mpse = _dpd.searchAPI->search_instance_new(); if (smtp_resp_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate SMTP " "response search.\n"); } for (tmp = &smtp_resps[0]; tmp->name != NULL; tmp++) { smtp_resp_search[tmp->search_id].name = tmp->name; smtp_resp_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(smtp_resp_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(smtp_resp_search_mpse); /* Header search */ smtp_hdr_search_mpse = _dpd.searchAPI->search_instance_new(); if (smtp_hdr_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate SMTP " "header search.\n"); } for (tmp = &smtp_hdrs[0]; tmp->name != NULL; tmp++) { smtp_hdr_search[tmp->search_id].name = tmp->name; smtp_hdr_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(smtp_hdr_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(smtp_hdr_search_mpse); /* Data end search */ smtp_data_search_mpse = _dpd.searchAPI->search_instance_new(); if (smtp_data_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate SMTP " "data search.\n"); } for (tmp = &smtp_data_end[0]; tmp->name != NULL; tmp++) { smtp_data_end_search[tmp->search_id].name = tmp->name; smtp_data_end_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(smtp_data_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(smtp_data_search_mpse); /* create regex for finding boundary string - since it can be cut across multiple * lines, a straight search won't do. Shouldn't be too slow since it will most * likely only be acting on a small portion of data */ //"^content-type:\\s*multipart.*boundary\\s*=\\s*\"?([^\\s]+)\"?" //"^\\s*multipart.*boundary\\s*=\\s*\"?([^\\s]+)\"?" //mime_boundary_pcre.re = pcre_compile("^.*boundary\\s*=\\s*\"?([^\\s\"]+)\"?", //mime_boundary_pcre.re = pcre_compile("boundary(?:\n|\r\n)?=(?:\n|\r\n)?\"?([^\\s\"]+)\"?", mime_boundary_pcre.re = pcre_compile("boundary\\s*=\\s*\"?([^\\s\"]+)\"?", PCRE_CASELESS | PCRE_DOTALL, &error, &erroffset, NULL); if (mime_boundary_pcre.re == NULL) { DynamicPreprocessorFatalMessage("Failed to compile pcre regex for getting boundary " "in a multipart SMTP message: %s\n", error); } mime_boundary_pcre.pe = pcre_study(mime_boundary_pcre.re, 0, &error); if (error != NULL) { DynamicPreprocessorFatalMessage("Failed to study pcre regex for getting boundary " "in a multipart SMTP message: %s\n", error); } } /* * Initialize run-time boundary search */ static int SMTP_BoundarySearchInit(void) { if (smtp_ssn->mime_boundary.boundary_search != NULL) _dpd.searchAPI->search_instance_free(smtp_ssn->mime_boundary.boundary_search); smtp_ssn->mime_boundary.boundary_search = _dpd.searchAPI->search_instance_new(); if (smtp_ssn->mime_boundary.boundary_search == NULL) return -1; _dpd.searchAPI->search_instance_add(smtp_ssn->mime_boundary.boundary_search, smtp_ssn->mime_boundary.boundary, smtp_ssn->mime_boundary.boundary_len, BOUNDARY); _dpd.searchAPI->search_instance_prep(smtp_ssn->mime_boundary.boundary_search); return 0; } /* * Reset SMTP session state * * @param none * * @return none */ static void SMTP_ResetState(void) { if (smtp_ssn->mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(smtp_ssn->mime_boundary.boundary_search); smtp_ssn->mime_boundary.boundary_search = NULL; } smtp_ssn->state = STATE_COMMAND; smtp_ssn->data_state = STATE_DATA_INIT; smtp_ssn->state_flags = 0; ClearEmailDecodeState(smtp_ssn->decode_state); memset(&smtp_ssn->mime_boundary, 0, sizeof(SMTPMimeBoundary)); } /* * Given a server configuration and a port number, we decide if the port is * in the SMTP server port list. * * @param port the port number to compare with the configuration * * @return integer * @retval 0 means that the port is not a server port * @retval !0 means that the port is a server port */ int SMTP_IsServer(uint16_t port) { if (smtp_eval_config->ports[port / 8] & (1 << (port % 8))) return 1; return 0; } static SMTP * SMTP_GetNewSession(SFSnortPacket *p, tSfPolicyId policy_id) { SMTP *ssn; SMTPConfig *pPolicyConfig = NULL; pPolicyConfig = (SMTPConfig *)sfPolicyUserDataGetCurrent(smtp_config); if ((p->stream_session_ptr == NULL) || (pPolicyConfig->inspection_type == SMTP_STATELESS)) { #ifdef DEBUG_MSGS if (p->stream_session_ptr == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Stream session pointer is NULL - " "treating packet as stateless\n");); } #endif SMTP_NoSessionFree(); memset(&smtp_no_session, 0, sizeof(SMTP)); ssn = &smtp_no_session; ssn->session_flags |= SMTP_FLAG_CHECK_SSL; return ssn; } DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Creating new session data structure\n");); ssn = (SMTP *)calloc(1, sizeof(SMTP)); if (ssn == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate SMTP session data\n"); } smtp_ssn = ssn; if (_dpd.fileAPI->set_log_buffers(&(smtp_ssn->log_state), &(pPolicyConfig->log_config),smtp_mempool) < 0) { free(ssn); return NULL; } _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_SMTP, ssn, &SMTP_SessionFree); if (p->flags & SSNFLAG_MIDSTREAM) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Got midstream packet - " "setting state to unknown\n");); ssn->state = STATE_UNKNOWN; } #ifdef DEBUG_MSGS smtp_session_counter++; ssn->session_number = smtp_session_counter; #endif if (p->stream_session_ptr != NULL) { /* check to see if we're doing client reassembly in stream */ if (_dpd.streamAPI->get_reassembly_direction(p->stream_session_ptr) & SSN_DIR_FROM_CLIENT) ssn->reassembling = 1; } ssn->policy_id = policy_id; ssn->config = smtp_config; pPolicyConfig->ref_count++; smtp_stats.sessions++; smtp_stats.conc_sessions++; if(smtp_stats.max_conc_sessions < smtp_stats.conc_sessions) smtp_stats.max_conc_sessions = smtp_stats.conc_sessions; return ssn; } /* * Do first-packet setup * * @param p standard Packet structure * * @return none */ static int SMTP_Setup(SFSnortPacket *p, SMTP *ssn) { int flags = 0; int pkt_dir; if (p->stream_session_ptr != NULL) { /* set flags to session flags */ flags = _dpd.streamAPI->get_session_flags(p->stream_session_ptr); } /* Figure out direction of packet */ pkt_dir = SMTP_GetPacketDirection(p, flags); DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Session number: "STDu64"\n", ssn->session_number);); /* reset check ssl flag for new packet */ if (!(ssn->session_flags & SMTP_FLAG_CHECK_SSL)) ssn->session_flags |= SMTP_FLAG_CHECK_SSL; /* Check to see if there is a reassembly gap. If so, we won't know * what state we're in when we get the _next_ reassembled packet */ if ((pkt_dir != SMTP_PKT_FROM_SERVER) && (p->flags & FLAG_REBUILT_STREAM)) { int missing_in_rebuilt = _dpd.streamAPI->missing_in_reassembled(p->stream_session_ptr, SSN_DIR_FROM_CLIENT); if (ssn->session_flags & SMTP_FLAG_NEXT_STATE_UNKNOWN) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Found gap in previous reassembly buffer - " "set state to unknown\n");); ssn->state = STATE_UNKNOWN; ssn->session_flags &= ~SMTP_FLAG_NEXT_STATE_UNKNOWN; } if (missing_in_rebuilt == SSN_MISSING_BEFORE) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Found missing packets before " "in reassembly buffer - set state to unknown\n");); ssn->state = STATE_UNKNOWN; } } return pkt_dir; } /* * Determine packet direction * * @param p standard Packet structure * * @return none */ static int SMTP_GetPacketDirection(SFSnortPacket *p, int flags) { int pkt_direction = SMTP_PKT_FROM_UNKNOWN; if (flags & SSNFLAG_MIDSTREAM) { if (SMTP_IsServer(p->src_port) && !SMTP_IsServer(p->dst_port)) { pkt_direction = SMTP_PKT_FROM_SERVER; } else if (!SMTP_IsServer(p->src_port) && SMTP_IsServer(p->dst_port)) { pkt_direction = SMTP_PKT_FROM_CLIENT; } } else { if (p->flags & FLAG_FROM_SERVER) { pkt_direction = SMTP_PKT_FROM_SERVER; } else if (p->flags & FLAG_FROM_CLIENT) { pkt_direction = SMTP_PKT_FROM_CLIENT; } /* if direction is still unknown ... */ if (pkt_direction == SMTP_PKT_FROM_UNKNOWN) { if (SMTP_IsServer(p->src_port) && !SMTP_IsServer(p->dst_port)) { pkt_direction = SMTP_PKT_FROM_SERVER; } else if (!SMTP_IsServer(p->src_port) && SMTP_IsServer(p->dst_port)) { pkt_direction = SMTP_PKT_FROM_CLIENT; } } } return pkt_direction; } /* * Free SMTP-specific related to this session * * @param v pointer to SMTP session structure * * * @return none */ static void SMTP_SessionFree(void *session_data) { SMTP *smtp = (SMTP *)session_data; #ifdef SNORT_RELOAD SMTPConfig *pPolicyConfig = NULL; #endif if (smtp == NULL) return; #ifdef SNORT_RELOAD pPolicyConfig = (SMTPConfig *)sfPolicyUserDataGet(smtp->config, smtp->policy_id); if (pPolicyConfig != NULL) { pPolicyConfig->ref_count--; if ((pPolicyConfig->ref_count == 0) && (smtp->config != smtp_config)) { sfPolicyUserDataClear (smtp->config, smtp->policy_id); SMTP_FreeConfig(pPolicyConfig); /* No more outstanding policies for this config */ if (sfPolicyUserPolicyGetActive(smtp->config) == 0) SMTP_FreeConfigs(smtp->config); } } #endif if (smtp->mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(smtp->mime_boundary.boundary_search); smtp->mime_boundary.boundary_search = NULL; } if(smtp->decode_state != NULL) { mempool_free(smtp_mime_mempool, smtp->decode_bkt); free(smtp->decode_state); } if(smtp->log_state != NULL) { mempool_free(smtp_mempool, smtp->log_state->log_hdrs_bkt); free(smtp->log_state); } if(smtp->auth_name != NULL) { free(smtp->auth_name); } free(smtp); if(smtp_stats.conc_sessions) smtp_stats.conc_sessions--; } static void SMTP_NoSessionFree(void) { if (smtp_no_session.mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(smtp_no_session.mime_boundary.boundary_search); smtp_no_session.mime_boundary.boundary_search = NULL; } } static int SMTP_FreeConfigsPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { SMTPConfig *pPolicyConfig = (SMTPConfig *)pData; //do any housekeeping before freeing SMTPConfig sfPolicyUserDataClear (config, policyId); SMTP_FreeConfig(pPolicyConfig); return 0; } void SMTP_FreeConfigs(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, SMTP_FreeConfigsPolicy); sfPolicyConfigDelete(config); } void SMTP_FreeConfig(SMTPConfig *config) { if (config == NULL) return; if (config->cmds != NULL) { SMTPToken *tmp = config->cmds; for (; tmp->name != NULL; tmp++) free(tmp->name); free(config->cmds); } if (config->cmd_config != NULL) free(config->cmd_config); if (config->cmd_search_mpse != NULL) _dpd.searchAPI->search_instance_free(config->cmd_search_mpse); if (config->cmd_search != NULL) free(config->cmd_search); free(config); } /* * Free anything that needs it before shutting down preprocessor * * @param none * * @return none */ void SMTP_Free(void) { SMTP_NoSessionFree(); SMTP_FreeConfigs(smtp_config); smtp_config = NULL; if (smtp_resp_search_mpse != NULL) _dpd.searchAPI->search_instance_free(smtp_resp_search_mpse); if (smtp_hdr_search_mpse != NULL) _dpd.searchAPI->search_instance_free(smtp_hdr_search_mpse); if (smtp_data_search_mpse != NULL) _dpd.searchAPI->search_instance_free(smtp_data_search_mpse); if (mime_boundary_pcre.re ) pcre_free(mime_boundary_pcre.re); if (mime_boundary_pcre.pe ) pcre_free(mime_boundary_pcre.pe); } /* * Callback function for string search * * @param id id in array of search strings from smtp_config.cmds * @param index index in array of search strings from smtp_config.cmds * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */ static int SMTP_SearchStrFound(void *id, void *unused, int index, void *data, void *unused2) { int search_id = (int)(uintptr_t)id; smtp_search_info.id = search_id; smtp_search_info.index = index; smtp_search_info.length = smtp_current_search[search_id].name_len; /* Returning non-zero stops search, which is okay since we only look for one at a time */ return 1; } /* * Callback function for boundary search * * @param id id in array of search strings * @param index index in array of search strings * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */ static int SMTP_BoundaryStrFound(void *id, void *unused, int index, void *data, void *unused2) { int boundary_id = (int)(uintptr_t)id; smtp_search_info.id = boundary_id; smtp_search_info.index = index; smtp_search_info.length = smtp_ssn->mime_boundary.boundary_len; return 1; } static int SMTP_GetBoundary(const char *data, int data_len) { int result; int ovector[9]; int ovecsize = 9; const char *boundary; int boundary_len; int ret; char *mime_boundary; int *mime_boundary_len; int *mime_boundary_state; mime_boundary = &smtp_ssn->mime_boundary.boundary[0]; mime_boundary_len = &smtp_ssn->mime_boundary.boundary_len; mime_boundary_state = &smtp_ssn->mime_boundary.state; /* result will be the number of matches (including submatches) */ result = pcre_exec(mime_boundary_pcre.re, mime_boundary_pcre.pe, data, data_len, 0, 0, ovector, ovecsize); if (result < 0) return -1; result = pcre_get_substring(data, ovector, result, 1, &boundary); if (result < 0) return -1; boundary_len = strlen(boundary); if (boundary_len > MAX_BOUNDARY_LEN) { /* XXX should we alert? breaking the law of RFC */ boundary_len = MAX_BOUNDARY_LEN; } mime_boundary[0] = '-'; mime_boundary[1] = '-'; ret = SafeMemcpy(mime_boundary + 2, boundary, boundary_len, mime_boundary + 2, mime_boundary + 2 + MAX_BOUNDARY_LEN); pcre_free_substring(boundary); if (ret != SAFEMEM_SUCCESS) { return -1; } *mime_boundary_len = 2 + boundary_len; *mime_boundary_state = 0; mime_boundary[*mime_boundary_len] = '\0'; return 0; } static bool SMTP_IsAuthCtxIgnored(const uint8_t *start, int length) { const SMTPAuth *tmp; for (tmp = &smtp_auth_no_ctx[0]; tmp->name != NULL; tmp++) { if ((tmp->name_len == length) && (!memcmp(start, tmp->name, length))) return true; } return false; } static bool SMTP_IsAuthChanged(const uint8_t *start_ptr, const uint8_t *end_ptr) { int length; bool auth_changed = false; uint8_t *start = (uint8_t *)start_ptr; uint8_t *end = (uint8_t *) end_ptr; while ((start < end) && isspace(*start)) start++; while ((start < end) && isspace(*(end-1))) end--; if (start >= end) return auth_changed; length = end - start; if (length > MAX_AUTH_NAME_LEN) return auth_changed; if (SMTP_IsAuthCtxIgnored(start, length)) return auth_changed; /* if authentication mechanism is set, compare it with current one*/ if (smtp_ssn->auth_name) { if (smtp_ssn->auth_name->length != length) auth_changed = true; else if (memcmp(start, smtp_ssn->auth_name->name, length)) auth_changed = true; } else smtp_ssn->auth_name = calloc(1, sizeof(*(smtp_ssn->auth_name))); /* save the current authentication mechanism*/ if (!smtp_ssn->auth_name) return auth_changed; if (auth_changed || (!smtp_ssn->auth_name->length)) { memcpy(smtp_ssn->auth_name->name, start, length); smtp_ssn->auth_name->length = length; } return auth_changed; } /* * Handle COMMAND state * * @param p standard Packet structure * @param ptr pointer into p->payload buffer to start looking at data * @param end points to end of p->payload buffer * * @return pointer into p->payload where we stopped looking at data * will be end of line or end of packet */ static const uint8_t * SMTP_HandleCommand(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *end) { const uint8_t *eol; /* end of line */ const uint8_t *eolm; /* end of line marker */ int cmd_line_len; int ret; int cmd_found; char alert_long_command_line = 0; /* get end of line and end of line marker */ SMTP_GetEOL(ptr, end, &eol, &eolm); /* calculate length of command line */ cmd_line_len = eol - ptr; /* check for command line exceeding maximum * do this before checking for a command since this could overflow * some server's buffers without the presence of a known command */ if ((smtp_eval_config->max_command_line_len != 0) && (cmd_line_len > smtp_eval_config->max_command_line_len)) { alert_long_command_line = 1; } /* TODO If the end of line marker coincides with the end of payload we can't be * sure that we got a command and not a substring which we could tell through * inspection of the next packet. Maybe a command pending state where the first * char in the next packet is checked for a space and end of line marker */ /* do not confine since there could be space chars before command */ smtp_current_search = &smtp_eval_config->cmd_search[0]; cmd_found = _dpd.searchAPI->search_instance_find (smtp_eval_config->cmd_search_mpse, (const char *)ptr, eolm - ptr, 0, SMTP_SearchStrFound); /* see if we actually found a command and not a substring */ if (cmd_found > 0) { const uint8_t *tmp = ptr; const uint8_t *cmd_start = ptr + smtp_search_info.index; const uint8_t *cmd_end = cmd_start + smtp_search_info.length; /* move past spaces up until start of command */ while ((tmp < cmd_start) && isspace((int)*tmp)) tmp++; /* if not all spaces before command, we found a * substring */ if (tmp != cmd_start) cmd_found = 0; /* if we're before the end of line marker and the next * character is not whitespace, we found a substring */ if ((cmd_end < eolm) && !isspace((int)*cmd_end)) cmd_found = 0; /* there is a chance that end of command coincides with the end of payload * in which case, it could be a substring, but for now, we will treat it as found */ } /* if command not found, alert and move on */ if (!cmd_found) { /* If we missed one or more packets we might not actually be in the command * state. Check to see if we're encrypted */ if (smtp_ssn->state == STATE_UNKNOWN) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Command not found, but state is " "unknown - checking for SSL\n");); /* check for encrypted */ if ((smtp_ssn->session_flags & SMTP_FLAG_CHECK_SSL) && (SMTP_IsSSL(ptr, end - ptr, p->flags))) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Packet is SSL encrypted\n");); smtp_ssn->state = STATE_TLS_DATA; /* Ignore data */ if (smtp_eval_config->ignore_tls_data) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Ignoring encrypted data\n");); _dpd.SetAltDecode(0); } return end; } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Not SSL - try data state\n");); /* don't check for ssl again in this packet */ if (smtp_ssn->session_flags & SMTP_FLAG_CHECK_SSL) smtp_ssn->session_flags &= ~SMTP_FLAG_CHECK_SSL; smtp_ssn->state = STATE_DATA; smtp_ssn->data_state = STATE_DATA_UNKNOWN; return ptr; } } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "No known command found\n");); if (smtp_ssn->state != STATE_AUTH) { if (smtp_eval_config->alert_unknown_cmds) { SMTP_GenerateAlert(SMTP_UNKNOWN_CMD, "%s", SMTP_UNKNOWN_CMD_STR); } if (alert_long_command_line) { SMTP_GenerateAlert(SMTP_COMMAND_OVERFLOW, "%s: more than %d chars", SMTP_COMMAND_OVERFLOW_STR, smtp_eval_config->max_command_line_len); } } /* if normalizing, copy line to alt buffer */ if (smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, ptr, eol - ptr); if (ret == -1) return NULL; } return eol; } } /* At this point we have definitely found a legitimate command */ DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "%s\n", smtp_eval_config->cmds[smtp_search_info.id].name);); /* check if max command line length for a specific command is exceeded */ if (smtp_eval_config->cmd_config[smtp_search_info.id].max_line_len != 0) { if (cmd_line_len > smtp_eval_config->cmd_config[smtp_search_info.id].max_line_len) { SMTP_GenerateAlert(SMTP_SPECIFIC_CMD_OVERFLOW, "%s: %s, %d chars", SMTP_SPECIFIC_CMD_OVERFLOW_STR, smtp_eval_config->cmd_search[smtp_search_info.id].name, cmd_line_len); } } else if (alert_long_command_line) { SMTP_GenerateAlert(SMTP_COMMAND_OVERFLOW, "%s: more than %d chars", SMTP_COMMAND_OVERFLOW_STR, smtp_eval_config->max_command_line_len); } /* Are we alerting on this command? */ if (smtp_eval_config->cmd_config[smtp_search_info.id].alert) { SMTP_GenerateAlert(SMTP_ILLEGAL_CMD, "%s: %s", SMTP_ILLEGAL_CMD_STR, smtp_eval_config->cmds[smtp_search_info.id].name); } switch (smtp_search_info.id) { /* unless we do our own parsing of MAIL and RCTP commands we have to assume they * are ok unless we got a server error in which case we flush and if this is a * reassembled packet, the last command in this packet will be the command that * caused the error */ case CMD_MAIL: smtp_ssn->state_flags |= SMTP_FLAG_GOT_MAIL_CMD; if( smtp_eval_config->log_config.log_mailfrom ) { if(!SMTP_CopyEmailID(ptr, eolm - ptr, CMD_MAIL)) smtp_ssn->log_flags |= SMTP_FLAG_MAIL_FROM_PRESENT; } break; case CMD_RCPT: if ((smtp_ssn->state_flags & SMTP_FLAG_GOT_MAIL_CMD) || smtp_ssn->state == STATE_UNKNOWN) { smtp_ssn->state_flags |= SMTP_FLAG_GOT_RCPT_CMD; } if( smtp_eval_config->log_config.log_rcptto) { if(!SMTP_CopyEmailID(ptr, eolm - ptr, CMD_RCPT)) smtp_ssn->log_flags |= SMTP_FLAG_RCPT_TO_PRESENT; } break; case CMD_RSET: case CMD_HELO: case CMD_EHLO: case CMD_QUIT: smtp_ssn->state_flags &= ~(SMTP_FLAG_GOT_MAIL_CMD | SMTP_FLAG_GOT_RCPT_CMD); break; case CMD_STARTTLS: /* if reassembled we flush after seeing a 220 so this should be the last * command in reassembled packet and if not reassembled it should be the * last line in the packet as you can't pipeline the tls hello */ if (eol == end) smtp_ssn->state = STATE_TLS_CLIENT_PEND; break; case CMD_X_LINK2STATE: if (smtp_eval_config->alert_xlink2state) ParseXLink2State(p, ptr + smtp_search_info.index); break; case CMD_AUTH: smtp_ssn->state = STATE_AUTH; if (SMTP_IsAuthChanged(ptr + smtp_search_info.index + smtp_search_info.length, eolm) && (smtp_ssn->state_flags & SMTP_FLAG_ABORT)) { SMTP_GenerateAlert(SMTP_AUTH_ABORT_AUTH, "%s", SMTP_AUTH_ABORT_AUTH_STR); } smtp_ssn->state_flags &= ~(SMTP_FLAG_ABORT); break; case CMD_ABORT: smtp_ssn->state_flags |= SMTP_FLAG_ABORT; break; default: switch (smtp_eval_config->cmds[smtp_search_info.id].type) { case SMTP_CMD_TYPE_DATA: if ((smtp_ssn->state_flags & SMTP_FLAG_GOT_RCPT_CMD) || smtp_ssn->state == STATE_UNKNOWN) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Set to data state.\n");); smtp_ssn->state = STATE_DATA; smtp_ssn->state_flags &= ~(SMTP_FLAG_GOT_MAIL_CMD | SMTP_FLAG_GOT_RCPT_CMD); } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Didn't get MAIL -> RCPT command sequence - " "stay in command state.\n");); } break; case SMTP_CMD_TYPE_BDATA: if ((smtp_ssn->state_flags & (SMTP_FLAG_GOT_RCPT_CMD | SMTP_FLAG_BDAT)) || (smtp_ssn->state == STATE_UNKNOWN)) { const uint8_t *begin_chunk; const uint8_t *end_chunk; const uint8_t *tmp; int num_digits; int ten_power; uint32_t dat_chunk = 0; begin_chunk = ptr + smtp_search_info.index + smtp_search_info.length; while ((begin_chunk < eolm) && isspace((int)*begin_chunk)) begin_chunk++; /* bad BDAT command - needs chunk argument */ if (begin_chunk == eolm) break; end_chunk = begin_chunk; while ((end_chunk < eolm) && isdigit((int)*end_chunk)) end_chunk++; /* didn't get all digits */ if ((end_chunk < eolm) && !isspace((int)*end_chunk)) break; /* get chunk size */ num_digits = end_chunk - begin_chunk; /* more than 9 digits could potentially overflow a 32 bit integer * most servers won't accept this much in a chunk */ if (num_digits > 9) break; tmp = end_chunk; for (ten_power = 1, tmp--; tmp >= begin_chunk; ten_power *= 10, tmp--) dat_chunk += (*tmp - '0') * ten_power; if (smtp_search_info.id == CMD_BDAT) { /* got a valid chunk size - check to see if this is the last chunk */ const uint8_t *last = end_chunk; bool bdat_last = false; while ((last < eolm) && isspace((int)*last)) last++; if (((eolm - last) >= 4) && (strncasecmp("LAST", (const char *)last, 4) == 0)) { bdat_last = true; } if (bdat_last || (dat_chunk == 0)) smtp_ssn->state_flags &= ~(SMTP_FLAG_BDAT); else smtp_ssn->state_flags |= SMTP_FLAG_BDAT; smtp_ssn->state = STATE_BDATA; smtp_ssn->state_flags &= ~(SMTP_FLAG_GOT_MAIL_CMD | SMTP_FLAG_GOT_RCPT_CMD); } else if (smtp_search_info.id == CMD_XEXCH50) { smtp_ssn->state = STATE_XEXCH50; } else { smtp_ssn->state = STATE_BDATA; smtp_ssn->state_flags &= ~(SMTP_FLAG_GOT_MAIL_CMD | SMTP_FLAG_GOT_RCPT_CMD); } smtp_ssn->dat_chunk = dat_chunk; } break; case SMTP_CMD_TYPE_AUTH: smtp_ssn->state = STATE_AUTH; break; default: break; } break; } /* Since we found a command, if state is still unknown, * set to command state */ if (smtp_ssn->state == STATE_UNKNOWN) smtp_ssn->state = STATE_COMMAND; /* normalize command line */ if (smtp_eval_config->normalize == NORMALIZE_ALL || smtp_eval_config->cmd_config[smtp_search_info.id].normalize) { ret = SMTP_NormalizeCmd(p, ptr, eolm, eol); if (ret == -1) return NULL; } else if (smtp_normalizing) /* Already normalizing */ { ret = SMTP_CopyToAltBuffer(p, ptr, eol - ptr); if (ret == -1) return NULL; } return eol; } static const uint8_t * SMTP_HandleData(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *end) { const uint8_t *data_end_marker = NULL; const uint8_t *data_end = NULL; int data_end_found; int ret; uint16_t alt_decode_len = 0; FilePosition position = SNORT_FILE_START; bool done_data = false; /* if we've just entered the data state, check for a dot + end of line * if found, no data */ if ((smtp_ssn->data_state == STATE_DATA_INIT) || (smtp_ssn->data_state == STATE_DATA_UNKNOWN)) { if ((ptr < end) && (*ptr == '.')) { const uint8_t *eol = NULL; const uint8_t *eolm = NULL; SMTP_GetEOL(ptr, end, &eol, &eolm); /* this means we got a real end of line and not just end of payload * and that the dot is only char on line */ if ((eolm != end) && (eolm == (ptr + 1))) { /* if we're normalizing and not ignoring data copy data end marker * and dot to alt buffer */ if (!smtp_eval_config->ignore_data && smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, ptr, eol - ptr); if (ret == -1) return NULL; } SMTP_ResetState(); return eol; } } if (smtp_ssn->data_state == STATE_DATA_INIT) smtp_ssn->data_state = STATE_DATA_HEADER; /* XXX A line starting with a '.' that isn't followed by a '.' is * deleted (RFC 821 - 4.5.2. TRANSPARENCY). If data starts with * '. text', i.e a dot followed by white space then text, some * servers consider it data header and some data body. * Postfix and Qmail will consider the start of data: * . text\r\n * . text\r\n * to be part of the header and the effect will be that of a * folded line with the '.' deleted. Exchange will put the same * in the body which seems more reasonable. */ } if (smtp_ssn->state == STATE_DATA) { /* get end of data body * TODO check last bytes of previous packet to see if we had a partial * end of data */ smtp_current_search = &smtp_data_end_search[0]; data_end_found = _dpd.searchAPI->search_instance_find (smtp_data_search_mpse, (const char *)ptr, end - ptr, 0, SMTP_SearchStrFound); if (data_end_found > 0) { data_end_marker = ptr + smtp_search_info.index; data_end = data_end_marker + smtp_search_info.length; done_data = true; } else { data_end_marker = data_end = end; } } else { if ((ptr + smtp_ssn->dat_chunk) <= end) { data_end_marker = data_end = ptr + smtp_ssn->dat_chunk; smtp_ssn->dat_chunk = 0; // State goes back to command, since all of the data from the // BDAT command has been sent, but there might be more BDAT // commands to come. smtp_ssn->state = STATE_COMMAND; // Got a LAST modifier or 0 length data chunk, so no more // BDAT commands if (!(smtp_ssn->state_flags & SMTP_FLAG_BDAT)) done_data = true; } else { data_end_marker = data_end = end; smtp_ssn->dat_chunk -= (end - ptr); } } if(!smtp_eval_config->ignore_data) _dpd.setFileDataPtr((uint8_t*)ptr, (uint16_t)(data_end - ptr)); if ((smtp_ssn->data_state == STATE_DATA_HEADER) || (smtp_ssn->data_state == STATE_DATA_UNKNOWN)) { #ifdef DEBUG_MSGS if (smtp_ssn->data_state == STATE_DATA_HEADER) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA UNKNOWN STATE ~~~~~~~~~~~~~~~~~~~~~\n");); } #endif ptr = SMTP_HandleHeader(p, ptr, data_end_marker); if (ptr == NULL) return NULL; } /* if we're ignoring data and not already normalizing, copy everything * up to here into alt buffer so detection engine doesn't have * to look at the data; otherwise, if we're normalizing and not * ignoring data, copy all of the data into the alt buffer */ if (smtp_eval_config->ignore_data && !smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, p->payload, ptr - p->payload); if (ret == -1) return NULL; } else if (!smtp_eval_config->ignore_data && smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, ptr, data_end - ptr); if (ret == -1) return NULL; } /* now we shouldn't have to worry about copying any data to the alt buffer * only mime headers if we find them and only if we're ignoring data */ initFilePosition(&position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); while ((ptr != NULL) && (ptr < data_end_marker)) { /* multiple MIME attachments in one single packet. * Pipeline the MIME decoded data.*/ if ( smtp_ssn->state_flags & SMTP_FLAG_MULTIPLE_EMAIL_ATTACH) { int detection_size = getDetectionSize(smtp_eval_config->b64_depth, smtp_eval_config->qp_depth, smtp_eval_config->uu_depth, smtp_eval_config->bitenc_depth,smtp_ssn->decode_state ); _dpd.setFileDataPtr(smtp_ssn->decode_state->decodePtr, (uint16_t)detection_size); /*Upload*/ if (_dpd.fileAPI->file_process(p,(uint8_t *)smtp_ssn->decode_state->decodePtr, (uint16_t)smtp_ssn->decode_state->decoded_bytes, position, true, false) && (isFileStart(position)) && smtp_ssn->log_state) { _dpd.fileAPI->set_file_name_from_log(&(smtp_ssn->log_state->file_log), p->stream_session_ptr); } updateFilePosition(&position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); SMTP_LogFuncs(smtp_eval_config, p); alt_decode_len = 0; if (_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE)) { alt_decode_len = _dpd.altBuffer->len; } _dpd.detect(p); smtp_ssn->state_flags &= ~SMTP_FLAG_MULTIPLE_EMAIL_ATTACH; SMTP_UpdateDecodeStats(smtp_ssn->decode_state); ResetEmailDecodeState(smtp_ssn->decode_state); p->flags |=FLAG_ALLOW_MULTIPLE_DETECT; /* Reset the log count when a packet goes through detection multiple times */ _dpd.DetectReset((uint8_t *)p->payload, p->payload_size); /* There might be previously normalized data for this session which should not be cleared */ if(alt_decode_len) _dpd.SetAltDecode(alt_decode_len); } switch (smtp_ssn->data_state) { case STATE_MIME_HEADER: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "MIME HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleHeader(p, ptr, data_end_marker); _dpd.fileAPI->finalize_mime_position(p->stream_session_ptr, smtp_ssn->decode_state, &position); break; case STATE_DATA_BODY: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA BODY STATE ~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleDataBody(p, ptr, data_end_marker); _dpd.fileAPI->update_file_name(smtp_ssn->log_state); break; } } /* We have either reached the end of MIME header or end of MIME encoded data*/ if(smtp_ssn->decode_state != NULL) { int detection_size = getDetectionSize(smtp_eval_config->b64_depth, smtp_eval_config->qp_depth, smtp_eval_config->uu_depth, smtp_eval_config->bitenc_depth,smtp_ssn->decode_state ); _dpd.setFileDataPtr(smtp_ssn->decode_state->decodePtr, (uint16_t)detection_size); if (done_data || (smtp_ssn->state_flags & SMTP_FLAG_MIME_END)) { finalFilePosition(&position); } if (_dpd.fileAPI->file_process(p,(uint8_t *)smtp_ssn->decode_state->decodePtr, (uint16_t)smtp_ssn->decode_state->decoded_bytes, position, true, false) && (isFileStart(position)) && smtp_ssn->log_state) { _dpd.fileAPI->set_file_name_from_log(&(smtp_ssn->log_state->file_log), p->stream_session_ptr); } SMTP_UpdateDecodeStats(smtp_ssn->decode_state); ResetDecodedBytes(smtp_ssn->decode_state); smtp_ssn->state_flags &= ~SMTP_FLAG_MULTIPLE_EMAIL_ATTACH; } /* if we got the data end reset state, otherwise we're probably still in the data * to expect more data in next packet */ if (done_data) SMTP_ResetState(); return data_end; } /* * Handle Headers - Data or Mime * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */ static const uint8_t * SMTP_HandleHeader(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *data_end_marker) { const uint8_t *eol; const uint8_t *eolm; const uint8_t *colon; const uint8_t *content_type_ptr = NULL; const uint8_t *cont_trans_enc = NULL; const uint8_t *cont_disp = NULL; int header_line_len; int header_found; int ret; const uint8_t *start_hdr; int header_name_len; start_hdr = ptr; /* if we got a content-type in a previous packet and are * folding, the boundary still needs to be checked for */ if (smtp_ssn->state_flags & SMTP_FLAG_IN_CONTENT_TYPE) content_type_ptr = ptr; if (smtp_ssn->state_flags & SMTP_FLAG_IN_CONT_TRANS_ENC) cont_trans_enc = ptr; if (smtp_ssn->state_flags & SMTP_FLAG_IN_CONT_DISP) cont_disp = ptr; while (ptr < data_end_marker) { SMTP_GetEOL(ptr, data_end_marker, &eol, &eolm); /* got a line with only end of line marker should signify end of header */ if (eolm == ptr) { /* reset global header state values */ smtp_ssn->state_flags &= ~(SMTP_FLAG_FOLDING | SMTP_FLAG_IN_CONTENT_TYPE | SMTP_FLAG_DATA_HEADER_CONT | SMTP_FLAG_IN_CONT_TRANS_ENC |SMTP_FLAG_IN_CONT_DISP ); smtp_ssn->data_state = STATE_DATA_BODY; /* if no headers, treat as data */ if (ptr == start_hdr) return eolm; else return eol; } /* if we're not folding, see if we should interpret line as a data line * instead of a header line */ if (!(smtp_ssn->state_flags & (SMTP_FLAG_FOLDING | SMTP_FLAG_DATA_HEADER_CONT))) { char got_non_printable_in_header_name = 0; /* if we're not folding and the first char is a space or * colon, it's not a header */ if (isspace((int)*ptr) || *ptr == ':') { smtp_ssn->data_state = STATE_DATA_BODY; return ptr; } /* look for header field colon - if we're not folding then we need * to find a header which will be all printables (except colon) * followed by a colon */ colon = ptr; while ((colon < eolm) && (*colon != ':')) { if (((int)*colon < 33) || ((int)*colon > 126)) got_non_printable_in_header_name = 1; colon++; } /* Check for Exim 4.32 exploit where number of chars before colon is greater than 64 */ header_name_len = colon - ptr; if ((smtp_ssn->data_state != STATE_DATA_UNKNOWN) && (colon < eolm) && (header_name_len > MAX_HEADER_NAME_LEN)) { SMTP_GenerateAlert(SMTP_HEADER_NAME_OVERFLOW, "%s: %d chars before colon", SMTP_HEADER_NAME_OVERFLOW_STR, header_name_len); } /* If the end on line marker and end of line are the same, assume * header was truncated, so stay in data header state */ if ((eolm != eol) && ((colon == eolm) || got_non_printable_in_header_name)) { /* no colon or got spaces in header name (won't be interpreted as a header) * assume we're in the body */ smtp_ssn->state_flags &= ~(SMTP_FLAG_FOLDING | SMTP_FLAG_IN_CONTENT_TYPE | SMTP_FLAG_DATA_HEADER_CONT |SMTP_FLAG_IN_CONT_TRANS_ENC | SMTP_FLAG_IN_CONT_DISP); smtp_ssn->data_state = STATE_DATA_BODY; return ptr; } if(tolower((int)*ptr) == 'c') { smtp_current_search = &smtp_hdr_search[0]; header_found = _dpd.searchAPI->search_instance_find (smtp_hdr_search_mpse, (const char *)ptr, eolm - ptr, 1, SMTP_SearchStrFound); /* Headers must start at beginning of line */ if ((header_found > 0) && (smtp_search_info.index == 0)) { switch (smtp_search_info.id) { case HDR_CONTENT_TYPE: content_type_ptr = ptr + smtp_search_info.length; smtp_ssn->state_flags |= SMTP_FLAG_IN_CONTENT_TYPE; break; case HDR_CONT_TRANS_ENC: cont_trans_enc = ptr + smtp_search_info.length; smtp_ssn->state_flags |= SMTP_FLAG_IN_CONT_TRANS_ENC; break; case HDR_CONT_DISP: cont_disp = ptr + smtp_search_info.length; smtp_ssn->state_flags |= SMTP_FLAG_IN_CONT_DISP; break; default: break; } } } else if(tolower((int)*ptr) == 'e') { if( (eolm - ptr) >= 9 ) { if(strncasecmp((const char *)ptr, "Encoding:", 9) == 0) { cont_trans_enc = ptr + 9; smtp_ssn->state_flags |= SMTP_FLAG_IN_CONT_TRANS_ENC; } } } } else { smtp_ssn->state_flags &= ~SMTP_FLAG_DATA_HEADER_CONT; } /* get length of header line */ header_line_len = eol - ptr; if ((smtp_eval_config->max_header_line_len != 0) && (header_line_len > smtp_eval_config->max_header_line_len)) { if (smtp_ssn->data_state != STATE_DATA_UNKNOWN) { SMTP_GenerateAlert(SMTP_DATA_HDR_OVERFLOW, "%s: %d chars", SMTP_DATA_HDR_OVERFLOW_STR, header_line_len); } else { /* assume we guessed wrong and are in the body */ smtp_ssn->data_state = STATE_DATA_BODY; smtp_ssn->state_flags &= ~(SMTP_FLAG_FOLDING | SMTP_FLAG_IN_CONTENT_TYPE | SMTP_FLAG_DATA_HEADER_CONT | SMTP_FLAG_IN_CONT_TRANS_ENC | SMTP_FLAG_IN_CONT_DISP); return ptr; } } /* XXX Does VRT want data headers normalized? * currently the code does not normalize headers */ if (smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, ptr, eol - ptr); if (ret == -1) return NULL; } if(smtp_eval_config->log_config.log_email_hdrs) { if(smtp_ssn->data_state == STATE_DATA_HEADER) { ret = SMTP_CopyEmailHdrs(ptr, eol - ptr); } } /* check for folding * if char on next line is a space and not \n or \r\n, we are folding */ if ((eol < data_end_marker) && isspace((int)eol[0]) && (eol[0] != '\n')) { if ((eol < (data_end_marker - 1)) && (eol[0] != '\r') && (eol[1] != '\n')) { smtp_ssn->state_flags |= SMTP_FLAG_FOLDING; } else { smtp_ssn->state_flags &= ~SMTP_FLAG_FOLDING; } } else if (eol != eolm) { smtp_ssn->state_flags &= ~SMTP_FLAG_FOLDING; } /* check if we're in a content-type header and not folding. if so we have the whole * header line/lines for content-type - see if we got a multipart with boundary * we don't check each folded line, but wait until we have the complete header * because boundary=BOUNDARY can be split across mulitple folded lines before * or after the '=' */ if ((smtp_ssn->state_flags & (SMTP_FLAG_IN_CONTENT_TYPE | SMTP_FLAG_FOLDING)) == SMTP_FLAG_IN_CONTENT_TYPE) { if (smtp_ssn->data_state != STATE_MIME_HEADER) { /* we got the full content-type header - look for boundary string */ ret = SMTP_GetBoundary((const char *)content_type_ptr, eolm - content_type_ptr); if (ret != -1) { ret = SMTP_BoundarySearchInit(); if (ret != -1) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Got mime boundary: %s\n", smtp_ssn->mime_boundary.boundary);); smtp_ssn->state_flags |= SMTP_FLAG_GOT_BOUNDARY; } } } else if (!(smtp_ssn->state_flags & SMTP_FLAG_EMAIL_ATTACH)) { if( !SMTP_IsDecodingEnabled(smtp_eval_config) && !smtp_eval_config->ignore_data) { SetSmtpBuffers(smtp_ssn); if(smtp_ssn->decode_state != NULL) { ResetBytesRead(smtp_ssn->decode_state); SMTP_DecodeType((const char *)content_type_ptr, (eolm - content_type_ptr), false); smtp_ssn->state_flags |= SMTP_FLAG_EMAIL_ATTACH; /* check to see if there are other attachments in this packet */ if( smtp_ssn->decode_state->decoded_bytes ) smtp_ssn->state_flags |= SMTP_FLAG_MULTIPLE_EMAIL_ATTACH; } } } smtp_ssn->state_flags &= ~SMTP_FLAG_IN_CONTENT_TYPE; content_type_ptr = NULL; } else if ((smtp_ssn->state_flags & (SMTP_FLAG_IN_CONT_TRANS_ENC | SMTP_FLAG_FOLDING)) == SMTP_FLAG_IN_CONT_TRANS_ENC) { /* Check for Content-Transfer-Encoding : */ if( !SMTP_IsDecodingEnabled(smtp_eval_config) && !smtp_eval_config->ignore_data) { SetSmtpBuffers(smtp_ssn); if(smtp_ssn->decode_state != NULL) { ResetBytesRead(smtp_ssn->decode_state); SMTP_DecodeType((const char *)cont_trans_enc, (eolm - cont_trans_enc), true); smtp_ssn->state_flags |= SMTP_FLAG_EMAIL_ATTACH; /* check to see if there are other attachments in this packet */ if( smtp_ssn->decode_state->decoded_bytes ) smtp_ssn->state_flags |= SMTP_FLAG_MULTIPLE_EMAIL_ATTACH; } } smtp_ssn->state_flags &= ~SMTP_FLAG_IN_CONT_TRANS_ENC; cont_trans_enc = NULL; } else if (((smtp_ssn->state_flags & (SMTP_FLAG_IN_CONT_DISP | SMTP_FLAG_FOLDING)) == SMTP_FLAG_IN_CONT_DISP) && cont_disp) { bool disp_cont = (smtp_ssn->state_flags & SMTP_FLAG_IN_CONT_DISP_CONT)? true: false; if( smtp_eval_config->log_config.log_filename && smtp_ssn->log_state ) { if(! _dpd.fileAPI->log_file_name(cont_disp, eolm - cont_disp, &(smtp_ssn->log_state->file_log), &disp_cont) ) smtp_ssn->log_flags |= SMTP_FLAG_FILENAME_PRESENT; } if (disp_cont) { smtp_ssn->state_flags |= SMTP_FLAG_IN_CONT_DISP_CONT; } else { smtp_ssn->state_flags &= ~SMTP_FLAG_IN_CONT_DISP; smtp_ssn->state_flags &= ~SMTP_FLAG_IN_CONT_DISP_CONT; } cont_disp = NULL; } /* if state was unknown, at this point assume we know */ if (smtp_ssn->data_state == STATE_DATA_UNKNOWN) smtp_ssn->data_state = STATE_DATA_HEADER; ptr = eol; if (ptr == data_end_marker) smtp_ssn->state_flags |= SMTP_FLAG_DATA_HEADER_CONT; } return ptr; } /* * Handle DATA_BODY state * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */ static const uint8_t * SMTP_HandleDataBody(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *data_end_marker) { int boundary_found = 0; const uint8_t *boundary_ptr = NULL; const uint8_t *attach_start = NULL; const uint8_t *attach_end = NULL; if ( smtp_ssn->state_flags & SMTP_FLAG_EMAIL_ATTACH ) attach_start = ptr; /* look for boundary */ if (smtp_ssn->state_flags & SMTP_FLAG_GOT_BOUNDARY) { boundary_found = _dpd.searchAPI->stateful_search_instance_find (smtp_ssn->mime_boundary.boundary_search, (const char *)ptr, data_end_marker - ptr, 0, SMTP_BoundaryStrFound, &(smtp_ssn->mime_boundary.state)); if (boundary_found > 0) { smtp_ssn->mime_boundary.state = 0; boundary_ptr = ptr + smtp_search_info.index; /* should start at beginning of line */ if ((boundary_ptr == ptr) || (*(boundary_ptr - 1) == '\n')) { const uint8_t *eol; const uint8_t *eolm; const uint8_t *tmp; if (smtp_ssn->state_flags & SMTP_FLAG_EMAIL_ATTACH ) { attach_end = boundary_ptr-1; smtp_ssn->state_flags &= ~SMTP_FLAG_EMAIL_ATTACH; if( attach_start < attach_end ) { if (*(attach_end - 1) == '\r') attach_end--; if(EmailDecode( attach_start, attach_end, smtp_ssn->decode_state) < DECODE_SUCCESS ) { SMTP_DecodeAlert(); } } } if(boundary_ptr > ptr) tmp = boundary_ptr + smtp_search_info.length; else { tmp = (const uint8_t *)_dpd.searchAPI->search_instance_find_end((char *)boundary_ptr, (data_end_marker - boundary_ptr), smtp_ssn->mime_boundary.boundary, smtp_search_info.length); } /* Check for end boundary */ if (((tmp + 1) < data_end_marker) && (tmp[0] == '-') && (tmp[1] == '-')) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Mime boundary end found: %s--\n", (char *)smtp_ssn->mime_boundary.boundary);); /* no more MIME */ smtp_ssn->state_flags &= ~SMTP_FLAG_GOT_BOUNDARY; smtp_ssn->state_flags |= SMTP_FLAG_MIME_END; /* free boundary search */ _dpd.searchAPI->search_instance_free(smtp_ssn->mime_boundary.boundary_search); smtp_ssn->mime_boundary.boundary_search = NULL; } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Mime boundary found: %s\n", (char *)smtp_ssn->mime_boundary.boundary);); smtp_ssn->data_state = STATE_MIME_HEADER; } /* get end of line - there could be spaces after boundary before eol */ SMTP_GetEOL(boundary_ptr + smtp_search_info.length, data_end_marker, &eol, &eolm); return eol; } } } if ( smtp_ssn->state_flags & SMTP_FLAG_EMAIL_ATTACH ) { attach_end = data_end_marker; if( attach_start < attach_end ) { if(EmailDecode( attach_start, attach_end, smtp_ssn->decode_state) < DECODE_SUCCESS ) { SMTP_DecodeAlert(); } } } return data_end_marker; } /* * Process client packet * * @param packet standard Packet structure * * @return none */ static void SMTP_ProcessClientPacket(SFSnortPacket *p) { const uint8_t *ptr = p->payload; const uint8_t *end = p->payload + p->payload_size; if (smtp_ssn->state == STATE_CONNECT) { smtp_ssn->state = STATE_COMMAND; } else if (smtp_ssn->state == STATE_XEXCH50) { if (p->payload_size > smtp_ssn->dat_chunk) { ptr += smtp_ssn->dat_chunk; smtp_ssn->dat_chunk = 0; } else { smtp_ssn->dat_chunk -= p->payload_size; ptr = end; } if (smtp_ssn->dat_chunk == 0) smtp_ssn->state = STATE_COMMAND; } while ((ptr != NULL) && (ptr < end)) { switch (smtp_ssn->state) { case STATE_COMMAND: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "COMMAND STATE ~~~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleCommand(p, ptr, end); break; case STATE_DATA: case STATE_BDATA: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "DATA STATE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = SMTP_HandleData(p, ptr, end); break; case STATE_XEXCH50: if (smtp_normalizing) SMTP_CopyToAltBuffer(p, ptr, end - ptr); return; case STATE_AUTH: ptr = SMTP_HandleCommand(p, ptr, end); break; case STATE_UNKNOWN: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "UNKNOWN STATE ~~~~~~~~~~~~~~~~~~~~~~~~~~\n");); /* If state is unknown try command state to see if we can * regain our bearings */ ptr = SMTP_HandleCommand(p, ptr, end); break; default: DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Bad SMTP state\n");); return; } } #ifdef DEBUG_MSGS if (smtp_normalizing) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Normalized payload\n%s\n", SMTP_PrintBuffer(p));); } #endif } /* very simplistic - just enough to say this is binary data - the rules will make a final * judgement. Should maybe add an option to the smtp configuration to enable the * continuing of command inspection like ftptelnet. */ static int SMTP_IsTlsClientHello(const uint8_t *ptr, const uint8_t *end) { /* at least 3 bytes of data - see below */ if ((end - ptr) < 3) return 0; if ((ptr[0] == 0x16) && (ptr[1] == 0x03)) { /* TLS v1 or SSLv3 */ return 1; } else if ((ptr[2] == 0x01) || (ptr[3] == 0x01)) { /* SSLv2 */ return 1; } return 0; } /* this may at least tell us whether the server accepted the client hello by the presence * of binary data */ static int SMTP_IsTlsServerHello(const uint8_t *ptr, const uint8_t *end) { /* at least 3 bytes of data - see below */ if ((end - ptr) < 3) return 0; if ((ptr[0] == 0x16) && (ptr[1] == 0x03)) { /* TLS v1 or SSLv3 */ return 1; } else if (ptr[2] == 0x04) { /* SSLv2 */ return 1; } return 0; } /* * Process server packet * * @param packet standard Packet structure * * @return do_flush * @retval 1 flush queued packets on client side * @retval 0 do not flush queued packets on client side */ static int SMTP_ProcessServerPacket(SFSnortPacket *p, int *next_state) { int resp_found; const uint8_t *ptr; const uint8_t *end; const uint8_t *eolm; const uint8_t *eol; int do_flush = 0; int resp_line_len; #ifdef DEBUG_MSGS const uint8_t *dash; #endif *next_state = 0; ptr = p->payload; end = p->payload + p->payload_size; if (smtp_ssn->state == STATE_TLS_SERVER_PEND) { if (SMTP_IsTlsServerHello(ptr, end)) { smtp_ssn->state = STATE_TLS_DATA; } else if (!(_dpd.streamAPI->get_session_flags(p->stream_session_ptr) & SSNFLAG_MIDSTREAM) && !_dpd.streamAPI->missed_packets(p->stream_session_ptr, SSN_DIR_BOTH)) { /* Check to see if the raw packet is in order */ if(p->flags & FLAG_STREAM_ORDER_OK) { /* revert back to command state - assume server didn't accept STARTTLS */ smtp_ssn->state = STATE_COMMAND; } else return 0; } } if (smtp_ssn->state == STATE_TLS_DATA) return 0; while (ptr < end) { SMTP_GetEOL(ptr, end, &eol, &eolm); resp_line_len = eol - ptr; /* Check for response code */ smtp_current_search = &smtp_resp_search[0]; resp_found = _dpd.searchAPI->search_instance_find (smtp_resp_search_mpse, (const char *)ptr, resp_line_len, 1, SMTP_SearchStrFound); if (resp_found > 0) { switch (smtp_search_info.id) { case RESP_220: /* This is either an initial server response or a STARTTLS response * flush the client side. if we've already seen STARTTLS, no need * to flush */ if (smtp_ssn->state == STATE_CONNECT) smtp_ssn->state = STATE_COMMAND; else if (smtp_ssn->state != STATE_TLS_CLIENT_PEND) do_flush = 1; break; case RESP_250: case RESP_221: case RESP_334: break; case RESP_354: do_flush = 1; break; case RESP_235: // Auth done *next_state = STATE_COMMAND; do_flush = 1; break; default: if (smtp_ssn->state != STATE_COMMAND) { *next_state = STATE_COMMAND; do_flush = 1; } break; } #ifdef DEBUG_MSGS dash = ptr + smtp_search_info.index + smtp_search_info.length; /* only add response if not a dash after response code */ if ((dash == eolm) || ((dash < eolm) && (*dash != '-'))) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Server sent %s response\n", smtp_resps[smtp_search_info.id].name);); } #endif } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Server response not found - see if it's SSL data\n");); if ((smtp_ssn->session_flags & SMTP_FLAG_CHECK_SSL) && (SMTP_IsSSL(ptr, end - ptr, p->flags))) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Server response is an SSL packet\n");); smtp_ssn->state = STATE_TLS_DATA; /* Ignore data */ if (smtp_eval_config->ignore_tls_data) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Ignoring Server TLS encrypted data\n");); _dpd.SetAltDecode(0); } return 0; } else if (smtp_ssn->session_flags & SMTP_FLAG_CHECK_SSL) { smtp_ssn->session_flags &= ~SMTP_FLAG_CHECK_SSL; } } if ((smtp_eval_config->max_response_line_len != 0) && (resp_line_len > smtp_eval_config->max_response_line_len)) { SMTP_GenerateAlert(SMTP_RESPONSE_OVERFLOW, "%s: %d chars", SMTP_RESPONSE_OVERFLOW_STR, resp_line_len); } ptr = eol; } return do_flush; } static int SMTP_IsSSL(const uint8_t *ptr, int len, int pkt_flags) { uint32_t ssl_flags = SSL_decode(ptr, len, pkt_flags, 0); if ((ssl_flags != SSL_ARG_ERROR_FLAG) && !(ssl_flags & SMTP_SSL_ERROR_FLAGS)) { return 1; } return 0; } /* For Target based * If a protocol for the session is already identified and not one SMTP is * interested in, SMTP should leave it alone and return without processing. * If a protocol for the session is already identified and is one that SMTP is * interested in, decode it. * If the protocol for the session is not already identified and the preprocessor * is configured to detect on one of the packet ports, detect. * Returns 0 if we should not inspect * 1 if we should continue to inspect */ static int SMTP_Inspect(SFSnortPacket *p) { #ifdef TARGET_BASED /* SMTP could be configured to be stateless. If stream isn't configured, assume app id * will never be set and just base inspection on configuration */ if (p->stream_session_ptr == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: No stream session.\n");); if ((SMTP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (SMTP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: Configured for this " "traffic, so let's inspect.\n");); return 1; } } else { int16_t app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if (app_id != 0) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: App id: %u.\n", app_id);); if (app_id == smtp_proto_id) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: App id is " "set to \"%s\".\n", SMTP_PROTO_REF_STR);); return 1; } } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: Unknown protocol for " "this session. See if we're configured.\n");); if ((SMTP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (SMTP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP: Target-based: SMTP port is configured.");); return 1; } } } DEBUG_WRAP(DebugMessage(DEBUG_SMTP,"SMTP: Target-based: Not inspecting ...\n");); #else /* Make sure it's traffic we're interested in */ if ((SMTP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (SMTP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) return 1; #endif /* TARGET_BASED */ return 0; } /* * Entry point to snort preprocessor for each packet * * @param packet standard Packet structure * * @return none */ void SnortSMTP(SFSnortPacket *p) { int detected = 0; int pkt_dir; tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; smtp_ssn = (SMTP *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_SMTP); if (smtp_ssn != NULL) smtp_eval_config = (SMTPConfig *)sfPolicyUserDataGet(smtp_ssn->config, smtp_ssn->policy_id); else smtp_eval_config = (SMTPConfig *)sfPolicyUserDataGetCurrent(smtp_config); if (smtp_eval_config == NULL) return; if (smtp_ssn == NULL) { if (!SMTP_Inspect(p)) return; smtp_ssn = SMTP_GetNewSession(p, policy_id); if (smtp_ssn == NULL) return; } pkt_dir = SMTP_Setup(p, smtp_ssn); /* reset normalization stuff */ smtp_normalizing = 0; _dpd.DetectFlag_Disable(SF_FLAG_ALT_DECODE); p->normalized_payload_size = 0; if (pkt_dir == SMTP_PKT_FROM_SERVER) { int do_flush = 0; int next_state = 0; DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP server packet\n");); /* Process as a server packet */ do_flush = SMTP_ProcessServerPacket(p, &next_state); if (do_flush) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Flushing stream\n");); _dpd.streamAPI->response_flush_stream(p); } if (next_state) smtp_ssn->state = next_state; } else { #ifdef DEBUG_MSGS if (pkt_dir == SMTP_PKT_FROM_CLIENT) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP client packet\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP packet NOT from client or server! " "Processing as a client packet\n");); } #endif /* This packet should be a tls client hello */ if (smtp_ssn->state == STATE_TLS_CLIENT_PEND) { if (SMTP_IsTlsClientHello(p->payload, p->payload + p->payload_size)) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "TLS DATA STATE ~~~~~~~~~~~~~~~~~~~~~~~~~\n");); smtp_ssn->state = STATE_TLS_SERVER_PEND; } else if(p->flags & FLAG_STREAM_ORDER_OK) { /* reset state - server may have rejected STARTTLS command */ smtp_ssn->state = STATE_COMMAND; } } if ((smtp_ssn->state == STATE_TLS_DATA) || (smtp_ssn->state == STATE_TLS_SERVER_PEND)) { /* if we're ignoring tls data, set a zero length alt buffer */ if (smtp_eval_config->ignore_tls_data) { _dpd.SetAltDecode(0); _dpd.streamAPI->stop_inspection( p->stream_session_ptr, p, SSN_DIR_BOTH, -1, 0 ); return; } } else { if (p->flags & FLAG_STREAM_INSERT) { /* Packet will be rebuilt, so wait for it */ DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Client packet will be reassembled\n")); return; } else if (smtp_ssn->reassembling && !(p->flags & FLAG_REBUILT_STREAM)) { /* If this isn't a reassembled packet and didn't get * inserted into reassembly buffer, there could be a * problem. If we miss syn or syn-ack that had window * scaling this packet might not have gotten inserted * into reassembly buffer because it fell outside of * window, because we aren't scaling it */ smtp_ssn->session_flags |= SMTP_FLAG_GOT_NON_REBUILT; smtp_ssn->state = STATE_UNKNOWN; } else if (smtp_ssn->reassembling && (smtp_ssn->session_flags & SMTP_FLAG_GOT_NON_REBUILT)) { /* This is a rebuilt packet. If we got previous packets * that were not rebuilt, state is going to be messed up * so set state to unknown. It's likely this was the * beginning of the conversation so reset state */ DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Got non-rebuilt packets before " "this rebuilt packet\n");); smtp_ssn->state = STATE_UNKNOWN; smtp_ssn->session_flags &= ~SMTP_FLAG_GOT_NON_REBUILT; } #ifdef DEBUG_MSGS /* Interesting to see how often packets are rebuilt */ DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Payload: %s\n%s\n", (p->flags & FLAG_REBUILT_STREAM) ? "reassembled" : "not reassembled", SMTP_PrintBuffer(p));); #endif SMTP_ProcessClientPacket(p); } } PREPROC_PROFILE_START(smtpDetectPerfStats); SMTP_LogFuncs(smtp_eval_config, p); detected = _dpd.detect(p); #ifdef PERF_PROFILING smtpDetectCalled = 1; #endif PREPROC_PROFILE_END(smtpDetectPerfStats); /* Turn off detection since we've already done it. */ SMTP_DisableDetect(p); if (detected) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP vulnerability detected\n");); } } static void SMTP_DisableDetect(SFSnortPacket *p) { _dpd.disableAllDetect(p); _dpd.setPreprocBit(p, PP_SFPORTSCAN); _dpd.setPreprocBit(p, PP_PERFMONITOR); _dpd.setPreprocBit(p, PP_STREAM5); _dpd.setPreprocBit(p, PP_SDF); } static inline SMTP *SMTP_GetSession(void *data) { if(data) return (SMTP *)_dpd.streamAPI->get_application_data(data, PP_SMTP); return NULL; } /* Callback to return the MIME attachment filenames accumulated */ int SMTP_GetFilename(void *data, uint8_t **buf, uint32_t *len, uint32_t *type) { SMTP *ssn = SMTP_GetSession(data); if(ssn == NULL) return 0; *buf = ssn->log_state->file_log.filenames; *len = ssn->log_state->file_log.file_logged; *type = EVENT_INFO_SMTP_FILENAME; return 1; } /* Callback to return the email addresses accumulated from the MAIL FROM command */ int SMTP_GetMailFrom(void *data, uint8_t **buf, uint32_t *len, uint32_t *type) { SMTP *ssn = SMTP_GetSession(data); if(ssn == NULL) return 0; *buf = ssn->log_state->senders; *len = ssn->log_state->snds_logged; *type = EVENT_INFO_SMTP_MAILFROM; return 1; } /* Callback to return the email addresses accumulated from the RCP TO command */ int SMTP_GetRcptTo(void *data, uint8_t **buf, uint32_t *len, uint32_t *type) { SMTP *ssn = SMTP_GetSession(data); if(ssn == NULL) return 0; *buf = ssn->log_state->recipients; *len = ssn->log_state->rcpts_logged; *type = EVENT_INFO_SMTP_RCPTTO; return 1; } /* Calback to return the email headers */ int SMTP_GetEmailHdrs(void *data, uint8_t **buf, uint32_t *len, uint32_t *type) { SMTP *ssn = SMTP_GetSession(data); if(ssn == NULL) return 0; *buf = ssn->log_state->emailHdrs; *len = ssn->log_state->hdrs_logged; *type = EVENT_INFO_SMTP_EMAIL_HDRS; return 1; } snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_xlink2state.h0000644000000000000000000000264712260565732021534 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************* * smtp_xlink2state.h * * Author: Andy Mullican * *************************************************************************/ #ifndef __SMTP_XLINK2STATE_H__ #define __SMTP_XLINK2STATE_H__ #include "sf_snort_packet.h" int ParseXLink2State(SFSnortPacket *, const uint8_t *); #endif /* __SMTP_XLINK2STATE_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_xlink2state.c0000644000000000000000000001723212260565732021523 00000000000000/*************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************ * * smtp_xlink2state.c * * Author: Andy Mullican * * Description: * * This file handles the X-Link2State vulnerability. * * Entry point function: * * ParseXLink2State() * * ************************************************************************/ #ifndef WIN32 #include #endif #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_smtp.h" #include "smtp_config.h" #include "smtp_util.h" #include "smtp_log.h" #include "smtp_xlink2state.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_packet.h" #define XLINK_OTHER 1 #define XLINK_FIRST 2 #define XLINK_CHUNK 3 #define XLINK_LEN 12 /* strlen("X-LINK2STATE") */ /* X-Link2State overlong length */ #define XLINK2STATE_MAX_LEN 520 extern SMTP *smtp_ssn; extern SMTPConfig *smtp_eval_config; /* Prototypes */ static uint32_t get_xlink_hex_value(const uint8_t *, const uint8_t *); static char get_xlink_keyword(const uint8_t *, const uint8_t *); /* * Extract a number from a string * * @param buf pointer to beginning of buffer to parse * @param end end pointer of buffer to parse * * @return unsigned long value of number extracted * * @note this could be more efficient, but the search buffer should be pretty short */ static uint32_t get_xlink_hex_value(const uint8_t *buf, const uint8_t *end) { char c; uint32_t value = 0; const uint8_t *hex_end; if ((end - buf) < 8) return 0; hex_end = buf + 8; while (buf < hex_end) { c = toupper((int)*buf); /* Make sure it is a number or hex char; if not return with what we have */ if (isdigit((int)c)) { c = c - '0'; } else if (c >= 'A' && c <= 'F') { c = (c - 'A') + 10; } else { return value; } value = (value * 16) + c; buf++; } return value; } /* * Check for X-LINK2STATE keywords FIRST or CHUNK * * * @param x pointer to "X-LINK2STATE" in buffer * @param x_len length of buffer after x * * @retval int identifies which keyword found, if any */ static char get_xlink_keyword(const uint8_t *ptr, const uint8_t *end) { int len; if (ptr == NULL || end == NULL) return XLINK_OTHER; ptr += XLINK_LEN; if (ptr >= end) return XLINK_OTHER; /* Skip over spaces */ while (ptr < end && isspace((int)*ptr)) { ptr++; } len = end - ptr; if (len > 5 && strncasecmp((const char *)ptr, "FIRST", 5) == 0) { return XLINK_FIRST; } else if (len > 5 && strncasecmp((const char *)ptr, "CHUNK", 5) == 0) { return XLINK_CHUNK; } return XLINK_OTHER; } /* * Handle X-Link2State vulnerability * * From Lurene Grenier: The X-LINK2STATE command always takes the following form: X-LINK2STATE [FIRST|NEXT|LAST] CHUNK= The overwrite occurs when three criteria are met: No chunk identifier exists - ie neither FIRST, NEXT, or LAST are specified No previous FIRST chunk was sent has a length greater than 520 bytes Normally you send a FIRST chunk, then some intermediary chunks marked with either NEXT or not marked, then finally a LAST chunk. If no first chunk is sent, and a chunk with no specifier is sent, it assumes it must append to something, but it has nothing to append to, so an overwrite occurs. Sending out of order chunks WITH specifiers results in an exception. So simply: if (gotFirstChunk) next; # chunks came with proper first chunk specified if (/X-LINK2STATE [FIRST|NEXT|LAST] CHUNK/) { if (/X-LINK2STATE FIRST CHUNK/) gotFirstChunk = TRUE; next; # some specifier is marked } if (chunkLen > 520) attempt = TRUE; # Gotcha! Usually it takes more than one unspecified packet in a row, but I think this is just a symptom of the fact that we're triggering a heap overwrite, and not a condition of the bug. However, if we're still getting FPs this might be an avenue to try. * * @param p standard Packet structure * @param x pointer to "X-LINK2STATE" in buffer * * @retval 1 if alert raised * @retval 0 if no alert raised */ int ParseXLink2State(SFSnortPacket *p, const uint8_t *ptr) { uint8_t *lf = NULL; uint32_t len = 0; char x_keyword; const uint8_t *end; if (p == NULL || ptr == NULL) return 0; /* If we got a FIRST chunk on this stream, this is not an exploit */ if (smtp_ssn->session_flags & SMTP_FLAG_XLINK2STATE_GOTFIRSTCHUNK) return 0; /* Calculate length from pointer to end of packet data */ end = p->payload + p->payload_size; if (ptr >= end) return 0; /* Check for "FIRST" or "CHUNK" after X-LINK2STATE */ x_keyword = get_xlink_keyword(ptr, end); if (x_keyword != XLINK_CHUNK) { if (x_keyword == XLINK_FIRST) smtp_ssn->session_flags |= SMTP_FLAG_XLINK2STATE_GOTFIRSTCHUNK; return 0; } ptr = (uint8_t *)memchr((char *)ptr, '=', end - ptr); if (ptr == NULL) return 0; /* move past '=' and make sure we're within bounds */ ptr++; if (ptr >= end) return 0; /* Look for one of two patterns: * * ... CHUNK={0000006d} MULTI (5) ({00000000051} ... * ... CHUNK=AAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n */ if (*ptr == '{') { /* move past '{' and make sure we're within bounds */ ptr++; if ((ptr + 8) >= end) return 0; /* Get length - can we always trust it? */ len = get_xlink_hex_value(ptr, end); } else { lf = (uint8_t *)memchr((char *)ptr, '\n', end - ptr); if (lf == NULL) return 0; len = lf - ptr; } if (len > XLINK2STATE_MAX_LEN) { /* Need to drop the packet if we're told to * (outside of whether its thresholded). */ if (smtp_eval_config->drop_xlink2state) { _dpd.inlineDropAndReset(p); } SMTP_GenerateAlert(SMTP_XLINK2STATE_OVERFLOW, "%s", SMTP_XLINK2STATE_OVERFLOW_STR); smtp_ssn->session_flags |= SMTP_FLAG_XLINK2STATE_ALERTED; return 1; } /* Check for more than one command in packet */ ptr = (uint8_t *)memchr((char *)ptr, '\n', end - ptr); if (ptr == NULL) return 0; /* move past '\n' */ ptr++; if (ptr < end) { ParseXLink2State(p, ptr); } return 0; } snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_util.h0000644000000000000000000000343512260565732020235 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************* * * smtp_util.h * * Author: Andy Mullican * Author: Todd Wease * *************************************************************************/ #ifndef __SMTP_UTIL_H__ #define __SMTP_UTIL_H__ #include "sf_snort_packet.h" void SMTP_GetEOL(const uint8_t *, const uint8_t *, const uint8_t **, const uint8_t **); int SMTP_CopyToAltBuffer(SFSnortPacket *, const uint8_t *, int); int SMTP_CopyEmailHdrs(const uint8_t *, int ); int SMTP_CopyEmailID(const uint8_t *, int , int ); void SMTP_LogFuncs(SMTPConfig *config, SFSnortPacket *p); void SMTP_DecodeType(const char *, int, bool ); #ifdef DEBUG_MSGS const char * SMTP_PrintBuffer(SFSnortPacket *); #endif #endif /* __SMTP_UTIL_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_util.c0000644000000000000000000002164512260565732020233 00000000000000/* * smtp_util.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * Author: Andy Mullican * * Description: * * This file contains SMTP helper functions. * * Entry point functions: * * safe_strchr() * safe_strstr() * copy_to_space() * safe_sscanf() * * */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "snort_bounds.h" #include "snort_smtp.h" #include "smtp_util.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_packet.h" extern SMTP *smtp_ssn; extern char smtp_normalizing; void SMTP_GetEOL(const uint8_t *ptr, const uint8_t *end, const uint8_t **eol, const uint8_t **eolm) { const uint8_t *tmp_eol; const uint8_t *tmp_eolm; /* XXX maybe should fatal error here since none of these * pointers should be NULL */ if (ptr == NULL || end == NULL || eol == NULL || eolm == NULL) return; tmp_eol = (uint8_t *)memchr(ptr, '\n', end - ptr); if (tmp_eol == NULL) { tmp_eol = end; tmp_eolm = end; } else { /* end of line marker (eolm) should point to marker and * end of line (eol) should point to end of marker */ if ((tmp_eol > ptr) && (*(tmp_eol - 1) == '\r')) { tmp_eolm = tmp_eol - 1; } else { tmp_eolm = tmp_eol; } /* move past newline */ tmp_eol++; } *eol = tmp_eol; *eolm = tmp_eolm; } int SMTP_CopyToAltBuffer(SFSnortPacket *p, const uint8_t *start, int length) { uint8_t *alt_buf; int alt_size; uint16_t *alt_len; int ret; /* if we make a call to this it means we want to use the alt buffer * regardless of whether we copy any data into it or not - barring a failure */ smtp_normalizing = 1; /* if start and end the same, nothing to copy */ if (length == 0) return 0; alt_buf = _dpd.altBuffer->data; alt_size = sizeof(_dpd.altBuffer->data); alt_len = &_dpd.altBuffer->len; ret = SafeMemcpy(alt_buf + *alt_len, start, length, alt_buf, alt_buf + alt_size); if (ret != SAFEMEM_SUCCESS) { _dpd.DetectFlag_Disable(SF_FLAG_ALT_DECODE); smtp_normalizing = 0; return -1; } *alt_len += length; _dpd.SetAltDecode(*alt_len); return 0; } /* Accumulate EOL seperated headers, one or more at a time */ int SMTP_CopyEmailHdrs(const uint8_t *start, int length) { int log_avail = 0; uint8_t *log_buf; uint32_t *hdrs_logged; int ret = 0; if ((smtp_ssn->log_state == NULL) || (length <= 0)) return -1; log_avail = (smtp_ssn->log_state->log_depth - smtp_ssn->log_state->hdrs_logged); hdrs_logged = &(smtp_ssn->log_state->hdrs_logged); log_buf = (uint8_t *)smtp_ssn->log_state->emailHdrs; if(log_avail <= 0) { return -1; } if(length > log_avail ) { length = log_avail; } /* appended by the EOL \r\n */ ret = SafeMemcpy(log_buf + *hdrs_logged, start, length, log_buf, log_buf+(smtp_ssn->log_state->log_depth)); if (ret != SAFEMEM_SUCCESS) { return -1; } *hdrs_logged += length; smtp_ssn->log_flags |= SMTP_FLAG_EMAIL_HDRS_PRESENT; return 0; } /* Accumulate email addresses from RCPT TO and/or MAIL FROM commands. Email addresses are separated by comma */ int SMTP_CopyEmailID(const uint8_t *start, int length, int command_type) { uint8_t *alt_buf; int alt_size; uint16_t *alt_len; int ret; int log_avail=0; const uint8_t *tmp_eol; if ((smtp_ssn->log_state == NULL) || (length <= 0)) return -1; tmp_eol = (uint8_t *)memchr(start, ':', length); if(tmp_eol == NULL) return -1; if((tmp_eol+1) < (start+length)) { length = length - ( (tmp_eol+1) - start ); start = tmp_eol+1; } else return -1; switch (command_type) { case CMD_MAIL: alt_buf = smtp_ssn->log_state->senders; alt_size = MAX_EMAIL; alt_len = &(smtp_ssn->log_state->snds_logged); break; case CMD_RCPT: alt_buf = smtp_ssn->log_state->recipients; alt_size = MAX_EMAIL; alt_len = &(smtp_ssn->log_state->rcpts_logged); break; default: return -1; } log_avail = alt_size - *alt_len; if(log_avail <= 0 || !alt_buf) return -1; else if(log_avail < length) length = log_avail; if ( *alt_len > 0 && ((*alt_len + 1) < alt_size)) { alt_buf[*alt_len] = ','; *alt_len = *alt_len + 1; } ret = SafeMemcpy(alt_buf + *alt_len, start, length, alt_buf, alt_buf + alt_size); if (ret != SAFEMEM_SUCCESS) { if(*alt_len != 0) *alt_len = *alt_len - 1; return -1; } *alt_len += length; return 0; } void SMTP_DecodeType(const char *start, int length, bool cnt_xf) { const char *tmp = NULL; if(cnt_xf) { if(smtp_ssn->decode_state->b64_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "base64"); if( tmp != NULL ) { smtp_ssn->decode_state->decode_type = DECODE_B64; smtp_stats.attachments[DECODE_B64]++; return; } } if(smtp_ssn->decode_state->qp_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "quoted-printable"); if( tmp != NULL ) { smtp_ssn->decode_state->decode_type = DECODE_QP; smtp_stats.attachments[DECODE_QP]++; return; } } if(smtp_ssn->decode_state->uu_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "uuencode"); if( tmp != NULL ) { smtp_ssn->decode_state->decode_type = DECODE_UU; smtp_stats.attachments[DECODE_UU]++; return; } } } if(smtp_ssn->decode_state->bitenc_state.depth > -1) { smtp_ssn->decode_state->decode_type = DECODE_BITENC; smtp_stats.attachments[DECODE_BITENC]++; return; } return; } void SMTP_LogFuncs(SMTPConfig *config, SFSnortPacket *p) { if((smtp_ssn->log_flags == 0) || !config) return; if(smtp_ssn->log_flags & SMTP_FLAG_FILENAME_PRESENT) { _dpd.streamAPI->set_extra_data(p->stream_session_ptr, p, config->xtra_filename_id); } if(smtp_ssn->log_flags & SMTP_FLAG_MAIL_FROM_PRESENT) { _dpd.streamAPI->set_extra_data(p->stream_session_ptr, p, config->xtra_mfrom_id); } if(smtp_ssn->log_flags & SMTP_FLAG_RCPT_TO_PRESENT) { _dpd.streamAPI->set_extra_data(p->stream_session_ptr, p, config->xtra_rcptto_id); } if(smtp_ssn->log_flags & SMTP_FLAG_EMAIL_HDRS_PRESENT) { _dpd.streamAPI->set_extra_data(p->stream_session_ptr, p, config->xtra_ehdrs_id); } } #ifdef DEBUG_MSGS char smtp_print_buffer[65537]; const char * SMTP_PrintBuffer(SFSnortPacket *p) { const uint8_t *ptr = NULL; int len = 0; int iorig, inew; if (smtp_normalizing) { ptr = _dpd.altBuffer->data; len = _dpd.altBuffer->len; } else { ptr = p->payload; len = p->payload_size; } for (iorig = 0, inew = 0; iorig < len; iorig++, inew++) { if ((isascii((int)ptr[iorig]) && isprint((int)ptr[iorig])) || (ptr[iorig] == '\n')) { smtp_print_buffer[inew] = ptr[iorig]; } else if (ptr[iorig] == '\r' && ((iorig + 1) < len) && (ptr[iorig + 1] == '\n')) { iorig++; smtp_print_buffer[inew] = '\n'; } else if (isspace((int)ptr[iorig])) { smtp_print_buffer[inew] = ' '; } else { smtp_print_buffer[inew] = '.'; } } smtp_print_buffer[inew] = '\0'; return &smtp_print_buffer[0]; } #endif snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_normalize.h0000644000000000000000000000216712260565732021261 00000000000000 /* * smtp_normalize.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * Author: Andy Mullican * */ #ifndef __SMTP_NORMALIZE_H__ #define __SMTP_NORMALIZE_H__ #include "sf_snort_packet.h" int SMTP_NormalizeCmd(SFSnortPacket *, const uint8_t *, const uint8_t *, const uint8_t *); #endif snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_normalize.c0000644000000000000000000001243112260565732021247 00000000000000/* * smtp_normalize.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * Author: Andy Mullican * * Description: * * This file handles normalizing SMTP traffic into the alternate buffer. * * Entry point functions: * * SMTP_NeedNormalize() * SMTP_Normalize() * * */ #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_smtp.h" #include "smtp_util.h" #include "snort_bounds.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_packet.h" extern SMTP *smtp_ssn; extern char smtp_normalizing; /* * SMTP_NormalizeCmd * * If command doesn't need normalizing it will do nothing, except in * the case where we are already normalizing in which case the line * will get copied to the alt buffer. * If the command needs normalizing the normalized data will be copied * to the alt buffer. If we are not already normalizing, all of the * data up to this point will be copied into the alt buffer first. * * XXX This may copy unwanted data if we are ignoring the data in the * message and there was data that came before the command in the * packet, for example if there are multiple transactions on the * session or if we're normalizing QUIT. * * @param p pointer to packet structure * @param ptr pointer to beginning of command line * @param eolm start of end of line marker * @param eol end of end of line marker * * @return response * @retval 0 function succeded without error * @retval -1 there were errors */ int SMTP_NormalizeCmd(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *eolm, const uint8_t *eol) { const uint8_t *tmp; const uint8_t *cmd_start; const uint8_t *cmd_end; const uint8_t *args_start; const uint8_t *args_end; const uint8_t *space = (uint8_t *)" "; int need_normalize = 0; int ret; tmp = ptr; /* move past initial whitespace */ while ((tmp < eolm) && isspace((int)*tmp)) tmp++; /* we got whitespace before command */ if (tmp > ptr) need_normalize = 1; /* move past the command */ cmd_start = cmd_end = tmp; while ((cmd_end < eolm) && !isspace((int)*cmd_end)) cmd_end++; args_start = cmd_end; while ((args_start < eolm) && isspace((int)*args_start)) args_start++; if (args_start == eolm) { /* nothing but space after command - normalize if we got any * spaces since there is not an argument */ if (args_start > cmd_end) need_normalize = 1; args_end = args_start; } else { /* more than one space between command and argument or * whitespace between command and argument is not a regular space character */ if ((args_start > (cmd_end + 1)) || (*cmd_end != ' ')) need_normalize = 1; /* see if there is any dangling space at end of argument */ args_end = eolm; while (isspace((int)*(args_end - 1))) args_end--; if (args_end != eolm) need_normalize = 1; } if (need_normalize) { DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Command needs normalizing\n");); /* if we're not yet normalizing copy everything in the payload up to this * line into the alt buffer */ if (!smtp_normalizing) { ret = SMTP_CopyToAltBuffer(p, p->payload, ptr - p->payload); if (ret == -1) return -1; } /* copy the command into the alt buffer */ ret = SMTP_CopyToAltBuffer(p, cmd_start, cmd_end - cmd_start); if (ret == -1) return -1; /* if we actually have an argument, copy it into the alt buffer */ if (args_start != args_end) { /* copy a 'pure' space */ ret = SMTP_CopyToAltBuffer(p, space, 1); if (ret == -1) return -1; ret = SMTP_CopyToAltBuffer(p, args_start, args_end - args_start); if (ret == -1) return -1; } /* copy the end of line marker into the alt buffer */ ret = SMTP_CopyToAltBuffer(p, eolm, eol - eolm); if (ret == -1) return -1; } else if (smtp_normalizing) { /* if we're already normalizing and didn't need to normalize this line, just * copy it into the alt buffer */ ret = SMTP_CopyToAltBuffer(p, ptr, eol - ptr); if (ret == -1) return -1; } return 0; } snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_log.h0000644000000000000000000000635212260565732020042 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * smtp_log.h * * Author: Andy Mullican * **************************************************************************/ #ifndef __SMTP_LOG_H__ #define __SMTP_LOG_H__ #define GENERATOR_SMTP 124 /* Events for SMTP */ #define SMTP_COMMAND_OVERFLOW 1 #define SMTP_DATA_HDR_OVERFLOW 2 #define SMTP_RESPONSE_OVERFLOW 3 #define SMTP_SPECIFIC_CMD_OVERFLOW 4 #define SMTP_UNKNOWN_CMD 5 #define SMTP_ILLEGAL_CMD 6 #define SMTP_HEADER_NAME_OVERFLOW 7 #define SMTP_XLINK2STATE_OVERFLOW 8 #define SMTP_DECODE_MEMCAP_EXCEEDED 9 #define SMTP_B64_DECODING_FAILED 10 #define SMTP_QP_DECODING_FAILED 11 /* Do not delete or reuse this SID. Commenting this SID as this alert is no longer valid.* * #define SMTP_BITENC_DECODING_FAILED 12 */ #define SMTP_UU_DECODING_FAILED 13 #define SMTP_AUTH_ABORT_AUTH 14 #define SMTP_EVENT_MAX 15 /* Messages for each event */ #define SMTP_COMMAND_OVERFLOW_STR "(smtp) Attempted command buffer overflow" #define SMTP_DATA_HDR_OVERFLOW_STR "(smtp) Attempted data header buffer overflow" #define SMTP_RESPONSE_OVERFLOW_STR "(smtp) Attempted response buffer overflow" #define SMTP_SPECIFIC_CMD_OVERFLOW_STR "(smtp) Attempted specific command buffer overflow" #define SMTP_UNKNOWN_CMD_STR "(smtp) Unknown command" #define SMTP_ILLEGAL_CMD_STR "(smtp) Illegal command" #define SMTP_HEADER_NAME_OVERFLOW_STR "(smtp) Attempted header name buffer overflow" #define SMTP_XLINK2STATE_OVERFLOW_STR "(smtp) Attempted X-Link2State command buffer overflow" #define SMTP_DECODE_MEMCAP_EXCEEDED_STR "(smtp) No memory available for decoding. Max Mime Mem exceeded" #define SMTP_B64_DECODING_FAILED_STR "(smtp) Base64 Decoding failed." #define SMTP_QP_DECODING_FAILED_STR "(smtp) Quoted-Printable Decoding failed." #define SMTP_UU_DECODING_FAILED_STR "(smtp) Unix-to-Unix Decoding failed." #define SMTP_AUTH_ABORT_AUTH_STR "(smtp) Cyrus SASL authentication attack." #define EVENT_STR_LEN 256 /* Function prototypes */ void SMTP_GenerateAlert(int, char *, ...); void SMTP_Decode( void ); void SMTP_DecodeAlert(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_log.c0000644000000000000000000000706712260565732020041 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * smtp_log.c * * Author: Andy Mullican * * Description: * * This file handles SMTP alerts. * * Entry point functions: * * SMTP_GenerateAlert() * * **************************************************************************/ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "smtp_config.h" #include "smtp_log.h" #include "snort_smtp.h" #include "sf_dynamic_preprocessor.h" extern SMTPConfig *smtp_eval_config; extern SMTP *smtp_ssn; char smtp_event[SMTP_EVENT_MAX][EVENT_STR_LEN]; void SMTP_GenerateAlert(int event, char *format, ...) { va_list ap; /* Only log a specific alert once per session */ if (smtp_ssn->alert_mask & (1 << event)) { #ifdef DEBUG_MSGS DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Already alerted on: %s - " "ignoring event.\n", smtp_event[event]);); #endif return; } /* set bit for this alert so we don't alert on again * in this session */ smtp_ssn->alert_mask |= (1 << event); if (smtp_eval_config->no_alerts) { #ifdef DEBUG_MSGS va_start(ap, format); smtp_event[event][0] = '\0'; vsnprintf(&smtp_event[event][0], EVENT_STR_LEN - 1, format, ap); smtp_event[event][EVENT_STR_LEN - 1] = '\0'; DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "Ignoring alert: %s\n", smtp_event[event]);); va_end(ap); #endif return; } va_start(ap, format); smtp_event[event][0] = '\0'; vsnprintf(&smtp_event[event][0], EVENT_STR_LEN - 1, format, ap); smtp_event[event][EVENT_STR_LEN - 1] = '\0'; _dpd.alertAdd(GENERATOR_SMTP, event, 1, 0, 3, &smtp_event[event][0], 0); DEBUG_WRAP(DebugMessage(DEBUG_SMTP, "SMTP Alert generated: %s\n", smtp_event[event]);); va_end(ap); } void SMTP_DecodeAlert(void) { switch( smtp_ssn->decode_state->decode_type ) { case DECODE_B64: if (smtp_eval_config->b64_depth > -1) SMTP_GenerateAlert(SMTP_B64_DECODING_FAILED, "%s", SMTP_B64_DECODING_FAILED_STR); break; case DECODE_QP: if (smtp_eval_config->qp_depth > -1) SMTP_GenerateAlert(SMTP_QP_DECODING_FAILED, "%s", SMTP_QP_DECODING_FAILED_STR); break; case DECODE_UU: if (smtp_eval_config->uu_depth > -1) SMTP_GenerateAlert(SMTP_UU_DECODING_FAILED, "%s", SMTP_UU_DECODING_FAILED_STR); break; default: break; } } snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_config.h0000644000000000000000000001604612260565732020527 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /*************************************************************************** * * smtp_config.h * * Author: Andy Mullican * Author: Todd Wease * ***************************************************************************/ #ifndef __SMTP_CONFIG_H__ #define __SMTP_CONFIG_H__ #include "sfPolicyUserData.h" #include "sf_email_attach_decode.h" #include "file_api.h" #define CONF_SEPARATORS " \t\n\r" #define CONF_PORTS "ports" #define CONF_INSPECTION_TYPE "inspection_type" #define CONF_NORMALIZE "normalize" #define CONF_NORMALIZE_CMDS "normalize_cmds" #define CONF_IGNORE_DATA "ignore_data" #define CONF_IGNORE_TLS_DATA "ignore_tls_data" #define CONF_MAX_COMMAND_LINE_LEN "max_command_line_len" #define CONF_MAX_HEADER_LINE_LEN "max_header_line_len" #define CONF_MAX_RESPONSE_LINE_LEN "max_response_line_len" #define CONF_ALT_MAX_COMMAND_LINE_LEN "alt_max_command_line_len" #define CONF_MAX_MIME_MEM "max_mime_mem" #define CONF_MAX_MIME_DEPTH "max_mime_depth" #define CONF_ENABLE_MIME_DECODING "enable_mime_decoding" #define CONF_B64_DECODE "b64_decode_depth" #define CONF_QP_DECODE "qp_decode_depth" #define CONF_BITENC_DECODE "bitenc_decode_depth" #define CONF_UU_DECODE "uu_decode_depth" #define CONF_LOG_FILENAME "log_filename" #define CONF_LOG_MAIL_FROM "log_mailfrom" #define CONF_LOG_RCPT_TO "log_rcptto" #define CONF_LOG_EMAIL_HDRS "log_email_hdrs" #define CONF_SMTP_MEMCAP "memcap" #define CONF_EMAIL_HDRS_LOG_DEPTH "email_hdrs_log_depth" #define CONF_DISABLED "disabled" #define CONF_NO_ALERTS "no_alerts" #define CONF_VALID_CMDS "valid_cmds" #define CONF_INVALID_CMDS "invalid_cmds" #define CONF_PRINT_CMDS "print_cmds" #define CONF_ALERT_UNKNOWN_CMDS "alert_unknown_cmds" #define CONF_XLINK2STATE "xlink2state" #define CONF_ENABLE "enable" #define CONF_DISABLE "disable" #define CONF_INLINE_DROP "drop" #define CONF_STATEFUL "stateful" #define CONF_STATELESS "stateless" #define CONF_YES "yes" #define CONF_ALL "all" #define CONF_NONE "none" #define CONF_CMDS "cmds" #define CONF_AUTH_CMDS "auth_cmds" #define CONF_DATA_CMDS "data_cmds" #define CONF_BDATA_CMDS "binary_data_cmds" #define CONF_START_LIST "{" #define CONF_END_LIST "}" #define NORMALIZE_NONE 0 #define NORMALIZE_CMDS 1 #define NORMALIZE_ALL 2 #define ACTION_ALERT 0 #define ACTION_NO_ALERT 1 #define ACTION_NORMALIZE 2 #define DEFAULT_MAX_COMMAND_LINE_LEN 0 #define DEFAULT_MAX_HEADER_LINE_LEN 0 #define DEFAULT_MAX_RESPONSE_LINE_LEN 0 /*These are temporary values*/ #define MAX_DEPTH 65535 #define MIN_DEPTH -1 #define DEFAULT_MAX_MIME_MEM 838860 #define DEFAULT_MAX_MIME_DEPTH 1460 #define DEFAULT_SMTP_MEMCAP 838860 #define DEFAULT_LOG_DEPTH 1464 #define MAX_MIME_MEM 104857600 #define MIN_MIME_MEM 3276 #define MAX_MIME_DEPTH 20480 #define MIN_MIME_DEPTH 4 #define MAX_SMTP_MEMCAP 104857600 #define MIN_SMTP_MEMCAP 3276 #define MAX_LOG_DEPTH 20480 #define MIN_LOG_DEPTH 1 #define SMTP_DEFAULT_SERVER_PORT 25 /* SMTP normally runs on port 25 */ #define SMTP_DEFAULT_SUBMISSION_PORT 587 /* SMTP Submission port - see RFC 2476 */ #define XLINK2STATE_DEFAULT_PORT 691 /* XLINK2STATE sometimes runs on port 691 */ #define ERRSTRLEN 512 typedef enum _SMTPCmdTypeEnum { SMTP_CMD_TYPE_NORMAL = 0, SMTP_CMD_TYPE_DATA, SMTP_CMD_TYPE_BDATA, SMTP_CMD_TYPE_AUTH, SMTP_CMD_TYPE_LAST } SMTPCmdTypeEnum; typedef struct _SMTPSearch { char *name; int name_len; } SMTPSearch; typedef struct _SMTPToken { char *name; int name_len; int search_id; SMTPCmdTypeEnum type; } SMTPToken; typedef struct _SMTPCmdConfig { char alert; /* 1 if alert when seen */ char normalize; /* 1 if we should normalize this command */ int max_line_len; /* Max length of this particular command */ } SMTPCmdConfig; typedef struct _SMTPConfig { char ports[8192]; char inspection_type; char normalize; char ignore_data; char ignore_tls_data; int max_command_line_len; int max_header_line_len; int max_response_line_len; char no_alerts; char alert_unknown_cmds; char alert_xlink2state; char drop_xlink2state; char print_cmds; char enable_mime_decoding; MAIL_LogConfig log_config; uint32_t memcap; int max_mime_mem; int max_mime_depth; int max_depth; int b64_depth; int qp_depth; int bitenc_depth; int uu_depth; int64_t file_depth; SMTPToken *cmds; SMTPCmdConfig *cmd_config; SMTPSearch *cmd_search; void *cmd_search_mpse; int num_cmds; int disabled; int ref_count; uint32_t xtra_filename_id; uint32_t xtra_mfrom_id; uint32_t xtra_rcptto_id; uint32_t xtra_ehdrs_id; } SMTPConfig; typedef struct _SMTP_Stats { uint64_t sessions; uint64_t conc_sessions; uint64_t max_conc_sessions; uint64_t memcap_exceeded; uint64_t attachments[DECODE_ALL]; uint64_t decoded_bytes[DECODE_ALL]; } SMTP_Stats; extern SMTP_Stats smtp_stats; /* Function prototypes */ void SMTP_ParseArgs(SMTPConfig *, char *); void SMTP_PrintConfig(SMTPConfig *config); void SMTP_CheckConfig(SMTPConfig *, tSfPolicyUserContextId); int SMTP_IsDecodingEnabled(SMTPConfig *pPolicyConfig); #endif snort-2.9.6.0/src/dynamic-preprocessors/smtp/smtp_config.c0000644000000000000000000013405412260565732020522 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /*************************************************************************** * smtp_config.c * * Author: Andy Mullican * Author: Todd Wease * * Description: * * Handle configuration of the SMTP preprocessor * * Entry point functions: * * SMTP_ParseArgs() * ***************************************************************************/ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_smtp.h" #include "smtp_config.h" #include "snort_bounds.h" #include "sf_dynamic_preprocessor.h" #include "sfPolicy.h" /* Global variable to hold configuration */ extern SMTPConfig **smtp_config; extern const SMTPToken smtp_known_cmds[]; /* Private functions */ static int ProcessPorts(SMTPConfig *, char *, int); static int ProcessCmds(SMTPConfig *, char *, int, int, SMTPCmdTypeEnum); static int GetCmdId(SMTPConfig *, char *, SMTPCmdTypeEnum); static int AddCmd(SMTPConfig *, char *, SMTPCmdTypeEnum); static int ProcessAltMaxCmdLen(SMTPConfig *, char *, int); static int ProcessMaxMimeDepth(SMTPConfig *, char *, int); static int ProcessLogDepth(SMTPConfig *, char *, int); static int ProcessXlink2State(SMTPConfig *, char *, int); static int ProcessDecodeDepth(SMTPConfig *, char *, int , char *, DecodeType ); /* * Function: SMTP_ParseArgs(char *) * * Purpose: Process the preprocessor arguments from the rules file and * initialize the preprocessor's data struct. This function doesn't * have to exist if it makes sense to parse the args in the init * function. * * Arguments: args => argument list * * Returns: void function * */ void SMTP_ParseArgs(SMTPConfig *config, char *args) { int ret = 0; char *arg; char *value; char errStr[ERRSTRLEN]; int errStrLen = ERRSTRLEN; int b64_option = 0; int deprecated_options = 0; if ((config == NULL) || (args == NULL)) return; config->ports[SMTP_DEFAULT_SERVER_PORT / 8] |= 1 << (SMTP_DEFAULT_SERVER_PORT % 8); config->ports[XLINK2STATE_DEFAULT_PORT / 8] |= 1 << (XLINK2STATE_DEFAULT_PORT % 8); config->ports[SMTP_DEFAULT_SUBMISSION_PORT / 8] |= 1 << (SMTP_DEFAULT_SUBMISSION_PORT % 8); config->inspection_type = SMTP_STATELESS; config->max_command_line_len = DEFAULT_MAX_COMMAND_LINE_LEN; config->max_header_line_len = DEFAULT_MAX_HEADER_LINE_LEN; config->max_response_line_len = DEFAULT_MAX_RESPONSE_LINE_LEN; config->max_mime_depth = DEFAULT_MAX_MIME_DEPTH; config->max_mime_mem = DEFAULT_MAX_MIME_MEM; config->memcap = DEFAULT_SMTP_MEMCAP; config->alert_xlink2state = 1; config->print_cmds = 1; config->enable_mime_decoding = 0; config->b64_depth = DEFAULT_MAX_MIME_DEPTH; config->qp_depth = DEFAULT_MAX_MIME_DEPTH; config->uu_depth = DEFAULT_MAX_MIME_DEPTH; config->bitenc_depth = DEFAULT_MAX_MIME_DEPTH; config->max_depth = MIN_DEPTH; config->log_config.log_filename = 0; config->log_config.log_mailfrom = 0; config->log_config.log_rcptto = 0; config->log_config.log_email_hdrs = 0; config->log_config.email_hdrs_log_depth = DEFAULT_LOG_DEPTH; config->cmd_config = (SMTPCmdConfig *)calloc(CMD_LAST, sizeof(SMTPCmdConfig)); if (config->cmd_config == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory for SMTP " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } *errStr = '\0'; arg = strtok(args, CONF_SEPARATORS); while ( arg != NULL ) { unsigned long val = 0; if ( !strcasecmp(CONF_PORTS, arg) ) { ret = ProcessPorts(config, errStr, errStrLen); } else if ( !strcasecmp(CONF_INSPECTION_TYPE, arg) ) { value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) { return; } if ( !strcasecmp(CONF_STATEFUL, value) ) { config->inspection_type = SMTP_STATEFUL; } else { config->inspection_type = SMTP_STATELESS; } } else if ( !strcasecmp(CONF_NORMALIZE, arg) ) { value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) { return; } if ( !strcasecmp(CONF_NONE, value) ) { config->normalize = NORMALIZE_NONE; } else if ( !strcasecmp(CONF_ALL, value) ) { config->normalize = NORMALIZE_ALL; } else { config->normalize = NORMALIZE_CMDS; } } else if ( !strcasecmp(CONF_IGNORE_DATA, arg) ) { config->ignore_data = 1; } else if ( !strcasecmp(CONF_IGNORE_TLS_DATA, arg) ) { config->ignore_tls_data = 1; } else if ( !strcasecmp(CONF_MAX_COMMAND_LINE_LEN, arg) ) { char *endptr; value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) return; config->max_command_line_len = strtol(value, &endptr, 10); } else if ( !strcasecmp(CONF_MAX_HEADER_LINE_LEN, arg) ) { char *endptr; value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) return; config->max_header_line_len = strtol(value, &endptr, 10); } else if ( !strcasecmp(CONF_MAX_RESPONSE_LINE_LEN, arg) ) { char *endptr; value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) return; config->max_response_line_len = strtol(value, &endptr, 10); } else if ( !strcasecmp(CONF_NO_ALERTS, arg) ) { config->no_alerts = 1; } else if ( !strcasecmp(CONF_ALERT_UNKNOWN_CMDS, arg) ) { config->alert_unknown_cmds = 1; } else if ( !strcasecmp(CONF_INVALID_CMDS, arg) ) { /* Parse disallowed commands */ ret = ProcessCmds(config, errStr, errStrLen, ACTION_ALERT, SMTP_CMD_TYPE_NORMAL); } else if ( !strcasecmp(CONF_VALID_CMDS, arg) ) { /* Parse allowed commands */ ret = ProcessCmds(config, errStr, errStrLen, ACTION_NO_ALERT, SMTP_CMD_TYPE_NORMAL); } else if ( !strcasecmp(CONF_AUTH_CMDS, arg) ) { ret = ProcessCmds(config, errStr, errStrLen, ACTION_NO_ALERT, SMTP_CMD_TYPE_AUTH); } else if ( !strcasecmp(CONF_DATA_CMDS, arg) ) { ret = ProcessCmds(config, errStr, errStrLen, ACTION_NO_ALERT, SMTP_CMD_TYPE_DATA); } else if ( !strcasecmp(CONF_BDATA_CMDS, arg) ) { ret = ProcessCmds(config, errStr, errStrLen, ACTION_NO_ALERT, SMTP_CMD_TYPE_BDATA); } else if ( !strcasecmp(CONF_NORMALIZE_CMDS, arg) ) { /* Parse normalized commands */ ret = ProcessCmds(config, errStr, errStrLen, ACTION_NORMALIZE, SMTP_CMD_TYPE_NORMAL); } else if ( !strcasecmp(CONF_ALT_MAX_COMMAND_LINE_LEN, arg) ) { /* Parse max line len for commands */ ret = ProcessAltMaxCmdLen(config, errStr, errStrLen); } else if ( !strcasecmp(CONF_SMTP_MEMCAP, arg) ) { ret = _dpd.checkValueInRange(strtok(NULL, CONF_SEPARATORS), CONF_SMTP_MEMCAP, MIN_SMTP_MEMCAP, MAX_SMTP_MEMCAP, &val); config->memcap = (uint32_t)val; } else if ( !strcasecmp(CONF_MAX_MIME_MEM, arg) ) { ret = _dpd.checkValueInRange(strtok(NULL, CONF_SEPARATORS), CONF_MAX_MIME_MEM, MIN_MIME_MEM, MAX_MIME_MEM, &val); config->max_mime_mem = (int)val; } else if ( !strcasecmp(CONF_MAX_MIME_DEPTH, arg) ) { deprecated_options = 1; _dpd.logMsg("WARNING: %s(%d) => The SMTP config option 'max_mime_depth' is deprecated.\n", *(_dpd.config_file), *(_dpd.config_line)); if(!b64_option) ret = ProcessMaxMimeDepth(config, errStr, errStrLen); } else if ( !strcasecmp(CONF_ENABLE_MIME_DECODING, arg) ) { deprecated_options = 1; _dpd.logMsg("WARNING: %s(%d) => The SMTP config option 'enable_mime_decoding' is deprecated.\n", *(_dpd.config_file), *(_dpd.config_line)); if(!b64_option) config->enable_mime_decoding = 1; } else if ( !strcasecmp(CONF_DISABLED, arg) ) { config->disabled = 1; } else if ( !strcasecmp(CONF_XLINK2STATE, arg) ) { ret = ProcessXlink2State(config, errStr, errStrLen); } else if ( !strcasecmp(CONF_LOG_FILENAME, arg) ) { config->log_config.log_filename = 1; } else if ( !strcasecmp(CONF_LOG_MAIL_FROM, arg) ) { config->log_config.log_mailfrom = 1; } else if ( !strcasecmp(CONF_LOG_RCPT_TO, arg) ) { config->log_config.log_rcptto = 1; } else if ( !strcasecmp(CONF_LOG_EMAIL_HDRS, arg) ) { config->log_config.log_email_hdrs = 1; } else if ( !strcasecmp(CONF_EMAIL_HDRS_LOG_DEPTH, arg) ) { ret = ProcessLogDepth(config, errStr, errStrLen); } else if ( !strcasecmp(CONF_PRINT_CMDS, arg) ) { config->print_cmds = 1; } else if ( !strcasecmp(CONF_B64_DECODE, arg) ) { b64_option = 1; ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_B64_DECODE, DECODE_B64); } else if ( !strcasecmp(CONF_QP_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_QP_DECODE, DECODE_QP); } else if ( !strcasecmp(CONF_UU_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_UU_DECODE, DECODE_UU); } else if ( !strcasecmp(CONF_BITENC_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_BITENC_DECODE, DECODE_BITENC); } else { DynamicPreprocessorFatalMessage("%s(%d) => Unknown SMTP configuration option %s\n", *(_dpd.config_file), *(_dpd.config_line), arg); } if (ret == -1) { /* ** Fatal Error, log error and exit. */ if (*errStr) { DynamicPreprocessorFatalMessage("%s(%d) => %s\n", *(_dpd.config_file), *(_dpd.config_line), errStr); } else { DynamicPreprocessorFatalMessage("%s(%d) => Undefined Error.\n", *(_dpd.config_file), *(_dpd.config_line)); } } /* Get next token */ arg = strtok(NULL, CONF_SEPARATORS); } if(!b64_option) { if(config->enable_mime_decoding) config->b64_depth = config->max_mime_depth; } else if(deprecated_options) { DynamicPreprocessorFatalMessage("%s(%d) => Cannot specify 'enable_mime_decoding' or 'max_mime_depth' with " "'b64_decode_depth'\n", *(_dpd.config_file), *(_dpd.config_line), arg); } if(!config->log_config.email_hdrs_log_depth) { if(config->log_config.log_email_hdrs) { _dpd.logMsg("WARNING: %s(%d) => 'log_email_hdrs' enabled with 'email_hdrs_log_depth' = 0." "Email headers won't be logged. Please set 'email_hdrs_log_depth' > 0 to enable logging.\n", *(_dpd.config_file), *(_dpd.config_line)); } config->log_config.log_email_hdrs = 0; } } int SMTP_IsDecodingEnabled(SMTPConfig *pPolicyConfig) { if( (pPolicyConfig->b64_depth > -1) || (pPolicyConfig->qp_depth > -1) || (pPolicyConfig->uu_depth > -1) || (pPolicyConfig->bitenc_depth > -1) ||(pPolicyConfig->file_depth > -1)) { return 0; } else return -1; } void SMTP_CheckConfig(SMTPConfig *pPolicyConfig, tSfPolicyUserContextId context) { int max = -1; SMTPConfig *defaultConfig = (SMTPConfig *)sfPolicyUserDataGetDefault(context); if (pPolicyConfig == defaultConfig) { if (!pPolicyConfig->max_mime_mem) pPolicyConfig->max_mime_mem = DEFAULT_MAX_MIME_MEM; if(!pPolicyConfig->b64_depth || !pPolicyConfig->qp_depth || !pPolicyConfig->uu_depth || !pPolicyConfig->bitenc_depth) { pPolicyConfig->max_depth = MAX_DEPTH; return; } else { if(max < pPolicyConfig->b64_depth) max = pPolicyConfig->b64_depth; if(max < pPolicyConfig->qp_depth) max = pPolicyConfig->qp_depth; if(max < pPolicyConfig->bitenc_depth) max = pPolicyConfig->bitenc_depth; if(max < pPolicyConfig->uu_depth) max = pPolicyConfig->uu_depth; pPolicyConfig->max_depth = max; } if (!pPolicyConfig->memcap) pPolicyConfig->memcap = DEFAULT_SMTP_MEMCAP; if(pPolicyConfig->disabled && !pPolicyConfig->log_config.email_hdrs_log_depth) pPolicyConfig->log_config.email_hdrs_log_depth = DEFAULT_LOG_DEPTH; } else if (defaultConfig == NULL) { if (pPolicyConfig->max_mime_mem) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: max_mime_mem must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->b64_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: b64_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->qp_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: qp_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->uu_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: uu_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->bitenc_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: bitenc_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->memcap) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: memcap must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if(pPolicyConfig->log_config.log_email_hdrs && pPolicyConfig->log_config.email_hdrs_log_depth) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: email_hdrs_log_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } } else { pPolicyConfig->max_mime_mem = defaultConfig->max_mime_mem; pPolicyConfig->max_depth = defaultConfig->max_depth; pPolicyConfig->memcap = defaultConfig->memcap; pPolicyConfig->log_config.email_hdrs_log_depth = defaultConfig->log_config.email_hdrs_log_depth; if(pPolicyConfig->disabled) { pPolicyConfig->b64_depth = defaultConfig->b64_depth; pPolicyConfig->qp_depth = defaultConfig->qp_depth; pPolicyConfig->uu_depth = defaultConfig->uu_depth; pPolicyConfig->bitenc_depth = defaultConfig->bitenc_depth; return; } if(!pPolicyConfig->b64_depth && defaultConfig->b64_depth) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: Cannot enable unlimited Base64 decoding" " in non-default config without turning on unlimited Base64 decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->b64_depth && (pPolicyConfig->b64_depth > defaultConfig->b64_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: b64_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->b64_depth, defaultConfig->b64_depth); } if(!pPolicyConfig->qp_depth && defaultConfig->qp_depth) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: Cannot enable unlimited Quoted-Printable decoding" " in non-default config without turning on unlimited Quoted-Printable decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->qp_depth && (pPolicyConfig->qp_depth > defaultConfig->qp_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: qp_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->qp_depth, defaultConfig->qp_depth); } if(!pPolicyConfig->uu_depth && defaultConfig->uu_depth ) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: Cannot enable unlimited Unix-to-Unix decoding" " in non-default config without turning on unlimited Unix-to-Unix decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->uu_depth && (pPolicyConfig->uu_depth > defaultConfig->uu_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: uu_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->uu_depth, defaultConfig->uu_depth); } if(!pPolicyConfig->bitenc_depth && defaultConfig->bitenc_depth) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: Cannot enable unlimited Non-Encoded MIME attachment extraction" " in non-default config without turning on unlimited Non-Encoded MIME attachment extraction in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->bitenc_depth && (pPolicyConfig->bitenc_depth > defaultConfig->bitenc_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => SMTP: bitenc_decode_depth value %d in non-default config " " cannot exceed default config's value.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->bitenc_depth, defaultConfig->bitenc_depth); } } } void SMTP_PrintConfig(SMTPConfig *config) { int i; const SMTPToken *cmd; char buf[8192]; if (config == NULL) return; memset(&buf[0], 0, sizeof(buf)); _dpd.logMsg("SMTP Config:\n"); if(config->disabled) { _dpd.logMsg(" SMTP: INACTIVE\n"); } snprintf(buf, sizeof(buf) - 1, " Ports: "); for (i = 0; i < 65536; i++) { if (config->ports[i / 8] & (1 << (i % 8))) { _dpd.printfappend(buf, sizeof(buf) - 1, "%d ", i); } } _dpd.logMsg("%s\n", buf); _dpd.logMsg(" Inspection Type: %s\n", config->inspection_type ? "Stateful" : "Stateless"); snprintf(buf, sizeof(buf) - 1, " Normalize: "); switch (config->normalize) { case NORMALIZE_ALL: _dpd.printfappend(buf, sizeof(buf) - 1, "all"); break; case NORMALIZE_NONE: _dpd.printfappend(buf, sizeof(buf) - 1, "none"); break; case NORMALIZE_CMDS: if (config->print_cmds) { for (cmd = config->cmds; cmd->name != NULL; cmd++) { if (config->cmd_config[cmd->search_id].normalize) { _dpd.printfappend(buf, sizeof(buf) - 1, "%s ", cmd->name); } } } else { _dpd.printfappend(buf, sizeof(buf) - 1, "cmds"); } break; } _dpd.logMsg("%s\n", buf); _dpd.logMsg(" Ignore Data: %s\n", config->ignore_data ? "Yes" : "No"); _dpd.logMsg(" Ignore TLS Data: %s\n", config->ignore_tls_data ? "Yes" : "No"); _dpd.logMsg(" Ignore SMTP Alerts: %s\n", config->no_alerts ? "Yes" : "No"); if (!config->no_alerts) { snprintf(buf, sizeof(buf) - 1, " Max Command Line Length: "); if (config->max_command_line_len == 0) _dpd.printfappend(buf, sizeof(buf) - 1, "Unlimited"); else _dpd.printfappend(buf, sizeof(buf) - 1, "%d", config->max_command_line_len); _dpd.logMsg("%s\n", buf); if (config->print_cmds) { int max_line_len_count = 0; int max_line_len = 0; snprintf(buf, sizeof(buf) - 1, " Max Specific Command Line Length: "); for (cmd = config->cmds; cmd->name != NULL; cmd++) { max_line_len = config->cmd_config[cmd->search_id].max_line_len; if (max_line_len != 0) { if (max_line_len_count % 5 == 0) { _dpd.logMsg("%s\n", buf); snprintf(buf, sizeof(buf) - 1, " %s:%d ", cmd->name, max_line_len); } else { _dpd.printfappend(buf, sizeof(buf) - 1, "%s:%d ", cmd->name, max_line_len); } max_line_len_count++; } } if (max_line_len_count == 0) _dpd.logMsg("%sNone\n", buf); else _dpd.logMsg("%s\n", buf); } snprintf(buf, sizeof(buf) - 1, " Max Header Line Length: "); if (config->max_header_line_len == 0) _dpd.logMsg("%sUnlimited\n", buf); else _dpd.logMsg("%s%d\n", buf, config->max_header_line_len); snprintf(buf, sizeof(buf) - 1, " Max Response Line Length: "); if (config->max_response_line_len == 0) _dpd.logMsg("%sUnlimited\n", buf); else _dpd.logMsg("%s%d\n", buf, config->max_response_line_len); } _dpd.logMsg(" X-Link2State Alert: %s\n", config->alert_xlink2state ? "Yes" : "No"); if (config->alert_xlink2state) { _dpd.logMsg(" Drop on X-Link2State Alert: %s\n", config->drop_xlink2state ? "Yes" : "No"); } if (config->print_cmds && !config->no_alerts) { int alert_count = 0; snprintf(buf, sizeof(buf) - 1, " Alert on commands: "); for (cmd = config->cmds; cmd->name != NULL; cmd++) { if (config->cmd_config[cmd->search_id].alert) { _dpd.printfappend(buf, sizeof(buf) - 1, "%s ", cmd->name); alert_count++; } } if (alert_count == 0) { _dpd.logMsg("%sNone\n", buf); } else { _dpd.logMsg("%s\n", buf); } } _dpd.logMsg(" Alert on unknown commands: %s\n", config->alert_unknown_cmds ? "Yes" : "No"); _dpd.logMsg(" SMTP Memcap: %u\n", config->memcap); _dpd.logMsg(" MIME Max Mem: %d\n", config->max_mime_mem); if(config->b64_depth > -1) { _dpd.logMsg(" Base64 Decoding: %s\n", "Enabled"); switch(config->b64_depth) { case 0: _dpd.logMsg(" Base64 Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Base64 Decoding Depth: %d\n", config->b64_depth); break; } } else _dpd.logMsg(" Base64 Decoding: %s\n", "Disabled"); if(config->qp_depth > -1) { _dpd.logMsg(" Quoted-Printable Decoding: %s\n","Enabled"); switch(config->qp_depth) { case 0: _dpd.logMsg(" Quoted-Printable Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Quoted-Printable Decoding Depth: %d\n", config->qp_depth); break; } } else _dpd.logMsg(" Quoted-Printable Decoding: %s\n", "Disabled"); if(config->uu_depth > -1) { _dpd.logMsg(" Unix-to-Unix Decoding: %s\n","Enabled"); switch(config->uu_depth) { case 0: _dpd.logMsg(" Unix-to-Unix Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Unix-to-Unix Decoding Depth: %d\n", config->uu_depth); break; } } else _dpd.logMsg(" Unix-to-Unix Decoding: %s\n", "Disabled"); if(config->bitenc_depth > -1) { _dpd.logMsg(" Non-Encoded MIME attachment Extraction: %s\n","Enabled"); switch(config->bitenc_depth) { case 0: _dpd.logMsg(" Non-Encoded MIME attachment Extraction Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Non-Encoded MIME attachment Extraction Depth: %d\n", config->bitenc_depth); break; } } else _dpd.logMsg(" Non-Encoded MIME attachment Extraction/text: %s\n", "Disabled"); _dpd.logMsg(" Log Attachment filename: %s\n", config->log_config.log_filename ? "Enabled" : "Not Enabled"); _dpd.logMsg(" Log MAIL FROM Address: %s\n", config->log_config.log_mailfrom ? "Enabled" : "Not Enabled"); _dpd.logMsg(" Log RCPT TO Addresses: %s\n", config->log_config.log_rcptto ? "Enabled" : "Not Enabled"); _dpd.logMsg(" Log Email Headers: %s\n", config->log_config.log_email_hdrs ? "Enabled" : "Not Enabled"); if(config->log_config.log_email_hdrs) { _dpd.logMsg(" Email Hdrs Log Depth: %u\n", config->log_config.email_hdrs_log_depth); } } /* ** NAME ** ProcessPorts:: */ /** ** Process the port list. ** ** This configuration is a list of valid ports and is ended by a ** delimiter. ** ** @param ErrorString error string buffer ** @param ErrStrLen the length of the error string buffer ** ** @return an error code integer ** (0 = success, >0 = non-fatal error, <0 = fatal error) ** ** @retval 0 successs ** @retval -1 generic fatal error ** @retval 1 generic non-fatal error */ static int ProcessPorts(SMTPConfig *config, char *ErrorString, int ErrStrLen) { char *pcToken; char *pcEnd; int iPort; int iEndPorts = 0; int num_ports = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "SMTP config is NULL.\n"); return -1; } pcToken = strtok(NULL, CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid port list format."); return -1; } if(strcmp(CONF_START_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a port list with the '%s' token.", CONF_START_LIST); return -1; } /* Since ports are specified, clear default ports */ config->ports[SMTP_DEFAULT_SERVER_PORT / 8] &= ~(1 << (SMTP_DEFAULT_SERVER_PORT % 8)); config->ports[XLINK2STATE_DEFAULT_PORT / 8] &= ~(1 << (XLINK2STATE_DEFAULT_PORT % 8)); config->ports[SMTP_DEFAULT_SUBMISSION_PORT / 8] &= ~(1 << (SMTP_DEFAULT_SUBMISSION_PORT % 8)); while ((pcToken = strtok(NULL, CONF_SEPARATORS)) != NULL) { if(!strcmp(CONF_END_LIST, pcToken)) { iEndPorts = 1; break; } iPort = strtol(pcToken, &pcEnd, 10); /* ** Validity check for port */ if(*pcEnd) { snprintf(ErrorString, ErrStrLen, "Invalid port number."); return -1; } if(iPort < 0 || iPort > MAXPORTS-1) { snprintf(ErrorString, ErrStrLen, "Invalid port number. Must be between 0 and 65535."); return -1; } config->ports[iPort / 8] |= (1 << (iPort % 8)); num_ports++; } if(!iEndPorts) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", CONF_PORTS, CONF_END_LIST); return -1; } else if(!num_ports) { snprintf(ErrorString, ErrStrLen, "SMTP: Empty port list not allowed."); return -1; } return 0; } /* ** NAME ** ProcessCmds:: */ /** ** Process the command list. ** ** This configuration is a list of valid ports and is ended by a ** delimiter. ** ** @param ErrorString error string buffer ** @param ErrStrLen the length of the error string buffer ** ** @return an error code integer ** (0 = success, >0 = non-fatal error, <0 = fatal error) ** ** @retval 0 successs ** @retval -1 generic fatal error */ static int ProcessCmds(SMTPConfig *config, char *ErrorString, int ErrStrLen, int action, SMTPCmdTypeEnum type) { char *pcToken; int iEndCmds = 0; int id; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "SMTP config is NULL.\n"); return -1; } pcToken = strtok(NULL, CONF_SEPARATORS); if (!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid command list format."); return -1; } if (strcmp(CONF_START_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a command list with the '%s' token.", CONF_START_LIST); return -1; } while ((pcToken = strtok(NULL, CONF_SEPARATORS)) != NULL) { if (strcmp(CONF_END_LIST, pcToken) == 0) { iEndCmds = 1; break; } id = GetCmdId(config, pcToken, type); if (action == ACTION_ALERT) { config->cmd_config[id].alert = 1; } else if (action == ACTION_NO_ALERT) { config->cmd_config[id].alert = 0; } else if (action == ACTION_NORMALIZE) { config->cmd_config[id].normalize = 1; } } if (!iEndCmds) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", action == ACTION_ALERT ? CONF_INVALID_CMDS : (action == ACTION_NO_ALERT ? CONF_VALID_CMDS : (action == ACTION_NORMALIZE ? CONF_NORMALIZE_CMDS : "")), CONF_END_LIST); return -1; } return 0; } /* Return id associated with a given command string */ static int GetCmdId(SMTPConfig *config, char *name, SMTPCmdTypeEnum type) { SMTPToken *cmd; for (cmd = config->cmds; cmd->name != NULL; cmd++) { if (strcasecmp(cmd->name, name) == 0) { if (type && (type != cmd->type)) cmd->type = type; return cmd->search_id; } } return AddCmd(config, name, type); } static int AddCmd(SMTPConfig *config, char *name, SMTPCmdTypeEnum type) { SMTPToken *cmds, *tmp_cmds; SMTPSearch *cmd_search; SMTPCmdConfig *cmd_config; int ret; if (config == NULL) { DynamicPreprocessorFatalMessage("%s(%d) SMTP config is NULL.\n", __FILE__, __LINE__); } config->num_cmds++; /* allocate enough memory for new commmand - alloc one extra for NULL entry */ cmds = (SMTPToken *)calloc(config->num_cmds + 1, sizeof(SMTPToken)); if (cmds == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory for SMTP " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } /* This gets filled in later */ cmd_search = (SMTPSearch *)calloc(config->num_cmds, sizeof(SMTPSearch)); if (cmd_search == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory for SMTP " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } cmd_config = (SMTPCmdConfig *)calloc(config->num_cmds, sizeof(SMTPCmdConfig)); if (cmd_config == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory for SMTP " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } /* copy existing commands into newly allocated memory * don't need to copy anything from cmd_search since this hasn't been initialized yet */ ret = SafeMemcpy(cmds, config->cmds, (config->num_cmds - 1) * sizeof(SMTPToken), cmds, cmds + (config->num_cmds - 1)); if (ret != SAFEMEM_SUCCESS) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to memory copy SMTP command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } ret = SafeMemcpy(cmd_config, config->cmd_config, (config->num_cmds - 1) * sizeof(SMTPCmdConfig), cmd_config, cmd_config + (config->num_cmds - 1)); if (ret != SAFEMEM_SUCCESS) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to memory copy SMTP command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } /* add new command to cmds * cmd_config doesn't need anything added - this will probably be done by a calling function * cmd_search will be initialized when the searches are initialized */ tmp_cmds = &cmds[config->num_cmds - 1]; tmp_cmds->name = strdup(name); tmp_cmds->name_len = strlen(name); tmp_cmds->search_id = config->num_cmds - 1; if (type) tmp_cmds->type = type; if (tmp_cmds->name == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory for SMTP " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } /* free global memory structures */ if (config->cmds != NULL) free(config->cmds); if (config->cmd_search != NULL) free(config->cmd_search); if (config->cmd_config != NULL) free(config->cmd_config); /* set globals to new memory */ config->cmds = cmds; config->cmd_search = cmd_search; config->cmd_config = cmd_config; return (config->num_cmds - 1); } static int ProcessMaxMimeDepth(SMTPConfig *config, char *ErrorString, int ErrStrLen) { char *endptr; char *value; int max_mime_depth = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "SMTP config is NULL.\n"); return -1; } value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) { snprintf(ErrorString, ErrStrLen, "Invalid format for max_mime_depth."); return -1; } max_mime_depth = strtol(value, &endptr, 10); if(*endptr) { snprintf(ErrorString, ErrStrLen, "Invalid format for max_mime_depth."); return -1; } if (max_mime_depth < MIN_MIME_DEPTH || max_mime_depth > MAX_MIME_DEPTH) { snprintf(ErrorString, ErrStrLen, "Invalid value for max_mime_depth." "It should range between %d and %d.", MIN_MIME_DEPTH, MAX_MIME_DEPTH); return -1; } if(max_mime_depth & 3) { max_mime_depth += 4 - (max_mime_depth & 3); _dpd.logMsg("WARNING: %s(%d) => SMTP: 'max_mime_depth' is not a multiple of 4. " "Rounding up to the next multiple of 4. The new 'max_mime_depth' is %d.\n", *(_dpd.config_file), *(_dpd.config_line), max_mime_depth); } config->max_mime_depth = max_mime_depth; return 0; } static int ProcessLogDepth(SMTPConfig *config, char *ErrorString, int ErrStrLen) { char *endptr; char *value; uint32_t log_depth = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "SMTP config is NULL.\n"); return -1; } value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) { snprintf(ErrorString, ErrStrLen, "Missing value for email_hdrs_log_depth."); return -1; } log_depth = strtoul(value, &endptr, 10); if((value[0] == '-') || (*endptr != '\0')) { snprintf(ErrorString, ErrStrLen, "Invalid format '%s' for email_hdrs_log_depth.", value); return -1; } if(log_depth && log_depth < MIN_LOG_DEPTH) { snprintf(ErrorString, ErrStrLen, "Invalid value for email_hdrs_log_depth." "It should range between %d and %d.", MIN_LOG_DEPTH, MAX_LOG_DEPTH); return -1; } else if (log_depth > MAX_LOG_DEPTH) { _dpd.logMsg("WARNING: %s(%d) => Invalid value for email_hdrs_log_depth. " "It should range between %d and %d. The email_hdrs_log_depth " "will be reduced to the max value.\n", *(_dpd.config_file), *(_dpd.config_line), MIN_LOG_DEPTH, MAX_LOG_DEPTH); log_depth = MAX_LOG_DEPTH; } /* Rounding the log depth to a multiple of 8 since * multiple sessions use the same mempool * * Moved from spp_smtp.c */ if (log_depth & 7) log_depth += (8 - (log_depth & 7)); config->log_config.email_hdrs_log_depth = log_depth; return 0; } static int ProcessDecodeDepth(SMTPConfig *config, char *ErrorString, int ErrStrLen, char *decode_type, DecodeType type) { char *endptr; char *value; int decode_depth = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "SMTP config is NULL.\n"); return -1; } value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) { snprintf(ErrorString, ErrStrLen, "Invalid format for SMTP config option '%s'.", decode_type); return -1; } decode_depth = strtol(value, &endptr, 10); if(*endptr) { snprintf(ErrorString, ErrStrLen, "Invalid format for SMTP config option '%s'.", decode_type); return -1; } if(decode_depth < MIN_DEPTH || decode_depth > MAX_DEPTH) { snprintf(ErrorString, ErrStrLen, "Invalid value for SMTP config option '%s'." "It should range between %d and %d.", decode_type, MIN_DEPTH, MAX_DEPTH); return -1; } switch(type) { case DECODE_B64: if((decode_depth > 0) && (decode_depth & 3)) { decode_depth += 4 - (decode_depth & 3); if(decode_depth > MAX_DEPTH ) { decode_depth = decode_depth - 4; } _dpd.logMsg("WARNING: %s(%d) => SMTP: 'b64_decode_depth' is not a multiple of 4. " "Rounding up to the next multiple of 4. The new 'b64_decode_depth' is %d.\n", *(_dpd.config_file), *(_dpd.config_line), decode_depth); } config->b64_depth = decode_depth; break; case DECODE_QP: config->qp_depth = decode_depth; break; case DECODE_UU: config->uu_depth = decode_depth; break; case DECODE_BITENC: config->bitenc_depth = decode_depth; break; default: return -1; } return 0; } /* ** NAME ** ProcessAltMaxCmdLen:: */ /** ** ** alt_max_command_line_len { [] } ** ** @param ErrorString error string buffer ** @param ErrStrLen the length of the error string buffer ** ** @return an error code integer ** (0 = success, >0 = non-fatal error, <0 = fatal error) ** ** @retval 0 successs ** @retval -1 generic fatal error */ static int ProcessAltMaxCmdLen(SMTPConfig *config, char *ErrorString, int ErrStrLen) { char *pcToken; char *pcLen; char *pcLenEnd; int iEndCmds = 0; int id; int cmd_len; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "SMTP config is NULL.\n"); return -1; } /* Find number */ pcLen = strtok(NULL, CONF_SEPARATORS); if (!pcLen) { snprintf(ErrorString, ErrStrLen, "Invalid format for alt_max_command_line_len."); return -1; } pcToken = strtok(NULL, CONF_SEPARATORS); if (!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid format for alt_max_command_line_len."); return -1; } cmd_len = strtoul(pcLen, &pcLenEnd, 10); if (pcLenEnd == pcLen) { snprintf(ErrorString, ErrStrLen, "Invalid format for alt_max_command_line_len (non-numeric)."); return -1; } if (strcmp(CONF_START_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start alt_max_command_line_len list with the '%s' token.", CONF_START_LIST); return -1; } while ((pcToken = strtok(NULL, CONF_SEPARATORS)) != NULL) { if (strcmp(CONF_END_LIST, pcToken) == 0) { iEndCmds = 1; break; } id = GetCmdId(config, pcToken, SMTP_CMD_TYPE_NORMAL); config->cmd_config[id].max_line_len = cmd_len; } if (!iEndCmds) { snprintf(ErrorString, ErrStrLen, "Must end alt_max_command_line_len configuration with '%s'.", CONF_END_LIST); return -1; } return 0; } /* ** NAME ** ProcessXlink2State:: */ /** ** ** xlink2state { } ** ** @param ErrorString error string buffer ** @param ErrStrLen the length of the error string buffer ** ** @return an error code integer ** (0 = success, >0 = non-fatal error, <0 = fatal error) ** ** @retval 0 successs ** @retval -1 generic fatal error */ static int ProcessXlink2State(SMTPConfig *config, char *ErrorString, int ErrStrLen) { char *pcToken; int iEnd = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "SMTP config is NULL.\n"); return -1; } pcToken = strtok(NULL, CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid xlink2state argument format."); return -1; } if(strcmp(CONF_START_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start xlink2state arguments with the '%s' token.", CONF_START_LIST); return -1; } while ((pcToken = strtok(NULL, CONF_SEPARATORS)) != NULL) { if(!strcmp(CONF_END_LIST, pcToken)) { iEnd = 1; break; } if ( !strcasecmp(CONF_DISABLE, pcToken) ) { config->alert_xlink2state = 0; config->ports[XLINK2STATE_DEFAULT_PORT / 8] &= ~(1 << (XLINK2STATE_DEFAULT_PORT % 8)); } else if ( !strcasecmp(CONF_ENABLE, pcToken) ) { config->alert_xlink2state = 1; config->ports[XLINK2STATE_DEFAULT_PORT / 8] |= 1 << (XLINK2STATE_DEFAULT_PORT % 8); } else if ( !strcasecmp(CONF_INLINE_DROP, pcToken) ) { if (!config->alert_xlink2state) { snprintf(ErrorString, ErrStrLen, "Alerting on X-LINK2STATE must be enabled to drop."); return -1; } config->drop_xlink2state = 1; } } if(!iEnd) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", CONF_XLINK2STATE, CONF_END_LIST); return -1; } return 0; } snort-2.9.6.0/src/dynamic-preprocessors/smtp/Makefile.am0000644000000000000000000000206211746560364020077 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_smtp_preproc.la libsf_smtp_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_smtp_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_smtp_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/mempool.c \ ../include/sf_sdlist.c \ ../include/sf_base64decode.c \ ../include/util_unfold.c \ ../include/sf_email_attach_decode.c \ ../include/sfPolicyUserData.c endif libsf_smtp_preproc_la_SOURCES = \ smtp_config.c \ smtp_config.h \ smtp_log.c \ smtp_log.h \ smtp_normalize.c \ smtp_normalize.h \ smtp_util.c \ smtp_util.h \ smtp_xlink2state.c \ smtp_xlink2state.h \ snort_smtp.c \ snort_smtp.h \ spp_smtp.c \ spp_smtp.h \ ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c \ ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.h EXTRA_DIST = \ sf_smtp.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/smtp/Makefile.in0000644000000000000000000005626512260606523020114 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/smtp DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_smtp_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_smtp_preproc_la_OBJECTS = smtp_config.lo smtp_log.lo \ smtp_normalize.lo smtp_util.lo smtp_xlink2state.lo \ snort_smtp.lo spp_smtp.lo ssl.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_smtp_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo mempool.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_sdlist.lo sf_base64decode.lo \ @SO_WITH_STATIC_LIB_FALSE@ util_unfold.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_email_attach_decode.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_smtp_preproc_la_OBJECTS = $(am_libsf_smtp_preproc_la_OBJECTS) \ $(nodist_libsf_smtp_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_smtp_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_smtp_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_smtp_preproc_la_SOURCES) \ $(nodist_libsf_smtp_preproc_la_SOURCES) DIST_SOURCES = $(libsf_smtp_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_smtp_preproc.la libsf_smtp_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_smtp_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_smtp_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/mempool.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_sdlist.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_base64decode.c \ @SO_WITH_STATIC_LIB_FALSE@../include/util_unfold.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_email_attach_decode.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_smtp_preproc_la_SOURCES = \ smtp_config.c \ smtp_config.h \ smtp_log.c \ smtp_log.h \ smtp_normalize.c \ smtp_normalize.h \ smtp_util.c \ smtp_util.h \ smtp_xlink2state.c \ smtp_xlink2state.h \ snort_smtp.c \ snort_smtp.h \ spp_smtp.c \ spp_smtp.h \ ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c \ ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.h EXTRA_DIST = \ sf_smtp.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/smtp/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/smtp/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_smtp_preproc.la: $(libsf_smtp_preproc_la_OBJECTS) $(libsf_smtp_preproc_la_DEPENDENCIES) $(EXTRA_libsf_smtp_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_smtp_preproc_la_LINK) -rpath $(libdir) $(libsf_smtp_preproc_la_OBJECTS) $(libsf_smtp_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< ssl.lo: ${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ssl.lo `test -f '${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c' || echo '$(srcdir)/'`${top_srcdir}/src/dynamic-preprocessors/libs/ssl.c sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c mempool.lo: ../include/mempool.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mempool.lo `test -f '../include/mempool.c' || echo '$(srcdir)/'`../include/mempool.c sf_sdlist.lo: ../include/sf_sdlist.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_sdlist.lo `test -f '../include/sf_sdlist.c' || echo '$(srcdir)/'`../include/sf_sdlist.c sf_base64decode.lo: ../include/sf_base64decode.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_base64decode.lo `test -f '../include/sf_base64decode.c' || echo '$(srcdir)/'`../include/sf_base64decode.c util_unfold.lo: ../include/util_unfold.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util_unfold.lo `test -f '../include/util_unfold.c' || echo '$(srcdir)/'`../include/util_unfold.c sf_email_attach_decode.lo: ../include/sf_email_attach_decode.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_email_attach_decode.lo `test -f '../include/sf_email_attach_decode.c' || echo '$(srcdir)/'`../include/sf_email_attach_decode.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/imap/0000755000000000000000000000000012260606563016060 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/imap/sf_imap.dsp0000644000000000000000000001424012153454770020131 00000000000000# Microsoft Developer Studio Project File - Name="sf_imap" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_imap - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_imap.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_imap.mak" CFG="sf_imap - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_imap - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_imap - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_imap - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_IMAP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 pcre.lib ws2_32.lib ../libs/Release/sfdynamic_preproc_libs.lib /nologo /dll /machine:I386 /libpath:"../../../src/win32/WIN32-Libraries" !ELSEIF "$(CFG)" == "sf_imap - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_IMAP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 pcre.lib ws2_32.lib ../libs/Debug/sfdynamic_preproc_libs.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../src/win32/WIN32-Libraries" !ENDIF # Begin Target # Name "sf_imap - Win32 Release" # Name "sf_imap - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\imap_config.c # End Source File # Begin Source File SOURCE=.\imap_log.c # End Source File # Begin Source File SOURCE=.\imap_util.c # End Source File # Begin Source File SOURCE=..\include\mempool.c # End Source File # Begin Source File SOURCE=..\include\sf_base64decode.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_email_attach_decode.c # End Source File # Begin Source File SOURCE=..\include\sf_sdlist.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\snort_imap.c # End Source File # Begin Source File SOURCE=.\spp_imap.c # End Source File # Begin Source File SOURCE=..\include\util_unfold.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\imap_config.h # End Source File # Begin Source File SOURCE=.\imap_log.h # End Source File # Begin Source File SOURCE=.\imap_util.h # End Source File # Begin Source File SOURCE=..\include\mempool.h # End Source File # Begin Source File SOURCE=..\include\sf_email_attach_decode.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=..\include\sf_sdlist.h # End Source File # Begin Source File SOURCE=.\snort_imap.h # End Source File # Begin Source File SOURCE=.\spp_imap.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/imap/spp_imap.h0000644000000000000000000000222612260565732017765 00000000000000 /* * spp_imap.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Bhagyashree Bantwal * * Description: * * This file defines the publicly available functions for the IMAP * functionality for Snort. * */ #ifndef __SPP_IMAP_H__ #define __SPP_IMAP_H__ void SetupIMAP(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/imap/spp_imap.c0000644000000000000000000005157312260565732017771 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * spp_imap.c * * Author: Bhagyashree Bantwal * * Description: * * This file initializes IMAP as a Snort preprocessor. * * This file registers the IMAP initialization function, * adds the IMAP function into the preprocessor list. * * In general, this file is a wrapper to IMAP functionality, * by interfacing with the Snort preprocessor functions. The rest * of IMAP should be separate from the preprocessor hooks. * **************************************************************************/ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_imap.h" #include "sf_preproc_info.h" #include "snort_imap.h" #include "imap_config.h" #include "imap_log.h" #include "preprocids.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "snort_debug.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "profiler.h" #ifdef PERF_PROFILING PreprocStats imapPerfStats; PreprocStats imapDetectPerfStats; int imapDetectCalled = 0; #endif #include "sf_types.h" #include "mempool.h" #include "snort_bounds.h" #include "file_api.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 0; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_IMAP"; const char *PROTOCOL_NAME = "IMAP"; #define SetupIMAP DYNAMIC_PREPROC_SETUP MemPool *imap_mempool = NULL; MemPool *imap_mime_mempool = NULL; tSfPolicyUserContextId imap_config = NULL; IMAPConfig *imap_eval_config = NULL; extern IMAP imap_no_session; extern int16_t imap_proto_id; static void IMAPInit(struct _SnortConfig *, char *); static void IMAPDetect(void *, void *context); static void IMAPCleanExitFunction(int, void *); static void IMAPResetFunction(int, void *); static void IMAPResetStatsFunction(int, void *); static void _addPortsToStream5Filter(struct _SnortConfig *, IMAPConfig *, tSfPolicyId); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static int IMAPCheckConfig(struct _SnortConfig *); #ifdef SNORT_RELOAD static void IMAPReload(struct _SnortConfig *, char *, void **); static int IMAPReloadVerify(struct _SnortConfig *, void *); static void * IMAPReloadSwap(struct _SnortConfig *, void *); static void IMAPReloadSwapFree(void *); #endif /* * Function: SetupIMAP() * * Purpose: Registers the preprocessor keyword and initialization * function into the preprocessor list. This is the function that * gets called from InitPreprocessors() in plugbase.c. * * Arguments: None. * * Returns: void function * */ void SetupIMAP(void) { /* link the preprocessor keyword to the init function in the preproc list */ #ifndef SNORT_RELOAD _dpd.registerPreproc("imap", IMAPInit); #else _dpd.registerPreproc("imap", IMAPInit, IMAPReload, IMAPReloadVerify, IMAPReloadSwap, IMAPReloadSwapFree); #endif } /* * Function: IMAPInit(char *) * * Purpose: Calls the argument parsing function, performs final setup on data * structs, links the preproc function into the function list. * * Arguments: args => ptr to argument string * * Returns: void function * */ static void IMAPInit(struct _SnortConfig *sc, char *args) { IMAPToken *tmp; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); IMAPConfig * pPolicyConfig = NULL; if (imap_config == NULL) { //create a context imap_config = sfPolicyConfigCreate(); if (imap_config == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create IMAP " "configuration.\n"); } /* Initialize the searches not dependent on configuration. * headers, reponsed, data, mime boundary regular expression */ IMAP_SearchInit(); /* zero out static IMAP global used for stateless IMAP or if there * is no session pointer */ memset(&imap_no_session, 0, sizeof(IMAP)); /* Put the preprocessor function into the function list */ /* _dpd.addPreproc(IMAPDetect, PRIORITY_APPLICATION, PP_IMAP, PROTO_BIT__TCP);*/ _dpd.addPreprocExit(IMAPCleanExitFunction, NULL, PRIORITY_LAST, PP_IMAP); _dpd.addPreprocReset(IMAPResetFunction, NULL, PRIORITY_LAST, PP_IMAP); _dpd.addPreprocResetStats(IMAPResetStatsFunction, NULL, PRIORITY_LAST, PP_IMAP); _dpd.addPreprocConfCheck(sc, IMAPCheckConfig); #ifdef TARGET_BASED imap_proto_id = _dpd.findProtocolReference(IMAP_PROTO_REF_STR); if (imap_proto_id == SFTARGET_UNKNOWN_PROTOCOL) imap_proto_id = _dpd.addProtocolReference(IMAP_PROTO_REF_STR); DEBUG_WRAP(DebugMessage(DEBUG_IMAP,"IMAP: Target-based: Proto id for %s: %u.\n", IMAP_PROTO_REF_STR, imap_proto_id);); #endif #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("imap", (void*)&imapPerfStats, 0, _dpd.totalPerfStats); #endif } sfPolicyUserPolicySet (imap_config, policy_id); pPolicyConfig = (IMAPConfig *)sfPolicyUserDataGetCurrent(imap_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("Can only configure IMAP preprocessor once.\n"); } pPolicyConfig = (IMAPConfig *)calloc(1, sizeof(IMAPConfig)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create IMAP " "configuration.\n"); } sfPolicyUserDataSetCurrent(imap_config, pPolicyConfig); IMAP_InitCmds(pPolicyConfig); IMAP_ParseArgs(pPolicyConfig, args); IMAP_CheckConfig(pPolicyConfig, imap_config); IMAP_PrintConfig(pPolicyConfig); if(pPolicyConfig->disabled) return; _dpd.addPreproc(sc, IMAPDetect, PRIORITY_APPLICATION, PP_IMAP, PROTO_BIT__TCP); if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled " "for IMAP preprocessor\n"); } /* Command search - do this here because it's based on configuration */ pPolicyConfig->cmd_search_mpse = _dpd.searchAPI->search_instance_new(); if (pPolicyConfig->cmd_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate IMAP " "command search.\n"); } for (tmp = pPolicyConfig->cmds; tmp->name != NULL; tmp++) { pPolicyConfig->cmd_search[tmp->search_id].name = tmp->name; pPolicyConfig->cmd_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pPolicyConfig->cmd_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pPolicyConfig->cmd_search_mpse); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } /* * Function: IMAPDetect(void *, void *) * * Purpose: Perform the preprocessor's intended function. This can be * simple (statistics collection) or complex (IP defragmentation) * as you like. Try not to destroy the performance of the whole * system by trying to do too much.... * * Arguments: p => pointer to the current packet data struct * * Returns: void function * */ static void IMAPDetect(void *pkt, void *context) { SFSnortPacket *p = (SFSnortPacket *)pkt; tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; // preconditions - what we registered for assert(IsTCP(p) && p->payload && p->payload_size); PREPROC_PROFILE_START(imapPerfStats); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP Start (((((((((((((((((((((((((((((((((((((((\n");); sfPolicyUserPolicySet (imap_config, policy_id); SnortIMAP(p); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP End )))))))))))))))))))))))))))))))))))))))))\n\n");); PREPROC_PROFILE_END(imapPerfStats); #ifdef PERF_PROFILING if (PROFILING_PREPROCS && imapDetectCalled) { imapPerfStats.ticks -= imapDetectPerfStats.ticks; /* And Reset ticks to 0 */ imapDetectPerfStats.ticks = 0; imapDetectCalled = 0; } #endif } /* * Function: IMAPCleanExitFunction(int, void *) * * Purpose: This function gets called when Snort is exiting, if there's * any cleanup that needs to be performed (e.g. closing files) * it should be done here. * * Arguments: signal => the code of the signal that was issued to Snort * data => any arguments or data structs linked to this * function when it was registered, may be * needed to properly exit * * Returns: void function */ static void IMAPCleanExitFunction(int signal, void *data) { IMAP_Free(); if (mempool_destroy(imap_mime_mempool) == 0) { free(imap_mime_mempool); imap_mime_mempool = NULL; } if (mempool_destroy(imap_mempool) == 0) { free(imap_mempool); imap_mempool = NULL; } } static void IMAPResetFunction(int signal, void *data) { return; } static void IMAPResetStatsFunction(int signal, void *data) { return; } static void _addPortsToStream5Filter(struct _SnortConfig *sc, IMAPConfig *config, tSfPolicyId policy_id) { unsigned int portNum; if (config == NULL) return; for (portNum = 0; portNum < MAXPORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); _dpd.fileAPI->register_mime_paf_port(sc, portNum, policy_id); } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status(sc, imap_proto_id, PORT_MONITOR_SESSION, policy_id, 1); _dpd.fileAPI->register_mime_paf_service(sc, imap_proto_id, policy_id); } #endif static int CheckFilePolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { IMAPConfig *context = (IMAPConfig *)pData; context->file_depth = _dpd.fileAPI->get_max_file_depth(); if (context->file_depth > -1) context->log_config.log_filename = 1; updateMaxDepth(context->file_depth, &context->max_depth); return 0; } static int IMAPEnableDecoding(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void *pData) { IMAPConfig *context = (IMAPConfig *)pData; if (pData == NULL) return 0; if(context->disabled) return 0; if(!IMAP_IsDecodingEnabled(context)) return 1; return 0; } static int IMAPCheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { IMAPConfig *context = (IMAPConfig *)pData; _dpd.setParserPolicy(sc, policyId); /* In a multiple-policy setting, the IMAP preproc can be turned on in a "disabled" state. In this case, we don't require Stream5. */ if (context->disabled) return 0; if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("Streaming & reassembly must be enabled " "for IMAP preprocessor\n"); return -1; } return 0; } static int IMAPLogExtraData(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void *pData) { IMAPConfig *context = (IMAPConfig *)pData; if (pData == NULL) return 0; if(context->disabled) return 0; if(context->log_config.log_filename) return 1; return 0; } static int IMAPCheckConfig(struct _SnortConfig *sc) { int rval; IMAPConfig *defaultConfig = (IMAPConfig *)sfPolicyUserDataGetDefault(imap_config); if ((rval = sfPolicyUserDataIterate (sc, imap_config, IMAPCheckPolicyConfig))) return rval; if ((rval = sfPolicyUserDataIterate (sc, imap_config, CheckFilePolicyConfig))) return rval; if (sfPolicyUserDataIterate(sc, imap_config, IMAPEnableDecoding) != 0) { if (defaultConfig == NULL) { /*error message */ _dpd.errMsg("IMAP: Must configure a default " "configuration if you want to imap decoding.\n"); return -1; } imap_mime_mempool = (MemPool *)_dpd.fileAPI->init_mime_mempool(defaultConfig->max_mime_mem, defaultConfig->max_depth, imap_mime_mempool, PROTOCOL_NAME); } if (sfPolicyUserDataIterate(sc, imap_config, IMAPLogExtraData) != 0) { if (defaultConfig == NULL) { /*error message */ _dpd.errMsg("IMAP: Must configure a default " "configuration if you want to log extra data.\n"); return -1; } imap_mempool = (MemPool *)_dpd.fileAPI->init_log_mempool(0, defaultConfig->memcap, imap_mempool, PROTOCOL_NAME); } return 0; } #ifdef SNORT_RELOAD static void IMAPReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId imap_swap_config = (tSfPolicyUserContextId)*new_config; IMAPToken *tmp; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); IMAPConfig *pPolicyConfig = NULL; if (imap_swap_config == NULL) { //create a context imap_swap_config = sfPolicyConfigCreate(); if (imap_swap_config == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create IMAP " "configuration.\n"); } *new_config = (void *)imap_swap_config; } sfPolicyUserPolicySet (imap_swap_config, policy_id); pPolicyConfig = (IMAPConfig *)sfPolicyUserDataGetCurrent(imap_swap_config); if (pPolicyConfig != NULL) DynamicPreprocessorFatalMessage("Can only configure IMAP preprocessor once.\n"); pPolicyConfig = (IMAPConfig *)calloc(1, sizeof(IMAPConfig)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create IMAP " "configuration.\n"); } sfPolicyUserDataSetCurrent(imap_swap_config, pPolicyConfig); IMAP_InitCmds(pPolicyConfig); IMAP_ParseArgs(pPolicyConfig, args); IMAP_CheckConfig(pPolicyConfig, imap_swap_config); IMAP_PrintConfig(pPolicyConfig); if( pPolicyConfig->disabled ) return; if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled " "for IMAP preprocessor\n"); } /* Command search - do this here because it's based on configuration */ pPolicyConfig->cmd_search_mpse = _dpd.searchAPI->search_instance_new(); if (pPolicyConfig->cmd_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate IMAP " "command search.\n"); } for (tmp = pPolicyConfig->cmds; tmp->name != NULL; tmp++) { pPolicyConfig->cmd_search[tmp->search_id].name = tmp->name; pPolicyConfig->cmd_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pPolicyConfig->cmd_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pPolicyConfig->cmd_search_mpse); _dpd.addPreproc(sc, IMAPDetect, PRIORITY_APPLICATION, PP_IMAP, PROTO_BIT__TCP); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } static int IMAPReloadVerify(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId imap_swap_config = (tSfPolicyUserContextId)swap_config; IMAPConfig *config = NULL; IMAPConfig *configNext = NULL; if (imap_swap_config == NULL) return 0; if (imap_config != NULL) { config = (IMAPConfig *)sfPolicyUserDataGet(imap_config, _dpd.getDefaultPolicy()); } configNext = (IMAPConfig *)sfPolicyUserDataGet(imap_swap_config, _dpd.getDefaultPolicy()); if (config == NULL) { return 0; } sfPolicyUserDataIterate (sc, imap_swap_config, CheckFilePolicyConfig); if (imap_mime_mempool != NULL) { if (configNext == NULL) { _dpd.errMsg("IMAP reload: Changing the IMAP configuration requires a restart.\n"); return -1; } if (configNext->max_mime_mem != config->max_mime_mem) { _dpd.errMsg("IMAP reload: Changing the memcap requires a restart.\n"); return -1; } if(configNext->b64_depth != config->b64_depth) { _dpd.errMsg("IMAP reload: Changing the b64_decode_depth requires a restart.\n"); return -1; } if(configNext->qp_depth != config->qp_depth) { _dpd.errMsg("IMAP reload: Changing the qp_decode_depth requires a restart.\n"); return -1; } if(configNext->bitenc_depth != config->bitenc_depth) { _dpd.errMsg("IMAP reload: Changing the bitenc_decode_depth requires a restart.\n"); return -1; } if(configNext->uu_depth != config->uu_depth) { _dpd.errMsg("IMAP reload: Changing the uu_decode_depth requires a restart.\n"); return -1; } if(configNext->file_depth != config->file_depth) { _dpd.errMsg("IMAP reload: Changing the file_depth requires a restart.\n"); return -1; } } if (imap_mempool != NULL) { if (configNext == NULL) { _dpd.errMsg("IMAP reload: Changing the memcap requires a restart.\n"); return -1; } if (configNext->memcap != config->memcap) { _dpd.errMsg("IMAP reload: Changing the memcap requires a restart.\n"); return -1; } } else if(configNext != NULL) { if (sfPolicyUserDataIterate(sc, imap_swap_config, IMAPEnableDecoding) != 0) { imap_mime_mempool = (MemPool *)_dpd.fileAPI->init_mime_mempool(configNext->max_mime_mem, configNext->max_depth, imap_mime_mempool, PROTOCOL_NAME); } if (sfPolicyUserDataIterate(sc, imap_swap_config, IMAPLogExtraData) != 0) { imap_mempool = (MemPool *)_dpd.fileAPI->init_log_mempool(0, configNext->memcap, imap_mempool, PROTOCOL_NAME); } if ( configNext->disabled ) return 0; } if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("Streaming & reassembly must be enabled for IMAP preprocessor\n"); return -1; } return 0; } static int IMAPReloadSwapPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { IMAPConfig *pPolicyConfig = (IMAPConfig *)pData; if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); IMAP_FreeConfig(pPolicyConfig); } return 0; } static void * IMAPReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId imap_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = imap_config; if (imap_swap_config == NULL) return NULL; imap_config = imap_swap_config; sfPolicyUserDataFreeIterate (old_config, IMAPReloadSwapPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) IMAP_FreeConfigs(old_config); return NULL; } static void IMAPReloadSwapFree(void *data) { if (data == NULL) return; IMAP_FreeConfigs((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/imap/snort_imap.h0000644000000000000000000001527212260565732020335 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * **************************************************************************/ /************************************************************************** * * snort_imap.h * * Author: Bhagyashree Bantwal * * Description: * * This file defines everything specific to the IMAP preprocessor. * **************************************************************************/ #ifndef __IMAP_H__ #define __IMAP_H__ /* Includes ***************************************************************/ #include #include "sf_snort_packet.h" #include "imap_config.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "mempool.h" #include "sf_email_attach_decode.h" #include "file_api.h" #ifdef DEBUG #include "sf_types.h" #endif /**************************************************************************/ /* Defines ****************************************************************/ /* Direction packet is coming from, if we can figure it out */ #define IMAP_PKT_FROM_UNKNOWN 0 #define IMAP_PKT_FROM_CLIENT 1 #define IMAP_PKT_FROM_SERVER 2 #define SEARCH_CMD 0 #define SEARCH_RESP 1 #define SEARCH_HDR 2 #define SEARCH_DATA_END 3 #define NUM_SEARCHES 4 #define BOUNDARY 0 #define MAX_BOUNDARY_LEN 70 /* Max length of boundary string, defined in RFC 2046 */ #define STATE_DATA 0 /* Data state */ #define STATE_UNKNOWN 1 #define STATE_DATA_INIT 0 #define STATE_DATA_HEADER 1 /* Data header section of data state */ #define STATE_DATA_BODY 2 /* Data body section of data state */ #define STATE_MIME_HEADER 3 /* MIME header section within data section */ #define STATE_DATA_UNKNOWN 4 /* state flags */ #define IMAP_FLAG_FOLDING 0x00000001 #define IMAP_FLAG_IN_CONTENT_TYPE 0x00000002 #define IMAP_FLAG_GOT_BOUNDARY 0x00000004 #define IMAP_FLAG_DATA_HEADER_CONT 0x00000008 #define IMAP_FLAG_IN_CONT_TRANS_ENC 0x00000010 #define IMAP_FLAG_EMAIL_ATTACH 0x00000020 #define IMAP_FLAG_MULTIPLE_EMAIL_ATTACH 0x00000040 #define IMAP_FLAG_MIME_END 0x00000080 #define IMAP_FLAG_IN_CONT_DISP 0x00000200 #define IMAP_FLAG_IN_CONT_DISP_CONT 0x00000400 /* log flags */ #define IMAP_FLAG_FILENAME_PRESENT 0x00000004 /* session flags */ #define IMAP_FLAG_NEXT_STATE_UNKNOWN 0x00000004 #define IMAP_FLAG_GOT_NON_REBUILT 0x00000008 #define IMAP_SSL_ERROR_FLAGS (SSL_BOGUS_HS_DIR_FLAG | \ SSL_BAD_VER_FLAG | \ SSL_BAD_TYPE_FLAG | \ SSL_UNKNOWN_FLAG) /* Maximum length of header chars before colon, based on Exim 4.32 exploit */ #define MAX_HEADER_NAME_LEN 64 #define IMAP_PROTO_REF_STR "imap" /**************************************************************************/ /* Data structures ********************************************************/ typedef enum _IMAPCmdEnum { CMD_APPEND = 0, CMD_AUTHENTICATE, CMD_CAPABILITY, CMD_CHECK, CMD_CLOSE, CMD_COMPARATOR, CMD_COMPRESS, CMD_CONVERSIONS, CMD_COPY, CMD_CREATE, CMD_DELETE, CMD_DELETEACL, CMD_DONE, CMD_EXAMINE, CMD_EXPUNGE, CMD_FETCH, CMD_GETACL, CMD_GETMETADATA, CMD_GETQUOTA, CMD_GETQUOTAROOT, CMD_IDLE, CMD_LIST, CMD_LISTRIGHTS, CMD_LOGIN, CMD_LOGOUT, CMD_LSUB, CMD_MYRIGHTS, CMD_NOOP, CMD_NOTIFY, CMD_RENAME, CMD_SEARCH, CMD_SELECT, CMD_SETACL, CMD_SETMETADATA, CMD_SETQUOTA, CMD_SORT, CMD_STARTTLS, CMD_STATUS, CMD_STORE, CMD_SUBSCRIBE, CMD_THREAD, CMD_UID, CMD_UNSELECT, CMD_UNSUBSCRIBE, CMD_X, CMD_LAST } IMAPCmdEnum; typedef enum _IMAPRespEnum { RESP_CAPABILITY = 0, RESP_LIST, RESP_LSUB, RESP_STATUS, RESP_SEARCH, RESP_FLAGS, RESP_EXISTS, RESP_RECENT, RESP_EXPUNGE, RESP_FETCH, RESP_BAD, RESP_BYE, RESP_NO, RESP_OK, RESP_PREAUTH, RESP_ENVELOPE, RESP_UID, RESP_LAST } IMAPRespEnum; typedef enum _IMAPHdrEnum { HDR_CONTENT_TYPE = 0, HDR_CONT_TRANS_ENC, HDR_CONT_DISP, HDR_LAST } IMAPHdrEnum; typedef enum _IMAPDataEndEnum { DATA_END_1 = 0, DATA_END_2, DATA_END_3, DATA_END_4, DATA_END_LAST } IMAPDataEndEnum; typedef struct _IMAPSearchInfo { int id; int index; int length; } IMAPSearchInfo; typedef struct _IMAPMimeBoundary { int state; char boundary[2 + MAX_BOUNDARY_LEN + 1]; /* '--' + MIME boundary string + '\0' */ int boundary_len; void *boundary_search; } IMAPMimeBoundary; typedef struct _IMAPPcre { pcre *re; pcre_extra *pe; } IMAPPcre; typedef struct _IMAP { int state; int data_state; int state_flags; int log_flags; int session_flags; int alert_mask; int reassembling; uint32_t body_len; uint32_t body_read; #ifdef DEBUG_MSGS uint64_t session_number; #endif MemBucket *decode_bkt; IMAPMimeBoundary mime_boundary; Email_DecodeState *decode_state; MAIL_LogState *log_state; tSfPolicyId policy_id; tSfPolicyUserContextId config; } IMAP; /**************************************************************************/ /* Function prototypes ****************************************************/ void IMAP_InitCmds(IMAPConfig *config); void IMAP_SearchInit(void); void IMAP_Free(void); void SnortIMAP(SFSnortPacket *); int IMAP_IsServer(uint16_t); void IMAP_FreeConfig(IMAPConfig *); void IMAP_FreeConfigs(tSfPolicyUserContextId); int IMAP_GetFilename(void *data, uint8_t **buf, uint32_t *len, uint32_t *type); /**************************************************************************/ #endif /* __IMAP_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/imap/snort_imap.c0000644000000000000000000016524212260565732020333 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * snort_imap.c * * Author: Bhagyashree Bantwal * * Description: * * This file handles IMAP protocol checking and normalization. * * Entry point functions: * * SnortIMAP() * IMAP_Init() * IMAP_Free() * **************************************************************************/ /* Includes ***************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "sf_types.h" #include "snort_imap.h" #include "imap_config.h" #include "imap_util.h" #include "imap_log.h" #include "sf_snort_packet.h" #include "stream_api.h" #include "snort_debug.h" #include "profiler.h" #include "snort_bounds.h" #include "sf_dynamic_preprocessor.h" #include "ssl.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "file_api.h" #ifdef DEBUG_MSGS #include "sf_types.h" #endif /**************************************************************************/ /* Externs ****************************************************************/ #ifdef PERF_PROFILING extern PreprocStats imapDetectPerfStats; extern int imapDetectCalled; #endif extern tSfPolicyUserContextId imap_config; extern IMAPConfig *imap_eval_config; extern MemPool *imap_mempool; extern MemPool *imap_mime_mempool; #ifdef DEBUG_MSGS extern char imap_print_buffer[]; #endif /**************************************************************************/ /* Globals ****************************************************************/ const IMAPToken imap_known_cmds[] = { {"APPEND", 6, CMD_APPEND}, {"AUTHENTICATE", 12, CMD_AUTHENTICATE}, {"CAPABILITY", 10, CMD_CAPABILITY}, {"CHECK", 5, CMD_CHECK}, {"CLOSE", 5, CMD_CLOSE}, {"COMPARATOR", 10, CMD_COMPARATOR}, {"COMPRESS", 8, CMD_COMPRESS}, {"CONVERSIONS", 11, CMD_CONVERSIONS}, {"COPY", 4, CMD_COPY}, {"CREATE", 6, CMD_CREATE}, {"DELETE", 6, CMD_DELETE}, {"DELETEACL", 9, CMD_DELETEACL}, {"DONE", 4, CMD_DONE}, {"EXAMINE", 7, CMD_EXAMINE}, {"EXPUNGE", 7, CMD_EXPUNGE}, {"FETCH", 5, CMD_FETCH}, {"GETACL", 6, CMD_GETACL}, {"GETMETADATA", 11, CMD_GETMETADATA}, {"GETQUOTA", 8, CMD_GETQUOTA}, {"GETQUOTAROOT", 12, CMD_GETQUOTAROOT}, {"IDLE", 4, CMD_IDLE}, {"LIST", 4, CMD_LIST}, {"LISTRIGHTS", 10, CMD_LISTRIGHTS}, {"LOGIN", 5, CMD_LOGIN}, {"LOGOUT", 6, CMD_LOGOUT}, {"LSUB", 4, CMD_LSUB}, {"MYRIGHTS", 8, CMD_MYRIGHTS}, {"NOOP", 4, CMD_NOOP}, {"NOTIFY", 6, CMD_NOTIFY}, {"RENAME", 6, CMD_RENAME}, {"SEARCH", 6, CMD_SEARCH}, {"SELECT", 6, CMD_SELECT}, {"SETACL", 6, CMD_SETACL}, {"SETMETADATA", 11, CMD_SETMETADATA}, {"SETQUOTA", 8, CMD_SETQUOTA}, {"SORT", 4, CMD_SORT}, {"STARTTLS", 8, CMD_STARTTLS}, {"STATUS", 6, CMD_STATUS}, {"STORE", 5, CMD_STORE}, {"SUBSCRIBE", 9, CMD_SUBSCRIBE}, {"THREAD", 6, CMD_THREAD}, {"UID", 3, CMD_UID}, {"UNSELECT", 8, CMD_UNSELECT}, {"UNSUBSCRIBE", 11, CMD_UNSUBSCRIBE}, {"X", 1, CMD_X}, {NULL, 0, 0} }; const IMAPToken imap_resps[] = { {"CAPABILITY", 10, RESP_CAPABILITY}, {"LIST", 4, RESP_LIST}, {"LSUB", 4, RESP_LSUB}, {"STATUS", 6, RESP_STATUS}, {"SEARCH", 6, RESP_SEARCH}, {"FLAGS", 5, RESP_FLAGS}, {"EXISTS", 6, RESP_EXISTS}, {"RECENT", 6, RESP_RECENT}, {"EXPUNGE", 7, RESP_EXPUNGE}, {"FETCH", 5, RESP_FETCH}, {"BAD", 3, RESP_BAD}, {"BYE", 3, RESP_BYE}, {"NO", 2, RESP_NO}, {"OK", 2, RESP_OK}, {"PREAUTH", 7, RESP_PREAUTH}, {"ENVELOPE", 8, RESP_ENVELOPE}, {"UID", 3, RESP_UID}, {NULL, 0, 0} }; const IMAPToken imap_hdrs[] = { {"Content-type:", 13, HDR_CONTENT_TYPE}, {"Content-Transfer-Encoding:", 26, HDR_CONT_TRANS_ENC}, {"Content-Disposition:", 20, HDR_CONT_DISP}, {NULL, 0, 0} }; const IMAPToken imap_data_end[] = { {"\r\n.\r\n", 5, DATA_END_1}, {"\n.\r\n", 4, DATA_END_2}, {"\r\n.\n", 4, DATA_END_3}, {"\n.\n", 3, DATA_END_4}, {NULL, 0, 0} }; IMAP *imap_ssn = NULL; IMAP imap_no_session; IMAPPcre mime_boundary_pcre; char imap_normalizing; IMAPSearchInfo imap_search_info; #ifdef DEBUG_MSGS uint64_t imap_session_counter = 0; #endif #ifdef TARGET_BASED int16_t imap_proto_id; #endif void *imap_resp_search_mpse = NULL; IMAPSearch imap_resp_search[RESP_LAST]; void *imap_hdr_search_mpse = NULL; IMAPSearch imap_hdr_search[HDR_LAST]; void *imap_data_search_mpse = NULL; IMAPSearch imap_data_end_search[DATA_END_LAST]; IMAPSearch *imap_current_search = NULL; /**************************************************************************/ /* Private functions ******************************************************/ static int IMAP_Setup(SFSnortPacket *p, IMAP *ssn); static void IMAP_ResetState(void); static void IMAP_SessionFree(void *); static void IMAP_NoSessionFree(void); static int IMAP_GetPacketDirection(SFSnortPacket *, int); static void IMAP_ProcessClientPacket(SFSnortPacket *); static void IMAP_ProcessServerPacket(SFSnortPacket *); static void IMAP_DisableDetect(SFSnortPacket *); static const uint8_t * IMAP_HandleCommand(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * IMAP_HandleData(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * IMAP_HandleHeader(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * IMAP_HandleDataBody(SFSnortPacket *, const uint8_t *, const uint8_t *); static int IMAP_SearchStrFound(void *, void *, int, void *, void *); static int IMAP_BoundaryStrFound(void *, void *, int , void *, void *); static int IMAP_GetBoundary(const char *, int); static int IMAP_Inspect(SFSnortPacket *); /**************************************************************************/ static void SetImapBuffers(IMAP *ssn) { if ((ssn != NULL) && (ssn->decode_state == NULL)) { MemBucket *bkt = mempool_alloc(imap_mime_mempool); if (bkt != NULL) { ssn->decode_state = (Email_DecodeState *)calloc(1, sizeof(Email_DecodeState)); if( ssn->decode_state != NULL ) { ssn->decode_bkt = bkt; SetEmailDecodeState(ssn->decode_state, bkt->data, imap_eval_config->max_depth, imap_eval_config->b64_depth, imap_eval_config->qp_depth, imap_eval_config->uu_depth, imap_eval_config->bitenc_depth, imap_eval_config->file_depth); } else { /*free mempool if calloc fails*/ mempool_free(imap_mime_mempool, bkt); } } else { IMAP_GenerateAlert(IMAP_MEMCAP_EXCEEDED, "%s", IMAP_MEMCAP_EXCEEDED_STR); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "No memory available for decoding. Memcap exceeded \n");); } } } void IMAP_InitCmds(IMAPConfig *config) { const IMAPToken *tmp; if (config == NULL) return; /* add one to CMD_LAST for NULL entry */ config->cmds = (IMAPToken *)calloc(CMD_LAST + 1, sizeof(IMAPToken)); if (config->cmds == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for imap " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } for (tmp = &imap_known_cmds[0]; tmp->name != NULL; tmp++) { config->cmds[tmp->search_id].name_len = tmp->name_len; config->cmds[tmp->search_id].search_id = tmp->search_id; config->cmds[tmp->search_id].name = strdup(tmp->name); if (config->cmds[tmp->search_id].name == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for imap " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } } /* initialize memory for command searches */ config->cmd_search = (IMAPSearch *)calloc(CMD_LAST, sizeof(IMAPSearch)); if (config->cmd_search == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for imap " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } config->num_cmds = CMD_LAST; } /* * Initialize IMAP searches * * @param none * * @return none */ void IMAP_SearchInit(void) { const char *error; int erroffset; const IMAPToken *tmp; /* Response search */ imap_resp_search_mpse = _dpd.searchAPI->search_instance_new(); if (imap_resp_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate IMAP " "response search.\n"); } for (tmp = &imap_resps[0]; tmp->name != NULL; tmp++) { imap_resp_search[tmp->search_id].name = tmp->name; imap_resp_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(imap_resp_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(imap_resp_search_mpse); /* Header search */ imap_hdr_search_mpse = _dpd.searchAPI->search_instance_new(); if (imap_hdr_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate IMAP " "header search.\n"); } for (tmp = &imap_hdrs[0]; tmp->name != NULL; tmp++) { imap_hdr_search[tmp->search_id].name = tmp->name; imap_hdr_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(imap_hdr_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(imap_hdr_search_mpse); /* Data end search */ imap_data_search_mpse = _dpd.searchAPI->search_instance_new(); if (imap_data_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate IMAP " "data search.\n"); } for (tmp = &imap_data_end[0]; tmp->name != NULL; tmp++) { imap_data_end_search[tmp->search_id].name = tmp->name; imap_data_end_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(imap_data_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(imap_data_search_mpse); /* create regex for finding boundary string - since it can be cut across multiple * lines, a straight search won't do. Shouldn't be too slow since it will most * likely only be acting on a small portion of data */ //"^content-type:\\s*multipart.*boundary\\s*=\\s*\"?([^\\s]+)\"?" //"^\\s*multipart.*boundary\\s*=\\s*\"?([^\\s]+)\"?" //mime_boundary_pcre.re = pcre_compile("^.*boundary\\s*=\\s*\"?([^\\s\"]+)\"?", //mime_boundary_pcre.re = pcre_compile("boundary(?:\n|\r\n)?=(?:\n|\r\n)?\"?([^\\s\"]+)\"?", mime_boundary_pcre.re = pcre_compile("boundary\\s*=\\s*\"?([^\\s\"]+)\"?", PCRE_CASELESS | PCRE_DOTALL, &error, &erroffset, NULL); if (mime_boundary_pcre.re == NULL) { DynamicPreprocessorFatalMessage("Failed to compile pcre regex for getting boundary " "in a multipart IMAP message: %s\n", error); } mime_boundary_pcre.pe = pcre_study(mime_boundary_pcre.re, 0, &error); if (error != NULL) { DynamicPreprocessorFatalMessage("Failed to study pcre regex for getting boundary " "in a multipart IMAP message: %s\n", error); } } /* * Initialize run-time boundary search */ static int IMAP_BoundarySearchInit(void) { if (imap_ssn->mime_boundary.boundary_search != NULL) _dpd.searchAPI->search_instance_free(imap_ssn->mime_boundary.boundary_search); imap_ssn->mime_boundary.boundary_search = _dpd.searchAPI->search_instance_new(); if (imap_ssn->mime_boundary.boundary_search == NULL) return -1; _dpd.searchAPI->search_instance_add(imap_ssn->mime_boundary.boundary_search, imap_ssn->mime_boundary.boundary, imap_ssn->mime_boundary.boundary_len, BOUNDARY); _dpd.searchAPI->search_instance_prep(imap_ssn->mime_boundary.boundary_search); return 0; } /* * Reset IMAP session state * * @param none * * @return none */ static void IMAP_ResetState(void) { if (imap_ssn->mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(imap_ssn->mime_boundary.boundary_search); imap_ssn->mime_boundary.boundary_search = NULL; } imap_ssn->state = STATE_UNKNOWN; imap_ssn->data_state = STATE_DATA_INIT; imap_ssn->state_flags = 0; imap_ssn->body_read = imap_ssn->body_len = 0; ClearEmailDecodeState(imap_ssn->decode_state); memset(&imap_ssn->mime_boundary, 0, sizeof(IMAPMimeBoundary)); } /* * Given a server configuration and a port number, we decide if the port is * in the IMAP server port list. * * @param port the port number to compare with the configuration * * @return integer * @retval 0 means that the port is not a server port * @retval !0 means that the port is a server port */ int IMAP_IsServer(uint16_t port) { if (imap_eval_config->ports[port / 8] & (1 << (port % 8))) return 1; return 0; } static IMAP * IMAP_GetNewSession(SFSnortPacket *p, tSfPolicyId policy_id) { IMAP *ssn; IMAPConfig *pPolicyConfig = NULL; pPolicyConfig = (IMAPConfig *)sfPolicyUserDataGetCurrent(imap_config); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Creating new session data structure\n");); ssn = (IMAP *)calloc(1, sizeof(IMAP)); if (ssn == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate IMAP session data\n"); } imap_ssn = ssn; if (_dpd.fileAPI->set_log_buffers(&(imap_ssn->log_state), &(pPolicyConfig->log_config), imap_mempool) < 0) { free(ssn); return NULL; } _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_IMAP, ssn, &IMAP_SessionFree); if (p->flags & SSNFLAG_MIDSTREAM) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Got midstream packet - " "setting state to unknown\n");); ssn->state = STATE_UNKNOWN; } #ifdef DEBUG_MSGS imap_session_counter++; ssn->session_number = imap_session_counter; #endif if (p->stream_session_ptr != NULL) { /* check to see if we're doing client reassembly in stream */ if (_dpd.streamAPI->get_reassembly_direction(p->stream_session_ptr) & SSN_DIR_FROM_CLIENT) ssn->reassembling = 1; if(!ssn->reassembling) { _dpd.streamAPI->set_reassembly(p->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_FROM_CLIENT, STREAM_FLPOLICY_SET_ABSOLUTE); ssn->reassembling = 1; } } ssn->body_read = ssn->body_len = 0; ssn->policy_id = policy_id; ssn->config = imap_config; pPolicyConfig->ref_count++; return ssn; } /* * Do first-packet setup * * @param p standard Packet structure * * @return none */ static int IMAP_Setup(SFSnortPacket *p, IMAP *ssn) { int flags = 0; int pkt_dir; if (p->stream_session_ptr != NULL) { /* set flags to session flags */ flags = _dpd.streamAPI->get_session_flags(p->stream_session_ptr); } /* Figure out direction of packet */ pkt_dir = IMAP_GetPacketDirection(p, flags); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Session number: "STDu64"\n", ssn->session_number);); /* Check to see if there is a reassembly gap. If so, we won't know * what state we're in when we get the _next_ reassembled packet */ if ((pkt_dir != IMAP_PKT_FROM_SERVER) && (p->flags & FLAG_REBUILT_STREAM)) { int missing_in_rebuilt = _dpd.streamAPI->missing_in_reassembled(p->stream_session_ptr, SSN_DIR_FROM_CLIENT); if (ssn->session_flags & IMAP_FLAG_NEXT_STATE_UNKNOWN) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Found gap in previous reassembly buffer - " "set state to unknown\n");); ssn->state = STATE_UNKNOWN; ssn->session_flags &= ~IMAP_FLAG_NEXT_STATE_UNKNOWN; } if (missing_in_rebuilt == SSN_MISSING_BEFORE) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Found missing packets before " "in reassembly buffer - set state to unknown\n");); ssn->state = STATE_UNKNOWN; } } return pkt_dir; } /* * Determine packet direction * * @param p standard Packet structure * * @return none */ static int IMAP_GetPacketDirection(SFSnortPacket *p, int flags) { int pkt_direction = IMAP_PKT_FROM_UNKNOWN; if (flags & SSNFLAG_MIDSTREAM) { if (IMAP_IsServer(p->src_port) && !IMAP_IsServer(p->dst_port)) { pkt_direction = IMAP_PKT_FROM_SERVER; } else if (!IMAP_IsServer(p->src_port) && IMAP_IsServer(p->dst_port)) { pkt_direction = IMAP_PKT_FROM_CLIENT; } } else { if (p->flags & FLAG_FROM_SERVER) { pkt_direction = IMAP_PKT_FROM_SERVER; } else if (p->flags & FLAG_FROM_CLIENT) { pkt_direction = IMAP_PKT_FROM_CLIENT; } /* if direction is still unknown ... */ if (pkt_direction == IMAP_PKT_FROM_UNKNOWN) { if (IMAP_IsServer(p->src_port) && !IMAP_IsServer(p->dst_port)) { pkt_direction = IMAP_PKT_FROM_SERVER; } else if (!IMAP_IsServer(p->src_port) && IMAP_IsServer(p->dst_port)) { pkt_direction = IMAP_PKT_FROM_CLIENT; } } } return pkt_direction; } /* * Free IMAP-specific related to this session * * @param v pointer to IMAP session structure * * * @return none */ static void IMAP_SessionFree(void *session_data) { IMAP *imap = (IMAP *)session_data; #ifdef SNORT_RELOAD IMAPConfig *pPolicyConfig = NULL; #endif if (imap == NULL) return; #ifdef SNORT_RELOAD pPolicyConfig = (IMAPConfig *)sfPolicyUserDataGet(imap->config, imap->policy_id); if (pPolicyConfig != NULL) { pPolicyConfig->ref_count--; if ((pPolicyConfig->ref_count == 0) && (imap->config != imap_config)) { sfPolicyUserDataClear (imap->config, imap->policy_id); IMAP_FreeConfig(pPolicyConfig); /* No more outstanding policies for this config */ if (sfPolicyUserPolicyGetActive(imap->config) == 0) IMAP_FreeConfigs(imap->config); } } #endif if (imap->mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(imap->mime_boundary.boundary_search); imap->mime_boundary.boundary_search = NULL; } if(imap->decode_state != NULL) { mempool_free(imap_mime_mempool, imap->decode_bkt); free(imap->decode_state); } if(imap->log_state != NULL) { mempool_free(imap_mempool, imap->log_state->log_hdrs_bkt); free(imap->log_state); } free(imap); } static void IMAP_NoSessionFree(void) { if (imap_no_session.mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(imap_no_session.mime_boundary.boundary_search); imap_no_session.mime_boundary.boundary_search = NULL; } } static int IMAP_FreeConfigsPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { IMAPConfig *pPolicyConfig = (IMAPConfig *)pData; //do any housekeeping before freeing IMAPConfig sfPolicyUserDataClear (config, policyId); IMAP_FreeConfig(pPolicyConfig); return 0; } void IMAP_FreeConfigs(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, IMAP_FreeConfigsPolicy); sfPolicyConfigDelete(config); } void IMAP_FreeConfig(IMAPConfig *config) { if (config == NULL) return; if (config->cmds != NULL) { IMAPToken *tmp = config->cmds; for (; tmp->name != NULL; tmp++) free(tmp->name); free(config->cmds); } if (config->cmd_search_mpse != NULL) _dpd.searchAPI->search_instance_free(config->cmd_search_mpse); if (config->cmd_search != NULL) free(config->cmd_search); free(config); } /* * Free anything that needs it before shutting down preprocessor * * @param none * * @return none */ void IMAP_Free(void) { IMAP_NoSessionFree(); IMAP_FreeConfigs(imap_config); imap_config = NULL; if (imap_resp_search_mpse != NULL) _dpd.searchAPI->search_instance_free(imap_resp_search_mpse); if (imap_hdr_search_mpse != NULL) _dpd.searchAPI->search_instance_free(imap_hdr_search_mpse); if (imap_data_search_mpse != NULL) _dpd.searchAPI->search_instance_free(imap_data_search_mpse); if (mime_boundary_pcre.re ) pcre_free(mime_boundary_pcre.re); if (mime_boundary_pcre.pe ) pcre_free(mime_boundary_pcre.pe); } /* * Callback function for string search * * @param id id in array of search strings from imap_config.cmds * @param index index in array of search strings from imap_config.cmds * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */ static int IMAP_SearchStrFound(void *id, void *unused, int index, void *data, void *unused2) { int search_id = (int)(uintptr_t)id; imap_search_info.id = search_id; imap_search_info.index = index; imap_search_info.length = imap_current_search[search_id].name_len; /* Returning non-zero stops search, which is okay since we only look for one at a time */ return 1; } /* * Callback function for boundary search * * @param id id in array of search strings * @param index index in array of search strings * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */ static int IMAP_BoundaryStrFound(void *id, void *unused, int index, void *data, void *unused2) { int boundary_id = (int)(uintptr_t)id; imap_search_info.id = boundary_id; imap_search_info.index = index; imap_search_info.length = imap_ssn->mime_boundary.boundary_len; return 1; } static int IMAP_GetBoundary(const char *data, int data_len) { int result; int ovector[9]; int ovecsize = 9; const char *boundary; int boundary_len; int ret; char *mime_boundary; int *mime_boundary_len; int *mime_boundary_state; mime_boundary = &imap_ssn->mime_boundary.boundary[0]; mime_boundary_len = &imap_ssn->mime_boundary.boundary_len; mime_boundary_state = &imap_ssn->mime_boundary.state; /* result will be the number of matches (including submatches) */ result = pcre_exec(mime_boundary_pcre.re, mime_boundary_pcre.pe, data, data_len, 0, 0, ovector, ovecsize); if (result < 0) return -1; result = pcre_get_substring(data, ovector, result, 1, &boundary); if (result < 0) return -1; boundary_len = strlen(boundary); if (boundary_len > MAX_BOUNDARY_LEN) { /* XXX should we alert? breaking the law of RFC */ boundary_len = MAX_BOUNDARY_LEN; } mime_boundary[0] = '-'; mime_boundary[1] = '-'; ret = SafeMemcpy(mime_boundary + 2, boundary, boundary_len, mime_boundary + 2, mime_boundary + 2 + MAX_BOUNDARY_LEN); pcre_free_substring(boundary); if (ret != SAFEMEM_SUCCESS) { return -1; } *mime_boundary_len = 2 + boundary_len; *mime_boundary_state = 0; mime_boundary[*mime_boundary_len] = '\0'; return 0; } /* * Handle COMMAND state * * @param p standard Packet structure * @param ptr pointer into p->payload buffer to start looking at data * @param end points to end of p->payload buffer * * @return pointer into p->payload where we stopped looking at data * will be end of line or end of packet */ static const uint8_t * IMAP_HandleCommand(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *end) { const uint8_t *eol; /* end of line */ const uint8_t *eolm; /* end of line marker */ int cmd_found; /* get end of line and end of line marker */ IMAP_GetEOL(ptr, end, &eol, &eolm); /* TODO If the end of line marker coincides with the end of payload we can't be * sure that we got a command and not a substring which we could tell through * inspection of the next packet. Maybe a command pending state where the first * char in the next packet is checked for a space and end of line marker */ /* do not confine since there could be space chars before command */ imap_current_search = &imap_eval_config->cmd_search[0]; cmd_found = _dpd.searchAPI->search_instance_find (imap_eval_config->cmd_search_mpse, (const char *)ptr, eolm - ptr, 0, IMAP_SearchStrFound); /* if command not found, alert and move on */ if (!cmd_found) { IMAP_GenerateAlert(IMAP_UNKNOWN_CMD, "%s", IMAP_UNKNOWN_CMD_STR); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "No known command found\n");); return eol; } /* At this point we have definitely found a legitimate command */ DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "%s\n", imap_eval_config->cmds[imap_search_info.id].name);); return eol; } static const uint8_t * IMAP_HandleData(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *end) { const uint8_t *data_end_marker = NULL; const uint8_t *data_end = NULL; int data_end_found; FilePosition position = SNORT_FILE_START; /* if we've just entered the data state, check for a dot + end of line * if found, no data */ if ((imap_ssn->data_state == STATE_DATA_INIT) || (imap_ssn->data_state == STATE_DATA_UNKNOWN)) { if ((ptr < end) && (*ptr == '.')) { const uint8_t *eol = NULL; const uint8_t *eolm = NULL; IMAP_GetEOL(ptr, end, &eol, &eolm); /* this means we got a real end of line and not just end of payload * and that the dot is only char on line */ if ((eolm != end) && (eolm == (ptr + 1))) { /* if we're normalizing and not ignoring data copy data end marker * and dot to alt buffer */ IMAP_ResetState(); return eol; } } if (imap_ssn->data_state == STATE_DATA_INIT) imap_ssn->data_state = STATE_DATA_HEADER; /* XXX A line starting with a '.' that isn't followed by a '.' is * deleted (RFC 821 - 4.5.2. TRANSPARENCY). If data starts with * '. text', i.e a dot followed by white space then text, some * servers consider it data header and some data body. * Postfix and Qmail will consider the start of data: * . text\r\n * . text\r\n * to be part of the header and the effect will be that of a * folded line with the '.' deleted. Exchange will put the same * in the body which seems more reasonable. */ } /* get end of data body * TODO check last bytes of previous packet to see if we had a partial * end of data */ imap_current_search = &imap_data_end_search[0]; data_end_found = _dpd.searchAPI->search_instance_find (imap_data_search_mpse, (const char *)ptr, end - ptr, 0, IMAP_SearchStrFound); if (data_end_found > 0) { data_end_marker = ptr + imap_search_info.index; data_end = data_end_marker + imap_search_info.length; } else { data_end_marker = data_end = end; } _dpd.setFileDataPtr((uint8_t*)ptr, (uint16_t)(data_end - ptr)); if ((imap_ssn->data_state == STATE_DATA_HEADER) || (imap_ssn->data_state == STATE_DATA_UNKNOWN)) { #ifdef DEBUG_MSGS if (imap_ssn->data_state == STATE_DATA_HEADER) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "DATA HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "DATA UNKNOWN STATE ~~~~~~~~~~~~~~~~~~~~~\n");); } #endif ptr = IMAP_HandleHeader(p, ptr, data_end_marker); if (ptr == NULL) return NULL; } /* now we shouldn't have to worry about copying any data to the alt buffer * only mime headers if we find them and only if we're ignoring data */ initFilePosition(&position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); while ((ptr != NULL) && (ptr < data_end_marker)) { /* multiple MIME attachments in one single packet. * Pipeline the MIME decoded data.*/ if ( imap_ssn->state_flags & IMAP_FLAG_MULTIPLE_EMAIL_ATTACH) { int detection_size = getDetectionSize(imap_eval_config->b64_depth, imap_eval_config->qp_depth, imap_eval_config->uu_depth, imap_eval_config->bitenc_depth,imap_ssn->decode_state ); _dpd.setFileDataPtr(imap_ssn->decode_state->decodePtr, (uint16_t)detection_size); /*Download*/ if (_dpd.fileAPI->file_process(p,(uint8_t *)imap_ssn->decode_state->decodePtr, (uint16_t)imap_ssn->decode_state->decoded_bytes, position, false, false) && (isFileStart(position)) && imap_ssn->log_state) { _dpd.fileAPI->set_file_name_from_log(&(imap_ssn->log_state->file_log), p->stream_session_ptr); } updateFilePosition(&position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); _dpd.detect(p); imap_ssn->state_flags &= ~IMAP_FLAG_MULTIPLE_EMAIL_ATTACH; ResetEmailDecodeState(imap_ssn->decode_state); p->flags |=FLAG_ALLOW_MULTIPLE_DETECT; /* Reset the log count when a packet goes through detection multiple times */ _dpd.DetectReset((uint8_t *)p->payload, p->payload_size); } switch (imap_ssn->data_state) { case STATE_MIME_HEADER: DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "MIME HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = IMAP_HandleHeader(p, ptr, data_end_marker); _dpd.fileAPI->finalize_mime_position(p->stream_session_ptr, imap_ssn->decode_state, &position); break; case STATE_DATA_BODY: DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "DATA BODY STATE ~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = IMAP_HandleDataBody(p, ptr, data_end_marker); _dpd.fileAPI->update_file_name(imap_ssn->log_state); break; } } /* We have either reached the end of MIME header or end of MIME encoded data*/ if(imap_ssn->decode_state != NULL) { int detection_size = getDetectionSize(imap_eval_config->b64_depth, imap_eval_config->qp_depth, imap_eval_config->uu_depth, imap_eval_config->bitenc_depth,imap_ssn->decode_state ); _dpd.setFileDataPtr(imap_ssn->decode_state->decodePtr, (uint16_t)detection_size); if ((data_end_marker != end)||(imap_ssn->state_flags & IMAP_FLAG_MIME_END)) { finalFilePosition(&position); } /*Download*/ if (_dpd.fileAPI->file_process(p,(uint8_t *)imap_ssn->decode_state->decodePtr, (uint16_t)imap_ssn->decode_state->decoded_bytes, position, false, false) && (isFileStart(position)) && imap_ssn->log_state) { _dpd.fileAPI->set_file_name_from_log(&(imap_ssn->log_state->file_log), p->stream_session_ptr); } ResetDecodedBytes(imap_ssn->decode_state); } /* if we got the data end reset state, otherwise we're probably still in the data * to expect more data in next packet */ if (data_end_marker != end) { IMAP_ResetState(); } return data_end; } /* * Handle Headers - Data or Mime * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */ static const uint8_t * IMAP_HandleHeader(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *data_end_marker) { const uint8_t *eol; const uint8_t *eolm; const uint8_t *colon; const uint8_t *content_type_ptr = NULL; const uint8_t *cont_trans_enc = NULL; const uint8_t *cont_disp = NULL; int header_found; int ret; const uint8_t *start_hdr; start_hdr = ptr; /* if we got a content-type in a previous packet and are * folding, the boundary still needs to be checked for */ if (imap_ssn->state_flags & IMAP_FLAG_IN_CONTENT_TYPE) content_type_ptr = ptr; if (imap_ssn->state_flags & IMAP_FLAG_IN_CONT_TRANS_ENC) cont_trans_enc = ptr; if (imap_ssn->state_flags & IMAP_FLAG_IN_CONT_DISP) cont_disp = ptr; while (ptr < data_end_marker) { IMAP_GetEOL(ptr, data_end_marker, &eol, &eolm); /* got a line with only end of line marker should signify end of header */ if (eolm == ptr) { /* reset global header state values */ imap_ssn->state_flags &= ~(IMAP_FLAG_FOLDING | IMAP_FLAG_IN_CONTENT_TYPE | IMAP_FLAG_DATA_HEADER_CONT | IMAP_FLAG_IN_CONT_TRANS_ENC ); imap_ssn->data_state = STATE_DATA_BODY; /* if no headers, treat as data */ if (ptr == start_hdr) return eolm; else return eol; } /* if we're not folding, see if we should interpret line as a data line * instead of a header line */ if (!(imap_ssn->state_flags & (IMAP_FLAG_FOLDING | IMAP_FLAG_DATA_HEADER_CONT))) { char got_non_printable_in_header_name = 0; /* if we're not folding and the first char is a space or * colon, it's not a header */ if (isspace((int)*ptr) || *ptr == ':') { imap_ssn->data_state = STATE_DATA_BODY; return ptr; } /* look for header field colon - if we're not folding then we need * to find a header which will be all printables (except colon) * followed by a colon */ colon = ptr; while ((colon < eolm) && (*colon != ':')) { if (((int)*colon < 33) || ((int)*colon > 126)) got_non_printable_in_header_name = 1; colon++; } /* If the end on line marker and end of line are the same, assume * header was truncated, so stay in data header state */ if ((eolm != eol) && ((colon == eolm) || got_non_printable_in_header_name)) { /* no colon or got spaces in header name (won't be interpreted as a header) * assume we're in the body */ imap_ssn->state_flags &= ~(IMAP_FLAG_FOLDING | IMAP_FLAG_IN_CONTENT_TYPE | IMAP_FLAG_DATA_HEADER_CONT |IMAP_FLAG_IN_CONT_TRANS_ENC); imap_ssn->data_state = STATE_DATA_BODY; return ptr; } if(tolower((int)*ptr) == 'c') { imap_current_search = &imap_hdr_search[0]; header_found = _dpd.searchAPI->search_instance_find (imap_hdr_search_mpse, (const char *)ptr, eolm - ptr, 1, IMAP_SearchStrFound); /* Headers must start at beginning of line */ if ((header_found > 0) && (imap_search_info.index == 0)) { switch (imap_search_info.id) { case HDR_CONTENT_TYPE: content_type_ptr = ptr + imap_search_info.length; imap_ssn->state_flags |= IMAP_FLAG_IN_CONTENT_TYPE; break; case HDR_CONT_TRANS_ENC: cont_trans_enc = ptr + imap_search_info.length; imap_ssn->state_flags |= IMAP_FLAG_IN_CONT_TRANS_ENC; break; case HDR_CONT_DISP: cont_disp = ptr + imap_search_info.length; imap_ssn->state_flags |= IMAP_FLAG_IN_CONT_DISP; break; default: break; } } } else if(tolower((int)*ptr) == 'e') { if((eolm - ptr) >= 9) { if(strncasecmp((const char *)ptr, "Encoding:", 9) == 0) { cont_trans_enc = ptr + 9; imap_ssn->state_flags |= IMAP_FLAG_IN_CONT_TRANS_ENC; } } } } else { imap_ssn->state_flags &= ~IMAP_FLAG_DATA_HEADER_CONT; } /* check for folding * if char on next line is a space and not \n or \r\n, we are folding */ if ((eol < data_end_marker) && isspace((int)eol[0]) && (eol[0] != '\n')) { if ((eol < (data_end_marker - 1)) && (eol[0] != '\r') && (eol[1] != '\n')) { imap_ssn->state_flags |= IMAP_FLAG_FOLDING; } else { imap_ssn->state_flags &= ~IMAP_FLAG_FOLDING; } } else if (eol != eolm) { imap_ssn->state_flags &= ~IMAP_FLAG_FOLDING; } /* check if we're in a content-type header and not folding. if so we have the whole * header line/lines for content-type - see if we got a multipart with boundary * we don't check each folded line, but wait until we have the complete header * because boundary=BOUNDARY can be split across mulitple folded lines before * or after the '=' */ if ((imap_ssn->state_flags & (IMAP_FLAG_IN_CONTENT_TYPE | IMAP_FLAG_FOLDING)) == IMAP_FLAG_IN_CONTENT_TYPE) { if (imap_ssn->data_state != STATE_MIME_HEADER) { /* we got the full content-type header - look for boundary string */ ret = IMAP_GetBoundary((const char *)content_type_ptr, eolm - content_type_ptr); if (ret != -1) { ret = IMAP_BoundarySearchInit(); if (ret != -1) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Got mime boundary: %s\n", imap_ssn->mime_boundary.boundary);); imap_ssn->state_flags |= IMAP_FLAG_GOT_BOUNDARY; } } } else if (!(imap_ssn->state_flags & IMAP_FLAG_EMAIL_ATTACH)) { /* Check for Encoding Type */ if( !IMAP_IsDecodingEnabled(imap_eval_config)) { SetImapBuffers(imap_ssn); if(imap_ssn->decode_state != NULL) { ResetBytesRead(imap_ssn->decode_state); IMAP_DecodeType((const char *)content_type_ptr, (eolm - content_type_ptr), false ); imap_ssn->state_flags |= IMAP_FLAG_EMAIL_ATTACH; /* check to see if there are other attachments in this packet */ if( imap_ssn->decode_state->decoded_bytes ) imap_ssn->state_flags |= IMAP_FLAG_MULTIPLE_EMAIL_ATTACH; } } } imap_ssn->state_flags &= ~IMAP_FLAG_IN_CONTENT_TYPE; content_type_ptr = NULL; } else if ((imap_ssn->state_flags & (IMAP_FLAG_IN_CONT_TRANS_ENC | IMAP_FLAG_FOLDING)) == IMAP_FLAG_IN_CONT_TRANS_ENC) { /* Check for Encoding Type */ if( !IMAP_IsDecodingEnabled(imap_eval_config)) { SetImapBuffers(imap_ssn); if(imap_ssn->decode_state != NULL) { ResetBytesRead(imap_ssn->decode_state); IMAP_DecodeType((const char *)cont_trans_enc, (eolm - cont_trans_enc), true ); imap_ssn->state_flags |= IMAP_FLAG_EMAIL_ATTACH; /* check to see if there are other attachments in this packet */ if( imap_ssn->decode_state->decoded_bytes ) imap_ssn->state_flags |= IMAP_FLAG_MULTIPLE_EMAIL_ATTACH; } } imap_ssn->state_flags &= ~IMAP_FLAG_IN_CONT_TRANS_ENC; cont_trans_enc = NULL; } else if (((imap_ssn->state_flags & (IMAP_FLAG_IN_CONT_DISP | IMAP_FLAG_FOLDING)) == IMAP_FLAG_IN_CONT_DISP) && cont_disp) { bool disp_cont = (imap_ssn->state_flags & IMAP_FLAG_IN_CONT_DISP_CONT)? true: false; if( imap_eval_config->log_config.log_filename && imap_ssn->log_state ) { if(! _dpd.fileAPI->log_file_name(cont_disp, eolm - cont_disp, &(imap_ssn->log_state->file_log), &disp_cont) ) imap_ssn->log_flags |= IMAP_FLAG_FILENAME_PRESENT; } if (disp_cont) { imap_ssn->state_flags |= IMAP_FLAG_IN_CONT_DISP_CONT; } else { imap_ssn->state_flags &= ~IMAP_FLAG_IN_CONT_DISP; imap_ssn->state_flags &= ~IMAP_FLAG_IN_CONT_DISP_CONT; } cont_disp = NULL; } /* if state was unknown, at this point assume we know */ if (imap_ssn->data_state == STATE_DATA_UNKNOWN) imap_ssn->data_state = STATE_DATA_HEADER; ptr = eol; if (ptr == data_end_marker) imap_ssn->state_flags |= IMAP_FLAG_DATA_HEADER_CONT; } return ptr; } /* * Handle DATA_BODY state * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */ static const uint8_t * IMAP_HandleDataBody(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *data_end_marker) { int boundary_found = 0; const uint8_t *boundary_ptr = NULL; const uint8_t *attach_start = NULL; const uint8_t *attach_end = NULL; if ( imap_ssn->state_flags & IMAP_FLAG_EMAIL_ATTACH ) attach_start = ptr; /* look for boundary */ if (imap_ssn->state_flags & IMAP_FLAG_GOT_BOUNDARY) { boundary_found = _dpd.searchAPI->stateful_search_instance_find (imap_ssn->mime_boundary.boundary_search, (const char *)ptr, data_end_marker - ptr, 0, IMAP_BoundaryStrFound, &(imap_ssn->mime_boundary.state)); if (boundary_found > 0) { imap_ssn->mime_boundary.state = 0; boundary_ptr = ptr + imap_search_info.index; /* should start at beginning of line */ if ((boundary_ptr == ptr) || (*(boundary_ptr - 1) == '\n')) { const uint8_t *eol; const uint8_t *eolm; const uint8_t *tmp; if (imap_ssn->state_flags & IMAP_FLAG_EMAIL_ATTACH ) { attach_end = boundary_ptr-1; imap_ssn->state_flags &= ~IMAP_FLAG_EMAIL_ATTACH; if(attach_start < attach_end) { if (*(attach_end - 1) == '\r') attach_end--; if(EmailDecode( attach_start, attach_end, imap_ssn->decode_state) < DECODE_SUCCESS ) { IMAP_DecodeAlert(); } } } if(boundary_ptr > ptr) tmp = boundary_ptr + imap_search_info.length; else { tmp = (const uint8_t *)_dpd.searchAPI->search_instance_find_end((char *)boundary_ptr, (data_end_marker - boundary_ptr), imap_ssn->mime_boundary.boundary, imap_search_info.length); } /* Check for end boundary */ if (((tmp + 1) < data_end_marker) && (tmp[0] == '-') && (tmp[1] == '-')) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Mime boundary end found: %s--\n", (char *)imap_ssn->mime_boundary.boundary);); /* no more MIME */ imap_ssn->state_flags &= ~IMAP_FLAG_GOT_BOUNDARY; imap_ssn->state_flags |= IMAP_FLAG_MIME_END; /* free boundary search */ _dpd.searchAPI->search_instance_free(imap_ssn->mime_boundary.boundary_search); imap_ssn->mime_boundary.boundary_search = NULL; } else { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Mime boundary found: %s\n", (char *)imap_ssn->mime_boundary.boundary);); imap_ssn->data_state = STATE_MIME_HEADER; } /* get end of line - there could be spaces after boundary before eol */ IMAP_GetEOL(boundary_ptr + imap_search_info.length, data_end_marker, &eol, &eolm); return eol; } } } if ( imap_ssn->state_flags & IMAP_FLAG_EMAIL_ATTACH ) { attach_end = data_end_marker; if(attach_start < attach_end) { if(EmailDecode( attach_start, attach_end, imap_ssn->decode_state) < DECODE_SUCCESS ) { IMAP_DecodeAlert(); } } } return data_end_marker; } /* * Process client packet * * @param packet standard Packet structure * * @return none */ static void IMAP_ProcessClientPacket(SFSnortPacket *p) { const uint8_t *ptr = p->payload; const uint8_t *end = p->payload + p->payload_size; ptr = IMAP_HandleCommand(p, ptr, end); } /* * Process server packet * * @param packet standard Packet structure * */ static void IMAP_ProcessServerPacket(SFSnortPacket *p) { int resp_found; const uint8_t *ptr; const uint8_t *end; const uint8_t *data_end; const uint8_t *eolm; const uint8_t *eol; int resp_line_len; const char *tmp = NULL; uint8_t *body_start, *body_end; char *eptr; uint32_t len = 0; body_start = body_end = NULL; ptr = p->payload; end = p->payload + p->payload_size; while (ptr < end) { if(imap_ssn->state == STATE_DATA) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "DATA STATE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");); if( imap_ssn->body_len > imap_ssn->body_read) { len = imap_ssn->body_len - imap_ssn->body_read ; if( (uint32_t)(end - ptr) < len ) { data_end = end; len = data_end - ptr; } else data_end = ptr + len; ptr = IMAP_HandleData(p, ptr, data_end); if( ptr < data_end) len = len - (data_end - ptr); imap_ssn->body_read += len; continue; } else { imap_ssn->body_len = imap_ssn->body_read = 0; IMAP_ResetState(); } } IMAP_GetEOL(ptr, end, &eol, &eolm); resp_line_len = eol - ptr; /* Check for response code */ imap_current_search = &imap_resp_search[0]; resp_found = _dpd.searchAPI->search_instance_find (imap_resp_search_mpse, (const char *)ptr, resp_line_len, 0, IMAP_SearchStrFound); if (resp_found > 0) { const uint8_t *cmd_start = ptr + imap_search_info.index; switch (imap_search_info.id) { case RESP_FETCH: imap_ssn->body_len = imap_ssn->body_read = 0; imap_ssn->state = STATE_DATA; tmp = _dpd.SnortStrcasestr((const char *)cmd_start, (eol - cmd_start), "BODY"); if(tmp != NULL) imap_ssn->state = STATE_DATA; else { tmp = _dpd.SnortStrcasestr((const char *)cmd_start, (eol - cmd_start), "RFC822"); if(tmp != NULL) imap_ssn->state = STATE_DATA; else imap_ssn->state = STATE_UNKNOWN; } break; default: break; } if(imap_ssn->state == STATE_DATA) { body_start = (uint8_t *)memchr((char *)ptr, '{', (eol - ptr)); if( body_start == NULL ) { imap_ssn->state = STATE_UNKNOWN; } else { if( (body_start + 1) < (uint8_t *)eol ) { len = (uint32_t)_dpd.SnortStrtoul((const char *)(body_start + 1), &eptr, 10); if (*eptr != '}') { imap_ssn->state = STATE_UNKNOWN; } else imap_ssn->body_len = len; len = 0; } else imap_ssn->state = STATE_UNKNOWN; } } } else { if ( (*ptr != '*') && (*ptr !='+') && (*ptr != '\r') && (*ptr != '\n') ) { IMAP_GenerateAlert(IMAP_UNKNOWN_RESP, "%s", IMAP_UNKNOWN_RESP_STR); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Server response not found\n");); } } ptr = eol; } return; } /* For Target based * If a protocol for the session is already identified and not one IMAP is * interested in, IMAP should leave it alone and return without processing. * If a protocol for the session is already identified and is one that IMAP is * interested in, decode it. * If the protocol for the session is not already identified and the preprocessor * is configured to detect on one of the packet ports, detect. * Returns 0 if we should not inspect * 1 if we should continue to inspect */ static int IMAP_Inspect(SFSnortPacket *p) { #ifdef TARGET_BASED /* IMAP could be configured to be stateless. If stream isn't configured, assume app id * will never be set and just base inspection on configuration */ if (p->stream_session_ptr == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP: Target-based: No stream session.\n");); if ((IMAP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (IMAP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP: Target-based: Configured for this " "traffic, so let's inspect.\n");); return 1; } } else { int16_t app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if (app_id != 0) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP: Target-based: App id: %u.\n", app_id);); if (app_id == imap_proto_id) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP: Target-based: App id is " "set to \"%s\".\n", IMAP_PROTO_REF_STR);); return 1; } } else { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP: Target-based: Unknown protocol for " "this session. See if we're configured.\n");); if ((IMAP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (IMAP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP: Target-based: IMAP port is configured.");); return 1; } } } DEBUG_WRAP(DebugMessage(DEBUG_IMAP,"IMAP: Target-based: Not inspecting ...\n");); #else /* Make sure it's traffic we're interested in */ if ((IMAP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (IMAP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) return 1; #endif /* TARGET_BASED */ return 0; } /* * Entry point to snort preprocessor for each packet * * @param packet standard Packet structure * * @return none */ void SnortIMAP(SFSnortPacket *p) { int detected = 0; int pkt_dir; tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; imap_ssn = (IMAP *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_IMAP); if (imap_ssn != NULL) imap_eval_config = (IMAPConfig *)sfPolicyUserDataGet(imap_ssn->config, imap_ssn->policy_id); else imap_eval_config = (IMAPConfig *)sfPolicyUserDataGetCurrent(imap_config); if (imap_eval_config == NULL) return; if (imap_ssn == NULL) { if (!IMAP_Inspect(p)) return; imap_ssn = IMAP_GetNewSession(p, policy_id); if (imap_ssn == NULL) return; } pkt_dir = IMAP_Setup(p, imap_ssn); if (pkt_dir == IMAP_PKT_FROM_CLIENT) { IMAP_ProcessClientPacket(p); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP client packet\n");); } else { #ifdef DEBUG_MSGS if (pkt_dir == IMAP_PKT_FROM_SERVER) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP server packet\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP packet NOT from client or server! " "Processing as a server packet\n");); } #endif if (!_dpd.readyForProcess(p)) { /* Packet will be rebuilt, so wait for it */ DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Client packet will be reassembled\n")); return; } else if (imap_ssn->reassembling && !(p->flags & FLAG_REBUILT_STREAM)) { /* If this isn't a reassembled packet and didn't get * inserted into reassembly buffer, there could be a * problem. If we miss syn or syn-ack that had window * scaling this packet might not have gotten inserted * into reassembly buffer because it fell outside of * window, because we aren't scaling it */ imap_ssn->session_flags |= IMAP_FLAG_GOT_NON_REBUILT; imap_ssn->state = STATE_UNKNOWN; } else if (imap_ssn->reassembling && (imap_ssn->session_flags & IMAP_FLAG_GOT_NON_REBUILT)) { /* This is a rebuilt packet. If we got previous packets * that were not rebuilt, state is going to be messed up * so set state to unknown. It's likely this was the * beginning of the conversation so reset state */ DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Got non-rebuilt packets before " "this rebuilt packet\n");); imap_ssn->state = STATE_UNKNOWN; imap_ssn->session_flags &= ~IMAP_FLAG_GOT_NON_REBUILT; } /* Process as a server packet */ IMAP_ProcessServerPacket(p); } PREPROC_PROFILE_START(imapDetectPerfStats); detected = _dpd.detect(p); #ifdef PERF_PROFILING imapDetectCalled = 1; #endif PREPROC_PROFILE_END(imapDetectPerfStats); /* Turn off detection since we've already done it. */ IMAP_DisableDetect(p); if (detected) { DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP vulnerability detected\n");); } } static void IMAP_DisableDetect(SFSnortPacket *p) { _dpd.disableAllDetect(p); _dpd.setPreprocBit(p, PP_SFPORTSCAN); _dpd.setPreprocBit(p, PP_PERFMONITOR); _dpd.setPreprocBit(p, PP_STREAM5); _dpd.setPreprocBit(p, PP_SDF); } static inline IMAP *IMAP_GetSession(void *data) { if(data) return (IMAP *)_dpd.streamAPI->get_application_data(data, PP_IMAP); return NULL; } /* Callback to return the MIME attachment filenames accumulated */ int IMAP_GetFilename(void *data, uint8_t **buf, uint32_t *len, uint32_t *type) { IMAP *ssn = IMAP_GetSession(data); if(ssn == NULL) return 0; *buf = ssn->log_state->file_log.filenames; *len = ssn->log_state->file_log.file_logged; return 1; } snort-2.9.6.0/src/dynamic-preprocessors/imap/imap_util.h0000644000000000000000000000313512260565732020140 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************* * * imap_util.h * * Author: Bhagyashree Bantwal * *************************************************************************/ #ifndef __IMAP_UTIL_H__ #define __IMAP_UTIL_H__ #include "sf_snort_packet.h" void IMAP_GetEOL(const uint8_t *, const uint8_t *, const uint8_t **, const uint8_t **); void IMAP_DecodeType(const char *start, int length, bool cnt_xf); #ifdef DEBUG_MSGS const char * IMAP_PrintBuffer(SFSnortPacket *); #endif #endif /* __IMAP_UTIL_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/imap/imap_util.c0000644000000000000000000001071112260565732020131 00000000000000/* * imap_util.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * * Author: Bhagyashree Bantwal * * Description: * * This file contains IMAP helper functions. * * Entry point functions: * * safe_strchr() * safe_strstr() * copy_to_space() * safe_sscanf() * * */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "snort_bounds.h" #include "snort_imap.h" #include "imap_util.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_packet.h" #include "Unified2_common.h" extern IMAP *imap_ssn; void IMAP_GetEOL(const uint8_t *ptr, const uint8_t *end, const uint8_t **eol, const uint8_t **eolm) { const uint8_t *tmp_eol; const uint8_t *tmp_eolm; /* XXX maybe should fatal error here since none of these * pointers should be NULL */ if (ptr == NULL || end == NULL || eol == NULL || eolm == NULL) return; tmp_eol = (uint8_t *)memchr(ptr, '\n', end - ptr); if (tmp_eol == NULL) { tmp_eol = end; tmp_eolm = end; } else { /* end of line marker (eolm) should point to marker and * end of line (eol) should point to end of marker */ if ((tmp_eol > ptr) && (*(tmp_eol - 1) == '\r')) { tmp_eolm = tmp_eol - 1; } else { tmp_eolm = tmp_eol; } /* move past newline */ tmp_eol++; } *eol = tmp_eol; *eolm = tmp_eolm; } void IMAP_DecodeType(const char *start, int length, bool cnt_xf) { const char *tmp = NULL; if(cnt_xf) { if(imap_ssn->decode_state->b64_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "base64"); if( tmp != NULL ) { imap_ssn->decode_state->decode_type = DECODE_B64; return; } } if(imap_ssn->decode_state->qp_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "quoted-printable"); if( tmp != NULL ) { imap_ssn->decode_state->decode_type = DECODE_QP; return; } } if(imap_ssn->decode_state->uu_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "uuencode"); if( tmp != NULL ) { imap_ssn->decode_state->decode_type = DECODE_UU; return; } } } if(imap_ssn->decode_state->bitenc_state.depth > -1) { imap_ssn->decode_state->decode_type = DECODE_BITENC; return; } return; } #ifdef DEBUG_MSGS char imap_print_buffer[65537]; const char * IMAP_PrintBuffer(SFSnortPacket *p) { const uint8_t *ptr = NULL; int len = 0; int iorig, inew; ptr = p->payload; len = p->payload_size; for (iorig = 0, inew = 0; iorig < len; iorig++, inew++) { if ((isascii((int)ptr[iorig]) && isprint((int)ptr[iorig])) || (ptr[iorig] == '\n')) { imap_print_buffer[inew] = ptr[iorig]; } else if (ptr[iorig] == '\r' && ((iorig + 1) < len) && (ptr[iorig + 1] == '\n')) { iorig++; imap_print_buffer[inew] = '\n'; } else if (isspace((int)ptr[iorig])) { imap_print_buffer[inew] = ' '; } else { imap_print_buffer[inew] = '.'; } } imap_print_buffer[inew] = '\0'; return &imap_print_buffer[0]; } #endif snort-2.9.6.0/src/dynamic-preprocessors/imap/imap_log.h0000644000000000000000000000463412260565732017751 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * imap_log.h * * Author: Bhagyashree Bantwal * **************************************************************************/ #ifndef __IMAP_LOG_H__ #define __IMAP_LOG_H__ #define GENERATOR_SPP_IMAP 141 /* Events for IMAP */ #define IMAP_UNKNOWN_CMD 1 #define IMAP_UNKNOWN_RESP 2 #define IMAP_MEMCAP_EXCEEDED 3 #define IMAP_B64_DECODING_FAILED 4 #define IMAP_QP_DECODING_FAILED 5 /* Do not delete or reuse this SID. Commenting this SID as this alert is no longer valid.* * #define IMAP_BITENC_DECODING_FAILED 6 */ #define IMAP_UU_DECODING_FAILED 7 #define IMAP_EVENT_MAX 8 /* Messages for each event */ #define IMAP_UNKNOWN_CMD_STR "(IMAP) Unknown IMAP4 command" #define IMAP_UNKNOWN_RESP_STR "(IMAP) Unknown IMAP4 response" #define IMAP_MEMCAP_EXCEEDED_STR "(IMAP) No memory available for decoding. Memcap exceeded" #define IMAP_B64_DECODING_FAILED_STR "(IMAP) Base64 Decoding failed." #define IMAP_QP_DECODING_FAILED_STR "(IMAP) Quoted-Printable Decoding failed." #define IMAP_UU_DECODING_FAILED_STR "(IMAP) Unix-to-Unix Decoding failed." #define EVENT_STR_LEN 256 /* Function prototypes */ void IMAP_GenerateAlert(int, char *, ...); void IMAP_DecodeAlert(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/imap/imap_log.c0000644000000000000000000000631512260565732017742 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * imap_log.c * * Author: Bhagyashree Bantwal * * Description: * * This file handles IMAP alerts. * * Entry point functions: * * IMAP_GenerateAlert() * * **************************************************************************/ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "imap_config.h" #include "imap_log.h" #include "snort_imap.h" #include "sf_dynamic_preprocessor.h" extern IMAPConfig *imap_eval_config; extern IMAP *imap_ssn; char imap_event[IMAP_EVENT_MAX][EVENT_STR_LEN]; void IMAP_GenerateAlert(int event, char *format, ...) { va_list ap; /* Only log a specific alert once per session */ if (imap_ssn->alert_mask & (1 << event)) { #ifdef DEBUG_MSGS DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "Already alerted on: %s - " "ignoring event.\n", imap_event[event]);); #endif return; } /* set bit for this alert so we don't alert on again * in this session */ imap_ssn->alert_mask |= (1 << event); va_start(ap, format); imap_event[event][0] = '\0'; vsnprintf(&imap_event[event][0], EVENT_STR_LEN - 1, format, ap); imap_event[event][EVENT_STR_LEN - 1] = '\0'; _dpd.alertAdd(GENERATOR_SPP_IMAP, event, 1, 0, 3, &imap_event[event][0], 0); DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP Alert generated: %s\n", imap_event[event]);); va_end(ap); } void IMAP_DecodeAlert(void) { switch( imap_ssn->decode_state->decode_type ) { case DECODE_B64: if (imap_eval_config->b64_depth > -1) IMAP_GenerateAlert(IMAP_B64_DECODING_FAILED, "%s", IMAP_B64_DECODING_FAILED_STR); break; case DECODE_QP: if (imap_eval_config->qp_depth > -1) IMAP_GenerateAlert(IMAP_QP_DECODING_FAILED, "%s", IMAP_QP_DECODING_FAILED_STR); break; case DECODE_UU: if (imap_eval_config->uu_depth > -1) IMAP_GenerateAlert(IMAP_UU_DECODING_FAILED, "%s", IMAP_UU_DECODING_FAILED_STR); break; default: break; } } snort-2.9.6.0/src/dynamic-preprocessors/imap/imap_config.h0000644000000000000000000000677512260565732020445 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /*************************************************************************** * * imap_config.h * * Author: Bhagyashree Bantwal * ***************************************************************************/ #ifndef __IMAP_CONFIG_H__ #define __IMAP_CONFIG_H__ #include "sfPolicyUserData.h" #include "file_api.h" #define CONF_SEPARATORS " \t\n\r" #define CONF_PORTS "ports" #define CONF_IMAP_MEMCAP "memcap" #define CONF_MAX_MIME_MEM "max_mime_mem" #define CONF_B64_DECODE "b64_decode_depth" #define CONF_QP_DECODE "qp_decode_depth" #define CONF_BITENC_DECODE "bitenc_decode_depth" #define CONF_UU_DECODE "uu_decode_depth" #define CONF_DISABLED "disabled" #define CONF_START_LIST "{" #define CONF_END_LIST "}" /*These are temporary values*/ #define DEFAULT_MAX_MIME_MEM 838860 #define DEFAULT_IMAP_MEMCAP 838860 #define DEFAULT_DEPTH 1464 #define MAX_IMAP_MEMCAP 104857600 #define MIN_IMAP_MEMCAP 3276 #define MAX_MIME_MEM 104857600 #define MIN_MIME_MEM 3276 #define MAX_DEPTH 65535 #define MIN_DEPTH -1 #define IMAP_DEFAULT_SERVER_PORT 143 /* IMAP normally runs on port 143 */ #define ERRSTRLEN 512 typedef struct _IMAPSearch { char *name; int name_len; } IMAPSearch; typedef struct _IMAPToken { char *name; int name_len; int search_id; } IMAPToken; typedef struct _IMAPCmdConfig { char alert; /* 1 if alert when seen */ char normalize; /* 1 if we should normalize this command */ int max_line_len; /* Max length of this particular command */ } IMAPCmdConfig; typedef struct _IMAPConfig { char ports[8192]; int max_mime_mem; uint32_t memcap; int max_depth; int b64_depth; int qp_depth; int bitenc_depth; int uu_depth; int64_t file_depth; IMAPToken *cmds; IMAPSearch *cmd_search; void *cmd_search_mpse; int num_cmds; int disabled; MAIL_LogConfig log_config; int ref_count; } IMAPConfig; /* Function prototypes */ void IMAP_ParseArgs(IMAPConfig *, char *); void IMAP_PrintConfig(IMAPConfig *config); void IMAP_CheckConfig(IMAPConfig *, tSfPolicyUserContextId); int IMAP_IsDecodingEnabled(IMAPConfig *); #endif snort-2.9.6.0/src/dynamic-preprocessors/imap/imap_config.c0000644000000000000000000004630312260565732020427 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /*************************************************************************** * imap_config.c * * Author: Bhagyashree Bantwal * * Description: * * Handle configuration of the IMAP preprocessor * * Entry point functions: * * IMAP_ParseArgs() * ***************************************************************************/ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_imap.h" #include "imap_config.h" #include "snort_bounds.h" #include "sf_dynamic_preprocessor.h" #include "sfPolicy.h" /* Global variable to hold configuration */ extern IMAPConfig **imap_config; extern const IMAPToken imap_known_cmds[]; /* Private functions */ static int ProcessPorts(IMAPConfig *, char *, int); static int ProcessDecodeDepth(IMAPConfig *, char *, int, char *, DecodeType); /* * Function: IMAP_ParseArgs(char *) * * Purpose: Process the preprocessor arguments from the rules file and * initialize the preprocessor's data struct. This function doesn't * have to exist if it makes sense to parse the args in the init * function. * * Arguments: args => argument list * * Returns: void function * */ void IMAP_ParseArgs(IMAPConfig *config, char *args) { int ret = 0; char *arg; char errStr[ERRSTRLEN]; int errStrLen = ERRSTRLEN; if ((config == NULL) || (args == NULL)) return; config->ports[IMAP_DEFAULT_SERVER_PORT / 8] |= 1 << (IMAP_DEFAULT_SERVER_PORT % 8); config->max_mime_mem = DEFAULT_IMAP_MEMCAP; config->memcap = DEFAULT_IMAP_MEMCAP; config->b64_depth = DEFAULT_DEPTH; config->qp_depth = DEFAULT_DEPTH; config->uu_depth = DEFAULT_DEPTH; config->bitenc_depth = DEFAULT_DEPTH; config->max_depth = MIN_DEPTH; config->log_config.log_filename = 0; config->log_config.log_mailfrom = 0; config->log_config.log_rcptto = 0; config->log_config.log_email_hdrs = 0; config->log_config.email_hdrs_log_depth = 0; *errStr = '\0'; arg = strtok(args, CONF_SEPARATORS); while ( arg != NULL ) { unsigned long value = 0; if ( !strcasecmp(CONF_PORTS, arg) ) { ret = ProcessPorts(config, errStr, errStrLen); } else if ( !strcasecmp(CONF_IMAP_MEMCAP, arg) ) { ret = _dpd.checkValueInRange(strtok(NULL, CONF_SEPARATORS), CONF_IMAP_MEMCAP, MIN_IMAP_MEMCAP, MAX_IMAP_MEMCAP, &value); config->memcap = (uint32_t)value; } else if ( !strcasecmp(CONF_MAX_MIME_MEM, arg) ) { ret = _dpd.checkValueInRange(strtok(NULL, CONF_SEPARATORS), CONF_MAX_MIME_MEM, MIN_MIME_MEM, MAX_MIME_MEM, &value); config->max_mime_mem = (int)value; } else if ( !strcasecmp(CONF_B64_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_B64_DECODE, DECODE_B64); } else if ( !strcasecmp(CONF_QP_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_QP_DECODE, DECODE_QP); } else if ( !strcasecmp(CONF_UU_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_UU_DECODE, DECODE_UU); } else if ( !strcasecmp(CONF_BITENC_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_BITENC_DECODE, DECODE_BITENC); } else if ( !strcasecmp(CONF_DISABLED, arg) ) { config->disabled = 1; } else { DynamicPreprocessorFatalMessage("%s(%d) => Unknown IMAP configuration option %s\n", *(_dpd.config_file), *(_dpd.config_line), arg); } if (ret == -1) { /* ** Fatal Error, log error and exit. */ if (*errStr) { DynamicPreprocessorFatalMessage("%s(%d) => %s\n", *(_dpd.config_file), *(_dpd.config_line), errStr); } else { DynamicPreprocessorFatalMessage("%s(%d) => Undefined Error.\n", *(_dpd.config_file), *(_dpd.config_line)); } } /* Get next token */ arg = strtok(NULL, CONF_SEPARATORS); } } int IMAP_IsDecodingEnabled(IMAPConfig *pPolicyConfig) { if( (pPolicyConfig->b64_depth > -1) || (pPolicyConfig->qp_depth > -1) || (pPolicyConfig->uu_depth > -1) || (pPolicyConfig->bitenc_depth > -1) || (pPolicyConfig->file_depth > -1)) { return 0; } else return -1; } void IMAP_CheckConfig(IMAPConfig *pPolicyConfig, tSfPolicyUserContextId context) { int max = -1; IMAPConfig *defaultConfig = (IMAPConfig *)sfPolicyUserDataGetDefault(context); if (pPolicyConfig == defaultConfig) { if (!pPolicyConfig->max_mime_mem) pPolicyConfig->max_mime_mem = DEFAULT_MAX_MIME_MEM; if(!pPolicyConfig->b64_depth || !pPolicyConfig->qp_depth || !pPolicyConfig->uu_depth || !pPolicyConfig->bitenc_depth) { pPolicyConfig->max_depth = MAX_DEPTH; return; } else { if(max < pPolicyConfig->b64_depth) max = pPolicyConfig->b64_depth; if(max < pPolicyConfig->qp_depth) max = pPolicyConfig->qp_depth; if(max < pPolicyConfig->bitenc_depth) max = pPolicyConfig->bitenc_depth; if(max < pPolicyConfig->uu_depth) max = pPolicyConfig->uu_depth; pPolicyConfig->max_depth = max; } if (!pPolicyConfig->memcap) pPolicyConfig->memcap = DEFAULT_IMAP_MEMCAP; } else if (defaultConfig == NULL) { if (pPolicyConfig->max_mime_mem) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: max_mime_mem must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->b64_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: b64_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->qp_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: qp_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->uu_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: uu_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->bitenc_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: bitenc_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } } else { pPolicyConfig->max_mime_mem = defaultConfig->max_mime_mem; pPolicyConfig->memcap = defaultConfig->memcap; pPolicyConfig->max_depth = defaultConfig->max_depth; if(pPolicyConfig->disabled) { pPolicyConfig->b64_depth = defaultConfig->b64_depth; pPolicyConfig->qp_depth = defaultConfig->qp_depth; pPolicyConfig->uu_depth = defaultConfig->uu_depth; pPolicyConfig->bitenc_depth = defaultConfig->bitenc_depth; return; } if(!pPolicyConfig->b64_depth && defaultConfig->b64_depth) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: Cannot enable unlimited Base64 decoding" " in non-default config without turning on unlimited Base64 decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->b64_depth && (pPolicyConfig->b64_depth > defaultConfig->b64_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: b64_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->b64_depth, defaultConfig->b64_depth); } if(!pPolicyConfig->qp_depth && defaultConfig->qp_depth) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: Cannot enable unlimited Quoted-Printable decoding" " in non-default config without turning on unlimited Quoted-Printable decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->qp_depth && (pPolicyConfig->qp_depth > defaultConfig->qp_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: qp_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->qp_depth, defaultConfig->qp_depth); } if(!pPolicyConfig->uu_depth && defaultConfig->uu_depth ) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: Cannot enable unlimited Unix-to-Unix decoding" " in non-default config without turning on unlimited Unix-to-Unix decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->uu_depth && (pPolicyConfig->uu_depth > defaultConfig->uu_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: uu_decode_depth value %d in the non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line),pPolicyConfig->uu_depth, defaultConfig->uu_depth); } if(!pPolicyConfig->bitenc_depth && defaultConfig->bitenc_depth) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: Cannot enable unlimited Non-Encoded MIME attachment extraction" " in non-default config without turning on unlimited Non-Encoded MIME attachment extraction in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->bitenc_depth && (pPolicyConfig->bitenc_depth > defaultConfig->bitenc_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => IMAP: bitenc_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->bitenc_depth, defaultConfig->bitenc_depth); } } } void IMAP_PrintConfig(IMAPConfig *config) { int i; int j = 0; char buf[8192]; if (config == NULL) return; memset(&buf[0], 0, sizeof(buf)); _dpd.logMsg("IMAP Config:\n"); if(config->disabled) _dpd.logMsg(" IMAP: INACTIVE\n"); snprintf(buf, sizeof(buf) - 1, " Ports: "); for (i = 0; i < 65536; i++) { if (config->ports[i / 8] & (1 << (i % 8))) { j++; _dpd.printfappend(buf, sizeof(buf) - 1, "%d ", i); if(!(j%10)) _dpd.printfappend(buf, sizeof(buf) - 1, "\n "); } } _dpd.logMsg("%s\n", buf); _dpd.logMsg(" IMAP Memcap: %u\n", config->memcap); _dpd.logMsg(" MIME Max Mem: %d\n", config->max_mime_mem); if(config->b64_depth > -1) { _dpd.logMsg(" Base64 Decoding: %s\n", "Enabled"); switch(config->b64_depth) { case 0: _dpd.logMsg(" Base64 Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Base64 Decoding Depth: %d\n", config->b64_depth); break; } } else _dpd.logMsg(" Base64 Decoding: %s\n", "Disabled"); if(config->qp_depth > -1) { _dpd.logMsg(" Quoted-Printable Decoding: %s\n","Enabled"); switch(config->qp_depth) { case 0: _dpd.logMsg(" Quoted-Printable Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Quoted-Printable Decoding Depth: %d\n", config->qp_depth); break; } } else _dpd.logMsg(" Quoted-Printable Decoding: %s\n", "Disabled"); if(config->uu_depth > -1) { _dpd.logMsg(" Unix-to-Unix Decoding: %s\n","Enabled"); switch(config->uu_depth) { case 0: _dpd.logMsg(" Unix-to-Unix Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Unix-to-Unix Decoding Depth: %d\n", config->uu_depth); break; } } else _dpd.logMsg(" Unix-to-Unix Decoding: %s\n", "Disabled"); if(config->bitenc_depth > -1) { _dpd.logMsg(" Non-Encoded MIME attachment Extraction: %s\n","Enabled"); switch(config->bitenc_depth) { case 0: _dpd.logMsg(" Non-Encoded MIME attachment Extraction Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Non-Encoded MIME attachment Extraction Depth: %d\n", config->bitenc_depth); break; } } else _dpd.logMsg(" Non-Encoded MIME attachment Extraction: %s\n", "Disabled"); } /* ** NAME ** ProcessPorts:: */ /** ** Process the port list. ** ** This configuration is a list of valid ports and is ended by a ** delimiter. ** ** @param ErrorString error string buffer ** @param ErrStrLen the length of the error string buffer ** ** @return an error code integer ** (0 = success, >0 = non-fatal error, <0 = fatal error) ** ** @retval 0 successs ** @retval -1 generic fatal error ** @retval 1 generic non-fatal error */ static int ProcessPorts(IMAPConfig *config, char *ErrorString, int ErrStrLen) { char *pcToken; char *pcEnd; int iPort; int iEndPorts = 0; int num_ports = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "IMAP config is NULL.\n"); return -1; } pcToken = strtok(NULL, CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid port list format."); return -1; } if(strcmp(CONF_START_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a port list with the '%s' token.", CONF_START_LIST); return -1; } /* Since ports are specified, clear default ports */ config->ports[IMAP_DEFAULT_SERVER_PORT / 8] &= ~(1 << (IMAP_DEFAULT_SERVER_PORT % 8)); while ((pcToken = strtok(NULL, CONF_SEPARATORS)) != NULL) { if(!strcmp(CONF_END_LIST, pcToken)) { iEndPorts = 1; break; } iPort = strtol(pcToken, &pcEnd, 10); /* ** Validity check for port */ if(*pcEnd) { snprintf(ErrorString, ErrStrLen, "Invalid port number."); return -1; } if(iPort < 0 || iPort > MAXPORTS-1) { snprintf(ErrorString, ErrStrLen, "Invalid port number. Must be between 0 and 65535."); return -1; } config->ports[iPort / 8] |= (1 << (iPort % 8)); num_ports++; } if(!iEndPorts) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", CONF_PORTS, CONF_END_LIST); return -1; } else if(!num_ports) { snprintf(ErrorString, ErrStrLen, "IMAP: Empty port list not allowed."); return -1; } return 0; } static int ProcessDecodeDepth(IMAPConfig *config, char *ErrorString, int ErrStrLen, char *decode_type, DecodeType type) { char *endptr; char *value; int decode_depth = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "IMAP config is NULL.\n"); return -1; } value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) { snprintf(ErrorString, ErrStrLen, "Invalid format for IMAP config option '%s'.", decode_type); return -1; } decode_depth = strtol(value, &endptr, 10); if(*endptr) { snprintf(ErrorString, ErrStrLen, "Invalid format for IMAP config option '%s'.", decode_type); return -1; } if(decode_depth < MIN_DEPTH || decode_depth > MAX_DEPTH) { snprintf(ErrorString, ErrStrLen, "Invalid value for IMAP config option '%s'." "It should range between %d and %d.", decode_type, MIN_DEPTH, MAX_DEPTH); return -1; } switch(type) { case DECODE_B64: if((decode_depth > 0) && (decode_depth & 3)) { decode_depth += 4 - (decode_depth & 3); if(decode_depth > MAX_DEPTH ) { decode_depth = decode_depth - 4; } _dpd.logMsg("WARNING: %s(%d) => IMAP: 'b64_decode_depth' is not a multiple of 4. " "Rounding up to the next multiple of 4. The new 'b64_decode_depth' is %d.\n", *(_dpd.config_file), *(_dpd.config_line), decode_depth); } config->b64_depth = decode_depth; break; case DECODE_QP: config->qp_depth = decode_depth; break; case DECODE_UU: config->uu_depth = decode_depth; break; case DECODE_BITENC: config->bitenc_depth = decode_depth; break; default: return -1; } return 0; } snort-2.9.6.0/src/dynamic-preprocessors/imap/Makefile.am0000644000000000000000000000157111746560364020046 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_imap_preproc.la libsf_imap_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_imap_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_imap_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/mempool.c \ ../include/sf_sdlist.c \ ../include/sf_base64decode.c \ ../include/util_unfold.c \ ../include/sf_email_attach_decode.c \ ../include/sfPolicyUserData.c endif libsf_imap_preproc_la_SOURCES = \ imap_config.c \ imap_config.h \ imap_log.c \ imap_log.h \ imap_util.c \ imap_util.h \ snort_imap.c \ snort_imap.h \ spp_imap.c \ spp_imap.h EXTRA_DIST = \ sf_imap.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/imap/Makefile.in0000644000000000000000000005510112260606522020042 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/imap DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_imap_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_imap_preproc_la_OBJECTS = imap_config.lo imap_log.lo \ imap_util.lo snort_imap.lo spp_imap.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_imap_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo mempool.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_sdlist.lo sf_base64decode.lo \ @SO_WITH_STATIC_LIB_FALSE@ util_unfold.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_email_attach_decode.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_imap_preproc_la_OBJECTS = $(am_libsf_imap_preproc_la_OBJECTS) \ $(nodist_libsf_imap_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_imap_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_imap_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_imap_preproc_la_SOURCES) \ $(nodist_libsf_imap_preproc_la_SOURCES) DIST_SOURCES = $(libsf_imap_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_imap_preproc.la libsf_imap_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_imap_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_imap_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/mempool.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_sdlist.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_base64decode.c \ @SO_WITH_STATIC_LIB_FALSE@../include/util_unfold.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_email_attach_decode.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_imap_preproc_la_SOURCES = \ imap_config.c \ imap_config.h \ imap_log.c \ imap_log.h \ imap_util.c \ imap_util.h \ snort_imap.c \ snort_imap.h \ spp_imap.c \ spp_imap.h EXTRA_DIST = \ sf_imap.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/imap/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/imap/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_imap_preproc.la: $(libsf_imap_preproc_la_OBJECTS) $(libsf_imap_preproc_la_DEPENDENCIES) $(EXTRA_libsf_imap_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_imap_preproc_la_LINK) -rpath $(libdir) $(libsf_imap_preproc_la_OBJECTS) $(libsf_imap_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c mempool.lo: ../include/mempool.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mempool.lo `test -f '../include/mempool.c' || echo '$(srcdir)/'`../include/mempool.c sf_sdlist.lo: ../include/sf_sdlist.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_sdlist.lo `test -f '../include/sf_sdlist.c' || echo '$(srcdir)/'`../include/sf_sdlist.c sf_base64decode.lo: ../include/sf_base64decode.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_base64decode.lo `test -f '../include/sf_base64decode.c' || echo '$(srcdir)/'`../include/sf_base64decode.c util_unfold.lo: ../include/util_unfold.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util_unfold.lo `test -f '../include/util_unfold.c' || echo '$(srcdir)/'`../include/util_unfold.c sf_email_attach_decode.lo: ../include/sf_email_attach_decode.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_email_attach_decode.lo `test -f '../include/sf_email_attach_decode.c' || echo '$(srcdir)/'`../include/sf_email_attach_decode.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/pop/0000755000000000000000000000000012260606563015730 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/pop/sf_pop.dsp0000644000000000000000000001444312153454770017656 00000000000000# Microsoft Developer Studio Project File - Name="sf_pop" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_pop - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_pop.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_pop.mak" CFG="sf_pop - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_pop - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_pop - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_pop - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_POP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 pcre.lib ws2_32.lib ../libs/Release/sfdynamic_preproc_libs.lib /nologo /dll /machine:I386 /libpath:"../../../src/win32/WIN32-Libraries" !ELSEIF "$(CFG)" == "sf_pop - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_POP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 pcre.lib ws2_32.lib ../libs/Debug/sfdynamic_preproc_libs.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../src/win32/WIN32-Libraries" !ENDIF # Begin Target # Name "sf_pop - Win32 Release" # Name "sf_pop - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\include\mempool.c # End Source File # Begin Source File SOURCE=.\pop_config.c # End Source File # Begin Source File SOURCE=.\pop_log.c # End Source File # Begin Source File SOURCE=.\pop_util.c # End Source File # Begin Source File SOURCE=..\include\sf_base64decode.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_email_attach_decode.c # End Source File # Begin Source File SOURCE=..\include\sf_sdlist.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=.\snort_pop.c # End Source File # Begin Source File SOURCE=.\spp_pop.c # End Source File # Begin Source File SOURCE=..\include\util_unfold.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\mempool.h # End Source File # Begin Source File SOURCE=.\pop_config.h # End Source File # Begin Source File SOURCE=.\pop_log.h # End Source File # Begin Source File SOURCE=.\pop_util.h # End Source File # Begin Source File SOURCE=..\include\sf_base64decode.h # End Source File # Begin Source File SOURCE=..\include\sf_email_attach_decode.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=..\include\sf_sdlist.h # End Source File # Begin Source File SOURCE=.\snort_pop.h # End Source File # Begin Source File SOURCE=.\spp_pop.h # End Source File # Begin Source File SOURCE=..\include\util_unfold.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/pop/spp_pop.h0000644000000000000000000000222112260565732017500 00000000000000 /* * spp_pop.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * Author: Bhagyashree Bantwal * * Description: * * This file defines the publicly available functions for the POP * functionality for Snort. * */ #ifndef __SPP_POP_H__ #define __SPP_POP_H__ void SetupPOP(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/pop/spp_pop.c0000644000000000000000000005070512260565732017505 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * spp_pop.c * * Author: Bhagyashree Bantwal * * Description: * * This file initializes POP as a Snort preprocessor. * * This file registers the POP initialization function, * adds the POP function into the preprocessor list. * * In general, this file is a wrapper to POP functionality, * by interfacing with the Snort preprocessor functions. The rest * of POP should be separate from the preprocessor hooks. * **************************************************************************/ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "spp_pop.h" #include "sf_preproc_info.h" #include "snort_pop.h" #include "pop_config.h" #include "pop_log.h" #include "preprocids.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #include "snort_debug.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "profiler.h" #ifdef PERF_PROFILING PreprocStats popPerfStats; PreprocStats popDetectPerfStats; int popDetectCalled = 0; #endif #include "sf_types.h" #include "mempool.h" #include "snort_bounds.h" #include "file_api.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 0; const int BUILD_VERSION = 1; const char *PREPROC_NAME = "SF_POP"; const char *PROTOCOL_NAME = "POP"; #define SetupPOP DYNAMIC_PREPROC_SETUP MemPool *pop_mime_mempool = NULL; MemPool *pop_mempool = NULL; tSfPolicyUserContextId pop_config = NULL; POPConfig *pop_eval_config = NULL; extern POP pop_no_session; extern int16_t pop_proto_id; static void POPInit(struct _SnortConfig *, char *); static void POPDetect(void *, void *context); static void POPCleanExitFunction(int, void *); static void POPResetFunction(int, void *); static void POPResetStatsFunction(int, void *); static void _addPortsToStream5Filter(struct _SnortConfig *, POPConfig *, tSfPolicyId); #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *, tSfPolicyId); #endif static int POPCheckConfig(struct _SnortConfig *); #ifdef SNORT_RELOAD static void POPReload(struct _SnortConfig *, char *, void **); static int POPReloadVerify(struct _SnortConfig *, void *); static void * POPReloadSwap(struct _SnortConfig *, void *); static void POPReloadSwapFree(void *); #endif /* * Function: SetupPOP() * * Purpose: Registers the preprocessor keyword and initialization * function into the preprocessor list. This is the function that * gets called from InitPreprocessors() in plugbase.c. * * Arguments: None. * * Returns: void function * */ void SetupPOP(void) { /* link the preprocessor keyword to the init function in the preproc list */ #ifndef SNORT_RELOAD _dpd.registerPreproc("pop", POPInit); #else _dpd.registerPreproc("pop", POPInit, POPReload, POPReloadVerify, POPReloadSwap, POPReloadSwapFree); #endif } /* * Function: POPInit(char *) * * Purpose: Calls the argument parsing function, performs final setup on data * structs, links the preproc function into the function list. * * Arguments: args => ptr to argument string * * Returns: void function * */ static void POPInit(struct _SnortConfig *sc, char *args) { POPToken *tmp; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); POPConfig * pPolicyConfig = NULL; if (pop_config == NULL) { //create a context pop_config = sfPolicyConfigCreate(); if (pop_config == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create POP " "configuration.\n"); } /* Initialize the searches not dependent on configuration. * headers, reponsed, data, mime boundary regular expression */ POP_SearchInit(); /* zero out static POP global used for stateless POP or if there * is no session pointer */ memset(&pop_no_session, 0, sizeof(POP)); /* Put the preprocessor function into the function list */ /* _dpd.addPreproc(POPDetect, PRIORITY_APPLICATION, PP_POP, PROTO_BIT__TCP);*/ _dpd.addPreprocExit(POPCleanExitFunction, NULL, PRIORITY_LAST, PP_POP); _dpd.addPreprocReset(POPResetFunction, NULL, PRIORITY_LAST, PP_POP); _dpd.addPreprocResetStats(POPResetStatsFunction, NULL, PRIORITY_LAST, PP_POP); _dpd.addPreprocConfCheck(sc, POPCheckConfig); #ifdef TARGET_BASED pop_proto_id = _dpd.findProtocolReference(POP_PROTO_REF_STR); if (pop_proto_id == SFTARGET_UNKNOWN_PROTOCOL) pop_proto_id = _dpd.addProtocolReference(POP_PROTO_REF_STR); DEBUG_WRAP(DebugMessage(DEBUG_POP,"POP: Target-based: Proto id for %s: %u.\n", POP_PROTO_REF_STR, pop_proto_id);); #endif #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("pop", (void*)&popPerfStats, 0, _dpd.totalPerfStats); #endif } sfPolicyUserPolicySet (pop_config, policy_id); pPolicyConfig = (POPConfig *)sfPolicyUserDataGetCurrent(pop_config); if (pPolicyConfig != NULL) { DynamicPreprocessorFatalMessage("Can only configure POP preprocessor once.\n"); } pPolicyConfig = (POPConfig *)calloc(1, sizeof(POPConfig)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create POP " "configuration.\n"); } sfPolicyUserDataSetCurrent(pop_config, pPolicyConfig); POP_InitCmds(pPolicyConfig); POP_ParseArgs(pPolicyConfig, args); POP_CheckConfig(pPolicyConfig, pop_config); POP_PrintConfig(pPolicyConfig); if(pPolicyConfig->disabled) return; _dpd.addPreproc(sc, POPDetect, PRIORITY_APPLICATION, PP_POP, PROTO_BIT__TCP); if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled " "for POP preprocessor\n"); } /* Command search - do this here because it's based on configuration */ pPolicyConfig->cmd_search_mpse = _dpd.searchAPI->search_instance_new(); if (pPolicyConfig->cmd_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate POP " "command search.\n"); } for (tmp = pPolicyConfig->cmds; tmp->name != NULL; tmp++) { pPolicyConfig->cmd_search[tmp->search_id].name = tmp->name; pPolicyConfig->cmd_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pPolicyConfig->cmd_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pPolicyConfig->cmd_search_mpse); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } /* * Function: POPDetect(void *, void *) * * Purpose: Perform the preprocessor's intended function. This can be * simple (statistics collection) or complex (IP defragmentation) * as you like. Try not to destroy the performance of the whole * system by trying to do too much.... * * Arguments: p => pointer to the current packet data struct * * Returns: void function * */ static void POPDetect(void *pkt, void *context) { SFSnortPacket *p = (SFSnortPacket *)pkt; tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; // preconditions - what we registered for assert(IsTCP(p) && p->payload && p->payload_size); PREPROC_PROFILE_START(popPerfStats); DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP Start (((((((((((((((((((((((((((((((((((((((\n");); sfPolicyUserPolicySet (pop_config, policy_id); SnortPOP(p); DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP End )))))))))))))))))))))))))))))))))))))))))\n\n");); PREPROC_PROFILE_END(popPerfStats); #ifdef PERF_PROFILING if (PROFILING_PREPROCS && popDetectCalled) { popPerfStats.ticks -= popDetectPerfStats.ticks; /* And Reset ticks to 0 */ popDetectPerfStats.ticks = 0; popDetectCalled = 0; } #endif } /* * Function: POPCleanExitFunction(int, void *) * * Purpose: This function gets called when Snort is exiting, if there's * any cleanup that needs to be performed (e.g. closing files) * it should be done here. * * Arguments: signal => the code of the signal that was issued to Snort * data => any arguments or data structs linked to this * function when it was registered, may be * needed to properly exit * * Returns: void function */ static void POPCleanExitFunction(int signal, void *data) { POP_Free(); if (mempool_destroy(pop_mime_mempool) == 0) { free(pop_mime_mempool); pop_mime_mempool = NULL; } if (mempool_destroy(pop_mempool) == 0) { free(pop_mempool); pop_mempool = NULL; } } static void POPResetFunction(int signal, void *data) { return; } static void POPResetStatsFunction(int signal, void *data) { return; } static void _addPortsToStream5Filter(struct _SnortConfig *sc, POPConfig *config, tSfPolicyId policy_id) { unsigned int portNum; if (config == NULL) return; for (portNum = 0; portNum < MAXPORTS; portNum++) { if(config->ports[(portNum/8)] & (1<<(portNum%8))) { //Add port the port _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_TCP, (uint16_t)portNum, PORT_MONITOR_SESSION, policy_id, 1); _dpd.fileAPI->register_mime_paf_port(sc, portNum, policy_id); } } } #ifdef TARGET_BASED static void _addServicesToStream5Filter(struct _SnortConfig *sc, tSfPolicyId policy_id) { _dpd.streamAPI->set_service_filter_status(sc, pop_proto_id, PORT_MONITOR_SESSION, policy_id, 1); _dpd.fileAPI->register_mime_paf_service(sc, pop_proto_id, policy_id); } #endif static int CheckFilePolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { POPConfig *context = (POPConfig *)pData; context->file_depth = _dpd.fileAPI->get_max_file_depth(); if (context->file_depth > -1) context->log_config.log_filename = 1; updateMaxDepth(context->file_depth, &context->max_depth); return 0; } static int POPEnableDecoding(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void *pData) { POPConfig *context = (POPConfig *)pData; if (pData == NULL) return 0; if(context->disabled) return 0; if(!POP_IsDecodingEnabled(context)) return 1; return 0; } static int POPLogExtraData(struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void *pData) { POPConfig *context = (POPConfig *)pData; if (pData == NULL) return 0; if(context->disabled) return 0; if(context->log_config.log_filename) return 1; return 0; } static int POPCheckPolicyConfig( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { POPConfig *context = (POPConfig *)pData; _dpd.setParserPolicy(sc, policyId); /* In a multiple-policy setting, the POP preproc can be turned on in a "disabled" state. In this case, we don't require Stream5. */ if (context->disabled) return 0; if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("Streaming & reassembly must be enabled for POP preprocessor\n"); return -1; } return 0; } static int POPCheckConfig(struct _SnortConfig *sc) { int rval; POPConfig *defaultConfig = (POPConfig *)sfPolicyUserDataGetDefault(pop_config); if ((rval = sfPolicyUserDataIterate (sc, pop_config, POPCheckPolicyConfig))) return rval; if ((rval = sfPolicyUserDataIterate (sc, pop_config, CheckFilePolicyConfig))) return rval; if (sfPolicyUserDataIterate(sc, pop_config, POPEnableDecoding) != 0) { if (defaultConfig == NULL) { /*error message */ _dpd.errMsg("POP: Must configure a default " "configuration if you want to pop decoding.\n"); return -1; } pop_mime_mempool = (MemPool *)_dpd.fileAPI->init_mime_mempool(defaultConfig->max_mime_mem, defaultConfig->max_depth, pop_mime_mempool, PROTOCOL_NAME); } if (sfPolicyUserDataIterate(sc, pop_config, POPLogExtraData) != 0) { pop_mempool = (MemPool *)_dpd.fileAPI->init_log_mempool(0, defaultConfig->memcap, pop_mempool, PROTOCOL_NAME); } return 0; } #ifdef SNORT_RELOAD static void POPReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId pop_swap_config = (tSfPolicyUserContextId)*new_config; POPToken *tmp; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); POPConfig *pPolicyConfig = NULL; if (pop_swap_config == NULL) { //create a context pop_swap_config = sfPolicyConfigCreate(); if (pop_swap_config == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create POP " "configuration.\n"); } *new_config = (void *)pop_swap_config; } sfPolicyUserPolicySet (pop_swap_config, policy_id); pPolicyConfig = (POPConfig *)sfPolicyUserDataGetCurrent(pop_swap_config); if (pPolicyConfig != NULL) DynamicPreprocessorFatalMessage("Can only configure POP preprocessor once.\n"); pPolicyConfig = (POPConfig *)calloc(1, sizeof(POPConfig)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("Not enough memory to create POP " "configuration.\n"); } sfPolicyUserDataSetCurrent(pop_swap_config, pPolicyConfig); POP_InitCmds(pPolicyConfig); POP_ParseArgs(pPolicyConfig, args); POP_CheckConfig(pPolicyConfig, pop_swap_config); POP_PrintConfig(pPolicyConfig); if( pPolicyConfig->disabled ) return; if (_dpd.streamAPI == NULL) { DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled " "for POP preprocessor\n"); } /* Command search - do this here because it's based on configuration */ pPolicyConfig->cmd_search_mpse = _dpd.searchAPI->search_instance_new(); if (pPolicyConfig->cmd_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate POP " "command search.\n"); } for (tmp = pPolicyConfig->cmds; tmp->name != NULL; tmp++) { pPolicyConfig->cmd_search[tmp->search_id].name = tmp->name; pPolicyConfig->cmd_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pPolicyConfig->cmd_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pPolicyConfig->cmd_search_mpse); _dpd.addPreproc(sc, POPDetect, PRIORITY_APPLICATION, PP_POP, PROTO_BIT__TCP); _addPortsToStream5Filter(sc, pPolicyConfig, policy_id); #ifdef TARGET_BASED _addServicesToStream5Filter(sc, policy_id); #endif } static int POPReloadVerify(struct _SnortConfig *sc, void *swap_config) { int rval; tSfPolicyUserContextId pop_swap_config = (tSfPolicyUserContextId)swap_config; POPConfig *config = NULL; POPConfig *configNext = NULL; if (pop_swap_config == NULL) return 0; if (pop_config != NULL) { config = (POPConfig *)sfPolicyUserDataGet(pop_config, _dpd.getDefaultPolicy()); } configNext = (POPConfig *)sfPolicyUserDataGet(pop_swap_config, _dpd.getDefaultPolicy()); if (config == NULL) { return 0; } if ((rval = sfPolicyUserDataIterate (sc, pop_swap_config, CheckFilePolicyConfig))) { return rval; } if (pop_mime_mempool != NULL) { if (configNext == NULL) { _dpd.errMsg("POP reload: Changing the POP configuration requires a restart.\n"); return -1; } if (configNext->max_mime_mem != config->max_mime_mem) { _dpd.errMsg("POP reload: Changing the memcap requires a restart.\n"); return -1; } if(configNext->b64_depth != config->b64_depth) { _dpd.errMsg("POP reload: Changing the b64_decode_depth requires a restart.\n"); return -1; } if(configNext->qp_depth != config->qp_depth) { _dpd.errMsg("POP reload: Changing the qp_decode_depth requires a restart.\n"); return -1; } if(configNext->bitenc_depth != config->bitenc_depth) { _dpd.errMsg("POP reload: Changing the bitenc_decode_depth requires a restart.\n"); return -1; } if(configNext->uu_depth != config->uu_depth) { _dpd.errMsg("POP reload: Changing the uu_decode_depth requires a restart.\n"); return -1; } if(configNext->file_depth != config->file_depth) { _dpd.errMsg("POP reload: Changing the file_depth requires a restart.\n"); return -1; } } if (pop_mempool != NULL) { if (configNext == NULL) { _dpd.errMsg("POP reload: Changing the memcap requires a restart.\n"); return -1; } if (configNext->memcap != config->memcap) { _dpd.errMsg("POP reload: Changing the memcap requires a restart.\n"); return -1; } } else if(configNext != NULL) { if (sfPolicyUserDataIterate(sc, pop_swap_config, POPEnableDecoding) != 0) { pop_mime_mempool = (MemPool *)_dpd.fileAPI->init_mime_mempool(configNext->max_mime_mem, configNext->max_depth, pop_mime_mempool, PREPROC_NAME); } if (sfPolicyUserDataIterate(sc, pop_swap_config, POPLogExtraData) != 0) { pop_mempool = (MemPool *)_dpd.fileAPI->init_log_mempool(0, configNext->memcap, pop_mempool, PREPROC_NAME); } if ( configNext->disabled ) return 0; } if (!_dpd.isPreprocEnabled(sc, PP_STREAM5)) { _dpd.errMsg("Streaming & reassembly must be enabled " "for POP preprocessor\n"); return -1; } return 0; } static int POPReloadSwapPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { POPConfig *pPolicyConfig = (POPConfig *)pData; if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); POP_FreeConfig(pPolicyConfig); } return 0; } static void * POPReloadSwap(struct _SnortConfig *sc, void *swap_config) { tSfPolicyUserContextId pop_swap_config = (tSfPolicyUserContextId)swap_config; tSfPolicyUserContextId old_config = pop_config; if (pop_swap_config == NULL) return NULL; pop_config = pop_swap_config; sfPolicyUserDataFreeIterate (old_config, POPReloadSwapPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) return old_config; return NULL; } static void POPReloadSwapFree(void *data) { if (data == NULL) return; POP_FreeConfigs((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/pop/snort_pop.h0000644000000000000000000001352312260565732020052 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * **************************************************************************/ /************************************************************************** * * snort_pop.h * * Author: Bhagyashree Bantwal * * Description: * * This file defines everything specific to the POP preprocessor. * **************************************************************************/ #ifndef __POP_H__ #define __POP_H__ /* Includes ***************************************************************/ #include #include "sf_snort_packet.h" #include "pop_config.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "mempool.h" #include "sf_email_attach_decode.h" #include "file_api.h" #ifdef DEBUG #include "sf_types.h" #endif /**************************************************************************/ /* Defines ****************************************************************/ /* Direction packet is coming from, if we can figure it out */ #define POP_PKT_FROM_UNKNOWN 0 #define POP_PKT_FROM_CLIENT 1 #define POP_PKT_FROM_SERVER 2 #define SEARCH_CMD 0 #define SEARCH_RESP 1 #define SEARCH_HDR 2 #define SEARCH_DATA_END 3 #define NUM_SEARCHES 4 #define BOUNDARY 0 #define MAX_BOUNDARY_LEN 70 /* Max length of boundary string, defined in RFC 2046 */ #define STATE_DATA 0 /* Data state */ #define STATE_UNKNOWN 1 #define STATE_DATA_INIT 0 #define STATE_DATA_HEADER 1 /* Data header section of data state */ #define STATE_DATA_BODY 2 /* Data body section of data state */ #define STATE_MIME_HEADER 3 /* MIME header section within data section */ #define STATE_DATA_UNKNOWN 4 /* state flags */ #define POP_FLAG_FOLDING 0x00000001 #define POP_FLAG_IN_CONTENT_TYPE 0x00000002 #define POP_FLAG_GOT_BOUNDARY 0x00000004 #define POP_FLAG_DATA_HEADER_CONT 0x00000008 #define POP_FLAG_IN_CONT_TRANS_ENC 0x00000010 #define POP_FLAG_EMAIL_ATTACH 0x00000020 #define POP_FLAG_MULTIPLE_EMAIL_ATTACH 0x00000040 #define POP_FLAG_IN_CONT_DISP 0x00000200 #define POP_FLAG_IN_CONT_DISP_CONT 0x00000400 #define POP_FLAG_MIME_END 0x00000800 /* log flags */ #define POP_FLAG_FILENAME_PRESENT 0x00000004 /* session flags */ #define POP_FLAG_NEXT_STATE_UNKNOWN 0x00000004 #define POP_FLAG_GOT_NON_REBUILT 0x00000008 #define POP_SSL_ERROR_FLAGS (SSL_BOGUS_HS_DIR_FLAG | \ SSL_BAD_VER_FLAG | \ SSL_BAD_TYPE_FLAG | \ SSL_UNKNOWN_FLAG) /* Maximum length of header chars before colon, based on Exim 4.32 exploit */ #define MAX_HEADER_NAME_LEN 64 #define POP_PROTO_REF_STR "pop3" /**************************************************************************/ /* Data structures ********************************************************/ typedef enum _POPCmdEnum { CMD_APOP = 0, CMD_AUTH, CMD_CAPA, CMD_DELE, CMD_LIST, CMD_NOOP, CMD_PASS, CMD_QUIT, CMD_RETR, CMD_RSET, CMD_STAT, CMD_STLS, CMD_TOP, CMD_UIDL, CMD_USER, CMD_LAST } POPCmdEnum; typedef enum _POPRespEnum { RESP_OK = 1, RESP_ERR, RESP_LAST } POPRespEnum; typedef enum _POPHdrEnum { HDR_CONTENT_TYPE = 0, HDR_CONT_TRANS_ENC, HDR_CONT_DISP, HDR_LAST } POPHdrEnum; typedef enum _POPDataEndEnum { DATA_END_1 = 0, DATA_END_2, DATA_END_3, DATA_END_4, DATA_END_LAST } POPDataEndEnum; typedef struct _POPSearchInfo { int id; int index; int length; } POPSearchInfo; typedef struct _POPMimeBoundary { int state; char boundary[2 + MAX_BOUNDARY_LEN + 1]; /* '--' + MIME boundary string + '\0' */ int boundary_len; void *boundary_search; } POPMimeBoundary; typedef struct _POPPcre { pcre *re; pcre_extra *pe; } POPPcre; typedef struct _POP { int state; int prev_response; int data_state; int state_flags; int log_flags; int session_flags; int alert_mask; int reassembling; #ifdef DEBUG_MSGS uint64_t session_number; #endif MemBucket *decode_bkt; POPMimeBoundary mime_boundary; Email_DecodeState *decode_state; MAIL_LogState *log_state; tSfPolicyId policy_id; tSfPolicyUserContextId config; } POP; /**************************************************************************/ /* Function prototypes ****************************************************/ void POP_InitCmds(POPConfig *config); void POP_SearchInit(void); void POP_Free(void); void SnortPOP(SFSnortPacket *); int POP_IsServer(uint16_t); void POP_FreeConfig(POPConfig *); void POP_FreeConfigs(tSfPolicyUserContextId); int POP_GetFilename(void *data, uint8_t **buf, uint32_t *len, uint32_t *type); /**************************************************************************/ #endif /* __POP_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/pop/snort_pop.c0000644000000000000000000015705312260565732020054 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * snort_pop.c * * Author: Bhagyashree Bantwal * * Description: * * This file handles POP protocol checking and normalization. * * Entry point functions: * * SnortPOP() * POP_Init() * POP_Free() * **************************************************************************/ /* Includes ***************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "sf_types.h" #include "snort_pop.h" #include "pop_config.h" #include "pop_util.h" #include "pop_log.h" #include "sf_snort_packet.h" #include "stream_api.h" #include "snort_debug.h" #include "profiler.h" #include "snort_bounds.h" #include "sf_dynamic_preprocessor.h" #include "ssl.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "file_api.h" #ifdef DEBUG_MSGS #include "sf_types.h" #endif /**************************************************************************/ /* Externs ****************************************************************/ #ifdef PERF_PROFILING extern PreprocStats popDetectPerfStats; extern int popDetectCalled; #endif extern tSfPolicyUserContextId pop_config; extern POPConfig *pop_eval_config; extern MemPool *pop_mime_mempool; extern MemPool *pop_mempool; #ifdef DEBUG_MSGS extern char pop_print_buffer[]; #endif /**************************************************************************/ /* Globals ****************************************************************/ const POPToken pop_known_cmds[] = { {"APOP", 4, CMD_APOP}, {"AUTH", 4, CMD_AUTH}, {"CAPA", 4, CMD_CAPA}, {"DELE", 4, CMD_DELE}, {"LIST", 4, CMD_LIST}, {"NOOP", 4, CMD_NOOP}, {"PASS", 4, CMD_PASS}, {"QUIT", 4, CMD_QUIT}, {"RETR", 4, CMD_RETR}, {"RSET", 4, CMD_RSET}, {"STAT", 4, CMD_STAT}, {"STLS", 4, CMD_STLS}, {"TOP", 3, CMD_TOP}, {"UIDL", 4, CMD_UIDL}, {"USER", 4, CMD_USER}, {NULL, 0, 0} }; const POPToken pop_resps[] = { {"+OK", 3, RESP_OK}, /* SUCCESS */ {"-ERR", 4, RESP_ERR}, /* FAILURE */ {NULL, 0, 0} }; const POPToken pop_hdrs[] = { {"Content-type:", 13, HDR_CONTENT_TYPE}, {"Content-Transfer-Encoding:", 26, HDR_CONT_TRANS_ENC}, {"Content-Disposition:", 20, HDR_CONT_DISP}, {NULL, 0, 0} }; const POPToken pop_data_end[] = { {"\r\n.\r\n", 5, DATA_END_1}, {"\n.\r\n", 4, DATA_END_2}, {"\r\n.\n", 4, DATA_END_3}, {"\n.\n", 3, DATA_END_4}, {NULL, 0, 0} }; POP *pop_ssn = NULL; POP pop_no_session; POPPcre mime_boundary_pcre; char pop_normalizing; POPSearchInfo pop_search_info; #ifdef DEBUG_MSGS uint64_t pop_session_counter = 0; #endif #ifdef TARGET_BASED int16_t pop_proto_id; #endif void *pop_resp_search_mpse = NULL; POPSearch pop_resp_search[RESP_LAST]; void *pop_hdr_search_mpse = NULL; POPSearch pop_hdr_search[HDR_LAST]; void *pop_data_search_mpse = NULL; POPSearch pop_data_end_search[DATA_END_LAST]; POPSearch *pop_current_search = NULL; /**************************************************************************/ /* Private functions ******************************************************/ static int POP_Setup(SFSnortPacket *p, POP *ssn); static void POP_ResetState(void); static void POP_SessionFree(void *); static void POP_NoSessionFree(void); static int POP_GetPacketDirection(SFSnortPacket *, int); static void POP_ProcessClientPacket(SFSnortPacket *); static void POP_ProcessServerPacket(SFSnortPacket *); static void POP_DisableDetect(SFSnortPacket *); static const uint8_t * POP_HandleCommand(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * POP_HandleData(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * POP_HandleHeader(SFSnortPacket *, const uint8_t *, const uint8_t *); static const uint8_t * POP_HandleDataBody(SFSnortPacket *, const uint8_t *, const uint8_t *); static int POP_SearchStrFound(void *, void *, int, void *, void *); static int POP_BoundaryStrFound(void *, void *, int , void *, void *); static int POP_GetBoundary(const char *, int); static int POP_Inspect(SFSnortPacket *); /**************************************************************************/ static void SetPopBuffers(POP *ssn) { if ((ssn != NULL) && (ssn->decode_state == NULL)) { MemBucket *bkt = mempool_alloc(pop_mime_mempool); if (bkt != NULL) { ssn->decode_state = (Email_DecodeState *)calloc(1, sizeof(Email_DecodeState)); if( ssn->decode_state != NULL ) { ssn->decode_bkt = bkt; SetEmailDecodeState(ssn->decode_state, bkt->data, pop_eval_config->max_depth, pop_eval_config->b64_depth, pop_eval_config->qp_depth, pop_eval_config->uu_depth, pop_eval_config->bitenc_depth, pop_eval_config->file_depth); } else { /*free mempool if calloc fails*/ mempool_free(pop_mime_mempool, bkt); } } else { POP_GenerateAlert(POP_MEMCAP_EXCEEDED, "%s", POP_MEMCAP_EXCEEDED_STR); DEBUG_WRAP(DebugMessage(DEBUG_POP, "No memory available for decoding. Memcap exceeded \n");); } } } void POP_InitCmds(POPConfig *config) { const POPToken *tmp; if (config == NULL) return; /* add one to CMD_LAST for NULL entry */ config->cmds = (POPToken *)calloc(CMD_LAST + 1, sizeof(POPToken)); if (config->cmds == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for pop " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } for (tmp = &pop_known_cmds[0]; tmp->name != NULL; tmp++) { config->cmds[tmp->search_id].name_len = tmp->name_len; config->cmds[tmp->search_id].search_id = tmp->search_id; config->cmds[tmp->search_id].name = strdup(tmp->name); if (config->cmds[tmp->search_id].name == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for pop " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } } /* initialize memory for command searches */ config->cmd_search = (POPSearch *)calloc(CMD_LAST, sizeof(POPSearch)); if (config->cmd_search == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => failed to allocate memory for pop " "command structure\n", *(_dpd.config_file), *(_dpd.config_line)); } config->num_cmds = CMD_LAST; } /* * Initialize POP searches * * @param none * * @return none */ void POP_SearchInit(void) { const char *error; int erroffset; const POPToken *tmp; /* Response search */ pop_resp_search_mpse = _dpd.searchAPI->search_instance_new(); if (pop_resp_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate POP " "response search.\n"); } for (tmp = &pop_resps[0]; tmp->name != NULL; tmp++) { pop_resp_search[tmp->search_id].name = tmp->name; pop_resp_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pop_resp_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pop_resp_search_mpse); /* Header search */ pop_hdr_search_mpse = _dpd.searchAPI->search_instance_new(); if (pop_hdr_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate POP " "header search.\n"); } for (tmp = &pop_hdrs[0]; tmp->name != NULL; tmp++) { pop_hdr_search[tmp->search_id].name = tmp->name; pop_hdr_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pop_hdr_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pop_hdr_search_mpse); /* Data end search */ pop_data_search_mpse = _dpd.searchAPI->search_instance_new(); if (pop_data_search_mpse == NULL) { DynamicPreprocessorFatalMessage("Could not allocate POP " "data search.\n"); } for (tmp = &pop_data_end[0]; tmp->name != NULL; tmp++) { pop_data_end_search[tmp->search_id].name = tmp->name; pop_data_end_search[tmp->search_id].name_len = tmp->name_len; _dpd.searchAPI->search_instance_add(pop_data_search_mpse, tmp->name, tmp->name_len, tmp->search_id); } _dpd.searchAPI->search_instance_prep(pop_data_search_mpse); /* create regex for finding boundary string - since it can be cut across multiple * lines, a straight search won't do. Shouldn't be too slow since it will most * likely only be acting on a small portion of data */ //"^content-type:\\s*multipart.*boundary\\s*=\\s*\"?([^\\s]+)\"?" //"^\\s*multipart.*boundary\\s*=\\s*\"?([^\\s]+)\"?" //mime_boundary_pcre.re = pcre_compile("^.*boundary\\s*=\\s*\"?([^\\s\"]+)\"?", //mime_boundary_pcre.re = pcre_compile("boundary(?:\n|\r\n)?=(?:\n|\r\n)?\"?([^\\s\"]+)\"?", mime_boundary_pcre.re = pcre_compile("boundary\\s*=\\s*\"?([^\\s\"]+)\"?", PCRE_CASELESS | PCRE_DOTALL, &error, &erroffset, NULL); if (mime_boundary_pcre.re == NULL) { DynamicPreprocessorFatalMessage("Failed to compile pcre regex for getting boundary " "in a multipart POP message: %s\n", error); } mime_boundary_pcre.pe = pcre_study(mime_boundary_pcre.re, 0, &error); if (error != NULL) { DynamicPreprocessorFatalMessage("Failed to study pcre regex for getting boundary " "in a multipart POP message: %s\n", error); } } /* * Initialize run-time boundary search */ static int POP_BoundarySearchInit(void) { if (pop_ssn->mime_boundary.boundary_search != NULL) _dpd.searchAPI->search_instance_free(pop_ssn->mime_boundary.boundary_search); pop_ssn->mime_boundary.boundary_search = _dpd.searchAPI->search_instance_new(); if (pop_ssn->mime_boundary.boundary_search == NULL) return -1; _dpd.searchAPI->search_instance_add(pop_ssn->mime_boundary.boundary_search, pop_ssn->mime_boundary.boundary, pop_ssn->mime_boundary.boundary_len, BOUNDARY); _dpd.searchAPI->search_instance_prep(pop_ssn->mime_boundary.boundary_search); return 0; } /* * Reset POP session state * * @param none * * @return none */ static void POP_ResetState(void) { if (pop_ssn->mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(pop_ssn->mime_boundary.boundary_search); pop_ssn->mime_boundary.boundary_search = NULL; } pop_ssn->state = STATE_UNKNOWN; pop_ssn->data_state = STATE_DATA_INIT; pop_ssn->prev_response = 0; pop_ssn->state_flags = 0; ClearEmailDecodeState(pop_ssn->decode_state); memset(&pop_ssn->mime_boundary, 0, sizeof(POPMimeBoundary)); } /* * Given a server configuration and a port number, we decide if the port is * in the POP server port list. * * @param port the port number to compare with the configuration * * @return integer * @retval 0 means that the port is not a server port * @retval !0 means that the port is a server port */ int POP_IsServer(uint16_t port) { if (pop_eval_config->ports[port / 8] & (1 << (port % 8))) return 1; return 0; } static POP * POP_GetNewSession(SFSnortPacket *p, tSfPolicyId policy_id) { POP *ssn; POPConfig *pPolicyConfig = NULL; pPolicyConfig = (POPConfig *)sfPolicyUserDataGetCurrent(pop_config); DEBUG_WRAP(DebugMessage(DEBUG_POP, "Creating new session data structure\n");); ssn = (POP *)calloc(1, sizeof(POP)); if (ssn == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate POP session data\n"); } pop_ssn = ssn; ssn->prev_response = 0; if (_dpd.fileAPI->set_log_buffers(&(pop_ssn->log_state), &(pPolicyConfig->log_config), pop_mempool) < 0) { free(ssn); return NULL; } _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_POP, ssn, &POP_SessionFree); if (p->flags & SSNFLAG_MIDSTREAM) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "Got midstream packet - " "setting state to unknown\n");); ssn->state = STATE_UNKNOWN; } #ifdef DEBUG_MSGS pop_session_counter++; ssn->session_number = pop_session_counter; #endif if (p->stream_session_ptr != NULL) { /* check to see if we're doing client reassembly in stream */ if (_dpd.streamAPI->get_reassembly_direction(p->stream_session_ptr) & SSN_DIR_FROM_CLIENT) ssn->reassembling = 1; if(!ssn->reassembling) { _dpd.streamAPI->set_reassembly(p->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_FROM_CLIENT, STREAM_FLPOLICY_SET_ABSOLUTE); ssn->reassembling = 1; } } ssn->policy_id = policy_id; ssn->config = pop_config; pPolicyConfig->ref_count++; return ssn; } /* * Do first-packet setup * * @param p standard Packet structure * * @return none */ static int POP_Setup(SFSnortPacket *p, POP *ssn) { int flags = 0; int pkt_dir; if (p->stream_session_ptr != NULL) { /* set flags to session flags */ flags = _dpd.streamAPI->get_session_flags(p->stream_session_ptr); } /* Figure out direction of packet */ pkt_dir = POP_GetPacketDirection(p, flags); DEBUG_WRAP(DebugMessage(DEBUG_POP, "Session number: "STDu64"\n", ssn->session_number);); /* Check to see if there is a reassembly gap. If so, we won't know * what state we're in when we get the _next_ reassembled packet */ if ((pkt_dir != POP_PKT_FROM_SERVER) && (p->flags & FLAG_REBUILT_STREAM)) { int missing_in_rebuilt = _dpd.streamAPI->missing_in_reassembled(p->stream_session_ptr, SSN_DIR_FROM_CLIENT); if (ssn->session_flags & POP_FLAG_NEXT_STATE_UNKNOWN) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "Found gap in previous reassembly buffer - " "set state to unknown\n");); ssn->state = STATE_UNKNOWN; ssn->session_flags &= ~POP_FLAG_NEXT_STATE_UNKNOWN; } if (missing_in_rebuilt == SSN_MISSING_BEFORE) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "Found missing packets before " "in reassembly buffer - set state to unknown\n");); ssn->state = STATE_UNKNOWN; } } return pkt_dir; } /* * Determine packet direction * * @param p standard Packet structure * * @return none */ static int POP_GetPacketDirection(SFSnortPacket *p, int flags) { int pkt_direction = POP_PKT_FROM_UNKNOWN; if (flags & SSNFLAG_MIDSTREAM) { if (POP_IsServer(p->src_port) && !POP_IsServer(p->dst_port)) { pkt_direction = POP_PKT_FROM_SERVER; } else if (!POP_IsServer(p->src_port) && POP_IsServer(p->dst_port)) { pkt_direction = POP_PKT_FROM_CLIENT; } } else { if (p->flags & FLAG_FROM_SERVER) { pkt_direction = POP_PKT_FROM_SERVER; } else if (p->flags & FLAG_FROM_CLIENT) { pkt_direction = POP_PKT_FROM_CLIENT; } /* if direction is still unknown ... */ if (pkt_direction == POP_PKT_FROM_UNKNOWN) { if (POP_IsServer(p->src_port) && !POP_IsServer(p->dst_port)) { pkt_direction = POP_PKT_FROM_SERVER; } else if (!POP_IsServer(p->src_port) && POP_IsServer(p->dst_port)) { pkt_direction = POP_PKT_FROM_CLIENT; } } } return pkt_direction; } /* * Free POP-specific related to this session * * @param v pointer to POP session structure * * * @return none */ static void POP_SessionFree(void *session_data) { POP *pop = (POP *)session_data; #ifdef SNORT_RELOAD POPConfig *pPolicyConfig = NULL; #endif if (pop == NULL) return; #ifdef SNORT_RELOAD pPolicyConfig = (POPConfig *)sfPolicyUserDataGet(pop->config, pop->policy_id); if (pPolicyConfig != NULL) { pPolicyConfig->ref_count--; if ((pPolicyConfig->ref_count == 0) && (pop->config != pop_config)) { sfPolicyUserDataClear (pop->config, pop->policy_id); POP_FreeConfig(pPolicyConfig); /* No more outstanding policies for this config */ if (sfPolicyUserPolicyGetActive(pop->config) == 0) POP_FreeConfigs(pop->config); } } #endif if (pop->mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(pop->mime_boundary.boundary_search); pop->mime_boundary.boundary_search = NULL; } if(pop->decode_state != NULL) { mempool_free(pop_mime_mempool, pop->decode_bkt); free(pop->decode_state); } if(pop->log_state != NULL) { mempool_free(pop_mempool, pop->log_state->log_hdrs_bkt); free(pop->log_state); } free(pop); } static void POP_NoSessionFree(void) { if (pop_no_session.mime_boundary.boundary_search != NULL) { _dpd.searchAPI->search_instance_free(pop_no_session.mime_boundary.boundary_search); pop_no_session.mime_boundary.boundary_search = NULL; } } static int POP_FreeConfigsPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { POPConfig *pPolicyConfig = (POPConfig *)pData; //do any housekeeping before freeing POPConfig sfPolicyUserDataClear (config, policyId); POP_FreeConfig(pPolicyConfig); return 0; } void POP_FreeConfigs(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, POP_FreeConfigsPolicy); sfPolicyConfigDelete(config); } void POP_FreeConfig(POPConfig *config) { if (config == NULL) return; if (config->cmds != NULL) { POPToken *tmp = config->cmds; for (; tmp->name != NULL; tmp++) free(tmp->name); free(config->cmds); } if (config->cmd_search_mpse != NULL) _dpd.searchAPI->search_instance_free(config->cmd_search_mpse); if (config->cmd_search != NULL) free(config->cmd_search); free(config); } /* * Free anything that needs it before shutting down preprocessor * * @param none * * @return none */ void POP_Free(void) { POP_NoSessionFree(); POP_FreeConfigs(pop_config); pop_config = NULL; if (pop_resp_search_mpse != NULL) _dpd.searchAPI->search_instance_free(pop_resp_search_mpse); if (pop_hdr_search_mpse != NULL) _dpd.searchAPI->search_instance_free(pop_hdr_search_mpse); if (pop_data_search_mpse != NULL) _dpd.searchAPI->search_instance_free(pop_data_search_mpse); if (mime_boundary_pcre.re ) pcre_free(mime_boundary_pcre.re); if (mime_boundary_pcre.pe ) pcre_free(mime_boundary_pcre.pe); } /* * Callback function for string search * * @param id id in array of search strings from pop_config.cmds * @param index index in array of search strings from pop_config.cmds * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */ static int POP_SearchStrFound(void *id, void *unused, int index, void *data, void *unused2) { int search_id = (int)(uintptr_t)id; pop_search_info.id = search_id; pop_search_info.index = index; pop_search_info.length = pop_current_search[search_id].name_len; /* Returning non-zero stops search, which is okay since we only look for one at a time */ return 1; } /* * Callback function for boundary search * * @param id id in array of search strings * @param index index in array of search strings * @param data buffer passed in to search function * * @return response * @retval 1 commands caller to stop searching */ static int POP_BoundaryStrFound(void *id, void *unused, int index, void *data, void *unused2) { int boundary_id = (int)(uintptr_t)id; pop_search_info.id = boundary_id; pop_search_info.index = index; pop_search_info.length = pop_ssn->mime_boundary.boundary_len; return 1; } static int POP_GetBoundary(const char *data, int data_len) { int result; int ovector[9]; int ovecsize = 9; const char *boundary; int boundary_len; int ret; char *mime_boundary; int *mime_boundary_len; int *mime_boundary_state; mime_boundary = &pop_ssn->mime_boundary.boundary[0]; mime_boundary_len = &pop_ssn->mime_boundary.boundary_len; mime_boundary_state = &pop_ssn->mime_boundary.state; /* result will be the number of matches (including submatches) */ result = pcre_exec(mime_boundary_pcre.re, mime_boundary_pcre.pe, data, data_len, 0, 0, ovector, ovecsize); if (result < 0) return -1; result = pcre_get_substring(data, ovector, result, 1, &boundary); if (result < 0) return -1; boundary_len = strlen(boundary); if (boundary_len > MAX_BOUNDARY_LEN) { /* XXX should we alert? breaking the law of RFC */ boundary_len = MAX_BOUNDARY_LEN; } mime_boundary[0] = '-'; mime_boundary[1] = '-'; ret = SafeMemcpy(mime_boundary + 2, boundary, boundary_len, mime_boundary + 2, mime_boundary + 2 + MAX_BOUNDARY_LEN); pcre_free_substring(boundary); if (ret != SAFEMEM_SUCCESS) { return -1; } *mime_boundary_len = 2 + boundary_len; *mime_boundary_state = 0; mime_boundary[*mime_boundary_len] = '\0'; return 0; } /* * Handle COMMAND state * * @param p standard Packet structure * @param ptr pointer into p->payload buffer to start looking at data * @param end points to end of p->payload buffer * * @return pointer into p->payload where we stopped looking at data * will be end of line or end of packet */ static const uint8_t * POP_HandleCommand(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *end) { const uint8_t *eol; /* end of line */ const uint8_t *eolm; /* end of line marker */ int cmd_found; /* get end of line and end of line marker */ POP_GetEOL(ptr, end, &eol, &eolm); /* TODO If the end of line marker coincides with the end of payload we can't be * sure that we got a command and not a substring which we could tell through * inspection of the next packet. Maybe a command pending state where the first * char in the next packet is checked for a space and end of line marker */ /* do not confine since there could be space chars before command */ pop_current_search = &pop_eval_config->cmd_search[0]; cmd_found = _dpd.searchAPI->search_instance_find (pop_eval_config->cmd_search_mpse, (const char *)ptr, eolm - ptr, 0, POP_SearchStrFound); /* see if we actually found a command and not a substring */ if (cmd_found > 0) { const uint8_t *tmp = ptr; const uint8_t *cmd_start = ptr + pop_search_info.index; const uint8_t *cmd_end = cmd_start + pop_search_info.length; /* move past spaces up until start of command */ while ((tmp < cmd_start) && isspace((int)*tmp)) tmp++; /* if not all spaces before command, we found a * substring */ if (tmp != cmd_start) cmd_found = 0; /* if we're before the end of line marker and the next * character is not whitespace, we found a substring */ if ((cmd_end < eolm) && !isspace((int)*cmd_end)) cmd_found = 0; /* there is a chance that end of command coincides with the end of payload * in which case, it could be a substring, but for now, we will treat it as found */ } /* if command not found, alert and move on */ if (!cmd_found) { POP_GenerateAlert(POP_UNKNOWN_CMD, "%s", POP_UNKNOWN_CMD_STR); DEBUG_WRAP(DebugMessage(DEBUG_POP, "No known command found\n");); return eol; } /* At this point we have definitely found a legitimate command */ DEBUG_WRAP(DebugMessage(DEBUG_POP, "%s\n", pop_eval_config->cmds[pop_search_info.id].name);); /* switch (pop_search_info.id) { case CMD_USER: case CMD_PASS: case CMD_RSET: case CMD_QUIT: case CMD_RETR: break; default: break; }*/ return eol; } static const uint8_t * POP_HandleData(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *end) { const uint8_t *data_end_marker = NULL; const uint8_t *data_end = NULL; int data_end_found; FilePosition position = SNORT_FILE_START; /* if we've just entered the data state, check for a dot + end of line * if found, no data */ if ((pop_ssn->data_state == STATE_DATA_INIT) || (pop_ssn->data_state == STATE_DATA_UNKNOWN)) { if ((ptr < end) && (*ptr == '.')) { const uint8_t *eol = NULL; const uint8_t *eolm = NULL; POP_GetEOL(ptr, end, &eol, &eolm); /* this means we got a real end of line and not just end of payload * and that the dot is only char on line */ if ((eolm != end) && (eolm == (ptr + 1))) { /* if we're normalizing and not ignoring data copy data end marker * and dot to alt buffer */ POP_ResetState(); return eol; } } if (pop_ssn->data_state == STATE_DATA_INIT) pop_ssn->data_state = STATE_DATA_HEADER; /* XXX A line starting with a '.' that isn't followed by a '.' is * deleted (RFC 821 - 4.5.2. TRANSPARENCY). If data starts with * '. text', i.e a dot followed by white space then text, some * servers consider it data header and some data body. * Postfix and Qmail will consider the start of data: * . text\r\n * . text\r\n * to be part of the header and the effect will be that of a * folded line with the '.' deleted. Exchange will put the same * in the body which seems more reasonable. */ } /* get end of data body * TODO check last bytes of previous packet to see if we had a partial * end of data */ pop_current_search = &pop_data_end_search[0]; data_end_found = _dpd.searchAPI->search_instance_find (pop_data_search_mpse, (const char *)ptr, end - ptr, 0, POP_SearchStrFound); if (data_end_found > 0) { data_end_marker = ptr + pop_search_info.index; data_end = data_end_marker + pop_search_info.length; } else { data_end_marker = data_end = end; } _dpd.setFileDataPtr((uint8_t*)ptr, (uint16_t)(data_end - ptr)); if ((pop_ssn->data_state == STATE_DATA_HEADER) || (pop_ssn->data_state == STATE_DATA_UNKNOWN)) { #ifdef DEBUG_MSGS if (pop_ssn->data_state == STATE_DATA_HEADER) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "DATA HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_POP, "DATA UNKNOWN STATE ~~~~~~~~~~~~~~~~~~~~~\n");); } #endif ptr = POP_HandleHeader(p, ptr, data_end_marker); if (ptr == NULL) return NULL; } /* now we shouldn't have to worry about copying any data to the alt buffer * only mime headers if we find them and only if we're ignoring data */ initFilePosition(&position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); while ((ptr != NULL) && (ptr < data_end_marker)) { /* multiple MIME attachments in one single packet. * Pipeline the MIME decoded data.*/ if ( pop_ssn->state_flags & POP_FLAG_MULTIPLE_EMAIL_ATTACH) { int detection_size = getDetectionSize(pop_eval_config->b64_depth, pop_eval_config->qp_depth, pop_eval_config->uu_depth, pop_eval_config->bitenc_depth,pop_ssn->decode_state ); _dpd.setFileDataPtr(pop_ssn->decode_state->decodePtr, (uint16_t)detection_size); /*Download*/ if (_dpd.fileAPI->file_process(p,(uint8_t *)pop_ssn->decode_state->decodePtr, (uint16_t)pop_ssn->decode_state->decoded_bytes, position, false, false) && (isFileStart(position)) && pop_ssn->log_state) { _dpd.fileAPI->set_file_name_from_log(&(pop_ssn->log_state->file_log), p->stream_session_ptr); } updateFilePosition(&position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); _dpd.detect(p); pop_ssn->state_flags &= ~POP_FLAG_MULTIPLE_EMAIL_ATTACH; ResetEmailDecodeState(pop_ssn->decode_state); p->flags |=FLAG_ALLOW_MULTIPLE_DETECT; /* Reset the log count when a packet goes through detection multiple times */ _dpd.DetectReset((uint8_t *)p->payload, p->payload_size); } switch (pop_ssn->data_state) { case STATE_MIME_HEADER: DEBUG_WRAP(DebugMessage(DEBUG_POP, "MIME HEADER STATE ~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = POP_HandleHeader(p, ptr, data_end_marker); _dpd.fileAPI->finalize_mime_position(p->stream_session_ptr, pop_ssn->decode_state, &position); break; case STATE_DATA_BODY: DEBUG_WRAP(DebugMessage(DEBUG_POP, "DATA BODY STATE ~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = POP_HandleDataBody(p, ptr, data_end_marker); _dpd.fileAPI->update_file_name(pop_ssn->log_state); break; } } /* We have either reached the end of MIME header or end of MIME encoded data*/ if(pop_ssn->decode_state != NULL) { int detection_size = getDetectionSize(pop_eval_config->b64_depth, pop_eval_config->qp_depth, pop_eval_config->uu_depth, pop_eval_config->bitenc_depth,pop_ssn->decode_state ); _dpd.setFileDataPtr(pop_ssn->decode_state->decodePtr, (uint16_t)detection_size); if ((data_end_marker != end) || (pop_ssn->state_flags & POP_FLAG_MIME_END)) { finalFilePosition(&position); } /*Download*/ if (_dpd.fileAPI->file_process(p,(uint8_t *)pop_ssn->decode_state->decodePtr, (uint16_t)pop_ssn->decode_state->decoded_bytes, position, false, false) && (isFileStart(position)) && pop_ssn->log_state) { _dpd.fileAPI->set_file_name_from_log(&(pop_ssn->log_state->file_log), p->stream_session_ptr); } ResetDecodedBytes(pop_ssn->decode_state); } /* if we got the data end reset state, otherwise we're probably still in the data * to expect more data in next packet */ if (data_end_marker != end) { POP_ResetState(); } return data_end; } /* * Handle Headers - Data or Mime * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */ static const uint8_t * POP_HandleHeader(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *data_end_marker) { const uint8_t *eol; const uint8_t *eolm; const uint8_t *colon; const uint8_t *content_type_ptr = NULL; const uint8_t *cont_trans_enc = NULL; const uint8_t *cont_disp = NULL; int header_found; int ret; const uint8_t *start_hdr; start_hdr = ptr; /* if we got a content-type in a previous packet and are * folding, the boundary still needs to be checked for */ if (pop_ssn->state_flags & POP_FLAG_IN_CONTENT_TYPE) content_type_ptr = ptr; if (pop_ssn->state_flags & POP_FLAG_IN_CONT_TRANS_ENC) cont_trans_enc = ptr; if (pop_ssn->state_flags & POP_FLAG_IN_CONT_DISP) cont_disp = ptr; while (ptr < data_end_marker) { POP_GetEOL(ptr, data_end_marker, &eol, &eolm); /* got a line with only end of line marker should signify end of header */ if (eolm == ptr) { /* reset global header state values */ pop_ssn->state_flags &= ~(POP_FLAG_FOLDING | POP_FLAG_IN_CONTENT_TYPE | POP_FLAG_DATA_HEADER_CONT | POP_FLAG_IN_CONT_TRANS_ENC ); pop_ssn->data_state = STATE_DATA_BODY; /* if no headers, treat as data */ if (ptr == start_hdr) return eolm; else return eol; } /* if we're not folding, see if we should interpret line as a data line * instead of a header line */ if (!(pop_ssn->state_flags & (POP_FLAG_FOLDING | POP_FLAG_DATA_HEADER_CONT))) { char got_non_printable_in_header_name = 0; /* if we're not folding and the first char is a space or * colon, it's not a header */ if (isspace((int)*ptr) || *ptr == ':') { pop_ssn->data_state = STATE_DATA_BODY; return ptr; } /* look for header field colon - if we're not folding then we need * to find a header which will be all printables (except colon) * followed by a colon */ colon = ptr; while ((colon < eolm) && (*colon != ':')) { if (((int)*colon < 33) || ((int)*colon > 126)) got_non_printable_in_header_name = 1; colon++; } /* If the end on line marker and end of line are the same, assume * header was truncated, so stay in data header state */ if ((eolm != eol) && ((colon == eolm) || got_non_printable_in_header_name)) { /* no colon or got spaces in header name (won't be interpreted as a header) * assume we're in the body */ pop_ssn->state_flags &= ~(POP_FLAG_FOLDING | POP_FLAG_IN_CONTENT_TYPE | POP_FLAG_DATA_HEADER_CONT |POP_FLAG_IN_CONT_TRANS_ENC); pop_ssn->data_state = STATE_DATA_BODY; return ptr; } if(tolower((int)*ptr) == 'c') { pop_current_search = &pop_hdr_search[0]; header_found = _dpd.searchAPI->search_instance_find (pop_hdr_search_mpse, (const char *)ptr, eolm - ptr, 1, POP_SearchStrFound); /* Headers must start at beginning of line */ if ((header_found > 0) && (pop_search_info.index == 0)) { switch (pop_search_info.id) { case HDR_CONTENT_TYPE: content_type_ptr = ptr + pop_search_info.length; pop_ssn->state_flags |= POP_FLAG_IN_CONTENT_TYPE; break; case HDR_CONT_TRANS_ENC: cont_trans_enc = ptr + pop_search_info.length; pop_ssn->state_flags |= POP_FLAG_IN_CONT_TRANS_ENC; break; case HDR_CONT_DISP: cont_disp = ptr + pop_search_info.length; pop_ssn->state_flags |= POP_FLAG_IN_CONT_DISP; break; default: break; } } } else if(tolower((int)*ptr) == 'e') { if((eolm - ptr) >= 9) { if(strncasecmp((const char *)ptr, "Encoding:", 9) == 0) { cont_trans_enc = ptr + 9; pop_ssn->state_flags |= POP_FLAG_IN_CONT_TRANS_ENC; } } } } else { pop_ssn->state_flags &= ~POP_FLAG_DATA_HEADER_CONT; } /* check for folding * if char on next line is a space and not \n or \r\n, we are folding */ if ((eol < data_end_marker) && isspace((int)eol[0]) && (eol[0] != '\n')) { if ((eol < (data_end_marker - 1)) && (eol[0] != '\r') && (eol[1] != '\n')) { pop_ssn->state_flags |= POP_FLAG_FOLDING; } else { pop_ssn->state_flags &= ~POP_FLAG_FOLDING; } } else if (eol != eolm) { pop_ssn->state_flags &= ~POP_FLAG_FOLDING; } /* check if we're in a content-type header and not folding. if so we have the whole * header line/lines for content-type - see if we got a multipart with boundary * we don't check each folded line, but wait until we have the complete header * because boundary=BOUNDARY can be split across mulitple folded lines before * or after the '=' */ if ((pop_ssn->state_flags & (POP_FLAG_IN_CONTENT_TYPE | POP_FLAG_FOLDING)) == POP_FLAG_IN_CONTENT_TYPE) { if (pop_ssn->data_state != STATE_MIME_HEADER) { /* we got the full content-type header - look for boundary string */ ret = POP_GetBoundary((const char *)content_type_ptr, eolm - content_type_ptr); if (ret != -1) { ret = POP_BoundarySearchInit(); if (ret != -1) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "Got mime boundary: %s\n", pop_ssn->mime_boundary.boundary);); pop_ssn->state_flags |= POP_FLAG_GOT_BOUNDARY; } } } else if (!(pop_ssn->state_flags & POP_FLAG_EMAIL_ATTACH)) { if( !POP_IsDecodingEnabled(pop_eval_config)) { SetPopBuffers(pop_ssn); if(pop_ssn->decode_state != NULL) { ResetBytesRead(pop_ssn->decode_state); POP_DecodeType((const char *)content_type_ptr, (eolm - content_type_ptr), false ); pop_ssn->state_flags |= POP_FLAG_EMAIL_ATTACH; /* check to see if there are other attachments in this packet */ if( pop_ssn->decode_state->decoded_bytes ) pop_ssn->state_flags |= POP_FLAG_MULTIPLE_EMAIL_ATTACH; } } } pop_ssn->state_flags &= ~POP_FLAG_IN_CONTENT_TYPE; content_type_ptr = NULL; } else if ((pop_ssn->state_flags & (POP_FLAG_IN_CONT_TRANS_ENC | POP_FLAG_FOLDING)) == POP_FLAG_IN_CONT_TRANS_ENC) { /* Check for Content-Transfer-Encoding : */ if( !POP_IsDecodingEnabled(pop_eval_config)) { SetPopBuffers(pop_ssn); if(pop_ssn->decode_state != NULL) { ResetBytesRead(pop_ssn->decode_state); POP_DecodeType((const char *)cont_trans_enc, (eolm - cont_trans_enc), true ); pop_ssn->state_flags |= POP_FLAG_EMAIL_ATTACH; /* check to see if there are other attachments in this packet */ if( pop_ssn->decode_state->decoded_bytes ) pop_ssn->state_flags |= POP_FLAG_MULTIPLE_EMAIL_ATTACH; } } pop_ssn->state_flags &= ~POP_FLAG_IN_CONT_TRANS_ENC; cont_trans_enc = NULL; } else if (((pop_ssn->state_flags & (POP_FLAG_IN_CONT_DISP | POP_FLAG_FOLDING)) == POP_FLAG_IN_CONT_DISP) && cont_disp) { bool disp_cont = (pop_ssn->state_flags & POP_FLAG_IN_CONT_DISP_CONT)? true: false; if( pop_eval_config->log_config.log_filename && pop_ssn->log_state) { if(! _dpd.fileAPI->log_file_name(cont_disp, eolm - cont_disp, &(pop_ssn->log_state->file_log), &disp_cont) ) pop_ssn->log_flags |= POP_FLAG_FILENAME_PRESENT; } if (disp_cont) { pop_ssn->state_flags |= POP_FLAG_IN_CONT_DISP_CONT; } else { pop_ssn->state_flags &= ~POP_FLAG_IN_CONT_DISP; pop_ssn->state_flags &= ~POP_FLAG_IN_CONT_DISP_CONT; } cont_disp = NULL; } /* if state was unknown, at this point assume we know */ if (pop_ssn->data_state == STATE_DATA_UNKNOWN) pop_ssn->data_state = STATE_DATA_HEADER; ptr = eol; if (ptr == data_end_marker) pop_ssn->state_flags |= POP_FLAG_DATA_HEADER_CONT; } return ptr; } /* * Handle DATA_BODY statepop_ssn->log_state * * @param packet standard Packet structure * * @param i index into p->payload buffer to start looking at data * * @return i index into p->payload where we stopped looking at data */ static const uint8_t * POP_HandleDataBody(SFSnortPacket *p, const uint8_t *ptr, const uint8_t *data_end_marker) { int boundary_found = 0; const uint8_t *boundary_ptr = NULL; const uint8_t *attach_start = NULL; const uint8_t *attach_end = NULL; if ( pop_ssn->state_flags & POP_FLAG_EMAIL_ATTACH ) attach_start = ptr; /* look for boundary */ if (pop_ssn->state_flags & POP_FLAG_GOT_BOUNDARY) { boundary_found = _dpd.searchAPI->stateful_search_instance_find (pop_ssn->mime_boundary.boundary_search, (const char *)ptr, data_end_marker - ptr, 0, POP_BoundaryStrFound, &(pop_ssn->mime_boundary.state)); if (boundary_found > 0) { pop_ssn->mime_boundary.state = 0; boundary_ptr = ptr + pop_search_info.index; /* should start at beginning of line */ if ((boundary_ptr == ptr) || (*(boundary_ptr - 1) == '\n')) { const uint8_t *eol; const uint8_t *eolm; const uint8_t *tmp; if (pop_ssn->state_flags & POP_FLAG_EMAIL_ATTACH ) { attach_end = boundary_ptr-1; pop_ssn->state_flags &= ~POP_FLAG_EMAIL_ATTACH; if(attach_start < attach_end) { if (*(attach_end - 1) == '\r') attach_end--; if(EmailDecode( attach_start, attach_end, pop_ssn->decode_state) < DECODE_SUCCESS ) { POP_DecodeAlert(); } } } if(boundary_ptr > ptr) tmp = boundary_ptr + pop_search_info.length; else { tmp = (const uint8_t *)_dpd.searchAPI->search_instance_find_end((char *)boundary_ptr, (data_end_marker - boundary_ptr), pop_ssn->mime_boundary.boundary, pop_search_info.length); } /* Check for end boundary */ if (((tmp + 1) < data_end_marker) && (tmp[0] == '-') && (tmp[1] == '-')) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "Mime boundary end found: %s--\n", (char *)pop_ssn->mime_boundary.boundary);); /* no more MIME */ pop_ssn->state_flags &= ~POP_FLAG_GOT_BOUNDARY; pop_ssn->state_flags |= POP_FLAG_MIME_END; /* free boundary search */ _dpd.searchAPI->search_instance_free(pop_ssn->mime_boundary.boundary_search); pop_ssn->mime_boundary.boundary_search = NULL; } else { DEBUG_WRAP(DebugMessage(DEBUG_POP, "Mime boundary found: %s\n", (char *)pop_ssn->mime_boundary.boundary);); pop_ssn->data_state = STATE_MIME_HEADER; } /* get end of line - there could be spaces after boundary before eol */ POP_GetEOL(boundary_ptr + pop_search_info.length, data_end_marker, &eol, &eolm); return eol; } } } if ( pop_ssn->state_flags & POP_FLAG_EMAIL_ATTACH ) { attach_end = data_end_marker; if(attach_start < attach_end) { if(EmailDecode( attach_start, attach_end, pop_ssn->decode_state) < DECODE_SUCCESS ) { POP_DecodeAlert(); } } } return data_end_marker; } /* * Process client packet * * @param packet standard Packet structure * * @return none */ static void POP_ProcessClientPacket(SFSnortPacket *p) { const uint8_t *ptr = p->payload; const uint8_t *end = p->payload + p->payload_size; ptr = POP_HandleCommand(p, ptr, end); } /* * Process server packet * * @param packet standard Packet structure * */ static void POP_ProcessServerPacket(SFSnortPacket *p) { int resp_found; const uint8_t *ptr; const uint8_t *end; const uint8_t *eolm; const uint8_t *eol; int resp_line_len; const char *tmp = NULL; ptr = p->payload; end = p->payload + p->payload_size; while (ptr < end) { if(pop_ssn->state == STATE_DATA) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "DATA STATE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");); ptr = POP_HandleData(p, ptr, end); continue; } POP_GetEOL(ptr, end, &eol, &eolm); resp_line_len = eol - ptr; /* Check for response code */ pop_current_search = &pop_resp_search[0]; resp_found = _dpd.searchAPI->search_instance_find (pop_resp_search_mpse, (const char *)ptr, resp_line_len, 1, POP_SearchStrFound); if (resp_found > 0) { const uint8_t *cmd_start = ptr + pop_search_info.index; switch (pop_search_info.id) { case RESP_OK: tmp = _dpd.SnortStrcasestr((const char *)cmd_start, (eol - cmd_start), "octets"); if(tmp != NULL) pop_ssn->state = STATE_DATA; else { pop_ssn->prev_response = RESP_OK; pop_ssn->state = STATE_UNKNOWN; } break; default: break; } } else { if(pop_ssn->prev_response == RESP_OK) { { pop_ssn->state = STATE_DATA; pop_ssn->prev_response = 0; continue; } } else if(*ptr == '+') { POP_GenerateAlert(POP_UNKNOWN_RESP, "%s", POP_UNKNOWN_RESP_STR); DEBUG_WRAP(DebugMessage(DEBUG_POP, "Server response not found\n");); } } ptr = eol; } return; } /* For Target based * If a protocol for the session is already identified and not one POP is * interested in, POP should leave it alone and return without processing. * If a protocol for the session is already identified and is one that POP is * interested in, decode it. * If the protocol for the session is not already identified and the preprocessor * is configured to detect on one of the packet ports, detect. * Returns 0 if we should not inspect * 1 if we should continue to inspect */ static int POP_Inspect(SFSnortPacket *p) { #ifdef TARGET_BASED /* POP could be configured to be stateless. If stream isn't configured, assume app id * will never be set and just base inspection on configuration */ if (p->stream_session_ptr == NULL) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP: Target-based: No stream session.\n");); if ((POP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (POP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP: Target-based: Configured for this " "traffic, so let's inspect.\n");); return 1; } } else { int16_t app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if (app_id != 0) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP: Target-based: App id: %u.\n", app_id);); if (app_id == pop_proto_id) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP: Target-based: App id is " "set to \"%s\".\n", POP_PROTO_REF_STR);); return 1; } } else { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP: Target-based: Unknown protocol for " "this session. See if we're configured.\n");); if ((POP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (POP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP: Target-based: POP port is configured.");); return 1; } } } DEBUG_WRAP(DebugMessage(DEBUG_POP,"POP: Target-based: Not inspecting ...\n");); #else /* Make sure it's traffic we're interested in */ if ((POP_IsServer(p->src_port) && (p->flags & FLAG_FROM_SERVER)) || (POP_IsServer(p->dst_port) && (p->flags & FLAG_FROM_CLIENT))) return 1; #endif /* TARGET_BASED */ return 0; } /* * Entry point to snort preprocessor for each packet * * @param packet standard Packet structure * * @return none */ void SnortPOP(SFSnortPacket *p) { int detected = 0; int pkt_dir; tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; pop_ssn = (POP *)_dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_POP); if (pop_ssn != NULL) pop_eval_config = (POPConfig *)sfPolicyUserDataGet(pop_ssn->config, pop_ssn->policy_id); else pop_eval_config = (POPConfig *)sfPolicyUserDataGetCurrent(pop_config); if (pop_eval_config == NULL) return; if (pop_ssn == NULL) { if (!POP_Inspect(p)) return; pop_ssn = POP_GetNewSession(p, policy_id); if (pop_ssn == NULL) return; } pkt_dir = POP_Setup(p, pop_ssn); if (pkt_dir == POP_PKT_FROM_CLIENT) { POP_ProcessClientPacket(p); DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP client packet\n");); } else { #ifdef DEBUG_MSGS if (pkt_dir == POP_PKT_FROM_SERVER) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP server packet\n");); } else { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP packet NOT from client or server! " "Processing as a server packet\n");); } #endif if (!_dpd.readyForProcess(p)) { /* Packet will be rebuilt, so wait for it */ DEBUG_WRAP(DebugMessage(DEBUG_POP, "Client packet will be reassembled\n")); return; } else if (pop_ssn->reassembling && !(p->flags & FLAG_REBUILT_STREAM)) { /* If this isn't a reassembled packet and didn't get * inserted into reassembly buffer, there could be a * problem. If we miss syn or syn-ack that had window * scaling this packet might not have gotten inserted * into reassembly buffer because it fell outside of * window, because we aren't scaling it */ pop_ssn->session_flags |= POP_FLAG_GOT_NON_REBUILT; pop_ssn->state = STATE_UNKNOWN; } else if (pop_ssn->reassembling && (pop_ssn->session_flags & POP_FLAG_GOT_NON_REBUILT)) { /* This is a rebuilt packet. If we got previous packets * that were not rebuilt, state is going to be messed up * so set state to unknown. It's likely this was the * beginning of the conversation so reset state */ DEBUG_WRAP(DebugMessage(DEBUG_POP, "Got non-rebuilt packets before " "this rebuilt packet\n");); pop_ssn->state = STATE_UNKNOWN; pop_ssn->session_flags &= ~POP_FLAG_GOT_NON_REBUILT; } /* Process as a server packet */ POP_ProcessServerPacket(p); } PREPROC_PROFILE_START(popDetectPerfStats); detected = _dpd.detect(p); #ifdef PERF_PROFILING popDetectCalled = 1; #endif PREPROC_PROFILE_END(popDetectPerfStats); /* Turn off detection since we've already done it. */ POP_DisableDetect(p); if (detected) { DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP vulnerability detected\n");); } } static void POP_DisableDetect(SFSnortPacket *p) { _dpd.disableAllDetect(p); _dpd.setPreprocBit(p, PP_SFPORTSCAN); _dpd.setPreprocBit(p, PP_PERFMONITOR); _dpd.setPreprocBit(p, PP_STREAM5); _dpd.setPreprocBit(p, PP_SDF); } static inline POP *POP_GetSession(void *data) { if(data) return (POP *)_dpd.streamAPI->get_application_data(data, PP_POP); return NULL; } /* Callback to return the MIME attachment filenames accumulated */ int POP_GetFilename(void *data, uint8_t **buf, uint32_t *len, uint32_t *type) { POP *ssn = POP_GetSession(data); if(ssn == NULL) return 0; *buf = ssn->log_state->file_log.filenames; *len = ssn->log_state->file_log.file_logged; return 1; } snort-2.9.6.0/src/dynamic-preprocessors/pop/pop_util.h0000644000000000000000000000312612260565732017660 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************* * * pop_util.h * * Author: Bhagyashree Bantwal * *************************************************************************/ #ifndef __POP_UTIL_H__ #define __POP_UTIL_H__ #include "sf_snort_packet.h" void POP_GetEOL(const uint8_t *, const uint8_t *, const uint8_t **, const uint8_t **); void POP_DecodeType(const char *start, int length, bool cnt_xf); #ifdef DEBUG_MSGS const char * POP_PrintBuffer(SFSnortPacket *); #endif #endif /* __POP_UTIL_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/pop/pop_util.c0000644000000000000000000001066012260565732017654 00000000000000/* * pop_util.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * * Author: Bhagyashree Bantwal * * Description: * * This file contains POP helper functions. * * Entry point functions: * * safe_strchr() * safe_strstr() * copy_to_space() * safe_sscanf() * * */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "snort_bounds.h" #include "snort_pop.h" #include "pop_util.h" #include "sf_dynamic_preprocessor.h" #include "sf_snort_packet.h" #include "Unified2_common.h" extern POP *pop_ssn; void POP_GetEOL(const uint8_t *ptr, const uint8_t *end, const uint8_t **eol, const uint8_t **eolm) { const uint8_t *tmp_eol; const uint8_t *tmp_eolm; /* XXX maybe should fatal error here since none of these * pointers should be NULL */ if (ptr == NULL || end == NULL || eol == NULL || eolm == NULL) return; tmp_eol = (uint8_t *)memchr(ptr, '\n', end - ptr); if (tmp_eol == NULL) { tmp_eol = end; tmp_eolm = end; } else { /* end of line marker (eolm) should point to marker and * end of line (eol) should point to end of marker */ if ((tmp_eol > ptr) && (*(tmp_eol - 1) == '\r')) { tmp_eolm = tmp_eol - 1; } else { tmp_eolm = tmp_eol; } /* move past newline */ tmp_eol++; } *eol = tmp_eol; *eolm = tmp_eolm; } void POP_DecodeType(const char *start, int length, bool cnt_xf) { const char *tmp = NULL; if(cnt_xf) { if(pop_ssn->decode_state->b64_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "base64"); if( tmp != NULL ) { pop_ssn->decode_state->decode_type = DECODE_B64; return; } } if(pop_ssn->decode_state->qp_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "quoted-printable"); if( tmp != NULL ) { pop_ssn->decode_state->decode_type = DECODE_QP; return; } } if(pop_ssn->decode_state->uu_state.encode_depth > -1) { tmp = _dpd.SnortStrcasestr(start, length, "uuencode"); if( tmp != NULL ) { pop_ssn->decode_state->decode_type = DECODE_UU; return; } } } if(pop_ssn->decode_state->bitenc_state.depth > -1) { pop_ssn->decode_state->decode_type = DECODE_BITENC; return; } return; } #ifdef DEBUG_MSGS char pop_print_buffer[65537]; const char * POP_PrintBuffer(SFSnortPacket *p) { const uint8_t *ptr = NULL; int len = 0; int iorig, inew; ptr = p->payload; len = p->payload_size; for (iorig = 0, inew = 0; iorig < len; iorig++, inew++) { if ((isascii((int)ptr[iorig]) && isprint((int)ptr[iorig])) || (ptr[iorig] == '\n')) { pop_print_buffer[inew] = ptr[iorig]; } else if (ptr[iorig] == '\r' && ((iorig + 1) < len) && (ptr[iorig + 1] == '\n')) { iorig++; pop_print_buffer[inew] = '\n'; } else if (isspace((int)ptr[iorig])) { pop_print_buffer[inew] = ' '; } else { pop_print_buffer[inew] = '.'; } } pop_print_buffer[inew] = '\0'; return &pop_print_buffer[0]; } #endif snort-2.9.6.0/src/dynamic-preprocessors/pop/pop_log.h0000644000000000000000000000457512260565732017475 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * pop_log.h * * Author: Bhagyashree Bantwal * **************************************************************************/ #ifndef __POP_LOG_H__ #define __POP_LOG_H__ #define GENERATOR_SPP_POP 142 /* Events for POP */ #define POP_UNKNOWN_CMD 1 #define POP_UNKNOWN_RESP 2 #define POP_MEMCAP_EXCEEDED 3 #define POP_B64_DECODING_FAILED 4 #define POP_QP_DECODING_FAILED 5 /* Do not delete or reuse this SID. Commenting this SID as this alert is no longer valid.* * #define POP_BITENC_DECODING_FAILED 6 */ #define POP_UU_DECODING_FAILED 7 #define POP_EVENT_MAX 8 /* Messages for each event */ #define POP_UNKNOWN_CMD_STR "(POP) Unknown POP3 command" #define POP_UNKNOWN_RESP_STR "(POP) Unknown POP3 response" #define POP_MEMCAP_EXCEEDED_STR "(POP) No memory available for decoding. Memcap exceeded" #define POP_B64_DECODING_FAILED_STR "(POP) Base64 Decoding failed." #define POP_QP_DECODING_FAILED_STR "(POP) Quoted-Printable Decoding failed." #define POP_UU_DECODING_FAILED_STR "(POP) Unix-to-Unix Decoding failed." #define EVENT_STR_LEN 256 /* Function prototypes */ void POP_GenerateAlert(int, char *, ...); void POP_DecodeAlert(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/pop/pop_log.c0000644000000000000000000000624612260565732017465 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /************************************************************************** * * pop_log.c * * Author: Bhagyashree Bantwal * * Description: * * This file handles POP alerts. * * Entry point functions: * * POP_GenerateAlert() * * **************************************************************************/ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "pop_config.h" #include "pop_log.h" #include "snort_pop.h" #include "sf_dynamic_preprocessor.h" extern POPConfig *pop_eval_config; extern POP *pop_ssn; char pop_event[POP_EVENT_MAX][EVENT_STR_LEN]; void POP_GenerateAlert(int event, char *format, ...) { va_list ap; /* Only log a specific alert once per session */ if (pop_ssn->alert_mask & (1 << event)) { #ifdef DEBUG_MSGS DEBUG_WRAP(DebugMessage(DEBUG_POP, "Already alerted on: %s - " "ignoring event.\n", pop_event[event]);); #endif return; } /* set bit for this alert so we don't alert on again * in this session */ pop_ssn->alert_mask |= (1 << event); va_start(ap, format); pop_event[event][0] = '\0'; vsnprintf(&pop_event[event][0], EVENT_STR_LEN - 1, format, ap); pop_event[event][EVENT_STR_LEN - 1] = '\0'; _dpd.alertAdd(GENERATOR_SPP_POP, event, 1, 0, 3, &pop_event[event][0], 0); DEBUG_WRAP(DebugMessage(DEBUG_POP, "POP Alert generated: %s\n", pop_event[event]);); va_end(ap); } void POP_DecodeAlert(void) { switch( pop_ssn->decode_state->decode_type ) { case DECODE_B64: if (pop_eval_config->b64_depth > -1) POP_GenerateAlert(POP_B64_DECODING_FAILED, "%s", POP_B64_DECODING_FAILED_STR); break; case DECODE_QP: if (pop_eval_config->qp_depth > -1) POP_GenerateAlert(POP_QP_DECODING_FAILED, "%s", POP_QP_DECODING_FAILED_STR); break; case DECODE_UU: if (pop_eval_config->uu_depth > -1) POP_GenerateAlert(POP_UU_DECODING_FAILED, "%s", POP_UU_DECODING_FAILED_STR); break; default: break; } } snort-2.9.6.0/src/dynamic-preprocessors/pop/pop_config.h0000644000000000000000000000672112260565732020154 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /*************************************************************************** * * pop_config.h * * Author: Bhagyashree Bantwal * ***************************************************************************/ #ifndef __POP_CONFIG_H__ #define __POP_CONFIG_H__ #include "sfPolicyUserData.h" #define CONF_SEPARATORS " \t\n\r" #define CONF_PORTS "ports" #define CONF_POP_MEMCAP "memcap" #define CONF_MAX_MIME_MEM "max_mime_mem" #define CONF_B64_DECODE "b64_decode_depth" #define CONF_QP_DECODE "qp_decode_depth" #define CONF_BITENC_DECODE "bitenc_decode_depth" #define CONF_UU_DECODE "uu_decode_depth" #define CONF_DISABLED "disabled" #define CONF_START_LIST "{" #define CONF_END_LIST "}" /*These are temporary values*/ #define DEFAULT_MAX_MIME_MEM 838860 #define DEFAULT_POP_MEMCAP 838860 #define DEFAULT_DEPTH 1464 #define MAX_POP_MEMCAP 104857600 #define MIN_POP_MEMCAP 3276 #define MAX_MIME_MEM 104857600 #define MIN_MIME_MEM 3276 #define MAX_DEPTH 65535 #define MIN_DEPTH -1 #define POP_DEFAULT_SERVER_PORT 110 /* POP normally runs on port 110 */ #define ERRSTRLEN 512 typedef struct _POPSearch { char *name; int name_len; } POPSearch; typedef struct _POPToken { char *name; int name_len; int search_id; } POPToken; typedef struct _POPCmdConfig { char alert; /* 1 if alert when seen */ char normalize; /* 1 if we should normalize this command */ int max_line_len; /* Max length of this particular command */ } POPCmdConfig; typedef struct _POPConfig { char ports[8192]; int max_mime_mem; uint32_t memcap; int max_depth; int b64_depth; int qp_depth; int bitenc_depth; int uu_depth; int64_t file_depth; POPToken *cmds; POPSearch *cmd_search; void *cmd_search_mpse; int num_cmds; int disabled; MAIL_LogConfig log_config; int ref_count; } POPConfig; /* Function prototypes */ void POP_ParseArgs(POPConfig *, char *); void POP_PrintConfig(POPConfig *config); void POP_CheckConfig(POPConfig *, tSfPolicyUserContextId); int POP_IsDecodingEnabled(POPConfig *); #endif snort-2.9.6.0/src/dynamic-preprocessors/pop/pop_config.c0000644000000000000000000004611512260565732020150 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /*************************************************************************** * pop_config.c * * Author: Bhagyashree Bantwal * * Description: * * Handle configuration of the POP preprocessor * * Entry point functions: * * POP_ParseArgs() * ***************************************************************************/ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_pop.h" #include "pop_config.h" #include "snort_bounds.h" #include "sf_dynamic_preprocessor.h" #include "sfPolicy.h" /* Global variable to hold configuration */ extern POPConfig **pop_config; extern const POPToken pop_known_cmds[]; /* Private functions */ static int ProcessPorts(POPConfig *, char *, int); static int ProcessDecodeDepth(POPConfig *, char *, int, char *, DecodeType); /* * Function: POP_ParseArgs(char *) * * Purpose: Process the preprocessor arguments from the rules file and * initialize the preprocessor's data struct. This function doesn't * have to exist if it makes sense to parse the args in the init * function. * * Arguments: args => argument list * * Returns: void function * */ void POP_ParseArgs(POPConfig *config, char *args) { int ret = 0; char *arg; char errStr[ERRSTRLEN]; int errStrLen = ERRSTRLEN; if ((config == NULL) || (args == NULL)) return; config->ports[POP_DEFAULT_SERVER_PORT / 8] |= 1 << (POP_DEFAULT_SERVER_PORT % 8); config->max_mime_mem = DEFAULT_POP_MEMCAP; config->memcap = DEFAULT_POP_MEMCAP; config->b64_depth = DEFAULT_DEPTH; config->qp_depth = DEFAULT_DEPTH; config->uu_depth = DEFAULT_DEPTH; config->bitenc_depth = DEFAULT_DEPTH; config->max_depth = MIN_DEPTH; config->log_config.log_filename = 0; config->log_config.log_mailfrom = 0; config->log_config.log_rcptto = 0; config->log_config.log_email_hdrs = 0; config->log_config.email_hdrs_log_depth = 0; *errStr = '\0'; arg = strtok(args, CONF_SEPARATORS); while ( arg != NULL ) { unsigned long value = 0; if ( !strcasecmp(CONF_PORTS, arg) ) { ret = ProcessPorts(config, errStr, errStrLen); } else if ( !strcasecmp(CONF_POP_MEMCAP, arg) ) { ret = _dpd.checkValueInRange(strtok(NULL, CONF_SEPARATORS), CONF_POP_MEMCAP, MIN_POP_MEMCAP, MAX_POP_MEMCAP, &value); config->memcap = (uint32_t)value; } else if ( !strcasecmp(CONF_MAX_MIME_MEM, arg) ) { ret = _dpd.checkValueInRange(strtok(NULL, CONF_SEPARATORS), CONF_MAX_MIME_MEM, MIN_MIME_MEM, MAX_MIME_MEM, &value); config->max_mime_mem = (int)value; } else if ( !strcasecmp(CONF_B64_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_B64_DECODE, DECODE_B64); } else if ( !strcasecmp(CONF_QP_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_QP_DECODE, DECODE_QP); } else if ( !strcasecmp(CONF_UU_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_UU_DECODE, DECODE_UU); } else if ( !strcasecmp(CONF_BITENC_DECODE, arg) ) { ret = ProcessDecodeDepth(config, errStr, errStrLen, CONF_BITENC_DECODE, DECODE_BITENC); } else if ( !strcasecmp(CONF_DISABLED, arg) ) { config->disabled = 1; } else { DynamicPreprocessorFatalMessage("%s(%d) => Unknown POP configuration option %s\n", *(_dpd.config_file), *(_dpd.config_line), arg); } if (ret == -1) { /* ** Fatal Error, log error and exit. */ if (*errStr) { DynamicPreprocessorFatalMessage("%s(%d) => %s\n", *(_dpd.config_file), *(_dpd.config_line), errStr); } else { DynamicPreprocessorFatalMessage("%s(%d) => Undefined Error.\n", *(_dpd.config_file), *(_dpd.config_line)); } } /* Get next token */ arg = strtok(NULL, CONF_SEPARATORS); } } int POP_IsDecodingEnabled(POPConfig *pPolicyConfig) { if( (pPolicyConfig->b64_depth > -1) || (pPolicyConfig->qp_depth > -1) || (pPolicyConfig->uu_depth > -1) || (pPolicyConfig->bitenc_depth > -1) || (pPolicyConfig->file_depth > -1)) { return 0; } else return -1; } void POP_CheckConfig(POPConfig *pPolicyConfig, tSfPolicyUserContextId context) { int max = -1; POPConfig *defaultConfig = (POPConfig *)sfPolicyUserDataGetDefault(context); if (pPolicyConfig == defaultConfig) { if (!pPolicyConfig->max_mime_mem) pPolicyConfig->max_mime_mem = DEFAULT_MAX_MIME_MEM; if(!pPolicyConfig->b64_depth || !pPolicyConfig->qp_depth || !pPolicyConfig->uu_depth || !pPolicyConfig->bitenc_depth) { pPolicyConfig->max_depth = MAX_DEPTH; return; } else { if(max < pPolicyConfig->b64_depth) max = pPolicyConfig->b64_depth; if(max < pPolicyConfig->qp_depth) max = pPolicyConfig->qp_depth; if(max < pPolicyConfig->bitenc_depth) max = pPolicyConfig->bitenc_depth; if(max < pPolicyConfig->uu_depth) max = pPolicyConfig->uu_depth; pPolicyConfig->max_depth = max; } if (!pPolicyConfig->memcap) pPolicyConfig->memcap = DEFAULT_POP_MEMCAP; } else if (defaultConfig == NULL) { if (pPolicyConfig->max_mime_mem) { DynamicPreprocessorFatalMessage("%s(%d) => POP: max_mime_mem must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->b64_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => POP: b64_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->qp_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => POP: qp_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->uu_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => POP: uu_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (pPolicyConfig->bitenc_depth > -1) { DynamicPreprocessorFatalMessage("%s(%d) => POP: bitenc_decode_depth must be " "configured in the default config.\n", *(_dpd.config_file), *(_dpd.config_line)); } } else { pPolicyConfig->max_mime_mem = defaultConfig->max_mime_mem; pPolicyConfig->memcap = defaultConfig->memcap; pPolicyConfig->max_depth = defaultConfig->max_depth; if(pPolicyConfig->disabled) { pPolicyConfig->b64_depth = defaultConfig->b64_depth; pPolicyConfig->qp_depth = defaultConfig->qp_depth; pPolicyConfig->uu_depth = defaultConfig->uu_depth; pPolicyConfig->bitenc_depth = defaultConfig->bitenc_depth; return; } if(!pPolicyConfig->b64_depth && defaultConfig->b64_depth) { DynamicPreprocessorFatalMessage("%s(%d) => POP: Cannot enable unlimited Base64 decoding" " in non-default config without turning on unlimited Base64 decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->b64_depth && (pPolicyConfig->b64_depth > defaultConfig->b64_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => POP: b64_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->b64_depth, defaultConfig->b64_depth); } if(!pPolicyConfig->qp_depth && defaultConfig->qp_depth) { DynamicPreprocessorFatalMessage("%s(%d) => POP: Cannot enable unlimited Quoted-Printable decoding" " in non-default config without turning on unlimited Quoted-Printable decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->qp_depth && (pPolicyConfig->qp_depth > defaultConfig->qp_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => POP: qp_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->qp_depth, defaultConfig->qp_depth); } if(!pPolicyConfig->uu_depth && defaultConfig->uu_depth ) { DynamicPreprocessorFatalMessage("%s(%d) => POP: Cannot enable unlimited Unix-to-Unix decoding" " in non-default config without turning on unlimited Unix-to-Unix decoding in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->uu_depth && (pPolicyConfig->uu_depth > defaultConfig->uu_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => POP: uu_decode_depth value %d in the non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line),pPolicyConfig->uu_depth, defaultConfig->uu_depth); } if(!pPolicyConfig->bitenc_depth && defaultConfig->bitenc_depth) { DynamicPreprocessorFatalMessage("%s(%d) => POP: Cannot enable unlimited Non-Encoded MIME attachment extraction" " in non-default config without turning on unlimited Non-Encoded MIME attachment extraction in the default " " config.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(defaultConfig->bitenc_depth && (pPolicyConfig->bitenc_depth > defaultConfig->bitenc_depth)) { DynamicPreprocessorFatalMessage("%s(%d) => POP: bitenc_decode_depth value %d in non-default config" " cannot exceed default config's value %d.\n", *(_dpd.config_file), *(_dpd.config_line), pPolicyConfig->bitenc_depth, defaultConfig->bitenc_depth); } } } void POP_PrintConfig(POPConfig *config) { int i; int j = 0; char buf[8192]; if (config == NULL) return; memset(&buf[0], 0, sizeof(buf)); _dpd.logMsg("POP Config:\n"); if(config->disabled) _dpd.logMsg(" POP: INACTIVE\n"); snprintf(buf, sizeof(buf) - 1, " Ports: "); for (i = 0; i < 65536; i++) { if (config->ports[i / 8] & (1 << (i % 8))) { j++; _dpd.printfappend(buf, sizeof(buf) - 1, "%d ", i); if(!(j%10)) _dpd.printfappend(buf, sizeof(buf) - 1, "\n "); } } _dpd.logMsg("%s\n", buf); _dpd.logMsg(" POP Memcap: %u\n", config->memcap); _dpd.logMsg(" MIME Max Mem: %d\n", config->max_mime_mem); if(config->b64_depth > -1) { _dpd.logMsg(" Base64 Decoding: %s\n", "Enabled"); switch(config->b64_depth) { case 0: _dpd.logMsg(" Base64 Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Base64 Decoding Depth: %d\n", config->b64_depth); break; } } else _dpd.logMsg(" Base64 Decoding: %s\n", "Disabled"); if(config->qp_depth > -1) { _dpd.logMsg(" Quoted-Printable Decoding: %s\n","Enabled"); switch(config->qp_depth) { case 0: _dpd.logMsg(" Quoted-Printable Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Quoted-Printable Decoding Depth: %d\n", config->qp_depth); break; } } else _dpd.logMsg(" Quoted-Printable Decoding: %s\n", "Disabled"); if(config->uu_depth > -1) { _dpd.logMsg(" Unix-to-Unix Decoding: %s\n","Enabled"); switch(config->uu_depth) { case 0: _dpd.logMsg(" Unix-to-Unix Decoding Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Unix-to-Unix Decoding Depth: %d\n", config->uu_depth); break; } } else _dpd.logMsg(" Unix-to-Unix Decoding: %s\n", "Disabled"); if(config->bitenc_depth > -1) { _dpd.logMsg(" Non-Encoded MIME attachment Extraction: %s\n","Enabled"); switch(config->bitenc_depth) { case 0: _dpd.logMsg(" Non-Encoded MIME attachment Extraction Depth: %s\n", "Unlimited"); break; default: _dpd.logMsg(" Non-Encoded MIME attachment Extraction Depth: %d\n", config->bitenc_depth); break; } } else _dpd.logMsg(" Non-Encoded MIME attachment Extraction: %s\n", "Disabled"); } /* ** NAME ** ProcessPorts:: */ /** ** Process the port list. ** ** This configuration is a list of valid ports and is ended by a ** delimiter. ** ** @param ErrorString error string buffer ** @param ErrStrLen the length of the error string buffer ** ** @return an error code integer ** (0 = success, >0 = non-fatal error, <0 = fatal error) ** ** @retval 0 successs ** @retval -1 generic fatal error ** @retval 1 generic non-fatal error */ static int ProcessPorts(POPConfig *config, char *ErrorString, int ErrStrLen) { char *pcToken; char *pcEnd; int iPort; int iEndPorts = 0; int num_ports = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "POP config is NULL.\n"); return -1; } pcToken = strtok(NULL, CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid port list format."); return -1; } if(strcmp(CONF_START_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a port list with the '%s' token.", CONF_START_LIST); return -1; } /* Since ports are specified, clear default ports */ config->ports[POP_DEFAULT_SERVER_PORT / 8] &= ~(1 << (POP_DEFAULT_SERVER_PORT % 8)); while ((pcToken = strtok(NULL, CONF_SEPARATORS)) != NULL) { if(!strcmp(CONF_END_LIST, pcToken)) { iEndPorts = 1; break; } iPort = strtol(pcToken, &pcEnd, 10); /* ** Validity check for port */ if(*pcEnd) { snprintf(ErrorString, ErrStrLen, "Invalid port number."); return -1; } if(iPort < 0 || iPort > MAXPORTS-1) { snprintf(ErrorString, ErrStrLen, "Invalid port number. Must be between 0 and 65535."); return -1; } config->ports[iPort / 8] |= (1 << (iPort % 8)); num_ports++; } if(!iEndPorts) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", CONF_PORTS, CONF_END_LIST); return -1; } else if(!num_ports) { snprintf(ErrorString, ErrStrLen, "POP: Empty port list not allowed."); return -1; } return 0; } static int ProcessDecodeDepth(POPConfig *config, char *ErrorString, int ErrStrLen, char *decode_type, DecodeType type) { char *endptr; char *value; int decode_depth = 0; if (config == NULL) { snprintf(ErrorString, ErrStrLen, "POP config is NULL.\n"); return -1; } value = strtok(NULL, CONF_SEPARATORS); if ( value == NULL ) { snprintf(ErrorString, ErrStrLen, "Invalid format for POP config option '%s'.", decode_type); return -1; } decode_depth = strtol(value, &endptr, 10); if(*endptr) { snprintf(ErrorString, ErrStrLen, "Invalid format for POP config option '%s'.", decode_type); return -1; } if(decode_depth < MIN_DEPTH || decode_depth > MAX_DEPTH) { snprintf(ErrorString, ErrStrLen, "Invalid value for POP config option '%s'." "It should range between %d and %d.", decode_type, MIN_DEPTH, MAX_DEPTH); return -1; } switch(type) { case DECODE_B64: if((decode_depth > 0) && (decode_depth & 3)) { decode_depth += 4 - (decode_depth & 3); if(decode_depth > MAX_DEPTH ) { decode_depth = decode_depth - 4; } _dpd.logMsg("WARNING: %s(%d) => POP: 'b64_decode_depth' is not a multiple of 4. " "Rounding up to the next multiple of 4. The new 'b64_decode_depth' is %d.\n", *(_dpd.config_file), *(_dpd.config_line), decode_depth); } config->b64_depth = decode_depth; break; case DECODE_QP: config->qp_depth = decode_depth; break; case DECODE_UU: config->uu_depth = decode_depth; break; case DECODE_BITENC: config->bitenc_depth = decode_depth; break; default: return -1; } return 0; } snort-2.9.6.0/src/dynamic-preprocessors/pop/Makefile.am0000644000000000000000000000155111746560364017714 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_pop_preproc.la libsf_pop_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_pop_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_pop_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/mempool.c \ ../include/sf_sdlist.c \ ../include/util_unfold.c \ ../include/sf_base64decode.c \ ../include/sf_email_attach_decode.c \ ../include/sfPolicyUserData.c endif libsf_pop_preproc_la_SOURCES = \ pop_config.c \ pop_config.h \ pop_log.c \ pop_log.h \ pop_util.c \ pop_util.h \ snort_pop.c \ snort_pop.h \ spp_pop.c \ spp_pop.h EXTRA_DIST = \ sf_pop.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/pop/Makefile.in0000644000000000000000000005502712260606522017721 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/pop DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_pop_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_pop_preproc_la_OBJECTS = pop_config.lo pop_log.lo pop_util.lo \ snort_pop.lo spp_pop.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_pop_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo mempool.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_sdlist.lo util_unfold.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_base64decode.lo \ @SO_WITH_STATIC_LIB_FALSE@ sf_email_attach_decode.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_pop_preproc_la_OBJECTS = $(am_libsf_pop_preproc_la_OBJECTS) \ $(nodist_libsf_pop_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_pop_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_pop_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_pop_preproc_la_SOURCES) \ $(nodist_libsf_pop_preproc_la_SOURCES) DIST_SOURCES = $(libsf_pop_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_pop_preproc.la libsf_pop_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_pop_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_pop_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/mempool.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_sdlist.c \ @SO_WITH_STATIC_LIB_FALSE@../include/util_unfold.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_base64decode.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_email_attach_decode.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_pop_preproc_la_SOURCES = \ pop_config.c \ pop_config.h \ pop_log.c \ pop_log.h \ pop_util.c \ pop_util.h \ snort_pop.c \ snort_pop.h \ spp_pop.c \ spp_pop.h EXTRA_DIST = \ sf_pop.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/pop/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/pop/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_pop_preproc.la: $(libsf_pop_preproc_la_OBJECTS) $(libsf_pop_preproc_la_DEPENDENCIES) $(EXTRA_libsf_pop_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_pop_preproc_la_LINK) -rpath $(libdir) $(libsf_pop_preproc_la_OBJECTS) $(libsf_pop_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c mempool.lo: ../include/mempool.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mempool.lo `test -f '../include/mempool.c' || echo '$(srcdir)/'`../include/mempool.c sf_sdlist.lo: ../include/sf_sdlist.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_sdlist.lo `test -f '../include/sf_sdlist.c' || echo '$(srcdir)/'`../include/sf_sdlist.c util_unfold.lo: ../include/util_unfold.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util_unfold.lo `test -f '../include/util_unfold.c' || echo '$(srcdir)/'`../include/util_unfold.c sf_base64decode.lo: ../include/sf_base64decode.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_base64decode.lo `test -f '../include/sf_base64decode.c' || echo '$(srcdir)/'`../include/sf_base64decode.c sf_email_attach_decode.lo: ../include/sf_email_attach_decode.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_email_attach_decode.lo `test -f '../include/sf_email_attach_decode.c' || echo '$(srcdir)/'`../include/sf_email_attach_decode.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/0000755000000000000000000000000012260606563017137 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/sf_ftptelnet.dsp0000644000000000000000000001663512153454770022301 00000000000000# Microsoft Developer Studio Project File - Name="sf_ftptelnet" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=sf_ftptelnet - Win32 IPv6 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_ftptelnet.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_ftptelnet.mak" CFG="sf_ftptelnet - Win32 IPv6 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_ftptelnet - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "sf_ftptelnet - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "sf_ftptelnet - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 ws2_32.lib /nologo /dll /machine:I386 !ELSEIF "$(CFG)" == "sf_ftptelnet - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SF_SMTP_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libs" /I "..\include" /I "..\..\win32\Win32-Includes" /I ".\\" /I "..\..\win32\Win32-Includes\WinPCAP" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "SF_SNORT_PREPROC_DLL" /D "_WINDOWS" /D "_USRDLL" /D "ACTIVE_RESPONSE" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ENABLE_RESPOND" /D "ENABLE_REACT" /D "_WINDLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "_AFXDLL" /D SIGNAL_SNORT_READ_ATTR_TBL=30 /FD /GZ /c # SUBTRACT CPP /X /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 ws2_32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "sf_ftptelnet - Win32 Release" # Name "sf_ftptelnet - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\ftp_bounce_lookup.c # End Source File # Begin Source File SOURCE=.\ftp_cmd_lookup.c # End Source File # Begin Source File SOURCE=.\ftpp_eo_log.c # End Source File # Begin Source File SOURCE=.\ftpp_si.c # End Source File # Begin Source File SOURCE=.\ftpp_ui_client_lookup.c # End Source File # Begin Source File SOURCE=.\ftpp_ui_config.c # End Source File # Begin Source File SOURCE=.\ftpp_ui_server_lookup.c # End Source File # Begin Source File SOURCE=.\hi_util_kmap.c # End Source File # Begin Source File SOURCE=.\hi_util_xmalloc.c # End Source File # Begin Source File SOURCE=..\include\inet_aton.c # End Source File # Begin Source File SOURCE=..\include\inet_pton.c # End Source File # Begin Source File SOURCE=.\pp_ftp.c # End Source File # Begin Source File SOURCE=.\pp_telnet.c # End Source File # Begin Source File SOURCE=..\include\sf_dynamic_preproc_lib.c # End Source File # Begin Source File SOURCE=..\include\sf_ip.c # End Source File # Begin Source File SOURCE=..\include\sfPolicyUserData.c # End Source File # Begin Source File SOURCE=..\include\sfrt.c # End Source File # Begin Source File SOURCE=..\include\sfrt_dir.c # End Source File # Begin Source File SOURCE=.\snort_ftptelnet.c # End Source File # Begin Source File SOURCE=.\spp_ftptelnet.c # End Source File # Begin Source File SOURCE=..\include\strtok_r.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\ftp_bounce_lookup.h # End Source File # Begin Source File SOURCE=.\ftp_client.h # End Source File # Begin Source File SOURCE=.\ftp_cmd_lookup.h # End Source File # Begin Source File SOURCE=.\ftp_server.h # End Source File # Begin Source File SOURCE=.\ftpp_eo.h # End Source File # Begin Source File SOURCE=.\ftpp_eo_events.h # End Source File # Begin Source File SOURCE=.\ftpp_eo_log.h # End Source File # Begin Source File SOURCE=.\ftpp_include.h # End Source File # Begin Source File SOURCE=.\ftpp_return_codes.h # End Source File # Begin Source File SOURCE=.\ftpp_si.h # End Source File # Begin Source File SOURCE=.\ftpp_ui_client_lookup.h # End Source File # Begin Source File SOURCE=.\ftpp_ui_config.h # End Source File # Begin Source File SOURCE=.\ftpp_ui_server_lookup.h # End Source File # Begin Source File SOURCE=.\ftpp_util_kmap.h # End Source File # Begin Source File SOURCE=.\hi_util_kmap.h # End Source File # Begin Source File SOURCE=.\hi_util_xmalloc.h # End Source File # Begin Source File SOURCE=.\pp_ftp.h # End Source File # Begin Source File SOURCE=.\pp_telnet.h # End Source File # Begin Source File SOURCE=.\sf_preproc_info.h # End Source File # Begin Source File SOURCE=.\snort_ftptelnet.h # End Source File # Begin Source File SOURCE=.\spp_ftptelnet.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/spp_ftptelnet.h0000644000000000000000000000246012260565732022123 00000000000000/* * spp_ftptelnet.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file defines the publicly available functions for the FTPTelnet * functionality for Snort. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __SPP_FTPTELNET_H__ #define __SPP_FTPTELNET_H__ void SetupFTPTelnet(void); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/spp_ftptelnet.c0000644000000000000000000005271412260565732022125 00000000000000/* * spp_ftptelnet.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file initializes FTPTelnet as a Snort preprocessor. * * This file registers the FTPTelnet initialization function, * adds the FTPTelnet function into the preprocessor list, reads * the user configuration in the snort.conf file, and prints out * the configuration that is read. * * In general, this file is a wrapper to FTPTelnet functionality, * by interfacing with the Snort preprocessor functions. The rest * of FTPTelnet should be separate from the preprocessor hooks. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "ftpp_ui_config.h" #ifdef CLIENT_READY #include "ftp_client.h" #include "ftp_norm.h" #endif #include "snort_ftptelnet.h" #include "spp_ftptelnet.h" #include "sf_preproc_info.h" #include "profiler.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" const int MAJOR_VERSION = 1; const int MINOR_VERSION = 2; const int BUILD_VERSION = 13; const char *PREPROC_NAME = "SF_FTPTELNET"; #define SetupFTPTelnet DYNAMIC_PREPROC_SETUP /* * Defines for preprocessor initialization */ /* * snort.conf preprocessor keyword */ #define GLOBAL_KEYWORD "ftp_telnet" #define PROTOCOL_KEYWORD "ftp_telnet_protocol" /* * The length of the error string buffer. */ #define ERRSTRLEN 1000 /* * External Global Variables * Variables that we need from Snort to log errors correctly and such. */ #ifdef PERF_PROFILING PreprocStats ftpPerfStats; PreprocStats telnetPerfStats; #ifdef TARGET_BASED PreprocStats ftpdataPerfStats; #endif #endif /* * Global Variables * This is the only way to work with Snort preprocessors because * the user configuration must be kept between the Init function * the actual preprocessor. There is no interaction between the * two except through global variable usage. */ tSfPolicyUserContextId ftp_telnet_config = NULL; FTPTELNET_GLOBAL_CONF *ftp_telnet_eval_config = NULL; #ifdef TARGET_BASED int16_t ftp_app_id = 0; int16_t ftp_data_app_id = 0; int16_t telnet_app_id = 0; #endif /* static function prototypes */ static void FTPTelnetReset(int, void *); static void FTPTelnetResetStats(int, void *); #ifdef SNORT_RELOAD static void FtpTelnetReloadGlobal(struct _SnortConfig *, char *, void **); static void FtpTelnetReload(struct _SnortConfig *, char *, void **); static int FtpTelnetReloadVerify(struct _SnortConfig *, void *); static void * FtpTelnetReloadSwap(struct _SnortConfig *, void *); static void FtpTelnetReloadSwapFree(void *); #endif extern char *maxToken; /* * Function: FTPTelnetChecks(Packet *p) * * Purpose: This function wraps the functionality in the generic FTPTelnet * processing. We get a Packet structure and pass this into the * FTPTelnet module where the first stage in FTPTelnet is the * Normalization stage where most of the other Snortisms are * taken care of. After that, the modules are generic. * * Arguments: p => pointer to a Packet structure that contains * Snort info about the packet. * * Returns: None * */ void FTPTelnetChecks(void *pkt, void *context) { SFSnortPacket *p = (SFSnortPacket*)pkt; // precondition - what we registered for assert(IsTCP(p) && p->payload && p->payload_size); SnortFTPTelnet(p); } #ifdef TARGET_BASED void FTPDataTelnetChecks(void *pkt, void *context) { SFSnortPacket *p = (SFSnortPacket*)pkt; // precondition - what we registered for assert(IsTCP(p)); if ( _dpd.fileAPI->get_max_file_depth() >= 0 ) { if ( _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr) == ftp_data_app_id ) { PROFILE_VARS; PREPROC_PROFILE_START(ftpdataPerfStats); SnortFTPData(p); PREPROC_PROFILE_END(ftpdataPerfStats); return; } } if ( !p->payload_size || (p->payload == NULL) ) return; SnortFTPTelnet(p); } #endif /* * Function: FTPTelnetInit(char *args) * * Purpose: This function cleans up FTPTelnet memory from the configuration * data. * * Arguments: sig => signal causing this to be called * args => pointer to a context strucutre * * Returns: None * */ void FTPTelnetCleanExit(int sig, void *args) { FTPTelnetFreeConfigs(ftp_telnet_config); ftp_telnet_config = NULL; } /* * Function: FTPTelnetInit(char *args) * * Purpose: This function initializes FTPTelnetInit with a user configuration. * The function is called when FTPTelnet is configured in snort.conf. * It gets passed a string of arguments, which gets parsed into * configuration constructs that FTPTelnet understands. * * This function gets called for every FTPTelnet configure line. We * use this characteristic to split up the configuration, so each * line is a configuration construct. We need to keep track of what * part of the configuration has been configured, so we don't * configure one part, then configure it again. * * Any upfront memory is allocated here (if necessary). * * Arguments: args => pointer to a string to the preprocessor arguments. * * Returns: None * */ extern char* mystrtok (char* s, const char* delim); static void FTPTelnetInit(struct _SnortConfig *sc, char *args) { char *pcToken; char ErrorString[ERRSTRLEN]; int iErrStrLen = ERRSTRLEN; int iRet = 0; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); FTPTELNET_GLOBAL_CONF *pPolicyConfig = NULL; ErrorString[0] = '\0'; if ((args == NULL) || (strlen(args) == 0)) { DynamicPreprocessorFatalMessage("%s(%d) No arguments to FtpTelnet " "configuration.\n", *_dpd.config_file, *_dpd.config_line); } /* Find out what is getting configured */ maxToken = args + strlen(args); pcToken = mystrtok(args, CONF_SEPARATORS); if (pcToken == NULL) { DynamicPreprocessorFatalMessage("%s(%d)mystrtok returned NULL when it " "should not.", __FILE__, __LINE__); } if (ftp_telnet_config == NULL) { //create a context ftp_telnet_config = sfPolicyConfigCreate(); if (ftp_telnet_config == NULL) { DynamicPreprocessorFatalMessage("No memory to allocate " "FTP/Telnet configuration.\n"); } _dpd.addPreprocExit(FTPTelnetCleanExit, NULL, PRIORITY_SESSION, PP_FTPTELNET); _dpd.addPreprocReset(FTPTelnetReset, NULL, PRIORITY_SESSION, PP_FTPTELNET); _dpd.addPreprocResetStats(FTPTelnetResetStats, NULL, PRIORITY_SESSION, PP_FTPTELNET); _dpd.addPreprocConfCheck(sc, FTPConfigCheck); #ifdef PERF_PROFILING _dpd.addPreprocProfileFunc("ftptelnet_ftp", (void*)&ftpPerfStats, 0, _dpd.totalPerfStats); _dpd.addPreprocProfileFunc("ftptelnet_telnet", (void*)&telnetPerfStats, 0, _dpd.totalPerfStats); #endif #ifdef TARGET_BASED if (_dpd.streamAPI != NULL) { /* Find and store the application ID for FTP & Telnet */ ftp_app_id = _dpd.addProtocolReference("ftp"); ftp_data_app_id = _dpd.addProtocolReference("ftp-data"); telnet_app_id = _dpd.addProtocolReference("telnet"); } #endif } /* * Global Configuration Processing * We only process the global configuration once, but always check for * user mistakes, like configuring more than once. That's why we * still check for the global token even if it's been checked. */ sfPolicyUserPolicySet (ftp_telnet_config, policy_id); pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(ftp_telnet_config); if (pPolicyConfig == NULL) { if (strcasecmp(pcToken, GLOBAL) != 0) { DynamicPreprocessorFatalMessage("%s(%d) Must configure the " "ftptelnet global configuration first.\n", *_dpd.config_file, *_dpd.config_line); } pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)calloc(1, sizeof(FTPTELNET_GLOBAL_CONF)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("No memory to allocate " "FTP/Telnet configuration.\n"); } sfPolicyUserDataSetCurrent(ftp_telnet_config, pPolicyConfig); iRet = FtpTelnetInitGlobalConfig(pPolicyConfig, ErrorString, iErrStrLen); if (iRet == 0) { iRet = ProcessFTPGlobalConf(pPolicyConfig, ErrorString, iErrStrLen); if (iRet == 0) { PrintFTPGlobalConf(pPolicyConfig); _dpd.preprocOptRegister(sc, "ftp.bounce", &FTPPBounceInit, &FTPPBounceEval, NULL, NULL, NULL, NULL, NULL); #ifdef TARGET_BASED if (_dpd.streamAPI != NULL) { _dpd.streamAPI->set_service_filter_status (sc, ftp_app_id, PORT_MONITOR_SESSION, policy_id, 1); _dpd.streamAPI->set_service_filter_status (sc, telnet_app_id, PORT_MONITOR_SESSION, policy_id, 1); } #endif } } } else if (strcasecmp(pcToken, TELNET) == 0) { iRet = ProcessTelnetConf(pPolicyConfig, ErrorString, iErrStrLen); } else if (strcasecmp(pcToken, FTP) == 0) { pcToken = NextToken(CONF_SEPARATORS); if ( !pcToken ) { DynamicPreprocessorFatalMessage( "%s(%d) Missing ftp_telnet ftp keyword.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if (strcasecmp(pcToken, SERVER) == 0) { iRet = ProcessFTPServerConf(pPolicyConfig, ErrorString, iErrStrLen); } else if (strcasecmp(pcToken, CLIENT) == 0) { iRet = ProcessFTPClientConf(pPolicyConfig, ErrorString, iErrStrLen); } else { DynamicPreprocessorFatalMessage("%s(%d) Invalid ftp_telnet ftp keyword.\n", *(_dpd.config_file), *(_dpd.config_line)); } } else { DynamicPreprocessorFatalMessage("%s(%d) Invalid ftp_telnet keyword.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (iRet) { if(iRet > 0) { /* * Non-fatal Error */ if(*ErrorString) { _dpd.errMsg("WARNING: %s(%d) => %s\n", *(_dpd.config_file), *(_dpd.config_line), ErrorString); } } else { /* * Fatal Error, log error and exit. */ if(*ErrorString) { DynamicPreprocessorFatalMessage("%s(%d) => %s\n", *(_dpd.config_file), *(_dpd.config_line), ErrorString); } else { /* * Check if ErrorString is undefined. */ if(iRet == -2) { DynamicPreprocessorFatalMessage("%s(%d) => ErrorString is undefined.\n", *(_dpd.config_file), *(_dpd.config_line)); } else { DynamicPreprocessorFatalMessage("%s(%d) => Undefined Error.\n", *(_dpd.config_file), *(_dpd.config_line)); } } } } } /* * Function: SetupFTPTelnet() * * Purpose: This function initializes FTPTelnet as a Snort preprocessor. * * It registers the preprocessor keyword for use in the snort.conf * and sets up the initialization module for the preprocessor, in * case it is configured. * * This function must be called in InitPreprocessors() in plugbase.c * in order to be recognized by Snort. * * Arguments: None * * Returns: None * */ void SetupFTPTelnet(void) { #ifndef SNORT_RELOAD _dpd.registerPreproc(GLOBAL_KEYWORD, FTPTelnetInit); _dpd.registerPreproc(PROTOCOL_KEYWORD, FTPTelnetInit); #else _dpd.registerPreproc(GLOBAL_KEYWORD, FTPTelnetInit, FtpTelnetReloadGlobal, FtpTelnetReloadVerify, FtpTelnetReloadSwap, FtpTelnetReloadSwapFree); _dpd.registerPreproc(PROTOCOL_KEYWORD, FTPTelnetInit, FtpTelnetReload, NULL, NULL, NULL); #endif DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Preprocessor: FTPTelnet is " "setup . . .\n");); } static void FTPTelnetReset(int signal, void *data) { return; } static void FTPTelnetResetStats(int signal, void *data) { return; } #ifdef SNORT_RELOAD static void _FtpTelnetReload(struct _SnortConfig *sc, tSfPolicyUserContextId ftp_telnet_swap_config, char *args) { char *pcToken; char ErrorString[ERRSTRLEN]; int iErrStrLen = ERRSTRLEN; int iRet = 0; tSfPolicyId policy_id = _dpd.getParserPolicy(sc); FTPTELNET_GLOBAL_CONF *pPolicyConfig = NULL; ErrorString[0] = '\0'; if ((args == NULL) || (strlen(args) == 0)) { DynamicPreprocessorFatalMessage("%s(%d) No arguments to FtpTelnet " "configuration.\n", *_dpd.config_file, *_dpd.config_line); } /* Find out what is getting configured */ maxToken = args + strlen(args); pcToken = mystrtok(args, CONF_SEPARATORS); if (pcToken == NULL) { DynamicPreprocessorFatalMessage("%s(%d)mystrtok returned NULL when it " "should not.", __FILE__, __LINE__); } /* * Global Configuration Processing * We only process the global configuration once, but always check for * user mistakes, like configuring more than once. That's why we * still check for the global token even if it's been checked. */ sfPolicyUserPolicySet (ftp_telnet_swap_config, policy_id); pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(ftp_telnet_swap_config); if (pPolicyConfig == NULL) { if (strcasecmp(pcToken, GLOBAL) != 0) { DynamicPreprocessorFatalMessage("%s(%d) Must configure the " "ftptelnet global configuration first.\n", *_dpd.config_file, *_dpd.config_line); } pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)calloc(1, sizeof(FTPTELNET_GLOBAL_CONF)); if (pPolicyConfig == NULL) { DynamicPreprocessorFatalMessage("No memory to allocate " "FTP/Telnet configuration.\n"); } sfPolicyUserDataSetCurrent(ftp_telnet_swap_config, pPolicyConfig); iRet = FtpTelnetInitGlobalConfig(pPolicyConfig, ErrorString, iErrStrLen); if (iRet == 0) { iRet = ProcessFTPGlobalConf(pPolicyConfig, ErrorString, iErrStrLen); if (iRet == 0) { PrintFTPGlobalConf(pPolicyConfig); _dpd.preprocOptRegister(sc, "ftp.bounce", &FTPPBounceInit, &FTPPBounceEval, NULL, NULL, NULL, NULL, NULL); } } } else if (strcasecmp(pcToken, TELNET) == 0) { iRet = ProcessTelnetConf(pPolicyConfig, ErrorString, iErrStrLen); } else if (strcasecmp(pcToken, FTP) == 0) { pcToken = NextToken(CONF_SEPARATORS); if ( !pcToken ) { DynamicPreprocessorFatalMessage( "%s(%d) Missing ftp_telnet ftp keyword.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if (strcasecmp(pcToken, SERVER) == 0) { iRet = ProcessFTPServerConf(pPolicyConfig, ErrorString, iErrStrLen); } else if (strcasecmp(pcToken, CLIENT) == 0) { iRet = ProcessFTPClientConf(pPolicyConfig, ErrorString, iErrStrLen); } else { DynamicPreprocessorFatalMessage("%s(%d) Invalid ftp_telnet ftp keyword.\n", *(_dpd.config_file), *(_dpd.config_line)); } } else { DynamicPreprocessorFatalMessage("%s(%d) Invalid ftp_telnet keyword.\n", *(_dpd.config_file), *(_dpd.config_line)); } if (iRet) { if(iRet > 0) { /* * Non-fatal Error */ if(*ErrorString) { _dpd.errMsg("WARNING: %s(%d) => %s\n", *(_dpd.config_file), *(_dpd.config_line), ErrorString); } } else { /* * Fatal Error, log error and exit. */ if(*ErrorString) { DynamicPreprocessorFatalMessage("%s(%d) => %s\n", *(_dpd.config_file), *(_dpd.config_line), ErrorString); } else { /* * Check if ErrorString is undefined. */ if(iRet == -2) { DynamicPreprocessorFatalMessage("%s(%d) => ErrorString is undefined.\n", *(_dpd.config_file), *(_dpd.config_line)); } else { DynamicPreprocessorFatalMessage("%s(%d) => Undefined Error.\n", *(_dpd.config_file), *(_dpd.config_line)); } } } } } static void FtpTelnetReloadGlobal(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId ftp_telnet_swap_config = (tSfPolicyUserContextId)*new_config; if (ftp_telnet_swap_config == NULL) { //create a context ftp_telnet_swap_config = sfPolicyConfigCreate(); if (ftp_telnet_swap_config == NULL) { DynamicPreprocessorFatalMessage("No memory to allocate " "FTP/Telnet swap_configuration.\n"); } *new_config = (void *)ftp_telnet_swap_config; } _FtpTelnetReload(sc, ftp_telnet_swap_config, args); } static void FtpTelnetReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId ftp_telnet_swap_config; ftp_telnet_swap_config = (tSfPolicyUserContextId)_dpd.getRelatedReloadData(sc, GLOBAL_KEYWORD); _FtpTelnetReload(sc, ftp_telnet_swap_config, args); } static int FtpTelnetReloadVerifyPolicy( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { return FTPTelnetCheckConfigs( sc, pData, policyId ); } static int FtpTelnetReloadVerify(struct _SnortConfig *sc, void *new_config) { tSfPolicyUserContextId ftp_telnet_swap_config = (tSfPolicyUserContextId)new_config; if (ftp_telnet_swap_config == NULL) return 0; if (sfPolicyUserDataIterate (sc, ftp_telnet_swap_config, FtpTelnetReloadVerifyPolicy)) return -1; return 0; } static int FtpTelnetReloadSwapPolicy( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { FTPTELNET_GLOBAL_CONF *pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)pData; //do any housekeeping before freeing FTPTELNET_GLOBAL_CONF if (pPolicyConfig->ref_count == 0) { sfPolicyUserDataClear (config, policyId); FTPTelnetFreeConfig(pPolicyConfig); } return 0; } static void * FtpTelnetReloadSwap(struct _SnortConfig *sc, void *new_config) { tSfPolicyUserContextId ftp_telnet_swap_config = (tSfPolicyUserContextId)new_config; tSfPolicyUserContextId old_config = ftp_telnet_config; if (ftp_telnet_swap_config == NULL) return NULL; ftp_telnet_config = ftp_telnet_swap_config; sfPolicyUserDataIterate (sc, old_config, FtpTelnetReloadSwapPolicy); if (sfPolicyUserPolicyGetActive(old_config) == 0) return (void *)old_config; return NULL; } static void FtpTelnetReloadSwapFree(void *data) { if (data == NULL) return; FTPTelnetFreeConfigs((tSfPolicyUserContextId)data); } #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/snort_ftptelnet.h0000644000000000000000000000647712260565732022502 00000000000000/* * snort_ftptelnet.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file defines the publicly available functions for the FTPTelnet * functionality for Snort. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __SNORT_FTPTELNET_H__ #define __SNORT_FTPTELNET_H__ #include "ftpp_ui_config.h" #include "sf_snort_packet.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" /* * The definition of the configuration separators in the snort.conf * configure line. */ #define CONF_SEPARATORS " \t\n\r" /* * These are the definitions of the parser section delimiting * keywords to configure FtpTelnet. When one of these keywords * are seen, we begin a new section. */ #define GLOBAL "global" #define TELNET "telnet" #define FTP "ftp" //#define GLOBAL_CLIENT "global_client" #define CLIENT "client" #define SERVER "server" #ifdef TARGET_BASED extern int16_t ftp_app_id; extern int16_t ftp_data_app_id; extern int16_t telnet_app_id; #endif void FTPTelnetFreeConfigs(tSfPolicyUserContextId GlobalConf); void FTPTelnetFreeConfig(FTPTELNET_GLOBAL_CONF *GlobalConf); int SnortFTPTelnet(SFSnortPacket *p); #ifdef TARGET_BASED void SnortFTPData_EOF(SFSnortPacket *p); int SnortFTPData(SFSnortPacket *p); #endif int FTPConfigCheck(struct _SnortConfig *); int FtpTelnetInitGlobalConfig(FTPTELNET_GLOBAL_CONF *, char *, int); char *NextToken(char *delimiters); int FTPPBounceInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr); int FTPPBounceEval(void *p, const uint8_t **cursor, void *dataPtr); void FTPTelnetChecks(void *pkt, void *context); #ifdef TARGET_BASED void FTPDataTelnetChecks(void *pkt, void *context); #endif void FTPTelnetCleanupFTPServerConf(void *serverConf); void FTPTelnetCleanupFTPCMDConf(void *ftpCmd); void FTPTelnetCleanupFTPClientConf(void *clientConf); void FTPTelnetCleanupFTPBounceTo(void *ftpBounce); int FTPTelnetCheckFTPServerConfigs(struct _SnortConfig *, FTPTELNET_GLOBAL_CONF *); int ProcessFTPGlobalConf(FTPTELNET_GLOBAL_CONF *, char *, int); int ProcessTelnetConf(FTPTELNET_GLOBAL_CONF *, char *, int); int ProcessFTPClientConf(FTPTELNET_GLOBAL_CONF *, char *, int); int ProcessFTPServerConf(FTPTELNET_GLOBAL_CONF *, char *, int); int PrintFTPGlobalConf(FTPTELNET_GLOBAL_CONF *); int FTPTelnetCheckConfigs(struct _SnortConfig *, void* , tSfPolicyId ); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/snort_ftptelnet.c0000644000000000000000000042733612260565732022476 00000000000000/* * snort_ftptelnet.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file wraps the FTPTelnet functionality for Snort * and starts the Normalization & Protocol checks. * * The file takes a Packet structure from the Snort IDS to start the * FTP/Telnet Normalization & Protocol checks. It also uses the Stream * Interface Module which is also Snort-centric. Mainly, just a wrapper * to FTP/Telnet functionality, but a key part to starting the basic flow. * * The main bulk of this file is taken up with user configuration and * parsing. The reason this is so large is because FTPTelnet takes * very detailed configuration parameters for each specified FTP client, * to provide detailed control over an internal network and robust control * of the external network. * * The main functions of note are: * - FTPTelnetSnortConf() the configuration portion * - SnortFTPTelnet() the actual normalization & inspection * - LogEvents() where we log the FTPTelnet events * * NOTES: * - 16.09.04: Initial Development. SAS * */ #define _GNU_SOURCE #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STRINGS_H #include #endif #include #include #include #include #include #include "sf_ip.h" #ifndef WIN32 #include #include #include #include #endif #define BUF_SIZE 1024 #include "sf_types.h" #include "snort_debug.h" #include "ftpp_return_codes.h" #include "ftpp_ui_config.h" #include "ftpp_ui_client_lookup.h" #include "ftpp_ui_server_lookup.h" #include "ftp_cmd_lookup.h" #include "ftp_bounce_lookup.h" #include "ftpp_si.h" #include "ftpp_eo_log.h" #include "pp_telnet.h" #include "pp_ftp.h" #include "snort_ftptelnet.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" #include "stream_api.h" #include "profiler.h" #include "sf_snort_plugin_api.h" #include "Unified2_common.h" #ifdef PERF_PROFILING extern PreprocStats ftpPerfStats; extern PreprocStats telnetPerfStats; PreprocStats ftppDetectPerfStats; int ftppDetectCalled = 0; #endif #ifdef TARGET_BASED static unsigned s_ftpdata_eof_cb_id = 0; #endif extern tSfPolicyUserContextId ftp_telnet_config; /* * GLOBAL subkeyword values */ #define ENCRYPTED_TRAFFIC "encrypted_traffic" #define CHECK_ENCRYPTED "check_encrypted" #define INSPECT_TYPE "inspection_type" #define INSPECT_TYPE_STATELESS "stateless" #define INSPECT_TYPE_STATEFUL "stateful" /* * Protocol subkeywords. */ #define PORTS "ports" /* * Telnet subkeywords. */ #define AYT_THRESHOLD "ayt_attack_thresh" #define NORMALIZE "normalize" #define DETECT_ANOMALIES "detect_anomalies" /* * FTP SERVER subkeywords. */ #define FTP_CMDS "ftp_cmds" #define PRINT_CMDS "print_cmds" #define MAX_PARAM_LEN "def_max_param_len" #define ALT_PARAM_LEN "alt_max_param_len" #define CMD_VALIDITY "cmd_validity" #define STRING_FORMAT "chk_str_fmt" #define TELNET_CMDS "telnet_cmds" #define IGNORE_TELNET_CMDS "ignore_telnet_erase_cmds" #define DATA_CHAN_CMD "data_chan_cmds" #define DATA_XFER_CMD "data_xfer_cmds" #define FILE_PUT_CMD "file_put_cmds" #define FILE_GET_CMD "file_get_cmds" #define DATA_CHAN "data_chan" #define LOGIN_CMD "login_cmds" #define ENCR_CMD "encr_cmds" #define DIR_CMD "dir_cmds" #define IGNORE_DATA_CHAN "ignore_data_chan" /* * FTP CLIENT subkeywords */ #define BOUNCE "bounce" #define ALLOW_BOUNCE "bounce_to" #define MAX_RESP_LEN "max_resp_len" /* * Data type keywords */ #define START_CMD_FORMAT "<" #define END_CMD_FORMAT ">" #define F_INT "int" #define F_NUMBER "number" #define F_CHAR "char" #define F_DATE "date" #define F_LITERAL "'" #define F_STRING "string" #define F_STRING_FMT "formated_string" #define F_HOST_PORT "host_port" #define F_LONG_HOST_PORT "long_host_port" #define F_EXTD_HOST_PORT "extd_host_port" /* * Optional parameter delimiters */ #define START_OPT_FMT "[" #define END_OPT_FMT "]" #define START_CHOICE_FMT "{" #define END_CHOICE_FMT "}" #define OR_FMT "|" /* * The cmd_validity keyword can be used with the format keyword to * restrict data types. The interpretation is specific to the data * type. 'format' is only supported with date & char data types. * * A few examples: * * 1. Will perform validity checking of an FTP Mode command to * check for one of the characters A, S, B, or C. * * cmd_validity MODE char ASBC * * * 2. Will perform validity checking of an FTP MDTM command to * check for an optional date argument following the format * specified. The date would uses the YYYYMMDDHHmmss+TZ format. * * cmd_validity MDTM [ date nnnnnnnnnnnnnn[.n[n[n]]] ] string * * * 3. Will perform validity checking of an FTP ALLO command to * check for an integer, then optionally, the letter R and another * integer. * * cmd_validity ALLO int [ char R int ] */ /* * The def_max_param_len & alt_max_param_len keywords can be used to * restrict parameter length for one or more commands. The space * separated list of commands is enclosed in {}s. * * A few examples: * * 1. Restricts all command parameters to 100 characters * * def_max_param_len 100 * * 2. Overrides CWD pathname to 256 characters * * alt_max_param_len 256 { CWD } * * 3. Overrides PWD & SYST to no parameters * * alt_max_param_len 0 { PWD SYST } * */ /* * Alert subkeywords */ #define BOOL_YES "yes" #define BOOL_NO "no" /* ** IP Address list delimiters */ #define START_IPADDR_LIST "{" #define END_IPADDR_LIST "}" /* * Port list delimiters */ #define START_PORT_LIST "{" #define END_PORT_LIST "}" /* * Keyword for the default client/server configuration */ #define DEFAULT "default" /* * The default FTP server configuration for FTP command validation. * Most of this comes from RFC 959, with additional commands being * drawn from other RFCs/Internet Drafts that are in use. * * Any of the below can be overridden in snort.conf. * * This is here to eliminate most of it from snort.conf to * avoid an ugly configuration file. The default_max_param_len * is somewhat arbitrary, but is taken from the majority of * the snort FTP rules that limit parameter size to 100 * characters, as of 18 Sep 2004. * * The data_chan_cmds, data_xfer_cmds are used to track open * data channel connections. * * The login_cmds and dir_cmds are used to track state of username * and current directory. * * The file_put_cmds and file_get_cmds are used to track file transfers * over open data channel connections. */ /* DEFAULT_FTP_CONF_* deliberately break the default conf into * chunks with lengths < 509 to keep ISO C89 compilers happy */ static const char* DEFAULT_FTP_CONF[] = { "hardcoded_config " "def_max_param_len 100 " "ftp_cmds { USER PASS ACCT CWD CDUP SMNT QUIT REIN TYPE STRU" " MODE RETR STOR STOU APPE ALLO REST RNFR RNTO ABOR" " DELE RMD MKD PWD LIST NLST SITE SYST STAT HELP NOOP } " "ftp_cmds { AUTH ADAT PROT PBSZ CONF ENC } " "ftp_cmds { PORT PASV LPRT LPSV EPRT EPSV } " "ftp_cmds { FEAT OPTS } " "ftp_cmds { MDTM REST SIZE MLST MLSD } " "alt_max_param_len 0 { CDUP QUIT REIN PASV STOU ABOR PWD SYST NOOP } ", "cmd_validity MODE < char SBC > " "cmd_validity STRU < char FRPO [ string ] > " "cmd_validity ALLO < int [ char R int ] > " "cmd_validity TYPE < { char AE [ char NTC ] | char I | char L [ number ] } > " "cmd_validity PORT < host_port > " "cmd_validity LPRT < long_host_port > " "cmd_validity EPRT < extd_host_port > " "cmd_validity EPSV < [ { '1' | '2' | 'ALL' } ] > ", "data_chan_cmds { PORT PASV LPRT LPSV EPRT EPSV } " "data_xfer_cmds { RETR STOR STOU APPE LIST NLST } " "file_put_cmds { STOR STOU } " "file_get_cmds { RETR } " "login_cmds { USER PASS } " "dir_cmds { CWD 250 CDUP 250 PWD 257 } " "encr_cmds { AUTH } " }; #define CONF_CHUNKS (sizeof(DEFAULT_FTP_CONF)/sizeof(DEFAULT_FTP_CONF[0])) static char* DefaultConf (size_t* pn) { unsigned i; size_t sz = 1, ns = 0; char* str = NULL; for ( i = 0; i < CONF_CHUNKS; i++ ) sz += strlen(DEFAULT_FTP_CONF[i]); str = malloc(sz); if ( !str ) DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); for ( i = 0; i < CONF_CHUNKS; i++ ) ns += snprintf(str+ns, sz-ns, "%s", DEFAULT_FTP_CONF[i]); *pn = sz; return str; } static int printedFTPHeader = 0; static int _checkServerConfig(struct _SnortConfig *, void *pData); char *maxToken = NULL; static tSfPolicyId ftp_current_policy = 0; static void _addPortsToStream5(struct _SnortConfig *, char *, tSfPolicyId, int); static int _addFtpServerConfPortsToStream5(struct _SnortConfig *, void *); static void _FTPTelnetAddPortsOfInterest(struct _SnortConfig *, FTPTELNET_GLOBAL_CONF *, tSfPolicyId); #ifdef TARGET_BASED static void _FTPTelnetAddService(struct _SnortConfig *, int16_t, tSfPolicyId); #endif char* mystrtok (char* s, const char* delim) { static char* last = NULL; if ( s || last ) last = strtok(s, delim); return last; } char *NextToken(char *delimiters) { char *retTok = mystrtok(NULL, delimiters); if (retTok > maxToken) return NULL; return retTok; } /* * Function: ProcessConfOpt(FTPTELNET_CONF_OPT *ConfOpt, * char *Option, * char *ErrorString, int ErrStrLen) * * Purpose: Set the CONF_OPT on and alert fields. * * We check to make sure of valid parameters and then set * the appropriate fields. * * Arguments: ConfOpt => pointer to the configuration option * Option => character pointer to the option being configured * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessConfOpt(FTPTELNET_CONF_OPT *ConfOpt, char *Option, char *ErrorString, int ErrStrLen) { char *pcToken; pcToken = NextToken(CONF_SEPARATORS); if(pcToken == NULL) { snprintf(ErrorString, ErrStrLen, "No argument to token '%s'.", Option); return FTPP_FATAL_ERR; } /* * Check for the alert value */ if(!strcmp(BOOL_YES, pcToken)) { ConfOpt->alert = 1; } else if(!strcmp(BOOL_NO, pcToken)) { ConfOpt->alert = 0; } else { snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s'.", Option); return FTPP_FATAL_ERR; } ConfOpt->on = 1; return FTPP_SUCCESS; } /* * Function: PrintConfOpt(FTPTELNET_CONF_OPT *ConfOpt, * char *Option) * * Purpose: Prints the CONF_OPT and alert fields. * * Arguments: ConfOpt => pointer to the configuration option * Option => character pointer to the option being configured * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int PrintConfOpt(FTPTELNET_CONF_OPT *ConfOpt, char *Option) { if(!ConfOpt || !Option) { return FTPP_INVALID_ARG; } if(ConfOpt->on) { _dpd.logMsg(" %s: YES alert: %s\n", Option, ConfOpt->alert ? "YES" : "NO"); } else { _dpd.logMsg(" %s: OFF\n", Option); } return FTPP_SUCCESS; } /* * Function: ProcessInspectType(FTPTELNET_CONF_OPT *ConfOpt, * char *ErrorString, int ErrStrLen) * * Purpose: Process the type of inspection. * This sets the type of inspection for FTPTelnet to do. * * Arguments: GlobalConf => pointer to the global configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessInspectType(FTPTELNET_GLOBAL_CONF *GlobalConf, char *ErrorString, int ErrStrLen) { char *pcToken; pcToken = NextToken(CONF_SEPARATORS); if(pcToken == NULL) { snprintf(ErrorString, ErrStrLen, "No argument to token '%s'.", INSPECT_TYPE); return FTPP_FATAL_ERR; } if(!strcmp(INSPECT_TYPE_STATEFUL, pcToken)) { GlobalConf->inspection_type = FTPP_UI_CONFIG_STATEFUL; } else if(!strcmp(INSPECT_TYPE_STATELESS, pcToken)) { GlobalConf->inspection_type = FTPP_UI_CONFIG_STATELESS; } else { snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s'. Must be either " "'%s' or '%s'.", INSPECT_TYPE, INSPECT_TYPE_STATEFUL, INSPECT_TYPE_STATELESS); return FTPP_FATAL_ERR; } return FTPP_SUCCESS; } /* * Function: ProcessFTPGlobalConf(FTPTELNET_GLOBAL_CONF *GlobalConf, * char *ErrorString, int ErrStrLen) * * Purpose: This is where we process the global configuration for FTPTelnet. * * We set the values of the global configuraiton here. Any errors * that are encountered are specified in the error string and the * type of error is returned through the return code, i.e. fatal, * non-fatal. * * The configuration options that are dealt with here are: * - inspection_type * Indicate whether to operate in stateful stateless mode * - encrypted_traffic * Detect and alert on encrypted sessions * - check_after_encrypted * Instructs the preprocessor to continue checking a data stream * after it is encrypted, looking for an eventual * non-ecrypted data. * * Arguments: GlobalConf => pointer to the global configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int ProcessFTPGlobalConf(FTPTELNET_GLOBAL_CONF *GlobalConf, char *ErrorString, int ErrStrLen) { FTPTELNET_CONF_OPT *ConfOpt; int iRet = 0; char *pcToken; int iTokens = 0; while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { /* * Show that we at least got one token */ iTokens = 1; /* * Search for configuration keywords */ if (!strcmp(pcToken, CHECK_ENCRYPTED)) { GlobalConf->check_encrypted_data = 1; } else if (!strcmp(pcToken, ENCRYPTED_TRAFFIC)) { ConfOpt = &GlobalConf->encrypted; iRet = ProcessConfOpt(ConfOpt, ENCRYPTED_TRAFFIC, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if(!strcmp(INSPECT_TYPE, pcToken)) { iRet = ProcessInspectType(GlobalConf, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else { snprintf(ErrorString, ErrStrLen, "Invalid keyword '%s' for '%s' configuration.", pcToken, GLOBAL); return FTPP_FATAL_ERR; } } /* * If there are not any tokens to the configuration, then * we let the user know and log the error. return non-fatal * error. */ if(!iTokens) { snprintf(ErrorString, ErrStrLen, "No tokens to '%s' configuration.", GLOBAL); return FTPP_NONFATAL_ERR; } return FTPP_SUCCESS; } /* * Function: ProcessPorts(PROTO_CONF *protocol, * char *ErrorString, int ErrStrLen) * * Purpose: Process the port list for the server configuration. * This configuration is a list of valid ports and is ended * by a delimiter. * * Arguments: protocol => pointer to the ports configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessPorts(PROTO_CONF *protocol, char *ErrorString, int ErrStrLen) { char *pcToken; char *pcEnd; int iPort; int iEndPorts = 0; pcToken = NextToken(CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid port list format."); return FTPP_FATAL_ERR; } if(strcmp(START_PORT_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a port list with the '%s' token.", START_PORT_LIST); return FTPP_FATAL_ERR; } /* Unset the defaults */ for (iPort = 0;iPortports[iPort] = 0; while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { if(!strcmp(END_PORT_LIST, pcToken)) { iEndPorts = 1; break; } iPort = strtol(pcToken, &pcEnd, 10); /* * Validity check for port */ if(*pcEnd) { snprintf(ErrorString, ErrStrLen, "Invalid port number."); return FTPP_FATAL_ERR; } if(iPort < 0 || iPort > MAXPORTS-1) { snprintf(ErrorString, ErrStrLen, "Invalid port number. Must be between 0 and " "65535."); return FTPP_FATAL_ERR; } protocol->ports[iPort] = 1; if(protocol->port_count < MAXPORTS) protocol->port_count++; } if(!iEndPorts) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", PORTS, END_PORT_LIST); return FTPP_FATAL_ERR; } return FTPP_SUCCESS; } /* * Function: ProcessTelnetAYTThreshold(TELNET_PROTO_CONF *TelnetConf, * char *ErrorString, int ErrStrLen) * * Purpose: Process the 'are you there' threshold configuration * This sets the maximum number of telnet ayt commands that * we will tolerate, before alerting. * * Arguments: TelnetConf => pointer to the telnet configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessTelnetAYTThreshold(TELNET_PROTO_CONF *TelnetConf, char *ErrorString, int ErrStrLen) { char *pcToken; char *pcEnd = NULL; pcToken = NextToken(CONF_SEPARATORS); if(pcToken == NULL) { snprintf(ErrorString, ErrStrLen, "No argument to token '%s'.", AYT_THRESHOLD); return FTPP_FATAL_ERR; } TelnetConf->ayt_threshold = strtol(pcToken, &pcEnd, 10); /* * Let's check to see if the entire string was valid. * If there is an address here, then there was an * invalid character in the string. */ if(*pcEnd) { snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s'. Must be a positive " "number.", AYT_THRESHOLD); return FTPP_FATAL_ERR; } return FTPP_SUCCESS; } /* * Function: PrintTelnetConf(TELNET_PROTO_CONF *TelnetConf, * char *Option) * * Purpose: Prints the telnet configuration * * Arguments: TelnetConf => pointer to the telnet configuration * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int PrintTelnetConf(TELNET_PROTO_CONF *TelnetConf) { char buf[BUF_SIZE+1]; int iCtr; if(!TelnetConf) { return FTPP_INVALID_ARG; } _dpd.logMsg(" TELNET CONFIG:\n"); memset(buf, 0, BUF_SIZE+1); snprintf(buf, BUF_SIZE, " Ports: "); /* * Print out all the applicable ports. */ for(iCtr = 0; iCtr < MAXPORTS; iCtr++) { if(TelnetConf->proto_ports.ports[iCtr]) { _dpd.printfappend(buf, BUF_SIZE, "%d ", iCtr); } } _dpd.logMsg("%s\n", buf); _dpd.logMsg(" Are You There Threshold: %d\n", TelnetConf->ayt_threshold); _dpd.logMsg(" Normalize: %s\n", TelnetConf->normalize ? "YES" : "NO"); _dpd.logMsg(" Detect Anomalies: %s\n", TelnetConf->detect_anomalies ? "YES" : "NO"); return FTPP_SUCCESS; } /* * Function: ProcessTelnetConf(FTPTELNET_GLOBAL_CONF *GlobalConf, * char *ErrorString, int ErrStrLen) * * Purpose: This is where we process the telnet configuration for FTPTelnet. * * We set the values of the telnet configuraiton here. Any errors * that are encountered are specified in the error string and the * type of error is returned through the return code, i.e. fatal, * non-fatal. * * The configuration options that are dealt with here are: * - ports { x } Ports on which to do telnet checks * - normalize Turns on normalization * - ayt_attack_thresh x Detect consecutive are you there commands * * Arguments: GlobalConf => pointer to the global configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int ProcessTelnetConf(FTPTELNET_GLOBAL_CONF *GlobalConf, char *ErrorString, int ErrStrLen) { int iRet; char *pcToken; int iTokens = 0; if (GlobalConf->telnet_config != NULL) { snprintf(ErrorString, ErrStrLen, "Telnet can only be configured once.\n"); return FTPP_FATAL_ERR; } GlobalConf->telnet_config = (TELNET_PROTO_CONF *)calloc(1, sizeof(TELNET_PROTO_CONF)); if (GlobalConf->telnet_config == NULL) { DynamicPreprocessorFatalMessage("Out of memory trying to create " "telnet configuration.\n"); } /* * Reset the global telnet configuration */ if(ftpp_ui_config_reset_telnet_proto(GlobalConf->telnet_config)) { snprintf(ErrorString, ErrStrLen, "Cannot reset the FTPTelnet global telnet configuration."); return FTPP_FATAL_ERR; } while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { /* * Show that we at least got one token */ iTokens = 1; /* * Search for configuration keywords */ if(!strcmp(PORTS, pcToken)) { PROTO_CONF *ports = (PROTO_CONF*)GlobalConf->telnet_config; iRet = ProcessPorts(ports, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if(!strcmp(AYT_THRESHOLD, pcToken)) { iRet = ProcessTelnetAYTThreshold(GlobalConf->telnet_config, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if(!strcmp(NORMALIZE, pcToken)) { GlobalConf->telnet_config->normalize = 1; } else if(!strcmp(DETECT_ANOMALIES, pcToken)) { GlobalConf->telnet_config->detect_anomalies = 1; } /* * Start the CONF_OPT configurations. */ else { snprintf(ErrorString, ErrStrLen, "Invalid keyword '%s' for '%s' configuration.", pcToken, GLOBAL); return FTPP_FATAL_ERR; } } /* * If there are not any tokens to the configuration, then * we let the user know and log the error. return non-fatal * error. */ if(!iTokens) { snprintf(ErrorString, ErrStrLen, "No tokens to '%s' configuration.", TELNET); return FTPP_NONFATAL_ERR; } /* Let's print out the telnet config */ PrintTelnetConf(GlobalConf->telnet_config); return FTPP_SUCCESS; } #if 0 /**obsoleted during changes for bug_31418 */ /* * Function: GetIPAddr(char *addrString, unsigned uint32_t *ipAddr, * char *ErrorString, int ErrStrLen) * * Purpose: This is where we convert an IP address to a numeric * * Any errors that are encountered are specified in the error * string and the type of error is returned through the return * code, i.e. fatal, non-fatal. * * Arguments: addrString => pointer to the address string * ipAddr => pointer to converted address * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int GetIPAddr(char *addrString, snort_ip *ipAddr, char *ErrorString, int ErrStrLen) { if(sfip_pton(addrString, ipAddr) != SFIP_SUCCESS) { snprintf(ErrorString, ErrStrLen, "Invalid FTP client IP address '%s'.", addrString); return FTPP_FATAL_ERR; } return FTPP_SUCCESS; } #endif /* * Function: ProcessFTPCmdList(FTP_SERVER_PROTO_CONF *ServerConf, * char *confOption, * char *ErrorString, int ErrStrLen, * int require_cmds, int require_length) * * Purpose: Process the FTP cmd lists for the client configuration. * This configuration is a parameter length for the list of * FTP commands and is ended by a delimiter. * * Arguments: ServerConf => pointer to the FTP server configuration * confOption => pointer to the name of the option * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * require_cmds => flag to require a command list * require_length => flag to require a length specifier * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessFTPCmdList(FTP_SERVER_PROTO_CONF *ServerConf, char *confOption, char *ErrorString, int ErrStrLen, int require_cmds, int require_length) { FTP_CMD_CONF *FTPCmd = NULL; char *pcToken; char *pcEnd = NULL; char *cmd; int iLength = 0; int iEndCmds = 0; int iRet; if (require_length) { pcToken = NextToken(CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid cmd list format."); return FTPP_FATAL_ERR; } iLength = strtol(pcToken, &pcEnd, 10); /* * Let's check to see if the entire string was valid. * If there is an address here, then there was an * invalid character in the string. */ if((*pcEnd) || (iLength < 0)) { snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s'. " "Length must be a positive number", confOption); return FTPP_FATAL_ERR; } } if (require_cmds) { pcToken = NextToken(CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid cmd list format."); return FTPP_FATAL_ERR; } if(strcmp(START_PORT_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a cmd list with the '%s' token.", START_PORT_LIST); return FTPP_FATAL_ERR; } while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { if(!strcmp(END_PORT_LIST, pcToken)) { iEndCmds = 1; break; } cmd = pcToken; FTPCmd = ftp_cmd_lookup_find(ServerConf->cmd_lookup, cmd, strlen(cmd), &iRet); if (FTPCmd == NULL) { /* Add it to the list */ // note that struct includes 1 byte for null, so just add len FTPCmd = (FTP_CMD_CONF *)calloc(1, sizeof(FTP_CMD_CONF)+strlen(cmd)); if (FTPCmd == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strcpy(FTPCmd->cmd_name, cmd); ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd, strlen(cmd), FTPCmd); FTPCmd->max_param_len = ServerConf->def_max_param_len; } if (require_length) { FTPCmd->max_param_len = iLength; FTPCmd->max_param_len_overridden = 1; } } if(!iEndCmds) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", FTP_CMDS, END_PORT_LIST); return FTPP_FATAL_ERR; } } if (!strcmp(confOption, MAX_PARAM_LEN)) { ServerConf->def_max_param_len = iLength; /* Reset the max length to the default for all existing commands */ FTPCmd = ftp_cmd_lookup_first(ServerConf->cmd_lookup, &iRet); while (FTPCmd) { if (!FTPCmd->max_param_len_overridden) { FTPCmd->max_param_len = ServerConf->def_max_param_len; } FTPCmd = ftp_cmd_lookup_next(ServerConf->cmd_lookup, &iRet); } } return FTPP_SUCCESS; } /* * Function: ResetStringFormat (FTP_PARAM_FMT *Fmt) * * Purpose: Recursively sets nodes that allow strings to nodes that check * for a string format attack within the FTP parameter validation tree * * Arguments: Fmt => pointer to the FTP Parameter configuration * * Returns: None * */ void ResetStringFormat (FTP_PARAM_FMT *Fmt) { int i; if (!Fmt) return; if (Fmt->type == e_unrestricted) Fmt->type = e_strformat; ResetStringFormat(Fmt->optional_fmt); for (i=0;inumChoices;i++) { ResetStringFormat(Fmt->choices[i]); } ResetStringFormat(Fmt->next_param_fmt); } /* * Function: ProcessFTPDataChanCmdsList(FTP_SERVER_PROTO_CONF *ServerConf, * char *confOption, * char *ErrorString, int ErrStrLen) * * Purpose: Process the FTP cmd lists for the client configuration. * This configuration is an indicator of data channels, data transfer, * string format, encryption, or login commands. * * Arguments: ServerConf => pointer to the FTP server configuration * confOption => pointer to the name of the option * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessFTPDataChanCmdsList(FTP_SERVER_PROTO_CONF *ServerConf, char *confOption, char *ErrorString, int ErrStrLen) { FTP_CMD_CONF *FTPCmd = NULL; char *pcToken; char *cmd; int iEndCmds = 0; int iRet; pcToken = NextToken(CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid %s list format.", confOption); return FTPP_FATAL_ERR; } if(strcmp(START_PORT_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a %s list with the '%s' token.", confOption, START_PORT_LIST); return FTPP_FATAL_ERR; } while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { if(!strcmp(END_PORT_LIST, pcToken)) { iEndCmds = 1; break; } cmd = pcToken; FTPCmd = ftp_cmd_lookup_find(ServerConf->cmd_lookup, cmd, strlen(cmd), &iRet); if (FTPCmd == NULL) { /* Add it to the list */ // note that struct includes 1 byte for null, so just add len FTPCmd = (FTP_CMD_CONF *)calloc(1, sizeof(FTP_CMD_CONF)+strlen(cmd)); if (FTPCmd == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strcpy(FTPCmd->cmd_name, cmd); FTPCmd->max_param_len = ServerConf->def_max_param_len; ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd, strlen(cmd), FTPCmd); } if (!strcmp(confOption, DATA_CHAN_CMD)) FTPCmd->data_chan_cmd = 1; else if (!strcmp(confOption, DATA_XFER_CMD)) FTPCmd->data_xfer_cmd = 1; else if (!strcmp(confOption, FILE_PUT_CMD)) { FTPCmd->data_xfer_cmd = 1; FTPCmd->file_put_cmd = 1; } else if (!strcmp(confOption, FILE_GET_CMD)) { FTPCmd->data_xfer_cmd = 1; FTPCmd->file_get_cmd = 1; } else if (!strcmp(confOption, STRING_FORMAT)) { FTP_PARAM_FMT *Fmt = FTPCmd->param_format; if (Fmt) { ResetStringFormat(Fmt); } else { Fmt = (FTP_PARAM_FMT *)calloc(1, sizeof(FTP_PARAM_FMT)); if (Fmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } Fmt->type = e_head; FTPCmd->param_format = Fmt; Fmt = (FTP_PARAM_FMT *)calloc(1, sizeof(FTP_PARAM_FMT)); if (Fmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } Fmt->type = e_strformat; FTPCmd->param_format->next_param_fmt = Fmt; Fmt->prev_param_fmt = FTPCmd->param_format; } FTPCmd->check_validity = 1; } else if (!strcmp(confOption, ENCR_CMD)) FTPCmd->encr_cmd = 1; else if (!strcmp(confOption, LOGIN_CMD)) FTPCmd->login_cmd = 1; } if(!iEndCmds) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", confOption, END_PORT_LIST); return FTPP_FATAL_ERR; } return FTPP_SUCCESS; } /* * Function: ProcessFTPDirCmdsList(FTP_SERVER_PROTO_CONF *ServerConf, * char *confOption, * char *ErrorString, int ErrStrLen) * * Purpose: Process the FTP cmd lists for the client configuration. * This configuration is an indicator of commands used to * retrieve or update the current directory. * * Arguments: ServerConf => pointer to the FTP server configuration * confOption => pointer to the name of the option * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessFTPDirCmdsList(FTP_SERVER_PROTO_CONF *ServerConf, char *confOption, char *ErrorString, int ErrStrLen) { FTP_CMD_CONF *FTPCmd = NULL; char *pcToken; char *pcEnd = NULL; char *cmd; int iCode; int iEndCmds = 0; int iRet; pcToken = NextToken(CONF_SEPARATORS); if(!pcToken) { snprintf(ErrorString, ErrStrLen, "Invalid %s list format.", confOption); return FTPP_FATAL_ERR; } if(strcmp(START_PORT_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a %s list with the '%s' token.", confOption, START_PORT_LIST); return FTPP_FATAL_ERR; } while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { if(!strcmp(END_PORT_LIST, pcToken)) { iEndCmds = 1; break; } cmd = pcToken; FTPCmd = ftp_cmd_lookup_find(ServerConf->cmd_lookup, cmd, strlen(cmd), &iRet); if (FTPCmd == NULL) { /* Add it to the list */ // note that struct includes 1 byte for null, so just add len FTPCmd = (FTP_CMD_CONF *)calloc(1, sizeof(FTP_CMD_CONF)+strlen(cmd)); if (FTPCmd == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strcpy(FTPCmd->cmd_name, cmd); FTPCmd->max_param_len = ServerConf->def_max_param_len; ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd, strlen(cmd), FTPCmd); } pcToken = NextToken(CONF_SEPARATORS); if (!pcToken) { snprintf(ErrorString, ErrStrLen, "FTP Dir Cmds must have associated response code: '%s'.", cmd); return FTPP_FATAL_ERR; } iCode = strtol(pcToken, &pcEnd, 10); /* * Let's check to see if the entire string was valid. * If there is an address here, then there was an * invalid character in the string. */ if((*pcEnd) || (iCode < 0)) { snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s'. " "Code must be a positive number", confOption); return FTPP_FATAL_ERR; } FTPCmd->dir_response = iCode; } if(!iEndCmds) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", confOption, END_PORT_LIST); return FTPP_FATAL_ERR; } return FTPP_SUCCESS; } static int ProcessFTPIgnoreDataChan(FTP_SERVER_PROTO_CONF *ServerConf, char *confOption, char *ErrorString, int ErrStrLen) { char *pcToken; pcToken = NextToken(CONF_SEPARATORS); if (pcToken == NULL) { snprintf(ErrorString, ErrStrLen, "No argument provided to option '%s'. " "Argument must be 'yes' or 'no'.", confOption); return FTPP_FATAL_ERR; } if (!strcasecmp("yes", pcToken)) { ServerConf->data_chan = 1; } else if (!strcasecmp("no", pcToken)) { if (ServerConf->data_chan == 1) { snprintf(ErrorString, ErrStrLen, "Both 'data_chan' and " "'ignore_data_chan' configured with conflicting options."); return FTPP_FATAL_ERR; } ServerConf->data_chan = 0; } else { snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s'. " "Argument must be 'yes' or 'no'.", confOption); return FTPP_FATAL_ERR; } return FTPP_SUCCESS; } /* * Function: SetOptionalsNext(FTP_PARAM_FMT *ThisFmt, * FTP_PARAM_FMT *NextFmt, * FTP_PARAM_FMT **choices, * int numChoices) * * Purpose: Recursively updates the next value for nodes in the FTP * Parameter validation tree. * * Arguments: ThisFmt => pointer to an FTP parameter validation node * NextFmt => pointer to an FTP parameter validation node * choices => pointer to a list of FTP parameter * validation nodes * numChoices => the number of nodes in the list * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static void SetOptionalsNext(FTP_PARAM_FMT *ThisFmt, FTP_PARAM_FMT *NextFmt, FTP_PARAM_FMT **choices, int numChoices) { if (!ThisFmt) return; if (ThisFmt->optional) { if (ThisFmt->next_param_fmt == NULL) { ThisFmt->next_param_fmt = NextFmt; if (numChoices) { ThisFmt->numChoices = numChoices; ThisFmt->choices = (FTP_PARAM_FMT **)calloc(numChoices, sizeof(FTP_PARAM_FMT *)); if (ThisFmt->choices == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } memcpy(ThisFmt->choices, choices, sizeof(FTP_PARAM_FMT *) * numChoices); } } else { SetOptionalsNext(ThisFmt->next_param_fmt, NextFmt, choices, numChoices); } } else { int i; SetOptionalsNext(ThisFmt->optional_fmt, ThisFmt->next_param_fmt, ThisFmt->choices, ThisFmt->numChoices); for (i=0;inumChoices;i++) { SetOptionalsNext(ThisFmt->choices[i], ThisFmt, choices, numChoices); } SetOptionalsNext(ThisFmt->next_param_fmt, ThisFmt, choices, numChoices); } } /* * Function: ProcessDateFormat(FTP_DATE_FMT *dateFmt, * FTP_DATE_FMT *LastNonOptFmt, * char **format) * * Purpose: Sets the value for nodes in the FTP Date validation tree. * * Arguments: dateFmt => pointer to an FTP date validation node * LastNonOptFmt => pointer to previous FTP date validation node * format => pointer to next part of date validation string * Updated on function exit. * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessDateFormat(FTP_DATE_FMT *dateFmt, FTP_DATE_FMT *LastNonOptFmt, char **format) { char *curr_format; int iRet = FTPP_SUCCESS; int curr_len = 0; char *curr_ch; char *start_ch; FTP_DATE_FMT *CurrFmt = dateFmt; if (!dateFmt) return FTPP_INVALID_ARG; if (!format || !*format) return FTPP_INVALID_ARG; start_ch = curr_ch = *format; while (*curr_ch != '\0') { switch (*curr_ch) { case 'n': case 'C': case '+': case '-': case '.': curr_len++; curr_ch++; break; case '[': curr_ch++; if (curr_len > 0) { FTP_DATE_FMT *OptFmt; OptFmt = (FTP_DATE_FMT *)calloc(1, sizeof(FTP_DATE_FMT)); if (OptFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } curr_format = (char *)calloc(curr_len + 1, sizeof(char)); if (curr_format == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strncpy(curr_format, start_ch, curr_len); CurrFmt->format_string = curr_format; curr_len = 0; CurrFmt->optional = OptFmt; OptFmt->prev = CurrFmt; iRet = ProcessDateFormat(OptFmt, CurrFmt, &curr_ch); if (iRet != FTPP_SUCCESS) { free(OptFmt); free(curr_format); return iRet; } } start_ch = curr_ch; break; case ']': curr_ch++; if (curr_len > 0) { curr_format = (char *)calloc(curr_len + 1, sizeof(char)); if (curr_format == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strncpy(curr_format, start_ch, curr_len); CurrFmt->format_string = curr_format; curr_len = 0; } *format = curr_ch; return FTPP_SUCCESS; break; case '{': curr_ch++; { FTP_DATE_FMT *NewFmt; NewFmt = (FTP_DATE_FMT *)calloc(1, sizeof(FTP_DATE_FMT)); if (NewFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } if (curr_len > 0) { curr_format = (char *)calloc(curr_len + 1, sizeof(char)); if (curr_format == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strncpy(curr_format, start_ch, curr_len); CurrFmt->format_string = curr_format; curr_len = 0; } else { CurrFmt->empty = 1; } NewFmt->prev = LastNonOptFmt; CurrFmt->next_a = NewFmt; iRet = ProcessDateFormat(NewFmt, CurrFmt, &curr_ch); if (iRet != FTPP_SUCCESS) { return iRet; } NewFmt = (FTP_DATE_FMT *)calloc(1, sizeof(FTP_DATE_FMT)); if (NewFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } NewFmt->prev = LastNonOptFmt; CurrFmt->next_b = NewFmt; iRet = ProcessDateFormat(NewFmt, CurrFmt, &curr_ch); if (iRet != FTPP_SUCCESS) { return iRet; } NewFmt = (FTP_DATE_FMT *)calloc(1, sizeof(FTP_DATE_FMT)); if (NewFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } NewFmt->prev = CurrFmt; CurrFmt->next = NewFmt; iRet = ProcessDateFormat(NewFmt, CurrFmt, &curr_ch); if (iRet != FTPP_SUCCESS) { return iRet; } } break; case '}': curr_ch++; if (curr_len > 0) { curr_format = (char *)calloc(curr_len + 1, sizeof(char)); if (curr_format == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strncpy(curr_format, start_ch, curr_len); CurrFmt->format_string = curr_format; curr_len = 0; *format = curr_ch; return FTPP_SUCCESS; } else { CurrFmt->empty = 1; *format = curr_ch; return FTPP_SUCCESS; } break; case '|': curr_ch++; if (curr_len > 0) { curr_format = (char *)calloc(curr_len + 1, sizeof(char)); if (curr_format == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strncpy(curr_format, start_ch, curr_len); CurrFmt->format_string = curr_format; curr_len = 0; *format = curr_ch; return FTPP_SUCCESS; } else { CurrFmt->empty = 1; *format = curr_ch; return FTPP_SUCCESS; } break; default: /* Uh, shouldn't get this. */ return FTPP_INVALID_ARG; break; } } if (curr_len > 0) { curr_format = (char *)calloc(curr_len + 1, sizeof(char)); if (curr_format == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strncpy(curr_format, start_ch, curr_len); CurrFmt->format_string = curr_format; start_ch = curr_ch; curr_len = 0; } /* Should've closed all options & ORs */ *format = curr_ch; return FTPP_SUCCESS; } /* * Function: DoNextFormat(FTP_PARAM_FMT *ThisFmt, int allocated, * char *ErrorString, int ErrStrLen) * * Purpose: Processes the next FTP parameter validation node. * * Arguments: ThisFmt => pointer to an FTP parameter validation node * allocated => indicator whether the next node is allocated * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int DoNextFormat(FTP_PARAM_FMT *ThisFmt, int allocated, char *ErrorString, int ErrStrLen) { FTP_PARAM_FMT *NextFmt; int iRet = FTPP_SUCCESS; char *fmt = NextToken(CONF_SEPARATORS); if (!fmt) return FTPP_INVALID_ARG; if(!strcmp(END_CMD_FORMAT, fmt)) { return FTPP_SUCCESS; } if (!strcmp(fmt, OR_FMT)) { return FTPP_OR_FOUND; } if (!strcmp(fmt, END_OPT_FMT)) { return FTPP_OPT_END_FOUND; } if (!strcmp(fmt, END_CHOICE_FMT)) { return FTPP_CHOICE_END_FOUND; } if (!strcmp(fmt, START_OPT_FMT)) { NextFmt = (FTP_PARAM_FMT *)calloc(1, sizeof(FTP_PARAM_FMT)); if (NextFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } ThisFmt->optional_fmt = NextFmt; NextFmt->optional = 1; NextFmt->prev_param_fmt = ThisFmt; if (ThisFmt->optional) NextFmt->prev_optional = 1; iRet = DoNextFormat(NextFmt, 1, ErrorString, ErrStrLen); if (iRet != FTPP_OPT_END_FOUND) { return FTPP_INVALID_ARG; } return DoNextFormat(ThisFmt, 0, ErrorString, ErrStrLen); } if (!strcmp(fmt, START_CHOICE_FMT)) { int numChoices = 1; do { FTP_PARAM_FMT **tmpChoices = (FTP_PARAM_FMT **)calloc(numChoices, sizeof(FTP_PARAM_FMT *)); if (tmpChoices == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } if (ThisFmt->numChoices) { /* explicit check that we have enough room for copy */ if (numChoices <= ThisFmt->numChoices) DynamicPreprocessorFatalMessage("%s(%d) => Can't do memcpy - index out of range \n", *(_dpd.config_file), *(_dpd.config_line)); memcpy(tmpChoices, ThisFmt->choices, sizeof(FTP_PARAM_FMT*) * ThisFmt->numChoices); } NextFmt = (FTP_PARAM_FMT *)calloc(1, sizeof(FTP_PARAM_FMT)); if (NextFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } ThisFmt->numChoices = numChoices; tmpChoices[numChoices-1] = NextFmt; if (ThisFmt->choices) free(ThisFmt->choices); ThisFmt->choices = tmpChoices; NextFmt->prev_param_fmt = ThisFmt; iRet = DoNextFormat(NextFmt, 1, ErrorString, ErrStrLen); numChoices++; } while (iRet == FTPP_OR_FOUND); if (iRet != FTPP_CHOICE_END_FOUND) { return FTPP_INVALID_ARG; } return DoNextFormat(ThisFmt, 0, ErrorString, ErrStrLen); } if (!allocated) { NextFmt = (FTP_PARAM_FMT *)calloc(1, sizeof(FTP_PARAM_FMT)); if (NextFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } NextFmt->prev_param_fmt = ThisFmt; ThisFmt->next_param_fmt = NextFmt; if (ThisFmt->optional) NextFmt->prev_optional = 1; } else { NextFmt = ThisFmt; } /* If its not an end cmd, OR, START/END Opt... * it must be a parameter specification. */ /* Setup the type & format specs */ if (!strcmp(fmt, F_INT)) { NextFmt->type = e_int; } else if (!strcmp(fmt, F_NUMBER)) { NextFmt->type = e_number; } else if (!strcmp(fmt, F_CHAR)) { char *chars_allowed = NextToken(CONF_SEPARATORS); NextFmt->type = e_char; NextFmt->format.chars_allowed = 0; while (*chars_allowed != 0) { int bitNum = (*chars_allowed & 0x1f); NextFmt->format.chars_allowed |= (1 << (bitNum-1)); chars_allowed++; } } else if (!strcmp(fmt, F_DATE)) { FTP_DATE_FMT *DateFmt; char *format = NextToken(CONF_SEPARATORS); NextFmt->type = e_date; DateFmt = (FTP_DATE_FMT *)calloc(1, sizeof(FTP_DATE_FMT)); if (DateFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } NextFmt->format.date_fmt = DateFmt; iRet = ProcessDateFormat(DateFmt, NULL, &format); if (iRet) { snprintf(ErrorString, ErrStrLen, "Illegal format %s for token '%s'.", format, CMD_VALIDITY); return FTPP_INVALID_ARG; } } else if ( *fmt == *F_LITERAL ) { char* end = strchr(++fmt, *F_LITERAL); int len = end ? end - fmt : 0; if ( len < 1 ) { snprintf( ErrorString, ErrStrLen, "Illegal format '' for token '%s'.", CMD_VALIDITY ); return FTPP_INVALID_ARG; } NextFmt->type = e_literal; NextFmt->format.literal = (char *)calloc(1, len+1); if ( !NextFmt->format.literal ) { DynamicPreprocessorFatalMessage( "%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line) ); } strncpy(NextFmt->format.literal, fmt, len); NextFmt->format.literal[len] = '\0'; } else if (!strcmp(fmt, F_STRING)) { NextFmt->type = e_unrestricted; } else if (!strcmp(fmt, F_HOST_PORT)) { NextFmt->type = e_host_port; } else if (!strcmp(fmt, F_LONG_HOST_PORT)) { NextFmt->type = e_long_host_port; } else if (!strcmp(fmt, F_EXTD_HOST_PORT)) { NextFmt->type = e_extd_host_port; } else { snprintf(ErrorString, ErrStrLen, "Illegal format type %s for token '%s'.", fmt, CMD_VALIDITY); return FTPP_INVALID_ARG; } return DoNextFormat(NextFmt, 0, ErrorString, ErrStrLen); } /* * Function: ProcessFTPCmdValidity(FTP_SERVER_PROTO_CONF *ServerConf, * char *ErrorString, int ErrStrLen) * * Purpose: Process the ftp cmd validity configuration. * This sets the FTP command parameter validation tree. * * Arguments: ServerConf => pointer to the FTP server configuration * confOption => pointer to the name of the option * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessFTPCmdValidity(FTP_SERVER_PROTO_CONF *ServerConf, char *ErrorString, int ErrStrLen) { FTP_CMD_CONF *FTPCmd = NULL; FTP_PARAM_FMT *HeadFmt = NULL; char *cmd; char *fmt; int iRet; fmt = NextToken(CONF_SEPARATORS); if(fmt == NULL) { snprintf(ErrorString, ErrStrLen, "No argument to token '%s'.", CMD_VALIDITY); return FTPP_FATAL_ERR; } cmd = fmt; fmt = NextToken(CONF_SEPARATORS); if(!fmt) { snprintf(ErrorString, ErrStrLen, "Invalid cmd validity format."); return FTPP_FATAL_ERR; } if(strcmp(START_CMD_FORMAT, fmt)) { snprintf(ErrorString, ErrStrLen, "Must start a cmd validity with the '%s' token.", START_CMD_FORMAT); return FTPP_FATAL_ERR; } HeadFmt = (FTP_PARAM_FMT *)calloc(1, sizeof(FTP_PARAM_FMT)); if (HeadFmt == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } HeadFmt->type = e_head; iRet = DoNextFormat(HeadFmt, 0, ErrorString, ErrStrLen); /* Need to check to be sure we got a complete command */ if (iRet) { return FTPP_FATAL_ERR; } SetOptionalsNext(HeadFmt, NULL, NULL, 0); FTPCmd = ftp_cmd_lookup_find(ServerConf->cmd_lookup, cmd, strlen(cmd), &iRet); if (FTPCmd == NULL) { /* Add it to the list */ // note that struct includes 1 byte for null, so just add len FTPCmd = (FTP_CMD_CONF *)calloc(1, sizeof(FTP_CMD_CONF)+strlen(cmd)); if (FTPCmd == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } strcpy(FTPCmd->cmd_name, cmd); FTPCmd->max_param_len = ServerConf->def_max_param_len; ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd, strlen(cmd), FTPCmd); } FTPCmd->check_validity = 1; if (FTPCmd->param_format) { ftpp_ui_config_reset_ftp_cmd_format(FTPCmd->param_format); FTPCmd->param_format = NULL; } FTPCmd->param_format = HeadFmt; return FTPP_SUCCESS; } /* * Function: PrintFormatDate(FTP_DATE_FMT *DateFmt) * * Purpose: Recursively prints the FTP date validation tree * * Arguments: DateFmt => pointer to the date format node * * Returns: None * */ static void PrintFormatDate(char *buf, FTP_DATE_FMT *DateFmt) { FTP_DATE_FMT *OptChild; if (!DateFmt->empty) _dpd.printfappend(buf, BUF_SIZE, "%s", DateFmt->format_string); if (DateFmt->optional) { OptChild = DateFmt->optional; _dpd.printfappend(buf, BUF_SIZE, "["); PrintFormatDate(buf, OptChild); _dpd.printfappend(buf, BUF_SIZE, "]"); } if (DateFmt->next_a) { if (DateFmt->next_b) _dpd.printfappend(buf, BUF_SIZE, "{"); OptChild = DateFmt->next_a; PrintFormatDate(buf, OptChild); if (DateFmt->next_b) { _dpd.printfappend(buf, BUF_SIZE, "|"); OptChild = DateFmt->next_b; PrintFormatDate(buf, OptChild); _dpd.printfappend(buf, BUF_SIZE, "}"); } } if (DateFmt->next) PrintFormatDate(buf, DateFmt->next); } /* * Function: PrintCmdFmt(FTP_PARAM_FMT *CmdFmt) * * Purpose: Recursively prints the FTP command parameter validation tree * * Arguments: CmdFmt => pointer to the parameter validation node * * Returns: None * */ static void PrintCmdFmt(char *buf, FTP_PARAM_FMT *CmdFmt) { FTP_PARAM_FMT *OptChild; switch(CmdFmt->type) { case e_int: _dpd.printfappend(buf, BUF_SIZE, " %s", F_INT); break; case e_number: _dpd.printfappend(buf, BUF_SIZE, " %s", F_NUMBER); break; case e_char: _dpd.printfappend(buf, BUF_SIZE, " %s 0x%x", F_CHAR, CmdFmt->format.chars_allowed); break; case e_date: _dpd.printfappend(buf, BUF_SIZE, " %s", F_DATE); PrintFormatDate(buf, CmdFmt->format.date_fmt); break; case e_literal: _dpd.printfappend(buf, BUF_SIZE, " %s 0x%x", F_LITERAL, CmdFmt->format.literal); break; case e_unrestricted: _dpd.printfappend(buf, BUF_SIZE, " %s", F_STRING); break; case e_strformat: _dpd.printfappend(buf, BUF_SIZE, " %s", F_STRING_FMT); break; case e_host_port: _dpd.printfappend(buf, BUF_SIZE, " %s", F_HOST_PORT); break; case e_long_host_port: _dpd.printfappend(buf, BUF_SIZE, " %s", F_LONG_HOST_PORT); break; case e_extd_host_port: _dpd.printfappend(buf, BUF_SIZE, " %s", F_EXTD_HOST_PORT); break; case e_head: break; default: break; } if (CmdFmt->optional_fmt) { OptChild = CmdFmt->optional_fmt; _dpd.printfappend(buf, BUF_SIZE, "["); PrintCmdFmt(buf, OptChild); _dpd.printfappend(buf, BUF_SIZE, "]"); } if (CmdFmt->numChoices) { int i; _dpd.printfappend(buf, BUF_SIZE, "{"); for (i=0;inumChoices;i++) { if (i) _dpd.printfappend(buf, BUF_SIZE, "|"); OptChild = CmdFmt->choices[i]; PrintCmdFmt(buf, OptChild); } _dpd.printfappend(buf, BUF_SIZE, "}"); } if (CmdFmt->next_param_fmt && CmdFmt->next_param_fmt->prev_optional) PrintCmdFmt(buf, CmdFmt->next_param_fmt); } /* * Function: ProcessFTPMaxRespLen(FTP_CLIENT_PROTO_CONF *ClientConf, * char *ErrorString, int ErrStrLen) * * Purpose: Process the max response length configuration * This sets the max length of an FTP response that we * will tolerate, before alerting. * * Arguments: ClientConf => pointer to the FTP client configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessFTPMaxRespLen(FTP_CLIENT_PROTO_CONF *ClientConf, char *ErrorString, int ErrStrLen) { char *pcToken; char *pcEnd = NULL; long int max_resp_len; pcToken = NextToken(CONF_SEPARATORS); if(pcToken == NULL) { snprintf(ErrorString, ErrStrLen, "No argument to token '%s'.", MAX_RESP_LEN); return FTPP_FATAL_ERR; } max_resp_len = _dpd.SnortStrtol(pcToken, &pcEnd, 10); /* * Let's check to see if the entire string was valid. * If there is an address here, then there was an * invalid character in the string. */ if ((*pcEnd) || (max_resp_len < 0) || (errno == ERANGE)) { snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s'. Must be a positive " "number.", MAX_RESP_LEN); return FTPP_FATAL_ERR; } ClientConf->max_resp_len = (unsigned int)max_resp_len; return FTPP_SUCCESS; } /* * Function: ParseBounceTo(char *token, FTP_BOUNCE_TO*) * * Purpose: Extract the IP address, masking bits (CIDR format), and * port information from an FTP Bounce To configuration. * * Arguments: token => string pointer to the FTP bounce configuration * required format: IP/CIDR,port[,portHi]\0 * FTP_BOUNCE_TO => populated with parsed data * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int ParseBounceTo(char* token, FTP_BOUNCE_TO* bounce) { char **toks; int num_toks; long int port_lo; char *endptr = NULL; sfip_t tmp_ip; toks = _dpd.tokenSplit(token, ",", 3, &num_toks, 0); if (num_toks < 2) return FTPP_INVALID_ARG; if (sfip_pton(toks[0], &tmp_ip) != SFIP_SUCCESS) { _dpd.tokenFree(&toks, num_toks); return FTPP_INVALID_ARG; } memcpy(&bounce->ip, &tmp_ip, sizeof(sfip_t)); port_lo = _dpd.SnortStrtol(toks[1], &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0') || (port_lo < 0) || (port_lo >= MAXPORTS)) { _dpd.tokenFree(&toks, num_toks); return FTPP_INVALID_ARG; } bounce->portlo = (unsigned short)port_lo; if (num_toks == 3) { long int port_hi = _dpd.SnortStrtol(toks[2], &endptr, 10); if ((errno == ERANGE) || (*endptr != '\0') || (port_hi < 0) || (port_hi >= MAXPORTS)) { _dpd.tokenFree(&toks, num_toks); return FTPP_INVALID_ARG; } if (bounce->portlo != (unsigned short)port_hi) { bounce->porthi = (unsigned short)port_hi; if (bounce->porthi < bounce->portlo) { unsigned short tmp = bounce->porthi; bounce->porthi = bounce->portlo; bounce->portlo = tmp; } } } _dpd.tokenFree(&toks, num_toks); return FTPP_SUCCESS; } /* * Function: ProcessFTPAlowBounce(FTP_CLIENT_PROTO_CONF *ClientConf, * char *ErrorString, int ErrStrLen) * * Purpose: Process the FTP allow bounce configuration. * This creates an allow bounce node and adds it to the list for the * client configuration. * * Arguments: ClientConf => pointer to the FTP client configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int ProcessFTPAllowBounce(FTP_CLIENT_PROTO_CONF *ClientConf, char *ErrorString, int ErrStrLen) { char *pcToken; int iOneAddr = 0; int iEndList = 0; int iRet; pcToken = NextToken(CONF_SEPARATORS); if(pcToken == NULL) { snprintf(ErrorString, ErrStrLen, "No argument to token '%s'.", ALLOW_BOUNCE); return FTPP_FATAL_ERR; } if(strcmp(START_PORT_LIST, pcToken)) { snprintf(ErrorString, ErrStrLen, "Must start a %s list with the '%s' token.", ALLOW_BOUNCE, START_PORT_LIST); return FTPP_FATAL_ERR; } while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { FTP_BOUNCE_TO *newBounce; if(!strcmp(END_PORT_LIST, pcToken)) { iEndList = 1; break; } /* TODO: Maybe want to redo this with high-speed searcher for ip/port. * Would be great if we could handle both full addresses and * subnets quickly -- using CIDR format. Need something that would * return most specific match -- ie a specific host is more specific * than subnet. */ newBounce = (FTP_BOUNCE_TO *)calloc(1, sizeof(FTP_BOUNCE_TO)); if (newBounce == NULL) { snprintf(ErrorString, ErrStrLen, "Failed to allocate memory for Bounce"); return FTPP_FATAL_ERR; } iRet = ParseBounceTo(pcToken, newBounce); if (iRet) { snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s': %s", ALLOW_BOUNCE, pcToken); free(newBounce); return FTPP_FATAL_ERR; } iRet = ftp_bounce_lookup_add( ClientConf->bounce_lookup, IP_ARG(newBounce->ip), newBounce ); if (iRet) { snprintf(ErrorString, ErrStrLen, "Failed to add configuration for Bounce object '%s'.", ALLOW_BOUNCE); free(newBounce); return FTPP_FATAL_ERR; } iOneAddr = 1; } if(!iEndList) { snprintf(ErrorString, ErrStrLen, "Must end '%s' configuration with '%s'.", ALLOW_BOUNCE, END_PORT_LIST); return FTPP_FATAL_ERR; } if(!iOneAddr) { snprintf(ErrorString, ErrStrLen, "Must include at least one address in '%s' configuration.", ALLOW_BOUNCE); return FTPP_FATAL_ERR; } return FTPP_SUCCESS; } /* * Function: PrintFTPClientConf(char * client, * FTP_CLIENT_PROTO_CONF *ClientConf) * * Purpose: Prints the FTP client configuration * * Arguments: client => string pointer to the client IP * ClientConf => pointer to the client configuration * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int PrintFTPClientConf(char * client, FTP_CLIENT_PROTO_CONF *ClientConf) { FTP_BOUNCE_TO *FTPBounce; int iErr; if(!ClientConf) { return FTPP_INVALID_ARG; } if (!printedFTPHeader) { _dpd.logMsg(" FTP CONFIG:\n"); printedFTPHeader = 1; } _dpd.logMsg(" FTP Client: %s\n", client); PrintConfOpt(&ClientConf->bounce, " Check for Bounce Attacks"); PrintConfOpt(&ClientConf->telnet_cmds, " Check for Telnet Cmds"); PrintConfOpt(&ClientConf->ignore_telnet_erase_cmds, " Ignore Telnet Cmd Operations"); _dpd.logMsg(" Max Response Length: %d\n", ClientConf->max_resp_len); FTPBounce = ftp_bounce_lookup_first(ClientConf->bounce_lookup, &iErr); if (FTPBounce) { _dpd.logMsg(" Allow FTP bounces to:\n"); while (FTPBounce) { char *addr_str; char bits_str[5]; uint8_t bits; bits_str[0] = '\0'; addr_str = sfip_to_str(&FTPBounce->ip); bits = (uint8_t)FTPBounce->ip.bits; if (((FTPBounce->ip.family == AF_INET) && (bits != 32)) || ((FTPBounce->ip.family == AF_INET6) && (bits != 128))) { snprintf(bits_str, sizeof(bits_str), "/%u", bits); } if (FTPBounce->porthi) { _dpd.logMsg(" Address: %s%s, Ports: %d-%d\n", addr_str, bits_str[0] ? bits_str : "", FTPBounce->portlo, FTPBounce->porthi); } else { _dpd.logMsg(" Address: %s%s, Port: %d\n", addr_str, bits_str[0] ? bits_str : "", FTPBounce->portlo); } FTPBounce = ftp_bounce_lookup_next(ClientConf->bounce_lookup, &iErr); } } return FTPP_SUCCESS; } /* * Function: ProcessFTPClientOptions(FTP_CLIENT_PROTO_CONF *ClientConf, * char *ErrorString, int ErrStrLen) * * Purpose: This is where we process the specific ftp client configuration * for FTPTelnet. * * We set the values of the ftp client configuraiton here. Any errors * that are encountered are specified in the error string and the type * of error is returned through the return code, i.e. fatal, non-fatal. * * Arguments: ClientConf => pointer to the client configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int ProcessFTPClientOptions(FTP_CLIENT_PROTO_CONF *ClientConf, char *ErrorString, int ErrStrLen) { FTPTELNET_CONF_OPT *ConfOpt; int iRet; char *pcToken; int iTokens = 0; while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { /* * Show that we at least got one token */ iTokens = 1; /* * Search for configuration keywords */ if(!strcmp(MAX_RESP_LEN, pcToken)) { iRet = ProcessFTPMaxRespLen(ClientConf, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(ALLOW_BOUNCE, pcToken)) { iRet = ProcessFTPAllowBounce(ClientConf, ErrorString, ErrStrLen); if (iRet) { return iRet; } } /* * Start the CONF_OPT configurations. */ else if(!strcmp(BOUNCE, pcToken)) { ConfOpt = &ClientConf->bounce; iRet = ProcessConfOpt(ConfOpt, BOUNCE, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if(!strcmp(TELNET_CMDS, pcToken)) { ConfOpt = &ClientConf->telnet_cmds; iRet = ProcessConfOpt(ConfOpt, TELNET_CMDS, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if(!strcmp(IGNORE_TELNET_CMDS, pcToken)) { ConfOpt = &ClientConf->ignore_telnet_erase_cmds; iRet = ProcessConfOpt(ConfOpt, IGNORE_TELNET_CMDS, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else { snprintf(ErrorString, ErrStrLen, "Invalid keyword '%s' for '%s' configuration.", pcToken, GLOBAL); return FTPP_FATAL_ERR; } } /* * If there are not any tokens to the configuration, then * we let the user know and log the error. return non-fatal * error. */ if(!iTokens) { snprintf(ErrorString, ErrStrLen, "No tokens to '%s %s' configuration.", FTP, CLIENT); return FTPP_NONFATAL_ERR; } return FTPP_SUCCESS; } /* * Function: ProcessFTPClientConf(FTPTELNET_GLOBAL_CONF *GlobalConf, * char *ErrorString, int ErrStrLen) * * Purpose: This is where we process the ftp client configuration for FTPTelnet. * * We set the values of the ftp client configuraiton here. Any errors * that are encountered are specified in the error string and the type * of error is returned through the return code, i.e. fatal, non-fatal. * * The configuration options that are dealt with here are: * ports { x } Ports on which to do FTP checks * telnet_cmds yes|no Detect telnet cmds on FTP command channel * ignore_telnet_erase_cmds yes|no Do not process telnet EAC and EAL * commands during normalization of FTP command * channel. * max_resp_len x Max response length * bounce yes|no Detect FTP bounce attacks * bounce_to IP port|port-range Allow FTP bounces to specified IP/ports * data_chan Ignore data channel OR coordinate with cmd chan * * Arguments: GlobalConf => pointer to the global configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int ProcessFTPClientConf(FTPTELNET_GLOBAL_CONF *GlobalConf, char *ErrorString, int ErrStrLen) { int iRet; int retVal = 0; char *client; char client_list[STD_BUF]; sfip_t ipAddr; char *pIpAddressList = NULL; char *pIpAddressList2 = NULL; char *brkt = NULL; char firstIpAddress = 1; FTP_CLIENT_PROTO_CONF *new_client_conf = NULL; //char *ConfigParseResumePtr = NULL; // Use this if a default client conf is added char ip_list = 0; FTP_CLIENT_PROTO_CONF *ftp_conf = NULL; /* * If not default, create one for this IP */ client = NextToken(CONF_SEPARATORS); if ( !client ) { DynamicPreprocessorFatalMessage( "%s(%d) Missing ftp_telnet ftp client address.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(strcmp(DEFAULT, client)) { /* ** Convert string to IP address */ /// get the first delimiter if(strcmp(START_IPADDR_LIST, client) == 0) { //list begin token matched ip_list = 1; if ((pIpAddressList = mystrtok(NULL, END_IPADDR_LIST)) == NULL) { snprintf(ErrorString, ErrStrLen, "Invalid IP Address list in '%s' token.", CLIENT); retVal = FTPP_INVALID_ARG; goto _return; } } else { //list begin didn't match so this must be an IP address pIpAddressList = client; } //ConfigParseResumePtr = pIpAddressList+strlen(pIpAddressList); pIpAddressList2 = strdup(pIpAddressList); if (!pIpAddressList2) { snprintf(ErrorString, ErrStrLen, "Could not allocate memory for server configuration."); retVal = FTPP_INVALID_ARG; goto _return; } for (client = strtok_r(pIpAddressList2, CONF_SEPARATORS, &brkt); client; client = strtok_r(NULL, CONF_SEPARATORS, &brkt)) { if (sfip_pton(client, &ipAddr) != SFIP_SUCCESS) { snprintf(ErrorString, ErrStrLen, "Invalid IP to '%s' token.", CLIENT); retVal = FTPP_INVALID_ARG; goto _return; } if (ipAddr.family == AF_INET) { ipAddr.ip.u6_addr32[0] = ntohl(ipAddr.ip.u6_addr32[0]); } /* ** allocate the memory for the client configuration */ if (firstIpAddress) { // Write this IP into the buffer for printing snprintf(client_list, STD_BUF, "%s", client); new_client_conf = (FTP_CLIENT_PROTO_CONF *)calloc(1, sizeof(FTP_CLIENT_PROTO_CONF)); if (new_client_conf == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } ftpp_ui_config_reset_ftp_client(new_client_conf, 1); //process the first IP address as usual firstIpAddress = 0; ftp_conf = new_client_conf; } else { // Write this IP into the buffer for printing snprintf(client_list + strlen(client_list), STD_BUF - strlen(client_list) , ", %s", client); new_client_conf = ftp_conf; } ftpp_ui_config_add_ftp_client(GlobalConf, &ipAddr, new_client_conf); //create a reference new_client_conf->referenceCount++; } if (firstIpAddress) { //no IP address was found snprintf(ErrorString, ErrStrLen, "Invalid IP Address list in '%s' token.", CLIENT); retVal = FTPP_INVALID_ARG; goto _return; } } else { /**default configuration */ if (GlobalConf->default_ftp_client != NULL) { snprintf(ErrorString, ErrStrLen, "Cannot configure '%s' settings more than once.", CLIENT); retVal = FTPP_INVALID_ARG; goto _return; } GlobalConf->default_ftp_client = (FTP_CLIENT_PROTO_CONF *)calloc(1, sizeof(FTP_CLIENT_PROTO_CONF)); if (GlobalConf->default_ftp_client == NULL) { DynamicPreprocessorFatalMessage("Out of memory trying to create " "default ftp client configuration.\n"); } ftpp_ui_config_reset_ftp_client(GlobalConf->default_ftp_client, 0); ftp_conf = GlobalConf->default_ftp_client; //ConfigParseResumePtr = client+strlen(client); } iRet = ProcessFTPClientOptions(ftp_conf, ErrorString, ErrStrLen); if (iRet < 0) { retVal = FTPP_INVALID_ARG; goto _return; } /* * Let's print out the FTP config */ if (ip_list) { client = &client_list[0]; } else if (pIpAddressList2) { client = pIpAddressList2; } PrintFTPClientConf(client, ftp_conf); _return: if (pIpAddressList2) { free(pIpAddressList2); } return retVal; } /* * Function: PrintFTPServerConf(char * server, * FTP_SERVER_PROTO_CONF *ServerConf) * * Purpose: Prints the FTP server configuration * * Arguments: server => string pointer to the server IP * ServerConf => pointer to the server configuration * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static int PrintFTPServerConf(char * server, FTP_SERVER_PROTO_CONF *ServerConf) { const char* spaf = ""; char buf[BUF_SIZE+1]; int iCtr; int iRet; FTP_CMD_CONF *FTPCmd; if(!ServerConf) { return FTPP_INVALID_ARG; } if (!printedFTPHeader) { _dpd.logMsg(" FTP CONFIG:\n"); printedFTPHeader = 1; } if ( _dpd.isPafEnabled() ) spaf = " (PAF)"; _dpd.logMsg(" FTP Server: %s\n", server); memset(buf, 0, BUF_SIZE+1); snprintf(buf, BUF_SIZE, " Ports%s: ", spaf); /* * Print out all the applicable ports. */ for(iCtr = 0; iCtr < MAXPORTS; iCtr++) { if(ServerConf->proto_ports.ports[iCtr]) { _dpd.printfappend(buf, BUF_SIZE, "%d ", iCtr); } } _dpd.logMsg("%s\n", buf); PrintConfOpt(&ServerConf->telnet_cmds, " Check for Telnet Cmds"); PrintConfOpt(&ServerConf->ignore_telnet_erase_cmds, " Ignore Telnet Cmd Operations"); _dpd.logMsg(" Ignore open data channels: %s\n", ServerConf->data_chan ? "YES" : "NO"); if (ServerConf->print_commands) { _dpd.logMsg(" FTP Commands:\n"); FTPCmd = ftp_cmd_lookup_first(ServerConf->cmd_lookup, &iRet); while (FTPCmd != NULL) { memset(buf, 0, BUF_SIZE+1); snprintf(buf, BUF_SIZE, " %s { %d ", FTPCmd->cmd_name, FTPCmd->max_param_len); #ifdef PRINT_DEFAULT_CONFIGS if (FTPCmd->data_chan_cmd) snprintf(buf, BUF_SIZE, "%s data_chan "); if (FTPCmd->data_xfer_cmd) snprintf(buf, BUF_SIZE, "%s data_xfer "); if (FTPCmd->encr_cmd) snprintf(buf, BUF_SIZE, "%s encr "); #endif if (FTPCmd->check_validity) { FTP_PARAM_FMT *CmdFmt = FTPCmd->param_format; while (CmdFmt != NULL) { PrintCmdFmt(buf, CmdFmt); CmdFmt = CmdFmt->next_param_fmt; } } _dpd.logMsg("%s}\n", buf); FTPCmd = ftp_cmd_lookup_next(ServerConf->cmd_lookup, &iRet); } } return FTPP_SUCCESS; } /* * Function: ProcessFTPServerOptions(FTP_SERVER_PROTO_CONF *ServerConf, * char *ErrorString, int ErrStrLen) * * Purpose: This is where we process the specific ftp server configuration * for FTPTelnet. * * We set the values of the ftp server configuraiton here. Any errors * that are encountered are specified in the error string and the type * of error is returned through the return code, i.e. fatal, non-fatal. * * Arguments: ServerConf => pointer to the server configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int ProcessFTPServerOptions(FTP_SERVER_PROTO_CONF *ServerConf, char *ErrorString, int ErrStrLen) { FTPTELNET_CONF_OPT *ConfOpt; int iRet = 0; char *pcToken; int iTokens = 0; int data_chan_configured = 0; while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL) { /* * Show that we at least got one token */ iTokens = 1; /* * Search for configuration keywords */ if(!strcmp(PORTS, pcToken)) { PROTO_CONF *ports = (PROTO_CONF*)&ServerConf->proto_ports; iRet = ProcessPorts(ports, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if(!strcmp(FTP_CMDS, pcToken)) { iRet = ProcessFTPCmdList(ServerConf, FTP_CMDS, ErrorString, ErrStrLen, 1, 0); if (iRet) { return iRet; } } else if(!strcmp(MAX_PARAM_LEN, pcToken)) { iRet = ProcessFTPCmdList(ServerConf, MAX_PARAM_LEN, ErrorString, ErrStrLen, 0, 1); if (iRet) { return iRet; } } else if(!strcmp(ALT_PARAM_LEN, pcToken)) { iRet = ProcessFTPCmdList(ServerConf, ALT_PARAM_LEN, ErrorString, ErrStrLen, 1, 1); if (iRet) { return iRet; } } else if(!strcmp(CMD_VALIDITY, pcToken)) { iRet = ProcessFTPCmdValidity(ServerConf, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if(!strcmp(STRING_FORMAT, pcToken)) { iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(DATA_CHAN_CMD, pcToken)) { iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(DATA_XFER_CMD, pcToken)) { iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(FILE_PUT_CMD, pcToken)) { iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(FILE_GET_CMD, pcToken)) { iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(ENCR_CMD, pcToken)) { iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(LOGIN_CMD, pcToken)) { iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(DIR_CMD, pcToken)) { iRet = ProcessFTPDirCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if (!strcmp(DATA_CHAN, pcToken)) { if (data_chan_configured && ServerConf->data_chan == 0) { snprintf(ErrorString, ErrStrLen, "Both 'data_chan' and " "'ignore_data_chan' configured with conflicting options."); return FTPP_FATAL_ERR; } else { ServerConf->data_chan = 1; data_chan_configured = 1; } } else if (!strcmp(PRINT_CMDS, pcToken)) { ServerConf->print_commands = 1; } else if (!strcmp(IGNORE_DATA_CHAN, pcToken)) { iRet = ProcessFTPIgnoreDataChan(ServerConf, pcToken, ErrorString, ErrStrLen); if (iRet) { return iRet; } data_chan_configured = 1; } /* * Start the CONF_OPT configurations. */ else if(!strcmp(TELNET_CMDS, pcToken)) { ConfOpt = &ServerConf->telnet_cmds; iRet = ProcessConfOpt(ConfOpt, TELNET_CMDS, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else if(!strcmp(IGNORE_TELNET_CMDS, pcToken)) { ConfOpt = &ServerConf->ignore_telnet_erase_cmds; iRet = ProcessConfOpt(ConfOpt, IGNORE_TELNET_CMDS, ErrorString, ErrStrLen); if (iRet) { return iRet; } } else { snprintf(ErrorString, ErrStrLen, "Invalid keyword '%s' for '%s' configuration.", pcToken, GLOBAL); return FTPP_FATAL_ERR; } } /* * If there are not any tokens to the configuration, then * we let the user know and log the error. return non-fatal * error. */ if(!iTokens) { snprintf(ErrorString, ErrStrLen, "No tokens to '%s %s' configuration.", FTP, SERVER); return FTPP_NONFATAL_ERR; } return FTPP_SUCCESS; } /* * Function: ProcessFTPServerConf:: * * Purpose: This is where we process the ftp server configuration for FTPTelnet. * * We set the values of the ftp server configuraiton here. Any * errors that are encountered are specified in the error string and * the type of error is returned through the return code, i.e. fatal, * non-fatal. * * The configuration options that are dealt with here are: * ports { x } Ports on which to do FTP checks * ftp_cmds { CMD1 CMD2 ... } Valid FTP commands * def_max_param_len x Default max param length * alt_max_param_len x { CMD1 ... } Override default max param len * for CMD * chk_str_fmt { CMD1 ...} Detect string format attacks for CMD * cmd_validity CMD < fmt > Check the parameter validity for CMD * fmt is as follows: * int Param is an int * char _chars Param is one of _chars * date _datefmt Param follows format specified where * # = Number, C=Char, []=optional, |=OR, * +-.=literal * [] Optional parameters * string Param is string (unrestricted) * data_chan Ignore data channel * * Arguments: GlobalConf => pointer to the global configuration * ErrorString => error string buffer * ErrStrLen => the length of the error string buffer * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int ProcessFTPServerConf(FTPTELNET_GLOBAL_CONF *GlobalConf, char *ErrorString, int ErrStrLen) { int iRet = 0; int retVal = 0; char *server; char server_list[STD_BUF]; sfip_t ipAddr; char *pIpAddressList = NULL; char *pIpAddressList2 = NULL; char *brkt = NULL; char firstIpAddress = 1; FTP_SERVER_PROTO_CONF *new_server_conf = NULL; char *ConfigParseResumePtr = NULL; char ip_list = 0; FTP_SERVER_PROTO_CONF *ftp_conf = NULL; /* * If not default, create one for this IP */ server = NextToken(CONF_SEPARATORS); if ( !server ) { DynamicPreprocessorFatalMessage( "%s(%d) Missing ftp_telnet ftp server address.\n", *(_dpd.config_file), *(_dpd.config_line)); } else if(strcmp(DEFAULT, server)) { if(strcmp(START_IPADDR_LIST, server) == 0) { //list begin token matched ip_list = 1; if ((pIpAddressList = mystrtok(NULL, END_IPADDR_LIST)) == NULL) { snprintf(ErrorString, ErrStrLen, "Invalid IP Address list in '%s' token.", SERVER); retVal = FTPP_INVALID_ARG; goto _return; } } else { //list begin didn't match so this must be an IP address pIpAddressList = server; } ConfigParseResumePtr = pIpAddressList+strlen(pIpAddressList); pIpAddressList2 = strdup(pIpAddressList); if (!pIpAddressList2) { snprintf(ErrorString, ErrStrLen, "Could not allocate memory for server configuration."); retVal = FTPP_INVALID_ARG; goto _return; } for (server = strtok_r(pIpAddressList2, CONF_SEPARATORS, &brkt); server; server = strtok_r(NULL, CONF_SEPARATORS, &brkt)) { if (sfip_pton(server, &ipAddr) != SFIP_SUCCESS) { snprintf(ErrorString, ErrStrLen, "Invalid IP to '%s' token.", SERVER); retVal = FTPP_INVALID_ARG; goto _return; } if (ipAddr.family == AF_INET) { ipAddr.ip.u6_addr32[0] = ntohl(ipAddr.ip.u6_addr32[0]); } if (firstIpAddress) { /* Write this IP into the buffer for printing */ snprintf(server_list, STD_BUF, "%s", server); new_server_conf = (FTP_SERVER_PROTO_CONF *)calloc(1, sizeof(FTP_SERVER_PROTO_CONF)); if (new_server_conf == NULL) { DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n", *(_dpd.config_file), *(_dpd.config_line)); } ftpp_ui_config_reset_ftp_server(new_server_conf, 1); new_server_conf->serverAddr = strdup(server); if (new_server_conf->serverAddr == NULL) { DynamicPreprocessorFatalMessage("ProcessFTPServerConf(): Out of memory allocing serverAddr.\n"); } ftp_conf = new_server_conf; //process the first IP address as usual firstIpAddress = 0; } else { /* Write this IP into the buffer for printing */ snprintf(server_list + strlen(server_list), STD_BUF - strlen(server_list) , ", %s", server); new_server_conf = ftp_conf; } ftpp_ui_config_add_ftp_server(GlobalConf, &ipAddr, new_server_conf); //create a reference new_server_conf->referenceCount++; } if (firstIpAddress) { //no IP address was found snprintf(ErrorString, ErrStrLen, "Invalid IP Address list in '%s' token.", CLIENT); retVal = FTPP_INVALID_ARG; goto _return; } } else { if (GlobalConf->default_ftp_server != NULL) { snprintf(ErrorString, ErrStrLen, "Cannot configure '%s' settings more than once.", SERVER); retVal = FTPP_INVALID_ARG; goto _return; } GlobalConf->default_ftp_server = (FTP_SERVER_PROTO_CONF *)calloc(1, sizeof(FTP_SERVER_PROTO_CONF)); if (GlobalConf->default_ftp_server == NULL) { DynamicPreprocessorFatalMessage("Out of memory trying to create " "default ftp server configuration.\n"); } ftpp_ui_config_reset_ftp_server(GlobalConf->default_ftp_server, 0); ftp_conf = GlobalConf->default_ftp_server; ConfigParseResumePtr = server+strlen(server); GlobalConf->default_ftp_server->serverAddr = strdup("default"); } /* First, process the default configuration -- namely, the * list of FTP commands, and the parameter validation checks */ { char *saveMaxToken = maxToken; size_t default_conf_len; char *default_conf_str = DefaultConf(&default_conf_len); maxToken = default_conf_str + default_conf_len; (void)mystrtok(default_conf_str, CONF_SEPARATORS); iRet = ProcessFTPServerOptions(ftp_conf, ErrorString, ErrStrLen); free(default_conf_str); maxToken = saveMaxToken; if (iRet < 0) { return iRet; } } /* Okay, now we need to reset the mystrtok pointers so we can process * the specific server configuration. Quick hack/trick here: reset * the end of the client string to a conf separator, then call mystrtok. * That will reset mystrtok's internal pointer to the next token after * the client name, which is what we're expecting it to be. */ if (ConfigParseResumePtr < maxToken) { /* only if there is data after the server/client name */ if (ip_list) *ConfigParseResumePtr-- = END_IPADDR_LIST[0]; else *ConfigParseResumePtr-- = CONF_SEPARATORS[0]; (void)mystrtok(ConfigParseResumePtr, CONF_SEPARATORS); iRet = ProcessFTPServerOptions(ftp_conf, ErrorString, ErrStrLen); if (iRet < 0) { return iRet; } } /* * Let's print out the FTP config */ if (ip_list) { server = &server_list[0]; } else if (pIpAddressList2) { server = pIpAddressList2; } PrintFTPServerConf(server, ftp_conf); _return: if (pIpAddressList2) { free(pIpAddressList2); } return retVal; } /* * Function: PrintFTPGlobalConf(FTPTELNET_GLOBAL_CONF *GlobalConf) * * Purpose: Prints the FTPTelnet preprocessor global configuration * * Arguments: GlobalConf => pointer to the global configuration * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int PrintFTPGlobalConf(FTPTELNET_GLOBAL_CONF *GlobalConf) { _dpd.logMsg("FTPTelnet Config:\n"); _dpd.logMsg(" GLOBAL CONFIG\n"); _dpd.logMsg(" Inspection Type: %s\n", GlobalConf->inspection_type == FTPP_UI_CONFIG_STATELESS ? "stateless" : "stateful"); PrintConfOpt(&GlobalConf->encrypted, "Check for Encrypted Traffic"); _dpd.logMsg(" Continue to check encrypted data: %s\n", GlobalConf->check_encrypted_data ? "YES" : "NO"); return FTPP_SUCCESS; } void FTPTelnetCleanupFTPCMDConf(void *ftpCmd) { FTP_CMD_CONF *FTPCmd = (FTP_CMD_CONF *)ftpCmd; /* Free the FTP_PARAM_FMT stuff... */ ftpp_ui_config_reset_ftp_cmd(FTPCmd); free(FTPCmd); } void FTPTelnetCleanupFTPServerConf(void *serverConf) { FTP_SERVER_PROTO_CONF *ServerConf = (FTP_SERVER_PROTO_CONF*)serverConf; if (ServerConf == NULL) return; free(ServerConf->serverAddr); ServerConf->serverAddr = NULL; /* Iterate through each cmd_lookup for this server */ ftp_cmd_lookup_cleanup(&ServerConf->cmd_lookup); } void FTPTelnetCleanupFTPBounceTo(void *ftpBounce) { FTP_BOUNCE_TO *FTPBounce = (FTP_BOUNCE_TO *)ftpBounce; free(FTPBounce); } void FTPTelnetCleanupFTPClientConf(void *clientConf) { FTP_CLIENT_PROTO_CONF *ClientConf = (FTP_CLIENT_PROTO_CONF*)clientConf; if (ClientConf == NULL) return; /* Iterate through each bounce_lookup for this client */ ftp_bounce_lookup_cleanup(&ClientConf->bounce_lookup); } static int FTPTelnetFreeConfigsPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { FTPTELNET_GLOBAL_CONF *pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)pData; //do any housekeeping before freeing FTPTELNET_GLOBAL_CONF sfPolicyUserDataClear (config, policyId); FTPTelnetFreeConfig(pPolicyConfig); return 0; } void FTPTelnetFreeConfigs(tSfPolicyUserContextId GlobalConf) { if (GlobalConf == NULL) return; sfPolicyUserDataFreeIterate(GlobalConf, FTPTelnetFreeConfigsPolicy); sfPolicyConfigDelete(GlobalConf); } void FTPTelnetFreeConfig(FTPTELNET_GLOBAL_CONF *GlobalConf) { if (GlobalConf == NULL) return; if (GlobalConf->default_ftp_client != NULL) { FTPTelnetCleanupFTPClientConf((void *)GlobalConf->default_ftp_client); free(GlobalConf->default_ftp_client); } if (GlobalConf->default_ftp_server != NULL) { FTPTelnetCleanupFTPServerConf((void *)GlobalConf->default_ftp_server); free(GlobalConf->default_ftp_server); } if (GlobalConf->telnet_config != NULL) free(GlobalConf->telnet_config); ftpp_ui_client_lookup_cleanup(&GlobalConf->client_lookup); ftpp_ui_server_lookup_cleanup(&GlobalConf->server_lookup); free(GlobalConf); } /* * Function: FTPTelnetCheckFTPCmdOptions(FTP_SERVER_PROTO_CONF *serverConf) * * Purpose: This checks that the FTP configuration provided has * options for CMDs that make sense: * -- check if max_len == 0 & there is a cmd_validity * * Arguments: serverConf => pointer to Server Configuration * * Returns: 0 => no errors * 1 => errors * */ int FTPTelnetCheckFTPCmdOptions(FTP_SERVER_PROTO_CONF *serverConf) { FTP_CMD_CONF *cmdConf; int iRet =0; int config_error = 0; cmdConf = ftp_cmd_lookup_first(serverConf->cmd_lookup, &iRet); while (cmdConf && (iRet == FTPP_SUCCESS)) { size_t len = strlen(cmdConf->cmd_name); if ( len > serverConf->max_cmd_len ) serverConf->max_cmd_len = len; if (cmdConf->check_validity && (cmdConf->max_param_len == 0)) { _dpd.errMsg("FTPConfigCheck() configuration for server '%s', " "command '%s' has max length of 0 and parameters to validate\n", serverConf->serverAddr, cmdConf->cmd_name); config_error = 1; } cmdConf = ftp_cmd_lookup_next(serverConf->cmd_lookup, &iRet); } return config_error; } /* * Function: FTPTelnetCheckFTPServerConfigs(void) * * Purpose: This checks that the FTP server configurations are reasonable * * Arguments: None * * Returns: -1 on error * */ int FTPTelnetCheckFTPServerConfigs(struct _SnortConfig *sc, FTPTELNET_GLOBAL_CONF *config) { FTP_SERVER_PROTO_CONF *serverConf; int iRet = 0; int rval; if (config == NULL) return 0; if ((rval = ftpp_ui_server_iterate(sc, config->server_lookup, _checkServerConfig, &iRet))) return rval; serverConf = config->default_ftp_server; if (FTPTelnetCheckFTPCmdOptions(serverConf)) { _dpd.errMsg("FTPConfigCheck(): invalid configuration for FTP commands\n"); return -1; } return 0; } static int _checkServerConfig(struct _SnortConfig *sc, void *pData) { FTP_SERVER_PROTO_CONF *serverConf = (FTP_SERVER_PROTO_CONF *)pData; if (FTPTelnetCheckFTPCmdOptions(serverConf)) { _dpd.errMsg("FTPConfigCheck(): invalid configuration for FTP commands\n"); return -1; } return 0; } /* * Function: FTPConfigCheck(void) * * Purpose: This checks that the FTP configuration provided includes * the default configurations for Server & Client. * * Arguments: None * * Returns: None * */ int FTPTelnetCheckConfigs(struct _SnortConfig *sc, void* pData, tSfPolicyId policyId) { int rval; FTPTELNET_GLOBAL_CONF *pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)pData; if ( pPolicyConfig == NULL ) return 0; if ((pPolicyConfig->default_ftp_server == NULL) || (pPolicyConfig->default_ftp_client == NULL)) { _dpd.errMsg("FTP/Telnet configuration requires " "default client and default server configurations.\n"); return -1; } if ( pPolicyConfig->telnet_config == NULL ) { ProcessTelnetConf(pPolicyConfig,"",0); } if ((pPolicyConfig->telnet_config->ayt_threshold > 0) && !pPolicyConfig->telnet_config->normalize) { _dpd.errMsg("WARNING: Telnet Configuration Check: using an " "AreYouThere threshold requires telnet normalization to be " "turned on.\n"); } if ((pPolicyConfig->encrypted.alert != 0) && !pPolicyConfig->telnet_config->normalize) { _dpd.errMsg("WARNING: Telnet Configuration Check: checking for " "encrypted traffic requires telnet normalization to be turned " "on.\n"); } /* So we don't have to check it every time we use it */ if ((!_dpd.streamAPI) || (_dpd.streamAPI->version < STREAM_API_VERSION5)) { _dpd.errMsg("FTPConfigCheck() Streaming & reassembly must be " "enabled\n"); return -1; } _dpd.setParserPolicy(sc, policyId); /* Add FTPTelnet into the preprocessor list */ #ifdef TARGET_BASED if ( _dpd.fileAPI->get_max_file_depth() >= 0 ) { _dpd.addPreproc(sc, FTPDataTelnetChecks, PRIORITY_SESSION, PP_FTPTELNET, PROTO_BIT__TCP); s_ftpdata_eof_cb_id = _dpd.streamAPI->register_event_handler(SnortFTPData_EOF); } else #endif { _dpd.addPreproc(sc, FTPTelnetChecks, PRIORITY_APPLICATION, PP_FTPTELNET, PROTO_BIT__TCP); } if ((rval = FTPTelnetCheckFTPServerConfigs(sc, pPolicyConfig))) return rval; _FTPTelnetAddPortsOfInterest(sc, pPolicyConfig, policyId); #ifdef TARGET_BASED _FTPTelnetAddService(sc, ftp_app_id, policyId); #endif return 0; } static int FTPConfigCheckPolicy( struct _SnortConfig *sc, tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { return FTPTelnetCheckConfigs(sc, pData, policyId); } int FTPConfigCheck(struct _SnortConfig *sc) { int rval; if (ftp_telnet_config == NULL) return 0; if ((rval = sfPolicyUserDataIterate (sc, ftp_telnet_config, FTPConfigCheckPolicy))) return rval; return 0; } /* * Function: LogFTPPEvents(FTPP_GEN_EVENTS *GenEvents, * int iGenerator) * * Purpose: This is the routine that logs FTP/Telnet Preprocessor (FTPP) * alerts through Snort. * * Every Session gets looked at for any logged events, and if * there are events to be logged then we select the one with the * highest priority. * * We use a generic event structure that we set for each different * event structure. This way we can use the same code for event * logging regardless of what type of event strucure we are dealing * with. * * The important things to know about this function is how to work * with the event queue. The number of unique events is contained * in the stack_count variable. So we loop through all the unique * events and find which one has the highest priority. During this * loop, we also re-initialize the individual event counts for the * next iteration, saving us time in a separate initialization phase. * * After we've iterated through all the events and found the one * with the highest priority, we then log that event through snort. * * We've mapped the FTPTelnet and the Snort alert IDs together, so * we can access them directly instead of having a more complex * mapping function. * * Arguments: GenEvents => pointer a list of events * iGenerator => Generator ID (Telnet or FTP) * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static inline int LogFTPPEvents(FTPP_GEN_EVENTS *GenEvents, int iGenerator) { FTPP_EVENT *OrigEvent; FTPP_EVENT *HiEvent = NULL; int iStackCnt; int iEvent; int iCtr; /* * Now starts the generic event processing */ iStackCnt = GenEvents->stack_count; /* * IMPORTANT:: * We have to check the stack count of the event queue before we process * an log. */ if(iStackCnt == 0) { return FTPP_SUCCESS; } /* * Cycle through the events and select the event with the highest * priority. */ for(iCtr = 0; iCtr < iStackCnt; iCtr++) { iEvent = GenEvents->stack[iCtr]; OrigEvent = &(GenEvents->events[iEvent]); /* * Set the event to start off the comparison */ if(!HiEvent) { HiEvent = OrigEvent; } /* * This is our "comparison function". Log the event with the highest * priority. */ if(OrigEvent->event_info->priority < HiEvent->event_info->priority) { HiEvent = OrigEvent; } /* * IMPORTANT: * This is how we reset the events in the event queue. * If you miss this step, you can be really screwed. */ OrigEvent->count = 0; } if (!HiEvent) return FTPP_SUCCESS; /* * We use the iEvent+1 because the event IDs between snort and * FTPTelnet are mapped off-by-one. They're mapped off-by one * because in the internal FTPTelnet queue, events are mapped * starting at 0. For some reason, it appears that the first * event can't be zero, so we use the internal value and add * one for snort. */ iEvent = HiEvent->event_info->alert_id + 1; /* GenID, SID, Rev, Classification, Pri, Msg, RuleInfo */ _dpd.alertAdd(iGenerator, HiEvent->event_info->alert_sid, 1, /* Revision 1 */ HiEvent->event_info->classification, HiEvent->event_info->priority, HiEvent->event_info->alert_str, NULL); /* No Rule info */ /* * Reset the event queue stack counter, in the case of pipelined * requests. */ GenEvents->stack_count = 0; return FTPP_SUCCESS; } /* * Function: LogFTPEvents(FTP_SESSION *FtpSession) * * Purpose: This is the routine that logs FTP alerts through Snort. * It maps the event into a generic event and calls * LOGFTPPEvents(). * * Arguments: FtpSession => pointer the session structure * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static inline int LogFTPEvents(FTP_SESSION *FtpSession) { FTPP_GEN_EVENTS GenEvents; int iGenerator; int iRet; GenEvents.stack = FtpSession->event_list.stack; GenEvents.stack_count = FtpSession->event_list.stack_count; GenEvents.events = FtpSession->event_list.events; iGenerator = GENERATOR_SPP_FTPP_FTP; iRet = LogFTPPEvents(&GenEvents, iGenerator); /* Reset the count... */ FtpSession->event_list.stack_count = 0; return iRet; } /* * Function: LogTelnetEvents(TELNET_SESSION *TelnetSession) * * Purpose: This is the routine that logs Telnet alerts through Snort. * It maps the event into a generic event and calls * LOGFTPPEvents(). * * Arguments: TelnetSession => pointer the session structure * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static inline int LogTelnetEvents(TELNET_SESSION *TelnetSession) { FTPP_GEN_EVENTS GenEvents; int iGenerator; int iRet; GenEvents.stack = TelnetSession->event_list.stack; GenEvents.stack_count = TelnetSession->event_list.stack_count; GenEvents.events = TelnetSession->event_list.events; iGenerator = GENERATOR_SPP_FTPP_TELNET; iRet = LogFTPPEvents(&GenEvents, iGenerator); /* Reset the count... */ TelnetSession->event_list.stack_count = 0; return iRet; } /* * Function: SetSiInput(FTPP_SI_INPUT *SiInput, Packet *p) * * Purpose: This is the routine sets the source and destination IP * address and port pairs so as to determine the direction * of the FTP or telnet connection. * * Arguments: SiInput => pointer the session input structure * p => pointer to the packet structure * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ static inline int SetSiInput(FTPP_SI_INPUT *SiInput, SFSnortPacket *p) { IP_COPY_VALUE(SiInput->sip, GET_SRC_IP(p)); IP_COPY_VALUE(SiInput->dip, GET_DST_IP(p)); SiInput->sport = p->src_port; SiInput->dport = p->dst_port; /* * We now set the packet direction */ if(p->stream_session_ptr && _dpd.streamAPI->get_session_flags(p->stream_session_ptr) & SSNFLAG_MIDSTREAM) { SiInput->pdir = FTPP_SI_NO_MODE; } else if(p->flags & FLAG_FROM_SERVER) { SiInput->pdir = FTPP_SI_SERVER_MODE; } else if(p->flags & FLAG_FROM_CLIENT) { SiInput->pdir = FTPP_SI_CLIENT_MODE; } else { SiInput->pdir = FTPP_SI_NO_MODE; } return FTPP_SUCCESS; } /* * Function: do_detection(Packet *p) * * Purpose: This is the routine that directly performs the rules checking * for each of the FTP & telnet preprocessing modules. * * Arguments: p => pointer to the packet structure * * Returns: None * */ void do_detection(SFSnortPacket *p) { //extern int do_detect; //extern OptTreeNode *otn_tmp; PROFILE_VARS; /* * If we get here we either had a client or server request/response. * We do the detection here, because we're starting a new paradigm * about protocol decoders. * * Protocol decoders are now their own detection engine, since we are * going to be moving protocol field detection from the generic * detection engine into the protocol module. This idea scales much * better than having all these Packet struct field checks in the * main detection engine for each protocol field. */ PREPROC_PROFILE_START(ftppDetectPerfStats); _dpd.detect(p); _dpd.disableAllDetect(p); PREPROC_PROFILE_END(ftppDetectPerfStats); #ifdef PERF_PROFILING ftppDetectCalled = 1; #endif //otn_tmp = NULL; /* * We set the global detection flag here so that if request pipelines * fail, we don't do any detection. */ //do_detect = 0; } /* * Function: SnortTelnet(FTPTELNET_GLOBAL_CONF *GlobalConf, * Packet *p, * int iInspectMode) * * Purpose: This is the routine that handles the protocol layer checks * for telnet. * * Arguments: GlobalConf => pointer the global configuration * p => pointer to the packet structure * iInspectMode => indicator whether this is a client or server * packet. * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int SnortTelnet(FTPTELNET_GLOBAL_CONF *GlobalConf, TELNET_SESSION *TelnetSession, SFSnortPacket *p, int iInspectMode) { int iRet; PROFILE_VARS; if (!TelnetSession) { if (GlobalConf->inspection_type == FTPP_UI_CONFIG_STATEFUL) { return FTPP_NONFATAL_ERR; } else { return FTPP_INVALID_SESSION; } } if (TelnetSession->encr_state && !GlobalConf->check_encrypted_data) { return FTPP_SUCCESS; } PREPROC_PROFILE_START(telnetPerfStats); if (!GlobalConf->telnet_config->normalize) { do_detection(p); } else { iRet = normalize_telnet(GlobalConf, TelnetSession, p, iInspectMode, FTPP_APPLY_TNC_ERASE_CMDS); if ((iRet == FTPP_SUCCESS) || (iRet == FTPP_NORMALIZED)) { do_detection(p); } LogTelnetEvents(TelnetSession); } PREPROC_PROFILE_END(telnetPerfStats); #ifdef PERF_PROFILING if (ftppDetectCalled) { telnetPerfStats.ticks -= ftppDetectPerfStats.ticks; /* And Reset ticks to 0 */ ftppDetectPerfStats.ticks = 0; ftppDetectCalled = 0; } #endif return FTPP_SUCCESS; } /* * Function: SnortFTP(FTPTELNET_GLOBAL_CONF *GlobalConf, * Packet *p, * int iInspectMode) * * Purpose: This is the routine that handles the protocol layer checks * for FTP. * * Arguments: GlobalConf => pointer the global configuration * p => pointer to the packet structure * iInspectMode => indicator whether this is a client or server * packet. * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int SnortFTP(FTPTELNET_GLOBAL_CONF *GlobalConf, FTP_SESSION *FTPSession, SFSnortPacket *p, int iInspectMode) { int iRet; PROFILE_VARS; if (!FTPSession || FTPSession->server_conf == NULL || FTPSession->client_conf == NULL) { return FTPP_INVALID_SESSION; } if (!GlobalConf->check_encrypted_data && ((FTPSession->encr_state == AUTH_TLS_ENCRYPTED) || (FTPSession->encr_state == AUTH_SSL_ENCRYPTED) || (FTPSession->encr_state == AUTH_UNKNOWN_ENCRYPTED)) ) { return FTPP_SUCCESS; } PREPROC_PROFILE_START(ftpPerfStats); if (iInspectMode == FTPP_SI_SERVER_MODE) { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Server packet: %.*s\n", p->payload_size, p->payload)); // FIXTHIS breaks target-based non-standard ports //if ( !_dpd.isPafEnabled() ) /* Force flush of client side of stream */ _dpd.streamAPI->response_flush_stream(p); } else { if ( !_dpd.readyForProcess(p) ) { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Client packet will be reassembled\n")); PREPROC_PROFILE_END(ftpPerfStats); return FTPP_SUCCESS; } else { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Client packet: rebuilt %s: %.*s\n", (p->flags & FLAG_REBUILT_STREAM) ? "yes" : "no", p->payload_size, p->payload)); } } iRet = initialize_ftp(FTPSession, p, iInspectMode); if (iRet) { LogFTPEvents(FTPSession); PREPROC_PROFILE_END(ftpPerfStats); return iRet; } iRet = check_ftp(FTPSession, p, iInspectMode); if (iRet == FTPP_SUCCESS) { /* Ideally, Detect(), called from do_detection, will look at * the cmd & param buffers, or the rsp & msg buffers. Current * architecture does not support this... * So, we call do_detection() here. Otherwise, we'd call it * from inside check_ftp -- each time we process a pipelined * FTP command. */ do_detection(p); } LogFTPEvents(FTPSession); PREPROC_PROFILE_END(ftpPerfStats); #ifdef PERF_PROFILING if (ftppDetectCalled) { ftpPerfStats.ticks -= ftppDetectPerfStats.ticks; /* And Reset ticks to 0 */ ftppDetectPerfStats.ticks = 0; ftppDetectCalled = 0; } #endif return iRet; } /* * Funtcion: SnortFTPTelnet * * Purpose: This function calls the FTPTelnet function that handles * the protocol layer checks for an FTP or Telnet session, * after determining which, if either, protocol applies. * * Arguments: GlobalConf => pointer the global configuration * p => pointer to the packet structure * * Returns: int => an error code integer (0 = success, * >0 = non-fatal error, <0 = fatal error) * */ int SnortFTPTelnet(SFSnortPacket *p) { FTPP_SI_INPUT SiInput; int iInspectMode = FTPP_SI_NO_MODE; FTP_TELNET_SESSION *ft_ssn = NULL; tSfPolicyId policy_id = _dpd.getRuntimePolicy(); FTPTELNET_GLOBAL_CONF *GlobalConf = NULL; sfPolicyUserPolicySet (ftp_telnet_config, policy_id); GlobalConf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(ftp_telnet_config); /* * Set up the FTPP_SI_INPUT pointer. This is what the session_inspection() * routines use to determine client and server traffic. Plus, this makes * the FTPTelnet library very independent from snort. */ SetSiInput(&SiInput, p); if (p->stream_session_ptr) { ft_ssn = (FTP_TELNET_SESSION *) _dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_FTPTELNET); if (ft_ssn != NULL) { SiInput.pproto = ft_ssn->proto; if (ft_ssn->proto == FTPP_SI_PROTO_TELNET) { TELNET_SESSION *telnet_ssn = (TELNET_SESSION *)ft_ssn; GlobalConf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(telnet_ssn->global_conf, telnet_ssn->policy_id); if (SiInput.pdir != FTPP_SI_NO_MODE) { iInspectMode = SiInput.pdir; } else { if ((telnet_ssn->telnet_conf != NULL) && (telnet_ssn->telnet_conf->proto_ports.ports[SiInput.sport])) { iInspectMode = FTPP_SI_SERVER_MODE; } else if ((telnet_ssn->telnet_conf != NULL) && (telnet_ssn->telnet_conf->proto_ports.ports[SiInput.dport])) { iInspectMode = FTPP_SI_CLIENT_MODE; } } } else if (ft_ssn->proto == FTPP_SI_PROTO_FTP) { FTP_SESSION *ftp_ssn = (FTP_SESSION *)ft_ssn; GlobalConf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(ftp_ssn->global_conf, ftp_ssn->policy_id); if (SiInput.pdir != FTPP_SI_NO_MODE) { iInspectMode = SiInput.pdir; } else { if ((ftp_ssn->server_conf != NULL) && ftp_ssn->server_conf->proto_ports.ports[SiInput.sport]) { iInspectMode = FTPP_SI_SERVER_MODE; } else if ((ftp_ssn->server_conf != NULL) && ftp_ssn->server_conf->proto_ports.ports[SiInput.dport]) { iInspectMode = FTPP_SI_CLIENT_MODE; } else { iInspectMode = FTPGetPacketDir(p); } } } else { /* XXX - Not FTP or Telnet */ _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_FTPTELNET, NULL, NULL); return 0; } } } if (GlobalConf == NULL) return 0; /* * FTPTelnet PACKET FLOW:: * * Determine Proto Module:: * The Session Inspection Module retrieves the appropriate * configuration for sessions, and takes care of the stateless * vs. stateful processing in order to do this. Once this module * does it's magic, we're ready for the primetime. This means * determining whether this is an FTP or a Telnet session. * * Proto Specific Module:: * This is where we normalize the data. The Protocol specific module * handles what type of normalization to do (telnet, ftp) and does * protocol related checks. * */ if (ft_ssn == NULL) { int iRet = ftpp_si_determine_proto(p, GlobalConf, &ft_ssn, &SiInput, &iInspectMode); if (iRet) return iRet; } if (ft_ssn != NULL) { switch (SiInput.pproto) { case FTPP_SI_PROTO_TELNET: return SnortTelnet(GlobalConf, (TELNET_SESSION *)ft_ssn, p, iInspectMode); break; case FTPP_SI_PROTO_FTP: return SnortFTP(GlobalConf, (FTP_SESSION *)ft_ssn, p, iInspectMode); break; } } /* Uh, shouldn't get here */ return FTPP_INVALID_PROTO; } #ifdef TARGET_BASED static void FTPDataProcess(SFSnortPacket *p, FTP_DATA_SESSION *data_ssn, uint8_t *file_data, uint16_t data_length) { int status; _dpd.setFileDataPtr((uint8_t *)p->payload, (uint16_t)p->payload_size); status = _dpd.fileAPI->file_process(p, (uint8_t *)file_data, data_length, data_ssn->position, data_ssn->direction, false); /* Filename needs to be set AFTER the first call to file_process( ) */ if (data_ssn->filename && !(data_ssn->flags & FTPDATA_FLG_FILENAME_SET)) { _dpd.fileAPI->set_file_name(p->stream_session_ptr, (uint8_t *)data_ssn->filename, data_ssn->file_xfer_info); data_ssn->flags |= FTPDATA_FLG_FILENAME_SET; } /* Ignore the rest of this transfer if file processing is complete * and preprocessor was configured to ignore ftp-data sessions. */ if (!status && data_ssn->data_chan) { _dpd.streamAPI->set_ignore_direction( p->stream_session_ptr, SSN_DIR_BOTH); } } void SnortFTPData_EOF(SFSnortPacket *p) { FTP_DATA_SESSION *data_ssn = (FTP_DATA_SESSION *) _dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_FTPTELNET); if (!PROTO_IS_FTP_DATA(data_ssn) || !FTPDataDirection(p, data_ssn)) return; initFilePosition(&data_ssn->position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); finalFilePosition(&data_ssn->position); _dpd.streamAPI->alert_flush_stream(p); } int SnortFTPData(SFSnortPacket *p) { FTP_DATA_SESSION *data_ssn; if (!p->stream_session_ptr) return -1; data_ssn = (FTP_DATA_SESSION *) _dpd.streamAPI->get_application_data(p->stream_session_ptr, PP_FTPTELNET); if (!PROTO_IS_FTP_DATA(data_ssn)) return -2; if (data_ssn->flags & FTPDATA_FLG_STOP) return 0; /* Do this now before splitting the work for rebuilt and raw packets. */ #if 0 if ((p->flags & FLAG_PDU_TAIL) || (p->tcp_header->flags & TCPHEADER_FIN)) SetFTPDataEOFDirection(p, data_ssn); #endif /* * Raw Packet Processing */ if (!(p->flags & FLAG_REBUILT_STREAM)) { if (!(data_ssn->flags & FTPDATA_FLG_REASSEMBLY_SET)) { /* Enable Reassembly */ _dpd.streamAPI->set_reassembly( p->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_BOTH, STREAM_FLPOLICY_SET_ABSOLUTE); data_ssn->flags |= FTPDATA_FLG_REASSEMBLY_SET; } if (isFileEnd(data_ssn->position)) { data_ssn->flags |= FTPDATA_FLG_STOP; FTPDataProcess(p, data_ssn, (uint8_t *)p->payload, (uint16_t)p->payload_size); } return 0; } if (data_ssn->file_xfer_info == FTPP_FILE_UNKNOWN) { /* FTP-Data Session is in limbo, we need to lookup the control session * to figure out what to do. */ FTP_SESSION *ftp_ssn = (FTP_SESSION *) _dpd.streamAPI->get_application_data_from_key(data_ssn->ftp_key, PP_FTPTELNET); if (!PROTO_IS_FTP(ftp_ssn)) { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP-DATA Invalid FTP_SESSION retrieved durring lookup\n");); if (data_ssn->data_chan) _dpd.streamAPI->set_ignore_direction(p->stream_session_ptr, SSN_DIR_BOTH); return -2; } switch (ftp_ssn->file_xfer_info) { case FTPP_FILE_UNKNOWN: /* Keep waiting */ break; case FTPP_FILE_IGNORE: /* This wasn't a file transfer; ignore it */ if (data_ssn->data_chan) _dpd.streamAPI->set_ignore_direction( p->stream_session_ptr, SSN_DIR_BOTH); return 0; default: /* A file transfer was detected. */ data_ssn->direction = ftp_ssn->data_xfer_dir; data_ssn->file_xfer_info = ftp_ssn->file_xfer_info; ftp_ssn->file_xfer_info = 0; data_ssn->filename = ftp_ssn->filename; ftp_ssn->filename = NULL; if ( p->tcp_header->flags & TCPHEADER_FIN ) { initFilePosition(&data_ssn->position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); finalFilePosition(&data_ssn->position); } else { _dpd.streamAPI->set_event_handler( p->stream_session_ptr, s_ftpdata_eof_cb_id, SE_EOF); } break; } } if (!FTPDataDirection(p, data_ssn)) return 0; if (isFileEnd(data_ssn->position)) { data_ssn->flags |= FTPDATA_FLG_STOP; } else { initFilePosition(&data_ssn->position, _dpd.fileAPI->get_file_processed_size(p->stream_session_ptr)); } FTPDataProcess(p, data_ssn, (uint8_t *)p->payload, (uint16_t)p->payload_size); return 0; } #endif /* TARGET_BASED */ int FTPPBounceInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr) { char **toks; int num_toks; toks = _dpd.tokenSplit(parameters, ",", 12, &num_toks, 0); if(num_toks > 0) { DynamicPreprocessorFatalMessage("ERROR: Bad arguments to '%s' option: '%s'\n", name, parameters); } _dpd.tokenFree(&toks, num_toks); *dataPtr = NULL; return 1; } /**************************************************************************** * * Function: FTPPBounce(void *pkt, uint8_t **cursor, void **dataPtr) * * Purpose: Use this function to perform the particular detection routine * that this rule keyword is supposed to encompass. * * Arguments: p => pointer to the decoded packet * cursor => pointer to the current location in the buffer * dataPtr => pointer to rule specific data (not used for this option) * * Returns: If the detection test fails, this function *must* return a zero! * On success, it returns 1; * ****************************************************************************/ int FTPPBounceEval(void *pkt, const uint8_t **cursor, void *dataPtr) { uint32_t ip = 0; SFSnortPacket *p = (SFSnortPacket *)pkt; int octet=0; const char *start_ptr, *end_ptr; const char *this_param = *(const char **)cursor; int dsize; if ( !p->ip4_header ) return 0; if(_dpd.Is_DetectFlag(SF_FLAG_ALT_DETECT)) { dsize = _dpd.altDetect->len; start_ptr = (char *) _dpd.altDetect->data; DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Using Alternative Detect buffer!\n");); } else if(_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE)) { dsize = _dpd.altBuffer->len; start_ptr = (char *) _dpd.altBuffer->data; DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "Using Alternative Decode buffer!\n");); } else { start_ptr = (const char *)p->payload; dsize = p->payload_size; } DEBUG_WRAP( DebugMessage(DEBUG_PATTERN_MATCH,"[*] ftpbounce firing...\n"); DebugMessage(DEBUG_PATTERN_MATCH,"payload starts at %p\n", start_ptr); ); /* END DEBUG_WRAP */ /* save off whatever our ending pointer is */ end_ptr = start_ptr + dsize; while (isspace((int)*this_param) && (this_param < end_ptr)) this_param++; do { int value = 0; do { if (!isdigit((int)*this_param)) { DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "[*] ftpbounce non digit char failed..\n");); return RULE_NOMATCH; } value = value * 10 + (*this_param - '0'); this_param++; } while ((this_param < end_ptr) && (*this_param != ',') && (!(isspace((int)*this_param)))); if (value > 0xFF) { DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "[*] ftpbounce value > 256 ..\n");); return RULE_NOMATCH; } if (octet < 4) { ip = (ip << 8) + value; } if (!isspace((int)*this_param)) this_param++; octet++; } while ((this_param < end_ptr) && !isspace((int)*this_param) && (octet < 4)); if (octet < 4) { DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "[*] ftpbounce insufficient data ..\n");); return RULE_NOMATCH; } if (ip != ntohl(p->ip4_header->source.s_addr)) { /* Bounce attempt -- IPs not equal */ return RULE_MATCH; } else { DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH, "PORT command not being used in bounce\n");); return RULE_NOMATCH; } /* Never reached */ return RULE_NOMATCH; } /* Add ports configured for ftptelnet preprocessor to stream5 port filtering so that * if any_any rules are being ignored then the packet still reaches ftptelnet. * * For ports in global_server configuration, server_lookup and server_lookupIpv6, * add the port to stream5 port filter list. */ static void _FTPTelnetAddPortsOfInterest(struct _SnortConfig *sc, FTPTELNET_GLOBAL_CONF *config, tSfPolicyId policy_id) { int i; if (config == NULL) return; /* For the server callback */ ftp_current_policy = policy_id; _addPortsToStream5(sc, config->telnet_config->proto_ports.ports, policy_id, 0); _addPortsToStream5(sc, config->default_ftp_server->proto_ports.ports, policy_id, 1); ftpp_ui_server_iterate(sc, config->server_lookup, _addFtpServerConfPortsToStream5, &i); } static int _addFtpServerConfPortsToStream5(struct _SnortConfig *sc, void *pData) { FTP_SERVER_PROTO_CONF *pConf = (FTP_SERVER_PROTO_CONF *)pData; _addPortsToStream5(sc, pConf->proto_ports.ports, ftp_current_policy, 1); return 0; } // flush at last line feed in payload // preproc will deal with any pipelined commands static PAF_Status ftp_paf ( void* ssn, void** pv, const uint8_t* data, uint32_t len, uint32_t flags, uint32_t* fp) { #ifdef HAVE_MEMRCHR uint8_t* lf = memrchr(data, '\n', len); #else uint32_t n = len; uint8_t* lf = NULL, * tmp = (uint8_t*) data; while ( (tmp = memchr(tmp, '\n', n)) ) { lf = tmp++; n = len - (tmp - data); } #endif DEBUG_WRAP(DebugMessage(DEBUG_STREAM_PAF, "%s[%d] '%*.*s'\n", __FUNCTION__, len, len, len, data)); if ( !lf ) return PAF_SEARCH; *fp = lf - data + 1; return PAF_FLUSH; } #ifdef TARGET_BASED static void _FTPTelnetAddService (struct _SnortConfig *sc, int16_t app, tSfPolicyId policy) { if ( _dpd.isPafEnabled() ) { _dpd.streamAPI->register_paf_service(sc, policy, app, true, ftp_paf, false); _dpd.streamAPI->register_paf_service(sc, policy, app, false, ftp_paf, false); } } #endif static void _addPortsToStream5(struct _SnortConfig *sc, char *ports, tSfPolicyId policy_id, int ftp) { unsigned int i; for (i = 0; i < MAXPORTS; i++) { if (ports[i]) { //Add port the port _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_TCP, (uint16_t)i, PORT_MONITOR_SESSION, policy_id, 1); if ( ftp && _dpd.isPafEnabled() ) { _dpd.streamAPI->register_paf_port(sc, policy_id, (uint16_t)i, true, ftp_paf, false); _dpd.streamAPI->register_paf_port(sc, policy_id, (uint16_t)i, false, ftp_paf, false); } } } } int FtpTelnetInitGlobalConfig(FTPTELNET_GLOBAL_CONF *config, char *ErrorString, int iErrStrLen) { int iRet; if (config == NULL) { snprintf(ErrorString, iErrStrLen, "Global configuration is NULL."); return FTPP_FATAL_ERR; } iRet = ftpp_ui_config_init_global_conf(config); if (iRet) { snprintf(ErrorString, iErrStrLen, "Error initializing Global Configuration."); return FTPP_FATAL_ERR; } #ifdef CLIENT_READY iRet = ftpp_client_init(config); if (iRet) { snprintf(ErrorString, iErrStrLen, "Error initializing client module."); return FTPP_FATAL_ERR; } iRet = ftpp_norm_init(config); if (iRet) { snprintf(ErrorString, iErrStrLen, "Error initializing normalization module."); return FTPP_FATAL_ERR; } #endif return 0; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/pp_telnet.h0000644000000000000000000000455412260565732021234 00000000000000/* * pp_telnet.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * Header file for FTPTelnet telnet Module * * This file defines the telnet checking functions * * NOTES: * - 20.09.04: Initial Development. SAS * */ #ifndef __PP_TELNET_H__ #define __PP_TELNET_H__ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* RFC 885 defines an End of Record telnet option */ #define RFC885 /* RFC 1184 defines Abort, Suspend, and End of File telnet optinos */ #define RFC1184 //#include "decode.h" #include "ftpp_ui_config.h" #include "ftpp_si.h" /* define the telnet negotiation codes (TNC) that we're interested in */ #define TNC_IAC 0xFF #define TNC_DONT 0xFE #define TNC_DO 0xFD #define TNC_WONT 0xFC #define TNC_WILL 0xFB #define TNC_SB 0xFA #define TNC_GA 0xF9 #define TNC_EAL 0xF8 #define TNC_EAC 0xF7 #define TNC_AYT 0xF6 #define TNC_AO 0xF5 #define TNC_IP 0xF4 #define TNC_BRK 0xF3 #define TNC_DM 0xF2 #define TNC_NOP 0xF1 #define TNC_SE 0xF0 #ifdef RFC885 #define TNC_EOR 0xEF #endif #ifdef RFC1184 #define TNC_ABOR 0xEE #define TNC_SUSP 0xED #define TNC_EOF 0xEC #endif #define FTPP_APPLY_TNC_ERASE_CMDS 0 #define FTPP_IGNORE_TNC_ERASE_CMDS 1 /* list of function prototypes for this preprocessor */ extern int normalize_telnet(FTPTELNET_GLOBAL_CONF *GlobalConf, TELNET_SESSION *Session, SFSnortPacket *p, int iMode, char ignoreEraseCmd); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/pp_telnet.c0000644000000000000000000003620312260565732021223 00000000000000/* * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2002-2013 Sourcefire, Inc. * Copyright (C) 1998-2002 Martin Roesch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Snort Preprocessor for Telnet Negotiation Normalization*/ /* $Id$ */ /* pp_telnet.c * * Purpose: Telnet sessions can contain telnet negotiation strings * that can disrupt pattern matching. This plugin detects * negotiation strings in stream and "normalizes" them much like * the http_decode preprocessor normalizes encoded URLs * * * official registry of options * http://www.iana.org/assignments/telnet-options * * Arguments: None * * Effect: The telnet nogiation data is removed from the payload * * Comments: * */ /* your preprocessor header file goes here */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STRINGS_H #include #endif #include #include "ftpp_eo_log.h" #include "pp_telnet.h" #include "ftpp_return_codes.h" #include "snort_debug.h" #include "stream_api.h" #define NUL 0x00 #define CR 0x0d #define LF 0x0a /* This is the allowable number of 8 bit characters, * ie, non-ASCII, before we declare this packet/stream * as encrypted. */ #define CONSECUTIVE_8BIT_THRESHOLD 3 /* * Function: normalize_telnet(Packet *) * * Purpose: Perform the preprocessor's intended function. This can be * simple (statistics collection) or complex (IP defragmentation) * as you like. Try not to destroy the performance of the whole * system by trying to do too much.... * * Arguments: p => pointer to the current packet data struct * * Returns: void function * */ int normalize_telnet(FTPTELNET_GLOBAL_CONF *GlobalConf, TELNET_SESSION *tnssn, SFSnortPacket *p, int iMode, char ignoreEraseCmds) { int ret = FTPP_NORMALIZED; const unsigned char *read_ptr, *sb_start = NULL; int saw_ayt = 0; const unsigned char *start = _dpd.altBuffer->data; unsigned char *write_ptr; const unsigned char *end; int normalization_required = 0; int consec_8bit_chars = 0; /* Telnet commands are handled in here. * They can be 2 bytes long -- ie, IAC NOP, IAC AYT, etc. * Sub-negotiation strings are at least 4 bytes, IAC SB x IAC SE */ if(p->payload_size < 2) { if (tnssn && iMode == FTPP_SI_CLIENT_MODE) tnssn->consec_ayt = 0; return FTPP_SUCCESS; } /* setup the pointers */ read_ptr = p->payload; end = p->payload + p->payload_size; /* look to see if we have any telnet negotiaion codes in the payload */ while(!normalization_required && (read_ptr < end)) { /* look for the start of a negotiation string */ if(*read_ptr == (unsigned char) TNC_IAC) { /* set a flag for stage 2 normalization */ normalization_required = 1; } else { /* Okay, it wasn't an IAC also its a midstream pickup */ if (*read_ptr > 0x7F && _dpd.streamAPI->get_session_flags(p->stream_session_ptr) & SSNFLAG_MIDSTREAM) { consec_8bit_chars++; if (consec_8bit_chars > CONSECUTIVE_8BIT_THRESHOLD) { /* This data stream had a series of 8 bit characters. * It is very likely encrypted. This handles the case * where we either missed the option negotiation, or * lost state of an already encrypted telnet session. */ if (tnssn) { tnssn->encr_state = 1; if (GlobalConf->encrypted.alert) { /* Alert on encrypted channel */ telnet_eo_event_log(tnssn, TELNET_EO_ENCRYPTED, NULL, NULL); } if (!GlobalConf->check_encrypted_data) { /* Mark this session & packet as one to ignore */ _dpd.streamAPI->stop_inspection(p->stream_session_ptr, p, SSN_DIR_BOTH, -1, 0); /* No point to do further normalization */ return FTPP_ALERT; } } break; } } else { consec_8bit_chars = 0; } } read_ptr++; } if(!normalization_required) { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Nothing to process!\n");); if (tnssn && iMode == FTPP_SI_CLIENT_MODE) tnssn->consec_ayt = 0; return FTPP_SUCCESS; } /* * if we found telnet negotiation strings OR backspace characters, * we're going to have to normalize the data * * Note that this is always ( now: 2002-08-12 ) done to a * alternative data buffer. */ /* rewind the data stream to p->data */ read_ptr = p->payload; /* setup for overwriting the negotaiation strings with * the follow-on data */ write_ptr = (unsigned char *) _dpd.altBuffer; /* walk thru the remainder of the packet */ while((read_ptr < end) && (write_ptr < ((unsigned char *) _dpd.altBuffer->data) + sizeof(_dpd.altBuffer->data))) { saw_ayt = 0; /* if the following byte isn't a subnegotiation initialization */ if(((read_ptr + 1) < end) && (*read_ptr == (unsigned char) TNC_IAC) && (*(read_ptr + 1) != (unsigned char) TNC_SB)) { /* NOPs are two bytes long */ switch(* ((unsigned char *)(read_ptr + 1))) { case TNC_NOP: read_ptr += 2; break; case TNC_EAC: read_ptr += 2; /* wind it back a character? */ if (ignoreEraseCmds == FTPP_APPLY_TNC_ERASE_CMDS) { if(write_ptr > start) { write_ptr--; } } break; case TNC_EAL: read_ptr += 2; /* wind it back a line? */ if (ignoreEraseCmds == FTPP_APPLY_TNC_ERASE_CMDS) { /* Go back to previous CR NULL or CR LF? */ while (write_ptr > start) { /* Go to previous char */ write_ptr--; if ((*write_ptr == CR) && ((*(write_ptr+1) == NUL) || (*(write_ptr+1) == LF)) ) { /* Okay, found the CR NUL or CR LF, move it * forward past those two -- that is the * beginning of this line */ write_ptr+=2; break; } } } break; /* These are two bytes long */ case TNC_AYT: saw_ayt = 1; if (tnssn) { tnssn->consec_ayt++; if ((tnssn->telnet_conf->ayt_threshold > 0) && (tnssn->consec_ayt > tnssn->telnet_conf->ayt_threshold)) { /* Alert on consecutive AYT commands */ telnet_eo_event_log(tnssn, TELNET_EO_AYT_OVERFLOW, NULL, NULL); tnssn->consec_ayt = 0; return FTPP_ALERT; } } /* Fall through */ case TNC_BRK: case TNC_DM: case TNC_IP: case TNC_AO: case TNC_GA: #ifdef RFC1184 case TNC_EOF: case TNC_SUSP: case TNC_ABOR: #endif #ifdef RFC885 case TNC_EOR: #endif read_ptr += 2; break; case TNC_SE: /* Uh, what the heck is a Subnegotiation-end * doing here without SB?. could generate an alert. * Will just normalize it out since we may have * processed the SB in a previous packet. */ read_ptr += 2; break; case TNC_IAC: /* IAC IAC -- means the IAC character (0xff) should be * in the data stream since it was escaped */ read_ptr++; /* skip past the first IAC */ *write_ptr++ = *read_ptr++; break; case TNC_WILL: case TNC_WONT: case TNC_DO: case TNC_DONT: read_ptr += 3; break; default: /* move the read ptr up 2 bytes */ read_ptr += 2; } /* If not an AYT, reset it */ if (!saw_ayt) { if (tnssn && iMode == FTPP_SI_CLIENT_MODE) tnssn->consec_ayt = 0; } } /* check for subnegotiation */ else if(((read_ptr + 1) < end) && (*read_ptr == (unsigned char) TNC_IAC) && (*(read_ptr+1) == (unsigned char) TNC_SB)) { sb_start = read_ptr; switch (*(read_ptr+2)) { case 0x26: /* Encryption -- RFC 2946 */ /* printf("Telnet: Saw SB for Encryption\n"); */ read_ptr += 3; switch (*read_ptr) { #ifdef TRACK_ENCRYPTION_NEGOTIATION case 0x00: /* Client sending the Encryption IS marker * followed by address. */ { read_ptr++; if (*read_ptr != 0x00) /* Encryption type is not NULL */ { /* printf("Encryption being negotiated by * telnet client\n"); */ } } break; #endif case 0x03: /* Client sending the Encryption START marker * followed by address. */ { read_ptr++; /* printf("Encryption started by telnet client\n"); */ if (tnssn) { tnssn->encr_state = 1; if (GlobalConf->encrypted.alert) { /* Alert on encrypted channel */ telnet_eo_event_log(tnssn, TELNET_EO_ENCRYPTED, NULL, NULL); } if (!GlobalConf->check_encrypted_data) { /* Mark this session & packet as one to ignore */ _dpd.streamAPI->stop_inspection(p->stream_session_ptr, p, SSN_DIR_BOTH, -1, 0); /* No point to do further normalization */ return FTPP_ALERT; } } } break; } break; } /* find the end of the subneg -- this handles when there are * embedded IAC IACs within a sub negotiation. Just looking * for the TNC_SE could cause problems. Similarly, just looking * for the TNC_IAC could end it too early. */ while(read_ptr < end) { if ((*read_ptr == (unsigned char) TNC_IAC) && (*(read_ptr+1) == (unsigned char) TNC_SE)) { sb_start = NULL; break; } read_ptr++; } if (sb_start) { /* Didn't find the IAC SE. Normalize out the IAC SB * and restart from there. Presumption is this is * just someone trying to fool us, since we usually * see the entire IAC SB ... IAC SE in one packet. */ read_ptr = sb_start+2; if (!tnssn) { /* Its an FTP session */ ret = FTPP_ALERT; } else if (GlobalConf->telnet_config->detect_anomalies) { /* Alert on SB without SE */ telnet_eo_event_log(tnssn, TELNET_EO_SB_NO_SE, NULL, NULL); ret = FTPP_ALERT; } continue; } /* Okay, found the IAC SE -- move past it */ if (read_ptr < end) { read_ptr += 2; } if (tnssn && iMode == FTPP_SI_CLIENT_MODE) tnssn->consec_ayt = 0; } else { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "overwriting %2X(%c) with %2X(%c)\n", (unsigned char)(*write_ptr&0xFF), *write_ptr, (unsigned char)(*read_ptr & 0xFF), *read_ptr);); /* overwrite the negotiation bytes with the follow-on bytes */ switch(* ((unsigned char *)(read_ptr))) { case 0x7F: /* Delete */ case 0x08: /* Backspace/Ctrl-H */ /* wind it back a character */ if (write_ptr > start) { write_ptr--; } read_ptr++; break; default: *write_ptr++ = *read_ptr++; break; } if (tnssn && iMode == FTPP_SI_CLIENT_MODE) tnssn->consec_ayt = 0; } } _dpd.SetAltDecode((uint16_t)(write_ptr - start)); /* DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Converted buffer after telnet normalization:\n"); PrintNetData(stdout, (char *) _dpd.altBuffer->data, _dpd.altBuffer->len);); */ return ret; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/pp_ftp.h0000644000000000000000000000300512260565732020520 00000000000000/* * pp_ftp.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * Header file for FTPTelnet FTP Module * * This file defines the ftp checking functions * * NOTES: * - 20.09.04: Initial Development. SAS * */ #ifndef __PP_FTP_H__ #define __PP_FTP_H__ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include //#include "decode.h" #include "ftpp_ui_config.h" #include "ftpp_si.h" /* list of function prototypes for this preprocessor */ extern int check_ftp(FTP_SESSION *Session, SFSnortPacket *p, int iMode); extern int initialize_ftp(FTP_SESSION *Session, SFSnortPacket *p, int iMode); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/pp_ftp.c0000644000000000000000000020743212260565732020525 00000000000000/* $Id$ */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2004-2013 Sourcefire, Inc. ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* pp_ftp.c * * Purpose: FTP sessions contain commands and responses. Certain * commands are vectors of attack. This module checks * those FTP client commands and their parameter values, as * well as the server responses per the configuration. * * Arguments: None * * Effect: Alerts may be raised * * Comments: * */ /* your preprocessor header file goes here */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STRINGS_H #include #endif #include #include #include #include #ifndef WIN32 #include #include #include #include #else #include #endif #include "ftpp_eo_log.h" #include "pp_ftp.h" #include "pp_telnet.h" #include "ftpp_return_codes.h" #include "ftp_cmd_lookup.h" #include "ftp_bounce_lookup.h" //#include "decode.h" #include "snort_debug.h" #include "stream_api.h" //#include "plugbase.h" #ifndef MAXHOSTNAMELEN /* Why doesn't Windows define this? */ #define MAXHOSTNAMELEN 256 #endif #include "ipv6_port.h" #ifdef TARGET_BASED extern int16_t ftp_data_app_id; #endif /* * Used to keep track of pipelined commands and the last one * that resulted in a */ static int ftp_cmd_pipe_index = 0; #if 0 /* * Function: getIP(char **ip_start, * char *last_char, * char term_char, * uint32_t *ipRet, * uint16_t *portRet) * * Purpose: Returns a 32bit IP address and port from an FTP-style * string -- ie, a,b,c,d,p1,p2. Stops checking when term_char * is seen. Used to get address and port information from FTP * PORT command and server response to PASV command. * * Arguments ip_start => Pointer to pointer to the start of string. * Updated to end of IP address if successful. * last_char => End of string * term_char => Character delimiting the end of the address. * ipRet => Return pointer to 32bit address on success * portRet => Return pointer to 16bit port on success * * Returns: int => return code indicating error or success * */ int getIP(const int type, const char **ip_start, const char *last_char, char *term_char, snort_ip *ipRet, uint16_t *portRet) { uint32_t ip=0; uint16_t port=0; int octet=0; const char *this_param = *ip_start; do { int value = 0; do { if (!isdigit((int)(*this_param))) { return FTPP_NON_DIGIT; } value = value * 10 + (*this_param - '0'); this_param++; } while ((this_param < last_char) && (*this_param != ',') && (*this_param != term_char)); if (value > 0xFF) { return FTPP_INVALID_ARG; } if (octet < 4) { ip = (ip << 8) + value; } else { port = (port << 8) + value; } if (*this_param != term_char) this_param++; octet++; } while ((this_param < last_char) && (*this_param != term_char) ); if (octet != 6) { return FTPP_MALFORMED_IP_PORT; } // XXX-IPv6 NOT YET IMPLEMENTED - IPv4 only at the moment sfip_set_raw(ipRet, &ip, AF_INET); *portRet = port; *ip_start = this_param; return FTPP_SUCCESS; } #endif /* * Function: getIP959(char **ip_start, * char *last_char, * char term_char, * uint32_t *ipRet, * uint16_t *portRet) * * Purpose: Returns a 32bit IP address and port from an RFC 959 FTP-style * string -- ie, a,b,c,d,p1,p2. Stops checking when term_char * is seen. Used to get address and port information from FTP * PORT command and server response to PASV command. * * Arguments ip_start => Pointer to pointer to the start of string. * Updated to end of IP address if successful. * last_char => End of string * term_char => Character delimiting the end of the address. * ipRet => Return pointer to 32bit address on success * portRet => Return pointer to 16bit port on success * * Returns: int => return code indicating error or success */ static int getIP959( const char **ip_start, const char *last_char, char *term_char, snort_ip *ipRet, uint16_t *portRet ) { uint32_t ip=0; uint16_t port=0; int octet=0; const char *this_param = *ip_start; do { int value = 0; do { if (!isdigit((int)(*this_param))) { return FTPP_NON_DIGIT; } value = value * 10 + (*this_param - '0'); this_param++; } while ((this_param < last_char) && (*this_param != ',') && (strchr(term_char, *this_param) == NULL)); if (value > 0xFF) { return FTPP_INVALID_ARG; } if (octet < 4) { ip = (ip << 8) + value; } else { port = (port << 8) + value; } if (strchr(term_char, *this_param) == NULL) this_param++; octet++; } while ((this_param < last_char) && (strchr(term_char, *this_param) == NULL)); if (octet != 6) { return FTPP_MALFORMED_IP_PORT; } ip = htonl(ip); sfip_set_raw(ipRet, &ip, AF_INET); *portRet = port; *ip_start = this_param; return FTPP_SUCCESS; } /* * getIP1639() parses the LPRT command parameters which have this * format (ftyp == e_long_host_port): * * LPRT af,hal,h1,h2,h3,h4...,pal,p1,p2... * LPRT 4,4,132,235,1,2,2,24,131 * LPRT 6,16,16,128,0,...,0,8,128,0,32,12,65,123,2,20,162 * * (The above examples correspond to the EPRT examples below.) * * af (address family) is the IP version. h# and p# are in network * byte order (high byte first). * * This function is called for the LPSV response as well, which * has this format: * * 228 (af,hal,h1,h2,h3,h4...,pal,p1,p2...) */ static int getIP1639 ( const char **ip_start, const char *last_char, char *term_char, snort_ip* ipRet, uint16_t *portRet ) { char bytes[21]; /* max of 1+5+3 and 1+17+3 */ const char* tok = *ip_start; unsigned nBytes = 0; bytes[0] = 0; /* first we just try to get a sequence of csv bytes */ while ( nBytes < sizeof(bytes) && tok < last_char ) { char* endPtr = (char*)tok; unsigned long val = strtoul(tok, &endPtr, 10); if ( val > 255 || endPtr == tok || ( *endPtr && *endPtr != ',' && endPtr != last_char ) ) { return FTPP_INVALID_ARG; } bytes[nBytes++] = (uint8_t)val; tok = (endPtr < last_char) ? endPtr + 1 : endPtr; } *ip_start = tok; /* now we check that the we have a valid sequence of */ /* bytes and convert the address and port accordingly */ switch ( bytes[0] ) { case 4: if ( nBytes != 9 || bytes[1] != 4 || bytes[6] != 2 ) return FTPP_INVALID_ARG; { uint32_t ip4_addr = 0; int n; for ( n = 0; n < 4; n++ ) ip4_addr = (ip4_addr << 8) | bytes[n+2]; /* don't call sfip_set_raw() on raw bytes to avoid possible word alignment issues */ ip4_addr = htonl(ip4_addr); sfip_set_raw(ipRet, (void*)&ip4_addr, AF_INET); } *portRet = (bytes[7] << 8) | bytes[8]; break; case 6: if ( nBytes != 21 || bytes[1] != 16 || bytes[18] != 2 ) return FTPP_INVALID_ARG; sfip_set_raw(ipRet, bytes+2, AF_INET6); *portRet = (bytes[19] << 8) | bytes[20]; break; default: return FTPP_INVALID_ARG; } return FTPP_SUCCESS; } /* * getIP2428() parses the EPRT command parameters which have this * format (ftyp == e_extd_host_port): * * EPRT ||address|| * EPRT |1|132.235.1.2|6275| * EPRT |2|1080::8:800:200C:417A|5282| * * Note that the address family is 1|2 (as in RFC 2428), not 4|6 * (as in IP version), nor 2|10 (as in AF_INET[6]). * * This function is called for the EPSV response as well, which * has this format (ftyp == e_int): * * 229 (||||) * * The delimiter may be other than '|' if required to represent * the protocol address, but must be between 33-126 inclusive. * Other delimiters aren't required for IPv{4,6} but we allow * them for flexibility. * * It is assumed that *ip_start points to the first delimiter in * both cases. */ /* * this copy is unfortunate but inet_pton() doesn't * like the delim and the src buf is const so ... */ void CopyField ( char* buf, const char* tok, int max, const char* end, char delim ) { int len = end - tok + 1; char* s; if ( len >= max ) { strncpy(buf, tok, max); buf[max-1] = '\0'; } else { strncpy(buf, tok, len); buf[len] = '\0'; } s = strchr(buf, delim); if ( s ) *s = '\0'; else *buf = '\0'; } static int getIP2428 ( const char **ip_start, const char *last_char, char *term_char, snort_ip* ipRet, uint16_t *portRet, FTP_PARAM_TYPE ftyp ) { const char* tok = *ip_start; char delim = *tok; int field = 1, fieldMask = 0; int family = AF_UNSPEC, port = 0; char buf[64]; IP_CLEAR((*ipRet)); *portRet = 0; /* check first delimiter */ if ( delim < 33 || delim > 126 ) return FTPP_INVALID_ARG; while ( tok && tok < last_char && field < 4 ) { int check = (*++tok != delim) ? field : 0; switch ( check ) { case 0: /* empty */ break; case 1: /* check family */ family = atoi(tok); if ( family == 1 ) family = AF_INET; else if ( family == 2 ) family = AF_INET6; else return FTPP_INVALID_ARG; fieldMask |= 1; break; case 2: /* check address */ CopyField(buf, tok, sizeof(buf), last_char, delim); if ( sfip_pton(buf, ipRet) != SFIP_SUCCESS || family != ipRet->family ) return FTPP_INVALID_ARG; fieldMask |= 2; break; case 3: /* check port */ port = atoi(tok); if ( port < 0 || port > MAXPORTS-1 ) return FTPP_MALFORMED_IP_PORT; *portRet = port; fieldMask |= 4; break; } /* advance to next field */ tok = strchr(tok, delim); field++; } if (tok) { if ( *tok == delim ) tok++; *ip_start = tok; } else { *ip_start = last_char; } if ( ftyp == e_int && fieldMask == 4 ) /* TBD: do we need to check for bounce if addr present? */ return FTPP_SUCCESS; if ( ftyp == e_extd_host_port && fieldMask == 7 ) return FTPP_SUCCESS; return FTPP_INVALID_ARG; } static int getFTPip( FTP_PARAM_TYPE ftyp, const char **ip_start, const char *last_char, char *term_char, snort_ip *ipRet, uint16_t *portRet ) { if ( ftyp == e_host_port ) { return getIP959(ip_start, last_char, term_char, ipRet, portRet); } if ( ftyp == e_long_host_port ) { return getIP1639(ip_start, last_char, term_char, ipRet, portRet); } return getIP2428(ip_start, last_char, term_char, ipRet, portRet, ftyp); } /* * Function: validate_date_format( * FTP_DATE_FMT *ThisFmt, * char **this_param) * * Purpose: Recursively determines whether a date matches the * a valid format. * * Arguments: ThisFmt => Pointer to the current format * this_param => Pointer to start of the portion to validate. * Updated to end of valid section if valid. * * Returns: int => return code indicating error or success * */ static int validate_date_format(FTP_DATE_FMT *ThisFmt, const char **this_param) { int valid_string = 0; int checked_something_else = 0; int checked_next = 0; int iRet = FTPP_ALERT; const char *curr_ch; if (!ThisFmt) return FTPP_INVALID_ARG; if (!this_param || !(*this_param)) return FTPP_INVALID_ARG; curr_ch = *this_param; if (!ThisFmt->empty) { char *format_char = ThisFmt->format_string; do { switch (*format_char) { case 'n': if (!isdigit((int)(*curr_ch))) { /* Return for non-digit */ return FTPP_INVALID_DATE; } curr_ch++; format_char++; break; case 'C': if (!isalpha((int)(*curr_ch))) { /* Return for non-char */ return FTPP_INVALID_DATE; } curr_ch++; format_char++; break; default: if (*curr_ch != *format_char) { /* Return for non-matching char */ return FTPP_INVALID_DATE; } curr_ch++; format_char++; break; } valid_string = 1; } while ((*format_char != '\0') && !isspace((int)(*curr_ch))); if ((*format_char != '\0') && isspace((int)(*curr_ch))) { /* Didn't have enough chars to complete this format */ return FTPP_INVALID_DATE; } } if ((ThisFmt->optional) && !isspace((int)(*curr_ch))) { const char *tmp_ch = curr_ch; iRet = validate_date_format(ThisFmt->optional, &tmp_ch); if (iRet == FTPP_SUCCESS) curr_ch = tmp_ch; } if ((ThisFmt->next_a) && !isspace((int)(*curr_ch))) { const char *tmp_ch = curr_ch; checked_something_else = 1; iRet = validate_date_format(ThisFmt->next_a, &tmp_ch); if (iRet == FTPP_SUCCESS) { curr_ch = tmp_ch; } else if (ThisFmt->next_b) { iRet = validate_date_format(ThisFmt->next_b, &tmp_ch); if (iRet == FTPP_SUCCESS) curr_ch = tmp_ch; } if (ThisFmt->next) { iRet = validate_date_format(ThisFmt->next, &tmp_ch); if (iRet == FTPP_SUCCESS) { curr_ch = tmp_ch; checked_next = 1; } } if (iRet == FTPP_SUCCESS) { *this_param = curr_ch; return iRet; } } if ((!checked_next) && (ThisFmt->next)) { const char *tmp_ch = curr_ch; checked_something_else = 1; iRet = validate_date_format(ThisFmt->next, &tmp_ch); if (iRet == FTPP_SUCCESS) { curr_ch = tmp_ch; checked_next = 1; } } if ((isspace((int)(*curr_ch))) && ((!ThisFmt->next) || checked_next)) { *this_param = curr_ch; return FTPP_SUCCESS; } if (valid_string) { int all_okay = 0; if (checked_something_else) { if (iRet == FTPP_SUCCESS) all_okay = 1; } else { all_okay = 1; } if (all_okay) { *this_param = curr_ch; return FTPP_SUCCESS; } } return FTPP_INVALID_DATE; } /* * Function: validate_param( * Packet *p * char *param * char *end * FTP_PARAM_FMT *param_format, * FTP_SESSION *Session) * * Purpose: Validates the current parameter against the format * specified. * * Arguments: p => Pointer to the current packet * params_begin => Pointer to beginning of parameters * params_end => End of params buffer * param_format => Parameter format specifier for this command * Session => Pointer to the session info * * Returns: int => return code indicating error or success * */ static int validate_param(SFSnortPacket *p, const char *param, const char *end, FTP_PARAM_FMT *ThisFmt, FTP_SESSION *Session) { int iRet; const char *this_param = param; if (param > end) return FTPP_ALERT; switch (ThisFmt->type) { case e_head: /* shouldn't get here, but just in case */ /* this hack is because we do get here! */ this_param--; break; case e_unrestricted: /* strings/filenames only occur as the last param, * so move to the end of the param buffer. */ this_param = end; break; case e_strformat: /* Check for 2 % signs within the parameter for an FTP command * 2 % signs is the magic number per existing rules (24 Sep 2004) */ #define MAX_PERCENT_SIGNS 2 { int numPercents = 0; do { if (*this_param == '%') { numPercents++; if (numPercents >= MAX_PERCENT_SIGNS) { break; } } this_param++; } while ((this_param < end) && (*this_param != '\n')); if (numPercents >= MAX_PERCENT_SIGNS) { /* Alert on string format attack in parameter */ ftp_eo_event_log(Session, FTP_EO_PARAMETER_STR_FORMAT, NULL, NULL); return FTPP_ALERTED; } } break; case e_int: /* check that this_param is all digits up to next space */ { do { if (!isdigit((int)(*this_param))) { /* Alert on non-digit */ return FTPP_INVALID_PARAM; } this_param++; } while ((this_param < end) && (*this_param != ' ') ); } break; case e_number: /* check that this_param is all digits up to next space * and value is between 1 & 255 */ { int iValue = 0; do { if (!isdigit((int)(*this_param))) { /* Alert on non-digit */ return FTPP_INVALID_PARAM; } iValue = iValue * 10 + (*this_param - '0'); this_param++; } while ((this_param < end) && (*this_param != ' ') ); if ((iValue > 255) || (iValue == 0)) return FTPP_INVALID_PARAM; } break; case e_char: /* check that this_param is one of chars specified */ { int bitNum = (*this_param & 0x1f); if (!isalpha((int)(*this_param))) { /* Alert on non-char */ return FTPP_INVALID_PARAM; } else { if (!(ThisFmt->format.chars_allowed & (1 << (bitNum-1))) ) { /* Alert on unexpected char */ return FTPP_INVALID_PARAM; } } this_param++; /* should be a space */ } break; case e_date: /* check that this_param conforms to date specified */ { const char *tmp_ch = this_param; iRet = validate_date_format(ThisFmt->format.date_fmt, &tmp_ch); if (iRet != FTPP_SUCCESS) { /* Alert invalid date */ return FTPP_INVALID_PARAM; } if (!isspace((int)(*tmp_ch))) { /* Alert invalid date -- didn't make it to end of parameter. Overflow attempt? */ return FTPP_INVALID_PARAM; } this_param = tmp_ch; } break; case e_literal: /* check that this_param matches the literal specified */ { const char* s = ThisFmt->format.literal; size_t n = strlen(s); if ( strncmp(this_param, s, n) ) { /* Alert on non-char */ return FTPP_INVALID_PARAM; } this_param += n; } break; /* check that this_param is: */ case e_host_port: /* PORT: h1,h2,h3,h4,p1,p2 */ case e_long_host_port: /* LPRT: af,hal,h1,h2,h3,h4...,pal,p1,p2... */ case e_extd_host_port: /* EPRT: |||| */ { snort_ip ipAddr; uint16_t port=0; int ret = getFTPip( ThisFmt->type, &this_param, end, " \n", &ipAddr, &port ); switch (ret) { case FTPP_NON_DIGIT: /* Alert on non-digit */ return FTPP_INVALID_PARAM; break; case FTPP_INVALID_ARG: /* Alert on number > 255 */ return FTPP_INVALID_PARAM; break; case FTPP_MALFORMED_IP_PORT: /* Alert on malformed host-port */ return FTPP_INVALID_PARAM; break; } if ( ThisFmt->type == e_extd_host_port && !IP_IS_SET(ipAddr) ) { // actually, we expect no addr in 229 responses, which is // understood to be server address, so we set that here ipAddr = *GET_SRC_IP(p); } if ((Session->client_conf->bounce.on) && (Session->client_conf->bounce.alert)) { if (!IP_EQUALITY(&ipAddr, GET_SRC_IP(p))) { int alert = 1; FTP_BOUNCE_TO *BounceTo = ftp_bounce_lookup_find( Session->client_conf->bounce_lookup, (snort_ip_p)IP_ARG(ipAddr), &iRet); if (BounceTo) { if (BounceTo->portlo) { if (BounceTo->porthi) { if ((port >= BounceTo->portlo) && (port <= BounceTo->porthi)) alert = 0; } else { if (port == BounceTo->portlo) alert = 0; } } } /* Alert on invalid IP address for PORT */ if (alert) { ftp_eo_event_log(Session, FTP_EO_BOUNCE, NULL, NULL); /* Return here -- because we will likely want to * inspect the data traffic over a bounced data * connection */ return FTPP_PORT_ATTACK; } } } Session->clientIP = ipAddr; Session->clientPort = port; Session->data_chan_state |= DATA_CHAN_PORT_CMD_ISSUED; if (Session->data_chan_state & DATA_CHAN_PASV_CMD_ISSUED) { /* * If there was a PORT command previously in * a series of pipelined requests, this * cancels it. */ Session->data_chan_state &= ~DATA_CHAN_PASV_CMD_ISSUED; } IP_CLEAR(Session->serverIP); Session->serverPort = 0; } break; } ThisFmt->next_param = this_param; return FTPP_SUCCESS; } /* * Function: check_ftp_param_validity( * Packet *p, * char *params_begin, * char *params_end, * FTP_PARAM_FMT *param_format, * FTP_SESSION *Session) * * Purpose: Recursively determines whether each of the parameters for * an FTP command are valid. * * Arguments: p => Pointer to the current packet * params_begin => Pointer to beginning of parameters * params_end => End of params buffer * param_format => Parameter format specifier for this command * Session => Pointer to the session info * * Returns: int => return code indicating error or success * */ static int check_ftp_param_validity(SFSnortPacket *p, const char *params_begin, const char *params_end, FTP_PARAM_FMT *param_format, FTP_SESSION *Session) { int iRet = FTPP_ALERT; FTP_PARAM_FMT *ThisFmt = param_format; FTP_PARAM_FMT *NextFmt; const char *this_param = params_begin; if (!param_format) return FTPP_INVALID_ARG; if (!params_begin && !ThisFmt->next_param_fmt && ThisFmt->optional_fmt) return FTPP_SUCCESS; /* no param is allowed in this case */ if (!params_begin && (ThisFmt->next_param_fmt && ThisFmt->next_param_fmt->type == e_strformat)) return FTPP_SUCCESS; /* string format check of non existent param */ if (!params_begin) return FTPP_INVALID_ARG; if ((!ThisFmt->next_param_fmt) && (params_begin >= params_end)) return FTPP_SUCCESS; ThisFmt->next_param = params_begin; if (ThisFmt->optional_fmt) { /* Check against optional */ iRet = validate_param(p, this_param, params_end, ThisFmt->optional_fmt, Session); if (iRet == FTPP_SUCCESS) { const char *next_param; NextFmt = ThisFmt->optional_fmt; next_param = NextFmt->next_param+1; iRet = check_ftp_param_validity(p, next_param, params_end, NextFmt, Session); if (iRet == FTPP_SUCCESS) { this_param = NextFmt->next_param+1; } } } if ((iRet != FTPP_SUCCESS) && (ThisFmt->choices)) { /* Check against choices -- one of many */ int i; int valid = 0; for (i=0;inumChoices && !valid;i++) { /* Try choice [i] */ iRet = validate_param(p, this_param, params_end, ThisFmt->choices[i], Session); if (iRet == FTPP_SUCCESS) { const char *next_param; NextFmt = ThisFmt->choices[i]; next_param = NextFmt->next_param+1; iRet = check_ftp_param_validity(p, next_param, params_end, NextFmt, Session); if (iRet == FTPP_SUCCESS) { this_param = NextFmt->next_param+1; valid = 1; break; } } } } else if ((iRet != FTPP_SUCCESS) && (ThisFmt->next_param_fmt)) { /* Check against next param */ iRet = validate_param(p, this_param, params_end, ThisFmt->next_param_fmt, Session); if (iRet == FTPP_SUCCESS) { const char *next_param; NextFmt = ThisFmt->next_param_fmt; next_param = NextFmt->next_param+1; iRet = check_ftp_param_validity(p, next_param, params_end, NextFmt, Session); if (iRet == FTPP_SUCCESS) { this_param = NextFmt->next_param+1; } } } else if ((iRet != FTPP_SUCCESS) && (!ThisFmt->next_param_fmt) && this_param) { iRet = FTPP_SUCCESS; } if (iRet == FTPP_SUCCESS) { ThisFmt->next_param = this_param; } return iRet; } /* * Function: initialize_ftp(FTP_SESSION *Session, Packet *p, int iMode) * * Purpose: Initializes the state machine for checking an FTP packet. * Does normalization checks. * * Arguments: Session => Pointer to session info * p => pointer to the current packet struct * iMode => Mode indicating server or client checks * * Returns: int => return code indicating error or success * */ int initialize_ftp(FTP_SESSION *Session, SFSnortPacket *p, int iMode) { int iRet; const unsigned char *read_ptr = p->payload; FTP_CLIENT_REQ *req; char ignoreTelnetErase = FTPP_APPLY_TNC_ERASE_CMDS; FTPTELNET_GLOBAL_CONF *global_conf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(Session->global_conf, Session->policy_id); /* Normalize this packet ala telnet */ if (((iMode == FTPP_SI_CLIENT_MODE) && (Session->client_conf->ignore_telnet_erase_cmds.on == 1)) || ((iMode == FTPP_SI_SERVER_MODE) && (Session->server_conf->ignore_telnet_erase_cmds.on == 1)) ) ignoreTelnetErase = FTPP_IGNORE_TNC_ERASE_CMDS; iRet = normalize_telnet(global_conf, NULL, p, iMode, ignoreTelnetErase); if (iRet != FTPP_SUCCESS && iRet != FTPP_NORMALIZED) { if (iRet == FTPP_ALERT) { if (global_conf->telnet_config->detect_anomalies) { ftp_eo_event_log(Session, FTP_EO_EVASIVE_TELNET_CMD, NULL, NULL); } } return iRet; } if (_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE)) { /* Normalized data will always be in decode buffer */ if ( ((Session->client_conf->telnet_cmds.alert) && (iMode == FTPP_SI_CLIENT_MODE)) || ((Session->server_conf->telnet_cmds.alert) && (iMode == FTPP_SI_SERVER_MODE)) ) { /* alert -- FTP channel with telnet commands */ ftp_eo_event_log(Session, FTP_EO_TELNET_CMD, NULL, NULL); return FTPP_ALERT; /* Nothing else to do since we alerted */ } read_ptr = _dpd.altBuffer->data; } if (iMode == FTPP_SI_CLIENT_MODE) req = &Session->client.request; else if (iMode == FTPP_SI_SERVER_MODE) { FTP_SERVER_RSP *rsp = &Session->server.response; req = (FTP_CLIENT_REQ *)rsp; } else return FTPP_INVALID_ARG; /* Set the beginning of the pipeline to the start of the * (normalized) buffer */ req->pipeline_req = (const char *)read_ptr; return FTPP_SUCCESS; } /* * Function: do_stateful_checks(FTP_SESSION *Session, Packet *p, * FTP_CLIENT_REQ *req, int rsp_code) * * Purpose: Handle stateful checks and state updates for FTP response * packets. * * Arguments: Session => Pointer to session info * p => Pointer to the current packet struct * req => Pointer to current response from packet * (this function may be called multiple * times for pipelined requests). * rsp_code => Integer response value for server response * * Returns: int => return code indicating error or success * */ static int do_stateful_checks(FTP_SESSION *Session, SFSnortPacket *p, FTP_CLIENT_REQ *req, int rsp_code) { int iRet = FTPP_SUCCESS; FTPTELNET_GLOBAL_CONF *global_conf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(Session->global_conf, Session->policy_id); //if (Session->server_conf->data_chan) { if (rsp_code == 226) { /* Just ignore this code -- end of transfer... * If we saw all the other dat for this channel * Session->data_chan_state should be NO_STATE. */ } else if (Session->data_chan_state & DATA_CHAN_PASV_CMD_ISSUED) { if (ftp_cmd_pipe_index == Session->data_chan_index) { if (Session->data_xfer_index == -1) ftp_cmd_pipe_index = 0; Session->data_chan_index = -1; if ( rsp_code >= 227 && rsp_code <= 229 ) { snort_ip ipAddr; uint16_t port=0; const char *ip_begin = req->param_begin; IP_CLEAR(ipAddr); Session->data_chan_state &= ~DATA_CHAN_PASV_CMD_ISSUED; Session->data_chan_state |= DATA_CHAN_PASV_CMD_ACCEPT; Session->data_chan_index = -1; /* Interpret response message to identify the * Server IP/Port. Server response is inside * a pair of ()s. Find the left (, and use same * means to find IP/Port as is done for the PORT * command. */ if (req->param_size != 0) { while ((ip_begin < req->param_end) && (*ip_begin != '(')) { ip_begin++; } } if (ip_begin < req->param_end) { FTP_PARAM_TYPE ftyp = /* e_int is used in lieu of adding a new value to the * enum because this case doesn't correspond to a * validation config option; it could effectively be * replaced with an additional bool arg to getFTPip() that * differentiated between commands and responses, but * this distinction is only required for EPSV rsps. */ (rsp_code == 229) ? e_int : (rsp_code == 228 ? e_long_host_port : e_host_port); ip_begin++; iRet = getFTPip( ftyp, &ip_begin, req->param_end, ")", &ipAddr, &port ); if (iRet == FTPP_SUCCESS) { if (!IP_IS_SET(ipAddr)) IP_COPY_VALUE(Session->serverIP, GET_SRC_IP(p)); else { Session->serverIP = ipAddr; } Session->serverPort = port; IP_COPY_VALUE(Session->clientIP, GET_DST_IP(p)); Session->clientPort = 0; #ifdef TARGET_BASED if ((_dpd.fileAPI->get_max_file_depth() > 0) || !(Session->server_conf->data_chan)) { FTP_DATA_SESSION *ftpdata = FTPDataSessionNew(p); if (ftpdata) { int result; /* This is a passive data transfer */ ftpdata->mode = FTPP_XFER_PASSIVE; ftpdata->data_chan = Session->server_conf->data_chan; /* Call into Streams to mark data channel as ftp-data */ result = _dpd.streamAPI->set_application_protocol_id_expected( IP_ARG(Session->clientIP), Session->clientPort, IP_ARG(Session->serverIP), Session->serverPort, (uint8_t)(GET_IPH_PROTO(p)), p->pkt_header->ts.tv_sec, ftp_data_app_id, PP_FTPTELNET, (void *)ftpdata, &FTPDataSessionFree); if (result < 0) FTPDataSessionFree(ftpdata); } } else if (Session->server_conf->data_chan) #else if (Session->server_conf->data_chan) #endif { /* Call into Streams to mark data channel as something * to ignore. */ _dpd.streamAPI->ignore_session(IP_ARG(Session->clientIP), Session->clientPort, IP_ARG(Session->serverIP), Session->serverPort, (uint8_t)(GET_IPH_PROTO(p)), p->pkt_header->ts.tv_sec, PP_FTPTELNET, SSN_DIR_BOTH, 0 /* Not permanent */ ); } } } else { iRet = FTPP_MALFORMED_FTP_RESPONSE; } } else { Session->data_chan_index = -1; Session->data_chan_state &= ~DATA_CHAN_PASV_CMD_ISSUED; } } } else if (Session->data_chan_state & DATA_CHAN_PORT_CMD_ISSUED) { if (ftp_cmd_pipe_index == Session->data_chan_index) { if (Session->data_xfer_index == -1) ftp_cmd_pipe_index = 0; Session->data_chan_index = -1; if (rsp_code == 200) { Session->data_chan_state &= ~DATA_CHAN_PORT_CMD_ISSUED; Session->data_chan_state |= DATA_CHAN_PORT_CMD_ACCEPT; Session->data_chan_index = -1; if (IP_IS_SET(Session->clientIP)) { /* This means we're not in passive mode. */ /* Server is listening/sending from its own IP, * FTP Port -1 */ /* Client IP, Port specified via PORT command */ IP_COPY_VALUE(Session->serverIP, GET_SRC_IP(p)); /* Can't necessarily guarantee this, especially * in the case of a proxy'd connection where the * data channel might not be on port 20 (or server * port-1). Comment it out for now. */ /* Session->serverPort = ntohs(p->tcph->th_sport) -1; */ #ifdef TARGET_BASED if ((_dpd.fileAPI->get_max_file_depth() > 0) || !(Session->server_conf->data_chan)) { FTP_DATA_SESSION *ftpdata = FTPDataSessionNew(p); if (ftpdata) { int result; /* This is a active data transfer */ ftpdata->mode = FTPP_XFER_ACTIVE; ftpdata->data_chan = Session->server_conf->data_chan; /* Call into Streams to mark data channel as ftp-data */ result = _dpd.streamAPI->set_application_protocol_id_expected( IP_ARG(Session->clientIP), Session->clientPort, IP_ARG(Session->serverIP), Session->serverPort, (uint8_t)(GET_IPH_PROTO(p)), p->pkt_header->ts.tv_sec, ftp_data_app_id, PP_FTPTELNET, (void *)ftpdata, &FTPDataSessionFree); if (result < 0) FTPDataSessionFree(ftpdata); } } else if (Session->server_conf->data_chan) #else if (Session->server_conf->data_chan) #endif { /* Call into Streams to mark data channel as something * to ignore. */ _dpd.streamAPI->ignore_session(IP_ARG(Session->clientIP), Session->clientPort, IP_ARG(Session->serverIP), Session->serverPort, (uint8_t)(GET_IPH_PROTO(p)), p->pkt_header->ts.tv_sec, PP_FTPTELNET, SSN_DIR_BOTH, 0 /* Not permanent */ ); } } } else if (ftp_cmd_pipe_index == Session->data_chan_index) { Session->data_chan_index = -1; Session->data_chan_state &= ~DATA_CHAN_PORT_CMD_ISSUED; } } } else if (Session->data_chan_state & DATA_CHAN_XFER_CMD_ISSUED) { if (ftp_cmd_pipe_index == Session->data_xfer_index) { if (Session->data_chan_index == -1) ftp_cmd_pipe_index = 0; Session->data_xfer_index = -1; if ((rsp_code == 150) || (rsp_code == 125)) { Session->data_chan_state &= ~DATA_CHAN_XFER_CMD_ISSUED; Session->data_chan_state = DATA_CHAN_XFER_STARTED; } /* Clear the session info for next transfer --> * reset host/port */ IP_CLEAR(Session->serverIP); IP_CLEAR(Session->clientIP); Session->serverPort = Session->clientPort = 0; Session->data_chan_state = NO_STATE; } } } /* if (Session->server_conf->data_chan) */ if (global_conf->encrypted.on) { switch(Session->encr_state) { case AUTH_TLS_CMD_ISSUED: if (rsp_code == 234) { /* Could check that response msg includes "TLS" */ Session->encr_state = AUTH_TLS_ENCRYPTED; if (global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(Session, FTP_EO_ENCRYPTED, NULL, NULL); } DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP stream is now TLS encrypted\n");); } break; case AUTH_SSL_CMD_ISSUED: if (rsp_code == 234) { /* Could check that response msg includes "SSL" */ Session->encr_state = AUTH_SSL_ENCRYPTED; if (global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(Session, FTP_EO_ENCRYPTED, NULL, NULL); } DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP stream is now SSL encrypted\n");); } break; case AUTH_UNKNOWN_CMD_ISSUED: if (rsp_code == 234) { Session->encr_state = AUTH_UNKNOWN_ENCRYPTED; if (global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(Session, FTP_EO_ENCRYPTED, NULL, NULL); } DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP stream is now encrypted\n");); } break; } } /* if (global_conf->encrypted.on) */ return iRet; } /* * Function: check_ftp(FTP_SESSION *Session, Packet *p, int iMode) * * Purpose: Handle some trivial validation checks of an FTP packet. Namely, * check argument length and some protocol enforcement. * * Wishful: This results in exposing the FTP command (and looking * at the results) to the rules layer. * * Arguments: Session => Pointer to session info * p => pointer to the current packet struct * iMode => Mode indicating server or client checks * * Returns: int => return code indicating error or success * */ #define NUL 0x00 #define CR 0x0d #define LF 0x0a #define SP 0x20 #define DASH 0x2D #define FTP_CMD_OK 0 #define FTP_CMD_INV 1 #define FTP_RESPONSE_INV 1 #define FTP_RESPONSE 2 #define FTP_RESPONSE_2BCONT 2 #define FTP_RESPONSE_CONT 3 #define FTP_RESPONSE_ENDCONT 4 int check_ftp(FTP_SESSION *ftpssn, SFSnortPacket *p, int iMode) { int iRet = FTPP_SUCCESS; int encrypted = 0; int space = 0; long state = FTP_CMD_OK; int rsp_code = 0; FTPTELNET_GLOBAL_CONF *global_conf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(ftpssn->global_conf, ftpssn->policy_id); FTP_CLIENT_REQ *req; FTP_CMD_CONF *CmdConf = NULL; const unsigned char *read_ptr; const unsigned char *end = p->payload + p->payload_size; if (_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE)) end = _dpd.altBuffer->data + _dpd.altBuffer->len; if (iMode == FTPP_SI_CLIENT_MODE) { req = &ftpssn->client.request; ftp_cmd_pipe_index = 0; } else if (iMode == FTPP_SI_SERVER_MODE) { FTP_SERVER_RSP *rsp = &ftpssn->server.response; req = (FTP_CLIENT_REQ *)rsp; } else return FTPP_INVALID_ARG; while (req->pipeline_req) { state = FTP_CMD_OK; /* Starts at the beginning of the buffer/line, * so next up is a command */ read_ptr = (const unsigned char *)req->pipeline_req; /* but first we ignore leading white space */ while ( (read_ptr < end) && (iMode == FTPP_SI_CLIENT_MODE) && isspace(*read_ptr) ) read_ptr++; // ignore extra \r\n emitted by some clients if ( read_ptr == end ) break; req->cmd_begin = (const char *)read_ptr; while ((read_ptr < end) && (*read_ptr != SP) && (*read_ptr != CR) && (*read_ptr != LF) && /* Check for LF when there wasn't a CR, * protocol violation, but accepted by * some servers. */ (*read_ptr != DASH)) { /* If the first char is a digit this is a response * in server mode. */ if (iMode == FTPP_SI_SERVER_MODE) { if (isdigit(*read_ptr)) { if (state != FTP_RESPONSE_INV) { state = FTP_RESPONSE; } } else if (!isascii(*read_ptr)) { /* Non-ascii char here? Bad response */ state = FTP_RESPONSE_INV; } } /* Or, if this is not a char, this is garbage in client mode */ else if (!isalpha(*read_ptr) && (iMode == FTPP_SI_CLIENT_MODE)) { state = FTP_CMD_INV; } read_ptr++; } req->cmd_end = (const char *)read_ptr; req->cmd_size = req->cmd_end - req->cmd_begin; if (iMode == FTPP_SI_CLIENT_MODE) { if ( (req->cmd_size > ftpssn->server_conf->max_cmd_len) || (req->cmd_size < MIN_CMD) || (state == FTP_CMD_INV) ) { /* Uh, something is very wrong... * nonalpha char seen or cmd is bad length. * See if this might be encrypted, ie, non-alpha bytes. */ const unsigned char *ptr = (const unsigned char *)req->cmd_begin; while (ptr < (const unsigned char *)req->cmd_end) { if (!isalpha((int)(*ptr))) { if (!isascii((int)(*ptr)) || !isprint((int)(*ptr))) { encrypted = 1; } break; } ptr++; } } if (encrypted) { /* If the session wasn't already marked as encrypted... * Don't want to double-alert if we've already * determined the session is encrypted and we're * checking encrypted sessions. */ if (ftpssn->encr_state == 0) { ftpssn->encr_state = AUTH_UNKNOWN_ENCRYPTED; if (global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(ftpssn, FTP_EO_ENCRYPTED, NULL, NULL); } if (!global_conf->check_encrypted_data) { /* Mark this session & packet as one to ignore */ _dpd.streamAPI->stop_inspection(p->stream_session_ptr, p, SSN_DIR_BOTH, -1, 0); } DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP client stream is now encrypted\n");); } break; } else { /* * Check the list of valid FTP commands as * supplied in ftpssn. */ if ( req->cmd_size > ftpssn->server_conf->max_cmd_len ) { /* Alert, cmd not found */ ftp_eo_event_log(ftpssn, FTP_EO_INVALID_CMD, NULL, NULL); state = FTP_CMD_INV; } else { CmdConf = ftp_cmd_lookup_find(ftpssn->server_conf->cmd_lookup, req->cmd_begin, req->cmd_size, &iRet); if ((iRet == FTPP_NOT_FOUND) || (CmdConf == NULL)) { /* Alert, cmd not found */ ftp_eo_event_log(ftpssn, FTP_EO_INVALID_CMD, NULL, NULL); state = FTP_CMD_INV; } else { /* In case we were encrypted, but aren't now */ ftpssn->encr_state = 0; } } } } else if (iMode == FTPP_SI_SERVER_MODE) { if (state == FTP_CMD_INV) state = FTP_RESPONSE_INV; if ( (req->cmd_size != 3) || (state == FTP_RESPONSE_INV) ) { /* Uh, something is very wrong... * nondigit char seen or resp code is not 3 chars. * See if this might be encrypted, ie, non-alpha bytes. */ const char *ptr = req->cmd_begin; while (ptr < req->cmd_end) { if (!isdigit((int)(*ptr))) { if (!isascii((int)(*ptr)) || !isprint((int)(*ptr))) { encrypted = 1; } break; } ptr++; } } if (encrypted) { /* If the session wasn't already marked as encrypted... * Don't want to double-alert if we've already * determined the session is encrypted and we're * checking encrypted sessions. */ if (ftpssn->encr_state == 0) { ftpssn->encr_state = AUTH_UNKNOWN_ENCRYPTED; if (global_conf->encrypted.alert) { /* Alert on encrypted channel */ ftp_eo_event_log(ftpssn, FTP_EO_ENCRYPTED, NULL, NULL); } if (!global_conf->check_encrypted_data) { /* Mark this session & packet as one to ignore */ _dpd.streamAPI->stop_inspection(p->stream_session_ptr, p, SSN_DIR_BOTH, -1, 0); } DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP server stream is now encrypted\n");); } break; } else { /* In case we were encrypted, but aren't now */ if ((ftpssn->encr_state == AUTH_TLS_ENCRYPTED) || (ftpssn->encr_state == AUTH_SSL_ENCRYPTED) || (ftpssn->encr_state == AUTH_UNKNOWN_ENCRYPTED)) { ftpssn->encr_state = 0; } /* Otherwise, might have an encryption command pending */ } if (read_ptr < end) { if (*read_ptr != DASH) { const unsigned char *resp_begin = (const unsigned char *)req->cmd_begin; const unsigned char *resp_end = (const unsigned char *)req->cmd_end; if (resp_end - resp_begin >= 3) { if (isdigit(*(resp_begin)) && isdigit(*(resp_begin+1)) && isdigit(*(resp_begin+2)) ) { rsp_code = ( (*(resp_begin) - '0') * 100 + (*(resp_begin+1) - '0') * 10 + (*(resp_begin+2) - '0') ); if (rsp_code == ftpssn->server.response.state) { /* End of continued response */ state = FTP_RESPONSE_ENDCONT; ftpssn->server.response.state = 0; } else { /* Single line response */ state = FTP_RESPONSE; } } } if (ftpssn->server.response.state != 0) { req->cmd_begin = NULL; req->cmd_end = NULL; if (*read_ptr != SP) read_ptr--; state = FTP_RESPONSE_CONT; } } else if ((state == FTP_RESPONSE) && (*read_ptr == DASH)) { const unsigned char *resp_begin = (const unsigned char *)req->cmd_begin; if (isdigit(*(resp_begin)) && isdigit(*(resp_begin+1)) && isdigit(*(resp_begin+2)) ) { int resp_code = ( (*(resp_begin) - '0') * 100 + (*(resp_begin+1) - '0') * 10 + (*(resp_begin+2) - '0') ); if (resp_code == ftpssn->server.response.state) { /* Continuation of previous response */ state = FTP_RESPONSE_CONT; } else { /* Start of response, state stays as -2 */ state = FTP_RESPONSE_2BCONT; ftpssn->server.response.state = resp_code; rsp_code = resp_code; } } else { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "invalid FTP response code.");); ftpssn->server.response.state = FTP_RESPONSE_INV; } } } } if (read_ptr < end) { if (*read_ptr == SP) { space = 1; } read_ptr++; /* Move past the space, dash, or CR */ } /* If there is anything left... */ if (read_ptr < end) { /* Look for an LF --> implies no parameters/message */ if (*read_ptr == LF) { read_ptr++; req->param_begin = NULL; req->param_end = NULL; } else if (!space && ftpssn->server.response.state == 0) { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Missing LF from end of FTP command\n");); } else { /* Now grab the command parameters/response message * read_ptr < end already checked */ req->param_begin = (const char *)read_ptr; if ((read_ptr = memchr(read_ptr, CR, end - read_ptr)) == NULL) read_ptr = end; req->param_end = (const char *)read_ptr; read_ptr++; if (read_ptr < end) { /* Cool, got the end of the parameters, move past * the LF, so we can process the next one in * the pipeline. */ if (*read_ptr == LF) { read_ptr++; } else { DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Missing LF from end of FTP command with params\n");); } } } } else { /* Nothing left --> no parameters/message. Not even an LF */ req->param_begin = NULL; req->param_end = NULL; DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Missing LF from end of FTP command sans params\n");); } /* Set the pointer for the next request/response * in the pipeline. */ if (read_ptr < end) req->pipeline_req = (const char *)read_ptr; else req->pipeline_req = NULL; req->param_size = req->param_end - req->param_begin; switch (state) { case FTP_CMD_INV: DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Illegal FTP command found: %.*s\n", req->cmd_size, req->cmd_begin)); iRet = FTPP_ALERT; break; case FTP_RESPONSE: /* Response */ DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP response: code: %.*s : M len %d : M %.*s\n", req->cmd_size, req->cmd_begin, req->param_size, req->param_size, req->param_begin)); if ((ftpssn->client_conf->max_resp_len > 0) && (req->param_size > ftpssn->client_conf->max_resp_len)) { /* Alert on response message overflow */ ftp_eo_event_log(ftpssn, FTP_EO_RESPONSE_LENGTH_OVERFLOW, NULL, NULL); iRet = FTPP_ALERT; } if (global_conf->inspection_type == FTPP_UI_CONFIG_STATEFUL) { int newRet = do_stateful_checks(ftpssn, p, req, rsp_code); if (newRet != FTPP_SUCCESS) iRet = newRet; } break; case FTP_RESPONSE_CONT: /* Response continued */ DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP response: continuation of code: %d : M len %d : M %.*s\n", ftpssn->server.response.state, req->param_size, req->param_size, req->param_begin)); if ((ftpssn->client_conf->max_resp_len > 0) && (req->param_size > ftpssn->client_conf->max_resp_len)) { /* Alert on response message overflow */ ftp_eo_event_log(ftpssn, FTP_EO_RESPONSE_LENGTH_OVERFLOW, NULL, NULL); iRet = FTPP_ALERT; } break; case FTP_RESPONSE_ENDCONT: /* Continued response end */ DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP response: final continue of code: %.*s : M len %d : " "M %.*s\n", req->cmd_size, req->cmd_begin, req->param_size, req->param_size, req->param_begin)); if ((ftpssn->client_conf->max_resp_len > 0) && (req->param_size > ftpssn->client_conf->max_resp_len)) { /* Alert on response message overflow */ ftp_eo_event_log(ftpssn, FTP_EO_RESPONSE_LENGTH_OVERFLOW, NULL, NULL); iRet = FTPP_ALERT; } break; default: DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP command: CMD: %.*s : " "P len %d : P %.*s\n", req->cmd_size, req->cmd_begin, req->param_size, req->param_size, req->param_begin)); if (CmdConf) { if ((req->param_size > CmdConf->max_param_len)) { /* Alert on param length overrun */ ftp_eo_event_log(ftpssn, FTP_EO_PARAMETER_LENGTH_OVERFLOW, NULL, NULL); DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP command: %.*s" "parameter length overrun %d > %d \n", req->cmd_size, req->cmd_begin, req->param_size, CmdConf->max_param_len)); iRet = FTPP_ALERT; break; } if (CmdConf->data_chan_cmd) { ftpssn->data_chan_state |= DATA_CHAN_PASV_CMD_ISSUED; ftpssn->data_chan_index = ftp_cmd_pipe_index; if (ftpssn->data_chan_state & DATA_CHAN_PORT_CMD_ISSUED) { /* * If there was a PORT command previously in * a series of pipelined requests, this * cancels it. */ ftpssn->data_chan_state &= ~DATA_CHAN_PORT_CMD_ISSUED; } } else if (CmdConf->data_xfer_cmd) { #ifdef TARGET_BASED /* If we are not ignoring the data channel OR file processing is enabled */ if (!ftpssn->server_conf->data_chan || (_dpd.fileAPI->get_max_file_depth() > -1)) { /* The following check cleans up filename for failed data * transfers. If the transfer had been successful the * filename pointer would have been handed off to the * FTP_DATA_SESSION for tracking. */ if (ftpssn->filename) { free(ftpssn->filename); ftpssn->filename = NULL; ftpssn->file_xfer_info = FTPP_FILE_IGNORE; } // Get the file name and set direction of the get/put request. // Request could have been sent without parameters, i.e. filename, // so make sure something is there. if (((req->param_begin != NULL) && (req->param_size > 0)) && (CmdConf->file_get_cmd || CmdConf->file_put_cmd)) { ftpssn->filename = (char *)malloc(req->param_size+1); if (ftpssn->filename) { memcpy(ftpssn->filename, req->param_begin, req->param_size); ftpssn->filename[req->param_size] = '\0'; ftpssn->file_xfer_info = req->param_size; } // 0 for Download, 1 for Upload ftpssn->data_xfer_dir = CmdConf->file_get_cmd ? false : true; } else { ftpssn->file_xfer_info = FTPP_FILE_IGNORE; } } #endif ftpssn->data_chan_state |= DATA_CHAN_XFER_CMD_ISSUED; ftpssn->data_xfer_index = ftp_cmd_pipe_index; } else if (CmdConf->encr_cmd) { if (req->param_begin && (req->param_size > 0) && ((req->param_begin[0] == 'T') || (req->param_begin[0] == 't'))) { ftpssn->encr_state = AUTH_TLS_CMD_ISSUED; } else if (req->param_begin && (req->param_size > 0) && ((req->param_begin[0] == 'S') || (req->param_begin[0] == 's'))) { ftpssn->encr_state = AUTH_SSL_CMD_ISSUED; } else { ftpssn->encr_state = AUTH_UNKNOWN_CMD_ISSUED; } } if (CmdConf->check_validity) { iRet = check_ftp_param_validity(p, req->param_begin, req->param_end, CmdConf->param_format, ftpssn); /* If negative, haven't already alerted on violation */ if (iRet < 0) { /* Set Alert on malformatted parameter */ ftp_eo_event_log(ftpssn, FTP_EO_MALFORMED_PARAMETER, NULL, NULL); iRet = FTPP_ALERT; break; } else if (iRet > 0) { /* Already alerted -- ie, string format attack. */ break; } } } break; } if (iMode == FTPP_SI_CLIENT_MODE) ftp_cmd_pipe_index++; else if ((rsp_code != 226) && (rsp_code != 426)) { /* * In terms of counting responses, ignore * 226 response saying transfer complete * 426 response saying transfer aborted * The 226 may or may not be sent by the server. * Both are 2nd response to a transfer command. */ ftp_cmd_pipe_index++; } } if (iMode == FTPP_SI_CLIENT_MODE) { ftp_cmd_pipe_index = 0; } if (encrypted) return FTPP_ALERT; return iRet; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/hi_util_xmalloc.h0000644000000000000000000000222612260565732022410 00000000000000/* * util.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * */ #ifndef __HI_UTIL_XMALLOC_H__ #define __HI_UTIL_XMALLOC_H__ #ifdef WIN32 #define snprintf _snprintf #else #include #endif void *xmalloc(size_t byteSize); char *xstrdup(const char *str); void xshowmem(void); void xfree( void * ); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/hi_util_xmalloc.c0000644000000000000000000000445312260565732022407 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /* ** util.c */ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif //#define MDEBUG static unsigned msize=0; void * xmalloc(size_t byteSize) { #ifdef MDEBUG int * data = (int*) malloc( byteSize + 4 ); unsigned m = msize; if(data)memset(data,0,byteSize+4); #else int * data = (int*) malloc( byteSize ); if(data)memset(data,0,byteSize); #endif if( data == NULL ) { return NULL; } #ifdef MDEBUG msize += byteSize + 4; *data = byteSize+4; //printf("** xmalloc msize=%u, allocbytes=%d, msize=%u %x\n", m, byteSize+4, msize, data); data++; return data; #else msize += byteSize; return data; #endif } void xfree( void * p ) { #ifdef MDEBUG unsigned m = msize; int *q = (int*)p; q--; msize -= *q; free(q); #else free(p); #endif } void xshowmem(void) { #ifdef MDEBUG printf("xmalloc-mem: %u bytes\n",msize); #endif } char *xstrdup(const char *str) { int data_size; char *data = NULL; data_size = strlen(str) + 1; data = (char *)xmalloc(data_size); if(data == NULL) { return NULL; } strncpy(data, str, data_size - 1); data[data_size - 1] = '\0'; return data; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/hi_util_kmap.h0000644000000000000000000000444112260565732021702 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /* * kmap.h * * Keyword Trie based Map Table * * Author: Marc Norton * */ #ifndef KTRIE_H #define KTRIE_H #define ALPHABET_SIZE 256 /* * */ typedef struct _keynode { struct _keynode * next; unsigned char * key; int nkey; void * userdata; /* data associated with this pattern */ } KEYNODE; /* * */ typedef struct _kmapnode { int nodechar; /* node character */ struct _kmapnode * sibling; struct _kmapnode * child; KEYNODE * knode; } KMAPNODE; /* * */ typedef void (*KMapUserFreeFunc)(void *p); typedef struct _kmap { KMAPNODE * root[256]; /* KTrie nodes */ KEYNODE * keylist; // list of key+data pairs KEYNODE * keynext; // findfirst/findnext node KMapUserFreeFunc userfree; // fcn to free user data int nchars; // # character nodes int nocase; } KMAP; /* * PROTOTYPES */ KMAP * KMapNew ( KMapUserFreeFunc userfree ); void KMapSetNoCase( KMAP * km, int flag ); int KMapAdd ( KMAP * km, void * key, int ksize, void * userdata ); void * KMapFind( KMAP * km, void * key, int ksize ); void * KMapFindFirst( KMAP * km ); void * KMapFindNext ( KMAP * km ); KEYNODE * KMapFindFirstKey( KMAP * km ); KEYNODE * KMapFindNextKey ( KMAP * km ); void KMapDelete(KMAP *km); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/hi_util_kmap.c0000644000000000000000000002705312260565732021701 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /* * * kmap.c - a generic map library - maps key + data pairs * * Uses Lexical Keyword Trie * The tree uses linked lists to build the finite automata * * MapKeyFind(): Performs a setwise strcmp() equivalant. * * Notes: * * Keys may be ascii or binary, both may be of random sizes. * Each key may be a different size, or all one size. * Fast dictionary lookup, proportional to the length of the key, * and independent of the number of keys in the table. * May use more memory than a hash table, depends. * Memory is allocated as needed, so none is wasted. * * Author: Marc Norton * */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_util_kmap.h" #include "hi_util_xmalloc.h" //#define MEMASSERT(p) if(!p){printf("KMAP-No Memory: File: %s Line:%d!\n",__FILE__,__LINE__);exit(0);} #define MEMASSERT(p) #define LOWERCASE tolower /* * */ static void * s_malloc( int n ) { void * p; p = xmalloc( n ); MEMASSERT(p); return p; } /* * */ static void s_free( void * p ) { if( p ) xfree( p ); } /* * */ KMAP * KMapNew( KMapUserFreeFunc userfree ) { KMAP * km = (KMAP*) s_malloc( sizeof(KMAP) ); if( !km ) return 0; memset(km, 0, sizeof(KMAP)); km->userfree = userfree; return km; } /* * */ void KMapSetNoCase( KMAP * km, int flag ) { km->nocase = flag; } /* * Free the list of key+data pair nodes - used by findfirst/next */ static int KMapFreeNodeList(KMAP * km ) { KEYNODE * k, *kold; for( k=km->keylist; k; ) { if( k->key ) { s_free( k->key ); } if( km->userfree && k->userdata ) { km->userfree( k->userdata ); } kold = k; k = k->next; s_free(kold); } return 0; } /* * Recursively walk and free nodes */ static void KMapFreeNode( KMAP * km, KMAPNODE * r) { if( r->sibling ) { KMapFreeNode( km, r->sibling ); } if( r->child ) { KMapFreeNode( km, r->child ); } s_free( r ); } /* * Free the KMAP and all of it's memory and nodes */ void KMapDelete( KMAP * km ) { KMAPNODE * r; int i; /* Free the tree - on root node at a time */ for(i=0;i<256;i++) { r = km->root[i]; if( r ) { KMapFreeNode(km,r); } } /* Free the node list */ KMapFreeNodeList( km ); s_free(km); } /* * Add key + data pair to the linked list of nodes */ static KEYNODE * KMapAddKeyNode(KMAP * km,void * key, int n, void * userdata ) { KEYNODE * knode; if (n <= 0) return 0; knode = (KEYNODE*) s_malloc( sizeof(KEYNODE) ); if (!knode) return 0; memset(knode, 0, sizeof(KEYNODE) ); knode->key = (unsigned char*)s_malloc(n); // Alloc the key space if( !knode->key ) { free(knode); return 0; } memcpy(knode->key,key,n); // Copy the key knode->nkey = n; knode->userdata = userdata; if( km->keylist ) // Insert at front of list { knode->next = km->keylist; km->keylist = knode; } else { km->keylist = knode; } return knode; } /* * Create a character node */ static KMAPNODE * KMapCreateNode(KMAP * km) { KMAPNODE * mn=(KMAPNODE*)s_malloc( sizeof(KMAPNODE) ); if(!mn) return NULL; memset(mn,0,sizeof(KMAPNODE)); km->nchars++; return mn; } /* * key : ptr to bytes of data used to identify this item * may be text string, or binary character sequence. * n : > 0 number of bytes in the key * <=0 key is a null terminated ascii string * userdata - ptr to data to associate with this key * * returns: * -1 - no memory * 1 - key already in table * 0 - key added successfully */ int KMapAdd( KMAP *km, void * key, int n, void * userdata ) { int i,ksize; int type = 0; unsigned char *P = (unsigned char *)key; KMAPNODE *root; unsigned char xkey[256]; if( n <= 0 ) { n = strlen( (char*) key ); if( n > (int)sizeof(xkey) ) return -99; } if( km->nocase ) { for(i=0;iroot[ *P ] ) { root = KMapCreateNode(km); if( !root ) return -1; km->root[ *P ] = root; root->nodechar = *P; }else{ root = km->root[ *P ]; } /* Walk exisitng Patterns */ while( n ) { if( root->nodechar == *P ) { //printf("matched char = %c, nleft = %d\n",*P,n-1); P++; n--; if( n && root->child ) { root=root->child; } else /* cannot continue */ { type = 0; /* Expand the tree via the child */ break; } } else { if( root->sibling ) { root=root->sibling; } else /* cannot continue */ { type = 1; /* Expand the tree via the sibling */ break; } } } /* * Add the next char of the Keyword, if any */ if( n ) { if( type == 0 ) { /* * Start with a new child to finish this Keyword */ //printf("added child branch nodechar = %c \n",*P); root->child= KMapCreateNode( km ); if( !root->child ) return -1; root=root->child; root->nodechar = *P; P++; n--; } else { /* * Start a new sibling bracnch to finish this Keyword */ //printf("added sibling branch nodechar = %c \n",*P); root->sibling= KMapCreateNode( km ); if( !root->sibling ) return -1; root=root->sibling; root->nodechar = *P; P++; n--; } } /* * Finish the keyword as child nodes */ while( n ) { //printf("added child nodechar = %c \n",*P); root->child = KMapCreateNode(km); if( !root->child ) return -1; root=root->child; root->nodechar = *P; P++; n--; } /* * Iteration support - Add this key/data to the linked list * This allows us to do a findfirst/findnext search of * all map nodes. */ if( root->knode ) /* Already present */ return 1; root->knode = KMapAddKeyNode( km, key, ksize, userdata ); if( !root->knode ) return -1; return 0; } /* * Exact Keyword Match - unique keys, with just one piece of * 'userdata' , for multiple entries, we could use a list * of 'userdata' nodes. */ void * KMapFind( KMAP * ks, void * key, int n ) { unsigned char * T = (unsigned char *)key; KMAPNODE * root; unsigned char xkey[256]; int i; if( n <= 0 ) { n = strlen( (char*)key ); if( n > (int)sizeof(xkey) ) return 0; } if( ks->nocase ) { for(i=0;iroot[ *T ]; if( !root ) return NULL; while( n ) { if( root->nodechar == *T ) { T++; n--; if( n && root->child ) { root = root->child; } else /* cannot continue -- match is over */ { break; } } else { if( root->sibling ) { root = root->sibling; } else /* cannot continue */ { break; } } } if( !n ) { if (root && root->knode) return root->knode->userdata; /* success */ } return NULL; } /* * */ KEYNODE * KMapFindFirstKey( KMAP * km ) { km->keynext = km->keylist; if(!km->keynext) { return NULL; } return km->keynext; } /* * */ void * KMapFindFirst( KMAP * km ) { km->keynext = km->keylist; if(!km->keynext) { return NULL; } return km->keynext->userdata; } /* * */ KEYNODE * KMapFindNextKey( KMAP * km ) { if( !km->keynext ) return 0; km->keynext = km->keynext->next; if( !km->keynext ) return 0; return km->keynext; } /* * */ void * KMapFindNext( KMAP * km ) { if( !km->keynext ) return 0; km->keynext = km->keynext->next; if( !km->keynext ) return 0; return km->keynext->userdata; } #ifdef KMAP_MAIN /* * */ int main( int argc, char ** argv ) { int i,n=10; KMAP * km; char * p; char str[80]; str[79] = '\0'; printf("usage: kmap nkeys (default=10)\n\n"); km = KMapNew( free ); /* use 'free' to free 'userdata' */ KMapSetNoCase(km,1); //need to add xlat.... if( argc > 1 ) { n = atoi(argv[1]); } for(i=1;i<=n;i++) { snprintf(str, sizeof(str) - 1, "KeyWord%d",i); KMapAdd( km, str, 0 /* strlen(str) */, strupr(strdup(str)) ); printf("Adding Key=%s\n",str); } printf("xmem: %u bytes, %d chars\n",xmalloc_bytes(),km->nchars); printf("\nKey Find test...\n"); for(i=1;i<=n;i++) { snprintf(str, sizeof(str) - 1, "KeyWord%d",i); p = (char*) KMapFind( km, str, 0 /*strlen(str) */ ); if(p)printf("key=%s, data=%*s\n",str,strlen(str),p); else printf("'%s' NOT found.\n",str); } KMapSetNoCase(km,0); // this should fail all key searches printf("\nKey Find test2...\n"); for(i=1;i<=n;i++) { snprintf(str, sizeof(str) - 1, "KeyWord%d",i); p = (char*) KMapFind( km, str, 0 /*strlen(str) */ ); if(p)printf("key=%s, data=%*s\n",str,strlen(str),p); else printf("'%s' NOT found.\n",str); } printf("\nKey FindFirst/Next test...\n"); for(p = (char*) KMapFindFirst(km); p; p=(char*)KMapFindNext(km) ) printf("data=%s\n",p); printf("\nKey FindFirst/Next test done.\n"); KMapDelete( km ); printf("xmem: %u bytes\n",xmalloc_bytes()); printf("normal pgm finish.\n"); return 0; } #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftp_server.h0000644000000000000000000000337112260565732021415 00000000000000/* * ftp_server.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * Header file for FTPTelnet FTP Server Module * * This file defines the server structure and functions to access server * inspection. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __FTP_SERVER_H__ #define __FTP_SERVER_H__ #include "ftpp_include.h" typedef struct s_FTP_SERVER_RSP { char *rsp_line; unsigned int rsp_line_size; char *rsp_begin; char *rsp_end; unsigned int rsp_size; char *msg_begin; char *msg_end; unsigned int msg_size; char *pipeline_req; int state; } FTP_SERVER_RSP; typedef struct s_FTP_SERVER { FTP_SERVER_RSP response; } FTP_SERVER; int ftp_server_inspection(void *S, unsigned char *data, int dsize); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_ui_server_lookup.h0000644000000000000000000000347712260565732023672 00000000000000/* * ftpp_ui_server_lookup.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains function definitions for server lookups. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __FTPP_UI_SERVER_LOOKUP_H__ #define __FTPP_UI_SERVER_LOOKUP_H__ #include "ftpp_include.h" #include "ftpp_ui_config.h" int ftpp_ui_server_lookup_init(SERVER_LOOKUP **ServerLookup); int ftpp_ui_server_lookup_cleanup(SERVER_LOOKUP **ServerLookup); int ftpp_ui_server_lookup_add(SERVER_LOOKUP *ServerLookup, sfip_t *IP, FTP_SERVER_PROTO_CONF *ServerConf); FTP_SERVER_PROTO_CONF *ftpp_ui_server_lookup_find(SERVER_LOOKUP *ServerLookup, snort_ip_p Ip, int *iError); int ftpp_ui_server_iterate( struct _SnortConfig *, SERVER_LOOKUP *ServerLookup, sfrt_sc_iterator_callback3 userfunc, int *iError ); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_ui_server_lookup.c0000644000000000000000000002215012260565732023652 00000000000000/* * ftpp_ui_server_lookup.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains functions to access the SERVER_LOOKUP structure. * * We wrap the access to SERVER_LOOKUP so changing the lookup algorithms * are more modular and independent. This is the only file that would need * to be changed to change the algorithmic lookup. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_util_kmap.h" #include "ftpp_ui_config.h" #include "ftpp_return_codes.h" #include "snort_ftptelnet.h" static void serverConfFree(void *pData); /* * Function: ftpp_ui_server_lookup_init(SERVER_LOOKUP **ServerLookup) * * Purpose: Initialize the server_lookup structure. * * We need to initialize the server_lookup structure for * the FTP server configuration. Don't want a NULL pointer * flying around, when we have to look for server configs. * * Arguments: ServerLookup => pointer to the pointer of the server * lookup structure. * * Returns: int => return code indicating error or success * */ #define FTPP_UI_CONFIG_MAX_SERVERS 20 int ftpp_ui_server_lookup_init(SERVER_LOOKUP **ServerLookup) { *ServerLookup = sfrt_new(DIR_16_4x4_16x5_4x4, IPv6, FTPP_UI_CONFIG_MAX_SERVERS, 20); if(*ServerLookup == NULL) { return FTPP_MEM_ALLOC_FAIL; } return FTPP_SUCCESS; } /* * Function: ftpp_ui_server_lookup_cleanup(SERVER_LOOKUP **ServerLookup) * * Purpose: Free the server_lookup structure. * We need to free the server_lookup structure. * * Arguments: ServerLookup => pointer to the pointer of the server * lookup structure. * * Returns: int => return code indicating error or success * */ int ftpp_ui_server_lookup_cleanup(SERVER_LOOKUP **ServerLookup) { if ((ServerLookup == NULL) || (*ServerLookup == NULL)) return FTPP_INVALID_ARG; sfrt_cleanup(*ServerLookup, serverConfFree); sfrt_free(*ServerLookup); *ServerLookup = NULL; return FTPP_SUCCESS; } /* * Function: ftpp_ui_server_lookup_add(SERVER_LOOKUP *ServerLookup, * char *ip, int len, * FTP_SERVER_PROTO_CONF *ServerConf) * * Purpose: Add a server configuration to the list. * We add these keys like you would normally think to add * them, because on low endian machines the least significant * byte is compared first. This is what we want to compare * IPs backward, doesn't work on high endian machines, but oh * well. Our platform is Intel. * * Arguments: ServerLookup => a pointer to the lookup structure * IP => the ftp server address * len => Length of the address * ServerConf => a pointer to the server configuration structure * * Returns: int => return code indicating error or success * */ int ftpp_ui_server_lookup_add( SERVER_LOOKUP *ServerLookup, sfip_t* Ip, FTP_SERVER_PROTO_CONF *ServerConf ) { int iRet; if(!ServerLookup || !ServerConf) { return FTPP_INVALID_ARG; } iRet = sfrt_insert((void *)Ip, (unsigned char)Ip->bits, (void *)ServerConf, RT_FAVOR_SPECIFIC, ServerLookup); if (iRet) { return FTPP_MEM_ALLOC_FAIL; } return FTPP_SUCCESS; } /* * Function: ftpp_ui_server_lookup_find(SERVER_LOOKUP *ServerLookup, * snort_ip_p ip, int *iError) * * Purpose: Find a server configuration given a IP. * We look up a server configuration given an IP and * return a pointer to that server configuration if found. * * Arguments: ServerLookup => a pointer to the lookup structure * IP => the ftp server address * iError => a pointer to an error code * * Returns: int => return code indicating error or success * * Returns: FTP_SERVER_PROTO_CONF* => Pointer to server configuration * structure matching IP if found, NULL otherwise. * */ FTP_SERVER_PROTO_CONF *ftpp_ui_server_lookup_find( SERVER_LOOKUP *ServerLookup, snort_ip_p Ip, int *iError ) { FTP_SERVER_PROTO_CONF *ServerConf = NULL; if(!iError) { return NULL; } if(!ServerLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; ServerConf = (FTP_SERVER_PROTO_CONF *)sfrt_lookup((void *)Ip, ServerLookup); if (!ServerConf) { *iError = FTPP_NOT_FOUND; } return ServerConf; } /**Iterate over all the stored IP addresses, calling the callback for * all elements. * * @param ServerLookup => a pointer to the lookup structure * @param userfunc => user defined callback function * @param iError => a pointer to an error code * * @returns iError => return code indicating error or success * */ int ftpp_ui_server_iterate( struct _SnortConfig *sc, SERVER_LOOKUP *ServerLookup, sfrt_sc_iterator_callback3 userfunc, int *iError ) { if(!iError) { return 0; } if(!ServerLookup) { *iError = FTPP_INVALID_ARG; return 0; } *iError = FTPP_SUCCESS; return sfrt_iterate2_with_snort_config(sc, ServerLookup, userfunc); } #if 0 /** Obsoleted. After changing underlying KMAP to SFRT. SFRT provides an iterator with * a callback function but does not support getFirst, getNext operations. */ /* * Function: ftpp_ui_server_lookup_first(SERVER_LOOKUP *ServerLookup, * int *iError) * * Purpose: This lookups the first server configuration, so we can * iterate through the configurations. * * Arguments: ServerLookup => pointer to the server lookup structure * iError => pointer to the integer to set for errors * * Returns: FTP_SERVER_PROTO_CONF* => Pointer to first server * configuration structure * */ FTP_SERVER_PROTO_CONF *ftpp_ui_server_lookup_first(SERVER_LOOKUP *ServerLookup, int *iError) { FTP_SERVER_PROTO_CONF *ServerConf; if(!iError) { return NULL; } if(!ServerLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; ServerConf = (FTP_SERVER_PROTO_CONF *)KMapFindFirst(ServerLookup); if (!ServerConf) { *iError = FTPP_NOT_FOUND; } return ServerConf; } /* * Function: ftpp_ui_server_lookup_next(SERVER_LOOKUP *ServerLookup, * int *iError) * * Iterates to the next configuration, like a list it just returns * the next config in the config list. * * Purpose: This lookups the next server configuration, so we can * iterate through the configurations. * * Arguments: ServerLookup => pointer to the server lookup structure * iError => pointer to the integer to set for errors * * Returns: FTP_SERVER_PROTO_CONF* => Pointer to next server configuration * structure * */ FTP_SERVER_PROTO_CONF *ftpp_ui_server_lookup_next(SERVER_LOOKUP *ServerLookup, int *iError) { FTP_SERVER_PROTO_CONF *ServerConf; if(!iError) { return NULL; } if(!ServerLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; ServerConf = (FTP_SERVER_PROTO_CONF *)KMapFindNext(ServerLookup); if (!ServerConf) { *iError = FTPP_NOT_FOUND; } return ServerConf; } #endif /**Free pData buffer, which may be referenced multiple times. ReferenceCount * is the number of times the buffer is referenced. For freeing the buffer, * we just decrement referenceCount till it reaches 0, at which time the * buffer is also freed. */ static void serverConfFree(void *pData) { FTP_SERVER_PROTO_CONF *serverConf = (FTP_SERVER_PROTO_CONF *)pData; if (serverConf) { serverConf->referenceCount--; if (serverConf->referenceCount == 0) { FTPTelnetCleanupFTPServerConf((void *)serverConf); free(serverConf); } } } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_ui_config.h0000644000000000000000000002325612260565732022235 00000000000000/* * ftpp_ui_config.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains the internal configuration structures * for FTPTelnet. * * This file holds the configuration constructs for the FTPTelnet global * configuration and the FTP client configurations. It also contains the * function prototypes for accessing client configurations. * * NOTES: * - 20.09.04: Initial Development. SAS */ #ifndef __FTPP_UI_CONFIG_H__ #define __FTPP_UI_CONFIG_H__ //#include "decode.h" #include "ftpp_include.h" #include "hi_util_kmap.h" #include "ipv6_port.h" #include "sfrt.h" #include "snort_bounds.h" /* * Defines */ #define FTPP_UI_CONFIG_STATELESS 0 #define FTPP_UI_CONFIG_STATEFUL 1 #define FTPP_UI_CONFIG_TELNET_DEF_AYT_THRESHOLD -1 #define FTPP_UI_CONFIG_FTP_DEF_RESP_MSG_MAX -1 #define FTPP_UI_CONFIG_FTP_DEF_CMD_PARAM_MAX 100 /**Maximum number of entries in server_lookup table. */ #define FTPP_UI_CONFIG_MAX_SERVERS 20 #define FTPP_UI_CONFIG_MAX_CLIENTS 20 #define MIN_CMD 3 #define MAX_CMD 4 /* * Defines a search type for the client configurations in the * global configuration. We want this generic so we can change * it easily if we change the search type. */ typedef table_t CLIENT_LOOKUP; typedef table_t SERVER_LOOKUP; typedef KMAP BOUNCE_LOOKUP; /* * Defines a search type for the FTP commands in the client * global configuration. We want this generic so we can change * it easily if we change the search type. */ typedef KMAP CMD_LOOKUP; /* * This structure simply holds a value for on/off and whether * alert is on/off. Should be used for many configure options. */ typedef struct s_FTPTELNET_CONF_OPT { int on; /*< if true, configuration option is on */ int alert; /*< if true, alert if option is found */ } FTPTELNET_CONF_OPT; typedef enum s_FTP_PARAM_TYPE { e_head = 0, e_unrestricted, /* The default */ e_strformat, e_int, e_number, e_char, e_date, e_literal, e_host_port, e_long_host_port, e_extd_host_port } FTP_PARAM_TYPE; /* * Some FTP servers accept MDTM commands to set the modification time * on a file. The most common are servers accept a format using * YYYYMMDDHHmmss[.uuu], while others accept a format using * YYYYMMDDHHmmss[+|-]TZ format. Because of this, the default syntax * below is for the first case (time format as specified in * http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16.txt) * * If you need to check validity for a server that uses the TZ format, * use the following: * * cmd_validity MDTM < [ date nnnnnnnnnnnnnn[{+|-}n[n]] ] string > * * Format uses the following: * n = digit * C = character * . = period (literal) * + = plus (literal) * - = minus (literal) * [ = optional begin * ] = optional end * { = OR begin * } = OR end * | = OR separator * * ie, nnnnnnnnnnnnnn[.n[n[n]]] --> * force conformance to YYYYMMDDHHmmss.uuu, * where 1,2, or 3 microsec digits are optional. * * ie, nnnnnnnnnnnnnn[{+|-}n[n]] --> * force conformance to YYYYMMDDHHmmss+TZ, * where optional +TZ is + or - one or two digit number */ typedef struct s_FTP_DATE_FMT { char *format_string; int empty; struct s_FTP_DATE_FMT *next; struct s_FTP_DATE_FMT *prev; struct s_FTP_DATE_FMT *optional; struct s_FTP_DATE_FMT *next_a; struct s_FTP_DATE_FMT *next_b; } FTP_DATE_FMT; typedef struct s_FTP_PARAM_FMT { FTP_PARAM_TYPE type; int optional; /* Format is only used for types listed below to specify * allowable values. Other types provide no variances * for the format. */ union u_FORMAT { uint32_t chars_allowed; /* For type == e_char */ FTP_DATE_FMT *date_fmt; /* For type == e_date */ char* literal; /* For type == e_literal */ } format; struct s_FTP_PARAM_FMT *prev_param_fmt; struct s_FTP_PARAM_FMT *next_param_fmt; struct s_FTP_PARAM_FMT *optional_fmt; struct s_FTP_PARAM_FMT **choices; int numChoices; int prev_optional; /* Only set if optional is set */ const char *next_param; /* Pointer to buffer for the next parameter. To be used to backtrack for optional parameters that don't match. */ } FTP_PARAM_FMT; typedef struct s_FTP_CMD_CONF { /* Maximum length for parameters for this cmd. * Default -1 is unlimited */ unsigned int max_param_len; int max_param_len_overridden; int check_validity; int data_chan_cmd; int data_xfer_cmd; int file_put_cmd; int file_get_cmd; int encr_cmd; int login_cmd; int dir_response; FTP_PARAM_FMT *param_format; char cmd_name[1]; // variable length array } FTP_CMD_CONF; typedef struct s_PROTO_CONF { unsigned int port_count; char ports[MAXPORTS]; } PROTO_CONF; /* * This is the configuration construct that holds the specific * options for a FTP server. Each unique server has it's own * structure and there is a global structure for servers that * don't have a unique configuration. */ typedef struct s_FTP_SERVER_PROTO_CONF { /* Ports must be first */ PROTO_CONF proto_ports; char *serverAddr; unsigned int def_max_param_len; unsigned int max_cmd_len; int print_commands; CMD_LOOKUP *cmd_lookup; FTPTELNET_CONF_OPT telnet_cmds; FTPTELNET_CONF_OPT ignore_telnet_erase_cmds; int data_chan; /**Counts references to this allocated data structure. Each additional * reference should increment referenceCount. Each attempted free should * decrement it. When reference count reaches 0, then this * data structure should be freed. */ int referenceCount; } FTP_SERVER_PROTO_CONF; typedef struct s_FTP_BOUNCE_TO { snort_ip ip; int relevant_bits; unsigned short portlo; unsigned short porthi; } FTP_BOUNCE_TO; /* * This is the configuration construct that holds the specific * options for a FTP client. Each unique client has it's own * structure and there is a global structure for clients that * don't have a unique configuration. */ typedef struct s_FTP_CLIENT_PROTO_CONF { char *clientAddr; unsigned int max_resp_len; int data_chan; FTPTELNET_CONF_OPT bounce; FTPTELNET_CONF_OPT telnet_cmds; FTPTELNET_CONF_OPT ignore_telnet_erase_cmds; /* allow_bounce to IP/mask port|port-range */ /* TODO: change this to use a quick find of IP/mask */ BOUNCE_LOOKUP *bounce_lookup; /**Counts references to this allocated data structure. Each additional * reference should increment referenceCount. Each attempted free should * decrement it. When reference count reaches 0, then this * data structure should be freed. */ int referenceCount; } FTP_CLIENT_PROTO_CONF; /* * This is the configuration construct that holds the specific * options for telnet. There is a global structure for all telnet * connections. */ typedef struct s_TELNET_PROTO_CONF { /* Ports must be first */ PROTO_CONF proto_ports; int normalize; int ayt_threshold; char detect_anomalies; } TELNET_PROTO_CONF; /* * This is the configuration for the global FTPTelnet * configuration. It contains the global aspects of the * configuration, a standard global default configuration, * and client configurations. */ typedef struct s_FTPTELNET_GLOBAL_CONF { int inspection_type; int check_encrypted_data; FTPTELNET_CONF_OPT encrypted; FTP_CLIENT_PROTO_CONF *default_ftp_client; FTP_SERVER_PROTO_CONF *default_ftp_server; TELNET_PROTO_CONF *telnet_config; SERVER_LOOKUP *server_lookup; CLIENT_LOOKUP *client_lookup; uint32_t ref_count; uint32_t xtra_filename_id; } FTPTELNET_GLOBAL_CONF; /* * Functions */ int ftpp_ui_config_init_global_conf(FTPTELNET_GLOBAL_CONF *GlobalConf); int ftpp_ui_config_default(FTPTELNET_GLOBAL_CONF *GlobalConf); int ftpp_ui_config_reset_global(FTPTELNET_GLOBAL_CONF *GlobalConf); int ftpp_ui_config_reset_ftp_client(FTP_CLIENT_PROTO_CONF *ClientConf, char first); int ftpp_ui_config_reset_ftp_server(FTP_SERVER_PROTO_CONF *ServerConf, char first); void ftpp_ui_config_reset_ftp_cmd_format(FTP_PARAM_FMT *ThisFmt); void ftpp_ui_config_reset_ftp_cmd_date_format(FTP_DATE_FMT *DateFmt); int ftpp_ui_config_reset_ftp_cmd(FTP_CMD_CONF *FTPCmd); int ftpp_ui_config_reset_telnet_proto(TELNET_PROTO_CONF *ClientConf); int ftpp_ui_config_add_ftp_client(FTPTELNET_GLOBAL_CONF *GlobalConf, sfip_t* ClientIP, FTP_CLIENT_PROTO_CONF *ClientConf); int ftpp_ui_config_add_ftp_server(FTPTELNET_GLOBAL_CONF *GlobalConf, sfip_t *ClientIP, FTP_SERVER_PROTO_CONF *ClientConf); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_ui_config.c0000644000000000000000000002712212260565732022224 00000000000000/* * ftpp_ui_config.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains library calls to configure FTPTelnet. * * This file deals with configuring FTPTelnet processing. It contains * routines to set a default configuration, add client configurations, etc. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #include #include #include #include #ifndef WIN32 #include #include #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "ftpp_return_codes.h" #include "ftpp_ui_client_lookup.h" #include "ftpp_ui_server_lookup.h" #include "ftp_cmd_lookup.h" #include "ftp_bounce_lookup.h" #include "ftpp_ui_config.h" /* * Function: ftpp_ui_config_init_global_conf(FTPTELNET_GLOBAL_CONF *GlobalConf) * * Purpose: Initialize the FTPTelnet global configuration. * The main point of this function is to initialize the client * lookup type. We also do things like memset, etc. * * Arguments: GlobalConf => pointer to the global configuration * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_init_global_conf(FTPTELNET_GLOBAL_CONF *GlobalConf) { int iRet; iRet = ftpp_ui_client_lookup_init(&GlobalConf->client_lookup); if (iRet) { return iRet; } iRet = ftpp_ui_server_lookup_init(&GlobalConf->server_lookup); if (iRet) { return iRet; } return FTPP_SUCCESS; } /* * Function: ftpp_ui_config_default(FTPTELNET_GLOBAL_CONF *GlobalConf) * * Purpose: This function sets the global and the global_client default * configuration. In order to change the default configuration * of FTPTelnet, you must change this function. * * Arguments: GlobalConf => pointer to the global configuration structure * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_default(FTPTELNET_GLOBAL_CONF *GlobalConf) { if(GlobalConf == NULL) { return FTPP_INVALID_ARG; } /* * Set Global Client Configurations */ ftpp_ui_config_reset_ftp_client(GlobalConf->default_ftp_client, 0); ftpp_ui_config_reset_ftp_server(GlobalConf->default_ftp_server, 0); ftpp_ui_config_reset_telnet_proto(GlobalConf->telnet_config); return FTPP_SUCCESS; } /* * Function: ftpp_ui_config_reset_global(FTPTELNET_GLOBAL_CONF *GlobalConf) * * Purpose: This function resets the global parameters. * THIS IS NOT THE GLOBAL FTP CLIENT CONFIGURATION. * * Arguments: GlobalConf => pointer to the global configuration structure * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_reset_global(FTPTELNET_GLOBAL_CONF *GlobalConf) { int iRet; /* Clean these up before mem setting */ ftp_bounce_lookup_cleanup(&GlobalConf->default_ftp_client->bounce_lookup); ftp_cmd_lookup_cleanup(&(GlobalConf->default_ftp_server->cmd_lookup)); ftpp_ui_client_lookup_cleanup(&GlobalConf->client_lookup); ftpp_ui_server_lookup_cleanup(&GlobalConf->server_lookup); memset(GlobalConf, 0x00, sizeof(FTPTELNET_GLOBAL_CONF)); iRet = ftpp_ui_client_lookup_init(&GlobalConf->client_lookup); if (iRet) { return iRet; } iRet = ftpp_ui_server_lookup_init(&GlobalConf->server_lookup); if (iRet) { return iRet; } return FTPP_SUCCESS; } /* * Function: ftpp_ui_config_reset_telnet_proto(TELNET_PROTO_CONF *TelnetConf) * * Purpose: This function resets a telnet construct. * * Arguments: TelnetConf => pointer to the TELNET_PROTO_CONF structure * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_reset_telnet_proto(TELNET_PROTO_CONF *TelnetConf) { memset(TelnetConf, 0x00, sizeof(TELNET_PROTO_CONF)); TelnetConf->ayt_threshold = FTPP_UI_CONFIG_TELNET_DEF_AYT_THRESHOLD; TelnetConf->proto_ports.port_count = 1; TelnetConf->proto_ports.ports[23] = 1; return FTPP_SUCCESS; } /* * Function: ftpp_ui_config_reset_ftp_cmd_date_format(FTP_DATE_FMT *DateFmt) * * Purpose: This function resets an FTP date parameter construct. * * Arguments: ThisFmt => pointer to the FTP_DATE_FMT structure * * Returns: void * */ void ftpp_ui_config_reset_ftp_cmd_date_format(FTP_DATE_FMT *DateFmt) { if (DateFmt->optional) { ftpp_ui_config_reset_ftp_cmd_date_format(DateFmt->optional); } if (DateFmt->next) { ftpp_ui_config_reset_ftp_cmd_date_format(DateFmt->next); } if (DateFmt->format_string) { free(DateFmt->format_string); } free(DateFmt); } /* * Function: ftpp_ui_config_reset_ftp_cmd_format(FTP_PARAM_FMT *ThisFmt) * * Purpose: This function resets an FTP parameter construct. * * Arguments: ThisFmt => pointer to the FTP_PARAM_FMT structure * * Returns: void * */ void ftpp_ui_config_reset_ftp_cmd_format(FTP_PARAM_FMT *ThisFmt) { if (ThisFmt->optional_fmt) { ftpp_ui_config_reset_ftp_cmd_format(ThisFmt->optional_fmt); } if (ThisFmt->numChoices) { int i; for (i=0;inumChoices;i++) { ftpp_ui_config_reset_ftp_cmd_format(ThisFmt->choices[i]); } free(ThisFmt->choices); } if (ThisFmt->next_param_fmt) { /* Don't free this one twice if its after an optional */ FTP_PARAM_FMT *next = ThisFmt->next_param_fmt; ThisFmt->next_param_fmt->prev_param_fmt->next_param_fmt = NULL; ThisFmt->next_param_fmt = NULL; ftpp_ui_config_reset_ftp_cmd_format(next); } if (ThisFmt->type == e_date) { ftpp_ui_config_reset_ftp_cmd_date_format(ThisFmt->format.date_fmt); } if (ThisFmt->type == e_literal) { free (ThisFmt->format.literal); } memset(ThisFmt, 0, sizeof(FTP_PARAM_FMT)); free(ThisFmt); } /* * Function: ftpp_ui_config_reset_ftp_cmd(FTP_CMD_CONF *FTPCmd) * * Purpose: This function resets a FTP command construct. * * Arguments: FTPCmd => pointer to the FTP_CMD_CONF structure * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_reset_ftp_cmd(FTP_CMD_CONF *FTPCmd) { FTP_PARAM_FMT *NextCmdFormat = FTPCmd->param_format; if (NextCmdFormat) { ftpp_ui_config_reset_ftp_cmd_format(NextCmdFormat); } return FTPP_SUCCESS; } /* * Function: ftpp_ui_config_reset_ftp_server(FTP_SERVER_PROTO_CONF *ServerConf, * char first) * * Purpose: This function resets a ftp server construct. * * Arguments: ServerConf => pointer to the FTP_SERVER_PROTO_CONF structure * first => indicator whether this is a new conf * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_reset_ftp_server(FTP_SERVER_PROTO_CONF *ServerConf, char first) { int iRet = FTPP_SUCCESS; if (first == 0) { ftp_cmd_lookup_cleanup(&ServerConf->cmd_lookup); } if (ServerConf->serverAddr) { free(ServerConf->serverAddr); } memset(ServerConf, 0x00, sizeof(FTP_SERVER_PROTO_CONF)); ServerConf->proto_ports.port_count = 1; ServerConf->proto_ports.ports[21] = 1; ftp_cmd_lookup_init(&ServerConf->cmd_lookup); ServerConf->def_max_param_len = FTPP_UI_CONFIG_FTP_DEF_CMD_PARAM_MAX; ServerConf->max_cmd_len = MAX_CMD; return iRet; } /* * Function: ftpp_ui_config_add_ftp_server( * FTPTELNET_GLOBAL_CONF *GlobalConf, * unsigned long ServerIP, * FTP_SERVER_PROTO_CONF *ServerConf) * * Purpose: Add a server config to the FTPTelnet configuration. * This function takes an IP address of a server and an FTP * Server configuration, and assigns the configuration to * the IP address in a lookup table. * * Arguments: GlobalConf => pointer to the global configuration * ServerIp => the IP address of the server * ServerConf => pointer to the server configuration * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_add_ftp_server(FTPTELNET_GLOBAL_CONF *GlobalConf, sfip_t * ServerIP, FTP_SERVER_PROTO_CONF *ServerConf) { int iRet; iRet = ftpp_ui_server_lookup_add(GlobalConf->server_lookup, ServerIP, ServerConf); if (iRet) { /* * Already added key will return a generic non-fatal * error. */ return iRet; } return FTPP_SUCCESS; } /* * Function: ftpp_ui_config_reset_ftp_client(FTP_CLIENT_PROTO_CONF *ClientConf, * char first) * * Purpose: This function resets a ftp client construct. * * Arguments: ClientConf => pointer to the FTP_CLIENT_PROTO_CONF structure * first => indicator whether this is a new conf * * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_reset_ftp_client(FTP_CLIENT_PROTO_CONF *ClientConf, char first) { int iRet = FTPP_SUCCESS; //FTP_BOUNCE_TO *NextBounceTo = NULL; if (first == 0) { ftp_bounce_lookup_cleanup(&ClientConf->bounce_lookup); } if (ClientConf->clientAddr) { free(ClientConf->clientAddr); } memset(ClientConf, 0x00, sizeof(FTP_CLIENT_PROTO_CONF)); ftp_bounce_lookup_init(&ClientConf->bounce_lookup); ClientConf->max_resp_len = (unsigned int)FTPP_UI_CONFIG_FTP_DEF_RESP_MSG_MAX; return iRet; } /* * Function: ftpp_ui_config_add_ftp_client( * FTPTELNET_GLOBAL_CONF *GlobalConf, * unsigned long ClientIP, * FTP_SERVER_PROTO_CONF *ClientConf) * * Purpose: Add a client config to the FTPTelnet configuration. * This function takes an IP address of a client and an FTP * Client configuration, and assigns the configuration to * the IP address in a lookup table. * * Arguments: GlobalConf => pointer to the global configuration * ClientIP => the IP address of the client * ClientConf => pointer to the client configuration * * Returns: int => return code indicating error or success * */ int ftpp_ui_config_add_ftp_client(FTPTELNET_GLOBAL_CONF *GlobalConf, sfip_t * ClientIP, FTP_CLIENT_PROTO_CONF *ClientConf) { int iRet; iRet = ftpp_ui_client_lookup_add(GlobalConf->client_lookup, ClientIP, ClientConf); if (iRet) { /* * Already added key will return a generic non-fatal * error. */ return iRet; } return FTPP_SUCCESS; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_ui_client_lookup.h0000644000000000000000000000402612260565732023631 00000000000000/* * ftpp_ui_client_lookup.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains function definitions for client lookups. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __FTPP_UI_CLIENT_LOOKUP_H__ #define __FTPP_UI_CLIENT_LOOKUP_H__ #include "ftpp_include.h" #include "ftpp_ui_config.h" int ftpp_ui_client_lookup_init(CLIENT_LOOKUP **ClientLookup); int ftpp_ui_client_lookup_cleanup(CLIENT_LOOKUP **ClientLookup); int ftpp_ui_client_lookup_add(CLIENT_LOOKUP *ClientLookup, sfip_t * IP, FTP_CLIENT_PROTO_CONF *ClientConf); FTP_CLIENT_PROTO_CONF *ftpp_ui_client_lookup_find(CLIENT_LOOKUP *ClientLookup, snort_ip_p Ip, int *iError); FTP_CLIENT_PROTO_CONF *ftpp_ui_client_lookup_first(CLIENT_LOOKUP *ClientLookup, int *iError); FTP_CLIENT_PROTO_CONF *ftpp_ui_client_lookup_next(CLIENT_LOOKUP *ClientLookup, int *iError); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_ui_client_lookup.c0000644000000000000000000002126412260565732023627 00000000000000/* * ftpp_ui_client_lookup.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains functions to access the CLIENT_LOOKUP structure. * * We wrap the access to CLIENT_LOOKUP so changing the lookup algorithms * are more modular and independent. This is the only file that would need * to be changed to change the algorithmic lookup. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_util_kmap.h" #include "ftpp_ui_config.h" #include "ftpp_return_codes.h" #include "snort_ftptelnet.h" #include "sfrt.h" static void clientConfFree(void *pData); /* * Function: ftpp_ui_client_lookup_init(CLIENT_LOOKUP **ClientLookup) * * Purpose: Initialize the client_lookup structure. * * We need to initialize the client_lookup structure for * the FTP client configuration. Don't want a NULL pointer * flying around, when we have to look for FTP clients. * * Arguments: ClientLookup => pointer to the pointer of the client * lookup structure. * * Returns: int => return code indicating error or success * */ #define FTPP_UI_CONFIG_MAX_CLIENTS 20 int ftpp_ui_client_lookup_init(CLIENT_LOOKUP **ClientLookup) { *ClientLookup = sfrt_new(DIR_16_4x4_16x5_4x4, IPv6, FTPP_UI_CONFIG_MAX_CLIENTS, 20); if(*ClientLookup == NULL) { return FTPP_MEM_ALLOC_FAIL; } return FTPP_SUCCESS; } /* * Function: ftpp_ui_client_lookup_cleanup(CLIENT_LOOKUP **ClientLookup) * * Purpose: Free the client_lookup structure. * We need to free the client_lookup structure. * * Arguments: ClientLookup => pointer to the pointer of the client * lookup structure. * * Returns: int => return code indicating error or success * */ int ftpp_ui_client_lookup_cleanup(CLIENT_LOOKUP **ClientLookup) { if ((ClientLookup == NULL) || (*ClientLookup == NULL)) return FTPP_INVALID_ARG; sfrt_cleanup(*ClientLookup, clientConfFree); sfrt_free(*ClientLookup); *ClientLookup = NULL; return FTPP_SUCCESS; } /* * Function: ftpp_ui_client_lookup_add(CLIENT_LOOKUP *ClientLookup, * sfip_t* Ip, * FTP_CLIENT_PROTO_CONF *ClientConf) * * Purpose: Add a client configuration to the list. * We add these keys like you would normally think to add * them, because on low endian machines the least significant * byte is compared first. This is what we want to compare * IPs backward, doesn't work on high endian machines, but oh * well. Our platform is Intel. * * Arguments: ClientLookup => a pointer to the lookup structure * IP => the ftp client address * ClientConf => a pointer to the client configuration structure * * Returns: int => return code indicating error or success * */ int ftpp_ui_client_lookup_add( CLIENT_LOOKUP *ClientLookup, sfip_t* Ip, FTP_CLIENT_PROTO_CONF *ClientConf) { int iRet; if(!ClientLookup || !ClientConf) { return FTPP_INVALID_ARG; } iRet = sfrt_insert((void *)Ip, (unsigned char)Ip->bits, (void *)ClientConf, RT_FAVOR_SPECIFIC, ClientLookup); if (iRet) { /* * This means the key has already been added. */ if(iRet == 1) { return FTPP_NONFATAL_ERR; } else { return FTPP_MEM_ALLOC_FAIL; } } return FTPP_SUCCESS; } /* * Function: ftpp_ui_client_lookup_find(CLIENT_LOOKUP *ClientLookup, * snort_ip_p ip, int *iError) * * Purpose: Find a client configuration given a IP. * We look up a client configuration given an IP and * return a pointer to that client configuration if found. * * Arguments: ClientLookup => a pointer to the lookup structure * IP => the ftp client address * iError => a pointer to an error code * * Returns: int => return code indicating error or success * * Returns: FTP_CLIENT_PROTO_CONF* => Pointer to client configuration * structure matching IP if found, NULL otherwise. * */ FTP_CLIENT_PROTO_CONF *ftpp_ui_client_lookup_find(CLIENT_LOOKUP *ClientLookup, snort_ip_p Ip, int *iError) { FTP_CLIENT_PROTO_CONF *ClientConf = NULL; if(!iError) { return NULL; } if(!ClientLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; ClientConf = (FTP_CLIENT_PROTO_CONF *)sfrt_lookup((void *)Ip, ClientLookup); if (!ClientConf) { *iError = FTPP_NOT_FOUND; } return ClientConf; } #if 0 /** Obsoleted. After changing underlying KMAP to SFRT. SFRT provides an iterator with * a callback function but does not support getFirst, getNext operations. */ /* * Function: ftpp_ui_client_lookup_first(CLIENT_LOOKUP *ClientLookup, * int *iError) * * Purpose: This lookups the first client configuration, so we can * iterate through the configurations. * * Arguments: ClientLookup => pointer to the client lookup structure * iError => pointer to the integer to set for errors * * Returns: FTP_CLIENT_PROTO_CONF* => Pointer to first client configuration * structure * */ FTP_CLIENT_PROTO_CONF *ftpp_ui_client_lookup_first(CLIENT_LOOKUP *ClientLookup, int *iError) { FTP_CLIENT_PROTO_CONF *ClientConf; if(!iError) { return NULL; } if(!ClientLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; ClientConf = (FTP_CLIENT_PROTO_CONF *)KMapFindFirst(ClientLookup); if (!ClientConf) { *iError = FTPP_NOT_FOUND; } return ClientConf; } /* * Function: ftpp_ui_client_lookup_next(CLIENT_LOOKUP *ClientLookup, * int *iError) * * Iterates to the next configuration, like a list it just returns * the next config in the config list. * * Purpose: This lookups the next client configuration, so we can * iterate through the configurations. * * Arguments: ClientLookup => pointer to the client lookup structure * iError => pointer to the integer to set for errors * * Returns: FTP_CLIENT_PROTO_CONF* => Pointer to next client configuration * structure * */ FTP_CLIENT_PROTO_CONF *ftpp_ui_client_lookup_next(CLIENT_LOOKUP *ClientLookup, int *iError) { FTP_CLIENT_PROTO_CONF *ClientConf; if(!iError) { return NULL; } if(!ClientLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; ClientConf = (FTP_CLIENT_PROTO_CONF *)KMapFindNext(ClientLookup); if (!ClientConf) { *iError = FTPP_NOT_FOUND; } return ClientConf; } #endif /**Free pData buffer, which may be referenced multiple times. ReferenceCount * is the number of times the buffer is referenced. For freeing the buffer, * we just decrement referenceCount till it reaches 0, at which time the * buffer is also freed. */ static void clientConfFree(void *pData) { FTP_CLIENT_PROTO_CONF *clientConf = (FTP_CLIENT_PROTO_CONF *)pData; if (clientConf) { clientConf->referenceCount--; if (clientConf->referenceCount == 0) { FTPTelnetCleanupFTPClientConf((void *)clientConf); free(clientConf); } } } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_si.h0000644000000000000000000001542712260565732020707 00000000000000/* * ftpp_si.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains structures and functions for the * Session Inspection Module. * * The Session Inspection Module has several data structures that are * very important to the functionality of the module. The two major * structures are the FTPP_SESSION and the FTPP_SI_INPUT. * * NOTES: * - 20.09.04: Initial Development. SAS * */ #ifndef __FTPP_SI_H__ #define __FTPP_SI_H__ #include #include "ftpp_include.h" #include "ftpp_ui_config.h" #include "ftp_client.h" #include "ftp_server.h" //#include "decode.h" #include "sf_snort_packet.h" #include "ftpp_eo.h" #include "sfPolicy.h" #include "sfPolicyUserData.h" /* * These are the defines for the different types of * inspection modes. We have a server mode and a client mode. */ #define FTPP_SI_NO_MODE 0 #define FTPP_SI_CLIENT_MODE 1 #define FTPP_SI_SERVER_MODE 2 #define FTPP_SI_PROTO_UNKNOWN 0 #define FTPP_SI_PROTO_TELNET 1 #define FTPP_SI_PROTO_FTP 2 #define FTPP_SI_PROTO_FTP_DATA 3 #define FTPP_FILE_IGNORE -1 #define FTPP_FILE_UNKNOWN 0 /* Macros for testing the type of FTP_TELNET_SESSION */ #define FTPP_SI_IS_PROTO(Ssn, Pro) ((Ssn) && ((Ssn)->ft_ssn.proto == (Pro))) #define PROTO_IS_FTP(ssn) FTPP_SI_IS_PROTO(ssn, FTPP_SI_PROTO_FTP) #define PROTO_IS_FTP_DATA(ssn) FTPP_SI_IS_PROTO(ssn, FTPP_SI_PROTO_FTP_DATA) #define PROTO_IS_TELNET(ssn) FTPP_SI_IS_PROTO(ssn, FTPP_SI_PROTO_TELNET) typedef struct s_FTP_TELNET_SESSION { int proto; } FTP_TELNET_SESSION; /* * The TELNET_SESSION structure contains the complete TELNET session. * This structure is the structure that is saved per session in the * Stream Interface Module. This structure gets sent through the * detection engine process (Normalization, Detection). */ typedef struct s_TELNET_SESSION { FTP_TELNET_SESSION ft_ssn; /* The global configuration for this session */ tSfPolicyId policy_id; tSfPolicyUserContextId global_conf; /* The client configuration for this session if its FTP */ TELNET_PROTO_CONF *telnet_conf; /* Number of consecutive are-you-there commands seen. */ int consec_ayt; int encr_state; TELNET_EVENTS event_list; } TELNET_SESSION; /* * These are the state values for determining the FTP data channel. */ #define NO_STATE 0x00 #define LOST_STATE 0xFFFFFFFF #define DATA_CHAN_PORT_CMD_ISSUED 0x01 #define DATA_CHAN_PORT_CMD_ACCEPT 0x02 #define DATA_CHAN_PASV_CMD_ISSUED 0x04 #define DATA_CHAN_PASV_CMD_ACCEPT 0x08 #define DATA_CHAN_XFER_CMD_ISSUED 0x10 #define DATA_CHAN_XFER_STARTED 0x20 #define AUTH_TLS_CMD_ISSUED 0x01 #define AUTH_SSL_CMD_ISSUED 0x02 #define AUTH_UNKNOWN_CMD_ISSUED 0x04 #define AUTH_TLS_ENCRYPTED 0x08 #define AUTH_SSL_ENCRYPTED 0x10 #define AUTH_UNKNOWN_ENCRYPTED 0x20 /* * The FTP_SESSION structure contains the complete FTP session, both the * client and the server constructs. This structure is the structure that * is saved per session in the Stream Interface Module. This structure * gets sent through the detection engine process (Normalization, * Detection). */ typedef struct s_FTP_SESSION { FTP_TELNET_SESSION ft_ssn; /* The client construct contains all the info associated with a * client request. */ FTP_CLIENT client; /* The server construct contains all the info associated with a * server response. */ FTP_SERVER server; /* The client configuration for this session if its FTP */ FTP_CLIENT_PROTO_CONF *client_conf; /* The server configuration for this session if its FTP */ FTP_SERVER_PROTO_CONF *server_conf; /* The global configuration for this session */ tSfPolicyId policy_id; tSfPolicyUserContextId global_conf; /* The data channel info */ int data_chan_state; int data_chan_index; int data_xfer_index; bool data_xfer_dir; snort_ip clientIP; uint16_t clientPort; snort_ip serverIP; uint16_t serverPort; /* A file is being transfered on ftp-data channel */ char *filename; int file_xfer_info; /* -1: ignore, 0: unknown, >0: filename length */ /* Command/data channel encryption */ int encr_state; /* Alertable event list */ FTP_EVENTS event_list; } FTP_SESSION; #ifdef TARGET_BASED /* FTP-Data Transfer Modes */ enum { FTPP_XFER_PASSIVE = 0, FTPP_XFER_ACTIVE = 1 }; typedef struct s_FTP_DATA_SESSION { FTP_TELNET_SESSION ft_ssn; StreamSessionKey * ftp_key; char *filename; int data_chan; int file_xfer_info; FilePosition position; bool direction; unsigned char mode; unsigned char flags; } FTP_DATA_SESSION; #define FTPDATA_FLG_REASSEMBLY_SET (1<<0) #define FTPDATA_FLG_FILENAME_SET (1<<1) #define FTPDATA_FLG_STOP (1<<2) #endif /* * The FTPP_SI_INPUT structure holds the information that the Session * Inspection Module needs to determine the type of inspection mode * (client, server, neither) and to retrieve the appropriate server * configuration. * * The input is the source and destination IP addresses, and the * source and destination ports (since this should always be a * TCP packet). */ typedef struct s_FTPP_SI_INPUT { snort_ip sip; snort_ip dip; unsigned short sport; unsigned short dport; unsigned char pdir; unsigned char pproto; } FTPP_SI_INPUT; int ftpp_si_determine_proto(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, FTP_TELNET_SESSION **, FTPP_SI_INPUT *SiInput, int *piInspectMode); int FTPGetPacketDir(SFSnortPacket *); #ifdef TARGET_BASED /* FTP-Data file processing */ FTP_DATA_SESSION * FTPDataSessionNew(SFSnortPacket *p); void FTPDataSessionFree(void *p_ssn); bool FTPDataDirection(SFSnortPacket *p, FTP_DATA_SESSION *ftpdata); #endif #endif /* ! __FTPP_SI_H__ */ snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_si.c0000644000000000000000000010301112260565732020665 00000000000000/* * ftpp_si.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains functions to select server configurations * and begin the FTPTelnet process. * * The Session Inspection Module interfaces with the Stream Inspection * Module and the User Interface Module to select the appropriate * FTPTelnet configuration and in the case of stateful inspection the * Session Inspection Module retrieves the user-data from the Stream * Module. For stateless inspection, the Session Inspection Module uses * the same structure for use by each packet. * * The main responsibility of this module is to supply the appropriate * data structures and configurations for the rest of the FTPTelnet * process. The module also determines what type of data is being * inspected, whether it is client, server, or neither. * * NOTES: * - 20.09.04: Initial Development. SAS * */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "ftpp_return_codes.h" #include "ftpp_ui_config.h" #include "ftpp_ui_client_lookup.h" #include "ftpp_ui_server_lookup.h" #include "ftpp_si.h" #include "stream_api.h" #include "snort_ftptelnet.h" #include "sfPolicyUserData.h" #ifndef WIN32 # include #endif extern tSfPolicyUserContextId ftp_telnet_config; static FTP_SESSION StaticSession; /* * Function: PortMatch(PROTO_CONF *Conf, unsigned short port) * * Purpose: Given a configuration and a port number, we decide if * the port is in the port list. * * Arguments: PROTO_CONF => pointer to the client or server configuration * port => the port number to check for * * Returns: int => 0 indicates the port is not a client/server port. * 1 indicates the port is one of the client/server ports. * */ static int PortMatch(PROTO_CONF *Conf, unsigned short port) { if(Conf->ports[port]) { return 1; } return 0; } /* * Function: TelnetFreeSession(void *preproc_session) * * Purpose: This function frees the data that is associated with a session. * * Arguments: preproc_session => pointer to the session to free * * Returns: None */ static void TelnetFreeSession(void *preproc_session) { TELNET_SESSION *ssn = (TELNET_SESSION *)preproc_session; FTPTELNET_GLOBAL_CONF *pPolicyConfig = NULL; if (ssn == NULL) return; pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(ssn->global_conf, ssn->policy_id); if (pPolicyConfig != NULL) { pPolicyConfig->ref_count--; if ((pPolicyConfig->ref_count == 0) && (ssn->global_conf != ftp_telnet_config)) { sfPolicyUserDataClear (ssn->global_conf, ssn->policy_id); FTPTelnetFreeConfig(pPolicyConfig); if (sfPolicyUserPolicyGetActive(ssn->global_conf) == 0) FTPTelnetFreeConfigs(ssn->global_conf); } } free(ssn); } /* * Function: TelnetResetSession(TELNET_SESSION *Session) * * Purpose: This function resets all the variables that need to be * initialized for a new Session. I've tried to keep this to * a minimum, so we don't have to worry about initializing big * structures. * * Arguments: Session => pointer to the session to reset * * Returns: int => return code indicating error or success * */ static inline int TelnetResetSession(TELNET_SESSION *Session) { Session->ft_ssn.proto = FTPP_SI_PROTO_TELNET; Session->telnet_conf = NULL; Session->global_conf = NULL; Session->consec_ayt = 0; Session->encr_state = NO_STATE; Session->event_list.stack_count = 0; return FTPP_SUCCESS; } /* * Function: TelnetStatefulSessionInspection(Packet *p, * FTPTELNET_GLOBAL_CONF *GlobalConf, * TELNET_SESSION **TelnetSession, * FTPP_SI_INPUT *SiInput) * * Purpose: Initialize the session and server configurations for * this packet/stream. In this function, we set the Session * pointer (which includes the correct server configuration). * The actual processing to find which IP is the server and * which is the client, is done in the InitServerConf() function. * * Arguments: p => pointer to the packet/stream * GlobalConf => pointer to the global configuration * Session => double pointer to the Session structure * SiInput => pointer to the session information * * Returns: int => return code indicating error or success * */ static int TelnetStatefulSessionInspection(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, TELNET_SESSION **TelnetSession, FTPP_SI_INPUT *SiInput) { if (p->stream_session_ptr) { TELNET_SESSION *NewSession = (TELNET_SESSION *)calloc(1, sizeof(TELNET_SESSION)); tSfPolicyId policy_id = _dpd.getRuntimePolicy(); if (NewSession == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory for " "new Telnet session.\n"); } TelnetResetSession(NewSession); NewSession->ft_ssn.proto = FTPP_SI_PROTO_TELNET; NewSession->telnet_conf = GlobalConf->telnet_config; NewSession->global_conf = ftp_telnet_config; NewSession->policy_id = policy_id; GlobalConf->ref_count++; SiInput->pproto = FTPP_SI_PROTO_TELNET; _dpd.streamAPI->set_application_data(p->stream_session_ptr, PP_FTPTELNET, NewSession, &TelnetFreeSession); *TelnetSession = NewSession; return FTPP_SUCCESS; } return FTPP_NONFATAL_ERR; } /* * Function: TelnetStatelessSessionInspection(Packet *p, * FTPTELNET_GLOBAL_CONF *GlobalConf, * TELNET_SESSION **TelnetSession, * FTPP_SI_INPUT *SiInput) * * Purpose: Initialize the session and server configurations for this * packet/stream. It is important to note in stateless mode that * we assume no knowledge of the state of a connection, other * than the knowledge that we can glean from an individual packet. * So in essence, each packet is it's own session and there * is no knowledge retained from one packet to another. If you * want to track a telnet session for real, use stateful mode. * * In this function, we set the Session pointer (which includes * the correct server configuration). The actual processing to * find which IP is the server and which is the client, is done in * the InitServerConf() function. * * Arguments: p => pointer to the packet/stream * GlobalConf => pointer to the global configuration * Session => double pointer to the Session structure * SiInput => pointer to the session information * * Returns: int => return code indicating error or success * */ static int TelnetStatelessSessionInspection(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, TELNET_SESSION **Session, FTPP_SI_INPUT *SiInput) { static TELNET_SESSION TelnetStaticSession; TelnetResetSession(&TelnetStaticSession); SiInput->pproto = FTPP_SI_PROTO_TELNET; TelnetStaticSession.telnet_conf = GlobalConf->telnet_config; TelnetStaticSession.global_conf = ftp_telnet_config; *Session = &TelnetStaticSession; return FTPP_SUCCESS; } /* * Function: TelnetSessionInspection(Packet *p, * FTPTELNET_GLOBAL_CONF *GlobalConf, * FTPP_SI_INPUT *SiInput, * int *piInspectMode) * * Purpose: The Session Inspection module selects the appropriate * configuration for the session, and the type of inspection * to be performed (client or server.) * * When the Session Inspection module is in stateful mode, it * checks to see if there is a TELNET_SESSION pointer already * associated with the stream. If there is, then it uses that * session pointer, otherwise it calculates the server configuration * using the FTP_SI_INPUT and returns a TELNET_SESSION pointer. In * stateful mode, this means that memory is allocated, but in * stateless mode, the same session pointer is used for all packets * to reduce the allocation overhead. * * The inspection mode can be either client or server. * * Arguments: p => pointer to the packet/stream * GlobalConf => pointer to the global configuration * Session => double pointer to the Session structure * SiInput => pointer to the session information * piInspectMode => pointer for setting inspection mode * * Returns: int => return code indicating error or success * */ int TelnetSessionInspection(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, TELNET_SESSION **TelnetSession, FTPP_SI_INPUT *SiInput, int *piInspectMode) { int iRet; int iTelnetSip; int iTelnetDip; #ifdef TARGET_BASED int16_t app_id = SFTARGET_UNKNOWN_PROTOCOL; /* If possible, use Stream API to determine protocol. */ if (_dpd.streamAPI) { app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); } if (app_id == SFTARGET_UNKNOWN_PROTOCOL) { return FTPP_INVALID_PROTO; } if (app_id == telnet_app_id) { if (SiInput->pdir == FTPP_SI_CLIENT_MODE || SiInput->pdir == FTPP_SI_SERVER_MODE) { *piInspectMode = (int)SiInput->pdir; } } else if (app_id && app_id != telnet_app_id) { return FTPP_INVALID_PROTO; } else { #endif iTelnetSip = PortMatch((PROTO_CONF*)GlobalConf->telnet_config, SiInput->sport); iTelnetDip = PortMatch((PROTO_CONF*)GlobalConf->telnet_config, SiInput->dport); if (iTelnetSip) { *piInspectMode = FTPP_SI_SERVER_MODE; } else if (iTelnetDip) { *piInspectMode = FTPP_SI_CLIENT_MODE; } else { return FTPP_INVALID_PROTO; } #ifdef TARGET_BASED } #endif /* * We get the server configuration and the session structure differently * depending on what type of inspection we are doing. In the case of * stateful processing, we may get the session structure from the Stream * Reassembly module (which includes the server configuration) or the * structure will be allocated and added to the stream pointer for the * rest of the session. * * In stateless mode, we just use a static variable that is contained in * the function here. */ if(GlobalConf->inspection_type == FTPP_UI_CONFIG_STATEFUL) { iRet = TelnetStatefulSessionInspection(p, GlobalConf, TelnetSession, SiInput); if (iRet) return iRet; } else { /* Assume stateless processing otherwise */ iRet = TelnetStatelessSessionInspection(p, GlobalConf, TelnetSession, SiInput); if (iRet) return iRet; } return FTPP_SUCCESS; } /* * Function: FTPGetPacketDir(Packet *p) * * Purpose: Attempts to determine the direction of an FTP packet by * examining the first 3 bytes. If all three are numeric, * the packet is a server response packet. * * Arguments: p => pointer to the Packet * * Returns: int => return code indicating the mode * */ int FTPGetPacketDir(SFSnortPacket *p) { if (p->payload_size >= 3) { if (isdigit(p->payload[0]) && isdigit(p->payload[1]) && isdigit(p->payload[2]) ) { return FTPP_SI_SERVER_MODE; } else { return FTPP_SI_CLIENT_MODE; } } return FTPP_SI_NO_MODE; } /* * Function: FTPInitConf(Packet *p, FTPTELNET_GLOBAL_CONF *GlobalConf, * FTP_CLIENT_PROTO_CONF **ClientConf, * FTP_SERVER_PROTO_CONF **ServerConf, * FTPP_SI_INPUT *SiInput, int *piInspectMode) * * Purpose: When a session is initialized, we must select the appropriate * server configuration and select the type of inspection based * on the source and destination ports. * * IMPORTANT NOTE: * We should check to make sure that there are some unique configurations, * otherwise we can just default to the global default and work some magic * that way. * * Arguments: p => pointer to the Packet/Session * GlobalConf => pointer to the global configuration * ClientConf => pointer to the address of the client * config so we can set it. * ServerConf => pointer to the address of the server * config so we can set it. * SiInput => pointer to the packet info * piInspectMode => pointer so we can set the inspection mode * * Returns: int => return code indicating error or success * */ static int FTPInitConf(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, FTP_CLIENT_PROTO_CONF **ClientConf, FTP_SERVER_PROTO_CONF **ServerConf, FTPP_SI_INPUT *SiInput, int *piInspectMode) { FTP_CLIENT_PROTO_CONF *ClientConfSip; FTP_CLIENT_PROTO_CONF *ClientConfDip; FTP_SERVER_PROTO_CONF *ServerConfSip; FTP_SERVER_PROTO_CONF *ServerConfDip; int iServerSip; int iServerDip; int iErr = 0; int iRet = FTPP_SUCCESS; #ifdef TARGET_BASED int16_t app_id = 0; #endif snort_ip sip; snort_ip dip; //structure copy sip = SiInput->sip; dip = SiInput->dip; if (sip.family == AF_INET) { sip.ip.u6_addr32[0] = ntohl(sip.ip.u6_addr32[0]); } if (dip.family == AF_INET) { dip.ip.u6_addr32[0] = ntohl(dip.ip.u6_addr32[0]); } /* * We find the client configurations for both the source and dest IPs. * There should be a check on the global configuration to see if there * is at least one unique client configuration. If there isn't then we * assume the global client configuration. */ ClientConfDip = ftpp_ui_client_lookup_find(GlobalConf->client_lookup, &dip, &iErr); if(!ClientConfDip) { ClientConfDip = GlobalConf->default_ftp_client; } ClientConfSip = ftpp_ui_client_lookup_find(GlobalConf->client_lookup, &sip, &iErr); if(!ClientConfSip) { ClientConfSip = GlobalConf->default_ftp_client; } /* * Now, we find the server configurations for both the source and dest IPs. * There should be a check on the global configuration to see if there * is at least one unique client configuration. If there isn't then we * assume the global client configuration. */ ServerConfDip = ftpp_ui_server_lookup_find(GlobalConf->server_lookup, &dip, &iErr); if(!ServerConfDip) { ServerConfDip = GlobalConf->default_ftp_server; } ServerConfSip = ftpp_ui_server_lookup_find(GlobalConf->server_lookup, &sip, &iErr); if(!ServerConfSip) { ServerConfSip = GlobalConf->default_ftp_server; } /* * We check the IP and the port to see if the FTP client is talking in * the session. This should tell us whether it is client communication * or server configuration. If both IPs and ports are servers, then there * is a sort of problem. We don't know which side is the client and which * side is the server so we have to assume one. * * In stateful processing, we only do this stage on the startup of a * session, so we can still assume that the initial packet is the client * talking. */ iServerDip = PortMatch((PROTO_CONF*)ServerConfDip, SiInput->dport); iServerSip = PortMatch((PROTO_CONF*)ServerConfSip, SiInput->sport); /* * We default to the no FTP traffic case */ *piInspectMode = FTPP_SI_NO_MODE; *ClientConf = NULL; *ServerConf = NULL; /* * Depending on the type of packet direction we get from the * state machine, we evaluate client/server differently. */ switch(SiInput->pdir) { case FTPP_SI_NO_MODE: #ifdef TARGET_BASED app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if (app_id == ftp_app_id || app_id == 0) { #endif /* * We check for the case where both SIP and DIP * appear to be servers. In this case, we assume server * and process that way. */ if(iServerSip && iServerDip) { /* * We check for the case where both SIP and DIP * appear to be servers. In this case, we look at * the first few bytes of the packet to try to * determine direction -- 3 digits indicate server * response. */ /* look at the first few bytes of the packet. We might * be wrong if this is a reassembled packet and we catch * a server response mid-stream. */ *piInspectMode = FTPGetPacketDir(p); if (*piInspectMode == FTPP_SI_SERVER_MODE) { /* Packet is from server --> src is Server */ *ClientConf = ClientConfDip; *ServerConf = ServerConfSip; } else /* Assume client */ { /* Packet is from client --> dest is Server */ *piInspectMode = FTPP_SI_CLIENT_MODE; *ClientConf = ClientConfSip; *ServerConf = ServerConfDip; } SiInput->pproto = FTPP_SI_PROTO_FTP; } else if(iServerDip) { /* Packet is from client --> dest is Server */ *piInspectMode = FTPP_SI_CLIENT_MODE; *ClientConf = ClientConfSip; *ServerConf = ServerConfDip; SiInput->pproto = FTPP_SI_PROTO_FTP; } else if(iServerSip) { /* Packet is from server --> src is Server */ *piInspectMode = FTPP_SI_SERVER_MODE; *ClientConf = ClientConfDip; *ServerConf = ServerConfSip; SiInput->pproto = FTPP_SI_PROTO_FTP; } break; #ifdef TARGET_BASED } #endif case FTPP_SI_CLIENT_MODE: /* Packet is from client --> dest is Server */ #ifdef TARGET_BASED app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if ((app_id == ftp_app_id) || (!app_id && iServerDip)) #else if(iServerDip) #endif { *piInspectMode = FTPP_SI_CLIENT_MODE; *ClientConf = ClientConfSip; *ServerConf = ServerConfDip; SiInput->pproto = FTPP_SI_PROTO_FTP; } else { *piInspectMode = FTPP_SI_NO_MODE; iRet = FTPP_NONFATAL_ERR; } break; case FTPP_SI_SERVER_MODE: /* Packet is from server --> src is Server */ #ifdef TARGET_BASED app_id = _dpd.streamAPI->get_application_protocol_id(p->stream_session_ptr); if ((app_id == ftp_app_id) || (!app_id && iServerSip)) #else if(iServerSip) #endif { *piInspectMode = FTPP_SI_SERVER_MODE; *ClientConf = ClientConfDip; *ServerConf = ServerConfSip; SiInput->pproto = FTPP_SI_PROTO_FTP; } else { *piInspectMode = FTPP_SI_NO_MODE; iRet = FTPP_NONFATAL_ERR; } break; default: *piInspectMode = FTPP_SI_NO_MODE; *ClientConf = NULL; *ServerConf = NULL; break; } return iRet; } /* * Function: FTPFreeSession(void *preproc_session) * * Purpose: This function frees the data that is associated with a session. * * Arguments: preproc_session => pointer to the session to free * * Returns: None */ static void FTPFreeSession(void *preproc_session) { FTP_SESSION *ssn = (FTP_SESSION *)preproc_session; FTPTELNET_GLOBAL_CONF *pPolicyConfig = NULL; if (ssn == NULL) return; pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(ssn->global_conf, ssn->policy_id); if (pPolicyConfig != NULL) { pPolicyConfig->ref_count--; if ((pPolicyConfig->ref_count == 0) && (ssn->global_conf != ftp_telnet_config)) { sfPolicyUserDataClear (ssn->global_conf, ssn->policy_id); FTPTelnetFreeConfig(pPolicyConfig); if (sfPolicyUserPolicyGetActive(ssn->global_conf) == 0) FTPTelnetFreeConfigs(ssn->global_conf); } } if (ssn->filename) { free(ssn->filename); } free(ssn); } #ifdef TARGET_BASED /* Function: FTPDataSessionNew * * Create an ftp-data session from a packet */ FTP_DATA_SESSION * FTPDataSessionNew(SFSnortPacket *p) { FTP_DATA_SESSION *ftpdata = calloc(1, sizeof *ftpdata); if (!ftpdata) return NULL; ftpdata->ft_ssn.proto = FTPP_SI_PROTO_FTP_DATA; /* Get the ftp-ctrl session key */ ftpdata->ftp_key = _dpd.streamAPI->get_session_key(p); if (!ftpdata->ftp_key) { free(ftpdata); ftpdata = NULL; } return ftpdata; } /* * Function: FTPDataSessionFree * * Free an ftp-data session */ void FTPDataSessionFree(void *p_ssn) { FTP_DATA_SESSION *ssn = (FTP_DATA_SESSION *)p_ssn; if (!ssn) return; /* ftp-data key shouldn't exist without this but */ if (ssn->ftp_key) { free(ssn->ftp_key); } if (ssn->filename) { free(ssn->filename); } free(ssn); } /* Function: FTPDataDirection * * Return true if packet is from the "sending" host * Return false if packet is from the "receiving" host */ bool FTPDataDirection(SFSnortPacket *p, FTP_DATA_SESSION *ftpdata) { uint32_t direction; uint32_t pktdir = _dpd.streamAPI->get_packet_direction(p); if (ftpdata->mode == FTPP_XFER_ACTIVE) direction = ftpdata->direction ? FLAG_FROM_SERVER : FLAG_FROM_CLIENT; else direction = ftpdata->direction ? FLAG_FROM_CLIENT : FLAG_FROM_SERVER; return (pktdir == direction); } #endif /* TARGET_BASED */ /* * Function: FTPResetSession(FTP_SESSION *FtpSession, int first) * * Purpose: This function resets all the variables that need to be * initialized for a new Session. I've tried to keep this to * a minimum, so we don't have to worry about initializing big * structures. * * Arguments: FtpSession => pointer to the session to reset * first => indicator whether this is a new conf * * Returns: int => return code indicating error or success * */ static inline int FTPResetSession(FTP_SESSION *FtpSession) { FtpSession->ft_ssn.proto = FTPP_SI_PROTO_FTP; FtpSession->server.response.pipeline_req = 0; FtpSession->server.response.state = 0; FtpSession->client.request.pipeline_req = 0; FtpSession->client.state = 0; FtpSession->client_conf = NULL; FtpSession->server_conf = NULL; FtpSession->global_conf = NULL; FtpSession->encr_state = NO_STATE; IP_CLEAR(FtpSession->clientIP); FtpSession->clientPort = 0; IP_CLEAR(FtpSession->serverIP); FtpSession->serverPort = 0; FtpSession->data_chan_state = NO_STATE; FtpSession->data_chan_index = -1; FtpSession->data_xfer_index = -1; FtpSession->event_list.stack_count = 0; return FTPP_SUCCESS; } /* * Function: FTPStatefulSessionInspection(Packet *p, * FTPTELNET_GLOBAL_CONF *GlobalConf, * FTP_SESSION **FtpSession, * FTPP_SI_INPUT *SiInput, int *piInspectMode) * * Purpose: Initialize the session and server configurations for this * packet/stream. In this function, we set the Session pointer * (which includes the correct server configuration). The actual * processing to find which IP is the server and which is the * client, is done in the InitServerConf() function. * * Arguments: p => pointer to the Packet/Session * GlobalConf => pointer to the global configuration * Session => double pointer to the Session structure * SiInput => pointer to the session information * piInspectMode => pointer so the inspection mode can be set * * Returns: int => return code indicating error or success * */ static int FTPStatefulSessionInspection(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, FTP_SESSION **FtpSession, FTPP_SI_INPUT *SiInput, int *piInspectMode) { if (p->stream_session_ptr) { FTP_CLIENT_PROTO_CONF *ClientConf; FTP_SERVER_PROTO_CONF *ServerConf; int iRet; iRet = FTPInitConf(p, GlobalConf, &ClientConf, &ServerConf, SiInput, piInspectMode); if (iRet) return iRet; if (*piInspectMode) { FTP_SESSION *NewSession = (FTP_SESSION *)calloc(1, sizeof(FTP_SESSION)); tSfPolicyId policy_id = _dpd.getRuntimePolicy(); if (NewSession == NULL) { DynamicPreprocessorFatalMessage("Failed to allocate memory for " "new FTP session.\n"); } FTPResetSession(NewSession); NewSession->ft_ssn.proto = FTPP_SI_PROTO_FTP; NewSession->client_conf = ClientConf; NewSession->server_conf = ServerConf; NewSession->global_conf = ftp_telnet_config; NewSession->policy_id = policy_id; GlobalConf->ref_count++; _dpd.streamAPI->set_application_data (p->stream_session_ptr, PP_FTPTELNET, NewSession, &FTPFreeSession); *FtpSession = NewSession; SiInput->pproto = FTPP_SI_PROTO_FTP; return FTPP_SUCCESS; } } return FTPP_INVALID_PROTO; } /* * Function: FTPStatelessSessionInspection(Packet *p, * FTPTELNET_GLOBAL_CONF *GlobalConf, * FTP_SESSION **FtpSession, * FTPP_SI_INPUT *SiInput, int *piInspectMode) * * Purpose: Initialize the session and server configurations for this * packet/stream. It is important to note in stateless mode that * we assume no knowledge of the state of a connection, other than * the knowledge that we can glean from an individual packet. So * in essence, each packet is it's own session and there is no * knowledge retained from one packet to another. If you want to * track an FTP session for real, use stateful mode. * * In this function, we set the Session pointer (which includes * the correct server configuration). The actual processing to find * which IP is the server and which is the client, is done in the * InitServerConf() function. * * Arguments: p => pointer to the Packet/Session * GlobalConf => pointer to the global configuration * Session => double pointer to the Session structure * SiInput => pointer to the session information * piInspectMode => pointer so the inspection mode can be set * * Returns: int => return code indicating error or success * */ static int FTPStatelessSessionInspection(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, FTP_SESSION **FtpSession, FTPP_SI_INPUT *SiInput, int *piInspectMode) { FTP_CLIENT_PROTO_CONF *ClientConf; FTP_SERVER_PROTO_CONF *ServerConf; int iRet; FTPResetSession(&StaticSession); iRet = FTPInitConf(p, GlobalConf, &ClientConf, &ServerConf, SiInput, piInspectMode); if (iRet) return iRet; StaticSession.ft_ssn.proto = FTPP_SI_PROTO_FTP; StaticSession.global_conf = ftp_telnet_config; StaticSession.client_conf = ClientConf; StaticSession.server_conf = ServerConf; SiInput->pproto = FTPP_SI_PROTO_FTP; *FtpSession = &StaticSession; return FTPP_SUCCESS; } /* * Function: FTPSessionInspection(Packet *p, * FTPTELNET_GLOBAL_CONF *GlobalConf, * FTPP_SI_INPUT *SiInput, int *piInspectMode) * * Purpose: The Session Inspection module selects the appropriate client * configuration for the session, and the type of inspection to * be performed (client or server.) * * When the Session Inspection module is in stateful mode, it * checks to see if there is a FTP_SESSION pointer already * associated with the stream. If there is, then it uses that * session pointer, otherwise it calculates the server * configuration using the FTP_SI_INPUT and returns a FTP_SESSION * pointer. In stateful mode, this means that memory is allocated, * but in stateless mode, the same session pointer is used for all * packets to reduce the allocation overhead. * * The inspection mode can be either client or server. * * Arguments: p => pointer to the Packet/Session * GlobalConf => pointer to the global configuration * SiInput => pointer to the session information * piInspectMode => pointer so the inspection mode can be set * * Returns: int => return code indicating error or success * */ int FTPSessionInspection(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, FTP_SESSION **FtpSession, FTPP_SI_INPUT *SiInput, int *piInspectMode) { int iRet; /* * We get the server configuration and the session structure differently * depending on what type of inspection we are doing. In the case of * stateful processing, we may get the session structure from the Stream * Reassembly module (which includes the server configuration) or the * structure will be allocated and added to the stream pointer for the * rest of the session. * * In stateless mode, we just use a static variable that is contained in * the function here. */ if(GlobalConf->inspection_type == FTPP_UI_CONFIG_STATEFUL) { iRet = FTPStatefulSessionInspection(p, GlobalConf, FtpSession, SiInput, piInspectMode); if (iRet) return iRet; } else { /* Assume stateless processing otherwise */ iRet = FTPStatelessSessionInspection(p, GlobalConf, FtpSession, SiInput, piInspectMode); if (iRet) return iRet; } return FTPP_SUCCESS; } /* * Function: ftpp_si_determine_proto(Packet *p, * FTPTELNET_GLOBAL_CONF *GlobalConf, * FTPP_SI_INPUT *SiInput, int *piInspectMode) * * Purpose: The Protocol Determination module determines whether this is * an FTP or telnet request. If this is an FTP request, it sets * the FTP Session data and inspection mode. * * The inspection mode can be either client or server. * * Arguments: p => pointer to the Packet/Session * GlobalConf => pointer to the global configuration * SiInput => pointer to the session information * piInspectMode => pointer so the inspection mode can be set * * Returns: int => return code indicating error or success * */ int ftpp_si_determine_proto(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf, FTP_TELNET_SESSION **ft_ssn, FTPP_SI_INPUT *SiInput, int *piInspectMode) { /* Default to no FTP or Telnet case */ SiInput->pproto = FTPP_SI_PROTO_UNKNOWN; *piInspectMode = FTPP_SI_NO_MODE; TelnetSessionInspection(p, GlobalConf, (TELNET_SESSION **)ft_ssn, SiInput, piInspectMode); if (SiInput->pproto == FTPP_SI_PROTO_TELNET) return FTPP_SUCCESS; FTPSessionInspection(p, GlobalConf, (FTP_SESSION **)ft_ssn, SiInput, piInspectMode); if (SiInput->pproto == FTPP_SI_PROTO_FTP) return FTPP_SUCCESS; return FTPP_INVALID_PROTO; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_return_codes.h0000644000000000000000000000444712260565732022770 00000000000000/* * ftpp_return_codes.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file defines the return codes for the FTPTelnet functions. * * Common return codes are defined here for all functions and libraries to * use. This should make function error checking easier. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __FTPP_RETURN_CODES_H__ #define __FTPP_RETURN_CODES_H__ #include "ftpp_include.h" #define FTPP_BOOL_FALSE 0 #define FTPP_SUCCESS 0 /* * Non-fatal errors are positive */ #define FTPP_BOOL_TRUE 1 #define FTPP_NONFATAL_ERR 1 #define FTPP_OUT_OF_BOUNDS 2 #define FTPP_INVALID_PROTO 3 #define FTPP_NORMALIZED 4 #define FTPP_MALFORMED_FTP_RESPONSE 5 #define FTPP_ALERTED 6 #define FTPP_NON_DIGIT 7 #define FTPP_MALFORMED_IP_PORT 8 #define FTPP_PORT_ATTACK 9 #define FTPP_INVALID_SESSION 10 #define FTPP_OR_FOUND 100 #define FTPP_OPT_END_FOUND 101 #define FTPP_CHOICE_END_FOUND 102 /* * Fatal errors are negative */ #define FTPP_FATAL_ERR -1 #define FTPP_INVALID_ARG -2 #define FTPP_MEM_ALLOC_FAIL -3 #define FTPP_NOT_FOUND -4 #define FTPP_INVALID_FILE -5 #define FTPP_ALERT -6 #define FTPP_INVALID_DATE -100 #define FTPP_INVALID_PARAM -101 #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_include.h0000644000000000000000000000272512260565732021714 00000000000000/* * ftpp_include.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * Global definitions for the FTPTelnet preprocessor. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __FTP_INCLUDE_H__ #define __FTP_INCLUDE_H__ #include "sf_types.h" #include "sf_ip.h" #include "snort_debug.h" #include "sf_snort_packet.h" #include "sf_dynamic_preprocessor.h" #define GENERATOR_SPP_FTPP_FTP 125 #define GENERATOR_SPP_FTPP_TELNET 126 #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_eo_log.h0000644000000000000000000000307412260565732021533 00000000000000/* * ftpp_eo_log.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * Defines the functions for logging within the FTP Telnet preprocessor. * * NOTES: * - 20.09.04: Initial Development. SAS * */ #ifndef __FTPP_EO_LOG_H__ #define __FTPP_EO_LOG_H__ #include "ftpp_include.h" #include "ftpp_si.h" #include "ftpp_return_codes.h" void ftpp_eo_event_log_init(void); int telnet_eo_event_log(TELNET_SESSION *Session, int iEvent, void *data, void (*free_data)(void *)); int ftp_eo_event_log(FTP_SESSION *Session, int iEvent, void *data, void (*free_data)(void *)); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_eo_log.c0000644000000000000000000003052412260565732021526 00000000000000/* * ftpp_eo_log.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains the event output functionality that * FTPTelnet uses to log events and data associated with * the events. * * Log events, retrieve events, and select events that HttpInspect * generates. * * Logging Events: * Since the object behind this is no memset()s, we have to rely on the * stack interface to make sure we don't log the same event twice. So * if there are events in the stack we cycle through to make sure that * there are none available before we add a new event and increment the * stack count. Then to reset the event queue, we just need to set the * stack count back to zero. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "ftpp_si.h" #include "ftpp_eo.h" #include "ftpp_eo_events.h" #include "ftpp_return_codes.h" //#include "signature.h" typedef struct _ClassInfo { char *typeName; int id; char *name; int priority; struct _ClassInfo *next; } ClassInfo; /* * The ftp & telnet events and the priorities are listed here. * Any time that a new client event is added, we have to * add the event id and the priority here. If you want to * change either of those characteristics, you have to change * them here. */ static FTPP_EVENT_INFO ftp_event_info[FTP_EO_EVENT_NUM] = { { FTP_EO_TELNET_CMD, FTP_EO_TELNET_CMD_SID, 0, FTPP_EO_LOW_PRIORITY, FTP_EO_TELNET_CMD_STR }, { FTP_EO_INVALID_CMD, FTP_EO_INVALID_CMD_SID, 0, FTPP_EO_LOW_PRIORITY, FTP_EO_INVALID_CMD_STR }, { FTP_EO_PARAMETER_LENGTH_OVERFLOW, FTP_EO_PARAMETER_LENGTH_OVERFLOW_SID, 0, FTPP_EO_HIGH_PRIORITY, FTP_EO_PARAMETER_LENGTH_OVERFLOW_STR }, { FTP_EO_MALFORMED_PARAMETER, FTP_EO_MALFORMED_PARAMETER_SID, 0, FTPP_EO_HIGH_PRIORITY, FTP_EO_MALFORMED_PARAMETER_STR }, { FTP_EO_PARAMETER_STR_FORMAT, FTP_EO_PARAMETER_STR_FORMAT_SID, 0, FTPP_EO_HIGH_PRIORITY, FTP_EO_PARAMETER_STR_FORMAT_STR }, { FTP_EO_RESPONSE_LENGTH_OVERFLOW, FTP_EO_RESPONSE_LENGTH_OVERFLOW_SID, 0, FTPP_EO_LOW_PRIORITY, FTP_EO_RESPONSE_LENGTH_OVERFLOW_STR }, { FTP_EO_ENCRYPTED, FTP_EO_ENCRYPTED_SID, 0, FTPP_EO_LOW_PRIORITY, FTP_EO_ENCRYPTED_STR }, { FTP_EO_BOUNCE, FTP_EO_BOUNCE_SID, 0, FTPP_EO_MED_PRIORITY, FTP_EO_BOUNCE_STR }, { FTP_EO_EVASIVE_TELNET_CMD, FTP_EO_EVASIVE_TELNET_CMD_SID, 0, FTPP_EO_LOW_PRIORITY, FTP_EO_EVASIVE_TELNET_CMD_STR } }; static FTPP_EVENT_INFO telnet_event_info[TELNET_EO_EVENT_NUM] = { { TELNET_EO_AYT_OVERFLOW, TELNET_EO_AYT_OVERFLOW_SID, 0, FTPP_EO_HIGH_PRIORITY, TELNET_EO_AYT_OVERFLOW_STR }, { TELNET_EO_ENCRYPTED, TELNET_EO_ENCRYPTED_SID, 0, FTPP_EO_LOW_PRIORITY, TELNET_EO_ENCRYPTED_STR }, { TELNET_EO_SB_NO_SE, TELNET_EO_SB_NO_SE_SID, 0, FTPP_EO_LOW_PRIORITY, TELNET_EO_SB_NO_SE_STR } }; static int log_initialized = 0; /* * Function: ftpp_eo_event_log_init() * * Purpose: Initialize the event logger. * We need to initialize the event logger for the FTP/Telnet * preprocessor. Initializes the event info objects and class types. * * Arguments: None * * Returns: void * */ void ftpp_eo_event_log_init(void) { if (!log_initialized) { ClassInfo *type = _dpd.getRuleInfoByName("protocol-command-decode"); if (type != NULL) { ftp_event_info[FTP_EO_TELNET_CMD].classification = type->id; ftp_event_info[FTP_EO_TELNET_CMD].priority = type->priority; ftp_event_info[FTP_EO_INVALID_CMD].classification = type->id; ftp_event_info[FTP_EO_INVALID_CMD].priority = type->priority; ftp_event_info[FTP_EO_MALFORMED_PARAMETER].classification = type->id; ftp_event_info[FTP_EO_MALFORMED_PARAMETER].priority = type->priority; ftp_event_info[FTP_EO_ENCRYPTED].classification = type->id; ftp_event_info[FTP_EO_ENCRYPTED].priority = type->priority; ftp_event_info[FTP_EO_EVASIVE_TELNET_CMD].classification = type->id; ftp_event_info[FTP_EO_EVASIVE_TELNET_CMD].priority = type->priority; telnet_event_info[TELNET_EO_ENCRYPTED].classification = type->id; telnet_event_info[TELNET_EO_ENCRYPTED].priority = type->priority; } type = _dpd.getRuleInfoByName("string-detect"); if (type != NULL) { ftp_event_info[FTP_EO_RESPONSE_LENGTH_OVERFLOW].classification = type->id; ftp_event_info[FTP_EO_RESPONSE_LENGTH_OVERFLOW].priority = type->priority; } type = _dpd.getRuleInfoByName("policy-violation"); if (type != NULL) { ftp_event_info[FTP_EO_BOUNCE].classification = type->id; ftp_event_info[FTP_EO_BOUNCE].priority = type->priority; } type = _dpd.getRuleInfoByName("attempted-admin"); if (type != NULL) { ftp_event_info[FTP_EO_PARAMETER_LENGTH_OVERFLOW].classification = type->id; ftp_event_info[FTP_EO_PARAMETER_LENGTH_OVERFLOW].priority = type->priority; ftp_event_info[FTP_EO_PARAMETER_STR_FORMAT].classification = type->id; ftp_event_info[FTP_EO_PARAMETER_STR_FORMAT].priority = type->priority; telnet_event_info[TELNET_EO_AYT_OVERFLOW].classification = type->id; telnet_event_info[TELNET_EO_AYT_OVERFLOW].priority = type->priority; telnet_event_info[TELNET_EO_SB_NO_SE].classification = type->id; telnet_event_info[TELNET_EO_SB_NO_SE].priority= type->priority; } log_initialized = 1; } } /* * Function: ftpp_eo_event_log(FTPP_GEN_EVENTS *gen_events, * FTPP_EVENT_INFO *event_info, * int iEvent, * void *data, void (*free_data)(void *) ) * * Purpose: This function logs events during FTPTelnet processing. * The idea behind this event logging is modularity, but at the * same time performance. We accomplish this utilizing an * optimized stack as an index into the client event array, * instead of walking a list for already logged events. The * problem here is that we can't just log every event that we've * already seen, because this opens us up to a DOS. So by using * this method, we can quickly check if an event has already been * logged and deal appropriately. * * Arguments: gen_events => pointer to the generic event data * event_info => pointer to the event info array * iEvent => index within the event array * data => pointer to user allocated data * free_data => pointer to a function to free the user data * * Returns: int => return code indicating error or success * */ int ftpp_eo_event_log(FTPP_GEN_EVENTS *gen_events, FTPP_EVENT_INFO *event_info, int iEvent, void *data, void (*free_data)(void *) ) { FTPP_EVENT *event; int iCtr; /* * This is where we cycle through the current event stack. If the event * to be logged is already in the queue, then we increment the event * count, before returning. Otherwise, we fall through the loop and * set the event before adding it to the queue and incrementing the * pointer. */ for(iCtr = 0; iCtr < gen_events->stack_count; iCtr++) { if(gen_events->stack[iCtr] == iEvent) { gen_events->events[iEvent].count++; return FTPP_SUCCESS; } } /* * Initialize the event before putting it in the queue. */ event = &(gen_events->events[iEvent]); event->event_info = event_info; event->count = 1; event->data = data; event->free_data = free_data; /* * We now add the event to the stack. */ gen_events->stack[gen_events->stack_count] = iEvent; gen_events->stack_count++; return FTPP_SUCCESS; } /* * Function: telnet_eo_event_log(TELNET_SESSION *Session, * int iEvent, * void *data, void (*free_data)(void *)) * * Purpose: This function logs events for telnet processing. * It invokes ftpp_eo_event_log using a generic event structure * that contains the telnet specific data. * * Arguments: Session => pointer to the Telnet session * iEvent => the event id for the event * data => pointer to the user data of the event * free_data => pointer to a function to free the user data * * Returns: int => return code indicating error or success * */ int telnet_eo_event_log(TELNET_SESSION *Session, int iEvent, void *data, void (*free_data)(void *)) { int iRet; TELNET_EVENTS *telnet_events; FTPP_EVENT_INFO *event_info; FTPP_GEN_EVENTS gen_events; ftpp_eo_event_log_init(); /* * Check the input variables for correctness */ if(!Session || (iEvent >= TELNET_EO_EVENT_NUM)) { return FTPP_INVALID_ARG; } telnet_events = &(Session->event_list); gen_events.events = (FTPP_EVENT *)&(telnet_events->events); gen_events.stack = (int *)&(telnet_events->stack); gen_events.stack_count = telnet_events->stack_count; event_info = &telnet_event_info[iEvent]; iRet = ftpp_eo_event_log(&gen_events, event_info, iEvent, data, free_data); telnet_events->stack_count = gen_events.stack_count; return iRet; } /* * Function: ftp_eo_event_log(FTP_SESSION *Session, * int iEvent, * void *data, void (*free_data)(void *)) * * Purpose: This function logs events for ftp processing. * It invokes ftpp_eo_event_log using a generic event structure * that contains the ftp specific data. * * Arguments: Session => pointer to the FTP session * iEvent => the event id for the event * data => pointer to the user data of the event * free_data => pointer to a function to free the user data * * Returns: int => return code indicating error or success * */ int ftp_eo_event_log(FTP_SESSION *Session, int iEvent, void *data, void (*free_data)(void *)) { int iRet; FTP_EVENTS *ftp_events; FTPP_EVENT_INFO *event_info; FTPP_GEN_EVENTS gen_events; ftpp_eo_event_log_init(); /* * Check the input variables for correctness */ if(!Session || (iEvent >= FTP_EO_EVENT_NUM)) { return FTPP_INVALID_ARG; } ftp_events = &(Session->event_list); gen_events.events = (FTPP_EVENT *)&(ftp_events->events); gen_events.stack = (int *)&(ftp_events->stack); gen_events.stack_count = ftp_events->stack_count; event_info = &ftp_event_info[iEvent]; iRet = ftpp_eo_event_log(&gen_events, event_info, iEvent, data, free_data); ftp_events->stack_count = gen_events.stack_count; return iRet; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_eo.h0000644000000000000000000000673112260565732020675 00000000000000/* * ftpp_eo.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * Contains the data structures, event types, specific events, * and function prototypes for the Event Output Module. * * This file is key to alerting with FTPTelnet. It contains the header * file with all the individual alerts. * * The Event Output Module provides a mechanism to queue HttpInspect events * and prioritize them. The Event Output Module does not actually log the * events, but tracks them per session/packet. The user program needs to * do the actual logging of events. * * Each event contains the type of event, the priority of the event, and * any data that is associated with the event. * * NOTES: * - 20.09.04: Initial Development. SAS * */ #ifndef __FTPP_EO_H__ #define __FTPP_EO_H__ #include "ftpp_include.h" #include "ftpp_eo_events.h" /* * We hold the type of alert, the priority of the alert * and any data associated with this alert. */ typedef struct s_FTPP_EVENT_INFO { int alert_id; /* the alert id */ int alert_sid; /* the unique sid */ int classification; /* classification */ int priority; /* the alert priority, 0 = highest */ char *alert_str; /* the alert string */ } FTPP_EVENT_INFO; typedef struct s_FTPP_EVENT { FTPP_EVENT_INFO *event_info; int count; /* number of times event occurred in session */ void *data; /* generic ptr to data */ void (*free_data)(void *); /* function to free data */ } FTPP_EVENT; /* * This is a generic structure to translate different event types to * the same structure. This helps when logging the different types * of events. */ typedef struct s_FTPP_GEN_EVENTS { int *stack; int stack_count; FTPP_EVENT *events; } FTPP_GEN_EVENTS; /* * The idea behind this event storage structure is that we use a * simple stack to tell us which events we have set, so we don't * set an event twice and can access the events very easily. */ typedef struct s_FTP_EVENTS { int stack[FTP_EO_EVENT_NUM]; int stack_count; FTPP_EVENT events[FTP_EO_EVENT_NUM]; } FTP_EVENTS; /* * The idea behind this event storage structure is that we use a * simple stack to tell us which events we have set, so we don't * set an event twice and can access the events very easily. */ typedef struct s_TELNET_EVENTS { int stack[TELNET_EO_EVENT_NUM]; int stack_count; FTPP_EVENT events[TELNET_EO_EVENT_NUM]; } TELNET_EVENTS; #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftpp_eo_events.h0000644000000000000000000001037712260565732022262 00000000000000/* * ftpp_eo_events.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * Defines the events for the FTP Telnet Preprocessor. * * NOTES: * - 20.09.04: Initial Development. SAS * */ #ifndef __FTP_EO_EVENTS_H__ #define __FTP_EO_EVENTS_H__ #include "ftpp_include.h" /* * FTP Events */ #define FTP_EO_TELNET_CMD 0 #define FTP_EO_INVALID_CMD 1 #define FTP_EO_PARAMETER_LENGTH_OVERFLOW 2 #define FTP_EO_MALFORMED_PARAMETER 3 #define FTP_EO_PARAMETER_STR_FORMAT 4 #define FTP_EO_RESPONSE_LENGTH_OVERFLOW 5 #define FTP_EO_ENCRYPTED 6 #define FTP_EO_BOUNCE 7 #define FTP_EO_EVASIVE_TELNET_CMD 8 #define FTP_EO_TELNET_CMD_SID 1 #define FTP_EO_INVALID_CMD_SID 2 #define FTP_EO_PARAMETER_LENGTH_OVERFLOW_SID 3 #define FTP_EO_MALFORMED_PARAMETER_SID 4 #define FTP_EO_PARAMETER_STR_FORMAT_SID 5 #define FTP_EO_RESPONSE_LENGTH_OVERFLOW_SID 6 #define FTP_EO_ENCRYPTED_SID 7 #define FTP_EO_BOUNCE_SID 8 #define FTP_EO_EVASIVE_TELNET_CMD_SID 9 /* * IMPORTANT: * Every time you add an FTP event, this number must be * incremented. */ #define FTP_EO_EVENT_NUM 9 /* * These defines are the alert names for each event */ #define FTP_EO_TELNET_CMD_STR \ "(ftp_telnet) TELNET CMD on FTP Command Channel" #define FTP_EO_INVALID_CMD_STR \ "(ftp_telnet) Invalid FTP Command" #define FTP_EO_PARAMETER_LENGTH_OVERFLOW_STR \ "(ftp_telnet) FTP command parameters were too long" #define FTP_EO_MALFORMED_PARAMETER_STR \ "(ftp_telnet) FTP command parameters were malformed" #define FTP_EO_PARAMETER_STR_FORMAT_STR \ "(ftp_telnet) FTP command parameters contained potential string format" #define FTP_EO_RESPONSE_LENGTH_OVERFLOW_STR \ "(ftp_telnet) FTP response message was too long" #define FTP_EO_ENCRYPTED_STR \ "(ftp_telnet) FTP traffic encrypted" #define FTP_EO_BOUNCE_STR \ "(ftp_telnet) FTP bounce attempt" #define FTP_EO_EVASIVE_TELNET_CMD_STR \ "(ftp_telnet) Evasive (incomplete) TELNET CMD on FTP Command Channel" /* * TELNET Events */ #define TELNET_EO_AYT_OVERFLOW 0 #define TELNET_EO_ENCRYPTED 1 #define TELNET_EO_SB_NO_SE 2 #define TELNET_EO_AYT_OVERFLOW_SID 1 #define TELNET_EO_ENCRYPTED_SID 2 #define TELNET_EO_SB_NO_SE_SID 3 /* * IMPORTANT: * Every time you add a telnet event, this number must be * incremented. */ #define TELNET_EO_EVENT_NUM 3 /* * These defines are the alert names for each event */ #define TELNET_EO_AYT_OVERFLOW_STR \ "(ftp_telnet) Consecutive Telnet AYT commands beyond threshold" #define TELNET_EO_ENCRYPTED_STR \ "(ftp_telnet) Telnet traffic encrypted" #define TELNET_EO_SB_NO_SE_STR \ "(ftp_telnet) Telnet Subnegotiation Begin Command without Subnegotiation End" /* * Event Priorities */ #define FTPP_EO_HIGH_PRIORITY 0 #define FTPP_EO_MED_PRIORITY 1 #define FTPP_EO_LOW_PRIORITY 2 #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftp_cmd_lookup.h0000644000000000000000000000340412260565732022240 00000000000000/* * ftp_cmd_lookup.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains function definitions for FTP command lookups. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __FTP_CMD_LOOKUP_H__ #define __FTP_CMD_LOOKUP_H__ #include "ftpp_include.h" #include "ftpp_ui_config.h" int ftp_cmd_lookup_init(CMD_LOOKUP **CmdLookup); int ftp_cmd_lookup_cleanup(CMD_LOOKUP **CmdLookup); int ftp_cmd_lookup_add(CMD_LOOKUP *CmdLookup, char cmd[], int len, FTP_CMD_CONF *FTPCmd); FTP_CMD_CONF *ftp_cmd_lookup_find(CMD_LOOKUP *CmdLookup, const char cmd[], int len, int *iError); FTP_CMD_CONF *ftp_cmd_lookup_first(CMD_LOOKUP *CmdLookup, int *iError); FTP_CMD_CONF *ftp_cmd_lookup_next(CMD_LOOKUP *CmdLookup, int *iError); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftp_cmd_lookup.c0000644000000000000000000001670012260565732022236 00000000000000/* * ftp_cmd_lookup.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains functions to access the CMD_LOOKUP structure. * * We wrap the access to CMD_LOOKUP so changing the lookup algorithms * are more modular and independent. This is the only file that would need * to be changed to change the algorithmic lookup. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_util_kmap.h" #include "ftpp_ui_config.h" #include "ftpp_return_codes.h" #include "snort_ftptelnet.h" /* * Function: ftp_cmd_lookup_init(CMD_LOOKUP **CmdLookup) * * Purpose: Initialize the cmd_lookup structure. * * We need to initialize the cmd_lookup structure for * the FTP command configuration. Don't want a NULL pointer * flying around, when we have to look for FTP commands. * * Arguments: CmdLookup => pointer to the pointer of the cmd * lookup structure. * * Returns: int => return code indicating error or success * */ int ftp_cmd_lookup_init(CMD_LOOKUP **CmdLookup) { KMAP *km = KMapNew((KMapUserFreeFunc)FTPTelnetCleanupFTPCMDConf); *CmdLookup = km; if(*CmdLookup == NULL) { return FTPP_MEM_ALLOC_FAIL; } km->nocase = 1; return FTPP_SUCCESS; } /* * Function: ftp_cmd_lookup_cleanup(CMD_LOOKUP **CmdLookup) * * Purpose: Free the cmd_lookup structure. * We need to free the cmd_lookup structure. * * Arguments: CmdLookup => pointer to the pointer of the cmd * lookup structure. * * Returns: int => return code indicating error or success * */ int ftp_cmd_lookup_cleanup(CMD_LOOKUP **CmdLookup) { KMAP *km; if (CmdLookup == NULL) return FTPP_INVALID_ARG; km = *CmdLookup; if (km) { KMapDelete(km); *CmdLookup = NULL; } return FTPP_SUCCESS; } /* * Function: ftp_cmd_lookup_add(CMD_LOOKUP *CmdLookup, * char *ip, int len, * FTP_CMD_CONF *FTPCmd) * * Purpose: Add a cmd configuration to the list. * We add these keys like you would normally think to add * them, because on low endian machines the least significant * byte is compared first. This is what we want to compare * IPs backward, doesn't work on high endian machines, but oh * well. Our platform is Intel. * * Arguments: CmdLookup => a pointer to the lookup structure * cmd => the ftp cmd * len => Length of the cmd * FTPCmd => a pointer to the cmd configuration structure * * Returns: int => return code indicating error or success * */ int ftp_cmd_lookup_add(CMD_LOOKUP *CmdLookup, char *cmd, int len, FTP_CMD_CONF *FTPCmd) { int iRet; if(!CmdLookup || !FTPCmd) { return FTPP_INVALID_ARG; } iRet = KMapAdd(CmdLookup, (void *)cmd, len, (void *)FTPCmd); if (iRet) { /* * This means the key has already been added. */ if(iRet == 1) { return FTPP_NONFATAL_ERR; } else { return FTPP_MEM_ALLOC_FAIL; } } return FTPP_SUCCESS; } /* * Function: ftp_cmd_lookup_find(CMD_LOOKUP *CmdLookup, * char *ip, int len, * int *iError) * * Purpose: Find a cmd configuration given a IP. * We look up a cmd configuration given an FTP cmd and * return a pointer to that cmd configuration if found. * * Arguments: CmdLookup => a pointer to the lookup structure * cmd => the ftp cmd * len => Length of the cmd * iError => a pointer to an error code * * Returns: int => return code indicating error or success * * Returns: FTP_CMD_CONF* => Pointer to cmd configuration structure * matching IP if found, NULL otherwise. * */ FTP_CMD_CONF *ftp_cmd_lookup_find(CMD_LOOKUP *CmdLookup, const char *cmd, int len, int *iError) { FTP_CMD_CONF *FTPCmd = NULL; if(!iError) { return NULL; } if(!CmdLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; FTPCmd = (FTP_CMD_CONF *)KMapFind(CmdLookup,(void *)cmd,len); if (!FTPCmd) { *iError = FTPP_NOT_FOUND; } return FTPCmd; } /* * Function: ftp_cmd_lookup_first(CMD_LOOKUP *CmdLookup, * int *iError) * * Purpose: This lookups the first cmd configuration, so we can * iterate through the configurations. * * Arguments: CmdLookup => pointer to the cmd lookup structure * iError => pointer to the integer to set for errors * * Returns: FTP_CMD_CONF* => Pointer to first cmd configuration structure * */ FTP_CMD_CONF *ftp_cmd_lookup_first(CMD_LOOKUP *CmdLookup, int *iError) { FTP_CMD_CONF *FTPCmd; if(!iError) { return NULL; } if(!CmdLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; FTPCmd = (FTP_CMD_CONF *)KMapFindFirst(CmdLookup); if (!FTPCmd) { *iError = FTPP_NOT_FOUND; } return FTPCmd; } /* * Function: ftp_cmd_lookup_next(CMD_LOOKUP *CmdLookup, * int *iError) * * Iterates to the next configuration, like a list it just returns * the next config in the config list. * * Purpose: This lookups the next cmd configuration, so we can * iterate through the configurations. * * Arguments: CmdLookup => pointer to the cmd lookup structure * iError => pointer to the integer to set for errors * * Returns: FTP_CMD_CONF* => Pointer to next cmd configuration structure * */ FTP_CMD_CONF *ftp_cmd_lookup_next(CMD_LOOKUP *CmdLookup, int *iError) { FTP_CMD_CONF *FTPCmd; if(!iError) { return NULL; } if(!CmdLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; FTPCmd = (FTP_CMD_CONF *)KMapFindNext(CmdLookup); if (!FTPCmd) { *iError = FTPP_NOT_FOUND; } return FTPCmd; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftp_client.h0000644000000000000000000000372512260565732021370 00000000000000/* * ftp_client.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * Header file for FTPTelnet FTP Client Module * * This file defines the client reqest structure and functions * to access client inspection. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __FTP_CLIENT_H__ #define __FTP_CLIENT_H__ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "ftpp_include.h" typedef struct s_FTP_CLIENT_REQ { const char *cmd_line; unsigned int cmd_line_size; const char *cmd_begin; const char *cmd_end; unsigned int cmd_size; const char *param_begin; const char *param_end; unsigned int param_size; const char *pipeline_req; } FTP_CLIENT_REQ; typedef struct s_FTP_CLIENT { FTP_CLIENT_REQ request; int (*state)(void *, unsigned char, int); } FTP_CLIENT; int ftp_client_inspection(void *Session, unsigned char *data, int dsize); int ftp_client_init(FTPTELNET_GLOBAL_CONF *GlobalConf); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftp_bounce_lookup.h0000644000000000000000000000346512260565732022757 00000000000000/* * ftp_bounce_lookup.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains function definitions for bounce IP lookups. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #ifndef __FTP_BOUNCE_LOOKUP_H__ #define __FTP_BOUNCE_LOOKUP_H__ #include "ftpp_include.h" #include "ftpp_ui_config.h" int ftp_bounce_lookup_init(BOUNCE_LOOKUP **BounceLookup); int ftp_bounce_lookup_cleanup(BOUNCE_LOOKUP **BounceLookup); int ftp_bounce_lookup_add(BOUNCE_LOOKUP *BounceLookup, snort_ip_p ip, FTP_BOUNCE_TO *BounceTo); FTP_BOUNCE_TO *ftp_bounce_lookup_find(BOUNCE_LOOKUP *BounceLookup, snort_ip_p ip, int *iError); FTP_BOUNCE_TO *ftp_bounce_lookup_first(BOUNCE_LOOKUP *BounceLookup, int *iError); FTP_BOUNCE_TO *ftp_bounce_lookup_next(BOUNCE_LOOKUP *BounceLookup, int *iError); #endif snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/ftp_bounce_lookup.c0000644000000000000000000001654212260565732022752 00000000000000/* * ftp_bounce_lookup.c * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2004-2013 Sourcefire, Inc. * Steven A. Sturges * Daniel J. Roelker * Marc A. Norton * Kevin Liu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file contains functions to access the BOUNCE_LOOKUP structure. * * We wrap the access to BOUNCE_LOOKUP so changing the lookup algorithms * are more modular and independent. This is the only file that would need * to be changed to change the algorithmic lookup. * * NOTES: * - 16.09.04: Initial Development. SAS * */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_util_kmap.h" #include "ftpp_ui_config.h" #include "ftpp_return_codes.h" #include "snort_ftptelnet.h" /* * Function: ftp_bounce_lookup_init(BOUNCE_LOOKUP **BounceLookup) * * Purpose: Initialize the bounce_lookup structure. * * We need to initialize the bounce_lookup structure for * the FTP bounce configuration. Don't want a NULL pointer * flying around, when we have to look for allowable bounces. * * Arguments: BounceLookup => pointer to the pointer of the bounce * lookup structure. * * Returns: int => return code indicating error or success * */ int ftp_bounce_lookup_init(BOUNCE_LOOKUP **BounceLookup) { KMAP *km = KMapNew((KMapUserFreeFunc)FTPTelnetCleanupFTPBounceTo); *BounceLookup = km; if(*BounceLookup == NULL) { return FTPP_MEM_ALLOC_FAIL; } km->nocase = 1; return FTPP_SUCCESS; } /* * Function: ftp_bounce_lookup_cleanup(BOUNCE_LOOKUP **BounceLookup) * * Purpose: Free the bounce_lookup structure. * We need to free the bounce_lookup structure. * * Arguments: BounceLookup => pointer to the pointer of the bounce * lookup structure. * * Returns: int => return code indicating error or success * */ int ftp_bounce_lookup_cleanup(BOUNCE_LOOKUP **BounceLookup) { KMAP *km; if (BounceLookup == NULL) return FTPP_INVALID_ARG; km = *BounceLookup; if (km) { KMapDelete(km); *BounceLookup = NULL; } return FTPP_SUCCESS; } /* * Function: ftp_bounce_lookup_add(BOUNCE_LOOKUP *BounceLookup, * char *ip, int len, * FTP_BOUNCE_TO *BounceTo) * * Purpose: Add a bounce configuration to the list. IP is stored * in dot notation order. When the lookup happens, we * compare up to len bytes of the address. * * Arguments: BounceLookup => a pointer to the lookup structure * IP => the ftp bounce address * BounceTo => a pointer to the bounce configuration structure * * Returns: int => return code indicating error or success * */ int ftp_bounce_lookup_add(BOUNCE_LOOKUP *BounceLookup, snort_ip_p Ip, FTP_BOUNCE_TO *BounceTo) { int iRet; if(!BounceLookup || !BounceTo) { return FTPP_INVALID_ARG; } iRet = KMapAdd(BounceLookup, (void*)IP_PTR(Ip), IP_SIZE(Ip), (void*)BounceTo); if (iRet) { /* * This means the key has already been added. */ if(iRet == 1) { return FTPP_NONFATAL_ERR; } else { return FTPP_MEM_ALLOC_FAIL; } } return FTPP_SUCCESS; } /* * Function: ftp_bounce_lookup_find(BOUNCE_LOOKUP *BounceLookup, * snort_ip_p ip, int *iError) * * Purpose: Find a bounce configuration given a IP. * We look up a bounce configuration given an IP and * return a pointer to that bounce configuration if found. * * Arguments: BounceLookup => a pointer to the lookup structure * IP => the ftp bounce address * iError => a pointer to an error code * * Returns: int => return code indicating error or success * * Returns: FTP_BOUNCE_TO* => Pointer to bounce configuration structure * matching IP if found, NULL otherwise. * */ FTP_BOUNCE_TO *ftp_bounce_lookup_find( BOUNCE_LOOKUP *BounceLookup, snort_ip_p Ip, int *iError ) { FTP_BOUNCE_TO *BounceTo = NULL; if(!iError) { return NULL; } if(!BounceLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; BounceTo = (FTP_BOUNCE_TO *)KMapFind(BounceLookup, (void*)IP_PTR(Ip), IP_SIZE(Ip)); if (!BounceTo) { *iError = FTPP_NOT_FOUND; } return BounceTo; } /* * Function: ftp_bounce_lookup_first(BOUNCE_LOOKUP *BounceLookup, * int *iError) * * Purpose: This lookups the first bounce configuration, so we can * iterate through the configurations. * * Arguments: BounceLookup => pointer to the bounce lookup structure * iError => pointer to the integer to set for errors * * Returns: FTP_BOUNCE_TO* => Pointer to first bounce configuration structure * */ FTP_BOUNCE_TO *ftp_bounce_lookup_first(BOUNCE_LOOKUP *BounceLookup, int *iError) { FTP_BOUNCE_TO *BounceTo; if(!iError) { return NULL; } if(!BounceLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; BounceTo = (FTP_BOUNCE_TO *)KMapFindFirst(BounceLookup); if (!BounceTo) { *iError = FTPP_NOT_FOUND; } return BounceTo; } /* * Function: ftp_bounce_lookup_next(BOUNCE_LOOKUP *BounceLookup, * int *iError) * * Iterates to the next configuration, like a list it just returns * the next config in the config list. * * Purpose: This lookups the next bounce configuration, so we can * iterate through the configurations. * * Arguments: BounceLookup => pointer to the bounce lookup structure * iError => pointer to the integer to set for errors * * Returns: FTP_BOUNCE_TO* => Pointer to next bounce configuration structure * */ FTP_BOUNCE_TO *ftp_bounce_lookup_next(BOUNCE_LOOKUP *BounceLookup, int *iError) { FTP_BOUNCE_TO *BounceTo; if(!iError) { return NULL; } if(!BounceLookup) { *iError = FTPP_INVALID_ARG; return NULL; } *iError = FTPP_SUCCESS; BounceTo = (FTP_BOUNCE_TO *)KMapFindNext(BounceLookup); if (!BounceTo) { *iError = FTPP_NOT_FOUND; } return BounceTo; } snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/Makefile.am0000644000000000000000000000242211746560364021121 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor lib_LTLIBRARIES = libsf_ftptelnet_preproc.la libsf_ftptelnet_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ if SO_WITH_STATIC_LIB libsf_ftptelnet_preproc_la_LIBADD = ../libsf_dynamic_preproc.la else nodist_libsf_ftptelnet_preproc_la_SOURCES = \ ../include/sf_dynamic_preproc_lib.c \ ../include/sf_ip.c \ ../include/sfrt.c \ ../include/sfrt_dir.c \ ../include/sfPolicyUserData.c endif libsf_ftptelnet_preproc_la_SOURCES = \ ftp_bounce_lookup.c \ ftp_bounce_lookup.h \ ftp_client.h \ ftp_cmd_lookup.c \ ftp_cmd_lookup.h \ ftpp_eo_events.h \ ftpp_eo.h \ ftpp_eo_log.c \ ftpp_eo_log.h \ ftpp_include.h \ ftpp_return_codes.h \ ftpp_si.c \ ftpp_si.h \ ftpp_ui_client_lookup.c \ ftpp_ui_client_lookup.h \ ftpp_ui_config.c \ ftpp_ui_config.h \ ftpp_ui_server_lookup.c \ ftpp_ui_server_lookup.h \ ftp_server.h \ hi_util_kmap.c \ hi_util_kmap.h \ hi_util_xmalloc.c \ hi_util_xmalloc.h \ pp_ftp.c \ pp_ftp.h \ pp_telnet.c \ pp_telnet.h \ snort_ftptelnet.c \ snort_ftptelnet.h \ spp_ftptelnet.c \ spp_ftptelnet.h EXTRA_DIST = \ sf_ftptelnet.dsp all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES snort-2.9.6.0/src/dynamic-preprocessors/ftptelnet/Makefile.in0000644000000000000000000005446512260606521021134 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/ftptelnet DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@libsf_ftptelnet_preproc_la_DEPENDENCIES = \ @SO_WITH_STATIC_LIB_TRUE@ ../libsf_dynamic_preproc.la am_libsf_ftptelnet_preproc_la_OBJECTS = ftp_bounce_lookup.lo \ ftp_cmd_lookup.lo ftpp_eo_log.lo ftpp_si.lo \ ftpp_ui_client_lookup.lo ftpp_ui_config.lo \ ftpp_ui_server_lookup.lo hi_util_kmap.lo hi_util_xmalloc.lo \ pp_ftp.lo pp_telnet.lo snort_ftptelnet.lo spp_ftptelnet.lo @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_ftptelnet_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_FALSE@ sf_dynamic_preproc_lib.lo sf_ip.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfrt.lo sfrt_dir.lo \ @SO_WITH_STATIC_LIB_FALSE@ sfPolicyUserData.lo libsf_ftptelnet_preproc_la_OBJECTS = \ $(am_libsf_ftptelnet_preproc_la_OBJECTS) \ $(nodist_libsf_ftptelnet_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_ftptelnet_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsf_ftptelnet_preproc_la_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_ftptelnet_preproc_la_SOURCES) \ $(nodist_libsf_ftptelnet_preproc_la_SOURCES) DIST_SOURCES = $(libsf_ftptelnet_preproc_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I../include -I${srcdir}/../libs -I$(srcdir)/includes INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = ${exec_prefix}/lib/snort_dynamicpreprocessor libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies lib_LTLIBRARIES = libsf_ftptelnet_preproc.la libsf_ftptelnet_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@ @SO_WITH_STATIC_LIB_TRUE@libsf_ftptelnet_preproc_la_LIBADD = ../libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_FALSE@nodist_libsf_ftptelnet_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sf_ip.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfrt.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfrt_dir.c \ @SO_WITH_STATIC_LIB_FALSE@../include/sfPolicyUserData.c libsf_ftptelnet_preproc_la_SOURCES = \ ftp_bounce_lookup.c \ ftp_bounce_lookup.h \ ftp_client.h \ ftp_cmd_lookup.c \ ftp_cmd_lookup.h \ ftpp_eo_events.h \ ftpp_eo.h \ ftpp_eo_log.c \ ftpp_eo_log.h \ ftpp_include.h \ ftpp_return_codes.h \ ftpp_si.c \ ftpp_si.h \ ftpp_ui_client_lookup.c \ ftpp_ui_client_lookup.h \ ftpp_ui_config.c \ ftpp_ui_config.h \ ftpp_ui_server_lookup.c \ ftpp_ui_server_lookup.h \ ftp_server.h \ hi_util_kmap.c \ hi_util_kmap.h \ hi_util_xmalloc.c \ hi_util_xmalloc.h \ pp_ftp.c \ pp_ftp.h \ pp_telnet.c \ pp_telnet.h \ snort_ftptelnet.c \ snort_ftptelnet.h \ spp_ftptelnet.c \ spp_ftptelnet.h EXTRA_DIST = \ sf_ftptelnet.dsp all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/ftptelnet/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/ftptelnet/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_ftptelnet_preproc.la: $(libsf_ftptelnet_preproc_la_OBJECTS) $(libsf_ftptelnet_preproc_la_DEPENDENCIES) $(EXTRA_libsf_ftptelnet_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_ftptelnet_preproc_la_LINK) -rpath $(libdir) $(libsf_ftptelnet_preproc_la_OBJECTS) $(libsf_ftptelnet_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< sf_dynamic_preproc_lib.lo: ../include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_dynamic_preproc_lib.lo `test -f '../include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`../include/sf_dynamic_preproc_lib.c sf_ip.lo: ../include/sf_ip.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sf_ip.lo `test -f '../include/sf_ip.c' || echo '$(srcdir)/'`../include/sf_ip.c sfrt.lo: ../include/sfrt.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfrt.lo `test -f '../include/sfrt.c' || echo '$(srcdir)/'`../include/sfrt.c sfrt_dir.lo: ../include/sfrt_dir.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfrt_dir.lo `test -f '../include/sfrt_dir.c' || echo '$(srcdir)/'`../include/sfrt_dir.c sfPolicyUserData.lo: ../include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sfPolicyUserData.lo `test -f '../include/sfPolicyUserData.c' || echo '$(srcdir)/'`../include/sfPolicyUserData.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) all-local installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am all-local check check-am clean \ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/../build install-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/treenodes.sed0000644000000000000000000000051311314032573017527 00000000000000s/Packet /SFSnortPacket / s/rules\.h/signature.h/ /signature.h/ a\ #include "sf_snort_packet.h" \ #include "event.h" s/RspFpList/void/ s/OutputFuncNode/void/ s/TagData/void/ s/RuleType/int/ s/IpAddrSet/void/ s/PortObject/void/ s/ActivateListNode/void/ s/struct _ListHead/void/ /sfutil\/sfghash\.h/d /sf_types\.h/d s/SFGHASH/void/g snort-2.9.6.0/src/dynamic-preprocessors/dynamic_preprocessors.dsp0000644000000000000000000000365112026730051022172 00000000000000# Microsoft Developer Studio Project File - Name="dynamic_preprocessors" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Generic Project" 0x010a CFG=dynamic_preprocessors - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "dynamic_preprocessors.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "dynamic_preprocessors.mak" CFG="dynamic_preprocessors - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "dynamic_preprocessors - Win32 Release" (based on "Win32 (x86) Generic Project") !MESSAGE "dynamic_preprocessors - Win32 Debug" (based on "Win32 (x86) Generic Project") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" MTL=midl.exe !IF "$(CFG)" == "dynamic_preprocessors - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "dynamic_preprocessors - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" !ENDIF # Begin Target # Name "dynamic_preprocessors - Win32 Release" # Name "dynamic_preprocessors - Win32 Debug" # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/Makefile.am0000644000000000000000000004261112232305217017101 00000000000000## $Id$ AUTOMAKE_OPTIONS=foreign no-dependencies INCLUDES = -I${top_builddir}/src/dynamic-preprocessors/include -I${top_srcdir}/src/dynamic-preprocessors/libs if SO_WITH_STATIC_LIB preproclibdir=$(pkglibdir)/dynamic_preproc preproclib_LTLIBRARIES = libsf_dynamic_preproc.la libsf_dynamic_preproc_la_CFLAGS = -fPIC -DPIC libsf_dynamic_preproc_la_LDFLAGS = -static nodist_libsf_dynamic_preproc_la_SOURCES = \ include/sf_dynamic_preproc_lib.c \ include/sf_ip.c \ include/sfrt.c \ include/sfrt_dir.c \ include/sfrt_flat.c \ include/sfrt_flat_dir.c \ include/segment_mem.c \ include/mempool.c \ include/sf_sdlist.c \ include/sfPolicyUserData.c \ include/util_unfold.c \ include/sf_base64decode.c \ include/sf_email_attach_decode.c libsf_dynamic_preproc_la_SOURCES = \ libs/ssl.c \ libs/sfparser.c preprocdir=$(pkgincludedir)/dynamic_preproc nodist_preproc_HEADERS = \ libs/ssl.h \ libs/sfcommon.h \ libs/sf_preproc_info.h \ include/sf_snort_packet.h \ include/sf_protocols.h \ include/sf_snort_plugin_api.h \ include/sf_decompression.h \ include/sfPolicyUserData.h \ include/snort_debug.h \ include/snort_bounds.h \ include/cpuclock.h \ include/profiler.h \ include/bitop.h \ include/mempool.h \ include/sf_sdlist_types.h \ include/sf_ip.h \ include/sfrt_flat.h \ include/sfrt_flat_dir.h \ include/segment_mem.h \ include/sf_dynamic_common.h \ include/sf_dynamic_engine.h \ include/sf_dynamic_define.h \ include/sf_dynamic_meta.h \ include/sf_dynamic_preprocessor.h \ include/sf_dynamic_preproc_lib.h \ include/ipv6_port.h \ include/sfPolicy.h \ include/sfrt.h \ include/sfrt_dir.h \ include/sfrt_trie.h \ include/obfuscation.h \ include/stream_api.h \ include/str_search.h \ include/preprocids.h \ include/sfcontrol.h \ include/idle_processing.h \ include/sf_seqnums.h \ include/file_api.h all-local: $(LTLIBRARIES) $(MAKE) DESTDIR=`pwd`/build install-preproclibLTLIBRARIES endif BUILT_SOURCES = \ include/snort_bounds.h \ include/snort_debug.h \ include/preprocids.h \ include/profiler.h \ include/cpuclock.h \ include/sf_dynamic_common.h \ include/sf_dynamic_engine.h \ include/sf_dynamic_define.h \ include/sf_dynamic_meta.h \ include/sf_dynamic_preprocessor.h \ include/sf_dynamic_preproc_lib.c \ include/sf_dynamic_preproc_lib.h \ include/sfghash.h \ include/sfhashfcn.h \ include/bitop.h \ include/sf_ip.h \ include/sf_ip.c \ include/sf_ipvar.h \ include/sf_vartable.h \ include/ipv6_port.h \ include/sfsnort_dynamic_detection_lib.c \ include/sfsnort_dynamic_detection_lib.h \ include/sf_snort_packet.h \ include/sf_protocols.h \ include/sf_snort_plugin_api.h \ include/sf_decompression.h \ include/pcap_pkthdr32.h \ include/stream_api.h \ include/str_search.h \ include/sf_types.h \ include/sfrt.h \ include/sfrt.c \ include/sfrt_dir.h \ include/sfrt_dir.c \ include/sfrt_flat.h \ include/sfrt_flat.c \ include/sfrt_flat_dir.h \ include/sfrt_flat_dir.c \ include/sfrt_trie.h \ include/segment_mem.h \ include/segment_mem.c \ include/mempool.h \ include/mempool.c \ include/sf_sdlist.h \ include/sf_sdlist_types.h \ include/sf_sdlist.c \ include/sfPolicyUserData.c \ include/sfPolicyUserData.h \ include/sfPolicy.h \ include/util_unfold.h \ include/util_unfold.c \ include/sf_base64decode.h \ include/sf_base64decode.c \ include/sf_email_attach_decode.h \ include/sf_email_attach_decode.c \ include/treenodes.h \ include/signature.h \ include/plugin_enum.h \ include/obfuscation.h \ include/rule_option_types.h \ include/event.h \ include/Unified2_common.h \ include/sfcontrol.h \ include/idle_processing.h \ include/sf_seqnums.h \ include/file_api.h sed_ipv6_headers = \ sed -e "s/->iph->ip_src/->ip4_header->source/" \ -e "s/->iph->ip_dst/->ip4_header->destination/" \ -e "s/->iph->/->ip4_header->/" \ -e "s/->iph$$/->ip4_header/" \ -e "s/orig_iph/orig_ipv4h/" \ -e "s/ip_verhl/version_headerlength/" \ -e "s/ip_tos/type_service/" \ -e "s/ip_len/data_length/" \ -e "s/ip_id/identifier/" \ -e "s/ip_off/offset/" \ -e "s/ip_ttl/time_to_live/" \ -e "s/ip_proto/proto/" \ -e "s/ip_csum/checksum/" \ $$dst_header.new > $$dst_header massage_ipv6_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_ipv6_headers); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_ipv6_headers); \ fi sed_headers = \ sed -e "s/Packet /SFSnortPacket /" \ -e "s/SnortPktHdr /SFSnortPktHdr /" \ -e "s/decode\.h/sf_snort_packet.h/" \ -e "/sfportobject\.h/d" \ -e "s/PortObject \*/void */g" \ $$dst_header.new > $$dst_header massage_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_headers); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_headers); \ fi sed_debug_header = \ sed -e "s/DebugMessageFile = /*_dpd.debugMsgFile = /" \ -e "s/DebugMessageLine = /*_dpd.debugMsgLine = /" \ -e "s/; DebugMessageFunc$$/; _dpd.debugMsg/" \ -e "s/; DebugWideMessageFunc$$/; _dpd.debugWideMsg/" \ $$dst_header.new > $$dst_header copy_debug_header = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_debug_header); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_debug_header); \ fi copy_error_message = \ if test -f $$dst_header; then \ sed -e "s/ErrorMessage/_dpd.errMsg/" \ -e "s/LogMessage /_dpd.logMsg /" \ -e "/util.h/d" \ $$dst_header > $$dst_header.new; \ mv $$dst_header.new $$dst_header; \ fi replace_policy_globals = \ if test -f $$dst_header; then \ sed -e "/SharedObjectAddStarts/d" \ -e "/SharedObjectAddEnds/d" \ -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" \ -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" \ -e "s/SnortStrnStr/_dpd.SnortStrnStr/" \ $$dst_header > $$dst_header.new; \ mv $$dst_header.new $$dst_header; \ fi copy_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi sed_treenode_header = \ sed -f $(srcdir)/treenodes.sed $$dst_header.new > $$dst_header copy_treenode_header = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_treenode_header); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_treenode_header); \ fi # From main src tree include/snort_debug.h: $(srcdir)/../snort_debug.h @src_header=$?; dst_header=$@; $(copy_debug_header) include/preprocids.h: $(srcdir)/../preprocids.h @src_header=$?; dst_header=$@; $(copy_headers) include/profiler.h: $(srcdir)/../profiler.h @src_header=$?; dst_header=$@; $(copy_headers) include/cpuclock.h: $(srcdir)/../cpuclock.h @src_header=$?; dst_header=$@; $(copy_headers) include/pcap_pkthdr32.h: $(srcdir)/../pcap_pkthdr32.h @src_header=$?; dst_header=$@; $(copy_headers) include/snort_bounds.h: $(srcdir)/../snort_bounds.h @src_header=$?; dst_header=$@; $(copy_headers) include/ipv6_port.h: $(srcdir)/../ipv6_port.h @src_header=$?; dst_header=$@; $(massage_ipv6_headers) include/sf_types.h: $(srcdir)/../sf_types.h @src_header=$?; dst_header=$@; $(copy_headers) include/obfuscation.h: $(srcdir)/../obfuscation.h @src_header=$?; dst_header=$@; $(massage_headers) include/rule_option_types.h: $(srcdir)/../rule_option_types.h @src_header=$?; dst_header=$@; $(copy_headers) include/event.h: $(srcdir)/../event.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins include/sf_dynamic_common.h: $(srcdir)/../dynamic-plugins/sf_dynamic_common.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_engine.h: $(srcdir)/../dynamic-plugins/sf_dynamic_engine.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_define.h: $(srcdir)/../dynamic-plugins/sf_dynamic_define.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_meta.h: $(srcdir)/../dynamic-plugins/sf_dynamic_meta.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_preprocessor.h: $(srcdir)/../dynamic-plugins/sf_dynamic_preprocessor.h @src_header=$?; dst_header=$@; $(massage_headers) # From dynamic-plugins/sf_preproc_example include/sf_dynamic_preproc_lib.c: $(srcdir)/../dynamic-plugins/sf_preproc_example/sf_dynamic_preproc_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_preproc_lib.h: $(srcdir)/../dynamic-plugins/sf_preproc_example/sf_dynamic_preproc_lib.h @src_header=$?; dst_header=$@; $(copy_headers) # From Utils include/sfghash.h: $(srcdir)/../sfutil/sfghash.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfhashfcn.h: $(srcdir)/../sfutil/sfhashfcn.h @src_header=$?; dst_header=$@; $(copy_headers) include/bitop.h: $(srcdir)/../sfutil/bitop.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ip.h: $(srcdir)/../sfutil/sf_ip.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ip.c: $(srcdir)/../sfutil/sf_ip.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ipvar.h: $(srcdir)/../sfutil/sf_ipvar.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_vartable.h: $(srcdir)/../sfutil/sf_vartable.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt.h: $(srcdir)/../sfutil/sfrt.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt.c: $(srcdir)/../sfutil/sfrt.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_dir.h: $(srcdir)/../sfutil/sfrt_dir.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_dir.c: $(srcdir)/../sfutil/sfrt_dir.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_flat.h: $(srcdir)/../sfutil/sfrt_flat.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_flat.c: $(srcdir)/../sfutil/sfrt_flat.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_flat_dir.h: $(srcdir)/../sfutil/sfrt_flat_dir.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_flat_dir.c: $(srcdir)/../sfutil/sfrt_flat_dir.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_trie.h: $(srcdir)/../sfutil/sfrt_trie.h @src_header=$?; dst_header=$@; $(copy_headers) include/segment_mem.c: $(srcdir)/../sfutil/segment_mem.c @src_header=$?; dst_header=$@; $(copy_headers) include/segment_mem.h: $(srcdir)/../sfutil/segment_mem.h @src_header=$?; dst_header=$@; $(copy_headers) include/mempool.h: $(srcdir)/../mempool.h @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/mempool.c: $(srcdir)/../mempool.c @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/sf_sdlist.h: $(srcdir)/../sf_sdlist.h @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/sf_sdlist_types.h: $(srcdir)/../sf_sdlist_types.h @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/sf_sdlist.c: $(srcdir)/../sf_sdlist.c @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/sfPolicyUserData.c: $(srcdir)/../sfutil/sfPolicyUserData.c @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/sfPolicyUserData.h: $(srcdir)/../sfutil/sfPolicyUserData.h @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/sfPolicy.h: $(srcdir)/../sfutil/sfPolicy.h @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/util_unfold.h: $(srcdir)/../sfutil/util_unfold.h @src_header=$?; dst_header=$@; $(copy_headers) include/util_unfold.c: $(srcdir)/../sfutil/util_unfold.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_base64decode.h: $(srcdir)/../sfutil/sf_base64decode.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_base64decode.c: $(srcdir)/../sfutil/sf_base64decode.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_email_attach_decode.h: $(srcdir)/../sfutil/sf_email_attach_decode.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_email_attach_decode.c: $(srcdir)/../sfutil/sf_email_attach_decode.c @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/Unified2_common.h: $(srcdir)/../sfutil/Unified2_common.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins/sf_engine/examples include/sfsnort_dynamic_detection_lib.c: $(srcdir)/../dynamic-plugins/sf_engine/examples/sfsnort_dynamic_detection_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfsnort_dynamic_detection_lib.h: $(srcdir)/../dynamic-plugins/sf_engine/examples/sfsnort_dynamic_detection_lib.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins/sf_engine include/sf_snort_packet.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_snort_packet.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_protocols.h: $(srcdir)/../sf_protocols.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_snort_plugin_api.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_snort_plugin_api.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_decompression.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_decompression.h @src_header=$?; dst_header=$@; $(copy_headers) # Stream API/String Searching, massage it to use SFSnortPacket include/stream_api.h: $(srcdir)/../preprocessors/stream_api.h @src_header=$?; dst_header=$@; $(massage_headers) include/str_search.h: $(srcdir)/../preprocessors/str_search.h @src_header=$?; dst_header=$@; $(massage_headers) include/treenodes.h: $(srcdir)/../treenodes.h @src_header=$?; dst_header=$@; $(copy_treenode_header) include/signature.h: $(srcdir)/../signature.h @src_header=$?; dst_header=$@; $(copy_treenode_header) include/plugin_enum.h: $(srcdir)/../plugin_enum.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfcontrol.h: $(top_srcdir)/src/control/sfcontrol.h @src_header=$?; dst_header=$@; $(copy_headers) include/idle_processing.h: $(top_srcdir)/src/idle_processing.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_seqnums.h: $(top_srcdir)/src/sfutil/sf_seqnums.h @src_header=$?; dst_header=$@; $(copy_headers) include/file_api.h: $(top_srcdir)/src/file-process/file_api.h @src_header=$?; dst_header=$@; $(copy_headers) if WANT_SF_SAAC RZB_SAAC_DIR=rzb_saac endif if FEAT_FILE_INSPECT FILE_INSPECT_DIR = file endif SUBDIRS = . libs ftptelnet pop imap smtp ssh dns ssl dcerpc2 sdf sip reputation gtp modbus dnp3 $(RZB_SAAC_DIR) $(FILE_INSPECT_DIR) clean-local: rm -rf include build EXTRA_DIST = \ dynamic_preprocessors.dsp \ sf_dynamic_initialize/sf_dynamic_initialize.dsp \ treenodes.sed srcinstdir = $(exec_prefix)/src/snort_dynamicsrc exported_files = \ include/sf_dynamic_common.h \ include/sf_dynamic_define.h \ include/sf_dynamic_engine.h \ include/sf_dynamic_meta.h \ include/sf_dynamic_preprocessor.h \ include/sf_dynamic_preproc_lib.h \ include/sf_dynamic_preproc_lib.c \ include/sf_ip.h \ include/sf_snort_packet.h \ include/sf_protocols.h \ include/sf_snort_plugin_api.h \ include/sf_decompression.h \ include/sf_types.h \ include/sfsnort_dynamic_detection_lib.h \ include/sfsnort_dynamic_detection_lib.c \ include/pcap_pkthdr32.h \ include/str_search.h \ include/stream_api.h \ include/snort_debug.h \ include/profiler.h \ include/sfghash.h \ include/sfhashfcn.h \ include/bitop.h \ include/preprocids.h \ include/sfPolicyUserData.h \ include/util_unfold.h \ include/util_unfold.c \ include/sf_base64decode.h \ include/sf_base64decode.c \ include/sf_email_attach_decode.h \ include/sf_email_attach_decode.c \ include/treenodes.h \ include/signature.h \ include/plugin_enum.h \ include/sfPolicyUserData.c \ include/obfuscation.h \ include/rule_option_types.h \ include/event.h \ include/Unified2_common.h \ include/sfcontrol.h \ include/idle_processing.h \ include/sf_seqnums.h \ include/file_api.h install-data-local: @for f in $(exported_files); do \ ## Compute the filename only truefile=`echo $$f | sed -e "s/.*\///"`; \ ## Make the install directory. $(mkinstalldirs) $(DESTDIR)$(srcinstdir); \ ## Find the header file -- in our case it might be in srcdir or ## it might be in the build directory. "p" is the variable that ## names the actual file we will install. if test -f $(srcdir)/$$f; then p=$(srcdir)/$$f; else p=$$f; fi; \ ## Actually install the file. $(INSTALL_DATA) $$p $(DESTDIR)$(srcinstdir)/$$truefile; \ done uninstall-local: @for f in $(exported_files); do \ ## Compute the filename only truefile=`echo $$f | sed -e "s/.*\///"`; \ ## Make the install directory. $(mkinstalldirs) $(DESTDIR)$(srcinstdir); \ ## Actually install the file. rm -f $(DESTDIR)$(srcinstdir)/$$truefile; \ done snort-2.9.6.0/src/dynamic-preprocessors/Makefile.in0000644000000000000000000014423712260606521017124 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(preproclibdir)" \ "$(DESTDIR)$(preprocdir)" LTLIBRARIES = $(preproclib_LTLIBRARIES) libsf_dynamic_preproc_la_LIBADD = am__libsf_dynamic_preproc_la_SOURCES_DIST = libs/ssl.c libs/sfparser.c @SO_WITH_STATIC_LIB_TRUE@am_libsf_dynamic_preproc_la_OBJECTS = \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-ssl.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sfparser.lo @SO_WITH_STATIC_LIB_TRUE@nodist_libsf_dynamic_preproc_la_OBJECTS = libsf_dynamic_preproc_la-sf_dynamic_preproc_lib.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sf_ip.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sfrt.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sfrt_dir.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sfrt_flat.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sfrt_flat_dir.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-segment_mem.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-mempool.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sf_sdlist.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sfPolicyUserData.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-util_unfold.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sf_base64decode.lo \ @SO_WITH_STATIC_LIB_TRUE@ libsf_dynamic_preproc_la-sf_email_attach_decode.lo libsf_dynamic_preproc_la_OBJECTS = \ $(am_libsf_dynamic_preproc_la_OBJECTS) \ $(nodist_libsf_dynamic_preproc_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsf_dynamic_preproc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) \ $(libsf_dynamic_preproc_la_LDFLAGS) $(LDFLAGS) -o $@ @SO_WITH_STATIC_LIB_TRUE@am_libsf_dynamic_preproc_la_rpath = -rpath \ @SO_WITH_STATIC_LIB_TRUE@ $(preproclibdir) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsf_dynamic_preproc_la_SOURCES) \ $(nodist_libsf_dynamic_preproc_la_SOURCES) DIST_SOURCES = $(am__libsf_dynamic_preproc_la_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(nodist_preproc_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = . libs ftptelnet pop imap smtp ssh dns ssl dcerpc2 sdf \ sip reputation gtp modbus dnp3 rzb_saac file DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = -I${top_builddir}/src/dynamic-preprocessors/include -I${top_srcdir}/src/dynamic-preprocessors/libs INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies @SO_WITH_STATIC_LIB_TRUE@preproclibdir = $(pkglibdir)/dynamic_preproc @SO_WITH_STATIC_LIB_TRUE@preproclib_LTLIBRARIES = libsf_dynamic_preproc.la @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_preproc_la_CFLAGS = -fPIC -DPIC @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_preproc_la_LDFLAGS = -static @SO_WITH_STATIC_LIB_TRUE@nodist_libsf_dynamic_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_TRUE@include/sf_dynamic_preproc_lib.c \ @SO_WITH_STATIC_LIB_TRUE@include/sf_ip.c \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt.c \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt_dir.c \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt_flat.c \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt_flat_dir.c \ @SO_WITH_STATIC_LIB_TRUE@include/segment_mem.c \ @SO_WITH_STATIC_LIB_TRUE@include/mempool.c \ @SO_WITH_STATIC_LIB_TRUE@include/sf_sdlist.c \ @SO_WITH_STATIC_LIB_TRUE@include/sfPolicyUserData.c \ @SO_WITH_STATIC_LIB_TRUE@include/util_unfold.c \ @SO_WITH_STATIC_LIB_TRUE@include/sf_base64decode.c \ @SO_WITH_STATIC_LIB_TRUE@include/sf_email_attach_decode.c @SO_WITH_STATIC_LIB_TRUE@libsf_dynamic_preproc_la_SOURCES = \ @SO_WITH_STATIC_LIB_TRUE@libs/ssl.c \ @SO_WITH_STATIC_LIB_TRUE@libs/sfparser.c @SO_WITH_STATIC_LIB_TRUE@preprocdir = $(pkgincludedir)/dynamic_preproc @SO_WITH_STATIC_LIB_TRUE@nodist_preproc_HEADERS = \ @SO_WITH_STATIC_LIB_TRUE@libs/ssl.h \ @SO_WITH_STATIC_LIB_TRUE@libs/sfcommon.h \ @SO_WITH_STATIC_LIB_TRUE@libs/sf_preproc_info.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_snort_packet.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_protocols.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_snort_plugin_api.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_decompression.h \ @SO_WITH_STATIC_LIB_TRUE@include/sfPolicyUserData.h \ @SO_WITH_STATIC_LIB_TRUE@include/snort_debug.h \ @SO_WITH_STATIC_LIB_TRUE@include/snort_bounds.h \ @SO_WITH_STATIC_LIB_TRUE@include/cpuclock.h \ @SO_WITH_STATIC_LIB_TRUE@include/profiler.h \ @SO_WITH_STATIC_LIB_TRUE@include/bitop.h \ @SO_WITH_STATIC_LIB_TRUE@include/mempool.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_sdlist_types.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_ip.h \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt_flat.h \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt_flat_dir.h \ @SO_WITH_STATIC_LIB_TRUE@include/segment_mem.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_dynamic_common.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_dynamic_engine.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_dynamic_define.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_dynamic_meta.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_dynamic_preprocessor.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_dynamic_preproc_lib.h \ @SO_WITH_STATIC_LIB_TRUE@include/ipv6_port.h \ @SO_WITH_STATIC_LIB_TRUE@include/sfPolicy.h \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt.h \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt_dir.h \ @SO_WITH_STATIC_LIB_TRUE@include/sfrt_trie.h \ @SO_WITH_STATIC_LIB_TRUE@include/obfuscation.h \ @SO_WITH_STATIC_LIB_TRUE@include/stream_api.h \ @SO_WITH_STATIC_LIB_TRUE@include/str_search.h \ @SO_WITH_STATIC_LIB_TRUE@include/preprocids.h \ @SO_WITH_STATIC_LIB_TRUE@include/sfcontrol.h \ @SO_WITH_STATIC_LIB_TRUE@include/idle_processing.h \ @SO_WITH_STATIC_LIB_TRUE@include/sf_seqnums.h \ @SO_WITH_STATIC_LIB_TRUE@include/file_api.h BUILT_SOURCES = \ include/snort_bounds.h \ include/snort_debug.h \ include/preprocids.h \ include/profiler.h \ include/cpuclock.h \ include/sf_dynamic_common.h \ include/sf_dynamic_engine.h \ include/sf_dynamic_define.h \ include/sf_dynamic_meta.h \ include/sf_dynamic_preprocessor.h \ include/sf_dynamic_preproc_lib.c \ include/sf_dynamic_preproc_lib.h \ include/sfghash.h \ include/sfhashfcn.h \ include/bitop.h \ include/sf_ip.h \ include/sf_ip.c \ include/sf_ipvar.h \ include/sf_vartable.h \ include/ipv6_port.h \ include/sfsnort_dynamic_detection_lib.c \ include/sfsnort_dynamic_detection_lib.h \ include/sf_snort_packet.h \ include/sf_protocols.h \ include/sf_snort_plugin_api.h \ include/sf_decompression.h \ include/pcap_pkthdr32.h \ include/stream_api.h \ include/str_search.h \ include/sf_types.h \ include/sfrt.h \ include/sfrt.c \ include/sfrt_dir.h \ include/sfrt_dir.c \ include/sfrt_flat.h \ include/sfrt_flat.c \ include/sfrt_flat_dir.h \ include/sfrt_flat_dir.c \ include/sfrt_trie.h \ include/segment_mem.h \ include/segment_mem.c \ include/mempool.h \ include/mempool.c \ include/sf_sdlist.h \ include/sf_sdlist_types.h \ include/sf_sdlist.c \ include/sfPolicyUserData.c \ include/sfPolicyUserData.h \ include/sfPolicy.h \ include/util_unfold.h \ include/util_unfold.c \ include/sf_base64decode.h \ include/sf_base64decode.c \ include/sf_email_attach_decode.h \ include/sf_email_attach_decode.c \ include/treenodes.h \ include/signature.h \ include/plugin_enum.h \ include/obfuscation.h \ include/rule_option_types.h \ include/event.h \ include/Unified2_common.h \ include/sfcontrol.h \ include/idle_processing.h \ include/sf_seqnums.h \ include/file_api.h sed_ipv6_headers = \ sed -e "s/->iph->ip_src/->ip4_header->source/" \ -e "s/->iph->ip_dst/->ip4_header->destination/" \ -e "s/->iph->/->ip4_header->/" \ -e "s/->iph$$/->ip4_header/" \ -e "s/orig_iph/orig_ipv4h/" \ -e "s/ip_verhl/version_headerlength/" \ -e "s/ip_tos/type_service/" \ -e "s/ip_len/data_length/" \ -e "s/ip_id/identifier/" \ -e "s/ip_off/offset/" \ -e "s/ip_ttl/time_to_live/" \ -e "s/ip_proto/proto/" \ -e "s/ip_csum/checksum/" \ $$dst_header.new > $$dst_header massage_ipv6_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_ipv6_headers); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_ipv6_headers); \ fi sed_headers = \ sed -e "s/Packet /SFSnortPacket /" \ -e "s/SnortPktHdr /SFSnortPktHdr /" \ -e "s/decode\.h/sf_snort_packet.h/" \ -e "/sfportobject\.h/d" \ -e "s/PortObject \*/void */g" \ $$dst_header.new > $$dst_header massage_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_headers); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_headers); \ fi sed_debug_header = \ sed -e "s/DebugMessageFile = /*_dpd.debugMsgFile = /" \ -e "s/DebugMessageLine = /*_dpd.debugMsgLine = /" \ -e "s/; DebugMessageFunc$$/; _dpd.debugMsg/" \ -e "s/; DebugWideMessageFunc$$/; _dpd.debugWideMsg/" \ $$dst_header.new > $$dst_header copy_debug_header = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_debug_header); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_debug_header); \ fi copy_error_message = \ if test -f $$dst_header; then \ sed -e "s/ErrorMessage/_dpd.errMsg/" \ -e "s/LogMessage /_dpd.logMsg /" \ -e "/util.h/d" \ $$dst_header > $$dst_header.new; \ mv $$dst_header.new $$dst_header; \ fi replace_policy_globals = \ if test -f $$dst_header; then \ sed -e "/SharedObjectAddStarts/d" \ -e "/SharedObjectAddEnds/d" \ -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" \ -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" \ -e "s/SnortStrnStr/_dpd.SnortStrnStr/" \ $$dst_header > $$dst_header.new; \ mv $$dst_header.new $$dst_header; \ fi copy_headers = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header; \ fi sed_treenode_header = \ sed -f $(srcdir)/treenodes.sed $$dst_header.new > $$dst_header copy_treenode_header = \ mkdir -p include; \ mkdir -p build; \ if test -f $$dst_header; then \ x=`diff $$src_header $$dst_header.new.new >> /dev/null`; \ if test "$$x" != "0"; then \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_treenode_header); \ fi \ else \ echo "Updating " $$dst_header; \ cp $$src_header $$dst_header.new; \ $(sed_treenode_header); \ fi @WANT_SF_SAAC_TRUE@RZB_SAAC_DIR = rzb_saac @FEAT_FILE_INSPECT_TRUE@FILE_INSPECT_DIR = file SUBDIRS = . libs ftptelnet pop imap smtp ssh dns ssl dcerpc2 sdf sip reputation gtp modbus dnp3 $(RZB_SAAC_DIR) $(FILE_INSPECT_DIR) EXTRA_DIST = \ dynamic_preprocessors.dsp \ sf_dynamic_initialize/sf_dynamic_initialize.dsp \ treenodes.sed srcinstdir = $(exec_prefix)/src/snort_dynamicsrc exported_files = \ include/sf_dynamic_common.h \ include/sf_dynamic_define.h \ include/sf_dynamic_engine.h \ include/sf_dynamic_meta.h \ include/sf_dynamic_preprocessor.h \ include/sf_dynamic_preproc_lib.h \ include/sf_dynamic_preproc_lib.c \ include/sf_ip.h \ include/sf_snort_packet.h \ include/sf_protocols.h \ include/sf_snort_plugin_api.h \ include/sf_decompression.h \ include/sf_types.h \ include/sfsnort_dynamic_detection_lib.h \ include/sfsnort_dynamic_detection_lib.c \ include/pcap_pkthdr32.h \ include/str_search.h \ include/stream_api.h \ include/snort_debug.h \ include/profiler.h \ include/sfghash.h \ include/sfhashfcn.h \ include/bitop.h \ include/preprocids.h \ include/sfPolicyUserData.h \ include/util_unfold.h \ include/util_unfold.c \ include/sf_base64decode.h \ include/sf_base64decode.c \ include/sf_email_attach_decode.h \ include/sf_email_attach_decode.c \ include/treenodes.h \ include/signature.h \ include/plugin_enum.h \ include/sfPolicyUserData.c \ include/obfuscation.h \ include/rule_option_types.h \ include/event.h \ include/Unified2_common.h \ include/sfcontrol.h \ include/idle_processing.h \ include/sf_seqnums.h \ include/file_api.h all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-preproclibLTLIBRARIES: $(preproclib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(preproclib_LTLIBRARIES)'; test -n "$(preproclibdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(preproclibdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(preproclibdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(preproclibdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(preproclibdir)"; \ } uninstall-preproclibLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(preproclib_LTLIBRARIES)'; test -n "$(preproclibdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(preproclibdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(preproclibdir)/$$f"; \ done clean-preproclibLTLIBRARIES: -test -z "$(preproclib_LTLIBRARIES)" || rm -f $(preproclib_LTLIBRARIES) @list='$(preproclib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsf_dynamic_preproc.la: $(libsf_dynamic_preproc_la_OBJECTS) $(libsf_dynamic_preproc_la_DEPENDENCIES) $(EXTRA_libsf_dynamic_preproc_la_DEPENDENCIES) $(AM_V_CCLD)$(libsf_dynamic_preproc_la_LINK) $(am_libsf_dynamic_preproc_la_rpath) $(libsf_dynamic_preproc_la_OBJECTS) $(libsf_dynamic_preproc_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< libsf_dynamic_preproc_la-ssl.lo: libs/ssl.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-ssl.lo `test -f 'libs/ssl.c' || echo '$(srcdir)/'`libs/ssl.c libsf_dynamic_preproc_la-sfparser.lo: libs/sfparser.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sfparser.lo `test -f 'libs/sfparser.c' || echo '$(srcdir)/'`libs/sfparser.c libsf_dynamic_preproc_la-sf_dynamic_preproc_lib.lo: include/sf_dynamic_preproc_lib.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sf_dynamic_preproc_lib.lo `test -f 'include/sf_dynamic_preproc_lib.c' || echo '$(srcdir)/'`include/sf_dynamic_preproc_lib.c libsf_dynamic_preproc_la-sf_ip.lo: include/sf_ip.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sf_ip.lo `test -f 'include/sf_ip.c' || echo '$(srcdir)/'`include/sf_ip.c libsf_dynamic_preproc_la-sfrt.lo: include/sfrt.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sfrt.lo `test -f 'include/sfrt.c' || echo '$(srcdir)/'`include/sfrt.c libsf_dynamic_preproc_la-sfrt_dir.lo: include/sfrt_dir.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sfrt_dir.lo `test -f 'include/sfrt_dir.c' || echo '$(srcdir)/'`include/sfrt_dir.c libsf_dynamic_preproc_la-sfrt_flat.lo: include/sfrt_flat.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sfrt_flat.lo `test -f 'include/sfrt_flat.c' || echo '$(srcdir)/'`include/sfrt_flat.c libsf_dynamic_preproc_la-sfrt_flat_dir.lo: include/sfrt_flat_dir.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sfrt_flat_dir.lo `test -f 'include/sfrt_flat_dir.c' || echo '$(srcdir)/'`include/sfrt_flat_dir.c libsf_dynamic_preproc_la-segment_mem.lo: include/segment_mem.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-segment_mem.lo `test -f 'include/segment_mem.c' || echo '$(srcdir)/'`include/segment_mem.c libsf_dynamic_preproc_la-mempool.lo: include/mempool.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-mempool.lo `test -f 'include/mempool.c' || echo '$(srcdir)/'`include/mempool.c libsf_dynamic_preproc_la-sf_sdlist.lo: include/sf_sdlist.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sf_sdlist.lo `test -f 'include/sf_sdlist.c' || echo '$(srcdir)/'`include/sf_sdlist.c libsf_dynamic_preproc_la-sfPolicyUserData.lo: include/sfPolicyUserData.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sfPolicyUserData.lo `test -f 'include/sfPolicyUserData.c' || echo '$(srcdir)/'`include/sfPolicyUserData.c libsf_dynamic_preproc_la-util_unfold.lo: include/util_unfold.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-util_unfold.lo `test -f 'include/util_unfold.c' || echo '$(srcdir)/'`include/util_unfold.c libsf_dynamic_preproc_la-sf_base64decode.lo: include/sf_base64decode.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sf_base64decode.lo `test -f 'include/sf_base64decode.c' || echo '$(srcdir)/'`include/sf_base64decode.c libsf_dynamic_preproc_la-sf_email_attach_decode.lo: include/sf_email_attach_decode.c $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_dynamic_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_dynamic_preproc_la-sf_email_attach_decode.lo `test -f 'include/sf_email_attach_decode.c' || echo '$(srcdir)/'`include/sf_email_attach_decode.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nodist_preprocHEADERS: $(nodist_preproc_HEADERS) @$(NORMAL_INSTALL) @list='$(nodist_preproc_HEADERS)'; test -n "$(preprocdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(preprocdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(preprocdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(preprocdir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(preprocdir)" || exit $$?; \ done uninstall-nodist_preprocHEADERS: @$(NORMAL_UNINSTALL) @list='$(nodist_preproc_HEADERS)'; test -n "$(preprocdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(preprocdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive @SO_WITH_STATIC_LIB_FALSE@all-local: all-am: Makefile $(LTLIBRARIES) $(HEADERS) all-local installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(preproclibdir)" "$(DESTDIR)$(preprocdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-libtool clean-local \ clean-preproclibLTLIBRARIES mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-data-local install-nodist_preprocHEADERS \ install-preproclibLTLIBRARIES install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-local uninstall-nodist_preprocHEADERS \ uninstall-preproclibLTLIBRARIES .MAKE: $(am__recursive_targets) all check install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ check check-am clean clean-generic clean-libtool clean-local \ clean-preproclibLTLIBRARIES cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-data-local install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man \ install-nodist_preprocHEADERS install-pdf install-pdf-am \ install-preproclibLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-local uninstall-nodist_preprocHEADERS \ uninstall-preproclibLTLIBRARIES @SO_WITH_STATIC_LIB_TRUE@all-local: $(LTLIBRARIES) @SO_WITH_STATIC_LIB_TRUE@ $(MAKE) DESTDIR=`pwd`/build install-preproclibLTLIBRARIES # From main src tree include/snort_debug.h: $(srcdir)/../snort_debug.h @src_header=$?; dst_header=$@; $(copy_debug_header) include/preprocids.h: $(srcdir)/../preprocids.h @src_header=$?; dst_header=$@; $(copy_headers) include/profiler.h: $(srcdir)/../profiler.h @src_header=$?; dst_header=$@; $(copy_headers) include/cpuclock.h: $(srcdir)/../cpuclock.h @src_header=$?; dst_header=$@; $(copy_headers) include/pcap_pkthdr32.h: $(srcdir)/../pcap_pkthdr32.h @src_header=$?; dst_header=$@; $(copy_headers) include/snort_bounds.h: $(srcdir)/../snort_bounds.h @src_header=$?; dst_header=$@; $(copy_headers) include/ipv6_port.h: $(srcdir)/../ipv6_port.h @src_header=$?; dst_header=$@; $(massage_ipv6_headers) include/sf_types.h: $(srcdir)/../sf_types.h @src_header=$?; dst_header=$@; $(copy_headers) include/obfuscation.h: $(srcdir)/../obfuscation.h @src_header=$?; dst_header=$@; $(massage_headers) include/rule_option_types.h: $(srcdir)/../rule_option_types.h @src_header=$?; dst_header=$@; $(copy_headers) include/event.h: $(srcdir)/../event.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins include/sf_dynamic_common.h: $(srcdir)/../dynamic-plugins/sf_dynamic_common.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_engine.h: $(srcdir)/../dynamic-plugins/sf_dynamic_engine.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_define.h: $(srcdir)/../dynamic-plugins/sf_dynamic_define.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_meta.h: $(srcdir)/../dynamic-plugins/sf_dynamic_meta.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_preprocessor.h: $(srcdir)/../dynamic-plugins/sf_dynamic_preprocessor.h @src_header=$?; dst_header=$@; $(massage_headers) # From dynamic-plugins/sf_preproc_example include/sf_dynamic_preproc_lib.c: $(srcdir)/../dynamic-plugins/sf_preproc_example/sf_dynamic_preproc_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_dynamic_preproc_lib.h: $(srcdir)/../dynamic-plugins/sf_preproc_example/sf_dynamic_preproc_lib.h @src_header=$?; dst_header=$@; $(copy_headers) # From Utils include/sfghash.h: $(srcdir)/../sfutil/sfghash.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfhashfcn.h: $(srcdir)/../sfutil/sfhashfcn.h @src_header=$?; dst_header=$@; $(copy_headers) include/bitop.h: $(srcdir)/../sfutil/bitop.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ip.h: $(srcdir)/../sfutil/sf_ip.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ip.c: $(srcdir)/../sfutil/sf_ip.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_ipvar.h: $(srcdir)/../sfutil/sf_ipvar.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_vartable.h: $(srcdir)/../sfutil/sf_vartable.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt.h: $(srcdir)/../sfutil/sfrt.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt.c: $(srcdir)/../sfutil/sfrt.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_dir.h: $(srcdir)/../sfutil/sfrt_dir.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_dir.c: $(srcdir)/../sfutil/sfrt_dir.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_flat.h: $(srcdir)/../sfutil/sfrt_flat.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_flat.c: $(srcdir)/../sfutil/sfrt_flat.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_flat_dir.h: $(srcdir)/../sfutil/sfrt_flat_dir.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_flat_dir.c: $(srcdir)/../sfutil/sfrt_flat_dir.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfrt_trie.h: $(srcdir)/../sfutil/sfrt_trie.h @src_header=$?; dst_header=$@; $(copy_headers) include/segment_mem.c: $(srcdir)/../sfutil/segment_mem.c @src_header=$?; dst_header=$@; $(copy_headers) include/segment_mem.h: $(srcdir)/../sfutil/segment_mem.h @src_header=$?; dst_header=$@; $(copy_headers) include/mempool.h: $(srcdir)/../mempool.h @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/mempool.c: $(srcdir)/../mempool.c @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/sf_sdlist.h: $(srcdir)/../sf_sdlist.h @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/sf_sdlist_types.h: $(srcdir)/../sf_sdlist_types.h @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/sf_sdlist.c: $(srcdir)/../sf_sdlist.c @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/sfPolicyUserData.c: $(srcdir)/../sfutil/sfPolicyUserData.c @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/sfPolicyUserData.h: $(srcdir)/../sfutil/sfPolicyUserData.h @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/sfPolicy.h: $(srcdir)/../sfutil/sfPolicy.h @src_header=$?; dst_header=$@; $(copy_headers); $(replace_policy_globals) include/util_unfold.h: $(srcdir)/../sfutil/util_unfold.h @src_header=$?; dst_header=$@; $(copy_headers) include/util_unfold.c: $(srcdir)/../sfutil/util_unfold.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_base64decode.h: $(srcdir)/../sfutil/sf_base64decode.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_base64decode.c: $(srcdir)/../sfutil/sf_base64decode.c @src_header=$?; dst_header=$@; $(copy_headers) include/sf_email_attach_decode.h: $(srcdir)/../sfutil/sf_email_attach_decode.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_email_attach_decode.c: $(srcdir)/../sfutil/sf_email_attach_decode.c @src_header=$?; dst_header=$@; $(copy_headers); $(copy_error_message); $(replace_policy_globals) include/Unified2_common.h: $(srcdir)/../sfutil/Unified2_common.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins/sf_engine/examples include/sfsnort_dynamic_detection_lib.c: $(srcdir)/../dynamic-plugins/sf_engine/examples/sfsnort_dynamic_detection_lib.c @src_header=$?; dst_header=$@; $(copy_headers) include/sfsnort_dynamic_detection_lib.h: $(srcdir)/../dynamic-plugins/sf_engine/examples/sfsnort_dynamic_detection_lib.h @src_header=$?; dst_header=$@; $(copy_headers) # From dynamic-plugins/sf_engine include/sf_snort_packet.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_snort_packet.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_protocols.h: $(srcdir)/../sf_protocols.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_snort_plugin_api.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_snort_plugin_api.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_decompression.h: $(srcdir)/../dynamic-plugins/sf_engine/sf_decompression.h @src_header=$?; dst_header=$@; $(copy_headers) # Stream API/String Searching, massage it to use SFSnortPacket include/stream_api.h: $(srcdir)/../preprocessors/stream_api.h @src_header=$?; dst_header=$@; $(massage_headers) include/str_search.h: $(srcdir)/../preprocessors/str_search.h @src_header=$?; dst_header=$@; $(massage_headers) include/treenodes.h: $(srcdir)/../treenodes.h @src_header=$?; dst_header=$@; $(copy_treenode_header) include/signature.h: $(srcdir)/../signature.h @src_header=$?; dst_header=$@; $(copy_treenode_header) include/plugin_enum.h: $(srcdir)/../plugin_enum.h @src_header=$?; dst_header=$@; $(copy_headers) include/sfcontrol.h: $(top_srcdir)/src/control/sfcontrol.h @src_header=$?; dst_header=$@; $(copy_headers) include/idle_processing.h: $(top_srcdir)/src/idle_processing.h @src_header=$?; dst_header=$@; $(copy_headers) include/sf_seqnums.h: $(top_srcdir)/src/sfutil/sf_seqnums.h @src_header=$?; dst_header=$@; $(copy_headers) include/file_api.h: $(top_srcdir)/src/file-process/file_api.h @src_header=$?; dst_header=$@; $(copy_headers) clean-local: rm -rf include build install-data-local: @for f in $(exported_files); do \ truefile=`echo $$f | sed -e "s/.*\///"`; \ $(mkinstalldirs) $(DESTDIR)$(srcinstdir); \ if test -f $(srcdir)/$$f; then p=$(srcdir)/$$f; else p=$$f; fi; \ $(INSTALL_DATA) $$p $(DESTDIR)$(srcinstdir)/$$truefile; \ done uninstall-local: @for f in $(exported_files); do \ truefile=`echo $$f | sed -e "s/.*\///"`; \ $(mkinstalldirs) $(DESTDIR)$(srcinstdir); \ rm -f $(DESTDIR)$(srcinstdir)/$$truefile; \ done # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/sf_dynamic_initialize/0000755000000000000000000000000012260606563021467 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/sf_dynamic_initialize/sf_dynamic_initialize.dsp0000755000000000000000000016555612232305202026462 00000000000000# Microsoft Developer Studio Project File - Name="sf_dynamic_initialize" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Generic Project" 0x010a CFG=sf_dynamic_initialize - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sf_dynamic_initialize.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sf_dynamic_initialize.mak" CFG="sf_dynamic_initialize - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sf_dynamic_initialize - Win32 Release" (based on "Win32 (x86) Generic Project") !MESSAGE "sf_dynamic_initialize - Win32 Debug" (based on "Win32 (x86) Generic Project") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" MTL=midl.exe !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" !ENDIF # Begin Target # Name "sf_dynamic_initialize - Win32 Release" # Name "sf_dynamic_initialize - Win32 Debug" # Begin Source File SOURCE=..\..\sfutil\bitop.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\bitop.h InputName=bitop "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\bitop.h InputName=bitop "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\cpuclock.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\cpuclock.h InputName=cpuclock "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\cpuclock.h InputName=cpuclock "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\event.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\event.h InputName=event "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\event.h InputName=event "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\file-process\file_api.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\file-process\file_api.h InputName=file_api "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\file-process\file_api.h InputName=file_api "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\idle_processing.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\idle_processing.h InputName=idle_processing "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\idle_processing.h InputName=idle_processing "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\win32\WIN32-Code\inet_aton.c" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\win32\WIN32-Code\inet_aton.c" InputName=inet_aton "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\win32\WIN32-Code\inet_aton.c" InputName=inet_aton "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\win32\WIN32-Code\inet_pton.c" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\win32\WIN32-Code\inet_pton.c" InputName=inet_pton "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\win32\WIN32-Code\inet_pton.c" InputName=inet_pton "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\ipv6_port.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\ipv6_port.h InputName=ipv6_port BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/->iph->ip_src/->ip4_header->source/" -e "s/->iph->ip_dst/->ip4_header->destination/" -e "s/->iph->/->ip4_header->/" -e "s/->iph$/->ip4_header/" -e "s/orig_iph$/orig_ip4_header/" -e "s/ip_verhl/version_headerlength/" -e "s/ip_tos/type_service/" -e "s/ip_len/data_length/" -e "s/ip_id/identifier/" -e "s/ip_off/offset/" -e "s/ip_ttl/time_to_live/" -e "s/ip_proto/proto/" -e "s/ip_csum/checksum/" -e "s/p->iph$/p->ip4_header/" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\ipv6_port.h InputName=ipv6_port BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/->iph->ip_src/->ip4_header->source/" -e "s/->iph->ip_dst/->ip4_header->destination/" -e "s/->iph->/->ip4_header->/" -e "s/->iph$/->ip4_header/" -e "s/orig_iph$/orig_ip4_header/" -e "s/ip_verhl/version_headerlength/" -e "s/ip_tos/type_service/" -e "s/ip_len/data_length/" -e "s/ip_id/identifier/" -e "s/ip_off/offset/" -e "s/ip_ttl/time_to_live/" -e "s/ip_proto/proto/" -e "s/ip_csum/checksum/" -e "s/p->iph$/p->ip4_header/" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\mempool.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\mempool.c InputName=mempool BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).c.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).c.new > ../include/$(InputName).c \ "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).c.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\mempool.c InputName=mempool BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).c.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).c.new > ../include/$(InputName).c \ "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).c.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\mempool.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\mempool.h InputName=mempool BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\mempool.h InputName=mempool BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\obfuscation.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\obfuscation.h InputName=obfuscation BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/Packet /SFSnortPacket /" -e "s/decode.h/sf_snort_packet.h/" -e "/sfportobject\.h/d" -e "s/PortObject/void/g" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\obfuscation.h InputName=obfuscation BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/Packet /SFSnortPacket /" -e "s/decode.h/sf_snort_packet.h/" -e "/sfportobject\.h/d" -e "s/PortObject/void/g" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\pcap_pkthdr32.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\pcap_pkthdr32.h InputName=pcap_pkthdr32 "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\pcap_pkthdr32.h InputName=pcap_pkthdr32 "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\plugin_enum.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\plugin_enum.h InputName=plugin_enum "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\plugin_enum.h InputName=plugin_enum "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\preprocids.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\preprocids.h InputName=preprocids "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\preprocids.h InputName=preprocids "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\profiler.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\profiler.h InputName=profiler "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\profiler.h InputName=profiler "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\rule_option_types.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\rule_option_types.h InputName=rule_option_types "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\rule_option_types.h InputName=rule_option_types "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\segment_mem.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\segment_mem.c InputName=segment_mem "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\segment_mem.c InputName=segment_mem "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\segment_mem.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\segment_mem.h InputName=segment_mem "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\segment_mem.h InputName=segment_mem "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sf_base64decode.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sf_base64decode.c InputName=sf_base64decode "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sf_base64decode.c InputName=sf_base64decode "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sf_base64decode.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sf_base64decode.h InputName=sf_base64decode "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sf_base64decode.h InputName=sf_base64decode "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_dynamic_common.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_common.h" InputName=sf_dynamic_common "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_common.h" InputName=sf_dynamic_common "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_dynamic_define.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_define.h" InputName=sf_dynamic_define "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_define.h" InputName=sf_dynamic_define "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_dynamic_engine.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_engine.h" InputName=sf_dynamic_engine "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_engine.h" InputName=sf_dynamic_engine "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_dynamic_meta.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_meta.h" InputName=sf_dynamic_meta "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_meta.h" InputName=sf_dynamic_meta "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_preproc_example\sf_dynamic_preproc_lib.c" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_preproc_example\sf_dynamic_preproc_lib.c" InputName=sf_dynamic_preproc_lib "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_preproc_example\sf_dynamic_preproc_lib.c" InputName=sf_dynamic_preproc_lib "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_preproc_example\sf_dynamic_preproc_lib.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_preproc_example\sf_dynamic_preproc_lib.h" InputName=sf_dynamic_preproc_lib "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_preproc_example\sf_dynamic_preproc_lib.h" InputName=sf_dynamic_preproc_lib "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_dynamic_preprocessor.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_preprocessor.h" InputName=sf_dynamic_preprocessor BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/Packet /SFSnortPacket /" -e "s/decode.h/sf_snort_packet.h/" -e "/sfportobject\.h/d" -e "s/PortObject/void/g" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_dynamic_preprocessor.h" InputName=sf_dynamic_preprocessor BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/Packet /SFSnortPacket /" -e "s/decode.h/sf_snort_packet.h/" -e "/sfportobject\.h/d" -e "s/PortObject/void/g" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sf_email_attach_decode.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sf_email_attach_decode.c InputName=sf_email_attach_decode BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).c.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/SnortStrnStr/_dpd.SnortStrnStr/" -e "/util.h/d" ../include/$(InputName).c.new > ../include/$(InputName).c \ "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).c.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sf_email_attach_decode.c InputName=sf_email_attach_decode BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).c.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/SnortStrnStr/_dpd.SnortStrnStr/" -e "/util.h/d" ../include/$(InputName).c.new > ../include/$(InputName).c \ "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).c.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sf_email_attach_decode.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sf_email_attach_decode.h InputName=sf_email_attach_decode "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sf_email_attach_decode.h InputName=sf_email_attach_decode "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sf_ip.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sf_ip.c InputName=sf_ip "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sf_ip.c InputName=sf_ip "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sf_ip.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sf_ip.h InputName=sf_ip "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sf_ip.h InputName=sf_ip "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sf_protocols.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sf_protocols.h InputName=sf_protocols "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sf_protocols.h InputName=sf_protocols "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sf_sdlist.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sf_sdlist.c InputName=sf_sdlist BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).c.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).c.new > ../include/$(InputName).c \ "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).c.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sf_sdlist.c InputName=sf_sdlist BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).c.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).c.new > ../include/$(InputName).c \ "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).c.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sf_sdlist.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sf_sdlist.h InputName=sf_sdlist BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sf_sdlist.h InputName=sf_sdlist BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sf_sdlist_types.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sf_sdlist_types.h InputName=sf_sdlist_types BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sf_sdlist_types.h InputName=sf_sdlist_types BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" -e "s/ErrorMessage/_dpd.errMsg/" -e "s/LogMessage /_dpd.logMsg /" -e "/util.h/d" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sf_seqnums.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sf_seqnums.h InputName=sf_seqnums "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sf_seqnums.h InputName=sf_seqnums "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_engine\sf_snort_packet.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_engine\sf_snort_packet.h" InputName=sf_snort_packet "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_engine\sf_snort_packet.h" InputName=sf_snort_packet "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_engine\sf_snort_plugin_api.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_engine\sf_snort_plugin_api.h" InputName=sf_snort_plugin_api "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_engine\sf_snort_plugin_api.h" InputName=sf_snort_plugin_api "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sf_types.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sf_types.h InputName=sf_types "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sf_types.h InputName=sf_types "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\control\sfcontrol.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\control\sfcontrol.h InputName=sfcontrol "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\control\sfcontrol.h InputName=sfcontrol "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfhashfcn.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfhashfcn.h InputName=sfhashfcn "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfhashfcn.h InputName=sfhashfcn "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\sfutil\sfPolicy.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\sfutil\sfPolicy.h" InputName=sfPolicy BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\sfutil\sfPolicy.h" InputName=sfPolicy BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\sfutil\sfPolicyUserData.c" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\sfutil\sfPolicyUserData.c" InputName=sfPolicyUserData BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).c.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" ../include/$(InputName).c.new > ../include/$(InputName).c \ "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).c.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\sfutil\sfPolicyUserData.c" InputName=sfPolicyUserData BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).c.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" ../include/$(InputName).c.new > ../include/$(InputName).c \ "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).c.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\sfutil\sfPolicyUserData.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\sfutil\sfPolicyUserData.h" InputName=sfPolicyUserData BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\sfutil\sfPolicyUserData.h" InputName=sfPolicyUserData BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "/SharedObjectAddStarts/d" -e "/SharedObjectAddEnds/d" -e "/SharedObjectDeleteBegins/,/SharedObjectDeleteEnds/d" -e "s/getDefaultPolicy()/_dpd.getDefaultPolicy()/" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt.c InputName=sfrt "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt.c InputName=sfrt "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt.h InputName=sfrt "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt.h InputName=sfrt "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt_dir.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt_dir.c InputName=sfrt_dir "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt_dir.c InputName=sfrt_dir "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt_dir.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt_dir.h InputName=sfrt_dir "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt_dir.h InputName=sfrt_dir "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt_flat.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt_flat.c InputName=sfrt_flat "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt_flat.c InputName=sfrt_flat "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt_flat.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt_flat.h InputName=sfrt_flat "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt_flat.h InputName=sfrt_flat "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt_flat_dir.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt_flat_dir.c InputName=sfrt_flat_dir "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt_flat_dir.c InputName=sfrt_flat_dir "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt_flat_dir.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt_flat_dir.h InputName=sfrt_flat_dir "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt_flat_dir.h InputName=sfrt_flat_dir "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfrt_trie.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfrt_trie.h InputName=sfrt_trie "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfrt_trie.h InputName=sfrt_trie "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_engine\examples\sfsnort_dynamic_detection_lib.c" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_engine\examples\sfsnort_dynamic_detection_lib.c" InputName=sfsnort_dynamic_detection_lib "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_engine\examples\sfsnort_dynamic_detection_lib.c" InputName=sfsnort_dynamic_detection_lib "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\dynamic-plugins\sf_engine\examples\sfsnort_dynamic_detection_lib.h" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_engine\examples\sfsnort_dynamic_detection_lib.h" InputName=sfsnort_dynamic_detection_lib "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\dynamic-plugins\sf_engine\examples\sfsnort_dynamic_detection_lib.h" InputName=sfsnort_dynamic_detection_lib "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\sfxhash.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\sfxhash.h InputName=sfxhash "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\sfxhash.h InputName=sfxhash "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\signature.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\signature.h InputName=signature BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -f ..\treenodes.sed ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\signature.h InputName=signature BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -f ..\treenodes.sed ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\snort_bounds.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\snort_bounds.h InputName=snort_bounds "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\snort_bounds.h InputName=snort_bounds "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\snort_debug.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\snort_debug.h InputName=snort_debug BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/DebugMessageFile = /*_dpd.debugMsgFile = /" -e "s/DebugMessageLine = /*_dpd.debugMsgLine = /" -e "s/; DebugMessageFunc$/; _dpd.debugMsg/" -e "s/; DebugWideMessageFunc$/; _dpd.debugWideMsg/" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\snort_debug.h InputName=snort_debug BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/DebugMessageFile = /*_dpd.debugMsgFile = /" -e "s/DebugMessageLine = /*_dpd.debugMsgLine = /" -e "s/; DebugMessageFunc$/; _dpd.debugMsg/" -e "s/; DebugWideMessageFunc$/; _dpd.debugWideMsg/" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\preprocessors\str_search.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\preprocessors\str_search.h InputName=str_search BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/Packet /SFSnortPacket /" -e "s/decode.h/sf_snort_packet.h/" -e "/sfportobject\.h/d" -e "s/PortObject/void/g" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\preprocessors\str_search.h InputName=str_search BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/Packet /SFSnortPacket /" -e "s/decode.h/sf_snort_packet.h/" -e "/sfportobject\.h/d" -e "s/PortObject/void/g" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\preprocessors\stream_api.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\preprocessors\stream_api.h InputName=stream_api BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/Packet /SFSnortPacket /" -e "s/decode.h/sf_snort_packet.h/" -e "/sfportobject\.h/d" -e "s/PortObject/void/g" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\preprocessors\stream_api.h InputName=stream_api BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -e "s/Packet /SFSnortPacket /" -e "s/decode.h/sf_snort_packet.h/" -e "/sfportobject\.h/d" -e "s/PortObject/void/g" ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE="..\..\win32\WIN32-Code\strtok_r.c" !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath="..\..\win32\WIN32-Code\strtok_r.c" InputName=strtok_r "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath="..\..\win32\WIN32-Code\strtok_r.c" InputName=strtok_r "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\treenodes.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\treenodes.h InputName=treenodes BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -f ..\treenodes.sed ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\treenodes.h InputName=treenodes BuildCmds= \ mkdir ..\include \ copy $(InputPath) ..\include\$(InputName).h.new \ c:\cygwin\bin\sed -f ..\treenodes.sed ../include/$(InputName).h.new > ../include/$(InputName).h \ "..\include\$(InputName).h.new" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\Unified2_common.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\Unified2_common.h InputName=Unified2_common "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\Unified2_common.h InputName=Unified2_common "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\util_unfold.c !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\util_unfold.c InputName=util_unfold "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\util_unfold.c InputName=util_unfold "..\include\$(InputName).c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # Begin Source File SOURCE=..\..\sfutil\util_unfold.h !IF "$(CFG)" == "sf_dynamic_initialize - Win32 Release" # Begin Custom Build InputPath=..\..\sfutil\util_unfold.h InputName=util_unfold "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ELSEIF "$(CFG)" == "sf_dynamic_initialize - Win32 Debug" # Begin Custom Build InputPath=..\..\sfutil\util_unfold.h InputName=util_unfold "..\include\$(InputName).h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" mkdir ..\include copy $(InputPath) ..\include # End Custom Build !ENDIF # End Source File # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/libs/0000755000000000000000000000000012260606563016063 500000000000000snort-2.9.6.0/src/dynamic-preprocessors/libs/sf_preproc_info.h0000644000000000000000000000263612260565732021342 00000000000000/* * sf_preproc_info.h * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2006-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Description: * * This file is part of the dynamically loadable preprocessor library. The * items must be globally defined within the source file of a given * preprocessor. * * Author: Steven A. Sturges * * NOTES: * */ #ifndef SF_PREPROC_INFO_H_ #define SF_PREPROC_INFO_H_ extern const int MAJOR_VERSION; extern const int MINOR_VERSION; extern const int BUILD_VERSION; extern const char *PREPROC_NAME; extern void DYNAMIC_PREPROC_SETUP(void); #endif /* SF_PREPROC_INFO_H_ */ snort-2.9.6.0/src/dynamic-preprocessors/libs/sfcommon.h0000644000000000000000000000332412260565732020001 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2007-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifndef DYN_PP_PARSER_H #define DYN_PP_PARSER_H #include "snort_bounds.h" #include "snort_debug.h" #define SFP_MIN_ERR_STR 128 /* Convert port value into an index */ #define PORT_INDEX(port) port/8 /* Convert port value into a value for bitwise operations */ #define CONV_PORT(port) 1<<(port%8) typedef enum _SFP_ret { SFP_SUCCESS, SFP_ERROR } SFP_ret_t; typedef uint8_t ports_tbl_t[MAXPORTS/8]; typedef char SFP_errstr_t[SFP_MIN_ERR_STR + 1]; static inline char *SFP_GET_ERR(SFP_errstr_t err) { return (char*)err; } SFP_ret_t SFP_ports(ports_tbl_t ports, char *str, SFP_errstr_t errstr); SFP_ret_t SFP_snprintfa(char *buf, size_t buf_size, const char *format, ...); #endif snort-2.9.6.0/src/dynamic-preprocessors/libs/ssl.h0000644000000000000000000001471712260565732016771 00000000000000/* * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 1998-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /* * Adam Keeton * ssl.h * 10/09/07 */ #ifndef SSL_H #define SSL_H #include #include #define SSL_NO_FLAG 0x00000000 /* SSL record type flags */ #define SSL_CHANGE_CIPHER_FLAG 0x00000001 #define SSL_ALERT_FLAG 0x00000002 #define SSL_POSSIBLE_HS_FLAG 0x00000004 /* For handshakes in TLSv3 that are encrypted */ #define SSL_CLIENT_HELLO_FLAG 0x00000008 #define SSL_SERVER_HELLO_FLAG 0x00000010 #define SSL_CERTIFICATE_FLAG 0x00000020 #define SSL_SERVER_KEYX_FLAG 0x00000040 #define SSL_CLIENT_KEYX_FLAG 0x00000080 #define SSL_CIPHER_SPEC_FLAG 0x00000100 #define SSL_SFINISHED_FLAG 0x00000200 #define SSL_SAPP_FLAG 0x00000400 #define SSL_CAPP_FLAG 0x00000800 #define SSL_HS_SDONE_FLAG 0x00001000 /* Misc state flag */ #define SSL_POSSIBLY_ENC_FLAG 0x00002000 /* Version flags */ #define SSL_VER_SSLV2_FLAG 0x00004000 #define SSL_VER_SSLV3_FLAG 0x00008000 #define SSL_VER_TLS10_FLAG 0x00010000 #define SSL_VER_TLS11_FLAG 0x00020000 #define SSL_VER_TLS12_FLAG 0x00040000 #define SSL_VERFLAGS (SSL_VER_SSLV2_FLAG | SSL_VER_SSLV3_FLAG | \ SSL_VER_TLS10_FLAG | SSL_VER_TLS11_FLAG | \ SSL_VER_TLS12_FLAG) #define SSL_V3_SERVER_HELLO(x) (((x) & SSL_CUR_SERVER_HELLO_FLAG) \ && ((x) & SSL_VERFLAGS) && (((x) & SSL_VERFLAGS) != SSL_VER_SSLV2_FLAG)) /* For rule state matching. These are only set when presently valid, * and do not stay set across packets. */ #define SSL_CUR_CLIENT_HELLO_FLAG 0x00080000 #define SSL_CUR_SERVER_HELLO_FLAG 0x00100000 #define SSL_CUR_SERVER_KEYX_FLAG 0x00200000 #define SSL_CUR_CLIENT_KEYX_FLAG 0x00400000 #define SSL_ENCRYPTED_FLAG 0x00800000 /* Provided for external use */ #define SSL_UNKNOWN_FLAG 0x01000000 /* Set when we decoded mostly garbage */ #define SSL_STATEFLAGS (SSL_CUR_CLIENT_HELLO_FLAG | SSL_CUR_SERVER_HELLO_FLAG | \ SSL_CUR_SERVER_KEYX_FLAG | SSL_CUR_CLIENT_KEYX_FLAG | \ SSL_UNKNOWN_FLAG) // Flag set when a client uses SSLv3/TLS backward compatibility and sends a // SSLv2 Hello specifying an SSLv3/TLS version. #define SSL_V3_BACK_COMPAT_V2 0x02000000 /* Error flags */ #define SSL_BOGUS_HS_DIR_FLAG 0x08000000 /* Record type disagrees with direction */ #define SSL_TRAILING_GARB_FLAG 0x10000000 #define SSL_BAD_TYPE_FLAG 0x20000000 #define SSL_BAD_VER_FLAG 0x40000000 #define SSL_TRUNCATED_FLAG 0x80000000 #define SSL_ARG_ERROR_FLAG 0x00000000 /* Note: overloaded with SSL_NO_FLAG */ /* The following flags are not presently of interest: * #define SSL_CERT_URL_FLAG (RFC 3546) * #define SSL_CERT_STATUS_FLAG (RFC 3546) * #define SSL_CFINISHED_FLAG This is contained in encrypted data * #define SSL_HS_FINISHED_FLAG Ignored for our purposes */ /* The constants used below are from RFC 2246 */ /* SSLv3 & TLS Record types */ #define SSL_CHANGE_CIPHER_REC 20 #define SSL_ALERT_REC 21 #define SSL_HANDSHAKE_REC 22 #define SSL_APPLICATION_REC 23 /* SSLv3 & TLS handshake types */ #define SSL_HS_HELLO_REQ 0 #define SSL_HS_CHELLO 1 #define SSL_HS_SHELLO 2 #define SSL_HS_CERT 11 #define SSL_HS_SKEYX 12 #define SSL_HS_CERT_REQ 13 #define SSL_HS_SHELLO_DONE 14 #define SSL_HS_CERT_VERIFY 15 #define SSL_HS_CKEYX 16 #define SSL_HS_FINISHED 20 #define SSL_CERT_URL 21 #define SSL_CERT_STATUS 22 /* SSLv2 handshake types */ #define SSL_V2_CHELLO 1 #define SSL_V2_CKEY 2 #define SSL_V2_SHELLO 4 #ifdef WIN32 #pragma pack(push,ssl_hdrs,1) #else #pragma pack(1) #endif typedef struct _SSL_record { uint8_t type; uint8_t major; uint8_t minor; uint16_t length; } SSL_record_t; #define SSL_REC_PAYLOAD_OFFSET (sizeof(uint8_t) * 5) typedef struct _SSL_handshake { uint8_t type; uint8_t length[3]; } SSL_handshake_t; typedef struct _SSL_handshake_hello { uint8_t type; uint8_t length[3]; uint8_t major; uint8_t minor; } SSL_handshake_hello_t; // http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html typedef struct _SSLv2_record { uint16_t length; uint8_t type; } SSLv2_record_t; typedef struct _SSLv2_chello { uint16_t length; uint8_t type; uint8_t major; uint8_t minor; } SSLv2_chello_t; typedef struct _SSLv2_shello { uint16_t length; uint8_t type; uint8_t ssnid; uint8_t certtype; uint8_t major; uint8_t minor; } SSLv2_shello_t; #define SSL_V2_MIN_LEN 5 #ifdef WIN32 #pragma pack(pop,ssl_hdrs) #else #pragma pack() #endif #define SSL_HS_PAYLOAD_OFFSET (sizeof(uint8_t) * 4) /* Type and length fields */ #define SSL_BAD_HS(x) (x & SSL_BOGUS_HS_DIR_FLAG) #define SSL_IS_HANDSHAKE(x) (x & (SSL_CLIENT_HELLO_FLAG | SSL_SERVER_HELLO_FLAG | \ SSL_CERTIFICATE_FLAG | SSL_SERVER_KEYX_FLAG | \ SSL_CLIENT_KEYX_FLAG | SSL_CIPHER_SPEC_FLAG)) #define SSL_IS_CHELLO(x) (x & SSL_CLIENT_HELLO_FLAG) #define SSL_IS_SHELLO(x) (x & SSL_SERVER_HELLO_FLAG) #define SSL_IS_CKEYX(x) (x & SSL_CLIENT_KEYX_FLAG) #define SSL_IS_APP(x) ((x & SSL_SAPP_FLAG) || (x & SSL_CAPP_FLAG)) #define SSL_IS_ALERT(x) (x & SSL_ALERT_FLAG) #define SSL_CLEAR_TEMPORARY_FLAGS(x) x &= ~SSL_STATEFLAGS; /* Verifies that the error flags haven't been triggered */ #define SSL_IS_CLEAN(x) !(x & (SSL_BOGUS_HS_DIR_FLAG | SSL_TRUNCATED_FLAG | \ SSL_BAD_VER_FLAG | SSL_BAD_TYPE_FLAG | \ SSL_TRAILING_GARB_FLAG | SSL_UNKNOWN_FLAG)) uint32_t SSL_decode(const uint8_t *pkt, int size, uint32_t pktflags, uint32_t prevflags); #endif snort-2.9.6.0/src/dynamic-preprocessors/libs/sfdynamic_preproc_libs.dsp0000755000000000000000000000750312153454770023245 00000000000000# Microsoft Developer Studio Project File - Name="sfdynamic_preproc_libs" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Static Library" 0x0104 CFG=sfdynamic_preproc_libs - Win32 IPv6 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "sfdynamic_preproc_libs.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "sfdynamic_preproc_libs.mak" CFG="sfdynamic_preproc_libs - Win32 IPv6 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "sfdynamic_preproc_libs - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "sfdynamic_preproc_libs - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "sfdynamic_preproc_libs - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\include" /I "..\..\win32\Win32-Includes" /I "..\..\\" /I ".\\" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "NDEBUG" /D "ENABLE_PAF" /D "_LIB" /D "SF_SNORT_PREPROC_DLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ACTIVE_RESPONSE" /D "_AFXDLL" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ELSEIF "$(CFG)" == "sfdynamic_preproc_libs - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\\" /I "..\include" /I "..\..\win32\Win32-Includes" /I "..\..\\" /I ".\\" /I "..\..\..\daq\api" /I "..\..\..\daq\sfbpf" /D "_DEBUG" /D "DEBUG" /D "ENABLE_PAF" /D "_LIB" /D "SF_SNORT_PREPROC_DLL" /D "WIN32" /D "_MBCS" /D "HAVE_CONFIG_H" /D "GRE" /D "MPLS" /D "TARGET_BASED" /D "PERF_PROFILING" /D "ACTIVE_RESPONSE" /D "_AFXDLL" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo !ENDIF # Begin Target # Name "sfdynamic_preproc_libs - Win32 Release" # Name "sfdynamic_preproc_libs - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\sfparser.c # End Source File # Begin Source File SOURCE=.\ssl.c # End Source File # Begin Source File SOURCE="..\..\win32\WIN32-Code\strtok_r.c" # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\sfcommon.h # End Source File # Begin Source File SOURCE=.\ssl.h # End Source File # End Group # End Target # End Project snort-2.9.6.0/src/dynamic-preprocessors/libs/snort_preproc.pc.in0000644000000000000000000000070111573541512021627 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ libdir=@libdir@ package=@PACKAGE@ includedir=@includedir@ datarootdir=@datarootdir@ datadir=@datadir@ mandir=@infodir@ infodir=@infodir@ Name: Snort Description: Snort dynamic preprocessors URL: www.snort.org Version: @VERSION@ Libs: -L${libdir}/${package}/dynamic_preproc -lsf_dynamic_preproc Cflags: -I${includedir}/${package}/dynamic_preproc @CONFIGFLAGS@ @CCONFIGFLAGS@ @ICONFIGFLAGS@ snort-2.9.6.0/src/dynamic-preprocessors/libs/Makefile.am0000644000000000000000000000041412153454770020040 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies EXTRA_DIST = \ sfdynamic_preproc_libs.dsp \ ssl.c \ ssl.h \ sfparser.c \ sfcommon.h \ sf_preproc_info.h \ snort_preproc.pc.in if SO_WITH_STATIC_LIB pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = snort_preproc.pc endif snort-2.9.6.0/src/dynamic-preprocessors/libs/Makefile.in0000644000000000000000000003523712260606522020055 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/dynamic-preprocessors/libs DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/snort_preproc.pc.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = snort_preproc.pc CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = depcomp = am__depfiles_maybe = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkgconfigdir)" DATA = $(pkgconfig_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies EXTRA_DIST = \ sfdynamic_preproc_libs.dsp \ ssl.c \ ssl.h \ sfparser.c \ sfcommon.h \ sf_preproc_info.h \ snort_preproc.pc.in @SO_WITH_STATIC_LIB_TRUE@pkgconfigdir = $(libdir)/pkgconfig @SO_WITH_STATIC_LIB_TRUE@pkgconfig_DATA = snort_preproc.pc all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dynamic-preprocessors/libs/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/dynamic-preprocessors/libs/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): snort_preproc.pc: $(top_builddir)/config.status $(srcdir)/snort_preproc.pc.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgconfigDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-pkgconfigDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-pkgconfigDATA install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am \ uninstall-pkgconfigDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/dynamic-preprocessors/libs/sfparser.c0000644000000000000000000001046012260565732017777 00000000000000/**************************************************************************** * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2007-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "sf_types.h" #include "sfcommon.h" #include "ctype.h" #define SET_ERR(x,y) \ if(errstr && \ snprintf((char*)errstr, SFP_MIN_ERR_STR, x, y) >= \ SFP_MIN_ERR_STR) \ { \ /* tok exceeded errstr. Overwrite trailing characters for \ * printability */ \ strcpy(((char*)errstr) + SFP_MIN_ERR_STR-4, "..."); \ } #define CLR_ERR() ((char*)errstr)[0] = 0; SFP_ret_t SFP_ports(ports_tbl_t port_tbl, char *str, SFP_errstr_t errstr) { char *tok; char *saveptr; char end_brace_found = 0; char port_found = 0; if(!str) { SET_ERR("%s", "Invalid pointer"); return SFP_ERROR; } if((tok = strtok_r(str, " ", &saveptr)) == NULL) { SET_ERR("%s", "No ports specified"); return SFP_ERROR; } /* This string had better start with a '{' and end with a '}', or else! */ if(strcmp(tok, "{")) { SET_ERR("Malformed port list: %s. Expecting a leading '{ '", tok); return SFP_ERROR; } while((tok = strtok_r(NULL, " ", &saveptr)) != NULL) { char *port_end; long int port; str = NULL; if(end_brace_found) { SET_ERR("Last character of a port list must be '}': %s", tok); return SFP_ERROR; } if(!strcmp(tok, "}")) { end_brace_found = 1; continue; } errno = 0; port = strtol(tok, &port_end, 10); if((port_end == tok) || (*port_end && *port_end != '}') || (errno == ERANGE)) { SET_ERR("Unable to parse: %s", tok); return SFP_ERROR; } if(port < 0 || port > MAXPORTS-1) { SET_ERR("Port out of range: %s", tok); return SFP_ERROR; } port_tbl[ PORT_INDEX(port) ] |= CONV_PORT(port); port_found = 1; } if(!end_brace_found) { SET_ERR("%s", "No end brace found"); return SFP_ERROR; } if(!port_found) { SET_ERR("%s", "No ports specified"); return SFP_ERROR; } CLR_ERR(); return SFP_SUCCESS; } SFP_ret_t SFP_snprintfa(char *buf, size_t buf_size, const char *format, ...) { size_t str_len; int ret; va_list ap; if (buf == NULL || buf_size <= 0 || format == NULL) return SFP_ERROR; /* equivalent of a strlen that stops at buf_size */ for(str_len = 0; (str_len < buf_size) && buf[str_len]; str_len++) ; /* Note: this is from the original SnortSnprintfAppend */ /* "since we've already checked buf and buf_size an error * indicates no null termination, so just start at * beginning of buffer" */ if(str_len >= buf_size) { buf[0] = '\0'; str_len = 0; } buf[buf_size - 1] = '\0'; va_start(ap, format); ret = vsnprintf(buf + str_len, buf_size - str_len, format, ap); va_end(ap); if (ret < 0) return SFP_ERROR; if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size) { /* truncation occured */ buf[buf_size - 1] = '\0'; return SFP_ERROR; } return SFP_SUCCESS; } snort-2.9.6.0/src/dynamic-preprocessors/libs/ssl.c0000644000000000000000000003464012260565732016761 00000000000000/* * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 1998-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /* * Adam Keeton * ssl.c * 10/09/07 */ #ifdef HAVE_CONFIG_H #include #endif #ifndef WIN32 #include #include #include #include #endif #include "sf_snort_packet.h" #include "ssl.h" #include "sf_types.h" #define THREE_BYTE_LEN(x) (x[2] | x[1] << 8 | x[0] << 16) static uint32_t SSL_decode_version_v3(uint8_t major, uint8_t minor) { /* Should only be called internally and by functions which have previously * validated their arguments */ if(major == 3) { /* Minor version */ switch(minor) { case 0: return SSL_VER_SSLV3_FLAG; break; case 1: return SSL_VER_TLS10_FLAG; break; case 2: return SSL_VER_TLS11_FLAG; break; case 3: return SSL_VER_TLS12_FLAG; break; default: return SSL_BAD_VER_FLAG; }; } /* This is a special case. Technically, major == 0, minor == 2 is SSLv2. * But if this traffic was SSLv2, this code path would not have been * exercised. */ else if(minor == 2) { return SSL_BAD_VER_FLAG; } return SSL_BAD_VER_FLAG; } static uint32_t SSL_decode_handshake_v3(const uint8_t *pkt , int size, uint32_t cur_flags, uint32_t pkt_flags) { SSL_handshake_t *handshake; SSL_handshake_hello_t *hello; uint32_t hs_len; uint32_t retval = 0; while (size > 0) { if (size < (int)SSL_HS_PAYLOAD_OFFSET) { retval |= SSL_TRUNCATED_FLAG; break; } /* Note, handhshake version field is optional depending on type */ /* Will recast to different type as necessary. */ handshake = (SSL_handshake_t *)pkt; pkt += SSL_HS_PAYLOAD_OFFSET; size -= SSL_HS_PAYLOAD_OFFSET; /* The code below effectively implements the following: * hs_len = 0; * memcpy(&hs_len, handshake->length, 3); * hs_len = ntohl(hs_len); * It was written this way for performance */ hs_len = THREE_BYTE_LEN(handshake->length); switch(handshake->type) { case SSL_HS_CHELLO: if(pkt_flags & FLAG_FROM_SERVER) retval |= SSL_BOGUS_HS_DIR_FLAG; else retval |= SSL_CLIENT_HELLO_FLAG | SSL_CUR_CLIENT_HELLO_FLAG; /* This type of record contains a version string. */ /* Make sure there is room for a version. */ if (size < (int)sizeof(uint16_t)) { retval |= SSL_TRUNCATED_FLAG; break; } hello = (SSL_handshake_hello_t *)handshake; retval |= SSL_decode_version_v3(hello->major, hello->minor); /* Compare version of record with version of handshake */ if((cur_flags & SSL_VERFLAGS) != (retval & SSL_VERFLAGS)) retval |= SSL_BAD_VER_FLAG; break; case SSL_HS_SHELLO: if(pkt_flags & FLAG_FROM_SERVER) retval |= SSL_SERVER_HELLO_FLAG | SSL_CUR_SERVER_HELLO_FLAG; else retval |= SSL_BOGUS_HS_DIR_FLAG; /* This type of record contains a version string. */ if (size < (int)sizeof(uint16_t)) { retval |= SSL_TRUNCATED_FLAG; break; } hello = (SSL_handshake_hello_t *)handshake; retval |= SSL_decode_version_v3(hello->major, hello->minor); /* Compare version of record with version of handshake */ if((cur_flags & SSL_VERFLAGS) != (retval & SSL_VERFLAGS)) retval |= SSL_BAD_VER_FLAG; break; case SSL_HS_SHELLO_DONE: if(pkt_flags & FLAG_FROM_SERVER) retval |= SSL_HS_SDONE_FLAG; else retval |= SSL_BOGUS_HS_DIR_FLAG; break; case SSL_HS_SKEYX: if(pkt_flags & FLAG_FROM_SERVER) retval |= SSL_SERVER_KEYX_FLAG | SSL_CUR_SERVER_KEYX_FLAG; else retval |= SSL_BOGUS_HS_DIR_FLAG; break; case SSL_HS_CKEYX: if(pkt_flags & FLAG_FROM_SERVER) retval |= SSL_BOGUS_HS_DIR_FLAG; else retval |= SSL_CLIENT_KEYX_FLAG | SSL_CUR_CLIENT_KEYX_FLAG; break; case SSL_HS_CERT: retval |= SSL_CERTIFICATE_FLAG; break; /* The following types are not presently of interest */ case SSL_HS_HELLO_REQ: case SSL_HS_CERT_VERIFY: case SSL_HS_CERT_REQ: case SSL_CERT_URL: /* RFC 3546 */ case SSL_CERT_STATUS: /* RFC 3546 */ break; /* Will never see this since it's always encrypted */ case SSL_HS_FINISHED: default: /* Could be either a bad type or an encrypted handshake record */ /* If the record is encrypted, the type will likely appear bogus. */ return SSL_POSSIBLE_HS_FLAG | SSL_POSSIBLY_ENC_FLAG; } size -= hs_len; pkt += hs_len; } if (size < 0) retval |= SSL_TRUNCATED_FLAG; return retval; } static uint32_t SSL_decode_v3(const uint8_t *pkt, int size, uint32_t pkt_flags) { SSL_record_t *record; uint32_t retval = 0; uint16_t reclen; int ccs = 0; /* Set if we see a Change Cipher Spec and reset after the next record */ while(size > 0) { if (size < (int)SSL_REC_PAYLOAD_OFFSET) { retval |= SSL_TRUNCATED_FLAG; break; } record = (SSL_record_t*)pkt; pkt += SSL_REC_PAYLOAD_OFFSET; size -= SSL_REC_PAYLOAD_OFFSET; retval |= SSL_decode_version_v3(record->major, record->minor); reclen = ntohs(record->length); switch (record->type) { case SSL_CHANGE_CIPHER_REC: retval |= SSL_CHANGE_CIPHER_FLAG; /* If there is another record, mark it as possibly encrypted */ if((size - (int)reclen) > 0) retval |= SSL_POSSIBLY_ENC_FLAG; ccs = 1; break; case SSL_ALERT_REC: retval |= SSL_ALERT_FLAG; ccs = 0; break; case SSL_HANDSHAKE_REC: /* If the CHANGE_CIPHER_FLAG is set, the following handshake * record should be encrypted */ if(!(retval & SSL_CHANGE_CIPHER_FLAG)) { int hsize = size < (int)reclen ? size : (int)reclen; retval |= SSL_decode_handshake_v3(pkt, hsize, retval, pkt_flags); } else if (ccs) { /* If we just got a change cipher spec, the next record must * be a finished encrypted, which has no type, so it will fall * into this default case, but it's good and we still need to * see client and server app data */ retval |= SSL_HS_SDONE_FLAG; } ccs = 0; break; case SSL_APPLICATION_REC: if(pkt_flags & FLAG_FROM_SERVER) retval |= SSL_SAPP_FLAG; else retval |= SSL_CAPP_FLAG; ccs = 0; break; default: retval |= SSL_BAD_TYPE_FLAG; ccs = 0; break; }; size -= reclen; pkt += reclen; } if (size < 0) retval |= SSL_TRUNCATED_FLAG; if(!(retval & SSL_VERFLAGS) || (retval & SSL_BAD_VER_FLAG)) return retval | SSL_UNKNOWN_FLAG; return retval; } // See RFCs 6101, 2246, 4346 and 5246 for SSL 3.0, TLS 1.0, 1.1 and 1.2 respectively // Appendix E. Backward Compatibility With SSL static inline bool SSL_v3_back_compat_v2(SSLv2_chello_t *chello) { if ((chello->major == 3) && (chello->minor <= 3)) return true; return false; } static uint32_t SSL_decode_v2(const uint8_t *pkt, int size, uint32_t pkt_flags) { uint16_t reclen; SSLv2_chello_t *chello; SSLv2_shello_t *shello; uint32_t retval = 0; SSLv2_record_t *record = (SSLv2_record_t*)pkt; while (size > 0) { if(size < SSL_V2_MIN_LEN) { retval |= SSL_TRUNCATED_FLAG | SSL_UNKNOWN_FLAG; break; } /* Note: top bit has special meaning and is not included * with the length */ reclen = ntohs(record->length) & 0x7fff; switch(record->type) { case SSL_V2_CHELLO: if(pkt_flags & FLAG_FROM_SERVER) retval |= SSL_BOGUS_HS_DIR_FLAG; else retval |= SSL_CLIENT_HELLO_FLAG | SSL_CUR_CLIENT_HELLO_FLAG ; if (size < (int)sizeof(SSLv2_chello_t)) { retval |= SSL_TRUNCATED_FLAG | SSL_UNKNOWN_FLAG; break; } chello = (SSLv2_chello_t*)pkt; // Check for SSLv3/TLS backward compatibility if (SSL_v3_back_compat_v2(chello)) retval |= SSL_V3_BACK_COMPAT_V2; else if (chello->minor != 2) retval |= SSL_BAD_VER_FLAG | SSL_UNKNOWN_FLAG; break; case SSL_V2_SHELLO: if(pkt_flags & FLAG_FROM_CLIENT) retval |= SSL_BOGUS_HS_DIR_FLAG; else retval |= SSL_SERVER_HELLO_FLAG | SSL_CUR_SERVER_HELLO_FLAG; if (size < (int)sizeof(SSLv2_shello_t)) { retval |= SSL_TRUNCATED_FLAG | SSL_UNKNOWN_FLAG; break; } shello = (SSLv2_shello_t*)pkt; if (shello->minor != 2) { retval |= SSL_BAD_VER_FLAG | SSL_UNKNOWN_FLAG; break; } break; case SSL_V2_CKEY: retval |= SSL_CLIENT_KEYX_FLAG | SSL_CUR_CLIENT_KEYX_FLAG; break; default: return retval | SSL_BAD_TYPE_FLAG | SSL_UNKNOWN_FLAG; } size -= (reclen + 2); pkt += (reclen + 2); } if (size < 0) retval |= SSL_TRUNCATED_FLAG; return retval | SSL_VER_SSLV2_FLAG; } uint32_t SSL_decode(const uint8_t *pkt, int size, uint32_t pkt_flags, uint32_t prev_flags) { SSL_record_t *record; uint16_t reclen; uint32_t datalen; if(!pkt || !size) return SSL_ARG_ERROR_FLAG; if (size < (int)SSL_REC_PAYLOAD_OFFSET) return SSL_TRUNCATED_FLAG | SSL_UNKNOWN_FLAG; if(!( prev_flags & SSL_HS_SDONE_FLAG )) { /* Determine the protocol type. */ /* Only SSL v2 will have these bits set */ if(pkt[0] & 0x80 || pkt[0] & 0x40) return SSL_decode_v2(pkt, size, pkt_flags); /* If this packet is only 5 bytes, it inconclusive whether its SSLv2 or TLS. * If it is v2, it's definitely truncated anyway. By decoding a 5 byte * SSLv2 as TLS,the decoder will either catch a bad type, bad version, or * indicate that it is truncated. */ if(size == 5) return SSL_decode_v3(pkt, size, pkt_flags); /* At this point, 'size' has to be > 5 */ /* If the field below contains a 2, it's either an SSLv2 client hello or * it is TLS and is containing a server hello. */ if(pkt[4] == 2) { /* This could be a TLS server hello. Check for a TLS version string */ if(size >= 10) { if(pkt[9] == 3) { /* Saw a TLS version, but this could also be an SSHv2 length. * If it is, check if a hypothetical TLS record-data length agress * with its record length */ datalen = THREE_BYTE_LEN( (pkt+6) ); record = (SSL_record_t*)pkt; reclen = ntohs(record->length); /* If these lengths match, it's v3 */ /* Otherwise, it's v2 */ if(reclen - SSL_HS_PAYLOAD_OFFSET != datalen) return SSL_decode_v2(pkt, size, pkt_flags); } } } /* Check if it's possibly a SSLv2 server-hello, in which case the version * is at byte 7 */ else if(size >= 8 && pkt[7] == 2) { /* A version of '2' at byte 7 overlaps with TLS record-data length. * Check if a hypothetical TLS record-data length agress with its * record length */ datalen = THREE_BYTE_LEN( (pkt+6) ); record = (SSL_record_t*)pkt; reclen = ntohs(record->length); /* If these lengths match, it's v3 */ /* Otherwise, it's v2 */ if(reclen - SSL_HS_PAYLOAD_OFFSET != datalen) return SSL_decode_v2(pkt, size, pkt_flags); } } return SSL_decode_v3(pkt, size, pkt_flags); } snort-2.9.6.0/src/parser/0000755000000000000000000000000012260606563012073 500000000000000snort-2.9.6.0/src/parser/IpAddrSet.h0000644000000000000000000000237512260565732014014 00000000000000/* $Id$ */ /* * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2002-2013 Sourcefire, Inc. * * Author(s): Andrew R. Baker * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef __IP_ADDR_SET_H__ #define __IP_ADDR_SET_H__ #include #include "sf_types.h" # include "ipv6_port.h" # include "sfutil/sf_ipvar.h" void IpAddrSetDestroy(IpAddrSet *); struct _SnortConfig; IpAddrSet *IpAddrSetParse(struct _SnortConfig *, char *); #endif /* __IP_ADDR_SET_H__ */ snort-2.9.6.0/src/parser/IpAddrSet.c0000644000000000000000000000573212260565732014007 00000000000000/* $Id$ */ /* * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2002-2013 Sourcefire, Inc. * * Author(s): Andrew R. Baker * Martin Roesch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /* includes */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifndef WIN32 #include #include #include #include #include #include #endif #ifdef HAVE_STRINGS_H #include #endif #include "util.h" #include "mstring.h" #include "parser.h" #include "snort_debug.h" #include "snort.h" #include "sfPolicy.h" #include "IpAddrSet.h" # include "ipv6_port.h" extern char *file_name; /* current rules file being processed */ extern int line_num; /* current rules file line */ IpAddrSet *IpAddrSetParse(SnortConfig *sc, char *addr) { IpAddrSet *ret; int ret_code; vartable_t *ip_vartable; if ((sc == NULL) || (sc->targeted_policies[getParserPolicy(sc)] == NULL)) { FatalError("%s(%d) Snort conf for parsing is NULL.\n", __FILE__, __LINE__); } ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable; DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got address string: %s\n", addr);); ret = (IpAddrSet*)SnortAlloc(sizeof(IpAddrSet)); if((ret_code = sfvt_add_to_var(ip_vartable, ret, addr)) != SFIP_SUCCESS) { if(ret_code == SFIP_LOOKUP_FAILURE) FatalError("%s(%d) => Undefined variable in the string: %s\n", file_name, file_line, addr); else if(ret_code == SFIP_CONFLICT) FatalError("%s(%d) => Negated IP ranges that equal to or are" " more-specific than non-negated ranges are not allowed." " Consider inverting the logic: %s.\n", file_name, file_line, addr); else FatalError("%s(%d) => Unable to process the IP address: %s\n", file_name, file_line, addr); } return ret; } void IpAddrSetDestroy(IpAddrSet *ipAddrSet) { if(!ipAddrSet) return; sfvar_free(ipAddrSet); } snort-2.9.6.0/src/parser/Makefile.am0000644000000000000000000000021707560030352014041 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libparser.a libparser_a_SOURCES = IpAddrSet.c IpAddrSet.h INCLUDES = @INCLUDES@ snort-2.9.6.0/src/parser/Makefile.in0000644000000000000000000003767112260606524014073 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/parser DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libparser_a_AR = $(AR) $(ARFLAGS) libparser_a_LIBADD = am_libparser_a_OBJECTS = IpAddrSet.$(OBJEXT) libparser_a_OBJECTS = $(am_libparser_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libparser_a_SOURCES) DIST_SOURCES = $(libparser_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libparser.a libparser_a_SOURCES = IpAddrSet.c IpAddrSet.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/parser/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/parser/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libparser.a: $(libparser_a_OBJECTS) $(libparser_a_DEPENDENCIES) $(EXTRA_libparser_a_DEPENDENCIES) $(AM_V_at)-rm -f libparser.a $(AM_V_AR)$(libparser_a_AR) libparser.a $(libparser_a_OBJECTS) $(libparser_a_LIBADD) $(AM_V_at)$(RANLIB) libparser.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/preprocessors/0000755000000000000000000000000012260606562013507 500000000000000snort-2.9.6.0/src/preprocessors/Stream5/0000755000000000000000000000000012260606563015030 500000000000000snort-2.9.6.0/src/preprocessors/Stream5/stream5_ha.h0000644000000000000000000000702712260565733017162 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ****************************************************************************/ /************************************************************************** * * stream5_ha.h * * Authors: Michael Altizer , Russ Combs * * Description: * * Stream5 high availability exported functionality. * **************************************************************************/ #ifndef __STREAM5_HA_H__ #define __STREAM5_HA_H__ #ifdef ENABLE_HA #include "sf_types.h" #include "snort_stream5_session.h" typedef enum { HA_EVENT_UPDATE, HA_EVENT_DELETE, HA_EVENT_MAX } HA_Event; typedef Stream5LWSession *(*f_ha_create_session) (const SessionKey *); typedef int (*f_ha_delete_session) (const SessionKey *); typedef Stream5LWSession *(*f_ha_get_lws) (const SessionKey *); typedef void (*f_ha_deactivate_session) (Stream5LWSession *); typedef struct { f_ha_get_lws get_lws; f_ha_create_session create_session; f_ha_deactivate_session deactivate_session; f_ha_delete_session delete_session; } HA_Api; extern int ha_set_api(unsigned proto, const HA_Api *); // Used with Stream5LWSession.ha_flags: #define HA_FLAG_STANDBY 0x01 // session is not active #define HA_FLAG_NEW 0x02 // flow has never been synchronized #define HA_FLAG_MODIFIED 0x04 // session HA state information has been modified #define HA_FLAG_MAJOR_CHANGE 0x08 // session HA state information has been modified in a major fashion #define HA_FLAG_CRITICAL_CHANGE 0x10 // session HA state information has been modified in a critical fashion #define HA_FLAG_DELETED 0x20 // flow deletion message has been sent int RegisterStreamHAFuncs(uint32_t preproc_id, uint8_t subcode, uint8_t size, StreamHAProducerFunc produce, StreamHAConsumerFunc consume); void UnregisterStreamHAFuncs(uint32_t preproc_id, uint8_t subcode); void Stream5SetHAPendingBit(void *ssnptr, int bit); void Stream5HAInit(struct _SnortConfig *sc, char *args); int Stream5VerifyHAConfig(struct _SnortConfig *sc, Stream5HAConfig *config, tSfPolicyId policy_id); #if defined(SNORT_RELOAD) void Stream5HAReload(struct _SnortConfig *sc, char *args, void **new_config); #endif void Stream5HAConfigFree(Stream5HAConfig *config); void Stream5HAPostConfigInit(struct _SnortConfig *sc, int unused, void *arg); void Stream5CleanHA(void); void Stream5PrintHAStats(void); void Stream5ResetHAStats(void); void Stream5ProcessHA(void *ssnptr); void Stream5HANotifyDeletion(Stream5LWSession *lwssn); #endif /* ENABLE_HA */ #endif /* __STREAM5_HA_H__ */ snort-2.9.6.0/src/preprocessors/Stream5/stream5_ha.c0000644000000000000000000014423512260565733017160 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2012-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ /************************************************************************** * * stream5_ha.c * * Authors: Michael Altizer , Russ Combs * * Description: * * Stream5 high availability support. * **************************************************************************/ #include #include #include #include #include #include "mstring.h" #include "packet_time.h" #include "parser.h" #include "sfcontrol_funcs.h" #ifdef SIDE_CHANNEL #include "sidechannel.h" #endif #include "stream5_ha.h" #include "util.h" /* * Stream5 HA messages will have the following format: * * ::=
*
::= version * ::= HA_EVENT_UPDATE | HA_EVENT_DELETE * ::= | * ::= HA_TYPE_KEY sizeof(ipv4-key) ipv4-key * ::= HA_TYPE_KEY sizeof(ipv6-key) ipv6-key * ::= HA_TYPE_HAS sizeof(has-rec) has-rec | (null) * ::= HA_TYPE_PSD sizeof(psd-rec) psd-preprocid psd-subcode psd-rec | (null) */ typedef struct _StreamHAFuncsNode { uint16_t id; uint16_t mask; uint8_t preproc_id; uint8_t subcode; uint8_t size; StreamHAProducerFunc produce; StreamHAConsumerFunc consume; uint32_t produced; uint32_t consumed; } StreamHAFuncsNode; typedef enum { HA_TYPE_KEY, // Lightweight Session Key HA_TYPE_HAS, // Lightweight Session Data HA_TYPE_PSD, // Preprocessor-specific Data HA_TYPE_MAX } HA_Type; typedef struct _MsgHeader { uint8_t event; uint8_t version; uint16_t total_length; uint8_t key_type; uint8_t key_size; } MsgHeader; typedef struct _RecordHeader { uint8_t type; uint8_t length; } RecordHeader; typedef struct _PreprocDataHeader { uint8_t preproc_id; uint8_t subcode; } PreprocDataHeader; /* Something more will probably be added to this structure in the future... */ #define HA_SESSION_FLAG_LOW 0x01 // client address / port is low in key #define HA_SESSION_FLAG_IP6 0x02 // key addresses are ip6 typedef struct { Stream5HAState ha_state; uint8_t flags; } Stream5HASession; typedef struct { uint32_t update_messages_received; uint32_t update_messages_received_no_session; uint32_t delete_messages_received; uint32_t update_messages_sent_immediately; uint32_t update_messages_sent_normally; uint32_t delete_messages_sent; uint32_t delete_messages_not_sent; } Stream5HAStats; typedef struct _HADebugSessionConstraints { sfip_t sip; sfip_t dip; uint16_t sport; uint16_t dport; uint8_t protocol; } HADebugSessionConstraints; #define MAX_STREAM_HA_FUNCS 8 // depends on sizeof(Stream5LWSession.ha_pending_mask) #define HA_MESSAGE_VERSION 0x81 static StreamHAFuncsNode *stream_ha_funcs[MAX_STREAM_HA_FUNCS]; static int n_stream_ha_funcs = 0; static int runtime_output_fd = -1; static uint8_t file_io_buffer[UINT16_MAX]; static Stream5HAStats s5ha_stats; /* Runtime debugging stuff. */ #define HA_DEBUG_SESSION_ID_SIZE (39+1+5+5+39+1+5+1+3+1) /* ": <-> : \0" */ static HADebugSessionConstraints s5_ha_debug_info; static volatile int s5_ha_debug_flag = 0; static char s5_ha_debug_session[HA_DEBUG_SESSION_ID_SIZE]; #define IP6_SESSION_KEY_SIZE sizeof(SessionKey) #define IP4_SESSION_KEY_SIZE (IP6_SESSION_KEY_SIZE - 24) #ifdef PERF_PROFILING PreprocStats s5HAPerfStats; PreprocStats s5HAConsumePerfStats; PreprocStats s5HAProducePerfStats; #endif //-------------------------------------------------------------------- // Runtime debugging support. //-------------------------------------------------------------------- static inline bool Stream5HADebugCheck(const SessionKey *key, volatile int debug_flag, HADebugSessionConstraints *info, char *debug_session, size_t debug_session_len) { #ifndef REG_TEST if (debug_flag) { if ((!info->protocol || info->protocol == key->protocol) && (((!info->sport || info->sport == key->port_l) && (!sfip_is_set(&info->sip) || memcmp(&info->sip.ip, key->ip_l, sizeof(info->sip.ip)) == 0) && (!info->dport || info->dport == key->port_h) && (!sfip_is_set(&info->dip) || memcmp(&info->dip.ip, key->ip_h, sizeof(info->dip.ip)) == 0)) || ((!info->sport || info->sport == key->port_h) && (!sfip_is_set(&info->sip) || memcmp(&info->sip.ip, key->ip_h, sizeof(info->sip.ip)) == 0) && (!info->dport || info->dport == key->port_l) && (!sfip_is_set(&info->dip) || memcmp(&info->dip.ip, key->ip_l, sizeof(info->dip.ip)) == 0)))) { #endif int af; char lipstr[INET6_ADDRSTRLEN]; char hipstr[INET6_ADDRSTRLEN]; if (!key->ip_l[1] && !key->ip_l[2] && !key->ip_l[3] && !key->ip_h[1] && !key->ip_h[2] && !key->ip_h[3]) af = AF_INET; else af = AF_INET6; lipstr[0] = '\0'; sfip_raw_ntop(af, key->ip_l, lipstr, sizeof(lipstr)); hipstr[0] = '\0'; sfip_raw_ntop(af, key->ip_h, hipstr, sizeof(hipstr)); snprintf(debug_session, debug_session_len, "%s:%hu <-> %s:%hu %hhu", lipstr, key->port_l, hipstr, key->port_h, key->protocol); return true; #ifndef REG_TEST } } return false; #endif } static void Stream5HADebugParse(const char *desc, const uint8_t *data, uint32_t length, volatile int *debug_flag, HADebugSessionConstraints *info) { *debug_flag = 0; memset(info, 0, sizeof(*info)); do { if (length >= sizeof(info->protocol)) { info->protocol = *(uint8_t *)data; length -= sizeof(info->protocol); data += sizeof(info->protocol); } else break; if (length >= sizeof(info->sip.ip)) { if (memcmp(data + 4, info->sip.ip8 + 4, 12) == 0) { if (memcmp(data, info->sip.ip8, 4) != 0) sfip_set_raw(&info->sip, (void *) data, AF_INET); } else sfip_set_raw(&info->sip, (void *) data, AF_INET6); length -= sizeof(info->sip.ip); data += sizeof(info->sip.ip); } else break; if (length >= sizeof(info->sport)) { info->sport = *(uint16_t *)data; length -= sizeof(info->sport); data += sizeof(info->sport); } else break; if (length >= sizeof(info->dip.ip)) { if (memcmp(data + 4, info->dip.ip8 + 4, 12) == 0) { if (memcmp(data, info->dip.ip8, 4) != 0) sfip_set_raw(&info->dip, (void *) data, AF_INET); } else sfip_set_raw(&info->dip, (void *) data, AF_INET6); length -= sizeof(info->dip.ip); data += sizeof(info->dip.ip); } else break; if (length >= sizeof(info->dport)) { info->dport = *(uint16_t *)data; length -= sizeof(info->dport); data += sizeof(info->dport); } else break; } while (0); if (info->protocol || sfip_is_set(&info->sip) || info->sport || sfip_is_set(&info->dip) || info->dport) { char sipstr[INET6_ADDRSTRLEN]; char dipstr[INET6_ADDRSTRLEN]; sipstr[0] = '\0'; if (sfip_is_set(&info->sip)) sfip_ntop(&info->sip, sipstr, sizeof(sipstr)); else snprintf(sipstr, sizeof(sipstr), "any"); dipstr[0] = '\0'; if (sfip_is_set(&info->dip)) sfip_ntop(&info->dip, dipstr, sizeof(dipstr)); else snprintf(dipstr, sizeof(dipstr), "any"); LogMessage("Debugging %s with %s-%hu and %s-%hu %hhu\n", desc, sipstr, info->sport, dipstr, info->dport, info->protocol); *debug_flag = 1; } else LogMessage("Debugging %s disabled\n", desc); } static int Stream5DebugHA(uint16_t type, const uint8_t *data, uint32_t length, void **new_context, char *statusBuf, int statusBuf_len) { Stream5HADebugParse("S5HA", data, length, &s5_ha_debug_flag, &s5_ha_debug_info); return 0; } //-------------------------------------------------------------------- // Protocol-specific HA API // could use an array here (and an enum instead of IPPROTO_*) //-------------------------------------------------------------------- static const HA_Api *s_tcp = NULL; static const HA_Api *s_udp = NULL; static const HA_Api *s_ip = NULL; int ha_set_api(unsigned proto, const HA_Api *api) { switch (proto) { case IPPROTO_TCP: s_tcp = api; break; case IPPROTO_UDP: s_udp = api; break; case IPPROTO_IP: s_ip = api; break; default: return -1; } return 0; } static inline const HA_Api *ha_get_api(unsigned proto) { switch (proto) { case IPPROTO_TCP: return s_tcp; case IPPROTO_UDP: return s_udp; case IPPROTO_ICMP: case IPPROTO_IP: default: return s_ip; } return NULL; } int RegisterStreamHAFuncs(uint32_t preproc_id, uint8_t subcode, uint8_t size, StreamHAProducerFunc produce, StreamHAConsumerFunc consume) { StreamHAFuncsNode *node; int i, idx; if (produce == NULL || consume == NULL) { FatalError("One must be both a producer and a consumer to participate in Stream5 HA!\n"); } if (preproc_id > UINT8_MAX) { FatalError("Preprocessor ID must be between 0 and %d to participate in Stream5 HA!\n", UINT8_MAX); } idx = n_stream_ha_funcs; for (i = 0; i < n_stream_ha_funcs; i++) { node = stream_ha_funcs[i]; if (node) { if (preproc_id == node->preproc_id && subcode == node->subcode) { FatalError("Duplicate Stream5 HA registration attempt for preprocessor %hu with subcode %hu\n", node->preproc_id, node->subcode); } } else if (idx == n_stream_ha_funcs) idx = i; } if (idx == MAX_STREAM_HA_FUNCS) { FatalError("Attempted to register more than %d Stream5 HA types!\n", MAX_STREAM_HA_FUNCS); } if (idx == n_stream_ha_funcs) n_stream_ha_funcs++; node = (StreamHAFuncsNode *) SnortAlloc(sizeof(StreamHAFuncsNode)); node->id = idx; node->mask = (1 << idx); node->preproc_id = (uint8_t) preproc_id; node->subcode = subcode; node->size = size; node->produce = produce; node->consume = consume; stream_ha_funcs[idx] = node; LogMessage("Stream5HA: Registered node %hu for preprocessor ID %hhu with subcode %hhu (size %hhu)\n", node->id, node->preproc_id, node->subcode, node->size); return idx; } void UnregisterStreamHAFuncs(uint32_t preproc_id, uint8_t subcode) { StreamHAFuncsNode *node; int i; for (i = 0; i < n_stream_ha_funcs; i++) { node = stream_ha_funcs[i]; if (node && preproc_id == node->preproc_id && subcode == node->subcode) { stream_ha_funcs[i] = NULL; free(node); break; } } if ((i + 1) == n_stream_ha_funcs) n_stream_ha_funcs--; } void Stream5SetHAPendingBit(void *ssnptr, int bit) { Stream5LWSession *lwssn = (Stream5LWSession*) ssnptr; if (!lwssn) return; if (bit >= n_stream_ha_funcs || !stream_ha_funcs[bit]) { FatalError("Attempted to set illegal HA pending bit %d!\n", bit); } lwssn->ha_pending_mask |= (1 << bit); } static void Stream5ParseHAArgs(SnortConfig *sc, Stream5HAConfig *config, char *args) { char **toks; int num_toks; int i; char **stoks = NULL; int s_toks; char *endPtr = NULL; unsigned long int value; if (config == NULL) return; if ((args == NULL) || (strlen(args) == 0)) return; toks = mSplit(args, ",", 0, &num_toks, 0); for (i = 0; i < num_toks; i++) { stoks = mSplit(toks[i], " ", 2, &s_toks, 0); if (s_toks == 0) { FatalError("%s(%d) => Missing parameter in Stream5 HA config.\n", file_name, file_line); } if (!strcmp(stoks[0], "min_session_lifetime")) { if (stoks[1]) value = strtoul(stoks[1], &endPtr, 10); else value = 0; if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid '%s' in config file. Requires integer parameter.\n", file_name, file_line, stoks[0]); } if (value > UINT16_MAX) { FatalError("%s(%d) => '%s %lu' invalid: value must be between 0 and %d milliseconds.\n", file_name, file_line, stoks[0], value, UINT16_MAX); } config->min_session_lifetime.tv_sec = 0; while (value >= 1000) { config->min_session_lifetime.tv_sec++; value -= 1000; } config->min_session_lifetime.tv_usec = value * 1000; } else if (!strcmp(stoks[0], "min_sync_interval")) { if (stoks[1]) value = strtoul(stoks[1], &endPtr, 10); else value = 0; if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid '%s' in config file. Requires integer parameter.\n", file_name, file_line, stoks[0]); } if (value > UINT16_MAX) { FatalError("%s(%d) => '%s %lu' invalid: value must be between 0 and %d milliseconds.\n", file_name, file_line, stoks[0], value, UINT16_MAX); } config->min_sync_interval.tv_sec = 0; while (value >= 1000) { config->min_sync_interval.tv_sec++; value -= 1000; } config->min_sync_interval.tv_usec = value * 1000; } else if (!strcmp(stoks[0], "startup_input_file")) { if (!stoks[1]) { FatalError("%s(%d) => '%s' missing an argument\n", file_name, file_line, stoks[0]); } if (config->startup_input_file) { FatalError("%s(%d) => '%s' specified multiple times\n", file_name, file_line, stoks[0]); } config->startup_input_file = SnortStrdup(stoks[1]); } else if (!strcmp(stoks[0], "runtime_output_file")) { if (!stoks[1]) { FatalError("%s(%d) => '%s' missing an argument\n", file_name, file_line, stoks[0]); } if (config->runtime_output_file) { FatalError("%s(%d) => '%s' specified multiple times\n", file_name, file_line, stoks[0]); } config->runtime_output_file = SnortStrdup(stoks[1]); } else if (!strcmp(stoks[0], "shutdown_output_file")) { if (!stoks[1]) { FatalError("%s(%d) => '%s' missing an argument\n", file_name, file_line, stoks[0]); } if (config->shutdown_output_file) { FatalError("%s(%d) => '%s' specified multiple times\n", file_name, file_line, stoks[0]); } config->shutdown_output_file = SnortStrdup(stoks[1]); } else if (!strcmp(stoks[0], "use_side_channel")) { #ifdef SIDE_CHANNEL if (!sc->side_channel_config.enabled) { FatalError("%s(%d) => '%s' cannot be specified without enabling the Snort side channel.\n", file_name, file_line, stoks[0]); } config->use_side_channel = 1; #else FatalError("%s(%d) => Snort has been compiled without Side Channel support.\n", file_name, file_line); #endif } else { FatalError("%s(%d) => Invalid Stream5 HA config option '%s'\n", file_name, file_line, stoks[0]); } mSplitFree(&stoks, s_toks); } mSplitFree(&toks, num_toks); #ifdef REG_TEST if(sc->ha_out) { if(config->runtime_output_file) free(config->runtime_output_file); config->runtime_output_file = SnortStrdup(sc->ha_out); } if(sc->ha_in) { if(config->startup_input_file) free(config->startup_input_file); config->startup_input_file = SnortStrdup(sc->ha_in); } #endif } static void Stream5PrintHAConfig(Stream5HAConfig *config) { if (config == NULL) return; LogMessage("Stream5 HA config:\n"); LogMessage(" Minimum Session Lifetime: %lu milliseconds\n", config->min_session_lifetime.tv_sec * 1000 + config->min_session_lifetime.tv_usec / 1000); LogMessage(" Minimum Sync Interval: %lu milliseconds\n", config->min_sync_interval.tv_sec * 1000 + config->min_sync_interval.tv_usec / 1000); if (config->startup_input_file) LogMessage(" Startup Input File: %s\n", config->startup_input_file); if (config->runtime_output_file) LogMessage(" Runtime Output File: %s\n", config->runtime_output_file); if (config->shutdown_output_file) LogMessage(" Shutdown Output File: %s\n", config->shutdown_output_file); #ifdef REG_TEST LogMessage(" Stream5 LWS HA Data Size: %zu\n", sizeof(Stream5HASession)); #endif } void Stream5PrintHAStats(void) { StreamHAFuncsNode *node; int i; LogMessage(" High Availability\n"); LogMessage(" Updates Received: %u\n", s5ha_stats.update_messages_received); LogMessage("Updates Received (No Session): %u\n", s5ha_stats.update_messages_received_no_session); LogMessage(" Deletions Received: %u\n", s5ha_stats.delete_messages_received); LogMessage(" Updates Sent Immediately: %u\n", s5ha_stats.update_messages_sent_immediately); LogMessage(" Updates Sent Normally: %u\n", s5ha_stats.update_messages_sent_normally); LogMessage(" Deletions Sent: %u\n", s5ha_stats.delete_messages_sent); LogMessage(" Deletions Not Sent: %u\n", s5ha_stats.delete_messages_not_sent); for (i = 0; i < n_stream_ha_funcs; i++) { node = stream_ha_funcs[i]; if (!node) continue; LogMessage(" Node %hhu/%hhu: %u produced, %u consumed\n", node->preproc_id, node->subcode, node->produced, node->consumed); } } void Stream5ResetHAStats(void) { memset(&s5ha_stats, 0, sizeof(s5ha_stats)); } void Stream5HAInit(struct _SnortConfig *sc, char *args) { tSfPolicyId policy_id = getParserPolicy(sc); Stream5Config *pDefaultPolicyConfig = NULL; Stream5Config *pCurrentPolicyConfig = NULL; if (s5_config == NULL) FatalError("Tried to config stream5 HA policy without global config!\n"); sfPolicyUserPolicySet(s5_config, policy_id); pDefaultPolicyConfig = (Stream5Config *)sfPolicyUserDataGet(s5_config, getDefaultPolicy()); pCurrentPolicyConfig = (Stream5Config *)sfPolicyUserDataGetCurrent(s5_config); if ((policy_id != getDefaultPolicy()) && ((pDefaultPolicyConfig == NULL) || (pDefaultPolicyConfig->ha_config == NULL))) { ParseError("Stream5 HA: Must configure default policy if other targeted policies are configured.\n"); } if ((pCurrentPolicyConfig == NULL) || (pCurrentPolicyConfig->global_config == NULL)) { FatalError("Tried to config stream5 HA policy without global config!\n"); } if (pCurrentPolicyConfig->ha_config != NULL) { FatalError("%s(%d) ==> Cannot duplicate Stream5 HA configuration\n", file_name, file_line); } if (!pCurrentPolicyConfig->global_config->enable_ha) { # ifdef SNORT_RELOAD /* Return if we're reloading - the discrepancy will be handled in * the reload verify */ if (GetReloadStreamConfig(sc) != NULL) # endif return; } pCurrentPolicyConfig->ha_config = (Stream5HAConfig*)SnortAlloc(sizeof(*pCurrentPolicyConfig->ha_config)); Stream5ParseHAArgs(sc, pCurrentPolicyConfig->ha_config, args); if (policy_id != getDefaultPolicy()) { pCurrentPolicyConfig->ha_config->min_session_lifetime = pDefaultPolicyConfig->ha_config->min_session_lifetime; pCurrentPolicyConfig->ha_config->min_sync_interval = pDefaultPolicyConfig->ha_config->min_sync_interval; } #ifdef PERF_PROFILING RegisterPreprocessorProfile("s5HAProduce", &s5HAProducePerfStats, 2, &s5HAPerfStats); RegisterPreprocessorProfile("s5HAConsume", &s5HAConsumePerfStats, 0, &totalPerfStats); #endif ControlSocketRegisterHandler(CS_TYPE_DEBUG_S5_HA, Stream5DebugHA, NULL, NULL); LogMessage("Registered Stream5HA Debug control socket message type (0x%x)\n", CS_TYPE_DEBUG_S5_HA); Stream5PrintHAConfig(pCurrentPolicyConfig->ha_config); } #if defined(SNORT_RELOAD) void Stream5HAReload(struct _SnortConfig *sc, char *args, void **new_config) { tSfPolicyUserContextId s5_swap_config = (tSfPolicyUserContextId)*new_config; tSfPolicyId policy_id = getParserPolicy(sc); Stream5Config *config; s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc); if (s5_swap_config == NULL) FatalError("Tried to config stream5 HA without global config!\n"); config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policy_id); if ((config == NULL) || (config->global_config == NULL)) { FatalError("Tried to config stream5 HA without global config!\n"); } if (config->ha_config == NULL) config->ha_config = (Stream5HAConfig *)SnortAlloc(sizeof(*config->ha_config)); Stream5ParseHAArgs(sc, config->ha_config, args); Stream5PrintHAConfig(config->ha_config); } #endif int Stream5VerifyHAConfig(struct _SnortConfig *sc, Stream5HAConfig *config, tSfPolicyId policy_id) { if (config == NULL) return -1; return 0; } void Stream5HAConfigFree(Stream5HAConfig *config) { if (config == NULL) return; if (config->startup_input_file) free(config->startup_input_file); if (config->runtime_output_file) free(config->runtime_output_file); if (config->shutdown_output_file) free(config->shutdown_output_file); free(config); } // This MUST have the exact same logic as GetLWSessionKeyFromIpPort() // TBD any alternative to this approach? static inline bool IsClientLower(const sfip_t *cltIP, uint16_t cltPort, const sfip_t *srvIP, uint16_t srvPort, char proto) { if (IS_IP4(cltIP)) { if (cltIP->ip32 < srvIP->ip32) return true; if (cltIP->ip32 > srvIP->ip32) return false; switch (proto) { case IPPROTO_TCP: case IPPROTO_UDP: if (cltPort < srvPort) return true; } return false; } if (sfip_fast_lt6(cltIP, srvIP)) return true; if (sfip_fast_lt6(srvIP, cltIP)) return false; switch (proto) { case IPPROTO_TCP: case IPPROTO_UDP: if (cltPort < srvPort) return true; } return false; } static Stream5LWSession *DeserializeHASession(const SessionKey *key, const Stream5HASession *has, Stream5LWSession *lwssn) { Stream5LWSession *retSsn; int family; if (!lwssn) { const HA_Api *api; api = ha_get_api(key->protocol); retSsn = api->create_session(key); retSsn->ha_flags &= ~HA_FLAG_NEW; family = (has->flags & HA_SESSION_FLAG_IP6) ? AF_INET6 : AF_INET; if (has->flags & HA_SESSION_FLAG_LOW) { sfip_set_raw(&retSsn->server_ip, retSsn->key->ip_l, family); sfip_set_raw(&retSsn->client_ip, retSsn->key->ip_h, family); retSsn->server_port = retSsn->key->port_l; retSsn->client_port = retSsn->key->port_h; } else { sfip_set_raw(&retSsn->client_ip, retSsn->key->ip_l, family); sfip_set_raw(&retSsn->server_ip, retSsn->key->ip_h, family); retSsn->client_port = retSsn->key->port_l; retSsn->server_port = retSsn->key->port_h; } } else { retSsn = lwssn; } retSsn->ha_state = has->ha_state; return retSsn; } static inline int DeserializePreprocData(uint8_t event, Stream5LWSession *lwssn, uint8_t preproc_id, uint8_t subcode, const uint8_t *data, uint8_t length) { StreamHAFuncsNode *node; int i; for (i = 0; i < n_stream_ha_funcs; i++) { node = stream_ha_funcs[i]; if (node && preproc_id == node->preproc_id && subcode == node->subcode) { if (node->size < length) { ErrorMessage("Stream5 HA preprocessor data record's length exceeds expected size! (%u vs %u)\n", length, node->size); return -1; } node->consumed++; return node->consume(lwssn, data, length); } } ErrorMessage("Stream5 HA preprocessor data record received with unrecognized preprocessor ID/subcode! (%hhu:%hhu)\n", preproc_id, subcode); return -1; } static int ConsumeHAMessage(const uint8_t *msg, uint32_t msglen) { const HA_Api *api; Stream5HASession *has; Stream5LWSession *lwssn; SessionKey key; MsgHeader *msg_hdr; RecordHeader *rec_hdr; PreprocDataHeader *psd_hdr; uint32_t offset; bool debug_flag; int rval = 1; PROFILE_VARS; PREPROC_PROFILE_START(s5HAConsumePerfStats); /* Read the message header */ if (msglen < sizeof(*msg_hdr)) { ErrorMessage("Stream5 HA message length shorter than header length! (%u)\n", msglen); goto consume_exit; } msg_hdr = (MsgHeader *) msg; offset = sizeof(*msg_hdr); if (msg_hdr->total_length != msglen) { ErrorMessage("Stream5 HA message header's total length does not match actual length! (%u vs %u)\n", msg_hdr->total_length, msglen); goto consume_exit; } if (msg_hdr->event != HA_EVENT_UPDATE && msg_hdr->event != HA_EVENT_DELETE) { ErrorMessage("Stream5 HA message has unknown event type: %hhu!\n", msg_hdr->event); goto consume_exit; } /* Read the key */ if (msg_hdr->key_size == IP4_SESSION_KEY_SIZE) /* IPv4, miniature key */ { /* Lower IPv4 address */ memcpy(&key.ip_l, msg + offset, 4); key.ip_l[1] = key.ip_l[2] = key.ip_l[3] = 0; offset += 4; /* Higher IPv4 address */ memcpy(&key.ip_h, msg + offset, 4); key.ip_h[1] = key.ip_h[2] = key.ip_h[3] = 0; offset += 4; /* The remainder of the key */ memcpy(((uint8_t *) &key) + 32, msg + offset, IP4_SESSION_KEY_SIZE - 8); offset += IP4_SESSION_KEY_SIZE - 8; } else if (msg_hdr->key_size == IP6_SESSION_KEY_SIZE) /* IPv6, full-size key */ { memcpy(&key, msg + offset, IP6_SESSION_KEY_SIZE); offset += IP6_SESSION_KEY_SIZE; } else { ErrorMessage("Stream5 HA message has unrecognized key size: %hhu!\n", msg_hdr->key_size); goto consume_exit; } debug_flag = Stream5HADebugCheck(&key, s5_ha_debug_flag, &s5_ha_debug_info, s5_ha_debug_session, sizeof(s5_ha_debug_session)); api = ha_get_api(key.protocol); if (!api) { ErrorMessage("Stream5 HA message has unhandled protocol: %u!\n", key.protocol); goto consume_exit; } if (msg_hdr->event == HA_EVENT_DELETE) { if (debug_flag) LogMessage("S5HADbg Consuming deletion message for %s\n", s5_ha_debug_session); if (offset != msglen) { ErrorMessage("Stream5 HA deletion message contains extraneous data! (%u bytes)\n", msglen - offset); goto consume_exit; } s5ha_stats.delete_messages_received++; rval = api->delete_session(&key); if (debug_flag) { if (!rval) LogMessage("S5HADbg Deleted LWSession for %s\n", s5_ha_debug_session); else LogMessage("S5HADbg Could not delete LWSession for %s\n", s5_ha_debug_session); } goto consume_exit; } if (debug_flag) LogMessage("S5HADbg Consuming update message for %s\n", s5_ha_debug_session); lwssn = api->get_lws(&key); /* Read any/all records. */ while (offset < msglen) { if (sizeof(*rec_hdr) > (msglen - offset)) { ErrorMessage("Stream5 HA message contains a truncated record header! (%zu vs %u)\n", sizeof(*rec_hdr), msglen - offset); goto consume_exit; } rec_hdr = (RecordHeader *) (msg + offset); offset += sizeof(*rec_hdr); switch (rec_hdr->type) { case HA_TYPE_HAS: if (rec_hdr->length != sizeof(*has)) { ErrorMessage("Stream5 HA message contains incorrectly size HA Session record! (%u vs %zu)\n", rec_hdr->length, sizeof(*has)); goto consume_exit; } if (rec_hdr->length > (msglen - offset)) { ErrorMessage("Stream5 HA message contains truncated HA Session record data! (%u vs %u)\n", rec_hdr->length, msglen - offset); goto consume_exit; } has = (Stream5HASession *) (msg + offset); offset += rec_hdr->length; if (debug_flag) { #ifdef TARGET_BASED LogMessage("S5HADbg %s LWSession for %s - SF=0x%x IPP=0x%hx AP=0x%hx DIR=%hhu IDIR=%hhu\n", (lwssn) ? "Updating" : "Creating", s5_ha_debug_session, has->ha_state.session_flags, has->ha_state.ipprotocol, has->ha_state.application_protocol, has->ha_state.direction, has->ha_state.ignore_direction); #else LogMessage("S5HADbg %s LWSession for %s - SF=0x%x DIR=%hhu IDIR=%hhu\n", (lwssn) ? "Updating" : "Creating", s5_ha_debug_session, has->ha_state.session_flags, has->ha_state.direction, has->ha_state.ignore_direction); #endif } lwssn = DeserializeHASession(&key, has, lwssn); break; case HA_TYPE_PSD: if (!lwssn) { //ErrorMessage("Stream5 HA message with preprocessor data record received for non-existent session!\n"); s5ha_stats.update_messages_received_no_session++; goto consume_exit; } if (sizeof(*psd_hdr) > (msglen - offset)) { ErrorMessage("Stream5 HA message contains a truncated preprocessor data record header! (%zu vs %u)\n", sizeof(*psd_hdr), msglen - offset); goto consume_exit; } psd_hdr = (PreprocDataHeader *) (msg + offset); offset += sizeof(*psd_hdr); if (rec_hdr->length > (msglen - offset)) { ErrorMessage("Stream5 HA message contains truncated preprocessor data record data! (%u vs %u)\n", rec_hdr->length, msglen - offset); goto consume_exit; } if (debug_flag) { LogMessage("SFHADbg Consuming %hhu byte preprocessor data record for %s with PPID=%hhu and SC=%hhu\n", rec_hdr->length, s5_ha_debug_session, psd_hdr->preproc_id, psd_hdr->subcode); } if (DeserializePreprocData(msg_hdr->event, lwssn, psd_hdr->preproc_id, psd_hdr->subcode, msg + offset, rec_hdr->length) != 0) { ErrorMessage("Stream5 HA message contained invalid preprocessor data record!\n"); goto consume_exit; } offset += rec_hdr->length; break; default: ErrorMessage("Stream5 HA message contains unrecognized record type: %hhu!\n", rec_hdr->type); goto consume_exit; } } /* Mark the session as being in standby mode since we just received an update. */ if (lwssn && !(lwssn->ha_flags & HA_FLAG_STANDBY)) { if (api->deactivate_session) api->deactivate_session(lwssn); lwssn->ha_flags |= HA_FLAG_STANDBY; } s5ha_stats.update_messages_received++; rval = 0; consume_exit: PREPROC_PROFILE_END(s5HAConsumePerfStats); return rval; } /* * File I/O */ static inline ssize_t Read(int fd, void *buf, size_t count) { ssize_t n; errno = 0; while ((n = read(fd, buf, count)) <= (ssize_t) count) { if (n == (ssize_t) count) return 0; if (n > 0) { buf = (uint8_t *) buf + n; count -= n; } else if (n == 0) break; else if (errno != EINTR) { ErrorMessage("Error reading from Stream5 HA message file: %s (%d)\n", strerror(errno), errno); break; } } return -1; } static int ReadHAMessagesFromFile(const char *filename) { MsgHeader *msg_header; uint8_t *msg; int rval, fd; fd = open(filename, O_RDONLY, 0664); if (fd < 0) { FatalError("Could not open %s for reading HA messages from: %s (%d)\n", filename, strerror(errno), errno); } LogMessage("Reading Stream5 HA messages from '%s'...\n", filename); msg = file_io_buffer; while ((rval = Read(fd, msg, sizeof(*msg_header))) == 0) { msg_header = (MsgHeader *) msg; if (msg_header->total_length < sizeof(*msg_header)) { ErrorMessage("Stream5 HA Message total length (%hu) is way too short!\n", msg_header->total_length); close(fd); return -1; } else if (msg_header->total_length > (UINT16_MAX - sizeof(*msg_header))) { ErrorMessage("Stream5 HA Message total length (%hu) is too long!\n", msg_header->total_length); close(fd); return -1; } else if (msg_header->total_length > sizeof(*msg_header)) { if ((rval = Read(fd, msg + sizeof(*msg_header), msg_header->total_length - sizeof(*msg_header))) != 0) { ErrorMessage("Error reading the remaining %zu bytes of an HA message from file: %s (%d)\n", msg_header->total_length - sizeof(*msg_header), strerror(errno), errno); close(fd); return rval; } } if ((rval = ConsumeHAMessage(msg, msg_header->total_length)) != 0) { close(fd); return rval; } } close(fd); return 0; } static inline ssize_t Write(int fd, const void *buf, size_t count) { ssize_t n; errno = 0; while ((n = write(fd, buf, count)) <= (ssize_t) count) { if (n == (ssize_t) count) return 0; if (n > 0) count -= n; else if (errno != EINTR) { ErrorMessage("Error writing to Stream5 HA message file: %s (%d)\n", strerror(errno), errno); break; } } return -1; } static uint32_t WriteHAMessageHeader(uint8_t event, uint16_t msglen, const SessionKey *key, uint8_t *msg) { MsgHeader *msg_hdr; uint32_t offset; msg_hdr = (MsgHeader *) msg; offset = sizeof(*msg_hdr); msg_hdr->event = event; msg_hdr->version = HA_MESSAGE_VERSION; msg_hdr->total_length = msglen; msg_hdr->key_type = HA_TYPE_KEY; if (key->ip_l[1] || key->ip_l[2] || key->ip_l[3] || key->ip_h[1] || key->ip_h[2] || key->ip_h[3]) { msg_hdr->key_size = IP6_SESSION_KEY_SIZE; memcpy(msg + offset, key, IP6_SESSION_KEY_SIZE); offset += IP6_SESSION_KEY_SIZE; } else { msg_hdr->key_size = IP4_SESSION_KEY_SIZE; memcpy(msg + offset, &key->ip_l[0], sizeof(key->ip_l[0])); offset += sizeof(key->ip_l[0]); memcpy(msg + offset, &key->ip_h[0], sizeof(key->ip_h[0])); offset += sizeof(key->ip_h[0]); memcpy(msg + offset, ((uint8_t *) key) + 32, IP4_SESSION_KEY_SIZE - 8); offset += IP4_SESSION_KEY_SIZE - 8; } return offset; } static void UpdateHAMessageHeaderLength(uint8_t *msg, uint16_t msglen) { MsgHeader *msg_hdr; msg_hdr = (MsgHeader *) msg; msg_hdr->total_length = msglen; } static uint32_t WriteHASession(Stream5LWSession *lwssn, uint8_t *msg) { Stream5HASession *has; RecordHeader *rec_hdr; uint32_t offset; rec_hdr = (RecordHeader *) msg; offset = sizeof(*rec_hdr); rec_hdr->type = HA_TYPE_HAS; rec_hdr->length = sizeof(*has); has = (Stream5HASession *) (msg + offset); offset += sizeof(*has); has->ha_state = lwssn->ha_state; if (!IsClientLower(&lwssn->client_ip, lwssn->client_port, &lwssn->server_ip, lwssn->server_port, lwssn->key->protocol)) has->flags |= HA_SESSION_FLAG_LOW; if (lwssn->client_ip.family == AF_INET6) has->flags |= HA_SESSION_FLAG_IP6; return offset; } static uint32_t WritePreprocDataRecord(Stream5LWSession *lwssn, StreamHAFuncsNode *node, uint8_t *msg) { RecordHeader *rec_hdr; PreprocDataHeader *psd_hdr; uint32_t offset; rec_hdr = (RecordHeader *) msg; offset = sizeof(*rec_hdr); rec_hdr->type = HA_TYPE_PSD; psd_hdr = (PreprocDataHeader *) (msg + offset); offset += sizeof(*psd_hdr); psd_hdr->preproc_id = node->preproc_id; psd_hdr->subcode = node->subcode; rec_hdr->length = node->produce(lwssn, msg + offset); offset += rec_hdr->length; node->produced++; return offset; } static uint32_t CalculateHAMessageSize(uint8_t event, Stream5LWSession *lwssn) { StreamHAFuncsNode *node; SessionKey *key; uint32_t msg_size; int idx; key = lwssn->key; /* Header (including the key). IPv4 keys are miniaturized. */ msg_size = sizeof(MsgHeader); if (key->ip_l[1] || key->ip_l[2] || key->ip_l[3] || key->ip_h[1] || key->ip_h[2] || key->ip_h[3]) msg_size += IP6_SESSION_KEY_SIZE; else msg_size += IP4_SESSION_KEY_SIZE; if (event == HA_EVENT_UPDATE) { /* HA Session record */ //if (lwssn->ha_flags & HA_FLAG_MODIFIED) msg_size += sizeof(RecordHeader) + sizeof(Stream5HASession); /* Preprocessor data records */ for (idx = 0; idx < n_stream_ha_funcs; idx++) { if (lwssn->ha_pending_mask & (1 << idx)) { node = stream_ha_funcs[idx]; if (!node) continue; msg_size += sizeof(RecordHeader) + sizeof(PreprocDataHeader) + node->size; } } } return msg_size; } static uint32_t GenerateHADeletionMessage(uint8_t *msg, uint32_t msg_size, Stream5LWSession *lwssn) { uint32_t msglen; PROFILE_VARS; PREPROC_PROFILE_START(s5HAProducePerfStats); msglen = WriteHAMessageHeader(HA_EVENT_DELETE, msg_size, lwssn->key, msg); PREPROC_PROFILE_END(s5HAProducePerfStats); return msglen; } #ifdef SIDE_CHANNEL static void SendSCDeletionMessage(Stream5LWSession *lwssn, uint32_t msg_size) { SCMsgHdr *sc_hdr; void *msg_handle; uint8_t *msg; int rval; /* Allocate space for the message. */ if ((rval = SideChannelPreallocMessageTX(msg_size, &sc_hdr, &msg, &msg_handle)) != 0) { /* TODO: Error stuff goes here. */ return; } /* Generate the message. */ msg_size = GenerateHADeletionMessage(msg, msg_size, lwssn); /* Send the message. */ sc_hdr->type = SC_MSG_TYPE_FLOW_STATE_TRACKING; sc_hdr->timestamp = packet_time(); SideChannelEnqueueMessageTX(sc_hdr, msg, msg_size, msg_handle, NULL); } #endif void Stream5HANotifyDeletion(Stream5LWSession *lwssn) { Stream5Config *pLWSPolicyConfig; uint32_t msg_size; bool debug_flag; PROFILE_VARS; PREPROC_PROFILE_START(s5HAPerfStats); if (!lwssn) { PREPROC_PROFILE_END(s5HAPerfStats); return; } pLWSPolicyConfig = (Stream5Config *) sfPolicyUserDataGet(lwssn->config, lwssn->policy_id); if (!pLWSPolicyConfig || !pLWSPolicyConfig->global_config || !pLWSPolicyConfig->global_config->enable_ha) { PREPROC_PROFILE_END(s5HAPerfStats); return; } /* Don't send a deletion notice if we've never sent an update for the flow, it is in standby, or we've already sent one. */ if (lwssn->ha_flags & (HA_FLAG_NEW|HA_FLAG_STANDBY|HA_FLAG_DELETED)) { s5ha_stats.delete_messages_not_sent++; PREPROC_PROFILE_END(s5HAPerfStats); return; } debug_flag = Stream5HADebugCheck(lwssn->key, s5_ha_debug_flag, &s5_ha_debug_info, s5_ha_debug_session, sizeof(s5_ha_debug_session)); if (debug_flag) LogMessage("S5HADbg Producing deletion message for %s\n", s5_ha_debug_session); /* Calculate the size of the deletion message. */ msg_size = CalculateHAMessageSize(HA_EVENT_DELETE, lwssn); if (runtime_output_fd >= 0) { msg_size = GenerateHADeletionMessage(file_io_buffer, msg_size, lwssn); if (Write(runtime_output_fd, file_io_buffer, msg_size) == -1) { /* TODO: Error stuff here. */ } } #ifdef SIDE_CHANNEL if (pLWSPolicyConfig->ha_config->use_side_channel) { SendSCDeletionMessage(lwssn, msg_size); } #endif lwssn->ha_flags |= HA_FLAG_DELETED; s5ha_stats.delete_messages_sent++; PREPROC_PROFILE_END(s5HAPerfStats); } static uint32_t GenerateHAUpdateMessage(uint8_t *msg, uint32_t msg_size, Stream5LWSession *lwssn) { StreamHAFuncsNode *node; uint32_t offset; int idx; PROFILE_VARS; PREPROC_PROFILE_START(s5HAProducePerfStats); offset = WriteHAMessageHeader(HA_EVENT_UPDATE, msg_size, lwssn->key, msg); offset += WriteHASession(lwssn, msg + offset); for (idx = 0; idx < n_stream_ha_funcs; idx++) { if (lwssn->ha_pending_mask & (1 << idx)) { node = stream_ha_funcs[idx]; if (!node) continue; offset += WritePreprocDataRecord(lwssn, node, msg + offset); } } /* Update the message header length since it might be shorter than originally anticipated. */ UpdateHAMessageHeaderLength(msg, offset); PREPROC_PROFILE_END(s5HAProducePerfStats); return offset; } #ifdef SIDE_CHANNEL static void SendSCUpdateMessage(Stream5LWSession *lwssn, uint32_t msg_size) { SCMsgHdr *schdr; void *msg_handle; uint8_t *msg; int rval; /* Allocate space for the message. */ if ((rval = SideChannelPreallocMessageTX(msg_size, &schdr, &msg, &msg_handle)) != 0) { /* TODO: Error stuff goes here. */ return; } /* Gnerate the message. */ msg_size = GenerateHAUpdateMessage(msg, msg_size, lwssn); /* Send the message. */ schdr->type = SC_MSG_TYPE_FLOW_STATE_TRACKING; schdr->timestamp = packet_time(); SideChannelEnqueueMessageTX(schdr, msg, msg_size, msg_handle, NULL); } #endif void Stream5ProcessHA(void *ssnptr) { struct timeval pkt_time; Stream5LWSession *lwssn = (Stream5LWSession*) ssnptr; Stream5Config *pLWSPolicyConfig; uint32_t msg_size; bool debug_flag; PROFILE_VARS; PREPROC_PROFILE_START(s5HAPerfStats); if (!lwssn || (!lwssn->ha_pending_mask && !(lwssn->ha_flags & HA_FLAG_MODIFIED))) { PREPROC_PROFILE_END(s5HAPerfStats); return; } pLWSPolicyConfig = (Stream5Config *) sfPolicyUserDataGet(lwssn->config, lwssn->policy_id); if (!pLWSPolicyConfig || !pLWSPolicyConfig->global_config || !pLWSPolicyConfig->global_config->enable_ha) { PREPROC_PROFILE_END(s5HAPerfStats); return; } /* For now, we are only generating messages for: (a) major and critical changes or (b) preprocessor changes on already synchronized sessions. */ if (!(lwssn->ha_flags & (HA_FLAG_MAJOR_CHANGE | HA_FLAG_CRITICAL_CHANGE)) && (!lwssn->ha_pending_mask || (lwssn->ha_flags & HA_FLAG_NEW))) { PREPROC_PROFILE_END(s5HAPerfStats); return; } /* Ensure that a new flow has lived long enough for anyone to care about it and that we're not overrunning the synchronization threshold. */ packet_gettimeofday(&pkt_time); if (pkt_time.tv_sec < lwssn->ha_next_update.tv_sec || (pkt_time.tv_sec == lwssn->ha_next_update.tv_sec && pkt_time.tv_usec < lwssn->ha_next_update.tv_usec)) { /* Critical changes will be allowed to bypass the message timing restrictions. */ if (!(lwssn->ha_flags & HA_FLAG_CRITICAL_CHANGE)) { PREPROC_PROFILE_END(s5HAPerfStats); return; } s5ha_stats.update_messages_sent_immediately++; } else s5ha_stats.update_messages_sent_normally++; debug_flag = Stream5HADebugCheck(lwssn->key, s5_ha_debug_flag, &s5_ha_debug_info, s5_ha_debug_session, sizeof(s5_ha_debug_session)); if (debug_flag) #ifdef TARGET_BASED LogMessage("S5HADbg Producing update message for %s - SF=0x%x IPP=0x%hx AP=0x%hx DIR=%hhu IDIR=%hhu HPM=0x%hhx HF=0x%hhx\n", s5_ha_debug_session, lwssn->ha_state.session_flags, lwssn->ha_state.ipprotocol, lwssn->ha_state.application_protocol, lwssn->ha_state.direction, lwssn->ha_state.ignore_direction, lwssn->ha_pending_mask, lwssn->ha_flags); #else LogMessage("S5HADbg Producing update message for %s - SF=0x%x DIR=%hhu IDIR=%hhu HPM=0x%hhx HF=0x%hhx\n", s5_ha_debug_session, lwssn->ha_state.session_flags, lwssn->ha_state.direction, lwssn->ha_state.ignore_direction, lwssn->ha_pending_mask, lwssn->ha_flags); #endif /* Calculate the size of the update message. */ msg_size = CalculateHAMessageSize(HA_EVENT_UPDATE, lwssn); if (runtime_output_fd >= 0) { msg_size = GenerateHAUpdateMessage(file_io_buffer, msg_size, lwssn); if (Write(runtime_output_fd, file_io_buffer, msg_size) == -1) { /* TODO: Error stuff here. */ } } #ifdef SIDE_CHANNEL if (pLWSPolicyConfig->ha_config->use_side_channel) { SendSCUpdateMessage(lwssn, msg_size); } #endif /* Calculate the next update threshold. */ lwssn->ha_next_update.tv_usec += pLWSPolicyConfig->ha_config->min_session_lifetime.tv_usec; if (lwssn->ha_next_update.tv_usec > 1000000) { lwssn->ha_next_update.tv_usec -= 1000000; lwssn->ha_next_update.tv_sec++; } lwssn->ha_next_update.tv_sec += pLWSPolicyConfig->ha_config->min_session_lifetime.tv_sec; /* Clear the modified/new flags and pending preprocessor updates. */ lwssn->ha_flags &= ~(HA_FLAG_NEW|HA_FLAG_MODIFIED|HA_FLAG_MAJOR_CHANGE|HA_FLAG_CRITICAL_CHANGE); lwssn->ha_pending_mask = 0; PREPROC_PROFILE_END(s5HAPerfStats); } #ifdef SIDE_CHANNEL static int Stream5HASCMsgHandler(SCMsgHdr *hdr, const uint8_t *msg, uint32_t msglen) { int rval; PROFILE_VARS; PREPROC_PROFILE_START(s5HAPerfStats); rval = ConsumeHAMessage(msg, msglen); PREPROC_PROFILE_END(s5HAPerfStats); return rval; } #endif void Stream5HAPostConfigInit(struct _SnortConfig *sc, int unused, void *arg) { Stream5Config *pDefaultPolicyConfig; int rval; pDefaultPolicyConfig = (Stream5Config *)sfPolicyUserDataGet(s5_config, getDefaultPolicy()); if (!pDefaultPolicyConfig->global_config->enable_ha) return; if (pDefaultPolicyConfig->ha_config->startup_input_file) { if ((rval = ReadHAMessagesFromFile(pDefaultPolicyConfig->ha_config->startup_input_file)) != 0) { ErrorMessage("Errors were encountered while reading HA messages from file!"); } } if (pDefaultPolicyConfig->ha_config->runtime_output_file) { runtime_output_fd = open(pDefaultPolicyConfig->ha_config->runtime_output_file, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (runtime_output_fd < 0) { FatalError("Could not open %s for writing HA messages to: %s (%d)\n", pDefaultPolicyConfig->ha_config->runtime_output_file, strerror(errno), errno); } } #ifdef SIDE_CHANNEL if (pDefaultPolicyConfig->ha_config->use_side_channel) { if ((rval = SideChannelRegisterRXHandler(SC_MSG_TYPE_FLOW_STATE_TRACKING, Stream5HASCMsgHandler, NULL)) != 0) { /* TODO: Fatal error here or something. */ } } #endif } void Stream5CleanHA(void) { int i; for (i = 0; i < n_stream_ha_funcs; i++) { if (stream_ha_funcs[i]) { free(stream_ha_funcs[i]); stream_ha_funcs[i] = NULL; } } if (runtime_output_fd >= 0) { close(runtime_output_fd); runtime_output_fd = -1; } } snort-2.9.6.0/src/preprocessors/Stream5/stream5_common.h0000644000000000000000000003517412260565733020066 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifndef STREAM5_COMMON_H_ #define STREAM5_COMMON_H_ #include #ifndef WIN32 #include #endif #include "sfutil/bitop_funcs.h" #include "sfutil/sfActionQueue.h" #include "parser/IpAddrSet.h" #include "stream_api.h" #include "mempool.h" #include "sf_types.h" #ifdef TARGET_BASED #include "target-based/sftarget_hostentry.h" #endif #include "sfPolicy.h" #include "sfPolicyUserData.h" //#define DEBUG_STREAM5 DEBUG /* defaults and limits */ #define S5_DEFAULT_SSN_TIMEOUT 30 /* seconds to timeout a session */ #define S5_MAX_SSN_TIMEOUT 3600*24 /* max timeout (approx 1 day) */ #define S5_MIN_SSN_TIMEOUT 1 /* min timeout (1 second) */ #define S5_MIN_ALT_HS_TIMEOUT 0 /* min timeout (0 seconds) */ #define S5_TRACK_YES 1 #define S5_TRACK_NO 0 #define S5_MAX_MAX_WINDOW 0x3FFFc000 /* max window allowed by TCP */ /* 65535 << 14 (max wscale) */ #define S5_MIN_MAX_WINDOW 0 #define MAX_PORTS_TO_PRINT 20 #define S5_DEFAULT_MAX_QUEUED_BYTES 1048576 /* 1 MB */ #define S5_MIN_MAX_QUEUED_BYTES 1024 /* Don't let this go below 1024 */ #define S5_MAX_MAX_QUEUED_BYTES 0x40000000 /* 1 GB, most we could reach within * largest window scale */ #define AVG_PKT_SIZE 400 #define S5_DEFAULT_MAX_QUEUED_SEGS (S5_DEFAULT_MAX_QUEUED_BYTES/AVG_PKT_SIZE) #define S5_MIN_MAX_QUEUED_SEGS 2 /* Don't let this go below 2 */ #define S5_MAX_MAX_QUEUED_SEGS 0x40000000 /* 1 GB worth of one-byte segments */ #define S5_DEFAULT_MAX_SMALL_SEG_SIZE 0 /* disabled */ #define S5_MAX_MAX_SMALL_SEG_SIZE 2048 /* 2048 bytes in single packet, uh, not small */ #define S5_MIN_MAX_SMALL_SEG_SIZE 0 /* 0 means disabled */ #define S5_DEFAULT_CONSEC_SMALL_SEGS 0 /* disabled */ #define S5_MAX_CONSEC_SMALL_SEGS 2048 /* 2048 single byte packets without acks is alot */ #define S5_MIN_CONSEC_SMALL_SEGS 0 /* 0 means disabled */ /* target-based policy types */ #define STREAM_POLICY_FIRST 1 #define STREAM_POLICY_LINUX 2 #define STREAM_POLICY_BSD 3 #define STREAM_POLICY_OLD_LINUX 4 #define STREAM_POLICY_LAST 5 #define STREAM_POLICY_WINDOWS 6 #define STREAM_POLICY_SOLARIS 7 #define STREAM_POLICY_HPUX11 8 #define STREAM_POLICY_IRIX 9 #define STREAM_POLICY_MACOS 10 #define STREAM_POLICY_HPUX10 11 #define STREAM_POLICY_VISTA 12 #define STREAM_POLICY_WINDOWS2K3 13 #define STREAM_POLICY_IPS 14 #define STREAM_POLICY_DEFAULT STREAM_POLICY_BSD #define STREAM5_CONFIG_STATEFUL_INSPECTION 0x00000001 #define STREAM5_CONFIG_ENABLE_ALERTS 0x00000002 #define STREAM5_CONFIG_LOG_STREAMS 0x00000004 #define STREAM5_CONFIG_REASS_CLIENT 0x00000008 #define STREAM5_CONFIG_REASS_SERVER 0x00000010 #define STREAM5_CONFIG_ASYNC 0x00000020 #define STREAM5_CONFIG_SHOW_PACKETS 0x00000040 #define STREAM5_CONFIG_FLUSH_ON_ALERT 0x00000080 #define STREAM5_CONFIG_REQUIRE_3WHS 0x00000100 #define STREAM5_CONFIG_MIDSTREAM_DROP_NOALERT 0x00000200 #define STREAM5_CONFIG_IGNORE_ANY 0x00000400 #define STREAM5_CONFIG_PERFORMANCE 0x00000800 #define STREAM5_CONFIG_STATIC_FLUSHPOINTS 0x00001000 #define STREAM5_CONFIG_IPS 0x00002000 #define STREAM5_CONFIG_CHECK_SESSION_HIJACKING 0x00004000 #define STREAM5_CONFIG_NO_ASYNC_REASSEMBLY 0x00008000 /* traffic direction identification */ #define FROM_SERVER 0 #define FROM_RESPONDER 0 #define FROM_CLIENT 1 #define FROM_SENDER 1 #define STREAM5_STATE_NONE 0x0000 #define STREAM5_STATE_SYN 0x0001 #define STREAM5_STATE_SYN_ACK 0x0002 #define STREAM5_STATE_ACK 0x0004 #define STREAM5_STATE_ESTABLISHED 0x0008 #define STREAM5_STATE_DROP_CLIENT 0x0010 #define STREAM5_STATE_DROP_SERVER 0x0020 #define STREAM5_STATE_MIDSTREAM 0x0040 #define STREAM5_STATE_TIMEDOUT 0x0080 #define STREAM5_STATE_UNREACH 0x0100 #define STREAM5_STATE_CLOSED 0x0800 #define TCP_HZ 100 /* Control Socket types */ #define CS_TYPE_DEBUG_S5_HA ((PP_STREAM5 << 7) + 0) // 0x680 / 1664 /* D A T A S T R U C T U R E S **********************************/ typedef StreamSessionKey SessionKey; typedef struct _Stream5AppData { uint32_t protocol; void *dataPointer; struct _Stream5AppData *next; struct _Stream5AppData *prev; StreamAppDataFree freeFunc; } Stream5AppData; typedef struct _Stream5HAState { uint32_t session_flags; #ifdef TARGET_BASED int16_t ipprotocol; int16_t application_protocol; #endif char direction; char ignore_direction; /* flag to ignore traffic on this session */ } Stream5HAState; // this struct is organized by member size for compactness typedef struct _Stream5LWSession { SessionKey *key; MemBucket *proto_specific_data; Stream5AppData *appDataList; MemBucket *flowdata; /* add flowbits */ void *policy; long last_data_seen; uint64_t expire_time; tSfPolicyUserContextId config; tSfPolicyId policy_id; Stream5HAState ha_state; uint16_t session_state; uint8_t handler[SE_MAX]; snort_ip client_ip; // FIXTHIS family and bits should be changed to uint16_t snort_ip server_ip; // or uint8_t to reduce sizeof from 24 to 20 uint16_t client_port; uint16_t server_port; uint8_t protocol; #ifdef ACTIVE_RESPONSE uint8_t response_count; #endif uint8_t inner_client_ttl, inner_server_ttl; uint8_t outer_client_ttl, outer_server_ttl; #ifdef ENABLE_HA struct timeval ha_next_update; uint8_t ha_pending_mask; uint8_t ha_flags; #endif } Stream5LWSession; typedef struct _Stream5GlobalConfig { char disabled; char track_tcp_sessions; char track_udp_sessions; char track_icmp_sessions; char track_ip_sessions; #ifdef ENABLE_HA char enable_ha; #endif uint32_t max_tcp_sessions; uint32_t max_udp_sessions; uint32_t max_icmp_sessions; uint32_t max_ip_sessions; uint16_t tcp_cache_pruning_timeout; uint16_t tcp_cache_nominal_timeout; uint16_t udp_cache_pruning_timeout; uint16_t udp_cache_nominal_timeout; uint32_t memcap; uint32_t prune_log_max; uint32_t flags; #ifdef ACTIVE_RESPONSE uint32_t min_response_seconds; uint8_t max_active_responses; #endif } Stream5GlobalConfig; typedef struct _FlushMgr { uint32_t flush_pt; uint16_t last_count; uint16_t last_size; uint8_t flush_policy; uint8_t flush_type; uint8_t auto_disable; //uint8_t spare; } FlushMgr; typedef struct _FlushConfig { FlushMgr client; FlushMgr server; //SF_LIST *dynamic_policy; #ifdef TARGET_BASED uint8_t configured; #endif } FlushConfig; #ifndef DYNAMIC_RANDOM_FLUSH_POINTS typedef struct _FlushPointList { uint8_t current; uint8_t initialized; uint32_t flush_range; uint32_t flush_base; /* Set as value - range/2 */ /* flush_pt is split evently on either side of flush_value, within * the flush_range. flush_pt can be from: * (flush_value - flush_range/2) to (flush_value + flush_range/2) * * For example: * flush_value = 192 * flush_range = 128 * flush_pt will vary from 128 to 256 */ uint32_t *flush_points; } FlushPointList; #endif typedef struct _Stream5TcpPolicy { uint16_t policy; uint16_t reassembly_policy; uint16_t flags; uint16_t flush_factor; uint32_t session_timeout; uint32_t max_window; uint32_t overlap_limit; uint32_t hs_timeout; IpAddrSet *bound_addrs; FlushConfig flush_config[MAX_PORTS]; #ifdef TARGET_BASED FlushConfig flush_config_protocol[MAX_PROTOCOL_ORDINAL]; #endif #ifndef DYNAMIC_RANDOM_FLUSH_POINTS FlushPointList flush_point_list; #endif uint32_t max_queued_bytes; uint32_t max_queued_segs; uint32_t max_consec_small_segs; uint32_t max_consec_small_seg_size; char small_seg_ignore[MAX_PORTS/8]; } Stream5TcpPolicy; typedef struct _Stream5TcpConfig { Stream5TcpPolicy *default_policy; Stream5TcpPolicy **policy_list; void* paf_config; uint8_t num_policies; uint16_t session_on_syn; uint16_t port_filter[MAX_PORTS + 1]; } Stream5TcpConfig; typedef struct _Stream5UdpPolicy { uint32_t session_timeout; uint16_t flags; IpAddrSet *bound_addrs; } Stream5UdpPolicy; typedef struct _Stream5UdpConfig { Stream5UdpPolicy *default_policy; Stream5UdpPolicy **policy_list; uint8_t num_policies; uint8_t dummy; /* For alignment */ uint16_t port_filter[MAX_PORTS + 1]; } Stream5UdpConfig; typedef struct _Stream5IcmpPolicy { uint32_t session_timeout; //uint16_t flags; } Stream5IcmpPolicy; typedef struct _Stream5IcmpConfig { Stream5IcmpPolicy default_policy; uint8_t num_policies; } Stream5IcmpConfig; typedef struct _Stream5IpPolicy { uint32_t session_timeout; } Stream5IpPolicy; typedef struct _Stream5IpConfig { Stream5IpPolicy default_policy; } Stream5IpConfig; #ifdef ENABLE_HA typedef struct _Stream5HAConfig { struct timeval min_session_lifetime; struct timeval min_sync_interval; char *startup_input_file; char *runtime_output_file; char *shutdown_output_file; # ifdef SIDE_CHANNEL uint8_t use_side_channel; # endif } Stream5HAConfig; #endif typedef struct _Stream5Config { Stream5GlobalConfig *global_config; Stream5TcpConfig *tcp_config; Stream5UdpConfig *udp_config; Stream5IcmpConfig *icmp_config; Stream5IpConfig *ip_config; #ifdef ENABLE_HA Stream5HAConfig *ha_config; #endif #ifdef TARGET_BASED uint8_t service_filter[MAX_PROTOCOL_ORDINAL]; #endif uint32_t ref_count; } Stream5Config; /**Common statistics for tcp and udp packets, maintained by port filtering. */ typedef struct { /**packets filtered without further processing by any preprocessor or * detection engine. */ uint32_t filtered; /**packets inspected and but processed futher by stream5 preprocessor. */ uint32_t inspected; /**packets session tracked by stream5 preprocessor. */ uint32_t session_tracked; } tPortFilterStats; typedef struct _Stream5Stats { uint32_t total_tcp_sessions; uint32_t total_udp_sessions; uint32_t total_icmp_sessions; uint32_t total_ip_sessions; uint32_t tcp_prunes; uint32_t udp_prunes; uint32_t icmp_prunes; uint32_t ip_prunes; uint32_t tcp_timeouts; uint32_t tcp_streamtrackers_created; uint32_t tcp_streamtrackers_released; uint32_t tcp_streamsegs_created; uint32_t tcp_streamsegs_released; uint32_t tcp_rebuilt_packets; uint32_t tcp_rebuilt_seqs_used; uint32_t tcp_overlaps; uint32_t tcp_discards; uint32_t tcp_gaps; uint32_t udp_timeouts; uint32_t udp_sessions_created; uint32_t udp_sessions_released; uint32_t udp_discards; uint32_t icmp_timeouts; uint32_t icmp_sessions_created; uint32_t icmp_sessions_released; uint32_t ip_timeouts; uint32_t events; uint32_t internalEvents; tPortFilterStats tcp_port_filter; tPortFilterStats udp_port_filter; } Stream5Stats; /**Whether incoming packets should be ignored or processed. */ typedef enum { /**Ignore the packet. */ PORT_MONITOR_PACKET_PROCESS = 0, /**Process the packet. */ PORT_MONITOR_PACKET_DISCARD } PortMonitorPacketStates; void Stream5DisableInspection(Stream5LWSession *lwssn, Packet *p); int Stream5ExpireSession(Stream5LWSession *lwssn); int Stream5Expire(Packet *p, Stream5LWSession *ssn); void Stream5SetExpire(Packet *p, Stream5LWSession *ssn, uint32_t timeout); #ifdef ACTIVE_RESPONSE int Stream5GetExpire(Packet*, Stream5LWSession*); void Stream5ActiveResponse(Packet*, Stream5LWSession*); void SetTTL (Stream5LWSession*, Packet*, int client); #endif void MarkupPacketFlags(Packet *p, Stream5LWSession *ssn); #ifdef TARGET_BASED void Stream5SetApplicationProtocolIdFromHostEntry(Stream5LWSession *lwssn, HostAttributeEntry *host_entry, int direction); #endif void Stream5FreeConfig(Stream5Config *); void Stream5FreeConfigs(tSfPolicyUserContextId); void Stream5CallHandler(Packet*, unsigned id); int isPacketFilterDiscard( Packet *p, int ignore_any_rules ); static inline void Stream5ResetFlowBits(Stream5LWSession *lwssn) { StreamFlowData *flowdata; if ((lwssn == NULL) || (lwssn->flowdata == NULL)) return; flowdata = (StreamFlowData *)lwssn->flowdata->data; boResetBITOP(&(flowdata->boFlowbits)); } #ifdef ENABLE_HA static inline void Stream5SetHABit(Stream5LWSession *lwssn, unsigned int ha_func_idx) { lwssn->ha_pending_mask |= (1 << ha_func_idx); } #endif void checkLWSessionTimeout( uint32_t flowCount, time_t cur_time ); // shared stream state extern Stream5Stats s5stats; extern uint32_t firstPacketTime; extern MemPool s5FlowMempool; extern uint32_t mem_in_use; extern Stream5GlobalConfig *s5_global_eval_config; extern Stream5TcpConfig *s5_tcp_eval_config; extern Stream5UdpConfig *s5_udp_eval_config; extern Stream5IcmpConfig *s5_icmp_eval_config; extern Stream5IpConfig *s5_ip_eval_config; extern tSfPolicyUserContextId s5_config; extern tSfActionQueueId decoderActionQ; #endif /* STREAM5_COMMON_H_ */ snort-2.9.6.0/src/preprocessors/Stream5/stream5_common.c0000644000000000000000000004200512260565733020050 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "decode.h" #include "log.h" #include "util.h" #include "generators.h" #include "event_queue.h" #include "snort.h" #include "snort_stream5_session.h" #include "stream5_common.h" #include "portscan.h" #include "sftarget_protocol_reference.h" #include "sp_dynamic.h" #include "snort_stream5_tcp.h" #include "snort_stream5_udp.h" #include "snort_stream5_icmp.h" #include "snort_stream5_ip.h" #include "parser.h" #include "active.h" #ifdef ENABLE_HA #include "stream5_ha.h" #endif static void printIgnoredRules( IgnoredRuleList *pIgnoredRuleList, int any_any_flow ); static void addRuleToIgnoreList( IgnoredRuleList **ppIgnoredRuleList, OptTreeNode *otn); /* M A C R O S **************************************************/ static inline uint64_t CalcJiffies(Packet *p) { uint64_t ret = 0; uint64_t sec = (uint64_t)p->pkth->ts.tv_sec * TCP_HZ; uint64_t usec = (p->pkth->ts.tv_usec / (1000000UL/TCP_HZ)); ret = sec + usec; return ret; //return (p->pkth->ts.tv_sec * TCP_HZ) + // (p->pkth->ts.tv_usec / (1000000UL/TCP_HZ)); } int Stream5ExpireSession(Stream5LWSession *lwssn) { #ifdef ENABLE_HA /* Sessions in standby cannot be locally expired. */ if (lwssn->ha_flags & HA_FLAG_STANDBY) return 0; #endif sfBase.iStreamTimeouts++; lwssn->ha_state.session_flags |= SSNFLAG_TIMEDOUT; lwssn->session_state |= STREAM5_STATE_TIMEDOUT; switch (lwssn->protocol) { case IPPROTO_TCP: s5stats.tcp_timeouts++; break; case IPPROTO_UDP: s5stats.udp_timeouts++; break; case IPPROTO_ICMP: s5stats.icmp_timeouts++; break; } return 1; } int Stream5Expire(Packet *p, Stream5LWSession *lwssn) { uint64_t pkttime = CalcJiffies(p); if (lwssn->expire_time == 0) { /* Not yet set, not expired */ return 0; } if((int)(pkttime - lwssn->expire_time) > 0) { /* Expiration time has passed. */ return Stream5ExpireSession(lwssn); } return 0; } void Stream5SetExpire(Packet *p, Stream5LWSession *lwssn, uint32_t timeout) { lwssn->expire_time = CalcJiffies(p) + (timeout * TCP_HZ); return; } #ifdef ACTIVE_RESPONSE int Stream5GetExpire(Packet *p, Stream5LWSession *lwssn) { return ( CalcJiffies(p) > lwssn->expire_time ); } // *DROP* flags are set to mark the direction(s) for which traffic was // seen since last reset and then cleared after sending new attempt so // that we only send in the still active direction(s). void Stream5ActiveResponse(Packet* p, Stream5LWSession *lwssn) { Stream5Config *config = sfPolicyUserDataGet(s5_config, getRuntimePolicy()); uint8_t max = config->global_config->max_active_responses; if ( p->packet_flags & PKT_FROM_CLIENT ) lwssn->session_state |= STREAM5_STATE_DROP_CLIENT; else lwssn->session_state |= STREAM5_STATE_DROP_SERVER; if ( (lwssn->response_count < max) && Stream5GetExpire(p, lwssn) ) { uint32_t delay = config->global_config->min_response_seconds; EncodeFlags flags = ( (lwssn->session_state & STREAM5_STATE_DROP_CLIENT) && (lwssn->session_state & STREAM5_STATE_DROP_SERVER) ) ? ENC_FLAG_FWD : 0; // reverse dir is always true Active_KillSession(p, &flags); ++lwssn->response_count; Stream5SetExpire(p, lwssn, delay); lwssn->session_state &= ~(STREAM5_STATE_DROP_CLIENT|STREAM5_STATE_DROP_SERVER); } } void SetTTL (Stream5LWSession* ssn, Packet* p, int client) { uint8_t inner_ttl = 0, outer_ttl = 0; if ( p->outer_iph_api ) outer_ttl = p->outer_iph_api->iph_ret_ttl(p); if ( p->iph_api ) inner_ttl = p->iph_api->iph_ret_ttl(p); if ( client ) { ssn->outer_client_ttl = outer_ttl; ssn->inner_client_ttl = inner_ttl; } else { ssn->outer_server_ttl = outer_ttl; ssn->inner_server_ttl = inner_ttl; } } #endif void MarkupPacketFlags(Packet *p, Stream5LWSession *lwssn) { if(!lwssn) return; if((lwssn->ha_state.session_flags & SSNFLAG_ESTABLISHED) != SSNFLAG_ESTABLISHED) { if((lwssn->ha_state.session_flags & (SSNFLAG_SEEN_SERVER|SSNFLAG_SEEN_CLIENT)) != (SSNFLAG_SEEN_SERVER|SSNFLAG_SEEN_CLIENT)) { p->packet_flags |= PKT_STREAM_UNEST_UNI; } } else { p->packet_flags |= PKT_STREAM_EST; if(p->packet_flags & PKT_STREAM_UNEST_UNI) { p->packet_flags ^= PKT_STREAM_UNEST_UNI; } } if ( lwssn->ha_state.session_flags & SSNFLAG_STREAM_ORDER_BAD ) p->packet_flags |= PKT_STREAM_ORDER_BAD; } #if 0 /** Get rule list for a specific protocol * * @param rule * @param ptocool protocol type * @returns RuleTreeNode* rule list for specific protocol */ static inline RuleTreeNode * protocolRuleList(RuleListNode *rule, int protocol) { switch (protocol) { case IPPROTO_TCP: return rule->RuleList->TcpList; case IPPROTO_UDP: return rule->RuleList->UdpList; case IPPROTO_ICMP: break; default: break; } return NULL; } #endif static inline char * getProtocolName (int protocol) { static char *protocolName[] = {"TCP", "UDP", "ICMP"}; switch (protocol) { case IPPROTO_TCP: return protocolName[0]; case IPPROTO_UDP: return protocolName[1]; case IPPROTO_ICMP: return protocolName[2]; break; default: break; } return NULL; } /**check whether a flow bit is set for an option node. * * @param otn Option Tree Node * @returns 0 - no flow bit is set, 1 otherwise */ int Stream5OtnHasFlowOrFlowbit(OptTreeNode *otn) { if (otn->ds_list[PLUGIN_CLIENTSERVER] || DynamicHasFlow(otn) || DynamicHasFlowbit(otn) || otn->ds_list[PLUGIN_FLOWBIT]) { return 1; } return 0; } /**initialize given port list from the given ruleset, for a given policy * @param portList pointer to array of MAX_PORTS+1 uint8_t. This array content * is changed by walking through the rulesets. * @param protocol - protocol type */ void setPortFilterList( struct _SnortConfig *sc, uint16_t *portList, int protocol, int ignoreAnyAnyRules, tSfPolicyId policyId ) { char *port_array = NULL; int num_ports = 0; int i; RuleTreeNode *rtn; OptTreeNode *otn; int inspectSrc, inspectDst; char any_any_flow = 0; IgnoredRuleList *pIgnoredRuleList = NULL; ///list of ignored rules char *protocolName; SFGHASH_NODE *hashNode; int flowBitIsSet = 0; if (sc == NULL) { FatalError("%s(%d) Snort conf for parsing is NULL.\n", __FILE__, __LINE__); } if ((protocol == IPPROTO_TCP) && (ignoreAnyAnyRules == 0)) { int j; for (j=0; jotn_map); hashNode; hashNode = sfghash_findnext(sc->otn_map)) { otn = (OptTreeNode *)hashNode->data; flowBitIsSet = Stream5OtnHasFlowOrFlowbit(otn); rtn = getRtnFromOtn(otn, policyId); if (!rtn) { continue; } if (rtn->proto == protocol) { //do operation inspectSrc = inspectDst = 0; if (PortObjectHasAny(rtn->src_portobject)) { inspectSrc = -1; } else { port_array = PortObjectCharPortArray(port_array, rtn->src_portobject, &num_ports); if (port_array && num_ports != 0) { inspectSrc = 1; for (i=0;idst_portobject)) { inspectDst = -1; } else { port_array = PortObjectCharPortArray(port_array, rtn->dst_portobject, &num_ports); if (port_array && num_ports != 0) { inspectDst = 1; for (i=0;i any rule */ if (any_any_flow == 0) { any_any_flow = Stream5AnyAnyFlow(portList, otn, rtn, any_any_flow, &pIgnoredRuleList, ignoreAnyAnyRules); } } } } /* If portscan is tracking TCP/UDP, need to create * sessions for all ports */ if (((protocol == IPPROTO_UDP) && (ps_get_protocols(sc, policyId) & PS_PROTO_UDP)) || ((protocol == IPPROTO_TCP) && (ps_get_protocols(sc, policyId) & PS_PROTO_TCP))) { int j; for (j=0; j any with flow/flowbits */ portList[i] |= PORT_MONITOR_SESSION; } return 1; } if (ignoreAnyAnyRules) { /* if not, then ignore the content/pcre/etc */ if (otn->ds_list[PLUGIN_PATTERN_MATCH] || otn->ds_list[PLUGIN_PATTERN_MATCH_OR] || otn->ds_list[PLUGIN_PATTERN_MATCH_URI] || DynamicHasContent(otn) || DynamicHasByteTest(otn) || DynamicHasPCRE(otn) || otn->ds_list[PLUGIN_BYTE_TEST] || otn->ds_list[PLUGIN_PCRE]) { /* Ignoring this rule.... */ addRuleToIgnoreList(ppIgnoredRuleList, otn); } } return 0; } /**add rule to the ignore rule list. */ static void addRuleToIgnoreList(IgnoredRuleList **ppIgnoredRuleList, OptTreeNode *otn) { IgnoredRuleList *ignored_rule; ignored_rule = SnortAlloc(sizeof(*ignored_rule)); ignored_rule->otn = otn; ignored_rule->next = *ppIgnoredRuleList; *ppIgnoredRuleList = ignored_rule; } /**print the ignored rule list. */ static void printIgnoredRules( IgnoredRuleList *pIgnoredRuleList, int any_any_flow ) { char six_sids = 0; int sids_ignored = 0; char buf[STD_BUF]; IgnoredRuleList *ignored_rule; IgnoredRuleList *next_ignored_rule; buf[0] = '\0'; for (ignored_rule = pIgnoredRuleList; ignored_rule != NULL; ) { if (any_any_flow == 0) { if (six_sids == 1) { SnortSnprintfAppend(buf, STD_BUF-1, "\n"); LogMessage("%s", buf); six_sids = 0; } if (sids_ignored == 0) { SnortSnprintf(buf, STD_BUF-1, " %d:%d", ignored_rule->otn->sigInfo.generator, ignored_rule->otn->sigInfo.id); } else { SnortSnprintfAppend(buf, STD_BUF-1, ", %d:%d", ignored_rule->otn->sigInfo.generator, ignored_rule->otn->sigInfo.id); } sids_ignored++; if (sids_ignored %6 == 0) { /* Have it print next time through */ six_sids = 1; sids_ignored = 0; } } next_ignored_rule = ignored_rule->next; free(ignored_rule); ignored_rule = next_ignored_rule; } if (sids_ignored || six_sids) { SnortSnprintfAppend(buf, STD_BUF-1, "\n"); LogMessage("%s", buf); } } static int Stream5FreeConfigsPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { Stream5Config *pPolicyConfig = (Stream5Config *)pData; //do any housekeeping before freeing Stream5Config sfPolicyUserDataClear (config, policyId); Stream5FreeConfig(pPolicyConfig); return 0; } void Stream5FreeConfigs(tSfPolicyUserContextId config) { if (config == NULL) return; sfPolicyUserDataFreeIterate (config, Stream5FreeConfigsPolicy); sfPolicyConfigDelete(config); } void Stream5FreeConfig(Stream5Config *config) { if (config == NULL) return; if (config->global_config != NULL) { free(config->global_config); config->global_config = NULL; } if (config->tcp_config != NULL) { Stream5TcpConfigFree(config->tcp_config); config->tcp_config = NULL; } if (config->udp_config != NULL) { Stream5UdpConfigFree(config->udp_config); config->udp_config = NULL; } if (config->icmp_config != NULL) { Stream5IcmpConfigFree(config->icmp_config); config->icmp_config = NULL; } if (config->ip_config != NULL) { Stream5IpConfigFree(config->ip_config); config->ip_config = NULL; } #ifdef ENABLE_HA if (config->ha_config != NULL) { Stream5HAConfigFree(config->ha_config); config->ha_config = NULL; } #endif free(config); } snort-2.9.6.0/src/preprocessors/Stream5/stream5_paf.h0000644000000000000000000000642312260565733017337 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ //-------------------------------------------------------------------- // s5 protocol aware flushing stuff // // @file stream5_paf.h // @author Russ Combs //-------------------------------------------------------------------- #ifndef __STREAM5_PAF_H__ #define __STREAM5_PAF_H__ #include "sf_types.h" #include "sfPolicy.h" #include "stream_api.h" void* s5_paf_new(void); // create new paf config (per policy) void s5_paf_delete(void*); // free config bool s5_paf_register_port( struct _SnortConfig *, // snort configuration tSfPolicyId, // applicable policy uint16_t port, // server port bool toServer, // direction of interest relative to server port PAF_Callback, // stateful byte scanning function bool autoEnable // enable PAF reassembly regardless of s5 ports config ); bool s5_paf_register_service( struct _SnortConfig *, // snort configuration tSfPolicyId, // same as above uint16_t service, // service ordinal bool toServer, PAF_Callback, bool autoEnable ); // flush indicates s5 port config uint8_t s5_paf_port_registration (void* pv, uint16_t port, bool c2s, bool flush); uint8_t s5_paf_service_registration (void* pv, uint16_t service, bool c2s, bool flush); typedef struct { void* user; // arbitrary user data uint32_t seq; // stream cursor uint32_t pos; // last flush position uint32_t fpt; // current flush point uint32_t tot; // total bytes flushed PAF_Status paf; // current scan state uint8_t cb_mask; // callback mask } PAF_State; // per session direction // called at session start void s5_paf_setup(PAF_State*, uint8_t registration); void s5_paf_clear(PAF_State*); // called at session end static inline uint32_t s5_paf_position (PAF_State* ps) { return ps->seq; } static inline uint32_t s5_paf_initialized (PAF_State* ps) { return ( ps->paf != PAF_START ); } static inline uint32_t s5_paf_active (PAF_State* ps) { return ( ps->paf != PAF_ABORT ); } // called on each in order segment uint32_t s5_paf_check( void* paf_config, PAF_State*, void* ssn, const uint8_t* data, uint32_t len, uint32_t total, uint32_t seq, uint16_t port, uint32_t* flags, uint32_t fuzz); #endif snort-2.9.6.0/src/preprocessors/Stream5/stream5_paf.c0000644000000000000000000003067312260565733017336 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ //-------------------------------------------------------------------- // s5 stuff // // @file stream5_paf.c // @author Russ Combs //-------------------------------------------------------------------- #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "sf_types.h" #include "snort_bounds.h" #include "snort_debug.h" #include "snort.h" #include "sfPolicyUserData.h" #include "stream5_common.h" #include "stream5_paf.h" #include "sftarget_protocol_reference.h" //-------------------------------------------------------------------- // private state //-------------------------------------------------------------------- typedef enum { FT_NOP, // no flush FT_SFP, // abort paf FT_PAF, // flush to paf pt when len >= paf FT_MAX // flush len when len >= mfp } FlushType; typedef struct { uint8_t cb_mask; uint8_t auto_on; } PAF_Map; typedef struct { uint32_t mfp; uint32_t prep_calls; uint32_t prep_bytes; PAF_Map port_map[MAXPORTS][2]; PAF_Map service_map[MAX_PROTOCOL_ORDINAL][2]; } PAF_Config; // for cb registration #define MAX_CB 8 // depends on sizeof(PAF_Map.cb_mask) static PAF_Callback s5_cb[MAX_CB]; static uint8_t s5_cb_idx = 0; // s5_len and s5_idx are used only during the // lifetime of s5_paf_check() static uint32_t s5_len; // total bytes queued static uint32_t s5_idx; // offset from start of queued bytes //-------------------------------------------------------------------- static uint32_t s5_paf_flush ( PAF_Config* pc, PAF_State* ps, FlushType ft, uint32_t* flags) { uint32_t at = 0; *flags &= ~(PKT_PDU_HEAD | PKT_PDU_TAIL); DEBUG_WRAP(DebugMessage(DEBUG_STREAM_PAF, "%s: type=%d, fpt=%u, len=%u, tot=%u\n", __FUNCTION__, ft, ps->fpt, s5_len, ps->tot);) switch ( ft ) { case FT_NOP: return 0; case FT_SFP: *flags = 0; return 0; case FT_PAF: at = ps->fpt; *flags |= PKT_PDU_TAIL; break; // use of s5_len is suboptimal here because the actual amount // flushed is determined later and can differ in certain cases // such as exceeding s5_pkt->max_dsize. the actual amount // flushed would ideally be applied to ps->fpt later. for // now we try to circumvent such cases so we track correctly. case FT_MAX: at = s5_len; if ( ps->fpt > s5_len ) ps->fpt -= s5_len; else ps->fpt = 0; break; } if ( !at || !s5_len ) return 0; // safety - prevent seq + at < seq if ( at > 0x7FFFFFFF ) at = 0x7FFFFFFF; if ( !ps->tot ) *flags |= PKT_PDU_HEAD; if ( *flags & PKT_PDU_TAIL ) ps->tot = 0; else ps->tot += at; return at; } //-------------------------------------------------------------------- static bool s5_paf_callback ( PAF_State* ps, void* ssn, const uint8_t* data, uint32_t len, uint32_t flags) { PAF_Status paf; uint8_t mask = ps->cb_mask; bool update = false; int i = 0; while ( mask ) { uint8_t bit = (1<user, data, len, flags, &ps->fpt); if ( paf == PAF_ABORT ) { // this one bailed out ps->cb_mask ^= bit; } else if ( paf != PAF_SEARCH ) { // this one selected ps->cb_mask = bit; update = true; break; } mask ^= bit; } if ( ++i == MAX_CB ) break; } if ( !ps->cb_mask ) { ps->paf = PAF_ABORT; update = true; } else if ( paf != PAF_ABORT ) { ps->paf = paf; } if ( update ) { ps->fpt += s5_idx; if ( ps->fpt <= s5_len ) { s5_idx = ps->fpt; return true; } } s5_idx = s5_len; return false; } //-------------------------------------------------------------------- static inline bool s5_paf_eval ( PAF_Config* pc, PAF_State* ps, void* ssn, uint16_t port, uint32_t flags, uint32_t fuzz, const uint8_t* data, uint32_t len, FlushType* ft) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_PAF, "%s: paf=%d, idx=%u, len=%u, fpt=%u\n", __FUNCTION__, ps->paf, s5_idx, s5_len, ps->fpt);) switch ( ps->paf ) { case PAF_SEARCH: if ( s5_len > s5_idx ) { return s5_paf_callback(ps, ssn, data, len, flags); } return false; case PAF_FLUSH: if ( s5_len >= ps->fpt ) { *ft = FT_PAF; ps->paf = PAF_SEARCH; return true; } if ( s5_len >= pc->mfp + fuzz ) { *ft = FT_MAX; return false; } return false; case PAF_SKIP: if ( s5_len > ps->fpt ) { if ( ps->fpt > s5_idx ) { uint32_t delta = ps->fpt - s5_idx; if ( delta > len ) return false; data += delta; len -= delta; } s5_idx = ps->fpt; return s5_paf_callback(ps, ssn, data, len, flags); } return false; default: // PAF_ABORT || PAF_START break; } *ft = FT_SFP; return false; } //-------------------------------------------------------------------- // helper functions static PAF_Config* get_config (struct _SnortConfig *sc, tSfPolicyId pid) { tSfPolicyUserContextId context; Stream5Config* config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc); context = s5_swap_config ? s5_swap_config : s5_config; #else context = s5_config; #endif #ifdef POLICY_BY_ID_ONLY pid = sfGetDefaultPolicy(NULL); #endif config = sfPolicyUserDataGet(context, pid); if ( !config || !config->tcp_config ) return NULL; return config->tcp_config->paf_config; } static int install_callback (PAF_Callback cb) { int i; for ( i = 0; i < s5_cb_idx; i++ ) { if ( s5_cb[i] == cb ) break; } if ( i == MAX_CB ) return -1; if ( i == s5_cb_idx ) { s5_cb[i] = cb; s5_cb_idx++; } return i; } //-------------------------------------------------------------------- // public stuff //-------------------------------------------------------------------- void s5_paf_setup (PAF_State* ps, uint8_t mask) { // this is already cleared when instantiated //memset(ps, 0, sizeof(*ps)); ps->paf = PAF_START; ps->cb_mask = mask; } void s5_paf_clear (PAF_State* ps) { // either require pp to manage in other session state // or provide user free func? if ( ps->user ) { free(ps->user); ps->user = NULL; } ps->paf = PAF_ABORT; } //-------------------------------------------------------------------- uint32_t s5_paf_check ( void* pv, PAF_State* ps, void* ssn, const uint8_t* data, uint32_t len, uint32_t total, uint32_t seq, uint16_t port, uint32_t* flags, uint32_t fuzz) { PAF_Config* pc = pv; DEBUG_WRAP(DebugMessage(DEBUG_STREAM_PAF, "%s: len=%u, amt=%u, seq=%u, cur=%u, pos=%u, fpt=%u, tot=%u, paf=%d\n", __FUNCTION__, len, total, seq, ps->seq, ps->pos, ps->fpt, ps->tot, ps->paf);) if ( !s5_paf_initialized(ps) ) { ps->seq = ps->pos = seq; ps->paf = PAF_SEARCH; } else if ( SEQ_GT(seq, ps->seq) ) { // if seq jumped we have a gap, so abort paf *flags = 0; return 0; } else if ( SEQ_LEQ(seq + len, ps->seq) ) { return 0; } else if ( SEQ_LT(seq, ps->seq) ) { uint32_t shift = ps->seq - seq; data += shift; len -= shift; } ps->seq += len; pc->prep_calls++; pc->prep_bytes += len; s5_len = total; s5_idx = total - len; do { FlushType ft = FT_NOP; uint32_t idx = s5_idx; uint32_t shift, fp; bool cont = s5_paf_eval(pc, ps, ssn, port, *flags, fuzz, data, len, &ft); if ( ft != FT_NOP ) { fp = s5_paf_flush(pc, ps, ft, flags); ps->pos += fp; ps->seq = ps->pos; return fp; } if ( !cont ) break; if ( s5_idx > idx ) { shift = s5_idx - idx; if ( shift > len ) shift = len; data += shift; len -= shift; } } while ( 1 ); if ( (ps->paf != PAF_FLUSH) && (s5_len > pc->mfp+fuzz) ) { uint32_t fp = s5_paf_flush(pc, ps, FT_MAX, flags); ps->pos += fp; ps->seq = ps->pos; return fp; } return 0; } //-------------------------------------------------------------------- // port registration foo bool s5_paf_register_port (struct _SnortConfig *sc, tSfPolicyId pid, uint16_t port, bool c2s, PAF_Callback cb, bool auto_on) { PAF_Config* pc = get_config(sc, pid); int i, dir = c2s ? 1 : 0; if ( !pc ) return false; i = install_callback(cb); if ( i < 0 ) return false; pc->port_map[port][dir].cb_mask |= (1<port_map[port][dir].auto_on ) pc->port_map[port][dir].auto_on = (uint8_t)auto_on; return true; } uint8_t s5_paf_port_registration (void* pv, uint16_t port, bool c2s, bool flush) { PAF_Config* pc = pv; PAF_Map* pm; if ( !pc ) return false; pm = pc->port_map[port] + (c2s?1:0); if ( !pm->cb_mask ) return 0; if ( pm->auto_on || flush ) return pm->cb_mask; return 0; } //-------------------------------------------------------------------- // service registration foo bool s5_paf_register_service (struct _SnortConfig *sc, tSfPolicyId pid, uint16_t service, bool c2s, PAF_Callback cb, bool auto_on) { PAF_Config* pc = get_config(sc, pid); int i, dir = c2s ? 1 : 0; if ( !pc ) return false; i = install_callback(cb); if ( i < 0 ) return false; pc->service_map[service][dir].cb_mask |= (1<service_map[service][dir].auto_on ) pc->service_map[service][dir].auto_on = (uint8_t)auto_on; return true; } uint8_t s5_paf_service_registration (void* pv, uint16_t service, bool c2s, bool flush) { PAF_Config* pc = pv; PAF_Map* pm; if ( !pc ) return false; pm = pc->service_map[service] + (c2s?1:0); if ( !pm->cb_mask ) return 0; if ( pm->auto_on || flush ) return pm->cb_mask; return 0; } //-------------------------------------------------------------------- void* s5_paf_new (void) { PAF_Config* pc = SnortAlloc(sizeof(*pc)); assert( pc ); pc->mfp = ScPafMax(); if ( !pc->mfp ) // this ensures max < IP_MAXPACKET pc->mfp = (65535 - 255); DEBUG_WRAP(DebugMessage(DEBUG_STREAM_PAF, "%s: mfp=%u\n", __FUNCTION__, pc->mfp);) return pc; } void s5_paf_delete (void* pv) { PAF_Config* pc = (PAF_Config*)pv; DEBUG_WRAP(DebugMessage(DEBUG_STREAM_PAF, "%s: prep=%u/%u\n", __FUNCTION__, pc->prep_calls, pc->prep_bytes);) free(pc); } snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_session.h0000644000000000000000000000774112260565733021505 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifndef SNORT_STREAM5_SESSION_H_ #define SNORT_STREAM5_SESSION_H_ #include "sfxhash.h" #include "stream5_common.h" #include "rules.h" #include "treenodes.h" typedef void(*Stream5SessionCleanup)(Stream5LWSession *ssn); #define SESSION_CACHE_FLAG_PURGING 0x01 #define SESSION_CACHE_FLAG_PRUNING 0x02 typedef struct _Stream5SessionCache { SFXHASH *hashTable; SFXHASH_NODE *nextTimeoutEvalNode; uint32_t timeoutAggressive; uint32_t timeoutNominal; uint32_t max_sessions; uint32_t cleanup_sessions; uint32_t prunes; uint32_t flags; Stream5SessionCleanup cleanup_fcn; } Stream5SessionCache; /**list of ignored rules. */ typedef struct _IgnoredRuleList { OptTreeNode *otn; struct _IgnoredRuleList *next; } IgnoredRuleList; #if 0 void PrintSessionKey(SessionKey *); #endif Stream5SessionCache *InitLWSessionCache(int max_sessions, uint32_t session_timeout_min, uint32_t session_timeout_max, uint32_t cleanup_sessions, uint32_t cleanup_percent, Stream5SessionCleanup clean_fcn); Stream5LWSession *GetLWSession(Stream5SessionCache *, Packet *, SessionKey *); int GetLWSessionKeyFromIpPort( snort_ip_p srcIP, uint16_t srcPort, snort_ip_p dstIP, uint16_t dstPort, char proto, uint16_t vlan, uint32_t mplsId, uint16_t addressSpaceId, SessionKey *key); Stream5LWSession *GetLWSessionFromKey(Stream5SessionCache *, const SessionKey *); Stream5LWSession *NewLWSession(Stream5SessionCache *, Packet *, const SessionKey *, void *); int DeleteLWSession(Stream5SessionCache *, Stream5LWSession *, char *reason); void PrintLWSessionCache(Stream5SessionCache *); int DeleteLWSessionCache(Stream5SessionCache *sessionCache); int PurgeLWSessionCache(Stream5SessionCache *); int PruneLWSessionCache(Stream5SessionCache *, uint32_t thetime, Stream5LWSession *save_me, int memcheck); int GetLWSessionCount(Stream5SessionCache *); void GetLWPacketDirection(Packet *p, Stream5LWSession *ssn); void FreeLWApplicationData(Stream5LWSession *ssn); void setPortFilterList( struct _SnortConfig *, uint16_t *portList, int isUdp, int ignoreAnyAnyRules, tSfPolicyId policyId ); int Stream5AnyAnyFlow( uint16_t *portList, OptTreeNode *otn, RuleTreeNode *rtn, int any_any_flow, IgnoredRuleList **ppIgnoredRuleList, int ignoreAnyAnyRules ); void s5PrintPortFilter( uint16_t portList[] ); int Stream5SetRuntimeConfiguration( Stream5LWSession *lwssn, uint8_t protocol ); #endif /* SNORT_STREAM5_SESSION_H_ */ snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_session.c0000644000000000000000000011235412260565733021475 00000000000000/* $Id$ */ /* ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. ** Copyright (C) 2005-2013 Sourcefire, Inc. ** AUTHOR: Steven Sturges ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License Version 2 as ** published by the Free Software Foundation. You may not use, modify or ** distribute this program under any other version of the GNU General ** Public License. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* snort_stream5_session.c * * Purpose: Hash Table implementation of session management functions for * Stream5 preprocessor. * * Arguments: * * Effect: * * Comments: * * Any comments? * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "active.h" #include "decode.h" #include "sf_types.h" #include "snort_debug.h" #include "log.h" #include "util.h" #include "snort_stream5_session.h" #include "stream5_common.h" #include "stream5_ha.h" #include "sfhashfcn.h" #include "bitop_funcs.h" #include "sp_flowbits.h" #include "packet_time.h" #ifndef WIN32 # include # include # include #endif #include "snort.h" #if 0 void PrintSessionKey(SessionKey *skey) { char ipL[INET6_ADDRSTRLEN], ipH[INET6_ADDRSTRLEN]; ipL[0] = ipH[0] = '\0'; if (skey->ip_l[1] || skey->ip_l[2] || skey->ip_l[3] || skey->ip_h[1] || skey->ip_h[2] || skey->ip_h[3]) { sfip_raw_ntop(AF_INET6, skey->ip_l, ipL, sizeof(ipL)); sfip_raw_ntop(AF_INET6, skey->ip_h, ipH, sizeof(ipH)); } else { sfip_raw_ntop(AF_INET, skey->ip_l, ipL, sizeof(ipL)); sfip_raw_ntop(AF_INET, skey->ip_h, ipH, sizeof(ipH)); } LogMessage("SessionKey:\n"); LogMessage(" ip_l = %s\n", ipL); LogMessage(" ip_h = %s\n", ipH); LogMessage(" prt_l = %d\n", skey->port_l); LogMessage(" prt_h = %d\n", skey->port_h); LogMessage(" vlan_tag = %d\n", skey->vlan_tag); #ifdef MPLS LogMessage(" mpls label = 0x%08X\n", skey->mplsLabel); #endif #ifdef HAVE_DAQ_ADDRESS_SPACE_ID LogMessage(" addr space id = %d\n", skey->addressSpaceId); #endif } #endif int GetLWSessionCount(Stream5SessionCache *sessionCache) { if (sessionCache && sessionCache->hashTable) return sessionCache->hashTable->count; else return 0; } int GetLWSessionKeyFromIpPort( snort_ip_p srcIP, uint16_t srcPort, snort_ip_p dstIP, uint16_t dstPort, char proto, uint16_t vlan, uint32_t mplsId, uint16_t addressSpaceId, SessionKey *key) { uint16_t sport; uint16_t dport; /* Because the key is going to be used for hash lookups, * the lower of the values of the IP address field is * stored in the key->ip_l and the port for that ip is * stored in key->port_l. */ if (!key) return 0; if (IS_IP4(srcIP)) { uint32_t *src; uint32_t *dst; switch (proto) { case IPPROTO_TCP: case IPPROTO_UDP: sport = srcPort; dport = dstPort; break; case IPPROTO_ICMP: if (srcPort == ICMP_ECHOREPLY) { dport = ICMP_ECHO; /* Treat ICMP echo reply the same as request */ sport = 0; } else /* otherwise, every ICMP type gets different key */ { sport = srcPort; dport = 0; } break; default: sport = dport = 0; break; } src = srcIP->ip32; dst = dstIP->ip32; /* These comparisons are done in this fashion for performance reasons */ if (*src < *dst) { COPY4(key->ip_l, src); COPY4(key->ip_h, dst); key->port_l = sport; key->port_h = dport; } else if (*src == *dst) { COPY4(key->ip_l, src); COPY4(key->ip_h, dst); if (sport < dport) { key->port_l = sport; key->port_h = dport; } else { key->port_l = dport; key->port_h = sport; } } else { COPY4(key->ip_l, dst); key->port_l = dport; COPY4(key->ip_h, src); key->port_h = sport; } # ifdef MPLS if (ScMplsOverlappingIp() && isPrivateIP(*src) && isPrivateIP(*dst)) { key->mplsLabel = mplsId; } else { key->mplsLabel = 0; } # else key->mplsLabel = 0; # endif } else { /* IPv6 */ sfip_t *src; sfip_t *dst; switch (proto) { case IPPROTO_TCP: case IPPROTO_UDP: sport = srcPort; dport = dstPort; break; case IPPROTO_ICMP: if (srcPort == ICMP_ECHOREPLY) { dport = ICMP_ECHO; /* Treat ICMP echo reply the same as request */ sport = 0; } else /* otherwise, every ICMP type gets different key */ { sport = srcPort; dport = 0; } break; case IPPROTO_ICMPV6: if (srcPort == ICMP6_REPLY) { dport = ICMP6_ECHO; /* Treat ICMPv6 echo reply the same as request */ sport = 0; } else /* otherwise, every ICMP type gets different key */ { sport = srcPort; dport = 0; } break; default: sport = dport = 0; break; } src = srcIP; dst = dstIP; if (sfip_fast_lt6(src, dst)) { COPY4(key->ip_l, src->ip32); key->port_l = sport; COPY4(key->ip_h, dst->ip32); key->port_h = dport; } else if (sfip_fast_eq6(src, dst)) { COPY4(key->ip_l, src->ip32); COPY4(key->ip_h, dst->ip32); if (sport < dport) { key->port_l = sport; key->port_h = dport; } else { key->port_l = dport; key->port_h = sport; } } else { COPY4(key->ip_l, dst->ip32); key->port_l = dport; COPY4(key->ip_h, src->ip32); key->port_h = sport; } # ifdef MPLS if (ScMplsOverlappingIp()) { key->mplsLabel = mplsId; } else { key->mplsLabel = 0; } # else key->mplsLabel = 0; # endif } key->protocol = proto; if (!ScVlanAgnostic()) key->vlan_tag = vlan; else key->vlan_tag = 0; key->pad = 0; #ifdef HAVE_DAQ_ADDRESS_SPACE_ID if (!ScAddressSpaceAgnostic()) key->addressSpaceId = addressSpaceId; else key->addressSpaceId = 0; #else key->addressSpaceId = 0; #endif key->addressSpaceIdPad1 = 0; return 1; } int GetLWSessionKey(Packet *p, SessionKey *key) { char proto = GET_IPH_PROTO(p); uint32_t mplsId = 0; uint16_t vlanId = 0; uint16_t sport = p->sp; uint16_t addressSpaceId = 0; # ifdef MPLS if (ScMplsOverlappingIp() && (p->mpls != NULL)) { mplsId = p->mplsHdr.label; } #endif #ifdef HAVE_DAQ_ADDRESS_SPACE_ID addressSpaceId = DAQ_GetAddressSpaceID(p->pkth); #endif if (p->vh && !ScVlanAgnostic()) vlanId = (uint16_t)VTH_VLAN(p->vh); if ((proto == IPPROTO_ICMP) || (proto == IPPROTO_ICMPV6)) { /* ICMP */ sport = p->icmph->type; } return GetLWSessionKeyFromIpPort(GET_SRC_IP(p), sport, GET_DST_IP(p), p->dp, proto, vlanId, mplsId, addressSpaceId, key); } void GetLWPacketDirection(Packet *p, Stream5LWSession *ssn) { if(IS_IP4(p)) { if (sfip_fast_eq4(&p->ip4h->ip_src, &ssn->client_ip)) { if (GET_IPH_PROTO(p) == IPPROTO_TCP) { if (p->tcph->th_sport == ssn->client_port) { p->packet_flags |= PKT_FROM_CLIENT; } else { p->packet_flags |= PKT_FROM_SERVER; } } else if (GET_IPH_PROTO(p) == IPPROTO_UDP) { if (p->udph->uh_sport == ssn->client_port) { p->packet_flags |= PKT_FROM_CLIENT; } else { p->packet_flags |= PKT_FROM_SERVER; } } else { p->packet_flags |= PKT_FROM_CLIENT; } } else if (sfip_fast_eq4(&p->ip4h->ip_dst, &ssn->client_ip)) { if (GET_IPH_PROTO(p) == IPPROTO_TCP) { if (p->tcph->th_dport == ssn->client_port) { p->packet_flags |= PKT_FROM_SERVER; } else { p->packet_flags |= PKT_FROM_CLIENT; } } else if (GET_IPH_PROTO(p) == IPPROTO_UDP) { if (p->udph->uh_dport == ssn->client_port) { p->packet_flags |= PKT_FROM_SERVER; } else { p->packet_flags |= PKT_FROM_CLIENT; } } else { p->packet_flags |= PKT_FROM_SERVER; } } } else /* IS_IP6(p) */ { if (sfip_fast_eq6(&p->ip6h->ip_src, &ssn->client_ip)) { if (GET_IPH_PROTO(p) == IPPROTO_TCP) { if (p->tcph->th_sport == ssn->client_port) { p->packet_flags |= PKT_FROM_CLIENT; } else { p->packet_flags |= PKT_FROM_SERVER; } } else if (GET_IPH_PROTO(p) == IPPROTO_UDP) { if (p->udph->uh_sport == ssn->client_port) { p->packet_flags |= PKT_FROM_CLIENT; } else { p->packet_flags |= PKT_FROM_SERVER; } } else { p->packet_flags |= PKT_FROM_CLIENT; } } else if (sfip_fast_eq6(&p->ip6h->ip_dst, &ssn->client_ip)) { if (GET_IPH_PROTO(p) == IPPROTO_TCP) { if (p->tcph->th_dport == ssn->client_port) { p->packet_flags |= PKT_FROM_SERVER; } else { p->packet_flags |= PKT_FROM_CLIENT; } } else if (GET_IPH_PROTO(p) == IPPROTO_UDP) { if (p->udph->uh_dport == ssn->client_port) { p->packet_flags |= PKT_FROM_SERVER; } else { p->packet_flags |= PKT_FROM_CLIENT; } } else { p->packet_flags |= PKT_FROM_SERVER; } } } } Stream5LWSession *GetLWSession(Stream5SessionCache *sessionCache, Packet *p, SessionKey *key) { Stream5LWSession *returned = NULL; SFXHASH_NODE *hnode; if (!sessionCache) return NULL; if (!GetLWSessionKey(p, key)) { return NULL; } hnode = sfxhash_find_node(sessionCache->hashTable, key); if (hnode && hnode->data) { /* This is a unique hnode, since the sfxhash finds the * same key before returning this node. */ returned = (Stream5LWSession *)hnode->data; if (returned && (returned->last_data_seen < p->pkth->ts.tv_sec)) { returned->last_data_seen = p->pkth->ts.tv_sec; } } return returned; } Stream5LWSession *GetLWSessionFromKey(Stream5SessionCache *sessionCache, const SessionKey *key) { Stream5LWSession *returned = NULL; SFXHASH_NODE *hnode; if (!sessionCache) return NULL; hnode = sfxhash_find_node(sessionCache->hashTable, key); if (hnode && hnode->data) { /* This is a unique hnode, since the sfxhash finds the * same key before returning this node. */ returned = (Stream5LWSession *)hnode->data; } return returned; } void FreeLWApplicationData(Stream5LWSession *ssn) { Stream5AppData *tmpData, *appData = ssn->appDataList; while (appData) { if (appData->freeFunc && appData->dataPointer) { appData->freeFunc(appData->dataPointer); } tmpData = appData->next; free(appData); appData = tmpData; } ssn->appDataList = NULL; } static int RemoveLWSession(Stream5SessionCache *sessionCache, Stream5LWSession *ssn) { SFXHASH_NODE *hnode; Stream5Config *pPolicyConfig = NULL; tSfPolicyId policy_id = ssn->policy_id; mempool_free(&s5FlowMempool, ssn->flowdata); ssn->flowdata = NULL; pPolicyConfig = (Stream5Config *)sfPolicyUserDataGet(ssn->config, policy_id); if (pPolicyConfig != NULL) { pPolicyConfig->ref_count--; if ((pPolicyConfig->ref_count == 0) && (ssn->config != s5_config)) { sfPolicyUserDataClear (ssn->config, policy_id); Stream5FreeConfig(pPolicyConfig); if (sfPolicyUserPolicyGetActive(ssn->config) == 0) Stream5FreeConfigs(ssn->config); } } hnode = sfxhash_find_node(sessionCache->hashTable, ssn->key); if (!hnode) return SFXHASH_ERR; if (sessionCache->nextTimeoutEvalNode == hnode) sessionCache->nextTimeoutEvalNode = NULL; return sfxhash_free_node(sessionCache->hashTable, hnode); } int DeleteLWSession(Stream5SessionCache *sessionCache, Stream5LWSession *ssn, char *delete_reason) { /* Need to save the current configurations being used since this function * may cause a packet reassembly on this deleted session when flushing * (via sessionCache->cleanup_fcn) and a preprocessor may call an API * function changing the configurations to this one to be deleted */ Stream5GlobalConfig *save_global_eval_config = s5_global_eval_config; Stream5TcpConfig *save_tcp_eval_config = s5_tcp_eval_config; Stream5UdpConfig *save_udp_eval_config = s5_udp_eval_config; Stream5IcmpConfig *save_icmp_eval_config = s5_icmp_eval_config; int ret; uint32_t prune_log_max; /* Save the current mem in use before pruning */ uint32_t old_mem_in_use = mem_in_use; /* And save some info on that session */ sfip_t client_ip; sfip_t server_ip; uint16_t client_port = ntohs(ssn->client_port); uint16_t server_port = ntohs(ssn->server_port); uint16_t lw_session_state = ssn->session_state; uint32_t lw_session_flags = ssn->ha_state.session_flags; #ifdef TARGET_BASED int16_t app_proto_id = ssn->ha_state.application_protocol; #endif sfip_set_ip(&client_ip, &ssn->client_ip); sfip_set_ip(&server_ip, &ssn->server_ip); #ifdef ENABLE_HA if (!(sessionCache->flags & SESSION_CACHE_FLAG_PURGING)) Stream5HANotifyDeletion(ssn); #endif /* * Call callback to cleanup the protocol (TCP/UDP/ICMP) * specific session details */ if (sessionCache->cleanup_fcn) sessionCache->cleanup_fcn(ssn); FreeLWApplicationData(ssn); /* Need to save this off since the global config might be from an * older session - because of a reload - and that config might * get freed after removing the session */ prune_log_max = s5_global_eval_config->prune_log_max; ret = RemoveLWSession(sessionCache, ssn); /* If we're pruning and we clobbered some large amount, log a * message about that session. */ if (prune_log_max && ((old_mem_in_use - mem_in_use ) > prune_log_max)) { char *client_ip_str, *server_ip_str; client_ip_str = SnortStrdup(inet_ntoa(&client_ip)); server_ip_str = SnortStrdup(inet_ntoa(&server_ip)); LogMessage("S5: Pruned session from cache that was " "using %d bytes (%s). %s %d --> %s %d " #ifdef TARGET_BASED "(%d) " #endif ": LWstate 0x%x LWFlags 0x%x\n", old_mem_in_use - mem_in_use, delete_reason, client_ip_str, client_port, server_ip_str, server_port, #ifdef TARGET_BASED app_proto_id, #endif lw_session_state, lw_session_flags); free(client_ip_str); free(server_ip_str); } s5_global_eval_config = save_global_eval_config; s5_tcp_eval_config = save_tcp_eval_config; s5_udp_eval_config = save_udp_eval_config; s5_icmp_eval_config = save_icmp_eval_config; return ret; } int PurgeLWSessionCache(Stream5SessionCache *sessionCache) { int retCount = 0; Stream5LWSession *idx; SFXHASH_NODE *hnode; if (!sessionCache) return 0; sessionCache->flags |= SESSION_CACHE_FLAG_PURGING; /* Remove all sessions from the hash table. */ hnode = sfxhash_mru_node(sessionCache->hashTable); while (hnode) { idx = (Stream5LWSession *)hnode->data; if (!idx) { sfxhash_free_node(sessionCache->hashTable, hnode); } else { idx->ha_state.session_flags |= SSNFLAG_PRUNED; if ( !Stream5SetRuntimeConfiguration(idx, idx->protocol) ) DeleteLWSession(sessionCache, idx, "purge whole cache"); } hnode = sfxhash_mru_node(sessionCache->hashTable); retCount++; } sessionCache->flags &= ~SESSION_CACHE_FLAG_PURGING; return retCount; } int DeleteLWSessionCache(Stream5SessionCache *sessionCache) { int retCount = 0; if (!sessionCache) return 0; retCount = PurgeLWSessionCache(sessionCache); sfxhash_delete(sessionCache->hashTable); free(sessionCache); return retCount; } static inline int SessionWasBlocked (Stream5LWSession* ssn) { return (ssn->ha_state.session_flags & (SSNFLAG_DROP_CLIENT|SSNFLAG_DROP_SERVER)) != 0; } int PruneLWSessionCache(Stream5SessionCache *sessionCache, uint32_t thetime, Stream5LWSession *save_me, int memCheck) { Stream5LWSession *idx; uint32_t pruned = 0; Active_Suspend(); if (thetime != 0) { /* Pruning, look for sessions that have time'd out */ char got_one; idx = (Stream5LWSession *) sfxhash_lru(sessionCache->hashTable); if(idx == NULL) { Active_Resume(); return 0; } do { got_one = 0; if(idx == save_me) { SFXHASH_NODE *lastNode = sfxhash_lru_node(sessionCache->hashTable); sfxhash_gmovetofront(sessionCache->hashTable, lastNode); lastNode = sfxhash_lru_node(sessionCache->hashTable); if ((lastNode) && (lastNode->data != idx)) { idx = (Stream5LWSession *)lastNode->data; continue; } else { sessionCache->prunes += pruned; Active_Resume(); return pruned; } } if((idx->last_data_seen+sessionCache->timeoutAggressive) < thetime) { Stream5LWSession *savidx = idx; if(sfxhash_count(sessionCache->hashTable) > 1) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "pruning stale session\n");); savidx->ha_state.session_flags |= SSNFLAG_TIMEDOUT; DeleteLWSession(sessionCache, savidx, "stale/timeout"); idx = (Stream5LWSession *) sfxhash_lru(sessionCache->hashTable); pruned++; got_one = 1; } else { savidx->ha_state.session_flags |= SSNFLAG_TIMEDOUT; DeleteLWSession(sessionCache, savidx, "stale/timeout/last ssn"); pruned++; sessionCache->prunes += pruned; Active_Resume(); return pruned; } } else { sessionCache->prunes += pruned; Active_Resume(); return pruned; } if (pruned > sessionCache->cleanup_sessions) { /* Don't bother cleaning more than 'n' at a time */ break; } } while ((idx != NULL) && (got_one == 1)); sessionCache->prunes += pruned; Active_Resume(); return pruned; } else { /* Free up 'n' sessions at a time until we get under the * memcap or free enough sessions to be able to create * new ones. */ unsigned int session_count; #define s5_sessions_in_table() \ ((session_count = sfxhash_count(sessionCache->hashTable)) > 1) #define s5_over_session_limit() \ (session_count > (sessionCache->max_sessions - sessionCache->cleanup_sessions)) #define s5_havent_pruned_yet() \ (pruned == 0) #define s5_over_memcap() \ (mem_in_use > s5_global_eval_config->memcap) while (s5_sessions_in_table() && ((!memCheck && (s5_over_session_limit() || s5_havent_pruned_yet())) || (memCheck && s5_over_memcap() ))) { unsigned int i; unsigned int blocks = 0; DEBUG_WRAP( DebugMessage(DEBUG_STREAM, "S5: Pruning session cache by %d ssns for %s: %d/%d\n", sessionCache->cleanup_sessions, memCheck ? "memcap" : "hash limit", mem_in_use, s5_global_eval_config->memcap);); idx = (Stream5LWSession *) sfxhash_lru(sessionCache->hashTable); for (i=0;icleanup_sessions && (sfxhash_count(sessionCache->hashTable) >= blocks+1); i++) { if ( (idx != save_me) && (!memCheck || !SessionWasBlocked(idx)) ) { idx->ha_state.session_flags |= SSNFLAG_PRUNED; DeleteLWSession(sessionCache, idx, memCheck ? "memcap/check" : "memcap/stale"); pruned++; idx = (Stream5LWSession *) sfxhash_lru(sessionCache->hashTable); } else { SFXHASH_NODE* lastNode; if ( SessionWasBlocked(idx) ) blocks++; lastNode = sfxhash_lru_node(sessionCache->hashTable); sfxhash_gmovetofront(sessionCache->hashTable, lastNode); lastNode = sfxhash_lru_node(sessionCache->hashTable); if ((lastNode) && (lastNode->data == idx)) { /* Okay, this session is the only one left */ break; } idx = (Stream5LWSession *) sfxhash_lru(sessionCache->hashTable); i--; /* Didn't clean this one */ } } /* Nothing (or the one we're working with) in table, couldn't * kill it */ if (!memCheck && (pruned == 0)) { break; } } } if (memCheck && pruned) { LogMessage("S5: Pruned %d sessions from cache for memcap. %d ssns remain. memcap: %d/%d\n", pruned, sfxhash_count(sessionCache->hashTable), mem_in_use, s5_global_eval_config->memcap); DEBUG_WRAP( if (sfxhash_count(sessionCache->hashTable) == 1) { DebugMessage(DEBUG_STREAM, "S5: Pruned, one session remains\n"); } ); } sessionCache->prunes += pruned; Active_Resume(); return pruned; } Stream5LWSession *NewLWSession(Stream5SessionCache *sessionCache, Packet *p, const SessionKey *key, void *policy) { Stream5LWSession *retSsn = NULL; Stream5Config *pLWSPolicyConfig; SFXHASH_NODE *hnode; StreamFlowData *flowdata; time_t timestamp = p ? p->pkth->ts.tv_sec : packet_time(); hnode = sfxhash_get_node(sessionCache->hashTable, key); if (!hnode) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "HashTable full, clean it\n");); if (!PruneLWSessionCache(sessionCache, timestamp, NULL, 0)) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "HashTable full, no timeouts, clean it\n");); PruneLWSessionCache(sessionCache, 0, NULL, 0); } /* Should have some freed nodes now */ hnode = sfxhash_get_node(sessionCache->hashTable, key); #ifdef DEBUG_MSGS if (!hnode) { LogMessage("%s(%d) Problem, no freed nodes\n", __FILE__, __LINE__); } #endif } if (hnode && hnode->data) { retSsn = hnode->data; /* Zero everything out */ memset(retSsn, 0, sizeof(Stream5LWSession)); /* Save the session key for future use */ retSsn->key = hnode->key; retSsn->protocol = key->protocol; retSsn->last_data_seen = timestamp; retSsn->flowdata = mempool_alloc(&s5FlowMempool); flowdata = retSsn->flowdata->data; boInitStaticBITOP(&(flowdata->boFlowbits), getFlowbitSizeInBytes(), flowdata->flowb); retSsn->policy = policy; retSsn->config = s5_config; retSsn->policy_id = getRuntimePolicy(); pLWSPolicyConfig = (Stream5Config *) sfPolicyUserDataGet(retSsn->config, retSsn->policy_id); pLWSPolicyConfig->ref_count++; #ifdef ENABLE_HA if (pLWSPolicyConfig->global_config->enable_ha) { retSsn->ha_flags |= HA_FLAG_NEW; /* Calculate the threshold time for the first HA update message. */ packet_gettimeofday(&retSsn->ha_next_update); if (pLWSPolicyConfig->ha_config) { retSsn->ha_next_update.tv_usec += pLWSPolicyConfig->ha_config->min_session_lifetime.tv_usec; if (retSsn->ha_next_update.tv_usec > 1000000) { retSsn->ha_next_update.tv_usec -= 1000000; retSsn->ha_next_update.tv_sec++; } retSsn->ha_next_update.tv_sec += pLWSPolicyConfig->ha_config->min_session_lifetime.tv_sec; } } #endif } return retSsn; } uint32_t HashFunc(SFHASHFCN *p, unsigned char *d, int n) { uint32_t a,b,c; uint32_t offset = 0; #ifdef MPLS uint32_t tmp = 0; #endif #ifdef HAVE_DAQ_ADDRESS_SPACE_ID uint32_t tmp2 = 0; #endif a = *(uint32_t*)d; /* IPv6 lo[0] */ b = *(uint32_t*)(d+4); /* IPv6 lo[1] */ c = *(uint32_t*)(d+8); /* IPv6 lo[2] */ mix(a,b,c); a += *(uint32_t*)(d+12); /* IPv6 lo[3] */ b += *(uint32_t*)(d+16); /* IPv6 hi[0] */ c += *(uint32_t*)(d+20); /* IPv6 hi[1] */ mix(a,b,c); a += *(uint32_t*)(d+24); /* IPv6 hi[2] */ b += *(uint32_t*)(d+28); /* IPv6 hi[3] */ c += *(uint32_t*)(d+32); /* port lo & port hi */ mix(a,b,c); offset=36; a += *(uint32_t*)(d+offset); /* vlan, protocol, & pad */ #ifdef MPLS tmp = *(uint32_t *)(d+offset+4); if( tmp ) { b += tmp; /* mpls label */ } offset += 8; /* skip past vlan/proto/ipver & mpls label */ #else offset += 4; /* skip past vlan/proto/ipver */ #endif #ifdef HAVE_DAQ_ADDRESS_SPACE_ID tmp2 = *(uint32_t*)(d+offset); /* after offset that has been moved */ c += tmp2; /* address space id and 16bits of zero'd pad */ #endif final(a,b,c); return c; } int HashKeyCmp(const void *s1, const void *s2, size_t n) { #ifndef SPARCV9 /* ie, everything else, use 64bit comparisons */ uint64_t *a,*b; a = (uint64_t*)s1; b = (uint64_t*)s2; if(*a - *b) return 1; /* Compares IPv4 lo/hi */ /* Compares IPv6 low[0,1] */ a++; b++; if(*a - *b) return 1; /* Compares port lo/hi, vlan, protocol, pad */ /* Compares IPv6 low[2,3] */ a++; b++; if(*a - *b) return 1; /* Compares IPv6 hi[0,1] */ a++; b++; if(*a - *b) return 1; /* Compares IPv6 hi[2,3] */ a++; b++; if(*a - *b) return 1; /* Compares port lo/hi, vlan, protocol, pad */ #ifdef MPLS a++; b++; #ifdef HAVE_DAQ_ADDRESS_SPACE_ID if (*a - *b) return 1; /* Compares MPLS label, AddressSpace ID and 16bit pad */ #else { uint32_t *x, *y; x = (uint32_t *)a; y = (uint32_t *)b; //x++; //y++; if (*x - *y) return 1; /* Compares mpls label, no pad */ } #endif #else #ifdef HAVE_DAQ_ADDRESS_SPACE_ID a++; b++; { uint16_t *x, *y; x = (uint16_t *)a; y = (uint16_t *)b; //x++; //y++; if (*x - *y) return 1; /* Compares addressSpaceID, no pad */ } #endif #endif #else /* SPARCV9 */ uint32_t *a,*b; a = (uint32_t*)s1; b = (uint32_t*)s2; if ((*a - *b) || (*(a+1) - *(b+1))) return 1; /* Compares IPv4 lo/hi */ /* Compares IPv6 low[0,1] */ a+=2; b+=2; if ((*a - *b) || (*(a+1) - *(b+1))) return 1; /* Compares port lo/hi, vlan, protocol, pad */ /* Compares IPv6 low[2,3] */ a+=2; b+=2; if ((*a - *b) || (*(a+1) - *(b+1))) return 1; /* Compares IPv6 hi[0,1] */ a+=2; b+=2; if ((*a - *b) || (*(a+1) - *(b+1))) return 1; /* Compares IPv6 hi[2,3] */ a+=2; b+=2; if ((*a - *b) || (*(a+1) - *(b+1))) return 1; /* Compares port lo/hi, vlan, protocol, pad */ #ifdef MPLS a+=2; b+=2; { uint32_t *x, *y; x = (uint32_t *)a; y = (uint32_t *)b; //x++; //y++; if (*x - *y) return 1; /* Compares mpls label */ } #endif #ifdef HAVE_DAQ_ADDRESS_SPACE_ID #ifdef MPLS a++; b++; #else a+=2; b+=2; #endif { uint16_t *x, *y; x = (uint16_t *)a; y = (uint16_t *)b; //x++; //y++; if (*x - *y) return 1; /* Compares addressSpaceID, no pad */ } #endif #endif /* SPARCV9 */ return 0; } Stream5SessionCache *InitLWSessionCache(int max_sessions, uint32_t session_timeout_min, uint32_t session_timeout_max, uint32_t cleanup_sessions, uint32_t cleanup_percent, Stream5SessionCleanup cleanup_fcn) { Stream5SessionCache *sessionCache = NULL; /* Rule of thumb, size should be 1.4 times max to avoid * collisions. */ int hashTableSize = max_sessions; // int hashTableSize = sfxhash_calcrows((int) (max_sessions * 1.4)); /* Memory required for 1 node: LW Session + Session Key + * Node + NodePtr. */ //int maxSessionMem = max_sessions * ( // sizeof(Stream5LWSession) + // sizeof(SFXHASH_NODE) + // sizeof(SessionKey) + // sizeof(SFXHASH_NODE *)); /* Memory required for table entries */ //int tableMem = (hashTableSize +1) * sizeof(SFXHASH_NODE*); sessionCache = SnortAlloc(sizeof(Stream5SessionCache)); if (sessionCache) { sessionCache->timeoutAggressive = session_timeout_min; sessionCache->timeoutNominal = session_timeout_max; sessionCache->max_sessions = max_sessions; if (cleanup_percent) { sessionCache->cleanup_sessions = max_sessions * cleanup_percent/100; } else { sessionCache->cleanup_sessions = cleanup_sessions; } if (sessionCache->cleanup_sessions == 0) { sessionCache->cleanup_sessions = 1; } sessionCache->cleanup_fcn = cleanup_fcn; /* Okay, now create the table */ sessionCache->hashTable = sfxhash_new( hashTableSize, sizeof(SessionKey), sizeof(Stream5LWSession), //maxSessionMem + tableMem, 0, NULL, NULL, 1); 0, 0, NULL, NULL, 1); sfxhash_set_max_nodes(sessionCache->hashTable, max_sessions); sfxhash_set_keyops(sessionCache->hashTable, HashFunc, HashKeyCmp); } return sessionCache; } void PrintLWSessionCache(Stream5SessionCache *sessionCache) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "%lu sessions active\n", sfxhash_count(sessionCache->hashTable));); } int Stream5SetRuntimeConfiguration( Stream5LWSession *lwssn, uint8_t protocol ) { Stream5Config *pPolicyConfig; if (lwssn == NULL) pPolicyConfig = (Stream5Config *)sfPolicyUserDataGet(s5_config, getRuntimePolicy()); else pPolicyConfig = (Stream5Config *)sfPolicyUserDataGet(lwssn->config, lwssn->policy_id); if (pPolicyConfig == NULL) return -1; if (pPolicyConfig->global_config == NULL) return -1; s5_global_eval_config = pPolicyConfig->global_config; switch (protocol) { case IPPROTO_TCP: if (!s5_global_eval_config->track_tcp_sessions || !pPolicyConfig->tcp_config) { s5_tcp_eval_config = NULL; return -1; } s5_tcp_eval_config = pPolicyConfig->tcp_config; break; case IPPROTO_UDP: if (!s5_global_eval_config->track_udp_sessions || !pPolicyConfig->udp_config) { s5_udp_eval_config = NULL; return -1; } s5_udp_eval_config = pPolicyConfig->udp_config; break; case IPPROTO_ICMP: if (s5_global_eval_config->track_icmp_sessions && pPolicyConfig->icmp_config) { s5_icmp_eval_config = pPolicyConfig->icmp_config; return 0; } s5_icmp_eval_config = NULL; // fall thru ... icmp is also handled by ip default: if (!s5_global_eval_config->track_ip_sessions || !pPolicyConfig->ip_config) { s5_ip_eval_config = NULL; return -1; } s5_ip_eval_config = pPolicyConfig->ip_config; break; } return 0; } static void checkCacheFlowTimeout(uint32_t flowCount, time_t cur_time, Stream5SessionCache *cache) { uint32_t flowRetiredCount = 0, flowExaminedCount = 0; Stream5LWSession *lwssn; SFXHASH_NODE *hnode, *hnode_prev; if (!cache) return; hnode_prev = cache->nextTimeoutEvalNode; while (flowRetiredCount < flowCount && flowExaminedCount < (2 * flowCount)) { if (!(hnode = hnode_prev) && !(hnode = sfxhash_lru_node(cache->hashTable))) break; lwssn = (Stream5LWSession *) hnode->data; if ((time_t)(lwssn->last_data_seen + cache->timeoutNominal) > cur_time) { uint64_t time_jiffies; /* Give extra 1 second delay*/ time_jiffies = ((uint64_t)cur_time - 1) * TCP_HZ; if (!lwssn->expire_time || !cur_time || (lwssn->expire_time > time_jiffies)) break; } hnode_prev = hnode->gprev; flowExaminedCount++; #ifdef ENABLE_HA if (lwssn->ha_flags & HA_FLAG_STANDBY) continue; #endif DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "retiring stale session\n");); lwssn->ha_state.session_flags |= SSNFLAG_TIMEDOUT; if ( !Stream5SetRuntimeConfiguration(lwssn, lwssn->protocol) ) DeleteLWSession(cache, lwssn, "stale/timeout"); flowRetiredCount++; } cache->nextTimeoutEvalNode = hnode_prev; } extern Stream5SessionCache *tcp_lws_cache, *udp_lws_cache; /*get next flow from session cache. */ void checkLWSessionTimeout(uint32_t flowCount, time_t cur_time) { Active_Suspend(); checkCacheFlowTimeout(flowCount, cur_time, tcp_lws_cache); checkCacheFlowTimeout(flowCount, cur_time, udp_lws_cache); //icmp_lws_cache does not need cleaning Active_Resume(); } snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_ip.h0000644000000000000000000000324212260565733020422 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2011-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /* * @file snort_stream5_ip.h * @author Russ Combs * */ #ifndef __STREAM5_IP_H__ #define __STREAM5_IP_H__ #include "stream5_common.h" #include "sfPolicy.h" void Stream5CleanIp(void); void Stream5ResetIp(void); void Stream5InitIp(Stream5GlobalConfig*); void Stream5IpPolicyInit(Stream5IpConfig*, char*); int Stream5VerifyIpConfig(Stream5IpConfig*, tSfPolicyId); void Stream5IpConfigFree(Stream5IpConfig*); int Stream5ProcessIp(Packet *p, Stream5LWSession *lwssn, SessionKey *skey); uint32_t Stream5GetIpPrunes(void); void Stream5ResetIpPrunes(void); void IpSessionCleanup (Stream5LWSession* lws); #endif snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_ip.c0000644000000000000000000003165212260565733020423 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * ***************************************************************************/ /* * @file snort_stream5_ip.c * @author Russ Combs * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "active.h" #include "decode.h" #include "detect.h" #include "mstring.h" #include "parser.h" #include "profiler.h" #include "sfPolicy.h" #include "sfxhash.h" #include "sf_types.h" #include "snort_debug.h" #include "snort_stream5_ip.h" #include "snort_stream5_session.h" #include "stream_expect.h" #include "stream5_ha.h" #include "util.h" #ifdef PERF_PROFILING PreprocStats s5IpPerfStats; #endif Stream5SessionCache* ip_lws_cache; //------------------------------------------------------------------------- // private methods //------------------------------------------------------------------------- static void Stream5PrintIpConfig (Stream5IpPolicy* policy) { LogMessage("Stream5 IP Policy config:\n"); LogMessage(" Timeout: %d seconds\n", policy->session_timeout); } static void Stream5ParseIpArgs (char* args, Stream5IpPolicy* policy) { char* *toks; int num_toks; int i; policy->session_timeout = S5_DEFAULT_SSN_TIMEOUT; if ( !args || !*args ) return; toks = mSplit(args, ",", 0, &num_toks, 0); for (i = 0; i < num_toks; i++) { int s_toks; char* *stoks = mSplit(toks[i], " ", 2, &s_toks, 0); if (s_toks == 0) { ParseError("Missing parameter in Stream5 IP config.\n"); } if(!strcasecmp(stoks[0], "timeout")) { char* endPtr = NULL; if(stoks[1]) { policy->session_timeout = strtoul(stoks[1], &endPtr, 10); } if (!stoks[1] || (endPtr == &stoks[1][0])) { ParseError("Invalid timeout in config file. Integer parameter required.\n"); } if ((policy->session_timeout > S5_MAX_SSN_TIMEOUT) || (policy->session_timeout < S5_MIN_SSN_TIMEOUT)) { ParseError("Invalid timeout in config file. Must be between %d and %d\n", S5_MIN_SSN_TIMEOUT, S5_MAX_SSN_TIMEOUT); } if (s_toks > 2) { ParseError("Invalid Stream5 IP Policy option. Missing comma?\n"); } } else { ParseError("Invalid Stream5 IP policy option\n"); } mSplitFree(&stoks, s_toks); } mSplitFree(&toks, num_toks); } void IpSessionCleanup (Stream5LWSession* lws) { if (lws->ha_state.session_flags & SSNFLAG_PRUNED) { CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED); } else if (lws->ha_state.session_flags & SSNFLAG_TIMEDOUT) { CloseStreamSession(&sfBase, SESSION_CLOSED_TIMEDOUT); } else { CloseStreamSession(&sfBase, SESSION_CLOSED_NORMALLY); } Stream5ResetFlowBits(lws); FreeLWApplicationData(lws); lws->ha_state.session_flags = SSNFLAG_NONE; lws->session_state = STREAM5_STATE_NONE; lws->expire_time = 0; lws->ha_state.ignore_direction = 0; } //------------------------------------------------------------------------- // ip ha stuff //------------------------------------------------------------------------- static Stream5LWSession *GetLWIpSession (const SessionKey *key) { return GetLWSessionFromKey(ip_lws_cache, key); } static Stream5LWSession *Stream5IPCreateSession (const SessionKey *key) { setRuntimePolicy(getDefaultPolicy()); return NewLWSession(ip_lws_cache, NULL, key, NULL); } static int Stream5IPDeleteSession (const SessionKey *key) { Stream5LWSession *lwssn = GetLWSessionFromKey(ip_lws_cache, key); // use explicit IPPROTO_IP instead of lwssn->protocol // because we might come here for icmp sessions if ( lwssn && !Stream5SetRuntimeConfiguration(lwssn, IPPROTO_IP) ) DeleteLWSession(ip_lws_cache, lwssn, "ha sync"); return 0; } #ifdef ENABLE_HA static HA_Api ha_ip_api = { /*.get_lws = */ GetLWIpSession, /*.create_session = */ Stream5IPCreateSession, /*.deactivate_session = */ NULL, /*.delete_session = */ Stream5IPDeleteSession, }; #endif //------------------------------------------------------------------------- // public methods //------------------------------------------------------------------------- void Stream5InitIp (Stream5GlobalConfig* gconfig) { if (gconfig == NULL) return; if((ip_lws_cache == NULL) && gconfig->track_ip_sessions) { ip_lws_cache = InitLWSessionCache( gconfig->max_ip_sessions, 30, 30, 5, 0, IpSessionCleanup); if(!ip_lws_cache) { ParseError("Unable to init stream5 IP session cache, no IP " "stream inspection!\n"); } } #ifdef ENABLE_HA ha_set_api(IPPROTO_IP, &ha_ip_api); #endif } void Stream5ResetIp (void) { PurgeLWSessionCache(ip_lws_cache); } void Stream5CleanIp (void) { if ( ip_lws_cache ) s5stats.ip_prunes = ip_lws_cache->prunes; /* Clean up hash table -- delete all sessions */ DeleteLWSessionCache(ip_lws_cache); ip_lws_cache = NULL; } //------------------------------------------------------------------------- // public config methods //------------------------------------------------------------------------- void Stream5IpPolicyInit (Stream5IpConfig* config, char* args) { if (config == NULL) return; Stream5ParseIpArgs(args, &config->default_policy); Stream5PrintIpConfig(&config->default_policy); } void Stream5IpConfigFree (Stream5IpConfig* config) { if (config == NULL) return; free(config); } int Stream5VerifyIpConfig (Stream5IpConfig* config, tSfPolicyId policy_id) { if (config == NULL) return -1; if (!ip_lws_cache) return -1; return 0; } //------------------------------------------------------------------------- // public access methods //------------------------------------------------------------------------- uint32_t Stream5GetIpPrunes (void) { return ip_lws_cache ? ip_lws_cache->prunes : s5stats.ip_prunes; } void Stream5ResetIpPrunes (void) { if ( ip_lws_cache ) ip_lws_cache->prunes = 0; } //------------------------------------------------------------------------- // private packet processing methods //------------------------------------------------------------------------- static inline void InitSession (Packet* p, Stream5LWSession* lws) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Stream5 IP session created!\n");); s5stats.total_ip_sessions++; IP_COPY_VALUE(lws->client_ip, GET_SRC_IP(p)); IP_COPY_VALUE(lws->server_ip, GET_DST_IP(p)); } static inline int BlockedSession (Packet* p, Stream5LWSession* lws) { if ( !(lws->ha_state.session_flags & (SSNFLAG_DROP_CLIENT|SSNFLAG_DROP_SERVER)) ) return 0; if ( ((p->packet_flags & PKT_FROM_SERVER) && (lws->ha_state.session_flags & SSNFLAG_DROP_SERVER)) || ((p->packet_flags & PKT_FROM_CLIENT) && (lws->ha_state.session_flags & SSNFLAG_DROP_CLIENT)) ) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Blocking %s packet as session was blocked\n", p->packet_flags & PKT_FROM_SERVER ? "server" : "client");); DisableDetect(p); /* Still want to add this number of bytes to totals */ SetPreprocBit(p, PP_PERFMONITOR); if ( lws->ha_state.session_flags & SSNFLAG_FORCE_BLOCK ) Active_ForceDropPacket(); else Active_DropPacket(p); #ifdef ACTIVE_RESPONSE Stream5ActiveResponse(p, lws); #endif return 1; } return 0; } static inline int IgnoreSession (Packet* p, Stream5LWSession* lws) { if ( ((p->packet_flags & PKT_FROM_SERVER) && (lws->ha_state.ignore_direction & SSN_DIR_FROM_CLIENT)) || ((p->packet_flags & PKT_FROM_CLIENT) && (lws->ha_state.ignore_direction & SSN_DIR_FROM_SERVER)) ) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5 Ignoring packet from %d. Session marked as ignore\n", p->packet_flags & PKT_FROM_CLIENT? "sender" : "responder");); Stream5DisableInspection(lws, p); return 1; } return 0; } static inline int CheckExpectedSession (Packet* p, Stream5LWSession* lws) { int ignore; ignore = StreamExpectCheck(p, lws); if (ignore) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Ignoring packet from %d. Marking session marked as ignore.\n", p->packet_flags & PKT_FROM_CLIENT? "sender" : "responder");); lws->ha_state.ignore_direction = ignore; Stream5DisableInspection(lws, p); return 1; } return 0; } static inline void UpdateSession (Packet* p, Stream5LWSession* lws) { MarkupPacketFlags(p, lws); if ( !(lws->ha_state.session_flags & SSNFLAG_ESTABLISHED) ) { if ( p->packet_flags & PKT_FROM_CLIENT ) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Updating on packet from client\n");); lws->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT; } else { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Updating on packet from server\n");); lws->ha_state.session_flags |= SSNFLAG_SEEN_SERVER; } if ( (lws->ha_state.session_flags & SSNFLAG_SEEN_CLIENT) && (lws->ha_state.session_flags & SSNFLAG_SEEN_SERVER) ) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: session established!\n");); lws->ha_state.session_flags |= SSNFLAG_ESTABLISHED; #ifdef ACTIVE_RESPONSE SetTTL(lws, p, 0); #endif } } // Reset the session timeout. { Stream5IpPolicy* policy; policy = (Stream5IpPolicy*)lws->policy; Stream5SetExpire(p, lws, policy->session_timeout); } } //------------------------------------------------------------------------- // public packet processing method //------------------------------------------------------------------------- int Stream5ProcessIp(Packet *p, Stream5LWSession *lwssn, SessionKey *skey) { PROFILE_VARS; PREPROC_PROFILE_START(s5IpPerfStats); if (!lwssn) { lwssn = NewLWSession(ip_lws_cache, p, skey, (void *) s5_ip_eval_config); if (!lwssn) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Stream5 IP session failure!\n");); return 0; } InitSession(p, lwssn); #ifdef ENABLE_EXPECTED_IP if (CheckExpectedSession(p, lwssn)) { PREPROC_PROFILE_END(s5IpPerfStats); return 0; } #endif } else { if ((lwssn->session_state & STREAM5_STATE_TIMEDOUT) || Stream5Expire(p, lwssn)) { lwssn->ha_state.session_flags |= SSNFLAG_TIMEDOUT; /* Session is timed out */ DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Stream5 IP session timeout!\n");); #ifdef ENABLE_HA /* Notify the HA peer of the session cleanup/reset by way of a deletion notification. */ PREPROC_PROFILE_TMPEND(s5IpPerfStats); Stream5HANotifyDeletion(lwssn); lwssn->ha_flags = (HA_FLAG_NEW | HA_FLAG_MODIFIED | HA_FLAG_MAJOR_CHANGE); PREPROC_PROFILE_TMPSTART(s5IpPerfStats); #endif /* Clean it up */ IpSessionCleanup(lwssn); #ifdef ENABLE_EXPECTED_IP if (CheckExpectedSession(p, lwssn)) { PREPROC_PROFILE_END(s5IpPerfStats); return 0; } #endif } /* If this is an existing LWSession that didn't have its policy set, set it now. */ if (lwssn->policy == NULL) lwssn->policy = s5_ip_eval_config; } GetLWPacketDirection(p, lwssn); p->ssnptr = lwssn; if (BlockedSession(p, lwssn) || IgnoreSession(p, lwssn)) { PREPROC_PROFILE_END(s5IpPerfStats); return 0; } UpdateSession(p, lwssn); PREPROC_PROFILE_END(s5IpPerfStats); return 0; } snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_icmp.h0000644000000000000000000000327612260565733020751 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifndef STREAM5_ICMP_H_ #define STREAM5_ICMP_H_ #include "stream5_common.h" #include "sfPolicy.h" void Stream5CleanIcmp(void); void Stream5ResetIcmp(void); void Stream5InitIcmp(Stream5GlobalConfig *); void Stream5IcmpPolicyInit(Stream5IcmpConfig *, char *); int Stream5VerifyIcmpConfig(Stream5IcmpConfig *, tSfPolicyId); int Stream5ProcessIcmp(Packet *p); void IcmpUpdateDirection(Stream5LWSession *ssn, char dir, snort_ip_p ip, uint16_t port); void Stream5IcmpConfigFree(Stream5IcmpConfig *); uint32_t Stream5GetIcmpPrunes(void); void Stream5ResetIcmpPrunes(void); void IcmpSessionCleanup(Stream5LWSession *ssn); #endif /* STREAM5_ICMP_H_ */ snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_icmp.c0000644000000000000000000002567012260565733020746 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "decode.h" #include "mstring.h" #include "sfxhash.h" #include "util.h" #include "stream5_common.h" #include "snort_stream5_session.h" #include "snort_stream5_tcp.h" #include "snort_stream5_udp.h" #include "snort_stream5_icmp.h" #include "parser.h" #include "profiler.h" #include "sfPolicy.h" #ifdef PERF_PROFILING PreprocStats s5IcmpPerfStats; #endif /* client/server ip/port dereference */ #define icmp_sender_ip lwSsn->client_ip #define icmp_responder_ip lwSsn->server_ip /* D A T A S T R U C T U R E S ***********************************/ typedef struct _IcmpSession { Stream5LWSession *lwSsn; uint32_t echo_count; struct timeval ssn_time; } IcmpSession; /* G L O B A L S **************************************************/ Stream5SessionCache *icmp_lws_cache; static MemPool icmp_session_mempool; /* P R O T O T Y P E S ********************************************/ static void Stream5ParseIcmpArgs(char *, Stream5IcmpPolicy *); static void Stream5PrintIcmpConfig(Stream5IcmpPolicy *); static int ProcessIcmpUnreach(Packet *p); static int ProcessIcmpEcho(Packet *p); void Stream5InitIcmp(Stream5GlobalConfig *gconfig) { if (gconfig == NULL) return; /* Finally ICMP */ if((icmp_lws_cache == NULL) && gconfig->track_icmp_sessions) { icmp_lws_cache = InitLWSessionCache(gconfig->max_icmp_sessions, 30, 30, 5, 0, NULL); if(!icmp_lws_cache) { FatalError("Unable to init stream5 ICMP session cache, no ICMP " "stream inspection!\n"); } if (mempool_init(&icmp_session_mempool, gconfig->max_icmp_sessions, sizeof(IcmpSession)) != 0) { FatalError("%s(%d) Could not initialize icmp session memory pool.\n", __FILE__, __LINE__); } } } void Stream5IcmpPolicyInit(Stream5IcmpConfig *config, char *args) { if (config == NULL) return; config->num_policies++; Stream5ParseIcmpArgs(args, &config->default_policy); Stream5PrintIcmpConfig(&config->default_policy); } static void Stream5ParseIcmpArgs(char *args, Stream5IcmpPolicy *s5IcmpPolicy) { char **toks; int num_toks; int i; char **stoks = NULL; int s_toks; char *endPtr = NULL; s5IcmpPolicy->session_timeout = S5_DEFAULT_SSN_TIMEOUT; //s5IcmpPolicy->flags = 0; if(args != NULL && strlen(args) != 0) { toks = mSplit(args, ",", 0, &num_toks, 0); for (i = 0; i < num_toks; i++) { stoks = mSplit(toks[i], " ", 2, &s_toks, 0); if (s_toks == 0) { FatalError("%s(%d) => Missing parameter in Stream5 ICMP config.\n", file_name, file_line); } if(!strcasecmp(stoks[0], "timeout")) { if(stoks[1]) { s5IcmpPolicy->session_timeout = strtoul(stoks[1], &endPtr, 10); } if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid timeout in config file. Integer parameter required.\n", file_name, file_line); } if ((s5IcmpPolicy->session_timeout > S5_MAX_SSN_TIMEOUT) || (s5IcmpPolicy->session_timeout < S5_MIN_SSN_TIMEOUT)) { FatalError("%s(%d) => Invalid timeout in config file. " "Must be between %d and %d\n", file_name, file_line, S5_MIN_SSN_TIMEOUT, S5_MAX_SSN_TIMEOUT); } if (s_toks > 2) { FatalError("%s(%d) => Invalid Stream5 ICMP Policy option. Missing comma?\n", file_name, file_line); } } else { FatalError("%s(%d) => Invalid Stream5 ICMP policy option\n", file_name, file_line); } mSplitFree(&stoks, s_toks); } mSplitFree(&toks, num_toks); } } static void Stream5PrintIcmpConfig(Stream5IcmpPolicy *s5IcmpPolicy) { LogMessage("Stream5 ICMP Policy config:\n"); LogMessage(" Timeout: %d seconds\n", s5IcmpPolicy->session_timeout); //LogMessage(" Flags: 0x%X\n", s5UdpPolicy->flags); //IpAddrSetPrint(" Bound Addresses:", s5UdpPolicy->bound_addrs); } void IcmpSessionCleanup(Stream5LWSession *ssn) { IcmpSession *icmpssn = NULL; if (ssn->ha_state.session_flags & SSNFLAG_PRUNED) { CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED); } else if (ssn->ha_state.session_flags & SSNFLAG_TIMEDOUT) { CloseStreamSession(&sfBase, SESSION_CLOSED_TIMEDOUT); } else { CloseStreamSession(&sfBase, SESSION_CLOSED_NORMALLY); } if (ssn->proto_specific_data) icmpssn = ssn->proto_specific_data->data; if (!icmpssn) { /* Huh? */ return; } /* Cleanup the proto specific data */ mempool_free(&icmp_session_mempool, ssn->proto_specific_data); ssn->proto_specific_data = NULL; Stream5ResetFlowBits(ssn); FreeLWApplicationData(ssn); s5stats.icmp_sessions_released++; } uint32_t Stream5GetIcmpPrunes(void) { return icmp_lws_cache ? icmp_lws_cache->prunes : s5stats.icmp_prunes; } void Stream5ResetIcmpPrunes(void) { if ( icmp_lws_cache ) icmp_lws_cache->prunes = 0; } void Stream5ResetIcmp(void) { PurgeLWSessionCache(icmp_lws_cache); mempool_clean(&icmp_session_mempool); } void Stream5CleanIcmp(void) { if ( icmp_lws_cache ) s5stats.icmp_prunes = icmp_lws_cache->prunes; /* Clean up hash table -- delete all sessions */ DeleteLWSessionCache(icmp_lws_cache); icmp_lws_cache = NULL; mempool_destroy(&icmp_session_mempool); } void Stream5IcmpConfigFree(Stream5IcmpConfig *config) { if (config == NULL) return; free(config); } int Stream5VerifyIcmpConfig(Stream5IcmpConfig *config, tSfPolicyId policy_id) { if (config == NULL) return -1; if (!icmp_lws_cache) return -1; if (config->num_policies == 0) return -1; return 0; } int Stream5ProcessIcmp(Packet *p) { int status; switch (p->icmph->type) { case ICMP_DEST_UNREACH: status = ProcessIcmpUnreach(p); break; case ICMP_ECHO: case ICMP_ECHOREPLY: status = ProcessIcmpEcho(p); break; default: /* We only handle the above ICMP messages with stream5 */ status = 0; break; } return status; } static int ProcessIcmpUnreach(Packet *p) { /* Handle ICMP unreachable */ SessionKey skey; Stream5LWSession *ssn = NULL; uint16_t sport; uint16_t dport; sfip_t *src; sfip_t *dst; /* No "orig" IP Header */ if (!p->orig_iph) return 0; /* Get TCP/UDP/ICMP session from original protocol/port info * embedded in the ICMP Unreach message. This is already decoded * in p->orig_foo. TCP/UDP ports are decoded as p->orig_sp/dp. */ skey.protocol = GET_ORIG_IPH_PROTO(p); sport = p->orig_sp; dport = p->orig_dp; src = GET_ORIG_SRC(p); dst = GET_ORIG_DST(p); if (sfip_fast_lt6(src, dst)) { COPY4(skey.ip_l, src->ip32); skey.port_l = sport; COPY4(skey.ip_h, dst->ip32); skey.port_h = dport; } else if (IP_EQUALITY(GET_ORIG_SRC(p), GET_ORIG_DST(p))) { COPY4(skey.ip_l, src->ip32); COPY4(skey.ip_h, skey.ip_l); if (sport < dport) { skey.port_l = sport; skey.port_h = dport; } else { skey.port_l = dport; skey.port_h = sport; } } else { COPY4(skey.ip_l, dst->ip32); COPY4(skey.ip_h, src->ip32); skey.port_l = dport; skey.port_h = sport; } if (p->vh) skey.vlan_tag = (uint16_t)VTH_VLAN(p->vh); else skey.vlan_tag = 0; switch (skey.protocol) { case IPPROTO_TCP: /* Lookup a TCP session */ ssn = GetLWTcpSession(&skey); break; case IPPROTO_UDP: /* Lookup a UDP session */ ssn = GetLWUdpSession(&skey); break; case IPPROTO_ICMP: /* Lookup a ICMP session */ ssn = GetLWSessionFromKey(icmp_lws_cache, &skey); break; } if (ssn) { /* Mark this session as dead. */ DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Marking session as dead, per ICMP Unreachable!\n");); ssn->ha_state.session_flags |= SSNFLAG_DROP_CLIENT; ssn->ha_state.session_flags |= SSNFLAG_DROP_SERVER; ssn->session_state |= STREAM5_STATE_UNREACH; } return 0; } static int ProcessIcmpEcho(Packet *p) { //SessionKey skey; //Stream5LWSession *ssn = NULL; return 0; } void IcmpUpdateDirection(Stream5LWSession *ssn, char dir, snort_ip_p ip, uint16_t port) { IcmpSession *icmpssn = ssn->proto_specific_data->data; snort_ip tmpIp; if (!icmpssn) { /* Huh? */ return; } if (IP_EQUALITY(&icmpssn->icmp_sender_ip, ip)) { if ((dir == SSN_DIR_FROM_SENDER) && (ssn->ha_state.direction == SSN_DIR_FROM_SENDER)) { /* Direction already set as SENDER */ return; } } else if (IP_EQUALITY(&icmpssn->icmp_responder_ip, ip)) { if ((dir == SSN_DIR_FROM_RESPONDER) && (ssn->ha_state.direction == SSN_DIR_FROM_RESPONDER)) { /* Direction already set as RESPONDER */ return; } } /* Swap them -- leave ssn->ha_state.direction the same */ tmpIp = icmpssn->icmp_sender_ip; icmpssn->icmp_sender_ip = icmpssn->icmp_responder_ip; icmpssn->icmp_responder_ip = tmpIp; } snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_udp.h0000644000000000000000000000451412260565733020605 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifndef STREAM5_UDP_H_ #define STREAM5_UDP_H_ #include "ipv6_port.h" #include "stream5_common.h" #include "sfPolicy.h" void Stream5CleanUdp(void); void Stream5ResetUdp(void); void Stream5InitUdp(Stream5GlobalConfig *); void Stream5UdpPolicyInit(Stream5UdpConfig *, char *); int Stream5VerifyUdpConfig(struct _SnortConfig *, Stream5UdpConfig *, tSfPolicyId); int Stream5ProcessUdp(Packet *, Stream5LWSession *, Stream5UdpPolicy *, SessionKey *); void UdpUpdateDirection(Stream5LWSession *ssn, char dir, snort_ip_p ip, uint16_t port); Stream5LWSession *GetLWUdpSession(const SessionKey *key); void s5UdpSetPortFilterStatus( struct _SnortConfig *sc, unsigned short port, uint16_t status, tSfPolicyId policyId, int parsing ); void s5UdpUnsetPortFilterStatus( struct _SnortConfig *sc, unsigned short port, uint16_t status, tSfPolicyId policyId, int parsing ); int s5UdpGetPortFilterStatus( struct _SnortConfig *sc, unsigned short port, tSfPolicyId policyId, int parsing ); void Stream5UdpConfigFree(Stream5UdpConfig *); uint32_t Stream5GetUdpPrunes(void); void Stream5ResetUdpPrunes(void); void UdpSessionCleanup(Stream5LWSession *lwssn); #endif /* STREAM5_UDP_H_ */ snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_udp.c0000644000000000000000000006256012260565733020605 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sf_types.h" #include "snort_debug.h" #include "detect.h" #include "plugbase.h" #include "mstring.h" #include "sfxhash.h" #include "util.h" #include "decode.h" #include "stream5_common.h" #include "stream_api.h" #include "snort_stream5_session.h" #include "stream_expect.h" #include "snort_stream5_udp.h" #include "plugin_enum.h" #include "rules.h" #include "treenodes.h" #include "snort.h" #include "active.h" #include "portscan.h" /* To know when to create sessions for all UDP */ #include "dynamic-plugins/sp_dynamic.h" #include "profiler.h" #include "sfPolicy.h" #include "stream5_ha.h" #ifdef PERF_PROFILING PreprocStats s5UdpPerfStats; #endif /* M A C R O S **************************************************/ /* actions */ #define ACTION_NOTHING 0x00000000 /* sender/responder ip/port dereference */ #define udp_sender_ip lwSsn->client_ip #define udp_sender_port lwSsn->client_port #define udp_responder_ip lwSsn->server_ip #define udp_responder_port lwSsn->server_port /* D A T A S T R U C T U R E S ***********************************/ typedef struct _UdpSession { Stream5LWSession *lwSsn; struct timeval ssn_time; //uint8_t c_ttl; //uint8_t s_ttl; } UdpSession; /* G L O B A L S **************************************************/ Stream5SessionCache *udp_lws_cache = NULL; static MemPool udp_session_mempool; /* P R O T O T Y P E S ********************************************/ static void Stream5ParseUdpArgs(Stream5UdpConfig *, char *, Stream5UdpPolicy *); static void Stream5PrintUdpConfig(Stream5UdpPolicy *); static int ProcessUdp(Stream5LWSession *, Packet *, Stream5UdpPolicy *, SFXHASH_NODE *); //------------------------------------------------------------------------- // udp ha stuff // TBD there may be some refactoring possible once tcp, icmp, and udp // are complete static Stream5LWSession *Stream5UDPCreateSession(const SessionKey *key) { setRuntimePolicy(getDefaultPolicy()); return NewLWSession(udp_lws_cache, NULL, key, NULL); } static int Stream5UDPDeleteSession(const SessionKey *key) { Stream5LWSession *lwssn = GetLWSessionFromKey(udp_lws_cache, key); if ( lwssn && !Stream5SetRuntimeConfiguration(lwssn, lwssn->protocol) ) DeleteLWSession(udp_lws_cache, lwssn, "ha sync"); return 0; } #ifdef ENABLE_HA static HA_Api ha_udp_api = { /*.get_lws = */ GetLWUdpSession, /*.create_session = */ Stream5UDPCreateSession, /*.deactivate_session = */ NULL, /*.delete_session = */ Stream5UDPDeleteSession, }; #endif //------------------------------------------------------------------------- void Stream5InitUdp(Stream5GlobalConfig *gconfig) { if (gconfig == NULL) return; /* Now UDP */ if ((udp_lws_cache == NULL) && (gconfig->track_udp_sessions)) { udp_lws_cache = InitLWSessionCache(gconfig->max_udp_sessions, gconfig->udp_cache_pruning_timeout, gconfig->udp_cache_nominal_timeout, 5, 0, &UdpSessionCleanup); if(!udp_lws_cache) { FatalError("Unable to init stream5 UDP session cache, no UDP " "stream inspection!\n"); } if (mempool_init(&udp_session_mempool, gconfig->max_udp_sessions, sizeof(UdpSession)) != 0) { FatalError("%s(%d) Could not initialize udp session memory pool.\n", __FILE__, __LINE__); } } #ifdef ENABLE_HA ha_set_api(IPPROTO_UDP, &ha_udp_api); #endif } void Stream5UdpPolicyInit(Stream5UdpConfig *config, char *args) { Stream5UdpPolicy *s5UdpPolicy; if (config == NULL) return; s5UdpPolicy = (Stream5UdpPolicy *)SnortAlloc(sizeof(Stream5UdpPolicy)); Stream5ParseUdpArgs(config, args, s5UdpPolicy); config->num_policies++; /* Now add this context to the internal list */ if (config->policy_list == NULL) { config->policy_list = (Stream5UdpPolicy **)SnortAlloc(sizeof(Stream5UdpPolicy *)); } else { Stream5UdpPolicy **tmpPolicyList = (Stream5UdpPolicy **)SnortAlloc(sizeof(Stream5UdpPolicy *) * config->num_policies); memcpy(tmpPolicyList, config->policy_list, sizeof(Stream5UdpPolicy *) * (config->num_policies - 1)); free(config->policy_list); config->policy_list = tmpPolicyList; } config->policy_list[config->num_policies - 1] = s5UdpPolicy; Stream5PrintUdpConfig(s5UdpPolicy); #ifdef REG_TEST LogMessage(" UDP Session Size: %lu\n",sizeof(UdpSession)); #endif } static void Stream5ParseUdpArgs(Stream5UdpConfig *config, char *args, Stream5UdpPolicy *s5UdpPolicy) { char **toks; int num_toks; int i; char *index; char **stoks = NULL; int s_toks; char *endPtr = NULL; if (s5UdpPolicy == NULL) return; s5UdpPolicy->session_timeout = S5_DEFAULT_SSN_TIMEOUT; s5UdpPolicy->flags = 0; if(args != NULL && strlen(args) != 0) { toks = mSplit(args, ",", 6, &num_toks, 0); i=0; while(i < num_toks) { index = toks[i]; while(isspace((int)*index)) index++; stoks = mSplit(index, " ", 3, &s_toks, 0); if (s_toks == 0) { FatalError("%s(%d) => Missing parameter in Stream5 UDP config.\n", file_name, file_line); } if(!strcasecmp(stoks[0], "timeout")) { if(stoks[1]) { s5UdpPolicy->session_timeout = strtoul(stoks[1], &endPtr, 10); } if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid timeout in config file. Integer parameter required.\n", file_name, file_line); } if ((s5UdpPolicy->session_timeout > S5_MAX_SSN_TIMEOUT) || (s5UdpPolicy->session_timeout < S5_MIN_SSN_TIMEOUT)) { FatalError("%s(%d) => Invalid timeout in config file. " "Must be between %d and %d\n", file_name, file_line, S5_MIN_SSN_TIMEOUT, S5_MAX_SSN_TIMEOUT); } if (s_toks > 2) { FatalError("%s(%d) => Invalid Stream5 UDP Policy option. Missing comma?\n", file_name, file_line); } } else if (!strcasecmp(stoks[0], "ignore_any_rules")) { s5UdpPolicy->flags |= STREAM5_CONFIG_IGNORE_ANY; if (s_toks > 1) { FatalError("%s(%d) => Invalid Stream5 UDP Policy option. Missing comma?\n", file_name, file_line); } } else { FatalError("%s(%d) => Invalid Stream5 UDP Policy option\n", file_name, file_line); } mSplitFree(&stoks, s_toks); i++; } mSplitFree(&toks, num_toks); } if (s5UdpPolicy->bound_addrs == NULL) { if (config->default_policy != NULL) { FatalError("%s(%d) => Default Stream5 UDP Policy already set. " "This policy must be bound to a specific host or " "network.\n", file_name, file_line); } config->default_policy = s5UdpPolicy; } else { if (s5UdpPolicy->flags & STREAM5_CONFIG_IGNORE_ANY) { FatalError("%s(%d) => \"ignore_any_rules\" option can be used only" " with Default Stream5 UDP Policy\n", file_name, file_line); } } } static void Stream5PrintUdpConfig(Stream5UdpPolicy *s5UdpPolicy) { LogMessage("Stream5 UDP Policy config:\n"); LogMessage(" Timeout: %d seconds\n", s5UdpPolicy->session_timeout); if (s5UdpPolicy->flags) { LogMessage(" Options:\n"); if (s5UdpPolicy->flags & STREAM5_CONFIG_IGNORE_ANY) { LogMessage(" Ignore Any -> Any Rules: YES\n"); } } //IpAddrSetPrint(" Bound Addresses:", s5UdpPolicy->bound_addrs); } int Stream5VerifyUdpConfig(struct _SnortConfig *sc, Stream5UdpConfig *config, tSfPolicyId policyId) { if (config == NULL) return -1; if (!udp_lws_cache) return -1; if (config->num_policies == 0) return -1; /* Post-process UDP rules to establish UDP ports to inspect. */ setPortFilterList(sc, config->port_filter, IPPROTO_UDP, (config->default_policy->flags & STREAM5_CONFIG_IGNORE_ANY), policyId); //printf ("UDP Ports with Inspection/Monitoring\n"); //s5PrintPortFilter(config->port_filter); return 0; } #ifdef DEBUG_STREAM5 static void PrintUdpSession(UdpSession *us) { LogMessage("UdpSession:\n"); LogMessage(" ssn_time: %lu\n", us->ssn_time.tv_sec); LogMessage(" sender IP: 0x%08X\n", us->udp_sender_ip); LogMessage(" responder IP: 0x%08X\n", us->udp_responder_ip); LogMessage(" sender port: %d\n", us->udp_sender_port); LogMessage(" responder port: %d\n", us->udp_responder_port); LogMessage(" flags: 0x%X\n", us->lwSsn->session_flags); } #endif Stream5LWSession *GetLWUdpSession(const SessionKey *key) { return GetLWSessionFromKey(udp_lws_cache, key); } void UdpSessionCleanup(Stream5LWSession *lwssn) { UdpSession *udpssn = NULL; if (lwssn->ha_state.session_flags & SSNFLAG_PRUNED) { CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED); } else if (lwssn->ha_state.session_flags & SSNFLAG_TIMEDOUT) { CloseStreamSession(&sfBase, SESSION_CLOSED_TIMEDOUT); } else { CloseStreamSession(&sfBase, SESSION_CLOSED_NORMALLY); } if (lwssn->proto_specific_data) udpssn = (UdpSession *)lwssn->proto_specific_data->data; if (!udpssn) { /* Huh? */ return; } /* Cleanup the proto specific data */ mempool_free(&udp_session_mempool, lwssn->proto_specific_data); lwssn->proto_specific_data = NULL; lwssn->session_state = STREAM5_STATE_NONE; lwssn->ha_state.session_flags = SSNFLAG_NONE; lwssn->expire_time = 0; lwssn->ha_state.ignore_direction = 0; Stream5ResetFlowBits(lwssn); FreeLWApplicationData(lwssn); s5stats.udp_sessions_released++; RemoveUDPSession(&sfBase); } uint32_t Stream5GetUdpPrunes(void) { return udp_lws_cache ? udp_lws_cache->prunes : s5stats.udp_prunes; } void Stream5ResetUdpPrunes(void) { if ( udp_lws_cache ) udp_lws_cache->prunes = 0; } void Stream5ResetUdp(void) { PurgeLWSessionCache(udp_lws_cache); mempool_clean(&udp_session_mempool); } void Stream5CleanUdp(void) { if ( udp_lws_cache ) s5stats.udp_prunes = udp_lws_cache->prunes; /* Clean up hash table -- delete all sessions */ DeleteLWSessionCache(udp_lws_cache); udp_lws_cache = NULL; mempool_destroy(&udp_session_mempool); } static int NewUdpSession(Packet *p, Stream5LWSession *lwssn, Stream5UdpPolicy *s5UdpPolicy) { UdpSession *tmp; MemBucket *tmpBucket; /****************************************************************** * create new sessions *****************************************************************/ tmpBucket = mempool_alloc(&udp_session_mempool); if (tmpBucket == NULL) return -1; tmp = tmpBucket->data; DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker!\n");); tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec; tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec; lwssn->ha_state.session_flags |= SSNFLAG_SEEN_SENDER; DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "adding UdpSession to lightweight session\n");); lwssn->proto_specific_data = tmpBucket; lwssn->protocol = GET_IPH_PROTO(p); lwssn->ha_state.direction = FROM_SENDER; tmp->lwSsn = lwssn; #ifdef DEBUG_STREAM5 PrintUdpSession(tmp); #endif Stream5SetExpire(p, lwssn, s5UdpPolicy->session_timeout); s5stats.udp_sessions_created++; AddUDPSession(&sfBase); if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP)) UpdateFlowIPState(&sfFlow, IP_ARG(lwssn->client_ip), IP_ARG(lwssn->server_ip), SFS_STATE_UDP_CREATED); return 0; } //------------------------------------------------------------------------- /* * Main entry point for UDP */ int Stream5ProcessUdp(Packet *p, Stream5LWSession *lwssn, Stream5UdpPolicy *s5UdpPolicy, SessionKey *skey) { SFXHASH_NODE *hash_node = NULL; PROFILE_VARS; // XXX-IPv6 Stream5ProcessUDP debugging PREPROC_PROFILE_START(s5UdpPerfStats); if (s5UdpPolicy == NULL) { int policyIndex; /* Find an Udp policy for this packet */ for (policyIndex = 0; policyIndex < s5_udp_eval_config->num_policies; policyIndex++) { s5UdpPolicy = s5_udp_eval_config->policy_list[policyIndex]; if (s5UdpPolicy->bound_addrs == NULL) continue; /* * Does this policy handle packets to this IP address? */ if(sfvar_ip_in(s5UdpPolicy->bound_addrs, GET_DST_IP(p))) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[Stream5] Found udp policy in IpAddrSet\n");); break; } } if (policyIndex == s5_udp_eval_config->num_policies) s5UdpPolicy = s5_udp_eval_config->default_policy; if (!s5UdpPolicy) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[Stream5] Could not find Udp Policy context " "for IP %s\n", inet_ntoa(GET_DST_ADDR(p)));); PREPROC_PROFILE_END(s5UdpPerfStats); return 0; } /* If this is an existing LWSession that didn't have its policy set, set it now to save time in the future. */ if (lwssn != NULL && lwssn->policy == NULL) lwssn->policy = s5UdpPolicy; } /* UDP Sessions required */ if (lwssn == NULL) { if ((isPacketFilterDiscard(p, s5UdpPolicy->flags & STREAM5_CONFIG_IGNORE_ANY) == PORT_MONITOR_PACKET_DISCARD) && !StreamExpectIsExpected(p, &hash_node)) { //ignore the packet UpdateFilteredPacketStats(&sfBase, IPPROTO_UDP); PREPROC_PROFILE_END(s5UdpPerfStats); return 0; } /* Create a new session, mark SENDER seen */ lwssn = NewLWSession(udp_lws_cache, p, skey, (void *)s5UdpPolicy); s5stats.total_udp_sessions++; } else { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Retrieved existing session object.\n");); } if (!lwssn) { LogMessage("Stream5: Failed to retrieve session object. Out of memory?\n"); PREPROC_PROFILE_END(s5UdpPerfStats); return -1; } p->ssnptr = lwssn; /* * Check if the session is expired. * Should be done before we do something with the packet... * ie, Insert a packet, or handle state change SYN, FIN, RST, etc. */ if ((lwssn->session_state & STREAM5_STATE_TIMEDOUT) || Stream5Expire(p, lwssn)) { lwssn->ha_state.session_flags |= SSNFLAG_TIMEDOUT; /* Session is timed out */ DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5 UDP session timedout!\n");); #ifdef ENABLE_HA /* Notify the HA peer of the session cleanup/reset by way of a deletion notification. */ PREPROC_PROFILE_TMPEND(s5UdpPerfStats); Stream5HANotifyDeletion(lwssn); PREPROC_PROFILE_TMPSTART(s5UdpPerfStats); lwssn->ha_flags = (HA_FLAG_NEW | HA_FLAG_MODIFIED | HA_FLAG_MAJOR_CHANGE); #endif /* Clean it up */ UdpSessionCleanup(lwssn); ProcessUdp(lwssn, p, s5UdpPolicy, hash_node); } else { ProcessUdp(lwssn, p, s5UdpPolicy, hash_node); DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Finished Stream5 UDP cleanly!\n" "---------------------------------------------------\n");); } MarkupPacketFlags(p, lwssn); Stream5SetExpire(p, lwssn, s5UdpPolicy->session_timeout); PREPROC_PROFILE_END(s5UdpPerfStats); return 0; } static int ProcessUdp(Stream5LWSession *lwssn, Packet *p, Stream5UdpPolicy *s5UdpPolicy, SFXHASH_NODE *hash_node) { char ignore; UdpSession *udpssn = NULL; if (lwssn->protocol != IPPROTO_UDP) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Lightweight session not UDP on UDP packet\n");); return ACTION_NOTHING; } if (lwssn->ha_state.session_flags & (SSNFLAG_DROP_CLIENT|SSNFLAG_DROP_SERVER)) { /* Got a packet on a session that was dropped (by a rule). */ GetLWPacketDirection(p, lwssn); /* Drop this packet */ if (((p->packet_flags & PKT_FROM_SERVER) && (lwssn->ha_state.session_flags & SSNFLAG_DROP_SERVER)) || ((p->packet_flags & PKT_FROM_CLIENT) && (lwssn->ha_state.session_flags & SSNFLAG_DROP_CLIENT))) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Blocking %s packet as session was blocked\n", p->packet_flags & PKT_FROM_SERVER ? "server" : "client");); DisableDetect(p); /* Still want to add this number of bytes to totals */ SetPreprocBit(p, PP_PERFMONITOR); if ( lwssn->ha_state.session_flags & SSNFLAG_FORCE_BLOCK ) Active_ForceDropPacket(); else Active_DropPacket(p); #ifdef ACTIVE_RESPONSE Stream5ActiveResponse(p, lwssn); #endif return ACTION_NOTHING; } } if (lwssn->proto_specific_data != NULL) udpssn = (UdpSession *)lwssn->proto_specific_data->data; if (udpssn == NULL) { lwssn->ha_state.direction = FROM_SENDER; IP_COPY_VALUE(lwssn->client_ip, GET_SRC_IP(p)); lwssn->client_port = p->udph->uh_sport; IP_COPY_VALUE(lwssn->server_ip, GET_DST_IP(p)); lwssn->server_port = p->udph->uh_dport; if (NewUdpSession(p, lwssn, s5UdpPolicy) == -1) return ACTION_NOTHING; udpssn = (UdpSession *)lwssn->proto_specific_data->data; /* Check if the session is to be ignored */ if (hash_node) ignore = StreamExpectProcessNode(p, lwssn, hash_node); else ignore = StreamExpectCheck(p, lwssn); if (ignore) { /* Set the directions to ignore... */ lwssn->ha_state.ignore_direction = ignore; DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Ignoring packet from %d. " "Marking session marked as ignore.\n", p->packet_flags & PKT_FROM_CLIENT? "sender" : "responder");); Stream5DisableInspection(lwssn, p); return ACTION_NOTHING; } } /* figure out direction of this packet */ GetLWPacketDirection(p, lwssn); if (((p->packet_flags & PKT_FROM_SERVER) && (lwssn->ha_state.ignore_direction & SSN_DIR_FROM_CLIENT)) || ((p->packet_flags & PKT_FROM_CLIENT) && (lwssn->ha_state.ignore_direction & SSN_DIR_FROM_SERVER))) { Stream5DisableInspection(lwssn, p); DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5 Ignoring packet from %d. " "Session marked as ignore\n", p->packet_flags & PKT_FROM_CLIENT? "sender" : "responder");); return ACTION_NOTHING; } /* if both seen, mark established */ if(p->packet_flags & PKT_FROM_SERVER) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Updating on packet from responder\n");); lwssn->ha_state.session_flags |= SSNFLAG_SEEN_RESPONDER; #ifdef ACTIVE_RESPONSE SetTTL(lwssn, p, 0); #endif } else { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Updating on packet from client\n");); /* if we got here we had to see the SYN already... */ lwssn->ha_state.session_flags |= SSNFLAG_SEEN_SENDER; #ifdef ACTIVE_RESPONSE SetTTL(lwssn, p, 1); #endif } if (!(lwssn->ha_state.session_flags & SSNFLAG_ESTABLISHED)) { if ((lwssn->ha_state.session_flags & SSNFLAG_SEEN_SENDER) && (lwssn->ha_state.session_flags & SSNFLAG_SEEN_RESPONDER)) { lwssn->ha_state.session_flags |= SSNFLAG_ESTABLISHED; } } return ACTION_NOTHING; } void UdpUpdateDirection(Stream5LWSession *ssn, char dir, snort_ip_p ip, uint16_t port) { UdpSession *udpssn = (UdpSession *)ssn->proto_specific_data->data; snort_ip tmpIp; uint16_t tmpPort; if (IP_EQUALITY(&udpssn->udp_sender_ip, ip) && (udpssn->udp_sender_port == port)) { if ((dir == SSN_DIR_FROM_SENDER) && (ssn->ha_state.direction == SSN_DIR_FROM_SENDER)) { /* Direction already set as SENDER */ return; } } else if (IP_EQUALITY(&udpssn->udp_responder_ip, ip) && (udpssn->udp_responder_port == port)) { if ((dir == SSN_DIR_FROM_RESPONDER) && (ssn->ha_state.direction == SSN_DIR_FROM_RESPONDER)) { /* Direction already set as RESPONDER */ return; } } /* Swap them -- leave ssn->ha_state.direction the same */ tmpIp = udpssn->udp_sender_ip; tmpPort = udpssn->udp_sender_port; udpssn->udp_sender_ip = udpssn->udp_responder_ip; udpssn->udp_sender_port = udpssn->udp_responder_port; udpssn->udp_responder_ip = tmpIp; udpssn->udp_responder_port = tmpPort; } void s5UdpSetPortFilterStatus(struct _SnortConfig *sc, unsigned short port, uint16_t status, tSfPolicyId policyId, int parsing) { Stream5Config *config; Stream5UdpConfig *udp_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; if (parsing && ((s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc)) != NULL)) config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policyId); else #endif config = (Stream5Config *)sfPolicyUserDataGet(s5_config, policyId); if (config == NULL) return; udp_config = config->udp_config; if (udp_config == NULL) return; udp_config->port_filter[port] |= status; } void s5UdpUnsetPortFilterStatus(struct _SnortConfig *sc, unsigned short port, uint16_t status, tSfPolicyId policyId, int parsing) { Stream5Config *config; Stream5UdpConfig *udp_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; if (parsing && ((s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc)) != NULL)) config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policyId); else #endif config = (Stream5Config *)sfPolicyUserDataGet(s5_config, policyId); if (config == NULL) return; udp_config = config->udp_config; if (udp_config == NULL) return; udp_config->port_filter[port] &= ~status; } int s5UdpGetPortFilterStatus(struct _SnortConfig *sc, unsigned short port, tSfPolicyId policyId, int parsing) { Stream5Config *config; Stream5UdpConfig *udp_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; if (parsing && ((s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc)) != NULL)) config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policyId); else #endif config = (Stream5Config *)sfPolicyUserDataGet(s5_config, policyId); if (config == NULL) return PORT_MONITOR_NONE; udp_config = config->udp_config; if (udp_config == NULL) return PORT_MONITOR_NONE; return (int)udp_config->port_filter[port]; } void Stream5UdpConfigFree(Stream5UdpConfig *config) { int i; if (config == NULL) return; /* Cleanup TCP Policies and the list */ for (i = 0; i < config->num_policies; i++) { Stream5UdpPolicy *policy = config->policy_list[i]; if (policy->bound_addrs != NULL) sfvar_free(policy->bound_addrs); free(policy); } free(config->policy_list); free(config); } snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_tcp.h0000644000000000000000000001132112260565733020575 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ #ifndef STREAM5_TCP_H_ #define STREAM5_TCP_H_ #include "stream5_common.h" #include "sfPolicy.h" extern uint32_t xtradata_func_count; extern LogFunction xtradata_map[LOG_FUNC_MAX]; extern LogExtraData extra_data_log; extern void *extra_data_config; void Stream5CleanTcp(void); void Stream5ResetTcp(void); void Stream5InitTcp(Stream5GlobalConfig *); void Stream5TcpRegisterPreprocProfiles(void); void Stream5TcpRegisterRuleOptions(struct _SnortConfig *); void Stream5TcpInitFlushPoints(void); int Stream5VerifyTcpConfig(struct _SnortConfig *, Stream5TcpConfig *, tSfPolicyId); void Stream5TcpPolicyInit(struct _SnortConfig *, Stream5TcpConfig *, char *); int Stream5ProcessTcp(Packet *, Stream5LWSession *, Stream5TcpPolicy *, SessionKey *); int Stream5FlushListener(Packet *p, Stream5LWSession *lwssn); int Stream5FlushTalker(Packet *p, Stream5LWSession *lwssn); int Stream5FlushClient(Packet *p, Stream5LWSession *lwssn); int Stream5FlushServer(Packet *p, Stream5LWSession *lwssn); void TcpUpdateDirection(Stream5LWSession *ssn, char dir, snort_ip_p ip, uint16_t port); void Stream5TcpSessionClear(Packet *p); Stream5LWSession *GetLWTcpSession(const SessionKey *key); int GetTcpRebuiltPackets(Packet *p, Stream5LWSession *ssn, PacketIterator callback, void *userdata); int GetTcpStreamSegments(Packet *p, Stream5LWSession *ssn, StreamSegmentIterator callback, void *userdata); int Stream5AddSessionAlertTcp(Stream5LWSession *lwssn, Packet *p, uint32_t gid, uint32_t sid); int Stream5CheckSessionAlertTcp(Stream5LWSession *lwssn, Packet *p, uint32_t gid, uint32_t sid); int Stream5UpdateSessionAlertTcp(Stream5LWSession *lwssn, Packet *p, uint32_t gid, uint32_t sid, uint32_t event_id, uint32_t event_second); void Stream5SetExtraDataTcp(Stream5LWSession*, Packet*, uint32_t flag); void Stream5ClearExtraDataTcp(Stream5LWSession*, Packet*, uint32_t flag); char Stream5GetReassemblyDirectionTcp(Stream5LWSession *lwssn); uint32_t Stream5GetFlushPointTcp(Stream5LWSession *lwssn, char dir); void Stream5SetFlushPointTcp(Stream5LWSession *lwssn, char dir, uint32_t flush_point); char Stream5SetReassemblyTcp(Stream5LWSession *lwssn, uint8_t flush_policy, char dir, char flags); char Stream5GetReassemblyFlushPolicyTcp(Stream5LWSession *lwssn, char dir); char Stream5IsStreamSequencedTcp(Stream5LWSession *lwssn, char dir); int Stream5MissingInReassembledTcp(Stream5LWSession *lwssn, char dir); char Stream5PacketsMissingTcp(Stream5LWSession *lwssn, char dir); void s5TcpSetPortFilterStatus( struct _SnortConfig *sc, unsigned short port, uint16_t status, tSfPolicyId policyId, int parsing ); void s5TcpUnsetPortFilterStatus( struct _SnortConfig *sc, unsigned short port, uint16_t status, tSfPolicyId policyId, int parsing ); int s5TcpGetPortFilterStatus( struct _SnortConfig *sc, unsigned short port, tSfPolicyId policyId, int parsing ); void s5TcpSetSynSessionStatus(struct _SnortConfig *sc, uint16_t status, tSfPolicyId policyId, int parsing); void s5TcpUnsetSynSessionStatus(struct _SnortConfig *sc, uint16_t status, tSfPolicyId policyId, int parsing); void Stream5TcpConfigFree(Stream5TcpConfig *); void** Stream5GetPAFUserDataTcp(Stream5LWSession*, bool to_server); bool Stream5IsPafActiveTcp(Stream5LWSession*, bool to_server); bool Stream5ActivatePafTcp(Stream5LWSession*, bool to_server); uint32_t Stream5GetTcpPrunes(void); void Stream5ResetTcpPrunes(void); #ifdef NORMALIZER void Stream_PrintNormalizationStats(void); void Stream_ResetNormalizationStats(void); #endif void Stream5PostConfigTcp(struct _SnortConfig *, void*); #endif /* STREAM5_TCP_H_ */ snort-2.9.6.0/src/preprocessors/Stream5/snort_stream5_tcp.c0000644000000000000000000125255212260565733020606 00000000000000/* $Id$ */ /**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2005-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /** * @file snort_stream5_tcp.c * @author Martin Roesch * @author Steven Sturges * */ /* * TODOs: * - midstream ssn pickup (done, SAS 10/14/2005) * - syn flood protection (done, SAS 9/27/2005) * * - review policy anomaly detection * + URG pointer (TODO) * + data on SYN (done, SAS 10/12/2005) * + data on FIN (done, SAS 10/12/2005) * + data after FIN (done, SAS 10/13/2005) * + window scaling/window size max (done, SAS 10/13/2005) * + PAWS, TCP Timestamps (done, SAS 10/12/2005) * * - session shutdown/Reset handling (done, SAS) * - flush policy for Window/Consumed * - limit on number of overlapping packets (done, SAS) */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "perf.h" #include "sf_types.h" #include "snort_debug.h" #include "detect.h" #include "plugbase.h" #include "mstring.h" #include "sfxhash.h" #include "util.h" #include "sflsq.h" #include "snort_bounds.h" #include "generators.h" #include "event_queue.h" #include "snort.h" #include "parser/IpAddrSet.h" #include "decode.h" #include "encode.h" #include "log.h" #include "active.h" #include "spp_normalize.h" #include "stream5_common.h" #include "snort_stream5_tcp.h" #include "stream_api.h" #include "snort_stream5_session.h" #include "stream_expect.h" #include "stream5_paf.h" #include "stream5_ha.h" #ifdef TARGET_BASED #include "sftarget_protocol_reference.h" #include "sftarget_hostentry.h" #endif #include "profiler.h" #include "ipv6_port.h" #include "sf_iph.h" #include "sp_preprocopt.h" #include "sfPolicy.h" #include "sfActionQueue.h" #include "detection_util.h" #include "file_api.h" #ifdef PERF_PROFILING PreprocStats s5TcpPerfStats; PreprocStats s5TcpNewSessPerfStats; PreprocStats s5TcpStatePerfStats; PreprocStats s5TcpDataPerfStats; PreprocStats s5TcpInsertPerfStats; PreprocStats s5TcpPAFPerfStats; PreprocStats s5TcpFlushPerfStats; PreprocStats s5TcpBuildPacketPerfStats; PreprocStats s5TcpProcessRebuiltPerfStats; PreprocStats streamSizePerfStats; PreprocStats streamReassembleRuleOptionPerfStats; extern PreprocStats preprocRuleOptionPerfStats; #endif /* M A C R O S **************************************************/ /* TCP flags */ #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 #define TH_ECE 0x40 #define TH_CWR 0x80 #define TH_NORESERVED (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) /* TCP states */ #define TCP_STATE_NONE 0 #define TCP_STATE_LISTEN 1 #define TCP_STATE_SYN_RCVD 2 #define TCP_STATE_SYN_SENT 3 #define TCP_STATE_ESTABLISHED 4 #define TCP_STATE_CLOSE_WAIT 5 #define TCP_STATE_LAST_ACK 6 #define TCP_STATE_FIN_WAIT_1 7 #define TCP_STATE_CLOSING 8 #define TCP_STATE_FIN_WAIT_2 9 #define TCP_STATE_TIME_WAIT 10 #define TCP_STATE_CLOSED 11 #ifndef MIN # define MIN(a,b) (((a)<(b)) ? (a):(b)) #endif #ifndef MAX # define MAX(a,b) (((a)>(b)) ? (a):(b)) #endif #define PAWS_WINDOW 60 #define PAWS_24DAYS 2073600 /* 24 days in seconds */ /* for state transition queuing */ #define CHK_SEQ 0 #define NO_CHK_SEQ 1 #define S5_UNALIGNED 0 #define S5_ALIGNED 1 /* actions */ #define ACTION_NOTHING 0x00000000 #define ACTION_FLUSH_SENDER_STREAM 0x00000001 #define ACTION_FLUSH_RECEIVER_STREAM 0x00000002 #define ACTION_DROP_SESSION 0x00000004 #define ACTION_ACK_SENDER_DATA 0x00000008 #define ACTION_ACK_RECEIVER_DATA 0x00000010 #define ACTION_SET_SSN 0x00000040 #define ACTION_COMPLETE_TWH 0x00000080 #define ACTION_RST 0x00000100 #define ACTION_BAD_SEQ 0x00000200 #define ACTION_BAD_PKT 0x00000400 #define ACTION_LWSSN_CLOSED 0x00000800 #define ACTION_DISABLE_INSPECTION 0x00001000 /* events */ #define EVENT_SYN_ON_EST 0x00000001 #define EVENT_DATA_ON_SYN 0x00000002 #define EVENT_DATA_ON_CLOSED 0x00000004 #define EVENT_BAD_TIMESTAMP 0x00000008 #define EVENT_BAD_SEGMENT 0x00000010 #define EVENT_WINDOW_TOO_LARGE 0x00000020 #define EVENT_EXCESSIVE_TCP_OVERLAPS 0x00000040 #define EVENT_DATA_AFTER_RESET 0x00000080 #define EVENT_SESSION_HIJACK_CLIENT 0x00000100 #define EVENT_SESSION_HIJACK_SERVER 0x00000200 #define EVENT_DATA_WITHOUT_FLAGS 0x00000400 #define EVENT_4WHS 0x00000800 #define EVENT_NO_TIMESTAMP 0x00001000 #define EVENT_BAD_RST 0x00002000 #define EVENT_BAD_FIN 0x00004000 #define EVENT_BAD_ACK 0x00008000 #define EVENT_DATA_AFTER_RST_RCVD 0x00010000 #define EVENT_WINDOW_SLAM 0x00020000 #define TF_NONE 0x0000 #define TF_WSCALE 0x0001 #define TF_TSTAMP 0x0002 #define TF_TSTAMP_ZERO 0x0004 #define TF_MSS 0x0008 #define TF_FORCE_FLUSH 0x0010 #define TF_PKT_MISSED 0x0020 // sticky #define TF_MISSING_PKT 0x0040 // used internally #define TF_MISSING_PREV_PKT 0x0080 // reset for each reassembled #define TF_FIRST_PKT_MISSING 0x0100 #define TF_ALL 0xFFFF #define STREAM_INSERT_OK 0 #define STREAM_INSERT_ANOMALY 1 #define STREAM_INSERT_TIMEOUT 2 #define STREAM_INSERT_FAILED 3 #define S5_DEFAULT_TCP_PACKET_MEMCAP 8388608 /* 8MB */ #define S5_MIN_OVERLAP_LIMIT 0 #define S5_MAX_OVERLAP_LIMIT 255 #define S5_MAX_FLUSH_FACTOR 2048 #define REASSEMBLY_POLICY_FIRST 1 #define REASSEMBLY_POLICY_LINUX 2 #define REASSEMBLY_POLICY_BSD 3 #define REASSEMBLY_POLICY_OLD_LINUX 4 #define REASSEMBLY_POLICY_LAST 5 #define REASSEMBLY_POLICY_WINDOWS 6 #define REASSEMBLY_POLICY_SOLARIS 7 #define REASSEMBLY_POLICY_HPUX11 8 #define REASSEMBLY_POLICY_IRIX 9 #define REASSEMBLY_POLICY_MACOS 10 #define REASSEMBLY_POLICY_HPUX10 11 #define REASSEMBLY_POLICY_VISTA 12 #define REASSEMBLY_POLICY_WINDOWS2K3 13 #define REASSEMBLY_POLICY_DEFAULT REASSEMBLY_POLICY_BSD #define SUB_SYN_SENT 0x01 #define SUB_ACK_SENT 0x02 #define SUB_SETUP_OK 0x03 #define SUB_RST_SENT 0x04 #define SUB_FIN_SENT 0x08 // flush types #define S5_FT_INTERNAL 0 // normal s5 "footprint" #define S5_FT_EXTERNAL 1 // set by other preprocessor #define S5_FT_PAF_MAX 2 // paf_max + footprint fp #define SLAM_MAX 4 /* Only track a maximum number of alerts per session */ #define MAX_SESSION_ALERTS 8 //#define DEBUG_STREAM5 #ifdef DEBUG_STREAM5 #define STREAM5_DEBUG_WRAP(x) DEBUG_WRAP(x) #else #define STREAM5_DEBUG_WRAP(x) #endif /* client/server ip/port dereference */ #define tcp_client_ip lwssn->client_ip #define tcp_client_port lwssn->client_port #define tcp_server_ip lwssn->server_ip #define tcp_server_port lwssn->server_port /* D A T A S T R U C T U R E S ***********************************/ typedef struct _TcpDataBlock { uint32_t seq; uint32_t ack; uint32_t win; uint32_t end_seq; uint32_t ts; } TcpDataBlock; typedef struct _StateMgr { uint8_t state; uint8_t sub_state; uint8_t state_queue; uint8_t expected_flags; uint32_t transition_seq; uint32_t stq_get_seq; } StateMgr; #define RAND_FLUSH_POINTS 64 //------------------------------------------------------------------------- // extra, extra - read all about it! // -- u2 is the only output plugin that currently supports extra data // -- extra data may be captured before or after alerts // -- extra data may be per packet or persistent (saved on session) // // -- per packet extra data is logged iff we alert on the packet // containing the extra data - u2 drives this // -- an extra data mask is added to Packet to indicate when per packet // extra data is available // // -- persistent extra data must be logged exactly once for each alert // regardless of capture/alert ordering - s5 purge_alerts drives this // -- an extra data mask is added to the session trackers to indicate that // persistent extra data is available // // -- event id and second are added to the session alert trackers so that // the extra data can be correlated with events // -- event id and second are not available when Stream5AddSessionAlertTcp // is called; u2 calls Stream5UpdateSessionAlertTcp as events are logged // to set these fields //------------------------------------------------------------------------- typedef struct _Stream5AlertInfo { /* For storing alerts that have already been seen on the session */ uint32_t sid; uint32_t gid; uint32_t seq; // if we log extra data, event_* is used to correlate with alert uint32_t event_id; uint32_t event_second; } Stream5AlertInfo; //----------------------------------------------------------------- // we make a lot of StreamSegments, StreamTrackers, and TcpSessions // so they are organized by member size/alignment requirements to // minimize unused space in the structs. // ... however, use of padding below is critical, adjust if needed //----------------------------------------------------------------- typedef struct _StreamSegment { uint8_t *data; uint8_t *payload; struct _StreamSegment *prev; struct _StreamSegment *next; #ifdef DEBUG int ordinal; #endif struct timeval tv; uint32_t caplen; uint32_t pktlen; uint32_t ts; uint32_t seq; uint16_t orig_dsize; uint16_t size; uint16_t urg_offset; uint8_t buffered; // this sequence ensures 4-byte alignment of iph in pkt // (only significant if we call the grinder) uint8_t pad1; uint16_t pad2; uint8_t pkt[1]; // variable length } StreamSegment; typedef struct _StreamTracker { StateMgr s_mgr; /* state tracking goodies */ FlushMgr flush_mgr; /* please flush twice, it's a long way to * the bitbucket... */ // this is intended to be private to s5_paf but is included // directly to avoid the need for allocation; do not directly // manipulate within this module. PAF_State paf_state; // for tracking protocol aware flushing Stream5AlertInfo alerts[MAX_SESSION_ALERTS]; /* history of alerts */ Stream5TcpPolicy *tcp_policy; StreamSegment *seglist; /* first queued segment */ StreamSegment *seglist_tail; /* last queued segment */ // TBD move out of here since only used per packet? StreamSegment* seglist_next; /* next queued segment to flush */ #ifdef DEBUG int segment_ordinal; #endif /* Local in the context of these variables means the local part * of the connection. For example, if this particular StreamTracker * was tracking the client side of a connection, the l_unackd value * would represent the client side of the connection's last unacked * sequence number */ uint32_t l_unackd; /* local unack'd seq number */ uint32_t l_nxt_seq; /* local next expected sequence */ uint32_t l_window; /* local receive window */ uint32_t r_nxt_ack; /* next expected ack from remote side */ uint32_t r_win_base; /* remote side window base sequence number * (i.e. the last ack we got) */ uint32_t isn; /* initial sequence number */ uint32_t ts_last; /* last timestamp (for PAWS) */ uint32_t ts_last_pkt; /* last packet timestamp we got */ uint32_t seglist_base_seq; /* seq of first queued segment */ uint32_t seg_count; /* number of current queued segments */ uint32_t seg_bytes_total; /* total bytes currently queued */ uint32_t seg_bytes_logical; /* logical bytes queued (total - overlaps) */ uint32_t total_bytes_queued; /* total bytes queued (life of session) */ uint32_t total_segs_queued; /* number of segments queued (life) */ uint32_t overlap_count; /* overlaps encountered */ uint32_t small_seg_count; uint32_t flush_count; /* number of flushed queued segments */ uint32_t xtradata_mask; /* extra data available to log */ uint16_t os_policy; uint16_t reassembly_policy; uint16_t wscale; /* window scale setting */ uint16_t mss; /* max segment size */ uint16_t flags; /* bitmap flags (TF_xxx) */ uint8_t mac_addr[6]; uint8_t alert_count; /* number alerts stored (up to MAX_SESSION_ALERTS) */ } StreamTracker; typedef struct _TcpSession { StreamTracker client; StreamTracker server; Stream5LWSession *lwssn; #ifdef DEBUG struct timeval ssn_time; #endif #ifdef HAVE_DAQ_ADDRESS_SPACE_ID int32_t ingress_index; /* Index of the inbound interface. */ int32_t egress_index; /* Index of the outbound interface. */ int32_t ingress_group; /* Index of the inbound group. */ int32_t egress_group; /* Index of the outbound group. */ uint32_t daq_flags; /* Flags for the packet (DAQ_PKT_FLAG_*) */ uint16_t address_space_id; #endif uint8_t ecn; } TcpSession; #define SL_BUF_FLUSHED 1 static inline int SetupOK (const StreamTracker* st) { return ( (st->s_mgr.sub_state & SUB_SETUP_OK) == SUB_SETUP_OK ); } static inline uint32_t SegsToFlush (const StreamTracker* st, unsigned max) { uint32_t n = st->seg_count - st->flush_count; StreamSegment* s; if ( !n || max == 1 ) return n; n = 0; s = st->seglist; while ( s ) { if ( !s->buffered && SEQ_LT(s->seq, st->r_win_base) ) n++; if ( max && n == max ) return n; s = s->next; } return n; } static inline bool DataToFlush (const StreamTracker* st) { if ( st->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL #ifdef NORMALIZER || st->flush_mgr.flush_policy == STREAM_FLPOLICY_PROTOCOL_IPS #endif ) return ( SegsToFlush(st, 1) > 0 ); #ifdef NORMALIZER if ( st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT_IPS ) return ( SegsToFlush(st, 1) > 1 ); #endif return ( SegsToFlush(st, 2) > 1 ); } int default_ports[] = { 21, 23, 25, 42, 53, 80, 110, 111, 135, 136, 137, 139, 143, 445, 513, 514, 1433, 1521, 2401, 3306 }; #ifdef TARGET_BASED char *default_protocols[] = { "ftp", "telnet", "smtp", "nameserver", "dns", "http", "pop3", "sunrpc", "dcerpc", "netbios-ssn", "imap", "login", "shell", "mssql", "oracle", "cvs", "mysql" }; #endif FlushConfig ignore_flush_policy[MAX_PORTS]; #ifdef TARGET_BASED FlushConfig ignore_flush_policy_protocol[MAX_PROTOCOL_ORDINAL]; #endif /* P R O T O T Y P E S ********************************************/ static void Stream5ParseTcpArgs(struct _SnortConfig *, Stream5TcpConfig *, char *, Stream5TcpPolicy *); static void Stream5PrintTcpConfig(Stream5TcpPolicy *); static void Stream5InitPacket(); static inline void SetupTcpDataBlock(TcpDataBlock *, Packet *); static int ProcessTcp(Stream5LWSession *, Packet *, TcpDataBlock *, Stream5TcpPolicy *); #if OLD_CODE_NOLONGER_USED_DEPENDS_ON_CURRENT_STATE static inline void QueueState(uint8_t, StreamTracker*, uint8_t, uint32_t, uint8_t); static inline int EvalStateQueue(StreamTracker *, uint8_t, uint32_t); #endif #ifdef NORMALIZER static inline int CheckFlushPolicyOnData( TcpSession *, StreamTracker *, StreamTracker *, TcpDataBlock *, Packet *); #endif static inline int CheckFlushPolicyOnAck( TcpSession *, StreamTracker *, StreamTracker *, TcpDataBlock *, Packet *); static void Stream5SeglistAddNode(StreamTracker *, StreamSegment *, StreamSegment *); static int Stream5SeglistDeleteNode(StreamTracker*, StreamSegment*); static int Stream5SeglistDeleteNodeTrim(StreamTracker*, StreamSegment*, uint32_t flush_seq); static int AddStreamNode(StreamTracker *st, Packet *p, TcpDataBlock*, TcpSession *tcpssn, int16_t len, uint32_t slide, uint32_t trunc, uint32_t seq, StreamSegment *left, StreamSegment **retSeg); static int DupStreamNode( Packet*, StreamTracker*, StreamSegment* left, StreamSegment** retSeg); static uint32_t Stream5GetWscale(Packet *, uint16_t *); static uint32_t Stream5PacketHasWscale(Packet *); static uint32_t Stream5GetMss(Packet *, uint16_t *); static uint32_t Stream5GetTcpTimestamp(Packet *, uint32_t *, int strip); static int FlushStream( Packet*, StreamTracker *st, uint32_t toSeq, uint8_t *flushbuf, const uint8_t *flushbuf_end); static void TcpSessionCleanup(Stream5LWSession *ssn, int freeApplicationData); static void TcpSessionCleanupWithFreeApplicationData(Stream5LWSession *ssn); int s5TcpStreamSizeInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr); int s5TcpStreamSizeEval(void *p, const uint8_t **cursor, void *dataPtr); void s5TcpStreamSizeCleanup(void *dataPtr); int s5TcpStreamReassembleRuleOptionInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr); int s5TcpStreamReassembleRuleOptionEval(void *p, const uint8_t **cursor, void *dataPtr); void s5TcpStreamReassembleRuleOptionCleanup(void *dataPtr); static inline void ResetFlushMgrs(void); static void targetPolicyIterate(void (*callback)(int)); static void policyDecoderFlagsSaveNClear(int policyId); static void policyDecoderFlagsRestore(int policyId); /* G L O B A L S **************************************************/ Stream5SessionCache *tcp_lws_cache = NULL; static MemPool tcp_session_mempool; static Packet *s5_pkt = NULL; static const uint8_t *s5_pkt_end = NULL; static char midstream_allowed = 0; /* enum for policy names */ static char *reassembly_policy_names[] = { "no policy!", "FIRST", "LINUX", "BSD", "OLD LINUX", "LAST", "WINDOWS", "SOLARIS", "HPUX11", "IRIX", "MACOS", "HPUX10", "WINDOWS VISTA", "WINDOWS 2003" "IPS" }; #ifdef DEBUG_STREAM5 static char *state_names[] = { "NONE", "LISTEN", "SYN_RCVD", "SYN_SENT", "ESTABLISHED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "CLOSING", "FIN_WAIT_2", "TIME_WAIT", "CLOSED" }; #endif static char *flush_policy_names[] = { "None", "Footprint", "Logical", "Response", "Sliding Window", #if 0 "Consumed", #endif "Ignore", "Protocol", "Footprint-IPS", "Protocol-IPS" }; static int s5_tcp_cleanup = 0; static uint32_t g_static_points[RAND_FLUSH_POINTS] = { 128, 217, 189, 130, 240, 221, 134, 129, 250, 232, 141, 131, 144, 177, 201, 130, 230, 190, 177, 142, 130, 200, 173, 129, 250, 244, 174, 151, 201, 190, 180, 198, 220, 201, 142, 185, 219, 129, 194, 140, 145, 191, 197, 183, 199, 220, 231, 245, 233, 135, 143, 158, 174, 194, 200, 180, 201, 142, 153, 187, 173, 199, 143, 201 }; /* F U N C T I O N S **********************************************/ static inline uint32_t GenerateFlushPoint(FlushPointList *flush_point_list) { return (rand() % flush_point_list->flush_range) + flush_point_list->flush_base; } static inline void InitFlushPointList(FlushPointList *flush_point_list, uint32_t value, uint32_t range, int use_static) { uint32_t i; uint32_t flush_range = range; uint32_t flush_base = value - range/2; if (!flush_point_list) return; if (!flush_point_list->initialized) { #ifdef REG_TEST const char* sfp = getenv("S5_FPT"); // no error checking required - atoi() is sufficient uint32_t cfp = sfp ? atoi(sfp) : 0; if ( cfp < 128 || cfp > 255 ) cfp = 192; #else const uint32_t cfp = 192; #endif flush_point_list->flush_range = flush_range; flush_point_list->flush_base = flush_base; #ifndef DYNAMIC_RANDOM_FLUSH_POINTS flush_point_list->current = 0; flush_point_list->flush_points = SnortAlloc(sizeof(uint32_t) * RAND_FLUSH_POINTS); for (i=0;irun_flags & RUN_FLAG__STATIC_HASH) { if ( i == 0 ) LogMessage("WARNING: using constant flush point = %u!\n", cfp); flush_point_list->flush_points[i] = cfp; } else if (use_static) { if ( i == 0 ) LogMessage("WARNING: using static flush points.\n"); flush_point_list->flush_points[i] = g_static_points[i]; } else { flush_point_list->flush_points[i] = GenerateFlushPoint(flush_point_list); } } #endif flush_point_list->initialized = 1; } } static inline void UpdateFlushMgr( FlushMgr *mgr, FlushPointList *flush_point_list, uint32_t flags) { if ( mgr->flush_type == S5_FT_EXTERNAL ) return; switch (mgr->flush_policy) { case STREAM_FLPOLICY_FOOTPRINT: case STREAM_FLPOLICY_LOGICAL: break; case STREAM_FLPOLICY_PROTOCOL: if ( flags & TF_PKT_MISSED ) { mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT; mgr->flush_type = S5_FT_PAF_MAX; } break; #ifdef NORMALIZER case STREAM_FLPOLICY_FOOTPRINT_IPS: break; case STREAM_FLPOLICY_PROTOCOL_IPS: if ( flags & TF_PKT_MISSED ) { mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS; mgr->flush_type = S5_FT_PAF_MAX; } break; #endif default: return; } /* Ideally, we would call rand() each time, but that * is a performance headache waiting to happen. */ #ifdef DYNAMIC_RANDOM_FLUSH_POINTS mgr->flush_pt = GenerateFlushPoint(); #else if (flush_point_list) { /* Handle case where it wasn't initialized... */ if (flush_point_list->initialized == 0) { InitFlushPointList(flush_point_list, 192, 128, 0); } mgr->flush_pt = flush_point_list->flush_points[flush_point_list->current]; flush_point_list->current = (flush_point_list->current+1) % RAND_FLUSH_POINTS; } #endif mgr->last_size = 0; mgr->last_count = 0; if ( mgr->flush_type == S5_FT_PAF_MAX ) mgr->flush_pt += ScPafMax(); } static inline void InitFlushMgr( FlushMgr *mgr, FlushPointList *flush_point_list, uint8_t policy, uint8_t auto_disable) { mgr->flush_policy = policy; mgr->flush_type = S5_FT_INTERNAL; mgr->auto_disable = auto_disable; UpdateFlushMgr(mgr, flush_point_list, 0); #ifdef NORMALIZER if ( Normalize_IsEnabled(snort_conf, NORM_TCP_IPS) ) { if ( policy == STREAM_FLPOLICY_FOOTPRINT ) mgr->flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS; else if ( policy == STREAM_FLPOLICY_PROTOCOL ) mgr->flush_policy = STREAM_FLPOLICY_PROTOCOL_IPS; } #endif } static inline void InitFlushMgrByPort ( Stream5LWSession* lwssn, StreamTracker* pst, uint16_t port, bool c2s, uint8_t flush_policy) { uint8_t registration, auto_disable = 0; bool flush = (flush_policy != STREAM_FLPOLICY_IGNORE); #if 0 // this check required if PAF doesn't abort if ( lwssn->session_state & STREAM5_STATE_MIDSTREAM ) registration = 0; else #endif registration = s5_paf_port_registration( s5_tcp_eval_config->paf_config, port, c2s, flush); if ( registration ) { flush_policy = STREAM_FLPOLICY_PROTOCOL; s5_paf_setup(&pst->paf_state, registration); auto_disable = !flush; } InitFlushMgr(&pst->flush_mgr, &pst->tcp_policy->flush_point_list, flush_policy, auto_disable); } static inline void InitFlushMgrByService ( Stream5LWSession* lwssn, StreamTracker* pst, int16_t service, bool c2s, uint8_t flush_policy) { uint8_t registration, auto_disable = 0; bool flush = (flush_policy != STREAM_FLPOLICY_IGNORE); #if 0 // this check required if PAF doesn't abort if ( lwssn->session_state & STREAM5_STATE_MIDSTREAM ) registration = 0; else #endif registration = s5_paf_service_registration( s5_tcp_eval_config->paf_config, service, c2s, flush); if ( registration ) { flush_policy = STREAM_FLPOLICY_PROTOCOL; s5_paf_setup(&pst->paf_state, registration); auto_disable = !flush; } InitFlushMgr(&pst->flush_mgr, &pst->tcp_policy->flush_point_list, flush_policy, auto_disable); } static int ResetFlushMgrsPolicy( tSfPolicyUserContextId config, tSfPolicyId policyId, void* pData ) { int i; Stream5Config *pPolicyConfig = (Stream5Config *)pData; //do any housekeeping before freeing Stream5Config if (pPolicyConfig->tcp_config == NULL) return 0; for (i = 0; i < pPolicyConfig->tcp_config->num_policies; i++) { int j; Stream5TcpPolicy *policy = pPolicyConfig->tcp_config->policy_list[i]; FlushPointList *fpl = &policy->flush_point_list; FlushMgr *client, *server; uint8_t flush_policy; fpl->current = 0; for (j = 0; j < MAX_PORTS; j++) { client = &policy->flush_config[j].client; flush_policy = policy->flush_config[j].client.flush_policy; InitFlushMgr(client, fpl, flush_policy, 0); server = &policy->flush_config[j].server; flush_policy = policy->flush_config[j].server.flush_policy; InitFlushMgr(server, fpl, flush_policy, 0); } #ifdef TARGET_BASED /* protocol 0 is the unknown case. skip it */ for (j = 1; j < MAX_PROTOCOL_ORDINAL; j++) { client = &policy->flush_config_protocol[j].client; flush_policy = policy->flush_config_protocol[j].client.flush_policy; InitFlushMgr(client, fpl, flush_policy, 0); server = &policy->flush_config_protocol[j].server; flush_policy = policy->flush_config_protocol[j].server.flush_policy; InitFlushMgr(server, fpl, flush_policy, 0); } #endif } return 0; } static inline void ResetFlushMgrs(void) { if (s5_config == NULL) return; sfPolicyUserDataFreeIterate (s5_config, ResetFlushMgrsPolicy); } void** Stream5GetPAFUserDataTcp (Stream5LWSession* lwssn, bool to_server) { TcpSession* tcpssn; if ( !lwssn->proto_specific_data ) return NULL; tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if ( !tcpssn ) return NULL; return to_server ? &tcpssn->server.paf_state.user : &tcpssn->client.paf_state.user; } bool Stream5IsPafActiveTcp (Stream5LWSession* lwssn, bool to_server) { TcpSession* tcpssn; FlushMgr* fm; if ( !lwssn->proto_specific_data ) return false; tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if ( !tcpssn ) return false; fm = to_server ? &tcpssn->server.flush_mgr : &tcpssn->client.flush_mgr; return ( (fm->flush_policy == STREAM_FLPOLICY_PROTOCOL) #ifdef NORMALIZER || (fm->flush_policy == STREAM_FLPOLICY_PROTOCOL_IPS) #endif ); } bool Stream5ActivatePafTcp (Stream5LWSession* lwssn, bool to_server) { TcpSession* tcpssn; StreamTracker* trk; FlushMgr* fm; if ( !lwssn->proto_specific_data ) return false; tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if ( !tcpssn ) return false; if ( to_server ) { trk = &tcpssn->server; fm = &tcpssn->server.flush_mgr; } else { trk = &tcpssn->client; fm = &tcpssn->client.flush_mgr; } switch ( fm->flush_policy) { case STREAM_FLPOLICY_IGNORE: InitFlushMgr(fm, &trk->tcp_policy->flush_point_list, STREAM_FLPOLICY_PROTOCOL, 0); break; case STREAM_FLPOLICY_FOOTPRINT: fm->flush_policy = STREAM_FLPOLICY_PROTOCOL; break; #ifdef NORMALIZER case STREAM_FLPOLICY_FOOTPRINT_IPS: fm->flush_policy = STREAM_FLPOLICY_PROTOCOL_IPS; break; #endif default: return false; } s5_paf_setup(&trk->paf_state, trk->paf_state.cb_mask); return true; } //------------------------------------------------------------------------- // tcp ha stuff static Stream5LWSession *Stream5TCPCreateSession(const SessionKey *key) { setRuntimePolicy(getDefaultPolicy()); /* TODO: Set the TCP policy to something here? */ return NewLWSession(tcp_lws_cache, NULL, key, NULL); } static void Stream5TCPDeactivateSession(Stream5LWSession *lwssn) { if (lwssn->proto_specific_data) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Cleaning up the TCP session associated with the session being put into standby.\n");); TcpSessionCleanup(lwssn, 0); } lwssn->session_state &= ~(STREAM5_STATE_SYN | STREAM5_STATE_SYN_ACK | STREAM5_STATE_ACK | STREAM5_STATE_ESTABLISHED); lwssn->ha_state.session_flags &= ~(SSNFLAG_SEEN_CLIENT | SSNFLAG_SEEN_SERVER); } static int Stream5TCPDeleteSession (const SessionKey *key) { Stream5LWSession *lwssn = GetLWSessionFromKey(tcp_lws_cache, key); if ( lwssn && !Stream5SetRuntimeConfiguration(lwssn, lwssn->protocol) ) DeleteLWSession(tcp_lws_cache, lwssn, "ha sync"); return 0; } Stream5LWSession *GetLWTcpSession(const SessionKey *key) { return GetLWSessionFromKey(tcp_lws_cache, key); } #ifdef ENABLE_HA static HA_Api ha_tcp_api = { /*.get_lws = */ GetLWTcpSession, /*.create_session = */ Stream5TCPCreateSession, /*.deactivate_session = */ Stream5TCPDeactivateSession, /*.delete_session = */ Stream5TCPDeleteSession, }; #endif void Stream5InitTcp(Stream5GlobalConfig *gconfig) { if (gconfig == NULL) return; if((tcp_lws_cache == NULL) && gconfig->track_tcp_sessions) { tcp_lws_cache = InitLWSessionCache(gconfig->max_tcp_sessions, gconfig->tcp_cache_pruning_timeout, gconfig->tcp_cache_nominal_timeout, 5, 0, &TcpSessionCleanupWithFreeApplicationData); if(!tcp_lws_cache) { FatalError("Unable to init stream5 TCP session cache, no TCP " "stream inspection!\n"); } if (mempool_init(&tcp_session_mempool, gconfig->max_tcp_sessions, sizeof(TcpSession)) != 0) { FatalError("%s(%d) Could not initialize tcp session memory pool.\n", __FILE__, __LINE__); } Stream5TcpRegisterPreprocProfiles(); } #ifdef ENABLE_HA ha_set_api(IPPROTO_TCP, &ha_tcp_api); #endif } void Stream5TcpRegisterPreprocProfiles(void) { #ifdef PERF_PROFILING RegisterPreprocessorProfile("s5TcpNewSess", &s5TcpNewSessPerfStats, 2, &s5TcpPerfStats); RegisterPreprocessorProfile("s5TcpState", &s5TcpStatePerfStats, 2, &s5TcpPerfStats); RegisterPreprocessorProfile("s5TcpData", &s5TcpDataPerfStats, 3, &s5TcpStatePerfStats); RegisterPreprocessorProfile("s5TcpPktInsert", &s5TcpInsertPerfStats, 4, &s5TcpDataPerfStats); RegisterPreprocessorProfile("s5TcpPAF", &s5TcpPAFPerfStats, 3, &s5TcpStatePerfStats); RegisterPreprocessorProfile("s5TcpFlush", &s5TcpFlushPerfStats, 3, &s5TcpStatePerfStats); RegisterPreprocessorProfile("s5TcpBuildPacket", &s5TcpBuildPacketPerfStats, 4, &s5TcpFlushPerfStats); RegisterPreprocessorProfile("s5TcpProcessRebuilt", &s5TcpProcessRebuiltPerfStats, 4, &s5TcpFlushPerfStats); #endif } void Stream5TcpRegisterRuleOptions(struct _SnortConfig *sc) { /* Register the 'stream_size' rule option */ RegisterPreprocessorRuleOption(sc, "stream_size", &s5TcpStreamSizeInit, &s5TcpStreamSizeEval, &s5TcpStreamSizeCleanup, NULL, NULL, NULL, NULL); RegisterPreprocessorRuleOption(sc, "stream_reassemble", &s5TcpStreamReassembleRuleOptionInit, &s5TcpStreamReassembleRuleOptionEval, &s5TcpStreamReassembleRuleOptionCleanup, NULL, NULL, NULL, NULL); #ifdef PERF_PROFILING RegisterPreprocessorProfile("stream_size", &streamSizePerfStats, 4, &preprocRuleOptionPerfStats); RegisterPreprocessorProfile("reassemble", &streamReassembleRuleOptionPerfStats, 4, &preprocRuleOptionPerfStats); #endif } void Stream5TcpInitFlushPoints(void) { int i; /* Seed the flushpoint random generator */ srand( (unsigned int) sizeof(default_ports) + (unsigned int) time(NULL) ); /* Default is to ignore, for all ports */ for(i=0;iflush_config, ignore_flush_policy, sizeof(FlushConfig) * MAX_PORTS); #ifdef TARGET_BASED memcpy(&s5TcpPolicy->flush_config_protocol, ignore_flush_policy_protocol, sizeof(FlushConfig) * MAX_PROTOCOL_ORDINAL); #endif Stream5ParseTcpArgs(sc, config, args, s5TcpPolicy); config->num_policies++; /* Now add this context to the internal list */ if (config->policy_list == NULL) { config->policy_list = (Stream5TcpPolicy **)SnortAlloc(sizeof (Stream5TcpPolicy *)); } else { Stream5TcpPolicy **tmpPolicyList = (Stream5TcpPolicy **)SnortAlloc(sizeof (Stream5TcpPolicy *) * (config->num_policies)); memcpy(tmpPolicyList, config->policy_list, sizeof(Stream5TcpPolicy *) * (config->num_policies - 1)); free(config->policy_list); config->policy_list = tmpPolicyList; } config->policy_list[config->num_policies - 1] = s5TcpPolicy; if ( ScPafEnabled() && !config->paf_config ) config->paf_config = s5_paf_new(); Stream5PrintTcpConfig(s5TcpPolicy); #ifdef REG_TEST LogMessage(" TCP Session Size: %lu\n",sizeof(TcpSession)); #endif } static inline uint16_t StreamPolicyIdFromName(char *name) { if (!name) { return STREAM_POLICY_DEFAULT; } if(!strcasecmp(name, "bsd")) { return STREAM_POLICY_BSD; } else if(!strcasecmp(name, "old-linux")) { return STREAM_POLICY_OLD_LINUX; } else if(!strcasecmp(name, "linux")) { return STREAM_POLICY_LINUX; } else if(!strcasecmp(name, "first")) { return STREAM_POLICY_FIRST; } else if(!strcasecmp(name, "last")) { return STREAM_POLICY_LAST; } else if(!strcasecmp(name, "windows")) { return STREAM_POLICY_WINDOWS; } else if(!strcasecmp(name, "solaris")) { return STREAM_POLICY_SOLARIS; } else if(!strcasecmp(name, "win2003") || !strcasecmp(name, "win2k3")) { return STREAM_POLICY_WINDOWS2K3; } else if(!strcasecmp(name, "vista")) { return STREAM_POLICY_VISTA; } else if(!strcasecmp(name, "hpux") || !strcasecmp(name, "hpux11")) { return STREAM_POLICY_HPUX11; } else if(!strcasecmp(name, "hpux10")) { return STREAM_POLICY_HPUX10; } else if(!strcasecmp(name, "irix")) { return STREAM_POLICY_IRIX; } else if(!strcasecmp(name, "macos") || !strcasecmp(name, "grannysmith")) { return STREAM_POLICY_MACOS; } return STREAM_POLICY_DEFAULT; /* BSD is the default */ } static inline uint16_t GetTcpReassemblyPolicy(int os_policy) { switch (os_policy) { case STREAM_POLICY_FIRST: return REASSEMBLY_POLICY_FIRST; case STREAM_POLICY_LINUX: return REASSEMBLY_POLICY_LINUX; case STREAM_POLICY_BSD: return REASSEMBLY_POLICY_BSD; case STREAM_POLICY_OLD_LINUX: return REASSEMBLY_POLICY_OLD_LINUX; case STREAM_POLICY_LAST: return REASSEMBLY_POLICY_LAST; case STREAM_POLICY_WINDOWS: return REASSEMBLY_POLICY_WINDOWS; case STREAM_POLICY_SOLARIS: return REASSEMBLY_POLICY_SOLARIS; case STREAM_POLICY_WINDOWS2K3: return REASSEMBLY_POLICY_WINDOWS2K3; case STREAM_POLICY_VISTA: return REASSEMBLY_POLICY_VISTA; case STREAM_POLICY_HPUX11: return REASSEMBLY_POLICY_HPUX11; case STREAM_POLICY_HPUX10: return REASSEMBLY_POLICY_HPUX10; case STREAM_POLICY_IRIX: return REASSEMBLY_POLICY_IRIX; case STREAM_POLICY_MACOS: return REASSEMBLY_POLICY_MACOS; default: return REASSEMBLY_POLICY_DEFAULT; } } #define STATIC_FP ((s5TcpPolicy->flags & STREAM5_CONFIG_STATIC_FLUSHPOINTS)?1:0) static void Stream5ParseTcpArgs(struct _SnortConfig *sc, Stream5TcpConfig *config, char *args, Stream5TcpPolicy *s5TcpPolicy) { char **toks; int num_toks; int i; char **stoks = NULL; int s_toks; char *endPtr = NULL; char set_flush_policy = 0; #ifdef TARGET_BASED char set_target_flush_policy = 0; #endif int reassembly_direction = SSN_DIR_FROM_CLIENT; int32_t long_val = 0; s5TcpPolicy->policy = STREAM_POLICY_DEFAULT; s5TcpPolicy->reassembly_policy = REASSEMBLY_POLICY_DEFAULT; s5TcpPolicy->session_timeout = S5_DEFAULT_SSN_TIMEOUT; s5TcpPolicy->max_window = 0; s5TcpPolicy->flags = 0; s5TcpPolicy->max_queued_bytes = S5_DEFAULT_MAX_QUEUED_BYTES; s5TcpPolicy->max_queued_segs = S5_DEFAULT_MAX_QUEUED_SEGS; s5TcpPolicy->max_consec_small_segs = S5_DEFAULT_CONSEC_SMALL_SEGS; s5TcpPolicy->max_consec_small_seg_size = S5_DEFAULT_MAX_SMALL_SEG_SIZE; if(args != NULL && strlen(args) != 0) { toks = mSplit(args, ",", 0, &num_toks, 0); for (i = 0; i < num_toks; i++) { if(!strcasecmp(toks[i], "use_static_footprint_sizes")) s5TcpPolicy->flags |= STREAM5_CONFIG_STATIC_FLUSHPOINTS; } for (i = 0; i < num_toks; i++) { int max_s_toks = 1; // set to 0 to disable check stoks = mSplit(toks[i], " ", 3, &s_toks, 0); if (s_toks == 0) { FatalError("%s(%d) => Missing parameter in Stream5 TCP config.\n", file_name, file_line); } if(!strcasecmp(stoks[0], "timeout")) { if(stoks[1]) { s5TcpPolicy->session_timeout = strtoul(stoks[1], &endPtr, 10); } if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid timeout in config file. " "Integer parameter required.\n", file_name, file_line); } if ((s5TcpPolicy->session_timeout > S5_MAX_SSN_TIMEOUT) || (s5TcpPolicy->session_timeout < S5_MIN_SSN_TIMEOUT)) { FatalError("%s(%d) => Invalid timeout in config file. " "Must be between %d and %d\n", file_name, file_line, S5_MIN_SSN_TIMEOUT, S5_MAX_SSN_TIMEOUT); } max_s_toks = 2; } else if(!strcasecmp(stoks[0], "overlap_limit")) { if(stoks[1]) { long_val = SnortStrtol(stoks[1], &endPtr, 10); if (errno == ERANGE) { errno = 0; long_val = -1; } s5TcpPolicy->overlap_limit = (uint8_t)long_val; } if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid overlap limit in config file." "Integer parameter required\n", file_name, file_line); } if ((long_val > S5_MAX_OVERLAP_LIMIT) || (long_val < S5_MIN_OVERLAP_LIMIT)) { FatalError("%s(%d) => Invalid overlap limit in config file." " Must be between %d and %d\n", file_name, file_line, S5_MIN_OVERLAP_LIMIT, S5_MAX_OVERLAP_LIMIT); } max_s_toks = 2; } else if(!strcasecmp(stoks[0], "detect_anomalies")) { s5TcpPolicy->flags |= STREAM5_CONFIG_ENABLE_ALERTS; } else if(!strcasecmp(stoks[0], "policy")) { s5TcpPolicy->policy = StreamPolicyIdFromName(stoks[1]); if ((s5TcpPolicy->policy == STREAM_POLICY_DEFAULT) && (strcasecmp(stoks[1], "bsd"))) { /* Default is BSD. If we don't have "bsd", its * the default and invalid. */ FatalError("%s(%d) => Bad policy name \"%s\"\n", file_name, file_line, stoks[1]); } s5TcpPolicy->reassembly_policy = GetTcpReassemblyPolicy(s5TcpPolicy->policy); max_s_toks = 2; } else if(!strcasecmp(stoks[0], "require_3whs")) { s5TcpPolicy->flags |= STREAM5_CONFIG_REQUIRE_3WHS; if (s_toks > 1) { s5TcpPolicy->hs_timeout = SnortStrtoul(stoks[1], &endPtr, 10); if ((endPtr == &stoks[1][0]) || (*endPtr != '\0') || (errno == ERANGE)) { FatalError("%s(%d) => Invalid 3Way Handshake allowable. Integer parameter required.\n", file_name, file_line); } if (s5TcpPolicy->hs_timeout > S5_MAX_SSN_TIMEOUT) { FatalError("%s(%d) => Invalid handshake timeout in " "config file. Must be between %d and %d\n", file_name, file_line, S5_MIN_ALT_HS_TIMEOUT, S5_MAX_SSN_TIMEOUT); } } max_s_toks = 2; } else if(!strcasecmp(stoks[0], "bind_to")) { if (s_toks < 2) { FatalError("%s(%d) => Invalid Stream5 TCP Policy option - " "\"bind_to\" option requires an argument.\n", file_name, file_line); } if(strstr(stoks[1], "[")) { FatalError("%s(%d) => Invalid Stream5 TCP Policy option. IP lists are not allowed.\n", file_name, file_line); } s5TcpPolicy->bound_addrs = IpAddrSetParse(sc, stoks[1]); max_s_toks = 2; } else if(!strcasecmp(stoks[0], "max_window")) { if(stoks[1]) { long_val = SnortStrtol(stoks[1], &endPtr, 10); if (errno == ERANGE) { errno = 0; FatalError("%s(%d) => Invalid Max Window size. Integer parameter required.\n", file_name, file_line); } s5TcpPolicy->max_window = (uint32_t)long_val; } if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid Max Window size. Integer parameter required.\n", file_name, file_line); } if ((long_val > S5_MAX_MAX_WINDOW) || (long_val < S5_MIN_MAX_WINDOW)) { FatalError("%s(%d) => Invalid Max Window size." " Must be between %d and %d\n", file_name, file_line, S5_MIN_MAX_WINDOW, S5_MAX_MAX_WINDOW); } max_s_toks = 2; } else if(!strcasecmp(stoks[0], "use_static_footprint_sizes")) { // we already handled this one above } else if(!strcasecmp(stoks[0], "flush_factor")) { if (stoks[1]) { s5TcpPolicy->flush_factor = (uint16_t)SnortStrtoulRange( stoks[1], &endPtr, 10, 0, S5_MAX_FLUSH_FACTOR); } if ( (!stoks[1] || (endPtr == &stoks[1][0])) || (s5TcpPolicy->flush_factor > S5_MAX_FLUSH_FACTOR)) { FatalError("%s(%d) => 'flush_factor %d' invalid: " "value must be between 0 and %d segments.\n", file_name, file_line, s5TcpPolicy->flush_factor, S5_MAX_FLUSH_FACTOR); } max_s_toks = 2; } else if(!strcasecmp(stoks[0], "dont_store_large_packets")) { s5TcpPolicy->flags |= STREAM5_CONFIG_PERFORMANCE; } else if(!strcasecmp(stoks[0], "check_session_hijacking")) { s5TcpPolicy->flags |= STREAM5_CONFIG_CHECK_SESSION_HIJACKING; } else if(!strcasecmp(stoks[0], "ignore_any_rules")) { s5TcpPolicy->flags |= STREAM5_CONFIG_IGNORE_ANY; } else if(!strcasecmp(stoks[0], "dont_reassemble_async")) { s5TcpPolicy->flags |= STREAM5_CONFIG_NO_ASYNC_REASSEMBLY; } else if(!strcasecmp(stoks[0], "max_queued_bytes")) { if(stoks[1]) { long_val = SnortStrtol(stoks[1], &endPtr, 10); if (errno == ERANGE) { errno = 0; FatalError("%s(%d) => Invalid Max Queued Bytes. Integer parameter required.\n", file_name, file_line); } s5TcpPolicy->max_queued_bytes = (uint32_t)long_val; } if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid Max Queued Bytes. Integer parameter required.\n", file_name, file_line); } if (((long_val > S5_MAX_MAX_QUEUED_BYTES) || (long_val < S5_MIN_MAX_QUEUED_BYTES)) && (long_val != 0)) { FatalError("%s(%d) => Invalid Max Queued Bytes." " Must be 0 (disabled) or between %d and %d\n", file_name, file_line, S5_MIN_MAX_QUEUED_BYTES, S5_MAX_MAX_QUEUED_BYTES); } max_s_toks = 2; } else if(!strcasecmp(stoks[0], "max_queued_segs")) { if(stoks[1]) { long_val = SnortStrtol(stoks[1], &endPtr, 10); if (errno == ERANGE) { errno = 0; FatalError("%s(%d) => Invalid Max Queued Bytes. Integer parameter required.\n", file_name, file_line); } s5TcpPolicy->max_queued_segs = (uint32_t)long_val; } if (!stoks[1] || (endPtr == &stoks[1][0])) { FatalError("%s(%d) => Invalid Max Queued Bytes. Integer parameter required.\n", file_name, file_line); } if (((long_val > S5_MAX_MAX_QUEUED_SEGS) || (long_val < S5_MIN_MAX_QUEUED_SEGS)) && (long_val != 0)) { FatalError("%s(%d) => Invalid Max Queued Bytes." " Must be 0 (disabled) or between %d and %d\n", file_name, file_line, S5_MIN_MAX_QUEUED_SEGS, S5_MAX_MAX_QUEUED_SEGS); } max_s_toks = 2; } else if (!strcasecmp(stoks[0], "small_segments")) { char **ptoks; int num_ptoks; /* Small segments takes at least 3 parameters... */ if (s_toks < 3) { FatalError("%s(%d) => Insufficient parameters to small " "segments configuration. Syntax is: " " bytes ignore_ports p1 p2, " "with ignore_ports being an optional parameter\n", file_name, file_line); } /* first the number of consecutive segments */ long_val = SnortStrtol(stoks[1], &endPtr, 10); if (errno == ERANGE) { errno = 0; FatalError("%s(%d) => Invalid Small Segment number. Integer parameter required.\n", file_name, file_line); } s5TcpPolicy->max_consec_small_segs = (uint32_t)long_val; if ((long_val > S5_MAX_CONSEC_SMALL_SEGS) || (long_val < S5_MIN_CONSEC_SMALL_SEGS)) { FatalError("%s(%d) => Invalid Small Segments." " Must be integer between %d and %d, inclusive\n", file_name, file_line, S5_MIN_CONSEC_SMALL_SEGS, S5_MAX_CONSEC_SMALL_SEGS); } ptoks = mSplit(stoks[2], " ", MAX_PORTS + 3, &num_ptoks, 0); /* the bytes keyword */ if (strcasecmp(ptoks[0], "bytes") || (num_ptoks < 2)) { FatalError("%s(%d) => Insufficient parameters to small " "segments configuration. Syntax is: " " bytes ignore_ports p1 p2, " "with ignore_ports being an optional parameter\n", file_name, file_line); } /* the minimum bytes for a segment to be considered "small" */ long_val = SnortStrtol(ptoks[1], &endPtr, 10); if (errno == ERANGE) { errno = 0; FatalError("%s(%d) => Invalid Small Segment bytes. Integer parameter required.\n", file_name, file_line); } s5TcpPolicy->max_consec_small_seg_size = (uint32_t)long_val; if ((long_val > S5_MAX_MAX_SMALL_SEG_SIZE) || (long_val < S5_MIN_MAX_SMALL_SEG_SIZE)) { FatalError("%s(%d) => Invalid Small Segments bytes." " Must be integer between %d and %d, inclusive\n", file_name, file_line, S5_MIN_MAX_SMALL_SEG_SIZE, S5_MAX_MAX_SMALL_SEG_SIZE); } /* and the optional ignore_ports */ if (num_ptoks > 2) { int j; unsigned short port = 0; long long_port = 0; if (strcasecmp(ptoks[2], "ignore_ports") || (num_ptoks < 4)) { FatalError("%s(%d) => Insufficient parameters to small " "segments configuration. Syntax is: " " bytes ignore_ports p1 p2, " "with ignore_ports being an optional parameter\n", file_name, file_line); } for (j=3; j Invalid Port for small segments ignore_ports parameter. Integer parameter required.\n", file_name, file_line); } if ((long_port < 0) || (long_port > MAX_PORTS-1)) { FatalError( "%s(%d) => Invalid port %ld for small segments ignore_ports " "parameter, must be between 0 and %d, inclusive\n", file_name, file_line, long_port, MAX_PORTS-1); } port = (unsigned short)long_port; s5TcpPolicy->small_seg_ignore[port/8] |= (1 << (port %8)); } } max_s_toks = 0; // we already checked all tokens mSplitFree(&ptoks, num_ptoks); } else if (!strcasecmp(stoks[0], "ports")) { if (s_toks > 1) { if(!strcasecmp(stoks[1], "client")) { reassembly_direction = SSN_DIR_FROM_CLIENT; } else if(!strcasecmp(stoks[1], "server")) { reassembly_direction = SSN_DIR_FROM_SERVER; } else if(!strcasecmp(stoks[1], "both")) { reassembly_direction = SSN_DIR_BOTH; } else { FatalError( "%s(%d) => Invalid direction for reassembly " "configuration \"%s\". Valid values are 'client', " "'server', or 'both'.\n", file_name, file_line, stoks[1]); } } if (s_toks > 2) { char **ptoks; int num_ptoks; int j; unsigned short port = 0; long long_port = 0; /* Initialize it if not already... */ InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP); if (!strcasecmp(stoks[2], "all")) { for (j=0; jflush_config[j].client; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } if (reassembly_direction & SSN_DIR_FROM_SERVER) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].server; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } } } else if (!strcasecmp(stoks[2], "none")) { for (j=0; jflush_config[j].client; flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE; } if (reassembly_direction & SSN_DIR_FROM_SERVER) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[j].server; flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE; } } } else { ptoks = mSplit(stoks[2], " ", MAX_PORTS, &num_ptoks, 0); for (j=0;j Invalid Port list. Integer parameter required.\n", file_name, file_line); } if ((long_port < 0) || (long_port > MAX_PORTS-1)) { FatalError( "%s(%d) => Invalid port %ld, must be between 0 and %d, " "inclusive\n", file_name, file_line, long_port, MAX_PORTS-1); } port = (unsigned short)long_port; if (reassembly_direction & SSN_DIR_FROM_CLIENT) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[port].client; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } if (reassembly_direction & SSN_DIR_FROM_SERVER) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[port].server; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } } mSplitFree(&ptoks, num_ptoks); } set_flush_policy = 1; } max_s_toks = 0; // we already checked all tokens } #ifdef TARGET_BASED else if (!strcasecmp(stoks[0], "protocol")) { if (s_toks > 1) { if(!strcasecmp(stoks[1], "client")) { reassembly_direction = SSN_DIR_FROM_CLIENT; } else if(!strcasecmp(stoks[1], "server")) { reassembly_direction = SSN_DIR_FROM_SERVER; } else if(!strcasecmp(stoks[1], "both")) { reassembly_direction = SSN_DIR_BOTH; } else { FatalError( "%s(%d) => Invalid direction for reassembly " "configuration \"%s\". Valid values are 'client', " "'server', or 'both'.\n", file_name, file_line, stoks[1]); } } if (s_toks > 2) { char **ptoks; int num_ptoks; int j; /* Initialize it if not already... */ InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP); if (!strcasecmp(stoks[2], "all")) { for (j=1; jflush_config_protocol[j].client; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } if (reassembly_direction & SSN_DIR_FROM_SERVER) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].server; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } s5TcpPolicy->flush_config_protocol[j].configured = 1; } } else if (!strcasecmp(stoks[2], "none")) { for (j=1; jflush_config_protocol[j].client; flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE; } if (reassembly_direction & SSN_DIR_FROM_SERVER) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[j].server; flush_mgr->flush_policy = STREAM_FLPOLICY_IGNORE; } s5TcpPolicy->flush_config_protocol[j].configured = 1; } } else { ptoks = mSplit(stoks[2], " ", MAX_PROTOCOL_ORDINAL, &num_ptoks, 0); for (j=0;j Invalid Protocol Name. Protocol name must be specified.\n", file_name, file_line); } /* First look it up */ proto_ordinal = FindProtocolReference(ptoks[j]); if (proto_ordinal == SFTARGET_UNKNOWN_PROTOCOL) { /* Not known -- add it */ proto_ordinal = AddProtocolReference(ptoks[j]); if (proto_ordinal == SFTARGET_UNKNOWN_PROTOCOL) { FatalError("%s(%d) => Failed to find protocol reference for '%s'\n", file_name, file_line, ptoks[j]); } } if (reassembly_direction & SSN_DIR_FROM_CLIENT) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[proto_ordinal].client; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } if (reassembly_direction & SSN_DIR_FROM_SERVER) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[proto_ordinal].server; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } s5TcpPolicy->flush_config_protocol[proto_ordinal].configured = 1; } mSplitFree(&ptoks, num_ptoks); } set_target_flush_policy = 1; } max_s_toks = 0; // we already checked all tokens } #endif else { FatalError("%s(%d) => Invalid Stream5 TCP policy option\n", file_name, file_line); } if ( max_s_toks && (s_toks > max_s_toks) ) { FatalError("%s(%d) => Invalid Stream5 TCP Policy option. Missing comma?\n", file_name, file_line); } mSplitFree(&stoks, s_toks); } mSplitFree(&toks, num_toks); } if (s5TcpPolicy->bound_addrs == NULL) { if (config->default_policy != NULL) { FatalError("%s(%d) => Default Stream5 TCP Policy already set. " "This policy must be bound to a specific host or " "network.\n", file_name, file_line); } config->default_policy = s5TcpPolicy; } else { if (s5TcpPolicy->flags & STREAM5_CONFIG_IGNORE_ANY) { FatalError("%s(%d) => \"ignore_any_rules\" option can be used only" " with Default Stream5 TCP Policy\n", file_name, file_line); } } if (!set_flush_policy) { /* Initialize it if not already... */ InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP); for (i=0;i<(int)(sizeof(default_ports)/sizeof(int)); i++) { if (reassembly_direction & SSN_DIR_FROM_CLIENT) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[default_ports[i]].client; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } if (reassembly_direction & SSN_DIR_FROM_SERVER) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config[default_ports[i]].server; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } } } #ifdef TARGET_BASED if (!set_target_flush_policy) { int app_id; /* Initialize it if not already... */ InitFlushPointList(&s5TcpPolicy->flush_point_list, 192, 128, STATIC_FP); for (i=0; i<(int)(sizeof(default_protocols)/sizeof(char *)); i++) { /* Look up the protocol by name. Add it if it doesn't exist. */ app_id = FindProtocolReference(default_protocols[i]); if (app_id == SFTARGET_UNKNOWN_PROTOCOL) { app_id = AddProtocolReference(default_protocols[i]); } /* While this should never happen, I don't feel guilty adding this * logic as it executes at parse time. */ if (app_id == SFTARGET_UNKNOWN_PROTOCOL) continue; /* Set flush managers. */ if (reassembly_direction & SSN_DIR_FROM_CLIENT) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[app_id].client; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } if (reassembly_direction & SSN_DIR_FROM_SERVER) { FlushMgr *flush_mgr = &s5TcpPolicy->flush_config_protocol[app_id].server; FlushPointList *flush_point_list = &s5TcpPolicy->flush_point_list; InitFlushMgr(flush_mgr, flush_point_list, STREAM_FLPOLICY_FOOTPRINT, 0); } s5TcpPolicy->flush_config_protocol[app_id].configured = 1; } } #endif } static void Stream5PrintTcpConfig(Stream5TcpPolicy *s5TcpPolicy) { int i=0, j=0; LogMessage("Stream5 TCP Policy config:\n"); if (s5TcpPolicy->bound_addrs != NULL) { IpAddrSetPrint(" Bound Addresses: ", s5TcpPolicy->bound_addrs); } else { LogMessage(" Bound Address: default\n"); } LogMessage(" Reassembly Policy: %s\n", reassembly_policy_names[s5TcpPolicy->reassembly_policy]); LogMessage(" Timeout: %d seconds\n", s5TcpPolicy->session_timeout); if (s5TcpPolicy->max_window != 0) LogMessage(" Max TCP Window: %u\n", s5TcpPolicy->max_window); if (s5TcpPolicy->overlap_limit) LogMessage(" Limit on TCP Overlaps: %d\n", s5TcpPolicy->overlap_limit); if (s5TcpPolicy->max_queued_bytes != 0) { LogMessage(" Maximum number of bytes to queue per session: %d\n", s5TcpPolicy->max_queued_bytes); } if (s5TcpPolicy->max_queued_segs != 0) { LogMessage(" Maximum number of segs to queue per session: %d\n", s5TcpPolicy->max_queued_segs); } if (s5TcpPolicy->flags) { LogMessage(" Options:\n"); if (s5TcpPolicy->flags & STREAM5_CONFIG_REQUIRE_3WHS) { LogMessage(" Require 3-Way Handshake: YES\n"); if (s5TcpPolicy->hs_timeout != 0) { LogMessage(" 3-Way Handshake Timeout: %d\n", s5TcpPolicy->hs_timeout); } } if (s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS) { LogMessage(" Detect Anomalies: YES\n"); } if (s5TcpPolicy->flags & STREAM5_CONFIG_STATIC_FLUSHPOINTS) { LogMessage(" Static Flushpoint Sizes: YES\n"); } if (s5TcpPolicy->flags & STREAM5_CONFIG_PERFORMANCE) { LogMessage(" Don't Queue Large Packets for Reassembly: YES\n"); } if (s5TcpPolicy->flags & STREAM5_CONFIG_CHECK_SESSION_HIJACKING) { LogMessage(" Check for TCP Session Hijacking: YES\n"); } if (s5TcpPolicy->flags & STREAM5_CONFIG_IGNORE_ANY) { LogMessage(" Ignore Any -> Any Rules: YES\n"); } if (s5TcpPolicy->flags & STREAM5_CONFIG_NO_ASYNC_REASSEMBLY) { LogMessage(" Don't queue packets on one-sided sessions: YES\n"); } } LogMessage(" Reassembly Ports:\n"); for (i=0; iflush_config[i].client.flush_policy; int server_flushpolicy = s5TcpPolicy->flush_config[i].server.flush_policy; char client_policy_str[STD_BUF]; char server_policy_str[STD_BUF]; client_policy_str[0] = server_policy_str[0] = '\0'; if (client_flushpolicy != STREAM_FLPOLICY_IGNORE) { direction |= SSN_DIR_FROM_CLIENT; if (client_flushpolicy < STREAM_FLPOLICY_MAX) SnortSnprintf(client_policy_str, STD_BUF, "client (%s)", flush_policy_names[client_flushpolicy]); } if (server_flushpolicy != STREAM_FLPOLICY_IGNORE) { direction |= SSN_DIR_FROM_SERVER; if (server_flushpolicy < STREAM_FLPOLICY_MAX) SnortSnprintf(server_policy_str, STD_BUF, "server (%s)", flush_policy_names[server_flushpolicy]); } if (direction) { if (j MAX_PORTS_TO_PRINT) { LogMessage(" additional ports configured but not printed.\n"); } } #ifdef TARGET_BASED int StreamPolicyIdFromHostAttributeEntry(HostAttributeEntry *host_entry) { if (!host_entry) return 0; host_entry->hostInfo.streamPolicy = StreamPolicyIdFromName(host_entry->hostInfo.streamPolicyName); host_entry->hostInfo.streamPolicySet = 1; STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "STREAM5 INIT: %s(%d) for Entry %s\n", reassembly_policy_names[host_entry->hostInfo.streamPolicy], host_entry->hostInfo.streamPolicy, host_entry->hostInfo.streamPolicyName);); return 0; } #endif void Stream5PostConfigTcp (struct _SnortConfig *sc, void* pv) { // nothing to do here } void s5TcpPrintPortFilter(); /** * Stream5VerifyTcpConfig is is called after all preprocs (static & dynamic) * are inited. */ int Stream5VerifyTcpConfig(struct _SnortConfig *sc, Stream5TcpConfig *config, tSfPolicyId policy_id) { if (config == NULL) return -1; if (!tcp_lws_cache) { LogMessage("WARNING: Stream5 TCP Session Cache not initialized.\n"); return -1; } if (config->num_policies == 0) { LogMessage("WARNING: Stream5 TCP no policies specified in configuration.\n"); return -1; } if (config->default_policy == NULL) { LogMessage("WARNING: Stream5 TCP default policy not specified in configuration.\n"); return -1; } /* Do this now * verify config is called after all preprocs (static & dynamic) * are inited. Gives us the correct number of bits for * p->preprocessor_bits */ if (!s5_pkt) Stream5InitPacket(); #ifdef TARGET_BASED SFAT_SetPolicyIds(StreamPolicyIdFromHostAttributeEntry, policy_id); #endif /* Post-process TCP rules to establish TCP ports to inspect. */ setPortFilterList(sc, config->port_filter, IPPROTO_TCP, (config->default_policy->flags & STREAM5_CONFIG_IGNORE_ANY), policy_id); //printf ("TCP Ports with Inspection/Monitoring\n"); //s5PrintPortFilter(config->tcpPortFilter); return 0; } uint32_t Stream5GetTcpPrunes(void) { return tcp_lws_cache ? tcp_lws_cache->prunes : s5stats.tcp_prunes; } void Stream5ResetTcpPrunes(void) { if ( tcp_lws_cache ) tcp_lws_cache->prunes = 0; } void Stream5ResetTcp(void) { if (snort_conf == NULL) { ErrorMessage("Snort configuration is NULL.\n"); return; } /* Unset decoder flags for the purge */ targetPolicyIterate(policyDecoderFlagsSaveNClear); s5_tcp_cleanup = 1; PurgeLWSessionCache(tcp_lws_cache); s5_tcp_cleanup = 0; mempool_clean(&tcp_session_mempool); /* Set decoder flags back to original */ targetPolicyIterate(policyDecoderFlagsRestore); ResetFlushMgrs(); } void Stream5CleanTcp(void) { if (snort_conf == NULL) { ErrorMessage("Snort configuration is NULL.\n"); return; } if ( tcp_lws_cache ) s5stats.tcp_prunes = tcp_lws_cache->prunes; /* Turn off decoder alerts since we're decoding stored * packets that we already alerted on. */ targetPolicyIterate(policyDecoderFlagsSaveNClear); /* Set s5_tcp_cleanup to force a flush of all queued data */ s5_tcp_cleanup = 1; /* Clean up hash table -- delete all sessions */ DeleteLWSessionCache(tcp_lws_cache); tcp_lws_cache = NULL; /* Cleanup the rebuilt packet */ if (s5_pkt) { Encode_Delete(s5_pkt); s5_pkt = NULL; } /* Reset this */ s5_tcp_cleanup = 0; mempool_destroy(&tcp_session_mempool); /* And turn decoder alerts back on (or whatever they were set to) */ targetPolicyIterate(policyDecoderFlagsRestore); } void Stream5TcpConfigFree(Stream5TcpConfig *config) { int i; if (config == NULL) return; /* Cleanup TCP Policies and the list */ for (i = 0; i < config->num_policies; i++) { Stream5TcpPolicy *policy = config->policy_list[i]; free(policy->flush_point_list.flush_points); if (policy->bound_addrs != NULL) sfvar_free(policy->bound_addrs); free(policy); } if ( config->paf_config ) s5_paf_delete(config->paf_config); free(config->policy_list); free(config); } #ifdef DEBUG_STREAM5 static void PrintStateMgr(StateMgr *s) { LogMessage("StateMgr:\n"); LogMessage(" state: %s\n", state_names[s->state]); LogMessage(" state_queue: %s\n", state_names[s->state_queue]); LogMessage(" expected_flags: 0x%X\n", s->expected_flags); LogMessage(" transition_seq: 0x%X\n", s->transition_seq); LogMessage(" stq_get_seq: %d\n", s->stq_get_seq); } static void PrintStreamTracker(StreamTracker *s) { LogMessage(" + StreamTracker +\n"); LogMessage(" isn: 0x%X\n", s->isn); LogMessage(" ts_last: %u\n", s->ts_last); LogMessage(" wscale: %u\n", s->wscale); LogMessage(" mss: 0x%08X\n", s->mss); LogMessage(" l_unackd: %X\n", s->l_unackd); LogMessage(" l_nxt_seq: %X\n", s->l_nxt_seq); LogMessage(" l_window: %u\n", s->l_window); LogMessage(" r_nxt_ack: %X\n", s->r_nxt_ack); LogMessage(" r_win_base: %X\n", s->r_win_base); LogMessage(" seglist_base_seq: %X\n", s->seglist_base_seq); LogMessage(" seglist: %p\n", (void*)s->seglist); LogMessage(" seglist_tail: %p\n", (void*)s->seglist_tail); LogMessage(" seg_count: %d\n", s->seg_count); LogMessage(" seg_bytes_total: %d\n", s->seg_bytes_total); LogMessage(" seg_bytes_logical: %d\n", s->seg_bytes_logical); PrintStateMgr(&s->s_mgr); } static void PrintTcpSession(TcpSession *ts) { char buf[64]; LogMessage("TcpSession:\n"); #ifdef DEBUG LogMessage(" ssn_time: %lu\n", ts->ssn_time.tv_sec); #endif sfip_ntop(&ts->tcp_server_ip, buf, sizeof(buf)); LogMessage(" server IP: %s\n", buf); sfip_ntop(&ts->tcp_client_ip, buf, sizeof(buf)); LogMessage(" client IP: %s\n", buf); LogMessage(" server port: %d\n", ts->tcp_server_port); LogMessage(" client port: %d\n", ts->tcp_client_port); LogMessage(" flags: 0x%X\n", ts->lwssn->ha_state.session_flags); LogMessage("Client Tracker:\n"); PrintStreamTracker(&ts->client); LogMessage("Server Tracker:\n"); PrintStreamTracker(&ts->server); } static void PrintTcpDataBlock(TcpDataBlock *tdb) { LogMessage("TcpDataBlock:\n"); LogMessage(" seq: 0x%08X\n", tdb->seq); LogMessage(" ack: 0x%08X\n", tdb->ack); LogMessage(" win: %d\n", tdb->win); LogMessage(" end: 0x%08X\n", tdb->end_seq); } #ifdef DEBUG_STREAM5 static void PrintFlushMgr(FlushMgr *fm) { if(fm == NULL) return; switch(fm->flush_policy) { case STREAM_FLPOLICY_NONE: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " NONE\n");); break; case STREAM_FLPOLICY_FOOTPRINT: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " FOOTPRINT %d\n", fm->flush_pt);); break; case STREAM_FLPOLICY_LOGICAL: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " LOGICAL %d\n", fm->flush_pt);); break; case STREAM_FLPOLICY_RESPONSE: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " RESPONSE\n");); break; case STREAM_FLPOLICY_SLIDING_WINDOW: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " SLIDING_WINDOW %d\n", fm->flush_pt);); break; #if 0 case STREAM_FLPOLICY_CONSUMED: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " CONSUMED %d\n", fm->flush_pt);); break; #endif case STREAM_FLPOLICY_IGNORE: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " IGNORE\n");); break; case STREAM_FLPOLICY_PROTOCOL: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " PROTOCOL\n");); break; } } #endif // DEBUG #endif // DEBUG_STREAM5 static inline void Discard () { s5stats.tcp_discards++; } static inline void EventSynOnEst(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_SYN_ON_EST, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_SYN_ON_EST_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventExcessiveOverlap(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_EXCESSIVE_TCP_OVERLAPS, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_EXCESSIVE_TCP_OVERLAPS_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventBadTimestamp(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_BAD_TIMESTAMP, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_BAD_TIMESTAMP_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventWindowTooLarge(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_WINDOW_TOO_LARGE, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_WINDOW_TOO_LARGE_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventDataOnSyn(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_DATA_ON_SYN, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_DATA_ON_SYN_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventDataOnClosed(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_DATA_ON_CLOSED, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_DATA_ON_CLOSED_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventDataAfterReset(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_DATA_AFTER_RESET, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_DATA_AFTER_RESET_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventBadSegment(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_BAD_SEGMENT, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_BAD_SEGMENT_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventSessionHijackedClient(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_SESSION_HIJACKED_CLIENT, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_SESSION_HIJACKED_CLIENT_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventSessionHijackedServer(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_SESSION_HIJACKED_SERVER, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_SESSION_HIJACKED_SERVER_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventDataWithoutFlags(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_DATA_WITHOUT_FLAGS, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_DATA_WITHOUT_FLAGS_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventMaxSmallSegsExceeded(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_SMALL_SEGMENT, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_SMALL_SEGMENT_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void Event4whs(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_4WAY_HANDSHAKE, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_4WAY_HANDSHAKE_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventNoTimestamp(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_NO_TIMESTAMP, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_NO_TIMESTAMP_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventBadReset(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_BAD_RST, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_BAD_RST_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventBadFin(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_BAD_FIN, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_BAD_FIN_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventBadAck(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_BAD_ACK, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_BAD_ACK_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventDataAfterRstRcvd(Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_DATA_AFTER_RST_RCVD, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_DATA_AFTER_RST_RCVD_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventInternal (uint32_t eventSid) { if ( !InternalEventIsEnabled(snort_conf->rate_filter_config, eventSid) ) return; s5stats.internalEvents++; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5 raised internal event %d\n", eventSid);); SnortEventqAdd(GENERATOR_INTERNAL, /* GID */ eventSid, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_INTERNAL_EVENT_STR, /* event msg*/ NULL); /* rule info ptr */ } static inline void EventWindowSlam (Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_WINDOW_SLAM, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_WINDOW_SLAM_STR, /* event msg */ NULL); /* rule info ptr */ } static inline void EventNo3whs (Stream5TcpPolicy *s5TcpPolicy) { if(!(s5TcpPolicy->flags & STREAM5_CONFIG_ENABLE_ALERTS)) return; s5stats.events++; SnortEventqAdd(GENERATOR_SPP_STREAM5, /* GID */ STREAM5_NO_3WHS, /* SID */ 1, /* rev */ 0, /* class */ 3, /* priority */ STREAM5_NO_3WHS_STR, /* event msg */ NULL); /* rule info ptr */ } /* * Utility functions for TCP stuff */ #ifdef NORMALIZER typedef enum { PC_TCP_TRIM, PC_TCP_ECN_SSN, PC_TCP_TS_NOP, PC_TCP_IPS_DATA, PC_TCP_BLOCK, PC_MAX } PegCounts; static uint64_t normStats[PC_MAX]; static const char* pegName[PC_MAX] = { "tcp::trim", "tcp::ecn_ssn", "tcp::ts_nop", "tcp::ips_data", "tcp::block", }; void Stream_PrintNormalizationStats (void) { int i; // header output by normalizer for ( i = 0; i < PC_MAX; i++ ) { // same alignment as in Norm_PrintStats() LogMessage("%23s: " STDu64 "\n", pegName[i], normStats[i]); } } void Stream_ResetNormalizationStats (void) { memset(normStats, 0, sizeof(normStats)); } //----------------------------------------------------------------------- // instead of centralizing all these normalizations so that // Normalize_IsEnabled() is called only once, the checks and // normalizations are localized. this should lead to many // fewer total checks. however, it is best to minimize // configuration checks on a per packet basis so there is // still room for improvement. static inline void NormalDropPacket (Packet* p) { Active_DropPacket(p); } static inline int NormalDropPacketIf (Packet* p, NormFlags f) { if ( Normalize_IsEnabled(snort_conf, f) ) { NormalDropPacket(p); normStats[PC_TCP_BLOCK]++; sfBase.iPegs[PERF_COUNT_TCP_BLOCK]++; return 1; } return 0; } static inline void NormalStripTimeStamp (Packet* p, int i) { uint8_t* opt; if ( i < 0 ) { for ( i = 0; i < p->tcp_option_count; i++ ) { if ( p->tcp_options[i].code == TCPOPT_TIMESTAMP ) break; } if ( i == p->tcp_option_count ) return; } // first set raw option bytes to nops opt = (uint8_t*)p->tcp_options[i].data - 2; memset(opt, TCPOPT_NOP, TCPOLEN_TIMESTAMP); // then nop decoded option code only p->tcp_options[i].code = TCPOPT_NOP; p->packet_flags |= PKT_MODIFIED; normStats[PC_TCP_TS_NOP]++; sfBase.iPegs[PERF_COUNT_TCP_TS_NOP]++; } static inline void NormalTrimPayload ( Packet* p, uint16_t max, TcpDataBlock* tdb ) { if ( p->dsize > max ) { uint16_t fat = p->dsize - max; p->dsize = max; p->packet_flags |= (PKT_MODIFIED|PKT_RESIZED); tdb->end_seq -= fat; normStats[PC_TCP_TRIM]++; sfBase.iPegs[PERF_COUNT_TCP_TRIM]++; } } static inline int NormalTrimPayloadIf ( Packet* p, NormFlags f, uint16_t max, TcpDataBlock* tdb ) { if ( Normalize_IsEnabled(snort_conf, f) && p->dsize > max ) { NormalTrimPayload(p, max, tdb); return 1; } return 0; } static inline void NormalTrackECN (TcpSession* s, TCPHdr* tcph, int req3way) { if ( !s ) return; if ( TCP_ISFLAGSET(tcph, TH_SYN|TH_ACK) ) { if ( !req3way || s->ecn ) s->ecn = ((tcph->th_flags & (TH_ECE|TH_CWR)) == TH_ECE); } else if ( TCP_ISFLAGSET(tcph, TH_SYN) ) s->ecn = TCP_ISFLAGSET(tcph, (TH_ECE|TH_CWR)); } static inline void NormalCheckECN (TcpSession* s, Packet* p) { if ( !s->ecn && (p->tcph->th_flags & (TH_ECE|TH_CWR)) ) { ((TCPHdr*)p->tcph)->th_flags &= ~(TH_ECE|TH_CWR); p->packet_flags |= PKT_MODIFIED; normStats[PC_TCP_ECN_SSN]++; sfBase.iPegs[PERF_COUNT_TCP_ECN_SSN]++; } } #else #define NormalDropPacketIf(p, f) #define NormalTrimPayloadIf(p, f, m, t) #define NormalTrackECN(s, h, r) #endif void Stream5UpdatePerfBaseState(SFBASE *sf_base, Stream5LWSession *lwssn, char newState) { if (!lwssn) { return; } switch (newState) { case TCP_STATE_SYN_SENT: if (!(lwssn->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE)) { sf_base->iSessionsInitializing++; lwssn->ha_state.session_flags |= SSNFLAG_COUNTED_INITIALIZE; } break; case TCP_STATE_ESTABLISHED: if (!(lwssn->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH)) { sf_base->iSessionsEstablished++; EventInternal(INTERNAL_EVENT_SESSION_ADD); if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP)) UpdateFlowIPState(&sfFlow, IP_ARG(lwssn->client_ip), IP_ARG(lwssn->server_ip), SFS_STATE_TCP_ESTABLISHED); lwssn->ha_state.session_flags |= SSNFLAG_COUNTED_ESTABLISH; if ((lwssn->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE) && !(lwssn->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING)) { assert(sf_base->iSessionsInitializing); sf_base->iSessionsInitializing--; } } break; case TCP_STATE_CLOSING: if (!(lwssn->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING)) { sf_base->iSessionsClosing++; lwssn->ha_state.session_flags |= SSNFLAG_COUNTED_CLOSING; if (lwssn->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH) { assert(sf_base->iSessionsEstablished); sf_base->iSessionsEstablished--; if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP)) UpdateFlowIPState(&sfFlow, IP_ARG(lwssn->client_ip), IP_ARG(lwssn->server_ip), SFS_STATE_TCP_CLOSED); } else if (lwssn->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE) { assert(sf_base->iSessionsInitializing); sf_base->iSessionsInitializing--; } } break; case TCP_STATE_CLOSED: if (lwssn->ha_state.session_flags & SSNFLAG_COUNTED_CLOSING) { assert(sf_base->iSessionsClosing); sf_base->iSessionsClosing--; } else if (lwssn->ha_state.session_flags & SSNFLAG_COUNTED_ESTABLISH) { assert(sf_base->iSessionsEstablished); sf_base->iSessionsEstablished--; if (perfmon_config && (perfmon_config->perf_flags & SFPERF_FLOWIP)) UpdateFlowIPState(&sfFlow, IP_ARG(lwssn->client_ip), IP_ARG(lwssn->server_ip), SFS_STATE_TCP_CLOSED); } else if (lwssn->ha_state.session_flags & SSNFLAG_COUNTED_INITIALIZE) { assert(sf_base->iSessionsInitializing); sf_base->iSessionsInitializing--; } break; default: break; } sf_base->stream5_mem_in_use = mem_in_use; } //------------------------------------------------------------------------- // ssn ingress is client; ssn egress is server #ifdef HAVE_DAQ_ADDRESS_SPACE_ID static inline void SetPacketHeaderFoo (TcpSession* tcpssn, const Packet* p) { if ( tcpssn->daq_flags & DAQ_PKT_FLAG_NOT_FORWARDING ) { tcpssn->ingress_index = p->pkth->ingress_index; tcpssn->ingress_group = p->pkth->ingress_group; // ssn egress may be unknown, but will be correct tcpssn->egress_index = p->pkth->egress_index; tcpssn->egress_group = p->pkth->egress_group; } else if ( p->packet_flags & PKT_FROM_CLIENT ) { tcpssn->ingress_index = p->pkth->ingress_index; tcpssn->ingress_group = p->pkth->ingress_group; // ssn egress not always correct here } else { // ssn ingress not always correct here tcpssn->egress_index = p->pkth->ingress_index; tcpssn->egress_group = p->pkth->ingress_group; } tcpssn->daq_flags = p->pkth->flags; tcpssn->address_space_id = p->pkth->address_space_id; } static inline void GetPacketHeaderFoo ( const TcpSession* tcpssn, DAQ_PktHdr_t* pkth, uint32_t dir) { if ( (dir & PKT_FROM_CLIENT) || (tcpssn->daq_flags & DAQ_PKT_FLAG_NOT_FORWARDING) ) { pkth->ingress_index = tcpssn->ingress_index; pkth->ingress_group = tcpssn->ingress_group; pkth->egress_index = tcpssn->egress_index; pkth->egress_group = tcpssn->egress_group; } else { pkth->ingress_index = tcpssn->egress_index; pkth->ingress_group = tcpssn->egress_group; pkth->egress_index = tcpssn->ingress_index; pkth->egress_group = tcpssn->ingress_group; } pkth->flags = tcpssn->daq_flags; pkth->address_space_id = tcpssn->address_space_id; } static inline void SwapPacketHeaderFoo (TcpSession* tcpssn) { if ( tcpssn->egress_index != DAQ_PKTHDR_UNKNOWN ) { int32_t ingress_index; int32_t ingress_group; ingress_index = tcpssn->ingress_index; ingress_group = tcpssn->ingress_group; tcpssn->ingress_index = tcpssn->egress_index; tcpssn->ingress_group = tcpssn->egress_group; tcpssn->egress_index = ingress_index; tcpssn->egress_group = ingress_group; } } #endif //------------------------------------------------------------------------- static inline int IsBetween(uint32_t low, uint32_t high, uint32_t cur) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "(%X, %X, %X) = (low, high, cur)\n", low,high,cur);); /* If we haven't seen anything, ie, low & high are 0, return true */ if ((low == 0) && (low == high)) return 1; return (SEQ_GEQ(cur, low) && SEQ_LEQ(cur, high)); } #define SSNFLAG_SEEN_BOTH (SSNFLAG_SEEN_SERVER | SSNFLAG_SEEN_CLIENT) static inline bool TwoWayTraffic (Stream5LWSession* lwssn) { return ( (lwssn->ha_state.session_flags & SSNFLAG_SEEN_BOTH) == SSNFLAG_SEEN_BOTH ); } static inline uint32_t Stream5GetWindow( Stream5LWSession* lwssn, StreamTracker* st, TcpDataBlock* tdb) { int32_t window; if ( st->l_window ) { // don't use the window if we may have missed scaling if ( !(lwssn->session_state & STREAM5_STATE_MIDSTREAM) ) return st->l_window; } // one way zero window is unitialized // two way zero window is actually closed (regardless of scaling) else if ( TwoWayTraffic(lwssn) ) return st->l_window; // ensure the data is in the window window = tdb->end_seq - st->r_win_base; if ( window < 0 ) window = 0; return (uint32_t)window; } // ack number must ack syn static inline int ValidRstSynSent(StreamTracker *st, TcpDataBlock *tdb) { return tdb->ack == st->l_unackd; } // per rfc 793 a rst is valid if the seq number is in window // for all states but syn-sent (handled above). however, we // validate here based on how various implementations actually // handle a rst. static inline int ValidRst( Stream5LWSession* lwssn, StreamTracker *st, TcpDataBlock *tdb) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Checking end_seq (%X) > r_win_base (%X) && " "seq (%X) < r_nxt_ack(%X)\n", tdb->end_seq, st->r_win_base, tdb->seq, st->r_nxt_ack+Stream5GetWindow(lwssn, st, tdb));); switch (st->os_policy) { case STREAM_POLICY_HPUX11: if (SEQ_GEQ(tdb->seq, st->r_nxt_ack)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (>= next seq)!\n");); return 1; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "rst is not valid seq (>= next seq)!\n");); return 0; break; case STREAM_POLICY_FIRST: case STREAM_POLICY_LAST: case STREAM_POLICY_MACOS: case STREAM_POLICY_WINDOWS: case STREAM_POLICY_VISTA: case STREAM_POLICY_WINDOWS2K3: case STREAM_POLICY_HPUX10: case STREAM_POLICY_IRIX: if (SEQ_EQ(tdb->seq, st->r_nxt_ack)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (next seq)!\n");); return 1; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "rst is not valid seq (next seq)!\n");); return 0; break; case STREAM_POLICY_BSD: case STREAM_POLICY_LINUX: case STREAM_POLICY_OLD_LINUX: case STREAM_POLICY_SOLARIS: if(SEQ_GEQ(tdb->end_seq, st->r_win_base)) { // reset must be admitted when window closed if ( SEQ_LEQ(tdb->seq, st->r_win_base+Stream5GetWindow(lwssn, st, tdb)) ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "rst is valid seq (within window)!\n");); return 1; } } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "rst is not valid seq (within window)!\n");); return 0; break; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "rst is not valid!\n");); return 0; } static inline int ValidTimestamp(StreamTracker *talker, StreamTracker *listener, TcpDataBlock *tdb, Packet *p, int *eventcode, int *got_ts) { if(p->tcph->th_flags & TH_RST) return ACTION_NOTHING; #ifdef NORMALIZER #if 0 if ( p->tcph->th_flags & TH_ACK && Normalize_IsEnabled(snort_conf, NORM_TCP_OPT) ) { // FIXTHIS validate tsecr here (check that it was previously sent) // checking for the most recent ts is easy enough must check if // ts are up to date in retransmitted packets } #endif #endif /* * check PAWS */ if((talker->flags & TF_TSTAMP) && (listener->flags & TF_TSTAMP)) { char validate_timestamp = 1; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Checking timestamps for PAWS\n");); *got_ts = Stream5GetTcpTimestamp(p, &tdb->ts, 0); if (*got_ts) { if (listener->tcp_policy->policy == STREAM_POLICY_HPUX11) { /* HPUX 11 ignores timestamps for out of order segments */ if ((listener->flags & TF_PKT_MISSED) || !SEQ_EQ(listener->r_nxt_ack, tdb->seq)) { validate_timestamp = 0; } } if (talker->flags & TF_TSTAMP_ZERO) { /* Handle the case where the 3whs used a 0 timestamp. Next packet * from that endpoint should have a valid timestamp... */ if ((listener->tcp_policy->policy == STREAM_POLICY_LINUX) || (listener->tcp_policy->policy == STREAM_POLICY_WINDOWS2K3)) { /* Linux, Win2k3 et al. do not support timestamps if * the 3whs used a 0 timestamp. */ talker->flags &= ~TF_TSTAMP; listener->flags &= ~TF_TSTAMP; validate_timestamp = 0; } else if ((listener->tcp_policy->policy == STREAM_POLICY_OLD_LINUX) || (listener->tcp_policy->policy == STREAM_POLICY_WINDOWS) || (listener->tcp_policy->policy == STREAM_POLICY_VISTA)) { /* Older Linux (2.2 kernel & earlier), Win32 (non 2K3) * allow the 3whs to use a 0 timestamp. */ talker->flags &= ~TF_TSTAMP_ZERO; if(SEQ_EQ(listener->r_nxt_ack, tdb->seq)) { talker->ts_last = tdb->ts; validate_timestamp = 0; /* Ignore the timestamp for this * first packet, next one will * checked. */ } } } if (validate_timestamp) { int result = 0; if (listener->tcp_policy->policy == STREAM_POLICY_LINUX) { /* Linux 2.6 accepts timestamp values that are off * by one. */ result = (int)((tdb->ts - talker->ts_last) + 1); } else { result = (int)(tdb->ts - talker->ts_last); } if(result < 0) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Packet outside PAWS window, dropping\n");); /* bail, we've got a packet outside the PAWS window! */ //Discard(); *eventcode |= EVENT_BAD_TIMESTAMP; NormalDropPacketIf(p, NORM_TCP_OPT); return ACTION_BAD_PKT; } else if ((talker->ts_last != 0) && ((uint32_t)p->pkth->ts.tv_sec > talker->ts_last_pkt+PAWS_24DAYS)) { /* this packet is from way too far into the future */ STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "packet PAWS timestamp way too far ahead of" "last packet %d %d...\n", p->pkth->ts.tv_sec, talker->ts_last_pkt);); //Discard(); *eventcode |= EVENT_BAD_TIMESTAMP; NormalDropPacketIf(p, NORM_TCP_OPT); return ACTION_BAD_PKT; } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "packet PAWS ok...\n");); } } } else { /* we've got a packet with no timestamp, but 3whs indicated talker * was doing timestamps. This breaks protocol, however, some servers * still ack the packet with the missing timestamp. Log an alert, * but continue to process the packet */ *eventcode |= EVENT_NO_TIMESTAMP; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "packet no timestamp, had one earlier from this side...ok for now...\n");); if (listener->tcp_policy->policy == STREAM_POLICY_SOLARIS) { /* Solaris stops using timestamps if it receives a packet * without a timestamp and there were timestamps in use. */ listener->flags &= ~TF_TSTAMP; } NormalDropPacketIf(p, NORM_TCP_OPT); } } else if ( TCP_ISFLAGSET(p->tcph, TH_SYN) && !TCP_ISFLAGSET(p->tcph, TH_ACK) ) { *got_ts = Stream5GetTcpTimestamp(p, &tdb->ts, 0); if ( *got_ts ) talker->flags |= TF_TSTAMP; } else { #ifdef NORMALIZER // if we are not handling timestamps, and this isn't a syn // (only), and we have seen a valid 3way setup, then we strip // (nop) the timestamp option. this includes the cases where // we disable timestamp handling. int strip = ( SetupOK(talker) && SetupOK(listener) ); #else int strip = 0; #endif STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "listener not doing timestamps...\n");); *got_ts = Stream5GetTcpTimestamp(p, &tdb->ts, strip); if (*got_ts) { if (!(talker->flags & TF_TSTAMP)) { /* Since we skipped the SYN, may have missed the talker's * timestamp there, so set it now. */ talker->flags |= TF_TSTAMP; if (tdb->ts == 0) { talker->flags |= TF_TSTAMP_ZERO; } } /* Only valid to test this if listener is using timestamps. * Otherwise, timestamp in this packet is not used, regardless * of its value. */ if ((tdb->ts == 0) && (listener->flags & TF_TSTAMP)) { switch (listener->os_policy) { case STREAM_POLICY_WINDOWS: case STREAM_POLICY_VISTA: case STREAM_POLICY_WINDOWS2K3: case STREAM_POLICY_OLD_LINUX: case STREAM_POLICY_SOLARIS: /* Old Linux & Windows allows a 0 timestamp value. */ break; default: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Packet with 0 timestamp, dropping\n");); //Discard(); /* bail */ *eventcode |= EVENT_BAD_TIMESTAMP; return ACTION_BAD_PKT; } } } } return ACTION_NOTHING; } #ifdef S5_PEDANTIC // From RFC 793: // // Segment Receive Test // Length Window // ------- ------- ------------------------------------------- // // 0 0 SEG.SEQ = RCV.NXT // // 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND // // >0 0 not acceptable // // >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND // or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND // static inline int ValidSeq( const Packet* p, Stream5LWSession* lwssn, StreamTracker *st, TcpDataBlock *tdb) { uint32_t win = Stream5GetWindow(lwssn, st, tdb); if ( !p->dsize ) { if ( !win ) { return ( tdb->seq == st->r_win_base ); } return SEQ_LEQ(st->r_win_base, tdb->seq) && SEQ_LT(tdb->seq, st->r_win_base+win); } if ( !win ) return 0; if ( SEQ_LEQ(st->r_win_base, tdb->seq) && SEQ_LT(tdb->seq, st->r_win_base+win) ) return 1; return SEQ_LEQ(st->r_win_base, tdb->end_seq) && SEQ_LT(tdb->end_seq, st->r_win_base+win); } #else static inline int ValidSeq( const Packet* p, Stream5LWSession* lwssn, StreamTracker *st, TcpDataBlock *tdb) { int right_ok; uint32_t left_seq; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Checking end_seq (%X) > r_win_base (%X) && " "seq (%X) < r_nxt_ack(%X)\n", tdb->end_seq, st->r_win_base, tdb->seq, st->r_nxt_ack+Stream5GetWindow(lwssn, st, tdb));); if ( SEQ_LT(st->r_nxt_ack, st->r_win_base) ) left_seq = st->r_nxt_ack; else left_seq = st->r_win_base; if ( p->dsize ) right_ok = SEQ_GT(tdb->end_seq, left_seq); else right_ok = SEQ_GEQ(tdb->end_seq, left_seq); if ( right_ok ) { uint32_t win = Stream5GetWindow(lwssn, st, tdb); if( SEQ_LEQ(tdb->seq, st->r_win_base+win) ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seq is within window!\n");); return 1; } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seq is past the end of the window!\n");); } } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "end_seq is before win_base\n");); } return 0; } #endif static inline void UpdateSsn( Packet* p, StreamTracker *rcv, StreamTracker *snd, TcpDataBlock *tdb) { #if 0 #ifdef NORMALIZER if ( // FIXTHIS these checks are a hack to avoid off by one normalization // due to FIN ... if last segment filled a hole, r_nxt_ack is not at // end of data, FIN is ignored so sequence isn't bumped, and this // forces seq-- on ACK of FIN. :( rcv->s_mgr.state == TCP_STATE_ESTABLISHED && rcv->s_mgr.state_queue == TCP_STATE_NONE && Normalize_IsEnabled(snort_conf, NORM_TCP_IPS) ) { // walk the seglist until a gap or tdb->ack whichever is first // if a gap exists prior to ack, move ack back to start of gap StreamSegment* seg = snd->seglist; // FIXTHIS must check ack oob with empty seglist // FIXTHIS add lower gap bound to tracker for efficiency? while ( seg ) { uint32_t seq = seg->seq + seg->size; if ( SEQ_LEQ(tdb->ack, seq) ) break; seg = seg->next; if ( !seg || seg->seq > seq ) { // normalize here tdb->ack = seq; ((TCPHdr*)p->tcph)->th_ack = htonl(seq); p->packet_flags |= PKT_MODIFIED; break; } } } #endif #endif // ** if we don't see a segment, we can't track seq at ** below // so we update the seq by the ack if it is beyond next expected if(SEQ_GT(tdb->ack, rcv->l_unackd)) rcv->l_unackd = tdb->ack; // ** this is how we track the last seq number sent // as is l_unackd is the "last left" seq recvd snd->l_unackd = tdb->seq; if (SEQ_GT(tdb->end_seq, snd->l_nxt_seq)) snd->l_nxt_seq = tdb->end_seq; if (!SEQ_EQ(snd->r_win_base, tdb->ack)) { snd->small_seg_count = 0; } #ifdef S5_PEDANTIC if ( SEQ_GT(tdb->ack, snd->r_win_base) && SEQ_LEQ(tdb->ack, snd->r_nxt_ack) ) #else if (SEQ_GT(tdb->ack, snd->r_win_base)) #endif snd->r_win_base = tdb->ack; snd->l_window = tdb->win; } static void Stream5InitPacket(void) { s5_pkt = Encode_New(); } static inline void SetupTcpDataBlock(TcpDataBlock *tdb, Packet *p) { tdb->seq = ntohl(p->tcph->th_seq); tdb->ack = ntohl(p->tcph->th_ack); tdb->win = ntohs(p->tcph->th_win); tdb->end_seq = tdb->seq + (uint32_t) p->dsize; tdb->ts = 0; if(p->tcph->th_flags & TH_SYN) { tdb->end_seq++; if(!(p->tcph->th_flags & TH_ACK)) EventInternal(INTERNAL_EVENT_SYN_RECEIVED); } // don't bump end_seq for fin here // we will bump if/when fin is processed return; } static void SegmentFree (StreamSegment *seg) { unsigned dropped = sizeof(StreamSegment); STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "Dumping segment at seq %X, size %d, caplen %d\n", seg->seq, seg->size, seg->caplen);); if ( seg->caplen > 0 ) dropped += seg->caplen - 1; // seg contains 1st byte mem_in_use -= dropped; free(seg); s5stats.tcp_streamsegs_released++; STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "SegmentFree dropped %d bytes\n", dropped);); } static void DeleteSeglist(StreamSegment *listhead) { StreamSegment *idx = listhead; StreamSegment *dump_me; int i = 0; STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "In DeleteSeglist\n");); while(idx) { i++; dump_me = idx; idx = idx->next; SegmentFree(dump_me); } STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "Dropped %d segments\n", i);); } static inline int purge_alerts(StreamTracker *st, uint32_t flush_seq, void *ssnptr) { int i; int new_count = 0; for (i=0;ialert_count;i++) { Stream5AlertInfo* ai = st->alerts + i; if (SEQ_LT(ai->seq, flush_seq) ) { if(st->xtradata_mask && extra_data_log) { extra_data_log( ssnptr, extra_data_config, xtradata_map, xtradata_func_count, st->xtradata_mask, ai->event_id, ai->event_second); } memset(ai, 0, sizeof(*ai)); } else { if (new_count != i) { st->alerts[new_count] = st->alerts[i]; } new_count++; } } st->alert_count = new_count; return new_count; } static inline int purge_to_seq(TcpSession *tcpssn, StreamTracker *st, uint32_t flush_seq) { StreamSegment *ss = NULL; StreamSegment *dump_me = NULL; int purged_bytes = 0; uint32_t last_ts = 0; if(st->seglist == NULL) { if ( SEQ_LT(st->seglist_base_seq, flush_seq) ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "setting st->seglist_base_seq to 0x%X\n", flush_seq);); st->seglist_base_seq = flush_seq; } return 0; } ss = st->seglist; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "In purge_to_seq, start seq = 0x%X end seq = 0x%X delta %d\n", ss->seq, flush_seq, flush_seq-ss->seq);); while(ss) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "s: %X sz: %d\n", ss->seq, ss->size);); dump_me = ss; ss = ss->next; if(SEQ_LT(dump_me->seq, flush_seq)) { if (dump_me->ts > last_ts) { last_ts = dump_me->ts; } purged_bytes += Stream5SeglistDeleteNodeTrim(st, dump_me, flush_seq); } else break; } if ( SEQ_LT(st->seglist_base_seq, flush_seq) ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "setting st->seglist_base_seq to 0x%X\n", flush_seq);); st->seglist_base_seq = flush_seq; } if ( SEQ_LT(st->r_nxt_ack, flush_seq) ) st->r_nxt_ack = flush_seq; purge_alerts(st, flush_seq,(void *)tcpssn->lwssn); if (st->seglist == NULL) { st->seglist_tail = NULL; } /* Update the "last" time stamp seen from the other side * to be the most recent timestamp (largest) that was removed * from the queue. This will ensure that as we go forward, * last timestamp is the highest one that we had stored and * purged and handle the case when packets arrive out of order, * such as: * P1: seq 10, length 10, timestamp 10 * P3: seq 30, length 10, timestamp 30 * P2: seq 20, length 10, timestamp 20 * * Without doing it this way, the timestamp would be 20. With * the next packet to arrive (P4, seq 40), the ts_last value * wouldn't be updated for the talker in ProcessTcp() since that * code specificially looks for the NEXT sequence number. */ if ( !last_ts ) return purged_bytes; if (st == &tcpssn->client) { int32_t delta = last_ts - tcpssn->server.ts_last; if (delta > 0) tcpssn->server.ts_last = last_ts; } else if (st == &tcpssn->server) { int32_t delta = last_ts - tcpssn->client.ts_last; if (delta > 0) tcpssn->client.ts_last = last_ts; } return purged_bytes; } static inline void purge_all (StreamTracker *st) { DeleteSeglist(st->seglist); st->seglist = st->seglist_tail = st->seglist_next = NULL; st->seg_count = st->flush_count = 0; st->seg_bytes_total = st->seg_bytes_logical = 0; } // purge_flushed_ackd(): // * must only purge flushed and acked bytes // * we may flush partial segments // * must adjust seq->seq and seg->size when a flush gets only the // initial part of a segment // * FIXTHIS need flag to mark any reassembled packets that have a gap // (if we reassemble such) static inline int purge_flushed_ackd (TcpSession *tcpssn, StreamTracker *st) { StreamSegment* seg = st->seglist; uint32_t seq; if ( !st->seglist ) return 0; seq = st->seglist->seq; while ( seg && seg->buffered ) { uint32_t end = seg->seq + seg->size; if ( SEQ_GT(end, st->r_win_base) ) { seq = st->r_win_base; break; } seq = end; seg = seg->next; } if ( seq != st->seglist->seq ) return purge_to_seq(tcpssn, st, seq); return 0; } static void ShowRebuiltPacket (Packet* p) { if(s5_global_eval_config->flags & STREAM5_CONFIG_SHOW_PACKETS) { //ClearDumpBuf(); printf("+++++++++++++++++++Stream Packet+++++++++++++++++++++\n"); PrintIPPkt(stdout, IPPROTO_TCP, p); printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); //ClearDumpBuf(); } } static inline int _flush_to_seq ( TcpSession *tcpssn, StreamTracker *st, uint32_t bytes, Packet *p, snort_ip_p sip, snort_ip_p dip, uint16_t sp, uint16_t dp, uint32_t dir) { uint32_t stop_seq; uint32_t footprint = 0; uint32_t bytes_processed = 0; int32_t flushed_bytes; #ifdef HAVE_DAQ_ADDRESS_SPACE_ID DAQ_PktHdr_t pkth; #endif EncodeFlags enc_flags = 0; PROFILE_VARS; PREPROC_PROFILE_START(s5TcpFlushPerfStats); if ( !p->packet_flags || (dir & p->packet_flags) ) enc_flags = ENC_FLAG_FWD; #ifdef HAVE_DAQ_ADDRESS_SPACE_ID GetPacketHeaderFoo(tcpssn, &pkth, dir); Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, &pkth, 0); #elif defined(HAVE_DAQ_ACQUIRE_WITH_META) Encode_Format_With_DAQ_Info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, 0); #else Encode_Format(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP); #endif s5_pkt_end = s5_pkt->data + s5_pkt->max_dsize; // TBD in ips mode, these should be coming from current packet (tdb) ((TCPHdr *)s5_pkt->tcph)->th_ack = htonl(st->l_unackd); ((TCPHdr *)s5_pkt->tcph)->th_win = htons((uint16_t)st->l_window); // if not specified, set bytes to flush to what was acked if ( !bytes && SEQ_GT(st->r_win_base, st->seglist_base_seq) ) bytes = st->r_win_base - st->seglist_base_seq; stop_seq = st->seglist_base_seq + bytes; do { footprint = stop_seq - st->seglist_base_seq; if(footprint == 0) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Negative footprint, bailing %d (0x%X - 0x%X)\n", footprint, stop_seq, st->seglist_base_seq);); PREPROC_PROFILE_END(s5TcpFlushPerfStats); return bytes_processed; } #ifdef DEBUG_STREAM5 if(footprint < st->seg_bytes_logical) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Footprint less than queued bytes, " "win_base: 0x%X base_seq: 0x%X\n", stop_seq, st->seglist_base_seq);); } #endif if(footprint > s5_pkt->max_dsize) { /* this is as much as we can pack into a stream buffer */ footprint = s5_pkt->max_dsize; stop_seq = st->seglist_base_seq + footprint; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Attempting to flush %lu bytes\n", footprint);); /* setup the pseudopacket payload */ flushed_bytes = FlushStream(p, st, stop_seq, (uint8_t *)s5_pkt->data, s5_pkt_end); if(flushed_bytes == -1) { /* couldn't put a stream together for whatever reason * should probably clean the seglist and bail... */ if(st->seglist) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "dumping entire seglist!\n");); purge_all(st); } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "setting st->seglist_base_seq to 0x%X\n", stop_seq);); st->seglist_base_seq = stop_seq; PREPROC_PROFILE_END(s5TcpFlushPerfStats); return bytes_processed; } if (flushed_bytes == 0) { /* No more ACK'd data... bail */ break; } ((TCPHdr *)s5_pkt->tcph)->th_seq = htonl(st->seglist_next->seq); s5_pkt->packet_flags |= (PKT_REBUILT_STREAM|PKT_STREAM_EST); s5_pkt->dsize = (uint16_t)flushed_bytes; if ((p->packet_flags & PKT_PDU_TAIL)) s5_pkt->packet_flags |= PKT_PDU_TAIL; Encode_Update(s5_pkt); if(sfip_family(sip) == AF_INET) { s5_pkt->inner_ip4h.ip_len = s5_pkt->iph->ip_len; } else { IP6RawHdr* ip6h = (IP6RawHdr*)s5_pkt->raw_ip6h; if ( ip6h ) s5_pkt->inner_ip6h.len = ip6h->ip6plen; } ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_sec = st->seglist_next->tv.tv_sec; ((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_usec = st->seglist_next->tv.tv_usec; sfBase.iStreamFlushes++; bytes_processed += s5_pkt->dsize; s5_pkt->packet_flags |= dir; s5_pkt->ssnptr = (void *) tcpssn->lwssn; #ifdef TARGET_BASED s5_pkt->application_protocol_ordinal = p->application_protocol_ordinal; #endif ShowRebuiltPacket(s5_pkt); s5stats.tcp_rebuilt_packets++; UpdateStreamReassStats(&sfBase, flushed_bytes); PREPROC_PROFILE_TMPEND(s5TcpFlushPerfStats); { int tmp_do_detect, tmp_do_detect_content; PROFILE_VARS; PREPROC_PROFILE_START(s5TcpProcessRebuiltPerfStats); tmp_do_detect = do_detect; tmp_do_detect_content = do_detect_content; SnortEventqPush(); Preprocess(s5_pkt); SnortEventqPop(); DetectReset((uint8_t *)s5_pkt->data, s5_pkt->dsize); do_detect = tmp_do_detect; do_detect_content = tmp_do_detect_content; PREPROC_PROFILE_END(s5TcpProcessRebuiltPerfStats); } PREPROC_PROFILE_TMPSTART(s5TcpFlushPerfStats); // TBD abort should be by PAF callback only since // recovery may be possible in some cases if ( st->flags & TF_MISSING_PKT ) { st->flags |= TF_MISSING_PREV_PKT; st->flags |= TF_PKT_MISSED; st->flags &= ~TF_MISSING_PKT; s5stats.tcp_gaps++; } else { st->flags &= ~TF_MISSING_PREV_PKT; } } while ( DataToFlush(st) ); if ( st->tcp_policy ) UpdateFlushMgr(&st->flush_mgr, &st->tcp_policy->flush_point_list, st->flags); /* tell them how many bytes we processed */ PREPROC_PROFILE_END(s5TcpFlushPerfStats); return bytes_processed; } /* * flush a seglist up to the given point, generate a pseudopacket, * and fire it thru the system. */ static inline int flush_to_seq( TcpSession *tcpssn, StreamTracker *st, uint32_t bytes, Packet *p, snort_ip_p sip, snort_ip_p dip, uint16_t sp, uint16_t dp, uint32_t dir) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "In flush_to_seq()\n");); if ( !bytes ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "bailing, no data\n");); return 0; } if ( !st->seglist_next ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "bailing, bad seglist ptr\n");); return 0; } if (!DataToFlush(st) && !(st->flags & TF_FORCE_FLUSH)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "only 1 packet in seglist no need to flush\n");); return 0; } st->flags &= ~TF_MISSING_PREV_PKT; /* This will set this flag on the first reassembly * if reassembly for this direction was set midstream */ if ( SEQ_LT(st->seglist_base_seq, st->seglist_next->seq) && !(st->flags & TF_FIRST_PKT_MISSING) ) { uint32_t missed = st->seglist_next->seq - st->seglist_base_seq; if ( missed <= bytes ) bytes -= missed; st->flags |= TF_MISSING_PREV_PKT; st->flags |= TF_PKT_MISSED; s5stats.tcp_gaps++; st->seglist_base_seq = st->seglist_next->seq; if ( !bytes ) return 0; } st->flags &= ~TF_FIRST_PKT_MISSING; return _flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir); } /* * get the footprint for the current seglist, the difference * between our base sequence and the last ack'd sequence we * received */ static inline uint32_t get_q_footprint(StreamTracker *st) { uint32_t fp; if (st == NULL) { return 0; } fp = st->r_win_base - st->seglist_base_seq; if(fp <= 0) return 0; st->seglist_next = st->seglist; return fp; } // FIXTHIS get_q_sequenced() performance could possibly be // boosted by tracking sequenced bytes as seglist is updated // to avoid the while loop, etc. below. static inline uint32_t get_q_sequenced(StreamTracker *st) { uint32_t len; StreamSegment* seg = st ? st->seglist : NULL; StreamSegment* base = NULL; if ( !seg ) return 0; if ( SEQ_LT(st->r_win_base, seg->seq) ) return 0; while ( seg->next && (seg->next->seq == seg->seq + seg->size) ) { if ( !seg->buffered && !base ) base = seg; seg = seg->next; } if ( !seg->buffered && !base ) base = seg; if ( !base ) return 0; st->seglist_next = base; st->seglist_base_seq = base->seq; len = seg->seq + seg->size - base->seq; return ( len > 0 ) ? len : 0; } static inline int flush_ackd( TcpSession *tcpssn, StreamTracker *st, Packet *p, snort_ip_p sip, snort_ip_p dip, uint16_t sp, uint16_t dp, uint32_t dir) { uint32_t bytes = get_q_footprint(st); return flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir); } // FIXTHIS flush_stream() calls should be replaced with calls to // CheckFlushPolicyOn*() with the exception that for the *OnAck() case, // any available ackd data must be flushed in both directions. static inline int flush_stream( TcpSession *tcpssn, StreamTracker *st, Packet *p, snort_ip_p sip, snort_ip_p dip, uint16_t sp, uint16_t dp, uint32_t dir) { #ifdef NORMALIZER if ( Normalize_IsEnabled(snort_conf, NORM_TCP_IPS) ) { uint32_t bytes = get_q_sequenced(st); return flush_to_seq(tcpssn, st, bytes, p, sip, dip, sp, dp, dir); } #endif return flush_ackd(tcpssn, st, p, sip, dip, sp, dp, dir); } static inline unsigned int getSegmentFlushSize( StreamTracker* st, StreamSegment *ss, uint32_t to_seq, unsigned int flushBufSize ) { unsigned int flushSize = ss->size; //copy only till flush buffer gets full if ( flushSize > flushBufSize ) flushSize = flushBufSize; // copy only to flush point if ( s5_paf_active(&st->paf_state) && SEQ_GT(ss->seq + flushSize, to_seq) ) flushSize = to_seq - ss->seq; return flushSize; } static int FlushStream( Packet* p, StreamTracker *st, uint32_t toSeq, uint8_t *flushbuf, const uint8_t *flushbuf_end) { StreamSegment *ss = NULL, *seglist, *sr; uint16_t bytes_flushed = 0; uint16_t bytes_skipped = 0; uint32_t bytes_queued = st->seg_bytes_logical; uint32_t segs = 0; int ret; PROFILE_VARS; if ( st->seglist == NULL || st->seglist_tail == NULL ) return -1; PREPROC_PROFILE_START(s5TcpBuildPacketPerfStats); // skip over previously flushed segments seglist = st->seglist_next; for(ss = seglist; ss && SEQ_LT(ss->seq, toSeq); ss = ss->next) { unsigned int flushbuf_size = flushbuf_end - flushbuf; unsigned int bytes_to_copy = getSegmentFlushSize(st, ss, toSeq, flushbuf_size); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Flushing %u bytes from %X\n", bytes_to_copy, ss->seq)); if(ss->urg_offset == 1) { /* if urg_offset is set, seq + urg_offset is seq # of octet * in stream following the last urgent octet. all preceding * octets in segment are considered urgent. this code will * skip over the urgent data when flushing. */ unsigned int non_urgent_bytes = ss->urg_offset < bytes_to_copy ? (bytes_to_copy - ss->urg_offset) : 0; if ( non_urgent_bytes ) { ret = SafeMemcpy(flushbuf, ss->payload+ss->urg_offset, non_urgent_bytes, flushbuf, flushbuf_end); if (ret == SAFEMEM_ERROR) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "ERROR writing flushbuf attempting to " "write flushbuf out of range!\n");); } else flushbuf += non_urgent_bytes; bytes_skipped += ss->urg_offset; } } else { ret = SafeMemcpy(flushbuf, ss->payload, bytes_to_copy, flushbuf, flushbuf_end); if (ret == SAFEMEM_ERROR) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "ERROR writing flushbuf attempting to " "write flushbuf out of range!\n");); } else flushbuf += bytes_to_copy; } if ( bytes_to_copy < ss->size && DupStreamNode(NULL, st, ss, &sr) == STREAM_INSERT_OK ) { ss->size = bytes_to_copy; sr->seq += bytes_to_copy; sr->size -= bytes_to_copy; sr->payload += bytes_to_copy + (ss->payload - ss->data); } bytes_flushed += bytes_to_copy; ss->buffered = SL_BUF_FLUSHED; st->flush_count++; segs++; if ( flushbuf >= flushbuf_end ) break; if ( SEQ_EQ(ss->seq + bytes_to_copy, toSeq) ) break; /* Check for a gap/missing packet */ // FIXTHIS PAF should account for missing data and resume // scanning at the start of next PDU instead of aborting. // FIXTHIS FIN may be in toSeq causing bogus gap counts. if ( ((ss->next && (ss->seq + ss->size != ss->next->seq)) || (!ss->next && (ss->seq + ss->size < toSeq))) && !(st->flags & TF_FIRST_PKT_MISSING) ) { if ( ss->next ) { toSeq = ss->next->seq; st->seglist_next = ss->next; } st->flags |= TF_MISSING_PKT; break; } } st->seglist_base_seq = toSeq; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "setting st->seglist_base_seq to 0x%X\n", st->seglist_base_seq);); bytes_queued -= bytes_flushed; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "flushed %d bytes / %d segs on stream, " "skipped %d bytes, %d still queued\n", bytes_flushed, segs, bytes_skipped, bytes_queued);); PREPROC_PROFILE_END(s5TcpBuildPacketPerfStats); return bytes_flushed - bytes_skipped; } int Stream5FlushServer(Packet *p, Stream5LWSession *lwssn) { int flushed; TcpSession *tcpssn = NULL; StreamTracker *flushTracker = NULL; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return 0; flushTracker = &tcpssn->server; flushTracker->flags |= TF_FORCE_FLUSH; /* If this is a rebuilt packet, don't flush now because we'll * overwrite the packet being processed. */ if (p->packet_flags & PKT_REBUILT_STREAM) { /* We'll check & clear the TF_FORCE_FLUSH next time through */ return 0; } /* Need to convert the addresses to network order */ flushed = flush_stream(tcpssn, flushTracker, p, &tcpssn->tcp_server_ip, &tcpssn->tcp_client_ip, tcpssn->tcp_server_port, tcpssn->tcp_client_port, PKT_FROM_SERVER); if (flushed) purge_flushed_ackd(tcpssn, flushTracker); flushTracker->flags &= ~TF_FORCE_FLUSH; return flushed; } int Stream5FlushClient(Packet *p, Stream5LWSession *lwssn) { int flushed; TcpSession *tcpssn = NULL; StreamTracker *flushTracker = NULL; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return 0; flushTracker = &tcpssn->client; flushTracker->flags |= TF_FORCE_FLUSH; /* If this is a rebuilt packet, don't flush now because we'll * overwrite the packet being processed. */ if (p->packet_flags & PKT_REBUILT_STREAM) { /* We'll check & clear the TF_FORCE_FLUSH next time through */ return 0; } /* Need to convert the addresses to network order */ flushed = flush_stream(tcpssn, flushTracker, p, &tcpssn->tcp_client_ip, &tcpssn->tcp_server_ip, tcpssn->tcp_client_port, tcpssn->tcp_server_port, PKT_FROM_CLIENT); if (flushed) purge_flushed_ackd(tcpssn, flushTracker); flushTracker->flags &= ~TF_FORCE_FLUSH; return flushed; } int Stream5FlushListener(Packet *p, Stream5LWSession *lwssn) { TcpSession *tcpssn = NULL; StreamTracker *listener = NULL; int dir = 0; int flushed = 0; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return 0; /* figure out direction of this packet -- we should've already * looked at it, so the packet_flags are already set. */ if(p->packet_flags & PKT_FROM_SERVER) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Flushing listener on packet from server\n");); listener = &tcpssn->client; /* dir of flush is the data from the opposite side */ dir = PKT_FROM_SERVER; } else if (p->packet_flags & PKT_FROM_CLIENT) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Flushing listener on packet from client\n");); listener = &tcpssn->server; /* dir of flush is the data from the opposite side */ dir = PKT_FROM_CLIENT; } if (dir != 0) { listener->flags |= TF_FORCE_FLUSH; flushed = flush_stream(tcpssn, listener, p, GET_SRC_IP(p), GET_DST_IP(p), p->tcph->th_sport, p->tcph->th_dport, dir); if (flushed) purge_flushed_ackd(tcpssn, listener); listener->flags &= ~TF_FORCE_FLUSH; } return flushed; } int Stream5FlushTalker(Packet *p, Stream5LWSession *lwssn) { TcpSession *tcpssn = NULL; StreamTracker *talker = NULL; int dir = 0; int flushed = 0; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) { return 0; } /* figure out direction of this packet -- we should've already * looked at it, so the packet_flags are already set. */ if(p->packet_flags & PKT_FROM_SERVER) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Flushing talker on packet from server\n");); talker = &tcpssn->server; /* dir of flush is the data from the opposite side */ dir = PKT_FROM_CLIENT; } else if (p->packet_flags & PKT_FROM_CLIENT) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Flushing talker on packet from client\n");); talker = &tcpssn->client; /* dir of flush is the data from the opposite side */ dir = PKT_FROM_SERVER; } if (dir != 0) { talker->flags |= TF_FORCE_FLUSH; flushed = flush_stream(tcpssn, talker, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, dir); if (flushed) purge_flushed_ackd(tcpssn, talker); talker->flags &= ~TF_FORCE_FLUSH; } return flushed; } static void TcpSessionClear (Stream5LWSession* lwssn, TcpSession* tcpssn, int freeApplicationData) { STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "In TcpSessionClear, %lu bytes in use\n", mem_in_use);); STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "client has %d segs queued\n", tcpssn->client.seg_count);); STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "server has %d segs queued\n", tcpssn->server.seg_count);); // update stats s5stats.tcp_streamtrackers_released++; Stream5UpdatePerfBaseState(&sfBase, tcpssn->lwssn, TCP_STATE_CLOSED); RemoveStreamSession(&sfBase); if (lwssn->ha_state.session_flags & SSNFLAG_PRUNED) { CloseStreamSession(&sfBase, SESSION_CLOSED_PRUNED); } else if (lwssn->ha_state.session_flags & SSNFLAG_TIMEDOUT) { CloseStreamSession(&sfBase, SESSION_CLOSED_TIMEDOUT); } else { CloseStreamSession(&sfBase, SESSION_CLOSED_NORMALLY); } // release external state if (freeApplicationData) FreeLWApplicationData(lwssn); Stream5ResetFlowBits(lwssn); // release internal protocol specific state purge_all(&tcpssn->client); purge_all(&tcpssn->server); s5_paf_clear(&tcpssn->client.paf_state); s5_paf_clear(&tcpssn->server.paf_state); mempool_free(&tcp_session_mempool, lwssn->proto_specific_data); lwssn->proto_specific_data = NULL; // update light-weight state lwssn->ha_state.session_flags = SSNFLAG_NONE; lwssn->session_state = STREAM5_STATE_NONE; lwssn->expire_time = 0; lwssn->ha_state.ignore_direction = 0; // generate event for rate filtering EventInternal(INTERNAL_EVENT_SESSION_DEL); STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "After cleaning, %lu bytes in use\n", mem_in_use);); } static void TcpSessionCleanup(Stream5LWSession *lwssn, int freeApplicationData) { DAQ_PktHdr_t tmp_pcap_hdr; TcpSession *tcpssn = NULL; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) { /* Huh? */ Stream5UpdatePerfBaseState(&sfBase, lwssn, TCP_STATE_CLOSED); return; } /* Flush ack'd data on both sides as necessary */ { Packet p; int flushed; if (!s5_tcp_cleanup) { /* Turn off decoder alerts since we're decoding stored * packets that we already alerted on. */ policyDecoderFlagsSaveNClear(lwssn->policy_id); } /* Flush the client */ if (tcpssn->client.seglist && !(lwssn->ha_state.ignore_direction & SSN_DIR_FROM_SERVER) ) { pc.s5tcp1++; /* Do each field individually because of size differences on 64bit OS */ tmp_pcap_hdr.ts.tv_sec = tcpssn->client.seglist->tv.tv_sec; tmp_pcap_hdr.ts.tv_usec = tcpssn->client.seglist->tv.tv_usec; tmp_pcap_hdr.caplen = tcpssn->client.seglist->caplen; tmp_pcap_hdr.pktlen = tcpssn->client.seglist->pktlen; SnortEventqPush(); (*grinder)(&p, &tmp_pcap_hdr, tcpssn->client.seglist->pkt); p.ssnptr = lwssn; //set policy id for this packet { int vlanId = (p.vh)? VTH_VLAN(p.vh) : -1; snort_ip_p srcIp = (p.iph)? GET_SRC_IP((&p)) : (snort_ip_p)0; snort_ip_p dstIp = (p.iph)? GET_DST_IP((&p)) : (snort_ip_p)0; setRuntimePolicy(sfGetApplicablePolicyId( snort_conf->policy_config, vlanId, srcIp, dstIp)); p.configPolicyId = snort_conf->targeted_policies[getRuntimePolicy()]->configPolicyId; //actions are queued only for IDS case sfActionQueueExecAll(decoderActionQ); } SnortEventqPop(); tcpssn->client.flags |= TF_FORCE_FLUSH; if ( !p.tcph ) { flushed = 0; } else { flushed = flush_stream(tcpssn, &tcpssn->client, &p, p.iph_api->iph_ret_src(&p), p.iph_api->iph_ret_dst(&p), p.tcph->th_sport, p.tcph->th_dport, PKT_FROM_SERVER); } if (flushed) purge_flushed_ackd(tcpssn, &tcpssn->client); else { SnortEventqPush(); SnortEventqLog(snort_conf->event_queue, &p); SnortEventqReset(); SnortEventqPop(); } tcpssn->client.flags &= ~TF_FORCE_FLUSH; } /* Flush the server */ if (tcpssn->server.seglist && !(lwssn->ha_state.ignore_direction & SSN_DIR_FROM_CLIENT) ) { pc.s5tcp2++; /* Do each field individually because of size differences on 64bit OS */ tmp_pcap_hdr.ts.tv_sec = tcpssn->server.seglist->tv.tv_sec; tmp_pcap_hdr.ts.tv_usec = tcpssn->server.seglist->tv.tv_usec; tmp_pcap_hdr.caplen = tcpssn->server.seglist->caplen; tmp_pcap_hdr.pktlen = tcpssn->server.seglist->pktlen; SnortEventqPush(); (*grinder)(&p, &tmp_pcap_hdr, tcpssn->server.seglist->pkt); //set policy id for this packet { int vlanId = (p.vh)? VTH_VLAN(p.vh) : -1; snort_ip_p srcIp = (p.iph)? GET_SRC_IP((&p)) : (snort_ip_p)0; snort_ip_p dstIp = (p.iph)? GET_DST_IP((&p)) : (snort_ip_p)0; setRuntimePolicy(sfGetApplicablePolicyId( snort_conf->policy_config, vlanId, srcIp, dstIp)); p.configPolicyId = snort_conf->targeted_policies[getRuntimePolicy()]->configPolicyId; //actions are queued only for IDS case sfActionQueueExecAll(decoderActionQ); } SnortEventqPop(); p.ssnptr = lwssn; tcpssn->server.flags |= TF_FORCE_FLUSH; if ( !p.tcph ) { flushed = 0; } else { flushed = flush_stream(tcpssn, &tcpssn->server, &p, p.iph_api->iph_ret_src(&p), p.iph_api->iph_ret_dst(&p), p.tcph->th_sport, p.tcph->th_dport, PKT_FROM_CLIENT); } if (flushed) purge_flushed_ackd(tcpssn, &tcpssn->server); else { SnortEventqPush(); SnortEventqLog(snort_conf->event_queue, &p); SnortEventqReset(); SnortEventqPop(); } tcpssn->server.flags &= ~TF_FORCE_FLUSH; } if (!s5_tcp_cleanup) { /* And turn decoder alerts back on (or whatever they were set to) */ policyDecoderFlagsRestore(lwssn->policy_id); } } TcpSessionClear(lwssn, tcpssn, freeApplicationData); } static void TcpSessionCleanupWithFreeApplicationData(Stream5LWSession *lwssn) { TcpSessionCleanup(lwssn, 1); } Stream5TcpPolicy *Stream5PolicyLookup(sfip_t *ip) { int policyIndex; Stream5TcpPolicy *policy = NULL; for (policyIndex = 0; policyIndex < s5_tcp_eval_config->num_policies; policyIndex++) { policy = s5_tcp_eval_config->policy_list[policyIndex]; if (policy->bound_addrs == NULL) continue; /* * Does this policy handle packets to this IP address? */ if(sfvar_ip_in(policy->bound_addrs, ip)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[Stream5] Found tcp policy in IpAddrSet\n");); break; } } if (policyIndex == s5_tcp_eval_config->num_policies) policy = s5_tcp_eval_config->default_policy; return policy; } #ifdef TARGET_BASED #define PRE_SESSION_CLEANUP_TARGET(lwssn) \ app_proto_id = lwssn->ha_state.application_protocol; #else #define PRE_SESSION_CLEANUP_TARGET(lwssn) #endif #define PRE_SESSION_CLEANUP(lwssn) \ uint32_t old_mem_in_use = mem_in_use; \ sfip_t client_ip; \ sfip_t server_ip; \ uint16_t client_port = lwssn->client_port; \ uint16_t server_port = lwssn->server_port; \ uint16_t lw_session_state = lwssn->session_state; \ uint32_t lw_session_flags = lwssn->ha_state.session_flags; \ int16_t app_proto_id = 0; \ sfip_set_ip(&client_ip, &lwssn->client_ip); \ sfip_set_ip(&server_ip, &lwssn->server_ip); #define POST_SESSION_CLEANUP(delete_reason) \ if (s5_global_eval_config->prune_log_max && \ (old_mem_in_use - mem_in_use) > s5_global_eval_config->prune_log_max) \ { \ char *client_ip_str, *server_ip_str; \ client_ip_str = SnortStrdup(inet_ntoa(&client_ip)); \ server_ip_str = SnortStrdup(inet_ntoa(&server_ip)); \ LogMessage("S5: Pruned session from cache that was " \ "using %d bytes (%s). %s %d --> %s %d (%d) : " \ "LWstate 0x%x LWFlags 0x%x\n", \ old_mem_in_use - mem_in_use, \ delete_reason, \ client_ip_str, client_port, \ server_ip_str, server_port, \ app_proto_id, lw_session_state, lw_session_flags); \ free(client_ip_str); \ free(server_ip_str); \ } #ifdef SEG_TEST static void CheckSegments (const StreamTracker* a) { StreamSegment* ss = a->seglist; uint32_t sx = ss ? ss->seq : 0; while ( ss ) { if ( SEQ_GT(sx, ss->seq) ) { const int SEGBORK = 0; assert(SEGBORK); } sx = ss->seq + ss->size; ss = ss->next; } } #endif #ifdef REG_TEST #define LCL(p, x) (p->x - p->isn) #define RMT(p, x, q) (p->x - (q ? q->isn : 0)) static int s5_trace_enabled = -1; static void TraceEvent ( const Packet* p, TcpDataBlock* tdb, uint32_t txd, uint32_t rxd ) { int i; char flags[7] = "UAPRSF"; const TCPHdr* h = p->tcph; const char* order = ""; if ( !h ) return; for ( i = 0; i < 6; i++) if ( !((1<<(5-i)) & h->th_flags) ) flags[i] = '-'; // force relative ack to zero if not conveyed if ( flags[1] != 'A' ) rxd = ntohl(h->th_ack); if ( p->packet_flags & PKT_STREAM_ORDER_OK ) order = " (ins)"; else if ( p->packet_flags & PKT_STREAM_ORDER_BAD ) order = " (oos)"; fprintf(stdout, "\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u%s\n", //"\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u End=%-4u%s\n", pc.total_from_daq, flags, h->th_flags, ntohl(h->th_seq)-txd, ntohl(h->th_ack)-rxd, ntohs(h->th_win), p->dsize, order //ntohs(h->th_win), p->dsize, tdb->end_seq-txd, order ); } static void TraceSession (const Stream5LWSession* lws) { fprintf(stdout, " LWS: ST=0x%x SF=0x%x CP=%u SP=%u\n", (unsigned)lws->session_state, lws->ha_state.session_flags, (unsigned)ntohs(lws->client_port), (unsigned)ntohs(lws->server_port) ); } static const char* statext[] = { "NON", "LST", "SYR", "SYS", "EST", "CLW", "LAK", "FW1", "CLG", "FW2", "TWT", "CLD" }; static const char* flushxt[] = { "NON", "FPR", "LOG", "RSP", "SLW", #if 0 "CON", #endif "IGN", "PRO", #ifdef NORMALIZER "PRE", "PAF" #endif }; static void TraceSegments (const StreamTracker* a) { StreamSegment* ss = a->seglist; uint32_t sx = a->r_win_base; unsigned segs = 0, bytes = 0; while ( ss ) { if ( SEQ_LT(sx, ss->seq) ) fprintf(stdout, " +%u", ss->seq-sx); else if ( SEQ_GT(sx, ss->seq) ) fprintf(stdout, " -%u", sx-ss->seq); fprintf(stdout, " %u", ss->size); segs++; bytes += ss->size; sx = ss->seq + ss->size; ss = ss->next; } assert(a->seg_count == segs); assert(a->seg_bytes_logical == bytes); } static void TraceState ( const StreamTracker* a, const StreamTracker* b, const char* s) { uint32_t why = a->l_nxt_seq ? LCL(a, l_nxt_seq) : 0; fprintf(stdout, " %s ST=%s:%02x UA=%-4u NS=%-4u LW=%-5u RN=%-4u RW=%-4u ", s, statext[a->s_mgr.state], a->s_mgr.sub_state, LCL(a, l_unackd), why, a->l_window, RMT(a, r_nxt_ack, b), RMT(a, r_win_base, b) ); if ( a->s_mgr.state_queue ) fprintf(stdout, "QS=%s QC=0x%02x QA=%-4u", statext[a->s_mgr.state_queue], a->s_mgr.expected_flags, RMT(a, s_mgr.transition_seq, b) ); fprintf(stdout, "\n"); fprintf(stdout, " FP=%s:%-4u SC=%-4u FL=%-4u SL=%-5u BS=%-4u", flushxt[a->flush_mgr.flush_policy], a->flush_mgr.flush_pt, a->seg_count, a->flush_count, a->seg_bytes_logical, a->seglist_base_seq - b->isn ); if ( s5_trace_enabled == 2 ) TraceSegments(a); fprintf(stdout, "\n"); } static void TraceTCP ( const Packet* p, const Stream5LWSession* lws, TcpDataBlock* tdb, int event ) { const TcpSession* ssn = (lws && lws->proto_specific_data) ? (TcpSession*)lws->proto_specific_data->data : NULL; const StreamTracker* srv = ssn ? &ssn->server : NULL; const StreamTracker* cli = ssn ? &ssn->client : NULL; const char* cdir = "?", *sdir = "?"; uint32_t txd = 0, rxd = 0; if ( p->packet_flags & PKT_FROM_SERVER ) { sdir = "SRV>"; cdir = "CLI<"; if ( srv ) txd = srv->isn; if ( cli ) rxd = cli->isn; } else if ( p->packet_flags & PKT_FROM_CLIENT ) { sdir = "SRV<"; cdir = "CLI>"; if ( cli ) txd = cli->isn; if ( srv ) rxd = srv->isn; } TraceEvent(p, tdb, txd, rxd); if ( lws ) TraceSession(lws); if ( !event ) { if ( cli ) TraceState(cli, srv, cdir); if ( srv ) TraceState(srv, cli, sdir); } } static inline void S5TraceTCP ( const Packet* p, const Stream5LWSession* lws, TcpDataBlock* tdb, int event ) { if ( !s5_trace_enabled ) return; if ( s5_trace_enabled < 0 ) { const char* s5t = getenv("S5_TRACE"); if ( !s5t ) { s5_trace_enabled = 0; return; } // no error checking required - atoi() is sufficient s5_trace_enabled = atoi(s5t); } TraceTCP(p, lws, tdb, event); } #endif // REG_TEST /* * Main entry point for TCP */ int Stream5ProcessTcp(Packet *p, Stream5LWSession *lwssn, Stream5TcpPolicy *s5TcpPolicy, SessionKey *skey) { TcpDataBlock tdb; int status; PROFILE_VARS; STREAM5_DEBUG_WRAP( char flagbuf[9]; CreateTCPFlagString(p, flagbuf); DebugMessage((DEBUG_STREAM|DEBUG_STREAM_STATE), "Got TCP Packet 0x%X:%d -> 0x%X:%d %s\nseq: 0x%X ack:0x%X " "dsize: %u\n" "active sessions: %u\n", GET_SRC_IP(p), p->sp, GET_DST_IP(p), p->dp, flagbuf, ntohl(p->tcph->th_seq), ntohl(p->tcph->th_ack), p->dsize, sfxhash_count(tcp_lws_cache->hashTable)); ); PREPROC_PROFILE_START(s5TcpPerfStats); if ( lwssn && (lwssn->ha_state.session_flags & (SSNFLAG_DROP_CLIENT|SSNFLAG_DROP_SERVER))) { /* Got a packet on a session that was dropped (by a rule). */ GetLWPacketDirection(p, lwssn); /* Drop this packet */ if (((p->packet_flags & PKT_FROM_SERVER) && (lwssn->ha_state.session_flags & SSNFLAG_DROP_SERVER)) || ((p->packet_flags & PKT_FROM_CLIENT) && (lwssn->ha_state.session_flags & SSNFLAG_DROP_CLIENT))) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Blocking %s packet as session was blocked\n", p->packet_flags & PKT_FROM_SERVER ? "server" : "client");); DisableAllDetect(p); /* Still want to add this number of bytes to totals */ SetPreprocBit(p, PP_PERFMONITOR); if ( lwssn->ha_state.session_flags & SSNFLAG_FORCE_BLOCK ) Active_ForceDropPacket(); else Active_DropPacket(p); #ifdef ACTIVE_RESPONSE Stream5ActiveResponse(p, lwssn); #endif PREPROC_PROFILE_END(s5TcpPerfStats); return ACTION_NOTHING; } } if (s5TcpPolicy == NULL) { /* Find an Tcp policy for this packet */ s5TcpPolicy = Stream5PolicyLookup(GET_DST_IP(p)); if (!s5TcpPolicy) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[Stream5] Could not find Tcp Policy context " "for IP %s\n", inet_ntoa(GET_DST_ADDR(p)));); PREPROC_PROFILE_END(s5TcpPerfStats); return 0; } /* If this is an existing LWSession that didn't have its policy set, set it now to save time in the future. */ if (lwssn != NULL && lwssn->policy == NULL) lwssn->policy = s5TcpPolicy; } if (isPacketFilterDiscard(p, (s5_tcp_eval_config->default_policy->flags & STREAM5_CONFIG_IGNORE_ANY)) == PORT_MONITOR_PACKET_DISCARD) { //ignore the packet STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "[Stream5] %s:%d -> %s:%d Packet discarded due to port filtering\n", inet_ntoa(GET_SRC_ADDR(p)),p->sp,inet_ntoa(GET_DST_ADDR(p)),p->dp);); UpdateFilteredPacketStats(&sfBase, IPPROTO_TCP); PREPROC_PROFILE_END(s5TcpPerfStats); return 0; } SetupTcpDataBlock(&tdb, p); #ifdef DEBUG_STREAM5 PrintTcpDataBlock(&tdb); #endif if (lwssn == NULL) { /* if require 3WHS, create Lightweight Session on SYN */ if (s5TcpPolicy->flags & STREAM5_CONFIG_REQUIRE_3WHS) { if (TCP_ISFLAGSET(p->tcph, TH_SYN) && !TCP_ISFLAGSET(p->tcph, TH_ACK)) { /* SYN only */ lwssn = NewLWSession(tcp_lws_cache, p, skey, (void *)s5TcpPolicy); lwssn->session_state = STREAM5_STATE_SYN; s5stats.total_tcp_sessions++; } else { /* If we're within the "startup" window, try to handle * this packet as midstream pickup -- allows for * connections that already existed before snort started. */ if (p->pkth->ts.tv_sec - firstPacketTime < s5TcpPolicy->hs_timeout) { midstream_allowed = 1; goto midstream_pickup_allowed; } /* * Do nothing with this packet since we require a 3-way. * Wow that just sounds cool... Require a 3-way. Hehe. */ DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "Stream5: Requiring 3-way " "Handshake, but failed to retrieve session object " "for non SYN packet.\n");); midstream_allowed = 0; EventNo3whs(s5TcpPolicy); PREPROC_PROFILE_END(s5TcpPerfStats); #ifdef REG_TEST S5TraceTCP(p, lwssn, &tdb, 1); #endif return 0; } } else { midstream_pickup_allowed: if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK))) { /* If we have a SYN/ACK */ lwssn = NewLWSession(tcp_lws_cache, p, skey, (void *)s5TcpPolicy); s5stats.total_tcp_sessions++; } else if (p->dsize > 0) { /* If we have data -- missed the SYN/ACK * somehow -- maybe just an incomplete PCAP. */ /* This handles data on SYN situations */ lwssn = NewLWSession(tcp_lws_cache, p, skey, (void *)s5TcpPolicy); s5stats.total_tcp_sessions++; } else if ((s5_tcp_eval_config->session_on_syn || (Stream5PacketHasWscale(p) & TF_WSCALE)) && TCP_ISFLAGSET(p->tcph, TH_SYN)) { /* If we have a wscale option, need to save the * option if its the first SYN from client. */ lwssn = NewLWSession(tcp_lws_cache, p, skey, (void *)s5TcpPolicy); lwssn->session_state = STREAM5_STATE_SYN; s5stats.total_tcp_sessions++; } else { /* No data, no need to create session yet */ /* This is done to handle SYN flood DoS attacks */ #ifdef DEBUG_STREAM5 if (TCP_ISFLAGSET(p->tcph, TH_SYN)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: no data in packet (SYN only), no need to" "create lightweight session.\n");); } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: no data in packet (non SYN/keep alive " "ACK?), no need to create lightweight session.\n");); } #endif PREPROC_PROFILE_END(s5TcpPerfStats); #ifdef REG_TEST S5TraceTCP(p, lwssn, &tdb, 1); #endif return 0; } } if (!lwssn) { LogMessage("Stream5: Failed to retrieve session object. Out of memory?\n"); PREPROC_PROFILE_END(s5TcpPerfStats); #ifdef REG_TEST S5TraceTCP(p, lwssn, &tdb, 1); #endif return -1; } } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Retrieved existing session object.\n");); } p->ssnptr = lwssn; /* * Check if the session is expired. * Should be done before we do something with the packet... * ie, Insert a packet, or handle state change SYN, FIN, RST, etc. */ if ((lwssn->session_state & STREAM5_STATE_TIMEDOUT) || Stream5Expire(p, lwssn)) { lwssn->ha_state.session_flags |= SSNFLAG_TIMEDOUT; #ifdef ENABLE_HA /* Notify the HA peer of the session cleanup/reset by way of a deletion notification. */ PREPROC_PROFILE_TMPEND(s5TcpPerfStats); Stream5HANotifyDeletion(lwssn); PREPROC_PROFILE_TMPSTART(s5TcpPerfStats); lwssn->ha_flags = (HA_FLAG_NEW | HA_FLAG_MODIFIED); #endif /* Session is timed out */ if (lwssn->ha_state.session_flags & SSNFLAG_RESET) { PRE_SESSION_CLEANUP(lwssn); PRE_SESSION_CLEANUP_TARGET(lwssn); /* If this one has been reset, delete the TCP * portion, and start a new. */ TcpSessionCleanupWithFreeApplicationData(lwssn); POST_SESSION_CLEANUP("new data/reset"); status = ProcessTcp(lwssn, p, &tdb, s5TcpPolicy); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Finished Stream5 TCP cleanly!\n" "---------------------------------------------------\n");); } else { PRE_SESSION_CLEANUP(lwssn); PRE_SESSION_CLEANUP_TARGET(lwssn); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5 TCP session timedout!\n");); /* Not reset, simply time'd out. Clean it up */ TcpSessionCleanupWithFreeApplicationData(lwssn); POST_SESSION_CLEANUP("new data/timedout"); status = ProcessTcp(lwssn, p, &tdb, s5TcpPolicy); } } else { status = ProcessTcp(lwssn, p, &tdb, s5TcpPolicy); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Finished Stream5 TCP cleanly!\n" "---------------------------------------------------\n");); } if ( !(status & ACTION_LWSSN_CLOSED) ) { MarkupPacketFlags(p, lwssn); Stream5SetExpire(p, lwssn, s5TcpPolicy->session_timeout); } #ifdef ENABLE_HA else { /* TCP Session closed, so send an HA deletion event for the session. */ Stream5HANotifyDeletion(lwssn); } #endif if ( status & ACTION_DISABLE_INSPECTION ) { Stream5DisableInspection(lwssn, p); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5 Ignoring packet from %d. Session marked as ignore\n", p->packet_flags & PKT_FROM_SERVER? "server" : "client");); } PREPROC_PROFILE_END(s5TcpPerfStats); #ifdef REG_TEST S5TraceTCP(p, lwssn, &tdb, 0); #endif return 0; } static uint32_t Stream5GetTcpTimestamp(Packet *p, uint32_t *ts, int strip) { unsigned int i = 0; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Getting timestamp...\n");); while(i < p->tcp_option_count && i < TCP_OPTLENMAX) { if(p->tcp_options[i].code == TCPOPT_TIMESTAMP) { #ifdef NORMALIZER if ( strip && Normalize_IsEnabled(snort_conf, NORM_TCP_OPT) ) { NormalStripTimeStamp(p, i); } else #endif { *ts = EXTRACT_32BITS(p->tcp_options[i].data); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Found timestamp %lu\n", *ts);); return TF_TSTAMP; } } i++; } *ts = 0; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "No timestamp...\n");); return TF_NONE; } static uint32_t Stream5GetMss(Packet *p, uint16_t *value) { unsigned int i = 0; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Getting MSS...\n");); while(i < p->tcp_option_count && i < TCP_OPTLENMAX) { if(p->tcp_options[i].code == TCPOPT_MAXSEG) { *value = EXTRACT_16BITS(p->tcp_options[i].data); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Found MSS %u\n", *value);); return TF_MSS; } i++; } *value = 0; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "No MSS...\n");); return TF_NONE; } static uint32_t Stream5GetWscale(Packet *p, uint16_t *value) { unsigned int i = 0; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Getting wscale...\n");); while(i < p->tcp_option_count && i < TCP_OPTLENMAX) { if(p->tcp_options[i].code == TCPOPT_WSCALE) { *value = (uint16_t) p->tcp_options[i].data[0]; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Found wscale %d\n", *value);); /* If scale specified in option is larger than 14, * use 14 because of limitation in the math of * shifting a 32bit value (max scaled window is 2^30th). * * See RFC 1323 for details. */ if (*value > 14) { *value = 14; } return TF_WSCALE; } i++; } *value = 0; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "No wscale...\n");); return TF_NONE; } static uint32_t Stream5PacketHasWscale(Packet *p) { uint16_t wscale; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Checking for wscale...\n");); return Stream5GetWscale(p, &wscale); } static inline int IsWellFormed(Packet *p, StreamTracker *ts) { return ( !ts->mss || (p->dsize <= ts->mss) ); } static void FinishServerInit(Packet *p, TcpDataBlock *tdb, TcpSession *ssn) { StreamTracker *server; StreamTracker *client; if (!ssn) { return; } server = &ssn->server; client = &ssn->client; server->l_window = tdb->win; /* set initial server window */ server->l_unackd = tdb->seq + 1; server->l_nxt_seq = server->l_unackd; server->isn = tdb->seq; client->r_nxt_ack = tdb->end_seq; if ( p->tcph->th_flags & TH_FIN ) server->l_nxt_seq--; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seglist_base_seq = %X\n", client->seglist_base_seq);); if (!(ssn->lwssn->session_state & STREAM5_STATE_MIDSTREAM)) { server->s_mgr.state = TCP_STATE_SYN_RCVD; client->seglist_base_seq = server->l_unackd; client->r_win_base = tdb->end_seq; } else { client->seglist_base_seq = tdb->seq; client->r_win_base = tdb->seq; } server->flags |= Stream5GetTcpTimestamp(p, &server->ts_last, 0); if (server->ts_last == 0) server->flags |= TF_TSTAMP_ZERO; else server->ts_last_pkt = p->pkth->ts.tv_sec; server->flags |= Stream5GetMss(p, &server->mss); server->flags |= Stream5GetWscale(p, &server->wscale); #ifdef DEBUG_STREAM5 PrintTcpSession(ssn); #endif } #ifdef OLD_CODE_NOLONGER_USED_DEPENDS_ON_CURRENT_STATE static inline void QueueState(uint8_t transition, StreamTracker *st, uint8_t expected_flags, uint32_t seq_num, uint8_t get_seq) { StateMgr *smgr = &st->s_mgr; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "[^^] Queing transition to %s, flag 0x%X, seq: 0x%X\n", state_names[transition], expected_flags, seq_num);); smgr->state_queue = transition; smgr->expected_flags = expected_flags; smgr->stq_get_seq = get_seq; smgr->transition_seq = seq_num; #ifdef DEBUG_STREAM5 PrintStateMgr(smgr); #endif return; } static inline int EvalStateQueue(StreamTracker *sptr, uint8_t flags, uint32_t ack) { StateMgr *smgr = &sptr->s_mgr; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Evaluating state queue!\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "StreamTracker %p, flags 0x%X ack: 0x%X\n", sptr, flags, ack); PrintStateMgr(smgr);); if(smgr->expected_flags != 0) { if((flags & smgr->expected_flags) != 0) { if(smgr->stq_get_seq && (SEQ_GEQ(ack, smgr->transition_seq))) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "[^^] Accepting %s state transition\n", state_names[smgr->state_queue]);); smgr->state = smgr->state_queue; smgr->expected_flags = 0; smgr->transition_seq = 0; return 1; } else if(!smgr->stq_get_seq) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "[^^] Accepting %s state transition\n", state_names[smgr->state_queue]);); smgr->state = smgr->state_queue; smgr->expected_flags = 0; smgr->transition_seq = 0; return 1; } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "[!!] sptr->stq_get_seq: %d " "[ack: 0x%X expected: 0x%X]\n", smgr->stq_get_seq, ack, smgr->transition_seq);); } } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "[!!] flags: 0x%X expected: 0x%X, bitwise: 0x%X\n", flags, smgr->expected_flags, (flags & smgr->expected_flags));); } } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "No transition queued, returning\n");); } return 0; } #endif static inline int IgnoreLargePkt(StreamTracker *st, Packet *p, TcpDataBlock *tdb) { if((st->flush_mgr.flush_policy == STREAM_FLPOLICY_FOOTPRINT) && (st->tcp_policy->flags & STREAM5_CONFIG_PERFORMANCE)) { if ((p->dsize > st->flush_mgr.flush_pt * 2) && (st->seg_count == 0)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "WARNING: Data larger than twice flushpoint. Not " "inserting for reassembly: seq: %d, size %d!\n" "This is a tradeoff of performance versus the remote " "possibility of catching an exploit that spans two or " "more consecuvitve large packets.\n", tdb->seq, p->dsize);); return 1; } } return 0; } static void NewQueue(StreamTracker *st, Packet *p, TcpDataBlock *tdb, TcpSession *tcpssn) { StreamSegment *ss = NULL; uint32_t overlap = 0; PROFILE_VARS; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "In NewQueue\n");); PREPROC_PROFILE_START(s5TcpInsertPerfStats); if(st->flush_mgr.flush_policy != STREAM_FLPOLICY_IGNORE) { uint32_t seq = tdb->seq; /* Check if we should not insert a large packet */ if (IgnoreLargePkt(st, p, tdb)) { return; } if ( p->tcph->th_flags & TH_SYN ) seq++; /* new packet seq is below the last ack... */ if ( SEQ_GT(st->r_win_base, seq) ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "segment overlaps ack'd data...\n");); overlap = st->r_win_base - tdb->seq; if(overlap >= p->dsize) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "full overlap on ack'd data, dropping segment\n");); PREPROC_PROFILE_END(s5TcpInsertPerfStats); return; } } AddStreamNode(st, p, tdb, tcpssn, p->dsize, overlap, 0, tdb->seq+overlap, NULL, &ss); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Attached new queue to seglist, %d bytes queued, " "base_seq 0x%X\n", ss->size, st->seglist_base_seq);); } PREPROC_PROFILE_END(s5TcpInsertPerfStats); return; } static inline StreamSegment *FindSegment(StreamTracker *st, uint32_t pkt_seq) { int32_t dist_head; int32_t dist_tail; StreamSegment *ss; if (!st->seglist) return NULL; dist_head = pkt_seq - st->seglist->seq; dist_tail = pkt_seq - st->seglist_tail->seq; if (dist_head <= dist_tail) { /* Start iterating at the head (left) */ for (ss = st->seglist; ss; ss = ss->next) { if (SEQ_EQ(ss->seq, pkt_seq)) return ss; if (SEQ_GEQ(ss->seq, pkt_seq)) break; } } else { /* Start iterating at the tail (right) */ for (ss = st->seglist_tail; ss; ss = ss->prev) { if (SEQ_EQ(ss->seq, pkt_seq)) return ss; if (SEQ_LT(ss->seq, pkt_seq)) break; } } return NULL; } void Stream5TcpSessionClear(Packet *p) { Stream5LWSession *lwssn; TcpSession *ssn; if ((!p) || (!p->ssnptr)) return; lwssn = (Stream5LWSession *)p->ssnptr; if (!lwssn->proto_specific_data) return; ssn = (TcpSession *)lwssn->proto_specific_data->data; if (!ssn) return; TcpSessionClear(lwssn, ssn, 1); } static inline int SegmentFastTrack(StreamSegment *tail, TcpDataBlock *tdb) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Checking seq for fast track: %X > %X\n", tdb->seq, tail->seq + tail->size);); if(SEQ_EQ(tdb->seq, tail->seq + tail->size)) return 1; return 0; } static inline StreamSegment* SegmentAlloc ( Packet* p, const struct timeval* tv, uint32_t caplen, uint32_t pktlen, const uint8_t* pkt) { StreamSegment* ss; unsigned size = sizeof(*ss); if ( caplen > 0 ) size += caplen - 1; // ss contains 1st byte mem_in_use += size; if ( mem_in_use > s5_global_eval_config->memcap ) { pc.str_mem_faults++; sfBase.iStreamFaults++; if ( !p ) { mem_in_use -= size; return NULL; } /* Smack the older time'd out sessions */ if (!PruneLWSessionCache(tcp_lws_cache, p->pkth->ts.tv_sec, (Stream5LWSession*)p->ssnptr, 0)) { /* Try the memcap - last parameter (1) specifies check * based on memory cap. */ PruneLWSessionCache(tcp_lws_cache, 0, (Stream5LWSession*)p->ssnptr, 1); } } ss = SnortAlloc(size); ss->tv.tv_sec = tv->tv_sec; ss->tv.tv_usec = tv->tv_usec; ss->caplen = caplen; ss->pktlen = pktlen; memcpy(ss->pkt, pkt, caplen); return ss; } static int AddStreamNode(StreamTracker *st, Packet *p, TcpDataBlock* tdb, TcpSession *tcpssn, int16_t len, uint32_t slide, uint32_t trunc, uint32_t seq, StreamSegment *left, StreamSegment **retSeg) { StreamSegment *ss = NULL; int32_t newSize = len - slide - trunc; if (newSize <= 0) { /* * zero size data because of trimming. Don't * insert it */ STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "zero size TCP data after left & right trimming " "(len: %d slide: %d trunc: %d)\n", len, slide, trunc);); Discard(); NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); #ifdef DEBUG_STREAM5 { StreamSegment *idx = st->seglist; unsigned long i = 0; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Dumping seglist, %d segments\n", st->seg_count);); while (idx) { i++; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "%d ptr: %p seq: 0x%X size: %d nxt: %p prv: %p\n", i, idx, idx->seq, idx->size, idx->next, idx->prev);); if(st->seg_count < i) FatalError("Circular list, WTF?\n"); idx = idx->next; } } #endif return STREAM_INSERT_ANOMALY; } ss = SegmentAlloc(p, &p->pkth->ts, p->pkth->caplen, p->pkth->pktlen, p->pkt); ss->data = ss->pkt + (p->data - p->pkt); ss->orig_dsize = p->dsize; ss->payload = ss->data + slide; ss->size = (uint16_t)newSize; ss->seq = seq; ss->ts = tdb->ts; /* handle the urg ptr */ if(p->tcph->th_flags & TH_URG) { if(ntohs(p->tcph->th_urp) < p->dsize) { switch(st->os_policy) { case STREAM_POLICY_LINUX: case STREAM_POLICY_OLD_LINUX: /* Linux, Old linux discard data from urgent pointer */ /* If urg pointer is 0, it's treated as a 1 */ ss->urg_offset = ntohs(p->tcph->th_urp); if (ss->urg_offset == 0) { ss->urg_offset = 1; } break; case STREAM_POLICY_FIRST: case STREAM_POLICY_LAST: case STREAM_POLICY_BSD: case STREAM_POLICY_MACOS: case STREAM_POLICY_SOLARIS: case STREAM_POLICY_WINDOWS: case STREAM_POLICY_WINDOWS2K3: case STREAM_POLICY_VISTA: case STREAM_POLICY_HPUX11: case STREAM_POLICY_HPUX10: case STREAM_POLICY_IRIX: /* Others discard data from urgent pointer */ /* If urg pointer is beyond this packet, it's treated as a 0 */ ss->urg_offset = ntohs(p->tcph->th_urp); if (ss->urg_offset > p->dsize) { ss->urg_offset = 0; } break; } } } Stream5SeglistAddNode(st, left, ss); st->seg_bytes_logical += ss->size; st->seg_bytes_total += ss->caplen; /* Includes protocol headers and payload */ st->total_segs_queued++; st->total_bytes_queued += ss->size; p->packet_flags |= PKT_STREAM_INSERT; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "added %d bytes on segment list @ seq: 0x%X, total %lu, " "%d segments queued\n", ss->size, ss->seq, st->seg_bytes_logical, SegsToFlush(st, 0));); *retSeg = ss; #ifdef SEG_TEST CheckSegments(st); #endif return STREAM_INSERT_OK; } static int DupStreamNode(Packet *p, StreamTracker *st, StreamSegment *left, StreamSegment **retSeg) { StreamSegment* ss = SegmentAlloc(p, &left->tv, left->caplen, left->pktlen, left->pkt); if ( !ss ) return STREAM_INSERT_FAILED; ss->data = ss->pkt + (left->data - left->pkt); ss->orig_dsize = left->orig_dsize; /* twiddle the values for overlaps */ ss->payload = ss->data; ss->size = left->size; ss->seq = left->seq; Stream5SeglistAddNode(st, left, ss); st->seg_bytes_total += ss->caplen; st->total_segs_queued++; //st->total_bytes_queued += ss->size; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "added %d bytes on segment list @ seq: 0x%X, total %lu, " "%d segments queued\n", ss->size, ss->seq, st->seg_bytes_logical, SegsToFlush(st, 0));); *retSeg = ss; return STREAM_INSERT_OK; } static inline bool IsRetransmit(StreamSegment *seg, const uint8_t *rdata, uint16_t rsize, uint32_t rseq) { // If seg->orig_size == seg->size, then it's sequence number wasn't adjusted // so can just do a straight compare of the sequence numbers. // Don't want to count as a retransmit if segment's size/sequence number // has been adjusted. if (SEQ_EQ(seg->seq, rseq) && (seg->orig_dsize == seg->size)) { if (((seg->size <= rsize) && (memcmp(seg->data, rdata, seg->size) == 0)) || ((seg->size > rsize) && (memcmp(seg->data, rdata, rsize) == 0))) return true; } return false; } static inline void RetransmitProcess(Packet *p, TcpSession *tcpssn) { // Data has already been analyzed so don't bother looking at it again. DisableDetect(p); // But still want to count this in the perfmonitor preprocessor SetPreprocBit(p, PP_PERFMONITOR); DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Allowing retransmitted data " "-- not blocked previously\n");); } static inline void RetransmitHandle(Packet *p, TcpSession *tcpssn) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Calling SE_REXMIT Handler\n");); if ( tcpssn->lwssn->handler[SE_REXMIT] ) Stream5CallHandler(p, tcpssn->lwssn->handler[SE_REXMIT]); } static inline void EndOfFileHandle(Packet *p, TcpSession *tcpssn) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Calling SE_EOF Handler\n");); if ( tcpssn->lwssn->handler[SE_EOF] ) Stream5CallHandler(p, tcpssn->lwssn->handler[SE_EOF]); } static int StreamQueue(StreamTracker *st, Packet *p, TcpDataBlock *tdb, TcpSession *tcpssn) { StreamSegment *ss = NULL; StreamSegment *left = NULL; StreamSegment *right = NULL; StreamSegment *dump_me = NULL; uint32_t seq = tdb->seq; uint32_t seq_end = tdb->end_seq; uint16_t len = p->dsize; int trunc = 0; int overlap = 0; int slide = 0; int ret = STREAM_INSERT_OK; char done = 0; char addthis = 1; int32_t dist_head; int32_t dist_tail; uint16_t reassembly_policy; #ifdef NORMALIZER int ips_data; #endif // To check for retransmitted data const uint8_t *rdata = p->data; uint16_t rsize = p->dsize; uint32_t rseq = tdb->seq; PROFILE_VARS; STREAM5_DEBUG_WRAP( StreamSegment *lastptr = NULL; uint32_t base_seq = st->seglist_base_seq; int last = 0; ); #ifdef NORMALIZER ips_data = Normalize_IsEnabled(snort_conf, NORM_TCP_IPS); if ( ips_data ) reassembly_policy = REASSEMBLY_POLICY_FIRST; else #endif reassembly_policy = st->reassembly_policy; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Queuing %d bytes on stream!\n" "base_seq: %X seq: %X seq_end: %X\n", seq_end - seq, base_seq, seq, seq_end);); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "%d segments on seglist\n", SegsToFlush(st, 0));); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n");); PREPROC_PROFILE_START(s5TcpInsertPerfStats); /* Check if we should not insert a large packet */ if (IgnoreLargePkt(st, p, tdb)) { // NORM should ignore large pkt be disabled for stream normalization? // if not, how to normalize ignored large packets? return ret; } // NORM fast tracks are in sequence - no norms if(st->seglist_tail && SegmentFastTrack(st->seglist_tail, tdb)) { /* segment fit cleanly at the end of the segment list */ left = st->seglist_tail; right = NULL; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Fast tracking segment! (tail_seq %X size %d)\n", st->seglist_tail->seq, st->seglist_tail->size);); ret = AddStreamNode(st, p, tdb, tcpssn, len, slide /* 0 */, trunc /* 0 */, seq, left /* tail */, &ss); PREPROC_PROFILE_END(s5TcpInsertPerfStats); return ret; } if (st->seglist && st->seglist_tail) { if (SEQ_GT(tdb->seq, st->seglist->seq)) { dist_head = tdb->seq - st->seglist->seq; } else { dist_head = st->seglist->seq - tdb->seq; } if (SEQ_GT(tdb->seq, st->seglist_tail->seq)) { dist_tail = tdb->seq - st->seglist_tail->seq; } else { dist_tail = st->seglist_tail->seq - tdb->seq; } } else { dist_head = dist_tail = 0; } if (SEQ_LEQ(dist_head, dist_tail)) { /* Start iterating at the head (left) */ for(ss = st->seglist; ss; ss = ss->next) { STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "ss: %p seq: 0x%X size: %lu delta: %d\n", ss, ss->seq, ss->size, (ss->seq-base_seq) - last); last = ss->seq-base_seq; lastptr = ss; DebugMessage(DEBUG_STREAM_STATE, " lastptr: %p ss->next: %p ss->prev: %p\n", lastptr, ss->next, ss->prev); ); right = ss; if(SEQ_GEQ(right->seq, seq)) break; left = right; } if(ss == NULL) right = NULL; } else { /* Start iterating at the tail (right) */ for(ss = st->seglist_tail; ss; ss = ss->prev) { STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "ss: %p seq: 0x%X size: %lu delta: %d\n", ss, ss->seq, ss->size, (ss->seq-base_seq) - last); last = ss->seq-base_seq; lastptr = ss; DebugMessage(DEBUG_STREAM_STATE, " lastptr: %p ss->next: %p ss->prev: %p\n", lastptr, ss->next, ss->prev); ); left = ss; if(SEQ_LT(left->seq, seq)) break; right = left; } if(ss == NULL) left = NULL; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+!+\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "left: %p:0x%X right: %p:0x%X\n", left, left?left->seq:0, right, right?right->seq:0);); /* * handle left overlaps */ if(left) { // NOTE that left->seq is always less than seq, otherwise it would // be a right based on the above determination of left and right /* check if the new segment overlaps on the left side */ overlap = left->seq + left->size - seq; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "left overlap %d\n", overlap);); if(overlap > 0) { // NOTE that overlap will always be less than left->size since // seq is always greater than left->seq s5stats.tcp_overlaps++; st->overlap_count++; switch(reassembly_policy) { case REASSEMBLY_POLICY_FIRST: case REASSEMBLY_POLICY_LINUX: case REASSEMBLY_POLICY_BSD: case REASSEMBLY_POLICY_WINDOWS: case REASSEMBLY_POLICY_WINDOWS2K3: case REASSEMBLY_POLICY_VISTA: case REASSEMBLY_POLICY_HPUX10: case REASSEMBLY_POLICY_IRIX: case REASSEMBLY_POLICY_OLD_LINUX: case REASSEMBLY_POLICY_MACOS: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring old data\n");); #ifdef NORMALIZER if ( ips_data ) { if (SEQ_LT(left->seq,tdb->seq) && SEQ_GT(left->seq + left->size, tdb->seq + p->dsize)) { unsigned offset = tdb->seq - left->seq; memcpy((uint8_t*)p->data, left->payload+offset, p->dsize); p->packet_flags |= PKT_MODIFIED; normStats[PC_TCP_IPS_DATA]++; sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA]++; } else if (SEQ_LT(left->seq, tdb->seq)) { unsigned offset = tdb->seq - left->seq; unsigned length = left->seq + left->size - tdb->seq; memcpy((uint8_t*)p->data, left->payload+offset, length); p->packet_flags |= PKT_MODIFIED; normStats[PC_TCP_IPS_DATA]++; sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA]++; } } #endif seq += overlap; slide = overlap; if(SEQ_LEQ(seq_end, seq)) { /* * houston, we have a problem */ /* flag an anomaly */ EventBadSegment(st->tcp_policy); Discard(); PREPROC_PROFILE_END(s5TcpInsertPerfStats); return STREAM_INSERT_ANOMALY; } break; case REASSEMBLY_POLICY_SOLARIS: case REASSEMBLY_POLICY_HPUX11: if (SEQ_LT(left->seq, seq) && SEQ_GEQ(left->seq + left->size, seq + len)) { /* New packet is entirely overlapped by an * existing packet on both sides. Drop the * new data. */ STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring old data\n");); seq += overlap; slide = overlap; if(SEQ_LEQ(seq_end, seq)) { /* * houston, we have a problem */ /* flag an anomaly */ EventBadSegment(st->tcp_policy); Discard(); PREPROC_PROFILE_END(s5TcpInsertPerfStats); return STREAM_INSERT_ANOMALY; } } /* Otherwise, trim the old data accordingly */ left->size -= (int16_t)overlap; st->seg_bytes_logical -= overlap; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring new data\n");); break; case REASSEMBLY_POLICY_LAST: /* True "Last" policy" */ if (SEQ_LT(left->seq, seq) && SEQ_GT(left->seq + left->size, seq + len)) { /* New data is overlapped on both sides by * existing data. Existing data needs to be * split and the new data inserted in the * middle. * * Need to duplicate left. Adjust that * seq by + (seq + len) and * size by - (seq + len - left->seq). */ ret = DupStreamNode(p, st, left, &right); if (ret != STREAM_INSERT_OK) { /* No warning, * its done in StreamSeglistAddNode */ PREPROC_PROFILE_END(s5TcpInsertPerfStats); return ret; } left->size -= (int16_t)overlap; st->seg_bytes_logical -= overlap; right->seq = seq + len; right->size -= (int16_t)(seq + len - left->seq); right->payload += (seq + len - left->seq); st->seg_bytes_logical -= (seq + len - left->seq); } else { left->size -= (int16_t)overlap; st->seg_bytes_logical -= overlap; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "left overlap, honoring new data\n");); break; } if(SEQ_LEQ(seq_end, seq)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seq_end < seq");); /* * houston, we have a problem */ /* flag an anomaly */ EventBadSegment(st->tcp_policy); Discard(); PREPROC_PROFILE_END(s5TcpInsertPerfStats); return STREAM_INSERT_ANOMALY; } } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "No left overlap\n");); } } //(seq_end > right->seq) && (seq_end <= (right->seq+right->size)))) while(right && !done && SEQ_LT(right->seq, seq_end)) { trunc = 0; overlap = (int)(seq_end - right->seq); //overlap = right->size - (right->seq - seq); //right->seq + right->size - seq_end; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "right overlap(%d): len: %d right->seq: 0x%X seq: 0x%X\n", overlap, len, right->seq, seq);); /* Treat sequence number overlap as a retransmission * Only check right side since left side happens rarely */ RetransmitHandle(p, tcpssn); if(overlap < right->size) { if (IsRetransmit(right, rdata, rsize, rseq)) { // All data was retransmitted RetransmitProcess(p, tcpssn); addthis = 0; break; } s5stats.tcp_overlaps++; st->overlap_count++; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got partial right overlap\n");); switch(reassembly_policy) { /* truncate existing data */ case REASSEMBLY_POLICY_LAST: case REASSEMBLY_POLICY_LINUX: case REASSEMBLY_POLICY_OLD_LINUX: case REASSEMBLY_POLICY_BSD: case REASSEMBLY_POLICY_WINDOWS: case REASSEMBLY_POLICY_WINDOWS2K3: case REASSEMBLY_POLICY_IRIX: case REASSEMBLY_POLICY_HPUX10: case REASSEMBLY_POLICY_MACOS: if (SEQ_EQ(right->seq, seq) && (reassembly_policy != REASSEMBLY_POLICY_LAST)) { slide = (right->seq + right->size - seq); seq += slide; } else { /* partial overlap */ right->seq += overlap; right->payload += overlap; right->size -= (int16_t)overlap; st->seg_bytes_logical -= overlap; st->total_bytes_queued -= overlap; } // right->size always > 0 since overlap < right->size break; case REASSEMBLY_POLICY_FIRST: case REASSEMBLY_POLICY_VISTA: case REASSEMBLY_POLICY_SOLARIS: case REASSEMBLY_POLICY_HPUX11: #ifdef NORMALIZER if ( ips_data ) { unsigned offset = right->seq - tdb->seq; unsigned length = tdb->seq + p->dsize - right->seq; memcpy((uint8_t*)p->data+offset, right->payload, length); p->packet_flags |= PKT_MODIFIED; normStats[PC_TCP_IPS_DATA]++; sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA]++; } #endif trunc = overlap; break; } /* all done, keep me out of the loop */ done = 1; } else // Full overlap { // Don't want to count retransmits as overlaps or do anything // else with them. Account for retransmits of multiple PDUs // in one segment. if (IsRetransmit(right, rdata, rsize, rseq)) { rdata += right->size; rsize -= right->size; rseq += right->size; seq += right->size; left = right; right = right->next; if (rsize == 0) { // All data was retransmitted RetransmitProcess(p, tcpssn); addthis = 0; } continue; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got full right overlap\n");); s5stats.tcp_overlaps++; st->overlap_count++; switch(reassembly_policy) { case REASSEMBLY_POLICY_BSD: case REASSEMBLY_POLICY_LINUX: case REASSEMBLY_POLICY_WINDOWS: case REASSEMBLY_POLICY_WINDOWS2K3: case REASSEMBLY_POLICY_HPUX10: case REASSEMBLY_POLICY_IRIX: case REASSEMBLY_POLICY_MACOS: if (SEQ_GEQ(seq_end, right->seq + right->size) && SEQ_LT(seq, right->seq)) { dump_me = right; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "retrans, dropping old data at seq %d, size %d\n", right->seq, right->size);); right = right->next; Stream5SeglistDeleteNode(st, dump_me); break; } else { switch (reassembly_policy) { case REASSEMBLY_POLICY_WINDOWS: case REASSEMBLY_POLICY_WINDOWS2K3: case REASSEMBLY_POLICY_BSD: case REASSEMBLY_POLICY_MACOS: /* BSD/MacOS & Windows follow a FIRST policy in the * case below... */ break; default: /* All others follow a LAST policy */ if (SEQ_GT(seq_end, right->seq + right->size) && SEQ_EQ(seq, right->seq)) { /* When existing data is fully overlapped by new * and sequence numbers are the same, most OSs * follow a LAST policy. */ goto right_overlap_last; } break; } } /* Fall through */ case REASSEMBLY_POLICY_FIRST: case REASSEMBLY_POLICY_VISTA: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got full right overlap, truncating new\n");); #ifdef NORMALIZER if ( ips_data ) { unsigned offset = right->seq - tdb->seq; memcpy((uint8_t*)p->data+offset, right->payload, right->size); p->packet_flags |= PKT_MODIFIED; normStats[PC_TCP_IPS_DATA]++; sfBase.iPegs[PERF_COUNT_TCP_IPS_DATA]++; } #endif if (SEQ_EQ(right->seq, seq)) { /* Overlap is greater than or equal to right->size * slide gets set before insertion */ seq += right->size; left = right; right = right->next; /* Adjusted seq is fully overlapped */ if (SEQ_EQ(seq, seq_end)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "StreamQueue got full right overlap with " "resulting seq too high, bad segment " "(seq: %X seq_end: %X overlap: %lu\n", seq, seq_end, overlap);); EventBadSegment(st->tcp_policy); Discard(); PREPROC_PROFILE_END(s5TcpInsertPerfStats); return STREAM_INSERT_ANOMALY; } /* No data to add on the left of right, so continue * since some of the other non-first targets may have * fallen into this case */ continue; } /* seq is less than right->seq */ /* trunc is reset to 0 at beginning of loop */ trunc = overlap; /* insert this one, and see if we need to chunk it up */ /* Adjust slide so that is correct relative to orig seq */ slide = seq - tdb->seq; ret = AddStreamNode(st, p, tdb, tcpssn, len, slide, trunc, seq, left, &ss); if (ret != STREAM_INSERT_OK) { /* no warning, already done above */ PREPROC_PROFILE_END(s5TcpInsertPerfStats); return ret; } /* Set seq to end of right since overlap was greater than * or equal to right->size and inserted seq has been * truncated to beginning of right * And reset trunc to 0 since we may fall out of loop if * next right is NULL */ seq = right->seq + right->size; left = right; right = right->next; trunc = 0; /* Keep looping since in IPS we may need to copy old * data into packet */ break; case REASSEMBLY_POLICY_HPUX11: case REASSEMBLY_POLICY_SOLARIS: /* If this packet is wholly overlapping and the same size * as a previous one and we have not received the one * immediately preceeding, we take the FIRST. */ if (SEQ_EQ(right->seq, seq) && (right->size == len) && (left && !SEQ_EQ(left->seq + left->size, seq))) { trunc += overlap; if(SEQ_LEQ((int)(seq_end - trunc), seq)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "StreamQueue got full right overlap with " "resulting seq too high, bad segment " "(seq: %X seq_end: %X overlap: %lu\n", seq, seq_end, overlap);); EventBadSegment(st->tcp_policy); Discard(); PREPROC_PROFILE_END(s5TcpInsertPerfStats); return STREAM_INSERT_ANOMALY; } break; } /* Fall through */ case REASSEMBLY_POLICY_OLD_LINUX: case REASSEMBLY_POLICY_LAST: right_overlap_last: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got full right overlap of old, dropping old\n");); dump_me = right; right = right->next; Stream5SeglistDeleteNode(st, dump_me); break; } } } if (addthis) { /* Adjust slide so that is correct relative to orig seq */ slide = seq - tdb->seq; ret = AddStreamNode(st, p, tdb, tcpssn, len, slide, trunc, seq, left, &ss); } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Fully truncated right overlap\n");); } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "StreamQueue returning normally\n");); PREPROC_PROFILE_END(s5TcpInsertPerfStats); return ret; } static void ProcessTcpStream(StreamTracker *rcv, TcpSession *tcpssn, Packet *p, TcpDataBlock *tdb, Stream5TcpPolicy *s5TcpPolicy) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "In ProcessTcpStream(), %d bytes to queue\n", p->dsize);); if ( p->packet_flags & PKT_IGNORE ) return; #ifdef HAVE_DAQ_ADDRESS_SPACE_ID SetPacketHeaderFoo(tcpssn, p); #endif if ((s5TcpPolicy->flags & STREAM5_CONFIG_NO_ASYNC_REASSEMBLY) && !TwoWayTraffic(tcpssn->lwssn)) { return; } if (s5TcpPolicy->max_consec_small_segs) { if (p->dsize < s5TcpPolicy->max_consec_small_seg_size) { /* check ignore_ports */ if (!(s5TcpPolicy->small_seg_ignore[p->dp/8] & (1 << (p->dp %8)))) { rcv->small_seg_count++; if (rcv->small_seg_count > s5TcpPolicy->max_consec_small_segs) { /* Above threshold, log it... requires detect_anomalies be * on in this TCP policy, action controlled by preprocessor * rule. */ EventMaxSmallSegsExceeded(s5TcpPolicy); /* Reset counter, so we're not too noisy */ rcv->small_seg_count = 0; } } } } if (s5TcpPolicy->max_queued_bytes && (rcv->seg_bytes_total > s5TcpPolicy->max_queued_bytes)) { if (!(tcpssn->lwssn->ha_state.session_flags & SSNFLAG_LOGGED_QUEUE_FULL)) { char *client_ip_str, *server_ip_str; sfip_t client_ip; sfip_t server_ip; sfip_set_ip(&client_ip, &tcpssn->lwssn->client_ip); sfip_set_ip(&server_ip, &tcpssn->lwssn->server_ip); client_ip_str = SnortStrdup(inet_ntoa(&client_ip)); server_ip_str = SnortStrdup(inet_ntoa(&server_ip)); LogMessage("S5: Session exceeded configured max bytes to queue %d " "using %d bytes (%s). %s %d --> %s %d " #ifdef TARGET_BASED "(%d) " #endif ": LWstate 0x%x LWFlags 0x%x\n", s5TcpPolicy->max_queued_bytes, rcv->seg_bytes_total, (rcv == &tcpssn->client) ? "client queue" : "server queue", client_ip_str, ntohs(tcpssn->lwssn->client_port), server_ip_str, ntohs(tcpssn->lwssn->server_port), #ifdef TARGET_BASED tcpssn->lwssn->ha_state.application_protocol, #endif tcpssn->lwssn->session_state, tcpssn->lwssn->ha_state.session_flags); free(client_ip_str); // FIXTHIS eliminate strdup and free free(server_ip_str); /* only log this one per session */ tcpssn->lwssn->ha_state.session_flags |= SSNFLAG_LOGGED_QUEUE_FULL; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Ignoring segment due to too many bytes queued\n");); return; } if (s5TcpPolicy->max_queued_segs && (rcv->seg_count+1 > s5TcpPolicy->max_queued_segs)) { if (!(tcpssn->lwssn->ha_state.session_flags & SSNFLAG_LOGGED_QUEUE_FULL)) { char *client_ip_str, *server_ip_str; sfip_t client_ip; sfip_t server_ip; sfip_set_ip(&client_ip, &tcpssn->lwssn->client_ip); sfip_set_ip(&server_ip, &tcpssn->lwssn->server_ip); client_ip_str = SnortStrdup(inet_ntoa(&client_ip)); server_ip_str = SnortStrdup(inet_ntoa(&server_ip)); LogMessage("S5: Session exceeded configured max segs to queue %d " "using %d segs (%s). %s %d --> %s %d " #ifdef TARGET_BASED "(%d) " #endif ": LWstate 0x%x LWFlags 0x%x\n", s5TcpPolicy->max_queued_segs, rcv->seg_count, (rcv == &tcpssn->client) ? "client queue" : "server queue", client_ip_str, ntohs(tcpssn->lwssn->client_port), server_ip_str, ntohs(tcpssn->lwssn->server_port), #ifdef TARGET_BASED tcpssn->lwssn->ha_state.application_protocol, #endif tcpssn->lwssn->session_state, tcpssn->lwssn->ha_state.session_flags); free(client_ip_str); // FIXTHIS eliminate strdup and free free(server_ip_str); /* only log this one per session */ tcpssn->lwssn->ha_state.session_flags |= SSNFLAG_LOGGED_QUEUE_FULL; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Ignoring segment due to too many bytes queued\n");); return; } if(rcv->seg_count != 0) { if(rcv->flush_mgr.flush_policy == STREAM_FLPOLICY_IGNORE) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Ignoring segment due to IGNORE flush_policy\n");); return; } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "queuing segment\n");); if ( SEQ_GT(rcv->r_win_base, tdb->seq) ) { uint32_t offset = rcv->r_win_base - tdb->seq; if ( offset < p->dsize ) { tdb->seq += offset; p->data += offset; p->dsize -= (uint16_t)offset; StreamQueue(rcv, p, tdb, tcpssn); p->dsize += (uint16_t)offset; p->data -= offset; tdb->seq -= offset; } } else StreamQueue(rcv, p, tdb, tcpssn); if ((rcv->tcp_policy->overlap_limit) && (rcv->overlap_count > rcv->tcp_policy->overlap_limit)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Reached the overlap limit. Flush the data " "and kill the session if configured\n");); if (p->packet_flags & PKT_FROM_CLIENT) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Flushing data on packet from the client\n");); flush_stream(tcpssn, rcv, p, GET_SRC_IP(p), GET_DST_IP(p), p->tcph->th_sport, p->tcph->th_dport, PKT_FROM_CLIENT); flush_stream(tcpssn, &tcpssn->server, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, PKT_FROM_SERVER); } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Flushing data on packet from the server\n");); flush_stream(tcpssn, rcv, p, GET_SRC_IP(p), GET_DST_IP(p), p->tcph->th_sport, p->tcph->th_dport, PKT_FROM_SERVER); flush_stream(tcpssn, &tcpssn->client, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, PKT_FROM_CLIENT); } purge_all(&tcpssn->client); purge_all(&tcpssn->server); /* Alert on overlap limit and reset counter */ EventExcessiveOverlap(rcv->tcp_policy); rcv->overlap_count = 0; } } } else { if(rcv->flush_mgr.flush_policy == STREAM_FLPOLICY_IGNORE) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Ignoring segment due to IGNORE flush_policy\n");); return; } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "queuing segment\n");); NewQueue(rcv, p, tdb, tcpssn); } } return; } static int ProcessTcpData(Packet *p, StreamTracker *listener, TcpSession *tcpssn, TcpDataBlock *tdb, Stream5TcpPolicy *s5TcpPolicy) { PROFILE_VARS; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "In ProcessTcpData()\n");); PREPROC_PROFILE_START(s5TcpDataPerfStats); if ((p->tcph->th_flags & TH_SYN) && (listener->os_policy != STREAM_POLICY_MACOS)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Bailing, data on SYN, not MAC Policy!\n");); NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); PREPROC_PROFILE_END(s5TcpDataPerfStats); return S5_UNALIGNED; } /* we're aligned, so that's nice anyway */ if(tdb->seq == listener->r_nxt_ack) { /* check if we're in the window */ if(Stream5GetWindow(tcpssn->lwssn, listener, tdb) == 0) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Bailing, we're out of the window!\n");); NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); PREPROC_PROFILE_END(s5TcpDataPerfStats); return S5_UNALIGNED; } /* move the ack boundry up, this is the only way we'll accept data */ // FIXTHIS for ips, must move all the way to first hole or right end if (listener->s_mgr.state_queue == TCP_STATE_NONE) listener->r_nxt_ack = tdb->end_seq; if(p->dsize != 0) { if ( !(tcpssn->lwssn->ha_state.session_flags & SSNFLAG_STREAM_ORDER_BAD) ) p->packet_flags |= PKT_STREAM_ORDER_OK; ProcessTcpStream(listener, tcpssn, p, tdb, s5TcpPolicy); /* set flags to session flags */ PREPROC_PROFILE_END(s5TcpDataPerfStats); return S5_ALIGNED; } } else { /* pkt is out of order, do some target-based shizzle here */ /* NO, we don't want to simply bail. Some platforms * favor unack'd dup data over the original data. * Let the reassembly policy decide how to handle * the overlapping data. * * See HP, Solaris, et al. for those that favor * duplicate data over the original in some cases. */ STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "out of order segment (tdb->seq: 0x%X " "l->r_nxt_ack: 0x%X!\n", tdb->seq, listener->r_nxt_ack);); if (listener->s_mgr.state_queue == TCP_STATE_NONE) { /* check if we're in the window */ if(Stream5GetWindow(tcpssn->lwssn, listener, tdb) == 0) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Bailing, we're out of the window!\n");); NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); PREPROC_PROFILE_END(s5TcpDataPerfStats); return S5_UNALIGNED; } if ((listener->s_mgr.state == TCP_STATE_ESTABLISHED) && (listener->flush_mgr.flush_policy == STREAM_FLPOLICY_IGNORE)) { if ( SEQ_GT(tdb->end_seq, listener->r_nxt_ack)) { /* set next ack so we are within the window going forward on * this side. */ // FIXTHIS for ips, must move all the way to first hole or right end listener->r_nxt_ack = tdb->end_seq; } } } if(p->dsize != 0) { if ( !(tcpssn->lwssn->ha_state.session_flags & SSNFLAG_STREAM_ORDER_BAD) ) { if ( !SEQ_LEQ((tdb->seq + p->dsize), listener->r_nxt_ack) ) tcpssn->lwssn->ha_state.session_flags |= SSNFLAG_STREAM_ORDER_BAD; } ProcessTcpStream(listener, tcpssn, p, tdb, s5TcpPolicy); } } PREPROC_PROFILE_END(s5TcpDataPerfStats); return S5_UNALIGNED; } uint16_t StreamGetPolicy(Stream5LWSession *lwssn, Stream5TcpPolicy *s5TcpPolicy, int direction) { #ifdef TARGET_BASED uint16_t policy_id; /* Not caching this host_entry in the frag tracker so we can * swap the table out after processing this packet if we need * to. */ HostAttributeEntry *host_entry = NULL; int ssn_dir; if (!IsAdaptiveConfigured(getRuntimePolicy())) return s5TcpPolicy->policy; if (direction == FROM_CLIENT) { host_entry = SFAT_LookupHostEntryByIP(&lwssn->server_ip); ssn_dir = SSN_DIR_FROM_SERVER; } else { host_entry = SFAT_LookupHostEntryByIP(&lwssn->client_ip); ssn_dir = SSN_DIR_FROM_CLIENT; } if (host_entry && (isStreamPolicySet(host_entry) == POLICY_SET)) { policy_id = getStreamPolicy(host_entry); if (policy_id != SFAT_UNKNOWN_STREAM_POLICY) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "StreamGetPolicy: Policy Map Entry: %d(%s)\n", policy_id, reassembly_policy_names[policy_id]);); /* Since we've already done the lookup, try to get the * application protocol id with that host_entry. */ Stream5SetApplicationProtocolIdFromHostEntry(lwssn, host_entry, ssn_dir); return policy_id; } } #endif STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "StreamGetPolicy: Using configured default %d(%s)\n", s5TcpPolicy->policy, reassembly_policy_names[s5TcpPolicy->policy]);); return s5TcpPolicy->policy; } void SetTcpReassemblyPolicy(StreamTracker *st) { st->reassembly_policy = GetTcpReassemblyPolicy(st->os_policy); } static void SetOSPolicy(TcpSession *tcpssn) { if (tcpssn->client.os_policy == 0) { tcpssn->client.os_policy = StreamGetPolicy(tcpssn->lwssn, tcpssn->client.tcp_policy, FROM_SERVER); SetTcpReassemblyPolicy(&tcpssn->client); } if (tcpssn->server.os_policy == 0) { tcpssn->server.os_policy = StreamGetPolicy(tcpssn->lwssn, tcpssn->server.tcp_policy, FROM_CLIENT); SetTcpReassemblyPolicy(&tcpssn->server); } } static inline int ValidMacAddress(StreamTracker *talker, StreamTracker *listener, Packet *p) { int i; int ret = 0; if (p->eh == NULL) return 0; /* Use a for loop and byte comparison, which has proven to be * faster on pipelined architectures compared to a memcmp (setup * for memcmp is slow). Not using a 4 byte and 2 byte long because * there is no guaranttee of memory alignment (and thus performance * issues similar to memcmp). */ for (i=0;i<6;i++) { if ((talker->mac_addr[i] != p->eh->ether_src[i])) { if (p->packet_flags & PKT_FROM_CLIENT) ret |= EVENT_SESSION_HIJACK_CLIENT; else ret |= EVENT_SESSION_HIJACK_SERVER; } if (listener->mac_addr[i] != p->eh->ether_dst[i]) { if (p->packet_flags & PKT_FROM_CLIENT) ret |= EVENT_SESSION_HIJACK_SERVER; else ret |= EVENT_SESSION_HIJACK_CLIENT; } } return ret; } static inline void CopyMacAddr(Packet *p, TcpSession *tcpssn, int dir) { int i; /* Not ethernet based, nothing to do */ if (p->eh == NULL) return; if (dir == FROM_CLIENT) { /* Client is SRC */ for (i=0;i<6;i++) { tcpssn->client.mac_addr[i] = p->eh->ether_src[i]; tcpssn->server.mac_addr[i] = p->eh->ether_dst[i]; } } else { /* Server is SRC */ for (i=0;i<6;i++) { tcpssn->server.mac_addr[i] = p->eh->ether_src[i]; tcpssn->client.mac_addr[i] = p->eh->ether_dst[i]; } } } static int NewTcpSession(Packet *p, Stream5LWSession *lwssn, TcpDataBlock *tdb, Stream5TcpPolicy *dstPolicy) { MemBucket *tmpBucket = NULL; TcpSession *tmp = NULL; uint16_t server_port = 0; PROFILE_VARS; PREPROC_PROFILE_START(s5TcpNewSessPerfStats); if (TCP_ISFLAGSET(p->tcph, TH_SYN) && !TCP_ISFLAGSET(p->tcph, TH_ACK)) { /****************************************************************** * start new sessions on proper SYN packets *****************************************************************/ tmpBucket = mempool_alloc(&tcp_session_mempool); tmp = tmpBucket->data; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on SYN!\n");); #ifdef DEBUG tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec; tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec; #endif lwssn->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT; if((p->tcph->th_flags & (TH_CWR|TH_ECE)) == (TH_CWR|TH_ECE)) { lwssn->ha_state.session_flags |= SSNFLAG_ECN_CLIENT_QUERY; } /* setup the stream trackers */ tmp->client.s_mgr.state = TCP_STATE_SYN_SENT; tmp->client.isn = tdb->seq; tmp->client.l_unackd = tdb->seq + 1; tmp->client.l_nxt_seq = tmp->client.l_unackd; tmp->client.l_window = tdb->win; tmp->client.ts_last_pkt = p->pkth->ts.tv_sec; tmp->server.seglist_base_seq = tmp->client.l_unackd; tmp->server.r_nxt_ack = tmp->client.l_unackd; tmp->server.r_win_base = tdb->seq+1; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seglist_base_seq = %X\n", tmp->server.seglist_base_seq);); tmp->server.s_mgr.state = TCP_STATE_LISTEN; tmp->client.flags |= Stream5GetTcpTimestamp(p, &tmp->client.ts_last, 0); if (tmp->client.ts_last == 0) tmp->client.flags |= TF_TSTAMP_ZERO; tmp->client.flags |= Stream5GetMss(p, &tmp->client.mss); tmp->client.flags |= Stream5GetWscale(p, &tmp->client.wscale); /* Set the Stream5TcpPolicy for each direction (pkt from client) */ tmp->client.tcp_policy = Stream5PolicyLookup(GET_SRC_IP(p)); tmp->server.tcp_policy = dstPolicy; /* Server is destination */ server_port = p->dp; CopyMacAddr(p, tmp, FROM_CLIENT); } else if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK))) { /****************************************************************** * start new sessions on SYN/ACK from server *****************************************************************/ tmpBucket = mempool_alloc(&tcp_session_mempool); tmp = tmpBucket->data; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on SYN_ACK!\n");); #ifdef DEBUG tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec; tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec; #endif lwssn->ha_state.session_flags |= SSNFLAG_SEEN_SERVER; if((p->tcph->th_flags & (TH_CWR|TH_ECE)) == (TH_CWR|TH_ECE)) { lwssn->ha_state.session_flags |= SSNFLAG_ECN_SERVER_REPLY; } /* setup the stream trackers */ tmp->server.s_mgr.state = TCP_STATE_SYN_RCVD; tmp->server.isn = tdb->seq; tmp->server.l_unackd = tdb->seq + 1; tmp->server.l_nxt_seq = tmp->server.l_unackd; tmp->server.l_window = tdb->win; tmp->server.seglist_base_seq = tdb->ack; tmp->server.r_win_base = tdb->ack; tmp->server.r_nxt_ack = tdb->ack; tmp->server.ts_last_pkt = p->pkth->ts.tv_sec; tmp->client.seglist_base_seq = tmp->server.l_unackd; tmp->client.r_nxt_ack = tmp->server.l_unackd; tmp->client.r_win_base = tdb->seq+1; tmp->client.l_nxt_seq = tdb->ack; tmp->client.isn = tdb->ack-1; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seglist_base_seq = %X\n", tmp->client.seglist_base_seq);); tmp->client.s_mgr.state = TCP_STATE_SYN_SENT; tmp->server.flags |= Stream5GetTcpTimestamp(p, &tmp->server.ts_last, 0); if (tmp->server.ts_last == 0) tmp->server.flags |= TF_TSTAMP_ZERO; tmp->server.flags |= Stream5GetMss(p, &tmp->server.mss); tmp->server.flags |= Stream5GetWscale(p, &tmp->server.wscale); /* Set the Stream5TcpPolicy for each direction (pkt from server) */ tmp->server.tcp_policy = Stream5PolicyLookup(GET_SRC_IP(p)); tmp->client.tcp_policy = dstPolicy; lwssn->policy = tmp->server.tcp_policy; /* Client is destination */ server_port = p->sp; CopyMacAddr(p, tmp, FROM_SERVER); } else if ((p->tcph->th_flags & TH_ACK) && !(p->tcph->th_flags & TH_RST) && (lwssn->session_state & STREAM5_STATE_ESTABLISHED)) { /****************************************************************** * start new sessions on completion of 3-way (ACK only, no data) *****************************************************************/ tmpBucket = mempool_alloc(&tcp_session_mempool); tmp = tmpBucket->data; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on ACK!\n");); #ifdef DEBUG tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec; tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec; #endif lwssn->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT; if((p->tcph->th_flags & (TH_CWR|TH_ECE)) == (TH_CWR|TH_ECE)) { lwssn->ha_state.session_flags |= SSNFLAG_ECN_CLIENT_QUERY; } /* setup the stream trackers */ tmp->client.s_mgr.state = TCP_STATE_ESTABLISHED; tmp->client.isn = tdb->seq; tmp->client.l_unackd = tdb->seq + 1; tmp->client.l_nxt_seq = tmp->client.l_unackd; tmp->client.l_window = tdb->win; tmp->client.ts_last_pkt = p->pkth->ts.tv_sec; tmp->server.seglist_base_seq = tmp->client.l_unackd; tmp->server.r_nxt_ack = tmp->client.l_unackd; tmp->server.r_win_base = tdb->seq+1; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seglist_base_seq = %X\n", tmp->server.seglist_base_seq);); tmp->server.s_mgr.state = TCP_STATE_ESTABLISHED; tmp->client.flags |= Stream5GetTcpTimestamp(p, &tmp->client.ts_last, 0); if (tmp->client.ts_last == 0) tmp->client.flags |= TF_TSTAMP_ZERO; tmp->client.flags |= Stream5GetMss(p, &tmp->client.mss); tmp->client.flags |= Stream5GetWscale(p, &tmp->client.wscale); /* Set the Stream5TcpPolicy for each direction (pkt from client) */ tmp->client.tcp_policy = Stream5PolicyLookup(GET_SRC_IP(p)); tmp->server.tcp_policy = dstPolicy; /* Server is destination */ server_port = p->dp; CopyMacAddr(p, tmp, FROM_CLIENT); } else if (p->dsize != 0) { /****************************************************************** * start new sessions on data in packet *****************************************************************/ tmpBucket = mempool_alloc(&tcp_session_mempool); tmp = tmpBucket->data; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Creating new session tracker on data packet (ACK|PSH)!\n");); #ifdef DEBUG tmp->ssn_time.tv_sec = p->pkth->ts.tv_sec; tmp->ssn_time.tv_usec = p->pkth->ts.tv_usec; #endif if (lwssn->ha_state.direction == FROM_CLIENT) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Session direction is FROM_CLIENT\n");); /* Sender is client (src port is higher) */ lwssn->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT; if((p->tcph->th_flags & (TH_CWR|TH_ECE)) == (TH_CWR|TH_ECE)) { lwssn->ha_state.session_flags |= SSNFLAG_ECN_CLIENT_QUERY; } /* setup the stream trackers */ tmp->client.s_mgr.state = TCP_STATE_ESTABLISHED; tmp->client.isn = tdb->seq; tmp->client.l_unackd = tdb->seq; tmp->client.l_nxt_seq = tmp->client.l_unackd; tmp->client.l_window = tdb->win; tmp->client.ts_last_pkt = p->pkth->ts.tv_sec; tmp->server.seglist_base_seq = tmp->client.l_unackd; tmp->server.r_nxt_ack = tmp->client.l_unackd; tmp->server.r_win_base = tdb->seq; tmp->server.l_window = 0; /* reset later */ /* Next server packet is what was ACKd */ //tmp->server.l_nxt_seq = tdb->ack + 1; tmp->server.l_unackd = tdb->ack - 1; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seglist_base_seq = %X\n", tmp->server.seglist_base_seq);); tmp->server.s_mgr.state = TCP_STATE_ESTABLISHED; tmp->client.flags |= Stream5GetTcpTimestamp(p, &tmp->client.ts_last, 0); if (tmp->client.ts_last == 0) tmp->client.flags |= TF_TSTAMP_ZERO; tmp->client.flags |= Stream5GetMss(p, &tmp->client.mss); tmp->client.flags |= Stream5GetWscale(p, &tmp->client.wscale); /* Set the Stream5TcpPolicy for each direction (pkt from client) */ tmp->client.tcp_policy = Stream5PolicyLookup(GET_SRC_IP(p)); tmp->server.tcp_policy = dstPolicy; /* Server is destination */ server_port = p->dp; CopyMacAddr(p, tmp, FROM_CLIENT); } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Session direction is FROM_SERVER\n");); /* Sender is server (src port is lower) */ lwssn->ha_state.session_flags |= SSNFLAG_SEEN_SERVER; /* setup the stream trackers */ tmp->server.s_mgr.state = TCP_STATE_ESTABLISHED; tmp->server.isn = tdb->seq; tmp->server.l_unackd = tdb->seq; tmp->server.l_nxt_seq = tmp->server.l_unackd; tmp->server.l_window = tdb->win; tmp->server.seglist_base_seq = tdb->ack; tmp->server.r_win_base = tdb->ack; tmp->server.r_nxt_ack = tdb->ack; tmp->server.ts_last_pkt = p->pkth->ts.tv_sec; tmp->client.seglist_base_seq = tmp->server.l_unackd; tmp->client.r_nxt_ack = tmp->server.l_unackd; tmp->client.r_win_base = tdb->seq; tmp->client.l_window = 0; /* reset later */ tmp->client.isn = tdb->ack-1; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seglist_base_seq = %X\n", tmp->client.seglist_base_seq);); tmp->client.s_mgr.state = TCP_STATE_ESTABLISHED; tmp->server.flags |= Stream5GetTcpTimestamp(p, &tmp->server.ts_last, 0); if (tmp->server.ts_last == 0) tmp->server.flags |= TF_TSTAMP_ZERO; tmp->server.flags |= Stream5GetMss(p, &tmp->server.mss); tmp->server.flags |= Stream5GetWscale(p, &tmp->server.wscale); /* Set the Stream5TcpPolicy for each direction (pkt from server) */ tmp->server.tcp_policy = Stream5PolicyLookup(GET_SRC_IP(p)); tmp->client.tcp_policy = dstPolicy; lwssn->policy = tmp->server.tcp_policy; /* Client is destination */ server_port = p->sp; CopyMacAddr(p, tmp, FROM_SERVER); } } if (tmp) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "adding TcpSession to lightweight session\n");); lwssn->proto_specific_data = tmpBucket; lwssn->protocol = GET_IPH_PROTO(p); tmp->lwssn = lwssn; /* New session, previous was marked as reset. Clear the * reset flag. */ if (lwssn->ha_state.session_flags & SSNFLAG_RESET) lwssn->ha_state.session_flags &= ~SSNFLAG_RESET; SetOSPolicy(tmp); if ( (lwssn->ha_state.session_flags & SSNFLAG_CLIENT_SWAP) && !(lwssn->ha_state.session_flags & SSNFLAG_CLIENT_SWAPPED) ) { StreamTracker trk = tmp->client; snort_ip ip = lwssn->client_ip; uint16_t port = lwssn->client_port; tmp->client = tmp->server; tmp->server = trk; lwssn->client_ip = lwssn->server_ip; lwssn->server_ip = ip; lwssn->client_port = lwssn->server_port; lwssn->server_port = port; if ( !TwoWayTraffic(lwssn) ) { if ( lwssn->ha_state.session_flags & SSNFLAG_SEEN_CLIENT ) { lwssn->ha_state.session_flags ^= SSNFLAG_SEEN_CLIENT; lwssn->ha_state.session_flags |= SSNFLAG_SEEN_SERVER; } else if ( lwssn->ha_state.session_flags & SSNFLAG_SEEN_SERVER ) { lwssn->ha_state.session_flags ^= SSNFLAG_SEEN_SERVER; lwssn->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT; } } lwssn->ha_state.session_flags |= SSNFLAG_CLIENT_SWAPPED; } /* Set up the flush behaviour, based on the configured info * for the server and client ports. */ /* Yes, the server flush manager gets the info from the * policy's server port's the flush policy from the client * and visa-versa. * * For example, when policy said 'ports client 80', that means * reassemble packets from the client side (stored in the server's * flush buffer in the session) destined for port 80. Port 80 is * the server port and we're reassembling the client side. * That should make this almost as clear as opaque mud! */ #ifdef TARGET_BASED if (tmp->server.tcp_policy->flush_config_protocol[lwssn->ha_state.application_protocol].configured == 1) { StreamTracker* pst = &tmp->server; uint8_t flush_policy = pst->tcp_policy->flush_config_protocol[lwssn->ha_state.application_protocol].client.flush_policy; InitFlushMgrByService(lwssn, pst, lwssn->ha_state.application_protocol, true, flush_policy); } else #endif { StreamTracker* pst = &tmp->server; uint8_t flush_policy = pst->tcp_policy->flush_config[server_port].client.flush_policy; InitFlushMgrByPort(lwssn, pst, server_port, true, flush_policy); } #ifdef TARGET_BASED if (tmp->client.tcp_policy->flush_config_protocol[lwssn->ha_state.application_protocol].configured == 1) { StreamTracker* pst = &tmp->client; uint8_t flush_policy = pst->tcp_policy->flush_config_protocol[lwssn->ha_state.application_protocol].server.flush_policy; InitFlushMgrByService(lwssn, pst, lwssn->ha_state.application_protocol, false, flush_policy); } else #endif { StreamTracker* pst = &tmp->client; uint8_t flush_policy = pst->tcp_policy->flush_config[server_port].server.flush_policy; InitFlushMgrByPort(lwssn, pst, server_port, false, flush_policy); } #ifdef DEBUG_STREAM5 PrintTcpSession(tmp); #endif Stream5SetExpire(p, lwssn, dstPolicy->session_timeout); s5stats.tcp_streamtrackers_created++; AddStreamSession(&sfBase, lwssn->session_state & STREAM5_STATE_MIDSTREAM ? SSNFLAG_MIDSTREAM : 0); Stream5UpdatePerfBaseState(&sfBase, tmp->lwssn, TCP_STATE_SYN_SENT); #ifdef NORMALIZER tmp->ecn = 0; #endif PREPROC_PROFILE_END(s5TcpNewSessPerfStats); return 1; } PREPROC_PROFILE_END(s5TcpNewSessPerfStats); return 0; } static int RepeatedSyn( StreamTracker *listener, StreamTracker *talker, TcpDataBlock *tdb, TcpSession *tcpssn) { switch (listener->os_policy) { case STREAM_POLICY_WINDOWS: case STREAM_POLICY_WINDOWS2K3: case STREAM_POLICY_VISTA: /* Windows has some strange behaviour here. If the * sequence of the reset is the next expected sequence, * it Resets. Otherwise it ignores the 2nd SYN. */ if (SEQ_EQ(tdb->seq, listener->r_nxt_ack)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got syn on established windows ssn, which causes Reset," "bailing\n");); tcpssn->lwssn->ha_state.session_flags |= SSNFLAG_RESET; talker->s_mgr.state = TCP_STATE_CLOSED; return ACTION_RST; } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got syn on established windows ssn, not causing Reset," "bailing\n");); Discard(); return ACTION_NOTHING; } break; case STREAM_POLICY_MACOS: /* MACOS ignores a 2nd SYN, regardless of the sequence number. */ STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got syn on established macos ssn, not causing Reset," "bailing\n");); Discard(); return ACTION_NOTHING; break; case STREAM_POLICY_FIRST: case STREAM_POLICY_LAST: case STREAM_POLICY_LINUX: case STREAM_POLICY_OLD_LINUX: case STREAM_POLICY_BSD: case STREAM_POLICY_SOLARIS: case STREAM_POLICY_HPUX11: case STREAM_POLICY_HPUX10: case STREAM_POLICY_IRIX: /* If its not a retransmission of the actual SYN... RESET */ if(!SEQ_EQ(tdb->seq,talker->isn)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got syn on established ssn, which causes Reset, bailing\n");); tcpssn->lwssn->ha_state.session_flags |= SSNFLAG_RESET; talker->s_mgr.state = TCP_STATE_CLOSED; return ACTION_RST; } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got syn on established ssn, not causing Reset," "bailing\n");); Discard(); return ACTION_NOTHING; } break; } return ACTION_NOTHING; } static void LogTcpEvents(Stream5TcpPolicy *s5TcpPolicy, int eventcode) { if ( !eventcode ) return; if (eventcode & EVENT_SYN_ON_EST) EventSynOnEst(s5TcpPolicy); if (eventcode & EVENT_DATA_ON_SYN) EventDataOnSyn(s5TcpPolicy); if (eventcode & EVENT_DATA_ON_CLOSED) EventDataOnClosed(s5TcpPolicy); if (eventcode & EVENT_BAD_TIMESTAMP) EventBadTimestamp(s5TcpPolicy); if (eventcode & EVENT_BAD_SEGMENT) EventBadSegment(s5TcpPolicy); if (eventcode & EVENT_WINDOW_TOO_LARGE) EventWindowTooLarge(s5TcpPolicy); if (eventcode & EVENT_EXCESSIVE_TCP_OVERLAPS) EventExcessiveOverlap(s5TcpPolicy); if (eventcode & EVENT_DATA_AFTER_RESET) EventDataAfterReset(s5TcpPolicy); if (eventcode & EVENT_SESSION_HIJACK_CLIENT) EventSessionHijackedClient(s5TcpPolicy); if (eventcode & EVENT_SESSION_HIJACK_SERVER) EventSessionHijackedServer(s5TcpPolicy); if (eventcode & EVENT_DATA_WITHOUT_FLAGS) EventDataWithoutFlags(s5TcpPolicy); if (eventcode & EVENT_4WHS) Event4whs(s5TcpPolicy); if (eventcode & EVENT_NO_TIMESTAMP) EventNoTimestamp(s5TcpPolicy); if (eventcode & EVENT_BAD_RST) EventBadReset(s5TcpPolicy); if (eventcode & EVENT_BAD_FIN) EventBadFin(s5TcpPolicy); if (eventcode & EVENT_BAD_ACK) EventBadAck(s5TcpPolicy); if (eventcode & EVENT_DATA_AFTER_RST_RCVD) EventDataAfterRstRcvd(s5TcpPolicy); if (eventcode & EVENT_WINDOW_SLAM) EventWindowSlam(s5TcpPolicy); } static inline void DisableInspection (Stream5LWSession* lwssn, Packet* p, char ignore) { /* Set the directions to ignore... */ lwssn->ha_state.ignore_direction = ignore; Stream5SetReassemblyTcp(lwssn, STREAM_FLPOLICY_IGNORE, ignore, STREAM_FLPOLICY_SET_ABSOLUTE); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Ignoring packet from %d. Marking session marked as ignore.\n", p->packet_flags & PKT_FROM_SERVER? "server" : "client");); Stream5DisableInspection(lwssn, p); } static int ProcessTcp(Stream5LWSession *lwssn, Packet *p, TcpDataBlock *tdb, Stream5TcpPolicy *s5TcpPolicy) { int retcode = ACTION_NOTHING; int eventcode = 0; char ignore; int got_ts = 0; int new_ssn = 0; int ts_action = ACTION_NOTHING; TcpSession *tcpssn = NULL; StreamTracker *talker = NULL; StreamTracker *listener = NULL; uint32_t require3Way = (s5TcpPolicy->flags & STREAM5_CONFIG_REQUIRE_3WHS); STREAM5_DEBUG_WRAP(char *t = NULL; char *l = NULL;) PROFILE_VARS; if (lwssn->protocol != IPPROTO_TCP) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Lightweight session not TCP on TCP packet\n");); return retcode; } if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; PREPROC_PROFILE_START(s5TcpStatePerfStats); if (tcpssn == NULL) { if ( ScPafEnabled() ) { /* Check if the session is to be ignored */ ignore = StreamExpectCheck(p, lwssn); if (ignore) { DisableInspection(lwssn, p, ignore); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode; } } if (TCP_ISFLAGSET(p->tcph, TH_SYN) && !TCP_ISFLAGSET(p->tcph, TH_ACK)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5 SYN PACKET, establishing lightweight" "session direction.\n");); /* SYN packet from client */ lwssn->ha_state.direction = FROM_CLIENT; IP_COPY_VALUE(lwssn->client_ip, GET_SRC_IP(p)); lwssn->client_port = p->tcph->th_sport; IP_COPY_VALUE(lwssn->server_ip, GET_DST_IP(p)); lwssn->server_port = p->tcph->th_dport; lwssn->session_state |= STREAM5_STATE_SYN; if (require3Way || (Stream5PacketHasWscale(p) & TF_WSCALE) || ((p->dsize > 0) && (StreamGetPolicy(lwssn, s5TcpPolicy, FROM_CLIENT) == STREAM_POLICY_MACOS))) { /* Create TCP session if we * 1) require 3-WAY HS, OR * 2) client sent wscale option, OR * 3) have data and its a MAC OS policy -- MAC * is the only one that accepts data on SYN * (and thus requires a TCP session at this point) */ NewTcpSession(p, lwssn, tdb, s5TcpPolicy); tcpssn = (TcpSession *)lwssn->proto_specific_data->data; new_ssn = 1; NormalTrackECN(tcpssn, (TCPHdr*)p->tcph, require3Way); } /* Nothing left todo here */ } else if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK))) { /* SYN-ACK from server */ if ((lwssn->session_state == STREAM5_STATE_NONE) || (lwssn->ha_state.session_flags & SSNFLAG_RESET)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5 SYN|ACK PACKET, establishing lightweight" "session direction.\n");); lwssn->ha_state.direction = FROM_SERVER; IP_COPY_VALUE(lwssn->client_ip, GET_DST_IP(p)); lwssn->client_port = p->tcph->th_dport; IP_COPY_VALUE(lwssn->server_ip, GET_SRC_IP(p)); lwssn->server_port = p->tcph->th_sport; } lwssn->session_state |= STREAM5_STATE_SYN_ACK; if (!require3Way || midstream_allowed) { NewTcpSession(p, lwssn, tdb, s5TcpPolicy); tcpssn = (TcpSession *)lwssn->proto_specific_data->data; new_ssn = 1; } NormalTrackECN(tcpssn, (TCPHdr*)p->tcph, require3Way); /* Nothing left todo here */ } else if (TCP_ISFLAGSET(p->tcph, TH_ACK) && !TCP_ISFLAGSET(p->tcph, TH_RST) && (lwssn->session_state & STREAM5_STATE_SYN_ACK)) { /* TODO: do we need to verify the ACK field is >= the seq of the SYN-ACK? */ /* 3-way Handshake complete, create TCP session */ lwssn->session_state |= STREAM5_STATE_ACK | STREAM5_STATE_ESTABLISHED; NewTcpSession(p, lwssn, tdb, s5TcpPolicy); tcpssn = (TcpSession *)lwssn->proto_specific_data->data; new_ssn = 1; NormalTrackECN(tcpssn, (TCPHdr*)p->tcph, require3Way); Stream5UpdatePerfBaseState(&sfBase, lwssn, TCP_STATE_ESTABLISHED); } else if ((p->dsize > 0) && (!require3Way || midstream_allowed)) { /* create session on data, need to figure out direction, etc */ /* Assume from client, can update later */ if (p->sp > p->dp) { lwssn->ha_state.direction = FROM_CLIENT; IP_COPY_VALUE(lwssn->client_ip, GET_SRC_IP(p)); lwssn->client_port = p->tcph->th_sport; IP_COPY_VALUE(lwssn->server_ip, GET_DST_IP(p)); lwssn->server_port = p->tcph->th_dport; } else { lwssn->ha_state.direction = FROM_SERVER; IP_COPY_VALUE(lwssn->client_ip, GET_DST_IP(p)); lwssn->client_port = p->tcph->th_dport; IP_COPY_VALUE(lwssn->server_ip, GET_SRC_IP(p)); lwssn->server_port = p->tcph->th_sport; } lwssn->session_state |= STREAM5_STATE_MIDSTREAM; lwssn->ha_state.session_flags |= SSNFLAG_MIDSTREAM; #ifdef DEBUG_STREAM5 if (ScReadMode()) { /* If we're in readback mode... may only have one packet. * That being packet with the exploit being tested, so * mark this session as established, so rule option * 'flow:established' works correctly. */ STREAM5_DEBUG_WRAP( char timestamp[TIMEBUF_SIZE]; char src_addr[17]; char dst_addr[17]; memset((char *)timestamp, 0, TIMEBUF_SIZE); ts_print((struct timeval *) &p->pkth->ts, timestamp); SnortSnprintf(src_addr, 17, "%s", inet_ntoa(GET_SRC_ADDR(p))); SnortSnprintf(dst_addr, 17, "%s", inet_ntoa(GET_DST_ADDR(p))); DebugMessage(DEBUG_STREAM_STATE, "Session not established " "on midstream-pickup of data packet. Will be marked " "as established when other side is seen. Packet Info: " "Time: %s\tSrc: %s:%d\tDst: %s:%d\n", timestamp, src_addr, p->sp, dst_addr, p->dp); ); #ifdef MIMIC_STREAM4_MIDSTREAM_BEHAVIOUR lwssn->session_state |= STREAM5_STATE_ESTABLISHED; lwssn->ha_state.session_flags |= SSNFLAG_ESTABLISHED; #endif } #endif NewTcpSession(p, lwssn, tdb, s5TcpPolicy); tcpssn = (TcpSession *)lwssn->proto_specific_data->data; new_ssn = 1; NormalTrackECN(tcpssn, (TCPHdr*)p->tcph, require3Way); if (lwssn->session_state & STREAM5_STATE_ESTABLISHED) Stream5UpdatePerfBaseState(&sfBase, lwssn, TCP_STATE_ESTABLISHED); } else if (p->dsize == 0) { /* Already have a lwssn, but no tcp session. * Probably just an ACK of already sent data (that * we missed). */ /* Do nothing. */ PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode; } } else { /* If session is already marked as established */ if (!(lwssn->session_state & STREAM5_STATE_ESTABLISHED) && (!require3Way || midstream_allowed)) { /* If not requiring 3-way Handshake... */ /* TCP session created on TH_SYN above, * or maybe on SYN-ACK, or anything else */ /* Need to update Lightweight session state */ if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK))) { /* SYN-ACK from server */ if (lwssn->session_state != STREAM5_STATE_NONE) { lwssn->session_state |= STREAM5_STATE_SYN_ACK; } } else if (TCP_ISFLAGSET(p->tcph, TH_ACK) && (lwssn->session_state & STREAM5_STATE_SYN_ACK)) { lwssn->session_state |= STREAM5_STATE_ACK | STREAM5_STATE_ESTABLISHED; Stream5UpdatePerfBaseState(&sfBase, lwssn, TCP_STATE_ESTABLISHED); } } #ifdef NORMALIZER if (TCP_ISFLAGSET(p->tcph, TH_SYN)) NormalTrackECN(tcpssn, (TCPHdr*)p->tcph, require3Way); #endif } /* figure out direction of this packet */ GetLWPacketDirection(p, lwssn); if(p->packet_flags & PKT_FROM_SERVER) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Updating on packet from server\n");); lwssn->ha_state.session_flags |= SSNFLAG_SEEN_SERVER; if (tcpssn) { talker = &tcpssn->server; listener = &tcpssn->client; } STREAM5_DEBUG_WRAP( t = "Server"; l = "Client"); if ( talker && talker->s_mgr.state == TCP_STATE_LISTEN && ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) ) { eventcode |= EVENT_4WHS; } /* If we picked this guy up midstream, finish the initialization */ if ((lwssn->session_state & STREAM5_STATE_MIDSTREAM) && !(lwssn->session_state & STREAM5_STATE_ESTABLISHED)) { FinishServerInit(p, tdb, tcpssn); if((p->tcph->th_flags & TH_ECE) && lwssn->ha_state.session_flags & SSNFLAG_ECN_CLIENT_QUERY) { lwssn->ha_state.session_flags |= SSNFLAG_ECN_SERVER_REPLY; } if (lwssn->ha_state.session_flags & SSNFLAG_SEEN_CLIENT) { // should TCP state go to established too? lwssn->session_state |= STREAM5_STATE_ESTABLISHED; lwssn->ha_state.session_flags |= SSNFLAG_ESTABLISHED; Stream5UpdatePerfBaseState(&sfBase, lwssn, TCP_STATE_ESTABLISHED); } } #ifdef ACTIVE_RESPONSE if ( !lwssn->inner_server_ttl ) SetTTL(lwssn, p, 0); #endif } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream5: Updating on packet from client\n");); /* if we got here we had to see the SYN already... */ lwssn->ha_state.session_flags |= SSNFLAG_SEEN_CLIENT; if (tcpssn) { talker = &tcpssn->client; listener = &tcpssn->server; } STREAM5_DEBUG_WRAP( t = "Client"; l = "Server";); if ((lwssn->session_state & STREAM5_STATE_MIDSTREAM) && !(lwssn->session_state & STREAM5_STATE_ESTABLISHED)) { /* Midstream and seen server. */ if (lwssn->ha_state.session_flags & SSNFLAG_SEEN_SERVER) { lwssn->session_state |= STREAM5_STATE_ESTABLISHED; lwssn->ha_state.session_flags |= SSNFLAG_ESTABLISHED; } } #ifdef ACTIVE_RESPONSE if ( !lwssn->inner_client_ttl ) SetTTL(lwssn, p, 1); #endif } /* * check for SYN on reset session */ if ((lwssn->ha_state.session_flags & SSNFLAG_RESET) && (p->tcph->th_flags & TH_SYN)) { if ((!tcpssn) || ((listener->s_mgr.state == TCP_STATE_CLOSED) || (talker->s_mgr.state == TCP_STATE_CLOSED))) { PRE_SESSION_CLEANUP(lwssn); PRE_SESSION_CLEANUP_TARGET(lwssn); /* Listener previously issued a reset */ /* Talker is re-SYN-ing */ TcpSessionCleanupWithFreeApplicationData(lwssn); POST_SESSION_CLEANUP("SYN on RST ssn"); if (p->tcph->th_flags & TH_RST) { /* Got SYN/RST. We're done. */ NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); tcpssn = NULL; PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_RST; } else if (TCP_ISFLAGSET(p->tcph, TH_SYN) && !TCP_ISFLAGSET(p->tcph, TH_ACK)) { lwssn->ha_state.direction = FROM_CLIENT; IP_COPY_VALUE(lwssn->client_ip, GET_SRC_IP(p)); lwssn->client_port = p->tcph->th_sport; IP_COPY_VALUE(lwssn->server_ip, GET_DST_IP(p)); lwssn->server_port = p->tcph->th_dport; lwssn->session_state = STREAM5_STATE_SYN; #ifdef ACTIVE_RESPONSE SetTTL(lwssn, p, 1); #endif NewTcpSession(p, lwssn, tdb, s5TcpPolicy); tcpssn = (TcpSession *)lwssn->proto_specific_data->data; new_ssn = 1; NormalTrackECN(tcpssn, (TCPHdr*)p->tcph, require3Way); if (tcpssn) { listener = &tcpssn->server; talker = &tcpssn->client; } lwssn->ha_state.session_flags = SSNFLAG_SEEN_CLIENT; } else if (TCP_ISFLAGSET(p->tcph, (TH_SYN|TH_ACK))) { lwssn->ha_state.direction = FROM_SERVER; IP_COPY_VALUE(lwssn->client_ip, GET_DST_IP(p)); lwssn->client_port = p->tcph->th_dport; IP_COPY_VALUE(lwssn->server_ip, GET_SRC_IP(p)); lwssn->server_port = p->tcph->th_sport; lwssn->session_state = STREAM5_STATE_SYN_ACK; #ifdef ACTIVE_RESPONSE SetTTL(lwssn, p, 0); #endif NewTcpSession(p, lwssn, tdb, s5TcpPolicy); tcpssn = (TcpSession *)lwssn->proto_specific_data->data; new_ssn = 1; NormalTrackECN(tcpssn, (TCPHdr*)p->tcph, require3Way); if (tcpssn) { listener = &tcpssn->client; talker = &tcpssn->server; } lwssn->ha_state.session_flags = SSNFLAG_SEEN_SERVER; } } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got SYN pkt on reset ssn, re-SYN-ing\n");); } if (((p->packet_flags & PKT_FROM_SERVER) && (lwssn->ha_state.ignore_direction & SSN_DIR_FROM_CLIENT)) || ((p->packet_flags & PKT_FROM_CLIENT) && (lwssn->ha_state.ignore_direction & SSN_DIR_FROM_SERVER))) { if ( talker && (talker->flags & TF_FORCE_FLUSH) ) { Stream5FlushTalker(p, lwssn); talker->flags &= ~TF_FORCE_FLUSH; } if ( listener && (listener->flags & TF_FORCE_FLUSH) ) { Stream5FlushListener(p, lwssn); listener->flags &= ~TF_FORCE_FLUSH; } p->packet_flags |= PKT_IGNORE; retcode |= ACTION_DISABLE_INSPECTION; } /* Check if the session is to be ignored */ if ( !ScPafEnabled() ) { ignore = StreamExpectCheck(p, lwssn); if (ignore) { DisableInspection(lwssn, p, ignore); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode; } } /* Handle data on SYN */ if ((p->dsize) && TCP_ISFLAGSET(p->tcph, TH_SYN)) { /* MacOS accepts data on SYN, so don't alert if policy is MACOS */ if (StreamGetPolicy(lwssn, s5TcpPolicy, FROM_CLIENT) != STREAM_POLICY_MACOS) { #ifdef NORMALIZER if ( Normalize_IsEnabled(snort_conf, NORM_TCP_TRIM) ) { NormalTrimPayload(p, 0, tdb); // remove data on SYN } else #endif { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got data on SYN packet, not processing it\n");); //EventDataOnSyn(s5TcpPolicy); eventcode |= EVENT_DATA_ON_SYN; retcode |= ACTION_BAD_PKT; } } } if (!tcpssn) { LogTcpEvents(s5TcpPolicy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t, state_names[talker->s_mgr.state]);); STREAM5_DEBUG_WRAP(PrintFlushMgr(&talker->flush_mgr);); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, state_names[listener->s_mgr.state], listener->s_mgr.state);); STREAM5_DEBUG_WRAP(PrintFlushMgr(&listener->flush_mgr);); // may find better placement to eliminate redundant flag checks if(p->tcph->th_flags & TH_SYN) talker->s_mgr.sub_state |= SUB_SYN_SENT; if(p->tcph->th_flags & TH_ACK) talker->s_mgr.sub_state |= SUB_ACK_SENT; /* * process SYN ACK on unestablished sessions */ if( (TCP_STATE_SYN_SENT == listener->s_mgr.state) && (TCP_STATE_LISTEN == talker->s_mgr.state) ) { if(p->tcph->th_flags & TH_ACK) { /* * make sure we've got a valid segment */ if(!IsBetween(listener->l_unackd, listener->l_nxt_seq, tdb->ack)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Pkt ack is out of bounds, bailing!\n");); Discard(); NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_BAD_PKT; } } talker->flags |= Stream5GetTcpTimestamp(p, &tdb->ts, 0); if (tdb->ts == 0) talker->flags |= TF_TSTAMP_ZERO; /* * catch resets sent by server */ if(p->tcph->th_flags & TH_RST) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "got RST\n");); NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); /* Reset is valid when in SYN_SENT if the * ack field ACKs the SYN. */ if(ValidRstSynSent(listener, tdb)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "got RST, closing talker\n");); /* Reset is valid */ /* Mark session as reset... Leave it around so that any * additional data sent from one side or the other isn't * processed (and is dropped in inline mode). */ lwssn->ha_state.session_flags |= SSNFLAG_RESET; talker->s_mgr.state = TCP_STATE_CLOSED; Stream5UpdatePerfBaseState(&sfBase, lwssn, TCP_STATE_CLOSING); /* Leave listener open, data may be in transit */ LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_RST; } /* Reset not valid. */ STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n");); Discard(); eventcode |= EVENT_BAD_RST; NormalDropPacketIf(p, NORM_TCP); LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode; } /* * finish up server init */ if(p->tcph->th_flags & TH_SYN) { FinishServerInit(p, tdb, tcpssn); if (talker->flags & TF_TSTAMP) { talker->ts_last_pkt = p->pkth->ts.tv_sec; talker->ts_last = tdb->ts; } STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Finish server init got called!\n");); } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Finish server init didn't get called!\n");); } if((p->tcph->th_flags & TH_ECE) && lwssn->ha_state.session_flags & SSNFLAG_ECN_CLIENT_QUERY) { lwssn->ha_state.session_flags |= SSNFLAG_ECN_SERVER_REPLY; } /* * explicitly set the state */ listener->s_mgr.state = TCP_STATE_SYN_SENT; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Accepted SYN ACK\n");); LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode; } /* * scale the window. Only if BOTH client and server specified * wscale option as part of 3-way handshake. * This is per RFC 1323. */ if ((talker->flags & TF_WSCALE) && (listener->flags & TF_WSCALE)) { tdb->win <<= talker->wscale; } /* Check for session hijacking -- compare mac address to the ones * that were recorded at session startup. */ #ifdef DAQ_PKT_FLAG_PRE_ROUTING if (!(p->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING) && listener->tcp_policy->flags & STREAM5_CONFIG_CHECK_SESSION_HIJACKING) #else if (listener->tcp_policy->flags & STREAM5_CONFIG_CHECK_SESSION_HIJACKING) #endif { eventcode |= ValidMacAddress(talker, listener, p); } /* Check timestamps */ ts_action = ValidTimestamp(talker, listener, tdb, p, &eventcode, &got_ts); /* * check RST validity */ if(p->tcph->th_flags & TH_RST) { NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); if(ValidRst(lwssn, listener, tdb)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got RST, bailing\n");); if ( listener->s_mgr.state == TCP_STATE_FIN_WAIT_1 || listener->s_mgr.state == TCP_STATE_FIN_WAIT_2 || listener->s_mgr.state == TCP_STATE_CLOSE_WAIT || listener->s_mgr.state == TCP_STATE_CLOSING ) { Stream5FlushTalker(p, lwssn); Stream5FlushListener(p, lwssn); FreeLWApplicationData(lwssn); } lwssn->ha_state.session_flags |= SSNFLAG_RESET; talker->s_mgr.state = TCP_STATE_CLOSED; talker->s_mgr.sub_state |= SUB_RST_SENT; Stream5UpdatePerfBaseState(&sfBase, lwssn, TCP_STATE_CLOSING); #ifdef NORMALIZER if ( Normalize_IsEnabled(snort_conf, NORM_TCP_IPS) ) listener->s_mgr.state = TCP_STATE_CLOSED; /* else for ids: leave listener open, data may be in transit */ #endif LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_RST; } /* Reset not valid. */ STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n");); Discard(); eventcode |= EVENT_BAD_RST; NormalDropPacketIf(p, NORM_TCP); LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ts_action; } else { /* check for valid seqeuence/retrans */ if ( (listener->s_mgr.state >= TCP_STATE_ESTABLISHED) && !ValidSeq(p, lwssn, listener, tdb) ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "bad sequence number, bailing\n");); Discard(); NormalTrimPayloadIf(p, NORM_TCP_TRIM, 0, tdb); LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ts_action; } } if (ts_action != ACTION_NOTHING) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "bad timestamp, bailing\n");); Discard(); // this packet was normalized elsewhere LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ts_action; } /* * update PAWS timestamps */ STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "PAWS update tdb->seq %lu > listener->r_win_base %lu\n", tdb->seq, listener->r_win_base);); if(got_ts && SEQ_EQ(listener->r_win_base, tdb->seq)) { if((int32_t)(tdb->ts - talker->ts_last) >= 0 || (uint32_t)p->pkth->ts.tv_sec >= talker->ts_last_pkt+PAWS_24DAYS) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "updating timestamps...\n");); talker->ts_last = tdb->ts; talker->ts_last_pkt = p->pkth->ts.tv_sec; } } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "not updating timestamps...\n");); } /* * check for repeat SYNs */ if ( !new_ssn && ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) ) { int action; #ifdef NORMALIZER if ( !SEQ_EQ(tdb->seq, talker->isn) && NormalDropPacketIf(p, NORM_TCP) ) action = ACTION_BAD_PKT; else #endif if ( talker->s_mgr.state >= TCP_STATE_ESTABLISHED ) action = RepeatedSyn(listener, talker, tdb, tcpssn); else action = ACTION_NOTHING; if (action != ACTION_NOTHING) { /* got a bad SYN on the session, alert! */ eventcode |= EVENT_SYN_ON_EST; LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | action; } } /* * Check that the window is within the limits */ if (listener->tcp_policy->max_window && (tdb->win > listener->tcp_policy->max_window)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got window that was beyond the allowed policy value, bailing\n");); /* got a window too large, alert! */ eventcode |= EVENT_WINDOW_TOO_LARGE; Discard(); NormalDropPacketIf(p, NORM_TCP); LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_BAD_PKT; } else if ((p->packet_flags & PKT_FROM_CLIENT) && (tdb->win <= SLAM_MAX) && (tdb->ack == listener->isn + 1) && !(p->tcph->th_flags & (TH_FIN|TH_RST)) && !(lwssn->ha_state.session_flags & SSNFLAG_MIDSTREAM)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Window slammed shut!\n");); /* got a window slam alert! */ eventcode |= EVENT_WINDOW_SLAM; Discard(); #ifdef NORMALIZER if ( NormalDropPacketIf(p, NORM_TCP) ) { LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_BAD_PKT; } #endif } if(talker->s_mgr.state_queue != TCP_STATE_NONE) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Found queued state transition on ack 0x%X, " "current 0x%X!\n", talker->s_mgr.transition_seq, tdb->ack);); if(tdb->ack == talker->s_mgr.transition_seq) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "accepting transition!\n");); talker->s_mgr.state = talker->s_mgr.state_queue; talker->s_mgr.state_queue = TCP_STATE_NONE; } } /* * process ACK flags */ if(p->tcph->th_flags & TH_ACK) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got an ACK...\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " %s [listener] state: %s\n", l, state_names[listener->s_mgr.state]);); switch(listener->s_mgr.state) { case TCP_STATE_SYN_SENT: if ( !require3Way || midstream_allowed ) break; // fall thru ... case TCP_STATE_SYN_RCVD: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "listener state is SYN_SENT...\n");); if(IsBetween(listener->l_unackd, listener->l_nxt_seq, tdb->ack) && ((!require3Way || midstream_allowed) || ((talker->s_mgr.sub_state == SUB_SETUP_OK) && (listener->s_mgr.sub_state == SUB_SETUP_OK)))) { UpdateSsn(p, listener, talker, tdb); lwssn->ha_state.session_flags |= SSNFLAG_ESTABLISHED; lwssn->session_state |= STREAM5_STATE_ESTABLISHED; listener->s_mgr.state = TCP_STATE_ESTABLISHED; talker->s_mgr.state = TCP_STATE_ESTABLISHED; Stream5UpdatePerfBaseState(&sfBase, lwssn, TCP_STATE_ESTABLISHED); /* Indicate this packet completes 3-way handshake */ p->packet_flags |= PKT_STREAM_TWH; } talker->flags |= got_ts; if(got_ts && SEQ_EQ(listener->r_nxt_ack, tdb->seq)) { talker->ts_last_pkt = p->pkth->ts.tv_sec; talker->ts_last = tdb->ts; } break; case TCP_STATE_ESTABLISHED: case TCP_STATE_CLOSE_WAIT: UpdateSsn(p, listener, talker, tdb); break; case TCP_STATE_FIN_WAIT_1: UpdateSsn(p, listener, talker, tdb); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "tdb->ack %X >= talker->r_nxt_ack %X\n", tdb->ack, talker->r_nxt_ack);); if ( SEQ_EQ(tdb->ack, listener->l_nxt_seq) ) { if ( (listener->os_policy == STREAM_POLICY_WINDOWS) && (tdb->win == 0) ) { eventcode |= EVENT_WINDOW_SLAM; Discard(); #ifdef NORMALIZER if ( NormalDropPacketIf(p, NORM_TCP) ) { LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_BAD_PKT; } #endif } listener->s_mgr.state = TCP_STATE_FIN_WAIT_2; if ( (p->tcph->th_flags & TH_FIN) ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "seq ok, setting state!\n");); if (talker->s_mgr.state_queue == TCP_STATE_NONE) { talker->s_mgr.state = TCP_STATE_LAST_ACK; EndOfFileHandle(p, (TcpSession *)lwssn->proto_specific_data->data); } if ( lwssn->ha_state.session_flags & SSNFLAG_MIDSTREAM ) { // FIXTHIS this should be handled below in fin section // but midstream sessions fail the seq test listener->s_mgr.state_queue = TCP_STATE_TIME_WAIT; listener->s_mgr.transition_seq = tdb->end_seq; listener->s_mgr.expected_flags = TH_ACK; } } else if (listener->s_mgr.state_queue == TCP_STATE_CLOSING) { listener->s_mgr.state_queue = TCP_STATE_TIME_WAIT; listener->s_mgr.transition_seq = tdb->end_seq; listener->s_mgr.expected_flags = TH_ACK; } } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "bad ack!\n");); } break; case TCP_STATE_FIN_WAIT_2: UpdateSsn(p, listener, talker, tdb); if ( SEQ_GT(tdb->ack, listener->l_nxt_seq) ) { eventcode |= EVENT_BAD_ACK; LogTcpEvents(talker->tcp_policy, eventcode); NormalDropPacketIf(p, NORM_TCP); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_BAD_PKT; } break; case TCP_STATE_CLOSING: UpdateSsn(p, listener, talker, tdb); if(SEQ_GEQ(tdb->end_seq, listener->r_nxt_ack)) { listener->s_mgr.state = TCP_STATE_TIME_WAIT; } break; case TCP_STATE_LAST_ACK: UpdateSsn(p, listener, talker, tdb); if ( SEQ_EQ(tdb->ack, listener->l_nxt_seq) ) { listener->s_mgr.state = TCP_STATE_CLOSED; } break; default: // FIXTHIS safe to ignore when inline? break; } } /* * handle data in the segment */ if(p->dsize) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " %s state: %s(%d) getting data\n", l, state_names[listener->s_mgr.state], listener->s_mgr.state);); // FIN means only that sender is done talking, // other side may continue yapping. if(TCP_STATE_FIN_WAIT_2 == talker->s_mgr.state || TCP_STATE_TIME_WAIT == talker->s_mgr.state) { /* data on a segment when we're not accepting data any more */ /* alert! */ //EventDataOnClosed(talker->tcp_policy); eventcode |= EVENT_DATA_ON_CLOSED; retcode |= ACTION_BAD_PKT; NormalDropPacketIf(p, NORM_TCP); } else if (TCP_STATE_CLOSED == talker->s_mgr.state) { /* data on a segment when we're not accepting data any more */ /* alert! */ if (lwssn->ha_state.session_flags & SSNFLAG_RESET) { // no need to run detection PPs on this packet DisableDetect( p ); //EventDataAfterReset(listener->tcp_policy); if ( talker->s_mgr.sub_state & SUB_RST_SENT ) eventcode |= EVENT_DATA_AFTER_RESET; else eventcode |= EVENT_DATA_AFTER_RST_RCVD; } else { //EventDataOnClosed(listener->tcp_policy); eventcode |= EVENT_DATA_ON_CLOSED; } retcode |= ACTION_BAD_PKT; NormalDropPacketIf(p, NORM_TCP); } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Queuing data on listener, t %s, l %s...\n", flush_policy_names[talker->flush_mgr.flush_policy], flush_policy_names[listener->flush_mgr.flush_policy]);); #ifdef NORMALIZER // these normalizations can't be done if we missed setup. and // window is zero in one direction until we've seen both sides. if ( !(lwssn->ha_state.session_flags & SSNFLAG_MIDSTREAM) ) { if ( Normalize_IsEnabled(snort_conf, NORM_TCP_TRIM) ) { // sender of syn w/mss limits payloads from peer // since we store mss on sender side, use listener mss // same reasoning for window size StreamTracker* st = listener; // get the current window size uint32_t max = (st->r_win_base + st->l_window) - st->r_nxt_ack; // get lesser of current window or mss but // if mss is zero it is unset so don't use it if ( st->mss && st->mss < max ) max = st->mss; NormalTrimPayload(p, max, tdb); } if ( Normalize_IsEnabled(snort_conf, NORM_TCP_ECN_STR) ) NormalCheckECN(tcpssn, p); } #endif /* * dunno if this is RFC but fragroute testing expects it * for the record, I've seen FTP data sessions that send * data packets with no tcp flags set */ if ((p->tcph->th_flags != 0) || (s5TcpPolicy->policy == STREAM_POLICY_LINUX)) { ProcessTcpData(p, listener, tcpssn, tdb, s5TcpPolicy); } else { eventcode |= EVENT_DATA_WITHOUT_FLAGS; NormalDropPacketIf(p, NORM_TCP); } } } if(p->tcph->th_flags & TH_FIN) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Got an FIN...\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, state_names[talker->s_mgr.state], talker->s_mgr.state);); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "checking ack (0x%X) vs nxt_ack (0x%X)\n", tdb->end_seq, listener->r_win_base);); if(SEQ_LT(tdb->end_seq,listener->r_win_base)) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "FIN inside r_win_base, bailing\n");); goto dupfin; } else { // need substate since we don't change state immediately if ( (talker->s_mgr.state >= TCP_STATE_ESTABLISHED) && !(talker->s_mgr.sub_state & SUB_FIN_SENT) ) { talker->l_nxt_seq++; listener->r_nxt_ack++; talker->s_mgr.sub_state |= SUB_FIN_SENT; #ifdef NORMALIZER if ((listener->flush_mgr.flush_policy != STREAM_FLPOLICY_PROTOCOL) && (listener->flush_mgr.flush_policy != STREAM_FLPOLICY_PROTOCOL_IPS) && Normalize_IsEnabled(snort_conf, NORM_TCP_IPS)) { p->packet_flags |= PKT_PDU_TAIL; } #endif } switch(talker->s_mgr.state) { case TCP_STATE_SYN_RCVD: case TCP_STATE_ESTABLISHED: if (talker->s_mgr.state_queue == TCP_STATE_CLOSE_WAIT) { talker->s_mgr.state_queue = TCP_STATE_CLOSING; } talker->s_mgr.state = TCP_STATE_FIN_WAIT_1; EndOfFileHandle(p, (TcpSession *)lwssn->proto_specific_data->data); #ifdef NORMALIZER if ( !p->dsize ) CheckFlushPolicyOnData(tcpssn, talker, listener, tdb, p); #endif Stream5UpdatePerfBaseState(&sfBase, tcpssn->lwssn, TCP_STATE_CLOSING); break; case TCP_STATE_CLOSE_WAIT: talker->s_mgr.state = TCP_STATE_LAST_ACK; break; default: /* all other states stay where they are */ break; } if ( (talker->s_mgr.state == TCP_STATE_FIN_WAIT_1) || (talker->s_mgr.state == TCP_STATE_LAST_ACK) ) { uint32_t end_seq = ( lwssn->ha_state.session_flags & SSNFLAG_MIDSTREAM ) ? tdb->end_seq-1 : tdb->end_seq; if ( (listener->s_mgr.expected_flags == TH_ACK) && SEQ_GEQ(end_seq, listener->s_mgr.transition_seq) ) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "FIN beyond previous, ignoring\n");); eventcode |= EVENT_BAD_FIN; LogTcpEvents(talker->tcp_policy, eventcode); NormalDropPacketIf(p, NORM_TCP); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_BAD_PKT; } } switch ( listener->s_mgr.state ) { case TCP_STATE_ESTABLISHED: listener->s_mgr.state_queue = TCP_STATE_CLOSE_WAIT; listener->s_mgr.transition_seq = tdb->end_seq + 1; listener->s_mgr.expected_flags = TH_ACK; break; case TCP_STATE_FIN_WAIT_1: listener->s_mgr.state_queue = TCP_STATE_CLOSING; listener->s_mgr.transition_seq = tdb->end_seq + 1; listener->s_mgr.expected_flags = TH_ACK; break; case TCP_STATE_FIN_WAIT_2: listener->s_mgr.state_queue = TCP_STATE_TIME_WAIT; listener->s_mgr.transition_seq = tdb->end_seq + 1; listener->s_mgr.expected_flags = TH_ACK; break; } } } dupfin: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " %s [talker] state: %s\n", t, state_names[talker->s_mgr.state]);); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, " %s state: %s(%d)\n", l, state_names[listener->s_mgr.state], listener->s_mgr.state);); /* * handle TIME_WAIT timer stuff */ if((talker->s_mgr.state == TCP_STATE_TIME_WAIT && listener->s_mgr.state == TCP_STATE_CLOSED) || (listener->s_mgr.state == TCP_STATE_TIME_WAIT && talker->s_mgr.state == TCP_STATE_CLOSED) || (listener->s_mgr.state == TCP_STATE_TIME_WAIT && talker->s_mgr.state == TCP_STATE_TIME_WAIT)) { //dropssn: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Session terminating, flushing session buffers\n");); if(p->packet_flags & PKT_FROM_SERVER) { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "flushing FROM_SERVER\n");); if(talker->seg_bytes_logical) { uint32_t flushed = flush_stream(tcpssn, talker, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, PKT_FROM_CLIENT); if(flushed) { // FIXTHIS - these calls redundant? purge_alerts(talker, talker->r_win_base, (void *)tcpssn->lwssn); purge_to_seq(tcpssn, talker, talker->seglist->seq + flushed); } } if(listener->seg_bytes_logical) { uint32_t flushed = flush_stream(tcpssn, listener, p, GET_SRC_IP(p), GET_DST_IP(p), p->tcph->th_sport, p->tcph->th_dport, PKT_FROM_SERVER); if(flushed) { purge_alerts(listener, listener->r_win_base, (void *)tcpssn->lwssn); purge_to_seq(tcpssn, listener, listener->seglist->seq + flushed); } } } else { STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "flushing FROM_CLIENT\n");); if(listener->seg_bytes_logical) { uint32_t flushed = flush_stream(tcpssn, listener, p, GET_SRC_IP(p), GET_DST_IP(p), p->tcph->th_sport, p->tcph->th_dport, PKT_FROM_CLIENT); if(flushed) { purge_alerts(listener, listener->r_win_base, (void *)tcpssn->lwssn); purge_to_seq(tcpssn, listener, listener->seglist->seq + flushed); } } if(talker->seg_bytes_logical) { uint32_t flushed = flush_stream(tcpssn, talker, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, PKT_FROM_SERVER); if(flushed) { purge_alerts(talker, talker->r_win_base,(void *)tcpssn->lwssn); purge_to_seq(tcpssn, talker, talker->seglist->seq + flushed); } } } LogTcpEvents(listener->tcp_policy, eventcode); /* The last ACK is a part of the session. Delete the session after processing is complete. */ TcpSessionCleanup(lwssn, 0); lwssn->session_state |= STREAM5_STATE_CLOSED; PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode | ACTION_LWSSN_CLOSED; } else if(listener->s_mgr.state == TCP_STATE_CLOSED && talker->s_mgr.state == TCP_STATE_SYN_SENT) { if(p->tcph->th_flags & TH_SYN && !(p->tcph->th_flags & TH_ACK) && !(p->tcph->th_flags & TH_RST)) { Stream5SetExpire(p, lwssn, s5TcpPolicy->session_timeout); } } #ifdef NORMALIZER if ( p->dsize > 0 ) CheckFlushPolicyOnData(tcpssn, talker, listener, tdb, p); #endif if ( p->tcph->th_flags & TH_ACK ) CheckFlushPolicyOnAck(tcpssn, talker, listener, tdb, p); LogTcpEvents(listener->tcp_policy, eventcode); PREPROC_PROFILE_END(s5TcpStatePerfStats); return retcode; } // this is for post-ack flushing static inline uint32_t GetReverseDir (const Packet* p) { /* Remember, one side's packets are stored in the * other side's queue. So when talker ACKs data, * we need to check if we're ready to flush. * * If we do decide to flush, the flush IP & port info * is the opposite of the packet -- again because this * is the ACK from the talker and we're flushing packets * that actually came from the listener. */ if ( p->packet_flags & PKT_FROM_SERVER ) return PKT_FROM_CLIENT; else if ( p->packet_flags & PKT_FROM_CLIENT ) return PKT_FROM_SERVER; return 0; } #ifdef NORMALIZER static inline uint32_t GetForwardDir (const Packet* p) { if ( p->packet_flags & PKT_FROM_SERVER ) return PKT_FROM_SERVER; else if ( p->packet_flags & PKT_FROM_CLIENT ) return PKT_FROM_CLIENT; return 0; } static inline int CheckFlushCoercion ( Packet* p, FlushMgr* fm, uint16_t flush_factor ) { if ( !flush_factor ) return 0; if ( p->dsize && (p->dsize < fm->last_size) && (fm->last_count >= flush_factor) ) { fm->last_size = 0; fm->last_count = 0; return 1; } if ( p->dsize > fm->last_size ) fm->last_size = p->dsize; fm->last_count++; return 0; } #endif static inline bool AutoDisable (StreamTracker* a, StreamTracker* b) { if ( !a->flush_mgr.auto_disable ) return false; a->flush_mgr.flush_policy = STREAM_FLPOLICY_IGNORE; purge_all(a); if ( b->flush_mgr.auto_disable ) { b->flush_mgr.flush_policy = STREAM_FLPOLICY_IGNORE; purge_all(b); } return true; } #ifdef NORMALIZER // see flush_pdu_ackd() for details // the key difference is that we operate on forward moving data // because we don't wait until it is acknowledged static inline uint32_t flush_pdu_ips ( TcpSession* ssn, StreamTracker* trk, Packet* pkt, uint32_t* flags) { bool to_srv = ( *flags == PKT_FROM_CLIENT ); uint16_t srv_port = ( to_srv ? pkt->dp : pkt->sp ); uint32_t total = 0, avail; StreamSegment* seg; PROFILE_VARS; PREPROC_PROFILE_START(s5TcpPAFPerfStats); avail = get_q_sequenced(trk); seg = trk->seglist_next; // * must stop if gap (checked in s5_paf_check) while ( seg && *flags && (total < avail) ) { uint32_t flush_pt; uint32_t size = seg->size; uint32_t end = seg->seq + seg->size; uint32_t pos = s5_paf_position(&trk->paf_state); total += size; if ( s5_paf_initialized(&trk->paf_state) && SEQ_LEQ(end, pos) ) { seg = seg->next; continue; } flush_pt = s5_paf_check( s5_tcp_eval_config->paf_config, &trk->paf_state, ssn->lwssn, seg->payload, size, total, seg->seq, srv_port, flags, trk->flush_mgr.flush_pt); if ( flush_pt > 0 ) { PREPROC_PROFILE_END(s5TcpPAFPerfStats); return flush_pt; } seg = seg->next; } PREPROC_PROFILE_END(s5TcpPAFPerfStats); return 0; } static inline int CheckFlushPolicyOnData( TcpSession *tcpssn, StreamTracker *talker, StreamTracker *listener, TcpDataBlock *tdb, Packet *p) { uint32_t flushed = 0; uint32_t avail; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "In CheckFlushPolicyOnData\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Talker flush policy: %s\n", flush_policy_names[talker->flush_mgr.flush_policy]);); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Listener flush policy: %s\n", flush_policy_names[listener->flush_mgr.flush_policy]);); switch(listener->flush_mgr.flush_policy) { case STREAM_FLPOLICY_IGNORE: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_IGNORE\n");); return 0; case STREAM_FLPOLICY_FOOTPRINT_IPS: { int coerce; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_FOOTPRINT-IPS\n");); avail = get_q_sequenced(listener); coerce = CheckFlushCoercion( p, &listener->flush_mgr, listener->tcp_policy->flush_factor); if ( (avail > 0) && (coerce || (avail >= listener->flush_mgr.flush_pt) || (avail && talker->s_mgr.state == TCP_STATE_FIN_WAIT_1)) ) { uint32_t dir = GetForwardDir(p); if ( talker->s_mgr.state == TCP_STATE_FIN_WAIT_1 ) listener->flags |= TF_FORCE_FLUSH; flushed = flush_to_seq( tcpssn, listener, avail, p, GET_SRC_IP(p), GET_DST_IP(p), p->tcph->th_sport, p->tcph->th_dport, dir); } } break; case STREAM_FLPOLICY_PROTOCOL_IPS: { uint32_t flags = GetForwardDir(p); uint32_t flush_amt = flush_pdu_ips(tcpssn, listener, p, &flags); uint32_t this_flush; while ( flush_amt > 0 ) { // if this payload is exactly one pdu, don't // actually flush, just use the raw packet if ( (tdb->seq == listener->seglist->seq) && (flush_amt == listener->seglist->size) && (flush_amt == p->dsize) ) { this_flush = flush_amt; listener->seglist->buffered = SL_BUF_FLUSHED; listener->flush_count++; p->packet_flags |= PKT_PDU_FULL; ShowRebuiltPacket(p); } else { this_flush = flush_to_seq( tcpssn, listener, flush_amt, p, GET_SRC_IP(p), GET_DST_IP(p), p->tcph->th_sport, p->tcph->th_dport, flags); } // if we didn't flush as expected, bail // (we can flush less than max dsize) if ( !this_flush ) break; flushed += this_flush; flags = GetForwardDir(p); flush_amt = flush_pdu_ips(tcpssn, listener, p, &flags); } if ( !flags ) { if ( AutoDisable(listener, talker) ) return 0; listener->flush_mgr.flush_policy = STREAM_FLPOLICY_FOOTPRINT_IPS; listener->flush_mgr.flush_pt += ScPafMax(); listener->flush_mgr.flush_type = S5_FT_PAF_MAX; return CheckFlushPolicyOnData(tcpssn, talker, listener, tdb, p); } } break; } return flushed; } #endif // iterate over seglist and scan all new acked bytes // - new means not yet scanned // - must use seglist data (not packet) since this packet may plug a // hole and enable paf scanning of following segments // - if we reach a flush point // - return bytes to flush if data available (must be acked) // - return zero if not yet received or received but not acked // - if we reach a skip point // - jump ahead and resume scanning any available data // - must stop if we reach a gap // - one segment may lead to multiple checks since // it may contain multiple encapsulated PDUs // - if we partially scan a segment we must save state so we // know where we left off and can resume scanning the remainder static inline uint32_t flush_pdu_ackd ( TcpSession* ssn, StreamTracker* trk, Packet* pkt, uint32_t* flags) { bool to_srv = ( *flags == PKT_FROM_CLIENT ); uint16_t srv_port = ( to_srv ? pkt->sp : pkt->dp ); uint32_t total = 0; StreamSegment* seg; PROFILE_VARS; PREPROC_PROFILE_START(s5TcpPAFPerfStats); seg = SEQ_LT(trk->seglist_base_seq, trk->r_win_base) ? trk->seglist : NULL; // * must stop if not acked // * must use adjusted size of seg if not fully acked // * must stop if gap (checked in s5_paf_check) while ( seg && *flags && SEQ_LT(seg->seq, trk->r_win_base) ) { uint32_t flush_pt; uint32_t size = seg->size; uint32_t end = seg->seq + seg->size; uint32_t pos = s5_paf_position(&trk->paf_state); if ( s5_paf_initialized(&trk->paf_state) && SEQ_LEQ(end, pos) ) { total += size; seg = seg->next; continue; } if ( SEQ_GT(end, trk->r_win_base) ) size = trk->r_win_base - seg->seq; total += size; flush_pt = s5_paf_check( s5_tcp_eval_config->paf_config, &trk->paf_state, ssn->lwssn, seg->payload, size, total, seg->seq, srv_port, flags, trk->flush_mgr.flush_pt); if ( flush_pt > 0 ) { PREPROC_PROFILE_END(s5TcpPAFPerfStats); return flush_pt; } seg = seg->next; } PREPROC_PROFILE_END(s5TcpPAFPerfStats); return 0; } int CheckFlushPolicyOnAck( TcpSession *tcpssn, StreamTracker *talker, StreamTracker *listener, TcpDataBlock *tdb, Packet *p) { uint32_t flushed = 0; STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "In CheckFlushPolicyOnAck\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Talker flush policy: %s\n", flush_policy_names[talker->flush_mgr.flush_policy]);); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Listener flush policy: %s\n", flush_policy_names[listener->flush_mgr.flush_policy]);); switch(talker->flush_mgr.flush_policy) { case STREAM_FLPOLICY_IGNORE: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_IGNORE\n");); return 0; case STREAM_FLPOLICY_FOOTPRINT: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_FOOTPRINT\n");); { if(get_q_footprint(talker) >= talker->flush_mgr.flush_pt) { uint32_t dir = GetReverseDir(p); flushed = flush_ackd(tcpssn, talker, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, dir); if(flushed) purge_flushed_ackd(tcpssn, talker); } } break; case STREAM_FLPOLICY_LOGICAL: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_LOGICAL\n");); if(talker->seg_bytes_logical > talker->flush_mgr.flush_pt) { uint32_t dir = GetReverseDir(p); flushed = flush_ackd(tcpssn, talker, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, dir); if(flushed) purge_flushed_ackd(tcpssn, talker); } break; case STREAM_FLPOLICY_RESPONSE: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Running FLPOLICY_RESPONSE\n");); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "checking l.r_win_base (0x%X) > " "t.seglist_base_seq (0x%X)\n", talker->r_win_base, talker->seglist_base_seq);); if(SEQ_GT(talker->r_win_base, talker->seglist_base_seq) && IsWellFormed(p, talker)) { uint32_t dir = GetReverseDir(p); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "flushing talker, t->sbl: %d\n", talker->seg_bytes_logical);); //PrintStreamTracker(talker); //PrintStreamTracker(talker); flushed = flush_ackd(tcpssn, talker, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, dir); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "bye bye data...\n");); if(flushed) purge_flushed_ackd(tcpssn, talker); } break; case STREAM_FLPOLICY_SLIDING_WINDOW: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_SLIDING_WINDOW\n");); if(get_q_footprint(talker) >= talker->flush_mgr.flush_pt) { uint32_t dir = GetReverseDir(p); flushed = flush_ackd(tcpssn, talker, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, dir); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Deleting head node for sliding window...\n");); /* Base sequence for next window'd flush is the end * of the first packet. */ talker->seglist_base_seq = talker->seglist->seq + talker->seglist->size; Stream5SeglistDeleteNode(talker, talker->seglist); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "setting talker->seglist_base_seq to 0x%X\n", talker->seglist->seq);); } break; #if 0 case STREAM_FLPOLICY_CONSUMED: STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "STREAM_FLPOLICY_CONSUMED\n");); if(get_q_footprint(talker) >= talker->flush_mgr.flush_pt) { uint32_t dir = GetReverseDir(p); flushed = flush_ackd(tcpssn, talker, p, p->iph->ip_dst.s_addr, p->iph->ip_src.s_addr, p->tcph->th_dport, p->tcph->th_sport, dir); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Deleting head node for sliding window...\n");); talker->seglist_base_seq = talker->seglist->seq + talker->seglist->size; /* TODO: Delete up to the consumed bytes */ Stream5SeglistDeleteNode(talker, talker->seglist); STREAM5_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "setting talker->seglist_base_seq to 0x%X\n", talker->seglist->seq);); } break; #endif case STREAM_FLPOLICY_PROTOCOL: { uint32_t flags = GetReverseDir(p); uint32_t flush_amt = flush_pdu_ackd(tcpssn, talker, p, &flags); while ( flush_amt > 0 ) { talker->seglist_next = talker->seglist; talker->seglist_base_seq = talker->seglist->seq; // for consistency with other cases, should return total // but that breaks flushing pipelined pdus flushed = flush_to_seq( tcpssn, talker, flush_amt, p, GET_DST_IP(p), GET_SRC_IP(p), p->tcph->th_dport, p->tcph->th_sport, flags); // ideally we would purge just once after this loop // but that throws off base purge_to_seq(tcpssn, talker, talker->seglist->seq + flushed); // if we didn't flush as expected, bail // (we can flush less than max dsize) if ( !flushed ) break; flags = GetReverseDir(p); flush_amt = flush_pdu_ackd(tcpssn, talker, p, &flags); } if ( !flags ) { if ( AutoDisable(talker, listener) ) return 0; talker->flush_mgr.flush_policy = STREAM_FLPOLICY_FOOTPRINT; talker->flush_mgr.flush_pt += ScPafMax(); talker->flush_mgr.flush_type = S5_FT_PAF_MAX; return CheckFlushPolicyOnAck(tcpssn, talker, listener, tdb, p); } } break; #ifdef NORMALIZER case STREAM_FLPOLICY_FOOTPRINT_IPS: case STREAM_FLPOLICY_PROTOCOL_IPS: purge_flushed_ackd(tcpssn, talker); break; #endif } return flushed; } static void Stream5SeglistAddNode(StreamTracker *st, StreamSegment *prev, StreamSegment *new) { s5stats.tcp_streamsegs_created++; if(prev) { new->next = prev->next; new->prev = prev; prev->next = new; if (new->next) new->next->prev = new; else st->seglist_tail = new; } else { new->next = st->seglist; if(new->next) new->next->prev = new; else st->seglist_tail = new; st->seglist = new; } st->seg_count++; #ifdef DEBUG new->ordinal = st->segment_ordinal++; if (new->next && (new->next->seq == new->seq)) { LogMessage("Same seq to right, check me\n"); } #endif } static int Stream5SeglistDeleteNode (StreamTracker* st, StreamSegment* seg) { int ret; assert(st && seg); STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "Dropping segment at seq %X, len %d\n", seg->seq, seg->size);); if(seg->prev) seg->prev->next = seg->next; else st->seglist = seg->next; if(seg->next) seg->next->prev = seg->prev; else st->seglist_tail = seg->prev; st->seg_bytes_logical -= seg->size; st->seg_bytes_total -= seg->caplen; ret = seg->caplen; if (seg->buffered) { s5stats.tcp_rebuilt_seqs_used++; st->flush_count--; } if ( st->seglist_next == seg ) st->seglist_next = NULL; SegmentFree(seg); st->seg_count--; return ret; } static int Stream5SeglistDeleteNodeTrim ( StreamTracker* st, StreamSegment* seg, uint32_t flush_seq) { assert(st && seg); if ( s5_paf_active(&st->paf_state) && ((seg->seq + seg->size) > flush_seq) ) { uint32_t delta = flush_seq - seg->seq; if ( delta < seg->size ) { STREAM5_DEBUG_WRAP( DebugMessage(DEBUG_STREAM_STATE, "Left-Trimming segment at seq %X, len %d, delta %u\n", seg->seq, seg->size, delta);); seg->seq = flush_seq; seg->size -= (uint16_t)delta; st->seg_bytes_logical -= delta; return 0; } } return Stream5SeglistDeleteNode(st, seg); } void TcpUpdateDirection(Stream5LWSession *ssn, char dir, snort_ip_p ip, uint16_t port) { TcpSession *tcpssn = (TcpSession *)ssn->proto_specific_data->data; snort_ip tmpIp; uint16_t tmpPort; StreamTracker tmpTracker; if (IP_EQUALITY(&tcpssn->tcp_client_ip, ip) && (tcpssn->tcp_client_port == port)) { if ((dir == SSN_DIR_FROM_CLIENT) && (ssn->ha_state.direction == SSN_DIR_FROM_CLIENT)) { /* Direction already set as client */ return; } } else if (IP_EQUALITY(&tcpssn->tcp_server_ip, ip) && (tcpssn->tcp_server_port == port)) { if ((dir == SSN_DIR_FROM_SERVER) && (ssn->ha_state.direction == SSN_DIR_FROM_SERVER)) { /* Direction already set as server */ return; } } /* Swap them -- leave ssn->ha_state.direction the same */ /* XXX: Gotta be a more efficient way to do this without the memcpy */ tmpIp = tcpssn->tcp_client_ip; tmpPort = tcpssn->tcp_client_port; tcpssn->tcp_client_ip = tcpssn->tcp_server_ip; tcpssn->tcp_client_port = tcpssn->tcp_server_port; tcpssn->tcp_server_ip = tmpIp; tcpssn->tcp_server_port = tmpPort; #ifdef HAVE_DAQ_ADDRESS_SPACE_ID SwapPacketHeaderFoo(tcpssn); #endif memcpy(&tmpTracker, &tcpssn->client, sizeof(StreamTracker)); memcpy(&tcpssn->client, &tcpssn->server, sizeof(StreamTracker)); memcpy(&tcpssn->server, &tmpTracker, sizeof(StreamTracker)); } /* Iterates through the packets that were reassembled for * logging of tagged packets. */ int GetTcpRebuiltPackets(Packet *p, Stream5LWSession *ssn, PacketIterator callback, void *userdata) { int packets = 0; TcpSession *tcpssn = (TcpSession *)ssn->proto_specific_data->data; StreamTracker *st; StreamSegment *ss; uint32_t start_seq = ntohl(p->tcph->th_seq); uint32_t end_seq = start_seq + p->dsize; if (!tcpssn) { return packets; } /* StreamTracker is the opposite of the ip of the reassembled * packet --> it came out the queue for the other side */ if (IP_EQUALITY(GET_SRC_IP(p), &tcpssn->tcp_client_ip)) { st = &tcpssn->server; } else { st = &tcpssn->client; } // skip over segments not covered by this reassembled packet for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next); // return flushed segments only for (; ss && ss->buffered == SL_BUF_FLUSHED; ss = ss->next) { if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq)) { DAQ_PktHdr_t pkth; pkth.ts.tv_sec = ss->tv.tv_sec; pkth.ts.tv_usec = ss->tv.tv_usec; pkth.caplen = ss->caplen; pkth.pktlen = ss->pktlen; callback(&pkth, ss->pkt, userdata); packets++; } else break; } return packets; } /* Iterates through the packets that were reassembled for * logging of tagged packets. */ int GetTcpStreamSegments(Packet *p, Stream5LWSession *ssn, StreamSegmentIterator callback, void *userdata) { int packets = 0; TcpSession *tcpssn = (TcpSession *)ssn->proto_specific_data->data; StreamTracker *st; StreamSegment *ss; uint32_t start_seq = ntohl(p->tcph->th_seq); uint32_t end_seq = start_seq + p->dsize; if (tcpssn == NULL) return -1; /* StreamTracker is the opposite of the ip of the reassembled * packet --> it came out the queue for the other side */ if (IP_EQUALITY(GET_SRC_IP(p), &tcpssn->tcp_client_ip)) st = &tcpssn->server; else st = &tcpssn->client; // skip over segments not covered by this reassembled packet for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next); // return flushed segments only for (; ss && ss->buffered == SL_BUF_FLUSHED; ss = ss->next) { if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq)) { DAQ_PktHdr_t pkth; pkth.ts.tv_sec = ss->tv.tv_sec; pkth.ts.tv_usec = ss->tv.tv_usec; pkth.caplen = ss->caplen; pkth.pktlen = ss->pktlen; if (callback(&pkth, ss->pkt, ss->data, ss->seq, userdata) != 0) return -1; packets++; } else break; } return packets; } int Stream5AddSessionAlertTcp( Stream5LWSession* lwssn, Packet* p, uint32_t gid, uint32_t sid) { TcpSession *tcpssn = NULL; StreamTracker *st; Stream5AlertInfo* ai; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) { return 0; } if (IP_EQUALITY(GET_SRC_IP(p),&tcpssn->tcp_client_ip)) { st = &tcpssn->server; } else { st = &tcpssn->client; } if (st->alert_count >= MAX_SESSION_ALERTS) return 0; ai = st->alerts + st->alert_count; ai->gid = gid; ai->sid = sid; ai->seq = GET_PKT_SEQ(p); if ( p->tcph->th_flags & TH_FIN ) ai->seq--; st->alert_count++; return 0; } int Stream5CheckSessionAlertTcp(Stream5LWSession *lwssn, Packet *p, uint32_t gid, uint32_t sid) { TcpSession *tcpssn = NULL; StreamTracker *st; int i; int iRet = 0; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) { return 0; } /* If this is not a rebuilt packet, no need to check further */ if (!(p->packet_flags & PKT_REBUILT_STREAM)) { return 0; } if (IP_EQUALITY(GET_SRC_IP(p), &tcpssn->tcp_client_ip)) { st = &tcpssn->server; } else { st = &tcpssn->client; } for (i=0;ialert_count;i++) { /* This is a rebuilt packet and if we've seen this alert before, * return that we have previously alerted on original packet. */ if ( st->alerts[i].gid == gid && st->alerts[i].sid == sid ) { return -1; } } return iRet; } int Stream5UpdateSessionAlertTcp ( Stream5LWSession *lwssn, Packet *p, uint32_t gid, uint32_t sid, uint32_t event_id, uint32_t event_second) { TcpSession *tcpssn = NULL; StreamTracker *st; int i; uint32_t seq_num; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) { return 0; } if (IP_EQUALITY(GET_SRC_IP(p), &tcpssn->tcp_client_ip)) { st = &tcpssn->server; } else { st = &tcpssn->client; } seq_num = GET_PKT_SEQ(p); if ( p->tcph->th_flags & TH_FIN ) seq_num--; for (i=0;ialert_count;i++) { Stream5AlertInfo* ai = st->alerts + i; if ( ai->gid == gid && ai->sid == sid && SEQ_EQ(ai->seq, seq_num)) { ai->event_id = event_id; ai->event_second = event_second; return 0; } } return -1; } void Stream5SetExtraDataTcp (Stream5LWSession* lwssn, Packet* p, uint32_t xid) { TcpSession *tcpssn = NULL; StreamTracker *st; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return; if (IP_EQUALITY(GET_SRC_IP(p),&tcpssn->tcp_client_ip)) st = &tcpssn->server; else st = &tcpssn->client; st->xtradata_mask |= BIT(xid); } void Stream5ClearExtraDataTcp (Stream5LWSession* lwssn, Packet* p, uint32_t xid) { TcpSession *tcpssn = NULL; StreamTracker *st; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return; if (IP_EQUALITY(GET_SRC_IP(p),&tcpssn->tcp_client_ip)) st = &tcpssn->server; else st = &tcpssn->client; if ( xid ) st->xtradata_mask &= ~BIT(xid); else st->xtradata_mask = 0; } char Stream5GetReassemblyDirectionTcp(Stream5LWSession *lwssn) { TcpSession *tcpssn = NULL; char dir = SSN_DIR_NONE; if (!lwssn) return SSN_DIR_NONE; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return SSN_DIR_NONE; if ((tcpssn->server.flush_mgr.flush_policy != STREAM_FLPOLICY_NONE) && (tcpssn->server.flush_mgr.flush_policy != STREAM_FLPOLICY_IGNORE)) { dir |= SSN_DIR_FROM_SERVER; } if ((tcpssn->client.flush_mgr.flush_policy != STREAM_FLPOLICY_NONE) && (tcpssn->client.flush_mgr.flush_policy != STREAM_FLPOLICY_IGNORE)) { dir |= SSN_DIR_FROM_CLIENT; } return dir; } uint32_t Stream5GetFlushPointTcp(Stream5LWSession *lwssn, char dir) { TcpSession *tcpssn = NULL; if (lwssn == NULL) return 0; if (lwssn->proto_specific_data != NULL) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (tcpssn == NULL) return 0; if (dir & SSN_DIR_FROM_CLIENT) return tcpssn->client.flush_mgr.flush_pt; else if (dir & SSN_DIR_FROM_SERVER) return tcpssn->server.flush_mgr.flush_pt; return 0; } void Stream5SetFlushPointTcp(Stream5LWSession *lwssn, char dir, uint32_t flush_point) { TcpSession *tcpssn = NULL; if (lwssn == NULL) return; if (lwssn->proto_specific_data != NULL) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (tcpssn == NULL) return; if (flush_point == 0) return; if (dir & SSN_DIR_FROM_CLIENT) { tcpssn->client.flush_mgr.flush_pt = flush_point; tcpssn->client.flush_mgr.last_size = 0; tcpssn->client.flush_mgr.last_count = 0; tcpssn->client.flush_mgr.flush_type = S5_FT_EXTERNAL; } else if (dir & SSN_DIR_FROM_SERVER) { tcpssn->server.flush_mgr.flush_pt = flush_point; tcpssn->server.flush_mgr.last_size = 0; tcpssn->server.flush_mgr.last_count = 0; tcpssn->server.flush_mgr.flush_type = S5_FT_EXTERNAL; } } char Stream5SetReassemblyTcp(Stream5LWSession *lwssn, uint8_t flush_policy, char dir, char flags) { TcpSession *tcpssn = NULL; uint16_t tmp_flags; if (!lwssn) return SSN_DIR_NONE; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return SSN_DIR_NONE; tmp_flags = (flush_policy == STREAM_FLPOLICY_IGNORE)? 0: TF_FIRST_PKT_MISSING; if (flags & STREAM_FLPOLICY_SET_APPEND) { if (dir & SSN_DIR_FROM_CLIENT) { if (tcpssn->client.flush_mgr.flush_policy != STREAM_FLPOLICY_NONE) { /* Changing policy with APPEND, Bad */ DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream: Changing client flush policy using " "append is asking for trouble. Ignored\n");); } else { InitFlushMgr(&tcpssn->client.flush_mgr, &tcpssn->client.tcp_policy->flush_point_list, flush_policy, 0); tcpssn->client.flags |= tmp_flags; } } if (dir & SSN_DIR_FROM_SERVER) { if (tcpssn->server.flush_mgr.flush_policy != STREAM_FLPOLICY_NONE) { /* Changing policy with APPEND, Bad */ DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "Stream: Changing server flush policy using " "append is asking for trouble. Ignored\n");); } else { InitFlushMgr(&tcpssn->server.flush_mgr, &tcpssn->server.tcp_policy->flush_point_list, flush_policy, 0); tcpssn->server.flags |= tmp_flags; } } } else if (flags & STREAM_FLPOLICY_SET_ABSOLUTE) { if (dir & SSN_DIR_FROM_CLIENT) { InitFlushMgr(&tcpssn->client.flush_mgr, &tcpssn->client.tcp_policy->flush_point_list, flush_policy, 0); tcpssn->client.flags |= tmp_flags; } if (dir & SSN_DIR_FROM_SERVER) { InitFlushMgr(&tcpssn->server.flush_mgr, &tcpssn->server.tcp_policy->flush_point_list, flush_policy, 0); tcpssn->server.flags |= tmp_flags; } } return Stream5GetReassemblyDirectionTcp(lwssn); } char Stream5GetReassemblyFlushPolicyTcp(Stream5LWSession *lwssn, char dir) { TcpSession *tcpssn = NULL; if (!lwssn) return STREAM_FLPOLICY_NONE; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return STREAM_FLPOLICY_NONE; if (dir & SSN_DIR_FROM_CLIENT) { return (char)tcpssn->client.flush_mgr.flush_policy; } if (dir & SSN_DIR_FROM_SERVER) { return (char)tcpssn->server.flush_mgr.flush_policy; } return STREAM_FLPOLICY_NONE; } char Stream5IsStreamSequencedTcp(Stream5LWSession *lwssn, char dir) { TcpSession *tcpssn = NULL; if (!lwssn) return 1; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return 1; if (dir & SSN_DIR_FROM_CLIENT) { if ( tcpssn->server.flags & TF_MISSING_PREV_PKT ) return 0; } if (dir & SSN_DIR_FROM_SERVER) { if ( tcpssn->client.flags & TF_MISSING_PREV_PKT ) return 0; } return 1; } /* This will falsly return SSN_MISSING_BEFORE on the first reassembed * packet if reassembly for this direction was set mid-session */ int Stream5MissingInReassembledTcp(Stream5LWSession *lwssn, char dir) { TcpSession *tcpssn = NULL; if (!lwssn) return SSN_MISSING_NONE; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return SSN_MISSING_NONE; if (dir & SSN_DIR_FROM_CLIENT) { if (tcpssn->server.flags & TF_MISSING_PREV_PKT) return SSN_MISSING_BEFORE; } else if (dir & SSN_DIR_FROM_SERVER) { if (tcpssn->client.flags & TF_MISSING_PREV_PKT) return SSN_MISSING_BEFORE; } return SSN_MISSING_NONE; } char Stream5PacketsMissingTcp(Stream5LWSession *lwssn, char dir) { TcpSession *tcpssn = NULL; if (!lwssn) return 0; if (lwssn->proto_specific_data) tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (!tcpssn) return 0; if (dir & SSN_DIR_FROM_CLIENT) { if (tcpssn->server.flags & TF_PKT_MISSED) return 1; } if (dir & SSN_DIR_FROM_SERVER) { if (tcpssn->client.flags & TF_PKT_MISSED) return 1; } return 0; } #define SSOD_LESS_THAN 1 #define SSOD_GREATER_THAN 2 #define SSOD_EQUALS 3 #define SSOD_LESS_THAN_OR_EQUALS 4 #define SSOD_GREATER_THAN_OR_EQUALS 5 #define SSOD_NOT_EQUALS 6 #define SSOD_MATCH 1 #define SSOD_NOMATCH 0 typedef struct _StreamSizeOptionData { char operator; uint32_t size; char direction; } StreamSizeOptionData; int s5TcpStreamSizeInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr) { char **toks; int num_toks; char *endp; StreamSizeOptionData *ssod = NULL; toks = mSplit(parameters, ",", 4, &num_toks, 0); if (num_toks != 3) { FatalError("%s(%d): Invalid parameters for %s option\n", file_name, file_line, name); } ssod = SnortAlloc(sizeof(StreamSizeOptionData)); if (!ssod) { FatalError("%s(%d): Failed to allocate data for %s option\n", file_name, file_line, name); } /* Parse the direction. * Can be: client, server, both, either */ if (!strcasecmp(toks[0], "client")) { ssod->direction = SSN_DIR_FROM_CLIENT; } else if (!strcasecmp(toks[0], "server")) { ssod->direction = SSN_DIR_FROM_SERVER; } else if (!strcasecmp(toks[0], "both")) { ssod->direction = SSN_DIR_BOTH; } else if (!strcasecmp(toks[0], "either")) { ssod->direction = SSN_DIR_NONE; } else { FatalError("%s(%d): Invalid direction: %s for option %s\n", file_name, file_line, toks[0], name); } /* Parse the operator. * Can be: =, <, > , !=, <=, >= */ if (!strcasecmp(toks[1], "=")) { ssod->operator = SSOD_EQUALS; } else if (!strcasecmp(toks[1], "<")) { ssod->operator = SSOD_LESS_THAN; } else if (!strcasecmp(toks[1], ">")) { ssod->operator = SSOD_GREATER_THAN; } else if (!strcasecmp(toks[1], "!=")) { ssod->operator = SSOD_NOT_EQUALS; } else if (!strcasecmp(toks[1], "<=")) { ssod->operator = SSOD_LESS_THAN_OR_EQUALS; } else if (!strcasecmp(toks[1], ">=")) { ssod->operator = SSOD_GREATER_THAN_OR_EQUALS; } else { FatalError("%s(%d): Invalid operator: %s for option %s\n", file_name, file_line, toks[1], name); } ssod->size = SnortStrtoul(toks[2], &endp, 0); if ((endp == toks[2]) || (errno == ERANGE)) { FatalError("%s(%d): Invalid size: %s for option %s\n", file_name, file_line, toks[2], name); } *dataPtr = ssod; mSplitFree(&toks, num_toks); return 1; } static inline int s5TcpStreamSizeCompare(uint32_t size1, uint32_t size2, char operator) { int retval = 0; switch (operator) { case SSOD_EQUALS: if (size1 == size2) retval = 1; break; case SSOD_LESS_THAN: if (size1 < size2) retval = 1; break; case SSOD_GREATER_THAN: if (size1 > size2) retval = 1; break; case SSOD_NOT_EQUALS: if (size1 != size2) retval = 1; break; case SSOD_LESS_THAN_OR_EQUALS: if (size1 <= size2) retval = 1; break; case SSOD_GREATER_THAN_OR_EQUALS: if (size1 >= size2) retval = 1; break; default: break; } return retval; } int s5TcpStreamSizeEval(void *p, const uint8_t **cursor, void *dataPtr) { Packet *pkt = p; Stream5LWSession *lwssn = NULL; TcpSession *tcpssn = NULL; StreamSizeOptionData *ssod = (StreamSizeOptionData *)dataPtr; uint32_t client_size; uint32_t server_size; PROFILE_VARS; if (!pkt || !pkt->ssnptr || !ssod || !pkt->tcph) return DETECTION_OPTION_NO_MATCH; lwssn = pkt->ssnptr; if (!lwssn->proto_specific_data) return DETECTION_OPTION_NO_MATCH; PREPROC_PROFILE_START(streamSizePerfStats); tcpssn = (TcpSession *)lwssn->proto_specific_data->data; if (tcpssn->client.l_nxt_seq > tcpssn->client.isn) { /* the normal case... */ client_size = tcpssn->client.l_nxt_seq - tcpssn->client.isn; } else { /* the seq num wrapping case... */ client_size = tcpssn->client.isn - tcpssn->client.l_nxt_seq; } if (tcpssn->server.l_nxt_seq > tcpssn->server.isn) { /* the normal case... */ server_size = tcpssn->server.l_nxt_seq - tcpssn->server.isn; } else { /* the seq num wrapping case... */ server_size = tcpssn->server.isn - tcpssn->server.l_nxt_seq; } switch (ssod->direction) { case SSN_DIR_FROM_CLIENT: if (s5TcpStreamSizeCompare(client_size, ssod->size, ssod->operator) == SSOD_MATCH) { PREPROC_PROFILE_END(streamSizePerfStats); return DETECTION_OPTION_MATCH; } break; case SSN_DIR_FROM_SERVER: if (s5TcpStreamSizeCompare(server_size, ssod->size, ssod->operator) == SSOD_MATCH) { PREPROC_PROFILE_END(streamSizePerfStats); return DETECTION_OPTION_MATCH; } break; case SSN_DIR_NONE: /* overloaded. really, its an 'either' */ if ((s5TcpStreamSizeCompare(client_size, ssod->size, ssod->operator) == SSOD_MATCH) || (s5TcpStreamSizeCompare(server_size, ssod->size, ssod->operator) == SSOD_MATCH)) { PREPROC_PROFILE_END(streamSizePerfStats); return DETECTION_OPTION_MATCH; } break; case SSN_DIR_BOTH: if ((s5TcpStreamSizeCompare(client_size, ssod->size, ssod->operator) == SSOD_MATCH) && (s5TcpStreamSizeCompare(server_size, ssod->size, ssod->operator) == SSOD_MATCH)) { PREPROC_PROFILE_END(streamSizePerfStats); return DETECTION_OPTION_MATCH; } break; default: break; } PREPROC_PROFILE_END(streamSizePerfStats); return DETECTION_OPTION_NO_MATCH; } void s5TcpStreamSizeCleanup(void *dataPtr) { StreamSizeOptionData *ssod = dataPtr; if (ssod) { free(ssod); } } typedef struct _StreamReassembleRuleOptionData { char enable; char alert; char direction; char fastpath; } StreamReassembleRuleOptionData; int s5TcpStreamReassembleRuleOptionInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr) { char **toks; int num_toks; StreamReassembleRuleOptionData *srod = NULL; toks = mSplit(parameters, ",", 4, &num_toks, 0); if (num_toks < 2) { FatalError("%s(%d): Invalid parameters for %s option\n", file_name, file_line, name); } srod = SnortAlloc(sizeof(StreamReassembleRuleOptionData)); if (!srod) { FatalError("%s(%d): Failed to allocate data for %s option\n", file_name, file_line, name); } /* Parse the action. * Can be: enable or disable */ if (!strcasecmp(toks[0], "enable")) { srod->enable = 1; } else if (!strcasecmp(toks[0], "disable")) { srod->enable = 0; } else { FatalError("%s(%d): Invalid action: %s for option %s. Valid " "parameters are 'enable' or 'disable'\n", file_name, file_line, toks[0], name); } /* Parse the direction. * Can be: client, server, both */ /* Need to these around, so they match the ones specified via the stream5_tcp ports * option, ie, stream5_tcp: ports client enables reassembly on client-sourced traffic. */ if (!strcasecmp(toks[1], "client")) { srod->direction = SSN_DIR_FROM_SERVER; } else if (!strcasecmp(toks[1], "server")) { srod->direction = SSN_DIR_FROM_CLIENT; } else if (!strcasecmp(toks[1], "both")) { srod->direction = SSN_DIR_BOTH; } else { FatalError("%s(%d): Invalid direction: %s for option %s\n", file_name, file_line, toks[1], name); } /* Parse the optional parameters: * noalert flag, fastpath flag */ srod->alert = 1; if (num_toks > 2) { int i = 2; for (; i< num_toks; i++) { if (!strcasecmp(toks[i], "noalert")) { srod->alert = 0; } else if (!strcasecmp(toks[i], "fastpath")) { srod->fastpath = 1; if (srod->enable) { FatalError("%s(%d): Using 'fastpath' with 'enable' is " "not valid for %s\n", file_name, file_line, name); } } else { FatalError("%s(%d): Invalid optional parameter: %s for option %s\n", file_name, file_line, toks[i], name); } } } *dataPtr = srod; mSplitFree(&toks, num_toks); return 1; } int s5TcpStreamReassembleRuleOptionEval(void *p, const uint8_t **cursor, void *dataPtr) { Packet *pkt = p; Stream5LWSession *lwssn = NULL; StreamReassembleRuleOptionData *srod = (StreamReassembleRuleOptionData *)dataPtr; PROFILE_VARS; if (!pkt || !pkt->ssnptr || !srod || !pkt->tcph) return 0; PREPROC_PROFILE_START(streamReassembleRuleOptionPerfStats); lwssn = pkt->ssnptr; if (!srod->enable) /* Turn it off */ Stream5SetReassemblyTcp(lwssn, STREAM_FLPOLICY_IGNORE, srod->direction, STREAM_FLPOLICY_SET_ABSOLUTE); else Stream5SetReassemblyTcp(lwssn, STREAM_FLPOLICY_FOOTPRINT, srod->direction, STREAM_FLPOLICY_SET_ABSOLUTE); if (srod->fastpath) { /* Turn off inspection */ lwssn->ha_state.ignore_direction |= srod->direction; Stream5DisableInspection(lwssn, pkt); /* TBD: Set TF_FORCE_FLUSH ? */ } if (srod->alert) { PREPROC_PROFILE_END(streamReassembleRuleOptionPerfStats); return DETECTION_OPTION_MATCH; } PREPROC_PROFILE_END(streamReassembleRuleOptionPerfStats); return DETECTION_OPTION_NO_ALERT; } void s5TcpStreamReassembleRuleOptionCleanup(void *dataPtr) { StreamReassembleRuleOptionData *srod = dataPtr; if (srod) { free(srod); } } void s5TcpSetPortFilterStatus(struct _SnortConfig *sc, unsigned short port, uint16_t status, tSfPolicyId policyId, int parsing) { Stream5Config *config; Stream5TcpConfig *tcp_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; if (parsing && ((s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc)) != NULL)) config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policyId); else #endif config = (Stream5Config *)sfPolicyUserDataGet(s5_config, policyId); if (config == NULL) return; tcp_config = config->tcp_config; if (tcp_config == NULL) return; tcp_config->port_filter[port] |= status; } void s5TcpUnsetPortFilterStatus(struct _SnortConfig *sc, unsigned short port, uint16_t status, tSfPolicyId policyId, int parsing) { Stream5Config *config; Stream5TcpConfig *tcp_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; if (parsing && ((s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc)) != NULL)) config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policyId); else #endif config = (Stream5Config *)sfPolicyUserDataGet(s5_config, policyId); if (config == NULL) return; tcp_config = config->tcp_config; if (tcp_config == NULL) return; tcp_config->port_filter[port] &= ~status; } int s5TcpGetPortFilterStatus(struct _SnortConfig *sc, unsigned short port, tSfPolicyId policyId, int parsing) { Stream5Config *config; Stream5TcpConfig *tcp_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; if (parsing && ((s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc)) != NULL)) config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policyId); else #endif config = (Stream5Config *)sfPolicyUserDataGet(s5_config, policyId); if (config == NULL) return PORT_MONITOR_NONE; tcp_config = config->tcp_config; if (tcp_config == NULL) return PORT_MONITOR_NONE; return (int)tcp_config->port_filter[port]; } void s5TcpSetSynSessionStatus(struct _SnortConfig *sc, uint16_t status, tSfPolicyId policyId, int parsing) { Stream5Config *config; Stream5TcpConfig *tcp_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; #endif if (status <= PORT_MONITOR_SESSION) return; #ifdef SNORT_RELOAD if (parsing && ((s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc)) != NULL)) config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policyId); else #endif config = (Stream5Config *)sfPolicyUserDataGet(s5_config, policyId); if (config == NULL) return; tcp_config = config->tcp_config; if (tcp_config == NULL) return; tcp_config->session_on_syn |= status; } void s5TcpUnsetSynSessionStatus(struct _SnortConfig *sc, uint16_t status, tSfPolicyId policyId, int parsing) { Stream5Config *config; Stream5TcpConfig *tcp_config; #ifdef SNORT_RELOAD tSfPolicyUserContextId s5_swap_config; #endif if (status <= PORT_MONITOR_SESSION) return; #ifdef SNORT_RELOAD if (parsing && ((s5_swap_config = (tSfPolicyUserContextId)GetReloadStreamConfig(sc)) != NULL)) config = (Stream5Config *)sfPolicyUserDataGet(s5_swap_config, policyId); else #endif config = (Stream5Config *)sfPolicyUserDataGet(s5_config, policyId); if (config == NULL) return; tcp_config = config->tcp_config; if (tcp_config == NULL) return; tcp_config->session_on_syn &= ~status; } static void targetPolicyIterate(void (*callback)(int)) { unsigned int i; for (i = 0; i < snort_conf->num_policies_allocated; i++) { if (snort_conf->targeted_policies[i] != NULL) { callback(i); } } } static void policyDecoderFlagsSaveNClear(int policyId) { SnortPolicy *pPolicy = snort_conf->targeted_policies[policyId]; if (pPolicy) { pPolicy->decoder_alert_flags_saved = pPolicy->decoder_alert_flags; pPolicy->decoder_drop_flags_saved = pPolicy->decoder_drop_flags; pPolicy->decoder_alert_flags = 0; pPolicy->decoder_drop_flags = 0; } } static void policyDecoderFlagsRestore(int policyId) { SnortPolicy *pPolicy = snort_conf->targeted_policies[policyId]; if (pPolicy) { pPolicy->decoder_alert_flags = pPolicy->decoder_alert_flags_saved; pPolicy->decoder_drop_flags = pPolicy->decoder_drop_flags_saved; pPolicy->decoder_alert_flags_saved = 0; pPolicy->decoder_drop_flags_saved = 0; } } snort-2.9.6.0/src/preprocessors/Stream5/Makefile.am0000644000000000000000000000130612153454771017007 00000000000000## $Id AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libstream5.a libstream5_a_SOURCES = \ snort_stream5_tcp.c \ snort_stream5_tcp.h \ snort_stream5_udp.c \ snort_stream5_udp.h \ snort_stream5_icmp.c \ snort_stream5_icmp.h \ snort_stream5_ip.c \ snort_stream5_ip.h \ snort_stream5_session.c \ snort_stream5_session.h \ stream5_paf.c \ stream5_paf.h \ stream5_common.c \ stream5_common.h libstream5_a_LIBADD = \ snort_stream5_tcp.o \ snort_stream5_udp.o \ snort_stream5_icmp.o \ snort_stream5_ip.o \ snort_stream5_session.o \ stream5_paf.o \ stream5_common.o if BUILD_HA libstream5_a_SOURCES += \ stream5_ha.c \ stream5_ha.h libstream5_a_LIBADD += \ stream5_ha.o endif INCLUDES = @INCLUDES@ snort-2.9.6.0/src/preprocessors/Stream5/Makefile.in0000644000000000000000000004253612260606525017025 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @BUILD_HA_TRUE@am__append_1 = \ @BUILD_HA_TRUE@stream5_ha.c \ @BUILD_HA_TRUE@stream5_ha.h @BUILD_HA_TRUE@am__append_2 = \ @BUILD_HA_TRUE@stream5_ha.o subdir = src/preprocessors/Stream5 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libstream5_a_AR = $(AR) $(ARFLAGS) libstream5_a_DEPENDENCIES = snort_stream5_tcp.o snort_stream5_udp.o \ snort_stream5_icmp.o snort_stream5_ip.o \ snort_stream5_session.o stream5_paf.o stream5_common.o \ $(am__append_2) am__libstream5_a_SOURCES_DIST = snort_stream5_tcp.c \ snort_stream5_tcp.h snort_stream5_udp.c snort_stream5_udp.h \ snort_stream5_icmp.c snort_stream5_icmp.h snort_stream5_ip.c \ snort_stream5_ip.h snort_stream5_session.c \ snort_stream5_session.h stream5_paf.c stream5_paf.h \ stream5_common.c stream5_common.h stream5_ha.c stream5_ha.h @BUILD_HA_TRUE@am__objects_1 = stream5_ha.$(OBJEXT) am_libstream5_a_OBJECTS = snort_stream5_tcp.$(OBJEXT) \ snort_stream5_udp.$(OBJEXT) snort_stream5_icmp.$(OBJEXT) \ snort_stream5_ip.$(OBJEXT) snort_stream5_session.$(OBJEXT) \ stream5_paf.$(OBJEXT) stream5_common.$(OBJEXT) \ $(am__objects_1) libstream5_a_OBJECTS = $(am_libstream5_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libstream5_a_SOURCES) DIST_SOURCES = $(am__libstream5_a_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libstream5.a libstream5_a_SOURCES = snort_stream5_tcp.c snort_stream5_tcp.h \ snort_stream5_udp.c snort_stream5_udp.h snort_stream5_icmp.c \ snort_stream5_icmp.h snort_stream5_ip.c snort_stream5_ip.h \ snort_stream5_session.c snort_stream5_session.h stream5_paf.c \ stream5_paf.h stream5_common.c stream5_common.h \ $(am__append_1) libstream5_a_LIBADD = snort_stream5_tcp.o snort_stream5_udp.o \ snort_stream5_icmp.o snort_stream5_ip.o \ snort_stream5_session.o stream5_paf.o stream5_common.o \ $(am__append_2) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/preprocessors/Stream5/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/preprocessors/Stream5/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libstream5.a: $(libstream5_a_OBJECTS) $(libstream5_a_DEPENDENCIES) $(EXTRA_libstream5_a_DEPENDENCIES) $(AM_V_at)-rm -f libstream5.a $(AM_V_AR)$(libstream5_a_AR) libstream5.a $(libstream5_a_OBJECTS) $(libstream5_a_LIBADD) $(AM_V_at)$(RANLIB) libstream5.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/preprocessors/HttpInspect/0000755000000000000000000000000012260606562015754 500000000000000snort-2.9.6.0/src/preprocessors/HttpInspect/normalization/0000755000000000000000000000000012260606562020642 500000000000000snort-2.9.6.0/src/preprocessors/HttpInspect/normalization/hi_norm.c0000644000000000000000000013610212260565733022370 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2003-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /** ** @file hi_norm.c ** ** @author Daniel Roelker #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_client_norm.h" #include "hi_server_norm.h" #include "hi_eo.h" #include "hi_eo_events.h" #include "hi_eo_log.h" #include "hi_ui_iis_unicode_map.h" #include "hi_return_codes.h" #include "hi_si.h" #include "hi_util.h" #include "hi_util_xmalloc.h" #include "sfPolicy.h" #include "detection_util.h" #define MAX_DIRS 2048 /** ** This define checks for negative return codes, since we have multiple ** reasons to error. This just cuts the return code checks, especially ** as we add more errors. */ #define GET_ERR 0x80000000 #define END_OF_BUFFER -1 #define DOUBLE_ENCODING -2 #define DIR_TRAV -2 #define NON_ASCII_CHAR 0xff typedef struct s_URI_NORM_STATE { u_char *abs_uri; u_char *param; /* ** Directory tracking */ u_int dir_count; u_char *dir_track[MAX_DIRS]; } URI_NORM_STATE; typedef int (*DECODE_FUNC)(HI_SESSION *, const u_char *, const u_char *, const u_char **, URI_NORM_STATE *, uint16_t *); bool byte_decoded=false; /* ** NAME ** GetPtr:: */ /** ** This routine is for getting bytes in the U decode. ** ** This checks the current bounds and checking for the double decoding. ** This routine differs from the other Get routines because it returns ** other values than just END_OF_BUFFER and the char. ** ** We also return DOUBLE_ENCODING if there is a % and double decoding ** is turned on. ** ** When using this function it is important to note that it increments ** the buffer before checking the bounds. So, if you call this function ** in a loop and don't check for END_OF_BUFFER being returned, then ** you are going to overwrite the buffer. If I put the check in, you ** would just be in an never-ending loop. So just use this correctly. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** ** @return integer ** ** @retval END_OF_BUFFER the end of the buffer has been reached. ** @retval DOUBLE_ENCODING a percent was found and double decoding is on ** @retval <= 0xff an ASCII char */ static int GetPtr(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; (*ptr)++; if(!hi_util_in_bounds(start, end, *ptr)) return END_OF_BUFFER; if(ServerConf->double_decoding.on && **ptr == '%') { *encodeType |= HTTP_ENCODE_TYPE__DOUBLE_ENCODE ; return DOUBLE_ENCODING; } return (int)**ptr; } /* ** NAME ** UDecode:: */ /** ** Handles the single decode for %U encoding. ** ** This routine receives the ptr pointing to the u. We check the bounds ** and continue with processing. %u encoding works by specifying the ** exact codepoint to be used. For example, %u002f would be /. So this ** all seems fine. BUT, the problem is that IIS maps multiple codepoints ** to ASCII characters. So, %u2044 also maps to /. So this is what we ** need to handle here. ** ** This routine only handles the single encoding. For double decoding, ** %u is handled in DoubleDecode(). It's the same routine, with just ** the GetByte function different. ** ** We use a get_byte function to get the bytes, so we can use this ** routine for PercentDecode and for DoubleDecode. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** @param get_byte the function pointer to get bytes. ** ** @return integer ** ** @retval END_OF_BUFFER we are at the end of the buffer ** @retval DOUBLE_ENCODING this U encoding is possible double encoded ** @retval NON_ASCII_CHAR return this char for non-ascii or bad decodes ** @retval iChar this is the char that we decoded. */ static int UDecode(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, DECODE_FUNC get_byte, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iByte; int iNorm; int iCtr; iNorm = 0; *encodeType |= HTTP_ENCODE_TYPE__UENCODE; hi_stats.unicode++; for(iCtr = 0; iCtr < 4; iCtr++) { iByte = get_byte(Session, start, end, ptr, norm_state, encodeType); if(iByte & GET_ERR) return iByte; if(valid_lookup[(u_char)iByte] < 0) { *encodeType |= HTTP_ENCODE_TYPE__NONASCII; hi_stats.non_ascii++; return NON_ASCII_CHAR; } iNorm <<= 4; iNorm = (iNorm | (hex_lookup[(u_char)iByte])); } /* ** If the decoded codepoint is greater than a single byte value, ** then we return a NON_ASCII_CHAR. */ if(iNorm > 0xff) { /* ** We check here for IIS codepoints that map to ASCII chars. */ if(ServerConf->iis_unicode.on && iNorm <= 0xffff) { iNorm = ServerConf->iis_unicode_map[iNorm]; if(iNorm == HI_UI_NON_ASCII_CODEPOINT) { *encodeType |= HTTP_ENCODE_TYPE__NONASCII; hi_stats.non_ascii++; iNorm = NON_ASCII_CHAR; } if(hi_eo_generate_event(Session, ServerConf->iis_unicode.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_UNICODE, NULL, NULL); } *encodeType |= HTTP_ENCODE_TYPE__IIS_UNICODE; } else { *encodeType |= HTTP_ENCODE_TYPE__NONASCII; hi_stats.non_ascii++; return NON_ASCII_CHAR; } } /* ** Check if we alert on this encoding */ if(hi_eo_generate_event(Session, ServerConf->u_encoding.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_U_ENCODE, NULL, NULL); } byte_decoded = true; return iNorm; } /* ** NAME ** PercentDecode:: */ /** ** This is the first level of decoding, and deals with ASCII, U, and ** double decoding. ** ** This function is the main decoding function. It handles all the ASCII ** encoding and the U encoding, and tells us when there is a double ** encoding. ** ** We use the GetPtr() routine to get the bytes for us. This routine ** checks for DOUBLE_ENCODING and tells us about it if it finds something, ** so we can reset the ptrs and run it through the double decoding ** routine. ** ** The philosophy behind this routine is that if we run out of buffer ** we return such, the only other thing we return besides the decodes ** char is a NON_ASCII_CHAR in the case that we try and decode something ** like %tt. This is no good, so we return a place holder. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** ** @return integer ** ** @retval END_OF_BUFFER We've hit the end of buffer while decoding. ** @retval NON_ASCII_CHAR Invalid hex encoding, so we return a placeholder. ** @retval char return the valid char ** ** @see GetPtr() */ static int PercentDecode(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iByte; const u_char *orig_ptr; int iNorm; orig_ptr = *ptr; iByte = GetPtr(Session, start, end, ptr, norm_state, encodeType); if(iByte & GET_ERR) { if(iByte == END_OF_BUFFER) return END_OF_BUFFER; if(iByte == DOUBLE_ENCODING) { *ptr = orig_ptr; return (int)**ptr; } } /* ** Initialize the normalization byte */ iNorm = 0; /* ** hex values */ if(valid_lookup[(u_char)iByte] < 0) { /* ** Check for %u encoding. ** ** The u-encoding loop always returns something. */ if(ServerConf->u_encoding.on && (toupper(iByte) == 'U')) { iNorm = UDecode(Session, start, end, ptr, GetPtr, norm_state, encodeType); /* ** We have to handle the double meaning of END_OF_BUFFER ** when using the GetPtr() function. */ if(iNorm & GET_ERR) { if(iNorm == END_OF_BUFFER) { /* ** We have reached the end of the buffer while ** processing a U encoding. */ return END_OF_BUFFER; } if(iNorm == DOUBLE_ENCODING) { *encodeType |= HTTP_ENCODE_TYPE__DOUBLE_ENCODE; *ptr = orig_ptr; return (int)**ptr; } } return iNorm; } else { *encodeType |= HTTP_ENCODE_TYPE__NONASCII; hi_stats.non_ascii++; return NON_ASCII_CHAR; } } iNorm = (hex_lookup[(u_char)iByte]<<4); iByte = GetPtr(Session, start, end, ptr, norm_state, encodeType); if(iByte & GET_ERR) { if(iByte == END_OF_BUFFER) return END_OF_BUFFER; if(iByte == DOUBLE_ENCODING) { *ptr = orig_ptr; return (int)**ptr; } } if(valid_lookup[(u_char)iByte] < 0) { *encodeType |= HTTP_ENCODE_TYPE__NONASCII; hi_stats.non_ascii++; return NON_ASCII_CHAR; } iNorm = (iNorm | (hex_lookup[(u_char)iByte])) & 0xff; *encodeType |= HTTP_ENCODE_TYPE__ASCII; byte_decoded = true; if(hi_eo_generate_event(Session,ServerConf->ascii.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_ASCII, NULL, NULL); } return iNorm; } /* ** NAME ** GetChar:: */ /** ** Wrapper for PercentDecode() and handles the return values from ** PercentDecode(). ** ** This really decodes the chars for UnicodeDecode(). If the char is ** a percent then we process stuff, otherwise we just increment the ** pointer and return. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** @param bare_byte value for a non-ASCII char or a decoded non-ASCII char ** ** @return integer ** ** @retval END_OF_BUFFER End of the buffer has been reached before decode. ** @retval NON_ASCII_CHAR End of buffer during decoding, return decoded char. ** @retval char return the valid decoded/undecoded char ** ** @see PercentDecode() ** @see GetByte() */ static int GetChar(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, int *bare_byte, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iNorm; if(!hi_util_in_bounds(start, end, *ptr)) return END_OF_BUFFER; iNorm = (int)(**ptr); if(**ptr == '%' && ServerConf->ascii.on) { /* ** We go into percent encoding. */ iNorm = PercentDecode(Session, start, end, ptr, norm_state, encodeType); /* ** If during the course of PercentDecode() we run into the end ** of the buffer, then we return early (WITHOUT INCREMENTING ptr) ** with a NON_ASCII_CHAR. */ if(iNorm == END_OF_BUFFER) return NON_ASCII_CHAR; *bare_byte = 0; } else { if(ServerConf->bare_byte.on && (u_char)iNorm > 0x7f) { *encodeType |= HTTP_ENCODE_TYPE__BARE_BYTE; if(hi_eo_generate_event(Session, ServerConf->bare_byte.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_BARE_BYTE, NULL, NULL); } /* ** Set the bare_byte flag */ *bare_byte = 0; } else { /* ** Set the bare_byte flag negative. */ *bare_byte = 1; } } /* ** Increment the buffer. */ (*ptr)++; return iNorm; } /* ** NAME ** UTF8Decode:: */ /* ** Decode the UTF-8 sequences and check for valid codepoints via the ** Unicode standard and the IIS standard. ** ** We decode up to 3 bytes of UTF-8 because that's all I've been able to ** get to work on various servers, so let's reduce some false positives. ** So we decode valid UTF-8 sequences and then check the value. If the ** value is ASCII, then it's decoded to that. Otherwise, if iis_unicode ** is turned on, we will check the unicode codemap for valid IIS mappings. ** If a mapping turns up, then we return the mapped ASCII. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** ** @return integer ** ** @retval NON_ASCII_CHAR Reached end of buffer while decoding ** @retval char return the decoded or badly decoded char ** ** @see GetByte() ** @see UnicodeDecode() */ static int UTF8Decode(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, int iFirst, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iBareByte; int iNorm; int iNumBytes; int iCtr; int iByte; /* ** Right now we support up to 3 byte unicode sequences. We can add ** more if any of the HTTP servers support more. */ if((iFirst & 0xe0) == 0xc0) { iNumBytes = 1; iNorm = iFirst & 0x1f; } else if((iFirst & 0xf0) == 0xe0) { iNumBytes = 2; iNorm = iFirst & 0x0f; } else { *encodeType |= HTTP_ENCODE_TYPE__NONASCII; hi_stats.non_ascii++; /* ** This means that we have an invalid first sequence byte for ** a unicode sequence. So we just return the byte and move on. */ return iFirst; } /* ** This is the main loop for UTF-8 decoding. We check for the only ** valid sequence after the first byte whish is 0x80. Otherwise, ** it was invalid and we setnd a NON_ASCII_CHAR and continue on ** with our processing. */ for(iCtr = 0; iCtr < iNumBytes; iCtr++) { iByte = GetChar(Session, start, end, ptr, &iBareByte, norm_state, encodeType); if(iByte == END_OF_BUFFER || iByte == NON_ASCII_CHAR || iBareByte) return NON_ASCII_CHAR; if((iByte & 0xc0) == 0x80) { iNorm <<= 6; iNorm |= (iByte & 0x3f); } else { *encodeType |= HTTP_ENCODE_TYPE__NONASCII; hi_stats.non_ascii++; /* ** This means that we don't have a valid unicode sequence, so ** we just bail. */ return NON_ASCII_CHAR; } } /* ** Check for unicode as ASCII and if there is not an ASCII char then ** we return the space holder char. */ if(iNorm > 0x7f) { if(ServerConf->iis_unicode.on) { iNorm = ServerConf->iis_unicode_map[iNorm]; if(iNorm == HI_UI_NON_ASCII_CODEPOINT) { iNorm = NON_ASCII_CHAR; } if(hi_eo_generate_event(Session, ServerConf->iis_unicode.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_UNICODE, NULL, NULL); } *encodeType |= HTTP_ENCODE_TYPE__IIS_UNICODE; hi_stats.unicode++; return iNorm; } else { *encodeType |= HTTP_ENCODE_TYPE__NONASCII; hi_stats.non_ascii++; iNorm = NON_ASCII_CHAR; } } *encodeType |= HTTP_ENCODE_TYPE__UTF8_UNICODE; if(hi_eo_generate_event(Session, ServerConf->utf_8.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_UTF_8, NULL, NULL); } return iNorm; } /* ** NAME ** UnicodeDecode:: */ /** ** Checks for the ServerConf values before we actually decode. ** ** This function is really a ServerConf wrapper for UTF8Decode. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** ** @return integer ** ** @retval char the decode/undecoded byte. ** ** @see GetByte() */ static int UnicodeDecode(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, int iFirst, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iNorm = iFirst; if(ServerConf->iis_unicode.on || ServerConf->utf_8.on) { iNorm = UTF8Decode(Session, start, end, ptr, iFirst, norm_state, encodeType); } return iNorm; } /* ** NAME ** GetByte:: */ /** ** Handles the first stage of URI decoding for the case of IIS double ** decoding. ** ** The first stage consists of ASCII decoding and unicode decoding. %U ** decoding is handled in the ASCII decoding. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** ** @return integer ** ** @retval END_OF_BUFFER means that we've reached the end of buffer in ** GetChar. ** @retval iChar this is the character that was decoded. */ static int GetByte(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state, uint16_t *encodeType) { int iChar; int iBareByte; iChar = GetChar(Session, start, end, ptr, &iBareByte, norm_state, encodeType); if(iChar == END_OF_BUFFER) return END_OF_BUFFER; if (iChar == NON_ASCII_CHAR) return NON_ASCII_CHAR; /* ** We now check for unicode bytes */ if((iChar & 0x80) && !iBareByte) { iChar = UnicodeDecode(Session, start, end, ptr, iChar, norm_state, encodeType); } return iChar; } /* ** NAME ** DoubleDecode:: */ /** ** The double decoding routine for IIS good times. ** ** Coming into this function means that we just decoded a % or that ** we just saw two percents in a row. We know which state we are ** in depending if the first char is a '%' or not. ** ** In the IIS world, there are two decodes, but only some of the decode ** options are valid. All options are valid in the first decode ** stage, but the second decode stage only supports: ** - %u encoding ** - ascii ** ** Knowing this, we can decode appropriately. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** @param norm_state the ptr to the URI norm state ** ** @return integer ** ** @retval NON_ASCII_CHAR End of buffer reached while decoding ** @retval char The decoded char */ static int DoubleDecode(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iByte; int iNorm; *encodeType |= HTTP_ENCODE_TYPE__DOUBLE_ENCODE; /* ** We now know that we have seen a previous % and that we need to ** decode the remaining bytes. We are in one of multiple cases: ** ** - %25xxxx ** - %%xx%xx ** - %u0025xxxx ** - etc. ** ** But, the one common factor is that they each started out with a ** % encoding of some type. ** ** So now we just get the remaining bytes and do the processing ** ourselves in this routine. */ iByte = GetByte(Session, start, end, ptr, norm_state, encodeType); if(iByte == END_OF_BUFFER) return NON_ASCII_CHAR; if(valid_lookup[(u_char)iByte] < 0) { if(ServerConf->u_encoding.on && (toupper(iByte) == 'U')) { iNorm = UDecode(Session, start, end, ptr, GetByte, norm_state, encodeType); if(iNorm == END_OF_BUFFER) { /* ** We have reached the end of the buffer while ** processing a U encoding. We keep the current ** pointer and return a NON_ASCII char for the ** bad encoding. */ return NON_ASCII_CHAR; } return iNorm; } return iByte; } iNorm = (hex_lookup[(u_char)iByte]<<4); iByte = GetByte(Session, start, end, ptr, norm_state, encodeType); if(iByte == END_OF_BUFFER) return NON_ASCII_CHAR; if(valid_lookup[(u_char)iByte] < 0) { return iByte; } iNorm = (iNorm | (hex_lookup[(u_char)iByte])) & 0xff; if(hi_eo_generate_event(Session, ServerConf->double_decoding.alert) && (norm_state->param == NULL)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_DOUBLE_DECODE, NULL, NULL); } byte_decoded = true; return iNorm; } /* ** NAME ** GetDecodedByte:: */ /** ** This is the final GetByte routine. The value that is returned from this ** routine is the final decoded byte, and normalization can begin. This ** routine handles the double phase of decoding that IIS is fond of. ** ** So to recap all the decoding up until this point. ** ** The first phase is to call GetByte(). GetByte() returns the first stage ** of decoding, which handles the UTF-8 decoding. If we have decoded a ** % of some type, then we head into DoubleDecode() if the ServerConf ** allows it. ** ** What returns from DoubleDecode is the final result. ** ** @param ServerConf the server configuration ** @param start the start of the URI ** @param end the end of the URI ** @param ptr the current pointer into the URI ** @param norm_state the pointer to the URI norm state ** ** @return integer ** ** @retval END_OF_BUFFER While decoding, the end of buffer was reached. ** @retval char The resultant decoded char. ** ** @see DoubleDecode(); ** @see GetByte(); */ static int GetDecodedByte(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iChar; iChar = GetByte(Session,start,end,ptr, norm_state,encodeType); if(iChar == END_OF_BUFFER) return END_OF_BUFFER; if(ServerConf->double_decoding.on && (u_char)iChar == '%') { iChar = DoubleDecode(Session,start,end,ptr,norm_state,encodeType); } /* ** Let's change '\' to '/' if possible */ if(ServerConf->iis_backslash.on && (u_char)iChar == 0x5c) { if(hi_eo_generate_event(Session, ServerConf->iis_backslash.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_BACKSLASH, NULL, NULL); } iChar = 0x2f; } if( (u_char)iChar == '+') { iChar = 0x20; } return iChar; } /* ** NAME ** DirTrav:: */ /** ** Set the ub_ptr and update the URI_NORM_STATE. ** ** The main point of this function is to take care of the details in ** updating the directory stack and setting the buffer pointer to the ** last directory. ** ** @param norm_state pointer to the normalization state struct ** @param ub_ptr double pointer to the normalized buffer ** ** @return integer ** ** @retval HI_SUCCESS function successful ** ** @see hi_norm_uri() */ static int DirTrav(HI_SESSION *Session, URI_NORM_STATE *norm_state, u_char *ub_start,u_char **ub_ptr) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; hi_stats.dir_trav++; if(norm_state->dir_count) { *ub_ptr = norm_state->dir_track[norm_state->dir_count - 1]; /* ** Check to make sure that we aren't at the beginning */ if(norm_state->dir_count >= 1) { norm_state->dir_count--; } } else { /* ** This is a special case where there was no / seen before ** we see a /../. When this happens, we just reset the ub_ptr ** back to the beginning of the norm buffer and let the slash ** get written on the next iteration of the loop. */ *ub_ptr = ub_start; /* ** Let's put the alert here for webroot dir traversal. */ if(hi_eo_generate_event(Session, ServerConf->webroot.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_WEBROOT_DIR, NULL, NULL); } } return HI_SUCCESS; } /* ** NAME ** DirSet:: */ /** ** Set the directory by writing a '/' to the normalization buffer and ** updating the directory stack. ** ** This gets called after every slash that isn't a directory traversal. We ** just write a '/' and then update the directory stack to point to the ** last directory, in the case of future directory traversals. ** ** @param norm_state pointer to the normalization state struct ** @param ub_ptr double pointer to the normalized buffer ** ** @return integer ** ** @retval HI_SUCCESS function successful ** ** @see hi_norm_uri() */ static int DirSet(URI_NORM_STATE *norm_state, u_char **ub_ptr) { /* ** Write the '/'. Even if iDir is the END_OF_BUFFER we still ** write it because the '/' came before the END_OF_BUFFER. */ **ub_ptr = '/'; if(!norm_state->param) { if(norm_state->dir_count < (MAX_DIRS - 1)) norm_state->dir_track[norm_state->dir_count++] = *ub_ptr; } (*ub_ptr)++; return HI_SUCCESS; } /* ** NAME ** DirNorm:: */ /** ** The main function for dealing with multiple slashes, self-referential ** directories, and directory traversals. ** ** This routine does GetDecodedByte() while looking for directory foo. It's ** called every time that we see a slash in the main hi_norm_uri. Most of ** the time we just enter this loop, find a non-directory-foo char and ** return that char. hi_norm_uri() takes care of the directory state ** updating and so forth. ** ** But when we run into trouble with directories, this function takes care ** of that. We loop through multiple slashes until we get to the next ** directory. We also loop through self-referential directories until we ** get to the next directory. Then finally we deal with directory ** traversals. ** ** With directory traversals we do a kind of "look ahead". We verify that ** there is indeed a directory traversal, and then set the ptr back to ** the beginning of the '/', so when we iterate through hi_norm_uri() we ** catch it. ** ** The return value for this function is usually the character after ** the directory. When there was a directory traversal, it returns the ** value DIR_TRAV. And when END_OF_BUFFER is returned, it means that we've ** really hit the end of the buffer, or we were looping through multiple ** slashes and self-referential directories until the end of the URI ** buffer. ** ** @param ServerConf pointer to the Server configuration ** @param start pointer to the start of the URI buffer ** @param end pointer to the end of the URI buffer ** @param ptr pointer to the index in the URI buffer ** ** @return integer ** ** @retval END_OF_BUFFER we've reached the end of buffer ** @retval DIR_TRAV we found a directory traversal ** @retval char return the next char after the directory ** ** @see hi_norm_uri() ** @see GetDecodedByte() */ static int DirNorm(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_NORM_STATE *norm_state, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iChar; int iDir; const u_char *orig_ptr; const u_char *dir_ptr; // save the directory path here to check for unicode attack while((iChar = GetDecodedByte(Session, start, end, ptr, norm_state, encodeType)) != END_OF_BUFFER) { orig_ptr = *ptr; /* ** This is kind of a short cut to get out of here as soon as we ** can. If the character is over 0x2f then we know that is can't ** be either the '.' or the '/', so we break and return the ** char. */ if((u_char)iChar < 0x30) { /* ** We check for multiple slashes. If we find multiple slashes ** then we just continue on until we find something interesting. */ if(ServerConf->multiple_slash.on && (u_char)iChar == '/') { hi_stats.slashes++; if(hi_eo_generate_event(Session, ServerConf->multiple_slash.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_MULTI_SLASH, NULL, NULL); } continue; } /* ** This is where we start looking for self-referential dirs ** and directory traversals. */ else if(ServerConf->directory.on && (u_char)iChar == '.' && !norm_state->param) { iDir = GetDecodedByte(Session,start,end,ptr,norm_state,encodeType); if(iDir != END_OF_BUFFER) { if((u_char)iDir == '.') { /* ** This sets the dir_ptr to the beginning of the ** byte that may be a dir. So if it is a slash, ** we can get back to that slash and continue ** processing. */ dir_ptr = *ptr; iDir = GetDecodedByte(Session,start,end,ptr,norm_state,encodeType); if(iDir != END_OF_BUFFER) { if((u_char)iDir == '/') { hi_stats.self_ref++; /* ** We found a real live directory traversal ** so we reset the pointer to before the ** '/' and finish up after the return. */ if(hi_eo_generate_event(Session, ServerConf->directory.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_DIR_TRAV, NULL, NULL); } *ptr = dir_ptr; return DIR_TRAV; } } *ptr = orig_ptr; return iChar; } else if((u_char)iDir == '/') { /* ** We got a self-referential directory traversal. ** ** Keep processing until we stop seeing self ** referential directories. */ if(hi_eo_generate_event(Session, ServerConf->directory.alert) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_SELF_DIR_TRAV, NULL, NULL); } continue; } } /* ** This means that we saw '.' and then another char, so ** it was just a file/dir that started with a '.'. */ *ptr = orig_ptr; return iChar; } } /* ** This is where we write the chars after the slash */ return iChar; } return END_OF_BUFFER; } /* ** NAME ** CheckLongDir:: */ /** ** This function checks for long directory names in the request URI. ** ** @param Session pointer to the session ** @param norm_state pointer to the directory stack ** @param ub_ptr current pointer in normalization buffer ** ** @return integer ** ** @retval HI_SUCCESS */ static int CheckLongDir(HI_SESSION *Session, URI_NORM_STATE *norm_state, u_char *ub_ptr) { int iDirLen; u_char *LastDir; /* ** First check that we are alerting on long directories and then ** check that we've seen a previous directory. */ if(Session->server_conf->long_dir && norm_state->dir_count && !norm_state->param) { LastDir = norm_state->dir_track[norm_state->dir_count - 1]; iDirLen = ub_ptr - LastDir; if(iDirLen > Session->server_conf->long_dir && hi_eo_generate_event(Session, HI_EO_CLIENT_OVERSIZE_DIR) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_OVERSIZE_DIR, NULL, NULL); } } return HI_SUCCESS; } /* ** NAME ** InspectUriChar:: */ /** ** This function inspects the normalized chars for any other processing ** that we need to do, such as directory traversals. ** ** The main things that we check for here are '/' and '?'. There reason ** for '/' is that we do directory traversals. If it's a slash, we call ** the routine that will normalize mutli-slashes, self-referential dirs, ** and dir traversals. We do all that processing here and call the ** appropriate functions. ** ** The '?' is so we can mark the parameter field, and check for oversize ** directories one last time. Once the parameter field is set, we don't ** do any more oversize directory checks since we aren't in the url ** any more. ** ** @param Session pointer to the current session ** @param iChar the char to inspect ** @param norm_state the normalization state ** @param start the start of the URI buffer ** @param end the end of the URI buffer ** @param ptr the address of the pointer index into the URI buffer ** @param ub_start the start of the norm buffer ** @param ub_end the end of the norm buffer ** @param ub_ptr the address of the pointer index into the norm buffer ** ** @return integer ** ** @retval END_OF_BUFFER we've reached the end of the URI or norm buffer ** @retval HI_NONFATAL_ERR no special char, so just write the char and ** increment the ub_ptr. ** @retval HI_SUCCESS normalized the special char and already ** incremented the buffers. */ static inline int InspectUriChar(HI_SESSION *Session, int iChar, URI_NORM_STATE *norm_state, const u_char *start, const u_char *end, const u_char **ptr, u_char *ub_start, u_char *ub_end, u_char **ub_ptr, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iDir; /* ** Let's add absolute URI/proxy support everyone. */ if(!norm_state->dir_count && (u_char)iChar == ':' && hi_util_in_bounds(start, end, ((*ptr)+2))) { if(**ptr == '/' && *((*ptr)+1) == '/') { /* ** We've found absolute vodka. */ if(!hi_util_in_bounds(ub_start, ub_end, ((*ub_ptr)+2))) return END_OF_BUFFER; /* ** Write the : */ **ub_ptr = (u_char)iChar; (*ub_ptr)++; /* ** This increments us past the first slash, so at the next ** slash we will track a directory. ** ** The reason we do this is so that an attacker can't trick ** us into normalizing a directory away that ended in a :. ** For instance, if we got a URL that was separated in by a ** packet boundary like this, and we were looking for the ** URL real_dir:/file.html: ** real_dir://obfuscate_dir/../file.html ** we would normalize it with proxy support to: ** /file.html ** because we never tracked the :// as a valid directory. So ** even though this isn't the best solution, it is the best ** we can do given that we are working with stateless ** inspection. */ (*ptr)++; return HI_SUCCESS; } } /* ** Now that we have the "true" byte, we check this byte for other ** types of normalization: ** - directory traversals ** - multiple slashes */ if((u_char)iChar == '/') { /* ** First thing we do is check for a long directory. */ CheckLongDir(Session, norm_state, *ub_ptr); iDir = DirNorm(Session, start, end, ptr, norm_state, encodeType); if(iDir == DIR_TRAV) { /* ** This is the case where we have a directory traversal. ** ** The DirTrav function will reset the ub_ptr to the previous ** slash. After that, we just continue through the loop because ** DirNorm has already set ptr to the slash, so we can just ** continue on. */ DirTrav(Session,norm_state, ub_start, ub_ptr); } else { /* ** This is the case where we didn't have a directory traversal, ** and we are now just writing the char after the '/'. ** ** We call DirSet, because all this function does is write a ** '/' into the buffer and increment the ub_ptr. We then ** check the return code and return END_OF_BUFFER if ** needed. */ DirSet(norm_state, ub_ptr); if(iDir == END_OF_BUFFER) return END_OF_BUFFER; /* ** We check the bounds before we write the next byte */ if(!hi_util_in_bounds(ub_start, ub_end, *ub_ptr)) return END_OF_BUFFER; /* ** Set the char to what we got in DirNorm() */ /* ** Look for user-defined Non-Rfc chars. If we find them ** then log an alert. */ if(ServerConf->non_rfc_chars[(u_char)iDir]) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_NON_RFC_CHAR) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_NON_RFC_CHAR, NULL, NULL); } } **ub_ptr = (u_char)iDir; (*ub_ptr)++; } return HI_SUCCESS; } if((!byte_decoded && (u_char)iChar == '?')) { /* ** We assume that this is the beginning of the parameter field, ** and check for a long directory following. Event though seeing ** a question mark does not guarantee the parameter field, thanks ** IIS. */ CheckLongDir(Session, norm_state, *ub_ptr); norm_state->param = *ub_ptr; } /* ** This is neither char, so we just bail and let the loop finish ** for us. */ return HI_NONFATAL_ERR; } /* ** NAME ** hi_norm_uri:: */ /** ** Normalize the URI into the URI normalize buffer. ** ** This is the routine that users call to normalize the URI. It iterates ** through the URI buffer decoding the next character and is then checked ** for any directory problems before writing the decoded character into the ** normalizing buffer. ** ** We return the length of the normalized URI buffer in the variable, ** uribuf_size. This value is passed in as the max size of the normalization ** buffer, which we then set in iMaxUriBufSize for later reference. ** ** If there was some sort of problem during normalizing we set the normalized ** URI buffer size to 0 and return HI_NONFATAL_ERR. ** ** @param ServerConf the pointer to the server configuration ** @param uribuf the pointer to the normalize uri buffer ** @param uribuf_size the size of the normalize buffer ** @param uri the pointer to the unnormalized uri buffer ** @param uri_size the size of the unnormalized uri buffer ** ** @return integer ** ** @retval HI_NONFATAL_ERR there was a problem during normalizing, the ** uribuf_size is also set to 0 ** @retval HI_SUCCESS Normalizing the URI was successful */ int hi_norm_uri(HI_SESSION *Session, u_char *uribuf, int *uribuf_size, const u_char *uri, int uri_size, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf; int iChar; int iRet; int iMaxUriBufSize; URI_NORM_STATE norm_state; u_char *ub_ptr; const u_char *ptr; const u_char *start; const u_char *end; u_char *ub_start; u_char *ub_end; ServerConf = Session->server_conf; iMaxUriBufSize = *uribuf_size; start = uri; end = uri + uri_size; ub_start = uribuf; ub_end = uribuf + iMaxUriBufSize; ub_ptr = uribuf; ptr = uri; /* ** Initialize the URI directory normalization state */ norm_state.dir_count = 0; norm_state.param = NULL; while(hi_util_in_bounds(ub_start, ub_end, ub_ptr)) { byte_decoded = false; iChar = GetDecodedByte(Session, start, end, &ptr, &norm_state, encodeType); if(iChar == END_OF_BUFFER) break; /* ** Look for user-defined Non-Rfc chars. If we find them ** then log an alert. */ if(ServerConf->non_rfc_chars[(u_char)iChar]) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_NON_RFC_CHAR) && !norm_state.param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_NON_RFC_CHAR, NULL, NULL); } } iRet = InspectUriChar(Session, iChar, &norm_state, start, end, &ptr, ub_start, ub_end, &ub_ptr, encodeType); if (iRet) { if(iRet == END_OF_BUFFER) break; /* ** This is the default case when we don't want anything to do with ** the char besides writing the value into the buffer. */ *ub_ptr = (u_char)iChar; ub_ptr++; } } /* ** Now that we are done, let's make sure that we didn't just have a ** single large directory, with the rest in the next packet. */ CheckLongDir(Session, &norm_state, ub_ptr); /* ** This means that we got to the end of the URI, so we set the length, ** check it, and move on. */ *uribuf_size = ub_ptr - ub_start; if(*uribuf_size > uri_size || *uribuf_size < 1) return HI_NONFATAL_ERR; return HI_SUCCESS; } /* ** NAME ** hi_normalization:: */ /** ** Wrap the logic for normalizing different inspection modes. ** ** We call the various normalization modes here, and adjust the appropriate ** Session constructs. ** ** @param Session pointer to the session structure. ** @param iInspectMode the type of inspection/normalization to do ** ** @return integer ** ** @retval HI_SUCCESS function successful ** @retval HI_INVALID_ARG invalid argument */ int hi_normalization(HI_SESSION *Session, int iInspectMode, HttpSessionData *hsd) { int iRet; if(!Session) { return HI_INVALID_ARG; } /* ** Depending on the mode, we normalize the packet differently. ** Currently, we only have normalization routines for the client ** URI, so that's all we are interested in. ** ** HI_SI_CLIENT_MODE: ** Inspect for HTTP client communication. */ if(iInspectMode == HI_SI_CLIENT_MODE) { iRet = hi_client_norm((void *)Session); if (iRet) { return iRet; } } else if(iInspectMode == HI_SI_SERVER_MODE) { iRet = hi_server_norm((void *)Session, hsd); if (iRet) { return iRet; } } return HI_SUCCESS; } snort-2.9.6.0/src/preprocessors/HttpInspect/normalization/Makefile.am0000644000000000000000000000020610277202367022615 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libhi_norm.a libhi_norm_a_SOURCES = \ hi_norm.c INCLUDES = @INCLUDES@ snort-2.9.6.0/src/preprocessors/HttpInspect/normalization/Makefile.in0000644000000000000000000004004312260606525022627 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/preprocessors/HttpInspect/normalization DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libhi_norm_a_AR = $(AR) $(ARFLAGS) libhi_norm_a_LIBADD = am_libhi_norm_a_OBJECTS = hi_norm.$(OBJEXT) libhi_norm_a_OBJECTS = $(am_libhi_norm_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libhi_norm_a_SOURCES) DIST_SOURCES = $(libhi_norm_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libhi_norm.a libhi_norm_a_SOURCES = \ hi_norm.c all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/preprocessors/HttpInspect/normalization/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/preprocessors/HttpInspect/normalization/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libhi_norm.a: $(libhi_norm_a_OBJECTS) $(libhi_norm_a_DEPENDENCIES) $(EXTRA_libhi_norm_a_DEPENDENCIES) $(AM_V_at)-rm -f libhi_norm.a $(AM_V_AR)$(libhi_norm_a_AR) libhi_norm.a $(libhi_norm_a_OBJECTS) $(libhi_norm_a_LIBADD) $(AM_V_at)$(RANLIB) libhi_norm.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/preprocessors/HttpInspect/client/0000755000000000000000000000000012260606562017232 500000000000000snort-2.9.6.0/src/preprocessors/HttpInspect/client/hi_client_norm.c0000644000000000000000000003272212260565733022321 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2003-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /** ** @file hi_client_norm.c ** ** @author Daniel Roelker ** ** @brief HTTP client normalization routines ** ** We deal with the normalization of HTTP client requests headers and ** URI. ** ** In this file, we handle all the different HTTP request URI evasions. The ** list is: ** - ASCII decoding ** - UTF-8 decoding ** - IIS Unicode decoding ** - Directory traversals (self-referential and traversal) ** - Multiple Slashes ** - Double decoding ** - %U decoding ** - Bare Byte Unicode decoding ** ** Base 36 is deprecated and essentially a noop ** - Base36 decoding ** ** NOTES: ** - Initial development. DJR */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_norm.h" #include "hi_util.h" #include "hi_return_codes.h" #include "snort_bounds.h" int hi_split_header_cookie(HI_SESSION *Session, u_char *header, int *i_header_len, u_char *cookie_header, int *i_cookie_len, const u_char *raw_header, int i_raw_header_len, COOKIE_PTR *cookie) { int iRet = HI_SUCCESS; COOKIE_PTR *last_cookie = NULL; COOKIE_PTR *first_cookie = cookie; const u_char *raw_header_end = raw_header + i_raw_header_len; int this_cookie_len = 0; const u_char *this_header_start = raw_header; const u_char *this_header_end; int this_header_len = 0; const u_char *header_end; const u_char *cookie_end; if (!cookie || !i_header_len || !i_cookie_len) return HI_INVALID_ARG; /* Can't use hi_util_in_bounds header because == is okay */ if (cookie->cookie_end > raw_header + i_raw_header_len) return HI_OUT_OF_BOUNDS; header_end = (const u_char *)(header + *i_header_len); *i_header_len = 0; cookie_end = (const u_char *)(cookie_header + *i_cookie_len); *i_cookie_len = 0; do { this_cookie_len = cookie->cookie_end - cookie->cookie; this_header_end = cookie->cookie; this_header_len = this_header_end - this_header_start; /* Trim the header and only copy what we can store in the buf */ if (*i_header_len + this_header_len > MAX_URI) { this_header_len = MAX_URI - *i_header_len; } /* Copy out the headers from start to beginning of the cookie */ if (this_header_len > 0) { if (SafeMemcpy(header + *i_header_len, this_header_start, this_header_len, header, header_end) == SAFEMEM_SUCCESS) { *i_header_len += this_header_len; } } else { DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "HttpInspect: no leading header: %d to %d\n", this_header_end - this_header_start, this_header_len);); } /* Trim the cookie and only copy what we can store in the buf */ if (*i_cookie_len + this_cookie_len > MAX_URI) { this_cookie_len = MAX_URI - *i_cookie_len; } /* And copy the cookie */ if (this_cookie_len > 0) { if (SafeMemcpy(cookie_header + *i_cookie_len, cookie->cookie, this_cookie_len, cookie_header, cookie_end) == SAFEMEM_SUCCESS) { *i_cookie_len += this_cookie_len; } } else { DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "HttpInspect: trimming cookie: %d to %d\n", cookie->cookie_end - cookie->cookie, this_cookie_len);); } /* update for the next one */ this_header_start = cookie->cookie_end; cookie = cookie->next; if (last_cookie && (last_cookie != first_cookie)) { free(last_cookie); } last_cookie = cookie; if (!cookie) { this_header_len = raw_header + i_raw_header_len - this_header_start; } else { this_header_len = cookie->cookie - this_header_start; } this_header_end = this_header_start + this_header_len; if ((*i_header_len == MAX_URI) || (*i_cookie_len == MAX_URI)) { last_cookie = NULL; } } while (last_cookie); /* Clear out the 'first' cookie since we're done with it */ /* Eliminates unexptected 'reuse' in the case of pipeline'd requests. */ memset(first_cookie, 0, sizeof(COOKIE_PTR)); if (this_header_len && hi_util_in_bounds(raw_header, raw_header_end, this_header_start)) { /* Trim the header and only copy what we can store in the buf */ if (*i_header_len + this_header_len > MAX_URI) { this_header_len = MAX_URI - *i_header_len; } /* Copy the remaining headers after the last cookie */ if (this_header_len > 0) { if (SafeMemcpy(header + *i_header_len, this_header_start, this_header_len, header, header_end) == SAFEMEM_SUCCESS) { *i_header_len += this_header_len; } } else { DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "HttpInspect: no leading header: %d to %d\n", this_header_end - this_header_start, this_header_len);); } } return iRet; } int hi_client_norm(HI_SESSION *Session) { static u_char UriBuf[MAX_URI]; static u_char HeaderBuf[MAX_URI]; static u_char CookieBuf[MAX_URI]; static u_char RawHeaderBuf[MAX_URI]; static u_char RawCookieBuf[MAX_URI]; static u_char PostBuf[MAX_URI]; HI_CLIENT_REQ *ClientReq; int iRet; int iUriBufSize = MAX_URI; int iRawHeaderBufSize = MAX_URI; int iRawCookieBufSize = MAX_URI; int iHeaderBufSize = MAX_URI; int iCookieBufSize = MAX_URI; int iPostBufSize = MAX_URI; uint16_t encodeType = 0; u_int updated_uri_size = 0; const u_char *updated_uri_start = NULL; if(!Session || !Session->server_conf) { return HI_INVALID_ARG; } ClientReq = &Session->client.request; ClientReq->uri_encode_type = 0; ClientReq->header_encode_type = 0; ClientReq->cookie_encode_type = 0; ClientReq->post_encode_type = 0; /* Handle URI normalization */ if(ClientReq->uri_norm) { updated_uri_start = ClientReq->uri; updated_uri_size = ClientReq->uri_size; Session->norm_flags &= ~HI_BODY; if(proxy_start && (ClientReq->uri == proxy_start)) { if(hi_util_in_bounds(ClientReq->uri, (ClientReq->uri + ClientReq->uri_size), proxy_end)) { updated_uri_start = proxy_end; updated_uri_size = (ClientReq->uri_size) - (proxy_end - proxy_start); } } proxy_start = proxy_end = NULL; iRet = hi_norm_uri(Session, UriBuf, &iUriBufSize, updated_uri_start, updated_uri_size, &encodeType); if (iRet == HI_NONFATAL_ERR) { /* There was a non-fatal problem normalizing */ ClientReq->uri_norm = NULL; ClientReq->uri_norm_size = 0; ClientReq->uri_encode_type = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ ClientReq->uri_norm = UriBuf; ClientReq->uri_norm_size = iUriBufSize; ClientReq->uri_encode_type = encodeType; } encodeType = 0; } else { if(proxy_start && (ClientReq->uri == proxy_start)) { if(hi_util_in_bounds(ClientReq->uri, (ClientReq->uri + ClientReq->uri_size), proxy_end)) { ClientReq->uri_norm = proxy_end; ClientReq->uri_norm_size = (ClientReq->uri_size) - (proxy_end - proxy_start); } } proxy_start = proxy_end = NULL; } if (ClientReq->cookie.cookie) { /* There is an HTTP header with a cookie, look for the cookie & * separate the two buffers */ iRet = hi_split_header_cookie(Session, RawHeaderBuf, &iRawHeaderBufSize, RawCookieBuf, &iRawCookieBufSize, ClientReq->header_raw, ClientReq->header_raw_size, &ClientReq->cookie); if( iRet == HI_SUCCESS ) { ClientReq->cookie.cookie = RawCookieBuf; ClientReq->cookie.cookie_end = RawCookieBuf + iRawCookieBufSize; } } else { if (ClientReq->header_raw_size) { if (ClientReq->header_raw_size > MAX_URI) { ClientReq->header_raw_size = MAX_URI; } /* Limiting to MAX_URI above should cause this to always return SAFEMEM_SUCCESS */ SafeMemcpy(RawHeaderBuf, ClientReq->header_raw, ClientReq->header_raw_size, &RawHeaderBuf[0], &RawHeaderBuf[0] + iRawHeaderBufSize); } iRawHeaderBufSize = ClientReq->header_raw_size; iRawCookieBufSize = 0; } if(ClientReq->header_norm && Session->server_conf->normalize_headers) { Session->norm_flags &= ~HI_BODY; iRet = hi_norm_uri(Session, HeaderBuf, &iHeaderBufSize, RawHeaderBuf, iRawHeaderBufSize, &encodeType); if (iRet == HI_NONFATAL_ERR) { /* There was a non-fatal problem normalizing */ ClientReq->header_norm = NULL; ClientReq->header_norm_size = 0; ClientReq->header_encode_type = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ ClientReq->header_norm = HeaderBuf; ClientReq->header_norm_size = iHeaderBufSize; ClientReq->header_encode_type = encodeType; } encodeType = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ if (iRawHeaderBufSize) { ClientReq->header_norm = RawHeaderBuf; ClientReq->header_norm_size = iRawHeaderBufSize; ClientReq->header_encode_type = 0; } } if(ClientReq->cookie.cookie && Session->server_conf->normalize_cookies) { Session->norm_flags &= ~HI_BODY; iRet = hi_norm_uri(Session, CookieBuf, &iCookieBufSize, RawCookieBuf, iRawCookieBufSize, &encodeType); if (iRet == HI_NONFATAL_ERR) { /* There was a non-fatal problem normalizing */ ClientReq->cookie_norm = NULL; ClientReq->cookie_norm_size = 0; ClientReq->cookie_encode_type = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ ClientReq->cookie_norm = CookieBuf; ClientReq->cookie_norm_size = iCookieBufSize; ClientReq->cookie_encode_type = encodeType; } encodeType = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ if (iRawCookieBufSize) { ClientReq->cookie_norm = RawCookieBuf; ClientReq->cookie_norm_size = iRawCookieBufSize; ClientReq->cookie_encode_type = 0; } } /* Handle normalization of post methods. * Note: posts go into a different buffer. */ if(ClientReq->post_norm) { Session->norm_flags |= HI_BODY; iRet = hi_norm_uri(Session, PostBuf, &iPostBufSize, ClientReq->post_raw, ClientReq->post_raw_size, &encodeType); if (iRet == HI_NONFATAL_ERR) { ClientReq->post_norm = NULL; ClientReq->post_norm_size = 0; ClientReq->post_encode_type = 0; } else { ClientReq->post_norm = PostBuf; ClientReq->post_norm_size = iPostBufSize; ClientReq->post_encode_type = encodeType; } encodeType = 0; } /* printf("** uri_norm = |"); for(iCtr = 0; iCtr < ClientReq->uri_norm_size; iCtr++) { if(!isascii((int)ClientReq->uri_norm[iCtr]) || !isprint((int)ClientReq->uri_norm[iCtr])) { printf(".[%.2x]", ClientReq->uri_norm[iCtr]); continue; } printf("%c", ClientReq->uri_norm[iCtr]); } printf("| size = %u\n", ClientReq->uri_norm_size); */ return HI_SUCCESS; } snort-2.9.6.0/src/preprocessors/HttpInspect/client/hi_client.c0000644000000000000000000030162412260565733021266 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2003-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /** ** @file hi_client.c ** ** @author Daniel Roelker ** ** @brief Main file for all the client functions and inspection ** flow. ** ** ** The job of the client module is to analyze and inspect the HTTP ** protocol, finding where the various fields begin and end. This must ** be accomplished in a stateful and stateless manner. ** ** While the fields are being determined, we also do checks for ** normalization, so we don't normalize fields that don't need it. ** ** Currently, the only fields we check for this is the URI and the ** parameter fields. ** ** NOTES: ** - 3.8.03: Initial development. DJR ** - 2.4.05: Added tab_uri_delimiter config option. AJM. */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_ui_config.h" #include "hi_si.h" #include "hi_mi.h" #include "hi_client.h" #include "hi_eo_log.h" #include "hi_util.h" #include "hi_util_hbm.h" #include "hi_return_codes.h" #include "util.h" #include "mstring.h" #include "sfutil/util_unfold.h" #include "hi_cmd_lookup.h" #include "detection_util.h" #define HEADER_NAME__COOKIE "Cookie" #define HEADER_LENGTH__COOKIE 6 #define HEADER_NAME__CONTENT_LENGTH "Content-length" #define HEADER_LENGTH__CONTENT_LENGTH 14 #define HEADER_NAME__XFF "X-Forwarded-For" #define HEADER_LENGTH__XFF 15 #define HEADER_NAME__TRUE_IP "True-Client-IP" #define HEADER_LENGTH__TRUE_IP 14 #define HEADER_NAME__HOSTNAME "Host" #define HEADER_LENGTH__HOSTNAME 4 #define HEADER_NAME__TRANSFER_ENCODING "Transfer-encoding" #define HEADER_LENGTH__TRANSFER_ENCODING 17 #define HEADER_NAME__CONTENT_TYPE "Content-Type" #define HEADER_LENGTH__CONTENT_TYPE 12 const u_char *proxy_start = NULL; const u_char *proxy_end = NULL; /** This makes passing function arguments much more readable and easier ** to follow. */ typedef int (*LOOKUP_FCN)(HI_SESSION *, const u_char *, const u_char *, const u_char **, URI_PTR *); /* ** The lookup table contains functions for different HTTP delimiters ** (like whitespace and the HTTP delimiter \r and \n). */ LOOKUP_FCN lookup_table[256]; int NextNonWhiteSpace(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr); extern const u_char *extract_http_transfer_encoding(HI_SESSION *, HttpSessionData *, const u_char *, const u_char *, const u_char *, HEADER_PTR *, int); /* ** NAME ** CheckChunkEncoding:: */ /** ** This routine checks for chunk encoding anomalies in an HTTP client request ** packet. ** ** We convert potential chunk lengths and test them against the user-defined ** max chunk length. We log events on any chunk lengths that are over this ** defined chunk lengths. ** ** Chunks are skipped to save time when the chunk is contained in the packet. ** ** We assume coming into this function that we are pointed at the beginning ** of what may be a chunk length. That's why the iCheckChunk var is set ** to 1. ** ** @param Session pointer to the Session construct ** @param start pointer to where to beginning of buffer ** @param end pointer to the end of buffer ** ** @return integer ** ** @retval HI_SUCCESS function successful ** @retval HI_INVALID_ARG invalid argument */ int CheckChunkEncoding(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **post_end, u_char *iChunkBuf, uint32_t max_size, uint32_t chunk_remainder, uint32_t *updated_chunk_remainder, uint32_t *chunkRead, HttpSessionData *hsd, int iInspectMode) { uint32_t iChunkLen = 0; uint32_t iChunkChars = 0; int chunkPresent = 0; uint32_t iCheckChunk = 1; const u_char *ptr; const u_char *jump_ptr; uint32_t iDataLen = 0; uint32_t chunkBytesCopied = 0; uint8_t stateless_chunk_count = 0; if(!start || !end) return HI_INVALID_ARG; ptr = start; if(chunk_remainder) { iDataLen = end - ptr; if( iDataLen < max_size) { if( chunk_remainder > iDataLen ) { if(updated_chunk_remainder) *updated_chunk_remainder = chunk_remainder - iDataLen ; chunk_remainder = iDataLen; } } else { if( chunk_remainder > max_size ) { if(updated_chunk_remainder) *updated_chunk_remainder = chunk_remainder - max_size ; chunk_remainder = max_size; } } jump_ptr = ptr + chunk_remainder - 1; if(hi_util_in_bounds(start, end, jump_ptr)) { chunkPresent = 1; if(iChunkBuf) { memcpy(iChunkBuf, ptr, chunk_remainder); chunkBytesCopied = chunk_remainder; } ptr = jump_ptr + 1; } } while(hi_util_in_bounds(start, end, ptr)) { if(*ptr == '\n') { if(iCheckChunk && iChunkLen != 0) { if (((Session->server_conf->chunk_length != 0) && (iInspectMode == HI_SI_CLIENT_MODE) && (Session->server_conf->chunk_length < iChunkLen) && hi_eo_generate_event(Session, HI_EO_CLIENT_LARGE_CHUNK))) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LARGE_CHUNK, NULL, NULL); } if (Session->server_conf->small_chunk_length.size != 0) { if (iChunkLen <= Session->server_conf->small_chunk_length.size) { uint8_t* chunk_count; int (*log_func)(HI_SESSION *, int, void *, void (*)(void *)); int event; if (iInspectMode == HI_SI_CLIENT_MODE) { if (hsd) chunk_count = &hsd->cli_small_chunk_count; else chunk_count = &stateless_chunk_count; log_func = hi_eo_client_event_log; event = HI_EO_CLIENT_CONSECUTIVE_SMALL_CHUNKS; } else { if (hsd) chunk_count = &hsd->srv_small_chunk_count; else chunk_count = &stateless_chunk_count; log_func = hi_eo_server_event_log; event = HI_EO_SERVER_CONSECUTIVE_SMALL_CHUNKS; } (*chunk_count)++; if (hi_eo_generate_event(Session, event) && (*chunk_count >= Session->server_conf->small_chunk_length.num)) { log_func(Session, event, NULL, NULL); *chunk_count = 0; } } else { // Reset for non-consecutive small chunks if (iInspectMode == HI_SI_CLIENT_MODE) { if (hsd) hsd->cli_small_chunk_count = 0; else stateless_chunk_count = 0; } else { if (hsd) hsd->srv_small_chunk_count = 0; else stateless_chunk_count = 0; } } } SkipBlankAndNewLine(start,end, &ptr); if(*ptr == '\n') ptr++; if(!hi_util_in_bounds(start, end, ptr)) { if(updated_chunk_remainder) *updated_chunk_remainder = iChunkLen; break; } iDataLen = end - ptr ; if( iChunkLen > iDataLen) { if(updated_chunk_remainder) *updated_chunk_remainder = iChunkLen - iDataLen; iChunkLen = iDataLen; } jump_ptr = ptr + iChunkLen; if(jump_ptr <= ptr) { break; } /* Since we're doing a memcpy end and jump_ptr can be the same * but hi_util_in_bounds ensures last arg is less than so * subtract 1 from jump_ptr */ if(hi_util_in_bounds(start, end, jump_ptr - 1)) { chunkPresent = 1; if(iChunkBuf && ((chunkBytesCopied + iChunkLen) <= max_size)) { memcpy(iChunkBuf+chunkBytesCopied, ptr, iChunkLen); chunkBytesCopied += iChunkLen; } ptr = jump_ptr; if (!hi_util_in_bounds(start, end, ptr)) break; /* Check to see if the chunks ends - LF or CRLF are valid */ if (hi_eo_generate_event(Session, HI_EO_CLIENT_CHUNK_SIZE_MISMATCH) && (*ptr != '\n') && (*ptr != '\r') && ((ptr + 1) < end) && (*(ptr + 1) != '\n')) { hi_eo_client_event_log(Session, HI_EO_CLIENT_CHUNK_SIZE_MISMATCH, NULL, NULL); } } else { /* ** Chunk too large for packet, so we bail */ break; } } /* ** If we've already evaluated the chunk, or we have a valid delimiter ** for handling new chunks, we reset and starting evaluating possible ** chunk lengths. */ if(iCheckChunk || (hi_util_in_bounds(start, end, ptr) && *ptr == '\n')) { iCheckChunk = 1; iChunkLen = 0; iChunkChars = 0; } ptr++; continue; } if(iCheckChunk) { if(valid_lookup[*ptr] != HEX_VAL) { if(*ptr == '\r') { ptr++; if(!hi_util_in_bounds(start, end, ptr)) break; if(*ptr == '\n') continue; } else if(*ptr != '\n') { /* ** This is where we skip through the chunk name=value ** field. */ ptr = memchr(ptr, '\n', (end-ptr)); if(ptr == NULL) { ptr = end; break; } else continue; } iCheckChunk = 0; iChunkLen = 0; iChunkChars = 0; } else { if(iChunkChars >= 8) { if (((Session->server_conf->chunk_length != 0) && (iInspectMode == HI_SI_CLIENT_MODE) && (Session->server_conf->chunk_length < iChunkLen) && hi_eo_generate_event(Session, HI_EO_CLIENT_LARGE_CHUNK))) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LARGE_CHUNK, NULL, NULL); } iCheckChunk = 0; iChunkLen = 0; iChunkChars = 0; } else { iChunkLen <<= 4; iChunkLen |= (unsigned int)(hex_lookup[*ptr]); iChunkChars++; } } } ptr++; } if (chunkPresent ) { if(post_end) { *(post_end) = ptr; } if(chunkRead) { *chunkRead = chunkBytesCopied; } return 1; } return HI_SUCCESS; } /* ** NAME ** FindPipelineReq:: */ /** ** Catch multiple requests per packet, by returning pointer to after the ** end of the request header if there is another request. ** ** There are 4 types of "valid" delimiters that we look for. They are: ** "\r\n\r\n" ** "\r\n\n" ** "\n\r\n" ** "\n\n" ** The only patterns that we really only need to look for are: ** "\n\r\n" ** "\n\n" ** The reason being that these two patterns are suffixes of the other ** patterns. So once we find those, we are all good. ** ** @param Session pointer to the session ** @param start pointer to the start of text ** @param end pointer to the end of text ** ** @return pointer ** ** @retval NULL Did not find pipeline request ** @retval !NULL Found another possible request. */ static inline const u_char *FindPipelineReq(HI_SESSION *Session, const u_char *start, const u_char *end) { const u_char *p; u_char *offset; if(!start || !end) return NULL; p = start; offset = (u_char*)p; /* ** We say end - 6 because we need at least six bytes to verify that ** there is an end to the URI and still a request afterwards. To be ** exact, we should only subtract 1, but we are not interested in a ** 1 byte method, uri, etc. ** ** a.k.a there needs to be data after the initial request to inspect ** to make it worth our while. */ while(p < (end - 6)) { if(*p == '\n') { if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len) && ((p - offset) >= Session->server_conf->max_hdr_len)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL); } p++; offset = (u_char*)p; if(*p < 0x0E) { if(*p == '\r') { p++; if(*p == '\n') { return ++p; } } else if(*p == '\n') { return ++p; } } } p++; } /* Never observed an end-of-field. Maybe it's not there, but the header is long anyway: */ if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len) && ((p - start) >= Session->server_conf->max_hdr_len)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL); } return NULL; } /* ** NAME ** IsHttpVersion:: */ /** ** This checks that there is a version following a space with in an HTTP ** packet. ** ** This function gets called when a whitespace area has ended, and we want ** to know if a version identifier is followed directly after. So we look ** for the rfc standard "HTTP/" and report appropriately. We also need ** to make sure that the function succeeds given an end of buffer, so for ** instance if the buffer ends like " HTT", we still assume that this is ** a valid version identifier because of TCP segmentation. ** ** We also check for the 0.9 standard of GET URI\r\n. When we see a \r or ** a \n, then we just return with the pointer still pointing to that char. ** The reason is because on the next loop, we'll do the evaluation that ** we normally do and finish up processing there. ** ** @param start pointer to the start of the version identifier ** @param end pointer to the end of the buffer (could be the end of the ** data section, or just to the beginning of the delimiter. ** ** @return integer ** ** @retval 1 this is an HTTP version identifier ** @retval 0 this is not an HTTP identifier, or bad parameters */ int IsHttpVersion(const u_char **ptr, const u_char *end) { static u_char s_acHttpDelimiter[] = "HTTP/"; static int s_iHttpDelimiterLen = 5; int len; int iCtr; if(*ptr >= end) { return 0; } len = end - *ptr; if(len > s_iHttpDelimiterLen) { len = s_iHttpDelimiterLen; } /* ** This is where we check for the defunct method again. This method ** allows a request of "GET /index.html \r[\n]". So we need to ** check validate this as a legal identifier. */ if(**ptr == '\n' || **ptr == '\r') { /* ** We don't increment the pointer because we check for a legal ** identifier in the delimiter checking. Read the comments for ** setting the defunct variable in these functions. */ return 1; } for(iCtr = 0; iCtr < len; iCtr++) { if(s_acHttpDelimiter[iCtr] != (u_char)toupper((int)**ptr)) { return 0; } (*ptr)++; } /* ** This means that we match all the chars that we could given the ** remaining length so we should increment the pointer by that much ** since we don't need to inspect this again. */ /* This pointer is not used again. When 1 is returned it causes * NextNonWhiteSpace to return also. */ #if 0 (*ptr)++; #endif return 1; } /* ** NAME ** find_rfc_delimiter:: */ /** ** Check for standard RFC HTTP delimiter. ** ** If we find the delimiter, we return that URI_PTR structures should ** be checked, which bails us out of the loop. If there isn't a RFC ** delimiter, then we bail with a no URI. Otherwise, we check for out ** of bounds. ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval HI_OUT_OF_BOUNDS ** @retval URI_END end of the URI is found, check URI_PTR. ** @retval NO_URI malformed delimiter, no URI. */ int find_rfc_delimiter(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { if(*ptr == start || !uri_ptr->uri) return NO_URI; /* ** This is important to catch the defunct way of getting URIs without ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for ** us to tell if we are in that state. ** ** We check for a legal identifier to deal with the case of ** "some_of_the_uri_in segmented packet \r\n" in the defunct case. ** Since we find a "valid" (still defunct) delimiter, we account for ** it here, so that we don't set the uri_end to the delimiter. ** ** NOTE: ** We now assume that the defunct method is in effect and if there is ** a valid identifier, then we don't update the uri_end because it's ** already been set when the identifier was validated. */ (*ptr)++; if(!hi_util_in_bounds(start, end, *ptr)) { return HI_OUT_OF_BOUNDS; } if(**ptr == '\n') { uri_ptr->delimiter = (*ptr)-1; if(!uri_ptr->ident) uri_ptr->uri_end = uri_ptr->delimiter; return URI_END; } return NextNonWhiteSpace(Session, start, end, ptr, uri_ptr); } /* ** NAME ** find_non_rfc_delimiter:: */ /** ** Check for non standard delimiter '\n'. ** ** It now appears that apache and iis both take this non-standard ** delimiter. So, we most likely will always look for it, but maybe ** give off a special alert or something. ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval URI_END delimiter found, end of URI ** @retval NO_URI */ int find_non_rfc_delimiter(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; if(*ptr == start || !uri_ptr->uri) return NO_URI; /* ** This is important to catch the defunct way of getting URIs without ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for ** us to tell if we are in that state. ** ** We check for a legal identifier to deal with the case of ** "some_of_the_uri_in segmented packet \r\n" in the defunct case. ** Since we find a "valid" (still defunct) delimiter, we account for ** it here, so that we don't set the uri_end to the delimiter. ** ** NOTE: ** We now assume that the defunct method is in effect and if there is ** a valid identifier, then we don't update the uri_end because it's ** already been set when the identifier was validated. */ if(ServerConf->iis_delimiter.on) { if(hi_eo_generate_event(Session, ServerConf->iis_delimiter.alert)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_DELIMITER, NULL, NULL); } uri_ptr->delimiter = *ptr; if(!uri_ptr->ident) uri_ptr->uri_end = uri_ptr->delimiter; return URI_END; } /* ** This allows us to do something if the delimiter check is not turned ** on. Most likely this is worthy of an alert, IF it's not normal to ** see these requests. ** ** But for now, we always return true. */ uri_ptr->delimiter = *ptr; if(!uri_ptr->ident) uri_ptr->uri_end = uri_ptr->delimiter; return URI_END; } /* ** NAME ** NextNonWhiteSpace:: */ /** ** Update the URI_PTR fields spaces, find the next non-white space char, ** and validate the HTTP version identifier after the spaces. ** ** This is the main part of the URI algorithm. This verifies that there ** isn't too many spaces in the data to be a URI, it checks that after the ** second space that there is an HTTP identifier or otherwise it's no good. ** Also, if we've found an identifier after the first whitespace, and ** find another whitespace, there is no URI. ** ** The uri and uri_end pointers are updated in this function depending ** on what space we are at, and if the space was followed by the HTTP ** identifier. (NOTE: the HTTP delimiter is no longer "HTTP/", but ** can also be "\r\n", "\n", or "\r". This is the defunct method, and ** we deal with it in the IsHttpVersion and delimiter functions.) ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval HI_SUCCESS found the next non-whitespace ** @retval HI_OUT_OF_BOUNDS whitespace to the end of the buffer ** @retval URI_END delimiter found, end of URI ** @retval NO_URI */ int NextNonWhiteSpace(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; const u_char **start_sp; const u_char **end_sp; /* ** Horizontal tab is only accepted by apache web servers, not IIS. ** Some IIS exploits contain a tab (0x09) in the URI, so we don't want ** to treat it as a URI delimiter and cut off the URI. */ if ( **ptr == '\t' && !ServerConf->tab_uri_delimiter ) { (*ptr)++; return HI_SUCCESS; } /* ** Reset the identifier, because we've just seen another space. We ** should only see the identifier immediately after a space followed ** by a delimiter. */ if(uri_ptr->ident) { if(ServerConf->non_strict) { /* ** In non-strict mode it is ok to see spaces after the ** "identifier", so we just increment the ptr and return. */ (*ptr)++; return HI_SUCCESS; } else { /* ** This means that we've already seen a space and a version ** identifier, and now that we've seen another space, we know ** that this can't be the URI so we just bail out with no ** URI. */ return NO_URI; } } uri_ptr->ident = NULL; /* ** We only check for one here, because both should be set if one ** is. */ if(uri_ptr->first_sp_end) { /* ** If the second space has been set, then this means that we have ** seen a third space, which we shouldn't see in the URI so we ** are now done and know there is no URI in this packet. */ if(uri_ptr->second_sp_end) { return NO_URI; } /* ** Treat whitespace differently at the end of the URI than we did ** at the beginning. Ignore and return if special characters are ** not defined as whitespace after the URI. */ if(ServerConf->whitespace[**ptr] && !(ServerConf->whitespace[**ptr] & HI_UI_CONFIG_WS_AFTER_URI)) { (*ptr)++; return HI_SUCCESS; } /* ** Since we've seen the second space, we need to update the uri ptr ** to the end of the first space, since the URI cannot be before the ** first space. */ uri_ptr->uri = uri_ptr->first_sp_end; uri_ptr->second_sp_start = *ptr; uri_ptr->second_sp_end = NULL; start_sp = &uri_ptr->second_sp_start; end_sp = &uri_ptr->second_sp_end; } else { /* ** This means that there is whitespace at the beginning of the line ** and we unset the URI so we can set it later if need be. ** ** This is mainly so we handle data that is all spaces correctly. ** ** In the normal case where we've seen text and then the first space, ** we leave the uri ptr pointing at the beginning of the data, and ** set the uri end after we've determined where to put it. */ if(start == *ptr) uri_ptr->uri = NULL; uri_ptr->first_sp_start = *ptr; uri_ptr->first_sp_end = NULL; start_sp = &uri_ptr->first_sp_start; end_sp = &uri_ptr->first_sp_end; } while(hi_util_in_bounds(start, end, *ptr)) { /* ** Check for whitespace */ if(**ptr == ' ') { (*ptr)++; continue; } else if(ServerConf->whitespace[**ptr]) { if(ServerConf->apache_whitespace.on) { if(hi_eo_generate_event(Session, ServerConf->apache_whitespace.alert)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_APACHE_WS, NULL, NULL); } } (*ptr)++; continue; } else { /* ** This sets the sp_end for whatever space delimiter we are on, ** whether that is the first space or the second space. */ *end_sp = *ptr; if(!IsHttpVersion(ptr, end)) { /* ** This is the default method and what we've been doing ** since the start of development. */ if(uri_ptr->second_sp_start) { /* ** There is no HTTP version indentifier at the beginning ** of the second space, and this means that there is no ** URI. */ if(ServerConf->non_strict) { /* ** In non-strict mode, we must assume the URI is ** between the first and second space, so now ** that we've seen the second space that's the ** identifier. */ uri_ptr->ident = *end_sp; uri_ptr->uri_end = *start_sp; return HI_SUCCESS; } else { /* ** Since we are in strict mode here, it means that ** we haven't seen a valid identifier, so there was ** no URI. */ return NO_URI; } } /* ** RESET NECESSARY URI_PTRs HERE. This is the place where ** the uri is updated. It can only happen once, so do it ** right here. ** ** When we get here it means that we have found the end of ** the FIRST whitespace, and that there was no delimiter, ** so we reset the uri pointers and other related ** pointers. */ uri_ptr->uri = *end_sp; uri_ptr->uri_end = end; uri_ptr->norm = NULL; uri_ptr->last_dir = NULL; uri_ptr->param = NULL; uri_ptr->proxy = NULL; } else { /* ** Means we found the HTTP version identifier and we reset ** the uri_end pointer to point to the beginning of the ** whitespace detected. ** ** This works for both "uri_is_here HTTP/1.0" and ** "METHOD uri_is_here HTTP/1.0", so it works when the ** identifier is after either the first or the second ** whitespace. */ uri_ptr->ident = *end_sp; uri_ptr->uri_end = *start_sp; } /* ** We found a non-whitespace char */ return HI_SUCCESS; } } /* ** This is the case where we've seen text and found a whitespace until ** the end of the buffer. In that case, we set the uri_end to the ** beginning of the whitespace. */ uri_ptr->uri_end = *start_sp; return HI_OUT_OF_BOUNDS; } /* ** NAME ** SetPercentNorm:: */ /** ** Check for percent normalization in the URI buffer. ** ** We don't do much here besides check the configuration, set the pointer, ** and continue processing. ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval HI_SUCCESS function successful */ int SetPercentNorm(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; if(!uri_ptr->norm && !uri_ptr->ident) { if(ServerConf->ascii.on) { uri_ptr->norm = *ptr; } } (*ptr)++; return HI_SUCCESS; } /* ** NAME ** CheckLongDir:: */ /** ** We check the directory length against the global config. ** ** @param Session pointer to the current session ** @param uri_ptr pointer to the URI state ** @param ptr pointer to the current index in buffer ** ** @return integer ** ** @retval HI_SUCCESS */ static inline int CheckLongDir(HI_SESSION *Session, URI_PTR *uri_ptr, const u_char *ptr) { int iDirLen; /* ** Check for oversize directory */ if(Session->server_conf->long_dir && uri_ptr->last_dir && !uri_ptr->param) { iDirLen = ptr - uri_ptr->last_dir; if(iDirLen > Session->server_conf->long_dir && hi_eo_generate_event(Session, HI_EO_CLIENT_OVERSIZE_DIR)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_OVERSIZE_DIR, NULL, NULL); } } return HI_SUCCESS; } /* ** NAME ** SetSlashNorm:: */ /** ** Check for any directory traversal or multi-slash normalization. ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval HI_SUCCESS function successful ** @retval HI_OUT_OF_BOUNDS reached the end of the buffer */ int SetSlashNorm(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; CheckLongDir(Session, uri_ptr, *ptr); if( proxy_start) { // This is the first dir after http:// if(!uri_ptr->ident && !uri_ptr->last_dir) proxy_end = *ptr; } uri_ptr->last_dir = *ptr; if(!uri_ptr->norm && !uri_ptr->ident) { uri_ptr->norm = *ptr; (*ptr)++; if(!hi_util_in_bounds(start,end, *ptr)) { /* ** This is the case where there is a slash as the last char ** and we don't want to normalize that since there really ** is nothing to normalize. */ uri_ptr->norm = NULL; return HI_OUT_OF_BOUNDS; } /* ** Check for directory traversals */ if(ServerConf->directory.on) { if(**ptr == '.') { (*ptr)++; if(!hi_util_in_bounds(start, end, *ptr)) { uri_ptr->norm = NULL; return HI_OUT_OF_BOUNDS; } if(**ptr == '.' || ** ptr == '/') { return HI_SUCCESS; } } } /* ** Check for multiple slash normalization */ if(ServerConf->multiple_slash.on) { if(**ptr == '/') { return HI_SUCCESS; } } uri_ptr->norm = NULL; return HI_SUCCESS; } (*ptr)++; return HI_SUCCESS; } /* ** NAME ** SetBackSlashNorm:: */ /** ** Check for backslashes and if we need to normalize. ** ** This really just checks the configuration option, and sets the norm ** variable if applicable. ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval HI_SUCCESS function successful */ int SetBackSlashNorm(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; if(!uri_ptr->norm && !uri_ptr->ident) { if(ServerConf->iis_backslash.on) { uri_ptr->norm = *ptr; } } (*ptr)++; return HI_SUCCESS; } /* * ** NAME * ** SetPlusNorm:: * */ /** * ** Check for "+" and if we need to normalize. * ** * ** * ** @param ServerConf pointer to the server configuration * ** @param start pointer to the start of payload * ** @param end pointer to the end of the payload * ** @param ptr pointer to the pointer of the current index * ** @param uri_ptr pointer to the URI_PTR construct * ** * ** @return integer * ** * ** @retval HI_SUCCESS function successful * */ int SetPlusNorm(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { if(!uri_ptr->norm && !uri_ptr->ident) { uri_ptr->norm = *ptr; } (*ptr)++; return HI_SUCCESS; } /* ** NAME ** SetBinaryNorm:: */ /** ** Look for non-ASCII chars in the URI. ** ** We look for these chars in the URI and set the normalization variable ** if it's not already set. I think we really only need this for IIS ** servers, but we may want to know if it's in the URI too. ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval HI_SUCCESS function successful */ int SetBinaryNorm(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { if(!uri_ptr->norm && !uri_ptr->ident) { uri_ptr->norm = *ptr; } (*ptr)++; return HI_SUCCESS; } /* ** NAME ** SetParamField:: */ /** ** This function sets the parameter field as the first '?'. The big thing ** is that we set the param value, so we don't false positive long dir ** events when it's really just a long parameter field. ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval HI_SUCCESS function successful */ int SetParamField(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { if(!uri_ptr->ident) { uri_ptr->param = *ptr; } (*ptr)++; return HI_SUCCESS; } /* ** NAME ** SetProxy:: */ /** ** This function checks for an absolute URI in the URI. ** ** @param ServerConf pointer to the server configuration ** @param start pointer to the start of payload ** @param end pointer to the end of the payload ** @param ptr pointer to the pointer of the current index ** @param uri_ptr pointer to the URI_PTR construct ** ** @return integer ** ** @retval HI_SUCCESS function successful */ int SetProxy(HI_SESSION *Session, const u_char *start, const u_char *end, const u_char **ptr, URI_PTR *uri_ptr) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; if(!uri_ptr->ident && !uri_ptr->last_dir) { if(hi_util_in_bounds(start, end, ((*ptr)+2))) { if(*((*ptr)+1) == '/' && *((*ptr)+2) == '/') { if(Session->global_conf->proxy_alert && !ServerConf->allow_proxy) uri_ptr->proxy = *ptr; //If we found :// check to see if it is preceeded by http. If so, this is a proxy proxy_start = (u_char *)SnortStrcasestr((const char *)uri_ptr->uri, (*ptr - uri_ptr->uri), "http"); proxy_end = end; (*ptr) = (*ptr) + 3; return HI_SUCCESS; } } } (*ptr)++; return HI_SUCCESS; } /* ** NAME ** SetClientVars:: */ /** ** This is where we set the HI_CLIENT values that we found during URI ** discovery. This also covers checking these values for errors. ** ** @param Client pointer to HI_CLIENT structure ** @param uri_ptr pointer to the uri data ** ** @return integer ** ** @retval HI_NONFATAL_ERR problem with the uri values. ** @retval HI_SUCCESS values set successfully */ static int SetClientVars(HI_CLIENT *Client, URI_PTR *uri_ptr, u_int dsize) { /* ** We got here either because we found the delimiter or we are ** out of bounds. */ /* if(uri_ptr->first_sp_start) printf("** first_start = %c\n", *uri_ptr->first_sp_start); if(uri_ptr->first_sp_end) printf("** first_end = %c\n", *uri_ptr->first_sp_end); if(uri_ptr->second_sp_start) printf("** second_start = %c\n", *uri_ptr->second_sp_start); if(uri_ptr->second_sp_end) printf("** second_end = %c\n", *uri_ptr->second_sp_end); if(uri_ptr->delimiter) printf("** delimiter = %c\n", *uri_ptr->delimiter); if(uri_ptr->uri) printf("** uri = %c\n", *uri_ptr->uri); if(uri_ptr->norm) printf("** norm = %.2x\n", *uri_ptr->norm); */ /* ** This means that there was only spaces or delimiters within the ** complete URI. In this case, there is no valid URI so we just ** return such. */ if(uri_ptr->uri == NULL) { return HI_NONFATAL_ERR; } /* ** This is where we set the Session variables before moving into more ** HttpInspect processing. If we don't get to this point, then we don't ** need to set these variables since we would have aborted with a ** NONFATAL_ERR. */ Client->request.uri = uri_ptr->uri; Client->request.uri_size = uri_ptr->uri_end - uri_ptr->uri; Client->request.uri_norm = uri_ptr->norm; /* ** LAST RESORT: ** ** This is one of the last checks we do to make sure that we didn't ** mess up or anything. */ if(Client->request.uri_size > dsize) { /* ** Bad stuff, let's just bail. */ return HI_NONFATAL_ERR; } /* printf("** Norm = %s\n", Client->request.uri_norm ? "YES" : "NO"); printf("** URI: |%.*s| size = %u\n", Client->request.uri_size, Client->request.uri, Client->request.uri_size); */ return HI_SUCCESS; } static inline int hi_client_extract_post( HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf, const u_char *ptr, const u_char *end, URI_PTR *result, int content_length, bool is_chunked, HttpSessionData *hsd) { const u_char *start = ptr; const u_char *post_end = end; Session->norm_flags &= HI_BODY; /* Limit search depth */ if (is_chunked) { if ( (ServerConf->chunk_length || ServerConf->small_chunk_length.size) && (CheckChunkEncoding(Session, start, end, &post_end, NULL, 0, 0, NULL, NULL, hsd, HI_SI_CLIENT_MODE) == 1) ) { result->uri = start; result->uri_end = post_end; return POST_END; } else { return HI_NONFATAL_ERR; } } else if(content_length > 0) { if ((post_end - ptr ) > content_length) { post_end = ptr + content_length; } } else { return HI_NONFATAL_ERR; } result->uri = start; result->uri_end = post_end; return POST_END; } static inline int HTTP_CopyExtraDataToSession(const uint8_t *start, int length, int command_type, HTTP_LOG_STATE *log_state) { uint8_t *alt_buf; uint32_t alt_size; uint32_t *alt_len; int ret; if (length <= 0) return -1; switch (command_type) { case COPY_URI: alt_buf = log_state->uri_extracted; alt_size = MAX_URI_EXTRACTED; alt_len = &(log_state->uri_bytes); break; case COPY_HOSTNAME: alt_buf = log_state->hostname_extracted; alt_size = MAX_HOSTNAME; alt_len = &(log_state->hostname_bytes); break; default: return -1; } if(length > (int) alt_size) length = alt_size; *alt_len = 0; ret = SafeMemcpy(alt_buf, start, length, alt_buf, alt_buf + alt_size); if (ret != SAFEMEM_SUCCESS) { return -1; } *alt_len += length; return 0; } static inline void HTTP_CopyUri(HTTPINSPECT_CONF *ServerConf, const u_char *start, const u_char *end, HttpSessionData *hsd, int stream_ins) { int iRet = 0; const u_char *cur_ptr; cur_ptr = start; if(ServerConf->log_uri && !stream_ins && hsd) { SkipBlankSpace(start,end,&cur_ptr); start = cur_ptr; if(!SetLogBuffers(hsd)) { iRet = HTTP_CopyExtraDataToSession((uint8_t *)start, (end - start), COPY_URI, hsd->log_state); if(!iRet) hsd->log_flags |= HTTP_LOG_URI; } } } static inline int unfold_http_uri(HTTPINSPECT_CONF *ServerConf, const u_char *end, URI_PTR *uri_ptr, HttpSessionData *hsd, int stream_ins) { uint8_t unfold_buf[DECODE_BLEN]; uint32_t unfold_size =0; const u_char *p; int folded = 0; const char *tmp = NULL; int iRet = -1; p = uri_ptr->uri; sf_unfold_header(p, (end - p), unfold_buf, sizeof(unfold_buf), &unfold_size, 0, &folded); if( !folded) { HTTP_CopyUri(ServerConf, uri_ptr->uri , uri_ptr->uri_end, hsd, stream_ins); return iRet; } tmp = SnortStrnPbrk((const char *)unfold_buf, unfold_size, " \t"); if (tmp != NULL) { unfold_size = ((uint8_t *)tmp - unfold_buf); iRet = 0; } p = p + unfold_size; uri_ptr->uri_end = p; HTTP_CopyUri(ServerConf, unfold_buf, unfold_buf + unfold_size, hsd, stream_ins); return iRet; } static inline int hi_client_extract_uri( HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf, HI_CLIENT * Client, const u_char *start, const u_char *end, const u_char *ptr, URI_PTR *uri_ptr, HttpSessionData *hsd, int stream_ins) { int iRet = HI_SUCCESS; const u_char *tmp; int uri_copied = 0; Session->norm_flags &= ~HI_BODY; /* ** This loop compares each char to an array of functions ** (one for each char) and calling that function if there is one. ** ** If there is no function, then we just increment the char ptr and ** continue processing. ** ** If there is a function, we call that function and process. It's ** important to note that the function that is called is responsible ** for incrementing the ptr to the next char to be inspected. The ** loop does not increment the pointer when a function is called to ** allow the maximum flexibility to the functions. */ while(hi_util_in_bounds(start, end, ptr)) { if(!ServerConf->extended_ascii_uri) { /* isascii returns non-zero if it is ascii */ if (isascii((int)*ptr) == 0) { /* Possible post data or something else strange... */ iRet = URI_END; /* Find the end of the URI in this case*/ tmp = (const u_char *)SnortStrnPbrk((const char *)ptr, (uri_ptr->uri_end - ptr), " \r\n\t"); if(tmp != NULL) uri_ptr->uri_end = tmp; if(!uri_copied) { HTTP_CopyUri(ServerConf, uri_ptr->uri , uri_ptr->uri_end, hsd, stream_ins); } break; } } if(lookup_table[*ptr] || ServerConf->whitespace[*ptr]) { if(lookup_table[*ptr]) { iRet = (lookup_table[*ptr])(Session, start, end, &ptr, uri_ptr); } else { iRet = NextNonWhiteSpace(Session, start, end, &ptr, uri_ptr); } if(iRet) { if(iRet == URI_END) { if((*(uri_ptr->uri_end) == '\n') || (*(uri_ptr->uri_end) == '\r') ) { uri_copied = 1; if(!unfold_http_uri(ServerConf, end, uri_ptr, hsd, stream_ins )) { SkipCRLF(start,end, &ptr); continue; } } else if(!uri_copied) { HTTP_CopyUri(ServerConf, uri_ptr->uri , uri_ptr->uri_end, hsd, stream_ins); } /* ** You found a URI, let's break and check it out. */ break; } else if(iRet == HI_OUT_OF_BOUNDS) { /* ** Means you've reached the end of the buffer. THIS ** DOESN'T MEAN YOU HAVEN'T FOUND A URI. */ break; } else /* NO_URI */ { /* ** Check for chunk encoding, because the delimiter can ** also be a space, which would look like a pipeline request ** to us if we don't do this first. */ if(Session->server_conf->chunk_length || Session->server_conf->small_chunk_length.size) { (void)CheckChunkEncoding(Session, start, end, NULL, NULL, 0, 0, NULL, NULL, hsd, HI_SI_CLIENT_MODE); } /* ** We only inspect the packet for another pipeline ** request if there wasn't a previous pipeline request. ** The reason that we do this is because */ if(!Client->request.pipeline_req) { /* ** Just because there was no URI in the first part ** the packet, doesn't mean that this isn't a ** pipelined request that has been segmented. */ if(!ServerConf->no_pipeline) { Client->request.pipeline_req = FindPipelineReq(Session, ptr, end); if(Client->request.pipeline_req) { return HI_SUCCESS; } } } return HI_NONFATAL_ERR; } } else { /* ** This means that we found the next non-whitespace char ** and since we are already pointed there, so we just ** continue. */ continue; } } ptr++; } /* No uri in this request. We shouldn't process this request */ if(uri_ptr->uri == uri_ptr->uri_end) return HI_NONFATAL_ERR; return iRet; } const u_char *extract_http_cookie(const u_char *p, const u_char *end, HEADER_PTR *header_ptr, HEADER_FIELD_PTR *header_field_ptr) { const u_char *crlf; const u_char *start; if (header_ptr->cookie.cookie) { /* unusal, multiple cookies... alloc new cookie pointer */ COOKIE_PTR *extra_cookie = calloc(1, sizeof(COOKIE_PTR)); if (!extra_cookie) { /* Failure to allocate, stop where we are... */ header_ptr->header.uri_end = p; return p; } header_field_ptr->cookie->next = extra_cookie; header_field_ptr->cookie = extra_cookie; /* extra_cookie->next = NULL; */ /* removed, since calloc NULLs this. */ } else { header_field_ptr->cookie = &header_ptr->cookie; } start = p; /* skip spaces before : */ SkipBlankSpace(start,end,&p); if(hi_util_in_bounds(start, end, p) && *p == ':') { p++; SkipBlankSpace(start,end,&p); } header_field_ptr->cookie->cookie = p; { crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n"); /* find a \n */ if (crlf) /* && hi_util_in_bounds(start, end, crlf+1)) bounds is checked in SnortStrnStr */ { if(*(crlf -1) == '\r') header_field_ptr->cookie->cookie_end = crlf - 1; else header_field_ptr->cookie->cookie_end = crlf; p = crlf; } else { header_ptr->header.uri_end = header_field_ptr->cookie->cookie_end = end; return end; } } return p; } const u_char *extract_http_xff(HI_SESSION *Session, const u_char *p, const u_char *start, const u_char *end, HI_CLIENT_HDR_ARGS *hdrs_args) { int num_spaces = 0; SFIP_RET status; sfip_t *tmp; char *ipAddr = NULL; uint8_t unfold_buf[DECODE_BLEN]; uint32_t unfold_size =0; const u_char *start_ptr, *end_ptr, *cur_ptr; const u_char *port; HEADER_PTR *header_ptr; sfip_t **true_ip; header_ptr = hdrs_args->hdr_ptr; true_ip = &(hdrs_args->sd->true_ip); if(!true_ip) return p; if( (hdrs_args->true_clnt_xff & HDRS_BOTH) == HDRS_BOTH) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_BOTH_TRUEIP_XFF_HDRS)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_BOTH_TRUEIP_XFF_HDRS, NULL, NULL); } } SkipBlankSpace(start,end,&p); if(hi_util_in_bounds(start, end, p) && *p == ':') { p++; if(hi_util_in_bounds(start, end, p)) sf_unfold_header(p, end-p, unfold_buf, sizeof(unfold_buf), &unfold_size, 0 , &num_spaces); if(!unfold_size) { header_ptr->header.uri_end = end; return end; } if(num_spaces >= Session->server_conf->max_spaces) { if(hi_eo_generate_event(Session, Session->server_conf->max_spaces)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL); } } p = p + unfold_size; start_ptr = unfold_buf; cur_ptr = unfold_buf; end_ptr = unfold_buf + unfold_size; SkipBlankSpace(start_ptr,end_ptr,&cur_ptr); start_ptr = cur_ptr; while( cur_ptr < end_ptr ) { if( *cur_ptr == ' ' || *cur_ptr == '\t' || *cur_ptr == ',' ) break; cur_ptr++; } if(cur_ptr - start_ptr) { ipAddr = SnortStrndup((const char *)start_ptr, cur_ptr - start_ptr ); } if(ipAddr) { if( (tmp = sfip_alloc(ipAddr, &status)) == NULL ) { port = (u_char *)SnortStrnStr((const char *)start_ptr, (cur_ptr - start_ptr), ":"); if(port) { free(ipAddr); ipAddr = SnortStrndup((const char *)start_ptr, port - start_ptr ); if( !ipAddr) { return p; } if( (tmp = sfip_alloc(ipAddr, &status)) == NULL ) { if((status != SFIP_ARG_ERR) && (status !=SFIP_ALLOC_ERR)) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_INVALID_TRUEIP)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_INVALID_TRUEIP, NULL, NULL); } free(ipAddr); return p; } } } else if((status != SFIP_ARG_ERR) && (status !=SFIP_ALLOC_ERR)) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_INVALID_TRUEIP)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_INVALID_TRUEIP, NULL, NULL); } free(ipAddr); return p; } } if(*true_ip) { if(!IP_EQUALITY(*true_ip, tmp)) { sfip_free(*true_ip); *true_ip = tmp; //alert if(hi_eo_generate_event(Session, HI_EO_CLIENT_MULTIPLE_TRUEIP_IN_SESSION)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_MULTIPLE_TRUEIP_IN_SESSION, NULL, NULL); } } else sfip_free(tmp); } else *true_ip = tmp; free(ipAddr); } } else { header_ptr->header.uri_end = end; return end; } return p; } const u_char *extract_http_hostname(HI_SESSION *Session, const u_char *p, const u_char *start, const u_char *end, HEADER_PTR *header_ptr, HttpSessionData *hsd) { int num_spaces = 0; uint8_t unfold_buf[DECODE_BLEN]; uint32_t unfold_size =0; const u_char *start_ptr, *end_ptr, *cur_ptr; int iRet=0; SkipBlankSpace(start,end,&p); if(hi_util_in_bounds(start, end, p) && *p == ':') { p++; if(hi_util_in_bounds(start, end, p)) sf_unfold_header(p, end-p, unfold_buf, sizeof(unfold_buf), &unfold_size, 0, &num_spaces); if(!unfold_size) { header_ptr->header.uri_end = end; return end; } if(num_spaces >= Session->server_conf->max_spaces) { //alert if(hi_eo_generate_event(Session, Session->server_conf->max_spaces)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL); } } p = p + unfold_size; start_ptr = unfold_buf; cur_ptr = unfold_buf; end_ptr = unfold_buf + unfold_size; SkipBlankSpace(start_ptr,end_ptr,&cur_ptr); start_ptr = cur_ptr; if((end_ptr - start_ptr) >= MAX_HOSTNAME) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_LONG_HOSTNAME)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HOSTNAME, NULL, NULL); } } iRet = HTTP_CopyExtraDataToSession((uint8_t *)start_ptr, (end_ptr - start_ptr), COPY_HOSTNAME, hsd->log_state); if(!iRet) { hsd->log_flags |= HTTP_LOG_HOSTNAME; } } else { header_ptr->header.uri_end = end; return end; } return p; } const u_char *extract_http_content_length(HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf, const u_char *p, const u_char *start, const u_char *end, HEADER_PTR *header_ptr, HEADER_FIELD_PTR *header_field_ptr) { int num_spaces = 0; const u_char *crlf; int space_present = 0; if (header_ptr->content_len.cont_len_start) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_MULTIPLE_CONTLEN)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_MULTIPLE_CONTLEN, NULL, NULL); } header_ptr->header.uri_end = p; header_ptr->content_len.len = 0; return p; } else { header_field_ptr->content_len = &header_ptr->content_len; p = p + 14; } /* Move past all the blank spaces. Only tabs and spaces are allowed here */ SkipBlankSpace(start,end,&p); if(hi_util_in_bounds(start, end, p) && *p == ':') { p++; if ( hi_util_in_bounds(start, end, p) ) { if ( ServerConf->profile == HI_APACHE || ServerConf->profile == HI_ALL) { SkipWhiteSpace(start,end,&p); } else { SkipBlankAndNewLine(start,end,&p); } if( hi_util_in_bounds(start, end, p)) { if ( *p == '\n' ) { while(hi_util_in_bounds(start, end, p)) { if ( *p == '\n') { p++; while( hi_util_in_bounds(start, end, p) && ( *p == ' ' || *p == '\t')) { space_present = 1; p++; num_spaces++; } if ( space_present ) { if(num_spaces >= Session->server_conf->max_spaces) { if(hi_eo_generate_event(Session, Session->server_conf->max_spaces)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL); } } if ( isdigit((int)*p)) break; else if(isspace((int)*p) && (ServerConf->profile == HI_APACHE || ServerConf->profile == HI_ALL) ) { SkipWhiteSpace(start,end,&p); } else { header_field_ptr->content_len->cont_len_start = header_field_ptr->content_len->cont_len_end = NULL; header_field_ptr->content_len->len = 0; return p; } } else { header_field_ptr->content_len->cont_len_start = header_field_ptr->content_len->cont_len_end = NULL; header_field_ptr->content_len->len = 0; return p; } } else break; } } else if(!isdigit((int)*p)) { header_field_ptr->content_len->cont_len_start = header_field_ptr->content_len->cont_len_end = NULL; header_field_ptr->content_len->len = 0; return p; } if(isdigit((int)*p)) { header_field_ptr->content_len->cont_len_start = p; p++; while(hi_util_in_bounds(start, end, p)) { if(isdigit((int)*p)) { p++; continue; } else if((*p == '\n')) /* digit followed by \n */ { header_field_ptr->content_len->cont_len_end = p; break; } else if( (!isdigit((int)*p)) && (!isspace((int)*p))) /* alphabet after digit*/ { header_field_ptr->content_len->cont_len_start = header_field_ptr->content_len->cont_len_end = NULL; header_field_ptr->content_len->len = 0; crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n"); if (crlf) { return p; } else { header_ptr->header.uri_end = end; return end; } } else { if (ServerConf->profile == HI_APACHE || ServerConf->profile == HI_ALL) { SkipWhiteSpace(start,end,&p); } else { SkipBlankAndNewLine(start,end,&p); } if ( *p == '\n' ) { header_field_ptr->content_len->cont_len_end = p; break; } else /*either a "digit digit" or "digit other character" */ { header_field_ptr->content_len->cont_len_start = header_field_ptr->content_len->cont_len_end = NULL; header_field_ptr->content_len->len = 0; crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n"); if (crlf) { p = crlf; return p; } else { header_ptr->header.uri_end = end; return end; } } } } } else { header_field_ptr->content_len->cont_len_start = header_field_ptr->content_len->cont_len_end = NULL; header_field_ptr->content_len->len = 0; return p; } } } } else { if(hi_util_in_bounds(start, end, p)) { crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n"); if(crlf) { p = crlf; } else { header_ptr->header.uri_end = end ; return end; } } } if ( header_field_ptr->content_len->cont_len_start && header_field_ptr->content_len->cont_len_end ) { char *pcEnd; uint64_t len; len = (uint64_t)SnortStrtol((char *)header_field_ptr->content_len->cont_len_start, &pcEnd, 10); if ( (errno == ERANGE) || ((char *)header_field_ptr->content_len->cont_len_start == pcEnd) || (len > 0xFFFFFFFF) ) { header_field_ptr->content_len->len = 0; } else header_field_ptr->content_len->len = (uint32_t)len; } if(!p || !hi_util_in_bounds(start, end, p)) p = end; return p; } static inline const u_char *extractHeaderFieldValues(HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf, const u_char *p, const u_char *offset, const u_char *start, const u_char *end, HI_CLIENT_HDR_ARGS *hdrs_args) { HttpSessionData *hsd; hsd = hdrs_args->sd; if (((p - offset) == 0) && ((*p == 'C') || (*p == 'c'))) { /* Search for 'Cookie' at beginning, starting from current *p */ if ( ServerConf->enable_cookie && IsHeaderFieldName(p, end, HEADER_NAME__COOKIE, HEADER_LENGTH__COOKIE)) { p = extract_http_cookie((p+ HEADER_LENGTH__COOKIE), end, hdrs_args->hdr_ptr, hdrs_args->hdr_field_ptr); } else if ( IsHeaderFieldName(p, end, HEADER_NAME__CONTENT_LENGTH, HEADER_LENGTH__CONTENT_LENGTH) ) { p = extract_http_content_length(Session, ServerConf, p, start, end, hdrs_args->hdr_ptr, hdrs_args->hdr_field_ptr ); } else if ( IsHeaderFieldName(p, end, HEADER_NAME__CONTENT_TYPE, HEADER_LENGTH__CONTENT_TYPE) ) { Session->client.request.content_type = p; } } else if (((p - offset) == 0) && ((*p == 'x') || (*p == 'X') || (*p == 't') || (*p == 'T'))) { if ( (ServerConf->enable_xff) && hsd ) { if(IsHeaderFieldName(p, end, HEADER_NAME__XFF, HEADER_LENGTH__XFF)) { hdrs_args->true_clnt_xff |= XFF_HDR; p = p + HEADER_LENGTH__XFF; p = extract_http_xff(Session, p, start, end, hdrs_args); } else if(IsHeaderFieldName(p, end, HEADER_NAME__TRUE_IP, HEADER_LENGTH__TRUE_IP)) { hdrs_args->true_clnt_xff |= TRUE_CLIENT_IP_HDR; p = p + HEADER_LENGTH__TRUE_IP; p = extract_http_xff(Session, p, start, end, hdrs_args); } } else if ( IsHeaderFieldName(p, end, HEADER_NAME__TRANSFER_ENCODING, HEADER_LENGTH__TRANSFER_ENCODING) && hsd) { p = p + HEADER_LENGTH__TRANSFER_ENCODING; p = extract_http_transfer_encoding(Session, hsd, p, start, end, hdrs_args->hdr_ptr, HI_SI_CLIENT_MODE); } } else if(((p - offset) == 0) && ((*p == 'H') || (*p == 'h'))) { if(IsHeaderFieldName(p, end, HEADER_NAME__HOSTNAME, HEADER_LENGTH__HOSTNAME)) { /* Alert when there are multiple host headers in one request */ if(hdrs_args->hst_name_hdr) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_MULTIPLE_HOST_HDRS)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_MULTIPLE_HOST_HDRS, NULL, NULL); } return p; } else { hdrs_args->hst_name_hdr = 1; if ( hsd && !(hdrs_args->strm_ins) && (ServerConf->log_hostname)) { if(!SetLogBuffers(hsd)) { p = p + HEADER_LENGTH__HOSTNAME; p = extract_http_hostname(Session, p, start, end, hdrs_args->hdr_ptr, hsd); } } } } } return p; } /* ** NAME ** hi_client_extract_header:: */ /** ** Catch multiple requests per packet, by returning pointer to after the ** end of the request header if there is another request. ** ** There are 4 types of "valid" delimiters that we look for. They are: ** "\r\n\r\n" ** "\r\n\n" ** "\n\r\n" ** "\n\n" ** The only patterns that we really only need to look for are: ** "\n\r\n" ** "\n\n" ** The reason being that these two patterns are suffixes of the other ** patterns. So once we find those, we are all good. ** ** @param Session pointer to the session ** @param start pointer to the start of text ** @param end pointer to the end of text ** ** @return pointer ** ** @retval NULL Did not find pipeline request ** @retval !NULL Found another possible request. */ static inline const u_char *hi_client_extract_header( HI_SESSION *Session, HTTPINSPECT_CONF *ServerConf, HEADER_PTR *header_ptr, const u_char *start, const u_char *end, HttpSessionData *hsd, int stream_ins) { int iRet = HI_SUCCESS; const u_char *p; const u_char *offset; const u_char *crlf; URI_PTR version_string; HEADER_FIELD_PTR header_field_ptr ; HI_CLIENT_HDR_ARGS hdrs_args; int header_count = 0; int num_spaces = 0; if(!start || !end) return NULL; p = start; /* ** We say end - 6 because we need at least six bytes to verify that ** there is an end to the URI and still a request afterwards. To be ** exact, we should only subtract 1, but we are not interested in a ** 1 byte method, uri, etc. ** ** a.k.a there needs to be data after the initial request to inspect ** to make it worth our while. */ if (p > (end - 6 )) { header_ptr->header.uri = NULL; return p; } header_ptr->content_len.len = 0; header_ptr->is_chunked = false; header_ptr->header.uri = start; header_ptr->header.uri_end = end; hdrs_args.hdr_ptr = header_ptr; hdrs_args.hdr_field_ptr = &header_field_ptr; hdrs_args.sd = hsd; hdrs_args.strm_ins = stream_ins; hdrs_args.hst_name_hdr = 0; hdrs_args.true_clnt_xff = 0; SkipBlankSpace(start,end,&p); /* This is to skip past the HTTP/1.0 (or 1.1) version string */ if (IsHttpVersion(&p, end)) { memset(&version_string, 0, sizeof(URI_PTR)); version_string.uri = p; while (hi_util_in_bounds(start, end, p)) { if(lookup_table[*p] || ServerConf->whitespace[*p]) { if(lookup_table[*p]) { iRet = (lookup_table[*p])(Session, start, end, &p, &version_string); } else { iRet = NextNonWhiteSpace(Session, start, end, &p, &version_string); } if(iRet == URI_END) { if (*p == '\n') { p++; if (hi_util_in_bounds(start, end, p)) { version_string.uri_end = p; } else { return p; } if(hi_eo_generate_event(Session, Session->server_conf->max_spaces)) { num_spaces = SkipBlankSpace(start,end,&p); if(num_spaces >= Session->server_conf->max_spaces) { //alert hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL); } } } break; } else if(iRet == HI_OUT_OF_BOUNDS) { return p; } } p++; } if (iRet == URI_END) { header_ptr->header.uri = version_string.uri_end + 1; offset = (u_char *)p; } else { return p; } } else { if(hi_eo_generate_event(Session, HI_EO_CLIENT_UNESCAPED_SPACE_URI)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_UNESCAPED_SPACE_URI, NULL, NULL); } if(p < end) { crlf = (u_char *)SnortStrnStr((const char *)p, end - p, "\n"); if(crlf) { p = crlf; } else return p; } else { return p; } } offset = (u_char*)p; header_ptr->header.uri = p; while (hi_util_in_bounds(start, end, p)) { if(*p == '\n') { header_count++; if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len) && ((p - offset) >= Session->server_conf->max_hdr_len)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL); } if (Session->server_conf->max_headers && (header_count > Session->server_conf->max_headers)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_MAX_HEADERS, NULL, NULL); } p++; if(hi_eo_generate_event(Session, Session->server_conf->max_spaces)) { num_spaces = SkipBlankSpace(start,end,&p); if(num_spaces >= Session->server_conf->max_spaces) { //alert hi_eo_client_event_log(Session, HI_EO_CLIENT_EXCEEDS_SPACES, NULL, NULL); } } offset = (u_char*)p; if (!hi_util_in_bounds(start, end, p)) { header_ptr->header.uri_end = p; return p; } hdrs_args.hdr_ptr = header_ptr; hdrs_args.hdr_field_ptr = &header_field_ptr; /* As performance ugly as this may be, need to bounds check p in each of the * if blocks below to prevent read beyond end of buffer */ if (*p < 0x0E) { if(*p == '\r') { p++; if (!hi_util_in_bounds(start, end, p)) { header_ptr->header.uri_end = p; return p; } else if(*p == '\n') { p++; header_ptr->header.uri_end = p; return p; } } else if(*p == '\n') { p++; header_ptr->header.uri_end = p; return p; } } else if ( (p = extractHeaderFieldValues(Session, ServerConf, p, offset, start, end, &hdrs_args)) == end) { return end; } } else if( (p == header_ptr->header.uri) && (p = extractHeaderFieldValues(Session, ServerConf, p, offset, start, end, &hdrs_args)) == end) { return end; } if ( *p == '\n') continue; p++; } /* Never observed an end-of-field. Maybe it's not there, but the header is long anyway: */ if(hi_eo_generate_event(Session, Session->server_conf->max_hdr_len) && ((p - start) >= Session->server_conf->max_hdr_len)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL); } header_ptr->header.uri_end = p; return p; } #define CLR_POST(Client) \ do { \ Client->request.post_raw = NULL;\ Client->request.post_raw_size = 0;\ Client->request.post_norm = NULL; \ } while(0); #define CLR_HEADER(Client) \ do { \ Client->request.header_raw = NULL;\ Client->request.header_raw_size = 0;\ Client->request.header_norm = NULL; \ Client->request.header_norm_size = 0 ;\ Client->request.cookie.cookie = NULL;\ Client->request.cookie.cookie_end = NULL;\ if(Client->request.cookie.next) { \ COOKIE_PTR *cookie = Client->request.cookie.next; \ do { \ Client->request.cookie.next = Client->request.cookie.next->next; \ free(cookie); \ cookie = Client->request.cookie.next; \ } while(cookie); \ }\ Client->request.cookie.next = NULL;\ Client->request.cookie_norm = NULL;\ Client->request.cookie_norm_size = 0;\ } while(0); #define CLR_METHOD(Client) \ do { \ Client->request.method_raw = NULL;\ Client->request.method_size = 0; \ Client->request.method = 0 ;\ } while(0); /* ** NAME ** StatelessInspection:: */ /** ** Find the URI and determine whether the URI needs to be normalized. ** ** This is a big step in stateless inspection, because we need to reliably ** find the URI and when possible filter out non-URIs. We do this using a ** simple state machine that is based on characters found in the data ** buffer. ** ** Another important aspect of the stateless inspection is the ability to ** track and inspect pipelined requests. It is VERY IMPORTANT to reset the ** pipeline_req pointer, since we don't memset the whole structure. This ** pointer is reset in the hi_si_session_inspection() function. Check there ** for more details. ** ** Normalization is detected when we are looking at the packet for the URI. ** We look for the following issues: ** - //// ** - /../ ** - /./ ** - non-ascii charss ** - % ** - \ ** When these things are seen we point to the first occurence in the URI, or ** where we have to start normalizing. If the URI is updated to a new ** pointer, then the normalization pointer is reset and we start over. ** Using this method should cut down the memcpy()s per URI, since most ** URIs are not normalized. ** ** If this function returns HI_NONFATAL_ERR, we return out of mode_inspection ** with an error and abort HttpInspect processing, and continue on with ** any other processing we do. The Session parameters that we use here are ** reset in the next time that we do session_inspection, so we don't do ** any initialization here. ** ** @param Session pointer to the HTTP session ** @param data pointer to the start of the packet payload ** @param dsize size of the payload ** ** @return integer ** ** @retval HI_INVALID_ARG invalid argument ** @retval HI_NONFATAL_ERR no URI detected ** @retval HI_SUCCESS URI detected and Session pointers updated */ int StatelessInspection(Packet *p, HI_SESSION *Session, HttpSessionData *hsd, int stream_ins) { HTTPINSPECT_CONF *ServerConf; HTTPINSPECT_CONF *ClientConf; HI_CLIENT *Client; URI_PTR method_ptr; URI_PTR uri_ptr; URI_PTR post_ptr; HEADER_PTR header_ptr; HTTP_CMD_CONF *CmdConf = NULL; const u_char *start; const u_char *end; const u_char *ptr, *mthd; const u_char *method_end = NULL; int method_len; int iRet=0; char sans_uri = 0; const unsigned char *data = p->data; int dsize = p->dsize; if ( ScPafEnabled() ) { if ( stream_ins && (p->packet_flags & PKT_STREAM_INSERT) ) return HI_INVALID_ARG; } ServerConf = Session->server_conf; if(!ServerConf) { return HI_INVALID_ARG; } ClientConf = Session->client_conf; if(!ClientConf) { return HI_INVALID_ARG; } Client = &Session->client; memset(&uri_ptr, 0x00, sizeof(URI_PTR)); memset(&post_ptr, 0x00, sizeof(URI_PTR)); memset(&header_ptr, 0x00, sizeof(HEADER_PTR)); memset(&method_ptr, 0x00, sizeof(URI_PTR)); /* ** We set the starting boundary depending on whether this request is ** a normal request or a pipeline request. The end boundary is always ** the same whether it is a pipeline request or other. */ if(Client->request.pipeline_req) { start = Client->request.pipeline_req; p->packet_flags |= PKT_ALLOW_MULTIPLE_DETECT; } else { start = data; } Client->request.pipeline_req = NULL; end = data + dsize; ptr = start; /* ** Apache and IIS strike again . . . Thanks Kanatoko ** - Ignore CRLFs at the beginning of the request. */ while(hi_util_in_bounds(start, end, ptr)) { if(*ptr < 0x21) { if(*ptr < 0x0E && *ptr > 0x08) { ptr++; continue; } else { if(*ptr == 0x20) { ptr++; continue; } } } break; } mthd = method_ptr.uri = ptr; while(hi_util_in_bounds(start, end, mthd)) { if (ServerConf->whitespace[*mthd] || (lookup_table[*mthd] == NextNonWhiteSpace)) { method_end = mthd++; break; } if ( !ScPafEnabled() ) { /* isascii returns non-zero if it is ascii */ if (isascii((int)*mthd) == 0) { /* Possible post data or something else strange... */ method_end = mthd++; break; } } mthd++; } if (method_end) { method_ptr.uri_end = method_end; } else { method_ptr.uri_end = end; } method_len = method_ptr.uri_end - method_ptr.uri; /* Need slightly special handling for POST requests * Since we don't normalize on the request method itself, * just do a strcmp here and skip the characters below. */ if(method_len == 4 && !strncasecmp("POST", (const char *)method_ptr.uri, 4)) { hi_stats.post++; Client->request.method = HI_POST_METHOD; } else if(method_len == 3 && !strncasecmp("GET", (const char *)method_ptr.uri, 3)) { hi_stats.get++; Client->request.method = HI_GET_METHOD; } else if(method_len > 0 && method_len <= MAX_METHOD_LEN ) { CmdConf = http_cmd_lookup_find(ServerConf->cmd_lookup, (const char *)method_ptr.uri, method_len, &iRet); if(iRet == -1 || (CmdConf == NULL)) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_UNKNOWN_METHOD)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_UNKNOWN_METHOD, NULL, NULL); } Client->request.method = HI_UNKNOWN_METHOD; } } else { if( ScPafEnabled() ) { /* Might have gotten non-ascii characters, hence no method, but if * PAF is in use, checking "!stream_ins" equates to PacketHasStartOfPDU() * so we know we're looking for a method and not guessing that we're in * the body or somewhere else because we found a non-ascii character */ if (!stream_ins && hi_eo_generate_event(Session, HI_EO_CLIENT_UNKNOWN_METHOD)) hi_eo_client_event_log(Session, HI_EO_CLIENT_UNKNOWN_METHOD, NULL, NULL); Client->request.method = HI_UNKNOWN_METHOD; } else { if (!stream_ins && hi_eo_generate_event(Session, HI_EO_CLIENT_UNKNOWN_METHOD)) hi_eo_client_event_log(Session, HI_EO_CLIENT_UNKNOWN_METHOD, NULL, NULL); sans_uri = 1; Client->request.method = HI_UNKNOWN_METHOD; } } if (!sans_uri ) { uri_ptr.uri = method_ptr.uri_end; uri_ptr.uri_end = end; /* This will set up the URI pointers - effectively extracting * the URI. */ iRet = hi_client_extract_uri( Session, ServerConf, Client, start, end, uri_ptr.uri, &uri_ptr, hsd, stream_ins); } /* Check if the URI exceeds the max header field length */ /* Only check if we succesfully observed a GET or POST method, otherwise, * this may very well be a POST body */ if(iRet == URI_END && hi_eo_generate_event(Session, ServerConf->max_hdr_len) && ((uri_ptr.uri_end - uri_ptr.uri) >= ServerConf->max_hdr_len)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_LONG_HDR, NULL, NULL); } if(iRet == URI_END && !(ServerConf->uri_only)) { Client->request.method_raw = method_ptr.uri; Client->request.method_size = method_ptr.uri_end - method_ptr.uri; ///XXX ///Copy out the header into its own buffer..., /// set ptr to end of header. // // uri_ptr.end points to end of URI & HTTP version identifier. if (hi_util_in_bounds(start, end, uri_ptr.uri_end + 1)) ptr = hi_client_extract_header(Session, ServerConf, &header_ptr, uri_ptr.uri_end+1, end, hsd, stream_ins); if (header_ptr.header.uri) { Client->request.header_raw = header_ptr.header.uri; Client->request.header_raw_size = header_ptr.header.uri_end - header_ptr.header.uri; if(!Client->request.header_raw_size) { CLR_HEADER(Client); } else { hi_stats.req_headers++; Client->request.header_norm = header_ptr.header.uri; if (header_ptr.cookie.cookie) { hi_stats.req_cookies++; Client->request.cookie.cookie = header_ptr.cookie.cookie; Client->request.cookie.cookie_end = header_ptr.cookie.cookie_end; Client->request.cookie.next = header_ptr.cookie.next; Client->request.cookie_norm = header_ptr.cookie.cookie; } else { Client->request.cookie.cookie = NULL; Client->request.cookie.cookie_end = NULL; Client->request.cookie.next = NULL; Client->request.cookie_norm = NULL; } } } else { CLR_HEADER(Client); } /* Got a Content-Length or it's a POST request which may be chunked */ if (header_ptr.content_len.cont_len_start || header_ptr.is_chunked) { /* Need to skip over header and get to the body. * The unaptly named FindPipelineReq will do that. */ ptr = FindPipelineReq(Session, uri_ptr.delimiter, end); //ptr = FindPipelineReq(Session, ptr, end); if(ptr) { post_ptr.uri = ptr; post_ptr.uri_end = end; if((POST_END == hi_client_extract_post( Session, ServerConf, ptr, end, &post_ptr, header_ptr.content_len.len, header_ptr.is_chunked, hsd ))) { hi_stats.post_params++; Client->request.post_raw = post_ptr.uri; Client->request.post_raw_size = post_ptr.uri_end - post_ptr.uri; Client->request.post_norm = post_ptr.norm; ptr = post_ptr.uri_end; } else { CLR_POST(Client); } if ( ptr < end ) Client->request.pipeline_req = ptr; if(Client->request.post_raw && (ServerConf->post_extract_size > -1)) { if(ServerConf->post_extract_size && ((int)Client->request.post_raw_size > ServerConf->post_extract_size)) { Client->request.post_raw_size = (unsigned int)ServerConf->post_extract_size; } } else { CLR_POST(Client); } } else { CLR_POST(Client); ptr = uri_ptr.delimiter; } } else { ptr = uri_ptr.delimiter; } } else { CLR_HEADER(Client); CLR_POST(Client); if (!(Client->request.method & HI_UNKNOWN_METHOD) && method_ptr.uri) { Client->request.method_raw = method_ptr.uri; Client->request.method_size = method_ptr.uri_end - method_ptr.uri; } else { CLR_METHOD(Client); return HI_NONFATAL_ERR; } ptr = uri_ptr.delimiter; } /* ** Find the next pipeline request, if one is there. If we don't find ** a pipeline request, then we return NULL here, so this is always ** set to the correct value. */ if(!ServerConf->no_pipeline) { if(post_ptr.uri) { Client->request.pipeline_req = FindPipelineReq(Session, post_ptr.delimiter, end); } else if(!Client->request.pipeline_req && uri_ptr.uri) { Client->request.pipeline_req = FindPipelineReq(Session, ptr, end); } } else { Client->request.pipeline_req = NULL; } /* ** We set the HI_CLIENT variables from the URI_PTR structure. We also ** do error checking for the values in this routine as well. */ iRet = SetClientVars(Client, &uri_ptr, dsize); if (iRet) { CLR_HEADER(Client); CLR_POST(Client); CLR_METHOD(Client); return iRet; } /* ** One last check for an oversize directory. This gets the long ** directory when there is a beginning slash and no other slashes ** until the end of the packet. ** ** We do this check after we set the variables, just in case there ** was some errors while setting the variables. This could save some ** false positives on a bad URI setting. */ if(uri_ptr.uri_end) CheckLongDir(Session, &uri_ptr, uri_ptr.uri_end); /* ** Check for absolute URI and alert for proxy comm if necessary ** ** NOTE: ** Also check ClientConf for proxy configuration so we don't ** alert on outbound requests from legitimate proxies. */ if(uri_ptr.proxy && Session->global_conf->proxy_alert && (!ServerConf->allow_proxy && !ClientConf->allow_proxy)) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_PROXY_USE)) { hi_eo_client_event_log(Session, HI_EO_CLIENT_PROXY_USE, NULL, NULL); } } return HI_SUCCESS; } int hi_client_inspection(Packet *p, void *S, HttpSessionData *hsd, int stream_ins) { HTTPINSPECT_GLOBAL_CONF *GlobalConf; HI_SESSION *Session; int iRet; if(!S || !(p->data) || (p->dsize < 1)) { return HI_INVALID_ARG; } Session = (HI_SESSION *)S; if(!Session->global_conf) { return HI_INVALID_ARG; } GlobalConf = Session->global_conf; /* ** We inspect the HTTP protocol in either stateful mode or ** stateless mode. */ if(GlobalConf->inspection_type == HI_UI_CONFIG_STATEFUL) { /* ** This is where we do stateful inspection. */ return HI_NONFATAL_ERR; } else { /* ** Otherwise we assume stateless inspection */ iRet = StatelessInspection(p, Session, hsd, stream_ins); if (iRet) { return iRet; } } return HI_SUCCESS; } /* ** NAME ** hi_client_init:: */ /** ** Initializes arrays and search algorithms depending on the type of ** inspection that we are doing. ** ** @param GlobalConf pointer to the global configuration ** ** @return integer ** ** @retval HI_SUCCESS function successful. */ int hi_client_init(HTTPINSPECT_GLOBAL_CONF *GlobalConf) { int iCtr; if(GlobalConf->inspection_type == HI_UI_CONFIG_STATEFUL) { /* ** We don't have to do anything here yet. */ } else { memset(lookup_table, 0x00, sizeof(lookup_table)); /* ** Set up the non-ASCII register for processing. */ for(iCtr = 0x80; iCtr <= 0xff; iCtr++) { lookup_table[iCtr] = SetBinaryNorm; } lookup_table[0x00] = SetBinaryNorm; lookup_table[' '] = NextNonWhiteSpace; lookup_table['\r'] = find_rfc_delimiter; lookup_table['\n'] = find_non_rfc_delimiter; /* ** ASCII encoding */ lookup_table['%'] = SetPercentNorm; /* ** Looking for multiple slashes */ lookup_table['/'] = SetSlashNorm; /* ** Looking for backslashs */ lookup_table['\\'] = SetBackSlashNorm; lookup_table['+'] = SetPlusNorm; /* ** Look up parameter field, so we don't alert on long directory ** strings, when the next slash in the parameter field. */ lookup_table['?'] = SetParamField; /* ** Look for absolute URI and proxy communication. */ lookup_table[':'] = SetProxy; } return HI_SUCCESS; } /** ** This was just an initial testing program for these functions. */ #ifdef TEST_ME #include #include #include int main(int argc, char **argv) { HTTPINSPECT_GLOBAL_CONF GlobalConf; HI_SESSION *Session; HI_SI_INPUT SiInput; int iInspectMode = 0; int iRet; char data[] = "Hdslkfjaslfkj HTTP/00000.111111"; if((iRet = hi_ui_config_init_global_conf(&GlobalConf))) { printf("** error during global init.\n"); return iRet; } if((iRet = hi_ui_config_default(&GlobalConf))) { printf("** error config default.\n"); return iRet; } hi_ui_config_print_config(&GlobalConf); if((iRet = hi_client_init(&GlobalConf))) { printf("** error client init\n"); return iRet; } SiInput.sip = inet_addr("1.1.1.1"); SiInput.sip = inet_addr("1.1.1.2"); SiInput.dport = 80; SiInput.sport = 7880; if((iRet = hi_si_session_inspection(&GlobalConf, &Session, &SiInput, &iInspectMode))) { printf("** error session inspection\n"); return iRet; } printf("** iInspectMode = %d\n", iInspectMode); if((iRet = hi_mi_mode_inspection(Session, iInspectMode, data, strlen(data)))) { printf("** error mode_inspection\n"); return iRet; } return 0; } #endif snort-2.9.6.0/src/preprocessors/HttpInspect/client/Makefile.am0000644000000000000000000000023710277202366021210 00000000000000AUTOMAKE_OPTIONS=foreign no-dependencies noinst_LIBRARIES = libhi_client.a libhi_client_a_SOURCES = \ hi_client.c \ hi_client_norm.c INCLUDES = @INCLUDES@ snort-2.9.6.0/src/preprocessors/HttpInspect/client/Makefile.in0000644000000000000000000004014712260606524021223 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/preprocessors/HttpInspect/client DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libhi_client_a_AR = $(AR) $(ARFLAGS) libhi_client_a_LIBADD = am_libhi_client_a_OBJECTS = hi_client.$(OBJEXT) \ hi_client_norm.$(OBJEXT) libhi_client_a_OBJECTS = $(am_libhi_client_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = am__depfiles_maybe = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libhi_client_a_SOURCES) DIST_SOURCES = $(libhi_client_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CCONFIGFLAGS = @CCONFIGFLAGS@ CFLAGS = @CFLAGS@ CONFIGFLAGS = @CONFIGFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ ICONFIGFLAGS = @ICONFIGFLAGS@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ RAZORBACK_CFLAGS = @RAZORBACK_CFLAGS@ RAZORBACK_LIBS = @RAZORBACK_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIGNAL_SNORT_DUMP_STATS = @SIGNAL_SNORT_DUMP_STATS@ SIGNAL_SNORT_READ_ATTR_TBL = @SIGNAL_SNORT_READ_ATTR_TBL@ SIGNAL_SNORT_RELOAD = @SIGNAL_SNORT_RELOAD@ SIGNAL_SNORT_ROTATE_STATS = @SIGNAL_SNORT_ROTATE_STATS@ STRIP = @STRIP@ VERSION = @VERSION@ XCCFLAGS = @XCCFLAGS@ YACC = @YACC@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ extra_incl = @extra_incl@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign no-dependencies noinst_LIBRARIES = libhi_client.a libhi_client_a_SOURCES = \ hi_client.c \ hi_client_norm.c all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/preprocessors/HttpInspect/client/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/preprocessors/HttpInspect/client/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libhi_client.a: $(libhi_client_a_OBJECTS) $(libhi_client_a_DEPENDENCIES) $(EXTRA_libhi_client_a_DEPENDENCIES) $(AM_V_at)-rm -f libhi_client.a $(AM_V_AR)$(libhi_client_a_AR) libhi_client.a $(libhi_client_a_OBJECTS) $(libhi_client_a_LIBADD) $(AM_V_at)$(RANLIB) libhi_client.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c .c.o: $(AM_V_CC)$(COMPILE) -c $< .c.obj: $(AM_V_CC)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: snort-2.9.6.0/src/preprocessors/HttpInspect/server/0000755000000000000000000000000012260606562017262 500000000000000snort-2.9.6.0/src/preprocessors/HttpInspect/server/hi_server_norm.c0000644000000000000000000003366112260565733022404 00000000000000/**************************************************************************** * * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. * Copyright (C) 2003-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ****************************************************************************/ /** ** @file hi_client_norm.c ** ** @author Daniel Roelker ** ** @brief HTTP client normalization routines ** ** We deal with the normalization of HTTP client requests headers and ** URI. ** ** In this file, we handle all the different HTTP request URI evasions. The ** list is: ** - ASCII decoding ** - UTF-8 decoding ** - IIS Unicode decoding ** - Directory traversals (self-referential and traversal) ** - Multiple Slashes ** - Double decoding ** - %U decoding ** - Bare Byte Unicode decoding ** ** Base 36 is deprecated and essentially a noop ** - Base36 decoding ** ** NOTES: ** - Initial development. DJR */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "hi_norm.h" #include "hi_util.h" #include "hi_return_codes.h" #include "hi_eo_log.h" #include "snort_bounds.h" #include "detection_util.h" extern int hi_split_header_cookie(HI_SESSION *, u_char *, int *, u_char *, int *, const u_char *, int , COOKIE_PTR *); int hi_server_norm(HI_SESSION *Session, HttpSessionData *hsd) { static u_char HeaderBuf[MAX_URI]; static u_char CookieBuf[MAX_URI]; static u_char RawHeaderBuf[MAX_URI]; static u_char RawCookieBuf[MAX_URI]; HI_SERVER_RESP *ServerResp; int iRet; int iRawHeaderBufSize = MAX_URI; int iRawCookieBufSize = MAX_URI; int iHeaderBufSize = MAX_URI; int iCookieBufSize = MAX_URI; uint16_t encodeType = 0; if(!Session || !Session->server_conf) { return HI_INVALID_ARG; } ServerResp = &Session->server.response; ServerResp->header_encode_type = 0; ServerResp->cookie_encode_type = 0; if (ServerResp->cookie.cookie) { /* There is an HTTP header with a cookie, look for the cookie & * separate the two buffers */ iRet = hi_split_header_cookie(Session, RawHeaderBuf, &iRawHeaderBufSize, RawCookieBuf, &iRawCookieBufSize, ServerResp->header_raw, ServerResp->header_raw_size, &ServerResp->cookie); if( iRet == HI_SUCCESS) { ServerResp->cookie.cookie = RawCookieBuf; ServerResp->cookie.cookie_end = RawCookieBuf + iRawCookieBufSize; } } else { if (ServerResp->header_raw_size) { if (ServerResp->header_raw_size > MAX_URI) { ServerResp->header_raw_size = MAX_URI; } /* Limiting to MAX_URI above should cause this to always return SAFEMEM_SUCCESS */ SafeMemcpy(RawHeaderBuf, ServerResp->header_raw, ServerResp->header_raw_size, &RawHeaderBuf[0], &RawHeaderBuf[0] + iRawHeaderBufSize); } iRawHeaderBufSize = ServerResp->header_raw_size; iRawCookieBufSize = 0; } if(ServerResp->header_norm && Session->server_conf->normalize_headers) { Session->norm_flags &= ~HI_BODY; iRet = hi_norm_uri(Session, HeaderBuf, &iHeaderBufSize, RawHeaderBuf, iRawHeaderBufSize, &encodeType); if (iRet == HI_NONFATAL_ERR) { /* There was a non-fatal problem normalizing */ ServerResp->header_norm = NULL; ServerResp->header_norm_size = 0; ServerResp->header_encode_type = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ ServerResp->header_norm = HeaderBuf; ServerResp->header_norm_size = iHeaderBufSize; ServerResp->header_encode_type = encodeType; } encodeType = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ if (iRawHeaderBufSize) { ServerResp->header_norm = RawHeaderBuf; ServerResp->header_norm_size = iRawHeaderBufSize; ServerResp->header_encode_type = 0; } } if(ServerResp->cookie.cookie && Session->server_conf->normalize_cookies) { Session->norm_flags &= ~HI_BODY; iRet = hi_norm_uri(Session, CookieBuf, &iCookieBufSize, RawCookieBuf, iRawCookieBufSize, &encodeType); if (iRet == HI_NONFATAL_ERR) { /* There was a non-fatal problem normalizing */ ServerResp->cookie_norm = NULL; ServerResp->cookie_norm_size = 0; ServerResp->cookie_encode_type = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ ServerResp->cookie_norm = CookieBuf; ServerResp->cookie_norm_size = iCookieBufSize; ServerResp->cookie_encode_type = encodeType; } encodeType = 0; } else { /* Client code is expecting these to be set to non-NULL if * normalization occurred. */ if (iRawCookieBufSize) { ServerResp->cookie_norm = RawCookieBuf; ServerResp->cookie_norm_size = iRawCookieBufSize; ServerResp->cookie_encode_type = 0; } } if (Session->server_conf->normalize_utf && (ServerResp->body_size > 0)) { int bytes_copied, result, charset; if (hsd) { charset = get_decode_utf_state_charset(&(hsd->utf_state)); if (charset == CHARSET_UNKNOWN) { /* Got a text content type but no charset. * Look for potential BOM (Byte Order Mark) */ if (ServerResp->body_size >= 4) { uint8_t size = 0; if (!memcmp(ServerResp->body, "\x00\x00\xFE\xFF", 4)) { charset = CHARSET_UTF32BE; size = 4; } else if (!memcmp(ServerResp->body, "\xFF\xFE\x00\x00", 4)) { charset = CHARSET_UTF32LE; size = 4; } else if (!memcmp(ServerResp->body, "\xFE\xFF", 2)) { charset = CHARSET_UTF16BE; size = 2; } else if (!memcmp(ServerResp->body, "\xFF\xFE", 2)) { charset = CHARSET_UTF16LE; size = 2; } else charset = CHARSET_DEFAULT; // ensure we don't try again ServerResp->body += size; ServerResp->body_size -= size; } else charset = CHARSET_DEFAULT; // ensure we don't try again set_decode_utf_state_charset(&(hsd->utf_state), charset); } /* Normalize server responses with utf-16le, utf-16be, utf-32le, or utf-32be charsets.*/ switch (charset) { case CHARSET_UTF16LE: case CHARSET_UTF16BE: case CHARSET_UTF32LE: case CHARSET_UTF32BE: result = DecodeUTF((char *)ServerResp->body, ServerResp->body_size, (char *)HttpDecodeBuf.data, sizeof(HttpDecodeBuf.data), &bytes_copied, &(hsd->utf_state)); if (result == DECODE_UTF_FAILURE) { if(hi_eo_generate_event(Session, HI_EO_SERVER_UTF_NORM_FAIL)) { hi_eo_server_event_log(Session, HI_EO_SERVER_UTF_NORM_FAIL, NULL, NULL); } } SetHttpDecode((uint16_t)bytes_copied); ServerResp->body = HttpDecodeBuf.data; ServerResp->body_size = HttpDecodeBuf.len; break; default: break; } } } if (Session->server_conf->normalize_javascript && (ServerResp->body_size > 0)) { int js_present, status, index; char *ptr, *start, *end; JSState js; js.allowed_spaces = Session->server_conf->max_js_ws; js.allowed_levels = MAX_ALLOWED_OBFUSCATION; js.alerts = 0; js_present = status = index = 0; start = (char *)ServerResp->body; ptr = start; end = start + ServerResp->body_size; while(ptr < end) { char *angle_bracket, *js_start; int type_js, bytes_copied, script_found; bytes_copied = 0; type_js = 0; hi_current_search = &hi_js_search[0]; script_found = search_api->search_instance_find(hi_javascript_search_mpse, (const char *)ptr, (end-ptr), 0 , HI_SearchStrFound); if (script_found > 0) { js_start = ptr + hi_search_info.index; angle_bracket = (char *)SnortStrnStr((const char *)(js_start), (end - js_start), ">"); if(!angle_bracket) break; if(angle_bracket > js_start) { script_found = search_api->search_instance_find(hi_htmltype_search_mpse, (const char *)js_start, (angle_bracket-js_start), 0 , HI_SearchStrFound); js_start = angle_bracket; if(script_found > 0) { switch (hi_search_info.id) { case HTML_JS: js_present = 1; type_js = 1; break; default: type_js = 0; break; } } else { //if no type or language is found we assume its a javascript js_present = 1; type_js = 1; } } //Save before the