libcli/smb: there's no PID field in the SMB2/3 header anymore
[mat/samba.git] / libcli / smb / smb2cli_session.c
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_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;
33 };
34
35 static void smb2cli_session_setup_done(struct tevent_req *subreq);
36
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)
47 {
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;
56
57         req = tevent_req_create(mem_ctx, &state,
58                                 struct smb2cli_session_setup_state);
59         if (req == NULL) {
60                 return NULL;
61         }
62
63         if (session == NULL) {
64                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
65                 return tevent_req_post(req, ev);
66         }
67         state->session = session;
68         security_mode = smb2cli_session_security_mode(session);
69
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);
74                 }
75                 security_buffer_offset = SMB2_HDR_BODY + 24;
76                 security_buffer_length = in_security_buffer->length;
77         }
78
79         buf = state->fixed;
80
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);
89
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);
96         }
97
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);
108         }
109         tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
110         return req;
111 }
112
113 static void smb2cli_session_setup_done(struct tevent_req *subreq)
114 {
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[] = {
132         {
133                 .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
134                 .body_size = 0x09
135         },
136         {
137                 .status = NT_STATUS_OK,
138                 .body_size = 0x09
139         }
140         };
141
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;
149         }
150
151         hdr = (const uint8_t *)state->recv_iov[0].iov_base;
152         body = (const uint8_t *)state->recv_iov[1].iov_base;
153
154         session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
155         session_flags = SVAL(body, 2);
156
157         security_buffer_offset = SVAL(body, 4);
158         security_buffer_length = SVAL(body, 6);
159
160         if (security_buffer_length > 0) {
161                 expected_offset = SMB2_HDR_BODY + 8;
162         }
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;
166         }
167
168         if (security_buffer_offset != expected_offset) {
169                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
170                 return;
171         }
172         if (security_buffer_length > state->recv_iov[2].iov_len) {
173                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
174                 return;
175         }
176
177         state->out_security_buffer.data = security_buffer_data;
178         state->out_security_buffer.length = security_buffer_length;
179
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;
184         }
185
186         if (current_session_id != session_id) {
187                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
188                 return;
189         }
190
191         smb2cli_session_set_id_and_flags(state->session,
192                                          session_id, session_flags);
193
194         state->status = status;
195         tevent_req_done(req);
196 }
197
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)
202 {
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;
208
209         if (tevent_req_is_nterror(req, &status)) {
210                 tevent_req_received(req);
211                 return status;
212         }
213
214         if (recv_iov == NULL) {
215                 recv_iov = &_tmp;
216         }
217
218         *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
219
220         *out_security_buffer = state->out_security_buffer;
221
222         /*
223          * Return the status from the server:
224          * NT_STATUS_MORE_PROCESSING_REQUIRED or
225          * NT_STATUS_OK.
226          */
227         status = state->status;
228         tevent_req_received(req);
229         return status;
230 }
231
232 struct smb2cli_logoff_state {
233         uint8_t fixed[4];
234 };
235
236 static void smb2cli_logoff_done(struct tevent_req *subreq);
237
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)
243 {
244         struct tevent_req *req, *subreq;
245         struct smb2cli_logoff_state *state;
246
247         req = tevent_req_create(mem_ctx, &state,
248                                 struct smb2cli_logoff_state);
249         if (req == NULL) {
250                 return NULL;
251         }
252         SSVAL(state->fixed, 0, 4);
253
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);
264         }
265         tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
266         return req;
267 }
268
269 static void smb2cli_logoff_done(struct tevent_req *subreq)
270 {
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[] = {
280         {
281                 .status = NT_STATUS_OK,
282                 .body_size = 0x04
283         }
284         };
285
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;
291         }
292         tevent_req_done(req);
293 }
294
295 NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
296 {
297         return tevent_req_simple_recv_ntstatus(req);
298 }
299
300 NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
301                         uint32_t timeout_msec,
302                         struct smbXcli_session *session)
303 {
304         TALLOC_CTX *frame = talloc_stackframe();
305         struct tevent_context *ev;
306         struct tevent_req *req;
307         NTSTATUS status = NT_STATUS_NO_MEMORY;
308
309         if (smbXcli_conn_has_async_calls(conn)) {
310                 /*
311                  * Can't use sync call while an async call is in flight
312                  */
313                 status = NT_STATUS_INVALID_PARAMETER;
314                 goto fail;
315         }
316         ev = tevent_context_init(frame);
317         if (ev == NULL) {
318                 goto fail;
319         }
320         req = smb2cli_logoff_send(frame, ev, conn, timeout_msec, session);
321         if (req == NULL) {
322                 goto fail;
323         }
324         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
325                 goto fail;
326         }
327         status = smb2cli_logoff_recv(req);
328  fail:
329         TALLOC_FREE(frame);
330         return status;
331 }