aide.conf - The configuration file for Advanced Intrusion
Detection Environment
aide.conf is the configuration file for Advanced Intrusion
Detection Environment. aide.conf contains the runtime configuration
aide uses to initialize or check the AIDE database.
aide.conf is case-sensitive. Leading and trailing white spaces are
ignored. Each config lines must end with new line.
AIDE uses the backslash character (\) as escape character
for ' ' (space), '@' and '\' (backslash) (e.g. '\ ' or '\@'). To literally
match a '\' in a file path with a regular expression you have to
escape the backslash twice (i.e. '\\\\').
There are three types of lines in aide.conf. First there
are the configuration options which are used to set configuration parameters
and define groups. Second, there are (restricted) rules that are used to
indicate which files are added to the database. Third, macro lines define or
undefine variables within the config file. Lines beginning with # are
ignored as comments.
These lines have the format parameter=value. See URLS for a list
of valid urls.
- database_in
(type: URL, default: see --version output, added in AIDE
v0.17)
- database (DEPRECATED
since AIDE v0.17, will be removed in AIDE v0.19)
- The url from which database is read. There can only be one of these lines.
If there are multiple database lines then the first is used.
Examples:
database_in=file:/var/lib/aide/aide.db
Read database locally from
/var/lib/aide/aide.db.
database_in=stdin
Read database from stdin.
database_in=https://example.com/aide.db
Read database remotely from
https://example.com/aide.db.
- database_out
(type: URL, default: see --version output)
- The url to which the new database is written to. There can only be one of
these lines. If there are multiple database_out lines then the first is
used.
- database_new
(type: URL, default: <none>)
- The url from which the other database for --compare is read.
- database_attrs
(type: attribute expression, default: H, added in AIDE
v0.16)
- The attributes of the (uncompressed) database files which are to be added
to the reports in report level >= database_attributes . Only
checksum attributes are supported. To disable set database_attrs to
'E'.
- database_add_metadata
(type: bool, default: true, added in AIDE v0.16)
- Whether to add the AIDE version and the time of database generation as
comments to the database file or not. This option may be set to false by
default in a future release.
- log_level (type: log
level, default: warning, added in AIDE v0.17)
- The log level to use. Log messages are written to stderr. If there
are multiple log_level lines then the first one is used. The
--log-level or -L command line option overwrites this option.
The following log levels are available:
error: show unrecoverable issues that have to be
handled by the user. Errors are fatal to the AIDE process.
warning: additionally show recoverable issues that most
likely lead to unexpected behaviour and should be handled by the user
notice: additionally show recoverable issues that sometimes
lead to unexpected behaviour and might be handled by the user.
info: additionally show informational messages
rule: additionally show messages to help to debug the path
rule matching
compare: additionally show messages to help to debug file
comparison and (special) attribute handling
config: additionally show messages to help to debug config
and rule parsing
debug: additionally show messages that are useful to debug
the application (very verbose)
thread: additionally show messages about thread processing
(e.g. broadcast events)
trace: detailed information about the flow of the
application (e.g. in-loop logging) (even more verbose)
- verbose (type: number,
range: 0 - 255, default: 5, REMOVED in AIDE v0.17)
- Removed, use log_level and report_level options
instead.
- gzip_dbout (type:
bool, default: false)
- Whether the output to the database is gzipped or not. This option is
available only if zlib support is compiled in.
- root_prefix
(type: path, default: <empty>, added in AIDE v0.16)
- The prefix to strip from each file name in the file system before applying
the rules and writing to database. AIDE removes a trailing slash from the
prefix. If there are multiple root_prefix lines then the first one is
used. This option has no effect in compare mode.
- acl_no_symlink_follow
(type: bool, default: false)
- Whether to check ACLs for symlinks or not. This option is available only
if acl support is compiled in.
- warn_dead_symlinks
(type: path, default: false)
- Whether to warn about dead symlinks or not.
- config_version
(type: string, default: <empty>)
- The value of config_version is printed in the report and also printed to
the database. This is for informational purposes only. It has no other
functionality.
- config_check_warn_unrestricted_rules
(type: bool, default: false, added in AIDE v0.18)
- Whether to warn on unrestricted rules during config check. To explicitly
define unrestricted rules use 0 (zero) as restriction
character.
- num_workers
(type: number|percentage, default: 1, added in AIDE v0.18)
- Specifies the number of simultaneous workers (threads) for file attribute
processing (i.a. hashsum calculation).
The number of workers can be a positive integer (e.g. '4') or
the percentage of the available processors (e.g. '60%'). The resulting
number of workers is rounded up to the next integer (e.g. '60%' of 8
processors results in 5 workers).
If there are multiple num_workers lines then the first
one is used.
Use 0 (zero) to disable multi-threading.
The default value 1 (single worker thread) may be changed in a
future release.
- report_url (type:
URL, default: stdout)
-
The URL that the output is written to.
Multiple instances of the report_url option are
supported.
Examples:
report_url=file:/var/log/aide.log
Write report to /var/log/aide.log.
report_url=stdout
Write report to stdout.
report_url=syslog:<LOG_FACILITY>
Write report to syslog using
LOG_FACILITY.
The following report options are available (to take effect they
have to be set before report_url):
- report_level
(type: report level, default: changed_attributes, added in AIDE
v0.17)
-
The report level to use. The available report levels are as
follows:
minimal: print single line whether AIDE found
differences to the database
summary: additionally print number of added, removed and
changed files
database_attributes: additionally print database
checksums
list_entries: additionally print lists of added, removed
and changed entries
changed_attributes: additionally print details about
changed entries
Example:
File: /var/lib/apt/extended_states
Perm : -rw-r--r-- | -rw-------
Uid : 0 | 106
The left column shows the old value (e.g. from the
database_in database) and the right column shows the new value (e.g.
from the file system).
added_removed_attributes: additionally print details about
added and removed attributes
added_removed_entries: additionally print details about
added and removed entries
- report_format
(type: report format, default: plain, added in AIDE v0.18)
- The report format to use. The available report formats are as follows:
plain: Print report in plain human-readable
format.
json: Print report in json machine-readable format.
- report_base16
(type: bool, default: false, added in AIDE v0.17)
- Base16 encode the checksums in the report. The default is to report
checksums in base64 encoding.
- report_detailed_init
(type: bool, default: false, added in AIDE v0.16)
- Report added files (report level >= list_entries) and their
details (report level >= added_removed_entries) in
initialization mode.
- report_quiet
(type: bool, default: false, added in AIDE v0.16)
- Suppress report output if no differences to the database have been
found.
- report_append
(type: bool, default: false, added in AIDE v0.17)
- Append to the report URL.
- report_grouped
(type: bool, default: true, added in AIDE v0.17)
- grouped (DEPRECATED
since AIDE v0.17, will be removed in AIDE v0.19)
- Group the files in the report by added, removed and changed files.
- report_summarize_changes
(type: bool, default: true, added in AIDE v0.17)
- summarize_changes
(DEPRECATED since AIDE v0.17, will be removed in AIDE v0.19)
- Summarize changes in the added, removed and changed files sections of the
report.
The general format is like the string YlZbpugamcinHAXSEC,
where Y is replaced by the file-type ('f' for a regular file,
'd' for a directory, 'l' for a symbolic link, 'c'
for a character device, 'b' for a block device, 'p' for a
FIFO, 's' for a unix socket, 'D' for a Solaris door,
'P' for a Solaris event port, '!' if file type has changed
and '?' otherwise).
The Z is replaced as follows: A '=' means that the size
has not changed, a '<' reports a shrinked size and a
'>' reports a grown size. The other letters in the string are
the actual letters that will be output if the associated attribute for
the item has been changed or a '.' for no change.
Otherwise a '+' is shown if the attribute has been
added, a '-' if it has been removed, a ':' if the
attribute is ignored (but not forced) or a ' ' if the attribute has not
been checked.
The exceptions to this are: (1) a newly created file replaces
each letter with a '+', and (2) a removed file replaces each
letter with a '-'.
The attribute that is associated with each letter is as
follows:
- o
- A l means that the link name has changed.
- o
- A b means that the block count has changed.
- o
- A p means that the permissions have changed.
- o
- An u means that the uid has changed.
- o
- A g means that the gid has changed.
- o
- An a means that the access time has changed.
- o
- A m means that the modification time has changed.
- o
- A c means that the change time has changed.
- o
- An i means that the inode has changed.
- o
- A n means that the link count has changed.
- o
- A H means that one or more message digests have changed.
The following letters are only available when explicitly
enabled using configure:
- o
- A A means that the access control list has changed.
- o
- A X means that the extended attributes have changed.
- o
- A S means that the SELinux attributes have changed.
- o
- A E means that the file attributes on a second extended file system
have changed.
- o
- A C means that the file capabilities have changed.
- report_ignore_added_attrs
(type: attribute expression, default: empty, added in AIDE
v0.16)
- Attributes whose addition is to be ignored in the report.
- report_ignore_removed_attrs
(type: attribute expression, default: empty, added in AIDE
v0.16)
- Attributes whose removal is to be ignored in the report.
- report_ignore_changed_attrs
(type: attribute expression, default: empty, added in AIDE
v0.16)
- ignore_list
(REMOVED in AIDE v0.17)
- Attributes whose change is to be ignored in the report.
- report_force_attrs
(type: attribute expression, default: empty, added in AIDE
v0.16)
- report_attributes
(REMOVED in AIDE v0.17)
- Attributes which are always printed in the report for changed files. If an
attribute is both ignored and forced the attribute is not considered for
file change but printed in the final report as long as the file has been
otherwise changed.
- report_ignore_e2fsattrs
(type: string, default: 0, added in AIDE v0.16)
- List (no delimiter) of ext2 file attributes which are to be ignored in the
report. See chattr(1) for the available attributes. Use 0
(zero) to not ignore any attribute. Ignored attributes are represented by
a ':' in the report.
By default AIDE also reports changes of the read-only
attributes mentioned in chattr(1) (see example below how to
ignore those changes).
Example:
Ignore changes of the read-only ext2 file attributes
verify (V), inline data (N), indexed directory (I) and encrypted (E):
report_ignore_e2fsattrs=VNIE
Groups are aggregations of attributes.
Group definitions have the format <group name> =
<attribute expression>.
Group names are limited to alphanumeric characters
(A-Za-z0-9).
See ATTRIBUTES for a description of all available attributes.
Default groups
- R
- p+ftype+i+l+n+u+g+s+m+c+md5+X
- L
- p+ftype+i+l+n+u+g+X
- >
- Growing file p+ftype+l+u+g+i+n+s+growing+X
- H
- all compiled in hashsums (added in AIDE v0.17)
- X
- acl+selinux+xattrs+e2fsattrs+caps (if attributes are compiled in, added in
AIDE v0.16)
- E
- Empty group
- Use 'aide --version' to list the
default compound groups.
-
AIDE supports three types of rules:
- Regular
rule:
- <regex> <attribute expression>
Files and directories matching the regular expression are
added to the database.
- Negative
rule:
- !<regex>
Files and directories matching the regular expression are
ignored and not added to the database. The children of matching
directories are also ignored.
- Equals
rule:
- =<regex> <attribute expression>
Files and directories matching the regular expression are
added to the database. The children of directories are only added if the
regular expression ends with a "/". The children of
sub-directories are not added at all.
Every regular expression has to start with an explicit
"/". An implicit ^ is added in front of each regular expression.
In other words, the regular expressions are matched at the first position
against the complete path. Special characters can be escaped using two-digit
URL encoding (for example, %20 to represent a space).
AIDE uses a deepest-match algorithm to find the tree node to
search, but a first-match algorithm inside the node. (see also rule
log level).
See EXAMPLES for examples.
More in-depth discussion of the selection algorithm can be found
in the AIDE manual.
Restricted rules are like normal rules but can be restricted to
file types (added in AIDE v0.16). The following file types are
supported:
- f
- restrict rule to regular files
- d
- restrict rule to directories
- l
- restrict rule to symbolic links
- c
- restrict rule to character devices
- b
- restrict rule to block devices
- p
- restrict rule to FIFO files
- s
- restrict rule to UNIX sockets
- D
- restrict rule to Solaris doors
- P
- restrict rule to Solaris event ports
- 0
- empty restriction, i.e. don't restrict rule (added in AIDE v0.18)
Multiple restrictions can be given as a comma-separated list.
The syntax of restricted rules is as follows:
- Restricted
regular rule
- <regex> <file types> <attribute expression>
- Restricted
negative rule
- !<regex> <file types>
- Restricted
equals rule
- =<regex> <file types> <attribute expression>
- @@define VAR val
- Define variable VAR to value val.
- @@undef VAR
- Undefine variable VAR.
- @@if boolean_expression (added in AIDE v0.18)
- @@else
- @@endif
- @@if begins an if statement. It must be terminated with an @@endif
statement. The lines between @@if and @@endif are used if the
boolean_expression evaluates to true. If there is an @@else
statement then the part between @@if and @@else is used if
boolean_expression evaluates to true otherwise the part
between @@else and @@endif is used.
Available operators and functions in boolean expressions:
not boolean_expression
Evaluates to true if the boolean_expression is
false, and false if the boolean_expression is true.
defined VARIABLE
Evaluates to true if VARIABLE is
defined.
hostname HOSTNAME
Evaluates to true if HOSTNAME equals the
hostname of the machine that AIDE is running on. hostname is the
name of the host without the domainname (ie 'hostname', not
'hostname.example.com').
exists PATH
Evaluates to true if PATH exists.
- @@ifdef VARIABLE (DEPRECATED since AIDE v0.18, will be removed in
AIDE v0.20)
- same as @@if defined VARIABLE
- @@ifndef VARIABLE (DEPRECATED since AIDE v0.18, will be removed in
AIDE v0.20)
- same as @@if not defined VARIABLE
- @@ifhost HOSTNAME (DEPRECATED since AIDE v0.18, will be removed in
AIDE v0.20)
- same as @@if hostname HOSTNAME
- @@ifnhost HOSTNAME (DEPRECATED since AIDE v0.18, will be removed in
AIDE v0.20)
- same as @@if not hostname HOSTNAME
- @@{VAR}
- @@{VAR} is replaced with the value of the variable VAR. If
variable VAR is not defined an empty string is used.
Variables are supported in strings and in regular expressions
of selection lines.
Pre-defined marco variables:
@@{HOSTNAME}: hostname of the current system
- @@include FILE
- Include FILE.
The content of the file is used as if it were inserted in this
part of the config file.
The maximum depth of nested includes is 16.
- @@include DIRECTORY REGEX [RULE_PREFIX] (added in
AIDE v0.17)
- Include all (regular) files found in DIRECTORY matching regular
expression REGEX (sub-directories are ignored). The file are
included in lexical sort order.
If RULE_PREFIX is set, all rules included by the
statement are prefixed with given RULE_PREFIX (added in AIDE
v0.18). Prefixes from nested include statements are concatenated.
The content of the files is used as if it were inserted in
this part of the config file.
- @@x_include FILE (added in AIDE v0.17)
- @@x_include DIRECTORY REGEX [RULE_PREFIX] (added in
AIDE v0.17)
- @x_include is identical to @@include, except that if a
config file is executable is is run and the output is used as config.
If the executable file exits with status greater than zero or
writes to stderr aide stops with an error.
For security reasons DIRECTORY and each executable
config file must be owned by the current user or root. They must not be
group- or world-writable.
- @@x_include_setenv VAR VALUE (added in AIDE v0.17)
-
Adds the variable VAR with the value VALUE to
the environment used for config file execution.
Environment variable names are limited to alphanumeric
characters (A-Za-z0-9) and the underscore '_' and must not
begin with a digit.
bool
Valid values are yes, true, no or
false.
attribute expression
An attribute expression is of the following form:
-
<attribute/group>
| <expr> + <attribute/group>
| <expr> - <attribute/group>
URLS
Urls can be one of the following. Input urls cannot be
used as outputs and vice versa.
- stdout
- stderr
- Output is sent to stdout, stderr respectively.
- stdin
- Input is read from stdin.
- file:/path
- Input is read from path or output is written to path.
- fd:number
- Input is read from filedescriptor number or output is written to
number.
- syslog:LOG_FACILITY
- Output is written to syslog using LOG_FACILITY.
File attributes
- ftype
- file type (added in AIDE v0.15)
- p
- permissions
- i
- inode
- l
- link name
- n
- number of links
- u
- user
- g
- group
- s
- size
- b
- block count
- m
- mtime
- a
- atime
- c
- ctime
- acl
- access control list (requires libacl)
- selinux
- selinux attributes (requires libselinux)
- xattrs
- extended attributes (requires libattr)
- e2fsattrs
- file attributes on a second extended file system, see also
report_ignore_e2fsattrs option (requires libext2fs, added in
AIDE v0.15)
- caps
- file capabilities (requires libcap2, added in AIDE v0.17)
Use 'aide --version' to show which compiled-in attributes are
available.
Special attributes
- S
- check for growing size (DEPRECATED since AIDE v0.18, will be removed in
AIDE v0.20)
Use growing+s attributes instead
- I
- ignore changed filename
When I is used, the inode of the old file is used to
search for a moved file in the new database.
Source and target file have to be located in the same
directory and must share the same attributes (except for special
attributes ANF, ARF, I, growing, and
compressed).
For moved entries a change of the ctime attribute is
ignored.
- growing
- ignore growing file (added in AIDE v0.18)
When growing is used, changes of the following
attributes are ignored:
size: if new size is greater than old size
bcount: if new bcount is greater than old bcount
atime: if new atime is greater than old atime
mtime: if new mtime is greater than old mtime
ctime: if new ctime is greater than old ctime
hashsums: if the hashsum of the new file restricted to
the old size equals the hashsums of the old file
For hashsum attributes the growing attribute is ignored
in compare mode.
- compressed
- ignore compressed file (added in AIDE v0.18)
When compressed is used, the uncompressed hashsums of
the new compressed file (supported compressions: gzip) are used
to search for the uncompressed file in the old database.
The old uncompressed and the new compressed file have to be
located in the same directory and must share the same attributes (except
for special attributes ANF, ARF, I, growing,
and compressed) including at least one hashsum.
Changes of the inode, size, bcount and
ctime attributes are ignored.
The growing attribute (i.e. the old file size) is not
considered for compressed files during the calculation of the
uncompressed hashsums.
The compressed attribute is ignored in compare
mode.
- ANF
- allow new files
When 'ANF' is used, new files are added to the new database,
but are ignored in the report.
- ARF
- allow removed files
When 'ARF' is used, files missing on disk are omitted from the
new database, but are ignored in the report.
Hashsums attributes
- md5
- MD5 checksum (not in libgcrypt FIPS mode)
- sha1
- SHA-1 checksum
- sha256
- SHA-256 checksum
- sha512
- SHA-512 checksum
- rmd160
- RIPEMD-160 checksum
- tiger
- tiger checksum
- haval
- haval256 checksum (libmhash only)
- crc32
- crc32 checksum
- crc32b
- crc32 checksum (libmhash only)
- gost
- GOST R 34.11-94 checksum
- whirlpool
- whirlpool checksum
- stribog256
- GOST R 34.11-2012, 256 bit checksum (libgcrypt only, added in AIDE
v0.17)
- stribog512
- GOST R 34.11-2012, 512 bit checksum (libgcrypt only, added in AIDE
v0.17)
Use 'aide --version' to show which hashsums are available.
- / R
- This adds all files on your machine to the database. This one line is a
fully qualified configuration file.
- !/dev$
- This ignores the /dev directory structure.
- =/foo R
- Only /foo and /foobar are taken into the database. None of their children
are added.
- =/foo/ R
- Only /foo and its children (e.g. /foo/file and /foo/directory) are taken
into the database. The children of sub-directories (e.g.
/foo/directory/bar) are not added.
- / d,f R
- Only add directories and files to the database
- !/run d
- /run R
- Add all but directory entries to the database
- /run d R-m-c-i
- /run R
- Use specific rule for directories
- Suggested
Groups
- OwnerMode
= p+u+g+ftype
- Check permissions, owner, group and file type
- Size =
s+b
- Check size and block count
- InodeData
= OwnerMode+n+i+Size+l+X
- StaticFile
= m+c+Checksums
- Files that stay static
Full = InodeData+StaticFile
- Full =
ftype+p+l+u+g+s+m+c+a+i+b+n+H+X
- / 0 Full
- This line defines group Full. It has all attributes, all compiled
in hashsums (H) and all compiled in extra file attributes
(X). See '--version' output for the compiled in hashsums and extra
groups. The example rule is the typical catch-all rule at the end of the
rule list.
- VarTime =
InodeData+Checksums
- /etc/ssl/certs/ca-certificates\\.crt$ VarTime
- Files that change their mtimes or ctimes but not their contents.
- VarInode =
VarTime-i
- /var/lib/nfs/etab$ f VarInode
- Files that are recreated regularly but do not change their contents
- VarFile =
OwnerMode+n+l+X
- /etc/resolv\\.conf$ f VarFile
- Files that change their contents during system operation
- VarDir =
OwnerMode+n+i+X
- /var/lib/snmp$ d VarDir
- Directories that change their contents during system operation
- RecreatedDir
= OwnerMode+n+X
- /run/samba$ d RecreatedDir
- Directories that are recreated regularly and change their contents
- Log Handling
Logs pose a number of special challenges to AIDE. An active log is
nearly constantly being written to. The process of log rotation changes file
names for files that are supposed to have unaltered contents. To save space,
Logs are compressed in the process of their rotation, and finally, they get
deleted. AIDE is supposed to handle all those cases without generating
reports, and it is still expected to flag the cases when an attacker tampers
with logs.
The following examples suggest a way to handle the common case of
log rotation with the logrotate(8) program, with its options
compress, delaycompress and nocopytruncate set. The
vast majority of logs are rotated this way on most Linux systems.
- ActLog=Full+growing+ANF+I
- /var/log/foo\\.log$ f ActLog
- An Active Log is typically named foo.log. It is constanty being written
to. The file does neither change its mode nor its inode number. The size
only increases, and what is written to the file is not supposed to change
(growing). During log rotation, foo.log is typically renamed to foo.log.1
(or foo.log.0) and the process is instructed to write to a new foo.log.
Log content is written to a new file (ANF) and will eventually be renamed
to foo.log.1 (I). The growing attribute suppresses reports for files that
just had content appended when compared to the database. A change of the
old content is still reported!
- RotLog=Full
- /var/log/foo\\.log\\.1$ f RotLog
- foo.log.0 or foo.log.1 is called the Rotated Log, the previously active
log renamed to the first name of the Log Series that is formed by the
rotation mechanism. Right after rotation, the file might still being
written to by the daemon. To aide, this looks like the Active Log's size
decreases and its inode and timestamps change. The Rotated Log is not
supposed to change its attributes once the process has stopped writing to
it. Reports might be generated if aide runs while the process still writes
to the Rotated Log, but this is quite unlikely to happen. Some log
rotation mechanisms rename foo.log to foo.log.0 to foo.log.1.gz, others
rename foo.log to foo.log.1 to foo.2.log.gz.
- CompSerLog=Full+I+compressed
- /var/log/foo\\.log\\.2\\.gz$ f CompSerLog
- In the next rotation step, foo.log.1 gets compressed to foo.log.2.gz,
becoming the Compressed Log in the Log Series. With this rule, AIDE does
not report this step because it uncompresses the contents of the file and
takes the checksum of the uncompressed content. The contents strictly
doesn't change, but some attribute changes are ignored (compressed).
- MidlSerLog=Full+I
- /var/log/foo\\.log\\.[345]\\.gz$ f MidlSerLog
- In the next log rotation, all foo.log.{x} get renamed to foo.log.{x+1}.
The other attributes are not supposed to change.
- LastSerLog=Full+ARF
- /var/log/foo\\.log\\.6\\.gz$ f LastSerLog
- The configuration of the log rotation process specifies a number of log
generations to keep. The last log in the series is therefore removed from
the disk (ARF).
aide 0.18 does not yet support the following cases of log
rotation:
- empty files
- It might be the case that a log is actually created, but never written to.
This commonly happens on rarely used web servers that use the log rotation
as a method to cater for data protection regulation. In result, all files
in a series are identical, breaking the heuristics that aide uses to
detect log rotation. A possible workaround is to begin a newly rotated log
with a timestamp. With logrotate, this can be done in a postrotate
scriptlet.
- nodelaycompress
- With logrotate's nodelaycompress option, a log is immediately
compressed after renaming it from the Active Log name. For the time being,
it is recommended to always use the delaycompress option to avoid
this behavior.
- copytruncate
- With logrotate's copytruncate option, the Active Log is not renamed
and newly created but copied to the new file name. After the copy
operation, the old file is truncated to zero size, allowing the daemon to
continuously write to the already open file handle. aide uses the Inode
number to detect the rotation process. That doesn't work with
copytruncate because the Inode stays with the Active Log. For the
time being, it is recommended to avoid the copytruncate option to
avoid this behavior.
In the following, the first is not allowed in AIDE. Use the latter
instead.
- /foo epug
- /foo e+p+u+g
All trademarks are the property of their respective owners. No
animals were harmed while making this webpage or this piece of software.