2 Unix SMB/CIFS implementation.
3 raw trans/trans2/nttrans operations
5 Copyright (C) James Myers 2003 <myersjj@samba.org>
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.
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.
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.
26 check out of bounds for incoming data
28 static BOOL raw_trans_oob(struct cli_request *req,
29 uint_t offset, uint_t count)
37 ptr = req->in.hdr + offset;
39 /* be careful with wraparound! */
40 if (ptr < req->in.data ||
41 ptr >= req->in.data + req->in.data_size ||
42 count > req->in.data_size ||
43 ptr + count > req->in.data + req->in.data_size) {
49 /****************************************************************************
50 receive a SMB trans or trans2 response allocating the necessary memory
51 ****************************************************************************/
52 NTSTATUS smb_raw_trans2_recv(struct cli_request *req,
54 struct smb_trans2 *parms)
61 parms->out.data.length = 0;
62 parms->out.data.data = NULL;
63 parms->out.params.length = 0;
64 parms->out.params.data = NULL;
66 if (!cli_request_receive(req)) {
67 return cli_request_destroy(req);
71 * An NT RPC pipe call can return ERRDOS, ERRmoredata
72 * to a trans call. This is not an error and should not
75 if (NT_STATUS_IS_ERR(req->status)) {
76 return cli_request_destroy(req);
79 CLI_CHECK_MIN_WCT(req, 10);
81 /* parse out the lengths */
82 total_data = SVAL(req->in.vwv, VWV(1));
83 total_param = SVAL(req->in.vwv, VWV(0));
86 if (total_data != 0) {
87 tdata = talloc_realloc(mem_ctx, parms->out.data.data,total_data);
89 DEBUG(0,("smb_raw_receive_trans: failed to enlarge data buffer to %d bytes\n", total_data));
90 req->status = NT_STATUS_NO_MEMORY;
91 return cli_request_destroy(req);
93 parms->out.data.data = tdata;
96 if (total_param != 0) {
97 tparam = talloc_realloc(mem_ctx, parms->out.params.data,total_param);
99 DEBUG(0,("smb_raw_receive_trans: failed to enlarge param buffer to %d bytes\n", total_param));
100 req->status = NT_STATUS_NO_MEMORY;
101 return cli_request_destroy(req);
103 parms->out.params.data = tparam;
106 parms->out.setup_count = SVAL(req->in.vwv, VWV(9));
107 CLI_CHECK_WCT(req, 10 + parms->out.setup_count);
109 if (parms->out.setup_count > 0) {
111 parms->out.setup = talloc(mem_ctx, 2 * parms->out.setup_count);
112 if (!parms->out.setup) {
113 req->status = NT_STATUS_NO_MEMORY;
114 return cli_request_destroy(req);
116 for (i=0;i<parms->out.setup_count;i++) {
117 parms->out.setup[i] = SVAL(req->in.vwv, VWV(10+i));
122 uint16_t param_count, param_ofs, param_disp;
123 uint16_t data_count, data_ofs, data_disp;
124 uint16_t total_data2, total_param2;
126 /* parse out the total lengths again - they can shrink! */
127 total_data2 = SVAL(req->in.vwv, VWV(1));
128 total_param2 = SVAL(req->in.vwv, VWV(0));
130 if (total_data2 > total_data ||
131 total_param2 > total_param) {
132 /* they must *only* shrink */
133 DEBUG(1,("smb_raw_receive_trans: data/params expanded!\n"));
134 req->status = NT_STATUS_BUFFER_TOO_SMALL;
135 return cli_request_destroy(req);
138 total_data = total_data2;
139 total_param = total_param2;
141 /* parse params for this lump */
142 param_count = SVAL(req->in.vwv, VWV(3));
143 param_ofs = SVAL(req->in.vwv, VWV(4));
144 param_disp = SVAL(req->in.vwv, VWV(5));
146 data_count = SVAL(req->in.vwv, VWV(6));
147 data_ofs = SVAL(req->in.vwv, VWV(7));
148 data_disp = SVAL(req->in.vwv, VWV(8));
150 if (data_count + data_disp > total_data ||
151 param_count + param_disp > total_param) {
152 DEBUG(1,("smb_raw_receive_trans: Buffer overflow\n"));
153 req->status = NT_STATUS_BUFFER_TOO_SMALL;
154 return cli_request_destroy(req);
157 /* check the server isn't being nasty */
158 if (raw_trans_oob(req, param_ofs, param_count) ||
159 raw_trans_oob(req, data_ofs, data_count)) {
160 DEBUG(1,("smb_raw_receive_trans: out of bounds parameters!\n"));
161 req->status = NT_STATUS_BUFFER_TOO_SMALL;
162 return cli_request_destroy(req);
166 memcpy(parms->out.data.data + data_disp,
167 req->in.hdr + data_ofs,
172 memcpy(parms->out.params.data + param_disp,
173 req->in.hdr + param_ofs,
177 parms->out.data.length += data_count;
178 parms->out.params.length += param_count;
180 if (total_data <= parms->out.data.length && total_param <= parms->out.params.length)
183 /* to receive more requests we need to mark this request as not received */
184 req->in.buffer = NULL;
186 if (!cli_request_receive(req)) {
187 req->status = NT_STATUS_UNSUCCESSFUL;
188 return cli_request_destroy(req);
193 return cli_request_destroy(req);
196 NTSTATUS smb_raw_trans_recv(struct cli_request *req,
198 struct smb_trans2 *parms)
200 return smb_raw_trans2_recv(req, mem_ctx, parms);
203 /****************************************************************************
204 trans/trans2 raw async interface - only BLOBs used in this interface.
205 note that this doesn't yet support multi-part requests
206 ****************************************************************************/
207 struct cli_request *smb_raw_trans_send_backend(struct cli_tree *tree,
208 struct smb_trans2 *parms,
211 int wct = 14 + parms->in.setup_count;
212 struct cli_request *req;
213 char *outdata,*outparam;
218 if (command == SMBtrans)
223 req = cli_request_setup(tree, command, wct, padding);
228 /* fill in SMB parameters */
229 outparam = req->out.data + padding;
230 outdata = outparam + parms->in.params.length;
232 /* make sure we don't leak data via the padding */
233 memset(req->out.data, 0, padding);
235 if (command == SMBtrans && parms->in.trans_name) {
236 namelen = cli_req_append_string(req, parms->in.trans_name,
240 /* primary request */
241 SSVAL(req->out.vwv,VWV(0),parms->in.params.length);
242 SSVAL(req->out.vwv,VWV(1),parms->in.data.length);
243 SSVAL(req->out.vwv,VWV(2),parms->in.max_param);
244 SSVAL(req->out.vwv,VWV(3),parms->in.max_data);
245 SSVAL(req->out.vwv,VWV(4),parms->in.max_setup);
246 SSVAL(req->out.vwv,VWV(5),parms->in.flags);
247 SIVAL(req->out.vwv,VWV(6),parms->in.timeout);
248 SSVAL(req->out.vwv,VWV(8),0); /* reserved */
249 SSVAL(req->out.vwv,VWV(9),parms->in.params.length);
250 SSVAL(req->out.vwv,VWV(10),PTR_DIFF(outparam,req->out.hdr)+namelen);
251 SSVAL(req->out.vwv,VWV(11),parms->in.data.length);
252 SSVAL(req->out.vwv,VWV(12),PTR_DIFF(outdata,req->out.hdr)+namelen);
253 SSVAL(req->out.vwv,VWV(13),parms->in.setup_count);
254 for (i=0;i<parms->in.setup_count;i++) {
255 SSVAL(req->out.vwv,VWV(14)+i*2,parms->in.setup[i]);
257 if (parms->in.params.data) {
258 cli_req_append_blob(req, &parms->in.params);
260 if (parms->in.data.data) {
261 cli_req_append_blob(req, &parms->in.data);
264 if (!cli_request_send(req)) {
265 cli_request_destroy(req);
272 /****************************************************************************
273 trans/trans2 raw async interface - only BLOBs used in this interface.
274 note that this doesn't yet support multi-part requests
275 ****************************************************************************/
277 struct cli_request *smb_raw_trans_send(struct cli_tree *tree,
278 struct smb_trans2 *parms)
280 return smb_raw_trans_send_backend(tree, parms, SMBtrans);
283 struct cli_request *smb_raw_trans2_send(struct cli_tree *tree,
284 struct smb_trans2 *parms)
286 return smb_raw_trans_send_backend(tree, parms, SMBtrans2);
290 trans2 synchronous blob interface
292 NTSTATUS smb_raw_trans2(struct cli_tree *tree,
294 struct smb_trans2 *parms)
296 struct cli_request *req;
297 req = smb_raw_trans2_send(tree, parms);
298 if (!req) return NT_STATUS_UNSUCCESSFUL;
299 return smb_raw_trans2_recv(req, mem_ctx, parms);
304 trans synchronous blob interface
306 NTSTATUS smb_raw_trans(struct cli_tree *tree,
308 struct smb_trans2 *parms)
310 struct cli_request *req;
311 req = smb_raw_trans_send(tree, parms);
312 if (!req) return NT_STATUS_UNSUCCESSFUL;
313 return smb_raw_trans_recv(req, mem_ctx, parms);
316 /****************************************************************************
317 receive a SMB nttrans response allocating the necessary memory
318 ****************************************************************************/
319 NTSTATUS smb_raw_nttrans_recv(struct cli_request *req,
321 struct smb_nttrans *parms)
323 uint32_t total_data, recvd_data=0;
324 uint32_t total_param, recvd_param=0;
326 if (!cli_request_receive(req) ||
327 cli_request_is_error(req)) {
328 return cli_request_destroy(req);
332 if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) {
333 DEBUG(0,("smb_raw_receive_nttrans: Expected %s response, got command 0x%02x\n",
335 CVAL(req->in.hdr,HDR_COM)));
336 req->status = NT_STATUS_UNSUCCESSFUL;
337 return cli_request_destroy(req);
340 CLI_CHECK_MIN_WCT(req, 18);
342 /* parse out the lengths */
343 total_param = IVAL(req->in.vwv, 3);
344 total_data = IVAL(req->in.vwv, 7);
346 parms->out.data = data_blob_talloc(mem_ctx, NULL, total_data);
347 parms->out.params = data_blob_talloc(mem_ctx, NULL, total_param);
349 if (parms->out.data.length != total_data ||
350 parms->out.params.length != total_param) {
351 req->status = NT_STATUS_NO_MEMORY;
352 return cli_request_destroy(req);
355 parms->out.setup_count = CVAL(req->in.vwv, 35);
356 CLI_CHECK_WCT(req, 18 + parms->out.setup_count);
358 if (parms->out.setup_count > 0) {
360 parms->out.setup = talloc(mem_ctx, 2 * parms->out.setup_count);
361 if (!parms->out.setup) {
362 req->status = NT_STATUS_NO_MEMORY;
363 return cli_request_destroy(req);
365 for (i=0;i<parms->out.setup_count;i++) {
366 parms->out.setup[i] = SVAL(req->in.vwv, VWV(18+i));
370 while (recvd_data < total_data ||
371 recvd_param < total_param) {
372 uint32_t param_count, param_ofs, param_disp;
373 uint32_t data_count, data_ofs, data_disp;
374 uint32_t total_data2, total_param2;
376 /* parse out the total lengths again - they can shrink! */
377 total_param2 = IVAL(req->in.vwv, 3);
378 total_data2 = IVAL(req->in.vwv, 7);
380 if (total_data2 > total_data ||
381 total_param2 > total_param) {
382 /* they must *only* shrink */
383 DEBUG(1,("smb_raw_receive_nttrans: data/params expanded!\n"));
384 req->status = NT_STATUS_BUFFER_TOO_SMALL;
385 return cli_request_destroy(req);
388 total_data = total_data2;
389 total_param = total_param2;
390 parms->out.data.length = total_data;
391 parms->out.params.length = total_param;
393 /* parse params for this lump */
394 param_count = IVAL(req->in.vwv, 11);
395 param_ofs = IVAL(req->in.vwv, 15);
396 param_disp = IVAL(req->in.vwv, 19);
398 data_count = IVAL(req->in.vwv, 23);
399 data_ofs = IVAL(req->in.vwv, 27);
400 data_disp = IVAL(req->in.vwv, 31);
402 if (data_count + data_disp > total_data ||
403 param_count + param_disp > total_param) {
404 DEBUG(1,("smb_raw_receive_nttrans: Buffer overflow\n"));
405 req->status = NT_STATUS_BUFFER_TOO_SMALL;
406 return cli_request_destroy(req);
409 /* check the server isn't being nasty */
410 if (raw_trans_oob(req, param_ofs, param_count) ||
411 raw_trans_oob(req, data_ofs, data_count)) {
412 DEBUG(1,("smb_raw_receive_nttrans: out of bounds parameters!\n"));
413 req->status = NT_STATUS_BUFFER_TOO_SMALL;
414 return cli_request_destroy(req);
418 memcpy(parms->out.data.data + data_disp,
419 req->in.hdr + data_ofs,
424 memcpy(parms->out.params.data + param_disp,
425 req->in.hdr + param_ofs,
429 recvd_param += param_count;
430 recvd_data += data_count;
432 if (recvd_data >= total_data &&
433 recvd_param >= total_param) {
437 if (!cli_request_receive(req) ||
438 cli_request_is_error(req)) {
439 return cli_request_destroy(req);
443 if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) {
444 DEBUG(0,("smb_raw_receive_nttrans: Expected nttranss, got command 0x%02x\n",
445 CVAL(req->in.hdr, HDR_COM)));
446 req->status = NT_STATUS_UNSUCCESSFUL;
447 return cli_request_destroy(req);
452 return cli_request_destroy(req);
456 /****************************************************************************
457 nttrans raw - only BLOBs used in this interface.
458 at the moment we only handle a single primary request
459 ****************************************************************************/
460 struct cli_request *smb_raw_nttrans_send(struct cli_tree *tree,
461 struct smb_nttrans *parms)
463 struct cli_request *req;
464 char *outdata, *outparam;
468 /* only align if there are parameters or data */
469 if (parms->in.params.length || parms->in.data.length) {
473 req = cli_request_setup(tree, SMBnttrans,
474 19 + parms->in.setup_count,
476 parms->in.params.length +
477 parms->in.data.length);
482 /* fill in SMB parameters */
483 outparam = req->out.data + align;
484 outdata = outparam + parms->in.params.length;
486 SCVAL(req->out.vwv, 0, parms->in.max_setup);
487 SSVAL(req->out.vwv, 1, 0); /* reserved */
488 SIVAL(req->out.vwv, 3, parms->in.params.length);
489 SIVAL(req->out.vwv, 7, parms->in.data.length);
490 SIVAL(req->out.vwv, 11, parms->in.max_param);
491 SIVAL(req->out.vwv, 15, parms->in.max_data);
492 SIVAL(req->out.vwv, 19, parms->in.params.length);
493 SIVAL(req->out.vwv, 23, PTR_DIFF(outparam,req->out.hdr));
494 SIVAL(req->out.vwv, 27, parms->in.data.length);
495 SIVAL(req->out.vwv, 31, PTR_DIFF(outdata,req->out.hdr));
496 SCVAL(req->out.vwv, 35, parms->in.setup_count);
497 SSVAL(req->out.vwv, 36, parms->in.function);
498 for (i=0;i<parms->in.setup_count;i++) {
499 SSVAL(req->out.vwv,VWV(19+i),parms->in.setup[i]);
501 if (parms->in.params.length) {
502 memcpy(outparam, parms->in.params.data, parms->in.params.length);
504 if (parms->in.data.length) {
505 memcpy(outparam, parms->in.data.data, parms->in.data.length);
508 if (!cli_request_send(req)) {
509 cli_request_destroy(req);
517 /****************************************************************************
518 receive a SMB nttrans response allocating the necessary memory
519 ****************************************************************************/
520 NTSTATUS smb_raw_nttrans(struct cli_tree *tree,
522 struct smb_nttrans *parms)
524 struct cli_request *req;
526 req = smb_raw_nttrans_send(tree, parms);
528 return NT_STATUS_UNSUCCESSFUL;
531 return smb_raw_nttrans_recv(req, mem_ctx, parms);