Collecting Log Files from Users via Self Service

cainehorr
Contributor III

Yesterday, my boss approached me and handed me this challenge...

THERE ARE NO ISSUES - ONLY OPPORTUNITIES TO IMPROVE
"I need to acquire the /var/log/system.log from user X. I don't want to walk over to the user's desk. We might need to do this again in the future. Can Jamf do this?"

My immediate response was, "Why yes! Jamf CAN do this!"

INTO THE WEEDS WE GO
Here are the hurdles I had to endure...

  • We don't use file servers so there's not a single SMB or AFP share to send files to.
  • Security has a "No SMB" policy.
  • SSH is disabled and therefore Recon is a no go.
  • No ARD ability.

This leaves me to figure out how to drop files into a secure location on a particular cloud sharing platform OR use email.

I chose email...

LET'S GET SCRIPTING, KIDDIES

So here is the script I wrote. It's far from perfect. I'm sure there some stuff I could do better.

The script zips up /var/logs/system.log into a nice, neat package with a unique file name and saves it to /tmp/.

The script then sends the zip file via sendmail as an attachment to the email address of your choice, but before we can do that, we need to enable postfix on the Mac.

We also need to do some fancy footwork on mime encoding, etc. YOIKES!

And then there's house keeping duties.

At the end of the day, I placed the following script into a Self Service policy...

You'll have to edit certain stuffs so this works in your environment - stuffs such as to/from email addresses, etc.

NOTE - The script can also be run in stand-alone mode without Jamf.

#!/bin/bash

# Description: Sends a user's /var/log/system.log to the email address of your choosing

# Written by Caine Hörr
# Written on 2017-10-31

# I gratuitously cannibalized sendmail code from http://backreference.org/2013/05/22/send-email-with-attachments-from-script-or-command-line/

main(){
    sanity_checks # Check all required dependencies
    postfix_lookup_table_modify # Create/Modify the Postfix lookup table from the sasl_passwd file
    postfix_stop_service # Stop postfix
    postfix_start_service # Start postfix
    local_system_attributes # Acquire and format system specific attributes
    compress_log_files # Compress log files in to zip format
    generate_email # Creates and sends email containing log files
    cleanup # Cleanup / Housekeeping
    quit # Quit notification
}

sanity_checks(){
    run_as_root
    postfix_main_cf_confirmation
    postfix_sasl_password_confirmation
}

run_as_root(){
    # Check for admin/root permissions
    if [ "$(id -u)" != "0" ]; then
        # Quit script immediately.
        echo "Script must be run as root, or have root privileges (ie. sudo)."
        quit
        exit 1
    fi
}

postfix_main_cf_confirmation(){
    # Set variable
    main_cf="/etc/postfix/main.cf"

    # Check existence of /etc/postfix/main.cf
    if [ -f "${main_cf}" ]; then
        echo "SUCCESS: ${main_cf} exists."

        # Confirm contents of /etc/postfix/main.cf are correct...
        postfix_main_cf_check_settings

        # Return to sanity_checks
    else
        # Fatal error. Quit script immediately.
        echo "ERROR: ${main_cf} does not exist!"
        quit    
        exit 1
    fi
}

postfix_main_cf_check_settings(){
    # Set variable
    main_cf_settings=`more /etc/postfix/main.cf | grep -i "SOME VALUE THAT YOU WANT TO SEARCH FOR GOES HERE"`

    if [ "${main_cf_settings}" = "# SOME VALUE THAT YOU WANT TO SEARCH FOR GOES HERE SMTP Relay Settings" ]; then
        echo "SUCCESS: ${main_cf} has been configured with proper settings."
    else
        echo "WARNING: ${main_cf} has not been configured with proper settings."

        # Append settings to /etc/postfix/main.cf
        postfix_main_cf_configure_settings
    fi
}

postfix_main_cf_configure_settings(){
# Write the following contents to /etc/postfix/main.cf
echo "NOTICE: Configuring ${main_cf} with proper settings."
cat <<EOT >> /etc/postfix/main.cf

# SOME VALUE THAT YOU WANT TO SEARCH FOR GOES HERE SMTP Relay Settings
relayhost=smtp.yourcompany.com:587
smtp_sasl_auth_enable=yes
smtp_sasl_password_maps=hash:/etc/postfix/sasl_passwd
smtp_use_tls=yes
smtp_tls_security_level=encrypt
tls_random_source=dev:/dev/urandom
smtp_sasl_security_options=noanonymous
smtp_always_send_ehlo=yes
smtp_sasl_mechanism_filter=plain
EOT
echo "SUCCESS: ${main_cf} has been configured with proper settings."
}

postfix_sasl_password_confirmation(){
    # Set variable
    sasl_passwd="/etc/postfix/sasl_passwd"

    # Check existence of /etc/postfix/sasl_passwd
    if [ -f "${sasl_passwd}" ]; then
        echo "SUCCESS: ${sasl_passwd} exists."

        # Confirm contents of /etc/postfix/sasl_passwd are correct...
        postfix_sasl_passwd_check_settings
    else
        echo "WARNING: ${sasl_passwd} does not exist."    
        # Create /etc/postfix/sasl_passwd with coreect contents...
        postfix_sasl_passwd_create_modify
    fi
}

postfix_sasl_passwd_check_settings(){
    sasl_passwd_settings=`more /etc/postfix/sasl_passwd | grep "smtp.yourcompany.com"`

    if [ "${sasl_passwd_settings}" = "smtp.yourcompany.com:587 username:password" ]; then
        echo "SUCCESS: ${sasl_passwd} has been configured with correct settings."
    else
        echo "WARNING: ${sasl_passwd} has not been configured with correct settings."

        # Append correct settings to /etc/postfix/sasl_passwd
    fi
}

postfix_sasl_passwd_create_modify(){
# Write the following contents to /etc/postfix/sasl_passwd
echo "NOTICE: Configuring ${sasl_passwd} with correct settings."
cat <<EOT >> /etc/postfix/sasl_passwd
smtp.yourcompany.com:587 username:password
EOT
}

postfix_lookup_table_modify(){
    # Create/Modify the Postfix lookup table from the sasl_passwd file
    # This will create /etc/postfix/sasl_passwd.db
    echo "NOTICE: Creating the postfix lookup table."
    sudo postmap /etc/postfix/sasl_passwd
}

postfix_stop_service(){
    # Stop postfix
    echo "NOTICE: Stopping the postfix service."
    sudo /usr/sbin/postfix stop
}

postfix_start_service(){
    # Start postfix
    echo "NOTICE: Starting the postfix service."
    sudo /usr/sbin/postfix start    
}

local_system_attributes(){
    local_username=`/usr/bin/stat -f "%Su" /dev/console`
    echo "Local Username: ${local_username}"
    local_hostname=`hostname`
    echo "Local Hostname: ${local_hostname}"
    local_date=`date +"%Y-%m-%d_%I%M%S%p_%Z"`
    echo "Local Date: ${local_date}"
}

compress_log_files(){
    # Compress system.log file
    log_file_path="/var/log/system.log"
    zip_file_name="${local_date}_${local_hostname}_${local_username}.zip"
    zip_file_path="/tmp/${zip_file_name}"

    echo "Compressing ${log_file_path} to ${zip_file_path}"
    zip ${zip_file_path} ${log_file_path}
}

generate_email(){
    # some variables
    # refactoring the script such that all these values are
    # passed from the outside as arguments should be easy

    from="jss@yourcompany.com"
    to="recipient@yourcompany.com"
    subject="${zip_file_name} from Jamf Pro Self Service"
    boundary="ZZ_/afg6432dfgkl.94531q"
    body="See attached zip file"
    declare -a attachments
    attachments="${zip_file_path}"
    mimetype="application/zip"

# Build headers
{

printf '%s
' "From: $from
To: $to
Subject: $subject
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="${boundary}"

--${boundary}
Content-Type: text/plain; charset="US-ASCII"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

$body

--${boundary}
Content-Type: application/zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="${zip_file_path}"
"

base64 "$zip_file_path"
echo

# print last boundary with closing --
printf '%s
' "--${boundary}--"

} | sendmail -t -oi   # one may also use -f here to set the envelope-from

}

cleanup(){
    rm -f ${zip_file_path}
}

quit(){
    # Quit notification.
    echo "Quitting..."
}

main

exit

FOLLOW-UP
So hay - if you have any thoughts or suggestions to make this better... I'm all ears!

Thanks for reading!

Cheers!

Kind regards,

Caine Hörr

A reboot a day keeps the admin away!

5 REPLIES 5

Look
Valued Contributor III

You couldn't just use curl with a PUT to a webserver? Or would that contravene other organisational rules?
I have no actual idea how to configure this, just thought it might be easier than emailing and could be given a front end for easily reading the files as well.

gachowski
Valued Contributor II

Great share Caine, Thank you !!!

C

seanhansell
Contributor

I would look into something like ElasticSearch/Logstash to accomplish like something this. Use Jamf to install MetricBeat on end user machines, and have the logs sent to ES and displayed with a tool like Kibana on a central server. This is what we use in production and it’s a life saver having all that raw data accesssible and graphable in the browser.

- Sean

cainehorr
Contributor III

@seanhansell @Look

If such options were (or should become) available to me, I'd certainly make use of them! ;-)

Kind regards,

Caine Hörr

A reboot a day keeps the admin away!

IT-Chris
New Contributor III

does this script still work??? the logs look like its working but I dont see the file in the /tmp folder. and I dont get any emails.