📜 ⬆️ ⬇️

GoogleApps + Postfix + Fetchmail (OpenLdap + Postfix)

Prehistory

Implementation

Platform
AltLinux 4, kernel version 2.6.18-std-smp-alt6. All packages were made from the official repository.
Install LDAP server
Install the openldap-servers-2.3.35-alt0, libldap2.3-2.3.35-alt0, openldap-clients-2.3.35-alt0, openldap-2.3.35-alt0, openldap-doc-2.3.35-alt0 packages.
We include additional schemas in the /etc/openldap/slapd.conf file:
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/courier.schema
include /etc/openldap/schema/qmail.schema
allow bind_v2
concurrency 20
gentlehup on
sizelimit -1
password-hash {CLEARTEXT}
pidfile /var/run/slapd.pid
argsfile /var/run/slapd.args
replica-pidfile /var/run/slurpd.pid
replica-argsfile /var/run/slurpd.args
rootDSE /etc/openldap/rootdse.ldif
access to dn.exact=""
by * read
access to dn.subtree="cn=Subschema"
by * read
access to attrs=userPassword
by self write
by anonymous auth
by * none
modulepath /usr/lib/openldap
moduleload back_hdb.la
moduleload back_monitor.la
moduleload back_null.la
include /etc/openldap/slapd-hdb-db01.conf

Register our new ldap database in slapd-hdb-db01.conf:
database hdb
suffix "dc=your,dc=ru"
rootdn "cn=admin,dc=your,dc=ru"
rootpw 123
directory /var/lib/ldap/bases/your.ru
index objectClass eq
index uid pres,eq,sub
index cn pres,eq,sub,subany
access to attrs=userPassword
by self write
by anonymous auth
by * none
access to *
by dn="cn=admin,dc=your,dc=ru" write
by * read

If you plan to publish the database to the outside, then configure the interface that our Ldap server / etc / sysconfig / ldap will listen on (by default 127.0.0.1):
SLAPDURLLIST="ldap://servername.your.ru/"
SLAPD_OPTIONS=""
SLURPD_OPTIONS='-t /'
We start the demon:
service slapd start
Then our base should be created in /var/lib/ldap/bases/your.ru
Filling user base
If there is already an existing domain base, then it is possible to unload it into a text CSV file and parse it using AWK to the ldif file ready for import. Anyway, it is most convenient to create a text file with a list of users, and then use the AWK script to convert it to ldif, automatically generating user passwords. Thus, you will have a script and a backup copy of the Ldap database. Here is an example of the CSV file format for uploading from Active Directory:
"DN","objectClass","ou","distinguishedName","instanceType","whenCreated","whenChanged","uSNCreated", "uSNChanged","name","objectGUID","objectCategory","dSCorePropagationData","cn","sn","displayName", "proxyAddresses","altRecipientBL","targetAddress","mAPIRecipient","mailNickname","internetEncoding", "legacyExchangeDN","textEncodedORAddress","mail","msExchPoliciesIncluded","msExchALObjectVersion", "msExchHideFromAddressLists","givenName","altRecipient","department","homeMTA","homeMDB", "mDBUseDefaults","userAccountControl","codePage","countryCode","pwdLastSet","primaryGroupID", "objectSid","accountExpires","sAMAccountName","sAMAccountType","showInAddressBook","userPrincipalName", "msExchHomeServerName","msExchMailboxSecurityDescriptor","msExchUserAccountControl","msExchMailboxGuid", "member","groupType","badPwdCount","badPasswordTime","lastLogoff","lastLogon","userParameters","logonCount", "lastLogonTimestamp","gPLink","gPOptions","userCertificate","adminCount","msNPAllowDialin","title", "physicalDeliveryOfficeName","telephoneNumber","initials","postOfficeBox","company","deliverAndRedirect", "memberOf","scriptPath","localPolicyFlags","operatingSystem","operatingSystemVersion", "operatingSystemServicePack","dNSHostName","servicePrincipalName","isCriticalSystemObject","location","flags", "uNCName","versionNumber","serverName","portName","driverName","priority","printStartTime","printEndTime", "printBinNames","printMaxResolutionSupported","printOrientationsSupported","printCollate","printColor", "printShareName","printSpooling","printKeepPrintedJobs","driverVersion","printMaxXExtent","printMaxYExtent", "printMinXExtent","printMinYExtent","printMediaSupported","printerName","url","shortServerName", "printDuplexSupported","printLanguage","printStaplingSupported","printMemory","printRate","printRateUnit", "printMediaReady","printNumberUp","printPagesPerMinute","description","deletedItemFlags","submissionContLength", "garbageCollPeriod","msExchRequireAuthToSendTo","homePhone","otherTelephone","mobile", "showInAdvancedViewOnly","keywords","serviceClassName","serviceDNSName","serviceDNSNameType", "mS-SQL-Name","mS-SQL-RegisteredOwner","mS-SQL-Contact","mS-SQL-Location","mS-SQL-Memory","mS-SQL-Build", "mS-SQL-ServiceAccount","mS-SQL-CharacterSet","mS-SQL-SortOrder","mS-SQL-UnicodeSortOrder","mS-SQL-Clustered", "mS-SQL-NamedPipe","mS-SQL-MultiProtocol","mS-SQL-SPX","mS-SQL-TCPIP","mS-SQL-AppleTalk","mS-SQL-Vines", "mS-SQL-Status","mS-SQL-LastUpdatedDate","mS-SQL-InformationURL","mS-SQL-GPSLatitude","mS-SQL-GPSLongitude", "mS-SQL-GPSHeight","mS-SQL-Keywords","mSMQSites","mSMQServiceType","mSMQOSType","mSMQEncryptKey","mSMQSignKey", "mSMQDependentClientServices","mSMQRoutingServices","mSMQDsServices","mS-SQL-Description","mS-SQL-Alias", "mS-SQL-Size","mS-SQL-CreationDate","mS-SQL-LastBackupDate","mS-SQL-LastDiagnosticDate","mS-SQL-Applications","msRRASAttribute","mS-DS-CreatorSID","rIDSetReferences","delivContLength","autoReplyMessage","reportToOriginator","reportToOwner", "oOFReplyToOriginator","mSMQSignCertificates","mSMQDigests"

Here is an example of an AWK script to process it:
##

BEGIN {
FS=",";
##
userCounter = 0;
}
function pass(name)
{
return substr(name,1,1)""int(rand()*100000);
}
function trim(v)
{
## Remove leading and trailing spaces (add tabs if you like)
sub(/^ */,"",v);
sub(/ *$/,"",v);
return v;
}
##
{
num = 1;
for(i=1; i<= NF; i++)
{
if($(i)~/\"/)
{
rez[num] = $(i);
for(j=i+1; j<= NF; j++)
{
rez[num]= rez[num]","$(j);
if($(j)~/\"/)
{
i =j;
break;
}
}
gsub(/\"/, "", rez[num]);
}
else rez[num] = $(i);
num+= 1;
}

if(rez[2]=="user")
{
mail = rez[25];
split(substr($1, 5, length($1)), fio, "/");
if(rez[21]!= "")
{
userdn = "uid="rez[21]""substr(rez[1], length($1), length(rez[1]));

## second name
i = 1;
while(i > 0)
{
if(i+1 in fio)
{
i++;
}
else
{
name = trim(fio[i]);
split(name, aname, " ");
if(2 in aname)
{
second_name = aname[2];
}
else
{
second_name = "null";
}
if(3 in aname)
{
second_name = second_name""aname[3];
}
delete aname;
break;
}
}
print "dn: cn="rez[21]",ou=People,dc=your,dc=ru\nobjectClass: inetOrgPerson\nobjectClass: organizationalPerson\nobjectClass: person\nobjectClass: qmailUser\nobjectClass: CourierMailAccount\nobjectClass: top\naccountStatus: active\ncn: "rez[21]"\nemployeeType: \ngidNumber: 100\nhomeDirectory: /var/spool/maildir\nmail: "mail"\nmailAlternateAddress: "rez[21]"@servername.your.ru\nmailAlternateAddress: "rez[21]"@your.ru\nmailMessageStore: /var/spool/maildir/"rez[21]"/\no: your.ru\nsn: "name"\nuid: "name"\nuidNumber: "userCounter+1000"\nuserPassword: "pass(rez[21])"\n";
userCounter += 1;
}
# uidNumber: 99 nobody
}
}

At once I will say that I used Windows ports of awk utilities (http://gnuwin32.sourceforge.net/packages/gawk.htm), so this script was not tested under Linux. Be careful with the translation of the string in the file when importing to the server. I used JExplorer as a browser and directory editor, this utility did not cause any complaints, it can do everything, including exporting and importing directory branches into .ldif files, the only thing is that it is written in Java. In principle, I heard that you can put PhpLdapAdmin, but I did not succeed in this.
Postfix installation
Install the postfix-cyrus-2.3.11-alt1, postfix-control-1.6.1-alt1, postfix-2.3.11-alt1, postfix-ldap-2.3.11-alt1, cyrus-sasl2-2.1.22, libcourier- packages authlib-0.59.1-alt1.0, courier-imap-utils-4.1.2-alt1, courier-imap-4.1.2-alt1, courier-authlib-0.59.1-alt1.0, courier-authlib-ldap- 0.59.1-alt1.0, procmail-3.22-alt7. Configuring postfix:
#/etc/postfix/main.cf

mailbox_command = /usr/bin/procmail -a $DOMAIN -d $LOGNAME
myhostname = servername.your.ru
#
local_transport = virtual
virtual_transport = virtual
virtual_mailbox_domains = your.ru
#
virtual_mailbox_base = /var/spool/maildir
virtual_mailbox_maps = ldap:/etc/postfix/ldapvirtual.cf
virtual_uid_maps = static:999
virtual_gid_maps = static:12
virtual_mailbox_limit = 0
message_size_limit = 20480000
relayhost =
transport_maps = cdb:/etc/postfix/transport
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
#
smtpd_recipient_restrictions = permit_sasl_authenticated, reject
smtpd_client_restrictions = permit
unknown_local_recipient_reject_code = 550
mynetworks = 192.168.0.0/24

I use the maildrop mailbox format (each letter is a separate text file in the mailbox folder). User boxes are created by themselves when they receive the first letter and subject to the permission to write to the maildir directory to the user under whom postfix runs.
#/etc/postfix/ldapvirtual.cf

server_host = servername.your.ru
server_port = 389
bind = yes
bind_dn = cn=admin,dc=your,dc=ru
bind_pw = 123
# ,
search_base = ou=People,dc=your,dc=ru
query_filter = (&(mail=%s)(objectClass=CourierMailAccount)(AccountStatus=active))
result_attribute = uid
result_format = %u/

#/etc/postfix/transport

your.ru :
.your.ru :
servername.your.ru :
* smtp:[mail.your_provider.ru]

Now compile this transport scheme with the command
postmap transport
And update the configuration team
postfix reload
In the next series, setting up courier-imap and authorization when you receive mail.

')

Source: https://habr.com/ru/post/62196/


All Articles