|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1996.
//
// File: DSOBJECT.CXX
//
// Contents: DSObject support functions
//
// History: 01-Jul-96 MacM Created
//
//----------------------------------------------------------------------------
#include <aclpch.hxx>
#pragma hdrstop
#define NO_PROPAGATE
#define ACTRL_SD_PROP_NAME L"nTSecurityDescriptor"
#define ACTRL_EXT_RIGHTS_CONTAINER L"CN=Extended-Rights,"
#include <dsgetdc.h>
#include <lmapibuf.h>
#include <mapicode.h>
extern "C" { #include <permit.h>
#include <seopaque.h>
#include <sertlp.h>
#include <ntdsguid.h>
#include <ntldap.h>
}
#define PSD_FROM_DS_PSD(psd) (PSECURITY_DESCRIPTOR)((PBYTE)psd + sizeof(ULONG))
#define BYTE_0_MASK 0xFF
#define BYTE_3(Value) (UCHAR)( (Value) & BYTE_0_MASK)
#define BYTE_2(Value) (UCHAR)( ((Value) >> 8) & BYTE_0_MASK)
#define BYTE_1(Value) (UCHAR)( ((Value) >> 16) & BYTE_0_MASK)
#define BYTE_0(Value) (UCHAR)( ((Value) >> 24) & BYTE_0_MASK)
#define MartaPutUlong(Buffer, Value) { \
((PBYTE)Buffer)[0] = BYTE_0(Value), \ ((PBYTE)Buffer)[1] = BYTE_1(Value), \ ((PBYTE)Buffer)[2] = BYTE_2(Value), \ ((PBYTE)Buffer)[3] = BYTE_3(Value); \ }
DWORD ConvertStringAToStringW ( IN PSTR pszString, OUT PWSTR *ppwszString ) /*++
Routine Description:
This routine will convert an ASCII string to a UNICODE string.
The returned string buffer must be freed via a call to LocalFree
Arguments:
pszString - The string to convert ppwszString - Where the converted string is returned
Return Value:
ERROR_SUCCESS - Success ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
--*/ {
if(pszString == NULL) { *ppwszString = NULL; } else { ULONG cLen = strlen(pszString); *ppwszString = (PWSTR)AccAlloc(sizeof(WCHAR) * (mbstowcs(NULL, pszString, cLen + 1) + 1)); if(*ppwszString != NULL) { mbstowcs(*ppwszString, pszString, cLen + 1); } else { return(ERROR_NOT_ENOUGH_MEMORY); } }
return(ERROR_SUCCESS); }
DWORD ConvertStringWToStringA ( IN PWSTR pwszString, OUT PSTR *ppszString ) /*++
Routine Description:
This routine will convert a UNICODE string to an ANSI string.
The returned string buffer must be freed via a call to LocalFree
Arguments:
pwszString - The string to convert ppszString - Where the converted string is returned
Return Value:
ERROR_SUCCESS - Success ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
--*/ {
if(pwszString == NULL) { *ppszString = NULL; } else { ULONG cLen = wcslen(pwszString); *ppszString = (PSTR)AccAlloc(sizeof(CHAR) * (wcstombs(NULL, pwszString, cLen + 1) + 1)); if(*ppszString != NULL) { wcstombs(*ppszString, pwszString, cLen + 1); } else { return(ERROR_NOT_ENOUGH_MEMORY); } }
return(ERROR_SUCCESS); }
//+---------------------------------------------------------------------------
//
// Function: DspSplitPath
//
// Synopsis: This function splits a path into the server portion and the
// path portion. If the server portion doesn't exist, a NULL is
// returned
//
// Arguments: [IN pwszObjectPath]-- The name of the object to be split
// [OUT ppwszAllocatedServer] -- Where the server name is returned.
// Must be freed via AccFree
// [OUT ppwszReferencePath] -- Ptr within the input path that
// contains the path portion.
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_PATH_NOT_FOUND-- The object was not reachable
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD DspSplitPath(IN PWSTR pwszObjectPath, OUT PWSTR *ppwszAllocatedServer, OUT PWSTR *ppwszReferencePath) { DWORD dwErr = ERROR_SUCCESS; PWSTR Temp = NULL; ULONG Len = 0;
if(IS_UNC_PATH(pwszObjectPath, wcslen(pwszObjectPath))) {
Temp = wcschr(pwszObjectPath + 2, L'\\');
if (Temp == NULL) {
Len = wcslen(pwszObjectPath); } else { Len = (ULONG)(Temp - pwszObjectPath); }
*ppwszAllocatedServer = ( PWSTR )AccAlloc( ( Len + 1 ) * sizeof( WCHAR ) );
if(*ppwszAllocatedServer == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY;
} else { wcsncpy( *ppwszAllocatedServer, pwszObjectPath, Len ); *( *ppwszAllocatedServer + Len ) = UNICODE_NULL; }
if(Temp != NULL) { *ppwszReferencePath = Temp + 1; } else { *ppwszReferencePath = NULL; } } else { *ppwszReferencePath = pwszObjectPath; *ppwszAllocatedServer = NULL; }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: PingDSObjByNameRes
//
// Synopsis: "Pings" the specified DS object, to determine if it is
// reachable or not
//
// REMOVE POST BETA - 1. Raid 107329
//
// Arguments: [IN pObjectName] -- The name of the object
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_PATH_NOT_FOUND-- The object was not reachable
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD PingDSObjByNameRes(IN PWSTR pwszDSObj, IN PDS_NAME_RESULTW pNameRes) { acDebugOut((DEB_TRACE, "in PingDSObjByNameRes\n")); DWORD dwErr;
if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) { dwErr = ERROR_PATH_NOT_FOUND; } else { //
// Now, we'll bind to the object, and then do the read
//
PLDAP pLDAP;
dwErr = BindToDSObject(NULL, pNameRes->rItems[0].pDomain, &pLDAP);
if(dwErr == ERROR_SUCCESS) { PLDAPMessage pMessage = NULL; PWSTR rgAttribs[2];
rgAttribs[0] = L"distinguishedName"; rgAttribs[1] = NULL;
if(dwErr == ERROR_SUCCESS) { dwErr = ldap_search_s(pLDAP, (PWSTR)pwszDSObj, LDAP_SCOPE_BASE, L"(objectClass=*)", rgAttribs, 0, &pMessage);
dwErr = LdapMapErrorToWin32( dwErr ); }
if(dwErr == ERROR_SUCCESS) { LDAPMessage *pEntry = NULL; pEntry = ldap_first_entry(pLDAP, pMessage);
if(pEntry == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } else { //
// Now, we'll have to get the values
//
PWSTR *ppwszValues = ldap_get_values(pLDAP, pEntry, rgAttribs[0]); if(ppwszValues == NULL) {
if(pLDAP->ld_errno == LDAP_NO_SUCH_ATTRIBUTE ) {
dwErr = ERROR_SUCCESS; } else { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } } else { ldap_value_free(ppwszValues); } }
ldap_msgfree(pMessage); } } }
acDebugOut((DEB_TRACE, "out PingDSObjByNameRes: %lu\n", dwErr)); return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: DspBindAndCrack
//
// Synopsis: Does a DsCrackName on the object
//
// Arguments: [IN pwszServer] -- Optional server name to bind to
// [IN pwszDSObj] -- The DS object to bind to
// [OUT pResults] -- The returned cracked name
//
// Returns: ERROR_SUCCESS -- The object is reachable
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD DspBindAndCrack( IN PWSTR pwszServer, OPTIONAL IN PWSTR pwszDSObj, IN DWORD OptionalDsGetDcFlags, OUT PDS_NAME_RESULTW *pResults ) { return DspBindAndCrackEx( pwszServer, pwszDSObj, OptionalDsGetDcFlags, DS_FQDN_1779_NAME, pResults ); }
//+---------------------------------------------------------------------------
//
// Function: DspBindAndCrackEx
//
// Synopsis: Does a DsCrackName on the object
//
// Arguments: [IN pwszServer] -- Optional server name to bind to
// [IN pwszDSObj] -- The DS object to bind to
// [IN formatDesired] -- indicates the format of the returned name
// [OUT pResults] -- The returned cracked name
//
// Returns: ERROR_SUCCESS -- The object is reachable
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD DspBindAndCrackEx( IN PWSTR pwszServer, IN PWSTR pwszDSObj, IN DWORD OptionalDsGetDcFlags, IN DS_NAME_FORMAT formatDesired, OUT PDS_NAME_RESULTW *pResults ) { DWORD dwErr = ERROR_SUCCESS;
HANDLE hDS = NULL; PDS_NAME_RESULTW pNameRes; PDOMAIN_CONTROLLER_INFOW pDCI = NULL; BOOL NamedServer = FALSE;
//
// The path we are given could be of the form \\\\servername\\path. If it is, it
// is not necessary to do the DsGetDcName call. We'll just use the server name
// we are given
//
if(pwszServer != NULL) { NamedServer = TRUE; } else { dwErr = DsGetDcNameW(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED | OptionalDsGetDcFlags, // DS_IP_REQUIRED
&pDCI);
if(dwErr == ERROR_SUCCESS) { pwszServer = pDCI[0].DomainControllerName; // pDCI[0].DomainControllerAddress;
} }
//
// Do the bind and crack
//
if(dwErr == ERROR_SUCCESS) { dwErr = DsBindW(pwszServer, NULL, &hDS);
if(dwErr == ERROR_SUCCESS) { dwErr = DsCrackNamesW(hDS, DS_NAME_NO_FLAGS, DS_UNKNOWN_NAME, formatDesired, 1, &pwszDSObj, &pNameRes);
if (dwErr == ERROR_SUCCESS) {
if(pNameRes->cItems != 0 && pNameRes->rItems[0].status == DS_NAME_ERROR_DOMAIN_ONLY && NamedServer == FALSE ) { NetApiBufferFree(pDCI); pDCI = NULL; dwErr = DsGetDcNameW(NULL, pNameRes->rItems[0].pDomain, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED | OptionalDsGetDcFlags, // DS_IP_REQUIRED |
&pDCI); if(dwErr == ERROR_SUCCESS) { DsUnBindW(&hDS); hDS = NULL;
dwErr = DsBindW(pDCI[0].DomainControllerName, // DomainControllerAddress,
NULL, &hDS);
if(dwErr == ERROR_SUCCESS) { dwErr = DsCrackNamesW(hDS, DS_NAME_NO_FLAGS, DS_UNKNOWN_NAME, formatDesired, 1, &pwszDSObj, &pNameRes); }
}
}
//
// If this is a case where we don't have a named server, handle
// the case where an object was created on one Dc, but we've just
// bound to a second one
//
//
if (dwErr == ERROR_SUCCESS && formatDesired == DS_FQDN_1779_NAME && NamedServer == FALSE ) { dwErr = PingDSObjByNameRes( pwszDSObj,pNameRes );
if(dwErr != ERROR_SUCCESS) { DsFreeNameResultW(pNameRes); }
if(dwErr == ERROR_PATH_NOT_FOUND && OptionalDsGetDcFlags == 0) { dwErr = DspBindAndCrackEx( pDCI[0].DomainControllerName, //DomainControllerAddress,
pwszDSObj, DS_WRITABLE_REQUIRED, formatDesired, &pNameRes ); } }
*pResults = pNameRes; }
if(hDS != NULL) { DsUnBindW(&hDS); } } }
if(pDCI != NULL) { NetApiBufferFree(pDCI); }
return( dwErr ); }
//+---------------------------------------------------------------------------
//
// Function: BindToDSObject
//
// Synopsis: Binds to a DS object
//
// Arguments: [IN pwszServer] -- OPTIONAL. If specified, this is the name
// of the server to bind to
// [IN pwszDSObj] -- The DS object to bind to
// [OUT ppLDAP] -- The returned LDAP handle
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_PATH_NOT_FOUND-- The object was not reachable
//
// Notes: The returned LDAP handle must be closed via UnbindFromDSObject
//
//----------------------------------------------------------------------------
DWORD BindToDSObject(IN PWSTR pwszServer, OPTIONAL IN LPWSTR pwszDSObj, OUT PLDAP *ppLDAP) { acDebugOut((DEB_TRACE, "in BindToDSObject\n")); PDOMAIN_CONTROLLER_INFOW pDCI = NULL; DWORD dwErr = ERROR_SUCCESS;
//
// The path we are given could be of the form \\\\servername\\path. If it is, it
// is not necessary to do the DsGetDcName call. We'll just use the server name
// we are given
//
// Change: in order to use mutual authentication, A DNS format domain name must
// be passed into ldap_open/ldap_init. So even a servername is passed in, it's
// necessary to call DsGetDcNameW to get the DNS format domain name.
// Since we asked for DIRECTORY_SERVICE_REQUIRED, this call won't talk to any
// NT4 domain and the DNS name should always be returned. If it fails to get the
// DNS name, we will fail this function - by design.
//
dwErr = DsGetDcNameW(pwszServer, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_DNS_NAME, &pDCI);
if(dwErr == ERROR_SUCCESS) { *ppLDAP = ldap_open(pDCI->DomainName, LDAP_PORT);
if(*ppLDAP == NULL) { dwErr = ERROR_PATH_NOT_FOUND; } else { //
// Do a bind...
//
dwErr = ldap_bind_s(*ppLDAP, NULL, NULL, LDAP_AUTH_SSPI);
}
}
if(pDCI != NULL) { NetApiBufferFree(pDCI); }
acDebugOut((DEB_TRACE, "out BindToDSObject: %lu\n", dwErr)); return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: UnBindFromDSObject
//
// Synopsis: Closes a binding to a DS object
//
// Arguments: [IN ppLDAP] -- The LDAP connection to close
//
// Returns: ERROR_SUCCESS -- The object is reachable
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD UnBindFromDSObject(OUT PLDAP *ppLDAP) { acDebugOut((DEB_TRACE, "in UnBindFromDSObject\n")); DWORD dwErr = ERROR_SUCCESS;
if(*ppLDAP != NULL) { ldap_unbind(*ppLDAP); *ppLDAP = NULL; }
acDebugOut((DEB_TRACE, "out UnBindFromDSObject: %lu\n", dwErr)); return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: ReadDSObjSecDesc
//
// Synopsis: Reads the security descriptor from the specied object via
// the open ldap connection
//
// Arguments: [IN pLDAP] -- The open LDAP connection
// [IN SeInfo] -- Parts of the security descriptor to
// read.
// [IN pwszDSObj] -- The DSObject to get the security
// descriptor for
// [OUT ppSD] -- Where the security descriptor is
// returned
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
//
// Notes: The returned security descriptor must be freed with LocalFree
//
//----------------------------------------------------------------------------
DWORD ReadDSObjSecDesc(IN PLDAP pLDAP, IN PWSTR pwszObject, IN SECURITY_INFORMATION SeInfo, OUT PSECURITY_DESCRIPTOR *ppSD) { DWORD dwErr = ERROR_SUCCESS;
PLDAPMessage pMessage = NULL; PWSTR rgAttribs[2]; BYTE berValue[8];
//
// JohnsonA The BER encoding is current hardcoded. Change this to use
// AndyHe's BER_printf package once it's done.
//
berValue[0] = 0x30; berValue[1] = 0x03; berValue[2] = 0x02; berValue[3] = 0x01; berValue[4] = (BYTE)((ULONG)SeInfo & 0xF);
LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR)berValue }, TRUE };
PLDAPControl ServerControls[2] = { &SeInfoControl, NULL };
rgAttribs[0] = ACTRL_SD_PROP_NAME; rgAttribs[1] = NULL;
if(dwErr == ERROR_SUCCESS) { dwErr = ldap_search_ext_s(pLDAP, pwszObject, LDAP_SCOPE_BASE, L"(objectClass=*)", rgAttribs, 0, (PLDAPControl *)&ServerControls, NULL, NULL, 10000, &pMessage);
dwErr = LdapMapErrorToWin32( dwErr ); }
if(dwErr == ERROR_SUCCESS) { LDAPMessage *pEntry = NULL; pEntry = ldap_first_entry(pLDAP, pMessage);
if(pEntry == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } else { //
// Now, we'll have to get the values
//
PWSTR *ppwszValues = ldap_get_values(pLDAP, pEntry, rgAttribs[0]); if(ppwszValues == NULL) { if(pLDAP->ld_errno == LDAP_NO_SUCH_ATTRIBUTE) { dwErr = ERROR_ACCESS_DENIED; } else { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); }
} else { PLDAP_BERVAL *pSize = ldap_get_values_len(pLDAP, pMessage, rgAttribs[0]); if(pSize == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } else { //
// Allocate the security descriptor to return
//
*ppSD = (PSECURITY_DESCRIPTOR)AccAlloc((*pSize)->bv_len); if(*ppSD == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { memcpy(*ppSD, (PBYTE)(*pSize)->bv_val, (*pSize)->bv_len); } ldap_value_free_len(pSize); }
ldap_value_free(ppwszValues); } }
ldap_msgfree(pMessage); }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: GetSDForDSObj
//
// Synopsis: Gets a security descriptor from a DS object
//
// Arguments: [IN pwszDSObj] -- The DSObject to get the security
// descriptor for
// [OUT ppSD] -- Where the security descriptor is
// returned
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
// ERROR_INVALID_PARAMETER The object name that was given was in
// a bad format (not \\x\y)
//
// Notes: The returned security descriptor must be freed with LocalFree
//
//----------------------------------------------------------------------------
DWORD GetSDForDSObj(IN LPWSTR pwszDSObj, IN SECURITY_INFORMATION SeInfo, OUT PSECURITY_DESCRIPTOR *ppSD) { acDebugOut((DEB_TRACE, "in GetSDForDSObj\n")); DWORD dwErr = ERROR_SUCCESS; PWSTR pwszServer = NULL, pwszPath = NULL;
dwErr = DspSplitPath(pwszDSObj, &pwszServer, &pwszPath);
if(dwErr == ERROR_SUCCESS) {
//
// Convert the name into attributed format
//
PDS_NAME_RESULTW pNameRes;
dwErr = DspBindAndCrack( pwszServer, pwszPath, 0, &pNameRes );
if(dwErr == ERROR_SUCCESS) { if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) { dwErr = ERROR_PATH_NOT_FOUND; } else { //
// Now, we'll bind to the object, and then do the read
//
PLDAP pLDAP;
dwErr = BindToDSObject(pwszServer, pNameRes->rItems[0].pDomain, &pLDAP);
if(dwErr == ERROR_SUCCESS) { //
// Now, we'll do the read...
//
dwErr = ReadDSObjSecDesc(pLDAP, pNameRes->rItems[0].pName, SeInfo, ppSD); UnBindFromDSObject(&pLDAP); } } DsFreeNameResultW(pNameRes); }
AccFree(pwszServer); }
acDebugOut((DEB_TRACE, "Out GetSDForDSObj: %lu\n", dwErr)); return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: ReadDSObjPropertyRights
//
// Synopsis: Reads the specified property rights from the named DS object
//
// Arguments: [IN pwszDSObj] -- The DSObject to get the security
// descriptor for
// [IN pRightsList] -- The rights information to get
// [IN cRights] -- Number of items in the rights list
// [IN AccessList] -- The access list to initialize
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_INVALID_PARAMETER A NULL parameter was given
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD ReadDSObjPropertyRights(IN LPWSTR pwszDSObj, IN PACTRL_RIGHTS_INFO pRightsList, IN ULONG cRights, IN CAccessList& AccessList) { acDebugOut((DEB_TRACE, "in ReadDSObjPropertyRights\n")); DWORD dwErr = ERROR_SUCCESS;
if(pwszDSObj == NULL || pRightsList == NULL) { return(ERROR_INVALID_PARAMETER); } else { //
// Build the security info structure we will need
//
SECURITY_INFORMATION SeInfo = 0;
for(ULONG i = 0; i < cRights; i++) { SeInfo |= pRightsList[i].SeInfo; }
PSECURITY_DESCRIPTOR pSD; dwErr = GetSDForDSObj(pwszDSObj, SeInfo, &pSD);
if(dwErr == ERROR_SUCCESS) { //
// Now, we'll simply add the appropriate property based entries
// to our access list.
//
for(ULONG iIndex = 0; iIndex < cRights && dwErr == ERROR_SUCCESS; iIndex++) { dwErr = AccessList.AddSD(pSD, pRightsList[iIndex].SeInfo, pRightsList[iIndex].pwszProperty, FALSE);
} AccFree(pSD); }
}
acDebugOut((DEB_TRACE, "out ReadDSObjPropertyRights: %lu\n", dwErr)); return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: ReadAllDSObjPropertyRights
//
// Synopsis: Reads the all the property rights from the named DS object
//
// Arguments: [IN pwszDSObj] -- The DSObject to get the security
// descriptor for
// [IN pRightsList] -- The rights information to get
// [IN cRights] -- Number of items in the rights list
// [IN AccessList] -- The access list to initialize
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_INVALID_PARAMETER A NULL parameter was given
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD ReadAllDSObjPropertyRights(IN LPWSTR pwszDSObj, IN PACTRL_RIGHTS_INFO pRightsList, IN ULONG cRights, IN CAccessList& AccessList) { DWORD dwErr = ERROR_SUCCESS;
if(pwszDSObj == NULL || pRightsList == NULL) { return(ERROR_INVALID_PARAMETER); } else { //
// Build the security info structure we will need
//
SECURITY_INFORMATION SeInfo = 0;
for(ULONG i = 0; i < cRights; i++) { SeInfo |= pRightsList[i].SeInfo; }
PSECURITY_DESCRIPTOR pSD; dwErr = GetSDForDSObj(pwszDSObj, SeInfo, &pSD);
if(dwErr == ERROR_SUCCESS) { //
// Now, we'll simply add it to our access list. We'll ignore
// any rights info after the first one.
//
dwErr = AccessList.AddSD(pSD, pRightsList[0].SeInfo, NULL, TRUE); AccFree(pSD); }
}
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: SetDSObjSecurityInfo
//
// Synopsis: Sets the security descriptor on the DS object
//
// Arguments: [IN pwszDSObj] -- The DSObject to get the security
// descriptor for
// [IN SeInfo] -- Security Infofor the security
// descriptor
// [IN pwszProperty] -- Object property to set the access on
// [IN pSD] -- Security descriptor to set
// [IN cSDSize] -- Size of the security descriptor
// [IN pfStopFlag] -- The stop flag to monitor
// [IN pcProcessed] -- Where to increment the count of
// processsed items
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_INVALID_PARAMETER A NULL parameter was given
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD SetDSObjSecurityInfo(IN LPWSTR pwszDSObj, IN SECURITY_INFORMATION SeInfo, IN PWSTR pwszProperty, IN PSECURITY_DESCRIPTOR pSD, IN ULONG cSDSize, IN PULONG pfStopFlag, IN PULONG pcProcessed) { DWORD dwErr = ERROR_SUCCESS; PWSTR pwszServer = NULL, pwszPath = NULL;
dwErr = DspSplitPath(pwszDSObj, &pwszServer, &pwszPath);
if(dwErr == ERROR_SUCCESS) {
//
// Convert the name into attributed format
//
PDS_NAME_RESULTW pNameRes;
dwErr = DspBindAndCrack( pwszServer, pwszPath, 0, &pNameRes );
if(dwErr == ERROR_SUCCESS) { if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) { dwErr = ERROR_PATH_NOT_FOUND; } else { //
// Convert our name to ascii
//
PLDAP pLDAP;
dwErr = BindToDSObject(pwszServer, pNameRes->rItems[0].pDomain, &pLDAP);
if(dwErr == ERROR_SUCCESS) { #ifdef NO_PROPAGATE
dwErr = StampSD(pNameRes->rItems[0].pName, cSDSize, SeInfo, pSD, pLDAP); #else
dwErr = PropagateDSRightsDeep(NULL, pSD, SeInfo, pNameRes->rItems[0].pName, pLDAP, pcProcessed, pfStopFlag); #endif
UnBindFromDSObject(&pLDAP); }
}
DsFreeNameResultW(pNameRes); }
AccFree(pwszServer); }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: PingDSObj
//
// Synopsis: "Pings" the specified DS object, to determine if it is
// reachable or not
//
// Arguments: [IN pObjectName] -- The name of the object
//
// Returns: ERROR_SUCCESS -- The object is reachable
// ERROR_PATH_NOT_FOUND-- The object was not reachable
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD PingDSObj(IN LPCWSTR pwszDSObj) { acDebugOut((DEB_TRACE, "in PingDSObj\n")); DWORD dwErr;
PWSTR pwszServer = NULL, pwszPath = NULL;
dwErr = DspSplitPath((PWSTR)pwszDSObj, &pwszServer, &pwszPath);
if(dwErr == ERROR_SUCCESS) {
//
// Convert the name into attributed format
//
PDS_NAME_RESULTW pNameRes; dwErr = DspBindAndCrack(pwszServer, pwszPath, 0, &pNameRes); if(dwErr == ERROR_SUCCESS) { if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) { dwErr = ERROR_PATH_NOT_FOUND; } else { //
// Now, we'll bind to the object, and then do the read
//
PLDAP pLDAP;
dwErr = BindToDSObject(pwszServer, pNameRes->rItems[0].pDomain, &pLDAP);
if(dwErr == ERROR_SUCCESS) { PLDAPMessage pMessage = NULL; PWSTR rgAttribs[2];
rgAttribs[0] = L"distinguishedName"; rgAttribs[1] = NULL;
if(dwErr == ERROR_SUCCESS) { dwErr = ldap_search_s(pLDAP, pwszPath, LDAP_SCOPE_BASE, L"(objectClass=*)", rgAttribs, 0, &pMessage);
dwErr = LdapMapErrorToWin32( dwErr ); }
if(dwErr == ERROR_SUCCESS) { LDAPMessage *pEntry = NULL; pEntry = ldap_first_entry(pLDAP, pMessage);
if(pEntry == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } else { //
// Now, we'll have to get the values
//
PWSTR *ppwszValues = ldap_get_values(pLDAP, pEntry, rgAttribs[0]); if(ppwszValues == NULL) {
if(pLDAP->ld_errno == LDAP_NO_SUCH_ATTRIBUTE ) {
dwErr = ERROR_SUCCESS; } else { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } } else { ldap_value_free(ppwszValues); } }
ldap_msgfree(pMessage); } } } DsFreeNameResultW(pNameRes); }
AccFree(pwszServer); } acDebugOut((DEB_TRACE, "out PingDSObj: %lu\n", dwErr)); return(dwErr); }
DWORD Nt4NameToNt5Name(IN PWSTR pwszName, IN PWSTR pwszDomain, OUT PWSTR *ppwszNt5Name) { DWORD dwErr = ERROR_SUCCESS;
WCHAR wszFullName[MAX_PATH + 1]; LPWSTR pwszFullName;
ULONG cLen = wcslen(pwszName) + 1;
if(pwszDomain != NULL) { cLen += wcslen(pwszDomain) + 1; }
if(cLen < MAX_PATH + 1) { pwszFullName = wszFullName; } else { pwszFullName = (PWSTR)AccAlloc(cLen * sizeof(WCHAR)); if(pwszFullName == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } }
if(dwErr == ERROR_SUCCESS) { if(pwszDomain != NULL) { wcscpy(pwszFullName, pwszDomain); wcscat(pwszFullName, L"\\"); } else { *pwszFullName = L'\0'; } wcscat(pwszFullName, pwszName);
}
//
// Now, for the crack name...
//
if(dwErr == ERROR_SUCCESS) { PDS_NAME_RESULTW pNameRes;
dwErr = DspBindAndCrack(NULL, wszFullName, 0, &pNameRes ); if(dwErr == ERROR_SUCCESS) { if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) { dwErr = ERROR_PATH_NOT_FOUND; } else { ACC_ALLOC_AND_COPY_STRINGW(pNameRes->rItems[0].pName, *ppwszNt5Name, dwErr); } } else { if(dwErr == MAPI_E_LOGON_FAILED) { dwErr = ERROR_LOGON_FAILURE; }
}
DsFreeNameResultW(pNameRes); }
//
// See if we need to free our buffer
//
if(pwszFullName != wszFullName) { AccFree(pwszFullName); }
return(dwErr); }
#define CLEANUP_ON_INTERRUPT(pstopflag) \
if(*pstopflag != 0) \ { \ goto DSCleanup; \ } //+---------------------------------------------------------------------------
//
// Function: PropagateDSRightsDeep, recursive
//
// Synopsis: Does a deep propagation of the access.
//
// Arguments: [IN pParentSD] -- The current parent sd
// [IN SeInfo] -- What is being written
// [IN pwszFile] -- Parent file path
// [IN pcProcessed] -- Where the number processed is
// returned.
// [IN pfStopFlag] -- Stop flag to monitor
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
//
//----------------------------------------------------------------------------
DWORD PropagateDSRightsDeep(IN PSECURITY_DESCRIPTOR pParentSD, IN PSECURITY_DESCRIPTOR pChildSD, IN SECURITY_INFORMATION SeInfo, IN PWSTR pwszDSObject, IN PLDAP pLDAP, IN PULONG pcProcessed, IN PULONG pfStopFlag) { acDebugOut((DEB_TRACE, "in PropagateDSRightsDeep\n")); DWORD dwErr = ERROR_SUCCESS; BOOL fFreeChildSD = FALSE;
acDebugOut((DEB_TRACE_PROP, "Processing %ws\n", pwszDSObject));
//
// If our security descriptor is already in DS form, then we'll have
// to adjust for that
//
if(pChildSD != NULL) { PULONG pSE = (PULONG)(pChildSD); if(*pSE == SeInfo) { pChildSD = (PSECURITY_DESCRIPTOR)((PBYTE)pChildSD + sizeof(ULONG)); } } else { dwErr = ReadDSObjSecDesc(pLDAP, pwszDSObject, SeInfo, &pChildSD); if(dwErr == ERROR_SUCCESS) { fFreeChildSD = TRUE; } else { return(dwErr); } }
//
// Ok, we'll convert our path to a narrow string, and then we'll enumerate
// all of the children
//
PSECURITY_DESCRIPTOR pNewSD = NULL; PLDAPMessage pMessage = NULL;
//
// First, we'll create the new SD...
//
HANDLE hProcessToken = NULL; GENERIC_MAPPING GenMap; GenMap.GenericRead = GENERIC_READ_MAPPING; GenMap.GenericWrite = GENERIC_WRITE_MAPPING; GenMap.GenericExecute = GENERIC_EXECUTE_MAPPING; GenMap.GenericAll = GENERIC_ALL_MAPPING;
dwErr = GetCurrentToken( &hProcessToken ); if(dwErr == ERROR_SUCCESS) { #ifdef DBG
DebugDumpSD("CPOSE ParentSD", pParentSD); DebugDumpSD("CPOSE ChildSD", pChildSD); #endif
if(CreatePrivateObjectSecurityEx(pParentSD, pChildSD, &pNewSD, NULL, TRUE, SEF_DACL_AUTO_INHERIT | SEF_SACL_AUTO_INHERIT, hProcessToken, &GenMap) == FALSE) { dwErr = GetLastError(); } else { #ifdef DBG
DebugDumpSD("CPOSE NewSD", pNewSD); #endif
//
// Stamp the SD on the object... This means that we'll have
// to allocate a new security descriptor that is 4 bytes
// bigger than what we need, and set our SeInfo
//
PSECURITY_DESCRIPTOR pSetSD = NULL; ULONG cNewSDSize = 0;
if(RtlpAreControlBitsSet((PISECURITY_DESCRIPTOR)pChildSD, SE_SELF_RELATIVE)) { cNewSDSize = RtlLengthSecurityDescriptor(pNewSD); ASSERT(cNewSDSize != 0); } else { MakeSelfRelativeSD(pNewSD, NULL, &cNewSDSize); ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER); }
cNewSDSize += sizeof(ULONG);
pSetSD = (PSECURITY_DESCRIPTOR)AccAlloc(cNewSDSize); if(pSetSD == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { pSetSD = (PSECURITY_DESCRIPTOR) ((PBYTE)pSetSD + sizeof(ULONG));
if(RtlpAreControlBitsSet((PISECURITY_DESCRIPTOR)pChildSD, SE_SELF_RELATIVE)) { memcpy(pSetSD, pNewSD, cNewSDSize - sizeof(ULONG)); } else { if(MakeSelfRelativeSD(pNewSD, pSetSD, &cNewSDSize) == FALSE) { dwErr = GetLastError(); } }
PULONG pSE = (PULONG)((PBYTE)pSetSD - sizeof(ULONG)); *pSE = SeInfo;
//
// We need to pass in the security_information
//
pSetSD = (PSECURITY_DESCRIPTOR)pSE;
//
// Now, do the write
//
dwErr = StampSD(pwszDSObject, cNewSDSize, SeInfo, pSetSD, pLDAP); AccFree(pSetSD); } } }
CLEANUP_ON_INTERRUPT(pfStopFlag); if(dwErr == ERROR_SUCCESS) { PWSTR rgAttribs[2]; WCHAR wszAttrib[]=L"distinguishedName";
//
// Do the search...
//
rgAttribs[0] = wszAttrib; rgAttribs[1] = NULL;
if(dwErr == ERROR_SUCCESS) { dwErr = ldap_search_s(pLDAP, pwszDSObject, LDAP_SCOPE_ONELEVEL, L"(objectClass=*)", rgAttribs, 0, &pMessage);
dwErr = LdapMapErrorToWin32( dwErr ); }
if(dwErr == ERROR_SUCCESS) {
ULONG cChildren = ldap_count_entries(pLDAP, pMessage); acDebugOut((DEB_TRACE_PROP, "%ws has %lu children\n", pwszDSObject, cChildren));
LDAPMessage *pEntry = ldap_first_entry(pLDAP, pMessage); for(ULONG i = 0; i < cChildren; i++) { if(pEntry == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); break; }
//
// Now, we'll have to get the values
//
CLEANUP_ON_INTERRUPT(pfStopFlag); PWSTR *ppwszValues = ldap_get_values(pLDAP, pEntry, rgAttribs[0]);
if(ppwszValues == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } else { //
// Go ahead and propagate to the child
//
acDebugOut((DEB_TRACE_PROP, "Child %ws of %ws [%lu]\n", ppwszValues[0], pwszDSObject, i));
dwErr = PropagateDSRightsDeep(pNewSD, NULL, SeInfo, ppwszValues[0], pLDAP, pcProcessed, pfStopFlag);
ldap_value_free(ppwszValues); CLEANUP_ON_INTERRUPT(pfStopFlag); }
pEntry = ldap_next_entry(pLDAP, pEntry); } } }
DSCleanup: ldap_msgfree(pMessage); DestroyPrivateObjectSecurity(&pNewSD);
if(fFreeChildSD == TRUE) { AccFree(pChildSD); }
acDebugOut((DEB_TRACE, "Out PropagateDSRightsDeep: %ld\n", dwErr)); return(dwErr);
}
//+---------------------------------------------------------------------------
//
// Function: StampSD
//
// Synopsis: Actually stamps the security descriptor on the object.
//
// Arguments: [IN pwszObject] -- The object to stamp the SD on
// [IN cSDSize] -- The size of the security descriptor
// [IN SeInfo] -- SecurityInformation about the security
// descriptor
// [IN pSD] -- The SD to stamp
// [IN pLDAP] -- The LDAP connection to use
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
//
//----------------------------------------------------------------------------
DWORD StampSD(IN PWSTR pwszObject, IN ULONG cSDSize, IN SECURITY_INFORMATION SeInfo, IN PSECURITY_DESCRIPTOR pSD, IN PLDAP pLDAP) { DWORD dwErr = ERROR_SUCCESS;
acDebugOut((DEB_TRACE_PROP, "Stamping %ws\n", pwszObject));
//
// Now, we'll do the write. The security descriptor
// we got passed in better not be in the old Ds format,
// where the leading 4 bytes are the SECURITY_INFORMATION, which we'll skip
// and replace with control information
//
ASSERT(*(PULONG)pSD > 0xF );
PLDAPMod rgMods[2]; PLDAP_BERVAL pBVals[2]; LDAPMod Mod; LDAP_BERVAL BVal; BYTE ControlBuffer[ 5 ];
LDAPControl SeInfoControl = { LDAP_SERVER_SD_FLAGS_OID_W, { 5, (PCHAR) &ControlBuffer }, TRUE };
//
// !!! Hardcoded for now. Use Andyhe's BER_printf once it's done.
//
ControlBuffer[0] = 0x30; ControlBuffer[1] = 0x3; ControlBuffer[2] = 0x02; // Denotes an integer;
ControlBuffer[3] = 0x01; // Size
ControlBuffer[4] = (BYTE)((ULONG)SeInfo & 0xF);
PLDAPControl ServerControls[2] = { &SeInfoControl, NULL };
ASSERT(IsValidSecurityDescriptor( pSD ) );
rgMods[0] = &Mod; rgMods[1] = NULL;
pBVals[0] = &BVal; pBVals[1] = NULL;
BVal.bv_len = cSDSize; BVal.bv_val = (PCHAR)pSD;
Mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; Mod.mod_type = ACTRL_SD_PROP_NAME; Mod.mod_values = (PWSTR *)pBVals;
//
// Now, we'll do the write...
//
dwErr = ldap_modify_ext_s(pLDAP, pwszObject, rgMods, (PLDAPControl *)&ServerControls, NULL);
dwErr = LdapMapErrorToWin32(dwErr);
#if DBG
PACL pAcl = RtlpDaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR)pSD); ACL_SIZE_INFORMATION AclSize; ACL_REVISION_INFORMATION AclRev; PKNOWN_ACE pAce; PSID pSid; DWORD iIndex; DWORD GuidPart; DWORD OldInfoLevel;
//
// Now, dump all of the aces
//
if(pAcl) { pAce = (PKNOWN_ACE)FirstAce(pAcl); for(iIndex = 0; iIndex < pAcl->AceCount; iIndex++) { //
// If it's an object ace, dump the guids
//
if(IsObjectAceType(pAce)) { OldInfoLevel = acInfoLevel; // acInfoLevel |= DEB_TRACE_SD;
DebugDumpGuid("\t\t\tObjectId", RtlObjectAceObjectType(pAce)); GuidPart = (ULONG)((ULONG_PTR)RtlObjectAceObjectType(pAce)); ASSERT(GuidPart != 0x2bfff20); acInfoLevel = OldInfoLevel; } pAce = (PKNOWN_ACE)NextAce(pAce); } } #endif
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccDsReadSchemaInfo
//
// Synopsis: Reads the schema object/property info.
//
// Arguments: [IN pLDAP] -- LDAP connection to use
// [OUT pcClasses] -- Where the count of class info
// is returned
// [OUT pppwszClasses] -- Where the list of classes info
// is returned. Freed with
// ldap_value_free
// [OUT pcAttributes] -- Where the count of property infos
// is returned
// [OUT pppwszAttributes] -- Where the list of property infos
// is returned. Freed with
// ldap_value_free
//
// Returns: ERROR_SUCCESS -- Success
//
//----------------------------------------------------------------------------
DWORD AccDsReadSchemaInfo (IN PLDAP pLDAP, OUT PULONG pcClasses, OUT PWSTR **pppwszClasses, OUT PULONG pcAttributes, OUT PWSTR **pppwszAttributes) { DWORD dwErr = ERROR_SUCCESS; PWSTR *ppwszValues = NULL; PWSTR rgwszAttribs[3]; PDS_NAME_RESULTW pNameRes = NULL; LDAPMessage *pMessage, *pEntry;
*pcClasses = 0; *pcAttributes = 0; *pppwszAttributes = NULL; *pppwszClasses = NULL;
//
// Get the subschema path
//
if(dwErr == ERROR_SUCCESS) { rgwszAttribs[0] = L"subschemaSubentry"; 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 { rgwszAttribs[0] = L"extendedClassInfo"; rgwszAttribs[1] = L"extendedAttributeInfo"; rgwszAttribs[2] = NULL;
dwErr = ldap_search_s(pLDAP, ppwszValues[0], LDAP_SCOPE_BASE, L"(objectClass=*)", rgwszAttribs, 0, &pMessage); ldap_value_free(ppwszValues);
if(dwErr == ERROR_SUCCESS) { ldap_count_entries( pLDAP, pMessage ); pEntry = ldap_first_entry(pLDAP, pMessage);
if(pEntry == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } else { //
// Now, we'll have to get the values
//
*pppwszClasses = ldap_get_values(pLDAP, pEntry, rgwszAttribs[0]); if(*pppwszClasses == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } else { *pcClasses = ldap_count_values(*pppwszClasses);
*pppwszAttributes = ldap_get_values(pLDAP, pEntry, rgwszAttribs[1]); if(*pppwszAttributes == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
ldap_value_free(*pppwszClasses); } else { *pcAttributes = ldap_count_values(*pppwszAttributes); } } }
} else { dwErr = LdapMapErrorToWin32( dwErr ); }
ldap_msgfree(pMessage); } }
} else { dwErr = LdapMapErrorToWin32( dwErr ); }
}
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccDsReadExtendedRights
//
// Synopsis: Reads the list of extended rights from the schema
//
// Arguments: [IN pLDAP] -- LDAP connection to use
// [OUT pcItems] -- Where the count of items
// is returned
// [OUT ppwszNames] -- Where the list of Names is
// returned.
// [OUT ppwszGuids] -- Where the list of guids is
// returned.
//
// Notes: Freed via AccDsFreeExtendedRights
//
// Returns: ERROR_SUCCESS -- Success
//
//----------------------------------------------------------------------------
DWORD AccDsReadExtendedRights(IN PLDAP pLDAP, OUT PULONG pcItems, OUT PWSTR **pppwszNames, OUT PWSTR **pppwszGuids) { DWORD dwErr = ERROR_SUCCESS; PWSTR *ppwszValues = NULL; PWSTR rgwszAttribs[3]; PWSTR pwszERContainer = NULL; PDS_NAME_RESULTW pNameRes = NULL; LDAPMessage *pMessage, *pEntry; ULONG cEntries = 0, i;
*pcItems = 0; *pppwszNames = NULL; *pppwszGuids = NULL;
//
// 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"displayName"; rgwszAttribs[1] = L"rightsGuid"; 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);
if(dwErr == ERROR_SUCCESS) { cEntries = ldap_count_entries( pLDAP, pMessage );
*pppwszNames = (PWSTR *)AccAlloc( sizeof( PWSTR ) * cEntries );
if(*pppwszNames == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { *pppwszGuids = (PWSTR *)AccAlloc( sizeof( PWSTR ) * cEntries );
if(*pppwszGuids == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; AccFree(*pppwszNames); *pppwszNames = NULL; } }
if(dwErr == ERROR_SUCCESS) { pEntry = ldap_first_entry(pLDAP, pMessage);
if(pEntry == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno ); } else { 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 { //
// Now, we'll have to get the values
//
ACC_ALLOC_AND_COPY_STRINGW(ppwszValues[0], (*pppwszNames)[i], dwErr);
ldap_value_free(ppwszValues);
if(dwErr == ERROR_SUCCESS) { ppwszValues = ldap_get_values(pLDAP, pEntry, rgwszAttribs[1]); if(ppwszValues == NULL) { dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
} else { ACC_ALLOC_AND_COPY_STRINGW(ppwszValues[0], (*pppwszGuids)[i], dwErr); ldap_value_free(ppwszValues); } } }
pEntry = ldap_next_entry( pLDAP, pEntry ); }
if(dwErr != ERROR_SUCCESS) { AccDsFreeExtendedRights(i, *pppwszNames, *pppwszGuids); } } }
}
if(dwErr == ERROR_SUCCESS) { *pcItems = cEntries; }
ldap_msgfree(pMessage); } }
} else { dwErr = LdapMapErrorToWin32( dwErr ); }
}
return(dwErr) ; }
VOID AccDsFreeExtendedRights(IN ULONG cItems, IN PWSTR *ppwszNames, IN PWSTR *ppwszGuids) { ULONG i;
for(i = 0;i < cItems;i++ ) { AccFree( ppwszNames[ i ]); AccFree( ppwszGuids[ i ]); }
AccFree(ppwszNames); AccFree(ppwszGuids); }
|