]> git.sur5r.net Git - openldap/blob - libraries/libldap/controls.c
rework controls API
[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 /*
55  * ldap_int_put_controls
56  */
57
58 int
59 ldap_int_put_controls(
60         LDAP *ld,
61         LDAPControl *const *ctrls,
62         BerElement *ber )
63 {
64         LDAPControl *const *c;
65
66         assert( ld != NULL );
67         assert( LDAP_VALID( ld ) );
68         assert( ber != NULL );
69
70         if( ctrls == NULL ) {
71                 /* use default server controls */
72                 ctrls = ld->ld_sctrls;
73         }
74
75         if( ctrls == NULL || *ctrls == NULL ) {
76                 return LDAP_SUCCESS;
77         }
78
79         if ( ld->ld_version < LDAP_VERSION3 ) {
80                 /* LDAPv2 doesn't support controls,
81                  * error if any control is critical
82                  */
83                 for( c = ctrls ; *c != NULL; c++ ) {
84                         if( (*c)->ldctl_iscritical ) {
85                                 ld->ld_errno = LDAP_NOT_SUPPORTED;
86                                 return ld->ld_errno;
87                         }
88                 }
89
90                 return LDAP_SUCCESS;
91         }
92
93         /* Controls are encoded as a sequence of sequences */
94         if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) {
95                 ld->ld_errno = LDAP_ENCODING_ERROR;
96                 return ld->ld_errno;
97         }
98
99         for( c = ctrls ; *c != NULL; c++ ) {
100                 if ( ber_printf( ber, "{s" /*}*/,
101                         (*c)->ldctl_oid ) == -1 )
102                 {
103                         ld->ld_errno = LDAP_ENCODING_ERROR;
104                         return ld->ld_errno;
105                 }
106
107                 if( (*c)->ldctl_iscritical /* only if true */
108                         &&  ( ber_printf( ber, "b",
109                                 (ber_int_t) (*c)->ldctl_iscritical ) == -1 ) )
110                 {
111                         ld->ld_errno = LDAP_ENCODING_ERROR;
112                         return ld->ld_errno;
113                 }
114
115                 if( (*c)->ldctl_value.bv_val != NULL /* only if we have a value */
116                         &&  ( ber_printf( ber, "O",
117                                 &((*c)->ldctl_value) ) == -1 ) )
118                 {
119                         ld->ld_errno = LDAP_ENCODING_ERROR;
120                         return ld->ld_errno;
121                 }
122
123
124                 if( ber_printf( ber, /*{*/"N}" ) == -1 ) {
125                         ld->ld_errno = LDAP_ENCODING_ERROR;
126                         return ld->ld_errno;
127                 }
128         }
129
130
131         if( ber_printf( ber, /*{*/ "}" ) == -1 ) {
132                 ld->ld_errno = LDAP_ENCODING_ERROR;
133                 return ld->ld_errno;
134         }
135
136         return LDAP_SUCCESS;
137 }
138
139 int ldap_pvt_get_controls(
140         BerElement *ber,
141         LDAPControl ***ctrls )
142 {
143         int nctrls;
144         ber_tag_t tag;
145         ber_len_t len;
146         char *opaque;
147
148         assert( ber != NULL );
149
150         if( ctrls == NULL ) {
151                 return LDAP_SUCCESS;
152         }
153         *ctrls = NULL;
154
155         len = ber_pvt_ber_remaining( ber );
156
157         if( len == 0) {
158                 /* no controls */
159                 return LDAP_SUCCESS;
160         }
161
162         if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
163                 if( tag == LBER_ERROR ) {
164                         /* decoding error */
165                         return LDAP_DECODING_ERROR;
166                 }
167
168                 /* ignore unexpected input */
169                 return LDAP_SUCCESS;
170         }
171
172         /* set through each element */
173         nctrls = 0;
174         *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) );
175
176         if( *ctrls == NULL ) {
177                 return LDAP_NO_MEMORY;
178         }
179
180         *ctrls[nctrls] = NULL;
181
182         for( tag = ber_first_element( ber, &len, &opaque );
183                 tag != LBER_ERROR;
184                 tag = ber_next_element( ber, &len, opaque ) )
185         {
186                 LDAPControl *tctrl;
187                 LDAPControl **tctrls;
188
189                 tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) );
190
191                 /* allocate pointer space for current controls (nctrls)
192                  * + this control + extra NULL
193                  */
194                 tctrls = (tctrl == NULL) ? NULL :
195                         LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
196
197                 if( tctrls == NULL ) {
198                         /* one of the above allocation failed */
199
200                         if( tctrl != NULL ) {
201                                 LDAP_FREE( tctrl );
202                         }
203
204                         ldap_controls_free(*ctrls);
205                         *ctrls = NULL;
206
207                         return LDAP_NO_MEMORY;
208                 }
209
210
211                 tctrls[nctrls++] = tctrl;
212                 tctrls[nctrls] = NULL;
213
214                 tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
215
216                 if( tag == LBER_ERROR ) {
217                         *ctrls = NULL;
218                         ldap_controls_free( tctrls );
219                         return LDAP_DECODING_ERROR;
220                 }
221
222                 tag = ber_peek_tag( ber, &len );
223
224                 if( tag == LBER_BOOLEAN ) {
225                         ber_int_t crit;
226                         tag = ber_scanf( ber, "b", &crit );
227                         tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
228                         tag = ber_peek_tag( ber, &len );
229                 }
230
231                 if( tag == LBER_OCTETSTRING ) {
232                         tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
233                 } else {
234                         BER_BVZERO( &tctrl->ldctl_value );
235                 }
236
237                 *ctrls = tctrls;
238         }
239                 
240         return LDAP_SUCCESS;
241 }
242
243 /*
244  * Free a LDAPControl
245  */
246 void
247 ldap_control_free( LDAPControl *c )
248 {
249         LDAP_MEMORY_DEBUG_ASSERT( c != NULL );
250
251         if ( c != NULL ) {
252                 if( c->ldctl_oid != NULL) {
253                         LDAP_FREE( c->ldctl_oid );
254                 }
255
256                 if( c->ldctl_value.bv_val != NULL ) {
257                         LDAP_FREE( c->ldctl_value.bv_val );
258                 }
259
260                 LDAP_FREE( c );
261         }
262 }
263
264 /*
265  * Free an array of LDAPControl's
266  */
267 void
268 ldap_controls_free( LDAPControl **controls )
269 {
270         LDAP_MEMORY_DEBUG_ASSERT( controls != NULL );
271
272         if ( controls != NULL ) {
273                 int i;
274
275                 for( i=0; controls[i] != NULL; i++) {
276                         ldap_control_free( controls[i] );
277                 }
278
279                 LDAP_FREE( controls );
280         }
281 }
282
283 /*
284  * Duplicate an array of LDAPControl
285  */
286 LDAPControl **
287 ldap_controls_dup( LDAPControl *const *controls )
288 {
289         LDAPControl **new;
290         int i;
291
292         if ( controls == NULL ) {
293                 return NULL;
294         }
295
296         /* count the controls */
297         for(i=0; controls[i] != NULL; i++) /* empty */ ;
298
299         if( i < 1 ) {
300                 /* no controls to duplicate */
301                 return NULL;
302         }
303
304         new = (LDAPControl **) LDAP_MALLOC( (i+1) * sizeof(LDAPControl *) );
305
306         if( new == NULL ) {
307                 /* memory allocation failure */
308                 return NULL;
309         }
310
311         /* duplicate the controls */
312         for(i=0; controls[i] != NULL; i++) {
313                 new[i] = ldap_control_dup( controls[i] );
314
315                 if( new[i] == NULL ) {
316                         ldap_controls_free( new );
317                         return NULL;
318                 }
319         }
320
321         new[i] = NULL;
322
323         return new;
324 }
325
326 /*
327  * Duplicate a LDAPControl
328  */
329 LDAPControl *
330 ldap_control_dup( const LDAPControl *c )
331 {
332         LDAPControl *new;
333
334         if ( c == NULL ) {
335                 return NULL;
336         }
337
338         new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
339
340         if( new == NULL ) {
341                 return NULL;
342         }
343
344         if( c->ldctl_oid != NULL ) {
345                 new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
346
347                 if(new->ldctl_oid == NULL) {
348                         LDAP_FREE( new );
349                         return NULL;
350                 }
351
352         } else {
353                 /* FIXME: how can a control have null OID? */
354                 new->ldctl_oid = 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 server 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 }