4. Defining file check policies: what, and how, to monitor

This section explains how to specify in the configuration file, which files or directories should be monitored, and which monitoring policy should be used.

4.1. Monitoring policies

samhain offers several pre-defined monitoring policies. Each of these policies has its own section in the configuration file. Placing a file in one of these sections will select the respective policy for that file.

The available policies (section headings) are:


All modifications except access times will be reported for these files.

Checked: owner, group, permissions, file type, device number, hardlinks, links, inode, checksum, size, mtime, ctime.


Modifications of timestamps, file size, and signature will be ignored.

Checked: owner, group, permissions, file type, device number, hardlinks, links, inode.


Modifications of timestamps, and signature will be ignored. Modification of the file size will only be ignored if the file size has increased.

Checked: owner, group, permissions, file type, device number, hardlinks, links, inode, size >= previous_size, checksum(file start up to previous size) equals previous checksum.

If the size has shrunk (e.g. because of log rotation), samhain will look for a file with the same inode as before and check whether it has a size >= previous_size, and checksum(file start up to previous size) equals previous checksum. No report will be issued if this check succeeds. Thus log rotation will be handled gracefully as long as the inode is kept (i.e. the old file is moved rather than copied) and the first rotated file is not compressed (the logrotate tool can be told to compress only after the second cycle, and on Debian this seems to be standard anyway).


Only modifications of ownership, access permissions, and device number will be checked.

Checked: owner, group, permissions, file type, device number.


No modifications will be reported. However, the existence of the specified file or directory will still be checked.


All modifications, including access time, but excluding ctime, will be reported - checking atime and ctime would require to play with the system clock.

Checked: owner, group, permissions, file type, device number, hardlinks, links, inode, checksum, size, mtime, atime.


Initialized to: report all modifications.


Initialized to: report all modifications.


Initialized to: report all modifications.


Initialized to: report all modifications.


Initialized to: report all modifications.


Modifications of timestamps, size, and inode will be ignored Checksums will be verified by calling /usr/sbin/prelink --verify . This policy is intended for verification of prelinked executables/libraries and/or directories containing such files. For details and further configuration options see Section 4.8 .

Checked: owner, group, permissions, file type, device number, hardlinks, links, checksum.


Each policy can be modified in the config file section Misc with entries like RedefReadOnly= +XXX[,...] or RedefReadOnly= -XXX[,...] to add (+XXX) or remove (-XXX) a (a comma-separated list of) tests XXX, where XXX can be any of CHK (checksum), TXT (store file content in database), LNK (link), HLN (hardlink), INO (inode), USR (user), GRP (group), MTM (mtime), ATM (atime), CTM (ctime), SIZ (size), RDEV (device numbers), MOD (file mode), PRE (Linux; prelinked binary), SGROW (file size is allowed to grow), and/or AUDIT (Linux; report who changed the file)

This must come before any file policies are used in the config file.

4.2. File/directory specification

Entries for files have the following syntax:

file= /full/path/to/the/file

Entries for directories have the following syntax:

dir= [recursion depth]/full/path/to/the/directory

The specification of a (numerical) recursion depth is optional (see Section 4.5 ). (Do not put the recursion depth in brackets — they just indicate that this is an optional argument!).

Wildcard patterns ('*', '?', '[...]') as in shell globbing are supported for paths. The leading '/' is mandatory. Since version 2.7.1, it is allowed to enclose the value of the directive (i.e. the path for files, the optional recursion depth and the path for directories) within matching single or double quotes, which allows to have trailing blanks ( note: it is not neccessary to escape quotes in between - the algorithm does not scan forward to find the matching quote, rather it uses the last character). Also since version 2.7.1, C quoting style is supported ('\a' [bell], '\b' [backspace], '\f' [form feed], '\n' [newline], '\r' [carriage return], '\t' [horizontal tab], '\v' [vertical tab], '\\' [backslash], '\'' [single quote], '\"' [double quote], '\nnn' [dree digit octal value], \xNN' [two digit hexadecimal value]). Example:

	  # valid examples
	  dir = /u01/oracle/archive00
	  dir = 7/u01/oracle/archive02
	  dir = "7/u01/oracle/archive03  "
	  dir = "7/u01/oracle/archi"ve"
	  dir = /u01/oracle/archive\v04
	  dir = /u01/oracle/archive\\04
	  dir = /u01/oracle/archive\076
	  file = '/u01/oracle/archive\x0a'
	  # valid (no quote at start, thus quote at end
	  #        is considered part of filename)
	  file = /u01/oracle/archive_0"
	  #invalid (no matching quote at end)
	  file = "/u01/oracle/archive_0
	  #invalid (\03 is bad, must be 3 digits [octal]
	  #         or \x03 for hexadecimal)
	  file = /u01/oracle/archive_\03
	  #invalid (\g is undefined escape sequence)
	  file = /u01/oracle/archive_\g
[Note]Note on directories

A directory is (a) a collection of files, with (b) a directory special file where a listing of all files in the directories is kept. This directory special file will be modified in case of a file addition, removal, or renaming. Depending on the chosen policy, samhain will report on such modifications of the directory special file.

The addition and/or deletion of files from a directory modifies the directory special file (mtime/ctime). The addition/deletion of subdirectories will also modify the number of hardlinks of the directory special file. A modification of a file may modify a directory special file (mtime/ctime), if this modification is done by first creating a temporary file, followed by renaming this temporary file to the original one.

4.2.1. Rules

  1. For the file check, samhain does not follow symlinks. If the argument for a file=... directive is a symlink, then the symlink itself is checked, not the location it points to.

  2. The argument for a dir=... directive must be a directory. Using a symlink to a directory as argument is incorrect.

  3. Precedence is given to the most specific location in the filesystem regardless of the order listed in the config file. I.e.,

    • a policy for a specific file overrides the policy for its directory

    • a policy for a subdirectory overrides the policy for its parent directory

    • if a directory or file path are explicitly listed twice in two different policy sections, Samhain will print a warning and honor only the first stanza processed. "First matching rule wins." Note however that it is perfectly ok to list a directory both as file=/path and dir=/path (see next rules).

  4. Checking a directory with dir=... will check both the content of the directory as well as the directory special file itself, honoring a local and global recursion depth, giving local preference.

  5. Using a directory as argument for both a file=... and a dir=... directive will have the effect that

    • the file=... directive will override the dir=... directive for the directory special file itself,

    • while the dir=... directive remains in effect for the directory content.

  6. The presence of a file= /parent/subdir , which is more specific of a path entry than that of the parent directory in another policy section with a "deeper" recursion depth as dir= N/parent will not prevent Samhain from descending into /parent/subdir and applying the higher level directory with the "deeper" recursion policy to the contents of /parent/subdir The more-specific rule will only apply to the directory special file and does not "truncate" the higher level policy in any way.

  7. To determine if you config file syntax is working as expected, increase the verbosity of debugging when running samhain with "-t init" using "-p info" or even "-p debug".

Example 1: If you only want to check files in a directory, but not the directory inode itself, use:

	    dir = /u01/oracle/archive00
	    file = /u01/oracle/archive00
	    # Note: /u01/oracle/archive00/archive01.dbf -> archive99.dbf *should* be
	    # mounted in the DB as a read-only tablespace and should never be
	    # changed, however, the DBA thinks he's God and does not need to consult
	    # with the Admin, so he may be adding new, deleting, or renaming the
	    # DBFs using SQLPlus without consulting with the admin, so tell me about
	    # changes to the files inside that we know about at Samhain INIT but
	    # such as when he adds a file.

Example 2: If you want to monitor a directory, but not the dynamic contents inside it:

	    file = /var/spool/mqueue 
	    file = /tmp 

Example 3: If you want to monitor a directory special file, while ensuring no files within are removed but not the actual attributes of those files:

	    file = /root 

Thanks to Brian A. Seklecki for his effort to clarify these rules and provide examples.

4.3. Suppress messages about new/deleted/modified files

If you want to suppress messages about the creation of certain files (e.g. rotated log files), you can use the options IgnoreAdded=/fullpath/with_some_regex_inside and/or IgnoreMissing=/fullpath/with_some_regex_inside (to be placed in the [Misc] section of the configuration files. If you want to add more regular expressions, you can use these options multiple times. Since transient files might get modified during their lifetime, there is also the option IgnoreModified=/fullpath/with_some_regex_inside


The argument to IgnoreAdded , IgnoreMissing , and IgnoreModified must be a regular expression that matches the full path. In particular, it has to start with a forward slash.. To test your regex before putting in samhain, you do something like this:

	    # This regex matches all files added by logrotate 
	    # (e.g: messages.1 or messages.2.gz, etc.) 
	    cd /var/log 
	    for file in *; do 
	      echo $file| \
	      egrep "(cron|messages|rpmpkgs|secure|up2date|wmtp)\.[0-9](\.gz)?$"; 

Once it's work this way, you can add it to your samhainrc file, but don't forget to add the full path. e.g:

	    IgnoreAdded = your_tested_regex

This tip has been provided by jim at aegis hyphen corp dot org.


If a directory is added to [Attributes] as a file=/dir, then only the directory special file is monitored for permissions/ownership. The advantage is that additions/removals of files to that subdirectory can happen without recourse, but the integrity of that directory is defended. Assuming the administrator doesn't want to get granular level of detail.

Good for such directories as: /var/mail /var/cron/tabs /var/tmp /tmp

This tip has been provided by Brian A. Seklecki

4.4. Dynamic database update (modified/disappeared/new files)

samhain reads the file signature database at startup and creates an in-memory copy. This in-memory copy is then dynamically updated to reflect changes in the file system.

I.e. for each modified/disappeared/new file you will receive an alarm, then the in-memory copy of the file signature database is updated, and you will only receive another alarm for that file if it is modified again (or disappears/appears again).

Note that the on-disk file signature database is not updated (if you have signed it, the daemon could not do that anyway). However, as long as the machine is not rebooted, there should be no need to update the on-disk file signature database.

If files disappear after initialization, you will get an error message with the severity specified for file access errors ( except if the file is placed under the IgnoreAll policy, in which case a message of SeverityIgnoreAll— see Section 1.1 — is generated).

If new files appear in a monitored directory after initialization, you will get an error message with the severity specified for that directory's file policy ( except if the file is placed under the IgnoreAll policy, in which case a message of SeverityIgnoreAll— see Section 1.1 — is generated).

The special treatment of files under the IgnoreAll policy allows to handle cases where a file might be deleted and/or recreated by the system more or less frequently.

4.5. Recursion depth(s)

Directories can be monitored up to a maximum recursion depth of 99 (i.e. 99 levels of subdirectories. The recursion depth actually used is defined in the following order of priority:

  1. The recursion depth specified for that individual directory ( Section 4 ). As a special case, for directories with the policy IgnoreAll, the recursion depth should be set to 0, if you want to monitor (the existence of) the files within that directory, but to -1, if you do not want samhain to look into that directory.

  2. The global default recursion depth specified in the configuration file. This is done in the configuration file section Misc with the entry SetRecursionLevel= number

  3. The default recursion depth, which is zero.

4.6. Hardlink check

As of version 1.8.4, samhain will by default compare the number of hardlinks of a directory to the number of its subdirectories (including "." and ".."). Normally, these numbers should be equal. The idea here is that a (kernel) rootkit may hide a directory, but fail to "fix" the parent directory hardlink count (actually, I am not aware of any kernel rootkit that would care to fix the hardlink count of the parent directory). This is an experimental feature; if there are any problems, it can be disabled with the option UseHardlinkCheck= no in the [Misc] section of the configuration file.

Errors will be reported at the same severity as directory access errors option SeverityDirs= severity in section [EventSeverity]).

[Note]MacOS X

This feature is not supported on MacOS X (because the resource fork is implemented as an invisible directory, it modifies the parent directory hardlink count.)

4.6.1. Specify exceptions for the hardlink check

Some filesystems do not always follow the rule mentioned above (directory hardlink equals number of subdirectories). E.g. the root directory of reiserfs partitions generally seems to have two additional hardlinks. To account for such exceptions, you can specify exceptions with the option HardlinkOffset= N: /path in the [Misc] section of the configuration file. Here, N is the numerical offset (actual - expected hardlinks) for /path. For multiple exceptions, use this options multiple times (note that '/path N:/path2' would itself be a valid path, so using the option only once with multiple exceptions on the same line would be ambiguous).


Please note that samhain will not check for an exception if the standard rule (offset = 0) is true for a directory. Thus it will not warn if a directory that once was exceptional is not anymore.

4.7. Check for weird filenames

Samhain checks for weird filenames (containing control/nonprintable characters, newlines or tabs) and warns about them at a severity level that is set with SeverityNames= severity in section [EventSeverity]. The rationale is: most of the time, such names are either the result of user errors, buggy scripts, or questionable activity.

If you want to add characters to the set of 'good' ones, you can do so with the option: AddOKChars= N1, N2, ... in the [Misc] section of the configuration file. Nn should be the unsigned byte value of the character(s) in hex (leading '0x': 0xNN), octal (leading zero: 0NNN), or decimal.

[Tip]UTF-8 filenames

To specify that filenames are UTF-8 rather than ASCII, use FileNamesAreUTF8=yes . Samhain will check for invalid UTF-8 sequences, and for filenames ending with invisible characters.


This check will not be performed for files under the IgnoreAll policy. To completely disable this check, use AddOKChars=all .

4.8. Support for prelink

prelink is a tool available on modern Linux systems that can significantly reduce the startup time of applications. It does this by performing some of the work of the dynamic linker in advance. As this changes both executables and shared libraries, file integrity verification will fail unless prelink is supported, in particular as prelinking has to be redone if libraries are updated (so initializing the checksum database after prelinking may not be good enough).

The disadvantage is that prelinking modifies libraries and executables, and may need to be redone (potentially modifying all or many executables again) if a library is updated. This is a major problem for file integrity checkers.

Version 2.0 of samhain and later support prelink. To use this support, you need to place prelinked executables and libraries (or directories holding them) under the [Prelink] policy rather than under the (e.g.) [ReadOnly] policy. For all files under the [Prelink] policy, inode, size, and timestamps will be ignored (prelinking changes them). In addition, for ELF binaries under the [Prelink] policy, /usr/sbin/prelink --verify will be used to compute checksums (i.e. the checksum will be computed on the output of this command). For other files, checksums are computed as usual.


Obviously, invoking prelink results in a significant overhead, and slows down file integrity checking (tests indicate a factor of three - your mileage may vary).

[Note]Verification failures (zero checksum)

It seems that prelink --verify fails if the dependencies of a prelinked binary have changed. This results in a zero checksum, and can be fixed by re-prelinking the affected binary.

There are two configuration options in the [Misc] section that can are relevant for prelink support:

SetPrelinkPath= fullpath sets the path to the prelink executable. The default is /usr/sbin/prelink.

SetPrelinkChecksum= checksum sets the TIGER192 checksum for the prelink executable. You can compute this with samhain -H /usr/sbin/prelink (remove whitespace from the computed checksum). If the checksum is set, samhain will verify the prelink executable immediately before using it, otherwise prelink will be used without this special precaution.

4.9. SELinux attributes and Posix ACLs

[Note]Note for users of SQL database logging

You need to update the database scheme before using this feature, if you are upgrading from a version below 2.3.0. See Section 12.1 for details.

As of version 2.3, samhain supports checking and verifying of SELinux attributes and/or Posix ACLs, if the operating system supports these features. SELinux attributes are a Linux-specific feature, while Posix ACLs are supported by multiple operating systems.

These features will only get compiled if the required development environment is available on the host where samhain is compiled (e.g. on Debian Linux, packages libattr1-dev and libacl1-dev).

For backward compatibility, these features are disabled by default, even if they are compiled in. To enable them, use the configuration directives:

	  UseACLCheck = yes 
	  UseSelinuxCheck = yes

4.10. Codes in messages about reported files

As of version 1.8.2, reports about modified files include a short code in the message field to describe which properties have been modified. The codes are: 'C' for 'checksum', 'L' for (soft) 'link', 'D' for 'device number', 'I' for 'inode', 'H' for (number of) 'hardlinks', 'M' for 'mode', 'U' for 'user' (owner), 'G' for 'group' (owner), 'T' for 'time' (any), and finally 'S' for 'size'.

As an example, 'C--I----TS' would indicate that a file has been replaced by one with different checksum, inode, timestamp, and size, but (e.g.) same mode (type and access permissions) and same ownership.

4.11. Loose directory checking

If files are added to, or removed from a directory, or modified by writing a temporary file and renaming it to the original, samhain will report the changed file as well as the changed directory inode. If you regard the report on the directory inode as redundant, you can suppress it with the option: LooseDirCheck= true in the [Misc] section of the configuration file. This will cause samhain to ignore modified directory inodes if nothing else but size and timestamps has changed.

4.12. Storing the full content of a file

This is discussed in Section 20 .

4.13. Who made changes to a file?

First of all, the UID of the user who changed or created a file is not stored in the file metadata, and hence in general not available. However, some operating systems may have non-standard security enhancements to log such information.

In particular, sufficiently recent versions of the Linux kernel provide an audit subsystem that can be used to gather such information if the required userspace tools are installed and the system is properly configured.

It should be noted that the Linux audit subsystem does NOT audit every file access by default. Rather, files are only audited if a watch is placed on them. What Samhain can do is making sure that watches are indeed placed on all files of interest for you (as defined in the Samhain configuration file), and collecting relevant information in case of an event.

Samhain supports the Linux audit system insofar as it can automatically mark files of interest for logging, and automatically collects and reports the log information after a change has been detected. This implies that you don't need to maintain two separate configurations (one for Samhain and one for the audit daemon).

4.13.1. Compiling

If you compile a Samhain standalone or client executable on a Linux system, support for the Linux audit system will be compiled in automatically if the required development packages for libaudit and libauparse are present (Debian: libaudit-dev, RedHat: audit-libs-devel).

To verify that the compiled executable has audit support, use samhain --version, which should list "optionally report auditd record of changed file".

[Note]Not supported with static compiling

This extension is incompatible with static compiling, i.e. it is not available if '--enable-static' has been used for compiling.

4.13.2. Audit System Configuration

(1) If you want Samhain to report who changed a file, you need to have the Linux audit daemon (Debian: auditd, RedHat: audit) installed. You also need to have the libaudit and libauparse libraries installed.

The audit daemon must be running. You can check that with the command auditctl -s , which should show a non-zero PID for the audit daemon. If it says 'pid=0', you need to enable the audit daemon. First, make sure the daemon will autostart on boot: on RedHat/CentOS use chkconfig auditd on , on Debian/Ubuntu use update-rc.d auditd defaults . Second, start the daemon with /etc/init.d/auditd start .

(2) You are most likely interested in the auid, i.e. the audit UID which tracks the login user. This UID is only set correctly if you are using the pam_loginuid PAM module, and in a correct way even. Please read the man page for pam_loginuid carefully, and add the line

session required pam_loginuid.so

to the files /etc/pam.d/gdm, /etc/pam.d/login, /etc/pam.d/atd, /etc/pam.d/cron, /etc/pam.d/sshd.

Do NOT add this line to /etc/pam.d/su or /etc/pam.d/sudo, as that will set auid=0 and hence erase the track of the login user. If your system has a /etc/pam.d/common-session file, don't add it there if that file is included by the /etc/pam.d/su or /etc/pam.d/sudo file(s).

(3) The audit daemon enables the audit system in the kernel. Therefore all processes starting earlier than the audit daemon itself may get an auid=4294967295 (unknown). To avoid this problem, add audit=1 to the kernel boot parameters.

(4) Because Samhain needs to fetch the audit information from the audit log, this log needs to be current. I.e. in the audit deamon configuration (/etc/audit/auditd.conf on Ubuntu), the parameter 'flush' must be set to DATA or SYNC, otherwise it might happen that the log entry has not been written yet when Samhain tries to fetch it.

4.13.3. Usage

In order to activate this feature for some particular file or directory, you have to add the AUDIT flag to the policy under which you place the file or directory (see Section 4.1 ). Note that placing an audit rule on a directory will cause the whole file hierarchy under that directory to be audited. Also note that you cannot place an audit rule on the root directory itself. This is a limitation of the Linux audit system itself, not of Samhain. You have to place audit rules on the individual directories in the root directory.

	    RedefReadOnly = +AUDIT 
	    file = /etc/login.defs 
	    dir = /bin 

By default, Samhain will set the flags "wa" (write|attribute change) on which the watch will trigger. If you want to use other flags (e.g. "r" for read), you can do so with the SetAuditdFlags= r|w|x|a (i.e. any combination of these four characters, see also man 8 auditctl). Please note that order matters (as with Redef... directives), i.e. this will affect only files/directories specified afterwards in the config file.

The rules set by Samhain are flagged with samhain, i.e. you can check them with auditctl -l -k samhain, and delete them manually with auditctl -D -k samhain. See the man page of the auditctl command for further reference.

If you want to verify that the audit system works properly, you can e.g. use ausearch -k samhain to see all audit log entries generated by rules flagged with 'samhain', i.e. inserted by Samhain.

[Note]Persistance of audit rules

If Samhain runs in the foreground, it will not delete the inserted rules upon exit. This is to ensure that file changes are still audited as desired when Samhain is run only occasionally or at fixed intervals (e.g. as a cron job). If you want to delete the rules, use the command auditctl -D -k samhain .

4.14. Skip checksumming for particular files

Checksumming can put a high I/O load on a machine, and in some cases one might want to skip this for particular files. As of version 2.8.2, Samhain allows to specify certain conditions for which checksumming of a file should be skipped. These are:

match_prefix( string )

Skip checksumming if the full path of the file starts with the given string (e.g.: /home/someuser).

match_regex( regular_expression )

Skip checksumming if the full path of the file matches the given POSIX regular expression (e.g.: .*\.mpg$).

size_exceeds( bytes )

Skip checksumming if the filesize exceeds the given size (in bytes).

match_permission( octal_perm )

Skip checksumming if the file permissions exactly match the given one (as octal number, e.g. 0755 for rwxr-xr-x, or 4755 for rwsr-xr-x).

have_permission( octal_perm )

Skip checksumming if the file permissions include the given one (as octal number, e.g. 0100 for execute by owner).

match_filetype( filetype )

Skip checksumming if the file is of some particular type. See appendix for a list of supported file types.

Files that should not be checksummed are specified with SkipChecksum= list of conditions in the [Misc] section of the configuration file. The following rules apply:

  1. To negate a condition, place an exclamation mark ('!') in front of it.

  2. All conditions in the given list are and ed, i.e. checksumming for a file is skipped only if all conditions in the list are true. E.g. you can place a match_prefix(string) condition at the start of the list to avoid evaluation of the following condition(s) for files that should not be skipped.

  3. If more than one SkipChecksum=... directives are given, then they are or ed, i.e. checksumming for a file is skipped if one of the directives matches.

4.14.1. User-defined file types

It is possible to add (at most 16) user-defined filetype descriptions to the compiled-in list. This can be done with the directive FileType= description where the format of description is 8 fields, separated by ':'.

The 8 fields are offset:type:length:G1:G2:G3:Name:Teststring, which describe:

  1. An optional offset into the file, can be at most 3072-length. Counting starts at 0, thus '6' would mean the 7th byte of the file.

  2. Type is 0 for a C string, 1 if binary, i.e. if the teststring contains NULL bytes,

  3. Length should be 0 if the type is 0, othewise the length of the teststring if it is of type 1 (binary).

  4. G1, G2, G2 give the filetype as GENERIC:MORE_SPECIFIC:EXACT, e.g. IMAGE:COMPRESSED:JPG

  5. The name field is currently unused and should hold a human-understandable description, e.g. 'Jpeg image'

  6. The teststring is a string or byte pattern that is found at the given offset in files of this type. You can use quoted-printable (qp) encoding (which is often used for e-mail) for arbitrary binary patterns. A qp-encoded character (byte) consists of 3 characters: a "=" followed by the two-digit hexadecimal value if the byte. Please note that NULL bytes MUST be qp-encoded as '=00', and the equal sign ('=') MUST be qp-encoded as '=3D'.

A valid example would be FileType= 6:0:0:IMAGE:COMPRESSED:JPG:JFIF Jpeg:JFIF (this one is already compiled in). This would recognize any file with the string 'JFIF' starting at the 7th byte (counting starts at '0') as a Jpeg image.

4.15. Graceful handling of log rotation

Growing log files should be placed under the [GrowingLogFiles] policy which (as of 3.0.11+) uses the following logic to handle log rotation:

If the size has shrunk (e.g. because of log rotation), samhain will look for a file with the same inode as before and check whether it has a size >= previous_size, and checksum(file start up to previous size) equal to the previous checksum. No report will be issued if this check succeeds. Thus log rotation will be handled gracefully as long as the inode is kept (i.e. the old file is moved rather than copied) and the first rotated file is not compressed (the logrotate tool can be told to compress only after the second cycle, and on Debian this seems to be standard anyway).