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 "samba/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
;
133 struct tsocket_address
*remote_address
, *local_address
;
135 status
= samba_server_gensec_start(req
,
136 req
->smb_conn
->connection
->event
.ctx
,
137 req
->smb_conn
->connection
->msg_ctx
,
138 req
->smb_conn
->lp_ctx
,
139 req
->smb_conn
->negotiate
.server_credentials
,
142 if (!NT_STATUS_IS_OK(status
)) {
143 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status
)));
147 gensec_want_feature(gensec_ctx
, GENSEC_FEATURE_SESSION_KEY
);
148 gensec_want_feature(gensec_ctx
, GENSEC_FEATURE_SMB_TRANSPORT
);
150 remote_address
= socket_get_remote_addr(req
->smb_conn
->connection
->socket
,
152 if (!remote_address
) {
153 status
= NT_STATUS_INTERNAL_ERROR
;
154 DBG_ERR("Failed to obtain remote address\n");
158 status
= gensec_set_remote_address(gensec_ctx
,
160 if (!NT_STATUS_IS_OK(status
)) {
161 DBG_ERR("Failed to set remote address\n");
165 local_address
= socket_get_local_addr(req
->smb_conn
->connection
->socket
,
167 if (!local_address
) {
168 status
= NT_STATUS_INTERNAL_ERROR
;
169 DBG_ERR("Failed to obtain local address\n");
173 status
= gensec_set_local_address(gensec_ctx
,
175 if (!NT_STATUS_IS_OK(status
)) {
176 DBG_ERR("Failed to set local address\n");
180 status
= gensec_set_target_service_description(gensec_ctx
,
183 if (!NT_STATUS_IS_OK(status
)) {
184 DBG_ERR("Failed to set service description\n");
188 status
= gensec_start_mech_by_oid(gensec_ctx
, GENSEC_OID_SPNEGO
);
189 if (!NT_STATUS_IS_OK(status
)) {
190 DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status
)));
194 /* allocate a new session */
195 smb_sess
= smbsrv_session_new(req
->smb_conn
, req
->smb_conn
, gensec_ctx
);
197 status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
200 status
= smbsrv_smb2_init_tcons(smb_sess
);
201 if (!NT_STATUS_IS_OK(status
)) {
205 /* lookup an existing session */
206 smb_sess
= smbsrv_session_find_sesssetup(req
->smb_conn
, vuid
);
210 status
= NT_STATUS_USER_SESSION_DELETED
;
214 if (smb_sess
->session_info
) {
215 /* see WSPP test suite - test 11 */
216 status
= NT_STATUS_REQUEST_NOT_ACCEPTED
;
220 if (!smb_sess
->gensec_ctx
) {
221 status
= NT_STATUS_INTERNAL_ERROR
;
222 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status
)));
226 callback_ctx
= talloc(req
, struct smb2srv_sesssetup_callback_ctx
);
227 if (!callback_ctx
) goto nomem
;
228 callback_ctx
->req
= req
;
229 callback_ctx
->io
= io
;
230 callback_ctx
->smb_sess
= smb_sess
;
232 subreq
= gensec_update_send(callback_ctx
,
233 req
->smb_conn
->connection
->event
.ctx
,
234 smb_sess
->gensec_ctx
,
235 io
->smb2
.in
.secblob
);
236 if (!subreq
) goto nomem
;
237 tevent_req_set_callback(subreq
, smb2srv_sesssetup_callback
, callback_ctx
);
239 /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
240 This is deliberate as windows does not set it even when it does
241 set SMB2_NEGOTIATE_SIGNING_REQUIRED */
242 if (io
->smb2
.in
.security_mode
& SMB2_NEGOTIATE_SIGNING_REQUIRED
) {
243 smb_sess
->smb2_signing
.required
= true;
246 /* disable receipt of more packets on this socket until we've
247 finished with the session setup. This avoids a problem with
248 crashes if we get EOF on the socket while processing a session
250 packet_recv_disable(req
->smb_conn
->packet
);
254 status
= NT_STATUS_NO_MEMORY
;
256 talloc_free(smb_sess
);
257 req
->status
= nt_status_squash(status
);
258 smb2srv_sesssetup_send(req
, io
);
261 void smb2srv_sesssetup_recv(struct smb2srv_request
*req
)
263 union smb_sesssetup
*io
;
265 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, true);
266 SMB2SRV_TALLOC_IO_PTR(io
, union smb_sesssetup
);
268 io
->smb2
.level
= RAW_SESSSETUP_SMB2
;
269 io
->smb2
.in
.vc_number
= CVAL(req
->in
.body
, 0x02);
270 io
->smb2
.in
.security_mode
= CVAL(req
->in
.body
, 0x03);
271 io
->smb2
.in
.capabilities
= IVAL(req
->in
.body
, 0x04);
272 io
->smb2
.in
.channel
= IVAL(req
->in
.body
, 0x08);
273 io
->smb2
.in
.previous_sessionid
= BVAL(req
->in
.body
, 0x10);
274 SMB2SRV_CHECK(smb2_pull_o16s16_blob(&req
->in
, io
, req
->in
.body
+0x0C, &io
->smb2
.in
.secblob
));
276 smb2srv_sesssetup_backend(req
, io
);
279 static int smb2srv_cleanup_session_destructor(struct smbsrv_session
**session
)
281 /* TODO: call ntvfs backends to close file of this session */
282 DEBUG(0,("free session[%p]\n", *session
));
283 talloc_free(*session
);
287 static NTSTATUS
smb2srv_logoff_backend(struct smb2srv_request
*req
)
289 struct smbsrv_session
**session_ptr
;
291 /* we need to destroy the session after sending the reply */
292 session_ptr
= talloc(req
, struct smbsrv_session
*);
293 NT_STATUS_HAVE_NO_MEMORY(session_ptr
);
295 *session_ptr
= req
->session
;
296 talloc_set_destructor(session_ptr
, smb2srv_cleanup_session_destructor
);
301 static void smb2srv_logoff_send(struct smb2srv_request
*req
)
303 if (NT_STATUS_IS_ERR(req
->status
)) {
304 smb2srv_send_error(req
, req
->status
);
308 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, false, 0));
310 SSVAL(req
->out
.body
, 0x02, 0);
312 smb2srv_send_reply(req
);
315 void smb2srv_logoff_recv(struct smb2srv_request
*req
)
317 SMB2SRV_CHECK_BODY_SIZE(req
, 0x04, false);
319 req
->status
= smb2srv_logoff_backend(req
);
321 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
325 smb2srv_logoff_send(req
);