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

Open Directory and Active Directory, Part 3

by Michael Bartosh

Editor's Note: In this third and final part of Michael Bartosh's series on Mac OS X's Directory Services architecture, he looks at data. If you haven't read part one and two yet, you should probably take a look before reading this final installment. Michael will be a speaker at the O'Reilly Mac OS X Conference in a session called "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.


Once Mac OS X has access to a directory like LDAP, it needs to find certain data in order to recognize users, groups, and any other data you've decided to use. One very fundamental issue is that Active Directory doesn't contain by default some of the user data Mac OS X expects to find in user, group and host records. Mac OS X makes use of directory data by mapping directory attributes to Apple's Directory Service data types.

In general there are several strategies for directory data integration. We'll examine some here.

Using Common Data. When attributes in the directory closely match in purpose and data content the attributes required by Mac OS X, they can be reused. This is the whole purpose behind a directory service. Certain data is common to the operation of various applications. Examples include authentication data, usernames, email address, telephone number, etc.

Static Mapping When data may be identical among all users on a particular machine, it can be statically mapped to a particular value. This means that the directory will not be consulted for this particular attribute. A good example is PrimaryGroupID (which corresponds to RFC 2307's gidNumber and NetInfo's gid). The default value for this attribute on all Mac OS Users is 20, which corresponds to the staff group. Unless your organization has some other gid management strategy, there is no reason to query the directory for this data. A "#" is prepended to static values in the Directory Access application in order to instruct DirectoryService to use that value rather than querying the directory.

Fig 2.3 Directory Access: Static mapping.

The sttatic mapping with variables approach allows you to statically specify most of a variable's value but to take a portion of it from the directory. For instance, #/Network/Servers/ace2/HOMES/$sAMAccountName$ would, for the user shiner, become /Network/Servers/ace2/HOMES/shiner. The implications of this are powerful, virtually freeing you from directory schema modifications. Unfortunately this functionality isn't currently a part of Apple's shipping plugin. Instead, it's included in a modified version of Apple's plugin available here. The plugin is distributed in source form and building it is quite laborious. I've published some instructions here.

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

The upside to this approach is obvious, namely, extra support for clientside functionality without data or schema additions to the directory. The downside, though, is that maintaining the software between releases (relying on a patched version of the plugin or having to patch it yourself) can be a maintenance headache and isn't supported by Apple.

Repurposing Unused Attributes AD ships with several hundred attributes, many of which are typically unused. When an unused (empty) attribute matches the equality characteristics of a Mac OS X attribute, it can often be used to hold the data that Mac OS X needs. This is not a ideal solution, since it might become necessary to use that attribute for its intended purpose at some point in time. It is often better than schema extension.

Repurposing Attributes In Use. When attributes in the directory match closely the content required by Mac OS X, but do not serve the same purpose of the Mac OS X attribute, they might be reusable. An example is uSNCreated, which closely matches in value the data required for UniqueID. Using attributes that meet value requirements but support different functions is a risky proposition due to a certain level of uncertainty surrounding maintenance of the value. In specific, uSNCreated should only be used if either there is only one domain controller or if users are always created on the same domain controller.

In general, re-purposing attributes in this way requires an in depth knowledge of the directory, and an understanding of the values that will be stored in the directory natively.

Schema Extension Another option for directory integration is schema extension, in which you extend the structure of AD to support the data types that Mac OS X needs. Schema changes to AD can't be undone in Windows 2000 Server, so this is a step that might have unforeseen consequences. We can also differentiate between supported and unsupported schema additions. Several Microsoft products--for example, Exchange and Services for Unix--modify Active Directory schema. Because these products are supported by Microsoft, their additions are generally well tolerated by AD administrators. In fact, the latter (Services for Unix 3.0) can be of great use during the process of directory service integration. Designed to help Windows administrators provide services to Unix hosts, the SFU package adds several types of data that most Unix operating systems (and hence Mac OS X) need. These attribute names are all prepended with msSFU30. We'll talk about several in depth later.

Unsupported schema modifications, though, are a very unpopular choice for enterprise directory administrators. In our experience it's very rare to find a deployment where such modification is not frowned upon. Additionally, it's common that an organization has policy against schema modification, or that schema modification is tied to a long and tedious committee review process. By far the most common circumstance is that the group managing Mac clients is not the same group that manages the enterprise directory, and the directory management group has little reason to placate the desktop IT group. These issues are not at all specific to Active Directory. Enterprise directories are mission critical parts of infrastructure and should be managed conservatively.

In general, if you plan to modify your schema outside the context of a Microsoft product, it's best to obtain an enterprise number for your organization and make these schema extensions in your own oid space. Discussions of oids and enterprise numbers in depth are beyond the scope of this document, but can be found here (this above refers to openldap but the information on the oid namespace applies to AD as well). You can apply for an oid space here.

Apple shows promise of providing a stable, supported oid space for Apple-specific attributes. Preliminary work can be found on every Mac OS X host at: /etc/openldap/schema/apple.schema. However, this schema should not be used with Active Directory, because it is not yet stable. Note the top lines of this file:

[ace2:/etc/openldap/schema] nadmin% head apple.schema
#ident $Id: apple.schema,v 2002/10/03 00:12:44 jtownsen Exp $
# Preliminary Apple OS X Native LDAP Schema
# This file is subject to change.

Indeed, in the upgrade from 10.2.3 to 10.2.4, the apple-mcxsettings attribute was modified. This wasn't catastrophic by any means, but due to this dynamic nature, we are avoiding Apple's oid space at the moment. Gordon Schukwit, a field sales engineer at Apple, has published a number of scripts and tools for adding Apple's schema to Active Directory here. They are nicely done; once apple.schema has been declared stable, this will be a much more seamless process than creation of your own oid space and attributes.

If schema modification does occur, it should be heavily tested and carried out in a programmatic and systematic manner rather than manually. You should already have a test forest that mimics your deployed configuration. Schema addition procedures should be published, reviewed and tested by independent groups prior to deployment.

The most important attributes for user authentication are the following.

RecordName: attribute used for authentication (legal characters are ASCII "A-Z", "a-z", "0-9", "_" and "-".) May have multiple values and values other than the first may contain UTF-8 Roman text. Max 16 values. In general, this maps to AD's sAMAcountName without any modification, but msSFU30Name is also a suitable match. Additionally, some sites will also map one of RecordName's subsequent values to userPrincipalName, allowing users to log in with the form. This is a strictly required attribute.

UniqueID: Unsigned 32-bit ASCII string of digits 0-9. Range is 100-2147483648. UniqueID is a numerical identifier Unix OS's use to keep track of users and of the files they own. Its presence is strictly required, but this requirement can be met in a number of ways.

  1. uSNCreated: uSNCreated is a standard Microsoft AD attribute which records the Update Sequence Number--a part of the AD replication process--associated with the user's creation. This value in general maps well to the data requirements of UniqueID; that is, it's unique, and it will usually be less than 2147483648. Several sites have deployed this mapping without issue and this Apple documentation recommends it. However there are potential caveats:
    1. different domain controllers keep different sequence numbers. So it's possible there might be a value collision at some point in a multimaster environment. This collision can be avoided, however, if all users are created on the same DC.
    2. Using attributes that meet value requirements but support different functions is a risky proposition due to a certain level of uncertainty surrounding maintenance of the value.
  2. msSFU30UidNumber: Microsoft provides an attribute as a part of its Services for Unix schema that specifically fulfills the requirements of UniqueID. This is a good solution using supported schema extensions for situation when unique, consistent UniqueID's are required.
  3. static: In some cases, UniqueID might be statically mapped, meaning that all users receive the same value. In 10.2.5 a bug exists where statically mapped UniqueID's may not log in. The work around for this (which is unsupported and frowned upon by Apple) is to move aside /System/Library/LoginPlugins/MCX.loginplugin. This actually solves a number of problems with loginwindow crashing mysteriously but disables Mac OS X's managed client capabilities. Apple neither supports nor recommends mapping UniqueID to a static value.

Password: Password expects a DES crypt'd value, which doesn't usually exist in Active Directory. Thus it should be mapped to a blank value (this is the default state of Apple's Active Directory mapping). Unless the user has already authenticated via some other method (usually kerberos) this should result in an LDAP Bind during login. That LDAP bind is used solely to authenticate the user: no directory data is queried during that connection.

We must reiterate the security implications of using LDAP Bind. You should seriously consider using SSL if you're not using Kerberos. Keep in mind if you're using kerberos this should alleviate the need for bind authentication, resulting in a secure login. However, in 10.2-10.2.5, the only way to really prevent LDAP binds is to map authenticationAuthority to some directory attribute, which will also prevent automounted network home directories from working. Luckily, if you've deployed 10.2.6, you can install Apple Security Update (6-9-03), which alleviates this behavior.

PrimaryGroupID: Unsigned 32-bit ASCII string of digits 0-9. Range is 100-2147483648. PrimaryGroupID is a numerical value that associates a user with its primary group. This attribute is not strictly required; group file and folder associations are generally inherited from the group association of the enclosing folder in Mac OS X. The default primary group in Mac OS X is 20. Unless your organization has some well-defined primary group strategy, this should be a static map to #20. Quite often we see the recommendation that PrimaryGroupID should be mapped to AD's PrimaryGroupID. This will have two results. It will increase network traffic (however slight), and it might result in delays on the rare instances lookupd does a groupWithNumber query. PrimaryGroupID may also be mapped to msSFU30GidNumber in a SFU installation.

HomeDirectory: Structured UTF-8 text. This is an XML formatted value that points to a user's home directory location. This data is not strictly required for user authentication but is required in order to use AFP or SMB home directories. It is functionally equivalent to the Windows HomeDirectory UNC value, though it is formatted very differently and the two are not interchangeable. HomeDirectory can probably refer to a number of protocols, but we've only tested AFP and SMB. Apple only supports AFP (although SMB home directories work with some caveats, and NFS home directories do not require this data). The data looks something like this:


This data is not at all native to AD. If you're using the same home directory for Mac and Windows clients over SMB you can derive the required values from the UNC HomeDirectory in AD as a part of the user creation process.

This data can be stored in any unused attribute that supports UTF-8 text and compatible equality rules. We often use userSharedFolderOther. Another choice is to use Apple's apple-user-homeurl, which is defined in the Apple oid space. Once again, use of Apple's schema should be executed cautiously since it is still subject to change.

NFSHomeDirectory: UTF-8 text referring to the file system path where the user's Unix home directory resides. Ironically, it has little to do with NFS or the network at all. This value looks something like


Its data is supplied natively by msSFU30HomeDirectory, but by far the least intrusive method for supplying the data for both NFSHomeDirectory and HomeDirectory is to make use of the variable support in static mappings, provided by the third-party LDAPv3 plugin mentioned above.

HomeDirectory's value might also be statically mapped in the case of certain local home directory design goals. Namely, it's common in lab environments to map NFSHomeDirectory to a static value:

Fig 2.4 Directory Access: Static mapping of NFSHomeDirectory.

This directory should restored to a pristine state on logout or login by external means--usually a LoginHook or LogoutHook--so that every user gets an identical, supported desktop environment. You can find directions for this at

Network Home Directories also require a corresponding mounts record. This, however, should almost never be stored in AD, since it requires creation of a new structural class and a number of new attributes. It is far less intrusive to store the mounts record in a shared Open Directory domain or in the local netinfo machine on each client. The mounts record looks something like this:

  "name" = ( "mounts" );
      "vfstype" = ( "url" );
      "opts" = ( "url==smb://", "net" );
      "name" = ( "w2k:/HOMES" );
      "dir" = ( "/Network/Servers" );

Paste this into a text file (be careful of line wrap; there should be 11 lines) and customize to your own preference or site. Use the niload command to add it to your desired directory. For example,

niload -r /mounts . < edited-mount
niload -r /mounts / < edited-mount

Be aware that this example will replace the mounts directory in the specified domain. Consult the niload man page for further details.

There are many other attributes available to Mac OS X Directory services. These, however, are the most important for directory integration, and in general we operate on the principal of least impact, keeping our additions to the Directory at a minimum. That said, many Mac OS X security policy features are directory based, and these Mac-specific attributes certainly aren't a part of Active Directory natively. When limiting the impact on a directory, you'd seem to be losing these features. This is not the case, though. Managed settings in Mac OS X (collectively known as managed client x, or mcx) can be enforced on 3 levels: user, group, host or a group of hosts.

By limiting our impact on directory schema, we are giving up a few user level management settings. However, in most environments, it's rare and inefficient to actually manage these settings on a per-user basis. More often they are managed on a workgroup or host basis. For example, you might want to ensure that everyone logging into a particular machine in a lab has access to a scanning application. This is not difficult to implement with Mac OS X and Active Directory. All clients are simply configured to get directory data from two sources: your AD and a parallel, Mac OS X Server hosted Open Directory Domain.

Fig 2.5 Directory Access: Multiple nodes in the LDAPv3 plug-in configuration dialog.

Fig 2.6 Directory Access: Multiple nodes (in this case 2 LDAPv3 nodes) in the Authentication path.

All users and enterprise data still resides in AD. Mac specific data- difficult to maintain when stored in AD and often not managed by AD administrators- lives in the Mac specific directory. In this way, management of Mac specific data can be delegated to Mac specific support personnel without having to train them for windows management tasks or create custom management tools. In effect, the Open Directory domain has a one way trust with the Active Directory.

In general, this is accomplished by adding AD users to Open Directory groups or by enforcing these policies on any user that logs into a particular set of machines. For instance:

  1. Scenario: User sadams logs into sadams, an AD user, does not belong to any workgroups with managed preferences. However, dtop00 belongs to a group of machines (NY-office) defined in Open Directory, and a certain set of preferences will be enforced to any user logging into that group of machines (regardless of where their user record is stored: locally, in Active Directory, or in Open Directory). Mac-specific security policy is thus applied to Active Directory users without administrative impact on the enterprise directory.
  2. Scenario: User jdoe logs in to User jdoe exists only in Active Directory. However, mcx.loginplugin searches dtop00's authentication path and determines that jdoe belongs to a workgroup with managed preferences. Since jdoe is logging into a managed client (dtop00 belongs to the NY-office group), he will receive an aggregate of per host and per-workgroup preferences.

Another option for integration involves kerberos and alternate user records. Kerberos authentication in Active Directory happens based on sAMAcountName; what we'd think of as short name in Mac OS X. It's entirely feasible to have a user (jdoe) in Active Directory and a user in Open Directory (jdoe) that both authenticate to the AD's kdc. Most Administrators don't consider this since Microsoft sells AD as a single directory product integrating authentication and authorization. The concepts are quite separate, however, and kerberos is actually designed solely as an authentication technology, specifically for use in conjunction with a directory. The process looks something like this:

All of these processes allow for full support of Mac-specific user attributes and client management technologies while maintaining a single enterprise authentication authority.

Finally, with Mac OS X 10.2.6 came the ability to leverage NIS. NIS by itself is fairly insecure (and in fact Apple's NIS plugin is incapable of using shadowed maps). However, when combined with Kerberos authentication, NIS begins to look better. With services for Unix installed, Active Directory serves not only as a KDC but also as a full fledged NIS server.

This approach has the added benefit of making group integration with AD much simpler. Active Directory stores group membership according to the users' distinguished names. Unfortunately, the LDAPv3 plugin expects to find group membership according to short name. There are a number of strategies for dealing with this issue, most of which revolve around deriving the RecordName from the distinguished name and dumping a list of short names into one of the group's attributes. However, SFU's NIS server knows how to interpret group membership to Unix clients, thus offering a much simpler solution, and one that involves a lot less work server-side.

In fact, NIS+Kerberos, especially in conjunction with a dual Open Directory as documented above, provides yet another secure, flexible option for leveraging your enterprise directory. In many cases, particularly around the issue of access, this is solution is superior to the LDAPv3 plugin. However, due to its relative newness, we're only aware of a couple sites deploying a solution like this and a high level of testing and auditing is warranted.

Final Thoughts

Cross platform directory services are by nature complex. The right solution for your environment will vary heavily depending on organizational, political, security, and technical requirements. Mac OS X provides a flexible client-side framework to meet these challenges. Because of its reliance on open standards, it's able to be integrated painlessly into existing infrastructures.

Michael Bartosh

Return to Mac DevCenter

Copyright © 2009 O'Reilly Media, Inc.