xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/vlvctrl.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /* $OpenLDAP: pkg/ldap/libraries/libldap/vlvctrl.c,v 1.21.2.3 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2008 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
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 
105 	ber = ldap_alloc_ber_with_options( ld );
106 	if ( ber == NULL ) {
107 		ld->ld_errno = LDAP_NO_MEMORY;
108 		return ld->ld_errno;
109 	}
110 
111 	tag = ber_printf( ber, "{ii" /*}*/,
112 		vlvinfop->ldvlv_before_count,
113 		vlvinfop->ldvlv_after_count );
114 	if ( tag == LBER_ERROR ) {
115 		goto error_return;
116 	}
117 
118 	if ( vlvinfop->ldvlv_attrvalue == NULL ) {
119 		tag = ber_printf( ber, "t{iiN}",
120 			LDAP_VLVBYINDEX_IDENTIFIER,
121 			vlvinfop->ldvlv_offset,
122 			vlvinfop->ldvlv_count );
123 		if ( tag == LBER_ERROR ) {
124 			goto error_return;
125 		}
126 
127 	} else {
128 		tag = ber_printf( ber, "tO",
129 			LDAP_VLVBYVALUE_IDENTIFIER,
130 			vlvinfop->ldvlv_attrvalue );
131 		if ( tag == LBER_ERROR ) {
132 			goto error_return;
133 		}
134 	}
135 
136 	if ( vlvinfop->ldvlv_context ) {
137 		tag = ber_printf( ber, "tO",
138 			LDAP_VLVCONTEXT_IDENTIFIER,
139 			vlvinfop->ldvlv_context );
140 		if ( tag == LBER_ERROR ) {
141 			goto error_return;
142 		}
143 	}
144 
145 	tag = ber_printf( ber, /*{*/ "N}" );
146 	if ( tag == LBER_ERROR ) {
147 		goto error_return;
148 	}
149 
150 	if ( ber_flatten2( ber, value, 1 ) == -1 ) {
151 		ld->ld_errno = LDAP_NO_MEMORY;
152 	}
153 
154 	if ( 0 ) {
155 error_return:;
156 		ld->ld_errno = LDAP_ENCODING_ERROR;
157 	}
158 
159 	if ( ber != NULL ) {
160 		ber_free( ber, 1 );
161 	}
162 
163 	return ld->ld_errno;
164 }
165 
166 /*---
167    ldap_create_vlv_control
168 
169    Create and encode the Virtual List View control.
170 
171    ld        (IN)  An LDAP session handle.
172 
173    vlvinfop  (IN)  The address of an LDAPVLVInfo structure whose contents
174 				   are used to construct the value of the control
175 				   that is created.
176 
177    ctrlp     (OUT) A result parameter that will be assigned the address
178 				   of an LDAPControl structure that contains the
179 				   VirtualListViewRequest control created by this function.
180 				   The memory occupied by the LDAPControl structure
181 				   SHOULD be freed when it is no longer in use by
182 				   calling ldap_control_free().
183 
184 
185    Ber encoding
186 
187    VirtualListViewRequest ::= SEQUENCE {
188 		beforeCount  INTEGER (0 .. maxInt),
189 		afterCount   INTEGER (0 .. maxInt),
190 		CHOICE {
191 				byoffset [0] SEQUENCE, {
192 				offset        INTEGER (0 .. maxInt),
193 				contentCount  INTEGER (0 .. maxInt) }
194 				[1] greaterThanOrEqual assertionValue }
195 		contextID     OCTET STRING OPTIONAL }
196 
197 
198    Note:  The first time the VLV control is created, the ldvlv_context
199 		  field of the LDAPVLVInfo structure should be set to NULL.
200 		  The context obtained from calling ldap_parse_vlv_control()
201 		  should be used as the context in the next ldap_create_vlv_control
202 		  call.
203 
204  ---*/
205 
206 int
207 ldap_create_vlv_control(
208 	LDAP *ld,
209 	LDAPVLVInfo *vlvinfop,
210 	LDAPControl **ctrlp )
211 {
212 	struct berval	value;
213 
214 	if ( ctrlp == NULL ) {
215 		ld->ld_errno = LDAP_PARAM_ERROR;
216 		return ld->ld_errno;
217 	}
218 
219 	ld->ld_errno = ldap_create_vlv_control_value( ld, vlvinfop, &value );
220 	if ( ld->ld_errno == LDAP_SUCCESS ) {
221 
222 		ld->ld_errno = ldap_control_create( LDAP_CONTROL_VLVREQUEST,
223 			1, &value, 0, ctrlp );
224 		if ( ld->ld_errno != LDAP_SUCCESS ) {
225 			LDAP_FREE( value.bv_val );
226 		}
227 	}
228 
229 	return ld->ld_errno;
230 }
231 
232 
233 /*---
234    ldap_parse_vlvresponse_control
235 
236    Decode the Virtual List View control return information.
237 
238    ld           (IN)   An LDAP session handle.
239 
240    ctrl         (IN)   The address of the LDAPControl structure.
241 
242    target_posp	(OUT)  This result parameter is filled in with the list
243 					   index of the target entry.  If this parameter is
244 					   NULL, the target position is not returned.
245 
246    list_countp  (OUT)  This result parameter is filled in with the server's
247 					   estimate of the size of the list.  If this parameter
248 					   is NULL, the size is not returned.
249 
250    contextp     (OUT)  This result parameter is filled in with the address
251 					   of a struct berval that contains the server-
252 					   generated context identifier if one was returned by
253 					   the server.  If the server did not return a context
254 					   identifier, this parameter will be set to NULL, even
255 					   if an error occured.
256 					   The returned context SHOULD be used in the next call
257 					   to create a VLV sort control.  The struct berval
258 					   returned SHOULD be disposed of by calling ber_bvfree()
259 					   when it is no longer needed.  If NULL is passed for
260 					   contextp, the context identifier is not returned.
261 
262    errcodep     (OUT)  This result parameter is filled in with the VLV
263 					   result code.  If this parameter is NULL, the result
264 					   code is not returned.
265 
266 
267    Ber encoding
268 
269    VirtualListViewResponse ::= SEQUENCE {
270 		targetPosition    INTEGER (0 .. maxInt),
271 		contentCount     INTEGER (0 .. maxInt),
272 		virtualListViewResult ENUMERATED {
273 		success (0),
274 		operatonsError (1),
275 		unwillingToPerform (53),
276 		insufficientAccessRights (50),
277 		busy (51),
278 		timeLimitExceeded (3),
279 		adminLimitExceeded (11),
280 		sortControlMissing (60),
281 		offsetRangeError (61),
282 		other (80) },
283 		contextID     OCTET STRING OPTIONAL }
284 
285 ---*/
286 
287 int
288 ldap_parse_vlvresponse_control(
289 	LDAP *ld,
290 	LDAPControl *ctrl,
291 	ber_int_t *target_posp,
292 	ber_int_t *list_countp,
293 	struct berval  **contextp,
294 	ber_int_t *errcodep )
295 {
296 	BerElement  *ber;
297 	ber_int_t pos, count, err;
298 	ber_tag_t tag, berTag;
299 	ber_len_t berLen;
300 
301 	assert( ld != NULL );
302 	assert( LDAP_VALID( ld ) );
303 
304 	if (contextp) {
305 		*contextp = NULL;	 /* Make sure we return a NULL if error occurs. */
306 	}
307 
308 	if (ctrl == NULL) {
309 		ld->ld_errno = LDAP_PARAM_ERROR;
310 		return(ld->ld_errno);
311 	}
312 
313 	if (strcmp(LDAP_CONTROL_VLVRESPONSE, ctrl->ldctl_oid) != 0) {
314 		/* Not VLV Response control */
315 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
316 		return(ld->ld_errno);
317 	}
318 
319 	/* Create a BerElement from the berval returned in the control. */
320 	ber = ber_init(&ctrl->ldctl_value);
321 
322 	if (ber == NULL) {
323 		ld->ld_errno = LDAP_NO_MEMORY;
324 		return(ld->ld_errno);
325 	}
326 
327 	/* Extract the data returned in the control. */
328 	tag = ber_scanf(ber, "{iie" /*}*/, &pos, &count, &err);
329 
330 	if( tag == LBER_ERROR) {
331 		ber_free(ber, 1);
332 		ld->ld_errno = LDAP_DECODING_ERROR;
333 		return(ld->ld_errno);
334 	}
335 
336 
337 	/* Since the context is the last item encoded, if caller doesn't want
338 	   it returned, don't decode it. */
339 	if (contextp) {
340 		if (LDAP_VLVCONTEXT_IDENTIFIER == ber_peek_tag(ber, &berLen)) {
341 			tag = ber_scanf(ber, "tO", &berTag, contextp);
342 
343 			if( tag == LBER_ERROR) {
344 				ber_free(ber, 1);
345 				ld->ld_errno = LDAP_DECODING_ERROR;
346 				return(ld->ld_errno);
347 			}
348 		}
349 	}
350 
351 	ber_free(ber, 1);
352 
353 	/* Return data to the caller for items that were requested. */
354 	if (target_posp) *target_posp = pos;
355 	if (list_countp) *list_countp = count;
356 	if (errcodep) *errcodep = err;
357 
358 	ld->ld_errno = LDAP_SUCCESS;
359 	return(ld->ld_errno);
360 }
361