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