|
|
/*++
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
|