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