io.c 13.1 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* io.c - ber general i/o routines */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
4
5
/*
 * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
6
/* Portions
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
9
10
11
12
13
14
15
16
17
 * Copyright (c) 1990 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
18
19
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
20
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
21
22

#include <ac/stdlib.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
23

Kurt Zeilenga's avatar
Kurt Zeilenga committed
24
25
26
27
28
#include <ac/ctype.h>
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/unistd.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
29

Kurt Zeilenga's avatar
Kurt Zeilenga committed
30
31
#ifdef HAVE_IO_H
#include <io.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
33
#endif

34
35
36
#undef LDAP_F_PRE
#define LDAP_F_PRE LDAP_F_EXPORT

37
#include "lber-int.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
38

39
40
41
42
43
44
45
46
static ber_slen_t BerRead LDAP_P((
	Sockbuf *sb,
	char *buf,
	ber_len_t len ));

static int ber_realloc LDAP_P((
	BerElement *ber,
	ber_len_t len ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
47
48
49

#define EXBUFSIZ	1024

50
51
52
53
54
55
56
57
/* probably far too large... */
#define MAX_BERBUFSIZE	(128*1024)

#if defined( DOS ) && !defined( _WIN32 ) && (MAX_BERBUFSIZE > 65535)
# undef MAX_BERBUFSIZE
# define MAX_BERBUFSIZE 65535
#endif

58
59
60
61
62
static ber_slen_t
BerRead(
	Sockbuf *sb,
	char *buf,
	ber_len_t len )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
63
{
64
65
	ber_slen_t	c;
	ber_slen_t	nread = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
66

Kurt Zeilenga's avatar
Kurt Zeilenga committed
67
68
69
	assert( sb != NULL );
	assert( buf != NULL );

70
71
	assert( SOCKBUF_VALID( sb ) );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
72
	while ( len > 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
73
		if ( (c = ber_pvt_sb_read( sb, buf, len )) <= 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
74
75
76
77
			if ( nread > 0 )
				break;
			return( c );
		}
78
79
80
		buf+= c;
		nread+=c;
		len-=c;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
81
82
83
84
85
	}

	return( nread );
}

86
87
88
89
90
ber_slen_t
ber_read(
	BerElement *ber,
	char *buf,
	ber_len_t len )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
91
{
92
	ber_len_t	actuallen, nleft;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93

Kurt Zeilenga's avatar
Kurt Zeilenga committed
94
95
96
	assert( ber != NULL );
	assert( buf != NULL );

97
98
	assert( BER_VALID( ber ) );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
99
100
101
	nleft = ber->ber_end - ber->ber_ptr;
	actuallen = nleft < len ? nleft : len;

102
	SAFEMEMCPY( buf, ber->ber_ptr, actuallen );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
103
104
105

	ber->ber_ptr += actuallen;

106
	return( (ber_slen_t) actuallen );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
107
108
}

109
ber_slen_t
Kurt Zeilenga's avatar
Kurt Zeilenga committed
110
111
112
ber_write(
	BerElement *ber,
	LDAP_CONST char *buf,
113
	ber_len_t len,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
114
	int nosos )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
115
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
116
117
118
	assert( ber != NULL );
	assert( buf != NULL );

119
120
	assert( BER_VALID( ber ) );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
121
122
123
124
125
126
127
	if ( nosos || ber->ber_sos == NULL ) {
		if ( ber->ber_ptr + len > ber->ber_end ) {
			if ( ber_realloc( ber, len ) != 0 )
				return( -1 );
		}
		SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
		ber->ber_ptr += len;
128
129
		return( (ber_slen_t) len );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
130
131
132
133
134
135
136
137
	} else {
		if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
			if ( ber_realloc( ber, len ) != 0 )
				return( -1 );
		}
		SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
		ber->ber_sos->sos_ptr += len;
		ber->ber_sos->sos_clen += len;
138
		return( (ber_slen_t) len );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
139
140
141
142
	}
}

static int
143
ber_realloc( BerElement *ber, ber_len_t len )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
144
{
145
	ber_len_t	need, have, total;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
146
147
148
149
	Seqorset	*s;
	long		off;
	char		*oldbuf;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
150
151
152
	assert( ber != NULL );
	assert( len > 0 );

153
154
	assert( BER_VALID( ber ) );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
155
156
157
158
159
160
	have = (ber->ber_end - ber->ber_buf) / EXBUFSIZ;
	need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
	total = have * EXBUFSIZ + need * EXBUFSIZ;

	oldbuf = ber->ber_buf;

161
162
	ber->ber_buf = (char *) LBER_REALLOC( ber->ber_buf, total );
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
163
	if ( ber->ber_buf == NULL ) {
164
		ber->ber_buf = oldbuf;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
165
		return( -1 );
166
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
167
168
169
170
171
172
173
174
175
176
177
178

	ber->ber_end = ber->ber_buf + total;

	/*
	 * If the stinking thing was moved, we need to go through and
	 * reset all the sos and ber pointers.  Offsets would've been
	 * a better idea... oh well.
	 */

	if ( ber->ber_buf != oldbuf ) {
		ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);

179
		for ( s = ber->ber_sos; s != NULL; s = s->sos_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
			off = s->sos_first - oldbuf;
			s->sos_first = ber->ber_buf + off;

			off = s->sos_ptr - oldbuf;
			s->sos_ptr = ber->ber_buf + off;
		}
	}

	return( 0 );
}

void
ber_free( BerElement *ber, int freebuf )
{
194
#ifdef LDAP_MEMORY_DEBUG
Kurt Zeilenga's avatar
Kurt Zeilenga committed
195
	assert( ber != NULL );
196
197
198
199
200
201
#endif

	if( ber == NULL ) {
		return;
	}

202
	assert( BER_VALID( ber ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
203

Kurt Zeilenga's avatar
Kurt Zeilenga committed
204
	if ( freebuf && ber->ber_buf != NULL )
205
		LBER_FREE( ber->ber_buf );
206

Kurt Zeilenga's avatar
Kurt Zeilenga committed
207
	ber->ber_buf = NULL;
208
	ber->ber_valid = LBER_UNINITIALIZED;
209

210
	LBER_FREE( (char *) ber );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
211
212
213
214
215
}

int
ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
{
216
217
	ber_len_t	nwritten, towrite;
	ber_slen_t	rc;	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
218

Kurt Zeilenga's avatar
Kurt Zeilenga committed
219
220
221
	assert( sb != NULL );
	assert( ber != NULL );

222
223
224
	assert( SOCKBUF_VALID( ber ) );
	assert( BER_VALID( ber ) );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
225
226
227
228
229
	if ( ber->ber_rwptr == NULL ) {
		ber->ber_rwptr = ber->ber_buf;
	}
	towrite = ber->ber_ptr - ber->ber_rwptr;

230
	if ( sb->sb_debug ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
231
		ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
232
			"ber_flush: %ld bytes to sd %ld%s\n", towrite,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
233
		    (long) sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
234
		    : "" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
235
		ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug,
236
			ber->ber_rwptr, towrite );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
237
	}
238

239
#if HAVE_WRITE
Kurt Zeilenga's avatar
Kurt Zeilenga committed
240
	if ( sb->sb_options & (LBER_TO_FILE | LBER_TO_FILE_ONLY) ) {
241
		rc = write( sb->sb_fd, ber->ber_rwptr, towrite );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
242
		if ( sb->sb_options & LBER_TO_FILE_ONLY ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
243
244
			if ( freeit )
				ber_free( ber, 1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
245
246
247
248
			return( (int)rc );
		}
	}
#endif
249
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
250
251
	nwritten = 0;
	do {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
252
		rc = ber_pvt_sb_write( sb, ber->ber_rwptr, towrite );
253
254
		if (rc<=0) {
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
		}
		towrite -= rc;
		nwritten += rc;
		ber->ber_rwptr += rc;
	} while ( towrite > 0 );

	if ( freeit )
		ber_free( ber, 1 );

	return( 0 );
}

BerElement *
ber_alloc_t( int options )
{
	BerElement	*ber;

272
273
    ber_int_options.lbo_valid = LBER_INITIALIZED;

274
	ber = (BerElement *) LBER_CALLOC( 1, sizeof(BerElement) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
275

276
277
	if ( ber == NULL )
		return( NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
278

279
	ber->ber_valid = LBER_VALID_BERELEMENT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
280
	ber->ber_tag = LBER_DEFAULT;
281
	ber->ber_options = options;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
282
	ber->ber_debug = ber_int_debug;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
283

284
	assert( BER_VALID( ber ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
285
286
287
288
	return( ber );
}

BerElement *
289
ber_alloc( void )	/* deprecated */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
290
291
292
293
294
{
	return( ber_alloc_t( 0 ) );
}

BerElement *
295
der_alloc( void )	/* deprecated */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
296
297
298
299
300
{
	return( ber_alloc_t( LBER_USE_DER ) );
}

BerElement *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
301
ber_dup( LDAP_CONST BerElement *ber )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
302
303
304
{
	BerElement	*new;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
305
	assert( ber != NULL );
306
	assert( BER_VALID( ber ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
307

308
	if ( (new = ber_alloc_t( ber->ber_options )) == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
309
		return( NULL );
310
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
311
312
313

	*new = *ber;

314
	assert( BER_VALID( new ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
315
316
317
318
	return( new );
}


319
/* OLD U-Mich ber_init() */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
320
void
321
ber_init_w_nullc( BerElement *ber, int options )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
322
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
323
324
	assert( ber != NULL );

325
326
    ber_int_options.lbo_valid = LBER_INITIALIZED;

327
	(void) memset( (char *)ber, '\0', sizeof( BerElement ));
328
	ber->ber_valid = LBER_VALID_BERELEMENT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
329
	ber->ber_tag = LBER_DEFAULT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
330
	ber->ber_options = (char) options;
331
	ber->ber_debug = ber_int_debug;
332
333

	assert( BER_VALID( ber ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
334
335
}

336
337
338
339
/* New C-API ber_init() */
/* This function constructs a BerElement containing a copy
** of the data in the bv argument.
*/
340
341
342
BerElement *
ber_init( struct berval *bv )
{
343
344
	BerElement *ber;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
345
346
	assert( bv != NULL );

347
348
    ber_int_options.lbo_valid = LBER_INITIALIZED;

349
350
351
352
353
354
	if ( bv == NULL ) {
		return NULL;
	}

	ber = ber_alloc_t( 0 );

355
	if( ber == NULL ) {
356
357
358
359
360
		/* allocation failed */
		return ( NULL );
	}

	/* copy the data */
361
	if ( ( (ber_len_t) ber_write ( ber, bv->bv_val, bv->bv_len, 0 )) != bv->bv_len ) {
362
363
364
365
366
367
368
369
		/* write failed, so free and return NULL */
		ber_free( ber, 1 );
		return( NULL );
	}

	ber_reset( ber, 1 );	/* reset the pointer to the start of the buffer */

	return ( ber );
370
371
}

372
373
374
375
376
377
/* New C-API ber_flatten routine */
/* This routine allocates a struct berval whose contents are a BER
** encoding taken from the ber argument.  The bvPtr pointer pointers to
** the returned berval.
*/
int ber_flatten(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
378
	LDAP_CONST BerElement *ber,
379
380
381
382
	struct berval **bvPtr)
{
	struct berval *bv;
 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
383
384
	assert( bvPtr != NULL );

385
386
    ber_int_options.lbo_valid = LBER_INITIALIZED;

387
388
389
390
	if(bvPtr == NULL) {
		return( -1 );
	}

391
	if ( (bv = LBER_MALLOC( sizeof(struct berval))) == NULL ) {
392
393
394
395
396
397
398
399
400
401
		return( -1 );
	}

	if ( ber == NULL ) {
		/* ber is null, create an empty berval */
		bv->bv_val = NULL;
		bv->bv_len = 0;

	} else {
		/* copy the berval */
402
		ber_len_t len = ber->ber_ptr - ber->ber_buf;
403

404
		if ( (bv->bv_val = (char *) LBER_MALLOC( len + 1 )) == NULL ) {
405
406
407
408
			ber_bvfree( bv );
			return( -1 );
		}

409
		SAFEMEMCPY( bv->bv_val, ber->ber_buf, len );
410
411
412
413
414
415
416
		bv->bv_val[len] = '\0';
		bv->bv_len = len;
	}
    
	*bvPtr = bv;
	return( 0 );
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
417
418
419
420

void
ber_reset( BerElement *ber, int was_writing )
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
421
	assert( ber != NULL );
422
	assert( BER_VALID( ber ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
423

Kurt Zeilenga's avatar
Kurt Zeilenga committed
424
425
426
427
428
429
430
431
432
433
	if ( was_writing ) {
		ber->ber_end = ber->ber_ptr;
		ber->ber_ptr = ber->ber_buf;
	} else {
		ber->ber_ptr = ber->ber_end;
	}

	ber->ber_rwptr = NULL;
}

434
#if 0
Kurt Zeilenga's avatar
Kurt Zeilenga committed
435
/* return the tag - LBER_DEFAULT returned means trouble */
436
static ber_tag_t
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437
438
439
get_tag( Sockbuf *sb )
{
	unsigned char	xbyte;
440
	ber_tag_t	tag;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
441
	char		*tagp;
Hallvard Furuseth's avatar
Hallvard Furuseth committed
442
	unsigned int	i;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
443

Kurt Zeilenga's avatar
Kurt Zeilenga committed
444
	assert( sb != NULL );
445
	assert( SOCKBUF_VALID( sb ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
446
447

	if ( ber_pvt_sb_read( sb, (char *) &xbyte, 1 ) != 1 )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
448
449
450
		return( LBER_DEFAULT );

	if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
451
		return( (ber_tag_t) xbyte );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
452
453
454

	tagp = (char *) &tag;
	tagp[0] = xbyte;
455
	for ( i = 1; i < sizeof(ber_tag_t); i++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
456
		if ( ber_pvt_sb_read( sb, (char *) &xbyte, 1 ) != 1 )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
457
458
459
460
461
462
463
464
465
			return( LBER_DEFAULT );

		tagp[i] = xbyte;

		if ( ! (xbyte & LBER_MORE_TAG_MASK) )
			break;
	}

	/* tag too big! */
466
	if ( i == sizeof(ber_tag_t) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
467
468
469
		return( LBER_DEFAULT );

	/* want leading, not trailing 0's */
470
	return( tag >> (sizeof(ber_tag_t) - i - 1) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
471
}
472
473
474
#endif

/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
475
 * A rewrite of ber_get_next that can safely be called multiple times 
476
477
478
 * for the same packet. It will simply continue were it stopped until
 * a full packet is read.
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
479

480
481
482
483
484
ber_tag_t
ber_get_next(
	Sockbuf *sb,
	ber_len_t *len,
	BerElement *ber )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
485
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
486
487
488
489
	assert( sb != NULL );
	assert( len != NULL );
	assert( ber != NULL );

490
491
492
493
494
495
	assert( SOCKBUF_VALID( sb ) );
	assert( BER_VALID( ber ) );

	ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
		"ber_get_next\n" );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
496
497
498
499
500
501
502
503
504
505
506
	/*
	 * Any ber element looks like this: tag length contents.
	 * Assuming everything's ok, we return the tag byte (we
	 * can assume a single byte), return the length in len,
	 * and the rest of the undecoded element in buf.
	 *
	 * Assumptions:
	 *	1) small tags (less than 128)
	 *	2) definite lengths
	 *	3) primitive encodings used whenever possible
	 */
507
508
	
	if (ber->ber_rwptr == NULL) {
509
510
511
512
		/* XXYYZ
		 * dtest does like this assert.
		 */
		/* assert( ber->ber_buf == NULL ); */
513
514
515
		ber->ber_rwptr = (char *) &ber->ber_tag;
		ber->ber_tag = 0;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
516

517
518
519
520
521
#define PTR_IN_VAR( ptr, var )\
(((ptr)>=(char *) &(var)) && ((ptr)< (char *) &(var)+sizeof(var)))
	
	if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag)) {
		if (ber->ber_rwptr == (char *) &ber->ber_tag) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
522
			if (ber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0)
523
524
525
526
527
528
529
530
				return LBER_DEFAULT;
			if ((ber->ber_rwptr[0] & LBER_BIG_TAG_MASK)
				!= LBER_BIG_TAG_MASK) {
				ber->ber_tag = ber->ber_rwptr[0];
				ber->ber_rwptr = (char *) &ber->ber_usertag;
				goto get_lenbyte;
			}
			ber->ber_rwptr++;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
531
		}
532
533
		do {
			/* reading the tag... */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
534
			if (ber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0)
535
536
537
538
539
540
541
542
543
544
545
546
547
548
				return LBER_DEFAULT;
			if (! (ber->ber_rwptr[0] & LBER_MORE_TAG_MASK) ) {
				ber->ber_tag>>=sizeof(ber->ber_tag) -
				  ((char *) &ber->ber_tag - ber->ber_rwptr);
				ber->ber_rwptr = (char *) &ber->ber_usertag;
				goto get_lenbyte;
			}
		} while (PTR_IN_VAR(ber->ber_rwptr,ber->ber_tag));
		errno = ERANGE; /* this is a serious error. */
		return LBER_DEFAULT;
	}
get_lenbyte:
	if (ber->ber_rwptr==(char *) &ber->ber_usertag) {
		unsigned char c;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549
		if (ber_pvt_sb_read( sb, (char *) &c, 1)<=0)
550
			return LBER_DEFAULT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
551
552
		if (c & 0x80U) {
			int len = c & 0x7fU;
553
			if ( (len==0) || ( len>sizeof( ber->ber_len ) ) ) {
554
555
				errno = ERANGE;
				return LBER_DEFAULT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
556
			}
557
558
559
			ber->ber_rwptr = (char *) &ber->ber_len +
				sizeof(ber->ber_len) - len;
			ber->ber_len = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
560
		} else {
561
562
			ber->ber_len = c;
			goto fill_buffer;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
563
		}
564
565
	}
	if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_len)) {
566
567
		ber_slen_t res;
		ber_slen_t to_go;
568
569
570
		to_go = (char *) &ber->ber_len + sizeof( ber->ber_len ) -
			ber->ber_rwptr;
		assert( to_go > 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
571
		res = ber_pvt_sb_read( sb, ber->ber_rwptr, to_go );
572
573
574
575
576
		if (res <=0)
			return LBER_DEFAULT;
		ber->ber_rwptr += res;
		if (res==to_go) {
			/* convert length. */
577
			ber->ber_len = LBER_LEN_NTOH( ber->ber_len );
578
579
580
581
582
583
584
585
			goto fill_buffer;
		} else {
#if defined( EWOULDBLOCK )
			errno = EWOULDBLOCK;
#elif defined( EAGAIN )
			errno = EAGAIN;
#endif			
			return LBER_DEFAULT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
586
		}
587
588
589
590
591
592
593
	}
fill_buffer:	
	/* now fill the buffer. */
	if (ber->ber_buf==NULL) {
		if (ber->ber_len > MAX_BERBUFSIZE) {
			errno = ERANGE;
			return LBER_DEFAULT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
594
		}
595
		ber->ber_buf = (char *) LBER_MALLOC( ber->ber_len );
596
597
		if (ber->ber_buf==NULL)
			return LBER_DEFAULT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
598
		ber->ber_rwptr = ber->ber_buf;
599
600
		ber->ber_ptr = ber->ber_buf;
		ber->ber_end = ber->ber_buf + ber->ber_len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
601
	}
602
	if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) {
603
604
		ber_slen_t res;
		ber_slen_t to_go;
605
606
607
608
		
		to_go = ber->ber_end - ber->ber_rwptr;
		assert( to_go > 0 );
		
Kurt Zeilenga's avatar
Kurt Zeilenga committed
609
		res = ber_pvt_sb_read( sb, ber->ber_rwptr, to_go );
610
611
612
613
614
615
616
617
618
619
620
		if (res<=0)
			return LBER_DEFAULT;
		ber->ber_rwptr+=res;
		
		if (res<to_go) {
#if defined( EWOULDBLOCK )
			errno = EWOULDBLOCK;
#elif defined( EAGAIN )
			errno = EAGAIN;
#endif			
			return LBER_DEFAULT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
621
		}
622
623
624
625
		
		ber->ber_rwptr = NULL;
		*len = ber->ber_len;
		if ( ber->ber_debug ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
626
			ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
627
628
				"ber_get_next: tag 0x%lx len %ld contents:\n",
				ber->ber_tag, ber->ber_len );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
629
			ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
630
631
		}
		return (ber->ber_tag);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
632
	}
633
634
635
	assert( 0 ); /* ber structure is messed up ?*/
	return LBER_DEFAULT;
}