]> git.sur5r.net Git - openldap/blob - libraries/libldap/controls.c
ldap_control*_dup() is no longer private; add ldap_pvt_put_control
[openldap] / libraries / libldap / controls.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2007 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 ) {
341                 return NULL;
342         }
343
344         new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
345
346         if( new == NULL ) {
347                 return NULL;
348         }
349
350         if( c->ldctl_oid != NULL ) {
351                 new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
352
353                 if(new->ldctl_oid == NULL) {
354                         LDAP_FREE( new );
355                         return NULL;
356                 }
357
358         } else {
359                 /* FIXME: how can a control have null OID? */
360                 new->ldctl_oid = NULL;
361         }
362
363         if( c->ldctl_value.bv_val != NULL ) {
364                 new->ldctl_value.bv_val =
365                         (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 );
366
367                 if(new->ldctl_value.bv_val == NULL) {
368                         if(new->ldctl_oid != NULL) {
369                                 LDAP_FREE( new->ldctl_oid );
370                         }
371                         LDAP_FREE( new );
372                         return NULL;
373                 }
374                 
375                 new->ldctl_value.bv_len = c->ldctl_value.bv_len;
376
377                 AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val, 
378                         c->ldctl_value.bv_len );
379
380                 new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0';
381
382         } else {
383                 new->ldctl_value.bv_len = 0;
384                 new->ldctl_value.bv_val = NULL;
385         }
386
387         new->ldctl_iscritical = c->ldctl_iscritical;
388         return new;
389 }
390
391 /*
392  * Find a LDAPControl - deprecated
393  */
394 LDAPControl *
395 ldap_find_control(
396         LDAP_CONST char *oid,
397         LDAPControl **ctrls )
398 {
399         if( ctrls == NULL || *ctrls == NULL ) {
400                 return NULL;
401         }
402
403         for( ; *ctrls != NULL; ctrls++ ) {
404                 if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
405                         return *ctrls;
406                 }
407         }
408
409         return NULL;
410 }
411
412 /*
413  * Find a LDAPControl
414  */
415 LDAPControl *
416 ldap_control_find(
417         LDAP_CONST char *oid,
418         LDAPControl **ctrls,
419         LDAPControl ***nextctrlp )
420 {
421         if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) {
422                 return NULL;
423         }
424
425         for( ; *ctrls != NULL; ctrls++ ) {
426                 if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
427                         if ( nextctrlp != NULL ) {
428                                 *nextctrlp = ctrls + 1;
429                         }
430
431                         return *ctrls;
432                 }
433         }
434
435         if ( nextctrlp != NULL ) {
436                 *nextctrlp = NULL;
437         }
438
439         return NULL;
440 }
441
442 /*
443  * Create a LDAPControl, optionally from ber - deprecated
444  */
445 int
446 ldap_create_control(
447         LDAP_CONST char *requestOID,
448         BerElement *ber,
449         int iscritical,
450         LDAPControl **ctrlp )
451 {
452         LDAPControl *ctrl;
453
454         assert( requestOID != NULL );
455         assert( ctrlp != NULL );
456
457         ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
458         if ( ctrl == NULL ) {
459                 return LDAP_NO_MEMORY;
460         }
461
462         BER_BVZERO(&ctrl->ldctl_value);
463         if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) {
464                 LDAP_FREE( ctrl );
465                 return LDAP_NO_MEMORY;
466         }
467
468         ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
469         ctrl->ldctl_iscritical = iscritical;
470
471         if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) {
472                 ldap_control_free( ctrl );
473                 return LDAP_NO_MEMORY;
474         }
475
476         *ctrlp = ctrl;
477         return LDAP_SUCCESS;
478 }
479
480 /*
481  * Create a LDAPControl, optionally from value
482  */
483 int
484 ldap_control_create(
485         LDAP_CONST char *requestOID,
486         int iscritical,
487         struct berval *value,
488         int dupval,
489         LDAPControl **ctrlp )
490 {
491         LDAPControl *ctrl;
492
493         assert( requestOID != NULL );
494         assert( ctrlp != NULL );
495
496         ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 );
497         if ( ctrl == NULL ) {
498                 return LDAP_NO_MEMORY;
499         }
500
501         ctrl->ldctl_iscritical = iscritical;
502         if ( requestOID != NULL ) {
503                 ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
504                 if ( ctrl->ldctl_oid == NULL ) {
505                         ldap_control_free( ctrl );
506                         return LDAP_NO_MEMORY;
507                 }
508         }
509
510         if ( value && !BER_BVISNULL( value ) ) {
511                 if ( dupval ) {
512                         ber_dupbv( &ctrl->ldctl_value, value );
513                         if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
514                                 ldap_control_free( ctrl );
515                                 return LDAP_NO_MEMORY;
516                         }
517
518                 } else {
519                         ctrl->ldctl_value = *value;
520                 }
521         }
522
523         *ctrlp = ctrl;
524
525         return LDAP_SUCCESS;
526 }
527
528 /*
529  * check for critical client controls and bitch if present
530  * if we ever support critical controls, we'll have to
531  * find a means for maintaining per API call control
532  * information.
533  */
534 int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
535 {
536         LDAPControl *const *c;
537
538         assert( ld != NULL );
539         assert( LDAP_VALID( ld ) );
540
541         if( ctrls == NULL ) {
542                 /* use default server controls */
543                 ctrls = ld->ld_cctrls;
544         }
545
546         if( ctrls == NULL || *ctrls == NULL ) {
547                 return LDAP_SUCCESS;
548         }
549
550         for( c = ctrls ; *c != NULL; c++ ) {
551                 if( (*c)->ldctl_iscritical ) {
552                         ld->ld_errno = LDAP_NOT_SUPPORTED;
553                         return ld->ld_errno;
554                 }
555         }
556
557         return LDAP_SUCCESS;
558 }