📄 cli.c
字号:
if (!GetMountList (FALSE))
return FALSE;
for (i = 0; MountList[i].DeviceNumber != -1; i++)
if (strcmp (volumePath, MountList[i].VolumePath) == 0)
return TRUE;
return FALSE;
}
static int GetFreeMapDevice ()
{
FILE *p;
char cmd[128];
int n;
if (!GetMountList (FALSE))
return -1;
for (n = 0; n < TC_MAX_MINOR; n++)
{
int j = 0;
while (MountList[j].DeviceNumber != -1)
{
if (MountList[j].DeviceNumber == n)
break;
j++;
}
if (MountList[j].DeviceNumber == -1)
return n;
}
return -1;
}
static BOOL DeleteLoopDevice (int loopDeviceNo)
{
char dev[32];
BOOL r;
int i;
sprintf (dev, TC_LOOP_DEV "%d", loopDeviceNo);
if (!IsBlockDevice (dev))
sprintf (dev, TC_LOOP_DEV "/%d", loopDeviceNo);
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;
}
static int AskSelection (int defaultChoice, int min, int max)
{
int c;
char s[3];
while (1)
{
printf ("Select [%d]: ", defaultChoice);
if (fgets (s, sizeof (s), stdin) && sscanf (s, "%d", &c) == 1)
{
if (c < min || c > max)
continue;
puts ("");
return c;
}
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);
if (fgets (buf, maxSize, stdin))
{
char *lf = strchr (buf, '\n');
if (lf)
lf[0] = 0;
return buf;
}
return NULL;
}
static void AskPassword (char *prompt, char *volumePath, Password *password)
{
struct termios noEcho;
if (tcgetattr (0, &TerminalAttributes) == 0)
{
noEcho = TerminalAttributes;
if (!DisplayPassword)
{
noEcho.c_lflag &= ~ECHO;
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))
{
char *newl = strchr ((char *)password->Text, '\n');
if (newl) newl[0] = 0;
password->Length = strlen ((char *)password->Text);
}
else
password->Length = 0;
if (IsTerminal && !DisplayPassword)
{
tcsetattr (0, TCSANOW, &TerminalAttributes);
puts ("");
}
}
static char *AskVolumePath (char *volumePath, char *prompt)
{
static char path[TC_MAX_PATH];
// Volume path
while (!volumePath || !volumePath[0])
{
volumePath = AskString (prompt, path, sizeof (path));
}
return volumePath;
}
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];
FILE *f = NULL;
struct stat volumeStat;
int tries = PasswordEntryTries;
char msg[128];
BOOL ret = FALSE;
int r;
memset (&volumeStat, 0, sizeof (volumeStat));
if ((!UpdateTime || ReadOnly)
&& IsFile (volumePath) && stat (volumePath, &volumeStat) != 0)
{
perror ("Cannot open volume");
volumeStat.st_ctime = 0;
goto err;
}
f = fopen (volumePath, "rb");
if (!f)
{
perror ("Cannot open volume");
goto err;
}
do
{
Password *pw = &password;
if (!secondaryPassword && !CmdPasswordValid || (secondaryPassword && !CmdPassword2Valid))
AskPassword (prompt, promptArg, &password);
else
pw = secondaryPassword ? &CmdPassword2 : &CmdPassword;
if ((!secondaryPassword
&& FirstKeyFile
&& !KeyFilesApply (pw, FirstKeyFile, !UpdateTime))
|| (secondaryPassword
&& FirstProtVolKeyFile
&& !KeyFilesApply (pw, FirstProtVolKeyFile, !UpdateTime)))
{
error ("Error while processing keyfiles\n");
goto err;
}
// Normal header
fseek (f, 0, SEEK_SET);
if (fread (header, 1, SECTOR_SIZE, f) != SECTOR_SIZE)
{
perror ("Cannot read volume header");
goto err;
}
if (fseek (f, 0, SEEK_END) == -1)
{
perror ("Cannot determine volume size");
goto err;
}
r = VolumeReadHeader (header, pw, cryptoInfo);
if (r == 0)
{
*totalSectors = ftello (f) / SECTOR_SIZE - 1;
*startSector = 1;
ret = TRUE;
break;
}
if (r == ERR_PASSWORD_WRONG)
{
// Hidden header
if (fseek (f, -HIDDEN_VOL_HEADER_OFFSET, SEEK_END) == -1
|| fread (header, 1, SECTOR_SIZE, f) != SECTOR_SIZE)
{
perror ("Cannot read hidden volume header");
if (IsFile (volumePath))
error ("Please check the filesystem supports files larger than 2GB.\n");
goto err;
}
r = VolumeReadHeader (header, pw, cryptoInfo);
if (r == 0)
{
*startSector = (ftello (f)
+ SECTOR_SIZE * 2
- (*cryptoInfo)->hiddenVolumeSize
- HIDDEN_VOL_HEADER_OFFSET) / SECTOR_SIZE;
*totalSectors = (*cryptoInfo)->hiddenVolumeSize / SECTOR_SIZE;
ret = TRUE;
break;
}
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 (s);
continue;
}
else
{
error ("%s\n", s);
goto err;
}
}
}
// Report errors
switch (r)
{
case ERR_NEW_VERSION_REQUIRED:
strcpy (msg, "A newer version of TrueCrypt is required to open this volume.");
break;
default:
sprintf (msg, "Volume cannot be opened: Error %d", r);
break;
}
if (IsTerminal)
printf ("%s\n", msg);
else
error ("%s\n", msg);
goto err;
} while (IsTerminal
&& --tries > 0
&& ((!secondaryPassword && !CmdPasswordValid)
|| (secondaryPassword && !CmdPassword2Valid)));
fclose (f);
if (!UpdateTime)
RestoreFileTime (volumePath, volumeStat.st_mtime, volumeStat.st_atime);
*modTime = volumeStat.st_mtime;
*acTime = volumeStat.st_atime;
return ret;
err:
*cryptoInfo = NULL;
if (f)
fclose (f);
if (volumeStat.st_ctime != 0 && !UpdateTime)
RestoreFileTime (volumePath, volumeStat.st_mtime, volumeStat.st_atime);
*totalSectors = 0;
return FALSE;
}
static char *EscapeSpaces (char *string)
{
static char escapedString[TC_MAX_PATH * 2];
char *e = escapedString;
char c;
if (strlen (string) > TC_MAX_PATH)
return NULL;
while ((c = *string++))
{
if (c == ' ')
*e++ = '\\';
*e++ = c;
}
return escapedString;
}
static BOOL MountVolume (char *volumePath, char *mountPoint)
{
char hostDevice[TC_MAX_PATH];
char mapDevice[TC_MAX_PATH];
int loopDevNo = -1;
PCRYPTO_INFO ci = NULL;
unsigned long long startSector, totalSectors;
unsigned long long readOnlyStartSector = 0, readOnlySectors = 0;
int pfd[2];
int pid, res, devNo;
time_t modTime, acTime;
FILE *f, *w;
int flags;
int i;
int tries = PasswordEntryTries;
#if DEBUG
if (!AutoTestAlgorithms ())
{
error ("Self-tests of algorithms FAILED!\n");
return FALSE;
}
#endif
if (IsVolumeMounted (volumePath))
{
error ("Volume already mapped\n");
return FALSE;
}
if (!OpenVolume (volumePath, "Enter password for '%s': ", volumePath, FALSE,
&ci, &startSector, &totalSectors, &modTime, &acTime))
goto err;
if (totalSectors == 0)
{
error ("Illegal volume size (0 bytes).\n");
goto err;
}
// Hidden volume protection
if (ProtectHidden)
{
PCRYPTO_INFO ciH = NULL;
unsigned long long startSectorH, totalSectorsH;
if (OpenVolume (volumePath, "Enter hidden volume password: ", "", TRUE,
&ciH, &startSectorH, &totalSectorsH, &modTime, &acTime))
{
readOnlyStartSector = startSectorH;
readOnlySectors = startSectorH + totalSectorsH;
}
if (ciH)
crypto_close (ciH);
if (readOnlySectors == 0)
goto err;
}
// Headers decrypted
// Loopback
if (IsFile (volumePath))
{
int i;
for (i = 0; i < TC_MAX_MINOR; i++)
{
snprintf (hostDevice, sizeof (hostDevice), TC_LOOP_DEV "%d", i);
if (!IsBlockDevice (hostDevice))
{
snprintf (hostDevice, sizeof (hostDevice), TC_LOOP_DEV "/%d", i);
if (!IsBlockDevice (hostDevice))
continue;
}
if (Execute (TRUE, "losetup", hostDevice, volumePath, NULL))
break;
}
if (i >= TC_MAX_MINOR)
{
error ("No free loopback device available for file-hosted volume\n");
goto err;
}
loopDevNo = i;
if (Verbose > 1)
printf ("Attached %s to %s\n", volumePath, hostDevice);
}
else
strncpy (hostDevice, volumePath, sizeof (hostDevice));
// Load kernel module
if (!LoadKernelModule ())
goto err;
if (!CheckKernelModuleVersion (TRUE, FALSE))
goto err;
// dmsetup
devNo = UseDeviceNumber == -1 ? GetFreeMapDevice () : UseDeviceNumber;
if (devNo == -1)
{
error ("Maximum number of volumes mounted\n");
goto err;
}
sprintf (mapDevice, "truecrypt%d", devNo);
pipe (pfd);
pid = fork ();
if (pid == -1)
{
perror ("fork");
goto err;
}
else if (pid == 0)
{
SecurityCleanup ();
close (pfd[1]);
dup2 (pfd[0], STDIN_FILENO);
execlp ("dmsetup", "dmsetup", "create", mapDevice, NULL);
perror ("execlp dmsetup");
_exit (1);
}
close (pfd[0]);
w = fdopen (pfd[1], "a");
if (w == NULL)
{
perror ("fdopen");
goto err;
}
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]);
fprintf (w, " ");
for (i = 0; i < (int)sizeof (ci->iv); i++)
fprintf (w, "%02x", ci->iv[i]);
flags = 0;
if (ReadOnly)
flags |= TC_READ_ONLY;
else if (ProtectHidden)
flags |= TC_HIDDEN_VOLUME_PROTECTION;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -