4274 lines
107 KiB
C
4274 lines
107 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
attr.c
|
||
|
||
Abstract:
|
||
|
||
This file contains services that manipulate SAM object attributes.
|
||
|
||
|
||
WARNING: Terminology can sometimes be confusing. SAM objects have
|
||
attributes (e.g., users have LogonHours, FullName, AcctName,
|
||
et cetera). These attributes are stored in the registry
|
||
in registry-key-attributes. There is NOT a one-to-one
|
||
correllation between object-attributes and registry-key-
|
||
attributes. For example, all the fixed-length attributes
|
||
of an object are stored in a single registry-key-attribute
|
||
(whose name is pointed to by SampFixedAttributeName).
|
||
|
||
|
||
Author:
|
||
|
||
Jim Kelly (JimK) 26-June-1992
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
|
||
/*
|
||
|
||
Each SAM object-type has an Object-type descriptor. This is in a
|
||
data structure called SAMP_OBJECT_INFORMATION. This structure
|
||
contains information that applies to all instances of that object
|
||
type. This includes things like a mask of write operations for
|
||
the object type, and a name for the object type to be used in
|
||
auditing.
|
||
|
||
Each instance of an open SAM object has another data structure
|
||
used to identify it (called SAMP_OBJECT). The header of this
|
||
structure contains information that is common to all object-types
|
||
and is there to allow unified object manipulation. This includes
|
||
things like the handle to the object's registry key.
|
||
|
||
There are fields in each of these structures that are there to
|
||
allow generic object-attribute support routines to operate. In
|
||
SAMP_OBJECT, there is a pointer to a block of allocated memory
|
||
housing a copy of the object's attributes as they are stored on-disk.
|
||
These attributes are arbitrarily divided into two groups: fixed-length
|
||
and variable-length.
|
||
|
||
One of the fields in SAMP_OBJECT_INFORMATION indicates whether the
|
||
fixed-length and variable-length attributes for that object-type
|
||
are stored together in a single registry-key-attribute or separately
|
||
in two registry-key-attributes.
|
||
|
||
|
||
The registry api for querying and setting registry-key attributes are
|
||
rather peculiar in that they require the I/O buffer to include a
|
||
description of the data. Even the simplest data structure for reading
|
||
attribute values (KEY_VALUE_PARTIAL_INFORMATION) includes 3 ULONGs
|
||
before the actual data (TitleIndex, value Type, data length,
|
||
and then, finally, the data). To efficiently perform registry i/o,
|
||
the in-memory copy of the on-disk object attributes includes room
|
||
for this information preceeding the fixed and variable-length attribute
|
||
sections of the data.
|
||
|
||
|
||
NOTE: For object classes that store fixed and variable-length
|
||
data together, only the KEY_VALUE_PARTIAL_INFORMATION
|
||
structure preceeding the fixed-length attributes is used.
|
||
The one preceeding the variable-length attributes is
|
||
#ifdef'd out.
|
||
|
||
|
||
The structures related to object-attributes look like:
|
||
|
||
|
||
On-Disk Image
|
||
+-------------+ SAMP_OBJECT_INFORMATION
|
||
+-->|KEY_VALUE_ | +-----------------------+
|
||
SAMP_OBJECT | |PARTIAL_ | | |
|
||
+-----------+ | |INFORMATION | | (header) |
|
||
| | | |-------------| | |
|
||
| (header) | | | Fixed-Length|<-----+ | |
|
||
| | | | Attributes | | |-----------------------|
|
||
|-----------| | | | +-------|-< FixedAttrsOffset |
|
||
| OnDisk >-|--+ |-------------+ |-----------------------|
|
||
|-----------| |KEY_VALUE_ |<-------------|-< VariableBuffOffset |
|
||
| OnDisk | |PARTIAL_ | |-----------------------|
|
||
| Control | |INFORMATION | +-------|-< VariableArrayOffset |
|
||
| Flags | |(Optional) | | |-----------------------|
|
||
|-----------| |-------------| | +----|-< VariableDataOffset |
|
||
| | | Variable- |<-----+ | |-----------------------|
|
||
| type- | | Length | | |VariableAttributeCount |
|
||
| specific | | Attributes | | |-----------------------|
|
||
| body | | Array | | |FixedStoredSeparately |
|
||
| | |-------------| | |-----------------------|
|
||
+-----------+ | Variable- |<--------+ | |
|
||
| Length | | |
|
||
| Attributes | | o |
|
||
| Data | | o |
|
||
| | +-----------------------+
|
||
| |
|
||
+-------------+
|
||
|
||
|
||
|
||
|
||
The KEY_VALUE_PARTIAL_INFORMATION preceeding the VariableLengthAttributes
|
||
array is marked optional because it is only present if fixed-length and
|
||
variable-length attribute information is stored separately. In this case,
|
||
the VariableBufferOffset field in the SAMP_OBJECT_INFORMATION structure
|
||
is set to be zero.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
*/
|
||
|
||
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Includes //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
#include <samsrvp.h>
|
||
#include <lmcons.h>
|
||
#include <nturtl.h>
|
||
|
||
|
||
|
||
//
|
||
// This value indicates the minumum size block of memory to allocate
|
||
// when retrieving object attributes from disk.
|
||
|
||
#define SAMP_MINIMUM_ATTRIBUTE_ALLOC (1000)
|
||
|
||
//
|
||
// This value is used when growing the size of the buffer containing
|
||
// object attributes. It represents the amount of free space that
|
||
// should be left (approximately) for future growth in the buffer.
|
||
//
|
||
|
||
#define SAMP_MINIMUM_ATTRIBUTE_PAD (200)
|
||
|
||
|
||
|
||
//
|
||
// The following type is used to identify which grouping of attribute
|
||
// (fixed or variable-length) are being refered to in a number of api.
|
||
//
|
||
|
||
#define SAMP_FIXED_ATTRIBUTES (0L)
|
||
#define SAMP_VARIABLE_ATTRIBUTES (1L)
|
||
|
||
|
||
//
|
||
// The following line enables attribute debugging code
|
||
//
|
||
|
||
//#define SAM_DEBUG_ATTRIBUTES
|
||
//#ifdef SAM_DEBUG_ATTRIBUTES
|
||
//Boolean that allows us to turn off debugging output
|
||
//BOOLEAN SampDebugAttributes = FALSE;
|
||
//#endif
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// private macros //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
//
|
||
// Macro to round up a ULONG value to be dword aligned
|
||
// (i.e., be a multipleof 4).
|
||
// Note, this does not handle the case where the Ulong is greater
|
||
// than 0xfffffffc.
|
||
//
|
||
|
||
#define SampDwordAlignUlong( v ) (((v)+3) & 0xfffffffc)
|
||
|
||
|
||
//
|
||
// Make sure an object type and corresponding variable-length attribute
|
||
// index are legitimate.
|
||
//
|
||
|
||
//
|
||
// Make sure it is a legitimate object type
|
||
// And a legitimate attribute index for the object type
|
||
//
|
||
|
||
#define SampValidateAttributeIndex( c, i ) { \
|
||
ASSERT( ((c)->ObjectType < SampUnknownObjectType) ); \
|
||
ASSERT(((i) < SampObjectInformation[(c)->ObjectType].VariableAttributeCount) ); \
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Test to see if an object's fixed or variable-length attributes
|
||
// are in memory.
|
||
//
|
||
|
||
#define SampFixedAttributesValid( c ) ((c)->FixedValid)
|
||
|
||
#define SampVariableAttributesValid( c ) ((c)->VariableValid)
|
||
|
||
|
||
//
|
||
// Get the number of variable-length attributes defined for the
|
||
// specified object
|
||
//
|
||
|
||
#define SampVariableAttributeCount( c ) \
|
||
(SampObjectInformation[(c)->ObjectType].VariableAttributeCount)
|
||
|
||
|
||
|
||
//
|
||
// Get the offset of the beginning of the attribute buffers
|
||
//
|
||
|
||
#define SampFixedBufferOffset( c ) \
|
||
( \
|
||
SampObjectInformation[(c)->ObjectType].FixedAttributesOffset \
|
||
)
|
||
|
||
#define SampVariableBufferOffset( c ) \
|
||
( \
|
||
SampObjectInformation[(c)->ObjectType].VariableBufferOffset \
|
||
)
|
||
|
||
|
||
|
||
//
|
||
// Get the offset of the beginning of the variable data i/o buffer.
|
||
// If the fixed and variable-length attributes are stored separately,
|
||
// then this will be the lower half of the buffer.
|
||
// Otherwise, there is only one buffer, so it is the entire allocated buffer.
|
||
//
|
||
|
||
#define SampFixedBufferAddress( c ) \
|
||
( \
|
||
((PUCHAR)((c)->OnDisk)) + SampFixedBufferOffset( c ) \
|
||
)
|
||
|
||
#define SampVariableBufferAddress( c ) \
|
||
( \
|
||
((PUCHAR)((c)->OnDisk)) + SampVariableBufferOffset( c ) \
|
||
)
|
||
|
||
|
||
|
||
//
|
||
// Get the offset of the beginning of the variable-length
|
||
// attributes discriptors array. This address is dword-aligned.
|
||
//
|
||
|
||
#define SampVariableArrayOffset( c ) \
|
||
( \
|
||
SampObjectInformation[(c)->ObjectType].VariableArrayOffset \
|
||
)
|
||
|
||
//
|
||
// Calculate the address of the beginning of the variable-length
|
||
// attributes array.
|
||
//
|
||
|
||
#define SampVariableArrayAddress( c ) \
|
||
( \
|
||
(PSAMP_VARIABLE_LENGTH_ATTRIBUTE)((PUCHAR)((c)->OnDisk) + \
|
||
SampVariableArrayOffset( c ) ) \
|
||
)
|
||
|
||
|
||
//
|
||
// Get the offset of the beginning of the variable-length
|
||
// attributes data.
|
||
//
|
||
|
||
|
||
#define SampVariableDataOffset( c ) \
|
||
( \
|
||
SampObjectInformation[(c)->ObjectType].VariableDataOffset \
|
||
)
|
||
|
||
|
||
|
||
//
|
||
// Get the length of the on-disk buffer for holding the variable-length
|
||
// attribute array and data. If the fixed and variable-length attributes
|
||
// are stored separately, then this will be the lower half of the buffer.
|
||
// Otherwise, there is only one buffer, so it is the entire allocated buffer.
|
||
//
|
||
|
||
#define SampFixedBufferLength( c ) \
|
||
( \
|
||
SampObjectInformation[(c)->ObjectType].FixedLengthSize \
|
||
)
|
||
|
||
#define SampVariableBufferLength( c ) \
|
||
( \
|
||
(c)->OnDiskAllocated - SampVariableBufferOffset( c ) \
|
||
)
|
||
|
||
|
||
|
||
|
||
//
|
||
// Return the address of a Qualifier field within the variable-length
|
||
// attribute descriptor array.
|
||
//
|
||
|
||
#define SampVariableQualifier( c, i ) \
|
||
( \
|
||
SampVariableArrayAddress( c ) + \
|
||
(sizeof(SAMP_VARIABLE_LENGTH_ATTRIBUTE) * i) \
|
||
+ FIELD_OFFSET(SAMP_VARIABLE_LENGTH_ATTRIBUTE, Qualifier) \
|
||
)
|
||
|
||
|
||
|
||
//
|
||
// Return the address of the first byte of free space
|
||
// in an object's attribute data buffer.
|
||
// This will be dword aligned.
|
||
//
|
||
|
||
#define SampFirstFreeVariableAddress( c ) \
|
||
(PUCHAR)(((PUCHAR)((c)->OnDisk)) + (c)->OnDiskUsed)
|
||
|
||
|
||
|
||
//
|
||
// Get the number of bytes needed to store the entire variable-length
|
||
// attribute information on disk.
|
||
//
|
||
|
||
#define SampVariableBufferUsedLength( c ) \
|
||
( \
|
||
(PUCHAR)SampFirstFreeVariableAddress(c) - \
|
||
(PUCHAR)SampVariableArrayAddress(c) \
|
||
)
|
||
|
||
|
||
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// private service prototypes //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampValidateAttributes(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeGroup
|
||
);
|
||
|
||
PUCHAR
|
||
SampObjectAttributeAddress(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex
|
||
);
|
||
|
||
ULONG
|
||
SampObjectAttributeLength(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex
|
||
);
|
||
|
||
PULONG
|
||
SampObjectAttributeQualifier(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex
|
||
);
|
||
|
||
NTSTATUS
|
||
SampGetAttributeBufferReadInfo(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeGroup,
|
||
OUT PUCHAR *Buffer,
|
||
OUT PULONG BufferLength,
|
||
OUT PUNICODE_STRING *KeyAttributeName
|
||
);
|
||
|
||
NTSTATUS
|
||
SampExtendAttributeBuffer(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG NewSize
|
||
);
|
||
|
||
NTSTATUS
|
||
SampReadRegistryAttribute(
|
||
IN HANDLE Key,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG BufferLength,
|
||
IN PUNICODE_STRING AttributeName,
|
||
OUT PULONG RequiredLength
|
||
);
|
||
|
||
NTSTATUS
|
||
SampSetVariableAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN ULONG Qualifier,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG Length
|
||
);
|
||
|
||
NTSTATUS
|
||
SampUpgradeToCurrentRevision(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeGroup,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG LengthOfDataRead,
|
||
IN PULONG TotalRequiredLength
|
||
);
|
||
|
||
|
||
|
||
#ifdef SAM_DEBUG_ATTRIBUTES
|
||
VOID
|
||
SampDumpAttributes(
|
||
IN PSAMP_OBJECT Context
|
||
);
|
||
|
||
VOID
|
||
SampDumpData(
|
||
IN PVOID Buffer,
|
||
IN ULONG Length
|
||
);
|
||
#endif
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Public Routines //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
VOID
|
||
SampInitObjectInfoAttributes(
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API initializes the attribute field information
|
||
of the various object information structures.
|
||
|
||
Attribute information includes:
|
||
|
||
FixedStoredSeparately (BOOLEAN)
|
||
|
||
FixedAttributeOffset (ULONG)
|
||
VariableBufferOffset (ULONG)
|
||
VariableArrayOffset (ULONG)
|
||
VariableDataOffset (ULONG)
|
||
|
||
FixedLengthSize (ULONG)
|
||
VariableAttributeCount (ULONG)
|
||
|
||
|
||
Parameters:
|
||
|
||
None.
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
|
||
//
|
||
// Define the size of the header that is in front of our data when
|
||
// we read it back out of the registry.
|
||
//
|
||
|
||
#define KEY_VALUE_HEADER_SIZE (SampDwordAlignUlong( \
|
||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)))
|
||
|
||
|
||
PSAMP_OBJECT_INFORMATION Object;
|
||
|
||
|
||
//
|
||
// SERVER object attribute information
|
||
//
|
||
|
||
Object = &SampObjectInformation[SampServerObjectType];
|
||
|
||
Object->FixedStoredSeparately = SAMP_SERVER_STORED_SEPARATELY;
|
||
|
||
Object->FixedAttributesOffset = KEY_VALUE_HEADER_SIZE;
|
||
|
||
Object->FixedLengthSize = sizeof(SAMP_V1_FIXED_LENGTH_SERVER);
|
||
|
||
#if SAMP_SERVER_STORED_SEPARATELY
|
||
|
||
Object->VariableBufferOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->VariableBufferOffset + KEY_VALUE_HEADER_SIZE;
|
||
#else
|
||
|
||
Object->VariableBufferOffset = 0;
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
#endif //SAMP_SERVER_STORED_SEPARATELY
|
||
|
||
|
||
Object->VariableAttributeCount = SAMP_SERVER_VARIABLE_ATTRIBUTES;
|
||
|
||
Object->VariableDataOffset =
|
||
SampDwordAlignUlong( Object->VariableArrayOffset +
|
||
(SAMP_SERVER_VARIABLE_ATTRIBUTES *
|
||
sizeof(SAMP_VARIABLE_LENGTH_ATTRIBUTE))
|
||
);
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// DOMAIN object attribute information
|
||
//
|
||
|
||
Object = &SampObjectInformation[SampDomainObjectType];
|
||
|
||
Object->FixedStoredSeparately = SAMP_DOMAIN_STORED_SEPARATELY;
|
||
|
||
Object->FixedAttributesOffset = KEY_VALUE_HEADER_SIZE;
|
||
|
||
Object->FixedLengthSize = sizeof(SAMP_V1_0A_FIXED_LENGTH_DOMAIN);
|
||
|
||
#if SAMP_DOMAIN_STORED_SEPARATELY
|
||
|
||
Object->VariableBufferOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->VariableBufferOffset + KEY_VALUE_HEADER_SIZE;
|
||
#else
|
||
|
||
Object->VariableBufferOffset = 0;
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
#endif //SAMP_DOMAIN_STORED_SEPARATELY
|
||
|
||
|
||
Object->VariableAttributeCount = SAMP_DOMAIN_VARIABLE_ATTRIBUTES;
|
||
|
||
Object->VariableDataOffset =
|
||
SampDwordAlignUlong( Object->VariableArrayOffset +
|
||
(SAMP_DOMAIN_VARIABLE_ATTRIBUTES *
|
||
sizeof(SAMP_VARIABLE_LENGTH_ATTRIBUTE))
|
||
);
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// USER object attribute information
|
||
//
|
||
|
||
Object = &SampObjectInformation[SampUserObjectType];
|
||
|
||
Object->FixedStoredSeparately = SAMP_USER_STORED_SEPARATELY;
|
||
|
||
Object->FixedAttributesOffset = KEY_VALUE_HEADER_SIZE;
|
||
|
||
Object->FixedLengthSize = sizeof(SAMP_V1_0A_FIXED_LENGTH_USER);
|
||
|
||
#if SAMP_USER_STORED_SEPARATELY
|
||
|
||
Object->VariableBufferOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->VariableBufferOffset + KEY_VALUE_HEADER_SIZE;
|
||
#else
|
||
|
||
Object->VariableBufferOffset = 0;
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
#endif //SAMP_USER_STORED_SEPARATELY
|
||
|
||
|
||
Object->VariableAttributeCount = SAMP_USER_VARIABLE_ATTRIBUTES;
|
||
|
||
Object->VariableDataOffset =
|
||
SampDwordAlignUlong( Object->VariableArrayOffset +
|
||
(SAMP_USER_VARIABLE_ATTRIBUTES *
|
||
sizeof(SAMP_VARIABLE_LENGTH_ATTRIBUTE))
|
||
);
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// GROUP object attribute information
|
||
//
|
||
|
||
Object = &SampObjectInformation[SampGroupObjectType];
|
||
|
||
Object->FixedStoredSeparately = SAMP_GROUP_STORED_SEPARATELY;
|
||
|
||
Object->FixedAttributesOffset = KEY_VALUE_HEADER_SIZE;
|
||
|
||
Object->FixedLengthSize = sizeof(SAMP_V1_0A_FIXED_LENGTH_GROUP);
|
||
|
||
#if SAMP_GROUP_STORED_SEPARATELY
|
||
|
||
Object->VariableBufferOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->VariableBufferOffset + KEY_VALUE_HEADER_SIZE;
|
||
#else
|
||
|
||
Object->VariableBufferOffset = 0;
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
#endif //SAMP_GROUP_STORED_SEPARATELY
|
||
|
||
|
||
Object->VariableAttributeCount = SAMP_GROUP_VARIABLE_ATTRIBUTES;
|
||
|
||
Object->VariableDataOffset =
|
||
SampDwordAlignUlong( Object->VariableArrayOffset +
|
||
(SAMP_GROUP_VARIABLE_ATTRIBUTES *
|
||
sizeof(SAMP_VARIABLE_LENGTH_ATTRIBUTE))
|
||
);
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// ALIAS object attribute information
|
||
//
|
||
|
||
Object = &SampObjectInformation[SampAliasObjectType];
|
||
|
||
Object->FixedStoredSeparately = SAMP_ALIAS_STORED_SEPARATELY;
|
||
|
||
Object->FixedAttributesOffset = KEY_VALUE_HEADER_SIZE;
|
||
|
||
Object->FixedLengthSize = sizeof(SAMP_V1_FIXED_LENGTH_ALIAS);
|
||
|
||
#if SAMP_ALIAS_STORED_SEPARATELY
|
||
|
||
Object->VariableBufferOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->VariableBufferOffset + KEY_VALUE_HEADER_SIZE;
|
||
#else
|
||
|
||
Object->VariableBufferOffset = 0;
|
||
|
||
Object->VariableArrayOffset =
|
||
Object->FixedAttributesOffset +
|
||
SampDwordAlignUlong(Object->FixedLengthSize);
|
||
|
||
#endif //SAMP_ALIAS_STORED_SEPARATELY
|
||
|
||
|
||
Object->VariableAttributeCount = SAMP_ALIAS_VARIABLE_ATTRIBUTES;
|
||
|
||
Object->VariableDataOffset =
|
||
SampDwordAlignUlong( Object->VariableArrayOffset +
|
||
(SAMP_ALIAS_VARIABLE_ATTRIBUTES *
|
||
sizeof(SAMP_VARIABLE_LENGTH_ATTRIBUTE))
|
||
);
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampStoreObjectAttributes(
|
||
IN PSAMP_OBJECT Context,
|
||
IN BOOLEAN UseKeyHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
This API is used to store an object's attributes onto
|
||
backing store.
|
||
|
||
The object attributes are not flushed to disk with this
|
||
routine. They are just added to the RXACT.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
UseKeyHandle - If TRUE, the RootKey in the context block is passed
|
||
to the transaction code - this assumes that the key
|
||
will still be open when the transaction is committed.
|
||
If FALSE, the RootKey will be ignored and the transaction code will
|
||
open a key for itself.
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
|
||
Other status values as may be returned by the RXACT services.
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
BOOLEAN
|
||
FlushFixed = FALSE,
|
||
FlushVariable = FALSE;
|
||
|
||
HANDLE
|
||
RootKey;
|
||
|
||
//
|
||
// See if anything is dirty and needs to be stored
|
||
//
|
||
|
||
if (Context->FixedValid && Context->FixedDirty) {
|
||
|
||
FlushFixed = TRUE;
|
||
}
|
||
|
||
if (Context->VariableValid && Context->VariableDirty) {
|
||
|
||
FlushVariable = TRUE;
|
||
}
|
||
|
||
|
||
if (!(FlushFixed || FlushVariable)) {
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Calculate the RootKey to pass to the transaction code
|
||
//
|
||
|
||
if (UseKeyHandle) {
|
||
RootKey = Context->RootKey;
|
||
} else {
|
||
RootKey = INVALID_HANDLE_VALUE;
|
||
}
|
||
|
||
//
|
||
// We keep an open domain context that is used to modify the change
|
||
// count whenever a change is made. But if this is a domain change
|
||
// here, then that change will overwrite this one. Check for that
|
||
// case, and copy this fixed data to the open domain context. Note
|
||
// that the open domain's variable data never gets changed.
|
||
//
|
||
|
||
if ( ( Context->ObjectType == SampDomainObjectType ) &&
|
||
( Context != SampDefinedDomains[Context->DomainIndex].Context ) ) {
|
||
|
||
PSAMP_OBJECT DefinedContext;
|
||
|
||
//
|
||
// Get a pointer to the corresponding open defined domain.
|
||
// No changes should have been made to its data.
|
||
//
|
||
|
||
DefinedContext = SampDefinedDomains[Context->DomainIndex].Context;
|
||
|
||
ASSERT( DefinedContext->FixedValid == TRUE );
|
||
ASSERT( DefinedContext->FixedDirty == FALSE );
|
||
|
||
#if DBG
|
||
if ( DefinedContext->VariableValid ) {
|
||
ASSERT( DefinedContext->VariableDirty == FALSE );
|
||
}
|
||
#endif
|
||
DefinedContext->VariableDirty = FALSE;
|
||
|
||
//
|
||
// Copy our fixed data over the defined domain's fixed data.
|
||
// Note that we're assuming that the fixed and variable data are
|
||
// stored separately.
|
||
//
|
||
|
||
ASSERT(SampObjectInformation[SampDomainObjectType].FixedStoredSeparately);
|
||
|
||
RtlCopyMemory(
|
||
SampFixedBufferAddress( DefinedContext ),
|
||
SampFixedBufferAddress( Context ),
|
||
SampFixedBufferLength( Context )
|
||
);
|
||
|
||
//
|
||
// No need to flush this context's fixed data, since the commit
|
||
// code will flush the same stuff (plus an altered modified count).
|
||
//
|
||
|
||
FlushFixed = FALSE;
|
||
Context->FixedDirty = FALSE;
|
||
}
|
||
|
||
//
|
||
// One or more of the attributes needs to be stored.
|
||
//
|
||
|
||
if (!SampObjectInformation[Context->ObjectType].FixedStoredSeparately) {
|
||
|
||
//
|
||
// fixed and variable-length attributes stored together.
|
||
// Note - strip off the partial key info struct from the start
|
||
//
|
||
|
||
NtStatus = RtlAddAttributeActionToRXact(
|
||
SampRXactContext,
|
||
RtlRXactOperationSetValue,
|
||
&(Context->RootName),
|
||
RootKey,
|
||
&SampCombinedAttributeName,
|
||
REG_BINARY,
|
||
SampFixedBufferAddress(Context),
|
||
Context->OnDiskUsed - SampFixedBufferOffset(Context)
|
||
);
|
||
#if SAMP_DIAGNOSTICS
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
SampDiagPrint( DISPLAY_STORAGE_FAIL,
|
||
("SAM: Failed to add action to RXact (0x%lx)\n",
|
||
NtStatus) );
|
||
IF_SAMP_GLOBAL( BREAK_ON_STORAGE_FAIL ) {
|
||
ASSERT(NT_SUCCESS(NtStatus));
|
||
}
|
||
}
|
||
#endif //SAMP_DIAGNOSTICS
|
||
|
||
|
||
if ( NT_SUCCESS( NtStatus ) ) {
|
||
|
||
Context->FixedDirty = FALSE;
|
||
Context->VariableDirty = FALSE;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// fixed and variable-length attributes stored separately.
|
||
// Only update the one(s) we need to.
|
||
//
|
||
|
||
NtStatus = STATUS_SUCCESS;
|
||
if (FlushFixed) {
|
||
|
||
NtStatus = RtlAddAttributeActionToRXact(
|
||
SampRXactContext,
|
||
RtlRXactOperationSetValue,
|
||
&(Context->RootName),
|
||
RootKey,
|
||
&SampFixedAttributeName,
|
||
REG_BINARY,
|
||
SampFixedBufferAddress(Context),
|
||
SampVariableBufferOffset(Context) - SampFixedBufferOffset(Context)
|
||
);
|
||
|
||
#if SAMP_DIAGNOSTICS
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
SampDiagPrint( DISPLAY_STORAGE_FAIL,
|
||
("SAM: Failed to add action to RXact (0x%lx)\n",
|
||
NtStatus) );
|
||
IF_SAMP_GLOBAL( BREAK_ON_STORAGE_FAIL ) {
|
||
ASSERT(NT_SUCCESS(NtStatus));
|
||
}
|
||
}
|
||
#endif //SAMP_DIAGNOSTICS
|
||
|
||
if ( NT_SUCCESS( NtStatus ) ) {
|
||
|
||
Context->FixedDirty = FALSE;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && FlushVariable) {
|
||
|
||
NtStatus = RtlAddAttributeActionToRXact(
|
||
SampRXactContext,
|
||
RtlRXactOperationSetValue,
|
||
&(Context->RootName),
|
||
RootKey,
|
||
&SampVariableAttributeName,
|
||
REG_BINARY,
|
||
SampVariableArrayAddress( Context ),
|
||
SampVariableBufferUsedLength(Context)
|
||
);
|
||
|
||
#if SAMP_DIAGNOSTICS
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
SampDiagPrint( DISPLAY_STORAGE_FAIL,
|
||
("SAM: Failed to add action to RXact (0x%lx)\n",
|
||
NtStatus) );
|
||
IF_SAMP_GLOBAL( BREAK_ON_STORAGE_FAIL ) {
|
||
ASSERT(NT_SUCCESS(NtStatus));
|
||
}
|
||
}
|
||
#endif //SAMP_DIAGNOSTICS
|
||
|
||
|
||
if ( NT_SUCCESS( NtStatus ) ) {
|
||
Context->VariableDirty = FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampDeleteAttributeKeys(
|
||
IN PSAMP_OBJECT Context
|
||
)
|
||
|
||
/*++
|
||
|
||
This API is used to delete the attribute keys that are created in the
|
||
registry underneath a SAM object.
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
Error status may be returned by registry calls.
|
||
|
||
--*/
|
||
{
|
||
UNICODE_STRING
|
||
KeyName;
|
||
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
if (SampObjectInformation[Context->ObjectType].FixedStoredSeparately) {
|
||
|
||
//
|
||
// Must delete both fixed and variable attribute keys.
|
||
//
|
||
|
||
NtStatus = SampBuildAccountSubKeyName(
|
||
SampUserObjectType,
|
||
&KeyName,
|
||
Context->TypeBody.User.Rid,
|
||
&SampFixedAttributeName
|
||
);
|
||
|
||
if (NT_SUCCESS(NtStatus)) {
|
||
|
||
NtStatus = RtlAddActionToRXact(
|
||
SampRXactContext,
|
||
RtlRXactOperationDelete,
|
||
&KeyName,
|
||
0,
|
||
NULL,
|
||
0
|
||
);
|
||
SampFreeUnicodeString( &KeyName );
|
||
|
||
NtStatus = SampBuildAccountSubKeyName(
|
||
SampUserObjectType,
|
||
&KeyName,
|
||
Context->TypeBody.User.Rid,
|
||
&SampVariableAttributeName
|
||
);
|
||
|
||
if (NT_SUCCESS(NtStatus)) {
|
||
|
||
NtStatus = RtlAddActionToRXact(
|
||
SampRXactContext,
|
||
RtlRXactOperationDelete,
|
||
&KeyName,
|
||
0,
|
||
NULL,
|
||
0
|
||
);
|
||
SampFreeUnicodeString( &KeyName );
|
||
}
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Must delete the combined attribute key.
|
||
//
|
||
|
||
NtStatus = SampBuildAccountSubKeyName(
|
||
SampUserObjectType,
|
||
&KeyName,
|
||
Context->TypeBody.User.Rid,
|
||
&SampCombinedAttributeName
|
||
);
|
||
|
||
if (NT_SUCCESS(NtStatus)) {
|
||
|
||
NtStatus = RtlAddActionToRXact(
|
||
SampRXactContext,
|
||
RtlRXactOperationDelete,
|
||
&KeyName,
|
||
0,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
SampFreeUnicodeString( &KeyName );
|
||
}
|
||
}
|
||
|
||
return( NtStatus );
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampGetFixedAttributes(
|
||
IN PSAMP_OBJECT Context,
|
||
IN BOOLEAN MakeCopy,
|
||
OUT PVOID *FixedData
|
||
)
|
||
|
||
/*++
|
||
|
||
This API is used to get a pointer to the fixed-length attributes.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
FixedData - Receives a pointer to the fixed-length data.
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
//
|
||
// Make the data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_FIXED_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Return a pointer to the fixed-length attributes.
|
||
//
|
||
|
||
if (MakeCopy == FALSE) {
|
||
*FixedData = (PVOID)SampFixedBufferAddress( Context );
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
//
|
||
// Need to make a copy of the fixed data
|
||
//
|
||
|
||
*FixedData = (PVOID)MIDL_user_allocate( SampFixedBufferLength( Context ) );
|
||
if ((*FixedData) == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
RtlCopyMemory( *FixedData,
|
||
SampFixedBufferAddress( Context ),
|
||
SampFixedBufferLength( Context ) );
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampSetFixedAttributes(
|
||
IN PSAMP_OBJECT Context,
|
||
IN PVOID FixedData
|
||
)
|
||
|
||
/*++
|
||
|
||
This API is used to replace the fixed-length data attribute.
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
//
|
||
// Make the fixed-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_FIXED_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
if ( FixedData != SampFixedBufferAddress( Context ) ) {
|
||
|
||
//
|
||
// The caller had a copy of the data, so we must copy the changes
|
||
// over our data buffer.
|
||
//
|
||
|
||
RtlCopyMemory( SampFixedBufferAddress( Context ),
|
||
FixedData,
|
||
SampFixedBufferLength( Context ) );
|
||
}
|
||
|
||
//
|
||
// Mark the buffer dirty now and it will get flushed when the
|
||
// changes are committed.
|
||
//
|
||
|
||
Context->FixedDirty = TRUE;
|
||
|
||
return( NtStatus );
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampGetUnicodeStringAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN BOOLEAN MakeCopy,
|
||
OUT PUNICODE_STRING UnicodeAttribute
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to get a copy of a UNICODE_STRING attribute or a
|
||
pointer to the attribute. If a pointer to the attribute is sought,
|
||
care must be taken to ensure the pointer is not used after it becomes
|
||
invalid. Actions that may cause an attribute pointer to become invalid
|
||
include setting an attribute value or dereferencing and then referencing the
|
||
object again.
|
||
|
||
If MakeCopy is FALSE, indicating the string is to be referenced rather
|
||
than copied, then only the body of the string is referenced. The lengths
|
||
and pointer are set in the provided argument.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be retrieved as a UNICODE_STRING.
|
||
|
||
MakeCopy - If TRUE, indicates that a copy of the attribute is to be made.
|
||
If FALSE, indicates a pointer to the attribute is desired without
|
||
making a copy. WARNING, if this is FALSE, the pointer is only
|
||
valid while the in-memory copy of the attribute remains in place.
|
||
Addition or replacement of any variable length attribute may
|
||
cause the attribute to be moved, and previously returned pointers
|
||
invalidated.
|
||
|
||
UnicodeAttribute - Receives a pointer to the UNICODE_STRING. If
|
||
MakeCopy was specified as TRUE, then this pointer points to a block
|
||
of memory allocated with MIDL_user_allocate() which the caller is
|
||
responsible for freeing (using MIDL_user_free()).
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS NtStatus;
|
||
ULONG Length;
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
//
|
||
// Get the length of the attribute
|
||
//
|
||
|
||
Length = SampObjectAttributeLength( Context, AttributeIndex );
|
||
ASSERT(Length <= 0xFFFF);
|
||
|
||
UnicodeAttribute->MaximumLength = (USHORT)Length;
|
||
UnicodeAttribute->Length = (USHORT)Length;
|
||
|
||
//
|
||
// If we are not to allocate memory, then just return a pointer
|
||
// to the attribute.
|
||
//
|
||
|
||
if (MakeCopy == FALSE) {
|
||
UnicodeAttribute->Buffer =
|
||
(PWSTR)SampObjectAttributeAddress( Context, AttributeIndex );
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
//
|
||
// Need to make a copy of the attribute
|
||
//
|
||
// NOTE: We should test for zero length here and return a NULL pointer
|
||
// in that case, but this change would require verification of all of the
|
||
// callers of this routine, so I'm leaving it as is.
|
||
//
|
||
|
||
UnicodeAttribute->Buffer = (PSID)MIDL_user_allocate( Length );
|
||
if ((UnicodeAttribute->Buffer) == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
RtlCopyMemory(
|
||
UnicodeAttribute->Buffer,
|
||
SampObjectAttributeAddress( Context, AttributeIndex ),
|
||
Length
|
||
);
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampSetUnicodeStringAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN PUNICODE_STRING Attribute
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to replace a UNICODE_STRING attribute in an
|
||
object's variable length attributes.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be set as a UNICODE_STRING.
|
||
|
||
|
||
Attribute - Points to the new UNICODE_STRING value.
|
||
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the variable-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the new attribute value...
|
||
//
|
||
|
||
NtStatus = SampSetVariableAttribute(
|
||
Context,
|
||
AttributeIndex,
|
||
0, // Qualifier not used
|
||
(PUCHAR)Attribute->Buffer,
|
||
Attribute->Length
|
||
);
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampGetSidAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN BOOLEAN MakeCopy,
|
||
OUT PSID *Sid
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to get a copy of a SID attribute or a pointer to
|
||
the attribute. If a pointer to the attribute is sought, care must
|
||
be taken to ensure the pointer is not used after it becomes invalid.
|
||
Actions that may cause an attribute pointer to become invalid include
|
||
setting an attribute value or dereferencing and then referencing the
|
||
object again.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be retrieved as a SID.
|
||
|
||
MakeCopy - If TRUE, indicates that a copy of the SID is to be made.
|
||
If FALSE, indicates a pointer to the SID is desired without
|
||
making a copy. WARNING, if this is FALSE, the pointer is only
|
||
valid while the in-memory copy of the SID remains in place.
|
||
Addition or replacement of any variable length attribute may
|
||
cause the SID to be moved, and previously returned pointers
|
||
invalidated.
|
||
|
||
Sid - Receives a pointer to the SID. If MakeCopy was specified, then
|
||
this pointer points to a block of memory allocated with
|
||
MIDL_user_allocate() which the caller is responsible for freeing
|
||
(using MIDL_user_free()).
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
ULONG
|
||
Length;
|
||
|
||
PSID
|
||
SidAttribute;
|
||
|
||
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the variable-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Get the address of the attribute in question
|
||
//
|
||
|
||
SidAttribute = (PSID)SampObjectAttributeAddress( Context, AttributeIndex );
|
||
|
||
|
||
//
|
||
// If we are not to allocate memory, then just return a pointer
|
||
// to the attribute.
|
||
//
|
||
|
||
if (MakeCopy == FALSE) {
|
||
(*Sid) = SidAttribute;
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Need to make a copy of the SID
|
||
//
|
||
|
||
Length = SampObjectAttributeLength( Context, AttributeIndex );
|
||
ASSERT(Length == RtlLengthSid( SidAttribute ) );
|
||
|
||
(*Sid) = (PSID)MIDL_user_allocate( Length );
|
||
if ((*Sid) == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
NtStatus = RtlCopySid( Length, (*Sid), SidAttribute );
|
||
ASSERT(NT_SUCCESS(NtStatus));
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampSetSidAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN PSID Attribute
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to replace a SID attribute in an object's variable
|
||
length attributes.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be set as a SID.
|
||
|
||
|
||
Attribute - Points to the new SID value.
|
||
|
||
Length - The length of the new attribute value (in bytes).
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
//
|
||
// Validate the passed SID
|
||
//
|
||
|
||
ASSERT(RtlValidSid(Attribute));
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the variable-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the new attribute value...
|
||
//
|
||
|
||
NtStatus = SampSetVariableAttribute(
|
||
Context,
|
||
AttributeIndex,
|
||
0, // Qualifier not used
|
||
(PUCHAR)Attribute,
|
||
RtlLengthSid(Attribute)
|
||
);
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampGetAccessAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN BOOLEAN MakeCopy,
|
||
OUT PULONG Revision,
|
||
OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to get a copy of the object access information.
|
||
This includes the security descriptor and revision level of the
|
||
object.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be retrieved.
|
||
|
||
MakeCopy - If TRUE, indicates that a copy of the attribute is to be made.
|
||
If FALSE, indicates a pointer to the attribute is desired without
|
||
making a copy. WARNING, if this is FALSE, the pointer is only
|
||
valid while the in-memory copy of the attribute remains in place.
|
||
Addition or replacement of any variable length attribute may
|
||
cause the attribute to be moved, and previously returned pointers
|
||
invalidated.
|
||
|
||
Revision - Receives the revision level from the access information.
|
||
|
||
SecurityDescriptor - Receives a pointer to the attribute. If MakeCopy
|
||
was specified as TRUE, then this pointer points to a block of memory
|
||
allocated with MIDL_user_allocate() which the caller is responsible
|
||
for freeing (using MIDL_user_free()).
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
ULONG
|
||
Length;
|
||
|
||
PVOID
|
||
RawAttribute;
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
|
||
|
||
//
|
||
// Make the data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Get the revision level from the qualifier field of the variable
|
||
// array entry.
|
||
//
|
||
|
||
(*Revision) = *(SampObjectAttributeQualifier( Context, AttributeIndex ));
|
||
|
||
|
||
//
|
||
// Get the address of the attribute in question
|
||
//
|
||
|
||
RawAttribute = (PVOID)SampObjectAttributeAddress( Context, AttributeIndex );
|
||
|
||
|
||
//
|
||
// If we are not to allocate memory, then just return a pointer
|
||
// to the attribute.
|
||
//
|
||
|
||
if (MakeCopy == FALSE) {
|
||
(*SecurityDescriptor) = (PSECURITY_DESCRIPTOR)RawAttribute;
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Need to make a copy of the attribute
|
||
//
|
||
|
||
Length = SampObjectAttributeLength( Context, AttributeIndex );
|
||
|
||
(*SecurityDescriptor) = (PSECURITY_DESCRIPTOR)MIDL_user_allocate( Length );
|
||
if ((*SecurityDescriptor) == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
RtlCopyMemory( (*SecurityDescriptor), RawAttribute, Length );
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampSetAccessAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN PSECURITY_DESCRIPTOR Attribute,
|
||
IN ULONG Length
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to replace a SECURITY_DESCRIPTOR attribute in
|
||
an object's variable length attributes.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be set as a SECURITY_DESCRIPTOR.
|
||
|
||
|
||
Attribute - Points to the new SECURITY_DESCRIPTOR value.
|
||
|
||
Length - The length of the new attribute value (in bytes).
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the variable-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the new attribute value...
|
||
//
|
||
|
||
NtStatus = SampSetVariableAttribute(
|
||
Context,
|
||
AttributeIndex,
|
||
SAMP_REVISION,
|
||
(PUCHAR)Attribute,
|
||
Length
|
||
);
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampGetUlongArrayAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN BOOLEAN MakeCopy,
|
||
OUT PULONG *UlongArray,
|
||
OUT PULONG UsedCount,
|
||
OUT PULONG LengthCount
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to get a copy of an array of ULONGs attribute or
|
||
a pointer to the attribute. If a pointer to the attribute is sought,
|
||
care must be taken to ensure the pointer is not used after it becomes
|
||
invalid. Actions that may cause an attribute pointer to become invalid
|
||
include setting an attribute value or dereferencing and then referencing
|
||
the object again.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be retrieved as a ULONG array.
|
||
|
||
MakeCopy - If TRUE, indicates that a copy of the attribute is to be made.
|
||
If FALSE, indicates a pointer to the attribute is desired without
|
||
making a copy. WARNING, if this is FALSE, the pointer is only
|
||
valid while the in-memory copy of the attribute remains in place.
|
||
Addition or replacement of any variable length attribute may
|
||
cause the attribute to be moved, and previously returned pointers
|
||
invalidated.
|
||
|
||
UlongArray - Receives a pointer to the array of ULONGS. If
|
||
MakeCopy was specified as TRUE, then this pointer points to a block
|
||
of memory allocated with MIDL_user_allocate() which the caller is
|
||
responsible for freeing (using MIDL_user_free()).
|
||
|
||
UsedCount - Receives the number of elements used in the array.
|
||
|
||
LengthCount - Receives the total number of elements in the array (some
|
||
at the end may be unused). If this value is zero, then
|
||
UlongArray will be returned as NULL.
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
ULONG
|
||
Length;
|
||
|
||
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
|
||
|
||
//
|
||
// Make the data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Get the count of array elements.
|
||
// If this is zero, then return will a null buffer pointer.
|
||
//
|
||
|
||
(*UsedCount) = *(SampObjectAttributeQualifier( Context, AttributeIndex));
|
||
|
||
|
||
|
||
|
||
//
|
||
// Get the length of the attribute
|
||
//
|
||
|
||
Length = SampObjectAttributeLength( Context, AttributeIndex );
|
||
|
||
(*LengthCount) = Length / sizeof(ULONG);
|
||
|
||
ASSERT( (*UsedCount) <= (*LengthCount) );
|
||
|
||
if ((*LengthCount) == 0) {
|
||
(*UlongArray) = NULL;
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// If we are not to allocate memory, then just return a pointer
|
||
// to the attribute.
|
||
//
|
||
|
||
if (MakeCopy == FALSE) {
|
||
(*UlongArray) =
|
||
(PULONG)SampObjectAttributeAddress( Context, AttributeIndex );
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Need to make a copy of the attribute
|
||
//
|
||
|
||
(*UlongArray) = (PULONG)MIDL_user_allocate( Length );
|
||
if ((*UlongArray) == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
|
||
RtlCopyMemory( (*UlongArray),
|
||
SampObjectAttributeAddress( Context, AttributeIndex ),
|
||
Length );
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampSetUlongArrayAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN PULONG Attribute,
|
||
IN ULONG UsedCount,
|
||
IN ULONG LengthCount
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to replace a ULONG array attribute in an
|
||
object's variable length attributes.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be set.
|
||
|
||
|
||
Attribute - Points to the new ULONG array value.
|
||
|
||
UsedCount - The number of used elements in the array.
|
||
|
||
LengthCount - the total number of elements in the array (some at the
|
||
end may be unused).
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
ASSERT( LengthCount >= UsedCount );
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the variable-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the new attribute value...
|
||
//
|
||
|
||
NtStatus = SampSetVariableAttribute(
|
||
Context,
|
||
AttributeIndex,
|
||
UsedCount, // Qualifier contains used element count
|
||
(PUCHAR)Attribute,
|
||
(LengthCount * sizeof(ULONG))
|
||
);
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampGetLargeIntArrayAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN BOOLEAN MakeCopy,
|
||
OUT PLARGE_INTEGER *LargeIntArray,
|
||
OUT PULONG Count
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to get a copy of an array of LARGE_INTEGERs attribute or
|
||
a pointer to the attribute. If a pointer to the attribute is sought,
|
||
care must be taken to ensure the pointer is not used after it becomes
|
||
invalid. Actions that may cause an attribute pointer to become invalid
|
||
include setting an attribute value or dereferencing and then referencing
|
||
the object again.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be retrieved.
|
||
|
||
MakeCopy - If TRUE, indicates that a copy of the attribute is to be made.
|
||
If FALSE, indicates a pointer to the attribute is desired without
|
||
making a copy. WARNING, if this is FALSE, the pointer is only
|
||
valid while the in-memory copy of the attribute remains in place.
|
||
Addition or replacement of any variable length attribute may
|
||
cause the attribute to be moved, and previously returned pointers
|
||
invalidated.
|
||
|
||
LargeIntArray - Receives a pointer to the array of ULONGS. If
|
||
MakeCopy was specified as TRUE, then this pointer points to a block
|
||
of memory allocated with MIDL_user_allocate() which the caller is
|
||
responsible for freeing (using MIDL_user_free()).
|
||
|
||
|
||
Count - Receives the number of elements in the array. If this value
|
||
is zero, then LargeIntArray will be returned as NULL.
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
ULONG
|
||
Length;
|
||
|
||
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
|
||
|
||
//
|
||
// Make the data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Get the count of array elements.
|
||
// If this is zero, then return will a null buffer pointer.
|
||
//
|
||
|
||
(*Count) = *(SampObjectAttributeQualifier( Context, AttributeIndex));
|
||
|
||
if ((*Count) == 0) {
|
||
(*LargeIntArray) = NULL;
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Get the length of the attribute
|
||
//
|
||
|
||
Length = SampObjectAttributeLength( Context, AttributeIndex );
|
||
|
||
ASSERT((*Count) == (Length / sizeof(LARGE_INTEGER)) );
|
||
|
||
|
||
|
||
//
|
||
// If we are not to allocate memory, then just return a pointer
|
||
// to the attribute.
|
||
//
|
||
|
||
if (MakeCopy == FALSE) {
|
||
(*LargeIntArray) =
|
||
(PLARGE_INTEGER)SampObjectAttributeAddress( Context, AttributeIndex );
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Need to make a copy of the attribute
|
||
//
|
||
|
||
(*LargeIntArray) = (PLARGE_INTEGER)MIDL_user_allocate( Length );
|
||
if ((*LargeIntArray) == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
|
||
RtlCopyMemory( (*LargeIntArray),
|
||
SampObjectAttributeAddress( Context, AttributeIndex ),
|
||
Length );
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampSetLargeIntArrayAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN PLARGE_INTEGER Attribute,
|
||
IN ULONG Count
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to replace a LARGE_INTEGER array attribute in an
|
||
object's variable length attributes.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be set.
|
||
|
||
|
||
Attribute - Points to the new LARGE_INTEGER array value.
|
||
|
||
Count - The number of elements in the array.
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the variable-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the new attribute value...
|
||
//
|
||
|
||
NtStatus = SampSetVariableAttribute(
|
||
Context,
|
||
AttributeIndex,
|
||
Count, // Qualifier contains element count
|
||
(PUCHAR)Attribute,
|
||
(Count * sizeof(LARGE_INTEGER))
|
||
);
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampGetSidArrayAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN BOOLEAN MakeCopy,
|
||
OUT PSID *SidArray,
|
||
OUT PULONG Length,
|
||
OUT PULONG Count
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to get a copy of an array of SIDs attribute or
|
||
a pointer to the attribute. If a pointer to the attribute is sought,
|
||
care must be taken to ensure the pointer is not used after it becomes
|
||
invalid. Actions that may cause an attribute pointer to become invalid
|
||
include setting an attribute value or dereferencing and then referencing
|
||
the object again.
|
||
|
||
|
||
NOTE: This routine does not define the structure of a SID array,
|
||
so this effectively is a GetRawDataAttribute routine.
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be retrieved.
|
||
|
||
MakeCopy - If TRUE, indicates that a copy of the attribute is to be made.
|
||
If FALSE, indicates a pointer to the attribute is desired without
|
||
making a copy. WARNING, if this is FALSE, the pointer is only
|
||
valid while the in-memory copy of the attribute remains in place.
|
||
Addition or replacement of any variable length attribute may
|
||
cause the attribute to be moved, and previously returned pointers
|
||
invalidated.
|
||
|
||
SidArray - Receives a pointer to the array of SIDs. If
|
||
MakeCopy was specified as TRUE, then this pointer points to a block
|
||
of memory allocated with MIDL_user_allocate() which the caller is
|
||
responsible for freeing (using MIDL_user_free()).
|
||
|
||
|
||
Count - Receives the number of elements in the array. If this value
|
||
is zero, then SidArray will be returned as NULL.
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
|
||
|
||
//
|
||
// Make the data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Get the count of array elements.
|
||
// If this is zero, then return will a null buffer pointer.
|
||
//
|
||
|
||
(*Count) = *(SampObjectAttributeQualifier( Context, AttributeIndex));
|
||
|
||
if ((*Count) == 0) {
|
||
(*SidArray) = NULL;
|
||
(*Length) = 0;
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Get the length of the attribute
|
||
//
|
||
|
||
(*Length) = SampObjectAttributeLength( Context, AttributeIndex );
|
||
|
||
|
||
|
||
|
||
//
|
||
// If we are not to allocate memory, then just return a pointer
|
||
// to the attribute.
|
||
//
|
||
|
||
if (MakeCopy == FALSE) {
|
||
(*SidArray) =
|
||
(PSID)SampObjectAttributeAddress( Context, AttributeIndex );
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Need to make a copy of the attribute
|
||
//
|
||
|
||
(*SidArray) = (PSID)MIDL_user_allocate( (*Length) );
|
||
if ((*SidArray) == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
|
||
RtlCopyMemory( (*SidArray),
|
||
SampObjectAttributeAddress( Context, AttributeIndex ),
|
||
(*Length) );
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampSetSidArrayAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN PSID Attribute,
|
||
IN ULONG Length,
|
||
IN ULONG Count
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to replace a SID array attribute in an
|
||
object's variable length attributes.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be set.
|
||
|
||
|
||
Attribute - Points to the new SID array value.
|
||
|
||
Length - Number of byte in the attribute buffer.
|
||
|
||
Count - Number of SIDs in the array.
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the variable-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the new attribute value...
|
||
//
|
||
|
||
NtStatus = SampSetVariableAttribute(
|
||
Context,
|
||
AttributeIndex,
|
||
Count, // Qualifier contains element count
|
||
(PUCHAR)Attribute,
|
||
Length
|
||
);
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampGetLogonHoursAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN BOOLEAN MakeCopy,
|
||
OUT PLOGON_HOURS LogonHours
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to get a copy of a logon hours attribute or
|
||
a pointer to the attribute. If a pointer to the attribute is sought,
|
||
care must be taken to ensure the pointer is not used after it becomes
|
||
invalid. Actions that may cause an attribute pointer to become invalid
|
||
include setting an attribute value or dereferencing and then referencing
|
||
the object again.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be retrieved.
|
||
|
||
MakeCopy - If TRUE, indicates that a copy of the attribute is to be made.
|
||
If FALSE, indicates a pointer to the attribute is desired without
|
||
making a copy. WARNING, if this is FALSE, the pointer is only
|
||
valid while the in-memory copy of the attribute remains in place.
|
||
Addition or replacement of any variable length attribute may
|
||
cause the attribute to be moved, and previously returned pointers
|
||
invalidated.
|
||
|
||
LogonHours - Receives the logon hours information. If MakeCopy is TRUE
|
||
then the bitmap pointed to from within this structure will be a copy
|
||
of the attribute and must be deallocated uing MIDL_user_free().
|
||
Otherwise, this same field will point to the bitmap in the on-disk
|
||
buffer.
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
ULONG
|
||
Length,
|
||
Units;
|
||
|
||
|
||
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
|
||
|
||
//
|
||
// Make the data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Get the time units.
|
||
// If this is zero, then return will a null buffer pointer.
|
||
//
|
||
|
||
Units = *(SampObjectAttributeQualifier( Context, AttributeIndex));
|
||
ASSERT(Units <= 0xFFFF);
|
||
LogonHours->UnitsPerWeek = (USHORT)Units;
|
||
|
||
if (Units == 0) {
|
||
LogonHours->LogonHours = NULL;
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// If we are not to allocate memory, then just return a pointer
|
||
// to the attribute.
|
||
//
|
||
|
||
if (MakeCopy == FALSE) {
|
||
LogonHours->LogonHours =
|
||
(PUCHAR)SampObjectAttributeAddress( Context, AttributeIndex );
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Get the length of the attribute
|
||
//
|
||
|
||
Length = SampObjectAttributeLength( Context, AttributeIndex );
|
||
ASSERT(Length <= 0xFFFF);
|
||
|
||
|
||
//
|
||
// Need to make a copy of the attribute
|
||
//
|
||
|
||
LogonHours->LogonHours =
|
||
(PUCHAR)MIDL_user_allocate( Length );
|
||
if (LogonHours->LogonHours == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
|
||
RtlCopyMemory( LogonHours->LogonHours,
|
||
SampObjectAttributeAddress( Context, AttributeIndex ),
|
||
Length );
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampSetLogonHoursAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN PLOGON_HOURS Attribute
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to replace a LOGON_HOURS attribute in an
|
||
object's variable length attributes.
|
||
|
||
UnitsPerWeek are stored in the Qualifier field of the attribute.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be set.
|
||
|
||
|
||
Attribute - Points to the new LOGON_HOURS value.
|
||
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to receive a copy of the attribute could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS NtStatus;
|
||
PUCHAR LogonHours;
|
||
ULONG Length;
|
||
USHORT UnitsPerWeek;
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
//
|
||
// Make the variable-length data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Grab the UnitsPerWeek value for the logon_hours structure.
|
||
// We use this to calculate the length of the data.
|
||
//
|
||
|
||
if ( Attribute == NULL ) {
|
||
UnitsPerWeek = 0;
|
||
LogonHours = NULL;
|
||
} else {
|
||
UnitsPerWeek = Attribute->UnitsPerWeek;
|
||
LogonHours = Attribute->LogonHours;
|
||
}
|
||
|
||
//
|
||
// Validate the data - make sure that if the units per week are non-zero
|
||
// then the logon hours buffer is non-NULL.
|
||
//
|
||
|
||
if ( (UnitsPerWeek != 0) && (LogonHours == NULL) ) {
|
||
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
//
|
||
// Calculate length of logon_hours structure
|
||
//
|
||
|
||
Length = (ULONG)((UnitsPerWeek + 7) / 8);
|
||
|
||
//
|
||
// Set the new attribute value...
|
||
//
|
||
|
||
NtStatus = SampSetVariableAttribute(
|
||
Context,
|
||
AttributeIndex,
|
||
(ULONG)UnitsPerWeek, // Qualifier contains units per week
|
||
LogonHours,
|
||
Length
|
||
);
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// private routines //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
NTSTATUS
|
||
SampValidateAttributes(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeGroup
|
||
)
|
||
|
||
/*++
|
||
|
||
Ensure specified attributes are in-memory.
|
||
If they are not, then read them from backing store.
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeGroup - identifies which kind of attributes are being
|
||
validated (SAMP_FIXED_ATTRIBUTES or SAMP_VARIABLE_ATTRIBUTES).
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The attributes are in-memory.
|
||
|
||
STATUS_NO_MEMORY - Memory could not be allocated to retrieve the
|
||
attributes.
|
||
|
||
Other values as may be returned by registry API trying to retrieve
|
||
the attributes from backing store.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
ULONG
|
||
RequiredLength,
|
||
TotalRequiredLength,
|
||
BufferLength;
|
||
|
||
PUCHAR
|
||
Buffer;
|
||
|
||
PUNICODE_STRING
|
||
KeyAttributeName;
|
||
|
||
BOOLEAN
|
||
CreatedObject = FALSE;
|
||
|
||
|
||
//
|
||
// The data might already be in memory.
|
||
//
|
||
|
||
if (AttributeGroup == SAMP_FIXED_ATTRIBUTES) {
|
||
if (SampFixedAttributesValid( Context )) {
|
||
ASSERT(Context->OnDisk != NULL);
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
} else {
|
||
|
||
ASSERT( AttributeGroup == SAMP_VARIABLE_ATTRIBUTES );
|
||
if (SampVariableAttributesValid( Context )) {
|
||
ASSERT(Context->OnDisk != NULL);
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Retrieve it from the registry, or allocate it if new.
|
||
//
|
||
|
||
|
||
NtStatus = SampGetAttributeBufferReadInfo(
|
||
Context,
|
||
AttributeGroup,
|
||
&Buffer,
|
||
&BufferLength,
|
||
&KeyAttributeName
|
||
);
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
if ( Context->RootKey != INVALID_HANDLE_VALUE ) {
|
||
|
||
//
|
||
// Account exists on disk, so read in the attributes.
|
||
//
|
||
|
||
NtStatus = SampReadRegistryAttribute( Context->RootKey,
|
||
Buffer,
|
||
BufferLength,
|
||
KeyAttributeName,
|
||
&RequiredLength
|
||
);
|
||
|
||
RequiredLength = SampDwordAlignUlong(RequiredLength);
|
||
|
||
if ( ( SampObjectInformation[Context->ObjectType].FixedStoredSeparately ) &&
|
||
( AttributeGroup == SAMP_VARIABLE_ATTRIBUTES ) ) {
|
||
|
||
//
|
||
// RequiredLength was returned to us as the length of the
|
||
// variable attributes on the disk. However, we're going
|
||
// to be using it to determine the total buffer size as well
|
||
// as to set how much of the buffer is in use, so we must add
|
||
// the size of the fixed stuff that preceeds the variable
|
||
// buffer.
|
||
//
|
||
|
||
TotalRequiredLength = RequiredLength +
|
||
SampVariableBufferOffset( Context );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Either the attribute groups are read together, or we're
|
||
// reading in the fixed attribute group. Either way, we
|
||
// already have the total size we need.
|
||
//
|
||
|
||
TotalRequiredLength = RequiredLength;
|
||
}
|
||
|
||
if ((NtStatus == STATUS_BUFFER_TOO_SMALL) ||
|
||
( NtStatus == STATUS_BUFFER_OVERFLOW ) ) {
|
||
|
||
NtStatus = SampExtendAttributeBuffer( Context, TotalRequiredLength );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
NtStatus = SampGetAttributeBufferReadInfo(
|
||
Context,
|
||
AttributeGroup,
|
||
&Buffer,
|
||
&BufferLength,
|
||
&KeyAttributeName
|
||
);
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
NtStatus = SampReadRegistryAttribute( Context->RootKey,
|
||
Buffer,
|
||
BufferLength,
|
||
KeyAttributeName,
|
||
&RequiredLength
|
||
);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// We're creating a new object.
|
||
//
|
||
// Initialize the requiredlength to the amount of the buffer
|
||
// we have used when we created the empty attributes. This will
|
||
// be the value stored in OnDiskUsed.
|
||
//
|
||
// Note OnDiskUsed is only used by operations on the variable
|
||
// length attributes.
|
||
//
|
||
|
||
TotalRequiredLength = SampVariableDataOffset(Context);
|
||
|
||
ASSERT(TotalRequiredLength <= Context->OnDiskAllocated);
|
||
|
||
CreatedObject = TRUE;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// if we read something, indicate that the corresponding buffer
|
||
// (and maybe both) are now valid.
|
||
//
|
||
// Also set the used and free information for the buffer if necessary.
|
||
//
|
||
|
||
if (NT_SUCCESS(NtStatus)) {
|
||
if (SampObjectInformation[Context->ObjectType].FixedStoredSeparately) {
|
||
|
||
//
|
||
// only one attribute group was read in
|
||
//
|
||
|
||
if (AttributeGroup == SAMP_FIXED_ATTRIBUTES) {
|
||
Context->FixedValid = TRUE;
|
||
Context->FixedDirty = FALSE;
|
||
} else {
|
||
|
||
ASSERT(AttributeGroup == SAMP_VARIABLE_ATTRIBUTES);
|
||
Context->VariableValid = TRUE;
|
||
Context->VariableDirty = FALSE;
|
||
|
||
Context->OnDiskUsed = SampDwordAlignUlong(TotalRequiredLength);
|
||
Context->OnDiskFree = Context->OnDiskAllocated -
|
||
Context->OnDiskUsed;
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Both attribute groups read in.
|
||
//
|
||
|
||
Context->FixedValid = TRUE;
|
||
Context->FixedDirty = FALSE;
|
||
|
||
Context->VariableValid = TRUE;
|
||
Context->VariableDirty = FALSE;
|
||
|
||
Context->OnDiskUsed = SampDwordAlignUlong(TotalRequiredLength);
|
||
Context->OnDiskFree = Context->OnDiskAllocated -
|
||
Context->OnDiskUsed;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(NtStatus) && !CreatedObject) {
|
||
|
||
//
|
||
// make any adjustments necessary to bring the data
|
||
// just read in up to current revision format.
|
||
//
|
||
|
||
NtStatus = SampUpgradeToCurrentRevision(
|
||
Context,
|
||
AttributeGroup,
|
||
Buffer,
|
||
RequiredLength,
|
||
&TotalRequiredLength
|
||
);
|
||
}
|
||
|
||
#ifdef SAM_DEBUG_ATTRIBUTES
|
||
if (SampDebugAttributes) {
|
||
DbgPrint("SampValidateAttributes - initialized the context :\n\n");
|
||
SampDumpAttributes(Context);
|
||
}
|
||
#endif
|
||
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampUpgradeToCurrentRevision(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeGroup,
|
||
IN OUT PUCHAR Buffer,
|
||
IN ULONG LengthOfDataRead,
|
||
IN OUT PULONG TotalRequiredLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Make any changes necessary bring attributes just read in
|
||
from disk up to the current revision level format.
|
||
|
||
When we upgrade our attribute format, we don't bother changing
|
||
all data on disk. We take a lazy update approach, and only change
|
||
the data as it is changed for other operations. This means that
|
||
data we read from disk may be from revision 1. When this is
|
||
detected, the data is copied into a current revision structure,
|
||
and a pointer to that buffer is returned.
|
||
|
||
|
||
|
||
|
||
NOTE: For future reference, GROUP and ALIAS objects have
|
||
a revision level stored as a "Qualifier" value associated
|
||
with the security descriptor attribute. The SERVER object
|
||
stores the revision level in its fixed length attributes.
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeGroup - identifies which kind of attributes are being
|
||
validated (SAMP_FIXED_ATTRIBUTES or SAMP_VARIABLE_ATTRIBUTES).
|
||
|
||
Buffer - Pointer to the buffer containing the attributes.
|
||
|
||
LengthOfDataRead - This is an important value. It must be the value
|
||
returned from the registry on the read operation. This tells us
|
||
exactly how many bytes of data were retrieved from disk.
|
||
|
||
TotalRequiredLength - Will be left unchanged if no update was
|
||
was required. If an updated was made, this will be adjusted
|
||
to reflect the new length of the data.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
LARGE_INTEGER
|
||
ZeroModifiedCount = {0,0};
|
||
PULONG
|
||
Pointer;
|
||
NTSTATUS
|
||
NtStatus = STATUS_SUCCESS;
|
||
|
||
|
||
//
|
||
// Note that Buffer points inside a buffer that is
|
||
// hung off the Context block. We don't need to re-allocate
|
||
// a new attributes buffer because we are only changing
|
||
// fixed-length attributes in this release (and the variable
|
||
// length attributes were placed beyond the end of the new
|
||
// format fixed-length data).
|
||
//
|
||
// The approach we take is to copy the current fixed-length
|
||
// contents into a temporary buffer, and then copy them back
|
||
// into the attribute buffer. This can be done with stack
|
||
// variables.
|
||
//
|
||
|
||
//
|
||
// Switch on the type of objects that have gone through revision
|
||
// changes.
|
||
//
|
||
|
||
switch (Context->ObjectType) {
|
||
case SampDomainObjectType:
|
||
|
||
//
|
||
// Domain FIXED_LENGTH attributes have had the following
|
||
// revisions:
|
||
//
|
||
// Revision 0x00010001 - NT1.0 (Revision NOT stored in )
|
||
// (record. )
|
||
// (Must ascertain revision )
|
||
// (by record length. )
|
||
//
|
||
// Revision 0x00010002 - NT1.0a (Revision is first ULONG )
|
||
// (in record. )
|
||
|
||
if (LengthOfDataRead ==
|
||
(sizeof(SAMP_V1_0_FIXED_LENGTH_DOMAIN) +
|
||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)) ) {
|
||
|
||
PSAMP_V1_0A_FIXED_LENGTH_DOMAIN
|
||
V1aFixed;
|
||
|
||
SAMP_V1_0_FIXED_LENGTH_DOMAIN
|
||
V1Fixed, *OldV1Fixed;
|
||
|
||
|
||
//
|
||
// Update from revision 0x00010001
|
||
//
|
||
// First, copy the current buffer contents into a temporary
|
||
// buffer.
|
||
//
|
||
|
||
OldV1Fixed = (PSAMP_V1_0_FIXED_LENGTH_DOMAIN)(Buffer +
|
||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
|
||
|
||
RtlMoveMemory(&V1Fixed, OldV1Fixed, sizeof(SAMP_V1_0_FIXED_LENGTH_DOMAIN));
|
||
|
||
|
||
//
|
||
// Now copy it back in the new format
|
||
//
|
||
|
||
V1aFixed = (PSAMP_V1_0A_FIXED_LENGTH_DOMAIN)OldV1Fixed;
|
||
|
||
V1aFixed->CreationTime = V1Fixed.CreationTime;
|
||
V1aFixed->ModifiedCount = V1Fixed.ModifiedCount;
|
||
V1aFixed->MaxPasswordAge = V1Fixed.MaxPasswordAge;
|
||
V1aFixed->MinPasswordAge = V1Fixed.MinPasswordAge;
|
||
V1aFixed->ForceLogoff = V1Fixed.ForceLogoff;
|
||
V1aFixed->NextRid = V1Fixed.NextRid;
|
||
V1aFixed->PasswordProperties = V1Fixed.PasswordProperties;
|
||
V1aFixed->MinPasswordLength = V1Fixed.MinPasswordLength;
|
||
V1aFixed->PasswordHistoryLength = V1Fixed.PasswordHistoryLength;
|
||
V1aFixed->ServerState = V1Fixed.ServerState;
|
||
V1aFixed->ServerRole = V1Fixed.ServerRole;
|
||
V1aFixed->UasCompatibilityRequired = V1Fixed.UasCompatibilityRequired;
|
||
|
||
|
||
//
|
||
// And initialize fields new for this revision
|
||
//
|
||
|
||
V1aFixed->Revision = SAMP_REVISION;
|
||
V1aFixed->LockoutDuration.LowPart = 0xCF1DCC00; // 30 minutes - low part
|
||
V1aFixed->LockoutDuration.HighPart = 0XFFFFFFFB; // 30 minutes - high part
|
||
V1aFixed->LockoutObservationWindow.LowPart = 0xCF1DCC00; // 30 minutes - low part
|
||
V1aFixed->LockoutObservationWindow.HighPart = 0XFFFFFFFB; // 30 minutes - high part
|
||
V1aFixed->LockoutThreshold = 0; // Disabled
|
||
|
||
if (V1aFixed->ServerRole == DomainServerRolePrimary) {
|
||
V1aFixed->ModifiedCountAtLastPromotion = V1Fixed.ModifiedCount;
|
||
} else {
|
||
V1aFixed->ModifiedCountAtLastPromotion = ZeroModifiedCount;
|
||
}
|
||
}
|
||
|
||
break; //out of switch
|
||
|
||
|
||
|
||
case SampUserObjectType:
|
||
|
||
//
|
||
// User FIXED_LENGTH attributes have had the following
|
||
// revisions:
|
||
//
|
||
// Revision 0x00010001 - NT1.0 (Revision NOT stored in )
|
||
// (record. )
|
||
// (Must ascertain revision )
|
||
// (by record length. )
|
||
//
|
||
// Revision 0x00010002 - NT1.0a (Revision is first ULONG )
|
||
// (in record. )
|
||
// Revision 0x00010002a - NT3.5 (Revision is first ULONG )
|
||
// (in record, still )
|
||
// (0x00010002. Must )
|
||
// (ascertain revison by )
|
||
// (by record length )
|
||
|
||
if (LengthOfDataRead ==
|
||
(sizeof(SAMP_V1_FIXED_LENGTH_USER) +
|
||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)) ) {
|
||
|
||
PSAMP_V1_0A_FIXED_LENGTH_USER
|
||
V1aFixed;
|
||
|
||
SAMP_V1_FIXED_LENGTH_USER
|
||
V1Fixed, *OldV1Fixed;
|
||
|
||
|
||
//
|
||
// Update from revision 0x00010001
|
||
//
|
||
// First, copy the current buffer contents into a temporary
|
||
// buffer.
|
||
//
|
||
|
||
OldV1Fixed = (PSAMP_V1_FIXED_LENGTH_USER)(Buffer +
|
||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
|
||
RtlMoveMemory(&V1Fixed, OldV1Fixed, sizeof(SAMP_V1_FIXED_LENGTH_USER));
|
||
|
||
|
||
//
|
||
// Now copy it back in the new format
|
||
//
|
||
|
||
V1aFixed = (PSAMP_V1_0A_FIXED_LENGTH_USER)OldV1Fixed;
|
||
|
||
|
||
V1aFixed->LastLogon = V1Fixed.LastLogon;
|
||
V1aFixed->LastLogoff = V1Fixed.LastLogoff;
|
||
V1aFixed->PasswordLastSet = V1Fixed.PasswordLastSet;
|
||
V1aFixed->AccountExpires = V1Fixed.AccountExpires;
|
||
V1aFixed->UserId = V1Fixed.UserId;
|
||
V1aFixed->PrimaryGroupId = V1Fixed.PrimaryGroupId;
|
||
V1aFixed->UserAccountControl = V1Fixed.UserAccountControl;
|
||
V1aFixed->CountryCode = V1Fixed.CountryCode;
|
||
V1aFixed->CodePage = V1Fixed.CodePage;
|
||
V1aFixed->BadPasswordCount = V1Fixed.BadPasswordCount;
|
||
V1aFixed->LogonCount = V1Fixed.LogonCount;
|
||
V1aFixed->AdminCount = V1Fixed.AdminCount;
|
||
|
||
//
|
||
// And initialize fields new for this revision
|
||
//
|
||
|
||
V1aFixed->Revision = SAMP_REVISION;
|
||
V1aFixed->LastBadPasswordTime = SampHasNeverTime;
|
||
V1aFixed->OperatorCount = 0;
|
||
V1aFixed->Unused2 = 0;
|
||
|
||
} else if ((LengthOfDataRead ==
|
||
(sizeof(SAMP_V1_0_FIXED_LENGTH_USER) +
|
||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)) ) &&
|
||
(AttributeGroup == SAMP_FIXED_ATTRIBUTES)) {
|
||
|
||
PSAMP_V1_0A_FIXED_LENGTH_USER
|
||
V1aFixed;
|
||
|
||
//
|
||
// Update from revision 0x00010002
|
||
//
|
||
// Just set the added field at the end to 0.
|
||
//
|
||
|
||
V1aFixed = (PSAMP_V1_0A_FIXED_LENGTH_USER)(Buffer +
|
||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
|
||
|
||
V1aFixed->OperatorCount = 0;
|
||
V1aFixed->Unused2 = 0;
|
||
}
|
||
|
||
break; //out of switch
|
||
|
||
case SampGroupObjectType:
|
||
//
|
||
// Group FIXED_LENGTH attributes have had the following
|
||
// revisions:
|
||
//
|
||
// Revision 0x00010001 - NT1.0 (Revision NOT stored in )
|
||
// (record. )
|
||
// (Must ascertain revision )
|
||
// (by first few ULONGs. )
|
||
//
|
||
// Revision 0x00010002 - NT1.0a (Revision is first ULONG )
|
||
// (in record. )
|
||
|
||
Pointer = (PULONG) (Buffer + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
|
||
|
||
//
|
||
// The old fixed length group had a RID in the first ULONG and
|
||
// an attributes field in the second. The attributes are in the
|
||
// first and last nibble of the field. Currently, the RID is in
|
||
// the second ULONG. Since all RIDs are more than one nibble,
|
||
// a rid will always have something set in the middle six nibbles.
|
||
//
|
||
|
||
if ( ( Pointer[0] != SAMP_REVISION ) &&
|
||
( ( Pointer[1] & 0x0ffffff0 ) == 0 ) ) {
|
||
|
||
PSAMP_V1_0A_FIXED_LENGTH_GROUP
|
||
V1aFixed;
|
||
|
||
SAMP_V1_FIXED_LENGTH_GROUP
|
||
V1Fixed, *OldV1Fixed;
|
||
|
||
ULONG TotalLengthRequired;
|
||
|
||
//
|
||
// Calculate the length required for the new group information.
|
||
// It is the size of the old group plus enough space for the
|
||
// new fields in the new fixed attributes.
|
||
//
|
||
|
||
TotalLengthRequired = SampDwordAlignUlong(
|
||
LengthOfDataRead +
|
||
sizeof(SAMP_V1_0A_FIXED_LENGTH_GROUP) -
|
||
sizeof(SAMP_V1_FIXED_LENGTH_GROUP)
|
||
);
|
||
|
||
|
||
NtStatus = SampExtendAttributeBuffer(
|
||
Context,
|
||
TotalLengthRequired
|
||
);
|
||
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
//
|
||
// Get the new buffer pointer
|
||
//
|
||
|
||
Buffer = Context->OnDisk;
|
||
|
||
//
|
||
// Move the variable information up to make space for the
|
||
// fixed information
|
||
//
|
||
|
||
RtlMoveMemory(
|
||
Buffer + SampFixedBufferOffset( Context ) + sizeof(SAMP_V1_0A_FIXED_LENGTH_GROUP),
|
||
Buffer + SampFixedBufferOffset( Context) + sizeof(SAMP_V1_FIXED_LENGTH_GROUP),
|
||
LengthOfDataRead - SampFixedBufferOffset( Context) - sizeof(SAMP_V1_FIXED_LENGTH_GROUP)
|
||
);
|
||
|
||
//
|
||
// Update from revision 0x00010001
|
||
//
|
||
// First, copy the current buffer contents into a temporary
|
||
// buffer.
|
||
//
|
||
|
||
OldV1Fixed = (PSAMP_V1_FIXED_LENGTH_GROUP)(Buffer +
|
||
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
|
||
|
||
RtlCopyMemory(&V1Fixed, OldV1Fixed, sizeof(SAMP_V1_FIXED_LENGTH_GROUP));
|
||
|
||
//
|
||
// Now copy it back in the new format
|
||
//
|
||
|
||
V1aFixed = (PSAMP_V1_0A_FIXED_LENGTH_GROUP)OldV1Fixed;
|
||
|
||
V1aFixed->Revision = SAMP_REVISION;
|
||
V1aFixed->Unused1 = 0;
|
||
V1aFixed->RelativeId = V1Fixed.RelativeId;
|
||
V1aFixed->Attributes = V1Fixed.Attributes;
|
||
V1aFixed->AdminCount = (V1Fixed.AdminGroup) ? TRUE : FALSE;
|
||
V1aFixed->OperatorCount = 0;
|
||
|
||
//
|
||
// Update the indicator of how long the on disk structure
|
||
// is.
|
||
//
|
||
|
||
Context->OnDiskUsed += (sizeof(SAMP_V1_0A_FIXED_LENGTH_GROUP) - sizeof(SAMP_V1_FIXED_LENGTH_GROUP));
|
||
Context->OnDiskFree = Context->OnDiskAllocated - Context->OnDiskUsed;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// The rest of the object types have not changed format
|
||
// and so need not be updated.
|
||
//
|
||
|
||
break; //out of switch
|
||
|
||
}
|
||
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
PUCHAR
|
||
SampObjectAttributeAddress(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
|
||
Retrieve the address of a variable-length attribute.
|
||
|
||
The attributes are assumed to already be in-memory.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be retrieved.
|
||
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The attributes are in-memory.
|
||
|
||
STATUS_NO_MEMORY - Memory could not be allocated to retrieve the
|
||
attributes.
|
||
|
||
Other values as may be returned by registry API trying to retrieve
|
||
the attributes from backing store.
|
||
|
||
--*/
|
||
{
|
||
|
||
PSAMP_VARIABLE_LENGTH_ATTRIBUTE
|
||
AttributeArray;
|
||
|
||
PUCHAR
|
||
AttributeAddress;
|
||
|
||
|
||
ASSERT( SampVariableAttributesValid( Context ) );
|
||
|
||
AttributeArray = (PSAMP_VARIABLE_LENGTH_ATTRIBUTE)
|
||
SampVariableArrayAddress( Context );
|
||
|
||
AttributeAddress = (PUCHAR)Context->OnDisk +
|
||
( SampVariableDataOffset( Context ) +
|
||
AttributeArray[AttributeIndex].Offset );
|
||
|
||
return( AttributeAddress );
|
||
|
||
}
|
||
|
||
|
||
|
||
ULONG
|
||
SampObjectAttributeLength(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Retrieve the length of a variable-length attribute.
|
||
|
||
|
||
The attributes are assumed to already be in-memory.
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute whose length is to be retrieved.
|
||
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
The length of the attribute (in bytes).
|
||
|
||
--*/
|
||
{
|
||
PSAMP_VARIABLE_LENGTH_ATTRIBUTE
|
||
AttributeArray;
|
||
|
||
|
||
ASSERT( SampVariableAttributesValid( Context ) );
|
||
|
||
AttributeArray = (PSAMP_VARIABLE_LENGTH_ATTRIBUTE)
|
||
SampVariableArrayAddress( Context );
|
||
|
||
return( AttributeArray[AttributeIndex].Length );
|
||
|
||
}
|
||
|
||
|
||
PULONG
|
||
SampObjectAttributeQualifier(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Retrieve the address of the qualifier field of a variable-length
|
||
attribute.
|
||
|
||
The attributes are assumed to already be in-memory.
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute whose qualifier address is to be returned.
|
||
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
The address of the specifed attribute's qualifier field.
|
||
|
||
--*/
|
||
{
|
||
PSAMP_VARIABLE_LENGTH_ATTRIBUTE
|
||
AttributeArray;
|
||
|
||
|
||
ASSERT( SampVariableAttributesValid( Context ) );
|
||
|
||
AttributeArray = (PSAMP_VARIABLE_LENGTH_ATTRIBUTE)
|
||
SampVariableArrayAddress( Context );
|
||
|
||
return( &(AttributeArray[AttributeIndex].Qualifier) );
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SampGetAttributeBufferReadInfo(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeGroup,
|
||
OUT PUCHAR *Buffer,
|
||
OUT PULONG BufferLength,
|
||
OUT PUNICODE_STRING *KeyAttributeName
|
||
)
|
||
|
||
/*++
|
||
|
||
Get attribute buffer information needed to read data from
|
||
backing store.
|
||
|
||
If there is currently no attribute buffer, then allocate one.
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeGroup - Indicates which attribute grouping you are
|
||
interested in. This is only interesting if the fixed and
|
||
variable-length attributes are stored separately.
|
||
|
||
Buffer - Receives a pointer to the beginning of the appropriate
|
||
buffer (fixed or variable). This will be dword aligned.
|
||
If the attributes are stored together, this will point
|
||
to the beginning of the fixed-length attributes.
|
||
|
||
BufferLength - Receives the number of bytes in the buffer.
|
||
|
||
KeyAttributeName - Receives a pointer to the unicode name of the
|
||
attribute to read the attributes from.
|
||
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The attributes have been read.
|
||
|
||
STATUS_NO_MEMORY - Memory could not be allocated to receive the
|
||
data from disk.
|
||
|
||
Other values as may be returned reading from disk.
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus = STATUS_SUCCESS;
|
||
|
||
|
||
//
|
||
// If the context block currently has no buffer info, then
|
||
// "extend" (create) it so we can return buffer information.
|
||
//
|
||
|
||
if (Context->OnDiskAllocated == 0) {
|
||
|
||
NtStatus = SampExtendAttributeBuffer(
|
||
Context,
|
||
SAMP_MINIMUM_ATTRIBUTE_ALLOC
|
||
);
|
||
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Get the buffer address and length
|
||
//
|
||
|
||
if (SampObjectInformation[Context->ObjectType].FixedStoredSeparately) {
|
||
|
||
//
|
||
// stored separately. Address and length is dependent upon
|
||
// what is being asked for. Source registry attribute name
|
||
// is also.
|
||
//
|
||
|
||
if (AttributeGroup == SAMP_FIXED_ATTRIBUTES) {
|
||
(*Buffer) = Context->OnDisk;
|
||
(*BufferLength) = SampVariableBufferOffset( Context );
|
||
(*KeyAttributeName) = &SampFixedAttributeName;
|
||
} else {
|
||
(*Buffer) = SampVariableBufferAddress( Context );
|
||
(*BufferLength) = SampVariableBufferLength( Context );
|
||
(*KeyAttributeName) = &SampVariableAttributeName;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Attributes stored together - doesn't matter which is being
|
||
// asked for.
|
||
//
|
||
|
||
(*Buffer) = Context->OnDisk;
|
||
(*BufferLength) = Context->OnDiskAllocated;
|
||
(*KeyAttributeName) = &SampCombinedAttributeName;
|
||
}
|
||
|
||
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampExtendAttributeBuffer(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG NewSize
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This routine extends (or creates) an attribute buffer by allocating
|
||
a larger one. It then copies the existing buffer's contents into
|
||
the new buffer, if there is an existing buffer.
|
||
|
||
If a new buffer can not be allocated, then the context block is
|
||
returned with the old buffer intact.
|
||
|
||
If this call succeeds, the buffer will be at least as large as
|
||
that asked for (and perhaps larger).
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
NewSize - The number of bytes to allocate for the new buffer.
|
||
This value can not be less than the number of bytes currently
|
||
in use.
|
||
|
||
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The attributes are in-memory.
|
||
|
||
STATUS_NO_MEMORY - Memory could not be allocated to retrieve the
|
||
attributes.
|
||
|
||
Other values as may be returned by registry API trying to retrieve
|
||
the attributes from backing store.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PUCHAR
|
||
OldBuffer;
|
||
|
||
ULONG
|
||
AllocationSize;
|
||
|
||
|
||
#if DBG
|
||
if ( Context->VariableValid ) {
|
||
ASSERT(NewSize >= Context->OnDiskUsed);
|
||
}
|
||
#endif
|
||
|
||
|
||
//
|
||
// Is an allocation necessary?
|
||
//
|
||
|
||
if (NewSize <= Context->OnDiskAllocated) {
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
OldBuffer = Context->OnDisk;
|
||
|
||
|
||
//
|
||
// Pad the extend to allow for future edits efficiently.
|
||
//
|
||
|
||
AllocationSize = SampDwordAlignUlong(NewSize + SAMP_MINIMUM_ATTRIBUTE_PAD);
|
||
Context->OnDisk = RtlAllocateHeap(
|
||
RtlProcessHeap(), 0,
|
||
AllocationSize
|
||
);
|
||
|
||
if (Context->OnDisk == NULL) {
|
||
Context->OnDisk = OldBuffer;
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the new allocated size
|
||
|
||
Context->OnDiskAllocated = AllocationSize;
|
||
|
||
//
|
||
// If there was no buffer originally, then zero the new buffer, mark
|
||
// it as being invalid, and return.
|
||
//
|
||
|
||
if (OldBuffer == NULL) {
|
||
|
||
RtlZeroMemory( (PVOID)Context->OnDisk, AllocationSize );
|
||
|
||
Context->FixedDirty = TRUE;
|
||
Context->VariableDirty = TRUE;
|
||
Context->FixedValid = FALSE;
|
||
Context->VariableValid = FALSE;
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the free size. Note that this information is only set if
|
||
// the variable data is valid.
|
||
// Used size remains the same.
|
||
//
|
||
|
||
if (Context->VariableValid == TRUE) {
|
||
Context->OnDiskFree = AllocationSize - Context->OnDiskUsed;
|
||
ASSERT(Context->OnDiskUsed == SampDwordAlignUlong(Context->OnDiskUsed));
|
||
}
|
||
|
||
|
||
//
|
||
// There was an old buffer (or else we would have exited earlier).
|
||
// If any data in it was valid, copy it to the new buffer. Free the
|
||
// old buffer.
|
||
//
|
||
|
||
if ( Context->FixedValid ) {
|
||
|
||
RtlCopyMemory(
|
||
Context->OnDisk,
|
||
OldBuffer,
|
||
SampFixedBufferLength( Context ) + SampFixedBufferOffset( Context )
|
||
);
|
||
}
|
||
|
||
//
|
||
// Note: in thise case we may copy the fixed data twice, since if the
|
||
// variable data is not stored separately then SampVariableBufferOffset
|
||
// is zero.
|
||
//
|
||
|
||
if ( Context->VariableValid ) {
|
||
|
||
RtlCopyMemory(
|
||
SampVariableBufferAddress( Context ),
|
||
OldBuffer + SampVariableBufferOffset( Context ),
|
||
Context->OnDiskUsed - SampVariableBufferOffset( Context )
|
||
);
|
||
}
|
||
|
||
RtlFreeHeap( RtlProcessHeap(), 0, OldBuffer );
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampReadRegistryAttribute(
|
||
IN HANDLE Key,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG BufferLength,
|
||
IN PUNICODE_STRING AttributeName,
|
||
OUT PULONG RequiredLength
|
||
)
|
||
|
||
/*++
|
||
|
||
|
||
Retrieve the address of a variable-length attribute.
|
||
|
||
The attributes are assumed to already be in-memory.
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Key - Handle to the key whose attribute is to be read.
|
||
|
||
Buffer - Pointer to the buffer to receive the information.
|
||
|
||
BufferLength - Length of the buffer receiving the information.
|
||
|
||
AttributeName - The name of the attribute.
|
||
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - Successful completion.
|
||
|
||
|
||
STATUS_BUFFER_TOO_SMALL - The data could not be read because the
|
||
buffer was too small.
|
||
|
||
Other values as may be returned by registry API trying to retrieve
|
||
the attribute from backing store.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
|
||
//
|
||
// Try to read the attribute
|
||
//
|
||
|
||
NtStatus = NtQueryValueKey( Key,
|
||
AttributeName, //ValueName,
|
||
KeyValuePartialInformation, //KeyValueInformationClass
|
||
(PVOID)Buffer,
|
||
BufferLength,
|
||
RequiredLength
|
||
);
|
||
|
||
return(NtStatus);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SampSetVariableAttribute(
|
||
IN PSAMP_OBJECT Context,
|
||
IN ULONG AttributeIndex,
|
||
IN ULONG Qualifier,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG Length
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This API is used to set a new attribute value. The new attribute
|
||
value may be longer, shorter, or the same size as the current
|
||
attribute. The data in the attribute buffer will be shifted to
|
||
make room for a larger attribute value or to fill in room left by
|
||
a smaller attribute value.
|
||
|
||
PERFORMANCE CONCERN: If you have a lot of attributes to set, it
|
||
is worthwhile to start with the smallest indexed attribute
|
||
and work up to the largest indexed attribute.
|
||
|
||
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
AttributeIndex - Indicates the index (into the variable length attribute
|
||
array) of the attribute to be set. Typically, all attributes beyond
|
||
this one will have their data shifted.
|
||
|
||
Buffer - The address of the buffer containing the new attribute value.
|
||
May be NULL if Length is zero.
|
||
|
||
Length - The length (in bytes) of the new attribute value.
|
||
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The service completed successfully.
|
||
|
||
STATUS_NO_MEMORY - Memory to expand the attribute buffer could not
|
||
be allocated.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS
|
||
NtStatus;
|
||
|
||
|
||
ULONG
|
||
OriginalAttributeLength,
|
||
AdditionalSpaceNeeded,
|
||
NewBufferLength,
|
||
MaximumAttributeIndex,
|
||
MoveLength,
|
||
i;
|
||
|
||
LONG
|
||
OffsetDelta;
|
||
|
||
PSAMP_VARIABLE_LENGTH_ATTRIBUTE
|
||
AttributeArray;
|
||
|
||
|
||
PUCHAR
|
||
NewStart,
|
||
OriginalStart;
|
||
|
||
//
|
||
// Make sure the requested attribute exists for the specified
|
||
// object type.
|
||
//
|
||
|
||
SampValidateAttributeIndex( Context, AttributeIndex );
|
||
|
||
|
||
|
||
//
|
||
// Make the data valid
|
||
//
|
||
|
||
NtStatus = SampValidateAttributes( Context, SAMP_VARIABLE_ATTRIBUTES );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate a new buffer if necessary
|
||
//
|
||
|
||
OriginalAttributeLength = SampObjectAttributeLength(Context, AttributeIndex);
|
||
|
||
if (OriginalAttributeLength < Length) {
|
||
|
||
AdditionalSpaceNeeded = Length - OriginalAttributeLength;
|
||
|
||
if (Context->OnDiskFree < AdditionalSpaceNeeded) {
|
||
|
||
NewBufferLength = Context->OnDiskUsed + AdditionalSpaceNeeded;
|
||
ASSERT(NewBufferLength > Context->OnDiskAllocated);
|
||
|
||
NtStatus = SampExtendAttributeBuffer( Context, NewBufferLength );
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
return(NtStatus);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get the address of the attribute array.
|
||
//
|
||
|
||
AttributeArray = SampVariableArrayAddress( Context );
|
||
|
||
|
||
//
|
||
// Now shift following attribute values
|
||
//
|
||
|
||
OffsetDelta = (LONG)(SampDwordAlignUlong(Length) -
|
||
SampDwordAlignUlong(OriginalAttributeLength));
|
||
|
||
MaximumAttributeIndex = SampVariableAttributeCount( Context );
|
||
|
||
if ((OffsetDelta != 0) && (AttributeIndex+1 < MaximumAttributeIndex)) {
|
||
|
||
//
|
||
// Shift all attributes above this one up or down by the OffsetDelta
|
||
//
|
||
|
||
MoveLength = Context->OnDiskUsed -
|
||
( SampVariableDataOffset( Context ) +
|
||
AttributeArray[AttributeIndex+1].Offset );
|
||
|
||
//
|
||
// Shift the data (if there is any)
|
||
//
|
||
|
||
if (MoveLength != 0) {
|
||
|
||
OriginalStart = SampObjectAttributeAddress( Context, AttributeIndex+1);
|
||
NewStart = (PUCHAR)(OriginalStart + OffsetDelta);
|
||
RtlMoveMemory( NewStart, OriginalStart, MoveLength );
|
||
}
|
||
|
||
|
||
//
|
||
// Adjust the offset pointers
|
||
//
|
||
|
||
for ( i=AttributeIndex+1; i<MaximumAttributeIndex; i++) {
|
||
AttributeArray[i].Offset =
|
||
(ULONG)(OffsetDelta + (LONG)(AttributeArray[i].Offset));
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Now set the length and qualifier, and copy in the new attribute value
|
||
// (if it is non-zero length)
|
||
//
|
||
|
||
AttributeArray[AttributeIndex].Length = Length;
|
||
AttributeArray[AttributeIndex].Qualifier = Qualifier;
|
||
|
||
if (Length != 0) {
|
||
|
||
RtlCopyMemory( SampObjectAttributeAddress( Context, AttributeIndex ),
|
||
Buffer,
|
||
Length
|
||
);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Adjust the Used and Free values
|
||
//
|
||
|
||
Context->OnDiskUsed += OffsetDelta;
|
||
Context->OnDiskFree -= OffsetDelta;
|
||
|
||
ASSERT(Context->OnDiskFree == Context->OnDiskAllocated - Context->OnDiskUsed);
|
||
|
||
//
|
||
// Mark the variable attributes dirty
|
||
//
|
||
|
||
Context->VariableDirty = TRUE;
|
||
|
||
|
||
#ifdef SAM_DEBUG_ATTRIBUTES
|
||
if (SampDebugAttributes) {
|
||
DbgPrint("SampSetVariableAttribute %d to length %#x, qualifier %#x:\n", AttributeIndex, Length, Qualifier);
|
||
SampDumpAttributes(Context);
|
||
}
|
||
#endif
|
||
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
SampFreeAttributeBuffer(
|
||
IN PSAMP_OBJECT Context
|
||
)
|
||
|
||
/*++
|
||
|
||
|
||
Free the buffer used to keep in-memory copies of the on-disk
|
||
object attributes.
|
||
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to the object context whose buffer is to
|
||
be freed.
|
||
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
#if DBG
|
||
if ( Context->FixedValid ) { ASSERT(Context->FixedDirty == FALSE); }
|
||
if ( Context->VariableValid) { ASSERT(Context->VariableDirty == FALSE); }
|
||
ASSERT(Context->OnDisk != NULL);
|
||
ASSERT(Context->OnDiskAllocated != 0);
|
||
#endif
|
||
|
||
RtlFreeHeap( RtlProcessHeap(), 0, Context->OnDisk );
|
||
|
||
Context->OnDisk = NULL;
|
||
Context->OnDiskAllocated = 0;
|
||
|
||
//
|
||
// Mark all attributes as invalid
|
||
//
|
||
|
||
Context->FixedValid = FALSE;
|
||
Context->VariableValid = FALSE;
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
#ifdef SAM_DEBUG_ATTRIBUTES
|
||
VOID
|
||
SampDumpAttributes(
|
||
IN PSAMP_OBJECT Context
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This is a debug-only API to dump out the attributes for a context
|
||
to the kernel debugger.
|
||
|
||
Parameters:
|
||
|
||
Context - Pointer to an object context block.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ULONG Index;
|
||
PSAMP_OBJECT_INFORMATION ObjectTypeInfo = &SampObjectInformation[Context->ObjectType];
|
||
PSAMP_VARIABLE_LENGTH_ATTRIBUTE AttributeArray;
|
||
|
||
AttributeArray = (PSAMP_VARIABLE_LENGTH_ATTRIBUTE)
|
||
SampVariableArrayAddress( Context );
|
||
|
||
|
||
DbgPrint("Dumping context 0x%x\n", Context);
|
||
DbgPrint("\n");
|
||
DbgPrint("TYPE INFO\n");
|
||
DbgPrint("Object type name = %wZ\n", &ObjectTypeInfo->ObjectTypeName);
|
||
DbgPrint("Fixed stored separately = %s\n", ObjectTypeInfo->FixedStoredSeparately ? "TRUE" : "FALSE");
|
||
DbgPrint("Fixed attributes offset = %#x\n", ObjectTypeInfo->FixedAttributesOffset);
|
||
DbgPrint("Fixed attributes size = %#x\n", ObjectTypeInfo->FixedLengthSize);
|
||
DbgPrint("Variable buffer offset = %#x\n", ObjectTypeInfo->VariableBufferOffset);
|
||
DbgPrint("Variable array offset = %#x\n", ObjectTypeInfo->VariableArrayOffset);
|
||
DbgPrint("Variable data offset = %#x\n", ObjectTypeInfo->VariableDataOffset);
|
||
DbgPrint("Variable attribute count = %d\n", ObjectTypeInfo->VariableAttributeCount);
|
||
DbgPrint("\n");
|
||
DbgPrint("INSTANCE INFO\n");
|
||
DbgPrint("RootName = %wZ\n", &Context->RootName);
|
||
DbgPrint("Fixed Valid = %s\n", Context->FixedValid ? "TRUE" : "FALSE");
|
||
DbgPrint("Variable Valid = %s\n", Context->VariableValid ? "TRUE" : "FALSE");
|
||
DbgPrint("Fixed Dirty = %s\n", Context->FixedDirty ? "TRUE" : "FALSE");
|
||
DbgPrint("Variable Dirty = %s\n", Context->VariableDirty ? "TRUE" : "FALSE");
|
||
DbgPrint("OnDiskAllocated = %#x\n", Context->OnDiskAllocated);
|
||
DbgPrint("OnDiskUsed = %#x\n", Context->OnDiskUsed);
|
||
DbgPrint("OnDiskFree = %#x\n", Context->OnDiskFree);
|
||
DbgPrint("\n");
|
||
|
||
if ( Context->VariableValid ) {
|
||
|
||
for (Index = 0; Index < ObjectTypeInfo->VariableAttributeCount; Index ++) {
|
||
|
||
DbgPrint("Attr %d: Qualifier = %#6x, Offset = %#6x, Length = %#6x\n",
|
||
Index,
|
||
AttributeArray[Index].Qualifier,
|
||
AttributeArray[Index].Offset,
|
||
AttributeArray[Index].Length
|
||
);
|
||
SampDumpData(SampObjectAttributeAddress(Context, Index),
|
||
SampObjectAttributeLength(Context, Index));
|
||
}
|
||
}
|
||
|
||
DbgPrint("\n\n");
|
||
}
|
||
|
||
|
||
VOID
|
||
SampDumpData(
|
||
IN PVOID Buffer,
|
||
IN ULONG Length
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
This is a debug-only API to dump out a buffer in hex
|
||
|
||
Parameters:
|
||
|
||
Buffer - Pointer to data
|
||
|
||
Length - number of bytes in data
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ULONG Index;
|
||
|
||
for (Index = 0; Index < Length; Index ++) {
|
||
|
||
ULONG Value = (ULONG)(((PBYTE)Buffer)[Index]);
|
||
|
||
if ((Index % 16) == 0) {
|
||
DbgPrint("\n ");
|
||
}
|
||
|
||
DbgPrint("%02x ", Value & 0xff);
|
||
}
|
||
|
||
if (Length > 0) {
|
||
DbgPrint("\n\n");
|
||
}
|
||
}
|
||
|
||
#endif
|