]> git.sur5r.net Git - openldap/blob - libraries/liblber/io.c
Fixed bug in dtest code.
[openldap] / libraries / liblber / io.c
1 /* io.c - ber general i/o routines */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* Portions
7  * Copyright (c) 1990 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include <ac/ctype.h>
24 #include <ac/errno.h>
25 #include <ac/socket.h>
26 #include <ac/string.h>
27 #include <ac/unistd.h>
28
29 #ifdef HAVE_IO_H
30 #include <io.h>
31 #endif
32
33 #include "lber-int.h"
34
35 static long BerRead LDAP_P(( Sockbuf *sb, char *buf, long len ));
36 static int ber_realloc LDAP_P(( BerElement *ber, unsigned long len ));
37
38 #define EXBUFSIZ        1024
39
40 /* probably far too large... */
41 #define MAX_BERBUFSIZE  (128*1024)
42
43 #if defined( DOS ) && !defined( _WIN32 ) && (MAX_BERBUFSIZE > 65535)
44 # undef MAX_BERBUFSIZE
45 # define MAX_BERBUFSIZE 65535
46 #endif
47
48 static long
49 BerRead( Sockbuf *sb, char *buf, long len )
50 {
51         int     c;
52         long    nread = 0;
53
54         assert( sb != NULL );
55         assert( buf != NULL );
56
57         while ( len > 0 ) {
58                 if ( (c = ber_pvt_sb_read( sb, buf, len )) <= 0 ) {
59                         if ( nread > 0 )
60                                 break;
61                         return( c );
62                 }
63                 buf+= c;
64                 nread+=c;
65                 len-=c;
66         }
67
68         return( nread );
69 }
70
71 long
72 ber_read( BerElement *ber, char *buf, unsigned long len )
73 {
74         unsigned long   actuallen, nleft;
75
76         assert( ber != NULL );
77         assert( buf != NULL );
78
79         nleft = ber->ber_end - ber->ber_ptr;
80         actuallen = nleft < len ? nleft : len;
81
82         SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen );
83
84         ber->ber_ptr += actuallen;
85
86         return( (long)actuallen );
87 }
88
89 long
90 ber_write(
91         BerElement *ber,
92         LDAP_CONST char *buf,
93         unsigned long len,
94         int nosos )
95 {
96         assert( ber != NULL );
97         assert( buf != NULL );
98
99         if ( nosos || ber->ber_sos == NULL ) {
100                 if ( ber->ber_ptr + len > ber->ber_end ) {
101                         if ( ber_realloc( ber, len ) != 0 )
102                                 return( -1 );
103                 }
104                 SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
105                 ber->ber_ptr += len;
106                 return( len );
107         } else {
108                 if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
109                         if ( ber_realloc( ber, len ) != 0 )
110                                 return( -1 );
111                 }
112                 SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
113                 ber->ber_sos->sos_ptr += len;
114                 ber->ber_sos->sos_clen += len;
115                 return( len );
116         }
117 }
118
119 static int
120 ber_realloc( BerElement *ber, unsigned long len )
121 {
122         unsigned long   need, have, total;
123         Seqorset        *s;
124         long            off;
125         char            *oldbuf;
126
127         assert( ber != NULL );
128         assert( len > 0 );
129
130         have = (ber->ber_end - ber->ber_buf) / EXBUFSIZ;
131         need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
132         total = have * EXBUFSIZ + need * EXBUFSIZ;
133
134         oldbuf = ber->ber_buf;
135
136         if ( ber->ber_buf == NULL ) {
137                 if ( (ber->ber_buf = (char *) malloc( (size_t)total )) == NULL )
138                         return( -1 );
139         } else if ( (ber->ber_buf = (char *) realloc( ber->ber_buf,
140             (size_t)total )) == NULL )
141                 return( -1 );
142
143         ber->ber_end = ber->ber_buf + total;
144
145         /*
146          * If the stinking thing was moved, we need to go through and
147          * reset all the sos and ber pointers.  Offsets would've been
148          * a better idea... oh well.
149          */
150
151         if ( ber->ber_buf != oldbuf ) {
152                 ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
153
154                 for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) {
155                         off = s->sos_first - oldbuf;
156                         s->sos_first = ber->ber_buf + off;
157
158                         off = s->sos_ptr - oldbuf;
159                         s->sos_ptr = ber->ber_buf + off;
160                 }
161         }
162
163         return( 0 );
164 }
165
166 void
167 ber_free( BerElement *ber, int freebuf )
168 {
169         assert( ber != NULL );
170
171         if ( freebuf && ber->ber_buf != NULL )
172                 free( ber->ber_buf );
173         ber->ber_buf = NULL;
174         free( (char *) ber );
175 }
176
177 int
178 ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
179 {
180         long    nwritten, towrite, rc;  
181
182         assert( sb != NULL );
183         assert( ber != NULL );
184
185         if ( ber->ber_rwptr == NULL ) {
186                 ber->ber_rwptr = ber->ber_buf;
187         }
188         towrite = ber->ber_ptr - ber->ber_rwptr;
189
190         if ( sb->sb_debug ) {
191                 ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
192                         "ber_flush: %ld bytes to sd %ld%s\n", towrite,
193                     (long) sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
194                     : "" );
195                 ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug,
196                         ber->ber_rwptr, towrite );
197         }
198
199 #if !defined(MACOS) && !defined(DOS)
200         if ( sb->sb_options & (LBER_TO_FILE | LBER_TO_FILE_ONLY) ) {
201                 rc = write( sb->sb_fd, ber->ber_rwptr, towrite );
202                 if ( sb->sb_options & LBER_TO_FILE_ONLY ) {
203                         return( (int)rc );
204                 }
205         }
206 #endif
207         
208         nwritten = 0;
209         do {
210                 rc = ber_pvt_sb_write( sb, ber->ber_rwptr, towrite );
211                 if (rc<=0) {
212                         return -1;
213                 }
214                 towrite -= rc;
215                 nwritten += rc;
216                 ber->ber_rwptr += rc;
217         } while ( towrite > 0 );
218
219         if ( freeit )
220                 ber_free( ber, 1 );
221
222         return( 0 );
223 }
224
225 BerElement *
226 ber_alloc_t( int options )
227 {
228         BerElement      *ber;
229
230         ber = (BerElement *) calloc( 1, sizeof(BerElement) );
231
232         if ( ber == NULLBER )
233                 return( NULLBER );
234
235         ber->ber_tag = LBER_DEFAULT;
236         ber->ber_options = options;
237         ber->ber_debug = ber_int_debug;
238
239         return( ber );
240 }
241
242 BerElement *
243 ber_alloc( void )
244 {
245         return( ber_alloc_t( 0 ) );
246 }
247
248 BerElement *
249 der_alloc( void )
250 {
251         return( ber_alloc_t( LBER_USE_DER ) );
252 }
253
254 BerElement *
255 ber_dup( LDAP_CONST BerElement *ber )
256 {
257         BerElement      *new;
258
259         assert( ber != NULL );
260
261         if ( (new = ber_alloc()) == NULL )
262                 return( NULL );
263
264         *new = *ber;
265
266         return( new );
267 }
268
269
270 /* OLD U-Mich ber_init() */
271 void
272 ber_init_w_nullc( BerElement *ber, int options )
273 {
274         assert( ber != NULL );
275
276         (void) memset( (char *)ber, '\0', sizeof( BerElement ));
277         ber->ber_tag = LBER_DEFAULT;
278         ber->ber_options = (char) options;
279 }
280
281 /* New C-API ber_init() */
282 /* This function constructs a BerElement containing a copy
283 ** of the data in the bv argument.
284 */
285 BerElement *
286 ber_init( struct berval *bv )
287 {
288         BerElement *ber;
289
290         assert( bv != NULL );
291
292         if ( bv == NULL ) {
293                 return NULL;
294         }
295
296         ber = ber_alloc_t( 0 );
297
298         if( ber == NULLBER ) {
299                 /* allocation failed */
300                 return ( NULL );
301         }
302
303         /* copy the data */
304         if ( ( (unsigned int) ber_write ( ber, bv->bv_val, bv->bv_len, 0 )) != bv->bv_len ) {
305                 /* write failed, so free and return NULL */
306                 ber_free( ber, 1 );
307                 return( NULL );
308         }
309
310         ber_reset( ber, 1 );    /* reset the pointer to the start of the buffer */
311
312         return ( ber );
313 }
314
315 /* New C-API ber_flatten routine */
316 /* This routine allocates a struct berval whose contents are a BER
317 ** encoding taken from the ber argument.  The bvPtr pointer pointers to
318 ** the returned berval.
319 */
320 int ber_flatten(
321         LDAP_CONST BerElement *ber,
322         struct berval **bvPtr)
323 {
324         struct berval *bv;
325  
326         assert( bvPtr != NULL );
327
328         if(bvPtr == NULL) {
329                 return( -1 );
330         }
331
332         if ( (bv = malloc( sizeof(struct berval))) == NULL ) {
333                 return( -1 );
334         }
335
336         if ( ber == NULL ) {
337                 /* ber is null, create an empty berval */
338                 bv->bv_val = NULL;
339                 bv->bv_len = 0;
340
341         } else {
342                 /* copy the berval */
343                 ptrdiff_t len = ber->ber_ptr - ber->ber_buf;
344
345                 if ( (bv->bv_val = (char *) malloc( len + 1 )) == NULL ) {
346                         ber_bvfree( bv );
347                         return( -1 );
348                 }
349
350                 SAFEMEMCPY( bv->bv_val, ber->ber_buf, (size_t)len );
351                 bv->bv_val[len] = '\0';
352                 bv->bv_len = len;
353         }
354     
355         *bvPtr = bv;
356         return( 0 );
357 }
358
359 void
360 ber_reset( BerElement *ber, int was_writing )
361 {
362         assert( ber != NULL );
363
364         if ( was_writing ) {
365                 ber->ber_end = ber->ber_ptr;
366                 ber->ber_ptr = ber->ber_buf;
367         } else {
368                 ber->ber_ptr = ber->ber_end;
369         }
370
371         ber->ber_rwptr = NULL;
372 }
373
374 #if 0
375 /* return the tag - LBER_DEFAULT returned means trouble */
376 static unsigned long
377 get_tag( Sockbuf *sb )
378 {
379         unsigned char   xbyte;
380         unsigned long   tag;
381         char            *tagp;
382         unsigned int    i;
383
384         assert( sb != NULL );
385
386         if ( ber_pvt_sb_read( sb, (char *) &xbyte, 1 ) != 1 )
387                 return( LBER_DEFAULT );
388
389         if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
390                 return( (unsigned long) xbyte );
391
392         tagp = (char *) &tag;
393         tagp[0] = xbyte;
394         for ( i = 1; i < sizeof(long); i++ ) {
395                 if ( ber_pvt_sb_read( sb, (char *) &xbyte, 1 ) != 1 )
396                         return( LBER_DEFAULT );
397
398                 tagp[i] = xbyte;
399
400                 if ( ! (xbyte & LBER_MORE_TAG_MASK) )
401                         break;
402         }
403
404         /* tag too big! */
405         if ( i == sizeof(long) )
406                 return( LBER_DEFAULT );
407
408         /* want leading, not trailing 0's */
409         return( tag >> (sizeof(long) - i - 1) );
410 }
411 #endif
412
413 /*
414  * A rewrite of ber_get_next that can safely be called multiple times 
415  * for the same packet. It will simply continue were it stopped until
416  * a full packet is read.
417  */
418
419 unsigned long
420 ber_get_next( Sockbuf *sb, unsigned long *len, BerElement *ber )
421 {
422         assert( sb != NULL );
423         assert( len != NULL );
424         assert( ber != NULL );
425
426         if ( ber->ber_debug ) {
427                 ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
428                         "ber_get_next\n" );
429         }
430         
431         /*
432          * Any ber element looks like this: tag length contents.
433          * Assuming everything's ok, we return the tag byte (we
434          * can assume a single byte), return the length in len,
435          * and the rest of the undecoded element in buf.
436          *
437          * Assumptions:
438          *      1) small tags (less than 128)
439          *      2) definite lengths
440          *      3) primitive encodings used whenever possible
441          */
442         
443         if (ber->ber_rwptr == NULL) {
444                 /* assert( ber->ber_buf == NULL ); */
445                 ber->ber_rwptr = (char *) &ber->ber_tag;
446                 ber->ber_tag = 0;
447         }
448
449 #define PTR_IN_VAR( ptr, var )\
450 (((ptr)>=(char *) &(var)) && ((ptr)< (char *) &(var)+sizeof(var)))
451         
452         if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_tag)) {
453                 if (ber->ber_rwptr == (char *) &ber->ber_tag) {
454                         if (ber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0)
455                                 return LBER_DEFAULT;
456                         if ((ber->ber_rwptr[0] & LBER_BIG_TAG_MASK)
457                                 != LBER_BIG_TAG_MASK) {
458                                 ber->ber_tag = ber->ber_rwptr[0];
459                                 ber->ber_rwptr = (char *) &ber->ber_usertag;
460                                 goto get_lenbyte;
461                         }
462                         ber->ber_rwptr++;
463                 }
464                 do {
465                         /* reading the tag... */
466                         if (ber_pvt_sb_read( sb, ber->ber_rwptr, 1)<=0)
467                                 return LBER_DEFAULT;
468                         if (! (ber->ber_rwptr[0] & LBER_MORE_TAG_MASK) ) {
469                                 ber->ber_tag>>=sizeof(ber->ber_tag) -
470                                   ((char *) &ber->ber_tag - ber->ber_rwptr);
471                                 ber->ber_rwptr = (char *) &ber->ber_usertag;
472                                 goto get_lenbyte;
473                         }
474                 } while (PTR_IN_VAR(ber->ber_rwptr,ber->ber_tag));
475                 errno = ERANGE; /* this is a serious error. */
476                 return LBER_DEFAULT;
477         }
478 get_lenbyte:
479         if (ber->ber_rwptr==(char *) &ber->ber_usertag) {
480                 unsigned char c;
481                 if (ber_pvt_sb_read( sb, (char *) &c, 1)<=0)
482                         return LBER_DEFAULT;
483                 if (c & 0x80U) {
484                         int len = c & 0x7fU;
485                         if ( (len==0) || ((unsigned) len>sizeof( ber->ber_len ) ) ) {
486                                 errno = ERANGE;
487                                 return LBER_DEFAULT;
488                         }
489                         ber->ber_rwptr = (char *) &ber->ber_len +
490                                 sizeof(ber->ber_len) - len;
491                         ber->ber_len = 0;
492                 } else {
493                         ber->ber_len = c;
494                         goto fill_buffer;
495                 }
496         }
497         if (PTR_IN_VAR(ber->ber_rwptr, ber->ber_len)) {
498                 int res;
499                 int to_go;
500                 to_go = (char *) &ber->ber_len + sizeof( ber->ber_len ) -
501                         ber->ber_rwptr;
502                 assert( to_go > 0 );
503                 res = ber_pvt_sb_read( sb, ber->ber_rwptr, to_go );
504                 if (res <=0)
505                         return LBER_DEFAULT;
506                 ber->ber_rwptr += res;
507                 if (res==to_go) {
508                         /* convert length. */
509                         ber->ber_len = AC_NTOHL( ber->ber_len );
510                         goto fill_buffer;
511                 } else {
512 #if defined( EWOULDBLOCK )
513                         errno = EWOULDBLOCK;
514 #elif defined( EAGAIN )
515                         errno = EAGAIN;
516 #endif                  
517                         return LBER_DEFAULT;
518                 }
519         }
520 fill_buffer:    
521         /* now fill the buffer. */
522         if (ber->ber_buf==NULL) {
523                 if (ber->ber_len > MAX_BERBUFSIZE) {
524                         errno = ERANGE;
525                         return LBER_DEFAULT;
526                 }
527                 ber->ber_buf = (char *) malloc( ber->ber_len );
528                 if (ber->ber_buf==NULL)
529                         return LBER_DEFAULT;
530                 ber->ber_rwptr = ber->ber_buf;
531                 ber->ber_ptr = ber->ber_buf;
532                 ber->ber_end = ber->ber_buf + ber->ber_len;
533         }
534         if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) {
535                 int res;
536                 int to_go;
537                 
538                 to_go = ber->ber_end - ber->ber_rwptr;
539                 assert( to_go > 0 );
540                 
541                 res = ber_pvt_sb_read( sb, ber->ber_rwptr, to_go );
542                 if (res<=0)
543                         return LBER_DEFAULT;
544                 ber->ber_rwptr+=res;
545                 
546                 if (res<to_go) {
547 #if defined( EWOULDBLOCK )
548                         errno = EWOULDBLOCK;
549 #elif defined( EAGAIN )
550                         errno = EAGAIN;
551 #endif                  
552                         return LBER_DEFAULT;
553                 }
554                 
555                 ber->ber_rwptr = NULL;
556                 *len = ber->ber_len;
557                 if ( ber->ber_debug ) {
558                         ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
559                                 "ber_get_next: tag 0x%lx len %ld contents:\n",
560                                 ber->ber_tag, ber->ber_len );
561                         ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
562                 }
563                 return (ber->ber_tag);
564         }
565         assert( 0 ); /* ber structure is messed up ?*/
566         return LBER_DEFAULT;
567 }
568
569 void    ber_clear( BerElement *ber, int freebuf )
570 {
571         assert( ber != NULL );
572
573         if ((freebuf) && (ber->ber_buf))
574                 free( ber->ber_buf );
575         ber->ber_buf = NULL;
576         ber->ber_rwptr = NULL;
577         ber->ber_end = NULL;
578 }
579