Fix bug #7608 - Win7 SMB2 authentication causes smbd panic
[metze/samba/wip.git] / source3 / smbd / smb2_sesssetup.c
1 /*
2    Unix SMB/CIFS implementation.
3    Core SMB2 server
4
5    Copyright (C) Stefan Metzmacher 2009
6    Copyright (C) Jeremy Allison 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../libcli/auth/spnego.h"
26 #include "../libcli/auth/ntlmssp.h"
27 #include "ntlmssp_wrap.h"
28 #include "../librpc/gen_ndr/krb5pac.h"
29 #include "libads/kerberos_proto.h"
30
31 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
32                                         uint64_t in_session_id,
33                                         uint8_t in_security_mode,
34                                         DATA_BLOB in_security_buffer,
35                                         uint16_t *out_session_flags,
36                                         DATA_BLOB *out_security_buffer,
37                                         uint64_t *out_session_id);
38
39 NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *smb2req)
40 {
41         const uint8_t *inhdr;
42         const uint8_t *inbody;
43         int i = smb2req->current_idx;
44         uint8_t *outhdr;
45         DATA_BLOB outbody;
46         DATA_BLOB outdyn;
47         size_t expected_body_size = 0x19;
48         size_t body_size;
49         uint64_t in_session_id;
50         uint8_t in_security_mode;
51         uint16_t in_security_offset;
52         uint16_t in_security_length;
53         DATA_BLOB in_security_buffer;
54         uint16_t out_session_flags;
55         uint64_t out_session_id;
56         uint16_t out_security_offset;
57         DATA_BLOB out_security_buffer;
58         NTSTATUS status;
59
60         inhdr = (const uint8_t *)smb2req->in.vector[i+0].iov_base;
61
62         if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
63                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
64         }
65
66         inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base;
67
68         body_size = SVAL(inbody, 0x00);
69         if (body_size != expected_body_size) {
70                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
71         }
72
73         in_security_offset = SVAL(inbody, 0x0C);
74         in_security_length = SVAL(inbody, 0x0E);
75
76         if (in_security_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
77                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
78         }
79
80         if (in_security_length > smb2req->in.vector[i+2].iov_len) {
81                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
82         }
83
84         in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
85         in_security_mode = CVAL(inbody, 0x03);
86         in_security_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base;
87         in_security_buffer.length = in_security_length;
88
89         status = smbd_smb2_session_setup(smb2req,
90                                          in_session_id,
91                                          in_security_mode,
92                                          in_security_buffer,
93                                          &out_session_flags,
94                                          &out_security_buffer,
95                                          &out_session_id);
96         if (!NT_STATUS_IS_OK(status) &&
97             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
98                 status = nt_status_squash(status);
99                 return smbd_smb2_request_error(smb2req, status);
100         }
101
102         out_security_offset = SMB2_HDR_BODY + 0x08;
103
104         outhdr = (uint8_t *)smb2req->out.vector[i].iov_base;
105
106         outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x08);
107         if (outbody.data == NULL) {
108                 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
109         }
110
111         SBVAL(outhdr, SMB2_HDR_SESSION_ID, out_session_id);
112
113         SSVAL(outbody.data, 0x00, 0x08 + 1);    /* struct size */
114         SSVAL(outbody.data, 0x02,
115               out_session_flags);               /* session flags */
116         SSVAL(outbody.data, 0x04,
117               out_security_offset);             /* security buffer offset */
118         SSVAL(outbody.data, 0x06,
119               out_security_buffer.length);      /* security buffer length */
120
121         outdyn = out_security_buffer;
122
123         return smbd_smb2_request_done_ex(smb2req, status, outbody, &outdyn,
124                                          __location__);
125 }
126
127 static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
128 {
129         if (session->sconn == NULL) {
130                 return 0;
131         }
132
133         /* first free all tcons */
134         while (session->tcons.list) {
135                 talloc_free(session->tcons.list);
136         }
137
138         idr_remove(session->sconn->smb2.sessions.idtree, session->vuid);
139         DLIST_REMOVE(session->sconn->smb2.sessions.list, session);
140         invalidate_vuid(session->sconn, session->vuid);
141
142         session->vuid = 0;
143         session->status = NT_STATUS_USER_SESSION_DELETED;
144         session->sconn = NULL;
145
146         return 0;
147 }
148
149 static NTSTATUS setup_ntlmssp_server_info(struct smbd_smb2_session *session,
150                                 NTSTATUS status)
151 {
152         if (NT_STATUS_IS_OK(status)) {
153                 status = auth_ntlmssp_steal_server_info(session,
154                                 session->auth_ntlmssp_state,
155                                 &session->server_info);
156         } else {
157                 /* Note that this server_info won't have a session
158                  * key.  But for map to guest, that's exactly the right
159                  * thing - we can't reasonably guess the key the
160                  * client wants, as the password was wrong */
161                 status = do_map_to_guest(status,
162                         &session->server_info,
163                         auth_ntlmssp_get_username(session->auth_ntlmssp_state),
164                         auth_ntlmssp_get_domain(session->auth_ntlmssp_state));
165         }
166         return status;
167 }
168
169 #ifdef HAVE_KRB5
170 static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
171                                         struct smbd_smb2_request *smb2req,
172                                         uint8_t in_security_mode,
173                                         const DATA_BLOB *secblob,
174                                         const char *mechOID,
175                                         uint16_t *out_session_flags,
176                                         DATA_BLOB *out_security_buffer,
177                                         uint64_t *out_session_id)
178 {
179         DATA_BLOB ap_rep = data_blob_null;
180         DATA_BLOB ap_rep_wrapped = data_blob_null;
181         DATA_BLOB ticket = data_blob_null;
182         DATA_BLOB session_key = data_blob_null;
183         DATA_BLOB secblob_out = data_blob_null;
184         uint8 tok_id[2];
185         struct PAC_LOGON_INFO *logon_info = NULL;
186         char *client = NULL;
187         char *p = NULL;
188         char *domain = NULL;
189         struct passwd *pw = NULL;
190         NTSTATUS status;
191         fstring user;
192         fstring real_username;
193         fstring tmp;
194         bool username_was_mapped = false;
195         bool map_domainuser_to_guest = false;
196
197         if (!spnego_parse_krb5_wrap(talloc_tos(), *secblob, &ticket, tok_id)) {
198                 status = NT_STATUS_LOGON_FAILURE;
199                 goto fail;
200         }
201
202         status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket,
203                                 &client, &logon_info, &ap_rep,
204                                 &session_key, true);
205
206         if (!NT_STATUS_IS_OK(status)) {
207                 DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n",
208                         nt_errstr(status)));
209                 if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
210                         status = NT_STATUS_LOGON_FAILURE;
211                 }
212                 goto fail;
213         }
214
215         DEBUG(3,("smb2: Ticket name is [%s]\n", client));
216
217         p = strchr_m(client, '@');
218         if (!p) {
219                 DEBUG(3,("smb2: %s Doesn't look like a valid principal\n",
220                         client));
221                 status = NT_STATUS_LOGON_FAILURE;
222                 goto fail;
223         }
224
225         *p = 0;
226
227         /* save the PAC data if we have it */
228
229         if (logon_info) {
230                 netsamlogon_cache_store(client, &logon_info->info3);
231         }
232
233         if (!strequal(p+1, lp_realm())) {
234                 DEBUG(3,("smb2: Ticket for foreign realm %s@%s\n", client, p+1));
235                 if (!lp_allow_trusted_domains()) {
236                         status = NT_STATUS_LOGON_FAILURE;
237                         goto fail;
238                 }
239         }
240
241         /* this gives a fully qualified user name (ie. with full realm).
242            that leads to very long usernames, but what else can we do? */
243
244         domain = p+1;
245
246         if (logon_info && logon_info->info3.base.domain.string) {
247                 domain = talloc_strdup(talloc_tos(),
248                                         logon_info->info3.base.domain.string);
249                 if (!domain) {
250                         status = NT_STATUS_NO_MEMORY;
251                         goto fail;
252                 }
253                 DEBUG(10, ("smb2: Mapped to [%s] (using PAC)\n", domain));
254         } else {
255
256                 /* If we have winbind running, we can (and must) shorten the
257                    username by using the short netbios name. Otherwise we will
258                    have inconsistent user names. With Kerberos, we get the
259                    fully qualified realm, with ntlmssp we get the short
260                    name. And even w2k3 does use ntlmssp if you for example
261                    connect to an ip address. */
262
263                 wbcErr wbc_status;
264                 struct wbcDomainInfo *info = NULL;
265
266                 DEBUG(10, ("smb2: Mapping [%s] to short name\n", domain));
267
268                 wbc_status = wbcDomainInfo(domain, &info);
269
270                 if (WBC_ERROR_IS_OK(wbc_status)) {
271                         domain = talloc_strdup(talloc_tos(), info->short_name);
272
273                         wbcFreeMemory(info);
274                         if (!domain) {
275                                 status = NT_STATUS_NO_MEMORY;
276                                 goto fail;
277                         }
278                         DEBUG(10, ("smb2: Mapped to [%s] (using Winbind)\n", domain));
279                 } else {
280                         DEBUG(3, ("smb2: Could not find short name: %s\n",
281                                 wbcErrorString(wbc_status)));
282                 }
283         }
284
285         /* We have to use fstring for this - map_username requires it. */
286         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
287
288         /* lookup the passwd struct, create a new user if necessary */
289
290         username_was_mapped = map_username(user);
291
292         pw = smb_getpwnam(talloc_tos(), user, real_username, true );
293         if (pw) {
294                 /* if a real user check pam account restrictions */
295                 /* only really perfomed if "obey pam restriction" is true */
296                 /* do this before an eventual mapping to guest occurs */
297                 status = smb_pam_accountcheck(pw->pw_name);
298                 if (!NT_STATUS_IS_OK(status)) {
299                         DEBUG(1,("smb2: PAM account restriction "
300                                 "prevents user login\n"));
301                         goto fail;
302                 }
303         }
304
305         if (!pw) {
306
307                 /* this was originally the behavior of Samba 2.2, if a user
308                    did not have a local uid but has been authenticated, then
309                    map them to a guest account */
310
311                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){
312                         map_domainuser_to_guest = true;
313                         fstrcpy(user,lp_guestaccount());
314                         pw = smb_getpwnam(talloc_tos(), user, real_username, true );
315                 }
316
317                 /* extra sanity check that the guest account is valid */
318
319                 if (!pw) {
320                         DEBUG(1,("smb2: Username %s is invalid on this system\n",
321                                 user));
322                         status = NT_STATUS_LOGON_FAILURE;
323                         goto fail;
324                 }
325         }
326
327         /* setup the string used by %U */
328
329         sub_set_smb_name(real_username);
330         reload_services(smb2req->sconn->msg_ctx, true);
331
332         if (map_domainuser_to_guest) {
333                 make_server_info_guest(session, &session->server_info);
334         } else if (logon_info) {
335                 /* pass the unmapped username here since map_username()
336                    will be called again from inside make_server_info_info3() */
337
338                 status = make_server_info_info3(session,
339                                                 client,
340                                                 domain,
341                                                 &session->server_info,
342                                                 &logon_info->info3);
343                 if (!NT_STATUS_IS_OK(status) ) {
344                         DEBUG(1,("smb2: make_server_info_info3 failed: %s!\n",
345                                 nt_errstr(status)));
346                         goto fail;
347                 }
348
349         } else {
350                 /*
351                  * We didn't get a PAC, we have to make up the user
352                  * ourselves. Try to ask the pdb backend to provide
353                  * SID consistency with ntlmssp session setup
354                  */
355                 struct samu *sampass;
356                 /* The stupid make_server_info_XX functions here
357                    don't take a talloc context. */
358                 struct auth_serversupplied_info *tmp_server_info = NULL;
359
360                 sampass = samu_new(talloc_tos());
361                 if (sampass == NULL) {
362                         status = NT_STATUS_NO_MEMORY;
363                         goto fail;
364                 }
365
366                 if (pdb_getsampwnam(sampass, real_username)) {
367                         DEBUG(10, ("smb2: found user %s in passdb, calling "
368                                 "make_server_info_sam\n", real_username));
369                         status = make_server_info_sam(&tmp_server_info, sampass);
370                         TALLOC_FREE(sampass);
371                 } else {
372                         /*
373                          * User not in passdb, make it up artificially
374                          */
375                         TALLOC_FREE(sampass);
376                         DEBUG(10, ("smb2: didn't find user %s in passdb, calling "
377                                 "make_server_info_pw\n", real_username));
378                         status = make_server_info_pw(&tmp_server_info,
379                                         real_username,
380                                         pw);
381                 }
382
383                 if (!NT_STATUS_IS_OK(status)) {
384                         DEBUG(1,("smb2: make_server_info_[sam|pw] failed: %s!\n",
385                                 nt_errstr(status)));
386                         goto fail;
387                 }
388
389                 /* Steal tmp_server_info into the session->server_info
390                    pointer. */
391                 session->server_info = talloc_move(session, &tmp_server_info);
392
393                 /* make_server_info_pw does not set the domain. Without this
394                  * we end up with the local netbios name in substitutions for
395                  * %D. */
396
397                 if (session->server_info->info3 != NULL) {
398                         session->server_info->info3->base.domain.string =
399                                 talloc_strdup(session->server_info->info3, domain);
400                 }
401
402         }
403
404         session->server_info->nss_token |= username_was_mapped;
405
406         /* we need to build the token for the user. make_server_info_guest()
407            already does this */
408
409         if (!session->server_info->ptok ) {
410                 status = create_local_token(session->server_info);
411                 if (!NT_STATUS_IS_OK(status)) {
412                         DEBUG(10,("smb2: failed to create local token: %s\n",
413                                 nt_errstr(status)));
414                         goto fail;
415                 }
416         }
417
418         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
419              lp_server_signing() == Required) {
420                 session->do_signing = true;
421         }
422
423         if (session->server_info->guest) {
424                 /* we map anonymous to guest internally */
425                 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
426                 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
427                 /* force no signing */
428                 session->do_signing = false;
429         }
430
431         data_blob_free(&session->server_info->user_session_key);
432         session->server_info->user_session_key =
433                         data_blob_talloc(
434                                 session->server_info,
435                                 session_key.data,
436                                 session_key.length);
437         if (session_key.length > 0) {
438                 if (session->server_info->user_session_key.data == NULL) {
439                         status = NT_STATUS_NO_MEMORY;
440                         goto fail;
441                 }
442         }
443         session->session_key = session->server_info->user_session_key;
444
445         session->compat_vuser = talloc_zero(session, user_struct);
446         if (session->compat_vuser == NULL) {
447                 status = NT_STATUS_NO_MEMORY;
448                 goto fail;
449         }
450         session->compat_vuser->auth_ntlmssp_state = NULL;
451         session->compat_vuser->homes_snum = -1;
452         session->compat_vuser->server_info = session->server_info;
453         session->compat_vuser->session_keystr = NULL;
454         session->compat_vuser->vuid = session->vuid;
455         DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
456
457         /* This is a potentially untrusted username */
458         alpha_strcpy(tmp,
459                 client,
460                 ". _-$",
461                 sizeof(tmp));
462         session->server_info->sanitized_username = talloc_strdup(
463                         session->server_info, tmp);
464
465         if (!session->server_info->guest) {
466                 session->compat_vuser->homes_snum =
467                         register_homes_share(session->server_info->unix_name);
468         }
469
470         if (!session_claim(sconn_server_id(session->sconn),
471                            session->compat_vuser)) {
472                 DEBUG(1, ("smb2: Failed to claim session "
473                         "for vuid=%d\n",
474                         session->compat_vuser->vuid));
475                 goto fail;
476         }
477
478         session->status = NT_STATUS_OK;
479
480         /*
481          * we attach the session to the request
482          * so that the response can be signed
483          */
484         smb2req->session = session;
485         if (session->do_signing) {
486                 smb2req->do_signing = true;
487         }
488
489         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
490         status = NT_STATUS_OK;
491
492         /* wrap that up in a nice GSS-API wrapping */
493         ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
494                                 TOK_ID_KRB_AP_REP);
495
496         secblob_out = spnego_gen_auth_response(
497                                         talloc_tos(),
498                                         &ap_rep_wrapped,
499                                         status,
500                                         mechOID);
501
502         *out_security_buffer = data_blob_talloc(smb2req,
503                                                 secblob_out.data,
504                                                 secblob_out.length);
505         if (secblob_out.data && out_security_buffer->data == NULL) {
506                 status = NT_STATUS_NO_MEMORY;
507                 goto fail;
508         }
509
510         data_blob_free(&ap_rep);
511         data_blob_free(&ap_rep_wrapped);
512         data_blob_free(&ticket);
513         data_blob_free(&session_key);
514         data_blob_free(&secblob_out);
515
516         *out_session_id = session->vuid;
517
518         return NT_STATUS_OK;
519
520   fail:
521
522         data_blob_free(&ap_rep);
523         data_blob_free(&ap_rep_wrapped);
524         data_blob_free(&ticket);
525         data_blob_free(&session_key);
526         data_blob_free(&secblob_out);
527
528         ap_rep_wrapped = data_blob_null;
529         secblob_out = spnego_gen_auth_response(
530                                         talloc_tos(),
531                                         &ap_rep_wrapped,
532                                         status,
533                                         mechOID);
534
535         *out_security_buffer = data_blob_talloc(smb2req,
536                                                 secblob_out.data,
537                                                 secblob_out.length);
538         data_blob_free(&secblob_out);
539         return status;
540 }
541 #endif
542
543 static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
544                                         struct smbd_smb2_request *smb2req,
545                                         uint8_t in_security_mode,
546                                         DATA_BLOB in_security_buffer,
547                                         uint16_t *out_session_flags,
548                                         DATA_BLOB *out_security_buffer,
549                                         uint64_t *out_session_id)
550 {
551         DATA_BLOB secblob_in = data_blob_null;
552         DATA_BLOB chal_out = data_blob_null;
553         char *kerb_mech = NULL;
554         NTSTATUS status;
555
556         /* Ensure we have no old NTLM state around. */
557         TALLOC_FREE(session->auth_ntlmssp_state);
558
559         status = parse_spnego_mechanisms(talloc_tos(), in_security_buffer,
560                         &secblob_in, &kerb_mech);
561         if (!NT_STATUS_IS_OK(status)) {
562                 goto out;
563         }
564
565 #ifdef HAVE_KRB5
566         if (kerb_mech && ((lp_security()==SEC_ADS) ||
567                                 USE_KERBEROS_KEYTAB) ) {
568                 status = smbd_smb2_session_setup_krb5(session,
569                                 smb2req,
570                                 in_security_mode,
571                                 &secblob_in,
572                                 kerb_mech,
573                                 out_session_flags,
574                                 out_security_buffer,
575                                 out_session_id);
576
577                 goto out;
578         }
579 #endif
580
581         if (kerb_mech) {
582                 /* The mechtoken is a krb5 ticket, but
583                  * we need to fall back to NTLM. */
584
585                 DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
586                         "but set to downgrade to NTLMSSP\n"));
587
588                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
589         } else {
590                 /* Fall back to NTLMSSP. */
591                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
592                 if (!NT_STATUS_IS_OK(status)) {
593                         goto out;
594                 }
595
596                 status = auth_ntlmssp_update(session->auth_ntlmssp_state,
597                                              secblob_in,
598                                              &chal_out);
599         }
600
601         if (!NT_STATUS_IS_OK(status) &&
602                         !NT_STATUS_EQUAL(status,
603                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
604                 goto out;
605         }
606
607         *out_security_buffer = spnego_gen_auth_response(smb2req,
608                                                 &chal_out,
609                                                 status,
610                                                 OID_NTLMSSP);
611         if (out_security_buffer->data == NULL) {
612                 status = NT_STATUS_NO_MEMORY;
613                 goto out;
614         }
615         *out_session_id = session->vuid;
616
617   out:
618
619         data_blob_free(&secblob_in);
620         data_blob_free(&chal_out);
621         TALLOC_FREE(kerb_mech);
622         if (!NT_STATUS_IS_OK(status) &&
623                         !NT_STATUS_EQUAL(status,
624                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
625                 TALLOC_FREE(session->auth_ntlmssp_state);
626                 TALLOC_FREE(session);
627         }
628         return status;
629 }
630
631 static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *session,
632                                         struct smbd_smb2_request *smb2req,
633                                         uint8_t in_security_mode,
634                                         DATA_BLOB in_security_buffer,
635                                         uint16_t *out_session_flags,
636                                         uint64_t *out_session_id)
637 {
638         fstring tmp;
639
640         if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
641             lp_server_signing() == Required) {
642                 session->do_signing = true;
643         }
644
645         if (session->server_info->guest) {
646                 /* we map anonymous to guest internally */
647                 *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
648                 *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
649                 /* force no signing */
650                 session->do_signing = false;
651         }
652
653         session->session_key = session->server_info->user_session_key;
654
655         session->compat_vuser = talloc_zero(session, user_struct);
656         if (session->compat_vuser == NULL) {
657                 TALLOC_FREE(session->auth_ntlmssp_state);
658                 TALLOC_FREE(session);
659                 return NT_STATUS_NO_MEMORY;
660         }
661         session->compat_vuser->auth_ntlmssp_state = session->auth_ntlmssp_state;
662         session->compat_vuser->homes_snum = -1;
663         session->compat_vuser->server_info = session->server_info;
664         session->compat_vuser->session_keystr = NULL;
665         session->compat_vuser->vuid = session->vuid;
666         DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
667
668         /* This is a potentially untrusted username */
669         alpha_strcpy(tmp,
670                      auth_ntlmssp_get_username(session->auth_ntlmssp_state),
671                      ". _-$",
672                      sizeof(tmp));
673         session->server_info->sanitized_username = talloc_strdup(
674                 session->server_info, tmp);
675
676         if (!session->compat_vuser->server_info->guest) {
677                 session->compat_vuser->homes_snum =
678                         register_homes_share(session->server_info->unix_name);
679         }
680
681         if (!session_claim(sconn_server_id(session->sconn),
682                            session->compat_vuser)) {
683                 DEBUG(1, ("smb2: Failed to claim session "
684                         "for vuid=%d\n",
685                         session->compat_vuser->vuid));
686                 TALLOC_FREE(session->auth_ntlmssp_state);
687                 TALLOC_FREE(session);
688                 return NT_STATUS_LOGON_FAILURE;
689         }
690
691
692         session->status = NT_STATUS_OK;
693
694         /*
695          * we attach the session to the request
696          * so that the response can be signed
697          */
698         smb2req->session = session;
699         if (session->do_signing) {
700                 smb2req->do_signing = true;
701         }
702
703         global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
704
705         *out_session_id = session->vuid;
706
707         return NT_STATUS_OK;
708 }
709
710 static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
711                                         struct smbd_smb2_request *smb2req,
712                                         uint8_t in_security_mode,
713                                         DATA_BLOB in_security_buffer,
714                                         uint16_t *out_session_flags,
715                                         DATA_BLOB *out_security_buffer,
716                                         uint64_t *out_session_id)
717 {
718         DATA_BLOB auth = data_blob_null;
719         DATA_BLOB auth_out = data_blob_null;
720         NTSTATUS status;
721
722         if (!spnego_parse_auth(talloc_tos(), in_security_buffer, &auth)) {
723                 TALLOC_FREE(session);
724                 return NT_STATUS_LOGON_FAILURE;
725         }
726
727         if (auth.data[0] == ASN1_APPLICATION(0)) {
728                 /* Might be a second negTokenTarg packet */
729                 DATA_BLOB secblob_in = data_blob_null;
730                 char *kerb_mech = NULL;
731
732                 status = parse_spnego_mechanisms(talloc_tos(),
733                                 in_security_buffer,
734                                 &secblob_in, &kerb_mech);
735                 if (!NT_STATUS_IS_OK(status)) {
736                         TALLOC_FREE(session);
737                         return status;
738                 }
739
740 #ifdef HAVE_KRB5
741                 if (kerb_mech && ((lp_security()==SEC_ADS) ||
742                                         USE_KERBEROS_KEYTAB) ) {
743                         status = smbd_smb2_session_setup_krb5(session,
744                                         smb2req,
745                                         in_security_mode,
746                                         &secblob_in,
747                                         kerb_mech,
748                                         out_session_flags,
749                                         out_security_buffer,
750                                         out_session_id);
751
752                         data_blob_free(&secblob_in);
753                         TALLOC_FREE(kerb_mech);
754                         if (!NT_STATUS_IS_OK(status)) {
755                                 TALLOC_FREE(session);
756                         }
757                         return status;
758                 }
759 #endif
760
761                 /* Can't blunder into NTLMSSP auth if we have
762                  * a krb5 ticket. */
763
764                 if (kerb_mech) {
765                         DEBUG(3,("smb2: network "
766                                 "misconfiguration, client sent us a "
767                                 "krb5 ticket and kerberos security "
768                                 "not enabled\n"));
769                         TALLOC_FREE(session);
770                         data_blob_free(&secblob_in);
771                         TALLOC_FREE(kerb_mech);
772                         return NT_STATUS_LOGON_FAILURE;
773                 }
774
775                 data_blob_free(&secblob_in);
776         }
777
778         if (session->auth_ntlmssp_state == NULL) {
779                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
780                 if (!NT_STATUS_IS_OK(status)) {
781                         data_blob_free(&auth);
782                         TALLOC_FREE(session);
783                         return status;
784                 }
785         }
786
787         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
788                                      auth,
789                                      &auth_out);
790         /* We need to call setup_ntlmssp_server_info() if status==NT_STATUS_OK,
791            or if status is anything except NT_STATUS_MORE_PROCESSING_REQUIRED,
792            as this can trigger map to guest. */
793         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
794                 status = setup_ntlmssp_server_info(session, status);
795         }
796
797         if (!NT_STATUS_IS_OK(status) &&
798                         !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
799                 TALLOC_FREE(session->auth_ntlmssp_state);
800                 data_blob_free(&auth);
801                 TALLOC_FREE(session);
802                 return status;
803         }
804
805         data_blob_free(&auth);
806
807         *out_security_buffer = spnego_gen_auth_response(smb2req,
808                                 &auth_out, status, NULL);
809
810         if (out_security_buffer->data == NULL) {
811                 TALLOC_FREE(session->auth_ntlmssp_state);
812                 TALLOC_FREE(session);
813                 return NT_STATUS_NO_MEMORY;
814         }
815
816         *out_session_id = session->vuid;
817
818         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
819                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
820         }
821
822         /* We're done - claim the session. */
823         return smbd_smb2_common_ntlmssp_auth_return(session,
824                                                 smb2req,
825                                                 in_security_mode,
826                                                 in_security_buffer,
827                                                 out_session_flags,
828                                                 out_session_id);
829 }
830
831 static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
832                                         struct smbd_smb2_request *smb2req,
833                                         uint8_t in_security_mode,
834                                         DATA_BLOB in_security_buffer,
835                                         uint16_t *out_session_flags,
836                                         DATA_BLOB *out_security_buffer,
837                                         uint64_t *out_session_id)
838 {
839         NTSTATUS status;
840         DATA_BLOB secblob_out = data_blob_null;
841
842         if (session->auth_ntlmssp_state == NULL) {
843                 status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
844                 if (!NT_STATUS_IS_OK(status)) {
845                         TALLOC_FREE(session);
846                         return status;
847                 }
848         }
849
850         /* RAW NTLMSSP */
851         status = auth_ntlmssp_update(session->auth_ntlmssp_state,
852                                      in_security_buffer,
853                                      &secblob_out);
854
855         if (NT_STATUS_IS_OK(status) ||
856                         NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
857                 *out_security_buffer = data_blob_talloc(smb2req,
858                                                 secblob_out.data,
859                                                 secblob_out.length);
860                 if (secblob_out.data && out_security_buffer->data == NULL) {
861                         TALLOC_FREE(session->auth_ntlmssp_state);
862                         TALLOC_FREE(session);
863                         return NT_STATUS_NO_MEMORY;
864                 }
865         }
866
867         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
868                 *out_session_id = session->vuid;
869                 return status;
870         }
871
872         status = setup_ntlmssp_server_info(session, status);
873
874         if (!NT_STATUS_IS_OK(status)) {
875                 TALLOC_FREE(session->auth_ntlmssp_state);
876                 TALLOC_FREE(session);
877                 return status;
878         }
879         *out_session_id = session->vuid;
880
881         return smbd_smb2_common_ntlmssp_auth_return(session,
882                                                 smb2req,
883                                                 in_security_mode,
884                                                 in_security_buffer,
885                                                 out_session_flags,
886                                                 out_session_id);
887 }
888
889 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
890                                         uint64_t in_session_id,
891                                         uint8_t in_security_mode,
892                                         DATA_BLOB in_security_buffer,
893                                         uint16_t *out_session_flags,
894                                         DATA_BLOB *out_security_buffer,
895                                         uint64_t *out_session_id)
896 {
897         struct smbd_smb2_session *session;
898
899         *out_session_flags = 0;
900         *out_session_id = 0;
901
902         if (in_session_id == 0) {
903                 int id;
904
905                 /* create a new session */
906                 session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
907                 if (session == NULL) {
908                         return NT_STATUS_NO_MEMORY;
909                 }
910                 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
911                 id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
912                                         session,
913                                         smb2req->sconn->smb2.sessions.limit);
914                 if (id == -1) {
915                         return NT_STATUS_INSUFFICIENT_RESOURCES;
916                 }
917                 session->vuid = id;
918
919                 session->tcons.idtree = idr_init(session);
920                 if (session->tcons.idtree == NULL) {
921                         return NT_STATUS_NO_MEMORY;
922                 }
923                 session->tcons.limit = 0x0000FFFE;
924                 session->tcons.list = NULL;
925
926                 DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
927                               struct smbd_smb2_session *);
928                 session->sconn = smb2req->sconn;
929                 talloc_set_destructor(session, smbd_smb2_session_destructor);
930         } else {
931                 void *p;
932
933                 /* lookup an existing session */
934                 p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
935                 if (p == NULL) {
936                         return NT_STATUS_USER_SESSION_DELETED;
937                 }
938                 session = talloc_get_type_abort(p, struct smbd_smb2_session);
939         }
940
941         if (NT_STATUS_IS_OK(session->status)) {
942                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
943         }
944
945         if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
946                 return smbd_smb2_spnego_negotiate(session,
947                                                 smb2req,
948                                                 in_security_mode,
949                                                 in_security_buffer,
950                                                 out_session_flags,
951                                                 out_security_buffer,
952                                                 out_session_id);
953         } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
954                 return smbd_smb2_spnego_auth(session,
955                                                 smb2req,
956                                                 in_security_mode,
957                                                 in_security_buffer,
958                                                 out_session_flags,
959                                                 out_security_buffer,
960                                                 out_session_id);
961         } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
962                 return smbd_smb2_raw_ntlmssp_auth(session,
963                                                 smb2req,
964                                                 in_security_mode,
965                                                 in_security_buffer,
966                                                 out_session_flags,
967                                                 out_security_buffer,
968                                                 out_session_id);
969         }
970
971         /* Unknown packet type. */
972         DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
973                 (unsigned int)in_security_buffer.data[0] ));
974         TALLOC_FREE(session->auth_ntlmssp_state);
975         TALLOC_FREE(session);
976         return NT_STATUS_LOGON_FAILURE;
977 }
978
979 NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
980 {
981         const uint8_t *inhdr;
982         const uint8_t *outhdr;
983         int i = req->current_idx;
984         uint64_t in_session_id;
985         void *p;
986         struct smbd_smb2_session *session;
987         bool chained_fixup = false;
988
989         inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
990
991         in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
992
993         if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
994                 if (req->async) {
995                         /*
996                          * async request - fill in session_id from
997                          * already setup request out.vector[].iov_base.
998                          */
999                         outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1000                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1001                 } else if (i > 2) {
1002                         /*
1003                          * Chained request - fill in session_id from
1004                          * the previous request out.vector[].iov_base.
1005                          */
1006                         outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
1007                         in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
1008                         chained_fixup = true;
1009                 }
1010         }
1011
1012         /* lookup an existing session */
1013         p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
1014         if (p == NULL) {
1015                 return NT_STATUS_USER_SESSION_DELETED;
1016         }
1017         session = talloc_get_type_abort(p, struct smbd_smb2_session);
1018
1019         if (!NT_STATUS_IS_OK(session->status)) {
1020                 return NT_STATUS_ACCESS_DENIED;
1021         }
1022
1023         set_current_user_info(session->server_info->sanitized_username,
1024                               session->server_info->unix_name,
1025                               session->server_info->info3->base.domain.string);
1026
1027         req->session = session;
1028
1029         if (chained_fixup) {
1030                 /* Fix up our own outhdr. */
1031                 outhdr = (const uint8_t *)req->out.vector[i].iov_base;
1032                 SBVAL(outhdr, SMB2_HDR_SESSION_ID, in_session_id);
1033         }
1034         return NT_STATUS_OK;
1035 }
1036
1037 NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req)
1038 {
1039         const uint8_t *inbody;
1040         int i = req->current_idx;
1041         DATA_BLOB outbody;
1042         size_t expected_body_size = 0x04;
1043         size_t body_size;
1044
1045         if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
1046                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1047         }
1048
1049         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
1050
1051         body_size = SVAL(inbody, 0x00);
1052         if (body_size != expected_body_size) {
1053                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
1054         }
1055
1056         /*
1057          * TODO: cancel all outstanding requests on the session
1058          *       and delete all tree connections.
1059          */
1060         smbd_smb2_session_destructor(req->session);
1061         /*
1062          * we may need to sign the response, so we need to keep
1063          * the session until the response is sent to the wire.
1064          */
1065         talloc_steal(req, req->session);
1066
1067         outbody = data_blob_talloc(req->out.vector, NULL, 0x04);
1068         if (outbody.data == NULL) {
1069                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
1070         }
1071
1072         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
1073         SSVAL(outbody.data, 0x02, 0);           /* reserved */
1074
1075         return smbd_smb2_request_done(req, outbody, NULL);
1076 }