Home | History | Annotate | Line # | Download | only in libldap
      1 /*	$NetBSD: controls.c,v 1.4 2025/09/05 21:16:21 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2024 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.4 2025/09/05 21:16:21 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