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