r19598: Ahead of a merge to current lorikeet-heimdal:
[samba.git] / source4 / smb_server / smb / sesssetup.c
1
2 /* 
3    Unix SMB/CIFS implementation.
4    handle SMBsessionsetup
5    Copyright (C) Andrew Tridgell                      1998-2001
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
7    Copyright (C) Jim McDonough                        2002
8    Copyright (C) Luke Howard                          2003
9    Copyright (C) Stefan Metzmacher                    2005
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "includes.h"
27 #include "version.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/auth.h"
31 #include "smb_server/smb_server.h"
32 #include "smbd/service_stream.h"
33 #include "librpc/gen_ndr/nbt.h"
34
35 /*
36   setup the OS, Lanman and domain portions of a session setup reply
37 */
38 static void sesssetup_common_strings(struct smbsrv_request *req,
39                                      char **os, char **lanman, char **domain)
40 {
41         (*os) = talloc_asprintf(req, "Unix");
42         (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
43         (*domain) = talloc_asprintf(req, "%s", lp_workgroup());
44 }
45
46 static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req,
47                                           union smb_sesssetup *sess,
48                                           NTSTATUS status)
49 {
50         if (NT_STATUS_IS_OK(status)) {
51                 req->smb_conn->negotiate.done_sesssetup = True;
52         }
53         smbsrv_reply_sesssetup_send(req, sess, status);
54 }
55
56 static void sesssetup_old_send(struct auth_check_password_request *areq,
57                                void *private_data)
58 {
59         struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request);
60         union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
61         struct auth_serversupplied_info *server_info = NULL;
62         struct auth_session_info *session_info;
63         struct smbsrv_session *smb_sess;
64         NTSTATUS status;
65
66         status = auth_check_password_recv(areq, req, &server_info);
67         if (!NT_STATUS_IS_OK(status)) goto failed;
68
69         /* This references server_info into session_info */
70         status = auth_generate_session_info(req, server_info, &session_info);
71         if (!NT_STATUS_IS_OK(status)) goto failed;
72
73         /* allocate a new session */
74         smb_sess = smbsrv_session_new(req->smb_conn, NULL);
75         if (!smb_sess) {
76                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
77                 goto failed;
78         }
79
80         /* Ensure this is marked as a 'real' vuid, not one
81          * simply valid for the session setup leg */
82         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
83         if (!NT_STATUS_IS_OK(status)) goto failed;
84
85         /* To correctly process any AndX packet (like a tree connect)
86          * we need to fill in the session on the request here */
87         req->session = smb_sess;
88         sess->old.out.vuid = smb_sess->vuid;
89
90 failed:
91         status = auth_nt_status_squash(status);
92         smbsrv_sesssetup_backend_send(req, sess, status);
93 }
94
95 /*
96   handler for old style session setup
97 */
98 static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
99 {
100         struct auth_usersupplied_info *user_info = NULL;
101         struct socket_address *remote_address;
102         const char *remote_machine = NULL;
103
104         sess->old.out.vuid = 0;
105         sess->old.out.action = 0;
106
107         sesssetup_common_strings(req, 
108                                  &sess->old.out.os,
109                                  &sess->old.out.lanman,
110                                  &sess->old.out.domain);
111
112         if (!req->smb_conn->negotiate.done_sesssetup) {
113                 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
114         }
115
116         if (req->smb_conn->negotiate.calling_name) {
117                 remote_machine = req->smb_conn->negotiate.calling_name->name;
118         }
119         
120         remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req);
121         if (!remote_address) goto nomem;
122
123         if (!remote_machine) {
124                 remote_machine = remote_address->addr;
125         }
126
127         user_info = talloc(req, struct auth_usersupplied_info);
128         if (!user_info) goto nomem;
129         
130         user_info->mapped_state = False;
131         user_info->logon_parameters = 0;
132         user_info->flags = 0;
133         user_info->client.account_name = sess->old.in.user;
134         user_info->client.domain_name = sess->old.in.domain;
135         user_info->workstation_name = remote_machine;
136         user_info->remote_host = talloc_steal(user_info, remote_address);
137         
138         user_info->password_state = AUTH_PASSWORD_RESPONSE;
139         user_info->password.response.lanman = sess->old.in.password;
140         user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data);
141         user_info->password.response.nt = data_blob(NULL, 0);
142
143         auth_check_password_send(req->smb_conn->negotiate.auth_context, user_info,
144                                  sesssetup_old_send, req);
145         return;
146
147 nomem:
148         smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY);
149 }
150
151 static void sesssetup_nt1_send(struct auth_check_password_request *areq,
152                                void *private_data)
153 {
154         struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request);
155         union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
156         struct auth_serversupplied_info *server_info = NULL;
157         struct auth_session_info *session_info;
158         struct smbsrv_session *smb_sess;
159         NTSTATUS status;
160
161         status = auth_check_password_recv(areq, req, &server_info);
162         if (!NT_STATUS_IS_OK(status)) goto failed;
163
164         /* This references server_info into session_info */
165         status = auth_generate_session_info(req, server_info, &session_info);
166         if (!NT_STATUS_IS_OK(status)) goto failed;
167
168         /* allocate a new session */
169         smb_sess = smbsrv_session_new(req->smb_conn, NULL);
170         if (!smb_sess) {
171                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
172                 goto failed;
173         }
174
175         /* Ensure this is marked as a 'real' vuid, not one
176          * simply valid for the session setup leg */
177         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
178         if (!NT_STATUS_IS_OK(status)) goto failed;
179
180         /* To correctly process any AndX packet (like a tree connect)
181          * we need to fill in the session on the request here */
182         req->session = smb_sess;
183         sess->nt1.out.vuid = smb_sess->vuid;
184
185         if (!session_info->server_info->authenticated) {
186                 /* don't try signing as anonymous */
187                 goto done;
188         }
189
190         if (!smbsrv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
191                 /* Already signing, or disabled */
192                 goto done;
193         }
194
195         /* Force check of the request packet, now we know the session key */
196         smbsrv_signing_check_incoming(req);
197 /* TODO: why don't we check the result here? */
198
199         /* Unfortunetly win2k3 as a client doesn't sign the request
200          * packet here, so we have to force signing to start again */
201
202         smbsrv_signing_restart(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2);
203
204 done:
205         status = NT_STATUS_OK;
206 failed:
207         status = auth_nt_status_squash(status);
208         smbsrv_sesssetup_backend_send(req, sess, status);
209 }
210
211 /*
212   handler for NT1 style session setup
213 */
214 static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
215 {
216         NTSTATUS status;
217         struct auth_context *auth_context;
218         struct auth_usersupplied_info *user_info = NULL;
219         struct socket_address *remote_address;
220         const char *remote_machine = NULL;
221         
222         sess->nt1.out.vuid = 0;
223         sess->nt1.out.action = 0;
224
225         sesssetup_common_strings(req, 
226                                  &sess->nt1.out.os,
227                                  &sess->nt1.out.lanman,
228                                  &sess->nt1.out.domain);
229
230         if (!req->smb_conn->negotiate.done_sesssetup) {
231                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
232                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
233         }
234
235         if (req->smb_conn->negotiate.oid) {
236                 if (sess->nt1.in.user && *sess->nt1.in.user) {
237                         /* We can't accept a normal login, because we
238                          * don't have a challenge */
239                         status = NT_STATUS_LOGON_FAILURE;
240                         goto failed;
241                 }
242
243                 /* TODO: should we use just "anonymous" here? */
244                 status = auth_context_create(req, lp_auth_methods(), 
245                                              req->smb_conn->connection->event.ctx,
246                                              req->smb_conn->connection->msg_ctx,
247                                              &auth_context);
248                 if (!NT_STATUS_IS_OK(status)) goto failed;
249         } else {
250                 auth_context = req->smb_conn->negotiate.auth_context;
251         }
252
253         if (req->smb_conn->negotiate.calling_name) {
254                 remote_machine = req->smb_conn->negotiate.calling_name->name;
255         }
256
257         remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req);
258         if (!remote_address) goto nomem;
259
260         if (!remote_machine) {
261                 remote_machine = remote_address->addr;
262         }
263
264         user_info = talloc(req, struct auth_usersupplied_info);
265         if (!user_info) goto nomem;
266
267         user_info->mapped_state = False;
268         user_info->logon_parameters = 0;
269         user_info->flags = 0;
270         user_info->client.account_name = sess->nt1.in.user;
271         user_info->client.domain_name = sess->nt1.in.domain;
272         user_info->workstation_name = remote_machine;
273         user_info->remote_host = talloc_steal(user_info, remote_address);
274         
275         user_info->password_state = AUTH_PASSWORD_RESPONSE;
276         user_info->password.response.lanman = sess->nt1.in.password1;
277         user_info->password.response.lanman.data = talloc_steal(user_info, sess->nt1.in.password1.data);
278         user_info->password.response.nt = sess->nt1.in.password2;
279         user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data);
280
281         auth_check_password_send(auth_context, user_info,
282                                  sesssetup_nt1_send, req);
283         return;
284
285 nomem:
286         status = NT_STATUS_NO_MEMORY;
287 failed:
288         status = auth_nt_status_squash(status);
289         smbsrv_sesssetup_backend_send(req, sess, status);
290 }
291
292 struct sesssetup_spnego_state {
293         struct smbsrv_request *req;
294         union smb_sesssetup *sess;
295         struct smbsrv_session *smb_sess;
296 };
297
298 static void sesssetup_spnego_send(struct gensec_update_request *greq, void *private_data)
299 {
300         struct sesssetup_spnego_state *s = talloc_get_type(private_data,
301                                            struct sesssetup_spnego_state);
302         struct smbsrv_request *req = s->req;
303         union smb_sesssetup *sess = s->sess;
304         struct smbsrv_session *smb_sess = s->smb_sess;
305         struct auth_session_info *session_info = NULL;
306         NTSTATUS status;
307         NTSTATUS skey_status;
308         DATA_BLOB session_key;
309
310         status = gensec_update_recv(greq, req, &sess->spnego.out.secblob);
311         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
312                 goto done;
313         } else if (!NT_STATUS_IS_OK(status)) {
314                 goto failed;
315         }
316
317         status = gensec_session_info(smb_sess->gensec_ctx, &session_info);
318         if (!NT_STATUS_IS_OK(status)) goto failed;
319
320         skey_status = gensec_session_key(smb_sess->gensec_ctx, &session_key);
321         if (NT_STATUS_IS_OK(skey_status) &&
322             session_info->server_info->authenticated &&
323             smbsrv_setup_signing(req->smb_conn, &session_key, NULL)) {
324                 /* Force check of the request packet, now we know the session key */
325                 smbsrv_signing_check_incoming(req);
326
327                 smbsrv_signing_restart(req->smb_conn, &session_key, NULL);
328         }
329
330         /* Ensure this is marked as a 'real' vuid, not one
331          * simply valid for the session setup leg */
332         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
333         if (!NT_STATUS_IS_OK(status)) goto failed;
334
335         req->session = smb_sess;
336
337 done:
338         sess->spnego.out.vuid = smb_sess->vuid;
339 failed:
340         status = auth_nt_status_squash(status);
341         smbsrv_sesssetup_backend_send(req, sess, status);
342 }
343
344 /*
345   handler for SPNEGO style session setup
346 */
347 static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
348 {
349         NTSTATUS status;
350         struct smbsrv_session *smb_sess = NULL;
351         struct sesssetup_spnego_state *s = NULL;
352         uint16_t vuid;
353
354         sess->spnego.out.vuid = 0;
355         sess->spnego.out.action = 0;
356
357         sesssetup_common_strings(req, 
358                                  &sess->spnego.out.os,
359                                  &sess->spnego.out.lanman,
360                                  &sess->spnego.out.workgroup);
361
362         if (!req->smb_conn->negotiate.done_sesssetup) {
363                 req->smb_conn->negotiate.max_send = sess->spnego.in.bufsize;
364                 req->smb_conn->negotiate.client_caps = sess->spnego.in.capabilities;
365         }
366
367         vuid = SVAL(req->in.hdr,HDR_UID);
368
369         /* lookup an existing session */
370         smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
371         if (!smb_sess) {
372                 struct gensec_security *gensec_ctx;
373
374                 status = gensec_server_start(req,
375                                              req->smb_conn->connection->event.ctx,
376                                              req->smb_conn->connection->msg_ctx,
377                                              &gensec_ctx);
378                 if (!NT_STATUS_IS_OK(status)) {
379                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
380                         goto failed;
381                 }
382
383                 gensec_set_credentials(gensec_ctx, req->smb_conn->negotiate.server_credentials);
384
385                 gensec_set_target_service(gensec_ctx, "cifs");
386
387                 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
388
389                 status = gensec_start_mech_by_oid(gensec_ctx, req->smb_conn->negotiate.oid);
390                 if (!NT_STATUS_IS_OK(status)) {
391                         DEBUG(1, ("Failed to start GENSEC %s server code: %s\n", 
392                                   gensec_get_name_by_oid(req->smb_conn->negotiate.oid), nt_errstr(status)));
393                         goto failed;
394                 }
395
396                 /* allocate a new session */
397                 smb_sess = smbsrv_session_new(req->smb_conn, gensec_ctx);
398                 if (!smb_sess) {
399                         status = NT_STATUS_INSUFFICIENT_RESOURCES;
400                         goto failed;
401                 }
402         }
403
404         if (!smb_sess) {
405                 status = NT_STATUS_ACCESS_DENIED;
406                 goto failed;
407         }
408
409         if (!smb_sess->gensec_ctx) {
410                 status = NT_STATUS_INTERNAL_ERROR;
411                 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
412                 goto failed;
413         }
414
415         s = talloc(req, struct sesssetup_spnego_state);
416         if (!s) goto nomem;
417         s->req          = req;
418         s->sess         = sess;
419         s->smb_sess     = smb_sess;
420
421         gensec_update_send(smb_sess->gensec_ctx, sess->spnego.in.secblob,
422                            sesssetup_spnego_send, s);
423         return;
424
425 nomem:
426         status = NT_STATUS_NO_MEMORY;
427 failed:
428         talloc_free(smb_sess);
429         status = auth_nt_status_squash(status);
430         smbsrv_sesssetup_backend_send(req, sess, status);
431 }
432
433 /*
434   backend for sessionsetup call - this takes all 3 variants of the call
435 */
436 void smbsrv_sesssetup_backend(struct smbsrv_request *req,
437                               union smb_sesssetup *sess)
438 {
439         switch (sess->old.level) {
440                 case RAW_SESSSETUP_OLD:
441                         sesssetup_old(req, sess);
442                         return;
443
444                 case RAW_SESSSETUP_NT1:
445                         sesssetup_nt1(req, sess);
446                         return;
447
448                 case RAW_SESSSETUP_SPNEGO:
449                         sesssetup_spnego(req, sess);
450                         return;
451
452                 case RAW_SESSSETUP_SMB2:
453                         break;
454         }
455
456         smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_INVALID_LEVEL);
457 }