Archive for October, 2006

Making parts of the filesystem read/write from NetBoot

Monday, October 30th, 2006

So we use NetBoot (well NetInstall really) a lot here for diagnostics and as a platform for radminding machines from.

I’ve recently been refactoring our entire Radmind setup here, mainly because we’ve been using it for so long that we’re not actually taking advantage of any of the features Radmind has introduced in the last couple of years.

As part of this, I’ve been trying to avoid using our existing radmind wrapper script, and instead to try and do everything using the supplied ra.sh script, with appropriately configured preapply/postapply scripts, which is working rather nicely so far.

Anyway, to get to the point of this post, I worked out that if I wanted to use ra.sh while booted from a NetInstall image, I really needed /var/radmind to be read/write, which it isn’t.

After poking around through the /etc/rc.cdrom script, I noticed that Apple do things this way:

echo "Creating RAM Disk for /private/tmp"
dev=`hdik -drivekey system-image=yes -nomount ram://2048 `  # 1MB
if [ $? -eq 0 ] ; then
  newfs $dev
  mount -o union $dev /private/tmp
fi

which is all rather dandy when you think about it. hdik is creating a 1Mb RAM disk, and then it is mounted as a union mount at /private/tmp, effectively making that directory read/write.

The only problem is that our Radmind transcripts take up about 40-50Mb, and you can’t use hdik to make a RAM disk of that size, which I imagine is a limitation of the fact that hdik is intended for rather lightweight disk images, being an in-kernel tool and all.

So I started poking around trying to work out how to use hdiutil to accomplish the same thing, but it turns out that hdid is actually far simpler. Rather than being an in-kernel tool, it will actually use the DiskImages.framework, which means the disk image limitations don’t hold.

So here’s what I add to /etc/rc.cdrom.postWS to create 96Mb of r/w space in /var/radmind

# Create r/w mount for /var/radmind and populate it with the file structure
echo "Creating RAM disk for /var/radmind"
dev=`hdid -nomount ram://196608` # 96Mb
if [ $? -eq 0 ]; then
  newfs $dev
  mount -o union $dev /var/radmind
  mkdir /var/radmind/cert
  mkdir /var/radmind/client
  mkdir /var/radmind/postapply
  mkdir /var/radmind/preapply
fi

and now everything is peachy.

Temporarily swapping user passwords in Open Directory

Tuesday, October 24th, 2006

So something I find that I need to do quite often is to log in as a specific user, and I don’t always want to reset their password.

While AFP has a really useful function where you can allow admins of an AFP server to masquerade as a specific user by using the admin password, no other services really offer that same kind of functionality.

What I tend to do in these situations is to swap the Authentication Authority around. I keep a test user account around that I know the password to, and I swap its Authentication Authority with the user I need to login as.

As the Authentication Authority describes which Password Server slot contains the password for a given user, by swapping them around you are effectively swapping the passwords. If you’re in a nice Kerberized environment (and if you’re not, you should be…) then you’ll notice that this doesn’t actually swap the Kerberos passwords around. This is because in a standard Open Directory setup, there are actually two password stores, one for Password Server and one for Kerberos. Apple have done some nifty stuff behind the scenes to keep the two in sync when users change their passwords, but by swapping Authentication Authorities around, you’re not modifying the Kerberos passwords at all.

Anyway, here’s the script I use to swap authentication authorities around. I tend to save it as something like “swap_auth_authorities.sh”, and then you’d use it like:

./swap_auth_authorities.sh -n /LDAPv3/my.od.domain -a diradmin -p diradminpass  testone testtwo

which would swap the Authentication Authorities for the users “testone” and “testtwo”.

As always, don’t blame me if you blow up your server, and you should definitely try this on test accounts first…. You can use the command “/usr/libexec/chkpasswd testone” to test the passwords for each user. If you get “Sorry” back, the password is wrong, if you get nothing back, the password is correct.

Love that famed Apple user friendliness :)

Script follows, or you can download it here:

#!/bin/bash
#

directorynode="/LDAPv3/127.0.0.1"
adminusername="diradmin"

export PATH="/usr/bin"

show_usage() {
echo "This script will swap the authentication authorities of two users in a directory node."
echo usage: swap_auth_authorities [-h] [-n directorynode] [-a adminusername] [-p adminpassword] username1 username2 ...
echo
echo "-h help (this output)"
echo "-n directory node name (default: /LDAPv3/127.0.0.1)"
echo "-a directory admin username (default: diradmin)"
echo "-p directory admin password"
echo "username1 and username2 are the users you wish to swap authentication authorities for"
echo
echo "Note: If the admin password is not specified, you will be prompted for it a number of times."
}

show_password_prompt() {
  if [ ${#adminpassword} -eq 0 ]; then
    echo "Enter the password for $adminusername"
  fi
}

while getopts  "hn:a:p:" flag; do
  # echo "$flag" $OPTIND $OPTARG
  case "$flag" in
    h) show_usage; exit ;;
    n) directorynode="$OPTARG" ;;
    a) adminusername="$OPTARG" ;;
    p) adminpassword="$OPTARG" ;;
    ?) echo >&2 "Illegal option '$OPTARG'"; exit 1 ;;
  esac
done
shift $(($OPTIND -1 ))

if [ $# -ne 2 ]; then
  echo >&2 "Error: You should only pass two additional parameters, the usernames whose authentication authorities are to be swapped"
  echo
  show_usage
  exit 1
fi

if [ ${#adminpassword} -eq 0 ]; then
  authstring="-u $adminusername -p"
  echo "You will now be prompted several times for the password for $adminusername"
else
  authstring="-u $adminusername -P $adminpassword"
fi

show_password_prompt
authority1=$(dscl $authstring $directorynode -read /Users/$1 AuthenticationAuthority | sed 's|^AuthenticationAuthority: ||g')

# check to see if users exist or permission denied.
if [ $? -ne 0 ]; then
  case $? in
    71 ) echo "User $1 not found in $directorynode"; exit 1 ;;
  esac
fi

# dscl really should return an error code in these cases...
if [ $(echo $authority1 | grep -c "Data source ($directorynode) is not valid.") -gt 0 ]; then
  echo "There is a problem with either your admin username/password combination, or the specified directory node"
  exit 1;
fi

show_password_prompt
authority2=$(dscl $authstring $directorynode -read /Users/$2 AuthenticationAuthority | sed 's|^AuthenticationAuthority: ||g')

# check to see if users exist or permission denied.
if [ $? -ne 0 ]; then
  case $? in
    71 ) echo "User $2 not found in $directorynode"; exit 1 ;;
  esac
fi

show_password_prompt
dscl $authstring $directorynode -create /Users/$1 AuthenticationAuthority "$authority2"

show_password_prompt
dscl $authstring $directorynode -create /Users/$2 AuthenticationAuthority "$authority1"

echo "The authentication authorities for $1 and $2 have been swapped."
echo "Note that Kerberos authentication will continue to use the old passwords."
echo "If you re-run this command, the authentication authorities will be swapped back again."

Typos can be fatal…

Wednesday, October 18th, 2006

So last night I was playing around with the MBR on an external drive… and completely without thinking managed to wipe out my laptop.

/dev/rdisk1 Nigel, not /dev/rdisk0 ….

bleagh.

Anyway, it’s made me realise just how much I love HomeSync, as 95% of everything that matters has been syncing up to the server… and as I’ve had two requests now for a post on Mobile Accounts and HomeSync best practices, this is as good a time as any… working on it now while watching OS X and Win XP reinstall….