WindowsXP-SP1/ds/adsi/ldapc/adsiutil.cxx

1323 lines
34 KiB
C++

//---------------------------------------------------------------------------
//
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1997
//
// File: cdsobj.cxx
//
// Contents: Microsoft ADs LDAP Provider DSObject
//
//
// History: 02-20-97 yihsins Created.
//
//----------------------------------------------------------------------------
#include "ldapc.hxx"
#pragma hdrstop
//
//Hard Coded Support for RootDSE object
//
LPWSTR SpecialSyntaxesTable[] =
{
LDAP_OPATT_CURRENT_TIME_W,
LDAP_OPATT_SUBSCHEMA_SUBENTRY_W,
LDAP_OPATT_SERVER_NAME_W,
LDAP_OPATT_NAMING_CONTEXTS_W,
LDAP_OPATT_DEFAULT_NAMING_CONTEXT_W,
LDAP_OPATT_SCHEMA_NAMING_CONTEXT_W,
LDAP_OPATT_CONFIG_NAMING_CONTEXT_W,
LDAP_OPATT_ROOT_DOMAIN_NAMING_CONTEXT_W,
LDAP_OPATT_SUPPORTED_CONTROL_W,
LDAP_OPATT_SUPPORTED_LDAP_VERSION_W,
L"lowestUncommittedUSN",
L"allowedAttributesEffective",
L"supportedExtension",
L"altServer",
NULL
};
HRESULT
ComputeAttributeBufferSize(
PADS_ATTR_INFO pAdsAttributes,
DWORD dwNumAttributes,
PDWORD pdwSize,
PDWORD pdwNumValues
);
LPBYTE
CopyAttributeName(
PADS_ATTR_INFO pThisAdsSrcAttribute,
PADS_ATTR_INFO pThisAdsTargAttribute,
LPBYTE pDataBuffer
);
HRESULT
ADsSetObjectAttributes(
ADS_LDP *ld,
LPTSTR pszLDAPServer,
LPTSTR pszLDAPDn,
CCredentials Credentials,
DWORD dwPort,
SECURITY_INFORMATION seInfo,
PADS_ATTR_INFO pAttributeEntries,
DWORD dwNumAttributes,
DWORD *pdwNumAttributesModified
)
{
HRESULT hr = S_OK;
DWORD i = 0;
DWORD j = 0;
PADS_ATTR_INFO pThisAttribute = NULL;
LDAPOBJECTARRAY ldapObjectArray;
DWORD dwSyntaxId = 0;
LDAPMod **aMods = NULL;
LDAPModW *aModsBuffer = NULL;
DWORD dwNumAttributesReturn = 0;
BOOL fNTSecDescriptor = FALSE;
int ldaperr = 0;
DWORD dwOptions = 0;
DWORD dwSecDescType = ADSI_LDAPC_SECDESC_NONE;
BOOL fModifyDone = FALSE;
BYTE berValue[8];
memset(berValue, 0, 8);
berValue[0] = 0x30; // Start sequence tag
berValue[1] = 0x03; // Length in bytes of following
berValue[2] = 0x02; // Actual value this and next 2
berValue[3] = 0x01;
berValue[4] = (BYTE)((ULONG)seInfo);
LDAPControl SeInfoControl =
{
LDAP_SERVER_SD_FLAGS_OID_W,
{
5, (PCHAR) berValue
},
TRUE
};
LDAPControl ModifyControl =
{
LDAP_SERVER_PERMISSIVE_MODIFY_OID_W,
{
0, NULL
},
FALSE
};
PLDAPControl ServerControls[2] =
{
&SeInfoControl,
NULL
};
PLDAPControl ServerControlsOnlyModify[2] =
{
&ModifyControl,
NULL
};
PLDAPControl ServerControlsAll[3] =
{
&SeInfoControl,
&ModifyControl,
NULL
};
BOOL fServerIsAD = FALSE;
*pdwNumAttributesModified = 0;
//
// Allocate memory to send the modify request
//
aMods = (LDAPModW **) AllocADsMem((dwNumAttributes+1) * sizeof(LDAPModW*));
if ( aMods == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
aModsBuffer = (LDAPModW *) AllocADsMem( dwNumAttributes * sizeof(LDAPModW));
if ( aModsBuffer == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
//
// Format the modify request
//
for (i = 0; i < dwNumAttributes; i++) {
BOOL fGenTime = FALSE;
LDAPOBJECTARRAY_INIT(ldapObjectArray);
pThisAttribute = pAttributeEntries + i;
if (!fNTSecDescriptor
&& _wcsicmp(L"ntSecurityDescriptor", pThisAttribute->pszAttrName)
== 0)
{
{
// we need to use appropriate controls if the operation
// is modify the security descriptor. Specifically we do
// not want to use any control if the operation is a clear
// and default to whatever the server deems fit.
if (pThisAttribute->dwControlCode != ADS_ATTR_CLEAR) {
fNTSecDescriptor = TRUE;
}
}
}
if (pThisAttribute->dwControlCode != ADS_ATTR_CLEAR) {
//
// If this is a time attribute, see if it is GenTime or
// UTCTime and set the syntax the flag appropriately
//
if (pThisAttribute->dwADsType == ADSTYPE_UTC_TIME) {
hr = LdapGetSyntaxOfAttributeOnServer(
pszLDAPServer,
pThisAttribute->pszAttrName,
&dwSyntaxId,
Credentials,
dwPort
);
if (SUCCEEDED(hr) && (dwSyntaxId == LDAPTYPE_GENERALIZEDTIME)) {
//
// Use GenTime conversion
//
fGenTime = TRUE;
}
}
}
switch (pThisAttribute->dwControlCode) {
case ADS_ATTR_UPDATE:
hr = AdsTypeToLdapTypeCopyConstruct(
pThisAttribute->pADsValues,
pThisAttribute->dwNumValues,
&ldapObjectArray,
&dwSyntaxId,
fGenTime
);
BAIL_ON_FAILURE(hr);
aMods[i] = &aModsBuffer[i];
aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
if ( ldapObjectArray.fIsString )
{
aModsBuffer[i].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
}
else
{
aModsBuffer[i].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
aModsBuffer[i].mod_op = LDAP_MOD_BVALUES;
}
aModsBuffer[i].mod_op |= LDAP_MOD_REPLACE;
dwNumAttributesReturn++;
break;
case ADS_ATTR_APPEND:
hr = AdsTypeToLdapTypeCopyConstruct(
pThisAttribute->pADsValues,
pThisAttribute->dwNumValues,
&ldapObjectArray,
&dwSyntaxId,
fGenTime
);
BAIL_ON_FAILURE(hr);
aMods[i] = &aModsBuffer[i];
aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
if ( ldapObjectArray.fIsString )
{
aModsBuffer[i].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
}
else
{
aModsBuffer[i].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
aModsBuffer[i].mod_op = LDAP_MOD_BVALUES;
}
aModsBuffer[i].mod_op |= LDAP_MOD_ADD;
dwNumAttributesReturn++;
break;
case ADS_ATTR_CLEAR:
aMods[i] = &aModsBuffer[i];
aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
aModsBuffer[i].mod_bvalues = NULL;
aModsBuffer[i].mod_op |= LDAP_MOD_DELETE;
dwNumAttributesReturn++;
break;
case ADS_ATTR_DELETE:
hr = AdsTypeToLdapTypeCopyConstruct(
pThisAttribute->pADsValues,
pThisAttribute->dwNumValues,
&ldapObjectArray,
&dwSyntaxId,
fGenTime
);
BAIL_ON_FAILURE(hr);
aMods[i] = &aModsBuffer[i];
aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
if ( ldapObjectArray.fIsString )
{
aModsBuffer[i].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
}
else
{
aModsBuffer[i].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
aModsBuffer[i].mod_op = LDAP_MOD_BVALUES;
}
aModsBuffer[i].mod_op |= LDAP_MOD_DELETE;
dwNumAttributesReturn++;
break;
default:
//
// ignore this attribute and move on
//
break;
}
}
//
// Find out if server is AD.
//
hr = ReadServerSupportsIsADControl(
pszLDAPServer,
&fServerIsAD,
Credentials,
dwPort
);
if (FAILED(hr)) {
//
// Assume it is not AD and continue, there is no
// good reason for this to fail on AD.
//
fServerIsAD = FALSE;
}
//
// Modify the object with appropriate call
//
if (fNTSecDescriptor) {
//
// Check if we are V3
//
ldaperr = ldap_get_option(
ld->LdapHandle,
LDAP_OPT_VERSION,
&dwOptions
);
//
// check supported controls and set accordingly
//
if (ldaperr == LDAP_SUCCESS && (dwOptions == LDAP_VERSION3)) {
//
// Read the security descriptor type if applicable
//
hr = ReadSecurityDescriptorControlType(
pszLDAPServer,
&dwSecDescType,
Credentials,
dwPort
);
if (SUCCEEDED(hr) && (dwSecDescType == ADSI_LDAPC_SECDESC_NT)) {
hr = LdapModifyExtS(
ld,
pszLDAPDn,
aMods,
fServerIsAD ?
(PLDAPControl *) &ServerControlsAll :
(PLDAPControl *) &ServerControls,
NULL
);
fModifyDone = TRUE;
}
} // If Read Version succeeded
}
//
// Perform a simple modify - only if fModifyDone is false
//
if (!fModifyDone) {
if (fServerIsAD) {
//
// Need to send the OID that allows delete on empty attributes
// without sending an error - for clients that have gotten used
// to bad practices.
//
hr = LdapModifyExtS(
ld,
pszLDAPDn,
aMods,
(PLDAPControl *)&ServerControlsOnlyModify,
NULL
);
}
else {
//
// Regular calls from most folks not using AD.
//
hr = LdapModifyS(
ld,
pszLDAPDn,
aMods
);
}
}
BAIL_ON_FAILURE(hr);
*pdwNumAttributesModified = dwNumAttributesReturn;
error:
if ( aModsBuffer )
{
for ( j = 0; j < i; j++ )
{
if ( aModsBuffer[j].mod_op & LDAP_MOD_BVALUES )
{
if ( aModsBuffer[j].mod_bvalues )
{
for ( DWORD k = 0; aModsBuffer[j].mod_bvalues[k]; k++ )
FreeADsMem( aModsBuffer[j].mod_bvalues[k] );
FreeADsMem( aModsBuffer[j].mod_bvalues );
}
}
else if ( aModsBuffer[j].mod_values )
{
for ( DWORD k = 0; aModsBuffer[j].mod_values[k]; k++ )
FreeADsMem( aModsBuffer[j].mod_values[k] );
FreeADsMem( aModsBuffer[j].mod_values );
}
}
FreeADsMem( aModsBuffer );
}
if ( aMods )
FreeADsMem( aMods );
return hr;
}
HRESULT
ADsGetObjectAttributes(
ADS_LDP *ld,
LPTSTR pszLDAPServer,
LPTSTR pszLDAPDn,
CCredentials Credentials,
DWORD dwPort,
SECURITY_INFORMATION seInfo,
LPWSTR *pAttributeNames,
DWORD dwNumberAttributes,
PADS_ATTR_INFO *ppAttributeEntries,
DWORD * pdwNumAttributesReturned
)
{
HRESULT hr = S_OK;
DWORD i = 0;
DWORD j = 0;
LPWSTR *aStrings = NULL;
LDAPMessage *res = NULL;
LDAPMessage *entry = NULL;
void *ptr;
DWORD dwNumberOfEntries = 0;
LPTSTR pszAttrName = NULL;
LDAPOBJECTARRAY ldapObjectArray;
PADSVALUE pAdsDestValues = NULL;
DWORD dwNumAdsValues = 0;
DWORD dwAdsType = 0;
DWORD dwSyntaxId = 0;
PADS_ATTR_INFO pAdsAttributes = NULL;
PADS_ATTR_INFO pThisAttributeDef = NULL;
LPBYTE pAttributeBuffer = NULL;
DWORD dwAttrCount = 0;
DWORD dwMemSize = 0;
DWORD dwTotalValues = 0;
DWORD dwNumValues = 0;
LPBYTE pValueBuffer = NULL;
LPBYTE pDataBuffer = NULL;
PADS_ATTR_INFO pAttrEntry = NULL;
PADSVALUE pAttrValue = NULL;
PADS_ATTR_INFO pThisAdsSrcAttribute = NULL;
PADS_ATTR_INFO pThisAdsTargAttribute = NULL;
PADSVALUE pThisAdsSrcValue = NULL;
PADSVALUE pThisAdsTargValue = NULL;
*ppAttributeEntries = NULL;
*pdwNumAttributesReturned = 0;
DWORD ldaperr = 0;
DWORD dwOptions = 0;
BOOLEAN getSecDesc = FALSE;
DWORD dwSecDescType = ADSI_LDAPC_SECDESC_NONE;
BOOLEAN fSearchDone = FALSE;
BYTE berValue[8];
memset(berValue, 0, 8);
berValue[0] = 0x30; // Start sequence tag
berValue[1] = 0x03; // Length in bytes of following
berValue[2] = 0x02; // Actual value this and next 2
berValue[3] = 0x01;
berValue[4] = (BYTE)((ULONG)seInfo);
LDAPControl SeInfoControl =
{
LDAP_SERVER_SD_FLAGS_OID_W,
{
5, (PCHAR) berValue
},
TRUE
};
PLDAPControl ServerControls[2] =
{
&SeInfoControl,
NULL
};
LDAPOBJECTARRAY_INIT(ldapObjectArray);
if (dwNumberAttributes != (DWORD)-1)
{
if ( dwNumberAttributes == 0 )
return S_OK;
//
// Package attributes
//
aStrings = (LPWSTR *) AllocADsMem( sizeof(LPTSTR) * (dwNumberAttributes + 1));
if ( aStrings == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
for ( i = 0; i < dwNumberAttributes; i++)
{
aStrings[i] = pAttributeNames[i];
if (!getSecDesc &&
_wcsicmp(L"ntSecurityDescriptor", pAttributeNames[i]) == 0) {
// we need go to get the security descriptor
getSecDesc = TRUE;
}
}
}
else
{
//
// If all attributes are requested, we will mark as read
// security descriptor also. Further down, the decision to
// use or not use a control is made.
//
getSecDesc = TRUE;
}
//
// Read the DS Object
//
// modified from LdapSearchS to LdapSearchExtS to get all attributes
// including SecurityDescriptor by one call
if (getSecDesc) {
ldaperr = ldap_get_option(
ld->LdapHandle,
LDAP_OPT_VERSION,
&dwOptions
);
if (dwOptions == LDAP_VERSION3) {
//
// Read the security descriptor type if applicable
//
hr = ReadSecurityDescriptorControlType(
pszLDAPServer,
&dwSecDescType,
Credentials,
dwPort
);
//
// If we could no get the control information for whatever reason,
// just try the SearchS.
//
if (SUCCEEDED(hr) && (dwSecDescType == ADSI_LDAPC_SECDESC_NT)) {
hr = LdapSearchExtS(
ld,
pszLDAPDn,
LDAP_SCOPE_BASE,
TEXT("(objectClass=*)"),
aStrings,
0,
(PLDAPControl *)&ServerControls,
NULL,
NULL,
10000,
&res
);
fSearchDone = TRUE;
}
}
}
//
// Perform just a LdapSearchS if the flag indicates that
// no search has been done. We do not try a second search
// if the first tone failed (saves packets on the wire).
//
if (!fSearchDone) {
hr = LdapSearchS(
ld,
pszLDAPDn,
LDAP_SCOPE_BASE,
TEXT("(objectClass=*)"),
aStrings,
0,
&res
);
fSearchDone = TRUE;
BAIL_ON_FAILURE(hr);
}
//
// Should only contain one entry
//
if ( LdapCountEntries( ld, res ) == 0 )
goto error;
hr = LdapFirstEntry( ld, res, &entry );
BAIL_ON_FAILURE(hr);
//
// Compute the number of attributes in the
// read buffer.
//
hr = LdapFirstAttribute( ld, entry, &ptr, &pszAttrName );
BAIL_ON_FAILURE(hr);
while ( pszAttrName != NULL )
{
dwNumberOfEntries++;
LdapAttributeFree( pszAttrName );
pszAttrName = NULL;
hr = LdapNextAttribute( ld, entry, ptr, &pszAttrName );
if (FAILED(hr))
break; // error occurred, ignore the rest of the attributes
}
//
// Allocate an attribute buffer which is as large as the
// number of attributes present
//
//
// Note that pADsAttributes is inited to Null
if (dwNumberOfEntries != 0) {
pAdsAttributes = (PADS_ATTR_INFO)AllocADsMem(
sizeof(ADS_ATTR_INFO) * dwNumberOfEntries
);
if (!pAdsAttributes)
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
dwAttrCount = 0;
ptr = NULL;
hr = LdapFirstAttribute( ld, entry, &ptr, &pszAttrName );
while ( SUCCEEDED(hr)
&& ( pszAttrName != NULL )
&& ( dwAttrCount < dwNumberOfEntries )
)
{
//
// Get the syntax of the attribute. Force only
// if we know that the this is not the RootDSE
// as RootDSE attributes are not in schema.
//
hr = LdapGetSyntaxOfAttributeOnServer(
pszLDAPServer,
pszAttrName,
&dwSyntaxId,
Credentials,
dwPort,
pszLDAPDn ? TRUE : FALSE
);
//
// If it failed with errorcode 0x8000500D which is
// E_ADS_PROPERTY_NOT_FOUND,
// see if it is one of the RootDSE syntaxes,
// if so set Syntax to ADSTYPE_CASE_IGNORE_STRING
//
if (hr == E_ADS_PROPERTY_NOT_FOUND) {
//
// search the hardcoded table to see if it is a known entry
//
BOOLEAN valFound = FALSE;
DWORD ctr = 0;
while (SpecialSyntaxesTable[ctr] && !valFound) {
if (!_wcsicmp(pszAttrName, SpecialSyntaxesTable[ctr])) {
dwSyntaxId = ADSTYPE_CASE_IGNORE_STRING;
hr = S_OK;
valFound = TRUE;
}
ctr++;
}
}else {
if (!_wcsicmp(pszAttrName, L"ntSecurityDescriptor")) {
dwSyntaxId = LDAPTYPE_SECURITY_DESCRIPTOR;
}
}
if ( hr == E_ADS_PROPERTY_NOT_FOUND ) {
//
// We will default to provider specific
//
dwSyntaxId = LDAPTYPE_UNKNOWN;
}
else if (FAILED(hr)) {
//
// Some other failure so skip attribute
//
goto NextAttr;
}
//
// Get the values of the current attribute
//
hr = UnMarshallLDAPToLDAPSynID(
pszAttrName,
ld,
entry,
dwSyntaxId,
&ldapObjectArray
);
if ( FAILED(hr))
goto NextAttr;
hr = LdapTypeToAdsTypeCopyConstruct(
ldapObjectArray,
dwSyntaxId,
&pAdsDestValues,
&dwNumAdsValues,
&dwAdsType
);
if (FAILED(hr))
goto NextAttr;
pThisAttributeDef = pAdsAttributes + dwAttrCount;
pThisAttributeDef->pszAttrName = AllocADsStr(pszAttrName);
if ( !pThisAttributeDef->pszAttrName )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pThisAttributeDef->pADsValues = pAdsDestValues;
if ( pThisAttributeDef->dwNumValues = ldapObjectArray.dwCount )
pThisAttributeDef->dwADsType = pAdsDestValues[0].dwType;
dwAttrCount++;
NextAttr:
if ( pszAttrName ) {
LdapAttributeFree( pszAttrName );
pszAttrName = NULL;
}
if ( ldapObjectArray.pLdapObjects )
{
if ( ldapObjectArray.fIsString )
LdapValueFree( (TCHAR **) ldapObjectArray.pLdapObjects );
else
LdapValueFreeLen( (struct berval **) ldapObjectArray.pLdapObjects );
LDAPOBJECTARRAY_INIT(ldapObjectArray);
}
if ( hr == E_OUTOFMEMORY ) // break on serious error
break;
hr = LdapNextAttribute( ld, entry, ptr, &pszAttrName );
}
BAIL_ON_FAILURE(hr);
if ( dwAttrCount == 0 )
goto error;
//
// Now package this data into a single contiguous buffer
//
hr = ComputeAttributeBufferSize(
pAdsAttributes,
dwAttrCount,
&dwMemSize,
&dwTotalValues
);
BAIL_ON_FAILURE(hr);
pAttributeBuffer = (LPBYTE) AllocADsMem( dwMemSize );
if (!pAttributeBuffer) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pValueBuffer = pAttributeBuffer + dwAttrCount * (sizeof(ADS_ATTR_INFO));
pDataBuffer = pValueBuffer + dwTotalValues * sizeof(ADSVALUE);
pAttrEntry = (PADS_ATTR_INFO) pAttributeBuffer;
pAttrValue = (PADSVALUE) pValueBuffer;
for (i = 0; i < dwAttrCount; i++) {
pThisAdsSrcAttribute = pAdsAttributes + i;
pThisAdsTargAttribute = pAttrEntry + i;
dwNumValues = pThisAdsSrcAttribute->dwNumValues;
pThisAdsTargAttribute->dwNumValues = dwNumValues;
pThisAdsTargAttribute->dwADsType = pThisAdsSrcAttribute->dwADsType;
pThisAdsTargAttribute->pADsValues = pAttrValue;
pThisAdsSrcValue = pThisAdsSrcAttribute->pADsValues;
pThisAdsTargValue = pAttrValue;
if (!pDataBuffer) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
for ( j = 0; j < dwNumValues; j++) {
pDataBuffer = AdsTypeCopy(
pThisAdsSrcValue,
pThisAdsTargValue,
pDataBuffer
);
pAttrValue++;
pThisAdsTargValue = pAttrValue;
pThisAdsSrcValue++;
}
if (!pDataBuffer) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
pDataBuffer = CopyAttributeName(
pThisAdsSrcAttribute,
pThisAdsTargAttribute,
pDataBuffer
);
}
hr = S_OK;
error:
if ( aStrings )
FreeADsMem( aStrings );
if ( res )
LdapMsgFree( res );
//
// Clean up the header based Ods structures
//
if ( pAdsAttributes ) {
for (i = 0; i < dwAttrCount; i++)
{
pThisAttributeDef = pAdsAttributes + i;
FreeADsStr( pThisAttributeDef->pszAttrName );
AdsTypeFreeAdsObjects( pThisAttributeDef->pADsValues,
pThisAttributeDef->dwNumValues );
}
FreeADsMem( pAdsAttributes );
}
if (FAILED(hr))
{
if ( pAttributeBuffer )
FreeADsMem(pAttributeBuffer);
*ppAttributeEntries = NULL;
*pdwNumAttributesReturned = 0;
}
else
{
*ppAttributeEntries = (PADS_ATTR_INFO)pAttributeBuffer;
*pdwNumAttributesReturned = dwAttrCount;
}
return hr;
}
HRESULT
ADsCreateDSObjectExt(
ADS_LDP *ld,
LPTSTR ADsPath,
LPWSTR pszRDNName,
PADS_ATTR_INFO pAttributeEntries,
DWORD dwNumAttributes,
SECURITY_INFORMATION seInfo,
BOOL fSecDesc
)
{
HRESULT hr = S_OK;
LPTSTR pszAbsoluteName = NULL;
TCHAR *pszLDAPServer = NULL;
LPWSTR pszLDAPDn = NULL;
DWORD dwSyntaxId = 0;
DWORD dwPort = 0;
DWORD i = 0;
DWORD j = 0;
PADS_ATTR_INFO pThisAttribute = NULL;
LDAPOBJECTARRAY ldapObjectArray;
LDAPMod **aMods = NULL;
LDAPModW *aModsBuffer = NULL;
BYTE berValue[8];
memset(berValue, 0, 8);
berValue[0] = 0x30; // Start sequence tag
berValue[1] = 0x03; // Length in bytes of following
berValue[2] = 0x02; // Actual value this and next 2
berValue[3] = 0x01;
berValue[4] = (BYTE)((ULONG)seInfo);
LDAPControl SeInfoControl =
{
LDAP_SERVER_SD_FLAGS_OID_W,
{
5, (PCHAR) berValue
},
TRUE
};
PLDAPControl ServerControls[2] =
{
&SeInfoControl,
NULL
};
//
// Get the LDAP path of the object to create
//
hr = BuildADsPathFromParent(
ADsPath,
pszRDNName,
&pszAbsoluteName
);
BAIL_ON_FAILURE(hr);
hr = BuildLDAPPathFromADsPath2(
pszAbsoluteName,
&pszLDAPServer,
&pszLDAPDn,
&dwPort
);
BAIL_ON_FAILURE(hr);
//
// Allocate memory to store the add request
//
aMods = (LDAPModW **) AllocADsMem((dwNumAttributes+1) * sizeof(LDAPModW*));
if ( aMods == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
aModsBuffer = (LDAPModW *) AllocADsMem( dwNumAttributes * sizeof(LDAPModW));
if ( aModsBuffer == NULL )
{
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
//
// Format the add request
//
for (i = 0; i < dwNumAttributes; i++) {
BOOL fGenTime = FALSE;
LDAPOBJECTARRAY_INIT(ldapObjectArray);
pThisAttribute = pAttributeEntries + i;
if (pThisAttribute->dwControlCode != ADS_ATTR_CLEAR) {
//
// If this is a time attribute, see if it is GenTime or
// UTCTime and set the syntax the flag appropriately
//
if (pThisAttribute->dwADsType == ADSTYPE_UTC_TIME) {
hr = LdapGetSyntaxOfAttributeOnServer(
pszLDAPServer,
pThisAttribute->pszAttrName,
&dwSyntaxId,
(*ld->pCredentials),
ld->PortNumber
);
if (SUCCEEDED(hr) && (dwSyntaxId == LDAPTYPE_GENERALIZEDTIME)) {
//
// Use GenTime conversion
//
fGenTime = TRUE;
}
}
}
hr = AdsTypeToLdapTypeCopyConstruct(
pThisAttribute->pADsValues,
pThisAttribute->dwNumValues,
&ldapObjectArray,
&dwSyntaxId,
fGenTime
);
BAIL_ON_FAILURE(hr);
aMods[i] = &aModsBuffer[i];
aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
if ( ldapObjectArray.fIsString )
{
aModsBuffer[i].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
}
else
{
aModsBuffer[i].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
aModsBuffer[i].mod_op = LDAP_MOD_BVALUES;
}
aModsBuffer[i].mod_op |= LDAP_MOD_REPLACE;
}
if (fSecDesc) {
hr = LdapAddExtS(
ld,
pszLDAPDn,
aMods,
(PLDAPControl *)&ServerControls,
NULL
);
}
else {
//
// Now, send the add request
//
hr = LdapAddS(
ld,
pszLDAPDn,
aMods
);
}
BAIL_ON_FAILURE(hr);
error:
if ( pszAbsoluteName ) {
FreeADsStr( pszAbsoluteName );
}
if ( pszLDAPServer ) {
FreeADsStr( pszLDAPServer );
}
if (pszLDAPDn) {
FreeADsStr( pszLDAPDn);
}
if ( aModsBuffer )
{
for ( j = 0; j < i; j++ )
{
if ( aModsBuffer[j].mod_op & LDAP_MOD_BVALUES )
{
if ( aModsBuffer[j].mod_bvalues )
{
for ( DWORD k = 0; aModsBuffer[j].mod_bvalues[k]; k++ )
FreeADsMem( aModsBuffer[j].mod_bvalues[k] );
FreeADsMem( aModsBuffer[j].mod_bvalues );
}
}
else if ( aModsBuffer[j].mod_values )
{
for ( DWORD k = 0; aModsBuffer[j].mod_values[k]; k++ )
FreeADsMem( aModsBuffer[j].mod_values[k] );
FreeADsMem( aModsBuffer[j].mod_values );
}
}
FreeADsMem( aModsBuffer );
}
if ( aMods )
FreeADsMem( aMods );
return hr;
}
HRESULT
ADsCreateDSObject(
ADS_LDP *ld,
LPTSTR ADsPath,
LPWSTR pszRDNName,
PADS_ATTR_INFO pAttributeEntries,
DWORD dwNumAttributes
)
{
RRETURN ( ADsCreateDSObjectExt(
ld,
ADsPath,
pszRDNName,
pAttributeEntries,
dwNumAttributes,
0, // for seInfo since it is ignored
FALSE
)
);
}
HRESULT
ADsDeleteDSObject(
ADS_LDP *ld,
LPTSTR ADsPath,
LPWSTR pszRDNName
)
{
HRESULT hr = S_OK;
LPTSTR pszAbsoluteName = NULL;
TCHAR *pszLDAPServer = NULL;
LPWSTR pszLDAPDn = NULL;
DWORD dwPort = 0;
//
// Get the LDAP path of the object to delete
//
hr = BuildADsPathFromParent(
ADsPath,
pszRDNName,
&pszAbsoluteName
);
BAIL_ON_FAILURE(hr);
hr = BuildLDAPPathFromADsPath2(
pszAbsoluteName,
&pszLDAPServer,
&pszLDAPDn,
&dwPort
);
BAIL_ON_FAILURE(hr);
//
// Now, send the delete request
//
hr = LdapDeleteS(
ld,
pszLDAPDn
);
BAIL_ON_FAILURE(hr);
error:
if ( pszAbsoluteName ) {
FreeADsStr( pszAbsoluteName );
}
if ( pszLDAPServer ) {
FreeADsStr( pszLDAPServer );
}
if (pszLDAPDn) {
FreeADsStr(pszLDAPDn);
}
return hr;
}
HRESULT
ComputeAttributeBufferSize(
PADS_ATTR_INFO pAdsAttributes,
DWORD dwNumAttributes,
PDWORD pdwSize,
PDWORD pdwNumValues
)
{
PADS_ATTR_INFO pThisAttribute = NULL;
PADSVALUE pAdsSrcValues = NULL;
DWORD dwNumValues = 0;
DWORD dwSize = 0;
DWORD dwTotalNumValues = 0;
for ( DWORD i = 0; i < dwNumAttributes; i++) {
pThisAttribute = pAdsAttributes + i;
dwNumValues = pThisAttribute->dwNumValues;
dwTotalNumValues += dwNumValues;
pAdsSrcValues = pThisAttribute->pADsValues;
for ( DWORD j = 0; j < dwNumValues; j++)
dwSize += AdsTypeSize(pAdsSrcValues + j) + sizeof(ADSVALUE);
dwSize += sizeof(ADS_ATTR_INFO);
dwSize += ((wcslen(pThisAttribute->pszAttrName) + 1)*sizeof(WCHAR)) + (ALIGN_WORD-1);
}
*pdwSize = dwSize;
*pdwNumValues = dwTotalNumValues;
return S_OK;
}
LPBYTE
CopyAttributeName(
PADS_ATTR_INFO pThisAdsSrcAttribute,
PADS_ATTR_INFO pThisAdsTargAttribute,
LPBYTE pDataBuffer
)
{
//
// strings should be WCHAR (i.e., WORD) aligned
//
pDataBuffer = (LPBYTE) ROUND_UP_POINTER(pDataBuffer, ALIGN_WORD);
LPWSTR pCurrentPos = (LPWSTR)pDataBuffer;
wcscpy(pCurrentPos, pThisAdsSrcAttribute->pszAttrName);
pThisAdsTargAttribute->pszAttrName = pCurrentPos;
pDataBuffer = pDataBuffer + (wcslen(pThisAdsSrcAttribute->pszAttrName) + 1)*sizeof(WCHAR);
return(pDataBuffer);
}