Postfix3.3.1
postconf_dbms.c
[詳解]
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 pcf_register_dbms_parameters(param_value, flag_parameter,
10 /* local_scope)
11 /* const char *param_value;
12 /* const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *);
13 /* PCF_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; if the table name specifies
26 /* a client configuration file, that file is scanned for unused
27 /* parameter settings.
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 /* Wietse Venema
48 /* Google, Inc.
49 /* 111 8th Avenue
50 /* New York, NY 10011, USA
51 /*--*/
52 
53 /* System library. */
54 
55 #include <sys_defs.h>
56 #include <sys/stat.h>
57 #include <errno.h>
58 #include <string.h>
59 
60 /* Utility library. */
61 
62 #include <stringops.h>
63 #include <split_at.h>
64 #include <mac_expand.h>
65 #include <dict.h>
66 #include <msg.h>
67 #include <mymalloc.h>
68 
69 /* Global library. */
70 
71 #include <mail_conf.h>
72 #include <mail_params.h>
73 #include <dict_ht.h>
74 #include <dict_proxy.h>
75 #include <dict_ldap.h>
76 #include <dict_mysql.h>
77 #include <dict_pgsql.h>
78 #include <dict_sqlite.h>
79 #include <dict_memcache.h>
80 
81 /* Application-specific. */
82 
83 #include <postconf.h>
84 
85  /*
86  * SLMs.
87  */
88 #define STR(x) vstring_str(x)
89 
90 #ifdef LEGACY_DBMS_SUPPORT
91 
92  /*
93  * The legacy database interface automagically instantiates a list of
94  * parameters by prepending the table name to database-specific suffixes.
95  */
96 
97 /* See ldap_table(5). */
98 
99 static const char *pcf_ldap_suffixes[] = {
100 #include "pcf_ldap_suffixes.h"
101  0,
102 };
103 
104 /* See mysql_table(5). */
105 
106 static const char *pcf_mysql_suffixes[] = {
107 #include "pcf_mysql_suffixes.h"
108  0,
109 };
110 
111 /* See pgsql_table(5). */
112 
113 static const char *pcf_pgsql_suffixes[] = {
114 #include "pcf_pgsql_suffixes.h"
115  0,
116 };
117 
118 /* See sqlite_table(5). */
119 
120 static const char *pcf_sqlite_suffixes[] = {
121 #include "pcf_sqlite_suffixes.h"
122  0,
123 };
124 
125 /* See memcache_table(5). */
126 
127 static const char *pcf_memcache_suffixes[] = {
128 #include "pcf_memcache_suffixes.h"
129  0,
130 };
131 
132  /*
133  * Bundle up the database types and their suffix lists.
134  */
135 typedef struct {
136  const char *db_type;
137  const char **db_suffixes;
138 } PCF_DBMS_INFO;
139 
140 static const PCF_DBMS_INFO pcf_dbms_info[] = {
141  DICT_TYPE_LDAP, pcf_ldap_suffixes,
142  DICT_TYPE_MYSQL, pcf_mysql_suffixes,
143  DICT_TYPE_PGSQL, pcf_pgsql_suffixes,
144  DICT_TYPE_SQLITE, pcf_sqlite_suffixes,
145  DICT_TYPE_MEMCACHE, pcf_memcache_suffixes,
146  0,
147 };
148 
149 /* pcf_check_dbms_client - look for unused names in client configuration */
150 
151 static void pcf_check_dbms_client(const PCF_DBMS_INFO *dp, const char *cf_file)
152 {
153  DICT *dict;
154  VSTREAM *fp;
155  const char **cpp;
156  const char *name;
157  const char *value;
158  char *dict_spec;
159  int dir;
160 
161  /*
162  * We read each database client configuration file into its own
163  * dictionary, and nag only the first time that a file is visited.
164  */
165  dict_spec = concatenate(dp->db_type, ":", cf_file, (char *) 0);
166  if ((dict = dict_handle(dict_spec)) == 0) {
167  struct stat st;
168 
169  /*
170  * Populate the dictionary with settings in this database client
171  * configuration file. Don't die if a file can't be opened - some
172  * files may contain passwords and should not be world-readable.
173  * Note: dict_load_fp() nags about duplicate pameter settings.
174  */
175  dict = dict_ht_open(dict_spec, O_CREAT | O_RDWR, 0);
176  dict_register(dict_spec, dict);
177  if ((fp = vstream_fopen(cf_file, O_RDONLY, 0)) == 0) {
178  if (errno != EACCES)
179  msg_warn("open \"%s\" configuration \"%s\": %m",
180  dp->db_type, cf_file);
181  myfree(dict_spec);
182  return;
183  }
184  if (fstat(vstream_fileno(fp), &st) == 0 && !S_ISREG(st.st_mode)) {
185  msg_warn("open \"%s\" configuration \"%s\": not a regular file",
186  dp->db_type, cf_file);
187  myfree(dict_spec);
188  (void) vstream_fclose(fp);
189  return;
190  }
191  dict_load_fp(dict_spec, fp);
192  if (vstream_fclose(fp)) {
193  msg_warn("read \"%s\" configuration \"%s\": %m",
194  dp->db_type, cf_file);
195  myfree(dict_spec);
196  return;
197  }
198 
199  /*
200  * Remove all known database client parameters from this dictionary,
201  * then report the remaining ones as "unused". We use ad-hoc logging
202  * code, because a database client parameter namespace is unlike the
203  * parameter namespaces in main.cf or master.cf.
204  */
205  for (cpp = dp->db_suffixes; *cpp; cpp++)
206  (void) dict_del(dict, *cpp);
207  for (dir = DICT_SEQ_FUN_FIRST;
208  dict->sequence(dict, dir, &name, &value) == DICT_STAT_SUCCESS;
209  dir = DICT_SEQ_FUN_NEXT)
210  msg_warn("%s: unused parameter: %s=%s", dict_spec, name, value);
211  }
212  myfree(dict_spec);
213 }
214 
215 /* pcf_register_dbms_helper - parse one possible database type:name */
216 
217 static void pcf_register_dbms_helper(char *str_value,
218  const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *),
219  PCF_MASTER_ENT *local_scope)
220 {
221  const PCF_DBMS_INFO *dp;
222  char *db_type;
223  char *prefix;
224  static VSTRING *candidate = 0;
225  const char **cpp;
226  char *err;
227 
228  /*
229  * Naive parsing. We don't really know if this substring specifies a
230  * database or some other text.
231  */
232  while ((db_type = mystrtokq(&str_value, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
233 
234  /*
235  * Skip over "proxy:" maptypes, to emulate the proxymap(8) server's
236  * behavior when opening a local database configuration file.
237  */
238  while ((prefix = split_at(db_type, ':')) != 0
239  && strcmp(db_type, DICT_TYPE_PROXY) == 0)
240  db_type = prefix;
241 
242  if (prefix == 0)
243  continue;
244 
245  /*
246  * Look for database:prefix where the prefix is an absolute pathname.
247  * Then, report unknown database client configuration parameters.
248  *
249  * XXX What about a pathname beginning with '.'? This supposedly is
250  * relative to the queue directory, which is the default directory
251  * for all Postfix daemon processes. This would also have to handle
252  * the case that the queue is not yet created.
253  */
254  if (*prefix == '/') {
255  for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
256  if (strcmp(db_type, dp->db_type) == 0) {
257  pcf_check_dbms_client(dp, prefix);
258  break;
259  }
260  }
261  continue;
262  }
263 
264  /*
265  * Look for database:prefix where the prefix is not a pathname and
266  * the database is a known type. Synthesize candidate parameter names
267  * from the user-defined prefix and from the database-defined suffix
268  * list, and see if those parameters have a "name=value" entry in the
269  * local or global namespace.
270  */
271  if (*prefix != '.') {
272  if (*prefix == CHARS_BRACE[0]) {
273  if ((err = extpar(&prefix, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0) {
274  /* XXX Encapsulate this in pcf_warn() function. */
275  if (local_scope)
276  msg_warn("%s:%s: %s",
277  MASTER_CONF_FILE, local_scope->name_space,
278  err);
279  else
280  msg_warn("%s: %s", MAIN_CONF_FILE, err);
281  myfree(err);
282  }
283  pcf_register_dbms_helper(prefix, flag_parameter,
284  local_scope);
285  } else {
286  for (dp = pcf_dbms_info; dp->db_type != 0; dp++) {
287  if (strcmp(db_type, dp->db_type) == 0) {
288  for (cpp = dp->db_suffixes; *cpp; cpp++) {
289  vstring_sprintf(candidate ? candidate :
290  (candidate = vstring_alloc(30)),
291  "%s_%s", prefix, *cpp);
292  flag_parameter(STR(candidate),
294  local_scope);
295  }
296  break;
297  }
298  }
299  }
300  }
301  }
302 }
303 
304 /* pcf_register_dbms_parameters - look for database_type:prefix_name */
305 
306 void pcf_register_dbms_parameters(const char *param_value,
307  const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *),
308  PCF_MASTER_ENT *local_scope)
309 {
310  char *bufp;
311  static VSTRING *buffer = 0;
312 
313  /*
314  * XXX This does not examine both sides of conditional macro expansion,
315  * and may expand the "wrong" conditional macros. This is the best we can
316  * do for legacy database configuration support.
317  */
318  if (buffer == 0)
319  buffer = vstring_alloc(100);
320  bufp = pcf_expand_parameter_value(buffer, PCF_SHOW_EVAL, param_value,
321  local_scope);
322  pcf_register_dbms_helper(bufp, flag_parameter, local_scope);
323 }
324 
325 #endif
char * name_space
Definition: postconf.h:121
void myfree(void *ptr)
Definition: mymalloc.c:207
#define CHARS_BRACE
Definition: sys_defs.h:1763
#define DICT_TYPE_PROXY
Definition: dict_proxy.h:22
char * extpar(char **bp, const char *parens, int flags)
Definition: extpar.c:77
void dict_register(const char *dict_name, DICT *dict_info)
Definition: dict.c:312
#define DICT_SEQ_FUN_FIRST
Definition: dict.h:200
#define EXTPAR_FLAG_NONE
Definition: stringops.h:56
#define stat(p, s)
Definition: warn_stat.h:18
#define DICT_SEQ_FUN_NEXT
Definition: dict.h:201
#define DICT_TYPE_LDAP
Definition: dict_ldap.h:22
char * pcf_expand_parameter_value(VSTRING *, int, const char *, PCF_MASTER_ENT *)
char * mystrtokq(char **src, const char *sep, const char *parens)
Definition: mystrtok.c:80
#define PCF_PARAM_FLAG_DBMS
Definition: postconf.h:70
#define STR(x)
Definition: postconf_dbms.c:88
#define MAIN_CONF_FILE
Definition: mail_params.h:334
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
Definition: vstream.c:1241
Definition: dict.h:78
#define DICT_STAT_SUCCESS
Definition: dict.h:186
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define PCF_SHOW_EVAL
Definition: postconf.h:33
#define MASTER_CONF_FILE
Definition: mail_params.h:335
DICT * dict_handle(const char *dict_name)
Definition: dict.c:333
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define DICT_TYPE_PGSQL
Definition: dict_pgsql.h:22
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
void pcf_register_dbms_parameters(const char *, const char *(*)(const char *, int, PCF_MASTER_ENT *), PCF_MASTER_ENT *)
DICT * dict_ht_open(const char *name, int unused_open_flags, int dict_flags)
Definition: dict_ht.c:155
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
void dict_load_fp(const char *dict_name, VSTREAM *fp)
Definition: dict.c:472
#define DICT_TYPE_SQLITE
Definition: dict_sqlite.h:22
#define CHARS_COMMA_SP
Definition: sys_defs.h:1761
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
#define DICT_TYPE_MEMCACHE
Definition: dict_memcache.h:22
#define PCF_PARAM_FLAG_USER
Definition: postconf.h:67
#define DICT_TYPE_MYSQL
Definition: dict_mysql.h:22
char * split_at(char *string, int delimiter)
Definition: split_at.c:53
#define vstream_fileno(vp)
Definition: vstream.h:115
#define dict_del(dp, key)
Definition: dict.h:238
#define fstat(f, s)
Definition: warn_stat.h:20