xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/psearchctrl.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: psearchctrl.c,v 1.2 2021/08/14 16:14:56 christos Exp $	*/
2e670fd5cSchristos 
3e670fd5cSchristos /* $OpenLDAP$ */
4e670fd5cSchristos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5e670fd5cSchristos  *
6e670fd5cSchristos  * Copyright 1998-2021 The OpenLDAP Foundation.
7e670fd5cSchristos  * All rights reserved.
8e670fd5cSchristos  *
9e670fd5cSchristos  * Redistribution and use in source and binary forms, with or without
10e670fd5cSchristos  * modification, are permitted only as authorized by the OpenLDAP
11e670fd5cSchristos  * Public License.
12e670fd5cSchristos  *
13e670fd5cSchristos  * A copy of this license is available in the file LICENSE in the
14e670fd5cSchristos  * top-level directory of the distribution or, alternatively, at
15e670fd5cSchristos  * <http://www.OpenLDAP.org/license.html>.
16e670fd5cSchristos  */
17e670fd5cSchristos /* ACKNOWLEDGEMENTS:
18e670fd5cSchristos  * This work was developed by Howard Chu for inclusion in
19e670fd5cSchristos  * OpenLDAP Software.
20e670fd5cSchristos  */
21e670fd5cSchristos 
22e670fd5cSchristos #include <sys/cdefs.h>
23*549b59edSchristos __RCSID("$NetBSD: psearchctrl.c,v 1.2 2021/08/14 16:14:56 christos Exp $");
24e670fd5cSchristos 
25e670fd5cSchristos #include "portable.h"
26e670fd5cSchristos 
27e670fd5cSchristos #include <stdio.h>
28e670fd5cSchristos #include <ac/stdlib.h>
29e670fd5cSchristos #include <ac/string.h>
30e670fd5cSchristos #include <ac/time.h>
31e670fd5cSchristos 
32e670fd5cSchristos #include "ldap-int.h"
33e670fd5cSchristos 
34e670fd5cSchristos /* Based on draft-ietf-ldapext-c-api-psearch-00 */
35e670fd5cSchristos 
36e670fd5cSchristos /* ---------------------------------------------------------------------------
37e670fd5cSchristos    ldap_create_persistentsearch_control_value
38e670fd5cSchristos 
39e670fd5cSchristos    Create and encode the value of the server-side sort control.
40e670fd5cSchristos 
41e670fd5cSchristos    ld          (IN) An LDAP session handle, as obtained from a call to
42e670fd5cSchristos 					ldap_init().
43e670fd5cSchristos 
44e670fd5cSchristos    changetypes (IN) A bit-sensitive field that indicates which kinds of
45e670fd5cSchristos 					changes the client wants to be informed about.  Its
46e670fd5cSchristos 					value should be LDAP_CHANGETYPE_ANY, or any logical-OR
47e670fd5cSchristos 					combination of LDAP_CHANGETYPE_ADD,
48e670fd5cSchristos 					LDAP_CHANGETYPE_DELETE, LDAP_CHANGETYPE_MODIFY, and
49e670fd5cSchristos 					LDAP_CHANGETYPE_MODDN.  This field corresponds to the
50e670fd5cSchristos 					changeType element of the BER-encoded PersistentSearch
51e670fd5cSchristos 					control value itself.
52e670fd5cSchristos 
53e670fd5cSchristos    changesonly (IN) A Boolean field that indicates whether the client
54e670fd5cSchristos 					wishes to only receive searchResultEntry messages for
55e670fd5cSchristos 					entries that have been changed. If non-zero, only
56e670fd5cSchristos 					entries that result from changes are returned; other-
57e670fd5cSchristos 					wise, all of the static entries that match the search
58e670fd5cSchristos 					criteria are returned before the server begins change
59e670fd5cSchristos 					notification.  This field corresponds to the changes-
60e670fd5cSchristos 					Only element of the BER-encoded PersistentSearch con-
61e670fd5cSchristos 					trol value itself.
62e670fd5cSchristos 
63e670fd5cSchristos    return_echg_ctls (IN) A Boolean field that indicates whether the server
64e670fd5cSchristos 					should send back an Entry Change Notification control
65e670fd5cSchristos 					with each searchResultEntry that is returned due to a
66e670fd5cSchristos 					change to an entry.  If non-zero, Entry Change
67e670fd5cSchristos 					Notification controls are requested; if zero, they are
68e670fd5cSchristos 					not.  This field corresponds to the returnECs element
69e670fd5cSchristos 					of the BER-encoded PersistentSearch control value
70e670fd5cSchristos 					itself.
71e670fd5cSchristos 
72e670fd5cSchristos    value      (OUT) Contains the control value; the bv_val member of the berval structure
73e670fd5cSchristos 					SHOULD be freed by calling ldap_memfree() when done.
74e670fd5cSchristos 
75e670fd5cSchristos    ---------------------------------------------------------------------------*/
76e670fd5cSchristos 
77e670fd5cSchristos int
ldap_create_persistentsearch_control_value(LDAP * ld,int changetypes,int changesonly,int return_echg_ctls,struct berval * value)78e670fd5cSchristos ldap_create_persistentsearch_control_value(
79e670fd5cSchristos 	LDAP *ld,
80e670fd5cSchristos 	int changetypes,
81e670fd5cSchristos 	int changesonly,
82e670fd5cSchristos 	int return_echg_ctls,
83e670fd5cSchristos 	struct berval *value )
84e670fd5cSchristos {
85e670fd5cSchristos 	int		i;
86e670fd5cSchristos 	BerElement	*ber = NULL;
87e670fd5cSchristos 	ber_tag_t	tag;
88e670fd5cSchristos 
89e670fd5cSchristos 	assert( ld != NULL );
90e670fd5cSchristos 	assert( LDAP_VALID( ld ) );
91e670fd5cSchristos 
92e670fd5cSchristos 	if ( ld == NULL ) return LDAP_PARAM_ERROR;
93e670fd5cSchristos 	if ( value == NULL ) {
94e670fd5cSchristos 		ld->ld_errno = LDAP_PARAM_ERROR;
95e670fd5cSchristos 		return LDAP_PARAM_ERROR;
96e670fd5cSchristos 	}
97e670fd5cSchristos 	if (( changetypes & 0x0f ) != changetypes ) {
98e670fd5cSchristos 		ld->ld_errno = LDAP_PARAM_ERROR;
99e670fd5cSchristos 		return LDAP_PARAM_ERROR;
100e670fd5cSchristos 	}
101e670fd5cSchristos 
102e670fd5cSchristos 	value->bv_val = NULL;
103e670fd5cSchristos 	value->bv_len = 0;
104e670fd5cSchristos 	ld->ld_errno = LDAP_SUCCESS;
105e670fd5cSchristos 
106e670fd5cSchristos 	ber = ldap_alloc_ber_with_options( ld );
107e670fd5cSchristos 	if ( ber == NULL) {
108e670fd5cSchristos 		ld->ld_errno = LDAP_NO_MEMORY;
109e670fd5cSchristos 		return ld->ld_errno;
110e670fd5cSchristos 	}
111e670fd5cSchristos 
112e670fd5cSchristos 	tag = ber_printf( ber, "{ibb}", changetypes, changesonly, return_echg_ctls );
113e670fd5cSchristos 	if ( tag == LBER_ERROR ) {
114e670fd5cSchristos 		goto error_return;
115e670fd5cSchristos 	}
116e670fd5cSchristos 
117e670fd5cSchristos 	if ( ber_flatten2( ber, value, 1 ) == -1 ) {
118e670fd5cSchristos 		ld->ld_errno = LDAP_NO_MEMORY;
119e670fd5cSchristos 	}
120e670fd5cSchristos 
121e670fd5cSchristos 	if ( 0 ) {
122e670fd5cSchristos error_return:;
123e670fd5cSchristos 		ld->ld_errno =  LDAP_ENCODING_ERROR;
124e670fd5cSchristos 	}
125e670fd5cSchristos 
126e670fd5cSchristos 	if ( ber != NULL ) {
127e670fd5cSchristos 		ber_free( ber, 1 );
128e670fd5cSchristos 	}
129e670fd5cSchristos 
130e670fd5cSchristos 	return ld->ld_errno;
131e670fd5cSchristos }
132e670fd5cSchristos 
133e670fd5cSchristos 
134e670fd5cSchristos /* ---------------------------------------------------------------------------
135e670fd5cSchristos    ldap_create_persistentsearch_control
136e670fd5cSchristos 
137e670fd5cSchristos    Create and encode the persistent search control.
138e670fd5cSchristos 
139e670fd5cSchristos    ld          (IN) An LDAP session handle, as obtained from a call to
140e670fd5cSchristos 					ldap_init().
141e670fd5cSchristos 
142e670fd5cSchristos    changetypes (IN) A bit-sensitive field that indicates which kinds of
143e670fd5cSchristos 					changes the client wants to be informed about.  Its
144e670fd5cSchristos 					value should be LDAP_CHANGETYPE_ANY, or any logical-OR
145e670fd5cSchristos 					combination of LDAP_CHANGETYPE_ADD,
146e670fd5cSchristos 					LDAP_CHANGETYPE_DELETE, LDAP_CHANGETYPE_MODIFY, and
147e670fd5cSchristos 					LDAP_CHANGETYPE_MODDN.  This field corresponds to the
148e670fd5cSchristos 					changeType element of the BER-encoded PersistentSearch
149e670fd5cSchristos 					control value itself.
150e670fd5cSchristos 
151e670fd5cSchristos    changesonly (IN) A Boolean field that indicates whether the client
152e670fd5cSchristos 					wishes to only receive searchResultEntry messages for
153e670fd5cSchristos 					entries that have been changed. If non-zero, only
154e670fd5cSchristos 					entries that result from changes are returned; other-
155e670fd5cSchristos 					wise, all of the static entries that match the search
156e670fd5cSchristos 					criteria are returned before the server begins change
157e670fd5cSchristos 					notification.  This field corresponds to the changes-
158e670fd5cSchristos 					Only element of the BER-encoded PersistentSearch con-
159e670fd5cSchristos 					trol value itself.
160e670fd5cSchristos 
161e670fd5cSchristos    return_echg_ctls (IN) A Boolean field that indicates whether the server
162e670fd5cSchristos 					should send back an Entry Change Notification control
163e670fd5cSchristos 					with each searchResultEntry that is returned due to a
164e670fd5cSchristos 					change to an entry.  If non-zero, Entry Change
165e670fd5cSchristos 					Notification controls are requested; if zero, they are
166e670fd5cSchristos 					not.  This field corresponds to the returnECs element
167e670fd5cSchristos 					of the BER-encoded PersistentSearch control value
168e670fd5cSchristos 					itself.
169e670fd5cSchristos 
170e670fd5cSchristos    isCritical  (IN) 0 - Indicates the control is not critical to the operation.
171e670fd5cSchristos 					non-zero - The control is critical to the operation.
172e670fd5cSchristos 
173e670fd5cSchristos    ctrlp      (OUT) Returns a pointer to the LDAPControl created.  This control
174e670fd5cSchristos 					SHOULD be freed by calling ldap_control_free() when done.
175e670fd5cSchristos 
176e670fd5cSchristos    ---------------------------------------------------------------------------*/
177e670fd5cSchristos 
178e670fd5cSchristos int
ldap_create_persistentsearch_control(LDAP * ld,int changetypes,int changesonly,int return_echg_ctls,int isCritical,LDAPControl ** ctrlp)179e670fd5cSchristos ldap_create_persistentsearch_control(
180e670fd5cSchristos 	LDAP *ld,
181e670fd5cSchristos 	int changetypes,
182e670fd5cSchristos 	int changesonly,
183e670fd5cSchristos 	int return_echg_ctls,
184e670fd5cSchristos 	int isCritical,
185e670fd5cSchristos 	LDAPControl **ctrlp )
186e670fd5cSchristos {
187e670fd5cSchristos 	struct berval	value;
188e670fd5cSchristos 
189e670fd5cSchristos 	assert( ld != NULL );
190e670fd5cSchristos 	assert( LDAP_VALID( ld ) );
191e670fd5cSchristos 
192e670fd5cSchristos 	if ( ld == NULL ) {
193e670fd5cSchristos 		return LDAP_PARAM_ERROR;
194e670fd5cSchristos 	}
195e670fd5cSchristos 
196e670fd5cSchristos 	if ( ctrlp == NULL ) {
197e670fd5cSchristos 		ld->ld_errno = LDAP_PARAM_ERROR;
198e670fd5cSchristos 		return ld->ld_errno;
199e670fd5cSchristos 	}
200e670fd5cSchristos 
201e670fd5cSchristos 	ld->ld_errno = ldap_create_persistentsearch_control_value( ld, changetypes, changesonly, return_echg_ctls, &value );
202e670fd5cSchristos 	if ( ld->ld_errno == LDAP_SUCCESS ) {
203e670fd5cSchristos 		ld->ld_errno = ldap_control_create( LDAP_CONTROL_PERSIST_REQUEST,
204e670fd5cSchristos 			isCritical, &value, 0, ctrlp );
205e670fd5cSchristos 		if ( ld->ld_errno != LDAP_SUCCESS ) {
206e670fd5cSchristos 			LDAP_FREE( value.bv_val );
207e670fd5cSchristos 		}
208e670fd5cSchristos 	}
209e670fd5cSchristos 
210e670fd5cSchristos 	return ld->ld_errno;
211e670fd5cSchristos }
212e670fd5cSchristos 
213e670fd5cSchristos 
214e670fd5cSchristos /* ---------------------------------------------------------------------------
215e670fd5cSchristos    ldap_parse_entrychange_control
216e670fd5cSchristos 
217e670fd5cSchristos    Decode the entry change notification control return information.
218e670fd5cSchristos 
219e670fd5cSchristos    ld          (IN) An LDAP session handle, as obtained from a call to
220e670fd5cSchristos 					ldap_init().
221e670fd5cSchristos 
222e670fd5cSchristos    ctrl        (IN) The address of the LDAP Control Structure.
223e670fd5cSchristos 
224e670fd5cSchristos    chgtypep   (OUT) This result parameter is filled in with one of the
225e670fd5cSchristos 					following values to indicate the type of change that was
226e670fd5cSchristos 					made that caused the entry to be returned:
227e670fd5cSchristos 					LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD (1),
228e670fd5cSchristos 					LDAP_CONTROL_PERSIST_ENTRY_CHANGE_DELETE (2),
229e670fd5cSchristos 					LDAP_CONTROL_PERSIST_ENTRY_CHANGE_MODIFY (4), or
230e670fd5cSchristos 					LDAP_CONTROL_PERSIST_ENTRY_CHANGE_RENAME (8).
231e670fd5cSchristos 					If this parameter is NULL, the change type information
232e670fd5cSchristos 					is not returned.
233e670fd5cSchristos 
234e670fd5cSchristos    prevdnp    (OUT) This result parameter points to the DN the
235e670fd5cSchristos    					entry had before it was renamed and/or moved by a
236e670fd5cSchristos 					modifyDN operation. It is set to NULL for other types
237e670fd5cSchristos 					of changes. If this parameter is NULL, the previous DN
238e670fd5cSchristos 					information is not returned. The returned value is a
239e670fd5cSchristos 					pointer to the contents of the control; it is not a
240e670fd5cSchristos 					copy of the data.
241e670fd5cSchristos 
242e670fd5cSchristos    chgnumpresentp (OUT) This result parameter is filled in with a non-zero
243e670fd5cSchristos    					value if a change number was returned in the control
244e670fd5cSchristos 					(the change number is optional and servers MAY choose
245e670fd5cSchristos 					not to return it). If this parameter is NULL, no indication
246e670fd5cSchristos 					of whether the change number was present is returned.
247e670fd5cSchristos 
248e670fd5cSchristos    chgnump    (OUT) This result parameter is filled in with the change number
249e670fd5cSchristos    					if one was returned in the control. If this parameter
250e670fd5cSchristos 					is NULL, the change number is not returned.
251e670fd5cSchristos 
252e670fd5cSchristos    ---------------------------------------------------------------------------*/
253e670fd5cSchristos 
254e670fd5cSchristos int
ldap_parse_entrychange_control(LDAP * ld,LDAPControl * ctrl,int * chgtypep,struct berval * prevdnp,int * chgnumpresentp,long * chgnump)255e670fd5cSchristos ldap_parse_entrychange_control(
256e670fd5cSchristos 	LDAP *ld,
257e670fd5cSchristos 	LDAPControl *ctrl,
258e670fd5cSchristos 	int *chgtypep,
259e670fd5cSchristos 	struct berval *prevdnp,
260e670fd5cSchristos 	int *chgnumpresentp,
261e670fd5cSchristos 	long *chgnump )
262e670fd5cSchristos {
263e670fd5cSchristos 	BerElement *ber;
264e670fd5cSchristos 	ber_tag_t tag, berTag;
265e670fd5cSchristos 	ber_len_t berLen;
266e670fd5cSchristos 	ber_int_t chgtype;
267e670fd5cSchristos 
268e670fd5cSchristos 	assert( ld != NULL );
269e670fd5cSchristos 	assert( LDAP_VALID( ld ) );
270e670fd5cSchristos 	assert( ctrl != NULL );
271e670fd5cSchristos 
272e670fd5cSchristos 	if (ld == NULL) {
273e670fd5cSchristos 		return LDAP_PARAM_ERROR;
274e670fd5cSchristos 	}
275e670fd5cSchristos 
276e670fd5cSchristos 	if (ctrl == NULL) {
277e670fd5cSchristos 		ld->ld_errno =  LDAP_PARAM_ERROR;
278e670fd5cSchristos 		return(ld->ld_errno);
279e670fd5cSchristos 	}
280e670fd5cSchristos 
281e670fd5cSchristos 	if ( !ctrl->ldctl_value.bv_val ) {
282e670fd5cSchristos 		ld->ld_errno = LDAP_DECODING_ERROR;
283e670fd5cSchristos 		return(ld->ld_errno);
284e670fd5cSchristos 	}
285e670fd5cSchristos 
286e670fd5cSchristos 	/* Create a BerElement from the berval returned in the control. */
287e670fd5cSchristos 	ber = ber_init(&ctrl->ldctl_value);
288e670fd5cSchristos 
289e670fd5cSchristos 	if (ber == NULL) {
290e670fd5cSchristos 		ld->ld_errno = LDAP_NO_MEMORY;
291e670fd5cSchristos 		return(ld->ld_errno);
292e670fd5cSchristos 	}
293e670fd5cSchristos 
294e670fd5cSchristos 	if ( prevdnp != NULL ) {
295e670fd5cSchristos 		BER_BVZERO( prevdnp );
296e670fd5cSchristos 	}
297e670fd5cSchristos 	if ( chgnumpresentp != NULL )
298e670fd5cSchristos 		*chgnumpresentp = 0;
299e670fd5cSchristos 	if ( chgnump != NULL )
300e670fd5cSchristos 		*chgnump = 0;
301e670fd5cSchristos 
302e670fd5cSchristos 	/* Extract the change type from the control. */
303e670fd5cSchristos 	tag = ber_scanf(ber, "{e" /*}*/, &chgtype);
304e670fd5cSchristos 
305e670fd5cSchristos 	if( tag != LBER_ENUMERATED ) {
306e670fd5cSchristos 		ber_free(ber, 1);
307e670fd5cSchristos 		ld->ld_errno = LDAP_DECODING_ERROR;
308e670fd5cSchristos 		return(ld->ld_errno);
309e670fd5cSchristos 	}
310e670fd5cSchristos 	if ( chgtypep != NULL )
311e670fd5cSchristos 		*chgtypep = chgtype;
312e670fd5cSchristos 
313e670fd5cSchristos 	tag = ber_peek_tag( ber, &berLen );
314e670fd5cSchristos 	if ( berLen ) {
315e670fd5cSchristos 		if (tag == LBER_OCTETSTRING) {
316e670fd5cSchristos 			if (prevdnp != NULL) {
317e670fd5cSchristos 				tag = ber_get_stringbv( ber, prevdnp, 0 );
318e670fd5cSchristos 			} else {
319e670fd5cSchristos 				struct berval bv;
320e670fd5cSchristos 				tag = ber_skip_element( ber, &bv );
321e670fd5cSchristos 			}
322e670fd5cSchristos 			if ( tag == LBER_ERROR ) {
323e670fd5cSchristos 				ber_free(ber, 1);
324e670fd5cSchristos 				ld->ld_errno = LDAP_DECODING_ERROR;
325e670fd5cSchristos 				return(ld->ld_errno);
326e670fd5cSchristos 			}
327e670fd5cSchristos 			tag = ber_peek_tag( ber, &berLen );
328e670fd5cSchristos 		}
329e670fd5cSchristos 
330e670fd5cSchristos 		if ( chgnumpresentp != NULL || chgnump != NULL ) {
331e670fd5cSchristos 			ber_int_t chgnum = 0;
332e670fd5cSchristos 			int present = 0;
333e670fd5cSchristos 			if (tag == LBER_INTEGER) {
334e670fd5cSchristos 				present = 1;
335e670fd5cSchristos 				tag = ber_get_int( ber, &chgnum );
336e670fd5cSchristos 				if ( tag == LBER_ERROR ) {
337e670fd5cSchristos 					ber_free(ber, 1);
338e670fd5cSchristos 					ld->ld_errno = LDAP_DECODING_ERROR;
339e670fd5cSchristos 					return(ld->ld_errno);
340e670fd5cSchristos 				}
341e670fd5cSchristos 				if ( chgnumpresentp != NULL )
342e670fd5cSchristos 					*chgnumpresentp = present;
343e670fd5cSchristos 				if ( chgnump != NULL )
344e670fd5cSchristos 					*chgnump = chgnum;
345e670fd5cSchristos 			}
346e670fd5cSchristos 		}
347e670fd5cSchristos 	}
348e670fd5cSchristos 
349e670fd5cSchristos 	ber_free(ber,1);
350e670fd5cSchristos 
351e670fd5cSchristos 	ld->ld_errno = LDAP_SUCCESS;
352e670fd5cSchristos 	return(ld->ld_errno);
353e670fd5cSchristos }
354