Some Notes on Replicating OpenDirectory to OpenLDAP
I did some work on a contract recently that involved creating an OpenLDAP replica of an OpenDirectory database. Here’s what I learned:
All of these notes assume you’re setting up an LDAP replica on OpenLDAP running with cn=config configuration. I did this on Ubuntu 10.04, and many commands include Ubuntu- or Debian-specific assumptions. Translating to slapd.conf or to, say, Redhat Enterprise Linux is left as an exercise. Obviously, most of this is not safe to apply to an existing OpenLDAP server and there are a few places where we step outside of Apple’s comfortable padded box on the OpenDirectory side, too. I’ve tried to point those out, but try this at your own risk.
Directory Access
You can use ldapsearch and ldapmodify and so on to manipulate and search the OpenDirectory master. Apple configures slapd to allow access to the cn=config tree to anyone who connects via ldapi://%2fvar%2frun%2fldapi, even “anonymously”. For example, to read the cn=config entry you’d use
master$ sudo ldapsearch -x -H ldapi://%2fvar%2frun%2fldapi -b cn=config \
-s base '*' '+'
Passwords
“Open Directory” passwords live in Apple Password Server, which I didn’t try to replicate over, rather than in the directory. For users who should be able to authenticate against the replica, I switched their passwords to Crypt passwords in Workgroup Manager. This has all of the downsides of Crypt password storage: 8-character limit, weak digest, and so on.
Open Questions
Does Workgroup Manager use the moral equivalent of ldappasswd(1) when setting users’ passwords? If so, configuring “Crypt” passwords to use salted SHA instead may be a matter of changing olcPasswordHash to {SSHA}. We weren’t brave enough to try.
Certificates
On the OpenDirectory master, I generated a self-signed “SSL Server” cert with a long expiry (ten years) and configured OpenDirectory to use it for SSL. The resulting .pem file is named after the server (ldap.example.com) and lives in /etc/certificates/ldap.example.com.A REALLY LONG HEX STRING.cert.pem. You can find the exact name by looking at the olcTLSCertificateFile entry in cn=config. If you’re using SSL for replication (and you should be), grab a copy of this file and put it on the replica:
master$ scp /etc/certificates/ldap.example.com.*.cert.pem \
replica:/tmp/ldap.example.com_cert.pem
and
replica$ sudo cp /tmp/ldap.example.com_cert.pem /etc/ssl/certs/
Replication Provider
OpenDirectory compiles syncrepl directly into slapd, for use with OpenDirectory replica servers. However, you can abuse that support to provide replication to OpenLDAP as well. You’ll need to add the syncrepl configuration to your directory manually. Here’s the LDIF I used:
master$ sudo ldapadd -x -H ldapi://%2fvar%2frun%2fldapi <<'SYNCREPL'
dn: olcOverlay=syncprov,olcDatabase={1}bdb,cn=config
objectClass: olcSyncProvConfig
olcOverlay: syncprov
olcSpCheckpoint: 100 10
olcSpSessionlog: 100
SYNCREPL
You can use any of the syncrepl provider configuration options here.
Open Questions
This configuration uses basic syncrepl. In theory delta syncrepl should work as well, but I was trying to make as few changes to the OpenDirectory server as possible.
It’s unclear what changes in Server Admin will blow away the syncrepl overlay, but I suspect setting up a real OpenDirectory replica may affect this config.
Schemata
Hoo boy.
OpenDirectory’s directory server is a patched version of OpenLDAP. The patches include baked-in support for a handful of attribute types and object classes, which are omitted in Apple’s apple.schema and apple_auxiliary.schema files. I opted to use Apple’s schema files as-is to create the cn=schema,cn=config subtree:
master$ mkdir ~/schema master$ cp /etc/openldap/schema/*.schema ~/schema master$ cat > ~/schema/extensions.schema <<'EXTENSIONS_SCHEMA' attributetype ( 1.3.6.1.4.1.63.1000.1.1.2.16.1 NAME 'authAuthority' DESC 'password server authentication authority' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributetype ( 1.3.6.1.4.1.63.1000.1.1.1.21.1 NAME 'apple-acl-entry' DESC 'acl entry' EQUALITY caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) objectclass ( 1.2.840.113556.1.3.23 NAME 'container' STRUCTURAL MUST cn ) EXTENSIONS_SCHEMA
Looking at OpenDirectory’s cn=schema,cn=config shows that Apple uses only nine schema files (and one of them is empty, so I omitted it). Use slaptest to convert the .schema files to a cn=schema directory:
master$ cat > ~/schema/convert.conf <<CONVERT_CONF include $HOME/schema/core.schema include $HOME/schema/cosine.schema include $HOME/schema/nis.schema include $HOME/schema/inetorgperson.schema include $HOME/schema/misc.schema include $HOME/schema/samba.schema include $HOME/schema/fmserver.schema include $HOME/schema/extensions.schema include $HOME/schema/apple_auxillary.schema include $HOME/schema/apple.schema CONVERT_CONF master$ mkdir ~/schema/output master$ slaptest -f ~/schema/convert.conf -F ~/schema/output
This converts the whole configuration file into a cn=config tree, but we’re only interested in the cn=schema,cn=config subtree:
master$ (cd ~/schema/output/cn\=config/ && \
tar czf ~/cn_schema.tar.gz cn\=schema)
master$ scp ~/cn_schema.tar.gz replica:/tmp/
On the replica, we’ll need to blow away OpenLDAP’s default schemata and replace them:
replica$ sudo -i # Yes. replica# service slapd stop replica# cd /etc/ldap/slapd.d/cn\=config/ replica# rm -rf cn\=schema replica# tar xzf /tmp/cn_schema.tar.gz replica# chown -R openldap:openldap cn\=schema replica# chmod -R g+rX cn\=schema # Files 0640, dirs 0750 replica# service slapd start replica# exit
If slapd fails to start, run it in debug mode as root to see why:
slapd -h 'ldap:/// ldapi:///' -g openldap -u openldap \
-F /etc/ldap/slapd.d/ -d 5
If I’ve omitted a schema element, or if you need to recover a schema element from the master, use the following query:
master$ sudo ldapsearch -x -H ldapi://%2fvar%2frun%2fldapi \
-b cn=Subschema -s base '*' '+' | less
The output will include many entries of the form
attributeTypes: ( 1.3.6.1.4.1.63.1000.1.1.2.16.2 NAME 'authAuthority' DESC 'pa ssword server authentication authority' EQUALITY caseExactMatch SUBSTR caseEx actSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
and
objectClasses: ( 1.2.840.113556.1.3.23 NAME 'container' STRUCTURAL MUST cn )
These are easy to convert to OpenLDAP schema entries. (In fact, go back and look at the contents of extensions.schema – these two entries should look familiar.) Find the ones you’re looking for, add them to extensions.schema, regenerate the schema directory as above, and blow away and replace the replica’s cn=schema,cn=config tree with the updated version.
Replication Consumer
Once the schemata are reasonably sane and slapd starts properly with them installed, we can create the replica. We’ll also need to create a database to hold it; we can do both in one step.
replica$ sudo ldapadd -Y EXTERNAL -H ldapi:/// <<'REPLICA'
dn: olcDatabase=hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcSuffix: dc=example,dc=com
olcDbDirectory: /var/lib/ldap
olcRootDN: uid=diradmin,cn=users,dc=example,dc=com
olcRootPW: DIRADMIN_PASSWORD
olcDbConfig: set_cachesize 0 2097152 0
olcDbConfig: set_lk_max_objects 1500
olcDbConfig: set_lk_max_locks 1500
olcDbConfig: set_lk_max_lockers 1500
olcDbIndex: objectClass eq
olcDbIndex: uid eq
olcDbIndex: cn eq
olcDbIndex: member eq
olcDbIndex: entryUUID eq
olcLastMod: TRUE
olcDbCheckpoint: 512 30
olcAccess: to attrs=userPassword
by dn="uid=diradmin,cn=users,dc=example,dc=com" manage
by anonymous auth
by self read
by * none
olcAccess: to dn.base=""
by dn="uid=diradmin,cn=users,dc=example,dc=com" manage
by users read
by * none
olcAccess: to *
by dn="uid=diradmin,cn=users,dc=example,dc=com" manage
by users read
by * none
olcSyncRepl: rid=100
provider=ldaps://ldap.example.com/
bindmethod=simple
binddn="uid=diradmin,cn=users,dc=example,dc=com"
searchbase="dc=example,dc=com"
credentials=DIRADMIN_PASSWORD
schemachecking=off
type=refreshAndPersist
retry="60 +"
interval="00:00:10:00"
tls_cacert="/etc/ssl/certs/ldap.example.com_cert.pem"
REPLICA
Replication will use the diradmin login you set up when you created the OpenDirectory master. Obviously, you can use a different user, but if you want passwords to be replicated that user needs to be a directory administrator.
The interval and retry settings can be tweaked; we’ve found that ten minute refresh intervals plus one minute retries on failure are a reasonable balance of currency and bandwidth use. If you need to force an immediate refresh for any reason, restart slapd on the replica.
The ACL given by the olcAccess attributes allows users to authenticate against the replica and read information from it, but disallows anonymous access and changes (except to the root DN for the database, which provides an escape hatch if you need to fix something by hand).
The database should replicate over immediately. If it doesn’t, start slapd up in debug mode (see above) and look at the errors. In particular, if you see a message similar to
syncrepl_message_to_entry: rid=100 mods check (objectClass: value #0 invalid per syntax)
it means you’re missing some schema entries. The DN of the object it was trying to replicate is on the preceeding line that looks like
<<< dnPrettyNormal: <cn=users,dc=example,dc=com>, <cn=users,dc=example,dc=com>
and you can check the affected attributes against the OpenDirectory master.
Open Questions
The same remark about delta syncrepl applies here, too.
Testing
If you have a user in your OpenDirectory master, you can test the replica by running searches against it:
replica$ ldapsearch -x -W -D uid=user,cn=users,dc=example,dc=com \
-b dc=example,dc=com '(uid=user)'
This should prompt you for the user’s password, then print back the user’s entry.
PAM and NSS Notes
OpenDirectory’s extensions sit on top of a mostly-normal RFC 2307 directory structure. Users are inetOrgPerson, posixAccount, shadowAccount objects, with some ancillary schemata to support the Apple features. The subtrees for users, groups, and so on are named cn=users rather than ou=users as in the RFC, so you may have to twiddle ldap.conf to recognize the correct subtrees.
OS X home directories are usually in /Users, not /home. It’s not really worth arguing with it; just create /Users home directories on your linux client boxes as well.
Again, only users with Crypt passwords in the OpenDirectory master will be able to use the replica for authentication.
4 Comments
Other Links to this Post
RSS feed for comments on this post. TrackBack URI

By Darius, November 25, 2010 @ 12:05 pm
Hey,
I know you wrote that you had to change the password type to crypt but did you hear of a way to work with this if you wanted to keep the apple password server for this purpose.
By Owen, November 25, 2010 @ 2:35 pm
Nope. As far as I know, Apple Password Server is some combination of Kerberos and SASL, with some proprietary extensions. I know approximately nothing about either of these things, and didn’t feel like exploring too enthusiastically on someone else’s dime (this was a contract job originally).
By alley, May 2, 2011 @ 4:58 pm
danke für den interessanten artikel.
By Bryan, May 24, 2011 @ 12:30 pm
Btw. changing olcPasswordHash to {SSHA} works.
Any crypted passwords will be inserted as a SSHA hash
You can even trick the schema by adding a 3rd authAuthority of ;basic; which allows you to have the SSHA password in userPassword and the password server authority for everthing else. (However adding basic breaks the web based password change page that apple includes because their code sucks)