diff options
Diffstat (limited to 'libraries/libldap/controls.c')
-rw-r--r-- | libraries/libldap/controls.c | 552 |
1 files changed, 552 insertions, 0 deletions
diff --git a/libraries/libldap/controls.c b/libraries/libldap/controls.c new file mode 100644 index 0000000..184866d --- /dev/null +++ b/libraries/libldap/controls.c @@ -0,0 +1,552 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 1998-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* This notice applies to changes, created by or for Novell, Inc., + * to preexisting works for which notices appear elsewhere in this file. + * + * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. + * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION + * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT + * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE + * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS + * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC + * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE + * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + *--- + * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License + * can be found in the file "build/LICENSE-2.0.1" in this distribution + * of OpenLDAP Software. + */ + +#include "portable.h" + +#include <ac/stdlib.h> + +#include <ac/time.h> +#include <ac/string.h> + +#include "ldap-int.h" + +/* LDAPv3 Controls (RFC 4511) + * + * Controls ::= SEQUENCE OF control Control + * + * Control ::= SEQUENCE { + * controlType LDAPOID, + * criticality BOOLEAN DEFAULT FALSE, + * controlValue OCTET STRING OPTIONAL + * } + */ + +int +ldap_pvt_put_control( + const LDAPControl *c, + BerElement *ber ) +{ + if ( ber_printf( ber, "{s" /*}*/, c->ldctl_oid ) == -1 ) { + return LDAP_ENCODING_ERROR; + } + + if ( c->ldctl_iscritical /* only if true */ + && ( ber_printf( ber, "b", + (ber_int_t) c->ldctl_iscritical ) == -1 ) ) + { + return LDAP_ENCODING_ERROR; + } + + if ( !BER_BVISNULL( &c->ldctl_value ) /* only if we have a value */ + && ( ber_printf( ber, "O", &c->ldctl_value ) == -1 ) ) + { + return LDAP_ENCODING_ERROR; + } + + if ( ber_printf( ber, /*{*/"N}" ) == -1 ) { + return LDAP_ENCODING_ERROR; + } + + return LDAP_SUCCESS; +} + + +/* + * ldap_int_put_controls + */ + +int +ldap_int_put_controls( + LDAP *ld, + LDAPControl *const *ctrls, + BerElement *ber ) +{ + LDAPControl *const *c; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( ber != NULL ); + + if( ctrls == NULL ) { + /* use default server controls */ + ctrls = ld->ld_sctrls; + } + + if( ctrls == NULL || *ctrls == NULL ) { + return LDAP_SUCCESS; + } + + if ( ld->ld_version < LDAP_VERSION3 ) { + /* LDAPv2 doesn't support controls, + * error if any control is critical + */ + for( c = ctrls ; *c != NULL; c++ ) { + if( (*c)->ldctl_iscritical ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + } + + return LDAP_SUCCESS; + } + + /* Controls are encoded as a sequence of sequences */ + if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + return ld->ld_errno; + } + + for( c = ctrls ; *c != NULL; c++ ) { + ld->ld_errno = ldap_pvt_put_control( *c, ber ); + if ( ld->ld_errno != LDAP_SUCCESS ) { + return ld->ld_errno; + } + } + + + if( ber_printf( ber, /*{*/ "}" ) == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + return ld->ld_errno; + } + + return LDAP_SUCCESS; +} + +int ldap_pvt_get_controls( + BerElement *ber, + LDAPControl ***ctrls ) +{ + int nctrls; + ber_tag_t tag; + ber_len_t len; + char *opaque; + + assert( ber != NULL ); + + if( ctrls == NULL ) { + return LDAP_SUCCESS; + } + *ctrls = NULL; + + len = ber_pvt_ber_remaining( ber ); + + if( len == 0) { + /* no controls */ + return LDAP_SUCCESS; + } + + if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) { + if( tag == LBER_ERROR ) { + /* decoding error */ + return LDAP_DECODING_ERROR; + } + + /* ignore unexpected input */ + return LDAP_SUCCESS; + } + + /* set through each element */ + nctrls = 0; + *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) ); + + if( *ctrls == NULL ) { + return LDAP_NO_MEMORY; + } + + *ctrls[nctrls] = NULL; + + for( tag = ber_first_element( ber, &len, &opaque ); + tag != LBER_ERROR; + tag = ber_next_element( ber, &len, opaque ) ) + { + LDAPControl *tctrl; + LDAPControl **tctrls; + + tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) ); + + /* allocate pointer space for current controls (nctrls) + * + this control + extra NULL + */ + tctrls = (tctrl == NULL) ? NULL : + LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *)); + + if( tctrls == NULL ) { + /* one of the above allocation failed */ + + if( tctrl != NULL ) { + LDAP_FREE( tctrl ); + } + + ldap_controls_free(*ctrls); + *ctrls = NULL; + + return LDAP_NO_MEMORY; + } + + + tctrls[nctrls++] = tctrl; + tctrls[nctrls] = NULL; + + tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid ); + + if( tag == LBER_ERROR ) { + *ctrls = NULL; + ldap_controls_free( tctrls ); + return LDAP_DECODING_ERROR; + } + + tag = ber_peek_tag( ber, &len ); + + if( tag == LBER_BOOLEAN ) { + ber_int_t crit; + tag = ber_scanf( ber, "b", &crit ); + tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0; + tag = ber_peek_tag( ber, &len ); + } + + if( tag == LBER_OCTETSTRING ) { + tag = ber_scanf( ber, "o", &tctrl->ldctl_value ); + } else { + BER_BVZERO( &tctrl->ldctl_value ); + } + + *ctrls = tctrls; + } + + return LDAP_SUCCESS; +} + +/* + * Free a LDAPControl + */ +void +ldap_control_free( LDAPControl *c ) +{ + LDAP_MEMORY_DEBUG_ASSERT( c != NULL ); + + if ( c != NULL ) { + if( c->ldctl_oid != NULL) { + LDAP_FREE( c->ldctl_oid ); + } + + if( c->ldctl_value.bv_val != NULL ) { + LDAP_FREE( c->ldctl_value.bv_val ); + } + + LDAP_FREE( c ); + } +} + +/* + * Free an array of LDAPControl's + */ +void +ldap_controls_free( LDAPControl **controls ) +{ + LDAP_MEMORY_DEBUG_ASSERT( controls != NULL ); + + if ( controls != NULL ) { + int i; + + for( i=0; controls[i] != NULL; i++) { + ldap_control_free( controls[i] ); + } + + LDAP_FREE( controls ); + } +} + +/* + * Duplicate an array of LDAPControl + */ +LDAPControl ** +ldap_controls_dup( LDAPControl *const *controls ) +{ + LDAPControl **new; + int i; + + if ( controls == NULL ) { + return NULL; + } + + /* count the controls */ + for(i=0; controls[i] != NULL; i++) /* empty */ ; + + if( i < 1 ) { + /* no controls to duplicate */ + return NULL; + } + + new = (LDAPControl **) LDAP_MALLOC( (i+1) * sizeof(LDAPControl *) ); + + if( new == NULL ) { + /* memory allocation failure */ + return NULL; + } + + /* duplicate the controls */ + for(i=0; controls[i] != NULL; i++) { + new[i] = ldap_control_dup( controls[i] ); + + if( new[i] == NULL ) { + ldap_controls_free( new ); + return NULL; + } + } + + new[i] = NULL; + + return new; +} + +/* + * Duplicate a LDAPControl + */ +LDAPControl * +ldap_control_dup( const LDAPControl *c ) +{ + LDAPControl *new; + + if ( c == NULL || c->ldctl_oid == NULL ) { + return NULL; + } + + new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); + + if( new == NULL ) { + return NULL; + } + + new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid ); + + if(new->ldctl_oid == NULL) { + LDAP_FREE( new ); + return NULL; + } + + if( c->ldctl_value.bv_val != NULL ) { + new->ldctl_value.bv_val = + (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 ); + + if(new->ldctl_value.bv_val == NULL) { + if(new->ldctl_oid != NULL) { + LDAP_FREE( new->ldctl_oid ); + } + LDAP_FREE( new ); + return NULL; + } + + new->ldctl_value.bv_len = c->ldctl_value.bv_len; + + AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val, + c->ldctl_value.bv_len ); + + new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0'; + + } else { + new->ldctl_value.bv_len = 0; + new->ldctl_value.bv_val = NULL; + } + + new->ldctl_iscritical = c->ldctl_iscritical; + return new; +} + +/* + * Find a LDAPControl - deprecated + */ +LDAPControl * +ldap_find_control( + LDAP_CONST char *oid, + LDAPControl **ctrls ) +{ + if( ctrls == NULL || *ctrls == NULL ) { + return NULL; + } + + for( ; *ctrls != NULL; ctrls++ ) { + if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) { + return *ctrls; + } + } + + return NULL; +} + +/* + * Find a LDAPControl + */ +LDAPControl * +ldap_control_find( + LDAP_CONST char *oid, + LDAPControl **ctrls, + LDAPControl ***nextctrlp ) +{ + if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) { + return NULL; + } + + for( ; *ctrls != NULL; ctrls++ ) { + if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) { + if ( nextctrlp != NULL ) { + *nextctrlp = ctrls + 1; + } + + return *ctrls; + } + } + + if ( nextctrlp != NULL ) { + *nextctrlp = NULL; + } + + return NULL; +} + +/* + * Create a LDAPControl, optionally from ber - deprecated + */ +int +ldap_create_control( + LDAP_CONST char *requestOID, + BerElement *ber, + int iscritical, + LDAPControl **ctrlp ) +{ + LDAPControl *ctrl; + + assert( requestOID != NULL ); + assert( ctrlp != NULL ); + + ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) ); + if ( ctrl == NULL ) { + return LDAP_NO_MEMORY; + } + + BER_BVZERO(&ctrl->ldctl_value); + if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) { + LDAP_FREE( ctrl ); + return LDAP_NO_MEMORY; + } + + ctrl->ldctl_oid = LDAP_STRDUP( requestOID ); + ctrl->ldctl_iscritical = iscritical; + + if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) { + ldap_control_free( ctrl ); + return LDAP_NO_MEMORY; + } + + *ctrlp = ctrl; + return LDAP_SUCCESS; +} + +/* + * Create a LDAPControl, optionally from value + */ +int +ldap_control_create( + LDAP_CONST char *requestOID, + int iscritical, + struct berval *value, + int dupval, + LDAPControl **ctrlp ) +{ + LDAPControl *ctrl; + + assert( requestOID != NULL ); + assert( ctrlp != NULL ); + + ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 ); + if ( ctrl == NULL ) { + return LDAP_NO_MEMORY; + } + + ctrl->ldctl_iscritical = iscritical; + if ( requestOID != NULL ) { + ctrl->ldctl_oid = LDAP_STRDUP( requestOID ); + if ( ctrl->ldctl_oid == NULL ) { + ldap_control_free( ctrl ); + return LDAP_NO_MEMORY; + } + } + + if ( value && !BER_BVISNULL( value ) ) { + if ( dupval ) { + ber_dupbv( &ctrl->ldctl_value, value ); + if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { + ldap_control_free( ctrl ); + return LDAP_NO_MEMORY; + } + + } else { + ctrl->ldctl_value = *value; + } + } + + *ctrlp = ctrl; + + return LDAP_SUCCESS; +} + +/* + * check for critical client controls and bitch if present + * if we ever support critical controls, we'll have to + * find a means for maintaining per API call control + * information. + */ +int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls ) +{ + LDAPControl *const *c; + + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + + if( ctrls == NULL ) { + /* use default client controls */ + ctrls = ld->ld_cctrls; + } + + if( ctrls == NULL || *ctrls == NULL ) { + return LDAP_SUCCESS; + } + + for( c = ctrls ; *c != NULL; c++ ) { + if( (*c)->ldctl_iscritical ) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + } + + return LDAP_SUCCESS; +} |