Ignore:
Timestamp:
Nov 14, 2012, 12:59:34 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to 3.6.0

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/source3/libsmb/clitrans.c

    r414 r740  
    1919
    2020#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"
    69424
    69525struct trans_recvblob {
     
    70333        uint8_t cmd;
    70434        uint16_t mid;
    705         uint32_t seqnum;
    70635        const char *pipe_name;
    70736        uint8_t *pipe_name_conv;
     
    72150        struct trans_recvblob rparam;
    72251        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];
    72755        uint8_t pad[4];
     56        uint8_t zero_pad[4];
    72857        uint16_t vwv[32];
     58
     59        struct tevent_req *primary_subreq;
    72960};
     61
     62static 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
     71static int cli_trans_state_destructor(struct cli_trans_state *state)
     72{
     73        cli_trans_cleanup_primary(state);
     74        return 0;
     75}
    73076
    73177static NTSTATUS cli_pull_trans(uint8_t *inbuf,
     
    843189        uint8_t *pad = state->pad;
    844190        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;
    848197        uint32_t useable_space;
    849198        uint8_t cmd;
     
    893242        }
    894243
    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;
    896256
    897257        if (state->param_sent < state->num_param) {
     
    903263        }
    904264
     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
    905278        if (state->data_sent < state->num_data) {
    906279                this_data = MIN(state->num_data - state->data_sent,
    907                                 useable_space - this_param);
     280                                useable_space);
    908281                iov[0].iov_base = (void *)(state->data + state->data_sent);
    909282                iov[0].iov_len = this_data;
     
    911284        }
    912285
    913         param_offset += wct * sizeof(uint16_t);
    914 
    915286        DEBUG(10, ("num_setup=%u, max_setup=%u, "
    916287                   "param_total=%u, this_param=%u, max_param=%u, "
    917288                   "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",
    919291                   (unsigned)state->num_setup, (unsigned)state->max_setup,
    920292                   (unsigned)state->num_param, (unsigned)this_param,
     
    922294                   (unsigned)state->num_data, (unsigned)this_data,
    923295                   (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));
    926300
    927301        switch (cmd) {
     
    940314                SSVAL(vwv +10, 0, param_offset);
    941315                SSVAL(vwv +11, 0, this_data);
    942                 SSVAL(vwv +12, 0, param_offset + this_param);
     316                SSVAL(vwv +12, 0, data_offset);
    943317                SCVAL(vwv +13, 0, state->num_setup);
    944318                SCVAL(vwv +13, 1, 0);   /* reserved */
     
    954328                SSVAL(vwv + 4, 0, state->param_sent);
    955329                SSVAL(vwv + 5, 0, this_data);
    956                 SSVAL(vwv + 6, 0, param_offset + this_param);
     330                SSVAL(vwv + 6, 0, data_offset);
    957331                SSVAL(vwv + 7, 0, state->data_sent);
    958332                if (cmd == SMBtranss2) {
     
    961335                break;
    962336        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);
    975349                memcpy(vwv + 19, state->setup,
    976350                       sizeof(uint16_t) * state->num_setup);
    977351                break;
    978352        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 */
    990364                break;
    991365        }
     
    1084458                return tevent_req_post(req, ev);
    1085459        }
    1086         state->mid = cli_smb_req_mid(subreq);
    1087460        status = cli_smb_req_send(subreq);
    1088461        if (!NT_STATUS_IS_OK(status)) {
     
    1090463                return tevent_req_post(req, state->ev);
    1091464        }
    1092         cli_state_seqnum_persistent(cli, state->mid);
    1093465        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
    1094479        return req;
    1095480}
     481
     482static void cli_trans_done2(struct tevent_req *subreq);
    1096483
    1097484static void cli_trans_done(struct tevent_req *subreq)
     
    1107494        uint32_t num_bytes;
    1108495        uint8_t *bytes;
     496        uint8_t *inbuf;
    1109497        uint8_t num_setup       = 0;
    1110498        uint16_t *setup         = NULL;
     
    1118506        uint8_t *data           = NULL;
    1119507
    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         */
    1121514
    1122515        /*
     
    1133526
    1134527        status = cli_pull_trans(
    1135                 cli_smb_inbuf(subreq), wct, vwv, num_bytes, bytes,
     528                inbuf, wct, vwv, num_bytes, bytes,
    1136529                state->cmd, !sent_all, &num_setup, &setup,
    1137530                &total_param, &num_param, &param_disp, &param,
     
    1144537        if (!sent_all) {
    1145538                int iov_count;
    1146 
    1147                 TALLOC_FREE(subreq);
     539                struct tevent_req *subreq2;
    1148540
    1149541                cli_trans_format(state, &wct, &iov_count);
    1150542
    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)) {
    1155547                        return;
    1156548                }
    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);
    1160552
    1161553                if (!NT_STATUS_IS_OK(status)) {
    1162554                        goto fail;
    1163555                }
    1164                 tevent_req_set_callback(subreq, cli_trans_done, req);
     556                tevent_req_set_callback(subreq2, cli_trans_done2, req);
     557
    1165558                return;
    1166559        }
     
    1186579        if ((state->rparam.total == state->rparam.received)
    1187580            && (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);
    1190583                tevent_req_done(req);
    1191584                return;
    1192585        }
    1193586
    1194         if (!cli_smb_req_set_pending(subreq)) {
    1195                 status = NT_STATUS_NO_MEMORY;
    1196                 goto fail;
    1197         }
     587        TALLOC_FREE(inbuf);
     588
    1198589        return;
    1199590
    1200591 fail:
    1201         cli_state_seqnum_remove(state->cli, state->mid);
    1202         TALLOC_FREE(subreq);
     592        cli_trans_cleanup_primary(state);
    1203593        tevent_req_nterror(req, status);
    1204594}
    1205595
    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 {
     596static void cli_trans_done2(struct tevent_req *subreq2)
     597{
     598        struct tevent_req *req = tevent_req_callback_data(
     599                subreq2, struct tevent_req);
    1211600        struct cli_trans_state *state = tevent_req_data(
    1212601                req, struct cli_trans_state);
    1213602        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
     659NTSTATUS 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);
    1214673
    1215674        if (tevent_req_is_nterror(req, &status)) {
    1216675                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;
    1217686        }
    1218687
     
    1248717                   uint8_t *param, uint32_t num_param, uint32_t max_param,
    1249718                   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)
    1253723{
    1254724        TALLOC_CTX *frame = talloc_stackframe();
     
    1286756        }
    1287757
    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);
    1290762 fail:
    1291763        TALLOC_FREE(frame);
Note: See TracChangeset for help on using the changeset viewer.