17c478bd9Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
27c478bd9Sstevel@tonic-gate  *
37c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public License
47c478bd9Sstevel@tonic-gate  * Version 1.0 (the "NPL"); you may not use this file except in
57c478bd9Sstevel@tonic-gate  * compliance with the NPL.  You may obtain a copy of the NPL at
67c478bd9Sstevel@tonic-gate  * http://www.mozilla.org/NPL/
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Software distributed under the NPL is distributed on an "AS IS" basis,
97c478bd9Sstevel@tonic-gate  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
107c478bd9Sstevel@tonic-gate  * for the specific language governing rights and limitations under the
117c478bd9Sstevel@tonic-gate  * NPL.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * The Initial Developer of this code under the NPL is Netscape
147c478bd9Sstevel@tonic-gate  * Communications Corporation.  Portions created by Netscape are
157c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
167c478bd9Sstevel@tonic-gate  * Reserved.
177c478bd9Sstevel@tonic-gate  */
187c478bd9Sstevel@tonic-gate /* control.c - routines to handle ldapv3 controls */
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate #include "ldap-int.h"
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate static LDAPControl *ldap_control_dup( LDAPControl *ctrl );
237c478bd9Sstevel@tonic-gate static int ldap_control_copy_contents( LDAPControl *ctrl_dst,
247c478bd9Sstevel@tonic-gate     LDAPControl *ctrl_src );
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Append a list of LDAPv3 controls to ber.  If ctrls is NULL, use default
287c478bd9Sstevel@tonic-gate  * set of controls from ld.
297c478bd9Sstevel@tonic-gate  * Return an LDAP error code (LDAP_SUCCESS if all goes well).
307c478bd9Sstevel@tonic-gate  * If closeseq is non-zero, we do an extra ber_put_seq() as well.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate int
nsldapi_put_controls(LDAP * ld,LDAPControl ** ctrls,int closeseq,BerElement * ber)337c478bd9Sstevel@tonic-gate nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq,
347c478bd9Sstevel@tonic-gate     BerElement *ber )
357c478bd9Sstevel@tonic-gate {
367c478bd9Sstevel@tonic-gate 	LDAPControl	*c;
377c478bd9Sstevel@tonic-gate 	int		rc, i;
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate 	rc = LDAP_ENCODING_ERROR;	/* the most popular error */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 	/* if no controls were passed in, use global list from LDAP * */
427c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_LOCK( ld, LDAP_CTRL_LOCK );
437c478bd9Sstevel@tonic-gate 	if ( ctrls == NULL ) {
447c478bd9Sstevel@tonic-gate 		ctrls = ld->ld_servercontrols;
457c478bd9Sstevel@tonic-gate 	}
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 	/* if there are no controls then we are done */
487c478bd9Sstevel@tonic-gate 	if ( ctrls == NULL || ctrls[ 0 ] == NULL ) {
497c478bd9Sstevel@tonic-gate 		goto clean_exit;
507c478bd9Sstevel@tonic-gate 	}
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	/*
537c478bd9Sstevel@tonic-gate 	 * If we're using LDAPv2 or earlier we can't send any controls, so
547c478bd9Sstevel@tonic-gate 	 * we just ignore them unless one is marked critical, in which case
557c478bd9Sstevel@tonic-gate 	 * we return an error.
567c478bd9Sstevel@tonic-gate 	 */
577c478bd9Sstevel@tonic-gate 	if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
587c478bd9Sstevel@tonic-gate 		for ( i = 0; ctrls != NULL && ctrls[i] != NULL; i++ ) {
597c478bd9Sstevel@tonic-gate 			if ( ctrls[i]->ldctl_iscritical ) {
607c478bd9Sstevel@tonic-gate 				rc = LDAP_NOT_SUPPORTED;
617c478bd9Sstevel@tonic-gate 				goto error_exit;
627c478bd9Sstevel@tonic-gate 			}
637c478bd9Sstevel@tonic-gate 		}
647c478bd9Sstevel@tonic-gate 		goto clean_exit;
657c478bd9Sstevel@tonic-gate 	}
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	/*
687c478bd9Sstevel@tonic-gate 	 * encode the controls as a Sequence of Sequence
697c478bd9Sstevel@tonic-gate 	 */
707c478bd9Sstevel@tonic-gate 	if ( ber_printf( ber, "t{", LDAP_TAG_CONTROLS ) == -1 ) {
717c478bd9Sstevel@tonic-gate 		goto error_exit;
727c478bd9Sstevel@tonic-gate 	}
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	for ( i = 0; ctrls[i] != NULL; i++ ) {
757c478bd9Sstevel@tonic-gate 		c = ctrls[i];
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 		if ( ber_printf( ber, "{s", c->ldctl_oid ) == -1 ) {
787c478bd9Sstevel@tonic-gate 			goto error_exit;
797c478bd9Sstevel@tonic-gate 		}
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 		/* criticality is "BOOLEAN DEFAULT FALSE" */
827c478bd9Sstevel@tonic-gate 		/* therefore, it should only be encoded if it exists AND is TRUE */
837c478bd9Sstevel@tonic-gate 		if ( c->ldctl_iscritical ) {
847c478bd9Sstevel@tonic-gate 			if ( ber_printf( ber, "b", (int)c->ldctl_iscritical )
857c478bd9Sstevel@tonic-gate 			    == -1 ) {
867c478bd9Sstevel@tonic-gate 				goto error_exit;
877c478bd9Sstevel@tonic-gate 			}
887c478bd9Sstevel@tonic-gate 		}
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 		if ( c->ldctl_value.bv_val != NULL ) {
917c478bd9Sstevel@tonic-gate 			if ( ber_printf( ber, "o", c->ldctl_value.bv_val,
927c478bd9Sstevel@tonic-gate 			    (int)c->ldctl_value.bv_len /* XXX lossy cast */ )
937c478bd9Sstevel@tonic-gate 			    == -1 ) {
947c478bd9Sstevel@tonic-gate 				goto error_exit;
957c478bd9Sstevel@tonic-gate 			}
967c478bd9Sstevel@tonic-gate 		}
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 		if ( ber_put_seq( ber ) == -1 ) {
997c478bd9Sstevel@tonic-gate 			goto error_exit;
1007c478bd9Sstevel@tonic-gate 		}
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if ( ber_put_seq( ber ) == -1 ) {
1047c478bd9Sstevel@tonic-gate 		goto error_exit;
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate clean_exit:
1087c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
1097c478bd9Sstevel@tonic-gate 	if ( closeseq && ber_put_seq( ber ) == -1 ) {
1107c478bd9Sstevel@tonic-gate 		goto error_exit;
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate error_exit:
1157c478bd9Sstevel@tonic-gate 	LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
1167c478bd9Sstevel@tonic-gate 	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
1177c478bd9Sstevel@tonic-gate 	return( rc );
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Pull controls out of "ber" (if any present) and return them in "controlsp."
1237c478bd9Sstevel@tonic-gate  * Returns an LDAP error code.
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate int
nsldapi_get_controls(BerElement * ber,LDAPControl *** controlsp)1267c478bd9Sstevel@tonic-gate nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp )
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	LDAPControl		*newctrl;
1297c478bd9Sstevel@tonic-gate 	ber_tag_t		tag;
1307c478bd9Sstevel@tonic-gate 	ber_len_t		len;
1317c478bd9Sstevel@tonic-gate 	int			rc, maxcontrols, curcontrols;
1327c478bd9Sstevel@tonic-gate 	char			*last;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	/*
1357c478bd9Sstevel@tonic-gate 	 * Each LDAPMessage can have a set of controls appended
1367c478bd9Sstevel@tonic-gate 	 * to it. Controls are used to extend the functionality
1377c478bd9Sstevel@tonic-gate 	 * of an LDAP operation (e.g., add an attribute size limit
1387c478bd9Sstevel@tonic-gate 	 * to the search operation). These controls look like this:
1397c478bd9Sstevel@tonic-gate 	 *
1407c478bd9Sstevel@tonic-gate 	 *	Controls ::= SEQUENCE OF Control
1417c478bd9Sstevel@tonic-gate 	 *
1427c478bd9Sstevel@tonic-gate 	 *	Control ::= SEQUENCE {
1437c478bd9Sstevel@tonic-gate 	 *		controlType	LDAPOID,
1447c478bd9Sstevel@tonic-gate 	 *		criticality	BOOLEAN DEFAULT FALSE,
1457c478bd9Sstevel@tonic-gate 	 *		controlValue	OCTET STRING
1467c478bd9Sstevel@tonic-gate 	 *	}
1477c478bd9Sstevel@tonic-gate 	 */
1487c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_get_controls\n", 0, 0, 0 );
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	*controlsp = NULL;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/*
1537c478bd9Sstevel@tonic-gate          * check to see if controls were included
1547c478bd9Sstevel@tonic-gate 	 */
1557c478bd9Sstevel@tonic-gate 	if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
1567c478bd9Sstevel@tonic-gate 		return( LDAP_DECODING_ERROR );	/* unexpected error */
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 	if ( len == 0 ) {
1597c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE,
1607c478bd9Sstevel@tonic-gate 		    "<= nsldapi_get_controls no controls\n", 0, 0, 0 );
1617c478bd9Sstevel@tonic-gate 		return( LDAP_SUCCESS );			/* no controls */
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 	if (( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
1647c478bd9Sstevel@tonic-gate 		if ( tag == LBER_ERROR ) {
1657c478bd9Sstevel@tonic-gate 			LDAPDebug( LDAP_DEBUG_TRACE,
1667c478bd9Sstevel@tonic-gate 			    "<= nsldapi_get_controls LDAP_PROTOCOL_ERROR\n",
1677c478bd9Sstevel@tonic-gate 			    0, 0, 0 );
1687c478bd9Sstevel@tonic-gate 			return( LDAP_DECODING_ERROR );	/* decoding error */
1697c478bd9Sstevel@tonic-gate 		}
1707c478bd9Sstevel@tonic-gate 		/*
1717c478bd9Sstevel@tonic-gate 		 * We found something other than controls.  This should never
1727c478bd9Sstevel@tonic-gate 		 * happen in LDAPv3, but we don't treat this is a hard error --
1737c478bd9Sstevel@tonic-gate 		 * we just ignore the extra stuff.
1747c478bd9Sstevel@tonic-gate 		 */
1757c478bd9Sstevel@tonic-gate 		LDAPDebug( LDAP_DEBUG_TRACE,
1767c478bd9Sstevel@tonic-gate 		    "<= nsldapi_get_controls ignoring unrecognized data in message (tag 0x%x)\n",
1777c478bd9Sstevel@tonic-gate 		    tag, 0, 0 );
1787c478bd9Sstevel@tonic-gate 		return( LDAP_SUCCESS );
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	maxcontrols = curcontrols = 0;
1827c478bd9Sstevel@tonic-gate 	for ( tag = ber_first_element( ber, &len, &last );
1837c478bd9Sstevel@tonic-gate 	    tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
1847c478bd9Sstevel@tonic-gate 	    tag = ber_next_element( ber, &len, last ) ) {
1857c478bd9Sstevel@tonic-gate 		if ( curcontrols >= maxcontrols - 1 ) {
1867c478bd9Sstevel@tonic-gate #define CONTROL_GRABSIZE	5
1877c478bd9Sstevel@tonic-gate 			maxcontrols += CONTROL_GRABSIZE;
1887c478bd9Sstevel@tonic-gate 			*controlsp = (struct ldapcontrol **)NSLDAPI_REALLOC(
1897c478bd9Sstevel@tonic-gate 			    (char *)*controlsp, maxcontrols *
1907c478bd9Sstevel@tonic-gate 			    sizeof(struct ldapcontrol *) );
1917c478bd9Sstevel@tonic-gate 			if ( *controlsp == NULL ) {
1927c478bd9Sstevel@tonic-gate 			    rc = LDAP_NO_MEMORY;
1937c478bd9Sstevel@tonic-gate 			    goto free_and_return;
1947c478bd9Sstevel@tonic-gate 			}
1957c478bd9Sstevel@tonic-gate 		}
1967c478bd9Sstevel@tonic-gate 		if (( newctrl = (struct ldapcontrol *)NSLDAPI_CALLOC( 1,
1977c478bd9Sstevel@tonic-gate 		    sizeof(LDAPControl))) == NULL ) {
1987c478bd9Sstevel@tonic-gate 			rc = LDAP_NO_MEMORY;
1997c478bd9Sstevel@tonic-gate 			goto free_and_return;
2007c478bd9Sstevel@tonic-gate 		}
201*1da57d55SToomas Soome 
2027c478bd9Sstevel@tonic-gate 		(*controlsp)[curcontrols++] = newctrl;
2037c478bd9Sstevel@tonic-gate 		(*controlsp)[curcontrols] = NULL;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		if ( ber_scanf( ber, "{a", &newctrl->ldctl_oid )
2067c478bd9Sstevel@tonic-gate 		    == LBER_ERROR ) {
2077c478bd9Sstevel@tonic-gate 			rc = LDAP_DECODING_ERROR;
2087c478bd9Sstevel@tonic-gate 			goto free_and_return;
2097c478bd9Sstevel@tonic-gate 		}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 		/* the criticality is optional */
2127c478bd9Sstevel@tonic-gate 		if ( ber_peek_tag( ber, &len ) == LBER_BOOLEAN ) {
2137c478bd9Sstevel@tonic-gate 			int		aint;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 			if ( ber_scanf( ber, "b", &aint ) == LBER_ERROR ) {
2167c478bd9Sstevel@tonic-gate 				rc = LDAP_DECODING_ERROR;
2177c478bd9Sstevel@tonic-gate 				goto free_and_return;
2187c478bd9Sstevel@tonic-gate 			}
2197c478bd9Sstevel@tonic-gate 			newctrl->ldctl_iscritical = (char)aint;	/* XXX lossy cast */
2207c478bd9Sstevel@tonic-gate 		} else {
2217c478bd9Sstevel@tonic-gate 			/* absent is synonomous with FALSE */
2227c478bd9Sstevel@tonic-gate 			newctrl->ldctl_iscritical = 0;
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		/* the control value is optional */
2267c478bd9Sstevel@tonic-gate 		if ( ber_peek_tag( ber, &len ) == LBER_OCTETSTRING ) {
2277c478bd9Sstevel@tonic-gate 			if ( ber_scanf( ber, "o", &newctrl->ldctl_value )
2287c478bd9Sstevel@tonic-gate 			    == LBER_ERROR ) {
2297c478bd9Sstevel@tonic-gate 				rc = LDAP_DECODING_ERROR;
2307c478bd9Sstevel@tonic-gate 				goto free_and_return;
2317c478bd9Sstevel@tonic-gate 			}
2327c478bd9Sstevel@tonic-gate 		} else {
2337c478bd9Sstevel@tonic-gate 			(newctrl->ldctl_value).bv_val = NULL;
2347c478bd9Sstevel@tonic-gate 			(newctrl->ldctl_value).bv_len = 0;
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if ( tag == LBER_ERROR ) {
2407c478bd9Sstevel@tonic-gate 		rc = LDAP_DECODING_ERROR;
2417c478bd9Sstevel@tonic-gate 		goto free_and_return;
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
2457c478bd9Sstevel@tonic-gate 	    "<= nsldapi_get_controls found %d controls\n", curcontrols, 0, 0 );
2467c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate free_and_return:;
2497c478bd9Sstevel@tonic-gate 	ldap_controls_free( *controlsp );
2507c478bd9Sstevel@tonic-gate 	*controlsp = NULL;
2517c478bd9Sstevel@tonic-gate 	LDAPDebug( LDAP_DEBUG_TRACE,
2527c478bd9Sstevel@tonic-gate 	    "<= nsldapi_get_controls error 0x%x\n", rc, 0, 0 );
2537c478bd9Sstevel@tonic-gate 	return( rc );
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate void
2587c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_control_free(LDAPControl * ctrl)2597c478bd9Sstevel@tonic-gate ldap_control_free( LDAPControl *ctrl )
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	if ( ctrl != NULL ) {
2627c478bd9Sstevel@tonic-gate 		if ( ctrl->ldctl_oid != NULL ) {
2637c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( ctrl->ldctl_oid );
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 		if ( ctrl->ldctl_value.bv_val != NULL ) {
2667c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( ctrl->ldctl_value.bv_val );
2677c478bd9Sstevel@tonic-gate 		}
2687c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( (char *)ctrl );
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate void
2747c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_controls_free(LDAPControl ** ctrls)2757c478bd9Sstevel@tonic-gate ldap_controls_free( LDAPControl **ctrls )
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate 	int	i;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	if ( ctrls != NULL ) {
2807c478bd9Sstevel@tonic-gate 		for ( i = 0; ctrls[i] != NULL; i++ ) {
2817c478bd9Sstevel@tonic-gate 			ldap_control_free( ctrls[i] );
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( (char *)ctrls );
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate #if 0
2907c478bd9Sstevel@tonic-gate LDAPControl **
2917c478bd9Sstevel@tonic-gate LDAP_CALL
2927c478bd9Sstevel@tonic-gate ldap_control_append( LDAPControl **ctrl_src, LDAPControl *ctrl )
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate     int nctrls = 0;
2957c478bd9Sstevel@tonic-gate 	LDAPControl **ctrlp;
2967c478bd9Sstevel@tonic-gate 	int i;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if ( NULL == ctrl )
2997c478bd9Sstevel@tonic-gate 	    return ( NULL );
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/* Count the existing controls */
3027c478bd9Sstevel@tonic-gate 	if ( NULL != ctrl_src ) {
3037c478bd9Sstevel@tonic-gate 		while( NULL != ctrl_src[nctrls] ) {
3047c478bd9Sstevel@tonic-gate 			nctrls++;
3057c478bd9Sstevel@tonic-gate 		}
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	/* allocate the new control structure */
3097c478bd9Sstevel@tonic-gate 	if ( ( ctrlp = (LDAPControl **)NSLDAPI_MALLOC( sizeof(LDAPControl *)
3107c478bd9Sstevel@tonic-gate 	    * (nctrls + 2) ) ) == NULL ) {
3117c478bd9Sstevel@tonic-gate 		return( NULL );
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 	memset( ctrlp, 0, sizeof(*ctrlp) * (nctrls + 2) );
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	for( i = 0; i < (nctrls + 1); i++ ) {
3167c478bd9Sstevel@tonic-gate 	    if ( i < nctrls ) {
3177c478bd9Sstevel@tonic-gate 		    ctrlp[i] = ldap_control_dup( ctrl_src[i] );
3187c478bd9Sstevel@tonic-gate 	    } else {
3197c478bd9Sstevel@tonic-gate 		    ctrlp[i] = ldap_control_dup( ctrl );
3207c478bd9Sstevel@tonic-gate 	    }
3217c478bd9Sstevel@tonic-gate 	    if ( NULL == ctrlp[i] ) {
3227c478bd9Sstevel@tonic-gate 		    ldap_controls_free( ctrlp );
3237c478bd9Sstevel@tonic-gate 		    return( NULL );
3247c478bd9Sstevel@tonic-gate 	    }
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 	return ctrlp;
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate #endif /* 0 */
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate  * Replace *ldctrls with a copy of newctrls.
3337c478bd9Sstevel@tonic-gate  * returns 0 if successful.
3347c478bd9Sstevel@tonic-gate  * return -1 if not and set error code inside LDAP *ld.
3357c478bd9Sstevel@tonic-gate  */
3367c478bd9Sstevel@tonic-gate int
nsldapi_dup_controls(LDAP * ld,LDAPControl *** ldctrls,LDAPControl ** newctrls)3377c478bd9Sstevel@tonic-gate nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls, LDAPControl **newctrls )
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	int	count;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	if ( *ldctrls != NULL ) {
3427c478bd9Sstevel@tonic-gate 		ldap_controls_free( *ldctrls );
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	if ( newctrls == NULL || newctrls[0] == NULL ) {
3467c478bd9Sstevel@tonic-gate 		*ldctrls = NULL;
3477c478bd9Sstevel@tonic-gate 		return( 0 );
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	for ( count = 0; newctrls[ count ] != NULL; ++count ) {
3517c478bd9Sstevel@tonic-gate 		;
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (( *ldctrls = (LDAPControl **)NSLDAPI_MALLOC(( count + 1 ) *
3557c478bd9Sstevel@tonic-gate 	    sizeof( LDAPControl *))) == NULL ) {
3567c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
3577c478bd9Sstevel@tonic-gate 		return( -1 );
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 	(*ldctrls)[ count ] = NULL;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	for ( count = 0; newctrls[ count ] != NULL; ++count ) {
3627c478bd9Sstevel@tonic-gate 		if (( (*ldctrls)[ count ] =
3637c478bd9Sstevel@tonic-gate 		    ldap_control_dup( newctrls[ count ] )) == NULL ) {
3647c478bd9Sstevel@tonic-gate 			ldap_controls_free( *ldctrls );
3657c478bd9Sstevel@tonic-gate 			*ldctrls = NULL;
3667c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
3677c478bd9Sstevel@tonic-gate 			return( -1 );
3687c478bd9Sstevel@tonic-gate 		}
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	return( 0 );
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate  * return a malloc'd copy of "ctrl" (NULL if memory allocation fails)
3777c478bd9Sstevel@tonic-gate  */
3787c478bd9Sstevel@tonic-gate static LDAPControl *
3797c478bd9Sstevel@tonic-gate /* LDAP_CALL */		/* keep this routine internal for now */
ldap_control_dup(LDAPControl * ctrl)3807c478bd9Sstevel@tonic-gate ldap_control_dup( LDAPControl *ctrl )
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	LDAPControl	*rctrl;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	if (( rctrl = (LDAPControl *)NSLDAPI_MALLOC( sizeof( LDAPControl )))
3857c478bd9Sstevel@tonic-gate 	    == NULL ) {
3867c478bd9Sstevel@tonic-gate 		return( NULL );
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	if ( ldap_control_copy_contents( rctrl, ctrl ) != LDAP_SUCCESS ) {
3907c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( rctrl );
3917c478bd9Sstevel@tonic-gate 		return( NULL );
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	return( rctrl );
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate  * duplicate the contents of "ctrl_src" and place in "ctrl_dst"
4007c478bd9Sstevel@tonic-gate  */
4017c478bd9Sstevel@tonic-gate static int
4027c478bd9Sstevel@tonic-gate /* LDAP_CALL */		/* keep this routine internal for now */
ldap_control_copy_contents(LDAPControl * ctrl_dst,LDAPControl * ctrl_src)4037c478bd9Sstevel@tonic-gate ldap_control_copy_contents( LDAPControl *ctrl_dst, LDAPControl *ctrl_src )
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate 	size_t	len;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	if ( NULL == ctrl_dst || NULL == ctrl_src ) {
4087c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	ctrl_dst->ldctl_iscritical = ctrl_src->ldctl_iscritical;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/* fill in the fields of this new control */
4147c478bd9Sstevel@tonic-gate 	if (( ctrl_dst->ldctl_oid = nsldapi_strdup( ctrl_src->ldctl_oid ))
4157c478bd9Sstevel@tonic-gate 	    == NULL ) {
4167c478bd9Sstevel@tonic-gate 		return( LDAP_NO_MEMORY );
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	len = (size_t)(ctrl_src->ldctl_value).bv_len;
4207c478bd9Sstevel@tonic-gate 	if ( ctrl_src->ldctl_value.bv_val == NULL || len <= 0 ) {
4217c478bd9Sstevel@tonic-gate 		ctrl_dst->ldctl_value.bv_len = 0;
4227c478bd9Sstevel@tonic-gate 		ctrl_dst->ldctl_value.bv_val = NULL;
4237c478bd9Sstevel@tonic-gate 	} else {
4247c478bd9Sstevel@tonic-gate 		ctrl_dst->ldctl_value.bv_len = len;
4257c478bd9Sstevel@tonic-gate 		if (( ctrl_dst->ldctl_value.bv_val = NSLDAPI_MALLOC( len ))
4267c478bd9Sstevel@tonic-gate 		    == NULL ) {
4277c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE( ctrl_dst->ldctl_oid );
4287c478bd9Sstevel@tonic-gate 			return( LDAP_NO_MEMORY );
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 		SAFEMEMCPY( ctrl_dst->ldctl_value.bv_val,
4317c478bd9Sstevel@tonic-gate 		    ctrl_src->ldctl_value.bv_val, len );
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	return ( LDAP_SUCCESS );
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate /*
4407c478bd9Sstevel@tonic-gate  * build an allocated LDAPv3 control.  Returns an LDAP error code.
4417c478bd9Sstevel@tonic-gate  */
4427c478bd9Sstevel@tonic-gate int
nsldapi_build_control(char * oid,BerElement * ber,int freeber,char iscritical,LDAPControl ** ctrlp)4437c478bd9Sstevel@tonic-gate nsldapi_build_control( char *oid, BerElement *ber, int freeber, char iscritical,
4447c478bd9Sstevel@tonic-gate     LDAPControl **ctrlp )
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	int		rc;
4477c478bd9Sstevel@tonic-gate 	struct berval	*bvp;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	if ( ber == NULL ) {
4507c478bd9Sstevel@tonic-gate 		bvp = NULL;
4517c478bd9Sstevel@tonic-gate 	} else {
4527c478bd9Sstevel@tonic-gate 		/* allocate struct berval with contents of the BER encoding */
4537c478bd9Sstevel@tonic-gate 		rc = ber_flatten( ber, &bvp );
4547c478bd9Sstevel@tonic-gate 		if ( freeber ) {
4557c478bd9Sstevel@tonic-gate 			ber_free( ber, 1 );
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 		if ( rc == -1 ) {
4587c478bd9Sstevel@tonic-gate 			return( LDAP_NO_MEMORY );
4597c478bd9Sstevel@tonic-gate 		}
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	/* allocate the new control structure */
4637c478bd9Sstevel@tonic-gate 	if (( *ctrlp = (LDAPControl *)NSLDAPI_MALLOC( sizeof(LDAPControl)))
4647c478bd9Sstevel@tonic-gate 	    == NULL ) {
4657c478bd9Sstevel@tonic-gate 		if ( bvp != NULL ) {
4667c478bd9Sstevel@tonic-gate 			ber_bvfree( bvp );
4677c478bd9Sstevel@tonic-gate 		}
4687c478bd9Sstevel@tonic-gate 		return( LDAP_NO_MEMORY );
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	/* fill in the fields of this new control */
472*1da57d55SToomas Soome 	(*ctrlp)->ldctl_iscritical = iscritical;
4737c478bd9Sstevel@tonic-gate 	if (( (*ctrlp)->ldctl_oid = nsldapi_strdup( oid )) == NULL ) {
474*1da57d55SToomas Soome 		NSLDAPI_FREE( *ctrlp );
4757c478bd9Sstevel@tonic-gate 		if ( bvp != NULL ) {
4767c478bd9Sstevel@tonic-gate 			ber_bvfree( bvp );
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 		return( LDAP_NO_MEMORY );
479*1da57d55SToomas Soome 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if ( bvp == NULL ) {
4827c478bd9Sstevel@tonic-gate 		(*ctrlp)->ldctl_value.bv_len = 0;
4837c478bd9Sstevel@tonic-gate 		(*ctrlp)->ldctl_value.bv_val = NULL;
4847c478bd9Sstevel@tonic-gate 	} else {
4857c478bd9Sstevel@tonic-gate 		(*ctrlp)->ldctl_value = *bvp;	/* struct copy */
4867c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE( bvp );	/* free container, not contents! */
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
4907c478bd9Sstevel@tonic-gate }
491