1 /*
2  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * The contents of this file are subject to the Netscape Public
8  * License Version 1.1 (the "License"); you may not use this file
9  * except in compliance with the License. You may obtain a copy of
10  * the License at http://www.mozilla.org/NPL/
11  *
12  * Software distributed under the License is distributed on an "AS
13  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14  * implied. See the License for the specific language governing
15  * rights and limitations under the License.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
20  * The Initial Developer of the Original Code is Netscape
21  * Communications Corporation. Portions created by Netscape are
22  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
23  * Rights Reserved.
24  *
25  * Contributor(s):
26  */
27 
28 /* vlistctrl.c - virtual list control implementation. */
29 #include "ldap-int.h"
30 
31 
32 
33 /*
34  * function to create a VirtualListViewRequest control that can be passed
35  * to ldap_search_ext() or ldap_search_ext_s().  *ctrlp will be set to a
36  * freshly allocated LDAPControl structure.  Returns an LDAP error code
37  * (LDAP_SUCCESS if all goes well).
38  *
39  *  Parameters
40  *   ld              LDAP pointer to the desired connection
41  *
42  *   ldvlistp        the control structure.
43  *
44  *   ctrlp           the address of a place to put the constructed control
45 
46   The controlValue is an OCTET STRING
47   whose value is the BER-encoding of the following SEQUENCE:
48 
49        VirtualListViewRequest ::= SEQUENCE {
50                beforeCount    INTEGER (0 .. maxInt),
51                afterCount     INTEGER (0 .. maxInt),
52                CHOICE {
53                        byIndex [0] SEQUENCE {
54                        index           INTEGER (0 .. maxInt),
55                        contentCount    INTEGER (0 .. maxInt) }
56                        byValue [1] greaterThanOrEqual assertionValue }
57 
58   beforeCount indicates how many  entries  before  the  target  entry  the
59   client  wants  the  server  to  send. afterCount indicates the number of
60   entries after the target entry the client  wants  the  server  to  send.
61   index  and contentCount identify the target entry
62   greaterThanOrEqual  is  an  attribute  assertion  value  defined  in
63   [LDAPv3].  If  present, the value supplied in greaterThanOrEqual is used
64   to determine the target entry by  comparison  with  the  values  of  the
65   attribute  specified as the primary sort key. The first list entry who's
66   value is no less than the supplied value is the target entry.
67 
68  */
69 
70 int
71 LDAP_CALL
ldap_create_virtuallist_control(LDAP * ld,LDAPVirtualList * ldvlistp,LDAPControl ** ctrlp)72 ldap_create_virtuallist_control(
73     LDAP *ld,
74     LDAPVirtualList *ldvlistp,
75     LDAPControl **ctrlp
76 )
77 {
78     BerElement *ber;
79     int rc;
80 
81     if (!NSLDAPI_VALID_LDAP_POINTER( ld )) {
82 	return( LDAP_PARAM_ERROR );
83     }
84 
85 
86     if ( NULL == ctrlp || NULL == ldvlistp ) {
87         LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
88         return ( LDAP_PARAM_ERROR );
89     }
90 
91     /* create a ber package to hold the controlValue */
92     if ( LDAP_SUCCESS != nsldapi_alloc_ber_with_options( ld, &ber )  )
93     {
94         LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
95         return( LDAP_NO_MEMORY );
96     }
97 
98     if ( LBER_ERROR == ber_printf( ber,
99                                    "{ii",
100                                    (int)ldvlistp->ldvlist_before_count,
101                                    (int)ldvlistp->ldvlist_after_count ))
102 				    /* XXX lossy casts */
103     {
104         LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
105         ber_free( ber, 1 );
106         return( LDAP_ENCODING_ERROR );
107     }
108 
109     if (NULL == ldvlistp->ldvlist_attrvalue)
110     {
111         if ( LBER_ERROR == ber_printf( ber,
112                                        "t{ii}}",
113 				       LDAP_TAG_VLV_BY_INDEX,
114                                        (int)ldvlistp->ldvlist_index,
115                                        (int)ldvlistp->ldvlist_size ) )
116 				       /* XXX lossy casts */
117         {
118             LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
119             ber_free( ber, 1 );
120             return( LDAP_ENCODING_ERROR );
121         }
122     }
123     else
124     {
125         if ( LBER_ERROR == ber_printf( ber,
126                                       "to}",
127 				       LDAP_TAG_VLV_BY_VALUE,
128                                       ldvlistp->ldvlist_attrvalue,
129 				       (int)strlen( ldvlistp->ldvlist_attrvalue )) ) {
130             LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
131             ber_free( ber, 1 );
132             return( LDAP_ENCODING_ERROR );
133         }
134     }
135 
136 
137     rc = nsldapi_build_control( LDAP_CONTROL_VLVREQUEST ,
138                                 ber,
139                                 1,
140                                 1,
141                                 ctrlp );
142 
143     LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
144     return( rc );
145 
146 }
147 
148 
149 /*
150  * function to find and parse a VirtualListViewResponse control contained in
151  * "ctrls"  *target_posp, *list_sizep, and *errcodep are set based on its
152  * contents.  Returns an LDAP error code that indicates whether the parsing
153  * itself was successful (LDAP_SUCCESS if all goes well).
154 
155   The controlValue is an OCTET STRING, whose value
156   is the BER encoding of a value of the following SEQUENCE:
157 
158        VirtualListViewResponse ::= SEQUENCE {
159                targetPosition    INTEGER (0 .. maxInt),
160                contentCount     INTEGER (0 .. maxInt),
161                virtualListViewResult ENUMERATED {
162                        success (0),
163                        operatonsError (1),
164                        unwillingToPerform (53),
165                        insufficientAccessRights (50),
166                        busy (51),
167                        timeLimitExceeded (3),
168                        adminLimitExceeded (11),
169                        sortControlMissing (60),
170                        indexRangeError (61),
171                        other (80) }  }
172 
173  */
174 int
175 LDAP_CALL
ldap_parse_virtuallist_control(LDAP * ld,LDAPControl ** ctrls,unsigned long * target_posp,unsigned long * list_sizep,int * errcodep)176 ldap_parse_virtuallist_control
177 (
178     LDAP *ld,
179     LDAPControl **ctrls,
180     unsigned long *target_posp,
181     unsigned long *list_sizep,
182     int *errcodep
183 )
184 {
185     BerElement		*ber;
186     int			i, foundListControl, errcode;
187     LDAPControl		*listCtrlp;
188     unsigned long	target_pos, list_size;
189     int			target_pos_int, list_size_int;
190 
191     if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
192         return( LDAP_PARAM_ERROR );
193     }
194 
195     /* only ldapv3 or higher can do virtual lists. */
196     if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
197         LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
198         return( LDAP_NOT_SUPPORTED );
199     }
200 
201     /* find the listControl in the list of controls if it exists */
202     if ( ctrls == NULL ) {
203         LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
204         return ( LDAP_CONTROL_NOT_FOUND );
205     }
206 
207     foundListControl = 0;
208     for ( i = 0; (( ctrls[i] != NULL ) && ( !foundListControl )); i++ ) {
209         foundListControl = !strcmp( ctrls[i]->ldctl_oid,
210                                     LDAP_CONTROL_VLVRESPONSE );
211     }
212     if ( !foundListControl ) {
213         LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
214         return ( LDAP_CONTROL_NOT_FOUND );
215     } else {
216         /* let local var point to the listControl */
217         listCtrlp = ctrls[i-1];
218     }
219 
220     /*  allocate a Ber element with the contents of the list_control's struct berval */
221     if ( ( ber = ber_init( &listCtrlp->ldctl_value ) ) == NULL ) {
222         LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
223         return( LDAP_NO_MEMORY );
224     }
225 
226     /* decode the result from the Berelement */
227     if (  LBER_ERROR == ber_scanf( ber, "{iie}", &target_pos_int, &list_size_int,
228 	    &errcode ) ) {
229         LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
230         ber_free( ber, 1 );
231         return( LDAP_DECODING_ERROR );
232     }
233 
234     target_pos = target_pos_int;
235     list_size = list_size_int;
236 
237     if ( target_posp != NULL ) {
238 	*target_posp = target_pos;
239     }
240     if ( list_sizep != NULL ) {
241 	*list_sizep = list_size;
242     }
243     if ( errcodep != NULL ) {
244 	*errcodep = errcode;
245     }
246 
247     /* the ber encoding is no longer needed */
248     ber_free(ber,1);
249 
250     return(LDAP_SUCCESS);
251 
252 }
253