Release new version 0.28
[grml-crypt.git] / grml-crypt
index 40f95ea..73f206c 100755 (executable)
@@ -1,10 +1,9 @@
-#!/bin/sh
+#!/bin/bash
 # Filename:      grml-crypt
 # Purpose:       Program to format, mount and unmount encrypted devices/files
 # Authors:       Michael Gebetsroither <gebi@grml.org>
 # Bug-Reports:   see http://grml.org/bugs/
 # License:       This file is licensed under the GPL v2.
-# Latest change: Don Jul 26 19:57:28 CEST 2007 [mika]
 ################################################################################
 
 
@@ -35,16 +34,19 @@ DM_PATH_=""
 ACTION_=""
 DM_PREFIX_="grml-crypt_"
 FORCE_='false'
-OVERWRITE_SOURCE_DEV_='/dev/urandom'
+FSCK_='false'
+FSCK_EXTRA_OPTS_=""
+ENTROPY_SOURCE_='/dev/urandom'
 OPTIMIZED_MODE_SET_='false'
 OPTIMIZING_LEVEL_=0
-CIPHER_SIZE_="128"
+CIPHER_SIZE_="256"
 CIPHER_="aes-cbc-essiv:sha256"
-ITERATION_TIME_="1"
+ITERATION_TIME_="1000"
 ADDITIONAL_CRYPTSETUP_ARGS_=""
 READONLY_SET_='false'
 ADDITIONAL_MOUNT_ARGS_=""
 BATCH_MODE_="--batch-mode"
+PV_='/usr/bin/pv'
 
 ###
 ### __FUNCTIONS
@@ -65,6 +67,10 @@ OPTIONS:
    -o         optimised initialisation mode (should be as secure as the default but faster)
    -y         verifies the passphrase by asking for it twice
    -f         force file overwriting in format mode and/or disable confirmation dialog
+   -F         only for action start: run fsck before mounting the filesystem.
+              Use fsck's -f option if given twice.
+   -X         Read next argument as a list of options to pass to fsck:
+              'grml-crypt -FF -X "-y -T" start /dev/ice' will run fsck with options -y and -T.
    -m         additional arguments to mount
    -v         verbose (show what is going on, v++)
    -h         this help text
@@ -72,16 +78,16 @@ OPTIONS:
 CRYPTSETUP FORMAT OPTIONS:
    -S         cipher size, could be 128, 192 or 256 (default=$CIPHER_SIZE_)
    -C         cipher, should be aes-plain for pre-2.6.10 (default=$CIPHER_)
-   -I         iteration time spend with PBKDF2 password  processing in seconds (default=$ITERATION_TIME_)
-   -A         additional arguments for cryptsetup (only supportet by format)
+   -I         iteration time spent with PBKDF2 password processing in seconds (default=$ITERATION_TIME_)
+   -A         additional arguments for cryptsetup (only supported by format)
 
 ACTIONS:
    format  <device/file> [mountpoint]
               Format a device or a file (is created with the given size if it
               does not exist) with the given filesystem and mount it, if a
               mountpoint was given.
-   start  <device/file> <mountpoint>
-              Mount the device/file in the mountpoint.
+   start  <device/file> [mountpoint]
+              Mount the device/file in the mountpoint or to a default mountpoint.
    stop   <mountpoint>
               Umount the given mountpoint (umount, luksClose, losetup -d)
 
@@ -123,6 +129,10 @@ function formatDevice
 {
   type_="$1"  # could be donothing or init
   ret_=0
+  local ddcmd_="dd if=/dev/zero of=$DM_PATH_ bs=1M &>/dev/null"
+  if [[ -x "$PV_" && $verbose_ -ge 3 ]] ; then
+    ddcmd_="dd if=/dev/zero bs=1M 2>/dev/null | $PV_ | dd of=$DM_PATH_ bs=1M &>/dev/null"
+  fi
 
   args_="$VERIFY_PW_ $BATCH_MODE_ --key-size $CIPHER_SIZE_ --cipher $CIPHER_ --iter-time $ITERATION_TIME_ $ADDITIONAL_CRYPTSETUP_ARGS_"
   #args_=`echo "$args_" |tr -s ' '`
@@ -133,7 +143,7 @@ function formatDevice
   if [[ $type_ == 'init' && $OPTIMIZED_MODE_SET_ == 'true' ]]; then
     echo "finishing optimised initialisation (this could take some time)"
     # FIXME
-    execute "dd if=/dev/zero of=$DM_PATH_ bs=1M &>/dev/null" # || \
+    execute "$ddcmd_" # || \
     #  warn "could not finish optimised initialisation properly"
     ret_=$?
     # cutted out because of no space left on device error :(
@@ -149,7 +159,7 @@ function formatDevice
     warn "could not create filesystem on $DM_PATH_" 1
     return 1
   else
-    echo "Successully created $FSTYPE_ on encrypted $TARGET_"
+    echo "Successfully created $FSTYPE_ on encrypted $TARGET_"
     return 0
   fi
 }
@@ -159,13 +169,13 @@ function actionStart
 {
   ret_=0
 
-  # no mountpoint, by-by
   if [[ "$MOUNT_POINT_" == "" ]]; then
-    printUsage
-    die 'no mountpoint given'
-  fi
-  if [ ! -d "$MOUNT_POINT_" ]; then
-    die "mountpoint $MOUNT_POINT_ does not exist"
+    MOUNT_POINT_="/media/$DM_NAME_"
+  else
+    # error out if mountpoint was given but doesn't exist
+    if [ ! -d "$MOUNT_POINT_" ]; then
+      die "mountpoint $MOUNT_POINT_ does not exist"
+    fi
   fi
   # removed due to unionfs problem isLuks does not work with filesystem images
   # without losetup
@@ -184,8 +194,18 @@ function actionStart
   $READONLY_SET_ && cargs_='--readonly'
   execute "$CRYPTSETUP_ $cargs_ luksOpen $TARGET_ $DM_NAME_" warn || execute "losetup -d $TARGET_" || \
     die "could not luksOpen $TARGET_"
+  if [[ "$FSCK_" == "true" ]] ; then
+    execute "fsck $FSCK_EXTRA_OPTS_ -C $DM_PATH_" || die "fsck failed on $DM_PATH_"
+  elif [[ "$FSCK_" == "trueforce" ]] ; then
+    execute "fsck -f $FSCK_EXTRA_OPTS_ -C $DM_PATH_" || die "fsck failed on $DM_PATH_"
+  fi
   margs_=""
   $READONLY_SET_ && margs_='-r'
+  # mountpoint was not given so we use the default one which we need to create first
+  if [ ! -d "$MOUNT_POINT_" ]; then
+    execute "mkdir -p '$MOUNT_POINT_'" || die "failed to create mountpoint $MOUNT_POINT_"
+  fi
+  udevadm settle
   execute "mount $margs_ $ADDITIONAL_MOUNT_ARGS_ $DM_PATH_ $MOUNT_POINT_" die
 }
 
@@ -204,21 +224,39 @@ function actionStop
   dm_path_=`echo $dm_path_ |awk '{print $1}'` || die "could not get devicemapper name for $tmp_"
   dprint "dm_path_=\"$dm_path_\""
 
+  # check for symlinks
+  unset tmp_dm_path_
+  for dmapper in /dev/mapper/grml-crypt* ; do
+    link=$(readlink -f "$dmapper")
+    dprint "looping device mapper devices, dmapper=$dmapper => link=$link"
+    if [ "$link" = "$dm_path_" ] ; then
+      tmp_dm_path_="$dmapper"
+    fi
+  done
+
+  if [ -n "$tmp_dm_path_" ] ; then
+    dm_path_="$tmp_dm_path_"
+    unset tmp_dm_path_
+  fi
+
   dm_name_="${dm_path_##*/}"
   dprint "dm_name_=\"$dm_name_\""
 
-  dmsetup info $dm_name_ >/dev/null ||die "$dm_name_ is not aktive"
+  dmsetup info $dm_name_ >/dev/null ||die "$dm_name_ is not active"
   device_=`$CRYPTSETUP_ status $dm_name_ |awk '/device:/{print $2}'` || \
     die "could not get underlying device of $dm_path_"
   dprint "device_=\"$device_\""
 
   execute "umount $dm_path_" die "could not unmount $device_"
+  if [[ "$MOUNT_POINT_" == "/media/$dm_name_" ]]; then
+    rmdir "$MOUNT_POINT_"
+  fi
   execute "$CRYPTSETUP_ luksClose $dm_name_" die "could not close $dm_path_"
   echo "$device_" |grep loop &>/dev/null && execute "losetup -d $device_" \
     die "could not delete loop device $device_" || \
     execute "losetup -d $device_ &>/dev/null" eprint "could not delete loop device $device_, \
-this device could possible not be a loop device => maybe bogus error"
-  notice "$mp_ successfully unmountet/closed/deleted"
+this device possibly is not a loop device => maybe bogus error"
+  notice "$mp_ successfully unmounted/closed/deleted"
 }
 
 function yesDialog
@@ -242,6 +280,7 @@ function actionFormat
   IS_IMAGE_='false'
   ret_=0
   init_='init'
+  local ddcmd_
 
   if (( $SIZE_ < 3 )); then
     die "the minimum size of an encrypted luks partition should be 2"
@@ -262,13 +301,13 @@ function actionFormat
         execute "dd if=/dev/zero of=$TARGET_ bs=1M count=${SIZE_} &>/dev/null" \
           die "could not initialise $TARGET_ with /dev/zero"
       else
-        if [[ $OVERWRITE_SOURCE_DEV_ == '/dev/zero' ]]; then
-          echo "INSERCURE mode"
+        if [[ $ENTROPY_SOURCE_ == '/dev/zero' ]]; then
+          echo "INSECURE mode"
         else
           echo "SECURE mode (taking /dev/urandom as source, this could take some time)"
         fi
-        execute "dd if=$OVERWRITE_SOURCE_DEV_ of=$TARGET_ bs=1M count=${SIZE_} &>/dev/null" ||\
-          die "could not initialise $TARGET_ with $OVERWRITE_SOURCE_DEV_"
+        execute "dd if=$ENTROPY_SOURCE_ of=$TARGET_ bs=1M count=${SIZE_} &>/dev/null" ||\
+          die "could not initialise $TARGET_ with $ENTROPY_SOURCE_"
       fi
     fi
 
@@ -276,26 +315,30 @@ function actionFormat
 
     # TARGET_ is now /dev/loop<x>
     execute "losetup $TARGET_ $ORIG_TARGET_" die
-    if [[ $OPTIMIZED_MODE_SET_ == 'true' || $OVERWRITE_SOURCE_DEV_ == '/dev/zero' ]]; then
+    if [[ $OPTIMIZED_MODE_SET_ == 'true' || $ENTROPY_SOURCE_ == '/dev/zero' ]]; then
       execute "dd if=/dev/urandom of=$TARGET_ bs=1M count=2 &>/dev/null" \
       die "could not initialise the fist 2MB of $TARGET_ with /dev/urandom"
     fi
     formatDevice "$init_"
     ret_=$?
   else
-    $FORCE_ || (yesDialog "Are you shure you want to overwrite $TARGET_ ?" || die 'You are not sure')
+    $FORCE_ || (yesDialog "Are you sure you want to overwrite ${TARGET_}?" || die 'You are not sure')
     notice 'Operating on a device'
     echo -n 'Initialising device with '
     if [[ $OPTIMIZED_MODE_SET_ == 'true' ]]; then
       echo "optimised SECURE mode"
       execute "dd if=/dev/urandom of=$TARGET_ bs=1M count=2 &>/dev/null" ||\
         die "could not initialise the first 2MB of $TARGET_ with /dev/urandom"
-    elif [[ $OVERWRITE_SOURCE_DEV_ != '/dev/zero' ]]; then
+    elif [[ $ENTROPY_SOURCE_ != '/dev/zero' ]]; then
       # default mode
-      echo "SECURE mode (taking $OVERWRITE_SOURCE_DEV_ as source, this could take some time)"
-      execute "dd if=$OVERWRITE_SOURCE_DEV_ of=$TARGET_ bs=1M &>/dev/null" #||\
+      echo "SECURE mode (taking $ENTROPY_SOURCE_ as source, this could take some time)"
+      ddcmd_="dd if=$ENTROPY_SOURCE_ of=$TARGET_ bs=1M &>/dev/null"
+      if [[ -x "$PV_" && $verbose_ -ge 3 ]] ; then
+        ddcmd_="dd if=$ENTROPY_SOURCE_ bs=1M 2>/dev/null | $PV_ | dd of=$TARGET_ bs=1M &>/dev/null"
+      fi
+      execute "$ddcmd_" # ||\
         # skipped because "no space left on device" from dd
-        # die "could not initialise $TARGET_ with $OVERWRITE_SOURCE_DEV_"
+        # die "could not initialise $TARGET_ with $ENTROPY_SOURCE_"
     else
       echo 'INSECURE mode (only initialising the fist 2MB with /dev/urandom)'
       execute "dd if=/dev/urandom of=$TARGET_ bs=1M count=2 &>/dev/null" \
@@ -317,7 +360,7 @@ function actionFormat
       execute "mount $margs_ $ADDITIONAL_MOUNT_ARGS_ $DM_PATH_ $MOUNT_POINT_" die
     else
       if [[ $MOUNT_POINT_ != "" ]]; then
-        $mount_point_exists_ || warn "mountpoint $MOUNT_POINT_ does not exist, not mounting. please use \"grml-crypt start $ORIG_TARGET_ <mountpoint>\" to start the device"
+        $mount_point_exists_ || warn "mountpoint $MOUNT_POINT_ does not exist, not mounting. Please use \"grml-crypt start $ORIG_TARGET_ <mountpoint>\" to start the device"
       fi
       execute "$CRYPTSETUP_ luksClose $DM_NAME_" warn
       $IS_IMAGE_ && execute "losetup -d $TARGET_" warn
@@ -334,18 +377,25 @@ function actionFormat
 ### __MAIN
 ###
 
-while getopts "s:t:rzoyfm:hvS:C:I:A:" opt; do
+while getopts "s:t:rzoyfFm:hvS:C:I:A:X:" opt; do
   case "$opt" in
     s) SIZE_="$OPTARG"; SIZE_SET_='true' ;;
     t) FSTYPE_="$OPTARG" ;;
     r) READONLY_SET_='true' ;;
     z) let OPTIMIZING_LEVEL_=$OPTIMIZING_LEVEL_+1
-        OVERWRITE_SOURCE_DEV_='/dev/zero'
+        ENTROPY_SOURCE_='/dev/zero'
         warn 'initialising from INSECURE source /dev/zero' ;;
     o) let OPTIMIZING_LEVEL_=$OPTIMIZING_LEVEL_+1
         OPTIMIZED_MODE_SET_='true' ;;
     y) VERIFY_PW_="--verify-passphrase" ;;
     f) FORCE_='true' ;;
+    F) if [[ "$FSCK_" == "true" ]] ; then
+         FSCK_='trueforce'
+       else
+         FSCK_='true'
+       fi
+      ;;
+    X) FSCK_EXTRA_OPTS_="$OPTARG" ;;
     m) ADDITIONAL_MOUNT_ARGS_="$OPTARG" ;;
     h) printUsage; exit ;;
     v) let verbose_=$verbose_+1 ;;
@@ -372,12 +422,12 @@ if (( $# < 2 )); then
 fi
 if (( $OPTIMIZING_LEVEL_ > 1 )); then
   printUsage
-  die "please choose ONE initialisation methode"
+  die "please choose ONE initialisation method"
 fi
 TARGET_="$2"
 
-MKFS_="/sbin/mkfs.$FSTYPE_"
-if [ ! -x "$MKFS_" ]; then
+MKFS_="`which mkfs.$FSTYPE_`"
+if [ $? != "0" ]; then
   die "invalid filesystem type \"$FSTYPE_\"" 1
 fi