A Socket Map Server
|Smap Manual (split by chapter):||?|
Socket map server
smapd is the main part of the package.
When invoked, it reads the configuration file and parses its
command line to determine its configuration settings. Command line
settings override ones from the configuration file. The default
configuration file is ‘/etc/smapd.conf’(4) After that,
smapd loads the requested modules and starts operation.
In this chapter we will describe the server operation in detail. The discussion below will often refer to command line options and configuration statements, so we'll first describe shortly what are those. The formal description will be given later.
Command line options have two forms. In traditional, or short form, an option is a letter prefixed by a dash (e.g. ‘-f’). In long form, an option consists of two dashes and option name (e.g. ‘--foreground’). Both option forms allow for an argument. For more information on option syntax, see Command Line Syntax.
Configuration file uses the traditional UNIX syntax. Each statement occupies a single line. Very long lines may be split into several physical lines by ending each one with a backslash character. Comments are introduced with the ‘#’ character: the character itself and everything after it up to next newline is ignored. For a detailed description, see Smapd Configuration File.
You can instruct
smapd to read an alternative
configuration file instead of the default one. It may be necessary,
for example, to test a new configuration. To do so, use the
‘--config=file’ (‘-c file’) command line
option. Its argument specifies the file name to read, e.g.:
$ smapd -c ./mysmapd.conf
To check whether your configuration is error-free, use the
‘--lint’ (‘-t’) option. It instructs
parse the configuration file and exit after that. Any errors found
are reported on the standard error. The exit code is ‘0’ if the file
parsed without errors and ‘78’ otherwise (see section Smapd Exit Codes, for
a full list of exit codes). For example:
$ smapd -t
Of course, the two options may be used together:
$ smapd -t -c ./mysmapd.conf
or, in long form:
$ smapd --lint --config ./mysmapd.conf
There are two modes of operation. In standalone mode,
smapd detaches itself from the terminal and listens on
incoming requests in background. In other words, it becomes a
daemon. When a connection arrives, the server spawns a copy
of itself (called child process) to handle it. Thus, a number
of incoming connections are handled in parallel. This is the default
In inetd mode,
smapd does not listen on network
addresses nor becomes a daemon. Instead, it reads requests from its
standard input and sends replies on its standard output. As its name
implies, this mode is intended for use from the ‘inetd.conf’
The inetd mode is requested from command line using the ‘--inetd’ (‘-i’) option, or from configuration file, using ‘inet-mode yes’ statement.
The server determines automatically where its diagnostics output
should go. By default, it goes to standard error. However, after
detaching from the terminal in standalone mode,
sends diagnostics to syslog, using facility ‘daemon’ by default.
The same applies also if its standard input is not attached to a
Two command line options are provided to manually alter these
defaults. The ‘--stderr’ (‘-e’) option instructs
smapd to always send its diagnostics to the standard error,
In contrast, the ‘--syslog’ (‘-l’) option forces it
to use syslog.
The log facility can be changed in configuration file, using the ‘log-facility’ statement (see log-facility), or in the command line, using the ‘--log-facility’ (‘-F’) option. In both cases, the argument is the facility number or symbolic name. Valid names are: ‘user’, ‘daemon’, ‘auth’, ‘authpriv’, ‘mail’, ‘cron’, and ‘local0’ through ‘local7’.
Similarly, the log tag can also be changed, either from the configuration file, using the ‘log-tag’ statement, or from the command line, using the ‘--log-tag’ (‘-L’) option,
The amount of information logged by the server is configurable. By default, it is quite silent and outputs only diagnostics that call to special attention, such as errors and the like. You may request more information, however. For further discussion, it is convenient to introduce two main information groups: query traces and debugging information. Query traces are log messages that show received queries and corresponding replies. They look like:
user bar => NOTFOUND access connect:18.104.22.168 => OK REJECT
The part to the left of the ‘=>’ sign shows the query exactly as received from the client, i.e. the first word is the map name, and the rest of words constitute the key. The part to the right of ‘=>’ is the reply to this query.
To enable query traces, use the ‘--trace’ (‘-T’) command line option or ‘trace yes’ statement in the configuration file.
When using syslog, query traces are reported using the ‘info’ priority.
Some requests may be of particular interest to you, whereas others may not be relevant at all. There is a way to abridge the traces to show those relevant requests only. If you give the ‘--trace-pattern=pattern’ option, only those requests that begin with pattern(5) will be shown. For example, to show only positive responses, use
The same can be requested in the configuration file as well:
trace yes trace-pattern OK
Any number of ‘--trace-pattern’ options (or configuration statements) may be given. The server will log only those queries that match one of the patterns specified by them.
Debugging information is auxiliary diagnostics reflecting
various details of internal functionality of
Although aimed primarily to help in debugging the server, it may
occasionally be of use for server administrators as well.
Debugging information is requested using the ‘--debug’ (‘-d’) command line option or ‘debug’ configuration statement. In both cases, the argument is a debug specification, consisting of two parts, separated by a dot: ‘cat.lev’. The cat part is a debug category. It is either an integer number identifying the category, or its symbolic names. For a list of categories and their meaning, see Debug Categories.
The lev part is the category level, an integer specifying how much verbosity is requested from that category. The ‘0’ value means no verbosity (i.e. to disable that category), the value of ‘100’ means maximum verbosity. The convention is that levels below ‘10’ may be of occasional use for sysadmins, whereas higher values are useful only for debugging.
To enable several debug categories, use several ‘--debug’ option (or ‘debug’ configuration statements).
smapd runs with the privileges of the user that
started it. Normally, this user is root. If you wish it to switch to
some unprivileged user after startup, use the
The above example instructs
smapd to switch to the UID of
the user ‘daemon’ and to the GID of its principal group. The
rest of groups the user might be a member of is dropped. To retain
all supplementary user groups, use the
allgroup statement. Its
argument is a boolean value, i.e. ‘yes’, ‘on’,
‘true’, or ‘t’ to indicate the true value,
and ‘no’, ‘off’, ‘false’ or ‘nil’ to indicate
false. So, to switch to the user ‘daemon’ and also retain
all its supplementary groups, one would write:
user daemon allgroups yes
You may also retain only some of the user's group, or even some
groups the user is not member of. This is done using the
user daemon group mail mysql
group are any number of valid group names.
Notice, that while running
smapd with non-root privileges
might be a good idea, it may render some modules useless. For
example, the ‘mailutils’ module in ‘mbq’ mode (see section Mailutils MBQ Mode)
requires root privileges for normal operation. To allow for
such uses, instead of setting global user privileges, set them
on a per-server basis. See section Server Configuration, for a detailed discussion of
Servers are internal
smapd objects, responsible for
listening on sockets and handling socket I/O operations. Each server
has a server id, which is a unique name associated with it, and
socket address, which describes the socket this server handles.
Socket addresses are represented as URLs. Smap version 1.1 recognizes the following URL forms:
Listen on the IPv4 address ip, on the given port. IP address may be given either in “dotted-quad” notation or as a hostname. Port may be specified either as a port number, or as a name of a service from ‘/etc/services’.
Listen on the UNIX socket pathname. Notice that the name of the socket must be absolute, so you would usually have three slashes running together, e.g. the notation
means UNIX socket ‘/var/run/smap.sock’.
server statement configures servers. It takes two
mandatory arguments: the socked ID and URL, e.g.:
server main inet://10.10.1.11:3056 server local unix:///var/run/smap.sock
These statements configure two servers. The one called ‘main’ is listening on IP 10.10.1.11, port 3056. The one called ‘local’ listens on UNIX socket ‘/var/run/smap.sock’.
If a server is assigned an ‘inet’ address, access to it will be controlled by TCP wrappers. The server ID is used as daemon name. See the next section (see section TCP Wrappers) for a detailed description.
server statement has also another form, called block
form, which allows to configure more details. In this form, the
statement is given third argument – the word ‘begin’. This
statement is followed by one or more statements supplying additional
configuration for this server, followed by the word ‘end’ on a
line by itself, which closes the construct. This is illustrated in
the following example:
server local unix:///var/run/smap.sock begin backlog 10 user mail end
Statements which may be used between ‘begin’ and ‘end’ fall into two categories: privilege control statements, and socket configuration statements.
The former are
described in the previous section (see section Runtime Privileges). Syntactically
they are exactly the same as their public scope counterparts. The only
difference is that they apply only to child processes spawned to
handle connections to that particular URL. For example, consider the
server local unix:///var/run/smap.sock begin user daemon group mail mysql end
This configuration works as follows. The master
process runs with root privileges. When a connection is requested to
socket ‘/var/run/smap.sock’, the master spawns a subprocess
to handle that connection. This subprocess switches to the UID and
GID of user ‘daemon’ and retains GIDs of the groups ‘mail’
and ‘mysql’ and then enters the mail read-and-reply loop. The
ownership of the socket ‘/var/run/smap.sock’ is set to UID of
user ‘daemon’ and GID of its primary group (see also the description
Of course, the per-server privilege control statements work only if the master daemon runs with the root privileges.
The second group of server statements are socket configuration
statements. Similarly to privilege control statements, these too
may appear inside a server block statement as well as outside of it,
in the global scope (with the exception of the
which is allowed only in
server scope). When used in global
scope, they affect all
server statements. When used in
per-server context, they apply to that particular server only. These
Sets the maximum size of pending connections queue for sockets. If a connection request arrives when the queue is full, the client receives an error with an indication of ‘ECONNREFUSED’.
Default backlog is 8.
If bool is ‘yes’ reuse existing socket addresses (both INET and UNIX). This is the default.
Maximum number of children processes allowed to run simultaneously. When the actual number of children reaches number, the server stops refusing further connections until any of them terminates. The value of ‘0’ means ‘unlimited’.
The default limit is ‘128’.
Operate in single-process mode. This options may become necessary
only when debugging the
smapd daemon. Never use it in
Set file mode for UNIX socket. Specify the mode argument
either int octal notation (e.g. ‘600’), or in
chmod-style notation (e.g. ‘rw-------’).
Set socket ownership to the given user and group. This applies only to UNIX sockets. User and group may be specified either by their symbolic names or numeric IDs. Either user or group may be omitted. There are following cases:
Set both owner UID and GID.
Set UID of the user user and GID of his primary group.
Set UID of the user user, but do not change the GID.
Set only owner GID, do not change the UID.
Note, that this statement cannot be used outside of
Access to servers having addresses in ‘INET’ family is controlled using TCP wrappers(6).
This system is based on two files, called tables, containing access rules. There are two tables: the allow table, stored in file ‘/etc/hosts.allow’, and the deny table, kept in file ‘/etc/hosts.deny’. The rules in each table begin with an identifier called daemon name. Access to a Smap server is controlled by two entries: a global one, with the daemon name ‘smapd’, and per-server one, with server ID (see section server id as its daemon name. The latter takes precedence over the former. For example, if you have the following in your ‘smapd.conf’:
server main inet://192.168.10.1
and wish this server to be accessible only to machines 192.168.10.2 and 192.168.10.3, then you would add the following line to your ‘/etc/hosts.allow’:
main: 192.168.10.2 192.168.10.3
and the following line to your ‘/etc/hosts.deny’:
The former allows access from these two IPs, and the latter blocks it from any other IPs.
A detailed description of TCP wrapper table format lies outside the scope of this document. Please, see (hosts_access(5))ACCESS CONTROL FILES section `ACCESS CONTROL FILES' in hosts_access(5) man page, for details.
Mapper modules are external pieces of software designed to
handle a particular subset of map queries. They are built as
shared libraries and loaded into
smapd at startup.
Modules are loaded using the
Load module ‘module-name’. Additional arguments (args), if specified, are passed to the module initialization function.
The module-id is a unique identifier, which will subsequently be used to refer to that module.
A module load path is an internal list of directories which
smapd scans in order to find a loadable file name specified in
module statement. By default the scan order is as follows:
LD_LIBRARY_PATH must be
colon-separated lists of absolute directory names, for example:
In any of these directories,
smapd first attempts to find and
the given module-name verbatim and to load it. If this fails,
it tries to append the following suffixes to it:
Additional search directories may be configured with
Prepends the directories listed in its argument to the module load path. The path argument must be a colon-separated list of absolute directory names.
Appends the directories listed in its argument to the module load path. The path argument must be a colon-separated list of absolute directory names.
A database is a logical entity associated with a particular module, that provides a specific configuration for it. In other words, database is a configured instance of the module.
Databases are declared using the following statement:
Declare database dbname as an instance of module modname.
This module should have been declared previously using the
module statement (see section modname).
Optional args provide configuration information for the module
initialization function. They are module-specific.
To illustrate this, let's consider the ‘echo’ module, which replies to any request with a constant string supplied to it as arguments (see section echo module). The following example configures two instances of this module:
database nomap echo NOTFOUND No such map database tempfail echo TEMP Try again later
The ‘nomap’ database always sends the string ‘NOTFOUND No such map’ in reply. The ‘tempfail’ database replies with the string ‘TEMP Try again later’.
When a query arrives,
smapd uses query dispatch rules to
decide to what database to dispatch this query. Dispatch rules are
somewhat similar to ACLs: each rule consists of a set of conditions
and a target part. The rules are joined in a list. When applied to a
particular query, this list is scanned from top down. The conditions
of each rule are evaluated using the query as their argument. If all
conditions return ‘True’, then the target part of this rule
is applied. The target part may either transform the map
name and/or key value (a transformation rule), or indicate a
database to dispatch this query to (a destination rule). After
applying a transformation rule, the scanning resumes at
the next rule. Destination rules end the processing.
If the list is exhausted without having found a matching destination
smapd sends back the default ‘NOTFOUND’ reply.
Consider for example the following rule:
dispatch map eq alias database maildb
It says that if the map part of a query is the word ‘alias’, then this query must be handled by the database ‘maildb’.
map condition allows for more sophisticated comparisons.
If you use ‘like’, instead of ‘eq’, than shell-style
globbing patterns are used. For example, this rule
dispatch map like us* database user
matches queries whose map part begins with ‘us’.
Finally, you may also use regular expressions:
dispatch map regexp /(alias)|(virtusers)/ database maildb
See The map condition, for a detailed description of this condition.
Another important condition is
from. It returns ‘True’
if its argument, which is an IP address or a CIDR, matches the IP of
the machine that sent the query. For example, the following rule
directs all queries coming from IP addresses 192.168.0.1 through
192.168.0.31 to the database ‘local’:
dispatch from 192.168.0.0/27 database local
Several conditions may be used together. The result is ‘True’ if all conditions yield ‘True’. For example:
dispatch from 192.168.0.0/27 \ map regexp /^(alias)|(virtuser)$/ \ database local-maildb
This rule dispatches to the database ‘local-maildb’ all queries coming from the network 192.168.0.0/27 and having ‘alias’ or ‘virtuser’ as their map part.
server condition is often used together with
Its argument is the id of a server (see section server id)
declared in the configuration. The condition returns ‘True’ if
the query was sent to that particular server. For example:
dispatch from 192.168.0.0/27 \ server privileged database secret dispatch from 192.168.0.0/27 database public
These rules dispatch to the database ‘secret’ any queries coming from IP address in network 192.168.0.0/27 and received by the server ‘privileged’. Queries from that network accepted by another servers are dispatched to the database ‘public’. It is, of course, supposed that somewhere in the configuration file there is a declaration, that looks like
server privileged inet://192.168.0.1:3145
The result of any condition may be reverted using the ‘not’ prefix before it, e.g.:
dispatch from 192.168.0.0/27 \ not map regexp /^(alias)|(virtuser)$/ \ database user
There is a special condition which is convenient for the last rule in the list. The ‘default’ condition always returns ‘True’, so this rule:
dispatch default database nomap
will match any rule and dispatch it to a database named ‘nomap’. The ‘default’ condition cannot be combined with other conditions.
Transformations are special rules that modify the key or map value. Syntax of transformation rules is:
dispatch cond-list transform key-or-map dbname
where cond-list is a condition list, as described in the previous section, key-or-map is ‘key’ if the transformation is applied to the key value and ‘map’ if it is applied to the map name, and dbname is the name of a database that handles the transformation. For example:
dispatch key like <*> transform key dequote
This rule applies the ‘dequote’ database to any key that is enclosed in angle brackets. It is supposed that the ‘dequote’ database removes the brackets. It may be implemented using the the ‘sed’ module (see section sed module), as follows.
module sed sed database dequote sed extended 's/<(.*)>/\1/g'
The transform rules can be chained, as in the example below:
# This database removes domain part from its argument. database localpart sed 's/@.*$//' # Dispatch rules: dispatch key like <*> transform key dequote dispatch key like *@* transform key localpart dispatch default database getpwnam
As a result, the ‘getpwnam’ database will get the local part of the original key (which may be supplied in the form of an email address).
The following table summarizes exit codes used by
For each code it lists its decimal number, symbolic name from the
‘sysexits.h’ header file, and its meaning.
|64||EX_USAGE||Command line usage error.|
|69||EX_UNAVAILABLE||Some other error occurred.|
|78||EX_CONFIG||Errors in configuration file detected.|
To be precise, it is ‘sysconfdir/smapd.conf’, where sysconfdir is the name of system configuration directory, determined when configuring the package. The two most frequently used values for it are ‘/etc’ and ‘/usr/local/etc’.
Actually, the argument would better be named prefix, but I plan to implement globbing patterns (or maybe even regular expressions) in future versions, so I refer to it as pattern in anticipation.
This feature requires
smapd to be compiled with the TCP wrappers library
libwrap. It is always enabled at configure time, unless
libwrap is absent, or you explicitly disable it.
Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.