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
ber_filbuf(Sockbuf * sb,ber_slen_t len)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
BerRead(Sockbuf * sb,char * buf,ber_slen_t len)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
ber_read(BerElement * ber,char * buf,ber_len_t len)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
nslberi_ber_realloc(BerElement * ber,ber_len_t len)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
ber_write(BerElement * ber,char * buf,ber_len_t len,int nosos)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
ber_free(BerElement * ber,int freebuf)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
ber_flush(Sockbuf * sb,BerElement * ber,int freeit)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
ber_alloc_t(int options)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
ber_alloc()449 ber_alloc()
450 {
451 return( ber_alloc_t( 0 ) );
452 }
453
454 BerElement *
455 LDAP_CALL
der_alloc()456 der_alloc()
457 {
458 return( ber_alloc_t( LBER_OPT_USE_DER ) );
459 }
460
461 BerElement *
462 LDAP_CALL
ber_dup(BerElement * ber)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
ber_init_w_nullchar(BerElement * ber,int options)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
ber_reset(BerElement * ber,int was_writing)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
ber_dump(BerElement * ber,int inout)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
ber_sos_dump(Seqorset * sos)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
get_tag(Sockbuf * sb)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
ber_get_next(Sockbuf * sb,ber_len_t * len,BerElement * ber)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
ber_sockbuf_alloc()716 ber_sockbuf_alloc()
717 {
718 return( (Sockbuf *)NSLBERI_CALLOC( 1, sizeof(struct sockbuf) ) );
719 }
720
721 void
722 LDAP_CALL
ber_sockbuf_free(Sockbuf * p)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
ber_set_option(struct berelement * ber,int option,void * value)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
ber_get_option(struct berelement * ber,int option,void * value)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
ber_sockbuf_set_option(Sockbuf * sb,int option,void * value)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 /* 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 */
920 int
921 LDAP_CALL
ber_sockbuf_get_option(Sockbuf * sb,int option,void * value)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
ber_special_alloc(size_t size,BerElement ** ppBer)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
ber_special_free(void * buf,BerElement * ber)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
read_bytes(byte_buffer * b,unsigned char * return_buffer,int bytes_to_read)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
get_buffer_tag(byte_buffer * sb)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
ber_get_next_buffer(void * buffer,size_t buffer_size,ber_len_t * len,BerElement * ber,ber_uint_t * Bytes_Scanned)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
ber_get_next_buffer_ext(void * buffer,size_t buffer_size,ber_len_t * len,BerElement * ber,ber_uint_t * Bytes_Scanned,Sockbuf * sock)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
ber_flatten(BerElement * ber,struct berval ** bvPtr)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
ber_init(const struct berval * bv)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 *
nslberi_malloc(size_t size)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 *
nslberi_calloc(size_t nelem,size_t elsize)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 *
nslberi_realloc(void * ptr,size_t size)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
nslberi_free(void * ptr)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
nslberi_extread_compat(int s,void * buf,int len,struct lextiof_socket_private * arg)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
nslberi_extwrite_compat(int s,const void * buf,int len,struct lextiof_socket_private * arg)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
nslberi_install_compat_io_fns(Sockbuf * sb)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