2189 lines
47 KiB
C
2189 lines
47 KiB
C
/*++
|
|
|
|
Copyright (C) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dslayer.c
|
|
|
|
Abstract:
|
|
|
|
Contains SAM Private API Routines to access the DS
|
|
These provide a simplified API, and hide most of the
|
|
underlying complexity to set up the parameters to a DS call
|
|
and parse the resulting result.
|
|
|
|
Author:
|
|
MURLIS
|
|
|
|
Revision History
|
|
|
|
5-14-96 Murlis Created
|
|
|
|
--*/
|
|
|
|
|
|
#include <samsrvp.h>
|
|
#include <duapi.h>
|
|
#include <dslayer.h>
|
|
#include <mappings.h>
|
|
#include <objids.h>
|
|
#include <filtypes.h>
|
|
#include <fileno.h>
|
|
|
|
//
|
|
// Define FILENO for SAM
|
|
//
|
|
|
|
|
|
#define FILENO FILENO_SAM
|
|
|
|
//++
|
|
//++
|
|
//++ IMPORTANT NOTE REGARDING SID's and RID's
|
|
//++
|
|
//++ The DS can choose to either store the entire SID's or only
|
|
//++ the Rid's for account objects. In case Entire SID's are stored
|
|
//++ the DS layer handles the Mapping between the attribute type and
|
|
//++ and value of SID and those of Rid for account objects. This is
|
|
//++ done within SampDsToSamAttrBlock and SampSamToDsAttrBlock.
|
|
//++
|
|
//++
|
|
//++ Irrespective of which way we go the Rid and Sid are both
|
|
//++ attributes defined in the schema.
|
|
//++
|
|
//++ If we go the way the of storing Sid's then the DS functions
|
|
//++ should call the Convert AttrBlock functions using the MAP_SID_RID
|
|
//++ conversion Flag, and Lookup Object By Rid, should actually use
|
|
//++ the Sid Attribute.
|
|
//++
|
|
//++
|
|
|
|
|
|
|
|
|
|
//
|
|
// Forward declarations of Private Samp Routines used in this file only
|
|
//
|
|
|
|
|
|
PVOID
|
|
DSAlloc(
|
|
IN ULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
SampMapDsErrorToNTStatus(
|
|
ULONG RetValue
|
|
);
|
|
|
|
|
|
void
|
|
BuildStdCommArg(
|
|
IN OUT COMMARG * pCommArg
|
|
);
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SampDsSetNewSidAttribute(
|
|
IN PSID DomainSid,
|
|
IN ULONG ConversionFlags,
|
|
IN ATTR *RidAttr,
|
|
IN OUT ATTR *SidAttr
|
|
);
|
|
|
|
NTSTATUS
|
|
SampDsCopyAttributeValue(
|
|
IN ATTR * Src,
|
|
IN OUT ATTR * Dst
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
BuildStdCommArg(
|
|
IN OUT COMMARG * pCommArg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills a COMMARG structue with the standard set of options
|
|
|
|
Arguments:
|
|
pCommArg - Pointer to the COMMARG structure
|
|
|
|
Return Values:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
SVCCNTL * pSvcCntl;
|
|
|
|
SAMTRACE("BuildStdCommonArg");
|
|
|
|
// Get the address of the service control structure
|
|
pSvcCntl = &(pCommArg->Svccntl);
|
|
|
|
|
|
// Setup the service control structure
|
|
pSvcCntl->preferChaining = FALSE;
|
|
pSvcCntl->chainingProhibited = TRUE;
|
|
pSvcCntl->localScope = TRUE;
|
|
pSvcCntl->dontUseCopy = FALSE;
|
|
pSvcCntl->dontDerefAlias = TRUE;
|
|
pSvcCntl->makeDeletionsAvail = FALSE;
|
|
pSvcCntl->fUnicodeSupport = TRUE;
|
|
|
|
// Setup the CommArgs part of the ReadArg Strucure
|
|
pCommArg->Opstate.nameRes = OP_NAMERES_NOT_STARTED;
|
|
pCommArg->aliasRDN = 0;
|
|
pCommArg->pReserved = NULL;
|
|
pCommArg->PagedResult.fPresent = FALSE;
|
|
pCommArg->PagedResult.pRestart = NULL;
|
|
pCommArg->ulSizeLimit = SAMP_DS_SIZE_LIMIT;
|
|
pCommArg->SortAttr = 0;
|
|
pCommArg->Delta = 0;
|
|
pCommArg->fForwardSeek = TRUE;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SampDsInitialize()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the DS system
|
|
starts up DS.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Values:
|
|
Any values from DsInitialize
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
SAMTRACE("SampDsInitialize");
|
|
|
|
// Start up the DS
|
|
Status = DsInitialize();
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampDsUninitialize()
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Initiates a clean shut down of the DS
|
|
|
|
Arguments:
|
|
None
|
|
Return codes:
|
|
Any returned by DSUninitialize
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
SAMTRACE("SampDsUninitialize");
|
|
|
|
Status = DsUninitialize();
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SampDsRead(
|
|
IN DSNAME * Object,
|
|
IN ULONG Flags,
|
|
IN SAMP_OBJECT_TYPE ObjectType,
|
|
IN ATTRBLOCK * AttributesToRead,
|
|
OUT ATTRBLOCK * AttributeValues
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read attributes of an object from the DS
|
|
|
|
Argumants:
|
|
Object -- Pointer to Dist Name, which sepcifies object to read
|
|
Flags -- To control operation of routine
|
|
ObjectType -- Specifies the type of the object
|
|
AttributesToRead -- Specfies the attributes to read
|
|
AttributeValues -- Returned value of the attributes
|
|
|
|
Return Values:
|
|
|
|
STATUS_SUCCESS on successful completion
|
|
DS return codes mapped to NT_STATUS as in SampMapDSErrorToNTStatus
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ENTINFSEL EntInf;
|
|
READARG ReadArg;
|
|
COMMARG *pCommArg;
|
|
ULONG RetValue;
|
|
READRES * pReadRes;
|
|
ATTRBLOCK *AttrBlockForDs, * ConvertedAttrBlock;
|
|
|
|
SAMTRACE("SampDsRead");
|
|
|
|
//
|
|
// Asserts and parameter validation
|
|
//
|
|
|
|
ASSERT(Object!=NULL);
|
|
ASSERT(AttributesToRead!=NULL);
|
|
ASSERT(AttributeValues != NULL);
|
|
ASSERT(AttributesToRead->attrCount > 0);
|
|
|
|
|
|
// Perform lazy thread and transaction initialization.
|
|
Status = SampMaybeBeginDsTransaction(SampWriteLock);
|
|
|
|
if (Status!= STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// Translate the attribute types in Attrblock to map between
|
|
// SAM and DS attributes
|
|
//
|
|
|
|
Status = SampSamToDsAttrBlock(
|
|
ObjectType, // Object Type
|
|
AttributesToRead, // Attributes To Convert
|
|
( MAP_RID_TO_SID
|
|
| MAP_ATTRIBUTE_TYPES
|
|
| REALLOC_IN_DSMEMORY ), // Conversion Flags
|
|
NULL, // Domain Sid
|
|
&(EntInf.AttrTypBlock)
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Setup up the ENTINFSEL structure
|
|
//
|
|
|
|
EntInf.attSel = EN_ATTSET_LIST;
|
|
EntInf.infoTypes = EN_INFOTYPES_TYPES_VALS;
|
|
|
|
//
|
|
// Build the commarg structure
|
|
//
|
|
|
|
pCommArg = &(ReadArg.CommArg);
|
|
BuildStdCommArg(pCommArg);
|
|
|
|
//
|
|
// Setup the Read Arg Structure
|
|
//
|
|
|
|
ReadArg.pObject = Object;
|
|
ReadArg.pSel = & EntInf;
|
|
|
|
//
|
|
// Make the DS call
|
|
//
|
|
|
|
RetValue = DirRead(& ReadArg, & pReadRes);
|
|
|
|
//
|
|
// Map the RetValue to a NT Status code
|
|
//
|
|
|
|
Status = SampMapDsErrorToNTStatus(RetValue);
|
|
|
|
if (Status!= STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// Translate attribute types back from DS to SAM
|
|
//
|
|
|
|
Status = SampDsToSamAttrBlock(
|
|
ObjectType,
|
|
&(pReadRes->entry.AttrBlock),
|
|
( MAP_ATTRIBUTE_TYPES | MAP_SID_TO_RID ),
|
|
AttributeValues
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
|
|
|
|
|
|
|
|
Error:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SampDsSetAttributes(
|
|
IN DSNAME * Object,
|
|
IN ULONG Operation,
|
|
IN SAMP_OBJECT_TYPE ObjectType,
|
|
IN ATTRBLOCK * AttributeList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set an Object's attributes
|
|
|
|
Arguments:
|
|
|
|
Object Specifies the DS Object
|
|
Operation Controls operation of routine
|
|
ObjectType SAM Object Type for attribute Type conversion
|
|
AttributeList Specifies the attributes to Modify
|
|
|
|
Return Values:
|
|
STATUS_SUCCESS on succesful completion
|
|
STATUS_NO_MEMORY - if failed to allocate memory
|
|
DS return codes mapped to NT_STATUS as in SampMapDSErrorToNTStatus
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ATTRMODLIST * AttrModList = NULL;
|
|
MODIFYARG ModifyArg;
|
|
ATTRMODLIST * CurrentMod, * NextMod, *LastMod;
|
|
ULONG Index;
|
|
COMMARG *pCommArg;
|
|
ULONG RetValue;
|
|
UCHAR Choice;
|
|
ULONG ModCount = 0;
|
|
|
|
|
|
SAMTRACE("SampDsSetAttributes");
|
|
|
|
//
|
|
// Asserts and parameter validation
|
|
//
|
|
|
|
ASSERT(Object!=NULL);
|
|
ASSERT(AttributeList != NULL);
|
|
ASSERT(AttributeList->attrCount > 0);
|
|
|
|
// Perform lazy thread and transaction initialization.
|
|
Status = SampMaybeBeginDsTransaction(SampWriteLock);
|
|
|
|
if (Status!= STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// Setup our Choice
|
|
//
|
|
|
|
if (Operation == ADD_VALUE)
|
|
Choice = AT_CHOICE_ADD_VALUES;
|
|
|
|
else if (Operation == REMOVE_VALUE)
|
|
Choice = AT_CHOICE_REMOVE_VALUES;
|
|
|
|
else if (Operation == REMOVE_ATT)
|
|
Choice = AT_CHOICE_REMOVE_ATT;
|
|
|
|
else if (Operation == REPLACE_ATT)
|
|
Choice = AT_CHOICE_REPLACE_ATT;
|
|
|
|
else
|
|
Choice = AT_CHOICE_REPLACE_ATT;
|
|
|
|
|
|
//
|
|
// Allocate enough memory in AttrModList to hold the contents of
|
|
// AttrBlock. First such structure is specified in ModifyArg itself
|
|
//
|
|
|
|
AttrModList = (ATTRMODLIST *) DSAlloc(
|
|
(AttributeList->attrCount -1)
|
|
* sizeof(ATTRMODLIST)
|
|
);
|
|
if (AttrModList==NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the Linked Attribute Modification List
|
|
// required for the DS call
|
|
//
|
|
|
|
CurrentMod = &(ModifyArg.FirstMod);
|
|
NextMod = AttrModList;
|
|
LastMod = NULL;
|
|
|
|
for (Index = 0; Index < AttributeList->attrCount; Index++)
|
|
{
|
|
ULONG DsAttrTyp;
|
|
|
|
//
|
|
// MAP the attribute Type from DS to SAM
|
|
//
|
|
DsAttrTyp = SampDsAttrFromSamAttr(
|
|
ObjectType,
|
|
AttributeList->pAttr[Index].attrTyp
|
|
);
|
|
|
|
//
|
|
// Skip over any Rid Attribute
|
|
//
|
|
if (DsAttrTyp == SampDsAttrFromSamAttr(
|
|
SampUnknownObjectType,
|
|
SAMP_UNKNOWN_OBJECTRID
|
|
))
|
|
{
|
|
|
|
//
|
|
// We will not allow modifications of Rid's
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Setup the Choice
|
|
//
|
|
|
|
CurrentMod->choice = Choice;
|
|
|
|
//
|
|
// Copy over the ATTR Type
|
|
//
|
|
CurrentMod->AttrInf.attrTyp = DsAttrTyp;
|
|
|
|
//
|
|
// Copy Over the Attribute Value
|
|
//
|
|
|
|
Status = SampDsCopyAttributeValue(
|
|
&(AttributeList->pAttr[Index]),
|
|
&(CurrentMod->AttrInf)
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// Setup the chaining. AttrModList is suposed to be a linked list, though
|
|
// for effciency purposes we allocated a single block
|
|
//
|
|
|
|
LastMod = CurrentMod;
|
|
CurrentMod->pNextMod = NextMod;
|
|
CurrentMod = CurrentMod->pNextMod;
|
|
NextMod = NextMod +1 ;
|
|
|
|
//
|
|
// Keep track of Count of Modifications we pass to DS, as we skip over RId etc
|
|
//
|
|
ModCount++;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the last pointer in the chain to NULL
|
|
//
|
|
|
|
if (LastMod)
|
|
LastMod->pNextMod = NULL;
|
|
else
|
|
|
|
{
|
|
//
|
|
// This Means we have nothing to modify
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto Error;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Setup the Common Args structure
|
|
//
|
|
|
|
pCommArg = &(ModifyArg.CommArg);
|
|
BuildStdCommArg(pCommArg);
|
|
|
|
//
|
|
// Setup the MODIFY ARG structure
|
|
//
|
|
|
|
ModifyArg.pObject = Object;
|
|
ModifyArg.count = (USHORT) ModCount;
|
|
|
|
//
|
|
// Make the DS call
|
|
//
|
|
|
|
RetValue = DirModifyEntry(&ModifyArg);
|
|
|
|
//
|
|
// Map the return code to an NT status
|
|
//
|
|
|
|
Status = SampMapDsErrorToNTStatus(RetValue);
|
|
|
|
|
|
Error:
|
|
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SampDsCreateObject(
|
|
IN DSNAME *Object,
|
|
SAMP_OBJECT_TYPE ObjectType,
|
|
IN ATTRBLOCK *AttributesToSet,
|
|
IN OPTIONAL PSID DomainSid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create Object in the DS
|
|
|
|
Arguments:
|
|
|
|
|
|
Object -- DSNAME of the object to be created
|
|
|
|
ObjectType -- one of
|
|
|
|
SampServerObjectType
|
|
SampDomainObjectType
|
|
SampGroupObjectType
|
|
SampUserObjectType
|
|
SampAliasObjectType
|
|
|
|
|
|
AttributesToSet -- Allows the caller to pass in an
|
|
attribute block to to Set at Object creation time
|
|
itself. Useful as this allows one to save a JET
|
|
write. Also the attributes are set in the same
|
|
transaction as the write.
|
|
NULL can be passed in if caller does
|
|
not want any attribute to be set
|
|
|
|
DomainSid -- Optional Parameter, used in creating the Full
|
|
SID for the account, from the specified Rid
|
|
|
|
|
|
Return values:
|
|
|
|
STATUS_SUCCESS on successful completion
|
|
DS return codes mapped to NT_STATUS as in SampMapDSErrorToNTStatus
|
|
|
|
|
|
BUG: Need to do something about DS requiring Allocs from the Thread
|
|
heap. We anyway alloc memory in the bunch of cases. Alloc this using the
|
|
thread heap.
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG RetCode;
|
|
ADDARG AddArg;
|
|
COMMARG * pCommArg;
|
|
|
|
|
|
SAMTRACE("SampDsCreateObject");
|
|
|
|
//
|
|
// Parameter validation
|
|
//
|
|
|
|
ASSERT(Object);
|
|
ASSERT(AttributesToSet);
|
|
ASSERT(AttributesToSet->attrCount > 0);
|
|
|
|
// Perform lazy thread and transaction initialization.
|
|
Status = SampMaybeBeginDsTransaction(SampWriteLock);
|
|
|
|
if (Status!= STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// MAP the AttrBlock to get the final attributes to Set
|
|
//
|
|
|
|
Status = SampSamToDsAttrBlock(
|
|
ObjectType,
|
|
AttributesToSet,
|
|
( MAP_RID_TO_SID | MAP_ATTRIBUTE_TYPES
|
|
| REALLOC_IN_DSMEMORY |ADD_OBJECT_CLASS_ATTRIBUTE),
|
|
DomainSid,
|
|
&AddArg.AttrBlock
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// Setup the Common Args structure
|
|
//
|
|
|
|
pCommArg = &(AddArg.CommArg);
|
|
BuildStdCommArg(pCommArg);
|
|
|
|
//
|
|
// Setup the AddArg structure
|
|
//
|
|
|
|
AddArg.pObject = Object;
|
|
|
|
//
|
|
// Make the DS call
|
|
//
|
|
|
|
RetCode = DirAddEntry(&AddArg);
|
|
|
|
//
|
|
// Map the return code to an NT status
|
|
//
|
|
|
|
Status = SampMapDsErrorToNTStatus(RetCode);
|
|
|
|
Error:
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampDsDeleteObject(
|
|
IN DSNAME * Object
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an Object in the DS
|
|
|
|
Arguments:
|
|
Object -- specifies the Object to delete
|
|
|
|
Return Values:
|
|
STATUS_SUCCESS on succesful completion
|
|
DS return codes mapped to NT_STATUS as in SampMapDSErrorToNTStatus
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
REMOVEARG RemoveArg;
|
|
COMMARG *pCommArg;
|
|
ULONG RetValue;
|
|
|
|
|
|
SAMTRACE("SampDsDeleteObject");
|
|
|
|
//
|
|
// Asserts and parameter validation
|
|
//
|
|
|
|
ASSERT(Object!=NULL);
|
|
|
|
// Perform lazy thread and transaction initialization.
|
|
Status = SampMaybeBeginDsTransaction(SampWriteLock);
|
|
|
|
if (Status!= STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// Setup the Common Args structure
|
|
//
|
|
|
|
pCommArg = &(RemoveArg.CommArg);
|
|
BuildStdCommArg(pCommArg);
|
|
|
|
//
|
|
// Setup the RemoveArgs structure
|
|
//
|
|
|
|
RemoveArg.pObject = Object;
|
|
|
|
//
|
|
// Make the directory call
|
|
//
|
|
|
|
RetValue = DirRemoveEntry(&RemoveArg);
|
|
|
|
//
|
|
// Map to corresponding NT status code
|
|
//
|
|
|
|
Status = SampMapDsErrorToNTStatus(RetValue);
|
|
|
|
Error:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampDsDoUniqueSearch(
|
|
IN ULONG Flags,
|
|
IN DSNAME * ContainerObject,
|
|
IN ATTR * AttributeToMatch,
|
|
OUT DSNAME **Object
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches for the object with the given attribute
|
|
NOTE - SampDsDoUniqueSearch expects that the search result is unique.
|
|
It is typically used in Rid to Object, Sid To Object, Name To Object Mappings,
|
|
This is a simplified search, so that simple searches on a single attribute
|
|
can be easily set up.
|
|
|
|
Arguments
|
|
Flags -- Flags, control searching
|
|
|
|
ContainerObject -- specifies the DSNAME of the container in which to search
|
|
|
|
AttributeToMatch -- specifies the type and value of the attribute that must match.
|
|
The attribute Type is the DS attribute Type. Caller must do
|
|
the translation. This is acceptable as this is not a function that
|
|
is called from outside dslayer.c
|
|
|
|
Object -- Pointer to a DSNAME specifying the object is returned in here.
|
|
This object is allocated using SAM's memory allocation routines
|
|
|
|
Return Values:
|
|
STATUS_SUCCESS -- on successful completion
|
|
STATUS_NOT_FOUND -- if object not found
|
|
STATUS_UNSUCCESSFUL -- if more than one match
|
|
DS return codes mapped to NT_STATUS as in SampMapDSErrorToNTStatus
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
SEARCHARG SearchArg;
|
|
SEARCHRES * SearchRes;
|
|
FILTER Filter;
|
|
ULONG RetCode;
|
|
COMMARG * pCommArg;
|
|
SVCCNTL * pSvcCntl;
|
|
ENTINFSEL EntInfSel;
|
|
|
|
|
|
SAMTRACE("SampDsDoSearch");
|
|
|
|
//
|
|
// Asserts and parameter validation
|
|
//
|
|
|
|
ASSERT(AttributeToMatch);
|
|
ASSERT(AttributeToMatch->AttrVal.pAVal);
|
|
ASSERT(ContainerObject);
|
|
ASSERT(Object);
|
|
|
|
//
|
|
// Set Object To NULL for sake of error returns
|
|
//
|
|
|
|
*Object = NULL;
|
|
|
|
// Perform lazy thread and transaction initialization.
|
|
Status = SampMaybeBeginDsTransaction(SampWriteLock);
|
|
|
|
if (Status!= STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// Build the filter
|
|
//
|
|
|
|
Filter.choice = FILTER_CHOICE_ITEM;
|
|
Filter.FilTypes.Item.choice = FI_CHOICE_EQUALITY;
|
|
Filter.FilTypes.Item.FilTypes.ava.type = AttributeToMatch->attrTyp;
|
|
Filter.FilTypes.Item.FilTypes.ava.Value.valLen = AttributeToMatch->AttrVal.pAVal->valLen;
|
|
Filter.FilTypes.Item.FilTypes.ava.Value.pVal = AttributeToMatch->AttrVal.pAVal->pVal;
|
|
|
|
//
|
|
// Build the SearchArg Structure
|
|
//
|
|
|
|
SearchArg.pObject = ContainerObject;
|
|
SearchArg.choice = SE_CHOICE_WHOLE_SUBTREE;
|
|
SearchArg.pFilter = & Filter;
|
|
SearchArg.searchAliases = FALSE;
|
|
SearchArg.pSelection = & EntInfSel;
|
|
|
|
EntInfSel.attSel = EN_ATTSET_LIST;
|
|
EntInfSel.AttrTypBlock.attrCount = 1;
|
|
EntInfSel.AttrTypBlock.pAttr = AttributeToMatch;
|
|
EntInfSel.infoTypes = EN_INFOTYPES_TYPES_ONLY;
|
|
|
|
//
|
|
// Build the Commarg structure
|
|
// Get the address of the service control structure
|
|
//
|
|
|
|
pCommArg = &(SearchArg.CommArg);
|
|
BuildStdCommArg(pCommArg);
|
|
|
|
if (Flags & MAKE_DEL_AVAILABLE)
|
|
{
|
|
pSvcCntl = &(pCommArg->Svccntl);
|
|
pSvcCntl->makeDeletionsAvail = TRUE;
|
|
}
|
|
|
|
//
|
|
// Make the Directory call
|
|
//
|
|
|
|
RetCode = DirSearch(&SearchArg, & SearchRes);
|
|
|
|
//
|
|
// check for errors
|
|
//
|
|
|
|
Status = SampMapDsErrorToNTStatus(RetCode);
|
|
if (Status != STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
//
|
|
// If more data exists then error out. Under normal memory
|
|
// conditions we should not ever need to hit size limits.
|
|
//
|
|
|
|
if ((SearchRes->pPartialOutcomeQualifier)
|
|
&& (SearchRes->pPartialOutcomeQualifier->problem == PA_PROBLEM_SIZE_LIMIT))
|
|
{
|
|
// Partial outcome, error out saying no mmeory
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if no match exists or more than one match exists.
|
|
//
|
|
|
|
if (SearchRes->count == 0)
|
|
{
|
|
//
|
|
// No Match Exists
|
|
//
|
|
|
|
Status = STATUS_NOT_FOUND;
|
|
goto Error;
|
|
}
|
|
else
|
|
if (SearchRes->count > 1)
|
|
{
|
|
//
|
|
// More than one match exists,
|
|
// BUG: for now fail the call saying STATUS_UNSUCCESSFUL. Later we
|
|
// may want to return a different error code.
|
|
//
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Allocate Memory to hold that object, and copy in its Value
|
|
//
|
|
|
|
*Object = MIDL_user_allocate(SearchRes->FirstEntInf.Entinf.pName->structLen);
|
|
if (NULL==Object)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
RtlCopyMemory(*Object,
|
|
SearchRes->FirstEntInf.Entinf.pName,
|
|
SearchRes->FirstEntInf.Entinf.pName->structLen
|
|
);
|
|
|
|
Error:
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampDsDoSearch(
|
|
RESTART *Restart,
|
|
DSNAME *DomainObject,
|
|
FILTER *DsFilter,
|
|
SAMP_OBJECT_TYPE ObjectTypeForConversion,
|
|
ATTRBLOCK * AttrsToRead,
|
|
ULONG MaxMemoryToUse,
|
|
SEARCHRES **SearchRes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine calls a DS Search to list a set of Objects with
|
|
the given Filter. The user passes in a Filter Structure. PagedResults
|
|
are always requested.
|
|
|
|
NOTE - This routine expects all attribute types to be DS attribute
|
|
Types. No Translation is Done, as otherwise it requires walking through
|
|
Messy and Complex Filter Structures, and Lists of AttrBlocks, as
|
|
returned by the Search.
|
|
|
|
Arguments:
|
|
|
|
Restart - Pointer to Restart Structure to contine an
|
|
old search
|
|
ContainerObject - The place to Search in
|
|
DsFilter - A Ds Filter Structure that is passed in
|
|
ObjectTypeForConversion - Sam Object Type to be used in
|
|
AttrBlock Conversion
|
|
AttrsToRead - Attributes to be read back, and returned with
|
|
every object that matched the search criteria.
|
|
MaxMemoryToUse - The Maximum Memory to Use.
|
|
SearchRes - Pointer to Search Results is passed back
|
|
in this
|
|
|
|
Return Values
|
|
DS error codes Mapped to NT Status
|
|
|
|
--*/
|
|
{
|
|
SEARCHARG SearchArg;
|
|
ENTINFSEL EntInfSel;
|
|
ULONG RetCode;
|
|
COMMARG *pCommArg;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
// Perform lazy thread and transaction initialization.
|
|
Status = SampMaybeBeginDsTransaction(SampWriteLock);
|
|
|
|
if (Status!= STATUS_SUCCESS)
|
|
return(Status);
|
|
|
|
//
|
|
// Build the SearchArg Structure
|
|
//
|
|
|
|
SearchArg.pObject = DomainObject;
|
|
SearchArg.choice = SE_CHOICE_WHOLE_SUBTREE;
|
|
SearchArg.pFilter = DsFilter;
|
|
SearchArg.searchAliases = FALSE;
|
|
SearchArg.pSelection = & EntInfSel;
|
|
|
|
//
|
|
// Fill the ENTINF Structure
|
|
//
|
|
|
|
EntInfSel.attSel = EN_ATTSET_LIST;
|
|
EntInfSel.infoTypes = EN_INFOTYPES_TYPES_VALS;
|
|
|
|
|
|
Status = SampSamToDsAttrBlock(
|
|
ObjectTypeForConversion,
|
|
AttrsToRead,
|
|
( MAP_RID_TO_SID | MAP_ATTRIBUTE_TYPES| REALLOC_IN_DSMEMORY),
|
|
NULL,
|
|
& EntInfSel.AttrTypBlock
|
|
);
|
|
|
|
//
|
|
// Build the CommArg Structure
|
|
// Build the Commarg structure
|
|
// Get the address of the service control structure
|
|
//
|
|
|
|
pCommArg = &(SearchArg.CommArg);
|
|
BuildStdCommArg(pCommArg);
|
|
|
|
//
|
|
// Request For Paged Results
|
|
//
|
|
|
|
pCommArg->PagedResult.fPresent = TRUE;
|
|
pCommArg->PagedResult.pRestart = Restart;
|
|
|
|
//
|
|
// Set our memory size
|
|
//
|
|
|
|
pCommArg->ulSizeLimit = MaxMemoryToUse;
|
|
|
|
//
|
|
// Make the Directory call
|
|
//
|
|
|
|
RetCode = DirSearch(&SearchArg, SearchRes);
|
|
|
|
//
|
|
// Map Errors
|
|
//
|
|
|
|
Status = SampMapDsErrorToNTStatus(RetCode);
|
|
|
|
//
|
|
// Return error code
|
|
//
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SampDsLookupObjectByName(
|
|
IN DSNAME * DomainObject,
|
|
IN SAMP_OBJECT_TYPE ObjectType,
|
|
IN PUNICODE_STRING ObjectName,
|
|
OUT DSNAME ** Object
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does a Name to Object Mapping.
|
|
|
|
Arguments:
|
|
ContainerObject -- The container in which to search the object
|
|
ObjectType -- The type of the Object.
|
|
ObjectName -- Unicode name of the Object to be located
|
|
Object -- DSNAME structure specifying the object
|
|
Return Values:
|
|
|
|
STATUS_UNSUCCESSFUL
|
|
Returned Status from SampDoDsSearch
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ATTRVAL NameVal;
|
|
ATTR NameAttr;
|
|
|
|
|
|
SAMTRACE("SampLookpObjectByName");
|
|
|
|
//
|
|
// The Name is a property stored in the object
|
|
// and we search for it.
|
|
//
|
|
|
|
//
|
|
// setup the attribute field for the search
|
|
//
|
|
NameVal.valLen = (ObjectName->Length+1) * sizeof(WCHAR);
|
|
NameVal.pVal = (UCHAR *) ObjectName->Buffer;
|
|
NameAttr.AttrVal.valCount = 1;
|
|
NameAttr.AttrVal.pAVal = & NameVal;
|
|
|
|
switch (ObjectType)
|
|
{
|
|
case SampGroupObjectType:
|
|
NameAttr.attrTyp =
|
|
SampDsAttrFromSamAttr(ObjectType,SAMP_GROUP_NAME);
|
|
break;
|
|
|
|
case SampUserObjectType:
|
|
NameAttr.attrTyp =
|
|
SampDsAttrFromSamAttr(ObjectType,SAMP_USER_ACCOUNT_NAME);
|
|
break;
|
|
|
|
case SampAliasObjectType:
|
|
NameAttr.attrTyp =
|
|
SampDsAttrFromSamAttr(ObjectType,SAMP_ALIAS_NAME);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Error;
|
|
}
|
|
|
|
|
|
Status = SampDsDoUniqueSearch(0,DomainObject,&NameAttr,Object);
|
|
|
|
|
|
Error:
|
|
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SampDsObjectFromSid(
|
|
IN PSID Sid,
|
|
OUT DSNAME ** Object
|
|
)
|
|
/*++
|
|
|
|
This Routine Searches the DS for specified SID.
|
|
PRE M1 -- This is just a DS search using the SID index
|
|
Post M1 -- This object may not exist in the current index,
|
|
in which case you go to the GC Server
|
|
|
|
Arguments:
|
|
|
|
Sid -- SID of the object
|
|
DsName -- DS NAME of the located object.
|
|
|
|
|
|
Return Values:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_NOT_FOUND
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ATTR SidAttr;
|
|
ATTRVAL SidVal;
|
|
DSNAME RootObject;
|
|
|
|
SAMTRACE("SampDsObjectFromSid");
|
|
|
|
|
|
//
|
|
// Set up the Sid Attribute
|
|
//
|
|
|
|
SidAttr.attrTyp = SampDsAttrFromSamAttr(
|
|
SampUnknownObjectType,
|
|
SAMP_UNKNOWN_OBJECTSID
|
|
);
|
|
|
|
SidAttr.AttrVal.valCount = 1;
|
|
SidAttr.AttrVal.pAVal = &SidVal;
|
|
SidVal.valLen = RtlLengthSid(Sid);
|
|
SidVal.pVal = (UCHAR *)Sid;
|
|
|
|
|
|
//
|
|
// Specify Root as base of Search. This
|
|
// Translates to a zeroing out a DSName
|
|
//
|
|
|
|
|
|
Status = SampDsDoUniqueSearch(
|
|
0, // Flags
|
|
ROOT_OBJECT, // Search Base
|
|
&SidAttr, // Sid
|
|
Object // Get Results in Here.
|
|
);
|
|
|
|
|
|
Error:
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
PSID
|
|
SampDsGetObjectSid(
|
|
IN DSNAME * Object
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Given the DSNAME of the Object this routine returns the Sid
|
|
of the Object.
|
|
|
|
Arguments:
|
|
|
|
Object:
|
|
Object whose Sid needs returning
|
|
|
|
Return Values:
|
|
Sid of the object.
|
|
NULL if no Sid exists
|
|
--*/
|
|
{
|
|
|
|
ATTR SidAttr;
|
|
ATTRBLOCK SidAttrBlock;
|
|
ATTRBLOCK Result;
|
|
NTSTATUS Status;
|
|
|
|
|
|
SidAttrBlock.attrCount =1;
|
|
SidAttrBlock.pAttr = &(SidAttr);
|
|
|
|
SidAttr.AttrVal.valCount =0;
|
|
SidAttr.AttrVal.pAVal = NULL;
|
|
SidAttr.attrTyp = SAMP_UNKNOWN_OBJECTSID;
|
|
|
|
Status = SampDsRead(
|
|
Object,
|
|
0,
|
|
SampUnknownObjectType,
|
|
& SidAttrBlock,
|
|
& Result
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
return NULL;
|
|
|
|
return Result.pAttr[0].AttrVal.pAVal->pVal;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampDsLookupObjectByRid(
|
|
IN DSNAME * DomainObject,
|
|
ULONG ObjectRid,
|
|
DSNAME **Object
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RID to Object Mapping
|
|
|
|
Arguments:
|
|
|
|
ContainerObject -- The container in which to locate this object
|
|
ObjectRid -- RID of the object to be located
|
|
Object -- returns pointer to DSNAME structure specifying the object
|
|
|
|
Return Values:
|
|
STATUS_SUCCESS on successful completion
|
|
Any returned by SampDsDoSearch
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ATTRVAL RidVal = {sizeof(ULONG), (UCHAR *)&ObjectRid};
|
|
ATTR RidAttr = {SAMP_UNKNOWN_OBJECTRID, {1, &RidVal}};
|
|
PSID DomainSid;
|
|
ATTR SidAttr;
|
|
|
|
SAMTRACE("SampDsLookupObjectByRid");
|
|
|
|
DomainSid = SampDsGetObjectSid(DomainObject);
|
|
|
|
if (DomainSid == NULL)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Error;
|
|
}
|
|
|
|
SidAttr.attrTyp = SampDsAttrFromSamAttr(
|
|
SampUnknownObjectType,
|
|
SAMP_UNKNOWN_OBJECTSID
|
|
);
|
|
|
|
Status = SampDsSetNewSidAttribute(
|
|
DomainSid,
|
|
REALLOC_IN_DSMEMORY,
|
|
&RidAttr,
|
|
&SidAttr
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
goto Error;
|
|
|
|
|
|
Status = SampDsDoUniqueSearch(0,DomainObject,&SidAttr,Object);
|
|
|
|
|
|
Error:
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampMapDsErrorToNTStatus(ULONG DsRetVal)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Maps a DS error to NTSTATUS
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Values:
|
|
See the switch statement below
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
switch (DsRetVal)
|
|
{
|
|
case 0L:
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case attributeError:
|
|
case nameError:
|
|
case referralError:
|
|
case securityError:
|
|
case serviceError:
|
|
case updError:
|
|
case systemError:
|
|
default:
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SampSamToDsAttrBlock(
|
|
IN SAMP_OBJECT_TYPE ObjectType,
|
|
IN ATTRBLOCK *AttrBlockToConvert,
|
|
IN ULONG ConversionFlags,
|
|
IN PSID DomainSid,
|
|
OUT ATTRBLOCK * ConvertedAttrBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts the Attribute types in an Attrblock
|
|
from SAM to DS Types
|
|
|
|
Arguments:
|
|
|
|
ObjectType -- specifies type of SAM object
|
|
AttrBlockToConvert -- pointer to Attrblock to be converted
|
|
ConversionFlags -- The Type of conversion Desired. Currently
|
|
defined values are
|
|
|
|
MAP_ATTRIBUTE_TYPES
|
|
REALLOC_IN_DSMEMORY
|
|
ADD_OBJECT_CLASS_ATTRIBUTE
|
|
MAP_RID_TO_SID
|
|
|
|
DomainSid -- Used to Compose the Sid of the Object
|
|
when the MAP sid to Rid is specified
|
|
|
|
ConvertedAttrBlock -- The Converted DS AttrBlock.
|
|
|
|
|
|
Return Values:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
ULONG DsSidAttr = SampDsAttrFromSamAttr(
|
|
SampUnknownObjectType,
|
|
SAMP_UNKNOWN_OBJECTSID
|
|
);
|
|
|
|
ULONG DsRidAttr = SampDsAttrFromSamAttr(
|
|
SampUnknownObjectType,
|
|
SAMP_UNKNOWN_OBJECTRID
|
|
);
|
|
|
|
|
|
//
|
|
// Copy the Fixed Portion
|
|
//
|
|
|
|
*ConvertedAttrBlock = *AttrBlockToConvert;
|
|
|
|
if (ConversionFlags & REALLOC_IN_DSMEMORY)
|
|
{
|
|
|
|
ULONG AttrsToAllocate = AttrBlockToConvert->attrCount;
|
|
|
|
if (ConversionFlags & ADD_OBJECT_CLASS_ATTRIBUTE)
|
|
{
|
|
//
|
|
// Caller requested that an object class attribute
|
|
// be added, alloc one more attr for object class
|
|
//
|
|
|
|
AttrsToAllocate++ ;
|
|
}
|
|
|
|
|
|
//
|
|
// Realloc and Copy the pAttr portion of it.
|
|
//
|
|
|
|
ConvertedAttrBlock->pAttr = DSAlloc(
|
|
AttrsToAllocate
|
|
* sizeof(ATTR)
|
|
);
|
|
|
|
if (NULL==ConvertedAttrBlock->pAttr)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
ConvertedAttrBlock->pAttr,
|
|
AttrBlockToConvert->pAttr,
|
|
AttrBlockToConvert->attrCount * sizeof(ATTR)
|
|
);
|
|
|
|
}
|
|
|
|
for (Index=0; Index<AttrBlockToConvert->attrCount;Index++)
|
|
{
|
|
|
|
|
|
//
|
|
// MAP Sam Attribute Types to DS Types if that was requested
|
|
//
|
|
|
|
if (ConversionFlags & MAP_ATTRIBUTE_TYPES)
|
|
{
|
|
ConvertedAttrBlock->pAttr[Index].attrTyp =
|
|
SampDsAttrFromSamAttr(
|
|
ObjectType,
|
|
AttrBlockToConvert->pAttr[Index].attrTyp
|
|
);
|
|
}
|
|
else
|
|
{
|
|
ConvertedAttrBlock->pAttr[Index].attrTyp =
|
|
AttrBlockToConvert->pAttr[Index].attrTyp;
|
|
}
|
|
|
|
|
|
//
|
|
// MAP Rid To Sid, if Attribute is Rid
|
|
//
|
|
|
|
if ( (ConversionFlags & MAP_RID_TO_SID)
|
|
&&(ConvertedAttrBlock->pAttr[Index].attrTyp == DsRidAttr)
|
|
)
|
|
|
|
{
|
|
|
|
|
|
ConvertedAttrBlock->pAttr[Index].attrTyp = DsSidAttr;
|
|
Status = SampDsSetNewSidAttribute(
|
|
DomainSid,
|
|
ConversionFlags,
|
|
& (AttrBlockToConvert->pAttr[Index]),
|
|
& (ConvertedAttrBlock->pAttr[Index])
|
|
);
|
|
|
|
if (!(NT_SUCCESS(Status)))
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Else Just simply copy the Attribute Value
|
|
//
|
|
|
|
else
|
|
{
|
|
Status = SampDsCopyAttributeValue(
|
|
& (AttrBlockToConvert->pAttr[Index]),
|
|
& (ConvertedAttrBlock->pAttr[Index])
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If Addition of Object Class attribute was requested then
|
|
// Add this attribute.
|
|
//
|
|
|
|
if (ConversionFlags & ADD_OBJECT_CLASS_ATTRIBUTE)
|
|
{
|
|
ULONG DsClass;
|
|
ATTR * LastAttr;
|
|
|
|
DsClass = SampDsClassFromSamObjectType(ObjectType);
|
|
LastAttr =
|
|
&(ConvertedAttrBlock->pAttr[AttrBlockToConvert->attrCount]);
|
|
LastAttr->attrTyp = SampDsAttrFromSamAttr(
|
|
SampUnknownObjectType,
|
|
SAMP_UNKNOWN_OBJECTCLASS
|
|
);
|
|
LastAttr->AttrVal.valCount = 1;
|
|
LastAttr->AttrVal.pAVal = DSAlloc(sizeof(ATTRVAL));
|
|
if (NULL== LastAttr->AttrVal.pAVal)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
LastAttr->AttrVal.pAVal->valLen = sizeof(ULONG);
|
|
LastAttr->AttrVal.pAVal->pVal = DSAlloc(sizeof(ULONG));
|
|
if (NULL== LastAttr->AttrVal.pAVal->pVal)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
*((ULONG *) LastAttr->AttrVal.pAVal->pVal) = DsClass;
|
|
|
|
//
|
|
// Increment the Attr Count
|
|
//
|
|
|
|
ConvertedAttrBlock->attrCount++;
|
|
|
|
|
|
}
|
|
|
|
|
|
Error:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SampDsNewAccountSid(
|
|
PSID DomainSid,
|
|
ULONG AccountRid,
|
|
PSID *NewSid
|
|
)
|
|
/*
|
|
Routine Description
|
|
|
|
Composes an Account Sid from the given Domain Sid and Rid.
|
|
Uses DS thread memory. THis is the main difference between
|
|
the function in utility.c
|
|
|
|
Arguments:
|
|
|
|
DomainSid The Domain Sid
|
|
AccountRid The Rid
|
|
NewSid The final account Sid
|
|
|
|
Return Values
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_NO_MEMORY
|
|
*/
|
|
|
|
{
|
|
ULONG DomainSidLength = RtlLengthSid(DomainSid);
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
//
|
|
// Alloc Memory to hold the account Sid
|
|
//
|
|
|
|
*NewSid = DSAlloc(DomainSidLength + sizeof(ULONG));
|
|
|
|
if (NULL==*NewSid)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Copy the Domain Sid Part
|
|
//
|
|
|
|
RtlCopyMemory(*NewSid,DomainSid,DomainSidLength);
|
|
|
|
//
|
|
// Increment the SubAuthority Count
|
|
//
|
|
|
|
((UCHAR *) *NewSid)[1]++;
|
|
|
|
//
|
|
// Add the RID as a sub authority
|
|
//
|
|
|
|
*((ULONG *) (((UCHAR *) *NewSid ) + DomainSidLength)) =
|
|
AccountRid;
|
|
|
|
Error:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampDsSetNewSidAttribute(
|
|
PSID DomainSid,
|
|
ULONG ConversionFlags,
|
|
ATTR *RidAttr,
|
|
ATTR *SidAttr
|
|
)
|
|
/*
|
|
Routine Description
|
|
|
|
Composes a DS Sid Attr , given a DS Rid Attr
|
|
|
|
Arguments:
|
|
|
|
Conversion Flags
|
|
|
|
Currently only valid value is REALLOC_IN_DS_MEMORY
|
|
|
|
RidAttr
|
|
|
|
Rid Attribute
|
|
SidAttr
|
|
The Sid Attribute that is composed
|
|
*/
|
|
{
|
|
|
|
PSID NewSid = NULL;
|
|
ULONG AccountRid;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (
|
|
(RidAttr->AttrVal.valCount)
|
|
&& (RidAttr->AttrVal.pAVal)
|
|
&& (RidAttr->AttrVal.pAVal->pVal)
|
|
&& (RidAttr->AttrVal.pAVal->valLen)
|
|
)
|
|
{
|
|
//
|
|
// Values are Present, assert that REALLOC is also
|
|
// specified
|
|
//
|
|
|
|
ASSERT(ConversionFlags & REALLOC_IN_DSMEMORY);
|
|
|
|
if (!(ConversionFlags & REALLOC_IN_DSMEMORY))
|
|
{
|
|
//
|
|
// Realloc in DS memory is not specified
|
|
//
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Compose New Sid
|
|
//
|
|
|
|
AccountRid = * ((ULONG *)RidAttr->AttrVal.pAVal->pVal);
|
|
Status = SampDsNewAccountSid(DomainSid,AccountRid, &NewSid);
|
|
if (!(NT_SUCCESS(Status)))
|
|
goto Error;
|
|
|
|
//
|
|
// Alloc Memory for ATTRVAL structure
|
|
//
|
|
|
|
SidAttr->AttrVal.pAVal =
|
|
DSAlloc(sizeof(ATTRVAL));
|
|
|
|
if (NULL== SidAttr->AttrVal.pAVal)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Set the Value to the New Sid
|
|
//
|
|
|
|
SidAttr->AttrVal.valCount = 1;
|
|
SidAttr->AttrVal.pAVal->valLen = RtlLengthSid(NewSid);
|
|
SidAttr->AttrVal.pAVal->pVal = NewSid;
|
|
}
|
|
else
|
|
{
|
|
SidAttr->AttrVal.valCount = 0;
|
|
SidAttr->AttrVal.pAVal = NULL;
|
|
}
|
|
|
|
Error:
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampDsCopyAttributeValue(
|
|
ATTR * Src,
|
|
ATTR * Dst
|
|
)
|
|
/*
|
|
Routine Description
|
|
|
|
Copies a DS Attributes Value
|
|
|
|
Arguments:
|
|
|
|
Src - Source Attribute
|
|
Dst - Destination Attribute
|
|
|
|
Return Values
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_NO_MEMORY
|
|
|
|
*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG Index;
|
|
|
|
if (
|
|
(Src->AttrVal.valCount)
|
|
&& (Src->AttrVal.pAVal)
|
|
)
|
|
{
|
|
//
|
|
// Values are Present, Copy Them
|
|
//
|
|
|
|
Dst->AttrVal.pAVal = DSAlloc(
|
|
Src->AttrVal.valCount *
|
|
sizeof(ATTRVAL)
|
|
);
|
|
|
|
if (NULL== Dst->AttrVal.pAVal)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
Dst->AttrVal.valCount = Src->AttrVal.valCount;
|
|
|
|
for (Index=0;Index<Src->AttrVal.valCount;Index++)
|
|
{
|
|
if (Src->AttrVal.pAVal[Index].valLen)
|
|
Dst->AttrVal.pAVal[Index].valLen =
|
|
Src->AttrVal.pAVal[Index].valLen;
|
|
|
|
if ((Src->AttrVal.pAVal[Index].valLen)
|
|
&& (Src->AttrVal.pAVal[Index].pVal))
|
|
{
|
|
Dst->AttrVal.pAVal[Index].pVal =
|
|
DSAlloc(Src->AttrVal.pAVal[Index].valLen);
|
|
if (NULL== Dst->AttrVal.pAVal[Index].pVal)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
RtlCopyMemory(
|
|
Dst->AttrVal.pAVal[Index].pVal,
|
|
Src->AttrVal.pAVal[Index].pVal,
|
|
Dst->AttrVal.pAVal[Index].valLen
|
|
);
|
|
}
|
|
else
|
|
Dst->AttrVal.pAVal[Index].pVal = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Dst->AttrVal.pAVal = NULL;
|
|
Dst->AttrVal.valCount = 0;
|
|
}
|
|
|
|
Error:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SampDsToSamAttrBlock(
|
|
IN SAMP_OBJECT_TYPE ObjectType,
|
|
IN ATTRBLOCK * AttrBlockToConvert,
|
|
IN ULONG ConversionFlags,
|
|
OUT ATTRBLOCK * ConvertedAttrBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts the Attribute types in an Attrblock
|
|
from DS to SAM Types
|
|
|
|
Arguments:
|
|
|
|
ObjectType -- specifies type of SAM object
|
|
AttrBlockToConvert -- pointer to Attrblock to be converted
|
|
ConversionFlags -- The Type of Conversion Desired. Currently
|
|
defined values are
|
|
|
|
MAP_ATTRIBUTE_TYPES
|
|
MAP_SID_TO_RID
|
|
|
|
ConvertedAttrBlock -- The converted AttrBlock.
|
|
|
|
Return Values:
|
|
None
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG Index;
|
|
ULONG DsSidAttr = SampDsAttrFromSamAttr(
|
|
SampUnknownObjectType,
|
|
SAMP_UNKNOWN_OBJECTSID
|
|
);
|
|
|
|
ULONG DsRidAttr = SampDsAttrFromSamAttr(
|
|
SampUnknownObjectType,
|
|
SAMP_UNKNOWN_OBJECTRID
|
|
);
|
|
|
|
|
|
*ConvertedAttrBlock = *AttrBlockToConvert;
|
|
|
|
for (Index=0; Index<AttrBlockToConvert->attrCount;Index++)
|
|
{
|
|
//
|
|
// MAP Any Sid Attribute to Rid Attribute
|
|
//
|
|
|
|
if ((ConversionFlags & MAP_SID_TO_RID) &&
|
|
(AttrBlockToConvert->pAttr[Index].attrTyp == DsSidAttr))
|
|
|
|
{
|
|
ATTR * pSidAttr = &(AttrBlockToConvert->pAttr[Index]);
|
|
|
|
switch(ObjectType)
|
|
{
|
|
case SampGroupObjectType:
|
|
case SampAliasObjectType:
|
|
case SampUserObjectType:
|
|
|
|
//
|
|
// Map the Attr Type
|
|
//
|
|
|
|
pSidAttr->attrTyp = DsRidAttr;
|
|
|
|
//
|
|
// Map the Attr Value, the Last ULONG in the Sid
|
|
// is the Rid, so advance the pointer accordingly
|
|
//
|
|
|
|
pSidAttr->AttrVal.pAVal->pVal+=
|
|
pSidAttr->AttrVal.pAVal->valLen - sizeof(ULONG);
|
|
pSidAttr->AttrVal.pAVal->valLen = sizeof(ULONG);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// MAP Attribute Types
|
|
//
|
|
|
|
if (ConversionFlags & MAP_ATTRIBUTE_TYPES)
|
|
{
|
|
ConvertedAttrBlock->pAttr[Index].attrTyp =
|
|
SampSamAttrFromDsAttr(
|
|
ObjectType,
|
|
AttrBlockToConvert->pAttr[Index].attrTyp
|
|
);
|
|
}
|
|
|
|
|
|
|
|
} // End of For Loop
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampDsCreateDsName(
|
|
IN DSNAME * DomainObject,
|
|
IN ULONG AccountId,
|
|
IN OUT DSNAME ** NewObject
|
|
)
|
|
/*++
|
|
Routine Description
|
|
Builds a DSName given an account Rid and the Domain Object
|
|
|
|
Arguments:
|
|
|
|
DomainObject -- DSName of the Domain Object
|
|
AccountRid -- The Rid of the account
|
|
NewObject -- Returns the New DS Name in this object
|
|
|
|
Return values:
|
|
STATUS_SUCCESS - upon successful completion
|
|
STATUS_NO_MEMORY - Memory alloc Failure
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
WCHAR LookupTable[]=L"0123456789ABCDEF";
|
|
WCHAR CommonNamePart[] = L"/cn=";
|
|
ULONG Mask = 0xF0000000;
|
|
ULONG Index = 0;
|
|
|
|
//
|
|
// Define the size of the Rid Part
|
|
// This should be length of the Rid Hex printed out +
|
|
// 1 for Null terminator
|
|
//
|
|
|
|
#define RidPartSize (8+sizeof(CommonNamePart))
|
|
WCHAR NameBuffer[RidPartSize];
|
|
|
|
|
|
//
|
|
// Alloc a DS Name capable of holding everything
|
|
//
|
|
|
|
*NewObject = MIDL_user_allocate(DomainObject->structLen +
|
|
RidPartSize * sizeof(WCHAR));
|
|
if (*NewObject == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Copy the comon name part
|
|
//
|
|
|
|
RtlCopyMemory(NameBuffer,CommonNamePart,sizeof(CommonNamePart));
|
|
|
|
//
|
|
// Now Hext print out the Rid.
|
|
//
|
|
|
|
for (Index=0;Index<(2*sizeof(ULONG));Index++)
|
|
{
|
|
ULONG HexDigit;
|
|
|
|
HexDigit = (AccountId & Mask)>>(4*(2*sizeof(ULONG)-1-Index));
|
|
NameBuffer[Index+sizeof(CommonNamePart)/sizeof(WCHAR)-1]
|
|
= LookupTable[HexDigit];
|
|
Mask = Mask>>4;
|
|
}
|
|
|
|
NameBuffer[RidPartSize-1]=0;
|
|
|
|
//
|
|
// Build the DS Name
|
|
//
|
|
|
|
SampInitializeDsName(*NewObject,
|
|
DomainObject->StringName,
|
|
DomainObject->NameLen*sizeof(WCHAR),
|
|
NameBuffer,
|
|
RidPartSize*sizeof(WCHAR)
|
|
);
|
|
Error:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
void
|
|
SampInitializeDsName(
|
|
IN DSNAME * pDsName,
|
|
IN WCHAR * NamePrefix,
|
|
IN ULONG NamePrefixLen,
|
|
IN WCHAR * ObjectName,
|
|
IN ULONG NameLen
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Initializes a DSNAME structure
|
|
|
|
Arguments:
|
|
pDsName -- A pointer to a buffer large enough to hold everything. This buffer will be
|
|
filled with a NULL GUID plus a complete name
|
|
|
|
NamePrefix -- pointer to a sequence of NULL terminated
|
|
UNICODE chars holding any prefix
|
|
to the name. Useful in composing
|
|
hierarchial names
|
|
|
|
NamePrefixLen -- Length of the Prefix in bytes. Also includes the NULL terminator
|
|
|
|
ObjectName -- pointer to a sequence of NULL terminated
|
|
UNICODE char the name of the object
|
|
|
|
NameLen -- Length of the Object Name in bytes. Also includes the NULL terminator
|
|
|
|
|
|
Return Values:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Single NULL string is not allowed for name or Prefix
|
|
//
|
|
|
|
ASSERT(NamePrefixLen!=sizeof(WCHAR));
|
|
ASSERT(NameLen!=sizeof(WCHAR));
|
|
|
|
//
|
|
// Zero the GUID
|
|
//
|
|
|
|
RtlZeroMemory(&(pDsName->Guid), sizeof(GUID));
|
|
|
|
//
|
|
// Compute String Length including Null terminator
|
|
//
|
|
|
|
if (NamePrefix)
|
|
{
|
|
|
|
pDsName->NameLen = (NameLen + NamePrefixLen)/sizeof(WCHAR)-1;
|
|
|
|
//
|
|
// Compute the Struct length
|
|
//
|
|
|
|
pDsName->structLen = sizeof (DSNAME) + NamePrefixLen + NameLen -2 * sizeof ( WCHAR);
|
|
|
|
//
|
|
// Copy the name Prefix
|
|
//
|
|
|
|
RtlCopyMemory(pDsName->StringName, NamePrefix,NamePrefixLen);
|
|
|
|
//
|
|
// Copy the Object Name
|
|
//
|
|
|
|
RtlCopyMemory(&(pDsName->StringName[(NamePrefixLen/sizeof(WCHAR))-1]), ObjectName, NameLen);
|
|
}
|
|
else
|
|
{
|
|
pDsName->NameLen = NameLen/sizeof(WCHAR);
|
|
|
|
//
|
|
// Compute the Struct length
|
|
//
|
|
|
|
pDsName->structLen = sizeof (DSNAME) + NameLen - sizeof(WCHAR);
|
|
|
|
//
|
|
// Copy the name Prefix
|
|
//
|
|
|
|
RtlCopyMemory(pDsName->StringName, NamePrefix,NamePrefixLen);
|
|
|
|
//
|
|
// Copy the Object Name
|
|
//
|
|
|
|
RtlCopyMemory(&(pDsName->StringName[0]), ObjectName, NameLen);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// DS Memory Allocation Routine
|
|
//
|
|
//
|
|
|
|
PVOID
|
|
DSAlloc(
|
|
IN ULONG Length
|
|
)
|
|
/*
|
|
|
|
Routine Description:
|
|
|
|
Ds Memory Allocation Routine
|
|
|
|
Arguments:
|
|
|
|
Length - Amount of memory to be allocated
|
|
|
|
Return Values
|
|
|
|
NULL if Memory alloc failed
|
|
Pointer to memory upon success
|
|
*/
|
|
{
|
|
PVOID MemoryToReturn = NULL;
|
|
|
|
__try
|
|
{
|
|
MemoryToReturn = THAllocEx((USHORT) Length);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
MemoryToReturn = NULL;
|
|
}
|
|
|
|
return MemoryToReturn;
|
|
}
|
|
|
|
|
|
VOID
|
|
SampDsBuildRootObjectName()
|
|
/*
|
|
|
|
Routine Description:
|
|
|
|
Initializes the Global variable that holds the
|
|
name of the Root Object
|
|
|
|
*/
|
|
{
|
|
WCHAR RootObjectStringName[] = L"/o=NT" ;
|
|
|
|
//
|
|
// BUG for now this is hard coded to /o=NT,
|
|
// as searches on root currently fail.
|
|
//
|
|
|
|
SampInitializeDsName(
|
|
ROOT_OBJECT,
|
|
NULL,
|
|
0,
|
|
RootObjectStringName,
|
|
sizeof(RootObjectStringName)
|
|
);
|
|
}
|
|
|
|
|