You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
578 lines
14 KiB
578 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
svcfile.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines for supporting the file APIs in the
|
|
server service, SrvNetFileClose, SrvNetFileEnum, and
|
|
SrvNetFileGetInfo,
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 31-Jan-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "svcfile.tmh"
|
|
#pragma hdrstop
|
|
|
|
#define BugCheckFileId SRV_FILE_SVCFILE
|
|
|
|
//
|
|
// Forward declarations.
|
|
//
|
|
|
|
VOID
|
|
FillFileInfoBuffer (
|
|
IN PSERVER_REQUEST_PACKET Srp,
|
|
IN PVOID Block,
|
|
IN OUT PVOID *FixedStructure,
|
|
IN LPWSTR *EndOfVariableData
|
|
);
|
|
|
|
BOOLEAN
|
|
FilterFiles (
|
|
IN PSERVER_REQUEST_PACKET Srp,
|
|
IN PVOID Block
|
|
);
|
|
|
|
ULONG
|
|
SizeFiles (
|
|
IN PSERVER_REQUEST_PACKET Srp,
|
|
IN PVOID Block
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, SrvNetFileClose )
|
|
#pragma alloc_text( PAGE, SrvNetFileEnum )
|
|
#pragma alloc_text( PAGE, FillFileInfoBuffer )
|
|
#pragma alloc_text( PAGE, FilterFiles )
|
|
#pragma alloc_text( PAGE, SizeFiles )
|
|
#endif
|
|
|
|
//
|
|
// Macros to determine the size an RFCB would take up at one of the
|
|
// levels of file information.
|
|
//
|
|
// *** Note that the zero terminator on the path name is accounted for by
|
|
// the leading backslash, which is not returned.
|
|
//
|
|
|
|
#define TOTAL_SIZE_OF_FILE(lfcb,level, user) \
|
|
( (level) == 2 ? sizeof(FILE_INFO_2) : \
|
|
sizeof(FILE_INFO_3) + \
|
|
SrvLengthOfStringInApiBuffer( \
|
|
&(lfcb)->Mfcb->FileName) + \
|
|
SrvLengthOfStringInApiBuffer( user ) )
|
|
|
|
#define FIXED_SIZE_OF_FILE(level) \
|
|
( (level) == 2 ? sizeof(FILE_INFO_2) : \
|
|
sizeof(FILE_INFO_3) )
|
|
|
|
NTSTATUS
|
|
SrvNetFileClose (
|
|
IN PSERVER_REQUEST_PACKET Srp,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes the NetFileClose API in the server.
|
|
|
|
Arguments:
|
|
|
|
Srp - a pointer to the server request packet that contains all
|
|
the information necessary to satisfy the request. This includes:
|
|
|
|
INPUT:
|
|
|
|
Parameters.Get.ResumeHandle - the file ID to close.
|
|
|
|
OUTPUT:
|
|
|
|
None.
|
|
|
|
Buffer - unused.
|
|
|
|
BufferLength - unused.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - result of operation to return to the server service.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRFCB rfcb;
|
|
|
|
PAGED_CODE( );
|
|
|
|
Buffer, BufferLength;
|
|
|
|
//
|
|
// Try to find a file that matches the file ID. Only an exact
|
|
// match will work.
|
|
//
|
|
|
|
rfcb = SrvFindEntryInOrderedList(
|
|
&SrvRfcbList,
|
|
NULL,
|
|
NULL,
|
|
Srp->Parameters.Get.ResumeHandle,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
|
|
if ( rfcb == NULL ) {
|
|
Srp->ErrorCode = NERR_FileIdNotFound;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Close this RFCB.
|
|
//
|
|
|
|
SrvCloseRfcb( rfcb );
|
|
|
|
//
|
|
// SrvFindEntryInOrderedList referenced the RFCB; dereference it
|
|
// now.
|
|
//
|
|
|
|
SrvDereferenceRfcb( rfcb );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // SrvNetFileClose
|
|
|
|
|
|
NTSTATUS
|
|
SrvNetFileEnum (
|
|
IN PSERVER_REQUEST_PACKET Srp,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes the NetFileEnum API in the server.
|
|
|
|
Arguments:
|
|
|
|
Srp - a pointer to the server request packet that contains all
|
|
the information necessary to satisfy the request. This includes:
|
|
|
|
INPUT:
|
|
|
|
Name1 - basename for limiting search--only files whose path name
|
|
begin with this string are returned.
|
|
|
|
Level - level of information to return, 2 or 3.
|
|
|
|
Flags - if SRP_RETURN_SINGLE_ENTRY is set, then this is a
|
|
NetFileGetInfo, so behave accordingly.
|
|
|
|
Parameters.Get.ResumeHandle - a handle to the last file that was
|
|
returned, or 0 if this is the first call.
|
|
|
|
OUTPUT:
|
|
|
|
Parameters.Get.EntriesRead - the number of entries that fit in
|
|
the output buffer.
|
|
|
|
Parameters.Get.TotalEntries - the total number of entries that
|
|
would be returned with a large enough buffer.
|
|
|
|
Parameters.Get.TotalBytesNeeded - the buffer size that would be
|
|
required to hold all the entries.
|
|
|
|
Parameters.Get.ResumeHandle - a handle to the last file
|
|
returned.
|
|
|
|
Buffer - a pointer to the buffer for results.
|
|
|
|
BufferLength - the length of this buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - result of operation to return to the server service.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// If this is a GetInfo API, we really want to start with the file
|
|
// corresponding to the resume handle, not the one after it.
|
|
// Decrement the resume handle.
|
|
//
|
|
|
|
if ( (Srp->Flags & SRP_RETURN_SINGLE_ENTRY) != 0 ) {
|
|
Srp->Parameters.Get.ResumeHandle--;
|
|
}
|
|
|
|
return SrvEnumApiHandler(
|
|
Srp,
|
|
Buffer,
|
|
BufferLength,
|
|
&SrvRfcbList,
|
|
FilterFiles,
|
|
SizeFiles,
|
|
FillFileInfoBuffer
|
|
);
|
|
|
|
} // SrvNetFileEnum
|
|
|
|
|
|
VOID
|
|
FillFileInfoBuffer (
|
|
IN PSERVER_REQUEST_PACKET Srp,
|
|
IN PVOID Block,
|
|
IN OUT PVOID *FixedStructure,
|
|
IN LPWSTR *EndOfVariableData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine puts a single fixed file structure and associated
|
|
variable data, into a buffer. Fixed data goes at the beginning of
|
|
the buffer, variable data at the end.
|
|
|
|
*** This routine assumes that ALL the data, both fixed and variable,
|
|
will fit.
|
|
|
|
Arguments:
|
|
|
|
Srp - a pointer to the SRP for the operation. Only the Level
|
|
field is used.
|
|
|
|
Block - the RFCB from which to get information.
|
|
|
|
FixedStructure - where the ine buffer to place the fixed structure.
|
|
This pointer is updated to point to the next available
|
|
position for a fixed structure.
|
|
|
|
EndOfVariableData - the last position on the buffer that variable
|
|
data for this structure can occupy. The actual variable data
|
|
is written before this position as long as it won't overwrite
|
|
fixed structures. It is would overwrite fixed structures, it
|
|
is not written.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFILE_INFO_3 fi3 = *FixedStructure;
|
|
PRFCB rfcb;
|
|
PLFCB lfcb;
|
|
UNICODE_STRING userName;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Update FixedStructure to point to the next structure location.
|
|
//
|
|
|
|
*FixedStructure = (PCHAR)*FixedStructure + FIXED_SIZE_OF_FILE( Srp->Level );
|
|
ASSERT( (ULONG_PTR)*EndOfVariableData >= (ULONG_PTR)*FixedStructure );
|
|
|
|
rfcb = Block;
|
|
lfcb = rfcb->Lfcb;
|
|
|
|
//
|
|
// Case on the level to fill in the fixed structure appropriately.
|
|
// We fill in actual pointers in the output structure. This is
|
|
// possible because we are in the server FSD, hence the server
|
|
// service's process and address space.
|
|
//
|
|
// *** Using the switch statement in this fashion relies on the fact
|
|
// that the first fields on the different file structures are
|
|
// identical.
|
|
//
|
|
|
|
switch( Srp->Level ) {
|
|
|
|
case 3:
|
|
|
|
//
|
|
// Set level 3 specific fields in the buffer. Convert the
|
|
// permissions (granted access) stored in the LFCB to the format
|
|
// expected by the API.
|
|
//
|
|
|
|
fi3->fi3_permissions = 0;
|
|
|
|
if ( (lfcb->GrantedAccess & FILE_READ_DATA) != 0 ) {
|
|
fi3->fi3_permissions |= ACCESS_READ;
|
|
}
|
|
|
|
if ( (lfcb->GrantedAccess & FILE_WRITE_DATA) != 0 ) {
|
|
fi3->fi3_permissions |= ACCESS_WRITE;
|
|
}
|
|
|
|
if ( (lfcb->GrantedAccess & FILE_EXECUTE) != 0 ) {
|
|
fi3->fi3_permissions |= ACCESS_EXEC;
|
|
}
|
|
|
|
if ( (lfcb->GrantedAccess & DELETE) != 0 ) {
|
|
fi3->fi3_permissions |= ACCESS_DELETE;
|
|
}
|
|
|
|
if ( (lfcb->GrantedAccess & FILE_WRITE_ATTRIBUTES) != 0 ) {
|
|
fi3->fi3_permissions |= ACCESS_ATRIB;
|
|
}
|
|
|
|
if ( (lfcb->GrantedAccess & WRITE_DAC) != 0 ) {
|
|
fi3->fi3_permissions |= ACCESS_PERM;
|
|
}
|
|
|
|
//
|
|
// Set count of locks on the RFCB.
|
|
//
|
|
|
|
fi3->fi3_num_locks = rfcb->NumberOfLocks;
|
|
|
|
//
|
|
// Set up the pathname and username of the RFCB. Note that we
|
|
// don't return the leading backslash on file names.
|
|
//
|
|
|
|
SrvCopyUnicodeStringToBuffer(
|
|
&lfcb->Mfcb->FileName,
|
|
*FixedStructure,
|
|
EndOfVariableData,
|
|
&fi3->fi3_pathname
|
|
);
|
|
|
|
ASSERT( fi3->fi3_pathname != NULL );
|
|
|
|
SrvGetUserAndDomainName( lfcb->Session, &userName, NULL );
|
|
|
|
SrvCopyUnicodeStringToBuffer(
|
|
&userName,
|
|
*FixedStructure,
|
|
EndOfVariableData,
|
|
&fi3->fi3_username
|
|
);
|
|
|
|
if( userName.Buffer ) {
|
|
SrvReleaseUserAndDomainName( lfcb->Session, &userName, NULL );
|
|
}
|
|
|
|
//ASSERT( fi3->fi3_username != NULL );
|
|
|
|
// *** Lack of break is intentional!
|
|
|
|
case 2:
|
|
|
|
//
|
|
// Set up the file ID. Note that it is the same value as is
|
|
// used for the resume handle, so it is possible to use this
|
|
// value for rewindability.
|
|
//
|
|
|
|
fi3->fi3_id = rfcb->GlobalRfcbListEntry.ResumeHandle;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// This should never happen. The server service should have
|
|
// checked for an invalid level.
|
|
//
|
|
|
|
INTERNAL_ERROR(
|
|
ERROR_LEVEL_UNEXPECTED,
|
|
"FillFileInfoBuffer: invalid level number: %ld",
|
|
Srp->Level,
|
|
NULL
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
return;
|
|
|
|
} // FillFileInfoBuffer
|
|
|
|
|
|
BOOLEAN
|
|
FilterFiles (
|
|
IN PSERVER_REQUEST_PACKET Srp,
|
|
IN PVOID Block
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is intended to be called by SrvEnumApiHandler to check
|
|
whether a particular RFCB should be returned.
|
|
|
|
Arguments:
|
|
|
|
Srp - a pointer to the SRP for the operation. ResumeHandle is
|
|
used if this is a NetFileGetInfo; Name1 is used as the path
|
|
name and Name2 is used as the user name if this is a
|
|
NetFileEnum.
|
|
|
|
Block - a pointer to the RFCB to check.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the block should be placed in the output buffer, FALSE
|
|
if it should be passed over.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRFCB rfcb = Block;
|
|
PLFCB lfcb = rfcb->Lfcb;
|
|
PMFCB mfcb = lfcb->Mfcb;
|
|
UNICODE_STRING pathName;
|
|
UNICODE_STRING userName;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Check if this is an Enum or GetInfo command. The SRP_RETURN_SINGLE_ENTRY
|
|
// flag is set if this is a get info.
|
|
//
|
|
|
|
if ( (Srp->Flags & SRP_RETURN_SINGLE_ENTRY) == 0 ) {
|
|
|
|
//
|
|
// If a user name was specified, the user name on the session
|
|
// must match the user name in the SRP exactly.
|
|
//
|
|
|
|
if ( Srp->Name2.Length != 0 ) {
|
|
|
|
//
|
|
// Get the user name for the owning session
|
|
//
|
|
SrvGetUserAndDomainName( lfcb->Session, &userName, NULL );
|
|
|
|
if( userName.Buffer == NULL ) {
|
|
//
|
|
// Since we don't know who owns the session, we can't match
|
|
// the username
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !RtlEqualUnicodeString(
|
|
&Srp->Name2,
|
|
&userName,
|
|
TRUE ) ) {
|
|
|
|
//
|
|
// The names don't match. Don't put this RFCB in the
|
|
// output buffer.
|
|
//
|
|
|
|
SrvReleaseUserAndDomainName( lfcb->Session, &userName, NULL );
|
|
return FALSE;
|
|
}
|
|
|
|
SrvReleaseUserAndDomainName( lfcb->Session, &userName, NULL );
|
|
}
|
|
|
|
//
|
|
// See if the names match to as many digits of precision as are in
|
|
// the specified base name. Note that if no base name was
|
|
// specified, then the length = 0 and the file path will always
|
|
// match. Also note that the path name stored in the MFCB has a
|
|
// leading backslash, while the passed-in path name will never have
|
|
// this leading slash, hence the increment of the MFCB file name
|
|
// buffer.
|
|
//
|
|
|
|
pathName.Buffer = mfcb->FileName.Buffer;
|
|
pathName.Length =
|
|
MIN( Srp->Name1.Length, mfcb->FileName.Length );
|
|
pathName.MaximumLength = mfcb->FileName.MaximumLength;
|
|
|
|
return RtlEqualUnicodeString(
|
|
&Srp->Name1,
|
|
&pathName,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
//
|
|
// It's a GetInfo, so just see if the ResumeHandle in the SRP
|
|
// matches the ResumeHandle on the RFCB. We increment the value in
|
|
// the SRP because it was decremented before calling
|
|
// SrvEnumApiHandler.
|
|
//
|
|
|
|
return (BOOLEAN)( Srp->Parameters.Get.ResumeHandle + 1==
|
|
SrvGetResumeHandle( &SrvRfcbList, rfcb ) );
|
|
|
|
} // FilterFiles
|
|
|
|
|
|
ULONG
|
|
SizeFiles (
|
|
IN PSERVER_REQUEST_PACKET Srp,
|
|
IN PVOID Block
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the size the passed-in RFCB would take up
|
|
in an API output buffer.
|
|
|
|
Arguments:
|
|
|
|
Srp - a pointer to the SRP for the operation. Only the level
|
|
parameter is used.
|
|
|
|
Block - a pointer to the RFCB to size.
|
|
|
|
Return Value:
|
|
|
|
ULONG - The number of bytes the file would take up in the output
|
|
buffer.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRFCB rfcb = Block;
|
|
UNICODE_STRING userName;
|
|
ULONG size;
|
|
|
|
PAGED_CODE( );
|
|
|
|
SrvGetUserAndDomainName( rfcb->Lfcb->Session, &userName, NULL );
|
|
|
|
size = TOTAL_SIZE_OF_FILE( rfcb->Lfcb, Srp->Level, &userName );
|
|
|
|
SrvReleaseUserAndDomainName( rfcb->Lfcb->Session, &userName, NULL );
|
|
|
|
return size;
|
|
|
|
} // SizeFiles
|