xref: /onnv-gate/usr/src/lib/libldap5/sources/ldap/ber/io.c (revision 12023:a90e8ee77a4b)
10Sstevel@tonic-gate /*
2*12023SDoug.Leavitt@Sun.COM  * CDDL HEADER START
3*12023SDoug.Leavitt@Sun.COM  *
4*12023SDoug.Leavitt@Sun.COM  * The contents of this file are subject to the terms of the
5*12023SDoug.Leavitt@Sun.COM  * Common Development and Distribution License (the "License").
6*12023SDoug.Leavitt@Sun.COM  * You may not use this file except in compliance with the License.
7*12023SDoug.Leavitt@Sun.COM  *
8*12023SDoug.Leavitt@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12023SDoug.Leavitt@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*12023SDoug.Leavitt@Sun.COM  * See the License for the specific language governing permissions
11*12023SDoug.Leavitt@Sun.COM  * and limitations under the License.
12*12023SDoug.Leavitt@Sun.COM  *
13*12023SDoug.Leavitt@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*12023SDoug.Leavitt@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12023SDoug.Leavitt@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*12023SDoug.Leavitt@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*12023SDoug.Leavitt@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12023SDoug.Leavitt@Sun.COM  *
19*12023SDoug.Leavitt@Sun.COM  * CDDL HEADER END
20*12023SDoug.Leavitt@Sun.COM  */
21*12023SDoug.Leavitt@Sun.COM 
22*12023SDoug.Leavitt@Sun.COM /*
23*12023SDoug.Leavitt@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public License
310Sstevel@tonic-gate  * Version 1.0 (the "NPL"); you may not use this file except in
320Sstevel@tonic-gate  * compliance with the NPL.  You may obtain a copy of the NPL at
330Sstevel@tonic-gate  * http://www.mozilla.org/NPL/
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * Software distributed under the NPL is distributed on an "AS IS" basis,
360Sstevel@tonic-gate  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
370Sstevel@tonic-gate  * for the specific language governing rights and limitations under the
380Sstevel@tonic-gate  * NPL.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * The Initial Developer of this code under the NPL is Netscape
410Sstevel@tonic-gate  * Communications Corporation.  Portions created by Netscape are
420Sstevel@tonic-gate  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
430Sstevel@tonic-gate  * Reserved.
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * Copyright (c) 1990 Regents of the University of Michigan.
480Sstevel@tonic-gate  * All rights reserved.
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
510Sstevel@tonic-gate  * provided that this notice is preserved and that due credit is given
520Sstevel@tonic-gate  * to the University of Michigan at Ann Arbor. The name of the University
530Sstevel@tonic-gate  * may not be used to endorse or promote products derived from this
540Sstevel@tonic-gate  * software without specific prior written permission. This software
550Sstevel@tonic-gate  * is provided ``as is'' without express or implied warranty.
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate /* io.c - ber general i/o routines */
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #include "lber-int.h"
600Sstevel@tonic-gate 
610Sstevel@tonic-gate #define bergetc( sb, len )    ( sb->sb_ber.ber_end > sb->sb_ber.ber_ptr ? \
620Sstevel@tonic-gate 			  (unsigned char)*sb->sb_ber.ber_ptr++ : \
630Sstevel@tonic-gate 			  ber_filbuf( sb, len ))
640Sstevel@tonic-gate 
650Sstevel@tonic-gate # ifdef macintosh
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate  * MacTCP/OpenTransport
680Sstevel@tonic-gate  */
690Sstevel@tonic-gate #  define read( s, b, l ) tcpread( s, 0, (unsigned char *)b, l, NULL )
700Sstevel@tonic-gate #  define MAX_WRITE	65535
710Sstevel@tonic-gate #  define BerWrite( sb, b, l )   tcpwrite( sb->sb_sd, (unsigned char *)(b), (l<MAX_WRITE)? l : MAX_WRITE )
720Sstevel@tonic-gate # else /* macintosh */
730Sstevel@tonic-gate #  if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2)
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate  * 32-bit Windows Socket API (under Windows NT or Windows 95)
760Sstevel@tonic-gate  */
770Sstevel@tonic-gate #   define read( s, b, l )		recv( s, b, l, 0 )
780Sstevel@tonic-gate #   define BerWrite( s, b, l )	send( s->sb_sd, b, l, 0 )
790Sstevel@tonic-gate #  else /* _WIN32 */
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * everything else (Unix/BSD 4.3 socket API)
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate #   define BerWrite( sb, b, l )	write( sb->sb_sd, b, l )
840Sstevel@tonic-gate #   define udp_read( sb, b, l, al ) recvfrom(sb->sb_sd, (char *)b, l, 0, \
850Sstevel@tonic-gate 		(struct sockaddr *)sb->sb_fromaddr, \
860Sstevel@tonic-gate 		(al = sizeof(struct sockaddr), &al))
870Sstevel@tonic-gate #   define udp_write( sb, b, l ) sendto(sb->sb_sd, (char *)(b), l, 0, \
880Sstevel@tonic-gate 		(struct sockaddr *)sb->sb_useaddr, sizeof(struct sockaddr))
890Sstevel@tonic-gate #  endif /* _WIN32 */
900Sstevel@tonic-gate # endif /* macintosh */
910Sstevel@tonic-gate 
920Sstevel@tonic-gate #ifndef udp_read
930Sstevel@tonic-gate #define udp_read( sb, b, l, al )	CLDAP NOT SUPPORTED
940Sstevel@tonic-gate #define udp_write( sb, b, l )		CLDAP NOT SUPPORTED
950Sstevel@tonic-gate #endif /* udp_read */
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define EXBUFSIZ	1024
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #ifdef LDAP_DEBUG
1000Sstevel@tonic-gate int	lber_debug;
1010Sstevel@tonic-gate #endif
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate  * function prototypes
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate static void nslberi_install_compat_io_fns( Sockbuf *sb );
1070Sstevel@tonic-gate static int nslberi_extread_compat( int s, void *buf, int len,
1080Sstevel@tonic-gate 		struct lextiof_socket_private *arg );
1090Sstevel@tonic-gate static int nslberi_extwrite_compat( int s, const void *buf, int len,
1100Sstevel@tonic-gate 		struct lextiof_socket_private *arg );
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * internal global structure for memory allocation callback functions
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate static struct lber_memalloc_fns nslberi_memalloc_fns;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * buffered read from "sb".
1210Sstevel@tonic-gate  * returns value of first character read on success and -1 on error.
1220Sstevel@tonic-gate  */
1230Sstevel@tonic-gate static int
ber_filbuf(Sockbuf * sb,ber_slen_t len)1240Sstevel@tonic-gate ber_filbuf( Sockbuf *sb, ber_slen_t len )
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate 	ssize_t	rc;
1270Sstevel@tonic-gate #ifdef CLDAP
1280Sstevel@tonic-gate 	int	addrlen;
1290Sstevel@tonic-gate #endif /* CLDAP */
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	if ( sb->sb_ber.ber_buf == NULL ) {
1320Sstevel@tonic-gate 		if ( (sb->sb_ber.ber_buf = (char *)NSLBERI_MALLOC(
1330Sstevel@tonic-gate 		    READBUFSIZ )) == NULL ) {
1340Sstevel@tonic-gate 			return( -1 );
1350Sstevel@tonic-gate 		}
1360Sstevel@tonic-gate 		sb->sb_ber.ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
1370Sstevel@tonic-gate 		sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf;
1380Sstevel@tonic-gate 		sb->sb_ber.ber_end = sb->sb_ber.ber_buf;
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	if ( sb->sb_naddr > 0 ) {
1420Sstevel@tonic-gate #ifdef CLDAP
1430Sstevel@tonic-gate 		rc = udp_read(sb, sb->sb_ber.ber_buf, READBUFSIZ, addrlen );
1440Sstevel@tonic-gate #ifdef LDAP_DEBUG
1450Sstevel@tonic-gate 		if ( lber_debug ) {
1460Sstevel@tonic-gate 			char msg[80];
1470Sstevel@tonic-gate 			sprintf( msg, "ber_filbuf udp_read %d bytes\n",
1480Sstevel@tonic-gate 				rc );
1490Sstevel@tonic-gate 			ber_err_print( msg );
1500Sstevel@tonic-gate 			if ( lber_debug > 1 && rc > 0 )
1510Sstevel@tonic-gate 				lber_bprint( sb->sb_ber.ber_buf, rc );
1520Sstevel@tonic-gate 		}
1530Sstevel@tonic-gate #endif /* LDAP_DEBUG */
1540Sstevel@tonic-gate #else /* CLDAP */
1550Sstevel@tonic-gate 		rc = -1;
1560Sstevel@tonic-gate #endif /* CLDAP */
1570Sstevel@tonic-gate 	} else {
1580Sstevel@tonic-gate 		if ( sb->sb_ext_io_fns.lbextiofn_read != NULL ) {
1590Sstevel@tonic-gate 			rc = sb->sb_ext_io_fns.lbextiofn_read(
1600Sstevel@tonic-gate 			    sb->sb_sd, sb->sb_ber.ber_buf,
1610Sstevel@tonic-gate 			    ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
1620Sstevel@tonic-gate 			    && (len < READBUFSIZ)) ? len : READBUFSIZ,
1630Sstevel@tonic-gate 			    sb->sb_ext_io_fns.lbextiofn_socket_arg );
1640Sstevel@tonic-gate 		} else {
1650Sstevel@tonic-gate 			rc = read( sb->sb_sd, sb->sb_ber.ber_buf,
1660Sstevel@tonic-gate 			    ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
1670Sstevel@tonic-gate 			    && (len < READBUFSIZ)) ? len : READBUFSIZ );
1680Sstevel@tonic-gate 		}
1690Sstevel@tonic-gate 	}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	if ( rc > 0 ) {
1720Sstevel@tonic-gate 		sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf + 1;
1730Sstevel@tonic-gate 		sb->sb_ber.ber_end = sb->sb_ber.ber_buf + rc;
1740Sstevel@tonic-gate 		return( (unsigned char)*sb->sb_ber.ber_buf );
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	return( -1 );
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate static ber_int_t
BerRead(Sockbuf * sb,char * buf,ber_slen_t len)1820Sstevel@tonic-gate BerRead( Sockbuf *sb, char *buf, ber_slen_t len )
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	int		c;
1850Sstevel@tonic-gate 	ber_int_t	nread = 0;
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	while ( len > 0 ) {
1880Sstevel@tonic-gate 		if ( (c = bergetc( sb, len )) < 0 ) {
1890Sstevel@tonic-gate 			if ( nread > 0 )
1900Sstevel@tonic-gate 				break;
1910Sstevel@tonic-gate 			return( c );
1920Sstevel@tonic-gate 		}
1930Sstevel@tonic-gate 		*buf++ = c;
1940Sstevel@tonic-gate 		nread++;
1950Sstevel@tonic-gate 		len--;
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	return( nread );
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * Note: ber_read() only uses the ber_end and ber_ptr elements of ber.
2040Sstevel@tonic-gate  * Functions like ber_get_tag(), ber_skip_tag, and ber_peek_tag() rely on
2050Sstevel@tonic-gate  * that fact, so if this code is changed to use any additional elements of
2060Sstevel@tonic-gate  * the ber structure, those functions will need to be changed as well.
2070Sstevel@tonic-gate  */
2080Sstevel@tonic-gate ber_int_t
2090Sstevel@tonic-gate LDAP_CALL
ber_read(BerElement * ber,char * buf,ber_len_t len)2100Sstevel@tonic-gate ber_read( BerElement *ber, char *buf, ber_len_t len )
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	ber_len_t	actuallen;
2130Sstevel@tonic-gate 	ber_uint_t	nleft;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	nleft = ber->ber_end - ber->ber_ptr;
2160Sstevel@tonic-gate 	actuallen = nleft < len ? nleft : len;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen );
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	ber->ber_ptr += actuallen;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	return( (ber_int_t)actuallen );
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate /*
2260Sstevel@tonic-gate  * enlarge the ber buffer.
2270Sstevel@tonic-gate  * return 0 on success, -1 on error.
2280Sstevel@tonic-gate  */
2290Sstevel@tonic-gate int
nslberi_ber_realloc(BerElement * ber,ber_len_t len)2300Sstevel@tonic-gate nslberi_ber_realloc( BerElement *ber, ber_len_t len )
2310Sstevel@tonic-gate {
2320Sstevel@tonic-gate 	ber_uint_t	need, have, total;
2330Sstevel@tonic-gate 	size_t		have_bytes;
2340Sstevel@tonic-gate 	Seqorset	*s;
2350Sstevel@tonic-gate 	ber_int_t	off;
2360Sstevel@tonic-gate 	char		*oldbuf;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	have_bytes = ber->ber_end - ber->ber_buf;
2390Sstevel@tonic-gate 	have = have_bytes / EXBUFSIZ;
2400Sstevel@tonic-gate 	need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
2410Sstevel@tonic-gate 	total = have * EXBUFSIZ + need * EXBUFSIZ;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	oldbuf = ber->ber_buf;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if (ber->ber_buf == NULL) {
2460Sstevel@tonic-gate 		if ( (ber->ber_buf = (char *)NSLBERI_MALLOC( (size_t)total ))
2470Sstevel@tonic-gate 		    == NULL ) {
2480Sstevel@tonic-gate 			return( -1 );
2490Sstevel@tonic-gate 		}
2500Sstevel@tonic-gate 		ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
2510Sstevel@tonic-gate 	} else {
2520Sstevel@tonic-gate 		if ( ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER ) {
2530Sstevel@tonic-gate 			/* transition to malloc'd buffer */
2540Sstevel@tonic-gate 			if ( (ber->ber_buf = (char *)NSLBERI_MALLOC(
2550Sstevel@tonic-gate 			    (size_t)total )) == NULL ) {
2560Sstevel@tonic-gate 				return( -1 );
2570Sstevel@tonic-gate 			}
2580Sstevel@tonic-gate 			ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
2590Sstevel@tonic-gate 			/* copy existing data into new malloc'd buffer */
2600Sstevel@tonic-gate 			SAFEMEMCPY( ber->ber_buf, oldbuf, have_bytes );
2610Sstevel@tonic-gate 		} else {
2620Sstevel@tonic-gate 			if ( (ber->ber_buf = (char *)NSLBERI_REALLOC(
2630Sstevel@tonic-gate 			    ber->ber_buf,(size_t)total )) == NULL ) {
2640Sstevel@tonic-gate 				return( -1 );
2650Sstevel@tonic-gate 			}
2660Sstevel@tonic-gate 		}
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	ber->ber_end = ber->ber_buf + total;
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/*
2720Sstevel@tonic-gate 	 * If the stinking thing was moved, we need to go through and
2730Sstevel@tonic-gate 	 * reset all the sos and ber pointers.  Offsets would've been
2740Sstevel@tonic-gate 	 * a better idea... oh well.
2750Sstevel@tonic-gate 	 */
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	if ( ber->ber_buf != oldbuf ) {
2780Sstevel@tonic-gate 		ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) {
2810Sstevel@tonic-gate 			off = s->sos_first - oldbuf;
2820Sstevel@tonic-gate 			s->sos_first = ber->ber_buf + off;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 			off = s->sos_ptr - oldbuf;
2850Sstevel@tonic-gate 			s->sos_ptr = ber->ber_buf + off;
2860Sstevel@tonic-gate 		}
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	return( 0 );
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate  * returns "len" on success and -1 on failure.
2940Sstevel@tonic-gate  */
2950Sstevel@tonic-gate ber_int_t
2960Sstevel@tonic-gate LDAP_CALL
ber_write(BerElement * ber,char * buf,ber_len_t len,int nosos)2970Sstevel@tonic-gate ber_write( BerElement *ber, char *buf, ber_len_t len, int nosos )
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate 	if ( nosos || ber->ber_sos == NULL ) {
3000Sstevel@tonic-gate 		if ( ber->ber_ptr + len > ber->ber_end ) {
3010Sstevel@tonic-gate 			if ( nslberi_ber_realloc( ber, len ) != 0 )
3020Sstevel@tonic-gate 				return( -1 );
3030Sstevel@tonic-gate 		}
3040Sstevel@tonic-gate 		SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
3050Sstevel@tonic-gate 		ber->ber_ptr += len;
3060Sstevel@tonic-gate 		return( len );
3070Sstevel@tonic-gate 	} else {
3080Sstevel@tonic-gate 		if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
3090Sstevel@tonic-gate 			if ( nslberi_ber_realloc( ber, len ) != 0 )
3100Sstevel@tonic-gate 				return( -1 );
3110Sstevel@tonic-gate 		}
3120Sstevel@tonic-gate 		SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
3130Sstevel@tonic-gate 		ber->ber_sos->sos_ptr += len;
3140Sstevel@tonic-gate 		ber->ber_sos->sos_clen += len;
3150Sstevel@tonic-gate 		return( len );
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate void
3200Sstevel@tonic-gate LDAP_CALL
ber_free(BerElement * ber,int freebuf)3210Sstevel@tonic-gate ber_free( BerElement *ber, int freebuf )
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 	if ( ber != NULL ) {
3240Sstevel@tonic-gate 		    if ( freebuf &&
3250Sstevel@tonic-gate 			!(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
3260Sstevel@tonic-gate 			    NSLBERI_FREE(ber->ber_buf);
3270Sstevel@tonic-gate 		    }
3280Sstevel@tonic-gate 		    NSLBERI_FREE( (char *) ber );
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate  * return >= 0 on success, -1 on failure.
3340Sstevel@tonic-gate  */
3350Sstevel@tonic-gate int
3360Sstevel@tonic-gate LDAP_CALL
ber_flush(Sockbuf * sb,BerElement * ber,int freeit)3370Sstevel@tonic-gate ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate 	ssize_t	nwritten, towrite, rc;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if ( ber->ber_rwptr == NULL ) {
3420Sstevel@tonic-gate 		ber->ber_rwptr = ber->ber_buf;
3430Sstevel@tonic-gate 	} else if (ber->ber_rwptr >= ber->ber_end) {
3440Sstevel@tonic-gate           /* we will use the ber_rwptr to continue an exited flush,
3450Sstevel@tonic-gate              so if rwptr is not within the buffer we return an error. */
3460Sstevel@tonic-gate           return( -1 );
3470Sstevel@tonic-gate         }
3480Sstevel@tonic-gate 	towrite = ber->ber_ptr - ber->ber_rwptr;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate #ifdef LDAP_DEBUG
3510Sstevel@tonic-gate 	if ( lber_debug ) {
3520Sstevel@tonic-gate 		char msg[80];
3530Sstevel@tonic-gate 		sprintf( msg, "ber_flush: %ld bytes to sd %ld%s\n", towrite,
3540Sstevel@tonic-gate 		    sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
3550Sstevel@tonic-gate 		    : "" );
3560Sstevel@tonic-gate 		ber_err_print( msg );
3570Sstevel@tonic-gate 		if ( lber_debug > 1 )
3580Sstevel@tonic-gate 			lber_bprint( ber->ber_rwptr, towrite );
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate #endif
3610Sstevel@tonic-gate #if !defined(macintosh) && !defined(DOS)
3620Sstevel@tonic-gate 	if ( sb->sb_options & (LBER_SOCKBUF_OPT_TO_FILE | LBER_SOCKBUF_OPT_TO_FILE_ONLY) ) {
3630Sstevel@tonic-gate 		rc = write( sb->sb_copyfd, ber->ber_buf, towrite );
3640Sstevel@tonic-gate 		if ( sb->sb_options & LBER_SOCKBUF_OPT_TO_FILE_ONLY ) {
3650Sstevel@tonic-gate 			return( (int)rc );
3660Sstevel@tonic-gate 		}
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate #endif
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	nwritten = 0;
3710Sstevel@tonic-gate 	do {
3720Sstevel@tonic-gate 		if (sb->sb_naddr > 0) {
3730Sstevel@tonic-gate #ifdef CLDAP
3740Sstevel@tonic-gate 			rc = udp_write( sb, ber->ber_buf + nwritten,
3750Sstevel@tonic-gate 			    (size_t)towrite );
3760Sstevel@tonic-gate #else /* CLDAP */
3770Sstevel@tonic-gate 			rc = -1;
3780Sstevel@tonic-gate #endif /* CLDAP */
3790Sstevel@tonic-gate 			if ( rc <= 0 )
3800Sstevel@tonic-gate 				return( -1 );
3810Sstevel@tonic-gate 			/* fake error if write was not atomic */
3820Sstevel@tonic-gate 			if (rc < towrite) {
3830Sstevel@tonic-gate #if !defined( macintosh ) && !defined( DOS )
3840Sstevel@tonic-gate 			    errno = EMSGSIZE;  /* For Win32, see portable.h */
3850Sstevel@tonic-gate #endif
3860Sstevel@tonic-gate 			    return( -1 );
3870Sstevel@tonic-gate 			}
3880Sstevel@tonic-gate 		} else {
3890Sstevel@tonic-gate 			if ( sb->sb_ext_io_fns.lbextiofn_write != NULL ) {
3900Sstevel@tonic-gate 				if ( (rc = sb->sb_ext_io_fns.lbextiofn_write(
3910Sstevel@tonic-gate 				    sb->sb_sd, ber->ber_rwptr, (size_t)towrite,
3920Sstevel@tonic-gate 				    sb->sb_ext_io_fns.lbextiofn_socket_arg ))
3930Sstevel@tonic-gate 				    <= 0 ) {
3940Sstevel@tonic-gate 					return( -1 );
3950Sstevel@tonic-gate 				}
3960Sstevel@tonic-gate 			} else {
3970Sstevel@tonic-gate 				if ( (rc = BerWrite( sb, ber->ber_rwptr,
3980Sstevel@tonic-gate 				    (size_t) towrite )) <= 0 ) {
3990Sstevel@tonic-gate 					return( -1 );
4000Sstevel@tonic-gate 				}
4010Sstevel@tonic-gate 			}
4020Sstevel@tonic-gate 		}
4030Sstevel@tonic-gate 		towrite -= rc;
4040Sstevel@tonic-gate 		nwritten += rc;
4050Sstevel@tonic-gate 		ber->ber_rwptr += rc;
4060Sstevel@tonic-gate 	} while ( towrite > 0 );
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if ( freeit )
4090Sstevel@tonic-gate 		ber_free( ber, 1 );
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	return( 0 );
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate /* we pre-allocate a buffer to save the extra malloc later */
4160Sstevel@tonic-gate BerElement *
4170Sstevel@tonic-gate LDAP_CALL
ber_alloc_t(int options)4180Sstevel@tonic-gate ber_alloc_t( int options )
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate 	BerElement	*ber;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	if ( (ber = (BerElement*)NSLBERI_CALLOC( 1,
4230Sstevel@tonic-gate 	    sizeof(struct berelement) + EXBUFSIZ )) == NULL ) {
4240Sstevel@tonic-gate 		return( NULL );
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	/*
4280Sstevel@tonic-gate 	 * for compatibility with the C LDAP API standard, we recognize
4290Sstevel@tonic-gate 	 * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
4300Sstevel@tonic-gate 	 */
4310Sstevel@tonic-gate 	if ( options & LBER_USE_DER ) {
4320Sstevel@tonic-gate 		options &= ~LBER_USE_DER;
4330Sstevel@tonic-gate 		options |= LBER_OPT_USE_DER;
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	ber->ber_tag = LBER_DEFAULT;
4370Sstevel@tonic-gate 	ber->ber_options = options;
4380Sstevel@tonic-gate 	ber->ber_buf = (char*)ber + sizeof(struct berelement);
4390Sstevel@tonic-gate 	ber->ber_ptr = ber->ber_buf;
4400Sstevel@tonic-gate 	ber->ber_end = ber->ber_buf + EXBUFSIZ;
4410Sstevel@tonic-gate 	ber->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	return( ber );
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate BerElement *
4480Sstevel@tonic-gate LDAP_CALL
ber_alloc()4490Sstevel@tonic-gate ber_alloc()
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	return( ber_alloc_t( 0 ) );
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate BerElement *
4550Sstevel@tonic-gate LDAP_CALL
der_alloc()4560Sstevel@tonic-gate der_alloc()
4570Sstevel@tonic-gate {
4580Sstevel@tonic-gate 	return( ber_alloc_t( LBER_OPT_USE_DER ) );
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate BerElement *
4620Sstevel@tonic-gate LDAP_CALL
ber_dup(BerElement * ber)4630Sstevel@tonic-gate ber_dup( BerElement *ber )
4640Sstevel@tonic-gate {
4650Sstevel@tonic-gate 	BerElement	*new;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	if ( (new = ber_alloc()) == NULL )
4680Sstevel@tonic-gate 		return( NULL );
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	*new = *ber;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	return( new );
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate void
4770Sstevel@tonic-gate LDAP_CALL
ber_init_w_nullchar(BerElement * ber,int options)4780Sstevel@tonic-gate ber_init_w_nullchar( BerElement *ber, int options )
4790Sstevel@tonic-gate {
4800Sstevel@tonic-gate 	(void) memset( (char *)ber, '\0', sizeof(struct berelement) );
4810Sstevel@tonic-gate 	ber->ber_tag = LBER_DEFAULT;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	/*
4840Sstevel@tonic-gate 	 * For compatibility with the C LDAP API standard, we recognize
4850Sstevel@tonic-gate 	 * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
4860Sstevel@tonic-gate 	 */
4870Sstevel@tonic-gate 	if ( options & LBER_USE_DER ) {
4880Sstevel@tonic-gate 		options &= ~LBER_USE_DER;
4890Sstevel@tonic-gate 		options |= LBER_OPT_USE_DER;
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	ber->ber_options = options;
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate void
4970Sstevel@tonic-gate LDAP_CALL
ber_reset(BerElement * ber,int was_writing)4980Sstevel@tonic-gate ber_reset( BerElement *ber, int was_writing )
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	if ( was_writing ) {
5010Sstevel@tonic-gate 		ber->ber_end = ber->ber_ptr;
5020Sstevel@tonic-gate 		ber->ber_ptr = ber->ber_buf;
5030Sstevel@tonic-gate 	} else {
5040Sstevel@tonic-gate 		ber->ber_ptr = ber->ber_end;
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	ber->ber_rwptr = NULL;
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate #ifdef LDAP_DEBUG
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate void
ber_dump(BerElement * ber,int inout)5140Sstevel@tonic-gate ber_dump( BerElement *ber, int inout )
5150Sstevel@tonic-gate {
5160Sstevel@tonic-gate 	char msg[128];
5170Sstevel@tonic-gate 	sprintf( msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
5180Sstevel@tonic-gate 	    ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end );
5190Sstevel@tonic-gate 	ber_err_print( msg );
5200Sstevel@tonic-gate 	if ( inout == 1 ) {
5210Sstevel@tonic-gate 		sprintf( msg, "          current len %ld, contents:\n",
5220Sstevel@tonic-gate 		    ber->ber_end - ber->ber_ptr );
5230Sstevel@tonic-gate 		ber_err_print( msg );
5240Sstevel@tonic-gate 		lber_bprint( ber->ber_ptr, ber->ber_end - ber->ber_ptr );
5250Sstevel@tonic-gate 	} else {
5260Sstevel@tonic-gate 		sprintf( msg, "          current len %ld, contents:\n",
5270Sstevel@tonic-gate 		    ber->ber_ptr - ber->ber_buf );
5280Sstevel@tonic-gate 		ber_err_print( msg );
5290Sstevel@tonic-gate 		lber_bprint( ber->ber_buf, ber->ber_ptr - ber->ber_buf );
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate void
ber_sos_dump(Seqorset * sos)5340Sstevel@tonic-gate ber_sos_dump( Seqorset *sos )
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 	char msg[80];
5370Sstevel@tonic-gate 	ber_err_print ( "*** sos dump ***\n" );
5380Sstevel@tonic-gate 	while ( sos != NULLSEQORSET ) {
5390Sstevel@tonic-gate 		sprintf( msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
5400Sstevel@tonic-gate 		    sos->sos_clen, sos->sos_first, sos->sos_ptr );
5410Sstevel@tonic-gate 		ber_err_print( msg );
5420Sstevel@tonic-gate 		sprintf( msg, "              current len %ld contents:\n",
5430Sstevel@tonic-gate 		    sos->sos_ptr - sos->sos_first );
5440Sstevel@tonic-gate 		ber_err_print( msg );
5450Sstevel@tonic-gate 		lber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first );
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		sos = sos->sos_next;
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 	ber_err_print( "*** end dump ***\n" );
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate #endif
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate /* return the tag - LBER_DEFAULT returned means trouble */
5550Sstevel@tonic-gate static ber_tag_t
get_tag(Sockbuf * sb)5560Sstevel@tonic-gate get_tag( Sockbuf *sb )
5570Sstevel@tonic-gate {
5580Sstevel@tonic-gate 	unsigned char	xbyte;
5590Sstevel@tonic-gate 	ber_tag_t	tag;
5600Sstevel@tonic-gate 	char		*tagp;
5610Sstevel@tonic-gate 	int		i;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	if ( (i = BerRead( sb, (char *) &xbyte, 1 )) != 1 ) {
5640Sstevel@tonic-gate 		return( LBER_DEFAULT );
5650Sstevel@tonic-gate 	}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
5680Sstevel@tonic-gate 		return( (ber_uint_t) xbyte );
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	tagp = (char *) &tag;
5720Sstevel@tonic-gate 	tagp[0] = xbyte;
5730Sstevel@tonic-gate 	for ( i = 1; i < sizeof(ber_int_t); i++ ) {
5740Sstevel@tonic-gate 		if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 )
5750Sstevel@tonic-gate 			return( LBER_DEFAULT );
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 		tagp[i] = xbyte;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 		if ( ! (xbyte & LBER_MORE_TAG_MASK) )
5800Sstevel@tonic-gate 			break;
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	/* tag too big! */
5840Sstevel@tonic-gate 	if ( i == sizeof(ber_int_t) )
5850Sstevel@tonic-gate 		return( LBER_DEFAULT );
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/* want leading, not trailing 0's */
5880Sstevel@tonic-gate 	return( tag >> (sizeof(ber_int_t) - i - 1) );
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate ber_tag_t
5920Sstevel@tonic-gate LDAP_CALL
ber_get_next(Sockbuf * sb,ber_len_t * len,BerElement * ber)5930Sstevel@tonic-gate ber_get_next( Sockbuf *sb, ber_len_t *len, BerElement *ber )
5940Sstevel@tonic-gate {
5950Sstevel@tonic-gate 	ber_tag_t	tag = 0;
5960Sstevel@tonic-gate 	ber_len_t	netlen;
5970Sstevel@tonic-gate 	ber_uint_t	 toread;
5980Sstevel@tonic-gate 	unsigned char	lc;
5990Sstevel@tonic-gate 	ber_int_t	rc;
6000Sstevel@tonic-gate 	int		noctets, diff;
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate #ifdef LDAP_DEBUG
6030Sstevel@tonic-gate 	if ( lber_debug )
6040Sstevel@tonic-gate 		ber_err_print( "ber_get_next\n" );
6050Sstevel@tonic-gate #endif
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	/*
6080Sstevel@tonic-gate 	 * Any ber element looks like this: tag length contents.
6090Sstevel@tonic-gate 	 * Assuming everything's ok, we return the tag byte (we
6100Sstevel@tonic-gate 	 * can assume a single byte), return the length in len,
6110Sstevel@tonic-gate 	 * and the rest of the undecoded element in buf.
6120Sstevel@tonic-gate 	 *
6130Sstevel@tonic-gate 	 * Assumptions:
6140Sstevel@tonic-gate 	 *	1) small tags (less than 128)
6150Sstevel@tonic-gate 	 *	2) definite lengths
6160Sstevel@tonic-gate 	 *	3) primitive encodings used whenever possible
6170Sstevel@tonic-gate 	 */
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	/*
6200Sstevel@tonic-gate 	 * first time through - malloc the buffer, set up ptrs, and
6210Sstevel@tonic-gate 	 * read the tag and the length and as much of the rest as we can
6220Sstevel@tonic-gate 	 */
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	if ( ber->ber_rwptr == NULL ) {
6250Sstevel@tonic-gate 		/*
6260Sstevel@tonic-gate 		 * First, we read the tag.
6270Sstevel@tonic-gate 		 */
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 		if ( (tag = get_tag( sb )) == LBER_DEFAULT ) {
6300Sstevel@tonic-gate 			return( LBER_DEFAULT );
6310Sstevel@tonic-gate 		}
6320Sstevel@tonic-gate 		ber->ber_tag = tag;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 		/*
6350Sstevel@tonic-gate 		 * Next, read the length.  The first byte contains the length
6360Sstevel@tonic-gate 		 * of the length.  If bit 8 is set, the length is the long
6370Sstevel@tonic-gate 		 * form, otherwise it's the short form.  We don't allow a
6380Sstevel@tonic-gate 		 * length that's greater than what we can hold in an unsigned
6390Sstevel@tonic-gate 		 * long.
6400Sstevel@tonic-gate 		 */
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		*len = netlen = 0;
6430Sstevel@tonic-gate 		if ( BerRead( sb, (char *) &lc, 1 ) != 1 ) {
6440Sstevel@tonic-gate 			return( LBER_DEFAULT );
6450Sstevel@tonic-gate 		}
6460Sstevel@tonic-gate 		if ( lc & 0x80 ) {
6470Sstevel@tonic-gate 			noctets = (lc & 0x7f);
6480Sstevel@tonic-gate 			if ( noctets > sizeof(ber_uint_t) )
6490Sstevel@tonic-gate 				return( LBER_DEFAULT );
6500Sstevel@tonic-gate 			diff = sizeof(ber_uint_t) - noctets;
6510Sstevel@tonic-gate 			if ( BerRead( sb, (char *) &netlen + diff, noctets ) !=
6520Sstevel@tonic-gate 			    noctets ) {
6530Sstevel@tonic-gate 				return( LBER_DEFAULT );
6540Sstevel@tonic-gate 			}
6550Sstevel@tonic-gate 			*len = LBER_NTOHL( netlen );
6560Sstevel@tonic-gate 		} else {
6570Sstevel@tonic-gate 			*len = lc;
6580Sstevel@tonic-gate 		}
6590Sstevel@tonic-gate 		ber->ber_len = *len;
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 		/*
6620Sstevel@tonic-gate 		 * Finally, malloc a buffer for the contents and read it in.
6630Sstevel@tonic-gate 		 * It's this buffer that's passed to all the other ber decoding
6640Sstevel@tonic-gate 		 * routines.
6650Sstevel@tonic-gate 		 */
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate #if defined( DOS ) && !( defined( _WIN32 ) || defined(XP_OS2) )
6680Sstevel@tonic-gate 		if ( *len > 65535 ) {	/* DOS can't allocate > 64K */
6690Sstevel@tonic-gate 		    return( LBER_DEFAULT );
6700Sstevel@tonic-gate 		}
6710Sstevel@tonic-gate #endif /* DOS && !_WIN32 */
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 		if ( ( sb->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
6740Sstevel@tonic-gate 		    && *len > sb->sb_max_incoming ) {
6750Sstevel@tonic-gate 			return( LBER_DEFAULT );
6760Sstevel@tonic-gate 		}
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 		if ( (ber->ber_buf = (char *)NSLBERI_CALLOC( 1,(size_t)*len ))
6790Sstevel@tonic-gate 		    == NULL ) {
6800Sstevel@tonic-gate 			return( LBER_DEFAULT );
6810Sstevel@tonic-gate 		}
6820Sstevel@tonic-gate 		ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
6830Sstevel@tonic-gate 		ber->ber_ptr = ber->ber_buf;
6840Sstevel@tonic-gate 		ber->ber_end = ber->ber_buf + *len;
6850Sstevel@tonic-gate 		ber->ber_rwptr = ber->ber_buf;
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	toread = (uintptr_t)ber->ber_end - (uintptr_t)ber->ber_rwptr;
6890Sstevel@tonic-gate 	do {
6900Sstevel@tonic-gate 		if ( (rc = BerRead( sb, ber->ber_rwptr, (ber_int_t)toread )) <= 0 ) {
6910Sstevel@tonic-gate 			return( LBER_DEFAULT );
6920Sstevel@tonic-gate 		}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 		toread -= rc;
6950Sstevel@tonic-gate 		ber->ber_rwptr += rc;
6960Sstevel@tonic-gate 	} while ( toread > 0 );
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate #ifdef LDAP_DEBUG
6990Sstevel@tonic-gate 	if ( lber_debug ) {
7000Sstevel@tonic-gate 		char msg[80];
7010Sstevel@tonic-gate 		sprintf( msg, "ber_get_next: tag 0x%lx len %ld contents:\n",
7020Sstevel@tonic-gate 		    tag, ber->ber_len );
7030Sstevel@tonic-gate 		ber_err_print( msg );
7040Sstevel@tonic-gate 		if ( lber_debug > 1 )
7050Sstevel@tonic-gate 			ber_dump( ber, 1 );
7060Sstevel@tonic-gate 	}
7070Sstevel@tonic-gate #endif
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	*len = ber->ber_len;
7100Sstevel@tonic-gate 	ber->ber_rwptr = NULL;
7110Sstevel@tonic-gate 	return( ber->ber_tag );
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate Sockbuf *
7150Sstevel@tonic-gate LDAP_CALL
ber_sockbuf_alloc()7160Sstevel@tonic-gate ber_sockbuf_alloc()
7170Sstevel@tonic-gate {
7180Sstevel@tonic-gate 	return( (Sockbuf *)NSLBERI_CALLOC( 1, sizeof(struct sockbuf) ) );
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate void
7220Sstevel@tonic-gate LDAP_CALL
ber_sockbuf_free(Sockbuf * p)7230Sstevel@tonic-gate ber_sockbuf_free(Sockbuf *p)
7240Sstevel@tonic-gate {
7250Sstevel@tonic-gate 	if ( p != NULL ) {
726*12023SDoug.Leavitt@Sun.COM #ifdef LDAP_SASLIO_HOOKS
727*12023SDoug.Leavitt@Sun.COM 		if ( p->sb_sasl_ctx != NULL)
728*12023SDoug.Leavitt@Sun.COM         		sasl_dispose(&p->sb_sasl_ctx);
729*12023SDoug.Leavitt@Sun.COM 		if ( p->sb_sasl_ibuf != NULL) {
730*12023SDoug.Leavitt@Sun.COM 			NSLBERI_FREE( p->sb_sasl_ibuf );
731*12023SDoug.Leavitt@Sun.COM 		}
732*12023SDoug.Leavitt@Sun.COM #endif
7330Sstevel@tonic-gate 		if ( p->sb_ber.ber_buf != NULL &&
7340Sstevel@tonic-gate 		    !(p->sb_ber.ber_flags & LBER_FLAG_NO_FREE_BUFFER) ) {
7350Sstevel@tonic-gate 			NSLBERI_FREE( p->sb_ber.ber_buf );
7360Sstevel@tonic-gate 		}
7370Sstevel@tonic-gate 		NSLBERI_FREE(p);
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate /*
7420Sstevel@tonic-gate  * return 0 on success and -1 on error
7430Sstevel@tonic-gate  */
7440Sstevel@tonic-gate int
7450Sstevel@tonic-gate LDAP_CALL
ber_set_option(struct berelement * ber,int option,void * value)7460Sstevel@tonic-gate ber_set_option( struct berelement *ber, int option, void *value )
7470Sstevel@tonic-gate {
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate   /*
7500Sstevel@tonic-gate    * memory allocation callbacks are global, so it is OK to pass
7510Sstevel@tonic-gate    * NULL for ber.  Handle this as a special case.
7520Sstevel@tonic-gate    */
7530Sstevel@tonic-gate   if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
7540Sstevel@tonic-gate     /* struct copy */
7550Sstevel@tonic-gate     nslberi_memalloc_fns = *((struct lber_memalloc_fns *)value);
7560Sstevel@tonic-gate     return( 0 );
7570Sstevel@tonic-gate   }
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate   /*
7600Sstevel@tonic-gate    * lber_debug is global, so it is OK to pass
7610Sstevel@tonic-gate    * NULL for ber.  Handle this as a special case.
7620Sstevel@tonic-gate    */
7630Sstevel@tonic-gate   if ( option == LBER_OPT_DEBUG_LEVEL ) {
7640Sstevel@tonic-gate #ifdef LDAP_DEBUG
7650Sstevel@tonic-gate     lber_debug = *(int *)value;
7660Sstevel@tonic-gate #endif
7670Sstevel@tonic-gate     return( 0 );
7680Sstevel@tonic-gate   }
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate   /*
7710Sstevel@tonic-gate    * all the rest require a non-NULL ber
7720Sstevel@tonic-gate    */
7730Sstevel@tonic-gate   if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
7740Sstevel@tonic-gate     return( -1 );
7750Sstevel@tonic-gate   }
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate   switch ( option ) {
7780Sstevel@tonic-gate 	case LBER_OPT_USE_DER:
7790Sstevel@tonic-gate 	case LBER_OPT_TRANSLATE_STRINGS:
7800Sstevel@tonic-gate 		if ( value != NULL ) {
7810Sstevel@tonic-gate 			ber->ber_options |= option;
7820Sstevel@tonic-gate 		} else {
7830Sstevel@tonic-gate 			ber->ber_options &= ~option;
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 		break;
7860Sstevel@tonic-gate 	case LBER_OPT_REMAINING_BYTES:
7870Sstevel@tonic-gate 		ber->ber_end = ber->ber_ptr + *((ber_uint_t *)value);
7880Sstevel@tonic-gate 		break;
7890Sstevel@tonic-gate 	case LBER_OPT_TOTAL_BYTES:
7900Sstevel@tonic-gate 		ber->ber_end = ber->ber_buf + *((ber_uint_t *)value);
7910Sstevel@tonic-gate 		break;
7920Sstevel@tonic-gate 	case LBER_OPT_BYTES_TO_WRITE:
7930Sstevel@tonic-gate 		ber->ber_ptr = ber->ber_buf + *((ber_uint_t *)value);
7940Sstevel@tonic-gate 		break;
7950Sstevel@tonic-gate 	default:
7960Sstevel@tonic-gate 		return( -1 );
7970Sstevel@tonic-gate   }
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate   return( 0 );
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate /*
8030Sstevel@tonic-gate  * return 0 on success and -1 on error
8040Sstevel@tonic-gate  */
8050Sstevel@tonic-gate int
8060Sstevel@tonic-gate LDAP_CALL
ber_get_option(struct berelement * ber,int option,void * value)8070Sstevel@tonic-gate ber_get_option( struct berelement *ber, int option, void *value )
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate 	/*
8100Sstevel@tonic-gate 	 * memory callocation callbacks are global, so it is OK to pass
8110Sstevel@tonic-gate 	 * NULL for ber.  Handle this as a special case
8120Sstevel@tonic-gate 	 */
8130Sstevel@tonic-gate 	if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
8140Sstevel@tonic-gate 		/* struct copy */
8150Sstevel@tonic-gate 		*((struct lber_memalloc_fns *)value) = nslberi_memalloc_fns;
8160Sstevel@tonic-gate 		return( 0 );
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	/*
8200Sstevel@tonic-gate 	 * lber_debug is global, so it is OK to pass
8210Sstevel@tonic-gate 	 * NULL for ber.  Handle this as a special case.
8220Sstevel@tonic-gate 	 */
8230Sstevel@tonic-gate 	if ( option == LBER_OPT_DEBUG_LEVEL ) {
8240Sstevel@tonic-gate #ifdef LDAP_DEBUG
8250Sstevel@tonic-gate 	 *(int *)value =  lber_debug;
8260Sstevel@tonic-gate #endif
8270Sstevel@tonic-gate 	  return( 0 );
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 	/*
8300Sstevel@tonic-gate 	 * all the rest require a non-NULL ber
8310Sstevel@tonic-gate 	 */
8320Sstevel@tonic-gate 	if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
8330Sstevel@tonic-gate 		return( -1 );
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	switch ( option ) {
8370Sstevel@tonic-gate 	case LBER_OPT_USE_DER:
8380Sstevel@tonic-gate 	case LBER_OPT_TRANSLATE_STRINGS:
8390Sstevel@tonic-gate 		*((int *) value) = (ber->ber_options & option);
8400Sstevel@tonic-gate 		break;
8410Sstevel@tonic-gate 	case LBER_OPT_REMAINING_BYTES:
8420Sstevel@tonic-gate 		*((ber_uint_t *) value) = ber->ber_end - ber->ber_ptr;
8430Sstevel@tonic-gate 		break;
8440Sstevel@tonic-gate 	case LBER_OPT_TOTAL_BYTES:
8450Sstevel@tonic-gate 		*((ber_uint_t *) value) = ber->ber_end - ber->ber_buf;
8460Sstevel@tonic-gate 		break;
8470Sstevel@tonic-gate 	case LBER_OPT_BYTES_TO_WRITE:
8480Sstevel@tonic-gate 		*((ber_uint_t *) value) = ber->ber_ptr - ber->ber_buf;
8490Sstevel@tonic-gate 		break;
8500Sstevel@tonic-gate 	default:
8510Sstevel@tonic-gate 		return( -1 );
8520Sstevel@tonic-gate 	}
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	return( 0 );
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate /*
8580Sstevel@tonic-gate  * return 0 on success and -1 on error
8590Sstevel@tonic-gate  */
8600Sstevel@tonic-gate int
8610Sstevel@tonic-gate LDAP_CALL
ber_sockbuf_set_option(Sockbuf * sb,int option,void * value)8620Sstevel@tonic-gate ber_sockbuf_set_option( Sockbuf *sb, int option, void *value )
8630Sstevel@tonic-gate {
8640Sstevel@tonic-gate 	struct lber_x_ext_io_fns	*extiofns;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
8670Sstevel@tonic-gate 		return( -1 );
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	switch ( option ) {
8710Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
8720Sstevel@tonic-gate 		sb->sb_max_incoming = *((ber_uint_t *) value);
8730Sstevel@tonic-gate 		/* FALL */
8740Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_TO_FILE:
8750Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
8760Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
8770Sstevel@tonic-gate 		if ( value != NULL ) {
8780Sstevel@tonic-gate 			sb->sb_options |= option;
8790Sstevel@tonic-gate 		} else {
8800Sstevel@tonic-gate 			sb->sb_options &= ~option;
8810Sstevel@tonic-gate 		}
8820Sstevel@tonic-gate 		break;
8830Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_DESC:
8840Sstevel@tonic-gate 		sb->sb_sd = *((LBER_SOCKET *) value);
8850Sstevel@tonic-gate 		break;
8860Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_COPYDESC:
8870Sstevel@tonic-gate 		sb->sb_copyfd = *((LBER_SOCKET *) value);
8880Sstevel@tonic-gate 		break;
8890Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_READ_FN:
8900Sstevel@tonic-gate 		sb->sb_io_fns.lbiof_read = (LDAP_IOF_READ_CALLBACK *) value;
8910Sstevel@tonic-gate 		nslberi_install_compat_io_fns( sb );
8920Sstevel@tonic-gate 		break;
8930Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_WRITE_FN:
8940Sstevel@tonic-gate 		sb->sb_io_fns.lbiof_write = (LDAP_IOF_WRITE_CALLBACK *) value;
8950Sstevel@tonic-gate 		nslberi_install_compat_io_fns( sb );
8960Sstevel@tonic-gate 		break;
8970Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_EXT_IO_FNS:
8980Sstevel@tonic-gate 		extiofns = (struct lber_x_ext_io_fns *) value;
8990Sstevel@tonic-gate 		if ( extiofns == NULL ) {	/* remove */
9000Sstevel@tonic-gate 			(void)memset( (char *)&sb->sb_ext_io_fns, '\0',
9010Sstevel@tonic-gate 				sizeof(sb->sb_ext_io_fns ));
9020Sstevel@tonic-gate 		} else if ( extiofns->lbextiofn_size
9030Sstevel@tonic-gate 		    == LBER_X_EXTIO_FNS_SIZE ) {
9040Sstevel@tonic-gate 			/* struct copy */
9050Sstevel@tonic-gate 			sb->sb_ext_io_fns = *extiofns;
9060Sstevel@tonic-gate 		} else {
9070Sstevel@tonic-gate 			return( -1 );
9080Sstevel@tonic-gate 		}
9090Sstevel@tonic-gate 		break;
9100Sstevel@tonic-gate 	default:
9110Sstevel@tonic-gate 		return( -1 );
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	return( 0 );
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate /*
9180Sstevel@tonic-gate  * return 0 on success and -1 on error
9190Sstevel@tonic-gate  */
9200Sstevel@tonic-gate int
9210Sstevel@tonic-gate LDAP_CALL
ber_sockbuf_get_option(Sockbuf * sb,int option,void * value)9220Sstevel@tonic-gate ber_sockbuf_get_option( Sockbuf *sb, int option, void *value )
9230Sstevel@tonic-gate {
9240Sstevel@tonic-gate 	struct lber_x_ext_io_fns	*extiofns;
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
9270Sstevel@tonic-gate 		return( -1 );
9280Sstevel@tonic-gate 	}
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	switch ( option ) {
9310Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
9320Sstevel@tonic-gate 		*((ber_uint_t *) value) = sb->sb_max_incoming;
9330Sstevel@tonic-gate 		break;
9340Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_TO_FILE:
9350Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
9360Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
9370Sstevel@tonic-gate 		*((int *) value) = (sb->sb_options & option);
9380Sstevel@tonic-gate 		break;
9390Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_DESC:
9400Sstevel@tonic-gate 		*((LBER_SOCKET *) value) = sb->sb_sd;
9410Sstevel@tonic-gate 		break;
9420Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_COPYDESC:
9430Sstevel@tonic-gate 		*((LBER_SOCKET *) value) = sb->sb_copyfd;
9440Sstevel@tonic-gate 		break;
9450Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_READ_FN:
9460Sstevel@tonic-gate 		*((LDAP_IOF_READ_CALLBACK **) value)
9470Sstevel@tonic-gate 		    = sb->sb_io_fns.lbiof_read;
9480Sstevel@tonic-gate 		break;
9490Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_WRITE_FN:
9500Sstevel@tonic-gate 		*((LDAP_IOF_WRITE_CALLBACK **) value)
9510Sstevel@tonic-gate 		    = sb->sb_io_fns.lbiof_write;
9520Sstevel@tonic-gate 		break;
9530Sstevel@tonic-gate 	case LBER_SOCKBUF_OPT_EXT_IO_FNS:
9540Sstevel@tonic-gate 		extiofns = (struct lber_x_ext_io_fns *) value;
9550Sstevel@tonic-gate 		if ( extiofns == NULL || extiofns->lbextiofn_size
9560Sstevel@tonic-gate 		    != LBER_X_EXTIO_FNS_SIZE ) {
9570Sstevel@tonic-gate 			return( -1 );
9580Sstevel@tonic-gate 		}
9590Sstevel@tonic-gate 		/* struct copy */
9600Sstevel@tonic-gate 		*extiofns = sb->sb_ext_io_fns;
9610Sstevel@tonic-gate 		break;
9620Sstevel@tonic-gate 	default:
9630Sstevel@tonic-gate 		return( -1 );
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	return( 0 );
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate /* new dboreham code below: */
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate struct byte_buffer  {
9730Sstevel@tonic-gate 	unsigned char *p;
9740Sstevel@tonic-gate 	int offset;
9750Sstevel@tonic-gate 	int length;
9760Sstevel@tonic-gate };
9770Sstevel@tonic-gate typedef struct byte_buffer byte_buffer;
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate /* This call allocates us a BerElement structure plus some extra memory.
9810Sstevel@tonic-gate  * It returns a pointer to the BerElement, plus a pointer to the extra memory.
9820Sstevel@tonic-gate  * This routine also allocates a ber data buffer within the same block, thus
9830Sstevel@tonic-gate  * saving a call to calloc later when we read data.
9840Sstevel@tonic-gate  */
9850Sstevel@tonic-gate void*
9860Sstevel@tonic-gate LDAP_CALL
ber_special_alloc(size_t size,BerElement ** ppBer)9870Sstevel@tonic-gate ber_special_alloc(size_t size, BerElement **ppBer)
9880Sstevel@tonic-gate {
9890Sstevel@tonic-gate 	char *mem = NULL;
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	/* Make sure mem size requested is aligned */
9920Sstevel@tonic-gate 	if (0 != ( size & 0x03 )) {
9930Sstevel@tonic-gate 		size += (sizeof(ber_int_t) - (size & 0x03));
9940Sstevel@tonic-gate 	}
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	mem = NSLBERI_MALLOC(sizeof(struct berelement) + EXBUFSIZ + size );
9970Sstevel@tonic-gate 	if (NULL == mem) {
9980Sstevel@tonic-gate 		return NULL;
9990Sstevel@tonic-gate 	}
10000Sstevel@tonic-gate 	*ppBer = (BerElement*) (mem + size);
10010Sstevel@tonic-gate 	memset(*ppBer,0,sizeof(struct berelement));
10020Sstevel@tonic-gate 	(*ppBer)->ber_tag = LBER_DEFAULT;
10030Sstevel@tonic-gate 	(*ppBer)->ber_buf = mem + size + sizeof(struct berelement);
10040Sstevel@tonic-gate 	(*ppBer)->ber_ptr = (*ppBer)->ber_buf;
10050Sstevel@tonic-gate 	(*ppBer)->ber_end = (*ppBer)->ber_buf + EXBUFSIZ;
10060Sstevel@tonic-gate 	(*ppBer)->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
10070Sstevel@tonic-gate 	return (void*)mem;
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate void
10110Sstevel@tonic-gate LDAP_CALL
ber_special_free(void * buf,BerElement * ber)10120Sstevel@tonic-gate ber_special_free(void* buf, BerElement *ber)
10130Sstevel@tonic-gate {
10140Sstevel@tonic-gate 	if (!(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
10150Sstevel@tonic-gate 		NSLBERI_FREE(ber->ber_buf);
10160Sstevel@tonic-gate 	}
10170Sstevel@tonic-gate 	NSLBERI_FREE( buf );
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate static int
read_bytes(byte_buffer * b,unsigned char * return_buffer,int bytes_to_read)10210Sstevel@tonic-gate read_bytes(byte_buffer *b, unsigned char *return_buffer, int bytes_to_read)
10220Sstevel@tonic-gate {
10230Sstevel@tonic-gate 	/* copy up to bytes_to_read bytes into the caller's buffer, return the number of bytes copied */
10240Sstevel@tonic-gate 	int bytes_to_copy = 0;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	if (bytes_to_read <= (b->length - b->offset) ) {
10270Sstevel@tonic-gate 		bytes_to_copy = bytes_to_read;
10280Sstevel@tonic-gate 	} else {
10290Sstevel@tonic-gate 		bytes_to_copy = (b->length - b->offset);
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 	if (1 == bytes_to_copy) {
10320Sstevel@tonic-gate 		*return_buffer = *(b->p+b->offset++);
10330Sstevel@tonic-gate 	} else
10340Sstevel@tonic-gate 	if (0 == bytes_to_copy) {
10350Sstevel@tonic-gate 		;
10360Sstevel@tonic-gate 	} else
10370Sstevel@tonic-gate 	{
10380Sstevel@tonic-gate 		memcpy(return_buffer,b->p+b->offset,bytes_to_copy);
10390Sstevel@tonic-gate 		b->offset += bytes_to_copy;
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate 	return bytes_to_copy;
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate /* return the tag - LBER_DEFAULT returned means trouble */
10450Sstevel@tonic-gate static ber_tag_t
get_buffer_tag(byte_buffer * sb)10460Sstevel@tonic-gate get_buffer_tag(byte_buffer *sb )
10470Sstevel@tonic-gate {
10480Sstevel@tonic-gate 	unsigned char	xbyte;
10490Sstevel@tonic-gate 	ber_tag_t	tag;
10500Sstevel@tonic-gate 	char		*tagp;
10510Sstevel@tonic-gate 	int		i;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	if ( (i = read_bytes( sb, &xbyte, 1 )) != 1 ) {
10540Sstevel@tonic-gate 		return( LBER_DEFAULT );
10550Sstevel@tonic-gate 	}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
10580Sstevel@tonic-gate 		return( (ber_uint_t) xbyte );
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	tagp = (char *) &tag;
10620Sstevel@tonic-gate 	tagp[0] = xbyte;
10630Sstevel@tonic-gate 	for ( i = 1; i < sizeof(ber_int_t); i++ ) {
10640Sstevel@tonic-gate 		if ( read_bytes( sb, &xbyte, 1 ) != 1 )
10650Sstevel@tonic-gate 			return( LBER_DEFAULT );
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 		tagp[i] = xbyte;
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 		if ( ! (xbyte & LBER_MORE_TAG_MASK) )
10700Sstevel@tonic-gate 			break;
10710Sstevel@tonic-gate 	}
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	/* tag too big! */
10740Sstevel@tonic-gate 	if ( i == sizeof(ber_int_t) )
10750Sstevel@tonic-gate 		return( LBER_DEFAULT );
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	/* want leading, not trailing 0's */
10780Sstevel@tonic-gate 	return( tag >> (sizeof(ber_int_t) - i - 1) );
10790Sstevel@tonic-gate }
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate /* Like ber_get_next, but from a byte buffer the caller already has. */
10820Sstevel@tonic-gate /* Bytes_Scanned returns the number of bytes we actually looked at in the buffer. */
10830Sstevel@tonic-gate /* ber_get_next_buffer is now implemented in terms of ber_get_next_buffer_ext */
10840Sstevel@tonic-gate /* and is here for backward compatibility.  This new function allows us to pass */
10850Sstevel@tonic-gate /* the Sockbuf structure along */
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate ber_uint_t
10880Sstevel@tonic-gate LDAP_CALL
ber_get_next_buffer(void * buffer,size_t buffer_size,ber_len_t * len,BerElement * ber,ber_uint_t * Bytes_Scanned)10890Sstevel@tonic-gate ber_get_next_buffer( void *buffer, size_t buffer_size, ber_len_t *len,
10900Sstevel@tonic-gate     BerElement *ber, ber_uint_t *Bytes_Scanned )
10910Sstevel@tonic-gate {
10920Sstevel@tonic-gate 	return (ber_get_next_buffer_ext( buffer, buffer_size, len, ber,
10930Sstevel@tonic-gate 		Bytes_Scanned, NULL));
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate ber_uint_t
10970Sstevel@tonic-gate LDAP_CALL
ber_get_next_buffer_ext(void * buffer,size_t buffer_size,ber_len_t * len,BerElement * ber,ber_uint_t * Bytes_Scanned,Sockbuf * sock)10980Sstevel@tonic-gate ber_get_next_buffer_ext( void *buffer, size_t buffer_size, ber_len_t *len,
10990Sstevel@tonic-gate     BerElement *ber, ber_uint_t *Bytes_Scanned, Sockbuf *sock )
11000Sstevel@tonic-gate {
11010Sstevel@tonic-gate 	ber_tag_t	tag = 0;
11020Sstevel@tonic-gate 	ber_len_t	netlen;
11030Sstevel@tonic-gate 	ber_uint_t	toread;
11040Sstevel@tonic-gate 	unsigned char	lc;
11050Sstevel@tonic-gate 	ssize_t		rc;
11060Sstevel@tonic-gate 	int		noctets, diff;
11070Sstevel@tonic-gate 	byte_buffer sb = {0};
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	/*
11110Sstevel@tonic-gate 	 * Any ber element looks like this: tag length contents.
11120Sstevel@tonic-gate 	 * Assuming everything's ok, we return the tag byte (we
11130Sstevel@tonic-gate 	 * can assume a single byte), return the length in len,
11140Sstevel@tonic-gate 	 * and the rest of the undecoded element in buf.
11150Sstevel@tonic-gate 	 *
11160Sstevel@tonic-gate 	 * Assumptions:
11170Sstevel@tonic-gate 	 *	1) small tags (less than 128)
11180Sstevel@tonic-gate 	 *	2) definite lengths
11190Sstevel@tonic-gate 	 *	3) primitive encodings used whenever possible
11200Sstevel@tonic-gate 	 */
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	/*
11230Sstevel@tonic-gate 	 * first time through - malloc the buffer, set up ptrs, and
11240Sstevel@tonic-gate 	 * read the tag and the length and as much of the rest as we can
11250Sstevel@tonic-gate 	 */
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	sb.p = buffer;
11280Sstevel@tonic-gate 	sb.length = buffer_size;
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	if ( ber->ber_rwptr == NULL ) {
11310Sstevel@tonic-gate 		/*
11320Sstevel@tonic-gate 		 * First, we read the tag.
11330Sstevel@tonic-gate 		 */
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 		if ( (tag = get_buffer_tag( &sb )) == LBER_DEFAULT ) {
11360Sstevel@tonic-gate 			goto premature_exit;
11370Sstevel@tonic-gate 		}
11380Sstevel@tonic-gate 		ber->ber_tag = tag;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 		/*
11410Sstevel@tonic-gate 		 * Next, read the length.  The first byte contains the length
11420Sstevel@tonic-gate 		 * of the length.  If bit 8 is set, the length is the long
11430Sstevel@tonic-gate 		 * form, otherwise it's the short form.  We don't allow a
11440Sstevel@tonic-gate 		 * length that's greater than what we can hold in an unsigned
11450Sstevel@tonic-gate 		 * long.
11460Sstevel@tonic-gate 		 */
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 		*len = netlen = 0;
11490Sstevel@tonic-gate 		if ( read_bytes( &sb, &lc, 1 ) != 1 ) {
11500Sstevel@tonic-gate 			goto premature_exit;
11510Sstevel@tonic-gate 		}
11520Sstevel@tonic-gate 		if ( lc & 0x80 ) {
11530Sstevel@tonic-gate 			noctets = (lc & 0x7f);
11540Sstevel@tonic-gate 			if ( noctets > sizeof(ber_uint_t) )
11550Sstevel@tonic-gate 				goto premature_exit;
11560Sstevel@tonic-gate 			diff = sizeof(ber_uint_t) - noctets;
11570Sstevel@tonic-gate 			if ( read_bytes( &sb, (unsigned char *)&netlen + diff,
11580Sstevel@tonic-gate 			    noctets ) != noctets ) {
11590Sstevel@tonic-gate 				goto premature_exit;
11600Sstevel@tonic-gate 			}
11610Sstevel@tonic-gate 			*len = LBER_NTOHL( netlen );
11620Sstevel@tonic-gate 		} else {
11630Sstevel@tonic-gate 			*len = lc;
11640Sstevel@tonic-gate 		}
11650Sstevel@tonic-gate 		ber->ber_len = *len;
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 		/*
11680Sstevel@tonic-gate 		 * Finally, malloc a buffer for the contents and read it in.
11690Sstevel@tonic-gate 		 * It's this buffer that's passed to all the other ber decoding
11700Sstevel@tonic-gate 		 * routines.
11710Sstevel@tonic-gate 		 */
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate #if defined( DOS ) && !defined( _WIN32 )
11740Sstevel@tonic-gate 		if ( *len > 65535 ) {	/* DOS can't allocate > 64K */
11750Sstevel@tonic-gate 			goto premature_exit;
11760Sstevel@tonic-gate 		}
11770Sstevel@tonic-gate #endif /* DOS && !_WIN32 */
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate                 if ( (sock != NULL)  &&
11800Sstevel@tonic-gate 		    ( sock->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
11810Sstevel@tonic-gate                     && (*len > sock->sb_max_incoming) ) {
11820Sstevel@tonic-gate                         return( LBER_DEFAULT );
11830Sstevel@tonic-gate                 }
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 		if ( ber->ber_buf + *len > ber->ber_end ) {
11860Sstevel@tonic-gate 			if ( nslberi_ber_realloc( ber, *len ) != 0 )
11870Sstevel@tonic-gate 				goto premature_exit;
11880Sstevel@tonic-gate 		}
11890Sstevel@tonic-gate 		ber->ber_ptr = ber->ber_buf;
11900Sstevel@tonic-gate 		ber->ber_end = ber->ber_buf + *len;
11910Sstevel@tonic-gate 		ber->ber_rwptr = ber->ber_buf;
11920Sstevel@tonic-gate 	}
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	toread = (uintptr_t)ber->ber_end - (uintptr_t)ber->ber_rwptr;
11950Sstevel@tonic-gate 	do {
11960Sstevel@tonic-gate 		if ( (rc = read_bytes( &sb, (unsigned char *)ber->ber_rwptr,
11970Sstevel@tonic-gate 		    (ber_int_t)toread )) <= 0 ) {
11980Sstevel@tonic-gate 			goto premature_exit;
11990Sstevel@tonic-gate 		}
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 		toread -= rc;
12020Sstevel@tonic-gate 		ber->ber_rwptr += rc;
12030Sstevel@tonic-gate 	} while ( toread > 0 );
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 	*len = ber->ber_len;
12060Sstevel@tonic-gate 	*Bytes_Scanned = sb.offset;
12070Sstevel@tonic-gate 	return( ber->ber_tag );
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate premature_exit:
12100Sstevel@tonic-gate 	/*
12110Sstevel@tonic-gate 	 * we're here because we hit the end of the buffer before seeing
12120Sstevel@tonic-gate 	 * all of the PDU
12130Sstevel@tonic-gate 	 */
12140Sstevel@tonic-gate 	*Bytes_Scanned = sb.offset;
12150Sstevel@tonic-gate 	return(LBER_DEFAULT);
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate /* The ber_flatten routine allocates a struct berval whose contents
12200Sstevel@tonic-gate  * are a BER encoding taken from the ber argument. The bvPtr pointer
12210Sstevel@tonic-gate  * points to the returned berval, which must be freed using
12220Sstevel@tonic-gate  * ber_bvfree().  This routine returns 0 on success and -1 on error.
12230Sstevel@tonic-gate  * The use of ber_flatten on a BerElement in which all '{' and '}'
12240Sstevel@tonic-gate  * format modifiers have not been properly matched can result in a
12250Sstevel@tonic-gate  * berval whose contents are not a valid BER encoding.
12260Sstevel@tonic-gate  * Note that the ber_ptr is not modified.
12270Sstevel@tonic-gate  */
12280Sstevel@tonic-gate int
12290Sstevel@tonic-gate LDAP_CALL
ber_flatten(BerElement * ber,struct berval ** bvPtr)12300Sstevel@tonic-gate ber_flatten( BerElement *ber, struct berval **bvPtr )
12310Sstevel@tonic-gate {
12320Sstevel@tonic-gate 	struct berval *new;
12330Sstevel@tonic-gate 	ber_len_t len;
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	/* allocate a struct berval */
12360Sstevel@tonic-gate 	if ( (new = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
12370Sstevel@tonic-gate 	    == NULL ) {
12380Sstevel@tonic-gate 		return( -1 );
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	/*
12420Sstevel@tonic-gate 	 * Copy everything from the BerElement's ber_buf to ber_ptr
12430Sstevel@tonic-gate 	 * into the berval structure.
12440Sstevel@tonic-gate 	 */
12450Sstevel@tonic-gate 	if ( ber == NULL ) {
12460Sstevel@tonic-gate 	    new->bv_val = NULL;
12470Sstevel@tonic-gate 	    new->bv_len = 0;
12480Sstevel@tonic-gate 	} else {
12490Sstevel@tonic-gate  	    len = ber->ber_ptr - ber->ber_buf;
12500Sstevel@tonic-gate 	    if ( ( new->bv_val = (char *)NSLBERI_MALLOC( len + 1 )) == NULL ) {
12510Sstevel@tonic-gate 		    ber_bvfree( new );
12520Sstevel@tonic-gate 		    return( -1 );
12530Sstevel@tonic-gate 	    }
12540Sstevel@tonic-gate  	    SAFEMEMCPY( new->bv_val, ber->ber_buf, (size_t)len );
12550Sstevel@tonic-gate 	    new->bv_val[len] = '\0';
12560Sstevel@tonic-gate 	    new->bv_len = len;
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	/* set bvPtr pointer to point to the returned berval */
12600Sstevel@tonic-gate   	*bvPtr = new;
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate         return( 0 );
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate /*
12670Sstevel@tonic-gate  * The ber_init function constructs and returns a new BerElement
12680Sstevel@tonic-gate  * containing a copy of the data in the bv argument.  ber_init
12690Sstevel@tonic-gate  * returns the null pointer on error.
12700Sstevel@tonic-gate  */
12710Sstevel@tonic-gate BerElement *
12720Sstevel@tonic-gate LDAP_CALL
ber_init(const struct berval * bv)12730Sstevel@tonic-gate ber_init( const struct berval *bv )
12740Sstevel@tonic-gate {
12750Sstevel@tonic-gate 	BerElement *ber;
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 	/* construct BerElement */
12780Sstevel@tonic-gate 	if (( ber = ber_alloc_t( 0 )) != NULLBER ) {
12790Sstevel@tonic-gate 		/* copy data from the bv argument into BerElement */
12800Sstevel@tonic-gate 		/* XXXmcs: had to cast unsigned long bv_len to long */
12810Sstevel@tonic-gate 		if ( (ber_write ( ber, bv->bv_val, bv->bv_len, 0 ))
12820Sstevel@tonic-gate 		    != (ber_slen_t)bv->bv_len ) {
12830Sstevel@tonic-gate 			ber_free( ber, 1 );
12840Sstevel@tonic-gate 			return( NULL );
12850Sstevel@tonic-gate 		}
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	/*
12890Sstevel@tonic-gate 	 * reset ber_ptr back to the beginning of buffer so that this new
12900Sstevel@tonic-gate 	 * and initialized ber element can be READ
12910Sstevel@tonic-gate 	 */
12920Sstevel@tonic-gate 	ber_reset( ber, 1);
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 	/*
12950Sstevel@tonic-gate 	 * return a ptr to a new BerElement containing a copy of the data
12960Sstevel@tonic-gate 	 * in the bv argument or a null pointer on error
12970Sstevel@tonic-gate 	 */
12980Sstevel@tonic-gate 	return( ber );
12990Sstevel@tonic-gate }
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate /*
13030Sstevel@tonic-gate  * memory allocation functions.
13040Sstevel@tonic-gate  */
13050Sstevel@tonic-gate void *
nslberi_malloc(size_t size)13060Sstevel@tonic-gate nslberi_malloc( size_t size )
13070Sstevel@tonic-gate {
13080Sstevel@tonic-gate 	return( nslberi_memalloc_fns.lbermem_malloc == NULL ?
13090Sstevel@tonic-gate 	    malloc( size ) :
13100Sstevel@tonic-gate 	    nslberi_memalloc_fns.lbermem_malloc( size ));
13110Sstevel@tonic-gate }
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate void *
nslberi_calloc(size_t nelem,size_t elsize)13150Sstevel@tonic-gate nslberi_calloc( size_t nelem, size_t elsize )
13160Sstevel@tonic-gate {
13170Sstevel@tonic-gate 	return( nslberi_memalloc_fns.lbermem_calloc == NULL ?
13180Sstevel@tonic-gate 	    calloc(  nelem, elsize ) :
13190Sstevel@tonic-gate 	    nslberi_memalloc_fns.lbermem_calloc( nelem, elsize ));
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate void *
nslberi_realloc(void * ptr,size_t size)13240Sstevel@tonic-gate nslberi_realloc( void *ptr, size_t size )
13250Sstevel@tonic-gate {
13260Sstevel@tonic-gate 	return( nslberi_memalloc_fns.lbermem_realloc == NULL ?
13270Sstevel@tonic-gate 	    realloc( ptr, size ) :
13280Sstevel@tonic-gate 	    nslberi_memalloc_fns.lbermem_realloc( ptr, size ));
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate void
nslberi_free(void * ptr)13330Sstevel@tonic-gate nslberi_free( void *ptr )
13340Sstevel@tonic-gate {
13350Sstevel@tonic-gate 	if ( nslberi_memalloc_fns.lbermem_free == NULL ) {
13360Sstevel@tonic-gate 		free( ptr );
13370Sstevel@tonic-gate 	} else {
13380Sstevel@tonic-gate 		nslberi_memalloc_fns.lbermem_free( ptr );
13390Sstevel@tonic-gate 	}
13400Sstevel@tonic-gate }
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate /*
13440Sstevel@tonic-gate  ******************************************************************************
13450Sstevel@tonic-gate  * functions to bridge the gap between new extended I/O functions that are
13460Sstevel@tonic-gate  *    installed using ber_sockbuf_set_option( ..., LBER_SOCKBUF_OPT_EXT_IO_FNS,
13470Sstevel@tonic-gate  *    ... ).
13480Sstevel@tonic-gate  *
13490Sstevel@tonic-gate  * the basic strategy is to use the new extended arg to hold a pointer to the
13500Sstevel@tonic-gate  *    Sockbuf itself so we can find the old functions and call them.
13510Sstevel@tonic-gate  * note that the integer socket s passed in is not used.  we use the sb_sd
13520Sstevel@tonic-gate  *    from the Sockbuf itself because it is the correct type.
13530Sstevel@tonic-gate  */
13540Sstevel@tonic-gate static int
nslberi_extread_compat(int s,void * buf,int len,struct lextiof_socket_private * arg)13550Sstevel@tonic-gate nslberi_extread_compat( int s, void *buf, int len,
13560Sstevel@tonic-gate 	struct lextiof_socket_private *arg )
13570Sstevel@tonic-gate {
13580Sstevel@tonic-gate 	Sockbuf	*sb = (Sockbuf *)arg;
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	return( sb->sb_io_fns.lbiof_read( sb->sb_sd, buf, len ));
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate static int
nslberi_extwrite_compat(int s,const void * buf,int len,struct lextiof_socket_private * arg)13650Sstevel@tonic-gate nslberi_extwrite_compat( int s, const void *buf, int len,
13660Sstevel@tonic-gate 	struct lextiof_socket_private *arg )
13670Sstevel@tonic-gate {
13680Sstevel@tonic-gate 	Sockbuf	*sb = (Sockbuf *)arg;
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 	return( sb->sb_io_fns.lbiof_write( sb->sb_sd, buf, len ));
13710Sstevel@tonic-gate }
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate /*
13750Sstevel@tonic-gate  * Install I/O compatiblity functions.  This can't fail.
13760Sstevel@tonic-gate  */
13770Sstevel@tonic-gate static void
nslberi_install_compat_io_fns(Sockbuf * sb)13780Sstevel@tonic-gate nslberi_install_compat_io_fns( Sockbuf *sb )
13790Sstevel@tonic-gate {
13800Sstevel@tonic-gate 	sb->sb_ext_io_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
13810Sstevel@tonic-gate 	sb->sb_ext_io_fns.lbextiofn_read = nslberi_extread_compat;
13820Sstevel@tonic-gate 	sb->sb_ext_io_fns.lbextiofn_write = nslberi_extwrite_compat;
13830Sstevel@tonic-gate 	sb->sb_ext_io_fns.lbextiofn_socket_arg = (void *)sb;
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate /*
13860Sstevel@tonic-gate  * end of compat I/O functions
13870Sstevel@tonic-gate  ******************************************************************************
13880Sstevel@tonic-gate  */
1389