Changeset 740 for vendor/current/source3/libsmb/clitrans.c
- Timestamp:
- Nov 14, 2012, 12:59:34 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source3/libsmb/clitrans.c
r414 r740 19 19 20 20 #include "includes.h" 21 22 23 /**************************************************************************** 24 Send a SMB trans or trans2 request. 25 ****************************************************************************/ 26 27 bool cli_send_trans(struct cli_state *cli, int trans, 28 const char *pipe_name, 29 int fid, int flags, 30 uint16 *setup, unsigned int lsetup, unsigned int msetup, 31 const char *param, unsigned int lparam, unsigned int mparam, 32 const char *data, unsigned int ldata, unsigned int mdata) 33 { 34 unsigned int i; 35 unsigned int this_ldata,this_lparam; 36 unsigned int tot_data=0,tot_param=0; 37 char *outdata,*outparam; 38 char *p; 39 int pipe_name_len=0; 40 uint16 mid; 41 42 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */ 43 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam)); 44 45 memset(cli->outbuf,'\0',smb_size); 46 cli_set_message(cli->outbuf,14+lsetup,0,True); 47 SCVAL(cli->outbuf,smb_com,trans); 48 SSVAL(cli->outbuf,smb_tid, cli->cnum); 49 cli_setup_packet(cli); 50 51 /* 52 * Save the mid we're using. We need this for finding 53 * signing replies. 54 */ 55 56 mid = cli->mid; 57 58 if (pipe_name) { 59 pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE); 60 } 61 62 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3); 63 outdata = outparam+this_lparam; 64 65 /* primary request */ 66 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */ 67 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */ 68 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */ 69 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */ 70 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */ 71 SSVAL(cli->outbuf,smb_flags,flags); /* flags */ 72 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */ 73 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */ 74 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */ 75 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */ 76 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */ 77 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */ 78 for (i=0;i<lsetup;i++) /* setup[] */ 79 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]); 80 p = smb_buf(cli->outbuf); 81 if (trans != SMBtrans) { 82 *p++ = 0; /* put in a null smb_name */ 83 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */ 84 } 85 if (this_lparam) /* param[] */ 86 memcpy(outparam,param,this_lparam); 87 if (this_ldata) /* data[] */ 88 memcpy(outdata,data,this_ldata); 89 cli_setup_bcc(cli, outdata+this_ldata); 90 91 show_msg(cli->outbuf); 92 93 if (!cli_send_smb(cli)) { 94 return False; 95 } 96 97 cli_state_seqnum_persistent(cli, mid); 98 99 if (this_ldata < ldata || this_lparam < lparam) { 100 /* receive interim response */ 101 if (!cli_receive_smb(cli) || cli_is_error(cli)) { 102 cli_state_seqnum_remove(cli, mid); 103 return(False); 104 } 105 106 tot_data = this_ldata; 107 tot_param = this_lparam; 108 109 while (tot_data < ldata || tot_param < lparam) { 110 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */ 111 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam)); 112 113 cli_set_message(cli->outbuf,trans==SMBtrans?8:9,0,True); 114 SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2)); 115 116 outparam = smb_buf(cli->outbuf); 117 outdata = outparam+this_lparam; 118 119 /* secondary request */ 120 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */ 121 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */ 122 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */ 123 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */ 124 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */ 125 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */ 126 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */ 127 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */ 128 if (trans==SMBtrans2) 129 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */ 130 if (this_lparam) /* param[] */ 131 memcpy(outparam,param+tot_param,this_lparam); 132 if (this_ldata) /* data[] */ 133 memcpy(outdata,data+tot_data,this_ldata); 134 cli_setup_bcc(cli, outdata+this_ldata); 135 136 show_msg(cli->outbuf); 137 138 cli->mid = mid; 139 if (!cli_send_smb(cli)) { 140 cli_state_seqnum_remove(cli, mid); 141 return False; 142 } 143 144 tot_data += this_ldata; 145 tot_param += this_lparam; 146 } 147 } 148 149 return(True); 150 } 151 152 /**************************************************************************** 153 Receive a SMB trans or trans2 response allocating the necessary memory. 154 ****************************************************************************/ 155 156 bool cli_receive_trans(struct cli_state *cli,int trans, 157 char **param, unsigned int *param_len, 158 char **data, unsigned int *data_len) 159 { 160 unsigned int total_data=0; 161 unsigned int total_param=0; 162 unsigned int this_data,this_param; 163 NTSTATUS status; 164 bool ret = False; 165 uint16_t mid; 166 167 *data_len = *param_len = 0; 168 169 mid = SVAL(cli->outbuf,smb_mid); 170 171 if (!cli_receive_smb(cli)) { 172 cli_state_seqnum_remove(cli, mid); 173 return False; 174 } 175 176 show_msg(cli->inbuf); 177 178 /* sanity check */ 179 if (CVAL(cli->inbuf,smb_com) != trans) { 180 DEBUG(0,("Expected %s response, got command 0x%02x\n", 181 trans==SMBtrans?"SMBtrans":"SMBtrans2", 182 CVAL(cli->inbuf,smb_com))); 183 cli_state_seqnum_remove(cli, mid); 184 return False; 185 } 186 187 /* 188 * An NT RPC pipe call can return ERRDOS, ERRmoredata 189 * to a trans call. This is not an error and should not 190 * be treated as such. Note that STATUS_NO_MORE_FILES is 191 * returned when a trans2 findfirst/next finishes. 192 * When setting up an encrypted transport we can also 193 * see NT_STATUS_MORE_PROCESSING_REQUIRED here. 194 * 195 * Vista returns NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT if the folder 196 * "<share>/Users/All Users" is enumerated. This is a special pseudo 197 * folder, and the response does not have parameters (nor a parameter 198 * length). 199 */ 200 status = cli_nt_error(cli); 201 202 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 203 if (NT_STATUS_IS_ERR(status) || 204 NT_STATUS_EQUAL(status,STATUS_NO_MORE_FILES) || 205 NT_STATUS_EQUAL(status,NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) { 206 goto out; 207 } 208 } 209 210 /* parse out the lengths */ 211 total_data = SVAL(cli->inbuf,smb_tdrcnt); 212 total_param = SVAL(cli->inbuf,smb_tprcnt); 213 214 /* allocate it */ 215 if (total_data!=0) { 216 /* We know adding 2 is safe as total_data is an 217 * SVAL <= 0xFFFF. */ 218 *data = (char *)SMB_REALLOC(*data,total_data+2); 219 if (!(*data)) { 220 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n")); 221 goto out; 222 } 223 } 224 225 if (total_param!=0) { 226 /* We know adding 2 is safe as total_param is an 227 * SVAL <= 0xFFFF. */ 228 *param = (char *)SMB_REALLOC(*param,total_param+2); 229 if (!(*param)) { 230 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n")); 231 goto out; 232 } 233 } 234 235 for (;;) { 236 this_data = SVAL(cli->inbuf,smb_drcnt); 237 this_param = SVAL(cli->inbuf,smb_prcnt); 238 239 if (this_data + *data_len > total_data || 240 this_param + *param_len > total_param) { 241 DEBUG(1,("Data overflow in cli_receive_trans\n")); 242 goto out; 243 } 244 245 if (this_data + *data_len < this_data || 246 this_data + *data_len < *data_len || 247 this_param + *param_len < this_param || 248 this_param + *param_len < *param_len) { 249 DEBUG(1,("Data overflow in cli_receive_trans\n")); 250 goto out; 251 } 252 253 if (this_data) { 254 unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp); 255 unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff); 256 257 if (data_offset_out > total_data || 258 data_offset_out + this_data > total_data || 259 data_offset_out + this_data < data_offset_out || 260 data_offset_out + this_data < this_data) { 261 DEBUG(1,("Data overflow in cli_receive_trans\n")); 262 goto out; 263 } 264 if (data_offset_in > cli->bufsize || 265 data_offset_in + this_data > cli->bufsize || 266 data_offset_in + this_data < data_offset_in || 267 data_offset_in + this_data < this_data) { 268 DEBUG(1,("Data overflow in cli_receive_trans\n")); 269 goto out; 270 } 271 272 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data); 273 } 274 if (this_param) { 275 unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp); 276 unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff); 277 278 if (param_offset_out > total_param || 279 param_offset_out + this_param > total_param || 280 param_offset_out + this_param < param_offset_out || 281 param_offset_out + this_param < this_param) { 282 DEBUG(1,("Param overflow in cli_receive_trans\n")); 283 goto out; 284 } 285 if (param_offset_in > cli->bufsize || 286 param_offset_in + this_param > cli->bufsize || 287 param_offset_in + this_param < param_offset_in || 288 param_offset_in + this_param < this_param) { 289 DEBUG(1,("Param overflow in cli_receive_trans\n")); 290 goto out; 291 } 292 293 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param); 294 } 295 *data_len += this_data; 296 *param_len += this_param; 297 298 if (total_data <= *data_len && total_param <= *param_len) { 299 ret = True; 300 break; 301 } 302 303 if (!cli_receive_smb(cli)) { 304 goto out; 305 } 306 307 show_msg(cli->inbuf); 308 309 /* sanity check */ 310 if (CVAL(cli->inbuf,smb_com) != trans) { 311 DEBUG(0,("Expected %s response, got command 0x%02x\n", 312 trans==SMBtrans?"SMBtrans":"SMBtrans2", 313 CVAL(cli->inbuf,smb_com))); 314 goto out; 315 } 316 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 317 if (NT_STATUS_IS_ERR(cli_nt_error(cli))) { 318 goto out; 319 } 320 } 321 322 /* parse out the total lengths again - they can shrink! */ 323 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data) 324 total_data = SVAL(cli->inbuf,smb_tdrcnt); 325 if (SVAL(cli->inbuf,smb_tprcnt) < total_param) 326 total_param = SVAL(cli->inbuf,smb_tprcnt); 327 328 if (total_data <= *data_len && total_param <= *param_len) { 329 ret = True; 330 break; 331 } 332 } 333 334 out: 335 336 cli_state_seqnum_remove(cli, mid); 337 338 if (ret) { 339 /* Ensure the last 2 bytes of param and data are 2 null 340 * bytes. These are malloc'ed, but not included in any 341 * length counts. This allows cli_XX string reading functions 342 * to safely null terminate. */ 343 if (total_data) { 344 SSVAL(*data,total_data,0); 345 } 346 if (total_param) { 347 SSVAL(*param,total_param,0); 348 } 349 } 350 351 return ret; 352 } 353 354 /**************************************************************************** 355 Send a SMB nttrans request. 356 ****************************************************************************/ 357 358 bool cli_send_nt_trans(struct cli_state *cli, 359 int function, 360 int flags, 361 uint16 *setup, unsigned int lsetup, unsigned int msetup, 362 char *param, unsigned int lparam, unsigned int mparam, 363 char *data, unsigned int ldata, unsigned int mdata) 364 { 365 unsigned int i; 366 unsigned int this_ldata,this_lparam; 367 unsigned int tot_data=0,tot_param=0; 368 uint16 mid; 369 char *outdata,*outparam; 370 371 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */ 372 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam)); 373 374 memset(cli->outbuf,'\0',smb_size); 375 cli_set_message(cli->outbuf,19+lsetup,0,True); 376 SCVAL(cli->outbuf,smb_com,SMBnttrans); 377 SSVAL(cli->outbuf,smb_tid, cli->cnum); 378 cli_setup_packet(cli); 379 380 /* 381 * Save the mid we're using. We need this for finding 382 * signing replies. 383 */ 384 385 mid = cli->mid; 386 387 outparam = smb_buf(cli->outbuf)+3; 388 outdata = outparam+this_lparam; 389 390 /* primary request */ 391 SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup); 392 SCVAL(cli->outbuf,smb_nt_Flags,flags); 393 SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam); 394 SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata); 395 SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam); 396 SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata); 397 SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam); 398 SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf)); 399 SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata); 400 SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf)); 401 SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup); 402 SIVAL(cli->outbuf,smb_nt_Function, function); 403 for (i=0;i<lsetup;i++) /* setup[] */ 404 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]); 405 406 if (this_lparam) /* param[] */ 407 memcpy(outparam,param,this_lparam); 408 if (this_ldata) /* data[] */ 409 memcpy(outdata,data,this_ldata); 410 411 cli_setup_bcc(cli, outdata+this_ldata); 412 413 show_msg(cli->outbuf); 414 if (!cli_send_smb(cli)) { 415 return False; 416 } 417 418 cli_state_seqnum_persistent(cli, mid); 419 420 if (this_ldata < ldata || this_lparam < lparam) { 421 /* receive interim response */ 422 if (!cli_receive_smb(cli) || cli_is_error(cli)) { 423 cli_state_seqnum_remove(cli, mid); 424 return(False); 425 } 426 427 tot_data = this_ldata; 428 tot_param = this_lparam; 429 430 while (tot_data < ldata || tot_param < lparam) { 431 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */ 432 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam)); 433 434 cli_set_message(cli->outbuf,18,0,True); 435 SCVAL(cli->outbuf,smb_com,SMBnttranss); 436 437 /* XXX - these should probably be aligned */ 438 outparam = smb_buf(cli->outbuf); 439 outdata = outparam+this_lparam; 440 441 /* secondary request */ 442 SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam); 443 SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata); 444 SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam); 445 SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf)); 446 SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param); 447 SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata); 448 SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf)); 449 SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data); 450 if (this_lparam) /* param[] */ 451 memcpy(outparam,param+tot_param,this_lparam); 452 if (this_ldata) /* data[] */ 453 memcpy(outdata,data+tot_data,this_ldata); 454 cli_setup_bcc(cli, outdata+this_ldata); 455 456 show_msg(cli->outbuf); 457 458 cli->mid = mid; 459 if (!cli_send_smb(cli)) { 460 cli_state_seqnum_remove(cli, mid); 461 return False; 462 } 463 464 tot_data += this_ldata; 465 tot_param += this_lparam; 466 } 467 } 468 469 return(True); 470 } 471 472 /**************************************************************************** 473 Receive a SMB nttrans response allocating the necessary memory. 474 ****************************************************************************/ 475 476 bool cli_receive_nt_trans(struct cli_state *cli, 477 char **param, unsigned int *param_len, 478 char **data, unsigned int *data_len) 479 { 480 unsigned int total_data=0; 481 unsigned int total_param=0; 482 unsigned int this_data,this_param; 483 uint8 eclass; 484 uint32 ecode; 485 bool ret = False; 486 uint16_t mid; 487 488 *data_len = *param_len = 0; 489 490 mid = SVAL(cli->outbuf,smb_mid); 491 492 if (!cli_receive_smb(cli)) { 493 cli_state_seqnum_remove(cli, mid); 494 return False; 495 } 496 497 show_msg(cli->inbuf); 498 499 /* sanity check */ 500 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) { 501 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n", 502 CVAL(cli->inbuf,smb_com))); 503 cli_state_seqnum_remove(cli, mid); 504 return(False); 505 } 506 507 /* 508 * An NT RPC pipe call can return ERRDOS, ERRmoredata 509 * to a trans call. This is not an error and should not 510 * be treated as such. 511 */ 512 if (cli_is_dos_error(cli)) { 513 cli_dos_error(cli, &eclass, &ecode); 514 if (!(eclass == ERRDOS && ecode == ERRmoredata)) { 515 goto out; 516 } 517 } 518 519 /* 520 * Likewise for NT_STATUS_BUFFER_TOO_SMALL 521 */ 522 if (cli_is_nt_error(cli)) { 523 if (!NT_STATUS_EQUAL(cli_nt_error(cli), 524 NT_STATUS_BUFFER_TOO_SMALL)) { 525 goto out; 526 } 527 } 528 529 /* parse out the lengths */ 530 total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount); 531 total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount); 532 /* Only allow 16 megs. */ 533 if (total_param > 16*1024*1024) { 534 DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n", 535 total_param)); 536 goto out; 537 } 538 if (total_data > 16*1024*1024) { 539 DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n", 540 total_data)); 541 goto out; 542 } 543 544 /* allocate it */ 545 if (total_data) { 546 /* We know adding 2 is safe as total_data is less 547 * than 16mb (above). */ 548 *data = (char *)SMB_REALLOC(*data,total_data+2); 549 if (!(*data)) { 550 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data)); 551 goto out; 552 } 553 } 554 555 if (total_param) { 556 /* We know adding 2 is safe as total_param is less 557 * than 16mb (above). */ 558 *param = (char *)SMB_REALLOC(*param,total_param+2); 559 if (!(*param)) { 560 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param)); 561 goto out; 562 } 563 } 564 565 while (1) { 566 this_data = SVAL(cli->inbuf,smb_ntr_DataCount); 567 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount); 568 569 if (this_data + *data_len > total_data || 570 this_param + *param_len > total_param) { 571 DEBUG(1,("Data overflow in cli_receive_nt_trans\n")); 572 goto out; 573 } 574 575 if (this_data + *data_len < this_data || 576 this_data + *data_len < *data_len || 577 this_param + *param_len < this_param || 578 this_param + *param_len < *param_len) { 579 DEBUG(1,("Data overflow in cli_receive_nt_trans\n")); 580 goto out; 581 } 582 583 if (this_data) { 584 unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement); 585 unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset); 586 587 if (data_offset_out > total_data || 588 data_offset_out + this_data > total_data || 589 data_offset_out + this_data < data_offset_out || 590 data_offset_out + this_data < this_data) { 591 DEBUG(1,("Data overflow in cli_receive_nt_trans\n")); 592 goto out; 593 } 594 if (data_offset_in > cli->bufsize || 595 data_offset_in + this_data > cli->bufsize || 596 data_offset_in + this_data < data_offset_in || 597 data_offset_in + this_data < this_data) { 598 DEBUG(1,("Data overflow in cli_receive_nt_trans\n")); 599 goto out; 600 } 601 602 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data); 603 } 604 605 if (this_param) { 606 unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement); 607 unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset); 608 609 if (param_offset_out > total_param || 610 param_offset_out + this_param > total_param || 611 param_offset_out + this_param < param_offset_out || 612 param_offset_out + this_param < this_param) { 613 DEBUG(1,("Param overflow in cli_receive_nt_trans\n")); 614 goto out; 615 } 616 if (param_offset_in > cli->bufsize || 617 param_offset_in + this_param > cli->bufsize || 618 param_offset_in + this_param < param_offset_in || 619 param_offset_in + this_param < this_param) { 620 DEBUG(1,("Param overflow in cli_receive_nt_trans\n")); 621 goto out; 622 } 623 624 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param); 625 } 626 627 *data_len += this_data; 628 *param_len += this_param; 629 630 if (total_data <= *data_len && total_param <= *param_len) { 631 ret = True; 632 break; 633 } 634 635 if (!cli_receive_smb(cli)) { 636 goto out; 637 } 638 639 show_msg(cli->inbuf); 640 641 /* sanity check */ 642 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) { 643 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n", 644 CVAL(cli->inbuf,smb_com))); 645 goto out; 646 } 647 if (cli_is_dos_error(cli)) { 648 cli_dos_error(cli, &eclass, &ecode); 649 if(!(eclass == ERRDOS && ecode == ERRmoredata)) { 650 goto out; 651 } 652 } 653 /* 654 * Likewise for NT_STATUS_BUFFER_TOO_SMALL 655 */ 656 if (cli_is_nt_error(cli)) { 657 if (!NT_STATUS_EQUAL(cli_nt_error(cli), 658 NT_STATUS_BUFFER_TOO_SMALL)) { 659 goto out; 660 } 661 } 662 663 /* parse out the total lengths again - they can shrink! */ 664 if (IVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data) 665 total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount); 666 if (IVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param) 667 total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount); 668 669 if (total_data <= *data_len && total_param <= *param_len) { 670 ret = True; 671 break; 672 } 673 } 674 675 out: 676 677 cli_state_seqnum_remove(cli, mid); 678 679 if (ret) { 680 /* Ensure the last 2 bytes of param and data are 2 null 681 * bytes. These are malloc'ed, but not included in any 682 * length counts. This allows cli_XX string reading functions 683 * to safely null terminate. */ 684 if (total_data) { 685 SSVAL(*data,total_data,0); 686 } 687 if (total_param) { 688 SSVAL(*param,total_param,0); 689 } 690 } 691 692 return ret; 693 } 21 #include "libsmb/libsmb.h" 22 #include "../lib/util/tevent_ntstatus.h" 23 #include "async_smb.h" 694 24 695 25 struct trans_recvblob { … … 703 33 uint8_t cmd; 704 34 uint16_t mid; 705 uint32_t seqnum;706 35 const char *pipe_name; 707 36 uint8_t *pipe_name_conv; … … 721 50 struct trans_recvblob rparam; 722 51 struct trans_recvblob rdata; 723 724 TALLOC_CTX *secondary_request_ctx; 725 726 struct iovec iov[4]; 52 uint16_t recv_flags2; 53 54 struct iovec iov[6]; 727 55 uint8_t pad[4]; 56 uint8_t zero_pad[4]; 728 57 uint16_t vwv[32]; 58 59 struct tevent_req *primary_subreq; 729 60 }; 61 62 static void cli_trans_cleanup_primary(struct cli_trans_state *state) 63 { 64 if (state->primary_subreq) { 65 cli_smb_req_set_mid(state->primary_subreq, 0); 66 cli_smb_req_unset_pending(state->primary_subreq); 67 TALLOC_FREE(state->primary_subreq); 68 } 69 } 70 71 static int cli_trans_state_destructor(struct cli_trans_state *state) 72 { 73 cli_trans_cleanup_primary(state); 74 return 0; 75 } 730 76 731 77 static NTSTATUS cli_pull_trans(uint8_t *inbuf, … … 843 189 uint8_t *pad = state->pad; 844 190 uint16_t *vwv = state->vwv; 845 uint16_t param_offset; 846 uint16_t this_param = 0; 847 uint16_t this_data = 0; 191 uint32_t param_offset; 192 uint32_t this_param = 0; 193 uint32_t param_pad; 194 uint32_t data_offset; 195 uint32_t this_data = 0; 196 uint32_t data_pad; 848 197 uint32_t useable_space; 849 198 uint8_t cmd; … … 893 242 } 894 243 895 useable_space = state->cli->max_xmit - smb_size - sizeof(uint16_t)*wct; 244 param_offset += wct * sizeof(uint16_t); 245 useable_space = state->cli->max_xmit - param_offset; 246 247 param_pad = param_offset % 4; 248 if (param_pad > 0) { 249 param_pad = MIN(param_pad, useable_space); 250 iov[0].iov_base = (void *)state->zero_pad; 251 iov[0].iov_len = param_pad; 252 iov += 1; 253 param_offset += param_pad; 254 } 255 useable_space = state->cli->max_xmit - param_offset; 896 256 897 257 if (state->param_sent < state->num_param) { … … 903 263 } 904 264 265 data_offset = param_offset + this_param; 266 useable_space = state->cli->max_xmit - data_offset; 267 268 data_pad = data_offset % 4; 269 if (data_pad > 0) { 270 data_pad = MIN(data_pad, useable_space); 271 iov[0].iov_base = (void *)state->zero_pad; 272 iov[0].iov_len = data_pad; 273 iov += 1; 274 data_offset += data_pad; 275 } 276 useable_space = state->cli->max_xmit - data_offset; 277 905 278 if (state->data_sent < state->num_data) { 906 279 this_data = MIN(state->num_data - state->data_sent, 907 useable_space - this_param);280 useable_space); 908 281 iov[0].iov_base = (void *)(state->data + state->data_sent); 909 282 iov[0].iov_len = this_data; … … 911 284 } 912 285 913 param_offset += wct * sizeof(uint16_t);914 915 286 DEBUG(10, ("num_setup=%u, max_setup=%u, " 916 287 "param_total=%u, this_param=%u, max_param=%u, " 917 288 "data_total=%u, this_data=%u, max_data=%u, " 918 "param_offset=%u, param_disp=%u, data_disp=%u\n", 289 "param_offset=%u, param_pad=%u, param_disp=%u, " 290 "data_offset=%u, data_pad=%u, data_disp=%u\n", 919 291 (unsigned)state->num_setup, (unsigned)state->max_setup, 920 292 (unsigned)state->num_param, (unsigned)this_param, … … 922 294 (unsigned)state->num_data, (unsigned)this_data, 923 295 (unsigned)state->rdata.max, 924 (unsigned)param_offset, 925 (unsigned)state->param_sent, (unsigned)state->data_sent)); 296 (unsigned)param_offset, (unsigned)param_pad, 297 (unsigned)state->param_sent, 298 (unsigned)data_offset, (unsigned)data_pad, 299 (unsigned)state->data_sent)); 926 300 927 301 switch (cmd) { … … 940 314 SSVAL(vwv +10, 0, param_offset); 941 315 SSVAL(vwv +11, 0, this_data); 942 SSVAL(vwv +12, 0, param_offset + this_param);316 SSVAL(vwv +12, 0, data_offset); 943 317 SCVAL(vwv +13, 0, state->num_setup); 944 318 SCVAL(vwv +13, 1, 0); /* reserved */ … … 954 328 SSVAL(vwv + 4, 0, state->param_sent); 955 329 SSVAL(vwv + 5, 0, this_data); 956 SSVAL(vwv + 6, 0, param_offset + this_param);330 SSVAL(vwv + 6, 0, data_offset); 957 331 SSVAL(vwv + 7, 0, state->data_sent); 958 332 if (cmd == SMBtranss2) { … … 961 335 break; 962 336 case SMBnttrans: 963 SCVAL(vwv ,0, state->max_setup);964 SSVAL(vwv ,1, 0); /* reserved */965 SIVAL(vwv , 3, state->num_param);966 SIVAL(vwv , 7, state->num_data);967 SIVAL(vwv , 11, state->rparam.max);968 SIVAL(vwv , 15, state->rdata.max);969 SIVAL(vwv , 19, this_param);970 SIVAL(vwv , 23, param_offset);971 SIVAL(vwv , 27, this_data);972 SIVAL(vwv , 31, param_offset + this_param);973 SCVAL(vwv , 35, state->num_setup);974 SSVAL(vwv , 36, state->function);337 SCVAL(vwv + 0, 0, state->max_setup); 338 SSVAL(vwv + 0, 1, 0); /* reserved */ 339 SIVAL(vwv + 1, 1, state->num_param); 340 SIVAL(vwv + 3, 1, state->num_data); 341 SIVAL(vwv + 5, 1, state->rparam.max); 342 SIVAL(vwv + 7, 1, state->rdata.max); 343 SIVAL(vwv + 9, 1, this_param); 344 SIVAL(vwv +11, 1, param_offset); 345 SIVAL(vwv +13, 1, this_data); 346 SIVAL(vwv +15, 1, data_offset); 347 SCVAL(vwv +17, 1, state->num_setup); 348 SSVAL(vwv +18, 0, state->function); 975 349 memcpy(vwv + 19, state->setup, 976 350 sizeof(uint16_t) * state->num_setup); 977 351 break; 978 352 case SMBnttranss: 979 SSVAL(vwv ,0, 0); /* reserved */980 SCVAL(vwv , 2, 0); /* reserved */981 SIVAL(vwv , 3, state->num_param);982 SIVAL(vwv , 7, state->num_data);983 SIVAL(vwv , 11, this_param);984 SIVAL(vwv , 15, param_offset);985 SIVAL(vwv , 19, state->param_sent);986 SIVAL(vwv , 23, this_data);987 SIVAL(vwv , 27, param_offset + this_param);988 SIVAL(vwv , 31, state->data_sent);989 SCVAL(vwv , 35, 0); /* reserved */353 SSVAL(vwv + 0, 0, 0); /* reserved */ 354 SCVAL(vwv + 1, 0, 0); /* reserved */ 355 SIVAL(vwv + 1, 1, state->num_param); 356 SIVAL(vwv + 3, 1, state->num_data); 357 SIVAL(vwv + 5, 1, this_param); 358 SIVAL(vwv + 7, 1, param_offset); 359 SIVAL(vwv + 9, 1, state->param_sent); 360 SIVAL(vwv +11, 1, this_data); 361 SIVAL(vwv +13, 1, data_offset); 362 SIVAL(vwv +15, 1, state->data_sent); 363 SCVAL(vwv +17, 1, 0); /* reserved */ 990 364 break; 991 365 } … … 1084 458 return tevent_req_post(req, ev); 1085 459 } 1086 state->mid = cli_smb_req_mid(subreq);1087 460 status = cli_smb_req_send(subreq); 1088 461 if (!NT_STATUS_IS_OK(status)) { … … 1090 463 return tevent_req_post(req, state->ev); 1091 464 } 1092 cli_state_seqnum_persistent(cli, state->mid);1093 465 tevent_req_set_callback(subreq, cli_trans_done, req); 466 467 /* 468 * Now get the MID of the primary request 469 * and mark it as persistent. This means 470 * we will able to send and receive multiple 471 * SMB pdus using this MID in both directions 472 * (including correct SMB signing). 473 */ 474 state->mid = cli_smb_req_mid(subreq); 475 cli_smb_req_set_mid(subreq, state->mid); 476 state->primary_subreq = subreq; 477 talloc_set_destructor(state, cli_trans_state_destructor); 478 1094 479 return req; 1095 480 } 481 482 static void cli_trans_done2(struct tevent_req *subreq); 1096 483 1097 484 static void cli_trans_done(struct tevent_req *subreq) … … 1107 494 uint32_t num_bytes; 1108 495 uint8_t *bytes; 496 uint8_t *inbuf; 1109 497 uint8_t num_setup = 0; 1110 498 uint16_t *setup = NULL; … … 1118 506 uint8_t *data = NULL; 1119 507 1120 status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes); 508 status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv, 509 &num_bytes, &bytes); 510 /* 511 * Do not TALLOC_FREE(subreq) here, we might receive more than 512 * one response for the same mid. 513 */ 1121 514 1122 515 /* … … 1133 526 1134 527 status = cli_pull_trans( 1135 cli_smb_inbuf(subreq), wct, vwv, num_bytes, bytes,528 inbuf, wct, vwv, num_bytes, bytes, 1136 529 state->cmd, !sent_all, &num_setup, &setup, 1137 530 &total_param, &num_param, ¶m_disp, ¶m, … … 1144 537 if (!sent_all) { 1145 538 int iov_count; 1146 1147 TALLOC_FREE(subreq); 539 struct tevent_req *subreq2; 1148 540 1149 541 cli_trans_format(state, &wct, &iov_count); 1150 542 1151 subreq = cli_smb_req_create(state, state->ev, state->cli,1152 state->cmd + 1, 0, wct, state->vwv,1153 iov_count, state->iov);1154 if (tevent_req_nomem(subreq , req)) {543 subreq2 = cli_smb_req_create(state, state->ev, state->cli, 544 state->cmd + 1, 0, wct, state->vwv, 545 iov_count, state->iov); 546 if (tevent_req_nomem(subreq2, req)) { 1155 547 return; 1156 548 } 1157 cli_smb_req_set_mid(subreq , state->mid);1158 1159 status = cli_smb_req_send(subreq );549 cli_smb_req_set_mid(subreq2, state->mid); 550 551 status = cli_smb_req_send(subreq2); 1160 552 1161 553 if (!NT_STATUS_IS_OK(status)) { 1162 554 goto fail; 1163 555 } 1164 tevent_req_set_callback(subreq, cli_trans_done, req); 556 tevent_req_set_callback(subreq2, cli_trans_done2, req); 557 1165 558 return; 1166 559 } … … 1186 579 if ((state->rparam.total == state->rparam.received) 1187 580 && (state->rdata.total == state->rdata.received)) { 1188 TALLOC_FREE(subreq);1189 cli_ state_seqnum_remove(state->cli, state->mid);581 state->recv_flags2 = SVAL(inbuf, smb_flg2); 582 cli_trans_cleanup_primary(state); 1190 583 tevent_req_done(req); 1191 584 return; 1192 585 } 1193 586 1194 if (!cli_smb_req_set_pending(subreq)) { 1195 status = NT_STATUS_NO_MEMORY; 1196 goto fail; 1197 } 587 TALLOC_FREE(inbuf); 588 1198 589 return; 1199 590 1200 591 fail: 1201 cli_state_seqnum_remove(state->cli, state->mid); 1202 TALLOC_FREE(subreq); 592 cli_trans_cleanup_primary(state); 1203 593 tevent_req_nterror(req, status); 1204 594 } 1205 595 1206 NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 1207 uint16_t **setup, uint8_t *num_setup, 1208 uint8_t **param, uint32_t *num_param, 1209 uint8_t **data, uint32_t *num_data) 1210 { 596 static void cli_trans_done2(struct tevent_req *subreq2) 597 { 598 struct tevent_req *req = tevent_req_callback_data( 599 subreq2, struct tevent_req); 1211 600 struct cli_trans_state *state = tevent_req_data( 1212 601 req, struct cli_trans_state); 1213 602 NTSTATUS status; 603 bool sent_all; 604 uint8_t wct; 605 uint32_t seqnum; 606 607 /* 608 * First backup the seqnum of the secondary request 609 * and attach it to the primary request. 610 */ 611 seqnum = cli_smb_req_seqnum(subreq2); 612 cli_smb_req_set_seqnum(state->primary_subreq, seqnum); 613 614 status = cli_smb_recv(subreq2, state, NULL, 0, &wct, NULL, 615 NULL, NULL); 616 TALLOC_FREE(subreq2); 617 618 if (!NT_STATUS_IS_OK(status)) { 619 goto fail; 620 } 621 622 if (wct != 0) { 623 status = NT_STATUS_INVALID_NETWORK_RESPONSE; 624 goto fail; 625 } 626 627 sent_all = ((state->param_sent == state->num_param) 628 && (state->data_sent == state->num_data)); 629 630 if (!sent_all) { 631 int iov_count; 632 633 cli_trans_format(state, &wct, &iov_count); 634 635 subreq2 = cli_smb_req_create(state, state->ev, state->cli, 636 state->cmd + 1, 0, wct, state->vwv, 637 iov_count, state->iov); 638 if (tevent_req_nomem(subreq2, req)) { 639 return; 640 } 641 cli_smb_req_set_mid(subreq2, state->mid); 642 643 status = cli_smb_req_send(subreq2); 644 645 if (!NT_STATUS_IS_OK(status)) { 646 goto fail; 647 } 648 tevent_req_set_callback(subreq2, cli_trans_done2, req); 649 return; 650 } 651 652 return; 653 654 fail: 655 cli_trans_cleanup_primary(state); 656 tevent_req_nterror(req, status); 657 } 658 659 NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 660 uint16_t *recv_flags2, 661 uint16_t **setup, uint8_t min_setup, 662 uint8_t *num_setup, 663 uint8_t **param, uint32_t min_param, 664 uint32_t *num_param, 665 uint8_t **data, uint32_t min_data, 666 uint32_t *num_data) 667 { 668 struct cli_trans_state *state = tevent_req_data( 669 req, struct cli_trans_state); 670 NTSTATUS status; 671 672 cli_trans_cleanup_primary(state); 1214 673 1215 674 if (tevent_req_is_nterror(req, &status)) { 1216 675 return status; 676 } 677 678 if ((state->num_rsetup < min_setup) 679 || (state->rparam.total < min_param) 680 || (state->rdata.total < min_data)) { 681 return NT_STATUS_INVALID_NETWORK_RESPONSE; 682 } 683 684 if (recv_flags2 != NULL) { 685 *recv_flags2 = state->recv_flags2; 1217 686 } 1218 687 … … 1248 717 uint8_t *param, uint32_t num_param, uint32_t max_param, 1249 718 uint8_t *data, uint32_t num_data, uint32_t max_data, 1250 uint16_t **rsetup, uint8_t *num_rsetup, 1251 uint8_t **rparam, uint32_t *num_rparam, 1252 uint8_t **rdata, uint32_t *num_rdata) 719 uint16_t *recv_flags2, 720 uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup, 721 uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam, 722 uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata) 1253 723 { 1254 724 TALLOC_CTX *frame = talloc_stackframe(); … … 1286 756 } 1287 757 1288 status = cli_trans_recv(req, mem_ctx, rsetup, num_rsetup, 1289 rparam, num_rparam, rdata, num_rdata); 758 status = cli_trans_recv(req, mem_ctx, recv_flags2, 759 rsetup, min_rsetup, num_rsetup, 760 rparam, min_rparam, num_rparam, 761 rdata, min_rdata, num_rdata); 1290 762 fail: 1291 763 TALLOC_FREE(frame);
Note:
See TracChangeset
for help on using the changeset viewer.