windows-nt/Source/XPSP1/NT/base/fs/srv/smbdir.c

1165 lines
34 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
smbdir.c
Abstract:
This module implements directory control SMB processors:
Create Directory
Create Directory2
Delete Directory
Check Directory
--*/
#include "precomp.h"
#include "smbdir.tmh"
#pragma hdrstop
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SrvSmbCreateDirectory )
#pragma alloc_text( PAGE, SrvSmbCreateDirectory2 )
#pragma alloc_text( PAGE, SrvSmbDeleteDirectory )
#pragma alloc_text( PAGE, SrvSmbCheckDirectory )
#endif
SMB_PROCESSOR_RETURN_TYPE
SrvSmbCreateDirectory (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
This routine processes the Create Directory SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
--*/
{
PREQ_CREATE_DIRECTORY request;
PRESP_CREATE_DIRECTORY response;
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
UNICODE_STRING directoryName;
HANDLE directoryHandle;
PTREE_CONNECT treeConnect;
PSESSION session;
PSHARE share;
BOOLEAN isUnicode;
PAGED_CODE( );
if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
WorkContext->PreviousSMB = EVENT_TYPE_SMB_CREATE_DIRECTORY;
SrvWmiStartContext(WorkContext);
IF_SMB_DEBUG(DIRECTORY1) {
SrvPrint2( "Create directory request header at 0x%p, response header at 0x%p\n",
WorkContext->RequestHeader,
WorkContext->ResponseHeader );
SrvPrint2( "Create directory request params at 0x%p, response params%p\n",
WorkContext->RequestParameters,
WorkContext->ResponseParameters );
}
request = (PREQ_CREATE_DIRECTORY)WorkContext->RequestParameters;
response = (PRESP_CREATE_DIRECTORY)WorkContext->ResponseParameters;
//
// If a session block has not already been assigned to the current
// work context , verify the UID. If verified, the address of the
// session block corresponding to this user is stored in the
// WorkContext block and the session block is referenced.
//
// Find tree connect corresponding to given TID if a tree connect
// pointer has not already been put in the WorkContext block by an
// AndX command.
//
status = SrvVerifyUidAndTid(
WorkContext,
&session,
&treeConnect,
ShareTypeDisk
);
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(SMB_ERRORS) {
SrvPrint0( "SrvSmbCreateDirectory: Invalid UID or TID\n" );
}
SrvSetSmbError( WorkContext, status );
goto Cleanup;
}
if( session->IsSessionExpired )
{
status = SESSION_EXPIRED_STATUS_CODE;
SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
goto Cleanup;
}
//
// Get the share block from the tree connect block. This doesn't need
// to be a referenced pointer because the tree connect has it referenced,
// and we just referenced the tree connect.
//
share = treeConnect->Share;
//
// Initialize the string containing the path name. The +1 is to account
// for the ASCII token in the Buffer field of the request SMB.
//
isUnicode = SMB_IS_UNICODE( WorkContext );
status = SrvCanonicalizePathName(
WorkContext,
share,
NULL,
(PVOID)(request->Buffer + 1),
END_OF_REQUEST_SMB( WorkContext ),
TRUE,
isUnicode,
&directoryName
);
if( !NT_SUCCESS( status ) ) {
IF_DEBUG(SMB_ERRORS) {
SrvPrint1( "SrvSmbCreateDirectory: illegal path name: %s\n",
(PSZ)request->Buffer + 1 );
}
SrvSetSmbError( WorkContext, status );
goto Cleanup;
}
//
// Initialize the object attributes structure. Open relative to the
// share root directory handle.
//
SrvInitializeObjectAttributes_U(
&objectAttributes,
&directoryName,
(WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
WorkContext->Session->UsingUppercasePaths) ?
OBJ_CASE_INSENSITIVE : 0L,
NULL,
NULL
);
//
// Attempt to create the directory. Since we must specify some desired
// access, request TRAVERSE_DIRECTORY even though we are going to close
// the directory just after we create it. The SMB protocol has no way
// of specifying attributes, so assume a normal file.
//
IF_SMB_DEBUG(DIRECTORY2) {
SrvPrint1( "Creating directory %wZ\n", objectAttributes.ObjectName );
}
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
status = SrvIoCreateFile(
WorkContext,
&directoryHandle,
FILE_TRAVERSE, // DesiredAccess
&objectAttributes,
&ioStatusBlock,
0L, // AllocationSize
FILE_ATTRIBUTE_NORMAL, // FileAttributes
0L, // ShareAccess
FILE_CREATE, // Disposition
FILE_DIRECTORY_FILE, // CreateOptions
NULL, // EaBuffer
0L, // EaLength
CreateFileTypeNone,
NULL, // ExtraCreateParameters
IO_FORCE_ACCESS_CHECK, // Options
share
);
if ( !isUnicode ) {
RtlFreeUnicodeString( &directoryName );
}
//
// If the user didn't have this permission, update the
// statistics database.
//
if ( status == STATUS_ACCESS_DENIED ) {
SrvStatistics.AccessPermissionErrors++;
}
//
// Special error mapping to return correct error.
//
if ( status == STATUS_OBJECT_NAME_COLLISION &&
!CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection)) {
status = STATUS_ACCESS_DENIED;
}
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(ERRORS) {
SrvPrint1( "SrvCreateDirectory: SrvIoCreateFile failed, "
"status = %X\n", status );
}
SrvSetSmbError( WorkContext, status );
goto Cleanup;
}
SRVDBG_CLAIM_HANDLE( directoryHandle, "DIR", 23, 0 );
SrvStatistics.TotalFilesOpened++;
IF_SMB_DEBUG(DIRECTORY2) {
SrvPrint1( "SrvIoCreateFile succeeded, handle = 0x%p\n",
directoryHandle );
}
//
// The SMB protocol has no concept of open directories; just close the
// handle now that we have created the directory.
//
SRVDBG_RELEASE_HANDLE( directoryHandle, "DIR", 36, 0 );
SrvNtClose( directoryHandle, TRUE );
//
// Build the response SMB.
//
response->WordCount = 0;
SmbPutUshort( &response->ByteCount, 0 );
WorkContext->ResponseParameters = NEXT_LOCATION(
response,
RESP_CREATE_DIRECTORY,
0
);
IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbCreateDirectory complete.\n" );
Cleanup:
SrvWmiEndContext(WorkContext);
return SmbStatusSendResponse;
} // SrvSmbCreateDirectory
SMB_TRANS_STATUS
SrvSmbCreateDirectory2 (
IN OUT PWORK_CONTEXT WorkContext
)
/*++
Routine Description:
Processes the Create Directory2 request. This request arrives
in a Transaction2 SMB.
Arguments:
WorkContext - Supplies the address of a Work Context Block
describing the current request. See smbtypes.h for a more
complete description of the valid fields.
Return Value:
BOOLEAN - Indicates whether an error occurred. See smbtypes.h for a
more complete description.
--*/
{
PREQ_CREATE_DIRECTORY2 request;
PRESP_CREATE_DIRECTORY2 response;
NTSTATUS status = STATUS_SUCCESS;
SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
IO_STATUS_BLOCK ioStatusBlock;
PTRANSACTION transaction;
UNICODE_STRING directoryName;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE directoryHandle;
PFILE_FULL_EA_INFORMATION ntFullEa = NULL;
ULONG ntFullEaLength = 0;
USHORT eaErrorOffset = 0;
PTREE_CONNECT treeConnect;
PSHARE share;
BOOLEAN isUnicode;
PAGED_CODE( );
if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
WorkContext->PreviousSMB = EVENT_TYPE_SMB_CREATE_DIRECTORY2;
SrvWmiStartContext(WorkContext);
transaction = WorkContext->Parameters.Transaction;
IF_SMB_DEBUG(DIRECTORY1) {
SrvPrint1( "Create Directory2 entered; transaction 0x%p\n",
transaction );
}
request = (PREQ_CREATE_DIRECTORY2)transaction->InParameters;
response = (PRESP_CREATE_DIRECTORY2)transaction->OutParameters;
//
// Verify that enough parameter bytes were sent and that we're allowed
// to return enough parameter bytes.
//
if ( (transaction->ParameterCount <
sizeof(REQ_CREATE_DIRECTORY2)) ||
(transaction->MaxParameterCount <
sizeof(RESP_CREATE_DIRECTORY2)) ) {
//
// Not enough parameter bytes were sent.
//
IF_DEBUG(SMB_ERRORS) {
SrvPrint2( "SrvSmbCreateDirectory2: bad parameter byte counts: "
"%ld %ld\n",
transaction->ParameterCount,
transaction->MaxParameterCount );
}
SrvLogInvalidSmb( WorkContext );
SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
status = STATUS_INVALID_SMB;
SmbStatus = SmbTransStatusErrorWithoutData;
goto Cleanup;
}
//
// Get the tree connect block from the transaction block and the share
// block from the tree connect block. These don't need to be referenced
// pointers because they are referenced by the transaction and the
// tree connect, respectively.
//
treeConnect = transaction->TreeConnect;
share = treeConnect->Share;
//
// Initialize the string containing the path name.
//
isUnicode = SMB_IS_UNICODE( WorkContext );
status = SrvCanonicalizePathName(
WorkContext,
share,
NULL,
request->Buffer,
END_OF_TRANSACTION_PARAMETERS( transaction ),
TRUE,
isUnicode,
&directoryName
);
if( !NT_SUCCESS( status ) ) {
IF_DEBUG(SMB_ERRORS) {
SrvPrint1( "SrvSmbCreateDirectory2: illegal path name: %ws\n",
directoryName.Buffer );
}
SrvSetSmbError( WorkContext, status );
SmbStatus = SmbTransStatusErrorWithoutData;
goto Cleanup;
}
//
// Initialize the object attributes structure. Open relative to the
// share root directory handle.
//
SrvInitializeObjectAttributes_U(
&objectAttributes,
&directoryName,
(WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
WorkContext->Session->UsingUppercasePaths) ?
OBJ_CASE_INSENSITIVE : 0L,
NULL,
NULL
);
//
// If an FEALIST was passed and it has valid size, convert it to
// NT style. SrvOs2FeaListToNt allocates space for the NT full EA
// list which must be deallocated. Note that sizeof(FEALIST) includes
// space for 1 FEA entry. Without at least much information, the EA
// code below should be skipped.
//
if ( transaction->DataCount > sizeof(FEALIST) &&
SmbGetUlong( &((PFEALIST)transaction->InData)->cbList ) > sizeof(FEALIST) &&
SmbGetUlong( &((PFEALIST)transaction->InData)->cbList ) <= transaction->DataCount ) {
status = SrvOs2FeaListToNt(
(PFEALIST)transaction->InData,
&ntFullEa,
&ntFullEaLength,
&eaErrorOffset
);
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(ERRORS) {
SrvPrint1( "SrvSmbCreateDirectory2: SrvOs2FeaListToNt failed, "
"status = %X\n", status );
}
if ( !isUnicode ) {
RtlFreeUnicodeString( &directoryName );
}
SrvSetSmbError2( WorkContext, status, TRUE );
transaction->SetupCount = 0;
transaction->ParameterCount = 2;
SmbPutUshort( &response->EaErrorOffset, eaErrorOffset );
transaction->DataCount = 0;
SmbStatus = SmbTransStatusErrorWithData;
goto Cleanup;
}
}
//
// Attempt to create the directory. Since we must specify some desired
// access, request FILE_TRAVERSE even though we are going to close
// the directory just after we create it. The SMB protocol has no way
// of specifying attributes, so assume a normal file.
//
IF_SMB_DEBUG(DIRECTORY2) {
SrvPrint1( "Creating directory %wZ\n", objectAttributes.ObjectName );
}
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
//
// Ensure the EaBuffer is correctly formatted. Since we are a kernel mode
// component, the Io subsystem does not check it for us.
//
if( ARGUMENT_PRESENT( ntFullEa ) ) {
ULONG ntEaErrorOffset = 0;
status = IoCheckEaBufferValidity( ntFullEa, ntFullEaLength, &ntEaErrorOffset );
eaErrorOffset = (USHORT)ntEaErrorOffset;
} else {
status = STATUS_SUCCESS;
}
if( NT_SUCCESS( status ) ) {
status = SrvIoCreateFile(
WorkContext,
&directoryHandle,
FILE_TRAVERSE, // DesiredAccess
&objectAttributes,
&ioStatusBlock,
0L, // AllocationSize
FILE_ATTRIBUTE_NORMAL, // FileAttributes
0L, // ShareAccess
FILE_CREATE, // Disposition
FILE_DIRECTORY_FILE, // CreateOptions
ntFullEa, // EaBuffer
ntFullEaLength, // EaLength
CreateFileTypeNone,
NULL, // ExtraCreateParameters
IO_FORCE_ACCESS_CHECK, // Options
share
);
}
if ( !isUnicode ) {
RtlFreeUnicodeString( &directoryName );
}
//
// If the user didn't have this permission, update the statistics
// database.
//
if ( status == STATUS_ACCESS_DENIED ) {
SrvStatistics.AccessPermissionErrors++;
}
if ( ARGUMENT_PRESENT( ntFullEa ) ) {
DEALLOCATE_NONPAGED_POOL( ntFullEa );
}
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(ERRORS) {
SrvPrint1( "SrvCreateDirectory2: SrvIoCreateFile failed, "
"status = %X\n", status );
}
SrvSetSmbError2( WorkContext, status, TRUE );
transaction->SetupCount = 0;
transaction->ParameterCount = 2;
SmbPutUshort( &response->EaErrorOffset, eaErrorOffset );
transaction->DataCount = 0;
SmbStatus = SmbTransStatusErrorWithData;
goto Cleanup;
}
IF_SMB_DEBUG(DIRECTORY2) {
SrvPrint1( "SrvIoCreateFile succeeded, handle = 0x%p\n",
directoryHandle );
}
//
// The SMB protocol has no concept of open directories; just close the
// handle now that we have created the directory.
//
SRVDBG_CLAIM_HANDLE( directoryHandle, "DIR", 24, 0 );
SRVDBG_RELEASE_HANDLE( directoryHandle, "DIR", 37, 0 );
SrvNtClose( directoryHandle, TRUE );
//
// Build the output parameter and data structures.
//
transaction->SetupCount = 0;
transaction->ParameterCount = 2;
SmbPutUshort( &response->EaErrorOffset, 0 );
transaction->DataCount = 0;
SmbStatus = SmbTransStatusSuccess;
Cleanup:
SrvWmiEndContext(WorkContext);
return SmbStatus;
} // SrvSmbCreateDirectory2
SMB_PROCESSOR_RETURN_TYPE
SrvSmbDeleteDirectory (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
This routine processes the Delete Directory SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
--*/
{
PREQ_DELETE_DIRECTORY request;
PRESP_DELETE_DIRECTORY response;
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
UNICODE_STRING directoryName;
HANDLE directoryHandle;
FILE_DISPOSITION_INFORMATION fileDispositionInformation;
PTREE_CONNECT treeConnect;
PSESSION session;
PSHARE share;
BOOLEAN isUnicode;
PAGED_CODE( );
if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
WorkContext->PreviousSMB = EVENT_TYPE_SMB_DELETE_DIRECTORY;
SrvWmiStartContext(WorkContext);
IF_SMB_DEBUG(DIRECTORY1) {
SrvPrint2( "Delete directory request header at 0x%p, response header at 0x%p\n",
WorkContext->RequestHeader,
WorkContext->ResponseHeader );
SrvPrint2( "Delete directory request params at 0x%p, response params at 0x%p\n",
WorkContext->RequestParameters,
WorkContext->ResponseParameters );
}
request = (PREQ_DELETE_DIRECTORY)WorkContext->RequestParameters;
response = (PRESP_DELETE_DIRECTORY)WorkContext->ResponseParameters;
//
// If a session block has not already been assigned to the current
// work context , verify the UID. If verified, the address of the
// session block corresponding to this user is stored in the WorkContext
// block and the session block is referenced.
//
// Find tree connect corresponding to given TID if a tree connect
// pointer has not already been put in the WorkContext block by an
// AndX command.
//
status = SrvVerifyUidAndTid(
WorkContext,
&session,
&treeConnect,
ShareTypeDisk
);
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(SMB_ERRORS) {
SrvPrint0( "SrvSmbDeleteDirectory: Invalid UID or TID\n" );
}
SrvSetSmbError( WorkContext, status );
goto Cleanup;
}
if( session->IsSessionExpired )
{
status = SESSION_EXPIRED_STATUS_CODE;
SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
goto Cleanup;
}
//
// Get the share block from the tree connect block. This doesn't need
// to be a referenced pointer becsue the tree connect has it referenced,
// and we just referenced the tree connect.
//
share = treeConnect->Share;
//
// Initialize the string containing the path name. The +1 is to account
// for the ASCII token in the Buffer field of the request SMB.
//
isUnicode = SMB_IS_UNICODE( WorkContext );
status = SrvCanonicalizePathName(
WorkContext,
share,
NULL,
(PVOID)(request->Buffer + 1),
END_OF_REQUEST_SMB( WorkContext ),
TRUE,
isUnicode,
&directoryName
);
if( !NT_SUCCESS( status ) ) {
IF_DEBUG(SMB_ERRORS) {
SrvPrint1( "SrvSmbDeleteDirectory: illegal path name: %s\n",
(PSZ)request->Buffer + 1 );
}
SrvSetSmbError( WorkContext, status );
goto Cleanup;
}
//
// If the client is trying to delete the root of the share, reject
// the request.
//
if ( directoryName.Length < sizeof(WCHAR) ) {
IF_DEBUG(SMB_ERRORS) {
SrvPrint0( "SrvSmbDeleteDirectory: attempting to delete share root\n" );
}
if ( !isUnicode ) {
RtlFreeUnicodeString( &directoryName );
}
SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
goto Cleanup;
}
//
// Initialize the object attributes structure. Open relative to the
// share root directory handle.
//
SrvInitializeObjectAttributes_U(
&objectAttributes,
&directoryName,
(WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
WorkContext->Session->UsingUppercasePaths) ?
OBJ_CASE_INSENSITIVE : 0L,
NULL,
NULL
);
//
// Attempt to open the directory. We just need DELETE access to delete
// the directory.
//
IF_SMB_DEBUG(DIRECTORY2) {
SrvPrint1( "Opening directory %wZ\n", &directoryName );
}
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
status = SrvIoCreateFile(
WorkContext,
&directoryHandle,
DELETE, // DesiredAccess
&objectAttributes,
&ioStatusBlock,
NULL, // AllocationSize
0L, // FileAttributes
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN, // Disposition
FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT, // CreateOptions
NULL, // EaBuffer
0L, // EaLength
CreateFileTypeNone,
NULL, // ExtraCreateParameters
IO_FORCE_ACCESS_CHECK, // Options
share
);
if( status == STATUS_INVALID_PARAMETER ) {
status = SrvIoCreateFile(
WorkContext,
&directoryHandle,
DELETE, // DesiredAccess
&objectAttributes,
&ioStatusBlock,
NULL, // AllocationSize
0L, // FileAttributes
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN, // Disposition
FILE_DIRECTORY_FILE, // CreateOptions
NULL, // EaBuffer
0L, // EaLength
CreateFileTypeNone,
NULL, // ExtraCreateParameters
IO_FORCE_ACCESS_CHECK, // Options
share
);
}
//
// If the user didn't have this permission, update the
// statistics database.
//
if ( status == STATUS_ACCESS_DENIED ) {
SrvStatistics.AccessPermissionErrors++;
}
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(ERRORS) {
SrvPrint2( "SrvDeleteDirectory: SrvIoCreateFile (%s) failed, "
"status = %X\n", (PSZ)request->Buffer + 1, status );
}
//
// If returned error is STATUS_NOT_A_DIRECTORY, downlevel clients
// expect ERROR_ACCESS_DENIED
//
if ( (status == STATUS_NOT_A_DIRECTORY) &&
!CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection) ) {
status = STATUS_ACCESS_DENIED;
}
SrvSetSmbError( WorkContext, status );
if ( !isUnicode ) {
RtlFreeUnicodeString( &directoryName );
}
goto Cleanup;
}
SRVDBG_CLAIM_HANDLE( directoryHandle, "DIR", 25, 0 );
IF_SMB_DEBUG(DIRECTORY2) {
SrvPrint1( "SrvIoCreateFile succeeded, handle = 0x%p\n",
directoryHandle );
}
//
// Delete the directory with NtSetInformationFile.
//
fileDispositionInformation.DeleteFile = TRUE;
status = NtSetInformationFile(
directoryHandle,
&ioStatusBlock,
&fileDispositionInformation,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation
);
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(ERRORS) {
SrvPrint2( "SrvDeleteDirectory: NtSetInformationFile for directory "
"%s returned %X\n", (PSZ)request->Buffer + 1, status );
}
SRVDBG_RELEASE_HANDLE( directoryHandle, "DIR", 38, 0 );
SrvNtClose( directoryHandle, TRUE );
if ( !isUnicode ) {
RtlFreeUnicodeString( &directoryName );
}
SrvSetSmbError( WorkContext, status );
goto Cleanup;
} else {
//
// Remove this directory name from the cache, since it has been deleted
//
SrvRemoveCachedDirectoryName( WorkContext, &directoryName );
}
IF_SMB_DEBUG(DIRECTORY2) {
SrvPrint0( "SrvSmbDeleteDirectory: NtSetInformationFile succeeded.\n" );
}
//
// Close the directory handle so that the directory will be deleted.
//
SRVDBG_RELEASE_HANDLE( directoryHandle, "DIR", 39, 0 );
SrvNtClose( directoryHandle, TRUE );
//
// Close all DOS directory searches on this directory and its
// subdirectories.
//
SrvCloseSearches(
treeConnect->Connection,
(PSEARCH_FILTER_ROUTINE)SrvSearchOnDelete,
(PVOID) &directoryName,
(PVOID) treeConnect
);
if ( !isUnicode ) {
RtlFreeUnicodeString( &directoryName );
}
//
// Build the response SMB.
//
response->WordCount = 0;
SmbPutUshort( &response->ByteCount, 0 );
WorkContext->ResponseParameters = NEXT_LOCATION(
response,
RESP_DELETE_DIRECTORY,
0
);
IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbDeleteDirectory complete.\n" );
Cleanup:
SrvWmiEndContext(WorkContext);
return SmbStatusSendResponse;
} // SrvSmbDeleteDirectory
SMB_PROCESSOR_RETURN_TYPE
SrvSmbCheckDirectory (
SMB_PROCESSOR_PARAMETERS
)
/*++
Routine Description:
This routine processes the Check Directory SMB.
Arguments:
SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
of the parameters to SMB processor routines.
Return Value:
SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
--*/
{
PREQ_CHECK_DIRECTORY request;
PRESP_CHECK_DIRECTORY response;
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
UNICODE_STRING directoryName;
FILE_NETWORK_OPEN_INFORMATION fileInformation;
PTREE_CONNECT treeConnect;
PSESSION session;
PSHARE share;
BOOLEAN isUnicode;
PAGED_CODE( );
if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
WorkContext->PreviousSMB = EVENT_TYPE_SMB_CHECK_DIRECTORY;
SrvWmiStartContext(WorkContext);
IF_SMB_DEBUG(DIRECTORY1) {
SrvPrint2( "Check directory request header at 0x%p, response header at 0x%p\n",
WorkContext->RequestHeader,
WorkContext->ResponseHeader );
SrvPrint2( "Check directory request params at 0x%p, response params at 0x%p\n",
WorkContext->RequestParameters,
WorkContext->ResponseParameters );
}
request = (PREQ_CHECK_DIRECTORY)WorkContext->RequestParameters;
response = (PRESP_CHECK_DIRECTORY)WorkContext->ResponseParameters;
//
// If a session block has not already been assigned to the current
// work context , verify the UID. If verified, the address of the
// session block corresponding to this user is stored in the WorkContext
// block and the session block is referenced.
//
// Find tree connect corresponding to given TID if a tree connect
// pointer has not already been put in the WorkContext block by an
// AndX command.
//
status = SrvVerifyUidAndTid(
WorkContext,
&session,
&treeConnect,
ShareTypeDisk
);
if ( !NT_SUCCESS(status) ) {
IF_DEBUG(SMB_ERRORS) {
SrvPrint0( "SrvSmbCheckDirectory: Invalid UID or TID\n" );
}
SrvSetSmbError( WorkContext, status );
goto Cleanup;
}
if( session->IsSessionExpired )
{
status = SESSION_EXPIRED_STATUS_CODE;
SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
goto Cleanup;
}
//
// Get the share block from the tree connect block. This doesn't need
// to be a referenced pointer because the tree connect has it referenced,
// and we just referenced the tree connect.
//
share = treeConnect->Share;
//
// Initialize the string containing the path name. The +1 is to account
// for the ASCII token in the Buffer field of the request SMB.
//
isUnicode = SMB_IS_UNICODE( WorkContext );
status = SrvCanonicalizePathName(
WorkContext,
share,
NULL,
(PVOID)(request->Buffer + 1),
END_OF_REQUEST_SMB( WorkContext ),
TRUE,
isUnicode,
&directoryName
);
if( !NT_SUCCESS( status ) ) {
IF_DEBUG(SMB_ERRORS) {
SrvPrint1( "SrvSmbCheckDirectory: illegal path name: %s\n",
(PSZ)request->Buffer + 1 );
}
SrvSetSmbError( WorkContext, status );
goto Cleanup;
}
//
// See if we can find this directory in the CachedDirectoryList
//
if( SrvIsDirectoryCached( WorkContext, &directoryName ) == FALSE ) {
//
// Is not in the cache, must really check.
//
SrvInitializeObjectAttributes_U(
&objectAttributes,
&directoryName,
(WorkContext->RequestHeader->Flags & SMB_FLAGS_CASE_INSENSITIVE ||
WorkContext->Session->UsingUppercasePaths) ?
OBJ_CASE_INSENSITIVE : 0L,
NULL,
NULL
);
status = IMPERSONATE( WorkContext );
if( NT_SUCCESS( status ) ) {
status = SrvGetShareRootHandle( share );
if( NT_SUCCESS( status ) ) {
ULONG FileOptions = FILE_DIRECTORY_FILE;
if (SeSinglePrivilegeCheck(
SeExports->SeBackupPrivilege,
KernelMode)) {
FileOptions |= FILE_OPEN_FOR_BACKUP_INTENT;
}
//
// The file name is always relative to the share root
//
status = SrvSnapGetRootHandle( WorkContext, &objectAttributes.RootDirectory );
if( !NT_SUCCESS(status) )
{
goto SnapError;
}
//
// Find out what this thing is
//
if( IoFastQueryNetworkAttributes( &objectAttributes,
FILE_TRAVERSE,
FileOptions,
&ioStatusBlock,
&fileInformation
) == FALSE ) {
SrvLogServiceFailure( SRV_SVC_IO_FAST_QUERY_NW_ATTRS, 0 );
ioStatusBlock.Status = STATUS_OBJECT_PATH_NOT_FOUND;
}
status = ioStatusBlock.Status;
//
// If the media was changed and we can come up with a new share root handle,
// then we should retry the operation
//
if( SrvRetryDueToDismount( share, status ) ) {
status = SrvSnapGetRootHandle( WorkContext, &objectAttributes.RootDirectory );
if( !NT_SUCCESS(status) )
{
goto SnapError;
}
if( IoFastQueryNetworkAttributes( &objectAttributes,
FILE_TRAVERSE,
FILE_DIRECTORY_FILE,
&ioStatusBlock,
&fileInformation
) == FALSE ) {
SrvLogServiceFailure( SRV_SVC_IO_FAST_QUERY_NW_ATTRS, 0 );
ioStatusBlock.Status = STATUS_OBJECT_PATH_NOT_FOUND;
}
status = ioStatusBlock.Status;
}
SnapError:
SrvReleaseShareRootHandle( share );
}
REVERT();
}
}
if ( !isUnicode ) {
RtlFreeUnicodeString( &directoryName );
}
if ( NT_SUCCESS(status) ) {
response->WordCount = 0;
SmbPutUshort( &response->ByteCount, 0 );
WorkContext->ResponseParameters = NEXT_LOCATION(
response,
RESP_CHECK_DIRECTORY,
0
);
} else {
//
// If the user didn't have this permission, update the
// statistics database.
//
if ( status == STATUS_ACCESS_DENIED ) {
SrvStatistics.AccessPermissionErrors++;
}
if (CLIENT_CAPABLE_OF(NT_STATUS, WorkContext->Connection)) {
SrvSetSmbError( WorkContext, status );
} else {
SrvSetSmbError( WorkContext, STATUS_OBJECT_PATH_NOT_FOUND );
}
}
IF_DEBUG(TRACE2) SrvPrint0( "SrvSmbCheckDirectory complete.\n" );
Cleanup:
SrvWmiEndContext(WorkContext);
return SmbStatusSendResponse;
} // SrvSmbCheckDirectory