1 #pragma ident "%Z%%M% %I% %E% SMI"
3 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.0 (the "NPL"); you may not use this file except in
7 * compliance with the NPL. You may obtain a copy of the NPL at
8 * http://www.mozilla.org/NPL/
10 * Software distributed under the NPL is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
12 * for the specific language governing rights and limitations under the
15 * The Initial Developer of this code under the NPL is Netscape
16 * Communications Corporation. Portions created by Netscape are
17 * Copyright (C) 1998 Netscape Communications Corporation. All Rights
20 /* control.c - routines to handle ldapv3 controls */
24 static LDAPControl
*ldap_control_dup( LDAPControl
*ctrl
);
25 static int ldap_control_copy_contents( LDAPControl
*ctrl_dst
,
26 LDAPControl
*ctrl_src
);
29 * Append a list of LDAPv3 controls to ber. If ctrls is NULL, use default
30 * set of controls from ld.
31 * Return an LDAP error code (LDAP_SUCCESS if all goes well).
32 * If closeseq is non-zero, we do an extra ber_put_seq() as well.
35 nsldapi_put_controls( LDAP
*ld
, LDAPControl
**ctrls
, int closeseq
,
41 rc
= LDAP_ENCODING_ERROR
; /* the most popular error */
43 /* if no controls were passed in, use global list from LDAP * */
44 LDAP_MUTEX_LOCK( ld
, LDAP_CTRL_LOCK
);
45 if ( ctrls
== NULL
) {
46 ctrls
= ld
->ld_servercontrols
;
49 /* if there are no controls then we are done */
50 if ( ctrls
== NULL
|| ctrls
[ 0 ] == NULL
) {
55 * If we're using LDAPv2 or earlier we can't send any controls, so
56 * we just ignore them unless one is marked critical, in which case
59 if ( NSLDAPI_LDAP_VERSION( ld
) < LDAP_VERSION3
) {
60 for ( i
= 0; ctrls
!= NULL
&& ctrls
[i
] != NULL
; i
++ ) {
61 if ( ctrls
[i
]->ldctl_iscritical
) {
62 rc
= LDAP_NOT_SUPPORTED
;
70 * encode the controls as a Sequence of Sequence
72 if ( ber_printf( ber
, "t{", LDAP_TAG_CONTROLS
) == -1 ) {
76 for ( i
= 0; ctrls
[i
] != NULL
; i
++ ) {
79 if ( ber_printf( ber
, "{s", c
->ldctl_oid
) == -1 ) {
83 /* criticality is "BOOLEAN DEFAULT FALSE" */
84 /* therefore, it should only be encoded if it exists AND is TRUE */
85 if ( c
->ldctl_iscritical
) {
86 if ( ber_printf( ber
, "b", (int)c
->ldctl_iscritical
)
92 if ( c
->ldctl_value
.bv_val
!= NULL
) {
93 if ( ber_printf( ber
, "o", c
->ldctl_value
.bv_val
,
94 (int)c
->ldctl_value
.bv_len
/* XXX lossy cast */ )
100 if ( ber_put_seq( ber
) == -1 ) {
105 if ( ber_put_seq( ber
) == -1 ) {
110 LDAP_MUTEX_UNLOCK( ld
, LDAP_CTRL_LOCK
);
111 if ( closeseq
&& ber_put_seq( ber
) == -1 ) {
114 return( LDAP_SUCCESS
);
117 LDAP_MUTEX_UNLOCK( ld
, LDAP_CTRL_LOCK
);
118 LDAP_SET_LDERRNO( ld
, rc
, NULL
, NULL
);
124 * Pull controls out of "ber" (if any present) and return them in "controlsp."
125 * Returns an LDAP error code.
128 nsldapi_get_controls( BerElement
*ber
, LDAPControl
***controlsp
)
130 LDAPControl
*newctrl
;
133 int rc
, maxcontrols
, curcontrols
;
137 * Each LDAPMessage can have a set of controls appended
138 * to it. Controls are used to extend the functionality
139 * of an LDAP operation (e.g., add an attribute size limit
140 * to the search operation). These controls look like this:
142 * Controls ::= SEQUENCE OF Control
144 * Control ::= SEQUENCE {
145 * controlType LDAPOID,
146 * criticality BOOLEAN DEFAULT FALSE,
147 * controlValue OCTET STRING
150 LDAPDebug( LDAP_DEBUG_TRACE
, "=> nsldapi_get_controls\n", 0, 0, 0 );
155 * check to see if controls were included
157 if ( ber_get_option( ber
, LBER_OPT_REMAINING_BYTES
, &len
) != 0 ) {
158 return( LDAP_DECODING_ERROR
); /* unexpected error */
161 LDAPDebug( LDAP_DEBUG_TRACE
,
162 "<= nsldapi_get_controls no controls\n", 0, 0, 0 );
163 return( LDAP_SUCCESS
); /* no controls */
165 if (( tag
= ber_peek_tag( ber
, &len
)) != LDAP_TAG_CONTROLS
) {
166 if ( tag
== LBER_ERROR
) {
167 LDAPDebug( LDAP_DEBUG_TRACE
,
168 "<= nsldapi_get_controls LDAP_PROTOCOL_ERROR\n",
170 return( LDAP_DECODING_ERROR
); /* decoding error */
173 * We found something other than controls. This should never
174 * happen in LDAPv3, but we don't treat this is a hard error --
175 * we just ignore the extra stuff.
177 LDAPDebug( LDAP_DEBUG_TRACE
,
178 "<= nsldapi_get_controls ignoring unrecognized data in message (tag 0x%x)\n",
180 return( LDAP_SUCCESS
);
183 maxcontrols
= curcontrols
= 0;
184 for ( tag
= ber_first_element( ber
, &len
, &last
);
185 tag
!= LBER_ERROR
&& tag
!= LBER_END_OF_SEQORSET
;
186 tag
= ber_next_element( ber
, &len
, last
) ) {
187 if ( curcontrols
>= maxcontrols
- 1 ) {
188 #define CONTROL_GRABSIZE 5
189 maxcontrols
+= CONTROL_GRABSIZE
;
190 *controlsp
= (struct ldapcontrol
**)NSLDAPI_REALLOC(
191 (char *)*controlsp
, maxcontrols
*
192 sizeof(struct ldapcontrol
*) );
193 if ( *controlsp
== NULL
) {
195 goto free_and_return
;
198 if (( newctrl
= (struct ldapcontrol
*)NSLDAPI_CALLOC( 1,
199 sizeof(LDAPControl
))) == NULL
) {
201 goto free_and_return
;
204 (*controlsp
)[curcontrols
++] = newctrl
;
205 (*controlsp
)[curcontrols
] = NULL
;
207 if ( ber_scanf( ber
, "{a", &newctrl
->ldctl_oid
)
209 rc
= LDAP_DECODING_ERROR
;
210 goto free_and_return
;
213 /* the criticality is optional */
214 if ( ber_peek_tag( ber
, &len
) == LBER_BOOLEAN
) {
217 if ( ber_scanf( ber
, "b", &aint
) == LBER_ERROR
) {
218 rc
= LDAP_DECODING_ERROR
;
219 goto free_and_return
;
221 newctrl
->ldctl_iscritical
= (char)aint
; /* XXX lossy cast */
223 /* absent is synonomous with FALSE */
224 newctrl
->ldctl_iscritical
= 0;
227 /* the control value is optional */
228 if ( ber_peek_tag( ber
, &len
) == LBER_OCTETSTRING
) {
229 if ( ber_scanf( ber
, "o", &newctrl
->ldctl_value
)
231 rc
= LDAP_DECODING_ERROR
;
232 goto free_and_return
;
235 (newctrl
->ldctl_value
).bv_val
= NULL
;
236 (newctrl
->ldctl_value
).bv_len
= 0;
241 if ( tag
== LBER_ERROR
) {
242 rc
= LDAP_DECODING_ERROR
;
243 goto free_and_return
;
246 LDAPDebug( LDAP_DEBUG_TRACE
,
247 "<= nsldapi_get_controls found %d controls\n", curcontrols
, 0, 0 );
248 return( LDAP_SUCCESS
);
251 ldap_controls_free( *controlsp
);
253 LDAPDebug( LDAP_DEBUG_TRACE
,
254 "<= nsldapi_get_controls error 0x%x\n", rc
, 0, 0 );
261 ldap_control_free( LDAPControl
*ctrl
)
263 if ( ctrl
!= NULL
) {
264 if ( ctrl
->ldctl_oid
!= NULL
) {
265 NSLDAPI_FREE( ctrl
->ldctl_oid
);
267 if ( ctrl
->ldctl_value
.bv_val
!= NULL
) {
268 NSLDAPI_FREE( ctrl
->ldctl_value
.bv_val
);
270 NSLDAPI_FREE( (char *)ctrl
);
277 ldap_controls_free( LDAPControl
**ctrls
)
281 if ( ctrls
!= NULL
) {
282 for ( i
= 0; ctrls
[i
] != NULL
; i
++ ) {
283 ldap_control_free( ctrls
[i
] );
285 NSLDAPI_FREE( (char *)ctrls
);
294 ldap_control_append( LDAPControl
**ctrl_src
, LDAPControl
*ctrl
)
303 /* Count the existing controls */
304 if ( NULL
!= ctrl_src
) {
305 while( NULL
!= ctrl_src
[nctrls
] ) {
310 /* allocate the new control structure */
311 if ( ( ctrlp
= (LDAPControl
**)NSLDAPI_MALLOC( sizeof(LDAPControl
*)
312 * (nctrls
+ 2) ) ) == NULL
) {
315 memset( ctrlp
, 0, sizeof(*ctrlp
) * (nctrls
+ 2) );
317 for( i
= 0; i
< (nctrls
+ 1); i
++ ) {
319 ctrlp
[i
] = ldap_control_dup( ctrl_src
[i
] );
321 ctrlp
[i
] = ldap_control_dup( ctrl
);
323 if ( NULL
== ctrlp
[i
] ) {
324 ldap_controls_free( ctrlp
);
334 * Replace *ldctrls with a copy of newctrls.
335 * returns 0 if successful.
336 * return -1 if not and set error code inside LDAP *ld.
339 nsldapi_dup_controls( LDAP
*ld
, LDAPControl
***ldctrls
, LDAPControl
**newctrls
)
343 if ( *ldctrls
!= NULL
) {
344 ldap_controls_free( *ldctrls
);
347 if ( newctrls
== NULL
|| newctrls
[0] == NULL
) {
352 for ( count
= 0; newctrls
[ count
] != NULL
; ++count
) {
356 if (( *ldctrls
= (LDAPControl
**)NSLDAPI_MALLOC(( count
+ 1 ) *
357 sizeof( LDAPControl
*))) == NULL
) {
358 LDAP_SET_LDERRNO( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
361 (*ldctrls
)[ count
] = NULL
;
363 for ( count
= 0; newctrls
[ count
] != NULL
; ++count
) {
364 if (( (*ldctrls
)[ count
] =
365 ldap_control_dup( newctrls
[ count
] )) == NULL
) {
366 ldap_controls_free( *ldctrls
);
368 LDAP_SET_LDERRNO( ld
, LDAP_NO_MEMORY
, NULL
, NULL
);
378 * return a malloc'd copy of "ctrl" (NULL if memory allocation fails)
381 /* LDAP_CALL */ /* keep this routine internal for now */
382 ldap_control_dup( LDAPControl
*ctrl
)
386 if (( rctrl
= (LDAPControl
*)NSLDAPI_MALLOC( sizeof( LDAPControl
)))
391 if ( ldap_control_copy_contents( rctrl
, ctrl
) != LDAP_SUCCESS
) {
392 NSLDAPI_FREE( rctrl
);
401 * duplicate the contents of "ctrl_src" and place in "ctrl_dst"
404 /* LDAP_CALL */ /* keep this routine internal for now */
405 ldap_control_copy_contents( LDAPControl
*ctrl_dst
, LDAPControl
*ctrl_src
)
409 if ( NULL
== ctrl_dst
|| NULL
== ctrl_src
) {
410 return( LDAP_PARAM_ERROR
);
413 ctrl_dst
->ldctl_iscritical
= ctrl_src
->ldctl_iscritical
;
415 /* fill in the fields of this new control */
416 if (( ctrl_dst
->ldctl_oid
= nsldapi_strdup( ctrl_src
->ldctl_oid
))
418 return( LDAP_NO_MEMORY
);
421 len
= (size_t)(ctrl_src
->ldctl_value
).bv_len
;
422 if ( ctrl_src
->ldctl_value
.bv_val
== NULL
|| len
<= 0 ) {
423 ctrl_dst
->ldctl_value
.bv_len
= 0;
424 ctrl_dst
->ldctl_value
.bv_val
= NULL
;
426 ctrl_dst
->ldctl_value
.bv_len
= len
;
427 if (( ctrl_dst
->ldctl_value
.bv_val
= NSLDAPI_MALLOC( len
))
429 NSLDAPI_FREE( ctrl_dst
->ldctl_oid
);
430 return( LDAP_NO_MEMORY
);
432 SAFEMEMCPY( ctrl_dst
->ldctl_value
.bv_val
,
433 ctrl_src
->ldctl_value
.bv_val
, len
);
436 return ( LDAP_SUCCESS
);
442 * build an allocated LDAPv3 control. Returns an LDAP error code.
445 nsldapi_build_control( char *oid
, BerElement
*ber
, int freeber
, char iscritical
,
446 LDAPControl
**ctrlp
)
454 /* allocate struct berval with contents of the BER encoding */
455 rc
= ber_flatten( ber
, &bvp
);
460 return( LDAP_NO_MEMORY
);
464 /* allocate the new control structure */
465 if (( *ctrlp
= (LDAPControl
*)NSLDAPI_MALLOC( sizeof(LDAPControl
)))
470 return( LDAP_NO_MEMORY
);
473 /* fill in the fields of this new control */
474 (*ctrlp
)->ldctl_iscritical
= iscritical
;
475 if (( (*ctrlp
)->ldctl_oid
= nsldapi_strdup( oid
)) == NULL
) {
476 NSLDAPI_FREE( *ctrlp
);
480 return( LDAP_NO_MEMORY
);
484 (*ctrlp
)->ldctl_value
.bv_len
= 0;
485 (*ctrlp
)->ldctl_value
.bv_val
= NULL
;
487 (*ctrlp
)->ldctl_value
= *bvp
; /* struct copy */
488 NSLDAPI_FREE( bvp
); /* free container, not contents! */
491 return( LDAP_SUCCESS
);