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