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 					 &param,
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 					 &param,
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