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 314730 : 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 6733 : NTSTATUS status;
42 314730 : uint8_t *out_data = NULL;
43 314730 : uint32_t out_data_len = 0;
44 :
45 314730 : if (ctl_code == FSCTL_PIPE_TRANSCEIVE) {
46 6733 : struct tevent_req *subreq;
47 :
48 314730 : 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 314730 : 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 314730 : 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 314730 : DEBUG(10,("smbd_smb2_ioctl_send: np_write_send of size %u\n",
64 : (unsigned int)state->in_input.length ));
65 :
66 321463 : subreq = np_write_send(state, ev,
67 314730 : state->fsp->fake_file_handle,
68 314730 : state->in_input.data,
69 : state->in_input.length);
70 314730 : if (tevent_req_nomem(subreq, req)) {
71 0 : return tevent_req_post(req, ev);
72 : }
73 314730 : tevent_req_set_callback(subreq,
74 : smbd_smb2_ioctl_pipe_write_done,
75 : req);
76 314730 : 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 314730 : static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq)
111 : {
112 314730 : struct tevent_req *req = tevent_req_callback_data(subreq,
113 : struct tevent_req);
114 314730 : struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
115 : struct smbd_smb2_ioctl_state);
116 6733 : NTSTATUS status;
117 314730 : ssize_t nwritten = -1;
118 :
119 314730 : status = np_write_recv(subreq, &nwritten);
120 :
121 314730 : DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: received %ld\n",
122 : (long int)nwritten ));
123 :
124 314730 : TALLOC_FREE(subreq);
125 314730 : if (!NT_STATUS_IS_OK(status)) {
126 0 : tevent_req_nterror(req, status);
127 0 : return;
128 : }
129 :
130 314730 : if (nwritten != state->in_input.length) {
131 0 : tevent_req_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE);
132 0 : return;
133 : }
134 :
135 314730 : state->out_output = data_blob_talloc(state, NULL, state->in_max_output);
136 629460 : if (state->in_max_output > 0 &&
137 314730 : tevent_req_nomem(state->out_output.data, req)) {
138 0 : return;
139 : }
140 :
141 314730 : 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 321463 : subreq = np_read_send(state->smbreq->conn,
146 314730 : state->smb2req->sconn->ev_ctx,
147 314730 : state->fsp->fake_file_handle,
148 : state->out_output.data,
149 : state->out_output.length);
150 314730 : if (tevent_req_nomem(subreq, req)) {
151 0 : return;
152 : }
153 314730 : tevent_req_set_callback(subreq, smbd_smb2_ioctl_pipe_read_done, req);
154 : }
155 :
156 314730 : static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq)
157 : {
158 314730 : struct tevent_req *req = tevent_req_callback_data(subreq,
159 : struct tevent_req);
160 314730 : struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
161 : struct smbd_smb2_ioctl_state);
162 6733 : NTSTATUS status;
163 314730 : ssize_t nread = -1;
164 314730 : bool is_data_outstanding = false;
165 :
166 314730 : status = np_read_recv(subreq, &nread, &is_data_outstanding);
167 :
168 314730 : 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 314730 : TALLOC_FREE(subreq);
175 314730 : if (!NT_STATUS_IS_OK(status)) {
176 12 : tevent_req_nterror(req, status);
177 15 : return;
178 : }
179 :
180 314718 : state->out_output.length = nread;
181 :
182 314718 : if (is_data_outstanding) {
183 0 : tevent_req_nterror(req, STATUS_BUFFER_OVERFLOW);
184 0 : return;
185 : }
186 :
187 314718 : tevent_req_done(req);
188 : }
|