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