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
)
36 if (NT_STATUS_IS_OK(req
->status
)) {
38 } else if (NT_STATUS_EQUAL(req
->status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
41 smb2srv_send_error(req
, req
->status
);
45 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x08, true, io
->smb2
.out
.secblob
.length
));
47 SSVAL(req
->out
.hdr
, SMB2_HDR_CREDIT
, credit
);
48 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, io
->smb2
.out
.uid
);
50 SSVAL(req
->out
.body
, 0x02, io
->smb2
.out
.session_flags
);
51 SMB2SRV_CHECK(smb2_push_o16s16_blob(&req
->out
, 0x04, io
->smb2
.out
.secblob
));
53 smb2srv_send_reply(req
);
56 struct smb2srv_sesssetup_callback_ctx
{
57 struct smb2srv_request
*req
;
58 union smb_sesssetup
*io
;
59 struct smbsrv_session
*smb_sess
;
62 static void smb2srv_sesssetup_callback(struct tevent_req
*subreq
)
64 struct smb2srv_sesssetup_callback_ctx
*ctx
= tevent_req_callback_data(subreq
,
65 struct smb2srv_sesssetup_callback_ctx
);
66 struct smb2srv_request
*req
= ctx
->req
;
67 union smb_sesssetup
*io
= ctx
->io
;
68 struct smbsrv_session
*smb_sess
= ctx
->smb_sess
;
69 struct auth_session_info
*session_info
= NULL
;
72 packet_recv_enable(req
->smb_conn
->packet
);
74 status
= gensec_update_recv(subreq
, req
, &io
->smb2
.out
.secblob
);
76 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
78 } else if (!NT_STATUS_IS_OK(status
)) {
82 status
= gensec_session_info(smb_sess
->gensec_ctx
, &session_info
);
83 if (!NT_STATUS_IS_OK(status
)) {
87 /* Ensure this is marked as a 'real' vuid, not one
88 * simply valid for the session setup leg */
89 status
= smbsrv_session_sesssetup_finished(smb_sess
, session_info
);
90 if (!NT_STATUS_IS_OK(status
)) {
93 req
->session
= smb_sess
;
95 if (smb_sess
->smb2_signing
.required
) {
96 /* activate smb2 signing on the session */
97 smb_sess
->smb2_signing
.active
= true;
100 io
->smb2
.out
.uid
= smb_sess
->vuid
;
102 req
->status
= nt_status_squash(status
);
103 smb2srv_sesssetup_send(req
, io
);
104 if (!NT_STATUS_IS_OK(status
) && !
105 NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
106 talloc_free(smb_sess
);
110 static void smb2srv_sesssetup_backend(struct smb2srv_request
*req
, union smb_sesssetup
*io
)
113 struct smb2srv_sesssetup_callback_ctx
*callback_ctx
;
114 struct smbsrv_session
*smb_sess
= NULL
;
116 struct tevent_req
*subreq
;
118 io
->smb2
.out
.session_flags
= 0;
119 io
->smb2
.out
.uid
= 0;
120 io
->smb2
.out
.secblob
= data_blob(NULL
, 0);
122 vuid
= BVAL(req
->in
.hdr
, SMB2_HDR_SESSION_ID
);
125 * only when we got '0' we should allocate a new session
128 struct gensec_security
*gensec_ctx
;
130 status
= samba_server_gensec_start(req
,
131 req
->smb_conn
->connection
->event
.ctx
,
132 req
->smb_conn
->connection
->msg_ctx
,
133 req
->smb_conn
->lp_ctx
,
134 req
->smb_conn
->negotiate
.server_credentials
,
137 if (!NT_STATUS_IS_OK(status
)) {
138 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status
)));
142 gensec_want_feature(gensec_ctx
, GENSEC_FEATURE_SESSION_KEY
);
144 status
= gensec_start_mech_by_oid(gensec_ctx
, GENSEC_OID_SPNEGO
);
145 if (!NT_STATUS_IS_OK(status
)) {
146 DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status
)));
150 /* allocate a new session */
151 smb_sess
= smbsrv_session_new(req
->smb_conn
, req
->smb_conn
, gensec_ctx
);
153 status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
156 status
= smbsrv_smb2_init_tcons(smb_sess
);
157 if (!NT_STATUS_IS_OK(status
)) {
161 /* lookup an existing session */
162 smb_sess
= smbsrv_session_find_sesssetup(req
->smb_conn
, vuid
);
166 /* see WSPP test suite - test 11 */
167 status
= NT_STATUS_REQUEST_NOT_ACCEPTED
;
171 if (!smb_sess
->gensec_ctx
) {
172 status
= NT_STATUS_INTERNAL_ERROR
;
173 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status
)));
177 callback_ctx
= talloc(req
, struct smb2srv_sesssetup_callback_ctx
);
178 if (!callback_ctx
) goto nomem
;
179 callback_ctx
->req
= req
;
180 callback_ctx
->io
= io
;
181 callback_ctx
->smb_sess
= smb_sess
;
183 subreq
= gensec_update_send(callback_ctx
,
184 req
->smb_conn
->connection
->event
.ctx
,
185 smb_sess
->gensec_ctx
,
186 io
->smb2
.in
.secblob
);
187 if (!subreq
) goto nomem
;
188 tevent_req_set_callback(subreq
, smb2srv_sesssetup_callback
, callback_ctx
);
190 /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
191 This is deliberate as windows does not set it even when it does
192 set SMB2_NEGOTIATE_SIGNING_REQUIRED */
193 if (io
->smb2
.in
.security_mode
& SMB2_NEGOTIATE_SIGNING_REQUIRED
) {
194 smb_sess
->smb2_signing
.required
= true;
195 } else if (req
->smb_conn
->smb2_signing_required
) {
197 * if required signing was negotiates in SMB2 Negotiate
198 * then the client made an error not using it here
200 DEBUG(1, ("SMB2 signing required on the connection but not used on session\n"));
201 req
->status
= NT_STATUS_FOOBAR
;
205 /* disable receipt of more packets on this socket until we've
206 finished with the session setup. This avoids a problem with
207 crashes if we get EOF on the socket while processing a session
209 packet_recv_disable(req
->smb_conn
->packet
);
213 status
= NT_STATUS_NO_MEMORY
;
215 talloc_free(smb_sess
);
216 req
->status
= nt_status_squash(status
);
217 smb2srv_sesssetup_send(req
, io
);
220 void smb2srv_sesssetup_recv(struct smb2srv_request
*req
)
222 union smb_sesssetup
*io
;
224 SMB2SRV_CHECK_BODY_SIZE(req
, 0x18, true);
225 SMB2SRV_TALLOC_IO_PTR(io
, union smb_sesssetup
);
227 io
->smb2
.level
= RAW_SESSSETUP_SMB2
;
228 io
->smb2
.in
.vc_number
= CVAL(req
->in
.body
, 0x02);
229 io
->smb2
.in
.security_mode
= CVAL(req
->in
.body
, 0x03);
230 io
->smb2
.in
.capabilities
= IVAL(req
->in
.body
, 0x04);
231 io
->smb2
.in
.channel
= IVAL(req
->in
.body
, 0x08);
232 io
->smb2
.in
.previous_sessionid
= BVAL(req
->in
.body
, 0x10);
233 SMB2SRV_CHECK(smb2_pull_o16s16_blob(&req
->in
, io
, req
->in
.body
+0x0C, &io
->smb2
.in
.secblob
));
235 smb2srv_sesssetup_backend(req
, io
);
238 static int smb2srv_cleanup_session_destructor(struct smbsrv_session
**session
)
240 /* TODO: call ntvfs backends to close file of this session */
241 DEBUG(0,("free session[%p]\n", *session
));
242 talloc_free(*session
);
246 static NTSTATUS
smb2srv_logoff_backend(struct smb2srv_request
*req
)
248 struct smbsrv_session
**session_ptr
;
250 /* we need to destroy the session after sending the reply */
251 session_ptr
= talloc(req
, struct smbsrv_session
*);
252 NT_STATUS_HAVE_NO_MEMORY(session_ptr
);
254 *session_ptr
= req
->session
;
255 talloc_set_destructor(session_ptr
, smb2srv_cleanup_session_destructor
);
260 static void smb2srv_logoff_send(struct smb2srv_request
*req
)
262 if (NT_STATUS_IS_ERR(req
->status
)) {
263 smb2srv_send_error(req
, req
->status
);
267 SMB2SRV_CHECK(smb2srv_setup_reply(req
, 0x04, false, 0));
269 SSVAL(req
->out
.body
, 0x02, 0);
271 smb2srv_send_reply(req
);
274 void smb2srv_logoff_recv(struct smb2srv_request
*req
)
278 SMB2SRV_CHECK_BODY_SIZE(req
, 0x04, false);
280 _pad
= SVAL(req
->in
.body
, 0x02);
282 req
->status
= smb2srv_logoff_backend(req
);
284 if (req
->control_flags
& SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY
) {
288 smb2srv_logoff_send(req
);