5 Tips for Mac OS X Sysadmins

Monday, 2007-03-26; 00:09:00

[UPDATE: This seems to be a very popular entry. If you found it useful, you may find my follow-up entry, “More Sysadmin Tips”, useful as well.]

Here are a few things that might be of interest to anyone who is managing a bunch of Mac OS X computers. These are a few things that I've recently discovered that have made my life a lot easier, and I figured I'd add them to the great electronic library that is the internets. To most Mac OS X users, these will probably be useless. But whatever.

1. Disabling Dashboard

Particularly when you're in a place where kids come in every day to use your computers and can easily get distracted by eye-candy, both Dashboard and Exposé are real annoyances. That zooming-in effect of the widgets and the windows flying all over the place is enough to keep a 3rd-grader happy for an hour when he's supposed to be doing other work, especially when he knows that you don't want him to be playing with Dashboard and Exposé.

Thankfully, here are some tactics you can use to win in your epic struggle. First, you can completely disable Dashboard across all users, like so:

defaults write /Library/Preferences/com.apple.dashboard mcx-disabled -boolean YES

This gets saved in a preference file that is read by every user, so even if you create a new user, Dashboard will be disabled by default.

To reverse the effect, use this command:

defaults delete /Library/Preferences/com.apple.dashboard mcx-disabled

Note that you can override this global setting by issuing a command for a single user using this variant of the command:

defaults write com.apple.dashboard mcx-disabled -boolean NO

When I first encountered this command, I wrote this in a comment over at UNEASYsilence:

I’ve never understood the need for Dashboard disablers. Why don’t you just set up your Dashboard preferences so that there’s no way to invoke it? That is, make it so there’s no hot key and no hot corners. Voilà, you’ve disabled dashboard, with no need for an extra utility.

This overlooks the fact that there's yet another way to invoke Dashboard: via the pseudo-app in the Applications folder. There's no way to disable that app other than to 1) delete it, or 2) use the above command. I prefer the latter.

2. Disabling Exposé

Exposé is a tougher beast, because, as far as I know, there's no way to completely disable Exposé. The only way to "disable" it is to make it so there's no way to invoke it, by disabling all the keyboard shortcuts and mouse clicks that trigger Exposé.

The best way I've found to do this is to go to the Dashboard and Exposé pane in System Preferences on one Mac, and manually disable all the keyboard shortcuts and mouse clicks. (You do this by setting the popup menus to a value of "-"). Then, go to ~/Library/Preferences/ (where ~ is your home folder), and fetch the file called "com.apple.symbolichotkeys.plist". You'll then need to transfer this file to all users on every computer on which you want to disable Exposé.

I did this by first copying the symbolic hotkeys plist file to /Library/Preferences/ on all the computers via Remote Desktop. Then, I ran this UNIX script as root on all the computers through Apple Remote Desktop:

for i in `ls /Users/`
        cp /Library/Preferences/com.apple.symbolichotkeys.plist /Users/$i/Library/Preferences/
        chown $i /Users/$i/Library/Preferences/
        chmod 700 /Users/$i/Library/Preferences/
        chown $i /Users/$i/Library/Preferences/com.apple.symbolichotkeys.plist
        chmod 600 /Users/$i/Library/Preferences/com.apple.symbolichotkeys.plist

This'll copy the symbolic hotkeys file from the global preferences folder to the preferences folder for each user. It will then make sure the permissions on both the user's preference folder and the preference file itself are correct. (Note that this command will probably generate some errors for "Shared", ".localized", and ".DS_Store" which also live in the Users folder, but these errors are harmless. I'm a bit lazy to modify the script to exclude these, but if anyone else wants to, feel free.)

Once you do this, Exposé will effectively be disabled on all users for the Macs to which you copied this plist file.

If anyone knows a Terminal command that actually and truly disables Exposé, I'd be very interested to know about it. Also, if anyone knows how to disable the brightness adjustment keys F14 and F15, that would also be very useful.

3. Setting a Software Update server across all users

This one might be a little obvious given the tip for disabling Dashboard globally, but I've found that even the command that sets the Software Update server for one user is a bit buried in Apple's documentation. The command to set the server for one user is:

defaults write com.apple.SoftwareUpdate CatalogURL "http://URL-to-server:8088/"

Note that the "/" at the end of the catalog URL is super important. If it's not there, Software Update will fail. I consider this a bug.

Well, as you might've guessed, the command to set the update server globally is:

defaults write /Library/Preferences/com.apple.SoftwareUpdate CatalogURL "http://URL-to-server:8088/"

Very useful. Once you run this command, you should be able to log in to any user, run Software Update, and the URL to your server should appear in the title bar of the Software Update application. (If it doesn't, then something's wrong.)

(Overriding this setting for a single user or deleting this global preference are similar to how you do it when you're disabling Dashboard.)

4. Scripting authentication

One of the things that's very useful about AppleScript is that starting with Jaguar, Mac OS X has a feature called "GUI scripting" which allows you to script virtually anything that you can do with your mouse and keyboard -- in other words, everything. You can do virtual clicks on buttons by referring to them, you can send virtual keystrokes to any application, and you can get access to the view hierarchy of various objects in the GUI so that you can do these things. You can even click by pixel position on the screen if an app doesn't allow access to its view hierarchy, like *cough* the iTunes Store. I still have grand designs to make a script that automatically fetches the free downloads for the week on a regular basis, in case you go away for a long period and don't have internet access.

Prefab UI Browser is absolutely your friend in your endeavor to do GUI scripting. Don't even think about doing it without that app. It's essential, despite it's sorta-clunky UI.

But remember how I said you can script everything? I lied. There's one crucial place that Mac OS X doesn't allow you to script: the standard authentication dialog. Despite all my trials and tribulations, I can't get that dialog to respond at all: the process that displays the dialog is called SecurityAgent and lives in /System/Library/CoreServices/ . Even if the dialog is at the front and has focus, sending keystrokes to SecurityAgent results in absolutely nothing.

Assuming I'm not just being dense, I can understand why Apple did this. It's obvious that you shouldn't be able to retrieve anything from the text fields in the authentication dialog, but it's less obvious why you shouldn't be able to use a script to provide your credentials to the dialog. The authentication dialog is designed to verify that the user currently sitting at the computer actually has the credentials to perform a certain action. Allowing the dialog to be scriptable means that it might not be the user who's entering their credentials. Even when you're using Remote Desktop or VNC, there's still ultimately a user on the other end that's putting in the user and password so that they can perform the action. Not so if it were scriptable.

The problem with this security measure is that it fucking sucks. I qualify the adjective with profanity because there are so many things that would be useful to be able to script that require authentication. An example is provided in the next tip. Needless to say, though, it's quite a hampering limitation.

Recently, though, I figured out a way around this problem. When you first log in to a Mac, your credentials are saved for 5 minutes. I believe that this happens whenever you put your password into an authentication dialog: you can repeat the actions that you are allowed to perform for 5 minutes. This is pretty sensible, since it would be ridiculous to require you to put in your credentials if you wanted to perform the same action many times in succession. (I encountered this when I was developing MUG; when you authenticate to kill a process, your credentials will be saved for MUG for 5 minutes.) This five minute window can be changed by modifying some system file I believe -- not sure where with the latest version of Mac OS X, so you might want to consult Apple's documentation on Mac OS X security if you're interested in how to do that.

But this five minute window is a boon if you want to script something that requires authentication. Why? The login window is scriptable!

So just log out of the current user, and then use Remote Desktop to send a script (run under the root user) to log in as a certain user and then perform the actions that require authentication. Because you've recently logged in, the authentication dialog won't pop up. It's a sweet workaround.

You're welcome to contemplate the security implications of this on your own. (I think the scriptability of the login window is on purpose, though, because the canonical way to log in to a user via Apple Remote Desktop is to send an AppleScript to the login window. That's how Apple says to do it in the ARD documentation.)

5. Scripting Open Directory binding

For sysadmins, Open Directory is a boon to system management. Instead of having to create local users on each and every Mac, Open Directory allows you to create all the accounts once on a server, and then just tell clients to connect to the server to authenticate users when they log in at the Mac OS X login window. (Stanford does this with public Macs, but I'm not sure if it actually uses Open Directory or something similar. Stanford has thousands of students, and it would be nigh-impossible to create local users for each and every student on each and every public computer.)

The problem is with setting it up. This is one of those actions that require authentication, and so there's no easy way to do it without doing it manually. (You could potentially script it up to the authentication point, manually go around and put in the administrator credentials, and then script everything past the authentication point. But that sort of defeats the purpose of scripting.) You could potentially fetch the preference file that stores this information and copy it to all the computers that require binding, but if you don't want to override any current bindings, replacing the preference file would be bad. And you have to restart the computer for these changes to take effect -- something which you wouldn't have to do if you manually go around and activate the binding. Lastly, you could try and edit the plist file using the "defaults" command, but since the preferences are buried inside an array inside a dictionary inside another array, this'll get messy and I'm not even sure how to do it.

(BTW, if you're wondering where this information is stored, it's all in a plist file at /Library/Preferences/DirectoryService/DSLDAPv3PlugInConfig.plist .)

So, to safely script the binding, we use the previous tip. Just log out, and then execute this script as root from the login window (easily accomplished via Apple Remote Desktop):

sudo touch /private/var/db/.AccessibilityAPIEnabled
osascript <<EndOfMyScript 
tell application "System Events" 
        keystroke "login" 
        keystroke return
        delay 1.0
        keystroke "password" 
        delay 1.0
        keystroke return 
end tell
osascript <<EndOfMyScript
delay 15
tell application "System Preferences" to activate
delay 5
tell application "System Events"
        tell process "System Preferences"
                click button "Sharing" of scroll area 1 of window "System Preferences"
                delay 5
                set computer_name to (get value of text field 1 of window "Sharing")
        end tell
end tell
tell application "Directory Access" to activate
delay 5
tell application "System Events"
        tell process "Directory Access"
                select row 5 of table 1 of scroll area 1 of tab group 1 of window "Directory Access"
                set connection_method to (get value of text field 1 of row 5 of table 1 of scroll area of tab group 1 of window "Directory Access")
                if (connection_method as string) is equal to "LDAPv3" then
                        click button 1 of tab group 1 of window "Directory Access"
                        delay 5
                        click button 3 of sheet 1 of window "Directory Access"
                        delay 5
                        click text field 1 of group 1 of window "New LDAP Connection"
                        display dialog "An error occurred: selected row is not LDAP." buttons {"OK"}
                end if
        end tell
end tell
tell application "Directory Access" to activate
tell application "System Events"
        tell process "Directory Access"
                keystroke "address-to-directory-server.domain"
                click button "Continue" of window "New LDAP Connection"
                delay 5
                set value of text field 3 of group 2 of window "New LDAP Connection" to computer_name
                set value of text field 2 of group 2 of window "New LDAP Connection" to "dirlogin"
                keystroke tab
                keystroke tab
                keystroke "dirpassword"
                click button "Continue" of window "New LDAP Connection"
                click button "OK" of window "New LDAP Connection"
                click button "OK" of sheet 1 of window "Directory Access"
        end tell
end tell
tell application "Directory Access" to quit
tell application "System Events" to log out
sudo rm /private/var/db/.AccessibilityAPIEnabled

It even scripts the turning on of the "Enable access to assistive devices" preference in the Universal Access preference pane, which is required to be on for GUI scripting to work. Thanks Mac OS X Hints!

(Note that there are 5 things you need to change in this script before you actually run it: "login", "password", "address-to-directory-server.domain", "dirlogin", and "dirpassword". The first two are the credentials for a local user on the machine, the third is the address to your Open Directory server, and the last two are the credentials for a directory administrator on your directory server.)

Technological Supernova   Tips   Older   Newer   Post a Comment