1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
29 *
30 * The contents of this file are subject to the Netscape Public License
31 * Version 1.0 (the "NPL"); you may not use this file except in
32 * compliance with the NPL.  You may obtain a copy of the NPL at
33 * http://www.mozilla.org/NPL/
34 *
35 * Software distributed under the NPL is distributed on an "AS IS" basis,
36 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
37 * for the specific language governing rights and limitations under the
38 * NPL.
39 *
40 * The Initial Developer of this code under the NPL is Netscape
41 * Communications Corporation.  Portions created by Netscape are
42 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
43 * Reserved.
44 */
45
46/*
47 * Copyright (c) 1990 Regents of the University of Michigan.
48 * All rights reserved.
49 *
50 * Redistribution and use in source and binary forms are permitted
51 * provided that this notice is preserved and that due credit is given
52 * to the University of Michigan at Ann Arbor. The name of the University
53 * may not be used to endorse or promote products derived from this
54 * software without specific prior written permission. This software
55 * is provided ``as is'' without express or implied warranty.
56 */
57/* io.c - ber general i/o routines */
58
59#include "lber-int.h"
60
61#define bergetc( sb, len )    ( sb->sb_ber.ber_end > sb->sb_ber.ber_ptr ? \
62			  (unsigned char)*sb->sb_ber.ber_ptr++ : \
63			  ber_filbuf( sb, len ))
64
65# ifdef macintosh
66/*
67 * MacTCP/OpenTransport
68 */
69#  define read( s, b, l ) tcpread( s, 0, (unsigned char *)b, l, NULL )
70#  define MAX_WRITE	65535
71#  define BerWrite( sb, b, l )   tcpwrite( sb->sb_sd, (unsigned char *)(b), (l<MAX_WRITE)? l : MAX_WRITE )
72# else /* macintosh */
73#  if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2)
74/*
75 * 32-bit Windows Socket API (under Windows NT or Windows 95)
76 */
77#   define read( s, b, l )		recv( s, b, l, 0 )
78#   define BerWrite( s, b, l )	send( s->sb_sd, b, l, 0 )
79#  else /* _WIN32 */
80/*
81 * everything else (Unix/BSD 4.3 socket API)
82 */
83#   define BerWrite( sb, b, l )	write( sb->sb_sd, b, l )
84#   define udp_read( sb, b, l, al ) recvfrom(sb->sb_sd, (char *)b, l, 0, \
85		(struct sockaddr *)sb->sb_fromaddr, \
86		(al = sizeof(struct sockaddr), &al))
87#   define udp_write( sb, b, l ) sendto(sb->sb_sd, (char *)(b), l, 0, \
88		(struct sockaddr *)sb->sb_useaddr, sizeof(struct sockaddr))
89#  endif /* _WIN32 */
90# endif /* macintosh */
91
92#ifndef udp_read
93#define udp_read( sb, b, l, al )	CLDAP NOT SUPPORTED
94#define udp_write( sb, b, l )		CLDAP NOT SUPPORTED
95#endif /* udp_read */
96
97#define EXBUFSIZ	1024
98
99#ifdef LDAP_DEBUG
100int	lber_debug;
101#endif
102
103/*
104 * function prototypes
105 */
106static void nslberi_install_compat_io_fns( Sockbuf *sb );
107static int nslberi_extread_compat( int s, void *buf, int len,
108		struct lextiof_socket_private *arg );
109static int nslberi_extwrite_compat( int s, const void *buf, int len,
110		struct lextiof_socket_private *arg );
111
112
113/*
114 * internal global structure for memory allocation callback functions
115 */
116static struct lber_memalloc_fns nslberi_memalloc_fns;
117
118
119/*
120 * buffered read from "sb".
121 * returns value of first character read on success and -1 on error.
122 */
123static int
124ber_filbuf( Sockbuf *sb, ber_slen_t len )
125{
126	ssize_t	rc;
127#ifdef CLDAP
128	int	addrlen;
129#endif /* CLDAP */
130
131	if ( sb->sb_ber.ber_buf == NULL ) {
132		if ( (sb->sb_ber.ber_buf = (char *)NSLBERI_MALLOC(
133		    READBUFSIZ )) == NULL ) {
134			return( -1 );
135		}
136		sb->sb_ber.ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
137		sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf;
138		sb->sb_ber.ber_end = sb->sb_ber.ber_buf;
139	}
140
141	if ( sb->sb_naddr > 0 ) {
142#ifdef CLDAP
143		rc = udp_read(sb, sb->sb_ber.ber_buf, READBUFSIZ, addrlen );
144#ifdef LDAP_DEBUG
145		if ( lber_debug ) {
146			char msg[80];
147			sprintf( msg, "ber_filbuf udp_read %d bytes\n",
148				rc );
149			ber_err_print( msg );
150			if ( lber_debug > 1 && rc > 0 )
151				lber_bprint( sb->sb_ber.ber_buf, rc );
152		}
153#endif /* LDAP_DEBUG */
154#else /* CLDAP */
155		rc = -1;
156#endif /* CLDAP */
157	} else {
158		if ( sb->sb_ext_io_fns.lbextiofn_read != NULL ) {
159			rc = sb->sb_ext_io_fns.lbextiofn_read(
160			    sb->sb_sd, sb->sb_ber.ber_buf,
161			    ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
162			    && (len < READBUFSIZ)) ? len : READBUFSIZ,
163			    sb->sb_ext_io_fns.lbextiofn_socket_arg );
164		} else {
165			rc = read( sb->sb_sd, sb->sb_ber.ber_buf,
166			    ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
167			    && (len < READBUFSIZ)) ? len : READBUFSIZ );
168		}
169	}
170
171	if ( rc > 0 ) {
172		sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf + 1;
173		sb->sb_ber.ber_end = sb->sb_ber.ber_buf + rc;
174		return( (unsigned char)*sb->sb_ber.ber_buf );
175	}
176
177	return( -1 );
178}
179
180
181static ber_int_t
182BerRead( Sockbuf *sb, char *buf, ber_slen_t len )
183{
184	int		c;
185	ber_int_t	nread = 0;
186
187	while ( len > 0 ) {
188		if ( (c = bergetc( sb, len )) < 0 ) {
189			if ( nread > 0 )
190				break;
191			return( c );
192		}
193		*buf++ = c;
194		nread++;
195		len--;
196	}
197
198	return( nread );
199}
200
201
202/*
203 * Note: ber_read() only uses the ber_end and ber_ptr elements of ber.
204 * Functions like ber_get_tag(), ber_skip_tag, and ber_peek_tag() rely on
205 * that fact, so if this code is changed to use any additional elements of
206 * the ber structure, those functions will need to be changed as well.
207 */
208ber_int_t
209LDAP_CALL
210ber_read( BerElement *ber, char *buf, ber_len_t len )
211{
212	ber_len_t	actuallen;
213	ber_uint_t	nleft;
214
215	nleft = ber->ber_end - ber->ber_ptr;
216	actuallen = nleft < len ? nleft : len;
217
218	SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen );
219
220	ber->ber_ptr += actuallen;
221
222	return( (ber_int_t)actuallen );
223}
224
225/*
226 * enlarge the ber buffer.
227 * return 0 on success, -1 on error.
228 */
229int
230nslberi_ber_realloc( BerElement *ber, ber_len_t len )
231{
232	ber_uint_t	need, have, total;
233	size_t		have_bytes;
234	Seqorset	*s;
235	ber_int_t	off;
236	char		*oldbuf;
237
238	have_bytes = ber->ber_end - ber->ber_buf;
239	have = have_bytes / EXBUFSIZ;
240	need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
241	total = have * EXBUFSIZ + need * EXBUFSIZ;
242
243	oldbuf = ber->ber_buf;
244
245	if (ber->ber_buf == NULL) {
246		if ( (ber->ber_buf = (char *)NSLBERI_MALLOC( (size_t)total ))
247		    == NULL ) {
248			return( -1 );
249		}
250		ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
251	} else {
252		if ( ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER ) {
253			/* transition to malloc'd buffer */
254			if ( (ber->ber_buf = (char *)NSLBERI_MALLOC(
255			    (size_t)total )) == NULL ) {
256				return( -1 );
257			}
258			ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
259			/* copy existing data into new malloc'd buffer */
260			SAFEMEMCPY( ber->ber_buf, oldbuf, have_bytes );
261		} else {
262			if ( (ber->ber_buf = (char *)NSLBERI_REALLOC(
263			    ber->ber_buf,(size_t)total )) == NULL ) {
264				return( -1 );
265			}
266		}
267	}
268
269	ber->ber_end = ber->ber_buf + total;
270
271	/*
272	 * If the stinking thing was moved, we need to go through and
273	 * reset all the sos and ber pointers.  Offsets would've been
274	 * a better idea... oh well.
275	 */
276
277	if ( ber->ber_buf != oldbuf ) {
278		ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
279
280		for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) {
281			off = s->sos_first - oldbuf;
282			s->sos_first = ber->ber_buf + off;
283
284			off = s->sos_ptr - oldbuf;
285			s->sos_ptr = ber->ber_buf + off;
286		}
287	}
288
289	return( 0 );
290}
291
292/*
293 * returns "len" on success and -1 on failure.
294 */
295ber_int_t
296LDAP_CALL
297ber_write( BerElement *ber, char *buf, ber_len_t len, int nosos )
298{
299	if ( nosos || ber->ber_sos == NULL ) {
300		if ( ber->ber_ptr + len > ber->ber_end ) {
301			if ( nslberi_ber_realloc( ber, len ) != 0 )
302				return( -1 );
303		}
304		SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
305		ber->ber_ptr += len;
306		return( len );
307	} else {
308		if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
309			if ( nslberi_ber_realloc( ber, len ) != 0 )
310				return( -1 );
311		}
312		SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
313		ber->ber_sos->sos_ptr += len;
314		ber->ber_sos->sos_clen += len;
315		return( len );
316	}
317}
318
319void
320LDAP_CALL
321ber_free( BerElement *ber, int freebuf )
322{
323	if ( ber != NULL ) {
324		    if ( freebuf &&
325			!(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
326			    NSLBERI_FREE(ber->ber_buf);
327		    }
328		    NSLBERI_FREE( (char *) ber );
329	}
330}
331
332/*
333 * return >= 0 on success, -1 on failure.
334 */
335int
336LDAP_CALL
337ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
338{
339	ssize_t	nwritten, towrite, rc;
340
341	if ( ber->ber_rwptr == NULL ) {
342		ber->ber_rwptr = ber->ber_buf;
343	} else if (ber->ber_rwptr >= ber->ber_end) {
344          /* we will use the ber_rwptr to continue an exited flush,
345             so if rwptr is not within the buffer we return an error. */
346          return( -1 );
347        }
348	towrite = ber->ber_ptr - ber->ber_rwptr;
349
350#ifdef LDAP_DEBUG
351	if ( lber_debug ) {
352		char msg[80];
353		sprintf( msg, "ber_flush: %ld bytes to sd %ld%s\n", towrite,
354		    sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
355		    : "" );
356		ber_err_print( msg );
357		if ( lber_debug > 1 )
358			lber_bprint( ber->ber_rwptr, towrite );
359	}
360#endif
361#if !defined(macintosh) && !defined(DOS)
362	if ( sb->sb_options & (LBER_SOCKBUF_OPT_TO_FILE | LBER_SOCKBUF_OPT_TO_FILE_ONLY) ) {
363		rc = write( sb->sb_copyfd, ber->ber_buf, towrite );
364		if ( sb->sb_options & LBER_SOCKBUF_OPT_TO_FILE_ONLY ) {
365			return( (int)rc );
366		}
367	}
368#endif
369
370	nwritten = 0;
371	do {
372		if (sb->sb_naddr > 0) {
373#ifdef CLDAP
374			rc = udp_write( sb, ber->ber_buf + nwritten,
375			    (size_t)towrite );
376#else /* CLDAP */
377			rc = -1;
378#endif /* CLDAP */
379			if ( rc <= 0 )
380				return( -1 );
381			/* fake error if write was not atomic */
382			if (rc < towrite) {
383#if !defined( macintosh ) && !defined( DOS )
384			    errno = EMSGSIZE;  /* For Win32, see portable.h */
385#endif
386			    return( -1 );
387			}
388		} else {
389			if ( sb->sb_ext_io_fns.lbextiofn_write != NULL ) {
390				if ( (rc = sb->sb_ext_io_fns.lbextiofn_write(
391				    sb->sb_sd, ber->ber_rwptr, (size_t)towrite,
392				    sb->sb_ext_io_fns.lbextiofn_socket_arg ))
393				    <= 0 ) {
394					return( -1 );
395				}
396			} else {
397				if ( (rc = BerWrite( sb, ber->ber_rwptr,
398				    (size_t) towrite )) <= 0 ) {
399					return( -1 );
400				}
401			}
402		}
403		towrite -= rc;
404		nwritten += rc;
405		ber->ber_rwptr += rc;
406	} while ( towrite > 0 );
407
408	if ( freeit )
409		ber_free( ber, 1 );
410
411	return( 0 );
412}
413
414
415/* we pre-allocate a buffer to save the extra malloc later */
416BerElement *
417LDAP_CALL
418ber_alloc_t( int options )
419{
420	BerElement	*ber;
421
422	if ( (ber = (BerElement*)NSLBERI_CALLOC( 1,
423	    sizeof(struct berelement) + EXBUFSIZ )) == NULL ) {
424		return( NULL );
425	}
426
427	/*
428	 * for compatibility with the C LDAP API standard, we recognize
429	 * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
430	 */
431	if ( options & LBER_USE_DER ) {
432		options &= ~LBER_USE_DER;
433		options |= LBER_OPT_USE_DER;
434	}
435
436	ber->ber_tag = LBER_DEFAULT;
437	ber->ber_options = options;
438	ber->ber_buf = (char*)ber + sizeof(struct berelement);
439	ber->ber_ptr = ber->ber_buf;
440	ber->ber_end = ber->ber_buf + EXBUFSIZ;
441	ber->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
442
443	return( ber );
444}
445
446
447BerElement *
448LDAP_CALL
449ber_alloc()
450{
451	return( ber_alloc_t( 0 ) );
452}
453
454BerElement *
455LDAP_CALL
456der_alloc()
457{
458	return( ber_alloc_t( LBER_OPT_USE_DER ) );
459}
460
461BerElement *
462LDAP_CALL
463ber_dup( BerElement *ber )
464{
465	BerElement	*new;
466
467	if ( (new = ber_alloc()) == NULL )
468		return( NULL );
469
470	*new = *ber;
471
472	return( new );
473}
474
475
476void
477LDAP_CALL
478ber_init_w_nullchar( BerElement *ber, int options )
479{
480	(void) memset( (char *)ber, '\0', sizeof(struct berelement) );
481	ber->ber_tag = LBER_DEFAULT;
482
483	/*
484	 * For compatibility with the C LDAP API standard, we recognize
485	 * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
486	 */
487	if ( options & LBER_USE_DER ) {
488		options &= ~LBER_USE_DER;
489		options |= LBER_OPT_USE_DER;
490	}
491
492	ber->ber_options = options;
493}
494
495
496void
497LDAP_CALL
498ber_reset( BerElement *ber, int was_writing )
499{
500	if ( was_writing ) {
501		ber->ber_end = ber->ber_ptr;
502		ber->ber_ptr = ber->ber_buf;
503	} else {
504		ber->ber_ptr = ber->ber_end;
505	}
506
507	ber->ber_rwptr = NULL;
508}
509
510
511#ifdef LDAP_DEBUG
512
513void
514ber_dump( BerElement *ber, int inout )
515{
516	char msg[128];
517	sprintf( msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
518	    ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end );
519	ber_err_print( msg );
520	if ( inout == 1 ) {
521		sprintf( msg, "          current len %ld, contents:\n",
522		    ber->ber_end - ber->ber_ptr );
523		ber_err_print( msg );
524		lber_bprint( ber->ber_ptr, ber->ber_end - ber->ber_ptr );
525	} else {
526		sprintf( msg, "          current len %ld, contents:\n",
527		    ber->ber_ptr - ber->ber_buf );
528		ber_err_print( msg );
529		lber_bprint( ber->ber_buf, ber->ber_ptr - ber->ber_buf );
530	}
531}
532
533void
534ber_sos_dump( Seqorset *sos )
535{
536	char msg[80];
537	ber_err_print ( "*** sos dump ***\n" );
538	while ( sos != NULLSEQORSET ) {
539		sprintf( msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
540		    sos->sos_clen, sos->sos_first, sos->sos_ptr );
541		ber_err_print( msg );
542		sprintf( msg, "              current len %ld contents:\n",
543		    sos->sos_ptr - sos->sos_first );
544		ber_err_print( msg );
545		lber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first );
546
547		sos = sos->sos_next;
548	}
549	ber_err_print( "*** end dump ***\n" );
550}
551
552#endif
553
554/* return the tag - LBER_DEFAULT returned means trouble */
555static ber_tag_t
556get_tag( Sockbuf *sb )
557{
558	unsigned char	xbyte;
559	ber_tag_t	tag;
560	char		*tagp;
561	int		i;
562
563	if ( (i = BerRead( sb, (char *) &xbyte, 1 )) != 1 ) {
564		return( LBER_DEFAULT );
565	}
566
567	if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
568		return( (ber_uint_t) xbyte );
569	}
570
571	tagp = (char *) &tag;
572	tagp[0] = xbyte;
573	for ( i = 1; i < sizeof(ber_int_t); i++ ) {
574		if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 )
575			return( LBER_DEFAULT );
576
577		tagp[i] = xbyte;
578
579		if ( ! (xbyte & LBER_MORE_TAG_MASK) )
580			break;
581	}
582
583	/* tag too big! */
584	if ( i == sizeof(ber_int_t) )
585		return( LBER_DEFAULT );
586
587	/* want leading, not trailing 0's */
588	return( tag >> (sizeof(ber_int_t) - i - 1) );
589}
590
591ber_tag_t
592LDAP_CALL
593ber_get_next( Sockbuf *sb, ber_len_t *len, BerElement *ber )
594{
595	ber_tag_t	tag = 0;
596	ber_len_t	netlen;
597	ber_uint_t	 toread;
598	unsigned char	lc;
599	ber_int_t	rc;
600	int		noctets, diff;
601
602#ifdef LDAP_DEBUG
603	if ( lber_debug )
604		ber_err_print( "ber_get_next\n" );
605#endif
606
607	/*
608	 * Any ber element looks like this: tag length contents.
609	 * Assuming everything's ok, we return the tag byte (we
610	 * can assume a single byte), return the length in len,
611	 * and the rest of the undecoded element in buf.
612	 *
613	 * Assumptions:
614	 *	1) small tags (less than 128)
615	 *	2) definite lengths
616	 *	3) primitive encodings used whenever possible
617	 */
618
619	/*
620	 * first time through - malloc the buffer, set up ptrs, and
621	 * read the tag and the length and as much of the rest as we can
622	 */
623
624	if ( ber->ber_rwptr == NULL ) {
625		/*
626		 * First, we read the tag.
627		 */
628
629		if ( (tag = get_tag( sb )) == LBER_DEFAULT ) {
630			return( LBER_DEFAULT );
631		}
632		ber->ber_tag = tag;
633
634		/*
635		 * Next, read the length.  The first byte contains the length
636		 * of the length.  If bit 8 is set, the length is the long
637		 * form, otherwise it's the short form.  We don't allow a
638		 * length that's greater than what we can hold in an unsigned
639		 * long.
640		 */
641
642		*len = netlen = 0;
643		if ( BerRead( sb, (char *) &lc, 1 ) != 1 ) {
644			return( LBER_DEFAULT );
645		}
646		if ( lc & 0x80 ) {
647			noctets = (lc & 0x7f);
648			if ( noctets > sizeof(ber_uint_t) )
649				return( LBER_DEFAULT );
650			diff = sizeof(ber_uint_t) - noctets;
651			if ( BerRead( sb, (char *) &netlen + diff, noctets ) !=
652			    noctets ) {
653				return( LBER_DEFAULT );
654			}
655			*len = LBER_NTOHL( netlen );
656		} else {
657			*len = lc;
658		}
659		ber->ber_len = *len;
660
661		/*
662		 * Finally, malloc a buffer for the contents and read it in.
663		 * It's this buffer that's passed to all the other ber decoding
664		 * routines.
665		 */
666
667#if defined( DOS ) && !( defined( _WIN32 ) || defined(XP_OS2) )
668		if ( *len > 65535 ) {	/* DOS can't allocate > 64K */
669		    return( LBER_DEFAULT );
670		}
671#endif /* DOS && !_WIN32 */
672
673		if ( ( sb->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
674		    && *len > sb->sb_max_incoming ) {
675			return( LBER_DEFAULT );
676		}
677
678		if ( (ber->ber_buf = (char *)NSLBERI_CALLOC( 1,(size_t)*len ))
679		    == NULL ) {
680			return( LBER_DEFAULT );
681		}
682		ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
683		ber->ber_ptr = ber->ber_buf;
684		ber->ber_end = ber->ber_buf + *len;
685		ber->ber_rwptr = ber->ber_buf;
686	}
687
688	toread = (uintptr_t)ber->ber_end - (uintptr_t)ber->ber_rwptr;
689	do {
690		if ( (rc = BerRead( sb, ber->ber_rwptr, (ber_int_t)toread )) <= 0 ) {
691			return( LBER_DEFAULT );
692		}
693
694		toread -= rc;
695		ber->ber_rwptr += rc;
696	} while ( toread > 0 );
697
698#ifdef LDAP_DEBUG
699	if ( lber_debug ) {
700		char msg[80];
701		sprintf( msg, "ber_get_next: tag 0x%lx len %ld contents:\n",
702		    tag, ber->ber_len );
703		ber_err_print( msg );
704		if ( lber_debug > 1 )
705			ber_dump( ber, 1 );
706	}
707#endif
708
709	*len = ber->ber_len;
710	ber->ber_rwptr = NULL;
711	return( ber->ber_tag );
712}
713
714Sockbuf *
715LDAP_CALL
716ber_sockbuf_alloc()
717{
718	return( (Sockbuf *)NSLBERI_CALLOC( 1, sizeof(struct sockbuf) ) );
719}
720
721void
722LDAP_CALL
723ber_sockbuf_free(Sockbuf *p)
724{
725	if ( p != NULL ) {
726#ifdef LDAP_SASLIO_HOOKS
727		if ( p->sb_sasl_ctx != NULL)
728        		sasl_dispose(&p->sb_sasl_ctx);
729		if ( p->sb_sasl_ibuf != NULL) {
730			NSLBERI_FREE( p->sb_sasl_ibuf );
731		}
732#endif
733		if ( p->sb_ber.ber_buf != NULL &&
734		    !(p->sb_ber.ber_flags & LBER_FLAG_NO_FREE_BUFFER) ) {
735			NSLBERI_FREE( p->sb_ber.ber_buf );
736		}
737		NSLBERI_FREE(p);
738	}
739}
740
741/*
742 * return 0 on success and -1 on error
743 */
744int
745LDAP_CALL
746ber_set_option( struct berelement *ber, int option, void *value )
747{
748
749  /*
750   * memory allocation callbacks are global, so it is OK to pass
751   * NULL for ber.  Handle this as a special case.
752   */
753  if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
754    /* struct copy */
755    nslberi_memalloc_fns = *((struct lber_memalloc_fns *)value);
756    return( 0 );
757  }
758
759  /*
760   * lber_debug is global, so it is OK to pass
761   * NULL for ber.  Handle this as a special case.
762   */
763  if ( option == LBER_OPT_DEBUG_LEVEL ) {
764#ifdef LDAP_DEBUG
765    lber_debug = *(int *)value;
766#endif
767    return( 0 );
768  }
769
770  /*
771   * all the rest require a non-NULL ber
772   */
773  if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
774    return( -1 );
775  }
776
777  switch ( option ) {
778	case LBER_OPT_USE_DER:
779	case LBER_OPT_TRANSLATE_STRINGS:
780		if ( value != NULL ) {
781			ber->ber_options |= option;
782		} else {
783			ber->ber_options &= ~option;
784		}
785		break;
786	case LBER_OPT_REMAINING_BYTES:
787		ber->ber_end = ber->ber_ptr + *((ber_uint_t *)value);
788		break;
789	case LBER_OPT_TOTAL_BYTES:
790		ber->ber_end = ber->ber_buf + *((ber_uint_t *)value);
791		break;
792	case LBER_OPT_BYTES_TO_WRITE:
793		ber->ber_ptr = ber->ber_buf + *((ber_uint_t *)value);
794		break;
795	default:
796		return( -1 );
797  }
798
799  return( 0 );
800}
801
802/*
803 * return 0 on success and -1 on error
804 */
805int
806LDAP_CALL
807ber_get_option( struct berelement *ber, int option, void *value )
808{
809	/*
810	 * memory callocation callbacks are global, so it is OK to pass
811	 * NULL for ber.  Handle this as a special case
812	 */
813	if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
814		/* struct copy */
815		*((struct lber_memalloc_fns *)value) = nslberi_memalloc_fns;
816		return( 0 );
817	}
818
819	/*
820	 * lber_debug is global, so it is OK to pass
821	 * NULL for ber.  Handle this as a special case.
822	 */
823	if ( option == LBER_OPT_DEBUG_LEVEL ) {
824#ifdef LDAP_DEBUG
825	 *(int *)value =  lber_debug;
826#endif
827	  return( 0 );
828	}
829	/*
830	 * all the rest require a non-NULL ber
831	 */
832	if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
833		return( -1 );
834	}
835
836	switch ( option ) {
837	case LBER_OPT_USE_DER:
838	case LBER_OPT_TRANSLATE_STRINGS:
839		*((int *) value) = (ber->ber_options & option);
840		break;
841	case LBER_OPT_REMAINING_BYTES:
842		*((ber_uint_t *) value) = ber->ber_end - ber->ber_ptr;
843		break;
844	case LBER_OPT_TOTAL_BYTES:
845		*((ber_uint_t *) value) = ber->ber_end - ber->ber_buf;
846		break;
847	case LBER_OPT_BYTES_TO_WRITE:
848		*((ber_uint_t *) value) = ber->ber_ptr - ber->ber_buf;
849		break;
850	default:
851		return( -1 );
852	}
853
854	return( 0 );
855}
856
857/*
858 * return 0 on success and -1 on error
859 */
860int
861LDAP_CALL
862ber_sockbuf_set_option( Sockbuf *sb, int option, void *value )
863{
864	struct lber_x_ext_io_fns	*extiofns;
865
866	if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
867		return( -1 );
868	}
869
870	switch ( option ) {
871	case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
872		sb->sb_max_incoming = *((ber_uint_t *) value);
873		/* FALL */
874	case LBER_SOCKBUF_OPT_TO_FILE:
875	case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
876	case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
877		if ( value != NULL ) {
878			sb->sb_options |= option;
879		} else {
880			sb->sb_options &= ~option;
881		}
882		break;
883	case LBER_SOCKBUF_OPT_DESC:
884		sb->sb_sd = *((LBER_SOCKET *) value);
885		break;
886	case LBER_SOCKBUF_OPT_COPYDESC:
887		sb->sb_copyfd = *((LBER_SOCKET *) value);
888		break;
889	case LBER_SOCKBUF_OPT_READ_FN:
890		sb->sb_io_fns.lbiof_read = (LDAP_IOF_READ_CALLBACK *) value;
891		nslberi_install_compat_io_fns( sb );
892		break;
893	case LBER_SOCKBUF_OPT_WRITE_FN:
894		sb->sb_io_fns.lbiof_write = (LDAP_IOF_WRITE_CALLBACK *) value;
895		nslberi_install_compat_io_fns( sb );
896		break;
897	case LBER_SOCKBUF_OPT_EXT_IO_FNS:
898		extiofns = (struct lber_x_ext_io_fns *) value;
899		if ( extiofns == NULL ) {	/* remove */
900			(void)memset( (char *)&sb->sb_ext_io_fns, '\0',
901				sizeof(sb->sb_ext_io_fns ));
902		} else if ( extiofns->lbextiofn_size
903		    == LBER_X_EXTIO_FNS_SIZE ) {
904			/* struct copy */
905			sb->sb_ext_io_fns = *extiofns;
906		} else {
907			return( -1 );
908		}
909		break;
910	default:
911		return( -1 );
912	}
913
914	return( 0 );
915}
916
917/*
918 * return 0 on success and -1 on error
919 */
920int
921LDAP_CALL
922ber_sockbuf_get_option( Sockbuf *sb, int option, void *value )
923{
924	struct lber_x_ext_io_fns	*extiofns;
925
926	if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
927		return( -1 );
928	}
929
930	switch ( option ) {
931	case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
932		*((ber_uint_t *) value) = sb->sb_max_incoming;
933		break;
934	case LBER_SOCKBUF_OPT_TO_FILE:
935	case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
936	case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
937		*((int *) value) = (sb->sb_options & option);
938		break;
939	case LBER_SOCKBUF_OPT_DESC:
940		*((LBER_SOCKET *) value) = sb->sb_sd;
941		break;
942	case LBER_SOCKBUF_OPT_COPYDESC:
943		*((LBER_SOCKET *) value) = sb->sb_copyfd;
944		break;
945	case LBER_SOCKBUF_OPT_READ_FN:
946		*((LDAP_IOF_READ_CALLBACK **) value)
947		    = sb->sb_io_fns.lbiof_read;
948		break;
949	case LBER_SOCKBUF_OPT_WRITE_FN:
950		*((LDAP_IOF_WRITE_CALLBACK **) value)
951		    = sb->sb_io_fns.lbiof_write;
952		break;
953	case LBER_SOCKBUF_OPT_EXT_IO_FNS:
954		extiofns = (struct lber_x_ext_io_fns *) value;
955		if ( extiofns == NULL || extiofns->lbextiofn_size
956		    != LBER_X_EXTIO_FNS_SIZE ) {
957			return( -1 );
958		}
959		/* struct copy */
960		*extiofns = sb->sb_ext_io_fns;
961		break;
962	default:
963		return( -1 );
964	}
965
966	return( 0 );
967}
968
969
970/* new dboreham code below: */
971
972struct byte_buffer  {
973	unsigned char *p;
974	int offset;
975	int length;
976};
977typedef struct byte_buffer byte_buffer;
978
979
980/* This call allocates us a BerElement structure plus some extra memory.
981 * It returns a pointer to the BerElement, plus a pointer to the extra memory.
982 * This routine also allocates a ber data buffer within the same block, thus
983 * saving a call to calloc later when we read data.
984 */
985void*
986LDAP_CALL
987ber_special_alloc(size_t size, BerElement **ppBer)
988{
989	char *mem = NULL;
990
991	/* Make sure mem size requested is aligned */
992	if (0 != ( size & 0x03 )) {
993		size += (sizeof(ber_int_t) - (size & 0x03));
994	}
995
996	mem = NSLBERI_MALLOC(sizeof(struct berelement) + EXBUFSIZ + size );
997	if (NULL == mem) {
998		return NULL;
999	}
1000	*ppBer = (BerElement*) (mem + size);
1001	memset(*ppBer,0,sizeof(struct berelement));
1002	(*ppBer)->ber_tag = LBER_DEFAULT;
1003	(*ppBer)->ber_buf = mem + size + sizeof(struct berelement);
1004	(*ppBer)->ber_ptr = (*ppBer)->ber_buf;
1005	(*ppBer)->ber_end = (*ppBer)->ber_buf + EXBUFSIZ;
1006	(*ppBer)->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
1007	return (void*)mem;
1008}
1009
1010void
1011LDAP_CALL
1012ber_special_free(void* buf, BerElement *ber)
1013{
1014	if (!(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
1015		NSLBERI_FREE(ber->ber_buf);
1016	}
1017	NSLBERI_FREE( buf );
1018}
1019
1020static int
1021read_bytes(byte_buffer *b, unsigned char *return_buffer, int bytes_to_read)
1022{
1023	/* copy up to bytes_to_read bytes into the caller's buffer, return the number of bytes copied */
1024	int bytes_to_copy = 0;
1025
1026	if (bytes_to_read <= (b->length - b->offset) ) {
1027		bytes_to_copy = bytes_to_read;
1028	} else {
1029		bytes_to_copy = (b->length - b->offset);
1030	}
1031	if (1 == bytes_to_copy) {
1032		*return_buffer = *(b->p+b->offset++);
1033	} else
1034	if (0 == bytes_to_copy) {
1035		;
1036	} else
1037	{
1038		memcpy(return_buffer,b->p+b->offset,bytes_to_copy);
1039		b->offset += bytes_to_copy;
1040	}
1041	return bytes_to_copy;
1042}
1043
1044/* return the tag - LBER_DEFAULT returned means trouble */
1045static ber_tag_t
1046get_buffer_tag(byte_buffer *sb )
1047{
1048	unsigned char	xbyte;
1049	ber_tag_t	tag;
1050	char		*tagp;
1051	int		i;
1052
1053	if ( (i = read_bytes( sb, &xbyte, 1 )) != 1 ) {
1054		return( LBER_DEFAULT );
1055	}
1056
1057	if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
1058		return( (ber_uint_t) xbyte );
1059	}
1060
1061	tagp = (char *) &tag;
1062	tagp[0] = xbyte;
1063	for ( i = 1; i < sizeof(ber_int_t); i++ ) {
1064		if ( read_bytes( sb, &xbyte, 1 ) != 1 )
1065			return( LBER_DEFAULT );
1066
1067		tagp[i] = xbyte;
1068
1069		if ( ! (xbyte & LBER_MORE_TAG_MASK) )
1070			break;
1071	}
1072
1073	/* tag too big! */
1074	if ( i == sizeof(ber_int_t) )
1075		return( LBER_DEFAULT );
1076
1077	/* want leading, not trailing 0's */
1078	return( tag >> (sizeof(ber_int_t) - i - 1) );
1079}
1080
1081/* Like ber_get_next, but from a byte buffer the caller already has. */
1082/* Bytes_Scanned returns the number of bytes we actually looked at in the buffer. */
1083/* ber_get_next_buffer is now implemented in terms of ber_get_next_buffer_ext */
1084/* and is here for backward compatibility.  This new function allows us to pass */
1085/* the Sockbuf structure along */
1086
1087ber_uint_t
1088LDAP_CALL
1089ber_get_next_buffer( void *buffer, size_t buffer_size, ber_len_t *len,
1090    BerElement *ber, ber_uint_t *Bytes_Scanned )
1091{
1092	return (ber_get_next_buffer_ext( buffer, buffer_size, len, ber,
1093		Bytes_Scanned, NULL));
1094}
1095
1096ber_uint_t
1097LDAP_CALL
1098ber_get_next_buffer_ext( void *buffer, size_t buffer_size, ber_len_t *len,
1099    BerElement *ber, ber_uint_t *Bytes_Scanned, Sockbuf *sock )
1100{
1101	ber_tag_t	tag = 0;
1102	ber_len_t	netlen;
1103	ber_uint_t	toread;
1104	unsigned char	lc;
1105	ssize_t		rc;
1106	int		noctets, diff;
1107	byte_buffer sb = {0};
1108
1109
1110	/*
1111	 * Any ber element looks like this: tag length contents.
1112	 * Assuming everything's ok, we return the tag byte (we
1113	 * can assume a single byte), return the length in len,
1114	 * and the rest of the undecoded element in buf.
1115	 *
1116	 * Assumptions:
1117	 *	1) small tags (less than 128)
1118	 *	2) definite lengths
1119	 *	3) primitive encodings used whenever possible
1120	 */
1121
1122	/*
1123	 * first time through - malloc the buffer, set up ptrs, and
1124	 * read the tag and the length and as much of the rest as we can
1125	 */
1126
1127	sb.p = buffer;
1128	sb.length = buffer_size;
1129
1130	if ( ber->ber_rwptr == NULL ) {
1131		/*
1132		 * First, we read the tag.
1133		 */
1134
1135		if ( (tag = get_buffer_tag( &sb )) == LBER_DEFAULT ) {
1136			goto premature_exit;
1137		}
1138		ber->ber_tag = tag;
1139
1140		/*
1141		 * Next, read the length.  The first byte contains the length
1142		 * of the length.  If bit 8 is set, the length is the long
1143		 * form, otherwise it's the short form.  We don't allow a
1144		 * length that's greater than what we can hold in an unsigned
1145		 * long.
1146		 */
1147
1148		*len = netlen = 0;
1149		if ( read_bytes( &sb, &lc, 1 ) != 1 ) {
1150			goto premature_exit;
1151		}
1152		if ( lc & 0x80 ) {
1153			noctets = (lc & 0x7f);
1154			if ( noctets > sizeof(ber_uint_t) )
1155				goto premature_exit;
1156			diff = sizeof(ber_uint_t) - noctets;
1157			if ( read_bytes( &sb, (unsigned char *)&netlen + diff,
1158			    noctets ) != noctets ) {
1159				goto premature_exit;
1160			}
1161			*len = LBER_NTOHL( netlen );
1162		} else {
1163			*len = lc;
1164		}
1165		ber->ber_len = *len;
1166
1167		/*
1168		 * Finally, malloc a buffer for the contents and read it in.
1169		 * It's this buffer that's passed to all the other ber decoding
1170		 * routines.
1171		 */
1172
1173#if defined( DOS ) && !defined( _WIN32 )
1174		if ( *len > 65535 ) {	/* DOS can't allocate > 64K */
1175			goto premature_exit;
1176		}
1177#endif /* DOS && !_WIN32 */
1178
1179                if ( (sock != NULL)  &&
1180		    ( sock->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
1181                    && (*len > sock->sb_max_incoming) ) {
1182                        return( LBER_DEFAULT );
1183                }
1184
1185		if ( ber->ber_buf + *len > ber->ber_end ) {
1186			if ( nslberi_ber_realloc( ber, *len ) != 0 )
1187				goto premature_exit;
1188		}
1189		ber->ber_ptr = ber->ber_buf;
1190		ber->ber_end = ber->ber_buf + *len;
1191		ber->ber_rwptr = ber->ber_buf;
1192	}
1193
1194	toread = (uintptr_t)ber->ber_end - (uintptr_t)ber->ber_rwptr;
1195	do {
1196		if ( (rc = read_bytes( &sb, (unsigned char *)ber->ber_rwptr,
1197		    (ber_int_t)toread )) <= 0 ) {
1198			goto premature_exit;
1199		}
1200
1201		toread -= rc;
1202		ber->ber_rwptr += rc;
1203	} while ( toread > 0 );
1204
1205	*len = ber->ber_len;
1206	*Bytes_Scanned = sb.offset;
1207	return( ber->ber_tag );
1208
1209premature_exit:
1210	/*
1211	 * we're here because we hit the end of the buffer before seeing
1212	 * all of the PDU
1213	 */
1214	*Bytes_Scanned = sb.offset;
1215	return(LBER_DEFAULT);
1216}
1217
1218
1219/* The ber_flatten routine allocates a struct berval whose contents
1220 * are a BER encoding taken from the ber argument. The bvPtr pointer
1221 * points to the returned berval, which must be freed using
1222 * ber_bvfree().  This routine returns 0 on success and -1 on error.
1223 * The use of ber_flatten on a BerElement in which all '{' and '}'
1224 * format modifiers have not been properly matched can result in a
1225 * berval whose contents are not a valid BER encoding.
1226 * Note that the ber_ptr is not modified.
1227 */
1228int
1229LDAP_CALL
1230ber_flatten( BerElement *ber, struct berval **bvPtr )
1231{
1232	struct berval *new;
1233	ber_len_t len;
1234
1235	/* allocate a struct berval */
1236	if ( (new = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
1237	    == NULL ) {
1238		return( -1 );
1239	}
1240
1241	/*
1242	 * Copy everything from the BerElement's ber_buf to ber_ptr
1243	 * into the berval structure.
1244	 */
1245	if ( ber == NULL ) {
1246	    new->bv_val = NULL;
1247	    new->bv_len = 0;
1248	} else {
1249 	    len = ber->ber_ptr - ber->ber_buf;
1250	    if ( ( new->bv_val = (char *)NSLBERI_MALLOC( len + 1 )) == NULL ) {
1251		    ber_bvfree( new );
1252		    return( -1 );
1253	    }
1254 	    SAFEMEMCPY( new->bv_val, ber->ber_buf, (size_t)len );
1255	    new->bv_val[len] = '\0';
1256	    new->bv_len = len;
1257	}
1258
1259	/* set bvPtr pointer to point to the returned berval */
1260  	*bvPtr = new;
1261
1262        return( 0 );
1263}
1264
1265
1266/*
1267 * The ber_init function constructs and returns a new BerElement
1268 * containing a copy of the data in the bv argument.  ber_init
1269 * returns the null pointer on error.
1270 */
1271BerElement *
1272LDAP_CALL
1273ber_init( const struct berval *bv )
1274{
1275	BerElement *ber;
1276
1277	/* construct BerElement */
1278	if (( ber = ber_alloc_t( 0 )) != NULLBER ) {
1279		/* copy data from the bv argument into BerElement */
1280		/* XXXmcs: had to cast unsigned long bv_len to long */
1281		if ( (ber_write ( ber, bv->bv_val, bv->bv_len, 0 ))
1282		    != (ber_slen_t)bv->bv_len ) {
1283			ber_free( ber, 1 );
1284			return( NULL );
1285		}
1286	}
1287
1288	/*
1289	 * reset ber_ptr back to the beginning of buffer so that this new
1290	 * and initialized ber element can be READ
1291	 */
1292	ber_reset( ber, 1);
1293
1294	/*
1295	 * return a ptr to a new BerElement containing a copy of the data
1296	 * in the bv argument or a null pointer on error
1297	 */
1298	return( ber );
1299}
1300
1301
1302/*
1303 * memory allocation functions.
1304 */
1305void *
1306nslberi_malloc( size_t size )
1307{
1308	return( nslberi_memalloc_fns.lbermem_malloc == NULL ?
1309	    malloc( size ) :
1310	    nslberi_memalloc_fns.lbermem_malloc( size ));
1311}
1312
1313
1314void *
1315nslberi_calloc( size_t nelem, size_t elsize )
1316{
1317	return( nslberi_memalloc_fns.lbermem_calloc == NULL ?
1318	    calloc(  nelem, elsize ) :
1319	    nslberi_memalloc_fns.lbermem_calloc( nelem, elsize ));
1320}
1321
1322
1323void *
1324nslberi_realloc( void *ptr, size_t size )
1325{
1326	return( nslberi_memalloc_fns.lbermem_realloc == NULL ?
1327	    realloc( ptr, size ) :
1328	    nslberi_memalloc_fns.lbermem_realloc( ptr, size ));
1329}
1330
1331
1332void
1333nslberi_free( void *ptr )
1334{
1335	if ( nslberi_memalloc_fns.lbermem_free == NULL ) {
1336		free( ptr );
1337	} else {
1338		nslberi_memalloc_fns.lbermem_free( ptr );
1339	}
1340}
1341
1342
1343/*
1344 ******************************************************************************
1345 * functions to bridge the gap between new extended I/O functions that are
1346 *    installed using ber_sockbuf_set_option( ..., LBER_SOCKBUF_OPT_EXT_IO_FNS,
1347 *    ... ).
1348 *
1349 * the basic strategy is to use the new extended arg to hold a pointer to the
1350 *    Sockbuf itself so we can find the old functions and call them.
1351 * note that the integer socket s passed in is not used.  we use the sb_sd
1352 *    from the Sockbuf itself because it is the correct type.
1353 */
1354static int
1355nslberi_extread_compat( int s, void *buf, int len,
1356	struct lextiof_socket_private *arg )
1357{
1358	Sockbuf	*sb = (Sockbuf *)arg;
1359
1360	return( sb->sb_io_fns.lbiof_read( sb->sb_sd, buf, len ));
1361}
1362
1363
1364static int
1365nslberi_extwrite_compat( int s, const void *buf, int len,
1366	struct lextiof_socket_private *arg )
1367{
1368	Sockbuf	*sb = (Sockbuf *)arg;
1369
1370	return( sb->sb_io_fns.lbiof_write( sb->sb_sd, buf, len ));
1371}
1372
1373
1374/*
1375 * Install I/O compatiblity functions.  This can't fail.
1376 */
1377static void
1378nslberi_install_compat_io_fns( Sockbuf *sb )
1379{
1380	sb->sb_ext_io_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
1381	sb->sb_ext_io_fns.lbextiofn_read = nslberi_extread_compat;
1382	sb->sb_ext_io_fns.lbextiofn_write = nslberi_extwrite_compat;
1383	sb->sb_ext_io_fns.lbextiofn_socket_arg = (void *)sb;
1384}
1385/*
1386 * end of compat I/O functions
1387 ******************************************************************************
1388 */
1389