r12092: - add dummy functions for the missing SMB2 opcodes
[samba.git] / source4 / 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 = NT_STATUS_ACCESS_DENIED;
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         /* TODO: we're stricter than the SMB version till we have
44          *       SMB2-CONTEXT test
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         } else {
71                 /* lookup an existing session */
72                 smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
73         }
74
75         if (!smb_sess) {
76                 return NT_STATUS_ACCESS_DENIED;
77         }
78
79         if (!smb_sess->gensec_ctx) {
80                 status = NT_STATUS_INTERNAL_ERROR;
81                 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
82                 goto failed;
83         }
84
85         status = gensec_update(smb_sess->gensec_ctx, req, io->in.secblob, &io->out.secblob);
86         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
87                 io->out.uid = smb_sess->vuid;
88                 return status;
89         } else if (!NT_STATUS_IS_OK(status)) {
90                 goto failed;
91         }
92
93         status = gensec_session_info(smb_sess->gensec_ctx, &session_info);
94         if (!NT_STATUS_IS_OK(status)) {
95                 goto failed;
96         }
97                 
98         /* Ensure this is marked as a 'real' vuid, not one
99          * simply valid for the session setup leg */
100         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
101         if (!NT_STATUS_IS_OK(status)) {
102                 goto failed;
103         }
104         req->session = smb_sess;
105
106         io->out.uid = smb_sess->vuid;
107         return status;
108
109 failed:
110         talloc_free(smb_sess);
111         return auth_nt_status_squash(status);
112 }
113
114 static void smb2srv_sesssetup_send(struct smb2srv_request *req, struct smb2_session_setup *io)
115 {
116         NTSTATUS status;
117
118         if (NT_STATUS_IS_ERR(req->status) && !NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
119                 smb2srv_send_error(req, req->status);
120                 return;
121         }
122
123         status = smb2srv_setup_reply(req, 0x08, io->out.secblob.length);
124         if (!NT_STATUS_IS_OK(status)) {
125                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
126                 talloc_free(req);
127                 return;
128         }
129
130         SBVAL(req->out.hdr, SMB2_HDR_UID,    io->out.uid);
131
132         SSVAL(req->out.body, 0x02, io->out._pad);
133         status = smb2_push_o16s16_blob(&req->out, 0x04, io->out.secblob);
134         if (!NT_STATUS_IS_OK(status)) {
135                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
136                 talloc_free(req);
137                 return;
138         }
139
140         smb2srv_send_reply(req);
141 }
142
143 void smb2srv_sesssetup_recv(struct smb2srv_request *req)
144 {
145         struct smb2_session_setup *io;
146         NTSTATUS status;
147
148         if (req->in.body_size < 0x10) {
149                 smb2srv_send_error(req,  NT_STATUS_FOOBAR);
150                 return;
151         }
152
153         io = talloc(req, struct smb2_session_setup);
154         if (!io) {
155                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
156                 talloc_free(req);
157                 return;
158         }
159
160         io->in._pad     = SVAL(req->in.body, 0x02);
161         io->in.unknown2 = IVAL(req->in.body, 0x04);
162         io->in.unknown3 = IVAL(req->in.body, 0x08);
163         status = smb2_pull_o16s16_blob(&req->in, io, req->in.body+0x0C, &io->in.secblob);
164         if (!NT_STATUS_IS_OK(status)) {
165                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
166                 talloc_free(req);
167                 return;
168         }
169
170         req->status = smb2srv_sesssetup_backend(req, io);
171
172         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
173                 talloc_free(req);
174                 return;
175         }
176         smb2srv_sesssetup_send(req, io);
177 }
178
179 static NTSTATUS smb2srv_logoff_backend(struct smb2srv_request *req)
180 {
181         /* TODO: call ntvfs backends to close file of this session */
182         talloc_free(req->session);
183         req->session = NULL;
184         return NT_STATUS_OK;
185 }
186
187 static void smb2srv_logoff_send(struct smb2srv_request *req)
188 {
189         NTSTATUS status;
190
191         if (NT_STATUS_IS_ERR(req->status)) {
192                 smb2srv_send_error(req, req->status);
193                 return;
194         }
195
196         status = smb2srv_setup_reply(req, 0x04, 0);
197         if (!NT_STATUS_IS_OK(status)) {
198                 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
199                 talloc_free(req);
200                 return;
201         }
202
203         SSVAL(req->out.body, 0x02, 0);
204
205         smb2srv_send_reply(req);
206 }
207
208 void smb2srv_logoff_recv(struct smb2srv_request *req)
209 {
210         uint16_t _pad;
211
212         if (req->in.body_size < 0x04) {
213                 smb2srv_send_error(req,  NT_STATUS_FOOBAR);
214                 return;
215         }
216
217         _pad    = SVAL(req->in.body, 0x02);
218
219         req->status = smb2srv_logoff_backend(req);
220
221         if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
222                 talloc_free(req);
223                 return;
224         }
225         smb2srv_logoff_send(req);
226 }