--- truecrypt/linux/cli/cli.c 2018/04/24 16:45:03 1.1.1.3 +++ truecrypt/linux/cli/cli.c 2018/04/24 16:46:50 1.1.1.5 @@ -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.2 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,47 +29,25 @@ 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; @@ -82,6 +63,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 +73,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 +84,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,7 +119,7 @@ static void OnExit () } -BOOL CheckAdminPrivileges () +static BOOL CheckAdminPrivileges () { char *env; @@ -143,7 +131,7 @@ BOOL CheckAdminPrivileges () if (getuid () != 0) { - // Impersonate root to support executing of commands like mount + // Impersonate root to support execution of commands like mount setuid (0); // Allow execution of system binaries only @@ -154,18 +142,18 @@ BOOL CheckAdminPrivileges () } -void DropEffectiveUserId () +static void DropEffectiveUserId () { setuid (getuid ()); } -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 +170,8 @@ static BOOL WaitChild (BOOL quiet, char return FALSE; } + LastExitStatus = WEXITSTATUS (status); + if (!WIFEXITED (status) || (WIFEXITED (status) && WEXITSTATUS (status))) { @@ -194,12 +184,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,7 +235,7 @@ BOOL Execute (BOOL quiet, char *execName execvp (execName, args); - fprintf (stderr, "%s ", execName); + fprintf (stderr, "(%s) ", execName); perror ("execlp"); _exit (1); } @@ -313,8 +305,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) + { + sprintf (module, "%s/truecrypt.ko", TC_SHARE_KERNEL, r1, r2, r3); + if (IsFile (module) && Execute (TRUE, "insmod", module, NULL)) + return TRUE; + + sprintf (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 +341,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 +393,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 +413,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 +493,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 +502,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,6 +512,7 @@ static BOOL GetMountList () &e->Hidden, &e->ReadOnlyStart, &e->ReadOnlyEnd, + &e->UserId, &e->ModTime, &e->AcTime, &e->Flags, @@ -503,7 +549,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 +566,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) @@ -545,16 +591,27 @@ static BOOL DeleteLoopDevice (int loopDe { char dev[32]; BOOL r; + int i; - sprintf (dev, LOOP_DEV "%d", loopDeviceNo); + sprintf (dev, TC_LOOP_DEV "%d", loopDeviceNo); if (!IsBlockDevice (dev)) - sprintf (dev, LOOP_DEV "/%d", loopDeviceNo); + sprintf (dev, TC_LOOP_DEV "/%d", loopDeviceNo); + + for (i = 0; i < 10; i++) + { + r = Execute (TRUE, "losetup", "-d", dev, NULL); + if (r) + break; - r = Execute (FALSE, "losetup", "-d", dev, NULL); + 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 +619,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 +634,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 +681,33 @@ static char *AskString (char *prompt, ch } +static BOOL ValidatePassword (Password *password) +{ + 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\n"); + return FALSE; + } + } + + return TRUE; +} + + static void AskPassword (char *prompt, char *volumePath, Password *password) { struct termios noEcho; + char pw[2048]; if (tcgetattr (0, &TerminalAttributes) == 0) { @@ -614,19 +719,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; + strncpy ((char *)password->Text, pw, sizeof (password->Text)); password->Length = strlen ((char *)password->Text); + + if (ValidatePassword (password)) + break; } - else - password->Length = 0; + + burn(pw, sizeof (pw)); if (IsTerminal && !DisplayPassword) { @@ -638,7 +756,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 +768,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; + } + strncpy (kf->FileName, path, sizeof (kf->FileName)); + *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; } @@ -724,7 +868,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 +890,19 @@ static BOOL OpenVolume (char *volumePath if (r == ERR_PASSWORD_WRONG) { + char s[128]; + + sprintf (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; } } @@ -807,11 +958,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 +977,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 +1023,12 @@ static BOOL MountVolume (char *volumePat return FALSE; } + if (mountPoint && !IsMountPointAvailable (mountPoint)) + { + error ("Mount directory %s 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 +1043,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 +1066,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 +1081,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; } @@ -927,7 +1100,7 @@ static BOOL MountVolume (char *volumePat if (!LoadKernelModule ()) goto err; - if (!CheckKernelModuleVersion (TRUE)) + if (!CheckKernelModuleVersion (TRUE, FALSE)) goto err; // dmsetup @@ -969,7 +1142,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 +1155,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)); @@ -1012,9 +1186,9 @@ static BOOL MountVolume (char *volumePat // Mount if (mountPoint) { - char fstype[64], opts[128]; + char fstype[64] = "-t"; + char opts[1024]; - strcpy (fstype, "-t"); if (Filesystem) strncat (fstype, Filesystem, sizeof (fstype) - 3); else @@ -1024,20 +1198,28 @@ static BOOL MountVolume (char *volumePat if (MountOpts) { strcat (opts, ","); - strncat (opts, MountOpts, sizeof (opts) - 6); + strncat (opts, MountOpts, 256); } + if (RealUserId != 0) + strcat (opts, ",nosuid"); + if (UserMount) { // Set default uid and gid char s[64]; - sprintf (s, ",uid=%d,gid=%d", RealUserId, RealGroupId); + sprintf (s, ",uid=%d,gid=%d,umask=077", RealUserId, RealGroupId); strcat (opts, s); } 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 +1245,180 @@ err: } -int RandGetBytesAvailable () -{ - 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; +static void HexDump (unsigned __int8 *data, unsigned int length) +{ + 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" + "- Install TrueCrypt as set-euid root.\n" + "- Add read permission to mouse device for all users (chmod o+r " 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; + } + if (i >= TC_REQUIRED_KEYSTROKES) + break; -double GetTime () -{ - struct timeval tv; - gettimeofday (&tv, NULL); + 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; - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; + 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 +1440,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,18 +1461,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; + OpenMiceDevice (); DropEffectiveUserId (); // Volume type @@ -1262,7 +1486,6 @@ static BOOL CreateVolume (char *hostPath case VOLUME_TYPE_HIDDEN: hiddenVolume = TRUE; - Quick = TRUE; break; default: @@ -1271,8 +1494,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 +1509,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 +1602,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,25 +1614,8 @@ 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) { @@ -1419,13 +1639,26 @@ ea: else pw = &CmdPassword; + 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, !UpdateTime)) { error ("Error while processing keyfiles\n"); goto err; } - RandBytesFillRequired (randReq); + if (!RandFillPool ()) + goto err; // Create volume header r = VolumeWriteHeader (header, @@ -1525,37 +1758,49 @@ ea: 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) @@ -1578,19 +1823,30 @@ static BOOL ChangePassword (char *volume } else 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)) { 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 +1854,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 +1873,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 +1880,6 @@ static BOOL ChangePassword (char *volume if (r != 0) { error ("Volume header creation failed.\n"); - ret = FALSE; goto err; } @@ -1637,7 +1891,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 +1899,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,22 +1913,36 @@ 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; @@ -1705,7 +1964,6 @@ static BOOL BackupVolumeHeaders (char *b { perror ("Cannot read volume's modification and access time"); volumeStat.st_mtime = 0; - ret = FALSE; goto err; } @@ -1766,7 +2024,7 @@ 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; @@ -1805,7 +2063,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 +2129,48 @@ err: static BOOL CreateKeyfile (char *path) { uint8_t keyFile[MAX_PASSWORD]; - FILE *f; + FILE *f = NULL; + int ret = FALSE; + OpenMiceDevice (); DropEffectiveUserId (); - 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 +2182,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 +2192,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 +2210,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 +2218,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 +2228,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,11 +2256,11 @@ 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\ +Released under the TrueCrypt Collective License 1.1\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" , VERSION_STRING); @@ -1987,11 +2271,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 +2287,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 +2334,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 +2347,12 @@ 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" "\n" "--backup-headers BACKUP_FILE [VOLUME_PATH]\n" " Backup headers of a volume specified by VOLUME_PATH to a file BACKUP_FILE.\n" @@ -2077,17 +2369,19 @@ 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" +" Note that this command drops effective user ID.\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" @@ -2097,6 +2391,10 @@ static void DumpHelp () "-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" +"\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" @@ -2121,9 +2419,9 @@ static void DumpHelp () " 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 +2441,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 +2457,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 +2472,20 @@ 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. This option can be specified only by an administrator.\n" +" 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 +2502,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" @@ -2221,9 +2529,10 @@ static void DumpHelp () "\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" +" group ID of the process which executed TrueCrypt. Some filesystems (e.g., FAT)\n" +" do not support Unix-style access control and, therefore, it is necessary to\n" +" supply a default user and group ID to the operating system when mounting them.\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" @@ -2242,11 +2551,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 under a non-admin user 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 +2574,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 +2599,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 +2655,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,9 +2666,9 @@ 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" ) ); } } @@ -2362,6 +2686,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 +2702,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 +2758,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 +2776,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,10 +2795,18 @@ static BOOL DismountVolume (int devNo) BOOL dismounted = FALSE; found = TRUE; - if (e->Flags & FLAG_PROTECTION_ACTIVATED) + sprintf (mapDevice, TC_MAP_DEV "%d", e->DeviceNumber); + + if (RealUserId != 0 && e->UserId != RealUserId) + { + error ("Dismount denied: %s mapped by a different user\n", mapDevice); + status = FALSE; + continue; + } + + 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)) { char name[32]; @@ -2472,8 +2819,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 +2859,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 +2870,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 +2891,7 @@ BOOL ToDeviceNumber (char *text, int *de } } - if (!GetMountList ()) + if (!GetMountList (FALSE)) return FALSE; for (i = 0; MountList[i].DeviceNumber != -1; i++) @@ -2558,7 +2916,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 +2936,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}, @@ -2629,7 +2990,7 @@ int main (int argc, char **argv) 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) { @@ -2683,6 +3044,12 @@ int main (int argc, char **argv) return DismountVolume (devNo) ? 0 : 1; } + case 'i': + Interactive = TRUE; + if (optind < argc) + goto usage; + break; + case 'l': // List { @@ -2708,6 +3075,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) @@ -2724,6 +3096,12 @@ int main (int argc, char **argv) break; case 'M': + if (RealUserId != 0) + { + error ("--mount-options can be specified only by an administrator (see options -r, -u)\n"); + return 1; + } + MountOpts = optarg; break; @@ -2738,12 +3116,20 @@ int main (int argc, char **argv) { strncpy ((char *)CmdPassword.Text, optarg, sizeof (CmdPassword.Text)); CmdPassword.Length = strlen ((char *)CmdPassword.Text); + + if (!ValidatePassword (&CmdPassword)) + return 1; + CmdPasswordValid = TRUE; } else if (!CmdPassword2Valid) { strncpy ((char *)CmdPassword2.Text, optarg, sizeof (CmdPassword2.Text)); + CmdPassword2.Length = strlen ((char *)CmdPassword2.Text); + if (!ValidatePassword (&CmdPassword2)) + return 1; + CmdPassword2Valid = TRUE; } break; @@ -2855,14 +3241,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; + } + strncpy (kf->FileName, optarg, sizeof (kf->FileName)); + FirstNewKeyFile = KeyFileAdd (FirstNewKeyFile, kf); } - strncpy (kf->FileName, optarg, sizeof (kf->FileName)); - FirstNewKeyFile = KeyFileAdd (FirstNewKeyFile, kf); break; } @@ -2871,6 +3264,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 +3308,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 +3365,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 ()) 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;