NetNewsWire on a USB Drive

For those of us who can't sync our NetNewsWire data over the web due to firewalls or other infonazi roadblocks, there is hope.

I currently keep the contents of ~/Library/Application \Support/NetNewsWire on my USB thumbdrive. It does slow things down a little bit, but nothing major, and it allows me to keep everything current.

Creating an alias to the file is not enough. NNW will just crash on startup. Instead, create a symbolic link from the command line. Here's the instructions.

1. Copy your netnewswire application support folder from your home folder's library folder to your external storage of choice.

2. Open up terminal and input the following

ln -s /Volumes/USBdrive/NetNewsWire/ ~/Library/Application\ Support/NetNewsWire

That's it. For each additional machine you want to use this folder on, just delete the existing NetNewsWire folder from application support and do step number 2 again. Happy feedreading.

Update:

In theory, one could just write up a little Applescript to rsync the files to a USB drive and not have to worry about the linking, but it would be much more elegant if Brent would implement syncing to disk. Is no one asking for this?

Posted by joe [ Permalink | Comments (3) ]

Need a 64 Character WPA Key?

Need an easy way to generate 64 character pre-shared hex keys for setting up WPA on your wireless network?

If you're running a unix/linux capable box with xxd installed, like say Mac OS X you can just paste this command into the terminal and hit enter.

dd if=/dev/random bs=1 count=32 2>/dev/null |xxd -c 256 -ps

That will give you a random 64 character hex key. Enjoy.

Posted by joe [ Permalink ]

Make iChat Reconnect to Server

iChat doesn't automatically reconnect to the aim server when it has been disconnected, and there's no option to make it do so. Being behind an HTTP firewall, this can be a big pain in the butt with disconnects every few minutes. Having to reconnect manually every time is not my idea of fun. So it was time to break out cron and applescript to make things better.

* 9,10,11,12,13,14,15,16 * * 1,2,3,4,5 osascript -e 'tell application “iChat” to log in'

Adding this line to your crontab will try and make ichat log in to the aim server every minute of the day between 9AM and 5PM on workdays. iChat is very graceful in its handling of this command. If you're already logged in, it won't do anything. If there is an error dialog up complaining about not being able to hit the server, it will simply dismiss the error and try to connect again.

For the short term, this will do fine for me, but I may write this up as a startup service that checks to make sure ichat is running and if so, passes the login command, then goes to sleep for 20 seconds. I know there has to be at least a couple of people out there experiencing the pain of this.

Hopefully in iChat 3 there will be an option to automatically rejoin the server when there is a disconnect. Otherwise I will write the startup item to include Tiger as well.

Posted by joe [ Permalink | Comments (2) | TrackBack (0) ]

Patching iCal to Send Alarms Via RSS

At work, I rarely check my e-mail, so I decided to see if I could have iCal 1.5 send me an RSS notification. After a little looking around, I discovered that you can patch iCal's e-mail notification to post to a blog via XML-RPC and Applescript.

This is a long one, so do the Continue reading thing.


Note: I have only tried this on iCal 1.5.1 and cannot guarantee it will work on any other version. If iCal is upgraded in the future, this will stop working.

Resources:
Mac OS X Hints - scroll to the bottom of the comments
Objective Labs - Blogger API Testing Script

Give these a quick look over before starting.

Instructions:
So we're not really having iCal push RSS, so you need to have a running blogging system that uses the Blogger API to take advantage of this. I run Movable Type for my blog and it works fine.

First things first. Backup iCal. Really.

Okay now that we're past that, do I right click on iCal and click "Show Package Contents. Open up Contents and then Resources and look for Mail.applescript. Copy this to your desktop and then open it in Script Editor.

As you can see, this is pretty much standard applescript in here. So we're going to add in some properties from the Objectivelabs script so we can call a modified fuction later. At the top of the file, right after the --iCal line, paste in the following:

property username : "username" -- your username
property myPassword : "password" -- your password
property apiurl : "http://myMTblog.com/cgi-bin/mt-xmlrpc.cgi" -- the complete api url
property blogid : "1" -- Id of the weblog you'd like to post to
property publish : true
property appkey : "4FCE1E1F9E2DC89044F09D583390AB8A36F4903E"

This stuff is important. Make sure that your username and password are the same as you use to log into your blog. The URL is the path to your XMLRPC interface. In MT it's mt-xmlrpc.cgi, in wordpress it's xlmrpc.php. The id of your blog can be tricky. The easiest way to get your blog ids is to run the Objective Labs script with only the username password and apiurl properties established. That will give you a list of the names and ids of your blogs. Plop in the correct id there. I would recommend just making a new blog for your alerts that you can check independently of the others.

Next, find the function send-mail_sbr. replace the function with this:

on send_mail_sbr(subjectLine, messageText, myrecipient)
newPost(blogid, messageText, publish)
end send_mail_sbr

This tells iCal to call the newPost function instead of sending mail. The date, title, and notes of the iCal event are published to the blog. Where is this function you may ask? Well we're adding it now. Scroll to the very bottom of the file and then paste this code in after everything else.

-- Sends the XML-RPC code to the remote server
on tellBloggerAPI(methodName, params)
using terms from application "http://www.apple.com"
-- any url works here. Fools applescirpt into using xml-rpc terms
tell application (apiurl as text)
set myResult to call xmlrpc {method name:methodName, parameters:{appkey} & params}
return myResult
end tell
end using terms from
end tellBloggerAPI

-- Creates a new post, and possibly it is published
on newPost(blogid, content, publish)
set params to {blogid, username, myPassword, content, publish}
return tellBloggerAPI("blogger.newPost", params)
end newPost

Okay, we're done here. Save the file. Now we're going to move that file into the iCal bundle and give it the right permissions. You backed up iCal right? Okay good. Assuming you saved the file to the desktop and iCal is in the root of the applications folder, do the following terminal magic:

mv ~/Desktop/Mail.applescript /Applications/iCal.app/Contents/Resources/Mail.scpt
sudo chown root:admin /Applications/iCal.app/Contents/Resources/Mail.scpt
sudo chown 664 /Applications/iCal.app/Contents/Resources/Mail.scpt

And.... we're.... spent. Okay, now iCal will post to our blogs when it's open. To make sure it does the same thing when it's closed, you have to patch a file in the iCal helper app. Thankfully it uses the same script so we can just pop the following in the terminal:

mv ~/Desktop/Mail.applescript /Applications/iCal.app/Contents/Resources/iCal\ Helper.app/Contents/Resources/Mail.scpt
sudo chown root:admin /Applications/iCal.app/Contents/Resources/iCal\ Helper.app/Contents/Resources/Mail.scpt
sudo chown 664 /Applications/iCal.app/Contents/Resources/iCal\ Helper.app/Contents/Resources/Mail.scpt

Now all your alarms for which you have specified e-mail as your alarm choice will instead be posted to your blog. Recipient doesn't matter as it is ignored anyway. Of course, e-mail alerts will no longer work, but if you want to do both, you can just have applescript call the post function right after the e-mail function.

I tried having iCal call an Applescript from the "Open File" alarm option, but I couldn't get iCal to pass any information to the script like the title of the event or the note attached to it. If anyone knows how to do this I would love to hear it.

Conclusion:
I am using this script to remind me when bills are due since I spend so much time in my aggregator, and so little in my email these days. But you could also use it to post entries by including HTML in the notes section of your events. There are a lot of possible uses for this. Hope you enjoy it. Thanks to Objective Labs for the script and dbikel on macosxhints for his sendmail hack for iCal 1.5.

Posted by joe [ Permalink | TrackBack (0) ]

Two Factor Authentication in OS X

Yet another take from a Macosxhints article.

This is a hacked up two factor authentication scheme for Mac OS X that relies on an external storage device like and iPod. You could also use a usb keychain, or anything that will mount. Used in combination with Filevault, this can provide a reasonable amount of security on your machine that requires the presence of your device.

The article on Macosxhints describes using a script to make sure a folder exists on your device. You call this script from a login hook which either prevents login if the folder does not exist, or allows it if it does.

I'd like to instead create a random data seed, and check it's hash on the client computer to make sure it's the same file. Plug in your ipod or usb keychain and open terminal. Type in the following:

dd if=/dev/random bs=1k count=1024 of=/Volumes/ipod/.login/randomseed

Make sure to change the ipod in the above to whatever you are calling your device. This will create a 1MB file filled with random data. It dumps it directly into your device in a hidden folder called .login. Unless someone got their hands on this file, it's extremely unlikely they would be able to duplicate it. Next we need to pull the hash value into a file on our machine:

MD5 -q /Volumes/ipod/.login/randomseed > ~/.login/hash

This will give you an MD5 hash in a hidden folder in your home directory that looks something like this:

2b913b93be5f241f7416b673c85b6641

Now that we have our random file on our ipod and a copy of the hash in our home folder, we can get to the fun stuff.

First we need to make sure that drives are auto mounted even when a user is not logged in:

sudo defaults write /Library/Preferences/SystemConfiguration/autodiskmount AutomountDisksWithoutUserLogin -bool true

Otherwise, external drives are not mounted until a user logs in, and that defeats the purpose of our script. You'll have to restart for this to take effect.

Now we have to adapt the script from Macosxhints to check for the hash instead of a folder. Here's the script.

#!/bin/sh
devicehash=`/sbin/md5 -q /Volumes/iPod/.login/randomseed`
storedhash=`/bin/cat /Users/$1/.hash`
if [ "$devicehash" == "$storedhash" ];
then
exit 0
else
/usr/bin/killall -HUP loginwindow
fi

What this does is compare the hash of the randomseed file on the ipod to the stored hash on the hard drive. Since this is a loginhook script, we can't use kill -9 -1 as loginhooks run as root and kill -9 -1 does bad things when it's run as root (check the man page). I use a killall instead. Long and short of it is, if the hashes match, then you log in, if they don't, you get the login screen again.

I saved this script in /Library/Hooks/login/myuser/login.sh and did a chown root login.sh and chmod 700 login.sh to change the owner to root and give only root permission to access the script.

Then you simply type this into the terminal:

sudo Defaults write com.apple.loginwindow LoginHook /path/to/script

If for some reason you can no longer login after this, say there's a typo in the script, boot into single user mode by holding down Command and S. When you get to the prompt, type:

mount -uw /
defaults delete com.apple.loginwindow LoginHook

Update

I have tried my best to find a way to make this work with fast user switching, and there is a limited way to do it. When you switch users from the fast user switching menu, the system writes a userid key to /System/Library/Preferences/com.apple.loginwindow.plist. We can use to see who is currently logged in. The problem is, when you chose a user from the login screen i.e. what we do when we have CGSession suspend our login, it doesn't update this plist. For a suspend script to work as a cron job, or even a background job while we're logged in, it has to know that we have control over the GUI at that moment, otherwise it will just indiscriminately suspend the current session regardless of who is running it.

Of course, if you were willing to be vigilant about saving your documents, you could make a script just kill the processes belonging to your user id. This will leave any other logged in users alone, but will kick you rather abruptly if your authentication device is not present. It wouldn't be much different from the previous script:

#!/bin/sh
devicehash=`/sbin/md5 -q /Volumes/iPod/.login/randomseed`
storedhash=`/bin/cat ~/.hash`
pid=`ps -x | grep -w loginwindow | grep -v grep | sed -e 's/^ *//' -e 's/ .*//'`

if [ “$devicehash” == “$storedhash” ]; then
exit
else
if [ $pid ]; then
kill $pid
else exit
fi
fi


Save this and move it someplace safe in your user folder. Chmod it to 770. Make sure this is in your user cron and not in the root cron, as it depends on being run as the user to pull the process id from ps. You could write a little deamon script to check the hash every couple of seconds, but I don't need it to do more than once a minute.

If someone can find a reliable way to find out who is current gui user, I have a much nicer script ready that will just switch to the login window, which will give you a chance to save any files.

Posted by joe [ Permalink | TrackBack (0) ]

Bigger CDRs from the Finder

In response to this hint over at macosxhints.com, I thought I would offer a better way to get bigger CD burns in the finder. The poster is suggesting just going around the finder and using command line utilities for burning. Pssshha I say. Let's make the finder bend to our wills.

The finder uses proxy disk images for determining burn sizes on CDs. They are located in:

/System/Library/CoreServices/Finder.app/Contents/Resources/

There you will find a bunch of proxy images with multiple CD sizes indicated by minute length and even one for DVDs. As the complaint goes, the 80 Minute CDR image offers only 670MB of burnable space. There is some consideration here for HFS overhead, but 30MB seems a little extreme. So let's make a new disk image to replace our 80 minute proxy image. Be sure to backup the proxy image to intend to mess with. Now to the good stuff. Bust open the terminal and type in the following:

hdiutil create -megabytes 700 ~/Desktop/cdrproxy.dmg -layout NONE

this creates a 700MB image on the desktop. It will actually be 700MB so make sure you have enough room.

hdid -nomount ~/Desktop/cdrproxy.dmg

This pseudo-mounts the image at a device location (/dev/something) to let us put a file system on it. Take note of the /dev/disk number that is returned as we'll be using it next.

newfs_hfs -v Untitled /dev/disk#

This puts our filesystem on the disk image where # is the number of the disk device we were given. It also names the volume Untitled.

hdiutil eject /dev/disk#

Eject our disk so we can convert it.

hdiutil convert -format UDZO ~/Desktop/cdrproxy.dmg -o ~/Desktop/cdr80-proxy.dmg

This will convert the image to read only compressed UDIF format which is required by the finder. It also gives the new image the correct name. You now have the image you need. Now you just have to move it into place.

sudo cp ~/Desktop/cdr80-proxy.dmg /System/Library/CoreServices/Finder.app/Contents/Resources

This moves the image into the right spot. It will ask for an admin password at this point.

sudo chmod 655 /System/Library/CoreServices/Finder.app/Contents/Resources/cdr80-proxy.dmg

This changes the permissions to the correct settings for the image.

sudo chown root /System/Library/CoreServices/Finder.app/Contents/Resources/cdr80-proxy.dmg

This changes the owner of the image to root as god intended. Now pop in a disc and revel in the extra space. This gives us a writable disc size of 689MB or about 19MB more than with the stock image. I tried making an 720 MB image and the finder failed with an error, so there will be no over-burning discs unless someone wants to break into the discburning framework and play around in there.

Posted by joe [ Permalink | Comments (3) | TrackBack (0) ]

Mount AFP Shares Read Only

In some cases you may want to mount shares over AFP read only. Sure you could mount SMB or NFS shares read only, but then you could run into some nasty resource fork issues. Since OS X Server doesn't allow you to share AFP read only, you will just have to mount it read only.

In my case, I have a backup share that contains snapshots of my user's data for a week. I want them to be able to mount the share for recovering data, but I don't want them to accidently delete or write over a file. So I made a little shell script that will mount the share.

mkdir /Volumes/Backup
mount -rt afp afp://username:password@yourserver/yourshare/ /Volumes/Backup
open /Volumes/Backup

This will simply mount the share read only and open a finder window to its contents. On the server, I only gave access to one user, and use that username in the script. I pop this into an applescript and compile it to an application so that users can't just pull the user name and password if they're feeling nosey.

Posted by joe [ Permalink | TrackBack (0) ]

Change Default Printer from the Command Line in OS X

This came up the other day when I was talking to Nic. So I did a little digging.

When you change your default printer in Mac OS X, it makes a change in your /Library/Preferences/.GlobalPreferences.plist file. There is a key called DefaultDevice-prtr that indicates the default printer. That printer is specified by an integer that correlates to the device, which you can get from further down the plist file.

But you don't have to mess with this plist file if you want to change the default printer on a large group of remote machines. Mac OS X responds correctly to the standard CUPS commands. So you can just do the following:

lpstat -p will show you the printers available
lpstat -d will show you the current default printer
lpoptions -d printername will set the default to whichever printer you specify

This can also be helpful for scripting, say when you want to have a login script that changes the default printer for specific users who aren't authenticating against a Mac OS X server.

Of course lpq, lprm and lpr work as well.

Posted by joe [ Permalink | TrackBack (0) ]

Universal 10.3.4 boot DVD from G5

If you're a Mac system administrator, like me you have probably used the restore discs from your newer machines to update and reinstall the OS on machines older than the one the discs were intended for. It's really nice to have OS X on one DVD instead of 3 cds, and you have the benefit of not having to run through so many updates in Software Update. It's a big time saver.

Until recently, you could install the OS from the restore DVDs that came with newer powerbooks and powermacs. You couldn't install the bundled 3rd party software that is included with new machines though because it checked the machine's model number, and if it didn't match up, then no install. This was fine as we're really only interested in having the latest version of OS X on a convenient DVD, not making illicit copies of 3rd party software.

The DVDs that come with the 2nd generation G5s which were just released prevent this however. While writing my in-depth review of the new migration features of Setup Assistant, I had access to a new set of restore DVDs from the G5, but not the G5 itself. When I tried to install on my powerbook, I got this message:

Bundled Software cannot be installed on this computer.

From here, your only option is to close the installer and restart the machine. Bummer.

So I set about to see what had changed in this new DVD. Turns out that there was one major difference in this restore DVD versus the older ones. On previous restore discs, restoring your system was a 2 step process.

1. Start off the DVD and install Mac OS X, reboot, set up your user
2. Use a package installer to re-install your bundled 3rd party apps, classic system folder, and various other goodies.

This second part required a check to insure that you're using a system that can use the software included in the bundle. This allowed the installer to selectively install iDVD on only machines with DVD drives for instance. No big deal here, except that for people who had to return these machines to factory software spec, you had to create a user to install software, then delete the user and all traces of having used the machine. Cumbersome and annoying.

Enter the new restore DVD and the changes that prevent us from using these DVDs as regular OS install discs. For this revision, apple decided to add the bundled software package to the default list of packages installed when first installing the OS. So now instead of having a 2 step process, you can just install everything all at once. Much better for people restoring these machines. Worse for Sys Admins who just want a 10.3.4 DVD for convenience.

TechGoesBoom to the rescue. I'm going to walk you through modifying a new G5 restore DVD to make it function as a normal install DVD. These instructions assume you are currently using 10.3.

1. Pop DVD #1 in your DVD drive. We don't need Disc 2. That has the extra bundled software which we're not concerned with anyway.
2. Open Disk Utility and click on the volume labeled "Mac OS X Install Disc 1"
3. From the Images menu, choose the New option and select "Image from Mac OS X Install Disc 1"
4. Name it whatever you want. I chose test.dmg. Make sure to chose "read/write" as the image format as we will be making changes to it. Do not use "DVD/CD Master". Click save, grab some coffee and wait until it finishes.
5. Once we have our image, go ahead and mount it.
6. The more astute of you have noticed at this point that there doesn't seem to be any folder containing the install packages like previous OS X install Discs. That crafty Apple hid them on you. The "go" menu is your friend. In the finder click the go menu and select "go to folder".
7. Type in "/Volumes/Mac OS X Install Disc 1/System/Installation/Packages/OSInstall.mpkg/Contents/" with no quotes. Feel free to copy and paste.
8. Info.plist is the one we're interested in here. Open this file in your favorite text editor. I recommend BBedit.
9. find the section that says

<dict>
<key>IFPkgFlagPackageLocation</key>
<string>Bundled Software.mpkg</string>
<key>IFPkgFlagPackageSelection</key>
<string>selected</string>
</dict>

10. Delete it and save the file.
11. Unmount the image by hitting the eject symbol next to it in the sidebar or by dragging to the trash.
12. Launch Disk Utility. Your image should still be in it's sidebar. Click on the image and then click on the burn symbol. You obviously need a DVD burner for this.

You now have a 10.3.4 install DVD. What we did was remove the XML pointer that told the installer to try and install the bundled software. Before it will do so, it runs through it's list is packages and makes sure they can all run. The bundled software package checks your machine against an approved list. If it doesn't meet up, it won't run, and so the OS installer won't run. None of the other packages do this check, so by removing this one, we get the go ahead for an install.

Disclaimer: Obviously don't install Mac OS X on machines for which you don't have licenses. This walkthrough is not meant to enable piracy, but to prevent users from having to install around 200mb of software updates that are required after a bare install of 10.3 from a retail CD. To paraphrase the iPod, Don't steal OSes. This method worked fine for both my Powerbook and my Mirrored Drive Doors G4. Let me know if you guys hit any snags.

Posted by joe [ Permalink | Comments (19) | TrackBack (0) ]