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