1/*++
2/* NAME
3/*	postconf_dbms 3
4/* SUMMARY
5/*	legacy support for database-defined main.cf parameter names
6/* SYNOPSIS
7/*	#include <postconf.h>
8/*
9/*	void	register_dbms_parameters(param_value, flag_parameter,
10/*					local_scope)
11/*	const char *param_value;
12/*	const char *(flag_parameter) (const char *, int, char *);
13/*	PC_MASTER_ENT *local_scope;
14/* DESCRIPTION
15/*	This module implements legacy support for database configuration
16/*	where main.cf parameter names are generated by prepending
17/*	the database name to a database-defined suffix.
18/*
19/*	Arguments:
20/* .IP param_value
21/*	A parameter value to be searched for "type:table" strings.
22/*	When a database type is found that supports legacy-style
23/*	configuration, the table name is combined with each of the
24/*	database-defined suffixes to generate candidate parameter
25/*	names for that database type.
26/* .IP flag_parameter
27/*	A function that takes as arguments a candidate parameter
28/*	name, an unused value, and a local namespace pointer. The
29/*	function will flag the parameter as "used" if it has a
30/*	"name=value" entry in the local or global namespace.
31/* .IP local_scope
32/*	The local namespace.
33/* DIAGNOSTICS
34/*	No explicit diagnostics.
35/* LICENSE
36/* .ad
37/* .fi
38/*	The Secure Mailer license must be distributed with this software.
39/* AUTHOR(S)
40/*	Wietse Venema
41/*	IBM T.J. Watson Research
42/*	P.O. Box 704
43/*	Yorktown Heights, NY 10598, USA
44/*--*/
45
46/* System library. */
47
48#include <sys_defs.h>
49#include <string.h>
50
51/* Utility library. */
52
53#include <stringops.h>
54#include <split_at.h>
55#include <mac_expand.h>
56#include <dict.h>
57
58/* Global library. */
59
60#include <mail_conf.h>
61#include <dict_proxy.h>
62#include <dict_ldap.h>
63#include <dict_mysql.h>
64#include <dict_pgsql.h>
65#include <dict_sqlite.h>
66#include <dict_memcache.h>
67
68/* Application-specific. */
69
70#include <postconf.h>
71
72 /*
73  * SLMs.
74  */
75#define STR(x)	vstring_str(x)
76
77#ifdef LEGACY_DBMS_SUPPORT
78
79 /*
80  * The legacy database interface automagically instantiates a list of
81  * parameters by prepending the table name to database-specific suffixes.
82  */
83
84/* See ldap_table(5). */
85
86static const char *ldap_suffixes[] = {
87    "bind", "bind_dn", "bind_pw", "cache", "cache_expiry", "cache_size",
88    "chase_referrals", "debuglevel", "dereference", "domain",
89    "expansion_limit", "leaf_result_attribute", "query_filter",
90    "recursion_limit", "result_attribute", "result_format", "scope",
91    "search_base", "server_host", "server_port", "size_limit",
92    "special_result_attribute", "terminal_result_attribute",
93    "timeout", "version", 0,
94};
95
96/* See mysql_table(5). */
97
98static const char *mysql_suffixes[] = {
99    "additional_conditions", "dbname", "domain", "expansion_limit",
100    "hosts", "password", "query", "result_format", "select_field",
101    "table", "user", "where_field", 0,
102};
103
104/* See pgsql_table(5). */
105
106static const char *pgsql_suffixes[] = {
107    "additional_conditions", "dbname", "domain", "expansion_limit",
108    "hosts", "password", "query", "result_format", "select_field",
109    "select_function", "table", "user", "where_field", 0,
110};
111
112/* See sqlite_table(5). */
113
114static const char *sqlite_suffixes[] = {
115    "additional_conditions", "dbpath", "domain", "expansion_limit",
116    "query", "result_format", "select_field", "table", "where_field",
117    0,
118};
119
120/* See memcache_table(5). */
121
122static const char *memcache_suffixes[] = {
123    "backup", "data_size_limit", "domain", "flags", "key_format",
124    "line_size_limit", "max_try", "memcache", "retry_pause",
125    "timeout", "ttl", 0,
126};
127
128 /*
129  * Bundle up the database types and their suffix lists.
130  */
131typedef struct {
132    const char *db_type;
133    const char **db_suffixes;
134} PC_DBMS_INFO;
135
136static const PC_DBMS_INFO dbms_info[] = {
137    DICT_TYPE_LDAP, ldap_suffixes,
138    DICT_TYPE_MYSQL, mysql_suffixes,
139    DICT_TYPE_PGSQL, pgsql_suffixes,
140    DICT_TYPE_SQLITE, sqlite_suffixes,
141    DICT_TYPE_MEMCACHE, memcache_suffixes,
142    0,
143};
144
145/* register_dbms_parameters_cb - mac_expand() call-back */
146
147static const char *register_dbms_parameters_cb(const char *mac_name,
148					               int unused_mode,
149					               char *context)
150{
151    PC_MASTER_ENT *local_scope = (PC_MASTER_ENT *) context;
152    const char *mac_val;
153
154    /*
155     * Local namespace "name=value" settings are always explicit. They have
156     * precedence over global namespace "name=value" settings which are
157     * either explicit or defined by their default value.
158     */
159    if (local_scope == 0
160	|| (mac_val = dict_get(local_scope->all_params, mac_name)) == 0)
161	mac_val = mail_conf_lookup(mac_name);
162    return (mac_val);
163}
164
165/* register_dbms_parameters - look for database_type:prefix_name */
166
167void    register_dbms_parameters(const char *param_value,
168	           const char *(flag_parameter) (const char *, int, char *),
169				         PC_MASTER_ENT *local_scope)
170{
171    const PC_DBMS_INFO *dp;
172    char   *bufp;
173    char   *db_type;
174    char   *prefix;
175    static VSTRING *buffer = 0;
176    static VSTRING *candidate = 0;
177    const char **cpp;
178
179    /*
180     * Emulate Postfix parameter value expansion, prepending the appropriate
181     * local (master.cf "-o name-value") namespace to the global (main.cf
182     * "name=value") namespace.
183     *
184     * XXX This does not examine both sides of conditional macro expansion, and
185     * may expand the "wrong" conditional macros. This is the best we can do
186     * for legacy database configuration support.
187     */
188#define NO_SCAN_FILTER	((char *) 0)
189
190    (void) mac_expand(buffer ? buffer : (buffer = vstring_alloc(100)),
191		      param_value, MAC_EXP_FLAG_RECURSE, NO_SCAN_FILTER,
192		      register_dbms_parameters_cb, (char *) local_scope);
193
194    /*
195     * Naive parsing. We don't really know if the parameter specifies free
196     * text or a list of databases.
197     */
198    bufp = STR(buffer);
199    while ((db_type = mystrtok(&bufp, " ,\t\r\n")) != 0) {
200
201	/*
202	 * Skip over "proxy:" indirections.
203	 */
204	while ((prefix = split_at(db_type, ':')) != 0
205	       && strcmp(db_type, DICT_TYPE_PROXY) == 0)
206	    db_type = prefix;
207
208	/*
209	 * Look for database:prefix where the prefix is not a pathname and
210	 * the database is a known type. Synthesize candidate parameter names
211	 * from the user-defined prefix and from the database-defined suffix
212	 * list, and see if those parameters have a "name=value" entry in the
213	 * local or global namespace.
214	 */
215	if (prefix != 0 && *prefix != '/' && *prefix != '.') {
216	    for (dp = dbms_info; dp->db_type != 0; dp++) {
217		if (strcmp(db_type, dp->db_type) == 0) {
218		    for (cpp = dp->db_suffixes; *cpp; cpp++) {
219			vstring_sprintf(candidate ? candidate :
220					(candidate = vstring_alloc(30)),
221					"%s_%s", prefix, *cpp);
222			flag_parameter(STR(candidate), 0, (char *) local_scope);
223		    }
224		    break;
225		}
226	    }
227	}
228    }
229}
230
231#endif
232