From 2022362f1c270b2c85df3b7a4c70070dddbd62c3 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sat, 19 Jun 2010 13:09:15 +0300 Subject: Fix invocation of database initialization methods. Update server docs. * include/smap/module.h (smap_module) : 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): 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): New member. (_mu_smap_result): 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. --- doc/Makefile.am | 3 +- doc/ex-meta1.texi | 213 +++++++++++++++++++++ doc/smap.texi | 425 +++++++++++++++++++++++++++++++++++++++++- include/smap/module.h | 2 +- modules/echo/echo.c | 2 +- modules/guile/getpw.scm | 5 +- modules/guile/guile.c | 15 +- modules/mailutils/mailutils.c | 8 +- src/module.c | 5 +- 9 files changed, 659 insertions(+), 19 deletions(-) create mode 100644 doc/ex-meta1.texi diff --git a/doc/Makefile.am b/doc/Makefile.am index 23af475..1a6e3b0 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -18,7 +18,8 @@ info_TEXINFOS=smap.texi smap_TEXINFOS=\ fdl.texi\ sockmap.texi\ - debugcat.texi + debugcat.texi\ + ex-meta1.texi EXTRA_DIST = \ gendocs_template\ 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 @@ -82,6 +82,7 @@ documents Smap @value{VERSION}. Appendices +* MeTA1:: Example: Using @command{smapd} with MeTA1 * Protocol:: The Sockmap Protocol * Debug Categories:: Debug Categories * Copying This Manual:: The GNU Free Documentation License @@ -102,6 +103,27 @@ The Socket Map Server * 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:: @@ -1408,13 +1430,16 @@ 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 @@ -1433,6 +1458,8 @@ expansion} in strings. This is a process, whereby any sequence @var{variable}. The defined variables are: @table @asis +@item db +The database name. @item map The map name. @item key @@ -1591,15 +1618,399 @@ onerr-reply}. @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 @@ -1621,6 +2032,10 @@ 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 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 @@ -39,7 +39,7 @@ 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); 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 @@ -29,7 +29,7 @@ struct echo_database { }; 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) { 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 @@ -23,10 +23,11 @@ ;;; 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 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 @@ -324,8 +324,8 @@ 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 @@ -344,6 +344,7 @@ typedef SCM guile_vtab[MAX_PROC]; struct _guile_database { guile_vtab vtab; + const char *dbname; int argc; char **argv; int oport_inited; @@ -379,7 +380,7 @@ call_init_handler(void *data) 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)); } @@ -485,7 +486,7 @@ guile_init(int argc, char **argv) } 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; @@ -516,12 +517,13 @@ guile_init_db(int argc, char **argv) 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; } @@ -550,7 +552,8 @@ 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; 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 @@ -37,6 +37,7 @@ typedef int (*query_fun_t)(smap_database_t dbp, struct smap_conninfo const *conninfo); struct _mu_smap_db { + const char *id; char *positive_reply; char *negative_reply; char *onerror_reply; @@ -46,6 +47,7 @@ struct _mu_smap_db { }; struct _mu_smap_result { + const char *db; const char *map; const char *key; struct mu_auth_data *auth; @@ -76,6 +78,7 @@ expand_reply_text(const char *arg, struct _mu_smap_result *res) 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); @@ -128,6 +131,7 @@ _mu_auth_query(smap_database_t dbp, struct _mu_smap_result res; char *reply; + res.db = mdb->id; res.map = map; res.key = key; res.auth = auth; @@ -265,6 +269,7 @@ _mu_mbq_query(smap_database_t dbp, char *reply; memset(&res, 0, sizeof(res)); + res.db = mdb->id; res.map = map; res.key = key; @@ -462,7 +467,7 @@ mod_mailutils_init(int argc, char **argv) } 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; @@ -502,6 +507,7 @@ mod_mailutils_init_db(int argc, char **argv) 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 ? diff --git a/src/module.c b/src/module.c index 1352bc5..a40182f 100644 --- a/src/module.c +++ b/src/module.c @@ -280,8 +280,9 @@ init_databases() else { debug(DBG_DATABASE, 2, ("initializing database %s", inst->id)); - - p->dbh = inst->module->smap_init_db(p->argc, + + p->dbh = inst->module->smap_init_db(p->id, + p->argc, p->argv); if (!p->dbh) smap_error("%s:%u: module %s: " -- cgit v1.2.1