[Dovecot] Sieve > Pigeonhole > external storage with LDAP or other data source available to dovecot

Martin F. Foster martin_foster at pacific.net.au
Wed Jan 6 10:47:44 EET 2010


> On 5.1.2010, at 10.02, Martin F. Foster wrote:
>
>    
>> I am looking at porting and generalizing an old in-house patch that I'm using for the CMU Sieve plugin.  It allows sieve script to test&  lookup arguments from LDAP.
>>      
> ..
>    
>> Related work:
>>
>>   1. Pigeonhole low priority TODO would like to implement alternate
>>      script storage, eg: LDAP&  SQL.  I'm not immediately interested in
>>      alternate types of script storage, but for what I want to acheive,
>>      I need to sanely access at least an LDAP directory.
>>   2. draft-ietf-sieve-external-lists
>>      (http://tools.ietf.org/html/draft-ietf-sieve-external-lists-01)
>>      proposes a mechanism to pull mailing list addresses from external
>>      storage mechanisms such as LDAP, ACAP or relational databases.      I'm interested in this, but would like to extend this
>>      functionality beyond just lists as the example above demonstrates.
>>      
> I haven't looked into that draft or thought much about this, but would doing the lookups via Dovecot's lib-dict be ok? That would of course need a dict-ldap backend implemented, but it would be a generic way to solve this, if its API is good enough.
>    

After another day of looking into this, I believe that there are two 
concerns to be addressed:
1. dovecot implementation: how dovecot/pigeonhole provides access to 
these external sources in a sane way. I do like the dict interface for 
this, which could keep LDAP url's (or SQL queries, etc) out of sieve 
scripts, and into nicely compartementalized configuration files. Being 
very ldap focussed at my site, I hadn't looked at dict before today.
2. sieve language: an extension which would allow scripts to get 
information from an external source. I'm asking the 
draft-ietf-sieve-external-lists authors a few questions about this.


The end result would be something like what follows:

Dovecot implementation (proposed):
-------------------------------------

<dovecot.conf>
dict {
dict_sieve = ldap:/etc/dovecot/dovecot-sieve-ldap.conf
}

plugin {
# TODO: proxy this dict?
sieve_extsrc = dict
}
</dovecot.conf>

then I'm not sure how you specify multiple hosts with the dict-sql 
format, so I'm using the postfix convention. there's probably a better 
way for dovecot.
<dovecot-sieve-ldap.conf>
map {
name = responder_mode
server_host = ldap://server1.mycorp.com, ldap://server2.mycorp.com
search_base = o=mailstuff
query_filter = (&(objectclass=mailschema)(uid=%u))
result_attribute = responder_mode
result_scope = sub
bind = no
version = 3
}
map {
name = responder_text
server_host = ldap://server1.mycorp.com, ldap://server2.mycorp.com
search_base = o=mailstuff
query_filter = (&(objectclass=mailschema)(uid=%u))
result_attribute = responder_text
result_scope = sub
bind = no
version = 3
}
map {
name = forward_keep
server_host = ldap://server1.mycorp.com, ldap://server2.mycorp.com
search_base = o=mailstuff
query_filter = (&(objectclass=mailschema)(uid=%u))
result_attribute = mailForwardKeep
result_scope = sub
bind = no
version = 3
}
map {
# in this case we can have many responses
name = forward_addresses
server_host = ldap://server1.mycorp.com, ldap://server2.mycorp.com
search_base = o=mailstuff
query_filter = (&(objectclass=mailschema)(uid=%u))
result_attribute = mailForwardAddress
result_scope = sub
bind = no
version = 3
}
</dovecot-sieve-ldap.conf>

Sieve language:
---------------------
then with proposed new functions of the sieve language (all names 
plucked out of my head 2hrs ago, would have to think about the semantics 
some more):

1. a “:list” argument that expects a string-list

2. a “:extsrc” argument that expects an <ext-name: string> and returns a 
string-list

3. a “:extsrc1” argument that expects an <ext-name: string> and returns 
a string

4. a new test that uses information that is not in the message, say 
“arbitrary [comparator] string string” (syntax needs work)


sample uses in scripts are then:

1. redirect to a mailing list sourced from ldap (or wheverver):

# mailForwardAddress attribute can be present >=0 times

redirect :list :extsrc “dict:forward_addresses”

2. decide whether to keep or discard forwarded messages (eg: after the 
above rule)

# mailForwardKeep attribute should only be present once, if at all

if arbitrary :is :extsrc1 “dict:forward_keep” “TRUE” {

keep;

}

3. decide vacation action and text based in information in an ldap dir:

# mailResponderMode & mailResponderText attrs should only be present 
once, if at all

if arbitrary :is :extsrc1 “dict:responder_mode” “alwaysreply” {

vacation :days 1 :extsrc1 “dict:responder_text";

}

if arbitrary :is :extsrc1 “dict:responder_mode” “holiday” {

vacation :days 30 :extsrc1 “dict:responder_text”;

}


... where the "dict:mapname" syntax would be dovecot implementation 
specific. could also support the URL & TAG-URI schemes as proposed by 
draft-ietf-sieve-external-lists. This would allow query URLs as a more 
general case, using whatever's configured in /etc/ldap/ldap.conf (or 
whatever the platform's ldap client lib uses). Doing this does raise 
some resource consumption concerns, hence there should probably be a 
means of restricting external queries to global scripts only (or 
sieve_before, sieve_after), and a means of providing timeout values, etc.

eg:

if arbitrary :is :extsrc1 “ldap:///o=myorg?mailForwardKeep” “TRUE” {

keep;

}



I'll keep on thinking about the design, staring intently at the dovecot 
sources and http://wiki.dovecot.org/Design for another couple days 
before attempting to write some code to test this. Feedback on the 
design of both the sieve language extension, & dovecot interface very 
appreciated.

Cheers,

-Martin Foster





More information about the dovecot mailing list