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