Audit, A policy driven security checker
a heterogeneous Environment
Security audit programs can be of great help to the
system administrator in the work of ensuring an adequate
level of security. One common problem with existing
security audit programs, however, is that they implement
default policies embedded in their code. Such embedded
policies are not always in agreement with those of the
real world (e.g., when the program complains about
/usr/spool/uucppublic being world writable).
It was therefore set as a goal to design and implement
a security auditing program which did had no hard coded
policies embedded in the program code. The result was the
security audit program called Audit , which
allows policy decisions (such as whether users should be
allowed to have private .rhosts file in their
home directory) to be made at the local site - without
requiring any program modifications. This has been
achieved by making policy- and platform-dependent
decisions in a specialized audit control language which
is used to write the control file(s).
Audit is a a program designed to assist the
system administrator in performing security audits which
check local security policies. Audit is also
designed for a heterogeneous environment, enabling new
platforms to be audited, without requiring any
modification to the audit program itself.
Audit is implemented in perl. The perl
language has the advantage of making Audit
easily portable, as most porting problems already have
been resolved in the perl interpreter. The parsing of the
audit control file(s) is implemented by recursive
descent, chosen for its simplicity and fast
implementation. Audit performs its security
audit by checking files and their attributes (file type,
permissions, size, checksum, etc). However,
Audit knows about items like home directories
and startup files and can audit them in a relevant
fashion. In addition, Audit supports auditing of
the content of a file, through an interface which enables
Audit to call an external script or program to
check the files and/or their contents.
The alpha version of Audit has been running
on several platforms (BSD, SunOS & SVr4) for some
time; a beta version is expected to be available for
distribution at the time of the conference.
This paper discusses goals for design and
implementation, as well as showing practical examples of
control files implementing different policies. The paper
also discusses how implementation and installation can be
done in order to prevent tampering by intruders to the
greatest possible extent.
One of the driving forces behind the development of
Audit was the fact that existing security
auditing programs contain embedded policies regarding
what, when, and how to audit. This complicates
modification of the security auditing program to check a
system in accordance with local policy and custom. In
addition, this approach obscures what is checked, a fact
which can make the security checker a double edged sword,
because it can lull the system administrator into a false
sense of security. While Audit cannot, and does
not claim to, fix all of the problems mentioned above, it
is an experiment of developing a highly configurable
auditing program. Before beginning development of the
current incarnation of Audit , the following
goals where set forth:
- It should be possible to make changes to the
security audit (to reflect the security policy) without
a need to change any code in the auditing program.
- The audit program should have no default policies
embedded in the code.
- The audit program should be able to audit files
relative to users home directories.
- The audit program should be able to handle
- The audit program should report errors in as secure
a manner as possible.
Many security violations in UNIX are caused by
critical files or directories having permissions flags
set incorrectly, while others are caused by faulty
content of configuration files. If these problems could
be addressed effectively, it should be possible to detect
other security problems, such as unauthorized
modification of system binaries.
Audit is primarily oriented towards auditing
file attributes for a large number of files. It can,
however, perform other kinds of checks, through call of
external scripts and programs, such as checking the
content of the password file. It was decided not to
provide this kind of audits as built-in test, partly
because of the difficulties of providing portable
solutions, and partly because of problems in providing a
good simple audit control language definitions. Instead,
a generalized interface to call specialized utilities is
provided. Example of such utilities (which are part of
the Audit distribution) are perl scripts for
checking the password and group file. External scripts
also have the advantage of extensibility.
3. Existing Practice
Several public distributable security audit program
are available. A brief overview of some of these are
Secure is a security checker written in
Bourne Shell. This shell script can be found in the
old UNIX System Security book by Wood and Kochan.
The main value of this script (in accordance with
its goal) is as a teaching device.
It is very System V rel. 2 oriented, and covers no
networking issues at all.
Setperm is also a shell script from the Wood
and Kochan book.
In addition, a similar version, written in C, can
be found on Xenix systems.
This utility can check owner, group, and
permissions of files.
It compares the actual values with a list and
reports any found differences.
Spy is an HP-UX specific security checker.
It is not publicly available; however, it was
presented at LISA III by Bruce Spence, and can be
found in the conference proceedings, with some
COPS , written by Dan Farmer, is the best
known of the publicly available security checkers.
Its greatest strength is its ability to check
users' configuration files (e.g., .cshrc) and,
through its built-in expert system, to check to see
if a user has been compromised through incorrect
permissions on the dot-files.
It greatest weakness is that many policy decisions
have been embedded in the code. It is also difficult
to change the audit to embed local requirements.
Crack (written by Alec David Muffett) is a
suite of Unix programs designed to quickly and
efficiently find easily guessable passwords in
standard crypt() encrypted Unix password files.
This program is not a audit program in the sense
of the other programs mentioned here, however it
should be part of any security sensitive system
An important goal of Audit was the capability to
support multiple platforms without modification to the
audit program itself. With the usage of audit control
files, this need has been eliminated. However, if the
audit control files need to be distributed to the hosts
being checked (using some scheme based on operating
system and hardware platform), the problems in doing so
would diminish the value in the heterogeneity on the
Unfortunately, there is currently no way to avoid the
differences between operating systems or vendors.
It has therefore been necessary to design
Audit so it can distinguish between information
related to the system currently being audited and
information related to other systems or hosts (which has
no bearing in the current audit).
The problem has been minimized through use of
conditional expressions in the audit control language and
through support of multiple audit control files.
The Audit control files can be distributed to
all hosts, independent of the underlying operation
This can be done with a program such as
rdist(1) or by read-only NFS mounts of the
Of course, if the control files are made available
through NFS mounts, great care must be taken that they
cannot be modified on the remote host.
As a minimum, the files must be located on a file
system mounted read-only on the audit master; it is
insufficient to relay on the NFS read-only mounts, as
they can be by-passed.
It is also possible to bypass the local read-only
mounts, but this requires access to the local host.
The only secure way of providing NFS mounts is to
store the control files on a disk where the read-only
mode is enforced by the hardware.
If the control files are distributed by
rdist(1) , it is wise to ensure they had not
been modified (this too can be done with rdist
), prior to starting the audit.
In either case, it is a good idea to keep the audit
master host as secure as possible, i.e., by restricted
access, both across the network and physically.
In addition, it is necessary to verify both programs
and control files against copies kept on off-site
As for any audit program, it is important to remember
that if an intruder is able to get to the program and
modify it, the audit it performs is no longer useful.
5. Policy Issues
As previously mentioned, the current available security
auditing programs do not lend themselves very well to
individual site policies.
One of the major goals of Audit was to
attempt to avoid such issues. Some of the ways this has
influenced the design of Audit are:
If a given file is not be allowed on the system,
these audit programs has no way of perform the
One good example of such policy decisions is to
decide whether users are allowed to keep their own
.rhosts file. As this file overrides the
content of the system-wide configuration in
/etc/hosts.equiv , the content of such files
can nullify the security policies implemented in the
Similar considerations can be made for the users
.forward file, which some sites disallow, to
ensure no mail is automatically forwarded out from
Audit has a built-in mechanism to allow
the system administrator to specify files which are
not allowed on the system, either by a full
path name or relative to the users' home
In a similar manner, a file can be
required to exist on the system (this is in
fact the default) or can specified as being
- Often it is not necessary to specify exact
permission for a file. For example, it is common among
system administrators to state that a file needs a
permission mode of 755 or less, meaning that a
permission mode of 751 or 511 is equally acceptable to
a permissions of 755 (here assuming the file is a
binary and not a shell script). Therefore,
Audit allows a permission range to be
specified wherever a single permission normally would
- Certain systems (a gateway, for example) will have
different (and likely more stringent) security
requirements than many other systems on the site. The
design of Audit therefore allows
specifications which state exceptions to the general
6. Audit Methodology
In UNIX, many security problems are caused by files or
directories with incorrect permissions. Audit
has been primarily been designed to detect this kind of
security problems. Audit is therefore able to
track a large number of file attributes, such as file
checksum, file size, inode number and hard links, in
addition to more traditional audited file attributes,
like owner, group and access permissions. It provides an
effective tool to detect unauthorized system
modifications, such as system binaries, modified without
Audit allows, for any given file or
directory, the system administrator to check for any of
the following values:
Most of these values are obtained with the perl
stat() function call. Whether the block size
checks is supported is dependent on the UNIX system
version. Where perl stat() function does not
return a usable value, no check will be performed. If an
unexpected value is found, an error message will be
Most sites will have no need for auditing all these
file attributes. In fact, some of them will be so
cumbersome to use (such as inode numbers) that they will
likely be different between otherwise identical systems.
However, checking such values is useful when a in-depth
security audit is required. It was therefore decided to
include all file attributes (with the exception of time
of last access, which makes no sense to include), in
order to meet the criteria of no embedded policies in the
If file attributes such as inode number, time of last
modification, and time of last status change are
verified, in addition to the usual checksum, owner,
group, and access permissions, it becomes very difficult
to make any modification to such files without it being
detected next time the audit program is executed. On
systems with requirements of high security, the
additional work required creating the audit control files
can be justified by the added safety.
However, to avoid a requirement of all sites to audit
all of these items, Audit uses default values
for each file. The default is initially set to `no
auditing' ( -no-audit ), but this default can be
set to any desired value, including a value called
error , which alway will generate an error
messages when checked.
Values are assigned for each attribute on a file by
file basis, allowing different attributes to be set for
different files. If a file attribute for a given file is
changed, a warning messages will be generated unless the
old value is no-audit or error .
It is also very useful to be able to specify whether a
file is required to be on the system. In Audit
it is possible to specify a file as:
The deny attribute is useful for enforcing
policies to not use certain files, such as
.rhosts , as well as a method to discover files
placed on the system by an intruder. Typical examples of
names used by system crackers to hide hide files, are
``.. '' (dot-dot-space) and ``...'' (dot-dot-dot).
- require If the specified file is not found
on the system, Audit issuing a warning.
- allow Presence of the file is optional;
however, if found, it must adhere to all other required
- deny The file must not be found
on the system.
It is possible to reduce the member of entries in the
audit control files, by using regular expressions in the
file path names. If this is done, one entry can cover a
large number of files with the same attributes, such as
owner, group and access permissions. Using this method it
is not be possible to use checksums or other attributes
which differ between files.
Home Directory Auditing
A large number of security problems are represented by
the dot-files in the users' home directories. Such files
can, in some cases, directly harm the security of the
system (.rhosts in specific), or more indirectly by being
writable by others.
It is possible to use the same method as described
above to audit such files, by use of regular expressions
in the path names. However, this method would be
cumbersome and error prone, especially as the directory
character (``/'') cannot be matched by any regular
expression. Instead, Audit supports auditing of
files with path-names relative to the users' home
This allows Audit to audit a specific file in
all users' home directories, without the system
administrator having to specify the path to those homes
(this information will be taken directly from the
password file). The same file attributes can be audited,
as with the file audit described above.
File Content Auditing
Audit is not capable of performing file content
auditing directly. However, such auditing can still be
achieved, by calling external utilities, which currently
exist for auditing the following files:
- passwd This check provides a way to check
most properties of the password file, including
verification of existence of a password on all
accounts. However, it does not include checking of the
quality of the passwords. The quality of the passwords
can be better be ensured through use of a pro-active
password checker, such as passwd+ (Matthew Bishop,
A Proactive Password Checker ) or through use
of password cracker, such as Crack.
- group Audit of the group file. At this
time, the only verification is the existence of a
non-password (a string less than 13 characters) in the
- shadow Audit of the shadow file.
Currently, only the password field in the shadow file
is checked and it is checked only for existence of a
password on all accounts.
- .rhosts This script checks that the file
does not contain a plus sign and that all other entries
consists of a host name, followed by a user name (i.e.,
only a host name will be considered a security breach,
Audit provides no facilities for events
checking. However, a separate program which checks last
login time of users is provided. It is capable of
flagging accounts which have not been used for a long
time and accounts where a login is not expected but which
have been used reasonably.
7. Audit Control Language
The audit process is determined by the audit control
language. The use of a control language is inspired by
setperm utility, however, the audit control
language for Audit is much richer. This is
necessary to achieve the required functionality.
The following is an overview of this language.
A complete syntax specification of the Audit
control language can be found in appendix A.
The audit control language consists of two major
parts, the definition statements and the audit control
statements. Each statement can be preceded by a boolean
conditional clause. The statements will only be effective
if the conditional clause evaluates to true.
The following definition statements are available:
The audit statements specify which path names must be
- default Defines alternate default value
for any file attribute.
- define Defines names for string
- program Definition of an external
- read Reads a control file.
- set Assigns values to variables
- file Specify expected file attributes for
a file. The path name is relative to root (``/'').
- home Specify expected file attributes for
a file. The path name is relative to the users home
- request Request to execute a program. No
path name associated with the request. These statements
are all described in some detail below.
The Default Statement
The default statement is used when it is
necessary to define alternate default value for one or
more file attribute. The initial default for all file
attributes are no auditing ( no-audit ).
The default statement can also be used to
substitute the string values for no-audit and
error , if for example audit is used at
a site where a user name is error.
The Define Statement
The define statement allows definition of named
strings, very similar to the C pre-processor's #define.
However, at least in the current implementation,
expansion of defines is done by the lexical scanner and
not by a separate pre-processor.
Audit requires the name of the string to be
in all upper case. This is consistent with common
practice in C and enables a significant speed-up, as only
all upper case lexical symbols must be looked up in the
table of defined strings. An example of a defined
where the defined string then can be used as a shorthand
alter in the control file.
define WHEEL wheel,other
The Program Statement
The program statement provides a way to define
an external program, which later will be called by
Audit . Only programs which are defined in this
manner can be called.
The program statement provides the system
administrator with a method to specify which file
attributes must be checked prior to the use of the
program sum /usr/bin/sum;
It is not possible to use a program without first
defining it in this manner. This helps to ensure programs
which are executed from Audit have the expected
program arch /usr/bin/local/arch uid=bin gid=wheel,other;
Audit verifies a program's attributes each
time it is called. While this increases the execution
time, it also assures that the external program satisfies
all the criteria specified in the program
statement, even if called at a much later time in the
auditing sequence. In most cases it is sufficiently to
execute a program once, and assign it to a variable.
The checksum program is treated a bit differently, as
it is called repeatedly. In addition, it would create an
infinitive checking loop, if it was required to check its
own checksum. Therefore, the checksum program (whose
defined name is required to be sum ) is verified
as its expected file attribute values are defined. Later,
the ctime , mtime , and size
attributes are checked at random intervals, to ensure
they have not been altered since the start of the
The Read Statement
To avoid that all audit control information would be
required to be kept in a single file, Audit
provides a read command. This command will cause the
specified file to be read before continuing processing
the current file.
The read statement can be used recursively.
if ($OS=bsdi) read audit.bsdi
uid=root gid=wheel size=9673;
The Set Statement
It is possible to set variables, which later can be used
in, for example, conditional clauses. A variable can
either be set to a string \f(CR
or, more usefully, can be set to the return value of an
if ( $Arch=386 && $Ostype=BSDI ) set Name bsdi/386;
The latter example executes the program defined in a
previous program statement as arch and
places the standard output in the variable named
Arch . It is then possible to use this in later
conditional clauses, such as:
set Arch exec arch;
or in an exec clause, such as
if ( $Arch = sun3 ) file /somefile size=32456;
file /etc/syslog.conf uid=root gid=wheel;
file /etc/syslog.conf exec chksyslog $Arch;
The File Statement
The file statement is used for the main audit control
specifications. Each path name which should be checked
require sa definition using this statement. A full path
name is required as there are no default directory path
This statement causes the password file to be checked to
ensure it has the expected UID, GID and permissions set.
Any discrepancies will be reported by audit.
file /etc/passwd uid=root gid=wheel,other perm=600;
It is possible to audit all of the file attributes in
this manner. In addition, an external program can be
called to audit the content of the file. Assuming the
file /usr/audit/bin/pwchk is a script which will check
the password file for, e.g., missing passwords, the
following definition would ensure this check would be
Audit is completing the parsing of the audit
control file(s), before it is starting the audit. It is
therefore possible to split the audit definitions,
without having the file checked multiple times.
program /usr/audit/bin/pwchk uid=root gid=wheel,other;
file /etc/passwd uid=root gid=wheel,other perm=600;
file /etc/passwd exec pwchk;
During the parsing of a file statement, the variable
$file is set to the full path name of the file.
This can be used to give the path-name as a parameter to
an external program.
It is possible to use regular expressions in the path
name to keep the audit control file small. Regular
expressions are discussed later.
The Home Statement
The home statement works as the file statement,
with the difference that the path names specified are
relative to the users' home directory.
A statement like \f(CR
will be expended to the equivalent of one file statement
with the full path-name for ~/.cshrc for each user found
in the password file.
home \.cshrc perm=640,400;
To simplify the specification, two variables (in
addition to $file ) are automatically set by
These are $uid , which will contain the name
of the current user, and $gid , which will
contain the name of the user's main group ID (the one
used in the password files fourth field). \f(CR
As the audit rules do not necessarily have to be the same
for all users, there are an except and a
for clause, which modifies the scope of the
home \.cshrc uid=$uid gid=$gid perm640,400;
The except clause enables the system
administrator to provide an exception list of users and
groups, for which the statement should not have any
In a similar manner, the for clause can be used
to target only specific users:
home \.cshrc required except user=sue,paul
uid=$uid gid=$gid perm640,400;
home .profile required for user=sue,paul
uid=$uid gid=$gid perm640,400;
The Request Statement
The request statement provides an interface to call
external programs without their being associated with the
audit of a specific file. An example of the use of a
request statement: \f(CR
In order to support generalizations, regular expressions
are allowed in path names. This can, for example, be used
to help keep the size of the control file down in size.
For example, in the /usr/lib directory, instead of
listing all the library files individually, one entry in
the audit control file can be used to audit them all:
Such an entry will, of course, not allow the checking of
attributes which are different, such as size or checksum.
file /usr/lib/.*\\.a uid=bin gid=bin perm=444;
When the Audit parser encounters a regular
expression in the control file, it will expand it to a
list of full path names, which match the path-name and
create an entry for each path name in its internal
Any file attributes which has been assigned where the
path name has been an regular expression will be
permitted to be over-written by a new value.
However, a file attribute value which has been
assigned by a statement where the path-name did not
contain any regular expression, will not be overwritten
If this is attempted by a statement with a path name
which are a regular expression, that assignment will be
However, if the second statement also had a full path
name, Audit would allow the assignment, but
would issue a warning.
This strategy gives the system administrator some
freedom from the sequence in which statement are written,
be identical to:
file /etc/.* uid=bin gid=bin;
file /etc/passwd uid=root gid=wheel,other;
This can also be used to ensure that no file is added to
a directory. If all files in the directory are defined
with explicit path names and also explicitly set to
required or optional , an entry like:
file /etc/passwd uid=root gid=wheel,other;
file /etc/.* uid=bin gid=bin;
will flag any new file added to the directory. However,
in general, using the count file attribute is
probably a better way to achieve this:
file /usr/lib/.* denied
The regular expressions used in the path names have the
same syntax as regular expression in perl (as they are
passed to, and evaluated by the perl interpreter). This,
however, has some side effects in how path names must be
specified in the audit control file.
file /usr/lib count=42;
The dot ('.') is special to regular expression and is
also commonly used in file names.
Because of this, any dot in a file name must be
escaped in order to ensure it is not matched against
Therefore, a file like the /etc/rc.local must
be specified as /etc/rc\.local , and the
.rhosts file as \.rhosts
The slash ('/') is another special character, both to
regular expressions and UNIX path names. This character
is special to the UNIX kernel and is treated likewise by
Audit . Therefore, no regular expression will be
allowed to stretch across directory boundaries. For
example, the path names /lib/.*\.a will match
any library file in /lib , but will not match
any in /usr/lib . This not only has simplified
the implementation of Audit , it also resembles
the traditional usage of regular expressions in the
shell, which seems desirable.
The above will work because a requirement set by a
regular expression cannot override a request set with an
explicit path name. Audit is keeping track of
each file attribute, whether the request specifying it
was done by a regular expression, or with a explicit path
name. The latter kind of requests will always be allowed
to override the first.
Accumulative Usage of Statements
Audit uses an accumulative definition scheme.
Any file attribute for a given file which has not been
previously defined, can be defined at any time.
Therefore, the statement:
can be written as
file /vmunix required uid=root gid=wheel perm=755 ;
While this in itself is not very helpful, it makes a
difference as soon as system specific information is
added. If the kernel was to be checked for size and
checksum as well as the owner, group and permissions from
above, the specification could look like this:
file /vmunix required;
file /vmunix uid=root;
file /vmunix gid=wheel;
file /vmunix perm=755;
Still, if a large number of such variants is required, it
will make the audit control file very large and difficult
to maintain. Audit therefore has a read
command, which directs the audit program to read the
specified file before continuing (this function is
file /.*unix required uid=root gid=other,wheel perm=755;
if ($OS=bsdi) file /vmunix sum="29875 496";
if ($OS=svr4) file /vmunix sum="05104 1435";
if ($OS=mach) file /unix sum="73846 657";
if ($OS=sunos) file /vmunix sum="32251 891";
It is therefore possible to split all audit control,
specific to a certain operating system, vendor, or even
host, onto a separate audit control file, which only will
be read if the relevant for the machine currently being
An example of the read command is shown below:
if ($OS=mach) read audit.mach;
if ($OS=bsdi) read audit.bsdi;
if ($OS=svr4) read audit.svr4;
if ($OS=sunos) read audit.sunos;
8. Error Handling
One of the concerns in the design of the Audit
program, where how to report any inconsistencies found
during the audit. It is necessary to choose a mechanism
which is difficult to spoof (i.e., writing to a local
file would be of less use than sending the reports
directly to a central location). It is also necessary to
ensure the amount of auditing information which is sent
to the system administrator is as minimal as possible. It
is a common problem with many existing audit style
programs that way too much information is sent to the
person who is supposed to review this information. If too
much output is generated to state that the situation is
essentially normal, then any possible information about
an abnormal situation is bound to disappear in the
On the other hand, it is also necessary to send
information that the audit has been performed and went
OK. It was therefore early on decided to use
syslog for error reporting. It is possible to
spoof this approach, by modifying the
syslog.conf file, but if this has happened, the
system is already penetrated and the audit is not of much
use. In addition, it is possible to use programs such as
rdist or fdist (Linda Bissum and Paul
M. Moriarty; Fdist: A Domain Based File Distribution
System for a Heterogeneous Environment , USENIX LISA V
Proceedings, 1991) to ensure the file are correct.
It is the intention to write a filtering program to
intercept incoming messages from Audit on the
central host and send information about such problems by
e-mail to interested parties (this program will be part
of the beta release).
9. Audit Control Samples
Below is a number of small audit control samples. Neither
of these is in any form a complete audit control file.
Instead of showing such a large file, it is rather the
intention to highlight some of the possible uses of the
First a minimum audit control file:
This file is so simple, that its practical value is
doubtful. However, with the addition of an explicit list
of all set user ID and set group ID files it is becoming
closer to something real. Below is shown just a few such
file / count=16 perm=755;
file / uid=root gid=wheel perm=755;
file /tmp perm=755 uid=root gid=wheel perm=777;
file /usr/tmp perm=755 uid=root gid=wheel perm=777;
file /usr/tmp type=dir perm=777;
perm=755 uid=uucp gid=uucp perm=777;
file /etc/.* uid=root,bin perm=755,111;
file /etc count=53 uid=root gid=wheel perm=755;
file /etc/passwd perm=644;
file /etc/group perm=644;
file /etc/phones uid=bin gid=bin;
file /bin count=34 id=root perm=755;
file /bin/.* uid=root perm=755;
file /usr count=29 uid=root perm=755;
file /usr/bin count=216 uid=root perm=755;
file /usr/bin/.* uid=root perm=755,111;
The real definition will of cause need to contain a
definition for all SUID/SGID files, as they otherwise
will be flagged as a security breach.
file /bin/ps uid=bin gid=kmem perm=4555;
file /bin/rpc uid=root gid=bin perm=4555;
file /bin/rsh uid=root gid=bin perm=4555;
Setting the default for some of the more interesting
file attributes to something other than `no check' can be
helpful to discover audit control errors. \f(CR
Using these defaults, any file entered into the
Audit table, will be required to specify owner,
group, and permissions. Any other of the file attributes
could be set in a similar fashion.
default uid=error gid=error perm=error;
In order to ensure a high quality audit, all files in
the important directories, such as /, /etc, /dev,
/bin , and /usr/bin all must be placed in
the the audit control file. However, such entries are
straight forward. Audit entries which are in regard to
the users home directory is much more interesting, and
the area, where big differences between sites are to be
expected, as such entries are subject to local security
One such policy issue is whether the users are allowed
to have their private .rhosts file. A strong
case can be made of technical reasons why users should
not be allowed to have their own .rhosts file
(with exceptions of special cases, such as root). However
it has been my experience that, in the name of
convenience, many sites actually allow their users to
create and use private .rhosts files in spite of
the security problems this can create for the responsible
system administrator. Later the sites chose the a
different strategy, allowing the users to create
.rhosts files but where the content of those
files is monitored. Audit has been designed to
be able to provide audit capabilities for all of those
strategies. However the third solution, checking the
content of the file, is very likely to be site dependent.
Audit therefore only provides the necessary
mechanism for that check, by calling an external program
to do the required auditing. Below is first a possible
audit specification entry which reports any
.rhosts file (with the exception of the users
root and operator:
On a site where the users were allowed to create the
.rhosts file, the audit entry could look like
home \e\.rhosts deny except user=root,backup:
home \e\.rhosts require for user=root,backup
uid=$uid gid=$gid perm=400,600;
This would at least notify the system administrator of
such files with inadequate permissions or ownership.
home \e\.rhosts allow;
home \e\.rhosts type=file uid=$uid gid=$gid perm=400,600;
Alternatively, the .rhosts file could be
allowed but would be required to be examined by an
external program, to ensure its content would not violate
local policy. The home statement for this would
This statement would result in any .rhosts file
found in any users directory would be checked by the
program hostchk .
home \.rhosts allow;
home \.rhosts uid=$uid gid=$gid perm=400,600;
home \.rhosts exec hostchk $file;
Normally Audit does not make any changes to
the the host it is auditing. This is, in most cases, a
wise strategy. However, there is nothing which prevents a
system administrator to create a shell script,
setfile , with the following content:
and then making the following audit control statements:
chown $1 $1
chgrp $2 $3
chmod $4 $1
This would set the desired UID, GID and permissions on
all rhosts files on the system. How well this
would be received by the user community is a question of
local polices and customs.
program\ setfile=/usr/audit/bin/setfile\ uid=root\ gid=wheel;
home \e\.rhosts allow exec setfile $file $uid $gid 600;
Another use is to ensure that specific users such as
uucp and ftp do not have a
.forward file, as this in some case can be used
by an intruder:
This will ensure the system administrator will be
notified if such files should be created. In a similar
fashion Audit can look for files with names
typically used by a cracker:
home \e.forward deny for user=uucp,ftp;
This will monitor for the famous dot-dot-space
and dot-dot-dot files, however, only in the
users home directories.
home \.\.\b deny
home \.\.\. deny
Finally, some other examples of possible statements
for the users home directories are:
home \.forward allow;
home \.forward uid=$uid gid=$gid perm=400,600 exec;
home \.forward chkforward $file;
home \.cshrc require;
home \.cshrc uid=$uid gid=$gid perm=400,600;
home \.login require;
home \.login uid=$uid gid=$gid perm=400,600;
home \.profile require;
home \.profile uid=$uid gid=$gid perm=400,600;
home \.mailrc allow uid=$uid gid=$gid perm=400,600;
home \.newsrc allow uid=$uid gid=$gid perm=400,600;
home \.elm allow uid=$uid gid=$gid perm=500,700;
The most interesting aspects of Audit is its
usage, however a few points should be made about its
The interpretation of the audit control file(s) is
done by a recursive descent parser. While this approach
is slower and is not very good at recovery after syntax
errors, compared to many other parsing strategies, it is
very fast to implement from the Bacchus\-Naur Form, and
in addition, its lack of complex data structures is
easier handle in perl.
All specifications from the audit control file(s) are
placed into one internal table. Any path name which
contains a regular expression (implicit path names) will
been expanded prior to being entered into the table.
For each file, there are two entries for each
attribute. The first is used to hold the value and the
second is used for showing whether the value has bee
assigned an implicit path name or one which had no
regular expressions (explicit path name) Any file
attribute can be assigned new values as long as implicit
path name is used. When an explicit path name has been
used for a file attribute, any subsequent assignment with
implicit path names will be silently ignored. If the path
name is explicit, Audit will generate a
Any audit specification which is specified by the
home statement will be expanded to one file
entry for each user in the password file (unless modified
by the except or for clause).
These entries are placed in the same table, as the
entries specified by the file statement.
All such entries will be explicit, unless a regular
expression has been used in specifying the path name
relative to the users' home directories.
After all audit control files have been read and all
entries been placed into the central table, the audit
During this part of the process, Audit will,
for each file, compare the value of the file attributes
in the table with the ones kept by the actual file.
File attribute entries which has the value
no-audit will not be verified.
File attribute entries which has the value
error will always generate an error message.
An earlier version of Audit used find2perl to
scan all the file systems instead of just checking the
file entries contained in the table. Not only was this a
violation of of the goal of no default polices hard-coded
in the software (NFS mounted file systems was not
checked), it also made Audit take an unnecessary
long time to complete on a large file server. However,
because of this change it is no longer possible to scan
the file systems for certain files, such as device files
outside of the /dev directory.
All error reporting is done through syslog .
All calls to syslog are centralized though one
subroutine call, making it possible to replace only this
routine if another strategy for error reporting should be
11. Future Development
While Audit has been used for some time, there
are still a number of improvements which must be
implemented. Some of these are currently being worked on
and will be part of the beta release. Other improvements
would be nice, but are not scheduled at this time.
It is therefore necessary to provide other means for
- A very recent change was to use the internal file
table for for file lookup.
- Previous to that time, a find like scan of all the
mounted file systems (using perl2find) was used.
- This change gave a significant speed improvement,
but a side effect of this was that it was no longer are
possible to look for, e.g., devices files which are
placed outside the device directory.
A new audit statement, scan , is planned for
It syntax has not yet been finalized; however, it is
the goal to combine the file attribute list from the
file and home statements, with
capabilities such as found in the find(1)
It is also a goal that only one scan of the file
systems shall be done, independent of the number of
scan statements found in the audit control
When this project was started several years ago, it was
based in the frustration of Secure being
incomplete. The goal was to build a security audit
program which was highly configurable. This has been
achieved at the cost of having a configuration which can
be complex. However, if the USENET distribution of
audit will contain audit control files for a
number of systems, this problem will have been reduced.
In my experience from using audit and its
various predecessors, it is worthwhile to take the time
required to configure this program.
The final Audit will eventually be posted to
USENET. However, the beta release will only be made
available on a limited basis, preferable to larger,
Thanks Larry Wall for the creation of Perl. Without Perl,
this project would probably never have been completed.
Thanks to Rob Kolstad for proof reading this
Bacchus-Naur Form for Audit Control Language
The complete syntax for the audit control language is
audit-control ::= <sentence> [ <audit-control> ]
sentence ::= [ <cond> ] <command> ";"
cond ::= "if" "(" <expr> [ && <expr> ] ")"
expr ::= <variable> "=" <reg-exp>
command ::= <specify> | <audit>
specify ::= <default> | <define> | <program> | <read> | <set>
audit ::= <check> | <file> | <home> | <request> | <scan>
default ::= "default" <default-list>
default-list ::= <set-default> | <attr-list>
set-default ::= <name> "=" <string>
name ::= "no-audit" | "error"
define ::= "define" <name> <value>
name ::= <upper-case-string>
value ::= <string> [<string> .. ]
program ::= "program" <path> [ <attr-list> ] [ <exec> ]
read ::= "read" <file> [ <attr-list> ]
set ::= "set" <varname> <value>
value ::= <string> | <exec>
file ::= "file" <path-name> [ <attr-list> ] [ <exec> ]
home ::= "home" <path-name> [<execpt>] [<file-attr>] [<exec>]
except ::= "execpt" <expt-list> [ <except-List> ... ]
expt-list := <uid-list> | <gid-list>
exec ::= "exec" <program> <parm-list>
attr-list ::= <fileattr> [<attr-list>]
fileattr ::= <count> | <sum> | <uid-list> | <gid-list> |
<perm> | <atime> | <mtime> | <ctime> |
<links> | <size> | <inode> | <dev> |
<rdev> | <blksize> | <blocks> | <filetype>
count ::= "count" "=" <integer>
sum ::= "sum" "=" ( <string> | "none" )
uid ::= "uid" "=" <id-list>
gid ::= "gid" "=" <id-list>
perm ::= "perm" "=" <perm-value> ["," <perm-value>]
atime ::= "atime" "=" <file-date>
mtime ::= "mtime" "=" <file-date>
ctime ::= "ctime" "=" <file-date>
links ::= "links" "=" <integer>
dev ::= "dev" = <integer>
size ::= "rdev" = <integer>
size ::= "blksize" = <integer>
size ::= "blocks" = <integer>
size ::= "size" "=" <integer>
inode ::= "inode" "=" <integer>
filetype ::= "type" "=" <type>
uid-list ::= "uid" "=" <id-list>
gid-list ::= "gid" "=" <id-list>
id-list ::= <id> [ "," <id-list> ]
id ::= <string> | <integer>
file-date ::= <integer> | <ascii-date>
ascii-date ::= <year> <month> <day> <hour> ":" <minutes> ":" <sec>
type ::= "file" | "dir" | "dev" | "bdev" | "cdev" |
"symlink" | "pipe" | "special"
UNIX System Security by Wood, Patrick H., and
Stephen G. Kochan. Hayden Books, 1986
Bruce Spence, Spy: A UNIX File System Security
Monitor , USENIX LISA III Workshop Proceedings,