Appendix C. Configuration file syntax and options

1. General

The configuration file for samhain is named samhainrc by default. Also by default, it is placed in /etc. (Name and location is configurable at compile time). The distribution package comes with a commented sample configuration file.

This section introduces the general structure of the configuration file. Details on individual entries in the configuration files are discussed in Section 4 (which files to monitor), Section 1 (what should be logged, which logging facilities should be used, and how these facilities are properly configured), and Section 11 (monitoring login/logout events).

The configuration file contains several sections, indicated by headings in square brackets(e.g. [Database] ). Sections exist to group related directives and avoid eventual name clashes among options. Any particular section may occur multiple times.

Each section may hold zero or more key= value pairs. Keys are not case sensitive, and space around the '=' is allowed, as well as before the key and after the value. More specifically: the line is processed by splitting into key and value at the first '=', trimming whitespace from the beginning and end of both key and value, and converting the key to lowercase.

Blank lines and lines starting with '#' are comments. Everything before the first section and after an [EOF] is ignored. The [EOF] end-of-file marker is optional. The file thus looks like:

	# this is a comment
	[Section heading] 
	key1=value 
	key2=value 
	[Another section]
	key3=value 
	key4=value
      

For boolean values the following are equivalent (case-insensitive): True, Yes, or 1. Likewise, the following are equivalent (case-insensitive): False, No, or 0.

In lists, values can be separated by space, tabs, or commas.

[Tip]Tip

Each section may occur multiple times.

[Note]Note

You can explicitely end the configuration file with an [EOF] (on a separate line), but this is not required, unless there is some junk beyond that may confuse the parser. A PGP signature does not qualify as 'junk' if samhain is compiled to verify the signature.

1.1. Shell expansion

As of version 2.5.3, it is possible to use shell expansion to define the value of an option. For any configuration file option written as Key = $( shell_command) , the string contained within the $() will be passed literally to the shell (by invoking /bin/sh -c shell_command ), and the first line returned by the shell - after stripping the newline char - will replace the $(..). If there is no output within 120 seconds, samhain will ignore the configuration option (and report an error).

[Note]Note

You cannot define just part of an option value this way. You need to write the shell expression such that it covers the whole option value (e.g. by including an 'echo -n foobar').

The PATH environment variable will be set to "/sbin:/bin:/usr/sbin:/usr/bin:/usr/ucb", the SHELL variable to "/bin/sh", the IFS variable to " \t\n", and the TZ variable will be copied from the startup environment. No other environment variables will be set.

In case you are unsure about the need for escaping: yes, the whole string will be passed as a single argument to the shell, like calling /bin/sh -c ' shell_command' from the shell, BUT since this is done from within a C program rather than from a shell, there are no single quotes surrounding the whole string.

In the following example, we parse the output of ifconfig to supply a list of all interfaces to the "PortCheckInterface" option.

#
# Lines broken for display purposes. Must be ONE line in config file!!!

# Linux/Solaris, FreeBSD, OpenBSD

$Linux:.*:.*
PortCheckInterface=$( /sbin/ifconfig | grep 'inet addr:' | 
    sed 's/.*r:\([0-9.]*\).*/\1 /' | tr -d '\n'; echo )
$end

# Solaris, FreeBSD, OpenBSD

$(SunOS|FreeBSD|OpenBSD):.*:.*
PortCheckInterface = $( /sbin/ifconfig -a| grep 'inet ' | 
    sed 's/.*t \([0-9.]*\) .*/\1 /' | tr -d '\n';echo )
$end
        

1.2. Conditionals

Conditional inclusion of entries for some host(s) is supported via any number of @if.. / @else / @fi directives. @if.., @else, and @fi must each be on separate lines. Configuration options in the @if.. (or the optional @else) branch will be read or ignored depending on the result of the test.

Supported tests are as follows:

hostname_matches

@if hostname_matches regex will succeed if the hostname matches the regular expression given.

system_matches

@if system_matches regex will succeed if the string sysname:release:machine — i.e. $(uname -s):$(uname -r):$uname - m) — matches the regular expression given.

file_exists

@if file_exists path will succeed if a file with the given absolute path exists. Wildcards/regular expression are not supported.

interface_exists

@if interface_exists address will succeed if a network interface with the given address exists.

command_succeeds

@if command_succeeds command will execute /bin/sh -c command and succeed if the exit status is zero. The PATH environment variable will be set to "/sbin:/bin:/usr/sbin:/usr/bin:/usr/ucb", the SHELL variable to "/bin/sh", the IFS variable to " \t\n", and the TZ variable will be copied from the startup environment. No other environment variables will be set.

You can negate a test by saying '@if not ..'. The 'not' may be replaced by a '!'. The following are all valid: '@if not file_exists /etc/motd', '@if !file_exists /etc/motd', and '@if ! file_exists /etc/motd'.

[Note]Note on backward compatibility

For backward compatibility, instead of @if hostname_matches hostname you can also say @hostname .

Likewise, instead of @if system_matches sysname:release:machine you can also say $sysname:release:machine .

Also, the old method of negating by prepending a '!' to the '@' ('$') is still supported, as well as the use of '@end' ('$end') instead of '@fi'.

	  @if hostname_matches foobar                                   
	  # only read if hostname is 'foobar'
	  @else
	  # read if hostname is NOT 'foobar'
	  @fi
          
	  @if not hostname_matches foobar                                 
	  # not read if hostname is 'foobar'    
	  @fi                                               
	  
	  @if system_matches Linux:2.6.24-21-generic:i686
	  # only read if $(uname -s):$(uname -r):$(uname -m)
	  #   matches Linux:2.6.24-21-generic:i686
	  @fi
	  
	  @if !system_matches Linux:2.6.24-21-generic:i686         
	  # not read if $(uname -s):$(uname -r):$(uname -m)
	  #   matches Linux:2.6.24-21-generic:i686
	  @fi