Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Core SMB2 server
4 :
5 : Copyright (C) Stefan Metzmacher 2009
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 "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 "smb2_ioctl_private.h"
29 :
30 : #undef DBGC_CLASS
31 : #define DBGC_CLASS DBGC_SMB2
32 :
33 : static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq);
34 : static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq);
35 :
36 317401 : struct tevent_req *smb2_ioctl_named_pipe(uint32_t ctl_code,
37 : struct tevent_context *ev,
38 : struct tevent_req *req,
39 : struct smbd_smb2_ioctl_state *state)
40 : {
41 7022 : NTSTATUS status;
42 317401 : uint8_t *out_data = NULL;
43 317401 : uint32_t out_data_len = 0;
44 :
45 317401 : if (ctl_code == FSCTL_PIPE_TRANSCEIVE) {
46 7022 : struct tevent_req *subreq;
47 :
48 317401 : if (!IS_IPC(state->smbreq->conn)) {
49 0 : tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
50 0 : return tevent_req_post(req, ev);
51 : }
52 :
53 317401 : if (state->fsp == NULL) {
54 0 : tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
55 0 : return tevent_req_post(req, ev);
56 : }
57 :
58 317401 : if (!fsp_is_np(state->fsp)) {
59 0 : tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
60 0 : return tevent_req_post(req, ev);
61 : }
62 :
63 317401 : DEBUG(10,("smbd_smb2_ioctl_send: np_write_send of size %u\n",
64 : (unsigned int)state->in_input.length ));
65 :
66 324423 : subreq = np_write_send(state, ev,
67 317401 : state->fsp->fake_file_handle,
68 317401 : state->in_input.data,
69 : state->in_input.length);
70 317401 : if (tevent_req_nomem(subreq, req)) {
71 0 : return tevent_req_post(req, ev);
72 : }
73 317401 : tevent_req_set_callback(subreq,
74 : smbd_smb2_ioctl_pipe_write_done,
75 : req);
76 317401 : return req;
77 : }
78 :
79 0 : if (state->fsp == NULL) {
80 0 : status = NT_STATUS_NOT_SUPPORTED;
81 : } else {
82 0 : status = SMB_VFS_FSCTL(state->fsp,
83 : state,
84 : ctl_code,
85 : state->smbreq->flags2,
86 : state->in_input.data,
87 : state->in_input.length,
88 : &out_data,
89 : state->in_max_output,
90 : &out_data_len);
91 0 : state->out_output = data_blob_const(out_data, out_data_len);
92 0 : if (NT_STATUS_IS_OK(status)) {
93 0 : tevent_req_done(req);
94 0 : return tevent_req_post(req, ev);
95 : }
96 : }
97 :
98 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
99 0 : if (IS_IPC(state->smbreq->conn)) {
100 0 : status = NT_STATUS_FS_DRIVER_REQUIRED;
101 : } else {
102 0 : status = NT_STATUS_INVALID_DEVICE_REQUEST;
103 : }
104 : }
105 :
106 0 : tevent_req_nterror(req, status);
107 0 : return tevent_req_post(req, ev);
108 : }
109 :
110 317401 : static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq)
111 : {
112 317401 : struct tevent_req *req = tevent_req_callback_data(subreq,
113 : struct tevent_req);
114 317401 : struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
115 : struct smbd_smb2_ioctl_state);
116 7022 : NTSTATUS status;
117 317401 : ssize_t nwritten = -1;
118 :
119 317401 : status = np_write_recv(subreq, &nwritten);
120 :
121 317401 : DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: received %ld\n",
122 : (long int)nwritten ));
123 :
124 317401 : TALLOC_FREE(subreq);
125 317401 : if (!NT_STATUS_IS_OK(status)) {
126 0 : tevent_req_nterror(req, status);
127 0 : return;
128 : }
129 :
130 317401 : if (nwritten != state->in_input.length) {
131 0 : tevent_req_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE);
132 0 : return;
133 : }
134 :
135 317401 : state->out_output = data_blob_talloc(state, NULL, state->in_max_output);
136 634802 : if (state->in_max_output > 0 &&
137 317401 : tevent_req_nomem(state->out_output.data, req)) {
138 0 : return;
139 : }
140 :
141 317401 : DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: issuing np_read_send "
142 : "of size %u\n",
143 : (unsigned int)state->out_output.length ));
144 :
145 324423 : subreq = np_read_send(state->smbreq->conn,
146 317401 : state->smb2req->sconn->ev_ctx,
147 317401 : state->fsp->fake_file_handle,
148 : state->out_output.data,
149 : state->out_output.length);
150 317401 : if (tevent_req_nomem(subreq, req)) {
151 0 : return;
152 : }
153 317401 : tevent_req_set_callback(subreq, smbd_smb2_ioctl_pipe_read_done, req);
154 : }
155 :
156 317401 : static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq)
157 : {
158 317401 : struct tevent_req *req = tevent_req_callback_data(subreq,
159 : struct tevent_req);
160 317401 : struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
161 : struct smbd_smb2_ioctl_state);
162 7022 : NTSTATUS status;
163 317401 : ssize_t nread = -1;
164 317401 : bool is_data_outstanding = false;
165 :
166 317401 : status = np_read_recv(subreq, &nread, &is_data_outstanding);
167 :
168 317401 : DEBUG(10,("smbd_smb2_ioctl_pipe_read_done: np_read_recv nread = %d "
169 : "is_data_outstanding = %d, status = %s\n",
170 : (int)nread,
171 : (int)is_data_outstanding,
172 : nt_errstr(status) ));
173 :
174 317401 : TALLOC_FREE(subreq);
175 317401 : if (!NT_STATUS_IS_OK(status)) {
176 12 : tevent_req_nterror(req, status);
177 15 : return;
178 : }
179 :
180 317389 : state->out_output.length = nread;
181 :
182 317389 : if (is_data_outstanding) {
183 0 : tevent_req_nterror(req, STATUS_BUFFER_OVERFLOW);
184 0 : return;
185 : }
186 :
187 317389 : tevent_req_done(req);
188 : }
|