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