#! /bin/bash # # ################################################################### # scriptname="`basename $0`" [ -z "${scriptname}" ] && scriptname="lfd" scriptversion="0.97" # # ################################################################### # showlic() { # echo "" case $LANG in fr*) echo "lfd (LUKSfile for dummies) v.${scriptversion}: Permet de créer / monter / démonter" echo " facilement un fichier-container chiffré au format LUKS.." ;; *) echo "lfd (LUKSfile for dummies) v.${scriptversion}: Allows users to easily create /mount / dismount" echo " LUKS encrypted files as encrypted filesystems." ;; esac echo "" echo "Written by Swâmi Petaramesh , 2007/11/13" echo "Modified by Swâmi Petaramesh , 2007/11/15" echo "Copyright (c) Swâmi Petaramesh , 2007" echo "" case $LANG in fr*) echo "Ce programme est un Logiciel Libre: Vous pouvez le redistribuer" echo "et/ou le modifier selon les termes de la GNU General Public License" echo "publiée par la Free Software Foundation, version 3 de la licence," echo "ou, à votre choix, toute version ultérieure." echo "" echo "Ce programme est distribué dans l'espoir qu'il sera utile, mais" echo "SANS AUCUNE GARANTIE; sans même aucune garantie implicite" echo "relative à un usage commercial ou à son adéquation à une" echo "utilisation spécifique. Référez-vous à la GNU General Public" echo "License pour plus de détails." echo "" echo "Vous devriez avoir reçu une copie de la GNU General Public License" echo "avec ce programme. Sinon, voir " ;; *) echo "This program is free software: you can redistribute it and/or modify" echo "it under the terms of the GNU General Public License as published by" echo "the Free Software Foundation, either version 3 of the License, or" echo "(at your option) any later version." echo "" echo "This program is distributed in the hope that it will be useful," echo "but WITHOUT ANY WARRANTY; without even the implied warranty of" echo "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" echo "GNU General Public License for more details." echo "" echo "You should have received a copy of the GNU General Public License" echo "along with this program. If not, see " ;; esac echo "" } # # ################################################################### # shortlic() { echo "" case $LANG in fr*) echo "${scriptname} Copyright (c) 2007 Swâmi Petaramesh " echo "Ce programme est fourni SANS AUCUNE GARANTIE sous licence GPL." echo "C'est un Logiciel Libre, et vous avez le droit de le redistribuer" echo "sous certaines conditions; voir '${scriptname} --license' pour les details." ;; *) echo "${scriptname} Copyright (c) 2007 Swâmi Petaramesh " echo "This program comes with ABSOLUTELY NO WARRANTY under GPL license." echo "This is free software, and you are welcome to redistribute it" echo "under certain conditions; type '${scriptname} --license' for details." ;; esac echo "" } # # ################################################################### # usage() { echo "Script usage:" echo "" case $LANG in fr*) echo "${scriptname} (-h|--help|--sudohelp|--license): Aide détaillée et licence." echo "" echo "${scriptname} [-v] [-F|-F32] (create|mount|umount|on|off|status) []" echo "" echo "Exemples:" echo "- ${scriptname} secret create 100 : Crée un container chiffré 'secret' de 100 Mo." echo "- ${scriptname} secret on : Ouvre et monte le container chiffré 'secret'." echo "- ${scriptname} secret off : Démonte et verrouille le container chiffré 'secret'." echo "- ${scriptname} secret status : Affiche l'état du container chiffré 'secret'." ;; *) echo "${scriptname} (-h|--help|--sudohelp|--license): Displays help or license details." echo "" echo "${scriptname} [-v] (create|mount|umount|on|off|status) []" echo "" echo "Examples:" echo "- ${scriptname} secret create 100 : Creates a 100 MB 'secret' encrypted container." echo "- ${scriptname} secret on : Open and mounts the 'secret' encrypted container." echo "- ${scriptname} secret off : Unmounts and locks the 'secret' encrypted container." echo "- ${scriptname} secret status : Shows status of the 'secret' encrypted container." ;; esac echo "" } # # ################################################################### # fullhelp() { shortlic case $LANG in fr*) # 1...+....1....+....2....+....3....+....4....+....5....+....6....+....7....5..8 echo "Ce script crée / monte / démonte un système de fichier chiffré LUKS qui se" echo "trouvera dans un fichier ordinaire du répertoire personnel de l'utilisateur." echo "Le fichier container s'appellera '.truc' et sera monté dans le répertoire de" echo "l'utilisateur en tant que sous-répertoire 'truc'." echo "Le fichier container sera un container chiffré LUKS standard utilisant AES" echo "avec une clé de 256 bits." echo "" echo "Si un chemin de fichier (optionnel) est spécifié dans le nom du container," echo "il sera créé et monté sous le chemin demandé, ce qui permet de créer le" echo "container sur une unité amovible (clé USB etc)." echo "" echo "Une fois le container monté, les répertoires et fichiers qu'il contient sont" echo "accessibles pour toute personne ayant accès aux fichiers de l'utilisateur," echo "incluant l'administrateur système 'root'." echo "Une fois le container démonté / verrouillé, les répertoires et fichiers qu'il" echo "contient sont chiffrés et totalement inaccessibles sans l'usage de la phrase" echo "secrète. Même l'administrateur 'root' ne pourra pas accéder aux contenu du" echo "système chiffré sans la phrase secrète." echo "Quand le système est arrêté ou redémarré, le container chiffré est toujours" echo "automatiquement démonté et verrouillé." echo "" echo "ATTENTION: Si vous oubliez votre phrase secrète, le contenu du système de" echo "fichiers sera DÉFINITIVEMENT IRRÉCUPÉRABLE." echo "" usage echo "-v Exécution bavarde" echo "" echo "-F|-F32 (Création seulement) Formatage du volume en FAT ou FAT32, ce qui" echo " permet de le rendre utilisable sous MS Windows avec le logiciel" echo " FreeOTFE. N.B.: Le 'fsck' de volumes FAT est impossible." echo "" echo "${scriptname} create : Crée et formate un container chiffré appelé" echo " '.' de méga-octets dans le répertoire personnel" echo " de l'utilisateur." echo "" echo "${scriptname} (mount|on): Demande la phrase secrète du container '<.nom_fichier>'" echo " et le monte comme sous-répertoire '' du répertoire" echo " personnel de l'utilisateur." echo "" echo "${scriptname} (umount|off): Démonte et verrouille complètement le container" echo " chiffré, à condition qu'aucun des fichiers qu'il contient ne soit" echo " ouvert. (Rebooter ou arrêter la machine laisse toujours le container" echo " verrouillé)." echo "" echo "${scriptname} status: Affiche l'état actuel du container." echo "" echo "Si vous souhaitez utiliser ce script sans devoir taper le mot de passe 'sudo" echo "root' à chaque fois, tapez: ${scriptname} --sudohelp" ;; *) echo "This script creates / mounts / dismounts a LUKS encrypted filesystem which" echo "will be hosted in a regular file in the home directory of the user." echo "The container file will be called '.something' and mount under the user's" echo "home directory as a 'something' subdirectory." echo "The container file will be a standard, portable LUKS container encrypted" echo "using AES-256." echo "" echo "If an (optional) pathname is specified in the container's name, it will be" echo "created and mounted in the requested path, which allows creating the" echo "container on a removable device (i.e. USB key)." echo "" echo "Once the container is mounted, the directories and files it holds will be" echo "visible for everybody who has access to the user's files (this includes the" echo "system administrator 'root')." echo "Once the container is unmounted / locked, the directories and files it holds" echo "are completely encrypted and unacessible to anybody who doesn't know the" echo "passphrase. Even the system administrator 'root' cannot access the container" echo "contents without the passphrase." echo "When the system is halted or rebooted, the encrypted filesystem is always" echo "automatically dismounted and locked." echo "" echo "CAUTION: If you forget your passphrase, the encrypted filesystem contents" echo "will be IRREMEDIABLY LOST." echo "" usage echo "-v Verbose execution" echo "" echo "-F|-F32 (For creation only) Formats the volume using FAT16 or FAT32, that" echo " makes it usable under MS Windows with 'FreeOTFE'." echo " N.B.: 'fsck' is not possible for FAT volumes." echo "" echo "${scriptname} create : Will create and format a LUKS encrypted" echo " container called '.' of megabytes in the user's" echo " home directory." echo "" echo "${scriptname} (mount|on): Will ask passphrase for encrypted container" echo " '.' and mount it as the '' directory under" echo " the user's home directory." echo "" echo "${scriptname} (umount|off): Will completely unmount and lock the encrypted" echo " container, provided there are no open files on it. (Powering the" echo " system off or rebooting will always leave the encrypted filesystem" echo " locked)." echo "" echo "${scriptname} status: Will show the current status of the encrypted container." echo "" echo "If you would like to use this script without having to type the 'sudo root" echo "password' everytime, type: ${scriptname} --sudohelp" ;; esac echo "" echo "" } # # ################################################################### # sudohelp() { shortlic case $LANG in fr*) echo "Ce script fait un usage extensif de la commande 'sudo' pour exécuter des " echo "commandes habituellement réservées à l'administrateur système 'root'." echo "Pour pouvoir utiliser ce script sans devoir taper le mot de passe 'sudo root'" echo "à chaque fois, il vous faut ajouter une ligne à la fin du fichier /etc/sudoers" echo "ce qui se fait en utilisant la commande 'sudo visudo'." echo "ATTENTION: Faire cela ajoutera des privilèges spécifiques mount/format/crypt" echo "à votre profil utilisateur ordinaire." echo "" echo "Ajoutez la ligne ci-dessous, exactement telle quelle, en remplaçant seulement" echo "'john' par votre propre identifiant utilisateur, au fichier sudoers." ;; *) echo "This script makes extensive use of the 'sudo' command to execute commands" echo "usually reserved to the 'root' system administrator." echo "To be able to use this script without having to type the 'sudo root password'" echo "everytime, you should add a line for your user profile to the /etc/sudoers" echo "file, which can be done using the 'sudo visudo' command." echo "CAUTION: Doing so will give special devices mount/format/crypt privileges" echo "to your normal user profile." echo "" echo "Add the line shown below, exactly like this, to the sudoers file. Just replace" echo "'john' with your own user ID." ;; esac echo "" echo "john localhost=(root) NOPASSWD: /sbin/modprobe, /sbin/losetup, /sbin/cryptsetup, /usr/bin/file, /sbin/mke2fs, /sbin/e2fsck, /bin/mount, /bin/umount, /bin/chown" echo "" echo "" } # # ################################################################### # SCRIPT PARAMETERS # # ################################################################### # cipher="aes-cbc-essiv:sha256" keysize="256" kmodules="aes_i586 sha256 loop dm_mod dm_crypt" # # ################################################################### # END OF SCRIPT PARAMETERS # # ################################################################### # # FUNCTIONS ######################################################### missingbin() { shortlic case $LANG in fr*) echo "ERREUR !" echo "Le programme '$1' est nécessaire pour ce script, mais n'a pas été trouvé." echo "Ce programme fait normalement partie du paquetage '$2'." echo "" echo "Veuillez installer ce programme pour pouvoir poursuivre." echo "Si vous utilisez Ubuntu ou Debian, vous pouvez l'installer en tapant la commande:" ;; *) echo "ERROR !" echo "Program '$1' est required for this script, but has not been found." echo "This program is normally part of package '$2'." echo "" echo "Please install this program before continuing." echo "If you use Ubuntu or Debian, you can install it by typing the command:" ;; esac echo "" echo "sudo aptitude install $2" echo "" exit 1 } # ------------------------------------------------------------------- paramorder() { shortlic case $LANG in fr*) echo "ERREUR d'ordre de paramètres: Le nom du container doit être donné avant" echo " l'action à effectuer." ;; *) echo "Parameters order ERROR: Please specify container name before action." ;; esac echo "" usage exit 1 } doubleaction() { shortlic case $LANG in fr*) echo "ERREUR: Deux actions différentes ont été demandées !" echo " Une seule action est possible." ;; *) echo "ERROR: Several different actions requested !" echo " Only one action is allowed at a time." ;; esac echo "" usage exit 1 } # ------------------------------------------------------------------- sizemissing() { shortlic case $LANG in fr*) echo "ERREUR: La taille du container doit être spécifiée pour l'action 'create' !" ;; *) echo "ERROR: Container size must be specified for 'create' action !" ;; esac echo "" usage exit 1 } invalidsize() { shortlic case $LANG in fr*) echo "ERREUR: La taille du container indiquée : (${size}) doit être composée uniquement de chiffres !" ;; *) echo "ERROR: Container size specified (${size}) must contain numbers only !" ;; esac echo "" usage exit 1 } toosmall() { shortlic case $LANG in fr*) echo "ERREUR: La taille du container indiquée : (${size}) est trop petite ! (Mini. 5 Mo)" ;; *) echo "ERROR: Container size specified (${size}) is too small (Min. 5 MB) !" ;; esac echo "" usage exit 1 } toobig() { shortlic case $LANG in fr*) echo "ERREUR: Le container demandé est trop gros (${size} Mo) !" ;; *) echo "ERROR: Container requested is too big (${size} MB) !" ;; esac echo "" usage exit 1 } # =================================================================== checkmodules() { for m in ${kmodules}; do if ! ${egrep} -q "^${m}[[:space:]]+" /proc/modules; then [ "$verbose" == "1" ] && echo -n "Loading '${m}' kernel module... " ${sudo} ${modprobe} ${m} if ! ${egrep} -q "^${m}[[:space:]_]" /proc/modules; then [ "$verbose" == "1" ] && echo "FAILED !" case $LANG in fr*) echo "ERREUR: Echec de chargement du module ${m} !" ;; *) echo "ERROR: Failed loading kernel module ${m} !" ;; esac exit 1 fi [ "$verbose" == "1" ] && echo "OK." fi done } # =================================================================== get_freespace() { frespace="" testmount="${cdir}" while [ -n "${testmount}" ]; do if ${egrep} -q "[[:space:]]${testmount}[[:space:]]" /proc/mounts; then freespace="`df -m ${testmount} | ${tail} -n 1 | ${gawk} '{print $4}'`" echo "${freespace}" | ${egrep} -q "^[0-9]+$" && break fi oldtestmount=${testmount} testmount="${oldtestmount%/*}" if [ "${testmount}" == "${oldtestmount}" ] || (( ${#testmount} <= 1 )); then break; fi done if ! echo "${freespace}" | ${egrep} -q "^[0-9]+$"; then testmount="/" freespace="`df -m ${testmount} | ${tail} -n 1 | ${gawk} '{print $4}'`" fi if echo "${freespace}" | ${egrep} -q "^[0-9]+$"; then [ "$verbose" == 1 ] && echo "Free space on ${testmount} partition: ${freespace} MB." else case $LANG in fr*) echo "WARNING: Impossible de déterminer l'espace libre pour la partition '${cdir}'." ;; *) echo "WARNING: Cannot determine free space on '${cdir}' partition." ;; esac freespace="" fi } # =================================================================== find_loopdev() { [ "$verbose" == "1" ] && echo -n "Looking for available loop device... " loopdev="" for (( i=0; i<=7; i++ )); do ${sudo} ${losetup} /dev/loop${i} >/dev/null 2>&1 && continue loopdev="/dev/loop${i}"; break done if [ -n "${i}" ]; then [ "$verbose" == "1" ] && echo "/dev/loop${i}; OK." else [ "$verbose" == "1" ] && echo "FAILED !" case $LANG in fr*) echo "ERREUR: Aucun loopback device disponible ! Abandon." ;; *) echo "ERROR: No loopback device available ! Aborting." ;; esac exit 1 fi } # ------------------------------------------------------------------- loop_del() { if [ -n "${loopdev}" ]; then lds="${loopdev}" else regfile=${cfile//\//\\/} lds="`/bin/bash -c \"for (( d=0; d<=7; d++ )); do ${sudo} ${losetup} /dev/loop\\\${d} 2>/dev/null ; done\" \ | ${gawk} \"BEGIN {FS=\\\":\\\"; ORS= \\\" \\\"} /${regfile}/ {print \\\$1}\"`" fi for loopdev in ${lds}; do if ${sudo} ${losetup} ${loopdev} | ${egrep} -q "${cfile}"; then case $LANG in fr*) echo "Désactivation du loop device ${loopdev}... " ;; *) echo "Deactivating ${loopdev} loop device... " ;; esac ${sudo} ${losetup} -d ${loopdev} >/dev/null 2>&1 if ! ${sudo} ${losetup} ${loopdev} >/dev/null 2>&1 ; then echo "OK." else echo "FAILED !" case $LANG in fr*) echo "ERREUR: Echec de désactivation de ${loopdev} ! Abandon." ;; *) echo "ERROR: Failed deactivating ${loopdev} ! Aborting." ;; esac exit 1 fi else echo "WARNING: Loop device ${loopdev} not affected to ${cfile} where expected to be !" fi done sync } # ------------------------------------------------------------------- loop_set() { case $LANG in fr*) echo -n "Affectation du container ${cfile} au loop device ${loopdev}... " ;; *) echo -n "Setting up ${cfile} container as ${loopdev} loop device... " ;; esac if ${sudo} ${losetup} ${loopdev} >/dev/null 2>&1; then if ${sudo} ${losetup} ${loopdev} | ${egrep} -q "${cfile}"; then echo "Already affected. Skipping." return 0 else echo "FAILED !" case $LANG in fr*) echo "ERREUR: Loop device ${loopdev} indisponible ! Abandon." ;; *) echo "ERROR: Loop device ${loopdev} unavailable ! Aborting." ;; esac exit 1 fi fi ${sudo} ${losetup} ${loopdev} ${cfile} >/dev/null 2>&1 if ${sudo} ${losetup} ${loopdev} | ${egrep} -q "${cfile}"; then echo "OK." else echo "FAILED !" case $LANG in fr*) echo "ERREUR: Echec de création du loop device ! Abandon." ;; *) echo "ERROR: Failed creating loop device ! Aborting." ;; esac exit 1 fi sync } # ------------------------------------------------------------------- # Workaround for ugly Debian bug #444914 close_tempdevs() { sleep 1 for closeme in `${find} /dev/mapper/ -type b -name "temporary-cryptsetup-[0-9]*"`; do closeme="`basename ${closeme}`" echo -n "Closing cryptsetup temporary file : ${closeme}... " sleep 1 ${sudo} ${cryptsetup} remove ${closeme} [ "$?" == "0" ] && echo "OK." || echo "FAILED !" done sync } # ------------------------------------------------------------------- close_luks() { case $LANG in fr*) echo -n "Fermeture du volume chiffré ${luksname}... " ;; *) echo -n "Closing encrypted ${luksname} LUKS volume... " ;; esac if ! [ -b "${cdev}" ]; then echo "Already inactive. Skipping." close_tempdevs return 0 fi sync ${sudo} ${cryptsetup} luksClose ${luksname} if [ "$?" != "0" -o -b "${cdev}" ]; then echo " FAILED !" case $LANG in fr*) echo "ERREUR: Echec de fermeture du volume chiffré ${luksname} ! Abandon." echo "" echo "ATTENTION: Vos données chiffrées demeurent accessibles !" ;; *) echo "ERROR: Failed closing encrypted ${luksname} volume ! Aborting." echo "" echo "WARNING: Your encrypted data are still accessible !" ;; esac exit 1 fi echo "OK." sync close_tempdevs } # ------------------------------------------------------------------- open_luks() { case $LANG in fr*) echo "Activation du volume chiffré ${luksname}... " ;; *) echo "Activating ${luksname} encrypted volume... " ;; esac if [ -z "${loopdev}" ] || ! ${sudo} ${losetup} ${loopdev} | ${egrep} -q "${cfile}"; then case $LANG in fr*) echo "ERREUR: Le loop device ${loopdev} n'est pas actif ! Abandon." ;; *) echo "ERROR: Loop device ${loopdev} inactive ! Aborting." ;; esac exit 1 fi if [ -b "${cdev}" ]; then if ${sudo} ${cryptsetup} status ${luksname} | ${egrep} -q "${loopdev}"; then echo "Already active. Skipping." return 0 else case $LANG in fr*) echo "ERREUR: Un device chiffré ${cdev} est déjà associé à un autre container !" echo " Vérifiez que vous n'avez pas ouvert un container de même nom" echo " pour deux utilisateurs différents ! Abandon." ;; *) echo "ERROR: Encrypted evice ${cdev} is associated to another container !" echo " Please check you haven't opened a container with the same name" echo " for 2 different users ! Aborting." ;; esac loop_del exit 1 fi fi ${sudo} ${cryptsetup} luksOpen ${loopdev} ${luksname} if ! [ "$?" == "0" -a -b "${cdev}" ]; then case $LANG in fr*) echo "ERREUR: Echec d'activation du volume chiffré ${luksname} ! Abandon." ;; *) echo "ERROR: Failed activating encrypted volume ${luksname} ! Aborting." ;; esac close_tempdevs loop_del exit 1 fi echo "OK." sync close_tempdevs } # =================================================================== do_umount() { if ${egrep} -q "[[:space:]]${mpoint}[[:space:]]" /proc/mounts; then case $LANG in fr*) echo "Vérification des fichiers ouverts dans le volume chiffré ${luksname}... " ;; *) echo "Checking for open files in the encrypted volume ${luksname}... " ;; esac if ${lsof} ${mpoint}; then echo "" case $LANG in fr*) echo "ERREUR: il y a des fichiers actuellement ouverts dans le volume chiffré !" echo "" echo "Il est impossible de le démonter tant que des fichiers ou répertoires" echo "sont ouverts." echo "Vérifiez que vous avez fermé toutes les applications utilisant ces fichiers" echo "Et que vous n'avez pas un gestionnaire de fichiers ou un 'shell' ouvert" echo "dans un répertoire chiffré." echo "" echo "ERREUR: Echec de fermeture du volume chiffré ! Abandon." echo "" echo "ATTENTION: Vos données chiffrées demeurent accessibles !" ;; *) echo "ERROR: There are open files in the encrypted volume !" echo "" echo "We cannot unmount the encrypted volume as long as files are open." echo "Please check that you have closed all applications using encrypted files" echo "and that you don't have a file manager or a 'shell' open in an" echo "encrypted directory." echo "" echo "ERROR: Failed closing encrypted volume ! Aborting." echo "" echo "WARNING: Your encrypted data are still accessible !" ;; esac echo "" exit 1 else case $LANG in fr*) echo -n "Démontage du volume ${luksname} de ${mpoint}... " ;; *) echo -n "Unmounting ${luksname} from ${mpoint}... " ;; esac sync ${sudo} umount ${mpoint} if [ "$?" != "0" ] || ${egrep} -q "[[:space:]]${mpoint}[[:space:]]" /proc/mounts; then echo "FAILED !" case $LANG in fr*) echo "ERREUR: Echec de démontage du volume chiffré ${mpoint} ! Abandon." echo "" echo "ATTENTION: Vos données chiffrées demeurent accessibles !" ;; *) echo "ERROR: Failed unmounting ${mpoint} encrypted volume ! Aborting." echo "" echo "WARNING: Your encrypted data are still accessible !" ;; esac echo "" exit 1 else echo "OK." fi fi else case $LANG in fr*) echo "Le volume chiffré ${mpoint} n'est pas monté." ;; *) echo "The ${mpoint} encrypted volume is not mounted." ;; esac fi sync close_luks loop_del } # ------------------------------------------------------------------- do_premount() { [ -z "${loopdev}" ] && find_loopdev if ${sudo} ${losetup} ${loopdev} 2>/dev/null | ${egrep} -q ${cfile}; then case $LANG in fr*) echo "Le fichier ${cfile} est associé à ${loopdev}." ;; *) echo "${cfile} file is associated to ${loopdev}." ;; esac elif ${sudo} ${losetup} ${loopdev} >/dev/null 2>&1; then case $LANG in fr*) echo "ERREUR: Le loop device ${loopdev} est affecté à un autre fichier ! Abandon." ;; *) echo "ERROR: Loop device ${loopdev} is associated to another file ! Aborting." ;; esac loop_del exit 1 else if ! [ -f "${cfile}" -a -r "${cfile}" -a -w "${cfile}" ]; then case $LANG in fr*) echo "ERREUR: Le fichier container ${cfile} n'existe pas, ou n'est pas accessible en écriture ! Abandon." ;; *) echo "ERROR: Container file ${cfile} doesn't exist, or is not writable ! Aborting." ;; esac exit 1 elif ! [ -O ${cfile} ]; then case $LANG in fr*) echo "ERREUR: Le fichier container ${cfile} n'appartient pas à ${cuser} ! Abandon." ;; *) echo "ERROR: Container file ${cfile} doesn't belong to ${cuser} ! Aborting." ;; esac exit 1 fi loop_set fi } # ------------------------------------------------------------------- do_mount() { if ${egrep} -q "^${cdev}[[:space:]]+${mpoint}[[:space:]]" /proc/mounts; then case $LANG in fr*) echo "Le volume chiffré ${luksname} est déjà monté." ;; *) echo "The ${luksname} encrypted volume is already mounted." ;; esac return 0 fi if [ -b "${cdev}" ]; then case $LANG in fr*) echo "Le volume chiffré ${luksname} est actif." ;; *) echo "The ${luksname} encrypted volume is active." ;; esac else do_premount open_luks fi fat="" if ! ${sudo} ${file} -s ${cdev} | ${egrep} -q "ext[23] filesystem"; then if ${sudo} ${file} -s ${cdev} | ${egrep} -q 'FAT \((12|16|32) bit\)'; then echo "Detected FAT filesystem." fat="1" else case $LANG in fr*) echo "ERREUR: ${cdev} contient un système de fichiers non supporté, ou n'est pas formaté ! Abandon." echo "ATTENTION: Le volume chiffré ${cdev} demeure ouvert pour vous permettre de tenter de corriger le problème manuellement." ;; *) echo "ERROR: ${cdev} contains an unsupprted filesystem or is unformatted ! Aborting." echo "WARNING: The ${cdev} encrypted device remains open to allow you to attempt to manually fix what needs be." ;; esac exit 1 fi fi if [ "${fat}" == "1" ]; then echo "Skipping fsck for FAT filesystem." else ${sudo} ${e2fsck} -p -C0 ${cdev} if (( $? > 1 )); then case $LANG in fr*) echo "ERREUR: Le système de fichiers ${cdev} comporte des erreurs qui n'ont pu être corrigées automatiquement ! Abandon." echo "ATTENTION: Le volume chiffré ${cdev} demeure ouvert pour vous permettre de tenter à nouveau une vérification manuelle du système de fichiers" ;; *) echo "ERROR: The ${cdev} filesystem has errors that could not be fixed automatically ! Aborting." echo "WARNING: The ${cdev} encrypted device remains open to allow you to attempt to fsck it manually and fix what needs be." ;; esac exit 1 fi fi sync if ! [ -d "${mpoint}" ]; then case $LANG in fr*) echo -n "Création du point de montage ${mpoint}... " ;; *) echo -n "Creating ${mpoint} mount point... " ;; esac mkdir ${mpoint} if [ -d "${mpoint}" ]; then echo "OK." ${sudo} chown ${cuser}: ${mpoint} 2> /dev/null chmod 700 ${mpoint} 2> /dev/null else echo "FAILED !" do_umount exit 1 fi fi if [ "${fat}" == "1" ]; then ${sudo} mount -t vfat -o uid=${UID},umask=77 ${cdev} ${mpoint} else ${sudo} mount -t ext3 -o noatime ${cdev} ${mpoint} fi if ${egrep} -q "^${cdev}[[:space:]]+${mpoint}[[:space:]]" /proc/mounts; then ${sudo} chown ${cuser}: ${mpoint} 2> /dev/null chmod 700 ${mpoint} 2> /dev/null case $LANG in fr*) echo "Le volume ${luksname} est désormais monté sur ${mpoint}. OK." ;; *) echo "Volume ${luksname} is now mounted on ${mpoint}. OK." ;; esac sync return 0 else case $LANG in fr*) echo "ERREUR: Echec du montage de ${cdev} sur ${mpoint} ! Abandon." ;; *) echo "ERROR: Failed mounting ${cdev} on ${mpoint} ! Aborting." ;; esac do_umount exit 1 fi } # =================================================================== do_create() { shortlic find_loopdev if [ -f ${cfile} ]; then case $LANG in fr*) echo "ERREUR: Un fichier '${cfile}' existe déjà !" echo " Impossible de créer un container nommé '${luksname}'." ;; *) echo "ERROR: A file '${cfile}' already exists !" echo " Cannot create a container named '${luksname}'." ;; esac exit 1 fi if [ -b "${cdev}" ]; then case $LANG in fr*) echo "ERREUR: Un volumer chiffré ${cdev} est déjà actif !" echo " Vérifiez que vous n'avez pas ouvert un container de même nom" echo " pour deux utilisateurs différents ! Abandon." ;; *) echo "ERROR: An encrypted evice ${cdev} is already active !" echo " Please check you haven't opened a container with the same name" echo " for 2 different users ! Aborting." ;; esac exit 1 fi get_freespace if [ -n "${freespace}" ]; then if (( ( ${size} * 10 ) > ( ${freespace} * 9 ) )); then case $LANG in fr*) echo "ERREUR: La taille du container que vous avez demandé dépasse 90%" echo " de l'espace disponible sur votre disque (${freespace} Mo)." echo " Impossible de créer un container aussi gros." ;; *) echo "ERROR: The size of the container you requested is bigger than 90%" echo " of your disk's free space (${freespace} MB)." echo " Cannot create a container that big." ;; esac exit 1 fi fi if (( ${size} > 512 )); then case $LANG in fr*) echo "Vous avez demandé la création d'un container chiffré de ${size} Mo." echo "La création d'un container de cette taille peut prendre beaucoup de temps" echo "(de plusieurs minutes à plusieurs heures en fonction de la taille demandée)." echo "" echo -n "Etes-vous sûr de vouloir créer un container aussi gros (o/n) ? " ;; *) echo "You requested the creation of a ${size} MB encrypted container" echo "Creating a so big container can take a long time (from several minutes" echo "to several hours depending on the size)." echo "" echo -n "Are you sure that you want to create a container that big (y/n) ? " ;; esac while read answer foo; do case ${answer} in o|O|y|Y) break ;; n|N) case $LANG in fr*) echo "Abandon." ;; *) echo "Aborting." ;; esac exit 1 ;; esac case $LANG in fr*) echo -n "Etes-vous sûr de vouloir créer un container aussi gros (o/n) ? " ;; *) echo -n "Are you sure that you want to create a container that big (y/n) ? " ;; esac done fi echo "" case $LANG in fr*) echo "Création d'un container chiffré '${cfile}' de ${size} Mo" echo "et remplissage avec des données aléatoires - En cours..." echo "Cette étape peut durer plusieurs minutes, soyez patient." ;; *) echo "Creating an encrypted container '${cfile}' of ${size} MB" echo "and filling it with random data - Processing..." echo "This can take several minutes, please be patient." ;; esac nice ${dd} if=/dev/urandom of=${cfile} bs=1M count=${size} if ! [ -f ${cfile} -a -s ${cfile} -a -r ${cfile} -a -w ${cfile} ]; then case $LANG in fr*) echo "ERREUR lors de la création du fichier container '${cfile}' !" ;; *) echo "ERROR creating '${cfile}' container !" ;; esac exit 1 fi sync case $LANG in fr*) echo "Container créé avec succès." ;; *) echo "Container successfully created." ;; esac # We check for an available device a 2nd time, as previous step # may have been long, and things may have changed meanwhile... find_loopdev loop_set echo "" case $LANG in fr*) echo "Chiffrement LUKS du container." echo "Vous allez devoir choisir une 'phrase secrète' connue de vous seul," echo "qui sera nécessaire pour 'monter' votre container chiffré et accéder" echo "aux fichiers qu'il contient." echo "La protection de vos données dépend de la complexité de votre phrase" echo "secrète. N'utilisez pas un mot de passe trop court ou facile à deviner." echo "Vous pouvez utiliser des lettres majuscules ou minuscules (qui ne sont" echo "PAS équivalentes), des chiffres, des espaces, des signes de ponctuation," echo "mais vous devrez taper à chaque fois exactement les mêmes caractères" echo "pour pouvoir accéder à vos données." echo "Si vous utilisez des caractères accentués, pensez que vous pourrez" echo "peut-être devoir un jour taper votre phrase sur un clavier d'une autre" echo "langue..." echo "Si vous oubliez votre phrase secrète ou la manière de l'écrire, vos" echo "données seront DÉFINITIVEMENT IRRÉCUPÉRABLES." ;; *) echo "LUKS enciphering of container." echo "You will have to choose a secret 'passphrase' known only to you," echo "that will be requested to 'mount' your container and access the" echo "files it will hold." echo "The security of your data depends upon the security of your passphrase." echo "Don't use a simple password or something easy to guess. You can use" echo "lowercase and uppercase letters (which are NOT equivalent), numbers," echo "punctuation signs, but you will have to type your passphrase in the" echo "exact same way everytime in order to be able to access your data." echo "If you use accentuated characters, think that you may someday have to" echo "type your passphrase using a foreign language keyboard..." echo "If you forget you passphrase or the specific way to type it, your data" echo "will be IRREMEDIABLY LOST." ;; esac echo "" ${sudo} ${cryptsetup} luksFormat --cipher ${cipher} --key-size ${keysize} ${loopdev} if [ "$?" != "0" ]; then case $LANG in fr*) echo "ERREUR: Echec lors du chiffrement du container !" ;; *) echo "ERROR: Failed enciphering container !" ;; esac loop_del exit 1 fi sync close_tempdevs open_luks [ -z "${fat}" ] && ftype="ext3" || ftype="fat${fat}" case $LANG in fr*) echo "Création d'un système de fichiers '${ftype}' dans le container chiffré..." ;; *) echo "Creating '${ftype}' filesystem in the encrypted container..." ;; esac if [ -z "${fat}" ]; then ${sudo} ${mke2fs} -j -L ${luksname} ${cdev} else ${sudo} ${mkdosfs} -F ${fat} -n ${luksname:0:11} ${cdev} fi if [ "$?" != "0" ]; then case $LANG in fr*) echo "ERREUR: Echec de création du système de fichiers ! Abandon." ;; *) echo "ERROR: Failed creating filesystem ! Aborting." ;; esac do_umount exit 1 fi sync do_mount echo "" case $LANG in fr*) echo "Votre container chiffré est désormais créé et monté dans le répertoire ${mpoint}." echo "Tous les fichiers que vous y créerez seront automatiquement chiffrés" echo "et deviendront inaccessibles dès que le répertoire sera démonté." echo "" echo "Quand vous voudrez démonter le répertoire et verrouiller le système de" echo "fichiers chiffrés, tapez: '$0 ${luksname} off'." ;; *) echo "Your encrypted container has been created and is now mounted at ${mpoint}." echo "All the files that you will put there will be automatically encrypted" echo "and will become inaccessible as soon as the directory will be unmounted." echo "" echo "When you want to unmount the directory and lock the encrypted filesystem," echo "type: '$0 ${luksname} off'." ;; esac echo "" } # ------------------------------------------------------------------- do_status() { if ! [ -f "${cfile}" -a -r "${cfile}" -a -w "${cfile}" ]; then case $LANG in fr*) echo "Le fichier container ${cfile} n'existe pas, ou n'est pas accessible en écriture." ;; *) echo "Container file ${cfile} doesn't exist, or is not writable." ;; esac elif ! [ -O ${cfile} ]; then case $LANG in fr*) echo "Le fichier container ${cfile} n'appartient pas à ${cuser}." ;; *) echo "Container file ${cfile} doesn't belong to ${cuser}." ;; esac else case $LANG in fr*) echo "Le fichier container ${cfile} est présent." ;; *) echo "Container file ${cfile} exists." ;; esac fi case $LANG in fr*) echo -n "Etat du loop device: " ;; *) echo -n "Loop device status: " ;; esac if ! /bin/bash -c "for (( d=0; d<=7; d++ )); do ${sudo} ${losetup} /dev/loop\${d} 2>/dev/null ; done" \ | ${egrep} "${cfile}"; then case $LANG in fr*) echo "Inactif." ;; *) echo "Inactive." ;; esac fi case $LANG in fr*) echo -n "Etat du volume chiffré: " ;; *) echo -n "Encrypted volume status: " ;; esac ${sudo} ${cryptsetup} status ${luksname} echo "" regdev=${cdev//\//\\/} testmount="`${gawk} \"BEGIN {ORS= \\\" \\\"} /${regdev} / {print \\\$2}\" /proc/mounts`" if [ -n "${testmount}" ]; then case $LANG in fr*) echo "Le volume chiffré ${luksname} EST actuellement monté sur ${testmount}." ;; *) echo "Encrypted volume ${luksname} IS currently mounted on ${testmount}." ;; esac else case $LANG in fr*) echo "Le volume chiffré ${luksname} n'est actuellement PAS monté." ;; *) echo "Encrypted volume ${luksname} is currently NOT mounted." ;; esac fi } # ------------------------------------------------------------------- do_unknown() { shortlic case $LANG in fr*) echo "ERREUR: Mode inconnu: '${mode}' !" ;; *) echo "ERROR: Unknown mode : '${mode}' !" ;; esac echo "" usage exit 1 } # # MAIN ############################################################## # Set PATH (normal users may not have sbin dirs in their default path) PATH="/sbin:/usr/sbin:$PATH" export PATH # Check for required binaries --------------------------------------- which cryptsetup > /dev/null && cryptsetup="`which cryptsetup`" || missingbin cryptsetup cryptsetup which dd > /dev/null && dd="`which dd`" || missingbin dd coreutils which e2fsck > /dev/null && e2fsck="`which e2fsck`" || missingbin e2fsck e2fsprogs which file > /dev/null && file="`which file`" || missingbin file file which find > /dev/null && find="`which find`" || missingbin find findutils which egrep > /dev/null && egrep="`which egrep`" || missingbin egrep grep which gawk > /dev/null && gawk="`which gawk`" || missingbin gawk gawk which losetup > /dev/null && losetup="`which losetup`" || missingbin losetup mount which lsof > /dev/null && lsof="`which lsof`" || missingbin lsof lsof which mke2fs > /dev/null && mke2fs="`which mke2fs`" || missingbin mke2fs e2fsprogs which mkdosfs > /dev/null && mkdosfs="`which mkdosfs`" || missingbin mkdosfs dosfstools which modprobe > /dev/null && modprobe="`which modprobe`" || missingbin modprobe module-init-tools which sudo > /dev/null && sudo="`which sudo`" || missingbin sudo sudo which tail > /dev/null && tail="`which tail`" || missingbin tail coreutils # Get script parameters --------------------------------------------- verbose=""; luksname=""; mode=""; size=""; fat="" # ${scriptname} [-v] (create|mount|umount|on|off|status) [] # ${scriptname} (-h|--help|--sudohelp|--license) while [ -n "$1" ]; do case "$1" in -h|--help) fullhelp exit 0 ;; --licen[cs]e) showlic exit 0 ;; --sudohelp) sudohelp exit 0 ;; -v|--verbose) verbose="1" ;; -F) fat="16" ;; -F32) fat="32" ;; create) [ -z "${luksname}" ] && paramorder [ -n "${mode}" ] && doubleaction mode="create" shift [ -z "$1" ] && sizemissing size="$1" echo "${size}" | ${egrep} -q "^[0-9]+$" || invalidsize (( ${size} >= 5 )) || toosmall (( ${size} <= 131072 )) || toobig ;; mount|on|ON|On) [ -z "${luksname}" ] && paramorder [ -n "${mode}" ] && doubleaction mode="mount" ;; umount|off|OFF|Off) [ -z "${luksname}" ] && paramorder [ -n "${mode}" ] && doubleaction mode="umount" ;; status) [ -z "${luksname}" ] && paramorder [ -n "${mode}" ] && doubleaction mode="status" ;; *) if [ -z "${luksname}" ]; then if ! echo "$1" | ${egrep} -q "^[[:alnum:]/\._-]+$"; then shortlic case $LANG in fr*) echo "ERREUR: Nom de container '$1' invalide !" echo "" echo "Le nom doit contenir seulement des lettres, des chiffres, et les caractères '._-'." ;; *) echo "ERROR: Invalid container name '$1' !" echo "" echo "Name must contain only alphanumeric and '._-' characters." ;; esac echo "" usage exit 1 elif echo "$1" | ${egrep} -q "^\."; then shortlic case $LANG in fr*) echo "ERREUR: Le nom de container ne doit pas commencer par un point !" ;; *) echo "ERROR: Container name must not start with a dot !" ;; esac echo "" usage exit 1 else luksname="$1" fi else shortlic case $LANG in fr*) echo "ERREUR: Paramètre invalide: '$1' !" ;; *) echo "ERROR: Invalid parameter : '$1' !" ;; esac echo "" usage exit 1 fi ;; esac shift done [ -z "${luksname}" -o -z "${mode}" ] && { shortlic; usage; exit 1; } cuser="$USER" cdir="`dirname ${luksname}`" luksname="`basename ${luksname}`" cdev="/dev/mapper/${luksname}" if [ -z "${cdir}" -o "${cdir}" == "." ]; then cdir="$HOME" else if [ "${cdir:0:1}" != "/" ]; then cdir="$HOME/${cdir}" fi fi if ! [ -d "${cdir}" -a -r "${cdir}" -a -w "${cdir}" ]; then shortlic case $LANG in fr*) echo "ERREUR: Le répertoire '${cdir}' n'existe pas ou n'est pas accessible en écriture !" ;; *) echo "ERROR: Directory '${cdir}' doesn't exist or isn't writable !" ;; esac exit 1 fi cfile="${cdir}/.${luksname}" mpoint="${cdir}/${luksname}" checkmodules case ${mode} in create) do_create ;; mount) do_mount ;; umount) do_umount ;; status) do_status ;; *) do_unknown ;; esac