2 Unix SMB2 implementation.
4 Copyright (C) Andrew Bartlett 2001-2005
5 Copyright (C) Stefan Metzmacher 2005
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.
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.
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/>.
23 #include "auth/gensec/gensec.h"
24 #include "auth/auth.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
27 #include "smb_server/smb_server.h"
28 #include "smb_server/smb2/smb2_server.h"
29 #include "smbd/service_stream.h"
30 #include "lib/stream/packet.h"
32 static void smb2srv_sesssetup_send(struct smb2srv_request
*req
, union smb_sesssetup
*io
)
34 if (NT_STATUS_IS_OK(req
->status
)) {
36 } else if (NT_STATUS_EQUAL(req
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
39 smb2srv_send_error(req
, req
->status
);
43 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x08, true, io
->smb2
.out
.secblob
.length
));
45 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, io
->smb2
.out
.uid
);
47 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.session_flags
);
48 SMB2SRV_CHECK(smb2_push_o16s16_blob(&req
->out
, 0x04, io
->smb2
.out
.secblob
));
50 smb2srv_send_reply(req
);
53 struct smb2srv_sesssetup_callback_ctx
{
54 struct smb2srv_request
*req
;
55 union smb_sesssetup
*io
;
56 struct smbsrv_session
*smb_sess
;
59 static void smb2srv_sesssetup_callback(struct tevent_req
*subreq
)
61 struct smb2srv_sesssetup_callback_ctx
*ctx
= tevent_req_callback_data(subreq
,
62 struct smb2srv_sesssetup_callback_ctx
);
63 struct smb2srv_request
*req
= ctx
->req
;
64 union smb_sesssetup
*io
= ctx
->io
;
65 struct smbsrv_session
*smb_sess
= ctx
->smb_sess
;
66 struct auth_session_info
*session_info
= NULL
;
67 enum security_user_level user_level
;
70 packet_recv_enable(req
->smb_conn
->packet
);
72 status
= gensec_update_recv(subreq
, req
, &io
->smb2
.out
.secblob
);
74 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
76 } else if (!NT_STATUS_IS_OK(status
)) {
80 status
= gensec_session_info(smb_sess
->gensec_ctx
, smb_sess
, &session_info
);
81 if (!NT_STATUS_IS_OK(status
)) {
85 /* Ensure this is marked as a 'real' vuid, not one
86 * simply valid for the session setup leg */
87 status
= smbsrv_session_sesssetup_finished(smb_sess
, session_info
);
88 if (!NT_STATUS_IS_OK(status
)) {
91 req
->session
= smb_sess
;
93 user_level
= security_session_user_level(smb_sess
->session_info
, NULL
);
94 if (user_level
>= SECURITY_USER
) {
95 if (smb_sess
->smb2_signing
.required
) {
96 /* activate smb2 signing on the session */
97 smb_sess
->smb2_signing
.active
= true;
99 /* we need to sign the session setup response */
100 req
->is_signed
= true;
104 io
->smb2
.out
.uid
= smb_sess
->vuid
;
106 req
->status
= nt_status_squash(status
);
107 smb2srv_sesssetup_send(req
, io
);
108 if (!NT_STATUS_IS_OK(status
) && !
109 NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
110 talloc_free(smb_sess
);
114 static void smb2srv_sesssetup_backend(struct smb2srv_request
*req
, union smb_sesssetup
*io
)
117 struct smb2srv_sesssetup_callback_ctx
*callback_ctx
;
118 struct smbsrv_session
*smb_sess
= NULL
;
120 struct tevent_req
*subreq
;
122 io
->smb2
.out
.session_flags
= 0;
123 io
->smb2
.out
.uid
= 0;
124 io
->smb2
.out
.secblob
= data_blob(NULL
, 0);
126 vuid
= BVAL(req
->in
.hdr
, SMB2_HDR_SESSION_ID
);
129 * only when we got '0' we should allocate a new session
132 struct gensec_security
*gensec_ctx
;
134 status
= samba_server_gensec_start(req
,
135 req
->smb_conn
->connection
->event
.ctx
,
136 req
->smb_conn
->connection
->msg_ctx
,
137 req
->smb_conn
->lp_ctx
,
138 req
->smb_conn
->negotiate
.server_credentials
,
141 if (!NT_STATUS_IS_OK(status
)) {
142 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status
)));
146 gensec_want_feature(gensec_ctx
, GENSEC_FEATURE_SESSION_KEY
);
148 status
= gensec_start_mech_by_oid(gensec_ctx
, GENSEC_OID_SPNEGO
);
149 if (!NT_STATUS_IS_OK(status
)) {
150 DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status
)));
154 /* allocate a new session */
155 smb_sess
= smbsrv_session_new(req
->smb_conn
, req
->smb_conn
, gensec_ctx
);
157 status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
160 status
= smbsrv_smb2_init_tcons(smb_sess
);
161 if (!NT_STATUS_IS_OK(status
)) {
165 /* lookup an existing session */
166 smb_sess
= smbsrv_session_find_sesssetup(req
->smb_conn
, vuid
);
170 status
= NT_STATUS_USER_SESSION_DELETED
;
174 if (smb_sess
->session_info
) {
175 /* see WSPP test suite - test 11 */
176 status
= NT_STATUS_REQUEST_NOT_ACCEPTED
;
180 if (!smb_sess
->gensec_ctx
) {
181 status
= NT_STATUS_INTERNAL_ERROR
;
182 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status
)));
186 callback_ctx
= talloc(req
, struct smb2srv_sesssetup_callback_ctx
);
187 if (!callback_ctx
) goto nomem
;
188 callback_ctx
->req
= req
;
189 callback_ctx
->io
= io
;
190 callback_ctx
->smb_sess
= smb_sess
;
192 subreq
= gensec_update_send(callback_ctx
,
193 req
->smb_conn
->connection
->event
.ctx
,
194 smb_sess
->gensec_ctx
,
195 io
->smb2
.in
.secblob
);
196 if (!subreq
) goto nomem
;
197 tevent_req_set_callback(subreq
, smb2srv_sesssetup_callback
, callback_ctx
);
199 /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
200 This is deliberate as windows does not set it even when it does
201 set SMB2_NEGOTIATE_SIGNING_REQUIRED */
202 if (io
->smb2
.in
.security_mode
& SMB2_NEGOTIATE_SIGNING_REQUIRED
) {
203 smb_sess
->smb2_signing
.required
= true;
204 } else if (req
->smb_conn
->smb2_signing_required
) {
206 * if required signing was negotiates in SMB2 Negotiate
207 * then the client made an error not using it here
209 DEBUG(1, ("SMB2 signing required on the connection but not used on session\n"));
210 req
->status
= NT_STATUS_FOOBAR
;
214 /* disable receipt of more packets on this socket until we've
215 finished with the session setup. This avoids a problem with
216 crashes if we get EOF on the socket while processing a session
218 packet_recv_disable(req
->smb_conn
->packet
);
222 status
= NT_STATUS_NO_MEMORY
;
224 talloc_free(smb_sess
);
225 req
->status
= nt_status_squash(status
);
226 smb2srv_sesssetup_send(req
, io
);
229 void smb2srv_sesssetup_recv(struct smb2srv_request
*req
)
231 union smb_sesssetup
*io
;
233 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, true);
234 SMB2SRV_TALLOC_IO_PTR(io
, union smb_sesssetup
);
236 io
->smb2
.level
= RAW_SESSSETUP_SMB2
;
237 io
->smb2
.in
.vc_number
= CVAL(req
->in
.body
, 0x02);
238 io
->smb2
.in
.security_mode
= CVAL(req
->in
.body
, 0x03);
239 io
->smb2
.in
.capabilities
= IVAL(req
->in
.body
, 0x04);
240 io
->smb2
.in
.channel
= IVAL(req
->in
.body
, 0x08);
241 io
->smb2
.in
.previous_sessionid
= BVAL(req
->in
.body
, 0x10);
242 SMB2SRV_CHECK(smb2_pull_o16s16_blob(&req
->in
, io
, req
->in
.body
+0x0C, &io
->smb2
.in
.secblob
));
244 smb2srv_sesssetup_backend(req
, io
);
247 static int smb2srv_cleanup_session_destructor(struct smbsrv_session
**session
)
249 /* TODO: call ntvfs backends to close file of this session */
250 DEBUG(0,("free session[%p]\n", *session
));
251 talloc_free(*session
);
255 static NTSTATUS
smb2srv_logoff_backend(struct smb2srv_request
*req
)
257 struct smbsrv_session
**session_ptr
;
259 /* we need to destroy the session after sending the reply */
260 session_ptr
= talloc(req
, struct smbsrv_session
*);
261 NT_STATUS_HAVE_NO_MEMORY(session_ptr
);
263 *session_ptr
= req
->session
;
264 talloc_set_destructor(session_ptr
, smb2srv_cleanup_session_destructor
);
269 static void smb2srv_logoff_send(struct smb2srv_request
*req
)
271 if (NT_STATUS_IS_ERR(req
->status
)) {
272 smb2srv_send_error(req
, req
->status
);
276 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, false, 0));
278 SSVAL(req
->out
.body
, 0x02, 0);
280 smb2srv_send_reply(req
);
283 void smb2srv_logoff_recv(struct smb2srv_request
*req
)
287 SMB2SRV_CHECK_BODY_SIZE(req
, 0x04, false);
289 _pad
= SVAL(req
->in
.body
, 0x02);
291 req
->status
= smb2srv_logoff_backend(req
);
293 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
297 smb2srv_logoff_send(req
);