Back to index

lightning-sunbird  0.9+nobinonly
io.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * Copyright (c) 1990 Regents of the University of Michigan.
00040  * All rights reserved.
00041  *
00042  * Redistribution and use in source and binary forms are permitted
00043  * provided that this notice is preserved and that due credit is given
00044  * to the University of Michigan at Ann Arbor. The name of the University
00045  * may not be used to endorse or promote products derived from this
00046  * software without specific prior written permission. This software
00047  * is provided ``as is'' without express or implied warranty.
00048  */
00049 /* io.c - ber general i/o routines */
00050 
00051 #include "lber-int.h"
00052 
00053 #define bergetc( sb, len )    ( sb->sb_ber.ber_end > sb->sb_ber.ber_ptr ? \
00054                        (unsigned char)*sb->sb_ber.ber_ptr++ : \
00055                        ber_filbuf( sb, len ))
00056 
00057 # ifdef macintosh
00058 /*
00059  * MacTCP/OpenTransport
00060  */
00061 #  define read( s, b, l ) tcpread( s, 0, (unsigned char *)b, l, NULL )
00062 #  define MAX_WRITE  65535
00063 #  define BerWrite( sb, b, l )   tcpwrite( sb->sb_sd, (unsigned char *)(b), (l<MAX_WRITE)? l : MAX_WRITE )
00064 # else /* macintosh */
00065 #  if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2)
00066 /*
00067  * 32-bit Windows Socket API (under Windows NT or Windows 95)
00068  */
00069 #   define read( s, b, l )         recv( s, b, l, 0 )
00070 #   define BerWrite( s, b, l )     send( s->sb_sd, b, l, 0 )
00071 #  else /* _WIN32 */
00072 /*
00073  * everything else (Unix/BSD 4.3 socket API)
00074  */
00075 #   define BerWrite( sb, b, l )    write( sb->sb_sd, b, l )
00076 #   define udp_read( sb, b, l, al ) recvfrom(sb->sb_sd, (char *)b, l, 0, \
00077               (struct sockaddr *)sb->sb_fromaddr, \
00078               (al = sizeof(struct sockaddr), &al))
00079 #   define udp_write( sb, b, l ) sendto(sb->sb_sd, (char *)(b), l, 0, \
00080               (struct sockaddr *)sb->sb_useaddr, sizeof(struct sockaddr))
00081 #  endif /* _WIN32 */
00082 # endif /* macintosh */
00083 
00084 #ifndef udp_read
00085 #define udp_read( sb, b, l, al )   CLDAP NOT SUPPORTED
00086 #define udp_write( sb, b, l )             CLDAP NOT SUPPORTED
00087 #endif /* udp_read */
00088 
00089 #define EXBUFSIZ     1024
00090 
00091 #ifdef LDAP_DEBUG
00092 int    lber_debug;
00093 #endif
00094 
00095 /*
00096  * function prototypes
00097  */
00098 static void nslberi_install_compat_io_fns( Sockbuf *sb );
00099 static int nslberi_extread_compat( int s, void *buf, int len,
00100               struct lextiof_socket_private *arg );
00101 static int nslberi_extwrite_compat( int s, const void *buf, int len,
00102               struct lextiof_socket_private *arg );
00103 static unsigned long get_tag( Sockbuf *sb, BerElement *ber);
00104 static unsigned long get_ber_len( BerElement *ber);
00105 static unsigned long read_len_in_ber( Sockbuf *sb, BerElement *ber);
00106 
00107 /*
00108  * internal global structure for memory allocation callback functions
00109  */
00110 static struct lber_memalloc_fns nslberi_memalloc_fns;
00111 
00112 
00113 /*
00114  * buffered read from "sb".
00115  * returns value of first character read on success and -1 on error.
00116  */
00117 static int
00118 ber_filbuf( Sockbuf *sb, long len )
00119 {
00120        short  rc;
00121 #ifdef CLDAP
00122        int    addrlen;
00123 #endif /* CLDAP */
00124 
00125        if ( sb->sb_ber.ber_buf == NULL ) {
00126               if ( (sb->sb_ber.ber_buf = (char *)NSLBERI_MALLOC(
00127                   READBUFSIZ )) == NULL ) {
00128                      return( -1 );
00129               }
00130               sb->sb_ber.ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
00131               sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf;
00132               sb->sb_ber.ber_end = sb->sb_ber.ber_buf;
00133        }
00134 
00135        if ( sb->sb_naddr > 0 ) {
00136 #ifdef CLDAP
00137               rc = udp_read(sb, sb->sb_ber.ber_buf, READBUFSIZ, addrlen );
00138 #ifdef LDAP_DEBUG
00139               if ( lber_debug ) {
00140                      char msg[80];
00141                      sprintf( msg, "ber_filbuf udp_read %d bytes\n",
00142                             rc );
00143                      ber_err_print( msg );
00144                      if ( lber_debug > 1 && rc > 0 )
00145                             lber_bprint( sb->sb_ber.ber_buf, rc );
00146               }
00147 #endif /* LDAP_DEBUG */
00148 #else /* CLDAP */
00149               rc = -1;
00150 #endif /* CLDAP */
00151        } else {
00152               if ( sb->sb_ext_io_fns.lbextiofn_read != NULL ) {
00153                      rc = sb->sb_ext_io_fns.lbextiofn_read(
00154                          sb->sb_sd, sb->sb_ber.ber_buf,
00155                          ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
00156                          && (len < READBUFSIZ)) ? len : READBUFSIZ,
00157                          sb->sb_ext_io_fns.lbextiofn_socket_arg );
00158               } else {
00159 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00160                      return( -1 );
00161 #else
00162                      rc = read( sb->sb_sd, sb->sb_ber.ber_buf,
00163                          ((sb->sb_options & LBER_SOCKBUF_OPT_NO_READ_AHEAD)
00164                          && (len < READBUFSIZ)) ? len : READBUFSIZ );
00165 #endif
00166               }
00167        }
00168 
00169        if ( rc > 0 ) {
00170               sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf + 1;
00171               sb->sb_ber.ber_end = sb->sb_ber.ber_buf + rc;
00172               return( (unsigned char)*sb->sb_ber.ber_buf );
00173        }
00174 
00175        return( -1 );
00176 }
00177 
00178 
00179 static long
00180 BerRead( Sockbuf *sb, char *buf, long len )
00181 {
00182        int    c;
00183        long   nread = 0;
00184 
00185        while ( len > 0 ) {
00186               if ( (c = bergetc( sb, len )) < 0 ) {
00187                      if ( nread > 0 )
00188                             break;
00189                      return( c );
00190               }
00191               *buf++ = c;
00192               nread++;
00193               len--;
00194        }
00195 
00196        return( nread );
00197 }
00198 
00199 
00200 /*
00201  * Note: ber_read() only uses the ber_end and ber_ptr elements of ber.
00202  * Functions like ber_get_tag(), ber_skip_tag, and ber_peek_tag() rely on
00203  * that fact, so if this code is changed to use any additional elements of
00204  * the ber structure, those functions will need to be changed as well.
00205  */
00206 long
00207 LDAP_CALL
00208 ber_read( BerElement *ber, char *buf, unsigned long len )
00209 {
00210        unsigned long actuallen, nleft;
00211 
00212        nleft = ber->ber_end - ber->ber_ptr;
00213        actuallen = nleft < len ? nleft : len;
00214 
00215        SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen );
00216 
00217        ber->ber_ptr += actuallen;
00218 
00219        return( (long)actuallen );
00220 }
00221 
00222 /*
00223  * enlarge the ber buffer.
00224  * return 0 on success, -1 on error.
00225  */
00226 int
00227 nslberi_ber_realloc( BerElement *ber, unsigned long len )
00228 {
00229        unsigned long need, have, total;
00230        size_t        have_bytes;
00231        Seqorset      *s;
00232        long          off;
00233        char          *oldbuf;
00234 
00235        have_bytes = ber->ber_end - ber->ber_buf;
00236        have = have_bytes / EXBUFSIZ;
00237        need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
00238        total = have * EXBUFSIZ + need * EXBUFSIZ;
00239 
00240        oldbuf = ber->ber_buf;
00241 
00242        if (ber->ber_buf == NULL) {
00243               if ( (ber->ber_buf = (char *)NSLBERI_MALLOC( (size_t)total ))
00244                   == NULL ) {
00245                      return( -1 );
00246               }
00247               ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
00248        } else {
00249               if ( ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER ) {
00250                      /* transition to malloc'd buffer */
00251                      if ( (ber->ber_buf = (char *)NSLBERI_MALLOC(
00252                          (size_t)total )) == NULL ) {
00253                             return( -1 );
00254                      }
00255                      ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
00256                      /* copy existing data into new malloc'd buffer */
00257                      SAFEMEMCPY( ber->ber_buf, oldbuf, have_bytes );
00258               } else {
00259                      if ( (ber->ber_buf = (char *)NSLBERI_REALLOC(
00260                          ber->ber_buf,(size_t)total )) == NULL ) {
00261                             return( -1 );
00262                      }
00263               }
00264        }
00265 
00266        ber->ber_end = ber->ber_buf + total;
00267 
00268        /*
00269         * If the stinking thing was moved, we need to go through and
00270         * reset all the sos and ber pointers.  Offsets would've been
00271         * a better idea... oh well.
00272         */
00273 
00274        if ( ber->ber_buf != oldbuf ) {    
00275               ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
00276 
00277               for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) {
00278                      off = s->sos_first - oldbuf;
00279                      s->sos_first = ber->ber_buf + off;
00280 
00281                      off = s->sos_ptr - oldbuf;
00282                      s->sos_ptr = ber->ber_buf + off;
00283               }
00284        }
00285 
00286        return( 0 );
00287 }
00288 
00289 /*
00290  * returns "len" on success and -1 on failure.
00291  */
00292 long
00293 LDAP_CALL
00294 ber_write( BerElement *ber, char *buf, unsigned long len, int nosos )
00295 {
00296        if ( nosos || ber->ber_sos == NULL ) {
00297               if ( ber->ber_ptr + len > ber->ber_end ) {
00298                      if ( nslberi_ber_realloc( ber, len ) != 0 )
00299                             return( -1 );
00300               }
00301               SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
00302               ber->ber_ptr += len;
00303               return( len );
00304        } else {
00305               if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
00306                      if ( nslberi_ber_realloc( ber, len ) != 0 )
00307                             return( -1 );
00308               }
00309               SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
00310               ber->ber_sos->sos_ptr += len;
00311               ber->ber_sos->sos_clen += len;
00312               return( len );
00313        }
00314 }
00315 
00316 void
00317 LDAP_CALL
00318 ber_free( BerElement *ber, int freebuf )
00319 {
00320        if ( ber != NULL ) {
00321                   if ( freebuf &&
00322                      !(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
00323                          NSLBERI_FREE(ber->ber_buf);
00324                   }
00325                   NSLBERI_FREE( (char *) ber );
00326        }
00327 }
00328 
00329 /*
00330  * return >= 0 on success, -1 on failure.
00331  */
00332 int
00333 LDAP_CALL
00334 ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
00335 {
00336        long   nwritten = 0, towrite, rc;
00337        int     i = 0;
00338        
00339        if (ber->ber_rwptr == NULL) {
00340          ber->ber_rwptr = ber->ber_buf;
00341        } else if (ber->ber_rwptr >= ber->ber_end) {
00342          /* we will use the ber_rwptr to continue an exited flush,
00343             so if rwptr is not within the buffer we return an error. */
00344          return( -1 );
00345        }
00346        
00347        /* writev section - for iDAR only!!! This section ignores freeit!!! */
00348        if (sb->sb_ext_io_fns.lbextiofn_writev != NULL) {
00349 
00350          /* add the sizes of the different buffers to write with writev */
00351          for (towrite = 0, i = 0; i < BER_ARRAY_QUANTITY; ++i) {
00352            /* don't add lengths of null buffers - writev will ignore them */
00353            if (ber->ber_struct[i].ldapiov_base) {
00354              towrite += ber->ber_struct[i].ldapiov_len;
00355            }
00356          }
00357          
00358          rc = sb->sb_ext_io_fns.lbextiofn_writev(sb->sb_sd, ber->ber_struct, BER_ARRAY_QUANTITY, 
00359                                             sb->sb_ext_io_fns.lbextiofn_socket_arg);
00360          
00361          if (rc >= 0) {
00362            /* return the number of bytes TO BE written */
00363            return (towrite - rc);
00364          } else {
00365            /* otherwise it's an error */
00366            return (rc);
00367          }
00368        } /* end writev section */
00369 
00370        towrite = ber->ber_ptr - ber->ber_rwptr;
00371 
00372 #ifdef LDAP_DEBUG
00373        if ( lber_debug ) {
00374               char msg[80];
00375               sprintf( msg, "ber_flush: %ld bytes to sd %ld%s\n", towrite,
00376                   sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
00377                   : "" );
00378               ber_err_print( msg );
00379               if ( lber_debug > 1 )
00380                      lber_bprint( ber->ber_rwptr, towrite );
00381        }
00382 #endif
00383 #if !defined(macintosh) && !defined(DOS)
00384        if ( sb->sb_options & (LBER_SOCKBUF_OPT_TO_FILE | LBER_SOCKBUF_OPT_TO_FILE_ONLY) ) {
00385               rc = write( sb->sb_copyfd, ber->ber_buf, towrite );
00386               if ( sb->sb_options & LBER_SOCKBUF_OPT_TO_FILE_ONLY ) {
00387                      return( (int)rc );
00388               }
00389        }
00390 #endif
00391 
00392        nwritten = 0;
00393        do {
00394               if (sb->sb_naddr > 0) {
00395 #ifdef CLDAP
00396                      rc = udp_write( sb, ber->ber_buf + nwritten,
00397                          (size_t)towrite );
00398 #else /* CLDAP */
00399                      rc = -1;
00400 #endif /* CLDAP */
00401                      if ( rc <= 0 )
00402                             return( -1 );
00403                      /* fake error if write was not atomic */
00404                      if (rc < towrite) {
00405 #if !defined( macintosh ) && !defined( DOS )
00406                          errno = EMSGSIZE;  /* For Win32, see portable.h */
00407 #endif
00408                          return( -1 );
00409                      }
00410               } else {
00411                      if ( sb->sb_ext_io_fns.lbextiofn_write != NULL ) {
00412                             if ( (rc = sb->sb_ext_io_fns.lbextiofn_write(
00413                                 sb->sb_sd, ber->ber_rwptr, (size_t)towrite,
00414                                 sb->sb_ext_io_fns.lbextiofn_socket_arg ))
00415                                 <= 0 ) {
00416                                    return( -1 );
00417                             }
00418                      } else {
00419 #ifdef NSLDAPI_AVOID_OS_SOCKETS
00420                             return( -1 );
00421 #else
00422                             if ( (rc = BerWrite( sb, ber->ber_rwptr,
00423                                 (size_t) towrite )) <= 0 ) {
00424                                    return( -1 );
00425                             }
00426 #endif
00427                      }
00428               }
00429               towrite -= rc;
00430               nwritten += rc;
00431               ber->ber_rwptr += rc;
00432        } while ( towrite > 0 );
00433 
00434        if ( freeit )
00435               ber_free( ber, 1 );
00436 
00437        return( 0 );
00438 }
00439 
00440 
00441 /* we pre-allocate a buffer to save the extra malloc later */
00442 BerElement *
00443 LDAP_CALL
00444 ber_alloc_t( int options )
00445 {
00446        BerElement    *ber;
00447 
00448        if ( (ber = (BerElement*)NSLBERI_CALLOC( 1,
00449            sizeof(struct berelement) + EXBUFSIZ )) == NULL ) {
00450               return( NULL );
00451        }
00452 
00453        /*
00454         * for compatibility with the C LDAP API standard, we recognize
00455         * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
00456         */
00457        if ( options & LBER_USE_DER ) {
00458               options &= ~LBER_USE_DER;
00459               options |= LBER_OPT_USE_DER;
00460        }
00461 
00462        ber->ber_tag = LBER_DEFAULT;
00463        ber->ber_options = options;
00464        ber->ber_buf = (char*)ber + sizeof(struct berelement);
00465        ber->ber_ptr = ber->ber_buf;
00466        ber->ber_end = ber->ber_buf + EXBUFSIZ;
00467        ber->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
00468 
00469        return( ber );
00470 }
00471 
00472 
00473 BerElement *
00474 LDAP_CALL
00475 ber_alloc()
00476 {
00477        return( ber_alloc_t( 0 ) );
00478 }
00479 
00480 BerElement *
00481 LDAP_CALL
00482 der_alloc()
00483 {
00484        return( ber_alloc_t( LBER_OPT_USE_DER ) );
00485 }
00486 
00487 BerElement *
00488 LDAP_CALL
00489 ber_dup( BerElement *ber )
00490 {
00491        BerElement    *new;
00492 
00493        if ( (new = ber_alloc()) == NULL )
00494               return( NULL );
00495 
00496        *new = *ber;
00497 
00498        return( new );
00499 }
00500 
00501 
00502 void
00503 LDAP_CALL
00504 ber_init_w_nullchar( BerElement *ber, int options )
00505 {
00506        (void) memset( (char *)ber, '\0', sizeof(struct berelement) );
00507        ber->ber_tag = LBER_DEFAULT;
00508 
00509        /*
00510         * For compatibility with the C LDAP API standard, we recognize
00511         * LBER_USE_DER as LBER_OPT_USE_DER.  See lber.h for a bit more info.
00512         */
00513        if ( options & LBER_USE_DER ) {
00514               options &= ~LBER_USE_DER;
00515               options |= LBER_OPT_USE_DER;
00516        }
00517 
00518        ber->ber_options = options;
00519 }
00520 
00521 void
00522 LDAP_CALL
00523 ber_reset( BerElement *ber, int was_writing )
00524 {
00525        if ( was_writing ) {
00526               ber->ber_end = ber->ber_ptr;
00527               ber->ber_ptr = ber->ber_buf;
00528        } else {
00529               ber->ber_ptr = ber->ber_end;
00530        }
00531 
00532        ber->ber_rwptr = NULL;
00533 
00534        memset(ber->ber_struct, 0, BER_CONTENTS_STRUCT_SIZE);
00535 }
00536 
00537 
00538 #ifdef LDAP_DEBUG
00539 
00540 void
00541 ber_dump( BerElement *ber, int inout )
00542 {
00543        char msg[128];
00544        sprintf( msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
00545            ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end );
00546        ber_err_print( msg );
00547        if ( inout == 1 ) {
00548               sprintf( msg, "          current len %ld, contents:\n",
00549                   ber->ber_end - ber->ber_ptr );
00550               ber_err_print( msg );
00551               lber_bprint( ber->ber_ptr, ber->ber_end - ber->ber_ptr );
00552        } else {
00553               sprintf( msg, "          current len %ld, contents:\n",
00554                   ber->ber_ptr - ber->ber_buf );
00555               ber_err_print( msg );
00556               lber_bprint( ber->ber_buf, ber->ber_ptr - ber->ber_buf );
00557        }
00558 }
00559 
00560 void
00561 ber_sos_dump( Seqorset *sos )
00562 {
00563        char msg[80];
00564        ber_err_print ( "*** sos dump ***\n" );
00565        while ( sos != NULLSEQORSET ) {
00566               sprintf( msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
00567                   sos->sos_clen, sos->sos_first, sos->sos_ptr );
00568               ber_err_print( msg );
00569               sprintf( msg, "              current len %ld contents:\n",
00570                   sos->sos_ptr - sos->sos_first );
00571               ber_err_print( msg );
00572               lber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first );
00573 
00574               sos = sos->sos_next;
00575        }
00576        ber_err_print( "*** end dump ***\n" );
00577 }
00578 
00579 #endif
00580 
00581 /* return the tag - LBER_DEFAULT returned means trouble
00582  * assumes the tag is only one byte! */
00583 static unsigned long
00584 get_tag( Sockbuf *sb, BerElement *ber)
00585 {
00586         unsigned char   xbyte;
00587 
00588         if ( (BerRead( sb, (char *) &xbyte, 1 )) != 1 ) {
00589                 return( LBER_DEFAULT );
00590         }
00591 
00592         if ( (xbyte & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK ) {
00593                 return( LBER_DEFAULT );
00594         }
00595 
00596        ber->ber_tag_contents[0] = xbyte;
00597        ber->ber_struct[BER_STRUCT_TAG].ldapiov_len = 1;
00598        return((unsigned long)xbyte);
00599 }
00600 
00601 
00602 /* Error checking? */
00603 /* Takes a ber and returns the actual length in a long */
00604 static unsigned long
00605 get_ber_len( BerElement *ber)
00606 {
00607   int noctets;
00608   unsigned long len = 0;
00609   char xbyte;
00610 
00611   xbyte = ber->ber_len_contents[0];
00612   
00613   /* long form */
00614   if (xbyte & 0x80) {
00615     noctets = (int) (xbyte & 0x7f);
00616     if (noctets >= MAX_LEN_SIZE) {
00617       return(LBER_DEFAULT);
00618     }
00619     memcpy((char*) &len + sizeof(unsigned long) - noctets, &ber->ber_len_contents[1], noctets);
00620     len = LBER_NTOHL(len);
00621     return(len);
00622   } else {
00623     return((unsigned long)(xbyte));
00624   }
00625 }
00626 
00627 /* LBER_DEFAULT means trouble
00628    reads in the length, stores it in ber->ber_struct, and returns get_ber_len */
00629 static unsigned long
00630 read_len_in_ber( Sockbuf *sb, BerElement *ber)
00631 {
00632   unsigned char xbyte;
00633   int           noctets;
00634   int           rc = 0;
00635 
00636   /*
00637    * Next, read the length.  The first byte contains the length
00638    * of the length.  If bit 8 is set, the length is the long
00639    * form, otherwise it's the short form.  We don't allow a
00640    * length that's greater than what we can hold in a long (2GB)
00641    */
00642  
00643   if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 ) {
00644     return( LBER_DEFAULT );
00645   }
00646 
00647   ber->ber_len_contents[0] = xbyte;
00648 
00649   /* long form of the length value */
00650   if ( xbyte & 0x80 ) {
00651     noctets = (xbyte & 0x7f);
00652     if ( noctets >= MAX_LEN_SIZE )
00653       return( LBER_DEFAULT );
00654     while (rc < noctets) {
00655       if ( (rc += BerRead( sb, &(ber->ber_len_contents[1]) + rc, noctets - rc )) <= 0) {
00656        return( LBER_DEFAULT );
00657       }
00658     }
00659     ber->ber_struct[BER_STRUCT_LEN].ldapiov_len = 1 + noctets;
00660   } else { /* short form of the length value */ 
00661     ber->ber_struct[BER_STRUCT_LEN].ldapiov_len = 1;
00662   }
00663   return(get_ber_len(ber));
00664 }
00665 
00666 
00667 unsigned long
00668 LDAP_CALL
00669 ber_get_next( Sockbuf *sb, unsigned long *len, BerElement *ber )
00670 {
00671        unsigned long tag, toread, newlen;
00672        long          rc;
00673 
00674 #ifdef LDAP_DEBUG
00675        if ( lber_debug )
00676               ber_err_print( "ber_get_next\n" );
00677 #endif
00678 
00679        /*
00680         * first time through - malloc the buffer, set up ptrs, and
00681         * read the tag and the length and as much of the rest as we can
00682         */
00683 
00684        if ( ber->ber_rwptr == NULL ) {
00685          /* read the tag */
00686          if ((tag = get_tag(sb, ber)) == LBER_DEFAULT ) {
00687            return( LBER_DEFAULT );
00688          }
00689 
00690          if((sb->sb_options & LBER_SOCKBUF_OPT_VALID_TAG) &&
00691             (tag != sb->sb_valid_tag)) {
00692            return( LBER_DEFAULT);
00693           }
00694 
00695          ber->ber_tag_contents[0] = (char)tag; /* we only handle 1 byte tags */
00696          
00697          /* read the length */
00698          if ((newlen = read_len_in_ber(sb, ber)) == LBER_DEFAULT ) {
00699            return( LBER_DEFAULT );
00700          }
00701 
00702          /*
00703           * Finally, malloc a buffer for the contents and read it in.
00704           * It's this buffer that's passed to all the other ber decoding
00705           * routines.
00706           */
00707          
00708 #if defined( DOS ) && !( defined( _WIN32 ) || defined(XP_OS2) )
00709          if ( newlen > 65535 ) {   /* DOS can't allocate > 64K */
00710            return( LBER_DEFAULT );
00711          }
00712 #endif /* DOS && !_WIN32 */
00713          
00714          if ( ( sb->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
00715               && newlen > sb->sb_max_incoming ) {
00716            return( LBER_DEFAULT );
00717          }
00718          
00719          /* check to see if we already have enough memory allocated */
00720          if ( (ber->ber_end - ber->ber_buf) < (size_t)newlen) {         
00721            if ( (ber->ber_buf = (char *)NSLBERI_CALLOC( 1,(size_t)newlen ))
00722                == NULL ) {
00723              return( LBER_DEFAULT );
00724            }
00725            ber->ber_flags &= ~LBER_FLAG_NO_FREE_BUFFER;
00726          }
00727          
00728 
00729          ber->ber_len = newlen;
00730          ber->ber_ptr = ber->ber_buf;
00731          ber->ber_end = ber->ber_buf + newlen;
00732          ber->ber_rwptr = ber->ber_buf;
00733        }
00734 
00735        /* OK, we've malloc-ed the buffer; now read the rest of the expected length */
00736        toread = (unsigned long)ber->ber_end - (unsigned long)ber->ber_rwptr;
00737        do {
00738          if ( (rc = BerRead( sb, ber->ber_rwptr, (long)toread )) <= 0 ) {
00739            return( LBER_DEFAULT );
00740          }
00741          
00742          toread -= rc;
00743          ber->ber_rwptr += rc;
00744        } while ( toread > 0 );
00745        
00746 #ifdef LDAP_DEBUG
00747        if ( lber_debug ) {
00748          char msg[80];
00749          sprintf( msg, "ber_get_next: tag 0x%lx len %ld contents:\n",
00750                  tag, ber->ber_len );
00751          ber_err_print( msg );
00752          if ( lber_debug > 1 )
00753            ber_dump( ber, 1 );
00754        }
00755 #endif
00756               
00757        ber->ber_rwptr = NULL;
00758        *len = newlen;
00759        ber->ber_struct[BER_STRUCT_VAL].ldapiov_len = newlen;
00760        return(tag);
00761 }
00762 
00763 Sockbuf *
00764 LDAP_CALL
00765 ber_sockbuf_alloc()
00766 {
00767        return( (Sockbuf *)NSLBERI_CALLOC( 1, sizeof(struct sockbuf) ) );
00768 }
00769 
00770 void
00771 LDAP_CALL
00772 ber_sockbuf_free(Sockbuf *p)
00773 {
00774        if ( p != NULL ) {
00775               if ( p->sb_ber.ber_buf != NULL &&
00776                   !(p->sb_ber.ber_flags & LBER_FLAG_NO_FREE_BUFFER) ) {
00777                      NSLBERI_FREE( p->sb_ber.ber_buf );
00778               }
00779               NSLBERI_FREE(p);
00780        }
00781 }
00782 
00783 /*
00784  * return 0 on success and -1 on error
00785  */
00786 int
00787 LDAP_CALL
00788 ber_set_option( struct berelement *ber, int option, void *value )
00789 {
00790   
00791   /*
00792    * memory allocation callbacks are global, so it is OK to pass
00793    * NULL for ber.  Handle this as a special case.
00794    */
00795   if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
00796     /* struct copy */
00797     nslberi_memalloc_fns = *((struct lber_memalloc_fns *)value);
00798     return( 0 );
00799   }
00800   
00801   /*
00802    * lber_debug is global, so it is OK to pass
00803    * NULL for ber.  Handle this as a special case.
00804    */
00805   if ( option == LBER_OPT_DEBUG_LEVEL ) {
00806 #ifdef LDAP_DEBUG
00807     lber_debug = *(int *)value;
00808 #endif
00809     return( 0 );
00810   }
00811   
00812   /*
00813    * all the rest require a non-NULL ber
00814    */
00815   if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
00816     return( -1 );
00817   }
00818   
00819   switch ( option ) {
00820        case LBER_OPT_USE_DER:
00821        case LBER_OPT_TRANSLATE_STRINGS:
00822               if ( value != NULL ) {
00823                      ber->ber_options |= option;
00824               } else {
00825                      ber->ber_options &= ~option;
00826               }
00827               break;
00828        case LBER_OPT_REMAINING_BYTES:
00829               ber->ber_end = ber->ber_ptr + *((unsigned long *)value);
00830               break;
00831        case LBER_OPT_TOTAL_BYTES:
00832               ber->ber_end = ber->ber_buf + *((unsigned long *)value);
00833               break;
00834        case LBER_OPT_BYTES_TO_WRITE:
00835               ber->ber_ptr = ber->ber_buf + *((unsigned long *)value);
00836               break;
00837        default:
00838               return( -1 );
00839   }
00840   
00841   return( 0 );
00842 }
00843 
00844 /*
00845  * return 0 on success and -1 on error
00846  */
00847 int
00848 LDAP_CALL
00849 ber_get_option( struct berelement *ber, int option, void *value )
00850 {
00851        /*
00852         * memory callocation callbacks are global, so it is OK to pass
00853         * NULL for ber.  Handle this as a special case
00854         */
00855        if ( option == LBER_OPT_MEMALLOC_FN_PTRS ) {
00856               /* struct copy */
00857               *((struct lber_memalloc_fns *)value) = nslberi_memalloc_fns;
00858               return( 0 );
00859        }
00860        
00861        /*
00862         * lber_debug is global, so it is OK to pass
00863         * NULL for ber.  Handle this as a special case.
00864         */
00865        if ( option == LBER_OPT_DEBUG_LEVEL ) {
00866 #ifdef LDAP_DEBUG
00867         *(int *)value =  lber_debug;
00868 #endif
00869          return( 0 );
00870        }
00871        /*
00872         * all the rest require a non-NULL ber
00873         */
00874        if ( !NSLBERI_VALID_BERELEMENT_POINTER( ber )) {
00875               return( -1 );
00876        }
00877 
00878        switch ( option ) {
00879        case LBER_OPT_USE_DER:
00880        case LBER_OPT_TRANSLATE_STRINGS:
00881               *((int *) value) = (ber->ber_options & option);
00882               break;
00883        case LBER_OPT_REMAINING_BYTES:
00884               *((unsigned long *) value) = ber->ber_end - ber->ber_ptr;
00885               break;
00886        case LBER_OPT_TOTAL_BYTES:
00887               *((unsigned long *) value) = ber->ber_end - ber->ber_buf;
00888               break;
00889        case LBER_OPT_BYTES_TO_WRITE:
00890               *((unsigned long *) value) = ber->ber_ptr - ber->ber_buf;
00891               break;
00892        default:
00893               return( -1 );
00894        }
00895 
00896        return( 0 );
00897 }
00898 
00899 /*
00900  * return 0 on success and -1 on error
00901  */
00902 int
00903 LDAP_CALL
00904 ber_sockbuf_set_option( Sockbuf *sb, int option, void *value )
00905 {
00906        struct lber_x_ext_io_fns    *extiofns;
00907 
00908        if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
00909               return( -1 );
00910        }
00911 
00912        switch ( option ) {
00913        case LBER_SOCKBUF_OPT_VALID_TAG:
00914               sb->sb_valid_tag= *((unsigned long *) value);
00915               if ( value != NULL ) {
00916                      sb->sb_options |= option;
00917               } else {
00918                      sb->sb_options &= ~option;
00919               }
00920               break;
00921        case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
00922               sb->sb_max_incoming = *((unsigned long *) value);
00923               /* FALL */
00924        case LBER_SOCKBUF_OPT_TO_FILE:
00925        case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
00926        case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
00927               if ( value != NULL ) {
00928                      sb->sb_options |= option;
00929               } else {
00930                      sb->sb_options &= ~option;
00931               }
00932               break;
00933        case LBER_SOCKBUF_OPT_DESC:
00934               sb->sb_sd = *((LBER_SOCKET *) value);
00935               break;
00936        case LBER_SOCKBUF_OPT_COPYDESC:
00937               sb->sb_copyfd = *((LBER_SOCKET *) value);
00938               break;
00939        case LBER_SOCKBUF_OPT_READ_FN:
00940               sb->sb_io_fns.lbiof_read = (LDAP_IOF_READ_CALLBACK *) value;
00941               nslberi_install_compat_io_fns( sb );
00942               break;
00943        case LBER_SOCKBUF_OPT_WRITE_FN:
00944               sb->sb_io_fns.lbiof_write = (LDAP_IOF_WRITE_CALLBACK *) value;
00945               nslberi_install_compat_io_fns( sb );
00946               break;
00947        case LBER_SOCKBUF_OPT_EXT_IO_FNS:
00948               extiofns = (struct lber_x_ext_io_fns *) value;
00949               if ( extiofns == NULL ) {   /* remove */
00950                      (void)memset( (char *)&sb->sb_ext_io_fns, '\0',
00951                             sizeof(sb->sb_ext_io_fns ));
00952               } else if ( extiofns->lbextiofn_size
00953                   == LBER_X_EXTIO_FNS_SIZE ) {
00954                      /* struct copy */
00955                      sb->sb_ext_io_fns = *extiofns;
00956               } else if ( extiofns->lbextiofn_size
00957                          == LBER_X_EXTIO_FNS_SIZE_REV0 ) {
00958                      /* backwards compatiblity for older struct */
00959                      sb->sb_ext_io_fns.lbextiofn_size =
00960                             LBER_X_EXTIO_FNS_SIZE;
00961                      sb->sb_ext_io_fns.lbextiofn_read =
00962                             extiofns->lbextiofn_read;
00963                      sb->sb_ext_io_fns.lbextiofn_write =
00964                                 extiofns->lbextiofn_write;
00965                      sb->sb_ext_io_fns.lbextiofn_writev = NULL;
00966                      sb->sb_ext_io_fns.lbextiofn_socket_arg =
00967                                 extiofns->lbextiofn_socket_arg;
00968               } else {
00969                      return( -1 );
00970               }
00971               break;
00972        default:
00973               return( -1 );
00974        }
00975 
00976        return( 0 );
00977 }
00978 
00979 /*
00980  * return 0 on success and -1 on error
00981  */
00982 int
00983 LDAP_CALL
00984 ber_sockbuf_get_option( Sockbuf *sb, int option, void *value )
00985 {
00986        struct lber_x_ext_io_fns    *extiofns;
00987 
00988        if ( !NSLBERI_VALID_SOCKBUF_POINTER( sb )) {
00989               return( -1 );
00990        }
00991 
00992        switch ( option ) {
00993        case LBER_SOCKBUF_OPT_VALID_TAG:
00994               *((unsigned long *) value) = sb->sb_valid_tag;
00995               break;
00996        case LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE:
00997               *((unsigned long *) value) = sb->sb_max_incoming;
00998               break;
00999        case LBER_SOCKBUF_OPT_TO_FILE:
01000        case LBER_SOCKBUF_OPT_TO_FILE_ONLY:
01001        case LBER_SOCKBUF_OPT_NO_READ_AHEAD:
01002               *((int *) value) = (sb->sb_options & option);
01003               break;
01004        case LBER_SOCKBUF_OPT_DESC:
01005               *((LBER_SOCKET *) value) = sb->sb_sd;
01006               break;
01007        case LBER_SOCKBUF_OPT_COPYDESC:
01008               *((LBER_SOCKET *) value) = sb->sb_copyfd;
01009               break;
01010        case LBER_SOCKBUF_OPT_READ_FN:
01011               *((LDAP_IOF_READ_CALLBACK **) value)
01012                   = sb->sb_io_fns.lbiof_read;
01013               break;
01014        case LBER_SOCKBUF_OPT_WRITE_FN:
01015               *((LDAP_IOF_WRITE_CALLBACK **) value)
01016                   = sb->sb_io_fns.lbiof_write;
01017               break;
01018        case LBER_SOCKBUF_OPT_EXT_IO_FNS:
01019               extiofns = (struct lber_x_ext_io_fns *) value;
01020               if ( extiofns == NULL ) {
01021                      return( -1 );
01022               } else if ( extiofns->lbextiofn_size
01023                          == LBER_X_EXTIO_FNS_SIZE ) {
01024                      /* struct copy */
01025                      *extiofns = sb->sb_ext_io_fns;
01026               } else if ( extiofns->lbextiofn_size
01027                          == LBER_X_EXTIO_FNS_SIZE_REV0 ) {
01028                      /* backwards compatiblity for older struct */
01029                      extiofns->lbextiofn_read = sb->sb_ext_io_fns.lbextiofn_read;
01030                      extiofns->lbextiofn_write = sb->sb_ext_io_fns.lbextiofn_write;
01031                      extiofns->lbextiofn_socket_arg = sb->sb_ext_io_fns.lbextiofn_socket_arg;
01032               } else {
01033                      return( -1 );
01034               }
01035               break;
01036        default:
01037               return( -1 );
01038        }
01039 
01040        return( 0 );
01041 }
01042 
01043 
01044 /* new dboreham code below: */
01045 
01046 struct byte_buffer  {
01047        unsigned char *p;
01048        int offset;
01049        int length;
01050 };
01051 typedef struct byte_buffer byte_buffer;
01052 
01053 
01054 /* This call allocates us a BerElement structure plus some extra memory. 
01055  * It returns a pointer to the BerElement, plus a pointer to the extra memory.
01056  * This routine also allocates a ber data buffer within the same block, thus
01057  * saving a call to calloc later when we read data.
01058  */
01059 void*
01060 LDAP_CALL
01061 ber_special_alloc(size_t size, BerElement **ppBer)
01062 {
01063        char *mem = NULL;
01064 
01065        /* Make sure mem size requested is aligned */
01066        if (0 != ( size & 0x03 )) {
01067               size += (sizeof(long) - (size & 0x03));
01068        }
01069 
01070        mem = NSLBERI_MALLOC(sizeof(struct berelement) + EXBUFSIZ + size );
01071        if (NULL == mem) {
01072               return NULL;
01073        } 
01074        *ppBer = (BerElement*) (mem + size);
01075        memset(*ppBer,0,sizeof(struct berelement));
01076        (*ppBer)->ber_tag = LBER_DEFAULT;
01077        (*ppBer)->ber_buf = mem + size + sizeof(struct berelement);
01078        (*ppBer)->ber_ptr = (*ppBer)->ber_buf;
01079        (*ppBer)->ber_end = (*ppBer)->ber_buf + EXBUFSIZ;
01080        (*ppBer)->ber_flags = LBER_FLAG_NO_FREE_BUFFER;
01081        return (void*)mem;
01082 }
01083 
01084 void
01085 LDAP_CALL
01086 ber_special_free(void* buf, BerElement *ber)
01087 {
01088        if (!(ber->ber_flags & LBER_FLAG_NO_FREE_BUFFER)) {
01089               NSLBERI_FREE(ber->ber_buf);
01090        }
01091        NSLBERI_FREE( buf );
01092 }
01093 
01094 static int
01095 read_bytes(byte_buffer *b, unsigned char *return_buffer, int bytes_to_read)
01096 {
01097        /* copy up to bytes_to_read bytes into the caller's buffer, return the number of bytes copied */
01098        int bytes_to_copy = 0;
01099 
01100        if (bytes_to_read <= (b->length - b->offset) ) {
01101               bytes_to_copy = bytes_to_read;
01102        } else {
01103               bytes_to_copy = (b->length - b->offset);
01104        }
01105        if (1 == bytes_to_copy) {
01106               *return_buffer = *(b->p+b->offset++);
01107        } else 
01108        if (0 == bytes_to_copy) {
01109               ;
01110        } else
01111        {
01112               memcpy(return_buffer,b->p+b->offset,bytes_to_copy);
01113               b->offset += bytes_to_copy;
01114        }
01115        return bytes_to_copy;
01116 }
01117 
01118 /* return the tag - LBER_DEFAULT returned means trouble */
01119 static unsigned long
01120 get_buffer_tag(byte_buffer *sb )
01121 {
01122        unsigned char xbyte;
01123        unsigned long tag;
01124        char          *tagp;
01125        int           i;
01126 
01127        if ( (i = read_bytes( sb, &xbyte, 1 )) != 1 ) {
01128               return( LBER_DEFAULT );
01129        }
01130 
01131        if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
01132               return( (unsigned long) xbyte );
01133        }
01134 
01135        tagp = (char *) &tag;
01136        tagp[0] = xbyte;
01137        for ( i = 1; i < sizeof(long); i++ ) {
01138               if ( read_bytes( sb, &xbyte, 1 ) != 1 )
01139                      return( LBER_DEFAULT );
01140 
01141               tagp[i] = xbyte;
01142 
01143               if ( ! (xbyte & LBER_MORE_TAG_MASK) )
01144                      break;
01145        }
01146 
01147        /* tag too big! */
01148        if ( i == sizeof(long) )
01149               return( LBER_DEFAULT );
01150 
01151        /* want leading, not trailing 0's */
01152        return( tag >> (sizeof(long) - i - 1) );
01153 }
01154 
01155 /* Like ber_get_next, but from a byte buffer the caller already has. */
01156 /* Bytes_Scanned returns the number of bytes we actually looked at in the buffer. */
01157 /* ber_get_next_buffer is now implemented in terms of ber_get_next_buffer_ext */
01158 /* and is here for backward compatibility.  This new function allows us to pass */
01159 /* the Sockbuf structure along */
01160 
01161 unsigned long
01162 LDAP_CALL
01163 ber_get_next_buffer( void *buffer, size_t buffer_size, unsigned long *len,
01164     BerElement *ber, unsigned long *Bytes_Scanned )
01165 {
01166        return (ber_get_next_buffer_ext( buffer, buffer_size, len, ber,
01167               Bytes_Scanned, NULL));
01168 }
01169 
01170 unsigned long
01171 LDAP_CALL
01172 ber_get_next_buffer_ext( void *buffer, size_t buffer_size, unsigned long *len,
01173     BerElement *ber, unsigned long *Bytes_Scanned, Sockbuf *sock )
01174 {
01175        unsigned long tag = 0, netlen, toread;
01176        unsigned char lc;
01177        long          rc;
01178        int           noctets, diff;
01179        byte_buffer sb = {0};
01180 
01181 
01182        /*
01183         * Any ber element looks like this: tag length contents.
01184         * Assuming everything's ok, we return the tag byte (we
01185         * can assume a single byte), return the length in len,
01186         * and the rest of the undecoded element in buf.
01187         *
01188         * Assumptions:
01189         *     1) small tags (less than 128)
01190         *     2) definite lengths
01191         *     3) primitive encodings used whenever possible
01192         */
01193 
01194        /*
01195         * first time through - malloc the buffer, set up ptrs, and
01196         * read the tag and the length and as much of the rest as we can
01197         */
01198 
01199        sb.p = buffer;
01200        sb.length = buffer_size;
01201 
01202        if ( ber->ber_rwptr == NULL ) {
01203               /*
01204                * First, we read the tag.
01205                */
01206 
01207                 /* if we have been called before with a fragment not
01208                * containing a comlete length, we have no rwptr but
01209                * a tag already
01210                  */
01211               if ( ber->ber_tag == LBER_DEFAULT ) {
01212                      if ( (tag = get_buffer_tag( &sb )) == LBER_DEFAULT ) {
01213                             goto premature_exit;
01214                      }
01215                      ber->ber_tag = tag;
01216               }
01217 
01218               if((sock->sb_options & LBER_SOCKBUF_OPT_VALID_TAG) &&
01219                 (tag != sock->sb_valid_tag)) {
01220                      *Bytes_Scanned=0;
01221                      return( LBER_DEFAULT);
01222               }
01223 
01224               /*
01225                * Next, read the length.  The first byte contains the length
01226                * of the length.  If bit 8 is set, the length is the long
01227                * form, otherwise it's the short form.  We don't allow a
01228                * length that's greater than what we can hold in an unsigned
01229                * long.
01230                */
01231 
01232                 /* if the length is in long form and we don't get it in one
01233                  * fragment, we should handle this (TBD).
01234                  */
01235 
01236               *len = netlen = 0;
01237               if ( read_bytes( &sb, &lc, 1 ) != 1 ) {
01238                      goto premature_exit;
01239               }
01240               if ( lc & 0x80 ) {
01241                      noctets = (lc & 0x7f);
01242                      if ( noctets > sizeof(unsigned long) )
01243                             goto premature_exit;
01244                      diff = sizeof(unsigned long) - noctets;
01245                      if ( read_bytes( &sb, (unsigned char *)&netlen + diff,
01246                          noctets ) != noctets ) {
01247                             goto premature_exit;
01248                      }
01249                      *len = LBER_NTOHL( netlen );
01250               } else {
01251                      *len = lc;
01252               }
01253               ber->ber_len = *len;
01254 
01255               /*
01256                * Finally, malloc a buffer for the contents and read it in.
01257                * It's this buffer that's passed to all the other ber decoding
01258                * routines.
01259                */
01260 
01261 #if defined( DOS ) && !defined( _WIN32 )
01262               if ( *len > 65535 ) {       /* DOS can't allocate > 64K */
01263                      goto premature_exit;
01264               }
01265 #endif /* DOS && !_WIN32 */
01266 
01267                 if ( (sock != NULL)  &&
01268                   ( sock->sb_options & LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE )
01269                     && (*len > sock->sb_max_incoming) ) {
01270                         return( LBER_DEFAULT );
01271                 }
01272 
01273               if ( ber->ber_buf + *len > ber->ber_end ) {
01274                      if ( nslberi_ber_realloc( ber, *len ) != 0 )
01275                             goto premature_exit;
01276               }
01277               ber->ber_ptr = ber->ber_buf;
01278               ber->ber_end = ber->ber_buf + *len;
01279               ber->ber_rwptr = ber->ber_buf;
01280        }
01281 
01282        toread = (unsigned long)ber->ber_end - (unsigned long)ber->ber_rwptr;
01283        do {
01284               if ( (rc = read_bytes( &sb, (unsigned char *)ber->ber_rwptr,
01285                   (long)toread )) <= 0 ) {
01286                      goto premature_exit;
01287               }
01288 
01289               toread -= rc;
01290               ber->ber_rwptr += rc;
01291        } while ( toread > 0 );
01292 
01293        *len = ber->ber_len;
01294        *Bytes_Scanned = sb.offset;
01295        return( ber->ber_tag );
01296 
01297 premature_exit:
01298        /*
01299         * we're here because we hit the end of the buffer before seeing
01300         * all of the PDU
01301         */
01302        *Bytes_Scanned = sb.offset;
01303        return(LBER_DEFAULT);
01304 }
01305 
01306 
01307 /* The ber_flatten routine allocates a struct berval whose contents
01308  * are a BER encoding taken from the ber argument. The bvPtr pointer
01309  * points to the returned berval, which must be freed using
01310  * ber_bvfree().  This routine returns 0 on success and -1 on error.
01311  * The use of ber_flatten on a BerElement in which all '{' and '}'
01312  * format modifiers have not been properly matched can result in a
01313  * berval whose contents are not a valid BER encoding. 
01314  * Note that the ber_ptr is not modified.
01315  */
01316 int
01317 LDAP_CALL
01318 ber_flatten( BerElement *ber, struct berval **bvPtr )
01319 {
01320        struct berval *new;
01321        unsigned long len;
01322 
01323        /* allocate a struct berval */
01324        if ( (new = (struct berval *)NSLBERI_MALLOC( sizeof(struct berval) ))
01325            == NULL ) {
01326               return( -1 );
01327        }
01328 
01329        /*
01330         * Copy everything from the BerElement's ber_buf to ber_ptr
01331         * into the berval structure.
01332         */
01333        if ( ber == NULL ) {
01334            new->bv_val = NULL;
01335            new->bv_len = 0;
01336        } else {
01337            len = ber->ber_ptr - ber->ber_buf; 
01338            if ( ( new->bv_val = (char *)NSLBERI_MALLOC( len + 1 )) == NULL ) {
01339                   ber_bvfree( new );
01340                   return( -1 );
01341            }
01342            SAFEMEMCPY( new->bv_val, ber->ber_buf, (size_t)len ); 
01343            new->bv_val[len] = '\0';
01344            new->bv_len = len;
01345        }
01346 
01347        /* set bvPtr pointer to point to the returned berval */
01348        *bvPtr = new; 
01349 
01350         return( 0 );
01351 }
01352 
01353 
01354 /*
01355  * The ber_init function constructs and returns a new BerElement
01356  * containing a copy of the data in the bv argument.  ber_init
01357  * returns the null pointer on error.
01358  */
01359 BerElement *
01360 LDAP_CALL
01361 ber_init( const struct berval *bv )
01362 {
01363        BerElement *ber;
01364 
01365        /* construct BerElement */
01366        if (( ber = ber_alloc_t( 0 )) != NULLBER ) {
01367               /* copy data from the bv argument into BerElement */
01368               /* XXXmcs: had to cast unsigned long bv_len to long */
01369               if ( (ber_write ( ber, bv->bv_val, bv->bv_len, 0 ))
01370                   != (long)bv->bv_len ) {
01371                      ber_free( ber, 1 );
01372                      return( NULL );
01373               }
01374        }
01375        
01376        /*
01377         * reset ber_ptr back to the beginning of buffer so that this new
01378         * and initialized ber element can be READ
01379         */
01380        ber_reset( ber, 1);
01381 
01382        /*
01383         * return a ptr to a new BerElement containing a copy of the data
01384         * in the bv argument or a null pointer on error
01385         */
01386        return( ber );
01387 }
01388 
01389 
01390 /*
01391  * memory allocation functions.
01392  */
01393 void *
01394 nslberi_malloc( size_t size )
01395 {
01396        return( nslberi_memalloc_fns.lbermem_malloc == NULL ?
01397            malloc( size ) :
01398            nslberi_memalloc_fns.lbermem_malloc( size ));
01399 }
01400 
01401 
01402 void *
01403 nslberi_calloc( size_t nelem, size_t elsize )
01404 {
01405        return( nslberi_memalloc_fns.lbermem_calloc == NULL ?
01406            calloc(  nelem, elsize ) :
01407            nslberi_memalloc_fns.lbermem_calloc( nelem, elsize ));
01408 }
01409 
01410 
01411 void *
01412 nslberi_realloc( void *ptr, size_t size )
01413 {
01414        return( nslberi_memalloc_fns.lbermem_realloc == NULL ?
01415            realloc( ptr, size ) :
01416            nslberi_memalloc_fns.lbermem_realloc( ptr, size ));
01417 }
01418 
01419 
01420 void
01421 nslberi_free( void *ptr )
01422 {
01423        if ( nslberi_memalloc_fns.lbermem_free == NULL ) {
01424               free( ptr );
01425        } else {
01426               nslberi_memalloc_fns.lbermem_free( ptr );
01427        }
01428 }
01429 
01430 
01431 /*
01432  ******************************************************************************
01433  * functions to bridge the gap between new extended I/O functions that are
01434  *    installed using ber_sockbuf_set_option( ..., LBER_SOCKBUF_OPT_EXT_IO_FNS,
01435  *    ... ).
01436  *
01437  * the basic strategy is to use the new extended arg to hold a pointer to the
01438  *    Sockbuf itself so we can find the old functions and call them.
01439  * note that the integer socket s passed in is not used.  we use the sb_sd
01440  *    from the Sockbuf itself because it is the correct type.
01441  */
01442 static int
01443 nslberi_extread_compat( int s, void *buf, int len,
01444        struct lextiof_socket_private *arg )
01445 {
01446        Sockbuf       *sb = (Sockbuf *)arg;
01447 
01448        return( sb->sb_io_fns.lbiof_read( sb->sb_sd, buf, len ));
01449 }
01450 
01451 
01452 static int
01453 nslberi_extwrite_compat( int s, const void *buf, int len,
01454        struct lextiof_socket_private *arg )
01455 {
01456        Sockbuf       *sb = (Sockbuf *)arg;
01457 
01458        return( sb->sb_io_fns.lbiof_write( sb->sb_sd, buf, len ));
01459 }
01460 
01461 
01462 /*
01463  * Install I/O compatiblity functions.  This can't fail.
01464  */
01465 static void
01466 nslberi_install_compat_io_fns( Sockbuf *sb )
01467 {
01468        sb->sb_ext_io_fns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
01469        sb->sb_ext_io_fns.lbextiofn_read = nslberi_extread_compat;
01470        sb->sb_ext_io_fns.lbextiofn_write = nslberi_extwrite_compat;
01471        sb->sb_ext_io_fns.lbextiofn_writev = NULL;
01472        sb->sb_ext_io_fns.lbextiofn_socket_arg = (void *)sb;
01473 }
01474 /*
01475  * end of compat I/O functions
01476  ******************************************************************************
01477  */