Directory Services |
The LDAP_SERVER_DIRSYNC_OID control allows an application to search the directory for objects that have changed since a previous state, and is used with the extended LDAP search functions such as ldap_search_ext.
To use this control, set the members of the LDAPControl structure as shown in the following code example.
PWCHAR ldctl_oid = LDAP_SERVER_DIRSYNC_OID; struct berval ldctl_value; BOOLEAN ldctl_iscritical = TRUE;
The DirSync control is used with the extended search functions, such as ldap_search_ext, to search a directory for objects changed since a previous request. This control must be exclusively used with a SearchRequest message and is ignored if used otherwise. However, if the criticality field is set to TRUE and the control is used with other than the SearchRequest message, the request fails and returns an UnsupportedCriticalExtension error.
On the first call to an extended LDAP search function that uses this control, the ldctl_value is a BER-endcoded version of the following.
Sequence { Flags INTEGER maxAttributeCount INTEGER Cookie OCTET STRING }
Value | Description |
---|---|
LDAP_DIRSYNC_OBJECT_SECURITY |
Windows Server 2003: If this flag is not present, the caller must have the replicate changes right. If this flag is present, the caller requires no rights, but is only allowed to view objects and attributes that are accessible to the caller. Windows 2000 Server: Not supported. |
LDAP_DIRSYNC_ANCESTORS_FIRST_ORDER | Return parents before children, when parents would otherwise appear later in the replication stream. |
LDAP_DIRSYNC_PUBLIC_DATA_ONLY | Do not return private data in the search results. |
LDAP_DIRSYNC_INCREMENTAL_VALUES |
Windows Server 2003: If this flag is not present, all of the values, up to a server-specified limit, in a multi-valued attribute are returned when any value changes. If this flag is present, only the changed values are returned. Windows 2000 Server: Not supported. |
The following code example shows how to initialize and encode a search request for the LDAP_SERVER_DIRSYNC_OID control .
[C++]
/***************************************************************************
BerEncodeDirSyncRequest()
Initializes and BER-encodes a DirSync request. The caller must free the
cookie with ber_bvfree() when it is no longer required.
Returns ERROR_SUCCESS if successful or an LDAP or Win32 error code if
an error occurs.
***************************************************************************/
ULONG BerEncodeDirSyncRequest(IN DWORD dwDirSyncFlags,
IN BYTE *pbCookie,
IN DWORD cbCookie,
IN DWORD dwMaxAttributeCount,
OUT PBERVAL *ppbvDirSyncRequest)
{
if( (pbCookie && IsBadReadPtr(pbCookie, cbCookie)) ||
IsBadWritePtr(ppbvDirSyncRequest, sizeof(BERVAL)))
{
return ERROR_INVALID_PARAMETER;
}
ULONG ulResult = ERROR_SUCCESS;
*ppbvDirSyncRequest = NULL;
// Format and encode the SEQUENCE data in a BerElement.
BerElement *pbe = ber_alloc_t(LBER_USE_DER);
if(!pbe)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
int iResult = ber_printf( pbe,
"{iiO}",
dwDirSyncFlags,
dwMaxAttributeCount,
pbCookie,
cbCookie);
if(iResult >= 0)
{
iResult = ber_flatten(pbe, ppbvDirSyncRequest);
if(0 != iResult)
{
*ppbvDirSyncRequest = NULL;
ulResult = ERROR_NOT_ENOUGH_MEMORY;
}
}
else
{
ulResult = ERROR_NOT_ENOUGH_MEMORY;
}
if(pbe)
{
ber_free(pbe, 1);
}
return ulResult;
}
The following code example shows how to initialize the LDAPControl structure for the first call to a search using the LDAP_SERVER_DIRSYNC_OID control . This code utilizes the BerEncodeDirSyncRequest example defined above.
[C++]
ULONG ulResult;
PBERVAL pBerval = NULL;
/*
BER-encode the flags and maximum number of attributes. The first time the
search is performed, the cookie is NULL.
*/
ulResult = BerEncodeDirSyncRequest( LDAP_DIRSYNC_ANCESTORS_FIRST_ORDER,
NULL,
0,
500,
&pBerval);
if(ERROR_SUCCESS == ulResult)
{
LDAPControl lControl;
// Initialize the LDAPControl structure.
#ifdef UNICODE
lControl.ldctl_oid = LDAP_SERVER_DIRSYNC_OID_W;
#else
lControl.ldctl_oid = LDAP_SERVER_DIRSYNC_OID;
#endif
lControl.ldctl_iscritical = TRUE;
lControl.ldctl_value.bv_val = pBerval->bv_val;
lControl.ldctl_value.bv_len = pBerval->bv_len;
/*
The LDAPControl data is now ready for use in ldap_search_ext() or
ldap_search_ext_s() call.
*/
/*
Free the temporary berval. This must not be freed until after
ldap_search_ext() or ldap_search_ext_s() has been called.
*/
if(pBerval)
{
ber_bvfree(pBerval);
}
}
The result of a search with the LDAP_SERVER_DIRSYNC_OID control is an LDAPControl structure that contains a BER-encoded version of the following data in the ldctl_value member.
Sequence { Flag INTEGER maxAttributeCount INTEGER Cookie OCTET STRING }
The following code example shows how to retrieve the LDAP_SERVER_DIRSYNC_OID control result data from an LDAPMessage structure, such as that returned by the ldap_search_ext_s function.
[C++]
/***************************************************************************
BerDecodeDirSyncReply()
Obtains the cookie and more data flag from a DirSync response. The
caller must free the cookie with FreeADsMem() when it is no longer
required.
Returns ERROR_SUCCESS if successful or an LDAP or Win32 error code if
an error occurs.
***************************************************************************/
ULONG BerDecodeDirSyncReply(IN LDAP *pConnection,
IN LDAPMessage *pLDAPMsg,
OUT LPBYTE *ppbNextCookie,
OUT DWORD *pcbNextCookie,
OUT BOOL *pfMoreData)
{
if( IsBadReadPtr(pConnection, sizeof(LDAP)) ||
IsBadReadPtr(pLDAPMsg, sizeof(LDAPMessage)) ||
IsBadWritePtr(ppbNextCookie, sizeof(LPBYTE)) ||
IsBadWritePtr(pcbNextCookie, sizeof(DWORD)) ||
IsBadWritePtr(pfMoreData, sizeof(BOOL)))
{
return ERROR_INVALID_PARAMETER;
}
ULONG ulResult = ERROR_SUCCESS;
PLDAPControl *rgpServerControls = NULL;
LPTSTR pszDirSyncOID;
*ppbNextCookie = NULL;
*pcbNextCookie = 0;
*pfMoreData = FALSE;
#ifdef UNICODE
pszDirSyncOID = LDAP_SERVER_DIRSYNC_OID_W;
#else
pszDirSyncOID = LDAP_SERVER_DIRSYNC_OID;
#endif
// Parse the results to get the server controls.
ulResult = ldap_parse_result( pConnection,
pLDAPMsg,
NULL,
NULL,
NULL,
NULL,
&rgpServerControls,
FALSE);
if(rgpServerControls)
{
BERVAL bvDirSyncResult = {0, NULL};
DWORD dwIndex;
// Find the DirSync OID.
for(dwIndex = 0; rgpServerControls[dwIndex]; dwIndex++)
{
if(0 == lstrcmpi(rgpServerControls[dwIndex]->ldctl_oid, pszDirSyncOID))
{
bvDirSyncResult = rgpServerControls[dwIndex]->ldctl_value;
break;
}
}
if(bvDirSyncResult.bv_len)
{
DWORD dwSize;
BerElement *pBer = ber_init(&bvDirSyncResult);
if(pBer)
{
PBERVAL pBerVal;
BOOL fMoreData;
ber_scanf(pBer, "{iiO}", &fMoreData, &dwSize, &pBerVal);
*ppbNextCookie = (LPBYTE)AllocADsMem(pBerVal->bv_len);
if(*ppbNextCookie)
{
CopyMemory(*ppbNextCookie, pBerVal->bv_val, pBerVal->bv_len);
*pcbNextCookie = pBerVal->bv_len;
*pfMoreData = fMoreData;
}
else
{
ulResult = ERROR_NOT_ENOUGH_MEMORY;
}
ber_free(pBer, 1);
ber_bvfree(pBerVal);
}
}
else
{
// The DirSync OID was not found.
ulResult = ERROR_NOT_FOUND;
}
// Free the memory for the controls.
ldap_controls_free(rgpServerControls);
}
return ulResult;
}
Note For more information about specific access rights required to use this control with an Active Directory server, see Polling_for_Changes_Using_the_DirSync_Control.
Client: Included in Windows XP and
Windows 2000 Professional.
Server: Included in Windows Server 2003 and
Windows 2000 Server.
Redistributable: Requires Active Directory Client Extension
on Windows NT 4.0 SP6a and Windows 95/98/Me.
Header: Declared in ntldap.h.