Am 2012-09-19 22:27, schrieb Wietse Venema:
Michael Storz:
The consistency check requires that a user object is first
(correctly)
defined in OpenLDAP. Only then the second check looks for the
correct
definition in Active Directory. If it is not then we defer the email
(we
...
If a new user is created the user object appears instantly in the
OpenLDAP directory. [...]
Therefore if the user/address is not in the OpenLDAP directory I can
sa[f]ely reject such an address.
So it is an inconsistency between LDAP and Active Directory, such
that the user exists in LDAP but not yet in Active Directory.
It's almost like different organizations being responsible for
different parts of the infrastructure. Hm.
We can attack this in a number of ways.
- You want to return "450 User not yet available" when the query
returns NOTFOUND. This could be as simple as exploiting the linear
search order of smtpd_mumble_restrictions:
smtp_mumble_restrictions =
...
# Query AD first.
check_something_access ldap:the-AD-table
# Not found in AD, return a generic error.
check_something_access pcre:/etc/postfix/mumble_default
/etc/postfix/mumble_default
/./ 450 User not yet available
- Introduce special lookup keys for each table-driven feature
(access, transport_maps, canonical, etc.). The "*" in transports
is a particularly ugly example. If it would be done in a more
general manner (see examples below), then I would not have to
maintain special code that works only for one feature.
- Introduce new table syntax for multi-table features:
local_recipient_maps =
ldap:the-AD-table
notfound=tempfail:
Where tempfail is a map that always fails all queries with a
temporary error.
This requires changing all code that queries multiple maps, so
that it makes an extra call to pick up the "notfound" result.
That's pretty straightforward, as long as we resist the temptation
to extend "notfound" and make it into a programming language.
- Finer control over multi-table iteration. If there were a way
to make Postfix do all the queries on the first map before it
queries the second map, and so on, then that could also solve the
problem.
It seems that your problem is not with the multi-table features,
so the linear smtpd_mumble_restrictions search order should take
care of things.
Wietse
Hi Wietse,
thank you for helping me to solve my problem. I tried to present a
simple
example to show my problem. Unfortunately, reality is much more
complex. In this
case 3 IDMs, 3 different directories (MS AD, OpenLDAP, Novell eDir) and
3 email
systems which share mail domains are involved. Therefore the
consistency checks
are a little bit more complex than the one I described. Because it
seems I was
not able to show the underlying problem, let me rephrase my problem:
How can I configure arbitrarily complex if-then-else constructs
for every possible table type?
I can see how to configure special cases, but I am stuck with a general
solution
to this problem. To make it easier to show me where my conclusions are
wrong,
let me show my reasoning step by step (sorry for this lengthy posting).
First let me revisit restriction classes and access table actions. As
far as I
understand it, there are 2 all encompassing system restriction classes.
For
receiving an email a class which I will call default_restriction_class
to have
a name for it:
default_restriction_class =
smtpd_client_restrictions
smtpd_helo_restrictions
smtpd_sender_restrictions
smtpd_recipient_restrictions
smtpd_data_restrictions
smtpd_end_of_data_restrictions
and a special class for the commnd ETRN:
etrn_restriction_class =
smtpd_client_restrictions
smtpd_helo_restrictions
smtpd_etrn_restrictions
Every action which can be specified on the RHS in an access table has
two parts:
the actual action and a control for the flow of the evaluation of
restrictions
(jump type). All actions can be grouped into 3 categories of jump
types:
DUNNO:
------
DUNNO jumps to the end of the current evaluation of an access table.
Further
processing is done with the next restriction.
actions: BCC, DEFER_IF_PERMIT, DEFER_IF_REJECT, (DISCARD),
DUNNO, FILTER, HOLD, PREPEND, REDIRECT, WARN
OK:
___
OK jumps to the end of the current smtpd_mumble_restrictions class. At
that
point it is converted to DUNNO. Further processing is done with the
next
smtpd_mumble_restrictions class from either default_restriction_class
or
etrn_restriction_class.
actions: (DISCARD), OK, PERMIT, RELAY, all numeric code
REJECT:
-------
REJECT (in an abstract sense) jumps to the end of the
default_restriction_class
or the etrn_restriction_class. No further restriction or restriction
class is
evaluated.
actions: DEFER, REJECT, 4XX, 5XX
Let me come to the if-then-else constructs. The simplest one is
---------------------------------------------------------------------
if (condition) {
restriction1;
restriction2;
} else {
DUNNO
}
---------------------------------------------------------------------
which evaluates the listed restrictions if the condition is true (key
found).
This is the way all check_mumble_access commands work and every kind of
table
can be used for it:
---------------------------------------------------------------------
/etc/postfix/main.cf:
smtpd_mumble_restrictions =
...
check_mumble_access table_type:/etc/postfix/condition
...
e.g. table_type=hash
/etc/postfix/condition:
key1 restriction1 restriction2
---------------------------------------------------------------------
However, if we have in addition an else-clause it gets difficult:
---------------------------------------------------------------------
if (condition) {
restriction1;
restriction2;
} else {
restriction3;
restriction4;
}
---------------------------------------------------------------------
If we can use a regexp or pcre table, we can use the default value of
/./ for the else-clause:
---------------------------------------------------------------------
/etc/postfix/main.cf:
smtpd_mumble_restrictions =
...
check_mumble_access pcre:/etc/postfix/condition
...
/etc/postfix/condition:
/^key1$/ restriction1 restriction2
/./ restriction3 restriction4
---------------------------------------------------------------------
Or if we can use a cidr table, we can use the default value of
0.0.0.0/0 for the else-clause:
---------------------------------------------------------------------
/etc/postfix/main.cf:
smtpd_mumble_restrictions =
...
check_client_mumble_access cidr:/etc/postfix/condition
...
/etc/postfix/condition:
key1 restriction1 restriction2
0.0.0.0/0 restriction3 restriction4
---------------------------------------------------------------------
All other access tables do not have a default. However there is still
another
special case. When the last restriction of the if-clause (here
restriction2)
always returns an action of type REJECT or OK, but never of type DUNNO
we
can use:
---------------------------------------------------------------------
/etc/postfix/main.cf:
smtpd_restriction_classes =
condition
condition =
# if
check_mumble_access table_type:/etc/postfix/condition
# else
restriction3
restriction4
smtpd_mumble_restrictions =
...
condition
...
e.g. table_type=hash
/etc/postfix/condition:
key1 restriction1 restriction2
---------------------------------------------------------------------
However, if the condition is true, no other restriction after the
if-then-else
construct will be evaluated in this smtpd_mumble_restrictions. Therfore
this
is not a general solution. And even worse, if the last restriction in
the
if-clause evaluates (sometimes) to DUNNO, then I do not see how this
can be
configured. At this point I am stuck and need your help. Is it possible
to
configure such a construct with Postfix?
If not, may I suggest the following solution. I would introduce of a
4th jump
type, which I will call LAST. It would stand between DUNNO and OK. It
jumps to
the end of the current restriction class, either user or system
defined. At that
point it is converted to DUNNO. Further processing is done with the
next
restriction after the current restriction class (do you see the
similarity to
OK?). With this action we can configure the following:
---------------------------------------------------------------------
/etc/postfix/main.cf:
smtpd_restriction_classes =
condition
condition =
# if
check_mumble_access table_type:/etc/postfix/condition
# else
restriction3
restriction4
smtpd_mumble_restrictions =
...
condition
...
e.g. table_type=hash
/etc/postfix/condition:
key1 restriction1 restriction2 LAST
---------------------------------------------------------------------
If the condition is true and restriction1 and restriction2 evaluated to
jump
type DUNNO the action LAST will be executed. This would jump over
restriction3
and restriction4 to the end of restriction class condition and the next
following restriction would be evaluated. This means the general
if-then-else
construction could be build with Postfix restriction classes.
If we have a long list of restrictions for the if-clause it would be
nice to be
able to encapsulate the list in an own restriction class. In this case
we would
need a label for the LAST action with the name of the outer restriction
class
to leave:
---------------------------------------------------------------------
nice general case: LAST with label
/etc/postfix/main.cf:
smtpd_restriction_classes =
condition
if_restriction_list
condition =
# if
check_mumble_access table_type:/etc/postfix/condition
# else
restriction3
restriction4
if_restriction_list =
restriction1
restriction2
LAST condition
smtpd_mumble_restrictions =
...
condition
...
e.g. table_type=hash
/etc/postfix/condition:
key1 if_restriction_list
---------------------------------------------------------------------
As you can see LAST works the same way for user restriction classes as
OK works
for smtpd_mumble_restrictions classes.
Does this make sense now? Or did I overlook something?
Michael