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