1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 2001 by Sun Microsystems, Inc.
3*0Sstevel@tonic-gate  * All rights reserved.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
9*0Sstevel@tonic-gate  *
10*0Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public License
11*0Sstevel@tonic-gate  * Version 1.0 (the "NPL"); you may not use this file except in
12*0Sstevel@tonic-gate  * compliance with the NPL.  You may obtain a copy of the NPL at
13*0Sstevel@tonic-gate  * http://www.mozilla.org/NPL/
14*0Sstevel@tonic-gate  *
15*0Sstevel@tonic-gate  * Software distributed under the NPL is distributed on an "AS IS" basis,
16*0Sstevel@tonic-gate  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
17*0Sstevel@tonic-gate  * for the specific language governing rights and limitations under the
18*0Sstevel@tonic-gate  * NPL.
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * The Initial Developer of this code under the NPL is Netscape
21*0Sstevel@tonic-gate  * Communications Corporation.  Portions created by Netscape are
22*0Sstevel@tonic-gate  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
23*0Sstevel@tonic-gate  * Reserved.
24*0Sstevel@tonic-gate  */
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * Copyright (c) 1990 Regents of the University of Michigan.
28*0Sstevel@tonic-gate  * All rights reserved.
29*0Sstevel@tonic-gate  *
30*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
31*0Sstevel@tonic-gate  * provided that this notice is preserved and that due credit is given
32*0Sstevel@tonic-gate  * to the University of Michigan at Ann Arbor. The name of the University
33*0Sstevel@tonic-gate  * may not be used to endorse or promote products derived from this
34*0Sstevel@tonic-gate  * software without specific prior written permission. This software
35*0Sstevel@tonic-gate  * is provided ``as is'' without express or implied warranty.
36*0Sstevel@tonic-gate  */
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate /* encode.c - ber output encoding routines */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include "lber-int.h"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /* the following constants are used in ber_calc_lenlen */
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #define LENMASK1	0xFF
45*0Sstevel@tonic-gate #define	LENMASK2 	0xFFFF
46*0Sstevel@tonic-gate #define LENMASK3	0xFFFFFF
47*0Sstevel@tonic-gate #define LENMASK4	0xFFFFFFFF
48*0Sstevel@tonic-gate #define _MASK		0x80
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate static int
51*0Sstevel@tonic-gate ber_calc_taglen( ber_tag_t tag )
52*0Sstevel@tonic-gate {
53*0Sstevel@tonic-gate 	int		i;
54*0Sstevel@tonic-gate 	ber_int_t	mask;
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate 	/* find the first non-all-zero byte in the tag */
57*0Sstevel@tonic-gate 	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
58*0Sstevel@tonic-gate 		mask = (LENMASK3 << (i * 8));
59*0Sstevel@tonic-gate 		/* not all zero */
60*0Sstevel@tonic-gate 		if ( tag & mask )
61*0Sstevel@tonic-gate 			break;
62*0Sstevel@tonic-gate 	}
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 	return( i + 1 );
65*0Sstevel@tonic-gate }
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate static int
68*0Sstevel@tonic-gate ber_put_tag( BerElement	*ber, ber_tag_t tag, int nosos )
69*0Sstevel@tonic-gate {
70*0Sstevel@tonic-gate 	int		taglen;
71*0Sstevel@tonic-gate 	ber_tag_t	ntag;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	taglen = ber_calc_taglen( tag );
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	ntag = LBER_HTONL( tag );
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	return( ber_write( ber, ((char *) &ntag) + sizeof(ber_int_t) - taglen,
78*0Sstevel@tonic-gate 	    taglen, nosos ) );
79*0Sstevel@tonic-gate }
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static int
82*0Sstevel@tonic-gate ber_calc_lenlen( ber_len_t len )
83*0Sstevel@tonic-gate {
84*0Sstevel@tonic-gate 	/*
85*0Sstevel@tonic-gate 	 * short len if it's less than 128 - one byte giving the len,
86*0Sstevel@tonic-gate 	 * with bit 8 0.
87*0Sstevel@tonic-gate 	 */
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	if ( len <= 0x7F )
90*0Sstevel@tonic-gate 		return( 1 );
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	/*
93*0Sstevel@tonic-gate 	 * long len otherwise - one byte with bit 8 set, giving the
94*0Sstevel@tonic-gate 	 * length of the length, followed by the length itself.
95*0Sstevel@tonic-gate 	 */
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	if ( len <= LENMASK1 )
98*0Sstevel@tonic-gate 		return( 2 );
99*0Sstevel@tonic-gate 	if ( len <= LENMASK2 )
100*0Sstevel@tonic-gate 		return( 3 );
101*0Sstevel@tonic-gate 	if ( len <= LENMASK3 )
102*0Sstevel@tonic-gate 		return( 4 );
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	return( 5 );
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate static int
108*0Sstevel@tonic-gate ber_put_len( BerElement *ber, ber_len_t len, int nosos )
109*0Sstevel@tonic-gate {
110*0Sstevel@tonic-gate 	int		i;
111*0Sstevel@tonic-gate 	char		lenlen;
112*0Sstevel@tonic-gate 	ber_int_t	mask;
113*0Sstevel@tonic-gate 	ber_len_t	netlen;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	/*
116*0Sstevel@tonic-gate 	 * short len if it's less than 128 - one byte giving the len,
117*0Sstevel@tonic-gate 	 * with bit 8 0.
118*0Sstevel@tonic-gate 	 */
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if ( len <= 127 ) {
121*0Sstevel@tonic-gate 		netlen = LBER_HTONL( len );
122*0Sstevel@tonic-gate 		return( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) - 1,
123*0Sstevel@tonic-gate 		    1, nosos ) );
124*0Sstevel@tonic-gate 	}
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	/*
127*0Sstevel@tonic-gate 	 * long len otherwise - one byte with bit 8 set, giving the
128*0Sstevel@tonic-gate 	 * length of the length, followed by the length itself.
129*0Sstevel@tonic-gate 	 */
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	/* find the first non-all-zero byte */
132*0Sstevel@tonic-gate 	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
133*0Sstevel@tonic-gate 		mask = (LENMASK1 << (i * 8));
134*0Sstevel@tonic-gate 		/* not all zero */
135*0Sstevel@tonic-gate 		if ( len & mask )
136*0Sstevel@tonic-gate 			break;
137*0Sstevel@tonic-gate 	}
138*0Sstevel@tonic-gate 	lenlen = ++i;
139*0Sstevel@tonic-gate 	if ( lenlen > 4 )
140*0Sstevel@tonic-gate 		return( -1 );
141*0Sstevel@tonic-gate 	lenlen |= 0x80;
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	/* write the length of the length */
144*0Sstevel@tonic-gate 	if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
145*0Sstevel@tonic-gate 		return( -1 );
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	/* write the length itself */
148*0Sstevel@tonic-gate 	netlen = LBER_HTONL( len );
149*0Sstevel@tonic-gate 	if ( ber_write( ber, (char *) &netlen + (sizeof(ber_int_t) - i), i, nosos )
150*0Sstevel@tonic-gate 	    != i )
151*0Sstevel@tonic-gate 		return( -1 );
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	return( i + 1 );
154*0Sstevel@tonic-gate }
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate static int
157*0Sstevel@tonic-gate ber_put_int_or_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate 	int		i, sign, taglen;
160*0Sstevel@tonic-gate 	int		len, lenlen;
161*0Sstevel@tonic-gate 	ber_int_t	netnum, mask;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	sign = (num < 0);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/*
166*0Sstevel@tonic-gate 	 * high bit is set - look for first non-all-one byte
167*0Sstevel@tonic-gate 	 * high bit is clear - look for first non-all-zero byte
168*0Sstevel@tonic-gate 	 */
169*0Sstevel@tonic-gate 	for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
170*0Sstevel@tonic-gate 		mask = (LENMASK1 << (i * 8));
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 		if ( sign ) {
173*0Sstevel@tonic-gate 			/* not all ones */
174*0Sstevel@tonic-gate 			if ( (num & mask) != mask )
175*0Sstevel@tonic-gate 				break;
176*0Sstevel@tonic-gate 		} else {
177*0Sstevel@tonic-gate 			/* not all zero */
178*0Sstevel@tonic-gate 			if ( num & mask )
179*0Sstevel@tonic-gate 				break;
180*0Sstevel@tonic-gate 		}
181*0Sstevel@tonic-gate 	}
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	/*
184*0Sstevel@tonic-gate 	 * we now have the "leading byte".  if the high bit on this
185*0Sstevel@tonic-gate 	 * byte matches the sign bit, we need to "back up" a byte.
186*0Sstevel@tonic-gate 	 */
187*0Sstevel@tonic-gate 	mask = (num & (_MASK << (i * 8)));
188*0Sstevel@tonic-gate 	if ( (mask && !sign) || (sign && !mask) )
189*0Sstevel@tonic-gate 		i++;
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	len = i + 1;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
194*0Sstevel@tonic-gate 		return( -1 );
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
197*0Sstevel@tonic-gate 		return( -1 );
198*0Sstevel@tonic-gate 	i++;
199*0Sstevel@tonic-gate 	netnum = LBER_HTONL( num );
200*0Sstevel@tonic-gate 	if ( ber_write( ber, (char *) &netnum + (sizeof(ber_int_t) - i), i, 0 )
201*0Sstevel@tonic-gate 		== i)
202*0Sstevel@tonic-gate 		/* length of tag + length + contents */
203*0Sstevel@tonic-gate 		return( taglen + lenlen + i );
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	return( -1 );
206*0Sstevel@tonic-gate }
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate int
209*0Sstevel@tonic-gate LDAP_CALL
210*0Sstevel@tonic-gate ber_put_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
211*0Sstevel@tonic-gate {
212*0Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
213*0Sstevel@tonic-gate 		tag = LBER_ENUMERATED;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	return( ber_put_int_or_enum( ber, num, tag ) );
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate int
219*0Sstevel@tonic-gate LDAP_CALL
220*0Sstevel@tonic-gate ber_put_int( BerElement *ber, ber_int_t num, ber_tag_t tag )
221*0Sstevel@tonic-gate {
222*0Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
223*0Sstevel@tonic-gate 		tag = LBER_INTEGER;
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	return( ber_put_int_or_enum( ber, num, tag ) );
226*0Sstevel@tonic-gate }
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate int
229*0Sstevel@tonic-gate LDAP_CALL
230*0Sstevel@tonic-gate ber_put_ostring( BerElement *ber, char *str, ber_len_t len,
231*0Sstevel@tonic-gate 	ber_tag_t tag )
232*0Sstevel@tonic-gate {
233*0Sstevel@tonic-gate 	int	taglen, lenlen, rc;
234*0Sstevel@tonic-gate #ifdef STR_TRANSLATION
235*0Sstevel@tonic-gate 	int	free_str;
236*0Sstevel@tonic-gate #endif /* STR_TRANSLATION */
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
239*0Sstevel@tonic-gate 		tag = LBER_OCTETSTRING;
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
242*0Sstevel@tonic-gate 		return( -1 );
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate #ifdef STR_TRANSLATION
245*0Sstevel@tonic-gate 	if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0
246*0Sstevel@tonic-gate 	    && ber->ber_encode_translate_proc != NULL ) {
247*0Sstevel@tonic-gate 		if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
248*0Sstevel@tonic-gate 		    != 0 ) {
249*0Sstevel@tonic-gate 			return( -1 );
250*0Sstevel@tonic-gate 		}
251*0Sstevel@tonic-gate 		free_str = 1;
252*0Sstevel@tonic-gate 	} else {
253*0Sstevel@tonic-gate 		free_str = 0;
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate #endif /* STR_TRANSLATION */
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate     /*
258*0Sstevel@tonic-gate      *  Note:  below is a spot where we limit ber_write
259*0Sstevel@tonic-gate      *         to signed long (instead of unsigned long)
260*0Sstevel@tonic-gate      */
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
263*0Sstevel@tonic-gate 		ber_write( ber, str, len, 0 ) != (ber_int_t) len ) {
264*0Sstevel@tonic-gate 		rc = -1;
265*0Sstevel@tonic-gate 	} else {
266*0Sstevel@tonic-gate 		/* return length of tag + length + contents */
267*0Sstevel@tonic-gate 		rc = taglen + lenlen + len;
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate #ifdef STR_TRANSLATION
271*0Sstevel@tonic-gate 	if ( free_str ) {
272*0Sstevel@tonic-gate 		NSLBERI_FREE( str );
273*0Sstevel@tonic-gate 	}
274*0Sstevel@tonic-gate #endif /* STR_TRANSLATION */
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	return( rc );
277*0Sstevel@tonic-gate }
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate int
280*0Sstevel@tonic-gate LDAP_CALL
281*0Sstevel@tonic-gate ber_put_string( BerElement *ber, char *str, ber_tag_t tag )
282*0Sstevel@tonic-gate {
283*0Sstevel@tonic-gate 	return( ber_put_ostring( ber, str, (ber_len_t) strlen( str ), tag ));
284*0Sstevel@tonic-gate }
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate int
287*0Sstevel@tonic-gate LDAP_CALL
288*0Sstevel@tonic-gate ber_put_bitstring( BerElement *ber, char *str,
289*0Sstevel@tonic-gate 	ber_len_t blen /* in bits */, ber_tag_t tag )
290*0Sstevel@tonic-gate {
291*0Sstevel@tonic-gate 	int		taglen, lenlen, len;
292*0Sstevel@tonic-gate 	unsigned char	unusedbits;
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
295*0Sstevel@tonic-gate 		tag = LBER_BITSTRING;
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
298*0Sstevel@tonic-gate 		return( -1 );
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	len = ( blen + 7 ) / 8;
301*0Sstevel@tonic-gate 	unusedbits = (unsigned char) (len * 8 - blen);
302*0Sstevel@tonic-gate 	if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
303*0Sstevel@tonic-gate 		return( -1 );
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
306*0Sstevel@tonic-gate 		return( -1 );
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	if ( ber_write( ber, str, len, 0 ) != len )
309*0Sstevel@tonic-gate 		return( -1 );
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	/* return length of tag + length + unused bit count + contents */
312*0Sstevel@tonic-gate 	return( taglen + 1 + lenlen + len );
313*0Sstevel@tonic-gate }
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate int
316*0Sstevel@tonic-gate LDAP_CALL
317*0Sstevel@tonic-gate ber_put_null( BerElement *ber, ber_tag_t tag )
318*0Sstevel@tonic-gate {
319*0Sstevel@tonic-gate 	int	taglen;
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
322*0Sstevel@tonic-gate 		tag = LBER_NULL;
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
325*0Sstevel@tonic-gate 		return( -1 );
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	if ( ber_put_len( ber, 0, 0 ) != 1 )
328*0Sstevel@tonic-gate 		return( -1 );
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	return( taglen + 1 );
331*0Sstevel@tonic-gate }
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate int
334*0Sstevel@tonic-gate LDAP_CALL
335*0Sstevel@tonic-gate ber_put_boolean( BerElement *ber, int boolval, ber_tag_t tag )
336*0Sstevel@tonic-gate {
337*0Sstevel@tonic-gate 	int		taglen;
338*0Sstevel@tonic-gate 	unsigned char	trueval = 0xff;
339*0Sstevel@tonic-gate 	unsigned char	falseval = 0x00;
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
342*0Sstevel@tonic-gate 		tag = LBER_BOOLEAN;
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
345*0Sstevel@tonic-gate 		return( -1 );
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	if ( ber_put_len( ber, 1, 0 ) != 1 )
348*0Sstevel@tonic-gate 		return( -1 );
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
351*0Sstevel@tonic-gate 	    != 1 )
352*0Sstevel@tonic-gate 		return( -1 );
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	return( taglen + 2 );
355*0Sstevel@tonic-gate }
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate #define FOUR_BYTE_LEN	5
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate /* the idea here is roughly this: we maintain a stack of these Seqorset
361*0Sstevel@tonic-gate  * structures. This is pushed when we see the beginning of a new set or
362*0Sstevel@tonic-gate  * sequence. It is popped when we see the end of a set or sequence.
363*0Sstevel@tonic-gate  * Since we don't want to malloc and free these structures all the time,
364*0Sstevel@tonic-gate  * we pre-allocate a small set of them within the ber element structure.
365*0Sstevel@tonic-gate  * thus we need to spot when we've overflowed this stack and fall back to
366*0Sstevel@tonic-gate  * malloc'ing instead.
367*0Sstevel@tonic-gate  */
368*0Sstevel@tonic-gate static int
369*0Sstevel@tonic-gate ber_start_seqorset( BerElement *ber, ber_tag_t tag )
370*0Sstevel@tonic-gate {
371*0Sstevel@tonic-gate 	Seqorset	*new_sos;
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	/* can we fit into the local stack ? */
374*0Sstevel@tonic-gate 	if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
375*0Sstevel@tonic-gate 		/* yes */
376*0Sstevel@tonic-gate 		new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
377*0Sstevel@tonic-gate 	} else {
378*0Sstevel@tonic-gate 		/* no */
379*0Sstevel@tonic-gate 		if ( (new_sos = (Seqorset *)NSLBERI_MALLOC( sizeof(Seqorset)))
380*0Sstevel@tonic-gate 		    == NULLSEQORSET ) {
381*0Sstevel@tonic-gate 			return( -1 );
382*0Sstevel@tonic-gate 		}
383*0Sstevel@tonic-gate 	}
384*0Sstevel@tonic-gate 	ber->ber_sos_stack_posn++;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	if ( ber->ber_sos == NULLSEQORSET )
387*0Sstevel@tonic-gate 		new_sos->sos_first = ber->ber_ptr;
388*0Sstevel@tonic-gate 	else
389*0Sstevel@tonic-gate 		new_sos->sos_first = ber->ber_sos->sos_ptr;
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	/* Set aside room for a 4 byte length field */
392*0Sstevel@tonic-gate 	new_sos->sos_ptr = new_sos->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
393*0Sstevel@tonic-gate 	new_sos->sos_tag = tag;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	new_sos->sos_next = ber->ber_sos;
396*0Sstevel@tonic-gate 	new_sos->sos_clen = 0;
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	ber->ber_sos = new_sos;
399*0Sstevel@tonic-gate     if (ber->ber_sos->sos_ptr > ber->ber_end) {
400*0Sstevel@tonic-gate         nslberi_ber_realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
401*0Sstevel@tonic-gate     }
402*0Sstevel@tonic-gate 	return( 0 );
403*0Sstevel@tonic-gate }
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate int
406*0Sstevel@tonic-gate LDAP_CALL
407*0Sstevel@tonic-gate ber_start_seq( BerElement *ber, ber_tag_t tag )
408*0Sstevel@tonic-gate {
409*0Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
410*0Sstevel@tonic-gate 		tag = LBER_SEQUENCE;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	return( ber_start_seqorset( ber, tag ) );
413*0Sstevel@tonic-gate }
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate int
416*0Sstevel@tonic-gate LDAP_CALL
417*0Sstevel@tonic-gate ber_start_set( BerElement *ber, ber_tag_t tag )
418*0Sstevel@tonic-gate {
419*0Sstevel@tonic-gate 	if ( tag == LBER_DEFAULT )
420*0Sstevel@tonic-gate 		tag = LBER_SET;
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	return( ber_start_seqorset( ber, tag ) );
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate static int
426*0Sstevel@tonic-gate ber_put_seqorset( BerElement *ber )
427*0Sstevel@tonic-gate {
428*0Sstevel@tonic-gate 	ber_len_t	len, netlen;
429*0Sstevel@tonic-gate 	int		taglen, lenlen;
430*0Sstevel@tonic-gate 	unsigned char	ltag = 0x80 + FOUR_BYTE_LEN - 1;
431*0Sstevel@tonic-gate 	Seqorset	*next;
432*0Sstevel@tonic-gate 	Seqorset	**sos = &ber->ber_sos;
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	/*
435*0Sstevel@tonic-gate 	 * If this is the toplevel sequence or set, we need to actually
436*0Sstevel@tonic-gate 	 * write the stuff out.  Otherwise, it's already been put in
437*0Sstevel@tonic-gate 	 * the appropriate buffer and will be written when the toplevel
438*0Sstevel@tonic-gate 	 * one is written.  In this case all we need to do is update the
439*0Sstevel@tonic-gate 	 * length and tag.
440*0Sstevel@tonic-gate 	 */
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	len = (*sos)->sos_clen;
443*0Sstevel@tonic-gate 	netlen = LBER_HTONL( len );
444*0Sstevel@tonic-gate 	if ( sizeof(ber_int_t) > 4 && len > LENMASK4 )
445*0Sstevel@tonic-gate 		return( -1 );
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	if ( ber->ber_options & LBER_OPT_USE_DER ) {
448*0Sstevel@tonic-gate 		lenlen = ber_calc_lenlen( len );
449*0Sstevel@tonic-gate 	} else {
450*0Sstevel@tonic-gate 		lenlen = FOUR_BYTE_LEN;
451*0Sstevel@tonic-gate 	}
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
454*0Sstevel@tonic-gate 		/* write the tag */
455*0Sstevel@tonic-gate 		if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
456*0Sstevel@tonic-gate 			return( -1 );
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 		if ( ber->ber_options & LBER_OPT_USE_DER ) {
459*0Sstevel@tonic-gate 			/* Write the length in the minimum # of octets */
460*0Sstevel@tonic-gate 			if ( ber_put_len( ber, len, 1 ) == -1 )
461*0Sstevel@tonic-gate 				return( -1 );
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 			if (lenlen != FOUR_BYTE_LEN) {
464*0Sstevel@tonic-gate 				/*
465*0Sstevel@tonic-gate 				 * We set aside FOUR_BYTE_LEN bytes for
466*0Sstevel@tonic-gate 				 * the length field.  Move the data if
467*0Sstevel@tonic-gate 				 * we don't actually need that much
468*0Sstevel@tonic-gate 				 */
469*0Sstevel@tonic-gate 				SAFEMEMCPY( (*sos)->sos_first + taglen +
470*0Sstevel@tonic-gate 				    lenlen, (*sos)->sos_first + taglen +
471*0Sstevel@tonic-gate 				    FOUR_BYTE_LEN, len );
472*0Sstevel@tonic-gate 			}
473*0Sstevel@tonic-gate 		} else {
474*0Sstevel@tonic-gate 			/* Fill FOUR_BYTE_LEN bytes for length field */
475*0Sstevel@tonic-gate 			/* one byte of length length */
476*0Sstevel@tonic-gate 			if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 )
477*0Sstevel@tonic-gate 				return( -1 );
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 			/* the length itself */
480*0Sstevel@tonic-gate 			if ( ber_write( ber, (char *) &netlen + sizeof(ber_int_t)
481*0Sstevel@tonic-gate 			    - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
482*0Sstevel@tonic-gate 			    != FOUR_BYTE_LEN - 1 )
483*0Sstevel@tonic-gate 				return( -1 );
484*0Sstevel@tonic-gate 		}
485*0Sstevel@tonic-gate 		/* The ber_ptr is at the set/seq start - move it to the end */
486*0Sstevel@tonic-gate 		ber->ber_ptr += len;
487*0Sstevel@tonic-gate 	} else {
488*0Sstevel@tonic-gate 		ber_tag_t	ntag;
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		/* the tag */
491*0Sstevel@tonic-gate 		taglen = ber_calc_taglen( (*sos)->sos_tag );
492*0Sstevel@tonic-gate 		ntag = LBER_HTONL( (*sos)->sos_tag );
493*0Sstevel@tonic-gate 		SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
494*0Sstevel@tonic-gate 		    sizeof(ber_int_t) - taglen, taglen );
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 		if ( ber->ber_options & LBER_OPT_USE_DER ) {
497*0Sstevel@tonic-gate 			ltag = (lenlen == 1) ? (unsigned char)len :
498*0Sstevel@tonic-gate                 (unsigned char) (0x80 + (lenlen - 1));
499*0Sstevel@tonic-gate 		}
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 		/* one byte of length length */
502*0Sstevel@tonic-gate 		SAFEMEMCPY( (*sos)->sos_first + 1, &ltag, 1 );
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 		if ( ber->ber_options & LBER_OPT_USE_DER ) {
505*0Sstevel@tonic-gate 			if (lenlen > 1) {
506*0Sstevel@tonic-gate 				/* Write the length itself */
507*0Sstevel@tonic-gate 				SAFEMEMCPY( (*sos)->sos_first + 2,
508*0Sstevel@tonic-gate 				    (char *)&netlen + sizeof(ber_uint_t) -
509*0Sstevel@tonic-gate 				    (lenlen - 1),
510*0Sstevel@tonic-gate 				    lenlen - 1 );
511*0Sstevel@tonic-gate 			}
512*0Sstevel@tonic-gate 			if (lenlen != FOUR_BYTE_LEN) {
513*0Sstevel@tonic-gate 				/*
514*0Sstevel@tonic-gate 				 * We set aside FOUR_BYTE_LEN bytes for
515*0Sstevel@tonic-gate 				 * the length field.  Move the data if
516*0Sstevel@tonic-gate 				 * we don't actually need that much
517*0Sstevel@tonic-gate 				 */
518*0Sstevel@tonic-gate 				SAFEMEMCPY( (*sos)->sos_first + taglen +
519*0Sstevel@tonic-gate 				    lenlen, (*sos)->sos_first + taglen +
520*0Sstevel@tonic-gate 				    FOUR_BYTE_LEN, len );
521*0Sstevel@tonic-gate 			}
522*0Sstevel@tonic-gate 		} else {
523*0Sstevel@tonic-gate 			/* the length itself */
524*0Sstevel@tonic-gate 			SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
525*0Sstevel@tonic-gate 			    (char *) &netlen + sizeof(ber_int_t) -
526*0Sstevel@tonic-gate 			    (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
527*0Sstevel@tonic-gate 		}
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 		next->sos_clen += (taglen + lenlen + len);
530*0Sstevel@tonic-gate 		next->sos_ptr += (taglen + lenlen + len);
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	/* we're done with this seqorset, so free it up */
534*0Sstevel@tonic-gate 	/* was this one from the local stack ? */
535*0Sstevel@tonic-gate 	if (ber->ber_sos_stack_posn <= SOS_STACK_SIZE) {
536*0Sstevel@tonic-gate 		/* yes */
537*0Sstevel@tonic-gate 	} else {
538*0Sstevel@tonic-gate 		/* no */
539*0Sstevel@tonic-gate 		NSLBERI_FREE( (char *) (*sos) );
540*0Sstevel@tonic-gate 	}
541*0Sstevel@tonic-gate 	ber->ber_sos_stack_posn--;
542*0Sstevel@tonic-gate 	*sos = next;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	return( taglen + lenlen + len );
545*0Sstevel@tonic-gate }
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate int
548*0Sstevel@tonic-gate LDAP_CALL
549*0Sstevel@tonic-gate ber_put_seq( BerElement *ber )
550*0Sstevel@tonic-gate {
551*0Sstevel@tonic-gate 	return( ber_put_seqorset( ber ) );
552*0Sstevel@tonic-gate }
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate int
555*0Sstevel@tonic-gate LDAP_CALL
556*0Sstevel@tonic-gate ber_put_set( BerElement *ber )
557*0Sstevel@tonic-gate {
558*0Sstevel@tonic-gate 	return( ber_put_seqorset( ber ) );
559*0Sstevel@tonic-gate }
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate /* VARARGS */
562*0Sstevel@tonic-gate int
563*0Sstevel@tonic-gate LDAP_C
564*0Sstevel@tonic-gate ber_printf( BerElement *ber, const char *fmt, ... )
565*0Sstevel@tonic-gate {
566*0Sstevel@tonic-gate 	va_list		ap;
567*0Sstevel@tonic-gate 	char		*s, **ss;
568*0Sstevel@tonic-gate 	struct berval	**bv;
569*0Sstevel@tonic-gate 	int		rc, i;
570*0Sstevel@tonic-gate 	ber_len_t	len;
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	va_start( ap, fmt );
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate #ifdef LDAP_DEBUG
575*0Sstevel@tonic-gate 	if ( lber_debug & 64 ) {
576*0Sstevel@tonic-gate 		char msg[80];
577*0Sstevel@tonic-gate 		sprintf( msg, "ber_printf fmt (%s)\n", fmt );
578*0Sstevel@tonic-gate 		ber_err_print( msg );
579*0Sstevel@tonic-gate 	}
580*0Sstevel@tonic-gate #endif
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 	for ( rc = 0; *fmt && rc != -1; fmt++ ) {
583*0Sstevel@tonic-gate 		switch ( *fmt ) {
584*0Sstevel@tonic-gate 		case 'b':	/* boolean */
585*0Sstevel@tonic-gate 			i = va_arg( ap, int );
586*0Sstevel@tonic-gate 			rc = ber_put_boolean( ber, i, ber->ber_tag );
587*0Sstevel@tonic-gate 			break;
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		case 'i':	/* int */
590*0Sstevel@tonic-gate 			i = va_arg( ap, int );
591*0Sstevel@tonic-gate 			rc = ber_put_int( ber, (ber_int_t)i, ber->ber_tag );
592*0Sstevel@tonic-gate 			break;
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 		case 'e':	/* enumeration */
595*0Sstevel@tonic-gate 			i = va_arg( ap, int );
596*0Sstevel@tonic-gate 			rc = ber_put_enum( ber, (ber_int_t)i, ber->ber_tag );
597*0Sstevel@tonic-gate 			break;
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 		case 'n':	/* null */
600*0Sstevel@tonic-gate 			rc = ber_put_null( ber, ber->ber_tag );
601*0Sstevel@tonic-gate 			break;
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 		case 'o':	/* octet string (non-null terminated) */
604*0Sstevel@tonic-gate 			s = va_arg( ap, char * );
605*0Sstevel@tonic-gate 			len = va_arg( ap, int );
606*0Sstevel@tonic-gate 			rc = ber_put_ostring( ber, s, len, ber->ber_tag );
607*0Sstevel@tonic-gate 			break;
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 		case 's':	/* string */
610*0Sstevel@tonic-gate 			s = va_arg( ap, char * );
611*0Sstevel@tonic-gate 			rc = ber_put_string( ber, s, ber->ber_tag );
612*0Sstevel@tonic-gate 			break;
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 		case 'B':	/* bit string */
615*0Sstevel@tonic-gate 			s = va_arg( ap, char * );
616*0Sstevel@tonic-gate 			len = va_arg( ap, int );	/* in bits */
617*0Sstevel@tonic-gate 			rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
618*0Sstevel@tonic-gate 			break;
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 		case 't':	/* tag for the next element */
621*0Sstevel@tonic-gate 			ber->ber_tag = va_arg( ap, ber_tag_t );
622*0Sstevel@tonic-gate 			ber->ber_usertag = 1;
623*0Sstevel@tonic-gate 			break;
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 		case 'v':	/* vector of strings */
626*0Sstevel@tonic-gate 			if ( (ss = va_arg( ap, char ** )) == NULL )
627*0Sstevel@tonic-gate 				break;
628*0Sstevel@tonic-gate 			for ( i = 0; ss[i] != NULL; i++ ) {
629*0Sstevel@tonic-gate 				if ( (rc = ber_put_string( ber, ss[i],
630*0Sstevel@tonic-gate 				    ber->ber_tag )) == -1 )
631*0Sstevel@tonic-gate 					break;
632*0Sstevel@tonic-gate 			}
633*0Sstevel@tonic-gate 			break;
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 		case 'V':	/* sequences of strings + lengths */
636*0Sstevel@tonic-gate 			if ( (bv = va_arg( ap, struct berval ** )) == NULL )
637*0Sstevel@tonic-gate 				break;
638*0Sstevel@tonic-gate 			for ( i = 0; bv[i] != NULL; i++ ) {
639*0Sstevel@tonic-gate 				if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
640*0Sstevel@tonic-gate 				    bv[i]->bv_len, ber->ber_tag )) == -1 )
641*0Sstevel@tonic-gate 					break;
642*0Sstevel@tonic-gate 			}
643*0Sstevel@tonic-gate 			break;
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 		case '{':	/* begin sequence */
646*0Sstevel@tonic-gate 			rc = ber_start_seq( ber, ber->ber_tag );
647*0Sstevel@tonic-gate 			break;
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 		case '}':	/* end sequence */
650*0Sstevel@tonic-gate 			rc = ber_put_seqorset( ber );
651*0Sstevel@tonic-gate 			break;
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 		case '[':	/* begin set */
654*0Sstevel@tonic-gate 			rc = ber_start_set( ber, ber->ber_tag );
655*0Sstevel@tonic-gate 			break;
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 		case ']':	/* end set */
658*0Sstevel@tonic-gate 			rc = ber_put_seqorset( ber );
659*0Sstevel@tonic-gate 			break;
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 		default: {
662*0Sstevel@tonic-gate 				char msg[80];
663*0Sstevel@tonic-gate 				sprintf( msg, "unknown fmt %c\n", *fmt );
664*0Sstevel@tonic-gate 				ber_err_print( msg );
665*0Sstevel@tonic-gate 				rc = -1;
666*0Sstevel@tonic-gate 				break;
667*0Sstevel@tonic-gate 			}
668*0Sstevel@tonic-gate 		}
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 		if ( ber->ber_usertag == 0 )
671*0Sstevel@tonic-gate 			ber->ber_tag = LBER_DEFAULT;
672*0Sstevel@tonic-gate 		else
673*0Sstevel@tonic-gate 			ber->ber_usertag = 0;
674*0Sstevel@tonic-gate 	}
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 	va_end( ap );
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	return( rc );
679*0Sstevel@tonic-gate }
680