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