s3:smb2_ioctl: add some more validation checks
[Samba/gebeck_regimport.git] / source3 / smbd / smb2_ioctl.c
blob521b13119e7c8ed38dfa4a75a807018208e71cbe
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
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.
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, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../lib/util/tevent_ntstatus.h"
26 #include "rpc_server/srv_pipe_hnd.h"
27 #include "include/ntioctl.h"
28 #include "../librpc/ndr/libndr.h"
30 static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx,
31 struct tevent_context *ev,
32 struct smbd_smb2_request *smb2req,
33 uint32_t in_ctl_code,
34 uint64_t in_file_id_volatile,
35 DATA_BLOB in_input,
36 uint32_t in_max_output,
37 uint32_t in_flags);
38 static NTSTATUS smbd_smb2_ioctl_recv(struct tevent_req *req,
39 TALLOC_CTX *mem_ctx,
40 DATA_BLOB *out_output,
41 bool *disconnect);
43 static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq);
44 NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
46 NTSTATUS status;
47 const uint8_t *inbody;
48 int i = req->current_idx;
49 uint32_t in_ctl_code;
50 uint64_t in_file_id_persistent;
51 uint64_t in_file_id_volatile;
52 uint32_t in_input_offset;
53 uint32_t in_input_length;
54 DATA_BLOB in_input_buffer;
55 uint32_t in_max_output_length;
56 uint32_t in_flags;
57 struct tevent_req *subreq;
59 status = smbd_smb2_request_verify_sizes(req, 0x39);
60 if (!NT_STATUS_IS_OK(status)) {
61 return smbd_smb2_request_error(req, status);
63 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
65 in_ctl_code = IVAL(inbody, 0x04);
66 in_file_id_persistent = BVAL(inbody, 0x08);
67 in_file_id_volatile = BVAL(inbody, 0x10);
68 in_input_offset = IVAL(inbody, 0x18);
69 in_input_length = IVAL(inbody, 0x1C);
70 in_max_output_length = IVAL(inbody, 0x2C);
71 in_flags = IVAL(inbody, 0x30);
74 * InputOffset (4 bytes): The offset, in bytes, from the beginning of
75 * the SMB2 header to the input data buffer. If no input data is
76 * required for the FSCTL/IOCTL command being issued, the client SHOULD
77 * set this value to 0.<49>
78 * <49> If no input data is required for the FSCTL/IOCTL command being
79 * issued, Windows-based clients set this field to any value.
81 if ((in_input_length > 0)
82 && (in_input_offset != (SMB2_HDR_BODY + req->in.vector[i+1].iov_len))) {
83 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
86 if (in_input_length > req->in.vector[i+2].iov_len) {
87 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
90 in_input_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
91 in_input_buffer.length = in_input_length;
94 * If the Flags field of the request is not SMB2_0_IOCTL_IS_FSCTL the
95 * server MUST fail the request with STATUS_NOT_SUPPORTED.
97 if (in_flags != SMB2_IOCTL_FLAG_IS_FSCTL) {
98 return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED);
101 switch (in_ctl_code) {
102 case FSCTL_DFS_GET_REFERRALS:
103 case FSCTL_DFS_GET_REFERRALS_EX:
104 case FSCTL_PIPE_WAIT:
105 case FSCTL_VALIDATE_NEGOTIATE_INFO_224:
106 case FSCTL_VALIDATE_NEGOTIATE_INFO:
107 case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
109 * Some SMB2 specific CtlCodes like FSCTL_DFS_GET_REFERRALS or
110 * FSCTL_PIPE_WAIT does not take a file handle.
112 * If FileId in the SMB2 Header of the request is not
113 * 0xFFFFFFFFFFFFFFFF, then the server MUST fail the request
114 * with STATUS_INVALID_PARAMETER.
116 if (in_file_id_persistent != UINT64_MAX ||
117 in_file_id_volatile != UINT64_MAX) {
118 return smbd_smb2_request_error(req,
119 NT_STATUS_INVALID_PARAMETER);
121 break;
122 default:
123 if (req->compat_chain_fsp) {
124 /* skip check */
125 } else if (in_file_id_persistent != in_file_id_volatile) {
126 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
128 break;
131 subreq = smbd_smb2_ioctl_send(req,
132 req->sconn->ev_ctx,
133 req,
134 in_ctl_code,
135 in_file_id_volatile,
136 in_input_buffer,
137 in_max_output_length,
138 in_flags);
139 if (subreq == NULL) {
140 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
142 tevent_req_set_callback(subreq, smbd_smb2_request_ioctl_done, req);
144 return smbd_smb2_request_pending_queue(req, subreq, 1000);
147 static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq)
149 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
150 struct smbd_smb2_request);
151 const uint8_t *inbody;
152 int i = req->current_idx;
153 DATA_BLOB outbody;
154 DATA_BLOB outdyn;
155 uint32_t in_ctl_code;
156 uint64_t in_file_id_persistent;
157 uint64_t in_file_id_volatile;
158 uint32_t out_input_offset;
159 uint32_t out_output_offset;
160 DATA_BLOB out_output_buffer = data_blob_null;
161 NTSTATUS status;
162 NTSTATUS error; /* transport error */
163 bool disconnect = false;
165 status = smbd_smb2_ioctl_recv(subreq, req,
166 &out_output_buffer,
167 &disconnect);
169 DEBUG(10,("smbd_smb2_request_ioctl_done: smbd_smb2_ioctl_recv returned "
170 "%u status %s\n",
171 (unsigned int)out_output_buffer.length,
172 nt_errstr(status) ));
174 TALLOC_FREE(subreq);
175 if (disconnect) {
176 error = status;
177 smbd_server_connection_terminate(req->sconn,
178 nt_errstr(error));
179 return;
182 if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
183 /* also ok */
184 } else if (!NT_STATUS_IS_OK(status)) {
185 error = smbd_smb2_request_error(req, status);
186 if (!NT_STATUS_IS_OK(error)) {
187 smbd_server_connection_terminate(req->sconn,
188 nt_errstr(error));
189 return;
191 return;
194 out_input_offset = SMB2_HDR_BODY + 0x30;
195 out_output_offset = SMB2_HDR_BODY + 0x30;
197 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
199 in_ctl_code = IVAL(inbody, 0x04);
200 in_file_id_persistent = BVAL(inbody, 0x08);
201 in_file_id_volatile = BVAL(inbody, 0x10);
203 outbody = data_blob_talloc(req->out.vector, NULL, 0x30);
204 if (outbody.data == NULL) {
205 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
206 if (!NT_STATUS_IS_OK(error)) {
207 smbd_server_connection_terminate(req->sconn,
208 nt_errstr(error));
209 return;
211 return;
214 SSVAL(outbody.data, 0x00, 0x30 + 1); /* struct size */
215 SSVAL(outbody.data, 0x02, 0); /* reserved */
216 SIVAL(outbody.data, 0x04,
217 in_ctl_code); /* ctl code */
218 SBVAL(outbody.data, 0x08,
219 in_file_id_persistent); /* file id (persistent) */
220 SBVAL(outbody.data, 0x10,
221 in_file_id_volatile); /* file id (volatile) */
222 SIVAL(outbody.data, 0x18,
223 out_input_offset); /* input offset */
224 SIVAL(outbody.data, 0x1C, 0); /* input count */
225 SIVAL(outbody.data, 0x20,
226 out_output_offset); /* output offset */
227 SIVAL(outbody.data, 0x24,
228 out_output_buffer.length); /* output count */
229 SIVAL(outbody.data, 0x28, 0); /* flags */
230 SIVAL(outbody.data, 0x2C, 0); /* reserved */
233 * Note: Windows Vista and 2008 send back also the
234 * input from the request. But it was fixed in
235 * Windows 7.
237 outdyn = out_output_buffer;
239 error = smbd_smb2_request_done_ex(req, status, outbody, &outdyn,
240 __location__);
241 if (!NT_STATUS_IS_OK(error)) {
242 smbd_server_connection_terminate(req->sconn,
243 nt_errstr(error));
244 return;
248 struct smbd_smb2_ioctl_state {
249 struct smbd_smb2_request *smb2req;
250 struct smb_request *smbreq;
251 files_struct *fsp;
252 DATA_BLOB in_input;
253 uint32_t in_max_output;
254 DATA_BLOB out_output;
255 bool disconnect;
258 static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq);
259 static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq);
261 static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx,
262 struct tevent_context *ev,
263 struct smbd_smb2_request *smb2req,
264 uint32_t in_ctl_code,
265 uint64_t in_file_id_volatile,
266 DATA_BLOB in_input,
267 uint32_t in_max_output,
268 uint32_t in_flags)
270 struct tevent_req *req;
271 struct smbd_smb2_ioctl_state *state;
272 struct smb_request *smbreq;
273 files_struct *fsp = NULL;
274 struct tevent_req *subreq;
276 req = tevent_req_create(mem_ctx, &state,
277 struct smbd_smb2_ioctl_state);
278 if (req == NULL) {
279 return NULL;
281 state->smb2req = smb2req;
282 state->smbreq = NULL;
283 state->fsp = NULL;
284 state->in_input = in_input;
285 state->in_max_output = in_max_output;
286 state->out_output = data_blob_null;
288 DEBUG(10, ("smbd_smb2_ioctl: ctl_code[0x%08x] file_id[0x%016llX]\n",
289 (unsigned)in_ctl_code,
290 (unsigned long long)in_file_id_volatile));
292 smbreq = smbd_smb2_fake_smb_request(smb2req);
293 if (tevent_req_nomem(smbreq, req)) {
294 return tevent_req_post(req, ev);
296 state->smbreq = smbreq;
298 if (in_file_id_volatile != UINT64_MAX) {
299 fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile);
300 if (fsp == NULL) {
301 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
302 return tevent_req_post(req, ev);
304 if (smbreq->conn != fsp->conn) {
305 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
306 return tevent_req_post(req, ev);
308 if (smb2req->session->vuid != fsp->vuid) {
309 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
310 return tevent_req_post(req, ev);
312 state->fsp = fsp;
315 switch (in_ctl_code) {
316 case 0x00060194: /* FSCTL_DFS_GET_REFERRALS */
318 uint16_t in_max_referral_level;
319 DATA_BLOB in_file_name_buffer;
320 char *in_file_name_string;
321 size_t in_file_name_string_size;
322 bool ok;
323 bool overflow = false;
324 NTSTATUS status;
325 int dfs_size;
326 char *dfs_data = NULL;
328 if (!IS_IPC(smbreq->conn)) {
329 tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
330 return tevent_req_post(req, ev);
333 if (!lp_host_msdfs()) {
334 tevent_req_nterror(req, NT_STATUS_FS_DRIVER_REQUIRED);
335 return tevent_req_post(req, ev);
338 if (in_input.length < (2 + 2)) {
339 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
340 return tevent_req_post(req, ev);
343 in_max_referral_level = SVAL(in_input.data, 0);
344 in_file_name_buffer.data = in_input.data + 2;
345 in_file_name_buffer.length = in_input.length - 2;
347 ok = convert_string_talloc(state, CH_UTF16, CH_UNIX,
348 in_file_name_buffer.data,
349 in_file_name_buffer.length,
350 &in_file_name_string,
351 &in_file_name_string_size);
352 if (!ok) {
353 tevent_req_nterror(req, NT_STATUS_ILLEGAL_CHARACTER);
354 return tevent_req_post(req, ev);
357 dfs_size = setup_dfs_referral(smbreq->conn,
358 in_file_name_string,
359 in_max_referral_level,
360 &dfs_data, &status);
361 if (dfs_size < 0) {
362 tevent_req_nterror(req, status);
363 return tevent_req_post(req, ev);
366 if (dfs_size > in_max_output) {
368 * TODO: we need a testsuite for this
370 overflow = true;
371 dfs_size = in_max_output;
374 state->out_output = data_blob_talloc(state,
375 (uint8_t *)dfs_data,
376 dfs_size);
377 SAFE_FREE(dfs_data);
378 if (dfs_size > 0 &&
379 tevent_req_nomem(state->out_output.data, req)) {
380 return tevent_req_post(req, ev);
383 if (overflow) {
384 tevent_req_nterror(req, STATUS_BUFFER_OVERFLOW);
385 } else {
386 tevent_req_done(req);
388 return tevent_req_post(req, ev);
390 case 0x0011C017: /* FSCTL_PIPE_TRANSCEIVE */
392 if (!IS_IPC(smbreq->conn)) {
393 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
394 return tevent_req_post(req, ev);
397 if (fsp == NULL) {
398 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
399 return tevent_req_post(req, ev);
402 if (!fsp_is_np(fsp)) {
403 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
404 return tevent_req_post(req, ev);
407 DEBUG(10,("smbd_smb2_ioctl_send: np_write_send of size %u\n",
408 (unsigned int)in_input.length ));
410 subreq = np_write_send(state, ev,
411 fsp->fake_file_handle,
412 in_input.data,
413 in_input.length);
414 if (tevent_req_nomem(subreq, req)) {
415 return tevent_req_post(req, ev);
417 tevent_req_set_callback(subreq,
418 smbd_smb2_ioctl_pipe_write_done,
419 req);
420 return req;
422 case FSCTL_VALIDATE_NEGOTIATE_INFO_224:
424 struct smbXsrv_connection *conn = smbreq->sconn->conn;
425 uint32_t in_capabilities;
426 DATA_BLOB in_guid_blob;
427 struct GUID in_guid;
428 uint16_t in_security_mode;
429 uint16_t in_max_dialect;
430 uint16_t max_dialect;
431 DATA_BLOB out_guid_blob;
432 NTSTATUS status;
434 if (in_input.length != 0x18) {
435 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
436 return tevent_req_post(req, ev);
439 if (in_max_output < 0x18) {
440 tevent_req_nterror(req, NT_STATUS_BUFFER_TOO_SMALL);
441 return tevent_req_post(req, ev);
444 in_capabilities = IVAL(in_input.data, 0x00);
445 in_guid_blob = data_blob_const(in_input.data + 0x04, 16);
446 in_security_mode = SVAL(in_input.data, 0x14);
447 in_max_dialect = SVAL(in_input.data, 0x16);
449 status = GUID_from_ndr_blob(&in_guid_blob, &in_guid);
450 if (tevent_req_nterror(req, status)) {
451 return tevent_req_post(req, ev);
454 max_dialect = conn->smb2.client.dialects[conn->smb2.client.num_dialects-1];
455 if (in_max_dialect != max_dialect) {
456 state->disconnect = true;
457 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
458 return tevent_req_post(req, ev);
461 if (!GUID_compare(&in_guid, &conn->smb2.client.guid)) {
462 state->disconnect = true;
463 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
464 return tevent_req_post(req, ev);
467 if (in_security_mode != conn->smb2.client.security_mode) {
468 state->disconnect = true;
469 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
470 return tevent_req_post(req, ev);
473 if (in_capabilities != conn->smb2.client.capabilities) {
474 state->disconnect = true;
475 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
476 return tevent_req_post(req, ev);
479 status = GUID_to_ndr_blob(&conn->smb2.server.guid, state,
480 &out_guid_blob);
481 if (tevent_req_nterror(req, status)) {
482 return tevent_req_post(req, ev);
485 state->out_output = data_blob_talloc(state, NULL, 0x18);
486 if (tevent_req_nomem(state->out_output.data, req)) {
487 return tevent_req_post(req, ev);
490 SIVAL(state->out_output.data, 0x00, conn->smb2.server.capabilities);
491 memcpy(state->out_output.data+0x04, out_guid_blob.data, 16);
492 SIVAL(state->out_output.data, 0x14, conn->smb2.server.security_mode);
493 SIVAL(state->out_output.data, 0x16, conn->smb2.server.dialect);
495 tevent_req_done(req);
496 return tevent_req_post(req, ev);
499 case FSCTL_VALIDATE_NEGOTIATE_INFO:
501 struct smbXsrv_connection *conn = smbreq->sconn->conn;
502 uint32_t in_capabilities;
503 DATA_BLOB in_guid_blob;
504 struct GUID in_guid;
505 uint16_t in_security_mode;
506 uint16_t in_num_dialects;
507 uint16_t i;
508 DATA_BLOB out_guid_blob;
509 NTSTATUS status;
511 if (in_input.length < 0x18) {
512 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
513 return tevent_req_post(req, ev);
516 in_capabilities = IVAL(in_input.data, 0x00);
517 in_guid_blob = data_blob_const(in_input.data + 0x04, 16);
518 in_security_mode = SVAL(in_input.data, 0x14);
519 in_num_dialects = SVAL(in_input.data, 0x16);
521 if (in_input.length != (0x18 + in_num_dialects*2)) {
522 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
523 return tevent_req_post(req, ev);
526 if (in_max_output < 0x18) {
527 tevent_req_nterror(req, NT_STATUS_BUFFER_TOO_SMALL);
528 return tevent_req_post(req, ev);
531 status = GUID_from_ndr_blob(&in_guid_blob, &in_guid);
532 if (tevent_req_nterror(req, status)) {
533 return tevent_req_post(req, ev);
536 if (in_num_dialects != conn->smb2.client.num_dialects) {
537 state->disconnect = true;
538 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
539 return tevent_req_post(req, ev);
542 for (i=0; i < in_num_dialects; i++) {
543 uint16_t v = SVAL(in_input.data, 0x18 + i*2);
545 if (conn->smb2.client.dialects[i] != v) {
546 state->disconnect = true;
547 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
548 return tevent_req_post(req, ev);
552 if (!GUID_compare(&in_guid, &conn->smb2.client.guid)) {
553 state->disconnect = true;
554 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
555 return tevent_req_post(req, ev);
558 if (in_security_mode != conn->smb2.client.security_mode) {
559 state->disconnect = true;
560 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
561 return tevent_req_post(req, ev);
564 if (in_capabilities != conn->smb2.client.capabilities) {
565 state->disconnect = true;
566 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
567 return tevent_req_post(req, ev);
570 status = GUID_to_ndr_blob(&conn->smb2.server.guid, state,
571 &out_guid_blob);
572 if (tevent_req_nterror(req, status)) {
573 return tevent_req_post(req, ev);
576 state->out_output = data_blob_talloc(state, NULL, 0x18);
577 if (tevent_req_nomem(state->out_output.data, req)) {
578 return tevent_req_post(req, ev);
581 SIVAL(state->out_output.data, 0x00, conn->smb2.server.capabilities);
582 memcpy(state->out_output.data+0x04, out_guid_blob.data, 16);
583 SIVAL(state->out_output.data, 0x14, conn->smb2.server.security_mode);
584 SIVAL(state->out_output.data, 0x16, conn->smb2.server.dialect);
586 tevent_req_done(req);
587 return tevent_req_post(req, ev);
590 default: {
591 uint8_t *out_data = NULL;
592 uint32_t out_data_len = 0;
593 NTSTATUS status;
595 if (fsp == NULL) {
596 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
597 return tevent_req_post(req, ev);
600 status = SMB_VFS_FSCTL(fsp,
601 state,
602 in_ctl_code,
603 smbreq->flags2,
604 in_input.data,
605 in_input.length,
606 &out_data,
607 in_max_output,
608 &out_data_len);
609 state->out_output = data_blob_const(out_data, out_data_len);
610 if (NT_STATUS_IS_OK(status)) {
611 tevent_req_done(req);
612 return tevent_req_post(req, ev);
615 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
616 if (IS_IPC(smbreq->conn)) {
617 status = NT_STATUS_FS_DRIVER_REQUIRED;
618 } else {
619 status = NT_STATUS_INVALID_DEVICE_REQUEST;
623 tevent_req_nterror(req, status);
624 return tevent_req_post(req, ev);
628 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
629 return tevent_req_post(req, ev);
632 static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq)
634 struct tevent_req *req = tevent_req_callback_data(subreq,
635 struct tevent_req);
636 struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
637 struct smbd_smb2_ioctl_state);
638 NTSTATUS status;
639 ssize_t nwritten = -1;
641 status = np_write_recv(subreq, &nwritten);
643 DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: received %ld\n",
644 (long int)nwritten ));
646 TALLOC_FREE(subreq);
647 if (!NT_STATUS_IS_OK(status)) {
648 NTSTATUS old = status;
649 status = nt_status_np_pipe(old);
650 tevent_req_nterror(req, status);
651 return;
654 if (nwritten != state->in_input.length) {
655 tevent_req_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE);
656 return;
659 state->out_output = data_blob_talloc(state, NULL, state->in_max_output);
660 if (state->in_max_output > 0 &&
661 tevent_req_nomem(state->out_output.data, req)) {
662 return;
665 DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: issuing np_read_send "
666 "of size %u\n",
667 (unsigned int)state->out_output.length ));
669 TALLOC_FREE(subreq);
670 subreq = np_read_send(state->smbreq->conn,
671 state->smb2req->sconn->ev_ctx,
672 state->fsp->fake_file_handle,
673 state->out_output.data,
674 state->out_output.length);
675 if (tevent_req_nomem(subreq, req)) {
676 return;
678 tevent_req_set_callback(subreq, smbd_smb2_ioctl_pipe_read_done, req);
681 static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq)
683 struct tevent_req *req = tevent_req_callback_data(subreq,
684 struct tevent_req);
685 struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
686 struct smbd_smb2_ioctl_state);
687 NTSTATUS status;
688 NTSTATUS old;
689 ssize_t nread = -1;
690 bool is_data_outstanding = false;
692 status = np_read_recv(subreq, &nread, &is_data_outstanding);
693 TALLOC_FREE(subreq);
695 old = status;
696 status = nt_status_np_pipe(old);
698 DEBUG(10,("smbd_smb2_ioctl_pipe_read_done: np_read_recv nread = %d "
699 "is_data_outstanding = %d, status = %s%s%s\n",
700 (int)nread,
701 (int)is_data_outstanding,
702 nt_errstr(old),
703 NT_STATUS_EQUAL(old, status)?"":" => ",
704 NT_STATUS_EQUAL(old, status)?"":nt_errstr(status)));
706 if (!NT_STATUS_IS_OK(status)) {
707 tevent_req_nterror(req, status);
708 return;
711 state->out_output.length = nread;
713 if (is_data_outstanding) {
714 tevent_req_nterror(req, STATUS_BUFFER_OVERFLOW);
715 return;
718 tevent_req_done(req);
721 static NTSTATUS smbd_smb2_ioctl_recv(struct tevent_req *req,
722 TALLOC_CTX *mem_ctx,
723 DATA_BLOB *out_output,
724 bool *disconnect)
726 NTSTATUS status = NT_STATUS_OK;
727 struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
728 struct smbd_smb2_ioctl_state);
730 *disconnect = state->disconnect;
732 if (tevent_req_is_nterror(req, &status)) {
733 if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
734 tevent_req_received(req);
735 return status;
739 *out_output = state->out_output;
740 talloc_steal(mem_ctx, out_output->data);
742 tevent_req_received(req);
743 return status;