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