1 /*        $NetBSD: controls.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  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* This notice applies to changes, created by or for Novell, Inc.,
18  * to preexisting works for which notices appear elsewhere in this file.
19  *
20  * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
21  *
22  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
23  * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
24  * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
25  * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
26  * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
27  * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
28  * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
29  * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
30  *---
31  * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
32  * can be found in the file "build/LICENSE-2.0.1" in this distribution
33  * of OpenLDAP Software.
34  */
35 
36 #include <sys/cdefs.h>
37 __RCSID("$NetBSD: controls.c,v 1.3 2021/08/14 16:14:55 christos Exp $");
38 
39 #include "portable.h"
40 
41 #include <ac/stdlib.h>
42 
43 #include <ac/time.h>
44 #include <ac/string.h>
45 
46 #include "ldap-int.h"
47 
48 /* LDAPv3 Controls (RFC 4511)
49  *
50  *        Controls ::= SEQUENCE OF control Control
51  *
52  *        Control ::= SEQUENCE {
53  *                  controlType                   LDAPOID,
54  *                  criticality                   BOOLEAN DEFAULT FALSE,
55  *                  controlValue        OCTET STRING OPTIONAL
56  *        }
57  */
58 
59 int
ldap_pvt_put_control(const LDAPControl * c,BerElement * ber)60 ldap_pvt_put_control(
61           const LDAPControl *c,
62           BerElement *ber )
63 {
64           if ( ber_printf( ber, "{s" /*}*/, c->ldctl_oid ) == -1 ) {
65                     return LDAP_ENCODING_ERROR;
66           }
67 
68           if ( c->ldctl_iscritical /* only if true */
69                     &&  ( ber_printf( ber, "b",
70                               (ber_int_t) c->ldctl_iscritical ) == -1 ) )
71           {
72                     return LDAP_ENCODING_ERROR;
73           }
74 
75           if ( !BER_BVISNULL( &c->ldctl_value ) /* only if we have a value */
76                     &&  ( ber_printf( ber, "O", &c->ldctl_value ) == -1 ) )
77           {
78                     return LDAP_ENCODING_ERROR;
79           }
80 
81           if ( ber_printf( ber, /*{*/"N}" ) == -1 ) {
82                     return LDAP_ENCODING_ERROR;
83           }
84 
85           return LDAP_SUCCESS;
86 }
87 
88 
89 /*
90  * ldap_int_put_controls
91  */
92 
93 int
ldap_int_put_controls(LDAP * ld,LDAPControl * const * ctrls,BerElement * ber)94 ldap_int_put_controls(
95           LDAP *ld,
96           LDAPControl *const *ctrls,
97           BerElement *ber )
98 {
99           LDAPControl *const *c;
100 
101           assert( ld != NULL );
102           assert( LDAP_VALID( ld ) );
103           assert( ber != NULL );
104 
105           if( ctrls == NULL ) {
106                     /* use default server controls */
107                     ctrls = ld->ld_sctrls;
108           }
109 
110           if( ctrls == NULL || *ctrls == NULL ) {
111                     return LDAP_SUCCESS;
112           }
113 
114           if ( ld->ld_version < LDAP_VERSION3 ) {
115                     /* LDAPv2 doesn't support controls,
116                      * error if any control is critical
117                      */
118                     for( c = ctrls ; *c != NULL; c++ ) {
119                               if( (*c)->ldctl_iscritical ) {
120                                         ld->ld_errno = LDAP_NOT_SUPPORTED;
121                                         return ld->ld_errno;
122                               }
123                     }
124 
125                     return LDAP_SUCCESS;
126           }
127 
128           /* Controls are encoded as a sequence of sequences */
129           if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) {
130                     ld->ld_errno = LDAP_ENCODING_ERROR;
131                     return ld->ld_errno;
132           }
133 
134           for( c = ctrls ; *c != NULL; c++ ) {
135                     ld->ld_errno = ldap_pvt_put_control( *c, ber );
136                     if ( ld->ld_errno != LDAP_SUCCESS ) {
137                               return ld->ld_errno;
138                     }
139           }
140 
141 
142           if( ber_printf( ber, /*{*/ "}" ) == -1 ) {
143                     ld->ld_errno = LDAP_ENCODING_ERROR;
144                     return ld->ld_errno;
145           }
146 
147           return LDAP_SUCCESS;
148 }
149 
ldap_pvt_get_controls(BerElement * ber,LDAPControl *** ctrls)150 int ldap_pvt_get_controls(
151           BerElement *ber,
152           LDAPControl ***ctrls )
153 {
154           int nctrls;
155           ber_tag_t tag;
156           ber_len_t len;
157           char *opaque;
158 
159           assert( ber != NULL );
160 
161           if( ctrls == NULL ) {
162                     return LDAP_SUCCESS;
163           }
164           *ctrls = NULL;
165 
166           len = ber_pvt_ber_remaining( ber );
167 
168           if( len == 0) {
169                     /* no controls */
170                     return LDAP_SUCCESS;
171           }
172 
173           if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
174                     if( tag == LBER_ERROR ) {
175                               /* decoding error */
176                               return LDAP_DECODING_ERROR;
177                     }
178 
179                     /* ignore unexpected input */
180                     return LDAP_SUCCESS;
181           }
182 
183           /* set through each element */
184           nctrls = 0;
185           *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) );
186 
187           if( *ctrls == NULL ) {
188                     return LDAP_NO_MEMORY;
189           }
190 
191           *ctrls[nctrls] = NULL;
192 
193           for( tag = ber_first_element( ber, &len, &opaque );
194                     tag != LBER_ERROR;
195                     tag = ber_next_element( ber, &len, opaque ) )
196           {
197                     LDAPControl *tctrl;
198                     LDAPControl **tctrls;
199 
200                     tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) );
201 
202                     /* allocate pointer space for current controls (nctrls)
203                      * + this control + extra NULL
204                      */
205                     tctrls = (tctrl == NULL) ? NULL :
206                               LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
207 
208                     if( tctrls == NULL ) {
209                               /* one of the above allocation failed */
210 
211                               if( tctrl != NULL ) {
212                                         LDAP_FREE( tctrl );
213                               }
214 
215                               ldap_controls_free(*ctrls);
216                               *ctrls = NULL;
217 
218                               return LDAP_NO_MEMORY;
219                     }
220 
221 
222                     tctrls[nctrls++] = tctrl;
223                     tctrls[nctrls] = NULL;
224 
225                     tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
226 
227                     if( tag == LBER_ERROR ) {
228                               *ctrls = NULL;
229                               ldap_controls_free( tctrls );
230                               return LDAP_DECODING_ERROR;
231                     }
232 
233                     tag = ber_peek_tag( ber, &len );
234 
235                     if( tag == LBER_BOOLEAN ) {
236                               ber_int_t crit;
237                               tag = ber_scanf( ber, "b", &crit );
238                               tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
239                               tag = ber_peek_tag( ber, &len );
240                     }
241 
242                     if( tag == LBER_OCTETSTRING ) {
243                               tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
244                     } else {
245                               BER_BVZERO( &tctrl->ldctl_value );
246                     }
247 
248                     *ctrls = tctrls;
249           }
250 
251           return LDAP_SUCCESS;
252 }
253 
254 /*
255  * Free a LDAPControl
256  */
257 void
ldap_control_free(LDAPControl * c)258 ldap_control_free( LDAPControl *c )
259 {
260           LDAP_MEMORY_DEBUG_ASSERT( c != NULL );
261 
262           if ( c != NULL ) {
263                     if( c->ldctl_oid != NULL) {
264                               LDAP_FREE( c->ldctl_oid );
265                     }
266 
267                     if( c->ldctl_value.bv_val != NULL ) {
268                               LDAP_FREE( c->ldctl_value.bv_val );
269                     }
270 
271                     LDAP_FREE( c );
272           }
273 }
274 
275 /*
276  * Free an array of LDAPControl's
277  */
278 void
ldap_controls_free(LDAPControl ** controls)279 ldap_controls_free( LDAPControl **controls )
280 {
281           LDAP_MEMORY_DEBUG_ASSERT( controls != NULL );
282 
283           if ( controls != NULL ) {
284                     int i;
285 
286                     for( i=0; controls[i] != NULL; i++) {
287                               ldap_control_free( controls[i] );
288                     }
289 
290                     LDAP_FREE( controls );
291           }
292 }
293 
294 /*
295  * Duplicate an array of LDAPControl
296  */
297 LDAPControl **
ldap_controls_dup(LDAPControl * const * controls)298 ldap_controls_dup( LDAPControl *const *controls )
299 {
300           LDAPControl **new;
301           int i;
302 
303           if ( controls == NULL ) {
304                     return NULL;
305           }
306 
307           /* count the controls */
308           for(i=0; controls[i] != NULL; i++) /* empty */ ;
309 
310           if( i < 1 ) {
311                     /* no controls to duplicate */
312                     return NULL;
313           }
314 
315           new = (LDAPControl **) LDAP_MALLOC( (i+1) * sizeof(LDAPControl *) );
316 
317           if( new == NULL ) {
318                     /* memory allocation failure */
319                     return NULL;
320           }
321 
322           /* duplicate the controls */
323           for(i=0; controls[i] != NULL; i++) {
324                     new[i] = ldap_control_dup( controls[i] );
325 
326                     if( new[i] == NULL ) {
327                               ldap_controls_free( new );
328                               return NULL;
329                     }
330           }
331 
332           new[i] = NULL;
333 
334           return new;
335 }
336 
337 /*
338  * Duplicate a LDAPControl
339  */
340 LDAPControl *
ldap_control_dup(const LDAPControl * c)341 ldap_control_dup( const LDAPControl *c )
342 {
343           LDAPControl *new;
344 
345           if ( c == NULL || c->ldctl_oid == NULL ) {
346                     return NULL;
347           }
348 
349           new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
350 
351           if( new == NULL ) {
352                     return NULL;
353           }
354 
355           new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
356 
357           if(new->ldctl_oid == NULL) {
358                     LDAP_FREE( new );
359                     return NULL;
360           }
361 
362           if( c->ldctl_value.bv_val != NULL ) {
363                     new->ldctl_value.bv_val =
364                               (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 );
365 
366                     if(new->ldctl_value.bv_val == NULL) {
367                               if(new->ldctl_oid != NULL) {
368                                         LDAP_FREE( new->ldctl_oid );
369                               }
370                               LDAP_FREE( new );
371                               return NULL;
372                     }
373 
374                     new->ldctl_value.bv_len = c->ldctl_value.bv_len;
375 
376                     AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val,
377                               c->ldctl_value.bv_len );
378 
379                     new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0';
380 
381           } else {
382                     new->ldctl_value.bv_len = 0;
383                     new->ldctl_value.bv_val = NULL;
384           }
385 
386           new->ldctl_iscritical = c->ldctl_iscritical;
387           return new;
388 }
389 
390 /*
391  * Find a LDAPControl - deprecated
392  */
393 LDAPControl *
ldap_find_control(LDAP_CONST char * oid,LDAPControl ** ctrls)394 ldap_find_control(
395           LDAP_CONST char *oid,
396           LDAPControl **ctrls )
397 {
398           if( ctrls == NULL || *ctrls == NULL ) {
399                     return NULL;
400           }
401 
402           for( ; *ctrls != NULL; ctrls++ ) {
403                     if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
404                               return *ctrls;
405                     }
406           }
407 
408           return NULL;
409 }
410 
411 /*
412  * Find a LDAPControl
413  */
414 LDAPControl *
ldap_control_find(LDAP_CONST char * oid,LDAPControl ** ctrls,LDAPControl *** nextctrlp)415 ldap_control_find(
416           LDAP_CONST char *oid,
417           LDAPControl **ctrls,
418           LDAPControl ***nextctrlp )
419 {
420           if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) {
421                     return NULL;
422           }
423 
424           for( ; *ctrls != NULL; ctrls++ ) {
425                     if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
426                               if ( nextctrlp != NULL ) {
427                                         *nextctrlp = ctrls + 1;
428                               }
429 
430                               return *ctrls;
431                     }
432           }
433 
434           if ( nextctrlp != NULL ) {
435                     *nextctrlp = NULL;
436           }
437 
438           return NULL;
439 }
440 
441 /*
442  * Create a LDAPControl, optionally from ber - deprecated
443  */
444 int
ldap_create_control(LDAP_CONST char * requestOID,BerElement * ber,int iscritical,LDAPControl ** ctrlp)445 ldap_create_control(
446           LDAP_CONST char *requestOID,
447           BerElement *ber,
448           int iscritical,
449           LDAPControl **ctrlp )
450 {
451           LDAPControl *ctrl;
452 
453           assert( requestOID != NULL );
454           assert( ctrlp != NULL );
455 
456           ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
457           if ( ctrl == NULL ) {
458                     return LDAP_NO_MEMORY;
459           }
460 
461           BER_BVZERO(&ctrl->ldctl_value);
462           if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) {
463                     LDAP_FREE( ctrl );
464                     return LDAP_NO_MEMORY;
465           }
466 
467           ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
468           ctrl->ldctl_iscritical = iscritical;
469 
470           if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) {
471                     ldap_control_free( ctrl );
472                     return LDAP_NO_MEMORY;
473           }
474 
475           *ctrlp = ctrl;
476           return LDAP_SUCCESS;
477 }
478 
479 /*
480  * Create a LDAPControl, optionally from value
481  */
482 int
ldap_control_create(LDAP_CONST char * requestOID,int iscritical,struct berval * value,int dupval,LDAPControl ** ctrlp)483 ldap_control_create(
484           LDAP_CONST char *requestOID,
485           int iscritical,
486           struct berval *value,
487           int dupval,
488           LDAPControl **ctrlp )
489 {
490           LDAPControl *ctrl;
491 
492           assert( requestOID != NULL );
493           assert( ctrlp != NULL );
494 
495           ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 );
496           if ( ctrl == NULL ) {
497                     return LDAP_NO_MEMORY;
498           }
499 
500           ctrl->ldctl_iscritical = iscritical;
501           if ( requestOID != NULL ) {
502                     ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
503                     if ( ctrl->ldctl_oid == NULL ) {
504                               ldap_control_free( ctrl );
505                               return LDAP_NO_MEMORY;
506                     }
507           }
508 
509           if ( value && !BER_BVISNULL( value ) ) {
510                     if ( dupval ) {
511                               ber_dupbv( &ctrl->ldctl_value, value );
512                               if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
513                                         ldap_control_free( ctrl );
514                                         return LDAP_NO_MEMORY;
515                               }
516 
517                     } else {
518                               ctrl->ldctl_value = *value;
519                     }
520           }
521 
522           *ctrlp = ctrl;
523 
524           return LDAP_SUCCESS;
525 }
526 
527 /*
528  * check for critical client controls and bitch if present
529  * if we ever support critical controls, we'll have to
530  * find a means for maintaining per API call control
531  * information.
532  */
ldap_int_client_controls(LDAP * ld,LDAPControl ** ctrls)533 int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
534 {
535           LDAPControl *const *c;
536 
537           assert( ld != NULL );
538           assert( LDAP_VALID( ld ) );
539 
540           if( ctrls == NULL ) {
541                     /* use default client controls */
542                     ctrls = ld->ld_cctrls;
543           }
544 
545           if( ctrls == NULL || *ctrls == NULL ) {
546                     return LDAP_SUCCESS;
547           }
548 
549           for( c = ctrls ; *c != NULL; c++ ) {
550                     if( (*c)->ldctl_iscritical ) {
551                               ld->ld_errno = LDAP_NOT_SUPPORTED;
552                               return ld->ld_errno;
553                     }
554           }
555 
556           return LDAP_SUCCESS;
557 }
558