Line data Source code
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 : #include "system/network.h"
22 : #include "../lib/util/tevent_ntstatus.h"
23 : #include "../libcli/smb/smb_common.h"
24 : #include "../libcli/smb/smbXcli_base.h"
25 :
26 : struct trans_recvblob {
27 : uint8_t *data;
28 : uint32_t max, total, received;
29 : };
30 :
31 : struct smb1cli_trans_state {
32 : struct smbXcli_conn *conn;
33 : struct tevent_context *ev;
34 : uint8_t cmd;
35 : uint8_t additional_flags;
36 : uint8_t clear_flags;
37 : uint16_t additional_flags2;
38 : uint16_t clear_flags2;
39 : uint32_t timeout_msec;
40 : uint16_t mid;
41 : uint32_t pid;
42 : struct smbXcli_tcon *tcon;
43 : struct smbXcli_session *session;
44 : const char *pipe_name;
45 : uint8_t *pipe_name_conv;
46 : size_t pipe_name_conv_len;
47 : uint16_t fid;
48 : uint16_t function;
49 : int flags;
50 : uint16_t *setup;
51 : uint8_t num_setup, max_setup;
52 : uint8_t *param;
53 : uint32_t num_param, param_sent;
54 : uint8_t *data;
55 : uint32_t num_data, data_sent;
56 :
57 : uint8_t num_rsetup;
58 : uint16_t *rsetup;
59 : struct trans_recvblob rparam;
60 : struct trans_recvblob rdata;
61 : uint16_t recv_flags2;
62 :
63 : struct iovec iov[6];
64 : uint8_t pad[4];
65 : uint8_t zero_pad[4];
66 : uint16_t vwv[32];
67 :
68 : NTSTATUS status;
69 :
70 : struct tevent_req *primary_subreq;
71 : };
72 :
73 282208 : static void smb1cli_trans_cleanup_primary(struct smb1cli_trans_state *state)
74 : {
75 282208 : if (state->primary_subreq) {
76 94068 : smb1cli_req_set_mid(state->primary_subreq, 0);
77 94068 : smbXcli_req_unset_pending(state->primary_subreq);
78 94068 : TALLOC_FREE(state->primary_subreq);
79 : }
80 282208 : }
81 :
82 94068 : static int smb1cli_trans_state_destructor(struct smb1cli_trans_state *state)
83 : {
84 94068 : smb1cli_trans_cleanup_primary(state);
85 94068 : return 0;
86 : }
87 :
88 56027 : static NTSTATUS smb1cli_pull_trans(uint8_t *inhdr,
89 : uint8_t wct,
90 : uint16_t *vwv,
91 : uint32_t vwv_ofs,
92 : uint32_t num_bytes,
93 : uint8_t *bytes,
94 : uint32_t bytes_ofs,
95 : uint8_t smb_cmd, bool expect_first_reply,
96 : uint8_t *pnum_setup, uint16_t **psetup,
97 : uint32_t *ptotal_param, uint32_t *pnum_param,
98 : uint32_t *pparam_disp, uint8_t **pparam,
99 : uint32_t *ptotal_data, uint32_t *pnum_data,
100 : uint32_t *pdata_disp, uint8_t **pdata)
101 : {
102 1218 : uint32_t param_ofs, data_ofs;
103 1218 : uint8_t expected_num_setup;
104 56027 : uint32_t max_bytes = UINT32_MAX - bytes_ofs;
105 1218 : uint32_t bytes_end;
106 :
107 56027 : if (num_bytes > max_bytes) {
108 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
109 : }
110 :
111 56027 : bytes_end = bytes_ofs + num_bytes;
112 :
113 56027 : if (expect_first_reply) {
114 0 : if ((wct != 0) || (num_bytes != 0)) {
115 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
116 : }
117 0 : return NT_STATUS_OK;
118 : }
119 :
120 56027 : switch (smb_cmd) {
121 39060 : case SMBtrans:
122 : case SMBtrans2:
123 39060 : if (wct < 10) {
124 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
125 : }
126 39060 : expected_num_setup = wct - 10;
127 39060 : *ptotal_param = SVAL(vwv + 0, 0);
128 39060 : *ptotal_data = SVAL(vwv + 1, 0);
129 39060 : *pnum_param = SVAL(vwv + 3, 0);
130 39060 : param_ofs = SVAL(vwv + 4, 0);
131 39060 : *pparam_disp = SVAL(vwv + 5, 0);
132 39060 : *pnum_data = SVAL(vwv + 6, 0);
133 39060 : data_ofs = SVAL(vwv + 7, 0);
134 39060 : *pdata_disp = SVAL(vwv + 8, 0);
135 39060 : *pnum_setup = CVAL(vwv + 9, 0);
136 39060 : if (expected_num_setup < (*pnum_setup)) {
137 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
138 : }
139 39060 : *psetup = vwv + 10;
140 :
141 39060 : break;
142 16967 : case SMBnttrans:
143 16967 : if (wct < 18) {
144 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
145 : }
146 16967 : expected_num_setup = wct - 18;
147 16967 : *ptotal_param = IVAL(vwv, 3);
148 16967 : *ptotal_data = IVAL(vwv, 7);
149 16967 : *pnum_param = IVAL(vwv, 11);
150 16967 : param_ofs = IVAL(vwv, 15);
151 16967 : *pparam_disp = IVAL(vwv, 19);
152 16967 : *pnum_data = IVAL(vwv, 23);
153 16967 : data_ofs = IVAL(vwv, 27);
154 16967 : *pdata_disp = IVAL(vwv, 31);
155 16967 : *pnum_setup = CVAL(vwv, 35);
156 16967 : if (expected_num_setup < (*pnum_setup)) {
157 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
158 : }
159 16967 : *psetup = vwv + 18;
160 16967 : break;
161 :
162 0 : default:
163 0 : return NT_STATUS_INTERNAL_ERROR;
164 : }
165 :
166 : /*
167 : * Check for buffer overflows. data_ofs needs to be checked against
168 : * the incoming buffer length, data_disp against the total
169 : * length. Likewise for param_ofs/param_disp.
170 : */
171 :
172 56027 : if (smb_buffer_oob(bytes_end, param_ofs, *pnum_param)
173 56027 : || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param)
174 56027 : || smb_buffer_oob(bytes_end, data_ofs, *pnum_data)
175 56027 : || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
176 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
177 : }
178 :
179 56027 : *pparam = (uint8_t *)inhdr + param_ofs;
180 56027 : *pdata = (uint8_t *)inhdr + data_ofs;
181 :
182 56027 : return NT_STATUS_OK;
183 : }
184 :
185 112054 : static NTSTATUS smb1cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
186 : struct trans_recvblob *blob,
187 : uint32_t total, uint32_t thistime,
188 : uint8_t *buf, uint32_t displacement)
189 : {
190 112054 : if (blob->data == NULL) {
191 111970 : if (total > blob->max) {
192 8 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
193 : }
194 111962 : blob->total = total;
195 111962 : blob->data = talloc_array(mem_ctx, uint8_t, total);
196 111962 : if (blob->data == NULL) {
197 0 : return NT_STATUS_NO_MEMORY;
198 : }
199 : }
200 :
201 112046 : if (total > blob->total) {
202 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
203 : }
204 :
205 112046 : if (thistime) {
206 83793 : memcpy(blob->data + displacement, buf, thistime);
207 83793 : blob->received += thistime;
208 : }
209 :
210 112046 : return NT_STATUS_OK;
211 : }
212 :
213 94072 : static void smb1cli_trans_format(struct smb1cli_trans_state *state,
214 : uint8_t *pwct,
215 : int *piov_count)
216 : {
217 94072 : uint8_t wct = 0;
218 94072 : struct iovec *iov = state->iov;
219 94072 : uint8_t *pad = state->pad;
220 94072 : uint16_t *vwv = state->vwv;
221 1283 : uint32_t param_offset;
222 94072 : uint32_t this_param = 0;
223 1283 : uint32_t param_pad;
224 1283 : uint32_t data_offset;
225 94072 : uint32_t this_data = 0;
226 1283 : uint32_t data_pad;
227 1283 : uint32_t useable_space;
228 1283 : uint8_t cmd;
229 94072 : uint32_t max_trans = smb1cli_conn_max_xmit(state->conn);
230 :
231 94072 : cmd = state->cmd;
232 :
233 94072 : if ((state->param_sent != 0) || (state->data_sent != 0)) {
234 : /* The secondary commands are one after the primary ones */
235 0 : cmd += 1;
236 : }
237 :
238 94072 : param_offset = MIN_SMB_SIZE;
239 :
240 94072 : switch (cmd) {
241 1610 : case SMBtrans:
242 1610 : if (smbXcli_conn_use_unicode(state->conn)) {
243 1610 : pad[0] = 0;
244 1610 : iov[0].iov_base = (void *)pad;
245 1610 : iov[0].iov_len = 1;
246 1610 : param_offset += 1;
247 1610 : iov += 1;
248 : }
249 1610 : iov[0].iov_base = (void *)state->pipe_name_conv;
250 1610 : iov[0].iov_len = state->pipe_name_conv_len;
251 1610 : wct = 14 + state->num_setup;
252 1610 : param_offset += iov[0].iov_len;
253 1610 : iov += 1;
254 1610 : break;
255 73802 : case SMBtrans2:
256 73802 : pad[0] = 0;
257 73802 : pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
258 73802 : pad[2] = ' ';
259 73802 : iov[0].iov_base = (void *)pad;
260 73802 : iov[0].iov_len = 3;
261 73802 : wct = 14 + state->num_setup;
262 73802 : param_offset += 3;
263 73802 : iov += 1;
264 73802 : break;
265 0 : case SMBtranss:
266 0 : wct = 8;
267 0 : break;
268 0 : case SMBtranss2:
269 0 : wct = 9;
270 0 : break;
271 18660 : case SMBnttrans:
272 18660 : wct = 19 + state->num_setup;
273 18660 : break;
274 0 : case SMBnttranss:
275 0 : wct = 18;
276 0 : break;
277 : }
278 :
279 94072 : param_offset += wct * sizeof(uint16_t);
280 94072 : useable_space = max_trans - param_offset;
281 :
282 94072 : param_pad = param_offset % 4;
283 94072 : if (param_pad > 0) {
284 20270 : param_pad = MIN(param_pad, useable_space);
285 20270 : iov[0].iov_base = (void *)state->zero_pad;
286 20270 : iov[0].iov_len = param_pad;
287 20270 : iov += 1;
288 20270 : param_offset += param_pad;
289 : }
290 94072 : useable_space = max_trans - param_offset;
291 :
292 94072 : if (state->param_sent < state->num_param) {
293 89625 : this_param = MIN(state->num_param - state->param_sent,
294 : useable_space);
295 89625 : iov[0].iov_base = (void *)(state->param + state->param_sent);
296 89625 : iov[0].iov_len = this_param;
297 89625 : iov += 1;
298 : }
299 :
300 94072 : data_offset = param_offset + this_param;
301 94072 : useable_space = max_trans - data_offset;
302 :
303 94072 : data_pad = data_offset % 4;
304 94072 : if (data_pad > 0) {
305 55224 : data_pad = MIN(data_pad, useable_space);
306 55224 : iov[0].iov_base = (void *)state->zero_pad;
307 55224 : iov[0].iov_len = data_pad;
308 55224 : iov += 1;
309 55224 : data_offset += data_pad;
310 : }
311 94072 : useable_space = max_trans - data_offset;
312 :
313 94072 : if (state->data_sent < state->num_data) {
314 22080 : this_data = MIN(state->num_data - state->data_sent,
315 : useable_space);
316 22080 : iov[0].iov_base = (void *)(state->data + state->data_sent);
317 22080 : iov[0].iov_len = this_data;
318 22080 : iov += 1;
319 : }
320 :
321 94072 : DEBUG(10, ("num_setup=%u, max_setup=%u, "
322 : "param_total=%u, this_param=%u, max_param=%u, "
323 : "data_total=%u, this_data=%u, max_data=%u, "
324 : "param_offset=%u, param_pad=%u, param_disp=%u, "
325 : "data_offset=%u, data_pad=%u, data_disp=%u\n",
326 : (unsigned)state->num_setup, (unsigned)state->max_setup,
327 : (unsigned)state->num_param, (unsigned)this_param,
328 : (unsigned)state->rparam.max,
329 : (unsigned)state->num_data, (unsigned)this_data,
330 : (unsigned)state->rdata.max,
331 : (unsigned)param_offset, (unsigned)param_pad,
332 : (unsigned)state->param_sent,
333 : (unsigned)data_offset, (unsigned)data_pad,
334 : (unsigned)state->data_sent));
335 :
336 94072 : switch (cmd) {
337 75412 : case SMBtrans:
338 : case SMBtrans2:
339 75412 : SSVAL(vwv + 0, 0, state->num_param);
340 75412 : SSVAL(vwv + 1, 0, state->num_data);
341 75412 : SSVAL(vwv + 2, 0, state->rparam.max);
342 75412 : SSVAL(vwv + 3, 0, state->rdata.max);
343 75412 : SCVAL(vwv + 4, 0, state->max_setup);
344 75412 : SCVAL(vwv + 4, 1, 0); /* reserved */
345 75412 : SSVAL(vwv + 5, 0, state->flags);
346 75412 : SIVAL(vwv + 6, 0, 0); /* timeout */
347 75412 : SSVAL(vwv + 8, 0, 0); /* reserved */
348 75412 : SSVAL(vwv + 9, 0, this_param);
349 75412 : SSVAL(vwv +10, 0, param_offset);
350 75412 : SSVAL(vwv +11, 0, this_data);
351 75412 : SSVAL(vwv +12, 0, data_offset);
352 75412 : SCVAL(vwv +13, 0, state->num_setup);
353 75412 : SCVAL(vwv +13, 1, 0); /* reserved */
354 75412 : if (state->num_setup > 0) {
355 76551 : memcpy(vwv + 14, state->setup,
356 75268 : sizeof(uint16_t) * state->num_setup);
357 : }
358 74194 : break;
359 0 : case SMBtranss:
360 : case SMBtranss2:
361 0 : SSVAL(vwv + 0, 0, state->num_param);
362 0 : SSVAL(vwv + 1, 0, state->num_data);
363 0 : SSVAL(vwv + 2, 0, this_param);
364 0 : SSVAL(vwv + 3, 0, param_offset);
365 0 : SSVAL(vwv + 4, 0, state->param_sent);
366 0 : SSVAL(vwv + 5, 0, this_data);
367 0 : SSVAL(vwv + 6, 0, data_offset);
368 0 : SSVAL(vwv + 7, 0, state->data_sent);
369 0 : if (cmd == SMBtranss2) {
370 0 : SSVAL(vwv + 8, 0, state->fid);
371 : }
372 0 : break;
373 18660 : case SMBnttrans:
374 18660 : SCVAL(vwv + 0, 0, state->max_setup);
375 18660 : SSVAL(vwv + 0, 1, 0); /* reserved */
376 18660 : SIVAL(vwv + 1, 1, state->num_param);
377 18660 : SIVAL(vwv + 3, 1, state->num_data);
378 18660 : SIVAL(vwv + 5, 1, state->rparam.max);
379 18660 : SIVAL(vwv + 7, 1, state->rdata.max);
380 18660 : SIVAL(vwv + 9, 1, this_param);
381 18660 : SIVAL(vwv +11, 1, param_offset);
382 18660 : SIVAL(vwv +13, 1, this_data);
383 18660 : SIVAL(vwv +15, 1, data_offset);
384 18660 : SCVAL(vwv +17, 1, state->num_setup);
385 18660 : SSVAL(vwv +18, 0, state->function);
386 19943 : memcpy(vwv + 19, state->setup,
387 18660 : sizeof(uint16_t) * state->num_setup);
388 18595 : break;
389 0 : case SMBnttranss:
390 0 : SSVAL(vwv + 0, 0, 0); /* reserved */
391 0 : SCVAL(vwv + 1, 0, 0); /* reserved */
392 0 : SIVAL(vwv + 1, 1, state->num_param);
393 0 : SIVAL(vwv + 3, 1, state->num_data);
394 0 : SIVAL(vwv + 5, 1, this_param);
395 0 : SIVAL(vwv + 7, 1, param_offset);
396 0 : SIVAL(vwv + 9, 1, state->param_sent);
397 0 : SIVAL(vwv +11, 1, this_data);
398 0 : SIVAL(vwv +13, 1, data_offset);
399 0 : SIVAL(vwv +15, 1, state->data_sent);
400 0 : SCVAL(vwv +17, 1, 0); /* reserved */
401 0 : break;
402 : }
403 :
404 94072 : state->param_sent += this_param;
405 94072 : state->data_sent += this_data;
406 :
407 94072 : *pwct = wct;
408 94072 : *piov_count = iov - state->iov;
409 94072 : }
410 :
411 : static bool smb1cli_trans_cancel(struct tevent_req *req);
412 : static void smb1cli_trans_done(struct tevent_req *subreq);
413 :
414 94072 : struct tevent_req *smb1cli_trans_send(
415 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
416 : struct smbXcli_conn *conn, uint8_t cmd,
417 : uint8_t additional_flags, uint8_t clear_flags,
418 : uint16_t additional_flags2, uint16_t clear_flags2,
419 : uint32_t timeout_msec,
420 : uint32_t pid,
421 : struct smbXcli_tcon *tcon,
422 : struct smbXcli_session *session,
423 : const char *pipe_name, uint16_t fid, uint16_t function, int flags,
424 : uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
425 : uint8_t *param, uint32_t num_param, uint32_t max_param,
426 : uint8_t *data, uint32_t num_data, uint32_t max_data)
427 : {
428 1283 : struct tevent_req *req, *subreq;
429 1283 : struct smb1cli_trans_state *state;
430 1283 : int iov_count;
431 1283 : uint8_t wct;
432 1283 : NTSTATUS status;
433 1283 : charset_t charset;
434 :
435 94072 : req = tevent_req_create(mem_ctx, &state,
436 : struct smb1cli_trans_state);
437 94072 : if (req == NULL) {
438 0 : return NULL;
439 : }
440 :
441 94072 : if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
442 75412 : if ((num_param > 0xffff) || (max_param > 0xffff)
443 75412 : || (num_data > 0xffff) || (max_data > 0xffff)) {
444 0 : DEBUG(3, ("Attempt to send invalid trans2 request "
445 : "(setup %u, params %u/%u, data %u/%u)\n",
446 : (unsigned)num_setup,
447 : (unsigned)num_param, (unsigned)max_param,
448 : (unsigned)num_data, (unsigned)max_data));
449 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
450 0 : return tevent_req_post(req, ev);
451 : }
452 : }
453 :
454 : /*
455 : * The largest wct will be for nttrans (19+num_setup). Make sure we
456 : * don't overflow state->vwv in smb1cli_trans_format.
457 : */
458 :
459 94072 : if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
460 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
461 0 : return tevent_req_post(req, ev);
462 : }
463 :
464 94072 : state->conn = conn;
465 94072 : state->ev = ev;
466 94072 : state->cmd = cmd;
467 94072 : state->additional_flags = additional_flags;
468 94072 : state->clear_flags = clear_flags;
469 94072 : state->additional_flags2 = additional_flags2;
470 94072 : state->clear_flags2 = clear_flags2;
471 94072 : state->timeout_msec = timeout_msec;
472 94072 : state->flags = flags;
473 94072 : state->num_rsetup = 0;
474 94072 : state->rsetup = NULL;
475 94072 : state->pid = pid;
476 94072 : state->tcon = tcon;
477 94072 : state->session = session;
478 94072 : ZERO_STRUCT(state->rparam);
479 94072 : ZERO_STRUCT(state->rdata);
480 :
481 94072 : if (smbXcli_conn_use_unicode(conn)) {
482 92787 : charset = CH_UTF16LE;
483 : } else {
484 2 : charset = CH_DOS;
485 : }
486 :
487 94072 : if ((pipe_name != NULL)
488 1610 : && (!convert_string_talloc(state, CH_UNIX, charset,
489 1610 : pipe_name, strlen(pipe_name) + 1,
490 1610 : &state->pipe_name_conv,
491 1610 : &state->pipe_name_conv_len))) {
492 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
493 0 : return tevent_req_post(req, ev);
494 : }
495 94072 : state->fid = fid; /* trans2 */
496 94072 : state->function = function; /* nttrans */
497 :
498 94072 : state->setup = setup;
499 94072 : state->num_setup = num_setup;
500 94072 : state->max_setup = max_setup;
501 :
502 94072 : state->param = param;
503 94072 : state->num_param = num_param;
504 94072 : state->param_sent = 0;
505 94072 : state->rparam.max = max_param;
506 :
507 94072 : state->data = data;
508 94072 : state->num_data = num_data;
509 94072 : state->data_sent = 0;
510 94072 : state->rdata.max = max_data;
511 :
512 94072 : smb1cli_trans_format(state, &wct, &iov_count);
513 :
514 188144 : subreq = smb1cli_req_create(state, ev, conn, cmd,
515 94072 : state->additional_flags,
516 94072 : state->clear_flags,
517 94072 : state->additional_flags2,
518 94072 : state->clear_flags2,
519 92789 : state->timeout_msec,
520 92789 : state->pid,
521 92789 : state->tcon,
522 92789 : state->session,
523 94072 : wct, state->vwv,
524 94072 : iov_count, state->iov);
525 94072 : if (tevent_req_nomem(subreq, req)) {
526 0 : return tevent_req_post(req, ev);
527 : }
528 94072 : status = smb1cli_req_chain_submit(&subreq, 1);
529 94072 : if (tevent_req_nterror(req, status)) {
530 4 : return tevent_req_post(req, state->ev);
531 : }
532 94068 : tevent_req_set_callback(subreq, smb1cli_trans_done, req);
533 :
534 : /*
535 : * Now get the MID of the primary request
536 : * and mark it as persistent. This means
537 : * we will able to send and receive multiple
538 : * SMB pdus using this MID in both directions
539 : * (including correct SMB signing).
540 : */
541 94068 : state->mid = smb1cli_req_mid(subreq);
542 94068 : smb1cli_req_set_mid(subreq, state->mid);
543 94068 : state->primary_subreq = subreq;
544 94068 : talloc_set_destructor(state, smb1cli_trans_state_destructor);
545 :
546 94068 : tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);
547 :
548 94068 : return req;
549 : }
550 :
551 1510 : static bool smb1cli_trans_cancel(struct tevent_req *req)
552 : {
553 0 : struct smb1cli_trans_state *state =
554 1510 : tevent_req_data(req,
555 : struct smb1cli_trans_state);
556 :
557 1510 : if (state->primary_subreq == NULL) {
558 0 : return false;
559 : }
560 :
561 1510 : return tevent_req_cancel(state->primary_subreq);
562 : }
563 :
564 : static void smb1cli_trans_done2(struct tevent_req *subreq);
565 :
566 94110 : static void smb1cli_trans_done(struct tevent_req *subreq)
567 : {
568 1283 : struct tevent_req *req =
569 94110 : tevent_req_callback_data(subreq,
570 : struct tevent_req);
571 1283 : struct smb1cli_trans_state *state =
572 94110 : tevent_req_data(req,
573 : struct smb1cli_trans_state);
574 1283 : NTSTATUS status;
575 1283 : bool sent_all;
576 94110 : struct iovec *recv_iov = NULL;
577 1283 : uint8_t *inhdr;
578 1283 : uint8_t wct;
579 1283 : uint16_t *vwv;
580 1283 : uint32_t vwv_ofs;
581 1283 : uint32_t num_bytes;
582 1283 : uint8_t *bytes;
583 1283 : uint32_t bytes_ofs;
584 94110 : uint8_t num_setup = 0;
585 94110 : uint16_t *setup = NULL;
586 94110 : uint32_t total_param = 0;
587 94110 : uint32_t num_param = 0;
588 94110 : uint32_t param_disp = 0;
589 94110 : uint32_t total_data = 0;
590 94110 : uint32_t num_data = 0;
591 94110 : uint32_t data_disp = 0;
592 94110 : uint8_t *param = NULL;
593 94110 : uint8_t *data = NULL;
594 :
595 94110 : status = smb1cli_req_recv(subreq, state,
596 : &recv_iov,
597 : &inhdr,
598 : &wct,
599 : &vwv,
600 : &vwv_ofs,
601 : &num_bytes,
602 : &bytes,
603 : &bytes_ofs,
604 : NULL, /* pinbuf */
605 : NULL, 0); /* expected */
606 : /*
607 : * Do not TALLOC_FREE(subreq) here, we might receive more than
608 : * one response for the same mid.
609 : */
610 :
611 : /*
612 : * We can receive something like STATUS_MORE_ENTRIES, so don't use
613 : * !NT_STATUS_IS_OK(status) here.
614 : */
615 :
616 94110 : if (NT_STATUS_IS_ERR(status)) {
617 38083 : goto fail;
618 : }
619 :
620 56027 : if (recv_iov == NULL) {
621 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
622 0 : goto fail;
623 : }
624 56027 : state->status = status;
625 :
626 112054 : sent_all = ((state->param_sent == state->num_param)
627 56027 : && (state->data_sent == state->num_data));
628 :
629 57245 : status = smb1cli_pull_trans(
630 : inhdr, wct, vwv, vwv_ofs,
631 : num_bytes, bytes, bytes_ofs,
632 56027 : state->cmd, !sent_all, &num_setup, &setup,
633 : &total_param, &num_param, ¶m_disp, ¶m,
634 56027 : &total_data, &num_data, &data_disp, &data);
635 :
636 56027 : if (!NT_STATUS_IS_OK(status)) {
637 0 : goto fail;
638 : }
639 :
640 56027 : if (!sent_all) {
641 0 : int iov_count;
642 0 : struct tevent_req *subreq2;
643 :
644 0 : smb1cli_trans_format(state, &wct, &iov_count);
645 :
646 0 : subreq2 = smb1cli_req_create(state, state->ev, state->conn,
647 0 : state->cmd + 1,
648 0 : state->additional_flags,
649 0 : state->clear_flags,
650 0 : state->additional_flags2,
651 0 : state->clear_flags2,
652 : state->timeout_msec,
653 : state->pid,
654 : state->tcon,
655 : state->session,
656 0 : wct, state->vwv,
657 0 : iov_count, state->iov);
658 0 : if (tevent_req_nomem(subreq2, req)) {
659 0 : return;
660 : }
661 0 : smb1cli_req_set_mid(subreq2, state->mid);
662 :
663 0 : status = smb1cli_req_chain_submit(&subreq2, 1);
664 :
665 0 : if (!NT_STATUS_IS_OK(status)) {
666 0 : goto fail;
667 : }
668 0 : tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
669 :
670 0 : return;
671 : }
672 :
673 56027 : status = smb1cli_trans_pull_blob(
674 : state, &state->rparam, total_param, num_param, param,
675 : param_disp);
676 :
677 56027 : if (!NT_STATUS_IS_OK(status)) {
678 0 : DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
679 0 : goto fail;
680 : }
681 :
682 56027 : status = smb1cli_trans_pull_blob(
683 : state, &state->rdata, total_data, num_data, data,
684 : data_disp);
685 :
686 56027 : if (!NT_STATUS_IS_OK(status)) {
687 8 : DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
688 8 : goto fail;
689 : }
690 :
691 56019 : if ((state->rparam.total == state->rparam.received)
692 56019 : && (state->rdata.total == state->rdata.received)) {
693 55977 : state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
694 55977 : smb1cli_trans_cleanup_primary(state);
695 55977 : tevent_req_done(req);
696 55977 : return;
697 : }
698 :
699 42 : TALLOC_FREE(recv_iov);
700 :
701 42 : return;
702 :
703 38091 : fail:
704 38091 : smb1cli_trans_cleanup_primary(state);
705 38091 : tevent_req_nterror(req, status);
706 : }
707 :
708 0 : static void smb1cli_trans_done2(struct tevent_req *subreq2)
709 : {
710 0 : struct tevent_req *req =
711 0 : tevent_req_callback_data(subreq2,
712 : struct tevent_req);
713 0 : struct smb1cli_trans_state *state =
714 0 : tevent_req_data(req,
715 : struct smb1cli_trans_state);
716 0 : NTSTATUS status;
717 0 : bool sent_all;
718 0 : uint32_t seqnum;
719 :
720 : /*
721 : * First backup the seqnum of the secondary request
722 : * and attach it to the primary request.
723 : */
724 0 : seqnum = smb1cli_req_seqnum(subreq2);
725 0 : smb1cli_req_set_seqnum(state->primary_subreq, seqnum);
726 :
727 : /* This was a one way request */
728 0 : status = smb1cli_req_recv(subreq2, state,
729 : NULL, /* recv_iov */
730 : NULL, /* phdr */
731 : NULL, /* pwct */
732 : NULL, /* pvwv */
733 : NULL, /* pvwv_offset */
734 : NULL, /* pnum_bytes */
735 : NULL, /* pbytes */
736 : NULL, /* pbytes_offset */
737 : NULL, /* pinbuf */
738 : NULL, 0); /* expected */
739 0 : TALLOC_FREE(subreq2);
740 :
741 0 : if (!NT_STATUS_IS_OK(status)) {
742 0 : goto fail;
743 : }
744 :
745 0 : sent_all = ((state->param_sent == state->num_param)
746 0 : && (state->data_sent == state->num_data));
747 :
748 0 : if (!sent_all) {
749 0 : uint8_t wct;
750 0 : int iov_count;
751 :
752 0 : smb1cli_trans_format(state, &wct, &iov_count);
753 :
754 0 : subreq2 = smb1cli_req_create(state, state->ev, state->conn,
755 0 : state->cmd + 1,
756 0 : state->additional_flags,
757 0 : state->clear_flags,
758 0 : state->additional_flags2,
759 0 : state->clear_flags2,
760 : state->timeout_msec,
761 : state->pid,
762 : state->tcon,
763 : state->session,
764 0 : wct, state->vwv,
765 0 : iov_count, state->iov);
766 0 : if (tevent_req_nomem(subreq2, req)) {
767 0 : return;
768 : }
769 0 : smb1cli_req_set_mid(subreq2, state->mid);
770 :
771 0 : status = smb1cli_req_chain_submit(&subreq2, 1);
772 :
773 0 : if (!NT_STATUS_IS_OK(status)) {
774 0 : goto fail;
775 : }
776 0 : tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
777 0 : return;
778 : }
779 :
780 0 : return;
781 :
782 0 : fail:
783 0 : smb1cli_trans_cleanup_primary(state);
784 0 : tevent_req_nterror(req, status);
785 : }
786 :
787 94072 : NTSTATUS smb1cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
788 : uint16_t *recv_flags2,
789 : uint16_t **setup, uint8_t min_setup,
790 : uint8_t *num_setup,
791 : uint8_t **param, uint32_t min_param,
792 : uint32_t *num_param,
793 : uint8_t **data, uint32_t min_data,
794 : uint32_t *num_data)
795 : {
796 1283 : struct smb1cli_trans_state *state =
797 94072 : tevent_req_data(req,
798 : struct smb1cli_trans_state);
799 1283 : NTSTATUS status;
800 :
801 94072 : smb1cli_trans_cleanup_primary(state);
802 :
803 94072 : if (tevent_req_is_nterror(req, &status)) {
804 38095 : if (!NT_STATUS_IS_ERR(status)) {
805 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
806 : }
807 38095 : tevent_req_received(req);
808 38095 : return status;
809 : }
810 :
811 55977 : if ((state->num_rsetup < min_setup)
812 55977 : || (state->rparam.total < min_param)
813 55977 : || (state->rdata.total < min_data)) {
814 0 : tevent_req_received(req);
815 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
816 : }
817 :
818 55977 : if (recv_flags2 != NULL) {
819 53650 : *recv_flags2 = state->recv_flags2;
820 : }
821 :
822 55977 : if (setup != NULL) {
823 53650 : *setup = talloc_move(mem_ctx, &state->rsetup);
824 53650 : *num_setup = state->num_rsetup;
825 : } else {
826 2327 : TALLOC_FREE(state->rsetup);
827 : }
828 :
829 55977 : if (param != NULL) {
830 54530 : *param = talloc_move(mem_ctx, &state->rparam.data);
831 54530 : *num_param = state->rparam.total;
832 : } else {
833 1447 : TALLOC_FREE(state->rparam.data);
834 : }
835 :
836 55977 : if (data != NULL) {
837 55977 : *data = talloc_move(mem_ctx, &state->rdata.data);
838 55977 : *num_data = state->rdata.total;
839 : } else {
840 0 : TALLOC_FREE(state->rdata.data);
841 : }
842 :
843 55977 : status = state->status;
844 55977 : tevent_req_received(req);
845 55977 : return status;
846 : }
847 :
848 0 : NTSTATUS smb1cli_trans(TALLOC_CTX *mem_ctx, struct smbXcli_conn *conn,
849 : uint8_t trans_cmd,
850 : uint8_t additional_flags, uint8_t clear_flags,
851 : uint16_t additional_flags2, uint16_t clear_flags2,
852 : uint32_t timeout_msec,
853 : uint32_t pid,
854 : struct smbXcli_tcon *tcon,
855 : struct smbXcli_session *session,
856 : const char *pipe_name, uint16_t fid, uint16_t function,
857 : int flags,
858 : uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
859 : uint8_t *param, uint32_t num_param, uint32_t max_param,
860 : uint8_t *data, uint32_t num_data, uint32_t max_data,
861 : uint16_t *recv_flags2,
862 : uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
863 : uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
864 : uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
865 : {
866 0 : TALLOC_CTX *frame = talloc_stackframe();
867 0 : struct tevent_context *ev;
868 0 : struct tevent_req *req;
869 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
870 :
871 0 : if (smbXcli_conn_has_async_calls(conn)) {
872 : /*
873 : * Can't use sync call while an async call is in flight
874 : */
875 0 : status = NT_STATUS_INVALID_PARAMETER_MIX;
876 0 : goto fail;
877 : }
878 :
879 0 : ev = samba_tevent_context_init(frame);
880 0 : if (ev == NULL) {
881 0 : goto fail;
882 : }
883 :
884 0 : req = smb1cli_trans_send(frame, ev, conn, trans_cmd,
885 : additional_flags, clear_flags,
886 : additional_flags2, clear_flags2,
887 : timeout_msec,
888 : pid, tcon, session,
889 : pipe_name, fid, function, flags,
890 : setup, num_setup, max_setup,
891 : param, num_param, max_param,
892 : data, num_data, max_data);
893 0 : if (req == NULL) {
894 0 : goto fail;
895 : }
896 :
897 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
898 0 : goto fail;
899 : }
900 :
901 0 : status = smb1cli_trans_recv(req, mem_ctx, recv_flags2,
902 : rsetup, min_rsetup, num_rsetup,
903 : rparam, min_rparam, num_rparam,
904 : rdata, min_rdata, num_rdata);
905 0 : fail:
906 0 : TALLOC_FREE(frame);
907 0 : return status;
908 : }
|