aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2010-06-19 13:09:15 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2010-06-19 13:09:15 +0300
commit2022362f1c270b2c85df3b7a4c70070dddbd62c3 (patch)
tree3a2e51f95d4cd87ccd35bcb55c0fb8407723c699
parentb6d5ac0de6b88208c7c59ddcc88f8d128e6d1dd5 (diff)
downloadsmap-2022362f1c270b2c85df3b7a4c70070dddbd62c3.tar.gz
smap-2022362f1c270b2c85df3b7a4c70070dddbd62c3.tar.bz2
Fix invocation of database initialization methods. Update server docs.
* include/smap/module.h (smap_module) <smap_init_db>: Change signature: pass database name as the first argument. * modules/echo/echo.c (echo_init_db): Update signature. * modules/guile/getpw.scm (smap-open): Likewise. * modules/guile/guile.c (_guile_database)<dbname>: new member. (call_init_handler): Pass #f if dbname is NULL. (guile_init_db): Initialize db->dbname; fix invocation of init_fun. * modules/mailutils/mailutils.c (_mu_smap_db)<id>: New member. (_mu_smap_result)<db>: New member. (expand_reply_text): Initialize "db" key to the name of the database. (_mu_auth_query, _mu_mbq_query): Set res.db (mod_mailutils_init_db): Update signature. Initialize db->id. * doc/ex-meta1.texi: New file. * doc/Makefile.am (smap_TEXINFOS): Add ex-meta1.texi. * doc/smap.texi: Finish server documentation.
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/ex-meta1.texi213
-rw-r--r--doc/smap.texi425
-rw-r--r--include/smap/module.h2
-rw-r--r--modules/echo/echo.c2
-rw-r--r--modules/guile/getpw.scm5
-rw-r--r--modules/guile/guile.c15
-rw-r--r--modules/mailutils/mailutils.c8
-rw-r--r--src/module.c5
9 files changed, 659 insertions, 19 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 23af475..1a6e3b0 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -15,13 +15,14 @@
# along with Smap. If not, see <http://www.gnu.org/licenses/>.
info_TEXINFOS=smap.texi
smap_TEXINFOS=\
fdl.texi\
sockmap.texi\
- debugcat.texi
+ debugcat.texi\
+ ex-meta1.texi
EXTRA_DIST = \
gendocs_template\
mastermenu.el\
untabify.el\
smapflow.txt\
diff --git a/doc/ex-meta1.texi b/doc/ex-meta1.texi
new file mode 100644
index 0000000..905e135
--- /dev/null
+++ b/doc/ex-meta1.texi
@@ -0,0 +1,213 @@
+@c This file is part of the Smap manual.
+@c Copyright (C) 2010 Sergey Poznyakoff
+@c See file smap.texi for copying conditions.
+@c *******************************************************************
+ In this appendix we will show how to use the @samp{mailutils}
+module (@pxref{mailutils module}) to configure local user and alias maps for
+@acronym{MeTA1}. For this purpose, we will assume that the actual
+data is stored in two tables in a @acronym{MySQL} database. The two
+maps will be served by two separate databases, each of which uses a
+separate configuration file.
+
+@menu
+* userdb-meta1:: Configure local_user_map.
+* aliases-meta1:: Configure aliases.
+* smapd-meta1:: Smapd configuration.
+* conf-meta1:: Configure MeTA1.
+@end menu
+
+@node userdb-meta1
+@appendixsec Configure local_user_map.
+
+Let's configure @samp{local_user_map} first. User data will be
+stored in the table @samp{userdb}, which has the following structure:
+
+@example
+@group
+CREATE TABLE userdb (
+ user varchar(32) NOT NULL default '',
+ mailbox text
+ PRIMARY KEY (user)
+);
+@end group
+@end example
+
+Module configuration file @file{/etc/mailutils.d/meta1-userdb}
+begins with the following stanza:
+
+@example
+@group
+auth @{
+ authentication clear;
+ authentication sql;
+ authorization clear;
+ authorization sql;
+@}
+@end group
+@end example
+
+This clears any previous settings that the authorization engine might
+have read from the main configuration file, and requests that only
+@samp{sql} method be used for both authentication and authorization.
+
+Now, we need to supply a @samp{sql} statement. Mailutils requires
+that the @code{getpwnam} query return at least six fields, whereas the
+@samp{userdb} table contains only two columns. So we will need to supply
+defaults for the remaining four:
+
+@example
+sql @{
+ interface mysql;
+ host sql.host.name
+ user smap;
+ passwd guessme;
+ db mail;
+ getpwnam "SELECT user as name, 'x' as passwd,10000 as uid, 10000 as gid, "
+ "'/nonexistent' as dir, '/sbin/nologin' as shell "
+ "FROM userdb WHERE user='$@{user@}'";
+@};
+@end example
+
+ That's all we need to have in @file{/etc/mailutils.d/meta1-userdb}.
+
+@node aliases-meta1
+@appendixsec Configure aliases
+
+We are going to store aliases in the table @samp{aliases} which has
+the following structure:
+
+@example
+@group
+CREATE TABLE userdb (
+ user varchar(32) NOT NULL default '',
+ alias text
+ PRIMARY KEY (user)
+);
+@end group
+@end example
+
+It will be served by @samp{alias} database, which will read
+the configuration for Mailutils from the file
+@file{/etc/mailutils.d/meta1-alias}. This file is similar to
+@file{meta1-userdb}, but uses a different query in its @samp{sql}
+section:
+
+@example
+auth @{
+ authentication clear;
+ authentication sql;
+ authorization clear;
+ authorization sql;
+@}
+
+sql @{
+ interface mysql;
+ host sql.host.name
+ user smap;
+ passwd guessme;
+ db mail;
+ getpwnam "SELECT alias as name, 'x' as passwd,1 as uid, 1 as gid, "
+ "'/nonexistent' as dir, '/sbin/nologin' as shell "
+ "FROM aliases WHERE name='$@{user@}'";
+@}
+@end example
+
+@node smapd-meta1
+@appendixsec Smapd configuration
+
+ Let's now configure @file{smapd.conf}. Suppose it will run a single
+server, which we will call @samp{local}. The server will listen on a
+UNIX socket @file{/var/spool/meta1/smap/userdb}. It is important that
+@samp{meta1} be able to read from and write to that socket, so we will make
+it owned by user @samp{meta1m}:
+
+@example
+server local unix:///var/spool/meta1/smap/userdb begin
+ user meta1m
+end
+@end example
+
+ Next task is to configure the databases. The @samp{userdb} database is
+pretty simple:
+
+@example
+database userdb mailutils mode=auth \
+ config-file=/etc/mailutils.d/meta1-userdb
+@end example
+
+ It will return @samp{OK} if the user is found in the database and
+@samp{NOTFOUND} otherwise, which is exactly what the @acronym{MTA} needs.
+
+ The @samp{aliasdb} database is a bit different. In case of a
+positive reply, it must return the expanded alias value, so we need to
+supply a new @samp{positive-reply} template:
+
+@example
+database aliasdb mailutils mode=auth \
+ config-file=/usr/local/etc/mailutils.d/meta1-alias \
+ positive-reply="OK $@{name@}"
+@end example
+
+ The @samp{$@{name@}} will be replaced with the value of the first
+column in the tuple returned by the @acronym{SQL} database
+(@pxref{aliases-meta1, getpwnam}).
+
+ To dispatch queries to these databases, the following rules will
+suffice:
+
+@example
+dispatch map alias database aliasdb
+dispatch map userdb database userdb
+@end example
+
+@node conf-meta1
+@appendixsec MeTA1 configuration
+
+ Finally we need to inform @acronym{MeTA1} about new maps. This is
+done in the file @file{/etc/meta1/meta1.conf}, section @samp{smar}.
+
+ First, the @samp{userdb} map:
+
+@example
+ map password @{ type = passwd; @}
+ map userdb @{
+ type = socket;
+ path = "/var/spool/meta1/smap/userdb";
+ mapname = userdb;
+ @}
+ map locusr @{
+ type = sequence;
+ maps = @{ password, userdb @};
+ @}
+
+ local_user_map @{
+ name = "locusr";
+ flags = @{ localpart, local_domains @};
+ @}
+@end example
+
+As a result, @acronym{MeTA1} will look up users in the system database
+first, and, if that fails, in the @acronym{SQL} database.
+
+ Next, the @samp{aliasdb} map:
+
+@example
+ map lum @{
+ type = socket;
+ path = "/var/spool/meta1/smap/userdb";
+ mapname = aliases;
+ @}
+ map stdal @{ file = "aliases.db"; type = hash; @}
+ map aliasmap @{ type = sequence; maps = @{ lum, stdal @}; @}
+ aliases @{
+ name = aliasmap;
+ flags = @{ localpart, local_domains @};
+ @}
+@end example
+
+ As for @samp{userdb}, this map declaration also uses two different
+databases. First, it asks @command{smapd} to find the alias. If it
+returns a negative reply, the map falls back to the default
+@file{aliases.db} database.
+
+
diff --git a/doc/smap.texi b/doc/smap.texi
index dedc910..e16343b 100644
--- a/doc/smap.texi
+++ b/doc/smap.texi
@@ -79,12 +79,13 @@ documents Smap @value{VERSION}.
* modules:: Modules Shipped with Smap
* smapc:: Socket Map Client
* Reporting Bugs:: How to Report a Bug
Appendices
+* MeTA1:: Example: Using @command{smapd} with MeTA1
* Protocol:: The Sockmap Protocol
* Debug Categories:: Debug Categories
* Copying This Manual:: The GNU Free Documentation License
* Concept Index:: Index of Concepts
@detailmenu
@@ -99,12 +100,33 @@ The Socket Map Server
* servers:: Server Configuration.
* loadable modules:: Loadable Modules.
* databases:: Databases.
* dispatch rules:: Query Dispatch Rules.
* exit codes:: Smapd Exit Codes.
+Modules Shipped with Smap
+
+* echo module::
+* mailutils module::
+* guile module::
+
+The @samp{mailutils} Module
+
+* expansion:: Variable Expansion
+* load-mailutils:: Loading Sequence
+* db-mailutils:: Mailutils Databases
+* auth:: Mailutils Auth Mode
+* mbq:: Mailutils MBQ Mode
+
+Example: Using @command{smapd} with MeTA1
+
+* userdb-meta1:: Configure local_user_map.
+* aliases-meta1:: Configure aliases.
+* smapd-meta1:: Smapd configuration.
+* conf-meta1:: Configure MeTA1.
+
The Sockmap Protocol
* Sendmail Status Codes::
* MeTA1 Status Codes::
* Mailfromd Status Codes::
@@ -1405,19 +1427,22 @@ dispatch default database default
(@uref{http://www.gnu.org/software/mailutils}) and provides two main
modes:
@table @samp
@item auth
This mode uses GNU Mailutils authorization mechanism to obtain
-user data (similar to the system @samp{getpwnam} routine).
+user data (similar to the system @samp{getpwnam} routine) and returns
+positive reply if the data were retrieved and negative reply
+otherwise. @xref{MeTA1}, for an example on how to use it as a local
+user and alias database.
@item mbq
This mode allows to check whether the user's mailbox exceeded the
allotted quota, and if not, whether it is able to accept a message
of the given size without exceeding it. The mode name is an
-abbreviation of @dfn{Mailbox Quota}.
+abbreviation of @dfn{Mailbox Quota}.
@end table
@menu
* expansion:: Variable Expansion
* load-mailutils:: Loading Sequence
* db-mailutils:: Mailutils Databases
@@ -1430,12 +1455,14 @@ abbreviation of @dfn{Mailbox Quota}.
In the discussion below we often refer to @dfn{meta-variable
expansion} in strings. This is a process, whereby any sequence
@samp{$@{@var{variable}@}} is replaced with the value of
@var{variable}. The defined variables are:
@table @asis
+@item db
+The database name.
@item map
The map name.
@item key
The lookup key.
@item diag
If the key was not found or some error occurred, this variable expands
@@ -1588,21 +1615,405 @@ Default string is @samp{NOTFOUND}, unless overridden by the
module-level @option{positive-reply} option (@pxref{db-mailutils,
onerr-reply}.
@end table
@node auth
@subsection Mailutils Auth Mode
-FIXME
+ Mailutils module in @samp{auth} mode uses GNU Mailutils
+authorization mechanism to obtain user data. It returns
+@samp{positive-reply} if the data were retrieved and @samp{negative-reply}
+otherwise. This mode is often used for databases of local users and
+aliases. The key is normally a user name (either local part or fully
+qualified).
+
+ @xref{MeTA1}, for an example on how to use it.
@node mbq
@subsection Mailutils MBQ Mode
-FIXME
+ @acronym{MBQ}, or @dfn{Mailbox Quota} mode, uses key as the name of
+a local user. It obtains the user parameters via Mailutils
+authorization mechanism and then switches to this user privileges and
+opens his mailbox for a brief period of time. After opening it
+determines the mailbox size and closes it. The mode returns
+@samp{positive-reply} if the mailbox size is less than the quota,
+and @samp{netagive-reply} otherwise.
+
+If the key value consists of two words, separated by whitespace,
+then the first word is used as a user name, and the second one as
+a size of a message which is about to be delivered to that user's
+mailbox (the size may be optionally prefixed by @samp{SIZE=}). In
+this case, @samp{positive-reply} is returned if the actual mailbox
+size plus the message size is less than quota.
+
+Two additional meta-variables may be used in reply templates to return
+quota-related information:
+
+@table @asis
+@item mbsize
+Mailbox size, in bytes. Defined only in @samp{mbq} mode.
+@item msgsize
+Expected message size, in bytes. Defined only in @samp{mbq} mode.
+@end table
+
+The following example shows a definition of @samp{mbq} database which
+the author uses on his servers:
+
+@example
+database mbq mailutils mode=mbq \
+ positive-reply="OK [$@{diag@}] $@{mailbox@} $@{mbsize@} $@{quota@}"\
+ negative-reply="NOTFOUND [$@{diag@}] $@{mailbox@} $@{mbsize@} $@{quota@}"\
+ onerror-reply="NOTFOUND [$@{diag@}]"
+@end example
+
+The @samp{diag} meta-variable contains a diagnostic string suitable
+for passing it back to the @acronym{MTA}. For example, in the case
+of @samp{negative-reply}, @samp{$@{diag@}} expands to:
+
+@example
+mailbox quota exceeded for this recipient
+@end example
+
+@noindent
+if the mailbox has grown beyond the allowed quota, and
+
+@example
+message would exceed maximum mailbox size for this recipient
+@end example
+
+@noindent
+if message of the given size cannot be delivered to mailbox without
+violating its quota.
+
+ Notice, that this mode requires superuser privileges.
@node guile module
@section The @samp{guile} Module
-FIXME
+ @dfn{Guile} is an acronym for @dfn{GNU's Ubiquitous Intelligent
+Language for Extensions}. It provides a Scheme interpreter conforming
+to the R5RS language specification and a number of convenience
+functions. For information about the language, refer to
+@ref{Top,,,r5rs,Revised(5) Report on the Algorithmic Language Scheme}.
+For a detailed description of Guile and its features, see
+@ref{Top,,Overview,guile,The Guile Reference Manual}.
+
+ The @command{guile} module provides an interface to Guile which
+allows for writing Smap modules in Scheme. The module is loaded
+using the following configuration file statement:
+
+@example
+module @var{name} guile [@var{args}]
+@end example
+
+ Optional @var{args} are:
+
+@table @option
+@kwindex debug
+@item debug
+ Enable Guile debugging and stack traces.
+
+@kwindex nodebug
+@item nodebug
+ Disable Guile debugging and stack traces (default).
+
+@kwindex load-path
+@item load-path=@var{path}
+ Append directories from @var{path} to the list of directories which
+should be searched for Scheme modules and libraries. The @var{path}
+must be a list of directory names, separated by colons.
+
+ This option modifies the value of Guile's @code{%load-path}
+variable.
+@c FIXME: Texi2html is unable to handle \, in the section title. This
+@c conditional overrides this bug.
+@ifnothtml
+@xref{Build Config, %load-path,
+{Configuration\, Build and Installation}, guile, The Guile Reference Manual}.
+@end ifnothtml
+@ifhtml
+See the section @uref{http://www.gnu.org/software/guile/manual/html_node/Build-Config.html, Configuration and Installation} in the Guile Reference Manual.
+@end ifhtml
+
+@kwindex init-script
+@item init-script=@var{script}
+ Specifies the name of a Scheme source file that must be loaded in
+order to initialize the module. The file is looked up using
+@samp{%load-path} variable.
+
+@kwindex init-args
+@item init-args
+ The @code{init-args} parameter supplies additional arguments to the
+module. They will be accessible to the @file{@var{script}} via
+the @code{command-line} function.
+
+@kwindex init-fun
+@item init-fun
+ This parameter specifies the name of a function that
+will be invoked to perform the initialization of the module and of
+particular databases. Default name is @samp{init}. @xref{Guile
+Initialization}, for a description of initialization sequence.
+@end table
+
+ Guile databases are declared using the following syntax:
+
+@anchor{guile-cmdline}
+@example
+database @var{dbname} @var{modname} [@var{args}] [@var{cmdline}]
+@end example
+
+where: @var{dbname} gives the name for this database and @var{modname}
+is the name given to Guile module in @code{module} statement (see
+above).
+
+@kwindex init-script
+@kwindex init-args
+@kwindex init-fun
+Optional @var{args} override global settings given in the
+@code{module} statement. The following options are understood:
+@code{init-script}, @code{init-args}, and @code{init-fun}. Their
+meaning is the same as for @code{module} statement (see above),
+except that they affect only this particular database.
+
+Any additional arguments, referenced as @var{cmdline} above, are
+be passed to the Guile @code{open-db} callback function (@pxref{open-db}).
+
+@menu
+* Virtual Functions::
+* Guile Output Ports::
+* Guile Initialization::
+* Guile API::
+@c * Guile Example Module::
+@end menu
+
+@node Virtual Functions
+@subsection Virtual Functions
+@cindex virtual functions, guile module
+ Any database handled by @command{guile} module is associated with a
+@var{virtual function table}. This table is an association list which
+supplies to the module the Scheme @dfn{call-back functions} implemented to
+perform particular tasks on that database. In this list,
+the @code{car} of each element contains the name of a function, and
+its @code{cdr} gives the corresponding function. The defined function
+names and their semantics are described in the following table:
+
+@table @asis
+@item init
+Initialize the module.
+
+@item done
+Close the module, releasing any resources held by it.
+
+@item open
+Open the database.
+
+@item close
+Close the database.
+
+@item query
+Handle a socket map query
+@end table
+
+For example, the following is a valid virtual function table:
+
+@lisp
+@group
+(list (cons "open" open-module)
+ (cons "close" close-module)
+ (cons "query" run-query))
+@end group
+@end lisp
+
+Apart from per-database virtual tables, there is also a global
+virtual function table, which is used to supply the entries missing in
+the former. Both tables are created during the module initialization,
+as described in the next subsection.
+
+Particular virtual functions are described in @ref{Guile API}.
+
+@node Guile Output Ports
+@subsection Guile Output Ports
+ Guile modules are executed in a specially prepared environment.
+Current error port is redirected so that everything written to it ends
+up in the @command{smapd} error stream. So, if @command{smapd} is
+writing its log to syslog, everything you write to
+@samp{(current-error-port)} will be written to syslog as well. The
+port is line-buffered. For example, the following code:
+
+@lisp
+(with-output-to-port
+ (current-error-port)
+ (lambda ()
+ (display "The diagnostics follows:")
+ (newline)
+ (display "Module opened")
+ (newline)))
+@end lisp
+
+@noindent
+will result in two lines in your syslog file, which will look like
+
+@example
+@group
+Jun 19 12:49:05 netbox smapd[7503]: The diagnostics follows
+Jun 19 12:49:05 netbox smapd[7503]: Module opened
+@end group
+@end example
+
+@kwindex smap-debug-port
+For any debugging output, use @code{smap-debug-port}. This port is
+configured so that everything written to it is explicitly marked as
+being debug output. If @command{smapd} logs to stderr, it will be
+prefixed with @samp{DEBUG:}, and if it logs to syslog, the output will
+be logged with @samp{LOG_DEBUG} priority.
+
+Finally, current output port is closed for any functions, excepting
+@samp{query} (@pxref{query-db}). For @samp{query} function, it is
+redirected so that anything written to it is reformatted according to
+the socket map protocol (@pxref{Protocol}) and sent back as a reply to
+the client.
+
+@node Guile Initialization
+@subsection Guile Initialization
+ The @code{module} configuration statement causes loading and
+initialization of the @command{guile} module:
+
+@example
+@group
+module @var{modname} guile [init-script=@file{@var{script}}] \
+ [init-fun=@var{function}"]
+@end group
+@end example
+
+@kwindex init-script
+@kwindex init-fun
+ Upon module initialization stage, the module attempts to load the
+file named @file{@var{script}}. The file is loaded using
+@code{primitive-load-path} call (@pxref{Loading, primitive-load-path, Loading,
+guile, The Guile Reference Manual}), i.e. it is searched in the Guile
+load path. The @code{init-fun} parameter supplies the name of the
+@dfn{initialization function}. This Scheme function returns virtual
+function tables for the module itself and for each database that uses
+this module. It must be declared as follows:
+
+@lisp
+(define (@var{function} arg)
+ @dots{})
+@end lisp
+
+This function is called several times. First of all, it is called after
+@var{script} is loaded. This time it is given @code{#f} as its
+argument, and its return value is saved as a global function table.
+Then, it is called for each @code{database} statement that uses module
+@var{modname} (defined in the @code{module} statement above), e.g.:
+
+@example
+database @var{dbname} @var{modname} @dots{}
+@end example
+
+This time, it is given @var{dbname} as its argument and its return is
+stored as the virtual function table for this particular database.
+
+The following example function returns a complete virtual function table:
+
+@lisp
+@group
+(define (my-smap-init arg)
+ (list (cons "init" db-init)
+ (cons "done" db-done)
+ (cons "open" db-open)
+ (cons "close" db-close)
+ (cons "query" db-query)))
+@end group
+@end lisp
+
+@node Guile API
+@subsection Guile API
+@cindex Guile API
+
+ This subsection describes callback functions that a Guile
+database module must provide. The description of each function begins
+with the function prototype and its entry in the virtual function
+table.
+
+
+@anchor{open-db}
+@deffn {Guile Callback} open-db name . args
+Virtual table: @code{(cons "open" open-db)}@*
+
+Open the database. The argument @var{name} contains database name as
+given in @code{dbname} of the @code{database} declaration
+(@pxref{databases}). Optional argument @var{args} is a list of
+command line parameters obtained from @var{cmdline} in @code{database}
+statement (@pxref{guile-cmdline}). For example, if the configuration
+file contained:
+
+@example
+database foo guile db=file 1 no
+@end example
+
+@noindent
+then the @code{open-db} callback will be called as:
+
+@lisp
+(open-db "foo" '("db=file" "1" "no"))
+@end lisp
+
+The @code{open-db} callback returns a @dfn{database handle}, i.e. an
+opaque Scheme object which identifies this database, and keeps its
+internal state. This value, hereinafter named @var{dbh},
+will be passed to another callback functions that need to access the
+database.
+
+The unspecified return value indicates an error.
+@end deffn
+
+@deffn {Guile Callback} close-db dbh
+Virtual Table: @code{(cons "close" close-db)}@*
+
+Close the database. This function is called during the cleanup
+procedure, before termination of @code{smapd} child process. The
+argument @code{dbh} is a database handle returned by @code{open-db}.
+
+The return value from @code{close-db} is ignored. To communicate
+errors to the daemon, throw an exception.
+@end deffn
+
+@anchor{query-db}
+@deffn {Guile Callback} query-db dbh map key . rest
+Virtual Table: @code{(cons "close" close-db)}@*
+ Perform the query. Arguments are:
+
+@table @var
+@item dbh
+A database handle returned by @code{open-db}.
+
+@item map
+The map name.
+
+@item key
+The lookup key
+
+@item rest
+If this query came over a UNIX socket, this argument is @samp{()}.
+Otherwise, if the query came over an INET socket, @var{rest} is a list
+of two network socket addresses (@pxref{Network Socket
+Address,,,guile, The Guile Reference Manual}): first element is the
+address of the remote party (client), second element is the address of
+the server that is handling the query.
+@end table
+
+ This function must write the reply, terminated with a newline, to
+the current output port, e.g.:
+
+@lisp
+@group
+(define-public (smap-query handle map arg . rest)
+ (display "NOTFOUND")
+ (newline))
+@end group
+@end lisp
+@end deffn
@node smapc
@chapter Socket map client
FIXME
@node Reporting Bugs
@@ -1618,12 +2029,16 @@ information needed is:
@item Compilation options used when configuring it.
@item Run-time configuration (the @file{smapd.conf} file and command
line options used).
@item Conditions under which the bug appears.
@end itemize
+@node MeTA1
+@appendix Example: Using @command{smapd} with MeTA1
+@include ex-meta1.texi
+
@node Protocol
@appendix The Sockmap Protocol
@include sockmap.texi
@node Debug Categories
@appendix Debug Categories
diff --git a/include/smap/module.h b/include/smap/module.h
index 5c265b8..120bf6e 100644
--- a/include/smap/module.h
+++ b/include/smap/module.h
@@ -36,13 +36,13 @@ struct smap_conninfo {
};
struct smap_module {
unsigned smap_version;
unsigned smap_capabilities; /* Unused so far */
int (*smap_init)(int argc, char **argv);
- smap_database_t (*smap_init_db)(int argc, char **argv);
+ smap_database_t (*smap_init_db)(const char *dbid, int argc, char **argv);
int (*smap_free_db)(smap_database_t dbp);
int (*smap_open) (smap_database_t hp);
int (*smap_close) (smap_database_t hp);
int (*smap_query)(smap_database_t dbp,
smap_stream_t ostr,
const char *map, const char *key,
diff --git a/modules/echo/echo.c b/modules/echo/echo.c
index 3cff90c..ad1d770 100644
--- a/modules/echo/echo.c
+++ b/modules/echo/echo.c
@@ -26,13 +26,13 @@
struct echo_database {
int argc;
char **argv;
};
static smap_database_t
-echo_init_db(int argc, char **argv)
+echo_init_db(const char *dbid, int argc, char **argv)
{
struct echo_database *db = malloc(sizeof(*db));
if (!db) {
smap_error("not enough memory");
return NULL;
}
diff --git a/modules/guile/getpw.scm b/modules/guile/getpw.scm
index e628ed0..2fd4a44 100644
--- a/modules/guile/getpw.scm
+++ b/modules/guile/getpw.scm
@@ -20,16 +20,17 @@
;;;; groups NAME - return the list of group names for the user NAME.
(use-modules (srfi srfi-1))
;;; This function is called after by the smap subprocess before
;;; entering main loop.
-(define (smap-open . rest)
+(define (smap-open dbname . rest)
;; Everything you write to the standard error port is sent to the
;; smapd error output.
- (format (current-error-port) "smap-open called; arguments: ~A~%" rest)
+ (format (current-error-port) "smap-open called; dbname=~A, arguments: ~A~%"
+ dbname rest)
#t)
;;; This function is called after by the smap subprocess after
;;; exiting from the event loop, and before terminating.
(define (smap-close handle)
(format (current-error-port) "smap-close called~%"))
diff --git a/modules/guile/guile.c b/modules/guile/guile.c
index 5696653..4853ee5 100644
--- a/modules/guile/guile.c
+++ b/modules/guile/guile.c
@@ -321,14 +321,14 @@ static int guile_debug;
static char *guile_init_script;
static char *guile_init_args;
static char *guile_init_fun = "init";
static char *guile_load_path;
enum guile_proc_ind {
- init_proc,
- done_proc,
+ init_proc, /* FIXME: this one is not yet used */
+ done_proc, /* FIXME: this one too */
open_proc,
close_proc,
query_proc
};
#define MAX_PROC (query_proc+1)
@@ -341,12 +341,13 @@ static char *guile_proc_name[] = {
};
typedef SCM guile_vtab[MAX_PROC];
struct _guile_database {
guile_vtab vtab;
+ const char *dbname;
int argc;
char **argv;
int oport_inited;
SCM handle;
};
@@ -376,13 +377,13 @@ call_init_handler(void *data)
struct init_struct *p = (struct init_struct *)data;
SCM procsym = SCM_VARIABLE_REF(scm_c_lookup(p->init_fun));
SCM arg;
if (p->db_name)
arg = scm_from_locale_string(p->db_name);
else
- arg = SCM_EOL;
+ arg = SCM_BOOL_F;
return scm_apply_0(procsym, scm_list_1(arg));
}
static int
init_vtab(const char *init_fun, const char *dbname, guile_vtab vtab)
{
@@ -482,13 +483,13 @@ guile_init(int argc, char **argv)
return 1;
}
return 0;
}
static smap_database_t
-guile_init_db(int argc, char **argv)
+guile_init_db(const char *dbname, int argc, char **argv)
{
struct _guile_database *db;
int i;
char *init_script = NULL;
char *init_args = NULL;
char *init_fun = guile_init_fun;
@@ -513,18 +514,19 @@ guile_init_db(int argc, char **argv)
db = malloc(sizeof(*db));
if (!db) {
smap_error("guile: not enough memory");
return NULL;
}
+ db->dbname = dbname;
db->argc = argc;
db->argv = argv;
db->oport_inited = 0;
db->handle = SCM_UNSPECIFIED;
memcpy(db->vtab, global_vtab, sizeof(db->vtab));
- if (init_fun && init_vtab(init_fun, argv[0], db->vtab)) {
+ if (init_fun && init_vtab(init_fun, dbname, db->vtab)) {
free(db);
return NULL;
}
if (!db->vtab[query_proc]) {
smap_error("guile: %s: %s: void virtual function",
@@ -547,13 +549,14 @@ guile_free_db(smap_database_t hp)
static int
guile_open(smap_database_t dp)
{
struct _guile_database *db = (struct _guile_database *)dp;
if (db->vtab[open_proc]) {
if (guile_call_proc(&db->handle, db->vtab[open_proc],
- argv_to_scm(db->argc, db->argv)))
+ scm_cons(scm_from_locale_string(db->dbname),
+ argv_to_scm(db->argc, db->argv))))
return 1;
if (db->handle == SCM_UNSPECIFIED)
return 1;
scm_gc_protect_object(db->handle);
}
return 0;
diff --git a/modules/mailutils/mailutils.c b/modules/mailutils/mailutils.c
index 78fed0d..1423227 100644
--- a/modules/mailutils/mailutils.c
+++ b/modules/mailutils/mailutils.c
@@ -34,21 +34,23 @@ static size_t dbgid;
typedef int (*query_fun_t)(smap_database_t dbp,
smap_stream_t ostr,
const char *map, const char *key,
struct smap_conninfo const *conninfo);
struct _mu_smap_db {
+ const char *id;
char *positive_reply;
char *negative_reply;
char *onerror_reply;
char *config_file;
int config_flags;
query_fun_t qfn;
};
struct _mu_smap_result {
+ const char *db;
const char *map;
const char *key;
struct mu_auth_data *auth;
mu_url_t url;
mu_off_t mbsize;
size_t msgsize;
@@ -73,12 +75,13 @@ expand_reply_text(const char *arg, struct _mu_smap_result *res)
char buf[512];
struct mu_auth_data *auth = res->auth;
if (!arg)
return NULL;
mu_vartab_create(&vtab);
+ mu_vartab_define(vtab, "db", res->db, 0);
mu_vartab_define(vtab, "key", res->key, 0);
mu_vartab_define(vtab, "map", res->map, 0);
mu_vartab_define(vtab, MU_AUTH_NAME, auth ? auth->name : "", 0);
mu_vartab_define(vtab, MU_AUTH_PASSWD, auth ? auth->passwd : "", 0);
if (!auth)
strcpy(buf, "-1");
@@ -125,12 +128,13 @@ _mu_auth_query(smap_database_t dbp,
{
struct _mu_smap_db *mdb = (struct _mu_smap_db *)dbp;
struct mu_auth_data *auth = mu_get_auth_by_name(key);
struct _mu_smap_result res;
char *reply;
+ res.db = mdb->id;
res.map = map;
res.key = key;
res.auth = auth;
res.mbsize = 0;
res.msgsize = 0;
res.diag = NULL;
@@ -262,12 +266,13 @@ _mu_mbq_query(smap_database_t dbp,
char *p;
size_t len;
struct _mu_smap_result res;
char *reply;
memset(&res, 0, sizeof(res));
+ res.db = mdb->id;
res.map = map;
res.key = key;
len = strcspn(user, " \t");
if (user[len]) {
char *q;
@@ -459,13 +464,13 @@ mod_mailutils_init(int argc, char **argv)
cfg_param, cfgflags, NULL);
mu_gocs_flush();
return !!(rc || mu_cfg_error_count);
}
static smap_database_t
-mod_mailutils_init_db(int argc, char **argv)
+mod_mailutils_init_db(const char *dbid, int argc, char **argv)
{
struct _mu_smap_db *db;
char *positive_reply = NULL;
char *negative_reply = NULL;
char *onerror_reply = NULL;
#define MODE_AUTH 0
@@ -499,12 +504,13 @@ mod_mailutils_init_db(int argc, char **argv)
db = malloc(sizeof(*db));
if (!db) {
mu_error("not enough memory");
return NULL;
}
+ db->id = dbid;
db->positive_reply = positive_reply ?
positive_reply : strdup(dfl_positive_reply);
db->negative_reply = negative_reply ?
negative_reply : strdup(dfl_negative_reply);
db->onerror_reply = onerror_reply ?
onerror_reply : strdup(dfl_onerror_reply);
diff --git a/src/module.c b/src/module.c
index 1352bc5..a40182f 100644
--- a/src/module.c
+++ b/src/module.c
@@ -277,14 +277,15 @@ init_databases()
if (!inst)
smap_error("%s:%u: module %s is not declared",
p->file, p->line, p->modname);
else {
debug(DBG_DATABASE,