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