]> git.sur5r.net Git - openldap/blob - libraries/liblber/io.c
081f386794a6a08b2ed5ca4225bf200556ca7a4f
[openldap] / libraries / liblber / io.c
1 /* io.c - ber general i/o routines */
2 /*
3  * Copyright (c) 1990 Regents of the University of Michigan.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted
7  * provided that this notice is preserved and that due credit is given
8  * to the University of Michigan at Ann Arbor. The name of the University
9  * may not be used to endorse or promote products derived from this
10  * software without specific prior written permission. This software
11  * is provided ``as is'' without express or implied warranty.
12  */
13
14 #include <stdio.h>
15 #include <ctype.h>
16
17 #if defined( DOS ) || defined( _WIN32 )
18 #include "msdos.h"
19 #endif /* DOS || _WIN32 */
20
21 #ifdef MACOS
22 #include <stdlib.h>
23 #include "macos.h"
24 #else /* MACOS */
25 #if defined(NeXT) || defined(VMS)
26 #include <stdlib.h>
27 #else /* next || vms */
28 #include <malloc.h>
29 #endif /* next || vms */
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #ifdef PCNFS
35 #include <tklib.h>
36 #endif /* PCNFS */
37 #endif /* MACOS */
38
39 #ifndef VMS
40 #include <memory.h>
41 #endif
42 #include <string.h>
43 #include "lber.h"
44
45 #ifdef _WIN32
46 #include <winsock.h>
47 #include <io.h>
48 #endif /* _WIN32 */
49
50 #ifdef NEEDPROTOS
51 static int ber_realloc( BerElement *ber, unsigned long len );
52 static int ber_filbuf( Sockbuf *sb, long len );
53 static long BerRead( Sockbuf *sb, char *buf, long len );
54 #ifdef PCNFS
55 static int BerWrite( Sockbuf *sb, char *buf, long len );
56 #endif /* PCNFS */
57 #else
58 int ber_filbuf();
59 long BerRead();
60 static int ber_realloc();
61 #endif /* NEEDPROTOS */
62
63 #define bergetc( sb, len )    ( sb->sb_ber.ber_end > sb->sb_ber.ber_ptr ? \
64                           (unsigned char)*sb->sb_ber.ber_ptr++ : \
65                           ber_filbuf( sb, len ))
66
67 #ifdef MACOS
68 /*
69  * MacTCP/OpenTransport
70  */
71 #define read( s, b, l ) tcpread( s, 0, (unsigned char *)b, l, NULL )
72 #define MAX_WRITE       65535
73 #define BerWrite( sb, b, l )   tcpwrite( sb->sb_sd, (unsigned char *)(b), (l<MAX_WRITE)? l : MAX_WRITE )
74 #else /* MACOS */
75 #ifdef DOS
76 #ifdef PCNFS
77 /*
78  * PCNFS (under DOS)
79  */
80 #define read( s, b, l ) recv( s, b, l, 0 )
81 #define BerWrite( s, b, l ) send( s->sb_sd, b, (int) l, 0 )
82 #endif /* PCNFS */
83 #ifdef NCSA
84 /*
85  * NCSA Telnet TCP/IP stack (under DOS)
86  */
87 #define read( s, b, l ) nread( s, b, l )
88 #define BerWrite( s, b, l ) netwrite( s->sb_sd, b, l )
89 #endif /* NCSA */
90 #ifdef WINSOCK
91 /*
92  * Windows Socket API (under DOS/Windows 3.x)
93  */
94 #define read( s, b, l ) recv( s, b, l, 0 )
95 #define BerWrite( s, b, l ) send( s->sb_sd, b, l, 0 )
96 #endif /* WINSOCK */
97 #else /* DOS */
98 #ifdef _WIN32
99 /*
100  * 32-bit Windows Socket API (under Windows NT or Windows 95)
101  */
102 #define read( s, b, l )         recv( s, b, l, 0 )
103 #define BerWrite( s, b, l )     send( s->sb_sd, b, l, 0 )
104 #else /* _WIN32 */
105 #ifdef VMS
106 /*
107  * VMS -- each write must be 64K or smaller
108  */
109 #define MAX_WRITE 65535
110 #define BerWrite( sb, b, l ) write( sb->sb_sd, b, (l<MAX_WRITE)? l : MAX_WRITE)
111 #else /* VMS */
112 /*
113  * everything else (Unix/BSD 4.3 socket API)
114  */
115 #define BerWrite( sb, b, l )    write( sb->sb_sd, b, l )
116 #endif /* VMS */
117 #define udp_read( sb, b, l, al ) recvfrom(sb->sb_sd, (char *)b, l, 0, \
118                 (struct sockaddr *)sb->sb_fromaddr, \
119                 (al = sizeof(struct sockaddr), &al))
120 #define udp_write( sb, b, l ) sendto(sb->sb_sd, (char *)(b), l, 0, \
121                 (struct sockaddr *)sb->sb_useaddr, sizeof(struct sockaddr))
122 #endif /* _WIN32 */
123 #endif /* DOS */
124 #endif /* MACOS */
125
126 #ifndef udp_read
127 #define udp_read( sb, b, l, al )        CLDAP NOT SUPPORTED
128 #define udp_write( sb, b, l )           CLDAP NOT SUPPORTED
129 #endif /* udp_read */
130
131 #define EXBUFSIZ        1024
132
133 int
134 ber_filbuf( Sockbuf *sb, long len )
135 {
136         short   rc;
137 #ifdef CLDAP
138         int     addrlen;
139 #endif /* CLDAP */
140
141         if ( sb->sb_ber.ber_buf == NULL ) {
142                 if ( (sb->sb_ber.ber_buf = (char *) malloc( READBUFSIZ )) ==
143                     NULL )
144                         return( -1 );
145                 sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf;
146                 sb->sb_ber.ber_end = sb->sb_ber.ber_buf;
147         }
148
149         if ( sb->sb_naddr > 0 ) {
150 #ifdef CLDAP
151                 rc = udp_read(sb, sb->sb_ber.ber_buf, READBUFSIZ, addrlen );
152 #ifdef LDAP_DEBUG
153                 if ( lber_debug ) {
154                         fprintf( stderr, "ber_filbuf udp_read %d bytes\n",
155                                 rc );
156                         if ( lber_debug > 1 && rc > 0 )
157                                 lber_bprint( sb->sb_ber.ber_buf, rc );
158                 }
159 #endif /* LDAP_DEBUG */
160 #else /* CLDAP */
161                 rc = -1;
162 #endif /* CLDAP */
163         } else {
164                 rc = read( sb->sb_sd, sb->sb_ber.ber_buf,
165                     ((sb->sb_options & LBER_NO_READ_AHEAD) &&
166                     (len < READBUFSIZ)) ?
167                     len : READBUFSIZ );
168         }
169
170         if ( rc > 0 ) {
171                 sb->sb_ber.ber_ptr = sb->sb_ber.ber_buf + 1;
172                 sb->sb_ber.ber_end = sb->sb_ber.ber_buf + rc;
173                 return( (unsigned char)*sb->sb_ber.ber_buf );
174         }
175
176         return( -1 );
177 }
178
179
180 long
181 BerRead( Sockbuf *sb, char *buf, long len )
182 {
183         int     c;
184         long    nread = 0;
185
186         while ( len > 0 ) {
187                 if ( (c = bergetc( sb, len )) < 0 ) {
188                         if ( nread > 0 )
189                                 break;
190                         return( c );
191                 }
192                 *buf++ = c;
193                 nread++;
194                 len--;
195         }
196
197         return( nread );
198 }
199
200
201 long
202 ber_read( BerElement *ber, char *buf, unsigned long len )
203 {
204         unsigned long   actuallen, nleft;
205
206         nleft = ber->ber_end - ber->ber_ptr;
207         actuallen = nleft < len ? nleft : len;
208
209         SAFEMEMCPY( buf, ber->ber_ptr, (size_t)actuallen );
210
211         ber->ber_ptr += actuallen;
212
213         return( (long)actuallen );
214 }
215
216 long
217 ber_write( BerElement *ber, char *buf, unsigned long len, int nosos )
218 {
219         if ( nosos || ber->ber_sos == NULL ) {
220                 if ( ber->ber_ptr + len > ber->ber_end ) {
221                         if ( ber_realloc( ber, len ) != 0 )
222                                 return( -1 );
223                 }
224                 SAFEMEMCPY( ber->ber_ptr, buf, (size_t)len );
225                 ber->ber_ptr += len;
226                 return( len );
227         } else {
228                 if ( ber->ber_sos->sos_ptr + len > ber->ber_end ) {
229                         if ( ber_realloc( ber, len ) != 0 )
230                                 return( -1 );
231                 }
232                 SAFEMEMCPY( ber->ber_sos->sos_ptr, buf, (size_t)len );
233                 ber->ber_sos->sos_ptr += len;
234                 ber->ber_sos->sos_clen += len;
235                 return( len );
236         }
237 }
238
239 static int
240 ber_realloc( BerElement *ber, unsigned long len )
241 {
242         unsigned long   need, have, total;
243         Seqorset        *s;
244         long            off;
245         char            *oldbuf;
246
247         have = (ber->ber_end - ber->ber_buf) / EXBUFSIZ;
248         need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
249         total = have * EXBUFSIZ + need * EXBUFSIZ;
250
251         oldbuf = ber->ber_buf;
252
253         if ( ber->ber_buf == NULL ) {
254                 if ( (ber->ber_buf = (char *) malloc( (size_t)total )) == NULL )
255                         return( -1 );
256         } else if ( (ber->ber_buf = (char *) realloc( ber->ber_buf,
257             (size_t)total )) == NULL )
258                 return( -1 );
259
260         ber->ber_end = ber->ber_buf + total;
261
262         /*
263          * If the stinking thing was moved, we need to go through and
264          * reset all the sos and ber pointers.  Offsets would've been
265          * a better idea... oh well.
266          */
267
268         if ( ber->ber_buf != oldbuf ) {
269                 ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
270
271                 for ( s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next ) {
272                         off = s->sos_first - oldbuf;
273                         s->sos_first = ber->ber_buf + off;
274
275                         off = s->sos_ptr - oldbuf;
276                         s->sos_ptr = ber->ber_buf + off;
277                 }
278         }
279
280         return( 0 );
281 }
282
283 void
284 ber_free( BerElement *ber, int freebuf )
285 {
286         if ( freebuf && ber->ber_buf != NULL )
287                 free( ber->ber_buf );
288         free( (char *) ber );
289 }
290
291 int
292 ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
293 {
294         long    nwritten, towrite, rc;
295
296         if ( ber->ber_rwptr == NULL ) {
297                 ber->ber_rwptr = ber->ber_buf;
298         }
299         towrite = ber->ber_ptr - ber->ber_rwptr;
300
301 #ifdef LDAP_DEBUG
302         if ( lber_debug ) {
303                 fprintf( stderr, "ber_flush: %ld bytes to sd %ld%s\n", towrite,
304                     sb->sb_sd, ber->ber_rwptr != ber->ber_buf ? " (re-flush)"
305                     : "" );
306                 if ( lber_debug > 1 )
307                         lber_bprint( ber->ber_rwptr, towrite );
308         }
309 #endif
310 #if !defined(MACOS) && !defined(DOS)
311         if ( sb->sb_options & (LBER_TO_FILE | LBER_TO_FILE_ONLY) ) {
312                 rc = write( sb->sb_fd, ber->ber_buf, towrite );
313                 if ( sb->sb_options & LBER_TO_FILE_ONLY ) {
314                         return( (int)rc );
315                 }
316         }
317 #endif
318
319         nwritten = 0;
320         do {
321                 if (sb->sb_naddr > 0) {
322 #ifdef CLDAP
323                         rc = udp_write( sb, ber->ber_buf + nwritten,
324                             (size_t)towrite );
325 #else /* CLDAP */
326                         rc = -1;
327 #endif /* CLDAP */
328                         if ( rc <= 0 )
329                                 return( -1 );
330                         /* fake error if write was not atomic */
331                         if (rc < towrite) {
332 #if !defined( MACOS ) && !defined( DOS )
333                             errno = EMSGSIZE;
334 #endif
335                             return( -1 );
336                         }
337                 } else {
338                         if ( (rc = BerWrite( sb, ber->ber_rwptr,
339                             (size_t) towrite )) <= 0 ) {
340                                 return( -1 );
341                         }
342                 }
343                 towrite -= rc;
344                 nwritten += rc;
345                 ber->ber_rwptr += rc;
346         } while ( towrite > 0 );
347
348         if ( freeit )
349                 ber_free( ber, 1 );
350
351         return( 0 );
352 }
353
354 BerElement *
355 ber_alloc_t( int options )
356 {
357         BerElement      *ber;
358
359         if ( (ber = (BerElement *) calloc( 1, sizeof(BerElement) )) == NULLBER )
360                 return( NULLBER );
361         ber->ber_tag = LBER_DEFAULT;
362         ber->ber_options = options;
363
364         return( ber );
365 }
366
367 BerElement *
368 ber_alloc()
369 {
370         return( ber_alloc_t( 0 ) );
371 }
372
373 BerElement *
374 der_alloc()
375 {
376         return( ber_alloc_t( LBER_USE_DER ) );
377 }
378
379 BerElement *
380 ber_dup( BerElement *ber )
381 {
382         BerElement      *new;
383
384         if ( (new = ber_alloc()) == NULLBER )
385                 return( NULLBER );
386
387         *new = *ber;
388
389         return( new );
390 }
391
392
393 void
394 ber_init( BerElement *ber, int options )
395 {
396         (void) memset( (char *)ber, '\0', sizeof( BerElement ));
397         ber->ber_tag = LBER_DEFAULT;
398         ber->ber_options = options;
399 }
400
401
402 void
403 ber_reset( BerElement *ber, int was_writing )
404 {
405         if ( was_writing ) {
406                 ber->ber_end = ber->ber_ptr;
407                 ber->ber_ptr = ber->ber_buf;
408         } else {
409                 ber->ber_ptr = ber->ber_end;
410         }
411
412         ber->ber_rwptr = NULL;
413 }
414
415
416 #ifdef LDAP_DEBUG
417
418 void
419 ber_dump( BerElement *ber, int inout )
420 {
421         fprintf( stderr, "ber_dump: buf 0x%lx, ptr 0x%lx, end 0x%lx\n",
422             ber->ber_buf, ber->ber_ptr, ber->ber_end );
423         if ( inout == 1 ) {
424                 fprintf( stderr, "          current len %ld, contents:\n",
425                     ber->ber_end - ber->ber_ptr );
426                 lber_bprint( ber->ber_ptr, ber->ber_end - ber->ber_ptr );
427         } else {
428                 fprintf( stderr, "          current len %ld, contents:\n",
429                     ber->ber_ptr - ber->ber_buf );
430                 lber_bprint( ber->ber_buf, ber->ber_ptr - ber->ber_buf );
431         }
432 }
433
434 void
435 ber_sos_dump( Seqorset *sos )
436 {
437         fprintf( stderr, "*** sos dump ***\n" );
438         while ( sos != NULLSEQORSET ) {
439                 fprintf( stderr, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
440                     sos->sos_clen, sos->sos_first, sos->sos_ptr );
441                 fprintf( stderr, "              current len %ld contents:\n",
442                     sos->sos_ptr - sos->sos_first );
443                 lber_bprint( sos->sos_first, sos->sos_ptr - sos->sos_first );
444
445                 sos = sos->sos_next;
446         }
447         fprintf( stderr, "*** end dump ***\n" );
448 }
449
450 #endif
451
452 /* return the tag - LBER_DEFAULT returned means trouble */
453 static unsigned long
454 get_tag( Sockbuf *sb )
455 {
456         unsigned char   xbyte;
457         unsigned long   tag;
458         char            *tagp;
459         int             i;
460
461         if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 )
462                 return( LBER_DEFAULT );
463
464         if ( (xbyte & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK )
465                 return( (unsigned long) xbyte );
466
467         tagp = (char *) &tag;
468         tagp[0] = xbyte;
469         for ( i = 1; i < sizeof(long); i++ ) {
470                 if ( BerRead( sb, (char *) &xbyte, 1 ) != 1 )
471                         return( LBER_DEFAULT );
472
473                 tagp[i] = xbyte;
474
475                 if ( ! (xbyte & LBER_MORE_TAG_MASK) )
476                         break;
477         }
478
479         /* tag too big! */
480         if ( i == sizeof(long) )
481                 return( LBER_DEFAULT );
482
483         /* want leading, not trailing 0's */
484         return( tag >> (sizeof(long) - i - 1) );
485 }
486
487 unsigned long
488 ber_get_next( Sockbuf *sb, unsigned long *len, BerElement *ber )
489 {
490         unsigned long   tag, netlen, toread;
491         unsigned char   lc;
492         long            rc;
493         int             noctets, diff;
494
495 #ifdef LDAP_DEBUG
496         if ( lber_debug )
497                 fprintf( stderr, "ber_get_next\n" );
498 #endif
499
500         /*
501          * Any ber element looks like this: tag length contents.
502          * Assuming everything's ok, we return the tag byte (we
503          * can assume a single byte), return the length in len,
504          * and the rest of the undecoded element in buf.
505          *
506          * Assumptions:
507          *      1) small tags (less than 128)
508          *      2) definite lengths
509          *      3) primitive encodings used whenever possible
510          */
511
512         /*
513          * first time through - malloc the buffer, set up ptrs, and
514          * read the tag and the length and as much of the rest as we can
515          */
516
517         if ( ber->ber_rwptr == NULL ) {
518                 /*
519                  * First, we read the tag.
520                  */
521
522                 if ( (tag = get_tag( sb )) == LBER_DEFAULT ) {
523                         return( LBER_DEFAULT );
524                 }
525                 ber->ber_tag = tag;
526
527                 /*
528                  * Next, read the length.  The first byte contains the length
529                  * of the length.  If bit 8 is set, the length is the long
530                  * form, otherwise it's the short form.  We don't allow a
531                  * length that's greater than what we can hold in an unsigned
532                  * long.
533                  */
534
535                 *len = netlen = 0;
536                 if ( BerRead( sb, (char *) &lc, 1 ) != 1 ) {
537                         return( LBER_DEFAULT );
538                 }
539                 if ( lc & 0x80 ) {
540                         noctets = (lc & 0x7f);
541                         if ( noctets > sizeof(unsigned long) )
542                                 return( LBER_DEFAULT );
543                         diff = sizeof(unsigned long) - noctets;
544                         if ( BerRead( sb, (char *) &netlen + diff, noctets ) !=
545                             noctets ) {
546                                 return( LBER_DEFAULT );
547                         }
548                         *len = LBER_NTOHL( netlen );
549                 } else {
550                         *len = lc;
551                 }
552                 ber->ber_len = *len;
553
554                 /*
555                  * Finally, malloc a buffer for the contents and read it in.
556                  * It's this buffer that's passed to all the other ber decoding
557                  * routines.
558                  */
559
560 #if defined( DOS ) && !defined( _WIN32 )
561                 if ( *len > 65535 ) {   /* DOS can't allocate > 64K */
562                     return( LBER_DEFAULT );
563                 }
564 #endif /* DOS && !_WIN32 */
565
566                 if ( ( sb->sb_options & LBER_MAX_INCOMING_SIZE ) &&
567                     *len > sb->sb_max_incoming ) {
568                         return( LBER_DEFAULT );
569                 }
570
571                 if ( (ber->ber_buf = (char *) malloc( (size_t)*len )) == NULL ) {
572                         return( LBER_DEFAULT );
573                 }
574                 ber->ber_ptr = ber->ber_buf;
575                 ber->ber_end = ber->ber_buf + *len;
576                 ber->ber_rwptr = ber->ber_buf;
577         }
578
579         toread = (unsigned long)ber->ber_end - (unsigned long)ber->ber_rwptr;
580         do {
581                 if ( (rc = BerRead( sb, ber->ber_rwptr, (long)toread )) <= 0 ) {
582                         return( LBER_DEFAULT );
583                 }
584
585                 toread -= rc;
586                 ber->ber_rwptr += rc;
587         } while ( toread > 0 );
588
589 #ifdef LDAP_DEBUG
590         if ( lber_debug ) {
591                 fprintf( stderr, "ber_get_next: tag 0x%lx len %ld contents:\n",
592                     tag, ber->ber_len );
593                 if ( lber_debug > 1 )
594                         ber_dump( ber, 1 );
595         }
596 #endif
597
598         *len = ber->ber_len;
599         ber->ber_rwptr = NULL;
600         return( ber->ber_tag );
601 }