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