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