Macs at home; Part 1: Three ways to do the same thing
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 hint: 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 _shadow_passwd: _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 _shadow_passwd: _writers_hint: iain _writers_passwd: iain _writers_picture: iain _writers_realname: iain _writers_tim_password: iain sharedDir: Public AppleMetaNodeLocation: /NetInfo/DefaultLocalNode AuthenticationAuthority: ;ShadowHash;HASHLIST:AuthenticationHint: 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.
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
Yes.
Comment by iain — 2007-08-28 @ 18:37:14