January 18, 2010

SSH Messenger

As a request, I have finished my second full Objective C project. If someone is on a computer wearing headphones and is not in convenient shouting range this app makes it simple to still get their attention.  It would also make a good admin tool, or a awesome way to prank/annoy someone. It is a simple application that will connect to a remote computer via SSH and then use the built in osascript libraries to cause a dialog prompt to appear. However instead of requiring some terminal skills, instead just enter the IP, username and password of the remote computer and then type your message. A handy shell script takes care of all the rest. Click here to check it out. (Universal Binary, Mac OS X 10.5+)

This was an interesting project, not so much on the Objective C side, which I am getting quite good at, instead the shell scripting was a challenge this time. In order to have the SSH command work without setting up key pairs, I needed to delve into the world of Expect. Expect is a handy command set that allows you to set up automation of terminal entry. In short you can have it "expect" some input and then after finding it, send some output to the terminal, which in my case was the password entry for ssh. The ssh command does not have a password argument, so it needed expect to look for the password prompt and then enter a password for the user.  It also led to a nice way to do some general result checking in the case of a prompt with two or more button options.

Expect while a little strange at first was not that hard to figure out and only took about an hour and a half to have down pat and working the way I wanted it to.  Sadly as it is based out of /usr/bin/expect you cannot use echo command, which made it slightly harder to learn when something was not working.

Check out the base script I came up with below...

#!/usr/bin/expect -f
#log_user 0
set addr [lindex $argv 0]
set usr [lindex $argv 1]
set pas [lindex $argv 2]
set message [lindex $argv 3]
set from [lindex $argv 4]
# now connect to remote UNIX box (addr) with given script to execute
spawn ssh $usr@$addr -o StrictHostKeyChecking=no
match_max 100000
# Look for any ssh issue that needs exit
set timeout 4
expect "ssh:" {exit 2}
# Look for password prompt(s)
expect "*?assword:*" {send "$pas\r"}
# Look for password rejection and exit
expect "*?assword:*" {exit 1}
set timeout 10
# send osascript commands for popup
send "osascript -e 'tell application \"Finder\" to activate'\r"
#send "osascript -e 'tell application \"Finder\" to display dialog \"$message\"'\r"
send "osascript -e 'tell app \"Finder\" to display dialog \"$message\" buttons \"Ok\" default button 1 with title \"Message From $from\" with icon caution'\r"
# Look for reply
expect "button returned:Ok" {
 send "logout\r"
 exit 0
send "logout\r"

Another important thing to note is that I was rather annoyed to find out it required the curly braces to be placed how they are, due to it being based on Tcl. However it was only a minor inconvenience until I realized that is why if kept having errors.  The script above takes 5 arguments Address, User, Password, Message and From, and is the general Alert script used in the SSH Messenger.

This makes the first Objective C and Shell combo app that I have done, which is a nice change from the Java Shell combo I am more used to working with.  That and it was a good refresher in shell scripting.

No comments: