Files
sudo/sudoers.html
1999-08-26 09:00:59 +00:00

586 lines
21 KiB
HTML

<HTML>
<HEAD>
<TITLE>Sudoers Manual</TITLE>
<LINK REV="made" HREF="mailto:root@localhost">
</HEAD>
<BODY>
<!-- INDEX BEGIN -->
<UL>
<LI><A HREF="#NAME">NAME</A>
<LI><A HREF="#DESCRIPTION">DESCRIPTION</A>
<UL>
<LI><A HREF="#Quick_guide_to_EBNF">Quick guide to EBNF</A>
<LI><A HREF="#Aliases">Aliases</A>
<LI><A HREF="#User_Specification">User Specification</A>
<LI><A HREF="#Runas_Spec">Runas_Spec</A>
<LI><A HREF="#NOPASSWD_and_PASSWD">NOPASSWD and PASSWD</A>
<LI><A HREF="#Wildcards_aka_meta_characters_">Wildcards (aka meta characters):</A>
<LI><A HREF="#Exceptions_to_wildcard_rules_">Exceptions to wildcard rules:</A>
<LI><A HREF="#Other_special_characters_and_res">Other special characters and reserved words:</A>
</UL>
<LI><A HREF="#EXAMPLES">EXAMPLES</A>
<LI><A HREF="#SECURITY_NOTES">SECURITY NOTES</A>
<LI><A HREF="#CAVEATS">CAVEATS</A>
<LI><A HREF="#FILES">FILES</A>
<LI><A HREF="#SEE_ALSO">SEE ALSO</A>
</UL>
<!-- INDEX END -->
<HR>
<P>
<HR>
<H1><A NAME="NAME">NAME</A></H1>
<P>
sudoers - list of which users may execute what
<P>
<HR>
<H1><A NAME="DESCRIPTION">DESCRIPTION</A></H1>
<P>
The <EM>sudoers</EM> file is composed two types of entries: aliases (basically variables) and
user specifications (which specify who may run what). The grammar of <EM>sudoers</EM>
will be described below in Extended Backus-Naur Form (EBNF). Don't despair
if you don't know what EBNF is, it is fairly simple and the definitions
below are annotated.
<P>
<HR>
<H2><A NAME="Quick_guide_to_EBNF">Quick guide to EBNF</A></H2>
<P>
EBNF is a concise and exact way of describing the grammar of a language.
Each EBNF definition is made up of <EM>production rules</EM>. Eg.
<P>
<PRE> symbol ::= definition | alternate1 | alternate2 ...
</PRE>
<P>
Each <EM>production rule</EM> references others and thus makes up a grammar for the language. EBNF also
contains the following operators, which many readers will recognize from
regular expressions. Do not, however, confuse them with ``wildcard''
characters, which have different meanings.
<DL>
<DT><STRONG><A NAME="item__">?</A></STRONG><DD>
<P>
Means that the preceding symbol (or group of symbols) is optional. That is,
it may appear once or not at all.
<LI>
<P>
Means that the preceding symbol (or group of symbols) may appear zero or
more times.
<DT><STRONG><A NAME="item__">+</A></STRONG><DD>
<P>
Means that the preceding symbol (or group of symbols) may appear one or
more times.
</DL>
<P>
Parentheses may be used to group symbols together. For clarity, we will use
single quotes ('') to designate what is a verbatim character string (as
opposed to a symbol name).
<P>
<HR>
<H2><A NAME="Aliases">Aliases</A></H2>
<P>
There are four kinds of aliases: the <CODE>User_Alias</CODE>, <CODE>Runas_Alias</CODE>,
<CODE>Host_Alias</CODE> and <CODE>Cmnd_Alias</CODE>.
<P>
<PRE> Alias ::= User_Alias = User_Alias (':' User_Alias)* |
Runas_Alias (':' Runas_Alias)* |
Host_Alias (':' Host_Alias)* |
Cmnd_Alias (':' Cmnd_Alias)*
</PRE>
<P>
<PRE> User_Alias ::= NAME '=' User_List
</PRE>
<P>
<PRE> Runas_Alias ::= NAME '=' Runas_User_List
</PRE>
<P>
<PRE> Host_Alias ::= NAME '=' Host_List
</PRE>
<P>
<PRE> Cmnd_Alias ::= NAME '=' Cmnd_List
</PRE>
<P>
<PRE> NAME ::= [A-Z]([A-Z][0-9]_)*
</PRE>
<P>
Each <EM>alias</EM> definition is of the form
<P>
<PRE> Alias_Type NAME = item1, item2, ...
</PRE>
<P>
where <EM>Alias_Type</EM> is one of <CODE>User_Alias</CODE>, <CODE>Runas_Alias</CODE>, <CODE>Host_Alias</CODE>, or <CODE>Cmnd_Alias</CODE>. A <CODE>NAME</CODE> is a string of upper case letters, numbers, and the underscore characters
('_'). A <CODE>NAME</CODE> <STRONG>must</STRONG> start with an upper case letter. It is possible to put several alias
definitions of the same type on a single line, joined by a semicolon (':').
Eg.
<P>
<PRE> Alias_Type NAME = item1, item2, item3 : NAME = item4, item5
</PRE>
<P>
The definitions of what constitutes a valid <EM>alias</EM> member follow.
<P>
<PRE> User_List ::= User |
User ',' User_List
</PRE>
<P>
<PRE> User ::= '!'* username |
'!'* '#'uid |
'!'* '%'group |
'!'* '+'netgroup |
'!'* User_Alias
</PRE>
<P>
A <CODE>User_List</CODE> is made up of one or more usernames, uids (prefixed with '#'), System
groups (prefixed with '%'), netgroups (prefixed with '+') and other
aliases. Each list item may be prefixed with one or more '!' operators. An
odd number of '!' operators negates the value of the item; an even number
just cancel each other out.
<P>
<PRE> Runas_List ::= Runas_User |
Runas_User ',' Runas_List
</PRE>
<P>
<PRE> Runas_User ::= '!'* username |
'!'* '#'uid |
'!'* '%'group |
'!'* +netgroup |
'!'* Runas_Alias
</PRE>
<P>
Likewise, a <CODE>Runas_List</CODE> has the same possible elements as a <CODE>User_List</CODE>, except that it can include a <CODE>Runas_Alias</CODE>, instead of a <CODE>User_Alias</CODE>.
<P>
<PRE> Host_List ::= Host |
Host ',' Host_List
</PRE>
<P>
<PRE> Host ::= '!'* hostname |
'!'* ip_addr |
'!'* network(/netmask)? |
'!'* '+'netgroup |
'!'* Host_Alias
</PRE>
<P>
A <CODE>Host_List</CODE> is made up of one or more hostnames, IP addresses, network numbers,
netgroups (prefixed with '+') and other aliases. Again, the value of an
item may be negated with the '!' operator. If you do not specify a netmask
with a network number, the netmask of the host's ethernet
<CODE>interface(s)</CODE> will be used when matching. The netmask may be
specified either in dotted quad notation (eg. 255.255.255.0) or CIDR
notation (number of bits, eg. 24).
<P>
<PRE> Cmnd_List ::= Cmnd |
Cmnd ',' Cmnd_List
</PRE>
<P>
<PRE> commandname ::= filename |
filename args |
filename '&quot;&quot;'
</PRE>
<P>
<PRE> Cmnd ::= '!'* commandname |
'!'* directory |
'!'* Cmnd_Alias
</PRE>
<P>
A <CODE>Cmnd_List</CODE> is a list of one or more commandnames, directories, and other aliases. A
commandname is a fully-qualified filename which may include shell-style
wildcards (see `Wildcards' section below). A simple filename allows the
user to run the command with any arguments he/she wishes. However, you may
also command line arguments (including wildcards). Alternately, you can
specify <CODE>&quot;&quot;</CODE> to indicate that the command may only be run <STRONG>without</STRONG> command line arguments. A directory is a fully qualified pathname ending in
a '/'. When you specify a directory in a <CODE>Cmnd_List</CODE>, the user will be able to run any file within that directory (but not in
any subdirectories therein).
<P>
If a <CODE>Cmnd</CODE> has associated command line arguments, then the arguments in the <CODE>Cmnd</CODE> must match exactly those given by the user on the command line (or match
the wildcards if there are any). Note that the following characters must be
escaped with a '\' if they are used in command arguments: ',', ':', '=',
'\\'.
<P>
<HR>
<H2><A NAME="User_Specification">User Specification</A></H2>
<P>
<PRE> Runas_Spec ::= '(' Runas_List ')'
</PRE>
<P>
<PRE> Cmnd_Spec ::= Runas_Spec? ('NOPASSWD:' | 'PASSWD:')? Cmnd
</PRE>
<P>
<PRE> Cmnd_Spec_List ::= Cmnd_Spec |
Cmnd_Spec ',' Cmnd_Spec_List
</PRE>
<P>
<PRE> User_Spec ::= User_list Cmnd_Spec_List (':' User_Spec)*
</PRE>
<P>
A <STRONG>user specification</STRONG> determines which commands a user may run (and as what user) on specified
hosts. By default, commands are run as <STRONG>root</STRONG> but this can be changed on a per-command basis.
<P>
Let's break that down into its constituent parts:
<P>
<HR>
<H2><A NAME="Runas_Spec">Runas_Spec</A></H2>
<P>
A <CODE>Runas_Spec</CODE> is simply a <CODE>Runas_List</CODE> (as defined above) enclosed in a set of parentheses. If you do not specify
a
<CODE>Runas_Spec</CODE> in the user specification, a default <CODE>Runas_Spec</CODE>
of <STRONG>root</STRONG> will be used. A <CODE>Runas_Spec</CODE> sets the default for commands that follow it. What this means is that for
the entry:
<P>
<PRE> dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/who
</PRE>
<P>
The user <STRONG>dgb</STRONG> may run <EM>/bin/ls</EM>, <EM>/bin/kill</EM>, and
<EM>/usr/bin/lprm</EM> -- but only as <STRONG>operator</STRONG>. Eg.
<P>
<PRE> sudo -u operator /bin/ls.
</PRE>
<P>
It is also possible to override a <CODE>Runas_Spec</CODE> later on in an entry. If we modify the entry like so:
<P>
<PRE> dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm
</PRE>
<P>
Then user <STRONG>dgb</STRONG> is now allowed to run <EM>/bin/ls</EM> as <STRONG>operator</STRONG>, but <EM>/bin/kill</EM> and <EM>/usr/bin/lprm</EM> as <STRONG>root</STRONG>.
<P>
<HR>
<H2><A NAME="NOPASSWD_and_PASSWD">NOPASSWD and PASSWD</A></H2>
<P>
By default, <STRONG>sudo</STRONG> requires that a user authenticate him or herself before running a command.
This behavior can be modified via the
<CODE>NOPASSWD</CODE> tag. Like a <CODE>Runas_Spec</CODE>, the <CODE>NOPASSWD</CODE> tag sets a default for the commands that follow it in the <CODE>Cmnd_Spec_List</CODE>. Conversely, the <CODE>PASSWD</CODE> tag can be used to reverse things. For example:
<P>
<PRE> ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm
</PRE>
<P>
would allow the user <STRONG>ray</STRONG> to run <EM>/bin/kill</EM>, <EM>/bin/ls</EM>, and
<EM>/usr/bin/lprm</EM> as root on the machine rushmore as <STRONG>root</STRONG> without authenticating himself. If we only want <STRONG>ray</STRONG> to be able to run <EM>/bin/kill</EM> without a password the entry would be:
<P>
<PRE> ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm
</PRE>
<P>
<HR>
<H2><A NAME="Wildcards_aka_meta_characters_">Wildcards (aka meta characters):</A></H2>
<P>
<STRONG>sudo</STRONG> allows shell-style <EM>wildcards</EM> to be used in pathnames as well as command line arguments in the <EM>sudoers</EM> file. Wildcard matching is done via the <STRONG>POSIX</STRONG> <CODE>fnmatch(3)</CODE> routine. Note that these are <EM>not</EM> regular expressions.
<UL>
<LI>
<P>
Matches any set of zero or more characters.
<DT><STRONG>?</STRONG><DD>
<P>
Matches any single character.
<DT><STRONG><A NAME="item__">[...]</A></STRONG><DD>
<P>
Matches any character in the specified range.
<DT><STRONG><A NAME="item__">[!...]</A></STRONG><DD>
<P>
Matches any character <STRONG>not</STRONG> in the specified range.
<DT><STRONG><A NAME="item__x">\x</A></STRONG><DD>
<P>
For any character ``x'', evaluates to ``x''. This is used to escape special
characters such as: ``*'', ``?'', ``['', and ``}''.
</UL>
<P>
Note that a forward slash ('/') will <STRONG>not</STRONG> be matched by wildcards used in the pathname. When matching the command
line arguments, however, as slash <STRONG>does</STRONG> get matched by wildcards. This is to make a path like:
<P>
<PRE> /usr/bin/*
</PRE>
<P>
match <CODE>/usr/bin/who</CODE> but not <CODE>/usr/bin/X11/xterm</CODE>.
<P>
<HR>
<H2><A NAME="Exceptions_to_wildcard_rules_">Exceptions to wildcard rules:</A></H2>
<P>
The following exceptions apply to the above rules:
<DL>
<DT><STRONG><A NAME="item__">&quot;&quot;</A></STRONG><DD>
<P>
If the empty string <CODE>&quot;&quot;</CODE> is the only command line argument in the
<EM>sudoers</EM> entry it means that command is not allowed to be run with <STRONG>any</STRONG> arguments.
</DL>
<P>
<HR>
<H2><A NAME="Other_special_characters_and_res">Other special characters and reserved words:</A></H2>
<P>
The pound sign ('#') is used to indicate a comment (unless it occurs in the
context of a user name and is followed by one or more digits, in which case
it is treated as a uid). Both the comment character and any text after it,
up to the end of the line, are ignored.
<P>
The reserved word <STRONG>ALL</STRONG> is a a built in <EM>alias</EM> that always causes a match to succeed. It can be used wherever one might
otherwise use a <CODE>Cmnd_Alias</CODE>, <CODE>User_Alias</CODE>, <CODE>Runas_Alias</CODE>, or <CODE>Host_Alias</CODE>. You should not try to define your own <EM>alias</EM> called <STRONG>ALL</STRONG> as the built in alias will be used in preference to your own.
<P>
An exclamation point ('!') can be used as a logical <EM>not</EM> operator both in an <EM>alias</EM> and in front of a <CODE>Cmnd</CODE>. This allows one to exclude certain values. Note, however, that using a <CODE>!</CODE> in conjunction with the built in <CODE>ALL</CODE> alias to allow a user to run ``all but a few'' commands rarely works as
intended (see SECURITY NOTES below).
<P>
Long lines can be continued with a backslash ('\\') as the last character
on the line.
<P>
Whitespace between elements in a list as well as specicial syntactic
characters in a <EM>User Specification</EM> ('=', ':', '(', ')') is optional.
<P>
<HR>
<H1><A NAME="EXAMPLES">EXAMPLES</A></H1>
<P>
Below are example <EM>sudoers</EM> entries. Admittedly, some of these are a bit contrived. First, we define
our <EM>aliases</EM>:
<P>
<PRE> # User alias specification
User_Alias FULLTIMERS = millert, mikef, dowdy
User_Alias PARTTIMERS = bostley, jwfox, crawl
User_Alias WEBMASTERS = will, wendy, wim
</PRE>
<P>
<PRE> # Runas alias specification
Runas_Alias OP = root, operator
Runas_Alias DB = oracle, sybase
</PRE>
<P>
<PRE> # Host alias specification
Host_Alias SPARC = bigtime, eclipse, moet, anchor :\
SGI = grolsch, dandelion, black :\
ALPHA = widget, thalamus, foobar :\
HPPA = boa, nag, python
Host_Alias CUNETS = 128.138.0.0/255.255.0.0
Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0
Host_Alias SERVERS = master, mail, www, ns
Host_Alias CDROM = orion, perseus, hercules
</PRE>
<P>
<PRE> # Cmnd alias specification
Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\
/usr/sbin/restore, /usr/sbin/rrestore
Cmnd_Alias KILL = /usr/bin/kill
Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm
Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown
Cmnd_Alias HALT = /usr/sbin/halt, /usr/sbin/fasthalt
Cmnd_Alias REBOOT = /usr/sbin/reboot, /usr/sbin/fastboot
Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \
/usr/local/bin/tcsh, /usr/bin/rsh, \
/usr/local/bin/zsh
Cmnd_Alias SU = /usr/bin/su
</PRE>
<P>
The <EM>User specification</EM> is the part that actually determines who may run what.
<P>
<PRE> root ALL = (ALL) ALL
%wheel ALL = (ALL) ALL
</PRE>
<P>
We let <STRONG>root</STRONG> and any user in group <STRONG>wheel</STRONG> run any command on any host as any user.
<P>
<PRE> FULLTIMERS ALL = NOPASSWD: ALL
</PRE>
<P>
Full time sysadmins (<STRONG>millert</STRONG>, <STRONG>mikef</STRONG>, and <STRONG>dowdy</STRONG>) may run any command on any host without authenticating themselves.
<P>
<PRE> PARTTIMERS ALL = ALL
</PRE>
<P>
Part time sysadmins (<STRONG>bostley</STRONG>, <STRONG>jwfox</STRONG>, and <STRONG>crawl</STRONG>) may run any command on any host but they must authenticate themselves
first (since the entry lacks the <CODE>NOPASSWD</CODE> tag).
<P>
<PRE> jack CSNETS = ALL
</PRE>
<P>
The user <STRONG>jack</STRONG> may run any command on the machines in the <EM>CSNETS</EM> alias (the networks <CODE>128.138.243.0</CODE>, <CODE>128.138.204.0</CODE>, and <CODE>128.138.242.0</CODE>). Of those networks, only &lt;128.138.204.0&gt; has an explicit netmask (in CIDR notation) indicating it
is a class C network. For the other networks in <EM>CSNETS</EM>, the local machine's netmask will be used during matching.
<P>
<PRE> lisa CUNETS = ALL
</PRE>
<P>
The user <STRONG>lisa</STRONG> may run any command on any host in the <EM>CUNETS</EM> alias (the class B network <CODE>128.138.0.0</CODE>).
<P>
<PRE> operator ALL = DUMPS, KILL, PRINTING, SHUTDOWN, HALT, REBOOT,\
/usr/oper/bin/
</PRE>
<P>
The <STRONG>operator</STRONG> user may run commands limited to simple maintenance. Here, those are
commands related to backups, killing processes, the printing system,
shutting down the system, and any commands in the directory <EM>/usr/oper/bin/</EM>.
<P>
<PRE> joe ALL = /usr/bin/su operator
</PRE>
<P>
The user <STRONG>joe</STRONG> may only <CODE>su(1)</CODE> to operator.
<P>
<PRE> pete HPPA = /usr/bin/passwd [A-z]*, !/usr/bin/passwd root
</PRE>
<P>
The user <STRONG>pete</STRONG> is allowed to change anyone's password except for root on the <EM>HPPA</EM> machines. Note that this assumes <CODE>passwd(1)</CODE> does not take
multiple usernames on the command line.
<P>
<PRE> bob SPARC = (OP) ALL : SGI = (OP) ALL
</PRE>
<P>
The user <STRONG>bob</STRONG> may run anything on the <EM>SPARC</EM> and <EM>SGI</EM> machines as any user listed in the <EM>OP</EM> <CODE>Runas_Alias</CODE> (<STRONG>root</STRONG> and <STRONG>operator</STRONG>).
<P>
<PRE> jim +biglab = ALL
</PRE>
<P>
The user <STRONG>jim</STRONG> may run any command on machines in the <EM>biglab</EM> netgroup.
<STRONG>Sudo</STRONG> knows that ``biglab'' is a netgroup due to the '+' prefix.
<P>
<PRE> +secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser
</PRE>
<P>
Users in the <STRONG>secretaries</STRONG> netgroup need to help manage the printers as well as add and remove users,
so they are allowed to run those commands on all machines.
<P>
<PRE> fred ALL = (DB) NOPASSWD: ALL
</PRE>
<P>
The user <STRONG>fred</STRONG> can run commands as any user in the <EM>DB</EM> <CODE>Runas_Alias</CODE>
(<STRONG>oracle</STRONG> or <STRONG>sybase</STRONG>) without giving a password.
<P>
<PRE> john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
</PRE>
<P>
On the <EM>ALPHA</EM> machines, user <STRONG>john</STRONG> may su to anyone except root but he is not allowed to give
<CODE>su(1)</CODE> any flags.
<P>
<PRE> jen ALL, !SERVERS = ALL
</PRE>
<P>
The user <STRONG>jen</STRONG> may run any command on any machine except for those in the <EM>SERVERS</EM> <CODE>Host_Alias</CODE> (master, mail, www and ns).
<P>
<PRE> jill SERVERS = /usr/bin/, !SU, !SHELLS
</PRE>
<P>
For any machine in the <EM>SERVERS</EM> <CODE>Host_Alias</CODE>, <STRONG>jill</STRONG> may run any commands in the directory /usr/bin/ except for those commands
belonging to the <EM>SU</EM> and <EM>SHELLS</EM> <CODE>Cmnd_Aliases</CODE>.
<P>
<PRE> steve CSNETS = (operator) /usr/local/op_commands/
</PRE>
<P>
The user <STRONG>steve</STRONG> may run any command in the directory /usr/local/op_commands/ but only as
user operator.
<P>
<PRE> matt valkyrie = KILL
</PRE>
<P>
On his personal workstation, valkyrie, <STRONG>matt</STRONG> needs to be able to kill hung processes.
<P>
<PRE> WEBMASTERS www = (www) ALL, (root) /usr/bin/su www
</PRE>
<P>
On the host www, any user in the <EM>WEBMASTERS</EM> <CODE>User_Alias</CODE> (will, wendy, and wim), may run any command as user www (which owns the web
pages) or simply <CODE>su(1)</CODE> to www.
<P>
<PRE> ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\
/sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM
</PRE>
<P>
Any user may mount or unmount a CD-ROM on the machines in the CDROM
<CODE>Host_Alias</CODE> (orion, perseus, hercules) without entering a password. This is a bit
tedious for users to type, so it is a prime candiate for encapsulating in a
shell script.
<P>
<HR>
<H1><A NAME="SECURITY_NOTES">SECURITY NOTES</A></H1>
<P>
It is generally not effective to ``subtract'' commands from <CODE>ALL</CODE>
using the '!' operator. A user can trivially circumvent this by copying the
desired command to a different name and then executing that. For example:
<P>
<PRE> bill ALL = ALL, !SU, !SHELLS
</PRE>
<P>
Doesn't really prevent <STRONG>bill</STRONG> from running the commands listed in
<EM>SU</EM> or <EM>SHELLS</EM> since he can simply copy those commands to a different name, or use a shell
escape from an editor or other program. Therefore, these kind of
restrictions should be considered advisory at best (and reinforced by
policy).
<P>
<HR>
<H1><A NAME="CAVEATS">CAVEATS</A></H1>
<P>
The <EM>sudoers</EM> file should <STRONG>always</STRONG> be edited by the <STRONG>visudo</STRONG>
command which locks the file and does grammatical checking. It is
imperative that <EM>sudoers</EM> be free of syntax errors since <STRONG>sudo</STRONG>
will not run with a syntactically incorrect <EM>sudoers</EM> file.
<P>
<HR>
<H1><A NAME="FILES">FILES</A></H1>
<P>
<PRE> /etc/sudoers List of who can run what
/etc/group Local groups file
/etc/netgroup List of network groups
</PRE>
<P>
<HR>
<H1><A NAME="SEE_ALSO">SEE ALSO</A></H1>
<P>
<CODE><A HREF="sudo.html">sudo(8)</A>,</CODE> <CODE><A HREF="visudo.html">visudo(8)</A>,</CODE> <CODE>su(1),</CODE> <CODE>fnmatch(3).</CODE>
</BODY>
</HTML>