2744 lines
74 KiB
C
2744 lines
74 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ea.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the mini redirector call down routines pertaining to query/set ea/security.
|
||
|
||
Author:
|
||
|
||
joelinn [joelinn] 12-jul-95
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// Forward declarations.
|
||
//
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
VOID
|
||
MRxSmbInitializeExtraAceArray(
|
||
VOID
|
||
);
|
||
|
||
BOOLEAN
|
||
MRxSmbAclHasExtraAces(
|
||
IN PACL Acl
|
||
);
|
||
|
||
NTSTATUS
|
||
MRxSmbRemoveExtraAcesFromSelfRelativeSD(
|
||
IN PSECURITY_DESCRIPTOR OriginalSecurityDescriptor,
|
||
OUT PSECURITY_DESCRIPTOR * NewSecurityDescriptor,
|
||
OUT PBOOLEAN WereRemoved
|
||
);
|
||
|
||
NTSTATUS
|
||
MRxSmbAddExtraAcesToSelfRelativeSD(
|
||
IN PSECURITY_DESCRIPTOR OriginalSecurityDescriptor,
|
||
IN BOOLEAN InheritableAces,
|
||
OUT PSECURITY_DESCRIPTOR * NewSecurityDescriptor
|
||
);
|
||
|
||
NTSTATUS
|
||
MRxSmbCreateExtraAcesSelfRelativeSD(
|
||
IN BOOLEAN InheritableAces,
|
||
OUT PSECURITY_DESCRIPTOR * NewSecurityDescriptor
|
||
);
|
||
|
||
NTSTATUS
|
||
MRxSmbSelfRelativeToAbsoluteSD(
|
||
IN PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
|
||
OUT PSECURITY_DESCRIPTOR * AbsoluteSecurityDescriptor,
|
||
OUT PACL * Dacl,
|
||
OUT PACL * Sacl,
|
||
OUT PSID * Owner,
|
||
OUT PSID * Group
|
||
);
|
||
|
||
NTSTATUS
|
||
MRxSmbAbsoluteToSelfRelativeSD(
|
||
PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
|
||
PSECURITY_DESCRIPTOR * SelfRelativeSecurityDescriptor
|
||
);
|
||
|
||
//
|
||
// Definitions from ntrtl.h
|
||
//
|
||
|
||
NTSYSAPI
|
||
NTSTATUS
|
||
NTAPI
|
||
RtlAbsoluteToSelfRelativeSD(
|
||
PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
|
||
PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
|
||
PULONG BufferLength
|
||
);
|
||
|
||
NTSYSAPI
|
||
NTSTATUS
|
||
NTAPI
|
||
RtlSelfRelativeToAbsoluteSD(
|
||
PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
|
||
PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
|
||
PULONG AbsoluteSecurityDescriptorSize,
|
||
PACL Dacl,
|
||
PULONG DaclSize,
|
||
PACL Sacl,
|
||
PULONG SaclSize,
|
||
PSID Owner,
|
||
PULONG OwnerSize,
|
||
PSID PrimaryGroup,
|
||
PULONG PrimaryGroupSize
|
||
);
|
||
|
||
NTSYSAPI
|
||
NTSTATUS
|
||
NTAPI
|
||
RtlAddAce (
|
||
PACL Acl,
|
||
ULONG AceRevision,
|
||
ULONG StartingAceIndex,
|
||
PVOID AceList,
|
||
ULONG AceListLength
|
||
);
|
||
|
||
NTSYSAPI
|
||
NTSTATUS
|
||
NTAPI
|
||
RtlDeleteAce (
|
||
PACL Acl,
|
||
ULONG AceIndex
|
||
);
|
||
|
||
NTSYSAPI
|
||
NTSTATUS
|
||
NTAPI
|
||
RtlGetAce (
|
||
PACL Acl,
|
||
ULONG AceIndex,
|
||
PVOID *Ace
|
||
);
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, MRxSmbQueryEaInformation)
|
||
#pragma alloc_text(PAGE, MRxSmbSetEaInformation)
|
||
#if defined(REMOTE_BOOT)
|
||
#pragma alloc_text(PAGE, MRxSmbInitializeExtraAceArray)
|
||
#pragma alloc_text(PAGE, MRxSmbAclHasExtraAces)
|
||
#pragma alloc_text(PAGE, MRxSmbRemoveExtraAcesFromSelfRelativeSD)
|
||
#pragma alloc_text(PAGE, MRxSmbAddExtraAcesToSelfRelativeSD)
|
||
#pragma alloc_text(PAGE, MRxSmbSelfRelativeToAbsoluteSD)
|
||
#pragma alloc_text(PAGE, MRxSmbAbsoluteToSelfRelativeSD)
|
||
#endif // defined(REMOTE_BOOT)
|
||
#pragma alloc_text(PAGE, MRxSmbQuerySecurityInformation)
|
||
#pragma alloc_text(PAGE, MRxSmbSetSecurityInformation)
|
||
#pragma alloc_text(PAGE, MRxSmbLoadEaList)
|
||
#pragma alloc_text(PAGE, MRxSmbNtGeaListToOs2)
|
||
#pragma alloc_text(PAGE, MRxSmbNtGetEaToOs2)
|
||
#pragma alloc_text(PAGE, MRxSmbQueryEasFromServer)
|
||
#pragma alloc_text(PAGE, MRxSmbNtFullEaSizeToOs2)
|
||
#pragma alloc_text(PAGE, MRxSmbNtFullListToOs2)
|
||
#pragma alloc_text(PAGE, MRxSmbNtFullEaToOs2)
|
||
#pragma alloc_text(PAGE, MRxSmbSetEaList)
|
||
#endif
|
||
|
||
////
|
||
//// The Bug check file id for this module
|
||
////
|
||
//
|
||
//#define BugCheckFileId (RDBSS_BUG_CHECK_LOCAL_CREATE)
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_EA)
|
||
|
||
//this is the largest EAs that could ever be returned! oh my god!
|
||
//this is used to simulate the nt resumable queryEA using the downlevel call
|
||
//sigh!
|
||
#define EA_QUERY_SIZE 0x0000ffff
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
//
|
||
// ACEs that are added to the front of server ACLs. The array is
|
||
// initialized by MRxSmbInitializeExtraAceArray.
|
||
//
|
||
|
||
typedef struct _EXTRA_ACE_INFO {
|
||
UCHAR AceType;
|
||
UCHAR AceFlags;
|
||
USHORT AceSize;
|
||
ACCESS_MASK Mask;
|
||
PVOID Sid;
|
||
} EXTRA_ACE_INFO, *PEXTRA_ACE_INFO;
|
||
|
||
#define EXTRA_ACE_INFO_COUNT 4
|
||
EXTRA_ACE_INFO ExtraAceInfo[EXTRA_ACE_INFO_COUNT];
|
||
ULONG ExtraAceInfoCount;
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
|
||
//for QueryEA
|
||
NTSTATUS
|
||
MRxSmbLoadEaList(
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PUCHAR UserEaList,
|
||
IN ULONG UserEaListLength,
|
||
OUT PFEALIST *ServerEaList
|
||
);
|
||
|
||
NTSTATUS
|
||
MRxSmbQueryEasFromServer(
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PFEALIST ServerEaList,
|
||
IN PVOID Buffer,
|
||
IN OUT PULONG BufferLengthRemaining,
|
||
IN BOOLEAN ReturnSingleEntry,
|
||
IN BOOLEAN UserEaListSupplied
|
||
);
|
||
|
||
//for SetEA
|
||
NTSTATUS
|
||
MRxSmbSetEaList(
|
||
// IN PICB Icb,
|
||
// IN PIRP Irp,
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PFEALIST ServerEaList
|
||
);
|
||
|
||
VOID MRxSmbExtraEaRoutine(LONG i){
|
||
RxDbgTrace( 0, Dbg, ("MRxSmbExtraEaRoutine i=%08lx\n", i ));
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbQueryEaInformation (
|
||
IN OUT PRX_CONTEXT RxContext
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
RxCaptureFcb;
|
||
RxCaptureFobx;
|
||
|
||
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
||
|
||
PVOID Buffer = RxContext->Info.Buffer;
|
||
PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
|
||
PUCHAR UserEaList = RxContext->QueryEa.UserEaList;
|
||
ULONG UserEaListLength = RxContext->QueryEa.UserEaListLength;
|
||
ULONG UserEaIndex = RxContext->QueryEa.UserEaIndex;
|
||
BOOLEAN RestartScan = RxContext->QueryEa.RestartScan;
|
||
BOOLEAN ReturnSingleEntry = RxContext->QueryEa.ReturnSingleEntry;
|
||
BOOLEAN IndexSpecified = RxContext->QueryEa.IndexSpecified;
|
||
|
||
PFEALIST ServerEaList = NULL;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbQueryEaInformation\n"));
|
||
|
||
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
||
|
||
//get rid of nonEA guys right now
|
||
if (!FlagOn(pServerEntry->Server.DialectFlags,DF_SUPPORTEA)) {
|
||
RxDbgTrace(-1, Dbg, ("EAs w/o EA support!\n"));
|
||
return((STATUS_NOT_SUPPORTED));
|
||
}
|
||
|
||
if (MRxSmbIsThisADisconnectedOpen(capFobx->pSrvOpen)) {
|
||
return STATUS_ONLY_IF_CONNECTED;
|
||
}
|
||
|
||
|
||
Status = MRxSmbDeferredCreate(RxContext);
|
||
if (Status!=STATUS_SUCCESS) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
Status = MRxSmbLoadEaList( RxContext, UserEaList, UserEaListLength, &ServerEaList );
|
||
|
||
if (( !NT_SUCCESS( Status ) )||
|
||
( ServerEaList == NULL )) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
if (IndexSpecified) {
|
||
|
||
//CODE.IMPROVEMENT this name is poor....it owes back to the fastfat heritage and is not so meaningful
|
||
// for a rdr
|
||
capFobx->OffsetOfNextEaToReturn = UserEaIndex;
|
||
Status = MRxSmbQueryEasFromServer(
|
||
RxContext,
|
||
ServerEaList,
|
||
Buffer,
|
||
pLengthRemaining,
|
||
ReturnSingleEntry,
|
||
(BOOLEAN)(UserEaList != NULL) );
|
||
|
||
//
|
||
// if there are no Ea's on the file, and the user supplied an EA
|
||
// index, we want to map the error to STATUS_NONEXISTANT_EA_ENTRY.
|
||
//
|
||
|
||
if ( Status == STATUS_NO_EAS_ON_FILE ) {
|
||
Status = STATUS_NONEXISTENT_EA_ENTRY;
|
||
}
|
||
} else {
|
||
|
||
if ( ( RestartScan == TRUE ) || (UserEaList != NULL) ){
|
||
|
||
//
|
||
// Ea Indices start at 1, not 0....
|
||
//
|
||
|
||
capFobx->OffsetOfNextEaToReturn = 1;
|
||
}
|
||
|
||
Status = MRxSmbQueryEasFromServer( //it is offensive to have two identical calls but oh, well.....
|
||
RxContext,
|
||
ServerEaList,
|
||
Buffer,
|
||
pLengthRemaining,
|
||
ReturnSingleEntry,
|
||
(BOOLEAN)(UserEaList != NULL) );
|
||
}
|
||
|
||
FINALLY:
|
||
|
||
if ( ServerEaList != NULL) {
|
||
RxFreePool(ServerEaList);
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbQueryEaInformation st=%08lx\n",Status));
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbSetEaInformation (
|
||
IN OUT struct _RX_CONTEXT * RxContext
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
RxCaptureFcb; RxCaptureFobx;
|
||
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
||
|
||
PVOID Buffer = RxContext->Info.Buffer;
|
||
ULONG Length = RxContext->Info.Length;
|
||
|
||
PFEALIST ServerEaList = NULL;
|
||
ULONG Size;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbSetEaInformation\n"));
|
||
|
||
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
||
|
||
//get rid of nonEA guys right now
|
||
if (!FlagOn(pServerEntry->Server.DialectFlags,DF_SUPPORTEA)) {
|
||
RxDbgTrace(-1, Dbg, ("EAs w/o EA support!\n"));
|
||
return((STATUS_NOT_SUPPORTED));
|
||
}
|
||
|
||
if (MRxSmbIsThisADisconnectedOpen(capFobx->pSrvOpen)) {
|
||
return STATUS_ONLY_IF_CONNECTED;
|
||
}
|
||
|
||
Status = MRxSmbDeferredCreate(RxContext);
|
||
if (Status!=STATUS_SUCCESS) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
//
|
||
// Convert Nt format FEALIST to OS/2 format
|
||
//
|
||
Size = MRxSmbNtFullEaSizeToOs2 ( Buffer );
|
||
if ( Size > 0x0000ffff ) {
|
||
Status = STATUS_EA_TOO_LARGE;
|
||
goto FINALLY;
|
||
}
|
||
|
||
//CODE.IMPROVEMENT since |os2eas|<=|nteas| we really don't need a maximum buffer
|
||
ServerEaList = RxAllocatePool ( PagedPool, EA_QUERY_SIZE );
|
||
if ( ServerEaList == NULL ) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto FINALLY;
|
||
}
|
||
|
||
MRxSmbNtFullListToOs2 ( Buffer, ServerEaList );
|
||
|
||
//
|
||
// Set EAs on the file/directory; if the error is EA_ERROR then SetEaList
|
||
// sets iostatus.information to the offset of the offender
|
||
//
|
||
|
||
Status = MRxSmbSetEaList( RxContext, ServerEaList);
|
||
|
||
FINALLY:
|
||
|
||
if ( ServerEaList != NULL) {
|
||
RxFreePool(ServerEaList);
|
||
}
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
// invalidate the name based file info cache since the attributes of the file on
|
||
// the server have been changed
|
||
MRxSmbInvalidateFileInfoCache(RxContext);
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbSetEaInformation st=%08lx\n",Status));
|
||
return Status;
|
||
|
||
}
|
||
|
||
#if DBG
|
||
VOID
|
||
MRxSmbDumpSecurityDescriptor(
|
||
IN PSECURITY_DESCRIPTOR SecurityDescriptor
|
||
)
|
||
{
|
||
PISECURITY_DESCRIPTOR sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
|
||
ULONG sdLength = RtlLengthSecurityDescriptor(sd);
|
||
PACL dacl;
|
||
PACCESS_ALLOWED_ACE ace;
|
||
ULONG i, j;
|
||
PUCHAR p;
|
||
PISID sid;
|
||
BOOLEAN selfRelative;
|
||
|
||
selfRelative = (BOOLEAN)((sd->Control & SE_SELF_RELATIVE) != 0);
|
||
DbgPrint( " SD:\n" );
|
||
DbgPrint( " Revision = %x, Control = %x\n", sd->Revision, sd->Control );
|
||
DbgPrint( " Owner = %x, Group = %x\n", sd->Owner, sd->Group );
|
||
DbgPrint( " Sacl = %x, Dacl = %x\n", sd->Sacl, sd->Dacl );
|
||
if ( (sd->Control & SE_DACL_PRESENT) != 0 ) {
|
||
dacl = sd->Dacl;
|
||
if ( selfRelative ) {
|
||
dacl = (PACL)((PUCHAR)sd + (ULONG_PTR)dacl);
|
||
}
|
||
DbgPrint( " DACL:\n" );
|
||
DbgPrint( " AclRevision = %x, AclSize = %x, AceCount = %x\n",
|
||
dacl->AclRevision, dacl->AclSize, dacl->AceCount );
|
||
ace = (PACCESS_ALLOWED_ACE)(dacl + 1);
|
||
for ( i = 0; i < dacl->AceCount; i++ ) {
|
||
DbgPrint( " ACE %d:\n", i );
|
||
DbgPrint( " AceType = %x, AceFlags = %x, AceSize = %x\n",
|
||
ace->Header.AceType, ace->Header.AceFlags, ace->Header.AceSize );
|
||
if ( ace->Header.AceType < ACCESS_MAX_MS_V2_ACE_TYPE ) {
|
||
DbgPrint(" Mask = %08x, Sid = ", ace->Mask );
|
||
for ( j = FIELD_OFFSET(ACCESS_ALLOWED_ACE,SidStart), p = (PUCHAR)&ace->SidStart;
|
||
j < ace->Header.AceSize;
|
||
j++, p++ ) {
|
||
DbgPrint( "%02x ", *p );
|
||
}
|
||
DbgPrint( "\n" );
|
||
}
|
||
ace = (PACCESS_ALLOWED_ACE)((PUCHAR)ace + ace->Header.AceSize );
|
||
}
|
||
}
|
||
if ( sd->Owner != 0 ) {
|
||
sid = sd->Owner;
|
||
if ( selfRelative ) {
|
||
sid = (PISID)((PUCHAR)sd + (ULONG_PTR)sid);
|
||
}
|
||
DbgPrint( " Owner SID:\n" );
|
||
DbgPrint( " Revision = %x, SubAuthorityCount = %x\n",
|
||
sid->Revision, sid->SubAuthorityCount );
|
||
DbgPrint( " IdentifierAuthority = " );
|
||
for ( j = 0; j < 6; j++ ) {
|
||
DbgPrint( "%02x ", sid->IdentifierAuthority.Value[j] );
|
||
}
|
||
DbgPrint( "\n" );
|
||
for ( i = 0; i < sid->SubAuthorityCount; i++ ) {
|
||
DbgPrint(" SubAuthority %d = ", i );
|
||
for ( j = 0, p = (PUCHAR)&sid->SubAuthority[i]; j < 4; j++, p++ ) {
|
||
DbgPrint( "%02x ", *p );
|
||
}
|
||
DbgPrint( "\n" );
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
VOID
|
||
MRxSmbInitializeExtraAceArray(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the array of extra ACEs that we add to
|
||
the front of ACLs for files on the server. It must be called
|
||
*after* SeEnableAccessToExports has been called.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ULONG i;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Our code assumes the ACEs we use have the same structure.
|
||
//
|
||
|
||
ASSERT(FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) ==
|
||
FIELD_OFFSET(ACCESS_DENIED_ACE, SidStart));
|
||
|
||
ASSERT((sizeof(ExtraAceInfo) / sizeof(EXTRA_ACE_INFO)) == EXTRA_ACE_INFO_COUNT);
|
||
ExtraAceInfoCount = EXTRA_ACE_INFO_COUNT;
|
||
|
||
ExtraAceInfo[0].AceType = ACCESS_ALLOWED_ACE_TYPE;
|
||
ExtraAceInfo[0].AceFlags = 0;
|
||
ExtraAceInfo[0].Mask = FILE_ALL_ACCESS;
|
||
ExtraAceInfo[0].Sid = MRxSmbRemoteBootMachineSid;
|
||
|
||
ExtraAceInfo[1].AceType = ACCESS_ALLOWED_ACE_TYPE;
|
||
ExtraAceInfo[1].AceFlags = 0;
|
||
ExtraAceInfo[1].Mask = FILE_ALL_ACCESS;
|
||
ExtraAceInfo[1].Sid = SeExports->SeLocalSystemSid;
|
||
|
||
ExtraAceInfo[2].AceType = ACCESS_ALLOWED_ACE_TYPE;
|
||
ExtraAceInfo[2].AceFlags = 0;
|
||
ExtraAceInfo[2].Mask = FILE_ALL_ACCESS;
|
||
ExtraAceInfo[2].Sid = SeExports->SeAliasAdminsSid;
|
||
|
||
ExtraAceInfo[3].AceType = ACCESS_DENIED_ACE_TYPE;
|
||
ExtraAceInfo[3].AceFlags = 0;
|
||
ExtraAceInfo[3].Mask = FILE_ALL_ACCESS;
|
||
ExtraAceInfo[3].Sid = SeExports->SeWorldSid;
|
||
|
||
for (i = 0; i < ExtraAceInfoCount; i++) {
|
||
ExtraAceInfo[i].AceSize = (USHORT)(FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) +
|
||
RtlLengthSid((PSID)(ExtraAceInfo[i].Sid)));
|
||
}
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
MRxSmbAclHasExtraAces(
|
||
IN PACL Acl
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine determines if an ACL has the special ACEs that we
|
||
put on the front for remote boot server files.
|
||
|
||
Arguments:
|
||
|
||
Acl - The ACL to check.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the ACEs are there, FALSE otherwise (including if there
|
||
are any errors while checking).
|
||
|
||
--*/
|
||
{
|
||
PACCESS_ALLOWED_ACE Ace;
|
||
ULONG KnownSidLength;
|
||
ULONG i;
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Make sure the first n ACEs in this ACL match those in our
|
||
// array.
|
||
//
|
||
|
||
for (i = 0; i < ExtraAceInfoCount; i++) {
|
||
|
||
Status = RtlGetAce(Acl, i, &Ace);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return FALSE;
|
||
}
|
||
|
||
KnownSidLength = ExtraAceInfo[i].AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart);
|
||
|
||
//
|
||
// Don't compare the flags to avoid worrying about inherited
|
||
// flags.
|
||
//
|
||
|
||
if ((Ace->Header.AceType != ExtraAceInfo[i].AceType) ||
|
||
// TMP: my server doesn't store 0x200 bit // (Ace->Mask != ExtraAceInfo[i].Mask) ||
|
||
(RtlLengthSid((PSID)(&Ace->SidStart)) != KnownSidLength) ||
|
||
(memcmp(&Ace->SidStart, ExtraAceInfo[i].Sid, KnownSidLength) != 0)) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Everything matched, so it does have the extra ACEs.
|
||
//
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbSelfRelativeToAbsoluteSD(
|
||
IN PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor,
|
||
OUT PSECURITY_DESCRIPTOR * AbsoluteSecurityDescriptor,
|
||
OUT PACL * Dacl,
|
||
OUT PACL * Sacl,
|
||
OUT PSID * Owner,
|
||
OUT PSID * Group
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine converts a self-relative security descriptor to
|
||
absolute form, allocating all the entries needed.
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
Status - Result of the operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG AbsoluteSecurityDescriptorSize = 0;
|
||
ULONG GroupSize = 0;
|
||
ULONG OwnerSize = 0;
|
||
ULONG SaclSize = 0;
|
||
ULONG DaclSize = 0;
|
||
PUCHAR AllocatedBuffer;
|
||
ULONG AllocatedBufferSize;
|
||
|
||
PAGED_CODE();
|
||
|
||
*AbsoluteSecurityDescriptor = NULL;
|
||
*Owner = NULL;
|
||
*Group = NULL;
|
||
*Dacl = NULL;
|
||
*Sacl = NULL;
|
||
|
||
//
|
||
// First determine how much storage is needed by the SD.
|
||
//
|
||
|
||
Status = RtlSelfRelativeToAbsoluteSD(
|
||
SelfRelativeSecurityDescriptor,
|
||
NULL,
|
||
&AbsoluteSecurityDescriptorSize,
|
||
NULL,
|
||
&DaclSize,
|
||
NULL,
|
||
&SaclSize,
|
||
NULL,
|
||
&OwnerSize,
|
||
NULL,
|
||
&GroupSize);
|
||
|
||
//
|
||
// We expect to get this error since at least the core of the SD
|
||
// has some non-zero size.
|
||
//
|
||
|
||
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||
|
||
AllocatedBufferSize =
|
||
AbsoluteSecurityDescriptorSize +
|
||
OwnerSize +
|
||
GroupSize +
|
||
SaclSize +
|
||
DaclSize;
|
||
|
||
ASSERT(AllocatedBufferSize > 0);
|
||
|
||
AllocatedBuffer = RxAllocatePoolWithTag(PagedPool, AllocatedBufferSize, MRXSMB_REMOTEBOOT_POOLTAG);
|
||
|
||
if (AllocatedBuffer == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Walk through each piece of memory we need and take a chunk
|
||
// of AllocatedBuffer. The caller assumes that AbsoluteSecurityDescriptor
|
||
// will be the address of the buffer they need to free, so we always
|
||
// set that even if the size needed is 0 (which should never happen!).
|
||
// For the others we set them if the size needed is not NULL.
|
||
//
|
||
|
||
ASSERT(AbsoluteSecurityDescriptorSize > 0);
|
||
|
||
*AbsoluteSecurityDescriptor = (PSECURITY_DESCRIPTOR)AllocatedBuffer;
|
||
AllocatedBuffer += AbsoluteSecurityDescriptorSize;
|
||
|
||
if (OwnerSize > 0) {
|
||
*Owner = (PSID)AllocatedBuffer;
|
||
AllocatedBuffer += OwnerSize;
|
||
}
|
||
|
||
if (GroupSize > 0) {
|
||
*Group = (PSID)AllocatedBuffer;
|
||
AllocatedBuffer += GroupSize;
|
||
}
|
||
|
||
if (SaclSize > 0) {
|
||
*Sacl = (PACL)AllocatedBuffer;
|
||
AllocatedBuffer += SaclSize;
|
||
}
|
||
|
||
if (DaclSize > 0) {
|
||
*Dacl = (PACL)AllocatedBuffer;
|
||
}
|
||
|
||
//
|
||
// Now make the call again to really do the conversion.
|
||
//
|
||
|
||
Status = RtlSelfRelativeToAbsoluteSD(
|
||
SelfRelativeSecurityDescriptor,
|
||
*AbsoluteSecurityDescriptor,
|
||
&AbsoluteSecurityDescriptorSize,
|
||
*Dacl,
|
||
&DaclSize,
|
||
*Sacl,
|
||
&SaclSize,
|
||
*Owner,
|
||
&OwnerSize,
|
||
*Group,
|
||
&GroupSize);
|
||
|
||
} else {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status) && (*AbsoluteSecurityDescriptor != NULL)) {
|
||
RxFreePool(*AbsoluteSecurityDescriptor);
|
||
*AbsoluteSecurityDescriptor = NULL;
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbAbsoluteToSelfRelativeSD(
|
||
PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
|
||
PSECURITY_DESCRIPTOR * SelfRelativeSecurityDescriptor
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine converts an absolute security descriptor to
|
||
self-relative form, allocating all the entries needed.
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
Status - Result of the operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG SelfRelativeSdSize = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
*SelfRelativeSecurityDescriptor = NULL;
|
||
|
||
Status = RtlAbsoluteToSelfRelativeSD(
|
||
AbsoluteSecurityDescriptor,
|
||
NULL,
|
||
&SelfRelativeSdSize);
|
||
|
||
ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
|
||
|
||
*SelfRelativeSecurityDescriptor = RxAllocatePoolWithTag(NonPagedPool, SelfRelativeSdSize, MRXSMB_REMOTEBOOT_POOLTAG);
|
||
if (*SelfRelativeSecurityDescriptor == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Now do the real conversion.
|
||
//
|
||
|
||
Status = RtlAbsoluteToSelfRelativeSD(
|
||
AbsoluteSecurityDescriptor,
|
||
*SelfRelativeSecurityDescriptor,
|
||
&SelfRelativeSdSize);
|
||
|
||
if (!NT_SUCCESS(Status) && (*SelfRelativeSecurityDescriptor != NULL)) {
|
||
RxFreePool(*SelfRelativeSecurityDescriptor);
|
||
*SelfRelativeSecurityDescriptor = NULL;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbRemoveExtraAcesFromSelfRelativeSD(
|
||
IN PSECURITY_DESCRIPTOR OriginalSecurityDescriptor,
|
||
OUT PSECURITY_DESCRIPTOR * NewSecurityDescriptor,
|
||
OUT PBOOLEAN WereRemoved
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes an existing self-relative security descriptor
|
||
and produces a new self-relative security descriptor with our
|
||
extra ACEs removed. It returns S_FALSE if they did not need to
|
||
be removed.
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
Status - Result of the operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PSECURITY_DESCRIPTOR AbsoluteSd = NULL;
|
||
PSID Owner;
|
||
PSID Group;
|
||
PACL Dacl;
|
||
PACL Sacl;
|
||
PACL NewDacl = NULL;
|
||
ULONG NewDaclSize;
|
||
BOOLEAN DaclPresent, DaclDefaulted;
|
||
|
||
*NewSecurityDescriptor = NULL;
|
||
*WereRemoved = FALSE;
|
||
|
||
//
|
||
// Check if we need to strip off any ACEs in the DACL
|
||
// that SetSecurityInformation may have added.
|
||
//
|
||
|
||
Status = RtlGetDaclSecurityDescriptor(
|
||
OriginalSecurityDescriptor,
|
||
&DaclPresent,
|
||
&Dacl,
|
||
&DaclDefaulted);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
if (DaclPresent &&
|
||
(Dacl != NULL) &&
|
||
MRxSmbAclHasExtraAces(Dacl)) {
|
||
|
||
ULONG i;
|
||
|
||
//
|
||
// Need to strip the extra ACEs off.
|
||
//
|
||
// First convert the SD to absolute.
|
||
//
|
||
|
||
Status = MRxSmbSelfRelativeToAbsoluteSD(
|
||
OriginalSecurityDescriptor,
|
||
&AbsoluteSd,
|
||
&Dacl,
|
||
&Sacl,
|
||
&Owner,
|
||
&Group);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Now modify the DACL. Each delete moves
|
||
// the other ACEs down, so we just delete
|
||
// ACE 0 as many times as needed.
|
||
//
|
||
|
||
for (i = 0; i < ExtraAceInfoCount; i++) {
|
||
|
||
Status = RtlDeleteAce(
|
||
Dacl,
|
||
0);
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the resulting Dacl has no ACEs, then remove it
|
||
// since a DACL with no ACEs implies no access.
|
||
//
|
||
|
||
if (Dacl->AceCount == 0) {
|
||
|
||
Status = RtlSetDaclSecurityDescriptor(
|
||
AbsoluteSd,
|
||
FALSE,
|
||
NULL,
|
||
FALSE);
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate and convert back to self-relative.
|
||
//
|
||
|
||
Status = MRxSmbAbsoluteToSelfRelativeSD(
|
||
AbsoluteSd,
|
||
NewSecurityDescriptor);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
*WereRemoved = TRUE;
|
||
|
||
}
|
||
|
||
CLEANUP:
|
||
|
||
if (AbsoluteSd != NULL) {
|
||
RxFreePool(AbsoluteSd);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status) && (*NewSecurityDescriptor != NULL)) {
|
||
RxFreePool(*NewSecurityDescriptor);
|
||
*NewSecurityDescriptor = NULL;
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbAddExtraAcesToSelfRelativeSD(
|
||
IN PSECURITY_DESCRIPTOR OriginalSecurityDescriptor,
|
||
IN BOOLEAN InheritableAces,
|
||
OUT PSECURITY_DESCRIPTOR * NewSecurityDescriptor
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes an existing self-relative security descriptor
|
||
and produces a new self-relative security descriptor with our
|
||
extra ACEs added.
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
Status - Result of the operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PSECURITY_DESCRIPTOR AbsoluteSd = NULL;
|
||
PSID Owner;
|
||
PSID Group;
|
||
PACL Dacl;
|
||
PACL Sacl;
|
||
PUCHAR NewAceList = NULL;
|
||
PACL NewDacl = NULL;
|
||
ULONG NewAceListSize;
|
||
ULONG NewDaclSize;
|
||
PACCESS_ALLOWED_ACE CurrentAce;
|
||
ULONG i;
|
||
|
||
*NewSecurityDescriptor = NULL;
|
||
|
||
//
|
||
// Allocate and convert the SD to absolute.
|
||
//
|
||
|
||
Status = MRxSmbSelfRelativeToAbsoluteSD(
|
||
OriginalSecurityDescriptor,
|
||
&AbsoluteSd,
|
||
&Dacl,
|
||
&Sacl,
|
||
&Owner,
|
||
&Group);
|
||
|
||
//
|
||
// If the SD is already absolute this call will have returned
|
||
// STATUS_BAD_DESCRIPTOR_FORMAT -- we don't expect that.
|
||
//
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// The server requires that the SD we pass to it has an owner -- so
|
||
// set one if there isn't one.
|
||
//
|
||
|
||
if (Owner == NULL) {
|
||
|
||
Status = RtlSetOwnerSecurityDescriptor(
|
||
AbsoluteSd,
|
||
MRxSmbRemoteBootMachineSid,
|
||
FALSE);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
}
|
||
|
||
//
|
||
// AbsoluteSd is now an absolute version of the passed-in
|
||
// security descriptor. We replace the DACL with our
|
||
// modified one.
|
||
//
|
||
|
||
//
|
||
// First create the ACEs we want to add to the ACL.
|
||
//
|
||
|
||
NewAceListSize = 0;
|
||
for (i = 0; i < ExtraAceInfoCount; i++) {
|
||
NewAceListSize += ExtraAceInfo[i].AceSize;
|
||
}
|
||
|
||
NewAceList = RxAllocatePoolWithTag(PagedPool, NewAceListSize, MRXSMB_REMOTEBOOT_POOLTAG);
|
||
if (NewAceList == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
CurrentAce = (PACCESS_ALLOWED_ACE)NewAceList;
|
||
|
||
for (i = 0; i < ExtraAceInfoCount; i++) {
|
||
CurrentAce->Header.AceType = ExtraAceInfo[i].AceType;
|
||
CurrentAce->Header.AceFlags = ExtraAceInfo[i].AceFlags;
|
||
if (InheritableAces) {
|
||
CurrentAce->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
|
||
}
|
||
CurrentAce->Header.AceSize = ExtraAceInfo[i].AceSize;
|
||
CurrentAce->Mask = ExtraAceInfo[i].Mask;
|
||
RtlCopyMemory(&CurrentAce->SidStart,
|
||
ExtraAceInfo[i].Sid,
|
||
ExtraAceInfo[i].AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart));
|
||
CurrentAce = (PACCESS_ALLOWED_ACE)(((PUCHAR)CurrentAce) + ExtraAceInfo[i].AceSize);
|
||
}
|
||
|
||
//
|
||
// Allocate the new DACL.
|
||
//
|
||
|
||
if (Dacl != NULL) {
|
||
NewDaclSize = Dacl->AclSize + NewAceListSize;
|
||
} else {
|
||
NewDaclSize = sizeof(ACL) + NewAceListSize;
|
||
}
|
||
|
||
NewDacl = RxAllocatePoolWithTag(NonPagedPool, NewDaclSize, MRXSMB_REMOTEBOOT_POOLTAG);
|
||
if (NewDacl == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
if (Dacl != NULL) {
|
||
RtlCopyMemory(NewDacl, Dacl, Dacl->AclSize);
|
||
NewDacl->AclSize = (USHORT)NewDaclSize;
|
||
} else {
|
||
Status = RtlCreateAcl(NewDacl, NewDaclSize, ACL_REVISION);
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Put our ACEs in the front.
|
||
//
|
||
|
||
Status = RtlAddAce(
|
||
NewDacl,
|
||
ACL_REVISION,
|
||
0, // StartingAceIndex
|
||
NewAceList,
|
||
NewAceListSize);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Replace the existing DACL with ours.
|
||
//
|
||
|
||
Status = RtlSetDaclSecurityDescriptor(
|
||
AbsoluteSd,
|
||
TRUE,
|
||
NewDacl,
|
||
FALSE);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Allocate and convert back to self-relative.
|
||
//
|
||
|
||
Status = MRxSmbAbsoluteToSelfRelativeSD(
|
||
AbsoluteSd,
|
||
NewSecurityDescriptor);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
CLEANUP:
|
||
|
||
//
|
||
// Free the temporary things we allocated.
|
||
//
|
||
|
||
if (AbsoluteSd != NULL) {
|
||
RxFreePool(AbsoluteSd);
|
||
}
|
||
|
||
if (NewAceList != NULL) {
|
||
RxFreePool(NewAceList);
|
||
}
|
||
|
||
if (NewDacl != NULL) {
|
||
RxFreePool(NewDacl);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status) && (*NewSecurityDescriptor != NULL)) {
|
||
RxFreePool(*NewSecurityDescriptor);
|
||
*NewSecurityDescriptor = NULL;
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbCreateExtraAcesSelfRelativeSD(
|
||
IN BOOLEAN InheritableAces,
|
||
OUT PSECURITY_DESCRIPTOR * NewSecurityDescriptor
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes an existing self-relative security descriptor
|
||
and produces a new self-relative security descriptor with our
|
||
extra ACEs added.
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
Status - Result of the operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PSECURITY_DESCRIPTOR AbsoluteSd = NULL;
|
||
PUCHAR NewAceList = NULL;
|
||
PACL NewDacl = NULL;
|
||
ULONG NewAceListSize;
|
||
ULONG NewDaclSize;
|
||
PACCESS_ALLOWED_ACE CurrentAce;
|
||
ULONG i;
|
||
|
||
AbsoluteSd = RxAllocatePoolWithTag(PagedPool, SECURITY_DESCRIPTOR_MIN_LENGTH, MRXSMB_REMOTEBOOT_POOLTAG);
|
||
|
||
if (AbsoluteSd == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
Status = RtlCreateSecurityDescriptor(
|
||
AbsoluteSd,
|
||
SECURITY_DESCRIPTOR_REVISION);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// First create the ACEs we want to add to the ACL.
|
||
//
|
||
|
||
NewAceListSize = 0;
|
||
for (i = 0; i < ExtraAceInfoCount; i++) {
|
||
NewAceListSize += ExtraAceInfo[i].AceSize;
|
||
}
|
||
|
||
NewAceList = RxAllocatePoolWithTag(PagedPool, NewAceListSize, MRXSMB_REMOTEBOOT_POOLTAG);
|
||
if (NewAceList == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
CurrentAce = (PACCESS_ALLOWED_ACE)NewAceList;
|
||
|
||
for (i = 0; i < ExtraAceInfoCount; i++) {
|
||
CurrentAce->Header.AceType = ExtraAceInfo[i].AceType;
|
||
CurrentAce->Header.AceFlags = ExtraAceInfo[i].AceFlags;
|
||
if (InheritableAces) {
|
||
CurrentAce->Header.AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
|
||
}
|
||
CurrentAce->Header.AceSize = ExtraAceInfo[i].AceSize;
|
||
CurrentAce->Mask = ExtraAceInfo[i].Mask;
|
||
RtlCopyMemory(&CurrentAce->SidStart,
|
||
ExtraAceInfo[i].Sid,
|
||
ExtraAceInfo[i].AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart));
|
||
CurrentAce = (PACCESS_ALLOWED_ACE)(((PUCHAR)CurrentAce) + ExtraAceInfo[i].AceSize);
|
||
}
|
||
|
||
//
|
||
// Allocate the new DACL.
|
||
//
|
||
|
||
NewDaclSize = sizeof(ACL) + NewAceListSize;
|
||
|
||
NewDacl = RxAllocatePoolWithTag(NonPagedPool, NewDaclSize, MRXSMB_REMOTEBOOT_POOLTAG);
|
||
if (NewDacl == NULL) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
RtlCreateAcl(NewDacl, NewDaclSize, ACL_REVISION);
|
||
|
||
//
|
||
// Put our ACEs in the front.
|
||
//
|
||
|
||
Status = RtlAddAce(
|
||
NewDacl,
|
||
ACL_REVISION,
|
||
0, // StartingAceIndex
|
||
NewAceList,
|
||
NewAceListSize);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Set the DACL on the SD.
|
||
//
|
||
|
||
Status = RtlSetDaclSecurityDescriptor(
|
||
AbsoluteSd,
|
||
TRUE,
|
||
NewDacl,
|
||
FALSE);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Set the owner on the SD.
|
||
//
|
||
|
||
Status = RtlSetOwnerSecurityDescriptor(
|
||
AbsoluteSd,
|
||
MRxSmbRemoteBootMachineSid,
|
||
FALSE);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Allocate and convert back to self-relative.
|
||
//
|
||
|
||
Status = MRxSmbAbsoluteToSelfRelativeSD(
|
||
AbsoluteSd,
|
||
NewSecurityDescriptor);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
CLEANUP:
|
||
|
||
if (AbsoluteSd != NULL) {
|
||
RxFreePool(AbsoluteSd);
|
||
}
|
||
|
||
if (NewAceList != NULL) {
|
||
RxFreePool(NewAceList);
|
||
}
|
||
|
||
if (NewDacl != NULL) {
|
||
RxFreePool(NewDacl);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status) && (*NewSecurityDescriptor != NULL)) {
|
||
RxFreePool(*NewSecurityDescriptor);
|
||
*NewSecurityDescriptor = NULL;
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
NTSTATUS
|
||
MRxSmbQuerySecurityInformation (
|
||
IN OUT PRX_CONTEXT RxContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the NtQuerySecurityFile api.
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
Status - Result of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
RxCaptureFcb;
|
||
RxCaptureFobx;
|
||
PVOID Buffer = RxContext->Info.Buffer;
|
||
PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen;
|
||
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
PSECURITY_DESCRIPTOR SelfRelativeSd;
|
||
BOOLEAN ConvertedAcl = FALSE;
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
NTSTATUS Status;
|
||
|
||
REQ_QUERY_SECURITY_DESCRIPTOR QuerySecurityRequest;
|
||
RESP_QUERY_SECURITY_DESCRIPTOR QuerySecurityResponse;
|
||
|
||
PBYTE pInputParamBuffer = NULL;
|
||
PBYTE pOutputParamBuffer = NULL;
|
||
PBYTE pInputDataBuffer = NULL;
|
||
PBYTE pOutputDataBuffer = NULL;
|
||
|
||
ULONG InputParamBufferLength = 0;
|
||
ULONG OutputParamBufferLength = 0;
|
||
ULONG InputDataBufferLength = 0;
|
||
ULONG OutputDataBufferLength = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbQuerySecurityInformation...\n"));
|
||
|
||
// Turn away this call from those servers which do not support the NT SMBs
|
||
|
||
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
||
|
||
if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
|
||
RxDbgTrace(-1, Dbg, ("QuerySecurityDescriptor not supported!\n"));
|
||
return((STATUS_NOT_SUPPORTED));
|
||
}
|
||
|
||
if (MRxSmbIsThisADisconnectedOpen(capFobx->pSrvOpen)) {
|
||
return STATUS_ONLY_IF_CONNECTED;
|
||
}
|
||
|
||
Status = MRxSmbDeferredCreate(RxContext);
|
||
if (Status!=STATUS_SUCCESS) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
smbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
|
||
|
||
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
SMB_TRANSACTION_OPTIONS TransactionOptions = RxDefaultTransactionOptions;
|
||
SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
|
||
//BOOLEAN printflag;
|
||
|
||
TransactionOptions.NtTransactFunction = NT_TRANSACT_QUERY_SECURITY_DESC;
|
||
//TransactionOptions.Flags |= SMB_XACT_FLAGS_COPY_ON_ERROR;
|
||
|
||
QuerySecurityRequest.Fid = smbSrvOpen->Fid;
|
||
QuerySecurityRequest.Reserved = 0;
|
||
QuerySecurityRequest.SecurityInformation = RxContext->QuerySecurity.SecurityInformation;
|
||
|
||
QuerySecurityResponse.LengthNeeded = 0xbaadbaad;
|
||
|
||
//printflag = RxDbgTraceDisableGlobally();//this is debug code anyway!
|
||
//RxDbgTraceEnableGlobally(FALSE);
|
||
|
||
Status = SmbCeTransact(
|
||
RxContext, // the RXContext for the transaction
|
||
&TransactionOptions, // transaction options
|
||
NULL, // the setup buffer
|
||
0, // input setup buffer length
|
||
NULL, // output setup buffer
|
||
0, // output setup buffer length
|
||
&QuerySecurityRequest, // Input Param Buffer
|
||
sizeof(QuerySecurityRequest), // Input param buffer length
|
||
&QuerySecurityResponse, // Output param buffer
|
||
sizeof(QuerySecurityResponse),// output param buffer length
|
||
NULL, // Input data buffer
|
||
0, // Input data buffer length
|
||
Buffer, // output data buffer
|
||
*pLengthRemaining, // output data buffer length
|
||
&ResumptionContext // the resumption context
|
||
);
|
||
|
||
//DbgPrint("QSR.len=%x\n", QuerySecurityResponse.LengthNeeded);
|
||
|
||
|
||
if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_TOO_SMALL)) {
|
||
ULONG ReturnedDataCount = ResumptionContext.DataBytesReceived;
|
||
|
||
RxContext->InformationToReturn = QuerySecurityResponse.LengthNeeded;
|
||
RxDbgTrace(0, Dbg, ("MRxSmbQuerySecurityInformation...ReturnedDataCount=%08lx\n",ReturnedDataCount));
|
||
ASSERT(ResumptionContext.ParameterBytesReceived == sizeof(RESP_QUERY_SECURITY_DESCRIPTOR));
|
||
|
||
if (((LONG)(QuerySecurityResponse.LengthNeeded)) > *pLengthRemaining) {
|
||
Status = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
if (MRxSmbBootedRemotely &&
|
||
MRxSmbRemoteBootDoMachineLogon) {
|
||
|
||
PSMBCE_SESSION pSession;
|
||
pSession = &SmbCeGetAssociatedVNetRootContext(
|
||
capFobx->pSrvOpen->pVNetRoot)->pSessionEntry->Session;
|
||
|
||
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
|
||
|
||
//
|
||
// if the user supplied a zero-length buffer, I.e. they were querying
|
||
// to see how big a buffer was needed, they will wind up with less
|
||
// data than expected because on the subsequent call with a real buffer,
|
||
// we may remove the extra ACEs.
|
||
//
|
||
|
||
if (NT_SUCCESS(Status) && (Buffer != NULL) && (ReturnedDataCount > 0)) {
|
||
|
||
BOOLEAN DaclPresent, DaclDefaulted;
|
||
|
||
// DbgPrint( ">>> Querying SD on %wZ\n", &capFcb->AlreadyPrefixedName);
|
||
|
||
//
|
||
// Remove any any ACEs in the DACL
|
||
// that SetSecurityInformation may have added.
|
||
//
|
||
|
||
Status = MRxSmbRemoveExtraAcesFromSelfRelativeSD(
|
||
(PSECURITY_DESCRIPTOR)Buffer,
|
||
&SelfRelativeSd,
|
||
&ConvertedAcl);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
if (ConvertedAcl) {
|
||
|
||
//
|
||
// Copy the new security descriptor and
|
||
// modify the data length.
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
Buffer,
|
||
SelfRelativeSd,
|
||
RtlLengthSecurityDescriptor(SelfRelativeSd));
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
}
|
||
|
||
//RxDbgTraceEnableGlobally(printflag);
|
||
}
|
||
|
||
|
||
FINALLY:
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
//
|
||
// If we modified the security descriptor for a remote boot server,
|
||
// clean it up.
|
||
//
|
||
|
||
if (ConvertedAcl) {
|
||
|
||
//
|
||
// Free the self-relative SD that was allocated.
|
||
//
|
||
|
||
if (SelfRelativeSd != NULL) {
|
||
RxFreePool(SelfRelativeSd);
|
||
}
|
||
}
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbQuerySecurityInformation...exit, st=%08lx,info=%08lx\n",
|
||
Status, RxContext->InformationToReturn));
|
||
return Status;
|
||
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbSetSecurityInformation (
|
||
IN OUT struct _RX_CONTEXT * RxContext
|
||
)
|
||
{
|
||
RxCaptureFcb;
|
||
RxCaptureFobx;
|
||
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen;
|
||
PSMBCEDB_SERVER_ENTRY pServerEntry;
|
||
|
||
NTSTATUS Status;
|
||
|
||
REQ_SET_SECURITY_DESCRIPTOR SetSecurityRequest;
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
PSECURITY_DESCRIPTOR OriginalSd;
|
||
PSECURITY_DESCRIPTOR SelfRelativeSd;
|
||
BOOLEAN DidRemoteBootProcessing = FALSE;
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbSetSecurityInformation...\n"));
|
||
|
||
pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
|
||
|
||
if (!FlagOn(pServerEntry->Server.DialectFlags,DF_NT_SMBS)) {
|
||
RxDbgTrace(-1, Dbg, ("Set Security Descriptor not supported!\n"));
|
||
|
||
return((STATUS_NOT_SUPPORTED));
|
||
|
||
} else if (MRxSmbIsThisADisconnectedOpen(capFobx->pSrvOpen)) {
|
||
|
||
return STATUS_ONLY_IF_CONNECTED;
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
} else if (MRxSmbBootedRemotely) {
|
||
|
||
PSMBCE_SESSION pSession;
|
||
pSession = &SmbCeGetAssociatedVNetRootContext(
|
||
capFobx->pSrvOpen->pVNetRoot)->pSessionEntry->Session;
|
||
|
||
if (FlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
|
||
|
||
TYPE_OF_OPEN TypeOfOpen = NodeType(capFcb);
|
||
|
||
//
|
||
// Set this so we know to call the CSC epilogue, and can clean
|
||
// up correctly.
|
||
//
|
||
|
||
DidRemoteBootProcessing = TRUE;
|
||
SelfRelativeSd = NULL;
|
||
|
||
// DbgPrint( ">>> setting SD on %wZ\n", &capFcb->AlreadyPrefixedName);
|
||
|
||
//
|
||
// First we need to set the security descriptor on the CSC
|
||
// version of the file, if one exists.
|
||
//
|
||
|
||
Status = MRxSmbCscSetSecurityPrologue(RxContext);
|
||
if (Status != STATUS_SUCCESS) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
if (MRxSmbRemoteBootDoMachineLogon) {
|
||
|
||
//
|
||
// Add our ACEs to the security descriptor. This returns the
|
||
// new security descriptor in SelfRelativeSd. If this is a
|
||
// directory we add inheritable ACEs.
|
||
//
|
||
|
||
Status = MRxSmbAddExtraAcesToSelfRelativeSD(
|
||
RxContext->SetSecurity.SecurityDescriptor,
|
||
(BOOLEAN)(TypeOfOpen == RDBSS_NTC_STORAGE_TYPE_DIRECTORY),
|
||
&SelfRelativeSd);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
//
|
||
// Now replace the original SD with the new one.
|
||
//
|
||
|
||
OriginalSd = RxContext->SetSecurity.SecurityDescriptor;
|
||
|
||
RxContext->SetSecurity.SecurityDescriptor = SelfRelativeSd;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If we logged on using the NULL session, then don't set ACLs
|
||
// on the server file. Jump to the end so that the CSC epilogue
|
||
// is called.
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
goto FINALLY;
|
||
|
||
}
|
||
}
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
}
|
||
|
||
Status = MRxSmbDeferredCreate(RxContext);
|
||
if (Status!=STATUS_SUCCESS) {
|
||
goto FINALLY;
|
||
}
|
||
|
||
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
smbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
|
||
|
||
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
SMB_TRANSACTION_OPTIONS TransactionOptions = RxDefaultTransactionOptions;
|
||
SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
|
||
ULONG SdLength = RtlLengthSecurityDescriptor(RxContext->SetSecurity.SecurityDescriptor);
|
||
|
||
TransactionOptions.NtTransactFunction = NT_TRANSACT_SET_SECURITY_DESC;
|
||
|
||
SetSecurityRequest.Fid = smbSrvOpen->Fid;
|
||
SetSecurityRequest.Reserved = 0;
|
||
SetSecurityRequest.SecurityInformation = RxContext->SetSecurity.SecurityInformation;
|
||
|
||
Status = SmbCeTransact(
|
||
RxContext, // the RXContext for the transaction
|
||
&TransactionOptions, // transaction options
|
||
NULL, // the input setup buffer
|
||
0, // input setup buffer length
|
||
NULL, // the output setup buffer
|
||
0, // output setup buffer length
|
||
&SetSecurityRequest, // Input Param Buffer
|
||
sizeof(SetSecurityRequest), // Input param buffer length
|
||
NULL, // Output param buffer
|
||
0, // output param buffer length
|
||
RxContext->SetSecurity.SecurityDescriptor, // Input data buffer
|
||
SdLength, // Input data buffer length
|
||
NULL, // output data buffer
|
||
0, // output data buffer length
|
||
&ResumptionContext // the resumption context
|
||
);
|
||
|
||
//the old rdr doesn't return any info...................
|
||
//RxContext->InformationToReturn = SetSecurityResponse.LengthNeeded;
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
ULONG ReturnedDataCount = ResumptionContext.DataBytesReceived;
|
||
|
||
RxDbgTrace(0, Dbg, ("MRxSmbSetSecurityInformation...ReturnedDataCount=%08lx\n",ReturnedDataCount));
|
||
ASSERT(ResumptionContext.ParameterBytesReceived == 0);
|
||
ASSERT(ResumptionContext.SetupBytesReceived == 0);
|
||
ASSERT(ResumptionContext.DataBytesReceived == 0);
|
||
}
|
||
}
|
||
|
||
|
||
FINALLY:
|
||
|
||
#if defined(REMOTE_BOOT)
|
||
//
|
||
// If we modified the security descriptor for a remote boot server,
|
||
// clean it up.
|
||
//
|
||
|
||
if (DidRemoteBootProcessing) {
|
||
|
||
if (SelfRelativeSd != NULL) {
|
||
|
||
RxFreePool(SelfRelativeSd);
|
||
|
||
//
|
||
// If we successfully allocated SelfRelativeSd then we
|
||
// also replaced the original passed-in SD, so we need
|
||
// to put the old SD back.
|
||
//
|
||
|
||
RxContext->SetSecurity.SecurityDescriptor = OriginalSd;
|
||
}
|
||
|
||
MRxSmbCscSetSecurityEpilogue(RxContext, &Status);
|
||
|
||
}
|
||
#endif // defined(REMOTE_BOOT)
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbSetSecurityInformation...exit, st=%08lx,info=%08lx\n",
|
||
Status, RxContext->InformationToReturn));
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MRxSmbLoadEaList(
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PUCHAR UserEaList,
|
||
IN ULONG UserEaListLength,
|
||
OUT PFEALIST *ServerEaList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the NtQueryEaFile api.
|
||
It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
IN PUCHAR UserEaList; - Supplies the Ea names required.
|
||
IN ULONG UserEaListLength;
|
||
|
||
OUT PFEALIST *ServerEaList - Eas returned by the server. Caller is responsible for
|
||
freeing memory.
|
||
|
||
Return Value:
|
||
|
||
Status - Result of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
RxCaptureFobx;
|
||
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen;
|
||
|
||
|
||
NTSTATUS Status;
|
||
USHORT Setup = TRANS2_QUERY_FILE_INFORMATION;
|
||
|
||
REQ_QUERY_FILE_INFORMATION QueryFileInfoRequest;
|
||
RESP_QUERY_FILE_INFORMATION QueryFileInfoResponse;
|
||
|
||
PBYTE pInputParamBuffer = NULL;
|
||
PBYTE pOutputParamBuffer = NULL;
|
||
PBYTE pInputDataBuffer = NULL;
|
||
PBYTE pOutputDataBuffer = NULL;
|
||
|
||
ULONG InputParamBufferLength = 0;
|
||
ULONG OutputParamBufferLength = 0;
|
||
ULONG InputDataBufferLength = 0;
|
||
ULONG OutputDataBufferLength = 0;
|
||
|
||
CLONG OutDataCount = EA_QUERY_SIZE;
|
||
|
||
CLONG OutSetupCount = 0;
|
||
|
||
PFEALIST Buffer;
|
||
|
||
PGEALIST ServerQueryEaList = NULL;
|
||
CLONG InDataCount;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbLoadEaList...\n"));
|
||
|
||
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
smbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
|
||
|
||
//
|
||
// Convert the supplied UserEaList to a GEALIST. The server will return just the Eas
|
||
// requested by the application.
|
||
//
|
||
//
|
||
// If the application specified a subset of EaNames then convert to OS/2 1.2 format and
|
||
// pass that to the server. ie. Use the server to filter out the names.
|
||
//
|
||
|
||
//CODE.IMPROVEMENT if write-cacheing is enabled, then we could find out the size once and save it. in
|
||
// this way we would at least avoid this everytime. the best way would be an NT-->NT api that
|
||
// implements this in a reasonable fashion. (we can only do the above optimization if it's a full
|
||
// query instead of a ealist!=NULL query.
|
||
|
||
Buffer = RxAllocatePool ( PagedPool, OutDataCount );
|
||
|
||
if ( Buffer == NULL ) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto FINALLY;
|
||
}
|
||
|
||
if ( UserEaList != NULL) {
|
||
|
||
//
|
||
// OS/2 format is always a little less than or equal to the NT UserEaList size.
|
||
// This code relies on the I/O system verifying the EaList is valid.
|
||
//
|
||
|
||
ServerQueryEaList = RxAllocatePool ( PagedPool, UserEaListLength );
|
||
if ( ServerQueryEaList == NULL ) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto FINALLY;
|
||
};
|
||
|
||
MRxSmbNtGeaListToOs2((PFILE_GET_EA_INFORMATION )UserEaList, UserEaListLength, ServerQueryEaList );
|
||
InDataCount = (CLONG)ServerQueryEaList->cbList;
|
||
|
||
} else {
|
||
InDataCount = 0;
|
||
}
|
||
|
||
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
|
||
SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
|
||
|
||
QueryFileInfoRequest.Fid = smbSrvOpen->Fid;
|
||
|
||
if ( UserEaList != NULL) {
|
||
QueryFileInfoRequest.InformationLevel = SMB_INFO_QUERY_EAS_FROM_LIST;
|
||
} else {
|
||
QueryFileInfoRequest.InformationLevel = SMB_INFO_QUERY_ALL_EAS;
|
||
}
|
||
|
||
// CODE.IMPROVEMENT it is unfortunate that this is defined so that a paramMDL cannot be passed
|
||
// perhaps it should be passed in the options!
|
||
Status = SmbCeTransact(
|
||
RxContext, // the RXContext for the transaction
|
||
pTransactionOptions, // transaction options
|
||
&Setup, // the setup buffer
|
||
sizeof(Setup), // setup buffer length
|
||
NULL, // the output setup buffer
|
||
0, // output setup buffer length
|
||
&QueryFileInfoRequest, // Input Param Buffer
|
||
sizeof(QueryFileInfoRequest), // Input param buffer length
|
||
&QueryFileInfoResponse, // Output param buffer
|
||
sizeof(QueryFileInfoResponse),// output param buffer length
|
||
ServerQueryEaList, // Input data buffer
|
||
InDataCount, // Input data buffer length
|
||
Buffer, // output data buffer
|
||
OutDataCount, // output data buffer length
|
||
&ResumptionContext // the resumption context
|
||
);
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
ULONG ReturnedDataCount = ResumptionContext.DataBytesReceived;
|
||
|
||
RxDbgTrace(0, Dbg, ("MRxSmbLoadEaList...ReturnedDataCount=%08lx\n",ReturnedDataCount));
|
||
ASSERT(ResumptionContext.ParameterBytesReceived == sizeof(RESP_QUERY_FILE_INFORMATION));
|
||
|
||
if ( SmbGetUlong( &((PFEALIST)Buffer)->cbList) != ReturnedDataCount ){
|
||
Status = STATUS_EA_CORRUPT_ERROR;
|
||
}
|
||
|
||
if ( ReturnedDataCount == 0 ) {
|
||
Status = STATUS_NO_EAS_ON_FILE;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
FINALLY:
|
||
if ( NT_SUCCESS(Status) ) {
|
||
*ServerEaList = Buffer;
|
||
} else {
|
||
if (Buffer != NULL) {
|
||
RxFreePool(Buffer);
|
||
}
|
||
}
|
||
|
||
if ( ServerQueryEaList != NULL) {
|
||
RxFreePool(ServerQueryEaList);
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbLoadEaList...exit, st=%08lx\n",Status));
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
MRxSmbNtGeaListToOs2 (
|
||
IN PFILE_GET_EA_INFORMATION NtGetEaList,
|
||
IN ULONG GeaListLength,
|
||
IN PGEALIST GeaList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts a single NT GET EA list to OS/2 GEALIST style. The GEALIST
|
||
need not have any particular alignment.
|
||
|
||
Arguments:
|
||
|
||
NtGetEaList - An NT style get EA list to be converted to OS/2 format.
|
||
|
||
GeaListLength - the maximum possible length of the GeaList.
|
||
|
||
GeaList - Where to place the OS/2 1.2 style GEALIST.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
{
|
||
|
||
PGEA gea = GeaList->list;
|
||
|
||
PFILE_GET_EA_INFORMATION ntGetEa = NtGetEaList;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Copy the Eas up until the last one
|
||
//
|
||
|
||
while ( ntGetEa->NextEntryOffset != 0 ) {
|
||
//
|
||
// Copy the NT format EA to OS/2 1.2 format and set the gea
|
||
// pointer for the next iteration.
|
||
//
|
||
|
||
gea = MRxSmbNtGetEaToOs2( gea, ntGetEa );
|
||
|
||
ASSERT( (ULONG_PTR)gea <= (ULONG_PTR)GeaList + GeaListLength );
|
||
|
||
ntGetEa = (PFILE_GET_EA_INFORMATION)((PCHAR)ntGetEa + ntGetEa->NextEntryOffset);
|
||
}
|
||
|
||
// Now copy the last entry.
|
||
|
||
gea = MRxSmbNtGetEaToOs2( gea, ntGetEa );
|
||
|
||
ASSERT( (ULONG_PTR)gea <= (ULONG_PTR)GeaList + GeaListLength );
|
||
|
||
|
||
|
||
//
|
||
// Set the number of bytes in the GEALIST.
|
||
//
|
||
|
||
SmbPutUlong(
|
||
&GeaList->cbList,
|
||
(ULONG)((PCHAR)gea - (PCHAR)GeaList)
|
||
);
|
||
|
||
UNREFERENCED_PARAMETER( GeaListLength );
|
||
}
|
||
|
||
|
||
PGEA
|
||
MRxSmbNtGetEaToOs2 (
|
||
OUT PGEA Gea,
|
||
IN PFILE_GET_EA_INFORMATION NtGetEa
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts a single NT Get EA entry to OS/2 GEA style. The GEA need not have
|
||
any particular alignment. This routine makes no checks on buffer
|
||
overrunning--this is the responsibility of the calling routine.
|
||
|
||
Arguments:
|
||
|
||
Gea - a pointer to the location where the OS/2 GEA is to be written.
|
||
|
||
NtGetEa - a pointer to the NT Get EA.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the location after the last byte written.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCHAR ptr;
|
||
|
||
PAGED_CODE();
|
||
|
||
Gea->cbName = NtGetEa->EaNameLength;
|
||
|
||
ptr = (PCHAR)(Gea) + 1;
|
||
RtlCopyMemory( ptr, NtGetEa->EaName, NtGetEa->EaNameLength );
|
||
|
||
ptr += NtGetEa->EaNameLength;
|
||
*ptr++ = '\0';
|
||
|
||
return ( (PGEA)ptr );
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MRxSmbQueryEasFromServer(
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PFEALIST ServerEaList,
|
||
IN PVOID Buffer,
|
||
IN OUT PULONG BufferLengthRemaining,
|
||
IN BOOLEAN ReturnSingleEntry,
|
||
IN BOOLEAN UserEaListSupplied
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies the required number of Eas from the ServerEaList
|
||
starting from the offset indicated in the Icb. The Icb is also updated
|
||
to show the last Ea returned.
|
||
|
||
Arguments:
|
||
|
||
IN PFEALIST ServerEaList - Supplies the Ea List in OS/2 format.
|
||
IN PVOID Buffer - Supplies where to put the NT format EAs
|
||
IN OUT PULONG BufferLengthRemaining - Supplies the user buffer space.
|
||
IN BOOLEAN ReturnSingleEntry
|
||
IN BOOLEAN UserEaListSupplied - ServerEaList is a subset of the Eas
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The status for the Irp.
|
||
|
||
--*/
|
||
|
||
{
|
||
RxCaptureFobx;
|
||
ULONG EaIndex = capFobx->OffsetOfNextEaToReturn;
|
||
ULONG Index = 1;
|
||
ULONG Size;
|
||
ULONG OriginalLengthRemaining = *BufferLengthRemaining;
|
||
BOOLEAN Overflow = FALSE;
|
||
PFEA LastFeaStartLocation;
|
||
PFEA Fea = NULL;
|
||
PFEA LastFea = NULL;
|
||
PFILE_FULL_EA_INFORMATION NtFullEa = Buffer;
|
||
PFILE_FULL_EA_INFORMATION LastNtFullEa = Buffer;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(0, Dbg, ("MRxSmbQueryEasFromServer...EaIndex/Buffer/Remaining=%08lx/%08lx/%08lx\n",
|
||
EaIndex,Buffer,((BufferLengthRemaining)?*BufferLengthRemaining:0xbadbad)
|
||
));
|
||
|
||
//
|
||
// If there are no Ea's present in the list, return the appropriate
|
||
// error.
|
||
//
|
||
// Os/2 servers indicate that a list is null if cbList==4.
|
||
//
|
||
|
||
if ( SmbGetUlong(&ServerEaList->cbList) == FIELD_OFFSET(FEALIST, list) ) {
|
||
return STATUS_NO_EAS_ON_FILE;
|
||
}
|
||
|
||
//
|
||
// Find the last location at which an FEA can start.
|
||
//
|
||
|
||
LastFeaStartLocation = (PFEA)( (PCHAR)ServerEaList +
|
||
SmbGetUlong( &ServerEaList->cbList ) -
|
||
sizeof(FEA) - 1 );
|
||
|
||
//
|
||
// Go through the ServerEaList until we find the entry corresponding to EaIndex
|
||
//
|
||
|
||
for ( Fea = ServerEaList->list;
|
||
(Fea <= LastFeaStartLocation) && (Index < EaIndex);
|
||
Index+= 1,
|
||
Fea = (PFEA)( (PCHAR)Fea + sizeof(FEA) +
|
||
Fea->cbName + 1 + SmbGetUshort( &Fea->cbValue ) ) ) {
|
||
NOTHING;
|
||
}
|
||
|
||
if ( Index != EaIndex ) {
|
||
|
||
if ( Index == EaIndex+1 ) {
|
||
return STATUS_NO_MORE_EAS;
|
||
}
|
||
|
||
//
|
||
// No such index
|
||
//
|
||
|
||
return STATUS_NONEXISTENT_EA_ENTRY;
|
||
}
|
||
|
||
//
|
||
// Go through the rest of the FEA list, converting from OS/2 1.2 format to NT
|
||
// until we pass the last possible location in which an FEA can start.
|
||
//
|
||
|
||
for ( ;
|
||
Fea <= LastFeaStartLocation;
|
||
Fea = (PFEA)( (PCHAR)Fea + sizeof(FEA) +
|
||
Fea->cbName + 1 + SmbGetUshort( &Fea->cbValue ) ) ) {
|
||
|
||
PCHAR ptr;
|
||
|
||
//
|
||
// Calculate the size of this Fea when converted to an NT EA structure.
|
||
//
|
||
// The last field shouldn't be padded.
|
||
//
|
||
|
||
if ((PFEA)((PCHAR)Fea+sizeof(FEA)+Fea->cbName+1+SmbGetUshort(&Fea->cbValue)) < LastFeaStartLocation) {
|
||
Size = SmbGetNtSizeOfFea( Fea );
|
||
} else {
|
||
Size = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
|
||
Fea->cbName + 1 + SmbGetUshort(&Fea->cbValue);
|
||
}
|
||
|
||
//
|
||
// Will the next Ea fit?
|
||
//
|
||
|
||
if ( *BufferLengthRemaining < Size ) {
|
||
|
||
if ( LastNtFullEa != NtFullEa ) {
|
||
|
||
if ( UserEaListSupplied == TRUE ) {
|
||
*BufferLengthRemaining = OriginalLengthRemaining;
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
Overflow = TRUE;
|
||
|
||
break;
|
||
|
||
} else {
|
||
|
||
// Not even room for a single EA!
|
||
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
} else {
|
||
*BufferLengthRemaining -= Size;
|
||
}
|
||
|
||
//
|
||
// We are comitted to copy the Os2 Fea to Nt format in the users buffer
|
||
//
|
||
|
||
LastNtFullEa = NtFullEa;
|
||
LastFea = Fea;
|
||
EaIndex++;
|
||
|
||
// Create new Nt Ea
|
||
|
||
NtFullEa->Flags = Fea->fEA;
|
||
NtFullEa->EaNameLength = Fea->cbName;
|
||
NtFullEa->EaValueLength = SmbGetUshort( &Fea->cbValue );
|
||
|
||
ptr = NtFullEa->EaName;
|
||
RtlCopyMemory( ptr, (PCHAR)(Fea+1), Fea->cbName );
|
||
|
||
ptr += NtFullEa->EaNameLength;
|
||
*ptr++ = '\0';
|
||
|
||
//
|
||
// Copy the EA value to the NT full EA.
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
ptr,
|
||
(PCHAR)(Fea+1) + NtFullEa->EaNameLength + 1,
|
||
NtFullEa->EaValueLength
|
||
);
|
||
|
||
ptr += NtFullEa->EaValueLength;
|
||
|
||
//
|
||
// Longword-align ptr to determine the offset to the next location
|
||
// for an NT full EA.
|
||
//
|
||
|
||
ptr = (PCHAR)( ((ULONG_PTR)ptr + 3) & ~3 );
|
||
|
||
NtFullEa->NextEntryOffset = (ULONG)( ptr - (PCHAR)NtFullEa );
|
||
|
||
NtFullEa = (PFILE_FULL_EA_INFORMATION)ptr;
|
||
|
||
if ( ReturnSingleEntry == TRUE ) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set the NextEntryOffset field of the last full EA to 0 to indicate
|
||
// the end of the list.
|
||
//
|
||
|
||
LastNtFullEa->NextEntryOffset = 0;
|
||
|
||
//
|
||
// Record position the default start position for the next query
|
||
//
|
||
|
||
capFobx->OffsetOfNextEaToReturn = EaIndex;
|
||
|
||
if ( Overflow == FALSE ) {
|
||
return STATUS_SUCCESS;
|
||
} else {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
ULONG
|
||
MRxSmbNtFullEaSizeToOs2 (
|
||
IN PFILE_FULL_EA_INFORMATION NtFullEa
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get the number of bytes that would be required to represent the
|
||
NT full EA list in OS/2 1.2 style. This routine assumes that
|
||
at least one EA is present in the buffer.
|
||
|
||
Arguments:
|
||
|
||
NtFullEa - a pointer to the list of NT EAs.
|
||
|
||
Return Value:
|
||
|
||
ULONG - number of bytes required to hold the EAs in OS/2 1.2 format.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG size;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Walk through the EAs, adding up the total size required to
|
||
// hold them in OS/2 format.
|
||
//
|
||
|
||
for ( size = FIELD_OFFSET(FEALIST, list[0]);
|
||
NtFullEa->NextEntryOffset != 0;
|
||
NtFullEa = (PFILE_FULL_EA_INFORMATION)(
|
||
(PCHAR)NtFullEa + NtFullEa->NextEntryOffset ) ) {
|
||
|
||
size += SmbGetOs2SizeOfNtFullEa( NtFullEa );
|
||
}
|
||
|
||
size += SmbGetOs2SizeOfNtFullEa( NtFullEa );
|
||
|
||
return size;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
MRxSmbNtFullListToOs2 (
|
||
IN PFILE_FULL_EA_INFORMATION NtEaList,
|
||
IN PFEALIST FeaList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts a single NT FULL EA list to OS/2 FEALIST style. The FEALIST
|
||
need not have any particular alignment.
|
||
|
||
It is the callers responsibility to ensure that FeaList is large enough.
|
||
|
||
Arguments:
|
||
|
||
NtEaList - An NT style get EA list to be converted to OS/2 format.
|
||
|
||
FeaList - Where to place the OS/2 1.2 style FEALIST.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
{
|
||
|
||
PFEA fea = FeaList->list;
|
||
|
||
PFILE_FULL_EA_INFORMATION ntFullEa = NtEaList;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Copy the Eas up until the last one
|
||
//
|
||
|
||
while ( ntFullEa->NextEntryOffset != 0 ) {
|
||
//
|
||
// Copy the NT format EA to OS/2 1.2 format and set the fea
|
||
// pointer for the next iteration.
|
||
//
|
||
|
||
fea = MRxSmbNtFullEaToOs2( fea, ntFullEa );
|
||
|
||
ntFullEa = (PFILE_FULL_EA_INFORMATION)((PCHAR)ntFullEa + ntFullEa->NextEntryOffset);
|
||
}
|
||
|
||
// Now copy the last entry.
|
||
|
||
fea = MRxSmbNtFullEaToOs2( fea, ntFullEa );
|
||
|
||
|
||
//
|
||
// Set the number of bytes in the FEALIST.
|
||
//
|
||
|
||
SmbPutUlong(
|
||
&FeaList->cbList,
|
||
(ULONG)((PCHAR)fea - (PCHAR)FeaList)
|
||
);
|
||
|
||
}
|
||
|
||
|
||
PVOID
|
||
MRxSmbNtFullEaToOs2 (
|
||
OUT PFEA Fea,
|
||
IN PFILE_FULL_EA_INFORMATION NtFullEa
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts a single NT full EA to OS/2 FEA style. The FEA need not have
|
||
any particular alignment. This routine makes no checks on buffer
|
||
overrunning--this is the responsibility of the calling routine.
|
||
|
||
Arguments:
|
||
|
||
Fea - a pointer to the location where the OS/2 FEA is to be written.
|
||
|
||
NtFullEa - a pointer to the NT full EA.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the location after the last byte written.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCHAR ptr;
|
||
|
||
PAGED_CODE();
|
||
|
||
Fea->fEA = (UCHAR)NtFullEa->Flags;
|
||
Fea->cbName = NtFullEa->EaNameLength;
|
||
SmbPutUshort( &Fea->cbValue, NtFullEa->EaValueLength );
|
||
|
||
ptr = (PCHAR)(Fea + 1);
|
||
RtlCopyMemory( ptr, NtFullEa->EaName, NtFullEa->EaNameLength );
|
||
|
||
ptr += NtFullEa->EaNameLength;
|
||
*ptr++ = '\0';
|
||
|
||
RtlCopyMemory(
|
||
ptr,
|
||
NtFullEa->EaName + NtFullEa->EaNameLength + 1,
|
||
NtFullEa->EaValueLength
|
||
);
|
||
|
||
return (ptr + NtFullEa->EaValueLength);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
MRxSmbSetEaList(
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PFEALIST ServerEaList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the NtQueryEaFile api.
|
||
It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PFEALIST ServerEaList - Eas to be sent to the server.
|
||
|
||
Return Value:
|
||
|
||
Status - Result of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
RxCaptureFobx;
|
||
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen;
|
||
|
||
|
||
NTSTATUS Status;
|
||
USHORT Setup = TRANS2_SET_FILE_INFORMATION;
|
||
|
||
REQ_SET_FILE_INFORMATION SetFileInfoRequest;
|
||
RESP_SET_FILE_INFORMATION SetFileInfoResponse;
|
||
|
||
PBYTE pInputParamBuffer = NULL;
|
||
PBYTE pOutputParamBuffer = NULL;
|
||
PBYTE pInputDataBuffer = NULL;
|
||
PBYTE pOutputDataBuffer = NULL;
|
||
|
||
ULONG InputParamBufferLength = 0;
|
||
ULONG OutputParamBufferLength = 0;
|
||
ULONG InputDataBufferLength = 0;
|
||
ULONG OutputDataBufferLength = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbSetEaList...\n"));
|
||
|
||
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
||
SetFileInfoResponse.EaErrorOffset = 0;
|
||
|
||
smbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
|
||
|
||
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
PSMB_TRANSACTION_OPTIONS pTransactionOptions = &RxDefaultTransactionOptions;
|
||
SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
|
||
|
||
//RxDbgTrace( 0, Dbg, ("MRxSmbNamedPipeFsControl: TransactionName %ws Length %ld\n",
|
||
// TransactionName.Buffer,TransactionName.Length));
|
||
|
||
SetFileInfoRequest.Fid = smbSrvOpen->Fid;
|
||
SetFileInfoRequest.InformationLevel = SMB_INFO_SET_EAS;
|
||
SetFileInfoRequest.Flags = 0;
|
||
|
||
// CODE.IMPROVEMENT it is unfortunate that this is defined so that a dataMDL cannot be passed
|
||
// perhaps it should be passed in the options!
|
||
Status = SmbCeTransact(
|
||
RxContext, // the RXContext for the transaction
|
||
pTransactionOptions, // transaction options
|
||
&Setup, // the setup buffer
|
||
sizeof(Setup), // setup buffer length
|
||
NULL, // the output setup buffer
|
||
0, // output setup buffer length
|
||
&SetFileInfoRequest, // Input Param Buffer
|
||
sizeof(SetFileInfoRequest), // Input param buffer length
|
||
&SetFileInfoResponse, // Output param buffer
|
||
sizeof(SetFileInfoResponse), // output param buffer length
|
||
ServerEaList, // Input data buffer
|
||
SmbGetUlong(&ServerEaList->cbList), // Input data buffer length
|
||
NULL, // output data buffer
|
||
0, // output data buffer length
|
||
&ResumptionContext // the resumption context
|
||
);
|
||
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
USHORT EaErrorOffset = SetFileInfoResponse.EaErrorOffset;
|
||
RxDbgTrace( 0, Dbg, ("MRxSmbSetEaList: Failed .. returning %lx/%lx\n",Status,EaErrorOffset));
|
||
RxContext->InformationToReturn = (EaErrorOffset);
|
||
}
|
||
else
|
||
{
|
||
// succeeded in setting EAs, reset this flag so that when this
|
||
// srvopen is used again for getting the EAs we will succeed
|
||
smbSrvOpen->FileStatusFlags &= ~SMB_FSF_NO_EAS;
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbSetEaList...exit\n"));
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbQueryQuotaInformation(
|
||
IN OUT PRX_CONTEXT RxContext)
|
||
{
|
||
RxCaptureFobx;
|
||
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen;
|
||
|
||
NTSTATUS Status;
|
||
USHORT Setup = NT_TRANSACT_QUERY_QUOTA;
|
||
|
||
PSID StartSid;
|
||
ULONG StartSidLength;
|
||
|
||
REQ_NT_QUERY_FS_QUOTA_INFO QueryQuotaInfoRequest;
|
||
RESP_NT_QUERY_FS_QUOTA_INFO QueryQuotaInfoResponse;
|
||
|
||
PBYTE pInputParamBuffer = NULL;
|
||
PBYTE pOutputParamBuffer = NULL;
|
||
PBYTE pInputDataBuffer = NULL;
|
||
PBYTE pOutputDataBuffer = NULL;
|
||
|
||
ULONG InputParamBufferLength = 0;
|
||
ULONG OutputParamBufferLength = 0;
|
||
ULONG InputDataBufferLength = 0;
|
||
ULONG OutputDataBufferLength = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbQueryQuotaInformation...\n"));
|
||
|
||
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
if (capFobx != NULL) {
|
||
smbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
|
||
}
|
||
|
||
if ((capFobx == NULL) ||
|
||
(smbSrvOpen == NULL)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
|
||
StartSid = RxContext->QueryQuota.StartSid;
|
||
|
||
if (StartSid != NULL) {
|
||
StartSidLength = RtlLengthRequiredSid(((PISID)StartSid)->SubAuthorityCount);
|
||
} else {
|
||
StartSidLength = 0;
|
||
}
|
||
|
||
QueryQuotaInfoRequest.Fid = smbSrvOpen->Fid;
|
||
|
||
QueryQuotaInfoRequest.ReturnSingleEntry = RxContext->QueryQuota.ReturnSingleEntry;
|
||
QueryQuotaInfoRequest.RestartScan = RxContext->QueryQuota.RestartScan;
|
||
|
||
QueryQuotaInfoRequest.SidListLength = RxContext->QueryQuota.SidListLength;
|
||
QueryQuotaInfoRequest.StartSidOffset = ROUND_UP_COUNT(
|
||
RxContext->QueryQuota.SidListLength,
|
||
sizeof(ULONG));
|
||
QueryQuotaInfoRequest.StartSidLength = StartSidLength;
|
||
|
||
|
||
// The input data buffer to be supplied to the server consists of two pieces
|
||
// of information the start sid and the sid list. Currently the I/O
|
||
// subsystem allocates them in contigous memory. In such cases we avoid
|
||
// another allocation by reusing the same buffer. If this condition is
|
||
// not satisfied we allocate a buffer large enough for both the
|
||
// components and copy them over.
|
||
|
||
InputDataBufferLength = ROUND_UP_COUNT(
|
||
RxContext->QueryQuota.SidListLength,
|
||
sizeof(ULONG)) +
|
||
StartSidLength;
|
||
|
||
QueryQuotaInfoRequest.StartSidLength = StartSidLength;
|
||
|
||
if (((PBYTE)RxContext->QueryQuota.SidList +
|
||
ROUND_UP_COUNT(RxContext->QueryQuota.SidListLength,sizeof(ULONG))) !=
|
||
RxContext->QueryQuota.StartSid) {
|
||
pInputDataBuffer = RxAllocatePoolWithTag(
|
||
PagedPool,
|
||
InputDataBufferLength,
|
||
MRXSMB_MISC_POOLTAG);
|
||
|
||
if (pInputDataBuffer != NULL) {
|
||
RtlCopyMemory(
|
||
pInputDataBuffer ,
|
||
RxContext->QueryQuota.SidList,
|
||
RxContext->QueryQuota.SidListLength);
|
||
|
||
RtlCopyMemory(
|
||
pInputDataBuffer + QueryQuotaInfoRequest.StartSidOffset,
|
||
StartSid,
|
||
StartSidLength);
|
||
} else {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
} else {
|
||
pInputDataBuffer = (PBYTE)RxContext->QueryQuota.SidList;
|
||
}
|
||
|
||
|
||
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
SMB_TRANSACTION_OPTIONS TransactionOptions = RxDefaultTransactionOptions;
|
||
SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
|
||
|
||
TransactionOptions.NtTransactFunction = NT_TRANSACT_QUERY_QUOTA;
|
||
|
||
pOutputDataBuffer = RxContext->Info.Buffer;
|
||
OutputDataBufferLength = RxContext->Info.LengthRemaining;
|
||
|
||
Status = SmbCeTransact(
|
||
RxContext, // the RXContext for the transaction
|
||
&TransactionOptions, // transaction options
|
||
&Setup, // the setup buffer
|
||
sizeof(Setup), // setup buffer length
|
||
NULL, // the output setup buffer
|
||
0, // output setup buffer length
|
||
&QueryQuotaInfoRequest, // Input Param Buffer
|
||
sizeof(QueryQuotaInfoRequest), // Input param buffer length
|
||
&QueryQuotaInfoResponse, // Output param buffer
|
||
sizeof(QueryQuotaInfoResponse), // output param buffer length
|
||
pInputDataBuffer, // Input data buffer
|
||
InputDataBufferLength, // Input data buffer length
|
||
pOutputDataBuffer, // output data buffer
|
||
OutputDataBufferLength, // output data buffer length
|
||
&ResumptionContext // the resumption context
|
||
);
|
||
}
|
||
|
||
if ((pInputDataBuffer != NULL) &&
|
||
(pInputDataBuffer != (PBYTE)RxContext->QueryQuota.SidList)) {
|
||
RxFreePool(pInputDataBuffer);
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
RxContext->InformationToReturn = 0;
|
||
} else {
|
||
RxContext->InformationToReturn = QueryQuotaInfoResponse.Length;
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbQueryQuotaInformation...exit\n"));
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
MRxSmbSetQuotaInformation(
|
||
IN OUT PRX_CONTEXT RxContext)
|
||
{
|
||
|
||
RxCaptureFobx;
|
||
|
||
PMRX_SMB_SRV_OPEN smbSrvOpen;
|
||
|
||
NTSTATUS Status;
|
||
USHORT Setup = NT_TRANSACT_SET_QUOTA;
|
||
|
||
REQ_NT_SET_FS_QUOTA_INFO SetQuotaInfoRequest;
|
||
|
||
PBYTE pInputParamBuffer = NULL;
|
||
PBYTE pOutputParamBuffer = NULL;
|
||
PBYTE pInputDataBuffer = NULL;
|
||
PBYTE pOutputDataBuffer = NULL;
|
||
|
||
ULONG InputParamBufferLength = 0;
|
||
ULONG OutputParamBufferLength = 0;
|
||
ULONG InputDataBufferLength = 0;
|
||
ULONG OutputDataBufferLength = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxSmbSetQuotaInformation...\n"));
|
||
|
||
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
if (capFobx != NULL) {
|
||
smbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
|
||
}
|
||
|
||
if ((capFobx == NULL) ||
|
||
(smbSrvOpen == NULL)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
|
||
SMB_TRANSACTION_OPTIONS TransactionOptions = RxDefaultTransactionOptions;
|
||
SMB_TRANSACTION_RESUMPTION_CONTEXT ResumptionContext;
|
||
|
||
TransactionOptions.NtTransactFunction = NT_TRANSACT_SET_QUOTA;
|
||
|
||
SetQuotaInfoRequest.Fid = smbSrvOpen->Fid;
|
||
|
||
pInputDataBuffer = RxContext->Info.Buffer;
|
||
InputDataBufferLength = RxContext->Info.LengthRemaining;
|
||
|
||
Status = SmbCeTransact(
|
||
RxContext, // the RXContext for the transaction
|
||
&TransactionOptions, // transaction options
|
||
&Setup, // the setup buffer
|
||
sizeof(Setup), // setup buffer length
|
||
NULL, // the output setup buffer
|
||
0, // output setup buffer length
|
||
&SetQuotaInfoRequest, // Input Param Buffer
|
||
sizeof(SetQuotaInfoRequest), // Input param buffer length
|
||
pOutputParamBuffer, // Output param buffer
|
||
OutputParamBufferLength, // output param buffer length
|
||
pInputDataBuffer, // Input data buffer
|
||
InputDataBufferLength, // Input data buffer length
|
||
pOutputDataBuffer, // output data buffer
|
||
OutputDataBufferLength, // output data buffer length
|
||
&ResumptionContext // the resumption context
|
||
);
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxSmbSetQuotaInformation...exit\n"));
|
||
|
||
return Status;
|
||
}
|