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