/*++
/* NAME
/* postconf_dbms 3
/* SUMMARY
/* legacy support for database-defined main.cf parameter names
/* SYNOPSIS
/* #include <postconf.h>
/*
/* void pcf_register_dbms_parameters(mode, param_value, flag_parameter,
/* local_scope)
/* int mode;
/* const char *param_value;
/* const char *(flag_parameter) (const char *, int, PCF_MASTER_ENT *);
/* PCF_MASTER_ENT *local_scope;
/* DESCRIPTION
/* This module implements legacy support for database configuration
/* where main.cf parameter names are generated by prepending
/* the database name to a database-defined suffix.
/*
/* Arguments:
/* .IP mode
/* If PCF_WARN_UNUSED_DEPRECATED is set, warn about unused
/* database settings.
/* .IP param_value
/* A parameter value to be searched for "type:table" strings.
/* When a database type is found that supports legacy-style
/* configuration, the table name is combined with each of the
/* database-defined suffixes to generate candidate parameter
/* names for that database type; if the table name specifies
/* a client configuration file, that file is scanned for unused
/* parameter settings.
/* .IP flag_parameter
/* A function that takes as arguments a candidate parameter
/* name, parameter flags, and a PCF_MASTER_ENT pointer. The
/* function will flag the parameter as "used" if it has a
/* "name=value" entry in the local or global namespace.
/* .IP local_scope
/* The local namespace.
/* DIAGNOSTICS
/* No explicit diagnostics.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
/* Utility library. */
#include <stringops.h>
#include <split_at.h>
#include <mac_expand.h>
#include <dict.h>
#include <msg.h>
#include <mymalloc.h>
/* Global library. */
#include <mail_conf.h>
#include <mail_params.h>
#include <dict_debug.h>
#include <dict_ht.h>
#include <dict_proxy.h>
#include <dict_ldap.h>
#include <dict_mysql.h>
#include <dict_pgsql.h>
#include <dict_sqlite.h>
#include <dict_memcache.h>
#include <dict_mongodb.h>
#include <dict_regexp.h>
#include <dict_pcre.h>
/* Application-specific. */
#include <postconf.h>
/*
* SLMs .
*/
#define STR(x) vstring_str(x)
#ifdef LEGACY_DBMS_SUPPORT
/*
* The legacy database interface automagically instantiates a list of
* parameters by prepending the table name to database - specific suffixes .
*/
/* See ldap_table(5). */
static const char *pcf_ldap_suffixes[] = {
#include "pcf_ldap_suffixes.h"
0 ,
};
/* See mysql_table(5). */
static const char *pcf_mysql_suffixes[] = {
#include "pcf_mysql_suffixes.h"
0 ,
};
/* See pgsql_table(5). */
static const char *pcf_pgsql_suffixes[] = {
#include "pcf_pgsql_suffixes.h"
0 ,
};
/* See sqlite_table(5). */
static const char *pcf_sqlite_suffixes[] = {
#include "pcf_sqlite_suffixes.h"
0 ,
};
/* See memcache_table(5). */
static const char *pcf_memcache_suffixes[] = {
#include "pcf_memcache_suffixes.h"
0 ,
};
/* See mongodb_table(5). */
static const char *pcf_mongodb_suffixes[] = {
#include "pcf_mongodb_suffixes.h"
0 ,
};
/*
* Bundle up the database types and their suffix lists .
*/
typedef struct {
const char *db_type;
int db_class;
const char **db_suffixes;
} PCF_DBMS_INFO;
#define PCF_DBMS_CLASS_CLIENT (1 ) /* DB name is client config path */
#define PCF_DBMS_CLASS_REGEX (2 ) /* DB name contains regex patterns */
static const PCF_DBMS_INFO pcf_dbms_info[] = {
{DICT_TYPE_LDAP, PCF_DBMS_CLASS_CLIENT, pcf_ldap_suffixes},
{DICT_TYPE_MYSQL, PCF_DBMS_CLASS_CLIENT, pcf_mysql_suffixes},
{DICT_TYPE_PGSQL, PCF_DBMS_CLASS_CLIENT, pcf_pgsql_suffixes},
{DICT_TYPE_SQLITE, PCF_DBMS_CLASS_CLIENT, pcf_sqlite_suffixes},
{DICT_TYPE_MEMCACHE, PCF_DBMS_CLASS_CLIENT, pcf_memcache_suffixes},
{DICT_TYPE_MONGODB, PCF_DBMS_CLASS_CLIENT, pcf_mongodb_suffixes},
{DICT_TYPE_REGEXP, PCF_DBMS_CLASS_REGEX},
{DICT_TYPE_PCRE, PCF_DBMS_CLASS_REGEX},
{0 },
};
/*
* Workaround to prevent a false warning about " # comment after other text " ,
* when an inline pcre or regexp pattern contains " # text " .
*/
#define PCF_DBMS_RECURSE 1 /* Parse inline {map-entry} */
#define PCF_DBMS_NO_RECURSE 0 /* Don't parse inline {map-entry} */
/* pcf_check_dbms_client - look for unused names in client configuration */
static void pcf_check_dbms_client(int mode, const PCF_DBMS_INFO *dp,
const char *cf_file)
{
DICT *dict;
VSTREAM *fp;
const char **cpp;
const char *name;
const char *value;
char *dict_spec;
int dir;
/*
* We read each database client configuration file into its own
* dictionary , and nag only the first time that a file is visited .
*/
dict_spec = concatenate(dp->db_type, ":" , cf_file, (char *) 0 );
if ((dict = dict_handle(dict_spec)) == 0 ) {
struct stat st;
/*
* Populate the dictionary with settings in this database client
* configuration file . Don ' t die if a file can ' t be opened - some
* files may contain passwords and should not be world - readable .
* Note : dict_load_fp ( ) nags about duplicate parameter settings .
*/
dict = dict_ht_open(dict_spec, O_CREAT | O_RDWR, 0 );
dict_register(dict_spec, dict);
if ((fp = vstream_fopen(cf_file, O_RDONLY, 0 )) == 0 ) {
if (errno != EACCES)
msg_warn("open \" %s\" configuration \" %s\": %m" ,
dp->db_type, cf_file);
myfree(dict_spec);
return ;
}
if (fstat(vstream_fileno(fp), &st) == 0 && !S_ISREG(st.st_mode)) {
msg_warn("open \" %s\" configuration \" %s\": not a regular file" ,
dp->db_type, cf_file);
myfree(dict_spec);
(void ) vstream_fclose(fp);
return ;
}
dict_load_fp(dict_spec, fp);
if (vstream_fclose(fp)) {
msg_warn("read \" %s\" configuration \" %s\": %m" ,
dp->db_type, cf_file);
myfree(dict_spec);
return ;
}
/*
* Remove all known database client parameters from this dictionary ,
* then report the remaining ones as " unused " . We use ad - hoc logging
* code , because a database client parameter namespace is unlike the
* parameter namespaces in main . cf or master . cf .
*/
if (mode & PCF_WARN_UNUSED_DEPRECATED) {
for (cpp = dp->db_suffixes; *cpp; cpp++)
(void ) dict_del(dict, *cpp);
for (dir = DICT_SEQ_FUN_FIRST;
dict->sequence(dict, dir, &name, &value) == DICT_STAT_SUCCESS;
dir = DICT_SEQ_FUN_NEXT)
msg_warn("%s: unused parameter: %s=%s" , dict_spec, name, value);
}
}
myfree(dict_spec);
}
/* pcf_register_dbms_helper - parse one possible database type:name */
static void pcf_register_dbms_helper(int mode, char *str_value,
const char *(flag_parameter) (const char *, int , PCF_MASTER_ENT *),
PCF_MASTER_ENT *local_scope,
int recurse)
{
const PCF_DBMS_INFO *dp;
char *db_type;
char *prefix;
static VSTRING *candidate = 0 ;
const char **cpp;
char *err;
/*
* Naive parsing . We don ' t really know if this substring specifies a
* database or some other text .
*/
while ((db_type = mystrtokq_cw(&str_value, CHARS_COMMA_SP, CHARS_BRACE,
local_scope ? pcf_get_master_path() : pcf_get_main_path())) != 0 ) {
if (*db_type == CHARS_BRACE[0 ]) {
if ((err = extpar(&db_type, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0 ) {
/* XXX Encapsulate this in pcf_warn() function. */
if (local_scope)
msg_warn("%s:%s: %s" , pcf_get_master_path(),
local_scope->name_space, err);
else
msg_warn("%s: %s" , pcf_get_main_path(), err);
myfree(err);
}
if (recurse)
pcf_register_dbms_helper(mode, db_type, flag_parameter,
local_scope, recurse);
continue ;
}
/*
* Skip over adapter maptypes " proxy : " and " debug : " , to emulate their
* behavior when wrapping a local database configuration file .
*/
while ((prefix = split_at(db_type, ':' )) != 0
&& (strcmp(db_type, DICT_TYPE_PROXY) == 0 ||
strcmp(db_type, DICT_TYPE_DEBUG) == 0 ))
db_type = prefix;
if (prefix == 0 )
continue ;
/*
* Look for database : prefix where the prefix is an absolute pathname .
* Then , report unknown database client configuration parameters .
*
* XXX What about a pathname beginning with ' . ' ? This supposedly is
* relative to the queue directory , which is the default directory
* for all Postfix daemon processes . This would also have to handle
* the case that the queue is not yet created .
*/
if (*prefix == '/' ) {
for (dp = pcf_dbms_info; dp->db_type != 0 ; dp++) {
if (strcmp(db_type, dp->db_type) == 0 ) {
if (dp->db_class == PCF_DBMS_CLASS_CLIENT)
pcf_check_dbms_client(mode, dp, prefix);
break ;
}
}
continue ;
}
/*
* Look for database : prefix where the prefix is not a pathname and
* the database is a known type . Synthesize candidate parameter names
* from the user - defined prefix and from the database - defined suffix
* list , and see if those parameters have a " name = value " entry in the
* local or global namespace .
*/
if (*prefix != '.' ) {
int next_recurse = recurse;
if (*prefix == CHARS_BRACE[0 ]) {
if ((err = extpar(&prefix, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0 ) {
/* XXX Encapsulate this in pcf_warn() function. */
if (local_scope)
msg_warn("%s:%s: %s" , pcf_get_master_path(),
local_scope->name_space, err);
else
msg_warn("%s: %s" , pcf_get_main_path(), err);
myfree(err);
}
for (dp = pcf_dbms_info; dp->db_type != 0 ; dp++) {
if (strcmp(db_type, dp->db_type) == 0 ) {
if (dp->db_class == PCF_DBMS_CLASS_REGEX)
next_recurse = PCF_DBMS_NO_RECURSE;
break ;
}
}
pcf_register_dbms_helper(mode, prefix, flag_parameter,
local_scope, next_recurse);
continue ;
} else {
for (dp = pcf_dbms_info; dp->db_type != 0 ; dp++) {
if (strcmp(db_type, dp->db_type) == 0 ) {
if (dp->db_class == PCF_DBMS_CLASS_CLIENT) {
for (cpp = dp->db_suffixes; *cpp; cpp++) {
vstring_sprintf(candidate ? candidate :
(candidate = vstring_alloc(30 )),
"%s_%s" , prefix, *cpp);
flag_parameter(STR(candidate),
PCF_PARAM_FLAG_DBMS | PCF_PARAM_FLAG_USER,
local_scope);
}
}
break ;
}
}
}
}
}
}
/* pcf_register_dbms_parameters - look for database_type:prefix_name */
void pcf_register_dbms_parameters(int mode, const char *param_value,
const char *(flag_parameter) (const char *, int , PCF_MASTER_ENT *),
PCF_MASTER_ENT *local_scope)
{
char *bufp;
static VSTRING *buffer = 0 ;
/*
* XXX This does not examine both sides of conditional macro expansion ,
* and may expand the " wrong " conditional macros . This is the best we can
* do for legacy database configuration support .
*/
if (buffer == 0 )
buffer = vstring_alloc(100 );
bufp = pcf_expand_parameter_value(buffer, PCF_SHOW_EVAL, param_value,
local_scope);
pcf_register_dbms_helper(mode, bufp, flag_parameter, local_scope,
PCF_DBMS_RECURSE);
}
#endif
Messung V0.5 in Prozent C=71 H=95 G=83
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland