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