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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 
22 #include "includes.h"
23 #include "lib/util/dlinklist.h"
24 #include "libcli/raw/libcliraw.h"
25 
26 #define TORTURE_TRANS_DATA 0
27 
28 /*
29   check out of bounds for incoming data
30 */
raw_trans_oob(struct smbcli_request * req,uint_t offset,uint_t count)31 static BOOL raw_trans_oob(struct smbcli_request *req,
32 			  uint_t offset, uint_t count)
33 {
34 	uint8_t *ptr;
35 
36 	if (count == 0) {
37 		return False;
38 	}
39 
40 	ptr = req->in.hdr + offset;
41 
42 	/* be careful with wraparound! */
43 	if (ptr < req->in.data ||
44 	    ptr >= req->in.data + req->in.data_size ||
45 	    count > req->in.data_size ||
46 	    ptr + count > req->in.data + req->in.data_size) {
47 		return True;
48 	}
49 	return False;
50 }
51 
52 /****************************************************************************
53   receive a SMB trans or trans2 response allocating the necessary memory
54   ****************************************************************************/
smb_raw_trans2_recv(struct smbcli_request * req,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)55 NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req,
56 			     TALLOC_CTX *mem_ctx,
57 			     struct smb_trans2 *parms)
58 {
59 	int total_data=0;
60 	int total_param=0;
61 	uint8_t *tdata;
62 	uint8_t *tparam;
63 
64 	parms->out.data.length = 0;
65 	parms->out.data.data = NULL;
66 	parms->out.params.length = 0;
67 	parms->out.params.data = NULL;
68 
69 	if (!smbcli_request_receive(req)) {
70 		return smbcli_request_destroy(req);
71 	}
72 
73 	/*
74 	 * An NT RPC pipe call can return ERRDOS, ERRmoredata
75 	 * to a trans call. This is not an error and should not
76 	 * be treated as such.
77 	 */
78 	if (NT_STATUS_IS_ERR(req->status)) {
79 		return smbcli_request_destroy(req);
80 	}
81 
82 	SMBCLI_CHECK_MIN_WCT(req, 10);
83 
84 	/* parse out the lengths */
85 	total_data = SVAL(req->in.vwv, VWV(1));
86 	total_param = SVAL(req->in.vwv, VWV(0));
87 
88 	/* allocate it */
89 	if (total_data != 0) {
90 		tdata = talloc_size(mem_ctx, total_data);
91 		if (!tdata) {
92 			DEBUG(0,("smb_raw_receive_trans: failed to enlarge data buffer to %d bytes\n", total_data));
93 			req->status = NT_STATUS_NO_MEMORY;
94 			return smbcli_request_destroy(req);
95 		}
96 		parms->out.data.data = tdata;
97 	}
98 
99 	if (total_param != 0) {
100 		tparam = talloc_size(mem_ctx, total_param);
101 		if (!tparam) {
102 			DEBUG(0,("smb_raw_receive_trans: failed to enlarge param buffer to %d bytes\n", total_param));
103 			req->status = NT_STATUS_NO_MEMORY;
104 			return smbcli_request_destroy(req);
105 		}
106 		parms->out.params.data = tparam;
107 	}
108 
109 	parms->out.setup_count = SVAL(req->in.vwv, VWV(9));
110 	SMBCLI_CHECK_WCT(req, 10 + parms->out.setup_count);
111 
112 	if (parms->out.setup_count > 0) {
113 		int i;
114 		parms->out.setup = talloc_array(mem_ctx, uint16_t, parms->out.setup_count);
115 		if (!parms->out.setup) {
116 			req->status = NT_STATUS_NO_MEMORY;
117 			return smbcli_request_destroy(req);
118 		}
119 		for (i=0;i<parms->out.setup_count;i++) {
120 			parms->out.setup[i] = SVAL(req->in.vwv, VWV(10+i));
121 		}
122 	}
123 
124 	while (1)  {
125 		uint16_t param_count, param_ofs, param_disp;
126 		uint16_t data_count, data_ofs, data_disp;
127 		uint16_t total_data2, total_param2;
128 
129 		/* parse out the total lengths again - they can shrink! */
130 		total_data2 = SVAL(req->in.vwv, VWV(1));
131 		total_param2 = SVAL(req->in.vwv, VWV(0));
132 
133 		if (total_data2 > total_data ||
134 		    total_param2 > total_param) {
135 			/* they must *only* shrink */
136 			DEBUG(1,("smb_raw_receive_trans: data/params expanded!\n"));
137 			req->status = NT_STATUS_BUFFER_TOO_SMALL;
138 			return smbcli_request_destroy(req);
139 		}
140 
141 		total_data = total_data2;
142 		total_param = total_param2;
143 
144 		/* parse params for this lump */
145 		param_count = SVAL(req->in.vwv, VWV(3));
146 		param_ofs   = SVAL(req->in.vwv, VWV(4));
147 		param_disp  = SVAL(req->in.vwv, VWV(5));
148 
149 		data_count = SVAL(req->in.vwv, VWV(6));
150 		data_ofs   = SVAL(req->in.vwv, VWV(7));
151 		data_disp  = SVAL(req->in.vwv, VWV(8));
152 
153 		if (data_count + data_disp > total_data ||
154 		    param_count + param_disp > total_param) {
155 			DEBUG(1,("smb_raw_receive_trans: Buffer overflow\n"));
156 			req->status = NT_STATUS_BUFFER_TOO_SMALL;
157 			return smbcli_request_destroy(req);
158 		}
159 
160 		/* check the server isn't being nasty */
161 		if (raw_trans_oob(req, param_ofs, param_count) ||
162 		    raw_trans_oob(req, data_ofs, data_count)) {
163 			DEBUG(1,("smb_raw_receive_trans: out of bounds parameters!\n"));
164 			req->status = NT_STATUS_BUFFER_TOO_SMALL;
165 			return smbcli_request_destroy(req);
166 		}
167 
168 		if (data_count) {
169 			memcpy(parms->out.data.data + data_disp,
170 			       req->in.hdr + data_ofs,
171 			       data_count);
172 		}
173 
174 		if (param_count) {
175 			memcpy(parms->out.params.data + param_disp,
176 			       req->in.hdr + param_ofs,
177 			       param_count);
178 		}
179 
180 		parms->out.data.length += data_count;
181 		parms->out.params.length += param_count;
182 
183 		if (total_data <= parms->out.data.length && total_param <= parms->out.params.length)
184 			break;
185 
186 		if (!smbcli_request_receive_more(req)) {
187 			req->status = NT_STATUS_UNSUCCESSFUL;
188 			return smbcli_request_destroy(req);
189 		}
190 	}
191 
192 failed:
193 	return smbcli_request_destroy(req);
194 }
195 
smb_raw_trans_recv(struct smbcli_request * req,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)196 NTSTATUS smb_raw_trans_recv(struct smbcli_request *req,
197 			     TALLOC_CTX *mem_ctx,
198 			     struct smb_trans2 *parms)
199 {
200 	return smb_raw_trans2_recv(req, mem_ctx, parms);
201 }
202 
203 
204 /*
205   trans/trans2 raw async interface - only BLOBs used in this interface.
206 */
smb_raw_trans_send_backend(struct smbcli_tree * tree,struct smb_trans2 * parms,uint8_t command)207 struct smbcli_request *smb_raw_trans_send_backend(struct smbcli_tree *tree,
208 						  struct smb_trans2 *parms,
209 						  uint8_t command)
210 {
211 	int wct = 14 + parms->in.setup_count;
212 	struct smbcli_request *req, *req2;
213 	uint8_t *outdata,*outparam;
214 	int i;
215 	int padding;
216 	size_t namelen = 0;
217 	uint16_t data_disp, data_length, max_data;
218 
219 	if (parms->in.params.length > UINT16_MAX ||
220 	    parms->in.data.length > UINT16_MAX) {
221 		DEBUG(3,("Attempt to send invalid trans2 request (params %u, data %u)\n",
222 			 (unsigned)parms->in.params.length, (unsigned)parms->in.data.length));
223 		return NULL;
224 	}
225 
226 
227 	if (command == SMBtrans)
228 		padding = 1;
229 	else
230 		padding = 3;
231 
232 	req = smbcli_request_setup(tree, command, wct, padding);
233 	if (!req) {
234 		return NULL;
235 	}
236 
237 	/* Watch out, this changes the req->out.* pointers */
238 	if (command == SMBtrans && parms->in.trans_name) {
239 		namelen = smbcli_req_append_string(req, parms->in.trans_name,
240 						STR_TERMINATE);
241 	}
242 
243 	/* fill in SMB parameters */
244 	outparam = req->out.data + padding;
245 	outdata = outparam + parms->in.params.length;
246 
247 	/* make sure we don't leak data via the padding */
248 	memset(req->out.data, 0, padding);
249 
250 	data_length = parms->in.data.length;
251 
252 	max_data = smb_raw_max_trans_data(tree, parms->in.params.length);
253 	if (max_data < data_length) {
254 		data_length = max_data;
255 	}
256 
257 #if TORTURE_TRANS_DATA
258 	if (data_length > 1) {
259 		data_length /= 2;
260 	}
261 #endif
262 
263 	/* primary request */
264 	SSVAL(req->out.vwv,VWV(0),parms->in.params.length);
265 	SSVAL(req->out.vwv,VWV(1),parms->in.data.length);
266 	SSVAL(req->out.vwv,VWV(2),parms->in.max_param);
267 	SSVAL(req->out.vwv,VWV(3),parms->in.max_data);
268 	SSVAL(req->out.vwv,VWV(4),parms->in.max_setup);
269 	SSVAL(req->out.vwv,VWV(5),parms->in.flags);
270 	SIVAL(req->out.vwv,VWV(6),parms->in.timeout);
271 	SSVAL(req->out.vwv,VWV(8),0); /* reserved */
272 	SSVAL(req->out.vwv,VWV(9),parms->in.params.length);
273 	SSVAL(req->out.vwv,VWV(10),PTR_DIFF(outparam,req->out.hdr)+namelen);
274 	SSVAL(req->out.vwv,VWV(11),data_length);
275 	SSVAL(req->out.vwv,VWV(12),PTR_DIFF(outdata,req->out.hdr)+namelen);
276 	SSVAL(req->out.vwv,VWV(13),parms->in.setup_count);
277 	for (i=0;i<parms->in.setup_count;i++)	{
278 		SSVAL(req->out.vwv,VWV(14)+i*2,parms->in.setup[i]);
279 	}
280 	if (parms->in.params.data)	{
281 		smbcli_req_append_blob(req, &parms->in.params);
282 	}
283 	if (parms->in.data.data) {
284 		DATA_BLOB data;
285 		data.data = parms->in.data.data;
286 		data.length = data_length;
287 		smbcli_req_append_blob(req, &data);
288 	}
289 
290 	if (!smbcli_request_send(req)) {
291 		smbcli_request_destroy(req);
292 		return NULL;
293 	}
294 
295 	data_disp = data_length;
296 
297 
298 	if (data_disp != parms->in.data.length) {
299 		/* TODO: this should be done asynchronously .... */
300 		if (!smbcli_request_receive(req) ||
301 		    !NT_STATUS_IS_OK(req->status)) {
302 			return req;
303 		}
304 
305 		req->state = SMBCLI_REQUEST_RECV;
306 		DLIST_ADD(req->transport->pending_recv, req);
307 	}
308 
309 
310 	while (data_disp != parms->in.data.length) {
311 		data_length = parms->in.data.length - data_disp;
312 
313 		max_data = smb_raw_max_trans_data(tree, 0);
314 		if (max_data < data_length) {
315 			data_length = max_data;
316 		}
317 
318 #if TORTURE_TRANS_DATA
319 		if (data_length > 1) {
320 			data_length /= 2;
321 		}
322 #endif
323 
324 		req2 = smbcli_request_setup(tree, command+1, 9, data_length);
325 		if (!req2) {
326 			return NULL;
327 		}
328 		req2->mid = req->mid;
329 		SSVAL(req2->out.hdr, HDR_MID, req2->mid);
330 
331 		outdata = req2->out.data;
332 
333 		SSVAL(req2->out.vwv,VWV(0), parms->in.params.length);
334 		SSVAL(req2->out.vwv,VWV(1), parms->in.data.length);
335 		SSVAL(req2->out.vwv,VWV(2), 0);
336 		SSVAL(req2->out.vwv,VWV(3), 0);
337 		SSVAL(req2->out.vwv,VWV(4), 0);
338 		SSVAL(req2->out.vwv,VWV(5), data_length);
339 		SSVAL(req2->out.vwv,VWV(6), PTR_DIFF(outdata,req2->out.hdr));
340 		SSVAL(req2->out.vwv,VWV(7), data_disp);
341 		SSVAL(req2->out.vwv,VWV(8), 0xFFFF);
342 
343 		if (data_length != 0) {
344 			memcpy(req2->out.data, parms->in.data.data + data_disp,
345 			       data_length);
346 		}
347 
348 		data_disp += data_length;
349 
350 		req2->one_way_request = 1;
351 
352 		if (!smbcli_request_send(req2)) {
353 			smbcli_request_destroy(req2);
354 			return NULL;
355 		}
356 
357 		req->seq_num = req2->seq_num;
358 	}
359 
360 
361 	return req;
362 }
363 
364 
365 /*
366   trans/trans2 raw async interface - only BLOBs used in this interface.
367   note that this doesn't yet support multi-part requests
368 */
smb_raw_trans_send(struct smbcli_tree * tree,struct smb_trans2 * parms)369 struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree,
370 				       struct smb_trans2 *parms)
371 {
372 	return smb_raw_trans_send_backend(tree, parms, SMBtrans);
373 }
374 
smb_raw_trans2_send(struct smbcli_tree * tree,struct smb_trans2 * parms)375 struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree,
376 				       struct smb_trans2 *parms)
377 {
378 	return smb_raw_trans_send_backend(tree, parms, SMBtrans2);
379 }
380 
381 /*
382   trans2 synchronous blob interface
383 */
smb_raw_trans2(struct smbcli_tree * tree,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)384 NTSTATUS smb_raw_trans2(struct smbcli_tree *tree,
385 			TALLOC_CTX *mem_ctx,
386 			struct smb_trans2 *parms)
387 {
388 	struct smbcli_request *req;
389 	req = smb_raw_trans2_send(tree, parms);
390 	if (!req) return NT_STATUS_UNSUCCESSFUL;
391 	return smb_raw_trans2_recv(req, mem_ctx, parms);
392 }
393 
394 
395 /*
396   trans synchronous blob interface
397 */
smb_raw_trans(struct smbcli_tree * tree,TALLOC_CTX * mem_ctx,struct smb_trans2 * parms)398 NTSTATUS smb_raw_trans(struct smbcli_tree *tree,
399 		       TALLOC_CTX *mem_ctx,
400 		       struct smb_trans2 *parms)
401 {
402 	struct smbcli_request *req;
403 	req = smb_raw_trans_send(tree, parms);
404 	if (!req) return NT_STATUS_UNSUCCESSFUL;
405 	return smb_raw_trans_recv(req, mem_ctx, parms);
406 }
407 
408 
409 /****************************************************************************
410   receive a SMB nttrans response allocating the necessary memory
411   ****************************************************************************/
smb_raw_nttrans_recv(struct smbcli_request * req,TALLOC_CTX * mem_ctx,struct smb_nttrans * parms)412 NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req,
413 			      TALLOC_CTX *mem_ctx,
414 			      struct smb_nttrans *parms)
415 {
416 	uint32_t total_data, recvd_data=0;
417 	uint32_t total_param, recvd_param=0;
418 
419 	if (!smbcli_request_receive(req) ||
420 	    smbcli_request_is_error(req)) {
421 		return smbcli_request_destroy(req);
422 	}
423 
424 	/* sanity check */
425 	if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) {
426 		DEBUG(0,("smb_raw_receive_nttrans: Expected %s response, got command 0x%02x\n",
427 			 "SMBnttrans",
428 			 CVAL(req->in.hdr,HDR_COM)));
429 		req->status = NT_STATUS_UNSUCCESSFUL;
430 		return smbcli_request_destroy(req);
431 	}
432 
433 	SMBCLI_CHECK_MIN_WCT(req, 18);
434 
435 	/* parse out the lengths */
436 	total_param = IVAL(req->in.vwv, 3);
437 	total_data  = IVAL(req->in.vwv, 7);
438 
439 	parms->out.data = data_blob_talloc(mem_ctx, NULL, total_data);
440 	parms->out.params = data_blob_talloc(mem_ctx, NULL, total_param);
441 
442 	if (parms->out.data.length != total_data ||
443 	    parms->out.params.length != total_param) {
444 		req->status = NT_STATUS_NO_MEMORY;
445 		return smbcli_request_destroy(req);
446 	}
447 
448 	parms->out.setup_count = CVAL(req->in.vwv, 35);
449 	SMBCLI_CHECK_WCT(req, 18 + parms->out.setup_count);
450 
451 	if (parms->out.setup_count > 0) {
452 		int i;
453 		parms->out.setup = talloc_array(mem_ctx, uint16_t, parms->out.setup_count);
454 		if (!parms->out.setup) {
455 			req->status = NT_STATUS_NO_MEMORY;
456 			return smbcli_request_destroy(req);
457 		}
458 		for (i=0;i<parms->out.setup_count;i++) {
459 			parms->out.setup[i] = SVAL(req->in.vwv, VWV(18+i));
460 		}
461 	}
462 
463 	while (recvd_data < total_data ||
464 	       recvd_param < total_param)  {
465 		uint32_t param_count, param_ofs, param_disp;
466 		uint32_t data_count, data_ofs, data_disp;
467 		uint32_t total_data2, total_param2;
468 
469 		/* parse out the total lengths again - they can shrink! */
470 		total_param2 = IVAL(req->in.vwv, 3);
471 		total_data2  = IVAL(req->in.vwv, 7);
472 
473 		if (total_data2 > total_data ||
474 		    total_param2 > total_param) {
475 			/* they must *only* shrink */
476 			DEBUG(1,("smb_raw_receive_nttrans: data/params expanded!\n"));
477 			req->status = NT_STATUS_BUFFER_TOO_SMALL;
478 			return smbcli_request_destroy(req);
479 		}
480 
481 		total_data = total_data2;
482 		total_param = total_param2;
483 		parms->out.data.length = total_data;
484 		parms->out.params.length = total_param;
485 
486 		/* parse params for this lump */
487 		param_count = IVAL(req->in.vwv, 11);
488 		param_ofs   = IVAL(req->in.vwv, 15);
489 		param_disp  = IVAL(req->in.vwv, 19);
490 
491 		data_count = IVAL(req->in.vwv, 23);
492 		data_ofs   = IVAL(req->in.vwv, 27);
493 		data_disp  = IVAL(req->in.vwv, 31);
494 
495 		if (data_count + data_disp > total_data ||
496 		    param_count + param_disp > total_param) {
497 			DEBUG(1,("smb_raw_receive_nttrans: Buffer overflow\n"));
498 			req->status = NT_STATUS_BUFFER_TOO_SMALL;
499 			return smbcli_request_destroy(req);
500 		}
501 
502 		/* check the server isn't being nasty */
503 		if (raw_trans_oob(req, param_ofs, param_count) ||
504 		    raw_trans_oob(req, data_ofs, data_count)) {
505 			DEBUG(1,("smb_raw_receive_nttrans: out of bounds parameters!\n"));
506 			req->status = NT_STATUS_BUFFER_TOO_SMALL;
507 			return smbcli_request_destroy(req);
508 		}
509 
510 		if (data_count) {
511 			memcpy(parms->out.data.data + data_disp,
512 			       req->in.hdr + data_ofs,
513 			       data_count);
514 		}
515 
516 		if (param_count) {
517 			memcpy(parms->out.params.data + param_disp,
518 			       req->in.hdr + param_ofs,
519 			       param_count);
520 		}
521 
522 		recvd_param += param_count;
523 		recvd_data += data_count;
524 
525 		if (recvd_data >= total_data &&
526 		    recvd_param >= total_param) {
527 			break;
528 		}
529 
530 		if (!smbcli_request_receive(req) ||
531 		    smbcli_request_is_error(req)) {
532 			return smbcli_request_destroy(req);
533 		}
534 
535 		/* sanity check */
536 		if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) {
537 			DEBUG(0,("smb_raw_receive_nttrans: Expected nttranss, got command 0x%02x\n",
538 				 CVAL(req->in.hdr, HDR_COM)));
539 			req->status = NT_STATUS_UNSUCCESSFUL;
540 			return smbcli_request_destroy(req);
541 		}
542 	}
543 
544 failed:
545 	return smbcli_request_destroy(req);
546 }
547 
548 
549 /****************************************************************************
550  nttrans raw - only BLOBs used in this interface.
551  at the moment we only handle a single primary request
552 ****************************************************************************/
smb_raw_nttrans_send(struct smbcli_tree * tree,struct smb_nttrans * parms)553 struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
554 					 struct smb_nttrans *parms)
555 {
556 	struct smbcli_request *req;
557 	uint8_t *outdata, *outparam;
558 	int i;
559 	int align = 0;
560 
561 	/* only align if there are parameters or data */
562 	if (parms->in.params.length || parms->in.data.length) {
563 		align = 3;
564 	}
565 
566 	req = smbcli_request_setup(tree, SMBnttrans,
567 				19 + parms->in.setup_count,
568 				align +
569 				parms->in.params.length +
570 				parms->in.data.length);
571 	if (!req) {
572 		return NULL;
573 	}
574 
575 	/* fill in SMB parameters */
576 	outparam = req->out.data + align;
577 	outdata = outparam + parms->in.params.length;
578 
579 	if (align != 0) {
580 		memset(req->out.data, 0, align);
581 	}
582 
583 	SCVAL(req->out.vwv,  0, parms->in.max_setup);
584 	SSVAL(req->out.vwv,  1, 0); /* reserved */
585 	SIVAL(req->out.vwv,  3, parms->in.params.length);
586 	SIVAL(req->out.vwv,  7, parms->in.data.length);
587 	SIVAL(req->out.vwv, 11, parms->in.max_param);
588 	SIVAL(req->out.vwv, 15, parms->in.max_data);
589 	SIVAL(req->out.vwv, 19, parms->in.params.length);
590 	SIVAL(req->out.vwv, 23, PTR_DIFF(outparam,req->out.hdr));
591 	SIVAL(req->out.vwv, 27, parms->in.data.length);
592 	SIVAL(req->out.vwv, 31, PTR_DIFF(outdata,req->out.hdr));
593 	SCVAL(req->out.vwv, 35, parms->in.setup_count);
594 	SSVAL(req->out.vwv, 36, parms->in.function);
595 	for (i=0;i<parms->in.setup_count;i++) {
596 		SSVAL(req->out.vwv,VWV(19+i),parms->in.setup[i]);
597 	}
598 	if (parms->in.params.length) {
599 		memcpy(outparam, parms->in.params.data, parms->in.params.length);
600 	}
601 	if (parms->in.data.length) {
602 		memcpy(outdata, parms->in.data.data, parms->in.data.length);
603 	}
604 
605 	if (!smbcli_request_send(req)) {
606 		smbcli_request_destroy(req);
607 		return NULL;
608 	}
609 
610 	return req;
611 }
612 
613 
614 /****************************************************************************
615   receive a SMB nttrans response allocating the necessary memory
616   ****************************************************************************/
smb_raw_nttrans(struct smbcli_tree * tree,TALLOC_CTX * mem_ctx,struct smb_nttrans * parms)617 NTSTATUS smb_raw_nttrans(struct smbcli_tree *tree,
618 			 TALLOC_CTX *mem_ctx,
619 			 struct smb_nttrans *parms)
620 {
621 	struct smbcli_request *req;
622 
623 	req = smb_raw_nttrans_send(tree, parms);
624 	if (!req) {
625 		return NT_STATUS_UNSUCCESSFUL;
626 	}
627 
628 	return smb_raw_nttrans_recv(req, mem_ctx, parms);
629 }
630 
631 /*
632   work out the maximum data size for a trans request while avoiding
633   multi-part replies
634 
635   TODO: we only need to avoid multi-part replies because the
636   multi-part trans receive code is broken.
637 */
smb_raw_max_trans_data(struct smbcli_tree * tree,size_t param_size)638 size_t smb_raw_max_trans_data(struct smbcli_tree *tree, size_t param_size)
639 {
640 	return tree->session->transport->negotiate.max_xmit - (70 + param_size);
641 }
642