File:  [truecrypt] / truecrypt / common / dismount.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:40:01 2018 UTC (8 years, 3 months ago) by root
Branches: drWhax, MAIN
CVS tags: v2_1a, v2_1, HEAD
2.1

/* The source code contained in this file has been derived from the source code
   of Encryption for the Masses 2.02a by Paul Le Roux. Modifications and
   additions to that source code contained in this file are Copyright (c) 2004
   TrueCrypt Team and Copyright (c) 2004 TrueCrypt Foundation. Unmodified
   parts are Copyright (c) 1998-99 Paul Le Roux. This is a TrueCrypt Foundation
   release. Please see the file license.txt for full license details. */

/* WARNING: The code for unmounting volumes is ugly for all Windows versions;
   becarefull what you change here as there might be unintended side effects
   in the device drivers */

/* For Windows NT the part of the system that actually unmounts drives is the
   TrueCryptService, this is because of NT security. Users don't normally have
   enough access to open raw partitions, but services do, TrueCryptService still
   calls this code however. */

#include "TCdefs.h"
#include "crypto.h"
#include "apidrvr.h"

#include "dismount.h"

extern HANDLE hDriver;

#ifdef NTSERVICE
extern void handleWin32Error (HWND dummy);
#else
#include "dlgcode.h"
#endif

/* NT support routines -----------------------------------> */

BOOL
UnmountAllVolumes (HWND hwndDlg, DWORD * os_error, int *err)
{
	MOUNT_LIST_STRUCT driver;
	DWORD dwResult;
	BOOL bResult;
	int i, nMounted = 0;

	*os_error = 0;
	*err = 0;

	bResult = DeviceIoControl (hDriver, MOUNT_LIST, &driver, sizeof (driver), &driver,
				   sizeof (driver), &dwResult, NULL);

	if (bResult == FALSE)
	{
		*os_error = GetLastError ();
		*err = ERR_OS_ERROR;
		return FALSE;
	}

	for (i = 0; i < 26; i++)
		if (driver.ulMountedDrives & 1 << i) nMounted++;

	// Dismount is tried in multiple rounds to ensure dismount of nested containers
	while (driver.ulMountedDrives != 0 && nMounted--)
	{
		for (i = 0; i < 26; i++)
		{
			if (driver.ulMountedDrives & 1 << i)
			{
				UnmountVolume (i, os_error, err);

				if (*err == 0)
					driver.ulMountedDrives &= ~(1 << i);

				if (*err != 0 && *err == ERR_OS_ERROR)
					handleWin32Error (hwndDlg);
			}
		}
	}

	return driver.ulMountedDrives == 0;
}

BOOL
UnmountVolume (int nDosDriveNo, DWORD * os_error, int *err)
{
	UNMOUNT_STRUCT tcUnmount;
	char volMountName[32];
	char dosName[3];
	DWORD dwResult;
	BOOL bResult;

	*os_error = 0;
	*err = 0;

	tcUnmount.nDosDriveNo = nDosDriveNo;

	dosName[0] = (char) (tcUnmount.nDosDriveNo + 'A');
	dosName[1] = ':';
	dosName[2] = 0;

	sprintf (volMountName, "\\\\.\\%s", dosName);

	if (DismountVolume (volMountName, os_error, err) == FALSE)
		return FALSE;

	bResult = DeviceIoControl (hDriver, UNMOUNT, &tcUnmount,
				   sizeof (tcUnmount), &tcUnmount, sizeof (tcUnmount), &dwResult, NULL);

	if (bResult == FALSE)
	{
		*os_error = GetLastError ();
		*err = ERR_OS_ERROR;
		return FALSE;
	}

	if (tcUnmount.nReturnCode == 0)
	{
		bResult = DefineDosDevice (DDD_REMOVE_DEFINITION, dosName, NULL);

		if (bResult == FALSE)
		{
			*os_error = GetLastError ();
			*err = ERR_OS_ERROR;
			return FALSE;
		}
	}
	else
		*err = tcUnmount.nReturnCode;

	return TRUE;
}

BOOL
DismountVolume (char *lpszVolMountName, DWORD * os_error, int *err)
{
	HANDLE hVolume = INVALID_HANDLE_VALUE;
	BOOL bRetry = FALSE;
	DWORD dwResult;
	int i;

	*os_error = 0;
	*err = 0;

      retry:

#ifdef _DEBUG
	OutputDebugString ("mount: dismount volume ----------------->...\n");
#endif

	for (i = 0; i < 16; i++)
	{
		BOOL bResult;

#ifdef _DEBUG
		OutputDebugString ("mount: trying to open the volume...\n");
#endif
		/* Try to open a handle to the mounted volume */
		hVolume = CreateFile (lpszVolMountName, GENERIC_READ | GENERIC_WRITE,
				      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
		if (hVolume == INVALID_HANDLE_VALUE)
		{
			*os_error = GetLastError ();
			*err = ERR_OS_ERROR;
			return FALSE;
		}

#ifdef _DEBUG
		OutputDebugString ("mount: trying to lock the volume...\n");
#endif
		bResult = DeviceIoControl (hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL);
		if (bResult == FALSE)
		{
			DWORD dwError = GetLastError ();
			if (dwError != ERROR_ACCESS_DENIED)
			{
				*os_error = GetLastError ();
				*err = ERR_OS_ERROR;
				CloseHandle (hVolume);
				return FALSE;
			}
			else
			{
				CloseHandle (hVolume);
				hVolume = INVALID_HANDLE_VALUE;
			}
		}
		else
			break;
	}

	if (hVolume == INVALID_HANDLE_VALUE)
	{
		if (bRetry == FALSE)
		{
			bRetry = TRUE;
			Sleep (1000);
			goto retry;
		}

		*err = ERR_FILES_OPEN_LOCK;

		return FALSE;
	}

#ifdef _DEBUG
	OutputDebugString ("mount: trying to dismount the volume...\n");
#endif
	DeviceIoControl (hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL);
#ifdef _DEBUG
	OutputDebugString ("mount: trying to unmount the volume...\n");
#endif

	DeviceIoControl (hVolume, UNMOUNT_PENDING, NULL, 0, NULL, 0, &dwResult, NULL);
	CloseHandle (hVolume);

#ifdef _DEBUG
	OutputDebugString ("<-------------------------------- mount: dismount volume!\n");
#endif

	return TRUE;
}


/* Windows 9x support routines -----------------------------------> */

typedef struct _DIOC_REGISTERS
{
	DWORD reg_EBX;
	DWORD reg_EDX;
	DWORD reg_ECX;
	DWORD reg_EAX;
	DWORD reg_EDI;
	DWORD reg_ESI;
	DWORD reg_Flags;
} DIOC_REGISTERS, *PDIOC_REGISTERS;

#define VWIN32_DIOC_DOS_IOCTL 1

typedef struct PARAMBLOCK
{
	char Operation;
	char NumLocks;
} PARAMBLOCK;


BOOL
DoDeviceClose (int slot, int *err)
{
	MOUNT_LIST_N_STRUCT mount_list;
	UNMOUNT_STRUCT unmount;
	int tries;
	int c;

	mount_list.nDosDriveNo = slot;
	if (DeviceIoControl (hDriver, MOUNT_LIST_N, &mount_list, sizeof (mount_list), NULL, 0, NULL, NULL) == FALSE)
	{
		*err = ERR_OS_ERROR;
		return FALSE;
	}
	else
	{
		if (mount_list.nReturnCode != 0)
		{
			*err = mount_list.nReturnCode;
			return TRUE;
		}
	}

	if (mount_list.mountfilehandle)
		EjectStop ((char)toupper(*((char *) mount_list.wszVolume)), FALSE);

	unmount.nDosDriveNo = slot;
	if (DeviceIoControl (hDriver, UNMOUNT_PENDING, &unmount, sizeof (unmount), NULL, 0, NULL, NULL) == FALSE)
	{
		*err = ERR_OS_ERROR;
		return FALSE;
	}
	else
	{
		if (mount_list.nReturnCode != 0)
		{
			*err = mount_list.nReturnCode;
			return TRUE;
		}
	}

	for (c = 0; c < 20; c++)
	{
		DeviceIoControl (hDriver, RELEASE_TIME_SLICE, NULL, 0, NULL, 0, NULL, NULL);
	}

	for (tries=0;tries<32;tries++)
	{
		DeviceIoControl (hDriver, RELEASE_TIME_SLICE, NULL, 0, NULL, 0, NULL, NULL);
		if (DeviceIoControl (hDriver, UNMOUNT, &unmount, sizeof (UNMOUNT), NULL, 0, NULL, NULL) == FALSE)
		{
			*err = ERR_OS_ERROR;
			return FALSE;
		}
		else
		{
			if (mount_list.nReturnCode == 0)
			{
				*err = 0;
				return TRUE;
			}
		}
	}

	*err = ERR_FILES_OPEN_LOCK;
	return TRUE;
}

int
ioctllock (unsigned int nDrive, int permissions, int function)
{
	HANDLE hDevice;
	DIOC_REGISTERS reg;
	BOOL fResult;
	DWORD cb;
	int lockfunc;

	if (function)
		lockfunc = 0x4a;
	else
		lockfunc = 0x6a;

	hDevice = CreateFile ("\\\\.\\vwin32",
			    0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);

	reg.reg_EAX = 0x440D;
	reg.reg_EBX = nDrive;
	reg.reg_ECX = 0x0800 | lockfunc;
	reg.reg_EDX = permissions;
	reg.reg_Flags = 0x0001;

	fResult = DeviceIoControl (hDevice,
				   VWIN32_DIOC_DOS_IOCTL,
				   &reg, sizeof (reg),
				   &reg, sizeof (reg),
				   &cb, 0);

	CloseHandle (hDevice);

	return reg.reg_Flags & 1;	/* error if carry flag is set */
}

int
locklogdrive (int drivenum, int mode)	/* error if true returned.... */
{
	int a;

	if (mode)
	{
		a = ioctllock (drivenum, 0, 1);
		a = ioctllock (drivenum, 4, 1);
	}
	else
	{
		a = 0;
		ioctllock (drivenum, 0, 0);
		ioctllock (drivenum, 0, 0);
	}

	return a;
}



int
ld (char *d, int mode)
{
	int drivelett = d[0];
	int a = 1;

	drivelett -= 'A';
	drivelett += 1;

	if ((drivelett > 1) && drivelett < 27)
		a = (locklogdrive (drivelett, mode));

	return a;

}

BOOL
CloseSlot (int slot, int brutal, int *err)
{
	char dr[3];
	BOOL bResult;

	if (brutal);		/* Remove warning */

	dr[0] = (char) (slot + 'A');
	dr[1] = ':';
	dr[2] = 0;

	if (ld (dr, 1))
	{
		bResult = TRUE;
		*err = ERR_FILES_OPEN_LOCK;
	}
	else
	{
		bResult = DoDeviceClose (slot, err);
		ld (dr, 0);
	}

	return bResult;
}


int
EjectStop (char Driveletter, BOOL function)
{
	HANDLE hDevice;
	DIOC_REGISTERS reg;
	BOOL fResult;
	DWORD cb;
	int lockfunc;
	PARAMBLOCK p;

	if (Driveletter == 0)
		return 0;

	Driveletter -= 'A';
	Driveletter++;

	lockfunc = 0x48;

	if (function == TRUE)
		p.Operation = 0;/* lock */
	else
		p.Operation = 1;

	hDevice = CreateFile ("\\\\.\\vwin32", 0, 0, NULL, 0,
			      FILE_FLAG_DELETE_ON_CLOSE, NULL);

	reg.reg_EAX = 0x440D;
	reg.reg_EBX = Driveletter;
	reg.reg_ECX = 0x0800 | lockfunc;
	reg.reg_EDX = (unsigned long) &p;
	reg.reg_Flags = 0x0001;

	fResult = DeviceIoControl (hDevice,
				   VWIN32_DIOC_DOS_IOCTL,
				   &reg, sizeof (reg),
				   &reg, sizeof (reg),
				   &cb, 0);

	CloseHandle (hDevice);

	return reg.reg_Flags & 1;	/* error if carry flag is set */
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.