xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/vlvctrl.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: vlvctrl.c,v 1.3 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 /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
18  *
19  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
20  * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
21  * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
22  * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
23  * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
24  * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
25  * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
26  * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
27  *---
28  * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
29  * can be found in the file "build/LICENSE-2.0.1" in this distribution
30  * of OpenLDAP Software.
31  */
32 
33 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: vlvctrl.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
35 
36 #include "portable.h"
37 
38 #include <stdio.h>
39 #include <ac/stdlib.h>
40 #include <ac/string.h>
41 #include <ac/time.h>
42 
43 #include "ldap-int.h"
44 
45 #define LDAP_VLVBYINDEX_IDENTIFIER     0xa0L
46 #define LDAP_VLVBYVALUE_IDENTIFIER     0x81L
47 #define LDAP_VLVCONTEXT_IDENTIFIER     0x04L
48 
49 
50 /*---
51    ldap_create_vlv_control
52 
53    Create and encode the Virtual List View control.
54 
55    ld        (IN)  An LDAP session handle.
56 
57    vlvinfop  (IN)  The address of an LDAPVLVInfo structure whose contents
58 				   are used to construct the value of the control
59 				   that is created.
60 
61    value     (OUT) A struct berval that contains the value to be assigned to the ldctl_value member
62 				   of an LDAPControl structure that contains the
63 				   VirtualListViewRequest control.
64 				   The bv_val member of the berval structure
65 				   SHOULD be freed when it is no longer in use by
66 				   calling ldap_memfree().
67 
68 
69    Ber encoding
70 
71    VirtualListViewRequest ::= SEQUENCE {
72 		beforeCount  INTEGER (0 .. maxInt),
73 		afterCount   INTEGER (0 .. maxInt),
74 		CHOICE {
75 				byoffset [0] SEQUENCE, {
76 				offset        INTEGER (0 .. maxInt),
77 				contentCount  INTEGER (0 .. maxInt) }
78 				[1] greaterThanOrEqual assertionValue }
79 		contextID     OCTET STRING OPTIONAL }
80 
81 
82    Note:  The first time the VLV control is created, the ldvlv_context
83 		  field of the LDAPVLVInfo structure should be set to NULL.
84 		  The context obtained from calling ldap_parse_vlv_control()
85 		  should be used as the context in the next ldap_create_vlv_control
86 		  call.
87 
88  ---*/
89 
90 int
ldap_create_vlv_control_value(LDAP * ld,LDAPVLVInfo * vlvinfop,struct berval * value)91 ldap_create_vlv_control_value(
92 	LDAP *ld,
93 	LDAPVLVInfo *vlvinfop,
94 	struct berval *value )
95 {
96 	ber_tag_t tag;
97 	BerElement *ber;
98 
99 	if ( ld == NULL || vlvinfop == NULL || value == NULL ) {
100 		if ( ld )
101 			ld->ld_errno = LDAP_PARAM_ERROR;
102 		return LDAP_PARAM_ERROR;
103 	}
104 
105 	assert( LDAP_VALID( ld ) );
106 
107 	value->bv_val = NULL;
108 	value->bv_len = 0;
109 	ld->ld_errno = LDAP_SUCCESS;
110 
111 	ber = ldap_alloc_ber_with_options( ld );
112 	if ( ber == NULL ) {
113 		ld->ld_errno = LDAP_NO_MEMORY;
114 		return ld->ld_errno;
115 	}
116 
117 	tag = ber_printf( ber, "{ii" /*}*/,
118 		vlvinfop->ldvlv_before_count,
119 		vlvinfop->ldvlv_after_count );
120 	if ( tag == LBER_ERROR ) {
121 		goto error_return;
122 	}
123 
124 	if ( vlvinfop->ldvlv_attrvalue == NULL ) {
125 		tag = ber_printf( ber, "t{iiN}",
126 			LDAP_VLVBYINDEX_IDENTIFIER,
127 			vlvinfop->ldvlv_offset,
128 			vlvinfop->ldvlv_count );
129 		if ( tag == LBER_ERROR ) {
130 			goto error_return;
131 		}
132 
133 	} else {
134 		tag = ber_printf( ber, "tO",
135 			LDAP_VLVBYVALUE_IDENTIFIER,
136 			vlvinfop->ldvlv_attrvalue );
137 		if ( tag == LBER_ERROR ) {
138 			goto error_return;
139 		}
140 	}
141 
142 	if ( vlvinfop->ldvlv_context ) {
143 		tag = ber_printf( ber, "tO",
144 			LDAP_VLVCONTEXT_IDENTIFIER,
145 			vlvinfop->ldvlv_context );
146 		if ( tag == LBER_ERROR ) {
147 			goto error_return;
148 		}
149 	}
150 
151 	tag = ber_printf( ber, /*{*/ "N}" );
152 	if ( tag == LBER_ERROR ) {
153 		goto error_return;
154 	}
155 
156 	if ( ber_flatten2( ber, value, 1 ) == -1 ) {
157 		ld->ld_errno = LDAP_NO_MEMORY;
158 	}
159 
160 	if ( 0 ) {
161 error_return:;
162 		ld->ld_errno = LDAP_ENCODING_ERROR;
163 	}
164 
165 	if ( ber != NULL ) {
166 		ber_free( ber, 1 );
167 	}
168 
169 	return ld->ld_errno;
170 }
171 
172 /*---
173    ldap_create_vlv_control
174 
175    Create and encode the Virtual List View control.
176 
177    ld        (IN)  An LDAP session handle.
178 
179    vlvinfop  (IN)  The address of an LDAPVLVInfo structure whose contents
180 				   are used to construct the value of the control
181 				   that is created.
182 
183    ctrlp     (OUT) A result parameter that will be assigned the address
184 				   of an LDAPControl structure that contains the
185 				   VirtualListViewRequest control created by this function.
186 				   The memory occupied by the LDAPControl structure
187 				   SHOULD be freed when it is no longer in use by
188 				   calling ldap_control_free().
189 
190 
191    Ber encoding
192 
193    VirtualListViewRequest ::= SEQUENCE {
194 		beforeCount  INTEGER (0 .. maxInt),
195 		afterCount   INTEGER (0 .. maxInt),
196 		CHOICE {
197 				byoffset [0] SEQUENCE, {
198 				offset        INTEGER (0 .. maxInt),
199 				contentCount  INTEGER (0 .. maxInt) }
200 				[1] greaterThanOrEqual assertionValue }
201 		contextID     OCTET STRING OPTIONAL }
202 
203 
204    Note:  The first time the VLV control is created, the ldvlv_context
205 		  field of the LDAPVLVInfo structure should be set to NULL.
206 		  The context obtained from calling ldap_parse_vlv_control()
207 		  should be used as the context in the next ldap_create_vlv_control
208 		  call.
209 
210  ---*/
211 
212 int
ldap_create_vlv_control(LDAP * ld,LDAPVLVInfo * vlvinfop,LDAPControl ** ctrlp)213 ldap_create_vlv_control(
214 	LDAP *ld,
215 	LDAPVLVInfo *vlvinfop,
216 	LDAPControl **ctrlp )
217 {
218 	struct berval	value;
219 
220 	if ( ctrlp == NULL ) {
221 		ld->ld_errno = LDAP_PARAM_ERROR;
222 		return ld->ld_errno;
223 	}
224 
225 	ld->ld_errno = ldap_create_vlv_control_value( ld, vlvinfop, &value );
226 	if ( ld->ld_errno == LDAP_SUCCESS ) {
227 
228 		ld->ld_errno = ldap_control_create( LDAP_CONTROL_VLVREQUEST,
229 			1, &value, 0, ctrlp );
230 		if ( ld->ld_errno != LDAP_SUCCESS ) {
231 			LDAP_FREE( value.bv_val );
232 		}
233 	}
234 
235 	return ld->ld_errno;
236 }
237 
238 
239 /*---
240    ldap_parse_vlvresponse_control
241 
242    Decode the Virtual List View control return information.
243 
244    ld           (IN)   An LDAP session handle.
245 
246    ctrl         (IN)   The address of the LDAPControl structure.
247 
248    target_posp	(OUT)  This result parameter is filled in with the list
249 					   index of the target entry.  If this parameter is
250 					   NULL, the target position is not returned.
251 
252    list_countp  (OUT)  This result parameter is filled in with the server's
253 					   estimate of the size of the list.  If this parameter
254 					   is NULL, the size is not returned.
255 
256    contextp     (OUT)  This result parameter is filled in with the address
257 					   of a struct berval that contains the server-
258 					   generated context identifier if one was returned by
259 					   the server.  If the server did not return a context
260 					   identifier, this parameter will be set to NULL, even
261 					   if an error occurred.
262 					   The returned context SHOULD be used in the next call
263 					   to create a VLV sort control.  The struct berval
264 					   returned SHOULD be disposed of by calling ber_bvfree()
265 					   when it is no longer needed.  If NULL is passed for
266 					   contextp, the context identifier is not returned.
267 
268    errcodep     (OUT)  This result parameter is filled in with the VLV
269 					   result code.  If this parameter is NULL, the result
270 					   code is not returned.
271 
272 
273    Ber encoding
274 
275    VirtualListViewResponse ::= SEQUENCE {
276 		targetPosition    INTEGER (0 .. maxInt),
277 		contentCount     INTEGER (0 .. maxInt),
278 		virtualListViewResult ENUMERATED {
279 		success (0),
280 		operationsError (1),
281 		unwillingToPerform (53),
282 		insufficientAccessRights (50),
283 		busy (51),
284 		timeLimitExceeded (3),
285 		adminLimitExceeded (11),
286 		sortControlMissing (60),
287 		offsetRangeError (61),
288 		other (80) },
289 		contextID     OCTET STRING OPTIONAL }
290 
291 ---*/
292 
293 int
ldap_parse_vlvresponse_control(LDAP * ld,LDAPControl * ctrl,ber_int_t * target_posp,ber_int_t * list_countp,struct berval ** contextp,ber_int_t * errcodep)294 ldap_parse_vlvresponse_control(
295 	LDAP *ld,
296 	LDAPControl *ctrl,
297 	ber_int_t *target_posp,
298 	ber_int_t *list_countp,
299 	struct berval  **contextp,
300 	ber_int_t *errcodep )
301 {
302 	BerElement  *ber;
303 	ber_int_t pos, count, err;
304 	ber_tag_t tag, berTag;
305 	ber_len_t berLen;
306 
307 	assert( ld != NULL );
308 	assert( LDAP_VALID( ld ) );
309 
310 	if (contextp) {
311 		*contextp = NULL;	 /* Make sure we return a NULL if error occurs. */
312 	}
313 
314 	if (ctrl == NULL) {
315 		ld->ld_errno = LDAP_PARAM_ERROR;
316 		return(ld->ld_errno);
317 	}
318 
319 	if (strcmp(LDAP_CONTROL_VLVRESPONSE, ctrl->ldctl_oid) != 0) {
320 		/* Not VLV Response control */
321 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
322 		return(ld->ld_errno);
323 	}
324 
325 	/* Create a BerElement from the berval returned in the control. */
326 	ber = ber_init(&ctrl->ldctl_value);
327 
328 	if (ber == NULL) {
329 		ld->ld_errno = LDAP_NO_MEMORY;
330 		return(ld->ld_errno);
331 	}
332 
333 	/* Extract the data returned in the control. */
334 	tag = ber_scanf(ber, "{iie" /*}*/, &pos, &count, &err);
335 
336 	if( tag == LBER_ERROR) {
337 		ber_free(ber, 1);
338 		ld->ld_errno = LDAP_DECODING_ERROR;
339 		return(ld->ld_errno);
340 	}
341 
342 
343 	/* Since the context is the last item encoded, if caller doesn't want
344 	   it returned, don't decode it. */
345 	if (contextp) {
346 		if (LDAP_VLVCONTEXT_IDENTIFIER == ber_peek_tag(ber, &berLen)) {
347 			tag = ber_scanf(ber, "tO", &berTag, contextp);
348 
349 			if( tag == LBER_ERROR) {
350 				ber_free(ber, 1);
351 				ld->ld_errno = LDAP_DECODING_ERROR;
352 				return(ld->ld_errno);
353 			}
354 		}
355 	}
356 
357 	ber_free(ber, 1);
358 
359 	/* Return data to the caller for items that were requested. */
360 	if (target_posp) *target_posp = pos;
361 	if (list_countp) *list_countp = count;
362 	if (errcodep) *errcodep = err;
363 
364 	ld->ld_errno = LDAP_SUCCESS;
365 	return(ld->ld_errno);
366 }
367