xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/deref.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: deref.c,v 1.3 2021/08/14 16:14:55 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2021 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.3 2021/08/14 16:14:55 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
ldap_create_deref_control_value(LDAP * ld,LDAPDerefSpec * ds,struct berval * value)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
ldap_create_deref_control(LDAP * ld,LDAPDerefSpec * ds,int iscritical,LDAPControl ** ctrlp)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
ldap_derefresponse_free(LDAPDerefRes * dr)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
ldap_parse_derefresponse_control(LDAP * ld,LDAPControl * ctrl,LDAPDerefRes ** drp2)163 ldap_parse_derefresponse_control(
164 	LDAP		*ld,
165 	LDAPControl	*ctrl,
166 	LDAPDerefRes	**drp2 )
167 {
168 	BerElement *ber;
169 	ber_tag_t tag;
170 	ber_len_t len;
171 	char *last;
172 	LDAPDerefRes *drhead = NULL, **drp;
173 
174 	if ( ld == NULL || ctrl == NULL || drp2 == NULL ) {
175 		if ( ld )
176 			ld->ld_errno = LDAP_PARAM_ERROR;
177 		return LDAP_PARAM_ERROR;
178 	}
179 
180 	/* Create a BerElement from the berval returned in the control. */
181 	ber = ber_init( &ctrl->ldctl_value );
182 
183 	if ( ber == NULL ) {
184 		ld->ld_errno = LDAP_NO_MEMORY;
185 		return ld->ld_errno;
186 	}
187 
188 	/* Extract the count and cookie from the control. */
189 	drp = &drhead;
190 	for ( tag = ber_first_element( ber, &len, &last );
191 		tag != LBER_DEFAULT;
192 		tag = ber_next_element( ber, &len, last ) )
193 	{
194 		LDAPDerefRes *dr;
195 		LDAPDerefVal **dvp;
196 		char *last2;
197 
198 		dr = LDAP_CALLOC( 1, sizeof(LDAPDerefRes) );
199 		if ( dr == NULL ) {
200 			ldap_derefresponse_free( drhead );
201 			*drp2 = NULL;
202 			ld->ld_errno = LDAP_NO_MEMORY;
203 			return ld->ld_errno;
204 		}
205 		dvp = &dr->attrVals;
206 
207 		tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal );
208 		if ( tag == LBER_ERROR ) {
209 			goto done;
210 		}
211 
212 		tag = ber_peek_tag( ber, &len );
213 		if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) {
214 			for ( tag = ber_first_element( ber, &len, &last2 );
215 				tag != LBER_DEFAULT;
216 				tag = ber_next_element( ber, &len, last2 ) )
217 			{
218 				LDAPDerefVal *dv;
219 
220 				dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) );
221 				if ( dv == NULL ) {
222 					ldap_derefresponse_free( drhead );
223 					LDAP_FREE( dr );
224 					*drp2 = NULL;
225 					ld->ld_errno = LDAP_NO_MEMORY;
226 					return ld->ld_errno;
227 				}
228 
229 				tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals );
230 				if ( tag == LBER_ERROR ) {
231 					goto done;
232 				}
233 
234 				*dvp = dv;
235 				dvp = &dv->next;
236 			}
237 		}
238 
239 		tag = ber_scanf( ber, "}" );
240 		if ( tag == LBER_ERROR ) {
241 			goto done;
242 		}
243 
244 		*drp = dr;
245 		drp = &dr->next;
246 	}
247 
248 	tag = 0;
249 
250 done:;
251         ber_free( ber, 1 );
252 
253 	if ( tag == LBER_ERROR ) {
254 		if ( drhead != NULL ) {
255 			ldap_derefresponse_free( drhead );
256 		}
257 
258 		*drp2 = NULL;
259 		ld->ld_errno = LDAP_DECODING_ERROR;
260 
261 	} else {
262 		*drp2 = drhead;
263 		ld->ld_errno = LDAP_SUCCESS;
264 	}
265 
266 	return ld->ld_errno;
267 }
268 
269 int
ldap_parse_deref_control(LDAP * ld,LDAPControl ** ctrls,LDAPDerefRes ** drp)270 ldap_parse_deref_control(
271 	LDAP		*ld,
272 	LDAPControl	**ctrls,
273 	LDAPDerefRes	**drp )
274 {
275 	LDAPControl *c;
276 
277 	if ( drp == NULL ) {
278 		ld->ld_errno = LDAP_PARAM_ERROR;
279 		return ld->ld_errno;
280 	}
281 
282 	*drp = NULL;
283 
284 	if ( ctrls == NULL ) {
285 		ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
286 		return ld->ld_errno;
287 	}
288 
289 	c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL );
290 	if ( c == NULL ) {
291 		/* No deref control was found. */
292 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
293 		return ld->ld_errno;
294 	}
295 
296 	ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp );
297 
298 	return ld->ld_errno;
299 }
300 
301