Published on MacDevCenter (
 See this if you're having trouble printing code examples

Open Directory and Active Directory, Part 1

by Michael Bartosh

Editor's Note: For the last number of months, Michael Bartosh has been working on a series of articles for Mac DevCenter readers which examines Mac OS X's Directory Services architecture in depth and explores how to integrate these services with Microsoft's Active Directory. We're looking at three, maybe four installments that will run about 10 days apart. These articles represent a tremendous amount of work, and I want to be the first to thank him for this tremendous effort. Michael will also be sharing his knowledge in person at the O'Reilly Mac OS X Conference in his session titled, Mac OS X and Active Directory: A Study in Directory Integration. If you haven't registered for this event yet, this article will give you a good idea of the quality content that will be presented there.

Mac OS X marks a significant first for Apple, an enterprise-capable operating system. Built from the ground up based on open standards with powerful Unix-like underpinnings, it's moving Apple further into the infrastructures of business and academic computing than ever before. Critical to this trend is its ability to make use of enterprise directories, that is, centralized network repositories for users, groups, security policy and other administrative data. Due to its ubiquitous nature, Microsoft's Active Directory plays a particularly important role.

Mac OSX Conference

Session by Michael Bartosh:
Mac OS X and Active Directory: A Study in Directory Integration

Participants in this session will be exposed to Mac OS X's directory services infrastructure in depth, and will learn to leverage its capabilities to maximize end user satisfaction while minimizing impact on enterprise systems. While Active Directory is the primary example, these strategies are applicable to almost any directory service.

O'Reilly Mac OS X Conference
October 27-30, 2003
Santa Clara, CA

Mac OS X's integration into Active Directory is an interesting phenomenon since it's not a product of any formalized cooperation between Apple and Microsoft. Rather, it's a product of open standards, the product of two vendors conforming to an established specification for directory services protocols. Out of this ecosystem, rich IT infrastructures evolve. End users and IT managers alike can take advantage of Mac OS X's robust feature set while utilizing their enterprise directory data and providing a single sign on for both Windows and Mac environments.

However, cross platform directory services are complex, and planning and implementing integration between Active Directory and Mac OS X has proven to be a formidable challenge for both Windows and Mac administrators. Although it's easy to prototype a generalized infrastructure, adopting that infrastructure to sophisticated, deployed environments is difficult without a good understanding of directory services in general, Active Directory, and the capabilities and data requirements of Mac OS X.

Rather than provide a cookie-cutter recipe for Directory Services integration, this series of articles seeks to examine Mac OS X's Directory Services architecture in depth, providing a solid conceptual framework on which the reader may build services that minimize impact on existing infrastructure while still providing a good end user experience. While our deployment target will be Active Directory, the more general architectural features and capabilities can be easily applied to other environments as well.

Active Directory integration has been fundamentally changed in Panther, Mac OS X 10.3. We're working with Apple right now in order to determine what we can say and when we can say about it. Beyond the NDAs, though, Jaguar is still very relevant. Apple's OS releases tend to be wide in scope, resulting in a significant lag between introduction and deployment while support infrastructures are updated. In many larger environments, Panther won't be rolled out until spring or summer of 2004. Because of this, Jaguar maintains its importance.

Open Directory

In order to understand Mac OS X's place in an enterprise directory, we first need to understand its capabilities, processes and configuration. Apple's Directory Services Architecture is known as Open Directory. You can think of Open Directory as Mac OS X's Rosetta Stone. Open Directory knows how to talk to LDAP directories so that specific Mac OS X applications (like Apache or loginwindow) don't have to. In a very general sense, the process looks something like this:

Fig 1.1 Open Directory

Open Directory can be accessed both via traditional libc calls (getpwnam(), gethostbyname(), etc) and also via the Directory Service framework, which is documented here (although some portions of that documentation appear to be out of date).

More specifically, Open Directory has a dual name service architecture; that is, requests may be serviced by one of two specific subsystems, lookupd or DirectoryService. libc requests are dispatched to lookupd while the Directory Service API communicates with DirectoryService (a daemon designed to integrate with directory services...the naming can be quite circular).

In NextStep 1.0 there was only lookupd. NeXT, opting to store its administrative data in a directory (NetInfo) rather than the traditional Unix flat files, knew that there should be a flexible, modular method for supporting lookups, so that administrative data might not always be stored in NetInfo. Out of this specification, lookupd was born. It could reply to queries based on data from a number of backing stores, including NetInfo, flat files, NIS, DNS and (eventually) LDAP. Each backing store had, and has, an associated agent, which could be configured for use based on the query type. lookupd has been steadily improved over the years and was overhauled for NextStep 3.3. Since then, it has remained mostly unchanged and currently has an extensive man page.

lookupd had some limitations, though. Designed in a time when libc calls expected to return full user records -- including crypt() passwords -- it has no specific authentication support. It is, additionally, a read-only architecture. While this is the norm for libc interfaces, it makes sense that in a world of evolving directory services to support write operations. Finally, lookupd is relatively difficult to extend. While third party lookupd agents were written, they were the exception rather than the rule.

DirectoryService was designed to meet these limitations. It's highly extensible and licensed as open source. Its API is well documented and supports write operations as well as multiple authentication methods. Due to these features, DirectoryService is the primary method for accessing enterprise directories. Apple has chosen to continue support of lookupd, presumably to maintain the stability of libc, on which much of the OS relies. The resulting architecture looks like this:

Fig 1.2 Open Directory architecture

In order for libc clients (most cross platform Unix utilities: for instance sshd, ls, pwd, etc.) to access DirectoryService data, Apple built a specialized lookupd agent, DSAgent, beginning in 10.1. DSAgent uses the DirectoryService API to provide access to enterprise directories to lookupd clients, including libc. Because lookupd has no authentication support, libc clients must be pam-enabled. pam, in turn, is able to access DirectoryService authenticating methods, like dsDoDirNodeAuth. This isn't the end of the story, however. lookupd is still Mac OS X's resolver, so host resolution (gethostby*()) will generally be answered by its FFAgent or DNSAgent. In addition, lookupd will, for performance reasons, query the local NetInfo directory itself rather than dispatch that query to DSAgent (and hence DirectoryService) although this behavior is configurable.


lookupd is configured manually and is able to store its configuration data in either netinfo or flat files. This is described accurately in its man page and is not covered here, due to DirectoryService's primary role in access of enterprise directories. DirectoryService and its associated plugins generally store their configuration in individual XML based files within the /Library/Preferences/DirectoryService directory.

[sinister:~] tarbosh% ls /Library/Preferences/DirectoryService/
        ContactsNodeConfig.plist DirectoryService.plist
        ContactsNodeConfigBackup.plist SearchNodeConfig.plist
        DSLDAPPlugInConfig.clpi SearchNodeConfigBackup.plist
SearchNodeConfig.plist preferences for OS Authentication path
DirectoryService.plist tracks which plug-ins are active
DSLDAPPlugInConfig.clpi LDAPv2 plug-in configuration
DSLDAPv3PlugInConfig.plist LDAPv3 plug-in configuration
ContactsNodeConfig.plist preferences for OS contact path

Fig 1.3 Config file sample DirectoryService configuration files

These files will usually be maintained by the Directory Access application, which lives in /Applications/Utilities on a default Mac OS X install. Directory Access Interface consists of 3 panes: Services, Authentication, and contacts.

Fig 1.4 Directory Access Service pane.

The services pane allows an administrator to configure the host's DirectoryService plugins to access to various directory services. A default 10.2.5 install includes NetInfo, LDAPv3, LDAPv2, and "BSD Configuration Files" (which allows DirectoryService rather than lookupd to access flat files in /etc). 10.2.6 added NIS as an option. Notice that there are also plugins not associated with directories, like Rendezvous, SMB, AppleTalk, and SLP. These are service discovery mechanisms. In addition to supplying access to directories, Open Directory also supports service discovery. We won't concern ourselves with this aspect of its functionality, since, again, our focus is directories. Each plugin, all of which are located at /System/Library/Frameworks/DirectoryService.framework/Resources/Plugins may have a plugin-specific configuration dialog:

Fig 1.5 NetInfo Plug-In configuration dialog.

This reference isn't meant to be exhaustive so we do not detail the configuration options for all plugins. The LDAPv3 plugin will be covered in some depth in a later article, since it is our primary mechanism for accessing Active Directory. A few concepts are important, though:

  1. With the exception of the NetInfo plugin, configuration data is stored in a corresponding file in /Library/Preferences/DirectoryService
  2. Each plugin is capable of accessing one or more external directories. Each external source of data is known as a node. Specifically, the LDAPv2 and LDAPv3 plugins are capable of accessing multiple nodes (directories) simultaneously. For example, perhaps there are both campus-wide iPlanet Directory ,and departmental Active Directory at a large University. The LDAPv2 and LDAPv3 plugins can both be configured to access both of them. The NetInfo plugin, however, is only capable of accessing one NetInfo hierarchy at a time.
  3. LDAPv2 is a strict subset of LDAPv3, and the LDAPv3 plugin doesn't support the full LDAPv3 specification (for instance, start_tls). Its best, then, to think of the LDAPv3 plugin as a more functional version of it's v2 counterpart, one that includes support for SSL, write operations, and UTF-8 (in addition to a number of features not necessarily associated with LDAP specifications, like static attribute mapping, which we'll discuss later).

The authentication pane allows you to add nodes configured in the services pane to the host's authentication search path. This means that the directory specified in a particular node will be searched by user lookups: getpwnam(), getpwent(), and friends, in addition to their DirectoryService API counterparts. It also implies that user entities that are returned from those lookups may authenticate.

Fig 1.6 Directory Access Authentication tab.

The authentication pane has 3 settings:

  1. Automatic: Make use of nodes delivered automatically via DHCP or broadcast. This is the default setting.
  2. Local Directory: Use only the local directory; don't use any external directory services.
  3. Custom Path: Use nodes explicitly specified in the configuration pane. After configuration in the services pane, you must click add to manually add them to the authentication path.

Fig 1.7 Directory Access: Adding a node to the Custom search path.

In order to allow users from a specific node to login, either locally or via directory enabled services like AppleFileServer, the node must appear in the authentication path. This is due to the granular nature of Open Directory. We'll see later that just because we want to access resources from a particular directory, we may not want users from that directory to be able to login to our host.

Out of box, Mac OS X (through 10.2.6) is configured to automatically locate NetInfo and LDAP search nodes--both of which can be returned via DHCP--and add those nodes to the authentication search path. This makes Mac OS X susceptible from a security standpoint to rogue DHCP and directory servers. A good localization or configuration policy will disable this functionality, unless it is explicitly needed, by specifying the search path as local or custom and by disabling automatic retrieval of configuration data in the NetInfo and LDAPv3 plugins.

The contacts pane allows you to add Directory Service nodes to the contacts path. This permits certain directory enabled applications (namely Mail and Address Book in a default Mac OS X install) to access a globally specified directory data. Contacts are configured separately from Authentication; you might want to search a directory without allowing all of the users from that directory to login to your host.

One final capability of Directory Access is remote configuration of Mac OS X Server. Other than manually editing extensive and mostly undocumented XML files, there is no way in Jaguar to configure DirectoryService or any of its plug-ins via ssh. However, on Mac OS X Server, DirectoryService listens on port 625. Remote clients can connect to the DirectoryService daemon by choosing Connect from the Server menu of Directory access. The resulting dialog

Fig 1.8 logging into Mac OS X Server via Directory Access.

will prompt you for administrative credentials of the remote server. Once authenticated, you'll be able to use Directory Access like you were seated at the console of the server.

Directory Integration

With a functional understanding of Open Directory we can seek to integrate it with Active Directory. We'll work toward this goal using tools included with Mac OS X, including DirectoryService's LDAPv3 plugin and the system's built in kerberos support. However, it's important to at least mention another option. In addition to the DirectoryService plugins that ship with Mac OS X, Apple provides a flexible API for creating more. Thursby Systems, makers of Dave, recently introduced an Active Directory native plugin. You can read about it here.

Among other things, it

  1. uses a machine account to access AD,
  2. uses kerberized LDAP connections to access AD securely, and
  3. requires no schema modification or additional data to work.

In other words, it allows Windows administrators to integrate Macs into the vast majority of Windows infrastructures seamlessly and securely. The downside, of course, is that it's not included with Mac OS X and is not free. Once again it's worth mentioning that Panther supports vastly increased Active Directory integration features, the details of which we'll discuss at a later date.

LDAPv3 plugin based solutions vary widely in detail. There is no one right answer to the question of Directory Integration. The right answer varies according to site specific configuration issues, political climate, and organizational policy. This article series does not concern itself with the basic details of creating or configuring a node. That is discussed in Apple's documentation and here. Instead the focus is on the options you have in integrating a node with Active Directory. In general, that question revolves around two issues: access and data, which I'll delve into in next week's installment.

Michael Bartosh

Return to

Copyright © 2009 O'Reilly Media, Inc.