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