]> git.sur5r.net Git - openldap/blob - libraries/libldap/deref.c
add support for (experimental) dereference control (ITS#5768); need to re-run autocon...
[openldap] / libraries / libldap / deref.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2008 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
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
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_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
133 void
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
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                 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                 for ( tag = ber_first_element( ber, &len, &last2 );
202                         tag != LBER_DEFAULT;
203                         tag = ber_next_element( ber, &len, last2 ) )
204                 {
205                         LDAPDerefVal *dv;
206
207                         dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) );
208
209                         tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals );
210                         if ( tag == LBER_ERROR ) {
211                                 goto done;
212                         }
213
214                         *dvp = dv;
215                         dvp = &dv->next;
216                 }
217
218                 tag = ber_scanf( ber, "}" );
219                 if ( tag == LBER_ERROR ) {
220                         goto done;
221                 }
222
223                 *drp = dr;
224                 drp = &dr->next;
225         }
226
227         tag = 0;
228
229 done:;
230         ber_free( ber, 1 );
231
232         if ( tag == LBER_ERROR ) {
233                 if ( drhead != NULL ) {
234                         ldap_derefresponse_free( drhead );
235                 }
236
237                 *drp2 = NULL;
238                 ld->ld_errno = LDAP_DECODING_ERROR;
239
240         } else {
241                 *drp2 = drhead;
242                 ld->ld_errno = LDAP_SUCCESS;
243         }
244
245         return ld->ld_errno;
246 }
247
248 int
249 ldap_parse_deref_control(
250         LDAP            *ld,
251         LDAPControl     **ctrls,
252         LDAPDerefRes    **drp )
253 {
254         LDAPControl *c;
255
256         if ( drp == NULL ) {
257                 ld->ld_errno = LDAP_PARAM_ERROR;
258                 return ld->ld_errno;
259         }
260
261         *drp = NULL;
262
263         if ( ctrls == NULL ) {
264                 ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
265                 return ld->ld_errno;
266         }
267
268         c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL );
269         if ( c == NULL ) {
270                 /* No deref control was found. */
271                 ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
272                 return ld->ld_errno;
273         }
274
275         ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp );
276
277         return ld->ld_errno;
278 }
279