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