Firmware Updates Redux

Mac firmware updates generally need some sort of user intervention in order to apply them.

This makes it very difficult to automate the process. I did manage at one point to automate SMC updates, but EFI updates and other hardware (keyboards, trackpads, graphics) each have their own issues.

So I finally decided to just punt on the issue. Here’s what I do now: a script runs at login and checks softwareupdate, looking for available firmware updates. If there are any, the user is notified to call the help desk.
Continue reading “Firmware Updates Redux”

Firmware Updates Redux

Radmind: converting to case-insensitive transcripts

Radmind, being a set of UNIX tools, originally supported only case-sensitive transcripts. Mac OS X’s HFS+ filesystem, developed by Apple pre-NeXT purchase, is a case-preserving, case-insensitive filesystem.

Support for case-insensitive transcripts was later added to the radmind tools.

As it turns out, it is perfectly possible to use radmind with case-sensitive transcripts to manage an OS X HFS+ filesystem. There are sometimes a few annoyances, but it generally works OK. Worst case, you might have to run the radmind tools twice to get the filesystem update when there is a case change: the first run might remove the lowercase version of the file, and the second run would install the uppercase version. Or a sharp radmind admin might be able to avoid the problem altogether by renaming files in troublesome transcripts.
Continue reading “Radmind: converting to case-insensitive transcripts”

Radmind: converting to case-insensitive transcripts

Converting NetInfo accounts to dslocal

If you are doing an in-place upgrade from Tiger to Leopard without using the Apple Leopard Install DVD, you may need a way to convert existing local or mobile accounts from NetInfo to the dslocal store.

Here’s a script that converts local accounts; it requires the nicl binary, which you can copy from any Tiger installation.

For local accounts, it uses nicl to read the account info, and dscl to create a new corresponding account. For mobile accounts, it uses createmobileaccount to recreate the mobile account.


Converting NetInfo accounts to dslocal

Automating Firmware Updates

Apple recently posted a firmware update for the MacBook that they claim addresses the spontaneous shutdown issue. If you have a lot of MacBooks at your site, you’ll have lots of fun visiting each one and doing the update.

It turns out that this updater can be run via command-line; either remotely via ARD or ssh, or via a local script on the machine. This opens up the possibility of automating it.
Continue reading “Automating Firmware Updates”

Automating Firmware Updates

radmind 1.5.1, Tiger, and symlinks

A little over a month ago, I discovered an issue with the way radmind 1.5.1 created symlinks under Tiger. This exhibited itself as a broken symlink to a directory on an automounted NFS volume. After discussing the matter with the radmind developers, and being unable to demonstrate any other actual problems caused by this, I decided to script a fix to the broken symlink and move on.

Yesterday, James Reynolds posted to both the MacEnterprise list and the radmind-users list about a problem with Adobe Bridge crashing on launch. James had used ktrace to discover it was crashing when trying to read a symlink.

James also discovered that if he copied the offending files from another (good) machine, Bridge worked as expected. It was only when radmind installed the files that things broke.

This rang a bell. I was quickly able to duplicate James’ issue by using radmind 1.5.1 to install Adobe Photoshop CS2 on a Mac.

After recreating the symlinks like so:

grep -h "^l" /var/radmind/client/AdobePhotoshopCS2.T | /usr/local/bin/lapply -u 022

Adobe Bridge worked as expected.

What is going on here?

There is a bug in Tiger that radmind 1.5.1 is exercising. Classically, owner, group and mode should be ignored on symlinks, deferring to the owner, group and mode of the symlink’s target. But in some operations, Tiger seems to honor symlink permissions, and if they are set so that a user cannot read the link, access to the link’s target will fail.

Here is a demonstration of the bug outside of the context of radmind:

(istanbul.fas) root [210] % uname -a
Darwin 8.5.0 Darwin Kernel Version 8.5.0: Sun Jan 22 10:38:46 PST 2006; root:xnu-792.6.61.obj~1/RELEASE_PPC Power Macintosh powerpc
(istanbul.fas) root [211] % cd /
(istanbul.fas) root [212] % umask 077
(istanbul.fas) root [213] % ln -s /Users/Shared /Shared
(istanbul.fas) root [214] % ls -al /Shared
lrwx------ 1 root admin 13 Mar 2 10:33 /Shared@ -> /Users/Shared

Note the restricted permissons for the /Shared symlink.

(istanbul.fas) root [215] % umask 022
(istanbul.fas) root [216] % readlink /Shared
(istanbul.fas) root [217] % exit
(istanbul.fas) gneagle [202] % readlink /Shared
(Nothing is returned)

As root, “readlink /Shared” returns the target path: “/Users/Shared”.
As “gneagle”, a non-privileged user, it returns nothing.

radmind 1.5.1 changed the way it creates files in an attempt to improve security. It changes the umask to 077, creates the file, and then chmods it to its intended permissions. But chmod has no effect on symlinks, and radmind captures no user, group or mode info for symlinks since the are not supposed to be significant.

The net effect is that all sysmlinks are created with owner as root and with mode 700. Normally that would not be a problem, and indeed is not under Panther. But under Tiger, it can be a problem.

So until Apple fixes the bug (I’ve reported to them) or the radmind team implements a workaround in their code, you can avoid this issue going foward by calling lapply with a “-u 022” option. This tells lapply to use a umask of 022 when creating temporary files. The net effect is that symlinks are created with mode 755, which makes them usable by non-root users.

That still leaves a major problem to solve. How do you fix the symlinks already created by radmind with a umask of 077? I developed a script to do just that.

#!/usr/bin/perl –w
# by Greg Neagle,
# - This script attempts to fix broken symlinks created by
# lapply 1.5.1 when run with the default umask option
# - No attempt is made to fix symlinks referenced in negative
# transcripts
# - Symlinks that are referenced in a positive transcript and a
# higher-precedence negative transcript therefore _will_ be
# modified, this could be bad. In my loadsets, I can find no
# actual occurrences of this problem, since the only symlink I
# have in any negative transcript is this one:
# l /private/etc/localtime /usr/share/zoneinfo/US/Pacific
# and it doesn't appear in any other transcripts.
# But the danger is there.
# - A deeper potential problem is transcript entries that
# _remove_ symlinks: if a transcript creates a symlink, and
# a higher-precedence transcript removes it, we'll have an
# unwanted symlink hanging around. A subsequent radmind
# session will remove it, but if this script is run again,
# it will come back.
# - Therefore we need to deal with "- l" lines in the
# transcripts as well. Unfortunately, we cannot just blindly
# pass these lines to lapply, because if symlink doesn't exist
# in the filesystem, lapply will fail and stop processing
# transcript lines.
# So we'll need to feed symlink removal lines to lapply
# one-by-one and ignore failures.
use strict;
my $radmindClientDir = "/var/radmind/client";
my $commandFile = $radmindClientDir . "/command.K";
my $symlinkremovet = "/tmp/symlinkremove.T";
#turn off output buffering
(open K, $commandFile) or die "Can't open the command file!";
while (<K>) {
   my $commandFileLine = $_;
   if ($commandFileLine =~ /^p/) {
      #positive transcript
      my @lineItems = split;
      my $transcript = $lineItems[1];
      print "Processing $transcript...\n";
      # re-create all symlinks in the transcript:
      # grep out all lines that begin with l and send them
      # to lapply with a 022 umask
      system "/usr/bin/grep -h \"^l\" \"$radmindClientDir/$transcript\" | /usr/local/bin/lapply -u 022";
      # grab symlink removal lines
      system "/usr/bin/grep -h \"^- l\" \"$radmindClientDir/$transcript\" > $symlinkremovet";
      print "Removing symlinks flagged for removal in $transcript...\n";
      if (open T, $symlinkremovet) {
         while (<T>) {
            #feed each line one-by-one to lapply
            system "echo $_ | /usr/local/bin/lapply -u 022";
         close T;
close K;

radmind 1.5.1, Tiger, and symlinks