1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 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
30int
31ldap_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
99done:;
100	if ( ber != NULL ) {
101		ber_free( ber, 1 );
102	}
103
104	return ld->ld_errno;
105}
106
107int
108ldap_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_PAGEDRESULTS,
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
133void
134ldap_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
157int
158ldap_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		dvp = &dr->attrVals;
195
196		tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal );
197		if ( tag == LBER_ERROR ) {
198			goto done;
199		}
200
201		tag = ber_peek_tag( ber, &len );
202		if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) {
203			for ( tag = ber_first_element( ber, &len, &last2 );
204				tag != LBER_DEFAULT;
205				tag = ber_next_element( ber, &len, last2 ) )
206			{
207				LDAPDerefVal *dv;
208
209				dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) );
210
211				tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals );
212				if ( tag == LBER_ERROR ) {
213					goto done;
214				}
215
216				*dvp = dv;
217				dvp = &dv->next;
218			}
219		}
220
221		tag = ber_scanf( ber, "}" );
222		if ( tag == LBER_ERROR ) {
223			goto done;
224		}
225
226		*drp = dr;
227		drp = &dr->next;
228	}
229
230	tag = 0;
231
232done:;
233        ber_free( ber, 1 );
234
235	if ( tag == LBER_ERROR ) {
236		if ( drhead != NULL ) {
237			ldap_derefresponse_free( drhead );
238		}
239
240		*drp2 = NULL;
241		ld->ld_errno = LDAP_DECODING_ERROR;
242
243	} else {
244		*drp2 = drhead;
245		ld->ld_errno = LDAP_SUCCESS;
246	}
247
248	return ld->ld_errno;
249}
250
251int
252ldap_parse_deref_control(
253	LDAP		*ld,
254	LDAPControl	**ctrls,
255	LDAPDerefRes	**drp )
256{
257	LDAPControl *c;
258
259	if ( drp == NULL ) {
260		ld->ld_errno = LDAP_PARAM_ERROR;
261		return ld->ld_errno;
262	}
263
264	*drp = NULL;
265
266	if ( ctrls == NULL ) {
267		ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
268		return ld->ld_errno;
269	}
270
271	c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL );
272	if ( c == NULL ) {
273		/* No deref control was found. */
274		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
275		return ld->ld_errno;
276	}
277
278	ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp );
279
280	return ld->ld_errno;
281}
282
283