--- truecrypt/linux/cli/cli.c 2018/04/24 16:45:03 1.1.1.3 +++ truecrypt/linux/cli/cli.c 2018/04/24 16:47:49 1.1.1.6 @@ -1,23 +1,26 @@ -/* -Copyright (c) 2004-2006 TrueCrypt Foundation. All rights reserved. +/* + Copyright (c) TrueCrypt Foundation. All rights reserved. -Covered by TrueCrypt License 2.0 the full text of which is contained in the file -License.txt included in TrueCrypt binary and source code distribution archives. + Covered by the TrueCrypt License 2.3 the full text of which is contained + in the file License.txt included in TrueCrypt binary and source code + distribution packages. */ #define _LARGEFILE_SOURCE 1 #define _FILE_OFFSET_BITS 64 +#include #include #include #include #include #include -#include +#include #include #include #include #include +#include #include #include #include @@ -26,51 +29,30 @@ License.txt included in TrueCrypt binary #include #include "Tcdefs.h" +#include "Crc.h" +#include "Dm-target.h" #include "Keyfiles.h" #include "Fat.h" #include "Format.h" +#include "Password.h" #include "Progress.h" #include "Random.h" #include "Volumes.h" #include "Tests.h" -#include "Dm-target.h" -#define MAX_VOLUMES 256 -#define MAX_MINOR 256 +#include "Cli.h" -#undef MAX_PATH -#define MAX_PATH 260 -#define MAX_PATH_STR "259" - -#define TC_MAP_DEV "/dev/mapper/truecrypt" -#define LOOP_DEV "/dev/loop" - -#define error(fmt, args...) fprintf (stderr, "truecrypt: " fmt, ## args) - -typedef struct -{ - int DeviceNumber; - int DeviceMajor; - int DeviceMinor; - uint64_t VolumeSize; - char VolumePath[MAX_PATH]; - int EA; - int Mode; - BOOL Hidden; - uint64_t ReadOnlyStart; - uint64_t ReadOnlyEnd; - uint64_t ModTime; - uint64_t AcTime; - int Flags; -} MountListEntry; - -static MountListEntry MountList[MAX_VOLUMES]; +static MountListEntry MountList[TC_MAX_VOLUMES]; static BOOL MountListValid = FALSE; +static FILE *MiceDevice = NULL; +static int MiceDeviceErrNo; + static BOOL DisplayKeys = FALSE; static BOOL DisplayPassword = FALSE; static BOOL DisplayProgress = TRUE; static BOOL UserMount = FALSE; +static BOOL UserMountAvailable = TRUE; static char *Filesystem = NULL; static char *MountOpts = NULL; static int PasswordEntryTries = 3; @@ -82,6 +64,8 @@ static int UseDeviceNumber = -1; static BOOL ProtectHidden = FALSE; static BOOL ReadOnly = FALSE; static BOOL UpdateTime = FALSE; +static BOOL Interactive = FALSE; +static BOOL Overwrite = FALSE; static int Verbose = 0; static BOOL IsTerminal = FALSE; @@ -90,11 +74,10 @@ static Password password; static KeyFile *FirstKeyFile; static KeyFile *FirstProtVolKeyFile; static KeyFile *FirstNewKeyFile; +static BOOL NoKeyFiles = FALSE; +static BOOL NoNewKeyFiles = FALSE; -static uid_t RealUserId; -static gid_t RealGroupId; - -static unsigned __int64 VolumeSize; +static unsigned long long VolumeSize; static unsigned int ClusterSize = 0; static int EA; static int EAMode; @@ -102,6 +85,12 @@ static int HashAlgorithm; static char *Filesystem; static int VolumeType = -1; static BOOL Quick; +static char *RandomSource = NULL; + +static uid_t RealUserId; +static gid_t RealGroupId; +static int LastExitStatus; + static void SecurityCleanup () { @@ -131,41 +120,42 @@ static void OnExit () } -BOOL CheckAdminPrivileges () +static BOOL CheckAdminPrivileges (int argc, char **argv) { char *env; - if (getuid () != 0 && geteuid () != 0) - { - error ("Administrator (root) privileges required\n"); - return FALSE; - } - if (getuid () != 0) { - // Impersonate root to support executing of commands like mount - setuid (0); + char *args[128]; + int i; - // Allow execution of system binaries only - setenv ("PATH", "/usr/sbin:/sbin:/usr/bin:/bin", 1); - } + args[0] = "sudo"; + args[1] = "-p"; + args[2] = "Enter %u's or root's system password: "; - return TRUE; -} + for (i = 0; i < argc && i < 127; i++) + args[i + 3] = argv[i]; + args[i + 3] = NULL; -void DropEffectiveUserId () -{ - setuid (getuid ()); + execvp ("sudo", args); + perror ("Executing sudo failed"); + + error ("Administrator (root) privileges required\n"); + return FALSE; + } + + setenv ("PATH", "/usr/sbin:/sbin:/usr/bin:/bin", 1); + return TRUE; } -BOOL LockMemory () +static BOOL LockMemory () { // Lock process memory if (mlockall (MCL_FUTURE) != 0) { - perror ("Cannot prevent memory swapping: mlockall"); + perror ("Cannot prevent paging of memory to disk: mlockall"); return FALSE; } @@ -182,6 +172,8 @@ static BOOL WaitChild (BOOL quiet, char return FALSE; } + LastExitStatus = WEXITSTATUS (status); + if (!WIFEXITED (status) || (WIFEXITED (status) && WEXITSTATUS (status))) { @@ -194,12 +186,14 @@ static BOOL WaitChild (BOOL quiet, char } -BOOL Execute (BOOL quiet, char *execName, ...) +static BOOL Execute (BOOL quiet, char *execName, ...) { int pid; va_list vl; va_start (vl, execName); + LastExitStatus = -1; + pid = fork (); if (pid == -1) { @@ -243,8 +237,8 @@ BOOL Execute (BOOL quiet, char *execName execvp (execName, args); - fprintf (stderr, "%s ", execName); - perror ("execlp"); + fprintf (stderr, "Executing %s", execName); + perror (" failed"); _exit (1); } @@ -313,8 +307,28 @@ static BOOL LoadKernelModule () fclose (m); - if (!Execute (FALSE, "modprobe", "truecrypt", NULL)) + if (!Execute (TRUE, "modprobe", "truecrypt", NULL)) { + struct utsname u; + char module[128]; + int r1, r2, r3; + char *p; + + if (!Execute (TRUE, "modprobe", "dm-mod", NULL)) + Execute (TRUE, "modprobe", "dm", NULL); + + if (uname (&u) == 0 && sscanf (u.release, "%d.%d.%d", &r1, &r2, &r3) == 3) + { + snprintf (module, sizeof (module), "%s/truecrypt.ko", TC_SHARE_KERNEL); + if (IsFile (module) && Execute (TRUE, "insmod", module, NULL)) + return TRUE; + + snprintf (module, sizeof (module), "%s/truecrypt-%d.%d.%d.ko", TC_SHARE_KERNEL, r1, r2, r3); + if (IsFile (module) && Execute (FALSE, "insmod", module, NULL)) + return TRUE; + } + + Execute (FALSE, "modprobe", "truecrypt", NULL); error ("Failed to load TrueCrypt kernel module\n"); return FALSE; } @@ -329,7 +343,7 @@ static BOOL UnloadKernelModule (BOOL qui } -static BOOL CheckKernelModuleVersion (BOOL wait) +static BOOL CheckKernelModuleVersion (BOOL wait, BOOL quiet) { FILE *p; int pfd[2]; @@ -381,7 +395,7 @@ static BOOL CheckKernelModuleVersion (BO fclose (p); WaitChild (FALSE, "dmsetup"); - if (ver1 == VERSION_NUM1 && ver2 == VERSION_NUM2 && ver3 == VERSION_NUM3) + if (ver1 == TC_VERSION_NUM1 && ver2 == TC_VERSION_NUM2 && ver3 == TC_VERSION_NUM3) return TRUE; error ("Incorrect version of kernel module loaded - version %s required\n", VERSION_STRING); @@ -401,19 +415,52 @@ static BOOL CheckKernelModuleVersion (BO } while (tries--); - error ("Kernel module not loaded\n"); + if (!quiet) + error ("Kernel module not loaded\n"); + return FALSE; } -static BOOL GetMountList () +static void OpenMiceDevice () +{ + if (!MiceDevice) + { + FILE *m; + char s[2048]; + + m = fopen ("/proc/bus/input/devices", "r"); + if (m != NULL) + { + BOOL found = FALSE; + while (fgets (s, sizeof (s), m)) + { + if (strstr (s, "mouse") || strstr (s, "Mouse") || strstr (s, "MOUSE")) + { + found = TRUE; + break; + } + } + + fclose (m); + if (!found) + return; + } + + MiceDevice = fopen (TC_MICE_DEVICE, "rb"); + MiceDeviceErrNo = errno; + } +} + + +static BOOL GetMountList (BOOL force) { FILE *p; int pfd[2]; int pid, res; int i, dummy; - if (MountListValid) + if (!force && MountListValid) return TRUE; MountList[0].DeviceNumber = -1; @@ -448,7 +495,7 @@ static BOOL GetMountList () goto err; } - for (i = 0; i < MAX_VOLUMES; i++) + for (i = 0; i < TC_MAX_VOLUMES; i++) { int n = 0; char s[2048]; @@ -457,7 +504,7 @@ static BOOL GetMountList () if (!fgets (s, sizeof (s), p)) break; - if (sscanf (s, "truecrypt%d: 0 %lld truecrypt %d %d 0 0 %d:%d %lld %lld %lld %lld %lld %d %n", + if (sscanf (s, "truecrypt%d: 0 %llu truecrypt %d %d 0 0 %d:%d %llu %llu %llu %llu %llu %llu %d %n", &e->DeviceNumber, &e->VolumeSize, &e->EA, @@ -467,13 +514,14 @@ static BOOL GetMountList () &e->Hidden, &e->ReadOnlyStart, &e->ReadOnlyEnd, + &e->UserId, &e->ModTime, &e->AcTime, &e->Flags, &n) >= 12 && n > 0) { int l; - strncpy (e->VolumePath, s + n, sizeof (e->VolumePath)); + snprintf (e->VolumePath, sizeof (e->VolumePath), "%s", s + n); l = strlen (s + n); if (l > 0) e->VolumePath[l - 1] = 0; @@ -503,7 +551,7 @@ err: static BOOL IsVolumeMounted (char *volumePath) { int i; - if (!GetMountList ()) + if (!GetMountList (FALSE)) return FALSE; for (i = 0; MountList[i].DeviceNumber != -1; i++) @@ -520,10 +568,10 @@ static int GetFreeMapDevice () char cmd[128]; int n; - if (!GetMountList ()) + if (!GetMountList (FALSE)) return -1; - for (n = 0; n < MAX_MINOR; n++) + for (n = 0; n < TC_MAX_MINOR; n++) { int j = 0; while (MountList[j].DeviceNumber != -1) @@ -543,18 +591,29 @@ static int GetFreeMapDevice () static BOOL DeleteLoopDevice (int loopDeviceNo) { - char dev[32]; + char dev[64]; BOOL r; + int i; - sprintf (dev, LOOP_DEV "%d", loopDeviceNo); + snprintf (dev, sizeof (dev), TC_LOOP_DEV "%d", loopDeviceNo); if (!IsBlockDevice (dev)) - sprintf (dev, LOOP_DEV "/%d", loopDeviceNo); + snprintf (dev, sizeof (dev), TC_LOOP_DEV "/%d", loopDeviceNo); - r = Execute (FALSE, "losetup", "-d", dev, NULL); + for (i = 0; i < 10; i++) + { + r = Execute (TRUE, "losetup", "-d", dev, NULL); + if (r) + break; + + usleep (200 * 1000); + } if (r && Verbose > 1) printf ("Detached %s\n", dev); + if (!r) + error ("Failed to detach %s\n", dev); + return r; } @@ -562,7 +621,7 @@ static BOOL DeleteLoopDevice (int loopDe static int AskSelection (int defaultChoice, int min, int max) { int c; - char s[3]; + char s[10]; while (1) { @@ -577,12 +636,36 @@ static int AskSelection (int defaultChoi return c; } + if (s[0] != 0 && s[0] != '\n') + continue; + puts (""); return defaultChoice; } } +static BOOL AskYesNo (char *prompt, BOOL defaultNo) +{ + char s[4]; + + do + { + printf ("%s [%c/%c]: ", prompt, defaultNo ? 'y' : 'Y', defaultNo ? 'N' : 'n'); + fgets (s, sizeof(s), stdin); + + if (s[0] == 'y' || s[0] == 'Y') + return TRUE; + + if (s[0] == 'n' || s[0] == 'N') + return FALSE; + + } while (s[0] != '\n'); + + return !defaultNo; +} + + static char *AskString (char *prompt, char *buf, int maxSize) { printf ("%s: ", prompt); @@ -600,9 +683,37 @@ static char *AskString (char *prompt, ch } -static void AskPassword (char *prompt, char *volumePath, Password *password) +static BOOL ValidatePassword (Password *password, BOOL requireAscii) +{ + int i; + + if (password->Length > MAX_PASSWORD) + { + error ("Maximum password length is %d characters\n", MAX_PASSWORD); + return FALSE; + } + + for (i = 0; i < password->Length; i++) + { + if (password->Text[i] >= 0x7f || password->Text[i] < 0x20) + { + error ("Password must be composed only of US-ASCII printable characters to maintain portability.\n"); + + if (requireAscii) + return FALSE; + else + break; + } + } + + return TRUE; +} + + +static void AskPassword (char *prompt, char *volumePath, Password *password, BOOL requireAscii) { struct termios noEcho; + char pw[2048]; if (tcgetattr (0, &TerminalAttributes) == 0) { @@ -614,19 +725,32 @@ static void AskPassword (char *prompt, c if (tcsetattr (0, TCSANOW, &noEcho) != 0) error ("Failed to turn terminal echo off\n"); } - - printf (prompt, volumePath); } - if (fgets ((char *)password->Text, sizeof (password->Text), stdin)) + while (TRUE) { - char *newl = strchr ((char *)password->Text, '\n'); + char *newl; + + if (IsTerminal) + printf (prompt, volumePath); + + if (!fgets (pw, sizeof (pw), stdin)) + { + password->Length = 0; + break; + } + + newl = strchr (pw, '\n'); if (newl) newl[0] = 0; + snprintf ((char *)password->Text, sizeof (password->Text), "%s", pw); password->Length = strlen ((char *)password->Text); + + if (ValidatePassword (password, requireAscii)) + break; } - else - password->Length = 0; + + burn(pw, sizeof (pw)); if (IsTerminal && !DisplayPassword) { @@ -638,7 +762,7 @@ static void AskPassword (char *prompt, c static char *AskVolumePath (char *volumePath, char *prompt) { - static char path[MAX_PATH]; + static char path[TC_MAX_PATH]; // Volume path while (!volumePath || !volumePath[0]) @@ -650,19 +774,45 @@ static char *AskVolumePath (char *volume } -static BOOL OpenVolume (char *volumePath, char *prompt, char *promptArg, BOOL secondaryPassword, PCRYPTO_INFO *cryptoInfo, uint64_t *startSector, uint64_t *totalSectors, time_t *modTime, time_t *acTime) +static BOOL AskKeyFiles (char *prompt, KeyFile **firstKeyFile) +{ + char path[TC_MAX_PATH]; + char lprompt[128]; + + snprintf (lprompt, sizeof(lprompt), "%s [none]", prompt); + while (AskString (lprompt, path, sizeof (path)) && path[0] != 0) + { + KeyFile *kf = malloc (sizeof (KeyFile)); + if (!kf) + { + perror ("malloc"); + return FALSE; + } + snprintf (kf->FileName, sizeof (kf->FileName), "%s", path); + *firstKeyFile = KeyFileAdd (*firstKeyFile, kf); + + snprintf (lprompt, sizeof(lprompt), "%s [finish]", prompt); + } + + return TRUE; +} + + +static BOOL OpenVolume (char *volumePath, char *prompt, char *promptArg, BOOL secondaryPassword, PCRYPTO_INFO *cryptoInfo, unsigned long long *startSector, unsigned long long *totalSectors, time_t *modTime, time_t *acTime) { char header[SECTOR_SIZE]; - uint64_t r; FILE *f = NULL; struct stat volumeStat; int tries = PasswordEntryTries; char msg[128]; BOOL ret = FALSE; + int r; - if (stat (volumePath, &volumeStat) != 0) + memset (&volumeStat, 0, sizeof (volumeStat)); + if ((!UpdateTime || ReadOnly) + && IsFile (volumePath) && stat (volumePath, &volumeStat) != 0) { - perror ("Cannot read volume's modification and access time"); + perror ("Cannot open volume"); volumeStat.st_ctime = 0; goto err; } @@ -679,16 +829,16 @@ static BOOL OpenVolume (char *volumePath Password *pw = &password; if (!secondaryPassword && !CmdPasswordValid || (secondaryPassword && !CmdPassword2Valid)) - AskPassword (prompt, promptArg, &password); + AskPassword (prompt, promptArg, &password, FALSE); else pw = secondaryPassword ? &CmdPassword2 : &CmdPassword; if ((!secondaryPassword && FirstKeyFile - && !KeyFilesApply (pw, FirstKeyFile, !UpdateTime)) + && !KeyFilesApply (pw, FirstKeyFile)) || (secondaryPassword && FirstProtVolKeyFile - && !KeyFilesApply (pw, FirstProtVolKeyFile, !UpdateTime))) + && !KeyFilesApply (pw, FirstProtVolKeyFile))) { error ("Error while processing keyfiles\n"); goto err; @@ -724,7 +874,9 @@ static BOOL OpenVolume (char *volumePath if (fseek (f, -HIDDEN_VOL_HEADER_OFFSET, SEEK_END) == -1 || fread (header, 1, SECTOR_SIZE, f) != SECTOR_SIZE) { - perror ("Cannot read volume header"); + perror ("Cannot read hidden volume header"); + if (IsFile (volumePath)) + error ("Please check the filesystem supports files larger than 2GB.\n"); goto err; } @@ -744,14 +896,19 @@ static BOOL OpenVolume (char *volumePath if (r == ERR_PASSWORD_WRONG) { + char s[128]; + + snprintf (s, sizeof (s), "Incorrect password %sor not a TrueCrypt volume." + , (FirstKeyFile || FirstProtVolKeyFile) ? "and/or keyfile(s) " : ""); + if (IsTerminal) { - puts ("Incorrect password or not a TrueCrypt volume."); + puts (s); continue; } else { - error ("Incorrect password or not a TrueCrypt volume.\n"); + error ("%s\n", s); goto err; } } @@ -761,11 +918,11 @@ static BOOL OpenVolume (char *volumePath switch (r) { case ERR_NEW_VERSION_REQUIRED: - strcpy (msg, "A newer version of TrueCrypt is required to open this volume."); + snprintf (msg, sizeof (msg), "A newer version of TrueCrypt is required to open this volume."); break; default: - sprintf (msg, "Volume cannot be opened: Error %d", r); + snprintf (msg, sizeof (msg), "Volume cannot be opened: Error %d", r); break; } @@ -807,11 +964,11 @@ err: static char *EscapeSpaces (char *string) { - static char escapedString[MAX_PATH * 2]; + static char escapedString[TC_MAX_PATH * 2]; char *e = escapedString; char c; - if (strlen (string) > MAX_PATH) + if (strlen (string) > TC_MAX_PATH) return NULL; while ((c = *string++)) @@ -826,14 +983,30 @@ static char *EscapeSpaces (char *string) } +static BOOL IsMountPointAvailable (char *mountPoint) +{ + char md[TC_MAX_PATH], mp[TC_MAX_PATH]; + + while (EnumMountPoints (md, mp)) + { + if (strcmp (mountPoint, mp) == 0) + { + EnumMountPoints (NULL, NULL); + return FALSE; + } + } + return TRUE; +} + + static BOOL MountVolume (char *volumePath, char *mountPoint) { - char hostDevice[MAX_PATH]; - char mapDevice[MAX_PATH]; + char hostDevice[TC_MAX_PATH]; + char mapDevice[TC_MAX_PATH]; int loopDevNo = -1; PCRYPTO_INFO ci = NULL; - uint64_t startSector, totalSectors; - uint64_t readOnlyStartSector = 0, readOnlySectors = 0; + unsigned long long startSector, totalSectors; + unsigned long long readOnlyStartSector = 0, readOnlySectors = 0; int pfd[2]; int pid, res, devNo; time_t modTime, acTime; @@ -856,6 +1029,24 @@ static BOOL MountVolume (char *volumePat return FALSE; } + if (UseDeviceNumber != -1) + { + for (i = 0; MountList[i].DeviceNumber != -1; i++) + { + if (MountList[i].DeviceNumber == UseDeviceNumber) + { + error (TC_MAP_DEV "%d already in use\n", UseDeviceNumber); + return FALSE; + } + } + } + + if (mountPoint && !IsMountPointAvailable (mountPoint)) + { + error ("Mount directory %s is already in use\n", mountPoint); + return FALSE; + } + if (!OpenVolume (volumePath, "Enter password for '%s': ", volumePath, FALSE, &ci, &startSector, &totalSectors, &modTime, &acTime)) goto err; @@ -870,7 +1061,7 @@ static BOOL MountVolume (char *volumePat if (ProtectHidden) { PCRYPTO_INFO ciH = NULL; - uint64_t startSectorH, totalSectorsH; + unsigned long long startSectorH, totalSectorsH; if (OpenVolume (volumePath, "Enter hidden volume password: ", "", TRUE, &ciH, &startSectorH, &totalSectorsH, &modTime, &acTime)) @@ -893,13 +1084,13 @@ static BOOL MountVolume (char *volumePat { int i; - for (i = 0; i < MAX_MINOR; i++) + for (i = 0; i < TC_MAX_MINOR; i++) { - snprintf (hostDevice, sizeof (hostDevice), LOOP_DEV "%d", i); + snprintf (hostDevice, sizeof (hostDevice), TC_LOOP_DEV "%d", i); if (!IsBlockDevice (hostDevice)) { - snprintf (hostDevice, sizeof (hostDevice), LOOP_DEV "/%d", i); + snprintf (hostDevice, sizeof (hostDevice), TC_LOOP_DEV "/%d", i); if (!IsBlockDevice (hostDevice)) continue; } @@ -908,9 +1099,9 @@ static BOOL MountVolume (char *volumePat break; } - if (i >= MAX_MINOR) + if (i >= TC_MAX_MINOR) { - error ("No free loopback device available for file-hosted volume\n"); + error ("Failed to assign loopback device for file-hosted volume\n"); goto err; } @@ -921,13 +1112,13 @@ static BOOL MountVolume (char *volumePat } else - strncpy (hostDevice, volumePath, sizeof (hostDevice)); + snprintf (hostDevice, sizeof (hostDevice), "%s", volumePath); // Load kernel module if (!LoadKernelModule ()) goto err; - if (!CheckKernelModuleVersion (TRUE)) + if (!CheckKernelModuleVersion (TRUE, FALSE)) goto err; // dmsetup @@ -938,7 +1129,7 @@ static BOOL MountVolume (char *volumePat goto err; } - sprintf (mapDevice, "truecrypt%d", devNo); + snprintf (mapDevice, sizeof (mapDevice), "truecrypt%d", devNo); pipe (pfd); pid = fork (); @@ -969,7 +1160,7 @@ static BOOL MountVolume (char *volumePat goto err; } - fprintf (w, "0 %lld truecrypt %d %d ", totalSectors, ci->ea, ci->mode); + fprintf (w, "0 %llu truecrypt %d %d ", totalSectors, ci->ea, ci->mode); for (i = DISK_IV_SIZE; i < EAGetKeySize (ci->ea) + DISK_IV_SIZE; i++) fprintf (w, "%02x", ci->master_key[i]); @@ -982,17 +1173,18 @@ static BOOL MountVolume (char *volumePat flags = 0; if (ReadOnly) - flags |= FLAG_READ_ONLY; + flags |= TC_READ_ONLY; else if (ProtectHidden) - flags |= FLAG_HIDDEN_VOLUME_PROTECTION; + flags |= TC_HIDDEN_VOLUME_PROTECTION; - fprintf (w, " %s %lld %lld %lld %lld %lld %d %s\n", + fprintf (w, " %s %llu %llu %llu %llu %llu %llu %d %s\n", hostDevice, startSector, readOnlyStartSector, readOnlySectors, - (uint64_t) modTime, - (uint64_t) acTime, + (unsigned long long) RealUserId, + (unsigned long long) modTime, + (unsigned long long) acTime, flags, EscapeSpaces (volumePath)); @@ -1004,7 +1196,7 @@ static BOOL MountVolume (char *volumePat goto err; } - sprintf (mapDevice, TC_MAP_DEV "%d", devNo); + snprintf (mapDevice, sizeof (mapDevice), TC_MAP_DEV "%d", devNo); if (Verbose >= 1) printf ("Mapped %s as %s\n", volumePath, mapDevice); @@ -1012,32 +1204,43 @@ static BOOL MountVolume (char *volumePat // Mount if (mountPoint) { - char fstype[64], opts[128]; + char fstype[64] = "-tauto"; + char opts[1024]; + char uopts[64] = ""; - strcpy (fstype, "-t"); if (Filesystem) - strncat (fstype, Filesystem, sizeof (fstype) - 3); - else - strcat (fstype, "auto"); - - strcpy (opts, ReadOnly ? "-oro" : "-orw"); - if (MountOpts) - { - strcat (opts, ","); - strncat (opts, MountOpts, sizeof (opts) - 6); - } + snprintf (fstype, sizeof (fstype), "-t%s", Filesystem); if (UserMount) { // Set default uid and gid - char s[64]; - sprintf (s, ",uid=%d,gid=%d", RealUserId, RealGroupId); - strcat (opts, s); + if (UserMountAvailable) + { + snprintf (uopts, sizeof (uopts), ",uid=%d,gid=%d,umask=077", RealUserId, RealGroupId); + } + else + { + error ("--user-mount can be specified only after sudo(8) command has been used.\n"); + Execute (TRUE, "dmsetup", "remove", mapDevice, NULL); + goto err; + } } + snprintf (opts, sizeof (opts), "%s%s%s%s", + ReadOnly ? "-oro" : "-orw", + MountOpts ? "," : "", + MountOpts ? MountOpts : "", + uopts); + + if (!Execute (FALSE, "mount", fstype, opts, mapDevice, mountPoint, NULL)) { + int devNo; error ("Mount failed\n"); + + if (GetMountList (TRUE) && ToDeviceNumber (mapDevice, &devNo)) + DismountVolume (devNo); + loopDevNo = -1; goto err; } @@ -1063,140 +1266,178 @@ err: } -int RandGetBytesAvailable () +static void HexDump (unsigned __int8 *data, unsigned int length) { - int n = -1; - FILE *f = fopen ("/proc/sys/kernel/random/entropy_avail", "r"); - - if (f == NULL) - return -1; - - if (fscanf (f, "%d", &n) == 1) - n /= 8; - - fclose (f); - return n; + while (length--) + printf ("%02x", (unsigned int) *data++); } -void RandBytesFillRequired (int randReq) +static uint64_t GetTimeUsec () { - int n; + struct timeval tv; + gettimeofday (&tv, NULL); - if (RandGetBytesAvailable () < randReq) - { - printf ("There is not enough entropy available in the kernel random pool. Please move\n" - "the mouse randomly and/or press random keys. Both the mouse and keyboard must\n" - "be physically connected to the computer where TrueCrypt is running. Disk\n" - "activity (read/write) can also be used to fill the kernel random pool.\n\n"); + return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec; +} - while ((n = RandGetBytesAvailable()) < randReq) - { - if (n < 0) - { - printf ("WARNING: Number of random bytes available could not be determined.\n" - "If the volume creation does not start, try moving the mouse or pressing keys\n" - "to increase the random pool entropy.\n"); - break; - } - printf ("\rRandom bytes available: %d%%", n * 100 / (randReq)); - fflush (stdout); - usleep (200 * 1000); - } +static double GetTime () +{ + struct timeval tv; + gettimeofday (&tv, NULL); - if (n > 0) - printf ("\rRandom bytes available: 100%%\n\n"); - } + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; } -BOOL RandpeekBytes (unsigned char *buf , int len) + +static BOOL RandFillPool () { - int f = open ("/dev/urandom", 0); + int i; - if (f == -1) + if (Randinit () != 0) { - perror ("Cannot open /dev/urandom"); + error ("Error while initializing the TrueCrypt random number generator.\n"); return FALSE; } - if (read (f, buf, len) != len) + FastPoll (); + + if (IsTerminal && !RandomSource) { - perror ("Read from /dev/urandom failed"); - return FALSE; - } + puts ("TrueCrypt will now collect random data."); - close (f); - return TRUE; -} + if (MiceDevice != NULL) + { + if (AskYesNo ("\nIs your mouse connected directly to computer where TrueCrypt is running?", FALSE)) + { + // Mouse + puts ("\nPlease move the mouse randomly until the required amount of data is captured..."); + for (i = 0; i <= TC_REQUIRED_MOUSE_EVENTS; i++) + { + unsigned char buf[sizeof (uint64_t)]; + printf ("\rMouse data captured: %d%% ", i * 100 / TC_REQUIRED_MOUSE_EVENTS); + fflush (stdout); -BOOL RandgetBytes (unsigned char *buf , int len, BOOL forceSlowPoll) -{ - char m[128]; - int f = open ("/dev/random", 0); - int r; + if (fread (buf, 1, 1, MiceDevice) != 1) + { + perror ("Cannot read from " TC_MICE_DEVICE); + goto keyboard; + } + RandaddBuf (buf, 1); - if (f == -1) - { - perror ("Cannot open /dev/random"); - return FALSE; - } + *(uint64_t *)buf += GetTimeUsec (); - while ((r = read (f, buf++, 1)) == 1 && --len); + /* The role of CRC-32 is merely to perform diffusion. Note that the output + of CRC-32 is subsequently processed using a cryptographically secure hash + algorithm. */ + RandAddInt (crc32 (buf, sizeof (buf))); + } - if (r == -1) - { - perror ("Read from /dev/random failed"); - close (f); - return FALSE; - } + if (i >= TC_REQUIRED_MOUSE_EVENTS) + { + puts ("\n"); + return TRUE; + } + } + } + else if (MiceDeviceErrNo == EACCES) + { + if (IsTerminal) + { + + puts ("\nTo enable mouse movements to be used as a source of random data,\n" + "please do one of the following:\n" + "- Run TrueCrypt under administrator (root) account.\n" + "- Add read permission for your user to device " TC_MICE_DEVICE "."); + } + } - if (len > 0) - { - perror ("Cannot read enough bytes from /dev/random"); - close (f); - return FALSE; - } +keyboard: + // Keyboard + printf ("\nPlease type at least %d randomly chosen characters and then press Enter:\n", TC_REQUIRED_KEYSTROKES); - close (f); - return TRUE; -} + i = 0; + while (1) + { + char buf[TC_REQUIRED_KEYSTROKES * 8]; + int l; + if (!fgets (buf, sizeof (buf), stdin)) + return FALSE; -void HexDump (unsigned __int8 *data, unsigned int length) -{ - while (length--) - printf ("%02x", (unsigned int) *data++); -} + l = strlen (buf) - 1; + if (l > 0) + { + RandaddBuf (buf, l); + i += l; + } -double GetTime () -{ - struct timeval tv; - gettimeofday (&tv, NULL); + if (i >= TC_REQUIRED_KEYSTROKES) + break; - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; + printf ("\nCharacters remaining: %d\n", TC_REQUIRED_KEYSTROKES - i); + fflush (stdout); + } + puts (""); + } + else if (RandomSource) + { + // File + char buf[RNG_POOL_SIZE]; + FILE *f = NULL; + int r; + + if (strcmp (RandomSource, "-") != 0) + { + f = fopen (RandomSource, "rb"); + if (!f) + { + perror ("Cannot open source of random data"); + return FALSE; + } + } + + if ((r = fread (buf, 1, sizeof (buf), f ? f : stdin)) < 1) + { + error ("Cannot read from source of random data"); + if (f) + fclose (f); + return FALSE; + } + + if (f) + fclose (f); + RandaddBuf (buf, r); + } + else + { + error ("Source of random data required (use --random-source).\n"); + return FALSE; + } + + return TRUE; } -static __int64 TotalSectors, StartSector; +static unsigned __int64 TotalSectors, StartSector; static double StartTime; static double LastUpdateTime; - void InitProgressBar (__int64 totalSectors) { LastUpdateTime = 0; StartTime = GetTime (); - TotalSectors = totalSectors; + TotalSectors = (unsigned __int64) totalSectors; } BOOL UpdateProgressBar (__int64 sector) { - unsigned __int64 s = sector - StartSector; + unsigned __int64 s = (unsigned __int64) sector - StartSector; double t = GetTime (); double elapsed = t - StartTime; unsigned __int64 bytesDone = (s + 1) * SECTOR_SIZE; @@ -1218,9 +1459,9 @@ BOOL UpdateProgressBar (__int64 sector) } -static BOOL ParseSize (char *string, uint64_t *size) +static BOOL ParseSize (char *string, unsigned long long *size) { - if (sscanf (string, "%lld", size) == 1) + if (sscanf (string, "%llu", size) == 1) { if (strchr (string, 'k') || strchr (string, 'K')) *size *= 1024; @@ -1239,19 +1480,20 @@ static BOOL ParseSize (char *string, uin static BOOL CreateVolume (char *hostPath) { - PCRYPTO_INFO ci; + PCRYPTO_INFO ci = NULL; char header[HEADER_SIZE]; - char path[MAX_PATH]; + char path[TC_MAX_PATH]; char str[128]; FILE *f; fatparams ft; Password *pw = &password; - unsigned __int64 startSector, totalSectors, hostSize; + unsigned long long startSector, totalSectors, hostSize; BOOL hiddenVolume; - int randReq; + BOOL deleteOnError = FALSE; + BOOL ret = FALSE; int i, r = 0; - DropEffectiveUserId (); + OpenMiceDevice (); // Volume type switch (VolumeType) @@ -1262,7 +1504,6 @@ static BOOL CreateVolume (char *hostPath case VOLUME_TYPE_HIDDEN: hiddenVolume = TRUE; - Quick = TRUE; break; default: @@ -1271,8 +1512,11 @@ static BOOL CreateVolume (char *hostPath break; } + if (hiddenVolume) + Quick = TRUE; + // Host file or device - hostPath = AskVolumePath (hostPath, hiddenVolume ? "Enter volume path" : "Enter file or device name for new volume"); + hostPath = AskVolumePath (hostPath, hiddenVolume ? "Enter volume path" : "Enter file or device path for new volume"); if (hiddenVolume) { @@ -1283,14 +1527,26 @@ static BOOL CreateVolume (char *hostPath } f = fopen (hostPath, "r+b"); } - else if (IsFile (hostPath)) - { - error ("File %s already exists.\n", hostPath); - return FALSE; - } - else + else { + if (!Overwrite + && IsFile (hostPath) + && (!IsTerminal || !AskYesNo ("Volume already exists - overwrite?", TRUE))) + { + if (!IsTerminal) + error ("Volume already exists.\n"); + return FALSE; + } + + if (!Overwrite + && IsBlockDevice (hostPath) + && (!IsTerminal || !AskYesNo ("WARNING: Data on device will be lost. Continue?", TRUE))) + { + return FALSE; + } + f = fopen (hostPath, "wb"); + deleteOnError = TRUE; } if (!f) @@ -1364,7 +1620,6 @@ static BOOL CreateVolume (char *hostPath if (EA == 0) { int max = 0; -ea: puts ("Encryption algorithm:"); for (i = EAGetFirst (); i != 0; i = EAGetNext (i)) @@ -1377,35 +1632,18 @@ ea: } EA = AskSelection (1, EAGetFirst (), max); - - if (CipherGetBlockSize (EAGetFirstCipher (EA)) == 8 - && VolumeSize > WARN_VOL_SIZE_BLOCK64) - { - char s[3]; - - AskString ("WARNING: You have selected a 64-bit block cipher. Due to security reasons,\n" - "for this volume size, it is strongly recommended to select a 128-bit block cipher\n" - "(for example, AES, Serpent, or Twofish) instead.\n\n" - "Continue? [y/N]", s, sizeof (s)); - puts (""); - - if (strcmp (s, "y") && strcmp (s, "Y")) - goto ea; - } } - randReq = EAGetKeySize (EA) * 2 + DISK_IV_SIZE * 2 + PKCS5_SALT_SIZE; - // Password if (!CmdPasswordValid) { while (1) { - AskPassword ("Enter password for new volume '%s': ", hostPath, &password); + AskPassword ("Enter password for new volume '%s': ", hostPath, &password, TRUE); if (!DisplayPassword) { Password pv; - AskPassword ("Re-enter password%s", ": ", &pv); + AskPassword ("Re-enter password%s", ": ", &pv, TRUE); if (password.Length != pv.Length || memcmp (password.Text, pv.Text, pv.Length)) { puts ("Passwords do not match.\n"); @@ -1417,15 +1655,33 @@ ea: puts (""); } else + { + if (!ValidatePassword (&CmdPassword, TRUE)) + goto err; + pw = &CmdPassword; + } - if (FirstKeyFile && !KeyFilesApply (pw, FirstKeyFile, !UpdateTime)) + if (!NoKeyFiles && !FirstKeyFile) + { + AskKeyFiles ("Enter keyfile path", &FirstKeyFile); + puts (""); + } + + if (!FirstKeyFile && pw->Length == 0) + { + error ("Password cannot be empty when no keyfile is specified\n"); + goto err; + } + + if (FirstKeyFile && !KeyFilesApply (pw, FirstKeyFile)) { error ("Error while processing keyfiles\n"); goto err; } - RandBytesFillRequired (randReq); + if (!RandFillPool ()) + goto err; // Create volume header r = VolumeWriteHeader (header, @@ -1522,49 +1778,64 @@ ea: goto err; } + LastUpdateTime = 0; + UpdateProgressBar (TotalSectors + StartSector); + if (DisplayProgress && IsTerminal) puts ("\nVolume created."); - crypto_close (ci); - fclose (f); - return TRUE; + ret = TRUE; err: - fclose (f); - return FALSE; + if (ci) + crypto_close (ci); + if (f) + fclose (f); + if (!ret && deleteOnError && IsFile (hostPath)) + remove (hostPath); + Randfree (); + return ret; } static BOOL ChangePassword (char *volumePath) { char header[HEADER_SIZE]; - char path[MAX_PATH]; + char path[TC_MAX_PATH]; Password *pw = &password; PCRYPTO_INFO ci = NULL, ci2 = NULL; - uint64_t startSector, totalSectors; + unsigned long long startSector, totalSectors; time_t modTime = 0, acTime; - int wipePass, ret = TRUE; - int fd, r; + int wipePass, ret = FALSE; + int fd = -1, r; FILE *f; // Volume path volumePath = AskVolumePath (volumePath, "Enter volume path"); + if (!NoKeyFiles && !FirstKeyFile) + AskKeyFiles ("Enter current keyfile path", &FirstKeyFile); + // Open volume if (!OpenVolume (volumePath, "Enter current password for '%s': ", volumePath, FALSE, &ci, &startSector, &totalSectors, &modTime, &acTime)) return FALSE; + puts (""); + // New password and/or keyfile(s) + if (!NoNewKeyFiles && !FirstNewKeyFile) + AskKeyFiles ("Enter new keyfile path", &FirstNewKeyFile); + if (!CmdPassword2Valid) { while (1) { - AskPassword ("Enter new password for '%s': ", volumePath, &password); + AskPassword ("Enter new password for '%s': ", volumePath, &password, TRUE); if (!DisplayPassword) { Password pv; - AskPassword ("Re-enter new password%s", ": ", &pv); + AskPassword ("Re-enter new password%s", ": ", &pv, TRUE); if (password.Length != pv.Length || memcmp (password.Text, pv.Text, pv.Length)) { puts ("Passwords do not match.\n"); @@ -1577,20 +1848,36 @@ static BOOL ChangePassword (char *volume puts (""); } else + { + if (!ValidatePassword (&CmdPassword2, TRUE)) + goto err; + pw = &CmdPassword2; + } + + if (!FirstNewKeyFile && pw->Length == 0) + { + error ("Password cannot be empty when no keyfile is specified\n"); + goto err; + } - if (FirstNewKeyFile && !KeyFilesApply (pw, FirstNewKeyFile, !UpdateTime)) + if (FirstNewKeyFile && !KeyFilesApply (pw, FirstNewKeyFile)) { error ("Error while processing new keyfiles\n"); - return FALSE; + goto err; } fd = open (volumePath, O_RDWR | O_SYNC); if (fd == -1) { perror ("Cannot open file or device"); - return FALSE; + goto err; } + + OpenMiceDevice (); + if (!RandFillPool ()) + goto err; + f = fdopen (fd, "r+b"); // Write a new volume header @@ -1598,10 +1885,10 @@ static BOOL ChangePassword (char *volume { BOOL wipeMode = wipePass < DISK_WIPE_PASSES - 1; - if (!wipeMode) + if (Verbose) { - if (Verbose) puts ("\n"); - RandBytesFillRequired (PKCS5_SALT_SIZE); + printf ("\rWriting header (pass %d)%s", wipePass, wipeMode ? "" : "\n"); + fflush (stdout); } r = VolumeWriteHeader (header, @@ -1617,7 +1904,6 @@ static BOOL ChangePassword (char *volume if (r == ERR_CIPHER_INIT_WEAK_KEY) { - ret = FALSE; error ("A weak or a potentially weak key has been generated. Please try again.\n"); goto err; } @@ -1625,7 +1911,6 @@ static BOOL ChangePassword (char *volume if (r != 0) { error ("Volume header creation failed.\n"); - ret = FALSE; goto err; } @@ -1637,7 +1922,6 @@ static BOOL ChangePassword (char *volume if (fseek (f, -HIDDEN_VOL_HEADER_OFFSET, SEEK_END) == -1) { perror ("Cannot seek to hidden volume header location"); - ret = FALSE; goto err; } } @@ -1646,21 +1930,13 @@ static BOOL ChangePassword (char *volume if (fseek (f, 0, SEEK_SET) == -1) { perror ("Cannot seek to volume header location"); - ret = FALSE; goto err; } } - if (Verbose) - { - printf ("\rWriting header (pass %d)", wipePass); - fflush (stdout); - } - if (fwrite (header, 1, HEADER_SIZE, f) != HEADER_SIZE) { perror ("Cannot write volume header"); - ret = FALSE; goto err; } @@ -1668,29 +1944,41 @@ static BOOL ChangePassword (char *volume fdatasync (fd); } - printf ("%sPassword and/or keyfile(s) changed.\n", Verbose ? "\n" : ""); + if (Verbose) + puts (""); + + printf ("Password %schanged.\n", FirstKeyFile && FirstNewKeyFile ? "and/or keyfile(s) " : ""); + + if (!FirstKeyFile && FirstNewKeyFile) + puts ("Keyfiles added."); + + if (FirstKeyFile && !FirstNewKeyFile) + puts ("Keyfiles removed."); + + ret = TRUE; err: - crypto_close (ci); - close (fd); + if (ci) + crypto_close (ci); + if (fd != -1) + close (fd); if (!UpdateTime && modTime != 0) RestoreFileTime (volumePath, modTime, acTime); + Randfree (); return ret; } static BOOL BackupVolumeHeaders (char *backupFile, char *volumePath) { - char path[MAX_PATH]; + char path[TC_MAX_PATH]; char header[HEADER_SIZE * 2]; FILE *f = NULL, *fb = NULL; struct stat volumeStat; int ret = FALSE; - DropEffectiveUserId (); - // Volume path volumePath = AskVolumePath (volumePath, "Enter volume path"); @@ -1705,7 +1993,6 @@ static BOOL BackupVolumeHeaders (char *b { perror ("Cannot read volume's modification and access time"); volumeStat.st_mtime = 0; - ret = FALSE; goto err; } @@ -1766,15 +2053,13 @@ err: static BOOL RestoreVolumeHeader (char *backupFile, char *volumePath) { - char path[MAX_PATH]; + char path[TC_MAX_PATH]; char header[HEADER_SIZE]; FILE *f = NULL, *fb = NULL; struct stat volumeStat; int ret = FALSE; BOOL hiddenVolume; - DropEffectiveUserId (); - // Backup file fb = fopen (backupFile, "rb"); if (!fb) @@ -1805,7 +2090,7 @@ static BOOL RestoreVolumeHeader (char *b break; default: - puts ("Restore headear of:\n 1) Normal/Outer Volume\n 2) Hidden Volume"); + puts ("Restore header of:\n 1) Normal/Outer Volume\n 2) Hidden Volume"); hiddenVolume = AskSelection (1, 1, 2) == 2; break; } @@ -1871,31 +2156,47 @@ err: static BOOL CreateKeyfile (char *path) { uint8_t keyFile[MAX_PASSWORD]; - FILE *f; + FILE *f = NULL; + int ret = FALSE; - DropEffectiveUserId (); + OpenMiceDevice (); - RandBytesFillRequired (sizeof (keyFile)); - if (!RandgetBytes (keyFile, sizeof (keyFile), FALSE)) + if (!Overwrite + && IsFile (path) + && (!IsTerminal || !AskYesNo ("Keyfile already exists - overwrite?", TRUE))) + { + if (!IsTerminal) + error ("Keyfile already exists.\n"); return FALSE; + } f = fopen (path, "wb"); if (!f) { perror ("Cannot open file"); - return FALSE; + goto err; } + if (!RandFillPool ()) + goto err; + + if (!RandgetBytes (keyFile, sizeof (keyFile), FALSE)) + goto err; + if (fwrite (keyFile, 1, sizeof (keyFile), f) != sizeof (keyFile)) { perror ("Cannot write file"); - fclose (f); - return FALSE; + goto err; } - fclose (f); puts ("Keyfile created."); - return TRUE; + ret = TRUE; + +err: + if (f) + fclose (f); + Randfree (); + return ret; } @@ -1907,7 +2208,7 @@ static time_t WindowsFileTime2UnixTime ( static BOOL DumpVolumeProperties (char *volumePath) { - uint64_t startSector, totalSectors; + unsigned long long startSector, totalSectors; time_t modTime = 0, acTime; PCRYPTO_INFO ci = NULL; BOOL ret = FALSE; @@ -1917,6 +2218,9 @@ static BOOL DumpVolumeProperties (char * volumePath = AskVolumePath (volumePath, "Enter volume path"); + if (!NoKeyFiles && !FirstKeyFile) + AskKeyFiles ("Enter keyfile path", &FirstKeyFile); + if (!OpenVolume (volumePath, "Enter password for '%s': ", volumePath, FALSE, &ci, &startSector, &totalSectors, &modTime, &acTime)) goto err; @@ -1932,7 +2236,7 @@ static BOOL DumpVolumeProperties (char * printf ("%sVolume properties:\n" " Location: %s\n" - " Size: %lld bytes\n" + " Size: %llu bytes\n" " Type: %s\n" " Encryption algorithm: %s\n" " Key size: %d bits\n" @@ -1940,8 +2244,6 @@ static BOOL DumpVolumeProperties (char * " Mode of operation: %s\n" " PKCS-5 PRF: %s\n" " PKCS-5 iteration count: %d\n" - " Volume created: %s" - " Header modified: %s" , CmdPasswordValid ? "" : "\n", volumePath, @@ -1952,11 +2254,19 @@ static BOOL DumpVolumeProperties (char * CipherGetBlockSize (EAGetFirstCipher(ci->ea)) * 8, EAGetModeName (ci->ea, ci->mode, TRUE), get_pkcs5_prf_name (ci->pkcs5), - ci->noIterations, - ctime_r (&volCTime, timeBuf), - ctime_r (&headerMTime, timeBuf2) + ci->noIterations ); + memset (timeBuf, 0, sizeof (timeBuf)); + memset (timeBuf2, 0, sizeof (timeBuf2)); + + if (ctime_r (&volCTime, timeBuf) == NULL || ctime_r (&headerMTime, timeBuf2) == NULL) + goto err; + + printf (" Volume created: %s" + " Header modified: %s", + timeBuf, timeBuf2); + ret = TRUE; err: if (ci != NULL) @@ -1972,13 +2282,13 @@ err: static void DumpVersion (FILE *f) { fprintf (f, -"truecrypt %s\n\n" -"Copyright (C) 2004-2006 TrueCrypt Foundation. All Rights Reserved.\n\ +"truecrypt %s\n\n\ +Copyright (C) 2003-2007 TrueCrypt Foundation. All Rights Reserved.\n\ Copyright (C) 1998-2000 Paul Le Roux. All Rights Reserved.\n\ -Copyright (C) 2004 TrueCrypt Team. All Rights Reserved.\n\ -Copyright (C) 1999-2005 Dr. Brian Gladman. All Rights Reserved.\n\ +Copyright (C) 1999-2006 Dr. Brian Gladman. All Rights Reserved.\n\ Copyright (C) 1995-1997 Eric Young. All Rights Reserved.\n\ -Copyright (C) 2001 Markus Friedl. All Rights Reserved.\n\n" +Copyright (C) 2001 Markus Friedl. All Rights Reserved.\n\n\ +Released under the TrueCrypt Collective License 1.2\n\n" , VERSION_STRING); } @@ -1987,11 +2297,12 @@ static void DumpUsage (FILE *f) { fprintf (f, "Usage: truecrypt [OPTIONS] VOLUME_PATH [MOUNT_DIRECTORY]\n" +" or: truecrypt [OPTIONS] -i\n" " or: truecrypt [OPTIONS] -c | --create | -C | --change [VOLUME_PATH]\n" " or: truecrypt [OPTIONS] -d | --dismount | -l | --list [MAPPED_VOLUME]\n" " or: truecrypt [OPTIONS] --backup-headers | --restore-header FILE [VOLUME]\n" " or: truecrypt [OPTIONS] --properties [VOLUME_PATH]\n" -" or: truecrypt --keyfile-create FILE\n" +" or: truecrypt [OPTIONS] --keyfile-create FILE\n" " or: truecrypt -h | --help | --test | -V | --version\n" "\nCommands:\n" " VOLUME_PATH Map volume\n" @@ -2002,39 +2313,44 @@ static void DumpUsage (FILE *f) " -d, --dismount [MAPPED_VOLUME] Dismount and unmap volume\n" " -h, --help Display detailed help\n" " --keyfile-create FILE Create a new keyfile\n" +" -i, --interactive Map and mount volume interactively\n" " -l, --list [MAPPED_VOLUME] List mapped volumes\n" " --properties [VOLUME_PATH] Display properties of volume\n" -" --restore-headers FILE [VOLUME] Restore header of VOLUME from FILE\n" +" --restore-header FILE [VOLUME] Restore header of VOLUME from FILE\n" " --test Test algorithms\n" -" -V, --version Display version information\n" +" -V, --version Display program version and legal notices\n" "\nOptions:\n" " --cluster SIZE Cluster size\n" " --display-keys Display encryption keys\n" " --display-password Display password while typing\n" " --disable-progress Disable progress display\n" " --encryption EA Encryption algorithm\n" -" --filesystem TYPE Filesystem type to mount\n" +" --filesystem TYPE Filesystem type\n" " --hash HASH Hash algorithm\n" " -k, --keyfile FILE|DIR Keyfile for volume\n" " --keyfile-add FILE|DIR New keyfile for volume\n" " -K, --keyfile-protected FILE|DIR Keyfile for protected volume\n" " -M, --mount-options OPTIONS Mount options\n" " -N, --device-number NUMBER Map volume as device number\n" +" --overwrite Overwrite files without confirmation\n" " -p, --password PASSWORD Password for volume\n" " --password-tries NUMBER Password entry tries\n" " -P, --protect-hidden Protect hidden volume\n" +" --random-source FILE Random number generator input file\n" " --quick Use quick format\n" " --update-time Do not preserve timestamps\n" -" -r, --read-only Map/Mount read-only\n" +" -r, --read-only Map/Mount volume as read-only\n" " --size SIZE Volume size\n" " --type TYPE Volume type\n" " -u, --user-mount Set default user and group ID on mount\n" " -v, --verbose Verbose output\n" "\n MAPPED_VOLUME = DEVICE_NUMBER | DEVICE_NAME | MOUNT_POINT | VOLUME_PATH\n" -"For a detailed help use --help or see truecrypt(1) man page.\n" +"For a detailed help, use --help or see truecrypt(1) man page.\n" +"For more information, visit .\n" ); } + static void DumpHelp () { fprintf (stdout, @@ -2044,11 +2360,12 @@ static void DumpHelp () "written to it is transparently encrypted.\n" "\n" "Usage: truecrypt [OPTIONS] VOLUME_PATH [MOUNT_DIRECTORY]\n" +" or: truecrypt [OPTIONS] -i\n" " or: truecrypt [OPTIONS] -c | --create | -C | --change [VOLUME_PATH]\n" " or: truecrypt [OPTIONS] -d | --dismount | -l | --list [MAPPED_VOLUME]\n" " or: truecrypt [OPTIONS] --backup-headers | --restore-header FILE [VOLUME]\n" " or: truecrypt [OPTIONS] --properties [VOLUME_PATH]\n" -" or: truecrypt --keyfile-create FILE\n" +" or: truecrypt [OPTIONS] --keyfile-create FILE\n" " or: truecrypt -h | --help | --test | -V | --version\n" "\n" "Options:\n" @@ -2056,11 +2373,13 @@ static void DumpHelp () "VOLUME_PATH [MOUNT_DIRECTORY]\n" " Open a TrueCrypt volume specified by VOLUME_PATH and map it as a block device\n" " /dev/mapper/truecryptN. N is the first available device number if not\n" -" otherwise specified with -N. To map a hidden volume, specify its password\n" +" otherwise specified with -N. Filesystem of the mapped volume is mounted at\n" +" MOUNT_DIRECTORY if specified. To open a hidden volume, specify its password\n" " and/or keyfiles (the outer volume cannot be mapped at the same time).\n" -" Filesystem of the mapped volume is mounted at MOUNT_DIRECTORY if specified.\n" -" See also options --display-password, --filesystem, -k, -M, -p, -P,\n" -" --password-tries, -r, -u, --update-time.\n" +" See also EXAMPLES and options --display-password, --filesystem, -k, -M, -p, -P,\n" +" --password-tries, -r, -u, --update-time. Note that passing some of the options\n" +" may affect security (see options -i and -p for more information).\n" +" This command requires administrator privileges (sudo(8) is used if available).\n" "\n" "--backup-headers BACKUP_FILE [VOLUME_PATH]\n" " Backup headers of a volume specified by VOLUME_PATH to a file BACKUP_FILE.\n" @@ -2068,8 +2387,7 @@ static void DumpHelp () " normal/outer and hidden volume headers are stored in the backup file even\n" " if there is no hidden volume within the volume (to preserve plausible\n" " deniability). When restoring the volume header, it is possible to select\n" -" which header is to be restored. Note that this command drops effective user\n" -" ID. See also --restore-header.\n" +" which header is to be restored. See also --restore-header.\n" "\n" "-c, --create [VOLUME_PATH]\n" " Create a new volume. Most options are requested from user if not specified\n" @@ -2077,35 +2395,43 @@ static void DumpHelp () " device. Size of the hidden volume should not exceed the free space of the\n" " filesystem on the outer volume. Hidden volume protection (see option -P)\n" " should be used to update the outer volume contents after the hidden volume\n" -" is created. Note that this command drops effective user ID.\n" +" is created. WARNING: To prevent data corruption, you should follow the\n" +" instructions in the EXAMPLES section on how to create a hidden volume.\n" " See also options --cluster, --disable-progress, --display-keys,\n" -" --encryption, -k, --filesystem, --hash, -p, --quick, --size, --type. Note\n" -" that passing some of the options may affect plausible deniability. See option\n" -" -p for more information.\n" +" --encryption, -k, --filesystem, --hash, -p, --random-source, --quick, --size,\n" +" --type. Note that passing some of the options may affect security (see option\n" +" -p for more information).\n" "\n" "-C, --change [VOLUME_PATH]\n" " Change a password and/or keyfile(s) of a volume. Volume path and passwords are\n" " requested from user if not specified on command line. PKCS-5 PRF HMAC hash\n" " algorithm can be changed with option --hash. See also options -k,\n" -" --keyfile-add, -p, -v.\n" +" --keyfile-add, -p, --random-source, -v.\n" "\n" "-d, --dismount [MAPPED_VOLUME]\n" " Dismount and unmap mapped volumes. If MAPPED_VOLUME is not specified, all\n" " volumes are dismounted and unmapped. See below for a description of\n" " MAPPED_VOLUME.\n" +" This command requires administrator privileges (sudo(8) is used if available).\n" "\n" "-h, --help\n" " Display help information.\n" "\n" +"-i, --interactive\n" +" Map and mount a volume interactively. Options which may affect security are\n" +" requested from the user. See option -p for more information.\n" +" This command requires administrator privileges (sudo(8) is used if available).\n" +"\n" "-l, --list [MAPPED_VOLUME]\n" " Display a list of mapped volumes. If MAPPED_VOLUME is not specified, all\n" " volumes are listed. By default, the list contains only volume path and mapped\n" " device name pairs. A more detailed list can be enabled by verbose output\n" " option (-v). See below for a description of MAPPED_VOLUME.\n" +" This command requires administrator privileges (sudo(8) is used if available).\n" "\n" "--keyfile-create FILE\n" " Create a new keyfile using the random number generator. FILE argument specifies\n" -" the output file. Note that this command drops effective user ID.\n" +" the output file.\n" "\n" "--properties [VOLUME_PATH]\n" " Display properties of a volume specified by VOLUME_PATH.\n" @@ -2114,16 +2440,15 @@ static void DumpHelp () " Restore header of a volume specified by VOLUME_PATH from a file BACKUP_FILE.\n" " Volume path is requested from user if not specified on command line.\n" " Type of the restored volume header (normal/hidden) is requested from user if\n" -" not specified with --type. Note that this command drops effective user ID.\n" -" See also --backup-headers.\n" +" not specified with --type. See also --backup-headers.\n" "\n" "--test\n" " Test all internal algorithms used in the process of encryption and decryption.\n" "\n" "-V, --version\n" -" Display version information.\n" +" Display program version and legal notices.\n" "\n" -"MAPPED_VOLUME\n" +"MAPPED_VOLUME:\n" " Specifies a mapped or mounted volume. One of the following forms can be used:\n\n" " 1) Path to the encrypted TrueCrypt volume.\n\n" " 2) Mount directory of the volume's filesystem (if mounted).\n\n" @@ -2143,7 +2468,7 @@ static void DumpHelp () "--display-password\n" " Display password characters while typing.\n" "\n" -"--encryption EA\n" +"--encryption ENCRYPTION_ALGORITHM\n" " Use specified encryption algorithm when creating a new volume.\n" "\n" "--filesystem TYPE\n" @@ -2159,11 +2484,13 @@ static void DumpHelp () " Use specified keyfile to open a volume to be mapped (or when changing password\n" " and/or keyfiles). When a directory is specified, all files inside it will be\n" " used (non-recursively). Additional keyfiles can be specified with multiple -k\n" -" options. See also option -K.\n" +" options. Empty keyfile (-k '') disables interactive requests for keyfiles\n" +" (e.g., when creating a new volume). See also option -K.\n" "\n" "-K, --keyfile-protected FILE | DIRECTORY\n" -" Use specified keyfile to open a hidden volume to be protected. See also\n" -" options -k and -P.\n" +" Use specified keyfile to open a hidden volume to be protected. This option\n" +" may be used only when mounting an outer volume with hidden volume protected.\n" +" See also options -k and -P.\n" "\n" "--keyfile-add FILE | DIRECTORY\n" " Add specified keyfile to a volume when changing its password and/or keyfiles.\n" @@ -2172,16 +2499,19 @@ static void DumpHelp () "\n" "-M, --mount-options OPTIONS\n" " Filesystem mount options. The OPTIONS argument is passed to mount(8)\n" -" command with option -o.\n" +" command with option -o. See also options -r and -u.\n" "\n" "-N, --device-number N\n" " Use device number N when mapping a volume as a block device\n" " /dev/mapper/truecryptN. Default is the first available device.\n" "\n" +"--overwrite\n" +" Overwrite files without prompting the user for confirmation.\n" +"\n" "-p, --password PASSWORD\n" " Use specified password to open a volume. Additional passwords can be\n" " specified with multiple -p options. An empty password can also be specified\n" -" (\"\" in most shells). Note that passing a password on the command line is\n" +" ('' in most shells). Note that passing a password on the command line is\n" " potentially insecure as the password may be visible in the process list\n" " (see ps(1)) and/or stored in a command history file. \n" " \n" @@ -2198,13 +2528,17 @@ static void DumpHelp () " prevented, the whole volume is switched to read-only mode. Verbose list command\n" " (-vl) can be used to query the state of the hidden volume protection. Warning\n" " message is displayed when a volume switched to read-only is being dismounted.\n" -" See also option -r.\n" +" See also options -r and -i.\n" "\n" "--quick\n" " Use quick format when creating a new volume. This option can be used only\n" " when creating a device-hosted volume. Quick format is always used when\n" " creating a hidden volume.\n" "\n" +"--random-source FILE\n" +" Use FILE as a source of random numbers. Standard input is used if '-' is\n" +" specified.\n" +"\n" "-r, --read-only\n" " Map and mount a volume as read-only. Write operations to the volume may not\n" " fail immediately due to the write buffering performed by the system, but the\n" @@ -2220,15 +2554,15 @@ static void DumpHelp () " header. TYPE can be 'normal' or 'hidden'.\n" "\n" "-u, --user-mount\n" -" Set default user and group ID of the filesystem being mounted to the user and\n" -" group ID of the parent process. Some filesystems (like FAT) do not support\n" -" user permissions and, therefore, it is necessary to supply a default user and\n" -" group ID to the system when mounting such filesystems.\n" +" Make a volume being mounted accessible in a non-administrator account. Some\n" +" filesystems (e.g., FAT) do not support Unix-style access control and it is\n" +" necessary to use this option when mounting them. Ownership of the mounted\n" +" filesystem is determined by environment variables set by sudo(8) command.\n" +" Note that Unix-style filesystems (e.g., ext2) do not support this option.\n" "\n" "--update-time\n" -" Do not preserve access and modification timestamps of volume containers and\n" -" access timestamps of keyfiles. By default, timestamps are restored after\n" -" a volume is unmapped or after a keyfile is closed.\n" +" Do not preserve access and modification timestamps of file containers.\n" +" By default, timestamps are restored after a volume is unmapped.\n" "\n" "-v, --verbose\n" " Enable verbose output. Multiple -v options can be specified to increase the\n" @@ -2242,11 +2576,14 @@ static void DumpHelp () "truecrypt -u /dev/hda2 /mnt/tc\n" " Map a volume /dev/hda2 (first ATA disk, primary partition 2) and mount its\n" " filesystem at /mnt/tc. Default user-id is set, which is useful when mounting\n" -" a filesystem like FAT under a non-admin user account.\n" +" a filesystem, such as FAT, for use in a non-administrative account.\n" +"\n" +"truecrypt -i\n" +" Map and mount a volume. Options are requested interactively.\n" "\n" "truecrypt -d\n" " Dismount and unmap all mapped volumes.\n" -" \n" +"\n" "truecrypt -d /root/volume.tc\n" " Dismount and unmap a volume /root/volume.tc.\n" "\n" @@ -2262,21 +2599,22 @@ static void DumpHelp () "truecrypt -P /dev/hdc1 /mnt/tc\n" " Map and mount outer volume /dev/hdc1 and protect hidden volume within it.\n" "\n" -"truecrypt -p \"\" -p \"\" -k key1 -k key2 -K key_hidden -P volume.tc\n" +"truecrypt -p '' -p '' -k key1 -k key2 -K key_hidden -P volume.tc\n" " Map outer volume ./volume.tc and protect hidden volume within it.\n" " The outer volume is opened with keyfiles ./key1 and ./key2 and the\n" " hidden volume with ./key_hidden. Passwords for both volumes are empty.\n" "\n" "truecrypt -c\n" -" Create a new volume." +" Create a new volume. Options are requested interactively." +"\n" +"truecrypt -c /dev/hda2\n" +" Create a new volume hosted at the second primary partition of the first\n" +" ATA disk.\n" "\n" "truecrypt -k keyfile --size 10M --encryption AES --hash SHA-1 -c vol.tc\n" " Create a new volume. Options which are not specified on command line are\n" " requested from the user.\n" "\n" -"truecrypt --type normal -c volume.tc && truecrypt --type hidden -c volume.tc\n" -" Create a new volume and then create a hidden volume inside it." -"\n" "truecrypt --keyfile-add keyfile -C volume.tc\n" " Change password and add a new keyfile to volume.\n" "\n" @@ -2286,25 +2624,36 @@ static void DumpHelp () "truecrypt -k keyfile --keyfile-add keyfile -C volume.tc\n" " Change password and keep previous keyfile.\n" "\n" - -"Report bugs at .\n" +"Creating a hidden volume without risking data corruption:\n" +" 1) Create an outer volume:\n" +" truecrypt --type normal --size 100M -c volume.tc\n" +" 2) Create a hidden volume:\n" +" truecrypt --type hidden --size 50M -c volume.tc\n" +" 3) Mount the outer volume with the hidden volume protected:\n" +" truecrypt -P volume.tc /mnt/tc\n" +" 4) Copy files to the outer volume:\n" +" cp outer_volume_file.txt /mnt/tc\n" +" 5) Dismount the outer volume:\n" +" truecrypt -d volume.tc\n" +" 6) If a warning message has been displayed in 5), start again from 1). Either\n" +" a larger outer volume should be created in 1), or less data should be copied\n" +" to the outer volume in 4).\n" +"\n" +"Report bugs at .\n" ); } + static BOOL DumpMountList (int devNo) { BOOL found = FALSE; int i; - if (!CheckKernelModuleVersion (FALSE)) - return FALSE; - - if (!GetMountList ()) - return FALSE; - - if (devNo == -1 && MountList[0].DeviceNumber == -1) + if (!CheckKernelModuleVersion (FALSE, TRUE) + || !GetMountList (FALSE) + || (devNo == -1 && MountList[0].DeviceNumber == -1)) { - error ("No volumes mounted\n"); + error ("No volumes mapped\n"); return FALSE; } @@ -2331,7 +2680,7 @@ static BOOL DumpMountList (int devNo) printf (TC_MAP_DEV "%d:\n" " Volume: %s\n" " Type: %s\n" - " Size: %lld bytes\n" + " Size: %llu bytes\n" " Encryption algorithm: %s\n" " Mode of operation: %s\n" " Read-only: %s\n" @@ -2342,16 +2691,20 @@ static BOOL DumpMountList (int devNo) e->VolumeSize, eaName, EAGetModeName (e->EA, e->Mode, TRUE), - (e->Flags & FLAG_READ_ONLY) ? "Yes" : "No", - (e->Flags & FLAG_PROTECTION_ACTIVATED) ? "Yes - damage prevented" : ( - (e->Flags & FLAG_HIDDEN_VOLUME_PROTECTION) ? "Yes" : "No" ) + (e->Flags & TC_READ_ONLY) ? "Yes" : "No", + (e->Flags & TC_PROTECTION_ACTIVATED) ? "Yes - damage prevented" : ( + (e->Flags & TC_HIDDEN_VOLUME_PROTECTION) ? "Yes" : "No" ) ); } } if (!found) { - error (TC_MAP_DEV "%d not mapped\n", devNo); + if (devNo == -1) + error ("No volumes mapped\n"); + else + error (TC_MAP_DEV "%d not mapped\n", devNo); + return FALSE; } @@ -2362,6 +2715,7 @@ static BOOL DumpMountList (int devNo) static BOOL EnumMountPoints (char *device, char *mountPoint) { static FILE *m = NULL; + char mp[TC_MAX_PATH], *p; if (device == NULL) { @@ -2377,24 +2731,42 @@ static BOOL EnumMountPoints (char *devic { perror ("fopen /proc/mounts"); return FALSE; - } + } } - if (fscanf (m, "%" MAX_PATH_STR "s %" MAX_PATH_STR "s %*s %*s %*s %*s", - device, mountPoint) != 2) + if (fscanf (m, "%" TC_MAX_PATH_STR "s %" TC_MAX_PATH_STR "s %*s %*s %*s %*s", + device, mp) != 2) { fclose (m); m = NULL; return FALSE; } + // Convert escaped characters + p = mp; + while (*p) + { + if (p[0] == '\\' && p[1] && p[2] && p[3]) + { + char c; + if (sscanf (p + 1, "%o", &c) == 1) + { + *mountPoint++ = c; + p += 4; + continue; + } + } + *mountPoint++ = *p++; + } + *mountPoint = 0; + return TRUE; } static BOOL DismountFileSystem (char *device) { - char mountedDevice[MAX_PATH], mountPoint[MAX_PATH]; + char mountedDevice[TC_MAX_PATH], mountPoint[TC_MAX_PATH]; BOOL result = TRUE; while (EnumMountPoints (mountedDevice, mountPoint)) @@ -2415,21 +2787,17 @@ static BOOL DismountFileSystem (char *de // devNo: -1 = Dismount all volumes static BOOL DismountVolume (int devNo) { - char mapDevice[MAX_PATH]; + char mapDevice[TC_MAX_PATH]; int nMountedVolumes = 0; int i; BOOL found = FALSE; BOOL status = TRUE; - if (!CheckKernelModuleVersion (FALSE)) - return FALSE; - - if (!GetMountList ()) - return FALSE; - - if (devNo == -1 && MountList[0].DeviceNumber == -1) + if (!CheckKernelModuleVersion (FALSE, TRUE) + || !GetMountList (FALSE) + || (devNo == -1 && MountList[0].DeviceNumber == -1)) { - error ("No volumes mounted\n"); + error ("No volumes mapped\n"); return FALSE; } @@ -2437,11 +2805,11 @@ static BOOL DismountVolume (int devNo) // mounted volumes with hidden volume protection for (i = 0; MountList[i].DeviceNumber != -1; i++) { - if (MountList[i].Flags & FLAG_HIDDEN_VOLUME_PROTECTION) + if (MountList[i].Flags & TC_HIDDEN_VOLUME_PROTECTION) { sync (); MountListValid = FALSE; - GetMountList (); + GetMountList (FALSE); break; } } @@ -2456,15 +2824,25 @@ static BOOL DismountVolume (int devNo) BOOL dismounted = FALSE; found = TRUE; - if (e->Flags & FLAG_PROTECTION_ACTIVATED) + snprintf (mapDevice, sizeof (mapDevice), TC_MAP_DEV "%d", e->DeviceNumber); + + if (e->Flags & TC_PROTECTION_ACTIVATED) printf ("WARNING: Write to the hidden volume %s has been prevented!\n", e->VolumePath); - sprintf (mapDevice, TC_MAP_DEV "%d", e->DeviceNumber); if (DismountFileSystem (mapDevice)) { + int t = 10; char name[32]; - sprintf (name, "truecrypt%d", e->DeviceNumber); - dismounted = Execute (FALSE, "dmsetup", "remove", name, NULL); + snprintf (name, sizeof (name), "truecrypt%d", e->DeviceNumber); + + while (t--) + { + dismounted = Execute (t > 0, "dmsetup", "remove", name, NULL); + if (dismounted) + break; + + usleep (200 * 1000); + } if (dismounted && IsFile (e->VolumePath)) { @@ -2472,8 +2850,8 @@ static BOOL DismountVolume (int devNo) status = FALSE; RestoreFileTime (e->VolumePath, - UpdateTime ? time (NULL) : (time_t) e->ModTime, - UpdateTime ? time (NULL) : (time_t) e->AcTime); + (UpdateTime || e->ModTime == 0) ? time (NULL) : (time_t) e->ModTime, + (UpdateTime || e->AcTime == 0) ? time (NULL) : (time_t) e->AcTime); } } @@ -2512,9 +2890,9 @@ static BOOL DismountVolume (int devNo) // Convert a string to device number // text: device number or name or mount point -BOOL ToDeviceNumber (char *text, int *deviceNumber) +static BOOL ToDeviceNumber (char *text, int *deviceNumber) { - char mountedDevice[MAX_PATH], mountPoint[MAX_PATH]; + char mountedDevice[TC_MAX_PATH], mountPoint[TC_MAX_PATH]; int i; if (sscanf (text, "%d", deviceNumber) == 1) @@ -2523,6 +2901,17 @@ BOOL ToDeviceNumber (char *text, int *de if (sscanf (text, TC_MAP_DEV "%d", deviceNumber) == 1) return TRUE; + // Relative path => absolute + if (text[0] != '/') + { + char s[TC_MAX_PATH]; + static char absolute[TC_MAX_PATH]; + + getcwd (s, sizeof (s)); + snprintf (absolute, sizeof (absolute), "%s/%s", s, text); + text = absolute; + } + while (EnumMountPoints (mountedDevice, mountPoint)) { if (strcmp (mountPoint, text) == 0 @@ -2533,7 +2922,7 @@ BOOL ToDeviceNumber (char *text, int *de } } - if (!GetMountList ()) + if (!GetMountList (FALSE)) return FALSE; for (i = 0; MountList[i].DeviceNumber != -1; i++) @@ -2558,7 +2947,7 @@ int main (int argc, char **argv) { char *volumePath = NULL; char *mountPoint = NULL; - char volumePathBuf[MAX_PATH]; + char volumePathBuf[TC_MAX_PATH]; int i, o; int optIndex = 0; FILE *f; @@ -2578,16 +2967,19 @@ int main (int argc, char **argv) {"keyfile-add", required_argument, 0, 0}, {"keyfile-protected", required_argument, 0, 'K'}, {"filesystem", required_argument, 0, 0}, + {"interactive", 0, 0, 'i'}, {"keyfile-create", required_argument, 0, 0}, {"list", optional_argument, 0, 'l'}, {"hash", required_argument, 0, 0}, {"help", 0, 0, 'h'}, {"mount-options", required_argument, 0, 'M'}, - {"password", required_argument, 0, 'l'}, + {"overwrite", 0, 0, 0}, + {"password", required_argument, 0, 'p'}, {"password-tries", required_argument, 0, 0}, {"properties", optional_argument, 0, 0}, {"protect-hidden", 0, 0, 'P'}, {"quick", 0, 0, 0}, + {"random-source", required_argument, 0, 0}, {"read-only", 0, 0, 'r'}, {"restore-header", required_argument, 0, 0}, {"size", required_argument, 0, 0}, @@ -2600,6 +2992,12 @@ int main (int argc, char **argv) {0, 0, 0, 0} }; + if (getuid () != 0 && geteuid () == 0) + { + error ("Running with effective user id 0 (set-euid root) is not supported.\n"); + return FALSE; + } + // Make sure pipes will not use file descriptors <= STDERR_FILENO f = fdopen (STDIN_FILENO, "r"); if (f == NULL) @@ -2626,10 +3024,18 @@ int main (int argc, char **argv) RealUserId = getuid (); RealGroupId = getgid (); + if (getenv ("SUDO_UID")) + sscanf (getenv ("SUDO_UID"), "%d", &RealUserId); + else + UserMountAvailable = FALSE; + + if (getenv ("SUDO_GID")) + sscanf (getenv ("SUDO_GID"), "%d", &RealGroupId); + if (tcgetattr (0, &TerminalAttributes) == 0) IsTerminal = TRUE; - while ((o = getopt_long (argc, argv, "c::C::d::hk:K:l::M:N:p:PruvV", longOptions, &optIndex)) != -1) + while ((o = getopt_long (argc, argv, "c::C::d::hik:K:l::M:N:p:PruvV", longOptions, &optIndex)) != -1) { switch (o) { @@ -2677,12 +3083,18 @@ int main (int argc, char **argv) else devNo = -1; - if (!CheckAdminPrivileges ()) + if (!CheckAdminPrivileges (argc, argv)) return 1; return DismountVolume (devNo) ? 0 : 1; } + case 'i': + Interactive = TRUE; + if (optind < argc) + goto usage; + break; + case 'l': // List { @@ -2699,7 +3111,7 @@ int main (int argc, char **argv) else devNo = -1; - if (!CheckAdminPrivileges ()) + if (!CheckAdminPrivileges (argc, argv)) return 1; return DumpMountList (devNo) ? 0 : 1; @@ -2708,6 +3120,11 @@ int main (int argc, char **argv) case 'k': case 'K': // Keyfile + if (optarg[0] == 0) + { + NoKeyFiles = TRUE; + } + else { KeyFile *kf = malloc (sizeof (KeyFile)); if (!kf) @@ -2715,7 +3132,7 @@ int main (int argc, char **argv) perror ("malloc"); return 1; } - strncpy (kf->FileName, optarg, sizeof (kf->FileName)); + snprintf (kf->FileName, sizeof (kf->FileName), "%s", optarg); if (o == 'k') FirstKeyFile = KeyFileAdd (FirstKeyFile, kf); else @@ -2736,14 +3153,22 @@ int main (int argc, char **argv) // Password if (!CmdPasswordValid) { - strncpy ((char *)CmdPassword.Text, optarg, sizeof (CmdPassword.Text)); + snprintf ((char *)CmdPassword.Text, sizeof (CmdPassword.Text), "%s", optarg); CmdPassword.Length = strlen ((char *)CmdPassword.Text); + + if (!ValidatePassword (&CmdPassword, FALSE)) + return 1; + CmdPasswordValid = TRUE; } else if (!CmdPassword2Valid) { - strncpy ((char *)CmdPassword2.Text, optarg, sizeof (CmdPassword2.Text)); + snprintf ((char *)CmdPassword2.Text, sizeof (CmdPassword2.Text), "%s", optarg); + CmdPassword2.Length = strlen ((char *)CmdPassword2.Text); + if (!ValidatePassword (&CmdPassword2, FALSE)) + return 1; + CmdPassword2Valid = TRUE; } break; @@ -2855,14 +3280,21 @@ int main (int argc, char **argv) if (strcmp ("keyfile-add", longOptions[optIndex].name) == 0) { - KeyFile *kf = malloc (sizeof (KeyFile)); - if (!kf) + if (optarg[0] == 0) { - perror ("malloc"); - return 1; + NoNewKeyFiles = TRUE; + } + else + { + KeyFile *kf = malloc (sizeof (KeyFile)); + if (!kf) + { + perror ("malloc"); + return 1; + } + snprintf (kf->FileName, sizeof (kf->FileName), "%s", optarg); + FirstNewKeyFile = KeyFileAdd (FirstNewKeyFile, kf); } - strncpy (kf->FileName, optarg, sizeof (kf->FileName)); - FirstNewKeyFile = KeyFileAdd (FirstNewKeyFile, kf); break; } @@ -2871,6 +3303,12 @@ int main (int argc, char **argv) return CreateKeyfile (optarg) ? 0 : 1; } + if (strcmp ("overwrite", longOptions[optIndex].name) == 0) + { + Overwrite = TRUE; + break; + } + if (strcmp ("quick", longOptions[optIndex].name) == 0) { Quick = TRUE; @@ -2909,7 +3347,12 @@ int main (int argc, char **argv) return DumpVolumeProperties (volumePath) ? 0 : 1; } - + + if (strcmp ("random-source", longOptions[optIndex].name) == 0) + { + RandomSource = optarg; + break; + } if (strcmp ("restore-header", longOptions[optIndex].name) == 0) { @@ -2961,25 +3404,48 @@ int main (int argc, char **argv) } } - if (optind >= argc) - goto usage; + if (!Interactive) + { + if (optind >= argc) + goto usage; - if (optind < argc) - volumePath = argv[optind++]; + if (optind < argc) + volumePath = argv[optind++]; - if (optind < argc) - mountPoint = argv[optind++]; + if (optind < argc) + mountPoint = argv[optind++]; - if (optind < argc) - goto usage; + if (optind < argc) + goto usage; + } - if (!CheckAdminPrivileges ()) + if (!CheckAdminPrivileges (argc, argv)) return 1; + if (Interactive) + { + static char mp[TC_MAX_PATH] = { 0 }; + + // Volume path + volumePath = AskVolumePath (volumePath, "Enter volume path"); + + // Mount point + mountPoint = AskString ("Enter mount directory [none]", mp, sizeof (mp)); + if (mp[0] == 0) + mountPoint = NULL; + + ProtectHidden = AskYesNo ("Protect hidden volume?", TRUE); + + AskKeyFiles ("Enter keyfile path", &FirstKeyFile); + + if (ProtectHidden) + AskKeyFiles ("Enter keyfile path for hidden volume", &FirstProtVolKeyFile); + } + // Relative path => absolute if (volumePath[0] != '/') { - char s[MAX_PATH]; + char s[TC_MAX_PATH]; getcwd (s, sizeof (s)); snprintf (volumePathBuf, sizeof (volumePathBuf), "%s/%s", s, volumePath); volumePath = volumePathBuf;