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