2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 21:55:20 +00:00

postfix-2.5-20071203

This commit is contained in:
Wietse Venema
2033-08-08 05:53:23 -05:00
committed by Viktor Dukhovni
parent 93d0a26a92
commit a98fc88914
26 changed files with 504 additions and 62 deletions

View File

@@ -13878,3 +13878,22 @@ Apologies for any names omitted.
Bugfix: don't update the back-to-back delivery time stamp
while deferring mail. File: *qmgr/qmgr_entry.c.
20071203
Feature: support for read-write tables in the proxymap
service. This is implemented with a separate master.cf entry
named "proxywrite" that should run with process limit of 1
if you want to update Berkeley DB like tables. This feature
requires that tables be authorized with the proxy_write_maps
configuration parameter. Files: global/dict_procy.[hc],
proxymap/proxymap.c.
Human factors: the postmap and postalias commands now produce
nicer diagnostics when asked to do something with a proxied
map that they can't do. Files: postmap/postmap.c,
postalias/postalias.c.
Bugfix: the proxymap client didn't properly propagate the
postmap (postalias) -r and -w options to the proxymap server.
File: util/dict.h.

View File

@@ -17,6 +17,14 @@ Incompatibility with Postfix 2.3 and earlier
If you upgrade from Postfix 2.3 or earlier, read RELEASE_NOTES-2.4
before proceeding.
Incompatibility with Postfix snapshot 20071203
==============================================
The "make upgrade" procedure adds a new service "proxywrite" to the
master.cf file, for read/write lookup table access. If you copy
your old configuration file over the updated one, you will have
to run "postfix upgrade-configuration" again.
Major changes with Postfix snapshot 20071202
============================================

View File

@@ -659,6 +659,15 @@ retry unix - - n - - error
EOF
}
# Add missing proxywrite service to master.cf.
grep '^proxywrite.*proxymap' $config_directory/master.cf >/dev/null || {
echo Editing $config_directory/master.cf, adding missing entry for proxywrite service
cat >>$config_directory/master.cf <<EOF || exit 1
proxywrite unix - - n - 1 proxymap
EOF
}
# Report (but do not remove) obsolete files.
test -n "$obsolete" && {

View File

@@ -6152,9 +6152,9 @@ Example:
(default: see "postconf -d" output)</b></DT><DD>
<p>
The lookup tables that the <a href="proxymap.8.html">proxymap(8)</a> server is allowed to access.
Table references that don't begin with <a href="proxymap.8.html">proxy</a>: are ignored. The
<a href="proxymap.8.html">proxymap(8)</a> table accesses are read-only.
The lookup tables that the <a href="proxymap.8.html">proxymap(8)</a> server is allowed to
access for the read-only service.
Table references that don't begin with <a href="proxymap.8.html">proxy</a>: are ignored.
</p>
<p>
@@ -6162,6 +6162,22 @@ This feature is available in Postfix 2.0 and later.
</p>
</DD>
<DT><b><a name="proxy_write_maps">proxy_write_maps</a>
(default: see "postconf -d" output)</b></DT><DD>
<p>
The lookup tables that the <a href="proxymap.8.html">proxymap(8)</a> server is allowed to
access for the read-write service.
Table references that don't begin with <a href="proxymap.8.html">proxy</a>: are ignored.
</p>
<p>
This feature is available in Postfix 2.5 and later.
</p>
</DD>
<DT><b><a name="qmgr_clog_warn_time">qmgr_clog_warn_time</a>

View File

@@ -13,8 +13,10 @@ PROXYMAP(8) PROXYMAP(8)
<b>proxymap</b> [generic Postfix daemon options]
<b>DESCRIPTION</b>
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server provides read-only table lookup
service to Postfix processes. The purpose of the service
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server provides read-only or read-write
table lookup service to Postfix processes. These services
are implemented with distinct service names: <b>proxymap</b> and
<b>proxywrite</b>, respectively. The purpose of these services
is:
<b>o</b> To overcome chroot restrictions. For example, a
@@ -39,6 +41,10 @@ PROXYMAP(8) PROXYMAP(8)
The total number of connections is limited by the
number of proxymap server processes.
<b>o</b> To provide single-updater functionality for lookup
tables that do not reliably support multiple writ-
ers (i.e. all file-based tables).
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server implements the following requests:
<b>open</b> <i>maptype:mapname flags</i>
@@ -49,10 +55,26 @@ PROXYMAP(8) PROXYMAP(8)
<b>lookup</b> <i>maptype:mapname flags key</i>
Look up the data stored under the requested key.
The reply is the request completion status code
(below) and the lookup result value. The <i>map-</i>
<i>type:mapname</i> and <i>flags</i> are the same as with the
<b>open</b> request.
The reply is the request completion status code and
the lookup result value. The <i>maptype:mapname</i> and
<i>flags</i> are the same as with the <b>open</b> request.
<b>update</b> <i>maptype:mapname flags key value</i>
Update the data stored under the requested key.
The reply is the request completion status code.
The <i>maptype:mapname</i> and <i>flags</i> are the same as with
the <b>open</b> request.
To implement single-updater maps, specify a process
limit of 1 in the <a href="master.5.html">master.cf</a> file entry for the
proxywrite service.
This request is supported in Postfix 2.5 and later.
The request completion status is one of OK, RETRY, NOKEY
(lookup failed because the key was not found), BAD (mal-
formed request) or DENY (the table is not approved for
proxy read or update access).
There is no <b>close</b> command, nor are tables implicitly
closed when a client disconnects. The purpose is to share
@@ -69,11 +91,11 @@ PROXYMAP(8) PROXYMAP(8)
<b>SECURITY</b>
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server opens only tables that are approved
via the <b><a href="postconf.5.html#proxy_read_maps">proxy_read_maps</a></b> configuration parameter, does not
talk to users, and can run at fixed low privilege,
chrooted or not. However, running the proxymap server
chrooted severely limits usability, because it can open
only chrooted tables.
via the <b><a href="postconf.5.html#proxy_read_maps">proxy_read_maps</a></b> or <b><a href="postconf.5.html#proxy_write_maps">proxy_write_maps</a></b> configuration
parameters, does not talk to users, and can run at fixed
low privilege, chrooted or not. However, running the
proxymap server chrooted severely limits usability,
because it can open only chrooted tables.
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server is not a trusted daemon process,
and must not be used to look up sensitive information such
@@ -94,6 +116,16 @@ PROXYMAP(8) PROXYMAP(8)
clients, and must therefore not be used for tables that
have high-latency lookups.
The <a href="proxymap.8.html"><b>proxymap</b>(8)</a> read-write service does not explicitly
close lookup tables (even if it did, this could not be
relied on, because the process may be terminated between
table updates). The read-write service should therefore
not be used with tables that leave persistent storage in
an inconsistent state between updates (for example, CDB).
Tables that support "sync on update" should be safe (for
example, Berkeley DB) as should tables that are imple-
mented by a real DBMS.
<b>CONFIGURATION PARAMETERS</b>
On busy mail systems a long time may pass before <a href="proxymap.8.html"><b>prox-</b></a>
<a href="proxymap.8.html"><b>ymap</b>(8)</a> relevant changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up. Use the
@@ -135,7 +167,13 @@ PROXYMAP(8) PROXYMAP(8)
<b><a href="postconf.5.html#proxy_read_maps">proxy_read_maps</a> (see 'postconf -d' output)</b>
The lookup tables that the <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server is
allowed to access.
allowed to access for the read-only service.
Available in Postfix 2.5 and later:
<b><a href="postconf.5.html#proxy_write_maps">proxy_write_maps</a> (see 'postconf -d' output)</b>
The lookup tables that the <a href="proxymap.8.html"><b>proxymap</b>(8)</a> server is
allowed to access for the read-write service.
<b>SEE ALSO</b>
<a href="postconf.5.html">postconf(5)</a>, configuration parameters
@@ -145,7 +183,7 @@ PROXYMAP(8) PROXYMAP(8)
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>

View File

@@ -3423,11 +3423,17 @@ proxy_interfaces = 1.2.3.4
.ad
.ft R
.SH proxy_read_maps (default: see "postconf -d" output)
The lookup tables that the \fBproxymap\fR(8) server is allowed to access.
Table references that don't begin with proxy: are ignored. The
\fBproxymap\fR(8) table accesses are read-only.
The lookup tables that the \fBproxymap\fR(8) server is allowed to
access for the read-only service.
Table references that don't begin with proxy: are ignored.
.PP
This feature is available in Postfix 2.0 and later.
.SH proxy_write_maps (default: see "postconf -d" output)
The lookup tables that the \fBproxymap\fR(8) server is allowed to
access for the read-write service.
Table references that don't begin with proxy: are ignored.
.PP
This feature is available in Postfix 2.5 and later.
.SH qmgr_clog_warn_time (default: 300s)
The minimal delay between warnings that a specific destination is
clogging up the Postfix active queue. Specify 0 to disable.

View File

@@ -12,9 +12,10 @@ Postfix lookup table proxy server
.SH DESCRIPTION
.ad
.fi
The \fBproxymap\fR(8) server provides read-only table
lookup service to Postfix processes. The purpose
of the service is:
The \fBproxymap\fR(8) server provides read-only or read-write
table lookup service to Postfix processes. These services are
implemented with distinct service names: \fBproxymap\fR and
\fBproxywrite\fR, respectively. The purpose of these services is:
.IP \(bu
To overcome chroot restrictions. For example, a chrooted SMTP
server needs access to the system passwd file in order to
@@ -39,6 +40,10 @@ virtual_alias_maps =
.sp
The total number of connections is limited by the number of
proxymap server processes.
.IP \(bu
To provide single-updater functionality for lookup tables
that do not reliably support multiple writers (i.e. all
file-based tables).
.PP
The \fBproxymap\fR(8) server implements the following requests:
.IP "\fBopen\fR \fImaptype:mapname flags\fR"
@@ -48,11 +53,26 @@ dependent flags (to distinguish a fixed string table from a regular
expression table).
.IP "\fBlookup\fR \fImaptype:mapname flags key\fR"
Look up the data stored under the requested key.
The reply is the request completion status code (below) and
The reply is the request completion status code and
the lookup result value.
The \fImaptype:mapname\fR and \fIflags\fR are the same
as with the \fBopen\fR request.
.IP "\fBupdate\fR \fImaptype:mapname flags key value\fR"
Update the data stored under the requested key.
The reply is the request completion status code.
The \fImaptype:mapname\fR and \fIflags\fR are the same
as with the \fBopen\fR request.
.sp
To implement single-updater maps, specify a process limit
of 1 in the master.cf file entry for the proxywrite service.
.sp
This request is supported in Postfix 2.5 and later.
.PP
The request completion status is one of OK, RETRY, NOKEY
(lookup failed because the key was not found), BAD (malformed
request) or DENY (the table is not approved for proxy read
or update access).
There is no \fBclose\fR command, nor are tables implicitly closed
when a client disconnects. The purpose is to share tables among
multiple client processes.
@@ -74,8 +94,9 @@ or after \fB$max_idle\fR seconds of idle time.
.nf
.ad
.fi
The \fBproxymap\fR(8) server opens only tables that are approved via the
\fBproxy_read_maps\fR configuration parameter, does not talk to
The \fBproxymap\fR(8) server opens only tables that are
approved via the \fBproxy_read_maps\fR or \fBproxy_write_maps\fR
configuration parameters, does not talk to
users, and can run at fixed low privilege, chrooted or not.
However, running the proxymap server chrooted severely limits
usability, because it can open only chrooted tables.
@@ -98,6 +119,15 @@ Problems and transactions are logged to \fBsyslogd\fR(8).
The \fBproxymap\fR(8) server provides service to multiple clients,
and must therefore not be used for tables that have high-latency
lookups.
The \fBproxymap\fR(8) read-write service does not explicitly
close lookup tables (even if it did, this could not be relied on,
because the process may be terminated between table updates).
The read-write service should therefore not be used with tables that
leave persistent storage in an inconsistent state between
updates (for example, CDB). Tables that support "sync on
update" should be safe (for example, Berkeley DB) as should
tables that are implemented by a real DBMS.
.SH "CONFIGURATION PARAMETERS"
.na
.nf
@@ -130,7 +160,13 @@ The process ID of a Postfix command or daemon process.
.IP "\fBprocess_name (read-only)\fR"
The process name of a Postfix command or daemon process.
.IP "\fBproxy_read_maps (see 'postconf -d' output)\fR"
The lookup tables that the \fBproxymap\fR(8) server is allowed to access.
The lookup tables that the \fBproxymap\fR(8) server is allowed to
access for the read-only service.
.PP
Available in Postfix 2.5 and later:
.IP "\fBproxy_write_maps (see 'postconf -d' output)\fR"
The lookup tables that the \fBproxymap\fR(8) server is allowed to
access for the read-write service.
.SH "SEE ALSO"
.na
.nf

View File

@@ -328,6 +328,7 @@ while (<>) {
s;\bpropagate_unmatched_extensions\b;<a href="postconf.5.html#propagate_unmatched_extensions">$&</a>;g;
s;\bproxy_inter[-</bB>]*\n* *[<bB>]*faces\b;<a href="postconf.5.html#proxy_interfaces">$&</a>;g;
s;\bproxy_read_maps\b;<a href="postconf.5.html#proxy_read_maps">$&</a>;g;
s;\bproxy_write_maps\b;<a href="postconf.5.html#proxy_write_maps">$&</a>;g;
s;\bqmgr_clog_warn_time\b;<a href="postconf.5.html#qmgr_clog_warn_time">$&</a>;g;
s;\bqmgr_fudge_factor\b;<a href="postconf.5.html#qmgr_fudge_factor">$&</a>;g;
s;\bqmgr_message_active_limit\b;<a href="postconf.5.html#qmgr_message_active_limit">$&</a>;g;

View File

@@ -7204,15 +7204,27 @@ This is a read-only parameter.
%PARAM proxy_read_maps see "postconf -d" output
<p>
The lookup tables that the proxymap(8) server is allowed to access.
Table references that don't begin with proxy: are ignored. The
proxymap(8) table accesses are read-only.
The lookup tables that the proxymap(8) server is allowed to
access for the read-only service.
Table references that don't begin with proxy: are ignored.
</p>
<p>
This feature is available in Postfix 2.0 and later.
</p>
%PARAM proxy_write_maps see "postconf -d" output
<p>
The lookup tables that the proxymap(8) server is allowed to
access for the read-write service.
Table references that don't begin with proxy: are ignored.
</p>
<p>
This feature is available in Postfix 2.5 and later.
</p>
%PARAM qmgr_clog_warn_time 300s
<p>

View File

@@ -28,7 +28,7 @@ SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
tok822_resolve.c tok822_rewrite.c tok822_tree.c trace.c \
user_acl.c valid_mailhost_addr.c verify.c verify_clnt.c \
verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c \
fold_addr.c header_body_checks.c
fold_addr.c header_body_checks.c mkmap_proxy.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
@@ -58,7 +58,7 @@ OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o trace.o \
user_acl.o valid_mailhost_addr.o verify.o verify_clnt.o \
verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o \
fold_addr.o header_body_checks.o
fold_addr.o header_body_checks.o mkmap_proxy.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
@@ -1451,8 +1451,19 @@ mkmap_open.o: ../../include/sys_defs.h
mkmap_open.o: ../../include/vbuf.h
mkmap_open.o: ../../include/vstream.h
mkmap_open.o: ../../include/vstring.h
mkmap_open.o: dict_proxy.h
mkmap_open.o: mkmap.h
mkmap_open.o: mkmap_open.c
mkmap_proxy.o: ../../include/argv.h
mkmap_proxy.o: ../../include/dict.h
mkmap_proxy.o: ../../include/mymalloc.h
mkmap_proxy.o: ../../include/sys_defs.h
mkmap_proxy.o: ../../include/vbuf.h
mkmap_proxy.o: ../../include/vstream.h
mkmap_proxy.o: ../../include/vstring.h
mkmap_proxy.o: dict_proxy.h
mkmap_proxy.o: mkmap.h
mkmap_proxy.o: mkmap_proxy.c
mkmap_sdbm.o: ../../include/argv.h
mkmap_sdbm.o: ../../include/dict.h
mkmap_sdbm.o: ../../include/dict_sdbm.h

View File

@@ -14,7 +14,10 @@
/* dict_proxy_open() relays read-only operations through
/* the Postfix proxymap server.
/*
/* The \fIopen_flags\fR argument must specify O_RDONLY.
/* The \fIopen_flags\fR argument must specify O_RDONLY
/* or O_RDWR|O_CREAT. Depending on this, the client
/* connects to the proxymap multiserver or to the
/* proxywrite single updater.
/*
/* The connection to the Postfix proxymap server is automatically
/* closed after $ipc_idle seconds of idle time, or after $ipc_ttl
@@ -154,6 +157,69 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key)
}
}
/* dict_proxy_update - update table entry */
static void dict_proxy_update(DICT *dict, const char *key, const char *value)
{
const char *myname = "dict_proxy_update";
DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
VSTREAM *stream;
int status;
int count = 0;
int request_flags;
/*
* The client and server live in separate processes that may start and
* terminate independently. We cannot rely on a persistent connection,
* let alone on persistent state (such as a specific open table) that is
* associated with a specific connection. Each lookup needs to specify
* the table and the flags that were specified to dict_proxy_open().
*/
request_flags = (dict_proxy->in_flags & DICT_FLAG_RQST_MASK)
| (dict->flags & DICT_FLAG_RQST_MASK);
for (;;) {
stream = clnt_stream_access(proxy_stream);
errno = 0;
count += 1;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_UPDATE,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, dict->name,
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, request_flags,
ATTR_TYPE_STR, MAIL_ATTR_KEY, key,
ATTR_TYPE_STR, MAIL_ATTR_VALUE, value,
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1) {
if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream));
} else {
if (msg_verbose)
msg_info("%s: table=%s flags=%s key=%s value=%s -> status=%d",
myname, dict->name, dict_flags_str(request_flags),
key, value, status);
switch (status) {
case PROXY_STAT_BAD:
msg_fatal("%s lookup failed for table \"%s\" key \"%s\": "
"invalid request",
MAIL_SERVICE_PROXYMAP, dict->name, key);
case PROXY_STAT_DENY:
msg_fatal("%s update access is not configured for table \"%s\"",
MAIL_SERVICE_PROXYMAP, dict->name);
case PROXY_STAT_OK:
return;
default:
msg_warn("%s update failed for table \"%s\" key \"%s\": "
"unexpected reply status %d",
MAIL_SERVICE_PROXYMAP, dict->name, key, status);
}
}
clnt_stream_recover(proxy_stream);
sleep(1); /* XXX make configurable */
}
}
/* dict_proxy_close - disconnect */
static void dict_proxy_close(DICT *dict)
@@ -178,9 +244,14 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
/*
* Sanity checks.
*
* XXX A complete implementation would also allow O_RDWR without O_CREAT.
* But we must not pass on every possible set of flags to the proxy
* server; only sets that make sense. For now, the flags are passed
* implicitly by choosing between the proxymap or proxywrite service.
*/
if (open_flags != O_RDONLY)
msg_fatal("%s: %s map open requires O_RDONLY access mode",
if (open_flags != O_RDONLY && open_flags != (O_RDWR | O_CREAT))
msg_fatal("%s: %s map open requires O_RDONLY or O_RDWR|O_CREAT mode",
map, DICT_TYPE_PROXY);
/*
@@ -197,6 +268,7 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
dict_proxy = (DICT_PROXY *)
dict_alloc(DICT_TYPE_PROXY, map, sizeof(*dict_proxy));
dict_proxy->dict.lookup = dict_proxy_lookup;
dict_proxy->dict.update = dict_proxy_update;
dict_proxy->dict.close = dict_proxy_close;
dict_proxy->in_flags = dict_flags;
dict_proxy->result = vstring_alloc(10);
@@ -207,13 +279,18 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
* XXX Use absolute pathname to make this work from non-daemon processes.
*/
if (proxy_stream == 0) {
if (access(MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYMAP, F_OK) == 0)
if (access(open_flags == O_RDONLY ?
MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYMAP :
MAIL_CLASS_PRIVATE "/" MAIL_SERVICE_PROXYWRITE,
F_OK) == 0)
prefix = MAIL_CLASS_PRIVATE;
else
prefix = kludge = concatenate(var_queue_dir, "/",
MAIL_CLASS_PRIVATE, (char *) 0);
proxy_stream = clnt_stream_create(prefix,
MAIL_SERVICE_PROXYMAP,
open_flags == O_RDONLY ?
MAIL_SERVICE_PROXYMAP :
MAIL_SERVICE_PROXYWRITE,
var_ipc_idle_limit,
var_ipc_ttl_limit);
if (kludge)

View File

@@ -28,6 +28,7 @@ extern DICT *dict_proxy_open(const char *, int, int);
*/
#define PROXY_REQ_OPEN "open"
#define PROXY_REQ_LOOKUP "lookup"
#define PROXY_REQ_UPDATE "update"
#define PROXY_STAT_OK 0 /* operation succeeded */
#define PROXY_STAT_NOKEY 1 /* requested key not found */

View File

@@ -2014,6 +2014,10 @@ extern int var_local_rcpt_code;
" $" VAR_MYNETWORKS
extern char *var_proxy_read_maps;
#define VAR_PROXY_WRITE_MAPS "proxy_write_maps"
#define DEF_PROXY_WRITE_MAPS "" /* Add here: "$" VAR_AUTH_FAIL_MAP */
extern char *var_proxy_write_maps;
/*
* Other.
*/

View File

@@ -56,6 +56,7 @@
#define MAIL_SERVICE_TRACE "trace"
#define MAIL_SERVICE_RELAY "relay"
#define MAIL_SERVICE_PROXYMAP "proxymap"
#define MAIL_SERVICE_PROXYWRITE "proxywrite"
#define MAIL_SERVICE_SCACHE "scache"
/*

View File

@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20071130"
#define MAIL_RELEASE_DATE "2007111203"
#define MAIL_VERSION_NUMBER "2.5"
#ifdef SNAPSHOT

View File

@@ -40,6 +40,7 @@ extern MKMAP *mkmap_cdb_open(const char *);
extern MKMAP *mkmap_hash_open(const char *);
extern MKMAP *mkmap_btree_open(const char *);
extern MKMAP *mkmap_sdbm_open(const char *);
extern MKMAP *mkmap_proxy_open(const char *);
/* LICENSE
/* .ad

View File

@@ -66,6 +66,7 @@
#include <dict_cdb.h>
#include <dict_dbm.h>
#include <dict_sdbm.h>
#include <dict_proxy.h>
#include <sigdelay.h>
#include <mymalloc.h>
@@ -83,6 +84,7 @@ typedef struct {
} MKMAP_OPEN_INFO;
MKMAP_OPEN_INFO mkmap_types[] = {
DICT_TYPE_PROXY, mkmap_proxy_open,
#ifdef HAS_CDB
DICT_TYPE_CDB, mkmap_cdb_open,
#endif

View File

@@ -0,0 +1,58 @@
/*++
/* NAME
/* mkmap_proxy 3
/* SUMMARY
/* create or proxied database
/* SYNOPSIS
/* #include <mkmap.h>
/*
/* MKMAP *mkmap_proxy_open(path)
/* const char *path;
/* DESCRIPTION
/* This module implements support for updating proxy databases.
/*
/* mkmap_proxy_open() is a proxymap-specific helper for the
/* more general mkmap_open() routine.
/*
/* All errors are fatal.
/* SEE ALSO
/* dict_proxy(3), proxy client interface.
/* 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
/*--*/
/* System library. */
#include <sys_defs.h>
/* Utility library. */
#include <mymalloc.h>
#include <dict_proxy.h>
/* Application-specific. */
#include "mkmap.h"
/* mkmap_proxy_open - create or open database */
MKMAP *mkmap_proxy_open(const char *unused_path)
{
MKMAP *mkmap = (MKMAP *) mymalloc(sizeof(*mkmap));
/*
* Fill in the generic members.
*/
mkmap->open = dict_proxy_open;
mkmap->after_open = 0;
mkmap->after_close = 0;
return (mkmap);
}

View File

@@ -304,7 +304,7 @@ void qmgr_queue_throttle(QMGR_QUEUE *queue, DSN *dsn)
queue->fail_cohorts += 1.0 / queue->window;
if (transport->fail_cohort_limit > 0
&& queue->fail_cohorts >= transport->fail_cohort_limit)
queue->window = 0;
queue->window = QMGR_QUEUE_STAT_THROTTLED;
}
/*

View File

@@ -83,6 +83,7 @@ depend: $(MAKES)
# do not edit below this line - it is generated by 'make depend'
postalias.o: ../../include/argv.h
postalias.o: ../../include/dict.h
postalias.o: ../../include/dict_proxy.h
postalias.o: ../../include/mail_conf.h
postalias.o: ../../include/mail_dict.h
postalias.o: ../../include/mail_params.h

View File

@@ -239,6 +239,7 @@
#include <mail_version.h>
#include <mkmap.h>
#include <mail_task.h>
#include <dict_proxy.h>
/* Application-specific. */
@@ -275,6 +276,8 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
if ((open_flags & O_TRUNC) == 0) {
source_fp = VSTREAM_IN;
vstream_control(source_fp, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END);
} else if (strcmp(map_type, DICT_TYPE_PROXY) == 0) {
msg_fatal("can't create maps via the proxy service");
} else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) {
msg_fatal("open %s: %m", path_name);
}
@@ -524,10 +527,14 @@ static int postalias_deletes(VSTREAM *in, char **maps, const int map_count,
* Open maps ahead of time.
*/
dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count);
for (n = 0; n < map_count; n++)
dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ?
for (n = 0; n < map_count; n++) {
map_name = split_at(maps[n], ':');
if (map_name && strcmp(maps[n], DICT_TYPE_PROXY) == 0)
msg_fatal("can't delete map entries via the proxy service");
dicts[n] = (map_name != 0 ?
dict_open3(maps[n], map_name, O_RDWR, dict_flags) :
dict_open3(var_db_type, maps[n], O_RDWR, dict_flags));
}
/*
* Perform all requests.
@@ -556,6 +563,8 @@ static int postalias_delete(const char *map_type, const char *map_name,
DICT *dict;
int status;
if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
msg_fatal("can't delete map entries via the proxy service");
dict = dict_open3(map_type, map_name, O_RDWR, dict_flags);
status = dict_del(dict, key);
dict_close(dict);
@@ -572,6 +581,8 @@ static void postalias_seq(const char *map_type, const char *map_name,
const char *value;
int func;
if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
msg_fatal("can't sequence maps via the proxy service");
dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
if (dict_seq(dict, func, &key, &value) != 0)

View File

@@ -83,6 +83,7 @@ depend: $(MAKES)
# do not edit below this line - it is generated by 'make depend'
postmap.o: ../../include/argv.h
postmap.o: ../../include/dict.h
postmap.o: ../../include/dict_proxy.h
postmap.o: ../../include/mail_conf.h
postmap.o: ../../include/mail_dict.h
postmap.o: ../../include/mail_params.h

View File

@@ -250,6 +250,7 @@
#include <mail_version.h>
#include <mkmap.h>
#include <mail_task.h>
#include <dict_proxy.h>
/* Application-specific. */
@@ -279,6 +280,8 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
if ((open_flags & O_TRUNC) == 0) {
source_fp = VSTREAM_IN;
vstream_control(source_fp, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END);
} else if (strcmp(map_type, DICT_TYPE_PROXY) == 0) {
msg_fatal("can't create maps via the proxy service");
} else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) {
msg_fatal("open %s: %m", path_name);
}
@@ -471,10 +474,14 @@ static int postmap_deletes(VSTREAM *in, char **maps, const int map_count,
* Open maps ahead of time.
*/
dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count);
for (n = 0; n < map_count; n++)
dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ?
for (n = 0; n < map_count; n++) {
map_name = split_at(maps[n], ':');
if (map_name && strcmp(maps[n], DICT_TYPE_PROXY) == 0)
msg_fatal("can't delete map entries via the proxy service");
dicts[n] = (map_name != 0 ?
dict_open3(maps[n], map_name, O_RDWR, dict_flags) :
dict_open3(var_db_type, maps[n], O_RDWR, dict_flags));
}
/*
* Perform all requests.
@@ -503,6 +510,8 @@ static int postmap_delete(const char *map_type, const char *map_name,
DICT *dict;
int status;
if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
msg_fatal("can't delete map entries via the proxy service");
dict = dict_open3(map_type, map_name, O_RDWR, dict_flags);
status = dict_del(dict, key);
dict_close(dict);
@@ -519,6 +528,8 @@ static void postmap_seq(const char *map_type, const char *map_name,
const char *value;
int func;
if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
msg_fatal("can't sequence maps via the proxy service");
dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
if (dict_seq(dict, func, &key, &value) != 0)

View File

@@ -6,9 +6,10 @@
/* SYNOPSIS
/* \fBproxymap\fR [generic Postfix daemon options]
/* DESCRIPTION
/* The \fBproxymap\fR(8) server provides read-only table
/* lookup service to Postfix processes. The purpose
/* of the service is:
/* The \fBproxymap\fR(8) server provides read-only or read-write
/* table lookup service to Postfix processes. These services are
/* implemented with distinct service names: \fBproxymap\fR and
/* \fBproxywrite\fR, respectively. The purpose of these services is:
/* .IP \(bu
/* To overcome chroot restrictions. For example, a chrooted SMTP
/* server needs access to the system passwd file in order to
@@ -33,6 +34,10 @@
/* .sp
/* The total number of connections is limited by the number of
/* proxymap server processes.
/* .IP \(bu
/* To provide single-updater functionality for lookup tables
/* that do not reliably support multiple writers (i.e. all
/* file-based tables).
/* .PP
/* The \fBproxymap\fR(8) server implements the following requests:
/* .IP "\fBopen\fR \fImaptype:mapname flags\fR"
@@ -42,11 +47,26 @@
/* expression table).
/* .IP "\fBlookup\fR \fImaptype:mapname flags key\fR"
/* Look up the data stored under the requested key.
/* The reply is the request completion status code (below) and
/* The reply is the request completion status code and
/* the lookup result value.
/* The \fImaptype:mapname\fR and \fIflags\fR are the same
/* as with the \fBopen\fR request.
/* .IP "\fBupdate\fR \fImaptype:mapname flags key value\fR"
/* Update the data stored under the requested key.
/* The reply is the request completion status code.
/* The \fImaptype:mapname\fR and \fIflags\fR are the same
/* as with the \fBopen\fR request.
/* .sp
/* To implement single-updater maps, specify a process limit
/* of 1 in the master.cf file entry for the proxywrite service.
/* .sp
/* This request is supported in Postfix 2.5 and later.
/* .PP
/* The request completion status is one of OK, RETRY, NOKEY
/* (lookup failed because the key was not found), BAD (malformed
/* request) or DENY (the table is not approved for proxy read
/* or update access).
/*
/* There is no \fBclose\fR command, nor are tables implicitly closed
/* when a client disconnects. The purpose is to share tables among
/* multiple client processes.
@@ -64,8 +84,9 @@
/* SECURITY
/* .ad
/* .fi
/* The \fBproxymap\fR(8) server opens only tables that are approved via the
/* \fBproxy_read_maps\fR configuration parameter, does not talk to
/* The \fBproxymap\fR(8) server opens only tables that are
/* approved via the \fBproxy_read_maps\fR or \fBproxy_write_maps\fR
/* configuration parameters, does not talk to
/* users, and can run at fixed low privilege, chrooted or not.
/* However, running the proxymap server chrooted severely limits
/* usability, because it can open only chrooted tables.
@@ -84,6 +105,15 @@
/* The \fBproxymap\fR(8) server provides service to multiple clients,
/* and must therefore not be used for tables that have high-latency
/* lookups.
/*
/* The \fBproxymap\fR(8) read-write service does not explicitly
/* close lookup tables (even if it did, this could not be relied on,
/* because the process may be terminated between table updates).
/* The read-write service should therefore not be used with tables that
/* leave persistent storage in an inconsistent state between
/* updates (for example, CDB). Tables that support "sync on
/* update" should be safe (for example, Berkeley DB) as should
/* tables that are implemented by a real DBMS.
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
@@ -114,7 +144,13 @@
/* .IP "\fBprocess_name (read-only)\fR"
/* The process name of a Postfix command or daemon process.
/* .IP "\fBproxy_read_maps (see 'postconf -d' output)\fR"
/* The lookup tables that the \fBproxymap\fR(8) server is allowed to access.
/* The lookup tables that the \fBproxymap\fR(8) server is allowed to
/* access for the read-only service.
/* .PP
/* Available in Postfix 2.5 and later:
/* .IP "\fBproxy_write_maps (see 'postconf -d' output)\fR"
/* The lookup tables that the \fBproxymap\fR(8) server is allowed to
/* access for the read-write service.
/* SEE ALSO
/* postconf(5), configuration parameters
/* master(5), generic daemon options
@@ -189,11 +225,12 @@ char *var_rcpt_canon_maps;
char *var_relocated_maps;
char *var_transport_maps;
char *var_proxy_read_maps;
char *var_proxy_write_maps;
/*
* The pre-approved, pre-parsed list of maps.
*/
static HTABLE *proxy_read_maps;
static HTABLE *proxy_auth_maps;
/*
* Shared and static to reduce memory allocation overhead.
@@ -201,8 +238,14 @@ static HTABLE *proxy_read_maps;
static VSTRING *request;
static VSTRING *request_map;
static VSTRING *request_key;
static VSTRING *request_value;
static VSTRING *map_type_name_flags;
/*
* Are we a proxy writer or not?
*/
static int proxy_writer;
/*
* Silly little macros.
*/
@@ -219,6 +262,7 @@ static DICT *proxy_map_find(const char *map_type_name, int request_flags,
#define PROXY_COLON DICT_TYPE_PROXY ":"
#define PROXY_COLON_LEN (sizeof(PROXY_COLON) - 1)
#define READ_OPEN_FLAGS O_RDONLY
#define WRITE_OPEN_FLAGS (O_RDWR | O_CREAT)
/*
* Canonicalize the map name. If the map is not on the approved list,
@@ -230,11 +274,13 @@ static DICT *proxy_map_find(const char *map_type_name, int request_flags,
map_type_name += PROXY_COLON_LEN;
if (strchr(map_type_name, ':') == 0)
PROXY_MAP_FIND_ERROR_RETURN(PROXY_STAT_BAD);
if (htable_locate(proxy_read_maps, map_type_name) == 0) {
if (htable_locate(proxy_auth_maps, map_type_name) == 0) {
msg_warn("request for unapproved table: \"%s\"", map_type_name);
msg_warn("to approve this table for %s access, list %s:%s in %s:%s",
MAIL_SERVICE_PROXYMAP, DICT_TYPE_PROXY, map_type_name,
MAIN_CONF_FILE, VAR_PROXY_READ_MAPS);
proxy_writer == 0 ? "read-only" : "read-write",
DICT_TYPE_PROXY, map_type_name, MAIN_CONF_FILE,
proxy_writer == 0 ? VAR_PROXY_READ_MAPS :
VAR_PROXY_WRITE_MAPS);
PROXY_MAP_FIND_ERROR_RETURN(PROXY_STAT_DENY);
}
@@ -243,13 +289,21 @@ static DICT *proxy_map_find(const char *map_type_name, int request_flags,
*
* Assume that a map instance can be shared among clients with different
* paranoia flag settings and with different map lookup flag settings.
*
* XXX The open() flags are passed implicitly, via the selection of the
* service name. For a more sophisticated interface, appropriate subsets
* of open() flags should be received directly from the client.
*/
vstring_sprintf(map_type_name_flags, "%s:%s", map_type_name,
dict_flags_str(request_flags & DICT_FLAG_NP_INST_MASK));
if ((dict = dict_handle(STR(map_type_name_flags))) == 0)
dict = dict_open(map_type_name, READ_OPEN_FLAGS, request_flags);
dict = dict_open(map_type_name, proxy_writer ?
WRITE_OPEN_FLAGS : READ_OPEN_FLAGS,
request_flags);
if (dict == 0)
msg_panic("proxy_map_find: dict_open null result");
if (proxy_writer)
dict->flags |= DICT_FLAG_SYNC_UPDATE;
dict_register(STR(map_type_name_flags), dict);
return (dict);
}
@@ -297,6 +351,46 @@ static void proxymap_lookup_service(VSTREAM *client_stream)
ATTR_TYPE_END);
}
/* proxymap_update_service - remote update service */
static void proxymap_update_service(VSTREAM *client_stream)
{
int request_flags;
DICT *dict;
int reply_status;
/*
* Process the request.
*/
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request_flags,
ATTR_TYPE_STR, MAIL_ATTR_KEY, request_key,
ATTR_TYPE_STR, MAIL_ATTR_VALUE, request_value,
ATTR_TYPE_END) != 4) {
reply_status = PROXY_STAT_BAD;
} else if (proxy_writer == 0) {
msg_warn("refusing %s update request on non-%s service",
STR(request_map), MAIL_SERVICE_PROXYWRITE);
reply_status = PROXY_STAT_DENY;
} else if ((dict = proxy_map_find(STR(request_map), request_flags,
&reply_status)) == 0) {
/* void */ ;
} else {
dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
| (request_flags & DICT_FLAG_RQST_MASK));
dict_put(dict, STR(request_key), STR(request_value));
reply_status = PROXY_STAT_OK;
}
/*
* Respond to the client.
*/
attr_print(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_INT, MAIL_ATTR_STATUS, reply_status,
ATTR_TYPE_END);
}
/* proxymap_open_service - open remote lookup table */
static void proxymap_open_service(VSTREAM *client_stream)
@@ -355,6 +449,8 @@ static void proxymap_service(VSTREAM *client_stream, char *unused_service,
ATTR_TYPE_END) == 1) {
if (VSTREQ(request, PROXY_REQ_LOOKUP)) {
proxymap_lookup_service(client_stream);
} else if (VSTREQ(request, PROXY_REQ_UPDATE)) {
proxymap_update_service(client_stream);
} else if (VSTREQ(request, PROXY_REQ_OPEN)) {
proxymap_open_service(client_stream);
} else {
@@ -381,26 +477,37 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
/* post_jail_init - initialization after privilege drop */
static void post_jail_init(char *unused_name, char **unused_argv)
static void post_jail_init(char *service_name, char **unused_argv)
{
const char *sep = ", \t\r\n";
char *saved_filter;
char *bp;
char *type_name;
/*
* Are we proxy writer?
*/
if (strcmp(service_name, MAIL_SERVICE_PROXYWRITE) == 0)
proxy_writer = 1;
else if (strcmp(service_name, MAIL_SERVICE_PROXYMAP) != 0)
msg_fatal("service name must be one of %s or %s",
MAIL_SERVICE_PROXYMAP, MAIL_SERVICE_PROXYMAP);
/*
* Pre-allocate buffers.
*/
request = vstring_alloc(10);
request_map = vstring_alloc(10);
request_key = vstring_alloc(10);
request_value = vstring_alloc(10);
map_type_name_flags = vstring_alloc(10);
/*
* Prepare the pre-approved list of proxied tables.
*/
saved_filter = bp = mystrdup(var_proxy_read_maps);
proxy_read_maps = htable_create(13);
saved_filter = bp = mystrdup(proxy_writer ? var_proxy_write_maps :
var_proxy_read_maps);
proxy_auth_maps = htable_create(13);
while ((type_name = mystrtok(&bp, sep)) != 0) {
if (strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN))
continue;
@@ -408,8 +515,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
type_name += PROXY_COLON_LEN;
} while (!strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN));
if (strchr(type_name, ':') != 0
&& htable_locate(proxy_read_maps, type_name) == 0)
(void) htable_enter(proxy_read_maps, type_name, (char *) 0);
&& htable_locate(proxy_auth_maps, type_name) == 0)
(void) htable_enter(proxy_auth_maps, type_name, (char *) 0);
}
myfree(saved_filter);
@@ -418,6 +525,13 @@ static void post_jail_init(char *unused_name, char **unused_argv)
* time, so we don't have to do it another time.
*/
var_idle_limit = 1;
/*
* Never, ever, get killed by a master signal, as that could corrupt a
* persistent database when we're in the middle of an update.
*/
if (proxy_writer != 0)
setsid();
}
/* pre_accept - see if tables have changed */
@@ -426,7 +540,7 @@ static void pre_accept(char *unused_name, char **unused_argv)
{
const char *table;
if ((table = dict_changed_name()) != 0) {
if (proxy_writer == 0 && (table = dict_changed_name()) != 0) {
msg_info("table %s has changed -- restarting", table);
exit(0);
}
@@ -452,6 +566,7 @@ int main(int argc, char **argv)
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
VAR_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 0, 0,
VAR_PROXY_WRITE_MAPS, DEF_PROXY_WRITE_MAPS, &var_proxy_write_maps, 0, 0,
0,
};
@@ -464,5 +579,6 @@ int main(int argc, char **argv)
MAIL_SERVER_STR_TABLE, str_table,
MAIL_SERVER_POST_INIT, post_jail_init,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
/* XXX MAIL_SERVER_SOLITARY if proxywrite */
0);
}

View File

@@ -306,7 +306,7 @@ void qmgr_queue_throttle(QMGR_QUEUE *queue, DSN *dsn)
queue->fail_cohorts += 1.0 / queue->window;
if (transport->fail_cohort_limit > 0
&& queue->fail_cohorts >= transport->fail_cohort_limit)
queue->window = 0;
queue->window = QMGR_QUEUE_STAT_THROTTLED;
}
/*

View File

@@ -95,7 +95,9 @@ extern DICT *dict_debug(DICT *);
#define DICT_FLAG_PARANOID \
(DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY | DICT_FLAG_NO_UNAUTH)
#define DICT_FLAG_IMPL_MASK (DICT_FLAG_FIXED | DICT_FLAG_PATTERN)
#define DICT_FLAG_RQST_MASK DICT_FLAG_FOLD_ANY
#define DICT_FLAG_RQST_MASK (DICT_FLAG_FOLD_ANY | DICT_FLAG_LOCK | \
DICT_FLAG_DUP_REPLACE | DICT_FLAG_DUP_WARN | \
DICT_FLAG_SYNC_UPDATE)
#define DICT_FLAG_NP_INST_MASK ~(DICT_FLAG_IMPL_MASK | DICT_FLAG_RQST_MASK)
#define DICT_FLAG_INST_MASK (DICT_FLAG_NP_INST_MASK | DICT_FLAG_PARANOID)