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 /* see WSPP test suite - test 11 */
171 status
= NT_STATUS_REQUEST_NOT_ACCEPTED
;
175 if (!smb_sess
->gensec_ctx
) {
176 status
= NT_STATUS_INTERNAL_ERROR
;
177 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status
)));
181 callback_ctx
= talloc(req
, struct smb2srv_sesssetup_callback_ctx
);
182 if (!callback_ctx
) goto nomem
;
183 callback_ctx
->req
= req
;
184 callback_ctx
->io
= io
;
185 callback_ctx
->smb_sess
= smb_sess
;
187 subreq
= gensec_update_send(callback_ctx
,
188 req
->smb_conn
->connection
->event
.ctx
,
189 smb_sess
->gensec_ctx
,
190 io
->smb2
.in
.secblob
);
191 if (!subreq
) goto nomem
;
192 tevent_req_set_callback(subreq
, smb2srv_sesssetup_callback
, callback_ctx
);
194 /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
195 This is deliberate as windows does not set it even when it does
196 set SMB2_NEGOTIATE_SIGNING_REQUIRED */
197 if (io
->smb2
.in
.security_mode
& SMB2_NEGOTIATE_SIGNING_REQUIRED
) {
198 smb_sess
->smb2_signing
.required
= true;
199 } else if (req
->smb_conn
->smb2_signing_required
) {
201 * if required signing was negotiates in SMB2 Negotiate
202 * then the client made an error not using it here
204 DEBUG(1, ("SMB2 signing required on the connection but not used on session\n"));
205 req
->status
= NT_STATUS_FOOBAR
;
209 /* disable receipt of more packets on this socket until we've
210 finished with the session setup. This avoids a problem with
211 crashes if we get EOF on the socket while processing a session
213 packet_recv_disable(req
->smb_conn
->packet
);
217 status
= NT_STATUS_NO_MEMORY
;
219 talloc_free(smb_sess
);
220 req
->status
= nt_status_squash(status
);
221 smb2srv_sesssetup_send(req
, io
);
224 void smb2srv_sesssetup_recv(struct smb2srv_request
*req
)
226 union smb_sesssetup
*io
;
228 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, true);
229 SMB2SRV_TALLOC_IO_PTR(io
, union smb_sesssetup
);
231 io
->smb2
.level
= RAW_SESSSETUP_SMB2
;
232 io
->smb2
.in
.vc_number
= CVAL(req
->in
.body
, 0x02);
233 io
->smb2
.in
.security_mode
= CVAL(req
->in
.body
, 0x03);
234 io
->smb2
.in
.capabilities
= IVAL(req
->in
.body
, 0x04);
235 io
->smb2
.in
.channel
= IVAL(req
->in
.body
, 0x08);
236 io
->smb2
.in
.previous_sessionid
= BVAL(req
->in
.body
, 0x10);
237 SMB2SRV_CHECK(smb2_pull_o16s16_blob(&req
->in
, io
, req
->in
.body
+0x0C, &io
->smb2
.in
.secblob
));
239 smb2srv_sesssetup_backend(req
, io
);
242 static int smb2srv_cleanup_session_destructor(struct smbsrv_session
**session
)
244 /* TODO: call ntvfs backends to close file of this session */
245 DEBUG(0,("free session[%p]\n", *session
));
246 talloc_free(*session
);
250 static NTSTATUS
smb2srv_logoff_backend(struct smb2srv_request
*req
)
252 struct smbsrv_session
**session_ptr
;
254 /* we need to destroy the session after sending the reply */
255 session_ptr
= talloc(req
, struct smbsrv_session
*);
256 NT_STATUS_HAVE_NO_MEMORY(session_ptr
);
258 *session_ptr
= req
->session
;
259 talloc_set_destructor(session_ptr
, smb2srv_cleanup_session_destructor
);
264 static void smb2srv_logoff_send(struct smb2srv_request
*req
)
266 if (NT_STATUS_IS_ERR(req
->status
)) {
267 smb2srv_send_error(req
, req
->status
);
271 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, false, 0));
273 SSVAL(req
->out
.body
, 0x02, 0);
275 smb2srv_send_reply(req
);
278 void smb2srv_logoff_recv(struct smb2srv_request
*req
)
282 SMB2SRV_CHECK_BODY_SIZE(req
, 0x04, false);
284 _pad
= SVAL(req
->in
.body
, 0x02);
286 req
->status
= smb2srv_logoff_backend(req
);
288 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
292 smb2srv_logoff_send(req
);