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