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