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