Skip to content
Snippets Groups Projects
Commit 4298f5d9 authored by Howard Chu's avatar Howard Chu
Browse files

Rewrote ber_get_next, fixed byte-order dependency on ber_tag and optimized

parent fda6569a
No related branches found
No related tags found
No related merge requests found
...@@ -34,34 +34,6 @@ ...@@ -34,34 +34,6 @@
#include "lber-int.h" #include "lber-int.h"
static ber_slen_t
BerRead(
Sockbuf *sb,
unsigned char *buf,
ber_len_t len )
{
ber_slen_t c;
ber_slen_t nread = 0;
assert( sb != NULL );
assert( buf != NULL );
assert( SOCKBUF_VALID( sb ) );
while ( len > 0 ) {
if ( (c = ber_int_sb_read( sb, buf, len )) <= 0 ) {
if ( nread > 0 )
break;
return( c );
}
buf+=c;
nread+=c;
len-=c;
}
return( nread );
}
ber_slen_t ber_slen_t
ber_read( ber_read(
BerElement *ber, BerElement *ber,
...@@ -476,131 +448,126 @@ ber_get_next( ...@@ -476,131 +448,126 @@ ber_get_next(
* 2) definite lengths * 2) definite lengths
* 3) primitive encodings used whenever possible * 3) primitive encodings used whenever possible
*/ */
if (ber->ber_rwptr == NULL) { if (ber->ber_rwptr == NULL) {
/* XXYYZ /* XXYYZ
* dtest does like this assert. * dtest does like this assert.
*/ */
/* assert( ber->ber_buf == NULL ); */ /* assert( ber->ber_buf == NULL ); */
ber->ber_rwptr = (char *) &ber->ber_tag; ber->ber_rwptr = (char *) &ber->ber_len-1;
ber->ber_ptr = ber->ber_rwptr;
ber->ber_tag = 0; ber->ber_tag = 0;
} }
#undef PTR_IN_VAR while (ber->ber_rwptr > (char *)&ber->ber_tag && ber->ber_rwptr <
#define PTR_IN_VAR( ptr, var ) \ (char *)(&ber->ber_usertag + 1)) {
(((ptr)>=(char *) &(var)) && ((ptr)< (char *) &(var)+sizeof(var))) int i;
char buf[sizeof(ber->ber_len)-1];
if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag)) { ber_len_t tlen = 0;
if (ber->ber_rwptr == (char *) &ber->ber_tag) {
if (ber_int_sb_read( sb, ber->ber_rwptr, 1)<=0)
return LBER_DEFAULT;
if ((ber->ber_rwptr[0] & LBER_BIG_TAG_MASK) if ((i=ber_int_sb_read( sb, ber->ber_rwptr,
!= LBER_BIG_TAG_MASK) (char *)(&ber->ber_usertag+1)-ber->ber_rwptr))<=0) {
{ return LBER_DEFAULT;
ber->ber_tag = ber->ber_rwptr[0];
ber->ber_rwptr = (char *) &ber->ber_usertag;
goto get_lenbyte;
}
ber->ber_rwptr++;
} }
do {
/* reading the tag... */
if (ber_int_sb_read( sb, ber->ber_rwptr, 1)<=0) {
return LBER_DEFAULT;
}
if (! (ber->ber_rwptr[0] & LBER_MORE_TAG_MASK) ) { ber->ber_rwptr += i;
ber->ber_tag>>=sizeof(ber->ber_tag) -
((char *) &ber->ber_tag - ber->ber_rwptr); /* We got at least one byte, try to parse the tag. */
ber->ber_rwptr = (char *) &ber->ber_usertag; if (ber->ber_ptr == (char *)&ber->ber_len-1) {
goto get_lenbyte; ber_tag_t tag;
unsigned char *p = (unsigned char *)ber->ber_ptr;
tag = *p++;
if ((tag & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK) {
for (i=1; (char *)p<ber->ber_rwptr; i++,p++) {
tag <<= 8;
tag |= *p;
if (!(*p & LBER_MORE_TAG_MASK))
break;
/* Is the tag too big? */
if (i == sizeof(ber_tag_t)-1) {
errno = ERANGE;
return LBER_DEFAULT;
}
}
/* Did we run out of bytes? */
if ((char *)p == ber->ber_rwptr) {
return LBER_DEFAULT;
}
p++;
} }
} while( PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag )); ber->ber_tag = tag;
ber->ber_ptr = (char *)p;
errno = ERANGE; /* this is a serious error. */
return LBER_DEFAULT;
}
get_lenbyte:
if (ber->ber_rwptr==(char *) &ber->ber_usertag) {
unsigned char c;
if (ber_int_sb_read( sb, (char *) &c, 1)<=0) {
return LBER_DEFAULT;
} }
if (c & 0x80U) { /* Now look for the length */
int len = c & 0x7fU; if (*ber->ber_ptr & 0x80) { /* multi-byte */
if ( (len==0) || ( len>sizeof( ber->ber_len ) ) ) { int llen = *(unsigned char *)ber->ber_ptr++ & 0x7f;
if (llen > sizeof(ber_len_t)) {
errno = ERANGE; errno = ERANGE;
return LBER_DEFAULT; return LBER_DEFAULT;
} }
/* Not enough bytes? */
ber->ber_rwptr = (char *) &ber->ber_len + if (ber->ber_rwptr - ber->ber_ptr < llen) {
sizeof(ber->ber_len) - len; return LBER_DEFAULT;
ber->ber_len = 0; }
for (i=0; i<llen && ber->ber_ptr<ber->ber_rwptr; i++,ber->ber_ptr++) {
tlen <<=8;
tlen |= *(unsigned char *)ber->ber_ptr;
}
} else { } else {
ber->ber_len = c; tlen = *(unsigned char *)ber->ber_ptr++;
goto fill_buffer;
} }
} /* Are there leftover data bytes inside ber->ber_len? */
if (ber->ber_ptr < (char *)&ber->ber_usertag) {
if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_len)) { i = (char *)&ber->ber_usertag - ber->ber_ptr;
unsigned char netlen[sizeof(ber_len_t)]; AC_MEMCPY(buf, ber->ber_ptr, i);
ber->ber_ptr += i;
ber_slen_t res; } else {
ber_slen_t to_go; i = 0;
to_go = (char *) &ber->ber_len + sizeof( ber->ber_len ) -
ber->ber_rwptr;
assert( to_go > 0 );
res = BerRead( sb, netlen, to_go );
if (res <= 0) {
return LBER_DEFAULT;
} }
ber->ber_rwptr += res; ber->ber_len = tlen;
/* convert length. */ /* now fill the buffer. */
for( to_go = 0; to_go < res ; to_go++ ) {
ber->ber_len <<= 8;
ber->ber_len |= netlen[to_go];
}
if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_len)) { /* make sure length is reasonable */
if ( ber->ber_len == 0 ) {
errno = ERANGE;
return LBER_DEFAULT; return LBER_DEFAULT;
} } else if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) {
}
fill_buffer:
/* now fill the buffer. */
/* make sure length is reasonable */
if ( ber->ber_len == 0 ) {
errno = ERANGE;
return LBER_DEFAULT;
} else if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) {
#ifdef NEW_LOGGING #ifdef NEW_LOGGING
LDAP_LOG(( "liblber", LDAP_LEVEL_ERR, LDAP_LOG(( "liblber", LDAP_LEVEL_ERR,
"ber_get_next: sockbuf_max_incoming limit hit " "ber_get_next: sockbuf_max_incoming limit hit "
"(%d > %d)\n", ber->ber_len, sb->sb_max_incoming )); "(%d > %d)\n", ber->ber_len, sb->sb_max_incoming ));
#else #else
ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug, ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug,
"ber_get_next: sockbuf_max_incoming limit hit " "ber_get_next: sockbuf_max_incoming limit hit "
"(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming ); "(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming );
#endif #endif
errno = ERANGE; errno = ERANGE;
return LBER_DEFAULT; return LBER_DEFAULT;
} }
if (ber->ber_buf==NULL) {
ber->ber_buf = (char *) LBER_MALLOC( ber->ber_len + 1 );
if (ber->ber_buf==NULL) { if (ber->ber_buf==NULL) {
return LBER_DEFAULT; ber->ber_buf = (char *) LBER_MALLOC( ber->ber_len + 1 );
if (ber->ber_buf==NULL) {
return LBER_DEFAULT;
}
ber->ber_end = ber->ber_buf + ber->ber_len;
if (i) {
AC_MEMCPY(ber->ber_buf, buf, i);
}
if (ber->ber_ptr < ber->ber_rwptr) {
AC_MEMCPY(ber->ber_buf + i, ber->ber_ptr, ber->ber_rwptr-
ber->ber_ptr);
i += ber->ber_rwptr - ber->ber_ptr;
}
ber->ber_ptr = ber->ber_buf;
ber->ber_usertag = 0;
if (i == ber->ber_len) {
goto done;
}
ber->ber_rwptr = ber->ber_buf + i;
} }
ber->ber_rwptr = ber->ber_buf;
ber->ber_ptr = ber->ber_buf;
ber->ber_end = ber->ber_buf + ber->ber_len;
} }
if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) { if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) {
...@@ -623,7 +590,7 @@ fill_buffer: ...@@ -623,7 +590,7 @@ fill_buffer:
#endif #endif
return LBER_DEFAULT; return LBER_DEFAULT;
} }
done:
ber->ber_rwptr = NULL; ber->ber_rwptr = NULL;
*len = ber->ber_len; *len = ber->ber_len;
if ( ber->ber_debug ) { if ( ber->ber_debug ) {
......
...@@ -69,10 +69,10 @@ struct berelement { ...@@ -69,10 +69,10 @@ struct berelement {
#define ber_options ber_opts.lbo_options #define ber_options ber_opts.lbo_options
#define ber_debug ber_opts.lbo_debug #define ber_debug ber_opts.lbo_debug
ber_tag_t ber_usertag; /* Do not change the order of these 3 fields! see ber_get_next */
ber_tag_t ber_tag; ber_tag_t ber_tag;
ber_len_t ber_len; ber_len_t ber_len;
ber_tag_t ber_usertag;
char *ber_buf; char *ber_buf;
char *ber_ptr; char *ber_ptr;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment