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