22.1 Class Configuration Commands
The five forms for the
class configuration command are the following:
CX list values from configuration file
CX $=Y copy values from another class (V8.10 and above)
FX /file values from a disk file
FX |program values via another program
FX key@database values from a database map (V8.12 and above)
The class configuration command starts with either the letter
C or F, which must begin a
line. The C says values will be assigned as a part
of the configuration command. The F says values
will be assigned from an external file, program, or database map.
The C or F is immediately
followed (with no intervening whitespace) by the name of the class
(the X in the preceding commands). A class name is
any single ASCII character or, beginning with V8.7
sendmail, a multicharacter name enclosed in
curly braces:
CX list all versions
C{LongName} list beginning with V8.7
See Section 21.4.2 for a full discussion of how to use
multicharacter names.
Note that classes are separate from macros, so they can both use the
same letter or name with no conflict.
The sendmail program reserves the lowercase
letters for its own use as internally defined class names. All
uppercase letters and all names that begin with uppercase letters are
available for your use.
22.1.1 The C Class Command
The C form of the class command causes values to
be assigned from within the configuration file. In general, the
C class command looks like this:
CX list values from configuration file
C{XX} list values from configuration file
Here, list is a list of string elements
(delimited by whitespace) that follows on the same line as the
C command. Each word in
list is added to the collection of values
in the class $=X, in the first case and to
the class $={XX} in the second.
Multiple declarations of the same named class can coexist in the
configuration file. Each declaration after the first adds its string
elements to those already in the collection. That is:
CX string1 string2
CX string3 string4
produces the same collection of class strings as does:
CX string1 string2 string3 string4
Both create a class containing four strings.
Whitespace separates one value from another. Whitespace is defined by
the C-language isspace(3) routine and usually
includes the space, tab, newline, carriage return, and form feed
characters. Each line of text assigned to a class is broken up by
sendmail into whitespace delimited words when
the C configuration command is parsed.
When a line is indented with a space or a tab, that line is joined by
sendmail to the preceding line. Thus, the
following three declarations also add four words to the class
$=X:
CX string1
CX string2
CX string3
string4
tab
Words that are added to a class cannot be removed after
sendmail has read them. Instead, they must be
edited out of whatever file or program produced them, and the
sendmail daemon must be restarted.
The list of words in a class declaration can include macros. For
example, the following assigns the same values to class
$=X as did the earlier example:
D{LIST} string1 string2 string3 string4
CX ${LIST}
Macros used in class declarations are expanded when the configuration
file is read. Deferred macros (those with the
$& prefix) cannot be used in class
declarations. But conditionals can:
CX ourhost$?{Domain}.${Domain}$.
22.1.1.1 Append one class to another
Beginning with V8.10
sendmail it is possible to copy and add values
from one class to another. The declaration to do this looks like the
following:
C{To} $={From}
Here, the values stored in the $={From} class are
added to the values stored in the $={To} class. If
$={To} does not exist, it will create them.
This effect is caused by the fact that class macros are now expanded
when placed on a C configuration line. To
illustrate, consider the following miniconfiguration file, which we
call x.cf:
V10
CA 1 2 3
CB 7 8 9
CX $=A 4 5 6 $=B
When this configuration file is read, first the class
$=A is filled with three values: 1, 2, and 3. Then
the class $=B is filled with three different
values: 7, 8, and 9. Finally, the class $=X is
filled first with the values from $=A (1, 2, and
3), then with its own values (4, 5, and 6), and lastly with the
values from $=B (7, 8, and 9). The result can be
seen by running sendmail on this
miniconfiguration file in rule-testing mode:
% /usr/sbin/sendmail -bt -C x.cf
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> $=X
2
3
1
6
7
4
5
8
9
>
Ignore the fact that the values you put in are printed in a different
order. This is an artifact of the way sendmail
stores class values in its symbol table and actually improves the
efficiency with which they are later looked up.
Class macros that you list as values for a C
configuration line need not be previously declared or even hold any
values. If they hold values, those values will be added to the target
class. Valueless and undeclared classes will simply be
ignored.
22.1.2 The F Class Command
The F form of the class configuration command
allows values to be appended to a class from outside the
configuration file. In general, the file command looks like either of
the following:
FX file values from a disk file
FX |program values via another program (V8.7 and above)
FX key@dbmap values from a database map (V8.12 and above)
The F is immediately followed by the name of the
class. This can be either a single-character name, as shown, or a
multicharacter name. The name is followed by optional whitespace and
then a filename, a program name, or a database-map lookup. If the
name begins with the pipe character (|), it is
taken to be the name of a program to run. If the name includes an @
character, it is taken to be a key to look up, and the name of a
database map. Otherwise, it is taken to be the name of a file to
read.
If SCANF (SCANF) was defined when
sendmail was compiled, each line that is read
from a file or program (but not from a database map) is parsed by the
C-language scanf(3) library routine. The
formatting pattern given to scanf(3) is
%s, which tells scanf(3) to
read only the first whitespace-delimited word from each line of text.
When the configuration file is processed, the file is opened for
reading, or the program is executed, or the database map is opened
for lookups. If any cannot be opened (for reading, execution, or
lookups), the following error is logged and
sendmail ignores that configuration command:
fileclass: cannot open what: why
Here, the what is the exact text that was
given in the configuration file, and why
is the text of a system error.
A file, program, or database map can also fail to open because of
defective permissions. See Section 10.5 to learn why
permissions are important, and Section 10.5.4 for a
list of recommended permissions.
For the file form only, if the file can optionally not exist, you can
prefix its name with a -o switch:
FX -o file OK for file to not exist
This tells sendmail to remain silent if the file
does not exit. The -o switch is useful when a
configuration file is shared by several machines, only some of which
need the external class macro file. But be aware that there can be
grave risk to not knowing when a critical file disappears.
The C and F forms of the
configuration command can be intermixed for any given class name. For
example, consider a file named
/etc/mail/localnames with the following
contents:
string3
string4
The following two configuration commands add the same four strings to
the class X as did the C
command alone in the previous section:
CX string1 string2
FX /etc/mail/localnames
This creates a class with four strings as elements. Whitespace
delimits one string from the others in the C line
declaration. The file /etc/local/names is then
opened and read, and each of the two words in that file is added to
the two words that are already in the class.
22.1.2.1 scanf(3) variations
The file form
of the class configuration command allows different formatting
patterns to be used with scanf(3). But the
program form does not allow any variation, and so its
scanf(3) pattern is always
%s, which tells scanf(3) to
read only the first whitespace-delimited word from each line of text:
FX file pat with scanf(3) pattern
FX |program always "%s"
FX key@dbmap cannot be used with scanf(3)
If the optional pat argument to the file form is
missing, the pattern given to scanf(3) is
%s. The optional pat argument
is separated from the file argument by one or more
spaces or tabs. It should not be quoted, and it consists of
everything from its first character to the end of the line.
Internally, scanf(3) is called with:
sscanf(result, pat, input)
Here, result is the string array element to be
added to the class definition. The pat is the
scanf(3) pattern, and input
is the line of text read from the file.
After each line of text is read from the file and filtered with the
scanf(3) pattern, it is further subdivided by
sendmail into individual words. That subdividing
uses whitespace (as defined by the C-language
isspace(3) routine) to separate words. Each
separate word is then appended as an individual element to the class
array.
Consider the contents of the following file named
/etc/mail/localhosts:
server1 server2 # my two nets
uuhost # my uucp alias
#mailhost # mail server alias (retired 06,23,91)
This file contains three hostname aliases to be added to a class
— say, H. The following configuration
command does just that:
FH /etc/mail/localhosts %[^#]
The pattern %[^#] causes
scanf(3) to read all characters in each line up
to, but not including, the first # character. The
first line includes two whitespace-delimited words that are appended
to the class H. The second line contains one word,
and the third contains none.
22.1.3 Class Via Database Map Lookups
Beginning with V8.12 you can declare
class values by specifying and using database-maps. Database maps are
described in Chapter 23. In its simplest form, such
a declaration looks like this:
FXkey@ type:detail
F{Name}key@ type:detail
Each such declaration begins with the F
configuration command, which is immediately followed (with no
intervening space) by the name of the class that will be filled with
values. The first line shows the single-character name form (the
X), and the second line shows the multicharacter
name form (the {Name}).
The name of the class is immediately followed by the key to look up
in the database map. Note that you must be very careful to specify a
key that actually exists. If the key is not found in the database
map, sendmail silently ignores the error.
The key is immediately followed by a
literal @ character, which in turn is immediately
followed by the type of the database map.
A db type database map, for example, could have
a type of either hash
or btree. An ldap type
database map, for example, would have a
type of ldap. (We
discuss ldap in detail in the next section.) A
complete list of types can be found in the
leftmost column of Table 23-2, in Section 23.2.2.
The type is immediately followed by a
colon and then by the detail. The nature
of the detail varies depending on what you
want this command to do. To illustrate, consider the following
addition to an mc configuration file:
LOCAL_CONFIG
FwCWhosts@hash:/etc/mail/access
Here, under the LOCAL_CONFIG part of the mc
file, we place an F configuration command. The
class that will be filled with values is the $=w
class ($=w), a special one that contains all
the names by which the local host can be known.
It will be filled with values by looking up the key
CWhosts in the hash type
database that is contained in the file
/etc/mail/access.
The key is optional, and it is not an error to omit it. This property
can be useful for ldap type maps, but is generally
not useful for other database maps. For most database-map types, a
missing key will simply match nothing and result in no values filling
the class.
The type is mandatory. If it is missing
(for example, if hash were omitted from the
preceding declaration), the following error would be printed and
logged:
fileclass: cannot open 'CWhosts@:/etc/mail/access': No such file or directory
If the type is misstated as one that does not
exist (for example, if foo replaced
hash), the following would be printed and logged:
fileclass: F{w}: class foo not available
If there is a problem with the detail (for
example, if access were misspelled as
acess), the following error would be printed and
logged:
hash map "w": missing map file /etc/mail/acess.db: No such file or directory
If the key contains an
@ character (as, for example,
gw@wash.dc.gov), the part to the left of the
first @ is taken as the
key (gw) and the rest
of the line through the : is taken as the
type
(wash.dc.gov@hash), yielding the following
error:
F{w}: class wash.dc.gov@hash not available
There is no possible way to put an @ character
into a key.
One use for filling a class with a database-map lookup might involve
looking up the name for root on the local
machine:
LOCAL_CONFIG
F{RootName}0@text:-k2 -v0 -z: /etc/passwd
Here, we need to know the name of root because
it is not the same on all machines (some might call it
toor, and others rot). The
name found will be placed into the class
$={RootName}. The text type
database map is used because it can look up keys in a plain file. The
/etc/passwd file might look, in part, like this:
0th
boss:Kmz4md67r66n2:0:1:Operator:/:/bin/csh daemon:*:1:1::/:
2nd
We wish to look up the first entry in that file that has a
user-id of zero. Note that
text type database maps are arranged in columns
that are numbered, starting with column zero. In this case, the
second column holds the user-id and the
"zeroth" column holds the name we
seek.
The F configuration command looks up the key
0 in a text type database map
found in the file /etc/passwd. The database-map
switches that prefix the filename tell sendmail to do the following:
look up the key in the second column (the -k2);
return the value from the zeroth column (the -v0);
and use a colon as the column separator (the -z:).
The text type database map and its switches are
described in text.
22.1.3.1 Class by replacing files with database lookups in mc macros
Several mc macros
are used to fill class macros with values. They are listed in Table 22-1, along with the class macros they fill. Note
that the classes shown should not be used directly because there is
no guarantee that they will continue to be available in the future.
To be safe, always use the mc macro instead. To
reinforce this precaution in the descriptions that follow, we use the
mc name for the class (as the EXPOSED_USER
class) instead of the class macro name (as the $=E
class).
It is possible to fill these class macros from database maps using
these mc macros. Instead of the file name, just
place the database lookup expression between the trailing parentheses
of the mc macro. For example, consider this way
of filling the RELAY_DOMAIN class with values from the
access database, assuming the following entry
exists in your access database:
DomainList: our.domain their.domain another.domain
Recall that the RELAY_DOMAIN class (Section 7.4.1.1)
determines which domains you want to relay for. The idea here is that
you want to fill it with the values our.domain,
their.domain, and
another.domain. You could perform that lookup
with an mc configuration line such as this:
RELAY_DOMAIN_FILE(`DomainList:@hash:/etc/mail/access')
Here, DomainList: (colon included) is the key
looked up in the hash type database-map located in
the database file /etc/mail/access. The presence
of the literal @ tells
sendmail this is a database-map lookup, and not
the name of a file to read.
To use an example from the previous section, consider adding a
user-id name to the EXPOSED_USER class (Section 4.4.1), like this:
EXPOSED_USER_FILE(`0@text:-k2 -v0 -z: /etc/passwd')
This lookup would result in the addition of the name
boss (from the previous section) to the
EXPOSED_USER class.
22.1.3.2 Class via ldap map lookups
Adding values to class
macros with ldap-type map databases is very easy.
In its simplest form, just use a literal @LDAP as the
type and nothing else:
RELAY_DOMAIN_FILE(`@LDAP')
FR@LDAP
The first form uses the mc macro
RELAY_DOMAIN_FILE to add values to the RELAY_DOMAIN class (Section 7.4.1.1). The second line adds to the same class, but
uses the F configuration command. For both lines,
the database used for the lookup is the ldap-type
database because of the literal @LDAP in both. That literal
expression causes the following default ldap
schema to be used:
-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName=R)
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j)))
-v sendmailMTAClassValue
When using the F configuration command form, you
must specify the class to be filled. For example:
F{OurStuff}@LDAP
Whichever class you specify (the {OurStuff} here)
will become the class listed with the
sendmailMTAClassName= in the default schema:
-k (&(objectClass=sendmailMTAClass)(sendmailMTAClassName={OurStuff})
(|(sendmailMTACluster=${sendmailMTACluster})(sendmailMTAHost=$j)))
-v sendmailMTAClassValue
Naturally you can bypass the default ldap
definition altogether by placing your own into the declaration.
Consider the following two lines, which do just that:
VIRTUSER_DOMAIN_FILE(`@ldap:-k (&(objectClass=virtHosts)(host=*)) -v host')
F{VirtHosts}@ldap:-k (&(objectClass=virtHosts)(host=*)) -v host
Note that by replacing the literal @LDAP with a
type declaration of
@ldap, you eliminate the automatic generation of a
default definition.
One possible pitfall is the temptation to define an identical class
macro's values in both your domain record and
individual host records. If you do, the lookup will be additive,
adding record values from both the domain and the host records.
|