Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : smb2 lib
4 : Copyright (C) Volker Lendecke 2011
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/network.h"
22 : #include "../lib/util/tevent_ntstatus.h"
23 : #include "../libcli/smb/smb_common.h"
24 : #include "../libcli/smb/smbXcli_base.h"
25 :
26 : struct smb2cli_tcon_state {
27 : struct tevent_context *ev;
28 : struct smbXcli_conn *conn;
29 : uint32_t timeout_msec;
30 : struct smbXcli_session *session;
31 : struct smbXcli_tcon *tcon;
32 : uint8_t fixed[8];
33 : uint8_t dyn_pad[1];
34 : };
35 :
36 : static void smb2cli_tcon_done(struct tevent_req *subreq);
37 :
38 36323 : struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx,
39 : struct tevent_context *ev,
40 : struct smbXcli_conn *conn,
41 : uint32_t timeout_msec,
42 : struct smbXcli_session *session,
43 : struct smbXcli_tcon *tcon,
44 : uint16_t flags,
45 : const char *unc)
46 : {
47 : struct tevent_req *req, *subreq;
48 : struct smb2cli_tcon_state *state;
49 : uint8_t *fixed;
50 : uint8_t *dyn;
51 : size_t dyn_len;
52 36323 : uint32_t additional_flags = 0;
53 36323 : uint32_t clear_flags = 0;
54 :
55 36323 : req = tevent_req_create(mem_ctx, &state, struct smb2cli_tcon_state);
56 36323 : if (req == NULL) {
57 0 : return NULL;
58 : }
59 36323 : state->ev = ev;
60 36323 : state->conn = conn;
61 36323 : state->timeout_msec = timeout_msec;
62 36323 : state->session = session;
63 36323 : state->tcon = tcon;
64 :
65 36323 : if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
66 : unc, strlen(unc),
67 : &dyn, &dyn_len)) {
68 0 : tevent_req_oom(req);
69 0 : return tevent_req_post(req, ev);
70 : }
71 :
72 36323 : if (strlen(unc) == 0) {
73 0 : TALLOC_FREE(dyn);
74 0 : dyn_len = 0;
75 : }
76 :
77 36323 : fixed = state->fixed;
78 36323 : SSVAL(fixed, 0, 9);
79 36323 : if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) {
80 32095 : SSVAL(fixed, 2, flags);
81 : } else {
82 4228 : SSVAL(fixed, 2, 0); /* Reserved */
83 : }
84 36323 : SSVAL(fixed, 4, SMB2_HDR_BODY + 8);
85 36323 : SSVAL(fixed, 6, dyn_len);
86 :
87 36323 : if (dyn_len == 0) {
88 0 : dyn = state->dyn_pad;
89 0 : dyn_len = sizeof(state->dyn_pad);
90 : }
91 :
92 36323 : if (smbXcli_session_is_authenticated(state->session)) {
93 35379 : additional_flags |= SMB2_HDR_FLAG_SIGNED;
94 : }
95 :
96 69116 : subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TCON,
97 : additional_flags, clear_flags,
98 : timeout_msec,
99 : NULL, /* tcon */
100 : session,
101 36323 : state->fixed, sizeof(state->fixed),
102 : dyn, dyn_len,
103 : 0); /* max_dyn_len */
104 36323 : if (tevent_req_nomem(subreq, req)) {
105 0 : return tevent_req_post(req, ev);
106 : }
107 36323 : tevent_req_set_callback(subreq, smb2cli_tcon_done, req);
108 :
109 36323 : return req;
110 : }
111 :
112 : static void smb2cli_tcon_validate(struct tevent_req *subreq);
113 :
114 36323 : static void smb2cli_tcon_done(struct tevent_req *subreq)
115 : {
116 36323 : struct tevent_req *req = tevent_req_callback_data(
117 : subreq, struct tevent_req);
118 36323 : struct smb2cli_tcon_state *state = tevent_req_data(
119 : req, struct smb2cli_tcon_state);
120 : NTSTATUS status;
121 : struct iovec *iov;
122 : uint8_t *body;
123 : uint32_t tcon_id;
124 : uint8_t share_type;
125 : uint32_t share_flags;
126 : uint32_t share_capabilities;
127 : uint32_t maximal_access;
128 : static const struct smb2cli_req_expected_response expected[] = {
129 : {
130 : .status = NT_STATUS_OK,
131 : .body_size = 0x10
132 : }
133 : };
134 :
135 36323 : status = smb2cli_req_recv(subreq, state, &iov,
136 : expected, ARRAY_SIZE(expected));
137 36323 : TALLOC_FREE(subreq);
138 36323 : if (!NT_STATUS_IS_OK(status)) {
139 78 : tevent_req_nterror(req, status);
140 2407 : return;
141 : }
142 :
143 36245 : tcon_id = IVAL(iov[0].iov_base, SMB2_HDR_TID);
144 :
145 36245 : body = (uint8_t *)iov[1].iov_base;
146 36245 : share_type = CVAL(body, 0x02);
147 36245 : share_flags = IVAL(body, 0x04);
148 36245 : share_capabilities = IVAL(body, 0x08);
149 36245 : maximal_access = IVAL(body, 0x0C);
150 :
151 36245 : smb2cli_tcon_set_values(state->tcon,
152 : state->session,
153 : tcon_id,
154 : share_type,
155 : share_flags,
156 : share_capabilities,
157 : maximal_access);
158 :
159 36245 : if (!smbXcli_session_is_authenticated(state->session)) {
160 940 : tevent_req_done(req);
161 940 : return;
162 : }
163 :
164 35305 : if (smbXcli_conn_protocol(state->conn) >= PROTOCOL_SMB3_11) {
165 31163 : tevent_req_done(req);
166 31163 : return;
167 : }
168 :
169 4142 : subreq = smb2cli_validate_negotiate_info_send(state, state->ev,
170 : state->conn,
171 : state->timeout_msec,
172 : state->session,
173 : state->tcon);
174 4142 : if (tevent_req_nomem(subreq, req)) {
175 0 : return;
176 : }
177 4142 : tevent_req_set_callback(subreq, smb2cli_tcon_validate, req);
178 : }
179 :
180 4142 : static void smb2cli_tcon_validate(struct tevent_req *subreq)
181 : {
182 4142 : struct tevent_req *req = tevent_req_callback_data(
183 : subreq, struct tevent_req);
184 4142 : struct smb2cli_tcon_state *state = tevent_req_data(
185 : req, struct smb2cli_tcon_state);
186 : NTSTATUS status;
187 :
188 4142 : status = smb2cli_validate_negotiate_info_recv(subreq);
189 4142 : TALLOC_FREE(subreq);
190 4142 : if (!NT_STATUS_IS_OK(status)) {
191 0 : smb2cli_tcon_set_values(state->tcon, NULL,
192 : UINT32_MAX, 0, 0, 0, 0);
193 0 : tevent_req_nterror(req, status);
194 0 : return;
195 : }
196 :
197 4142 : tevent_req_done(req);
198 : }
199 :
200 36323 : NTSTATUS smb2cli_tcon_recv(struct tevent_req *req)
201 : {
202 36323 : return tevent_req_simple_recv_ntstatus(req);
203 : }
204 :
205 0 : NTSTATUS smb2cli_tcon(struct smbXcli_conn *conn,
206 : uint32_t timeout_msec,
207 : struct smbXcli_session *session,
208 : struct smbXcli_tcon *tcon,
209 : uint16_t flags,
210 : const char *unc)
211 : {
212 0 : TALLOC_CTX *frame = talloc_stackframe();
213 : struct tevent_context *ev;
214 : struct tevent_req *req;
215 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
216 :
217 0 : if (smbXcli_conn_has_async_calls(conn)) {
218 : /*
219 : * Can't use sync call while an async call is in flight
220 : */
221 0 : status = NT_STATUS_INVALID_PARAMETER;
222 0 : goto fail;
223 : }
224 0 : ev = samba_tevent_context_init(frame);
225 0 : if (ev == NULL) {
226 0 : goto fail;
227 : }
228 0 : req = smb2cli_tcon_send(frame, ev, conn,
229 : timeout_msec, session, tcon,
230 : flags, unc);
231 0 : if (req == NULL) {
232 0 : goto fail;
233 : }
234 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
235 0 : goto fail;
236 : }
237 0 : status = smb2cli_tcon_recv(req);
238 0 : fail:
239 0 : TALLOC_FREE(frame);
240 0 : return status;
241 : }
242 :
243 : struct smb2cli_tdis_state {
244 : struct smbXcli_tcon *tcon;
245 : uint8_t fixed[4];
246 : };
247 :
248 : static void smb2cli_tdis_done(struct tevent_req *subreq);
249 :
250 22675 : struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx,
251 : struct tevent_context *ev,
252 : struct smbXcli_conn *conn,
253 : uint32_t timeout_msec,
254 : struct smbXcli_session *session,
255 : struct smbXcli_tcon *tcon)
256 : {
257 : struct tevent_req *req, *subreq;
258 : struct smb2cli_tdis_state *state;
259 :
260 22675 : req = tevent_req_create(mem_ctx, &state,
261 : struct smb2cli_tdis_state);
262 22675 : if (req == NULL) {
263 0 : return NULL;
264 : }
265 22675 : state->tcon = tcon;
266 :
267 22675 : SSVAL(state->fixed, 0, 4);
268 :
269 22675 : subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TDIS,
270 : 0, 0, /* flags */
271 : timeout_msec,
272 : tcon, session,
273 22675 : state->fixed, sizeof(state->fixed),
274 : NULL, 0, /* dyn* */
275 : 0); /* max_dyn_len */
276 22675 : if (tevent_req_nomem(subreq, req)) {
277 0 : return tevent_req_post(req, ev);
278 : }
279 22675 : tevent_req_set_callback(subreq, smb2cli_tdis_done, req);
280 22675 : return req;
281 : }
282 :
283 22675 : static void smb2cli_tdis_done(struct tevent_req *subreq)
284 : {
285 21493 : struct tevent_req *req =
286 22675 : tevent_req_callback_data(subreq,
287 : struct tevent_req);
288 21493 : struct smb2cli_tdis_state *state =
289 22675 : tevent_req_data(req,
290 : struct smb2cli_tdis_state);
291 : NTSTATUS status;
292 : static const struct smb2cli_req_expected_response expected[] = {
293 : {
294 : .status = NT_STATUS_OK,
295 : .body_size = 0x04
296 : }
297 : };
298 :
299 22675 : status = smb2cli_req_recv(subreq, NULL, NULL,
300 : expected, ARRAY_SIZE(expected));
301 22675 : TALLOC_FREE(subreq);
302 22675 : if (tevent_req_nterror(req, status)) {
303 95 : return;
304 : }
305 22580 : smb2cli_tcon_set_values(state->tcon, NULL,
306 : UINT32_MAX, 0, 0, 0, 0);
307 22580 : tevent_req_done(req);
308 : }
309 :
310 22675 : NTSTATUS smb2cli_tdis_recv(struct tevent_req *req)
311 : {
312 22675 : return tevent_req_simple_recv_ntstatus(req);
313 : }
314 :
315 22675 : NTSTATUS smb2cli_tdis(struct smbXcli_conn *conn,
316 : uint32_t timeout_msec,
317 : struct smbXcli_session *session,
318 : struct smbXcli_tcon *tcon)
319 : {
320 22675 : TALLOC_CTX *frame = talloc_stackframe();
321 : struct tevent_context *ev;
322 : struct tevent_req *req;
323 22675 : NTSTATUS status = NT_STATUS_NO_MEMORY;
324 :
325 22675 : if (smbXcli_conn_has_async_calls(conn)) {
326 : /*
327 : * Can't use sync call while an async call is in flight
328 : */
329 0 : status = NT_STATUS_INVALID_PARAMETER;
330 0 : goto fail;
331 : }
332 22675 : ev = samba_tevent_context_init(frame);
333 22675 : if (ev == NULL) {
334 0 : goto fail;
335 : }
336 22675 : req = smb2cli_tdis_send(frame, ev, conn,
337 : timeout_msec, session, tcon);
338 22675 : if (req == NULL) {
339 0 : goto fail;
340 : }
341 22675 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
342 0 : goto fail;
343 : }
344 22675 : status = smb2cli_tdis_recv(req);
345 22675 : fail:
346 22675 : TALLOC_FREE(frame);
347 22675 : return status;
348 : }
|