17c478bd9Sstevel@tonic-gate /*
2924965c7SSerge Dussud  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3924965c7SSerge Dussud  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public License
97c478bd9Sstevel@tonic-gate  * Version 1.0 (the "NPL"); you may not use this file except in
107c478bd9Sstevel@tonic-gate  * compliance with the NPL.  You may obtain a copy of the NPL at
117c478bd9Sstevel@tonic-gate  * http://www.mozilla.org/NPL/
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Software distributed under the NPL is distributed on an "AS IS" basis,
147c478bd9Sstevel@tonic-gate  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
157c478bd9Sstevel@tonic-gate  * for the specific language governing rights and limitations under the
167c478bd9Sstevel@tonic-gate  * NPL.
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * The Initial Developer of this code under the NPL is Netscape
197c478bd9Sstevel@tonic-gate  * Communications Corporation.  Portions created by Netscape are
207c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
217c478bd9Sstevel@tonic-gate  * Reserved.
227c478bd9Sstevel@tonic-gate  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate /*
257c478bd9Sstevel@tonic-gate  * Copyright (c) 1990 Regents of the University of Michigan.
267c478bd9Sstevel@tonic-gate  * All rights reserved.
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
297c478bd9Sstevel@tonic-gate  * provided that this notice is preserved and that due credit is given
307c478bd9Sstevel@tonic-gate  * to the University of Michigan at Ann Arbor. The name of the University
317c478bd9Sstevel@tonic-gate  * may not be used to endorse or promote products derived from this
327c478bd9Sstevel@tonic-gate  * software without specific prior written permission. This software
337c478bd9Sstevel@tonic-gate  * is provided ``as is'' without express or implied warranty.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /* encode.c - ber output encoding routines */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include "lber-int.h"
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /* the following constants are used in ber_calc_lenlen */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #define LENMASK1	0xFF
437c478bd9Sstevel@tonic-gate #define	LENMASK2 	0xFFFF
447c478bd9Sstevel@tonic-gate #define LENMASK3	0xFFFFFF
457c478bd9Sstevel@tonic-gate #define LENMASK4	0xFFFFFFFF
467c478bd9Sstevel@tonic-gate #define _MASK		0x80
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static int
ber_calc_taglen(ber_tag_t tag)497c478bd9Sstevel@tonic-gate ber_calc_taglen( ber_tag_t tag )
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate 	int		i;
527c478bd9Sstevel@tonic-gate 	ber_int_t	mask;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 	/* find the first non-all-zero byte in the tag */
557c478bd9Sstevel@tonic-gate 	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
567c478bd9Sstevel@tonic-gate 		mask = (LENMASK3 << (i * 8));
577c478bd9Sstevel@tonic-gate 		/* not all zero */
587c478bd9Sstevel@tonic-gate 		if ( tag & mask )
597c478bd9Sstevel@tonic-gate 			break;
607c478bd9Sstevel@tonic-gate 	}
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	return( i + 1 );
637c478bd9Sstevel@tonic-gate }
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static int
ber_put_tag(BerElement * ber,ber_tag_t tag,int nosos)667c478bd9Sstevel@tonic-gate ber_put_tag( BerElement	*ber, ber_tag_t tag, int nosos )
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate 	int		taglen;
697c478bd9Sstevel@tonic-gate 	ber_tag_t	ntag;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	taglen = ber_calc_taglen( tag );
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	ntag = LBER_HTONL( tag );
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	return( ber_write( ber, ((char *) &ntag) + sizeof(ber_int_t) - taglen,
767c478bd9Sstevel@tonic-gate 	    taglen, nosos ) );
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static int
ber_calc_lenlen(ber_len_t len)807c478bd9Sstevel@tonic-gate ber_calc_lenlen( ber_len_t len )
817c478bd9Sstevel@tonic-gate {
827c478bd9Sstevel@tonic-gate 	/*
837c478bd9Sstevel@tonic-gate 	 * short len if it's less than 128 - one byte giving the len,
847c478bd9Sstevel@tonic-gate 	 * with bit 8 0.
857c478bd9Sstevel@tonic-gate 	 */
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	if ( len <= 0x7F )
887c478bd9Sstevel@tonic-gate 		return( 1 );
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	/*
917c478bd9Sstevel@tonic-gate 	 * long len otherwise - one byte with bit 8 set, giving the
927c478bd9Sstevel@tonic-gate 	 * length of the length, followed by the length itself.
937c478bd9Sstevel@tonic-gate 	 */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	if ( len <= LENMASK1 )
967c478bd9Sstevel@tonic-gate 		return( 2 );
977c478bd9Sstevel@tonic-gate 	if ( len <= LENMASK2 )
987c478bd9Sstevel@tonic-gate 		return( 3 );
997c478bd9Sstevel@tonic-gate 	if ( len <= LENMASK3 )
1007c478bd9Sstevel@tonic-gate 		return( 4 );
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	return( 5 );
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static int
ber_put_len(BerElement * ber,ber_len_t len,int nosos)1067c478bd9Sstevel@tonic-gate ber_put_len( BerElement *ber, ber_len_t len, int nosos )
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 	int		i;
1097c478bd9Sstevel@tonic-gate 	char		lenlen;
1107c478bd9Sstevel@tonic-gate 	ber_int_t	mask;
1117c478bd9Sstevel@tonic-gate 	ber_len_t	netlen;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/*
1147c478bd9Sstevel@tonic-gate 	 * short len if it's less than 128 - one byte giving the len,
1157c478bd9Sstevel@tonic-gate 	 * with bit 8 0.
1167c478bd9Sstevel@tonic-gate 	 */
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	if ( len <= 127 ) {
1197c478bd9Sstevel@tonic-gate 		netlen = LBER_HTONL( len );
1207c478bd9Sstevel@tonic-gate 		return( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) - 1,
1217c478bd9Sstevel@tonic-gate 		    1, nosos ) );
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	/*
1257c478bd9Sstevel@tonic-gate 	 * long len otherwise - one byte with bit 8 set, giving the
1267c478bd9Sstevel@tonic-gate 	 * length of the length, followed by the length itself.
1277c478bd9Sstevel@tonic-gate 	 */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	/* find the first non-all-zero byte */
1307c478bd9Sstevel@tonic-gate 	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
1317c478bd9Sstevel@tonic-gate 		mask = (LENMASK1 << (i * 8));
1327c478bd9Sstevel@tonic-gate 		/* not all zero */
1337c478bd9Sstevel@tonic-gate 		if ( len & mask )
1347c478bd9Sstevel@tonic-gate 			break;
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate 	lenlen = ++i;
1377c478bd9Sstevel@tonic-gate 	if ( lenlen > 4 )
1387c478bd9Sstevel@tonic-gate 		return( -1 );
1397c478bd9Sstevel@tonic-gate 	lenlen |= 0x80;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	/* write the length of the length */
1427c478bd9Sstevel@tonic-gate 	if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
1437c478bd9Sstevel@tonic-gate 		return( -1 );
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	/* write the length itself */
1467c478bd9Sstevel@tonic-gate 	netlen = LBER_HTONL( len );
1477c478bd9Sstevel@tonic-gate 	if ( ber_write( ber, (char *) &netlen + (sizeof(ber_int_t) - i), i, nosos )
1487c478bd9Sstevel@tonic-gate 	    != i )
1497c478bd9Sstevel@tonic-gate 		return( -1 );
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	return( i + 1 );
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static int
ber_put_int_or_enum(BerElement * ber,ber_int_t num,ber_tag_t tag)1557c478bd9Sstevel@tonic-gate ber_put_int_or_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	int		i, sign, taglen;
1587c478bd9Sstevel@tonic-gate 	int		len, lenlen;
1597c478bd9Sstevel@tonic-gate 	ber_int_t	netnum, mask;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	sign = (num < 0);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/*
1647c478bd9Sstevel@tonic-gate 	 * high bit is set - look for first non-all-one byte
1657c478bd9Sstevel@tonic-gate 	 * high bit is clear - look for first non-all-zero byte
1667c478bd9Sstevel@tonic-gate 	 */
1677c478bd9Sstevel@tonic-gate 	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
1687c478bd9Sstevel@tonic-gate 		mask = (LENMASK1 << (i * 8));
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 		if ( sign ) {
1717c478bd9Sstevel@tonic-gate 			/* not all ones */
1727c478bd9Sstevel@tonic-gate 			if ( (num & mask) != mask )
1737c478bd9Sstevel@tonic-gate 				break;
1747c478bd9Sstevel@tonic-gate 		} else {
1757c478bd9Sstevel@tonic-gate 			/* not all zero */
1767c478bd9Sstevel@tonic-gate 			if ( num & mask )
1777c478bd9Sstevel@tonic-gate 				break;
1787c478bd9Sstevel@tonic-gate 		}
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 * we now have the "leading byte".  if the high bit on this
1837c478bd9Sstevel@tonic-gate 	 * byte matches the sign bit, we need to "back up" a byte.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	mask = (num & (_MASK << (i * 8)));
1867c478bd9Sstevel@tonic-gate 	if ( (mask && !sign) || (sign && !mask) )
1877c478bd9Sstevel@tonic-gate 		i++;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	len = i + 1;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
1927c478bd9Sstevel@tonic-gate 		return( -1 );
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
1957c478bd9Sstevel@tonic-gate 		return( -1 );
1967c478bd9Sstevel@tonic-gate 	i++;
1977c478bd9Sstevel@tonic-gate 	netnum = LBER_HTONL( num );
198*55fea89dSDan Cross 	if ( ber_write( ber, (char *) &netnum + (sizeof(ber_int_t) - i), i, 0 )
199*55fea89dSDan Cross 		== i)
2007c478bd9Sstevel@tonic-gate 		/* length of tag + length + contents */
2017c478bd9Sstevel@tonic-gate 		return( taglen + lenlen + i );
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	return( -1 );
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate int
2077c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_enum(BerElement * ber,ber_int_t num,ber_tag_t tag)2087c478bd9Sstevel@tonic-gate ber_put_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
2117c478bd9Sstevel@tonic-gate 		tag = LBER_ENUMERATED;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	return( ber_put_int_or_enum( ber, num, tag ) );
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate int
2177c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_int(BerElement * ber,ber_int_t num,ber_tag_t tag)2187c478bd9Sstevel@tonic-gate ber_put_int( BerElement *ber, ber_int_t num, ber_tag_t tag )
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
2217c478bd9Sstevel@tonic-gate 		tag = LBER_INTEGER;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	return( ber_put_int_or_enum( ber, num, tag ) );
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate int
2277c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_ostring(BerElement * ber,char * str,ber_len_t len,ber_tag_t tag)2287c478bd9Sstevel@tonic-gate ber_put_ostring( BerElement *ber, char *str, ber_len_t len,
2297c478bd9Sstevel@tonic-gate 	ber_tag_t tag )
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate 	int	taglen, lenlen, rc;
2327c478bd9Sstevel@tonic-gate #ifdef STR_TRANSLATION
2337c478bd9Sstevel@tonic-gate 	int	free_str;
2347c478bd9Sstevel@tonic-gate #endif /* STR_TRANSLATION */
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
2377c478bd9Sstevel@tonic-gate 		tag = LBER_OCTETSTRING;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
2407c478bd9Sstevel@tonic-gate 		return( -1 );
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate #ifdef STR_TRANSLATION
2437c478bd9Sstevel@tonic-gate 	if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0
2447c478bd9Sstevel@tonic-gate 	    && ber->ber_encode_translate_proc != NULL ) {
2457c478bd9Sstevel@tonic-gate 		if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
2467c478bd9Sstevel@tonic-gate 		    != 0 ) {
2477c478bd9Sstevel@tonic-gate 			return( -1 );
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 		free_str = 1;
2507c478bd9Sstevel@tonic-gate 	} else {
2517c478bd9Sstevel@tonic-gate 		free_str = 0;
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate #endif /* STR_TRANSLATION */
2547c478bd9Sstevel@tonic-gate 
255*55fea89dSDan Cross     /*
256*55fea89dSDan Cross      *  Note:  below is a spot where we limit ber_write
2577c478bd9Sstevel@tonic-gate      *         to signed long (instead of unsigned long)
2587c478bd9Sstevel@tonic-gate      */
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
2617c478bd9Sstevel@tonic-gate 		ber_write( ber, str, len, 0 ) != (ber_int_t) len ) {
2627c478bd9Sstevel@tonic-gate 		rc = -1;
2637c478bd9Sstevel@tonic-gate 	} else {
2647c478bd9Sstevel@tonic-gate 		/* return length of tag + length + contents */
2657c478bd9Sstevel@tonic-gate 		rc = taglen + lenlen + len;
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate #ifdef STR_TRANSLATION
2697c478bd9Sstevel@tonic-gate 	if ( free_str ) {
2707c478bd9Sstevel@tonic-gate 		NSLBERI_FREE( str );
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate #endif /* STR_TRANSLATION */
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	return( rc );
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate int
2787c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_string(BerElement * ber,char * str,ber_tag_t tag)2797c478bd9Sstevel@tonic-gate ber_put_string( BerElement *ber, char *str, ber_tag_t tag )
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	return( ber_put_ostring( ber, str, (ber_len_t) strlen( str ), tag ));
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate int
2857c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_bitstring(BerElement * ber,char * str,ber_len_t blen,ber_tag_t tag)2867c478bd9Sstevel@tonic-gate ber_put_bitstring( BerElement *ber, char *str,
2877c478bd9Sstevel@tonic-gate 	ber_len_t blen /* in bits */, ber_tag_t tag )
2887c478bd9Sstevel@tonic-gate {
2897c478bd9Sstevel@tonic-gate 	int		taglen, lenlen, len;
2907c478bd9Sstevel@tonic-gate 	unsigned char	unusedbits;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
2937c478bd9Sstevel@tonic-gate 		tag = LBER_BITSTRING;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
2967c478bd9Sstevel@tonic-gate 		return( -1 );
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	len = ( blen + 7 ) / 8;
2997c478bd9Sstevel@tonic-gate 	unusedbits = (unsigned char) (len * 8 - blen);
3007c478bd9Sstevel@tonic-gate 	if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
3017c478bd9Sstevel@tonic-gate 		return( -1 );
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
3047c478bd9Sstevel@tonic-gate 		return( -1 );
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if ( ber_write( ber, str, len, 0 ) != len )
3077c478bd9Sstevel@tonic-gate 		return( -1 );
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	/* return length of tag + length + unused bit count + contents */
3107c478bd9Sstevel@tonic-gate 	return( taglen + 1 + lenlen + len );
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate int
3147c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_null(BerElement * ber,ber_tag_t tag)3157c478bd9Sstevel@tonic-gate ber_put_null( BerElement *ber, ber_tag_t tag )
3167c478bd9Sstevel@tonic-gate {
3177c478bd9Sstevel@tonic-gate 	int	taglen;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
3207c478bd9Sstevel@tonic-gate 		tag = LBER_NULL;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
3237c478bd9Sstevel@tonic-gate 		return( -1 );
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	if ( ber_put_len( ber, 0, 0 ) != 1 )
3267c478bd9Sstevel@tonic-gate 		return( -1 );
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	return( taglen + 1 );
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate int
3327c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_boolean(BerElement * ber,int boolval,ber_tag_t tag)3337c478bd9Sstevel@tonic-gate ber_put_boolean( BerElement *ber, int boolval, ber_tag_t tag )
3347c478bd9Sstevel@tonic-gate {
3357c478bd9Sstevel@tonic-gate 	int		taglen;
3367c478bd9Sstevel@tonic-gate 	unsigned char	trueval = 0xff;
3377c478bd9Sstevel@tonic-gate 	unsigned char	falseval = 0x00;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
3407c478bd9Sstevel@tonic-gate 		tag = LBER_BOOLEAN;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
3437c478bd9Sstevel@tonic-gate 		return( -1 );
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	if ( ber_put_len( ber, 1, 0 ) != 1 )
3467c478bd9Sstevel@tonic-gate 		return( -1 );
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
3497c478bd9Sstevel@tonic-gate 	    != 1 )
3507c478bd9Sstevel@tonic-gate 		return( -1 );
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	return( taglen + 2 );
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate #define FOUR_BYTE_LEN	5
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate /* the idea here is roughly this: we maintain a stack of these Seqorset
3597c478bd9Sstevel@tonic-gate  * structures. This is pushed when we see the beginning of a new set or
3607c478bd9Sstevel@tonic-gate  * sequence. It is popped when we see the end of a set or sequence.
3617c478bd9Sstevel@tonic-gate  * Since we don't want to malloc and free these structures all the time,
3627c478bd9Sstevel@tonic-gate  * we pre-allocate a small set of them within the ber element structure.
3637c478bd9Sstevel@tonic-gate  * thus we need to spot when we've overflowed this stack and fall back to
3647c478bd9Sstevel@tonic-gate  * malloc'ing instead.
3657c478bd9Sstevel@tonic-gate  */
3667c478bd9Sstevel@tonic-gate static int
ber_start_seqorset(BerElement * ber,ber_tag_t tag)3677c478bd9Sstevel@tonic-gate ber_start_seqorset( BerElement *ber, ber_tag_t tag )
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate 	Seqorset	*new_sos;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	/* can we fit into the local stack ? */
3727c478bd9Sstevel@tonic-gate 	if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
3737c478bd9Sstevel@tonic-gate 		/* yes */
3747c478bd9Sstevel@tonic-gate 		new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
3757c478bd9Sstevel@tonic-gate 	} else {
3767c478bd9Sstevel@tonic-gate 		/* no */
3777c478bd9Sstevel@tonic-gate 		if ( (new_sos = (Seqorset *)NSLBERI_MALLOC( sizeof(Seqorset)))
3787c478bd9Sstevel@tonic-gate 		    == NULLSEQORSET ) {
3797c478bd9Sstevel@tonic-gate 			return( -1 );
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 	ber->ber_sos_stack_posn++;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	if ( ber->ber_sos == NULLSEQORSET )
3857c478bd9Sstevel@tonic-gate 		new_sos->sos_first = ber->ber_ptr;
3867c478bd9Sstevel@tonic-gate 	else
3877c478bd9Sstevel@tonic-gate 		new_sos->sos_first = ber->ber_sos->sos_ptr;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	/* Set aside room for a 4 byte length field */
3907c478bd9Sstevel@tonic-gate 	new_sos->sos_ptr = new_sos->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
3917c478bd9Sstevel@tonic-gate 	new_sos->sos_tag = tag;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	new_sos->sos_next = ber->ber_sos;
3947c478bd9Sstevel@tonic-gate 	new_sos->sos_clen = 0;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	ber->ber_sos = new_sos;
3977c478bd9Sstevel@tonic-gate     if (ber->ber_sos->sos_ptr > ber->ber_end) {
3987c478bd9Sstevel@tonic-gate         nslberi_ber_realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
3997c478bd9Sstevel@tonic-gate     }
4007c478bd9Sstevel@tonic-gate 	return( 0 );
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate int
4047c478bd9Sstevel@tonic-gate LDAP_CALL
ber_start_seq(BerElement * ber,ber_tag_t tag)4057c478bd9Sstevel@tonic-gate ber_start_seq( BerElement *ber, ber_tag_t tag )
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
4087c478bd9Sstevel@tonic-gate 		tag = LBER_SEQUENCE;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	return( ber_start_seqorset( ber, tag ) );
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate int
4147c478bd9Sstevel@tonic-gate LDAP_CALL
ber_start_set(BerElement * ber,ber_tag_t tag)4157c478bd9Sstevel@tonic-gate ber_start_set( BerElement *ber, ber_tag_t tag )
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
4187c478bd9Sstevel@tonic-gate 		tag = LBER_SET;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	return( ber_start_seqorset( ber, tag ) );
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate static int
ber_put_seqorset(BerElement * ber)4247c478bd9Sstevel@tonic-gate ber_put_seqorset( BerElement *ber )
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	ber_len_t	len, netlen;
4277c478bd9Sstevel@tonic-gate 	int		taglen, lenlen;
4287c478bd9Sstevel@tonic-gate 	unsigned char	ltag = 0x80 + FOUR_BYTE_LEN - 1;
4297c478bd9Sstevel@tonic-gate 	Seqorset	*next;
4307c478bd9Sstevel@tonic-gate 	Seqorset	**sos = &ber->ber_sos;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	/*
4337c478bd9Sstevel@tonic-gate 	 * If this is the toplevel sequence or set, we need to actually
4347c478bd9Sstevel@tonic-gate 	 * write the stuff out.  Otherwise, it's already been put in
4357c478bd9Sstevel@tonic-gate 	 * the appropriate buffer and will be written when the toplevel
4367c478bd9Sstevel@tonic-gate 	 * one is written.  In this case all we need to do is update the
4377c478bd9Sstevel@tonic-gate 	 * length and tag.
4387c478bd9Sstevel@tonic-gate 	 */
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	len = (*sos)->sos_clen;
4417c478bd9Sstevel@tonic-gate 	netlen = LBER_HTONL( len );
4427c478bd9Sstevel@tonic-gate 	if ( sizeof(ber_int_t) > 4 && len > LENMASK4 )
4437c478bd9Sstevel@tonic-gate 		return( -1 );
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	if ( ber->ber_options & LBER_OPT_USE_DER ) {
4467c478bd9Sstevel@tonic-gate 		lenlen = ber_calc_lenlen( len );
4477c478bd9Sstevel@tonic-gate 	} else {
4487c478bd9Sstevel@tonic-gate 		lenlen = FOUR_BYTE_LEN;
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
4527c478bd9Sstevel@tonic-gate 		/* write the tag */
4537c478bd9Sstevel@tonic-gate 		if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
4547c478bd9Sstevel@tonic-gate 			return( -1 );
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 		if ( ber->ber_options & LBER_OPT_USE_DER ) {
4577c478bd9Sstevel@tonic-gate 			/* Write the length in the minimum # of octets */
4587c478bd9Sstevel@tonic-gate 			if ( ber_put_len( ber, len, 1 ) == -1 )
4597c478bd9Sstevel@tonic-gate 				return( -1 );
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 			if (lenlen != FOUR_BYTE_LEN) {
4627c478bd9Sstevel@tonic-gate 				/*
4637c478bd9Sstevel@tonic-gate 				 * We set aside FOUR_BYTE_LEN bytes for
4647c478bd9Sstevel@tonic-gate 				 * the length field.  Move the data if
4657c478bd9Sstevel@tonic-gate 				 * we don't actually need that much
4667c478bd9Sstevel@tonic-gate 				 */
4677c478bd9Sstevel@tonic-gate 				SAFEMEMCPY( (*sos)->sos_first + taglen +
4687c478bd9Sstevel@tonic-gate 				    lenlen, (*sos)->sos_first + taglen +
4697c478bd9Sstevel@tonic-gate 				    FOUR_BYTE_LEN, len );
4707c478bd9Sstevel@tonic-gate 			}
4717c478bd9Sstevel@tonic-gate 		} else {
4727c478bd9Sstevel@tonic-gate 			/* Fill FOUR_BYTE_LEN bytes for length field */
4737c478bd9Sstevel@tonic-gate 			/* one byte of length length */
4747c478bd9Sstevel@tonic-gate 			if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 )
4757c478bd9Sstevel@tonic-gate 				return( -1 );
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 			/* the length itself */
4787c478bd9Sstevel@tonic-gate 			if ( ber_write( ber, (char *) &netlen + sizeof(ber_int_t)
4797c478bd9Sstevel@tonic-gate 			    - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
4807c478bd9Sstevel@tonic-gate 			    != FOUR_BYTE_LEN - 1 )
4817c478bd9Sstevel@tonic-gate 				return( -1 );
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 		/* The ber_ptr is at the set/seq start - move it to the end */
4847c478bd9Sstevel@tonic-gate 		ber->ber_ptr += len;
4857c478bd9Sstevel@tonic-gate 	} else {
4867c478bd9Sstevel@tonic-gate 		ber_tag_t	ntag;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		/* the tag */
4897c478bd9Sstevel@tonic-gate 		taglen = ber_calc_taglen( (*sos)->sos_tag );
4907c478bd9Sstevel@tonic-gate 		ntag = LBER_HTONL( (*sos)->sos_tag );
4917c478bd9Sstevel@tonic-gate 		SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
4927c478bd9Sstevel@tonic-gate 		    sizeof(ber_int_t) - taglen, taglen );
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		if ( ber->ber_options & LBER_OPT_USE_DER ) {
495*55fea89dSDan Cross 			ltag = (lenlen == 1) ? (unsigned char)len :
4967c478bd9Sstevel@tonic-gate                 (unsigned char) (0x80 + (lenlen - 1));
4977c478bd9Sstevel@tonic-gate 		}
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 		/* one byte of length length */
5007c478bd9Sstevel@tonic-gate 		SAFEMEMCPY( (*sos)->sos_first + 1, &ltag, 1 );
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		if ( ber->ber_options & LBER_OPT_USE_DER ) {
5037c478bd9Sstevel@tonic-gate 			if (lenlen > 1) {
5047c478bd9Sstevel@tonic-gate 				/* Write the length itself */
5057c478bd9Sstevel@tonic-gate 				SAFEMEMCPY( (*sos)->sos_first + 2,
5067c478bd9Sstevel@tonic-gate 				    (char *)&netlen + sizeof(ber_uint_t) -
5077c478bd9Sstevel@tonic-gate 				    (lenlen - 1),
5087c478bd9Sstevel@tonic-gate 				    lenlen - 1 );
5097c478bd9Sstevel@tonic-gate 			}
5107c478bd9Sstevel@tonic-gate 			if (lenlen != FOUR_BYTE_LEN) {
5117c478bd9Sstevel@tonic-gate 				/*
5127c478bd9Sstevel@tonic-gate 				 * We set aside FOUR_BYTE_LEN bytes for
5137c478bd9Sstevel@tonic-gate 				 * the length field.  Move the data if
5147c478bd9Sstevel@tonic-gate 				 * we don't actually need that much
5157c478bd9Sstevel@tonic-gate 				 */
5167c478bd9Sstevel@tonic-gate 				SAFEMEMCPY( (*sos)->sos_first + taglen +
5177c478bd9Sstevel@tonic-gate 				    lenlen, (*sos)->sos_first + taglen +
5187c478bd9Sstevel@tonic-gate 				    FOUR_BYTE_LEN, len );
5197c478bd9Sstevel@tonic-gate 			}
5207c478bd9Sstevel@tonic-gate 		} else {
5217c478bd9Sstevel@tonic-gate 			/* the length itself */
5227c478bd9Sstevel@tonic-gate 			SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
5237c478bd9Sstevel@tonic-gate 			    (char *) &netlen + sizeof(ber_int_t) -
5247c478bd9Sstevel@tonic-gate 			    (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
5257c478bd9Sstevel@tonic-gate 		}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 		next->sos_clen += (taglen + lenlen + len);
5287c478bd9Sstevel@tonic-gate 		next->sos_ptr += (taglen + lenlen + len);
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	/* we're done with this seqorset, so free it up */
5327c478bd9Sstevel@tonic-gate 	/* was this one from the local stack ? */
5337c478bd9Sstevel@tonic-gate 	if (ber->ber_sos_stack_posn <= SOS_STACK_SIZE) {
5347c478bd9Sstevel@tonic-gate 		/* yes */
5357c478bd9Sstevel@tonic-gate 	} else {
5367c478bd9Sstevel@tonic-gate 		/* no */
5377c478bd9Sstevel@tonic-gate 		NSLBERI_FREE( (char *) (*sos) );
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 	ber->ber_sos_stack_posn--;
5407c478bd9Sstevel@tonic-gate 	*sos = next;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	return( taglen + lenlen + len );
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate int
5467c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_seq(BerElement * ber)5477c478bd9Sstevel@tonic-gate ber_put_seq( BerElement *ber )
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate 	return( ber_put_seqorset( ber ) );
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate int
5537c478bd9Sstevel@tonic-gate LDAP_CALL
ber_put_set(BerElement * ber)5547c478bd9Sstevel@tonic-gate ber_put_set( BerElement *ber )
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate 	return( ber_put_seqorset( ber ) );
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /* VARARGS */
5607c478bd9Sstevel@tonic-gate int
5617c478bd9Sstevel@tonic-gate LDAP_C
ber_printf(BerElement * ber,const char * fmt,...)5627c478bd9Sstevel@tonic-gate ber_printf( BerElement *ber, const char *fmt, ... )
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	va_list		ap;
5657c478bd9Sstevel@tonic-gate 	char		*s, **ss;
566924965c7SSerge Dussud 	struct berval	*bval, **bv;
5677c478bd9Sstevel@tonic-gate 	int		rc, i;
5687c478bd9Sstevel@tonic-gate 	ber_len_t	len;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	va_start( ap, fmt );
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate #ifdef LDAP_DEBUG
5737c478bd9Sstevel@tonic-gate 	if ( lber_debug & 64 ) {
5747c478bd9Sstevel@tonic-gate 		char msg[80];
5757c478bd9Sstevel@tonic-gate 		sprintf( msg, "ber_printf fmt (%s)\n", fmt );
5767c478bd9Sstevel@tonic-gate 		ber_err_print( msg );
5777c478bd9Sstevel@tonic-gate 	}
5787c478bd9Sstevel@tonic-gate #endif
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	for ( rc = 0; *fmt && rc != -1; fmt++ ) {
5817c478bd9Sstevel@tonic-gate 		switch ( *fmt ) {
5827c478bd9Sstevel@tonic-gate 		case 'b':	/* boolean */
5837c478bd9Sstevel@tonic-gate 			i = va_arg( ap, int );
5847c478bd9Sstevel@tonic-gate 			rc = ber_put_boolean( ber, i, ber->ber_tag );
5857c478bd9Sstevel@tonic-gate 			break;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 		case 'i':	/* int */
5887c478bd9Sstevel@tonic-gate 			i = va_arg( ap, int );
5897c478bd9Sstevel@tonic-gate 			rc = ber_put_int( ber, (ber_int_t)i, ber->ber_tag );
5907c478bd9Sstevel@tonic-gate 			break;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 		case 'e':	/* enumeration */
5937c478bd9Sstevel@tonic-gate 			i = va_arg( ap, int );
5947c478bd9Sstevel@tonic-gate 			rc = ber_put_enum( ber, (ber_int_t)i, ber->ber_tag );
5957c478bd9Sstevel@tonic-gate 			break;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 		case 'n':	/* null */
5987c478bd9Sstevel@tonic-gate 			rc = ber_put_null( ber, ber->ber_tag );
5997c478bd9Sstevel@tonic-gate 			break;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 		case 'o':	/* octet string (non-null terminated) */
6027c478bd9Sstevel@tonic-gate 			s = va_arg( ap, char * );
6037c478bd9Sstevel@tonic-gate 			len = va_arg( ap, int );
6047c478bd9Sstevel@tonic-gate 			rc = ber_put_ostring( ber, s, len, ber->ber_tag );
6057c478bd9Sstevel@tonic-gate 			break;
6067c478bd9Sstevel@tonic-gate 
607924965c7SSerge Dussud 		case 'O':	/* berval octet string */
608924965c7SSerge Dussud 			if( ( bval = va_arg( ap, struct berval * ) ) == NULL )
609924965c7SSerge Dussud 				break;
610924965c7SSerge Dussud 			if( bval->bv_len == 0 ) {
611924965c7SSerge Dussud 				rc = ber_put_ostring( ber, "", 0, ber->ber_tag );
612924965c7SSerge Dussud 			} else {
613924965c7SSerge Dussud 				rc = ber_put_ostring( ber, bval->bv_val, bval->bv_len,
614924965c7SSerge Dussud 				    ber->ber_tag );
615924965c7SSerge Dussud 			}
616924965c7SSerge Dussud 			break;
617924965c7SSerge Dussud 
6187c478bd9Sstevel@tonic-gate 		case 's':	/* string */
6197c478bd9Sstevel@tonic-gate 			s = va_arg( ap, char * );
6207c478bd9Sstevel@tonic-gate 			rc = ber_put_string( ber, s, ber->ber_tag );
6217c478bd9Sstevel@tonic-gate 			break;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		case 'B':	/* bit string */
6247c478bd9Sstevel@tonic-gate 			s = va_arg( ap, char * );
6257c478bd9Sstevel@tonic-gate 			len = va_arg( ap, int );	/* in bits */
6267c478bd9Sstevel@tonic-gate 			rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
6277c478bd9Sstevel@tonic-gate 			break;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 		case 't':	/* tag for the next element */
6307c478bd9Sstevel@tonic-gate 			ber->ber_tag = va_arg( ap, ber_tag_t );
6317c478bd9Sstevel@tonic-gate 			ber->ber_usertag = 1;
6327c478bd9Sstevel@tonic-gate 			break;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 		case 'v':	/* vector of strings */
6357c478bd9Sstevel@tonic-gate 			if ( (ss = va_arg( ap, char ** )) == NULL )
6367c478bd9Sstevel@tonic-gate 				break;
6377c478bd9Sstevel@tonic-gate 			for ( i = 0; ss[i] != NULL; i++ ) {
6387c478bd9Sstevel@tonic-gate 				if ( (rc = ber_put_string( ber, ss[i],
6397c478bd9Sstevel@tonic-gate 				    ber->ber_tag )) == -1 )
6407c478bd9Sstevel@tonic-gate 					break;
6417c478bd9Sstevel@tonic-gate 			}
6427c478bd9Sstevel@tonic-gate 			break;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 		case 'V':	/* sequences of strings + lengths */
6457c478bd9Sstevel@tonic-gate 			if ( (bv = va_arg( ap, struct berval ** )) == NULL )
6467c478bd9Sstevel@tonic-gate 				break;
6477c478bd9Sstevel@tonic-gate 			for ( i = 0; bv[i] != NULL; i++ ) {
6487c478bd9Sstevel@tonic-gate 				if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
6497c478bd9Sstevel@tonic-gate 				    bv[i]->bv_len, ber->ber_tag )) == -1 )
6507c478bd9Sstevel@tonic-gate 					break;
6517c478bd9Sstevel@tonic-gate 			}
6527c478bd9Sstevel@tonic-gate 			break;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 		case '{':	/* begin sequence */
6557c478bd9Sstevel@tonic-gate 			rc = ber_start_seq( ber, ber->ber_tag );
6567c478bd9Sstevel@tonic-gate 			break;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 		case '}':	/* end sequence */
6597c478bd9Sstevel@tonic-gate 			rc = ber_put_seqorset( ber );
6607c478bd9Sstevel@tonic-gate 			break;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		case '[':	/* begin set */
6637c478bd9Sstevel@tonic-gate 			rc = ber_start_set( ber, ber->ber_tag );
6647c478bd9Sstevel@tonic-gate 			break;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 		case ']':	/* end set */
6677c478bd9Sstevel@tonic-gate 			rc = ber_put_seqorset( ber );
6687c478bd9Sstevel@tonic-gate 			break;
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		default: {
6717c478bd9Sstevel@tonic-gate 				char msg[80];
6727c478bd9Sstevel@tonic-gate 				sprintf( msg, "unknown fmt %c\n", *fmt );
6737c478bd9Sstevel@tonic-gate 				ber_err_print( msg );
6747c478bd9Sstevel@tonic-gate 				rc = -1;
6757c478bd9Sstevel@tonic-gate 				break;
6767c478bd9Sstevel@tonic-gate 			}
6777c478bd9Sstevel@tonic-gate 		}
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 		if ( ber->ber_usertag == 0 )
6807c478bd9Sstevel@tonic-gate 			ber->ber_tag = LBER_DEFAULT;
6817c478bd9Sstevel@tonic-gate 		else
6827c478bd9Sstevel@tonic-gate 			ber->ber_usertag = 0;
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	va_end( ap );
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	return( rc );
6887c478bd9Sstevel@tonic-gate }
689