So, from time to time we get computers stolen, and more often than one might think, they don't get erased but rather just gets a new admin account (using the .applesetupdone trick).
Our users aren't too happy about us collecting geo-location on a daily basis so we crafted a nifty little script that gives us the adress of the stolen computer. The script gets scoped to a static group containing all computers that are stolen (or lost) and set to run ongoing on all triggers (to get as much data as possible). As soon as the computer reports back in to the JSS, these scripts starts collecting data.
Along with the adress-script we have another script that prints the safari surf history of the current logged in user to stdin so it gets into the policy log to be viewed and finally one script that prints out the external IP and DNS name of the computer.
The adress scripts works by listing all the wifi networks seen by the computer and crafts a URL that requests data from google. The result is the approximate adress of the computers present location and the coordinates and finally the accuracy of the positioning.
We have recovered several computers using these scripts as all we have to do is provide law enforcement with location, IP/ISP and some "proof" of who we think is using the computer (you can often tell by the surf log since people tend to log into sites like Facebook and email which nicely prints out the name in the page title and therefore gets logged using the surf history part).
The record shows that the script is amazingly correct, or rather, Google is extremely good at provide location just using wifi networks. Most of the time, Google reports an accuracy of "150" which I guess would refer to 150 meters but from experience, that could easily be 15 meters, it's that accurate!
These scripts work for us, your mileage may vary, computers may catch fire, the scripts may contains bugs and so on...
Nevertheless, here are the scripts:
To get external IP:
#!/bin/sh
IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
DNS=$(host $IP | awk '{print $5}' | sed "s/.$//g")
echo "$IP - $DNS"
To log the surf history to the JSS (nb does not work in 10.10 as Safari now saves the history in a sqlite 3-file):
#!/bin/sh
unset LANG
#echo "START"
PREFIX="/tmp/safari-log"
USER=$(w | grep console | awk '{print $1}')
eval cp ~$USER/Library/Safari/History.plist $PREFIX-history-bin.plist
plutil -convert xml1 -o $PREFIX-history-xml.plist $PREFIX-history-bin.plist
split -p "WebHistoryDomains.v2" $PREFIX-history-xml.plist $PREFIX-
tail -n +5 $PREFIX-aa | egrep -o "(<string>.*</string>)|(<dict>)" | sed -E "s/</?string>//g" | sed "s/<dict>//g" | grep -v "^http://www.google.*,d.Yms$" > $PREFIX-history.txt
OLD_IFS=$IFS
IFS=""
exec 5<$PREFIX-history.txt
while read -u 5 LINE
do
echo $LINE | egrep -s "^[0-9.]+$" > /dev/null
if [ $? -ne 0 ] ; then
echo $LINE
else
TIME=$(expr $(echo $LINE | egrep -o "^[0-9]*") + 978307200)
date -r $TIME
fi
done
IFS=$OLD_IFS
rm $PREFIX-*
#echo "END"
And finally the one that prints out the address (location):
#!/bin/sh
INTERFACE=$(networksetup -listallhardwareports | grep -A1 Wi-Fi | tail -1 | awk '{print $2}')
STATUS=$(networksetup -getairportpower $INTERFACE | awk '{print $4}')
if [ $STATUS = "Off" ] ; then
sleep 5
networksetup -setairportpower $INTERFACE on
fi
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -s | tail -n +2 | awk '{print substr($0, 34, 17)"$"substr($0, 52, 4)"$"substr($0, 1, 32)}' | sort -t $ -k2,2rn | head -12 > /tmp/gl_ssids.txt
if [ $STATUS = "Off" ] ; then
networksetup -setairportpower $INTERFACE off
fi
OLD_IFS=$IFS
IFS="$"
URL="https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=false"
exec 5</tmp/gl_ssids.txt
while read -u 5 MAC SS SSID
do
SSID=`echo $SSID | sed "s/^ *//g" | sed "s/ *$//g" | sed "s/ /%20/g"`
MAC=`echo $MAC | sed "s/^ *//g" | sed "s/ *$//g"`
SS=`echo $SS | sed "s/^ *//g" | sed "s/ *$//g"`
URL+="&wifi=mac:$MAC&ssid:$SSID&ss:$SS"
done
IFS=$OLD_IFS
#echo $URL
curl -s -A "Mozilla" "$URL" > /tmp/gl_coordinates.txt
LAT=`cat /tmp/gl_coordinates.txt | grep "lat" | awk '{print $3}' | tr -d ","`
LONG=`cat /tmp/gl_coordinates.txt | grep "lng" | awk '{print $3}' | tr -d ","`
ACC=`cat /tmp/gl_coordinates.txt | grep "accuracy" | awk '{print $3}' | tr -d ","`
#echo "LAT: $LAT"
#echo "LONG: $LONG"
#echo "ACC: $ACC"
curl -s -A "Mozilla" "http://maps.googleapis.com/maps/api/geocode/json?latlng=$LAT,$LONG&sensor=false" > /tmp/gl_address.txt
ADDRESS=`cat /tmp/gl_address.txt | grep "formatted_address" | head -1 | awk '{$1=$2=""; print $0}' | sed "s/,$//g" | tr -d " | sed "s/^ *//g"`
if [ $EA -ne 0 ] ; then
echo "<result>$ADDRESS (lat=$LAT, long=$LONG, acc=$ACC)</result>"
else
echo "$ADDRESS (lat=$LAT, long=$LONG, acc=$ACC)"
fi
rm /tmp/gl_ssids.txt /tmp/gl_coordinates.txt /tmp/gl_address.txt