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