1 /* io.c - ber general i/o routines */
2 /* $OpenLDAP: pkg/ldap/libraries/liblber/io.c,v 1.111.2.8 2008/07/09 23:16:48 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
17 * All rights reserved.
19 * Redistribution and use in source and binary forms are permitted
20 * provided that this notice is preserved and that due credit is given
21 * to the University of Michigan at Ann Arbor. The name of the University
22 * may not be used to endorse or promote products derived from this
23 * software without specific prior written permission. This software
24 * is provided ``as is'' without express or implied warranty.
27 * This work was originally developed by the University of Michigan
28 * (as part of U-MICH LDAP).
35 #include <ac/stdlib.h>
39 #include <ac/socket.h>
40 #include <ac/string.h>
41 #include <ac/unistd.h>
55 ber_len_t actuallen
, nleft
;
57 assert( ber
!= NULL
);
59 assert( LBER_VALID( ber
) );
61 nleft
= ber_pvt_ber_remaining( ber
);
62 actuallen
= nleft
< len
? nleft
: len
;
63 ber
->ber_ptr
+= actuallen
;
64 ber
->ber_tag
= *(unsigned char *)ber
->ber_ptr
;
66 return( (ber_slen_t
) actuallen
);
75 ber_len_t actuallen
, nleft
;
77 assert( ber
!= NULL
);
78 assert( buf
!= NULL
);
80 assert( LBER_VALID( ber
) );
82 nleft
= ber_pvt_ber_remaining( ber
);
83 actuallen
= nleft
< len
? nleft
: len
;
85 AC_MEMCPY( buf
, ber
->ber_ptr
, actuallen
);
87 ber
->ber_ptr
+= actuallen
;
89 return( (ber_slen_t
) actuallen
);
99 assert( ber
!= NULL
);
100 assert( buf
!= NULL
);
102 assert( LBER_VALID( ber
) );
104 if ( nosos
|| ber
->ber_sos
== NULL
) {
105 if ( ber
->ber_ptr
+ len
> ber
->ber_end
) {
106 if ( ber_realloc( ber
, len
) != 0 ) return( -1 );
108 AC_MEMCPY( ber
->ber_ptr
, buf
, (size_t)len
);
110 return( (ber_slen_t
) len
);
113 if ( ber
->ber_sos
->sos_ptr
+ len
> ber
->ber_end
) {
114 if ( ber_realloc( ber
, len
) != 0 ) return( -1 );
116 AC_MEMCPY( ber
->ber_sos
->sos_ptr
, buf
, (size_t)len
);
117 ber
->ber_sos
->sos_ptr
+= len
;
118 ber
->ber_sos
->sos_clen
+= len
;
119 return( (ber_slen_t
) len
);
124 ber_realloc( BerElement
*ber
, ber_len_t len
)
131 assert( ber
!= NULL
);
133 assert( LBER_VALID( ber
) );
135 total
= ber_pvt_ber_total( ber
);
137 #define LBER_EXBUFSIZ 4060 /* a few words less than 2^N for binary buddy */
138 #if defined( LBER_EXBUFSIZ ) && LBER_EXBUFSIZ > 0
140 /* don't realloc by small amounts */
141 total
+= len
< LBER_EXBUFSIZ
? LBER_EXBUFSIZ
: len
;
143 { /* not sure what value this adds */
144 ber_len_t have
= (total
+ (LBER_EXBUFSIZE
- 1)) / LBER_EXBUFSIZ
;
145 ber_len_t need
= (len
+ (LBER_EXBUFSIZ
- 1)) / LBER_EXBUFSIZ
;
146 total
= ( have
+ need
) * LBER_EXBUFSIZ
;
150 total
+= len
; /* realloc just what's needed */
153 oldbuf
= ber
->ber_buf
;
155 ber
->ber_buf
= (char *) ber_memrealloc_x( oldbuf
, total
, ber
->ber_memctx
);
157 if ( ber
->ber_buf
== NULL
) {
158 ber
->ber_buf
= oldbuf
;
162 ber
->ber_end
= ber
->ber_buf
+ total
;
165 * If the stinking thing was moved, we need to go through and
166 * reset all the sos and ber pointers. Offsets would've been
167 * a better idea... oh well.
170 if ( ber
->ber_buf
!= oldbuf
) {
171 ber
->ber_ptr
= ber
->ber_buf
+ (ber
->ber_ptr
- oldbuf
);
173 for ( s
= ber
->ber_sos
; s
!= NULL
; s
= s
->sos_next
) {
174 off
= s
->sos_first
- oldbuf
;
175 s
->sos_first
= ber
->ber_buf
+ off
;
177 off
= s
->sos_ptr
- oldbuf
;
178 s
->sos_ptr
= ber
->ber_buf
+ off
;
186 ber_free_buf( BerElement
*ber
)
190 assert( LBER_VALID( ber
) );
192 if ( ber
->ber_buf
) ber_memfree_x( ber
->ber_buf
, ber
->ber_memctx
);
194 for( s
= ber
->ber_sos
; s
!= NULL
; s
= next
) {
196 ber_memfree_x( s
, ber
->ber_memctx
);
201 ber
->ber_valid
= LBER_UNINITIALIZED
;
205 ber_free( BerElement
*ber
, int freebuf
)
208 LDAP_MEMORY_DEBUG_ASSERT( ber
!= NULL
);
212 if( freebuf
) ber_free_buf( ber
);
214 ber_memfree_x( (char *) ber
, ber
->ber_memctx
);
218 ber_flush( Sockbuf
*sb
, BerElement
*ber
, int freeit
)
220 return ber_flush2( sb
, ber
,
221 freeit
? LBER_FLUSH_FREE_ON_SUCCESS
222 : LBER_FLUSH_FREE_NEVER
);
226 ber_flush2( Sockbuf
*sb
, BerElement
*ber
, int freeit
)
231 assert( sb
!= NULL
);
232 assert( ber
!= NULL
);
234 assert( SOCKBUF_VALID( sb
) );
235 assert( LBER_VALID( ber
) );
237 if ( ber
->ber_rwptr
== NULL
) {
238 ber
->ber_rwptr
= ber
->ber_buf
;
240 towrite
= ber
->ber_ptr
- ber
->ber_rwptr
;
242 if ( sb
->sb_debug
) {
243 ber_log_printf( LDAP_DEBUG_TRACE
, sb
->sb_debug
,
244 "ber_flush2: %ld bytes to sd %ld%s\n",
245 towrite
, (long) sb
->sb_fd
,
246 ber
->ber_rwptr
!= ber
->ber_buf
? " (re-flush)" : "" );
247 ber_log_bprint( LDAP_DEBUG_PACKETS
, sb
->sb_debug
,
248 ber
->ber_rwptr
, towrite
);
251 while ( towrite
> 0 ) {
254 rc
= ber_int_sb_write( sb
, ber
->ber_rwptr
, 1 );
256 rc
= ber_int_sb_write( sb
, ber
->ber_rwptr
, towrite
);
259 if ( freeit
& LBER_FLUSH_FREE_ON_ERROR
) ber_free( ber
, 1 );
263 ber
->ber_rwptr
+= rc
;
266 if ( freeit
& LBER_FLUSH_FREE_ON_SUCCESS
) ber_free( ber
, 1 );
272 ber_alloc_t( int options
)
276 ber
= (BerElement
*) LBER_CALLOC( 1, sizeof(BerElement
) );
282 ber
->ber_valid
= LBER_VALID_BERELEMENT
;
283 ber
->ber_tag
= LBER_DEFAULT
;
284 ber
->ber_options
= options
;
285 ber
->ber_debug
= ber_int_debug
;
287 assert( LBER_VALID( ber
) );
292 ber_alloc( void ) /* deprecated */
294 return ber_alloc_t( 0 );
298 der_alloc( void ) /* deprecated */
300 return ber_alloc_t( LBER_USE_DER
);
304 ber_dup( BerElement
*ber
)
308 assert( ber
!= NULL
);
309 assert( LBER_VALID( ber
) );
311 if ( (new = ber_alloc_t( ber
->ber_options
)) == NULL
) {
317 assert( LBER_VALID( new ) );
323 ber_init2( BerElement
*ber
, struct berval
*bv
, int options
)
325 assert( ber
!= NULL
);
327 (void) memset( (char *)ber
, '\0', sizeof( BerElement
));
328 ber
->ber_valid
= LBER_VALID_BERELEMENT
;
329 ber
->ber_tag
= LBER_DEFAULT
;
330 ber
->ber_options
= (char) options
;
331 ber
->ber_debug
= ber_int_debug
;
334 ber
->ber_buf
= bv
->bv_val
;
335 ber
->ber_ptr
= ber
->ber_buf
;
336 ber
->ber_end
= ber
->ber_buf
+ bv
->bv_len
;
339 assert( LBER_VALID( ber
) );
342 /* OLD U-Mich ber_init() */
344 ber_init_w_nullc( BerElement
*ber
, int options
)
346 ber_init2( ber
, NULL
, options
);
349 /* New C-API ber_init() */
350 /* This function constructs a BerElement containing a copy
351 ** of the data in the bv argument.
354 ber_init( struct berval
*bv
)
358 assert( bv
!= NULL
);
364 ber
= ber_alloc_t( 0 );
367 /* allocation failed */
372 if ( ((ber_len_t
) ber_write ( ber
, bv
->bv_val
, bv
->bv_len
, 0 ))
375 /* write failed, so free and return NULL */
380 ber_reset( ber
, 1 ); /* reset the pointer to the start of the buffer */
384 /* New C-API ber_flatten routine */
385 /* This routine allocates a struct berval whose contents are a BER
386 ** encoding taken from the ber argument. The bvPtr pointer points to
387 ** the returned berval.
389 ** ber_flatten2 is the same, but uses a struct berval passed by
390 ** the caller. If alloc is 0 the returned bv uses the ber buf directly.
397 assert( bv
!= NULL
);
404 /* ber is null, create an empty berval */
409 /* copy the berval */
410 ber_len_t len
= ber_pvt_ber_write( ber
);
413 bv
->bv_val
= (char *) ber_memalloc_x( len
+ 1, ber
->ber_memctx
);
414 if ( bv
->bv_val
== NULL
) {
417 AC_MEMCPY( bv
->bv_val
, ber
->ber_buf
, len
);
419 bv
->bv_val
= ber
->ber_buf
;
421 bv
->bv_val
[len
] = '\0';
429 struct berval
**bvPtr
)
434 assert( bvPtr
!= NULL
);
440 bv
= ber_memalloc_x( sizeof(struct berval
), ber
->ber_memctx
);
444 rc
= ber_flatten2(ber
, bv
, 1);
446 ber_memfree_x(bv
, ber
->ber_memctx
);
454 ber_reset( BerElement
*ber
, int was_writing
)
456 assert( ber
!= NULL
);
457 assert( LBER_VALID( ber
) );
460 ber
->ber_end
= ber
->ber_ptr
;
461 ber
->ber_ptr
= ber
->ber_buf
;
464 ber
->ber_ptr
= ber
->ber_end
;
467 ber
->ber_rwptr
= NULL
;
471 * A rewrite of ber_get_next that can safely be called multiple times
472 * for the same packet. It will simply continue where it stopped until
473 * a full packet is read.
484 assert( sb
!= NULL
);
485 assert( len
!= NULL
);
486 assert( ber
!= NULL
);
488 assert( SOCKBUF_VALID( sb
) );
489 assert( LBER_VALID( ber
) );
491 if ( ber
->ber_debug
& LDAP_DEBUG_TRACE
) {
492 ber_log_printf( LDAP_DEBUG_TRACE
, ber
->ber_debug
,
497 * Any ber element looks like this: tag length contents.
498 * Assuming everything's ok, we return the tag byte (we
499 * can assume a single byte), return the length in len,
500 * and the rest of the undecoded element in buf.
503 * 1) small tags (less than 128)
504 * 2) definite lengths
505 * 3) primitive encodings used whenever possible
507 * The code also handles multi-byte tags. The first few bytes
508 * of the message are read to check for multi-byte tags and
509 * lengths. These bytes are temporarily stored in the ber_tag,
510 * ber_len, and ber_usertag fields of the berelement until
511 * tag/len parsing is complete. After this parsing, any leftover
512 * bytes and the rest of the message are copied into the ber_buf.
514 * We expect tag and len to be at most 32 bits wide.
517 if (ber
->ber_rwptr
== NULL
) {
518 assert( ber
->ber_buf
== NULL
);
519 ber
->ber_rwptr
= (char *) &ber
->ber_len
-1;
520 ber
->ber_ptr
= ber
->ber_rwptr
;
524 while (ber
->ber_rwptr
> (char *)&ber
->ber_tag
&& ber
->ber_rwptr
<
525 (char *)&ber
->ber_len
+ LENSIZE
*2) {
527 char buf
[sizeof(ber
->ber_len
)-1];
530 /* The tag & len can be at most 9 bytes; we try to read up to 8 here */
532 sblen
=((char *)&ber
->ber_len
+ LENSIZE
*2 - 1)-ber
->ber_rwptr
;
533 /* Trying to read the last len byte of a 9 byte tag+len */
536 sblen
=ber_int_sb_read( sb
, ber
->ber_rwptr
, sblen
);
537 if (sblen
<=0) return LBER_DEFAULT
;
538 ber
->ber_rwptr
+= sblen
;
540 /* We got at least one byte, try to parse the tag. */
541 if (ber
->ber_ptr
== (char *)&ber
->ber_len
-1) {
543 unsigned char *p
= (unsigned char *)ber
->ber_ptr
;
545 if ((tag
& LBER_BIG_TAG_MASK
) == LBER_BIG_TAG_MASK
) {
547 for (i
=1; (char *)p
<ber
->ber_rwptr
; i
++) {
550 if (!(tag
& LBER_MORE_TAG_MASK
))
552 /* Is the tag too big? */
553 if (i
== sizeof(ber_tag_t
)-1) {
558 /* Did we run out of bytes? */
559 if ((char *)p
== ber
->ber_rwptr
) {
560 #if defined( EWOULDBLOCK )
561 sock_errset(EWOULDBLOCK
);
562 #elif defined( EAGAIN )
569 ber
->ber_ptr
= (char *)p
;
572 if ( ber
->ber_ptr
== ber
->ber_rwptr
) {
573 #if defined( EWOULDBLOCK )
574 sock_errset(EWOULDBLOCK
);
575 #elif defined( EAGAIN )
581 /* Now look for the length */
582 if (*ber
->ber_ptr
& 0x80) { /* multi-byte */
584 unsigned char *p
= (unsigned char *)ber
->ber_ptr
;
585 int llen
= *p
++ & 0x7f;
586 if (llen
> LENSIZE
) {
590 /* Not enough bytes? */
591 if (ber
->ber_rwptr
- (char *)p
< llen
) {
592 #if defined( EWOULDBLOCK )
593 sock_errset(EWOULDBLOCK
);
594 #elif defined( EAGAIN )
599 for (i
=0; i
<llen
; i
++) {
603 ber
->ber_ptr
= (char *)p
;
605 tlen
= *(unsigned char *)ber
->ber_ptr
++;
608 /* Are there leftover data bytes inside ber->ber_len? */
609 if (ber
->ber_ptr
< (char *)&ber
->ber_usertag
) {
610 if (ber
->ber_rwptr
< (char *)&ber
->ber_usertag
) {
611 sblen
= ber
->ber_rwptr
- ber
->ber_ptr
;
613 sblen
= (char *)&ber
->ber_usertag
- ber
->ber_ptr
;
615 AC_MEMCPY(buf
, ber
->ber_ptr
, sblen
);
616 ber
->ber_ptr
+= sblen
;
622 /* now fill the buffer. */
624 /* make sure length is reasonable */
625 if ( ber
->ber_len
== 0 ) {
630 if ( sb
->sb_max_incoming
&& ber
->ber_len
> sb
->sb_max_incoming
) {
631 ber_log_printf( LDAP_DEBUG_CONNS
, ber
->ber_debug
,
632 "ber_get_next: sockbuf_max_incoming exceeded "
633 "(%ld > %ld)\n", ber
->ber_len
, sb
->sb_max_incoming
);
638 if (ber
->ber_buf
==NULL
) {
639 ber_len_t l
= ber
->ber_rwptr
- ber
->ber_ptr
;
640 /* ber->ber_ptr is always <= ber->ber->ber_rwptr.
641 * make sure ber->ber_len agrees with what we've
644 if ( ber
->ber_len
< sblen
+ l
) {
648 ber
->ber_buf
= (char *) ber_memalloc_x( ber
->ber_len
+ 1, ber
->ber_memctx
);
649 if (ber
->ber_buf
==NULL
) {
652 ber
->ber_end
= ber
->ber_buf
+ ber
->ber_len
;
654 AC_MEMCPY(ber
->ber_buf
, buf
, sblen
);
657 AC_MEMCPY(ber
->ber_buf
+ sblen
, ber
->ber_ptr
, l
);
660 *ber
->ber_end
= '\0';
661 ber
->ber_ptr
= ber
->ber_buf
;
662 ber
->ber_usertag
= 0;
663 if ((ber_len_t
)sblen
== ber
->ber_len
) {
666 ber
->ber_rwptr
= ber
->ber_buf
+ sblen
;
670 if ((ber
->ber_rwptr
>=ber
->ber_buf
) && (ber
->ber_rwptr
<ber
->ber_end
)) {
674 to_go
= ber
->ber_end
- ber
->ber_rwptr
;
678 res
= ber_int_sb_read( sb
, ber
->ber_rwptr
, to_go
);
679 if (res
<=0) return LBER_DEFAULT
;
683 #if defined( EWOULDBLOCK )
684 sock_errset(EWOULDBLOCK
);
685 #elif defined( EAGAIN )
691 ber
->ber_rwptr
= NULL
;
693 if ( ber
->ber_debug
) {
694 ber_log_printf( LDAP_DEBUG_TRACE
, ber
->ber_debug
,
695 "ber_get_next: tag 0x%lx len %ld contents:\n",
696 ber
->ber_tag
, ber
->ber_len
);
697 ber_log_dump( LDAP_DEBUG_BER
, ber
->ber_debug
, ber
, 1 );
699 return (ber
->ber_tag
);
702 assert( 0 ); /* ber structure is messed up ?*/
707 ber_start( BerElement
* ber
)
713 ber_len( BerElement
* ber
)
715 return ( ber
->ber_end
- ber
->ber_buf
);
719 ber_ptrlen( BerElement
* ber
)
721 return ( ber
->ber_ptr
- ber
->ber_buf
);
725 ber_rewind ( BerElement
* ber
)
727 ber
->ber_rwptr
= NULL
;
729 ber
->ber_end
= ber
->ber_ptr
;
730 ber
->ber_ptr
= ber
->ber_buf
;
734 ber_remaining( BerElement
* ber
)
736 return ber_pvt_ber_remaining( ber
);