r1796: Enable server-side SPNEGO, now that I have fixed the server-side SMB
[bbaumbach/samba-autobuild/.git] / source4 / smb_server / sesssetup.c
1 /* 
2    Unix SMB/CIFS implementation.
3    handle SMBsessionsetup
4    Copyright (C) Andrew Tridgell 1998-2001
5    Copyright (C) Andrew Bartlett      2001
6    Copyright (C) Jim McDonough        2002
7    Copyright (C) Luke Howard          2003
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 /*
27   setup the OS, Lanman and domain portions of a session setup reply
28 */
29 static void sesssetup_common_strings(struct smbsrv_request *req,
30                                      char **os, char **lanman, char **domain)
31 {
32         (*os) = talloc_asprintf(req->mem_ctx, "Unix");
33         (*lanman) = talloc_asprintf(req->mem_ctx, "Samba %s", SAMBA_VERSION_STRING);
34         (*domain) = talloc_asprintf(req->mem_ctx, "%s", lp_workgroup());
35 }
36
37
38 /*
39   handler for old style session setup
40 */
41 static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
42 {
43         NTSTATUS status;
44         struct auth_usersupplied_info *user_info = NULL;
45         struct auth_serversupplied_info *server_info = NULL;
46         struct auth_session_info *session_info;
47         DATA_BLOB null_blob;
48
49         if (!req->smb_conn->negotiate.done_sesssetup) {
50                 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
51         }
52
53         null_blob.length = 0;
54
55         status = make_user_info_for_reply_enc(&user_info, 
56                                               sess->old.in.user, sess->old.in.domain,
57                                               sess->old.in.password,
58                                               null_blob);
59         if (!NT_STATUS_IS_OK(status)) {
60                 return NT_STATUS_ACCESS_DENIED;
61         }
62
63         status = req->smb_conn->negotiate.auth_context->check_ntlm_password(req->smb_conn->negotiate.auth_context, 
64                                                                        user_info, 
65                                                                        &server_info);
66         if (!NT_STATUS_IS_OK(status)) {
67                 return nt_status_squash(status);
68         }
69
70         status = make_session_info(server_info, &session_info);
71         if (!NT_STATUS_IS_OK(status)) {
72                 return nt_status_squash(status);
73         }
74
75         sess->old.out.action = 0;
76         sess->old.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
77         if (sess->old.out.vuid == UID_FIELD_INVALID) {
78                 return NT_STATUS_ACCESS_DENIED;
79         }
80         sesssetup_common_strings(req, 
81                                  &sess->old.out.os,
82                                  &sess->old.out.lanman,
83                                  &sess->old.out.domain);
84
85         req->session = smbsrv_session_find(req->smb_conn, sess->old.out.vuid);
86
87         return NT_STATUS_OK;
88 }
89
90
91 /*
92   handler for NT1 style session setup
93 */
94 static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
95 {
96         NTSTATUS status;
97         struct auth_usersupplied_info *user_info = NULL;
98         struct auth_serversupplied_info *server_info = NULL;
99         struct auth_session_info *session_info;
100
101         if (!req->smb_conn->negotiate.done_sesssetup) {
102                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
103                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
104         }
105
106         if (req->smb_conn->negotiate.spnego_negotiated) {
107                 struct auth_context *auth_context;
108
109                 if (sess->nt1.in.user && *sess->nt1.in.user) {
110                         return NT_STATUS_ACCESS_DENIED;
111                 } else {
112                         make_user_info_guest(&user_info);
113                 }
114                 
115                 status = make_auth_context_subsystem(&auth_context);
116
117                 if (!NT_STATUS_IS_OK(status)) {
118                         return status;
119                 }
120                 
121                 status = auth_context->check_ntlm_password(auth_context, 
122                                                            user_info, 
123                                                            &server_info);
124                 
125                 free_auth_context(&auth_context);
126
127         } else {
128                 status = make_user_info_for_reply_enc(&user_info, 
129                                                       sess->nt1.in.user, sess->nt1.in.domain,
130                                                       sess->nt1.in.password1,
131                                                       sess->nt1.in.password2);
132                 if (!NT_STATUS_IS_OK(status)) {
133                         return NT_STATUS_ACCESS_DENIED;
134                 }
135                 
136                 status = req->smb_conn->negotiate
137                         .auth_context->check_ntlm_password(req->smb_conn->negotiate
138                                                            .auth_context, 
139                                                            user_info, 
140                                                            &server_info);
141         }
142
143         if (!NT_STATUS_IS_OK(status)) {
144                 return nt_status_squash(status);
145         }
146
147         status = make_session_info(server_info, &session_info);
148         if (!NT_STATUS_IS_OK(status)) {
149                 return nt_status_squash(status);
150         }
151
152         sess->nt1.out.action = 0;
153         sess->nt1.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
154         if (sess->nt1.out.vuid == UID_FIELD_INVALID) {
155                 return NT_STATUS_ACCESS_DENIED;
156         }
157         sesssetup_common_strings(req, 
158                                  &sess->nt1.out.os,
159                                  &sess->nt1.out.lanman,
160                                  &sess->nt1.out.domain);
161         
162         req->session = smbsrv_session_find(req->smb_conn, sess->nt1.out.vuid);
163         if (session_info->server_info->guest) {
164                 return NT_STATUS_OK;
165         }
166         if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
167                 /* Already signing, or disabled */
168                 return NT_STATUS_OK;
169         }
170                 
171         /* Force check of the request packet, now we know the session key */
172         req_signing_check_incoming(req);
173
174         srv_signing_restart(req->smb_conn,  &session_info->session_key, &sess->nt1.in.password2);
175
176         return NT_STATUS_OK;
177 }
178
179
180 /*
181   handler for SPNEGO style session setup
182 */
183 static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
184 {
185         NTSTATUS status = NT_STATUS_ACCESS_DENIED;
186         struct smbsrv_session *smb_sess;
187         struct gensec_security *gensec_ctx = NULL;
188         struct auth_session_info *session_info = NULL;
189         uint16_t vuid;
190
191         if (!req->smb_conn->negotiate.done_sesssetup) {
192                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
193                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
194         }
195
196         vuid = SVAL(req->in.hdr,HDR_UID);
197         smb_sess = smbsrv_session_find(req->smb_conn, vuid);
198         if (smb_sess) {
199                 if (!smb_sess->gensec_ctx) {
200                         return NT_STATUS_INVALID_HANDLE;
201                 }
202
203                 /* what is when the client is already successful authentificated? */
204                 if (smb_sess->session_info) {
205                         return NT_STATUS_ACCESS_DENIED;
206                 }
207
208                 status = gensec_update(smb_sess->gensec_ctx, req->mem_ctx, sess->spnego.in.secblob, &sess->spnego.out.secblob);
209         } else {
210                 status = gensec_server_start(&gensec_ctx);
211                 if (!NT_STATUS_IS_OK(status)) {
212                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
213                         return status;
214                 }
215
216                 status = gensec_start_mech_by_oid(gensec_ctx, OID_SPNEGO);
217                 if (!NT_STATUS_IS_OK(status)) {
218                         DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
219                         return status;
220                 }
221
222                 status = gensec_update(gensec_ctx, req->mem_ctx, sess->spnego.in.secblob, &sess->spnego.out.secblob);
223
224         }
225
226         if (!smb_sess) {
227                 vuid = smbsrv_register_session(req->smb_conn, session_info, gensec_ctx);
228                 if (vuid == UID_FIELD_INVALID) {
229                         return NT_STATUS_ACCESS_DENIED;
230                 }
231                 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
232                 if (!smb_sess) {
233                         return NT_STATUS_FOOBAR;
234                 }
235         }
236
237         if (NT_STATUS_IS_OK(status)) {
238                 DATA_BLOB session_key;
239                 
240                 status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info);
241                 if (!NT_STATUS_IS_OK(status)) {
242                         return status;
243                 }
244                 
245                 status = gensec_session_key(smb_sess->gensec_ctx, 
246                                             &session_key);
247                 if (NT_STATUS_IS_OK(status) 
248                     && !smb_sess->session_info->server_info->guest
249                     && srv_setup_signing(req->smb_conn, &session_key, NULL)) {
250                         /* Force check of the request packet, now we know the session key */
251                         req_signing_check_incoming(req);
252
253                         srv_signing_restart(req->smb_conn, &session_key, NULL);
254
255                 }
256         } else {
257                 status = nt_status_squash(status);
258         }
259
260         sess->spnego.out.action = 0;
261         sess->spnego.out.vuid = vuid;
262         sesssetup_common_strings(req, 
263                                  &sess->spnego.out.os,
264                                  &sess->spnego.out.lanman,
265                                  &sess->spnego.out.domain);
266
267         return status;
268 }
269
270 /*
271   backend for sessionsetup call - this takes all 3 variants of the call
272 */
273 NTSTATUS sesssetup_backend(struct smbsrv_request *req, 
274                            union smb_sesssetup *sess)
275 {
276         NTSTATUS status = NT_STATUS_INVALID_LEVEL;
277
278         switch (sess->generic.level) {
279                 case RAW_SESSSETUP_GENERIC:
280                         status = NT_STATUS_INVALID_LEVEL;
281                         break;
282                 case RAW_SESSSETUP_OLD:
283                         status = sesssetup_old(req, sess);
284                         break;
285                 case RAW_SESSSETUP_NT1:
286                         status = sesssetup_nt1(req, sess);
287                         break;
288                 case RAW_SESSSETUP_SPNEGO:
289                         status = sesssetup_spnego(req, sess);
290                         break;
291         }
292
293         if (NT_STATUS_IS_OK(status)) {
294                 req->smb_conn->negotiate.done_sesssetup = True;
295         }
296
297         return status;
298 }
299
300