====== Setup an email server with OpenLDAP backend ====== This tutorial assumes that you have: * Installed ''sudo'' * Added your user to the ''sudoers'' file The process on this page has been tested with Debian 6 x64. ===== About this tutorial ===== This tutorial is intended to show you, step by step, the process of setting up a complete mailserver using Gandi hosting. It will show you how to: - Install an LDAP server and the associated client utilities (OpenLDAP) - The installation of an electronic messaging server (Postfix) - Installation of binaries for SMTP authentication (Cyrus-SASL) - The installation of an IMAP and POP3 server (Dovecot) The tutorial does not cover: * The installation or management of a webserver (this is another topic) * SSL security * Securing an LDAP server and management of its permissions * Advanced management of email accounts (quotas, etc) These topics will be addressed in other tutorials. ===== Installation of OpenLDAP ===== To store email addresses, user accounts, passwords and aliases, you can choose between an LDAP directory or a SQL server. SQL offers good storage performance, however, we are using LDAP here for several reasons: * LDAP provides better performance than SQL for storing users because that is its primary purpose, whereas SQL is used for storing any type of data. * LDAP, as its name implies, provides the benefits of a //directory//. If it is configured correctly, you can use it with email clients like Thunderbird or Outlook to access email address lists. ==== Installation and basic configuration ==== === Installation === Installing OpenLDAP isn't complicated; just run the following commands: To become root: su - root apt-get install –y slapd You will be prompted to create and confirm an LDAP password. Choose a complex password, preferably different from the administrator password of your machine. Once you've entered and confirmed the password, the installation will continue and should complete on its own. === Basic configuration === Once the installation is complete, it is necessary to configure the server a bit. To do this, enter the following command: dpkg-reconfigure slapd - The first screen will prompt you to omit the OpenLDAP server configuration. **Select ''''** - The second screen prompts you for the domain name for the DNS. It is preferable to use the bare domain (i.e. ''%%example.com%%'') as opposed to a subdomain (i.e. ''ldap.example.com''). This will be translated to an LDAP DN (for example, ''example.com'' would become ''dc=example, dc=com''). This becomes what is known as your BaseDN, the root of your database. - The next screen asks you for the name of the organization. You can enter any string; this becomes associated with the ''o'' field of your BaseDN record. - Next, enter your LDAP administrator password twice. This will set the password for ''cn=admin, BaseDN'' and give ''cn=admin, BaseDN'' write access to everything in your LDAP tree. //Note: this isn't the same account as the one you set up in the first step. While the account on the first step will have rights to the tree configuration, the administrator in this step has the rights to the domain (sub)tree.// - The fifth screen prompts you to choose a database backend. **Choose ''HDB''**. - The sixth screen asks if you want the database to be removed when slapd is purged. **Choose ''''**; this will come in handy if you accidentally uninstall the server (it happens to the best of us). - The seventh screen prompts you to move the old database files before creating a new database. **Select ''''**. Upon submitting the last step, ''slapd'' will validate your configuration. If it is invalid, it will prompt you to retry. Make sure the organization is not left empty and the admin passwords match. * If your input is valid, the following screen will ask if you want to allow the LDAPv2 protocol to be activated. If you want to be able to look consult your directory with old versions of Windows and/or Outlook, which don't support version 3 of the LDAP protocol, you can choose ''''**. Good job, you've made it through the initial configuration. ==== Additional configuration ==== Run this command: apt-get ldap-utils An OpenLDAP update changed a configuration option for OpenLDAP. Where before this configuration was stored in a file (/etc/ldap/slapd.conf), it is now in a container on the LDAP server (cn = config). Some utilities allow you to perform direct conversion of files written in the old format to LDIF files, which can be used to add / modify entries in the directory. Many tutorials show how to do all server configuration using slaptest. In this tutorial, we decided to use slaptest to migrate any old configuration files to the new format. This tutorial will therefore show you how to make configuration the changes directly in the directory, since that is where they should be after migration. As for the schema extensions proposed by Courier and not updated to the new configuration format, you will use slaptest to perform the update of any requisite schema. You will need the OpenLDAP client utilities installed: apt-get install -y ldap-utils ==== Modification of access rules ==== First, verify if, when connecting anonymously to the principal branch of your directory, you are able to access its data: ldapsearch -x -h localhost -b "dc=example,dc=com" -LLL "dc=example" dn A result like this should then appear: dn: dc=example,dc=com This result indicates that an anonymous user has the ability to access this branch of your directory (with some limitations). This is not preferable. Listing the full contents of cn=config would be too much data to be helpful, so we will use a filter to get only the information we need. ** Fishing lessons > free fish ** To know where in your directory to find certain information, you can consult the OpenLDAP documentation. First, verify the version of your OpenLDAP server: slapd -V The results will look like this: # slapd -V @(#) $OpenLDAP: slapd 2.4.23 (Jun 15 2011 13:31:57) $ @incagijs:/home/thijs/debian/p-u/openldap-2.4.23/debian/build/servers/slapd Once you know the version of your server (in this case, 2.4.23), see the official [[http://www.openldap.org/doc/index.html|OpenLdap docs]] corresponding to your version. There, you will find a section on the configuration of ''slapd'', including the full structure of ''cn=config'', as well as the role of each of its entries and attributes. According to the OpenLDAP documentation, it appears that the entries containing the configuration of a tree are contained in ''olcDatabaseConfig''-type entires, and that the ''DN'' (distinct name) of the tree is contained in the ''olcSuffix'' attribute. We will therefore display the data of the tree ''cn=config'' in applying the corresponding filter. To understand the filter syntax of ''ldapsearch'', please see [[http://download.oracle.com/docs/cd/E19199-01/816-6696-10/cmdline.html#LDAP%20Search%20Filters|LDAP Search Filters by Oracle]]. This command will display information on our tree's configuration (replace ''gandi101'' and ''fr'' as appropriate): ldapsearch -Y EXTERNAL -H ldapi:// -b cn=config "(&(objectClass=olcDatabaseConfig)(olcSuffix=dc=gandi101,dc=fr))" The above command should produce results like the following: SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 # extended LDIF # # LDAPv3 # base with scope subtree # filter: (&(objectClass=olcDatabaseConfig)(olcSuffix=dc=gandi101,dc=fr)) # requesting: ALL # # {1}hdb, config dn: olcDatabase={1}hdb,cn=config objectClass: olcDatabaseConfig objectClass: olcHdbConfig olcDatabase: {1}hdb olcDbDirectory: /var/lib/ldap olcSuffix: dc=gandi101,dc=fr olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=gandi101,dc=fr" write by * none olcAccess: {1}to dn.base="" by * read olcAccess: {2}to * by self write by dn="cn=admin,dc=gandi101,dc=fr" write by * read olcLastMod: TRUE olcRootDN: cn=admin,dc=gandi101,dc=fr olcRootPW: {SSHA}7j9LqSeTlwiWkODSi8dCpK1AUtfbMy/j olcDbCheckpoint: 512 30 olcDbConfig: {0}set_cachesize 0 2097152 0 olcDbConfig: {1}set_lk_max_objects 1500 olcDbConfig: {2}set_lk_max_locks 1500 olcDbConfig: {3}set_lk_max_lockers 1500 olcDbIndex: objectClass eq olcDbIndex: cn pres,sub,eq olcDbIndex: sn pres,sub,eq olcDbIndex: uid pres,sub,eq olcDbIndex: displayName pres,sub,eq olcDbIndex: default sub olcDbIndex: uidNumber eq olcDbIndex: gidNumber eq olcDbIndex: mail,givenName eq,subinitial olcDbIndex: dc eq # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1 In this entry, we are primarily interested in the three ''olcAccess'' attributes and their respective values. In particular: * ''to *'' (on the whole tree) * ''by self write'' (when your authentication corresponds to a directory entry, you have write permissions on this object) * ''by dn="cn=admin,dc=gandi101,dc=fr" write'' (the administrator possesses write permissions on the whole tree) * ''by * read'' (the world has read access to the tree) As you can imagine, the last part is what poses a problem (''by * read''), which can be replaced by ''by * none''. To do this, we will use another tool in the ''ldap-utils'' package: ''ldapmodify''. **WARNING**: Modifying the configuration of a tree is delicate, especially concerning permissions. One misstep can remove access to the tree. Be careful, and use your own results instead of copying from this tutorial. We are therefore going to modify the ''olcAccess'' attribute. Edit the file ''/etc/ldap/slapd.d/cn=config/olcDatabase={1}hdb.ldif'' by running this command: nano /etc/ldap/slapd.d/cn\=config/olcDatabase={1}hdb.ldif Modify the line in question by replacing ''* read'' with ''* none''. Save the modification and close the file. Restart the service: /etc/init.d/slapd restart ===== Create temporary file ===== Run the following command to create our temporary file (again, copy and paste from your own results and not from this tutorial): cat > changeAccess.ldif << EOF dn: olcDatabase={1}hdb,cn=config changetype: modify delete: olcAccess - add: olcAccess olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=uncertaindomaine,dc=net" write by * none - add: olcAccess olcAccess: {1}to dn.base="" by * read - add: olcAccess olcAccess: {2}to * by self write by dn="cn=admin,dc=uncertaindomaine,dc=net" write by * none - EOF As you can see, the only change is the replacement of "read by none" at the end of the last attribute. Once the file is created (which you should double check for content), you can apply the changes in your database: ldapmodify -c -Y EXTERNAL -H ldapi:/// -f changeAccess.ldif The result should be similar to this: SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 modifying entry "olcDatabase={1}hdb,cn=config" Once this is done, check that anonymous access is extended: ldapsearch -x -c -h localhost -b dc=uncertaindomaine,dc=net The result should be something like: # extended LDIF # # LDAPv3 # base with scope subtree # filter: (objectclass=*) # requesting: ALL # # search result search: 2 result: 32 No such object # numResponses: 1 The "no such object" message indicates that the configuration is correct. The server is saying that there is no such object called uncertaindomaine dc =, dc = net. This is quite logical since the rules prevent anonymous access to this tree. Let us now try connecting as administrator: ldapsearch -c -h localhost -b dc=uncertaindomaine,dc=net -D "cn=admin,dc=uncertaindomaine,dc=net" -W Once you enter the password, you should see something like: # extended LDIF # # LDAPv3 # base with scope subtree # filter: (objectclass=*) # requesting: ALL # # uncertaindomaine.net dn: dc=uncertaindomaine,dc=net objectClass: top objectClass: dcObject objectClass: organization o: UnCertainDomaine dc: uncertaindomaine # admin, uncertaindomaine.net dn: cn=admin,dc=uncertaindomaine,dc=net objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator userPassword:: passwordHashé # search result search: 2 result: 0 Success # numResponses: 3 # numEntries: 2 We see our results. Thus, we can consider the configuration of our tree as good. ===== Configure for Postfix ===== Another configuration change is needed. We will extend the existing schema to accommodate the features of Postfix. While Courier is not going to be used as our PO/IMAP server, we will need to use the same LDAP extensions it offers. This will ensure standards compliance (RFC) and portability of our data. apt-get install courier-ldap The first (and last) prompt offers to install the necessary directories for web administration. Since we do not use Courier, you can say no, and just install the minimum. We will extract the gzip, which contains the schema we want, and copy it to the directory containing the ldap schema. gunzip /usr/share/doc/courier-authlib-ldap/authldap.schema.gz cp /usr/share/doc/courier-authlib-ldap/authldap.schema /etc/ldap/schema We will now see a second method to change the configuration of OpenLDAP, namely, slaptest. Before we do this however, we need to know what schema is already included in OpenLDAP. To do so, we will go through the base cn = schema, cn = config in our tree, and limit the review to the cn attribute (Common Name) as this is where the entries for the schema are provided. The result should be easy to understand. Also in order to make the schema more understandable, and let you discover more about the ldapsearch command, we will also use the -LLL option. This will allow us to delete comments and Ldif versions. So our command will be: ldapsearch -Y EXTERNAL -H ldapi:// -b "cn=schema,cn=config" -LLL "(objectClass=*)" cn The results should look something like: SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 dn: cn=schema,cn=config cn: schema dn: cn={0}core,cn=schema,cn=config cn: {0}core dn: cn={1}cosine,cn=schema,cn=config cn: {1}cosine dn: cn={2}nis,cn=schema,cn=config cn: {2}nis dn: cn={3}inetorgperson,cn=schema,cn=config cn: {3}inetorgperson Looking at our results, we can conclude that OpenLDAP includes four patterns in this example configuration, namely core, cosine, nis, and inetorgperson. We also need to add the Courier extension that we just added to the directory ''/etc/ldap/schema'' So let's create a file that will include all these schema (those already present, and the additional Courier). mkdir /tmp/ldapConfig cat > /tmp/ldapConfig/schemaInclude.conf << EOF include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/nis.schema include /etc/ldap/schema/inetorgperson.schema include /etc/ldap/schema/authldap.schema EOF Now run the slaptest command, which will convert the ldif formatted file so it can be included in our configuration. But before that we will actually need to edit the file authldap.schema which contains a small error (at least in my version) . In this file, it describes the purpose of CourierMailAccount type by indicating it may contain an attribute of type mailhost. The description of this attribute, which is just above the code, is commented out. We have two options, remove this attribute CourierMailAccount, or uncomment the section describing this attribute. For purely arbitrary reasons, I chose the latter option. I suggest you to edit the file /etc/ldap/schema/authldap.schema, and remove the # in front of the first 4 Commented lines, the ones describing the attribute. Note that the line that starts with Objects lines: 1.3.6 [...] should be kept. Once the file is edited, run the slaptest command: slaptest -f /tmp/ldapConfig/schemaInclude.conf -F /tmp/ldapConfig This command should normally send you a success message. The slaptest command created an entire tree for us in the /tmp/ldapconfig directory. I encourage you to go to the directory containing your schema and check the content: cd /tmp/ldapConfig/cn=config/cn=schema ls –l You'll notice the presence of a file cn = {x] authldap.ldif (where x is a variable integer in my example, it is 4). We will make some changes to this file. Open it with your preferred editor, for example using one of the following two commands: vi cn={*}authldap.ldif Or nano cn={*}authldap.ldif The first editor (vi) is a very powerful editor, and will be installed by default on any Linux-based machine. As for nano, it is a very intuitive alternative, useful for the uninitiated. It's usually installed by default on Debian and derived distributions (Ubuntu, ...). The navigation is very intuitive (arrows) and editing is as well. However, nano show its limits when you have to make complex changes. An example? You will see the following issue: Line 1 and Line 3, delete the parts {x} (brackets included). In fact, there are numbers that your server will automatically assign in function dependencies, we do not want to comment on that. On the first line, fill in the path name, adding: ,cn=schema,cn=config Now go to the end of the file (with vi, type G, with nano keep pressing the down arrow) We will delete the last seven lines, which our LDAP server will have automatically generated. In VI, just type 7dd. Save and exit (in vi, type :wq). Currently, you have your file cn = {x} authldap.ldif, ready to be imported into your LDAP configuration. To do this, run the ldapadd command, whose syntax is similar to ldapsearch and ldapmodify. ldapadd -Y EXTERNAL -H ldapi:// -f /tmp/ldapConfig/cn=config/cn=schema/cn={4}authldap.ldif Normally, if all goes well, this command should confirm that an entry has been added. We will check it by running the previous command: ldapsearch -Y EXTERNAL -H ldapi:// -b "cn=schema,cn=config" -LLL "(objectClass=*)" cn Normally you should see the authldap schema as output. Now, we need to remove the packages we installed with courier-ldap, namely: apt-get purge –y courier-ldap courier-authlib courier-authlib-ldap courier-base courier-doc We shall cover the configuration of SSL in our directory later. Why not do it now? Well, if you choose a Gandi certificate rather than a self-signed certificate (and you should), it will have to send email to the address admin@domaine.tld. This will not exist before our server is fully installed. ===== Prepare for Postfix ===== Now, before you install Postfix, we will create entries for the email addresses that you want to create initially. We decided to use the following configuration for demonstration purposes: vargisj@uncertaindomaine.net vargisj@uncertaindomaine.com vargisj@uncertaindomaine.org These three addresses are the same. That is, we want to be able to connect with the login of these three addresses, and have the e-mails they are sent go to the same mailbox. To configure this, we will create three different email accounts, but all with the same directory for storing messages. I could choose to have several mail attribute details per entry (which works fine), the only concern is that for consistency, with a tree deployed, I prefer to have a separate entry for each mail account to expose the list of existing emails. admin@uncertaindomaine.net admin@uncertaindomaine.com This will create a new account for this email address. all@uncertaindomaine.net As its name (all) suggests, this email address is used to send an email to everyone in the tree. So when you send an email to all@uncertaindomaine.net, it will send an email to admin@uncertaindomaine.net, vargisj@uncertaindomaine.net (the other two vargisj do not interest us, since a mail to vargisj@uncertaindomaine.net also automatically sends the mail to the other two). In my main tree, you will notice I created an email tree that will contain everything. Why? Well, because we may have to have other things in our directory. Thus, having an email tree allows us to have better sorting if needed in the future. There are many options for organizing your tree. In this e-mail tree, I chose to have one entry per field. Some people (take the example of iRedAdmin to name one) store all fields in one tree, and all the email accounts in another. My choice was for convenience of working with the LDAP directory. Eventually, I may want to restrict access to this directory by domain, so that the domain users will have read access to data about users in their own domain. If you do not want to be that permissive, we recommend that you have on one side the list of domains, and the list of emails on the other. For each domain, I decided to separate the email accounts of mail aliases. This has no use other than for human readability, in that it is easier when you browse the directory to see if it is an alias or a real account. Note: You will find in my ldif file that for the user's password, the string {SSHA} + cbPM32CCzgLXhxnpSq6W7OJdg7hq ZQD is listed. I recommend you to use this method (it is the password hash of 0000). To generate a hash of the password (so you do not store clear the password of your users), you can use the following command (the second line is what the command returns): slappasswd -s 0000 -h {SSHA} {SSHA}H8v4t6NnK4/rtR3IMwsCIRAgttkJkGZ+ Here's the reulting ldif file, stored in the / (root) directory, and called addingFirstValues.ldif # # Création d'une arborescence mail qui contiendra l'ensemble # dn:dc=mail,dc=uncertaindomaine,dc=net dc: mail o: mail objectClass: top objectClass: dcObject objectClass: organization # # Création des entrées pour les domaines à prendre en charge # Je créée également, dans chaque domaine, une arborescence # mailAlias, et une arborescence mailAccount, afin d'avoir un # meilleur classement # dn:dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net o: uncertaindomainenet dc: uncertaindomaine.net description: virtualDomain userPassword: {SSHA}cbPM32CCzgLXhxnpSq6W7OJdg7hq+zqD objectClass: top objectClass: dcObject objectClass: organization dn:dc=mailAccount,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net dc: mailAccount o: mailAccount objectClass: top objectClass: dcObject objectClass: organization dn:dc=mailAlias,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net dc: mailAlias o: mailAlias objectClass: top objectClass: dcObject objectClass: organization dn:dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net o: uncertaindomainecom dc: uncertaindomaine.com description: virtualDomain userPassword: {SSHA}cbPM32CCzgLXhxnpSq6W7OJdg7hq+zqD objectClass: top objectClass: dcObject objectClass: organization dn:dc=mailAccount,dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net dc: mailAccount o: mailAccount objectClass: top objectClass: dcObject objectClass: organization dn:dc=mailAlias,dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net dc: mailAlias o: mailAlias objectClass: top objectClass: dcObject objectClass: organization dn:dc=uncertaindomaine.org,dc=mail,dc=uncertaindomaine,dc=net o: uncertaindomaineorg dc: uncertaindomaine.org description: virtualDomain userPassword: {SSHA}cbPM32CCzgLXhxnpSq6W7OJdg7hq+zqD objectClass: top objectClass: dcObject objectClass: organization dn:dc=mailAccount,dc=uncertaindomaine.org,dc=mail,dc=uncertaindomaine,dc=net dc: mailAccount o: mailAccount objectClass: top objectClass: dcObject objectClass: organization dn:dc=mailAlias,dc=uncertaindomaine.org,dc=mail,dc=uncertaindomaine,dc=net dc: mailAlias o: mailAlias objectClass: top objectClass: dcObject objectClass: organization # #Création des comptes mails # dn:mail=vargisj@uncertaindomaine.net,dc=mailAccount,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net cn:vargisj@uncertaindomaine.net mail:vargisj@uncertaindomaine.net sn: VARGIS givenName: Julien displayName: Julien VARGIS mailbox: uncertaindomaine.net/vargisj/ homeDirectory: /home/vmail/ objectClass: top objectClass: inetOrgPerson objectClass: CourierMailAccount userPassword: {SSHA}cbPM32CCzgLXhxnpSq6W7OJdg7hq+zqD dn:mail=vargisj@uncertaindomaine.com,dc=mailAccount,dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net cn:vargisj@uncertaindomaine.com mail:vargisj@uncertaindomaine.com sn: VARGIS givenName: Julien displayName: Julien VARGIS mailbox: uncertaindomaine.net/vargisj/ homeDirectory: /home/vmail/ objectClass: top objectClass: inetOrgPerson objectClass: CourierMailAccount userPassword: {SSHA}cbPM32CCzgLXhxnpSq6W7OJdg7hq+zqD dn:mail=vargisj@uncertaindomaine.org,dc=mailAccount,dc=uncertaindomaine.org,dc=mail,dc=uncertaindomaine,dc=net cn:vargisj@uncertaindomaine.org mail:vargisj@uncertaindomaine.org sn: VARGIS givenName: Julien displayName: Julien VARGIS mailbox: uncertaindomaine.net/vargisj/ homeDirectory: /home/vmail/ objectClass: top objectClass: inetOrgPerson objectClass: CourierMailAccount userPassword: {SSHA}cbPM32CCzgLXhxnpSq6W7OJdg7hq+zqD dn:mail=admin@uncertaindomaine.net,dc=mailAccount,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net cn:admin@uncertaindomaine.net mail:admin@uncertaindomaine.net sn: Administrator displayName: Administrator mailbox: uncertaindomaine.net/admin/ homeDirectory: /home/vmail/ objectClass: top objectClass: inetOrgPerson objectClass: CourierMailAccount userPassword: {SSHA}cbPM32CCzgLXhxnpSq6W7OJdg7hq+zqD dn:mail=admin@uncertaindomaine.com,dc=mailAccount,dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net cn:admin@uncertaindomaine.com mail:admin@uncertaindomaine.com sn: Administrator displayName: Administrator mailbox: uncertaindomaine.com/admin/ homeDirectory: /home/vmail/ objectClass: top objectClass: inetOrgPerson objectClass: CourierMailAccount userPassword: {SSHA}cbPM32CCzgLXhxnpSq6W7OJdg7hq+zqD dn:mail=all@uncertaindomaine.net,dc=mailAlias,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net cn:all@uncertaindomaine.net mail:all@uncertaindomaine.net maildrop:admin@uncertaindomaine.net,vargisj@uncertaindomaine.net sn: Everybody displayName: Everybody objectClass: top objectClass: inetOrgPerson objectClass: CourierMailAlias Once you have created your file, you can add it to your directory with the following command: ldapadd -D "cn=admin,dc=uncertaindomaine,dc=net" -W -h localhost -f /root/addingFirstValues.ldif If you succeed, the result will look something like this: adding new entry "dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=mailAccount,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=mailAlias,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=mailAccount,dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=mailAlias,dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=uncertaindomaine.org,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=mailAccount,dc=uncertaindomaine.org,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "dc=mailAlias,dc=uncertaindomaine.org,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "mail=vargisj@uncertaindomaine.net,dc=mailAccount,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "mail=vargisj@uncertaindomaine.com,dc=mailAccount,dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "mail=vargisj@uncertaindomaine.org,dc=mailAccount,dc=uncertaindomaine.org,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "mail=admin@uncertaindomaine.net,dc=mailAccount,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "mail=admin@uncertaindomaine.com,dc=mailAccount,dc=uncertaindomaine.com,dc=mail,dc=uncertaindomaine,dc=net" adding new entry "mail=all@uncertaindomaine.net,dc=mailAlias,dc=uncertaindomaine.net,dc=mail,dc=uncertaindomaine,dc=net" If you hit errors (everyone does, it's ok), you might need to reset to default and try again. Here's a useful command to do that (adjust it to your particular tree): ldapdelete -D "cn=admin,dc=uncertaindomaine,dc=net" -W -h localhost -v -r "dc=mail,dc=uncertaindomaine,dc=net" This command will be useful in the sense that it will remove your email tree and all its contents. In fact, if you have errors in your file, and you correct them and then run ldapadd, it will return an error stating that you could not create the entry email, which already exists. Ok, that's all for now...