#!/usr/bin/ksh93 ################################################################ function usagemsg_dodwipe_k93 { print " Program: dodwipe_k93 This script will perform a DoD style disk wipe of a file, logical volume, or disk partition. It performs 3 passes, first pass fills the space with zero's using an octal 0 character, second pass fills the space with one's using an octal 377 character, and the third pass fills the space with random bits. Usage: ${1##*/} [-?vV] [-w] [-1|-2|-3] -f fileName | -l lvName | -p pvName Where: -f fileName = full path file name of a file to wipe clean (/home/username/filename) -l lvName = full path file name of a logical volume to wipe clean (/dev/vgName/lvName) -p pvName = full path file name of a physical volume to wipe clean (/dev/rdsk/sdx#) -w = turn off warning message and confirmation prompt -1 = Do NOT perform Pass 1: Do NOT overwrite space with zero's (0) -2 = Do NOT perform Pass 2: Do NOT overwrite space with one's (1) -3 = Do NOT perform Pass 3: Do NOT overwrite space with random bits -v = Verbose mode - displays dodwipe_k93 function info -V = Very Verbose Mode - debug output displayed -? = Help - display this message Author: Dana French (dfrench@mtxia.com) Copyright 2014, All Rights Reserved \"AutoContent\" enabled " } ################################################################ #### #### Description: #### #### This script will perform a DoD style disk wipe of a file, logical #### volume, or disk partition. It performs 3 passes, first pass fills the #### space with zero's using an octal 0 character, second pass fills the #### space with one's using an octal 377 character, and the third pass fills #### the space with random bits. #### #### Assumptions: #### #### This script assumes the existance of /dev/zero to generate continuous #### stream of 0's. If /dev/zero does not exist, this script will generate #### it's own continuous stream of zero's or one's, but it takes much longer #### to run. #### #### Dependencies: #### #### This script is dependent upon the Unix utility "dd" and uses it to #### overwrite logical volumes and physical volumes. #### #### Products: #### #### The product of this shell script are wiped clean and overwritten files, #### logical volumes and physical volumes. The result is NOT a newly #### initialize file, logical volume, or physical volume. The result is a #### file, LV, or PV where every bit has been overwritten multiple times, #### then every byte is overwritten with a random set of bits. #### #### Configured Usage: #### #### This shell script can be executed as a standalone script, or included in #### a function library to be referenced and used by other shell scripts. #### #### Details: #### ################################################################ configure_dodwipe_k93() { #### #### Notice this function is a POSIX function so that it can see local #### and global variables from calling functions and scripts. #### #### Configuration parameters can be stored in a file and #### this script can be dynamically reconfigured by sending #### the running script a HUP signal using the kill command. #### #### Configuration variables can be defined in the configuration file using #### the same syntax as defining a shell variable, e.g.: VARIABLE="value" CFILE=~/.dodwipe_k93.conf (( VERBOSE == TRUE )) && print -- "# Configuration File: ${CFILE}" if [[ -f ${CFILE} ]] then (( VERBOSE == TRUE )) && cat ${CFILE} . ${CFILE} fi return 0 } ################################################################ function dodwipe_k93 { typeset VERSION="1.0" typeset TRUE="1" typeset FALSE="0" typeset VERBOSE="${FALSE}" typeset VERYVERB="${FALSE}" typeset FILETOGGLE="${FALSE}" typeset FINAME="" typeset LVTOGGLE="${FALSE}" typeset LVNAME="" typeset PVTOGGLE="${FALSE}" typeset PVNAME="" typeset WARNTOGGLE="${TRUE}" typeset P1TOGGLE="${TRUE}" typeset P2TOGGLE="${TRUE}" typeset P3TOGGLE="${TRUE}" typeset BSIZE="1024" typeset CFILE typeset TFILE typeset BLOCK typeset SKIP typeset BCNT typeset ANS typeset LV typeset PV typeset OF typeset R typeset i #### #### Set up a trap of the HUP signal to cause this script #### to dynamically configure or reconfigure itself upon #### receipt of the HUP signal. trap "configure_dodwipe_k93 ${0}" HUP #### Read the configuration file and initialize variables by #### sending this script a HUP signal kill -HUP ${$} #### Process the command line options and arguments. while getopts ":vVw123f:l:p:" OPTION do case "${OPTION}" in 'f') FITOGGLE="${TRUE}" FINAME="${OPTARG}";; 'l') LVTOGGLE="${TRUE}" LVNAME="${OPTARG}";; 'p') PVTOGGLE="${TRUE}" PVNAME="${OPTARG}";; 'w') WARNTOGGLE="${FALSE}";; '1') P1TOGGLE="${FALSE}" P2TOGGLE="${FALSE}" P3TOGGLE="${FALSE}";; '2') P2TOGGLE="${FALSE}" P3TOGGLE="${FALSE}";; '3') P3TOGGLE="${FALSE}";; 'v') VERBOSE="${TRUE}";; 'V') VERYVERB="${TRUE}";; '?') usagemsg_dodwipe_k93 "${0}" && return 1 ;; ':') usagemsg_dodwipe_k93 "${0}" && return 1 ;; '#') usagemsg_dodwipe_k93 "${0}" && return 1 ;; esac done shift $(( ${OPTIND} - 1 )) (( VERYVERB == TRUE )) && set -x (( VERYVERB == TRUE )) && VERBOSE="${TRUE}" (( VERBOSE == TRUE )) && print -u 2 "# Program Name...: ${0}" (( VERBOSE == TRUE )) && print -u 2 "# Version........: ${VERSION}" (( VERBOSE == TRUE )) && print -u 2 "# Block Size.....: ${BSIZE}" (( VERBOSE == TRUE )) && (( P1TOGGLE == TRUE )) && print -u 2 "# PASS 1 Request.: TRUE" (( VERBOSE == TRUE )) && (( P2TOGGLE == TRUE )) && print -u 2 "# PASS 2 Request.: TRUE" (( VERBOSE == TRUE )) && (( P3TOGGLE == TRUE )) && print -u 2 "# PASS 3 Request.: TRUE" (( VERBOSE == TRUE )) && (( P1TOGGLE == FALSE )) && print -u 2 "# PASS 1 Request.: FALSE" (( VERBOSE == TRUE )) && (( P2TOGGLE == FALSE )) && print -u 2 "# PASS 2 Request.: FALSE" (( VERBOSE == TRUE )) && (( P3TOGGLE == FALSE )) && print -u 2 "# PASS 3 Request.: FALSE" ################################################################ #### #### Check the command line options and arguments and verify that required #### information has been provided, and that it is of the correct type, and #### that it makes sense. If anything is incorrect, then return from this #### function and display the usage message by trapping the exit. trap "usagemsg_dodwipe_k93 ${0}" EXIT #### #### Check the file name, logical volume, and physical volume toggle #### variables. If they are all set to FALSE, issue an error message and #### return from the script. Tell the user they must specify at least one of #### these. if (( FITOGGLE == FALSE )) && (( LVTOGGLE == FALSE )) && (( PVTOGGLE == FALSE )) then print -u 2 -- "# SYNTAX ERROR: You must specify a file, logical volume, or physical partition." return 10 fi #### #### If the user specified a filename to wipe on the command line, check to see if #### it is a regular file. If not, issue an error message and return from the script. if (( FITOGGLE == TRUE )) then OF="${FINAME}" if [[ ! -f "${FINAME}" ]] then print -u 2 -- "# $( ls -l ${FINAME} )" print -u 2 -- "# ERROR: The file name specified \"${FINAME}\" is not a regular file." return 11 fi (( VERBOSE == TRUE )) && print -u 2 "# File Name......: ${FINAME}" fi #### #### If the user specified a logical volume to wipe on the command line, check to see if #### it is a block device file. If not, issue an error message and return from the script. if (( LVTOGGLE == TRUE )) && OF="${LVNAME}" then OF="${LVNAME}" if [[ ! -b "${LVNAME}" ]] then print -u 2 -- "# $( ls -l ${LVNAME} )" print -u 2 -- "# ERROR: The Logical Volume name specified \"${LVNAME}\" is not a block device." return 12 fi (( VERBOSE == TRUE )) && print -u 2 "# Logical Volume.: ${LVNAME}" fi #### #### If the user specified a logical volume to wipe on the command line, check to see if #### it is a block device file. If not, issue an error message and return from the script. if (( PVTOGGLE == TRUE )) && OF="${PVNAME}" then OF="${PVNAME}" if [[ ! -c "${PVNAME}" ]] then print -u 2 -- "# $( ls -l ${PVNAME} )" print -u 2 -- "# ERROR: The Physical Volume name specified \"${PVNAME}\" is not a character device." return 13 fi (( VERBOSE == TRUE )) && print -u 2 "# Physical Volume: ${PVNAME}" fi #### #### Check the data wipe PASS toggles selected on the command line. If the #### first data wipe pass is turned off, then return from the function and #### inform the user that all data wipe passes are disabled. The first pass #### is a requirement before other passes can be executed. if (( P1TOGGLE == FALSE )) then print -u 2 -- "# All data wipe passes are disabled." return 10 fi #### #### Check the data wipe PASS toggles selected on the command line. If the #### second data wipe pass is false, but the third is true, then some sort of #### error has occurred. Each pass must be executed in order, so it is not #### allowed to run pass 1, and pass 3, but NOT pass 2. if (( P2TOGGLE == FALSE )) && (( P3TOGGLE == TRUE )) then print -u 2 -- "# ERROR: You must first execute PASS 2 before you can execute PASS 3" return 10 fi if [[ ! -c /dev/zero ]] then print -u 2 -- "# ERROR: The ZERO device /dev/zero must exist as a character device" return 15 fi trap "-" EXIT ################################################################ #### #### Warn the user that they are about to wipe clean whatever storage device #### they specified, ask them to verify they really want to do this. If the #### user specified the "-w" command line option, do not ask, just do it. if (( WARNTOGGLE == TRUE )) then print -- "# The storage area \"${OF}\" is about to be wiped clean and overwritten." print -n -- "# Are you sure you want to wipe clean/overwrite \"${OF}\" (y/N)? " read ANS if [[ "_${ANS}" != _[Yy] ]] then print "# You did not answer \"Y\" or \"y\", exiting program." return 99 fi fi ################################################################ #### Pass 1: fill the space with zero's (\0) if (( P1TOGGLE == TRUE )) then if (( FITOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 -- "# $( ls -l ${FINAME} )" (( VERBOSE == TRUE )) && print -u 2 -- "# Pass 1 (0's)...: Overwritting every bit with zero's" TFILE="/tmp/tmp${$}.out" if cp "${FINAME}" "${TFILE}" then tr '[[:print:][:cntrl:][:xdigit:][:space:]]' '\0' < "${TFILE}" > "${FINAME}" fi [[ -f "${TFILE}" ]] && rm -f "${TFILE}" fi #### #### Check to see if the /dev/zero device exists, if so use it to generate a #### continuous stream of zeros to overwrite all the bits of the targeted #### storage space. if [[ -c /dev/zero ]] then if (( LVTOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 "# Pass 1 (0's)...: /dev/zero" dd bs=${BSIZE} of="${LVNAME}" if=/dev/zero fi if (( PVTOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 "# Pass 1 (0's)...: /dev/zero" dd bs=${BSIZE} of="${PVNAME}" if=/dev/zero fi else #### #### This "else" code is not currently active because /dev/zero is required to exist (( VERBOSE == TRUE )) && print -u 2 "# ZERO Device....: none" if (( LVTOGGLE == TRUE )) || (( PVTOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 "# Pass 1 (0's)...: while looping" BLOCK="" for (( i=0; i<${BSIZE}; ++i )) do R=$'\0' BLOCK="${BLOCK}${R}" done # SKIP=0 # while print -- "${BLOCK}" | dd bs=${BSIZE} of="${OF}" count=1 skip=${SKIP} # do # (( ++SKIP )) # done fi fi fi ################################################################ #### Pass 2: fill the space with one's (\377) if (( P2TOGGLE == TRUE )) then if (( FITOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 -- "# Pass 2 (1's)...: Overwritting every bit with one's" TFILE="/tmp/tmp${$}.out" if cp "${FINAME}" "${TFILE}" then tr '\0' '\377' < "${TFILE}" > "${FINAME}" fi [[ -f "${TFILE}" ]] && rm -f "${TFILE}" fi #### #### Check to see if the /dev/zero device exists, if so use it to generate a #### continuous stream of zeros, then translate those zeros to one's and #### overwrite all the bits of the targeted storage space. if [[ -c /dev/zero ]] then if (( LVTOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 "# Pass 2 (1's)...: tr conv < /dev/zero" tr '\0' '\377' < /dev/zero | dd bs=${BSIZE} of="${LV}" fi if (( PVTOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 "# Pass 2 (1's)...: tr conv < /dev/zero" tr '\0' '\377' < /dev/zero | dd bs=${BSIZE} of="${PV}" fi else #### #### This "else" code is not currently active because /dev/zero is required to exist (( VERBOSE == TRUE )) && print -u 2 "# ZERO Device....: none" if (( LVTOGGLE == TRUE )) || (( PVTOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 "# Pass 2 (1's)...: while looping" BLOCK="" for (( i=0; i<${BSIZE}; ++i )) do R=$'\377' BLOCK="${BLOCK}${R}" done # SKIP=0 # while print -- "${BLOCK}" | dd bs=${BSIZE} of="${OF}" count=1 skip=${SKIP} # do # (( ++SKIP )) # done fi fi fi ################################################################ #### Pass 3: fill the space with random bits (( RANDOM % 377 )) if (( P3TOGGLE == TRUE )) then if (( FITOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 "# Pass 3 (random): Overwritting every byte with random bits" TFILE="/tmp/tmp${$}.out" if cp "${FINAME}" "${TFILE}" then BCNT=0 > "${FINAME}" tr '\377' '\n' < "${TFILE}" | while read -- C do R=$( printf "%o" $(( ${RANDOM} % 377 )) ) print -n -- "\\0${R}" >> "${FINAME}" (( ++BCNT )) if (( VERBOSE == TRUE )) then if (( BCNT >= BSIZE )) then print -u 2 -n -- "." BCNT=0 fi fi done (( VERBOSE == TRUE )) && print -u 2 -- "." fi [[ -f "${TFILE}" ]] && rm -f "${TFILE}" (( VERBOSE == TRUE )) && print -u 2 -- "# $( ls -l ${FINAME} )" fi if (( LVTOGGLE == TRUE )) || (( PVTOGGLE == TRUE )) then (( VERBOSE == TRUE )) && print -u 2 "# Pass 3 (random): while looping" SKIP=0 while :; do BLOCK="" for (( i=0; i<${BSIZE}; ++i )) do R=$( printf "%o" $(( ${RANDOM} % 377 )) ) BLOCK="${BLOCK}\\0${R}" done if ! print -- "${BLOCK}" | dd bs=${BSIZE} of="${OF}" count=1 skip=${SKIP} then break fi (( ++SKIP )) done fi fi trap "-" HUP return 0 } ################################################################ dodwipe_k93 "${@}"