xref: /illumos-gate/usr/src/lib/libldap5/sources/ldap/ber/io.c (revision e3ae4b35c024af1196582063ecee3ab79367227d)
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
100 int	lber_debug;
101 #endif
102 
103 /*
104  * function prototypes
105  */
106 static void nslberi_install_compat_io_fns( Sockbuf *sb );
107 static int nslberi_extread_compat( int s, void *buf, int len,
108 		struct lextiof_socket_private *arg );
109 static 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  */
116 static 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  */
123 static int
124 ber_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 
181 static ber_int_t
182 BerRead( 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  */
208 ber_int_t
209 LDAP_CALL
210 ber_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  */
229 int
230 nslberi_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  */
295 ber_int_t
296 LDAP_CALL
297 ber_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 
319 void
320 LDAP_CALL
321 ber_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  */
335 int
336 LDAP_CALL
337 ber_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 */
416 BerElement *
417 LDAP_CALL
418 ber_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 
447 BerElement *
448 LDAP_CALL
449 ber_alloc()
450 {
451 	return( ber_alloc_t( 0 ) );
452 }
453 
454 BerElement *
455 LDAP_CALL
456 der_alloc()
457 {
458 	return( ber_alloc_t( LBER_OPT_USE_DER ) );
459 }
460 
461 BerElement *
462 LDAP_CALL
463 ber_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 
476 void
477 LDAP_CALL
478 ber_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 
496 void
497 LDAP_CALL
498 ber_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 
513 void
514 ber_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 
533 void
534 ber_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 */
555 static ber_tag_t
556 get_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 
591 ber_tag_t
592 LDAP_CALL
593 ber_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 
714 Sockbuf *
715 LDAP_CALL
716 ber_sockbuf_alloc()
717 {
718 	return( (Sockbuf *)NSLBERI_CALLOC( 1, sizeof(struct sockbuf) ) );
719 }
720 
721 void
722 LDAP_CALL
723 ber_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  */
744 int
745 LDAP_CALL
746 ber_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  */
805 int
806 LDAP_CALL
807 ber_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  */
860 int
861 LDAP_CALL
862 ber_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 		/* FALLTHROUGH */
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  */
920 int
921 LDAP_CALL
922 ber_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 
972 struct byte_buffer  {
973 	unsigned char *p;
974 	int offset;
975 	int length;
976 };
977 typedef 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  */
985 void*
986 LDAP_CALL
987 ber_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 
1010 void
1011 LDAP_CALL
1012 ber_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 
1020 static int
1021 read_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 */
1045 static ber_tag_t
1046 get_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 
1087 ber_uint_t
1088 LDAP_CALL
1089 ber_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 
1096 ber_uint_t
1097 LDAP_CALL
1098 ber_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 
1209 premature_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  */
1228 int
1229 LDAP_CALL
1230 ber_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  */
1271 BerElement *
1272 LDAP_CALL
1273 ber_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  */
1305 void *
1306 nslberi_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 
1314 void *
1315 nslberi_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 
1323 void *
1324 nslberi_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 
1332 void
1333 nslberi_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  */
1354 static int
1355 nslberi_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 
1364 static int
1365 nslberi_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  */
1377 static void
1378 nslberi_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