~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/clitrans.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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)
 
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(
 
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,
 
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,
 
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
}