#!/bin/bash

# USB-Installer for Privatix Live-System
# Version 10.02.07 by Markus Mandalka
#
# Format and encrypt the choosen USB-Device and install Privatix into it


# print error message and abbort installing
error()
{
  $DIALOG --title "Error" --msgbox "$@" 0 0;
  exit 1;
}


unmount_device()
{
  # unmount device
  umount $@ >/dev/null 2>/dev/null

  # unmount all partitions on the device
  dev_part=${@/\/dev\/}
  for partition in $(udevinfo --export-db| egrep -o "/block/${dev_part}/.*");
  do
    devicepartition="/dev/$(udevinfo --query=name -p ${partition})"
    umount $devicepartition >/dev/null 2>/dev/null
  done
}


DIALOG="Xdialog";
installer_dir=$(dirname $0)

mount_target="/tmp/privatix-install-$$";
mount_base="/tmp/squashfs-$$";



# Language and messages

title_select="Install Privatix Live-System";
msg_select="\nChoose an usb-device (usb-key or external harddisk),
on which privatix will be installed:"

menuitem_none="None"
menuitem_none_description="No device"

msg_error_password="Error: The passwords did not match!"
title_password="Password";
msg_password_1="Password"
msg_password_2="Checking password"

title_password_admin="Admin-Password";
msg_password_admin_1="Password for software-administration:"
msg_password_admin_2="Checking admin-password:"




title_done="Installation done"
msg_done="Installation done.

You can now boot privatix from the usb-device."
msg_overwrite_ask_title="Overwrite old data?"
msg_overwrite_ask="
Overwrite old data on the device with random data?

This may take long time.

If you don't do it,
- parts of the data, that were on the device before
the installation could be restored by others very easy.
- others can find out, how much data is saved 
inside the encrypted partition.

If it is not only a test installation,
choose [yes] here !

Overwrite old data?";
title_overwrite="Deleting old data";
msg_overwrite="\nOverwriting device with random data ...";
title_are_you_sure="Danger: Data on this device will be deleted!!!";
msg_are_you_sure1="Are you absoluteley sure, that data on this device
should be overwritten?

"
msg_are_you_sure2="

If you selected the wrong device you will loose all data
on the usb-key or on the external harddisk!

If you choose < Yes >, there will be no return!

Realy continue and overwrite the selected device?";

msg_error_mounted="The selected device is mounted!

Please unmount it and start again!";


# Messages not used by the gui
# You don't have to translate them to support another language
msg_error_luksformat="Error while luksformat!";
msg_error_luksopen="Error while luksopen!";

msg_overwrite_done="Overwrite done.";
msg_luksformat="Encrypting device ...";
msg_luksopen="Opening encrypted device ...";
msg_umount_rootcrypt="Unmounting root-filesystem ...";
msg_syncing="Syncing unwritten data. Please wait ...";
msg_error_mkfs_root="Error while making filesystem on /dev/mapper/root_crypt ! Abort.";
msg_error_mount_boot="Error mounting boot-partition! Abort.";
msg_error_mount_root="Error mounting /dev/mapper/root_crypt ! Abort.";
msg_error_copy_root="Error while copy system to target! Maybe this parts of the cd-rom are not readable or there is not enough space on your usb-device.";
msg_error_umount_boot="Error while umount boot-partition ! Abort.";
msg_error_umount_root="Error while umount /dev/mapper/root_crypt ! Abort.";
msg_error_luksclose="Error while closing devicemaper with luksClose! Abort.";
msg_update_grub="
Writing bootmenu ...";
msg_copy_root="
Copy system into the encrypted partition.
This may take a while. Please wait ...";

msg_mkfs_root="

Formating root-filesystem:

";
msg_sfdisk="Writing partitiontable ...";
msg_mount_boot="
Mount boot-partition ...";
msg_mkfssetup="Setup crypttab and fstab";
msg_copy_boot="
Copy kernel to bootpartition. Please wait ...";
msg_grub_install="
Installing bootloader ...

"
msg_mkfs_boot="
Formating boot filesystem:
";
msg_error_copy_boot="
Error while copying! Abort.

Maybe the cd-rom is not readable.
";
msg_mount_proc="Mounting /proc ...";
msg_mount_dev="Mounting /dev ...";
msg_update_initramfs="
Creating Initramdisks with cryptroot setup ...";
msg_mkbootiso="

Creating boot-cd-iso ...";
msg_umount_proc="Unmounting /proc ...";
msg_umount_dev="Unmounting /dev ...";
msg_umount_boot="Unmounting /boot ...";
msg_error_grub_install="Error while grub-install! Abort.";
msg_error_update_grub="Error while update-grub ! Abort.";
msg_error_update_initramfs="Error while update-initramfs! Abort.";
msg_error_sfdisk="Error while writing partition table with sfdisk !

 Abort.";
msg_error_mount_proc="Error while mounting /proc to target! Abort.";
msg_error_mount_dev="Error while mounting /dev to target. Abort.";
msg_error_mount_base="Error mounting squashfs! Abort.";
msg_error_mkfs_boot="Error creating filesystem (mkfs.vfat on boot)! Abort.";

msg_mkfs_doc="Create filesystem for windows ...";
msg_error_mkfs_doc="Error while formating windows-filesystem!";
msg_mount_doc="Mounting windows readable filesystem ...";
msg_umount_doc="Unmounting windows readable filesystem ...";
msg_error_umount_doc="Error while unmounting windows readable filesystem!";

case "$LANG" in
de*|at*|ch*)

title_select="Privatix Installation";
msg_select="Wählen Sie das Gerät
(Speicherkarte, USB-Stick oder externe Festplatte),
auf dem Privatix installiert werden soll:"

menuitem_none="None"
menuitem_none_description="Kein Gerät"

title_done="Installation abgeschlossen"
msg_done="Die Installation wurde erfolgreich abgeschlossen.

Sie können Privatix nun vom eben eingerichteten Datenträger booten."

msg_error_password="Fehler: Das Passwort stimmt nicht überein!"
title_password="Passwort";
msg_password_1="Verschlüsselungspasswort eingeben:"
msg_password_2="Bitte das Verschlüsselungspasswort wiederholen:"

title_password_admin="Admin-Passwort";
msg_password_admin_1="Admin-Passwort für zukünftige Einstellungen eingeben:"
msg_password_admin_2="Bitte das Admin-Passwort wiederholen:"


msg_error_luksformat="Fehler beim Aufruf von luksformat!";
msg_error_luksopen="Fehler beim Aufruf von luksopen!";

msg_overwrite_ask_title="Alte Daten überschreiben?"
msg_overwrite_ask="
Soll der Datenträger mit Zufallsdaten überschrieben werden?

Dieser Schritt dauert bei grossen Festplatten sehr lange.

Wird das Überschreiben jedoch nicht durchgeführt,
- können Teile der Daten, die sich vor der Installation
auf diesem Datenträger befunden haben, mit einfachsten Mitteln
wieder her gestellt werden
- kann evtl. herausgefunden werden, wie viel Speicherplatz
im verschlüsselten Bereich tatsächlich belegt ist.

Wenn es sich nicht um eine reine Testinstallation handelt,
sollten Sie unbedingt [Ja] wählen!

Sollen vor der Installation alte Daten überschrieben werden?";
title_overwrite="Lösche alte Daten";
msg_overwrite="\nDer Datenträger wird mit Zufallsdaten überschrieben ...";
msg_overwrite_done="Das Überschreiben ist abgeschlossen.";
msg_luksformat="Verschlüssele das Gerät ...";
msg_luksopen="Öffne verschlüsseltes Gerät ...";
msg_umount_rootcrypt="Hänge das Root-Filesystem wieder aus ...";
msg_syncing="Synchronisiere noch ungeschriebene Daten. Bitte warten ...";
msg_error_mkfs_root="Fehler beim Anlegen des Filesystems auf /dev/mapper/root_crypt ! Abbruch.";
msg_error_mount_boot="Fehler beim Mounten der Boot-Partition ! Abbruch.";
msg_error_mount_root="Fehler beim Mounten von /dev/mapper/root_crypt ! Abbruch.";
msg_error_copy_root="Fehler beim Kopieren auf das Ziel!
Vielleicht kann die CD nicht richtig gelesen werden
oder auf dem Datenträger war zu wenig
freier Speicherplatz verfügbar.";
msg_error_umount_boot="Fehler beim Aushängen (umount) der Boot-Partition ! Abbruch.";
msg_error_umount_root="Fehler beim Aushängen (umount) von /dev/mapper/root_crypt ! Abbruch.";
msg_error_luksclose="Fehler beim Schliessen des Devicemappers mit luksClose! Abbruch.";
title_are_you_sure="Achtung: Daten auf diesem Datenträger werden gelöscht!!!";
msg_update_grub="
Schreibe Bootmenu ...";
msg_copy_root="

Kopiere das System in die verschlüsselte Partition.

Dies kann eine Weile dauern. Bitte warten ...";
msg_mkfs_root="

Formatiere Root-Dateisystem:

";
msg_sfdisk="Lege Partitionstabelle an ...";
msg_mount_boot="
Mounte Boot-Partition ...";
msg_mkfssetup="
Erstelle crypttab und fstab ...";
msg_copy_boot="
Kopiere Kernel in die Bootpartition. Bitte warten ...";
msg_grub_install="
Installiere den Bootloader ...

"
msg_mkfs_boot="
Formatiere Boot-Dateisystem:
";
msg_error_copy_boot="
Fehler beim Kopieren! Abbruch.

Vielleicht kann die CD nicht richtig gelesen werden?
";
msg_mount_proc="Mounte /proc in Target ...";
msg_mount_dev="Mounte /dev in Target ...";
msg_update_initramfs="
Aktualisiere Initramdisks mit Cryptroot-Einstellungen ...";
msg_mkbootiso="

Erstelle CD-Abbild der Boot-CD ...";
msg_umount_proc="Hänge im Target /proc wieder aus...";
msg_umount_dev="Hänge im Target /dev wieder aus...";
msg_umount_boot="Hänge das Boot-Filesystem wieder aus ...";
msg_error_grub_install="Fehler beim Aufruf von grub-install! Abbruch.";
msg_error_update_grub="Fehler beim Aufruf von update-grub ! Abbruch.";
msg_error_update_initramfs="Fehler bei update-initramfs! Abbruch.";
msg_error_sfdisk="Fehler beim Schreiben der Partitionstabelle mit sfdisk !

 Abbruch.";
msg_error_mount_proc="Fehler beim Mounten von /proc in Target! Abbruch.";
msg_error_mount_dev="Fehler beim Mounten von /dev in Target. Abbruch.";
msg_error_mount_base="Fehler beim Mounten des squashfs! Abbruch.";
msg_error_mkfs_boot="Fehler beim Anlegen des Filesystems (mkfs.vfat) auf boot! Abbruch.";


msg_mkfs_doc="Lege das unter Windows lesbare Dateisystem für die Dokumentation an ...";
msg_error_mkfs_doc="Fehler beim Anlegen des unter Windows lesbaren Dateisystems";
msg_mount_doc="Hänge unter Windows lesbares Dateisystem ein ...";
msg_umount_doc="Hänge unter Windows lesbares Dateisystem aus ...";
msg_error_umount_doc="Fehler beim Aushängen des Windows-Dateisystems";

msg_are_you_sure1="Sind Sie sich absolut sicher, dass der nachfolgende Datenträger
verwendet werden soll?

";
msg_are_you_sure2="

Falls Sie das falsche Gerät gewählt haben,
werden Daten auf einem anderen USB-Speicher
oder einer externen Festplatte überschrieben!

Wenn Sie mit < Ja > bestätigen, gibt es kein Zurück mehr
und auf dem gewählten Datenträger vorhandenen Daten sind verloren!

Wirklich fortfahren und den Datenträger formatieren?";

msg_error_mounted="Der zu verschlüsselnde Datenträger ist noch eingehängt
und wird offenbar noch genutzt!

Bitte schliessen Sie alle Programme, die auf Dateien des Datenträgers zugreifen,
hängen Sie den Datenträger aus und führen Sie dann dieses Programm erneut aus!";

;;
esac

modprobe dm-crypt

# Select USB-Device
filter="usb-devices"
TEMPFILE=/tmp/selection.$$

if ! partsel -d $DIALOG -f $filter -o $TEMPFILE -t "$title_select" -m "$msg_select" -nt "$menuitem_none" -nd "$menuitem_none_description"
then
  exit
fi

choice=`cat $TEMPFILE`
rm $TEMPFILE

if [ "$choice" == "$menuitem_none" ];
then
   exit
fi

device=$choice;

# Get infos about the device to ask, if it is the right one
model=$(udevinfo --query=env -p `udevinfo -q path -n $device` 2>/dev/null | grep "ID_MODEL=" | cut -f 2 -d "=" | sed s/_/\ /g| tr -d [:punct:])
bus=$(udevinfo --query=env -p `udevinfo -q path -n $device` 2>/dev/null | grep "ID_BUS=" | cut -f 2 -d "=" | sed s/_/\ /g)
size=$(LC_ALL=C fdisk -l $device 2>/dev/null | grep Disk | grep -i bytes | cut -f 1 -d "," | cut -f 3,4 -d " ");
vendor=$(udevinfo --query=env -p ${partition} 2>/dev/null | grep "ID_VENDOR=" | cut -f2 -d'='|sed s/_/\ /g| tr -d [:punct:])

modelandvendor="$model";
[ -n "$vendor" ] && modelandvendor="$modelandvendor ($vendor)";
msg_are_you_sure="$msg_are_you_sure1$device: $modelandvendor - $size$msg_are_you_sure2"

if ! $DIALOG --title "$title_are_you_sure" --yesno "$msg_are_you_sure" 0 0;
  then
    exit
fi;


# Ask password
PASSWORD1=$($DIALOG --stdout --title $title_password --passwordbox "$msg_password_1" 0 0) || exit
PASSWORD2=$($DIALOG --stdout --title $title_password --passwordbox "$msg_password_2" 0 0) || exit

if [ "$PASSWORD1" != "$PASSWORD2" ]
then
  error "$msg_error_password";
  exit 1;
fi
PASSWORD2="";

# Ask admin password
PASSWORDADMIN1=$($DIALOG --stdout --title $title_password_admin --passwordbox "$msg_password_admin_1" 0 0) || exit
PASSWORDADMIN2=$($DIALOG --stdout --title $title_password_admin --passwordbox "$msg_password_admin_2" 0 0) || exit

if [ "$PASSWORDADMIN1" != "$PASSWORDADMIN2" ]
then
  error "$msg_error_password";
  exit 1;
fi
PASSWORDADMIN2="";


unmount_device $device;

# check if the device or a parition on the device is mounted
if cat /etc/mtab | grep $device && echo $?
  then
    error "$msg_error_mounted";
fi

# ask if overwrite old data
if $DIALOG --title "$msg_overwrite_ask_title" --yesno "$msg_overwrite_ask" 0 0;
then

  # Overwrite old data
  dd bs=2M if=/dev/urandom | pv -n --size=$(fdisk -s $device)k 2>&1 >$device | $DIALOG --title "$title_overwrite" --gauge "$msg_overwrite" 0 0;
  clear;
  echo $msg_overwrite_done;

else
  # Overwrite begin of the old partition
  # so that the system won't try to mount it
  # after following initialize of the new partition table
  dd bs=2M count=1 if=/dev/zero of=$device
  clear;
fi;


# Create partitions
echo "$msg_sfdisk";
if ! sfdisk $device -uM <<EOF
,32,b
,96,L
,,L
EOF
then
 error "$msg_error_sfdisk";
fi

# Read the new partition table
partprobe $device

# Yet existing (if not overwritten) filesystems could be mounted again after rereading new partition table, so we unmount it again
unmount_device $device;

clear;

device_doc=${device}1
device_boot=${device}2
device_root=${device}3

# crypt device
echo "$msg_luksformat";
if ! echo -n "$PASSWORD1" | cryptsetup --batch-mode luksFormat $device_root
then
 error "$msg_error_luksformat";
fi;


# open crypted device
echo "$msg_luksopen";
if ! echo -n "$PASSWORD1" | cryptsetup luksOpen $device_root root_crypt
then
 error "$msg_error_luksopen";
fi;

PASSWORD1="";

# create filesystem
echo "$msg_mkfs_root"
if ! mkfs.ext3 /dev/mapper/root_crypt
then
 error "$msg_error_mkfs_root";
fi;

mkdir $mount_target
if ! mount /dev/mapper/root_crypt $mount_target
then
  error "$msg_error_mount_root";
fi

# mount the squashfs and copy system to target
echo "$msg_copy_root";
mkdir $mount_base
if ! mount -o loop /live/image/live/filesystem.squashfs $mount_base
then
  error "$msg_error_mount_base";
fi;

if ! cp -a $mount_base/* $mount_target/
then
  error "$msg_error_copy_root";
fi;

# /boot at root_crypt only as mount directory for the unencrypted boot-partition
rm -R $mount_target/boot
mkdir $mount_target/boot

# Remove installer
rm $mount_target/home/privatix/Desktop/Installation.desktop
rm $mount_target/usr/local/sbin/installer
# Remove builder
rm -R $mount_target/usr/local/src/privatix

echo "$msg_syncing";
sync

umount $device_boot >/dev/null 2>/dev/null

echo "$msg_mkfs_boot"
if ! mkfs.ext3 $device_boot
then
  error "$msg_error_mkfs_boot";
fi;



echo "$msg_mount_boot";

if ! mount $device_boot $mount_target/boot
then
  error "Error mounting $device_boot on $mount_target/boot ! Abort."
fi


echo "$msg_copy_boot";

if ! cp $mount_base/boot/* $mount_target/boot/
then
  error "$msg_error_copy_boot";
fi

echo "$msg_syncing";
sync


umount $device_doc >/dev/null 2>/dev/null

echo "$msg_mkfs_doc"
if ! mkfs.vfat -n Privatix $device_doc
then
  error "$msg_error_mkfs_doc";
fi;


echo "$msg_mount_doc";

mkdir $mount_target/win

if ! mount $device_doc $mount_target/win
then
  error "Error mounting $device_doc on $mount_target/win ! Abort."
fi



umount $mount_base
rmdir $mount_base


echo "$msg_mkfssetup";

root_uuid=`/lib/udev/vol_id -u $device_root`
boot_uuid=`/lib/udev/vol_id -u $device_boot`
doc_uuid=`/lib/udev/vol_id -u $device_doc`

# Create fstab
echo "# /etc/fstab: static file system information.
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
proc            /proc           proc    defaults        0       0
/dev/mapper/root_crypt /               ext3    errors=remount-ro 0       1
/dev/disk/by-uuid/$boot_uuid /boot ext3 defaults 0 1
/dev/disk/by-uuid/$doc_uuid /win vfat noauto,ro,noexec,nosuid 0 1" >$mount_target/etc/fstab

# Create crypttab
echo "root_crypt /dev/disk/by-uuid/$root_uuid none luks" >$mount_target/etc/crypttab

# Create kernel-img.conf
echo "do_initrd = yes" >>$mount_target/etc/kernel-img.conf

# Set hostname
echo "privatix" > $mount_target/etc/hostname

# Set hosts
cat >> $mount_target/etc/hosts << EOF
127.0.0.1 localhost
127.0.1.1 privatix

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
EOF


echo "$msg_grub_install";

mkdir $mount_target/boot/grub
echo "(hd0) $device" >$mount_target/boot/grub/device.map;

if ! /usr/sbin/grub-install --no-floppy --root-directory=$mount_target $device
then
  error "$msg_error_grub_install";
fi

echo "$msg_mount_proc";
if ! mount -t proc /proc $mount_target/proc
then
  error "$msg_error_mount_proc";
fi;

echo "$msg_mount_dev";
if ! mount -o bind /dev $mount_target/dev
then
  error "$msg_error_mount_dev";
fi;

echo "$msg_update_grub";
if ! chroot $mount_target update-grub
then
  error "$msg_error_update_grub";
fi

echo "$msg_update_initramfs";
# Create new initramdisk because of changed crypttab
if ! chroot $mount_target update-initramfs -u
then
  error "$msg_error_update_initramfs";
fi;

echo "$msg_mkbootiso";
# Create boot.iso containing this ramdisk with our crypttab
chroot $mount_target/ /usr/local/sbin/mkbootiso

# Delete packages that are not needet on usb-device
chroot $mount_target/ apt-get -y purge live-helper
chroot $mount_target/ apt-get -y autoremove

# set root- and user-password
chroot $mount_target/ chpasswd -c MD5 <<EOF
root:$PASSWORDADMIN1
privatix:$PASSWORDADMIN1
EOF

# Copy doc to windows-readable partition
cp /live/image/usb.html $mount_target/win/index.html
cp /live/image/style.css $mount_target/win
cp /live/image/autorun.bat $mount_target/win
cp /live/image/autorun.inf $mount_target/win
cp $mount_target/boot/boot.iso $mount_target/win

echo "$msg_umount_dev";
umount $mount_target/dev
echo "$msg_umount_proc";
umount $mount_target/proc

echo "$msg_umount_doc";
if ! umount $device_doc
then
  error "$msg_error_umount_doc";
fi


echo "$msg_umount_boot";
if ! umount $device_boot
then
  error "$msg_error_umount_boot";
fi

echo "$msg_umount_rootcrypt";
if ! umount /dev/mapper/root_crypt
then
  error "$msg_error_umount_root";
fi

if ! cryptsetup luksClose root_crypt
then
  error "$msg_error_luksclose";
fi

rmdir $mount_target
$DIALOG --title "$title_done" --msgbox "$msg_done" 0 0
