1/* 2 Unix SMB/CIFS implementation. 3 raw trans/trans2/nttrans operations 4 5 Copyright (C) James Myers 2003 <myersjj@samba.org> 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#include "../lib/util/dlinklist.h" 23#include "libcli/raw/libcliraw.h" 24#include "libcli/raw/raw_proto.h" 25 26#define TORTURE_TRANS_DATA 0 27 28/* 29 check out of bounds for incoming data 30*/ 31static bool raw_trans_oob(struct smbcli_request *req, 32 uint_t offset, uint_t count) 33{ 34 uint8_t *ptr; 35 36 if (count == 0) { 37 return false; 38 } 39 40 ptr = req->in.hdr + offset; 41 42 /* be careful with wraparound! */ 43 if ((uintptr_t)ptr < (uintptr_t)req->in.data || 44 (uintptr_t)ptr >= (uintptr_t)req->in.data + req->in.data_size || 45 count > req->in.data_size || 46 (uintptr_t)ptr + count > (uintptr_t)req->in.data + req->in.data_size) { 47 return true; 48 } 49 return false; 50} 51 52static size_t raw_trans_space_left(struct smbcli_request *req) 53{ 54 if (req->transport->negotiate.max_xmit <= req->out.size) { 55 return 0; 56 } 57 58 return req->transport->negotiate.max_xmit - req->out.size; 59} 60 61struct smb_raw_trans2_recv_state { 62 uint8_t command; 63 uint32_t params_total; 64 uint32_t data_total; 65 uint32_t params_left; 66 uint32_t data_left; 67 bool got_first; 68 uint32_t recvd_data; 69 uint32_t recvd_param; 70 struct smb_trans2 io; 71}; 72 73NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req, 74 TALLOC_CTX *mem_ctx, 75 struct smb_trans2 *parms) 76{ 77 struct smb_raw_trans2_recv_state *state; 78 79 if (!smbcli_request_receive(req) || 80 smbcli_request_is_error(req)) { 81 goto failed; 82 } 83 84 state = talloc_get_type(req->recv_helper.private_data, 85 struct smb_raw_trans2_recv_state); 86 87 parms->out = state->io.out; 88 talloc_steal(mem_ctx, parms->out.setup); 89 talloc_steal(mem_ctx, parms->out.params.data); 90 talloc_steal(mem_ctx, parms->out.data.data); 91 talloc_free(state); 92 93 ZERO_STRUCT(req->recv_helper); 94 95failed: 96 return smbcli_request_destroy(req); 97} 98 99static enum smbcli_request_state smb_raw_trans2_ship_rest(struct smbcli_request *req, 100 struct smb_raw_trans2_recv_state *state); 101 102/* 103 * This helper returns SMBCLI_REQUEST_RECV until all data has arrived 104 */ 105static enum smbcli_request_state smb_raw_trans2_recv_helper(struct smbcli_request *req) 106{ 107 struct smb_raw_trans2_recv_state *state = talloc_get_type(req->recv_helper.private_data, 108 struct smb_raw_trans2_recv_state); 109 uint16_t param_count, param_ofs, param_disp; 110 uint16_t data_count, data_ofs, data_disp; 111 uint16_t total_data, total_param; 112 uint8_t setup_count; 113 114 /* 115 * An NT RPC pipe call can return ERRDOS, ERRmoredata 116 * to a trans call. This is not an error and should not 117 * be treated as such. 118 */ 119 if (smbcli_request_is_error(req)) { 120 goto failed; 121 } 122 123 if (state->params_left > 0 || state->data_left > 0) { 124 return smb_raw_trans2_ship_rest(req, state); 125 } 126 127 SMBCLI_CHECK_MIN_WCT(req, 10); 128 129 total_data = SVAL(req->in.vwv, VWV(1)); 130 total_param = SVAL(req->in.vwv, VWV(0)); 131 setup_count = CVAL(req->in.vwv, VWV(9)); 132 133 param_count = SVAL(req->in.vwv, VWV(3)); 134 param_ofs = SVAL(req->in.vwv, VWV(4)); 135 param_disp = SVAL(req->in.vwv, VWV(5)); 136 137 data_count = SVAL(req->in.vwv, VWV(6)); 138 data_ofs = SVAL(req->in.vwv, VWV(7)); 139 data_disp = SVAL(req->in.vwv, VWV(8)); 140 141 if (!state->got_first) { 142 if (total_param > 0) { 143 state->io.out.params = data_blob_talloc(state, NULL, total_param); 144 if (!state->io.out.params.data) { 145 goto nomem; 146 } 147 } 148 149 if (total_data > 0) { 150 state->io.out.data = data_blob_talloc(state, NULL, total_data); 151 if (!state->io.out.data.data) { 152 goto nomem; 153 } 154 } 155 156 if (setup_count > 0) { 157 uint16_t i; 158 159 SMBCLI_CHECK_WCT(req, 10 + setup_count); 160 161 state->io.out.setup_count = setup_count; 162 state->io.out.setup = talloc_array(state, uint16_t, setup_count); 163 if (!state->io.out.setup) { 164 goto nomem; 165 } 166 for (i=0; i < setup_count; i++) { 167 state->io.out.setup[i] = SVAL(req->in.vwv, VWV(10+i)); 168 } 169 } 170 171 state->got_first = true; 172 } 173 174 if (total_data > state->io.out.data.length || 175 total_param > state->io.out.params.length) { 176 /* they must *only* shrink */ 177 DEBUG(1,("smb_raw_trans2_recv_helper: data/params expanded!\n")); 178 req->status = NT_STATUS_BUFFER_TOO_SMALL; 179 goto failed; 180 } 181 182 state->io.out.data.length = total_data; 183 state->io.out.params.length = total_param; 184 185 if (data_count + data_disp > total_data || 186 param_count + param_disp > total_param) { 187 DEBUG(1,("smb_raw_trans2_recv_helper: Buffer overflow\n")); 188 req->status = NT_STATUS_BUFFER_TOO_SMALL; 189 goto failed; 190 } 191 192 /* check the server isn't being nasty */ 193 if (raw_trans_oob(req, param_ofs, param_count) || 194 raw_trans_oob(req, data_ofs, data_count)) { 195 DEBUG(1,("smb_raw_trans2_recv_helper: out of bounds parameters!\n")); 196 req->status = NT_STATUS_BUFFER_TOO_SMALL; 197 goto failed; 198 } 199 200 if (data_count) { 201 memcpy(state->io.out.data.data + data_disp, 202 req->in.hdr + data_ofs, 203 data_count); 204 } 205 206 if (param_count) { 207 memcpy(state->io.out.params.data + param_disp, 208 req->in.hdr + param_ofs, 209 param_count); 210 } 211 212 state->recvd_param += param_count; 213 state->recvd_data += data_count; 214 215 if (state->recvd_data < total_data || 216 state->recvd_param < total_param) { 217 218 /* we don't need the in buffer any more */ 219 talloc_free(req->in.buffer); 220 ZERO_STRUCT(req->in); 221 222 /* we still wait for more data */ 223 DEBUG(10,("smb_raw_trans2_recv_helper: more data needed\n")); 224 return SMBCLI_REQUEST_RECV; 225 } 226 227 DEBUG(10,("smb_raw_trans2_recv_helper: done\n")); 228 return SMBCLI_REQUEST_DONE; 229 230nomem: 231 req->status = NT_STATUS_NO_MEMORY; 232failed: 233 return SMBCLI_REQUEST_ERROR; 234} 235 236_PUBLIC_ NTSTATUS smb_raw_trans_recv(struct smbcli_request *req, 237 TALLOC_CTX *mem_ctx, 238 struct smb_trans2 *parms) 239{ 240 return smb_raw_trans2_recv(req, mem_ctx, parms); 241} 242 243 244/* 245 trans/trans2 raw async interface - only BLOBs used in this interface. 246*/ 247struct smbcli_request *smb_raw_trans_send_backend(struct smbcli_tree *tree, 248 struct smb_trans2 *parms, 249 uint8_t command) 250{ 251 struct smb_raw_trans2_recv_state *state; 252 struct smbcli_request *req; 253 int i; 254 int padding; 255 size_t space_left; 256 size_t namelen = 0; 257 DATA_BLOB params_chunk; 258 uint16_t ofs; 259 uint16_t params_ofs = 0; 260 DATA_BLOB data_chunk; 261 uint16_t data_ofs = 0; 262 263 if (parms->in.params.length > UINT16_MAX || 264 parms->in.data.length > UINT16_MAX) { 265 DEBUG(3,("Attempt to send invalid trans2 request (params %u, data %u)\n", 266 (unsigned)parms->in.params.length, (unsigned)parms->in.data.length)); 267 return NULL; 268 } 269 270 271 if (command == SMBtrans) 272 padding = 1; 273 else 274 padding = 3; 275 276 req = smbcli_request_setup(tree, command, 277 14 + parms->in.setup_count, 278 padding); 279 if (!req) { 280 return NULL; 281 } 282 283 state = talloc_zero(req, struct smb_raw_trans2_recv_state); 284 if (!state) { 285 smbcli_request_destroy(req); 286 return NULL; 287 } 288 289 state->command = command; 290 291 /* make sure we don't leak data via the padding */ 292 memset(req->out.data, 0, padding); 293 294 /* Watch out, this changes the req->out.* pointers */ 295 if (command == SMBtrans && parms->in.trans_name) { 296 namelen = smbcli_req_append_string(req, parms->in.trans_name, 297 STR_TERMINATE); 298 } 299 300 ofs = PTR_DIFF(req->out.data,req->out.hdr)+padding+namelen; 301 302 /* see how much bytes of the params block we can ship in the first request */ 303 space_left = raw_trans_space_left(req); 304 305 params_chunk.length = MIN(parms->in.params.length, space_left); 306 params_chunk.data = parms->in.params.data; 307 params_ofs = ofs; 308 309 state->params_left = parms->in.params.length - params_chunk.length; 310 311 if (state->params_left > 0) { 312 /* we copy the whole params block, if needed we can optimize that latter */ 313 state->io.in.params = data_blob_talloc(state, NULL, parms->in.params.length); 314 if (!state->io.in.params.data) { 315 smbcli_request_destroy(req); 316 return NULL; 317 } 318 memcpy(state->io.in.params.data, 319 parms->in.params.data, 320 parms->in.params.length); 321 } 322 323 /* see how much bytes of the data block we can ship in the first request */ 324 space_left -= params_chunk.length; 325 326#if TORTURE_TRANS_DATA 327 if (space_left > 1) { 328 space_left /= 2; 329 } 330#endif 331 332 data_chunk.length = MIN(parms->in.data.length, space_left); 333 data_chunk.data = parms->in.data.data; 334 data_ofs = params_ofs + params_chunk.length; 335 336 state->data_left = parms->in.data.length - data_chunk.length; 337 338 if (state->data_left > 0) { 339 /* we copy the whole params block, if needed we can optimize that latter */ 340 state->io.in.data = data_blob_talloc(state, NULL, parms->in.data.length); 341 if (!state->io.in.data.data) { 342 smbcli_request_destroy(req); 343 return NULL; 344 } 345 memcpy(state->io.in.data.data, 346 parms->in.data.data, 347 parms->in.data.length); 348 } 349 350 state->params_total = parms->in.params.length; 351 state->data_total = parms->in.data.length; 352 353 /* primary request */ 354 SSVAL(req->out.vwv,VWV(0),parms->in.params.length); 355 SSVAL(req->out.vwv,VWV(1),parms->in.data.length); 356 SSVAL(req->out.vwv,VWV(2),parms->in.max_param); 357 SSVAL(req->out.vwv,VWV(3),parms->in.max_data); 358 SCVAL(req->out.vwv,VWV(4),parms->in.max_setup); 359 SCVAL(req->out.vwv,VWV(4)+1,0); /* reserved */ 360 SSVAL(req->out.vwv,VWV(5),parms->in.flags); 361 SIVAL(req->out.vwv,VWV(6),parms->in.timeout); 362 SSVAL(req->out.vwv,VWV(8),0); /* reserved */ 363 SSVAL(req->out.vwv,VWV(9),params_chunk.length); 364 SSVAL(req->out.vwv,VWV(10),params_ofs); 365 SSVAL(req->out.vwv,VWV(11),data_chunk.length); 366 SSVAL(req->out.vwv,VWV(12),data_ofs); 367 SCVAL(req->out.vwv,VWV(13),parms->in.setup_count); 368 SCVAL(req->out.vwv,VWV(13)+1,0); /* reserved */ 369 for (i=0;i<parms->in.setup_count;i++) { 370 SSVAL(req->out.vwv,VWV(14)+VWV(i),parms->in.setup[i]); 371 } 372 smbcli_req_append_blob(req, ¶ms_chunk); 373 smbcli_req_append_blob(req, &data_chunk); 374 375 /* add the helper which will check that all multi-part replies are 376 in before an async client callack will be issued */ 377 req->recv_helper.fn = smb_raw_trans2_recv_helper; 378 req->recv_helper.private_data = state; 379 380 if (!smbcli_request_send(req)) { 381 smbcli_request_destroy(req); 382 return NULL; 383 } 384 385 return req; 386} 387 388static enum smbcli_request_state smb_raw_trans2_ship_next(struct smbcli_request *req, 389 struct smb_raw_trans2_recv_state *state) 390{ 391 struct smbcli_request *req2; 392 size_t space_left; 393 DATA_BLOB params_chunk; 394 uint16_t ofs; 395 uint16_t params_ofs = 0; 396 uint16_t params_disp = 0; 397 DATA_BLOB data_chunk; 398 uint16_t data_ofs = 0; 399 uint16_t data_disp = 0; 400 uint8_t wct; 401 402 if (state->command == SMBtrans2) { 403 wct = 9; 404 } else { 405 wct = 8; 406 } 407 408 req2 = smbcli_request_setup(req->tree, state->command+1, wct, 0); 409 if (!req2) { 410 goto nomem; 411 } 412 req2->mid = req->mid; 413 SSVAL(req2->out.hdr, HDR_MID, req2->mid); 414 415 ofs = PTR_DIFF(req2->out.data,req2->out.hdr); 416 417 /* see how much bytes of the params block we can ship in the first request */ 418 space_left = raw_trans_space_left(req2); 419 420 params_disp = state->io.in.params.length - state->params_left; 421 params_chunk.length = MIN(state->params_left, space_left); 422 params_chunk.data = state->io.in.params.data + params_disp; 423 params_ofs = ofs; 424 425 state->params_left -= params_chunk.length; 426 427 /* see how much bytes of the data block we can ship in the first request */ 428 space_left -= params_chunk.length; 429 430#if TORTURE_TRANS_DATA 431 if (space_left > 1) { 432 space_left /= 2; 433 } 434#endif 435 436 data_disp = state->io.in.data.length - state->data_left; 437 data_chunk.length = MIN(state->data_left, space_left); 438 data_chunk.data = state->io.in.data.data + data_disp; 439 data_ofs = params_ofs+params_chunk.length; 440 441 state->data_left -= data_chunk.length; 442 443 SSVAL(req2->out.vwv,VWV(0), state->params_total); 444 SSVAL(req2->out.vwv,VWV(1), state->data_total); 445 SSVAL(req2->out.vwv,VWV(2), params_chunk.length); 446 SSVAL(req2->out.vwv,VWV(3), params_ofs); 447 SSVAL(req2->out.vwv,VWV(4), params_disp); 448 SSVAL(req2->out.vwv,VWV(5), data_chunk.length); 449 SSVAL(req2->out.vwv,VWV(6), data_ofs); 450 SSVAL(req2->out.vwv,VWV(7), data_disp); 451 if (wct == 9) { 452 SSVAL(req2->out.vwv,VWV(8), 0xFFFF); 453 } 454 455 smbcli_req_append_blob(req2, ¶ms_chunk); 456 smbcli_req_append_blob(req2, &data_chunk); 457 458 /* 459 * it's a one way request but we need 460 * the seq_num, so we destroy req2 by hand 461 */ 462 if (!smbcli_request_send(req2)) { 463 goto failed; 464 } 465 466 req->seq_num = req2->seq_num; 467 smbcli_request_destroy(req2); 468 469 return SMBCLI_REQUEST_RECV; 470 471nomem: 472 req->status = NT_STATUS_NO_MEMORY; 473failed: 474 if (req2) { 475 req->status = smbcli_request_destroy(req2); 476 } 477 return SMBCLI_REQUEST_ERROR; 478} 479 480static enum smbcli_request_state smb_raw_trans2_ship_rest(struct smbcli_request *req, 481 struct smb_raw_trans2_recv_state *state) 482{ 483 enum smbcli_request_state ret = SMBCLI_REQUEST_ERROR; 484 485 while (state->params_left > 0 || state->data_left > 0) { 486 ret = smb_raw_trans2_ship_next(req, state); 487 if (ret != SMBCLI_REQUEST_RECV) { 488 break; 489 } 490 } 491 492 return ret; 493} 494 495 496/* 497 trans/trans2 raw async interface - only BLOBs used in this interface. 498 note that this doesn't yet support multi-part requests 499*/ 500_PUBLIC_ struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree, 501 struct smb_trans2 *parms) 502{ 503 return smb_raw_trans_send_backend(tree, parms, SMBtrans); 504} 505 506struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree, 507 struct smb_trans2 *parms) 508{ 509 return smb_raw_trans_send_backend(tree, parms, SMBtrans2); 510} 511 512/* 513 trans2 synchronous blob interface 514*/ 515NTSTATUS smb_raw_trans2(struct smbcli_tree *tree, 516 TALLOC_CTX *mem_ctx, 517 struct smb_trans2 *parms) 518{ 519 struct smbcli_request *req; 520 req = smb_raw_trans2_send(tree, parms); 521 if (!req) return NT_STATUS_UNSUCCESSFUL; 522 return smb_raw_trans2_recv(req, mem_ctx, parms); 523} 524 525 526/* 527 trans synchronous blob interface 528*/ 529_PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree, 530 TALLOC_CTX *mem_ctx, 531 struct smb_trans2 *parms) 532{ 533 struct smbcli_request *req; 534 req = smb_raw_trans_send(tree, parms); 535 if (!req) return NT_STATUS_UNSUCCESSFUL; 536 return smb_raw_trans_recv(req, mem_ctx, parms); 537} 538 539struct smb_raw_nttrans_recv_state { 540 uint32_t params_total; 541 uint32_t data_total; 542 uint32_t params_left; 543 uint32_t data_left; 544 bool got_first; 545 uint32_t recvd_data; 546 uint32_t recvd_param; 547 struct smb_nttrans io; 548}; 549 550NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req, 551 TALLOC_CTX *mem_ctx, 552 struct smb_nttrans *parms) 553{ 554 struct smb_raw_nttrans_recv_state *state; 555 556 if (!smbcli_request_receive(req) || 557 smbcli_request_is_error(req)) { 558 goto failed; 559 } 560 561 state = talloc_get_type(req->recv_helper.private_data, 562 struct smb_raw_nttrans_recv_state); 563 564 parms->out = state->io.out; 565 talloc_steal(mem_ctx, parms->out.setup); 566 talloc_steal(mem_ctx, parms->out.params.data); 567 talloc_steal(mem_ctx, parms->out.data.data); 568 talloc_free(state); 569 570 ZERO_STRUCT(req->recv_helper); 571 572failed: 573 return smbcli_request_destroy(req); 574} 575 576static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request *req, 577 struct smb_raw_nttrans_recv_state *state); 578 579/* 580 * This helper returns SMBCLI_REQUEST_RECV until all data has arrived 581 */ 582static enum smbcli_request_state smb_raw_nttrans_recv_helper(struct smbcli_request *req) 583{ 584 struct smb_raw_nttrans_recv_state *state = talloc_get_type(req->recv_helper.private_data, 585 struct smb_raw_nttrans_recv_state); 586 uint32_t param_count, param_ofs, param_disp; 587 uint32_t data_count, data_ofs, data_disp; 588 uint32_t total_data, total_param; 589 uint8_t setup_count; 590 591 /* 592 * An NT RPC pipe call can return ERRDOS, ERRmoredata 593 * to a trans call. This is not an error and should not 594 * be treated as such. 595 */ 596 if (smbcli_request_is_error(req)) { 597 goto failed; 598 } 599 600 /* sanity check */ 601 if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) { 602 DEBUG(0,("smb_raw_nttrans_recv_helper: Expected %s response, got command 0x%02x\n", 603 "SMBnttrans", 604 CVAL(req->in.hdr,HDR_COM))); 605 req->status = NT_STATUS_INVALID_NETWORK_RESPONSE; 606 goto failed; 607 } 608 609 if (state->params_left > 0 || state->data_left > 0) { 610 return smb_raw_nttrans_ship_rest(req, state); 611 } 612 613 /* this is the first packet of the response */ 614 SMBCLI_CHECK_MIN_WCT(req, 18); 615 616 total_param = IVAL(req->in.vwv, 3); 617 total_data = IVAL(req->in.vwv, 7); 618 setup_count = CVAL(req->in.vwv, 35); 619 620 param_count = IVAL(req->in.vwv, 11); 621 param_ofs = IVAL(req->in.vwv, 15); 622 param_disp = IVAL(req->in.vwv, 19); 623 624 data_count = IVAL(req->in.vwv, 23); 625 data_ofs = IVAL(req->in.vwv, 27); 626 data_disp = IVAL(req->in.vwv, 31); 627 628 if (!state->got_first) { 629 if (total_param > 0) { 630 state->io.out.params = data_blob_talloc(state, NULL, total_param); 631 if (!state->io.out.params.data) { 632 goto nomem; 633 } 634 } 635 636 if (total_data > 0) { 637 state->io.out.data = data_blob_talloc(state, NULL, total_data); 638 if (!state->io.out.data.data) { 639 goto nomem; 640 } 641 } 642 643 if (setup_count > 0) { 644 SMBCLI_CHECK_WCT(req, 18 + setup_count); 645 646 state->io.out.setup_count = setup_count; 647 state->io.out.setup = talloc_array(state, uint8_t, 648 setup_count * VWV(1)); 649 if (!state->io.out.setup) { 650 goto nomem; 651 } 652 memcpy(state->io.out.setup, (uint8_t *)req->out.vwv + VWV(18), 653 setup_count * VWV(1)); 654 } 655 656 state->got_first = true; 657 } 658 659 if (total_data > state->io.out.data.length || 660 total_param > state->io.out.params.length) { 661 /* they must *only* shrink */ 662 DEBUG(1,("smb_raw_nttrans_recv_helper: data/params expanded!\n")); 663 req->status = NT_STATUS_BUFFER_TOO_SMALL; 664 goto failed; 665 } 666 667 state->io.out.data.length = total_data; 668 state->io.out.params.length = total_param; 669 670 if (data_count + data_disp > total_data || 671 param_count + param_disp > total_param) { 672 DEBUG(1,("smb_raw_nttrans_recv_helper: Buffer overflow\n")); 673 req->status = NT_STATUS_BUFFER_TOO_SMALL; 674 goto failed; 675 } 676 677 /* check the server isn't being nasty */ 678 if (raw_trans_oob(req, param_ofs, param_count) || 679 raw_trans_oob(req, data_ofs, data_count)) { 680 DEBUG(1,("smb_raw_nttrans_recv_helper: out of bounds parameters!\n")); 681 req->status = NT_STATUS_BUFFER_TOO_SMALL; 682 goto failed; 683 } 684 685 if (data_count) { 686 memcpy(state->io.out.data.data + data_disp, 687 req->in.hdr + data_ofs, 688 data_count); 689 } 690 691 if (param_count) { 692 memcpy(state->io.out.params.data + param_disp, 693 req->in.hdr + param_ofs, 694 param_count); 695 } 696 697 state->recvd_param += param_count; 698 state->recvd_data += data_count; 699 700 if (state->recvd_data < total_data || 701 state->recvd_param < total_param) { 702 703 /* we don't need the in buffer any more */ 704 talloc_free(req->in.buffer); 705 ZERO_STRUCT(req->in); 706 707 /* we still wait for more data */ 708 DEBUG(10,("smb_raw_nttrans_recv_helper: more data needed\n")); 709 return SMBCLI_REQUEST_RECV; 710 } 711 712 DEBUG(10,("smb_raw_nttrans_recv_helper: done\n")); 713 return SMBCLI_REQUEST_DONE; 714 715nomem: 716 req->status = NT_STATUS_NO_MEMORY; 717failed: 718 return SMBCLI_REQUEST_ERROR; 719} 720 721/**************************************************************************** 722 nttrans raw - only BLOBs used in this interface. 723 at the moment we only handle a single primary request 724****************************************************************************/ 725struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree, 726 struct smb_nttrans *parms) 727{ 728 struct smbcli_request *req; 729 struct smb_raw_nttrans_recv_state *state; 730 uint32_t ofs; 731 size_t space_left; 732 DATA_BLOB params_chunk; 733 uint32_t params_ofs; 734 DATA_BLOB data_chunk; 735 uint32_t data_ofs; 736 int align = 0; 737 738 /* only align if there are parameters or data */ 739 if (parms->in.params.length || parms->in.data.length) { 740 align = 3; 741 } 742 743 req = smbcli_request_setup(tree, SMBnttrans, 744 19 + parms->in.setup_count, align); 745 if (!req) { 746 return NULL; 747 } 748 749 state = talloc_zero(req, struct smb_raw_nttrans_recv_state); 750 if (!state) { 751 talloc_free(req); 752 return NULL; 753 } 754 755 /* fill in SMB parameters */ 756 757 if (align != 0) { 758 memset(req->out.data, 0, align); 759 } 760 761 ofs = PTR_DIFF(req->out.data,req->out.hdr)+align; 762 763 /* see how much bytes of the params block we can ship in the first request */ 764 space_left = raw_trans_space_left(req); 765 766 params_chunk.length = MIN(parms->in.params.length, space_left); 767 params_chunk.data = parms->in.params.data; 768 params_ofs = ofs; 769 770 state->params_left = parms->in.params.length - params_chunk.length; 771 772 if (state->params_left > 0) { 773 /* we copy the whole params block, if needed we can optimize that latter */ 774 state->io.in.params = data_blob_talloc(state, NULL, parms->in.params.length); 775 if (!state->io.in.params.data) { 776 smbcli_request_destroy(req); 777 return NULL; 778 } 779 memcpy(state->io.in.params.data, 780 parms->in.params.data, 781 parms->in.params.length); 782 } 783 784 /* see how much bytes of the data block we can ship in the first request */ 785 space_left -= params_chunk.length; 786 787#if TORTURE_TRANS_DATA 788 if (space_left > 1) { 789 space_left /= 2; 790 } 791#endif 792 793 data_chunk.length = MIN(parms->in.data.length, space_left); 794 data_chunk.data = parms->in.data.data; 795 data_ofs = params_ofs + params_chunk.length; 796 797 state->data_left = parms->in.data.length - data_chunk.length; 798 799 if (state->data_left > 0) { 800 /* we copy the whole params block, if needed we can optimize that latter */ 801 state->io.in.data = data_blob_talloc(state, NULL, parms->in.data.length); 802 if (!state->io.in.data.data) { 803 smbcli_request_destroy(req); 804 return NULL; 805 } 806 memcpy(state->io.in.data.data, 807 parms->in.data.data, 808 parms->in.data.length); 809 } 810 811 state->params_total = parms->in.params.length; 812 state->data_total = parms->in.data.length; 813 814 SCVAL(req->out.vwv, 0, parms->in.max_setup); 815 SSVAL(req->out.vwv, 1, 0); /* reserved */ 816 SIVAL(req->out.vwv, 3, parms->in.params.length); 817 SIVAL(req->out.vwv, 7, parms->in.data.length); 818 SIVAL(req->out.vwv, 11, parms->in.max_param); 819 SIVAL(req->out.vwv, 15, parms->in.max_data); 820 SIVAL(req->out.vwv, 19, params_chunk.length); 821 SIVAL(req->out.vwv, 23, params_ofs); 822 SIVAL(req->out.vwv, 27, data_chunk.length); 823 SIVAL(req->out.vwv, 31, data_ofs); 824 SCVAL(req->out.vwv, 35, parms->in.setup_count); 825 SSVAL(req->out.vwv, 36, parms->in.function); 826 memcpy(req->out.vwv + VWV(19), parms->in.setup, 827 sizeof(uint16_t) * parms->in.setup_count); 828 829 smbcli_req_append_blob(req, ¶ms_chunk); 830 smbcli_req_append_blob(req, &data_chunk); 831 832 /* add the helper which will check that all multi-part replies are 833 in before an async client callack will be issued */ 834 req->recv_helper.fn = smb_raw_nttrans_recv_helper; 835 req->recv_helper.private_data = state; 836 837 if (!smbcli_request_send(req)) { 838 smbcli_request_destroy(req); 839 return NULL; 840 } 841 842 return req; 843} 844 845static enum smbcli_request_state smb_raw_nttrans_ship_next(struct smbcli_request *req, 846 struct smb_raw_nttrans_recv_state *state) 847{ 848 struct smbcli_request *req2; 849 size_t space_left; 850 DATA_BLOB params_chunk; 851 uint32_t ofs; 852 uint32_t params_ofs = 0; 853 uint32_t params_disp = 0; 854 DATA_BLOB data_chunk; 855 uint32_t data_ofs = 0; 856 uint32_t data_disp = 0; 857 858 req2 = smbcli_request_setup(req->tree, SMBnttranss, 18, 0); 859 if (!req2) { 860 goto nomem; 861 } 862 req2->mid = req->mid; 863 SSVAL(req2->out.hdr, HDR_MID, req2->mid); 864 865 ofs = PTR_DIFF(req2->out.data,req2->out.hdr); 866 867 /* see how much bytes of the params block we can ship in the first request */ 868 space_left = raw_trans_space_left(req2); 869 870 params_disp = state->io.in.params.length - state->params_left; 871 params_chunk.length = MIN(state->params_left, space_left); 872 params_chunk.data = state->io.in.params.data + params_disp; 873 params_ofs = ofs; 874 875 state->params_left -= params_chunk.length; 876 877 /* see how much bytes of the data block we can ship in the first request */ 878 space_left -= params_chunk.length; 879 880#if TORTURE_TRANS_DATA 881 if (space_left > 1) { 882 space_left /= 2; 883 } 884#endif 885 886 data_disp = state->io.in.data.length - state->data_left; 887 data_chunk.length = MIN(state->data_left, space_left); 888 data_chunk.data = state->io.in.data.data + data_disp; 889 data_ofs = params_ofs+params_chunk.length; 890 891 state->data_left -= data_chunk.length; 892 893 SSVAL(req2->out.vwv,0, 0); /* reserved */ 894 SCVAL(req2->out.vwv,2, 0); /* reserved */ 895 SIVAL(req2->out.vwv,3, state->params_total); 896 SIVAL(req2->out.vwv,7, state->data_total); 897 SIVAL(req2->out.vwv,11, params_chunk.length); 898 SIVAL(req2->out.vwv,15, params_ofs); 899 SIVAL(req2->out.vwv,19, params_disp); 900 SIVAL(req2->out.vwv,23, data_chunk.length); 901 SIVAL(req2->out.vwv,27, data_ofs); 902 SIVAL(req2->out.vwv,31, data_disp); 903 SCVAL(req2->out.vwv,35, 0); /* reserved */ 904 905 smbcli_req_append_blob(req2, ¶ms_chunk); 906 smbcli_req_append_blob(req2, &data_chunk); 907 908 /* 909 * it's a one way request but we need 910 * the seq_num, so we destroy req2 by hand 911 */ 912 if (!smbcli_request_send(req2)) { 913 goto failed; 914 } 915 916 req->seq_num = req2->seq_num; 917 smbcli_request_destroy(req2); 918 919 return SMBCLI_REQUEST_RECV; 920 921nomem: 922 req->status = NT_STATUS_NO_MEMORY; 923failed: 924 if (req2) { 925 req->status = smbcli_request_destroy(req2); 926 } 927 return SMBCLI_REQUEST_ERROR; 928} 929 930static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request *req, 931 struct smb_raw_nttrans_recv_state *state) 932{ 933 enum smbcli_request_state ret = SMBCLI_REQUEST_ERROR; 934 935 while (state->params_left > 0 || state->data_left > 0) { 936 ret = smb_raw_nttrans_ship_next(req, state); 937 if (ret != SMBCLI_REQUEST_RECV) { 938 break; 939 } 940 } 941 942 return ret; 943} 944 945 946/**************************************************************************** 947 receive a SMB nttrans response allocating the necessary memory 948 ****************************************************************************/ 949NTSTATUS smb_raw_nttrans(struct smbcli_tree *tree, 950 TALLOC_CTX *mem_ctx, 951 struct smb_nttrans *parms) 952{ 953 struct smbcli_request *req; 954 955 req = smb_raw_nttrans_send(tree, parms); 956 if (!req) { 957 return NT_STATUS_UNSUCCESSFUL; 958 } 959 960 return smb_raw_nttrans_recv(req, mem_ctx, parms); 961} 962