1 /*	$NetBSD: controls.c,v 1.3 2021/08/14 16:14:55 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2021 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 <sys/cdefs.h>
37 __RCSID("$NetBSD: controls.c,v 1.3 2021/08/14 16:14:55 christos Exp $");
38 
39 #include "portable.h"
40 
41 #include <ac/stdlib.h>
42 
43 #include <ac/time.h>
44 #include <ac/string.h>
45 
46 #include "ldap-int.h"
47 
48 /* LDAPv3 Controls (RFC 4511)
49  *
50  *	Controls ::= SEQUENCE OF control Control
51  *
52  *	Control ::= SEQUENCE {
53  *		controlType		LDAPOID,
54  *		criticality		BOOLEAN DEFAULT FALSE,
55  *		controlValue	OCTET STRING OPTIONAL
56  *	}
57  */
58 
59 int
ldap_pvt_put_control(const LDAPControl * c,BerElement * ber)60 ldap_pvt_put_control(
61 	const LDAPControl *c,
62 	BerElement *ber )
63 {
64 	if ( ber_printf( ber, "{s" /*}*/, c->ldctl_oid ) == -1 ) {
65 		return LDAP_ENCODING_ERROR;
66 	}
67 
68 	if ( c->ldctl_iscritical /* only if true */
69 		&&  ( ber_printf( ber, "b",
70 			(ber_int_t) c->ldctl_iscritical ) == -1 ) )
71 	{
72 		return LDAP_ENCODING_ERROR;
73 	}
74 
75 	if ( !BER_BVISNULL( &c->ldctl_value ) /* only if we have a value */
76 		&&  ( ber_printf( ber, "O", &c->ldctl_value ) == -1 ) )
77 	{
78 		return LDAP_ENCODING_ERROR;
79 	}
80 
81 	if ( ber_printf( ber, /*{*/"N}" ) == -1 ) {
82 		return LDAP_ENCODING_ERROR;
83 	}
84 
85 	return LDAP_SUCCESS;
86 }
87 
88 
89 /*
90  * ldap_int_put_controls
91  */
92 
93 int
ldap_int_put_controls(LDAP * ld,LDAPControl * const * ctrls,BerElement * ber)94 ldap_int_put_controls(
95 	LDAP *ld,
96 	LDAPControl *const *ctrls,
97 	BerElement *ber )
98 {
99 	LDAPControl *const *c;
100 
101 	assert( ld != NULL );
102 	assert( LDAP_VALID( ld ) );
103 	assert( ber != NULL );
104 
105 	if( ctrls == NULL ) {
106 		/* use default server controls */
107 		ctrls = ld->ld_sctrls;
108 	}
109 
110 	if( ctrls == NULL || *ctrls == NULL ) {
111 		return LDAP_SUCCESS;
112 	}
113 
114 	if ( ld->ld_version < LDAP_VERSION3 ) {
115 		/* LDAPv2 doesn't support controls,
116 		 * error if any control is critical
117 		 */
118 		for( c = ctrls ; *c != NULL; c++ ) {
119 			if( (*c)->ldctl_iscritical ) {
120 				ld->ld_errno = LDAP_NOT_SUPPORTED;
121 				return ld->ld_errno;
122 			}
123 		}
124 
125 		return LDAP_SUCCESS;
126 	}
127 
128 	/* Controls are encoded as a sequence of sequences */
129 	if( ber_printf( ber, "t{"/*}*/, LDAP_TAG_CONTROLS ) == -1 ) {
130 		ld->ld_errno = LDAP_ENCODING_ERROR;
131 		return ld->ld_errno;
132 	}
133 
134 	for( c = ctrls ; *c != NULL; c++ ) {
135 		ld->ld_errno = ldap_pvt_put_control( *c, ber );
136 		if ( ld->ld_errno != LDAP_SUCCESS ) {
137 			return ld->ld_errno;
138 		}
139 	}
140 
141 
142 	if( ber_printf( ber, /*{*/ "}" ) == -1 ) {
143 		ld->ld_errno = LDAP_ENCODING_ERROR;
144 		return ld->ld_errno;
145 	}
146 
147 	return LDAP_SUCCESS;
148 }
149 
ldap_pvt_get_controls(BerElement * ber,LDAPControl *** ctrls)150 int ldap_pvt_get_controls(
151 	BerElement *ber,
152 	LDAPControl ***ctrls )
153 {
154 	int nctrls;
155 	ber_tag_t tag;
156 	ber_len_t len;
157 	char *opaque;
158 
159 	assert( ber != NULL );
160 
161 	if( ctrls == NULL ) {
162 		return LDAP_SUCCESS;
163 	}
164 	*ctrls = NULL;
165 
166 	len = ber_pvt_ber_remaining( ber );
167 
168 	if( len == 0) {
169 		/* no controls */
170 		return LDAP_SUCCESS;
171 	}
172 
173 	if(( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
174 		if( tag == LBER_ERROR ) {
175 			/* decoding error */
176 			return LDAP_DECODING_ERROR;
177 		}
178 
179 		/* ignore unexpected input */
180 		return LDAP_SUCCESS;
181 	}
182 
183 	/* set through each element */
184 	nctrls = 0;
185 	*ctrls = LDAP_MALLOC( 1 * sizeof(LDAPControl *) );
186 
187 	if( *ctrls == NULL ) {
188 		return LDAP_NO_MEMORY;
189 	}
190 
191 	*ctrls[nctrls] = NULL;
192 
193 	for( tag = ber_first_element( ber, &len, &opaque );
194 		tag != LBER_ERROR;
195 		tag = ber_next_element( ber, &len, opaque ) )
196 	{
197 		LDAPControl *tctrl;
198 		LDAPControl **tctrls;
199 
200 		tctrl = LDAP_CALLOC( 1, sizeof(LDAPControl) );
201 
202 		/* allocate pointer space for current controls (nctrls)
203 		 * + this control + extra NULL
204 		 */
205 		tctrls = (tctrl == NULL) ? NULL :
206 			LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
207 
208 		if( tctrls == NULL ) {
209 			/* one of the above allocation failed */
210 
211 			if( tctrl != NULL ) {
212 				LDAP_FREE( tctrl );
213 			}
214 
215 			ldap_controls_free(*ctrls);
216 			*ctrls = NULL;
217 
218 			return LDAP_NO_MEMORY;
219 		}
220 
221 
222 		tctrls[nctrls++] = tctrl;
223 		tctrls[nctrls] = NULL;
224 
225 		tag = ber_scanf( ber, "{a" /*}*/, &tctrl->ldctl_oid );
226 
227 		if( tag == LBER_ERROR ) {
228 			*ctrls = NULL;
229 			ldap_controls_free( tctrls );
230 			return LDAP_DECODING_ERROR;
231 		}
232 
233 		tag = ber_peek_tag( ber, &len );
234 
235 		if( tag == LBER_BOOLEAN ) {
236 			ber_int_t crit;
237 			tag = ber_scanf( ber, "b", &crit );
238 			tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
239 			tag = ber_peek_tag( ber, &len );
240 		}
241 
242 		if( tag == LBER_OCTETSTRING ) {
243 			tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
244 		} else {
245 			BER_BVZERO( &tctrl->ldctl_value );
246 		}
247 
248 		*ctrls = tctrls;
249 	}
250 
251 	return LDAP_SUCCESS;
252 }
253 
254 /*
255  * Free a LDAPControl
256  */
257 void
ldap_control_free(LDAPControl * c)258 ldap_control_free( LDAPControl *c )
259 {
260 	LDAP_MEMORY_DEBUG_ASSERT( c != NULL );
261 
262 	if ( c != NULL ) {
263 		if( c->ldctl_oid != NULL) {
264 			LDAP_FREE( c->ldctl_oid );
265 		}
266 
267 		if( c->ldctl_value.bv_val != NULL ) {
268 			LDAP_FREE( c->ldctl_value.bv_val );
269 		}
270 
271 		LDAP_FREE( c );
272 	}
273 }
274 
275 /*
276  * Free an array of LDAPControl's
277  */
278 void
ldap_controls_free(LDAPControl ** controls)279 ldap_controls_free( LDAPControl **controls )
280 {
281 	LDAP_MEMORY_DEBUG_ASSERT( controls != NULL );
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 **
ldap_controls_dup(LDAPControl * const * controls)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 *
ldap_control_dup(const LDAPControl * c)341 ldap_control_dup( const LDAPControl *c )
342 {
343 	LDAPControl *new;
344 
345 	if ( c == NULL || c->ldctl_oid == NULL ) {
346 		return NULL;
347 	}
348 
349 	new = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
350 
351 	if( new == NULL ) {
352 		return NULL;
353 	}
354 
355 	new->ldctl_oid = LDAP_STRDUP( c->ldctl_oid );
356 
357 	if(new->ldctl_oid == NULL) {
358 		LDAP_FREE( new );
359 		return NULL;
360 	}
361 
362 	if( c->ldctl_value.bv_val != NULL ) {
363 		new->ldctl_value.bv_val =
364 			(char *) LDAP_MALLOC( c->ldctl_value.bv_len + 1 );
365 
366 		if(new->ldctl_value.bv_val == NULL) {
367 			if(new->ldctl_oid != NULL) {
368 				LDAP_FREE( new->ldctl_oid );
369 			}
370 			LDAP_FREE( new );
371 			return NULL;
372 		}
373 
374 		new->ldctl_value.bv_len = c->ldctl_value.bv_len;
375 
376 		AC_MEMCPY( new->ldctl_value.bv_val, c->ldctl_value.bv_val,
377 			c->ldctl_value.bv_len );
378 
379 		new->ldctl_value.bv_val[new->ldctl_value.bv_len] = '\0';
380 
381 	} else {
382 		new->ldctl_value.bv_len = 0;
383 		new->ldctl_value.bv_val = NULL;
384 	}
385 
386 	new->ldctl_iscritical = c->ldctl_iscritical;
387 	return new;
388 }
389 
390 /*
391  * Find a LDAPControl - deprecated
392  */
393 LDAPControl *
ldap_find_control(LDAP_CONST char * oid,LDAPControl ** ctrls)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  * Find a LDAPControl
413  */
414 LDAPControl *
ldap_control_find(LDAP_CONST char * oid,LDAPControl ** ctrls,LDAPControl *** nextctrlp)415 ldap_control_find(
416 	LDAP_CONST char *oid,
417 	LDAPControl **ctrls,
418 	LDAPControl ***nextctrlp )
419 {
420 	if ( oid == NULL || ctrls == NULL || *ctrls == NULL ) {
421 		return NULL;
422 	}
423 
424 	for( ; *ctrls != NULL; ctrls++ ) {
425 		if( strcmp( (*ctrls)->ldctl_oid, oid ) == 0 ) {
426 			if ( nextctrlp != NULL ) {
427 				*nextctrlp = ctrls + 1;
428 			}
429 
430 			return *ctrls;
431 		}
432 	}
433 
434 	if ( nextctrlp != NULL ) {
435 		*nextctrlp = NULL;
436 	}
437 
438 	return NULL;
439 }
440 
441 /*
442  * Create a LDAPControl, optionally from ber - deprecated
443  */
444 int
ldap_create_control(LDAP_CONST char * requestOID,BerElement * ber,int iscritical,LDAPControl ** ctrlp)445 ldap_create_control(
446 	LDAP_CONST char *requestOID,
447 	BerElement *ber,
448 	int iscritical,
449 	LDAPControl **ctrlp )
450 {
451 	LDAPControl *ctrl;
452 
453 	assert( requestOID != NULL );
454 	assert( ctrlp != NULL );
455 
456 	ctrl = (LDAPControl *) LDAP_MALLOC( sizeof(LDAPControl) );
457 	if ( ctrl == NULL ) {
458 		return LDAP_NO_MEMORY;
459 	}
460 
461 	BER_BVZERO(&ctrl->ldctl_value);
462 	if ( ber && ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 )) {
463 		LDAP_FREE( ctrl );
464 		return LDAP_NO_MEMORY;
465 	}
466 
467 	ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
468 	ctrl->ldctl_iscritical = iscritical;
469 
470 	if ( requestOID != NULL && ctrl->ldctl_oid == NULL ) {
471 		ldap_control_free( ctrl );
472 		return LDAP_NO_MEMORY;
473 	}
474 
475 	*ctrlp = ctrl;
476 	return LDAP_SUCCESS;
477 }
478 
479 /*
480  * Create a LDAPControl, optionally from value
481  */
482 int
ldap_control_create(LDAP_CONST char * requestOID,int iscritical,struct berval * value,int dupval,LDAPControl ** ctrlp)483 ldap_control_create(
484 	LDAP_CONST char *requestOID,
485 	int iscritical,
486 	struct berval *value,
487 	int dupval,
488 	LDAPControl **ctrlp )
489 {
490 	LDAPControl *ctrl;
491 
492 	assert( requestOID != NULL );
493 	assert( ctrlp != NULL );
494 
495 	ctrl = (LDAPControl *) LDAP_CALLOC( sizeof(LDAPControl), 1 );
496 	if ( ctrl == NULL ) {
497 		return LDAP_NO_MEMORY;
498 	}
499 
500 	ctrl->ldctl_iscritical = iscritical;
501 	if ( requestOID != NULL ) {
502 		ctrl->ldctl_oid = LDAP_STRDUP( requestOID );
503 		if ( ctrl->ldctl_oid == NULL ) {
504 			ldap_control_free( ctrl );
505 			return LDAP_NO_MEMORY;
506 		}
507 	}
508 
509 	if ( value && !BER_BVISNULL( value ) ) {
510 		if ( dupval ) {
511 			ber_dupbv( &ctrl->ldctl_value, value );
512 			if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
513 				ldap_control_free( ctrl );
514 				return LDAP_NO_MEMORY;
515 			}
516 
517 		} else {
518 			ctrl->ldctl_value = *value;
519 		}
520 	}
521 
522 	*ctrlp = ctrl;
523 
524 	return LDAP_SUCCESS;
525 }
526 
527 /*
528  * check for critical client controls and bitch if present
529  * if we ever support critical controls, we'll have to
530  * find a means for maintaining per API call control
531  * information.
532  */
ldap_int_client_controls(LDAP * ld,LDAPControl ** ctrls)533 int ldap_int_client_controls( LDAP *ld, LDAPControl **ctrls )
534 {
535 	LDAPControl *const *c;
536 
537 	assert( ld != NULL );
538 	assert( LDAP_VALID( ld ) );
539 
540 	if( ctrls == NULL ) {
541 		/* use default client controls */
542 		ctrls = ld->ld_cctrls;
543 	}
544 
545 	if( ctrls == NULL || *ctrls == NULL ) {
546 		return LDAP_SUCCESS;
547 	}
548 
549 	for( c = ctrls ; *c != NULL; c++ ) {
550 		if( (*c)->ldctl_iscritical ) {
551 			ld->ld_errno = LDAP_NOT_SUPPORTED;
552 			return ld->ld_errno;
553 		}
554 	}
555 
556 	return LDAP_SUCCESS;
557 }
558