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