b263196165da0690c018b059e1bb692bb560ff4b
[samba.git] / source / smb_server / smb2 / sesssetup.c
1 /* 
2    Unix SMB2 implementation.
3    
4    Copyright (C) Andrew Bartlett        2001-2005
5    Copyright (C) Stefan Metzmacher      2005
6    
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 2 of the License, or
10    (at your option) any later version.
11    
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.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "auth/auth.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "smb_server/smb_server.h"
27 #include "smb_server/smb2/smb2_server.h"
28 #include "smbd/service_stream.h"
29
30 static NTSTATUS smb2srv_sesssetup_backend(struct smb2srv_request *req, struct smb2_session_setup *io)
31 {
32         NTSTATUS status;
33         struct smbsrv_session *smb_sess = NULL;
34         struct auth_session_info *session_info = NULL;
35         uint64_t vuid;
36
37         io->out._pad    = 0;
38         io->out.uid     = 0;
39         io->out.secblob = data_blob(NULL, 0);
40
41         vuid = BVAL(req->in.hdr, SMB2_HDR_UID);
42
43         /*
44          * only when we got '0' we should allocate a new session
45          */
46         if (vuid == 0) {
47                 struct gensec_security *gensec_ctx;
48
49                 status = gensec_server_start(req, &gensec_ctx,
50                                              req->smb_conn->connection->event.ctx);
51                 if (!NT_STATUS_IS_OK(status)) {
52                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
53                         return status;
54                 }
55
56                 gensec_set_credentials(gensec_ctx, req->smb_conn->negotiate.server_credentials);
57
58                 gensec_set_target_service(gensec_ctx, "cifs");
59
60                 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
61
62                 status = gensec_start_mech_by_oid(gensec_ctx, GENSEC_OID_SPNEGO);
63                 if (!NT_STATUS_IS_OK(status)) {
64                         DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
65                         return status;
66                 }
67
68                 /* allocate a new session */
69                 smb_sess = smbsrv_session_new(req->smb_conn, gensec_ctx);
70                 NT_STATUS_HAVE_NO_MEMORY(smb_sess);
71                 status = smbsrv_smb2_init_tcons(smb_sess);
72                 if (!NT_STATUS_IS_OK(status)) {
73                         goto failed;
74                 }
75         } else {
76                 /* lookup an existing session */
77                 smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
78         }
79
80         if (!smb_sess) {
81                 return NT_STATUS_USER_SESSION_DELETED;
82         }
83
84         if (!smb_sess->gensec_ctx) {
85                 status = NT_STATUS_INTERNAL_ERROR;
86                 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
87                 goto failed;
88         }
89
90         status = gensec_update(smb_sess->gensec_ctx, req, io->in.secblob, &io->out.secblob);
91         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
92                 io->out.uid = smb_sess->vuid;
93                 return status;
94         } else if (!NT_STATUS_IS_OK(status)) {
95                 goto failed;
96         }
97
98         status = gensec_session_info(smb_sess->gensec_ctx, &session_info);
99         if (!NT_STATUS_IS_OK(status)) {
100                 goto failed;
101         }
102                 
103         /* Ensure this is marked as a 'real' vuid, not one
104          * simply valid for the session setup leg */
105         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
106         if (!NT_STATUS_IS_OK(status)) {
107                 goto failed;
108         }
109         req->session = smb_sess;
110
111         io->out.uid = smb_sess->vuid;
112         return status;
113
114 failed:
115         talloc_free(smb_sess);
116         return auth_nt_status_squash(status);
117 }
118
119 static void smb2srv_sesssetup_send(struct smb2srv_request *req, struct smb2_session_setup *io)
120 {
121         NTSTATUS status;
122
123         if (NT_STATUS_IS_ERR(req->status) && !NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
124                 smb2srv_send_error(req, req->status);
125                 return;
126         }
127
128         status = smb2srv_setup_reply(req, 0x08, io->out.secblob.length);
129         if (!NT_STATUS_IS_OK(status)) {
130                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
131                 talloc_free(req);
132                 return;
133         }
134
135         SBVAL(req->out.hdr, SMB2_HDR_UID,    io->out.uid);
136
137         SSVAL(req->out.body, 0x02, io->out._pad);
138         status = smb2_push_o16s16_blob(&req->out, 0x04, io->out.secblob);
139         if (!NT_STATUS_IS_OK(status)) {
140                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
141                 talloc_free(req);
142                 return;
143         }
144
145         smb2srv_send_reply(req);
146 }
147
148 void smb2srv_sesssetup_recv(struct smb2srv_request *req)
149 {
150         struct smb2_session_setup *io;
151         NTSTATUS status;
152
153         if (req->in.body_size < 0x10) {
154                 smb2srv_send_error(req,  NT_STATUS_FOOBAR);
155                 return;
156         }
157
158         io = talloc(req, struct smb2_session_setup);
159         if (!io) {
160                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
161                 talloc_free(req);
162                 return;
163         }
164
165         io->in._pad     = SVAL(req->in.body, 0x02);
166         io->in.unknown2 = IVAL(req->in.body, 0x04);
167         io->in.unknown3 = IVAL(req->in.body, 0x08);
168         status = smb2_pull_o16s16_blob(&req->in, io, req->in.body+0x0C, &io->in.secblob);
169         if (!NT_STATUS_IS_OK(status)) {
170                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
171                 talloc_free(req);
172                 return;
173         }
174
175         req->status = smb2srv_sesssetup_backend(req, io);
176
177         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
178                 talloc_free(req);
179                 return;
180         }
181         smb2srv_sesssetup_send(req, io);
182 }
183
184 static NTSTATUS smb2srv_logoff_backend(struct smb2srv_request *req)
185 {
186         /* TODO: call ntvfs backends to close file of this session */
187         talloc_free(req->session);
188         req->session = NULL;
189         return NT_STATUS_OK;
190 }
191
192 static void smb2srv_logoff_send(struct smb2srv_request *req)
193 {
194         NTSTATUS status;
195
196         if (NT_STATUS_IS_ERR(req->status)) {
197                 smb2srv_send_error(req, req->status);
198                 return;
199         }
200
201         status = smb2srv_setup_reply(req, 0x04, 0);
202         if (!NT_STATUS_IS_OK(status)) {
203                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
204                 talloc_free(req);
205                 return;
206         }
207
208         SSVAL(req->out.body, 0x02, 0);
209
210         smb2srv_send_reply(req);
211 }
212
213 void smb2srv_logoff_recv(struct smb2srv_request *req)
214 {
215         uint16_t _pad;
216
217         if (req->in.body_size < 0x04) {
218                 smb2srv_send_error(req,  NT_STATUS_FOOBAR);
219                 return;
220         }
221
222         _pad    = SVAL(req->in.body, 0x02);
223
224         req->status = smb2srv_logoff_backend(req);
225
226         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
227                 talloc_free(req);
228                 return;
229         }
230         smb2srv_logoff_send(req);
231 }