3. The Socket Map Server

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 smapd to 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

3.1 Smapd Operation Modes

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 mode.

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’ file.

The inetd mode is requested from command line using the ‘--inetd’ (‘-i’) option, or from configuration file, using ‘inet-mode yes’ statement.

3.2 Logging

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, smapd sends diagnostics to syslog, using facility ‘daemon’ by default. The same applies also if its standard input is not attached to a terminal.

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,

3.3 Tracing and Debugging

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:111.67.206.187 => 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

 
--trace --trace-pattern=OK

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 smapd. 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).

3.4 Runtime Privileges

By default 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 user configuration statement:

 
user daemon

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 group statement:

 
user daemon
group mail mysql

Arguments to 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 this technique.

3.5 Server Configuration

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:

inet://ip:port

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’.

unix://pathname

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

 
unix:///var/run/smap.sock

means UNIX socket ‘/var/run/smap.sock’.

The 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.

The 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 user, allgroups and group, 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 following statement:

 
server local unix:///var/run/smap.sock begin
  user daemon
  group mail mysql
end  

This configuration works as follows. The master smapd 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 owner, below).

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 owner statement, 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 statements are:

Config: backlog number

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.

Config: reuseaddr bool

If bool is ‘yes’ reuse existing socket addresses (both INET and UNIX). This is the default.

Config: max-children number

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’.

Config: single-process bool

Operate in single-process mode. This options may become necessary only when debugging the smapd daemon. Never use it in production environment!

Config: socket-mode mode

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-------’).

Config: socket-owner user:group

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:

owner user:group

Set both owner UID and GID.

owner user

Set UID of the user user and GID of his primary group.

owner user:

Set UID of the user user, but do not change the GID.

owner :group

Set only owner GID, do not change the UID.

Note, that this statement cannot be used outside of server scope.

3.6 TCP Wrappers

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’:

 
main: ALL

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.

3.7 Loadable Modules

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 module command:

Config: module module-id module-name [args]

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:

  1. Additional search directories specified by prepend-load-path (see below);
  2. Smap module directory: ‘$prefix/lib/smap’;
  3. Additional search directories specified by append-load-path (see below);
  4. Directories specified in the environment variable LTDL_LIBRARY_PATH.
  5. The system dependent library search path (e.g. on GNU/Linux it is set by the file ‘/etc/ld.so.conf’ and the environment variable LD_LIBRARY_PATH).

Values of LTDL_LIBRARY_PATH and LD_LIBRARY_PATH must be colon-separated lists of absolute directory names, for example: ‘/usr/lib/mypkg:/lib/foo'’.

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:

  1. the libtool archive suffix ‘.la
  2. the suffix used for native dynamic libraries on the host platform, e.g.: ‘.so’, ‘.sl’, etc.

Additional search directories may be configured with prepend-load-path and append-load-path statements:

Config: prepend-load-path path

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.

Config: append-load-path path
Config: load-path path

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.

3.8 Databases

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:

Config: database dbname modname [args]

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’.

3.9 Query Dispatch Rules

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 rule, 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’.

The 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.

The server condition is often used together with from. 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.

3.10 Transformations

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).

3.11 Smapd Exit Codes

The following table summarizes exit codes used by smapd. For each code it lists its decimal number, symbolic name from the ‘sysexits.h’ header file, and its meaning.

Code Name Meaning
0 EX_OK Normal termination.
64 EX_USAGE Command line usage error.
69 EX_UNAVAILABLE Some other error occurred.
78 EX_CONFIG Errors in configuration file detected.

Footnotes

(4)

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’.

(5)

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.

(6)

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.