mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-31 14:17:41 +00:00
snapshot-20010729
This commit is contained in:
committed by
Viktor Dukhovni
parent
04d0db6c63
commit
4fe7066ddd
2
postfix/.indent.pro
vendored
2
postfix/.indent.pro
vendored
@@ -20,6 +20,8 @@
|
|||||||
-TCONFIG_STR_TABLE
|
-TCONFIG_STR_TABLE
|
||||||
-TCONFIG_TIME_FN_TABLE
|
-TCONFIG_TIME_FN_TABLE
|
||||||
-TCONFIG_TIME_TABLE
|
-TCONFIG_TIME_TABLE
|
||||||
|
-TCTABLE
|
||||||
|
-TCTABLE_ENTRY
|
||||||
-TDELIVER_ATTR
|
-TDELIVER_ATTR
|
||||||
-TDELIVER_REQUEST
|
-TDELIVER_REQUEST
|
||||||
-TDICT
|
-TDICT
|
||||||
|
@@ -5350,13 +5350,27 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
20010719
|
20010719
|
||||||
|
|
||||||
Feature: stiffer coupling between mail arrival rates and
|
Feature: stiffer coupling between mail receiving rates and
|
||||||
mail delivery rates, using a trivial token-based scheme
|
mail delivery rates, using a trivial token-based scheme,
|
||||||
where qmgr provides a token when it retrieves mail from
|
implemented by reading and writing an in-memory pipe. The
|
||||||
the incoming queue, and where the cleanup daemon wants a
|
queue manager produces one token when it retrieves mail
|
||||||
token after enqueueing mail. If no token is available the
|
from the incoming queue. The cleanup daemon consumes one
|
||||||
cleanup server pauses briefly and proceeds anyway. This
|
token when it adds mail to the incoming queue. If no token
|
||||||
allows input rates to gradually exceed output rates. After
|
is available the cleanup server pauses for $in_flow_delay
|
||||||
sustained exposure to high input loads Postfix reverts to
|
seconds and proceeds anyway. The delay allows mail sending
|
||||||
the old situation where it sacrifices output rates in favor
|
process to catch up and access the disk. Valid delays are
|
||||||
of receiving mail.
|
0..10 seconds.
|
||||||
|
|
||||||
|
20010727
|
||||||
|
|
||||||
|
Bugfix: updated LDAP client module from LaMont Jones, HP.
|
||||||
|
|
||||||
|
20010729
|
||||||
|
|
||||||
|
Bugfix: recursive restrictions could clobber non-reentrant
|
||||||
|
address resolving results. Problem found by Victor Duchovni,
|
||||||
|
morganstanley.com.
|
||||||
|
|
||||||
|
Bugfix: the not yet published DUNNO table lookup result
|
||||||
|
did not prevent further partial key lookups in the same
|
||||||
|
table. Problem found by Victor Duchovni, morganstanley.com.
|
||||||
|
@@ -12,9 +12,10 @@ the mysqlclient library (and libm) to AUXLIBS, for example:
|
|||||||
|
|
||||||
make -f Makefile.init makefiles \
|
make -f Makefile.init makefiles \
|
||||||
'CCARGS=-DHAS_MYSQL -I/usr/local/mysql/include' \
|
'CCARGS=-DHAS_MYSQL -I/usr/local/mysql/include' \
|
||||||
'AUXLIBS=-L/usr/local/mysql/lib -lmysqlclient -lm'
|
'AUXLIBS=-L/usr/local/mysql/lib -lmysqlclient -lz -lm'
|
||||||
|
|
||||||
then, just run 'make'.
|
then, just run 'make'. This requires libz, the compression library.
|
||||||
|
Older mysql implementations build without libz.
|
||||||
|
|
||||||
Postfix installations which may benefit from using mysql map types
|
Postfix installations which may benefit from using mysql map types
|
||||||
include sites that have a need for instantaneous updates of
|
include sites that have a need for instantaneous updates of
|
||||||
|
@@ -23,6 +23,13 @@
|
|||||||
#ldap_server_port = 389
|
#ldap_server_port = 389
|
||||||
|
|
||||||
# The ldap_query_filter parameter specifies the filter used for queries.
|
# The ldap_query_filter parameter specifies the filter used for queries.
|
||||||
|
# The replacement for "%s" is the address input into the map; e.g.
|
||||||
|
# for alias maps, the "user" part (the RFC 2822 local-part) of
|
||||||
|
# "user@domain.com" for To: addresses destined for local delivery
|
||||||
|
# (those matching $mydestination or a virtual domain), and all of
|
||||||
|
# "user@domain.com" (the RFC 2822 addr-spec) for other addresses.
|
||||||
|
# "%u" provides just the user portion of the input, and "%d" provides
|
||||||
|
# just the hostname.
|
||||||
#
|
#
|
||||||
#ldap_query_filter = (mailacceptinggeneralid=%s)
|
#ldap_query_filter = (mailacceptinggeneralid=%s)
|
||||||
|
|
||||||
@@ -31,6 +38,13 @@
|
|||||||
#
|
#
|
||||||
#ldap_result_attribute = maildrop
|
#ldap_result_attribute = maildrop
|
||||||
|
|
||||||
|
# The ldap_special_result_attribute lists the attribute(s) of an
|
||||||
|
# entry which contain links, either ldap url's or distinguished names.
|
||||||
|
# The entries referenced by these links are (recursively) treated as if
|
||||||
|
# they were contained in the referencing entity.
|
||||||
|
#
|
||||||
|
# ldap_special_result_attribute =
|
||||||
|
|
||||||
# The ldap_scope parameter specifies the LDAP search scope: sub, base, or one.
|
# The ldap_scope parameter specifies the LDAP search scope: sub, base, or one.
|
||||||
#
|
#
|
||||||
#ldap_scope = sub
|
#ldap_scope = sub
|
||||||
|
@@ -296,6 +296,9 @@ domains with "relay access denied"</a>
|
|||||||
<li><a href="#domain_mailbox">Receiving a virtual domain in a
|
<li><a href="#domain_mailbox">Receiving a virtual domain in a
|
||||||
mailbox</a>
|
mailbox</a>
|
||||||
|
|
||||||
|
<li><a href="#virtual_logging">Postfix logs delivery to virtual
|
||||||
|
address with the wrong name</a>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a name="address_rewriting"><h3>Address rewriting</h3>
|
<a name="address_rewriting"><h3>Address rewriting</h3>
|
||||||
@@ -2716,6 +2719,44 @@ your system supports, use the command <b>postconf -m</b>.
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
|
<a name="virtual_logging"><h3>Postfix logs delivery to virtual
|
||||||
|
address with the wrong name</h3></a>
|
||||||
|
|
||||||
|
When Postfix delivers mail for a virtual address <i>vuser@vdomain.name</i>
|
||||||
|
that is aliased to a local user, then Postfix logs the local username
|
||||||
|
instead of the virtual one.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
Changing this requires non-trivial changes, because Postfix only
|
||||||
|
remembers the address that it delivers to, not the address that
|
||||||
|
was original specified in, for example, the SMTP MAIL FROM command.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
A workaround exists. It uses regular expressions. This
|
||||||
|
can be expensive if you have many virtual domains.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
/etc/postfix/main.cf:
|
||||||
|
virtual_maps = regexp:/etc/postfix/virtual_regexp
|
||||||
|
recipient_delimiter = +
|
||||||
|
|
||||||
|
/etc/postfix/virtual_regexp:
|
||||||
|
/^vdomain\.name$/ whatever
|
||||||
|
/(.*)@vdomain\.name$/ localuser+$1=vdomain.name
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
This delivers the mail as
|
||||||
|
<i>localuser+vuser=vdomain.name@your.domain</i>.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
<a name="masquerade"><h3>Address masquerading with exceptions</h3></a>
|
<a name="masquerade"><h3>Address masquerading with exceptions</h3></a>
|
||||||
|
|
||||||
For people outside your organization it can be desirable to only
|
For people outside your organization it can be desirable to only
|
||||||
|
@@ -271,6 +271,6 @@ int main(int argc, char **argv)
|
|||||||
MAIL_SERVER_PRE_INIT, cleanup_pre_jail,
|
MAIL_SERVER_PRE_INIT, cleanup_pre_jail,
|
||||||
MAIL_SERVER_POST_INIT, cleanup_post_jail,
|
MAIL_SERVER_POST_INIT, cleanup_post_jail,
|
||||||
MAIL_SERVER_PRE_ACCEPT, pre_accept,
|
MAIL_SERVER_PRE_ACCEPT, pre_accept,
|
||||||
MAIL_SERVER_FLOW_CTL,
|
MAIL_SERVER_IN_FLOW_DELAY, var_in_flow_delay,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
@@ -69,7 +69,7 @@
|
|||||||
/* char *var_export_environ;
|
/* char *var_export_environ;
|
||||||
/* char *var_debug_peer_list;
|
/* char *var_debug_peer_list;
|
||||||
/* int var_debug_peer_level;
|
/* int var_debug_peer_level;
|
||||||
/* int var_glob_flow_ctl;
|
/* int var_in_flow_delay;
|
||||||
/*
|
/*
|
||||||
/* void mail_params_init()
|
/* void mail_params_init()
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
@@ -186,7 +186,7 @@ char *var_def_transport;
|
|||||||
char *var_mynetworks_style;
|
char *var_mynetworks_style;
|
||||||
char *var_verp_delims;
|
char *var_verp_delims;
|
||||||
char *var_verp_filter;
|
char *var_verp_filter;
|
||||||
int var_glob_flow_ctl;
|
int var_in_flow_delay;
|
||||||
|
|
||||||
char *var_import_environ;
|
char *var_import_environ;
|
||||||
char *var_export_environ;
|
char *var_export_environ;
|
||||||
@@ -327,7 +327,6 @@ void mail_params_init()
|
|||||||
VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0,
|
VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0,
|
||||||
VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0,
|
VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0,
|
||||||
VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
|
VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
|
||||||
VAR_GLOB_FLOW_CTL, DEF_GLOB_FLOW_CTL, &var_glob_flow_ctl, 0, 0,
|
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
static CONFIG_TIME_TABLE time_defaults[] = {
|
static CONFIG_TIME_TABLE time_defaults[] = {
|
||||||
@@ -339,6 +338,7 @@ void mail_params_init()
|
|||||||
VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0,
|
VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0,
|
||||||
VAR_FLOCK_STALE, DEF_FLOCK_STALE, &var_flock_stale, 1, 0,
|
VAR_FLOCK_STALE, DEF_FLOCK_STALE, &var_flock_stale, 1, 0,
|
||||||
VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0,
|
VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0,
|
||||||
|
VAR_IN_FLOW_DELAY, DEF_IN_FLOW_DELAY, &var_in_flow_delay, 0, 10,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
static CONFIG_BOOL_TABLE bool_defaults[] = {
|
static CONFIG_BOOL_TABLE bool_defaults[] = {
|
||||||
|
@@ -1284,15 +1284,17 @@ extern char *var_verp_delims;
|
|||||||
extern char *var_verp_filter;
|
extern char *var_verp_filter;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global flow control. This allows for a stiffer coupling between receiving
|
* Inbound mail flow control. This allows for a stiffer coupling between
|
||||||
* programs and the queue manager, so that receiving processes cannot easily
|
* receiving mail and sending mail. A sending process produces one token for
|
||||||
* overwhelm the file system. The coupling is not so tight that Postfix
|
* each message that it takes from the incoming queue; a receiving process
|
||||||
* stops receiving mail althogether. It just slows down a bit so that
|
* consumes one token for each message that it adds to the incoming queue.
|
||||||
* sending processes get a chance to read from the disk.
|
* When no token is available (Postfix receives more mail than it is able to
|
||||||
|
* deliver) a receiving process pauses for $in_flow_delay seconds so that
|
||||||
|
* the sending processes get a chance to access the disk.
|
||||||
*/
|
*/
|
||||||
#define VAR_GLOB_FLOW_CTL "global_mail_flow_control"
|
#define VAR_IN_FLOW_DELAY "in_flow_delay"
|
||||||
#define DEF_GLOB_FLOW_CTL 0
|
#define DEF_IN_FLOW_DELAY "1s"
|
||||||
extern int var_glob_flow_ctl;
|
extern int var_in_flow_delay;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* Version of this program.
|
* Version of this program.
|
||||||
*/
|
*/
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "Snapshot-20010722"
|
#define DEF_MAIL_VERSION "Snapshot-20010729"
|
||||||
extern char *var_mail_version;
|
extern char *var_mail_version;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
@@ -232,6 +232,7 @@ multi_server.o: ../../include/mail_params.h
|
|||||||
multi_server.o: ../../include/mail_conf.h
|
multi_server.o: ../../include/mail_conf.h
|
||||||
multi_server.o: ../../include/timed_ipc.h
|
multi_server.o: ../../include/timed_ipc.h
|
||||||
multi_server.o: ../../include/resolve_local.h
|
multi_server.o: ../../include/resolve_local.h
|
||||||
|
multi_server.o: mail_flow.h
|
||||||
multi_server.o: master_proto.h
|
multi_server.o: master_proto.h
|
||||||
multi_server.o: mail_server.h
|
multi_server.o: mail_server.h
|
||||||
single_server.o: single_server.c
|
single_server.o: single_server.c
|
||||||
@@ -259,6 +260,7 @@ single_server.o: ../../include/debug_process.h
|
|||||||
single_server.o: ../../include/mail_conf.h
|
single_server.o: ../../include/mail_conf.h
|
||||||
single_server.o: ../../include/timed_ipc.h
|
single_server.o: ../../include/timed_ipc.h
|
||||||
single_server.o: ../../include/resolve_local.h
|
single_server.o: ../../include/resolve_local.h
|
||||||
|
single_server.o: mail_flow.h
|
||||||
single_server.o: master_proto.h
|
single_server.o: master_proto.h
|
||||||
single_server.o: mail_server.h
|
single_server.o: mail_server.h
|
||||||
trigger_server.o: trigger_server.c
|
trigger_server.o: trigger_server.c
|
||||||
@@ -285,5 +287,6 @@ trigger_server.o: ../../include/mail_task.h
|
|||||||
trigger_server.o: ../../include/debug_process.h
|
trigger_server.o: ../../include/debug_process.h
|
||||||
trigger_server.o: ../../include/mail_conf.h
|
trigger_server.o: ../../include/mail_conf.h
|
||||||
trigger_server.o: ../../include/resolve_local.h
|
trigger_server.o: ../../include/resolve_local.h
|
||||||
|
trigger_server.o: mail_flow.h
|
||||||
trigger_server.o: master_proto.h
|
trigger_server.o: master_proto.h
|
||||||
trigger_server.o: mail_server.h
|
trigger_server.o: mail_server.h
|
||||||
|
@@ -11,6 +11,8 @@
|
|||||||
/*
|
/*
|
||||||
/* void mail_flow_put(count)
|
/* void mail_flow_put(count)
|
||||||
/* int count;
|
/* int count;
|
||||||
|
/*
|
||||||
|
/* int mail_flow_count()
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* This module implements a simple flow control mechanism that
|
/* This module implements a simple flow control mechanism that
|
||||||
/* is based on tokens that are consumed by mail receiving processes
|
/* is based on tokens that are consumed by mail receiving processes
|
||||||
@@ -23,6 +25,8 @@
|
|||||||
/* mail_flow_put() produces the specified number of tokens. The
|
/* mail_flow_put() produces the specified number of tokens. The
|
||||||
/* token producing process is expected to produce new tokens
|
/* token producing process is expected to produce new tokens
|
||||||
/* whenever it falls idle and no more tokens are available.
|
/* whenever it falls idle and no more tokens are available.
|
||||||
|
/*
|
||||||
|
/* mail_flow_count() returns the number of available tokens.
|
||||||
/* BUGS
|
/* BUGS
|
||||||
/* The producer needs to wake up periodically to ensure that
|
/* The producer needs to wake up periodically to ensure that
|
||||||
/* tokens are not lost due to leakage.
|
/* tokens are not lost due to leakage.
|
||||||
@@ -110,3 +114,15 @@ int mail_flow_put(int len)
|
|||||||
msg_info("%s: %d %d", myname, len, len - count);
|
msg_info("%s: %d %d", myname, len, len - count);
|
||||||
return (len - count);
|
return (len - count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mail_flow_count - return number of available tokens */
|
||||||
|
|
||||||
|
int mail_flow_count(void)
|
||||||
|
{
|
||||||
|
char *myname = "mail_flow_count";
|
||||||
|
int count;
|
||||||
|
|
||||||
|
if ((count = peekfd(MASTER_FLOW_READ)) < 0)
|
||||||
|
msg_warn("%s: %m", myname);
|
||||||
|
return (count);
|
||||||
|
}
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
extern int mail_flow_get(int);
|
extern int mail_flow_get(int);
|
||||||
extern int mail_flow_put(int);
|
extern int mail_flow_put(int);
|
||||||
|
extern int mail_flow_count(void);
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
#define MAIL_SERVER_EXIT 13
|
#define MAIL_SERVER_EXIT 13
|
||||||
#define MAIL_SERVER_PRE_ACCEPT 14
|
#define MAIL_SERVER_PRE_ACCEPT 14
|
||||||
|
|
||||||
#define MAIL_SERVER_FLOW_CTL 20
|
#define MAIL_SERVER_IN_FLOW_DELAY 20
|
||||||
|
|
||||||
typedef void (*MAIL_SERVER_INIT_FN) (char *, char **);
|
typedef void (*MAIL_SERVER_INIT_FN) (char *, char **);
|
||||||
typedef int (*MAIL_SERVER_LOOP_FN) (char *, char **);
|
typedef int (*MAIL_SERVER_LOOP_FN) (char *, char **);
|
||||||
|
@@ -27,4 +27,7 @@ void master_flow_init(void)
|
|||||||
|
|
||||||
non_blocking(master_flow_pipe[0], NON_BLOCKING);
|
non_blocking(master_flow_pipe[0], NON_BLOCKING);
|
||||||
non_blocking(master_flow_pipe[1], NON_BLOCKING);
|
non_blocking(master_flow_pipe[1], NON_BLOCKING);
|
||||||
|
|
||||||
|
close_on_exec(master_flow_pipe[0], CLOSE_ON_EXEC);
|
||||||
|
close_on_exec(master_flow_pipe[1], CLOSE_ON_EXEC);
|
||||||
}
|
}
|
||||||
|
@@ -95,6 +95,9 @@
|
|||||||
/* Function to be executed prior to accepting a new connection.
|
/* Function to be executed prior to accepting a new connection.
|
||||||
/* .sp
|
/* .sp
|
||||||
/* Only the last instance of this parameter type is remembered.
|
/* Only the last instance of this parameter type is remembered.
|
||||||
|
/* .IP "MAIL_SERVER_IN_FLOW_DELAY (int)"
|
||||||
|
/* The amount of seconds to pause when no "mail flow control token"
|
||||||
|
/* is available. A token is consumed for each connection request.
|
||||||
/* .PP
|
/* .PP
|
||||||
/* multi_server_disconnect() should be called by the application
|
/* multi_server_disconnect() should be called by the application
|
||||||
/* when a client disconnects.
|
/* when a client disconnects.
|
||||||
@@ -168,6 +171,7 @@
|
|||||||
#include <mail_conf.h>
|
#include <mail_conf.h>
|
||||||
#include <timed_ipc.h>
|
#include <timed_ipc.h>
|
||||||
#include <resolve_local.h>
|
#include <resolve_local.h>
|
||||||
|
#include <mail_flow.h>
|
||||||
|
|
||||||
/* Process manager. */
|
/* Process manager. */
|
||||||
|
|
||||||
@@ -190,6 +194,7 @@ static void (*multi_server_accept) (int, char *);
|
|||||||
static void (*multi_server_onexit) (char *, char **);
|
static void (*multi_server_onexit) (char *, char **);
|
||||||
static void (*multi_server_pre_accept) (char *, char **);
|
static void (*multi_server_pre_accept) (char *, char **);
|
||||||
static VSTREAM *multi_server_lock;
|
static VSTREAM *multi_server_lock;
|
||||||
|
static int multi_server_in_flow_delay;
|
||||||
|
|
||||||
/* multi_server_exit - normal termination */
|
/* multi_server_exit - normal termination */
|
||||||
|
|
||||||
@@ -253,6 +258,15 @@ static void multi_server_execute(int unused_event, char *context)
|
|||||||
event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit);
|
event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* multi_server_enable_read - enable read events */
|
||||||
|
|
||||||
|
static void multi_server_enable_read(int unused_event, char *context)
|
||||||
|
{
|
||||||
|
VSTREAM *stream = (VSTREAM *) context;
|
||||||
|
|
||||||
|
event_enable_read(vstream_fileno(stream), multi_server_execute, (char *) stream);
|
||||||
|
}
|
||||||
|
|
||||||
/* multi_server_wakeup - wake up application */
|
/* multi_server_wakeup - wake up application */
|
||||||
|
|
||||||
static void multi_server_wakeup(int fd)
|
static void multi_server_wakeup(int fd)
|
||||||
@@ -266,7 +280,11 @@ static void multi_server_wakeup(int fd)
|
|||||||
client_count++;
|
client_count++;
|
||||||
stream = vstream_fdopen(fd, O_RDWR);
|
stream = vstream_fdopen(fd, O_RDWR);
|
||||||
timed_ipc_setup(stream);
|
timed_ipc_setup(stream);
|
||||||
event_enable_read(fd, multi_server_execute, (char *) stream);
|
if (multi_server_in_flow_delay > 0 && mail_flow_get(1) < 0)
|
||||||
|
event_request_timer(multi_server_enable_read, (char *) stream,
|
||||||
|
multi_server_in_flow_delay);
|
||||||
|
else
|
||||||
|
multi_server_enable_read(0, (char *) stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* multi_server_accept_local - accept client connection request */
|
/* multi_server_accept_local - accept client connection request */
|
||||||
@@ -498,6 +516,9 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
|
|||||||
case MAIL_SERVER_PRE_ACCEPT:
|
case MAIL_SERVER_PRE_ACCEPT:
|
||||||
multi_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
|
multi_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
|
||||||
break;
|
break;
|
||||||
|
case MAIL_SERVER_IN_FLOW_DELAY:
|
||||||
|
multi_server_in_flow_delay = va_arg(ap, int);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
msg_panic("%s: unknown argument type: %d", myname, key);
|
msg_panic("%s: unknown argument type: %d", myname, key);
|
||||||
}
|
}
|
||||||
|
@@ -92,6 +92,9 @@
|
|||||||
/* Function to be executed prior to accepting a new connection.
|
/* Function to be executed prior to accepting a new connection.
|
||||||
/* .sp
|
/* .sp
|
||||||
/* Only the last instance of this parameter type is remembered.
|
/* Only the last instance of this parameter type is remembered.
|
||||||
|
/* .IP "MAIL_SERVER_IN_FLOW_DELAY (int)"
|
||||||
|
/* The amount of seconds to pause when no "mail flow control token"
|
||||||
|
/* is available. A token is consumed for each connection request.
|
||||||
/* .PP
|
/* .PP
|
||||||
/* The var_use_limit variable limits the number of clients that
|
/* The var_use_limit variable limits the number of clients that
|
||||||
/* a server can service before it commits suicide.
|
/* a server can service before it commits suicide.
|
||||||
@@ -184,7 +187,7 @@ static void (*single_server_accept) (int, char *);
|
|||||||
static void (*single_server_onexit) (char *, char **);
|
static void (*single_server_onexit) (char *, char **);
|
||||||
static void (*single_server_pre_accept) (char *, char **);
|
static void (*single_server_pre_accept) (char *, char **);
|
||||||
static VSTREAM *single_server_lock;
|
static VSTREAM *single_server_lock;
|
||||||
static int single_server_flow_ctl;
|
static int single_server_in_flow_delay;
|
||||||
|
|
||||||
/* single_server_exit - normal termination */
|
/* single_server_exit - normal termination */
|
||||||
|
|
||||||
@@ -233,6 +236,8 @@ static void single_server_wakeup(int fd)
|
|||||||
timed_ipc_setup(stream);
|
timed_ipc_setup(stream);
|
||||||
if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
|
if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
|
||||||
single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
|
single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
|
||||||
|
if (single_server_in_flow_delay > 0 && mail_flow_get(1) < 0)
|
||||||
|
doze(single_server_in_flow_delay * 1000000);
|
||||||
single_server_service(stream, single_server_name, single_server_argv);
|
single_server_service(stream, single_server_name, single_server_argv);
|
||||||
(void) vstream_fclose(stream);
|
(void) vstream_fclose(stream);
|
||||||
if (master_notify(var_pid, MASTER_STAT_AVAIL) < 0)
|
if (master_notify(var_pid, MASTER_STAT_AVAIL) < 0)
|
||||||
@@ -240,9 +245,6 @@ static void single_server_wakeup(int fd)
|
|||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("connection closed");
|
msg_info("connection closed");
|
||||||
use_count++;
|
use_count++;
|
||||||
if (single_server_flow_ctl)
|
|
||||||
if (mail_flow_get(1) < 0)
|
|
||||||
rand_sleep(single_server_flow_ctl, 0);
|
|
||||||
if (var_idle_limit > 0)
|
if (var_idle_limit > 0)
|
||||||
event_request_timer(single_server_timeout, (char *) 0, var_idle_limit);
|
event_request_timer(single_server_timeout, (char *) 0, var_idle_limit);
|
||||||
}
|
}
|
||||||
@@ -474,8 +476,8 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
|
|||||||
case MAIL_SERVER_PRE_ACCEPT:
|
case MAIL_SERVER_PRE_ACCEPT:
|
||||||
single_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
|
single_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
|
||||||
break;
|
break;
|
||||||
case MAIL_SERVER_FLOW_CTL:
|
case MAIL_SERVER_IN_FLOW_DELAY:
|
||||||
single_server_flow_ctl = var_glob_flow_ctl;
|
single_server_in_flow_delay = va_arg(ap, int);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
msg_panic("%s: unknown argument type: %d", myname, key);
|
msg_panic("%s: unknown argument type: %d", myname, key);
|
||||||
|
@@ -99,6 +99,9 @@
|
|||||||
/* Function to be executed prior to accepting a new request.
|
/* Function to be executed prior to accepting a new request.
|
||||||
/* .sp
|
/* .sp
|
||||||
/* Only the last instance of this parameter type is remembered.
|
/* Only the last instance of this parameter type is remembered.
|
||||||
|
/* .IP "MAIL_SERVER_IN_FLOW_DELAY (int)"
|
||||||
|
/* The amount of seconds to pause when no "mail flow control token"
|
||||||
|
/* is available. A token is consumed for each connection request.
|
||||||
/* .PP
|
/* .PP
|
||||||
/* The var_use_limit variable limits the number of clients that
|
/* The var_use_limit variable limits the number of clients that
|
||||||
/* a server can service before it commits suicide.
|
/* a server can service before it commits suicide.
|
||||||
@@ -169,6 +172,7 @@
|
|||||||
#include <debug_process.h>
|
#include <debug_process.h>
|
||||||
#include <mail_conf.h>
|
#include <mail_conf.h>
|
||||||
#include <resolve_local.h>
|
#include <resolve_local.h>
|
||||||
|
#include <mail_flow.h>
|
||||||
|
|
||||||
/* Process manager. */
|
/* Process manager. */
|
||||||
|
|
||||||
@@ -190,6 +194,7 @@ static void (*trigger_server_accept) (int, char *);
|
|||||||
static void (*trigger_server_onexit) (char *, char **);
|
static void (*trigger_server_onexit) (char *, char **);
|
||||||
static void (*trigger_server_pre_accept) (char *, char **);
|
static void (*trigger_server_pre_accept) (char *, char **);
|
||||||
static VSTREAM *trigger_server_lock;
|
static VSTREAM *trigger_server_lock;
|
||||||
|
static int trigger_server_in_flow_delay;
|
||||||
|
|
||||||
/* trigger_server_exit - normal termination */
|
/* trigger_server_exit - normal termination */
|
||||||
|
|
||||||
@@ -230,6 +235,8 @@ static void trigger_server_wakeup(int fd)
|
|||||||
*/
|
*/
|
||||||
if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
|
if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
|
||||||
trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
|
trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
|
||||||
|
if (trigger_server_in_flow_delay > 0 && mail_flow_get(1) < 0)
|
||||||
|
doze(trigger_server_in_flow_delay * 1000000);
|
||||||
if ((len = read(fd, buf, sizeof(buf))) >= 0)
|
if ((len = read(fd, buf, sizeof(buf))) >= 0)
|
||||||
trigger_server_service(buf, len, trigger_server_name,
|
trigger_server_service(buf, len, trigger_server_name,
|
||||||
trigger_server_argv);
|
trigger_server_argv);
|
||||||
@@ -469,6 +476,9 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
|
|||||||
case MAIL_SERVER_PRE_ACCEPT:
|
case MAIL_SERVER_PRE_ACCEPT:
|
||||||
trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
|
trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
|
||||||
break;
|
break;
|
||||||
|
case MAIL_SERVER_IN_FLOW_DELAY:
|
||||||
|
trigger_server_in_flow_delay = va_arg(ap, int);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
msg_panic("%s: unknown argument type: %d", myname, key);
|
msg_panic("%s: unknown argument type: %d", myname, key);
|
||||||
}
|
}
|
||||||
|
@@ -421,7 +421,7 @@ static int qmgr_loop(char *unused_name, char **unused_argv)
|
|||||||
{
|
{
|
||||||
char *in_path = 0;
|
char *in_path = 0;
|
||||||
char *df_path = 0;
|
char *df_path = 0;
|
||||||
int token_count;
|
int token_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This routine runs as part of the event handling loop, after the event
|
* This routine runs as part of the event handling loop, after the event
|
||||||
@@ -456,13 +456,13 @@ int token_count;
|
|||||||
* Global flow control. If enabled, slow down receiving processes that
|
* Global flow control. If enabled, slow down receiving processes that
|
||||||
* get ahead of the queue manager, but don't block them completely.
|
* get ahead of the queue manager, but don't block them completely.
|
||||||
*/
|
*/
|
||||||
if (var_glob_flow_ctl) {
|
if (var_in_flow_delay > 0) {
|
||||||
if (in_path != 0)
|
if (in_path != 0)
|
||||||
mail_flow_put(1);
|
mail_flow_put(1);
|
||||||
else if ((token_count = peekfd(MASTER_FLOW_READ)) < var_proc_limit)
|
else if ((token_count = mail_flow_count()) < var_proc_limit)
|
||||||
mail_flow_put(var_proc_limit - token_count);
|
mail_flow_put(var_proc_limit - token_count);
|
||||||
else if (token_count > var_proc_limit)
|
else if (token_count > var_proc_limit)
|
||||||
mail_flow_get(token_count - var_proc_limit);
|
mail_flow_get(token_count - var_proc_limit);
|
||||||
}
|
}
|
||||||
if (in_path || df_path)
|
if (in_path || df_path)
|
||||||
return (DONT_WAIT);
|
return (DONT_WAIT);
|
||||||
@@ -514,7 +514,7 @@ static void qmgr_post_init(char *unused_name, char **unused_argv)
|
|||||||
qmgr_incoming = qmgr_scan_create(MAIL_QUEUE_INCOMING);
|
qmgr_incoming = qmgr_scan_create(MAIL_QUEUE_INCOMING);
|
||||||
qmgr_deferred = qmgr_scan_create(MAIL_QUEUE_DEFERRED);
|
qmgr_deferred = qmgr_scan_create(MAIL_QUEUE_DEFERRED);
|
||||||
qmgr_scan_request(qmgr_incoming, QMGR_SCAN_START);
|
qmgr_scan_request(qmgr_incoming, QMGR_SCAN_START);
|
||||||
qmgr_deferred_run_event(0, (char *) 0);
|
qmgr_deferred_run_event(0, (char *)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* main - the main program */
|
/* main - the main program */
|
||||||
|
@@ -418,10 +418,10 @@ static int qmgr_loop(char *unused_name, char **unused_argv)
|
|||||||
* Global flow control. If enabled, slow down receiving processes that
|
* Global flow control. If enabled, slow down receiving processes that
|
||||||
* get ahead of the queue manager, but don't block them completely.
|
* get ahead of the queue manager, but don't block them completely.
|
||||||
*/
|
*/
|
||||||
if (var_glob_flow_ctl) {
|
if (var_in_flow_delay > 0) {
|
||||||
if (in_path != 0)
|
if (in_path != 0)
|
||||||
mail_flow_put(1);
|
mail_flow_put(1);
|
||||||
else if ((token_count = peekfd(MASTER_FLOW_READ)) < var_proc_limit)
|
else if ((token_count = mail_flow_count()) < var_proc_limit)
|
||||||
mail_flow_put(var_proc_limit - token_count);
|
mail_flow_put(var_proc_limit - token_count);
|
||||||
else if (token_count > var_proc_limit)
|
else if (token_count > var_proc_limit)
|
||||||
mail_flow_get(token_count - var_proc_limit);
|
mail_flow_get(token_count - var_proc_limit);
|
||||||
|
@@ -67,6 +67,7 @@ typedef struct SMTPD_STATE {
|
|||||||
int recursion;
|
int recursion;
|
||||||
off_t msg_size;
|
off_t msg_size;
|
||||||
int junk_cmds;
|
int junk_cmds;
|
||||||
|
VSTRING *error_text;
|
||||||
#ifdef USE_SASL_AUTH
|
#ifdef USE_SASL_AUTH
|
||||||
char *sasl_mechanism_list;
|
char *sasl_mechanism_list;
|
||||||
char *sasl_method;
|
char *sasl_method;
|
||||||
|
@@ -269,6 +269,7 @@
|
|||||||
#include <mymalloc.h>
|
#include <mymalloc.h>
|
||||||
#include <dict.h>
|
#include <dict.h>
|
||||||
#include <htable.h>
|
#include <htable.h>
|
||||||
|
#include <ctable.h>
|
||||||
|
|
||||||
/* DNS library. */
|
/* DNS library. */
|
||||||
|
|
||||||
@@ -310,9 +311,8 @@ static jmp_buf smtpd_check_buf;
|
|||||||
* Intermediate results. These are static to avoid unnecessary stress on the
|
* Intermediate results. These are static to avoid unnecessary stress on the
|
||||||
* memory manager routines.
|
* memory manager routines.
|
||||||
*/
|
*/
|
||||||
static RESOLVE_REPLY reply;
|
|
||||||
static VSTRING *query;
|
|
||||||
static VSTRING *error_text;
|
static VSTRING *error_text;
|
||||||
|
static CTABLE *smtpd_resolve_cache;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pre-opened SMTP recipient maps so we can reject mail for unknown users.
|
* Pre-opened SMTP recipient maps so we can reject mail for unknown users.
|
||||||
@@ -346,7 +346,7 @@ static HTABLE *smtpd_rest_classes;
|
|||||||
/*
|
/*
|
||||||
* The routine that recursively applies restrictions.
|
* The routine that recursively applies restrictions.
|
||||||
*/
|
*/
|
||||||
static int generic_checks(SMTPD_STATE *, ARGV *, char *, char *, char *);
|
static int generic_checks(SMTPD_STATE *, ARGV *, const char *, const char *, const char *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reject context.
|
* Reject context.
|
||||||
@@ -361,6 +361,49 @@ static int generic_checks(SMTPD_STATE *, ARGV *, char *, char *, char *);
|
|||||||
* YASLM.
|
* YASLM.
|
||||||
*/
|
*/
|
||||||
#define STR vstring_str
|
#define STR vstring_str
|
||||||
|
#define CONST_STR(x) ((const char *) vstring_str(x))
|
||||||
|
|
||||||
|
/* resolve_pagein - page in an address resolver result */
|
||||||
|
|
||||||
|
static void *resolve_pagein(const char *addr, void *unused_context)
|
||||||
|
{
|
||||||
|
static VSTRING *query;
|
||||||
|
RESOLVE_REPLY *reply;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize on the fly.
|
||||||
|
*/
|
||||||
|
if (query == 0)
|
||||||
|
query = vstring_alloc(10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize.
|
||||||
|
*/
|
||||||
|
reply = (RESOLVE_REPLY *) mymalloc(sizeof(*reply));
|
||||||
|
resolve_clnt_init(reply);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolve the address.
|
||||||
|
*/
|
||||||
|
canon_addr_internal(query, addr);
|
||||||
|
resolve_clnt_query(STR(query), reply);
|
||||||
|
lowercase(STR(reply->recipient));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save the result.
|
||||||
|
*/
|
||||||
|
return ((void *) reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* resolve_pageout - page out an address resolver result */
|
||||||
|
|
||||||
|
static void resolve_pageout(void *data, void *unused_context)
|
||||||
|
{
|
||||||
|
RESOLVE_REPLY *reply = (RESOLVE_REPLY *) data;
|
||||||
|
|
||||||
|
resolve_clnt_free(reply);
|
||||||
|
myfree((void *) reply);
|
||||||
|
}
|
||||||
|
|
||||||
/* smtpd_check_parse - pre-parse restrictions */
|
/* smtpd_check_parse - pre-parse restrictions */
|
||||||
|
|
||||||
@@ -474,13 +517,16 @@ void smtpd_check_init(void)
|
|||||||
DICT_FLAG_LOCK);
|
DICT_FLAG_LOCK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reply is used as a cache for resolved addresses, and error_text is
|
* error_text is used for returning error responses.
|
||||||
* used for returning error responses.
|
|
||||||
*/
|
*/
|
||||||
resolve_clnt_init(&reply);
|
|
||||||
query = vstring_alloc(10);
|
|
||||||
error_text = vstring_alloc(10);
|
error_text = vstring_alloc(10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the resolved address cache.
|
||||||
|
*/
|
||||||
|
smtpd_resolve_cache = ctable_create(100, resolve_pagein,
|
||||||
|
resolve_pageout, (void *) 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pre-parse the restriction lists. At the same time, pre-open tables
|
* Pre-parse the restriction lists. At the same time, pre-open tables
|
||||||
* before going to jail.
|
* before going to jail.
|
||||||
@@ -623,8 +669,10 @@ static const char *check_maps_find(SMTPD_STATE *state, const char *reply_name,
|
|||||||
|
|
||||||
/* check_mail_addr_find - reject with temporary failure if dict lookup fails */
|
/* check_mail_addr_find - reject with temporary failure if dict lookup fails */
|
||||||
|
|
||||||
static const char *check_mail_addr_find(SMTPD_STATE *state, const char *reply_name,
|
static const char *check_mail_addr_find(SMTPD_STATE *state,
|
||||||
MAPS *maps, const char *key, char **ext)
|
const char *reply_name,
|
||||||
|
MAPS *maps, const char *key,
|
||||||
|
char **ext)
|
||||||
{
|
{
|
||||||
const char *result;
|
const char *result;
|
||||||
|
|
||||||
@@ -819,8 +867,8 @@ static int reject_unknown_hostname(SMTPD_STATE *state, char *name,
|
|||||||
|
|
||||||
/* reject_unknown_mailhost - fail if name has no A or MX record */
|
/* reject_unknown_mailhost - fail if name has no A or MX record */
|
||||||
|
|
||||||
static int reject_unknown_mailhost(SMTPD_STATE *state, char *name,
|
static int reject_unknown_mailhost(SMTPD_STATE *state, const char *name,
|
||||||
char *reply_name, char *reply_class)
|
const char *reply_name, const char *reply_class)
|
||||||
{
|
{
|
||||||
char *myname = "reject_unknown_mailhost";
|
char *myname = "reject_unknown_mailhost";
|
||||||
int dns_status;
|
int dns_status;
|
||||||
@@ -876,7 +924,8 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient,
|
|||||||
static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
|
static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
|
||||||
{
|
{
|
||||||
char *myname = "permit_auth_destination";
|
char *myname = "permit_auth_destination";
|
||||||
char *domain;
|
const RESOLVE_REPLY *reply;
|
||||||
|
const char *domain;
|
||||||
|
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: %s", myname, recipient);
|
msg_info("%s: %s", myname, recipient);
|
||||||
@@ -884,14 +933,13 @@ static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
|
|||||||
/*
|
/*
|
||||||
* Resolve the address.
|
* Resolve the address.
|
||||||
*/
|
*/
|
||||||
canon_addr_internal(query, recipient);
|
reply = (const RESOLVE_REPLY *)
|
||||||
resolve_clnt_query(STR(query), &reply);
|
ctable_locate(smtpd_resolve_cache, recipient);
|
||||||
lowercase(STR(reply.recipient));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle special case that is not supposed to happen.
|
* Handle special case that is not supposed to happen.
|
||||||
*/
|
*/
|
||||||
if ((domain = strrchr(STR(reply.recipient), '@')) == 0)
|
if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0)
|
||||||
return (SMTPD_CHECK_OK);
|
return (SMTPD_CHECK_OK);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
|
|
||||||
@@ -909,7 +957,7 @@ static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
|
|||||||
/*
|
/*
|
||||||
* Skip source-routed mail (uncertain destination).
|
* Skip source-routed mail (uncertain destination).
|
||||||
*/
|
*/
|
||||||
if (var_allow_untrust_route == 0 && (reply.flags & RESOLVE_FLAG_ROUTED))
|
if (var_allow_untrust_route == 0 && (reply->flags & RESOLVE_FLAG_ROUTED))
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -968,7 +1016,7 @@ static int reject_unauth_pipelining(SMTPD_STATE *state)
|
|||||||
|
|
||||||
/* has_my_addr - see if this host name lists one of my network addresses */
|
/* has_my_addr - see if this host name lists one of my network addresses */
|
||||||
|
|
||||||
static int has_my_addr(char *host)
|
static int has_my_addr(const char *host)
|
||||||
{
|
{
|
||||||
char *myname = "has_my_addr";
|
char *myname = "has_my_addr";
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
@@ -1012,7 +1060,8 @@ static int has_my_addr(char *host)
|
|||||||
static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
|
static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
|
||||||
{
|
{
|
||||||
char *myname = "permit_mx_backup";
|
char *myname = "permit_mx_backup";
|
||||||
char *domain;
|
const RESOLVE_REPLY *reply;
|
||||||
|
const char *domain;
|
||||||
|
|
||||||
DNS_RR *mx_list;
|
DNS_RR *mx_list;
|
||||||
DNS_RR *mx;
|
DNS_RR *mx;
|
||||||
@@ -1024,15 +1073,14 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
|
|||||||
/*
|
/*
|
||||||
* Resolve the address.
|
* Resolve the address.
|
||||||
*/
|
*/
|
||||||
canon_addr_internal(query, recipient);
|
reply = (const RESOLVE_REPLY *)
|
||||||
resolve_clnt_query(STR(query), &reply);
|
ctable_locate(smtpd_resolve_cache, recipient);
|
||||||
lowercase(STR(reply.recipient));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the destination is local, it is acceptable, because we are
|
* If the destination is local, it is acceptable, because we are
|
||||||
* supposedly MX for our own address.
|
* supposedly MX for our own address.
|
||||||
*/
|
*/
|
||||||
if ((domain = strrchr(STR(reply.recipient), '@')) == 0)
|
if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0)
|
||||||
return (SMTPD_CHECK_OK);
|
return (SMTPD_CHECK_OK);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
if (resolve_local(domain)
|
if (resolve_local(domain)
|
||||||
@@ -1048,7 +1096,7 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
|
|||||||
/*
|
/*
|
||||||
* Skip source-routed mail (uncertain destination).
|
* Skip source-routed mail (uncertain destination).
|
||||||
*/
|
*/
|
||||||
if (var_allow_untrust_route == 0 && (reply.flags & RESOLVE_FLAG_ROUTED))
|
if (var_allow_untrust_route == 0 && (reply->flags & RESOLVE_FLAG_ROUTED))
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1157,11 +1205,12 @@ static int reject_non_fqdn_address(SMTPD_STATE *state, char *addr,
|
|||||||
|
|
||||||
/* reject_unknown_address - fail if address does not resolve */
|
/* reject_unknown_address - fail if address does not resolve */
|
||||||
|
|
||||||
static int reject_unknown_address(SMTPD_STATE *state, char *addr,
|
static int reject_unknown_address(SMTPD_STATE *state, const char *addr,
|
||||||
char *reply_name, char *reply_class)
|
const char *reply_name, const char *reply_class)
|
||||||
{
|
{
|
||||||
char *myname = "reject_unknown_address";
|
char *myname = "reject_unknown_address";
|
||||||
char *domain;
|
const RESOLVE_REPLY *reply;
|
||||||
|
const char *domain;
|
||||||
|
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: %s", myname, addr);
|
msg_info("%s: %s", myname, addr);
|
||||||
@@ -1169,14 +1218,12 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
|
|||||||
/*
|
/*
|
||||||
* Resolve the address.
|
* Resolve the address.
|
||||||
*/
|
*/
|
||||||
canon_addr_internal(query, addr);
|
reply = (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, addr);
|
||||||
resolve_clnt_query(STR(query), &reply);
|
|
||||||
lowercase(STR(reply.recipient));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip local destinations and non-DNS forms.
|
* Skip local destinations and non-DNS forms.
|
||||||
*/
|
*/
|
||||||
if ((domain = strrchr(STR(reply.recipient), '@')) == 0)
|
if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0)
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
if (resolve_local(domain)
|
if (resolve_local(domain)
|
||||||
@@ -1198,10 +1245,11 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
|
|||||||
|
|
||||||
/* check_table_result - translate table lookup result into pass/reject */
|
/* check_table_result - translate table lookup result into pass/reject */
|
||||||
|
|
||||||
static int check_table_result(SMTPD_STATE *state, char *table,
|
static int check_table_result(SMTPD_STATE *state, const char *table,
|
||||||
const char *value, const char *datum,
|
const char *value, const char *datum,
|
||||||
char *reply_name, char *reply_class,
|
const char *reply_name,
|
||||||
char *def_acl)
|
const char *reply_class,
|
||||||
|
const char *def_acl)
|
||||||
{
|
{
|
||||||
char *myname = "check_table_result";
|
char *myname = "check_table_result";
|
||||||
int code;
|
int code;
|
||||||
@@ -1296,17 +1344,20 @@ static int check_table_result(SMTPD_STATE *state, char *table,
|
|||||||
|
|
||||||
/* check_access - table lookup without substring magic */
|
/* check_access - table lookup without substring magic */
|
||||||
|
|
||||||
static int check_access(SMTPD_STATE *state, char *table, char *name, int flags,
|
static int check_access(SMTPD_STATE *state, const char *table, const char *name,
|
||||||
char *reply_name, char *reply_class, char *def_acl)
|
int flags, int *found, const char *reply_name,
|
||||||
|
const char *reply_class, const char *def_acl)
|
||||||
{
|
{
|
||||||
char *myname = "check_access";
|
char *myname = "check_access";
|
||||||
char *low_name = lowercase(mystrdup(name));
|
char *low_name = lowercase(mystrdup(name));
|
||||||
const char *value;
|
const char *value;
|
||||||
DICT *dict;
|
DICT *dict;
|
||||||
|
|
||||||
#define CHK_ACCESS_RETURN(x) { myfree(low_name); return(x); }
|
#define CHK_ACCESS_RETURN(x,y) { *found = y; myfree(low_name); return(x); }
|
||||||
#define FULL 0
|
#define FULL 0
|
||||||
#define PARTIAL DICT_FLAG_FIXED
|
#define PARTIAL DICT_FLAG_FIXED
|
||||||
|
#define FOUND 1
|
||||||
|
#define MISSED 0
|
||||||
|
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: %s", myname, name);
|
msg_info("%s: %s", myname, name);
|
||||||
@@ -1317,19 +1368,20 @@ static int check_access(SMTPD_STATE *state, char *table, char *name, int flags,
|
|||||||
if ((value = dict_get(dict, low_name)) != 0)
|
if ((value = dict_get(dict, low_name)) != 0)
|
||||||
CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
|
CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
|
||||||
reply_name, reply_class,
|
reply_name, reply_class,
|
||||||
def_acl));
|
def_acl), FOUND);
|
||||||
if (dict_errno != 0)
|
if (dict_errno != 0)
|
||||||
msg_fatal("%s: table lookup problem", table);
|
msg_fatal("%s: table lookup problem", table);
|
||||||
}
|
}
|
||||||
CHK_ACCESS_RETURN(SMTPD_CHECK_DUNNO);
|
CHK_ACCESS_RETURN(SMTPD_CHECK_DUNNO, MISSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check_domain_access - domainname-based table lookup */
|
/* check_domain_access - domainname-based table lookup */
|
||||||
|
|
||||||
static int check_domain_access(SMTPD_STATE *state, char *table,
|
static int check_domain_access(SMTPD_STATE *state, const char *table,
|
||||||
char *domain, int flags,
|
const char *domain, int flags,
|
||||||
char *reply_name, char *reply_class,
|
int *found, const char *reply_name,
|
||||||
char *def_acl)
|
const char *reply_class,
|
||||||
|
const char *def_acl)
|
||||||
{
|
{
|
||||||
char *myname = "check_domain_access";
|
char *myname = "check_domain_access";
|
||||||
char *low_domain = lowercase(mystrdup(domain));
|
char *low_domain = lowercase(mystrdup(domain));
|
||||||
@@ -1344,7 +1396,7 @@ static int check_domain_access(SMTPD_STATE *state, char *table,
|
|||||||
/*
|
/*
|
||||||
* Try the name and its parent domains. Including top-level domains.
|
* Try the name and its parent domains. Including top-level domains.
|
||||||
*/
|
*/
|
||||||
#define CHK_DOMAIN_RETURN(x) { myfree(low_domain); return(x); }
|
#define CHK_DOMAIN_RETURN(x,y) { *found = y; myfree(low_domain); return(x); }
|
||||||
|
|
||||||
if ((dict = dict_handle(table)) == 0)
|
if ((dict = dict_handle(table)) == 0)
|
||||||
msg_panic("%s: dictionary not found: %s", myname, table);
|
msg_panic("%s: dictionary not found: %s", myname, table);
|
||||||
@@ -1353,7 +1405,7 @@ static int check_domain_access(SMTPD_STATE *state, char *table,
|
|||||||
if ((value = dict_get(dict, name)) != 0)
|
if ((value = dict_get(dict, name)) != 0)
|
||||||
CHK_DOMAIN_RETURN(check_table_result(state, table, value,
|
CHK_DOMAIN_RETURN(check_table_result(state, table, value,
|
||||||
domain, reply_name, reply_class,
|
domain, reply_name, reply_class,
|
||||||
def_acl));
|
def_acl), FOUND);
|
||||||
if (dict_errno != 0)
|
if (dict_errno != 0)
|
||||||
msg_fatal("%s: table lookup problem", table);
|
msg_fatal("%s: table lookup problem", table);
|
||||||
}
|
}
|
||||||
@@ -1361,15 +1413,16 @@ static int check_domain_access(SMTPD_STATE *state, char *table,
|
|||||||
break;
|
break;
|
||||||
flags = PARTIAL;
|
flags = PARTIAL;
|
||||||
}
|
}
|
||||||
CHK_DOMAIN_RETURN(SMTPD_CHECK_DUNNO);
|
CHK_DOMAIN_RETURN(SMTPD_CHECK_DUNNO, MISSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check_addr_access - address-based table lookup */
|
/* check_addr_access - address-based table lookup */
|
||||||
|
|
||||||
static int check_addr_access(SMTPD_STATE *state, char *table,
|
static int check_addr_access(SMTPD_STATE *state, const char *table,
|
||||||
char *address, int flags,
|
const char *address, int flags,
|
||||||
char *reply_name, char *reply_class,
|
int *found, const char *reply_name,
|
||||||
char *def_acl)
|
const char *reply_class,
|
||||||
|
const char *def_acl)
|
||||||
{
|
{
|
||||||
char *myname = "check_addr_access";
|
char *myname = "check_addr_access";
|
||||||
char *addr;
|
char *addr;
|
||||||
@@ -1382,6 +1435,8 @@ static int check_addr_access(SMTPD_STATE *state, char *table,
|
|||||||
/*
|
/*
|
||||||
* Try the address and its parent networks.
|
* Try the address and its parent networks.
|
||||||
*/
|
*/
|
||||||
|
#define CHK_ADDR_RETURN(x,y) { *found = y; return(x); }
|
||||||
|
|
||||||
addr = STR(vstring_strcpy(error_text, address));
|
addr = STR(vstring_strcpy(error_text, address));
|
||||||
|
|
||||||
if ((dict = dict_handle(table)) == 0)
|
if ((dict = dict_handle(table)) == 0)
|
||||||
@@ -1389,24 +1444,26 @@ static int check_addr_access(SMTPD_STATE *state, char *table,
|
|||||||
do {
|
do {
|
||||||
if (flags == 0 || (flags & dict->flags) != 0) {
|
if (flags == 0 || (flags & dict->flags) != 0) {
|
||||||
if ((value = dict_get(dict, addr)) != 0)
|
if ((value = dict_get(dict, addr)) != 0)
|
||||||
return (check_table_result(state, table, value, address,
|
CHK_ADDR_RETURN(check_table_result(state, table, value, address,
|
||||||
reply_name, reply_class,
|
reply_name, reply_class,
|
||||||
def_acl));
|
def_acl), FOUND);
|
||||||
if (dict_errno != 0)
|
if (dict_errno != 0)
|
||||||
msg_fatal("%s: table lookup problem", table);
|
msg_fatal("%s: table lookup problem", table);
|
||||||
}
|
}
|
||||||
flags = PARTIAL;
|
flags = PARTIAL;
|
||||||
} while (split_at_right(addr, '.'));
|
} while (split_at_right(addr, '.'));
|
||||||
|
|
||||||
return (SMTPD_CHECK_DUNNO);
|
CHK_ADDR_RETURN(SMTPD_CHECK_DUNNO, MISSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check_namadr_access - OK/FAIL based on host name/address lookup */
|
/* check_namadr_access - OK/FAIL based on host name/address lookup */
|
||||||
|
|
||||||
static int check_namadr_access(SMTPD_STATE *state, char *table,
|
static int check_namadr_access(SMTPD_STATE *state, const char *table,
|
||||||
char *name, char *addr, int flags,
|
const char *name, const char *addr,
|
||||||
char *reply_name, char *reply_class,
|
int flags, int *found,
|
||||||
char *def_acl)
|
const char *reply_name,
|
||||||
|
const char *reply_class,
|
||||||
|
const char *def_acl)
|
||||||
{
|
{
|
||||||
char *myname = "check_namadr_access";
|
char *myname = "check_namadr_access";
|
||||||
int status;
|
int status;
|
||||||
@@ -1419,16 +1476,16 @@ static int check_namadr_access(SMTPD_STATE *state, char *table,
|
|||||||
* wildcard may pre-empt a more specific address table entry.
|
* wildcard may pre-empt a more specific address table entry.
|
||||||
*/
|
*/
|
||||||
if ((status = check_domain_access(state, table, name, flags,
|
if ((status = check_domain_access(state, table, name, flags,
|
||||||
reply_name, reply_class,
|
found, reply_name, reply_class,
|
||||||
def_acl)) != 0)
|
def_acl)) != 0 || *found)
|
||||||
return (status);
|
return (status);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up the network address, or parent networks thereof.
|
* Look up the network address, or parent networks thereof.
|
||||||
*/
|
*/
|
||||||
if ((status = check_addr_access(state, table, addr, flags,
|
if ((status = check_addr_access(state, table, addr, flags,
|
||||||
reply_name, reply_class,
|
found, reply_name, reply_class,
|
||||||
def_acl)) != 0)
|
def_acl)) != 0 || *found)
|
||||||
return (status);
|
return (status);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1439,12 +1496,15 @@ static int check_namadr_access(SMTPD_STATE *state, char *table,
|
|||||||
|
|
||||||
/* check_mail_access - OK/FAIL based on mail address lookup */
|
/* check_mail_access - OK/FAIL based on mail address lookup */
|
||||||
|
|
||||||
static int check_mail_access(SMTPD_STATE *state, char *table, char *addr,
|
static int check_mail_access(SMTPD_STATE *state, const char *table,
|
||||||
char *reply_name, char *reply_class,
|
const char *addr, int *found,
|
||||||
char *def_acl)
|
const char *reply_name,
|
||||||
|
const char *reply_class,
|
||||||
|
const char *def_acl)
|
||||||
{
|
{
|
||||||
char *myname = "check_mail_access";
|
char *myname = "check_mail_access";
|
||||||
char *ratsign;
|
const RESOLVE_REPLY *reply;
|
||||||
|
const char *ratsign;
|
||||||
int status;
|
int status;
|
||||||
char *local_at;
|
char *local_at;
|
||||||
|
|
||||||
@@ -1454,39 +1514,39 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr,
|
|||||||
/*
|
/*
|
||||||
* Resolve the address.
|
* Resolve the address.
|
||||||
*/
|
*/
|
||||||
canon_addr_internal(query, addr);
|
reply = (const RESOLVE_REPLY *) ctable_locate(smtpd_resolve_cache, addr);
|
||||||
resolve_clnt_query(STR(query), &reply);
|
|
||||||
lowercase(STR(reply.recipient));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Garbage in, garbage out. Every address from canon_addr_internal() and
|
* Garbage in, garbage out. Every address from canon_addr_internal() and
|
||||||
* from resolve_clnt_query() must be fully qualified.
|
* from resolve_clnt_query() must be fully qualified.
|
||||||
*/
|
*/
|
||||||
if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
|
if ((ratsign = strrchr(CONST_STR(reply->recipient), '@')) == 0) {
|
||||||
msg_warn("%s: no @domain in address: %s", myname, STR(reply.recipient));
|
msg_warn("%s: no @domain in address: %s", myname, CONST_STR(reply->recipient));
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up the full address.
|
* Look up the full address.
|
||||||
*/
|
*/
|
||||||
if ((status = check_access(state, table, STR(reply.recipient), FULL,
|
if ((status = check_access(state, table, CONST_STR(reply->recipient), FULL,
|
||||||
reply_name, reply_class, def_acl)) != 0)
|
found, reply_name, reply_class, def_acl)) != 0
|
||||||
|
|| *found)
|
||||||
return (status);
|
return (status);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up the domain name, or parent domains thereof.
|
* Look up the domain name, or parent domains thereof.
|
||||||
*/
|
*/
|
||||||
if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL,
|
if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL,
|
||||||
reply_name, reply_class, def_acl)) != 0)
|
found, reply_name, reply_class, def_acl)) != 0
|
||||||
|
|| *found)
|
||||||
return (status);
|
return (status);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up localpart@
|
* Look up localpart@
|
||||||
*/
|
*/
|
||||||
local_at = mystrndup(STR(reply.recipient),
|
local_at = mystrndup(CONST_STR(reply->recipient),
|
||||||
ratsign - STR(reply.recipient) + 1);
|
ratsign - CONST_STR(reply->recipient) + 1);
|
||||||
status = check_access(state, table, local_at, PARTIAL,
|
status = check_access(state, table, local_at, PARTIAL, found,
|
||||||
reply_name, reply_class, def_acl);
|
reply_name, reply_class, def_acl);
|
||||||
myfree(local_at);
|
myfree(local_at);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
@@ -1587,7 +1647,7 @@ static int reject_maps_rbl(SMTPD_STATE *state)
|
|||||||
|
|
||||||
/* is_map_command - restriction has form: check_xxx_access type:name */
|
/* is_map_command - restriction has form: check_xxx_access type:name */
|
||||||
|
|
||||||
static int is_map_command(char *name, char *command, char ***argp)
|
static int is_map_command(const char *name, const char *command, char ***argp)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1610,13 +1670,16 @@ static int is_map_command(char *name, char *command, char ***argp)
|
|||||||
/* generic_checks - generic restrictions */
|
/* generic_checks - generic restrictions */
|
||||||
|
|
||||||
static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
||||||
char *reply_name, char *reply_class, char *def_acl)
|
const char *reply_name,
|
||||||
|
const char *reply_class,
|
||||||
|
const char *def_acl)
|
||||||
{
|
{
|
||||||
char *myname = "generic_checks";
|
char *myname = "generic_checks";
|
||||||
char **cpp;
|
char **cpp;
|
||||||
char *name;
|
const char *name;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
ARGV *list;
|
ARGV *list;
|
||||||
|
int found;
|
||||||
|
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: START", myname);
|
msg_info("%s: START", myname);
|
||||||
@@ -1663,7 +1726,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
|||||||
status = permit_mynetworks(state);
|
status = permit_mynetworks(state);
|
||||||
} else if (is_map_command(name, CHECK_CLIENT_ACL, &cpp)) {
|
} else if (is_map_command(name, CHECK_CLIENT_ACL, &cpp)) {
|
||||||
status = check_namadr_access(state, *cpp, state->name, state->addr,
|
status = check_namadr_access(state, *cpp, state->name, state->addr,
|
||||||
FULL, state->namaddr,
|
FULL, &found, state->namaddr,
|
||||||
SMTPD_NAME_CLIENT, def_acl);
|
SMTPD_NAME_CLIENT, def_acl);
|
||||||
} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
|
} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
|
||||||
status = reject_maps_rbl(state);
|
status = reject_maps_rbl(state);
|
||||||
@@ -1675,7 +1738,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
|||||||
else if (is_map_command(name, CHECK_HELO_ACL, &cpp)) {
|
else if (is_map_command(name, CHECK_HELO_ACL, &cpp)) {
|
||||||
if (state->helo_name)
|
if (state->helo_name)
|
||||||
status = check_domain_access(state, *cpp, state->helo_name,
|
status = check_domain_access(state, *cpp, state->helo_name,
|
||||||
FULL, state->helo_name,
|
FULL, &found, state->helo_name,
|
||||||
SMTPD_NAME_HELO, def_acl);
|
SMTPD_NAME_HELO, def_acl);
|
||||||
} else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
|
} else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
|
||||||
if (state->helo_name) {
|
if (state->helo_name) {
|
||||||
@@ -1719,7 +1782,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
|||||||
else if (is_map_command(name, CHECK_SENDER_ACL, &cpp)) {
|
else if (is_map_command(name, CHECK_SENDER_ACL, &cpp)) {
|
||||||
if (state->sender && *state->sender)
|
if (state->sender && *state->sender)
|
||||||
status = check_mail_access(state, *cpp, state->sender,
|
status = check_mail_access(state, *cpp, state->sender,
|
||||||
state->sender,
|
&found, state->sender,
|
||||||
SMTPD_NAME_SENDER, def_acl);
|
SMTPD_NAME_SENDER, def_acl);
|
||||||
} else if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) {
|
} else if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) {
|
||||||
if (state->sender && *state->sender)
|
if (state->sender && *state->sender)
|
||||||
@@ -1741,7 +1804,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
|||||||
else if (is_map_command(name, CHECK_RECIP_ACL, &cpp)) {
|
else if (is_map_command(name, CHECK_RECIP_ACL, &cpp)) {
|
||||||
if (state->recipient)
|
if (state->recipient)
|
||||||
status = check_mail_access(state, *cpp, state->recipient,
|
status = check_mail_access(state, *cpp, state->recipient,
|
||||||
state->recipient,
|
&found, state->recipient,
|
||||||
SMTPD_NAME_RECIPIENT, def_acl);
|
SMTPD_NAME_RECIPIENT, def_acl);
|
||||||
} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
|
} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
|
||||||
if (state->recipient)
|
if (state->recipient)
|
||||||
@@ -1781,7 +1844,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
|||||||
else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) {
|
else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) {
|
||||||
if (state->etrn_name)
|
if (state->etrn_name)
|
||||||
status = check_domain_access(state, *cpp, state->etrn_name,
|
status = check_domain_access(state, *cpp, state->etrn_name,
|
||||||
FULL, state->etrn_name,
|
FULL, &found, state->etrn_name,
|
||||||
SMTPD_NAME_ETRN, def_acl);
|
SMTPD_NAME_ETRN, def_acl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2023,7 +2086,8 @@ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
|||||||
{
|
{
|
||||||
char *myname = "smtpd_check_rcptmap";
|
char *myname = "smtpd_check_rcptmap";
|
||||||
char *saved_recipient;
|
char *saved_recipient;
|
||||||
char *domain;
|
const RESOLVE_REPLY *reply;
|
||||||
|
const char *domain;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2050,14 +2114,13 @@ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
|||||||
/*
|
/*
|
||||||
* Resolve the address.
|
* Resolve the address.
|
||||||
*/
|
*/
|
||||||
canon_addr_internal(query, recipient);
|
reply = (const RESOLVE_REPLY *)
|
||||||
resolve_clnt_query(STR(query), &reply);
|
ctable_locate(smtpd_resolve_cache, recipient);
|
||||||
lowercase(STR(reply.recipient));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip non-DNS forms. Skip non-local numerical forms.
|
* Skip non-DNS forms. Skip non-local numerical forms.
|
||||||
*/
|
*/
|
||||||
if ((domain = strrchr(STR(reply.recipient), '@')) == 0)
|
if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0)
|
||||||
SMTPD_CHECK_RCPT_RETURN(0);
|
SMTPD_CHECK_RCPT_RETURN(0);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
if (domain[0] == '#' || domain[0] == '[')
|
if (domain[0] == '#' || domain[0] == '[')
|
||||||
@@ -2072,11 +2135,11 @@ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
|||||||
*/
|
*/
|
||||||
if (*var_virtual_maps
|
if (*var_virtual_maps
|
||||||
&& (check_maps_find(state, recipient, virtual_maps, domain, 0))) {
|
&& (check_maps_find(state, recipient, virtual_maps, domain, 0))) {
|
||||||
if (NOMATCH(rcpt_canon_maps, STR(reply.recipient))
|
if (NOMATCH(rcpt_canon_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(canonical_maps, STR(reply.recipient))
|
&& NOMATCH(canonical_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(relocated_maps, STR(reply.recipient))
|
&& NOMATCH(relocated_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(virt_mailbox_maps, STR(reply.recipient))
|
&& NOMATCH(virt_mailbox_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(virtual_maps, STR(reply.recipient))) {
|
&& NOMATCH(virtual_maps, CONST_STR(reply->recipient))) {
|
||||||
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
||||||
"%d <%s>: User unknown", 550, recipient);
|
"%d <%s>: User unknown", 550, recipient);
|
||||||
SMTPD_CHECK_RCPT_RETURN(STR(error_text));
|
SMTPD_CHECK_RCPT_RETURN(STR(error_text));
|
||||||
@@ -2087,12 +2150,12 @@ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
|||||||
* Reject mail to unknown addresses in Postfix-style virtual domains.
|
* Reject mail to unknown addresses in Postfix-style virtual domains.
|
||||||
*/
|
*/
|
||||||
if (*var_virt_mailbox_maps
|
if (*var_virt_mailbox_maps
|
||||||
&& (check_maps_find(state, recipient, virt_mailbox_maps, domain, 0))) {
|
&& (check_maps_find(state, recipient, virt_mailbox_maps, domain, 0))) {
|
||||||
if (NOMATCH(rcpt_canon_maps, STR(reply.recipient))
|
if (NOMATCH(rcpt_canon_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(canonical_maps, STR(reply.recipient))
|
&& NOMATCH(canonical_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(relocated_maps, STR(reply.recipient))
|
&& NOMATCH(relocated_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(virt_mailbox_maps, STR(reply.recipient))
|
&& NOMATCH(virt_mailbox_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(virtual_maps, STR(reply.recipient))) {
|
&& NOMATCH(virtual_maps, CONST_STR(reply->recipient))) {
|
||||||
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
||||||
"%d <%s>: User unknown", 550, recipient);
|
"%d <%s>: User unknown", 550, recipient);
|
||||||
SMTPD_CHECK_RCPT_RETURN(STR(error_text));
|
SMTPD_CHECK_RCPT_RETURN(STR(error_text));
|
||||||
@@ -2105,12 +2168,12 @@ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
|||||||
* Sendmail-style virtual domains.
|
* Sendmail-style virtual domains.
|
||||||
*/
|
*/
|
||||||
if (*var_local_rcpt_maps && resolve_local(domain)) {
|
if (*var_local_rcpt_maps && resolve_local(domain)) {
|
||||||
if (NOMATCH(rcpt_canon_maps, STR(reply.recipient))
|
if (NOMATCH(rcpt_canon_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(canonical_maps, STR(reply.recipient))
|
&& NOMATCH(canonical_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(relocated_maps, STR(reply.recipient))
|
&& NOMATCH(relocated_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(virt_mailbox_maps, STR(reply.recipient))
|
&& NOMATCH(virt_mailbox_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(virtual_maps, STR(reply.recipient))
|
&& NOMATCH(virtual_maps, CONST_STR(reply->recipient))
|
||||||
&& NOMATCH(local_rcpt_maps, STR(reply.recipient))) {
|
&& NOMATCH(local_rcpt_maps, CONST_STR(reply->recipient))) {
|
||||||
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
||||||
"%d <%s>: User unknown", 550, recipient);
|
"%d <%s>: User unknown", 550, recipient);
|
||||||
SMTPD_CHECK_RCPT_RETURN(STR(error_text));
|
SMTPD_CHECK_RCPT_RETURN(STR(error_text));
|
||||||
@@ -2377,11 +2440,19 @@ static void rest_class(char *class)
|
|||||||
|
|
||||||
void resolve_clnt_init(RESOLVE_REPLY *reply)
|
void resolve_clnt_init(RESOLVE_REPLY *reply)
|
||||||
{
|
{
|
||||||
|
reply->flags = 0;
|
||||||
reply->transport = vstring_alloc(100);
|
reply->transport = vstring_alloc(100);
|
||||||
reply->nexthop = vstring_alloc(100);
|
reply->nexthop = vstring_alloc(100);
|
||||||
reply->recipient = vstring_alloc(100);
|
reply->recipient = vstring_alloc(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resolve_clnt_free(RESOLVE_REPLY *reply)
|
||||||
|
{
|
||||||
|
vstring_free(reply->transport);
|
||||||
|
vstring_free(reply->nexthop);
|
||||||
|
vstring_free(reply->recipient);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_SASL_AUTH
|
#ifdef USE_SASL_AUTH
|
||||||
|
|
||||||
bool var_smtpd_sasl_enable = 0;
|
bool var_smtpd_sasl_enable = 0;
|
||||||
@@ -2424,7 +2495,7 @@ VSTRING *canon_addr_internal(VSTRING *result, const char *addr)
|
|||||||
|
|
||||||
void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
|
void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
|
||||||
{
|
{
|
||||||
if (addr == STR(reply->recipient))
|
if (addr == CONST_STR(reply->recipient))
|
||||||
msg_panic("resolve_clnt_query: result clobbers input");
|
msg_panic("resolve_clnt_query: result clobbers input");
|
||||||
vstring_strcpy(reply->transport, "foo");
|
vstring_strcpy(reply->transport, "foo");
|
||||||
vstring_strcpy(reply->nexthop, "foo");
|
vstring_strcpy(reply->nexthop, "foo");
|
||||||
@@ -2446,7 +2517,7 @@ static NORETURN usage(char *myname)
|
|||||||
msg_fatal("usage: %s", myname);
|
msg_fatal("usage: %s", myname);
|
||||||
}
|
}
|
||||||
|
|
||||||
main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
VSTRING *buf = vstring_alloc(100);
|
VSTRING *buf = vstring_alloc(100);
|
||||||
SMTPD_STATE state;
|
SMTPD_STATE state;
|
||||||
|
@@ -91,6 +91,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream)
|
|||||||
state->recursion = 0;
|
state->recursion = 0;
|
||||||
state->msg_size = 0;
|
state->msg_size = 0;
|
||||||
state->junk_cmds = 0;
|
state->junk_cmds = 0;
|
||||||
|
state->error_text = vstring_alloc(100);
|
||||||
|
|
||||||
#ifdef USE_SASL_AUTH
|
#ifdef USE_SASL_AUTH
|
||||||
if (SMTPD_STAND_ALONE(state))
|
if (SMTPD_STAND_ALONE(state))
|
||||||
@@ -123,6 +124,7 @@ void smtpd_state_reset(SMTPD_STATE *state)
|
|||||||
if (state->buffer)
|
if (state->buffer)
|
||||||
vstring_free(state->buffer);
|
vstring_free(state->buffer);
|
||||||
smtpd_peer_reset(state);
|
smtpd_peer_reset(state);
|
||||||
|
vstring_free(state->error_text);
|
||||||
|
|
||||||
#ifdef USE_SASL_AUTH
|
#ifdef USE_SASL_AUTH
|
||||||
if (var_smtpd_sasl_enable)
|
if (var_smtpd_sasl_enable)
|
||||||
|
@@ -196,7 +196,7 @@ int smtpd_token(char *cp, SMTPD_TOKEN **argvp)
|
|||||||
#include <vstream.h>
|
#include <vstream.h>
|
||||||
#include <vstring_vstream.h>
|
#include <vstring_vstream.h>
|
||||||
|
|
||||||
main(int unused_argc, char **unused_argv)
|
int main(int unused_argc, char **unused_argv)
|
||||||
{
|
{
|
||||||
VSTRING *vp = vstring_alloc(10);
|
VSTRING *vp = vstring_alloc(10);
|
||||||
int tok_argc;
|
int tok_argc;
|
||||||
|
@@ -23,7 +23,7 @@ SRCS = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
|
|||||||
clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
|
clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
|
||||||
sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \
|
sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \
|
||||||
hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \
|
hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \
|
||||||
sane_socketpair.c myrand.c netstring.c
|
sane_socketpair.c myrand.c netstring.c ctable.c
|
||||||
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
||||||
close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
|
close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
|
||||||
dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
|
dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
|
||||||
@@ -48,7 +48,7 @@ OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
|||||||
clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
|
clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
|
||||||
sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \
|
sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \
|
||||||
hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \
|
hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \
|
||||||
sane_socketpair.o myrand.o netstring.o
|
sane_socketpair.o myrand.o netstring.o ctable.o
|
||||||
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
|
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
|
||||||
dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
|
dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
|
||||||
dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
|
dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
|
||||||
@@ -64,7 +64,7 @@ HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
|
|||||||
vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
|
vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
|
||||||
dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \
|
dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \
|
||||||
watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \
|
watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \
|
||||||
sane_time.h sane_socketpair.h myrand.h netstring.h
|
sane_time.h sane_socketpair.h myrand.h netstring.h ctable.h
|
||||||
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
|
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
|
||||||
stream_test.c dup2_pass_on_exec.c
|
stream_test.c dup2_pass_on_exec.c
|
||||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||||
@@ -80,7 +80,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
|
|||||||
inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \
|
inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \
|
||||||
mystrtok sigdelay translit valid_hostname vstream_popen \
|
mystrtok sigdelay translit valid_hostname vstream_popen \
|
||||||
vstring vstring_vstream doze select_bug stream_test mac_expand \
|
vstring vstring_vstream doze select_bug stream_test mac_expand \
|
||||||
watchdog unescape hex_quote name_mask rand_sleep sane_time
|
watchdog unescape hex_quote name_mask rand_sleep sane_time ctable
|
||||||
|
|
||||||
LIB_DIR = ../../lib
|
LIB_DIR = ../../lib
|
||||||
INC_DIR = ../../include
|
INC_DIR = ../../include
|
||||||
@@ -274,6 +274,11 @@ sane_time: $(LIB)
|
|||||||
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
|
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
|
||||||
mv junk $@.o
|
mv junk $@.o
|
||||||
|
|
||||||
|
ctable: $(LIB)
|
||||||
|
mv $@.o junk
|
||||||
|
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
|
||||||
|
mv junk $@.o
|
||||||
|
|
||||||
depend: $(MAKES)
|
depend: $(MAKES)
|
||||||
(sed '1,/^# do not edit/!d' Makefile.in; \
|
(sed '1,/^# do not edit/!d' Makefile.in; \
|
||||||
set -e; for i in [a-z][a-z0-9]*.c; do \
|
set -e; for i in [a-z][a-z0-9]*.c; do \
|
||||||
@@ -286,7 +291,7 @@ stream_test: stream_test.c $(LIB)
|
|||||||
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
|
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
|
||||||
|
|
||||||
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
|
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
|
||||||
hex_quote_test
|
hex_quote_test cache_test
|
||||||
|
|
||||||
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
|
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
|
||||||
./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
|
./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
|
||||||
@@ -309,6 +314,11 @@ hex_quote_test: hex_quote
|
|||||||
cmp hex_quote.ref hex_quote.tmp
|
cmp hex_quote.ref hex_quote.tmp
|
||||||
rm -f hex_quote.ref hex_quote.tmp
|
rm -f hex_quote.ref hex_quote.tmp
|
||||||
|
|
||||||
|
ctable_test: ctable
|
||||||
|
./ctable <ctable.in >ctable.tmp 2>&1
|
||||||
|
diff ctable.ref ctable.tmp
|
||||||
|
rm -f ctable.tmp
|
||||||
|
|
||||||
DB_TYPE = `../postconf/postconf -h default_database_type`
|
DB_TYPE = `../postconf/postconf -h default_database_type`
|
||||||
|
|
||||||
dict_test: dict_open testdb dict_test.in dict_test.ref
|
dict_test: dict_open testdb dict_test.in dict_test.ref
|
||||||
@@ -368,6 +378,13 @@ concatenate.o: mymalloc.h
|
|||||||
concatenate.o: stringops.h
|
concatenate.o: stringops.h
|
||||||
concatenate.o: vstring.h
|
concatenate.o: vstring.h
|
||||||
concatenate.o: vbuf.h
|
concatenate.o: vbuf.h
|
||||||
|
ctable.o: ctable.c
|
||||||
|
ctable.o: sys_defs.h
|
||||||
|
ctable.o: msg.h
|
||||||
|
ctable.o: mymalloc.h
|
||||||
|
ctable.o: ring.h
|
||||||
|
ctable.o: htable.h
|
||||||
|
ctable.o: ctable.h
|
||||||
dict.o: dict.c
|
dict.o: dict.c
|
||||||
dict.o: sys_defs.h
|
dict.o: sys_defs.h
|
||||||
dict.o: msg.h
|
dict.o: msg.h
|
||||||
|
BIN
postfix/src/util/cache
Executable file
BIN
postfix/src/util/cache
Executable file
Binary file not shown.
26
postfix/src/util/cache.in
Normal file
26
postfix/src/util/cache.in
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
a
|
||||||
|
1
|
||||||
|
b
|
||||||
|
2
|
||||||
|
c
|
||||||
|
3
|
||||||
|
d
|
||||||
|
4
|
||||||
|
e
|
||||||
|
5
|
||||||
|
f
|
||||||
|
6
|
||||||
|
f
|
||||||
|
e
|
||||||
|
d
|
||||||
|
c
|
||||||
|
b
|
||||||
|
a
|
||||||
|
1
|
||||||
|
b
|
||||||
|
c
|
||||||
|
d
|
||||||
|
e
|
||||||
|
f
|
||||||
|
6
|
||||||
|
f
|
273
postfix/src/util/ctable.c
Normal file
273
postfix/src/util/ctable.c
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* ctable 3
|
||||||
|
/* SUMMARY
|
||||||
|
/* cache manager
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* #include <ctable.h>
|
||||||
|
/*
|
||||||
|
/* CTABLE *ctable_create(limit, create, delete, context)
|
||||||
|
/* int limit;
|
||||||
|
/* void *(*create)(const char *key, void *context);
|
||||||
|
/* void (*delete)(void *value, void *context);
|
||||||
|
/* void *context;
|
||||||
|
/*
|
||||||
|
/* const void *ctable_locate(cache, key)
|
||||||
|
/* CTABLE *cache;
|
||||||
|
/* const char *key;
|
||||||
|
/*
|
||||||
|
/* void ctable_free(cache)
|
||||||
|
/* CTABLE *cache;
|
||||||
|
/*
|
||||||
|
/* void ctable_walk(cache, action)
|
||||||
|
/* CTABLE *cache;
|
||||||
|
/* void (*action)(const char *key, const void *value);
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* This module maintains multiple caches. Cache items are purged
|
||||||
|
/* automatically when the number of items exceeds a configurable
|
||||||
|
/* limit. Caches never shrink. Each cache entry consists of a
|
||||||
|
/* string-valued lookup key and a generic data pointer value.
|
||||||
|
/*
|
||||||
|
/* ctable_create() creates a cache with the specified size limit, and
|
||||||
|
/* returns a pointer to the result. The create and delete arguments
|
||||||
|
/* specify pointers to call-back functions that create a value, given
|
||||||
|
/* a key, and delete a given value, respectively. The context argument
|
||||||
|
/* is passed on to the call-back routines.
|
||||||
|
/*
|
||||||
|
/* ctable_locate() looks up or generates the value that corresponds to
|
||||||
|
/* the specified key, and returns that value.
|
||||||
|
/*
|
||||||
|
/* ctable_free() destroys the specified cache, including its contents.
|
||||||
|
/*
|
||||||
|
/* ctable_walk() iterates over all elements in the cache, and invokes
|
||||||
|
/* the action function for each cache element with the corresponding
|
||||||
|
/* key and value as arguments. This function is useful mainly for
|
||||||
|
/* cache performance debugging.
|
||||||
|
/* DIAGNOSTICS
|
||||||
|
/* Fatal errors: out of memory. Panic: interface violation.
|
||||||
|
/* 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>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* Utility library. */
|
||||||
|
|
||||||
|
#include <msg.h>
|
||||||
|
#include <mymalloc.h>
|
||||||
|
#include <ring.h>
|
||||||
|
#include <htable.h>
|
||||||
|
#include <ctable.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cache entries are kept in most-recently used order. We use a hash table
|
||||||
|
* to quickly locate cache entries.
|
||||||
|
*/
|
||||||
|
#define CTABLE_ENTRY struct ctable_entry
|
||||||
|
|
||||||
|
struct ctable_entry {
|
||||||
|
RING ring; /* MRU linkage */
|
||||||
|
const char *key; /* lookup key */
|
||||||
|
void *value; /* corresponding value */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RING_TO_CTABLE_ENTRY(ring_ptr) \
|
||||||
|
RING_TO_APPL(ring_ptr, CTABLE_ENTRY, ring)
|
||||||
|
#define RING_PTR_OF(x) (&((x)->ring))
|
||||||
|
|
||||||
|
struct ctable {
|
||||||
|
HTABLE *table; /* table with key, ctable_entry pairs */
|
||||||
|
unsigned limit; /* max nr of entries */
|
||||||
|
unsigned used; /* current nr of entries */
|
||||||
|
CTABLE_CREATE_FN create; /* constructor */
|
||||||
|
CTABLE_DELETE_FN delete; /* destructor */
|
||||||
|
RING ring; /* MRU linkage */
|
||||||
|
void *context; /* application context */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CTABLE_MIN_SIZE 5
|
||||||
|
|
||||||
|
/* ctable_create - create empty cache */
|
||||||
|
|
||||||
|
CTABLE *ctable_create(int limit, CTABLE_CREATE_FN create,
|
||||||
|
CTABLE_DELETE_FN delete, void *context)
|
||||||
|
{
|
||||||
|
CTABLE *cache = (CTABLE *) mymalloc(sizeof(CTABLE));
|
||||||
|
char *myname = "ctable_create";
|
||||||
|
|
||||||
|
if (limit < 1)
|
||||||
|
msg_panic("%s: bad cache limit: %d", myname, limit);
|
||||||
|
|
||||||
|
cache->table = htable_create(limit);
|
||||||
|
cache->limit = (limit < CTABLE_MIN_SIZE ? CTABLE_MIN_SIZE : limit);
|
||||||
|
cache->used = 0;
|
||||||
|
cache->create = create;
|
||||||
|
cache->delete = delete;
|
||||||
|
ring_init(RING_PTR_OF(cache));
|
||||||
|
cache->context = context;
|
||||||
|
return (cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ctable_locate - look up or create cache item */
|
||||||
|
|
||||||
|
const void *ctable_locate(CTABLE *cache, const char *key)
|
||||||
|
{
|
||||||
|
char *myname = "ctable_locate";
|
||||||
|
CTABLE_ENTRY *entry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the entry is not in the cache, make sure there is room for a new
|
||||||
|
* entry and install it at the front of the MRU chain. Otherwise, move
|
||||||
|
* the entry to the front of the MRU chain if it is not already there.
|
||||||
|
* All this means that the cache never shrinks.
|
||||||
|
*/
|
||||||
|
if ((entry = (CTABLE_ENTRY *) htable_find(cache->table, key)) == 0) {
|
||||||
|
if (cache->used >= cache->limit) {
|
||||||
|
entry = RING_TO_CTABLE_ENTRY(ring_pred(RING_PTR_OF(cache)));
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("%s: purge entry key %s", myname, entry->key);
|
||||||
|
ring_detach(RING_PTR_OF(entry));
|
||||||
|
cache->delete(entry->value, cache->context);
|
||||||
|
htable_delete(cache->table, entry->key, (void (*) (char *)) 0);
|
||||||
|
} else {
|
||||||
|
entry = (CTABLE_ENTRY *) mymalloc(sizeof(CTABLE_ENTRY));
|
||||||
|
cache->used++;
|
||||||
|
}
|
||||||
|
entry->value = cache->create(key, cache->context);
|
||||||
|
entry->key = htable_enter(cache->table, key, (char *) entry)->key;
|
||||||
|
ring_append(RING_PTR_OF(cache), RING_PTR_OF(entry));
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("%s: install entry key %s", myname, entry->key);
|
||||||
|
} else if (entry == RING_TO_CTABLE_ENTRY(ring_succ(RING_PTR_OF(cache)))) {
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("%s: leave existing entry key %s", myname, entry->key);
|
||||||
|
} else {
|
||||||
|
ring_detach(RING_PTR_OF(entry));
|
||||||
|
ring_append(RING_PTR_OF(cache), RING_PTR_OF(entry));
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("%s: move existing entry key %s", myname, entry->key);
|
||||||
|
}
|
||||||
|
return (entry->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CTABLE *ctable_free_cache;
|
||||||
|
|
||||||
|
/* ctable_free_callback - callback function */
|
||||||
|
|
||||||
|
static void ctable_free_callback(char *ptr)
|
||||||
|
{
|
||||||
|
CTABLE_ENTRY *entry = (CTABLE_ENTRY *) ptr;
|
||||||
|
|
||||||
|
ctable_free_cache->delete(entry->value, ctable_free_cache->context);
|
||||||
|
myfree((char *) entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ctable_free - destroy cache and contents */
|
||||||
|
|
||||||
|
void ctable_free(CTABLE *cache)
|
||||||
|
{
|
||||||
|
CTABLE *saved_cache = ctable_free_cache;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX the hash table does not pass application context so we have to
|
||||||
|
* store it in a global variable.
|
||||||
|
*/
|
||||||
|
ctable_free_cache = cache;
|
||||||
|
htable_free(cache->table, ctable_free_callback);
|
||||||
|
myfree((char *) cache);
|
||||||
|
ctable_free_cache = saved_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ctable_walk - iterate over all cache entries */
|
||||||
|
|
||||||
|
void ctable_walk(CTABLE *cache, void (*action) (const char *, const void *))
|
||||||
|
{
|
||||||
|
RING *entry = RING_PTR_OF(cache);
|
||||||
|
|
||||||
|
/* Walking down the MRU chain is less work than using ht_walk(). */
|
||||||
|
|
||||||
|
while ((entry = ring_succ(entry)) != RING_PTR_OF(cache))
|
||||||
|
action((RING_TO_CTABLE_ENTRY(entry)->key),
|
||||||
|
(RING_TO_CTABLE_ENTRY(entry)->value));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Proof-of-concept test program. Read keys from stdin, ask for values not
|
||||||
|
* in cache.
|
||||||
|
*/
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <vstream.h>
|
||||||
|
#include <vstring.h>
|
||||||
|
#include <vstring_vstream.h>
|
||||||
|
#include <msg_vstream.h>
|
||||||
|
|
||||||
|
#define STR(x) vstring_str(x)
|
||||||
|
|
||||||
|
static void *ask(const char *key, void *context)
|
||||||
|
{
|
||||||
|
VSTRING *data_buf = (VSTRING *) context;
|
||||||
|
|
||||||
|
vstream_printf("ask: %s = ", key);
|
||||||
|
vstream_fflush(VSTREAM_OUT);
|
||||||
|
if (vstring_get_nonl(data_buf, VSTREAM_IN) == VSTREAM_EOF)
|
||||||
|
vstream_longjmp(VSTREAM_IN, 1);
|
||||||
|
if (!isatty(0)) {
|
||||||
|
vstream_printf("%s\n", STR(data_buf));
|
||||||
|
vstream_fflush(VSTREAM_OUT);
|
||||||
|
}
|
||||||
|
return (mystrdup(STR(data_buf)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drop(void *data, void *unused_context)
|
||||||
|
{
|
||||||
|
myfree(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int unused_argc, char **argv)
|
||||||
|
{
|
||||||
|
VSTRING *key_buf;
|
||||||
|
VSTRING *data_buf;
|
||||||
|
CTABLE *cache;
|
||||||
|
const char *value;
|
||||||
|
|
||||||
|
msg_vstream_init(argv[0], VSTREAM_ERR);
|
||||||
|
key_buf = vstring_alloc(100);
|
||||||
|
data_buf = vstring_alloc(100);
|
||||||
|
cache = ctable_create(1, ask, drop, (void *) data_buf);
|
||||||
|
msg_verbose = 1;
|
||||||
|
vstream_control(VSTREAM_IN, VSTREAM_CTL_EXCEPT, VSTREAM_CTL_END);
|
||||||
|
|
||||||
|
if (vstream_setjmp(VSTREAM_IN) == 0) {
|
||||||
|
for (;;) {
|
||||||
|
vstream_printf("key = ");
|
||||||
|
vstream_fflush(VSTREAM_OUT);
|
||||||
|
if (vstring_get_nonl(key_buf, VSTREAM_IN) == VSTREAM_EOF)
|
||||||
|
vstream_longjmp(VSTREAM_IN, 1);
|
||||||
|
if (!isatty(0)) {
|
||||||
|
vstream_printf("%s\n", STR(key_buf));
|
||||||
|
vstream_fflush(VSTREAM_OUT);
|
||||||
|
}
|
||||||
|
value = ctable_locate(cache, STR(key_buf));
|
||||||
|
vstream_printf("result: %s\n", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctable_free(cache);
|
||||||
|
vstring_free(key_buf);
|
||||||
|
vstring_free(data_buf);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
39
postfix/src/util/ctable.h
Normal file
39
postfix/src/util/ctable.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef _CTABLE_H_INCLUDED_
|
||||||
|
#define _CTABLE_H_INCLUDED_
|
||||||
|
|
||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* ctable 5
|
||||||
|
/* SUMMARY
|
||||||
|
/* cache manager
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* #include <ctable.h>
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* .nf
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface of the cache manager. The structure of a cache is not visible
|
||||||
|
* to the caller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CTABLE struct ctable
|
||||||
|
typedef void *(*CTABLE_CREATE_FN) (const char *, void *);
|
||||||
|
typedef void (*CTABLE_DELETE_FN) (void *, void *);
|
||||||
|
|
||||||
|
extern CTABLE *ctable_create(int, CTABLE_CREATE_FN, CTABLE_DELETE_FN, void *);
|
||||||
|
extern void ctable_free(CTABLE *);
|
||||||
|
extern void ctable_walk(CTABLE *, void (*) (const char *, const void *));
|
||||||
|
extern const void *ctable_locate(CTABLE *, const char *);
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
/*--*/
|
||||||
|
|
||||||
|
#endif
|
39
postfix/src/util/ctable.in
Normal file
39
postfix/src/util/ctable.in
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
a
|
||||||
|
1
|
||||||
|
b
|
||||||
|
2
|
||||||
|
c
|
||||||
|
3
|
||||||
|
d
|
||||||
|
4
|
||||||
|
e
|
||||||
|
5
|
||||||
|
f
|
||||||
|
6
|
||||||
|
f
|
||||||
|
a
|
||||||
|
1
|
||||||
|
b
|
||||||
|
2
|
||||||
|
c
|
||||||
|
3
|
||||||
|
d
|
||||||
|
4
|
||||||
|
e
|
||||||
|
5
|
||||||
|
f
|
||||||
|
6
|
||||||
|
f
|
||||||
|
e
|
||||||
|
d
|
||||||
|
c
|
||||||
|
b
|
||||||
|
a
|
||||||
|
1
|
||||||
|
b
|
||||||
|
c
|
||||||
|
d
|
||||||
|
e
|
||||||
|
f
|
||||||
|
6
|
||||||
|
f
|
99
postfix/src/util/ctable.ref
Normal file
99
postfix/src/util/ctable.ref
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
key = a
|
||||||
|
ask: a = 1
|
||||||
|
./ctable: ctable_locate: install entry key a
|
||||||
|
result: 1
|
||||||
|
key = b
|
||||||
|
ask: b = 2
|
||||||
|
./ctable: ctable_locate: install entry key b
|
||||||
|
result: 2
|
||||||
|
key = c
|
||||||
|
ask: c = 3
|
||||||
|
./ctable: ctable_locate: install entry key c
|
||||||
|
result: 3
|
||||||
|
key = d
|
||||||
|
ask: d = 4
|
||||||
|
./ctable: ctable_locate: install entry key d
|
||||||
|
result: 4
|
||||||
|
key = e
|
||||||
|
ask: e = 5
|
||||||
|
./ctable: ctable_locate: install entry key e
|
||||||
|
result: 5
|
||||||
|
key = f
|
||||||
|
./ctable: ctable_locate: purge entry key a
|
||||||
|
ask: f = 6
|
||||||
|
./ctable: ctable_locate: install entry key f
|
||||||
|
result: 6
|
||||||
|
key = f
|
||||||
|
./ctable: ctable_locate: leave existing entry key f
|
||||||
|
result: 6
|
||||||
|
key = a
|
||||||
|
./ctable: ctable_locate: purge entry key b
|
||||||
|
ask: a = 1
|
||||||
|
./ctable: ctable_locate: install entry key a
|
||||||
|
result: 1
|
||||||
|
key = b
|
||||||
|
./ctable: ctable_locate: purge entry key c
|
||||||
|
ask: b = 2
|
||||||
|
./ctable: ctable_locate: install entry key b
|
||||||
|
result: 2
|
||||||
|
key = c
|
||||||
|
./ctable: ctable_locate: purge entry key d
|
||||||
|
ask: c = 3
|
||||||
|
./ctable: ctable_locate: install entry key c
|
||||||
|
result: 3
|
||||||
|
key = d
|
||||||
|
./ctable: ctable_locate: purge entry key e
|
||||||
|
ask: d = 4
|
||||||
|
./ctable: ctable_locate: install entry key d
|
||||||
|
result: 4
|
||||||
|
key = e
|
||||||
|
./ctable: ctable_locate: purge entry key f
|
||||||
|
ask: e = 5
|
||||||
|
./ctable: ctable_locate: install entry key e
|
||||||
|
result: 5
|
||||||
|
key = f
|
||||||
|
./ctable: ctable_locate: purge entry key a
|
||||||
|
ask: f = 6
|
||||||
|
./ctable: ctable_locate: install entry key f
|
||||||
|
result: 6
|
||||||
|
key = f
|
||||||
|
./ctable: ctable_locate: leave existing entry key f
|
||||||
|
result: 6
|
||||||
|
key = e
|
||||||
|
./ctable: ctable_locate: move existing entry key e
|
||||||
|
result: 5
|
||||||
|
key = d
|
||||||
|
./ctable: ctable_locate: move existing entry key d
|
||||||
|
result: 4
|
||||||
|
key = c
|
||||||
|
./ctable: ctable_locate: move existing entry key c
|
||||||
|
result: 3
|
||||||
|
key = b
|
||||||
|
./ctable: ctable_locate: move existing entry key b
|
||||||
|
result: 2
|
||||||
|
key = a
|
||||||
|
./ctable: ctable_locate: purge entry key f
|
||||||
|
ask: a = 1
|
||||||
|
./ctable: ctable_locate: install entry key a
|
||||||
|
result: 1
|
||||||
|
key = b
|
||||||
|
./ctable: ctable_locate: move existing entry key b
|
||||||
|
result: 2
|
||||||
|
key = c
|
||||||
|
./ctable: ctable_locate: move existing entry key c
|
||||||
|
result: 3
|
||||||
|
key = d
|
||||||
|
./ctable: ctable_locate: move existing entry key d
|
||||||
|
result: 4
|
||||||
|
key = e
|
||||||
|
./ctable: ctable_locate: move existing entry key e
|
||||||
|
result: 5
|
||||||
|
key = f
|
||||||
|
./ctable: ctable_locate: purge entry key a
|
||||||
|
ask: f = 6
|
||||||
|
./ctable: ctable_locate: install entry key f
|
||||||
|
result: 6
|
||||||
|
key = f
|
||||||
|
./ctable: ctable_locate: leave existing entry key f
|
||||||
|
result: 6
|
||||||
|
key =
|
@@ -151,6 +151,10 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
|||||||
void (*saved_alarm) (int);
|
void (*saved_alarm) (int);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
#ifdef LDAP_API_FEATURE_X_MEMCACHE
|
||||||
|
LDAPMemCache *dircache;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LDAP_OPT_NETWORK_TIMEOUT
|
#ifdef LDAP_OPT_NETWORK_TIMEOUT
|
||||||
struct timeval mytimeval;
|
struct timeval mytimeval;
|
||||||
|
|
||||||
@@ -162,7 +166,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
|||||||
msg_info("%s: Connecting to server %s", myname,
|
msg_info("%s: Connecting to server %s", myname,
|
||||||
dict_ldap->server_host);
|
dict_ldap->server_host);
|
||||||
|
|
||||||
#ifdef UNTESTED_LDAP_OPT_NETWORK_TIMEOUT
|
#ifdef LDAP_OPT_NETWORK_TIMEOUT
|
||||||
dict_ldap->ld = ldap_init(dict_ldap->server_host,
|
dict_ldap->ld = ldap_init(dict_ldap->server_host,
|
||||||
(int) dict_ldap->server_port);
|
(int) dict_ldap->server_port);
|
||||||
if (dict_ldap->ld == NULL) {
|
if (dict_ldap->ld == NULL) {
|
||||||
@@ -247,6 +251,27 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
|||||||
myname, dict_ldap->cache_size, dict_ldap->ldapsource,
|
myname, dict_ldap->cache_size, dict_ldap->ldapsource,
|
||||||
dict_ldap->cache_expiry);
|
dict_ldap->cache_expiry);
|
||||||
|
|
||||||
|
#ifdef LDAP_API_FEATURE_X_MEMCACHE
|
||||||
|
rc = ldap_memcache_init(dict_ldap->cache_expiry, dict_ldap->cache_size,
|
||||||
|
NULL, NULL, &dircache);
|
||||||
|
if (rc != LDAP_SUCCESS) {
|
||||||
|
msg_warn
|
||||||
|
("%s: Unable to configure cache for %s: %d (%s) -- continuing",
|
||||||
|
myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
|
||||||
|
} else {
|
||||||
|
rc = ldap_memcache_set(dict_ldap->ld, dircache);
|
||||||
|
if (rc != LDAP_SUCCESS) {
|
||||||
|
msg_warn
|
||||||
|
("%s: Unable to configure cache for %s: %d (%s) -- continuing",
|
||||||
|
myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
|
||||||
|
} else {
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("%s: Caching enabled for %s",
|
||||||
|
myname, dict_ldap->ldapsource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
rc = ldap_enable_cache(dict_ldap->ld, dict_ldap->cache_expiry,
|
rc = ldap_enable_cache(dict_ldap->ld, dict_ldap->cache_expiry,
|
||||||
dict_ldap->cache_size);
|
dict_ldap->cache_size);
|
||||||
if (rc != LDAP_SUCCESS) {
|
if (rc != LDAP_SUCCESS) {
|
||||||
@@ -258,6 +283,8 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
|||||||
msg_info("%s: Caching enabled for %s",
|
msg_info("%s: Caching enabled for %s",
|
||||||
myname, dict_ldap->ldapsource);
|
myname, dict_ldap->ldapsource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: Cached connection handle for LDAP source %s",
|
msg_info("%s: Cached connection handle for LDAP source %s",
|
||||||
@@ -315,7 +342,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
|||||||
if (strcasecmp(dict_ldap->result_attributes->argv[i],
|
if (strcasecmp(dict_ldap->result_attributes->argv[i],
|
||||||
attr) == 0) {
|
attr) == 0) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: search returned value(s) for requested result attribute %s", myname, attr);
|
msg_info("%s: search returned %d value(s) for requested result attribute %s", myname, i, attr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,7 +417,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
|||||||
* load on the LDAP server.
|
* load on the LDAP server.
|
||||||
*/
|
*/
|
||||||
if (dict_ldap->domain) {
|
if (dict_ldap->domain) {
|
||||||
char *p=strrchr(name,'@');
|
const char *p=strrchr(name,'@');
|
||||||
if (p != 0)
|
if (p != 0)
|
||||||
p=p+1;
|
p=p+1;
|
||||||
else
|
else
|
||||||
@@ -482,7 +509,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
|||||||
/*
|
/*
|
||||||
* Does the supplied query_filter even include a substitution?
|
* Does the supplied query_filter even include a substitution?
|
||||||
*/
|
*/
|
||||||
if ((char *) strstr(dict_ldap->query_filter, "%s") == NULL) {
|
if ((char *) strchr(dict_ldap->query_filter, '%') == NULL) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No, log the fact and continue.
|
* No, log the fact and continue.
|
||||||
@@ -494,21 +521,40 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Yes, replace all instances of %s with the address to look up.
|
* Yes, replace all instances of %s with the address to look up.
|
||||||
|
* Replace %u with the user portion, and %d with the domain portion.
|
||||||
*/
|
*/
|
||||||
sub = dict_ldap->query_filter;
|
sub = dict_ldap->query_filter;
|
||||||
end = sub + strlen(dict_ldap->query_filter);
|
end = sub + strlen(dict_ldap->query_filter);
|
||||||
while (sub < end) {
|
while (sub < end) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure it's %s and not something else, though it wouldn't
|
* Make sure it's %[sud] and not something else. For backward
|
||||||
* really matter; the token could be any single character.
|
* compatibilty, treat anything other than %u or %d as %s, with
|
||||||
|
* a warning.
|
||||||
*/
|
*/
|
||||||
if (*(sub) == '%') {
|
if (*(sub) == '%') {
|
||||||
if ((sub + 1) != end && *(sub + 1) != 's')
|
char *u=vstring_str(escaped_name);
|
||||||
msg_warn
|
char *p=strchr(u,'@');
|
||||||
("%s: Invalid lookup substitution format '%%%c'!",
|
switch (*(sub+1)) {
|
||||||
myname, *(sub + 1));
|
case 'd':
|
||||||
vstring_strcat(filter_buf, vstring_str(escaped_name));
|
if (p)
|
||||||
|
vstring_strcat(filter_buf, p+1);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (p)
|
||||||
|
vstring_strncat(filter_buf, u, p-u);
|
||||||
|
else
|
||||||
|
vstring_strcat(filter_buf, u);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg_warn
|
||||||
|
("%s: Invalid lookup substitution format '%%%c'!",
|
||||||
|
myname, *(sub + 1));
|
||||||
|
/* fall through */
|
||||||
|
case 's':
|
||||||
|
vstring_strcat(filter_buf, u);
|
||||||
|
break;
|
||||||
|
}
|
||||||
sub++;
|
sub++;
|
||||||
} else
|
} else
|
||||||
vstring_strncat(filter_buf, sub, 1);
|
vstring_strncat(filter_buf, sub, 1);
|
||||||
@@ -607,7 +653,8 @@ static void dict_ldap_close(DICT *dict)
|
|||||||
myfree(dict_ldap->ldapsource);
|
myfree(dict_ldap->ldapsource);
|
||||||
myfree(dict_ldap->server_host);
|
myfree(dict_ldap->server_host);
|
||||||
myfree(dict_ldap->search_base);
|
myfree(dict_ldap->search_base);
|
||||||
match_list_free(dict_ldap->domain);
|
if (dict_ldap->domain)
|
||||||
|
match_list_free(dict_ldap->domain);
|
||||||
myfree(dict_ldap->query_filter);
|
myfree(dict_ldap->query_filter);
|
||||||
argv_free(dict_ldap->result_attributes);
|
argv_free(dict_ldap->result_attributes);
|
||||||
myfree(dict_ldap->bind_dn);
|
myfree(dict_ldap->bind_dn);
|
||||||
@@ -626,15 +673,15 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
|||||||
char *scope;
|
char *scope;
|
||||||
char *attr;
|
char *attr;
|
||||||
|
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("%s: Using LDAP source %s", myname, ldapsource);
|
||||||
|
|
||||||
dict_ldap = (DICT_LDAP *) dict_alloc(DICT_TYPE_LDAP, ldapsource,
|
dict_ldap = (DICT_LDAP *) dict_alloc(DICT_TYPE_LDAP, ldapsource,
|
||||||
sizeof(*dict_ldap));
|
sizeof(*dict_ldap));
|
||||||
dict_ldap->dict.lookup = dict_ldap_lookup;
|
dict_ldap->dict.lookup = dict_ldap_lookup;
|
||||||
dict_ldap->dict.close = dict_ldap_close;
|
dict_ldap->dict.close = dict_ldap_close;
|
||||||
dict_ldap->dict.flags = dict_flags | DICT_FLAG_FIXED;
|
dict_ldap->dict.flags = dict_flags | DICT_FLAG_FIXED;
|
||||||
|
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("%s: Using LDAP source %s", myname, ldapsource);
|
|
||||||
|
|
||||||
dict_ldap->ldapsource = mystrdup(ldapsource);
|
dict_ldap->ldapsource = mystrdup(ldapsource);
|
||||||
|
|
||||||
config_param = vstring_alloc(15);
|
config_param = vstring_alloc(15);
|
||||||
|
@@ -29,6 +29,17 @@ extern void ring_detach(RING *);
|
|||||||
#define ring_succ(c) ((c)->succ)
|
#define ring_succ(c) ((c)->succ)
|
||||||
#define ring_pred(c) ((c)->pred)
|
#define ring_pred(c) ((c)->pred)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Typically, an application will embed a RING structure into a larger
|
||||||
|
* structure that also contains application-specific members. This approach
|
||||||
|
* gives us the best of both worlds. The application can still use the
|
||||||
|
* generic RING primitives for manipulating RING structures. The macro below
|
||||||
|
* transforms a pointer from RING structure to the structure that contains
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
#define RING_TO_APPL(ring_ptr,app_type,ring_member) \
|
||||||
|
((app_type *) (((char *) (ring_ptr)) - offsetof(app_type,ring_member)))
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
|
Reference in New Issue
Block a user