2 Unix SMB/CIFS implementation.
4 SMB2 client session handling
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "libcli/composite/composite.h"
27 #include "auth/gensec/gensec.h"
28 #include "param/param.h"
31 initialise a smb2_session structure
33 struct smb2_session
*smb2_session_init(struct smb2_transport
*transport
,
34 struct loadparm_context
*lp_ctx
,
35 TALLOC_CTX
*parent_ctx
, bool primary
)
37 struct smb2_session
*session
;
40 session
= talloc_zero(parent_ctx
, struct smb2_session
);
45 session
->transport
= talloc_steal(session
, transport
);
47 session
->transport
= talloc_reference(session
, transport
);
50 /* prepare a gensec context for later use */
51 status
= gensec_client_start(session
, &session
->gensec
,
52 session
->transport
->socket
->event
.ctx
,
54 if (!NT_STATUS_IS_OK(status
)) {
59 gensec_want_feature(session
->gensec
, GENSEC_FEATURE_SESSION_KEY
);
65 send a session setup request
67 struct smb2_request
*smb2_session_setup_send(struct smb2_session
*session
,
68 struct smb2_session_setup
*io
)
70 struct smb2_request
*req
;
73 req
= smb2_request_init(session
->transport
, SMB2_OP_SESSSETUP
,
74 0x18, true, io
->in
.secblob
.length
);
75 if (req
== NULL
) return NULL
;
77 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, session
->uid
);
78 SCVAL(req
->out
.body
, 0x02, io
->in
.vc_number
);
79 SCVAL(req
->out
.body
, 0x03, io
->in
.security_mode
);
80 SIVAL(req
->out
.body
, 0x04, io
->in
.capabilities
);
81 SIVAL(req
->out
.body
, 0x08, io
->in
.channel
);
82 SBVAL(req
->out
.body
, 0x10, io
->in
.previous_sessionid
);
84 req
->session
= session
;
86 status
= smb2_push_o16s16_blob(&req
->out
, 0x0C, io
->in
.secblob
);
87 if (!NT_STATUS_IS_OK(status
)) {
92 smb2_transport_send(req
);
99 recv a session setup reply
101 NTSTATUS
smb2_session_setup_recv(struct smb2_request
*req
, TALLOC_CTX
*mem_ctx
,
102 struct smb2_session_setup
*io
)
106 if (!smb2_request_receive(req
) ||
107 (smb2_request_is_error(req
) &&
108 !NT_STATUS_EQUAL(req
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
))) {
109 return smb2_request_destroy(req
);
112 SMB2_CHECK_PACKET_RECV(req
, 0x08, true);
114 io
->out
.session_flags
= SVAL(req
->in
.body
, 0x02);
115 io
->out
.uid
= BVAL(req
->in
.hdr
, SMB2_HDR_SESSION_ID
);
117 status
= smb2_pull_o16s16_blob(&req
->in
, mem_ctx
, req
->in
.body
+0x04, &io
->out
.secblob
);
118 if (!NT_STATUS_IS_OK(status
)) {
119 smb2_request_destroy(req
);
123 return smb2_request_destroy(req
);
127 sync session setup request
129 NTSTATUS
smb2_session_setup(struct smb2_session
*session
,
130 TALLOC_CTX
*mem_ctx
, struct smb2_session_setup
*io
)
132 struct smb2_request
*req
= smb2_session_setup_send(session
, io
);
133 return smb2_session_setup_recv(req
, mem_ctx
, io
);
137 struct smb2_session_state
{
138 struct smb2_session_setup io
;
139 struct smb2_request
*req
;
140 NTSTATUS gensec_status
;
144 handle continuations of the spnego session setup
146 static void session_request_handler(struct smb2_request
*req
)
148 struct composite_context
*c
= talloc_get_type(req
->async
.private_data
,
149 struct composite_context
);
150 struct smb2_session_state
*state
= talloc_get_type(c
->private_data
,
151 struct smb2_session_state
);
152 struct smb2_session
*session
= req
->session
;
154 c
->status
= smb2_session_setup_recv(req
, c
, &state
->io
);
155 if (NT_STATUS_EQUAL(c
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) ||
156 (NT_STATUS_IS_OK(c
->status
) &&
157 NT_STATUS_EQUAL(state
->gensec_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
))) {
158 NTSTATUS session_key_err
;
159 DATA_BLOB session_key
;
160 c
->status
= gensec_update(session
->gensec
, c
,
161 state
->io
.out
.secblob
,
162 &state
->io
.in
.secblob
);
163 state
->gensec_status
= c
->status
;
165 session_key_err
= gensec_session_key(session
->gensec
, &session_key
);
166 if (NT_STATUS_IS_OK(session_key_err
)) {
167 session
->session_key
= session_key
;
171 session
->uid
= state
->io
.out
.uid
;
173 if (NT_STATUS_EQUAL(c
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
174 state
->req
= smb2_session_setup_send(session
, &state
->io
);
175 if (state
->req
== NULL
) {
176 composite_error(c
, NT_STATUS_NO_MEMORY
);
180 state
->req
->async
.fn
= session_request_handler
;
181 state
->req
->async
.private_data
= c
;
185 if (!NT_STATUS_IS_OK(c
->status
)) {
186 composite_error(c
, c
->status
);
190 if (session
->transport
->signing_required
) {
191 if (session
->session_key
.length
== 0) {
192 DEBUG(0,("Wrong session key length %u for SMB2 signing\n",
193 (unsigned)session
->session_key
.length
));
194 composite_error(c
, NT_STATUS_ACCESS_DENIED
);
197 session
->signing_active
= true;
204 a composite function that does a full SPNEGO session setup
206 struct composite_context
*smb2_session_setup_spnego_send(struct smb2_session
*session
,
207 struct cli_credentials
*credentials
)
209 struct composite_context
*c
;
210 struct smb2_session_state
*state
;
212 c
= composite_create(session
, session
->transport
->socket
->event
.ctx
);
213 if (c
== NULL
) return NULL
;
215 state
= talloc(c
, struct smb2_session_state
);
216 if (composite_nomem(state
, c
)) return c
;
217 c
->private_data
= state
;
219 ZERO_STRUCT(state
->io
);
220 state
->io
.in
.vc_number
= 0;
221 if (session
->transport
->signing_required
) {
222 state
->io
.in
.security_mode
=
223 SMB2_NEGOTIATE_SIGNING_ENABLED
| SMB2_NEGOTIATE_SIGNING_REQUIRED
;
225 state
->io
.in
.capabilities
= 0;
226 state
->io
.in
.channel
= 0;
227 state
->io
.in
.previous_sessionid
= 0;
229 c
->status
= gensec_set_credentials(session
->gensec
, credentials
);
230 if (!composite_is_ok(c
)) return c
;
232 c
->status
= gensec_set_target_hostname(session
->gensec
,
233 session
->transport
->socket
->hostname
);
234 if (!composite_is_ok(c
)) return c
;
236 c
->status
= gensec_set_target_service(session
->gensec
, "cifs");
237 if (!composite_is_ok(c
)) return c
;
239 c
->status
= gensec_start_mech_by_oid(session
->gensec
, GENSEC_OID_SPNEGO
);
240 if (!composite_is_ok(c
)) return c
;
242 c
->status
= gensec_update(session
->gensec
, c
,
243 session
->transport
->negotiate
.secblob
,
244 &state
->io
.in
.secblob
);
245 if (!NT_STATUS_EQUAL(c
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
246 composite_error(c
, c
->status
);
249 state
->gensec_status
= c
->status
;
251 state
->req
= smb2_session_setup_send(session
, &state
->io
);
252 composite_continue_smb2(c
, state
->req
, session_request_handler
, c
);
257 receive a composite session setup reply
259 NTSTATUS
smb2_session_setup_spnego_recv(struct composite_context
*c
)
262 status
= composite_wait(c
);
268 sync version of smb2_session_setup_spnego
270 NTSTATUS
smb2_session_setup_spnego(struct smb2_session
*session
,
271 struct cli_credentials
*credentials
)
273 struct composite_context
*c
= smb2_session_setup_spnego_send(session
, credentials
);
274 return smb2_session_setup_spnego_recv(c
);