10Sstevel@tonic-gate /* 2*7866SSerge.Dussud@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3*7866SSerge.Dussud@Sun.COM * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * The contents of this file are subject to the Netscape Public License 90Sstevel@tonic-gate * Version 1.0 (the "NPL"); you may not use this file except in 100Sstevel@tonic-gate * compliance with the NPL. You may obtain a copy of the NPL at 110Sstevel@tonic-gate * http://www.mozilla.org/NPL/ 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * Software distributed under the NPL is distributed on an "AS IS" basis, 140Sstevel@tonic-gate * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 150Sstevel@tonic-gate * for the specific language governing rights and limitations under the 160Sstevel@tonic-gate * NPL. 170Sstevel@tonic-gate * 180Sstevel@tonic-gate * The Initial Developer of this code under the NPL is Netscape 190Sstevel@tonic-gate * Communications Corporation. Portions created by Netscape are 200Sstevel@tonic-gate * Copyright (C) 1998 Netscape Communications Corporation. All Rights 210Sstevel@tonic-gate * Reserved. 220Sstevel@tonic-gate */ 230Sstevel@tonic-gate 240Sstevel@tonic-gate /* 250Sstevel@tonic-gate * Copyright (c) 1990 Regents of the University of Michigan. 260Sstevel@tonic-gate * All rights reserved. 270Sstevel@tonic-gate * 280Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 290Sstevel@tonic-gate * provided that this notice is preserved and that due credit is given 300Sstevel@tonic-gate * to the University of Michigan at Ann Arbor. The name of the University 310Sstevel@tonic-gate * may not be used to endorse or promote products derived from this 320Sstevel@tonic-gate * software without specific prior written permission. This software 330Sstevel@tonic-gate * is provided ``as is'' without express or implied warranty. 340Sstevel@tonic-gate */ 350Sstevel@tonic-gate 360Sstevel@tonic-gate /* encode.c - ber output encoding routines */ 370Sstevel@tonic-gate 380Sstevel@tonic-gate #include "lber-int.h" 390Sstevel@tonic-gate 400Sstevel@tonic-gate /* the following constants are used in ber_calc_lenlen */ 410Sstevel@tonic-gate 420Sstevel@tonic-gate #define LENMASK1 0xFF 430Sstevel@tonic-gate #define LENMASK2 0xFFFF 440Sstevel@tonic-gate #define LENMASK3 0xFFFFFF 450Sstevel@tonic-gate #define LENMASK4 0xFFFFFFFF 460Sstevel@tonic-gate #define _MASK 0x80 470Sstevel@tonic-gate 480Sstevel@tonic-gate static int 490Sstevel@tonic-gate ber_calc_taglen( ber_tag_t tag ) 500Sstevel@tonic-gate { 510Sstevel@tonic-gate int i; 520Sstevel@tonic-gate ber_int_t mask; 530Sstevel@tonic-gate 540Sstevel@tonic-gate /* find the first non-all-zero byte in the tag */ 550Sstevel@tonic-gate for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) { 560Sstevel@tonic-gate mask = (LENMASK3 << (i * 8)); 570Sstevel@tonic-gate /* not all zero */ 580Sstevel@tonic-gate if ( tag & mask ) 590Sstevel@tonic-gate break; 600Sstevel@tonic-gate } 610Sstevel@tonic-gate 620Sstevel@tonic-gate return( i + 1 ); 630Sstevel@tonic-gate } 640Sstevel@tonic-gate 650Sstevel@tonic-gate static int 660Sstevel@tonic-gate ber_put_tag( BerElement *ber, ber_tag_t tag, int nosos ) 670Sstevel@tonic-gate { 680Sstevel@tonic-gate int taglen; 690Sstevel@tonic-gate ber_tag_t ntag; 700Sstevel@tonic-gate 710Sstevel@tonic-gate taglen = ber_calc_taglen( tag ); 720Sstevel@tonic-gate 730Sstevel@tonic-gate ntag = LBER_HTONL( tag ); 740Sstevel@tonic-gate 750Sstevel@tonic-gate return( ber_write( ber, ((char *) &ntag) + sizeof(ber_int_t) - taglen, 760Sstevel@tonic-gate taglen, nosos ) ); 770Sstevel@tonic-gate } 780Sstevel@tonic-gate 790Sstevel@tonic-gate static int 800Sstevel@tonic-gate ber_calc_lenlen( ber_len_t len ) 810Sstevel@tonic-gate { 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * short len if it's less than 128 - one byte giving the len, 840Sstevel@tonic-gate * with bit 8 0. 850Sstevel@tonic-gate */ 860Sstevel@tonic-gate 870Sstevel@tonic-gate if ( len <= 0x7F ) 880Sstevel@tonic-gate return( 1 ); 890Sstevel@tonic-gate 900Sstevel@tonic-gate /* 910Sstevel@tonic-gate * long len otherwise - one byte with bit 8 set, giving the 920Sstevel@tonic-gate * length of the length, followed by the length itself. 930Sstevel@tonic-gate */ 940Sstevel@tonic-gate 950Sstevel@tonic-gate if ( len <= LENMASK1 ) 960Sstevel@tonic-gate return( 2 ); 970Sstevel@tonic-gate if ( len <= LENMASK2 ) 980Sstevel@tonic-gate return( 3 ); 990Sstevel@tonic-gate if ( len <= LENMASK3 ) 1000Sstevel@tonic-gate return( 4 ); 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate return( 5 ); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate static int 1060Sstevel@tonic-gate ber_put_len( BerElement *ber, ber_len_t len, int nosos ) 1070Sstevel@tonic-gate { 1080Sstevel@tonic-gate int i; 1090Sstevel@tonic-gate char lenlen; 1100Sstevel@tonic-gate ber_int_t mask; 1110Sstevel@tonic-gate ber_len_t netlen; 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * short len if it's less than 128 - one byte giving the len, 1150Sstevel@tonic-gate * with bit 8 0. 1160Sstevel@tonic-gate */ 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate if ( len <= 127 ) { 1190Sstevel@tonic-gate netlen = LBER_HTONL( len ); 1200Sstevel@tonic-gate return( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) - 1, 1210Sstevel@tonic-gate 1, nosos ) ); 1220Sstevel@tonic-gate } 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* 1250Sstevel@tonic-gate * long len otherwise - one byte with bit 8 set, giving the 1260Sstevel@tonic-gate * length of the length, followed by the length itself. 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /* find the first non-all-zero byte */ 1300Sstevel@tonic-gate for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) { 1310Sstevel@tonic-gate mask = (LENMASK1 << (i * 8)); 1320Sstevel@tonic-gate /* not all zero */ 1330Sstevel@tonic-gate if ( len & mask ) 1340Sstevel@tonic-gate break; 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate lenlen = ++i; 1370Sstevel@tonic-gate if ( lenlen > 4 ) 1380Sstevel@tonic-gate return( -1 ); 1390Sstevel@tonic-gate lenlen |= 0x80; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* write the length of the length */ 1420Sstevel@tonic-gate if ( ber_write( ber, &lenlen, 1, nosos ) != 1 ) 1430Sstevel@tonic-gate return( -1 ); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* write the length itself */ 1460Sstevel@tonic-gate netlen = LBER_HTONL( len ); 1470Sstevel@tonic-gate if ( ber_write( ber, (char *) &netlen + (sizeof(ber_int_t) - i), i, nosos ) 1480Sstevel@tonic-gate != i ) 1490Sstevel@tonic-gate return( -1 ); 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate return( i + 1 ); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate static int 1550Sstevel@tonic-gate ber_put_int_or_enum( BerElement *ber, ber_int_t num, ber_tag_t tag ) 1560Sstevel@tonic-gate { 1570Sstevel@tonic-gate int i, sign, taglen; 1580Sstevel@tonic-gate int len, lenlen; 1590Sstevel@tonic-gate ber_int_t netnum, mask; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate sign = (num < 0); 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * high bit is set - look for first non-all-one byte 1650Sstevel@tonic-gate * high bit is clear - look for first non-all-zero byte 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) { 1680Sstevel@tonic-gate mask = (LENMASK1 << (i * 8)); 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate if ( sign ) { 1710Sstevel@tonic-gate /* not all ones */ 1720Sstevel@tonic-gate if ( (num & mask) != mask ) 1730Sstevel@tonic-gate break; 1740Sstevel@tonic-gate } else { 1750Sstevel@tonic-gate /* not all zero */ 1760Sstevel@tonic-gate if ( num & mask ) 1770Sstevel@tonic-gate break; 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * we now have the "leading byte". if the high bit on this 1830Sstevel@tonic-gate * byte matches the sign bit, we need to "back up" a byte. 1840Sstevel@tonic-gate */ 1850Sstevel@tonic-gate mask = (num & (_MASK << (i * 8))); 1860Sstevel@tonic-gate if ( (mask && !sign) || (sign && !mask) ) 1870Sstevel@tonic-gate i++; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate len = i + 1; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 1920Sstevel@tonic-gate return( -1 ); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ) 1950Sstevel@tonic-gate return( -1 ); 1960Sstevel@tonic-gate i++; 1970Sstevel@tonic-gate netnum = LBER_HTONL( num ); 1980Sstevel@tonic-gate if ( ber_write( ber, (char *) &netnum + (sizeof(ber_int_t) - i), i, 0 ) 1990Sstevel@tonic-gate == i) 2000Sstevel@tonic-gate /* length of tag + length + contents */ 2010Sstevel@tonic-gate return( taglen + lenlen + i ); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate return( -1 ); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate int 2070Sstevel@tonic-gate LDAP_CALL 2080Sstevel@tonic-gate ber_put_enum( BerElement *ber, ber_int_t num, ber_tag_t tag ) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) 2110Sstevel@tonic-gate tag = LBER_ENUMERATED; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate return( ber_put_int_or_enum( ber, num, tag ) ); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate int 2170Sstevel@tonic-gate LDAP_CALL 2180Sstevel@tonic-gate ber_put_int( BerElement *ber, ber_int_t num, ber_tag_t tag ) 2190Sstevel@tonic-gate { 2200Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) 2210Sstevel@tonic-gate tag = LBER_INTEGER; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate return( ber_put_int_or_enum( ber, num, tag ) ); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate int 2270Sstevel@tonic-gate LDAP_CALL 2280Sstevel@tonic-gate ber_put_ostring( BerElement *ber, char *str, ber_len_t len, 2290Sstevel@tonic-gate ber_tag_t tag ) 2300Sstevel@tonic-gate { 2310Sstevel@tonic-gate int taglen, lenlen, rc; 2320Sstevel@tonic-gate #ifdef STR_TRANSLATION 2330Sstevel@tonic-gate int free_str; 2340Sstevel@tonic-gate #endif /* STR_TRANSLATION */ 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) 2370Sstevel@tonic-gate tag = LBER_OCTETSTRING; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 2400Sstevel@tonic-gate return( -1 ); 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate #ifdef STR_TRANSLATION 2430Sstevel@tonic-gate if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0 2440Sstevel@tonic-gate && ber->ber_encode_translate_proc != NULL ) { 2450Sstevel@tonic-gate if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 ) 2460Sstevel@tonic-gate != 0 ) { 2470Sstevel@tonic-gate return( -1 ); 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate free_str = 1; 2500Sstevel@tonic-gate } else { 2510Sstevel@tonic-gate free_str = 0; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate #endif /* STR_TRANSLATION */ 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate /* 2560Sstevel@tonic-gate * Note: below is a spot where we limit ber_write 2570Sstevel@tonic-gate * to signed long (instead of unsigned long) 2580Sstevel@tonic-gate */ 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 || 2610Sstevel@tonic-gate ber_write( ber, str, len, 0 ) != (ber_int_t) len ) { 2620Sstevel@tonic-gate rc = -1; 2630Sstevel@tonic-gate } else { 2640Sstevel@tonic-gate /* return length of tag + length + contents */ 2650Sstevel@tonic-gate rc = taglen + lenlen + len; 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate #ifdef STR_TRANSLATION 2690Sstevel@tonic-gate if ( free_str ) { 2700Sstevel@tonic-gate NSLBERI_FREE( str ); 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate #endif /* STR_TRANSLATION */ 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate return( rc ); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate int 2780Sstevel@tonic-gate LDAP_CALL 2790Sstevel@tonic-gate ber_put_string( BerElement *ber, char *str, ber_tag_t tag ) 2800Sstevel@tonic-gate { 2810Sstevel@tonic-gate return( ber_put_ostring( ber, str, (ber_len_t) strlen( str ), tag )); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate int 2850Sstevel@tonic-gate LDAP_CALL 2860Sstevel@tonic-gate ber_put_bitstring( BerElement *ber, char *str, 2870Sstevel@tonic-gate ber_len_t blen /* in bits */, ber_tag_t tag ) 2880Sstevel@tonic-gate { 2890Sstevel@tonic-gate int taglen, lenlen, len; 2900Sstevel@tonic-gate unsigned char unusedbits; 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) 2930Sstevel@tonic-gate tag = LBER_BITSTRING; 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 2960Sstevel@tonic-gate return( -1 ); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate len = ( blen + 7 ) / 8; 2990Sstevel@tonic-gate unusedbits = (unsigned char) (len * 8 - blen); 3000Sstevel@tonic-gate if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) 3010Sstevel@tonic-gate return( -1 ); 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) 3040Sstevel@tonic-gate return( -1 ); 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate if ( ber_write( ber, str, len, 0 ) != len ) 3070Sstevel@tonic-gate return( -1 ); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate /* return length of tag + length + unused bit count + contents */ 3100Sstevel@tonic-gate return( taglen + 1 + lenlen + len ); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate int 3140Sstevel@tonic-gate LDAP_CALL 3150Sstevel@tonic-gate ber_put_null( BerElement *ber, ber_tag_t tag ) 3160Sstevel@tonic-gate { 3170Sstevel@tonic-gate int taglen; 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) 3200Sstevel@tonic-gate tag = LBER_NULL; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 3230Sstevel@tonic-gate return( -1 ); 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate if ( ber_put_len( ber, 0, 0 ) != 1 ) 3260Sstevel@tonic-gate return( -1 ); 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate return( taglen + 1 ); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate int 3320Sstevel@tonic-gate LDAP_CALL 3330Sstevel@tonic-gate ber_put_boolean( BerElement *ber, int boolval, ber_tag_t tag ) 3340Sstevel@tonic-gate { 3350Sstevel@tonic-gate int taglen; 3360Sstevel@tonic-gate unsigned char trueval = 0xff; 3370Sstevel@tonic-gate unsigned char falseval = 0x00; 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) 3400Sstevel@tonic-gate tag = LBER_BOOLEAN; 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) 3430Sstevel@tonic-gate return( -1 ); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate if ( ber_put_len( ber, 1, 0 ) != 1 ) 3460Sstevel@tonic-gate return( -1 ); 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 ) 3490Sstevel@tonic-gate != 1 ) 3500Sstevel@tonic-gate return( -1 ); 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate return( taglen + 2 ); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate #define FOUR_BYTE_LEN 5 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* the idea here is roughly this: we maintain a stack of these Seqorset 3590Sstevel@tonic-gate * structures. This is pushed when we see the beginning of a new set or 3600Sstevel@tonic-gate * sequence. It is popped when we see the end of a set or sequence. 3610Sstevel@tonic-gate * Since we don't want to malloc and free these structures all the time, 3620Sstevel@tonic-gate * we pre-allocate a small set of them within the ber element structure. 3630Sstevel@tonic-gate * thus we need to spot when we've overflowed this stack and fall back to 3640Sstevel@tonic-gate * malloc'ing instead. 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate static int 3670Sstevel@tonic-gate ber_start_seqorset( BerElement *ber, ber_tag_t tag ) 3680Sstevel@tonic-gate { 3690Sstevel@tonic-gate Seqorset *new_sos; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate /* can we fit into the local stack ? */ 3720Sstevel@tonic-gate if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) { 3730Sstevel@tonic-gate /* yes */ 3740Sstevel@tonic-gate new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn]; 3750Sstevel@tonic-gate } else { 3760Sstevel@tonic-gate /* no */ 3770Sstevel@tonic-gate if ( (new_sos = (Seqorset *)NSLBERI_MALLOC( sizeof(Seqorset))) 3780Sstevel@tonic-gate == NULLSEQORSET ) { 3790Sstevel@tonic-gate return( -1 ); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate ber->ber_sos_stack_posn++; 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate if ( ber->ber_sos == NULLSEQORSET ) 3850Sstevel@tonic-gate new_sos->sos_first = ber->ber_ptr; 3860Sstevel@tonic-gate else 3870Sstevel@tonic-gate new_sos->sos_first = ber->ber_sos->sos_ptr; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate /* Set aside room for a 4 byte length field */ 3900Sstevel@tonic-gate new_sos->sos_ptr = new_sos->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN; 3910Sstevel@tonic-gate new_sos->sos_tag = tag; 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate new_sos->sos_next = ber->ber_sos; 3940Sstevel@tonic-gate new_sos->sos_clen = 0; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate ber->ber_sos = new_sos; 3970Sstevel@tonic-gate if (ber->ber_sos->sos_ptr > ber->ber_end) { 3980Sstevel@tonic-gate nslberi_ber_realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end); 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate return( 0 ); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate int 4040Sstevel@tonic-gate LDAP_CALL 4050Sstevel@tonic-gate ber_start_seq( BerElement *ber, ber_tag_t tag ) 4060Sstevel@tonic-gate { 4070Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) 4080Sstevel@tonic-gate tag = LBER_SEQUENCE; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate return( ber_start_seqorset( ber, tag ) ); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate int 4140Sstevel@tonic-gate LDAP_CALL 4150Sstevel@tonic-gate ber_start_set( BerElement *ber, ber_tag_t tag ) 4160Sstevel@tonic-gate { 4170Sstevel@tonic-gate if ( tag == LBER_DEFAULT ) 4180Sstevel@tonic-gate tag = LBER_SET; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate return( ber_start_seqorset( ber, tag ) ); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate static int 4240Sstevel@tonic-gate ber_put_seqorset( BerElement *ber ) 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate ber_len_t len, netlen; 4270Sstevel@tonic-gate int taglen, lenlen; 4280Sstevel@tonic-gate unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; 4290Sstevel@tonic-gate Seqorset *next; 4300Sstevel@tonic-gate Seqorset **sos = &ber->ber_sos; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * If this is the toplevel sequence or set, we need to actually 4340Sstevel@tonic-gate * write the stuff out. Otherwise, it's already been put in 4350Sstevel@tonic-gate * the appropriate buffer and will be written when the toplevel 4360Sstevel@tonic-gate * one is written. In this case all we need to do is update the 4370Sstevel@tonic-gate * length and tag. 4380Sstevel@tonic-gate */ 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate len = (*sos)->sos_clen; 4410Sstevel@tonic-gate netlen = LBER_HTONL( len ); 4420Sstevel@tonic-gate if ( sizeof(ber_int_t) > 4 && len > LENMASK4 ) 4430Sstevel@tonic-gate return( -1 ); 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate if ( ber->ber_options & LBER_OPT_USE_DER ) { 4460Sstevel@tonic-gate lenlen = ber_calc_lenlen( len ); 4470Sstevel@tonic-gate } else { 4480Sstevel@tonic-gate lenlen = FOUR_BYTE_LEN; 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate if ( (next = (*sos)->sos_next) == NULLSEQORSET ) { 4520Sstevel@tonic-gate /* write the tag */ 4530Sstevel@tonic-gate if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 ) 4540Sstevel@tonic-gate return( -1 ); 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate if ( ber->ber_options & LBER_OPT_USE_DER ) { 4570Sstevel@tonic-gate /* Write the length in the minimum # of octets */ 4580Sstevel@tonic-gate if ( ber_put_len( ber, len, 1 ) == -1 ) 4590Sstevel@tonic-gate return( -1 ); 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate if (lenlen != FOUR_BYTE_LEN) { 4620Sstevel@tonic-gate /* 4630Sstevel@tonic-gate * We set aside FOUR_BYTE_LEN bytes for 4640Sstevel@tonic-gate * the length field. Move the data if 4650Sstevel@tonic-gate * we don't actually need that much 4660Sstevel@tonic-gate */ 4670Sstevel@tonic-gate SAFEMEMCPY( (*sos)->sos_first + taglen + 4680Sstevel@tonic-gate lenlen, (*sos)->sos_first + taglen + 4690Sstevel@tonic-gate FOUR_BYTE_LEN, len ); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate } else { 4720Sstevel@tonic-gate /* Fill FOUR_BYTE_LEN bytes for length field */ 4730Sstevel@tonic-gate /* one byte of length length */ 4740Sstevel@tonic-gate if ( ber_write( ber, (char *)<ag, 1, 1 ) != 1 ) 4750Sstevel@tonic-gate return( -1 ); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate /* the length itself */ 4780Sstevel@tonic-gate if ( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) 4790Sstevel@tonic-gate - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 ) 4800Sstevel@tonic-gate != FOUR_BYTE_LEN - 1 ) 4810Sstevel@tonic-gate return( -1 ); 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate /* The ber_ptr is at the set/seq start - move it to the end */ 4840Sstevel@tonic-gate ber->ber_ptr += len; 4850Sstevel@tonic-gate } else { 4860Sstevel@tonic-gate ber_tag_t ntag; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /* the tag */ 4890Sstevel@tonic-gate taglen = ber_calc_taglen( (*sos)->sos_tag ); 4900Sstevel@tonic-gate ntag = LBER_HTONL( (*sos)->sos_tag ); 4910Sstevel@tonic-gate SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag + 4920Sstevel@tonic-gate sizeof(ber_int_t) - taglen, taglen ); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate if ( ber->ber_options & LBER_OPT_USE_DER ) { 4950Sstevel@tonic-gate ltag = (lenlen == 1) ? (unsigned char)len : 4960Sstevel@tonic-gate (unsigned char) (0x80 + (lenlen - 1)); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* one byte of length length */ 5000Sstevel@tonic-gate SAFEMEMCPY( (*sos)->sos_first + 1, <ag, 1 ); 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate if ( ber->ber_options & LBER_OPT_USE_DER ) { 5030Sstevel@tonic-gate if (lenlen > 1) { 5040Sstevel@tonic-gate /* Write the length itself */ 5050Sstevel@tonic-gate SAFEMEMCPY( (*sos)->sos_first + 2, 5060Sstevel@tonic-gate (char *)&netlen + sizeof(ber_uint_t) - 5070Sstevel@tonic-gate (lenlen - 1), 5080Sstevel@tonic-gate lenlen - 1 ); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate if (lenlen != FOUR_BYTE_LEN) { 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * We set aside FOUR_BYTE_LEN bytes for 5130Sstevel@tonic-gate * the length field. Move the data if 5140Sstevel@tonic-gate * we don't actually need that much 5150Sstevel@tonic-gate */ 5160Sstevel@tonic-gate SAFEMEMCPY( (*sos)->sos_first + taglen + 5170Sstevel@tonic-gate lenlen, (*sos)->sos_first + taglen + 5180Sstevel@tonic-gate FOUR_BYTE_LEN, len ); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate } else { 5210Sstevel@tonic-gate /* the length itself */ 5220Sstevel@tonic-gate SAFEMEMCPY( (*sos)->sos_first + taglen + 1, 5230Sstevel@tonic-gate (char *) &netlen + sizeof(ber_int_t) - 5240Sstevel@tonic-gate (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 ); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate next->sos_clen += (taglen + lenlen + len); 5280Sstevel@tonic-gate next->sos_ptr += (taglen + lenlen + len); 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate /* we're done with this seqorset, so free it up */ 5320Sstevel@tonic-gate /* was this one from the local stack ? */ 5330Sstevel@tonic-gate if (ber->ber_sos_stack_posn <= SOS_STACK_SIZE) { 5340Sstevel@tonic-gate /* yes */ 5350Sstevel@tonic-gate } else { 5360Sstevel@tonic-gate /* no */ 5370Sstevel@tonic-gate NSLBERI_FREE( (char *) (*sos) ); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate ber->ber_sos_stack_posn--; 5400Sstevel@tonic-gate *sos = next; 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate return( taglen + lenlen + len ); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate int 5460Sstevel@tonic-gate LDAP_CALL 5470Sstevel@tonic-gate ber_put_seq( BerElement *ber ) 5480Sstevel@tonic-gate { 5490Sstevel@tonic-gate return( ber_put_seqorset( ber ) ); 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate int 5530Sstevel@tonic-gate LDAP_CALL 5540Sstevel@tonic-gate ber_put_set( BerElement *ber ) 5550Sstevel@tonic-gate { 5560Sstevel@tonic-gate return( ber_put_seqorset( ber ) ); 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate /* VARARGS */ 5600Sstevel@tonic-gate int 5610Sstevel@tonic-gate LDAP_C 5620Sstevel@tonic-gate ber_printf( BerElement *ber, const char *fmt, ... ) 5630Sstevel@tonic-gate { 5640Sstevel@tonic-gate va_list ap; 5650Sstevel@tonic-gate char *s, **ss; 566*7866SSerge.Dussud@Sun.COM struct berval *bval, **bv; 5670Sstevel@tonic-gate int rc, i; 5680Sstevel@tonic-gate ber_len_t len; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate va_start( ap, fmt ); 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate #ifdef LDAP_DEBUG 5730Sstevel@tonic-gate if ( lber_debug & 64 ) { 5740Sstevel@tonic-gate char msg[80]; 5750Sstevel@tonic-gate sprintf( msg, "ber_printf fmt (%s)\n", fmt ); 5760Sstevel@tonic-gate ber_err_print( msg ); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate #endif 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate for ( rc = 0; *fmt && rc != -1; fmt++ ) { 5810Sstevel@tonic-gate switch ( *fmt ) { 5820Sstevel@tonic-gate case 'b': /* boolean */ 5830Sstevel@tonic-gate i = va_arg( ap, int ); 5840Sstevel@tonic-gate rc = ber_put_boolean( ber, i, ber->ber_tag ); 5850Sstevel@tonic-gate break; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate case 'i': /* int */ 5880Sstevel@tonic-gate i = va_arg( ap, int ); 5890Sstevel@tonic-gate rc = ber_put_int( ber, (ber_int_t)i, ber->ber_tag ); 5900Sstevel@tonic-gate break; 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate case 'e': /* enumeration */ 5930Sstevel@tonic-gate i = va_arg( ap, int ); 5940Sstevel@tonic-gate rc = ber_put_enum( ber, (ber_int_t)i, ber->ber_tag ); 5950Sstevel@tonic-gate break; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate case 'n': /* null */ 5980Sstevel@tonic-gate rc = ber_put_null( ber, ber->ber_tag ); 5990Sstevel@tonic-gate break; 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate case 'o': /* octet string (non-null terminated) */ 6020Sstevel@tonic-gate s = va_arg( ap, char * ); 6030Sstevel@tonic-gate len = va_arg( ap, int ); 6040Sstevel@tonic-gate rc = ber_put_ostring( ber, s, len, ber->ber_tag ); 6050Sstevel@tonic-gate break; 6060Sstevel@tonic-gate 607*7866SSerge.Dussud@Sun.COM case 'O': /* berval octet string */ 608*7866SSerge.Dussud@Sun.COM if( ( bval = va_arg( ap, struct berval * ) ) == NULL ) 609*7866SSerge.Dussud@Sun.COM break; 610*7866SSerge.Dussud@Sun.COM if( bval->bv_len == 0 ) { 611*7866SSerge.Dussud@Sun.COM rc = ber_put_ostring( ber, "", 0, ber->ber_tag ); 612*7866SSerge.Dussud@Sun.COM } else { 613*7866SSerge.Dussud@Sun.COM rc = ber_put_ostring( ber, bval->bv_val, bval->bv_len, 614*7866SSerge.Dussud@Sun.COM ber->ber_tag ); 615*7866SSerge.Dussud@Sun.COM } 616*7866SSerge.Dussud@Sun.COM break; 617*7866SSerge.Dussud@Sun.COM 6180Sstevel@tonic-gate case 's': /* string */ 6190Sstevel@tonic-gate s = va_arg( ap, char * ); 6200Sstevel@tonic-gate rc = ber_put_string( ber, s, ber->ber_tag ); 6210Sstevel@tonic-gate break; 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate case 'B': /* bit string */ 6240Sstevel@tonic-gate s = va_arg( ap, char * ); 6250Sstevel@tonic-gate len = va_arg( ap, int ); /* in bits */ 6260Sstevel@tonic-gate rc = ber_put_bitstring( ber, s, len, ber->ber_tag ); 6270Sstevel@tonic-gate break; 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate case 't': /* tag for the next element */ 6300Sstevel@tonic-gate ber->ber_tag = va_arg( ap, ber_tag_t ); 6310Sstevel@tonic-gate ber->ber_usertag = 1; 6320Sstevel@tonic-gate break; 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate case 'v': /* vector of strings */ 6350Sstevel@tonic-gate if ( (ss = va_arg( ap, char ** )) == NULL ) 6360Sstevel@tonic-gate break; 6370Sstevel@tonic-gate for ( i = 0; ss[i] != NULL; i++ ) { 6380Sstevel@tonic-gate if ( (rc = ber_put_string( ber, ss[i], 6390Sstevel@tonic-gate ber->ber_tag )) == -1 ) 6400Sstevel@tonic-gate break; 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate break; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate case 'V': /* sequences of strings + lengths */ 6450Sstevel@tonic-gate if ( (bv = va_arg( ap, struct berval ** )) == NULL ) 6460Sstevel@tonic-gate break; 6470Sstevel@tonic-gate for ( i = 0; bv[i] != NULL; i++ ) { 6480Sstevel@tonic-gate if ( (rc = ber_put_ostring( ber, bv[i]->bv_val, 6490Sstevel@tonic-gate bv[i]->bv_len, ber->ber_tag )) == -1 ) 6500Sstevel@tonic-gate break; 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate break; 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate case '{': /* begin sequence */ 6550Sstevel@tonic-gate rc = ber_start_seq( ber, ber->ber_tag ); 6560Sstevel@tonic-gate break; 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate case '}': /* end sequence */ 6590Sstevel@tonic-gate rc = ber_put_seqorset( ber ); 6600Sstevel@tonic-gate break; 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate case '[': /* begin set */ 6630Sstevel@tonic-gate rc = ber_start_set( ber, ber->ber_tag ); 6640Sstevel@tonic-gate break; 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate case ']': /* end set */ 6670Sstevel@tonic-gate rc = ber_put_seqorset( ber ); 6680Sstevel@tonic-gate break; 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate default: { 6710Sstevel@tonic-gate char msg[80]; 6720Sstevel@tonic-gate sprintf( msg, "unknown fmt %c\n", *fmt ); 6730Sstevel@tonic-gate ber_err_print( msg ); 6740Sstevel@tonic-gate rc = -1; 6750Sstevel@tonic-gate break; 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if ( ber->ber_usertag == 0 ) 6800Sstevel@tonic-gate ber->ber_tag = LBER_DEFAULT; 6810Sstevel@tonic-gate else 6820Sstevel@tonic-gate ber->ber_usertag = 0; 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate va_end( ap ); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate return( rc ); 6880Sstevel@tonic-gate } 689