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