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