1 /*
2 Unix SMB/CIFS implementation.
3 raw trans/trans2/nttrans operations
4
5 Copyright (C) James Myers 2003 <myersjj@samba.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include <tevent.h>
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "../libcli/smb/smbXcli_base.h"
26
27 static void smb_raw_trans_backend_done(struct tevent_req *subreq);
28
smb_raw_trans_backend_send(struct smbcli_tree * tree,struct smb_trans2 * parms,uint8_t command)29 static struct smbcli_request *smb_raw_trans_backend_send(struct smbcli_tree *tree,
30 struct smb_trans2 *parms,
31 uint8_t command)
32 {
33 struct smbcli_request *req;
34 uint8_t additional_flags;
35 uint8_t clear_flags;
36 uint16_t additional_flags2;
37 uint16_t clear_flags2;
38 uint32_t pid;
39 struct smbXcli_tcon *tcon = NULL;
40 struct smbXcli_session *session = NULL;
41 const char *pipe_name = NULL;
42 uint8_t s;
43 uint32_t timeout_msec;
44 uint32_t tmp;
45
46 tmp = parms->in.params.length + parms->in.data.length;
47
48 req = smbcli_request_setup(tree, command, parms->in.setup_count, tmp);
49 if (req == NULL) {
50 return NULL;
51 }
52
53 additional_flags = CVAL(req->out.hdr, HDR_FLG);
54 additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
55 pid = SVAL(req->out.hdr, HDR_PID);
56 pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
57
58 if (req->session) {
59 session = req->session->smbXcli;
60 }
61
62 if (req->tree) {
63 tcon = req->tree->smbXcli;
64 }
65
66 clear_flags = ~additional_flags;
67 clear_flags2 = ~additional_flags2;
68
69 timeout_msec = req->transport->options.request_timeout * 1000;
70
71 for (s=0; s < parms->in.setup_count; s++) {
72 SSVAL(req->out.vwv, VWV(s), parms->in.setup[s]);
73 }
74
75 if (parms->in.params.length > 0) {
76 memcpy(req->out.data,
77 parms->in.params.data,
78 parms->in.params.length);
79 }
80 if (parms->in.data.length > 0) {
81 memcpy(req->out.data + parms->in.params.length,
82 parms->in.data.data,
83 parms->in.data.length);
84 }
85
86 if (command == SMBtrans && parms->in.trans_name) {
87 pipe_name = parms->in.trans_name;
88 }
89
90 req->subreqs[0] = smb1cli_trans_send(req,
91 req->transport->ev,
92 req->transport->conn,
93 command,
94 additional_flags,
95 clear_flags,
96 additional_flags2,
97 clear_flags2,
98 timeout_msec,
99 pid,
100 tcon,
101 session,
102 pipe_name,
103 0xFFFF, /* fid */
104 0, /* function */
105 parms->in.flags,
106 (uint16_t *)req->out.vwv,
107 parms->in.setup_count,
108 parms->in.max_setup,
109 req->out.data,
110 parms->in.params.length,
111 parms->in.max_param,
112 req->out.data+
113 parms->in.params.length,
114 parms->in.data.length,
115 parms->in.max_data);
116 if (req->subreqs[0] == NULL) {
117 talloc_free(req);
118 return NULL;
119 }
120 tevent_req_set_callback(req->subreqs[0],
121 smb_raw_trans_backend_done,
122 req);
123
124 return req;
125 }
126
smb_raw_trans_backend_done(struct tevent_req * subreq)127 static void smb_raw_trans_backend_done(struct tevent_req *subreq)
128 {
129 struct smbcli_request *req =
130 tevent_req_callback_data(subreq,
131 struct smbcli_request);
132 struct smbcli_transport *transport = req->transport;
133 uint16_t *setup = NULL;
134 uint8_t num_setup = 0;
135 uint8_t s;
136 uint8_t *param = NULL;
137 uint32_t num_param = 0;
138 uint8_t *data = NULL;
139 uint32_t num_data = 0;
140
141 req->status = smb1cli_trans_recv(req->subreqs[0], req,
142 &req->flags2,
143 &setup,
144 0, /* min_setup */
145 &num_setup,
146 ¶m,
147 0, /* min_param */
148 &num_param,
149 &data,
150 0, /* min_data */
151 &num_data);
152 TALLOC_FREE(req->subreqs[0]);
153 if (NT_STATUS_IS_ERR(req->status)) {
154 req->state = SMBCLI_REQUEST_ERROR;
155 transport->error.e.nt_status = req->status;
156 transport->error.etype = ETYPE_SMB;
157 if (req->async.fn) {
158 req->async.fn(req);
159 }
160 return;
161 }
162
163 req->trans2.out.setup_count = num_setup;
164 req->trans2.out.setup = talloc_array(req, uint16_t, num_setup);
165 if (req->trans2.out.setup == NULL) {
166 req->state = SMBCLI_REQUEST_ERROR;
167 req->status = NT_STATUS_NO_MEMORY;
168 transport->error.e.nt_status = req->status;
169 transport->error.etype = ETYPE_SMB;
170 if (req->async.fn) {
171 req->async.fn(req);
172 }
173 return;
174 }
175 for (s = 0; s < num_setup; s++) {
176 req->trans2.out.setup[s] = SVAL(setup, VWV(s));
177 }
178
179 req->trans2.out.params.data = param;
180 req->trans2.out.params.length = num_param;
181
182 req->trans2.out.data.data = data;
183 req->trans2.out.data.length = num_data;
184
185 transport->error.e.nt_status = req->status;
186 if (NT_STATUS_IS_OK(req->status)) {
187 transport->error.etype = ETYPE_NONE;
188 } else {
189 transport->error.etype = ETYPE_SMB;
190 }
191
192 req->state = SMBCLI_REQUEST_DONE;
193 if (req->async.fn) {
194 req->async.fn(req);
195 }
196 }
197
smb_raw_trans_backend_recv(struct smbcli_request * req,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)198 static NTSTATUS smb_raw_trans_backend_recv(struct smbcli_request *req,
199 TALLOC_CTX *mem_ctx,
200 struct smb_trans2 *parms)
201 {
202 if (!smbcli_request_receive(req) ||
203 smbcli_request_is_error(req)) {
204 goto failed;
205 }
206
207 parms->out = req->trans2.out;
208 talloc_steal(mem_ctx, parms->out.setup);
209 talloc_steal(mem_ctx, parms->out.params.data);
210 talloc_steal(mem_ctx, parms->out.data.data);
211
212 failed:
213 return smbcli_request_destroy(req);
214 }
215
smb_raw_trans_send(struct smbcli_tree * tree,struct smb_trans2 * parms)216 _PUBLIC_ struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree,
217 struct smb_trans2 *parms)
218 {
219 return smb_raw_trans_backend_send(tree, parms, SMBtrans);
220 }
221
smb_raw_trans_recv(struct smbcli_request * req,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)222 _PUBLIC_ NTSTATUS smb_raw_trans_recv(struct smbcli_request *req,
223 TALLOC_CTX *mem_ctx,
224 struct smb_trans2 *parms)
225 {
226 return smb_raw_trans_backend_recv(req, mem_ctx, parms);
227 }
228
smb_raw_trans(struct smbcli_tree * tree,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)229 _PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree,
230 TALLOC_CTX *mem_ctx,
231 struct smb_trans2 *parms)
232 {
233 struct smbcli_request *req;
234 req = smb_raw_trans_send(tree, parms);
235 if (!req) return NT_STATUS_UNSUCCESSFUL;
236 return smb_raw_trans_recv(req, mem_ctx, parms);
237 }
238
smb_raw_trans2_send(struct smbcli_tree * tree,struct smb_trans2 * parms)239 struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree,
240 struct smb_trans2 *parms)
241 {
242 return smb_raw_trans_backend_send(tree, parms, SMBtrans2);
243 }
244
smb_raw_trans2_recv(struct smbcli_request * req,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)245 NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req,
246 TALLOC_CTX *mem_ctx,
247 struct smb_trans2 *parms)
248 {
249 return smb_raw_trans_backend_recv(req, mem_ctx, parms);
250 }
251
smb_raw_trans2(struct smbcli_tree * tree,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)252 NTSTATUS smb_raw_trans2(struct smbcli_tree *tree,
253 TALLOC_CTX *mem_ctx,
254 struct smb_trans2 *parms)
255 {
256 struct smbcli_request *req;
257 req = smb_raw_trans2_send(tree, parms);
258 if (!req) return NT_STATUS_UNSUCCESSFUL;
259 return smb_raw_trans2_recv(req, mem_ctx, parms);
260 }
261
262 static void smb_raw_nttrans_done(struct tevent_req *subreq);
263
smb_raw_nttrans_send(struct smbcli_tree * tree,struct smb_nttrans * parms)264 struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
265 struct smb_nttrans *parms)
266 {
267 struct smbcli_request *req;
268 uint8_t additional_flags;
269 uint8_t clear_flags;
270 uint16_t additional_flags2;
271 uint16_t clear_flags2;
272 uint32_t pid;
273 struct smbXcli_tcon *tcon = NULL;
274 struct smbXcli_session *session = NULL;
275 uint32_t timeout_msec;
276 uint32_t tmp;
277
278 tmp = parms->in.params.length + parms->in.data.length;
279
280 req = smbcli_request_setup(tree, SMBnttrans, parms->in.setup_count, tmp);
281 if (req == NULL) {
282 return NULL;
283 }
284
285 additional_flags = CVAL(req->out.hdr, HDR_FLG);
286 additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
287 pid = SVAL(req->out.hdr, HDR_PID);
288 pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
289
290 if (req->session) {
291 session = req->session->smbXcli;
292 }
293
294 if (req->tree) {
295 tcon = req->tree->smbXcli;
296 }
297
298 clear_flags = ~additional_flags;
299 clear_flags2 = ~additional_flags2;
300
301 timeout_msec = req->transport->options.request_timeout * 1000;
302
303 if (parms->in.setup_count > 0) {
304 memcpy(
305 req->out.vwv, parms->in.setup, parms->in.setup_count * 2);
306 }
307
308 if (parms->in.params.length > 0) {
309 memcpy(req->out.data,
310 parms->in.params.data,
311 parms->in.params.length);
312 }
313 if (parms->in.data.length > 0) {
314 memcpy(req->out.data + parms->in.params.length,
315 parms->in.data.data,
316 parms->in.data.length);
317 }
318
319 req->subreqs[0] = smb1cli_trans_send(req,
320 req->transport->ev,
321 req->transport->conn,
322 SMBnttrans,
323 additional_flags,
324 clear_flags,
325 additional_flags2,
326 clear_flags2,
327 timeout_msec,
328 pid,
329 tcon,
330 session,
331 NULL, /* pipe_name */
332 0xFFFF, /* fid */
333 parms->in.function,
334 0, /* flags */
335 (uint16_t *)req->out.vwv,
336 parms->in.setup_count,
337 parms->in.max_setup,
338 req->out.data,
339 parms->in.params.length,
340 parms->in.max_param,
341 req->out.data+
342 parms->in.params.length,
343 parms->in.data.length,
344 parms->in.max_data);
345 if (req->subreqs[0] == NULL) {
346 talloc_free(req);
347 return NULL;
348 }
349 tevent_req_set_callback(req->subreqs[0],
350 smb_raw_nttrans_done,
351 req);
352
353 return req;
354 }
355
smb_raw_nttrans_done(struct tevent_req * subreq)356 static void smb_raw_nttrans_done(struct tevent_req *subreq)
357 {
358 struct smbcli_request *req =
359 tevent_req_callback_data(subreq,
360 struct smbcli_request);
361 struct smbcli_transport *transport = req->transport;
362 uint16_t *setup = NULL;
363 uint8_t num_setup = 0;
364 uint8_t *param = NULL;
365 uint32_t num_param = 0;
366 uint8_t *data = NULL;
367 uint32_t num_data = 0;
368
369 req->status = smb1cli_trans_recv(req->subreqs[0], req,
370 &req->flags2,
371 &setup,
372 0, /* min_setup */
373 &num_setup,
374 ¶m,
375 0, /* min_param */
376 &num_param,
377 &data,
378 0, /* min_data */
379 &num_data);
380 TALLOC_FREE(req->subreqs[0]);
381 if (NT_STATUS_IS_ERR(req->status)) {
382 req->state = SMBCLI_REQUEST_ERROR;
383 transport->error.e.nt_status = req->status;
384 transport->error.etype = ETYPE_SMB;
385 if (req->async.fn) {
386 req->async.fn(req);
387 }
388 return;
389 }
390
391 req->nttrans.out.setup_count = num_setup;
392 req->nttrans.out.setup = (uint8_t *)setup;
393
394 req->nttrans.out.params.data = param;
395 req->nttrans.out.params.length = num_param;
396
397 req->nttrans.out.data.data = data;
398 req->nttrans.out.data.length = num_data;
399
400 transport->error.e.nt_status = req->status;
401 if (NT_STATUS_IS_OK(req->status)) {
402 transport->error.etype = ETYPE_NONE;
403 } else {
404 transport->error.etype = ETYPE_SMB;
405 }
406
407 req->state = SMBCLI_REQUEST_DONE;
408 if (req->async.fn) {
409 req->async.fn(req);
410 }
411 }
412
smb_raw_nttrans_recv(struct smbcli_request * req,TALLOC_CTX * mem_ctx,struct smb_nttrans * parms)413 NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req,
414 TALLOC_CTX *mem_ctx,
415 struct smb_nttrans *parms)
416 {
417 if (!smbcli_request_receive(req) ||
418 smbcli_request_is_error(req)) {
419 goto failed;
420 }
421
422 parms->out = req->nttrans.out;
423 talloc_steal(mem_ctx, parms->out.setup);
424 talloc_steal(mem_ctx, parms->out.params.data);
425 talloc_steal(mem_ctx, parms->out.data.data);
426
427 failed:
428 return smbcli_request_destroy(req);
429 }
430
431 /****************************************************************************
432 receive a SMB nttrans response allocating the necessary memory
433 ****************************************************************************/
smb_raw_nttrans(struct smbcli_tree * tree,TALLOC_CTX * mem_ctx,struct smb_nttrans * parms)434 NTSTATUS smb_raw_nttrans(struct smbcli_tree *tree,
435 TALLOC_CTX *mem_ctx,
436 struct smb_nttrans *parms)
437 {
438 struct smbcli_request *req;
439
440 req = smb_raw_nttrans_send(tree, parms);
441 if (!req) {
442 return NT_STATUS_UNSUCCESSFUL;
443 }
444
445 return smb_raw_nttrans_recv(req, mem_ctx, parms);
446 }
447