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