Home | History | Annotate | Line # | Download | only in libldap
      1 /*	$NetBSD: deref.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  * Portions Copyright 2008 Pierangelo Masarati.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* ACKNOWLEDGEMENTS:
     19  * This work was initially developed by Pierangelo Masarati
     20  * for inclusion in OpenLDAP Software.
     21  */
     22 
     23 #include <sys/cdefs.h>
     24 __RCSID("$NetBSD: deref.c,v 1.4 2025/09/05 21:16:21 christos Exp $");
     25 
     26 #include "portable.h"
     27 
     28 #include <stdio.h>
     29 #include <ac/stdlib.h>
     30 #include <ac/string.h>
     31 #include <ac/time.h>
     32 
     33 #include "ldap-int.h"
     34 
     35 int
     36 ldap_create_deref_control_value(
     37 	LDAP		*ld,
     38 	LDAPDerefSpec	*ds,
     39 	struct berval	*value )
     40 {
     41 	BerElement	*ber = NULL;
     42 	ber_tag_t	tag;
     43 	int		i;
     44 
     45 	if ( ld == NULL || value == NULL || ds == NULL )
     46 	{
     47 		if ( ld )
     48 			ld->ld_errno = LDAP_PARAM_ERROR;
     49 		return LDAP_PARAM_ERROR;
     50 	}
     51 
     52 	assert( LDAP_VALID( ld ) );
     53 
     54 	value->bv_val = NULL;
     55 	value->bv_len = 0;
     56 	ld->ld_errno = LDAP_SUCCESS;
     57 
     58 	ber = ldap_alloc_ber_with_options( ld );
     59 	if ( ber == NULL ) {
     60 		ld->ld_errno = LDAP_NO_MEMORY;
     61 		return ld->ld_errno;
     62 	}
     63 
     64 	tag = ber_printf( ber, "{" /*}*/ );
     65 	if ( tag == LBER_ERROR ) {
     66 		ld->ld_errno = LDAP_ENCODING_ERROR;
     67 		goto done;
     68 	}
     69 
     70 	for ( i = 0; ds[i].derefAttr != NULL; i++ ) {
     71 		int j;
     72 
     73 		tag = ber_printf( ber, "{s{" /*}}*/ , ds[i].derefAttr );
     74 		if ( tag == LBER_ERROR ) {
     75 			ld->ld_errno = LDAP_ENCODING_ERROR;
     76 			goto done;
     77 		}
     78 
     79 		for ( j = 0; ds[i].attributes[j] != NULL; j++ ) {
     80 			tag = ber_printf( ber, "s", ds[i].attributes[ j ] );
     81 			if ( tag == LBER_ERROR ) {
     82 				ld->ld_errno = LDAP_ENCODING_ERROR;
     83 				goto done;
     84 			}
     85 		}
     86 
     87 		tag = ber_printf( ber, /*{{*/ "}N}" );
     88 		if ( tag == LBER_ERROR ) {
     89 			ld->ld_errno = LDAP_ENCODING_ERROR;
     90 			goto done;
     91 		}
     92 	}
     93 
     94 	tag = ber_printf( ber, /*{*/ "}" );
     95 	if ( tag == LBER_ERROR ) {
     96 		ld->ld_errno = LDAP_ENCODING_ERROR;
     97 		goto done;
     98 	}
     99 
    100 	if ( ber_flatten2( ber, value, 1 ) == -1 ) {
    101 		ld->ld_errno = LDAP_NO_MEMORY;
    102 	}
    103 
    104 done:;
    105 	if ( ber != NULL ) {
    106 		ber_free( ber, 1 );
    107 	}
    108 
    109 	return ld->ld_errno;
    110 }
    111 
    112 int
    113 ldap_create_deref_control(
    114 	LDAP		*ld,
    115 	LDAPDerefSpec	*ds,
    116 	int		iscritical,
    117 	LDAPControl	**ctrlp )
    118 {
    119 	struct berval	value;
    120 
    121 	if ( ctrlp == NULL ) {
    122 		ld->ld_errno = LDAP_PARAM_ERROR;
    123 		return ld->ld_errno;
    124 	}
    125 
    126 	ld->ld_errno = ldap_create_deref_control_value( ld, ds, &value );
    127 	if ( ld->ld_errno == LDAP_SUCCESS ) {
    128 		ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_DEREF,
    129 			iscritical, &value, 0, ctrlp );
    130 		if ( ld->ld_errno != LDAP_SUCCESS ) {
    131 			LDAP_FREE( value.bv_val );
    132 		}
    133 	}
    134 
    135 	return ld->ld_errno;
    136 }
    137 
    138 void
    139 ldap_derefresponse_free( LDAPDerefRes *dr )
    140 {
    141 	for ( ; dr; ) {
    142 		LDAPDerefRes *drnext = dr->next;
    143 		LDAPDerefVal *dv;
    144 
    145 		LDAP_FREE( dr->derefAttr );
    146 		LDAP_FREE( dr->derefVal.bv_val );
    147 
    148 		for ( dv = dr->attrVals; dv; ) {
    149 			LDAPDerefVal *dvnext = dv->next;
    150 			LDAP_FREE( dv->type );
    151 			ber_bvarray_free( dv->vals );
    152 			LDAP_FREE( dv );
    153 			dv = dvnext;
    154 		}
    155 
    156 		LDAP_FREE( dr );
    157 
    158 		dr = drnext;
    159 	}
    160 }
    161 
    162 int
    163 ldap_parse_derefresponse_control(
    164 	LDAP		*ld,
    165 	LDAPControl	*ctrl,
    166 	LDAPDerefRes	**drp2 )
    167 {
    168 	BerElementBuffer berbuf;
    169 	BerElement *ber = (BerElement *)&berbuf;
    170 	ber_tag_t tag;
    171 	ber_len_t len;
    172 	char *last;
    173 	LDAPDerefRes *drhead = NULL, **drp;
    174 
    175 	if ( ld == NULL || ctrl == NULL || drp2 == NULL ) {
    176 		if ( ld )
    177 			ld->ld_errno = LDAP_PARAM_ERROR;
    178 		return LDAP_PARAM_ERROR;
    179 	}
    180 
    181 	/* Set up a BerElement from the berval returned in the control. */
    182 	ber_init2( ber, &ctrl->ldctl_value, 0 );
    183 
    184 	/* Extract the count and cookie from the control. */
    185 	drp = &drhead;
    186 	for ( tag = ber_first_element( ber, &len, &last );
    187 		tag != LBER_DEFAULT;
    188 		tag = ber_next_element( ber, &len, last ) )
    189 	{
    190 		LDAPDerefRes *dr;
    191 		LDAPDerefVal **dvp;
    192 		char *last2;
    193 
    194 		dr = LDAP_CALLOC( 1, sizeof(LDAPDerefRes) );
    195 		if ( dr == NULL ) {
    196 			ldap_derefresponse_free( drhead );
    197 			*drp2 = NULL;
    198 			ld->ld_errno = LDAP_NO_MEMORY;
    199 			return ld->ld_errno;
    200 		}
    201 		dvp = &dr->attrVals;
    202 
    203 		tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal );
    204 		if ( tag == LBER_ERROR ) {
    205 			goto done;
    206 		}
    207 
    208 		tag = ber_peek_tag( ber, &len );
    209 		if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) {
    210 			for ( tag = ber_first_element( ber, &len, &last2 );
    211 				tag != LBER_DEFAULT;
    212 				tag = ber_next_element( ber, &len, last2 ) )
    213 			{
    214 				LDAPDerefVal *dv;
    215 
    216 				dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) );
    217 				if ( dv == NULL ) {
    218 					ldap_derefresponse_free( drhead );
    219 					LDAP_FREE( dr );
    220 					*drp2 = NULL;
    221 					ld->ld_errno = LDAP_NO_MEMORY;
    222 					return ld->ld_errno;
    223 				}
    224 
    225 				tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals );
    226 				if ( tag == LBER_ERROR ) {
    227 					goto done;
    228 				}
    229 
    230 				*dvp = dv;
    231 				dvp = &dv->next;
    232 			}
    233 		}
    234 
    235 		tag = ber_scanf( ber, "}" );
    236 		if ( tag == LBER_ERROR ) {
    237 			goto done;
    238 		}
    239 
    240 		*drp = dr;
    241 		drp = &dr->next;
    242 	}
    243 
    244 	tag = 0;
    245 
    246 done:;
    247 	if ( tag == LBER_ERROR ) {
    248 		if ( drhead != NULL ) {
    249 			ldap_derefresponse_free( drhead );
    250 		}
    251 
    252 		*drp2 = NULL;
    253 		ld->ld_errno = LDAP_DECODING_ERROR;
    254 
    255 	} else {
    256 		*drp2 = drhead;
    257 		ld->ld_errno = LDAP_SUCCESS;
    258 	}
    259 
    260 	return ld->ld_errno;
    261 }
    262 
    263 int
    264 ldap_parse_deref_control(
    265 	LDAP		*ld,
    266 	LDAPControl	**ctrls,
    267 	LDAPDerefRes	**drp )
    268 {
    269 	LDAPControl *c;
    270 
    271 	if ( drp == NULL ) {
    272 		ld->ld_errno = LDAP_PARAM_ERROR;
    273 		return ld->ld_errno;
    274 	}
    275 
    276 	*drp = NULL;
    277 
    278 	if ( ctrls == NULL ) {
    279 		ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
    280 		return ld->ld_errno;
    281 	}
    282 
    283 	c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL );
    284 	if ( c == NULL ) {
    285 		/* No deref control was found. */
    286 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
    287 		return ld->ld_errno;
    288 	}
    289 
    290 	ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp );
    291 
    292 	return ld->ld_errno;
    293 }
    294 
    295