xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/deref.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: deref.c,v 1.2 2020/08/11 13:15:37 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2020 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.2 2020/08/11 13:15:37 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 	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 		dvp = &dr->attrVals;
200 
201 		tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal );
202 		if ( tag == LBER_ERROR ) {
203 			goto done;
204 		}
205 
206 		tag = ber_peek_tag( ber, &len );
207 		if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) {
208 			for ( tag = ber_first_element( ber, &len, &last2 );
209 				tag != LBER_DEFAULT;
210 				tag = ber_next_element( ber, &len, last2 ) )
211 			{
212 				LDAPDerefVal *dv;
213 
214 				dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) );
215 
216 				tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals );
217 				if ( tag == LBER_ERROR ) {
218 					goto done;
219 				}
220 
221 				*dvp = dv;
222 				dvp = &dv->next;
223 			}
224 		}
225 
226 		tag = ber_scanf( ber, "}" );
227 		if ( tag == LBER_ERROR ) {
228 			goto done;
229 		}
230 
231 		*drp = dr;
232 		drp = &dr->next;
233 	}
234 
235 	tag = 0;
236 
237 done:;
238         ber_free( ber, 1 );
239 
240 	if ( tag == LBER_ERROR ) {
241 		if ( drhead != NULL ) {
242 			ldap_derefresponse_free( drhead );
243 		}
244 
245 		*drp2 = NULL;
246 		ld->ld_errno = LDAP_DECODING_ERROR;
247 
248 	} else {
249 		*drp2 = drhead;
250 		ld->ld_errno = LDAP_SUCCESS;
251 	}
252 
253 	return ld->ld_errno;
254 }
255 
256 int
257 ldap_parse_deref_control(
258 	LDAP		*ld,
259 	LDAPControl	**ctrls,
260 	LDAPDerefRes	**drp )
261 {
262 	LDAPControl *c;
263 
264 	if ( drp == NULL ) {
265 		ld->ld_errno = LDAP_PARAM_ERROR;
266 		return ld->ld_errno;
267 	}
268 
269 	*drp = NULL;
270 
271 	if ( ctrls == NULL ) {
272 		ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
273 		return ld->ld_errno;
274 	}
275 
276 	c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL );
277 	if ( c == NULL ) {
278 		/* No deref control was found. */
279 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
280 		return ld->ld_errno;
281 	}
282 
283 	ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp );
284 
285 	return ld->ld_errno;
286 }
287 
288