747 lines
22 KiB
C++
747 lines
22 KiB
C++
//+-------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1998.
|
|
//
|
|
// File: rightsca.cxx
|
|
//
|
|
// Contents: Implementation of the DS access control rights cache
|
|
//
|
|
// History: 20-Feb-98 MacM Created
|
|
//
|
|
//--------------------------------------------------------------------
|
|
#include <aclpch.hxx>
|
|
#pragma hdrstop
|
|
#include <stdio.h>
|
|
#include <alsup.hxx>
|
|
|
|
//
|
|
// Global name/id cache
|
|
//
|
|
PACTRL_RIGHTS_CACHE grgRightsNameCache[ACTRL_OBJ_ID_TABLE_SIZE];
|
|
|
|
//
|
|
// Last connection info/time we read from the schema
|
|
//
|
|
static ACTRL_ID_SCHEMA_INFO LastSchemaRead;
|
|
|
|
static RTL_RESOURCE RightsCacheLock;
|
|
BOOL bRightsCacheLockInitialized = FALSE;
|
|
|
|
#define ACTRL_EXT_RIGHTS_CONTAINER L"CN=Extended-Rights,"
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: AccctrlInitializeRightsCache
|
|
//
|
|
// Synopsis: Initialize the access control rights lookup cache
|
|
//
|
|
// Arguments: VOID
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD AccctrlInitializeRightsCache(VOID)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
if (TRUE == bRightsCacheLockInitialized)
|
|
{
|
|
//
|
|
// Just a precautionary measure to make sure that we do not initialize
|
|
// multiple times.
|
|
//
|
|
|
|
ASSERT(FALSE);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
memset(grgRightsNameCache, 0,
|
|
sizeof(PACTRL_RIGHTS_CACHE) * ACTRL_OBJ_ID_TABLE_SIZE);
|
|
|
|
memset(&LastSchemaRead, 0, sizeof(ACTRL_ID_SCHEMA_INFO));
|
|
|
|
__try
|
|
{
|
|
RtlInitializeResource(&RightsCacheLock);
|
|
dwErr = ERROR_SUCCESS;
|
|
bRightsCacheLockInitialized = TRUE;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwErr = RtlNtStatusToDosError(GetExceptionCode());
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: AccctrlFreeRightsCache
|
|
//
|
|
// Synopsis: Frees any memory allocated for the id name/guid cache
|
|
//
|
|
// Arguments: VOID
|
|
//
|
|
// Returns: VOID
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID AccctrlFreeRightsCache(VOID)
|
|
{
|
|
INT i,j;
|
|
PACTRL_RIGHTS_CACHE pNode, pNext;
|
|
|
|
if (FALSE == bRightsCacheLockInitialized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(i = 0; i < ACTRL_OBJ_ID_TABLE_SIZE; i++)
|
|
{
|
|
pNode = grgRightsNameCache[i];
|
|
while(pNode != NULL)
|
|
{
|
|
pNext = pNode->pNext;
|
|
for (j = 0; j < (INT)pNode->cRights; j++)
|
|
{
|
|
AccFree(pNode->RightsList[j]);
|
|
}
|
|
AccFree(pNode->RightsList);
|
|
|
|
AccFree(pNode);
|
|
pNode = pNext;
|
|
}
|
|
}
|
|
|
|
AccFree(LastSchemaRead.pwszPath);
|
|
|
|
RtlDeleteResource(&RightsCacheLock);
|
|
|
|
bRightsCacheLockInitialized = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: AccctrlFindRightsNode
|
|
//
|
|
// Synopsis: Looks up the node for the given class GUID
|
|
//
|
|
// Arguments: [ClassGuid] -- Class guid to look up
|
|
//
|
|
// Returns: NULL -- Node not found
|
|
// else a valid node pointer
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
PACTRL_RIGHTS_CACHE
|
|
AccctrlpLookupClassGuidInCache(IN PGUID ClassGuid)
|
|
{
|
|
PACTRL_RIGHTS_CACHE pNode = NULL;
|
|
|
|
pNode = grgRightsNameCache[ActrlHashGuid(ClassGuid)];
|
|
|
|
while(pNode != NULL)
|
|
{
|
|
if(memcmp(ClassGuid, &pNode->ObjectClassGuid,sizeof(GUID)) == 0)
|
|
{
|
|
break;
|
|
}
|
|
pNode = pNode->pNext;
|
|
}
|
|
|
|
#if DBG
|
|
if(pNode != NULL )
|
|
{
|
|
CHAR szGuid[38];
|
|
PGUID pGuid = &pNode->ObjectClassGuid;
|
|
sprintf(szGuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
pGuid->Data1,pGuid->Data2,pGuid->Data3,pGuid->Data4[0],
|
|
pGuid->Data4[1],pGuid->Data4[2],pGuid->Data4[3],
|
|
pGuid->Data4[4],pGuid->Data4[5],pGuid->Data4[6],
|
|
pGuid->Data4[7]);
|
|
|
|
acDebugOut((DEB_TRACE_LOOKUP,
|
|
"Found guid %s\n",
|
|
szGuid));
|
|
}
|
|
#endif
|
|
|
|
return(pNode);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: AccctrlpInsertRightsNode
|
|
//
|
|
// Synopsis: Updates the information for an existing node or creates and
|
|
// inserts a new one
|
|
//
|
|
// Arguments: [AppliesTo] -- Guid this control right applies to
|
|
// [RightsGuid] -- Control right
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD AccctrlpInsertRightsNode(IN PGUID AppliesTo,
|
|
IN PWSTR ControlRight)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PACTRL_RIGHTS_CACHE Node, pNext, pTrail = NULL;
|
|
PWSTR *NewList;
|
|
BOOL NewNode = FALSE;
|
|
|
|
//
|
|
// First, find the existing node, if it exists
|
|
//
|
|
Node = AccctrlpLookupClassGuidInCache( AppliesTo );
|
|
|
|
if(Node == NULL)
|
|
{
|
|
//
|
|
// Have to create and insert a new one
|
|
//
|
|
Node = (PACTRL_RIGHTS_CACHE)AccAlloc(sizeof(ACTRL_RIGHTS_CACHE));
|
|
|
|
if(Node == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
NewNode = TRUE;
|
|
memcpy(&Node->ObjectClassGuid, AppliesTo, sizeof(GUID));
|
|
Node->cRights=0;
|
|
|
|
pNext = grgRightsNameCache[ActrlHashGuid(AppliesTo)];
|
|
|
|
while(pNext != NULL)
|
|
{
|
|
if(memcmp(AppliesTo, &(pNext->ObjectClassGuid), sizeof(GUID)) == 0)
|
|
{
|
|
dwErr = ERROR_ALREADY_EXISTS;
|
|
acDebugOut((DEB_TRACE_LOOKUP, "Guid collision. Bailing\n"));
|
|
break;
|
|
}
|
|
|
|
pTrail = pNext;
|
|
pNext = pNext->pNext;
|
|
}
|
|
|
|
}
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
if(pTrail == NULL)
|
|
{
|
|
|
|
grgRightsNameCache[ActrlHashGuid(AppliesTo)] = Node;
|
|
|
|
}
|
|
else {
|
|
|
|
pTrail->pNext = Node;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, insert the new applies to list
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
NewList = (PWSTR *)AccAlloc((Node->cRights + 1) * sizeof(PWSTR));
|
|
if(NewList==NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(NewList, Node->RightsList, Node->cRights * sizeof( PWSTR ));
|
|
|
|
NewList[Node->cRights] = (PWSTR)AccAlloc((wcslen(ControlRight) + 1) * sizeof(WCHAR));
|
|
if(NewList[Node->cRights] == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
AccFree(NewList);
|
|
}
|
|
else
|
|
{
|
|
wcscpy(NewList[Node->cRights], ControlRight);
|
|
Node->cRights++;
|
|
AccFree(Node->RightsList);
|
|
Node->RightsList = NewList;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up if necessary
|
|
//
|
|
if(dwErr != ERROR_SUCCESS && NewNode == TRUE)
|
|
{
|
|
AccFree(Node);
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AccDsReadAndInsertExtendedRights
|
|
//
|
|
// Synopsis: Reads the full list of extended rights from the schema
|
|
//
|
|
// Arguments: [IN pLDAP] -- LDAP connection to use
|
|
// [OUT pcItems] -- Where the count of items
|
|
// is returned
|
|
// [OUT RightsList] -- Where the list of rights
|
|
// entries is returned.
|
|
//
|
|
// Notes:
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
DWORD
|
|
AccDsReadAndInsertExtendedRights(IN PLDAP pLDAP)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PWSTR *ppwszValues = NULL, *ppwszApplies = NULL;
|
|
PWSTR rgwszAttribs[3];
|
|
PWSTR pwszERContainer = NULL;
|
|
PDS_NAME_RESULTW pNameRes = NULL;
|
|
LDAPMessage *pMessage, *pEntry;
|
|
ULONG cEntries, i, j;
|
|
PACTRL_RIGHTS_CACHE pCurrentEntry;
|
|
GUID RightsGuid;
|
|
|
|
//
|
|
// Get the subschema path
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
rgwszAttribs[0] = L"configurationNamingContext";
|
|
rgwszAttribs[1] = NULL;
|
|
|
|
dwErr = ldap_search_s(pLDAP,
|
|
NULL,
|
|
LDAP_SCOPE_BASE,
|
|
L"(objectClass=*)",
|
|
rgwszAttribs,
|
|
0,
|
|
&pMessage);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pEntry = ldap_first_entry(pLDAP,
|
|
pMessage);
|
|
|
|
if(pEntry == NULL)
|
|
{
|
|
dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Now, we'll have to get the values
|
|
//
|
|
ppwszValues = ldap_get_values(pLDAP,
|
|
pEntry,
|
|
rgwszAttribs[0]);
|
|
ldap_msgfree(pMessage);
|
|
|
|
if(ppwszValues == NULL)
|
|
{
|
|
dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
|
|
}
|
|
else
|
|
{
|
|
pwszERContainer = (PWSTR)AccAlloc((wcslen(ppwszValues[0]) * sizeof(WCHAR)) +
|
|
sizeof(ACTRL_EXT_RIGHTS_CONTAINER));
|
|
if(pwszERContainer == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pwszERContainer,
|
|
ACTRL_EXT_RIGHTS_CONTAINER);
|
|
wcscat(pwszERContainer,
|
|
ppwszValues[0]);
|
|
|
|
|
|
rgwszAttribs[0] = L"rightsGuid";
|
|
rgwszAttribs[1] = L"appliesTo";
|
|
rgwszAttribs[2] = NULL;
|
|
|
|
//
|
|
// Read the control access rights
|
|
//
|
|
dwErr = ldap_search_s(pLDAP,
|
|
pwszERContainer,
|
|
LDAP_SCOPE_ONELEVEL,
|
|
L"(objectClass=controlAccessRight)",
|
|
rgwszAttribs,
|
|
0,
|
|
&pMessage);
|
|
|
|
dwErr = LdapMapErrorToWin32( dwErr );
|
|
|
|
AccFree(pwszERContainer);
|
|
}
|
|
ldap_value_free(ppwszValues);
|
|
|
|
|
|
//
|
|
// Process the entries
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
pEntry = ldap_first_entry(pLDAP,
|
|
pMessage);
|
|
|
|
if(pEntry == NULL)
|
|
{
|
|
dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
|
|
}
|
|
else
|
|
{
|
|
cEntries = ldap_count_entries( pLDAP, pMessage );
|
|
|
|
for(i = 0; i < cEntries && dwErr == ERROR_SUCCESS; i++) {
|
|
|
|
ppwszValues = ldap_get_values(pLDAP,
|
|
pEntry,
|
|
rgwszAttribs[0]);
|
|
if(ppwszValues == NULL)
|
|
{
|
|
dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Then the list of applies to
|
|
//
|
|
ppwszApplies = ldap_get_values(pLDAP,
|
|
pEntry,
|
|
rgwszAttribs[1]);
|
|
j = 0;
|
|
|
|
while(ppwszApplies[j] != NULL && dwErr == ERROR_SUCCESS)
|
|
{
|
|
|
|
dwErr = UuidFromString(ppwszApplies[j],
|
|
&RightsGuid);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccctrlpInsertRightsNode( &RightsGuid,
|
|
ppwszValues[0]);
|
|
}
|
|
j++;
|
|
}
|
|
|
|
ldap_value_free(ppwszApplies);
|
|
ppwszApplies = NULL;
|
|
ldap_value_free(ppwszValues);
|
|
|
|
}
|
|
|
|
pEntry = ldap_next_entry( pLDAP, pEntry );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
ldap_msgfree(pMessage);
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
dwErr = LdapMapErrorToWin32( dwErr );
|
|
}
|
|
|
|
}
|
|
|
|
return(dwErr) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: AccctrlpLoadRightsCacheFromSchema
|
|
//
|
|
// Synopsis: Reads the control rights schema cache and adds the entries into the
|
|
// cache
|
|
//
|
|
// Arguments: [pLDAP] -- LDAP connection to the server
|
|
// [pwszPath] -- DS path to the object
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD AccctrlpLoadRightsCacheFromSchema(PLDAP pLDAP,
|
|
PWSTR pwszDsPath)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PLDAP pLocalLDAP = pLDAP;
|
|
ULONG cValues[2];
|
|
PWSTR *ppwszValues[2];
|
|
|
|
acDebugOut((DEB_TRACE_LOOKUP, "Reloading rights cache from schema\n"));
|
|
|
|
//
|
|
// If we have no parameters, just return...
|
|
//
|
|
if(pLDAP == NULL && pwszDsPath == NULL)
|
|
{
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// See if we need to read... If our data is over 5 minutes old or if our path referenced is
|
|
// not the same as the last one...
|
|
//
|
|
#define FIVE_MINUTES 300000
|
|
if((LastSchemaRead.LastReadTime != 0 &&
|
|
(GetTickCount() - LastSchemaRead.LastReadTime < FIVE_MINUTES)) &&
|
|
DoPropertiesMatch(pwszDsPath, LastSchemaRead.pwszPath) &&
|
|
((pLDAP == NULL && LastSchemaRead.fLDAP == FALSE) ||
|
|
(pLDAP != NULL && memcmp(pLDAP, &(LastSchemaRead.LDAP), sizeof(LDAP)))))
|
|
|
|
{
|
|
acDebugOut((DEB_TRACE_LOOKUP,"Cache up to date...\n"));
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Need to reinitialize it...
|
|
//
|
|
if(pLDAP == NULL)
|
|
{
|
|
LastSchemaRead.fLDAP = FALSE;
|
|
}
|
|
else
|
|
{
|
|
LastSchemaRead.fLDAP = TRUE;
|
|
memcpy(&(LastSchemaRead.LDAP), pLDAP, sizeof(LDAP));
|
|
}
|
|
|
|
AccFree(LastSchemaRead.pwszPath);
|
|
if(pwszDsPath != NULL)
|
|
{
|
|
ACC_ALLOC_AND_COPY_STRINGW(pwszDsPath, LastSchemaRead.pwszPath, dwErr);
|
|
}
|
|
|
|
LastSchemaRead.LastReadTime = GetTickCount();
|
|
}
|
|
|
|
|
|
|
|
if(dwErr == ERROR_SUCCESS && pLocalLDAP == NULL)
|
|
{
|
|
PWSTR pwszServer = NULL, pwszObject = NULL;
|
|
|
|
dwErr = DspSplitPath( pwszDsPath, &pwszServer, &pwszObject );
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = BindToDSObject(pwszServer, pwszObject, &pLocalLDAP);
|
|
LocalFree(pwszServer);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, get the info. First, extended rights, then the schema info
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccDsReadAndInsertExtendedRights(pLocalLDAP);
|
|
}
|
|
|
|
//
|
|
// See if we need to release our ldap connection
|
|
//
|
|
if(pLocalLDAP != pLDAP && pLocalLDAP != NULL)
|
|
{
|
|
UnBindFromDSObject(&pLocalLDAP);
|
|
}
|
|
|
|
return(dwErr);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: AccctrlLookupRightByName
|
|
//
|
|
// Synopsis: Returns the list of control rights for a given object class
|
|
//
|
|
// Arguments: [pLDAP] -- LDAP connection to the server
|
|
// [pwszPath] -- DS path to the object
|
|
// [pwszName] -- Object class name
|
|
// [pCount] -- Where the count if items is returned
|
|
// [ppRightsList] -- List of control rights
|
|
// [ppwszNameList] -- List of control rights names
|
|
//
|
|
// Returns: ERROR_SUCCESS -- Success
|
|
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
|
|
// ERROR_NOT_FOUND -- No such ID exists
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD
|
|
AccctrlLookupRightsByName(IN PLDAP pLDAP,
|
|
IN PWSTR pwszDsPath,
|
|
IN PWSTR pwszName,
|
|
OUT PULONG pCount,
|
|
OUT PACTRL_CONTROL_INFOW *ControlInfo)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
GUID *ObjectClassGuid, RightsGuid;
|
|
PACTRL_RIGHTS_CACHE Node;
|
|
ULONG Size = 0, i;
|
|
PWSTR GuidName, Current;
|
|
|
|
if((pwszDsPath == NULL && pLDAP == NULL) || pwszName == NULL)
|
|
{
|
|
*pCount = 0;
|
|
*ControlInfo = NULL;
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
RtlAcquireResourceShared(&RightsCacheLock, TRUE);
|
|
|
|
//
|
|
// This is a multi-staged process. First, we have to lookup the guid associated
|
|
// with the object class name. Then, we get the list of control rights for it
|
|
//
|
|
dwErr = AccctrlLookupGuid(pLDAP,
|
|
pwszDsPath,
|
|
pwszName,
|
|
FALSE, // Don't allocate
|
|
&ObjectClassGuid);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
Node = AccctrlpLookupClassGuidInCache(ObjectClassGuid);
|
|
|
|
if(Node == NULL)
|
|
{
|
|
RtlConvertSharedToExclusive( &RightsCacheLock );
|
|
|
|
dwErr = AccctrlpLoadRightsCacheFromSchema(pLDAP, pwszDsPath );
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
Node = AccctrlpLookupClassGuidInCache(ObjectClassGuid);
|
|
if(Node == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if(Node != NULL)
|
|
{
|
|
//
|
|
// Size all of the return strings
|
|
//
|
|
for (i = 0;i < Node->cRights && dwErr == ERROR_SUCCESS; i++) {
|
|
|
|
dwErr = UuidFromString( Node->RightsList[i],&RightsGuid);
|
|
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = AccctrlLookupIdName(pLDAP,
|
|
pwszDsPath,
|
|
&RightsGuid,
|
|
FALSE,
|
|
FALSE,
|
|
&GuidName);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
Size += wcslen( GuidName ) + 1;
|
|
Size += wcslen( Node->RightsList[i] ) + 1;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, allocate the return information
|
|
//
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
*ControlInfo = (PACTRL_CONTROL_INFOW)AccAlloc((Size * sizeof(WCHAR)) +
|
|
(Node->cRights * sizeof(ACTRL_CONTROL_INFOW)));
|
|
if(*ControlInfo == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
Current = (PWSTR)((*ControlInfo) + Node->cRights);
|
|
for (i = 0;i < Node->cRights && dwErr == ERROR_SUCCESS; i++) {
|
|
|
|
UuidFromString( Node->RightsList[i],&RightsGuid);
|
|
|
|
dwErr = AccctrlLookupIdName(pLDAP,
|
|
pwszDsPath,
|
|
&RightsGuid,
|
|
FALSE,
|
|
FALSE,
|
|
&GuidName);
|
|
if(dwErr == ERROR_SUCCESS)
|
|
{
|
|
(*ControlInfo)[i].lpControlId = Current;
|
|
wcscpy(Current, Node->RightsList[i]);
|
|
Current += wcslen(Node->RightsList[i]);
|
|
*Current = L'\0';
|
|
Current++;
|
|
|
|
(*ControlInfo)[i].lpControlName = Current;
|
|
wcscpy(Current, GuidName);
|
|
Current += wcslen(GuidName);
|
|
*Current = L'\0';
|
|
Current++;
|
|
}
|
|
}
|
|
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
AccFree(*ControlInfo);
|
|
}
|
|
else
|
|
{
|
|
*pCount = Node->cRights;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
RtlReleaseResource(&RightsCacheLock);
|
|
|
|
return(dwErr);
|
|
}
|
|
|