4ebc0c477181fdda472d877b296b1d8381a7024d
[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 3 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, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include <tevent.h>
27 #include "version.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth/auth.h"
30 #include "smb_server/smb_server.h"
31 #include "smbd/service_stream.h"
32 #include "param/param.h"
33 #include "../lib/tsocket/tsocket.h"
34 #include "lib/stream/packet.h"
35
36 struct sesssetup_context {
37         struct auth4_context *auth_context;
38         struct smbsrv_request *req;
39 };
40
41 /*
42   setup the OS, Lanman and domain portions of a session setup reply
43 */
44 static void sesssetup_common_strings(struct smbsrv_request *req,
45                                      char **os, char **lanman, char **domain)
46 {
47         (*os) = talloc_asprintf(req, "Unix");
48         (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
49         (*domain) = talloc_asprintf(req, "%s", 
50                                     lpcfg_workgroup(req->smb_conn->lp_ctx));
51 }
52
53 static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req,
54                                           union smb_sesssetup *sess,
55                                           NTSTATUS status)
56 {
57         if (NT_STATUS_IS_OK(status)) {
58                 req->smb_conn->negotiate.done_sesssetup = true;
59                 /* we need to keep the session long term */
60                 req->session = talloc_steal(req->smb_conn, req->session);
61         }
62         smbsrv_reply_sesssetup_send(req, sess, status);
63 }
64
65 static void sesssetup_old_send(struct tevent_req *subreq)
66 {
67         struct sesssetup_context *state = tevent_req_callback_data(subreq, struct sesssetup_context);
68         struct smbsrv_request *req = state->req;
69
70         union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
71         struct auth_user_info_dc *user_info_dc = NULL;
72         struct auth_session_info *session_info;
73         struct smbsrv_session *smb_sess;
74         NTSTATUS status;
75         uint32_t flags;
76
77         status = auth_check_password_recv(subreq, req, &user_info_dc);
78         TALLOC_FREE(subreq);
79         if (!NT_STATUS_IS_OK(status)) goto failed;
80
81         flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
82         if (user_info_dc->info->authenticated) {
83                 flags |= AUTH_SESSION_INFO_AUTHENTICATED;
84         }
85         /* This references user_info_dc into session_info */
86         status = req->smb_conn->negotiate.auth_context->generate_session_info(req->smb_conn->negotiate.auth_context,
87                                                                               req,
88                                                                               user_info_dc, sess->old.in.user, 
89                                                                               flags, &session_info);
90         if (!NT_STATUS_IS_OK(status)) goto failed;
91
92         /* allocate a new session */
93         smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
94         if (!smb_sess) {
95                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
96                 goto failed;
97         }
98
99         /* Ensure this is marked as a 'real' vuid, not one
100          * simply valid for the session setup leg */
101         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
102         if (!NT_STATUS_IS_OK(status)) goto failed;
103
104         /* To correctly process any AndX packet (like a tree connect)
105          * we need to fill in the session on the request here */
106         req->session = smb_sess;
107         sess->old.out.vuid = smb_sess->vuid;
108
109 failed:
110         status = nt_status_squash(status);
111         smbsrv_sesssetup_backend_send(req, sess, status);
112 }
113
114 /*
115   handler for old style session setup
116 */
117 static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
118 {
119         struct auth_usersupplied_info *user_info = NULL;
120         struct tsocket_address *remote_address;
121         const char *remote_machine = NULL;
122         struct tevent_req *subreq;
123         struct sesssetup_context *state;
124
125         sess->old.out.vuid = 0;
126         sess->old.out.action = 0;
127
128         sesssetup_common_strings(req, 
129                                  &sess->old.out.os,
130                                  &sess->old.out.lanman,
131                                  &sess->old.out.domain);
132
133         if (!req->smb_conn->negotiate.done_sesssetup) {
134                 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
135         }
136
137         if (req->smb_conn->negotiate.calling_name) {
138                 remote_machine = req->smb_conn->negotiate.calling_name->name;
139         }
140         
141         remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
142         if (!remote_address) goto nomem;
143
144         if (!remote_machine) {
145                 remote_machine = tsocket_address_inet_addr_string(remote_address, req);
146                 if (!remote_machine) goto nomem;
147         }
148
149         user_info = talloc_zero(req, struct auth_usersupplied_info);
150         if (!user_info) goto nomem;
151         
152         user_info->mapped_state = false;
153         user_info->logon_parameters = 0;
154         user_info->flags = 0;
155         user_info->client.account_name = sess->old.in.user;
156         user_info->client.domain_name = sess->old.in.domain;
157         user_info->workstation_name = remote_machine;
158         user_info->remote_host = talloc_steal(user_info, remote_address);
159         
160         user_info->password_state = AUTH_PASSWORD_RESPONSE;
161         user_info->password.response.lanman = sess->old.in.password;
162         user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data);
163         user_info->password.response.nt = data_blob(NULL, 0);
164
165         state = talloc(req, struct sesssetup_context);
166         if (!state) goto nomem;
167
168         if (req->smb_conn->negotiate.auth_context) {
169                 state->auth_context = req->smb_conn->negotiate.auth_context;
170         } else {
171                 /* TODO: should we use just "anonymous" here? */
172                 NTSTATUS status = auth_context_create(state,
173                                                       req->smb_conn->connection->event.ctx,
174                                                       req->smb_conn->connection->msg_ctx,
175                                                       req->smb_conn->lp_ctx,
176                                                       &state->auth_context);
177                 if (!NT_STATUS_IS_OK(status)) {
178                         smbsrv_sesssetup_backend_send(req, sess, status);
179                         return;
180                 }
181         }
182
183         state->req = req;
184
185         subreq = auth_check_password_send(state,
186                                           req->smb_conn->connection->event.ctx,
187                                           req->smb_conn->negotiate.auth_context,
188                                           user_info);
189         if (!subreq) goto nomem;
190         tevent_req_set_callback(subreq, sesssetup_old_send, state);
191         return;
192
193 nomem:
194         smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY);
195 }
196
197 static void sesssetup_nt1_send(struct tevent_req *subreq)
198 {
199         struct sesssetup_context *state = tevent_req_callback_data(subreq, struct sesssetup_context);
200         struct smbsrv_request *req = state->req;
201         union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
202         struct auth_user_info_dc *user_info_dc = NULL;
203         struct auth_session_info *session_info;
204         struct smbsrv_session *smb_sess;
205
206         uint32_t flags;
207         NTSTATUS status;
208
209         status = auth_check_password_recv(subreq, req, &user_info_dc);
210         TALLOC_FREE(subreq);
211         if (!NT_STATUS_IS_OK(status)) goto failed;
212
213         flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
214         if (user_info_dc->info->authenticated) {
215                 flags |= AUTH_SESSION_INFO_AUTHENTICATED;
216         }
217         /* This references user_info_dc into session_info */
218         status = state->auth_context->generate_session_info(state->auth_context,
219                                                             req,
220                                                             user_info_dc,
221                                                             sess->nt1.in.user,
222                                                             flags,
223                                                             &session_info);
224         if (!NT_STATUS_IS_OK(status)) goto failed;
225
226         /* allocate a new session */
227         smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
228         if (!smb_sess) {
229                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
230                 goto failed;
231         }
232
233         /* Ensure this is marked as a 'real' vuid, not one
234          * simply valid for the session setup leg */
235         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
236         if (!NT_STATUS_IS_OK(status)) goto failed;
237
238         /* To correctly process any AndX packet (like a tree connect)
239          * we need to fill in the session on the request here */
240         req->session = smb_sess;
241         sess->nt1.out.vuid = smb_sess->vuid;
242
243         if (!smbsrv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
244                 /* Already signing, or disabled */
245                 goto done;
246         }
247
248 done:
249         status = NT_STATUS_OK;
250 failed:
251         status = nt_status_squash(status);
252         smbsrv_sesssetup_backend_send(req, sess, status);
253 }
254
255 /*
256   handler for NT1 style session setup
257 */
258 static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
259 {
260         NTSTATUS status;
261         struct auth_usersupplied_info *user_info = NULL;
262         struct tsocket_address *remote_address;
263         const char *remote_machine = NULL;
264         struct tevent_req *subreq;
265         struct sesssetup_context *state;
266
267         sess->nt1.out.vuid = 0;
268         sess->nt1.out.action = 0;
269
270         sesssetup_common_strings(req, 
271                                  &sess->nt1.out.os,
272                                  &sess->nt1.out.lanman,
273                                  &sess->nt1.out.domain);
274
275         if (!req->smb_conn->negotiate.done_sesssetup) {
276                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
277                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
278         }
279
280         state = talloc(req, struct sesssetup_context);
281         if (!state) goto nomem;
282
283         state->req = req;
284
285         if (req->smb_conn->negotiate.oid) {
286                 if (sess->nt1.in.user && *sess->nt1.in.user) {
287                         /* We can't accept a normal login, because we
288                          * don't have a challenge */
289                         status = NT_STATUS_LOGON_FAILURE;
290                         goto failed;
291                 }
292
293                 /* TODO: should we use just "anonymous" here? */
294                 status = auth_context_create(state,
295                                              req->smb_conn->connection->event.ctx,
296                                              req->smb_conn->connection->msg_ctx,
297                                              req->smb_conn->lp_ctx,
298                                              &state->auth_context);
299                 if (!NT_STATUS_IS_OK(status)) goto failed;
300         } else if (req->smb_conn->negotiate.auth_context) {
301                 state->auth_context = req->smb_conn->negotiate.auth_context;
302         } else {
303                 /* TODO: should we use just "anonymous" here? */
304                 status = auth_context_create(state,
305                                              req->smb_conn->connection->event.ctx,
306                                              req->smb_conn->connection->msg_ctx,
307                                              req->smb_conn->lp_ctx,
308                                              &state->auth_context);
309                 if (!NT_STATUS_IS_OK(status)) goto failed;
310         }
311
312         if (req->smb_conn->negotiate.calling_name) {
313                 remote_machine = req->smb_conn->negotiate.calling_name->name;
314         }
315
316         remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
317         if (!remote_address) goto nomem;
318
319         if (!remote_machine) {
320                 remote_machine = tsocket_address_inet_addr_string(remote_address, req);
321                 if (!remote_machine) goto nomem;
322         }
323
324         user_info = talloc_zero(req, struct auth_usersupplied_info);
325         if (!user_info) goto nomem;
326
327         user_info->mapped_state = false;
328         user_info->logon_parameters = 0;
329         user_info->flags = 0;
330         user_info->client.account_name = sess->nt1.in.user;
331         user_info->client.domain_name = sess->nt1.in.domain;
332         user_info->workstation_name = remote_machine;
333         user_info->remote_host = talloc_steal(user_info, remote_address);
334         
335         user_info->password_state = AUTH_PASSWORD_RESPONSE;
336         user_info->password.response.lanman = sess->nt1.in.password1;
337         user_info->password.response.lanman.data = talloc_steal(user_info, sess->nt1.in.password1.data);
338         user_info->password.response.nt = sess->nt1.in.password2;
339         user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data);
340
341         subreq = auth_check_password_send(state,
342                                           req->smb_conn->connection->event.ctx,
343                                           state->auth_context,
344                                           user_info);
345         if (!subreq) goto nomem;
346         tevent_req_set_callback(subreq, sesssetup_nt1_send, state);
347
348         return;
349
350 nomem:
351         status = NT_STATUS_NO_MEMORY;
352 failed:
353         status = nt_status_squash(status);
354         smbsrv_sesssetup_backend_send(req, sess, status);
355 }
356
357 struct sesssetup_spnego_state {
358         struct smbsrv_request *req;
359         union smb_sesssetup *sess;
360         struct smbsrv_session *smb_sess;
361 };
362
363 static void sesssetup_spnego_send(struct tevent_req *subreq)
364 {
365         struct sesssetup_spnego_state *s = tevent_req_callback_data(subreq,
366                                            struct sesssetup_spnego_state);
367         struct smbsrv_request *req = s->req;
368         union smb_sesssetup *sess = s->sess;
369         struct smbsrv_session *smb_sess = s->smb_sess;
370         struct auth_session_info *session_info = NULL;
371         NTSTATUS status;
372         NTSTATUS skey_status;
373         DATA_BLOB session_key;
374
375         status = gensec_update_recv(subreq, req, &sess->spnego.out.secblob);
376         packet_recv_enable(req->smb_conn->packet);
377         TALLOC_FREE(subreq);
378         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
379                 goto done;
380         } else if (!NT_STATUS_IS_OK(status)) {
381                 goto failed;
382         }
383
384         status = gensec_session_info(smb_sess->gensec_ctx, smb_sess, &session_info);
385         if (!NT_STATUS_IS_OK(status)) goto failed;
386
387         /* The session_key is only needed until the end of the smbsrv_setup_signing() call */
388         skey_status = gensec_session_key(smb_sess->gensec_ctx, req, &session_key);
389         if (NT_STATUS_IS_OK(skey_status)) {
390                 smbsrv_setup_signing(req->smb_conn, &session_key, NULL);
391         }
392
393         /* Ensure this is marked as a 'real' vuid, not one
394          * simply valid for the session setup leg */
395         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
396         if (!NT_STATUS_IS_OK(status)) goto failed;
397
398         req->session = smb_sess;
399
400 done:
401         sess->spnego.out.vuid = smb_sess->vuid;
402 failed:
403         status = nt_status_squash(status);
404         smbsrv_sesssetup_backend_send(req, sess, status);
405         if (!NT_STATUS_IS_OK(status) && 
406             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
407                 talloc_free(smb_sess);
408         }
409 }
410
411 /*
412   handler for SPNEGO style session setup
413 */
414 static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
415 {
416         NTSTATUS status;
417         struct smbsrv_session *smb_sess = NULL;
418         bool is_smb_sess_new = false;
419         struct sesssetup_spnego_state *s = NULL;
420         uint16_t vuid;
421         struct tevent_req *subreq;
422
423         sess->spnego.out.vuid = 0;
424         sess->spnego.out.action = 0;
425
426         sesssetup_common_strings(req, 
427                                  &sess->spnego.out.os,
428                                  &sess->spnego.out.lanman,
429                                  &sess->spnego.out.workgroup);
430
431         if (!req->smb_conn->negotiate.done_sesssetup) {
432                 req->smb_conn->negotiate.max_send = sess->spnego.in.bufsize;
433                 req->smb_conn->negotiate.client_caps = sess->spnego.in.capabilities;
434         }
435
436         vuid = SVAL(req->in.hdr,HDR_UID);
437
438         /* lookup an existing session */
439         if (vuid == 0) {
440                 struct gensec_security *gensec_ctx;
441
442                 status = samba_server_gensec_start(req,
443                                                    req->smb_conn->connection->event.ctx,
444                                                    req->smb_conn->connection->msg_ctx,
445                                                    req->smb_conn->lp_ctx,
446                                                    req->smb_conn->negotiate.server_credentials,
447                                                    "cifs",
448                                                    &gensec_ctx);
449                 if (!NT_STATUS_IS_OK(status)) {
450                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
451                         goto failed;
452                 }
453
454                 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
455
456                 status = gensec_start_mech_by_oid(gensec_ctx, req->smb_conn->negotiate.oid);
457                 if (!NT_STATUS_IS_OK(status)) {
458                         DEBUG(1, ("Failed to start GENSEC %s server code: %s\n", 
459                                   gensec_get_name_by_oid(gensec_ctx, req->smb_conn->negotiate.oid), nt_errstr(status)));
460                         goto failed;
461                 }
462
463                 /* allocate a new session */
464                 smb_sess = smbsrv_session_new(req->smb_conn, req->smb_conn, gensec_ctx);
465                 if (!smb_sess) {
466                         status = NT_STATUS_INSUFFICIENT_RESOURCES;
467                         goto failed;
468                 }
469                 is_smb_sess_new = true;
470         } else {
471                 smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
472         }
473
474         if (!smb_sess) {
475                 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
476                 goto failed;
477         }
478
479         if (smb_sess->session_info) {
480                 status = NT_STATUS_INVALID_PARAMETER;
481                 goto failed;
482         }
483
484         if (!smb_sess->gensec_ctx) {
485                 status = NT_STATUS_INTERNAL_ERROR;
486                 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
487                 goto failed;
488         }
489
490         s = talloc(req, struct sesssetup_spnego_state);
491         if (!s) goto nomem;
492         s->req          = req;
493         s->sess         = sess;
494         s->smb_sess     = smb_sess;
495
496         subreq = gensec_update_send(s,
497                                     req->smb_conn->connection->event.ctx,
498                                     smb_sess->gensec_ctx,
499                                     sess->spnego.in.secblob);
500         if (!subreq) {
501                 goto nomem;
502         }
503         /* disable receipt of more packets on this socket until we've
504            finished with the session setup. This avoids a problem with
505            crashes if we get EOF on the socket while processing a session
506            setup */
507         packet_recv_disable(req->smb_conn->packet);
508         tevent_req_set_callback(subreq, sesssetup_spnego_send, s);
509
510         return;
511
512 nomem:
513         status = NT_STATUS_NO_MEMORY;
514 failed:
515         if (is_smb_sess_new) {
516                 talloc_free(smb_sess);
517         }
518         status = nt_status_squash(status);
519         smbsrv_sesssetup_backend_send(req, sess, status);
520 }
521
522 /*
523   backend for sessionsetup call - this takes all 3 variants of the call
524 */
525 void smbsrv_sesssetup_backend(struct smbsrv_request *req,
526                               union smb_sesssetup *sess)
527 {
528         switch (sess->old.level) {
529                 case RAW_SESSSETUP_OLD:
530                         sesssetup_old(req, sess);
531                         return;
532
533                 case RAW_SESSSETUP_NT1:
534                         sesssetup_nt1(req, sess);
535                         return;
536
537                 case RAW_SESSSETUP_SPNEGO:
538                         sesssetup_spnego(req, sess);
539                         return;
540
541                 case RAW_SESSSETUP_SMB2:
542                         break;
543         }
544
545         smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_INVALID_LEVEL);
546 }