...making Linux just a little more fun!
[ In reference to "Migrating a Mail Server to Postfix/Cyrus/OpenLDAP" in LG#124 ]
René Pfeiffer [lynx at luchs.at]
Hello, Peter!
Glad to be of help, but please keep in mind posting replies also to the TAG list. Others might find helpful comments, which is never a bad thing.
On Dec 10, 2007 at 1428 -0600, Peter Clark appeared and said:
> [...] > Some more questions for you, if you do not mind. > > # Indices to maintain > > You have mailLocalAddress, mailRoutingAddress and memberUid being > maintained (in your example slapd.conf). What is calling upon them in > your example?
These attributes were supposed to be used in a future project, that's the main reason. I took the slapd.conf from a live server and anonymised the critical part of the configuration.
> You also have mail listed, isn't mail and mailLocalAddress > the same thing?
No, we only used the mail attribute in our setup, we ignored mailLocalAddress.
> Also, mailQuotaSize, mailQuotaCount,mailSizeMax; I > understand mailQuotaSize but did you restrict a user by the # of > messages in their account (mailQuotaCount) and how did you use > mailSizeMax?
These attributes are used by the quota management system, which I didn't describe in the article. It is basically a web-based GUI where administrators can change these values. Some scripts read the quota values from the LDAP directory and write it to the Cyrus server by using the Cyrus Perl API. mailSizeMax isn't used in the setup, but again it was supposed to be.
> Doesn't imap.conf and main.cf hold those values?
AFAIK the imap.conf only holds IMAP-relevant things. Cyrus is only interested in the authentication, and this is done by saslauthd. main.cf only holds references to the configuration files that contain the LDAP lookups.
> Does the order in which the indices are listed matter? > > ie could: > index accountStatus eq > index objectClass,uidNumber,gidNumber eq > index cn,sn,uid,displayName,mail eq,pres,sub > > be written: > index cn,sn,uid,displayName,mail eq,pres,sub > index accountStatus eq > index objectClass,uidNumber,gidNumber eq > > also couldnt: > index accountStatus eq > index objectClass,uidNumber,gidNumber eq > be combined to: > index accountStatus,objectClass,uidNumber,gidNumber eq > > Is it separated due to visual aesthetics or does it make a difference to > the database somehow?
Frankly I doubt that the order matters. The indices I used are an educated guess. Having too much indices slows things down, having too few leads also to low performance. Generally speaking all attributes that are accessed often should have indices.
> I am struggling with creating the ldif file. This directory structure > is so all encompassing I am getting buried by to many options. In > looking at the OpenLDAP Admin guide and various "How To" guides > everyone has so many different ways of achieving their goals and I am > really confused.
Try to think of "your" tree as a collection of logical containers. Try to imagine what data you wish to to have grouped in order to make access and access rules easy later on.
LDAP trees need some design before they are put into the field (similar to database structures). This is also the reason why everyone has a different design.
> I have an existing openldap-2.0.11 install. It was installed prior to > me and only functioned as a global address book for our mail system. > It does not serve as much of a template for data. I have only 2 types > of records in this data base. > > One entry of: > dn: dc=3Dexample, dc=3Dnet > dc: example > objectclass: domain > > and the rest are users: > dn: uid=3Dpeckt, dc=3Dexample, dc=3Dnet > cn: Templeton Peck > ou: student > o: Example College > objectclass: person > mail: [email protected] > > So building the directory structure is getting frustrating.
Yes, I can imagine. This looks more like a simple tree with one branch for the mail users. In this case you can extend the existing branch with suitable object classes and use it for the mail subsystem. However if not too many systems use the existing structure, then you have the unique opportunity of improving the design.
> In order to use the structure you suggested (this is fresh install > with no existing structure or data): > > dn: dc=3Dexample,dc=3Dnet > ou=3Daccounts,dc=3Dexample,dc=3Dnet > ou=3Dsystem,ou=3Daccounts,dc=3Dexample,dc=3Dnet > cn=3Dcyrus,ou=3Dsystem,ou=3Daccounts,dc=3Dexample,dc=3Dnet > cn=3Dpostfix,ou=3Dsystem,ou=3Daccounts,dc=3Dexample,dc=3Dnet > cn=3Dwebmail,ou=3Dsystem,ou=3Daccounts,dc=3Dexample,dc=3Dnet > ou=3Dusers,ou=3Daccounts,dc=3Dexample,dc=3Dnet > ou=3Dedv,dc=3Dexample,dc=3Dnet > ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet > cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet > cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet > (these under the last entry, gotta love wordwrap) > lookupName=3Daliases,cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet > lookupName=3Dmydestination,cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet > lookupName=3Dvirtualdomains,cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet > lookupName=3Dvirtualusers,cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet > > For curiosity's sake why did you name it "edv" (ou=3Dedv, dc=3Dexample, dc=3Dnet)?
For language reasons, EDV means "Elektronische Datenverarbeitung" in German. This is the equivalent of the acronym IT for most German speaking people.
> I guess the first question is the root level of the tree. Is "dn: > dc=3Dexample,dc=3Dnet" the correct way to write that?
It is common. Most organisations using TCP/IP and DNS code their domain and subdomains into the LDAP tree by using "dc=3Ddomain,dc=3Dtld".
> And then in building the DIT from scratch by creating a LDIF file to import > that lookis like this?: > > dn: dc=3Dexample, dc=3Dnet > o: Example College > description: Organization Root > objectClass: top > objectClass: organization > > dn: ou=3Daccounts, dc=3Dexample, dc=3Dnet > ou: Accounts > description: Accounts that can interact with us > objectClass: top > objectClass: organizationalUnit > > dn: ou=3Dedv, dc=3Dexample, dc=3Dnet > ou: Edv > description: Server environment settings > objectClass: top > objectClass: organizationalUnit > > dn: ou=3Dsystem, ou=3Daccounts, dc=3Dexample, dc=3Dnet > ou: System > description: Read-only accounts to do lookups > objectClass: top > objectClass: organizationalUnit > > dn: ou=3Dusers, ou=3Daccounts, dc=3Dexample, dc=3Dnet > ou: Users > description: Actual users > objectClass: top > objectClass: organizationalUnit > > dn: ou=3Dserver, ou=3Dedv, dc=3Dexample, dc=3Dnet > ou: Server > description: Various servers > objectClass: top > objectClass: organizationalUnit > > dn: cn=3Dcyrus, ou=3Dsystem, ou=3Daccounts, dc=3Dexample, dc=3Dnet > cn: cyrus > sn: cyrus > userPassword: {SSHA}blah1 > objectClass: Top > objectClass: Person > > dn: cn=3Dpostfix, ou=3Dsystem, ou=3Daccounts, dc=3Dexample, dc=3Dnet > cn: postfix > sn: postfix > userPassword: {SSHA}blah2 > objectClass: Top > objectClass: Person > > dn: cn=3Dwebmail, ou=3Dsystem, ou=3Daccounts, dc=3Dexample, dc=3Dnet > cn: webmail > sn: webmail > userPassword: {SSHA}blah3 > objectClass: Top > objectClass: Person > > dn: cn=3Dpostfix, cn=3Dmailstore, ou=3Dserver, ou=3Dedv, dc=3Dexample, dc=3Dnet > cn: postfix > sn: postfix > userPassword: {SSHA}blah3 > objectClass: Top > objectClass: Person > > dn: lookupName=3Daliases, cn=3Dpostfix, cn=3Dmailstore, ou=3Dserver, ou=3Dedv, > dc=3Dexample, dc=3Dnet > cn: postfix > sn: postfix > userPassword: {SSHA}blah3 > objectClass: Top > objectClass: Person > > dn: lookupName=3Dmydestination, cn=3Dpostfix, cn=3Dmailstore, ou=3Dserver, ou=3Dedv, > dc=3Dexample, dc=3Dnet > cn: postfix > sn: postfix > userPassword: {SSHA}blah3 > objectClass: Top > objectClass: Person > > dn: lookupName=3Dvirtualdomains, cn=3Dpostfix, cn=3Dmailstore, ou=3Dserver, ou=3Dedvv, > dc=3Dexample, dc=3Dnet > cn: postfix > sn: postfix > userPassword: {SSHA}blah3 > objectClass: Top > objectClass: Person > > dn: lookupName=3Dvirtualusers, cn=3Dpostfix, cn=3Dmailstore, ou=3Dserver, ou=3Dedv, > dc=3Dexample, dc=3Dnet > cn: postfix > sn: postfix > userPassword: {SSHA}blah3 > objectClass: Top > objectClass: Person > > dn: uid=3Dpeckt, ou=3Dusers, ou=3Daccounts, dc=3Dexample dc=3Dnet > objectClass: account > objectClass: greenUser > objectClass: posixAccount > objectClass: sqAccount > userPassword: {SSHA}XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX > mail: [email protected] > uid: peckt > uidNumber: 123456 > cn: Templeton J Peck > gn: Templeton > sn: Peck > accountStatus: active > gidNumber: 100 > homeDirectory: /home/peckt > mailQuotaSize: 51200 > mailForwardingAddress: > mailReplyText: > mailServer: mail1.example.edu > ou: Student
Looks ok to me; it's just that I have no LDAP server ready to test an import.
> Do I actually need to make containers in this manner for this > implementation?
Yes. When creating LDIFs make sure you create the roots of the branches before the objects that have to be stored inside these branches. "ou=3Dusers, ou=3Daccounts, dc=3Dexample dc=3Dnet" has to exist before "uid=3Dpeckt, ou=3Dusers, ou=3Daccounts, dc=3Dexample dc=3Dnet" can be added. This can be ensured by ordering the entries in the LDIF.
> Do I need to specify objectClass:top in any (in just one and it is > inherited?) or all of them? I guess I am not sure how to apply objectClass > to postfix, cyrus, webmail either.
The objectClass attribute defines an object class. You can list as many as you wish (and as long as they are compatible). An object class in LDAP is pretty similar to objects in Java or C++. Objects can have relations such as inheritance. "objectClass: top" is an abstract class to start somewhere.
http://www.openldap.org/lists/openldap-software/200504/msg00226.html http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/rzahy/rzahyobjectclass.htm
> You also have entries for lookupName. Do I have these entries even remotely > close (objectClass, cn and such)?
The lookupName is the name and container of a simple lookup table (as Postfix/Sendmail use for their aliases or other maps). This means that
lookupName=3Daliases,cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnetis just a fancy LDAP name for the alias table of the Postfix belonging to the mailstore subsystem on server edv.example.net. It is one of the many way to organise data inside a LDAP tree.
> Do I actually need info under these or are they just like the cyrus > and postfix entries and are a way for postfix to search the DIT?
The info below "lookupName=3Daliases,..." represents the data of the lookup table. The whole DN "lookupName=3Daliases,..." serves as a reference where to start looking. This is why DNs like these are used in the Postfix and Cyrus configurations.
> Do they even need a password?
It is good practice to guard your lookup tables by using passwords. In order to do this the individual DNs don't need password attributes. You can use access lists and describe which branch is accessible by which user.
> Thank you for any time you are willing spend helping me.
You're welcome.
Best, René.
-- )\._.,--....,'``. Let GNU/Linux work for you while you take a nap. /, _.. \ _\ (`._ ,. R. Pfeiffer <lynx at luchs.at> + http://web.luchs2Eat/ `._.-(,_..'--(,_..'`-.;.' - System administration + Consulting + Teaching - Got mail delivery problems? http://web.luchs.at/information/blockedmail.php
Peter Clark [clarkp at mtmary.edu]
René Pfeiffer wrote:
> Hello, Peter! > > Glad to be of help, but please keep in mind posting replies also to the > TAG list. Other's might find helpful comments, which is never a bad > thing.Thank you for the reminder, apparently I hit "reply to sender" and not "reply all".
>> Also, mailQuotaSize, mailQuotaCount,mailSizeMax; I >> understand mailQuotaSize but did you restrict a user by the # of >> messages in their account (mailQuotaCount) and how did you use >> mailSizeMax? > > These attributes are used by the quota management system, which I didn't > describe in the article. It is basically a web-based GUI where > administrators can change these values. Some scripts read the quota > values from the LDAP directory and write it to the Cyrus server by using > the Cyrus Perl API. mailSizeMax isn't used in the setup, but again it > was supposed to be. >
Is the management system based off your "cyrus_syncboxes.pl"? Could you describe the system you used?
> >> Do I need to specify objectClass:top in any (in just one and it is >> inherited?) or all of them? I guess I am not sure how to apply objectClass >> to postfix, cyrus, webmail either. > > The objectClass attribute defines an object class. You can list as many > as you wish (and as long as they are compatible). An object class in > LDAP is pretty similar to objects in Java or C++. Objects can have > relations such as inheritance. "objectClass: top" is an abstract class > to start somewhere. > > http://www.openldap.org/lists/openldap-software/200504/msg00226.html > http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/rzahy/rzahyobjectclass.htm
Am I understanding correctly that because 'top' is an abstract it does not explicitly need to be added to every entry? The second link shows an example that seems to conflict this.
"all objectClasses defined in the schema must directly or indirectly inherit from "top", so your entries will be fine as soon as you provide exactly one structural objectClass in all of them"
Because every objectClass in the SCHEMA inherits from 'top' I only need to provide to each LDIF entry for OpenLDAP?
objectClass: blah and NOT: objectClass: top objectClass: blah
>> You also have entries for lookupName. Do I have these entries even remotely >> close (objectClass, cn and such)? > > The lookupName is the name and container of a simple lookup table (as > Postfix/Sendmail use for their aliases or other maps). This means that > > lookupName=aliases,cn=postfix,cn=mailstore,ou=server,ou=edv,dc=example,dc=net > > is just a fancy LDAP name for the alias table of the Postfix belonging > to the mailstore subsystem on server edv.example.net. It is one of the > many way to organise data inside a LDAP tree. > >> Do I actually need info under these or are they just like the cyrus >> and postfix entries and are a way for postfix to search the DIT? > > The info below "lookupName=aliases,..." represents the data of the > lookup table. The whole DN "lookupName=aliases,..." serves as a > reference where to start looking. This is why DNs like these are used in > the Postfix and Cyrus configurations. >
Postfix and ldif configuring.
In your OpenLDAP structure section you refer to:
lookupName=aliases lookupName=mydestination lookupName=virtualdomains lookupName=virtualusersI only see that you 'search_base' on 3 of them (mydestination, virtualdomains and virtualusers). What happened to aliases? Is it not used in the example due to this: '' alias_maps = hash:/etc/aliases, hash:/etc/postfix/cgate_lists '' in main.cf?
Could you give an example of an entry under any of the lookupName in the ldif file (is this actually called a table entry?)? Should I be using an objectClass of lookupTable or lookupTableEntry? I guess I am not sure what data would actually go into the attributes either.
I have this currently but from what I am thinking now, this is not correct:
dn: lookupName=aliases, cn=postfix, cn=mailstore, ou=server, ou=edv, dc=example, dc=net cn: postfix sn: postfix userPassword: {SSHA}blah3 objectClass: PersonOK I just re-read your last response to me and now I am getting locked in a circle.
"lookupName=aliases,cn=postfix,cn=mailstore,ou=server,ou=edv,dc=example,dc=net is just a fancy LDAP name for the alias table of the Postfix belonging to the mailstore subsystem on server edv.example.net. It is one of the many way to organise data inside a LDAP tree."Are you saying that the main.cf calls:
mydestination = localhost, ldap:/etc/postfix/mydestination.cf'' and Postfix is told to do a ldap query (ldap based on a file (/etc/postfix/mydestination.cf) and this query binds as `` cn=postfix,ou=system,ou=accounts,dc=example,dc=netand returns an attribute of some type from the '' lookupName=mydestination,cn=postfix,cn=mailstore,ou=server,ou=edv,dc=example,dc=net '' entry? Even though I do not know the contained data, is that the process?
And lastly can I have blank entries in my ldif file? ie:
mailQuotaSize: 51200 mailForwardingAddress: mailReplyText: mailServer: mail1.example.netI would assume so as long as nothing is looking there and expecting to find something.
I am truly grateful for this.
Peter
René Pfeiffer [lynx at luchs.at]
Hello, Peter!
On Dec 12, 2007 at 1536 -0600, Peter Clark appeared and said:
> René Pfeiffer wrote: >> Glad to be of help, but please keep in mind posting replies also to the >> TAG list. Other's might find helpful comments, which is never a bad >> thing. > > Thank you for the reminder, apparently I hit "reply to sender" and not > "reply all".
No problem.
>> These attributes are used by the quota management system, which I didn't >> describe in the article. It is basically a web-based GUI where >> administrators can change these values. Some scripts read the quota >> values from the LDAP directory and write it to the Cyrus server by using >> the Cyrus Perl API. mailSizeMax isn't used in the setup, but again it >> was supposed to be. > > Is the management system based off your "cyrus_syncboxes.pl"? Could you > describe the system you used?
The management system consists of a couple of Perl scripts. cyrus_syncboxes.pl only synchronises the mail quota settings from the LDAP tree with the settings on the Cyrus server. The other scripts are CGIs and part of a web management UI. Admins can create, delete and modify accounts. A rough overview over the functionality can be found here: http://web.luchs.at/information/docs/mailadmin_prozesse.pdf
I am trying to publish the scripts as soon as I got the time to review the code and remove everything specific to the servers they manage.
>> The objectClass attribute defines an object class. You can list as many >> as you wish (and as long as they are compatible). An object class in >> LDAP is pretty similar to objects in Java or C++. Objects can have >> relations such as inheritance. "objectClass: top" is an abstract class >> to start somewhere.=20 >> http://www.openldap.org/lists/openldap-software/200504/msg00226.html >> http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/rzahy/rzahyobjectclass.htm > > Am I understanding correctly that because 'top' is an abstract it does not > explicitly need to be added to every entry? The second link shows an > example that seems to conflict this.
Usually you use the "top" object class when you create branches that don't need any special attributes. Since LDIF exports often contain "top" I also included it when writing LDIF files.
> [...] > Because every objectClass in the SCHEMA inherits from 'top' I only need to > provide to each LDIF entry for OpenLDAP? > objectClass: blah > and NOT: > objectClass: top > objectClass: blah
Yes, although the latter should work fine, too.
>> [...] >> The info below "lookupName=3Daliases,..." represents the data of the >> lookup table. The whole DN "lookupName=3Daliases,..." serves as a >> reference where to start looking. This is why DNs like these are used in >> the Postfix and Cyrus configurations. >> > > Postfix and ldif configuring. > In your OpenLDAP structure section you refer to: > lookupName=3Daliases > lookupName=3Dmydestination > lookupName=3Dvirtualdomains > lookupName=3Dvirtualusers > > I only see that you 'search_base' on 3 of them (mydestination,=20 > virtualdomains and virtualusers). What happened to aliases? Is it not used > in the example due to this: > alias_maps =3D hash:/etc/aliases, hash:/etc/postfix/cgate_lists > in main.cf?
Yes, we chose to use files because we didn't configure the main domain as virtual domain. Postfix allows you to mix this. You could use a line like this:
alias_maps =3D hash:/etc/aliases, ldap:/etc/postfix/aliases.cfThen Postfix would look first into the file database belonging to /etc/aliases. If no match occurs it looks into the LDAP branch defined by /etc/postfix/aliases.cf. This is very nice for chaining tables by order of preference or adding legacy configurations (such as the list aliases in our case).
> Could you give an example of an entry under any of the lookupName in the > ldif file (is this actually called a table entry?)? Should I be using an > objectClass of lookupTable or lookupTableEntry? I guess I am not sure what > data would actually go into the attributes either.
Ok, let's build a blacklist for users that don't receive any email. First we create a lookupTable called blacklist.
dn: lookupName=3Dblacklistrcpt,cn=3Dmta,dc=3Dexample,dc=3Dnet objectclass: top objectclass: lookupTable lookupName: blacklistrcpt description: Table for blacklisted recipientsAfter that you can fill the table with accounts that receive no email:
dn: lookupKey=3Dman,lookupName=3Dblacklistrcpt,cn=3Dmta,dc=3Dexample,dc=3Dnet objectclass: top objectclass: lookupTableEntry lookupKey: man lookupValue: REJECT dn: lookupKey=3Dsys,lookupName=3Dblacklistrcpt,cn=3Dmta,dc=3Dexample,dc=3Dnet objectclass: top objectclass: lookupTableEntry lookupKey: sys lookupValue: REJECT dn: lookupKey=3Duucp,lookupName=3Dblacklistrcpt,cn=3Dmta,dc=3Dexample,dc=3Dnet objectclass: top objectclass: lookupTableEntry lookupKey: uucp lookupValue: REJECT
> I have this currently but from what I am thinking now, this is not correct: > dn: lookupName=3Daliases, cn=3Dpostfix, cn=3Dmailstore, ou=3Dserver, ou=3Dedv, dc=3Dexample, dc=3Dnet > cn: postfix > sn: postfix > userPassword: {SSHA}blah3 > objectClass: Person
You don't need the object class "person" for lookup tables. You only need "lookupTable" for the table itself and "lookupTableEntry" for every entry in the table.
> OK I just re-read your last response to me and now I am getting locked in a > circle. > "lookupName=3Daliases,cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet > is just a fancy LDAP name for the alias table of the Postfix belonging to > the mailstore subsystem on server edv.example.net. It is one of the many ways > to organise data inside a LDAP tree." > > Are you saying that the main.cf calls: > mydestination =3D localhost, ldap:/etc/postfix/mydestination.cf and Postfix is > told to do a ldap query (ldap based on a file > (/etc/postfix/mydestination.cf) and this query binds as > cn=3Dpostfix,ou=3Dsystem,ou=3Daccounts,dc=3Dexample,dc=3Dnet and returns an attribute > of some type from the > lookupName=3Dmydestination,cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3De=dv,dc=3Dexample,dc=3Dnet > entry? Even though I do not know the contained data, is that the process?
Yes, that's exactly what it does. Postfix sends lookup as LDAP query. The query searches everything below "lookupName=3Dmydestination,cn=3Dpostfix,cn=3Dmailstore,ou=3Dserver,ou=3Dedv,dc=3Dexample,dc=3Dnet". If it returns a result, then Postfix knows that the item is contained in the table and Postfix will assume that the domain it queried is part of the mydestination domains. If the query returns no results, Postfix knows that the domain belongs to somewhere else. In the case of mydestination Postfix doesn't use the result. In the case of our blacklist table, the result is used as an action code, just as in a simple text-based table.
> And lastly can I have blank entries in my ldif file? ie: > mailQuotaSize: 51200 > mailForwardingAddress: > mailReplyText: > mailServer: mail1.example.net > I would assume so as long as nothing is looking there and expecting to find > something.
This depends on the definition of the object class in the schema file. Some attributes may be empty, some need to have a value. I think in this case the LDAP import will not create an entry with this attribute. When building our LDAP tree we left many attributes out since we only needed what Postfix should look up.
Best regards, René.