1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 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
54int
55ldap_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
88int
89ldap_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
145int 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 */
252void
253ldap_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 */
273void
274ldap_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 */
292LDAPControl **
293ldap_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 */
335LDAPControl *
336ldap_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 */
388LDAPControl *
389ldap_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 */
409LDAPControl *
410ldap_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 */
439int
440ldap_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 */
477int
478ldap_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 */
528int 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