1 /* $NetBSD: controls.c,v 1.1.1.7 2019/08/08 13:31:16 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2019 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 /* This notice applies to changes, created by or for Novell, Inc., 18 * to preexisting works for which notices appear elsewhere in this file. 19 * 20 * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. 21 * 22 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. 23 * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION 24 * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT 25 * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE 26 * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS 27 * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC 28 * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE 29 * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 30 *--- 31 * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License 32 * can be found in the file "build/LICENSE-2.0.1" in this distribution 33 * of OpenLDAP Software. 34 */ 35 36 #include <sys/cdefs.h> 37 __RCSID("$NetBSD: controls.c,v 1.1.1.7 2019/08/08 13:31:16 christos Exp $"); 38 39 #include "portable.h" 40 41 #include <ac/stdlib.h> 42 43 #include <ac/time.h> 44 #include <ac/string.h> 45 46 #include "ldap-int.h" 47 48 /* LDAPv3 Controls (RFC 4511) 49 * 50 * Controls ::= SEQUENCE OF control Control 51 * 52 * Control ::= SEQUENCE { 53 * controlType LDAPOID, 54 * criticality BOOLEAN DEFAULT FALSE, 55 * controlValue OCTET STRING OPTIONAL 56 * } 57 */ 58 59 int 60 ldap_pvt_put_control( 61 const LDAPControl *c, 62 BerElement *ber ) 63 { 64 if ( ber_printf( ber, "{s" /*}*/, c->ldctl_oid ) == -1 ) { 65 return LDAP_ENCODING_ERROR; 66 } 67 68 if ( c->ldctl_iscritical /* only if true */ 69 && ( ber_printf( ber, "b", 70 (ber_int_t) c->ldctl_iscritical ) == -1 ) ) 71 { 72 return LDAP_ENCODING_ERROR; 73 } 74 75 if ( !BER_BVISNULL( &c->ldctl_value ) /* only if we have a value */ 76 && ( ber_printf( ber, "O", &c->ldctl_value ) == -1 ) ) 77 { 78 return LDAP_ENCODING_ERROR; 79 } 80 81 if ( ber_printf( ber, /*{*/"N}" ) == -1 ) { 82 return LDAP_ENCODING_ERROR; 83 } 84 85 return LDAP_SUCCESS; 86 } 87 88 89 /* 90 * ldap_int_put_controls 91 */ 92 93 int 94 ldap_int_put_controls( 95 LDAP *ld, 96 LDAPControl *const *ctrls, 97 BerElement *ber ) 98 { 99 LDAPControl *const *c; 100 101 assert( ld != NULL ); 102 assert( LDAP_VALID( ld ) ); 103 assert( ber != NULL ); 104 105 if( ctrls == NULL ) { 106 /* use default server controls */ 107 ctrls = ld->ld_sctrls; 108 } 109 110 if( ctrls == NULL || *ctrls == NULL ) { 111 return LDAP_SUCCESS; 112 } 113 114 if ( ld->ld_version < LDAP_VERSION3 ) { 115 /* LDAPv2 doesn't support controls, 116 * error if any control is critical 117 */ 118 for( c = ctrls ; *c != NULL; c++ ) { 119 if( (*c)->ldctl_iscritical ) { 120 ld->ld_errno = LDAP_NOT_SUPPORTED; 121 return ld->ld_errno; 122 } 123 } 124 125 return LDAP_SUCCESS; 126 } 127 128 /* Controls are encoded as a sequence of sequences */ 129 if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) { 130 ld->ld_errno = LDAP_ENCODING_ERROR; 131 return ld->ld_errno; 132 } 133 134 for( c = ctrls ; *c != NULL; c++ ) { 135 ld->ld_errno = ldap_pvt_put_control( *c, ber ); 136 if ( ld->ld_errno != LDAP_SUCCESS ) { 137 return ld->ld_errno; 138 } 139 } 140 141 142 if( ber_printf( ber, /*{*/ "}" ) == -1 ) { 143 ld->ld_errno = LDAP_ENCODING_ERROR; 144 return ld->ld_errno; 145 } 146 147 return LDAP_SUCCESS; 148 } 149 150 int ldap_pvt_get_controls( 151 BerElement *ber, 152 LDAPControl ***ctrls ) 153 { 154 int nctrls; 155 ber_tag_t tag; 156 ber_len_t len; 157 char *opaque; 158 159 assert( ber != NULL ); 160 161 if( ctrls == NULL ) { 162 return LDAP_SUCCESS; 163 } 164 *ctrls = NULL; 165 166 len = ber_pvt_ber_remaining( ber ); 167 168 if( len == 0) { 169 /* no controls */ 170 return LDAP_SUCCESS; 171 } 172 173 if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) { 174 if( tag == LBER_ERROR ) { 175 /* decoding error */ 176 return LDAP_DECODING_ERROR; 177 } 178 179 /* ignore unexpected input */ 180 return LDAP_SUCCESS; 181 } 182 183 /* set through each element */ 184 nctrls = 0; 185 *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) ); 186 187 if( *ctrls == NULL ) { 188 return LDAP_NO_MEMORY; 189 } 190 191 *ctrls[nctrls] = NULL; 192 193 for( tag = ber_first_element( ber, &len, &opaque ); 194 tag != LBER_ERROR; 195 tag = ber_next_element( ber, &len, opaque ) ) 196 { 197 LDAPControl *tctrl; 198 LDAPControl **tctrls; 199 200 tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) ); 201 202 /* allocate pointer space for current controls (nctrls) 203 * + this control + extra NULL 204 */ 205 tctrls = (tctrl == NULL) ? NULL : 206 LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *)); 207 208 if( tctrls == NULL ) { 209 /* one of the above allocation failed */ 210 211 if( tctrl != NULL ) { 212 LDAP_FREE( tctrl ); 213 } 214 215 ldap_controls_free(*ctrls); 216 *ctrls = NULL; 217 218 return LDAP_NO_MEMORY; 219 } 220 221 222 tctrls[nctrls++] = tctrl; 223 tctrls[nctrls] = NULL; 224 225 tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid ); 226 227 if( tag == LBER_ERROR ) { 228 *ctrls = NULL; 229 ldap_controls_free( tctrls ); 230 return LDAP_DECODING_ERROR; 231 } 232 233 tag = ber_peek_tag( ber, &len ); 234 235 if( tag == LBER_BOOLEAN ) { 236 ber_int_t crit; 237 tag = ber_scanf( ber, "b", &crit ); 238 tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0; 239 tag = ber_peek_tag( ber, &len ); 240 } 241 242 if( tag == LBER_OCTETSTRING ) { 243 tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); 244 } else { 245 BER_BVZERO( &tctrl->ldctl_value ); 246 } 247 248 *ctrls = tctrls; 249 } 250 251 return LDAP_SUCCESS; 252 } 253 254 /* 255 * Free a LDAPControl 256 */ 257 void 258 ldap_control_free( LDAPControl *c ) 259 { 260 LDAP_MEMORY_DEBUG_ASSERT( c != NULL ); 261 262 if ( c != NULL ) { 263 if( c->ldctl_oid != NULL) { 264 LDAP_FREE( c->ldctl_oid ); 265 } 266 267 if( c->ldctl_value.bv_val != NULL ) { 268 LDAP_FREE( c->ldctl_value.bv_val ); 269 } 270 271 LDAP_FREE( c ); 272 } 273 } 274 275 /* 276 * Free an array of LDAPControl's 277 */ 278 void 279 ldap_controls_free( LDAPControl **controls ) 280 { 281 LDAP_MEMORY_DEBUG_ASSERT( controls != NULL ); 282 283 if ( controls != NULL ) { 284 int i; 285 286 for( i=0; controls[i] != NULL; i++) { 287 ldap_control_free( controls[i] ); 288 } 289 290 LDAP_FREE( controls ); 291 } 292 } 293 294 /* 295 * Duplicate an array of LDAPControl 296 */ 297 LDAPControl ** 298 ldap_controls_dup( LDAPControl *const *controls ) 299 { 300 LDAPControl **new; 301 int i; 302 303 if ( controls == NULL ) { 304 return NULL; 305 } 306 307 /* count the controls */ 308 for(i=0; controls[i] != NULL; i++) /* empty */ ; 309 310 if( i < 1 ) { 311 /* no controls to duplicate */ 312 return NULL; 313 } 314 315 new = (LDAPControl **) LDAP_MALLOC( (i+1) * sizeof(LDAPControl *) ); 316 317 if( new == NULL ) { 318 /* memory allocation failure */ 319 return NULL; 320 } 321 322 /* duplicate the controls */ 323 for(i=0; controls[i] != NULL; i++) { 324 new[i] = ldap_control_dup( controls[i] ); 325 326 if( new[i] == NULL ) { 327 ldap_controls_free( new ); 328 return NULL; 329 } 330 } 331 332 new[i] = NULL; 333 334 return new; 335 } 336 337 /* 338 * Duplicate a LDAPControl 339 */ 340 LDAPControl * 341 ldap_control_dup( const LDAPControl *c ) 342 { 343 LDAPControl *new; 344 345 if ( c == NULL || c->ldctl_oid == NULL ) { 346 return NULL; 347 } 348 349 new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); 350 351 if( new == NULL ) { 352 return NULL; 353 } 354 355 new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid ); 356 357 if(new->ldctl_oid == NULL) { 358 LDAP_FREE( new ); 359 return NULL; 360 } 361 362 if( c->ldctl_value.bv_val != NULL ) { 363 new->ldctl_value.bv_val = 364 (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 ); 365 366 if(new->ldctl_value.bv_val == NULL) { 367 if(new->ldctl_oid != NULL) { 368 LDAP_FREE( new->ldctl_oid ); 369 } 370 LDAP_FREE( new ); 371 return NULL; 372 } 373 374 new->ldctl_value.bv_len = c->ldctl_value.bv_len; 375 376 AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val, 377 c->ldctl_value.bv_len ); 378 379 new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0'; 380 381 } else { 382 new->ldctl_value.bv_len = 0; 383 new->ldctl_value.bv_val = NULL; 384 } 385 386 new->ldctl_iscritical = c->ldctl_iscritical; 387 return new; 388 } 389 390 /* 391 * Find a LDAPControl - deprecated 392 */ 393 LDAPControl * 394 ldap_find_control( 395 LDAP_CONST char *oid, 396 LDAPControl **ctrls ) 397 { 398 if( ctrls == NULL || *ctrls == NULL ) { 399 return NULL; 400 } 401 402 for( ; *ctrls != NULL; ctrls++ ) { 403 if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) { 404 return *ctrls; 405 } 406 } 407 408 return NULL; 409 } 410 411 /* 412 * Find a LDAPControl 413 */ 414 LDAPControl * 415 ldap_control_find( 416 LDAP_CONST char *oid, 417 LDAPControl **ctrls, 418 LDAPControl ***nextctrlp ) 419 { 420 if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) { 421 return NULL; 422 } 423 424 for( ; *ctrls != NULL; ctrls++ ) { 425 if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) { 426 if ( nextctrlp != NULL ) { 427 *nextctrlp = ctrls + 1; 428 } 429 430 return *ctrls; 431 } 432 } 433 434 if ( nextctrlp != NULL ) { 435 *nextctrlp = NULL; 436 } 437 438 return NULL; 439 } 440 441 /* 442 * Create a LDAPControl, optionally from ber - deprecated 443 */ 444 int 445 ldap_create_control( 446 LDAP_CONST char *requestOID, 447 BerElement *ber, 448 int iscritical, 449 LDAPControl **ctrlp ) 450 { 451 LDAPControl *ctrl; 452 453 assert( requestOID != NULL ); 454 assert( ctrlp != NULL ); 455 456 ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); 457 if ( ctrl == NULL ) { 458 return LDAP_NO_MEMORY; 459 } 460 461 BER_BVZERO(&ctrl->ldctl_value); 462 if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) { 463 LDAP_FREE( ctrl ); 464 return LDAP_NO_MEMORY; 465 } 466 467 ctrl->ldctl_oid = LDAP_STRDUP( requestOID ); 468 ctrl->ldctl_iscritical = iscritical; 469 470 if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) { 471 ldap_control_free( ctrl ); 472 return LDAP_NO_MEMORY; 473 } 474 475 *ctrlp = ctrl; 476 return LDAP_SUCCESS; 477 } 478 479 /* 480 * Create a LDAPControl, optionally from value 481 */ 482 int 483 ldap_control_create( 484 LDAP_CONST char *requestOID, 485 int iscritical, 486 struct berval *value, 487 int dupval, 488 LDAPControl **ctrlp ) 489 { 490 LDAPControl *ctrl; 491 492 assert( requestOID != NULL ); 493 assert( ctrlp != NULL ); 494 495 ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 ); 496 if ( ctrl == NULL ) { 497 return LDAP_NO_MEMORY; 498 } 499 500 ctrl->ldctl_iscritical = iscritical; 501 if ( requestOID != NULL ) { 502 ctrl->ldctl_oid = LDAP_STRDUP( requestOID ); 503 if ( ctrl->ldctl_oid == NULL ) { 504 ldap_control_free( ctrl ); 505 return LDAP_NO_MEMORY; 506 } 507 } 508 509 if ( value && !BER_BVISNULL( value ) ) { 510 if ( dupval ) { 511 ber_dupbv( &ctrl->ldctl_value, value ); 512 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { 513 ldap_control_free( ctrl ); 514 return LDAP_NO_MEMORY; 515 } 516 517 } else { 518 ctrl->ldctl_value = *value; 519 } 520 } 521 522 *ctrlp = ctrl; 523 524 return LDAP_SUCCESS; 525 } 526 527 /* 528 * check for critical client controls and bitch if present 529 * if we ever support critical controls, we'll have to 530 * find a means for maintaining per API call control 531 * information. 532 */ 533 int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls ) 534 { 535 LDAPControl *const *c; 536 537 assert( ld != NULL ); 538 assert( LDAP_VALID( ld ) ); 539 540 if( ctrls == NULL ) { 541 /* use default client controls */ 542 ctrls = ld->ld_cctrls; 543 } 544 545 if( ctrls == NULL || *ctrls == NULL ) { 546 return LDAP_SUCCESS; 547 } 548 549 for( c = ctrls ; *c != NULL; c++ ) { 550 if( (*c)->ldctl_iscritical ) { 551 ld->ld_errno = LDAP_NOT_SUPPORTED; 552 return ld->ld_errno; 553 } 554 } 555 556 return LDAP_SUCCESS; 557 } 558