xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/controls.c (revision b5677b36047b601b9addaaa494a58ceae82c2a6c)
1 /* $OpenLDAP: pkg/ldap/libraries/libldap/controls.c,v 1.48.2.5 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2008 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 || c->ldctl_oid == NULL ) {
341 		return NULL;
342 	}
343 
344 	new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
345 
346 	if( new == NULL ) {
347 		return NULL;
348 	}
349 
350 	new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
351 
352 	if(new->ldctl_oid == NULL) {
353 		LDAP_FREE( new );
354 		return 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 }
553