Directory Services

LDAP_SERVER_DIRSYNC_OID

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;

Members

ldctl_oid
LDAP_SERVER_DIRSYNC_OID, which is defined as "1.2.840.113556.1.4.841".
ldctl_value
Specifies a BER-encoded sequence of parameters that allows the application to limit the amount of data to be returned in a single call. The sequence also includes a "cookie" used for subsequent reiterative search calls. In the berval structure, set bv_val to a pointer to the sequence that contains the control and cookie data and set bv_len to the length of the sequence. For more information, see Remarks.
ldctl_iscritical
TRUE

Remarks

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
}
Flags
Contains optional flags for use with the LDAP_SERVER_DIRSYNC_OID control. This can be zero or a combination of one or more of the following values.
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.

maxAttributeCount
Specifies the maximum number of attributes to return. This value may also be used to limit the amount of data returned.
Cookie
An opaque Octet String that is implementation specific. It is updated during each SearchRequest by the directory and allows the DirSync control to incrementally read changes from the directory. Initial creation of this control should be a NULL string of 0 length.

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
}
Flag
Contains a non-zero value if there is more data to retreive or zero if there is no more data to retrieve. If this memebr contains a non-zero value, a subsequent search should be performed with the Cookie of this data to retrieve the next block of results.
maxAttributeCount
Specifies the maximum number of attributes to return. This value may also be used to limit the amount of data returned.
Cookie
Contain an opaque Octet string that is implementation specific. This value is returned by the server for use in subsequent searches by the client.
Subsequent calls to the LDAP extended search functions should pass the returned Cookie data back in order to return any additional search results as indicated by the Flag data.

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.

Requirements

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.