Tag Archives: Bash

Integrating Open Directory and Google Apps (Natively Syncing Open Directory Passwords to Google Apps)

I have been reviewing for some time the different ways which are available to push password change updates from a Apple Open Directory (OpenLDAP) Master to our Google Apps domain, and I have waited for some time for a solution I could go with. However, I was and have been unsatisfied with the solutions which are available for OS X. I wanted a very simple, secure, and natively run solution – running on my snow leopard server or lion server. Simple is a major part here, while some people don’t mind getting into configs and changing them I wanted it to be, run a installer, answer some easy questions, and bam! So below are my personal requirements for this first round of development.

 

Integrating Google Apps with Open Directory Requirements

  1. Do NOT store a plaintext password on disk.
  2. No extra services (such as MySQL), I wanted to use a simple flat file structure, similar to svn, because it is one less thing to fail.
  3. Easily configurable, easy to extend, easy to archive, easy to remove.
  4. When a user changes their LDAP password it should change their Google Apps password.
  5. If a user sets a password on a LDAP account which does not exist in Google Apps, it should be created.
  6. It should work for multiple Google Apps Domains.
  7. Install it & forget about it.

So I wrote a simple series of bash scripts, and an easy installer & uninstaller to accomplish what I wanted. While this is my first iteration of this tool it is currently in the last stages of production deployment testing, and I believe this to be ready to be used by most. I tried reasonably well to make the setup easy and very straight forward. Everything that is needed for this to work is already on OS X Server or included in the installer.

This is designed to be installed on your ODM, while the installer is NOT fool proof – I believe it to handle the most common cases and setups without problem. I will be developing this more and maturing the features, but I am currently focusing on my own needs, so I would really like to hear what would be popular to add.

It makes heavy use of openssl for storing confidential information using public key cryptography, this also allows root to actually recover a password if the situation ever arises. The tools that are installed with this are required to be run by root as well as access to the flat file structure it uses to store information in, this is intentional so that it adds a measure of security as to who can access it. Because if someone has access to your ODM as root all bets are off anyway.

It also uses Apple’s native launchd instead of cron because of the discontinuing support of cron on Apple’s platform. I believe this is the easiest most straight forward solution I have come across for syncing passwords from OpenDirectory to Google Apps on OS X.

There are some conventions to follow in order for this to work properly and they are as follows:

  1. In each of the user accounts in OD make sure their full Google App email account is entered under the user info tab, it should be the only email address entered.
  2. In each of the Google App domains make sure you create the SAME domain admin user (the part before the @) with the SAME password.

All messages are printed to the system.log file, so watch this file if you want to see any errors or it just working. You might have to issue a -HUP or restart PasswordServer or ODM for changes to take effect, but I did not have to. Formal documentation will follow after the next release.

 

Installation is simple:

  1. Download latest zip file to Open Directory Master.
  2. Unzip file.
  3. Open Terminal
  4. Change to the setup directory inside the package (this is a must!).
  5. CD to the newly unzipped folder
  6. Run: sudo ./install.sh

googlePasswordSync Release Log:

CURRENT RELEASE: org.theObfuscated.googlePasswordSync

SPECIAL NOTE: Bugs should be filed under the issues section on GitHub at https://github.com/jjviscomi/googlePasswordSync/issues. Please include all the output from the logs and whatever else is necessary to help correct or identify the issue.

- Added Google Apps Directory Sync Integration Capability. (If you choose to it will now modify the users LDAP record to include a SHA hash of the password so that GADS can push that information to Google Apps.) However if you choose this option make sure you use DACL to prevent everyone from seeing this information.

Read more »

Removing ‘other’ Users Home Folders – in a mobile home folder environment

OS X Home FolderIf you have a large network that uses mobile home folders which allows multiple users to access any given machine, but each machine is assigned a primary user then this little addition to your login hook might be for you. Let me clarify when I say ‘Allow multiple users access’, I mean they can authenticate to a machine but normally DO NOT work on it. The ‘Primary User’ is the person who is expected to be logged into this machine the majority of the time, but say another user need to check their e-mail or get a document, or something where they need access for a limited time – then this little bit of code will remove any of their personal files when the ‘Primary User’ logs back in.

# Author: Joseph J. Viscomi    E-Mail: jjviscomi [at] gmail [dot] com || jviscomi [at] brehm [dot] org
# Date: 3/11/2011
# Description: This script can be included in a login hook when you want to remove all mobile or other home folders that
#              do not belong to the primary user of this computer. Mainly used to remove unwanted files and free disk space.
#              Once this script is applied in order for it to work correctly the first person that logs in must be the
#              'Primary User' of the computer.
#
#		Every time the 'Primary User' signs on to the computer it will remove all other home folders.
#
#              If you want to reset the 'Primary User' run the command - sudo rm -f /var/log/currentUser.log
#              then restart the computer and login as the 'Primary User'

#REMOVE HOME FOLDERS FOR NON-PRIMARY USERS
#CHECK TO MAKE SURE THE USER LOGGING IN HAS A HOME FOLDER
if [ -d "/Users/$1" ]; then
	#CHECKS TO SEE IF THE FILE THAT CONTAINS THE 'PRIMARY USER' EXISTS
	if [ -e "/var/log/currentUser.log" ]; then
		#CHECK TO SEE IF THE CURRENT USER IS THE 'PRIMARY USER'
		if [ `cat /var/log/currentUser.log` = $1 ]; then
                        #REMOVE ALL OTHER USER HOME FOLDERS - NOTE: DO NOT REMOVE Shared FOLDER, THIS CAN CAUSE PROBLEMS!
			#LOG THE OPERATIONS TO SYSLOG
			ls  /Users/ | grep -v `cat /var/log/currentUser.log` | grep -v Shared | xargs -I {} sudo rm -vrf /Users/{} >> /var/log/system.log
		fi
	else
		#IF THE FILE WHICH CONTAINS THE CURRENT USER DOESN'T EXISTS THEN THE PERSON THAT IS LOGGIN IN MUST THE 'PRIMARY USER'
		#RECORD THEIR USER NAME IN THE LOG FILE FOR FUTURE USE.
		sudo echo $1 > /var/log/currentUser.log
	fi
fi

The above script has been simplified for easy readability and commented to improve understanding of what is going on.

Tracking a Mac laptop over the internet (locating a stolen laptop)

This is an example of what you can achieve with just a little work, this is meant to provide more of an idea than an actual production piece of code (however it seems like a good place to start). So the problem I want to address is the ability to track Mac laptops in the wild, via the internet. I want to know where in the entire world and when my laptops are on line, even be able for them to fetch commands (future post) based on their status. This is ment to be simple I threw this idea together in about two hours (from start to finish) so not polished, but effective. This tutorial has a couple of distinct pieces you need:

  1. Client computers running os x, 10.6 in this case, but 10.5 should also work.
  2. A web server that is accessible over the internet and able to run PHP server side scripts.
  3. A mysql server accessible by the web server.

Lets begin by examining the client bash script that will send data to our web server, there are a few things to configure in it.

#!/bin/bash

# Author: Joseph J. Viscomi    E-Mail: jjviscomi [at] gmail [dot] com || jviscomi [at] brehm [dot] org
# Website: http://www.theobfuscated.org
# Date: 4/6/2011
# Description: This script when run will send information about itself to a webserver.
#              It can be used to track computers in the wild, on the internet. This is
#              the first of two files that will need to be installed on the clients.
#              For full functionality you will also need the server side code to handle
#              this script.
#              I have provided a basic verson of this for educational purposes only.
#              This is an attempt to show you what can be possible, this can be extended
#              to relay any information back to a server, and it can even be used for
#              two-way communications (post to follow).

# STEP 1.
#       CREATE A DIRECTORY ON THE CLIENT MACHINES: sudo mkdir /etc/.callHome/
#       CHANGE THE HOMEADDRESS TO POINT TO THE CORRECT DIRECTORY ON YOUR WEBSERVER WHERE THE callHome.php IS LOCATED
#       SET THE UNIQUE LOCATIONID - USE ONLY UPPERCASE AND NUMBERS, UPTO 64 CHARS
#       SAVE AND SET THE FILE TO EXECUTABLE, sudo chmod +x callHome.sh
#       PLACE THIS FILE IN /etc/.callHome/

# STEP 2.
#       PLACE THE org.theObfuscated.callHome.plist FILE IN THE /Library/LaunchDaemons/ DIRECTORY
#       IT IS SET TO CALL IN EVERY 10 MIN, THIS CAN BE CHANGED.

# STEP 3.
#       launchctl load /Library/LaunchDaemons/org.theObfuscated.callHome.plist

#THIS IS THE ADDRESS THE COMPUTER CALLS HOME TO, IP OR FQDN
# - CHANGE THIS TO REFLECT WHERE THE SERVER SIDE SCRIPT RESIDES
HOMEADDRESS="www.theobfuscated.org/callHome/"
#THIS IS THE NAME OF THE SERVER SIDE SCRIPT TO HANDLE THE REQUEST
SCRIPTNAME="checkin.php"

#THIS IS LIKE A SITE PASSWORD, JUST A BASIC SECURITY MEASURE - MAKE SURE IT MATCHES WHAT YOU HAVE IN THE DB
#EACH SITE SHOULD HAVE A UNIQUE LOCATIONID
LOCATIONID="SDJELK45689DSK"

#GET THE MAC ADDRESS OF THE MACHINE THAT IS CALLING HOME
LOCALMAC=`(/sbin/ifconfig en0 | awk '/ether/ { gsub(":", ""); print $2 }')`
#GET THE PUBLIC IP ADDRESS OF WHERE THIS MACHINE IS CURRENTLY CONNECTED TO THE INTERNET
EXTERNALIP=`(curl -s http://checkip.dyndns.org | awk '{print $6}' | awk ' BEGIN { FS = "<" } { print $1 } ')`
#GET THE SERIAL NUMBER OF THIS MACHINE
SERIALNUMBER=`ioreg -l | grep IOPlatformSerialNumber | awk '{ print $4 }' | sed "s/^\([\"']\)\(.*\)\1\$/\2/g"`
#GET THE TIME IN DAYS SINCE THE LAST RESTART
UPTIMEDAYS=`(uptime | awk '{ print $3 }')`
#GET THE USERNAME OF THE CURRENT USER
CURRENTUSER=`whoami`
#GET THE CURRENT HOSTNAME
HOSTNAME=`hostname`

#CHECKIN SITE
HOMESITE="http://"$HOMEADDRESS"/"$SCRIPTNAME"?mac="$LOCALMAC"&hostname="$HOSTNAME"&user="$CURRENTUSER"&days="$UPTIMEDAYS"&ip="$EXTERNALIP"&serial="$SERIALNUMBER"&loc="$LOCATIONID

#GET THE RESPONSE FROM THE SERVER
HOMERESPONSE=`(curl -s $HOMESITE)`

#RECORD IN THE LOCAL LOG
echo "$HOMERESPONSE" >> /Library/Logs/callHome.log

The above script can be download here, for simplicity call it what we do, callHome.sh. The first thing you will need to edit the script at line # 32
HOMEADDRESS="www.theobfuscated.org/callHome/"
It should point to the directory on your web server where the server side script will reside. It is important to exclude the http:// but to include the trailing slash. Now depending on if you modify the name of the file on the server (I recommend you do not) you might need to change line # 34, this needs to be the file that will accept the client communications.

Line # 38 is the next important line, this is here for some simple security. This is a randomly generated “Location ID”, randomly type some upper case & numeric characters here (up to a maximum length of 64). However you have to write this down for a later step, we will refer to this as the LOCATIONID, this should not be shared with anyone else.

This is all the editing you have to do in this script. Save it to the following location: /etc/.callHome/callHome.sh
Make sure this script is executable (i.e. sudo chmod +x /etc/.callHome/callHome.sh). Just because we have this script now on the client computers doesn’t mean we are finished yet.

We want to make sure it will regularly contact our web server and register with it, and to do that we will run it as a Launch Deamon. To simplify this process I have created a plist file that will tell launchd to run this script every 10 minuets, it is displayed below:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>org.theObfuscated.callHome</string>
    <key>OnDemand</key>
    <true/>
    <key>StartInterval</key>
    <integer>600</integer>
    <key>ProgramArguments</key>
    <array>
      <string>/private/etc/.callHome/callHome.sh</string>
    </array>
  </dict>
</plist>

Line # 10 specifies how often the script should be run, in this case every 600 seconds. Feel free to change this, but I would suggest to wait until after you confirm this is working. This file should be called org.theObfuscated.callHome.plist , down load it here. This file needs to be saved in the following location: /Library/LaunchDaemons/org.theObfuscated.callHome.plist and then we just need to tell launchd to load it, however this should wait until we have our servers configured properly first.

 

Configuring the Server side PHP Recording Script & MySQL DB.

Copy  this file to the location you desire on your web server, it should be the same location and name as indicated earlier when configuring the client script.

<?php
/**
 * User: Joe Viscomi | jjviscomi [at] gmail [dot] com | www.theobfuscated.org
 * Date: 4/6/11
 * Time: 8:29 PM
 * Description: Simple PHP Script to handle reporting from clients.
 */

    //#CHANGE THESE SETTING TO REFLECT YOUR DATABASE
    $DBHOST="localhost";
    $DBUSER="root";
    $DBPASSWORD="root";
    $DBNAME="call_home";

    //#GET KEY VAULES TO AUTHENTICATE THE REMOTE COMPUTER
    $location_hash = $_GET['loc'];
    $mac_address = $_GET['mac'];
    $computer_serial = $_GET['serial'];

    //#CONNECT TO THE DATABASE
    $db_link = mysql_connect($DBHOST,$DBUSER,$DBPASSWORD);
    mysql_select_db($DBNAME, $db_link);

    //#THIS IS THE AUTHENTICATION QUERY
    $sql  = "SELECT `LOCATION`.`LOCATION_id`, `LOCATION`.`LOCATION_name`, `COMPUTER`.`COMPUTER_mac`, ";
    $sql .= "`STATUS`.`STATUS_name`, `STATUS`.`STATUS_id`, `COMPUTER`.`COMPUTER_id` ";
    $sql .= "FROM `LOCATION`, `COMPUTER`, `STATUS` ";
    $sql .= "WHERE `LOCATION`.`LOCATION_active` = '1' AND `LOCATION`.`LOCATION_hash` = '".$location_hash;
    $sql .= "' AND `COMPUTER`.`COMPUTER_mac` = '". $mac_address ."' AND ";
    $sql .= "`COMPUTER`.`LOCATION_id` = `LOCATION`.`LOCATION_id` AND ";
    $sql .= "`COMPUTER`.`COMPUTER_serial` = '". $computer_serial ."' AND `COMPUTER`.`COMPUTER_active` = '1' AND ";
    $sql .= "`COMPUTER`.`STATUS_id` = `STATUS`.`STATUS_id`";

    //#QUERY THE DB TO SEE IF THIS COMPUTER SHOULD EVEN CALL HOME
    $result = mysql_query($sql, $db_link);
    $computer = mysql_fetch_array($result);
    mysql_free_result($result);

    //IF $COMPUTER HAS A SIZE OF 12 THEN A RECORD EXISTS FOR THE REMOTE COMPUTER
    if(sizeof($computer) === 12){

        //GET LAST CONTACT TIME
        $sql  = "SELECT MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`) FROM `CONTACT-LOG` WHERE `CONTACT-LOG`.`COMPUTER_id` = '";
        $sql .= $computer['COMPUTER_id']."' AND `CONTACT-LOG_active` = '1'";
        $result = mysql_query($sql, $db_link);
        $last = mysql_fetch_array($result);
        mysql_free_result($result);

        //LOG THE REMOTE CONTACT
        $sql  = "INSERT INTO `call_home`.`CONTACT-LOG` (`CONTACT-LOG_id`, `COMPUTER_id`, `STATUS_id`, ";
        $sql .= "`CONTACT-LOG_hostname`, `CONTACT-LOG_user`, `CONTACT-LOG_uptime`, `CONTACT-LOG_ip`, ";
        $sql .= "`CONTACT-LOG_client`, `CONTACT-LOG_doc`, `CONTACT-LOG_active`) VALUES (NULL, ";
        $sql .= "'" . $computer['COMPUTER_id'] . "', '" . $computer['STATUS_id'] . "', '" . $_GET['hostname'];
        $sql .= "', '".$_GET['user']."', '".$_GET['days']."', '".$_GET['ip']."', '" .$_SERVER['REMOTE_ADDR'];
        $sql .= "', CURRENT_TIMESTAMP, '1')";
        mysql_query($sql);

        //GET LAST CONTACT TIME - NOW
        $sql  = "SELECT MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`) FROM `CONTACT-LOG` WHERE `CONTACT-LOG`.`COMPUTER_id` = '";
        $sql .= $computer['COMPUTER_id']."' AND `CONTACT-LOG_active` = '1'";
        $result = mysql_query($sql, $db_link);
        $current_date = mysql_fetch_array($result);
        mysql_free_result($result);

        //COMPUTER HAS ACCOUNT
        echo("[" . $_SERVER['SERVER_ADDR'] ."][" .$current_date['MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`)'] . "]:" .
             "Computer Account Found\r\n");
        echo("[" . $_SERVER['SERVER_ADDR'] ."][" .$current_date['MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`)'] . "][" .
             "STATUS]: " . $computer['STATUS_name'] . "\r\n");
        echo("[" . $_SERVER['SERVER_ADDR'] ."][" .$current_date['MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`)'] . "][" .
             "TIME OF LAST CONTACT]: " . $last['MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`)']);

    }else{
        echo("[" . $_SERVER['SERVER_ADDR'] ."][" .$current_date['MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`)'] . "]:" .
             "Computer Account Not Found\r\n");
    }

    mysql_close($db_link);

?>

Lines # 11-14 are the only lines you need to change here, they need to reflect the setting to access your mysql database server. Then save this file as stated earlier in the proper location in you web server this can be downloaded here in zip format.

The last step is to setup the MySQL server DB and table structure and populate it with the inventory of the computers it is suposed to keep track of. You can download the sql file that will create all the necessary tables and default values for you here. It is also displayed below for you to read if you wish, however the detail is not that important.

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Database: `call_home`
--

-- --------------------------------------------------------

--
-- Table structure for table `COMPUTER`
--

CREATE TABLE `COMPUTER` (
  `COMPUTER_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `LOCATION_id` int(10) unsigned NOT NULL,
  `COMPUTER_serial` varchar(64) NOT NULL,
  `COMPUTER_mac` varchar(64) NOT NULL,
  `STATUS_id` smallint(5) unsigned NOT NULL DEFAULT '1',
  `COMPUTER_active` smallint(5) unsigned NOT NULL DEFAULT '1',
  PRIMARY KEY (`COMPUTER_id`),
  UNIQUE KEY `COMPUTER_serial` (`COMPUTER_serial`,`COMPUTER_mac`),
  KEY `COMPUTER_active` (`COMPUTER_active`),
  KEY `LOCATION_id` (`LOCATION_id`),
  KEY `STATUS_id` (`STATUS_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `COMPUTER`
--

-- --------------------------------------------------------

--
-- Table structure for table `CONTACT-LOG`
--

CREATE TABLE `CONTACT-LOG` (
  `CONTACT-LOG_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `COMPUTER_id` int(10) unsigned NOT NULL,
  `STATUS_id` smallint(5) unsigned NOT NULL,
  `CONTACT-LOG_hostname` varchar(128) NOT NULL,
  `CONTACT-LOG_user` varchar(128) NOT NULL,
  `CONTACT-LOG_uptime` smallint(5) unsigned NOT NULL,
  `CONTACT-LOG_ip` varchar(64) NOT NULL,
  `CONTACT-LOG_client` varchar(64) NOT NULL,
  `CONTACT-LOG_doc` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `CONTACT-LOG_active` smallint(5) unsigned NOT NULL DEFAULT '1',
  PRIMARY KEY (`CONTACT-LOG_id`),
  KEY `CONTACT-LOG_hostname` (`CONTACT-LOG_hostname`,`CONTACT-LOG_user`,`CONTACT-LOG_uptime`,`CONTACT-LOG_ip`,`CONTACT-LOG_client`),
  KEY `CONTACT-LOG_active` (`CONTACT-LOG_active`),
  KEY `COMPUTER_id` (`COMPUTER_id`),
  KEY `STATUS_id` (`STATUS_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `CONTACT-LOG`
--

-- --------------------------------------------------------

--
-- Table structure for table `LOCATION`
--

CREATE TABLE `LOCATION` (
  `LOCATION_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `LOCATION_hash` varchar(64) NOT NULL,
  `LOCATION_name` varchar(128) NOT NULL,
  `LOCATION_active` smallint(6) NOT NULL DEFAULT '1',
  PRIMARY KEY (`LOCATION_id`),
  UNIQUE KEY `LOCATION_hash` (`LOCATION_hash`),
  KEY `LOCATION_active` (`LOCATION_active`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `LOCATION`
--

-- --------------------------------------------------------

--
-- Table structure for table `STATUS`
--

CREATE TABLE `STATUS` (
  `STATUS_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `STATUS_name` varchar(64) NOT NULL,
  `STATUS_active` smallint(6) NOT NULL DEFAULT '1',
  PRIMARY KEY (`STATUS_id`),
  KEY `STATUS_name` (`STATUS_name`,`STATUS_active`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

--
-- Dumping data for table `STATUS`
--

INSERT INTO `STATUS` VALUES(1, 'NORMAL', 1);
INSERT INTO `STATUS` VALUES(2, 'UPDATES REQUIRED', 1);
INSERT INTO `STATUS` VALUES(3, 'CRITICAL ERRORS', 1);
INSERT INTO `STATUS` VALUES(4, 'FORCE SHUTDOWN', 1);
INSERT INTO `STATUS` VALUES(5, 'STOLEN', 1);

Just make sure you create a database with the same name that is configured in the php file above (i.e. $DBNAME=”call_home”;). I suggest using a tool like phpMyAdmin to import the sql file and to make the following inserts, we will not cover this in this article, I will assume you can do/ figure this out:

INSERT INTO  `call_home`.`LOCATION` (
`LOCATION_id` ,
`LOCATION_hash` ,
`LOCATION_name` ,
`LOCATION_active`
)
VALUES (
NULL ,  'SDFA78ASDFA98F',  'MY HOME',  '1'
);

The insert above registers your LOCATIONID that was set on the client script, so replace SDFA78ASDFA98F with what ever you set earlier. Also Replace MY HOME with a description that is meaningful to your site location. Next we need to insert inventory of all the client computers this server can expect to hear from:

INSERT INTO  `call_home`.`COMPUTER` (
`COMPUTER_id` ,
`LOCATION_id` ,
`COMPUTER_serial` ,
`COMPUTER_mac` ,
`STATUS_id` ,
`COMPUTER_active`
)
VALUES (
NULL ,  '1',  'SERIALNUMBER',  'MACADDRESS',  '1',  '1'
);

Please note that you need to insert the serial number and the mac address for each Mac you want to track, you can get that by running the following commands respectively, then simply copy and paste it in place of  ’SERIALNUMBER’ and ‘MACADDRESS’:

ioreg -l | grep IOPlatformSerialNumber | awk '{ print $4 }' | sed "s/^\([\"']\)\(.*\)\1\$/\2/g"
/sbin/ifconfig en0 | awk '/ether/ { gsub(":", ""); print $2 }'

That is all we have to do to prepare the MySQL Server to record the clients announcements. It is importiant that if you do not insert the correct values then the computer calls will NOT be recorded by the server.

You can view the results in phpMyAdmin or you can include this server side script to display a simple table of the latest requests from all registered clients (I know this is sloppy but, again it is just a proof of concept):

<?php
/**
 * User: Joe Viscomi | jjviscomi [at] gmail [dot] com | www.theobfuscated.org
 * Date: 4/6/11
 * Time: 8:41 PM
 * Description: To Display the latest results from all registered clients!
 */

    //#CHANGE THESE SETTING TO REFLECT YOUR DATABASE
    $DBHOST="localhost";
    $DBUSER="root";
    $DBPASSWORD="root";
    $DBNAME="call_home";

    $db_link = mysql_connect($DBHOST,$DBUSER,$DBPASSWORD);
    mysql_select_db($DBNAME, $db_link);

    $sql  = "SELECT MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`), `CONTACT-LOG`.`CONTACT-LOG_user`, `CONTACT-LOG`.`CONTACT-LOG_ip`, ";
    $sql .= "`CONTACT-LOG`.`CONTACT-LOG_client`, `CONTACT-LOG`.`CONTACT-LOG_hostname`, `CONTACT-LOG`.`CONTACT-LOG_uptime` FROM `CONTACT-LOG` ";
    $sql .= "WHERE EXISTS (SELECT * FROM COMPUTER WHERE `CONTACT-LOG`.COMPUTER_id = COMPUTER.COMPUTER_id ";
    $sql .= "AND COMPUTER_active = 1)";

    $result = mysql_query($sql,$db_link);

    $lastContactPage  = "<table class=\"sample\">\n";
    $lastContactPage .= "<tr>";
    $lastContactPage .= " <th>HOSTNAME</th>\n";
    $lastContactPage .= " <th>PUBLIC IP</th>\n";
    $lastContactPage .= " <th>CLIENT IP</th>\n";
    $lastContactPage .= " <th>USER</th>\n";
    $lastContactPage .= " <th>UP TIME (DAYS)</th>\n";
    $lastContactPage .= " <th>TIME OF LAST CONTACT</th>\n";
    $lastContactPage .= "</tr>";

    while($row = mysql_fetch_array($result)){
        $lastContactPage .= "<tr>\n";
        $lastContactPage .= "  <td>" . $row['CONTACT-LOG_hostname'] . "</td>\n";
        $lastContactPage .= "  <td>" . $row['CONTACT-LOG_ip'] . "</td>\n";
        $lastContactPage .= "  <td>" . $row['CONTACT-LOG_client'] . "</td>\n";
        $lastContactPage .= "  <td>" . $row['CONTACT-LOG_user'] . "</td>\n";
        $lastContactPage .= "  <td>" . $row['CONTACT-LOG_uptime'] . "</td>\n";
        $lastContactPage .= "  <td>" . $row['MAX(`CONTACT-LOG`.`CONTACT-LOG_doc`)'] . "</td>\n";
        $lastContactPage .= "</tr>\n";
    }

    $lastContactPage .= "</table>\n";

    mysql_free_result($result);
    mysql_close($db_link);

    echo "<html><head><title>Client Up Time</title>";
    echo "<style type=\"text/css\">" .
         "  table.sample {" .
	     "    border-width: 0px;" .
	     "    border-spacing: 2px;" .
	     "    border-style: none;" .
	     "    border-color: gray;" .
	     "    border-collapse: separate;" .
	     "    background-color: white;" .
         "  }" .
         "  table.sample th {" .
	     "    border-width: 0px;" .
	     "    padding: 2px;" .
	     "    border-style: inset;" .
	     "    border-color: gray;" .
	     "    background-color: rgb(250, 240, 230);" .
	     "    -moz-border-radius: ;" .
         "  }" .
         "  table.sample td {" .
	     "    border-width: 0px;" .
	     "    padding: 2px;" .
	     "    border-style: inset;" .
	     "    border-color: gray;" .
	     "    background-color: rgb(250, 240, 230);" .
	     "   -moz-border-radius: ;" .
         "  }" .
         "</style>";
    echo "</head>";
    echo "  <body>".$lastContactPage."</body>";
    echo "</html>";

That is it all we have to do now is enable the clients, or load our script to launchd. So on each of the clients run the following command:

launchctl load /Library/LaunchDaemons/org.theObfuscated.callHome.plist

That should be it … I have tested this, but in my hurry to put this together I might have included some errors in this post, please let me know so that I can correct them! I hope this provides a clear and clean example of how this all could work. Eventually I might post a more polished packaged solution that can be used by anyone.

Feel free to extend this or clean it up, and let me know so I can put it on the site.

Getting the size of a directory using bash

Sometimes as a system admin you would like to automate tasks based on how large a particular directory/folder is on a computer, or for a homework assignment in school. The very simple script below takes one argument, a path to the folder you would like to know the size of. It then will calculate the total size on the disk this folder and it contents take up and return in MB the folder size. It is a very simple script so I could see this being helpful to people new to bash scripting.

#!/bin/bash

# Author: Joseph J. Viscomi   E-Mail: jviscomi [at] brehm [dot] org || jviscomi [at] brehm [dot] org
# Date:   3/23/2011
# Arguments: Absolute path to a folder.
# Description: Prints the size of the folder in MB to standard out.
# Erros: Should handle all errors gracfully by returning -1.

# Checks to see that you gave it a directory and that it
# exists!
if [ $# = 1 ] && [ -d $1 ]
then
  du -sm $1 | cut -f 1
else
  # Echo -1 since NO folder can take up -1 M
  echo -1
fi

exit

Un-pausing printers in OS X as a non-administrator

A sore spot for me is the print server in OS X, talk about something that should be simple. The biggest headache we have had with printing in a 1-to-1 environment are pushing drivers out to different clients and that student and faculty printer keep on pausing and because they are not an administrator they cannot un-pause them, we are going to address the second issue here. I know you can add them to the lpadmin group and be done with it, but I don’t like giving people access unless absolutely necessary when I am responsible for the uptime and reliability of the machines.

In stead we added a bit of code to our login hooks so that if a printer does get paused once the end user restarts it will empty the printer queues and un-pause any paused printers. It is a very simple concept and very useful, and no ARD to un-pause a printer, just tell them to restart which they probably need to do anyway. Below is the unPausePrinters.sh:

#!/bin/bash

# Author: Joseph J. Viscomi    E-Mail: jjviscomi [at] gmail [dot] com || jviscomi [at] brehm [dot] org
# Date: 3/11/2011
# Description: This script should be used in a login hook. Upon loging on it clears any
#              print jobs in the printer queues, and unpauses any paused printers.

#EMPTYS ALL PRINTER QUEUES THAT ARE PAUSED
sudo cancel -a `lpstat -t | grep disabled | awk '{print $2}'`
#UNPAUSES PAUSED PRINTERS
sudo cupsenable `lpstat -t | grep disabled | awk '{print $2}'`
Performance Optimization WordPress Plugins by W3 EDGE