Macs at home; Part 1: Three ways to do the same thing

Filed under: Geekiness — iain @ 21:30:00

See the introduction to this post.

My first goal was somewhat prosaic. I wanted user accounts on belsunce and maling to have the same UID and GID as in LDAP. Nothing more than that. The first user account created when you install OS X has UID 501 and GID 501. Subsequent accounts take the next available UID and GID.

Because my account was the first one created on my Mac and Rebecca’s was the first created on hers, I was user 501 on belsunce and 502 on maling while she was 503 on belsunce and 501 on maling. Our LDAP UIDs are 101 and 314 respectively. Rather than delete and create new accounts I wanted to edit the details of the existing ones.

This operation would be equivalent to the traditional UNIX passwd file editing. On Macs we have what Apple calls NetInfo.

NetInfo is basically a database of various things including user account information. There’s a graphical tool to look at how it’s laid out: /Applications/Utilities/NetInfo Manager.app. Open the tool, click users and there are all the users on the system complete with the various attributes associated with them.

We can get and set this information from the command line too.

niutil is the tool for this. If you’re following along with NetInfo Manager.app you will notice that the NetInfo database is arranged in a directory tree-like structure so that the details for my account (iain) are under /users/iain. So it is with niutil.

    $ niutil -read . /users/iain
    name: iain
    home: /Users/iain
    gid: 501
    picture: /Library/Caches/com.apple.user501pictureCache.tiff
    uid: 501
    sharedDir: Public
    shell: /bin/bash
    passwd: ********
    authentication_authority: ;ShadowHash;HASHLIST:
    realname: Iain Patterson
    generateduid: 69D69C5D-7BC6-498A-A338-836454E6F71E
    _writers_passwd: iain
    _writers_tim_password: iain
    _writers_picture: iain
    _writers_hint: iain
    _writers_realname: iain

Note the syntax niutil -read <dot> /users/iain.

So there’s my UID and GID 501/501. You can also see the field name: iain which you might find surprising. In fact iain is not a key in the user database as it is in a traditional UNIX passwd file. Each NetInfo has a unique ID by which it can be accessed. You can see it by using niutil -list.

    $ niutil -list . /users | grep iain
    95       iain

My entry is 95.

    $ niutil -read . 95
    name: iain

You can also do:

    $ niutil -read /users/uid=501
    name: iain

This is interesting to know when you accidentally (or deliberately) delete the name attribute and can no longer access your user record with the /users/username syntax…

Now, how do we go about changing this information? As root, with niutil, that’s how.

    # niutil -insertval . /users/iain uid 101 0
    # niutil -destroyval . /users/iain uid 501

This creates a new attribute/value pair of uid/101 for iain and inserts it as value 0; an attribute may take multiple values. Then the old pair of uid/501 is deleted. The result is that my user ID is now 101. Hurrah.

My GID can also be changed. Since it (like the UID) can only meaningfully take one value, we don’t need to insert one value and delete the old. The -createprop flag will insert a value, overwriting any existing one. So it’s easier to do this:

    # niutil -createprop . /users/iain gid 100

Now my UID/GID is 101/100 which is what I wanted but the system doesn’t know about group 100 (users). It only knows about the now-redundant group 501. You can probably guess how to go about fixing that but the title of this post promises three ways to do the same thing and thus far we’ve only seen one. Therefore we will not use niutil to mangle group 501 but its cousin nicl.

nicl is just like niutil but different. Here’s the syntax we need:

    $ nicl . -read /groups/iain
    name: iain
    gid: 501
    passwd: *
    generateduid: 01423153-01D3-442A-9769-FB2E95F4D3B2

Notice how the syntax has changed. It’s nicl <dot> -read instead of niutil -read <dot>. Why is that? Dunno. Ask Apple.

Anyway let’s press on.

    # nicl . -create /groups/iain gid 100

Using the alternative syntax to change the name from iain to users:

    # nicl . -append /groups/iain name users
    # nicl . -delete /groups/iain name iain

The group can now be referenced as /groups/users.

The third way

For this we need to go up a layer of abstraction from NetInfo. Just as a UNIX machine has nsswitch and can get account information from other domains such as LDAP and NIS, so the Mac knows about other datastores than simply NetInfo.

The Mac equivalent of the nameservice switch is the DirectoryService and the tool to control it is dscl. Like its NetInfo-only counterparts, dscl can read and change data. One handy feature it has is the ability to search all known domains for user information. Behold:

    $ dscl localhost -read /Search/Users/iain
    _writers_hint: iain
    _writers_passwd: iain
    _writers_picture: iain
    _writers_realname: iain
    _writers_tim_password: iain
    sharedDir: Public
    AppleMetaNodeLocation: /NetInfo/DefaultLocalNode
    AuthenticationAuthority: ;ShadowHash;HASHLIST:
    GeneratedUID: 69D69C5D-7BC6-498A-A338-836454E6F71E
    NFSHomeDirectory: /Users/iain
    Password: ********
    Picture: /Library/Caches/com.apple.user501pictureCache.tiff
    PrimaryGroupID: 100
    RealName: Iain Patterson
    RecordName: iain
    RecordType: dsRecTypeStandard:Users
    UniqueID: 101
    UserShell: /bin/bash

Note that this is the equivalent of getent passwd iain on a UNIX machine. Note also that the record names have changed. Instead of uid we have the abstract UniqueID. Finally note that dscl told us where it got my details from:

    AppleMetaNodeLocation: /NetInfo/DefaultLocalNode

This tells us what we already knew: the account is managed by NetInfo. In comparison, an LDAP user would have AppleMetaNodeLocation: /LDAPv3/ldap.fqdn.

Just to confirm this:

    $ dscl localhost -read /NetInfo/Users/iain
    RecordName: iain

The syntax for changing a record is -change with the old and new values, viz:

    # dscl localhost -change /NetInfo/Users/iain UniqueID 501 101
    # dscl localhost -change /NetInfo/Users/iain PrimaryGroupID 501 100

Update 2007-10-31: Note that on Leopard the syntax is:

    # dscl localhost -change /Local/Default/Users/iain ...

So there you have it. Three ways to do the same thing. Next time I’ll talk about one way to do one thing: mount a home directory over NFS.


  1. Do I assume correctly that the last step in all three cases is a recursive “chown” on at least “/Users/iain”?

    Comment by Tron — 2007-08-27 @ 14:04:56

  2. Yes.

    Comment by iain — 2007-08-28 @ 18:37:14

RSS feed for comments on this post.

Leave a comment

You must be logged in to post a comment.

Powered by WordPress