root/source3/libsmb/clitrans.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cli_send_trans
  2. cli_receive_trans
  3. cli_send_nt_trans
  4. cli_receive_nt_trans
  5. cli_ship_trans
  6. cli_trans_ship_rest
  7. cli_pull_trans
  8. cli_trans_pull_blob
  9. cli_trans_recv_helper
  10. cli_trans_send
  11. cli_trans_recv
  12. cli_trans

   1 /*
   2    Unix SMB/CIFS implementation.
   3    client transaction calls
   4    Copyright (C) Andrew Tridgell 1994-1998
   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 /****************************************************************************
  24  Send a SMB trans or trans2 request.
  25 ****************************************************************************/
  26 
  27 bool cli_send_trans(struct cli_state *cli, int trans,
     /* [<][>][^][v][top][bottom][index][help] */
  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         /* Note we're in a trans state. Save the sequence
  98          * numbers for replies. */
  99         client_set_trans_sign_state_on(cli, mid);
 100 
 101         if (this_ldata < ldata || this_lparam < lparam) {
 102                 /* receive interim response */
 103                 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
 104                         client_set_trans_sign_state_off(cli, mid);
 105                         return(False);
 106                 }
 107 
 108                 tot_data = this_ldata;
 109                 tot_param = this_lparam;
 110 
 111                 while (tot_data < ldata || tot_param < lparam)  {
 112                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
 113                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
 114 
 115                         cli_set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
 116                         SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
 117 
 118                         outparam = smb_buf(cli->outbuf);
 119                         outdata = outparam+this_lparam;
 120 
 121                         /* secondary request */
 122                         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
 123                         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
 124                         SSVAL(cli->outbuf,smb_spscnt,this_lparam);      /* pscnt */
 125                         SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
 126                         SSVAL(cli->outbuf,smb_spsdisp,tot_param);       /* psdisp */
 127                         SSVAL(cli->outbuf,smb_sdscnt,this_ldata);       /* dscnt */
 128                         SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
 129                         SSVAL(cli->outbuf,smb_sdsdisp,tot_data);        /* dsdisp */
 130                         if (trans==SMBtrans2)
 131                                 SSVALS(cli->outbuf,smb_sfid,fid);               /* fid */
 132                         if (this_lparam)                        /* param[] */
 133                                 memcpy(outparam,param+tot_param,this_lparam);
 134                         if (this_ldata)                 /* data[] */
 135                                 memcpy(outdata,data+tot_data,this_ldata);
 136                         cli_setup_bcc(cli, outdata+this_ldata);
 137 
 138                         show_msg(cli->outbuf);
 139 
 140                         client_set_trans_sign_state_off(cli, mid);
 141                         cli->mid = mid;
 142                         if (!cli_send_smb(cli)) {
 143                                 return False;
 144                         }
 145                         client_set_trans_sign_state_on(cli, mid);
 146 
 147                         tot_data += this_ldata;
 148                         tot_param += this_lparam;
 149                 }
 150         }
 151 
 152         return(True);
 153 }
 154 
 155 /****************************************************************************
 156  Receive a SMB trans or trans2 response allocating the necessary memory.
 157 ****************************************************************************/
 158 
 159 bool cli_receive_trans(struct cli_state *cli,int trans,
     /* [<][>][^][v][top][bottom][index][help] */
 160                               char **param, unsigned int *param_len,
 161                               char **data, unsigned int *data_len)
 162 {
 163         unsigned int total_data=0;
 164         unsigned int total_param=0;
 165         unsigned int this_data,this_param;
 166         NTSTATUS status;
 167         bool ret = False;
 168 
 169         *data_len = *param_len = 0;
 170 
 171         if (!cli_receive_smb(cli)) {
 172                 return False;
 173         }
 174 
 175         show_msg(cli->inbuf);
 176 
 177         /* sanity check */
 178         if (CVAL(cli->inbuf,smb_com) != trans) {
 179                 DEBUG(0,("Expected %s response, got command 0x%02x\n",
 180                          trans==SMBtrans?"SMBtrans":"SMBtrans2",
 181                          CVAL(cli->inbuf,smb_com)));
 182                 return False;
 183         }
 184 
 185         /*
 186          * An NT RPC pipe call can return ERRDOS, ERRmoredata
 187          * to a trans call. This is not an error and should not
 188          * be treated as such. Note that STATUS_NO_MORE_FILES is
 189          * returned when a trans2 findfirst/next finishes.
 190          * When setting up an encrypted transport we can also
 191          * see NT_STATUS_MORE_PROCESSING_REQUIRED here.
 192          *
 193          * Vista returns NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT if the folder
 194          * "<share>/Users/All Users" is enumerated.  This is a special pseudo
 195          * folder, and the response does not have parameters (nor a parameter
 196          * length).
 197          */
 198         status = cli_nt_error(cli);
 199 
 200         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 201                 if (NT_STATUS_IS_ERR(status) ||
 202                     NT_STATUS_EQUAL(status,STATUS_NO_MORE_FILES) ||
 203                     NT_STATUS_EQUAL(status,NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
 204                         goto out;
 205                 }
 206         }
 207 
 208         /* parse out the lengths */
 209         total_data = SVAL(cli->inbuf,smb_tdrcnt);
 210         total_param = SVAL(cli->inbuf,smb_tprcnt);
 211 
 212         /* allocate it */
 213         if (total_data!=0) {
 214                 /* We know adding 2 is safe as total_data is an
 215                  * SVAL <= 0xFFFF. */
 216                 *data = (char *)SMB_REALLOC(*data,total_data+2);
 217                 if (!(*data)) {
 218                         DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
 219                         goto out;
 220                 }
 221         }
 222 
 223         if (total_param!=0) {
 224                 /* We know adding 2 is safe as total_param is an
 225                  * SVAL <= 0xFFFF. */
 226                 *param = (char *)SMB_REALLOC(*param,total_param+2);
 227                 if (!(*param)) {
 228                         DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
 229                         goto out;
 230                 }
 231         }
 232 
 233         for (;;)  {
 234                 this_data = SVAL(cli->inbuf,smb_drcnt);
 235                 this_param = SVAL(cli->inbuf,smb_prcnt);
 236 
 237                 if (this_data + *data_len > total_data ||
 238                     this_param + *param_len > total_param) {
 239                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
 240                         goto out;
 241                 }
 242 
 243                 if (this_data + *data_len < this_data ||
 244                                 this_data + *data_len < *data_len ||
 245                                 this_param + *param_len < this_param ||
 246                                 this_param + *param_len < *param_len) {
 247                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
 248                         goto out;
 249                 }
 250 
 251                 if (this_data) {
 252                         unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
 253                         unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
 254 
 255                         if (data_offset_out > total_data ||
 256                                         data_offset_out + this_data > total_data ||
 257                                         data_offset_out + this_data < data_offset_out ||
 258                                         data_offset_out + this_data < this_data) {
 259                                 DEBUG(1,("Data overflow in cli_receive_trans\n"));
 260                                 goto out;
 261                         }
 262                         if (data_offset_in > cli->bufsize ||
 263                                         data_offset_in + this_data >  cli->bufsize ||
 264                                         data_offset_in + this_data < data_offset_in ||
 265                                         data_offset_in + this_data < this_data) {
 266                                 DEBUG(1,("Data overflow in cli_receive_trans\n"));
 267                                 goto out;
 268                         }
 269 
 270                         memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
 271                 }
 272                 if (this_param) {
 273                         unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
 274                         unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
 275 
 276                         if (param_offset_out > total_param ||
 277                                         param_offset_out + this_param > total_param ||
 278                                         param_offset_out + this_param < param_offset_out ||
 279                                         param_offset_out + this_param < this_param) {
 280                                 DEBUG(1,("Param overflow in cli_receive_trans\n"));
 281                                 goto out;
 282                         }
 283                         if (param_offset_in > cli->bufsize ||
 284                                         param_offset_in + this_param >  cli->bufsize ||
 285                                         param_offset_in + this_param < param_offset_in ||
 286                                         param_offset_in + this_param < this_param) {
 287                                 DEBUG(1,("Param overflow in cli_receive_trans\n"));
 288                                 goto out;
 289                         }
 290 
 291                         memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
 292                 }
 293                 *data_len += this_data;
 294                 *param_len += this_param;
 295 
 296                 if (total_data <= *data_len && total_param <= *param_len) {
 297                         ret = True;
 298                         break;
 299                 }
 300 
 301                 if (!cli_receive_smb(cli)) {
 302                         goto out;
 303                 }
 304 
 305                 show_msg(cli->inbuf);
 306 
 307                 /* sanity check */
 308                 if (CVAL(cli->inbuf,smb_com) != trans) {
 309                         DEBUG(0,("Expected %s response, got command 0x%02x\n",
 310                                  trans==SMBtrans?"SMBtrans":"SMBtrans2", 
 311                                  CVAL(cli->inbuf,smb_com)));
 312                         goto out;
 313                 }
 314                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 315                         if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
 316                                 goto out;
 317                         }
 318                 }
 319 
 320                 /* parse out the total lengths again - they can shrink! */
 321                 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
 322                         total_data = SVAL(cli->inbuf,smb_tdrcnt);
 323                 if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
 324                         total_param = SVAL(cli->inbuf,smb_tprcnt);
 325 
 326                 if (total_data <= *data_len && total_param <= *param_len) {
 327                         ret = True;
 328                         break;
 329                 }
 330         }
 331 
 332   out:
 333 
 334         if (ret) {
 335                 /* Ensure the last 2 bytes of param and data are 2 null
 336                  * bytes. These are malloc'ed, but not included in any
 337                  * length counts. This allows cli_XX string reading functions
 338                  * to safely null terminate. */
 339                 if (total_data) {
 340                         SSVAL(*data,total_data,0);
 341                 }
 342                 if (total_param) {
 343                         SSVAL(*param,total_param,0);
 344                 }
 345         }
 346 
 347         client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
 348         return ret;
 349 }
 350 
 351 /****************************************************************************
 352  Send a SMB nttrans request.
 353 ****************************************************************************/
 354 
 355 bool cli_send_nt_trans(struct cli_state *cli,
     /* [<][>][^][v][top][bottom][index][help] */
 356                        int function,
 357                        int flags,
 358                        uint16 *setup, unsigned int lsetup, unsigned int msetup,
 359                        char *param, unsigned int lparam, unsigned int mparam,
 360                        char *data, unsigned int ldata, unsigned int mdata)
 361 {
 362         unsigned int i;
 363         unsigned int this_ldata,this_lparam;
 364         unsigned int tot_data=0,tot_param=0;
 365         uint16 mid;
 366         char *outdata,*outparam;
 367 
 368         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
 369         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
 370 
 371         memset(cli->outbuf,'\0',smb_size);
 372         cli_set_message(cli->outbuf,19+lsetup,0,True);
 373         SCVAL(cli->outbuf,smb_com,SMBnttrans);
 374         SSVAL(cli->outbuf,smb_tid, cli->cnum);
 375         cli_setup_packet(cli);
 376 
 377         /*
 378          * Save the mid we're using. We need this for finding
 379          * signing replies.
 380          */
 381 
 382         mid = cli->mid;
 383 
 384         outparam = smb_buf(cli->outbuf)+3;
 385         outdata = outparam+this_lparam;
 386 
 387         /* primary request */
 388         SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
 389         SCVAL(cli->outbuf,smb_nt_Flags,flags);
 390         SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
 391         SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
 392         SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
 393         SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
 394         SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
 395         SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
 396         SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
 397         SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
 398         SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
 399         SIVAL(cli->outbuf,smb_nt_Function, function);
 400         for (i=0;i<lsetup;i++)          /* setup[] */
 401                 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
 402 
 403         if (this_lparam)                        /* param[] */
 404                 memcpy(outparam,param,this_lparam);
 405         if (this_ldata)                 /* data[] */
 406                 memcpy(outdata,data,this_ldata);
 407 
 408         cli_setup_bcc(cli, outdata+this_ldata);
 409 
 410         show_msg(cli->outbuf);
 411         if (!cli_send_smb(cli)) {
 412                 return False;
 413         }
 414 
 415         /* Note we're in a trans state. Save the sequence
 416          * numbers for replies. */
 417         client_set_trans_sign_state_on(cli, mid);
 418 
 419         if (this_ldata < ldata || this_lparam < lparam) {
 420                 /* receive interim response */
 421                 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
 422                         client_set_trans_sign_state_off(cli, mid);
 423                         return(False);
 424                 }
 425 
 426                 tot_data = this_ldata;
 427                 tot_param = this_lparam;
 428 
 429                 while (tot_data < ldata || tot_param < lparam)  {
 430                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
 431                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
 432 
 433                         cli_set_message(cli->outbuf,18,0,True);
 434                         SCVAL(cli->outbuf,smb_com,SMBnttranss);
 435 
 436                         /* XXX - these should probably be aligned */
 437                         outparam = smb_buf(cli->outbuf);
 438                         outdata = outparam+this_lparam;
 439 
 440                         /* secondary request */
 441                         SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
 442                         SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
 443                         SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
 444                         SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
 445                         SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
 446                         SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
 447                         SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
 448                         SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
 449                         if (this_lparam)                        /* param[] */
 450                                 memcpy(outparam,param+tot_param,this_lparam);
 451                         if (this_ldata)                 /* data[] */
 452                                 memcpy(outdata,data+tot_data,this_ldata);
 453                         cli_setup_bcc(cli, outdata+this_ldata);
 454 
 455                         show_msg(cli->outbuf);
 456 
 457                         client_set_trans_sign_state_off(cli, mid);
 458                         cli->mid = mid;
 459                         if (!cli_send_smb(cli)) {
 460                                 return False;
 461                         }
 462                         client_set_trans_sign_state_on(cli, mid);
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 487         *data_len = *param_len = 0;
 488 
 489         if (!cli_receive_smb(cli)) {
 490                 return False;
 491         }
 492 
 493         show_msg(cli->inbuf);
 494 
 495         /* sanity check */
 496         if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
 497                 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
 498                          CVAL(cli->inbuf,smb_com)));
 499                 return(False);
 500         }
 501 
 502         /*
 503          * An NT RPC pipe call can return ERRDOS, ERRmoredata
 504          * to a trans call. This is not an error and should not
 505          * be treated as such.
 506          */
 507         if (cli_is_dos_error(cli)) {
 508                 cli_dos_error(cli, &eclass, &ecode);
 509                 if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
 510                         goto out;
 511                 }
 512         }
 513 
 514         /*
 515          * Likewise for NT_STATUS_BUFFER_TOO_SMALL
 516          */
 517         if (cli_is_nt_error(cli)) {
 518                 if (!NT_STATUS_EQUAL(cli_nt_error(cli),
 519                                      NT_STATUS_BUFFER_TOO_SMALL)) {
 520                         goto out;
 521                 }
 522         }
 523 
 524         /* parse out the lengths */
 525         total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
 526         total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
 527         /* Only allow 16 megs. */
 528         if (total_param > 16*1024*1024) {
 529                 DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n",
 530                                         total_param));
 531                 goto out;
 532         }
 533         if (total_data > 16*1024*1024) {
 534                 DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n",
 535                                         total_data));
 536                 goto out;
 537         }
 538 
 539         /* allocate it */
 540         if (total_data) {
 541                 /* We know adding 2 is safe as total_data is less
 542                  * than 16mb (above). */
 543                 *data = (char *)SMB_REALLOC(*data,total_data+2);
 544                 if (!(*data)) {
 545                         DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
 546                         goto out;
 547                 }
 548         }
 549 
 550         if (total_param) {
 551                 /* We know adding 2 is safe as total_param is less
 552                  * than 16mb (above). */
 553                 *param = (char *)SMB_REALLOC(*param,total_param+2);
 554                 if (!(*param)) {
 555                         DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
 556                         goto out;
 557                 }
 558         }
 559 
 560         while (1)  {
 561                 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
 562                 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
 563 
 564                 if (this_data + *data_len > total_data ||
 565                     this_param + *param_len > total_param) {
 566                         DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
 567                         goto out;
 568                 }
 569 
 570                 if (this_data + *data_len < this_data ||
 571                                 this_data + *data_len < *data_len ||
 572                                 this_param + *param_len < this_param ||
 573                                 this_param + *param_len < *param_len) {
 574                         DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
 575                         goto out;
 576                 }
 577 
 578                 if (this_data) {
 579                         unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
 580                         unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
 581 
 582                         if (data_offset_out > total_data ||
 583                                         data_offset_out + this_data > total_data ||
 584                                         data_offset_out + this_data < data_offset_out ||
 585                                         data_offset_out + this_data < this_data) {
 586                                 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
 587                                 goto out;
 588                         }
 589                         if (data_offset_in > cli->bufsize ||
 590                                         data_offset_in + this_data >  cli->bufsize ||
 591                                         data_offset_in + this_data < data_offset_in ||
 592                                         data_offset_in + this_data < this_data) {
 593                                 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
 594                                 goto out;
 595                         }
 596 
 597                         memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
 598                 }
 599 
 600                 if (this_param) {
 601                         unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
 602                         unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
 603 
 604                         if (param_offset_out > total_param ||
 605                                         param_offset_out + this_param > total_param ||
 606                                         param_offset_out + this_param < param_offset_out ||
 607                                         param_offset_out + this_param < this_param) {
 608                                 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
 609                                 goto out;
 610                         }
 611                         if (param_offset_in > cli->bufsize ||
 612                                         param_offset_in + this_param >  cli->bufsize ||
 613                                         param_offset_in + this_param < param_offset_in ||
 614                                         param_offset_in + this_param < this_param) {
 615                                 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
 616                                 goto out;
 617                         }
 618 
 619                         memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
 620                 }
 621 
 622                 *data_len += this_data;
 623                 *param_len += this_param;
 624 
 625                 if (total_data <= *data_len && total_param <= *param_len) {
 626                         ret = True;
 627                         break;
 628                 }
 629 
 630                 if (!cli_receive_smb(cli)) {
 631                         goto out;
 632                 }
 633 
 634                 show_msg(cli->inbuf);
 635 
 636                 /* sanity check */
 637                 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
 638                         DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
 639                                  CVAL(cli->inbuf,smb_com)));
 640                         goto out;
 641                 }
 642                 if (cli_is_dos_error(cli)) {
 643                         cli_dos_error(cli, &eclass, &ecode);
 644                         if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
 645                                 goto out;
 646                         }
 647                 }
 648                 /*
 649                  * Likewise for NT_STATUS_BUFFER_TOO_SMALL
 650                  */
 651                 if (cli_is_nt_error(cli)) {
 652                         if (!NT_STATUS_EQUAL(cli_nt_error(cli),
 653                                              NT_STATUS_BUFFER_TOO_SMALL)) {
 654                                 goto out;
 655                         }
 656                 }
 657 
 658                 /* parse out the total lengths again - they can shrink! */
 659                 if (IVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
 660                         total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
 661                 if (IVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
 662                         total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
 663 
 664                 if (total_data <= *data_len && total_param <= *param_len) {
 665                         ret = True;
 666                         break;
 667                 }
 668         }
 669 
 670   out:
 671 
 672         if (ret) {
 673                 /* Ensure the last 2 bytes of param and data are 2 null
 674                  * bytes. These are malloc'ed, but not included in any
 675                  * length counts. This allows cli_XX string reading functions
 676                  * to safely null terminate. */
 677                 if (total_data) {
 678                         SSVAL(*data,total_data,0);
 679                 }
 680                 if (total_param) {
 681                         SSVAL(*param,total_param,0);
 682                 }
 683         }
 684 
 685         client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
 686         return ret;
 687 }
 688 
 689 struct trans_recvblob {
 690         uint8_t *data;
 691         uint32_t max, total, received;
 692 };
 693 
 694 struct cli_trans_state {
 695         struct cli_state *cli;
 696         struct event_context *ev;
 697         uint8_t cmd;
 698         uint16_t mid;
 699         const char *pipe_name;
 700         uint16_t fid;
 701         uint16_t function;
 702         int flags;
 703         uint16_t *setup;
 704         uint8_t num_setup, max_setup;
 705         uint8_t *param;
 706         uint32_t num_param, param_sent;
 707         uint8_t *data;
 708         uint32_t num_data, data_sent;
 709 
 710         uint8_t num_rsetup;
 711         uint16_t *rsetup;
 712         struct trans_recvblob rparam;
 713         struct trans_recvblob rdata;
 714 
 715         TALLOC_CTX *secondary_request_ctx;
 716 };
 717 
 718 static void cli_trans_recv_helper(struct async_req *req);
 719 
 720 static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 721                                         struct cli_trans_state *state)
 722 {
 723         TALLOC_CTX *frame;
 724         struct async_req *result = NULL;
 725         struct cli_request *cli_req;
 726         uint8_t wct;
 727         uint16_t *vwv;
 728         uint8_t *bytes = NULL;
 729         uint16_t param_offset;
 730         uint16_t this_param = 0;
 731         uint16_t this_data = 0;
 732         uint32_t useable_space;
 733         uint8_t cmd;
 734         uint8_t pad[3];
 735 
 736         frame = talloc_stackframe();
 737 
 738         cmd = state->cmd;
 739 
 740         if ((state->param_sent != 0) || (state->data_sent != 0)) {
 741                 /* The secondary commands are one after the primary ones */
 742                 cmd += 1;
 743         }
 744 
 745         param_offset = smb_size - 4;
 746 
 747         bytes = TALLOC_ARRAY(talloc_tos(), uint8_t, 0); /* padding */
 748         if (bytes == NULL) {
 749                 goto fail;
 750         }
 751 
 752         switch (cmd) {
 753         case SMBtrans:
 754                 pad[0] = 0;
 755                 bytes = (uint8_t *)talloc_append_blob(talloc_tos(), bytes,
 756                                                 data_blob_const(pad, 1));
 757                 if (bytes == NULL) {
 758                         goto fail;
 759                 }
 760                 bytes = smb_bytes_push_str(bytes, cli_ucs2(state->cli),
 761                                            state->pipe_name,
 762                                            strlen(state->pipe_name)+1, NULL);
 763                 if (bytes == NULL) {
 764                         goto fail;
 765                 }
 766                 wct = 14 + state->num_setup;
 767                 param_offset += talloc_get_size(bytes);
 768                 break;
 769         case SMBtrans2:
 770                 pad[0] = 0;
 771                 pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
 772                 pad[2] = ' ';
 773                 bytes = (uint8_t *)talloc_append_blob(talloc_tos(), bytes,
 774                                                 data_blob_const(pad, 3));
 775                 if (bytes == NULL) {
 776                         goto fail;
 777                 }
 778                 wct = 14 + state->num_setup;
 779                 param_offset += talloc_get_size(bytes);
 780                 break;
 781         case SMBtranss:
 782                 wct = 8;
 783                 break;
 784         case SMBtranss2:
 785                 wct = 9;
 786                 break;
 787         case SMBnttrans:
 788                 wct = 19 + state->num_setup;
 789                 break;
 790         case SMBnttranss:
 791                 wct = 18;
 792                 break;
 793         default:
 794                 goto fail;
 795         }
 796 
 797         useable_space = state->cli->max_xmit - smb_size - sizeof(uint16_t)*wct;
 798 
 799         if (state->param_sent < state->num_param) {
 800                 this_param = MIN(state->num_param - state->param_sent,
 801                                  useable_space);
 802         }
 803 
 804         if (state->data_sent < state->num_data) {
 805                 this_data = MIN(state->num_data - state->data_sent,
 806                                 useable_space - this_param);
 807         }
 808 
 809         vwv = TALLOC_ARRAY(talloc_tos(), uint16_t, wct);
 810         if (vwv == NULL) {
 811                 goto fail;
 812         }
 813         param_offset += wct * sizeof(uint16_t);
 814 
 815         DEBUG(10, ("num_setup=%u, max_setup=%u, "
 816                    "param_total=%u, this_param=%u, max_param=%u, "
 817                    "data_total=%u, this_data=%u, max_data=%u, "
 818                    "param_offset=%u, param_disp=%u, data_disp=%u\n",
 819                    (unsigned)state->num_setup, (unsigned)state->max_setup,
 820                    (unsigned)state->num_param, (unsigned)this_param,
 821                    (unsigned)state->rparam.max,
 822                    (unsigned)state->num_data, (unsigned)this_data,
 823                    (unsigned)state->rdata.max,
 824                    (unsigned)param_offset,
 825                    (unsigned)state->param_sent, (unsigned)state->data_sent));
 826 
 827         switch (cmd) {
 828         case SMBtrans:
 829         case SMBtrans2:
 830                 SSVAL(vwv + 0, 0, state->num_param);
 831                 SSVAL(vwv + 1, 0, state->num_data);
 832                 SSVAL(vwv + 2, 0, state->rparam.max);
 833                 SSVAL(vwv + 3, 0, state->rdata.max);
 834                 SCVAL(vwv + 4, 0, state->max_setup);
 835                 SCVAL(vwv + 4, 1, 0);   /* reserved */
 836                 SSVAL(vwv + 5, 0, state->flags);
 837                 SIVAL(vwv + 6, 0, 0);   /* timeout */
 838                 SSVAL(vwv + 8, 0, 0);   /* reserved */
 839                 SSVAL(vwv + 9, 0, this_param);
 840                 SSVAL(vwv +10, 0, param_offset);
 841                 SSVAL(vwv +11, 0, this_data);
 842                 SSVAL(vwv +12, 0, param_offset + this_param);
 843                 SCVAL(vwv +13, 0, state->num_setup);
 844                 SCVAL(vwv +13, 1, 0);   /* reserved */
 845                 memcpy(vwv + 14, state->setup,
 846                        sizeof(uint16_t) * state->num_setup);
 847                 break;
 848         case SMBtranss:
 849         case SMBtranss2:
 850                 SSVAL(vwv + 0, 0, state->num_param);
 851                 SSVAL(vwv + 1, 0, state->num_data);
 852                 SSVAL(vwv + 2, 0, this_param);
 853                 SSVAL(vwv + 3, 0, param_offset);
 854                 SSVAL(vwv + 4, 0, state->param_sent);
 855                 SSVAL(vwv + 5, 0, this_data);
 856                 SSVAL(vwv + 6, 0, param_offset + this_param);
 857                 SSVAL(vwv + 7, 0, state->data_sent);
 858                 if (cmd == SMBtranss2) {
 859                         SSVAL(vwv + 8, 0, state->fid);
 860                 }
 861                 break;
 862         case SMBnttrans:
 863                 SCVAL(vwv,  0, state->max_setup);
 864                 SSVAL(vwv,  1, 0); /* reserved */
 865                 SIVAL(vwv,  3, state->num_param);
 866                 SIVAL(vwv,  7, state->num_data);
 867                 SIVAL(vwv, 11, state->rparam.max);
 868                 SIVAL(vwv, 15, state->rdata.max);
 869                 SIVAL(vwv, 19, this_param);
 870                 SIVAL(vwv, 23, param_offset);
 871                 SIVAL(vwv, 27, this_data);
 872                 SIVAL(vwv, 31, param_offset + this_param);
 873                 SCVAL(vwv, 35, state->num_setup);
 874                 SSVAL(vwv, 36, state->function);
 875                 memcpy(vwv + 19, state->setup,
 876                        sizeof(uint16_t) * state->num_setup);
 877                 break;
 878         case SMBnttranss:
 879                 SSVAL(vwv,  0, 0); /* reserved */
 880                 SCVAL(vwv,  2, 0); /* reserved */
 881                 SIVAL(vwv,  3, state->num_param);
 882                 SIVAL(vwv,  7, state->num_data);
 883                 SIVAL(vwv, 11, this_param);
 884                 SIVAL(vwv, 15, param_offset);
 885                 SIVAL(vwv, 19, state->param_sent);
 886                 SIVAL(vwv, 23, this_data);
 887                 SIVAL(vwv, 27, param_offset + this_param);
 888                 SIVAL(vwv, 31, state->data_sent);
 889                 SCVAL(vwv, 35, 0); /* reserved */
 890                 break;
 891         }
 892 
 893         bytes = (uint8_t *)talloc_append_blob(
 894                 talloc_tos(), bytes,
 895                 data_blob_const(state->param + state->param_sent, this_param));
 896         if (bytes == NULL) {
 897                 goto fail;
 898         }
 899         state->param_sent += this_param;
 900 
 901         bytes = (uint8_t *)talloc_append_blob(
 902                 talloc_tos(), bytes,
 903                 data_blob_const(state->data + state->data_sent, this_data));
 904         if (bytes == NULL) {
 905                 goto fail;
 906         }
 907         state->data_sent += this_data;
 908 
 909         if ((cmd == SMBtrans) || (cmd == SMBtrans2) || (cmd == SMBnttrans)) {
 910                 /*
 911                  * Primary request, retrieve our mid
 912                  */
 913                 result = cli_request_send(mem_ctx, state->ev, state->cli,
 914                                           cmd, 0, wct, vwv, 0,
 915                                           talloc_get_size(bytes), bytes);
 916                 if (result == NULL) {
 917                         goto fail;
 918                 }
 919                 cli_req = talloc_get_type_abort(result->private_data,
 920                                                 struct cli_request);
 921                 state->mid = cli_req->mid;
 922         } else {
 923                 uint16_t num_bytes = talloc_get_size(bytes);
 924                 /*
 925                  * Secondary request, we have to fix up the mid. Thus we do
 926                  * the chain_cork/chain/uncork ourselves.
 927                  */
 928                 if (!cli_chain_cork(state->cli, state->ev,
 929                                     wct * sizeof(uint16_t) + num_bytes + 3)) {
 930                         goto fail;
 931                 }
 932                 result = cli_request_send(mem_ctx, state->ev, state->cli, cmd,
 933                                           0, wct, vwv, 0, num_bytes, bytes);
 934                 if (result == NULL) {
 935                         goto fail;
 936                 }
 937                 cli_req = talloc_get_type_abort(result->private_data,
 938                                                 struct cli_request);
 939                 cli_req->recv_helper.fn = cli_trans_recv_helper;
 940                 cli_req->recv_helper.priv = state;
 941                 cli_req->mid = state->mid;
 942                 client_set_trans_sign_state_off(state->cli, state->mid);
 943                 cli_chain_uncork(state->cli);
 944         }
 945 
 946         client_set_trans_sign_state_on(state->cli, state->mid);
 947 
 948  fail:
 949         TALLOC_FREE(frame);
 950         return result;
 951 }
 952 
 953 static void cli_trans_ship_rest(struct async_req *req,
     /* [<][>][^][v][top][bottom][index][help] */
 954                                 struct cli_trans_state *state)
 955 {
 956         state->secondary_request_ctx = talloc_new(state);
 957         if (state->secondary_request_ctx == NULL) {
 958                 async_req_nterror(req, NT_STATUS_NO_MEMORY);
 959                 return;
 960         }
 961 
 962         while ((state->param_sent < state->num_param)
 963                || (state->data_sent < state->num_data)) {
 964                 struct async_req *cli_req;
 965 
 966                 cli_req = cli_ship_trans(state->secondary_request_ctx, state);
 967                 if (cli_req == NULL) {
 968                         async_req_nterror(req, NT_STATUS_NO_MEMORY);
 969                         return;
 970                 }
 971         }
 972 }
 973 
 974 static NTSTATUS cli_pull_trans(struct async_req *req,
     /* [<][>][^][v][top][bottom][index][help] */
 975                                struct cli_request *cli_req,
 976                                uint8_t smb_cmd, bool expect_first_reply,
 977                                uint8_t *pnum_setup, uint16_t **psetup,
 978                                uint32_t *ptotal_param, uint32_t *pnum_param,
 979                                uint32_t *pparam_disp, uint8_t **pparam,
 980                                uint32_t *ptotal_data, uint32_t *pnum_data,
 981                                uint32_t *pdata_disp, uint8_t **pdata)
 982 {
 983         uint32_t param_ofs, data_ofs;
 984         uint8_t wct;
 985         uint16_t *vwv;
 986         uint16_t num_bytes;
 987         uint8_t *bytes;
 988         NTSTATUS status;
 989 
 990         status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
 991 
 992         /*
 993          * We can receive something like STATUS_MORE_ENTRIES, so don't use
 994          * !NT_STATUS_IS_OK(status) here.
 995          */
 996 
 997         if (NT_STATUS_IS_ERR(status)) {
 998                 return status;
 999         }
1000 
1001         if (expect_first_reply) {
1002                 if ((wct != 0) || (num_bytes != 0)) {
1003                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
1004                 }
1005                 return NT_STATUS_OK;
1006         }
1007 
1008         switch (smb_cmd) {
1009         case SMBtrans:
1010         case SMBtrans2:
1011                 if (wct < 10) {
1012                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
1013                 }
1014                 *ptotal_param   = SVAL(vwv + 0, 0);
1015                 *ptotal_data    = SVAL(vwv + 1, 0);
1016                 *pnum_param     = SVAL(vwv + 3, 0);
1017                 param_ofs       = SVAL(vwv + 4, 0);
1018                 *pparam_disp    = SVAL(vwv + 5, 0);
1019                 *pnum_data      = SVAL(vwv + 6, 0);
1020                 data_ofs        = SVAL(vwv + 7, 0);
1021                 *pdata_disp     = SVAL(vwv + 8, 0);
1022                 *pnum_setup     = CVAL(vwv + 9, 0);
1023                 if (wct < 10 + (*pnum_setup)) {
1024                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
1025                 }
1026                 *psetup = vwv + 10;
1027 
1028                 break;
1029         case SMBnttrans:
1030                 if (wct < 18) {
1031                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
1032                 }
1033                 *ptotal_param   = IVAL(vwv, 3);
1034                 *ptotal_data    = IVAL(vwv, 7);
1035                 *pnum_param     = IVAL(vwv, 11);
1036                 param_ofs       = IVAL(vwv, 15);
1037                 *pparam_disp    = IVAL(vwv, 19);
1038                 *pnum_data      = IVAL(vwv, 23);
1039                 data_ofs        = IVAL(vwv, 27);
1040                 *pdata_disp     = IVAL(vwv, 31);
1041                 *pnum_setup     = CVAL(vwv, 35);
1042                 *psetup         = vwv + 18;
1043                 break;
1044 
1045         default:
1046                 return NT_STATUS_INTERNAL_ERROR;
1047         }
1048 
1049         /*
1050          * Check for buffer overflows. data_ofs needs to be checked against
1051          * the incoming buffer length, data_disp against the total
1052          * length. Likewise for param_ofs/param_disp.
1053          */
1054 
1055         if (trans_oob(smb_len(cli_req->inbuf), param_ofs, *pnum_param)
1056             || trans_oob(*ptotal_param, *pparam_disp, *pnum_param)
1057             || trans_oob(smb_len(cli_req->inbuf), data_ofs, *pnum_data)
1058             || trans_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
1059                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1060         }
1061 
1062         *pparam = (uint8_t *)cli_req->inbuf + 4 + param_ofs;
1063         *pdata = (uint8_t *)cli_req->inbuf + 4 + data_ofs;
1064 
1065         return NT_STATUS_OK;
1066 }
1067 
1068 static NTSTATUS cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1069                                     struct trans_recvblob *blob,
1070                                     uint32_t total, uint32_t thistime,
1071                                     uint8_t *buf, uint32_t displacement)
1072 {
1073         if (blob->data == NULL) {
1074                 if (total > blob->max) {
1075                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
1076                 }
1077                 blob->total = total;
1078                 blob->data = TALLOC_ARRAY(mem_ctx, uint8_t, total);
1079                 if (blob->data == NULL) {
1080                         return NT_STATUS_NO_MEMORY;
1081                 }
1082         }
1083 
1084         if (total > blob->total) {
1085                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1086         }
1087 
1088         if (thistime) {
1089                 memcpy(blob->data + displacement, buf, thistime);
1090                 blob->received += thistime;
1091         }
1092 
1093         return NT_STATUS_OK;
1094 }
1095 
1096 static void cli_trans_recv_helper(struct async_req *req)
     /* [<][>][^][v][top][bottom][index][help] */
1097 {
1098         struct cli_request *cli_req = talloc_get_type_abort(
1099                 req->private_data, struct cli_request);
1100         struct cli_trans_state *state = talloc_get_type_abort(
1101                 cli_req->recv_helper.priv, struct cli_trans_state);
1102         uint8_t num_setup       = 0;
1103         uint16_t *setup         = NULL;
1104         uint32_t total_param    = 0;
1105         uint32_t num_param      = 0;
1106         uint32_t param_disp     = 0;
1107         uint32_t total_data     = 0;
1108         uint32_t num_data       = 0;
1109         uint32_t data_disp      = 0;
1110         uint8_t *param          = NULL;
1111         uint8_t *data           = NULL;
1112         bool sent_all;
1113         NTSTATUS status;
1114 
1115         sent_all = (state->param_sent == state->num_param)
1116                 && (state->data_sent == state->num_data);
1117 
1118         status = cli_pull_trans(
1119                 req, cli_req, state->cmd, !sent_all, &num_setup, &setup,
1120                 &total_param, &num_param, &param_disp, &param,
1121                 &total_data, &num_data, &data_disp, &data);
1122 
1123         /*
1124          * We can receive something like STATUS_MORE_ENTRIES, so don't use
1125          * !NT_STATUS_IS_OK(status) here.
1126          */
1127 
1128         if (NT_STATUS_IS_ERR(status)) {
1129                 async_req_nterror(req, status);
1130                 return;
1131         }
1132 
1133         if (!sent_all) {
1134                 cli_trans_ship_rest(req, state);
1135                 return;
1136         }
1137 
1138         /*
1139          * We've just received a real response. This means that we don't need
1140          * the secondary cli_request structures anymore, they have all been
1141          * shipped to the server.
1142          */
1143         TALLOC_FREE(state->secondary_request_ctx);
1144 
1145         if (num_setup != 0) {
1146                 TALLOC_FREE(state->rsetup);
1147                 state->rsetup = (uint16_t *)TALLOC_MEMDUP(
1148                         state, setup, sizeof(uint16_t) * num_setup);
1149                 if (state->rsetup == NULL) {
1150                         async_req_nterror(req, NT_STATUS_NO_MEMORY);
1151                         return;
1152                 }
1153         }
1154 
1155         status = cli_trans_pull_blob(
1156                 state, &state->rparam, total_param, num_param, param,
1157                 param_disp);
1158 
1159         if (!NT_STATUS_IS_OK(status)) {
1160                 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
1161                 async_req_nterror(req, status);
1162                 return;
1163         }
1164 
1165         status = cli_trans_pull_blob(
1166                 state, &state->rdata, total_data, num_data, data,
1167                 data_disp);
1168 
1169         if (!NT_STATUS_IS_OK(status)) {
1170                 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
1171                 async_req_nterror(req, status);
1172                 return;
1173         }
1174 
1175         if ((state->rparam.total == state->rparam.received)
1176             && (state->rdata.total == state->rdata.received)) {
1177                 client_set_trans_sign_state_off(state->cli, state->mid);
1178                 async_req_done(req);
1179         }
1180 }
1181 
1182 struct async_req *cli_trans_send(
     /* [<][>][^][v][top][bottom][index][help] */
1183         TALLOC_CTX *mem_ctx, struct event_context *ev,
1184         struct cli_state *cli, uint8_t trans_cmd,
1185         const char *pipe_name, uint16_t fid, uint16_t function, int flags,
1186         uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
1187         uint8_t *param, uint32_t num_param, uint32_t max_param,
1188         uint8_t *data, uint32_t num_data, uint32_t max_data)
1189 {
1190         struct async_req *req;
1191         struct cli_request *cli_req;
1192         struct cli_trans_state *state;
1193 
1194         /*
1195          * We can't use it in a chained request chain, we'd get the offset
1196          * calculations wrong.
1197          */
1198 
1199         if (cli_in_chain(cli)) {
1200                 return NULL;
1201         }
1202 
1203         if ((trans_cmd == SMBtrans) || (trans_cmd == SMBtrans2)) {
1204                 if ((num_param > 0xffff) || (max_param > 0xffff)
1205                     || (num_data > 0xffff) || (max_data > 0xffff)) {
1206                         DEBUG(3, ("Attempt to send invalid trans2 request "
1207                                   "(setup %u, params %u/%u, data %u/%u)\n",
1208                                   (unsigned)num_setup,
1209                                   (unsigned)num_param, (unsigned)max_param,
1210                                   (unsigned)num_data, (unsigned)max_data));
1211                         return NULL;
1212                 }
1213         }
1214 
1215         state = talloc(mem_ctx, struct cli_trans_state);
1216         if (state == NULL) {
1217                 goto nomem;
1218         }
1219 
1220         state->cli = cli;
1221         state->ev = ev;
1222         state->cmd = trans_cmd;
1223         state->num_rsetup = 0;
1224         state->rsetup = NULL;
1225         ZERO_STRUCT(state->rparam);
1226         ZERO_STRUCT(state->rdata);
1227         state->secondary_request_ctx = NULL;
1228 
1229         if (trans_cmd == SMBtrans) {
1230                 state->pipe_name = talloc_strdup(state, pipe_name);
1231                 if (state->pipe_name == NULL) {
1232                         goto nomem;
1233                 }
1234         }
1235         if (trans_cmd == SMBtrans2) {
1236                 state->fid = fid;
1237         }
1238         if (trans_cmd == SMBnttrans) {
1239                 state->function = function;
1240         }
1241 
1242         state->flags = flags;
1243 
1244         if (setup != NULL) {
1245                 state->setup = (uint16_t *)TALLOC_MEMDUP(
1246                         state, setup, sizeof(*setup) * num_setup);
1247                 if (state->setup == NULL) {
1248                         goto nomem;
1249                 }
1250                 state->num_setup = num_setup;
1251         } else {
1252                 state->setup = NULL;
1253                 state->num_setup = 0;
1254         }
1255 
1256         state->max_setup = max_setup;
1257 
1258         if (param != NULL) {
1259                 state->param = (uint8_t *)TALLOC_MEMDUP(state, param,
1260                                                         num_param);
1261                 if (state->param == NULL) {
1262                         goto nomem;
1263                 }
1264                 state->num_param = num_param;
1265         } else {
1266                 state->param = NULL;
1267                 state->num_param = 0;
1268         }
1269 
1270         state->param_sent = 0;
1271         state->rparam.max = max_param;
1272 
1273         if (data != NULL) {
1274                 state->data = (uint8_t *)TALLOC_MEMDUP(state, data, num_data);
1275                 if (state->data == NULL) {
1276                         goto nomem;
1277                 }
1278                 state->num_data = num_data;
1279         } else {
1280                 state->data = NULL;
1281                 state->num_data = 0;
1282         }
1283 
1284         state->data_sent = 0;
1285         state->rdata.max = max_data;
1286 
1287         req = cli_ship_trans(state, state);
1288         if (req == NULL) {
1289                 goto nomem;
1290         }
1291 
1292         cli_req = talloc_get_type_abort(req->private_data, struct cli_request);
1293         cli_req->recv_helper.fn = cli_trans_recv_helper;
1294         cli_req->recv_helper.priv = state;
1295 
1296         return req;
1297 
1298  nomem:
1299         TALLOC_FREE(state);
1300         return NULL;
1301 }
1302 
1303 NTSTATUS cli_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1304                         uint16_t **setup, uint8_t *num_setup,
1305                         uint8_t **param, uint32_t *num_param,
1306                         uint8_t **data, uint32_t *num_data)
1307 {
1308         struct cli_request *cli_req = talloc_get_type_abort(
1309                 req->private_data, struct cli_request);
1310         struct cli_trans_state *state = talloc_get_type_abort(
1311                 cli_req->recv_helper.priv, struct cli_trans_state);
1312         NTSTATUS status;
1313 
1314         if (async_req_is_nterror(req, &status)) {
1315                 return status;
1316         }
1317 
1318         if (setup != NULL) {
1319                 *setup = talloc_move(mem_ctx, &state->rsetup);
1320                 *num_setup = state->num_rsetup;
1321         } else {
1322                 TALLOC_FREE(state->rsetup);
1323         }
1324 
1325         if (param != NULL) {
1326                 *param = talloc_move(mem_ctx, &state->rparam.data);
1327                 *num_param = state->rparam.total;
1328         } else {
1329                 TALLOC_FREE(state->rparam.data);
1330         }
1331 
1332         if (data != NULL) {
1333                 *data = talloc_move(mem_ctx, &state->rdata.data);
1334                 *num_data = state->rdata.total;
1335         } else {
1336                 TALLOC_FREE(state->rdata.data);
1337         }
1338 
1339         return NT_STATUS_OK;
1340 }
1341 
1342 NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
     /* [<][>][^][v][top][bottom][index][help] */
1343                    uint8_t trans_cmd,
1344                    const char *pipe_name, uint16_t fid, uint16_t function,
1345                    int flags,
1346                    uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
1347                    uint8_t *param, uint32_t num_param, uint32_t max_param,
1348                    uint8_t *data, uint32_t num_data, uint32_t max_data,
1349                    uint16_t **rsetup, uint8_t *num_rsetup,
1350                    uint8_t **rparam, uint32_t *num_rparam,
1351                    uint8_t **rdata, uint32_t *num_rdata)
1352 {
1353         TALLOC_CTX *frame = talloc_stackframe();
1354         struct event_context *ev;
1355         struct async_req *req;
1356         NTSTATUS status = NT_STATUS_NO_MEMORY;
1357 
1358         if (cli->fd_event != NULL) {
1359                 /*
1360                  * Can't use sync call while an async call is in flight
1361                  */
1362                 cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
1363                 goto fail;
1364         }
1365 
1366         ev = event_context_init(frame);
1367         if (ev == NULL) {
1368                 goto fail;
1369         }
1370 
1371         req = cli_trans_send(frame, ev, cli, trans_cmd,
1372                              pipe_name, fid, function, flags,
1373                              setup, num_setup, max_setup,
1374                              param, num_param, max_param,
1375                              data, num_data, max_data);
1376         if (req == NULL) {
1377                 goto fail;
1378         }
1379 
1380         while (req->state < ASYNC_REQ_DONE) {
1381                 event_loop_once(ev);
1382         }
1383 
1384         status = cli_trans_recv(req, mem_ctx, rsetup, num_rsetup,
1385                                 rparam, num_rparam, rdata, num_rdata);
1386  fail:
1387         TALLOC_FREE(frame);
1388         return status;
1389 }

/* [<][>][^][v][top][bottom][index][help] */