xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/deref.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: deref.c,v 1.3 2021/08/14 16:14:55 christos Exp $	*/
24e6df137Slukem 
3d11b170bStron /* $OpenLDAP$ */
44e6df137Slukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
54e6df137Slukem  *
6*549b59edSchristos  * Copyright 1998-2021 The OpenLDAP Foundation.
74e6df137Slukem  * Portions Copyright 2008 Pierangelo Masarati.
84e6df137Slukem  * All rights reserved.
94e6df137Slukem  *
104e6df137Slukem  * Redistribution and use in source and binary forms, with or without
114e6df137Slukem  * modification, are permitted only as authorized by the OpenLDAP
124e6df137Slukem  * Public License.
134e6df137Slukem  *
144e6df137Slukem  * A copy of this license is available in the file LICENSE in the
154e6df137Slukem  * top-level directory of the distribution or, alternatively, at
164e6df137Slukem  * <http://www.OpenLDAP.org/license.html>.
174e6df137Slukem  */
184e6df137Slukem /* ACKNOWLEDGEMENTS:
194e6df137Slukem  * This work was initially developed by Pierangelo Masarati
204e6df137Slukem  * for inclusion in OpenLDAP Software.
214e6df137Slukem  */
224e6df137Slukem 
23376af7d7Schristos #include <sys/cdefs.h>
24*549b59edSchristos __RCSID("$NetBSD: deref.c,v 1.3 2021/08/14 16:14:55 christos Exp $");
25376af7d7Schristos 
264e6df137Slukem #include "portable.h"
274e6df137Slukem 
284e6df137Slukem #include <stdio.h>
294e6df137Slukem #include <ac/stdlib.h>
304e6df137Slukem #include <ac/string.h>
314e6df137Slukem #include <ac/time.h>
324e6df137Slukem 
334e6df137Slukem #include "ldap-int.h"
344e6df137Slukem 
354e6df137Slukem int
ldap_create_deref_control_value(LDAP * ld,LDAPDerefSpec * ds,struct berval * value)364e6df137Slukem ldap_create_deref_control_value(
374e6df137Slukem 	LDAP		*ld,
384e6df137Slukem 	LDAPDerefSpec	*ds,
394e6df137Slukem 	struct berval	*value )
404e6df137Slukem {
414e6df137Slukem 	BerElement	*ber = NULL;
424e6df137Slukem 	ber_tag_t	tag;
434e6df137Slukem 	int		i;
444e6df137Slukem 
454e6df137Slukem 	if ( ld == NULL || value == NULL || ds == NULL )
464e6df137Slukem 	{
474e6df137Slukem 		if ( ld )
484e6df137Slukem 			ld->ld_errno = LDAP_PARAM_ERROR;
494e6df137Slukem 		return LDAP_PARAM_ERROR;
504e6df137Slukem 	}
514e6df137Slukem 
524e6df137Slukem 	assert( LDAP_VALID( ld ) );
534e6df137Slukem 
544e6df137Slukem 	value->bv_val = NULL;
554e6df137Slukem 	value->bv_len = 0;
564e6df137Slukem 	ld->ld_errno = LDAP_SUCCESS;
574e6df137Slukem 
584e6df137Slukem 	ber = ldap_alloc_ber_with_options( ld );
594e6df137Slukem 	if ( ber == NULL ) {
604e6df137Slukem 		ld->ld_errno = LDAP_NO_MEMORY;
614e6df137Slukem 		return ld->ld_errno;
624e6df137Slukem 	}
634e6df137Slukem 
644e6df137Slukem 	tag = ber_printf( ber, "{" /*}*/ );
654e6df137Slukem 	if ( tag == LBER_ERROR ) {
664e6df137Slukem 		ld->ld_errno = LDAP_ENCODING_ERROR;
674e6df137Slukem 		goto done;
684e6df137Slukem 	}
694e6df137Slukem 
704e6df137Slukem 	for ( i = 0; ds[i].derefAttr != NULL; i++ ) {
714e6df137Slukem 		int j;
724e6df137Slukem 
734e6df137Slukem 		tag = ber_printf( ber, "{s{" /*}}*/ , ds[i].derefAttr );
744e6df137Slukem 		if ( tag == LBER_ERROR ) {
754e6df137Slukem 			ld->ld_errno = LDAP_ENCODING_ERROR;
764e6df137Slukem 			goto done;
774e6df137Slukem 		}
784e6df137Slukem 
794e6df137Slukem 		for ( j = 0; ds[i].attributes[j] != NULL; j++ ) {
804e6df137Slukem 			tag = ber_printf( ber, "s", ds[i].attributes[ j ] );
814e6df137Slukem 			if ( tag == LBER_ERROR ) {
824e6df137Slukem 				ld->ld_errno = LDAP_ENCODING_ERROR;
834e6df137Slukem 				goto done;
844e6df137Slukem 			}
854e6df137Slukem 		}
864e6df137Slukem 
874e6df137Slukem 		tag = ber_printf( ber, /*{{*/ "}N}" );
884e6df137Slukem 		if ( tag == LBER_ERROR ) {
894e6df137Slukem 			ld->ld_errno = LDAP_ENCODING_ERROR;
904e6df137Slukem 			goto done;
914e6df137Slukem 		}
924e6df137Slukem 	}
934e6df137Slukem 
944e6df137Slukem 	tag = ber_printf( ber, /*{*/ "}" );
954e6df137Slukem 	if ( tag == LBER_ERROR ) {
964e6df137Slukem 		ld->ld_errno = LDAP_ENCODING_ERROR;
974e6df137Slukem 		goto done;
984e6df137Slukem 	}
994e6df137Slukem 
1004e6df137Slukem 	if ( ber_flatten2( ber, value, 1 ) == -1 ) {
1014e6df137Slukem 		ld->ld_errno = LDAP_NO_MEMORY;
1024e6df137Slukem 	}
1034e6df137Slukem 
1044e6df137Slukem done:;
1054e6df137Slukem 	if ( ber != NULL ) {
1064e6df137Slukem 		ber_free( ber, 1 );
1074e6df137Slukem 	}
1084e6df137Slukem 
1094e6df137Slukem 	return ld->ld_errno;
1104e6df137Slukem }
1114e6df137Slukem 
1124e6df137Slukem int
ldap_create_deref_control(LDAP * ld,LDAPDerefSpec * ds,int iscritical,LDAPControl ** ctrlp)1134e6df137Slukem ldap_create_deref_control(
1144e6df137Slukem 	LDAP		*ld,
1154e6df137Slukem 	LDAPDerefSpec	*ds,
1164e6df137Slukem 	int		iscritical,
1174e6df137Slukem 	LDAPControl	**ctrlp )
1184e6df137Slukem {
1194e6df137Slukem 	struct berval	value;
1204e6df137Slukem 
1214e6df137Slukem 	if ( ctrlp == NULL ) {
1224e6df137Slukem 		ld->ld_errno = LDAP_PARAM_ERROR;
1234e6df137Slukem 		return ld->ld_errno;
1244e6df137Slukem 	}
1254e6df137Slukem 
1264e6df137Slukem 	ld->ld_errno = ldap_create_deref_control_value( ld, ds, &value );
1274e6df137Slukem 	if ( ld->ld_errno == LDAP_SUCCESS ) {
128d11b170bStron 		ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_DEREF,
1294e6df137Slukem 			iscritical, &value, 0, ctrlp );
1304e6df137Slukem 		if ( ld->ld_errno != LDAP_SUCCESS ) {
1314e6df137Slukem 			LDAP_FREE( value.bv_val );
1324e6df137Slukem 		}
1334e6df137Slukem 	}
1344e6df137Slukem 
1354e6df137Slukem 	return ld->ld_errno;
1364e6df137Slukem }
1374e6df137Slukem 
1384e6df137Slukem void
ldap_derefresponse_free(LDAPDerefRes * dr)1394e6df137Slukem ldap_derefresponse_free( LDAPDerefRes *dr )
1404e6df137Slukem {
1414e6df137Slukem 	for ( ; dr; ) {
1424e6df137Slukem 		LDAPDerefRes *drnext = dr->next;
1434e6df137Slukem 		LDAPDerefVal *dv;
1444e6df137Slukem 
1454e6df137Slukem 		LDAP_FREE( dr->derefAttr );
1464e6df137Slukem 		LDAP_FREE( dr->derefVal.bv_val );
1474e6df137Slukem 
1484e6df137Slukem 		for ( dv = dr->attrVals; dv; ) {
1494e6df137Slukem 			LDAPDerefVal *dvnext = dv->next;
1504e6df137Slukem 			LDAP_FREE( dv->type );
1514e6df137Slukem 			ber_bvarray_free( dv->vals );
1524e6df137Slukem 			LDAP_FREE( dv );
1534e6df137Slukem 			dv = dvnext;
1544e6df137Slukem 		}
1554e6df137Slukem 
1564e6df137Slukem 		LDAP_FREE( dr );
1574e6df137Slukem 
1584e6df137Slukem 		dr = drnext;
1594e6df137Slukem 	}
1604e6df137Slukem }
1614e6df137Slukem 
1624e6df137Slukem int
ldap_parse_derefresponse_control(LDAP * ld,LDAPControl * ctrl,LDAPDerefRes ** drp2)1634e6df137Slukem ldap_parse_derefresponse_control(
1644e6df137Slukem 	LDAP		*ld,
1654e6df137Slukem 	LDAPControl	*ctrl,
1664e6df137Slukem 	LDAPDerefRes	**drp2 )
1674e6df137Slukem {
1684e6df137Slukem 	BerElement *ber;
1694e6df137Slukem 	ber_tag_t tag;
1704e6df137Slukem 	ber_len_t len;
1714e6df137Slukem 	char *last;
1724e6df137Slukem 	LDAPDerefRes *drhead = NULL, **drp;
1734e6df137Slukem 
1744e6df137Slukem 	if ( ld == NULL || ctrl == NULL || drp2 == NULL ) {
1754e6df137Slukem 		if ( ld )
1764e6df137Slukem 			ld->ld_errno = LDAP_PARAM_ERROR;
1774e6df137Slukem 		return LDAP_PARAM_ERROR;
1784e6df137Slukem 	}
1794e6df137Slukem 
1804e6df137Slukem 	/* Create a BerElement from the berval returned in the control. */
1814e6df137Slukem 	ber = ber_init( &ctrl->ldctl_value );
1824e6df137Slukem 
1834e6df137Slukem 	if ( ber == NULL ) {
1844e6df137Slukem 		ld->ld_errno = LDAP_NO_MEMORY;
1854e6df137Slukem 		return ld->ld_errno;
1864e6df137Slukem 	}
1874e6df137Slukem 
1884e6df137Slukem 	/* Extract the count and cookie from the control. */
1894e6df137Slukem 	drp = &drhead;
1904e6df137Slukem 	for ( tag = ber_first_element( ber, &len, &last );
1914e6df137Slukem 		tag != LBER_DEFAULT;
1924e6df137Slukem 		tag = ber_next_element( ber, &len, last ) )
1934e6df137Slukem 	{
1944e6df137Slukem 		LDAPDerefRes *dr;
1954e6df137Slukem 		LDAPDerefVal **dvp;
1964e6df137Slukem 		char *last2;
1974e6df137Slukem 
1984e6df137Slukem 		dr = LDAP_CALLOC( 1, sizeof(LDAPDerefRes) );
199*549b59edSchristos 		if ( dr == NULL ) {
200*549b59edSchristos 			ldap_derefresponse_free( drhead );
201*549b59edSchristos 			*drp2 = NULL;
202*549b59edSchristos 			ld->ld_errno = LDAP_NO_MEMORY;
203*549b59edSchristos 			return ld->ld_errno;
204*549b59edSchristos 		}
2054e6df137Slukem 		dvp = &dr->attrVals;
2064e6df137Slukem 
2074e6df137Slukem 		tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal );
2084e6df137Slukem 		if ( tag == LBER_ERROR ) {
2094e6df137Slukem 			goto done;
2104e6df137Slukem 		}
2114e6df137Slukem 
2124e6df137Slukem 		tag = ber_peek_tag( ber, &len );
2134e6df137Slukem 		if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) {
2144e6df137Slukem 			for ( tag = ber_first_element( ber, &len, &last2 );
2154e6df137Slukem 				tag != LBER_DEFAULT;
2164e6df137Slukem 				tag = ber_next_element( ber, &len, last2 ) )
2174e6df137Slukem 			{
2184e6df137Slukem 				LDAPDerefVal *dv;
2194e6df137Slukem 
2204e6df137Slukem 				dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) );
221*549b59edSchristos 				if ( dv == NULL ) {
222*549b59edSchristos 					ldap_derefresponse_free( drhead );
223*549b59edSchristos 					LDAP_FREE( dr );
224*549b59edSchristos 					*drp2 = NULL;
225*549b59edSchristos 					ld->ld_errno = LDAP_NO_MEMORY;
226*549b59edSchristos 					return ld->ld_errno;
227*549b59edSchristos 				}
2284e6df137Slukem 
2294e6df137Slukem 				tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals );
2304e6df137Slukem 				if ( tag == LBER_ERROR ) {
2314e6df137Slukem 					goto done;
2324e6df137Slukem 				}
2334e6df137Slukem 
2344e6df137Slukem 				*dvp = dv;
2354e6df137Slukem 				dvp = &dv->next;
2364e6df137Slukem 			}
2374e6df137Slukem 		}
2384e6df137Slukem 
2394e6df137Slukem 		tag = ber_scanf( ber, "}" );
2404e6df137Slukem 		if ( tag == LBER_ERROR ) {
2414e6df137Slukem 			goto done;
2424e6df137Slukem 		}
2434e6df137Slukem 
2444e6df137Slukem 		*drp = dr;
2454e6df137Slukem 		drp = &dr->next;
2464e6df137Slukem 	}
2474e6df137Slukem 
2484e6df137Slukem 	tag = 0;
2494e6df137Slukem 
2504e6df137Slukem done:;
2514e6df137Slukem         ber_free( ber, 1 );
2524e6df137Slukem 
2534e6df137Slukem 	if ( tag == LBER_ERROR ) {
2544e6df137Slukem 		if ( drhead != NULL ) {
2554e6df137Slukem 			ldap_derefresponse_free( drhead );
2564e6df137Slukem 		}
2574e6df137Slukem 
2584e6df137Slukem 		*drp2 = NULL;
2594e6df137Slukem 		ld->ld_errno = LDAP_DECODING_ERROR;
2604e6df137Slukem 
2614e6df137Slukem 	} else {
2624e6df137Slukem 		*drp2 = drhead;
2634e6df137Slukem 		ld->ld_errno = LDAP_SUCCESS;
2644e6df137Slukem 	}
2654e6df137Slukem 
2664e6df137Slukem 	return ld->ld_errno;
2674e6df137Slukem }
2684e6df137Slukem 
2694e6df137Slukem int
ldap_parse_deref_control(LDAP * ld,LDAPControl ** ctrls,LDAPDerefRes ** drp)2704e6df137Slukem ldap_parse_deref_control(
2714e6df137Slukem 	LDAP		*ld,
2724e6df137Slukem 	LDAPControl	**ctrls,
2734e6df137Slukem 	LDAPDerefRes	**drp )
2744e6df137Slukem {
2754e6df137Slukem 	LDAPControl *c;
2764e6df137Slukem 
2774e6df137Slukem 	if ( drp == NULL ) {
2784e6df137Slukem 		ld->ld_errno = LDAP_PARAM_ERROR;
2794e6df137Slukem 		return ld->ld_errno;
2804e6df137Slukem 	}
2814e6df137Slukem 
2824e6df137Slukem 	*drp = NULL;
2834e6df137Slukem 
2844e6df137Slukem 	if ( ctrls == NULL ) {
2854e6df137Slukem 		ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
2864e6df137Slukem 		return ld->ld_errno;
2874e6df137Slukem 	}
2884e6df137Slukem 
2894e6df137Slukem 	c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL );
2904e6df137Slukem 	if ( c == NULL ) {
2914e6df137Slukem 		/* No deref control was found. */
2924e6df137Slukem 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
2934e6df137Slukem 		return ld->ld_errno;
2944e6df137Slukem 	}
2954e6df137Slukem 
2964e6df137Slukem 	ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp );
2974e6df137Slukem 
2984e6df137Slukem 	return ld->ld_errno;
2994e6df137Slukem }
3004e6df137Slukem 
301