MCX, dslocal, and Leopard
Recently on the MacEnterprise mailing list, several of us were discussing putting MCX records into the local directory service. This is an appealing idea to me, because we don’t use Open Directory, and I’ve never wanted to spend the political capital to get our LDAP schema extended to support MCX, especially since I didn’t really know if ManagedClient/MCX would actually do what we wanted.
MCX in the local directory service seemed to me a way to experiment without having to convince our LDAP admins to make schema changes.
The idea of putting MCX records in the local directory service is not new. Karl Kuehn documented a method to inject MCX settings into the local NetInfo database here. Karl’s method is a little complicated due to the complexities of working with the NetInfo database.
With the arrival of Leopard, what was an opaque database file has been transformed into simple plist files arranged in an easy-to-understand directory structure. This makes working with the local directory service much easier – in many cases, to make a directory service modification, you can just drop a file into a directory!
Additionally, Leopard’s directory service has replaced ComputerLists with ComputerGroups, which have a great new feature: computers can belong to multiple ComputerGroups. We’ll use that new feature later.
When designing my implementation – I wanted some key features:
1) Use Workgroup Manager to create ComputerGroups and set managed preferences.
2) Capture the changes quickly and easily.
3) Make the managed preferences modular, so I could mix and match sets of managed preferences on any given machine.
4) Have different sets of managed preferences apply to laptops versus desktops, and have the correct set apply to the right class of machines without having to manually associate laptop preferences to laptops, and desktop preferences to desktops.
You’ll need Workgroup Manager, which is part of Apple’s Server Admin Tools 10.5. Download those here, get them from your Leopard Server install media, or search Apple’s website for “Server Admin Tools”.
To work with the local directory service, launch Workgroup Manager on a OS X client machine. When presented with the dialog to connect to a server, type “localhost” as the server name, and enter the name and password of a local admin for the local machine.

You’ll see a warning that you are working in a directory node that is not visible to the network. Check “Do not show this warning again” if you wish, and click OK to dismiss the panel.
Get started by selecting the Computer tab in the left pane. Click “New Computer” in the toolbar to create a new computer object. Name it “local_desktop”. Don’t add any other info to the record other than the name and short name, which should be “local_desktop” as well. Repeat the process, creating another computer object named “local_laptop”.

Next, move to the Computer Groups tab in the left pane. This is where it gets interesting. Create Computer Groups for each group of preferences you want to manage. I grouped them logically: the LoginWindow group contains the managed preferences for the loginwindow; NetworkProxies contains the managed settings for the network proxies, etc.

For each group, add local_desktop, local_laptop, or both as members; depending on whether you want the managed preferences to apply to desktop machines, laptops, or both. For example, you might want Mobility settings to apply only to laptops, so you would add only the local_laptop to the group that contained the managed preferences for Mobility.
Once you’ve created a group and added the appropriate local machines, you can then configure the preferences you wish to manage. See Apple’s documentation on User Management for more on managing preferences.

You now have MCX data in your local directory service. Next, we need to get that data to all our managed machines.
With Leopard, you are interested in two directories:
/private/var/db/dslocal/nodes/Default/computers/
and
/private/var/db/dslocal/nodes/Default/computergroups/
There should be two files in /private/var/db/dslocal/nodes/Default/computers/:
local_desktop.plist
local_laptop.plist
In /private/var/db/dslocal/nodes/Default/computergroups/ you should find one plist file for each Computer Group you created.
To replicate your MCX records across all your machines, you’ll need to copy the files from those directories to the same directories on all your other machines. I use radmind, which is perfectly suited for this task. You could also use FileWave, ARD, or puppet, to mention a few possibilities. Another possibility that seems pretty interesting would be to copy these files to a web server, and have a local script on each machine periodically curl them down and copy them into place.
Once you get these files to another test machine, check to see that DirectoryServices sees them:
dscl . list /Computers
dscl . list /ComputerGroups
If you don’t see them listed and you’re certain they are there, try killall DirectoryService to restart DirectoryService and check again with dscl.
There’s one more thing you must do on the local machine, though, before these files will actually do anything useful on each client.
You’ll recall that when we created the local_desktop and local_laptop computer objects, we only named them – we did not enter the Ethernet ID information. In order to actually work, the appropriate object (local_desktop or local_laptop) must have its ENetAddress field set to the MAC layer address of the en0 interface of the local machine. To do this, I run a script at startup (I’ve added a bunch of line breaks [\] to make the text fit inside WordPress’s textwidth):
#!/bin/sh
changedMCX=false
macAddress=`/sbin/ifconfig en0 | \
/usr/bin/grep 'ether' | \
/usr/bin/sed \
"s/^[[:space:]]ether //" | \
cut -f1 -d " "`
IS_LAPTOP=`/usr/sbin/system_profiler \
SPHardwareDataType | \
grep "Model Identifier" | grep "Book"`
if [ "$IS_LAPTOP" != "" ]; then
computerRecordName=local_laptop
otherRecordName=local_desktop
else
computerRecordName=local_desktop
otherRecordName=local_laptop
fi
storedMacAddress=`/usr/bin/dscl . -read \
/Computers/$computerRecordName \
ENetAddress | cut -f2 -d " "`
if [ "$storedMacAddress" != "$macAddress" ] ; then
echo "Updating MAC address \
for /Computers/$computerRecordName..."
echo "was: $storedMacAddress"
echo "now: $macAddress"
/usr/bin/dscl . -create \
/Computers/$computerRecordName \
ENetAddress $macAddress
/usr/bin/dscl . -delete \
/Computers/$otherRecordName \
ENetAddress
changedMCX=true
fi
if [ "$changedMCX" = "true" ] ; then
currentuser=`/usr/bin/who | \
grep console`
if [ "$currentuser" = "" ]; then
echo "Restarting loginwindow..."
`/usr/bin/killall loginwindow`
fi
fi
This script uses system_profiler to tell if the machine is a laptop. If it is, it adds its en0 MAC layer address to local_laptop, otherwise it adds it to local_desktop.
Once local_laptop or local_desktop point to the local machine by way of the MAC layer address, all the policies you’ve defined in the various ComputerGroup objects will now apply.
You can deliver all the ComputerGroup objects to each client, or if you have a client with special settings, you can deliver only some of the ComputerGroup objects, or deliver different ComputerGroup objects.
The local_laptop and local_desktop Computer objects allow you to specify that some policies apply only to laptops, only to desktops, or both, and the local machine automatically places itself in the correct Computer object. This could be extended to have a machine place itself in some other Computer object, but it’s important to note that a machine’s MAC layer address can be in only ONE Computer object. The Computer object can be in multiple ComputerGroups.
In my implementation, local_laptop is in all the ComputerGroups, but local_desktop is not in the MobileAccounts, ScreenSaver, or SecureVM groups as we don’t enforce those settings on desktop machines. No-one has to remember to add the laptop-only policies to the right machines, or remember to add the laptops to the correct ComputerGroups – the machines do this themselves.
Fully implemented, we now have a solution that allows us to use Apple’s tools (Workgroup Manager, ManagedClient.app, MCX preference manifests, etc) to manage client preferences without having to extend the LDAP schema or build a “Magic Triangle” solution. This might serve as a test platform, or a learning environment to allow Mac admins to experiment with Client Management, or as an actual deployed method of managing OS X clients in your environment.
Nigel Kersten has also written on this topic. His article on afp548.com has a lot of command line examples, including examples of the new MCX support in dscl in Leopard.
February 7, 2008 at 7:51 pm
More MCX in DSLocal from Greg…
And along similar lines to <a href=”http://www.afp548.com/article.php?story=using-mcx-in-the-dslocal-domain”>the afp548.com article on this</a>, Greg Neagle <a href=”http://managingosx.wordpress.com/2008/02/07/mcx-dsloc…
February 7, 2008 at 8:12 pm
[...] MCX, dslocal, and Leopard: “ [...]
February 8, 2008 at 4:38 pm
[...] dslocal, and radmind In an earlier article about putting MCX data into the local DS store, I mentioned that I’m using radmind to deliver [...]
October 29, 2008 at 8:37 pm
Greg,
Thanks for getting me on the right track. I moved our network from AFP to NFS and PHDs stopped syncing. I couldn’t find anything on the web to lead me in the right direction until I came across your blog. It was when you mentioned:
“With Leopard, you are interested in two directories:
/private/var/db/dslocal/nodes/Default/computers/
and
/private/var/db/dslocal/nodes/Default/computergroups/”
It got me thinking there was something in there regarding users, and sure enough, there the golden plist lie. All I had to do was delete the array for “original_home_loc”, and I was good to go.
Thanks again, I’ll be checking back often.
Jason
March 3, 2009 at 6:01 am
Ok, I’ve done pretty much all of the above steps but didn’t see any change in my MCX settings on the local client. I performed all of the dscl checks and even restarted the computer.
The only thing I suspect is the script I copied the script and then attempted executing it with ARD to the local client. Bad idea? If so where should I place the script in order for it to execute? Also, for MCX settings to take would existing user accounts see the new MCX settings?
Thanks
Jerry
March 3, 2009 at 9:57 am
If the script did not execute properly, then the MCX settings won’t be applied.
Forgetting remote machines for a moment – does the script run correctly on your local machine?
Is the stored MAClayer address in /var/db/dslocal/nodes/Default/computers/local_desktop.plist (or local_laptop.plist) correct?
If so, check a remote machine – the ENetAddress in the local_desktop.plist (or local_laptop.plist) must be the same as the MAC layer address of en0.