Annotation of truecrypt/driver/ntvol.c, revision 1.1.1.15

1.1.1.10  root        1: /*
1.1.1.12  root        2:  Legal Notice: Some portions of the source code contained in this file were
                      3:  derived from the source code of Encryption for the Masses 2.02a, which is
                      4:  Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
                      5:  Agreement for Encryption for the Masses'. Modifications and additions to
                      6:  the original source code (contained in this file) and all other portions of
                      7:  this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
1.1.1.15! root        8:  by the TrueCrypt License 2.6 the full text of which is contained in the
1.1.1.12  root        9:  file License.txt included in TrueCrypt binary and source code distribution
1.1.1.10  root       10:  packages. */
1.1       root       11: 
                     12: #include "TCdefs.h"
1.1.1.15! root       13: #include <wchar.h>
1.1.1.6   root       14: #include "Crypto.h"
                     15: #include "Volumes.h"
1.1       root       16: 
1.1.1.6   root       17: #include "Apidrvr.h"
1.1.1.14  root       18: #include "DriveFilter.h"
1.1.1.6   root       19: #include "Ntdriver.h"
                     20: #include "Ntvol.h"
1.1.1.14  root       21: #include "VolumeFilter.h"
1.1       root       22: 
1.1.1.13  root       23: #include "Boot/Windows/BootCommon.h"
                     24: 
1.1.1.6   root       25: #include "Cache.h"
1.1       root       26: 
1.1.1.10  root       27: #if 0 && _DEBUG
                     28: #define EXTRA_INFO 1
                     29: #endif
1.1       root       30: 
                     31: #pragma warning( disable : 4127 )
                     32: 
1.1.1.14  root       33: volatile BOOL ProbingHostDeviceForWrite = FALSE;
                     34: 
                     35: 
1.1.1.15! root       36: NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
1.1       root       37:               PEXTENSION Extension,
1.1.1.6   root       38:               MOUNT_STRUCT *mount,
1.1       root       39:               PWSTR pwszMountVolume,
                     40:               BOOL bRawDevice)
                     41: {
                     42:        FILE_STANDARD_INFORMATION FileStandardInfo;
                     43:        FILE_BASIC_INFORMATION FileBasicInfo;
                     44:        OBJECT_ATTRIBUTES oaFileAttributes;
                     45:        UNICODE_STRING FullFileName;
                     46:        IO_STATUS_BLOCK IoStatusBlock;
1.1.1.6   root       47:        PCRYPTO_INFO cryptoInfoPtr = NULL;
                     48:        PCRYPTO_INFO tmpCryptoInfo = NULL;
1.1       root       49:        LARGE_INTEGER lDiskLength;
1.1.1.15! root       50:        __int64 partitionStartingOffset = 0;
1.1.1.6   root       51:        int volumeType;
1.1.1.4   root       52:        char *readBuffer = 0;
1.1.1.5   root       53:        NTSTATUS ntStatus = 0;
1.1.1.15! root       54:        BOOL forceAccessCheck = (!bRawDevice && !(OsMajorVersion == 5 &&OsMinorVersion == 0)); // Windows 2000 does not support OBJ_FORCE_ACCESS_CHECK attribute
1.1       root       55: 
                     56:        Extension->pfoDeviceFile = NULL;
                     57:        Extension->hDeviceFile = NULL;
1.1.1.6   root       58:        Extension->bTimeStampValid = FALSE;
1.1       root       59: 
1.1.1.4   root       60:        RtlInitUnicodeString (&FullFileName, pwszMountVolume);
1.1.1.15! root       61:        InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0), NULL, NULL);
1.1.1.4   root       62:        KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE);
                     63: 
1.1.1.15! root       64:        if (Extension->SecurityClientContextValid)
        !            65:        {
        !            66:                ntStatus = SeImpersonateClientEx (&Extension->SecurityClientContext, NULL);
        !            67:                if (!NT_SUCCESS (ntStatus))
        !            68:                        goto error;
        !            69:        }
        !            70: 
1.1.1.4   root       71:        // If we are opening a device, query its size first
                     72:        if (bRawDevice)
1.1       root       73:        {
1.1.1.5   root       74:                PARTITION_INFORMATION pi;
1.1.1.10  root       75:                PARTITION_INFORMATION_EX pix;
1.1.1.15! root       76:                LARGE_INTEGER diskLengthInfo;
1.1.1.4   root       77:                DISK_GEOMETRY dg;
1.1       root       78: 
1.1.1.4   root       79:                ntStatus = IoGetDeviceObjectPointer (&FullFileName,
                     80:                        FILE_READ_DATA,
                     81:                        &Extension->pfoDeviceFile,
                     82:                        &Extension->pFsdDevice);
                     83: 
                     84:                if (!NT_SUCCESS (ntStatus))
                     85:                        goto error;
                     86: 
1.1.1.12  root       87:                if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY, (char *) &dg, sizeof (dg))))
1.1.1.4   root       88:                {
1.1.1.10  root       89:                        lDiskLength.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.BytesPerSector;
                     90:                        mount->BytesPerSector = dg.BytesPerSector;
1.1.1.4   root       91:                }
1.1.1.5   root       92:                else
1.1.1.10  root       93:                        lDiskLength.QuadPart = 0;
1.1.1.4   root       94: 
1.1.1.10  root       95:                // Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails
1.1.1.12  root       96:                if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO_EX, (char *) &pix, sizeof (pix))))
1.1.1.13  root       97:                {
1.1.1.10  root       98:                        lDiskLength.QuadPart = pix.PartitionLength.QuadPart;
1.1.1.13  root       99:                        partitionStartingOffset = pix.StartingOffset.QuadPart;
                    100:                }
1.1.1.10  root      101:                // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
1.1.1.12  root      102:                else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO, (char *) &pi, sizeof (pi))))
1.1.1.13  root      103:                {
1.1.1.10  root      104:                        lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
1.1.1.13  root      105:                        partitionStartingOffset = pi.StartingOffset.QuadPart;
                    106:                }
1.1.1.15! root      107:                else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_LENGTH_INFO, &diskLengthInfo, sizeof (diskLengthInfo))))
        !           108:                {
        !           109:                        lDiskLength = diskLengthInfo;
        !           110:                }
1.1       root      111: 
1.1.1.14  root      112:                ProbingHostDeviceForWrite = TRUE;
                    113: 
                    114:                if (!mount->bMountReadOnly
                    115:                        && TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
                    116:                                IsHiddenSystemRunning() ? TC_IOCTL_DISK_IS_WRITABLE : IOCTL_DISK_IS_WRITABLE, NULL, 0) == STATUS_MEDIA_WRITE_PROTECTED)
1.1.1.10  root      117:                {
                    118:                        mount->bMountReadOnly = TRUE;
                    119:                        DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
1.1.1.4   root      120:                }
1.1.1.14  root      121: 
                    122:                ProbingHostDeviceForWrite = FALSE;
1.1.1.4   root      123:        }
1.1       root      124: 
1.1.1.10  root      125:        if (mount->BytesPerSector == 0)
                    126:                mount->BytesPerSector = SECTOR_SIZE;
                    127: 
                    128:        Extension->HostBytesPerSector = mount->BytesPerSector;
                    129: 
1.1.1.4   root      130:        // Open the volume hosting file/device
                    131:        if (!mount->bMountReadOnly)
                    132:        {
                    133:                ntStatus = ZwCreateFile (&Extension->hDeviceFile,
                    134:                        GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
                    135:                        &oaFileAttributes,
                    136:                        &IoStatusBlock,
                    137:                        NULL,
                    138:                        FILE_ATTRIBUTE_NORMAL |
                    139:                        FILE_ATTRIBUTE_SYSTEM,
                    140:                        mount->bExclusiveAccess ? 0 : FILE_SHARE_READ | FILE_SHARE_WRITE,
                    141:                        FILE_OPEN,
1.1.1.10  root      142:                        FILE_RANDOM_ACCESS |
1.1.1.4   root      143:                        FILE_WRITE_THROUGH |
1.1.1.10  root      144:                        (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
1.1.1.4   root      145:                        FILE_SYNCHRONOUS_IO_NONALERT,
                    146:                        NULL,
                    147:                        0);
                    148:        }
1.1       root      149: 
1.1.1.10  root      150:        /* 26-4-99 NT for some partitions returns this code, it is really a     access denied */
1.1       root      151:        if (ntStatus == 0xc000001b)
                    152:                ntStatus = STATUS_ACCESS_DENIED;
1.1.1.6   root      153:        
1.1.1.4   root      154:        if (mount->bMountReadOnly || ntStatus == STATUS_ACCESS_DENIED)
1.1       root      155:        {
                    156:                ntStatus = ZwCreateFile (&Extension->hDeviceFile,
1.1.1.4   root      157:                        GENERIC_READ | SYNCHRONIZE,
                    158:                        &oaFileAttributes,
                    159:                        &IoStatusBlock,
                    160:                        NULL,
                    161:                        FILE_ATTRIBUTE_NORMAL |
                    162:                        FILE_ATTRIBUTE_SYSTEM,
1.1.1.8   root      163:                        mount->bExclusiveAccess ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
1.1.1.4   root      164:                        FILE_OPEN,
1.1.1.10  root      165:                        FILE_RANDOM_ACCESS |
1.1.1.4   root      166:                        FILE_WRITE_THROUGH |
1.1.1.11  root      167:                        (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
1.1.1.4   root      168:                        FILE_SYNCHRONOUS_IO_NONALERT,
                    169:                        NULL,
                    170:                        0);
1.1.1.11  root      171: 
1.1       root      172:                Extension->bReadOnly = TRUE;
1.1.1.11  root      173:                DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
1.1       root      174:        }
                    175:        else
                    176:                Extension->bReadOnly = FALSE;
                    177: 
                    178:        /* 26-4-99 NT for some partitions returns this code, it is really a
1.1.1.4   root      179:        access denied */
1.1       root      180:        if (ntStatus == 0xc000001b)
                    181:        {
                    182:                /* Partitions which return this code can still be opened with
1.1.1.4   root      183:                FILE_SHARE_READ but this causes NT problems elsewhere in
                    184:                particular if you do FILE_SHARE_READ NT will die later if
1.1.1.12  root      185:                anyone even tries to open the partition (or file for that
1.1.1.4   root      186:                matter...)  */
1.1       root      187:                ntStatus = STATUS_SHARING_VIOLATION;
                    188:        }
                    189: 
                    190:        if (!NT_SUCCESS (ntStatus))
                    191:        {
                    192:                goto error;
                    193:        }
                    194: 
1.1.1.4   root      195:        // If we have opened a file, query its size now
1.1       root      196:        if (bRawDevice == FALSE)
                    197:        {
                    198:                ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
1.1.1.4   root      199:                        &IoStatusBlock,
                    200:                        &FileBasicInfo,
                    201:                        sizeof (FileBasicInfo),
                    202:                        FileBasicInformation);
1.1       root      203: 
                    204:                if (NT_SUCCESS (ntStatus))
1.1.1.4   root      205:                {
1.1.1.6   root      206:                        if (mount->bPreserveTimestamp)
                    207:                        {
                    208:                                /* Remember the container timestamp. (Used to reset access/modification file date/time
                    209:                                of file-hosted volumes upon dismount or after unsuccessful mount attempt to preserve
                    210:                                plausible deniability of hidden volumes.) */
                    211:                                Extension->fileCreationTime = FileBasicInfo.CreationTime;
                    212:                                Extension->fileLastAccessTime = FileBasicInfo.LastAccessTime;
                    213:                                Extension->fileLastWriteTime = FileBasicInfo.LastWriteTime;
                    214:                                Extension->fileLastChangeTime = FileBasicInfo.ChangeTime;
                    215:                                Extension->bTimeStampValid = TRUE;
                    216:                        }
1.1.1.4   root      217: 
1.1       root      218:                        ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
1.1.1.4   root      219:                                &IoStatusBlock,
                    220:                                &FileStandardInfo,
                    221:                                sizeof (FileStandardInfo),
                    222:                                FileStandardInformation);
                    223:                }
1.1       root      224: 
                    225:                if (!NT_SUCCESS (ntStatus))
                    226:                {
                    227:                        Dump ("ZwQueryInformationFile failed while opening file: NTSTATUS 0x%08x\n",
1.1.1.4   root      228:                                ntStatus);
1.1       root      229:                        goto error;
                    230:                }
1.1.1.4   root      231: 
                    232:                lDiskLength.QuadPart = FileStandardInfo.EndOfFile.QuadPart;
1.1       root      233: 
                    234:                if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)
                    235:                {
                    236:                        Dump ("File \"%ls\" is marked as compressed - not supported!\n", pwszMountVolume);
                    237:                        mount->nReturnCode = ERR_COMPRESSION_NOT_SUPPORTED;
                    238:                        ntStatus = STATUS_SUCCESS;
                    239:                        goto error;
                    240:                }
                    241: 
                    242:                ntStatus = ObReferenceObjectByHandle (Extension->hDeviceFile,
1.1.1.4   root      243:                        FILE_ALL_ACCESS,
                    244:                        *IoFileObjectType,
                    245:                        KernelMode,
                    246:                        &Extension->pfoDeviceFile,
                    247:                        0);
1.1       root      248: 
                    249:                if (!NT_SUCCESS (ntStatus))
                    250:                {
                    251:                        goto error;
                    252:                }
                    253: 
1.1.1.4   root      254:                /* Get the FSD device for the file (probably either NTFS or     FAT) */
1.1       root      255:                Extension->pFsdDevice = IoGetRelatedDeviceObject (Extension->pfoDeviceFile);
                    256:        }
1.1.1.15! root      257:        else
        !           258:        {
        !           259:                // Try to gain "raw" access to the partition in case there is a live filesystem on it (otherwise, 
        !           260:                // the NTFS driver guards hidden sectors and prevents mounting using a backup header e.g. after the user 
        !           261:                // accidentally quick-formats a dismounted partition-hosted TrueCrypt volume as NTFS).
        !           262: 
        !           263:                PFILE_OBJECT pfoTmpDeviceFile = NULL;
        !           264: 
        !           265:                if (NT_SUCCESS (ObReferenceObjectByHandle (Extension->hDeviceFile, FILE_ALL_ACCESS, *IoFileObjectType, KernelMode, &pfoTmpDeviceFile, NULL))
        !           266:                        && pfoTmpDeviceFile != NULL)
        !           267:                {
        !           268:                        TCFsctlCall (pfoTmpDeviceFile, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0);
        !           269:                        ObDereferenceObject (pfoTmpDeviceFile);
        !           270:                }
        !           271:        }
1.1       root      272: 
1.1.1.4   root      273:        // Check volume size
1.1.1.14  root      274:        if (lDiskLength.QuadPart < TC_MIN_VOLUME_SIZE_LEGACY || lDiskLength.QuadPart > TC_MAX_VOLUME_SIZE)
1.1.1.4   root      275:        {
                    276:                mount->nReturnCode = ERR_VOL_SIZE_WRONG;
                    277:                ntStatus = STATUS_SUCCESS;
                    278:                goto error;
                    279:        }
1.1.1.6   root      280: 
1.1.1.4   root      281:        Extension->DiskLength = lDiskLength.QuadPart;
1.1       root      282: 
1.1.1.15! root      283:        readBuffer = TCalloc (max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, PAGE_SIZE));
1.1.1.4   root      284:        if (readBuffer == NULL)
                    285:        {
                    286:                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
                    287:                goto error;
                    288:        }
1.1       root      289: 
1.1.1.6   root      290:        // Go through all volume types (e.g., normal, hidden)
1.1.1.14  root      291:        for (volumeType = TC_VOLUME_TYPE_NORMAL;
                    292:                volumeType < TC_VOLUME_TYPE_COUNT;
1.1.1.6   root      293:                volumeType++)   
1.1.1.4   root      294:        {
1.1.1.14  root      295:                Dump ("Trying to open volume type %d\n", volumeType);
                    296: 
1.1.1.13  root      297:                if (mount->bPartitionInInactiveSysEncScope
1.1.1.14  root      298:                        && volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
1.1.1.13  root      299:                        continue;               
                    300: 
1.1.1.6   root      301:                /* Read the volume header */
1.1       root      302: 
1.1.1.14  root      303:                if (!mount->bPartitionInInactiveSysEncScope
                    304:                        || (mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_HIDDEN))
1.1.1.13  root      305:                {
1.1.1.14  root      306:                        // Header of a volume that is not within the scope of system encryption, or
                    307:                        // header of a system hidden volume (containing a hidden OS)
                    308: 
                    309:                        LARGE_INTEGER headerOffset;
                    310: 
                    311:                        if (mount->UseBackupHeader && lDiskLength.QuadPart <= TC_TOTAL_VOLUME_HEADERS_SIZE)
                    312:                                continue;
                    313: 
                    314:                        switch (volumeType)
                    315:                        {
                    316:                        case TC_VOLUME_TYPE_NORMAL:
                    317:                                headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
                    318:                                break;
                    319: 
                    320:                        case TC_VOLUME_TYPE_HIDDEN:
                    321:                                if (lDiskLength.QuadPart <= TC_VOLUME_HEADER_GROUP_SIZE)
                    322:                                        continue;
                    323: 
                    324:                                headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET : TC_HIDDEN_VOLUME_HEADER_OFFSET;
                    325:                                break;
                    326: 
                    327:                        case TC_VOLUME_TYPE_HIDDEN_LEGACY:
                    328:                                if (mount->UseBackupHeader)
                    329:                                        continue;
                    330: 
                    331:                                headerOffset.QuadPart = lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
                    332:                                break;
                    333:                        }
                    334: 
                    335:                        Dump ("Reading volume header at %I64d\n", headerOffset.QuadPart);
1.1.1.13  root      336: 
                    337:                        ntStatus = ZwReadFile (Extension->hDeviceFile,
1.1.1.6   root      338:                        NULL,
                    339:                        NULL,
                    340:                        NULL,
                    341:                        &IoStatusBlock,
                    342:                        readBuffer,
1.1.1.14  root      343:                        TC_VOLUME_HEADER_EFFECTIVE_SIZE,
                    344:                        &headerOffset,
1.1.1.6   root      345:                        NULL);
1.1.1.13  root      346:                }
                    347:                else
                    348:                {
                    349:                        // Header of a partition that is within the scope of system encryption
                    350: 
                    351:                        WCHAR parentDrivePath [47+1] = {0};
                    352:                        HANDLE hParentDeviceFile = NULL;
                    353:                        UNICODE_STRING FullParentPath;
                    354:                        OBJECT_ATTRIBUTES oaParentFileAttributes;
                    355:                        LARGE_INTEGER parentKeyDataOffset;
                    356: 
                    357:                        _snwprintf (parentDrivePath,
                    358:                                sizeof (parentDrivePath) / sizeof (WCHAR) - 1,
                    359:                                WIDE ("\\Device\\Harddisk%d\\Partition0"),
                    360:                                mount->nPartitionInInactiveSysEncScopeDriveNo);
                    361: 
                    362:                        Dump ("Mounting partition within scope of system encryption (reading key data from: %ls)\n", parentDrivePath);
                    363: 
                    364:                        RtlInitUnicodeString (&FullParentPath, parentDrivePath);
                    365:                        InitializeObjectAttributes (&oaParentFileAttributes, &FullParentPath, OBJ_CASE_INSENSITIVE,     NULL, NULL);
                    366: 
                    367:                        ntStatus = ZwCreateFile (&hParentDeviceFile,
                    368:                                GENERIC_READ | SYNCHRONIZE,
                    369:                                &oaParentFileAttributes,
                    370:                                &IoStatusBlock,
                    371:                                NULL,
                    372:                                FILE_ATTRIBUTE_NORMAL |
                    373:                                FILE_ATTRIBUTE_SYSTEM,
                    374:                                FILE_SHARE_READ | FILE_SHARE_WRITE,
                    375:                                FILE_OPEN,
                    376:                                FILE_RANDOM_ACCESS |
                    377:                                FILE_WRITE_THROUGH |
                    378:                                (Extension->HostBytesPerSector == SECTOR_SIZE ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
                    379:                                FILE_SYNCHRONOUS_IO_NONALERT,
                    380:                                NULL,
                    381:                                0);
                    382: 
                    383:                        if (!NT_SUCCESS (ntStatus))
                    384:                        {
                    385:                                if (hParentDeviceFile != NULL)
                    386:                                        ZwClose (hParentDeviceFile);
                    387: 
                    388:                                Dump ("Cannot open %ls\n", parentDrivePath);
                    389: 
                    390:                                goto error;
                    391:                        }
                    392: 
1.1.1.14  root      393:                        parentKeyDataOffset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
1.1.1.13  root      394: 
                    395:                        ntStatus = ZwReadFile (hParentDeviceFile,
                    396:                                NULL,
                    397:                                NULL,
                    398:                                NULL,
                    399:                                &IoStatusBlock,
                    400:                                readBuffer,
1.1.1.14  root      401:                                TC_VOLUME_HEADER_EFFECTIVE_SIZE,
1.1.1.13  root      402:                                &parentKeyDataOffset,
                    403:                                NULL);
                    404: 
                    405:                        if (hParentDeviceFile != NULL)
                    406:                                ZwClose (hParentDeviceFile);
                    407:                }
1.1.1.6   root      408: 
1.1.1.15! root      409:                if (!NT_SUCCESS (ntStatus) && ntStatus != STATUS_END_OF_FILE)
1.1       root      410:                {
1.1.1.6   root      411:                        Dump ("Read failed: NTSTATUS 0x%08x\n", ntStatus);
1.1.1.14  root      412:                        goto error;
1.1       root      413:                }
                    414: 
1.1.1.15! root      415:                if (ntStatus == STATUS_END_OF_FILE || IoStatusBlock.Information != TC_VOLUME_HEADER_EFFECTIVE_SIZE)
1.1.1.6   root      416:                {
1.1.1.14  root      417:                        Dump ("Read didn't read enough data\n");
1.1.1.15! root      418: 
        !           419:                        // If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
        !           420:                        // filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is 
        !           421:                        // shorter than the partition). This can happen for example after the user quick-formats a dismounted
        !           422:                        // partition-hosted TrueCrypt volume and then tries to mount the volume using the embedded backup header.
        !           423:                        memset (readBuffer, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1.1.1.6   root      424:                }
1.1       root      425: 
1.1.1.6   root      426:                /* Attempt to recognize the volume (decrypt the header) */
1.1       root      427: 
1.1.1.15! root      428:                ReadVolumeHeaderRecoveryMode = mount->RecoveryMode;
        !           429: 
1.1.1.14  root      430:                if ((volumeType == TC_VOLUME_TYPE_HIDDEN || volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY) && mount->bProtectHiddenVolume)
1.1.1.6   root      431:                {
1.1.1.15! root      432:                        mount->nReturnCode = ReadVolumeHeaderWCache (
1.1.1.14  root      433:                                FALSE,
1.1.1.6   root      434:                                mount->bCache,
                    435:                                readBuffer,
                    436:                                &mount->ProtectedHidVolPassword,
                    437:                                &tmpCryptoInfo);
                    438:                }
                    439:                else
                    440:                {
1.1.1.15! root      441:                        mount->nReturnCode = ReadVolumeHeaderWCache (
1.1.1.14  root      442:                                mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_NORMAL,
1.1.1.6   root      443:                                mount->bCache,
                    444:                                readBuffer,
                    445:                                &mount->VolumePassword,
                    446:                                &Extension->cryptoInfo);
                    447:                }
1.1.1.4   root      448: 
1.1.1.15! root      449:                ReadVolumeHeaderRecoveryMode = FALSE;
        !           450: 
1.1.1.6   root      451:                if (mount->nReturnCode == 0 || mount->nReturnCode == ERR_CIPHER_INIT_WEAK_KEY)
                    452:                {
                    453:                        /* Volume header successfully decrypted */
1.1       root      454: 
1.1.1.14  root      455:                        Dump ("Volume header decrypted\n");
                    456:                        Dump ("Required program version = %x\n", (int) Extension->cryptoInfo->RequiredProgramVersion);
                    457:                        Dump ("Legacy volume = %d\n", (int) Extension->cryptoInfo->LegacyVolume);
                    458: 
                    459:                        if (IsHiddenSystemRunning() && !Extension->cryptoInfo->hiddenVolume)
                    460:                        {
                    461:                                Extension->bReadOnly = mount->bMountReadOnly = TRUE;
                    462:                                HiddenSysLeakProtectionCount++;
                    463:                        }
                    464: 
1.1.1.6   root      465:                        Extension->cryptoInfo->bProtectHiddenVolume = FALSE;
                    466:                        Extension->cryptoInfo->bHiddenVolProtectionAction = FALSE;
1.1       root      467: 
1.1.1.13  root      468:                        Extension->cryptoInfo->bPartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
                    469: 
1.1.1.15! root      470:                        if (volumeType == TC_VOLUME_TYPE_NORMAL)
1.1.1.13  root      471:                        {
1.1.1.15! root      472:                                if (mount->bPartitionInInactiveSysEncScope)
1.1.1.13  root      473:                                {
1.1.1.15! root      474:                                        if (Extension->cryptoInfo->EncryptedAreaStart.Value > (unsigned __int64) partitionStartingOffset
        !           475:                                                || Extension->cryptoInfo->EncryptedAreaStart.Value + Extension->cryptoInfo->VolumeSize.Value <= (unsigned __int64) partitionStartingOffset)
        !           476:                                        {
        !           477:                                                // The partition is not within the key scope of system encryption
        !           478:                                                mount->nReturnCode = ERR_PASSWORD_WRONG;
        !           479:                                                ntStatus = STATUS_SUCCESS;
        !           480:                                                goto error;
        !           481:                                        }
        !           482: 
        !           483:                                        if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
        !           484:                                        {
        !           485:                                                // Partial encryption is not supported for volumes mounted as regular
        !           486:                                                mount->nReturnCode = ERR_ENCRYPTION_NOT_COMPLETED;
        !           487:                                                ntStatus = STATUS_SUCCESS;
        !           488:                                                goto error;
        !           489:                                        }
        !           490:                                }
        !           491:                                else if (Extension->cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC)
        !           492:                                {
        !           493:                                        if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
        !           494:                                        {
        !           495:                                                // Non-system in-place encryption process has not been completed on this volume
        !           496:                                                mount->nReturnCode = ERR_NONSYS_INPLACE_ENC_INCOMPLETE;
        !           497:                                                ntStatus = STATUS_SUCCESS;
        !           498:                                                goto error;
        !           499:                                        }
1.1.1.13  root      500:                                }
                    501:                        }
                    502: 
1.1.1.14  root      503:                        Extension->cryptoInfo->FirstDataUnitNo.Value = 0;
1.1       root      504: 
1.1.1.14  root      505:                        if (Extension->cryptoInfo->hiddenVolume && IsHiddenSystemRunning())
                    506:                        {
                    507:                                // Prevent mount of a hidden system partition if the system hosted on it is currently running
                    508:                                if (memcmp (Extension->cryptoInfo->master_keydata, GetSystemDriveCryptoInfo()->master_keydata, EAGetKeySize (Extension->cryptoInfo->ea)) == 0)
1.1.1.13  root      509:                                {
1.1.1.14  root      510:                                        mount->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
                    511:                                        ntStatus = STATUS_SUCCESS;
                    512:                                        goto error;
1.1.1.13  root      513:                                }
1.1.1.14  root      514:                        }
                    515: 
                    516:                        switch (volumeType)
                    517:                        {
                    518:                        case TC_VOLUME_TYPE_NORMAL:
1.1.1.13  root      519: 
1.1.1.6   root      520:                                Extension->cryptoInfo->hiddenVolume = FALSE;
1.1.1.13  root      521: 
1.1.1.14  root      522:                                if (mount->bPartitionInInactiveSysEncScope)
                    523:                                {
                    524:                                        Extension->cryptoInfo->volDataAreaOffset = 0;
                    525:                                        Extension->DiskLength = lDiskLength.QuadPart;
                    526:                                        Extension->cryptoInfo->FirstDataUnitNo.Value = partitionStartingOffset / ENCRYPTION_DATA_UNIT_SIZE;
                    527:                                }
                    528:                                else if (Extension->cryptoInfo->LegacyVolume)
                    529:                                {
                    530:                                        Extension->cryptoInfo->volDataAreaOffset = TC_VOLUME_HEADER_SIZE_LEGACY;
                    531:                                        Extension->DiskLength = lDiskLength.QuadPart - TC_VOLUME_HEADER_SIZE_LEGACY;
                    532:                                }
                    533:                                else
                    534:                                {
                    535:                                        Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->EncryptedAreaStart.Value;
                    536:                                        Extension->DiskLength = Extension->cryptoInfo->VolumeSize.Value;
                    537:                                }
1.1.1.6   root      538: 
                    539:                                break;
                    540: 
1.1.1.14  root      541:                        case TC_VOLUME_TYPE_HIDDEN:
                    542:                        case TC_VOLUME_TYPE_HIDDEN_LEGACY:
1.1.1.6   root      543: 
                    544:                                cryptoInfoPtr = mount->bProtectHiddenVolume ? tmpCryptoInfo : Extension->cryptoInfo;
                    545: 
1.1.1.14  root      546:                                if (volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
                    547:                                        Extension->cryptoInfo->hiddenVolumeOffset = lDiskLength.QuadPart - cryptoInfoPtr->hiddenVolumeSize - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
                    548:                                else
                    549:                                        Extension->cryptoInfo->hiddenVolumeOffset = cryptoInfoPtr->EncryptedAreaStart.Value;
1.1.1.6   root      550: 
1.1.1.14  root      551:                                Dump ("Hidden volume offset = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset);
                    552:                                Dump ("Hidden volume size = %I64d\n", cryptoInfoPtr->hiddenVolumeSize);
                    553:                                Dump ("Hidden volume end = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset + cryptoInfoPtr->hiddenVolumeSize - 1);
1.1.1.6   root      554: 
                    555:                                // Validate the offset
1.1.1.12  root      556:                                if (Extension->cryptoInfo->hiddenVolumeOffset % ENCRYPTION_DATA_UNIT_SIZE != 0)
1.1.1.6   root      557:                                {
                    558:                                        mount->nReturnCode = ERR_VOL_SIZE_WRONG;
                    559:                                        ntStatus = STATUS_SUCCESS;
                    560:                                        goto error;
                    561:                                }
                    562: 
                    563:                                // If we are supposed to actually mount the hidden volume (not just to protect it)
                    564:                                if (!mount->bProtectHiddenVolume)       
                    565:                                {
                    566:                                        Extension->DiskLength = cryptoInfoPtr->hiddenVolumeSize;
                    567:                                        Extension->cryptoInfo->hiddenVolume = TRUE;
1.1.1.13  root      568:                                        Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->hiddenVolumeOffset;
1.1.1.6   root      569:                                }
                    570:                                else
                    571:                                {
                    572:                                        // Hidden volume protection
                    573:                                        Extension->cryptoInfo->hiddenVolume = FALSE;
                    574:                                        Extension->cryptoInfo->bProtectHiddenVolume = TRUE;
1.1.1.14  root      575:                                        
                    576:                                        Extension->cryptoInfo->hiddenVolumeProtectedSize = tmpCryptoInfo->hiddenVolumeSize;
1.1.1.13  root      577: 
1.1.1.14  root      578:                                        if (volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY)
                    579:                                                Extension->cryptoInfo->hiddenVolumeProtectedSize += TC_VOLUME_HEADER_SIZE_LEGACY;
1.1.1.13  root      580: 
1.1.1.14  root      581:                                        Dump ("Hidden volume protection active: %I64d-%I64d (%I64d)\n", Extension->cryptoInfo->hiddenVolumeOffset, Extension->cryptoInfo->hiddenVolumeProtectedSize + Extension->cryptoInfo->hiddenVolumeOffset - 1, Extension->cryptoInfo->hiddenVolumeProtectedSize);
1.1.1.6   root      582:                                }
1.1.1.4   root      583: 
1.1.1.6   root      584:                                break;
                    585:                        }
1.1.1.4   root      586: 
1.1.1.14  root      587:                        Dump ("Volume data offset = %I64d\n", Extension->cryptoInfo->volDataAreaOffset);
                    588:                        Dump ("Volume data size = %I64d\n", Extension->DiskLength);
                    589:                        Dump ("Volume data end = %I64d\n", Extension->cryptoInfo->volDataAreaOffset + Extension->DiskLength - 1);
                    590: 
1.1.1.15! root      591:                        if (Extension->DiskLength == 0)
        !           592:                        {
        !           593:                                Dump ("Incorrect volume size\n");
        !           594:                                continue;
        !           595:                        }
        !           596: 
1.1.1.6   root      597:                        // If this is a hidden volume, make sure we are supposed to actually
                    598:                        // mount it (i.e. not just to protect it)
1.1.1.14  root      599:                        if (volumeType == TC_VOLUME_TYPE_NORMAL || !mount->bProtectHiddenVolume)        
1.1.1.4   root      600:                        {
1.1.1.6   root      601:                                // Calculate virtual volume geometry
                    602:                                Extension->TracksPerCylinder = 1;
                    603:                                Extension->SectorsPerTrack = 1;
1.1.1.10  root      604:                                Extension->BytesPerSector = SECTOR_SIZE;
                    605:                                Extension->NumberOfCylinders = Extension->DiskLength / SECTOR_SIZE;
1.1.1.6   root      606:                                Extension->PartitionType = 0;
                    607: 
                    608:                                Extension->bRawDevice = bRawDevice;
1.1.1.7   root      609:                                
1.1.1.8   root      610:                                memset (Extension->wszVolume, 0, sizeof (Extension->wszVolume));
1.1.1.7   root      611:                                if (wcsstr (pwszMountVolume, WIDE ("\\??\\UNC\\")) == pwszMountVolume)
                    612:                                {
                    613:                                        /* UNC path */
                    614:                                        _snwprintf (Extension->wszVolume,
                    615:                                                sizeof (Extension->wszVolume) / sizeof (WCHAR) - 1,
                    616:                                                WIDE ("\\??\\\\%s"),
                    617:                                                pwszMountVolume + 7);
                    618:                                }
1.1.1.6   root      619:                                else
                    620:                                {
1.1.1.7   root      621:                                        wcsncpy (Extension->wszVolume, pwszMountVolume, sizeof (Extension->wszVolume) / sizeof (WCHAR) - 1);
1.1.1.6   root      622:                                }
1.1.1.4   root      623:                        }
                    624: 
1.1.1.6   root      625:                        // If we are to protect a hidden volume we cannot exit yet, for we must also
                    626:                        // decrypt the hidden volume header.
1.1.1.14  root      627:                        if (!(volumeType == TC_VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
1.1.1.4   root      628:                        {
1.1.1.6   root      629:                                TCfree (readBuffer);
1.1.1.4   root      630: 
1.1.1.6   root      631:                                if (tmpCryptoInfo != NULL)
1.1.1.14  root      632:                                {
1.1.1.6   root      633:                                        crypto_close (tmpCryptoInfo);
1.1.1.14  root      634:                                        tmpCryptoInfo = NULL;
                    635:                                }
1.1.1.6   root      636:                                
                    637:                                return STATUS_SUCCESS;
                    638:                        }
1.1.1.4   root      639:                }
1.1.1.14  root      640:                else if ((mount->bProtectHiddenVolume && volumeType == TC_VOLUME_TYPE_NORMAL)
1.1.1.6   root      641:                          || mount->nReturnCode != ERR_PASSWORD_WRONG)
1.1.1.4   root      642:                {
1.1.1.6   root      643:                         /* If we are not supposed to protect a hidden volume, the only error that is
                    644:                                tolerated is ERR_PASSWORD_WRONG (to allow mounting a possible hidden volume). 
1.1.1.4   root      645: 
1.1.1.6   root      646:                                If we _are_ supposed to protect a hidden volume, we do not tolerate any error
                    647:                                (both volume headers must be successfully decrypted). */
1.1       root      648: 
1.1.1.6   root      649:                        break;
1.1       root      650:                }
                    651:        }
                    652: 
                    653:        /* Failed due to some non-OS reason so we drop through and return NT
                    654:           SUCCESS then nReturnCode is checked later in user-mode */
                    655: 
                    656:        if (mount->nReturnCode == ERR_OUTOFMEMORY)
                    657:                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
                    658:        else
                    659:                ntStatus = STATUS_SUCCESS;
                    660: 
1.1.1.4   root      661: error:
1.1.1.14  root      662:        if (mount->nReturnCode == ERR_SUCCESS)
                    663:                mount->nReturnCode = ERR_PASSWORD_WRONG;
                    664: 
                    665:        if (tmpCryptoInfo != NULL)
                    666:        {
                    667:                crypto_close (tmpCryptoInfo);
                    668:                tmpCryptoInfo = NULL;
                    669:        }
                    670: 
                    671:        if (Extension->cryptoInfo)
                    672:        {
                    673:                crypto_close (Extension->cryptoInfo);
                    674:                Extension->cryptoInfo = NULL;
                    675:        }
                    676: 
1.1.1.6   root      677:        if (Extension->bTimeStampValid)
1.1.1.4   root      678:        {
                    679:                /* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
                    680:                RestoreTimeStamp (Extension);
                    681:        }
1.1       root      682: 
                    683:        /* Close the hDeviceFile */
                    684:        if (Extension->hDeviceFile != NULL)
                    685:                ZwClose (Extension->hDeviceFile);
                    686: 
                    687:        /* The cryptoInfo pointer is deallocated if the readheader routines
                    688:           fail so there is no need to deallocate here  */
                    689: 
                    690:        /* Dereference the user-mode file object */
                    691:        if (Extension->pfoDeviceFile != NULL)
                    692:                ObDereferenceObject (Extension->pfoDeviceFile);
                    693: 
1.1.1.4   root      694:        /* Free the tmp IO buffers */
1.1       root      695:        if (readBuffer != NULL)
                    696:                TCfree (readBuffer);
                    697: 
                    698:        return ntStatus;
                    699: }
                    700: 
1.1.1.14  root      701: void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
1.1       root      702: {
                    703:        if (DeviceObject);      /* Remove compiler warning */
                    704: 
                    705:        if (Extension->hDeviceFile != NULL)
1.1.1.4   root      706:        {
1.1.1.6   root      707:                if (Extension->bRawDevice == FALSE
                    708:                        && Extension->bTimeStampValid)
1.1.1.4   root      709:                {
                    710:                        /* Restore the container timestamp to preserve plausible deniability of possible hidden volume. */
                    711:                        RestoreTimeStamp (Extension);
                    712:                }
1.1.1.6   root      713:                ZwClose (Extension->hDeviceFile);
1.1.1.4   root      714:        }
1.1       root      715:        ObDereferenceObject (Extension->pfoDeviceFile);
                    716:        crypto_close (Extension->cryptoInfo);
                    717: }
                    718: 
                    719: 
1.1.1.14  root      720: NTSTATUS TCSendHostDeviceIoControlRequest (PDEVICE_OBJECT DeviceObject,
1.1       root      721:                               PEXTENSION Extension,
                    722:                               ULONG IoControlCode,
1.1.1.15! root      723:                               void *OutputBuffer,
        !           724:                               ULONG OutputBufferSize)
1.1       root      725: {
                    726:        IO_STATUS_BLOCK IoStatusBlock;
                    727:        NTSTATUS ntStatus;
                    728:        PIRP Irp;
                    729: 
                    730:        if (DeviceObject);      /* Remove compiler warning */
                    731: 
                    732:        KeClearEvent (&Extension->keVolumeEvent);
                    733: 
                    734:        Irp = IoBuildDeviceIoControlRequest (IoControlCode,
                    735:                                             Extension->pFsdDevice,
                    736:                                             NULL, 0,
                    737:                                             OutputBuffer, OutputBufferSize,
                    738:                                             FALSE,
                    739:                                             &Extension->keVolumeEvent,
                    740:                                             &IoStatusBlock);
                    741: 
                    742:        if (Irp == NULL)
                    743:        {
                    744:                Dump ("IRP allocation failed\n");
                    745:                return STATUS_INSUFFICIENT_RESOURCES;
                    746:        }
                    747: 
1.1.1.5   root      748:        // Disk device may be used by filesystem driver which needs file object
                    749:        IoGetNextIrpStackLocation (Irp) -> FileObject = Extension->pfoDeviceFile;
                    750: 
1.1       root      751:        ntStatus = IoCallDriver (Extension->pFsdDevice, Irp);
                    752:        if (ntStatus == STATUS_PENDING)
                    753:        {
1.1.1.12  root      754:                KeWaitForSingleObject (&Extension->keVolumeEvent, Executive, KernelMode, FALSE, NULL);
1.1       root      755:                ntStatus = IoStatusBlock.Status;
                    756:        }
                    757: 
                    758:        return ntStatus;
                    759: }
                    760: 
1.1.1.14  root      761: NTSTATUS COMPLETE_IRP (PDEVICE_OBJECT DeviceObject,
1.1       root      762:              PIRP Irp,
                    763:              NTSTATUS IrpStatus,
1.1.1.4   root      764:              ULONG_PTR IrpInformation)
1.1       root      765: {
                    766:        Irp->IoStatus.Status = IrpStatus;
                    767:        Irp->IoStatus.Information = IrpInformation;
                    768: 
                    769:        if (DeviceObject);      /* Remove compiler warning */
                    770: 
1.1.1.10  root      771: #if EXTRA_INFO
                    772:        if (!NT_SUCCESS (IrpStatus))
                    773:        {
                    774:                PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
                    775:                Dump ("COMPLETE_IRP FAILING IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
                    776:                      (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
                    777:        }
                    778:        else
                    779:        {
                    780:                PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
                    781:                Dump ("COMPLETE_IRP SUCCESS IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
                    782:                      (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
                    783:        }
1.1       root      784: #endif
                    785:        IoCompleteRequest (Irp, IO_NO_INCREMENT);
                    786:        return IrpStatus;
                    787: }
1.1.1.4   root      788: 
                    789: // Restores the container timestamp to preserve plausible deniability of possible hidden volume.
                    790: static void RestoreTimeStamp (PEXTENSION Extension)
                    791: {
                    792:        NTSTATUS ntStatus;
                    793:        FILE_BASIC_INFORMATION FileBasicInfo;
                    794:        IO_STATUS_BLOCK IoStatusBlock;
                    795: 
1.1.1.6   root      796:        if (Extension->hDeviceFile != NULL 
                    797:                && Extension->bRawDevice == FALSE 
                    798:                && Extension->bReadOnly == FALSE
                    799:                && Extension->bTimeStampValid)
1.1.1.4   root      800:        {
                    801:                ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
                    802:                        &IoStatusBlock,
                    803:                        &FileBasicInfo,
                    804:                        sizeof (FileBasicInfo),
                    805:                        FileBasicInformation); 
                    806: 
                    807:                if (!NT_SUCCESS (ntStatus))
                    808:                {
                    809:                        Dump ("ZwQueryInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",
                    810:                                ntStatus);
                    811:                }
                    812:                else
                    813:                {
                    814:                        FileBasicInfo.CreationTime = Extension->fileCreationTime;
                    815:                        FileBasicInfo.LastAccessTime = Extension->fileLastAccessTime;
                    816:                        FileBasicInfo.LastWriteTime = Extension->fileLastWriteTime;
                    817:                        FileBasicInfo.ChangeTime = Extension->fileLastChangeTime;
                    818: 
                    819:                        ntStatus = ZwSetInformationFile(
                    820:                                Extension->hDeviceFile,
                    821:                                &IoStatusBlock,
                    822:                                &FileBasicInfo,
                    823:                                sizeof (FileBasicInfo),
                    824:                                FileBasicInformation); 
                    825: 
                    826:                        if (!NT_SUCCESS (ntStatus))
                    827:                                Dump ("ZwSetInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",ntStatus);
                    828:                }
                    829:        }
                    830: }

unix.superglobalmegacorp.com

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