1 /*	$NetBSD: controls.c,v 1.1.1.3 2010/12/12 15:21:30 adam Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/libraries/libldap/controls.c,v 1.48.2.7 2010/04/13 20:22:56 kurt Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2010 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* This notice applies to changes, created by or for Novell, Inc.,
18  * to preexisting works for which notices appear elsewhere in this file.
19  *
20  * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
21  *
22  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
23  * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
24  * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
25  * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
26  * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
27  * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
28  * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
29  * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
30  *---
31  * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
32  * can be found in the file "build/LICENSE-2.0.1" in this distribution
33  * of OpenLDAP Software.
34  */
35 
36 #include "portable.h"
37 
38 #include <ac/stdlib.h>
39 
40 #include <ac/time.h>
41 #include <ac/string.h>
42 
43 #include "ldap-int.h"
44 
45 /* LDAPv3 Controls (RFC 4511)
46  *
47  *	Controls ::= SEQUENCE OF control Control
48  *
49  *	Control ::= SEQUENCE {
50  *		controlType		LDAPOID,
51  *		criticality		BOOLEAN DEFAULT FALSE,
52  *		controlValue	OCTET STRING OPTIONAL
53  *	}
54  */
55 
56 int
57 ldap_pvt_put_control(
58 	const LDAPControl *c,
59 	BerElement *ber )
60 {
61 	if ( ber_printf( ber, "{s" /*}*/, c->ldctl_oid ) == -1 ) {
62 		return LDAP_ENCODING_ERROR;
63 	}
64 
65 	if ( c->ldctl_iscritical /* only if true */
66 		&&  ( ber_printf( ber, "b",
67 			(ber_int_t) c->ldctl_iscritical ) == -1 ) )
68 	{
69 		return LDAP_ENCODING_ERROR;
70 	}
71 
72 	if ( !BER_BVISNULL( &c->ldctl_value ) /* only if we have a value */
73 		&&  ( ber_printf( ber, "O", &c->ldctl_value ) == -1 ) )
74 	{
75 		return LDAP_ENCODING_ERROR;
76 	}
77 
78 	if ( ber_printf( ber, /*{*/"N}" ) == -1 ) {
79 		return LDAP_ENCODING_ERROR;
80 	}
81 
82 	return LDAP_SUCCESS;
83 }
84 
85 
86 /*
87  * ldap_int_put_controls
88  */
89 
90 int
91 ldap_int_put_controls(
92 	LDAP *ld,
93 	LDAPControl *const *ctrls,
94 	BerElement *ber )
95 {
96 	LDAPControl *const *c;
97 
98 	assert( ld != NULL );
99 	assert( LDAP_VALID( ld ) );
100 	assert( ber != NULL );
101 
102 	if( ctrls == NULL ) {
103 		/* use default server controls */
104 		ctrls = ld->ld_sctrls;
105 	}
106 
107 	if( ctrls == NULL || *ctrls == NULL ) {
108 		return LDAP_SUCCESS;
109 	}
110 
111 	if ( ld->ld_version < LDAP_VERSION3 ) {
112 		/* LDAPv2 doesn't support controls,
113 		 * error if any control is critical
114 		 */
115 		for( c = ctrls ; *c != NULL; c++ ) {
116 			if( (*c)->ldctl_iscritical ) {
117 				ld->ld_errno = LDAP_NOT_SUPPORTED;
118 				return ld->ld_errno;
119 			}
120 		}
121 
122 		return LDAP_SUCCESS;
123 	}
124 
125 	/* Controls are encoded as a sequence of sequences */
126 	if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) {
127 		ld->ld_errno = LDAP_ENCODING_ERROR;
128 		return ld->ld_errno;
129 	}
130 
131 	for( c = ctrls ; *c != NULL; c++ ) {
132 		ld->ld_errno = ldap_pvt_put_control( *c, ber );
133 		if ( ld->ld_errno != LDAP_SUCCESS ) {
134 			return ld->ld_errno;
135 		}
136 	}
137 
138 
139 	if( ber_printf( ber, /*{*/ "}" ) == -1 ) {
140 		ld->ld_errno = LDAP_ENCODING_ERROR;
141 		return ld->ld_errno;
142 	}
143 
144 	return LDAP_SUCCESS;
145 }
146 
147 int ldap_pvt_get_controls(
148 	BerElement *ber,
149 	LDAPControl ***ctrls )
150 {
151 	int nctrls;
152 	ber_tag_t tag;
153 	ber_len_t len;
154 	char *opaque;
155 
156 	assert( ber != NULL );
157 
158 	if( ctrls == NULL ) {
159 		return LDAP_SUCCESS;
160 	}
161 	*ctrls = NULL;
162 
163 	len = ber_pvt_ber_remaining( ber );
164 
165 	if( len == 0) {
166 		/* no controls */
167 		return LDAP_SUCCESS;
168 	}
169 
170 	if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
171 		if( tag == LBER_ERROR ) {
172 			/* decoding error */
173 			return LDAP_DECODING_ERROR;
174 		}
175 
176 		/* ignore unexpected input */
177 		return LDAP_SUCCESS;
178 	}
179 
180 	/* set through each element */
181 	nctrls = 0;
182 	*ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) );
183 
184 	if( *ctrls == NULL ) {
185 		return LDAP_NO_MEMORY;
186 	}
187 
188 	*ctrls[nctrls] = NULL;
189 
190 	for( tag = ber_first_element( ber, &len, &opaque );
191 		tag != LBER_ERROR;
192 		tag = ber_next_element( ber, &len, opaque ) )
193 	{
194 		LDAPControl *tctrl;
195 		LDAPControl **tctrls;
196 
197 		tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) );
198 
199 		/* allocate pointer space for current controls (nctrls)
200 		 * + this control + extra NULL
201 		 */
202 		tctrls = (tctrl == NULL) ? NULL :
203 			LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
204 
205 		if( tctrls == NULL ) {
206 			/* one of the above allocation failed */
207 
208 			if( tctrl != NULL ) {
209 				LDAP_FREE( tctrl );
210 			}
211 
212 			ldap_controls_free(*ctrls);
213 			*ctrls = NULL;
214 
215 			return LDAP_NO_MEMORY;
216 		}
217 
218 
219 		tctrls[nctrls++] = tctrl;
220 		tctrls[nctrls] = NULL;
221 
222 		tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
223 
224 		if( tag == LBER_ERROR ) {
225 			*ctrls = NULL;
226 			ldap_controls_free( tctrls );
227 			return LDAP_DECODING_ERROR;
228 		}
229 
230 		tag = ber_peek_tag( ber, &len );
231 
232 		if( tag == LBER_BOOLEAN ) {
233 			ber_int_t crit;
234 			tag = ber_scanf( ber, "b", &crit );
235 			tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
236 			tag = ber_peek_tag( ber, &len );
237 		}
238 
239 		if( tag == LBER_OCTETSTRING ) {
240 			tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
241 		} else {
242 			BER_BVZERO( &tctrl->ldctl_value );
243 		}
244 
245 		*ctrls = tctrls;
246 	}
247 
248 	return LDAP_SUCCESS;
249 }
250 
251 /*
252  * Free a LDAPControl
253  */
254 void
255 ldap_control_free( LDAPControl *c )
256 {
257 	LDAP_MEMORY_DEBUG_ASSERT( c != NULL );
258 
259 	if ( c != NULL ) {
260 		if( c->ldctl_oid != NULL) {
261 			LDAP_FREE( c->ldctl_oid );
262 		}
263 
264 		if( c->ldctl_value.bv_val != NULL ) {
265 			LDAP_FREE( c->ldctl_value.bv_val );
266 		}
267 
268 		LDAP_FREE( c );
269 	}
270 }
271 
272 /*
273  * Free an array of LDAPControl's
274  */
275 void
276 ldap_controls_free( LDAPControl **controls )
277 {
278 	LDAP_MEMORY_DEBUG_ASSERT( controls != NULL );
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 || c->ldctl_oid == NULL ) {
343 		return NULL;
344 	}
345 
346 	new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
347 
348 	if( new == NULL ) {
349 		return NULL;
350 	}
351 
352 	new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
353 
354 	if(new->ldctl_oid == NULL) {
355 		LDAP_FREE( new );
356 		return NULL;
357 	}
358 
359 	if( c->ldctl_value.bv_val != NULL ) {
360 		new->ldctl_value.bv_val =
361 			(char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 );
362 
363 		if(new->ldctl_value.bv_val == NULL) {
364 			if(new->ldctl_oid != NULL) {
365 				LDAP_FREE( new->ldctl_oid );
366 			}
367 			LDAP_FREE( new );
368 			return NULL;
369 		}
370 
371 		new->ldctl_value.bv_len = c->ldctl_value.bv_len;
372 
373 		AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val,
374 			c->ldctl_value.bv_len );
375 
376 		new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0';
377 
378 	} else {
379 		new->ldctl_value.bv_len = 0;
380 		new->ldctl_value.bv_val = NULL;
381 	}
382 
383 	new->ldctl_iscritical = c->ldctl_iscritical;
384 	return new;
385 }
386 
387 /*
388  * Find a LDAPControl - deprecated
389  */
390 LDAPControl *
391 ldap_find_control(
392 	LDAP_CONST char *oid,
393 	LDAPControl **ctrls )
394 {
395 	if( ctrls == NULL || *ctrls == NULL ) {
396 		return NULL;
397 	}
398 
399 	for( ; *ctrls != NULL; ctrls++ ) {
400 		if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
401 			return *ctrls;
402 		}
403 	}
404 
405 	return NULL;
406 }
407 
408 /*
409  * Find a LDAPControl
410  */
411 LDAPControl *
412 ldap_control_find(
413 	LDAP_CONST char *oid,
414 	LDAPControl **ctrls,
415 	LDAPControl ***nextctrlp )
416 {
417 	if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) {
418 		return NULL;
419 	}
420 
421 	for( ; *ctrls != NULL; ctrls++ ) {
422 		if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
423 			if ( nextctrlp != NULL ) {
424 				*nextctrlp = ctrls + 1;
425 			}
426 
427 			return *ctrls;
428 		}
429 	}
430 
431 	if ( nextctrlp != NULL ) {
432 		*nextctrlp = NULL;
433 	}
434 
435 	return NULL;
436 }
437 
438 /*
439  * Create a LDAPControl, optionally from ber - deprecated
440  */
441 int
442 ldap_create_control(
443 	LDAP_CONST char *requestOID,
444 	BerElement *ber,
445 	int iscritical,
446 	LDAPControl **ctrlp )
447 {
448 	LDAPControl *ctrl;
449 
450 	assert( requestOID != NULL );
451 	assert( ctrlp != NULL );
452 
453 	ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
454 	if ( ctrl == NULL ) {
455 		return LDAP_NO_MEMORY;
456 	}
457 
458 	BER_BVZERO(&ctrl->ldctl_value);
459 	if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) {
460 		LDAP_FREE( ctrl );
461 		return LDAP_NO_MEMORY;
462 	}
463 
464 	ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
465 	ctrl->ldctl_iscritical = iscritical;
466 
467 	if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) {
468 		ldap_control_free( ctrl );
469 		return LDAP_NO_MEMORY;
470 	}
471 
472 	*ctrlp = ctrl;
473 	return LDAP_SUCCESS;
474 }
475 
476 /*
477  * Create a LDAPControl, optionally from value
478  */
479 int
480 ldap_control_create(
481 	LDAP_CONST char *requestOID,
482 	int iscritical,
483 	struct berval *value,
484 	int dupval,
485 	LDAPControl **ctrlp )
486 {
487 	LDAPControl *ctrl;
488 
489 	assert( requestOID != NULL );
490 	assert( ctrlp != NULL );
491 
492 	ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 );
493 	if ( ctrl == NULL ) {
494 		return LDAP_NO_MEMORY;
495 	}
496 
497 	ctrl->ldctl_iscritical = iscritical;
498 	if ( requestOID != NULL ) {
499 		ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
500 		if ( ctrl->ldctl_oid == NULL ) {
501 			ldap_control_free( ctrl );
502 			return LDAP_NO_MEMORY;
503 		}
504 	}
505 
506 	if ( value && !BER_BVISNULL( value ) ) {
507 		if ( dupval ) {
508 			ber_dupbv( &ctrl->ldctl_value, value );
509 			if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
510 				ldap_control_free( ctrl );
511 				return LDAP_NO_MEMORY;
512 			}
513 
514 		} else {
515 			ctrl->ldctl_value = *value;
516 		}
517 	}
518 
519 	*ctrlp = ctrl;
520 
521 	return LDAP_SUCCESS;
522 }
523 
524 /*
525  * check for critical client controls and bitch if present
526  * if we ever support critical controls, we'll have to
527  * find a means for maintaining per API call control
528  * information.
529  */
530 int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
531 {
532 	LDAPControl *const *c;
533 
534 	assert( ld != NULL );
535 	assert( LDAP_VALID( ld ) );
536 
537 	if( ctrls == NULL ) {
538 		/* use default server controls */
539 		ctrls = ld->ld_cctrls;
540 	}
541 
542 	if( ctrls == NULL || *ctrls == NULL ) {
543 		return LDAP_SUCCESS;
544 	}
545 
546 	for( c = ctrls ; *c != NULL; c++ ) {
547 		if( (*c)->ldctl_iscritical ) {
548 			ld->ld_errno = LDAP_NOT_SUPPORTED;
549 			return ld->ld_errno;
550 		}
551 	}
552 
553 	return LDAP_SUCCESS;
554 }
555