#include "ldap-int.h"
static LDAPControl *ldap_control_dup( LDAPControl *ctrl );
static int ldap_control_copy_contents( LDAPControl *ctrl_dst,
LDAPControl *ctrl_src );
int
nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq,
BerElement *ber )
{
LDAPControl *c;
int rc, i;
rc = LDAP_ENCODING_ERROR;
LDAP_MUTEX_LOCK( ld, LDAP_CTRL_LOCK );
if ( ctrls == NULL ) {
ctrls = ld->ld_servercontrols;
}
if ( ctrls == NULL || ctrls[ 0 ] == NULL ) {
goto clean_exit;
}
if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
for ( i = 0; ctrls != NULL && ctrls[i] != NULL; i++ ) {
if ( ctrls[i]->ldctl_iscritical ) {
rc = LDAP_NOT_SUPPORTED;
goto error_exit;
}
}
goto clean_exit;
}
if ( ber_printf( ber, "t{", LDAP_TAG_CONTROLS ) == -1 ) {
goto error_exit;
}
for ( i = 0; ctrls[i] != NULL; i++ ) {
c = ctrls[i];
if ( ber_printf( ber, "{s", c->ldctl_oid ) == -1 ) {
goto error_exit;
}
if ( c->ldctl_iscritical ) {
if ( ber_printf( ber, "b", (int)c->ldctl_iscritical )
== -1 ) {
goto error_exit;
}
}
if ( c->ldctl_value.bv_val != NULL ) {
if ( ber_printf( ber, "o", c->ldctl_value.bv_val,
(int)c->ldctl_value.bv_len )
== -1 ) {
goto error_exit;
}
}
if ( ber_put_seq( ber ) == -1 ) {
goto error_exit;
}
}
if ( ber_put_seq( ber ) == -1 ) {
goto error_exit;
}
clean_exit:
LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
if ( closeseq && ber_put_seq( ber ) == -1 ) {
goto error_exit;
}
return( LDAP_SUCCESS );
error_exit:
LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
return( rc );
}
int
nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp )
{
LDAPControl *newctrl;
ber_tag_t tag;
ber_len_t len;
int rc, maxcontrols, curcontrols;
char *last;
LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_get_controls\n", 0, 0, 0 );
*controlsp = NULL;
if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
return( LDAP_DECODING_ERROR );
}
if ( len == 0 ) {
LDAPDebug( LDAP_DEBUG_TRACE,
"<= nsldapi_get_controls no controls\n", 0, 0, 0 );
return( LDAP_SUCCESS );
}
if (( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
if ( tag == LBER_ERROR ) {
LDAPDebug( LDAP_DEBUG_TRACE,
"<= nsldapi_get_controls LDAP_PROTOCOL_ERROR\n",
0, 0, 0 );
return( LDAP_DECODING_ERROR );
}
LDAPDebug( LDAP_DEBUG_TRACE,
"<= nsldapi_get_controls ignoring unrecognized data in message (tag 0x%x)\n",
tag, 0, 0 );
return( LDAP_SUCCESS );
}
maxcontrols = curcontrols = 0;
for ( tag = ber_first_element( ber, &len, &last );
tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
tag = ber_next_element( ber, &len, last ) ) {
if ( curcontrols >= maxcontrols - 1 ) {
#define CONTROL_GRABSIZE 5
maxcontrols += CONTROL_GRABSIZE;
*controlsp = (struct ldapcontrol **)NSLDAPI_REALLOC(
(char *)*controlsp, maxcontrols *
sizeof(struct ldapcontrol *) );
if ( *controlsp == NULL ) {
rc = LDAP_NO_MEMORY;
goto free_and_return;
}
}
if (( newctrl = (struct ldapcontrol *)NSLDAPI_CALLOC( 1,
sizeof(LDAPControl))) == NULL ) {
rc = LDAP_NO_MEMORY;
goto free_and_return;
}
(*controlsp)[curcontrols++] = newctrl;
(*controlsp)[curcontrols] = NULL;
if ( ber_scanf( ber, "{a", &newctrl->ldctl_oid )
== LBER_ERROR ) {
rc = LDAP_DECODING_ERROR;
goto free_and_return;
}
if ( ber_peek_tag( ber, &len ) == LBER_BOOLEAN ) {
int aint;
if ( ber_scanf( ber, "b", &aint ) == LBER_ERROR ) {
rc = LDAP_DECODING_ERROR;
goto free_and_return;
}
newctrl->ldctl_iscritical = (char)aint;
} else {
newctrl->ldctl_iscritical = 0;
}
if ( ber_peek_tag( ber, &len ) == LBER_OCTETSTRING ) {
if ( ber_scanf( ber, "o", &newctrl->ldctl_value )
== LBER_ERROR ) {
rc = LDAP_DECODING_ERROR;
goto free_and_return;
}
} else {
(newctrl->ldctl_value).bv_val = NULL;
(newctrl->ldctl_value).bv_len = 0;
}
}
if ( tag == LBER_ERROR ) {
rc = LDAP_DECODING_ERROR;
goto free_and_return;
}
LDAPDebug( LDAP_DEBUG_TRACE,
"<= nsldapi_get_controls found %d controls\n", curcontrols, 0, 0 );
return( LDAP_SUCCESS );
free_and_return:;
ldap_controls_free( *controlsp );
*controlsp = NULL;
LDAPDebug( LDAP_DEBUG_TRACE,
"<= nsldapi_get_controls error 0x%x\n", rc, 0, 0 );
return( rc );
}
void
LDAP_CALL
ldap_control_free( LDAPControl *ctrl )
{
if ( ctrl != NULL ) {
if ( ctrl->ldctl_oid != NULL ) {
NSLDAPI_FREE( ctrl->ldctl_oid );
}
if ( ctrl->ldctl_value.bv_val != NULL ) {
NSLDAPI_FREE( ctrl->ldctl_value.bv_val );
}
NSLDAPI_FREE( (char *)ctrl );
}
}
void
LDAP_CALL
ldap_controls_free( LDAPControl **ctrls )
{
int i;
if ( ctrls != NULL ) {
for ( i = 0; ctrls[i] != NULL; i++ ) {
ldap_control_free( ctrls[i] );
}
NSLDAPI_FREE( (char *)ctrls );
}
}
#if 0
LDAPControl **
LDAP_CALL
ldap_control_append( LDAPControl **ctrl_src, LDAPControl *ctrl )
{
int nctrls = 0;
LDAPControl **ctrlp;
int i;
if ( NULL == ctrl )
return ( NULL );
if ( NULL != ctrl_src ) {
while( NULL != ctrl_src[nctrls] ) {
nctrls++;
}
}
if ( ( ctrlp = (LDAPControl **)NSLDAPI_MALLOC( sizeof(LDAPControl *)
* (nctrls + 2) ) ) == NULL ) {
return( NULL );
}
memset( ctrlp, 0, sizeof(*ctrlp) * (nctrls + 2) );
for( i = 0; i < (nctrls + 1); i++ ) {
if ( i < nctrls ) {
ctrlp[i] = ldap_control_dup( ctrl_src[i] );
} else {
ctrlp[i] = ldap_control_dup( ctrl );
}
if ( NULL == ctrlp[i] ) {
ldap_controls_free( ctrlp );
return( NULL );
}
}
return ctrlp;
}
#endif
int
nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls, LDAPControl **newctrls )
{
int count;
if ( *ldctrls != NULL ) {
ldap_controls_free( *ldctrls );
}
if ( newctrls == NULL || newctrls[0] == NULL ) {
*ldctrls = NULL;
return( 0 );
}
for ( count = 0; newctrls[ count ] != NULL; ++count ) {
;
}
if (( *ldctrls = (LDAPControl **)NSLDAPI_MALLOC(( count + 1 ) *
sizeof( LDAPControl *))) == NULL ) {
LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
return( -1 );
}
(*ldctrls)[ count ] = NULL;
for ( count = 0; newctrls[ count ] != NULL; ++count ) {
if (( (*ldctrls)[ count ] =
ldap_control_dup( newctrls[ count ] )) == NULL ) {
ldap_controls_free( *ldctrls );
*ldctrls = NULL;
LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
return( -1 );
}
}
return( 0 );
}
static LDAPControl *
ldap_control_dup( LDAPControl *ctrl )
{
LDAPControl *rctrl;
if (( rctrl = (LDAPControl *)NSLDAPI_MALLOC( sizeof( LDAPControl )))
== NULL ) {
return( NULL );
}
if ( ldap_control_copy_contents( rctrl, ctrl ) != LDAP_SUCCESS ) {
NSLDAPI_FREE( rctrl );
return( NULL );
}
return( rctrl );
}
static int
ldap_control_copy_contents( LDAPControl *ctrl_dst, LDAPControl *ctrl_src )
{
size_t len;
if ( NULL == ctrl_dst || NULL == ctrl_src ) {
return( LDAP_PARAM_ERROR );
}
ctrl_dst->ldctl_iscritical = ctrl_src->ldctl_iscritical;
if (( ctrl_dst->ldctl_oid = nsldapi_strdup( ctrl_src->ldctl_oid ))
== NULL ) {
return( LDAP_NO_MEMORY );
}
len = (size_t)(ctrl_src->ldctl_value).bv_len;
if ( ctrl_src->ldctl_value.bv_val == NULL || len <= 0 ) {
ctrl_dst->ldctl_value.bv_len = 0;
ctrl_dst->ldctl_value.bv_val = NULL;
} else {
ctrl_dst->ldctl_value.bv_len = len;
if (( ctrl_dst->ldctl_value.bv_val = NSLDAPI_MALLOC( len ))
== NULL ) {
NSLDAPI_FREE( ctrl_dst->ldctl_oid );
return( LDAP_NO_MEMORY );
}
SAFEMEMCPY( ctrl_dst->ldctl_value.bv_val,
ctrl_src->ldctl_value.bv_val, len );
}
return ( LDAP_SUCCESS );
}
int
nsldapi_build_control( char *oid, BerElement *ber, int freeber, char iscritical,
LDAPControl **ctrlp )
{
int rc;
struct berval *bvp;
if ( ber == NULL ) {
bvp = NULL;
} else {
rc = ber_flatten( ber, &bvp );
if ( freeber ) {
ber_free( ber, 1 );
}
if ( rc == -1 ) {
return( LDAP_NO_MEMORY );
}
}
if (( *ctrlp = (LDAPControl *)NSLDAPI_MALLOC( sizeof(LDAPControl)))
== NULL ) {
if ( bvp != NULL ) {
ber_bvfree( bvp );
}
return( LDAP_NO_MEMORY );
}
(*ctrlp)->ldctl_iscritical = iscritical;
if (( (*ctrlp)->ldctl_oid = nsldapi_strdup( oid )) == NULL ) {
NSLDAPI_FREE( *ctrlp );
if ( bvp != NULL ) {
ber_bvfree( bvp );
}
return( LDAP_NO_MEMORY );
}
if ( bvp == NULL ) {
(*ctrlp)->ldctl_value.bv_len = 0;
(*ctrlp)->ldctl_value.bv_val = NULL;
} else {
(*ctrlp)->ldctl_value = *bvp;
NSLDAPI_FREE( bvp );
}
return( LDAP_SUCCESS );
}