]> git.sur5r.net Git - openldap/blob - libraries/libldap/controls.c
f803b000be6c638dcfa0218b7bac9b2e4f4d2868
[openldap] / libraries / libldap / controls.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2005 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 /* Portions Copyright (C) The Internet Society (1997)
34  * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
35  */
36
37 /* LDAPv3 Controls (RFC2251)
38  *
39  *      Controls ::= SEQUENCE OF Control  
40  *
41  *      Control ::= SEQUENCE { 
42  *              controlType             LDAPOID,
43  *              criticality             BOOLEAN DEFAULT FALSE,
44  *              controlValue    OCTET STRING OPTIONAL
45  *      }
46  */
47
48 #include "portable.h"
49
50 #include <ac/stdlib.h>
51
52 #include <ac/time.h>
53 #include <ac/string.h>
54
55 #include "ldap-int.h"
56
57
58 /*
59  * ldap_int_put_controls
60  */
61
62 int
63 ldap_int_put_controls(
64         LDAP *ld,
65         LDAPControl *const *ctrls,
66         BerElement *ber )
67 {
68         LDAPControl *const *c;
69
70         assert( ld != NULL );
71         assert( LDAP_VALID( ld ) );
72         assert( ber != NULL );
73
74         if( ctrls == NULL ) {
75                 /* use default server controls */
76                 ctrls = ld->ld_sctrls;
77         }
78
79         if( ctrls == NULL || *ctrls == NULL ) {
80                 return LDAP_SUCCESS;
81         }
82
83         if ( ld->ld_version < LDAP_VERSION3 ) {
84                 /* LDAPv2 doesn't support controls,
85                  * error if any control is critical
86                  */
87                 for( c = ctrls ; *c != NULL; c++ ) {
88                         if( (*c)->ldctl_iscritical ) {
89                                 ld->ld_errno = LDAP_NOT_SUPPORTED;
90                                 return ld->ld_errno;
91                         }
92                 }
93
94                 return LDAP_SUCCESS;
95         }
96
97         /* Controls are encoded as a sequence of sequences */
98         if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) {
99                 ld->ld_errno = LDAP_ENCODING_ERROR;
100                 return ld->ld_errno;
101         }
102
103         for( c = ctrls ; *c != NULL; c++ ) {
104                 if ( ber_printf( ber, "{s" /*}*/,
105                         (*c)->ldctl_oid ) == -1 )
106                 {
107                         ld->ld_errno = LDAP_ENCODING_ERROR;
108                         return ld->ld_errno;
109                 }
110
111                 if( (*c)->ldctl_iscritical /* only if true */
112                         &&  ( ber_printf( ber, "b",
113                                 (ber_int_t) (*c)->ldctl_iscritical ) == -1 ) )
114                 {
115                         ld->ld_errno = LDAP_ENCODING_ERROR;
116                         return ld->ld_errno;
117                 }
118
119                 if( (*c)->ldctl_value.bv_val != NULL /* only if we have a value */
120                         &&  ( ber_printf( ber, "O",
121                                 &((*c)->ldctl_value) ) == -1 ) )
122                 {
123                         ld->ld_errno = LDAP_ENCODING_ERROR;
124                         return ld->ld_errno;
125                 }
126
127
128                 if( ber_printf( ber, /*{*/"N}" ) == -1 ) {
129                         ld->ld_errno = LDAP_ENCODING_ERROR;
130                         return ld->ld_errno;
131                 }
132         }
133
134
135         if( ber_printf( ber, /*{*/ "}" ) == -1 ) {
136                 ld->ld_errno = LDAP_ENCODING_ERROR;
137                 return ld->ld_errno;
138         }
139
140         return LDAP_SUCCESS;
141 }
142
143 int ldap_pvt_get_controls(
144         BerElement *ber,
145         LDAPControl ***ctrls )
146 {
147         int nctrls;
148         ber_tag_t tag;
149         ber_len_t len;
150         char *opaque;
151
152         assert( ber != NULL );
153
154         if( ctrls == NULL ) {
155                 return LDAP_SUCCESS;
156         }
157         *ctrls = NULL;
158
159         len = ber_pvt_ber_remaining( ber );
160
161         if( len == 0) {
162                 /* no controls */
163                 return LDAP_SUCCESS;
164         }
165
166         if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
167                 if( tag == LBER_ERROR ) {
168                         /* decoding error */
169                         return LDAP_DECODING_ERROR;
170                 }
171
172                 /* ignore unexpected input */
173                 return LDAP_SUCCESS;
174         }
175
176         /* set through each element */
177         nctrls = 0;
178         *ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) );
179
180         if( *ctrls == NULL ) {
181                 return LDAP_NO_MEMORY;
182         }
183
184         *ctrls[nctrls] = NULL;
185
186         for( tag = ber_first_element( ber, &len, &opaque );
187                 tag != LBER_ERROR;
188                 tag = ber_next_element( ber, &len, opaque ) )
189         {
190                 LDAPControl *tctrl;
191                 LDAPControl **tctrls;
192
193                 tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) );
194
195                 /* allocate pointer space for current controls (nctrls)
196                  * + this control + extra NULL
197                  */
198                 tctrls = (tctrl == NULL) ? NULL :
199                         LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
200
201                 if( tctrls == NULL ) {
202                         /* one of the above allocation failed */
203
204                         if( tctrl != NULL ) {
205                                 LDAP_FREE( tctrl );
206                         }
207
208                         ldap_controls_free(*ctrls);
209                         *ctrls = NULL;
210
211                         return LDAP_NO_MEMORY;
212                 }
213
214
215                 tctrls[nctrls++] = tctrl;
216                 tctrls[nctrls] = NULL;
217
218                 tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
219
220                 if( tag == LBER_ERROR ) {
221                         *ctrls = NULL;
222                         ldap_controls_free( tctrls );
223                         return LDAP_DECODING_ERROR;
224                 }
225
226                 tag = ber_peek_tag( ber, &len );
227
228                 if( tag == LBER_BOOLEAN ) {
229                         ber_int_t crit;
230                         tag = ber_scanf( ber, "b", &crit );
231                         tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
232                         tag = ber_peek_tag( ber, &len );
233                 }
234
235                 if( tag == LBER_OCTETSTRING ) {
236                         tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
237                 } else {
238                         tctrl->ldctl_value.bv_val = NULL;
239                 }
240
241                 *ctrls = tctrls;
242         }
243                 
244         return LDAP_SUCCESS;
245 }
246
247 /*
248  * Free a LDAPControl
249  */
250 void
251 ldap_control_free( LDAPControl *c )
252 {
253 #ifdef LDAP_MEMORY_DEBUG
254         assert( c != NULL );
255 #endif
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 #ifdef LDAP_MEMORY_DEBUG
277         assert( controls != NULL );
278 #endif
279
280         if ( controls != NULL ) {
281                 int i;
282
283                 for( i=0; controls[i] != NULL; i++) {
284                         ldap_control_free( controls[i] );
285                 }
286
287                 LDAP_FREE( controls );
288         }
289 }
290
291 /*
292  * Duplicate an array of LDAPControl
293  */
294 LDAPControl **
295 ldap_controls_dup( LDAPControl *const *controls )
296 {
297         LDAPControl **new;
298         int i;
299
300         if ( controls == NULL ) {
301                 return NULL;
302         }
303
304         /* count the controls */
305         for(i=0; controls[i] != NULL; i++) /* empty */ ;
306
307         if( i < 1 ) {
308                 /* no controls to duplicate */
309                 return NULL;
310         }
311
312         new = (LDAPControl **) LDAP_MALLOC( (i+1) * sizeof(LDAPControl *) );
313
314         if( new == NULL ) {
315                 /* memory allocation failure */
316                 return NULL;
317         }
318
319         /* duplicate the controls */
320         for(i=0; controls[i] != NULL; i++) {
321                 new[i] = ldap_control_dup( controls[i] );
322
323                 if( new[i] == NULL ) {
324                         ldap_controls_free( new );
325                         return NULL;
326                 }
327         }
328
329         new[i] = NULL;
330
331         return new;
332 }
333
334 /*
335  * Duplicate a LDAPControl
336  */
337 LDAPControl *
338 ldap_control_dup( const LDAPControl *c )
339 {
340         LDAPControl *new;
341
342         if ( c == NULL ) {
343                 return NULL;
344         }
345
346         new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
347
348         if( new == NULL ) {
349                 return NULL;
350         }
351
352         if( c->ldctl_oid != NULL ) {
353                 new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
354
355                 if(new->ldctl_oid == NULL) {
356                         LDAP_FREE( new );
357                         return NULL;
358                 }
359
360         } else {
361                 new->ldctl_oid = NULL;
362         }
363
364         if( c->ldctl_value.bv_val != NULL ) {
365                 new->ldctl_value.bv_val =
366                         (char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 );
367
368                 if(new->ldctl_value.bv_val == NULL) {
369                         if(new->ldctl_oid != NULL) {
370                                 LDAP_FREE( new->ldctl_oid );
371                         }
372                         LDAP_FREE( new );
373                         return NULL;
374                 }
375                 
376                 new->ldctl_value.bv_len = c->ldctl_value.bv_len;
377
378                 AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val, 
379                         c->ldctl_value.bv_len );
380
381                 new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0';
382
383         } else {
384                 new->ldctl_value.bv_len = 0;
385                 new->ldctl_value.bv_val = NULL;
386         }
387
388         new->ldctl_iscritical = c->ldctl_iscritical;
389         return new;
390 }
391
392
393 LDAPControl *
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    ldap_create_control
413    
414    Internal function to create an LDAP control from the encoded BerElement.
415
416    requestOID  (IN) The OID to use in creating the control.
417    
418    ber         (IN) The encoded BerElement to use in creating the control.
419    
420    iscritical  (IN) 0 - Indicates the control is not critical to the operation.
421                                         non-zero - The control is critical to the operation.
422                                   
423    ctrlp      (OUT) Returns a pointer to the LDAPControl created.  This control
424                                         SHOULD be freed by calling ldap_control_free() when done.
425 ---*/
426
427 int
428 ldap_create_control(
429         LDAP_CONST char *requestOID,
430         BerElement *ber,
431         int iscritical,
432         LDAPControl **ctrlp )
433 {
434         LDAPControl *ctrl;
435
436         assert( requestOID != NULL );
437         assert( ber != NULL );
438         assert( ctrlp != NULL );
439
440         ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
441         if ( ctrl == NULL ) {
442                 return LDAP_NO_MEMORY;
443         }
444
445         if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
446                 LDAP_FREE( ctrl );
447                 return LDAP_NO_MEMORY;
448         }
449
450         ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
451         ctrl->ldctl_iscritical = iscritical;
452
453         if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) {
454                 ldap_control_free( ctrl );
455                 return LDAP_NO_MEMORY;
456         }
457
458         *ctrlp = ctrl;
459         return LDAP_SUCCESS;
460 }
461
462 /*
463  * check for critical client controls and bitch if present
464  * if we ever support critical controls, we'll have to
465  * find a means for maintaining per API call control
466  * information.
467  */
468 int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
469 {
470         LDAPControl *const *c;
471
472         assert( ld != NULL );
473         assert( LDAP_VALID( ld ) );
474
475         if( ctrls == NULL ) {
476                 /* use default server controls */
477                 ctrls = ld->ld_cctrls;
478         }
479
480         if( ctrls == NULL || *ctrls == NULL ) {
481                 return LDAP_SUCCESS;
482         }
483
484         for( c = ctrls ; *c != NULL; c++ ) {
485                 if( (*c)->ldctl_iscritical ) {
486                         ld->ld_errno = LDAP_NOT_SUPPORTED;
487                         return ld->ld_errno;
488                 }
489         }
490
491         return LDAP_SUCCESS;
492 }