1 /* $NetBSD: io.c,v 1.3 2021/08/14 16:14:55 christos Exp $ */ 2 3 /* io.c - ber general i/o routines */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2021 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 /* Portions Copyright (c) 1990 Regents of the University of Michigan. 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms are permitted 22 * provided that this notice is preserved and that due credit is given 23 * to the University of Michigan at Ann Arbor. The name of the University 24 * may not be used to endorse or promote products derived from this 25 * software without specific prior written permission. This software 26 * is provided ``as is'' without express or implied warranty. 27 */ 28 /* ACKNOWLEDGEMENTS: 29 * This work was originally developed by the University of Michigan 30 * (as part of U-MICH LDAP). 31 */ 32 33 #include <sys/cdefs.h> 34 __RCSID("$NetBSD: io.c,v 1.3 2021/08/14 16:14:55 christos Exp $"); 35 36 #include "portable.h" 37 38 #include <stdio.h> 39 40 #include <ac/stdlib.h> 41 42 #include <ac/ctype.h> 43 #include <ac/errno.h> 44 #include <ac/socket.h> 45 #include <ac/string.h> 46 #include <ac/unistd.h> 47 48 #ifdef HAVE_IO_H 49 #include <io.h> 50 #endif 51 52 #include "lber-int.h" 53 #include "ldap_log.h" 54 55 ber_slen_t 56 ber_skip_data( 57 BerElement *ber, 58 ber_len_t len ) 59 { 60 ber_len_t actuallen, nleft; 61 62 assert( ber != NULL ); 63 assert( LBER_VALID( ber ) ); 64 65 nleft = ber_pvt_ber_remaining( ber ); 66 actuallen = nleft < len ? nleft : len; 67 ber->ber_ptr += actuallen; 68 ber->ber_tag = *(unsigned char *)ber->ber_ptr; 69 70 return( (ber_slen_t) actuallen ); 71 } 72 73 /* 74 * Read from the ber buffer. The caller must maintain ber->ber_tag. 75 * Do not use to read whole tags. See ber_get_tag() and ber_skip_data(). 76 */ 77 ber_slen_t 78 ber_read( 79 BerElement *ber, 80 char *buf, 81 ber_len_t len ) 82 { 83 ber_len_t actuallen, nleft; 84 85 assert( ber != NULL ); 86 assert( buf != NULL ); 87 assert( LBER_VALID( ber ) ); 88 89 nleft = ber_pvt_ber_remaining( ber ); 90 actuallen = nleft < len ? nleft : len; 91 92 AC_MEMCPY( buf, ber->ber_ptr, actuallen ); 93 94 ber->ber_ptr += actuallen; 95 96 return( (ber_slen_t) actuallen ); 97 } 98 99 /* 100 * Write to the ber buffer. 101 * Note that ber_start_seqorset/ber_put_seqorset() bypass ber_write(). 102 */ 103 ber_slen_t 104 ber_write( 105 BerElement *ber, 106 LDAP_CONST char *buf, 107 ber_len_t len, 108 int zero ) /* nonzero is unsupported from OpenLDAP 2.4.18 */ 109 { 110 char **p; 111 112 assert( ber != NULL ); 113 assert( buf != NULL ); 114 assert( LBER_VALID( ber ) ); 115 116 if ( zero != 0 ) { 117 ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, "%s", 118 "ber_write: nonzero 4th argument not supported\n" ); 119 return( -1 ); 120 } 121 122 p = ber->ber_sos_ptr == NULL ? &ber->ber_ptr : &ber->ber_sos_ptr; 123 if ( len > (ber_len_t) (ber->ber_end - *p) ) { 124 if ( ber_realloc( ber, len ) != 0 ) return( -1 ); 125 } 126 AC_MEMCPY( *p, buf, len ); 127 *p += len; 128 129 return( (ber_slen_t) len ); 130 } 131 132 /* Resize the ber buffer */ 133 int 134 ber_realloc( BerElement *ber, ber_len_t len ) 135 { 136 ber_len_t total, offset, sos_offset, rw_offset; 137 char *buf; 138 139 assert( ber != NULL ); 140 assert( LBER_VALID( ber ) ); 141 142 /* leave room for ber_flatten() to \0-terminate ber_buf */ 143 if ( ++len == 0 ) { 144 return( -1 ); 145 } 146 147 total = ber_pvt_ber_total( ber ); 148 149 #define LBER_EXBUFSIZ 4060 /* a few words less than 2^N for binary buddy */ 150 #if defined( LBER_EXBUFSIZ ) && LBER_EXBUFSIZ > 0 151 # ifndef notdef 152 /* don't realloc by small amounts */ 153 total += len < LBER_EXBUFSIZ ? LBER_EXBUFSIZ : len; 154 # else 155 { /* not sure what value this adds. reduce fragmentation? */ 156 ber_len_t have = (total + (LBER_EXBUFSIZE - 1)) / LBER_EXBUFSIZ; 157 ber_len_t need = (len + (LBER_EXBUFSIZ - 1)) / LBER_EXBUFSIZ; 158 total = ( have + need ) * LBER_EXBUFSIZ; 159 } 160 # endif 161 #else 162 total += len; /* realloc just what's needed */ 163 #endif 164 165 if ( total < len || total > (ber_len_t)-1 / 2 /* max ber_slen_t */ ) { 166 return( -1 ); 167 } 168 169 buf = ber->ber_buf; 170 offset = ber->ber_ptr - buf; 171 sos_offset = ber->ber_sos_ptr ? ber->ber_sos_ptr - buf : 0; 172 /* if ber_sos_ptr != NULL, it is > ber_buf so that sos_offset > 0 */ 173 rw_offset = ber->ber_rwptr ? ber->ber_rwptr - buf : 0; 174 175 buf = (char *) ber_memrealloc_x( buf, total, ber->ber_memctx ); 176 if ( buf == NULL ) { 177 return( -1 ); 178 } 179 180 ber->ber_buf = buf; 181 ber->ber_end = buf + total; 182 ber->ber_ptr = buf + offset; 183 if ( sos_offset ) 184 ber->ber_sos_ptr = buf + sos_offset; 185 if ( ber->ber_rwptr ) 186 ber->ber_rwptr = buf + rw_offset; 187 188 return( 0 ); 189 } 190 191 void 192 ber_free_buf( BerElement *ber ) 193 { 194 assert( LBER_VALID( ber ) ); 195 196 if ( ber->ber_buf) ber_memfree_x( ber->ber_buf, ber->ber_memctx ); 197 198 ber->ber_buf = NULL; 199 ber->ber_sos_ptr = NULL; 200 ber->ber_valid = LBER_UNINITIALIZED; 201 } 202 203 void 204 ber_free( BerElement *ber, int freebuf ) 205 { 206 if( ber == NULL ) { 207 LDAP_MEMORY_DEBUG_ASSERT( ber != NULL ); 208 return; 209 } 210 211 if( freebuf ) ber_free_buf( ber ); 212 213 ber_memfree_x( (char *) ber, ber->ber_memctx ); 214 } 215 216 int 217 ber_flush( Sockbuf *sb, BerElement *ber, int freeit ) 218 { 219 return ber_flush2( sb, ber, 220 freeit ? LBER_FLUSH_FREE_ON_SUCCESS 221 : LBER_FLUSH_FREE_NEVER ); 222 } 223 224 int 225 ber_flush2( Sockbuf *sb, BerElement *ber, int freeit ) 226 { 227 ber_len_t towrite; 228 ber_slen_t rc; 229 230 assert( sb != NULL ); 231 assert( ber != NULL ); 232 assert( SOCKBUF_VALID( sb ) ); 233 assert( LBER_VALID( ber ) ); 234 235 if ( ber->ber_rwptr == NULL ) { 236 ber->ber_rwptr = ber->ber_buf; 237 } 238 towrite = ber->ber_ptr - ber->ber_rwptr; 239 240 if ( sb->sb_debug ) { 241 ber_log_printf( LDAP_DEBUG_TRACE, sb->sb_debug, 242 "ber_flush2: %ld bytes to sd %ld%s\n", 243 towrite, (long) sb->sb_fd, 244 ber->ber_rwptr != ber->ber_buf ? " (re-flush)" : "" ); 245 ber_log_bprint( LDAP_DEBUG_BER, sb->sb_debug, 246 ber->ber_rwptr, towrite ); 247 } 248 249 while ( towrite > 0 ) { 250 #ifdef LBER_TRICKLE 251 sleep(1); 252 rc = ber_int_sb_write( sb, ber->ber_rwptr, 1 ); 253 #else 254 rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite ); 255 #endif 256 if ( rc <= 0 ) { 257 if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 ); 258 return -1; 259 } 260 towrite -= rc; 261 ber->ber_rwptr += rc; 262 } 263 264 if ( freeit & LBER_FLUSH_FREE_ON_SUCCESS ) ber_free( ber, 1 ); 265 266 return 0; 267 } 268 269 BerElement * 270 ber_alloc_t( int options ) 271 { 272 BerElement *ber; 273 274 ber = (BerElement *) LBER_CALLOC( 1, sizeof(BerElement) ); 275 276 if ( ber == NULL ) { 277 return NULL; 278 } 279 280 ber->ber_valid = LBER_VALID_BERELEMENT; 281 ber->ber_tag = LBER_DEFAULT; 282 ber->ber_options = options; 283 ber->ber_debug = ber_int_debug; 284 285 assert( LBER_VALID( ber ) ); 286 return ber; 287 } 288 289 BerElement * 290 ber_alloc( void ) /* deprecated */ 291 { 292 return ber_alloc_t( 0 ); 293 } 294 295 BerElement * 296 der_alloc( void ) /* deprecated */ 297 { 298 return ber_alloc_t( LBER_USE_DER ); 299 } 300 301 BerElement * 302 ber_dup( BerElement *ber ) 303 { 304 BerElement *new; 305 306 assert( ber != NULL ); 307 assert( LBER_VALID( ber ) ); 308 309 if ( (new = ber_alloc_t( ber->ber_options )) == NULL ) { 310 return NULL; 311 } 312 313 *new = *ber; 314 315 assert( LBER_VALID( new ) ); 316 return( new ); 317 } 318 319 320 void 321 ber_init2( BerElement *ber, struct berval *bv, int options ) 322 { 323 assert( ber != NULL ); 324 325 (void) memset( (char *)ber, '\0', sizeof( BerElement )); 326 ber->ber_valid = LBER_VALID_BERELEMENT; 327 ber->ber_tag = LBER_DEFAULT; 328 ber->ber_options = (char) options; 329 ber->ber_debug = ber_int_debug; 330 331 if ( bv != NULL ) { 332 ber->ber_buf = bv->bv_val; 333 ber->ber_ptr = ber->ber_buf; 334 ber->ber_end = ber->ber_buf + bv->bv_len; 335 } 336 337 assert( LBER_VALID( ber ) ); 338 } 339 340 /* OLD U-Mich ber_init() */ 341 void 342 ber_init_w_nullc( BerElement *ber, int options ) 343 { 344 ber_init2( ber, NULL, options ); 345 } 346 347 /* New C-API ber_init() */ 348 /* This function constructs a BerElement containing a copy 349 ** of the data in the bv argument. 350 */ 351 BerElement * 352 ber_init( struct berval *bv ) 353 { 354 BerElement *ber; 355 356 assert( bv != NULL ); 357 358 if ( bv == NULL ) { 359 return NULL; 360 } 361 362 ber = ber_alloc_t( 0 ); 363 364 if( ber == NULL ) { 365 /* allocation failed */ 366 return NULL; 367 } 368 369 /* copy the data */ 370 if ( ((ber_len_t) ber_write ( ber, bv->bv_val, bv->bv_len, 0 )) 371 != bv->bv_len ) 372 { 373 /* write failed, so free and return NULL */ 374 ber_free( ber, 1 ); 375 return NULL; 376 } 377 378 ber_reset( ber, 1 ); /* reset the pointer to the start of the buffer */ 379 return ber; 380 } 381 382 /* New C-API ber_flatten routine */ 383 /* This routine allocates a struct berval whose contents are a BER 384 ** encoding taken from the ber argument. The bvPtr pointer points to 385 ** the returned berval. 386 ** 387 ** ber_flatten2 is the same, but uses a struct berval passed by 388 ** the caller. If alloc is 0 the returned bv uses the ber buf directly. 389 */ 390 int ber_flatten2( 391 BerElement *ber, 392 struct berval *bv, 393 int alloc ) 394 { 395 assert( bv != NULL ); 396 397 if ( bv == NULL ) { 398 return -1; 399 } 400 401 if ( ber == NULL ) { 402 /* ber is null, create an empty berval */ 403 bv->bv_val = NULL; 404 bv->bv_len = 0; 405 406 } else if ( ber->ber_sos_ptr != NULL ) { 407 /* unmatched "{" and "}" */ 408 return -1; 409 410 } else { 411 /* copy the berval */ 412 ber_len_t len = ber_pvt_ber_write( ber ); 413 414 if ( alloc ) { 415 bv->bv_val = (char *) ber_memalloc_x( len + 1, ber->ber_memctx ); 416 if ( bv->bv_val == NULL ) { 417 return -1; 418 } 419 AC_MEMCPY( bv->bv_val, ber->ber_buf, len ); 420 bv->bv_val[len] = '\0'; 421 } else if ( ber->ber_buf != NULL ) { 422 bv->bv_val = ber->ber_buf; 423 bv->bv_val[len] = '\0'; 424 } else { 425 bv->bv_val = ""; 426 } 427 bv->bv_len = len; 428 } 429 return 0; 430 } 431 432 int ber_flatten( 433 BerElement *ber, 434 struct berval **bvPtr) 435 { 436 struct berval *bv; 437 int rc; 438 439 assert( bvPtr != NULL ); 440 441 if(bvPtr == NULL) { 442 return -1; 443 } 444 445 bv = ber_memalloc_x( sizeof(struct berval), ber->ber_memctx ); 446 if ( bv == NULL ) { 447 return -1; 448 } 449 rc = ber_flatten2(ber, bv, 1); 450 if (rc == -1) { 451 ber_memfree_x(bv, ber->ber_memctx); 452 } else { 453 *bvPtr = bv; 454 } 455 return rc; 456 } 457 458 void 459 ber_reset( BerElement *ber, int was_writing ) 460 { 461 assert( ber != NULL ); 462 assert( LBER_VALID( ber ) ); 463 464 if ( was_writing ) { 465 ber->ber_end = ber->ber_ptr; 466 ber->ber_ptr = ber->ber_buf; 467 468 } else { 469 ber->ber_ptr = ber->ber_end; 470 } 471 472 ber->ber_rwptr = NULL; 473 } 474 475 /* 476 * A rewrite of ber_get_next that can safely be called multiple times 477 * for the same packet. It will simply continue where it stopped until 478 * a full packet is read. 479 */ 480 481 #define LENSIZE 4 482 483 ber_tag_t 484 ber_get_next( 485 Sockbuf *sb, 486 ber_len_t *len, 487 BerElement *ber ) 488 { 489 assert( sb != NULL ); 490 assert( len != NULL ); 491 assert( ber != NULL ); 492 assert( SOCKBUF_VALID( sb ) ); 493 assert( LBER_VALID( ber ) ); 494 495 if ( ber->ber_debug & LDAP_DEBUG_TRACE ) { 496 ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, 497 "ber_get_next\n" ); 498 } 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 * The code also handles multi-byte tags. The first few bytes 512 * of the message are read to check for multi-byte tags and 513 * lengths. These bytes are temporarily stored in the ber_tag, 514 * ber_len, and ber_usertag fields of the berelement until 515 * tag/len parsing is complete. After this parsing, any leftover 516 * bytes and the rest of the message are copied into the ber_buf. 517 * 518 * We expect tag and len to be at most 32 bits wide. 519 */ 520 521 if (ber->ber_rwptr == NULL) { 522 assert( ber->ber_buf == NULL ); 523 ber->ber_rwptr = (char *) &ber->ber_len-1; 524 ber->ber_ptr = ber->ber_rwptr; 525 ber->ber_tag = 0; 526 } 527 528 while (ber->ber_rwptr > (char *)&ber->ber_tag && ber->ber_rwptr < 529 (char *)&ber->ber_len + LENSIZE*2) { 530 ber_slen_t sblen; 531 char buf[sizeof(ber->ber_len)-1]; 532 ber_len_t tlen = 0; 533 534 /* The tag & len can be at most 9 bytes; we try to read up to 8 here */ 535 sock_errset(0); 536 sblen=((char *)&ber->ber_len + LENSIZE*2 - 1)-ber->ber_rwptr; 537 /* Trying to read the last len byte of a 9 byte tag+len */ 538 if (sblen<1) 539 sblen = 1; 540 sblen=ber_int_sb_read( sb, ber->ber_rwptr, sblen ); 541 if (sblen<=0) return LBER_DEFAULT; 542 ber->ber_rwptr += sblen; 543 544 /* We got at least one byte, try to parse the tag. */ 545 if (ber->ber_ptr == (char *)&ber->ber_len-1) { 546 ber_tag_t tag; 547 unsigned char *p = (unsigned char *)ber->ber_ptr; 548 tag = *p++; 549 if ((tag & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK) { 550 ber_len_t i; 551 for (i=1; (char *)p<ber->ber_rwptr; i++) { 552 tag <<= 8; 553 tag |= *p++; 554 if (!(tag & LBER_MORE_TAG_MASK)) 555 break; 556 /* Is the tag too big? */ 557 if (i == sizeof(ber_tag_t)-1) { 558 sock_errset(ERANGE); 559 return LBER_DEFAULT; 560 } 561 } 562 /* Did we run out of bytes? */ 563 if ((char *)p == ber->ber_rwptr) { 564 sock_errset(EWOULDBLOCK); 565 return LBER_DEFAULT; 566 } 567 } 568 ber->ber_tag = tag; 569 ber->ber_ptr = (char *)p; 570 } 571 572 if ( ber->ber_ptr == ber->ber_rwptr ) { 573 sock_errset(EWOULDBLOCK); 574 return LBER_DEFAULT; 575 } 576 577 /* Now look for the length */ 578 if (*ber->ber_ptr & 0x80) { /* multi-byte */ 579 int i; 580 unsigned char *p = (unsigned char *)ber->ber_ptr; 581 int llen = *p++ & 0x7f; 582 if (llen > LENSIZE) { 583 sock_errset(ERANGE); 584 return LBER_DEFAULT; 585 } 586 /* Not enough bytes? */ 587 if (ber->ber_rwptr - (char *)p < llen) { 588 sock_errset(EWOULDBLOCK); 589 return LBER_DEFAULT; 590 } 591 for (i=0; i<llen; i++) { 592 tlen <<=8; 593 tlen |= *p++; 594 } 595 ber->ber_ptr = (char *)p; 596 } else { 597 tlen = *(unsigned char *)ber->ber_ptr++; 598 } 599 600 /* Are there leftover data bytes inside ber->ber_len? */ 601 if (ber->ber_ptr < (char *)&ber->ber_usertag) { 602 if (ber->ber_rwptr < (char *)&ber->ber_usertag) { 603 sblen = ber->ber_rwptr - ber->ber_ptr; 604 } else { 605 sblen = (char *)&ber->ber_usertag - ber->ber_ptr; 606 } 607 AC_MEMCPY(buf, ber->ber_ptr, sblen); 608 ber->ber_ptr += sblen; 609 } else { 610 sblen = 0; 611 } 612 ber->ber_len = tlen; 613 614 /* now fill the buffer. */ 615 616 /* make sure length is reasonable */ 617 if ( ber->ber_len == 0 ) { 618 sock_errset(ERANGE); 619 return LBER_DEFAULT; 620 } 621 622 if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) { 623 ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug, 624 "ber_get_next: sockbuf_max_incoming exceeded " 625 "(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming ); 626 sock_errset(ERANGE); 627 return LBER_DEFAULT; 628 } 629 630 if (ber->ber_buf==NULL) { 631 ber_len_t l = ber->ber_rwptr - ber->ber_ptr; 632 /* ber->ber_ptr is always <= ber->ber->ber_rwptr. 633 * make sure ber->ber_len agrees with what we've 634 * already read. 635 */ 636 if ( ber->ber_len < sblen + l ) { 637 sock_errset(ERANGE); 638 return LBER_DEFAULT; 639 } 640 ber->ber_buf = (char *) ber_memalloc_x( ber->ber_len + 1, ber->ber_memctx ); 641 if (ber->ber_buf==NULL) { 642 return LBER_DEFAULT; 643 } 644 ber->ber_end = ber->ber_buf + ber->ber_len; 645 if (sblen) { 646 AC_MEMCPY(ber->ber_buf, buf, sblen); 647 } 648 if (l > 0) { 649 AC_MEMCPY(ber->ber_buf + sblen, ber->ber_ptr, l); 650 sblen += l; 651 } 652 *ber->ber_end = '\0'; 653 ber->ber_ptr = ber->ber_buf; 654 ber->ber_usertag = 0; 655 if ((ber_len_t)sblen == ber->ber_len) { 656 goto done; 657 } 658 ber->ber_rwptr = ber->ber_buf + sblen; 659 } 660 } 661 662 if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) { 663 ber_slen_t res; 664 ber_slen_t to_go; 665 666 to_go = ber->ber_end - ber->ber_rwptr; 667 /* unsigned/signed overflow */ 668 if (to_go<0) return LBER_DEFAULT; 669 670 sock_errset(0); 671 res = ber_int_sb_read( sb, ber->ber_rwptr, to_go ); 672 if (res<=0) return LBER_DEFAULT; 673 ber->ber_rwptr+=res; 674 675 if (res<to_go) { 676 sock_errset(EWOULDBLOCK); 677 return LBER_DEFAULT; 678 } 679 done: 680 ber->ber_rwptr = NULL; 681 *len = ber->ber_len; 682 if ( ber->ber_debug ) { 683 ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug, 684 "ber_get_next: tag 0x%lx len %ld contents:\n", 685 ber->ber_tag, ber->ber_len ); 686 ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 ); 687 } 688 return (ber->ber_tag); 689 } 690 691 /* invalid input */ 692 return LBER_DEFAULT; 693 } 694 695 char * 696 ber_start( BerElement* ber ) 697 { 698 return ber->ber_buf; 699 } 700 701 int 702 ber_len( BerElement* ber ) 703 { 704 return ( ber->ber_end - ber->ber_buf ); 705 } 706 707 int 708 ber_ptrlen( BerElement* ber ) 709 { 710 return ( ber->ber_ptr - ber->ber_buf ); 711 } 712 713 void 714 ber_rewind ( BerElement * ber ) 715 { 716 ber->ber_rwptr = NULL; 717 ber->ber_sos_ptr = NULL; 718 ber->ber_end = ber->ber_ptr; 719 ber->ber_ptr = ber->ber_buf; 720 #if 0 /* TODO: Should we add this? */ 721 ber->ber_tag = LBER_DEFAULT; 722 ber->ber_usertag = 0; 723 #endif 724 } 725 726 int 727 ber_remaining( BerElement * ber ) 728 { 729 return ber_pvt_ber_remaining( ber ); 730 } 731