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