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/>.
22 #include "auth/credentials/credentials.h"
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/service_smb_proto.h"
29 #include "smb_server/smb2/smb2_server.h"
30 #include "smbd/service_stream.h"
31 #include "param/param.h"
33 static void smb2srv_sesssetup_send(struct smb2srv_request
*req
, union smb_sesssetup
*io
)
37 if (NT_STATUS_IS_OK(req
->status
)) {
39 } else if (NT_STATUS_EQUAL(req
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
42 smb2srv_send_error(req
, req
->status
);
46 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x08, true, io
->smb2
.out
.secblob
.length
));
48 SSVAL(req
->out
.hdr
, SMB2_HDR_CREDIT
, credit
);
49 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, io
->smb2
.out
.uid
);
51 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.session_flags
);
52 SMB2SRV_CHECK(smb2_push_o16s16_blob(&req
->out
, 0x04, io
->smb2
.out
.secblob
));
54 smb2srv_send_reply(req
);
57 struct smb2srv_sesssetup_callback_ctx
{
58 struct smb2srv_request
*req
;
59 union smb_sesssetup
*io
;
60 struct smbsrv_session
*smb_sess
;
63 static void smb2srv_sesssetup_callback(struct gensec_update_request
*greq
, void *private_data
)
65 struct smb2srv_sesssetup_callback_ctx
*ctx
= talloc_get_type(private_data
,
66 struct smb2srv_sesssetup_callback_ctx
);
67 struct smb2srv_request
*req
= ctx
->req
;
68 union smb_sesssetup
*io
= ctx
->io
;
69 struct smbsrv_session
*smb_sess
= ctx
->smb_sess
;
70 struct auth_session_info
*session_info
= NULL
;
73 status
= gensec_update_recv(greq
, 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
, &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 if (smb_sess
->smb2_signing
.required
) {
94 /* activate smb2 signing on the session */
95 smb_sess
->smb2_signing
.active
= true;
98 io
->smb2
.out
.uid
= smb_sess
->vuid
;
100 req
->status
= auth_nt_status_squash(status
);
101 smb2srv_sesssetup_send(req
, io
);
102 if (!NT_STATUS_IS_OK(status
) && !
103 NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
104 talloc_free(smb_sess
);
108 static void smb2srv_sesssetup_backend(struct smb2srv_request
*req
, union smb_sesssetup
*io
)
111 struct smb2srv_sesssetup_callback_ctx
*callback_ctx
;
112 struct smbsrv_session
*smb_sess
= NULL
;
115 io
->smb2
.out
.session_flags
= 0;
116 io
->smb2
.out
.uid
= 0;
117 io
->smb2
.out
.secblob
= data_blob(NULL
, 0);
119 vuid
= BVAL(req
->in
.hdr
, SMB2_HDR_SESSION_ID
);
122 * only when we got '0' we should allocate a new session
125 struct gensec_security
*gensec_ctx
;
127 status
= samba_server_gensec_start(req
,
128 req
->smb_conn
->connection
->event
.ctx
,
129 req
->smb_conn
->connection
->msg_ctx
,
130 req
->smb_conn
->lp_ctx
,
131 req
->smb_conn
->negotiate
.server_credentials
,
134 if (!NT_STATUS_IS_OK(status
)) {
135 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status
)));
139 gensec_want_feature(gensec_ctx
, GENSEC_FEATURE_SESSION_KEY
);
141 status
= gensec_start_mech_by_oid(gensec_ctx
, GENSEC_OID_SPNEGO
);
142 if (!NT_STATUS_IS_OK(status
)) {
143 DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status
)));
147 /* allocate a new session */
148 smb_sess
= smbsrv_session_new(req
->smb_conn
, req
->smb_conn
, gensec_ctx
);
150 status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
153 status
= smbsrv_smb2_init_tcons(smb_sess
);
154 if (!NT_STATUS_IS_OK(status
)) {
158 /* lookup an existing session */
159 smb_sess
= smbsrv_session_find_sesssetup(req
->smb_conn
, vuid
);
163 /* see WSPP test suite - test 11 */
164 status
= NT_STATUS_REQUEST_NOT_ACCEPTED
;
168 if (!smb_sess
->gensec_ctx
) {
169 status
= NT_STATUS_INTERNAL_ERROR
;
170 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status
)));
174 callback_ctx
= talloc(req
, struct smb2srv_sesssetup_callback_ctx
);
175 if (!callback_ctx
) goto nomem
;
176 callback_ctx
->req
= req
;
177 callback_ctx
->io
= io
;
178 callback_ctx
->smb_sess
= smb_sess
;
180 gensec_update_send(smb_sess
->gensec_ctx
, io
->smb2
.in
.secblob
,
181 smb2srv_sesssetup_callback
, callback_ctx
);
183 /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
184 This is deliberate as windows does not set it even when it does
185 set SMB2_NEGOTIATE_SIGNING_REQUIRED */
186 if (io
->smb2
.in
.security_mode
& SMB2_NEGOTIATE_SIGNING_REQUIRED
) {
187 smb_sess
->smb2_signing
.required
= true;
188 } else if (req
->smb_conn
->smb2_signing_required
) {
190 * if required signing was negotiates in SMB2 Negotiate
191 * then the client made an error not using it here
193 DEBUG(1, ("SMB2 signing required on the connection but not used on session\n"));
194 req
->status
= NT_STATUS_FOOBAR
;
200 status
= NT_STATUS_NO_MEMORY
;
202 talloc_free(smb_sess
);
203 req
->status
= auth_nt_status_squash(status
);
204 smb2srv_sesssetup_send(req
, io
);
207 void smb2srv_sesssetup_recv(struct smb2srv_request
*req
)
209 union smb_sesssetup
*io
;
211 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, true);
212 SMB2SRV_TALLOC_IO_PTR(io
, union smb_sesssetup
);
214 io
->smb2
.level
= RAW_SESSSETUP_SMB2
;
215 io
->smb2
.in
.vc_number
= CVAL(req
->in
.body
, 0x02);
216 io
->smb2
.in
.security_mode
= CVAL(req
->in
.body
, 0x03);
217 io
->smb2
.in
.capabilities
= IVAL(req
->in
.body
, 0x04);
218 io
->smb2
.in
.channel
= IVAL(req
->in
.body
, 0x08);
219 io
->smb2
.in
.previous_sessionid
= BVAL(req
->in
.body
, 0x10);
220 SMB2SRV_CHECK(smb2_pull_o16s16_blob(&req
->in
, io
, req
->in
.body
+0x0C, &io
->smb2
.in
.secblob
));
222 smb2srv_sesssetup_backend(req
, io
);
225 static int smb2srv_cleanup_session_destructor(struct smbsrv_session
**session
)
227 /* TODO: call ntvfs backends to close file of this session */
228 DEBUG(0,("free session[%p]\n", *session
));
229 talloc_free(*session
);
233 static NTSTATUS
smb2srv_logoff_backend(struct smb2srv_request
*req
)
235 struct smbsrv_session
**session_ptr
;
237 /* we need to destroy the session after sending the reply */
238 session_ptr
= talloc(req
, struct smbsrv_session
*);
239 NT_STATUS_HAVE_NO_MEMORY(session_ptr
);
241 *session_ptr
= req
->session
;
242 talloc_set_destructor(session_ptr
, smb2srv_cleanup_session_destructor
);
247 static void smb2srv_logoff_send(struct smb2srv_request
*req
)
249 if (NT_STATUS_IS_ERR(req
->status
)) {
250 smb2srv_send_error(req
, req
->status
);
254 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, false, 0));
256 SSVAL(req
->out
.body
, 0x02, 0);
258 smb2srv_send_reply(req
);
261 void smb2srv_logoff_recv(struct smb2srv_request
*req
)
265 SMB2SRV_CHECK_BODY_SIZE(req
, 0x04, false);
267 _pad
= SVAL(req
->in
.body
, 0x02);
269 req
->status
= smb2srv_logoff_backend(req
);
271 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
275 smb2srv_logoff_send(req
);