1/* 2 Unix SMB/CIFS implementation. 3 SMB client generic functions 4 Copyright (C) Andrew Tridgell 1994-1998 5 Copyright (C) Jeremy Allison 2007. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19*/ 20 21#include "includes.h" 22 23/******************************************************************* 24 Setup the word count and byte count for a client smb message. 25********************************************************************/ 26 27int cli_set_message(char *buf,int num_words,int num_bytes,bool zero) 28{ 29 if (zero && (num_words || num_bytes)) { 30 memset(buf + smb_size,'\0',num_words*2 + num_bytes); 31 } 32 SCVAL(buf,smb_wct,num_words); 33 SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes); 34 smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4); 35 return (smb_size + num_words*2 + num_bytes); 36} 37 38/**************************************************************************** 39 Change the timeout (in milliseconds). 40****************************************************************************/ 41 42unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout) 43{ 44 unsigned int old_timeout = cli->timeout; 45 cli->timeout = timeout; 46 return old_timeout; 47} 48 49/**************************************************************************** 50 Change the port number used to call on. 51****************************************************************************/ 52 53void cli_set_port(struct cli_state *cli, int port) 54{ 55 cli->port = port; 56} 57 58/**************************************************************************** 59 convenience routine to find if we negotiated ucs2 60****************************************************************************/ 61 62bool cli_ucs2(struct cli_state *cli) 63{ 64 return ((cli->capabilities & CAP_UNICODE) != 0); 65} 66 67 68/**************************************************************************** 69 Read an smb from a fd ignoring all keepalive packets. 70 The timeout is in milliseconds 71 72 This is exactly the same as receive_smb except that it never returns 73 a session keepalive packet (just as receive_smb used to do). 74 receive_smb was changed to return keepalives as the oplock processing means this call 75 should never go into a blocking read. 76****************************************************************************/ 77 78static ssize_t client_receive_smb(struct cli_state *cli, size_t maxlen) 79{ 80 size_t len; 81 82 for(;;) { 83 NTSTATUS status; 84 85 set_smb_read_error(&cli->smb_rw_error, SMB_READ_OK); 86 87 status = receive_smb_raw(cli->fd, cli->inbuf, cli->bufsize, 88 cli->timeout, maxlen, &len); 89 if (!NT_STATUS_IS_OK(status)) { 90 DEBUG(10,("client_receive_smb failed\n")); 91 show_msg(cli->inbuf); 92 93 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { 94 set_smb_read_error(&cli->smb_rw_error, 95 SMB_READ_EOF); 96 return -1; 97 } 98 99 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { 100 set_smb_read_error(&cli->smb_rw_error, 101 SMB_READ_TIMEOUT); 102 return -1; 103 } 104 105 set_smb_read_error(&cli->smb_rw_error, SMB_READ_ERROR); 106 return -1; 107 } 108 109 /* 110 * I don't believe len can be < 0 with NT_STATUS_OK 111 * returned above, but this check doesn't hurt. JRA. 112 */ 113 114 if ((ssize_t)len < 0) { 115 return len; 116 } 117 118 /* Ignore session keepalive packets. */ 119 if(CVAL(cli->inbuf,0) != SMBkeepalive) { 120 break; 121 } 122 } 123 124 if (cli_encryption_on(cli)) { 125 NTSTATUS status = cli_decrypt_message(cli); 126 if (!NT_STATUS_IS_OK(status)) { 127 DEBUG(0, ("SMB decryption failed on incoming packet! Error %s\n", 128 nt_errstr(status))); 129 cli->smb_rw_error = SMB_READ_BAD_DECRYPT; 130 return -1; 131 } 132 } 133 134 show_msg(cli->inbuf); 135 return len; 136} 137 138static bool cli_state_set_seqnum(struct cli_state *cli, uint16_t mid, uint32_t seqnum) 139{ 140 struct cli_state_seqnum *c; 141 142 for (c = cli->seqnum; c; c = c->next) { 143 if (c->mid == mid) { 144 c->seqnum = seqnum; 145 return true; 146 } 147 } 148 149 c = talloc_zero(cli, struct cli_state_seqnum); 150 if (!c) { 151 return false; 152 } 153 154 c->mid = mid; 155 c->seqnum = seqnum; 156 c->persistent = false; 157 DLIST_ADD_END(cli->seqnum, c, struct cli_state_seqnum *); 158 159 return true; 160} 161 162bool cli_state_seqnum_persistent(struct cli_state *cli, 163 uint16_t mid) 164{ 165 struct cli_state_seqnum *c; 166 167 for (c = cli->seqnum; c; c = c->next) { 168 if (c->mid == mid) { 169 c->persistent = true; 170 return true; 171 } 172 } 173 174 return false; 175} 176 177bool cli_state_seqnum_remove(struct cli_state *cli, 178 uint16_t mid) 179{ 180 struct cli_state_seqnum *c; 181 182 for (c = cli->seqnum; c; c = c->next) { 183 if (c->mid == mid) { 184 DLIST_REMOVE(cli->seqnum, c); 185 TALLOC_FREE(c); 186 return true; 187 } 188 } 189 190 return false; 191} 192 193static uint32_t cli_state_get_seqnum(struct cli_state *cli, uint16_t mid) 194{ 195 struct cli_state_seqnum *c; 196 197 for (c = cli->seqnum; c; c = c->next) { 198 if (c->mid == mid) { 199 uint32_t seqnum = c->seqnum; 200 if (!c->persistent) { 201 DLIST_REMOVE(cli->seqnum, c); 202 TALLOC_FREE(c); 203 } 204 return seqnum; 205 } 206 } 207 208 return 0; 209} 210 211/**************************************************************************** 212 Recv an smb. 213****************************************************************************/ 214 215bool cli_receive_smb(struct cli_state *cli) 216{ 217 ssize_t len; 218 uint16_t mid; 219 uint32_t seqnum; 220 221 /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ 222 if (cli->fd == -1) 223 return false; 224 225 again: 226 len = client_receive_smb(cli, 0); 227 228 if (len > 0) { 229 /* it might be an oplock break request */ 230 if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) && 231 CVAL(cli->inbuf,smb_com) == SMBlockingX && 232 SVAL(cli->inbuf,smb_vwv6) == 0 && 233 SVAL(cli->inbuf,smb_vwv7) == 0) { 234 if (cli->oplock_handler) { 235 int fnum = SVAL(cli->inbuf,smb_vwv2); 236 unsigned char level = CVAL(cli->inbuf,smb_vwv3+1); 237 if (!NT_STATUS_IS_OK(cli->oplock_handler(cli, fnum, level))) { 238 return false; 239 } 240 } 241 /* try to prevent loops */ 242 SCVAL(cli->inbuf,smb_com,0xFF); 243 goto again; 244 } 245 } 246 247 /* If the server is not responding, note that now */ 248 if (len < 0) { 249 DEBUG(0, ("Receiving SMB: Server stopped responding\n")); 250 close(cli->fd); 251 cli->fd = -1; 252 return false; 253 } 254 255 mid = SVAL(cli->inbuf,smb_mid); 256 seqnum = cli_state_get_seqnum(cli, mid); 257 258 if (!cli_check_sign_mac(cli, cli->inbuf, seqnum+1)) { 259 /* 260 * If we get a signature failure in sessionsetup, then 261 * the server sometimes just reflects the sent signature 262 * back to us. Detect this and allow the upper layer to 263 * retrieve the correct Windows error message. 264 */ 265 if (CVAL(cli->outbuf,smb_com) == SMBsesssetupX && 266 (smb_len(cli->inbuf) > (smb_ss_field + 8 - 4)) && 267 (SVAL(cli->inbuf,smb_flg2) & FLAGS2_SMB_SECURITY_SIGNATURES) && 268 memcmp(&cli->outbuf[smb_ss_field],&cli->inbuf[smb_ss_field],8) == 0 && 269 cli_is_error(cli)) { 270 271 /* 272 * Reflected signature on login error. 273 * Set bad sig but don't close fd. 274 */ 275 cli->smb_rw_error = SMB_READ_BAD_SIG; 276 return true; 277 } 278 279 DEBUG(0, ("SMB Signature verification failed on incoming packet!\n")); 280 cli->smb_rw_error = SMB_READ_BAD_SIG; 281 close(cli->fd); 282 cli->fd = -1; 283 return false; 284 }; 285 return true; 286} 287 288/**************************************************************************** 289 Read the data portion of a readX smb. 290 The timeout is in milliseconds 291****************************************************************************/ 292 293ssize_t cli_receive_smb_data(struct cli_state *cli, char *buffer, size_t len) 294{ 295 NTSTATUS status; 296 297 set_smb_read_error(&cli->smb_rw_error, SMB_READ_OK); 298 299 status = read_fd_with_timeout( 300 cli->fd, buffer, len, len, cli->timeout, NULL); 301 if (NT_STATUS_IS_OK(status)) { 302 return len; 303 } 304 305 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { 306 set_smb_read_error(&cli->smb_rw_error, SMB_READ_EOF); 307 return -1; 308 } 309 310 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { 311 set_smb_read_error(&cli->smb_rw_error, SMB_READ_TIMEOUT); 312 return -1; 313 } 314 315 set_smb_read_error(&cli->smb_rw_error, SMB_READ_ERROR); 316 return -1; 317} 318 319static ssize_t write_socket(int fd, const char *buf, size_t len) 320{ 321 ssize_t ret=0; 322 323 DEBUG(6,("write_socket(%d,%d)\n",fd,(int)len)); 324 ret = write_data(fd,buf,len); 325 326 DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,(int)len,(int)ret)); 327 if(ret <= 0) 328 DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n", 329 (int)len, fd, strerror(errno) )); 330 331 return(ret); 332} 333 334/**************************************************************************** 335 Send an smb to a fd. 336****************************************************************************/ 337 338bool cli_send_smb(struct cli_state *cli) 339{ 340 size_t len; 341 size_t nwritten=0; 342 ssize_t ret; 343 char *buf_out = cli->outbuf; 344 bool enc_on = cli_encryption_on(cli); 345 uint32_t seqnum; 346 347 /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ 348 if (cli->fd == -1) 349 return false; 350 351 cli_calculate_sign_mac(cli, cli->outbuf, &seqnum); 352 353 if (!cli_state_set_seqnum(cli, cli->mid, seqnum)) { 354 DEBUG(0,("Failed to store mid[%u]/seqnum[%u]\n", 355 (unsigned int)cli->mid, 356 (unsigned int)seqnum)); 357 return false; 358 } 359 360 if (enc_on) { 361 NTSTATUS status = cli_encrypt_message(cli, cli->outbuf, 362 &buf_out); 363 if (!NT_STATUS_IS_OK(status)) { 364 close(cli->fd); 365 cli->fd = -1; 366 cli->smb_rw_error = SMB_WRITE_ERROR; 367 DEBUG(0,("Error in encrypting client message. Error %s\n", 368 nt_errstr(status) )); 369 return false; 370 } 371 } 372 373 len = smb_len(buf_out) + 4; 374 375 while (nwritten < len) { 376 ret = write_socket(cli->fd,buf_out+nwritten,len - nwritten); 377 if (ret <= 0) { 378 if (enc_on) { 379 cli_free_enc_buffer(cli, buf_out); 380 } 381 close(cli->fd); 382 cli->fd = -1; 383 cli->smb_rw_error = SMB_WRITE_ERROR; 384 DEBUG(0,("Error writing %d bytes to client. %d (%s)\n", 385 (int)len,(int)ret, strerror(errno) )); 386 return false; 387 } 388 nwritten += ret; 389 } 390 391 if (enc_on) { 392 cli_free_enc_buffer(cli, buf_out); 393 } 394 395 /* Increment the mid so we can tell between responses. */ 396 cli->mid++; 397 if (!cli->mid) 398 cli->mid++; 399 return true; 400} 401 402/**************************************************************************** 403 Send a "direct" writeX smb to a fd. 404****************************************************************************/ 405 406bool cli_send_smb_direct_writeX(struct cli_state *cli, 407 const char *p, 408 size_t extradata) 409{ 410 /* First length to send is the offset to the data. */ 411 size_t len = SVAL(cli->outbuf,smb_vwv11) + 4; 412 size_t nwritten=0; 413 struct iovec iov[2]; 414 415 /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ 416 if (cli->fd == -1) { 417 return false; 418 } 419 420 if (client_is_signing_on(cli)) { 421 DEBUG(0,("cli_send_smb_large: cannot send signed packet.\n")); 422 return false; 423 } 424 425 iov[0].iov_base = (void *)cli->outbuf; 426 iov[0].iov_len = len; 427 iov[1].iov_base = CONST_DISCARD(void *, p); 428 iov[1].iov_len = extradata; 429 430 nwritten = write_data_iov(cli->fd, iov, 2); 431 if (nwritten < (len + extradata)) { 432 close(cli->fd); 433 cli->fd = -1; 434 cli->smb_rw_error = SMB_WRITE_ERROR; 435 DEBUG(0,("Error writing %d bytes to client. (%s)\n", 436 (int)(len+extradata), strerror(errno))); 437 return false; 438 } 439 440 /* Increment the mid so we can tell between responses. */ 441 cli->mid++; 442 if (!cli->mid) 443 cli->mid++; 444 return true; 445} 446 447/**************************************************************************** 448 Setup basics in a outgoing packet. 449****************************************************************************/ 450 451void cli_setup_packet_buf(struct cli_state *cli, char *buf) 452{ 453 uint16 flags2; 454 cli->rap_error = 0; 455 SIVAL(buf,smb_rcls,0); 456 SSVAL(buf,smb_pid,cli->pid); 457 memset(buf+smb_pidhigh, 0, 12); 458 SSVAL(buf,smb_uid,cli->vuid); 459 SSVAL(buf,smb_mid,cli->mid); 460 461 if (cli->protocol <= PROTOCOL_CORE) { 462 return; 463 } 464 465 if (cli->case_sensitive) { 466 SCVAL(buf,smb_flg,0x0); 467 } else { 468 /* Default setting, case insensitive. */ 469 SCVAL(buf,smb_flg,0x8); 470 } 471 flags2 = FLAGS2_LONG_PATH_COMPONENTS; 472 if (cli->capabilities & CAP_UNICODE) 473 flags2 |= FLAGS2_UNICODE_STRINGS; 474 if ((cli->capabilities & CAP_DFS) && cli->dfsroot) 475 flags2 |= FLAGS2_DFS_PATHNAMES; 476 if (cli->capabilities & CAP_STATUS32) 477 flags2 |= FLAGS2_32_BIT_ERROR_CODES; 478 if (cli->use_spnego) 479 flags2 |= FLAGS2_EXTENDED_SECURITY; 480 SSVAL(buf,smb_flg2, flags2); 481} 482 483void cli_setup_packet(struct cli_state *cli) 484{ 485 cli_setup_packet_buf(cli, cli->outbuf); 486} 487 488/**************************************************************************** 489 Setup the bcc length of the packet from a pointer to the end of the data. 490****************************************************************************/ 491 492void cli_setup_bcc(struct cli_state *cli, void *p) 493{ 494 set_message_bcc(cli->outbuf, PTR_DIFF(p, smb_buf(cli->outbuf))); 495} 496 497/**************************************************************************** 498 Initialize Domain, user or password. 499****************************************************************************/ 500 501NTSTATUS cli_set_domain(struct cli_state *cli, const char *domain) 502{ 503 TALLOC_FREE(cli->domain); 504 cli->domain = talloc_strdup(cli, domain ? domain : ""); 505 if (cli->domain == NULL) { 506 return NT_STATUS_NO_MEMORY; 507 } 508 return NT_STATUS_OK; 509} 510 511NTSTATUS cli_set_username(struct cli_state *cli, const char *username) 512{ 513 TALLOC_FREE(cli->user_name); 514 cli->user_name = talloc_strdup(cli, username ? username : ""); 515 if (cli->user_name == NULL) { 516 return NT_STATUS_NO_MEMORY; 517 } 518 return NT_STATUS_OK; 519} 520 521NTSTATUS cli_set_password(struct cli_state *cli, const char *password) 522{ 523 TALLOC_FREE(cli->password); 524 525 /* Password can be NULL. */ 526 if (password) { 527 cli->password = talloc_strdup(cli, password); 528 if (cli->password == NULL) { 529 return NT_STATUS_NO_MEMORY; 530 } 531 } else { 532 /* Use zero NTLMSSP hashes and session key. */ 533 cli->password = NULL; 534 } 535 536 return NT_STATUS_OK; 537} 538 539/**************************************************************************** 540 Initialise credentials of a client structure. 541****************************************************************************/ 542 543NTSTATUS cli_init_creds(struct cli_state *cli, const char *username, const char *domain, const char *password) 544{ 545 NTSTATUS status = cli_set_username(cli, username); 546 if (!NT_STATUS_IS_OK(status)) { 547 return status; 548 } 549 status = cli_set_domain(cli, domain); 550 if (!NT_STATUS_IS_OK(status)) { 551 return status; 552 } 553 DEBUG(10,("cli_init_creds: user %s domain %s\n", cli->user_name, cli->domain)); 554 555 return cli_set_password(cli, password); 556} 557 558/**************************************************************************** 559 Initialise a client structure. Always returns a talloc'ed struct. 560 Set the signing state (used from the command line). 561****************************************************************************/ 562 563struct cli_state *cli_initialise_ex(int signing_state) 564{ 565 struct cli_state *cli = NULL; 566 bool allow_smb_signing = false; 567 bool mandatory_signing = false; 568 569 /* Check the effective uid - make sure we are not setuid */ 570 if (is_setuid_root()) { 571 DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n")); 572 return NULL; 573 } 574 575 cli = TALLOC_ZERO_P(NULL, struct cli_state); 576 if (!cli) { 577 return NULL; 578 } 579 580 cli->dfs_mountpoint = talloc_strdup(cli, ""); 581 if (!cli->dfs_mountpoint) { 582 goto error; 583 } 584 cli->port = 0; 585 cli->fd = -1; 586 cli->cnum = -1; 587 cli->pid = (uint16)sys_getpid(); 588 cli->mid = 1; 589 cli->vuid = UID_FIELD_INVALID; 590 cli->protocol = PROTOCOL_NT1; 591 cli->timeout = 20000; /* Timeout is in milliseconds. */ 592 cli->bufsize = CLI_BUFFER_SIZE+4; 593 cli->max_xmit = cli->bufsize; 594 cli->outbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN); 595 cli->seqnum = 0; 596 cli->inbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN); 597 cli->oplock_handler = cli_oplock_ack; 598 cli->case_sensitive = false; 599 cli->smb_rw_error = SMB_READ_OK; 600 601 cli->use_spnego = lp_client_use_spnego(); 602 603 cli->capabilities = CAP_UNICODE | CAP_STATUS32 | CAP_DFS; 604 605 /* Set the CLI_FORCE_DOSERR environment variable to test 606 client routines using DOS errors instead of STATUS32 607 ones. This intended only as a temporary hack. */ 608 if (getenv("CLI_FORCE_DOSERR")) 609 cli->force_dos_errors = true; 610 611 if (lp_client_signing()) { 612 allow_smb_signing = true; 613 } 614 615 if (lp_client_signing() == Required) { 616 mandatory_signing = true; 617 } 618 619 if (signing_state != Undefined) { 620 allow_smb_signing = true; 621 } 622 623 if (signing_state == false) { 624 allow_smb_signing = false; 625 mandatory_signing = false; 626 } 627 628 if (signing_state == Required) { 629 mandatory_signing = true; 630 } 631 632 if (!cli->outbuf || !cli->inbuf) 633 goto error; 634 635 memset(cli->outbuf, 0, cli->bufsize); 636 memset(cli->inbuf, 0, cli->bufsize); 637 638 639#if defined(DEVELOPER) 640 /* just because we over-allocate, doesn't mean it's right to use it */ 641 clobber_region(FUNCTION_MACRO, __LINE__, cli->outbuf+cli->bufsize, SAFETY_MARGIN); 642 clobber_region(FUNCTION_MACRO, __LINE__, cli->inbuf+cli->bufsize, SAFETY_MARGIN); 643#endif 644 645 /* initialise signing */ 646 cli->signing_state = smb_signing_init(cli, 647 allow_smb_signing, 648 mandatory_signing); 649 if (!cli->signing_state) { 650 goto error; 651 } 652 653 cli->outgoing = tevent_queue_create(cli, "cli_outgoing"); 654 if (cli->outgoing == NULL) { 655 goto error; 656 } 657 cli->pending = NULL; 658 659 cli->initialised = 1; 660 661 return cli; 662 663 /* Clean up after malloc() error */ 664 665 error: 666 667 SAFE_FREE(cli->inbuf); 668 SAFE_FREE(cli->outbuf); 669 TALLOC_FREE(cli); 670 return NULL; 671} 672 673struct cli_state *cli_initialise(void) 674{ 675 return cli_initialise_ex(Undefined); 676} 677 678/**************************************************************************** 679 Close all pipes open on this session. 680****************************************************************************/ 681 682void cli_nt_pipes_close(struct cli_state *cli) 683{ 684 while (cli->pipe_list != NULL) { 685 /* 686 * No TALLOC_FREE here! 687 */ 688 talloc_free(cli->pipe_list); 689 } 690} 691 692/**************************************************************************** 693 Shutdown a client structure. 694****************************************************************************/ 695 696void cli_shutdown(struct cli_state *cli) 697{ 698 if (cli == NULL) { 699 return; 700 } 701 702 if (cli->prev == NULL) { 703 /* 704 * Possible head of a DFS list, 705 * shutdown all subsidiary DFS 706 * connections. 707 */ 708 struct cli_state *p, *next; 709 710 for (p = cli->next; p; p = next) { 711 next = p->next; 712 cli_shutdown(p); 713 } 714 } else { 715 /* 716 * We're a subsidiary connection. 717 * Just remove ourselves from the 718 * DFS list. 719 */ 720 DLIST_REMOVE(cli->prev, cli); 721 } 722 723 cli_nt_pipes_close(cli); 724 725 /* 726 * tell our peer to free his resources. Wihtout this, when an 727 * application attempts to do a graceful shutdown and calls 728 * smbc_free_context() to clean up all connections, some connections 729 * can remain active on the peer end, until some (long) timeout period 730 * later. This tree disconnect forces the peer to clean up, since the 731 * connection will be going away. 732 * 733 * Also, do not do tree disconnect when cli->smb_rw_error is SMB_DO_NOT_DO_TDIS 734 * the only user for this so far is smbmount which passes opened connection 735 * down to kernel's smbfs module. 736 */ 737 if ( (cli->cnum != (uint16)-1) && (cli->smb_rw_error != SMB_DO_NOT_DO_TDIS ) ) { 738 cli_tdis(cli); 739 } 740 741 SAFE_FREE(cli->outbuf); 742 SAFE_FREE(cli->inbuf); 743 744 data_blob_free(&cli->secblob); 745 data_blob_free(&cli->user_session_key); 746 747 if (cli->fd != -1) { 748 close(cli->fd); 749 } 750 cli->fd = -1; 751 cli->smb_rw_error = SMB_READ_OK; 752 753 /* 754 * Need to free pending first, they remove themselves 755 */ 756 while (cli->pending) { 757 talloc_free(cli->pending[0]); 758 } 759 TALLOC_FREE(cli); 760} 761 762/**************************************************************************** 763 Set socket options on a open connection. 764****************************************************************************/ 765 766void cli_sockopt(struct cli_state *cli, const char *options) 767{ 768 set_socket_options(cli->fd, options); 769} 770 771/**************************************************************************** 772 Set the PID to use for smb messages. Return the old pid. 773****************************************************************************/ 774 775uint16 cli_setpid(struct cli_state *cli, uint16 pid) 776{ 777 uint16 ret = cli->pid; 778 cli->pid = pid; 779 return ret; 780} 781 782/**************************************************************************** 783 Set the case sensitivity flag on the packets. Returns old state. 784****************************************************************************/ 785 786bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive) 787{ 788 bool ret = cli->case_sensitive; 789 cli->case_sensitive = case_sensitive; 790 return ret; 791} 792 793/**************************************************************************** 794Send a keepalive packet to the server 795****************************************************************************/ 796 797bool cli_send_keepalive(struct cli_state *cli) 798{ 799 if (cli->fd == -1) { 800 DEBUG(3, ("cli_send_keepalive: fd == -1\n")); 801 return false; 802 } 803 if (!send_keepalive(cli->fd)) { 804 close(cli->fd); 805 cli->fd = -1; 806 DEBUG(0,("Error sending keepalive packet to client.\n")); 807 return false; 808 } 809 return true; 810} 811 812struct cli_echo_state { 813 uint16_t vwv[1]; 814 DATA_BLOB data; 815 int num_echos; 816}; 817 818static void cli_echo_done(struct tevent_req *subreq); 819 820struct tevent_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev, 821 struct cli_state *cli, uint16_t num_echos, 822 DATA_BLOB data) 823{ 824 struct tevent_req *req, *subreq; 825 struct cli_echo_state *state; 826 827 req = tevent_req_create(mem_ctx, &state, struct cli_echo_state); 828 if (req == NULL) { 829 return NULL; 830 } 831 SSVAL(state->vwv, 0, num_echos); 832 state->data = data; 833 state->num_echos = num_echos; 834 835 subreq = cli_smb_send(state, ev, cli, SMBecho, 0, 1, state->vwv, 836 data.length, data.data); 837 if (subreq == NULL) { 838 goto fail; 839 } 840 tevent_req_set_callback(subreq, cli_echo_done, req); 841 return req; 842 fail: 843 TALLOC_FREE(req); 844 return NULL; 845} 846 847static void cli_echo_done(struct tevent_req *subreq) 848{ 849 struct tevent_req *req = tevent_req_callback_data( 850 subreq, struct tevent_req); 851 struct cli_echo_state *state = tevent_req_data( 852 req, struct cli_echo_state); 853 NTSTATUS status; 854 uint32_t num_bytes; 855 uint8_t *bytes; 856 857 status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes); 858 if (!NT_STATUS_IS_OK(status)) { 859 tevent_req_nterror(req, status); 860 return; 861 } 862 if ((num_bytes != state->data.length) 863 || (memcmp(bytes, state->data.data, num_bytes) != 0)) { 864 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); 865 return; 866 } 867 868 state->num_echos -=1; 869 if (state->num_echos == 0) { 870 tevent_req_done(req); 871 return; 872 } 873 874 if (!cli_smb_req_set_pending(subreq)) { 875 tevent_req_nterror(req, NT_STATUS_NO_MEMORY); 876 return; 877 } 878} 879 880/** 881 * Get the result out from an echo request 882 * @param[in] req The async_req from cli_echo_send 883 * @retval Did the server reply correctly? 884 */ 885 886NTSTATUS cli_echo_recv(struct tevent_req *req) 887{ 888 return tevent_req_simple_recv_ntstatus(req); 889} 890 891/** 892 * @brief Send/Receive SMBEcho requests 893 * @param[in] mem_ctx The memory context to put the async_req on 894 * @param[in] ev The event context that will call us back 895 * @param[in] cli The connection to send the echo to 896 * @param[in] num_echos How many times do we want to get the reply? 897 * @param[in] data The data we want to get back 898 * @retval Did the server reply correctly? 899 */ 900 901NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data) 902{ 903 TALLOC_CTX *frame = talloc_stackframe(); 904 struct event_context *ev; 905 struct tevent_req *req; 906 NTSTATUS status = NT_STATUS_OK; 907 908 if (cli_has_async_calls(cli)) { 909 /* 910 * Can't use sync call while an async call is in flight 911 */ 912 status = NT_STATUS_INVALID_PARAMETER; 913 goto fail; 914 } 915 916 ev = event_context_init(frame); 917 if (ev == NULL) { 918 status = NT_STATUS_NO_MEMORY; 919 goto fail; 920 } 921 922 req = cli_echo_send(frame, ev, cli, num_echos, data); 923 if (req == NULL) { 924 status = NT_STATUS_NO_MEMORY; 925 goto fail; 926 } 927 928 if (!tevent_req_poll(req, ev)) { 929 status = map_nt_error_from_unix(errno); 930 goto fail; 931 } 932 933 status = cli_echo_recv(req); 934 fail: 935 TALLOC_FREE(frame); 936 if (!NT_STATUS_IS_OK(status)) { 937 cli_set_error(cli, status); 938 } 939 return status; 940} 941 942/** 943 * Is the SMB command able to hold an AND_X successor 944 * @param[in] cmd The SMB command in question 945 * @retval Can we add a chained request after "cmd"? 946 */ 947bool is_andx_req(uint8_t cmd) 948{ 949 switch (cmd) { 950 case SMBtconX: 951 case SMBlockingX: 952 case SMBopenX: 953 case SMBreadX: 954 case SMBwriteX: 955 case SMBsesssetupX: 956 case SMBulogoffX: 957 case SMBntcreateX: 958 return true; 959 break; 960 default: 961 break; 962 } 963 964 return false; 965} 966