1/* 2 Unix SMB/CIFS implementation. 3 Infrastructure for async SMB client requests 4 Copyright (C) Volker Lendecke 2008 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18*/ 19 20#include "includes.h" 21 22/* 23 * Read an smb packet asynchronously, discard keepalives 24 */ 25 26struct read_smb_state { 27 struct tevent_context *ev; 28 int fd; 29 uint8_t *buf; 30}; 31 32static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data); 33static void read_smb_done(struct tevent_req *subreq); 34 35static struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx, 36 struct tevent_context *ev, 37 int fd) 38{ 39 struct tevent_req *result, *subreq; 40 struct read_smb_state *state; 41 42 result = tevent_req_create(mem_ctx, &state, struct read_smb_state); 43 if (result == NULL) { 44 return NULL; 45 } 46 state->ev = ev; 47 state->fd = fd; 48 49 subreq = read_packet_send(state, ev, fd, 4, read_smb_more, NULL); 50 if (subreq == NULL) { 51 goto fail; 52 } 53 tevent_req_set_callback(subreq, read_smb_done, result); 54 return result; 55 fail: 56 TALLOC_FREE(result); 57 return NULL; 58} 59 60static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data) 61{ 62 if (buflen > 4) { 63 return 0; /* We've been here, we're done */ 64 } 65 return smb_len_large(buf); 66} 67 68static void read_smb_done(struct tevent_req *subreq) 69{ 70 struct tevent_req *req = tevent_req_callback_data( 71 subreq, struct tevent_req); 72 struct read_smb_state *state = tevent_req_data( 73 req, struct read_smb_state); 74 ssize_t len; 75 int err; 76 77 len = read_packet_recv(subreq, state, &state->buf, &err); 78 TALLOC_FREE(subreq); 79 if (len == -1) { 80 tevent_req_error(req, err); 81 return; 82 } 83 84 if (CVAL(state->buf, 0) == SMBkeepalive) { 85 subreq = read_packet_send(state, state->ev, state->fd, 4, 86 read_smb_more, NULL); 87 if (tevent_req_nomem(subreq, req)) { 88 return; 89 } 90 tevent_req_set_callback(subreq, read_smb_done, req); 91 return; 92 } 93 tevent_req_done(req); 94} 95 96static ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 97 uint8_t **pbuf, int *perrno) 98{ 99 struct read_smb_state *state = tevent_req_data( 100 req, struct read_smb_state); 101 102 if (tevent_req_is_unix_error(req, perrno)) { 103 return -1; 104 } 105 *pbuf = talloc_move(mem_ctx, &state->buf); 106 return talloc_get_size(*pbuf); 107} 108 109/** 110 * Fetch an error out of a NBT packet 111 * @param[in] buf The SMB packet 112 * @retval The error, converted to NTSTATUS 113 */ 114 115NTSTATUS cli_pull_error(char *buf) 116{ 117 uint32_t flags2 = SVAL(buf, smb_flg2); 118 119 if (flags2 & FLAGS2_32_BIT_ERROR_CODES) { 120 return NT_STATUS(IVAL(buf, smb_rcls)); 121 } 122 123 /* if the client uses dos errors, but there is no error, 124 we should return no error here, otherwise it looks 125 like an unknown bad NT_STATUS. jmcd */ 126 if (CVAL(buf, smb_rcls) == 0) 127 return NT_STATUS_OK; 128 129 return NT_STATUS_DOS(CVAL(buf, smb_rcls), SVAL(buf,smb_err)); 130} 131 132/** 133 * Compatibility helper for the sync APIs: Fake NTSTATUS in cli->inbuf 134 * @param[in] cli The client connection that just received an error 135 * @param[in] status The error to set on "cli" 136 */ 137 138void cli_set_error(struct cli_state *cli, NTSTATUS status) 139{ 140 uint32_t flags2 = SVAL(cli->inbuf, smb_flg2); 141 142 if (NT_STATUS_IS_DOS(status)) { 143 SSVAL(cli->inbuf, smb_flg2, 144 flags2 & ~FLAGS2_32_BIT_ERROR_CODES); 145 SCVAL(cli->inbuf, smb_rcls, NT_STATUS_DOS_CLASS(status)); 146 SSVAL(cli->inbuf, smb_err, NT_STATUS_DOS_CODE(status)); 147 return; 148 } 149 150 SSVAL(cli->inbuf, smb_flg2, flags2 | FLAGS2_32_BIT_ERROR_CODES); 151 SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(status)); 152 return; 153} 154 155/** 156 * Figure out if there is an andx command behind the current one 157 * @param[in] buf The smb buffer to look at 158 * @param[in] ofs The offset to the wct field that is followed by the cmd 159 * @retval Is there a command following? 160 */ 161 162static bool have_andx_command(const char *buf, uint16_t ofs) 163{ 164 uint8_t wct; 165 size_t buflen = talloc_get_size(buf); 166 167 if ((ofs == buflen-1) || (ofs == buflen)) { 168 return false; 169 } 170 171 wct = CVAL(buf, ofs); 172 if (wct < 2) { 173 /* 174 * Not enough space for the command and a following pointer 175 */ 176 return false; 177 } 178 return (CVAL(buf, ofs+1) != 0xff); 179} 180 181#define MAX_SMB_IOV 5 182 183struct cli_smb_state { 184 struct tevent_context *ev; 185 struct cli_state *cli; 186 uint8_t header[smb_wct+1]; /* Space for the header including the wct */ 187 188 /* 189 * For normal requests, cli_smb_req_send chooses a mid. Secondary 190 * trans requests need to use the mid of the primary request, so we 191 * need a place to store it. Assume it's set if != 0. 192 */ 193 uint16_t mid; 194 195 uint16_t *vwv; 196 uint8_t bytecount_buf[2]; 197 198 struct iovec iov[MAX_SMB_IOV+3]; 199 int iov_count; 200 201 uint8_t *inbuf; 202 uint32_t seqnum; 203 int chain_num; 204 struct tevent_req **chained_requests; 205}; 206 207static uint16_t cli_alloc_mid(struct cli_state *cli) 208{ 209 int num_pending = talloc_array_length(cli->pending); 210 uint16_t result; 211 212 while (true) { 213 int i; 214 215 result = cli->mid++; 216 if ((result == 0) || (result == 0xffff)) { 217 continue; 218 } 219 220 for (i=0; i<num_pending; i++) { 221 if (result == cli_smb_req_mid(cli->pending[i])) { 222 break; 223 } 224 } 225 226 if (i == num_pending) { 227 return result; 228 } 229 } 230} 231 232void cli_smb_req_unset_pending(struct tevent_req *req) 233{ 234 struct cli_smb_state *state = tevent_req_data( 235 req, struct cli_smb_state); 236 struct cli_state *cli = state->cli; 237 int num_pending = talloc_array_length(cli->pending); 238 int i; 239 240 if (num_pending == 1) { 241 /* 242 * The pending read_smb tevent_req is a child of 243 * cli->pending. So if nothing is pending anymore, we need to 244 * delete the socket read fde. 245 */ 246 TALLOC_FREE(cli->pending); 247 return; 248 } 249 250 for (i=0; i<num_pending; i++) { 251 if (req == cli->pending[i]) { 252 break; 253 } 254 } 255 if (i == num_pending) { 256 /* 257 * Something's seriously broken. Just returning here is the 258 * right thing nevertheless, the point of this routine is to 259 * remove ourselves from cli->pending. 260 */ 261 return; 262 } 263 264 /* 265 * Remove ourselves from the cli->pending array 266 */ 267 if (num_pending > 1) { 268 cli->pending[i] = cli->pending[num_pending-1]; 269 } 270 271 /* 272 * No NULL check here, we're shrinking by sizeof(void *), and 273 * talloc_realloc just adjusts the size for this. 274 */ 275 cli->pending = talloc_realloc(NULL, cli->pending, struct tevent_req *, 276 num_pending - 1); 277 return; 278} 279 280static int cli_smb_req_destructor(struct tevent_req *req) 281{ 282 cli_smb_req_unset_pending(req); 283 return 0; 284} 285 286static void cli_smb_received(struct tevent_req *subreq); 287 288bool cli_smb_req_set_pending(struct tevent_req *req) 289{ 290 struct cli_smb_state *state = tevent_req_data( 291 req, struct cli_smb_state); 292 struct cli_state *cli; 293 struct tevent_req **pending; 294 int num_pending; 295 struct tevent_req *subreq; 296 297 cli = state->cli; 298 num_pending = talloc_array_length(cli->pending); 299 300 pending = talloc_realloc(cli, cli->pending, struct tevent_req *, 301 num_pending+1); 302 if (pending == NULL) { 303 return false; 304 } 305 pending[num_pending] = req; 306 cli->pending = pending; 307 talloc_set_destructor(req, cli_smb_req_destructor); 308 309 if (num_pending > 0) { 310 return true; 311 } 312 313 /* 314 * We're the first ones, add the read_smb request that waits for the 315 * answer from the server 316 */ 317 subreq = read_smb_send(cli->pending, state->ev, cli->fd); 318 if (subreq == NULL) { 319 cli_smb_req_unset_pending(req); 320 return false; 321 } 322 tevent_req_set_callback(subreq, cli_smb_received, cli); 323 return true; 324} 325 326/* 327 * Fetch a smb request's mid. Only valid after the request has been sent by 328 * cli_smb_req_send(). 329 */ 330uint16_t cli_smb_req_mid(struct tevent_req *req) 331{ 332 struct cli_smb_state *state = tevent_req_data( 333 req, struct cli_smb_state); 334 return SVAL(state->header, smb_mid); 335} 336 337void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid) 338{ 339 struct cli_smb_state *state = tevent_req_data( 340 req, struct cli_smb_state); 341 state->mid = mid; 342} 343 344static size_t iov_len(const struct iovec *iov, int count) 345{ 346 size_t result = 0; 347 int i; 348 for (i=0; i<count; i++) { 349 result += iov[i].iov_len; 350 } 351 return result; 352} 353 354static uint8_t *iov_concat(TALLOC_CTX *mem_ctx, const struct iovec *iov, 355 int count) 356{ 357 size_t len = iov_len(iov, count); 358 size_t copied; 359 uint8_t *buf; 360 int i; 361 362 buf = talloc_array(mem_ctx, uint8_t, len); 363 if (buf == NULL) { 364 return NULL; 365 } 366 copied = 0; 367 for (i=0; i<count; i++) { 368 memcpy(buf+copied, iov[i].iov_base, iov[i].iov_len); 369 copied += iov[i].iov_len; 370 } 371 return buf; 372} 373 374struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx, 375 struct event_context *ev, 376 struct cli_state *cli, 377 uint8_t smb_command, 378 uint8_t additional_flags, 379 uint8_t wct, uint16_t *vwv, 380 int iov_count, 381 struct iovec *bytes_iov) 382{ 383 struct tevent_req *result; 384 struct cli_smb_state *state; 385 struct timeval endtime; 386 387 if (iov_count > MAX_SMB_IOV) { 388 /* 389 * Should not happen :-) 390 */ 391 return NULL; 392 } 393 394 result = tevent_req_create(mem_ctx, &state, struct cli_smb_state); 395 if (result == NULL) { 396 return NULL; 397 } 398 state->ev = ev; 399 state->cli = cli; 400 state->mid = 0; /* Set to auto-choose in cli_smb_req_send */ 401 state->chain_num = 0; 402 state->chained_requests = NULL; 403 404 cli_setup_packet_buf(cli, (char *)state->header); 405 SCVAL(state->header, smb_com, smb_command); 406 SSVAL(state->header, smb_tid, cli->cnum); 407 SCVAL(state->header, smb_wct, wct); 408 409 state->vwv = vwv; 410 411 SSVAL(state->bytecount_buf, 0, iov_len(bytes_iov, iov_count)); 412 413 state->iov[0].iov_base = (void *)state->header; 414 state->iov[0].iov_len = sizeof(state->header); 415 state->iov[1].iov_base = (void *)state->vwv; 416 state->iov[1].iov_len = wct * sizeof(uint16_t); 417 state->iov[2].iov_base = (void *)state->bytecount_buf; 418 state->iov[2].iov_len = sizeof(uint16_t); 419 420 if (iov_count != 0) { 421 memcpy(&state->iov[3], bytes_iov, 422 iov_count * sizeof(*bytes_iov)); 423 } 424 state->iov_count = iov_count + 3; 425 426 endtime = timeval_current_ofs(0, cli->timeout * 1000); 427 if (!tevent_req_set_endtime(result, ev, endtime)) { 428 tevent_req_nomem(NULL, result); 429 } 430 return result; 431} 432 433static NTSTATUS cli_signv(struct cli_state *cli, struct iovec *iov, int count, 434 uint32_t *seqnum) 435{ 436 uint8_t *buf; 437 438 /* 439 * Obvious optimization: Make cli_calculate_sign_mac work with struct 440 * iovec directly. MD5Update would do that just fine. 441 */ 442 443 if ((count <= 0) || (iov[0].iov_len < smb_wct)) { 444 return NT_STATUS_INVALID_PARAMETER; 445 } 446 447 buf = iov_concat(talloc_tos(), iov, count); 448 if (buf == NULL) { 449 return NT_STATUS_NO_MEMORY; 450 } 451 452 cli_calculate_sign_mac(cli, (char *)buf, seqnum); 453 memcpy(iov[0].iov_base, buf, iov[0].iov_len); 454 455 TALLOC_FREE(buf); 456 return NT_STATUS_OK; 457} 458 459static void cli_smb_sent(struct tevent_req *subreq); 460 461static NTSTATUS cli_smb_req_iov_send(struct tevent_req *req, 462 struct cli_smb_state *state, 463 struct iovec *iov, int iov_count) 464{ 465 struct tevent_req *subreq; 466 NTSTATUS status; 467 468 if (state->cli->fd == -1) { 469 return NT_STATUS_CONNECTION_INVALID; 470 } 471 472 if (iov[0].iov_len < smb_wct) { 473 return NT_STATUS_INVALID_PARAMETER; 474 } 475 476 if (state->mid != 0) { 477 SSVAL(iov[0].iov_base, smb_mid, state->mid); 478 } else { 479 uint16_t mid = cli_alloc_mid(state->cli); 480 SSVAL(iov[0].iov_base, smb_mid, mid); 481 } 482 483 smb_setlen((char *)iov[0].iov_base, iov_len(iov, iov_count) - 4); 484 485 status = cli_signv(state->cli, iov, iov_count, &state->seqnum); 486 487 if (!NT_STATUS_IS_OK(status)) { 488 return status; 489 } 490 491 if (cli_encryption_on(state->cli)) { 492 char *buf, *enc_buf; 493 494 buf = (char *)iov_concat(talloc_tos(), iov, iov_count); 495 if (buf == NULL) { 496 return NT_STATUS_NO_MEMORY; 497 } 498 status = cli_encrypt_message(state->cli, (char *)buf, 499 &enc_buf); 500 TALLOC_FREE(buf); 501 if (!NT_STATUS_IS_OK(status)) { 502 DEBUG(0, ("Error in encrypting client message: %s\n", 503 nt_errstr(status))); 504 return status; 505 } 506 buf = (char *)talloc_memdup(state, enc_buf, 507 smb_len(enc_buf)+4); 508 SAFE_FREE(enc_buf); 509 if (buf == NULL) { 510 return NT_STATUS_NO_MEMORY; 511 } 512 iov[0].iov_base = (void *)buf; 513 iov[0].iov_len = talloc_get_size(buf); 514 iov_count = 1; 515 } 516 subreq = writev_send(state, state->ev, state->cli->outgoing, 517 state->cli->fd, false, iov, iov_count); 518 if (subreq == NULL) { 519 return NT_STATUS_NO_MEMORY; 520 } 521 tevent_req_set_callback(subreq, cli_smb_sent, req); 522 return NT_STATUS_OK; 523} 524 525NTSTATUS cli_smb_req_send(struct tevent_req *req) 526{ 527 struct cli_smb_state *state = tevent_req_data( 528 req, struct cli_smb_state); 529 530 return cli_smb_req_iov_send(req, state, state->iov, state->iov_count); 531} 532 533struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx, 534 struct event_context *ev, 535 struct cli_state *cli, 536 uint8_t smb_command, 537 uint8_t additional_flags, 538 uint8_t wct, uint16_t *vwv, 539 uint32_t num_bytes, 540 const uint8_t *bytes) 541{ 542 struct tevent_req *req; 543 struct iovec iov; 544 NTSTATUS status; 545 546 iov.iov_base = CONST_DISCARD(void *, bytes); 547 iov.iov_len = num_bytes; 548 549 req = cli_smb_req_create(mem_ctx, ev, cli, smb_command, 550 additional_flags, wct, vwv, 1, &iov); 551 if (req == NULL) { 552 return NULL; 553 } 554 555 status = cli_smb_req_send(req); 556 if (!NT_STATUS_IS_OK(status)) { 557 tevent_req_nterror(req, status); 558 return tevent_req_post(req, ev); 559 } 560 return req; 561} 562 563static void cli_smb_sent(struct tevent_req *subreq) 564{ 565 struct tevent_req *req = tevent_req_callback_data( 566 subreq, struct tevent_req); 567 struct cli_smb_state *state = tevent_req_data( 568 req, struct cli_smb_state); 569 ssize_t nwritten; 570 int err; 571 572 nwritten = writev_recv(subreq, &err); 573 TALLOC_FREE(subreq); 574 if (nwritten == -1) { 575 if (state->cli->fd != -1) { 576 close(state->cli->fd); 577 state->cli->fd = -1; 578 } 579 tevent_req_nterror(req, map_nt_error_from_unix(err)); 580 return; 581 } 582 583 switch (CVAL(state->header, smb_com)) { 584 case SMBtranss: 585 case SMBtranss2: 586 case SMBnttranss: 587 case SMBntcancel: 588 state->inbuf = NULL; 589 tevent_req_done(req); 590 return; 591 case SMBlockingX: 592 if ((CVAL(state->header, smb_wct) == 8) && 593 (CVAL(state->vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) { 594 state->inbuf = NULL; 595 tevent_req_done(req); 596 return; 597 } 598 } 599 600 if (!cli_smb_req_set_pending(req)) { 601 tevent_req_nterror(req, NT_STATUS_NO_MEMORY); 602 return; 603 } 604} 605 606static void cli_smb_received(struct tevent_req *subreq) 607{ 608 struct cli_state *cli = tevent_req_callback_data( 609 subreq, struct cli_state); 610 struct tevent_req *req; 611 struct cli_smb_state *state; 612 struct tevent_context *ev; 613 NTSTATUS status; 614 uint8_t *inbuf; 615 ssize_t received; 616 int num_pending; 617 int i, err; 618 uint16_t mid; 619 bool oplock_break; 620 621 received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err); 622 TALLOC_FREE(subreq); 623 if (received == -1) { 624 if (cli->fd != -1) { 625 close(cli->fd); 626 cli->fd = -1; 627 } 628 status = map_nt_error_from_unix(err); 629 goto fail; 630 } 631 632 if ((IVAL(inbuf, 4) != 0x424d53ff) /* 0xFF"SMB" */ 633 && (SVAL(inbuf, 4) != 0x45ff)) /* 0xFF"E" */ { 634 DEBUG(10, ("Got non-SMB PDU\n")); 635 status = NT_STATUS_INVALID_NETWORK_RESPONSE; 636 goto fail; 637 } 638 639 if (cli_encryption_on(cli) && (CVAL(inbuf, 0) == 0)) { 640 uint16_t enc_ctx_num; 641 642 status = get_enc_ctx_num(inbuf, &enc_ctx_num); 643 if (!NT_STATUS_IS_OK(status)) { 644 DEBUG(10, ("get_enc_ctx_num returned %s\n", 645 nt_errstr(status))); 646 goto fail; 647 } 648 649 if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) { 650 DEBUG(10, ("wrong enc_ctx %d, expected %d\n", 651 enc_ctx_num, 652 cli->trans_enc_state->enc_ctx_num)); 653 status = NT_STATUS_INVALID_HANDLE; 654 goto fail; 655 } 656 657 status = common_decrypt_buffer(cli->trans_enc_state, 658 (char *)inbuf); 659 if (!NT_STATUS_IS_OK(status)) { 660 DEBUG(10, ("common_decrypt_buffer returned %s\n", 661 nt_errstr(status))); 662 goto fail; 663 } 664 } 665 666 mid = SVAL(inbuf, smb_mid); 667 num_pending = talloc_array_length(cli->pending); 668 669 for (i=0; i<num_pending; i++) { 670 if (mid == cli_smb_req_mid(cli->pending[i])) { 671 break; 672 } 673 } 674 if (i == num_pending) { 675 /* Dump unexpected reply */ 676 TALLOC_FREE(inbuf); 677 goto done; 678 } 679 680 oplock_break = false; 681 682 if (mid == 0xffff) { 683 /* 684 * Paranoia checks that this is really an oplock break request. 685 */ 686 oplock_break = (smb_len(inbuf) == 51); /* hdr + 8 words */ 687 oplock_break &= ((CVAL(inbuf, smb_flg) & FLAG_REPLY) == 0); 688 oplock_break &= (CVAL(inbuf, smb_com) == SMBlockingX); 689 oplock_break &= (SVAL(inbuf, smb_vwv6) == 0); 690 oplock_break &= (SVAL(inbuf, smb_vwv7) == 0); 691 692 if (!oplock_break) { 693 /* Dump unexpected reply */ 694 TALLOC_FREE(inbuf); 695 goto done; 696 } 697 } 698 699 req = cli->pending[i]; 700 state = tevent_req_data(req, struct cli_smb_state); 701 ev = state->ev; 702 703 if (!oplock_break /* oplock breaks are not signed */ 704 && !cli_check_sign_mac(cli, (char *)inbuf, state->seqnum+1)) { 705 DEBUG(10, ("cli_check_sign_mac failed\n")); 706 TALLOC_FREE(inbuf); 707 status = NT_STATUS_ACCESS_DENIED; 708 close(cli->fd); 709 cli->fd = -1; 710 goto fail; 711 } 712 713 if (state->chained_requests == NULL) { 714 state->inbuf = talloc_move(state, &inbuf); 715 talloc_set_destructor(req, NULL); 716 cli_smb_req_destructor(req); 717 tevent_req_done(req); 718 } else { 719 struct tevent_req **chain = talloc_move( 720 talloc_tos(), &state->chained_requests); 721 int num_chained = talloc_array_length(chain); 722 723 for (i=0; i<num_chained; i++) { 724 state = tevent_req_data(chain[i], struct 725 cli_smb_state); 726 state->inbuf = inbuf; 727 state->chain_num = i; 728 tevent_req_done(chain[i]); 729 } 730 TALLOC_FREE(inbuf); 731 TALLOC_FREE(chain); 732 } 733 done: 734 if (talloc_array_length(cli->pending) > 0) { 735 /* 736 * Set up another read request for the other pending cli_smb 737 * requests 738 */ 739 state = tevent_req_data(cli->pending[0], struct cli_smb_state); 740 subreq = read_smb_send(cli->pending, state->ev, cli->fd); 741 if (subreq == NULL) { 742 status = NT_STATUS_NO_MEMORY; 743 goto fail; 744 } 745 tevent_req_set_callback(subreq, cli_smb_received, cli); 746 } 747 return; 748 fail: 749 /* 750 * Cancel all pending requests. We don't do a for-loop walking 751 * cli->pending because that array changes in 752 * cli_smb_req_destructor(). 753 */ 754 while (talloc_array_length(cli->pending) > 0) { 755 req = cli->pending[0]; 756 talloc_set_destructor(req, NULL); 757 cli_smb_req_destructor(req); 758 tevent_req_nterror(req, status); 759 } 760} 761 762NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct, 763 uint8_t *pwct, uint16_t **pvwv, 764 uint32_t *pnum_bytes, uint8_t **pbytes) 765{ 766 struct cli_smb_state *state = tevent_req_data( 767 req, struct cli_smb_state); 768 NTSTATUS status = NT_STATUS_OK; 769 uint8_t cmd, wct; 770 uint16_t num_bytes; 771 size_t wct_ofs, bytes_offset; 772 int i; 773 774 if (tevent_req_is_nterror(req, &status)) { 775 return status; 776 } 777 778 if (state->inbuf == NULL) { 779 /* This was a request without a reply */ 780 return NT_STATUS_OK; 781 } 782 783 wct_ofs = smb_wct; 784 cmd = CVAL(state->inbuf, smb_com); 785 786 for (i=0; i<state->chain_num; i++) { 787 if (i < state->chain_num-1) { 788 if (cmd == 0xff) { 789 return NT_STATUS_REQUEST_ABORTED; 790 } 791 if (!is_andx_req(cmd)) { 792 return NT_STATUS_INVALID_NETWORK_RESPONSE; 793 } 794 } 795 796 if (!have_andx_command((char *)state->inbuf, wct_ofs)) { 797 /* 798 * This request was not completed because a previous 799 * request in the chain had received an error. 800 */ 801 return NT_STATUS_REQUEST_ABORTED; 802 } 803 804 wct_ofs = SVAL(state->inbuf, wct_ofs + 3); 805 806 /* 807 * Skip the all-present length field. No overflow, we've just 808 * put a 16-bit value into a size_t. 809 */ 810 wct_ofs += 4; 811 812 if (wct_ofs+2 > talloc_get_size(state->inbuf)) { 813 return NT_STATUS_INVALID_NETWORK_RESPONSE; 814 } 815 816 cmd = CVAL(state->inbuf, wct_ofs + 1); 817 } 818 819 status = cli_pull_error((char *)state->inbuf); 820 821 if (!have_andx_command((char *)state->inbuf, wct_ofs) 822 && NT_STATUS_IS_ERR(status)) { 823 /* 824 * The last command takes the error code. All further commands 825 * down the requested chain will get a 826 * NT_STATUS_REQUEST_ABORTED. 827 */ 828 return status; 829 } 830 831no_err: 832 833 wct = CVAL(state->inbuf, wct_ofs); 834 bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t); 835 num_bytes = SVAL(state->inbuf, bytes_offset); 836 837 if (wct < min_wct) { 838 return NT_STATUS_INVALID_NETWORK_RESPONSE; 839 } 840 841 /* 842 * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes 843 * is a 16-bit value. So bytes_offset being size_t should be far from 844 * wrapping. 845 */ 846 if ((bytes_offset + 2 > talloc_get_size(state->inbuf)) 847 || (bytes_offset > 0xffff)) { 848 return NT_STATUS_INVALID_NETWORK_RESPONSE; 849 } 850 851 if (pwct != NULL) { 852 *pwct = wct; 853 } 854 if (pvwv != NULL) { 855 *pvwv = (uint16_t *)(state->inbuf + wct_ofs + 1); 856 } 857 if (pnum_bytes != NULL) { 858 *pnum_bytes = num_bytes; 859 } 860 if (pbytes != NULL) { 861 *pbytes = (uint8_t *)state->inbuf + bytes_offset + 2; 862 } 863 864 return NT_STATUS_OK; 865} 866 867size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs) 868{ 869 size_t wct_ofs; 870 int i; 871 872 wct_ofs = smb_wct - 4; 873 874 for (i=0; i<num_reqs; i++) { 875 struct cli_smb_state *state; 876 state = tevent_req_data(reqs[i], struct cli_smb_state); 877 wct_ofs += iov_len(state->iov+1, state->iov_count-1); 878 wct_ofs = (wct_ofs + 3) & ~3; 879 } 880 return wct_ofs; 881} 882 883NTSTATUS cli_smb_chain_send(struct tevent_req **reqs, int num_reqs) 884{ 885 struct cli_smb_state *first_state = tevent_req_data( 886 reqs[0], struct cli_smb_state); 887 struct cli_smb_state *last_state = tevent_req_data( 888 reqs[num_reqs-1], struct cli_smb_state); 889 struct cli_smb_state *state; 890 size_t wct_offset; 891 size_t chain_padding = 0; 892 int i, iovlen; 893 struct iovec *iov = NULL; 894 struct iovec *this_iov; 895 NTSTATUS status; 896 897 iovlen = 0; 898 for (i=0; i<num_reqs; i++) { 899 state = tevent_req_data(reqs[i], struct cli_smb_state); 900 iovlen += state->iov_count; 901 } 902 903 iov = talloc_array(last_state, struct iovec, iovlen); 904 if (iov == NULL) { 905 return NT_STATUS_NO_MEMORY; 906 } 907 908 first_state->chained_requests = (struct tevent_req **)talloc_memdup( 909 last_state, reqs, sizeof(*reqs) * num_reqs); 910 if (first_state->chained_requests == NULL) { 911 TALLOC_FREE(iov); 912 return NT_STATUS_NO_MEMORY; 913 } 914 915 wct_offset = smb_wct - 4; 916 this_iov = iov; 917 918 for (i=0; i<num_reqs; i++) { 919 size_t next_padding = 0; 920 uint16_t *vwv; 921 922 state = tevent_req_data(reqs[i], struct cli_smb_state); 923 924 if (i < num_reqs-1) { 925 if (!is_andx_req(CVAL(state->header, smb_com)) 926 || CVAL(state->header, smb_wct) < 2) { 927 TALLOC_FREE(iov); 928 TALLOC_FREE(first_state->chained_requests); 929 return NT_STATUS_INVALID_PARAMETER; 930 } 931 } 932 933 wct_offset += iov_len(state->iov+1, state->iov_count-1) + 1; 934 if ((wct_offset % 4) != 0) { 935 next_padding = 4 - (wct_offset % 4); 936 } 937 wct_offset += next_padding; 938 vwv = state->vwv; 939 940 if (i < num_reqs-1) { 941 struct cli_smb_state *next_state = tevent_req_data( 942 reqs[i+1], struct cli_smb_state); 943 SCVAL(vwv+0, 0, CVAL(next_state->header, smb_com)); 944 SCVAL(vwv+0, 1, 0); 945 SSVAL(vwv+1, 0, wct_offset); 946 } else if (is_andx_req(CVAL(state->header, smb_com))) { 947 /* properly end the chain */ 948 SCVAL(vwv+0, 0, 0xff); 949 SCVAL(vwv+0, 1, 0xff); 950 SSVAL(vwv+1, 0, 0); 951 } 952 953 if (i == 0) { 954 this_iov[0] = state->iov[0]; 955 } else { 956 /* 957 * This one is a bit subtle. We have to add 958 * chain_padding bytes between the requests, and we 959 * have to also include the wct field of the 960 * subsequent requests. We use the subsequent header 961 * for the padding, it contains the wct field in its 962 * last byte. 963 */ 964 this_iov[0].iov_len = chain_padding+1; 965 this_iov[0].iov_base = (void *)&state->header[ 966 sizeof(state->header) - this_iov[0].iov_len]; 967 memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1); 968 } 969 memcpy(this_iov+1, state->iov+1, 970 sizeof(struct iovec) * (state->iov_count-1)); 971 this_iov += state->iov_count; 972 chain_padding = next_padding; 973 } 974 975 status = cli_smb_req_iov_send(reqs[0], last_state, iov, iovlen); 976 if (!NT_STATUS_IS_OK(status)) { 977 TALLOC_FREE(iov); 978 TALLOC_FREE(first_state->chained_requests); 979 return status; 980 } 981 982 return NT_STATUS_OK; 983} 984 985uint8_t *cli_smb_inbuf(struct tevent_req *req) 986{ 987 struct cli_smb_state *state = tevent_req_data( 988 req, struct cli_smb_state); 989 return state->inbuf; 990} 991 992bool cli_has_async_calls(struct cli_state *cli) 993{ 994 return ((tevent_queue_length(cli->outgoing) != 0) 995 || (talloc_array_length(cli->pending) != 0)); 996} 997 998struct cli_smb_oplock_break_waiter_state { 999 uint16_t fnum; 1000 uint8_t level; 1001}; 1002 1003static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq); 1004 1005struct tevent_req *cli_smb_oplock_break_waiter_send(TALLOC_CTX *mem_ctx, 1006 struct event_context *ev, 1007 struct cli_state *cli) 1008{ 1009 struct tevent_req *req, *subreq; 1010 struct cli_smb_oplock_break_waiter_state *state; 1011 struct cli_smb_state *smb_state; 1012 1013 req = tevent_req_create(mem_ctx, &state, 1014 struct cli_smb_oplock_break_waiter_state); 1015 if (req == NULL) { 1016 return NULL; 1017 } 1018 1019 /* 1020 * Create a fake SMB request that we will never send out. This is only 1021 * used to be set into the pending queue with the right mid. 1022 */ 1023 subreq = cli_smb_req_create(mem_ctx, ev, cli, 0, 0, 0, NULL, 0, NULL); 1024 if (tevent_req_nomem(subreq, req)) { 1025 return tevent_req_post(req, ev); 1026 } 1027 smb_state = tevent_req_data(subreq, struct cli_smb_state); 1028 SSVAL(smb_state->header, smb_mid, 0xffff); 1029 1030 if (!cli_smb_req_set_pending(subreq)) { 1031 tevent_req_nterror(req, NT_STATUS_NO_MEMORY); 1032 return tevent_req_post(req, ev); 1033 } 1034 tevent_req_set_callback(subreq, cli_smb_oplock_break_waiter_done, req); 1035 return req; 1036} 1037 1038static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq) 1039{ 1040 struct tevent_req *req = tevent_req_callback_data( 1041 subreq, struct tevent_req); 1042 struct cli_smb_oplock_break_waiter_state *state = tevent_req_data( 1043 req, struct cli_smb_oplock_break_waiter_state); 1044 uint8_t wct; 1045 uint16_t *vwv; 1046 uint32_t num_bytes; 1047 uint8_t *bytes; 1048 NTSTATUS status; 1049 1050 status = cli_smb_recv(subreq, 8, &wct, &vwv, &num_bytes, &bytes); 1051 if (!NT_STATUS_IS_OK(status)) { 1052 TALLOC_FREE(subreq); 1053 tevent_req_nterror(req, status); 1054 return; 1055 } 1056 state->fnum = SVAL(vwv+2, 0); 1057 state->level = CVAL(vwv+3, 1); 1058 tevent_req_done(req); 1059} 1060 1061NTSTATUS cli_smb_oplock_break_waiter_recv(struct tevent_req *req, 1062 uint16_t *pfnum, 1063 uint8_t *plevel) 1064{ 1065 struct cli_smb_oplock_break_waiter_state *state = tevent_req_data( 1066 req, struct cli_smb_oplock_break_waiter_state); 1067 NTSTATUS status; 1068 1069 if (tevent_req_is_nterror(req, &status)) { 1070 return status; 1071 } 1072 *pfnum = state->fnum; 1073 *plevel = state->level; 1074 return NT_STATUS_OK; 1075} 1076 1077 1078struct cli_session_request_state { 1079 struct tevent_context *ev; 1080 int sock; 1081 uint32 len_hdr; 1082 struct iovec iov[3]; 1083 uint8_t nb_session_response; 1084}; 1085 1086static void cli_session_request_sent(struct tevent_req *subreq); 1087static void cli_session_request_recvd(struct tevent_req *subreq); 1088 1089struct tevent_req *cli_session_request_send(TALLOC_CTX *mem_ctx, 1090 struct tevent_context *ev, 1091 int sock, 1092 const struct nmb_name *called, 1093 const struct nmb_name *calling) 1094{ 1095 struct tevent_req *req, *subreq; 1096 struct cli_session_request_state *state; 1097 1098 req = tevent_req_create(mem_ctx, &state, 1099 struct cli_session_request_state); 1100 if (req == NULL) { 1101 return NULL; 1102 } 1103 state->ev = ev; 1104 state->sock = sock; 1105 1106 state->iov[1].iov_base = name_mangle( 1107 state, called->name, called->name_type); 1108 if (tevent_req_nomem(state->iov[1].iov_base, req)) { 1109 return tevent_req_post(req, ev); 1110 } 1111 state->iov[1].iov_len = name_len( 1112 (unsigned char *)state->iov[1].iov_base, 1113 talloc_get_size(state->iov[1].iov_base)); 1114 1115 state->iov[2].iov_base = name_mangle( 1116 state, calling->name, calling->name_type); 1117 if (tevent_req_nomem(state->iov[2].iov_base, req)) { 1118 return tevent_req_post(req, ev); 1119 } 1120 state->iov[2].iov_len = name_len( 1121 (unsigned char *)state->iov[2].iov_base, 1122 talloc_get_size(state->iov[2].iov_base)); 1123 1124 _smb_setlen(((char *)&state->len_hdr), 1125 state->iov[1].iov_len + state->iov[2].iov_len); 1126 SCVAL((char *)&state->len_hdr, 0, 0x81); 1127 1128 state->iov[0].iov_base = &state->len_hdr; 1129 state->iov[0].iov_len = sizeof(state->len_hdr); 1130 1131 subreq = writev_send(state, ev, NULL, sock, true, state->iov, 3); 1132 if (tevent_req_nomem(subreq, req)) { 1133 return tevent_req_post(req, ev); 1134 } 1135 tevent_req_set_callback(subreq, cli_session_request_sent, req); 1136 return req; 1137} 1138 1139static void cli_session_request_sent(struct tevent_req *subreq) 1140{ 1141 struct tevent_req *req = tevent_req_callback_data( 1142 subreq, struct tevent_req); 1143 struct cli_session_request_state *state = tevent_req_data( 1144 req, struct cli_session_request_state); 1145 ssize_t ret; 1146 int err; 1147 1148 ret = writev_recv(subreq, &err); 1149 TALLOC_FREE(subreq); 1150 if (ret == -1) { 1151 tevent_req_error(req, err); 1152 return; 1153 } 1154 subreq = read_smb_send(state, state->ev, state->sock); 1155 if (tevent_req_nomem(subreq, req)) { 1156 return; 1157 } 1158 tevent_req_set_callback(subreq, cli_session_request_recvd, req); 1159} 1160 1161static void cli_session_request_recvd(struct tevent_req *subreq) 1162{ 1163 struct tevent_req *req = tevent_req_callback_data( 1164 subreq, struct tevent_req); 1165 struct cli_session_request_state *state = tevent_req_data( 1166 req, struct cli_session_request_state); 1167 uint8_t *buf; 1168 ssize_t ret; 1169 int err; 1170 1171 ret = read_smb_recv(subreq, talloc_tos(), &buf, &err); 1172 TALLOC_FREE(subreq); 1173 1174 if (ret < 4) { 1175 ret = -1; 1176 err = EIO; 1177 } 1178 if (ret == -1) { 1179 tevent_req_error(req, err); 1180 return; 1181 } 1182 /* 1183 * In case of an error there is more information in the data 1184 * portion according to RFC1002. We're not subtle enough to 1185 * respond to the different error conditions, so drop the 1186 * error info here. 1187 */ 1188 state->nb_session_response = CVAL(buf, 0); 1189 tevent_req_done(req); 1190} 1191 1192bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp) 1193{ 1194 struct cli_session_request_state *state = tevent_req_data( 1195 req, struct cli_session_request_state); 1196 1197 if (tevent_req_is_unix_error(req, err)) { 1198 return false; 1199 } 1200 *resp = state->nb_session_response; 1201 return true; 1202} 1203