s3:smbd: allow info class SMB_QUERY_FS_ATTRIBUTE_INFO to return partial data
[Samba.git] / libcli / smb / smb2cli_session.c
blobd34fbd4fe62b40fce5d42dc2d957eebb776058ef
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
4 Copyright (C) Volker Lendecke 2011
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.
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.
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/>.
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"
26 struct smb2cli_session_setup_state {
27 struct smbXcli_session *session;
28 uint8_t fixed[24];
29 uint8_t dyn_pad[1];
30 struct iovec *recv_iov;
31 DATA_BLOB out_security_buffer;
32 NTSTATUS status;
35 static void smb2cli_session_setup_done(struct tevent_req *subreq);
37 struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
38 struct tevent_context *ev,
39 struct smbXcli_conn *conn,
40 uint32_t timeout_msec,
41 struct smbXcli_session *session,
42 uint8_t in_flags,
43 uint32_t in_capabilities,
44 uint32_t in_channel,
45 uint64_t in_previous_session_id,
46 const DATA_BLOB *in_security_buffer)
48 struct tevent_req *req, *subreq;
49 struct smb2cli_session_setup_state *state;
50 uint8_t *buf;
51 uint8_t *dyn;
52 size_t dyn_len;
53 uint8_t security_mode;
54 uint16_t security_buffer_offset = 0;
55 uint16_t security_buffer_length = 0;
57 req = tevent_req_create(mem_ctx, &state,
58 struct smb2cli_session_setup_state);
59 if (req == NULL) {
60 return NULL;
63 if (session == NULL) {
64 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
65 return tevent_req_post(req, ev);
67 state->session = session;
68 security_mode = smb2cli_session_security_mode(session);
70 if (in_security_buffer) {
71 if (in_security_buffer->length > UINT16_MAX) {
72 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
73 return tevent_req_post(req, ev);
75 security_buffer_offset = SMB2_HDR_BODY + 24;
76 security_buffer_length = in_security_buffer->length;
79 buf = state->fixed;
81 SSVAL(buf, 0, 25);
82 SCVAL(buf, 2, in_flags);
83 SCVAL(buf, 3, security_mode);
84 SIVAL(buf, 4, in_capabilities);
85 SIVAL(buf, 8, in_channel);
86 SSVAL(buf, 12, security_buffer_offset);
87 SSVAL(buf, 14, security_buffer_length);
88 SBVAL(buf, 16, in_previous_session_id);
90 if (security_buffer_length > 0) {
91 dyn = in_security_buffer->data;
92 dyn_len = in_security_buffer->length;
93 } else {
94 dyn = state->dyn_pad;;
95 dyn_len = sizeof(state->dyn_pad);
98 subreq = smb2cli_req_send(state, ev,
99 conn, SMB2_OP_SESSSETUP,
100 0, 0, /* flags */
101 timeout_msec,
102 NULL, /* tcon */
103 session,
104 state->fixed, sizeof(state->fixed),
105 dyn, dyn_len);
106 if (tevent_req_nomem(subreq, req)) {
107 return tevent_req_post(req, ev);
109 tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
110 return req;
113 static void smb2cli_session_setup_done(struct tevent_req *subreq)
115 struct tevent_req *req =
116 tevent_req_callback_data(subreq,
117 struct tevent_req);
118 struct smb2cli_session_setup_state *state =
119 tevent_req_data(req,
120 struct smb2cli_session_setup_state);
121 NTSTATUS status;
122 uint64_t current_session_id;
123 uint64_t session_id;
124 uint16_t session_flags;
125 uint16_t expected_offset = 0;
126 uint16_t security_buffer_offset;
127 uint16_t security_buffer_length;
128 uint8_t *security_buffer_data = NULL;
129 const uint8_t *hdr;
130 const uint8_t *body;
131 static const struct smb2cli_req_expected_response expected[] = {
133 .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
134 .body_size = 0x09
137 .status = NT_STATUS_OK,
138 .body_size = 0x09
142 status = smb2cli_req_recv(subreq, state, &state->recv_iov,
143 expected, ARRAY_SIZE(expected));
144 TALLOC_FREE(subreq);
145 if (!NT_STATUS_IS_OK(status) &&
146 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
147 tevent_req_nterror(req, status);
148 return;
151 hdr = (const uint8_t *)state->recv_iov[0].iov_base;
152 body = (const uint8_t *)state->recv_iov[1].iov_base;
154 session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
155 session_flags = SVAL(body, 2);
157 security_buffer_offset = SVAL(body, 4);
158 security_buffer_length = SVAL(body, 6);
160 if (security_buffer_length > 0) {
161 expected_offset = SMB2_HDR_BODY + 8;
163 if (security_buffer_offset != 0) {
164 security_buffer_data = (uint8_t *)state->recv_iov[2].iov_base;
165 expected_offset = SMB2_HDR_BODY + 8;
168 if (security_buffer_offset != expected_offset) {
169 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
170 return;
172 if (security_buffer_length > state->recv_iov[2].iov_len) {
173 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
174 return;
177 state->out_security_buffer.data = security_buffer_data;
178 state->out_security_buffer.length = security_buffer_length;
180 current_session_id = smb2cli_session_current_id(state->session);
181 if (current_session_id == 0) {
182 /* A new session was requested */
183 current_session_id = session_id;
186 if (current_session_id != session_id) {
187 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
188 return;
191 smb2cli_session_set_id_and_flags(state->session,
192 session_id, session_flags);
194 state->status = status;
195 tevent_req_done(req);
198 NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
199 TALLOC_CTX *mem_ctx,
200 struct iovec **recv_iov,
201 DATA_BLOB *out_security_buffer)
203 struct smb2cli_session_setup_state *state =
204 tevent_req_data(req,
205 struct smb2cli_session_setup_state);
206 NTSTATUS status;
207 struct iovec *_tmp;
209 if (tevent_req_is_nterror(req, &status)) {
210 tevent_req_received(req);
211 return status;
214 if (recv_iov == NULL) {
215 recv_iov = &_tmp;
218 *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
220 *out_security_buffer = state->out_security_buffer;
223 * Return the status from the server:
224 * NT_STATUS_MORE_PROCESSING_REQUIRED or
225 * NT_STATUS_OK.
227 status = state->status;
228 tevent_req_received(req);
229 return status;
232 struct smb2cli_logoff_state {
233 uint8_t fixed[4];
236 static void smb2cli_logoff_done(struct tevent_req *subreq);
238 struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
239 struct tevent_context *ev,
240 struct smbXcli_conn *conn,
241 uint32_t timeout_msec,
242 struct smbXcli_session *session)
244 struct tevent_req *req, *subreq;
245 struct smb2cli_logoff_state *state;
247 req = tevent_req_create(mem_ctx, &state,
248 struct smb2cli_logoff_state);
249 if (req == NULL) {
250 return NULL;
252 SSVAL(state->fixed, 0, 4);
254 subreq = smb2cli_req_send(state, ev,
255 conn, SMB2_OP_LOGOFF,
256 0, 0, /* flags */
257 timeout_msec,
258 NULL, /* tcon */
259 session,
260 state->fixed, sizeof(state->fixed),
261 NULL, 0);
262 if (tevent_req_nomem(subreq, req)) {
263 return tevent_req_post(req, ev);
265 tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
266 return req;
269 static void smb2cli_logoff_done(struct tevent_req *subreq)
271 struct tevent_req *req =
272 tevent_req_callback_data(subreq,
273 struct tevent_req);
274 struct smb2cli_logoff_state *state =
275 tevent_req_data(req,
276 struct smb2cli_logoff_state);
277 NTSTATUS status;
278 struct iovec *iov;
279 static const struct smb2cli_req_expected_response expected[] = {
281 .status = NT_STATUS_OK,
282 .body_size = 0x04
286 status = smb2cli_req_recv(subreq, state, &iov,
287 expected, ARRAY_SIZE(expected));
288 TALLOC_FREE(subreq);
289 if (tevent_req_nterror(req, status)) {
290 return;
292 tevent_req_done(req);
295 NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
297 return tevent_req_simple_recv_ntstatus(req);
300 NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
301 uint32_t timeout_msec,
302 struct smbXcli_session *session)
304 TALLOC_CTX *frame = talloc_stackframe();
305 struct tevent_context *ev;
306 struct tevent_req *req;
307 NTSTATUS status = NT_STATUS_NO_MEMORY;
309 if (smbXcli_conn_has_async_calls(conn)) {
311 * Can't use sync call while an async call is in flight
313 status = NT_STATUS_INVALID_PARAMETER;
314 goto fail;
316 ev = tevent_context_init(frame);
317 if (ev == NULL) {
318 goto fail;
320 req = smb2cli_logoff_send(frame, ev, conn, timeout_msec, session);
321 if (req == NULL) {
322 goto fail;
324 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
325 goto fail;
327 status = smb2cli_logoff_recv(req);
328 fail:
329 TALLOC_FREE(frame);
330 return status;