]> git.sur5r.net Git - openldap/blob - libraries/libldap/controls.c
4ff12c2807dea18d6fbb0087d03609bb257d1f1c
[openldap] / libraries / libldap / controls.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2003 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  * Modification to OpenLDAP source by Novell, Inc.
30  * June 2000 sfs  Added control utilities
31  *--
32  * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
33  * can be found in the file "build/LICENSE-2.0.1" in this distribution
34  * of OpenLDAP Software.
35  */
36 /* Portions Copyright (C) The Internet Society (1997)
37  * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
38  */
39
40 /* LDAPv3 Controls (RFC2251)
41  *
42  *      Controls ::= SEQUENCE OF Control  
43  *
44  *      Control ::= SEQUENCE { 
45  *              controlType             LDAPOID,
46  *              criticality             BOOLEAN DEFAULT FALSE,
47  *              controlValue    OCTET STRING OPTIONAL
48  *      }
49  */
50
51 #include "portable.h"
52
53 #include <ac/stdlib.h>
54
55 #include <ac/time.h>
56 #include <ac/string.h>
57
58 #include "ldap-int.h"
59
60
61 /*
62  * ldap_int_put_controls
63  */
64
65 int
66 ldap_int_put_controls(
67         LDAP *ld,
68         LDAPControl *const *ctrls,
69         BerElement *ber )
70 {
71         LDAPControl *const *c;
72
73         assert( ld != NULL );
74         assert( LDAP_VALID(ld) );
75         assert( ber != NULL );
76
77         if( ctrls == NULL ) {
78                 /* use default server controls */
79                 ctrls = ld->ld_sctrls;
80         }
81
82         if( ctrls == NULL || *ctrls == NULL ) {
83                 return LDAP_SUCCESS;
84         }
85
86         if ( ld->ld_version < LDAP_VERSION3 ) {
87                 /* LDAPv2 doesn't support controls,
88                  * error if any control is critical
89                  */
90                 for( c = ctrls ; *c != NULL; c++ ) {
91                         if( (*c)->ldctl_iscritical ) {
92                                 ld->ld_errno = LDAP_NOT_SUPPORTED;
93                                 return ld->ld_errno;
94                         }
95                 }
96
97                 return LDAP_SUCCESS;
98         }
99
100         /* Controls are encoded as a sequence of sequences */
101         if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) {
102                 ld->ld_errno = LDAP_ENCODING_ERROR;
103                 return ld->ld_errno;
104         }
105
106         for( c = ctrls ; *c != NULL; c++ ) {
107                 if ( ber_printf( ber, "{s" /*}*/,
108                         (*c)->ldctl_oid ) == -1 )
109                 {
110                         ld->ld_errno = LDAP_ENCODING_ERROR;
111                         return ld->ld_errno;
112                 }
113
114                 if( (*c)->ldctl_iscritical /* only if true */
115                         &&  ( ber_printf( ber, "b",
116                                 (ber_int_t) (*c)->ldctl_iscritical ) == -1 ) )
117                 {
118                         ld->ld_errno = LDAP_ENCODING_ERROR;
119                         return ld->ld_errno;
120                 }
121
122                 if( (*c)->ldctl_value.bv_val != NULL /* only if we have a value */
123                         &&  ( ber_printf( ber, "O",
124                                 &((*c)->ldctl_value) ) == -1 ) )
125                 {
126                         ld->ld_errno = LDAP_ENCODING_ERROR;
127                         return ld->ld_errno;
128                 }
129
130
131                 if( ber_printf( ber, /*{*/"N}" ) == -1 ) {
132                         ld->ld_errno = LDAP_ENCODING_ERROR;
133                         return ld->ld_errno;
134                 }
135         }
136
137
138         if( ber_printf( ber, /*{*/ "}" ) == -1 ) {
139                 ld->ld_errno = LDAP_ENCODING_ERROR;
140                 return ld->ld_errno;
141         }
142
143         return LDAP_SUCCESS;
144 }
145
146 int ldap_pvt_get_controls(
147         BerElement *ber,
148         LDAPControl ***ctrls )
149 {
150         int nctrls;
151         ber_tag_t tag;
152         ber_len_t len;
153         char *opaque;
154
155         assert( ber != NULL );
156
157         if( ctrls == NULL ) {
158                 return LDAP_SUCCESS;
159         }
160         *ctrls = NULL;
161
162         len = ber_pvt_ber_remaining( ber );
163
164         if( len == 0) {
165                 /* no controls */
166                 return LDAP_SUCCESS;
167         }
168
169         if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
170                 if( tag == LBER_ERROR ) {
171                         /* decoding error */
172                         return LDAP_DECODING_ERROR;
173                 }
174
175                 /* ignore unexpected input */
176                 return LDAP_SUCCESS;
177         }
178
179         /* set through each element */
180         nctrls = 0;
181         *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) );
182
183         if( *ctrls == NULL ) {
184                 return LDAP_NO_MEMORY;
185         }
186
187         *ctrls[nctrls] = NULL;
188
189         for( tag = ber_first_element( ber, &len, &opaque );
190                 tag != LBER_ERROR;
191                 tag = ber_next_element( ber, &len, opaque ) )
192         {
193                 LDAPControl *tctrl;
194                 LDAPControl **tctrls;
195
196                 tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) );
197
198                 /* allocate pointer space for current controls (nctrls)
199                  * + this control + extra NULL
200                  */
201                 tctrls = (tctrl == NULL) ? NULL :
202                         LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
203
204                 if( tctrls == NULL ) {
205                         /* one of the above allocation failed */
206
207                         if( tctrl != NULL ) {
208                                 LDAP_FREE( tctrl );
209                         }
210
211                         ldap_controls_free(*ctrls);
212                         *ctrls = NULL;
213
214                         return LDAP_NO_MEMORY;
215                 }
216
217
218                 tctrls[nctrls++] = tctrl;
219                 tctrls[nctrls] = NULL;
220
221                 tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
222
223                 if( tag == LBER_ERROR ) {
224                         *ctrls = NULL;
225                         ldap_controls_free( tctrls );
226                         return LDAP_DECODING_ERROR;
227                 }
228
229                 tag = ber_peek_tag( ber, &len );
230
231                 if( tag == LBER_BOOLEAN ) {
232                         ber_int_t crit;
233                         tag = ber_scanf( ber, "b", &crit );
234                         tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
235                         tag = ber_peek_tag( ber, &len );
236                 }
237
238                 if( tag == LBER_OCTETSTRING ) {
239                         tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
240                 } else {
241                         tctrl->ldctl_value.bv_val = NULL;
242                 }
243
244                 *ctrls = tctrls;
245         }
246                 
247         return LDAP_SUCCESS;
248 }
249
250 /*
251  * Free a LDAPControl
252  */
253 void
254 ldap_control_free( LDAPControl *c )
255 {
256 #ifdef LDAP_MEMORY_DEBUG
257         assert( c != NULL );
258 #endif
259
260         if ( c != NULL ) {
261                 if( c->ldctl_oid != NULL) {
262                         LDAP_FREE( c->ldctl_oid );
263                 }
264
265                 if( c->ldctl_value.bv_val != NULL ) {
266                         LDAP_FREE( c->ldctl_value.bv_val );
267                 }
268
269                 LDAP_FREE( c );
270         }
271 }
272
273 /*
274  * Free an array of LDAPControl's
275  */
276 void
277 ldap_controls_free( LDAPControl **controls )
278 {
279 #ifdef LDAP_MEMORY_DEBUG
280         assert( controls != NULL );
281 #endif
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 **
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 *
341 ldap_control_dup( const LDAPControl *c )
342 {
343         LDAPControl *new;
344
345         if ( c == NULL ) {
346                 return NULL;
347         }
348
349         new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
350
351         if( new == NULL ) {
352                 return NULL;
353         }
354
355         if( c->ldctl_oid != NULL ) {
356                 new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
357
358                 if(new->ldctl_oid == NULL) {
359                         LDAP_FREE( new );
360                         return NULL;
361                 }
362
363         } else {
364                 new->ldctl_oid = NULL;
365         }
366
367         if( c->ldctl_value.bv_val != NULL ) {
368                 new->ldctl_value.bv_val =
369                         (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 );
370
371                 if(new->ldctl_value.bv_val == NULL) {
372                         if(new->ldctl_oid != NULL) {
373                                 LDAP_FREE( new->ldctl_oid );
374                         }
375                         LDAP_FREE( new );
376                         return NULL;
377                 }
378                 
379                 new->ldctl_value.bv_len = c->ldctl_value.bv_len;
380
381                 AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val, 
382                         c->ldctl_value.bv_len );
383
384                 new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0';
385
386         } else {
387                 new->ldctl_value.bv_len = 0;
388                 new->ldctl_value.bv_val = NULL;
389         }
390
391         new->ldctl_iscritical = c->ldctl_iscritical;
392         return new;
393 }
394
395 /*
396    ldap_create_control
397    
398    Internal function to create an LDAP control from the encoded BerElement.
399
400    requestOID  (IN) The OID to use in creating the control.
401    
402    ber         (IN) The encoded BerElement to use in creating the control.
403    
404    iscritical  (IN) 0 - Indicates the control is not critical to the operation.
405                                         non-zero - The control is critical to the operation.
406                                   
407    ctrlp      (OUT) Returns a pointer to the LDAPControl created.  This control
408                                         SHOULD be freed by calling ldap_control_free() when done.
409 ---*/
410
411 int
412 ldap_create_control(
413         LDAP_CONST char *requestOID,
414         BerElement *ber,
415         int iscritical,
416         LDAPControl **ctrlp )
417 {
418         LDAPControl *ctrl;
419
420         assert( requestOID != NULL );
421         assert( ber != NULL );
422         assert( ctrlp != NULL );
423
424         ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
425         if ( ctrl == NULL ) {
426                 return LDAP_NO_MEMORY;
427         }
428
429         if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
430                 LDAP_FREE( ctrl );
431                 return LDAP_NO_MEMORY;
432         }
433
434         ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
435         ctrl->ldctl_iscritical = iscritical;
436
437         if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) {
438                 ldap_control_free( ctrl );
439                 return LDAP_NO_MEMORY;
440         }
441
442         *ctrlp = ctrl;
443         return LDAP_SUCCESS;
444 }
445
446 /*
447  * check for critical client controls and bitch if present
448  * if we ever support critical controls, we'll have to
449  * find a means for maintaining per API call control
450  * information.
451  */
452 int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
453 {
454         LDAPControl *const *c;
455
456         assert( ld != NULL );
457         assert( LDAP_VALID(ld) );
458
459         if( ctrls == NULL ) {
460                 /* use default server controls */
461                 ctrls = ld->ld_cctrls;
462         }
463
464         if( ctrls == NULL || *ctrls == NULL ) {
465                 return LDAP_SUCCESS;
466         }
467
468         for( c = ctrls ; *c != NULL; c++ ) {
469                 if( (*c)->ldctl_iscritical ) {
470                         ld->ld_errno = LDAP_NOT_SUPPORTED;
471                         return ld->ld_errno;
472                 }
473         }
474
475         return LDAP_SUCCESS;
476 }