#!/bin/bash # # ODBackup.bash # # Author: Eddie Kelley # # This script attempts to duplicate the Open Directory service's "Archive" functionality # # After archiving an Open Directory master with this script, you should end up with a # sparseimage whose contents can be restored using the Server Admin program. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # self_help(){ echo "" echo "Open Directory script for Mac OS X Server v.10.5" echo "" echo "This script attempts to create a restorable archive of the Open Directory" echo "configuration and data, storing it in an encrypted disk image" echo "" echo usage: ODBackup.bash [ -o output_archive_name] [ -p passphrase] [-v] [-r] [-n] [-h] echo "-o specifies the path to the output archive" echo "-p specifies a passphrase to use for encrypting the resulting archive" echo "-v provides verbose logging" echo "-r specifies that a random password should be generated with uuidgen (implies -n)" echo "-n send notification of backup completion and image passphrase" echo "-h show this dialog" echo "" echo example: echo "ODBackup.bash -o ~/Desktop/odbackup.sparseimage -p password" echo "" echo "Administrative privileges are required to run this script" echo "" } check_root() { if [ `whoami` != "root" ] then echo "Insufficient permissions: this script must be executed as root" self_help exit 1; fi } # verify that the script is being executed with privileges check_root NOTIFY_SUBJECT="OpenDirectory backup key" NOTIFY_TO="admin@example.com" VERBOSE="NO" NOTIFY="NO" BACKUP_DIR="/tmp/ldap_bk" LOCAL_KDC="`/usr/bin/dscl localhost read /Local/Default/Config/KerberosKDC RealName | sed s/RealName..//`" OD_KDC="`/usr/bin/dscl localhost read /LDAPv3/127.0.0.1/Config/KerberosKDC RealName | sed s/RealName..//`" HOSTNAME=`/bin/hostname` PRIMARY_IPV4="`host $HOSTNAME | sed s/.*address.//`" backup_ldap(){ if [ "$VERBOSE" = "YES" ]; then echo "Backing up LDAP database..." fi /usr/sbin/slapcat -l $BACKUP_DIR/backup.ldif /bin/cp /var/db/openldap/openldap-data/DB_CONFIG $BACKUP_DIR /bin/cp -R /private/etc/openldap $BACKUP_DIR/openldap } backup_pwdb(){ if [ "$VERBOSE" = "YES" ]; then echo "Backing up password server database..." fi /bin/mkdir -p $BACKUP_DIR/passwordserver_backup /usr/sbin/mkpassdb -backupdb $BACKUP_DIR/passwordserver_backup /bin/cp /Library/Preferences/com.apple.passwordserver.plist $BACKUP_DIR /usr/sbin/mkpassdb -list > $BACKUP_DIR/sasl-plugin-list /bin/hostname > $BACKUP_DIR/hostname } backup_kerberos(){ if [ "$VERBOSE" = "YES" ]; then echo "Backing up Kerberos database..." fi /usr/sbin/kdb5_util -r $LOCAL_KDC dump > "$BACKUP_DIR/kdb5dump.$LOCAL_KDC.bak" /usr/sbin/kdb5_util -r $OD_KDC dump > $BACKUP_DIR/kdb5dump.$OD_KDC.bak /usr/sbin/sso_util info -pr /Local/Default > $BACKUP_DIR/local_krb5realm.plist /usr/sbin/sso_util info -pr /LDAPv3/127.0.0.1 > $BACKUP_DIR/local_odkrb5realm.plist /usr/bin/tar -czpf $BACKUP_DIR/krb5backup.tar.gz /var/db/krb5kdc/kdc.conf /var/db/krb5kdc/kadm5.acl /var/db/krb5kdc/kadm5.keytab /var/db/krb5kdc/.k5.* /Library/Preferences/edu.mit.Kerberos /etc/krb5.keytab 2>&1 /bin/cp /var/db/dslocal/nodes/Default/config/KerberosKDC.plist $BACKUP_DIR/KerberosKDC.plist } backup_config(){ if [ "$VERBOSE" = "YES" ]; then echo "Backing up configuration files..." fi /bin/mkdir $BACKUP_DIR/LaunchDaemons /bin/cp /System/Library/LaunchDaemons/com.apple.PasswordService.plist $BACKUP_DIR/LaunchDaemons /bin/cp /System/Library/LaunchDaemons/org.openldap.slapd.plist $BACKUP_DIR/LaunchDaemons /bin/cp /System/Library/LaunchDaemons/org.openldap.slurpd.plist $BACKUP_DIR/LaunchDaemons /bin/cp /System/Library/LaunchDaemons/com.apple.kdcmond.plist $BACKUP_DIR/LaunchDaemons /bin/cp /System/Library/LaunchDaemons/edu.mit.kadmind.plist $BACKUP_DIR/LaunchDaemons /bin/cp /System/Library/LaunchDaemons/smbd.plist $BACKUP_DIR/LaunchDaemons /bin/cp -R /Library/Preferences/DirectoryService $BACKUP_DIR/DirectoryService } backup_ds(){ if [ "$VERBOSE" = "YES" ]; then echo "Backing up local directory database..." fi /bin/cp /Library/Preferences/com.apple.openldap.plist $BACKUP_DIR /usr/bin/sw_vers > $BACKUP_DIR/version.txt /bin/cp -R /var/db/dslocal $BACKUP_DIR/dslocal /usr/bin/tar -czf $BACKUP_DIR/shadowbackup.tar.gz /var/db/shadow/hash 2>&1 /usr/bin/tar -czf "$BACKUP_DIR/sambabackup.tar.gz" /var/db/samba /etc/smb.conf 2>&1 KEYCHAIN_OUTPUT="`security find-generic-password -g -s com.apple.opendirectory /Library/Keychains/System.keychain 2>&1`" PASSWORD="`echo "$KEYCHAIN_OUTPUT" | head -n 1 | sed s/password...// | sed 's/"//'`" echo "$PASSWORD" > $BACKUP_DIR/keychain /bin/echo $PRIMARY_IPV4 | cat > $BACKUP_DIR/primary_ipv4 /usr/bin/touch $BACKUP_DIR/id_omitfile } # create a disk image that can be used to restore the OD service make_image(){ if [ "$VERBOSE" = "YES" ]; then echo "Creating archive..." fi /bin/echo -n "$IMAGE_PW" | /usr/bin/hdiutil create -ov -quiet -plist -puppetstrings -layout "UNIVERSAL CD" -fs "HFS+" -volname ldap_bk -srcDir $BACKUP_DIR -format SPARSE -encryption AES-256 -stdinpass $IMAGE_PATH } # cleanup after image creation cleanup(){ if [ "$VERBOSE" = "YES" ]; then echo "Cleaning up..." fi # we should use srm here, but it takes a long time rm -rf $BACKUP_DIR } send_mail(){ NOTIFY_BODY="OpenDirectory on `hostname` was backed up successfully. The key for this backup is: $IMAGE_PW" echo "$NOTIFY_BODY" | mail -s "$NOTIFY_SUBJECT" "$NOTIFY_TO" } # parse command-line arguments while getopts o:p:rvnh SWITCH do case $SWITCH in o) IMAGE_PATH=$OPTARG;; p) IMAGE_PW=$OPTARG;; r) IMAGE_PW="`uuidgen`" NOTIFY="YES";; v) VERBOSE="YES";; n) NOTIFY="YES";; h) self_help && exit 0;; *) self_help && exit 1;; esac done # main script function main(){ if [ "$IMAGE_PATH" = "" ]; then self_help echo "" echo "Error: the image path must be specified" exit 1 fi /bin/mkdir -p $BACKUP_DIR backup_ldap backup_pwdb backup_kerberos backup_config backup_ds make_image cleanup if [ "$NOTIFY" = "YES" ]; then send_mail fi } main