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